summaryrefslogtreecommitdiff
authorXindong Xu <xindong.xu@amlogic.com>2018-05-02 04:59:43 (GMT)
committer Xindong Xu <xindong.xu@amlogic.com>2018-05-02 04:59:43 (GMT)
commit8cdf75a85b6ecf3304c91d2d335d55666c3dcc55 (patch)
treeeef4f38371c2d05a394f1433f304ac7b4cdfafa3
parent63a6eb525b61c3c41635102534127a42e1a3b4cd (diff)
downloadamlogic-o-mr1-tv-dev.zip
amlogic-o-mr1-tv-dev.tar.gz
amlogic-o-mr1-tv-dev.tar.bz2
amlogic: add mtkbt code
Change-Id: I4abef7b0293f690df82903605353cba5b97793d6
Diffstat
-rwxr-xr-xmtkbt/Android.mk4
-rwxr-xr-xmtkbt/code/Android.mk4
-rwxr-xr-xmtkbt/code/bt/.gitignore2
-rwxr-xr-xmtkbt/code/bt/.gn22
-rwxr-xr-xmtkbt/code/bt/Android.bp19
-rwxr-xr-xmtkbt/code/bt/Android.mk1
-rwxr-xr-xmtkbt/code/bt/BUILD.gn41
-rwxr-xr-xmtkbt/code/bt/CleanSpec.mk53
-rwxr-xr-xmtkbt/code/bt/EventLogTags.logtags38
-rwxr-xr-xmtkbt/code/bt/MODULE_LICENSE_APACHE20
-rwxr-xr-xmtkbt/code/bt/NOTICE202
-rwxr-xr-xmtkbt/code/bt/OWNERS13
-rwxr-xr-xmtkbt/code/bt/PREUPLOAD.cfg6
-rwxr-xr-xmtkbt/code/bt/README.md113
-rwxr-xr-xmtkbt/code/bt/audio_a2dp_hw/Android.bp53
-rwxr-xr-xmtkbt/code/bt/audio_a2dp_hw/include/audio_a2dp_hw.h154
-rwxr-xr-xmtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw.cc1885
-rwxr-xr-xmtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc41
-rwxr-xr-xmtkbt/code/bt/audio_a2dp_hw/test/audio_a2dp_hw_test.cc142
-rwxr-xr-xmtkbt/code/bt/bta/Android.bp135
-rwxr-xr-xmtkbt/code/bt/bta/BUILD.gn119
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_act.cc863
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_api.cc278
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_at.cc209
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_at.h120
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_cfg.cc83
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_ci.cc88
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_cmd.cc1769
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_int.h398
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_main.cc951
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_rfc.cc396
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_sco.cc1431
-rwxr-xr-xmtkbt/code/bt/bta/ag/bta_ag_sdp.cc474
-rwxr-xr-xmtkbt/code/bt/bta/ar/bta_ar.cc322
-rwxr-xr-xmtkbt/code/bt/bta/ar/bta_ar_int.h58
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_aact.cc3169
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_act.cc2347
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_api.cc601
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_cfg.cc281
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_ci.cc89
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_int.h710
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_main.cc1357
-rwxr-xr-xmtkbt/code/bt/bta/av/bta_av_ssm.cc674
-rwxr-xr-xmtkbt/code/bt/bta/closure/bta_closure.cc87
-rwxr-xr-xmtkbt/code/bt/bta/closure/bta_closure_int.h34
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_act.cc4830
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_api.cc1201
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_cfg.cc629
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_ci.cc108
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_int.h875
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_main.cc343
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_pm.cc1180
-rwxr-xr-xmtkbt/code/bt/bta/dm/bta_dm_sco.cc667
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_act.cc1765
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_api.cc749
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_cache.cc1544
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_int.h510
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_main.cc509
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gattc_utils.cc746
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gatts_act.cc683
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gatts_api.cc343
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gatts_int.h189
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gatts_main.cc115
-rwxr-xr-xmtkbt/code/bt/bta/gatt/bta_gatts_utils.cc210
-rwxr-xr-xmtkbt/code/bt/bta/hd/bta_hd_act.cc738
-rwxr-xr-xmtkbt/code/bt/bta/hd/bta_hd_api.cc309
-rwxr-xr-xmtkbt/code/bt/bta/hd/bta_hd_int.h180
-rwxr-xr-xmtkbt/code/bt/bta/hd/bta_hd_main.cc365
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_act.cc463
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_api.cc199
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_at.cc2112
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_at.h60
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_int.h340
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_main.cc957
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_rfc.cc293
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_sco.cc654
-rwxr-xr-xmtkbt/code/bt/bta/hf_client/bta_hf_client_sdp.cc362
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_act.cc1275
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_api.cc411
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_cfg.cc55
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_int.h396
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_le.cc2438
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_main.cc595
-rwxr-xr-xmtkbt/code/bt/bta/hh/bta_hh_utils.cc506
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_act.cc2377
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_api.cc489
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_ci.cc162
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_int.h853
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_main.cc1872
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_sdp.cc574
-rwxr-xr-xmtkbt/code/bt/bta/hl/bta_hl_utils.cc3093
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_ag_api.h586
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_ag_ci.h70
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_ag_co.h87
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_api.h1770
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_ar_api.h153
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_av_api.h792
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_av_ci.h63
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_av_co.h215
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_closure_api.h36
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_dm_api.h32
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_dm_ci.h71
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_dm_co.h242
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_gatt_api.h1168
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_gatts_co.h82
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hd_api.h268
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hf_client_api.h372
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hh_api.h514
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hh_co.h136
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hl_api.h827
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hl_ci.h116
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_hl_co.h240
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_jv_api.h832
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_jv_co.h49
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_mce_api.h121
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_op_api.h65
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_pan_api.h179
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_pan_ci.h142
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_pan_co.h199
-rwxr-xr-xmtkbt/code/bt/bta/include/bta_sdp_api.h136
-rwxr-xr-xmtkbt/code/bt/bta/include/utl.h165
-rwxr-xr-xmtkbt/code/bt/bta/jv/bta_jv_act.cc2537
-rwxr-xr-xmtkbt/code/bt/bta/jv/bta_jv_api.cc989
-rwxr-xr-xmtkbt/code/bt/bta/jv/bta_jv_cfg.cc58
-rwxr-xr-xmtkbt/code/bt/bta/jv/bta_jv_int.h409
-rwxr-xr-xmtkbt/code/bt/bta/jv/bta_jv_main.cc92
-rwxr-xr-xmtkbt/code/bt/bta/mce/bta_mce_act.cc180
-rwxr-xr-xmtkbt/code/bt/bta/mce/bta_mce_api.cc107
-rwxr-xr-xmtkbt/code/bt/bta/mce/bta_mce_cfg.cc45
-rwxr-xr-xmtkbt/code/bt/bta/mce/bta_mce_int.h86
-rwxr-xr-xmtkbt/code/bt/bta/mce/bta_mce_main.cc75
-rwxr-xr-xmtkbt/code/bt/bta/pan/bta_pan_act.cc707
-rwxr-xr-xmtkbt/code/bt/bta/pan/bta_pan_api.cc193
-rwxr-xr-xmtkbt/code/bt/bta/pan/bta_pan_ci.cc263
-rwxr-xr-xmtkbt/code/bt/bta/pan/bta_pan_int.h186
-rwxr-xr-xmtkbt/code/bt/bta/pan/bta_pan_main.cc362
-rwxr-xr-xmtkbt/code/bt/bta/pb/bta_pbs_int.h60
-rwxr-xr-xmtkbt/code/bt/bta/sdp/bta_sdp.cc72
-rwxr-xr-xmtkbt/code/bt/bta/sdp/bta_sdp_act.cc569
-rwxr-xr-xmtkbt/code/bt/bta/sdp/bta_sdp_api.cc156
-rwxr-xr-xmtkbt/code/bt/bta/sdp/bta_sdp_cfg.cc40
-rwxr-xr-xmtkbt/code/bt/bta/sdp/bta_sdp_int.h100
-rwxr-xr-xmtkbt/code/bt/bta/sys/bta_sys.h277
-rwxr-xr-xmtkbt/code/bt/bta/sys/bta_sys_conn.cc505
-rwxr-xr-xmtkbt/code/bt/bta/sys/bta_sys_int.h101
-rwxr-xr-xmtkbt/code/bt/bta/sys/bta_sys_main.cc619
-rwxr-xr-xmtkbt/code/bt/bta/sys/utl.cc266
-rwxr-xr-xmtkbt/code/bt/bta/test/bta_closure_test.cc101
-rwxr-xr-xmtkbt/code/bt/bta/test/bta_hf_client_test.cc84
-rwxr-xr-xmtkbt/code/bt/btcore/Android.bp60
-rwxr-xr-xmtkbt/code/bt/btcore/BUILD.gn64
-rwxr-xr-xmtkbt/code/bt/btcore/include/bdaddr.h60
-rwxr-xr-xmtkbt/code/bt/btcore/include/device_class.h96
-rwxr-xr-xmtkbt/code/bt/btcore/include/device_features.h25
-rwxr-xr-xmtkbt/code/bt/btcore/include/event_mask.h26
-rwxr-xr-xmtkbt/code/bt/btcore/include/hal_util.h24
-rwxr-xr-xmtkbt/code/bt/btcore/include/iac.h28
-rwxr-xr-xmtkbt/code/bt/btcore/include/module.h68
-rwxr-xr-xmtkbt/code/bt/btcore/include/osi_module.h21
-rwxr-xr-xmtkbt/code/bt/btcore/include/property.h80
-rwxr-xr-xmtkbt/code/bt/btcore/include/uuid.h75
-rwxr-xr-xmtkbt/code/bt/btcore/include/version.h29
-rwxr-xr-xmtkbt/code/bt/btcore/src/bdaddr.cc88
-rwxr-xr-xmtkbt/code/bt/btcore/src/device_class.cc165
-rwxr-xr-xmtkbt/code/bt/btcore/src/hal_util.cc91
-rwxr-xr-xmtkbt/code/bt/btcore/src/module.cc213
-rwxr-xr-xmtkbt/code/bt/btcore/src/osi_module.cc44
-rwxr-xr-xmtkbt/code/bt/btcore/src/property.cc230
-rwxr-xr-xmtkbt/code/bt/btcore/src/uuid.cc163
-rwxr-xr-xmtkbt/code/bt/btcore/test/bdaddr_test.cc72
-rwxr-xr-xmtkbt/code/bt/btcore/test/device_class_test.cc218
-rwxr-xr-xmtkbt/code/bt/btcore/test/property_test.cc238
-rwxr-xr-xmtkbt/code/bt/btcore/test/uuid_test.cc162
-rwxr-xr-xmtkbt/code/bt/btif/Android.bp123
-rwxr-xr-xmtkbt/code/bt/btif/BUILD.gn102
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_ag_co.cc88
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_av_co.cc1361
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_dm_co.cc369
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_gatts_co.cc168
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_hh_co.cc679
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_hl_co.cc415
-rwxr-xr-xmtkbt/code/bt/btif/co/bta_pan_co.cc316
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_a2dp.h61
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_a2dp_control.h51
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_a2dp_sink.h104
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_a2dp_source.h102
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_api.h425
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_av.h231
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_av_co.h71
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_avrcp_audio_track.h68
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_common.h254
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_config.h61
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_config_transcode.h23
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_debug.h25
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_debug_btsnoop.h44
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_debug_conn.h35
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_dm.h108
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_gatt.h35
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_gatt_util.h42
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_hd.h47
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_hf.h28
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_hh.h118
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_hl.h315
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_mce.h35
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_pan.h36
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_pan_internal.h118
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_profile_queue.h40
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sdp.h34
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sm.h122
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock.h28
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_l2cap.h24
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_rfc.h42
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_sco.h29
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_sdp.h52
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_thread.h58
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_sock_util.h38
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_storage.h278
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_uid.h43
-rwxr-xr-xmtkbt/code/bt/btif/include/btif_util.h81
-rwxr-xr-xmtkbt/code/bt/btif/include/stack_manager.h38
-rwxr-xr-xmtkbt/code/bt/btif/src/bluetooth.cc486
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_a2dp.cc123
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_a2dp_control.cc424
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_a2dp_sink.cc823
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_a2dp_source.cc1126
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_av.cc1889
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_avrcp_audio_track.cc146
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_ble_advertiser.cc248
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_ble_scanner.cc458
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_config.cc555
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_config_transcode.cc66
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_core.cc1185
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_debug.cc30
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_debug_btsnoop.cc231
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_debug_conn.cc107
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_dm.cc3494
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_gatt.cc105
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_gatt_client.cc638
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_gatt_server.cc471
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_gatt_test.cc292
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_gatt_util.cc271
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_hd.cc685
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_hf.cc1668
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_hf_client.cc1059
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_hh.cc1697
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_hl.cc4729
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_mce.cc168
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_pan.cc784
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_profile_queue.cc175
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_rc.cc5522
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sdp.cc177
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sdp_server.cc767
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sm.cc181
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock.cc203
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_l2cap.cc1081
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_rfc.cc929
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_sco.cc331
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_sdp.cc470
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_thread.cc552
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_sock_util.cc233
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_storage.cc1452
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_uid.cc123
-rwxr-xr-xmtkbt/code/bt/btif/src/btif_util.cc539
-rwxr-xr-xmtkbt/code/bt/btif/src/stack_manager.cc251
-rwxr-xr-xmtkbt/code/bt/btif/test/btif_storage_test.cc68
-rwxr-xr-xmtkbt/code/bt/build/Android.bp47
-rwxr-xr-xmtkbt/code/bt/build/BUILD.gn74
-rwxr-xr-xmtkbt/code/bt/build/config/BUILDCONFIG.gn54
-rwxr-xr-xmtkbt/code/bt/build/fluoride.go69
-rwxr-xr-xmtkbt/code/bt/build/install_deps.sh57
-rwxr-xr-xmtkbt/code/bt/build/mediatek.go36
-rwxr-xr-xmtkbt/code/bt/build/toolchain/clang/BUILD.gn116
-rwxr-xr-xmtkbt/code/bt/build/toolchain/clang/get_clang_suffix.py43
-rwxr-xr-xmtkbt/code/bt/build/toolchain/gcc/BUILD.gn97
-rwxr-xr-xmtkbt/code/bt/conf/Android.mk24
-rwxr-xr-xmtkbt/code/bt/conf/bt_did.conf88
-rwxr-xr-xmtkbt/code/bt/conf/bt_stack.conf69
-rwxr-xr-xmtkbt/code/bt/device/Android.bp46
-rwxr-xr-xmtkbt/code/bt/device/BUILD.gn58
-rwxr-xr-xmtkbt/code/bt/device/include/controller.h96
-rwxr-xr-xmtkbt/code/bt/device/include/esco_parameters.h137
-rwxr-xr-xmtkbt/code/bt/device/include/interop.h230
-rwxr-xr-xmtkbt/code/bt/device/include/interop_database.h358
-rwxr-xr-xmtkbt/code/bt/device/src/controller.cc589
-rwxr-xr-xmtkbt/code/bt/device/src/esco_parameters.cc159
-rwxr-xr-xmtkbt/code/bt/device/src/interop.cc242
-rwxr-xr-xmtkbt/code/bt/device/test/interop_test.cc82
-rwxr-xr-xmtkbt/code/bt/doc/btsnoop_net.md15
-rwxr-xr-xmtkbt/code/bt/doc/directory_layout.md29
-rwxr-xr-xmtkbt/code/bt/doc/log_tags.md57
-rwxr-xr-xmtkbt/code/bt/doc/network_ports.md8
-rwxr-xr-xmtkbt/code/bt/doc/power_management.md202
-rwxr-xr-xmtkbt/code/bt/doc/properties.md20
-rwxr-xr-xmtkbt/code/bt/doc/style_guide.md429
-rwxr-xr-xmtkbt/code/bt/doc/supported_features.md20
-rwxr-xr-xmtkbt/code/bt/embdrv/Android.bp3
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/Android.bp4
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/BUILD.gn62
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/Android.bp26
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_assert.h87
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_bitstream.h120
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_bt_spec.h239
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h515
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h232
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_common.h43
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h288
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_modules.h177
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_osinterface.h198
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_status.h873
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_stddefs.h331
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_string.h193
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_time.h193
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/include/oi_utils.h376
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/alloc.c82
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c161
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc.c379
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/bitstream-decode.c87
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-oina.c119
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-private.c226
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-sbc.c479
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/dequant.c215
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/framing-sbc.c58
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/framing.c286
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/oi_codec_version.c57
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc112
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c160
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c347
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c559
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/Android.bp23
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/include/sbc_dct.h94
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h56
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/include/sbc_encoder.h208
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/include/sbc_if.h47
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/include/sbc_types.h35
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_analysis.c1400
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct.c268
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c116
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c177
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c187
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c244
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_encoder.c258
-rwxr-xr-xmtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_packing.c250
-rwxr-xr-xmtkbt/code/bt/hci/Android.bp77
-rwxr-xr-xmtkbt/code/bt/hci/BUILD.gn75
-rwxr-xr-xmtkbt/code/bt/hci/include/bt_hci_bdroid.h95
-rwxr-xr-xmtkbt/code/bt/hci/include/bt_vendor_lib.h413
-rwxr-xr-xmtkbt/code/bt/hci/include/btsnoop.h34
-rwxr-xr-xmtkbt/code/bt/hci/include/btsnoop_mem.h37
-rwxr-xr-xmtkbt/code/bt/hci/include/buffer_allocator.h23
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_hal.h92
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_inject.h34
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_internals.h28
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_layer.h95
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_packet_factory.h50
-rwxr-xr-xmtkbt/code/bt/hci/include/hci_packet_parser.h86
-rwxr-xr-xmtkbt/code/bt/hci/include/low_power_manager.h49
-rwxr-xr-xmtkbt/code/bt/hci/include/packet_fragmenter.h64
-rwxr-xr-xmtkbt/code/bt/hci/include/userial.h71
-rwxr-xr-xmtkbt/code/bt/hci/include/vendor.h70
-rwxr-xr-xmtkbt/code/bt/hci/src/btsnoop.cc282
-rwxr-xr-xmtkbt/code/bt/hci/src/btsnoop_mem.cc57
-rwxr-xr-xmtkbt/code/bt/hci/src/btsnoop_net.cc158
-rwxr-xr-xmtkbt/code/bt/hci/src/buffer_allocator.cc31
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_inject.cc204
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_layer.cc750
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_layer_android.cc166
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_layer_linux.cc398
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_packet_factory.cc223
-rwxr-xr-xmtkbt/code/bt/hci/src/hci_packet_parser.cc278
-rwxr-xr-xmtkbt/code/bt/hci/src/packet_fragmenter.cc256
-rwxr-xr-xmtkbt/code/bt/hci/test/packet_fragmenter_test.cc396
-rwxr-xr-xmtkbt/code/bt/include/bt_common.h24
-rwxr-xr-xmtkbt/code/bt/include/bt_target.h1517
-rwxr-xr-xmtkbt/code/bt/include/bt_trace.h776
-rwxr-xr-xmtkbt/code/bt/include/bte.h131
-rwxr-xr-xmtkbt/code/bt/include/bte_appl.h35
-rwxr-xr-xmtkbt/code/bt/include/stack_config.h38
-rwxr-xr-xmtkbt/code/bt/main/Android.bp89
-rwxr-xr-xmtkbt/code/bt/main/BUILD.gn86
-rwxr-xr-xmtkbt/code/bt/main/bte_conf.cc99
-rwxr-xr-xmtkbt/code/bt/main/bte_init.cc120
-rwxr-xr-xmtkbt/code/bt/main/bte_init_cpp_logging.cc55
-rwxr-xr-xmtkbt/code/bt/main/bte_logmsg.cc235
-rwxr-xr-xmtkbt/code/bt/main/bte_main.cc230
-rwxr-xr-xmtkbt/code/bt/main/main_int.h27
-rwxr-xr-xmtkbt/code/bt/main/stack_config.cc125
-rwxr-xr-xmtkbt/code/bt/mediatek/Android.bp26
-rwxr-xr-xmtkbt/code/bt/mediatek/Android.mk1
-rwxr-xr-xmtkbt/code/bt/mediatek/BUILD.gn21
-rwxr-xr-xmtkbt/code/bt/mediatek/conf/Android.mk23
-rwxr-xr-xmtkbt/code/bt/mediatek/conf/mtk_bt_fw.conf84
-rwxr-xr-xmtkbt/code/bt/mediatek/conf/mtk_bt_stack.conf33
-rwxr-xr-xmtkbt/code/bt/mediatek/config/log_mode.cc195
-rwxr-xr-xmtkbt/code/bt/mediatek/config/log_time.cc99
-rwxr-xr-xmtkbt/code/bt/mediatek/config/mtk_stack_config.cc490
-rwxr-xr-xmtkbt/code/bt/mediatek/gatt/gatts_mtk.cc110
-rwxr-xr-xmtkbt/code/bt/mediatek/hci/fw_logger_filter.cc105
-rwxr-xr-xmtkbt/code/bt/mediatek/hci/fw_logger_switch.cc218
-rwxr-xr-xmtkbt/code/bt/mediatek/hci/hci_inbound_data_monitor.cc417
-rwxr-xr-xmtkbt/code/bt/mediatek/hci/twrite.cc483
-rwxr-xr-xmtkbt/code/bt/mediatek/include/fw_logger_filter.h73
-rwxr-xr-xmtkbt/code/bt/mediatek/include/fw_logger_switch.h67
-rwxr-xr-xmtkbt/code/bt/mediatek/include/gatts_mtk.h99
-rwxr-xr-xmtkbt/code/bt/mediatek/include/hci_inbound_data_monitor.h96
-rwxr-xr-xmtkbt/code/bt/mediatek/include/interop_mtk.h85
-rwxr-xr-xmtkbt/code/bt/mediatek/include/log_mode.h75
-rwxr-xr-xmtkbt/code/bt/mediatek/include/log_time.h72
-rwxr-xr-xmtkbt/code/bt/mediatek/include/mdroid_buildcfg.h164
-rwxr-xr-xmtkbt/code/bt/mediatek/include/mtk_bt_av.h63
-rwxr-xr-xmtkbt/code/bt/mediatek/include/mtk_stack_config.h84
-rwxr-xr-xmtkbt/code/bt/mediatek/include/mtk_util.h92
-rwxr-xr-xmtkbt/code/bt/mediatek/include/twrite.h76
-rwxr-xr-xmtkbt/code/bt/mediatek/interop/interop_mtk.cc107
-rwxr-xr-xmtkbt/code/bt/osi/Android.bp159
-rwxr-xr-xmtkbt/code/bt/osi/BUILD.gn99
-rwxr-xr-xmtkbt/code/bt/osi/include/alarm.h119
-rwxr-xr-xmtkbt/code/bt/osi/include/allocation_tracker.h59
-rwxr-xr-xmtkbt/code/bt/osi/include/allocator.h53
-rwxr-xr-xmtkbt/code/bt/osi/include/array.h58
-rwxr-xr-xmtkbt/code/bt/osi/include/buffer.h56
-rwxr-xr-xmtkbt/code/bt/osi/include/compat.h37
-rwxr-xr-xmtkbt/code/bt/osi/include/config.h150
-rwxr-xr-xmtkbt/code/bt/osi/include/data_dispatcher.h60
-rwxr-xr-xmtkbt/code/bt/osi/include/fixed_queue.h133
-rwxr-xr-xmtkbt/code/bt/osi/include/future.h41
-rwxr-xr-xmtkbt/code/bt/osi/include/hash_map_utils.h40
-rwxr-xr-xmtkbt/code/bt/osi/include/leaky_bonded_queue.h158
-rwxr-xr-xmtkbt/code/bt/osi/include/list.h139
-rwxr-xr-xmtkbt/code/bt/osi/include/log.h86
-rwxr-xr-xmtkbt/code/bt/osi/include/metrics.h266
-rwxr-xr-xmtkbt/code/bt/osi/include/mutex.h27
-rwxr-xr-xmtkbt/code/bt/osi/include/osi.h67
-rwxr-xr-xmtkbt/code/bt/osi/include/properties.h45
-rwxr-xr-xmtkbt/code/bt/osi/include/reactor.h87
-rwxr-xr-xmtkbt/code/bt/osi/include/ringbuffer.h62
-rwxr-xr-xmtkbt/code/bt/osi/include/semaphore.h57
-rwxr-xr-xmtkbt/code/bt/osi/include/socket.h109
-rwxr-xr-xmtkbt/code/bt/osi/include/socket_utils/socket_local.h36
-rwxr-xr-xmtkbt/code/bt/osi/include/socket_utils/sockets.h70
-rwxr-xr-xmtkbt/code/bt/osi/include/thread.h84
-rwxr-xr-xmtkbt/code/bt/osi/include/time.h42
-rwxr-xr-xmtkbt/code/bt/osi/include/wakelock.h54
-rwxr-xr-xmtkbt/code/bt/osi/src/alarm.cc733
-rwxr-xr-xmtkbt/code/bt/osi/src/allocation_tracker.cc187
-rwxr-xr-xmtkbt/code/bt/osi/src/allocator.cc84
-rwxr-xr-xmtkbt/code/bt/osi/src/array.cc111
-rwxr-xr-xmtkbt/code/bt/osi/src/buffer.cc91
-rwxr-xr-xmtkbt/code/bt/osi/src/compat.cc121
-rwxr-xr-xmtkbt/code/bt/osi/src/config.cc517
-rwxr-xr-xmtkbt/code/bt/osi/src/data_dispatcher.cc108
-rwxr-xr-xmtkbt/code/bt/osi/src/fixed_queue.cc262
-rwxr-xr-xmtkbt/code/bt/osi/src/future.cc88
-rwxr-xr-xmtkbt/code/bt/osi/src/hash_map_utils.cc84
-rwxr-xr-xmtkbt/code/bt/osi/src/list.cc215
-rwxr-xr-xmtkbt/code/bt/osi/src/metrics.cc504
-rwxr-xr-xmtkbt/code/bt/osi/src/metrics_linux.cc204
-rwxr-xr-xmtkbt/code/bt/osi/src/mutex.cc29
-rwxr-xr-xmtkbt/code/bt/osi/src/osi.cc53
-rwxr-xr-xmtkbt/code/bt/osi/src/properties.cc54
-rwxr-xr-xmtkbt/code/bt/osi/src/protos/bluetooth.proto224
-rwxr-xr-xmtkbt/code/bt/osi/src/reactor.cc297
-rwxr-xr-xmtkbt/code/bt/osi/src/ringbuffer.cc116
-rwxr-xr-xmtkbt/code/bt/osi/src/semaphore.cc111
-rwxr-xr-xmtkbt/code/bt/osi/src/socket.cc232
-rwxr-xr-xmtkbt/code/bt/osi/src/socket_utils/README41
-rwxr-xr-xmtkbt/code/bt/osi/src/socket_utils/socket_local_client.cc151
-rwxr-xr-xmtkbt/code/bt/osi/src/socket_utils/socket_local_server.cc106
-rwxr-xr-xmtkbt/code/bt/osi/src/thread.cc253
-rwxr-xr-xmtkbt/code/bt/osi/src/time.cc43
-rwxr-xr-xmtkbt/code/bt/osi/src/wakelock.cc373
-rwxr-xr-xmtkbt/code/bt/osi/test/AlarmTestHarness.cc57
-rwxr-xr-xmtkbt/code/bt/osi/test/AlarmTestHarness.h33
-rwxr-xr-xmtkbt/code/bt/osi/test/AllocationTestHarness.cc33
-rwxr-xr-xmtkbt/code/bt/osi/test/AllocationTestHarness.h27
-rwxr-xr-xmtkbt/code/bt/osi/test/alarm_test.cc453
-rwxr-xr-xmtkbt/code/bt/osi/test/allocation_tracker_test.cc64
-rwxr-xr-xmtkbt/code/bt/osi/test/allocator_test.cc52
-rwxr-xr-xmtkbt/code/bt/osi/test/array_test.cc67
-rwxr-xr-xmtkbt/code/bt/osi/test/config_test.cc202
-rwxr-xr-xmtkbt/code/bt/osi/test/data_dispatcher_test.cc258
-rwxr-xr-xmtkbt/code/bt/osi/test/fixed_queue_test.cc350
-rwxr-xr-xmtkbt/code/bt/osi/test/future_test.cc53
-rwxr-xr-xmtkbt/code/bt/osi/test/hash_map_utils_test.cc113
-rwxr-xr-xmtkbt/code/bt/osi/test/leaky_bonded_queue_test.cc242
-rwxr-xr-xmtkbt/code/bt/osi/test/list_test.cc211
-rwxr-xr-xmtkbt/code/bt/osi/test/metrics_test.cc802
-rwxr-xr-xmtkbt/code/bt/osi/test/properties_test.cc56
-rwxr-xr-xmtkbt/code/bt/osi/test/rand_test.cc17
-rwxr-xr-xmtkbt/code/bt/osi/test/reactor_test.cc113
-rwxr-xr-xmtkbt/code/bt/osi/test/ringbuffer_test.cc139
-rwxr-xr-xmtkbt/code/bt/osi/test/semaphore_test.cc86
-rwxr-xr-xmtkbt/code/bt/osi/test/test_stubs.h101
-rwxr-xr-xmtkbt/code/bt/osi/test/thread_test.cc57
-rwxr-xr-xmtkbt/code/bt/osi/test/time_test.cc154
-rwxr-xr-xmtkbt/code/bt/osi/test/wakelock_test.cc157
-rwxr-xr-xmtkbt/code/bt/service/Android.bp243
-rwxr-xr-xmtkbt/code/bt/service/BUILD.gn100
-rwxr-xr-xmtkbt/code/bt/service/adapter.cc417
-rwxr-xr-xmtkbt/code/bt/service/adapter.h154
-rwxr-xr-xmtkbt/code/bt/service/bluetooth_instance.h75
-rwxr-xr-xmtkbt/code/bt/service/bluetoothtbd.rc4
-rwxr-xr-xmtkbt/code/bt/service/client/main.cc1110
-rwxr-xr-xmtkbt/code/bt/service/common/README18
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/AdvertiseData.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/AdvertiseSettings.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/BluetoothGattService.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetooth.aidl50
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothCallback.aidl21
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl26
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl21
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl44
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl47
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl35
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl24
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl32
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl24
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl33
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl26
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/ScanFilter.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/ScanResult.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/ScanSettings.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/UUID.aidl19
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/advertise_data.cc35
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/advertise_data.h54
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/advertise_settings.cc63
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/advertise_settings.h56
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc84
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h55
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc60
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h55
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc58
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h67
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc86
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.h59
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_filter.cc93
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_filter.h54
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_result.cc60
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_result.h54
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_settings.cc80
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/scan_settings.h54
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/uuid.cc91
-rwxr-xr-xmtkbt/code/bt/service/common/android/bluetooth/uuid.h53
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/adapter_state.cc44
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/adapter_state.h43
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/advertise_data.cc83
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/advertise_data.h64
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/advertise_settings.cc47
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/advertise_settings.h96
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/characteristic.cc54
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/characteristic.h59
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/descriptor.cc46
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/descriptor.h45
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/low_energy_constants.h125
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_filter.cc92
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_filter.h77
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_result.cc42
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_result.h54
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_settings.cc55
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/scan_settings.h161
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/service.cc48
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/service.h63
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/util/address_helper.cc54
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/util/address_helper.h36
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/util/atomic_string.cc34
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/util/atomic_string.h40
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/uuid.cc160
-rwxr-xr-xmtkbt/code/bt/service/common/bluetooth/uuid.h109
-rwxr-xr-xmtkbt/code/bt/service/daemon.cc173
-rwxr-xr-xmtkbt/code/bt/service/daemon.h74
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetooth.txt119
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothCallback.txt26
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothGattClient.txt180
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothGattClientCallback.txt121
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothGattServer.txt75
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothGattServerCallback.txt134
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothLowEnergy.txt97
-rwxr-xr-xmtkbt/code/bt/service/doc/IBluetoothLowEnergyCallback.txt54
-rwxr-xr-xmtkbt/code/bt/service/example/heart_rate/constants.h45
-rwxr-xr-xmtkbt/code/bt/service/example/heart_rate/heart_rate_server.cc493
-rwxr-xr-xmtkbt/code/bt/service/example/heart_rate/heart_rate_server.h144
-rwxr-xr-xmtkbt/code/bt/service/example/heart_rate/server_main.cc160
-rwxr-xr-xmtkbt/code/bt/service/gatt_client.cc102
-rwxr-xr-xmtkbt/code/bt/service/gatt_client.h83
-rwxr-xr-xmtkbt/code/bt/service/gatt_server.cc635
-rwxr-xr-xmtkbt/code/bt/service/gatt_server.h296
-rwxr-xr-xmtkbt/code/bt/service/gatt_server_old.cc729
-rwxr-xr-xmtkbt/code/bt/service/gatt_server_old.h126
-rwxr-xr-xmtkbt/code/bt/service/hal/bluetooth_gatt_interface.cc821
-rwxr-xr-xmtkbt/code/bt/service/hal/bluetooth_gatt_interface.h262
-rwxr-xr-xmtkbt/code/bt/service/hal/bluetooth_interface.cc406
-rwxr-xr-xmtkbt/code/bt/service/hal/bluetooth_interface.h128
-rwxr-xr-xmtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.cc325
-rwxr-xr-xmtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.h150
-rwxr-xr-xmtkbt/code/bt/service/hal/fake_bluetooth_interface.cc164
-rwxr-xr-xmtkbt/code/bt/service/hal/fake_bluetooth_interface.h75
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.cc253
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.h124
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc89
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h75
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc309
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h117
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc184
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h85
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc148
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h87
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc181
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h91
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/interface_with_instances_base.cc152
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/interface_with_instances_base.h105
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/ipc_handler_binder.cc79
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/ipc_handler_binder.h45
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/remote_callback_list.h205
-rwxr-xr-xmtkbt/code/bt/service/ipc/binder/remote_callback_map.h246
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_handler.cc31
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_handler.h62
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_handler_linux.cc207
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_handler_linux.h89
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_manager.cc76
-rwxr-xr-xmtkbt/code/bt/service/ipc/ipc_manager.h100
-rwxr-xr-xmtkbt/code/bt/service/ipc/linux_ipc_host.cc338
-rwxr-xr-xmtkbt/code/bt/service/ipc/linux_ipc_host.h107
-rwxr-xr-xmtkbt/code/bt/service/logging_helpers.cc149
-rwxr-xr-xmtkbt/code/bt/service/logging_helpers.h47
-rwxr-xr-xmtkbt/code/bt/service/low_energy_advertiser.cc349
-rwxr-xr-xmtkbt/code/bt/service/low_energy_advertiser.h145
-rwxr-xr-xmtkbt/code/bt/service/low_energy_client.cc261
-rwxr-xr-xmtkbt/code/bt/service/low_energy_client.h175
-rwxr-xr-xmtkbt/code/bt/service/low_energy_scanner.cc227
-rwxr-xr-xmtkbt/code/bt/service/low_energy_scanner.h161
-rwxr-xr-xmtkbt/code/bt/service/main.cc81
-rwxr-xr-xmtkbt/code/bt/service/settings.cc82
-rwxr-xr-xmtkbt/code/bt/service/settings.h71
-rwxr-xr-xmtkbt/code/bt/service/switches.h42
-rwxr-xr-xmtkbt/code/bt/service/test/ParcelableTest.aidl30
-rwxr-xr-xmtkbt/code/bt/service/test/adapter_unittest.cc284
-rwxr-xr-xmtkbt/code/bt/service/test/advertise_data_unittest.cc112
-rwxr-xr-xmtkbt/code/bt/service/test/fake_hal_util.cc25
-rwxr-xr-xmtkbt/code/bt/service/test/gatt_client_unittest.cc163
-rwxr-xr-xmtkbt/code/bt/service/test/gatt_server_unittest.cc730
-rwxr-xr-xmtkbt/code/bt/service/test/ipc_linux_unittest.cc205
-rwxr-xr-xmtkbt/code/bt/service/test/low_energy_advertiser_unittest.cc639
-rwxr-xr-xmtkbt/code/bt/service/test/low_energy_client_unittest.cc304
-rwxr-xr-xmtkbt/code/bt/service/test/low_energy_scanner_unittest.cc354
-rwxr-xr-xmtkbt/code/bt/service/test/main.cc32
-rwxr-xr-xmtkbt/code/bt/service/test/mock_adapter.h56
-rwxr-xr-xmtkbt/code/bt/service/test/mock_daemon.h41
-rwxr-xr-xmtkbt/code/bt/service/test/parcelable_unittest.cc211
-rwxr-xr-xmtkbt/code/bt/service/test/settings_unittest.cc100
-rwxr-xr-xmtkbt/code/bt/service/test/stub_ipc_handler_binder.cc48
-rwxr-xr-xmtkbt/code/bt/service/test/stub_ipc_handler_linux.cc71
-rwxr-xr-xmtkbt/code/bt/service/test/util_unittest.cc46
-rwxr-xr-xmtkbt/code/bt/service/test/uuid_unittest.cc160
-rwxr-xr-xmtkbt/code/bt/stack/Android.bp291
-rwxr-xr-xmtkbt/code/bt/stack/BUILD.gn266
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_aac.cc1464
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_aac_encoder.cc694
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_api.cc393
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_codec_config.cc1316
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_int.h65
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_sbc.cc1670
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_sbc_encoder.cc921
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_sbc_up_sample.cc370
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor.cc571
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx.cc889
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_encoder.cc504
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd.cc917
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc499
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac.cc1184
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_abr.cc168
-rwxr-xr-xmtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_encoder.cc789
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_api.cc430
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_bcb_act.cc679
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_ccb.cc137
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_defs.h63
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_int.h223
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_l2c.cc412
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_l2c_br.cc417
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_lcb.cc394
-rwxr-xr-xmtkbt/code/bt/stack/avct/avct_lcb_act.cc634
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_ad.cc573
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_api.cc1161
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_ccb.cc522
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_ccb_act.cc1032
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_defs.h242
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_int.h715
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_l2c.cc517
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_msg.cc1665
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_scb.cc993
-rwxr-xr-xmtkbt/code/bt/stack/avdt/avdt_scb_act.cc1454
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_api.cc1368
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_bld_ct.cc664
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_bld_tg.cc1523
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_int.h176
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_opt.cc226
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_pars_ct.cc688
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_pars_tg.cc549
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_sdp.cc341
-rwxr-xr-xmtkbt/code/bt/stack/avrc/avrc_utils.cc234
-rwxr-xr-xmtkbt/code/bt/stack/bnep/bnep_api.cc693
-rwxr-xr-xmtkbt/code/bt/stack/bnep/bnep_int.h234
-rwxr-xr-xmtkbt/code/bt/stack/bnep/bnep_main.cc734
-rwxr-xr-xmtkbt/code/bt/stack/bnep/bnep_utils.cc1324
-rwxr-xr-xmtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.cc715
-rwxr-xr-xmtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.h95
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_acl.cc2424
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble.cc2481
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_addr.cc522
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_adv_filter.cc849
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_batchscan.cc552
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_bgconn.cc652
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_cont_energy.cc99
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_gap.cc2805
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_int.h204
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_int_types.h330
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_multi_adv.cc884
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_ble_privacy.cc943
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_dev.cc574
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_devctl.cc842
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_inq.cc2687
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_int.h281
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_int_types.h885
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_main.cc101
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_pm.cc953
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_sco.cc1869
-rwxr-xr-xmtkbt/code/bt/stack/btm/btm_sec.cc6246
-rwxr-xr-xmtkbt/code/bt/stack/btu/btu_hcif.cc1746
-rwxr-xr-xmtkbt/code/bt/stack/btu/btu_init.cc159
-rwxr-xr-xmtkbt/code/bt/stack/btu/btu_task.cc196
-rwxr-xr-xmtkbt/code/bt/stack/gap/gap_api.cc69
-rwxr-xr-xmtkbt/code/bt/stack/gap/gap_ble.cc771
-rwxr-xr-xmtkbt/code/bt/stack/gap/gap_conn.cc1137
-rwxr-xr-xmtkbt/code/bt/stack/gap/gap_int.h150
-rwxr-xr-xmtkbt/code/bt/stack/gap/gap_utils.cc129
-rwxr-xr-xmtkbt/code/bt/stack/gatt/att_protocol.cc570
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_api.cc1485
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_attr.cc500
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_auth.cc475
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_cl.cc1150
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_db.cc774
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_int.h609
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_main.cc1217
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_sr.cc1268
-rwxr-xr-xmtkbt/code/bt/stack/gatt/gatt_utils.cc2021
-rwxr-xr-xmtkbt/code/bt/stack/hcic/hciblecmds.cc798
-rwxr-xr-xmtkbt/code/bt/stack/hcic/hcicmds.cc1388
-rwxr-xr-xmtkbt/code/bt/stack/hid/hid_conn.h68
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidd_api.cc633
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidd_conn.cc980
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidd_int.h94
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidh_api.cc597
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidh_conn.cc1142
-rwxr-xr-xmtkbt/code/bt/stack/hid/hidh_int.h82
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_aac.h258
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_aac_constants.h65
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_aac_encoder.h60
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_api.h209
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_codec_api.h691
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_constants.h47
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_error_codes.h133
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_sbc.h266
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_sbc_constants.h71
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_sbc_encoder.h63
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_sbc_up_sample.h163
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor.h204
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx.h151
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx_constants.h36
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx_encoder.h61
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd.h152
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_constants.h38
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_encoder.h61
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_ldac.h158
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_ldac_abr.h62
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_ldac_constants.h59
-rwxr-xr-xmtkbt/code/bt/stack/include/a2dp_vendor_ldac_encoder.h64
-rwxr-xr-xmtkbt/code/bt/stack/include/advertise_data_parser.h88
-rwxr-xr-xmtkbt/code/bt/stack/include/avct_api.h276
-rwxr-xr-xmtkbt/code/bt/stack/include/avdt_api.h937
-rwxr-xr-xmtkbt/code/bt/stack/include/avdtc_api.h236
-rwxr-xr-xmtkbt/code/bt/stack/include/avrc_api.h717
-rwxr-xr-xmtkbt/code/bt/stack/include/avrc_defs.h1537
-rwxr-xr-xmtkbt/code/bt/stack/include/ble_advertiser.h160
-rwxr-xr-xmtkbt/code/bt/stack/include/bnep_api.h428
-rwxr-xr-xmtkbt/code/bt/stack/include/bt_types.h1015
-rwxr-xr-xmtkbt/code/bt/stack/include/btm_api.h2076
-rwxr-xr-xmtkbt/code/bt/stack/include/btm_api_types.h1881
-rwxr-xr-xmtkbt/code/bt/stack/include/btm_ble_api.h828
-rwxr-xr-xmtkbt/code/bt/stack/include/btm_ble_api_types.h560
-rwxr-xr-xmtkbt/code/bt/stack/include/btu.h78
-rwxr-xr-xmtkbt/code/bt/stack/include/gap_api.h399
-rwxr-xr-xmtkbt/code/bt/stack/include/gatt_api.h1110
-rwxr-xr-xmtkbt/code/bt/stack/include/gattdefs.h130
-rwxr-xr-xmtkbt/code/bt/stack/include/hcidefs.h3200
-rwxr-xr-xmtkbt/code/bt/stack/include/hcimsgs.h878
-rwxr-xr-xmtkbt/code/bt/stack/include/hidd_api.h260
-rwxr-xr-xmtkbt/code/bt/stack/include/hiddefs.h156
-rwxr-xr-xmtkbt/code/bt/stack/include/hidh_api.h245
-rwxr-xr-xmtkbt/code/bt/stack/include/l2c_api.h1252
-rwxr-xr-xmtkbt/code/bt/stack/include/l2cap_client.h79
-rwxr-xr-xmtkbt/code/bt/stack/include/l2cdefs.h395
-rwxr-xr-xmtkbt/code/bt/stack/include/mca_api.h553
-rwxr-xr-xmtkbt/code/bt/stack/include/mca_defs.h126
-rwxr-xr-xmtkbt/code/bt/stack/include/pan_api.h423
-rwxr-xr-xmtkbt/code/bt/stack/include/port_api.h652
-rwxr-xr-xmtkbt/code/bt/stack/include/port_ext.h32
-rwxr-xr-xmtkbt/code/bt/stack/include/profiles_api.h75
-rwxr-xr-xmtkbt/code/bt/stack/include/rfcdefs.h245
-rwxr-xr-xmtkbt/code/bt/stack/include/sdp_api.h645
-rwxr-xr-xmtkbt/code/bt/stack/include/sdpdefs.h337
-rwxr-xr-xmtkbt/code/bt/stack/include/smp_api.h241
-rwxr-xr-xmtkbt/code/bt/stack/include/smp_api_types.h281
-rwxr-xr-xmtkbt/code/bt/stack/include/srvc_api.h199
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_api.cc2274
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_ble.cc1480
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_csm.cc1444
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_fcr.cc2457
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_int.h846
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_link.cc1465
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_main.cc918
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_ucd.cc1114
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2c_utils.cc3577
-rwxr-xr-xmtkbt/code/bt/stack/l2cap/l2cap_client.cc464
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_api.cc857
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_cact.cc547
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_csm.cc328
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_dact.cc156
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_dsm.cc295
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_int.h370
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_l2c.cc538
-rwxr-xr-xmtkbt/code/bt/stack/mcap/mca_main.cc564
-rwxr-xr-xmtkbt/code/bt/stack/pan/pan_api.cc704
-rwxr-xr-xmtkbt/code/bt/stack/pan/pan_int.h128
-rwxr-xr-xmtkbt/code/bt/stack/pan/pan_main.cc718
-rwxr-xr-xmtkbt/code/bt/stack/pan/pan_utils.cc321
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/port_api.cc1769
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/port_int.h241
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/port_rfc.cc1019
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/port_utils.cc535
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_int.h378
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_l2cap_if.cc412
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_mx_fsm.cc669
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_port_fsm.cc864
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_port_if.cc332
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_ts_frames.cc805
-rwxr-xr-xmtkbt/code/bt/stack/rfcomm/rfc_utils.cc445
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_api.cc1147
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_db.cc905
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_discovery.cc974
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_main.cc677
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_server.cc871
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdp_utils.cc927
-rwxr-xr-xmtkbt/code/bt/stack/sdp/sdpint.h305
-rwxr-xr-xmtkbt/code/bt/stack/smp/aes.cc953
-rwxr-xr-xmtkbt/code/bt/stack/smp/aes.h154
-rwxr-xr-xmtkbt/code/bt/stack/smp/p_256_curvepara.cc77
-rwxr-xr-xmtkbt/code/bt/stack/smp/p_256_ecc_pp.cc247
-rwxr-xr-xmtkbt/code/bt/stack/smp/p_256_ecc_pp.h63
-rwxr-xr-xmtkbt/code/bt/stack/smp/p_256_multprecision.cc614
-rwxr-xr-xmtkbt/code/bt/stack/smp/p_256_multprecision.h68
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_act.cc2017
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_api.cc576
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_br_main.cc352
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_cmac.cc313
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_int.h545
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_keys.cc1924
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_l2c.cc321
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_main.cc1032
-rwxr-xr-xmtkbt/code/bt/stack/smp/smp_utils.cc1532
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_battery.cc362
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_battery_int.h66
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_dis.cc476
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_dis_int.h66
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_eng.cc440
-rwxr-xr-xmtkbt/code/bt/stack/srvc/srvc_eng_int.h69
-rwxr-xr-xmtkbt/code/bt/stack/test/ad_parser_unittest.cc81
-rwxr-xr-xmtkbt/code/bt/stack/test/ble_advertiser_test.cc745
-rwxr-xr-xmtkbt/code/bt/stack/test/stack_a2dp_test.cc944
-rwxr-xr-xmtkbt/code/bt/stack/test/stack_smp_test.cc227
-rwxr-xr-xmtkbt/code/bt/test/Android.bp4
-rwxr-xr-xmtkbt/code/bt/test/README.md81
-rwxr-xr-xmtkbt/code/bt/test/rootcanal/Android.bp56
-rwxr-xr-xmtkbt/code/bt/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc4
-rwxr-xr-xmtkbt/code/bt/test/rootcanal/bluetooth_hci.cc183
-rwxr-xr-xmtkbt/code/bt/test/rootcanal/bluetooth_hci.h79
-rwxr-xr-xmtkbt/code/bt/test/rootcanal/service.cc40
-rwxr-xr-xmtkbt/code/bt/test/run_unit_tests.sh138
-rwxr-xr-xmtkbt/code/bt/test/suite/Android.bp50
-rwxr-xr-xmtkbt/code/bt/test/suite/BUILD.gn45
-rwxr-xr-xmtkbt/code/bt/test/suite/adapter/adapter_unittest.cc195
-rwxr-xr-xmtkbt/code/bt/test/suite/adapter/bluetooth_test.cc150
-rwxr-xr-xmtkbt/code/bt/test/suite/adapter/bluetooth_test.h120
-rwxr-xr-xmtkbt/code/bt/test/suite/gatt/gatt_test.cc143
-rwxr-xr-xmtkbt/code/bt/test/suite/gatt/gatt_test.h130
-rwxr-xr-xmtkbt/code/bt/test/suite/gatt/gatt_unittest.cc116
-rwxr-xr-xmtkbt/code/bt/test/suite/rfcomm/rfcomm_test.cc85
-rwxr-xr-xmtkbt/code/bt/test/suite/rfcomm/rfcomm_test.h47
-rwxr-xr-xmtkbt/code/bt/test/suite/rfcomm/rfcomm_unittest.cc136
-rwxr-xr-xmtkbt/code/bt/tools/Android.mk.disabled1
-rwxr-xr-xmtkbt/code/bt/tools/bdtool/Android.mk.disabled49
-rwxr-xr-xmtkbt/code/bt/tools/bdtool/adapter.c275
-rwxr-xr-xmtkbt/code/bt/tools/bdtool/bdtool.c361
-rwxr-xr-xmtkbt/code/bt/tools/hci/Android.mk.disabled34
-rwxr-xr-xmtkbt/code/bt/tools/hci/main.c215
-rwxr-xr-xmtkbt/code/bt/tools/scripts/btsnooz.py167
-rwxr-xr-xmtkbt/code/bt/tools/scripts/change_types.sh85
-rwxr-xr-xmtkbt/code/bt/tools/scripts/viewbtsnoop.sh74
-rwxr-xr-xmtkbt/code/bt/udrv/Android.bp19
-rwxr-xr-xmtkbt/code/bt/udrv/BUILD.gn30
-rwxr-xr-xmtkbt/code/bt/udrv/include/uipc.h126
-rwxr-xr-xmtkbt/code/bt/udrv/ulinux/uipc.cc769
-rwxr-xr-xmtkbt/code/bt/utils/Android.bp15
-rwxr-xr-xmtkbt/code/bt/utils/BUILD.gn27
-rwxr-xr-xmtkbt/code/bt/utils/include/bt_utils.h42
-rwxr-xr-xmtkbt/code/bt/utils/src/bt_utils.cc178
-rwxr-xr-xmtkbt/code/bt/vendor_libs/Android.bp3
-rwxr-xr-xmtkbt/code/bt/vendor_libs/Android.mk28
-rwxr-xr-xmtkbt/code/bt/vendor_libs/linux/Android.mk47
-rwxr-xr-xmtkbt/code/bt/vendor_libs/linux/bt_vendor_linux.cc411
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/Android.bp81
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/data/controller_properties.json13
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/async_manager.h115
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/bt_address.h87
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/command_packet.h81
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h547
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/event_packet.h158
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet.h95
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet_stream.h66
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h65
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh127
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py247
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/async_manager.cc518
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/bt_address.cc84
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/command_packet.cc49
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc747
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/event_packet.cc328
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet.cc108
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc129
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc142
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc174
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc194
-rwxr-xr-xmtkbt/code/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc154
-rwxr-xr-xmtkbt/code/bt/vnd/ble/vendor_hcidefs.h52
-rwxr-xr-xmtkbt/code/bt/vnd/include/vendor_api.h23
-rwxr-xr-xmtkbt/code/libdriver/Android.mk57
-rwxr-xr-xmtkbt/code/libdriver/bperf_util.c1249
-rwxr-xr-xmtkbt/code/libdriver/bperf_util.h85
-rwxr-xr-xmtkbt/code/libdriver/bt_drv.c425
-rwxr-xr-xmtkbt/code/libdriver/bt_drv.h102
-rwxr-xr-xmtkbt/code/libdriver/bt_mtk.h105
-rwxr-xr-xmtkbt/code/libdriver/mtk.c227
-rwxr-xr-xmtkbt/code/libdriver/os_dep.h115
-rwxr-xr-xmtkbt/code/libdriver/platform.c295
-rwxr-xr-xmtkbt/code/libdriver/radiomgr.c57
-rwxr-xr-xmtkbt/mtkbt.mk8
-rwxr-xr-xrealtek/Android.mk2
957 files changed, 351867 insertions, 0 deletions
diff --git a/mtkbt/Android.mk b/mtkbt/Android.mk
new file mode 100755
index 0000000..935aa57
--- a/dev/null
+++ b/mtkbt/Android.mk
@@ -0,0 +1,4 @@
+ifeq ($(BOARD_HAVE_BLUETOOTH_MTK),true)
+LOCAL_PATH := $(call my-dir)
+include $(call all-subdir-makefiles)
+endif
diff --git a/mtkbt/code/Android.mk b/mtkbt/code/Android.mk
new file mode 100755
index 0000000..935aa57
--- a/dev/null
+++ b/mtkbt/code/Android.mk
@@ -0,0 +1,4 @@
+ifeq ($(BOARD_HAVE_BLUETOOTH_MTK),true)
+LOCAL_PATH := $(call my-dir)
+include $(call all-subdir-makefiles)
+endif
diff --git a/mtkbt/code/bt/.gitignore b/mtkbt/code/bt/.gitignore
new file mode 100755
index 0000000..3301466
--- a/dev/null
+++ b/mtkbt/code/bt/.gitignore
@@ -0,0 +1,2 @@
+out
+third_party
diff --git a/mtkbt/code/bt/.gn b/mtkbt/code/bt/.gn
new file mode 100755
index 0000000..947ebac
--- a/dev/null
+++ b/mtkbt/code/bt/.gn
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This file is used by the GN meta build system to find the root of the source
+# tree and to set startup options. For documentation on the values set in this
+# file, run "gn help dotfile" at the command line.
+
+buildconfig = "//build/config/BUILDCONFIG.gn"
+secondary_source = "//build/secondary/"
diff --git a/mtkbt/code/bt/Android.bp b/mtkbt/code/bt/Android.bp
new file mode 100755
index 0000000..7e578d7
--- a/dev/null
+++ b/mtkbt/code/bt/Android.bp
@@ -0,0 +1,19 @@
+subdirs = [
+ "build",
+ "btif",
+ "btcore",
+ "audio_a2dp_hw",
+ "hci",
+ "utils",
+ "device",
+ "stack",
+ "osi",
+ "embdrv",
+ "service",
+ "main",
+ "bta",
+ "vendor_libs",
+ "test",
+ "udrv",
+ "mediatek",
+]
diff --git a/mtkbt/code/bt/Android.mk b/mtkbt/code/bt/Android.mk
new file mode 100755
index 0000000..3176979
--- a/dev/null
+++ b/mtkbt/code/bt/Android.mk
@@ -0,0 +1 @@
+#include $(call all-subdir-makefiles)
diff --git a/mtkbt/code/bt/BUILD.gn b/mtkbt/code/bt/BUILD.gn
new file mode 100755
index 0000000..3cb29e1
--- a/dev/null
+++ b/mtkbt/code/bt/BUILD.gn
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This is the root build file for GN. GN will start processing by loading this
+# file, and recursively load all dependencies until all dependencies are either
+# resolved or known not to exist (which will cause the build to fail). So if
+# you add a new build file, there must be some path of dependencies from this
+# file to your new one or GN won't know about it.
+
+# This pulls in main/BUILD.gn and all of its dependencies.
+group("bluetooth") {
+ deps = [
+ "//main:bluetooth.default",
+ "//service:bluetoothtbd",
+ ]
+}
+
+group("bluetooth_tests") {
+ testonly = true
+
+ deps = [
+ "//test/suite:net_test_bluetooth",
+ "//btcore:net_test_btcore",
+ "//hci:net_test_hci",
+ "//osi:net_test_osi",
+ "//device:net_test_device",
+ ]
+}
diff --git a/mtkbt/code/bt/CleanSpec.mk b/mtkbt/code/bt/CleanSpec.mk
new file mode 100755
index 0000000..518119b
--- a/dev/null
+++ b/mtkbt/code/bt/CleanSpec.mk
@@ -0,0 +1,53 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Start of Clean Step list:
+$(call add-clean-step, find $(OUT_DIR) -type f -iname "*blue*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, find $(OUT_DIR) -type f -iname "*bdroid*" -print0 | xargs -0 rm -f)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/mtkbt/code/bt/EventLogTags.logtags b/mtkbt/code/bt/EventLogTags.logtags
new file mode 100755
index 0000000..dc1d239
--- a/dev/null
+++ b/mtkbt/code/bt/EventLogTags.logtags
@@ -0,0 +1,38 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1010000 bt_hci_timeout (opcode|1)
+1010001 bt_config_source (opcode|1)
+1010002 bt_hci_unknown_type (hci_type|1)
diff --git a/mtkbt/code/bt/MODULE_LICENSE_APACHE2 b/mtkbt/code/bt/MODULE_LICENSE_APACHE2
new file mode 100755
index 0000000..e69de29
--- a/dev/null
+++ b/mtkbt/code/bt/MODULE_LICENSE_APACHE2
diff --git a/mtkbt/code/bt/NOTICE b/mtkbt/code/bt/NOTICE
new file mode 100755
index 0000000..d645695
--- a/dev/null
+++ b/mtkbt/code/bt/NOTICE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/mtkbt/code/bt/OWNERS b/mtkbt/code/bt/OWNERS
new file mode 100755
index 0000000..6128a94
--- a/dev/null
+++ b/mtkbt/code/bt/OWNERS
@@ -0,0 +1,13 @@
+set noparent
+
+# Project owners
+eisenbach@google.com
+apanicke@google.com
+jamuraa@google.com
+jpawlowski@google.com
+mylesgw@google.com
+pavlin@google.com
+
+# Android Team (rollbacks, global changes etc.)
+bsears@google.com
+ijpedowitz@google.com
diff --git a/mtkbt/code/bt/PREUPLOAD.cfg b/mtkbt/code/bt/PREUPLOAD.cfg
new file mode 100755
index 0000000..7fb1636
--- a/dev/null
+++ b/mtkbt/code/bt/PREUPLOAD.cfg
@@ -0,0 +1,6 @@
+[Options]
+ignore_merged_commits = true
+
+[Builtin Hooks]
+clang_format = true
+
diff --git a/mtkbt/code/bt/README.md b/mtkbt/code/bt/README.md
new file mode 100755
index 0000000..e937e81
--- a/dev/null
+++ b/mtkbt/code/bt/README.md
@@ -0,0 +1,113 @@
+# Fluoride Bluetooth stack
+
+## Building and running on AOSP
+Just build AOSP - Fluoride is there by default.
+
+## Building and running on Linux
+
+Instructions for Ubuntu, tested on 14.04 with Clang 3.5.0 and 16.10 with Clang
+ 3.8.0
+
+### Download source
+
+```sh
+mkdir ~/fluoride
+cd ~/fluoride
+git clone https://android.googlesource.com/platform/system/bt
+```
+
+Install dependencies (require sudo access):
+
+```sh
+cd ~/fluoride/bt
+build/install_deps.sh
+```
+
+Then fetch third party dependencies:
+
+```sh
+cd ~/fluoride/bt
+mkdir third_party
+cd third_party
+git clone https://github.com/google/googletest.git
+git clone https://android.googlesource.com/platform/external/aac
+git clone https://android.googlesource.com/platform/external/libchrome
+git clone https://android.googlesource.com/platform/external/libldac
+git clone https://android.googlesource.com/platform/external/modp_b64
+git clone https://android.googlesource.com/platform/external/tinyxml2
+git clone https://android.googlesource.com/platform/hardware/libhardware
+```
+
+And third party dependencies of third party dependencies:
+
+```sh
+cd fluoride/bt/third_party/libchrome/base/third_party
+mkdir valgrind
+cd valgrind
+curl https://chromium.googlesource.com/chromium/src/base/+/master/third_party/valgrind/valgrind.h?format=TEXT | base64 -d > valgrind.h
+curl https://chromium.googlesource.com/chromium/src/base/+/master/third_party/valgrind/memcheck.h?format=TEXT | base64 -d > memcheck.h
+```
+
+NOTE: If system/bt is checked out under AOSP, then create symbolic links instead
+of downloading sources
+
+```
+cd system/bt
+mkdir third_party
+cd third_party
+ln -s ../../../external/aac aac
+ln -s ../../../external/libchrome libchrome
+ln -s ../../../external/libldac libldac
+ln -s ../../../external/modp_b64 modp_b64
+ln -s ../../../external/tinyxml2 tinyxml2
+ln -s ../../../hardware/libhardware libhardware
+ln -s ../../../external/googletest googletest
+```
+
+### Generate your build files
+
+```sh
+cd ~/fluoride/bt
+gn gen out/Default
+```
+
+### Build
+
+```sh
+cd ~/fluoride/bt
+ninja -C out/Default all
+```
+
+This will build all targets (the shared library, executables, tests, etc) and
+ put them in out/Default. To build an individual target, replace "all" with the
+ target of your choice, e.g. ```ninja -C out/Default net_test_osi```.
+
+### Run
+
+```sh
+cd ~/fluoride/bt/out/Default
+LD_LIBRARY_PATH=./ ./bluetoothtbd -create-ipc-socket=fluoride
+```
+
+### Eclipse IDE Support
+
+1. Follows the Chromium project
+ [Eclipse Setup Instructions](https://chromium.googlesource.com/chromium/src/+/master/docs/linux_eclipse_dev.md)
+ until "Optional: Building inside Eclipse" section (don't do that section, we
+ will set it up differently)
+
+2. Generate Eclipse settings:
+
+ ```sh
+ cd system/bt
+ gn gen --ide=eclipse out/Default
+ ```
+
+3. In Eclipse, do File->Import->C/C++->C/C++ Project Settings, choose the XML
+ location under system/bt/out/Default
+
+4. Right click on the project. Go to Preferences->C/C++ Build->Builder Settings.
+ Uncheck "Use default build command", but instead using "ninja -C out/Default"
+
+5. Goto Behaviour tab, change clean command to "-t clean"
+
diff --git a/mtkbt/code/bt/audio_a2dp_hw/Android.bp b/mtkbt/code/bt/audio_a2dp_hw/Android.bp
new file mode 100755
index 0000000..7aa45cf
--- a/dev/null
+++ b/mtkbt/code/bt/audio_a2dp_hw/Android.bp
@@ -0,0 +1,53 @@
+cc_defaults {
+ name: "audio_a2dp_hw_defaults",
+ defaults: ["fluoride_defaults"],
+ include_dirs: [
+ "hardware/mtk/bluetooth/mtkbt/code/bt",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/audio_a2dp_hw/include",
+ ]
+}
+
+// Audio A2DP shared library for target
+// ========================================================
+cc_library {
+ name: "audio.a2dp.default",
+ defaults: ["audio_a2dp_hw_defaults"],
+ relative_install_path: "hw",
+ srcs: [
+ "src/audio_a2dp_hw.cc",
+ "src/audio_a2dp_hw_utils.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ /** M: Change Feature for A2DP PCM dump @{ */
+ "libcutils",
+ /** @} */
+ ],
+ static_libs: ["libosi"],
+}
+
+cc_library_static {
+ name: "libaudio-a2dp-hw-utils",
+ defaults: ["audio_a2dp_hw_defaults"],
+ srcs: [
+ "src/audio_a2dp_hw_utils.cc",
+ ],
+}
+
+// Audio A2DP library unit tests for target and host
+// ========================================================
+cc_test {
+ name: "net_test_audio_a2dp_hw",
+ test_suites: ["device-tests"],
+ defaults: ["audio_a2dp_hw_defaults"],
+ srcs: [
+ "test/audio_a2dp_hw_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "audio.a2dp.default",
+ "libosi",
+ ],
+}
diff --git a/mtkbt/code/bt/audio_a2dp_hw/include/audio_a2dp_hw.h b/mtkbt/code/bt/audio_a2dp_hw/include/audio_a2dp_hw.h
new file mode 100755
index 0000000..f725475
--- a/dev/null
+++ b/mtkbt/code/bt/audio_a2dp_hw/include/audio_a2dp_hw.h
@@ -0,0 +1,154 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: audio_a2dp_hw.h
+ *
+ * Description:
+ *
+ *****************************************************************************/
+
+#ifndef AUDIO_A2DP_HW_H
+#define AUDIO_A2DP_HW_H
+
+#include <stdint.h>
+
+#include <hardware/bt_av.h>
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#include "mtk_bt_av.h"
+#endif
+
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+#define A2DP_AUDIO_HARDWARE_INTERFACE "audio.a2dp"
+#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
+#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
+
+// AUDIO_STREAM_OUTPUT_BUFFER_SZ controls the size of the audio socket buffer.
+// If one assumes the write buffer is always full during normal BT playback,
+// then increasing this value increases our playback latency.
+//
+// FIXME: The BT HAL should consume data at a constant rate.
+// AudioFlinger assumes that the HAL draws data at a constant rate, which is
+// true for most audio devices; however, the BT engine reads data at a variable
+// rate (over the short term), which confuses both AudioFlinger as well as
+// applications which deliver data at a (generally) fixed rate.
+//
+// 20 * 512 is not sufficient to smooth the variability for some BT devices,
+// resulting in mixer sleep and throttling. We increase this to 28 * 512 to help
+// reduce the effect of variable data consumption.
+#define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512)
+#define AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ 256
+
+// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is divided
+// for AudioFlinger data delivery. The AudioFlinger mixer delivers data in
+// chunks of AUDIO_STREAM_OUTPUT_BUFFER_SZ / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS.
+// If the number of periods is 2, the socket buffer represents "double
+// buffering" of the AudioFlinger mixer buffer.
+//
+// In general, AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 * 4 should be a divisor
+// of AUDIO_STREAM_OUTPUT_BUFFER_SZ.
+//
+// These values should be chosen such that
+//
+// AUDIO_STREAM_BUFFER_SIZE * 1000 / (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS
+// * AUDIO_STREAM_DEFAULT_RATE * 4) > 20 (ms)
+//
+// to avoid introducing the FastMixer in AudioFlinger. Using the FastMixer
+// results in unnecessary latency and CPU overhead for Bluetooth.
+#define AUDIO_STREAM_OUTPUT_BUFFER_PERIODS 2
+
+#define AUDIO_SKT_DISCONNECTED (-1)
+
+typedef enum {
+ A2DP_CTRL_CMD_NONE,
+ A2DP_CTRL_CMD_CHECK_READY,
+ A2DP_CTRL_CMD_START,
+ A2DP_CTRL_CMD_STOP,
+ A2DP_CTRL_CMD_SUSPEND,
+ A2DP_CTRL_GET_INPUT_AUDIO_CONFIG,
+ A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG,
+ A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG,
+ A2DP_CTRL_CMD_OFFLOAD_START,
+} tA2DP_CTRL_CMD;
+
+typedef enum {
+ A2DP_CTRL_ACK_SUCCESS,
+ A2DP_CTRL_ACK_FAILURE,
+ A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
+ A2DP_CTRL_ACK_UNSUPPORTED
+} tA2DP_CTRL_ACK;
+
+typedef uint32_t tA2DP_SAMPLE_RATE;
+typedef uint8_t tA2DP_CHANNEL_COUNT;
+typedef uint8_t tA2DP_BITS_PER_SAMPLE;
+
+/*****************************************************************************
+ * Type definitions for callback functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Type definitions and return values
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Extern variables and functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Functions
+ *****************************************************************************/
+
+// Computes the Audio A2DP HAL output buffer size.
+// |codec_sample_rate| is the sample rate of the output stream.
+// |codec_bits_per_sample| is the number of bits per sample of the output
+// stream.
+// |codec_channel_mode| is the channel mode of the output stream.
+//
+// The buffer size is computed by using the following formula:
+//
+// AUDIO_STREAM_OUTPUT_BUFFER_SIZE =
+// (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+// SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000
+//
+// AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is
+// divided for AudioFlinger data delivery. The AudioFlinger mixer delivers
+// data in chunks of
+// (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) .
+// If the number of periods is 2, the socket buffer represents "double
+// buffering" of the AudioFlinger mixer buffer.
+//
+// Furthermore, the AudioFlinger expects the buffer size to be a multiple
+// of 16 frames.
+//
+// NOTE: Currently, the computation uses the conservative 20ms time period.
+//
+// Returns the computed buffer size. If any of the input parameters is
+// invalid, the return value is the default |AUDIO_STREAM_OUTPUT_BUFFER_SZ|.
+extern size_t audio_a2dp_hw_stream_compute_buffer_size(
+ btav_a2dp_codec_sample_rate_t codec_sample_rate,
+ btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
+ btav_a2dp_codec_channel_mode_t codec_channel_mode);
+
+// Returns a string representation of |event|.
+extern const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event);
+
+#endif /* A2DP_AUDIO_HW_H */
diff --git a/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw.cc b/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw.cc
new file mode 100755
index 0000000..307d753
--- a/dev/null
+++ b/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw.cc
@@ -0,0 +1,1885 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: audio_a2dp_hw.c
+ *
+ * Description: Implements hal for bluedroid a2dp audio device
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_a2dp_hw"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+#include <system/audio.h>
+
+#include "osi/include/hash_map_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#include "audio_a2dp_hw.h"
+
+#if defined(MTK_A2DP_PCM_DUMP) && (MTK_A2DP_PCM_DUMP == TRUE)
+#include <cutils/properties.h>
+
+#define INVALID_FD (-1)
+#define MTK_PCM_DUMP_PROPERTY "mtk.a2dp.pcmdump"
+
+static const char *pcmfilename = "/sdcard/mtklog/btlog/bt_audio.pcm";
+static int dump_fd = INVALID_FD;
+#endif
+
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+/** M: Bug fix for suspend no response timeout, need wait response fail ack @{ */
+#define CTRL_CHAN_RETRY_COUNT 4
+/** @} */
+
+#define USEC_PER_SEC 1000000L
+#define SOCK_SEND_TIMEOUT_MS 2000 /* Timeout for sending */
+#define SOCK_RECV_TIMEOUT_MS 5000 /* Timeout for receiving */
+
+// set WRITE_POLL_MS to 0 for blocking sockets, nonzero for polled non-blocking
+// sockets
+#define WRITE_POLL_MS 20
+
+#define FNLOG() LOG_VERBOSE(LOG_TAG, "%s", __func__);
+#define DEBUG(fmt, ...) \
+ LOG_VERBOSE(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define INFO(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define WARN(fmt, ...) LOG_WARN(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define ERROR(fmt, ...) LOG_ERROR(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define ASSERTC(cond, msg, val) \
+ if (!(cond)) { \
+ ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, \
+ val); \
+ }
+
+/*****************************************************************************
+ * Local type definitions
+ *****************************************************************************/
+
+typedef enum {
+ AUDIO_A2DP_STATE_STARTING,
+ AUDIO_A2DP_STATE_STARTED,
+ AUDIO_A2DP_STATE_STOPPING,
+ AUDIO_A2DP_STATE_STOPPED,
+ /* need explicit set param call to resume (suspend=false) */
+ AUDIO_A2DP_STATE_SUSPENDED,
+ AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
+} a2dp_state_t;
+
+struct a2dp_stream_in;
+struct a2dp_stream_out;
+
+struct a2dp_audio_device {
+ // Important: device must be first as an audio_hw_device* may be cast to
+ // a2dp_audio_device* when the type is implicitly known.
+ struct audio_hw_device device;
+ std::recursive_mutex* mutex; // See note below on mutex acquisition order.
+ struct a2dp_stream_in* input;
+ struct a2dp_stream_out* output;
+};
+
+struct a2dp_config {
+ uint32_t rate;
+ uint32_t channel_mask;
+ int format;
+};
+
+/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
+
+struct a2dp_stream_common {
+ std::recursive_mutex* mutex; // See note below on mutex acquisition order.
+ int ctrl_fd;
+ int audio_fd;
+ size_t buffer_sz;
+ struct a2dp_config cfg;
+ a2dp_state_t state;
+};
+
+struct a2dp_stream_out {
+ struct audio_stream_out stream;
+ struct a2dp_stream_common common;
+ uint64_t frames_presented; // frames written, never reset
+ uint64_t frames_rendered; // frames written, reset on standby
+};
+
+struct a2dp_stream_in {
+ struct audio_stream_in stream;
+ struct a2dp_stream_common common;
+};
+
+/*
+ * Mutex acquisition order:
+ *
+ * The a2dp_audio_device (adev) mutex must be acquired before
+ * the a2dp_stream_common (out or in) mutex.
+ *
+ * This may differ from other audio HALs.
+ */
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Static functions
+ *****************************************************************************/
+
+static size_t out_get_buffer_size(const struct audio_stream* stream);
+
+/*****************************************************************************
+ * Externs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Functions
+ *****************************************************************************/
+static void a2dp_open_ctrl_path(struct a2dp_stream_common* common);
+
+/*****************************************************************************
+ * Miscellaneous helper functions
+ *****************************************************************************/
+
+/* logs timestamp with microsec precision
+ pprev is optional in case a dedicated diff is required */
+static void ts_log(UNUSED_ATTR const char* tag, UNUSED_ATTR int val,
+ struct timespec* pprev_opt) {
+ struct timespec now;
+ static struct timespec prev = {0, 0};
+ unsigned long long now_us;
+ unsigned long long diff_us;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ now_us = now.tv_sec * USEC_PER_SEC + now.tv_nsec / 1000;
+
+ if (pprev_opt) {
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC +
+ (now.tv_nsec - prev.tv_nsec) / 1000;
+ *pprev_opt = now;
+ DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
+ } else {
+ diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC +
+ (now.tv_nsec - prev.tv_nsec) / 1000;
+ prev = now;
+ DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
+ }
+}
+
+static int calc_audiotime_usec(struct a2dp_config cfg, int bytes) {
+ int chan_count = audio_channel_count_from_out_mask(cfg.channel_mask);
+ int bytes_per_sample;
+
+ switch (cfg.format) {
+ case AUDIO_FORMAT_PCM_8_BIT:
+ bytes_per_sample = 1;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ bytes_per_sample = 2;
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ bytes_per_sample = 3;
+ break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ bytes_per_sample = 4;
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ bytes_per_sample = 4;
+ break;
+ default:
+ ASSERTC(false, "unsupported sample format", cfg.format);
+ bytes_per_sample = 2;
+ break;
+ }
+
+ return (
+ int)(((int64_t)bytes * (USEC_PER_SEC / (chan_count * bytes_per_sample))) /
+ cfg.rate);
+}
+
+/*****************************************************************************
+ *
+ * bluedroid stack adaptation
+ *
+ ****************************************************************************/
+
+static int skt_connect(const char* path, size_t buffer_sz) {
+ int ret;
+ int skt_fd;
+ int len;
+
+ INFO("connect to %s (sz %zu)", path, buffer_sz);
+
+ skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+ if (osi_socket_local_client_connect(
+ skt_fd, path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0) {
+ ERROR("failed to connect (%s)", strerror(errno));
+ close(skt_fd);
+ return -1;
+ }
+
+ len = buffer_sz;
+ ret =
+ setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
+ if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+ ret =
+ setsockopt(skt_fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, (int)sizeof(len));
+ if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+ /* Socket send/receive timeout value */
+ struct timeval tv;
+ tv.tv_sec = SOCK_SEND_TIMEOUT_MS / 1000;
+ tv.tv_usec = (SOCK_SEND_TIMEOUT_MS % 1000) * 1000;
+
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+ tv.tv_sec = SOCK_RECV_TIMEOUT_MS / 1000;
+ tv.tv_usec = (SOCK_RECV_TIMEOUT_MS % 1000) * 1000;
+
+ ret = setsockopt(skt_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ if (ret < 0) ERROR("setsockopt failed (%s)", strerror(errno));
+
+ INFO("connected to stack fd = %d", skt_fd);
+
+ return skt_fd;
+}
+
+static int skt_read(int fd, void* p, size_t len) {
+ ssize_t read;
+
+ FNLOG();
+
+ ts_log("skt_read recv", len, NULL);
+
+ OSI_NO_INTR(read = recv(fd, p, len, MSG_NOSIGNAL));
+ if (read == -1) ERROR("read failed with errno=%d\n", errno);
+
+ return (int)read;
+}
+
+static int skt_write(int fd, const void* p, size_t len) {
+ ssize_t sent;
+ FNLOG();
+
+ ts_log("skt_write", len, NULL);
+
+ if (WRITE_POLL_MS == 0) {
+ // do not poll, use blocking send
+ OSI_NO_INTR(sent = send(fd, p, len, MSG_NOSIGNAL));
+ if (sent == -1) ERROR("write failed with error(%s)", strerror(errno));
+
+ return (int)sent;
+ }
+
+ // use non-blocking send, poll
+ int ms_timeout = SOCK_SEND_TIMEOUT_MS;
+ size_t count = 0;
+ while (count < len) {
+ OSI_NO_INTR(sent = send(fd, p, len - count, MSG_NOSIGNAL | MSG_DONTWAIT));
+ if (sent == -1) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ ERROR("write failed with error(%s)", strerror(errno));
+ return -1;
+ }
+ if (ms_timeout >= WRITE_POLL_MS) {
+ usleep(WRITE_POLL_MS * 1000);
+ ms_timeout -= WRITE_POLL_MS;
+ continue;
+ }
+ WARN("write timeout exceeded, sent %zu bytes", count);
+ return -1;
+ }
+ count += sent;
+ p = (const uint8_t*)p + sent;
+ }
+ return (int)count;
+}
+
+static int skt_disconnect(int fd) {
+ INFO("fd %d", fd);
+
+ if (fd != AUDIO_SKT_DISCONNECTED) {
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
+ }
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * AUDIO CONTROL PATH
+ *
+ ****************************************************************************/
+
+static int a2dp_ctrl_receive(struct a2dp_stream_common* common, void* buffer,
+ size_t length) {
+ ssize_t ret;
+ int i;
+
+ for (i = 0;; i++) {
+ OSI_NO_INTR(ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL));
+ if (ret > 0) {
+ break;
+ }
+ if (ret == 0) {
+ ERROR("receive control data failed: peer closed");
+ break;
+ }
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ ERROR("receive control data failed: error(%s)", strerror(errno));
+ break;
+ }
+ if (i == (CTRL_CHAN_RETRY_COUNT - 1)) {
+ ERROR("receive control data failed: max retry count");
+ break;
+ }
+ INFO("receive control data failed (%s), retrying", strerror(errno));
+ }
+ if (ret <= 0) {
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+ return ret;
+}
+
+// Sends control info for stream |common|. The data to send is stored in
+// |buffer| and has size |length|.
+// On success, returns the number of octets sent, otherwise -1.
+static int a2dp_ctrl_send(struct a2dp_stream_common* common, const void* buffer,
+ size_t length) {
+ ssize_t sent;
+ size_t remaining = length;
+ int i;
+
+ if (length == 0) return 0; // Nothing to do
+
+ for (i = 0;; i++) {
+ OSI_NO_INTR(sent = send(common->ctrl_fd, buffer, remaining, MSG_NOSIGNAL));
+ if (sent == static_cast<ssize_t>(remaining)) {
+ remaining = 0;
+ break;
+ }
+ if (sent > 0) {
+ buffer = (static_cast<const char*>(buffer) + sent);
+ remaining -= sent;
+ continue;
+ }
+ if (sent < 0) {
+ if (errno != EWOULDBLOCK && errno != EAGAIN) {
+ ERROR("send control data failed: error(%s)", strerror(errno));
+ break;
+ }
+ INFO("send control data failed (%s), retrying", strerror(errno));
+ }
+ if (i >= (CTRL_CHAN_RETRY_COUNT - 1)) {
+ ERROR("send control data failed: max retry count");
+ break;
+ }
+ }
+ if (remaining > 0) {
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ return -1;
+ }
+ return length;
+}
+
+static int a2dp_command(struct a2dp_stream_common* common, tA2DP_CTRL_CMD cmd) {
+ char ack;
+
+ DEBUG("A2DP COMMAND %s", audio_a2dp_hw_dump_ctrl_event(cmd));
+
+ if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+ INFO("starting up or recovering from previous error");
+ a2dp_open_ctrl_path(common);
+ if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+ ERROR("failure to open ctrl path");
+ return -1;
+ }
+ }
+
+ /* send command */
+ ssize_t sent;
+ OSI_NO_INTR(sent = send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL));
+ if (sent == -1) {
+ ERROR("cmd failed (%s)", strerror(errno));
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ return -1;
+ }
+
+ /* wait for ack byte */
+ if (a2dp_ctrl_receive(common, &ack, 1) < 0) {
+ ERROR("A2DP COMMAND %s: no ACK", audio_a2dp_hw_dump_ctrl_event(cmd));
+ return -1;
+ }
+
+ DEBUG("A2DP COMMAND %s DONE STATUS %d", audio_a2dp_hw_dump_ctrl_event(cmd),
+ ack);
+
+ if (ack == A2DP_CTRL_ACK_INCALL_FAILURE) return ack;
+ if (ack != A2DP_CTRL_ACK_SUCCESS) {
+ ERROR("A2DP COMMAND %s error %d", audio_a2dp_hw_dump_ctrl_event(cmd), ack);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_a2dp_ready(struct a2dp_stream_common* common) {
+ if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0) {
+ ERROR("check a2dp ready failed");
+ return -1;
+ }
+ return 0;
+}
+
+static int a2dp_read_input_audio_config(struct a2dp_stream_common* common) {
+ tA2DP_SAMPLE_RATE sample_rate;
+ tA2DP_CHANNEL_COUNT channel_count;
+
+ if (a2dp_command(common, A2DP_CTRL_GET_INPUT_AUDIO_CONFIG) < 0) {
+ ERROR("get a2dp input audio config failed");
+ return -1;
+ }
+
+ if (a2dp_ctrl_receive(common, &sample_rate, sizeof(tA2DP_SAMPLE_RATE)) < 0)
+ return -1;
+ if (a2dp_ctrl_receive(common, &channel_count, sizeof(tA2DP_CHANNEL_COUNT)) <
+ 0) {
+ return -1;
+ }
+
+ switch (sample_rate) {
+ case 44100:
+ case 48000:
+ common->cfg.rate = sample_rate;
+ break;
+ default:
+ ERROR("Invalid sample rate: %" PRIu32, sample_rate);
+ return -1;
+ }
+
+ switch (channel_count) {
+ case 1:
+ common->cfg.channel_mask = AUDIO_CHANNEL_IN_MONO;
+ break;
+ case 2:
+ common->cfg.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ break;
+ default:
+ ERROR("Invalid channel count: %" PRIu32, channel_count);
+ return -1;
+ }
+
+ // TODO: For now input audio format is always hard-coded as PCM 16-bit
+ common->cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ INFO("got input audio config %d %d", common->cfg.format, common->cfg.rate);
+
+ return 0;
+}
+
+static int a2dp_read_output_audio_config(
+ struct a2dp_stream_common* common, btav_a2dp_codec_config_t* codec_config,
+ btav_a2dp_codec_config_t* codec_capability, bool update_stream_config) {
+ struct a2dp_config stream_config;
+
+ if (a2dp_command(common, A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG) < 0) {
+ ERROR("get a2dp output audio config failed");
+ return -1;
+ }
+
+ // Receive the current codec config
+ if (a2dp_ctrl_receive(common, &codec_config->sample_rate,
+ sizeof(btav_a2dp_codec_sample_rate_t)) < 0) {
+ return -1;
+ }
+ if (a2dp_ctrl_receive(common, &codec_config->bits_per_sample,
+ sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+ return -1;
+ }
+ if (a2dp_ctrl_receive(common, &codec_config->channel_mode,
+ sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+ return -1;
+ }
+
+ // Receive the current codec capability
+ if (a2dp_ctrl_receive(common, &codec_capability->sample_rate,
+ sizeof(btav_a2dp_codec_sample_rate_t)) < 0) {
+ return -1;
+ }
+ if (a2dp_ctrl_receive(common, &codec_capability->bits_per_sample,
+ sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+ return -1;
+ }
+ if (a2dp_ctrl_receive(common, &codec_capability->channel_mode,
+ sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+ return -1;
+ }
+
+ // Check the codec config sample rate
+ switch (codec_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ stream_config.rate = 44100;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ stream_config.rate = 48000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ stream_config.rate = 88200;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ stream_config.rate = 96000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ stream_config.rate = 176400;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ stream_config.rate = 192000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ default:
+ ERROR("Invalid sample rate: 0x%x", codec_config->sample_rate);
+ return -1;
+ }
+
+ // Check the codec config bits per sample
+ switch (codec_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ stream_config.format = AUDIO_FORMAT_PCM_16_BIT;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ stream_config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ stream_config.format = AUDIO_FORMAT_PCM_32_BIT;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ default:
+ ERROR("Invalid bits per sample: 0x%x", codec_config->bits_per_sample);
+ return -1;
+ }
+
+ // Check the codec config channel mode
+ switch (codec_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ /**M:Bug fix for audioflinger not support mono mode @{*/
+ //stream_config.channel_mask = AUDIO_CHANNEL_OUT_MONO;
+ stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ /**@}*/
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ default:
+ ERROR("Invalid channel mode: 0x%x", codec_config->channel_mode);
+ return -1;
+ }
+
+ // Update the output stream configuration
+ if (update_stream_config) {
+ common->cfg.rate = stream_config.rate;
+ common->cfg.channel_mask = stream_config.channel_mask;
+ common->cfg.format = stream_config.format;
+ common->buffer_sz = audio_a2dp_hw_stream_compute_buffer_size(
+ codec_config->sample_rate, codec_config->bits_per_sample,
+ codec_config->channel_mode);
+ }
+
+ INFO(
+ "got output codec capability: sample_rate=0x%x bits_per_sample=0x%x "
+ "channel_mode=0x%x",
+ codec_capability->sample_rate, codec_capability->bits_per_sample,
+ codec_capability->channel_mode);
+
+ return 0;
+}
+
+static int a2dp_write_output_audio_config(struct a2dp_stream_common* common) {
+ btav_a2dp_codec_config_t codec_config;
+
+ if (a2dp_command(common, A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG) < 0) {
+ ERROR("set a2dp output audio config failed");
+ return -1;
+ }
+
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+
+ switch (common->cfg.rate) {
+ case 44100:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ break;
+ case 48000:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ break;
+ case 88200:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ break;
+ case 96000:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ break;
+ case 176400:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ break;
+ case 192000:
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+ break;
+ default:
+ ERROR("Invalid sample rate: %" PRIu32, common->cfg.rate);
+ return -1;
+ }
+
+ switch (common->cfg.format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ break;
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ break;
+ case AUDIO_FORMAT_PCM_32_BIT:
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ // FALLTHROUGH
+ // All 24-bit audio is expected in AUDIO_FORMAT_PCM_24_BIT_PACKED format
+ default:
+ ERROR("Invalid audio format: 0x%x", common->cfg.format);
+ return -1;
+ }
+
+ switch (common->cfg.channel_mask) {
+ case AUDIO_CHANNEL_OUT_MONO:
+ codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ break;
+ case AUDIO_CHANNEL_OUT_STEREO:
+ codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ break;
+ default:
+ ERROR("Invalid channel mask: 0x%x", common->cfg.channel_mask);
+ return -1;
+ }
+
+ // Send the current codec config that has been selected by us
+ if (a2dp_ctrl_send(common, &codec_config.sample_rate,
+ sizeof(btav_a2dp_codec_sample_rate_t)) < 0)
+ return -1;
+ if (a2dp_ctrl_send(common, &codec_config.bits_per_sample,
+ sizeof(btav_a2dp_codec_bits_per_sample_t)) < 0) {
+ return -1;
+ }
+ if (a2dp_ctrl_send(common, &codec_config.channel_mode,
+ sizeof(btav_a2dp_codec_channel_mode_t)) < 0) {
+ return -1;
+ }
+
+ INFO(
+ "sent output codec config: sample_rate=0x%x bits_per_sample=0x%x "
+ "channel_mode=0x%x",
+ codec_config.sample_rate, codec_config.bits_per_sample,
+ codec_config.channel_mode);
+
+ return 0;
+}
+
+static void a2dp_open_ctrl_path(struct a2dp_stream_common* common) {
+ int i;
+
+ if (common->ctrl_fd != AUDIO_SKT_DISCONNECTED) return; // already connected
+
+ /* retry logic to catch any timing variations on control channel */
+ for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) {
+ /* connect control channel if not already connected */
+ if ((common->ctrl_fd = skt_connect(
+ A2DP_CTRL_PATH, AUDIO_STREAM_CONTROL_OUTPUT_BUFFER_SZ)) >= 0) {
+ /* success, now check if stack is ready */
+ if (check_a2dp_ready(common) == 0) break;
+
+ ERROR("error : a2dp not ready, wait 250 ms and retry");
+ usleep(250000);
+ skt_disconnect(common->ctrl_fd);
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+
+ /* ctrl channel not ready, wait a bit */
+ usleep(250000);
+ }
+}
+
+/*****************************************************************************
+ *
+ * AUDIO DATA PATH
+ *
+ ****************************************************************************/
+
+static void a2dp_stream_common_init(struct a2dp_stream_common* common) {
+ FNLOG();
+
+ common->mutex = new std::recursive_mutex;
+
+ common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+ common->state = AUDIO_A2DP_STATE_STOPPED;
+
+ /* manages max capacity of socket pipe */
+ common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+}
+
+static void a2dp_stream_common_destroy(struct a2dp_stream_common* common) {
+ FNLOG();
+
+ delete common->mutex;
+ common->mutex = NULL;
+}
+
+static int start_audio_datapath(struct a2dp_stream_common* common) {
+ INFO("state %d", common->state);
+
+ int oldstate = common->state;
+ common->state = AUDIO_A2DP_STATE_STARTING;
+
+ int a2dp_status = a2dp_command(common, A2DP_CTRL_CMD_START);
+ if (a2dp_status < 0) {
+ ERROR("Audiopath start failed (status %d)", a2dp_status);
+ goto error;
+ } else if (a2dp_status == A2DP_CTRL_ACK_INCALL_FAILURE) {
+ ERROR("Audiopath start failed - in call, move to suspended");
+ goto error;
+ }
+
+ /* connect socket if not yet connected */
+ if (common->audio_fd == AUDIO_SKT_DISCONNECTED) {
+ common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz);
+ if (common->audio_fd < 0) {
+ ERROR("Audiopath start failed - error opening data socket");
+ goto error;
+ }
+ }
+ common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STARTED;
+ return 0;
+
+error:
+ common->state = (a2dp_state_t)oldstate;
+ return -1;
+}
+
+static int stop_audio_datapath(struct a2dp_stream_common* common) {
+ int oldstate = common->state;
+
+ INFO("state %d", common->state);
+
+/** M: Bug fix for avoid retry control channel @{ */
+ if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED)
+ return -1;
+/** @} */
+
+ /* prevent any stray output writes from autostarting the stream
+ while stopping audiopath */
+ common->state = AUDIO_A2DP_STATE_STOPPING;
+
+ if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0) {
+ ERROR("audiopath stop failed");
+ common->state = (a2dp_state_t)oldstate;
+ return -1;
+ }
+
+ common->state = (a2dp_state_t)AUDIO_A2DP_STATE_STOPPED;
+
+ /* disconnect audio path */
+ skt_disconnect(common->audio_fd);
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+ return 0;
+}
+
+static int suspend_audio_datapath(struct a2dp_stream_common* common,
+ bool standby) {
+ INFO("state %d", common->state);
+
+ if (common->state == AUDIO_A2DP_STATE_STOPPING) return -1;
+
+ if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0) return -1;
+
+ if (standby)
+ common->state = AUDIO_A2DP_STATE_STANDBY;
+ else
+ common->state = AUDIO_A2DP_STATE_SUSPENDED;
+
+ /* disconnect audio path */
+ skt_disconnect(common->audio_fd);
+
+ common->audio_fd = AUDIO_SKT_DISCONNECTED;
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * audio output callbacks
+ *
+ ****************************************************************************/
+
+static ssize_t out_write(struct audio_stream_out* stream, const void* buffer,
+ size_t bytes) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+ int sent = -1;
+
+ DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd);
+
+ std::unique_lock<std::recursive_mutex> lock(*out->common.mutex);
+ if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED ||
+ out->common.state == AUDIO_A2DP_STATE_STOPPING) {
+ DEBUG("stream suspended or closing");
+ goto finish;
+ }
+
+ /* only allow autostarting if we are in stopped or standby */
+ if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) ||
+ (out->common.state == AUDIO_A2DP_STATE_STANDBY)) {
+/** M: Bug fix for avoid retry control channel @{ */
+ if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) {
+ goto finish;
+ }
+/** @} */
+ if (start_audio_datapath(&out->common) < 0) {
+ goto finish;
+ }
+ } else if (out->common.state != AUDIO_A2DP_STATE_STARTED) {
+ ERROR("stream not in stopped or standby");
+ goto finish;
+ }
+
+#if defined(MTK_A2DP_PCM_DUMP) && (MTK_A2DP_PCM_DUMP == TRUE)
+ if (buffer != NULL && bytes != 0 && dump_fd != INVALID_FD){
+ write(dump_fd, buffer, bytes);
+ DEBUG("dump a2dp pcm data (%zu bytes)", bytes);
+ }
+#endif
+
+ lock.unlock();
+ sent = skt_write(out->common.audio_fd, buffer, bytes);
+ lock.lock();
+
+ if (sent == -1) {
+ skt_disconnect(out->common.audio_fd);
+ out->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+ if ((out->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
+ (out->common.state != AUDIO_A2DP_STATE_STOPPING)) {
+ out->common.state = AUDIO_A2DP_STATE_STOPPED;
+ } else {
+ ERROR("write failed : stream suspended, avoid resetting state");
+ }
+ goto finish;
+ }
+
+finish:;
+ const size_t frames = bytes / audio_stream_out_frame_size(stream);
+ out->frames_rendered += frames;
+ out->frames_presented += frames;
+ lock.unlock();
+
+ // If send didn't work out, sleep to emulate write delay.
+ if (sent == -1) {
+ const int us_delay = calc_audiotime_usec(out->common.cfg, bytes);
+ DEBUG("emulate a2dp write delay (%d us)", us_delay);
+ usleep(us_delay);
+ }
+ return bytes;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream* stream) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ DEBUG("rate %" PRIu32, out->common.cfg.rate);
+
+ return out->common.cfg.rate;
+}
+
+static int out_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ DEBUG("out_set_sample_rate : %" PRIu32, rate);
+
+ out->common.cfg.rate = rate;
+
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream* stream) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+ // period_size is the AudioFlinger mixer buffer size.
+ const size_t period_size =
+ out->common.buffer_sz / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS;
+
+ DEBUG("socket buffer size: %zu period size: %zu", out->common.buffer_sz,
+ period_size);
+
+ return period_size;
+}
+
+size_t audio_a2dp_hw_stream_compute_buffer_size(
+ btav_a2dp_codec_sample_rate_t codec_sample_rate,
+ btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample,
+ btav_a2dp_codec_channel_mode_t codec_channel_mode) {
+ size_t buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; // Default value
+ const uint64_t time_period_ms = 20; // Conservative 20ms
+ uint32_t sample_rate;
+ uint32_t bits_per_sample;
+ uint32_t number_of_channels;
+
+ // Check the codec config sample rate
+ switch (codec_sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ sample_rate = 44100;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ sample_rate = 48000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ sample_rate = 88200;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ sample_rate = 96000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ sample_rate = 176400;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ sample_rate = 192000;
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ default:
+ ERROR("Invalid sample rate: 0x%x", codec_sample_rate);
+ return buffer_sz;
+ }
+
+ // Check the codec config bits per sample
+ switch (codec_bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ bits_per_sample = 16;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ bits_per_sample = 24;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ bits_per_sample = 32;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ default:
+ ERROR("Invalid bits per sample: 0x%x", codec_bits_per_sample);
+ return buffer_sz;
+ }
+
+ // Check the codec config channel mode
+ switch (codec_channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ number_of_channels = 1;
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ number_of_channels = 2;
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ default:
+ ERROR("Invalid channel mode: 0x%x", codec_channel_mode);
+ return buffer_sz;
+ }
+
+ //
+ // The buffer size is computed by using the following formula:
+ //
+ // AUDIO_STREAM_OUTPUT_BUFFER_SIZE =
+ // (TIME_PERIOD_MS * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+ // SAMPLE_RATE_HZ * NUMBER_OF_CHANNELS * (BITS_PER_SAMPLE / 8)) / 1000
+ //
+ // AUDIO_STREAM_OUTPUT_BUFFER_PERIODS controls how the socket buffer is
+ // divided for AudioFlinger data delivery. The AudioFlinger mixer delivers
+ // data in chunks of
+ // (AUDIO_STREAM_OUTPUT_BUFFER_SIZE / AUDIO_STREAM_OUTPUT_BUFFER_PERIODS) .
+ // If the number of periods is 2, the socket buffer represents "double
+ // buffering" of the AudioFlinger mixer buffer.
+ //
+ // Furthermore, the AudioFlinger expects the buffer size to be a multiple
+ // of 16 frames.
+ const size_t divisor = (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 *
+ number_of_channels * bits_per_sample) /
+ 8;
+
+ buffer_sz = (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS *
+ sample_rate * number_of_channels * (bits_per_sample / 8)) /
+ 1000;
+
+ // Adjust the buffer size so it can be divided by the divisor
+ const size_t remainder = buffer_sz % divisor;
+ if (remainder != 0) {
+ buffer_sz += divisor - remainder;
+ }
+
+ return buffer_sz;
+}
+
+static uint32_t out_get_channels(const struct audio_stream* stream) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_mask);
+
+ return out->common.cfg.channel_mask;
+}
+
+static audio_format_t out_get_format(const struct audio_stream* stream) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+ DEBUG("format 0x%x", out->common.cfg.format);
+ return (audio_format_t)out->common.cfg.format;
+}
+
+static int out_set_format(UNUSED_ATTR struct audio_stream* stream,
+ UNUSED_ATTR audio_format_t format) {
+ DEBUG("setting format not yet supported (0x%x)", format);
+ return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream* stream) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+ int retVal = 0;
+
+ FNLOG();
+
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+ // Do nothing in SUSPENDED state.
+ if (out->common.state != AUDIO_A2DP_STATE_SUSPENDED)
+ retVal = suspend_audio_datapath(&out->common, true);
+ out->frames_rendered = 0; // rendered is reset, presented is not
+
+ return retVal;
+}
+
+static int out_dump(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR int fd) {
+ FNLOG();
+ return 0;
+}
+
+static int out_set_parameters(struct audio_stream* stream,
+ const char* kvpairs) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ INFO("state %d kvpairs %s", out->common.state, kvpairs);
+
+ std::unordered_map<std::string, std::string> params =
+ hash_map_utils_new_from_string_params(kvpairs);
+ int status = 0;
+
+ if (params.empty()) return status;
+
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+ /* dump params */
+ hash_map_utils_dump_string_keys_string_values(params);
+
+ if (params["closing"].compare("true") == 0) {
+ DEBUG("stream closing, disallow any writes");
+ out->common.state = AUDIO_A2DP_STATE_STOPPING;
+ }
+
+ if (params["A2dpSuspended"].compare("true") == 0) {
+ if (out->common.state == AUDIO_A2DP_STATE_STARTED)
+ status = suspend_audio_datapath(&out->common, false);
+ } else {
+ /* Do not start the streaming automatically. If the phone was streaming
+ * prior to being suspended, the next out_write shall trigger the
+ * AVDTP start procedure */
+ if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED)
+ out->common.state = AUDIO_A2DP_STATE_STANDBY;
+ /* Irrespective of the state, return 0 */
+ }
+
+ return status;
+}
+
+static char* out_get_parameters(const struct audio_stream* stream,
+ const char* keys) {
+ FNLOG();
+
+ btav_a2dp_codec_config_t codec_config;
+ btav_a2dp_codec_config_t codec_capability;
+
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ std::unordered_map<std::string, std::string> params =
+ hash_map_utils_new_from_string_params(keys);
+ std::unordered_map<std::string, std::string> return_params;
+
+ if (params.empty()) return strdup("");
+
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+
+ if (a2dp_read_output_audio_config(&out->common, &codec_config,
+ &codec_capability,
+ false /* update_stream_config */) < 0) {
+ ERROR("a2dp_read_output_audio_config failed");
+ goto done;
+ }
+
+ // Add the format
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_FORMATS) != params.end()) {
+ std::string param;
+ if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ if (!param.empty()) param += "|";
+ param += "AUDIO_FORMAT_PCM_16_BIT";
+ }
+ if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ if (!param.empty()) param += "|";
+ param += "AUDIO_FORMAT_PCM_24_BIT_PACKED";
+ }
+ if (codec_capability.bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ if (!param.empty()) param += "|";
+ param += "AUDIO_FORMAT_PCM_32_BIT";
+ }
+ if (param.empty()) {
+ ERROR("Invalid codec capability bits_per_sample=0x%x",
+ codec_capability.bits_per_sample);
+ goto done;
+ } else {
+ return_params[AUDIO_PARAMETER_STREAM_SUP_FORMATS] = param;
+ }
+ }
+
+ // Add the sample rate
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES) != params.end()) {
+ std::string param;
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100) {
+ if (!param.empty()) param += "|";
+ param += "44100";
+ }
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000) {
+ if (!param.empty()) param += "|";
+ param += "48000";
+ }
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200) {
+ if (!param.empty()) param += "|";
+ param += "88200";
+ }
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000) {
+ if (!param.empty()) param += "|";
+ param += "96000";
+ }
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400) {
+ if (!param.empty()) param += "|";
+ param += "176400";
+ }
+ if (codec_capability.sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000) {
+ if (!param.empty()) param += "|";
+ param += "192000";
+ }
+ if (param.empty()) {
+ ERROR("Invalid codec capability sample_rate=0x%x",
+ codec_capability.sample_rate);
+ goto done;
+ } else {
+ return_params[AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES] = param;
+ }
+ }
+
+ // Add the channel mask
+ if (params.find(AUDIO_PARAMETER_STREAM_SUP_CHANNELS) != params.end()) {
+ std::string param;
+ if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO) {
+ if (!param.empty()) param += "|";
+ param += "AUDIO_CHANNEL_OUT_MONO";
+ }
+ if (codec_capability.channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) {
+ if (!param.empty()) param += "|";
+ param += "AUDIO_CHANNEL_OUT_STEREO";
+ }
+ if (param.empty()) {
+ ERROR("Invalid codec capability channel_mode=0x%x",
+ codec_capability.channel_mode);
+ goto done;
+ } else {
+ return_params[AUDIO_PARAMETER_STREAM_SUP_CHANNELS] = param;
+ }
+ }
+
+done:
+ std::string result;
+ for (const auto& ptr : return_params) {
+ result += ptr.first + "=" + ptr.second + ";";
+ }
+
+ INFO("get parameters result = %s", result.c_str());
+
+ return strdup(result.c_str());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out* stream) {
+ int latency_us;
+
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ FNLOG();
+
+ latency_us =
+ ((out->common.buffer_sz * 1000) /
+ audio_stream_out_frame_size(&out->stream) / out->common.cfg.rate) *
+ 1000;
+
+ return (latency_us / 1000) + 200;
+}
+
+static int out_set_volume(UNUSED_ATTR struct audio_stream_out* stream,
+ UNUSED_ATTR float left, UNUSED_ATTR float right) {
+ FNLOG();
+
+ /* volume controlled in audioflinger mixer (digital) */
+
+ return -ENOSYS;
+}
+
+static int out_get_presentation_position(const struct audio_stream_out* stream,
+ uint64_t* frames,
+ struct timespec* timestamp) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ FNLOG();
+ if (stream == NULL || frames == NULL || timestamp == NULL) return -EINVAL;
+
+ int ret = -EWOULDBLOCK;
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+ uint64_t latency_frames =
+ (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+ if (out->frames_presented >= latency_frames) {
+ *frames = out->frames_presented - latency_frames;
+ clock_gettime(CLOCK_MONOTONIC,
+ timestamp); // could also be associated with out_write().
+ ret = 0;
+ }
+ return ret;
+}
+
+static int out_get_render_position(const struct audio_stream_out* stream,
+ uint32_t* dsp_frames) {
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ FNLOG();
+ if (stream == NULL || dsp_frames == NULL) return -EINVAL;
+
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+ uint64_t latency_frames =
+ (uint64_t)out_get_latency(stream) * out->common.cfg.rate / 1000;
+ if (out->frames_rendered >= latency_frames) {
+ *dsp_frames = (uint32_t)(out->frames_rendered - latency_frames);
+ } else {
+ *dsp_frames = 0;
+ }
+ return 0;
+}
+
+static int out_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR effect_handle_t effect) {
+ FNLOG();
+ return 0;
+}
+
+static int out_remove_audio_effect(
+ UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR effect_handle_t effect) {
+ FNLOG();
+ return 0;
+}
+
+/*
+ * AUDIO INPUT STREAM
+ */
+
+static uint32_t in_get_sample_rate(const struct audio_stream* stream) {
+ struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
+
+ FNLOG();
+ return in->common.cfg.rate;
+}
+
+static int in_set_sample_rate(struct audio_stream* stream, uint32_t rate) {
+ struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
+
+ FNLOG();
+
+ if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate)
+ return 0;
+ else
+ return -1;
+}
+
+static size_t in_get_buffer_size(
+ UNUSED_ATTR const struct audio_stream* stream) {
+ FNLOG();
+ return 320;
+}
+
+static uint32_t in_get_channels(const struct audio_stream* stream) {
+ struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
+
+ FNLOG();
+ return in->common.cfg.channel_mask;
+}
+
+static audio_format_t in_get_format(
+ UNUSED_ATTR const struct audio_stream* stream) {
+ FNLOG();
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+static int in_set_format(UNUSED_ATTR struct audio_stream* stream,
+ UNUSED_ATTR audio_format_t format) {
+ FNLOG();
+ if (format == AUDIO_FORMAT_PCM_16_BIT)
+ return 0;
+ else
+ return -1;
+}
+
+static int in_standby(UNUSED_ATTR struct audio_stream* stream) {
+ FNLOG();
+ return 0;
+}
+
+static int in_dump(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR int fd) {
+ FNLOG();
+ return 0;
+}
+
+static int in_set_parameters(UNUSED_ATTR struct audio_stream* stream,
+ UNUSED_ATTR const char* kvpairs) {
+ FNLOG();
+ return 0;
+}
+
+static char* in_get_parameters(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR const char* keys) {
+ FNLOG();
+ return strdup("");
+}
+
+static int in_set_gain(UNUSED_ATTR struct audio_stream_in* stream,
+ UNUSED_ATTR float gain) {
+ FNLOG();
+ return 0;
+}
+
+static ssize_t in_read(struct audio_stream_in* stream, void* buffer,
+ size_t bytes) {
+ struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
+ int read;
+ int us_delay;
+
+ DEBUG("read %zu bytes, state: %d", bytes, in->common.state);
+
+ std::unique_lock<std::recursive_mutex> lock(*in->common.mutex);
+ if (in->common.state == AUDIO_A2DP_STATE_SUSPENDED ||
+ in->common.state == AUDIO_A2DP_STATE_STOPPING) {
+ DEBUG("stream suspended");
+ goto error;
+ }
+
+ /* only allow autostarting if we are in stopped or standby */
+ if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) ||
+ (in->common.state == AUDIO_A2DP_STATE_STANDBY)) {
+ if (start_audio_datapath(&in->common) < 0) {
+ goto error;
+ }
+ } else if (in->common.state != AUDIO_A2DP_STATE_STARTED) {
+ ERROR("stream not in stopped or standby");
+ goto error;
+ }
+
+ lock.unlock();
+ read = skt_read(in->common.audio_fd, buffer, bytes);
+ lock.lock();
+ if (read == -1) {
+ skt_disconnect(in->common.audio_fd);
+ in->common.audio_fd = AUDIO_SKT_DISCONNECTED;
+ if ((in->common.state != AUDIO_A2DP_STATE_SUSPENDED) &&
+ (in->common.state != AUDIO_A2DP_STATE_STOPPING)) {
+ in->common.state = AUDIO_A2DP_STATE_STOPPED;
+ } else {
+ ERROR("read failed : stream suspended, avoid resetting state");
+ }
+ goto error;
+ } else if (read == 0) {
+ DEBUG("read time out - return zeros");
+ memset(buffer, 0, bytes);
+ read = bytes;
+ }
+ lock.unlock();
+
+ DEBUG("read %d bytes out of %zu bytes", read, bytes);
+ return read;
+
+error:
+ memset(buffer, 0, bytes);
+ us_delay = calc_audiotime_usec(in->common.cfg, bytes);
+ DEBUG("emulate a2dp read delay (%d us)", us_delay);
+
+ usleep(us_delay);
+ return bytes;
+}
+
+static uint32_t in_get_input_frames_lost(
+ UNUSED_ATTR struct audio_stream_in* stream) {
+ FNLOG();
+ return 0;
+}
+
+static int in_add_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR effect_handle_t effect) {
+ FNLOG();
+ return 0;
+}
+
+static int in_remove_audio_effect(UNUSED_ATTR const struct audio_stream* stream,
+ UNUSED_ATTR effect_handle_t effect) {
+ FNLOG();
+
+ return 0;
+}
+
+static int adev_open_output_stream(struct audio_hw_device* dev,
+ UNUSED_ATTR audio_io_handle_t handle,
+ UNUSED_ATTR audio_devices_t devices,
+ UNUSED_ATTR audio_output_flags_t flags,
+ struct audio_config* config,
+ struct audio_stream_out** stream_out,
+ UNUSED_ATTR const char* address)
+
+{
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
+ struct a2dp_stream_out* out;
+ int ret = 0;
+
+ INFO("opening output");
+ // protect against adev->output and stream_out from being inconsistent
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ out = (struct a2dp_stream_out*)calloc(1, sizeof(struct a2dp_stream_out));
+
+ if (!out) return -ENOMEM;
+
+ out->stream.common.get_sample_rate = out_get_sample_rate;
+ out->stream.common.set_sample_rate = out_set_sample_rate;
+ out->stream.common.get_buffer_size = out_get_buffer_size;
+ out->stream.common.get_channels = out_get_channels;
+ out->stream.common.get_format = out_get_format;
+ out->stream.common.set_format = out_set_format;
+ out->stream.common.standby = out_standby;
+ out->stream.common.dump = out_dump;
+ out->stream.common.set_parameters = out_set_parameters;
+ out->stream.common.get_parameters = out_get_parameters;
+ out->stream.common.add_audio_effect = out_add_audio_effect;
+ out->stream.common.remove_audio_effect = out_remove_audio_effect;
+ out->stream.get_latency = out_get_latency;
+ out->stream.set_volume = out_set_volume;
+ out->stream.write = out_write;
+ out->stream.get_render_position = out_get_render_position;
+ out->stream.get_presentation_position = out_get_presentation_position;
+
+ /* initialize a2dp specifics */
+ a2dp_stream_common_init(&out->common);
+
+ // Make sure we always have the feeding parameters configured
+ btav_a2dp_codec_config_t codec_config;
+ btav_a2dp_codec_config_t codec_capability;
+ if (a2dp_read_output_audio_config(&out->common, &codec_config,
+ &codec_capability,
+ true /* update_stream_config */) < 0) {
+ ERROR("a2dp_read_output_audio_config failed");
+ ret = -1;
+ goto err_open;
+ }
+ // a2dp_read_output_audio_config() opens the socket control path (or fails)
+
+ /* set output config values */
+ if (config != nullptr) {
+ // Try to use the config parameters and send it to the remote side
+ // TODO: Shall we use out_set_format() and similar?
+ if (config->format != 0) out->common.cfg.format = config->format;
+ if (config->sample_rate != 0) out->common.cfg.rate = config->sample_rate;
+ if (config->channel_mask != 0)
+ out->common.cfg.channel_mask = config->channel_mask;
+ if ((out->common.cfg.format != 0) || (out->common.cfg.rate != 0) ||
+ (out->common.cfg.channel_mask != 0)) {
+ if (a2dp_write_output_audio_config(&out->common) < 0) {
+ ERROR("a2dp_write_output_audio_config failed");
+ ret = -1;
+ goto err_open;
+ }
+ // Read again and make sure we use the same parameters as the remote side
+ if (a2dp_read_output_audio_config(&out->common, &codec_config,
+ &codec_capability,
+ true /* update_stream_config */) < 0) {
+ ERROR("a2dp_read_output_audio_config failed");
+ ret = -1;
+ goto err_open;
+ }
+ }
+ config->format = out_get_format((const struct audio_stream*)&out->stream);
+ config->sample_rate =
+ out_get_sample_rate((const struct audio_stream*)&out->stream);
+ config->channel_mask =
+ out_get_channels((const struct audio_stream*)&out->stream);
+
+ INFO(
+ "Output stream config: format=0x%x sample_rate=%d channel_mask=0x%x "
+ "buffer_sz=%zu",
+ config->format, config->sample_rate, config->channel_mask,
+ out->common.buffer_sz);
+ }
+ *stream_out = &out->stream;
+ a2dp_dev->output = out;
+
+#if defined(MTK_A2DP_PCM_DUMP) && (MTK_A2DP_PCM_DUMP == TRUE)
+ char dump_enable[PROPERTY_VALUE_MAX];
+
+ property_get(MTK_PCM_DUMP_PROPERTY, dump_enable, "false");
+
+ if (!strcmp("true", dump_enable)){
+ DEBUG("pcm dump property is true");
+
+ dump_fd = open(pcmfilename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+
+ if (dump_fd == INVALID_FD) {
+ ERROR("%s unable to open '%s': %s", __func__, pcmfilename, strerror(errno));
+ }
+ }
+#endif
+
+ DEBUG("success");
+ /* Delay to ensure Headset is in proper state when START is initiated from
+ * DUT immediately after the connection due to ongoing music playback. */
+ usleep(250000);
+ return 0;
+
+err_open:
+ a2dp_stream_common_destroy(&out->common);
+ free(out);
+ *stream_out = NULL;
+ a2dp_dev->output = NULL;
+ ERROR("failed");
+ return ret;
+}
+
+static void adev_close_output_stream(struct audio_hw_device* dev,
+ struct audio_stream_out* stream) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
+ struct a2dp_stream_out* out = (struct a2dp_stream_out*)stream;
+
+ // prevent interference with adev_set_parameters.
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ {
+ std::lock_guard<std::recursive_mutex> lock(*out->common.mutex);
+ const a2dp_state_t state = out->common.state;
+ INFO("closing output (state %d)", (int)state);
+ if ((state == AUDIO_A2DP_STATE_STARTED) ||
+ (state == AUDIO_A2DP_STATE_STOPPING)) {
+ stop_audio_datapath(&out->common);
+ }
+
+ skt_disconnect(out->common.ctrl_fd);
+ out->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+
+ a2dp_stream_common_destroy(&out->common);
+ free(stream);
+ a2dp_dev->output = NULL;
+
+#if defined(MTK_A2DP_PCM_DUMP) && (MTK_A2DP_PCM_DUMP == TRUE)
+ if (dump_fd != INVALID_FD)
+ close(dump_fd);
+#endif
+
+ DEBUG("done");
+}
+
+static int adev_set_parameters(struct audio_hw_device* dev,
+ const char* kvpairs) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
+ int retval = 0;
+
+ // prevent interference with adev_close_output_stream
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ struct a2dp_stream_out* out = a2dp_dev->output;
+
+ if (out == NULL) return retval;
+
+ INFO("state %d", out->common.state);
+
+ retval =
+ out->stream.common.set_parameters((struct audio_stream*)out, kvpairs);
+
+ return retval;
+}
+
+static char* adev_get_parameters(UNUSED_ATTR const struct audio_hw_device* dev,
+ const char* keys) {
+ FNLOG();
+
+ std::unordered_map<std::string, std::string> params =
+ hash_map_utils_new_from_string_params(keys);
+ hash_map_utils_dump_string_keys_string_values(params);
+
+ return strdup("");
+}
+
+static int adev_init_check(UNUSED_ATTR const struct audio_hw_device* dev) {
+ FNLOG();
+
+ return 0;
+}
+
+static int adev_set_voice_volume(UNUSED_ATTR struct audio_hw_device* dev,
+ UNUSED_ATTR float volume) {
+ FNLOG();
+
+ return -ENOSYS;
+}
+
+static int adev_set_master_volume(UNUSED_ATTR struct audio_hw_device* dev,
+ UNUSED_ATTR float volume) {
+ FNLOG();
+
+ return -ENOSYS;
+}
+
+static int adev_set_mode(UNUSED_ATTR struct audio_hw_device* dev,
+ UNUSED_ATTR audio_mode_t mode) {
+ FNLOG();
+
+ return 0;
+}
+
+static int adev_set_mic_mute(UNUSED_ATTR struct audio_hw_device* dev,
+ UNUSED_ATTR bool state) {
+ FNLOG();
+
+ return -ENOSYS;
+}
+
+static int adev_get_mic_mute(UNUSED_ATTR const struct audio_hw_device* dev,
+ UNUSED_ATTR bool* state) {
+ FNLOG();
+
+ return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(
+ UNUSED_ATTR const struct audio_hw_device* dev,
+ UNUSED_ATTR const struct audio_config* config) {
+ FNLOG();
+
+ return 320;
+}
+
+static int adev_open_input_stream(struct audio_hw_device* dev,
+ UNUSED_ATTR audio_io_handle_t handle,
+ UNUSED_ATTR audio_devices_t devices,
+ UNUSED_ATTR struct audio_config* config,
+ struct audio_stream_in** stream_in,
+ UNUSED_ATTR audio_input_flags_t flags,
+ UNUSED_ATTR const char* address,
+ UNUSED_ATTR audio_source_t source) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
+ struct a2dp_stream_in* in;
+ int ret;
+
+ FNLOG();
+
+ // protect against adev->input and stream_in from being inconsistent
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ in = (struct a2dp_stream_in*)calloc(1, sizeof(struct a2dp_stream_in));
+
+ if (!in) return -ENOMEM;
+
+ in->stream.common.get_sample_rate = in_get_sample_rate;
+ in->stream.common.set_sample_rate = in_set_sample_rate;
+ in->stream.common.get_buffer_size = in_get_buffer_size;
+ in->stream.common.get_channels = in_get_channels;
+ in->stream.common.get_format = in_get_format;
+ in->stream.common.set_format = in_set_format;
+ in->stream.common.standby = in_standby;
+ in->stream.common.dump = in_dump;
+ in->stream.common.set_parameters = in_set_parameters;
+ in->stream.common.get_parameters = in_get_parameters;
+ in->stream.common.add_audio_effect = in_add_audio_effect;
+ in->stream.common.remove_audio_effect = in_remove_audio_effect;
+ in->stream.set_gain = in_set_gain;
+ in->stream.read = in_read;
+ in->stream.get_input_frames_lost = in_get_input_frames_lost;
+
+ /* initialize a2dp specifics */
+ a2dp_stream_common_init(&in->common);
+
+ *stream_in = &in->stream;
+ a2dp_dev->input = in;
+
+ if (a2dp_read_input_audio_config(&in->common) < 0) {
+ ERROR("a2dp_read_input_audio_config failed (%s)", strerror(errno));
+ ret = -1;
+ goto err_open;
+ }
+ // a2dp_read_input_audio_config() opens socket control path (or fails)
+
+ DEBUG("success");
+ return 0;
+
+err_open:
+ a2dp_stream_common_destroy(&in->common);
+ free(in);
+ *stream_in = NULL;
+ a2dp_dev->input = NULL;
+ ERROR("failed");
+ return ret;
+}
+
+static void adev_close_input_stream(struct audio_hw_device* dev,
+ struct audio_stream_in* stream) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)dev;
+ struct a2dp_stream_in* in = (struct a2dp_stream_in*)stream;
+
+ std::lock_guard<std::recursive_mutex> lock(*a2dp_dev->mutex);
+ {
+ std::lock_guard<std::recursive_mutex> lock(*in->common.mutex);
+ const a2dp_state_t state = in->common.state;
+ INFO("closing input (state %d)", (int)state);
+
+ if ((state == AUDIO_A2DP_STATE_STARTED) ||
+ (state == AUDIO_A2DP_STATE_STOPPING))
+ stop_audio_datapath(&in->common);
+
+ skt_disconnect(in->common.ctrl_fd);
+ in->common.ctrl_fd = AUDIO_SKT_DISCONNECTED;
+ }
+ a2dp_stream_common_destroy(&in->common);
+ free(stream);
+ a2dp_dev->input = NULL;
+
+ DEBUG("done");
+}
+
+static int adev_dump(UNUSED_ATTR const audio_hw_device_t* device,
+ UNUSED_ATTR int fd) {
+ FNLOG();
+
+ return 0;
+}
+
+static int adev_close(hw_device_t* device) {
+ struct a2dp_audio_device* a2dp_dev = (struct a2dp_audio_device*)device;
+ FNLOG();
+
+ delete a2dp_dev->mutex;
+ a2dp_dev->mutex = nullptr;
+ free(device);
+ return 0;
+}
+
+static int adev_open(const hw_module_t* module, const char* name,
+ hw_device_t** device) {
+ struct a2dp_audio_device* adev;
+
+ INFO(" adev_open in A2dp_hw module");
+ FNLOG();
+
+ if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) {
+ ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
+ return -EINVAL;
+ }
+
+ adev = (struct a2dp_audio_device*)calloc(1, sizeof(struct a2dp_audio_device));
+
+ if (!adev) return -ENOMEM;
+
+ adev->mutex = new std::recursive_mutex;
+
+ adev->device.common.tag = HARDWARE_DEVICE_TAG;
+ adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+ adev->device.common.module = (struct hw_module_t*)module;
+ adev->device.common.close = adev_close;
+
+ adev->device.init_check = adev_init_check;
+ adev->device.set_voice_volume = adev_set_voice_volume;
+ adev->device.set_master_volume = adev_set_master_volume;
+ adev->device.set_mode = adev_set_mode;
+ adev->device.set_mic_mute = adev_set_mic_mute;
+ adev->device.get_mic_mute = adev_get_mic_mute;
+ adev->device.set_parameters = adev_set_parameters;
+ adev->device.get_parameters = adev_get_parameters;
+ adev->device.get_input_buffer_size = adev_get_input_buffer_size;
+ adev->device.open_output_stream = adev_open_output_stream;
+ adev->device.close_output_stream = adev_close_output_stream;
+ adev->device.open_input_stream = adev_open_input_stream;
+ adev->device.close_input_stream = adev_close_input_stream;
+ adev->device.dump = adev_dump;
+
+ adev->output = NULL;
+
+ *device = &adev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+ .open = adev_open,
+};
+
+__attribute__((
+ visibility("default"))) struct audio_module HAL_MODULE_INFO_SYM = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = AUDIO_HARDWARE_MODULE_ID,
+ .name = "A2DP Audio HW HAL",
+ .author = "The Android Open Source Project",
+ .methods = &hal_module_methods,
+ },
+};
diff --git a/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc b/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
new file mode 100755
index 0000000..199b0f9
--- a/dev/null
+++ b/mtkbt/code/bt/audio_a2dp_hw/src/audio_a2dp_hw_utils.cc
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "audio_a2dp_hw.h"
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+const char* audio_a2dp_hw_dump_ctrl_event(tA2DP_CTRL_CMD event) {
+ switch (event) {
+ CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ CASE_RETURN_STR(A2DP_CTRL_GET_INPUT_AUDIO_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_START)
+ default:
+ break;
+ }
+
+ return "UNKNOWN A2DP_CTRL_CMD";
+}
diff --git a/mtkbt/code/bt/audio_a2dp_hw/test/audio_a2dp_hw_test.cc b/mtkbt/code/bt/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
new file mode 100755
index 0000000..f2cefa8
--- a/dev/null
+++ b/mtkbt/code/bt/audio_a2dp_hw/test/audio_a2dp_hw_test.cc
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+
+namespace {
+static uint32_t codec_sample_rate2value(
+ btav_a2dp_codec_sample_rate_t codec_sample_rate) {
+ switch (codec_sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ return 44100;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ return 48000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ return 88200;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ return 96000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ return 176400;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ return 192000;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+ return 0;
+}
+
+static uint32_t codec_bits_per_sample2value(
+ btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) {
+ switch (codec_bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return 16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return 24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return 32;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return 0;
+}
+
+static uint32_t codec_channel_mode2value(
+ btav_a2dp_codec_channel_mode_t codec_channel_mode) {
+ switch (codec_channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ return 1;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ return 2;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+ return 0;
+}
+
+} // namespace
+
+class AudioA2dpHwTest : public ::testing::Test {
+ protected:
+ AudioA2dpHwTest() {}
+
+ private:
+};
+
+TEST_F(AudioA2dpHwTest, test_compute_buffer_size) {
+ const btav_a2dp_codec_sample_rate_t codec_sample_rate_array[] = {
+ BTAV_A2DP_CODEC_SAMPLE_RATE_NONE, BTAV_A2DP_CODEC_SAMPLE_RATE_44100,
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000, BTAV_A2DP_CODEC_SAMPLE_RATE_88200,
+ BTAV_A2DP_CODEC_SAMPLE_RATE_96000, BTAV_A2DP_CODEC_SAMPLE_RATE_176400,
+ BTAV_A2DP_CODEC_SAMPLE_RATE_192000};
+
+ const btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample_array[] = {
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16,
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24, BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32};
+
+ const btav_a2dp_codec_channel_mode_t codec_channel_mode_array[] = {
+ BTAV_A2DP_CODEC_CHANNEL_MODE_NONE, BTAV_A2DP_CODEC_CHANNEL_MODE_MONO,
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO};
+
+ for (const auto codec_sample_rate : codec_sample_rate_array) {
+ for (const auto codec_bits_per_sample : codec_bits_per_sample_array) {
+ for (const auto codec_channel_mode : codec_channel_mode_array) {
+ size_t buffer_size = audio_a2dp_hw_stream_compute_buffer_size(
+ codec_sample_rate, codec_bits_per_sample, codec_channel_mode);
+
+ // Check for invalid input
+ if ((codec_sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||
+ (codec_bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||
+ (codec_channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {
+ EXPECT_EQ(buffer_size,
+ static_cast<size_t>(AUDIO_STREAM_OUTPUT_BUFFER_SZ));
+ continue;
+ }
+
+ uint32_t sample_rate = codec_sample_rate2value(codec_sample_rate);
+ EXPECT_TRUE(sample_rate != 0);
+
+ uint32_t bits_per_sample =
+ codec_bits_per_sample2value(codec_bits_per_sample);
+ EXPECT_TRUE(bits_per_sample != 0);
+
+ uint32_t number_of_channels =
+ codec_channel_mode2value(codec_channel_mode);
+ EXPECT_TRUE(number_of_channels != 0);
+
+ const uint64_t time_period_ms = 20; // TODO: Must be a parameter
+ size_t expected_buffer_size =
+ (time_period_ms * AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * sample_rate *
+ number_of_channels * (bits_per_sample / 8)) /
+ 1000;
+
+ // Compute the divisor and adjust the buffer size
+ const size_t divisor = (AUDIO_STREAM_OUTPUT_BUFFER_PERIODS * 16 *
+ number_of_channels * bits_per_sample) /
+ 8;
+ const size_t remainder = expected_buffer_size % divisor;
+ if (remainder != 0) {
+ expected_buffer_size += divisor - remainder;
+ }
+
+ EXPECT_EQ(buffer_size, expected_buffer_size);
+ }
+ }
+ }
+}
diff --git a/mtkbt/code/bt/bta/Android.bp b/mtkbt/code/bt/bta/Android.bp
new file mode 100755
index 0000000..128a63c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/Android.bp
@@ -0,0 +1,135 @@
+cc_defaults {
+ name: "fluoride_bta_defaults",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "sys",
+ "dm",
+ "hd",
+ "hh",
+ "closure",
+ ],
+ include_dirs: [
+ "hardware/mtk/bluetooth/mtkbt/code/bt",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/bta/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/btcore/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/hci/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/btm",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/udrv/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/vnd/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/utils/include",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ cflags: ["-DBUILDCFG"],
+}
+
+// BTA static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-bta",
+ defaults: ["fluoride_bta_defaults"],
+ srcs: [
+ "ag/bta_ag_act.cc",
+ "ag/bta_ag_api.cc",
+ "ag/bta_ag_at.cc",
+ "ag/bta_ag_cfg.cc",
+ "ag/bta_ag_ci.cc",
+ "ag/bta_ag_cmd.cc",
+ "ag/bta_ag_main.cc",
+ "ag/bta_ag_rfc.cc",
+ "ag/bta_ag_sco.cc",
+ "ag/bta_ag_sdp.cc",
+ "ar/bta_ar.cc",
+ "av/bta_av_aact.cc",
+ "av/bta_av_act.cc",
+ "av/bta_av_api.cc",
+ "av/bta_av_cfg.cc",
+ "av/bta_av_ci.cc",
+ "av/bta_av_main.cc",
+ "av/bta_av_ssm.cc",
+ "closure/bta_closure.cc",
+ "dm/bta_dm_act.cc",
+ "dm/bta_dm_api.cc",
+ "dm/bta_dm_cfg.cc",
+ "dm/bta_dm_ci.cc",
+ "dm/bta_dm_main.cc",
+ "dm/bta_dm_pm.cc",
+ "dm/bta_dm_sco.cc",
+ "gatt/bta_gattc_act.cc",
+ "gatt/bta_gattc_api.cc",
+ "gatt/bta_gattc_cache.cc",
+ "gatt/bta_gattc_main.cc",
+ "gatt/bta_gattc_utils.cc",
+ "gatt/bta_gatts_act.cc",
+ "gatt/bta_gatts_api.cc",
+ "gatt/bta_gatts_main.cc",
+ "gatt/bta_gatts_utils.cc",
+ "hf_client/bta_hf_client_act.cc",
+ "hf_client/bta_hf_client_api.cc",
+ "hf_client/bta_hf_client_at.cc",
+ "hf_client/bta_hf_client_main.cc",
+ "hf_client/bta_hf_client_rfc.cc",
+ "hf_client/bta_hf_client_sco.cc",
+ "hf_client/bta_hf_client_sdp.cc",
+ "hh/bta_hh_act.cc",
+ "hh/bta_hh_api.cc",
+ "hh/bta_hh_cfg.cc",
+ "hh/bta_hh_le.cc",
+ "hh/bta_hh_main.cc",
+ "hh/bta_hh_utils.cc",
+ "hl/bta_hl_act.cc",
+ "hl/bta_hl_api.cc",
+ "hl/bta_hl_ci.cc",
+ "hl/bta_hl_main.cc",
+ "hl/bta_hl_sdp.cc",
+ "hl/bta_hl_utils.cc",
+ "hd/bta_hd_act.cc",
+ "hd/bta_hd_api.cc",
+ "hd/bta_hd_main.cc",
+ "jv/bta_jv_act.cc",
+ "jv/bta_jv_api.cc",
+ "jv/bta_jv_cfg.cc",
+ "jv/bta_jv_main.cc",
+ "mce/bta_mce_act.cc",
+ "mce/bta_mce_api.cc",
+ "mce/bta_mce_cfg.cc",
+ "mce/bta_mce_main.cc",
+ "pan/bta_pan_act.cc",
+ "pan/bta_pan_api.cc",
+ "pan/bta_pan_ci.cc",
+ "pan/bta_pan_main.cc",
+ "sdp/bta_sdp.cc",
+ "sdp/bta_sdp_act.cc",
+ "sdp/bta_sdp_api.cc",
+ "sdp/bta_sdp_cfg.cc",
+ "sys/bta_sys_conn.cc",
+ "sys/bta_sys_main.cc",
+ "sys/utl.cc",
+ ],
+}
+
+// bta unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_bta",
+ defaults: ["fluoride_bta_defaults"],
+ srcs: [
+ "test/bta_closure_test.cc",
+ "test/bta_hf_client_test.cc",
+ ],
+ shared_libs: [
+ "libhardware",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libbt-bta",
+ "libosi",
+ "libbt-protos",
+ ],
+}
diff --git a/mtkbt/code/bt/bta/BUILD.gn b/mtkbt/code/bt/bta/BUILD.gn
new file mode 100755
index 0000000..56a7597
--- a/dev/null
+++ b/mtkbt/code/bt/bta/BUILD.gn
@@ -0,0 +1,119 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("bta") {
+ sources = [
+ "ag/bta_ag_act.cc",
+ "ag/bta_ag_api.cc",
+ "ag/bta_ag_at.cc",
+ "ag/bta_ag_cfg.cc",
+ "ag/bta_ag_ci.cc",
+ "ag/bta_ag_cmd.cc",
+ "ag/bta_ag_main.cc",
+ "ag/bta_ag_rfc.cc",
+ "ag/bta_ag_sco.cc",
+ "ag/bta_ag_sdp.cc",
+ "ar/bta_ar.cc",
+ "av/bta_av_aact.cc",
+ "av/bta_av_act.cc",
+ "av/bta_av_api.cc",
+ "av/bta_av_cfg.cc",
+ "av/bta_av_ci.cc",
+ "av/bta_av_main.cc",
+ "av/bta_av_ssm.cc",
+ "closure/bta_closure.cc",
+ "dm/bta_dm_act.cc",
+ "dm/bta_dm_api.cc",
+ "dm/bta_dm_cfg.cc",
+ "dm/bta_dm_ci.cc",
+ "dm/bta_dm_main.cc",
+ "dm/bta_dm_pm.cc",
+ "dm/bta_dm_sco.cc",
+ "gatt/bta_gattc_act.cc",
+ "gatt/bta_gattc_api.cc",
+ "gatt/bta_gattc_cache.cc",
+ "gatt/bta_gattc_main.cc",
+ "gatt/bta_gattc_utils.cc",
+ "gatt/bta_gatts_act.cc",
+ "gatt/bta_gatts_api.cc",
+ "gatt/bta_gatts_main.cc",
+ "gatt/bta_gatts_utils.cc",
+ "hf_client/bta_hf_client_act.cc",
+ "hf_client/bta_hf_client_api.cc",
+ "hf_client/bta_hf_client_at.cc",
+ "hf_client/bta_hf_client_main.cc",
+ "hf_client/bta_hf_client_rfc.cc",
+ "hf_client/bta_hf_client_sdp.cc",
+ "hf_client/bta_hf_client_sco.cc",
+ "hh/bta_hh_act.cc",
+ "hh/bta_hh_api.cc",
+ "hh/bta_hh_cfg.cc",
+ "hh/bta_hh_le.cc",
+ "hh/bta_hh_main.cc",
+ "hh/bta_hh_utils.cc",
+ "hd/bta_hd_act.cc",
+ "hd/bta_hd_api.cc",
+ "hd/bta_hd_main.cc",
+ "hl/bta_hl_act.cc",
+ "hl/bta_hl_api.cc",
+ "hl/bta_hl_ci.cc",
+ "hl/bta_hl_main.cc",
+ "hl/bta_hl_sdp.cc",
+ "hl/bta_hl_utils.cc",
+ "jv/bta_jv_act.cc",
+ "jv/bta_jv_api.cc",
+ "jv/bta_jv_cfg.cc",
+ "jv/bta_jv_main.cc",
+ "mce/bta_mce_act.cc",
+ "mce/bta_mce_api.cc",
+ "mce/bta_mce_cfg.cc",
+ "mce/bta_mce_main.cc",
+ "pan/bta_pan_act.cc",
+ "pan/bta_pan_api.cc",
+ "pan/bta_pan_ci.cc",
+ "pan/bta_pan_main.cc",
+ "sdp/bta_sdp.cc",
+ "sdp/bta_sdp_act.cc",
+ "sdp/bta_sdp_api.cc",
+ "sdp/bta_sdp_cfg.cc",
+ "sys/bta_sys_conn.cc",
+ "sys/bta_sys_main.cc",
+ "sys/utl.cc",
+ ]
+
+ include_dirs = [
+ "closure",
+ "dm",
+ "hh",
+ "hd",
+ "include",
+ "sys",
+ "//",
+ "//btcore/include",
+ "//hci/include",
+ "//include",
+ "//stack/include",
+ "//stack/btm",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base"
+ ]
+
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_act.cc b/mtkbt/code/bt/bta/ag/bta_ag_act.cc
new file mode 100755
index 0000000..f145904
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_act.cc
@@ -0,0 +1,863 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for the audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_sys.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX 512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX 512
+
+const uint16_t bta_ag_uuid[BTA_AG_NUM_IDX] = {
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, UUID_SERVCLASS_AG_HANDSFREE};
+
+const uint8_t bta_ag_sec_id[BTA_AG_NUM_IDX] = {BTM_SEC_SERVICE_HEADSET_AG,
+ BTM_SEC_SERVICE_AG_HANDSFREE};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] = {BTA_HSP_SERVICE_ID,
+ BTA_HFP_SERVICE_ID};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] = {
+ BTA_HSP_SERVICE_MASK, BTA_HFP_SERVICE_MASK};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB* p_scb, uint16_t cmd,
+ uint8_t arg_type, char* p_arg,
+ int16_t int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] = {
+ bta_ag_at_hsp_cback, bta_ag_at_hfp_cback};
+
+/*******************************************************************************
+ *
+ * Function bta_ag_cback_open
+ *
+ * Description Send open callback event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data,
+ tBTA_AG_STATUS status) {
+ tBTA_AG_OPEN open;
+
+ /* call app callback with open event */
+ open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ open.hdr.app_id = p_scb->app_id;
+ open.status = status;
+ open.service_id = bta_ag_svc_id[p_scb->conn_service];
+ if (p_data) {
+ /* if p_data is provided then we need to pick the bd address from the open
+ * api structure */
+ bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+ } else {
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ }
+
+ (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG*)&open);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_register
+ *
+ * Description This function initializes values of the AG cb and sets up
+ * the SDP record for the services.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ tBTA_AG_REGISTER reg;
+
+ /* initialize control block */
+ p_scb->reg_services = p_data->api_register.services;
+ p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+ p_scb->features = p_data->api_register.features;
+ p_scb->app_id = p_data->api_register.app_id;
+
+ /* create SDP records */
+ bta_ag_create_records(p_scb, p_data);
+
+ /* start RFCOMM servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* call app callback with register event */
+ reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ reg.hdr.app_id = p_scb->app_id;
+ reg.status = BTA_AG_SUCCESS;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG*)&reg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_deregister
+ *
+ * Description This function removes the sdp records, closes the RFCOMM
+ * servers, and deallocates the service control block.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* set dealloc */
+ p_scb->dealloc = true;
+
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+
+ /* remove rfcomm servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+ /* dealloc */
+ bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_start_dereg
+ *
+ * Description Start a deregister event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* set dealloc */
+ p_scb->dealloc = true;
+
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_start_open
+ *
+ * Description This starts an AG open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ BD_ADDR pending_bd_addr;
+
+ /* store parameters */
+ if (p_data) {
+ bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+ p_scb->open_services = p_data->api_open.services;
+ p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+ }
+
+ /* Check if RFCOMM has any incoming connection to avoid collision. */
+ if (PORT_IsOpening(pending_bd_addr)) {
+ /* Let the incoming connection goes through. */
+ /* Issue collision for this scb for now. */
+ /* We will decide what to do when we find incoming connetion later. */
+ bta_ag_collision_cback(0, BTA_ID_AG, 0, p_scb->peer_addr);
+ return;
+ }
+
+ /* close servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+
+ /* set role */
+ p_scb->role = BTA_AG_INT;
+
+ /* do service search */
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_disc_int_res
+ *
+ * Description This function handles a discovery result when initiator.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ uint16_t event = BTA_AG_DISC_FAIL_EVT;
+
+ APPL_TRACE_DEBUG("bta_ag_disc_int_res: Status: %d",
+ p_data->disc_result.status);
+
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services)) {
+ /* set connected service */
+ p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+
+ /* send ourselves sdp ok event */
+ event = BTA_AG_DISC_OK_EVT;
+ }
+ }
+
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+
+ /* if service not found check if we should search for other service */
+ if ((event == BTA_AG_DISC_FAIL_EVT) &&
+ (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL ||
+ p_data->disc_result.status == SDP_NO_RECS_MATCH)) {
+ if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+ (p_scb->open_services & BTA_HSP_SERVICE_MASK)) {
+ /* search for HSP */
+ p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ } else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+ (p_scb->hsp_version == HSP_VERSION_1_2)) {
+ /* search for UUID_SERVCLASS_HEADSET instead */
+ p_scb->hsp_version = HSP_VERSION_1_0;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ } else {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+ } else {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_disc_acp_res
+ *
+ * Description This function handles a discovery result when acceptor.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+ }
+
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_disc_fail
+ *
+ * Description This function handles a discovery failure.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* reinitialize stuff */
+
+ /* clear the remote BD address */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_open_fail
+ *
+ * Description open connection failed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_fail
+ *
+ * Description RFCOMM connection failed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ /* reinitialize stuff */
+ p_scb->conn_handle = 0;
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+ p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+ p_scb->role = 0;
+ p_scb->svc_conn = false;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+ /*Clear the BD address*/
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_close
+ *
+ * Description RFCOMM connection closed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ tBTA_AG_CLOSE close;
+ tBTA_SERVICE_MASK services;
+ int i, num_active_conn = 0;
+
+ /* reinitialize stuff */
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+ p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+ /* Clear these flags upon SLC teardown */
+ p_scb->codec_updated = false;
+ p_scb->codec_fallback = false;
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+ p_scb->role = 0;
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ p_scb->svc_conn = false;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+ bta_ag_at_reinit(&p_scb->at_cb);
+
+ memset(&(p_scb->peer_hf_indicators), 0, sizeof(p_scb->peer_hf_indicators));
+ memset(&(p_scb->local_hf_indicators), 0, sizeof(p_scb->local_hf_indicators));
+
+ /* stop timers */
+ alarm_cancel(p_scb->ring_timer);
+ alarm_cancel(p_scb->codec_negotiation_timer);
+
+ close.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ close.hdr.app_id = p_scb->app_id;
+ bdcpy(close.bd_addr, p_scb->peer_addr);
+
+ bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* call close call-out */
+ bta_ag_co_data_close(close.hdr.handle);
+
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG*)&close);
+
+ /* if not deregistering (deallocating) reopen registered servers */
+ if (p_scb->dealloc == false) {
+ /* Clear peer bd_addr so instance can be reused */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+
+ /* start only unopened server */
+ services = p_scb->reg_services;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++) {
+ if (p_scb->serv_handle[i])
+ services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+ }
+ bta_ag_start_servers(p_scb, services);
+
+ p_scb->conn_handle = 0;
+
+ /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+ bta_ag_sco_shutdown(p_scb, NULL);
+
+ /* Check if all the SLCs are down */
+ for (i = 0; i < BTA_AG_NUM_SCB; i++) {
+ if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn)
+ num_active_conn++;
+ }
+
+ if (!num_active_conn) {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ }
+ /* else close port and deallocate scb */
+ else {
+ RFCOMM_RemoveServer(p_scb->conn_handle);
+ bta_ag_scb_dealloc(p_scb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_open
+ *
+ * Description Handle RFCOMM channel open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* initialize AT feature variables */
+ p_scb->clip_enabled = false;
+ p_scb->ccwa_enabled = false;
+ p_scb->cmer_enabled = false;
+ p_scb->cmee_enabled = false;
+ p_scb->inband_enabled =
+ ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+ /* set up AT command interpreter */
+ p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD*)bta_ag_at_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_cmd_cback =
+ (tBTA_AG_AT_CMD_CBACK*)bta_ag_at_cback_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK*)bta_ag_at_err_cback;
+ p_scb->at_cb.p_user = p_scb;
+ p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+ bta_ag_at_init(&p_scb->at_cb);
+
+ /* call app open call-out */
+ bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb),
+ bta_ag_svc_id[p_scb->conn_service]);
+
+ bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+ if (p_scb->conn_service == BTA_AG_HFP) {
+ /* if hfp start timer for service level conn */
+ bta_sys_start_timer(p_scb->ring_timer, p_bta_ag_cfg->conn_tout,
+ BTA_AG_SVC_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
+ } else {
+ /* else service level conn is open */
+ bta_ag_svc_conn_open(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_acp_open
+ *
+ * Description Handle RFCOMM channel open when accepting connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ uint16_t lcid;
+ int i;
+ tBTA_AG_SCB *ag_scb, *other_scb;
+ BD_ADDR dev_addr;
+ int status;
+
+ /* set role */
+ p_scb->role = BTA_AG_ACP;
+
+ APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+ p_scb->serv_handle[0], p_scb->serv_handle[1]);
+
+ /* get bd addr of peer */
+ if (PORT_SUCCESS != (status = PORT_CheckConnection(p_data->rfc.port_handle,
+ dev_addr, &lcid))) {
+ APPL_TRACE_DEBUG(
+ "bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d",
+ status);
+ }
+
+ /* Collision Handling */
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) {
+ if (ag_scb->in_use && alarm_is_scheduled(ag_scb->collision_timer)) {
+ alarm_cancel(ag_scb->collision_timer);
+
+ if (bdcmp(dev_addr, ag_scb->peer_addr) == 0) {
+ /* If incoming and outgoing device are same, nothing more to do. */
+ /* Outgoing conn will be aborted because we have successful incoming
+ * conn. */
+ } else {
+ /* Resume outgoing connection. */
+ other_scb = bta_ag_get_other_idle_scb(p_scb);
+ if (other_scb) {
+ bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+ other_scb->open_services = ag_scb->open_services;
+ other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+
+ bta_ag_resume_open(other_scb);
+ }
+ }
+
+ break;
+ }
+ }
+
+ bdcpy(p_scb->peer_addr, dev_addr);
+
+ /* determine connected service from port handle */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ APPL_TRACE_DEBUG(
+ "bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d", i,
+ p_scb->serv_handle[i], p_data->rfc.port_handle);
+
+ if (p_scb->serv_handle[i] == p_data->rfc.port_handle) {
+ p_scb->conn_service = i;
+ p_scb->conn_handle = p_data->rfc.port_handle;
+ break;
+ }
+ }
+
+ APPL_TRACE_DEBUG("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+ p_scb->conn_service, p_scb->conn_handle);
+
+ /* close any unopened server */
+ bta_ag_close_servers(
+ p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+
+ /* do service discovery to get features */
+ bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+
+ /* continue with common open processing */
+ bta_ag_rfc_open(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_data
+ *
+ * Description Read and process data from RFCOMM.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ uint16_t len;
+ char buf[BTA_AG_RFC_READ_MAX];
+
+ memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* do the following */
+ for (;;) {
+ /* read data from rfcomm; if bad status, we're done */
+ if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) !=
+ PORT_SUCCESS) {
+ break;
+ }
+
+ /* if no data, we're done */
+ if (len == 0) {
+ break;
+ }
+
+ /* run AT command interpreter on data */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ bta_ag_at_parse(&p_scb->at_cb, buf, len);
+ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) &&
+ bta_ag_sco_is_open(p_scb)) {
+ APPL_TRACE_DEBUG("%s change link policy for SCO", __func__);
+ bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ } else {
+ bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ /* no more data to read, we're done */
+ if (len < BTA_AG_RFC_READ_MAX) {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_start_close
+ *
+ * Description Start the process of closing SCO and RFCOMM connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ /* Take the link out of sniff and set L2C idle time to 0 */
+ bta_dm_pm_active(p_scb->peer_addr);
+ L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0, BT_TRANSPORT_BR_EDR);
+
+ /* if SCO is open close SCO and wait on RFCOMM close */
+ if (bta_ag_sco_is_open(p_scb)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_rfc_do_close(p_scb, p_data);
+ }
+
+ /* always do SCO shutdown to handle all SCO corner cases */
+ bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_post_sco_open
+ *
+ * Description Perform post-SCO open action, if any
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ switch (p_scb->post_sco) {
+ case BTA_AG_POST_SCO_RING:
+ bta_ag_send_ring(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_post_sco_close
+ *
+ * Description Perform post-SCO close action, if any
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ switch (p_scb->post_sco) {
+ case BTA_AG_POST_SCO_CLOSE_RFC:
+ bta_ag_rfc_do_close(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_ORIG:
+ bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END:
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END_INCALL:
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+
+ /* Sending callsetup IND and Ring were defered to after SCO close. */
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+ if (bta_ag_inband_enabled(p_scb) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, p_data);
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_send_ring(p_scb, p_data);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_svc_conn_open
+ *
+ * Description Service level connection opened
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ tBTA_AG_CONN evt;
+
+ if (!p_scb->svc_conn) {
+ /* set state variable */
+ p_scb->svc_conn = true;
+
+ /* Clear AT+BIA mask from previous SLC if any. */
+ p_scb->bia_masked_out = 0;
+
+ alarm_cancel(p_scb->ring_timer);
+
+ /* call callback */
+ evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ evt.hdr.app_id = p_scb->app_id;
+ evt.peer_feat = p_scb->peer_features;
+ bdcpy(evt.bd_addr, p_scb->peer_addr);
+ evt.peer_codec = p_scb->peer_codecs;
+
+ if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+ (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) {
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG*)&evt);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_ci_rx_data
+ *
+ * Description Send result code
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ uint16_t len;
+ tBTA_AG_CI_RX_WRITE* p_rx_write_msg = (tBTA_AG_CI_RX_WRITE*)p_data;
+ char* p_data_area =
+ (char*)(p_rx_write_msg + 1); /* Point to data area after header */
+
+ APPL_TRACE_DEBUG("bta_ag_ci_rx_data:");
+ /* send to RFCOMM */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) && bta_ag_sco_is_open(p_scb)) {
+ APPL_TRACE_DEBUG("bta_ag_rfc_data, change link policy for SCO");
+ bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ } else {
+ bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rcvd_slc_ready
+ *
+ * Description Handles SLC ready call-in in case of pass-through mode.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ APPL_TRACE_DEBUG("bta_ag_rcvd_slc_ready: handle = %d",
+ bta_ag_scb_to_idx(p_scb));
+
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+ /* In pass-through mode, BTA knows that SLC is ready only through call-in.
+ */
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_setcodec
+ *
+ * Description Handle API SetCodec
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+ tBTA_AG_VAL val;
+
+ /** M: Bug Fix For Invalid index @{ */
+ // Set handle to avoid Invalid index in btif_hf_upstreams_evt
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ /** @} */
+
+ /* Check if the requested codec type is valid */
+ if ((codec_type != BTA_AG_CODEC_NONE) && (codec_type != BTA_AG_CODEC_CVSD) &&
+ (codec_type != BTA_AG_CODEC_MSBC)) {
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d",
+ codec_type);
+ (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
+ return;
+ }
+
+ if ((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) ||
+ (codec_type == BTA_AG_CODEC_CVSD)) {
+ p_scb->sco_codec = codec_type;
+ p_scb->codec_updated = true;
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_SUCCESS;
+ APPL_TRACE_DEBUG("bta_ag_setcodec: Updated codec type %d", codec_type);
+ } else {
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d",
+ codec_type);
+ }
+
+ (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG*)&val);
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_api.cc b/mtkbt/code/bt/bta/ag/bta_ag_api.cc
new file mode 100755
index 0000000..6df3a1e
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_api.cc
@@ -0,0 +1,278 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for the audio gateway (AG)
+ * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+
+#include "bta_ag_api.h"
+#include <string.h>
+#include "bt_common.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg = {bta_ag_hdl_event, BTA_AgDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_AgEnable
+ *
+ * Description Enable the audio gateway service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_AG_ENABLE_EVT. This function must
+ * be called before other function in the AG API are
+ * called.
+ *
+ * Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode,
+ tBTA_AG_CBACK* p_cback) {
+ /* Error if AG is already enabled, or AG is in the middle of disabling. */
+ for (int idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+ if (bta_ag_cb.scb[idx].in_use) {
+ APPL_TRACE_ERROR("BTA_AgEnable: FAILED, AG already enabled.");
+ return BTA_FAILURE;
+ }
+ }
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+
+ tBTA_AG_API_ENABLE* p_buf =
+ (tBTA_AG_API_ENABLE*)osi_malloc(sizeof(tBTA_AG_API_ENABLE));
+ p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+ p_buf->parse_mode = parse_mode;
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgDisable
+ *
+ * Description Disable the audio gateway service
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AG_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgRegister
+ *
+ * Description Register an Audio Gateway service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+ tBTA_AG_FEAT features, const char* p_service_names[],
+ uint8_t app_id) {
+ tBTA_AG_API_REGISTER* p_buf =
+ (tBTA_AG_API_REGISTER*)osi_malloc(sizeof(tBTA_AG_API_REGISTER));
+
+ p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+ p_buf->features = features;
+ p_buf->sec_mask = sec_mask;
+ p_buf->services = services;
+ p_buf->app_id = app_id;
+ for (int i = 0; i < BTA_AG_NUM_IDX; i++) {
+ if (p_service_names[i])
+ strlcpy(p_buf->p_name[i], p_service_names[i], BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->p_name[i][0] = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgDeregister
+ *
+ * Description Deregister an audio gateway service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgDeregister(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgOpen
+ *
+ * Description Opens a connection to a headset or hands-free device.
+ * When connection is open callback function is called
+ * with a BTA_AG_OPEN_EVT. Only the data connection is
+ * opened. The audio connection is not opened.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask,
+ tBTA_SERVICE_MASK services) {
+ tBTA_AG_API_OPEN* p_buf =
+ (tBTA_AG_API_OPEN*)osi_malloc(sizeof(tBTA_AG_API_OPEN));
+
+ p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->services = services;
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgClose
+ *
+ * Description Close the current connection to a headset or a handsfree
+ * Any current audio connection will also be closed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgClose(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AG_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgAudioOpen
+ *
+ * Description Opens an audio connection to the currently connected
+ * headset or hnadsfree.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgAudioOpen(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgAudioClose
+ *
+ * Description Close the currently active audio connection to a headset
+ * or hnadsfree. The data connection remains open
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgAudioClose(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgResult
+ *
+ * Description Send an AT result code to a headset or hands-free device.
+ * This function is only used when the AG parse mode is set
+ * to BTA_AG_PARSE.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
+ tBTA_AG_RES_DATA* p_data) {
+ tBTA_AG_API_RESULT* p_buf =
+ (tBTA_AG_API_RESULT*)osi_malloc(sizeof(tBTA_AG_API_RESULT));
+
+ p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->result = result;
+ if (p_data) memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AgSetCodec
+ *
+ * Description Specify the codec type to be used for the subsequent
+ * audio connection.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec) {
+ tBTA_AG_API_SETCODEC* p_buf =
+ (tBTA_AG_API_SETCODEC*)osi_malloc(sizeof(tBTA_AG_API_SETCODEC));
+
+ p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->codec = codec;
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_at.cc b/mtkbt/code/bt/bta/ag/bta_ag_at.cc
new file mode 100755
index 0000000..3e4868b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_at.cc
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_at.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * Function bta_ag_at_init
+ *
+ * Description Initialize the AT command parser control block.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB* p_cb) {
+ p_cb->p_cmd_buf = NULL;
+ p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+ *
+ * Function bta_ag_at_reinit
+ *
+ * Description Re-initialize the AT command parser control block. This
+ * function resets the AT command parser state and frees
+ * any GKI buffer.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB* p_cb) {
+ osi_free_and_reset((void**)&p_cb->p_cmd_buf);
+ p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+ *
+ * Function bta_ag_process_at
+ *
+ * Description Parse AT commands. This function will take the input
+ * character string and parse it for AT commands according to
+ * the AT command table passed in the control block.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB* p_cb) {
+ uint16_t idx;
+ uint8_t arg_type;
+ char* p_arg;
+ int16_t int_arg = 0;
+ /* loop through at command table looking for match */
+ for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) {
+ if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) {
+ break;
+ }
+ }
+
+ /* if there is a match; verify argument type */
+ if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) {
+ /* start of argument is p + strlen matching command */
+ p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+
+ /* if no argument */
+ if (p_arg[0] == 0) {
+ arg_type = BTA_AG_AT_NONE;
+ }
+ /* else if arg is '?' and it is last character */
+ else if (p_arg[0] == '?' && p_arg[1] == 0) {
+ /* we have a read */
+ arg_type = BTA_AG_AT_READ;
+ }
+ /* else if arg is '=' */
+ else if (p_arg[0] == '=' && p_arg[1] != 0) {
+ if (p_arg[1] == '?' && p_arg[2] == 0) {
+ /* we have a test */
+ arg_type = BTA_AG_AT_TEST;
+ } else {
+ /* we have a set */
+ arg_type = BTA_AG_AT_SET;
+
+ /* skip past '=' */
+ p_arg++;
+ }
+ } else
+ /* else it is freeform argument */
+ {
+ arg_type = BTA_AG_AT_FREE;
+ }
+
+ /* if arguments match command capabilities */
+ if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) {
+ /* if it's a set integer check max, min range */
+ if (arg_type == BTA_AG_AT_SET &&
+ p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) {
+ int_arg = utl_str2int(p_arg);
+ if (int_arg < (int16_t)p_cb->p_at_tbl[idx].min ||
+ int_arg > (int16_t)p_cb->p_at_tbl[idx].max) {
+ /* arg out of range; error */
+ (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+ } else {
+ (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
+ arg_type, p_arg, int_arg);
+ }
+ } else {
+ (*p_cb->p_cmd_cback)(p_cb->p_user, p_cb->p_at_tbl[idx].command_id,
+ arg_type, p_arg, int_arg);
+ }
+ }
+ /* else error */
+ else {
+ (*p_cb->p_err_cback)(p_cb->p_user, false, NULL);
+ }
+ }
+ /* else no match call error callback */
+ else {
+ (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+ }
+}
+
+/******************************************************************************
+ *
+ * Function bta_ag_at_parse
+ *
+ * Description Parse AT commands. This function will take the input
+ * character string and parse it for AT commands according to
+ * the AT command table passed in the control block.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len) {
+ int i = 0;
+ char* p_save;
+
+ if (p_cb->p_cmd_buf == NULL) {
+ p_cb->p_cmd_buf = (char*)osi_malloc(p_cb->cmd_max_len);
+ p_cb->cmd_pos = 0;
+ }
+
+ for (i = 0; i < len;) {
+ while (p_cb->cmd_pos < p_cb->cmd_max_len - 1 && i < len) {
+ /* Skip null characters between AT commands. */
+ if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
+ i++;
+ continue;
+ }
+
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+ if (p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' ||
+ p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+ if ((p_cb->cmd_pos > 2) &&
+ (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+ (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
+ p_save = p_cb->p_cmd_buf;
+ p_cb->p_cmd_buf += 2;
+ bta_ag_process_at(p_cb);
+ p_cb->p_cmd_buf = p_save;
+ }
+
+ p_cb->cmd_pos = 0;
+
+ } else if (p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A ||
+ p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
+ p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+ (*p_cb->p_err_cback)(p_cb->p_user, true, p_cb->p_cmd_buf);
+ p_cb->cmd_pos = 0;
+ } else {
+ ++p_cb->cmd_pos;
+ }
+ }
+
+ if (i < len) p_cb->cmd_pos = 0;
+ }
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_at.h b/mtkbt/code/bt/bta/ag/bta_ag_at.h
new file mode 100755
index 0000000..144bc38
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_at.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Interface file for BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE 0x01 /* no argument */
+#define BTA_AG_AT_SET 0x02 /* set value */
+#define BTA_AG_AT_READ 0x04 /* read value */
+#define BTA_AG_AT_TEST 0x08 /* test value range */
+#define BTA_AG_AT_FREE 0x10 /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR 0 /* string */
+#define BTA_AG_AT_INT 1 /* integer */
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+
+/* AT command table element */
+typedef struct {
+ const char* p_cmd; /* AT command string */
+ size_t command_id; /* passed to the callback on p_cmd match */
+ uint8_t arg_type; /* allowable argument type syntax */
+ uint8_t fmt; /* whether arg is int or string */
+ uint8_t min; /* minimum value for int arg */
+ int16_t max; /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void(tBTA_AG_AT_CMD_CBACK)(void* p_user, uint16_t command_id,
+ uint8_t arg_type, char* p_arg,
+ int16_t int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void(tBTA_AG_AT_ERR_CBACK)(void* p_user, bool unknown, char* p_arg);
+
+/* AT command parsing control block */
+typedef struct {
+ tBTA_AG_AT_CMD* p_at_tbl; /* AT command table */
+ tBTA_AG_AT_CMD_CBACK* p_cmd_cback; /* command callback */
+ tBTA_AG_AT_ERR_CBACK* p_err_cback; /* error callback */
+ void* p_user; /* user-defined data */
+ char* p_cmd_buf; /* temp parsing buffer */
+ uint16_t cmd_pos; /* position in temp buffer */
+ uint16_t cmd_max_len; /* length of temp buffer to allocate */
+ uint8_t state; /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function bta_ag_at_init
+ *
+ * Description Initialize the AT command parser control block.
+ *
+ *
+ * Returns void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB* p_cb);
+
+/*****************************************************************************
+ *
+ * Function bta_ag_at_reinit
+ *
+ * Description Re-initialize the AT command parser control block. This
+ * function resets the AT command parser state and frees
+ * any GKI buffer.
+ *
+ *
+ * Returns void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB* p_cb);
+
+/*****************************************************************************
+ *
+ * Function bta_ag_at_parse
+ *
+ * Description Parse AT commands. This function will take the input
+ * character string and parse it for AT commands according to
+ * the AT command table passed in the control block.
+ *
+ *
+ * Returns void
+ *
+ ****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB* p_cb, char* p_buf, uint16_t len);
+
+#endif /* BTA_AG_AT_H */
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_cfg.cc b/mtkbt/code/bt/bta/ag/bta_ag_cfg.cc
new file mode 100755
index 0000000..5a9bf8c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_cfg.cc
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for the audio
+ * gateway.
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO \
+ "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-" \
+ "6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2)),(\"bearer\"," \
+ "(0-7))"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3,4)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL "(0,1,2,3,4)"
+#endif
+
+#ifndef BTA_AG_CONN_TIMEOUT
+//#define BTA_AG_CONN_TIMEOUT 5000
+/** M: Change Feature For SLC check timer @{ */
+// Some device send CHLD slowly, in order to avoid fail,
+// extend the timer value to 15 seconds.
+#define BTA_AG_CONN_TIMEOUT 15000
+/** @} */
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+/* S1 packet type setting from HFP 1.5 spec */
+#define BTA_AG_SCO_PKT_TYPES /* BTM_SCO_LINK_ALL_PKT_MASK */ \
+ (BTM_SCO_LINK_ONLY_MASK | ESCO_PKT_TYPES_MASK_EV3 | \
+ ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ ESCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+#ifndef BTA_AG_BIND_INFO
+#define BTA_AG_BIND_INFO "(1)"
+#endif
+
+const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[] = {
+ /* The first row contains the number of indicators. Need to be updated
+ accordingly */
+ {BTA_AG_NUM_LOCAL_HF_IND, 0, 0, 0, 0},
+
+ {1, 1, 1, 0,
+ 1}, /* Enhanced Driver Status, supported, enabled, range 0 ~ 1 */
+ {2, 1, 1, 0,
+ 100} /* Battery Level Status, supported, enabled, range 0 ~ 100 */
+};
+
+const tBTA_AG_CFG bta_ag_cfg = {BTA_AG_CIND_INFO, BTA_AG_BIND_INFO,
+ BTA_AG_NUM_LOCAL_HF_IND, BTA_AG_CONN_TIMEOUT,
+ BTA_AG_SCO_PKT_TYPES, BTA_AG_CHLD_VAL_ECC,
+ BTA_AG_CHLD_VAL};
+
+tBTA_AG_CFG* p_bta_ag_cfg = (tBTA_AG_CFG*)&bta_ag_cfg;
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_ci.cc b/mtkbt/code/bt/bta/ag/bta_ag_ci.cc
new file mode 100755
index 0000000..1fde9d8
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_ci.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for audio gateway call-in functions.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_ci.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+
+/******************************************************************************
+ *
+ * Function bta_ag_ci_rx_write
+ *
+ * Description This function is called to send data to the AG when the AG
+ * is configured for AT command pass-through. The function
+ * copies data to an event buffer and sends it.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len) {
+ uint16_t len_remaining = len;
+ char* p_data_area;
+
+ if (len > (RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1))
+ len = RFCOMM_DATA_BUF_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
+
+ while (len_remaining) {
+ if (len_remaining < len) len = len_remaining;
+
+ tBTA_AG_CI_RX_WRITE* p_buf =
+ (tBTA_AG_CI_RX_WRITE*)osi_malloc(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1);
+ p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
+ p_buf->hdr.layer_specific = handle;
+
+ p_data_area = (char*)(p_buf + 1); /* Point to data area after header */
+ strncpy(p_data_area, p_data, len);
+ p_data_area[len] = 0;
+
+ bta_sys_sendmsg(p_buf);
+
+ len_remaining -= len;
+ p_data += len;
+ }
+}
+
+/******************************************************************************
+ *
+ * Function bta_ag_ci_slc_ready
+ *
+ * Description This function is called to notify AG that SLC is up at
+ * the application. This funcion is only used when the app
+ * is running in pass-through mode.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ag_ci_slc_ready(uint16_t handle) {
+ tBTA_AG_DATA* p_buf = (tBTA_AG_DATA*)osi_malloc(sizeof(tBTA_AG_DATA));
+
+ p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
+ p_buf->hdr.layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_cmd.cc b/mtkbt/code/bt/bta/ag/bta_ag_cmd.cc
new file mode 100755
index 0000000..a99a48d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_cmd.cc
@@ -0,0 +1,1769 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bta_ag_cmd"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Ring timeout */
+#define BTA_AG_RING_TIMEOUT_MS (5 * 1000) /* 5 seconds */
+
+#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */
+
+/* Invalid Chld command */
+#define BTA_AG_INVALID_CHLD 255
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN 128
+#define BTA_AG_CLIP_TYPE_MAX 175
+#define BTA_AG_CLIP_TYPE_DEFAULT 129
+#define BTA_AG_CLIP_TYPE_VOIP 255
+
+#define COLON_IDX_4_VGSVGM 4
+
+/* Local events which will not trigger a higher layer callback */
+enum {
+ BTA_AG_LOCAL_EVT_FIRST = 0x100,
+ BTA_AG_LOCAL_EVT_CCWA,
+ BTA_AG_LOCAL_EVT_CLIP,
+ BTA_AG_LOCAL_EVT_CMER,
+ BTA_AG_LOCAL_EVT_BRSF,
+ BTA_AG_LOCAL_EVT_CMEE,
+ BTA_AG_LOCAL_EVT_BIA,
+ BTA_AG_LOCAL_EVT_BCC,
+};
+
+/* AT command interpreter table for HSP */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] = {
+ {"+CKPD", BTA_AG_AT_CKPD_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
+ {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ /* End-of-table marker used to stop lookup iteration */
+ {"", 0, 0, 0, 0, 0}};
+
+/* AT command interpreter table for HFP */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = {
+ {"A", BTA_AG_AT_A_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"D", BTA_AG_AT_D_EVT, BTA_AG_AT_NONE | BTA_AG_AT_FREE, BTA_AG_AT_STR, 0,
+ 0},
+ {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+CCWA", BTA_AG_LOCAL_EVT_CCWA, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ /* Consider CHLD as str to take care of indexes for ECC */
+ {"+CHLD", BTA_AG_AT_CHLD_EVT, BTA_AG_AT_SET | BTA_AG_AT_TEST, BTA_AG_AT_STR,
+ 0, 4},
+ {"+CHUP", BTA_AG_AT_CHUP_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+CIND", BTA_AG_AT_CIND_EVT, BTA_AG_AT_READ | BTA_AG_AT_TEST,
+ BTA_AG_AT_STR, 0, 0},
+ {"+CLIP", BTA_AG_LOCAL_EVT_CLIP, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+CMER", BTA_AG_LOCAL_EVT_CMER, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+VTS", BTA_AG_AT_VTS_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BINP", BTA_AG_AT_BINP_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
+ {"+BLDN", BTA_AG_AT_BLDN_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BVRA", BTA_AG_AT_BVRA_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BRSF", BTA_AG_LOCAL_EVT_BRSF, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
+ BTA_AG_CMD_MAX_VAL},
+ {"+NREC", BTA_AG_AT_NREC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
+ {"+CNUM", BTA_AG_AT_CNUM_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BTRH", BTA_AG_AT_BTRH_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_INT,
+ 0, 2},
+ {"+CLCC", BTA_AG_AT_CLCC_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR,
+ 0, 0},
+ {"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+ {"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
+ {"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
+ BTA_AG_CMD_MAX_VAL},
+ {"+BIND", BTA_AG_AT_BIND_EVT,
+ BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0},
+ {"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ /* End-of-table marker used to stop lookup iteration */
+ {"", 0, 0, 0, 0, 0}};
+
+/* AT result code table element */
+typedef struct {
+ const char* result_string; /* AT result string */
+ size_t result_id; /* Local or BTA result id */
+ uint8_t arg_type; /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code argument types */
+enum {
+ BTA_AG_RES_FMT_NONE, /* no argument */
+ BTA_AG_RES_FMT_INT, /* integer argument */
+ BTA_AG_RES_FMT_STR /* string argument */
+};
+
+/* Local AT command result codes not defined in bta_ag_api.h */
+enum {
+ BTA_AG_LOCAL_RES_FIRST = 0x0100,
+ BTA_AG_LOCAL_RES_OK,
+ BTA_AG_LOCAL_RES_ERROR,
+ BTA_AG_LOCAL_RES_RING,
+ BTA_AG_LOCAL_RES_CLIP,
+ BTA_AG_LOCAL_RES_BRSF,
+ BTA_AG_LOCAL_RES_CMEE,
+ BTA_AG_LOCAL_RES_BCS
+};
+
+/* AT result code constant table */
+const tBTA_AG_RESULT bta_ag_result_tbl[] = {
+ {"OK", BTA_AG_LOCAL_RES_OK, BTA_AG_RES_FMT_NONE},
+ {"ERROR", BTA_AG_LOCAL_RES_ERROR, BTA_AG_RES_FMT_NONE},
+ {"RING", BTA_AG_LOCAL_RES_RING, BTA_AG_RES_FMT_NONE},
+ {"+VGS: ", BTA_AG_SPK_RES, BTA_AG_RES_FMT_INT},
+ {"+VGM: ", BTA_AG_MIC_RES, BTA_AG_RES_FMT_INT},
+ {"+CCWA: ", BTA_AG_CALL_WAIT_RES, BTA_AG_RES_FMT_STR},
+ {"+CHLD: ", BTA_AG_IN_CALL_HELD_RES, BTA_AG_RES_FMT_STR},
+ {"+CIND: ", BTA_AG_CIND_RES, BTA_AG_RES_FMT_STR},
+ {"+CLIP: ", BTA_AG_LOCAL_RES_CLIP, BTA_AG_RES_FMT_STR},
+ {"+CIEV: ", BTA_AG_IND_RES, BTA_AG_RES_FMT_STR},
+ {"+BINP: ", BTA_AG_BINP_RES, BTA_AG_RES_FMT_STR},
+ {"+BVRA: ", BTA_AG_BVRA_RES, BTA_AG_RES_FMT_INT},
+ {"+BRSF: ", BTA_AG_LOCAL_RES_BRSF, BTA_AG_RES_FMT_INT},
+ {"+BSIR: ", BTA_AG_INBAND_RING_RES, BTA_AG_RES_FMT_INT},
+ {"+CNUM: ", BTA_AG_CNUM_RES, BTA_AG_RES_FMT_STR},
+ {"+BTRH: ", BTA_AG_BTRH_RES, BTA_AG_RES_FMT_INT},
+ {"+CLCC: ", BTA_AG_CLCC_RES, BTA_AG_RES_FMT_STR},
+ {"+COPS: ", BTA_AG_COPS_RES, BTA_AG_RES_FMT_STR},
+ {"+CME ERROR: ", BTA_AG_LOCAL_RES_CMEE, BTA_AG_RES_FMT_INT},
+ {"+BCS: ", BTA_AG_LOCAL_RES_BCS, BTA_AG_RES_FMT_INT},
+ {"+BIND: ", BTA_AG_BIND_RES, BTA_AG_RES_FMT_STR},
+ {"", BTA_AG_UNAT_RES, BTA_AG_RES_FMT_STR}};
+
+static const tBTA_AG_RESULT* bta_ag_result_by_code(size_t code) {
+ for (size_t i = 0;
+ i != sizeof(bta_ag_result_tbl) / sizeof(bta_ag_result_tbl[0]); ++i) {
+ if (code == bta_ag_result_tbl[i].result_id) return &bta_ag_result_tbl[i];
+ }
+ return 0;
+}
+
+const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX] = {bta_ag_hsp_cmd,
+ bta_ag_hfp_cmd};
+
+typedef struct {
+ size_t result_code;
+ size_t indicator;
+} tBTA_AG_INDICATOR_MAP;
+
+/* callsetup indicator value lookup table */
+const tBTA_AG_INDICATOR_MAP callsetup_indicator_map[] = {
+ {BTA_AG_IN_CALL_RES, BTA_AG_CALLSETUP_INCOMING},
+ {BTA_AG_CALL_WAIT_RES, BTA_AG_CALLSETUP_INCOMING},
+ {BTA_AG_OUT_CALL_ORIG_RES, BTA_AG_CALLSETUP_OUTGOING},
+ {BTA_AG_OUT_CALL_ALERT_RES, BTA_AG_CALLSETUP_ALERTING}};
+
+static size_t bta_ag_indicator_by_result_code(size_t code) {
+ for (size_t i = 0;
+ i !=
+ sizeof(callsetup_indicator_map) / sizeof(callsetup_indicator_map[0]);
+ ++i) {
+ if (code == callsetup_indicator_map[i].result_code)
+ return callsetup_indicator_map[i].indicator;
+ }
+ return BTA_AG_CALLSETUP_NONE;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_result
+ *
+ * Description Send an AT result code.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB* p_scb, size_t code,
+ const char* p_arg, int16_t int_arg) {
+ const tBTA_AG_RESULT* result = bta_ag_result_by_code(code);
+ if (result == 0) {
+ LOG_ERROR(LOG_TAG, "%s Unable to lookup result for code %zu", __func__,
+ code);
+ return;
+ }
+
+ char buf[BTA_AG_AT_MAX_LEN + 16];
+ char* p = buf;
+ memset(buf, 0, sizeof(buf));
+
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ strlcpy(p, result->result_string, sizeof(buf) - 2);
+
+ if (p_scb->conn_service == BTA_AG_HSP) {
+ /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+ switch (code) {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ if (*(p + COLON_IDX_4_VGSVGM) == ':') {
+ *(p + COLON_IDX_4_VGSVGM) = '=';
+ }
+ break;
+ }
+ }
+
+ p += strlen(result->result_string);
+
+ /* copy argument if any */
+ if (result->arg_type == BTA_AG_RES_FMT_INT) {
+ p += utl_itoa((uint16_t)int_arg, p);
+ } else if (result->arg_type == BTA_AG_RES_FMT_STR) {
+ strcpy(p, p_arg);
+ p += strlen(p_arg);
+ }
+
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* send to RFCOMM */
+ uint16_t len = 0;
+ PORT_WriteData(p_scb->conn_handle, buf, (uint16_t)(p - buf), &len);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_ok
+ *
+ * Description Send an OK result code.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB* p_scb) {
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_error
+ *
+ * Description Send an ERROR result code.
+ * errcode - used to send verbose errocode
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB* p_scb, int16_t errcode) {
+ /* If HFP and extended audio gateway error codes are enabled */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled)
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, NULL, errcode);
+ else
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_ind
+ *
+ * Description Send an indicator CIEV result code.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB* p_scb, uint16_t id, uint16_t value,
+ bool on_demand) {
+ char str[12];
+ char* p = str;
+
+ /* If the indicator is masked out, just return */
+ /* Mandatory indicators can not be masked out. */
+ if ((p_scb->bia_masked_out & ((uint32_t)1 << id)) &&
+ ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) &&
+ (id != BTA_AG_IND_CALLHELD)))
+ return;
+
+ /* Ensure we do not send duplicate indicators if not requested by app */
+ /* If it was requested by app, transmit CIEV even if it is duplicate. */
+ if (id == BTA_AG_IND_CALL) {
+ if ((value == p_scb->call_ind) && (on_demand == false)) return;
+
+ p_scb->call_ind = (uint8_t)value;
+ }
+
+ if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == false)) {
+ if (value == p_scb->callsetup_ind) return;
+
+ p_scb->callsetup_ind = (uint8_t)value;
+ }
+
+ if ((id == BTA_AG_IND_SERVICE) && (on_demand == false)) {
+ if (value == p_scb->service_ind) return;
+
+ p_scb->service_ind = (uint8_t)value;
+ }
+ if ((id == BTA_AG_IND_SIGNAL) && (on_demand == false)) {
+ if (value == p_scb->signal_ind) return;
+
+ p_scb->signal_ind = (uint8_t)value;
+ }
+ if ((id == BTA_AG_IND_ROAM) && (on_demand == false)) {
+ if (value == p_scb->roam_ind) return;
+
+ p_scb->roam_ind = (uint8_t)value;
+ }
+ if ((id == BTA_AG_IND_BATTCHG) && (on_demand == false)) {
+ if (value == p_scb->battchg_ind) return;
+
+ p_scb->battchg_ind = (uint8_t)value;
+ }
+
+ if ((id == BTA_AG_IND_CALLHELD) && (on_demand == false)) {
+ /* call swap could result in sending callheld=1 multiple times */
+ if ((value != 1) && (value == p_scb->callheld_ind)) return;
+
+ p_scb->callheld_ind = (uint8_t)value;
+ }
+
+ if (p_scb->cmer_enabled) {
+ p += utl_itoa(id, p);
+ *p++ = ',';
+ utl_itoa(value, p);
+ bta_ag_send_result(p_scb, BTA_AG_IND_RES, str, 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_parse_cmer
+ *
+ * Description Parse AT+CMER parameter string.
+ *
+ *
+ * Returns true if parsed ok, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_cmer(char* p_s, bool* p_enabled) {
+ int16_t n[4] = {-1, -1, -1, -1};
+ int i;
+ char* p;
+
+ for (i = 0; i < 4; i++) {
+ /* skip to comma delimiter */
+ for (p = p_s; *p != ',' && *p != 0; p++)
+ ;
+
+ /* get integer value */
+ *p = 0;
+ n[i] = utl_str2int(p_s);
+ p_s = p + 1;
+ if (p_s == 0) {
+ break;
+ }
+ }
+
+ /* process values */
+ if (n[0] < 0 || n[3] < 0) {
+ return false;
+ }
+
+ if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0))) {
+ *p_enabled = (bool)n[3];
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_parse_chld
+ *
+ * Description Parse AT+CHLD parameter string.
+ *
+ *
+ * Returns Returns idx (1-7), 0 if ECC not enabled or
+ BTA_AG_INVALID_CHLD
+ if idx doesn't exist/1st character of argument is not a
+ digit
+ *
+ ******************************************************************************/
+static uint8_t bta_ag_parse_chld(UNUSED_ATTR tBTA_AG_SCB* p_scb, char* p_s) {
+ uint8_t retval = 0;
+ int16_t idx = -1;
+
+ if (!isdigit(p_s[0])) {
+ return BTA_AG_INVALID_CHLD;
+ }
+
+ if (p_s[1] != 0) {
+ /* p_idxstr++; point to beginning of call number */
+ idx = utl_str2int(&p_s[1]);
+ if (idx != -1 && idx < 255) {
+ retval = (uint8_t)idx;
+ } else {
+ retval = BTA_AG_INVALID_CHLD;
+ }
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_parse_bac
+ *
+ * Description Parse AT+BAC parameter string.
+ *
+ * Returns Returns bitmap of supported codecs.
+ *
+ ******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB* p_scb, char* p_s) {
+ tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
+ uint16_t uuid_codec;
+ bool cont = false; /* Continue processing */
+ char* p;
+
+ while (p_s) {
+ /* skip to comma delimiter */
+ for (p = p_s; *p != ',' && *p != 0; p++)
+ ;
+
+ /* get integre value */
+ if (*p != 0) {
+ *p = 0;
+ cont = true;
+ } else
+ cont = false;
+
+ uuid_codec = utl_str2int(p_s);
+ switch (uuid_codec) {
+ case UUID_CODEC_CVSD:
+ retval |= BTA_AG_CODEC_CVSD;
+ break;
+ case UUID_CODEC_MSBC:
+ retval |= BTA_AG_CODEC_MSBC;
+ break;
+ default:
+ APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec);
+ break;
+ }
+
+ if (cont)
+ p_s = p + 1;
+ else
+ break;
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_process_unat_res
+ *
+ * Description Process the unat response data and remove extra carriage
+ * return and line feed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bta_ag_process_unat_res(char* unat_result) {
+ uint8_t str_leng;
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t pairs_of_nl_cr;
+ char trim_data[BTA_AG_AT_MAX_LEN];
+
+ str_leng = strlen(unat_result);
+
+ /* If no extra CR and LF, just return */
+ if (str_leng < 4) return;
+
+ /* Remove the carriage return and left feed */
+ while (unat_result[0] == '\r' && unat_result[1] == '\n' &&
+ unat_result[str_leng - 2] == '\r' &&
+ unat_result[str_leng - 1] == '\n') {
+ pairs_of_nl_cr = 1;
+ for (i = 0; i < (str_leng - 4 * pairs_of_nl_cr); i++) {
+ trim_data[j++] = unat_result[i + pairs_of_nl_cr * 2];
+ }
+ /* Add EOF */
+ trim_data[j] = '\0';
+ str_leng = str_leng - 4;
+ strlcpy(unat_result, trim_data, str_leng + 1);
+ i = 0;
+ j = 0;
+
+ if (str_leng < 4) return;
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_inband_enabled
+ *
+ * Description Determine whether in-band ring can be used.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb) {
+ /* if feature is enabled and no other scbs connected */
+ if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_call_inds
+ *
+ * Description Send call and callsetup indicators.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result) {
+ uint8_t call = p_scb->call_ind;
+
+ /* set new call and callsetup values based on BTA_AgResult */
+ size_t callsetup = bta_ag_indicator_by_result_code(result);
+
+ if (result == BTA_AG_END_CALL_RES) {
+ call = BTA_AG_CALL_INACTIVE;
+ } else if (result == BTA_AG_IN_CALL_CONN_RES ||
+ result == BTA_AG_OUT_CALL_CONN_RES ||
+ result == BTA_AG_IN_CALL_HELD_RES) {
+ call = BTA_AG_CALL_ACTIVE;
+ } else {
+ call = p_scb->call_ind;
+ }
+
+ /* Send indicator function tracks if the values have actually changed */
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, false);
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, false);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_at_hsp_cback
+ *
+ * Description AT command processing callback for HSP.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id,
+ uint8_t arg_type, char* p_arg, int16_t int_arg) {
+ APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type,
+ int_arg, p_arg);
+
+ bta_ag_send_ok(p_scb);
+
+ tBTA_AG_VAL val;
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = (uint16_t)int_arg;
+ strlcpy(val.str, p_arg, sizeof(val.str));
+
+ /* call callback with event */
+ (*bta_ag_cb.p_cback)(command_id, (tBTA_AG*)&val);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_find_empty_hf_ind)
+ *
+ * Description This function returns the index of an empty HF indicator
+ * structure.
+ *
+ * Returns int : index of the empty HF indicator structure or
+ * -1 if no empty indicator
+ * is available.
+ *
+ ******************************************************************************/
+static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB* p_scb) {
+ for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++) {
+ if (p_scb->peer_hf_indicators[index].ind_id == 0) return index;
+ }
+
+ return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_find_hf_ind_by_id
+ *
+ * Description This function returns the index of the HF indicator
+ * structure by the indicator id
+ *
+ * Returns int : index of the HF indicator structure
+ * -1 if the indicator
+ * was not found.
+ *
+ ******************************************************************************/
+static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND* p_hf_ind, int size,
+ uint32_t ind_id) {
+ for (int index = 0; index < size; index++) {
+ if (p_hf_ind[index].ind_id == ind_id) return index;
+ }
+
+ return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_parse_bind_set
+ *
+ * Description Parse AT+BIND set command and save the indicators
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_bind_set(tBTA_AG_SCB* p_scb, tBTA_AG_VAL val) {
+ char* p_token = strtok(val.str, ",");
+ if (p_token == NULL) return false;
+
+ while (p_token != NULL) {
+ uint16_t rcv_ind_id = atoi(p_token);
+ int index = bta_ag_find_empty_hf_ind(p_scb);
+ if (index == -1) {
+ APPL_TRACE_WARNING("%s Can't save more indicators", __func__);
+ return false;
+ }
+
+ p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id;
+ APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id);
+
+ p_token = strtok(NULL, ",");
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_bind_response
+ *
+ * Description Send response for the AT+BIND command (HFP 1.7) received
+ * from the headset based on the argument types.
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+static void bta_ag_bind_response(tBTA_AG_SCB* p_scb, uint8_t arg_type) {
+ char buffer[BTA_AG_AT_MAX_LEN];
+ memset(buffer, 0, BTA_AG_AT_MAX_LEN);
+
+ if (arg_type == BTA_AG_AT_TEST) {
+ int index = 0;
+ buffer[index++] = '(';
+
+ for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) {
+ if (bta_ag_local_hf_ind_cfg[i + 1].is_supported) {
+ /* Add ',' from second indicator */
+ if (index > 1) buffer[index++] = ',';
+ snprintf(&buffer[index++], 2, "%d",
+ bta_ag_local_hf_ind_cfg[i + 1].ind_id);
+ }
+ }
+
+ buffer[index++] = ')';
+
+ bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
+ bta_ag_send_ok(p_scb);
+ } else if (arg_type == BTA_AG_AT_READ) {
+ char* p = buffer;
+
+ /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */
+ for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) {
+ if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND) {
+ APPL_TRACE_WARNING("%s No space for more HF indicators", __func__);
+ break;
+ }
+
+ p_scb->local_hf_indicators[i].ind_id =
+ bta_ag_local_hf_ind_cfg[i + 1].ind_id;
+ p_scb->local_hf_indicators[i].is_supported =
+ bta_ag_local_hf_ind_cfg[i + 1].is_supported;
+ p_scb->local_hf_indicators[i].is_enable =
+ bta_ag_local_hf_ind_cfg[i + 1].is_enable;
+
+ int peer_index = bta_ag_find_hf_ind_by_id(
+ p_scb->peer_hf_indicators, BTA_AG_MAX_NUM_PEER_HF_IND,
+ p_scb->local_hf_indicators[i].ind_id);
+
+ /* Check whether local and peer sides support this indicator */
+ if (p_scb->local_hf_indicators[i].is_supported == true &&
+ peer_index != -1) {
+ /* In the format of ind, state */
+ p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].ind_id, p);
+ *p++ = ',';
+ p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].is_enable, p);
+
+ bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0);
+
+ memset(buffer, 0, sizeof(buffer));
+ p = buffer;
+ } else {
+ /* If indicator is not supported, also set it to disable */
+ p_scb->local_hf_indicators[i].is_enable = false;
+ }
+ }
+
+ bta_ag_send_ok(p_scb);
+
+ /* If the service level connection wan't already open, now it's open */
+ if (!p_scb->svc_conn) bta_ag_svc_conn_open(p_scb, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_parse_biev_response
+ *
+ * Description Send response for AT+BIEV command (HFP 1.7) received from
+ * the headset based on the argument types.
+ *
+ * Returns true if the response was parsed successfully
+ *
+ ******************************************************************************/
+static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) {
+ char* p_token = strtok(val->str, ",");
+ uint16_t rcv_ind_id = atoi(p_token);
+
+ p_token = strtok(NULL, ",");
+ uint16_t rcv_ind_val = atoi(p_token);
+
+ APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id,
+ rcv_ind_val);
+
+ /* Check whether indicator ID is valid or not */
+ if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND) {
+ APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__,
+ rcv_ind_id);
+ return false;
+ }
+
+ /* Check this indicator is support or not and enabled or not */
+ int local_index = bta_ag_find_hf_ind_by_id(
+ p_scb->local_hf_indicators, BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id);
+ if (local_index == -1 ||
+ p_scb->local_hf_indicators[local_index].is_supported != true ||
+ p_scb->local_hf_indicators[local_index].is_enable != true) {
+ APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__,
+ rcv_ind_id);
+ return false;
+ }
+
+ /* For each indicator ID, check whether the indicator value is in range */
+ if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val ||
+ rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val) {
+ APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val);
+ return false;
+ }
+
+ val->lidx = rcv_ind_id;
+ val->num = rcv_ind_val;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_at_hfp_cback
+ *
+ * Description AT command processing callback for HFP.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type,
+ char* p_arg, int16_t int_arg) {
+ tBTA_AG_VAL val;
+ tBTA_AG_SCB* ag_scb;
+ uint32_t i, ind_id;
+ uint32_t bia_masked_out;
+ if (p_arg == NULL) {
+ APPL_TRACE_ERROR("%s: p_arg is null, send error and return", __func__);
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: AT command %d, arg_type %d, int_arg %d, arg %s",
+ __func__, cmd, arg_type, int_arg, p_arg);
+
+ memset(&val, 0, sizeof(tBTA_AG_VAL));
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.hdr.status = BTA_AG_SUCCESS;
+ val.num = int_arg;
+ bdcpy(val.bd_addr, p_scb->peer_addr);
+ strlcpy(val.str, p_arg, sizeof(val.str));
+
+ /**
+ * Unless this this is a local event, by default we'll forward
+ * the event code to the application.
+ * If |event| is 0 at the end of this function, the application
+ * callback is NOT invoked.
+ */
+ tBTA_AG_EVT event = 0;
+ if (cmd < BTA_AG_LOCAL_EVT_FIRST) event = cmd;
+
+ switch (cmd) {
+ case BTA_AG_AT_A_EVT:
+ case BTA_AG_SPK_EVT:
+ case BTA_AG_MIC_EVT:
+ case BTA_AG_AT_CHUP_EVT:
+ case BTA_AG_AT_CBC_EVT:
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ /** M: Add for Speaker no sound blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if(interop_mtk_match_addr_name(INTEROP_MTK_HFP_GAIN_UPDATE_CANCEL,
+ (const bt_bdaddr_t *)p_scb->peer_addr)){
+ if ((cmd == BTA_AG_SPK_EVT ||cmd == BTA_AG_MIC_EVT) && val.num == 0) {
+ event = 0;
+ APPL_TRACE_DEBUG("%s BTA_AG_HF_CMD_VGS arg_type: %d", __func__, val.num);
+ }
+ }
+#endif
+ /** @} */
+ break;
+
+ case BTA_AG_AT_BLDN_EVT:
+ /* Do not send OK, App will send error or OK depending on
+ ** last dial number enabled or not */
+ break;
+
+ case BTA_AG_AT_D_EVT:
+ /* Do not send OK for Dial cmds
+ ** Let application decide whether to send OK or ERROR*/
+
+ /* if mem dial cmd, make sure string contains only digits */
+ if (p_arg[0] == '>') {
+ if (!utl_isintstr(p_arg + 1)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ } else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */
+ {
+ /* We do not check string. Code will be added later if needed. */
+ if (!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) &&
+ (p_scb->features & BTA_AG_FEAT_VOIP))) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ }
+ /* If dial cmd, make sure string contains only dial digits
+ ** Dial digits are 0-9, A-C, *, #, + */
+ else {
+ if (!utl_isdialstr(p_arg)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ }
+ break;
+
+ case BTA_AG_LOCAL_EVT_CCWA:
+ /* store setting */
+ p_scb->ccwa_enabled = (bool)int_arg;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_AT_CHLD_EVT:
+ if (arg_type == BTA_AG_AT_TEST) {
+ /* don't call callback */
+ event = 0;
+
+ /* send CHLD string */
+ /* Form string based on supported 1.5 feature */
+ if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+ (p_scb->features & BTA_AG_FEAT_ECC) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))
+ bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
+ p_bta_ag_cfg->chld_val_ecc, 0);
+ else
+ bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES,
+ p_bta_ag_cfg->chld_val, 0);
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+
+ /* if service level conn. not already open, now it's open */
+ bta_ag_svc_conn_open(p_scb, NULL);
+ } else {
+ val.idx = bta_ag_parse_chld(p_scb, val.str);
+
+ if (val.idx == BTA_AG_INVALID_CHLD) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+ }
+ if (val.idx &&
+ !((p_scb->features & BTA_AG_FEAT_ECC) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))) {
+ /* we do not support ECC, but HF is sending us a CHLD with call
+ * index*/
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+ } else {
+ /* If it is swap between calls, set call held indicator to 3(out of
+ *valid 0-2)
+ ** Application will set it back to 1
+ ** callheld indicator will be sent across to the peer. */
+ if (val.str[0] == '2') {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+ i++, ag_scb++) {
+ if (ag_scb->in_use) {
+ if ((ag_scb->call_ind == BTA_AG_CALL_ACTIVE) &&
+ (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+ ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+ }
+ }
+ }
+ }
+
+ /* Do not send OK. Let app decide after parsing the val str */
+ /* bta_ag_send_ok(p_scb); */
+ }
+ break;
+
+ case BTA_AG_AT_BIND_EVT:
+ APPL_TRACE_DEBUG("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__,
+ arg_type);
+ if (arg_type == BTA_AG_AT_SET) {
+ if (bta_ag_parse_bind_set(p_scb, val)) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0; /* don't call callback */
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+ }
+ } else {
+ bta_ag_bind_response(p_scb, arg_type);
+
+ /* Need not pass this command beyond BTIF.*/
+ /* Stack handles it internally */
+ event = 0; /* don't call callback */
+ }
+ break;
+
+ case BTA_AG_AT_BIEV_EVT:
+ if (bta_ag_parse_biev_response(p_scb, &val)) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+ /* don't call callback receiving invalid indicator */
+ event = 0;
+ }
+ break;
+
+ case BTA_AG_AT_CIND_EVT:
+ if (arg_type == BTA_AG_AT_TEST) {
+ /* don't call callback */
+ event = 0;
+
+ /* send CIND string, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_CIND_RES, p_bta_ag_cfg->cind_info, 0);
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_LOCAL_EVT_CLIP:
+ /* store setting, send OK */
+ p_scb->clip_enabled = (bool)int_arg;
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_LOCAL_EVT_CMER:
+ /* if parsed ok store setting, send OK */
+ if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled)) {
+ bta_ag_send_ok(p_scb);
+
+ /* if service level conn. not already open and our features and
+ ** peer features do not have 3-way, service level conn. now open
+ */
+ if (!p_scb->svc_conn &&
+ !((p_scb->features & BTA_AG_FEAT_3WAY) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) {
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_AT_VTS_EVT:
+ /* check argument */
+ if (strlen(p_arg) == 1) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_AT_BINP_EVT:
+ /* if feature not set don't call callback, send ERROR */
+ if (!(p_scb->features & BTA_AG_FEAT_VTAG)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_AT_BVRA_EVT:
+ /* if feature not supported don't call callback, send ERROR. App will send
+ * OK */
+ if (!(p_scb->features & BTA_AG_FEAT_VREC)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_LOCAL_EVT_BRSF: {
+ /* store peer features */
+ p_scb->peer_features = (uint16_t)int_arg;
+
+ tBTA_AG_FEAT features = p_scb->features;
+ if (p_scb->peer_version < HFP_VERSION_1_7) {
+ features &= HFP_1_6_FEAT_MASK;
+ }
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ else {
+ APPL_TRACE_DEBUG("BTA_AG_LOCAL_EVT_BRSF check peer addr");
+ if (interop_mtk_match_addr_name(
+ INTEROP_MTK_HFP_17_TO_16,
+ (const bt_bdaddr_t*)&p_scb->peer_addr)) {
+ APPL_TRACE_DEBUG("Set HFP1.6 feature mark");
+ features &= HFP_1_6_FEAT_MASK;
+ }
+ }
+#endif
+ /** @} */
+
+ APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__,
+ p_scb->peer_features, features);
+
+ /* send BRSF, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t)features);
+ bta_ag_send_ok(p_scb);
+ break;
+ }
+
+ case BTA_AG_AT_NREC_EVT:
+ /* if feature send OK, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_ECNR) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_AT_BTRH_EVT:
+ /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_BTRH) {
+ /* If set command; send response and notify app */
+ if (arg_type == BTA_AG_AT_SET) {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB;
+ i++, ag_scb++) {
+ if (ag_scb->in_use) {
+ bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, NULL, int_arg);
+ }
+ }
+ bta_ag_send_ok(p_scb);
+ } else /* Read Command */
+ {
+ val.num = BTA_AG_BTRH_READ;
+ }
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_AT_COPS_EVT:
+ if (arg_type == BTA_AG_AT_SET) {
+ /* don't call callback */
+ event = 0;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_LOCAL_EVT_CMEE:
+ if (p_scb->features & BTA_AG_FEAT_EXTERR) {
+ /* store setting */
+ p_scb->cmee_enabled = (bool)int_arg;
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ /* don't call callback */
+ event = 0;
+ break;
+
+ case BTA_AG_LOCAL_EVT_BIA:
+ /* don't call callback */
+ event = 0;
+
+ bia_masked_out = p_scb->bia_masked_out;
+
+ /* Parse the indicator mask */
+ for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20);
+ i++, ind_id++) {
+ if (val.str[i] == ',') continue;
+
+ if (val.str[i] == '0')
+ bia_masked_out |= ((uint32_t)1 << ind_id);
+ else if (val.str[i] == '1')
+ bia_masked_out &= ~((uint32_t)1 << ind_id);
+ else
+ break;
+
+ i++;
+ if ((val.str[i] == 0) || (val.str[i] != ',')) break;
+ }
+ if (val.str[i] == 0) {
+ p_scb->bia_masked_out = bia_masked_out;
+ bta_ag_send_ok(p_scb);
+ } else
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX);
+ break;
+
+ case BTA_AG_AT_CNUM_EVT:
+ break;
+
+ case BTA_AG_AT_CLCC_EVT:
+ if (!(p_scb->features & BTA_AG_FEAT_ECS)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_AT_BAC_EVT:
+ bta_ag_send_ok(p_scb);
+
+ /* store available codecs from the peer */
+ if ((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) &&
+ (p_scb->features & BTA_AG_FEAT_CODEC)) {
+ p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+ p_scb->codec_updated = true;
+
+ if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC) {
+ p_scb->sco_codec = UUID_CODEC_MSBC;
+ APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC");
+ } else {
+ p_scb->sco_codec = UUID_CODEC_CVSD;
+ APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD");
+ }
+ /* The above logic sets the stack preferred codec based on local and
+ peer codec
+ capabilities. This can be overridden by the application depending on its
+ preference
+ using the bta_ag_setcodec API. We send the peer_codecs to the
+ application. */
+ val.num = p_scb->peer_codecs;
+ /* Received BAC while in codec negotiation. */
+ if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb)) {
+ bta_ag_codec_negotiate(p_scb);
+ }
+ } else {
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+ APPL_TRACE_ERROR(
+ "Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+ }
+ break;
+
+ case BTA_AG_AT_BCS_EVT: {
+ tBTA_AG_PEER_CODEC codec_type, codec_sent;
+ bta_ag_send_ok(p_scb);
+ alarm_cancel(p_scb->codec_negotiation_timer);
+
+ switch (int_arg) {
+ case UUID_CODEC_CVSD:
+ codec_type = BTA_AG_CODEC_CVSD;
+ break;
+ case UUID_CODEC_MSBC:
+ codec_type = BTA_AG_CODEC_MSBC;
+ break;
+ default:
+ APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg);
+ codec_type = 0xFFFF;
+ break;
+ }
+
+ if (p_scb->codec_fallback)
+ codec_sent = BTA_AG_CODEC_CVSD;
+ else
+ codec_sent = p_scb->sco_codec;
+
+ if (codec_type == codec_sent)
+ bta_ag_sco_codec_nego(p_scb, true);
+ else
+ bta_ag_sco_codec_nego(p_scb, false);
+
+ /* send final codec info to callback */
+ val.num = codec_sent;
+ break;
+ }
+ case BTA_AG_LOCAL_EVT_BCC:
+ bta_ag_send_ok(p_scb);
+ bta_ag_sco_open(p_scb, NULL);
+ break;
+
+ default:
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+ }
+
+ /* call callback */
+ if (event != 0) {
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&val);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_at_err_cback
+ *
+ * Description AT command parser error callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg) {
+ tBTA_AG_VAL val;
+
+ if (unknown && (!strlen(p_arg))) {
+ APPL_TRACE_DEBUG("Empty AT cmd string received");
+ bta_ag_send_ok(p_scb);
+ return;
+ }
+
+ /* if unknown AT command and configured to pass these to app */
+ if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) {
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.hdr.status = BTA_AG_SUCCESS;
+ val.num = 0;
+ strlcpy(val.str, p_arg, sizeof(val.str));
+ (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG*)&val);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_hsp_result
+ *
+ * Description Handle API result for HSP connections.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
+ APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
+
+ switch (p_result->result) {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+ } else {
+ /* else open sco, send ring after sco opened */
+ /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+ if (p_scb->peer_version >= HSP_VERSION_1_2) {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ }
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ break;
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ /* if incoming call connected stop ring timer */
+ if (p_result->result == BTA_AG_IN_CALL_CONN_RES) {
+ alarm_cancel(p_scb->ring_timer);
+ }
+
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ /* if audio connected to this scb AND sco is not opened, open sco */
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !bta_ag_sco_is_open(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ /* else if no audio at call close sco */
+ else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE &&
+ bta_ag_sco_is_open(p_scb)) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_END_CALL_RES:
+ alarm_cancel(p_scb->ring_timer);
+
+ /* close sco */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ } else {
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+ break;
+
+ case BTA_AG_UNAT_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ default:
+ /* ignore all others */
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_hfp_result
+ *
+ * Description Handle API result for HFP connections.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) {
+ APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
+
+ switch (p_result->result) {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* store caller id string.
+ * append type info at the end.
+ * make sure a valid type info is passed.
+ * otherwise add 129 as default type */
+ if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) ||
+ (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) {
+ if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP)
+ p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+ }
+
+ APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num);
+ p_scb->clip[0] = 0;
+ if (p_result->data.str[0] != 0)
+ snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", p_result->data.str,
+ p_result->data.num);
+
+ /* send callsetup indicator */
+ if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) {
+ /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO
+ * close. */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+ } else {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result);
+ } else {
+ /* else open sco, send ring after sco opened */
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ alarm_cancel(p_scb->ring_timer);
+
+ /* if sco not opened and we need to open it, send indicators first
+ ** then open sco.
+ */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !bta_ag_sco_is_open(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ } else if ((p_result->data.audio_handle == BTA_AG_HANDLE_NONE) &&
+ bta_ag_sco_is_open(p_scb)) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_IN_CALL_HELD_RES:
+ alarm_cancel(p_scb->ring_timer);
+
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ break;
+
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ break;
+
+ case BTA_AG_OUT_CALL_ALERT_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ break;
+
+ case BTA_AG_MULTI_CALL_RES:
+ /* open SCO at SLC for this three way call */
+ APPL_TRACE_DEBUG("Headset Connected in three way call");
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb))
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE)
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ break;
+
+ case BTA_AG_OUT_CALL_CONN_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* open or close sco */
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result);
+ } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_CALL_CANCEL_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_END_CALL_RES:
+ alarm_cancel(p_scb->ring_timer);
+
+ /* if sco open, close sco then send indicator values */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) &&
+ !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result);
+ } else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) {
+ /* sco closing for outgoing call because of incoming call */
+ /* Send only callsetup end indicator after sco close */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ } else {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+ bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_CIND_RES:
+ /* store local values */
+ p_scb->call_ind = p_result->data.str[0] - '0';
+ p_scb->callsetup_ind = p_result->data.str[2] - '0';
+ p_scb->service_ind = p_result->data.str[4] - '0';
+ p_scb->signal_ind = p_result->data.str[6] - '0';
+ p_scb->roam_ind = p_result->data.str[8] - '0';
+ p_scb->battchg_ind = p_result->data.str[10] - '0';
+ p_scb->callheld_ind = p_result->data.str[12] - '0';
+ APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind,
+ p_scb->callsetup_ind);
+
+ bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_BINP_RES:
+ case BTA_AG_CNUM_RES:
+ case BTA_AG_CLCC_RES:
+ case BTA_AG_COPS_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ case BTA_AG_UNAT_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_process_unat_res(p_result->data.str);
+ APPL_TRACE_DEBUG("BTA_AG_RES :%s", p_result->data.str);
+ bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ case BTA_AG_CALL_WAIT_RES:
+ if (p_scb->ccwa_enabled) {
+ bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0);
+ }
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_IND_RES:
+ bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value,
+ false);
+ break;
+
+ case BTA_AG_BVRA_RES:
+ bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_BTRH_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ /* Don't respond to read if not in response & hold state */
+ if (p_result->data.num != BTA_AG_BTRH_NO_RESP) {
+ bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num);
+ }
+
+ /* In case of a response to a read request we need to send OK */
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ case BTA_AG_BIND_RES: {
+ /* Find whether ind_id is supported by local device or not */
+ int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators,
+ BTA_AG_MAX_NUM_LOCAL_HF_IND,
+ p_result->data.ind.id);
+ if (local_index == -1) {
+ APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+ p_result->data.ind.id);
+ return;
+ }
+
+ /* Find whether ind_id is supported by peer device or not */
+ int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators,
+ BTA_AG_MAX_NUM_PEER_HF_IND,
+ p_result->data.ind.id);
+ if (peer_index == -1) {
+ APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__,
+ p_result->data.ind.id);
+ return;
+ } else {
+ /* If the current state is different from the one upper layer request
+ change current state and send out the result */
+ if (p_scb->local_hf_indicators[local_index].is_enable !=
+ p_result->data.ind.on_demand) {
+ char buffer[BTA_AG_AT_MAX_LEN] = {0};
+ char* p = buffer;
+
+ p_scb->local_hf_indicators[local_index].is_enable =
+ p_result->data.ind.on_demand;
+ p += utl_itoa(p_result->data.ind.id, p);
+ *p++ = ',';
+ p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p);
+
+ bta_ag_send_result(p_scb, p_result->result, buffer, 0);
+ } else {
+ APPL_TRACE_DEBUG(
+ "%s HF Indicator %d already %s", p_result->data.ind.id,
+ (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled");
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_result
+ *
+ * Description Handle API result.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ if (p_scb->conn_service == BTA_AG_HSP) {
+ bta_ag_hsp_result(p_scb, &p_data->api_result);
+ } else {
+ bta_ag_hfp_result(p_scb, &p_data->api_result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_bcs
+ *
+ * Description Send +BCS AT command to peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ uint16_t codec_uuid;
+
+ if (p_scb->codec_fallback) {
+ codec_uuid = UUID_CODEC_CVSD;
+ } else {
+ switch (p_scb->sco_codec) {
+ case BTA_AG_CODEC_NONE:
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+ case BTA_AG_CODEC_CVSD:
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+ case BTA_AG_CODEC_MSBC:
+ codec_uuid = UUID_CODEC_MSBC;
+ break;
+ default:
+ APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD",
+ p_scb->sco_codec);
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+ }
+ }
+
+ /* send +BCS */
+ APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, NULL, codec_uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_send_ring
+ *
+ * Description Send RING result code to peer.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ /* send RING */
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, NULL, 0);
+
+ /* if HFP and clip enabled and clip data send CLIP */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled &&
+ p_scb->clip[0] != 0) {
+ bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CLIP, p_scb->clip, 0);
+ }
+
+ bta_sys_start_timer(p_scb->ring_timer, BTA_AG_RING_TIMEOUT_MS,
+ BTA_AG_RING_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb));
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_int.h b/mtkbt/code/bt/bta/ag/bta_ag_int.h
new file mode 100755
index 0000000..c980028
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_int.h
@@ -0,0 +1,398 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_ag_api.h"
+#include "bta_ag_at.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB 2
+#endif
+
+/* Time to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMEOUT_MS
+#define BTA_AG_COLLISION_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU 256
+
+/* Max number of peer and local HF indicators */
+#define BTA_AG_MAX_NUM_PEER_HF_IND 20
+#define BTA_AG_MAX_NUM_LOCAL_HF_IND 4
+
+/* Internal profile indexes */
+#define BTA_AG_HSP 0 /* index for HSP */
+#define BTA_AG_HFP 1 /* index for HFP */
+#define BTA_AG_NUM_IDX 2 /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP 0 /* accepted connection */
+#define BTA_AG_INT 1 /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC \
+ (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | BTA_AG_FEAT_EXTERR | \
+ BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
+ BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC \
+ (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_INBAND | BTA_AG_FEAT_VTAG)
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+ BTA_AG_API_DEREGISTER_EVT,
+ BTA_AG_API_OPEN_EVT,
+ BTA_AG_API_CLOSE_EVT,
+ BTA_AG_API_AUDIO_OPEN_EVT,
+ BTA_AG_API_AUDIO_CLOSE_EVT,
+ BTA_AG_API_RESULT_EVT,
+ BTA_AG_API_SETCODEC_EVT,
+ BTA_AG_RFC_OPEN_EVT,
+ BTA_AG_RFC_CLOSE_EVT,
+ BTA_AG_RFC_SRV_CLOSE_EVT,
+ BTA_AG_RFC_DATA_EVT,
+ BTA_AG_SCO_OPEN_EVT,
+ BTA_AG_SCO_CLOSE_EVT,
+ BTA_AG_DISC_ACP_RES_EVT,
+ BTA_AG_DISC_INT_RES_EVT,
+ BTA_AG_DISC_OK_EVT,
+ BTA_AG_DISC_FAIL_EVT,
+ BTA_AG_CI_RX_WRITE_EVT,
+ BTA_AG_RING_TIMEOUT_EVT,
+ BTA_AG_SVC_TIMEOUT_EVT,
+ BTA_AG_CI_SCO_DATA_EVT,
+ BTA_AG_CI_SLC_READY_EVT,
+ BTA_AG_MAX_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_AG_API_ENABLE_EVT,
+ BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum {
+ BTA_AG_POST_SCO_NONE, /* no action */
+ BTA_AG_POST_SCO_CLOSE_RFC, /* close RFCOMM channel after SCO closes */
+ BTA_AG_POST_SCO_RING, /* send RING result code after SCO opens */
+ BTA_AG_POST_SCO_CALL_CONN, /* send call indicators after SCO opens/closes */
+ BTA_AG_POST_SCO_CALL_ORIG, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END_INCALL /* send call indicators for end call &
+ incoming call after SCO closes */
+};
+
+/* sco states */
+enum {
+ BTA_AG_SCO_SHUTDOWN_ST, /* no sco listening, all sco connections closed */
+ BTA_AG_SCO_LISTEN_ST, /* sco listening */
+ BTA_AG_SCO_CODEC_ST, /* sco codec negotiation */
+ BTA_AG_SCO_OPENING_ST, /* sco connection opening */
+ BTA_AG_SCO_OPEN_CL_ST, /* opening sco connection being closed */
+ BTA_AG_SCO_OPEN_XFER_ST, /* opening sco connection being transferred */
+ BTA_AG_SCO_OPEN_ST, /* sco open */
+ BTA_AG_SCO_CLOSING_ST, /* sco closing */
+ BTA_AG_SCO_CLOSE_OP_ST, /* closing sco being opened */
+ BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */
+ BTA_AG_SCO_SHUTTING_ST /* sco shutting down */
+};
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AG_PARSE_MODE parse_mode;
+ tBTA_AG_CBACK* p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ char p_name[2][BTA_SERVICE_NAME_LEN + 1];
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+ tBTA_AG_FEAT features;
+ uint8_t app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AG_RES result;
+ tBTA_AG_RES_DATA data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AG_PEER_CODEC codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ // char p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union {
+ BT_HDR hdr;
+ tBTA_AG_API_ENABLE api_enable;
+ tBTA_AG_API_REGISTER api_register;
+ tBTA_AG_API_OPEN api_open;
+ tBTA_AG_API_RESULT api_result;
+ tBTA_AG_API_SETCODEC api_setcodec;
+ tBTA_AG_DISC_RESULT disc_result;
+ tBTA_AG_RFC rfc;
+ tBTA_AG_CI_RX_WRITE ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct {
+ uint32_t sdp_handle;
+ uint8_t scn;
+} tBTA_AG_PROFILE;
+
+typedef enum {
+ BTA_AG_SCO_MSBC_SETTINGS_T2 = 0, /* preferred/default when codec is mSBC */
+ BTA_AG_SCO_MSBC_SETTINGS_T1,
+} tBTA_AG_SCO_MSBC_SETTINGS;
+
+/* type for each service control block */
+typedef struct {
+ char clip[BTA_AG_AT_MAX_LEN + 1]; /* number string used for CLIP */
+ uint16_t serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+ tBTA_AG_AT_CB at_cb; /* AT command interpreter */
+ BD_ADDR peer_addr; /* peer bd address */
+ tSDP_DISCOVERY_DB* p_disc_db; /* pointer to discovery database */
+ tBTA_SERVICE_MASK reg_services; /* services specified in register API */
+ tBTA_SERVICE_MASK open_services; /* services specified in open API */
+ uint16_t conn_handle; /* RFCOMM handle of connected service */
+ tBTA_SEC serv_sec_mask; /* server security mask */
+ tBTA_SEC cli_sec_mask; /* client security mask */
+ tBTA_AG_FEAT features; /* features registered by application */
+ tBTA_AG_PEER_FEAT peer_features; /* peer device features */
+ uint16_t peer_version; /* profile version of peer device */
+ uint16_t hsp_version; /* HSP profile version before SDP */
+ uint16_t sco_idx; /* SCO handle */
+ bool in_use; /* scb in use */
+ bool dealloc; /* true if service shutting down */
+ bool clip_enabled; /* set to true if HF enables CLIP reporting */
+ bool ccwa_enabled; /* set to true if HF enables CCWA reporting */
+ bool cmer_enabled; /* set to true if HF enables CMER reporting */
+ bool cmee_enabled; /* set to true if HF enables CME ERROR reporting */
+ bool inband_enabled; /* set to true if inband ring enabled */
+ bool svc_conn; /* set to true when service level connection up */
+ uint8_t state; /* state machine state */
+ uint8_t conn_service; /* connected service */
+ uint8_t peer_scn; /* peer scn */
+ uint8_t app_id; /* application id */
+ uint8_t role; /* initiator/acceptor role */
+ uint8_t post_sco; /* action to perform after sco event */
+ uint8_t call_ind; /* CIEV call indicator value */
+ uint8_t callsetup_ind; /* CIEV callsetup indicator value */
+ uint8_t service_ind; /* CIEV service indicator value */
+ uint8_t signal_ind; /* CIEV signal indicator value */
+ uint8_t roam_ind; /* CIEV roam indicator value */
+ uint8_t battchg_ind; /* CIEV battery charge indicator value */
+ uint8_t callheld_ind; /* CIEV call held indicator value */
+ uint32_t bia_masked_out; /* indicators HF does not want us to send */
+ alarm_t* collision_timer;
+ alarm_t* ring_timer;
+ alarm_t* codec_negotiation_timer;
+ tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */
+ tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */
+ tBTA_AG_PEER_CODEC
+ inuse_codec; /* codec being used for the current SCO connection */
+ bool codec_updated; /* set to true whenever the app updates codec type */
+ bool codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+ tBTA_AG_SCO_MSBC_SETTINGS
+ codec_msbc_settings; /* settings to be used for the impending eSCO */
+
+ tBTA_AG_HF_IND
+ peer_hf_indicators[BTA_AG_MAX_NUM_PEER_HF_IND]; /* Peer supported
+ HF indicators */
+ tBTA_AG_HF_IND
+ local_hf_indicators[BTA_AG_MAX_NUM_LOCAL_HF_IND]; /* Local supported
+ HF indicators */
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct {
+ tBTM_ESCO_CONN_REQ_EVT_DATA conn_data; /* SCO data for pending conn request */
+ tBTA_AG_SCB* p_curr_scb; /* SCB associated with SCO connection */
+ tBTA_AG_SCB* p_xfer_scb; /* SCB associated with SCO transfer */
+ uint16_t cur_idx; /* SCO handle */
+ uint8_t state; /* SCO state variable */
+ bool is_local; /* SCO connection initiated locally or remotely */
+} tBTA_AG_SCO_CB;
+
+/* type for AG control block */
+typedef struct {
+ tBTA_AG_SCB scb[BTA_AG_NUM_SCB]; /* service control blocks */
+ tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */
+ tBTA_AG_SCO_CB sco; /* SCO data */
+ tBTA_AG_CBACK* p_cback; /* application callback */
+ tBTA_AG_PARSE_MODE parse_mode; /* parse/pass-through mode */
+} tBTA_AG_CB;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* constant lookup tables */
+extern const uint16_t bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const uint8_t bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+extern tBTA_AG_CB bta_ag_cb;
+
+/* config struct */
+extern tBTA_AG_CFG* p_bta_ag_cfg;
+extern const tBTA_AG_HF_IND bta_ag_local_hf_ind_cfg[];
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb);
+extern uint16_t bta_ag_scb_to_idx(tBTA_AG_SCB* p_scb);
+extern tBTA_AG_SCB* bta_ag_scb_by_idx(uint16_t idx);
+extern uint8_t bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern uint16_t bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb);
+extern bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb);
+extern tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
+ tBTA_AG_DATA* p_data);
+extern bool bta_ag_hdl_event(BT_HDR* p_msg);
+extern void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open(tBTA_AG_SCB* p_scb);
+
+/* SDP functions */
+extern bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name,
+ uint8_t scn, tBTA_AG_FEAT features,
+ uint32_t sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB* p_scb,
+ tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB* p_scb,
+ tBTA_SERVICE_MASK services);
+extern bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* SCO functions */
+extern bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb);
+extern bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb,
+ tBTM_ESCO_CONN_REQ_EVT_DATA* p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
+ uint8_t arg_type, char* p_arg, int16_t int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd,
+ uint8_t arg_type, char* p_arg, int16_t int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg);
+extern bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result);
+extern void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb);
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_send_ring(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+#endif /* BTA_AG_INT_H */
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_main.cc b/mtkbt/code/bt/bta/ag/bta_ag_main.cc
new file mode 100755
index 0000000..8a28983
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_main.cc
@@ -0,0 +1,951 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG FALSE
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+#if (BTA_AG_DEBUG == TRUE)
+static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result);
+static char* bta_ag_state_str(uint8_t state);
+#endif
+
+/* state machine states */
+enum { BTA_AG_INIT_ST, BTA_AG_OPENING_ST, BTA_AG_OPEN_ST, BTA_AG_CLOSING_ST };
+
+/* state machine action enumeration list */
+enum {
+ BTA_AG_REGISTER,
+ BTA_AG_DEREGISTER,
+ BTA_AG_START_OPEN,
+ BTA_AG_RFC_DO_OPEN,
+ BTA_AG_RFC_DO_CLOSE,
+ BTA_AG_START_DEREG,
+ BTA_AG_START_CLOSE,
+ BTA_AG_RFC_OPEN,
+ BTA_AG_OPEN_FAIL,
+ BTA_AG_RFC_ACP_OPEN,
+ BTA_AG_RFC_CLOSE,
+ BTA_AG_RFC_FAIL,
+ BTA_AG_RFC_DATA,
+ BTA_AG_DISC_INT_RES,
+ BTA_AG_DISC_FAIL,
+ BTA_AG_DISC_ACP_RES,
+ BTA_AG_FREE_DB,
+ BTA_AG_SCO_CONN_OPEN,
+ BTA_AG_SCO_CONN_CLOSE,
+ BTA_AG_SCO_LISTEN,
+ BTA_AG_SCO_OPEN,
+ BTA_AG_SCO_CLOSE,
+ BTA_AG_SCO_SHUTDOWN,
+ BTA_AG_POST_SCO_OPEN,
+ BTA_AG_POST_SCO_CLOSE,
+ BTA_AG_SVC_CONN_OPEN,
+ BTA_AG_RESULT,
+ BTA_AG_SETCODEC,
+ BTA_AG_SEND_RING,
+ BTA_AG_CI_SCO_DATA,
+ BTA_AG_CI_RX_DATA,
+ BTA_AG_RCVD_SLC_READY,
+ BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION)(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] = {
+ bta_ag_register, bta_ag_deregister, bta_ag_start_open,
+ bta_ag_rfc_do_open, bta_ag_rfc_do_close, bta_ag_start_dereg,
+ bta_ag_start_close, bta_ag_rfc_open, bta_ag_open_fail,
+ bta_ag_rfc_acp_open, bta_ag_rfc_close, bta_ag_rfc_fail,
+ bta_ag_rfc_data, bta_ag_disc_int_res, bta_ag_disc_fail,
+ bta_ag_disc_acp_res, bta_ag_free_db, bta_ag_sco_conn_open,
+ bta_ag_sco_conn_close, bta_ag_sco_listen, bta_ag_sco_open,
+ bta_ag_sco_close, bta_ag_sco_shutdown, bta_ag_post_sco_open,
+ bta_ag_post_sco_close, bta_ag_svc_conn_open, bta_ag_result,
+ bta_ag_setcodec, bta_ag_send_ring, bta_ag_ci_sco_data,
+ bta_ag_ci_rx_data, bta_ag_rcvd_slc_ready};
+
+/* state table information */
+#define BTA_AG_ACTIONS 2 /* number of actions */
+#define BTA_AG_NEXT_STATE 2 /* position of next state */
+#define BTA_AG_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+const uint8_t bta_ag_st_init[][BTA_AG_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* API_REGISTER_EVT */ {BTA_AG_REGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_DEREGISTER_EVT */ {BTA_AG_DEREGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_OPEN_EVT */ {BTA_AG_START_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}};
+
+/* state table for opening state */
+const uint8_t bta_ag_st_opening[][BTA_AG_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG,
+ BTA_AG_CLOSING_ST},
+ /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE,
+ BTA_AG_OPENING_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE,
+ BTA_AG_OPENING_ST},
+ /* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+ /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t bta_ag_st_open[][BTA_AG_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG,
+ BTA_AG_CLOSING_ST},
+ /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN,
+ BTA_AG_OPEN_ST},
+ /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
+ BTA_AG_OPEN_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+ /* CI_SLC_READY_EVT */
+ {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE, BTA_AG_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t bta_ag_st_closing[][BTA_AG_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE,
+ BTA_AG_CLOSING_ST},
+ /* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE,
+ BTA_AG_CLOSING_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+ /* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+ /* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] = {bta_ag_st_init, bta_ag_st_opening,
+ bta_ag_st_open, bta_ag_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* AG control block */
+tBTA_AG_CB bta_ag_cb;
+
+/*******************************************************************************
+ *
+ * Function bta_ag_scb_alloc
+ *
+ * Description Allocate an AG service control block.
+ *
+ *
+ * Returns pointer to the scb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+static tBTA_AG_SCB* bta_ag_scb_alloc(void) {
+ tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (!p_scb->in_use) {
+ /* initialize variables */
+ p_scb->in_use = true;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_scb->codec_updated = false;
+ p_scb->codec_fallback = false;
+ p_scb->peer_codecs = BTA_AG_CODEC_CVSD;
+ p_scb->sco_codec = BTA_AG_CODEC_CVSD;
+ /* set up timers */
+ p_scb->ring_timer = alarm_new("bta_ag.scb_ring_timer");
+ p_scb->collision_timer = alarm_new("bta_ag.scb_collision_timer");
+ p_scb->codec_negotiation_timer =
+ alarm_new("bta_ag.scb_codec_negotiation_timer");
+ /* set eSCO mSBC setting to T2 as the preferred */
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+ APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+ break;
+ }
+ }
+
+ if (i == BTA_AG_NUM_SCB) {
+ /* out of scbs */
+ p_scb = NULL;
+ APPL_TRACE_WARNING("%s: Out of scbs", __func__);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_scb_dealloc
+ *
+ * Description Deallocate a service control block.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB* p_scb) {
+ uint8_t idx;
+ bool allocated = false;
+
+ APPL_TRACE_DEBUG("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+
+ /* stop and free timers */
+ alarm_free(p_scb->ring_timer);
+ alarm_free(p_scb->codec_negotiation_timer);
+ alarm_free(p_scb->collision_timer);
+
+ /* initialize control block */
+ memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+ /* If all scbs are deallocated, callback with disable event */
+ if (!bta_sys_is_register(BTA_ID_AG)) {
+ for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+ if (bta_ag_cb.scb[idx].in_use) {
+ allocated = true;
+ break;
+ }
+ }
+
+ if (!allocated) {
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_scb_to_idx
+ *
+ * Description Given a pointer to an scb, return its index.
+ *
+ *
+ * Returns Index of scb.
+ *
+ ******************************************************************************/
+uint16_t bta_ag_scb_to_idx(tBTA_AG_SCB* p_scb) {
+ /* use array arithmetic to determine index */
+ return ((uint16_t)(p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_scb_by_idx
+ *
+ * Description Given an scb index return pointer to scb.
+ *
+ *
+ * Returns Pointer to scb or NULL if not allocated.
+ *
+ ******************************************************************************/
+tBTA_AG_SCB* bta_ag_scb_by_idx(uint16_t idx) {
+ tBTA_AG_SCB* p_scb;
+
+ /* verify index */
+ if (idx > 0 && idx <= BTA_AG_NUM_SCB) {
+ p_scb = &bta_ag_cb.scb[idx - 1];
+ if (!p_scb->in_use) {
+ p_scb = NULL;
+ APPL_TRACE_WARNING("ag scb idx %d not allocated", idx);
+ }
+ } else {
+ p_scb = NULL;
+ APPL_TRACE_DEBUG("ag scb idx %d out of range", idx);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_service_to_idx
+ *
+ * Description Given a BTA service mask convert to profile index.
+ *
+ *
+ * Returns Profile ndex of scb.
+ *
+ ******************************************************************************/
+uint8_t bta_ag_service_to_idx(tBTA_SERVICE_MASK services) {
+ if (services & BTA_HFP_SERVICE_MASK) {
+ return BTA_AG_HFP;
+ } else {
+ return BTA_AG_HSP;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_idx_by_bdaddr
+ *
+ * Description Find SCB associated with peer BD address.
+ *
+ *
+ * Returns Index of SCB or zero if none found.
+ *
+ ******************************************************************************/
+uint16_t bta_ag_idx_by_bdaddr(BD_ADDR peer_addr) {
+ tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+ uint16_t i;
+
+ if (peer_addr != NULL) {
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr)) {
+ return (i + 1);
+ }
+ }
+ }
+
+ /* no scb found */
+ APPL_TRACE_WARNING("No ag scb for peer addr");
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_other_scb_open
+ *
+ * Description Check whether any other scb is in open state.
+ *
+ *
+ * Returns true if another scb is in open state, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_other_scb_open(tBTA_AG_SCB* p_curr_scb) {
+ tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && p_scb != p_curr_scb &&
+ p_scb->state == BTA_AG_OPEN_ST) {
+ return true;
+ }
+ }
+
+ /* no other scb found */
+ APPL_TRACE_DEBUG("No other ag scb open");
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_scb_open
+ *
+ * Description Check whether given scb is in open state.
+ *
+ *
+ * Returns true if scb is in open state, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_scb_open(tBTA_AG_SCB* p_curr_scb) {
+ if (p_curr_scb && p_curr_scb->in_use && p_curr_scb->state == BTA_AG_OPEN_ST) {
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_get_other_idle_scb
+ *
+ * Description Return other scb if it is in INIT st.
+ *
+ *
+ * Returns Pointer to other scb if INIT st, NULL otherwise.
+ *
+ ******************************************************************************/
+tBTA_AG_SCB* bta_ag_get_other_idle_scb(tBTA_AG_SCB* p_curr_scb) {
+ tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+ uint8_t xx;
+
+ for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++) {
+ if (p_scb->in_use && (p_scb != p_curr_scb) &&
+ (p_scb->state == BTA_AG_INIT_ST)) {
+ return p_scb;
+ }
+ }
+
+ /* no other scb found */
+ APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_collision_timer_cback
+ *
+ * Description AG connection collision timer callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_collision_timer_cback(void* data) {
+ tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* If the peer haven't opened AG connection */
+ /* we will restart opening process. */
+ bta_ag_resume_open(p_scb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_collision_cback
+ *
+ * Description Get notified about collision.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status, uint8_t id,
+ UNUSED_ATTR uint8_t app_id, BD_ADDR peer_addr) {
+ uint16_t handle;
+ tBTA_AG_SCB* p_scb;
+
+ /* Check if we have opening scb for the peer device. */
+ handle = bta_ag_idx_by_bdaddr(peer_addr);
+ p_scb = bta_ag_scb_by_idx(handle);
+
+ if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
+ if (id == BTA_ID_SYS) /* ACL collision */
+ {
+ APPL_TRACE_WARNING("AG found collision (ACL) ...");
+ } else if (id == BTA_ID_AG) /* RFCOMM collision */
+ {
+ APPL_TRACE_WARNING("AG found collision (RFCOMM) ...");
+ } else {
+ APPL_TRACE_WARNING("AG found collision (\?\?\?) ...");
+ }
+
+ p_scb->state = BTA_AG_INIT_ST;
+
+ /* Cancel SDP if it had been started. */
+ if (p_scb->p_disc_db) {
+ (void)SDP_CancelServiceSearch(p_scb->p_disc_db);
+ bta_ag_free_db(p_scb, NULL);
+ }
+
+ /* reopen registered servers */
+ /* Collision may be detected before or after we close servers. */
+ if (bta_ag_is_server_closed(p_scb))
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+
+/** M: Change for bug fix: change the timer for ACL collision. @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_HFP_ACL_COLLISION,
+ ((const bt_bdaddr_t *)peer_addr))) {
+ /* Start timer to han */
+ alarm_set_on_queue(p_scb->collision_timer, 25 * 1000,
+ bta_ag_collision_timer_cback, p_scb,
+ btu_bta_alarm_queue);
+ } else {
+#endif
+/** @} */
+ /* Start timer to han */
+ alarm_set_on_queue(p_scb->collision_timer, BTA_AG_COLLISION_TIMEOUT_MS,
+ bta_ag_collision_timer_cback, p_scb,
+ btu_bta_alarm_queue);
+/** M: Change for bug fix: change the timer for ACL collision. @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ }
+#endif
+/** @} */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_resume_open
+ *
+ * Description Resume opening process.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_resume_open(tBTA_AG_SCB* p_scb) {
+ if (p_scb) {
+ APPL_TRACE_DEBUG("bta_ag_resume_open, Handle(%d)",
+ bta_ag_scb_to_idx(p_scb));
+
+ /* resume opening process. */
+ if (p_scb->state == BTA_AG_INIT_ST) {
+ p_scb->state = BTA_AG_OPENING_ST;
+ bta_ag_start_open(p_scb, NULL);
+ }
+ } else {
+ APPL_TRACE_ERROR("bta_ag_resume_open, Null p_scb");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_api_enable
+ *
+ * Description Handle an API enable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA* p_data) {
+ /* initialize control block */
+ for (size_t i = 0; i < BTA_AG_NUM_SCB; i++) {
+ alarm_free(bta_ag_cb.scb[i].ring_timer);
+ alarm_free(bta_ag_cb.scb[i].codec_negotiation_timer);
+ alarm_free(bta_ag_cb.scb[i].collision_timer);
+ }
+ memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+
+ /* store callback function */
+ bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+ bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+
+ /* call init call-out */
+ bta_ag_co_init();
+
+ bta_sys_collision_register(BTA_ID_AG, bta_ag_collision_cback);
+
+ /* call callback with enable event */
+ (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_api_disable
+ *
+ * Description Handle an API disable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA* p_data) {
+ /* deregister all scbs in use */
+ tBTA_AG_SCB* p_scb = &bta_ag_cb.scb[0];
+ bool do_dereg = false;
+ int i;
+
+ if (!bta_sys_is_register(BTA_ID_AG)) {
+ APPL_TRACE_ERROR("BTA AG is already disabled, ignoring ...");
+ return;
+ }
+
+ /* De-register with BTA system manager */
+ bta_sys_deregister(BTA_ID_AG);
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use) {
+ bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+ do_dereg = true;
+ }
+ }
+
+ if (!do_dereg) {
+ /* Done, send callback evt to app */
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+
+ bta_sys_collision_register(BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_api_register
+ *
+ * Description Handle an API event registers a new service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA* p_data) {
+ tBTA_AG_SCB* p_scb;
+ tBTA_AG_REGISTER reg;
+
+ /* allocate an scb */
+ p_scb = bta_ag_scb_alloc();
+ if (p_scb != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_api_register: p_scb 0x%08x ", p_scb);
+ bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+ } else {
+ reg.status = BTA_AG_FAIL_RESOURCES;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG*)&reg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_api_result
+ *
+ * Description Handle an API result event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA* p_data) {
+ tBTA_AG_SCB* p_scb;
+ int i;
+
+ if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) {
+ p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific);
+ if (p_scb != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_api_result: p_scb 0x%08x ", p_scb);
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ } else {
+ for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && p_scb->svc_conn) {
+ APPL_TRACE_DEBUG("bta_ag_api_result p_scb 0x%08x ", p_scb);
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sm_execute
+ *
+ * Description State machine event handling function for AG
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB* p_scb, uint16_t event,
+ tBTA_AG_DATA* p_data) {
+ tBTA_AG_ST_TBL state_table;
+ uint8_t action;
+ int i;
+#if (BTA_AG_DEBUG == TRUE)
+ uint16_t previous_event = event;
+ uint8_t previous_state = p_scb->state;
+
+ /* Ignore displaying of AT results when not connected (Ignored in state
+ * machine) */
+ if ((previous_event != BTA_AG_API_RESULT_EVT ||
+ p_scb->state == BTA_AG_OPEN_ST) &&
+ event != BTA_AG_CI_SCO_DATA_EVT) {
+ APPL_TRACE_EVENT("%s: Handle 0x%04x, State %d (%s), Event 0x%04x (%s)",
+ __func__, bta_ag_scb_to_idx(p_scb), p_scb->state,
+ bta_ag_state_str(p_scb->state), event,
+ bta_ag_evt_str(event, p_data->api_result.result));
+ }
+#else
+ if (event != BTA_AG_CI_SCO_DATA_EVT) {
+ APPL_TRACE_EVENT("%s: Handle 0x%04x, State %d, Event 0x%04x", __func__,
+ bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+ }
+#endif
+
+ event &= 0x00FF;
+ if (event >= (BTA_AG_MAX_EVT & 0x00FF)) {
+ APPL_TRACE_ERROR("%s: event out of range, ignored", __func__);
+ return;
+ }
+
+ /* look up the state table for the current state */
+ state_table = bta_ag_st_tbl[p_scb->state];
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_AG_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_AG_IGNORE) {
+ (*bta_ag_action[action])(p_scb, p_data);
+ } else {
+ break;
+ }
+ }
+#if (BTA_AG_DEBUG == TRUE)
+ if (p_scb->state != previous_state) {
+ APPL_TRACE_EVENT("%s: State Change: [%s] -> [%s] after Event [%s]",
+ __func__, bta_ag_state_str(previous_state),
+ bta_ag_state_str(p_scb->state),
+ bta_ag_evt_str(previous_event, p_data->api_result.result));
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_hdl_event
+ *
+ * Description Data gateway main event handling function.
+ *
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool bta_ag_hdl_event(BT_HDR* p_msg) {
+ tBTA_AG_SCB* p_scb;
+
+ APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
+ switch (p_msg->event) {
+ case BTA_AG_API_ENABLE_EVT:
+ bta_ag_api_enable((tBTA_AG_DATA*)p_msg);
+ break;
+
+ case BTA_AG_API_DISABLE_EVT:
+ bta_ag_api_disable((tBTA_AG_DATA*)p_msg);
+ break;
+
+ case BTA_AG_API_REGISTER_EVT:
+ bta_ag_api_register((tBTA_AG_DATA*)p_msg);
+ break;
+
+ case BTA_AG_API_RESULT_EVT:
+ bta_ag_api_result((tBTA_AG_DATA*)p_msg);
+ break;
+
+ /* all others reference scb by handle */
+ default:
+ p_scb = bta_ag_scb_by_idx(p_msg->layer_specific);
+ if (p_scb != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", p_scb);
+ bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA*)p_msg);
+ }
+ break;
+ }
+ return true;
+}
+
+#if (BTA_AG_DEBUG == TRUE)
+static char* bta_ag_evt_str(uint16_t event, tBTA_AG_RES result) {
+ switch (event) {
+ case BTA_AG_API_REGISTER_EVT:
+ return "Register Request";
+ case BTA_AG_API_DEREGISTER_EVT:
+ return "Deregister Request";
+ case BTA_AG_API_OPEN_EVT:
+ return "Open SLC Request";
+ case BTA_AG_API_CLOSE_EVT:
+ return "Close SLC Request";
+ case BTA_AG_API_AUDIO_OPEN_EVT:
+ return "Open Audio Request";
+ case BTA_AG_API_AUDIO_CLOSE_EVT:
+ return "Close Audio Request";
+ case BTA_AG_API_RESULT_EVT:
+ switch (result) {
+ case BTA_AG_SPK_RES:
+ return ("AT Result BTA_AG_SPK_RES");
+ case BTA_AG_MIC_RES:
+ return ("AT Result BTA_AG_MIC_RES");
+ case BTA_AG_INBAND_RING_RES:
+ return ("AT Result BTA_AG_INBAND_RING_RES");
+ case BTA_AG_CIND_RES:
+ return ("AT Result BTA_AG_CIND_RES");
+ case BTA_AG_BINP_RES:
+ return ("AT Result BTA_AG_BINP_RES");
+ case BTA_AG_IND_RES:
+ return ("AT Result BTA_AG_IND_RES");
+ case BTA_AG_BVRA_RES:
+ return ("AT Result BTA_AG_BVRA_RES");
+ case BTA_AG_CNUM_RES:
+ return ("AT Result BTA_AG_CNUM_RES");
+ case BTA_AG_BTRH_RES:
+ return ("AT Result BTA_AG_BTRH_RES");
+ case BTA_AG_CLCC_RES:
+ return ("AT Result BTA_AG_CLCC_RES");
+ case BTA_AG_COPS_RES:
+ return ("AT Result BTA_AG_COPS_RES");
+ case BTA_AG_IN_CALL_RES:
+ return ("AT Result BTA_AG_IN_CALL_RES");
+ case BTA_AG_IN_CALL_CONN_RES:
+ return ("AT Result BTA_AG_IN_CALL_CONN_RES");
+ case BTA_AG_CALL_WAIT_RES:
+ return ("AT Result BTA_AG_CALL_WAIT_RES");
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ return ("AT Result BTA_AG_OUT_CALL_ORIG_RES");
+ case BTA_AG_OUT_CALL_ALERT_RES:
+ return ("AT Result BTA_AG_OUT_CALL_ALERT_RES");
+ case BTA_AG_OUT_CALL_CONN_RES:
+ return ("AT Result BTA_AG_OUT_CALL_CONN_RES");
+ case BTA_AG_CALL_CANCEL_RES:
+ return ("AT Result BTA_AG_CALL_CANCEL_RES");
+ case BTA_AG_END_CALL_RES:
+ return ("AT Result BTA_AG_END_CALL_RES");
+ case BTA_AG_UNAT_RES:
+ return ("AT Result BTA_AG_UNAT_RES");
+ default:
+ return ("Unknown AG Result");
+ }
+ case BTA_AG_API_SETCODEC_EVT:
+ return "Set Codec Request";
+ case BTA_AG_RFC_OPEN_EVT:
+ return "RFC Opened";
+ case BTA_AG_RFC_CLOSE_EVT:
+ return "RFC Closed";
+ case BTA_AG_RFC_SRV_CLOSE_EVT:
+ return "RFC SRV Closed";
+ case BTA_AG_RFC_DATA_EVT:
+ return "RFC Data";
+ case BTA_AG_SCO_OPEN_EVT:
+ return "Audio Opened";
+ case BTA_AG_SCO_CLOSE_EVT:
+ return "Audio Closed";
+ case BTA_AG_DISC_ACP_RES_EVT:
+ return "Discovery ACP Result";
+ case BTA_AG_DISC_INT_RES_EVT:
+ return "Discovery INT Result";
+ case BTA_AG_DISC_OK_EVT:
+ return "Discovery OK";
+ case BTA_AG_DISC_FAIL_EVT:
+ return "Discovery Failed";
+ case BTA_AG_CI_RX_WRITE_EVT:
+ return "CI RX Write";
+ case BTA_AG_RING_TIMEOUT_EVT:
+ return "Ring Timeout";
+ case BTA_AG_SVC_TIMEOUT_EVT:
+ return "Service Timeout";
+ case BTA_AG_API_ENABLE_EVT:
+ return "Enable AG";
+ case BTA_AG_API_DISABLE_EVT:
+ return "Disable AG";
+ case BTA_AG_CI_SCO_DATA_EVT:
+ return "SCO data Callin";
+ case BTA_AG_CI_SLC_READY_EVT:
+ return "SLC Ready Callin";
+ default:
+ return "Unknown AG Event";
+ }
+}
+
+static char* bta_ag_state_str(uint8_t state) {
+ switch (state) {
+ case BTA_AG_INIT_ST:
+ return "Initial";
+ case BTA_AG_OPENING_ST:
+ return "Opening";
+ case BTA_AG_OPEN_ST:
+ return "Open";
+ case BTA_AG_CLOSING_ST:
+ return "Closing";
+ default:
+ return "Unknown AG State";
+ }
+}
+
+#endif
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_rfc.cc b/mtkbt/code/bt/bta/ag/bta_ag_rfc.cc
new file mode 100755
index 0000000..fcf61a1
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_rfc.cc
@@ -0,0 +1,396 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions controlling the RFCOMM
+ * connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "utl.h"
+
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle);
+void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle);
+
+void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle);
+void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle);
+
+int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len);
+int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len);
+int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK* tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = {
+ bta_ag_port_cback_1, bta_ag_port_cback_2, bta_ag_port_cback_3};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = {
+ bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3};
+
+typedef tPORT_DATA_CALLBACK* tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = {
+ bta_ag_data_cback_1, bta_ag_data_cback_2, bta_ag_data_cback_3};
+
+/*******************************************************************************
+ *
+ * Function bta_ag_port_cback
+ *
+ * Description RFCOMM Port callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle,
+ uint16_t handle) {
+ tBTA_AG_SCB* p_scb;
+
+ p_scb = bta_ag_scb_by_idx(handle);
+ if (p_scb != NULL) {
+ /* ignore port events for port handles other than connected handle */
+ if (port_handle != p_scb->conn_handle) {
+ APPL_TRACE_DEBUG(
+ "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+ port_handle, p_scb->conn_handle, handle);
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_AG_RFC_DATA_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_mgmt_cback
+ *
+ * Description RFCOMM management callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle,
+ uint16_t handle) {
+ tBTA_AG_SCB* p_scb;
+ uint16_t event;
+ uint8_t i;
+ bool found_handle = false;
+
+ APPL_TRACE_DEBUG("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+ code, port_handle, handle);
+
+ p_scb = bta_ag_scb_by_idx(handle);
+ if (p_scb != NULL) {
+ /* ignore close event for port handles other than connected handle */
+ if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) {
+ APPL_TRACE_DEBUG("ag_mgmt_cback ignoring handle:%d", port_handle);
+ return;
+ }
+
+ if (code == PORT_SUCCESS) {
+ if (p_scb->conn_handle) /* Outgoing connection */
+ {
+ if (port_handle == p_scb->conn_handle) found_handle = true;
+ } else /* Incoming connection */
+ {
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ if (port_handle == p_scb->serv_handle[i]) found_handle = true;
+ }
+ }
+
+ if (!found_handle) {
+ APPL_TRACE_ERROR(
+ "bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d",
+ port_handle);
+ return;
+ }
+
+ event = BTA_AG_RFC_OPEN_EVT;
+ }
+ /* distinguish server close events */
+ else if (port_handle == p_scb->conn_handle) {
+ event = BTA_AG_RFC_CLOSE_EVT;
+ } else {
+ event = BTA_AG_RFC_SRV_CLOSE_EVT;
+ }
+
+ tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->port_handle = port_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_data_cback
+ *
+ * Description RFCOMM data callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static int bta_ag_data_cback(UNUSED_ATTR uint16_t port_handle, void* p_data,
+ uint16_t len, uint16_t handle) {
+ /* call data call-out directly */
+ bta_ag_co_tx_write(handle, (uint8_t*)p_data, len);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_port_cback_1 to 3
+ * bta_ag_mgmt_cback_1 to 3
+ *
+ * Description RFCOMM callback functions. This is an easy way to
+ * distinguish scb from the callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_mgmt_cback_1(uint32_t code, uint16_t handle) {
+ bta_ag_mgmt_cback(code, handle, 1);
+}
+void bta_ag_mgmt_cback_2(uint32_t code, uint16_t handle) {
+ bta_ag_mgmt_cback(code, handle, 2);
+}
+void bta_ag_mgmt_cback_3(uint32_t code, uint16_t handle) {
+ bta_ag_mgmt_cback(code, handle, 3);
+}
+void bta_ag_port_cback_1(uint32_t code, uint16_t handle) {
+ bta_ag_port_cback(code, handle, 1);
+}
+void bta_ag_port_cback_2(uint32_t code, uint16_t handle) {
+ bta_ag_port_cback(code, handle, 2);
+}
+void bta_ag_port_cback_3(uint32_t code, uint16_t handle) {
+ bta_ag_port_cback(code, handle, 3);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_data_cback_1 to 3
+ *
+ * Description RFCOMM data callback functions. This is an easy way to
+ * distinguish scb from the callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len) {
+ return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len) {
+ return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len) {
+ return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_setup_port
+ *
+ * Description Setup RFCOMM port for use by AG.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) {
+ uint16_t i = bta_ag_scb_to_idx(p_scb) - 1;
+
+ /* set up data callback if using pass through mode */
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+ PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+ }
+
+ PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+ PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_start_servers
+ *
+ * Description Setup RFCOMM servers for use by AG.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
+ int i;
+ int bta_ag_port_status;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ BTM_SetSecurityLevel(false, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+ BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+ bta_ag_cb.profile[i].scn);
+
+ bta_ag_port_status = RFCOMM_CreateConnection(
+ bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU,
+ (uint8_t*)bd_addr_any, &(p_scb->serv_handle[i]),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+ if (bta_ag_port_status == PORT_SUCCESS) {
+ bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+ } else {
+ /* TODO: CR#137125 to handle to error properly */
+ APPL_TRACE_DEBUG(
+ "bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d",
+ bta_ag_port_status);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_close_servers
+ *
+ * Description Close RFCOMM servers port for use by AG.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) {
+ int i;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+ p_scb->serv_handle[i] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_is_server_closed
+ *
+ * Description Returns true if all servers are closed.
+ *
+ *
+ * Returns true if all servers are closed, false otherwise
+ *
+ ******************************************************************************/
+bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb) {
+ uint8_t xx;
+ bool is_closed = true;
+
+ for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) {
+ if (p_scb->serv_handle[xx] != 0) is_closed = false;
+ }
+
+ return is_closed;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_do_open
+ *
+ * Description Open an RFCOMM connection to the peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ BTM_SetSecurityLevel(true, "", bta_ag_sec_id[p_scb->conn_service],
+ p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+ p_scb->peer_scn);
+
+ if (RFCOMM_CreateConnection(
+ bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU,
+ p_scb->peer_addr, &(p_scb->conn_handle),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) ==
+ PORT_SUCCESS) {
+ bta_ag_setup_port(p_scb, p_scb->conn_handle);
+ APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d",
+ p_scb->conn_handle);
+ }
+ /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ else {
+ bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_rfc_do_close
+ *
+ * Description Close RFCOMM connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ if (p_scb->conn_handle) {
+ RFCOMM_RemoveConnection(p_scb->conn_handle);
+ } else {
+ /* Close API was called while AG is in Opening state. */
+ /* Need to trigger the state machine to send callback to the app */
+ /* and move back to INIT state. */
+ tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC));
+ p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+ bta_sys_sendmsg(p_buf);
+
+ /* Cancel SDP if it had been started. */
+ /*
+ if(p_scb->p_disc_db)
+ {
+ (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+ }
+ */
+ }
+}
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_sco.cc b/mtkbt/code/bt/bta/ag/bta_ag_sco.cc
new file mode 100755
index 0000000..6f0473c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_sco.cc
@@ -0,0 +1,1431 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for managing the SCO connection used in AG.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_co.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#include "bta_dm_co.h"
+#endif
+#include "btm_api.h"
+#include "device/include/controller.h"
+#include "device/include/esco_parameters.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+#ifndef BTA_AG_SCO_DEBUG
+#define BTA_AG_SCO_DEBUG FALSE
+#endif
+
+/* Codec negotiation timeout */
+#ifndef BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS
+#define BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS (3 * 1000) /* 3 seconds */
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+#if (BTA_AG_SCO_DEBUG == TRUE)
+static char* bta_ag_sco_evt_str(uint8_t event);
+static char* bta_ag_sco_state_str(uint8_t state);
+#endif
+
+#define BTA_AG_NO_EDR_ESCO \
+ (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum {
+ BTA_AG_SCO_LISTEN_E, /* listen request */
+ BTA_AG_SCO_OPEN_E, /* open request */
+ BTA_AG_SCO_XFER_E, /* transfer request */
+ BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */
+ BTA_AG_SCO_REOPEN_E, /* Retry with other codec when failed */
+ BTA_AG_SCO_CLOSE_E, /* close request */
+ BTA_AG_SCO_SHUTDOWN_E, /* shutdown request */
+ BTA_AG_SCO_CONN_OPEN_E, /* sco open */
+ BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
+ BTA_AG_SCO_CI_DATA_E /* SCO data ready */
+};
+
+static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local);
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_conn_cback
+ *
+ * Description BTM SCO connection callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_conn_cback(uint16_t sco_idx) {
+ uint16_t handle;
+ tBTA_AG_SCB* p_scb;
+
+ /* match callback to scb; first check current sco scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+ /* then check for scb connected to this peer */
+ else {
+ /* Check if SLC is up */
+ handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+ p_scb = bta_ag_scb_by_idx(handle);
+ if (p_scb && !p_scb->svc_conn) handle = 0;
+ }
+
+ if (handle != 0) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_AG_SCO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ } else {
+ /* no match found; disconnect sco, init sco variables */
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ BTM_RemoveSco(sco_idx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_disc_cback
+ *
+ * Description BTM SCO disconnection callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_disc_cback(uint16_t sco_idx) {
+ uint16_t handle = 0;
+
+ APPL_TRACE_DEBUG(
+ "bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: "
+ "%d",
+ sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
+
+ APPL_TRACE_DEBUG(
+ "bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x "
+ " sco state: %u",
+ &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx,
+ bta_ag_cb.scb[0].state);
+ APPL_TRACE_DEBUG(
+ "bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x in_use: %u sco_idx: 0x%x "
+ " sco state: %u",
+ &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx,
+ bta_ag_cb.scb[1].state);
+
+ /* match callback to scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use) {
+ /* We only care about callbacks for the active SCO */
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx) {
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF) return;
+ }
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+
+ if (handle != 0) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+
+ tBTM_STATUS status =
+ BTM_ConfigScoPath(ESCO_DATA_PATH_PCM, NULL, NULL, true);
+ APPL_TRACE_DEBUG("%s: sco close config status = %d", __func__, status);
+ /* SCO clean up here */
+ bta_dm_sco_co_close();
+#endif
+
+ /* Restore settings */
+ if (bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC) {
+ /* Bypass vendor specific and voice settings if enhanced eSCO supported */
+ /** M: Change feature For enhanced setup synchronous connection. @{ */
+ // Always to set the voice setting.
+ /*if (!(controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection())) {*/
+ BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+ /*}*/
+ /** @} */
+
+ /* If SCO open was initiated by AG and failed for mSBC T2, try mSBC T1
+ * 'Safe setting' first. If T1 also fails, try CVSD */
+ if (bta_ag_sco_is_opening(bta_ag_cb.sco.p_curr_scb)) {
+ bta_ag_cb.sco.p_curr_scb->state = BTA_AG_SCO_CODEC_ST;
+ if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings ==
+ BTA_AG_SCO_MSBC_SETTINGS_T2) {
+ APPL_TRACE_WARNING(
+ "%s: eSCO/SCO failed to open, falling back to mSBC T1 settings",
+ __func__);
+ bta_ag_cb.sco.p_curr_scb->codec_msbc_settings =
+ BTA_AG_SCO_MSBC_SETTINGS_T1;
+ } else {
+ APPL_TRACE_WARNING(
+ "%s: eSCO/SCO failed to open, falling back to CVSD", __func__);
+ bta_ag_cb.sco.p_curr_scb->codec_fallback = true;
+ }
+ }
+ } else if (bta_ag_sco_is_opening(bta_ag_cb.sco.p_curr_scb)) {
+ APPL_TRACE_ERROR("%s: eSCO/SCO failed to open, no more fall back",
+ __func__);
+ }
+
+ bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ } else {
+ /* no match found */
+ APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
+
+ /* sco could be closed after scb dealloc'ed */
+ if (bta_ag_cb.sco.p_curr_scb != NULL) {
+ bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ }
+}
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_read_cback
+ *
+ * Description Callback function is the callback function for incoming
+ * SCO data over HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_read_cback(uint16_t sco_inx, BT_HDR* p_data,
+ tBTM_SCO_DATA_FLAG status) {
+ if (status != BTM_SCO_DATA_CORRECT) {
+ APPL_TRACE_DEBUG("%s: status %d", __func__, status);
+ }
+
+ /* Callout function must free the data. */
+ bta_dm_sco_co_in_data(p_data, status);
+}
+#endif
+/*******************************************************************************
+ *
+ * Function bta_ag_remove_sco
+ *
+ * Description Removes the specified SCO from the system.
+ * If only_active is true, then SCO is only removed if
+ * connected
+ *
+ * Returns bool - true if SCO removal was started
+ *
+ ******************************************************************************/
+static bool bta_ag_remove_sco(tBTA_AG_SCB* p_scb, bool only_active) {
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) {
+ if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx) {
+ tBTM_STATUS status = BTM_RemoveSco(p_scb->sco_idx);
+ APPL_TRACE_DEBUG("%s: SCO index 0x%04x, status %d", __func__,
+ p_scb->sco_idx, status);
+ if (status == BTM_CMD_STARTED) {
+ /* SCO is connected; set current control block */
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ return true;
+ } else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
+ /* If no connection reset the SCO handle */
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ }
+ }
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_esco_connreq_cback
+ *
+ * Description BTM eSCO connection requests and eSCO change requests
+ * Only the connection requests are processed by BTA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event,
+ tBTM_ESCO_EVT_DATA* p_data) {
+ tBTA_AG_SCB* p_scb;
+ uint16_t handle;
+ uint16_t sco_inx = p_data->conn_evt.sco_inx;
+
+ /* Only process connection requests */
+ if (event == BTM_ESCO_CONN_REQ_EVT) {
+ if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+ ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn) {
+ p_scb->sco_idx = sco_inx;
+
+ /* If no other SCO active, allow this one */
+ if (!bta_ag_cb.sco.p_curr_scb) {
+ APPL_TRACE_EVENT("%s: Accept Conn Request (sco_inx 0x%04x)", __func__,
+ sco_inx);
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ } else {
+ /* Begin a transfer: Close current SCO before responding */
+ APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER");
+ bta_ag_cb.sco.p_xfer_scb = p_scb;
+ bta_ag_cb.sco.conn_data = p_data->conn_evt;
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+ if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, true)) {
+ APPL_TRACE_ERROR(
+ "%s: Nothing to remove,so accept Conn Request(sco_inx 0x%04x)",
+ __func__, sco_inx);
+ bta_ag_cb.sco.p_xfer_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+ }
+ }
+ } else {
+ /* If error occurred send reject response immediately */
+ APPL_TRACE_WARNING(
+ "no scb for bta_ag_esco_connreq_cback or no resources");
+ BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+ (enh_esco_params_t*)NULL);
+ }
+ } else if (event == BTM_ESCO_CHG_EVT) {
+ /* Received a change in the esco link */
+ APPL_TRACE_EVENT(
+ "%s: eSCO change event (inx %d): rtrans %d, "
+ "rxlen %d, txlen %d, txint %d",
+ __func__, p_data->chg_evt.sco_inx, p_data->chg_evt.retrans_window,
+ p_data->chg_evt.rx_pkt_len, p_data->chg_evt.tx_pkt_len,
+ p_data->chg_evt.tx_interval);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_cback_sco
+ *
+ * Description Call application callback function with SCO event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB* p_scb, uint8_t event) {
+ tBTA_AG_HDR sco;
+
+ sco.handle = bta_ag_scb_to_idx(p_scb);
+ sco.app_id = p_scb->app_id;
+
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&sco);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_create_sco
+ *
+ * Description Create a SCO connection for a given control block
+ * p_scb : Pointer to the target AG control block
+ * is_orig : Whether to initiate or listen for SCO connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB* p_scb, bool is_orig) {
+ APPL_TRACE_DEBUG(
+ "%s: BEFORE codec_updated=%d, codec_fallback=%d, "
+ "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
+ __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
+ p_scb->peer_codecs, p_scb->codec_msbc_settings);
+ tBTA_AG_PEER_CODEC esco_codec = BTA_AG_CODEC_CVSD;
+
+ /* Make sure this SCO handle is not already in use */
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX) {
+ APPL_TRACE_ERROR("%s: Index 0x%04x already in use!", __func__,
+ p_scb->sco_idx);
+ return;
+ }
+
+ if ((p_scb->sco_codec == BTA_AG_CODEC_MSBC) && !p_scb->codec_fallback)
+ esco_codec = BTA_AG_CODEC_MSBC;
+
+ if (p_scb->codec_fallback) {
+ p_scb->codec_fallback = false;
+ /* Force AG to send +BCS for the next audio connection. */
+ p_scb->codec_updated = true;
+ /* Reset mSBC settings to T2 for the next audio connection */
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+ }
+
+ esco_codec_t codec_index = ESCO_CODEC_CVSD;
+ /* If WBS included, use CVSD by default, index is 0 for CVSD by
+ * initialization. If eSCO codec is mSBC, index is T2 or T1 */
+ if (esco_codec == BTA_AG_CODEC_MSBC) {
+ if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2) {
+ codec_index = ESCO_CODEC_MSBC_T2;
+ } else {
+ codec_index = ESCO_CODEC_MSBC_T1;
+ }
+ }
+
+ /* Initialize eSCO parameters */
+ enh_esco_params_t params = esco_parameters_for_codec(codec_index);
+ /* For CVSD */
+ if (esco_codec == BTM_SCO_CODEC_CVSD) {
+ /* Use the applicable packet types
+ (3-EV3 not allowed due to errata 2363) */
+ params.packet_types =
+ p_bta_ag_cfg->sco_pkt_types | ESCO_PKT_TYPES_MASK_NO_3_EV3;
+ if ((!(p_scb->features & BTA_AG_FEAT_ESCO)) ||
+ (!(p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO))) {
+ params.max_latency_ms = 10;
+ params.retransmission_effort = ESCO_RETRANSMISSION_POWER;
+ }
+ }
+
+ /* If initiating, setup parameters to start SCO/eSCO connection */
+ if (is_orig) {
+ bta_ag_cb.sco.is_local = true;
+ /* Set eSCO Mode */
+ BTM_SetEScoMode(&params);
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ /* save the current codec as sco_codec can be updated while SCO is open. */
+ p_scb->inuse_codec = esco_codec;
+
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Send pending commands to create SCO connection to peer */
+ bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local);
+ } else {
+ /* Not initiating, go to listen mode */
+ uint8_t* p_bd_addr = NULL;
+ p_bd_addr = p_scb->peer_addr;
+
+ tBTM_STATUS status =
+ BTM_CreateSco(p_bd_addr, false, params.packet_types, &p_scb->sco_idx,
+ bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
+ if (status == BTM_CMD_STARTED)
+ BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+
+ APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+ __func__, is_orig, p_scb->sco_idx, status,
+ params.packet_types);
+ }
+ APPL_TRACE_DEBUG(
+ "%s: AFTER codec_updated=%d, codec_fallback=%d, "
+ "sco_codec=%d, peer_codec=%d, msbc_settings=%d",
+ __func__, p_scb->codec_updated, p_scb->codec_fallback, p_scb->sco_codec,
+ p_scb->peer_codecs, p_scb->codec_msbc_settings);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_create_pending_sco
+ *
+ * Description This Function is called after the pre-SCO vendor setup is
+ * done for the BTA to continue and send the HCI Commands for
+ * creating/accepting SCO connection with peer based on the
+ * is_local parameter.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_create_pending_sco(tBTA_AG_SCB* p_scb, bool is_local) {
+ tBTA_AG_PEER_CODEC esco_codec = p_scb->inuse_codec;
+ enh_esco_params_t params;
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+
+ /* Local device requested SCO connection to peer */
+ if (is_local) {
+ if (esco_codec == BTA_AG_CODEC_MSBC) {
+ if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2) {
+ params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
+ } else
+ params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1);
+ } else {
+ params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ if ((!(p_scb->features & BTA_AG_FEAT_ESCO)) ||
+ (!(p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO))) {
+ params.max_latency_ms = 10;
+ params.retransmission_effort = ESCO_RETRANSMISSION_POWER;
+ }
+ }
+
+ /* Bypass voice settings if enhanced SCO setup command is supported */
+ /** M: Change feature: always set the voice settings. @{ */
+ /*if (!(controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection())) {*/
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ BTM_WriteVoiceSettings(BTM_VOICE_SETTING_TRANS);
+ else
+ BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+ /*}*/
+ /** @} */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ /* initialize SCO setup, no voice setting for AG, data rate <==> sample
+ * rate */
+ BTM_ConfigScoPath(params.input_data_path, bta_ag_sco_read_cback, NULL,
+ TRUE);
+#endif
+
+ tBTM_STATUS status = BTM_CreateSco(
+ p_scb->peer_addr, true, params.packet_types, &p_scb->sco_idx,
+ bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
+ if (status == BTM_CMD_STARTED) {
+ /* Initiating the connection, set the current sco handle */
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ } else {
+ /* Local device accepted SCO connection from peer */
+ params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ if ((!(p_scb->features & BTA_AG_FEAT_ESCO)) ||
+ (!(p_scb->peer_features & BTA_AG_PEER_FEAT_ESCO))) {
+ params.max_latency_ms = 10;
+ params.retransmission_effort = ESCO_RETRANSMISSION_POWER;
+ }
+
+ BTM_EScoConnRsp(p_scb->sco_idx, HCI_SUCCESS, &params);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_codec_negotiation_timer_cback
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_codec_negotiation_timer_cback(void* data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_AG_SCB* p_scb = (tBTA_AG_SCB*)data;
+
+ /* Announce that codec negotiation failed. */
+ bta_ag_sco_codec_nego(p_scb, false);
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_codec_negotiate
+ *
+ * Description Initiate codec negotiation by sending AT command.
+ * If not necessary, skip negotiation.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB* p_scb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ if ((p_scb->codec_updated || p_scb->codec_fallback) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC)) {
+ /* Change the power mode to Active until SCO open is completed. */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Send +BCS to the peer */
+ bta_ag_send_bcs(p_scb, NULL);
+
+ /* Start timer to handle timeout */
+ alarm_set_on_queue(
+ p_scb->codec_negotiation_timer, BTA_AG_CODEC_NEGOTIATION_TIMEOUT_MS,
+ bta_ag_codec_negotiation_timer_cback, p_scb, btu_bta_alarm_queue);
+ } else {
+ /* use same codec type as previous SCO connection, skip codec negotiation */
+ APPL_TRACE_DEBUG(
+ "use same codec type as previous SCO connection,skip codec "
+ "negotiation");
+ bta_ag_sco_codec_nego(p_scb, true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_event
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB* p_scb, uint8_t event) {
+ tBTA_AG_SCO_CB* p_sco = &bta_ag_cb.sco;
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ BT_HDR* p_buf;
+#endif
+
+#if (BTA_AG_SCO_DEBUG == TRUE)
+ uint8_t in_state = p_sco->state;
+
+ if (event != BTA_AG_SCO_CI_DATA_E) {
+ APPL_TRACE_EVENT("%s: SCO Index 0x%04x, State %d (%s), Event %d (%s)",
+ __func__, p_scb->sco_idx, p_sco->state,
+ bta_ag_sco_state_str(p_sco->state), event,
+ bta_ag_sco_evt_str(event));
+ }
+#else
+ if (event != BTA_AG_SCO_CI_DATA_E) {
+ APPL_TRACE_EVENT("%s: SCO Index 0x%04x, State %d, Event %d", __func__,
+ p_scb->sco_idx, p_sco->state, event);
+ }
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ if (event == BTA_AG_SCO_CI_DATA_E) {
+ while (true) {
+ bta_dm_sco_co_out_data(&p_buf);
+ if (p_buf) {
+ if (p_sco->state == BTA_AG_SCO_OPEN_ST)
+ BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+ else
+ osi_free(p_buf);
+ } else
+ break;
+ }
+
+ return;
+ }
+#endif
+
+ switch (p_sco->state) {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, false);
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ bta_ag_codec_negotiate(p_scb);
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+
+ if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb)) {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* remove listening connection */
+ /* Ignore the event. Keep listening SCO for the active SLC
+ */
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %d",
+ __func__, event);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_LISTEN_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CODEC_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, false);
+ break;
+
+ case BTA_AG_SCO_CN_DONE_E:
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_scb, true);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+
+ if (p_scb == p_sco->p_curr_scb) p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb)) {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* sco open is not started yet. just go back to listening */
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_CODEC_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPENING_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb) {
+ bta_ag_create_sco(p_scb, false);
+ }
+ break;
+
+ case BTA_AG_SCO_REOPEN_E:
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ bta_ag_codec_negotiate(p_scb);
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb) {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+ } else
+ /** M: Bug Fix for ag sco state machine @{ */
+ //p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ /** @} */
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPENING_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_CL_ST:
+ switch (event) {
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb) {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+ } else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, true);
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ switch (event) {
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, true);
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all connection */
+ bta_ag_remove_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* closed sco; place in listen mode and
+ accept the transferred connection */
+ bta_ag_create_sco(p_scb, false); /* Back into listen mode */
+
+ /* Accept sco connection with xfer scb */
+ bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ p_sco->p_curr_scb = p_sco->p_xfer_scb;
+ p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+ p_sco->p_xfer_scb = NULL;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb) {
+ bta_ag_create_sco(p_scb, false);
+ }
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* close current sco connection */
+ bta_ag_remove_sco(p_sco->p_curr_scb, true);
+
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection if active */
+ if (bta_ag_remove_sco(p_scb, true)) {
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all listening connections */
+ bta_ag_remove_sco(p_scb, false);
+
+ /* If SCO was active on this scb, close it */
+ if (p_scb == p_sco->p_curr_scb) {
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_OPEN_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSING_ST:
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb) {
+ bta_ag_create_sco(p_scb, false);
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not closing scb, just close it */
+ if (p_scb != p_sco->p_curr_scb) {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, false);
+ } else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, false);
+
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSING_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ switch (event) {
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ bta_ag_codec_negotiate(p_scb);
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb) {
+ bta_ag_create_sco(p_scb, false);
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ switch (event) {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection so headset can be transferred
+ Probably entered this state from "opening state" */
+ bta_ag_remove_sco(p_scb, true);
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E: {
+ /* closed sco; place old sco in listen mode,
+ take current sco out of listen, and
+ create originating sco for current */
+ bta_ag_create_sco(p_scb, false);
+ bta_ag_remove_sco(p_sco->p_xfer_scb, false);
+
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ tBTA_AG_SCB* p_cn_scb = p_sco->p_xfer_scb;
+ p_sco->p_xfer_scb = NULL;
+ bta_ag_codec_negotiate(p_cn_scb);
+ break;
+ }
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTTING_ST:
+ switch (event) {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection; wait for conn close event */
+ bta_ag_remove_sco(p_scb, true);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb)) {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ } else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ /* If SCO closed for other HS which is not being disconnected,
+ then create listen sco connection for it as scb still open */
+ if (bta_ag_scb_open(p_scb)) {
+ bta_ag_create_sco(p_scb, false);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb) {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb) {
+ bta_ag_create_sco(p_scb, false);
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ if (!bta_ag_other_scb_open(p_scb)) {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ } else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb) {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING("%s: BTA_AG_SCO_SHUTTING_ST: Ignoring event %d",
+ __func__, event);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+#if (BTA_AG_SCO_DEBUG == TRUE)
+ if (p_sco->state != in_state) {
+ APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_sco_state_str(in_state),
+ bta_ag_sco_state_str(p_sco->state),
+ bta_ag_sco_evt_str(event));
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_is_open
+ *
+ * Description Check if sco is open for this scb.
+ *
+ *
+ * Returns true if sco open for this scb, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sco_is_open(tBTA_AG_SCB* p_scb) {
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_is_opening
+ *
+ * Description Check if sco is in Opening state.
+ *
+ *
+ * Returns true if sco is in Opening state for this scb, false
+ * otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sco_is_opening(tBTA_AG_SCB* p_scb) {
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_listen
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_open
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ uint8_t event;
+
+ /* if another scb using sco, this is a transfer */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb) {
+ event = BTA_AG_SCO_XFER_E;
+ }
+ /* else it is an open */
+ else {
+ event = BTA_AG_SCO_OPEN_E;
+ }
+
+ bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_close
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+/* if scb is in use */
+ /* sco_idx is not allocated in SCO_CODEC_ST, still need to move to listen
+ * state. */
+ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) ||
+ (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+ {
+ APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_codec_nego
+ *
+ * Description Handles result of eSCO codec negotiation
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB* p_scb, bool result) {
+ if (result == true) {
+ /* Subsequent SCO connection will skip codec negotiation */
+ APPL_TRACE_DEBUG("%s: Succeeded for index 0x%04x", __func__,
+ p_scb->sco_idx);
+ p_scb->codec_updated = false;
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+ } else {
+ /* codec negotiation failed */
+ APPL_TRACE_ERROR("%s: Failed for index 0x%04x", __func__, p_scb->sco_idx);
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_shutdown
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_conn_open
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+ bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ /* open SCO codec if SCO is routed through transport */
+ bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE,
+ BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+ /* reset to mSBC T2 settings as the preferred */
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_conn_close
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ /* clear current scb */
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+ /* codec_fallback is set when AG is initiator and connection failed for mSBC.
+ * OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
+ if (p_scb->svc_conn &&
+ (p_scb->codec_fallback ||
+ (p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
+ p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1))) {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+ } else {
+ /* Indicate if the closing of audio is because of transfer */
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+ bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* if av got suspended by this call, let it resume. */
+ /* In case call stays alive regardless of sco, av should not be affected. */
+ if (((p_scb->call_ind == BTA_AG_CALL_INACTIVE) &&
+ (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) ||
+ (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END)) {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sco_conn_rsp
+ *
+ * Description Process the SCO connection request
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB* p_scb,
+ tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
+ bta_ag_cb.sco.is_local = false;
+
+ APPL_TRACE_DEBUG("%s: eSCO %d, state %d", __func__,
+ controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection(),
+ bta_ag_cb.sco.state);
+
+ if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST) {
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ /* When HS initiated SCO, it cannot be WBS. */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ /* Configure the transport being used */
+ BTM_ConfigScoPath(resp.input_data_path, bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+ }
+
+ /* If SCO open was initiated from HS, it must be CVSD */
+ p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+ /* Send pending commands to create SCO connection to peer */
+ bta_ag_create_pending_sco(p_scb, bta_ag_cb.sco.is_local);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_ci_sco_data
+ *
+ * Description Process the SCO data ready callin event
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_ci_sco_data(UNUSED_ATTR tBTA_AG_SCB* p_scb,
+ UNUSED_ATTR tBTA_AG_DATA* p_data) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+ * Debugging functions
+ ******************************************************************************/
+
+#if (BTA_AG_SCO_DEBUG == TRUE)
+static char* bta_ag_sco_evt_str(uint8_t event) {
+ switch (event) {
+ case BTA_AG_SCO_LISTEN_E:
+ return "Listen Request";
+ case BTA_AG_SCO_OPEN_E:
+ return "Open Request";
+ case BTA_AG_SCO_XFER_E:
+ return "Transfer Request";
+ case BTA_AG_SCO_CN_DONE_E:
+ return "Codec Negotiation Done";
+ case BTA_AG_SCO_REOPEN_E:
+ return "Reopen Request";
+ case BTA_AG_SCO_CLOSE_E:
+ return "Close Request";
+ case BTA_AG_SCO_SHUTDOWN_E:
+ return "Shutdown Request";
+ case BTA_AG_SCO_CONN_OPEN_E:
+ return "Opened";
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ return "Closed";
+ case BTA_AG_SCO_CI_DATA_E:
+ return "Sco Data";
+ default:
+ return "Unknown SCO Event";
+ }
+}
+
+static char* bta_ag_sco_state_str(uint8_t state) {
+ switch (state) {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ return "Shutdown";
+ case BTA_AG_SCO_LISTEN_ST:
+ return "Listening";
+ case BTA_AG_SCO_CODEC_ST:
+ return "Codec Negotiation";
+ case BTA_AG_SCO_OPENING_ST:
+ return "Opening";
+ case BTA_AG_SCO_OPEN_CL_ST:
+ return "Open while closing";
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ return "Opening while Transferring";
+ case BTA_AG_SCO_OPEN_ST:
+ return "Open";
+ case BTA_AG_SCO_CLOSING_ST:
+ return "Closing";
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ return "Close while Opening";
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ return "Close while Transferring";
+ case BTA_AG_SCO_SHUTTING_ST:
+ return "Shutting Down";
+ default:
+ return "Unknown SCO State";
+ }
+}
+
+#endif /* (BTA_AG_SCO_DEBUG) */
diff --git a/mtkbt/code/bt/bta/ag/bta_ag_sdp.cc b/mtkbt/code/bt/bta/ag/bta_ag_sdp.cc
new file mode 100755
index 0000000..692d2e5
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ag/bta_ag_sdp.cc
@@ -0,0 +1,474 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions performing SDP
+ * operations.
+ *
+ ******************************************************************************/
+/** M: New Feature for setting volume support to property. @{ */
+#include <cutils/properties.h>
+/** @ } */
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS 2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(uint16_t status);
+void bta_ag_sdp_cback_2(uint16_t status);
+void bta_ag_sdp_cback_3(uint16_t status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB* tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] = {
+ bta_ag_sdp_cback_1, bta_ag_sdp_cback_2, bta_ag_sdp_cback_3};
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sdp_cback
+ *
+ * Description SDP callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ag_sdp_cback(uint16_t status, uint8_t idx) {
+ uint16_t event;
+ tBTA_AG_SCB* p_scb;
+
+ APPL_TRACE_DEBUG("%s status:0x%x", __func__, status);
+
+ p_scb = bta_ag_scb_by_idx(idx);
+ if (p_scb != NULL) {
+ /* set event according to int/acp */
+ if (p_scb->role == BTA_AG_ACP) {
+ event = BTA_AG_DISC_ACP_RES_EVT;
+ } else {
+ event = BTA_AG_DISC_INT_RES_EVT;
+ }
+
+ tBTA_AG_DISC_RESULT* p_buf =
+ (tBTA_AG_DISC_RESULT*)osi_malloc(sizeof(tBTA_AG_DISC_RESULT));
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = idx;
+ p_buf->status = status;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sdp_cback_1 to 3
+ *
+ * Description SDP callback functions. Since there is no way to
+ * distinguish scb from the callback we need separate
+ * callbacks for each scb.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_sdp_cback_1(uint16_t status) { bta_ag_sdp_cback(status, 1); }
+void bta_ag_sdp_cback_2(uint16_t status) { bta_ag_sdp_cback(status, 2); }
+void bta_ag_sdp_cback_3(uint16_t status) { bta_ag_sdp_cback(status, 3); }
+
+/******************************************************************************
+ *
+ * Function bta_ag_add_record
+ *
+ * Description This function is called by a server application to add
+ * HSP or HFP information to an SDP record. Prior to
+ * calling this function the application must call
+ * SDP_CreateRecord() to create an SDP record.
+ *
+ * Returns true if function execution succeeded,
+ * false if function execution failed.
+ *
+ *****************************************************************************/
+bool bta_ag_add_record(uint16_t service_uuid, char* p_service_name, uint8_t scn,
+ tBTA_AG_FEAT features, uint32_t sdp_handle) {
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+ uint16_t svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+ uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ uint16_t version;
+ uint16_t profile_uuid;
+ uint8_t network;
+ bool result = true;
+ bool codec_supported = false;
+ uint8_t buf[2];
+
+ APPL_TRACE_DEBUG("%s uuid: %x", __func__, service_uuid);
+
+ memset(proto_elem_list, 0,
+ BTA_AG_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = scn;
+ result &=
+ SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+ /* add service class id list */
+ svc_class_id_list[0] = service_uuid;
+ svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+ result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS,
+ svc_class_id_list);
+
+ /* add profile descriptor list */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+ profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ version = BTA_HFP_VERSION;
+ } else {
+ profile_uuid = UUID_SERVCLASS_HEADSET;
+ version = HSP_VERSION_1_2;
+ }
+ result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+ /* add service name */
+ if (p_service_name != NULL && p_service_name[0] != 0) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+ }
+
+ /* add features and network */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+ network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+ UINT_DESC_TYPE, 1, &network);
+
+ if (features & BTA_AG_FEAT_CODEC) codec_supported = true;
+
+ features &= BTA_AG_SDP_FEAT_SPEC;
+
+ /* Codec bit position is different in SDP and in BRSF */
+ if (codec_supported) features |= 0x0020;
+
+ UINT16_TO_BE_FIELD(buf, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, 2, buf);
+ }
+
+ /* add browse group list */
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+ browse_list);
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_create_records
+ *
+ * Description Create SDP records for registered services.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) {
+ int i;
+ tBTA_SERVICE_MASK services;
+
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ /* add sdp record if not already registered */
+ if (bta_ag_cb.profile[i].sdp_handle == 0) {
+ bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+ bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+ bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+ bta_ag_cb.profile[i].scn,
+ p_data->api_register.features,
+ bta_ag_cb.profile[i].sdp_handle);
+ bta_sys_add_uuid(bta_ag_uuid[i]);
+ }
+ }
+ }
+
+ p_scb->hsp_version = HSP_VERSION_1_2;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_del_records
+ *
+ * Description Delete SDP records for any registered services.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ tBTA_AG_SCB* p = &bta_ag_cb.scb[0];
+ tBTA_SERVICE_MASK services;
+ tBTA_SERVICE_MASK others = 0;
+ int i;
+
+ /* get services of all other registered servers */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++, p++) {
+ if (p_scb == p) {
+ continue;
+ }
+
+ if (p->in_use && p->dealloc == false) {
+ others |= p->reg_services;
+ }
+ }
+
+ others >>= BTA_HSP_SERVICE_ID;
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0;
+ i++, services >>= 1, others >>= 1) {
+ /* if service registered for this scb and not registered for any other scb
+ */
+ if (((services & 1) == 1) && ((others & 1) == 0)) {
+ APPL_TRACE_DEBUG("bta_ag_del_records %d", i);
+ if (bta_ag_cb.profile[i].sdp_handle != 0) {
+ SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+ bta_ag_cb.profile[i].sdp_handle = 0;
+ }
+ BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+ BTM_SecClrService(bta_ag_sec_id[i]);
+ bta_sys_remove_uuid(bta_ag_uuid[i]);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_sdp_find_attr
+ *
+ * Description Process SDP discovery results to find requested attributes
+ * for requested service.
+ *
+ *
+ * Returns true if results found, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_ag_sdp_find_attr(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
+ tSDP_DISC_REC* p_rec = NULL;
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t uuid;
+ bool result = false;
+
+ if (service & BTA_HFP_SERVICE_MASK) {
+ uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+ } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ uuid = UUID_SERVCLASS_HEADSET_HS;
+ p_scb->peer_version = HSP_VERSION_1_2; /* Default version */
+ } else {
+ return result;
+ }
+
+ /* loop through all records we found */
+ while (true) {
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec);
+ if (p_rec == NULL) {
+ if (uuid == UUID_SERVCLASS_HEADSET_HS) {
+ /* Search again in case the peer device uses the old HSP UUID */
+ uuid = UUID_SERVCLASS_HEADSET;
+ p_scb->peer_version = HSP_VERSION_1_0;
+ p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec);
+ if (p_rec == NULL) {
+ break;
+ }
+ } else
+ break;
+ }
+
+ /* get scn from proto desc list if initiator */
+ if (p_scb->role == BTA_AG_INT) {
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ p_scb->peer_scn = (uint8_t)pe.params[0];
+ } else {
+ continue;
+ }
+ }
+
+ /* get profile version (if failure, version parameter is not updated) */
+ if (!SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version)) {
+ APPL_TRACE_WARNING("%s: Get peer_version failed, using default 0x%04x",
+ __func__, p_scb->peer_version);
+ }
+
+ /* get features if HFP */
+ if (service & BTA_HFP_SERVICE_MASK) {
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ /* Found attribute. Get value. */
+ /* There might be race condition between SDP and BRSF. */
+ /* Do not update if we already received BRSF. */
+ if (p_scb->peer_features == 0)
+ p_scb->peer_features = p_attr->attr_value.v.u16;
+ /** M: New Feature for setting volume support to property. @{ */
+ if ((p_scb->peer_features & BTA_AG_PEER_FEAT_VOL) == 0) {
+ property_set("persist.service.bdroid.vol", "0");
+ } else {
+ property_set("persist.service.bdroid.vol", "1");
+ }
+ /** @} */
+ }
+ } else /* HSP */
+ {
+ p_attr =
+ SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL);
+ if (p_attr != NULL) {
+ /* Remote volume control of HSP */
+ if (p_attr->attr_value.v.u8) {
+ p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+ /** M: New Feature for setting volume support to property. @{ */
+ property_set("persist.service.bdroid.vol", "1");
+ /** @} */
+ }
+ else
+ {
+ p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+ /** M: New Feature for setting volume support to property. @{ */
+ property_set("persist.service.bdroid.vol", "0");
+ /** @} */
+ }
+ }
+ }
+
+ /* found what we needed */
+ result = true;
+ break;
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_do_disc
+ *
+ * Description Do service discovery.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK service) {
+ tSDP_UUID uuid_list[1];
+ uint16_t num_uuid = 1;
+ uint16_t attr_list[4];
+ uint8_t num_attr;
+ bool db_inited = false;
+
+ /* HFP initiator; get proto list and features */
+ if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 4;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ }
+ /* HFP acceptor; get features */
+ else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 3;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ }
+ /* HSP initiator; get proto list */
+ else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+ num_attr = 4;
+ // Although UUID_SERVCLASS_HEADSET_HS (0x1131) is to be used in HSP 1.2,
+ // some HSP 1.2 implementations, such as PTS, still use
+ // UUID_SERVCLASS_HEADSET (0x1108) to store its service record. However,
+ // most of such devices are HSP 1.0 devices.
+ if (p_scb->hsp_version >= HSP_VERSION_1_2) {
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+ } else {
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET;
+ }
+ }
+ /* HSP acceptor; no discovery */
+ else {
+ return;
+ }
+
+ /* allocate buffer for sdp database */
+ p_scb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AG_DISC_BUF_SIZE);
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE,
+ num_uuid, uuid_list, num_attr, attr_list);
+
+ if (db_inited) {
+ /*Service discovery not initiated */
+ db_inited = SDP_ServiceSearchAttributeRequest(
+ p_scb->peer_addr, p_scb->p_disc_db,
+ bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+ }
+
+ if (!db_inited) {
+ /*free discover db */
+ bta_ag_free_db(p_scb, NULL);
+ /* sent failed event */
+ bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_free_db
+ *
+ * Description Free discovery database.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) {
+ osi_free_and_reset((void**)&p_scb->p_disc_db);
+}
diff --git a/mtkbt/code/bt/bta/ar/bta_ar.cc b/mtkbt/code/bt/bta/ar/bta_ar.cc
new file mode 100755
index 0000000..41fe832
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ar/bta_ar.cc
@@ -0,0 +1,322 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation for the audio/video registration module.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_ar_api.h"
+#include "bta_ar_int.h"
+
+/* AV control block */
+tBTA_AR_CB bta_ar_cb;
+
+/*******************************************************************************
+ *
+ * Function bta_ar_id
+ *
+ * Description This function maps sys_id to ar id mask.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_ar_id(tBTA_SYS_ID sys_id) {
+ uint8_t mask = 0;
+ if (sys_id == BTA_ID_AV) {
+ mask = BTA_AR_AV_MASK;
+ } else if (sys_id == BTA_ID_AVK) {
+ mask = BTA_AR_AVK_MASK;
+ }
+
+ return mask;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_init
+ *
+ * Description This function is called to register to AVDTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_init(void) {
+ /* initialize control block */
+ memset(&bta_ar_cb, 0, sizeof(tBTA_AR_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_reg_avdt
+ *
+ * Description This function is called to register to AVDTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_ar_avdt_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ /* route the AVDT registration callback to av or avk */
+ if (bta_ar_cb.p_av_conn_cback)
+ (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data);
+ if (bta_ar_cb.p_avk_conn_cback)
+ (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_reg_avdt
+ *
+ * Description AR module registration to AVDT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+ tBTA_SYS_ID sys_id) {
+ uint8_t mask = 0;
+
+ if (sys_id == BTA_ID_AV) {
+ bta_ar_cb.p_av_conn_cback = p_cback;
+ mask = BTA_AR_AV_MASK;
+ } else if (sys_id == BTA_ID_AVK) {
+ bta_ar_cb.p_avk_conn_cback = p_cback;
+ mask = BTA_AR_AVK_MASK;
+ }
+#if (BTA_AR_DEBUG == TRUE)
+ else {
+ APPL_TRACE_ERROR(
+ "bta_ar_reg_avdt: the registration is from wrong sys_id:%d", sys_id);
+ }
+#endif
+
+ if (mask) {
+ if (bta_ar_cb.avdt_registered == 0) {
+ AVDT_Register(p_reg, bta_ar_avdt_cback);
+ }
+ bta_ar_cb.avdt_registered |= mask;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_dereg_avdt
+ *
+ * Description This function is called to de-register from AVDTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id) {
+ uint8_t mask = 0;
+
+ if (sys_id == BTA_ID_AV) {
+ bta_ar_cb.p_av_conn_cback = NULL;
+ mask = BTA_AR_AV_MASK;
+ } else if (sys_id == BTA_ID_AVK) {
+ bta_ar_cb.p_avk_conn_cback = NULL;
+ mask = BTA_AR_AVK_MASK;
+ }
+ bta_ar_cb.avdt_registered &= ~mask;
+
+ if (bta_ar_cb.avdt_registered == 0) AVDT_Deregister();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_avdt_conn
+ *
+ * Description This function is called to let ar know that some AVDTP
+ * profile is connected for this sys_id.
+ * If the other sys modules started a timer for PENDING_EVT,
+ * the timer can be stopped now.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr) {
+ uint8_t event = BTA_AR_AVDT_CONN_EVT;
+ tAVDT_CTRL data;
+
+ if (sys_id == BTA_ID_AV) {
+ if (bta_ar_cb.p_avk_conn_cback) {
+ (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data);
+ }
+ } else if (sys_id == BTA_ID_AVK) {
+ if (bta_ar_cb.p_av_conn_cback) {
+ (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_reg_avct
+ *
+ * Description This function is called to register to AVCTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_reg_avct(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask,
+ tBTA_SYS_ID sys_id) {
+ uint8_t mask = bta_ar_id(sys_id);
+
+ if (mask) {
+ if (bta_ar_cb.avct_registered == 0) {
+ AVCT_Register(mtu, mtu_br, sec_mask);
+ }
+ bta_ar_cb.avct_registered |= mask;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ar_dereg_avct
+ *
+ * Description This function is called to deregister from AVCTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ar_dereg_avct(tBTA_SYS_ID sys_id) {
+ uint8_t mask = bta_ar_id(sys_id);
+
+ bta_ar_cb.avct_registered &= ~mask;
+
+ if (bta_ar_cb.avct_registered == 0) AVCT_Deregister();
+}
+
+/******************************************************************************
+ *
+ * Function bta_ar_reg_avrc
+ *
+ * Description This function is called to register an SDP record for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ar_reg_avrc(uint16_t service_uuid, const char* service_name,
+ const char* provider_name, uint16_t categories,
+ tBTA_SYS_ID sys_id, bool browse_supported,
+ uint16_t profile_version) {
+ uint8_t mask = bta_ar_id(sys_id);
+ uint8_t temp[8], *p;
+
+ if (!mask || !categories) return;
+
+ if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
+ if (bta_ar_cb.sdp_tg_handle == 0) {
+ bta_ar_cb.tg_registered = mask;
+ bta_ar_cb.sdp_tg_handle = SDP_CreateRecord();
+ AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+ bta_ar_cb.sdp_tg_handle, browse_supported,
+ profile_version);
+ bta_sys_add_uuid(service_uuid);
+ }
+ /* only one TG is allowed (first-come, first-served).
+ * If sdp_tg_handle is non-0, ignore this request */
+ } else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+ (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) {
+ bta_ar_cb.ct_categories[mask - 1] = categories;
+ categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
+ if (bta_ar_cb.sdp_ct_handle == 0) {
+ bta_ar_cb.sdp_ct_handle = SDP_CreateRecord();
+ AVRC_AddRecord(service_uuid, service_name, provider_name, categories,
+ bta_ar_cb.sdp_ct_handle, browse_supported,
+ profile_version);
+ bta_sys_add_uuid(service_uuid);
+ } else {
+ /* multiple CTs are allowed.
+ * Change supported categories on the second one */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, categories);
+ SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+ }
+ }
+}
+
+/******************************************************************************
+ *
+ * Function bta_ar_dereg_avrc
+ *
+ * Description This function is called to de-register/delete an SDP record
+ * for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ar_dereg_avrc(uint16_t service_uuid, tBTA_SYS_ID sys_id) {
+ uint8_t mask = bta_ar_id(sys_id);
+ uint16_t categories = 0;
+ uint8_t temp[8], *p;
+
+ if (!mask) return;
+
+ if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) {
+ if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) {
+ bta_ar_cb.tg_registered = 0;
+ SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle);
+ bta_ar_cb.sdp_tg_handle = 0;
+ bta_sys_remove_uuid(service_uuid);
+ }
+ } else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) {
+ if (bta_ar_cb.sdp_ct_handle) {
+ bta_ar_cb.ct_categories[mask - 1] = 0;
+ categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1];
+ if (!categories) {
+ /* no CT is still registered - cleaup */
+ SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle);
+ bta_ar_cb.sdp_ct_handle = 0;
+ bta_sys_remove_uuid(service_uuid);
+ } else {
+ /* change supported categories to the remaning one */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, categories);
+ SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+ }
+ }
+ }
+}
+
+/** M: Bug fix for update avrcp version @{ */
+/******************************************************************************
+ *
+ * Function bta_ar_update_avrc_version
+ *
+ * Description This function is called when need update to remote
+ * version update for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void bta_ar_update_avrc_version(uint16_t peer_rc_version, tBTA_SYS_ID sys_id) {
+ uint8_t mask = bta_ar_id(sys_id);
+
+ if (mask) {
+ AVRC_Update_Version(bta_ar_cb.sdp_tg_handle, peer_rc_version);
+ }
+
+}
+/** @} */
diff --git a/mtkbt/code/bt/bta/ar/bta_ar_int.h b/mtkbt/code/bt/bta/ar/bta_ar_int.h
new file mode 100755
index 0000000..4661e74
--- a/dev/null
+++ b/mtkbt/code/bt/bta/ar/bta_ar_int.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA audio/video registration
+ * module.
+ *
+ ******************************************************************************/
+#ifndef BTA_AR_INT_H
+#define BTA_AR_INT_H
+
+#include "bta_av_api.h"
+
+#ifndef BTA_AR_DEBUG
+#define BTA_AR_DEBUG TRUE
+#endif
+
+#define BTA_AR_AV_MASK 0x01
+#define BTA_AR_AVK_MASK 0x02
+
+/* data associated with BTA_AR */
+typedef struct {
+ tAVDT_CTRL_CBACK* p_av_conn_cback; /* av connection callback function */
+ tAVDT_CTRL_CBACK* p_avk_conn_cback; /* avk connection callback function */
+ uint8_t avdt_registered;
+ uint8_t avct_registered;
+ uint32_t sdp_tg_handle;
+ uint32_t sdp_ct_handle;
+ uint16_t ct_categories[2];
+ uint8_t tg_registered;
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the
+ connection. */
+} tBTA_AR_CB;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* control block declaration */
+extern tBTA_AR_CB bta_ar_cb;
+
+#endif /* BTA_AR_INT_H */
diff --git a/mtkbt/code/bt/bta/av/bta_av_aact.cc b/mtkbt/code/bt/bta/av/bta_av_aact.cc
new file mode 100755
index 0000000..303de59
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_aact.cc
@@ -0,0 +1,3169 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for advanced audio/video stream
+ * state machine. these functions are shared by both audio and video
+ * streams.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <base/logging.h>
+#include <string.h>
+#include <vector>
+
+#include "avdt_api.h"
+#include "bt_utils.h"
+#include "bta_av_int.h"
+#include "btif/include/btif_av_co.h"
+#include "btif/include/btif_storage.h"
+#include "device/include/interop.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "utl.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* the delay time in milliseconds to start service discovery on AVRCP */
+#ifndef BTA_AV_RC_DISC_TIME_VAL
+#define BTA_AV_RC_DISC_TIME_VAL 3500
+#endif
+
+/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed
+ * to be sent */
+#ifndef BTA_AV_CLOSE_REQ_TIME_VAL
+#define BTA_AV_CLOSE_REQ_TIME_VAL 4000
+#endif
+
+/* number to retry on reconfigure failure - some headsets requirs this number to
+ * be more than 1 */
+#ifndef BTA_AV_RECONFIG_RETRY
+#define BTA_AV_RECONFIG_RETRY 6
+#endif
+
+/* ACL quota we are letting FW use for A2DP Offload Tx. */
+#define BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA 4
+
+static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
+ UNUSED_ATTR tBTA_AV_DATA* p_data);
+
+/* state machine states */
+enum {
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
+
+/* the call out functions for audio stream */
+const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos = {
+ bta_av_co_audio_init, bta_av_co_audio_disc_res,
+ bta_av_co_audio_getconfig, bta_av_co_audio_setconfig,
+ bta_av_co_audio_open, bta_av_co_audio_close,
+ bta_av_co_audio_start, bta_av_co_audio_stop,
+ bta_av_co_audio_src_data_path, bta_av_co_audio_delay,
+ bta_av_co_audio_update_mtu};
+
+/* ssm action functions for audio stream */
+const tBTA_AV_SACT bta_av_a2dp_action[] = {
+ bta_av_do_disc_a2dp, /* BTA_AV_DO_DISC */
+ bta_av_cleanup, /* BTA_AV_CLEANUP */
+ bta_av_free_sdb, /* BTA_AV_FREE_SDB */
+ bta_av_config_ind, /* BTA_AV_CONFIG_IND */
+ bta_av_disconnect_req, /* BTA_AV_DISCONNECT_REQ */
+ bta_av_security_req, /* BTA_AV_SECURITY_REQ */
+ bta_av_security_rsp, /* BTA_AV_SECURITY_RSP */
+ bta_av_setconfig_rsp, /* BTA_AV_SETCONFIG_RSP */
+ bta_av_st_rc_timer, /* BTA_AV_ST_RC_TIMER */
+ bta_av_str_opened, /* BTA_AV_STR_OPENED */
+ bta_av_security_ind, /* BTA_AV_SECURITY_IND */
+ bta_av_security_cfm, /* BTA_AV_SECURITY_CFM */
+ bta_av_do_close, /* BTA_AV_DO_CLOSE */
+ bta_av_connect_req, /* BTA_AV_CONNECT_REQ */
+ bta_av_sdp_failed, /* BTA_AV_SDP_FAILED */
+ bta_av_disc_results, /* BTA_AV_DISC_RESULTS */
+ bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */
+ bta_av_open_failed, /* BTA_AV_OPEN_FAILED */
+ bta_av_getcap_results, /* BTA_AV_GETCAP_RESULTS */
+ bta_av_setconfig_rej, /* BTA_AV_SETCONFIG_REJ */
+ bta_av_discover_req, /* BTA_AV_DISCOVER_REQ */
+ bta_av_conn_failed, /* BTA_AV_CONN_FAILED */
+ bta_av_do_start, /* BTA_AV_DO_START */
+ bta_av_str_stopped, /* BTA_AV_STR_STOPPED */
+ bta_av_reconfig, /* BTA_AV_RECONFIG */
+ bta_av_data_path, /* BTA_AV_DATA_PATH */
+ bta_av_start_ok, /* BTA_AV_START_OK */
+ bta_av_start_failed, /* BTA_AV_START_FAILED */
+ bta_av_str_closed, /* BTA_AV_STR_CLOSED */
+ bta_av_clr_cong, /* BTA_AV_CLR_CONG */
+ bta_av_suspend_cfm, /* BTA_AV_SUSPEND_CFM */
+ bta_av_rcfg_str_ok, /* BTA_AV_RCFG_STR_OK */
+ bta_av_rcfg_failed, /* BTA_AV_RCFG_FAILED */
+ bta_av_rcfg_connect, /* BTA_AV_RCFG_CONNECT */
+ bta_av_rcfg_discntd, /* BTA_AV_RCFG_DISCNTD */
+ bta_av_suspend_cont, /* BTA_AV_SUSPEND_CONT */
+ bta_av_rcfg_cfm, /* BTA_AV_RCFG_CFM */
+ bta_av_rcfg_open, /* BTA_AV_RCFG_OPEN */
+ bta_av_security_rej, /* BTA_AV_SECURITY_REJ */
+ bta_av_open_rc, /* BTA_AV_OPEN_RC */
+ bta_av_chk_2nd_start, /* BTA_AV_CHK_2ND_START */
+ bta_av_save_caps, /* BTA_AV_SAVE_CAPS */
+ bta_av_set_use_rc, /* BTA_AV_SET_USE_RC */
+ bta_av_cco_close, /* BTA_AV_CCO_CLOSE */
+ bta_av_switch_role, /* BTA_AV_SWITCH_ROLE */
+ bta_av_role_res, /* BTA_AV_ROLE_RES */
+ bta_av_delay_co, /* BTA_AV_DELAY_CO */
+ bta_av_open_at_inc, /* BTA_AV_OPEN_AT_INC */
+ bta_av_offload_req, /* BTA_AV_OFFLOAD_REQ */
+ bta_av_offload_rsp, /* BTA_AV_OFFLOAD_RSP */
+ NULL};
+
+/* these tables translate AVDT events to SSM events */
+static const uint16_t bta_av_stream_evt_ok[] = {
+ BTA_AV_STR_DISC_OK_EVT, /* AVDT_DISCOVER_CFM_EVT */
+ BTA_AV_STR_GETCAP_OK_EVT, /* AVDT_GETCAP_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */
+ BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_CFM_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */
+ BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+ 0, /* AVDT_RECONFIG_IND_EVT */
+ BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+ BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+ BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */
+ BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */
+ BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+ BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+ 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static const uint16_t bta_av_stream_evt_fail[] = {
+ BTA_AV_STR_DISC_FAIL_EVT, /* AVDT_DISCOVER_CFM_EVT */
+ BTA_AV_STR_GETCAP_FAIL_EVT, /* AVDT_GETCAP_CFM_EVT */
+ BTA_AV_STR_OPEN_FAIL_EVT, /* AVDT_OPEN_CFM_EVT */
+ BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */
+ BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */
+ BTA_AV_STR_START_FAIL_EVT, /* AVDT_START_CFM_EVT */
+ BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */
+ BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */
+ BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */
+ BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */
+ 0, /* AVDT_RECONFIG_IND_EVT */
+ BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */
+ BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */
+ BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */
+ BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */
+ BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */
+ BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */
+#endif
+ BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */
+ 0 /* AVDT_DELAY_REPORT_CFM_EVT */
+};
+
+static void bta_av_stream0_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+static void bta_av_stream1_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+#if BTA_AV_NUM_STRS > 2
+static void bta_av_stream2_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 3
+static void bta_av_stream3_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+#endif
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+#endif
+/* the array of callback functions to receive events from AVDT control channel
+ */
+tAVDT_CTRL_CBACK* const bta_av_dt_cback[] = {bta_av_stream0_cback,
+ bta_av_stream1_cback
+#if BTA_AV_NUM_STRS > 2
+ ,
+ bta_av_stream2_cback
+#endif
+#if BTA_AV_NUM_STRS > 3
+ ,
+ bta_av_stream3_cback
+#endif
+#if BTA_AV_NUM_STRS > 4
+ ,
+ bta_av_stream4_cback
+#endif
+#if BTA_AV_NUM_STRS > 5
+ ,
+ bta_av_stream5_cback
+#endif
+};
+/***********************************************
+ *
+ * Function bta_get_scb_handle
+ *
+ * Description gives the registered AVDT handle.by checking with sep_type.
+ *
+ *
+ * Returns void
+ **********************************************/
+static uint8_t bta_av_get_scb_handle(tBTA_AV_SCB* p_scb, uint8_t local_sep) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = 0; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ if ((p_scb->seps[i].tsep == local_sep) &&
+ A2DP_CodecTypeEquals(p_scb->seps[i].codec_info,
+ p_scb->cfg.codec_info)) {
+ return (p_scb->seps[i].av_handle);
+ }
+ }
+ APPL_TRACE_DEBUG("%s: local sep_type %d not found", __func__, local_sep)
+ return 0; /* return invalid handle */
+}
+
+/***********************************************
+ *
+ * Function bta_av_get_scb_sep_type
+ *
+ * Description gives the sep type by cross-checking with AVDT handle
+ *
+ *
+ * Returns void
+ **********************************************/
+static uint8_t bta_av_get_scb_sep_type(tBTA_AV_SCB* p_scb,
+ uint8_t tavdt_handle) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = 0; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ if (p_scb->seps[i].av_handle == tavdt_handle) return (p_scb->seps[i].tsep);
+ }
+ APPL_TRACE_DEBUG("%s: handle %d not found", __func__, tavdt_handle)
+ return AVDT_TSEP_INVALID;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_save_addr
+ *
+ * Description copy the bd_addr and maybe reset the supported flags
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_save_addr(tBTA_AV_SCB* p_scb, const BD_ADDR b) {
+ APPL_TRACE_DEBUG("%s: r:%d, s:%d", __func__, p_scb->recfg_sup,
+ p_scb->suspend_sup);
+ if (bdcmp(p_scb->peer_addr, b) != 0) {
+ APPL_TRACE_ERROR("%s: reset flags", __func__);
+ /* a new addr, reset the supported flags */
+ p_scb->recfg_sup = true;
+ p_scb->suspend_sup = true;
+ }
+
+ /* do this copy anyway, just in case the first addr matches
+ * the control block one by accident */
+ bdcpy(p_scb->peer_addr, b);
+}
+
+/*******************************************************************************
+ *
+ * Function notify_start_failed
+ *
+ * Description notify up-layer AV start failed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void notify_start_failed(tBTA_AV_SCB* p_scb) {
+ tBTA_AV_START start;
+ /* if start failed, clear role */
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL;
+ start.initiator = true;
+ start.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_st_rc_timer
+ *
+ * Description start the AVRC timer if no RC connection & CT is supported &
+ * RC is used or
+ * as ACP (we do not really know if we want AVRC)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_st_rc_timer(tBTA_AV_SCB* p_scb,
+ UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s: rc_handle:%d, use_rc: %d", __func__, p_scb->rc_handle,
+ p_scb->use_rc);
+ /* for outgoing RC connection as INT/CT */
+ if ((p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) &&
+ /* (bta_av_cb.features & BTA_AV_FEAT_RCCT) && */
+ (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP))) {
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) {
+ bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+ BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+ } else {
+ p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_next_getcap
+ *
+ * Description The function gets the capabilities of the next available
+ * stream found in the discovery results.
+ *
+ * Returns true if we sent request to AVDT, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_av_next_getcap(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ int i;
+ tAVDT_GETCAP_REQ* p_req;
+ bool sent_cmd = false;
+ uint16_t uuid_int = p_scb->uuid_int;
+ uint8_t sep_requested = 0;
+
+ if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+ sep_requested = AVDT_TSEP_SNK;
+ else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+ sep_requested = AVDT_TSEP_SRC;
+
+ for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) {
+ /* steam not in use, is a sink, and is the right media type (audio/video) */
+ if ((p_scb->sep_info[i].in_use == false) &&
+ (p_scb->sep_info[i].tsep == sep_requested) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+ p_scb->sep_info_idx = i;
+
+ /* we got a stream; get its capabilities */
+ if (p_scb->p_cap == NULL)
+ p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
+ if (p_scb->avdt_version >= AVDT_VERSION_SYNC) {
+ p_req = AVDT_GetAllCapReq;
+ } else {
+ p_req = AVDT_GetCapReq;
+ }
+ (*p_req)(p_scb->peer_addr, p_scb->sep_info[i].seid, p_scb->p_cap,
+ bta_av_dt_cback[p_scb->hdi]);
+ sent_cmd = true;
+ break;
+ }
+ }
+
+ /* if no streams available then stream open fails */
+ if (!sent_cmd) {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data);
+ }
+
+ return sent_cmd;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_proc_stream_evt
+ *
+ * Description Utility function to compose stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_proc_stream_evt(uint8_t handle, BD_ADDR bd_addr,
+ uint8_t event, tAVDT_CTRL* p_data,
+ int index) {
+ uint16_t sec_len = 0;
+ tBTA_AV_SCB* p_scb = bta_av_cb.p_scb[index];
+
+ if (p_data) {
+ if (event == AVDT_SECURITY_IND_EVT) {
+ sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN)
+ ? p_data->security_ind.len
+ : BTA_AV_SECURITY_MAX_LEN;
+ } else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0) {
+ sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN)
+ ? p_data->security_cfm.len
+ : BTA_AV_SECURITY_MAX_LEN;
+ }
+ }
+
+ if (p_scb) {
+ tBTA_AV_STR_MSG* p_msg =
+ (tBTA_AV_STR_MSG*)osi_malloc(sizeof(tBTA_AV_STR_MSG) + sec_len);
+
+ /* copy event data, bd addr, and handle to event message buffer */
+ p_msg->hdr.offset = 0;
+
+ if (bd_addr != NULL) {
+ bdcpy(p_msg->bd_addr, bd_addr);
+ APPL_TRACE_DEBUG("%s: bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", __func__,
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3],
+ bd_addr[4], bd_addr[5]);
+ }
+
+ if (p_data != NULL) {
+ memcpy(&p_msg->msg, p_data, sizeof(tAVDT_CTRL));
+ /* copy config params to event message buffer */
+ switch (event) {
+ case AVDT_RECONFIG_CFM_EVT:
+ if (p_msg->msg.hdr.err_code == 0) {
+ APPL_TRACE_DEBUG(
+ "%s: reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x",
+ __func__,
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0] << 16) +
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[1] << 8) +
+ p_msg->msg.reconfig_cfm.p_cfg->codec_info[2],
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3] << 16) +
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[4] << 8) +
+ p_msg->msg.reconfig_cfm.p_cfg->codec_info[5],
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6] << 16) +
+ (p_msg->msg.reconfig_cfm.p_cfg->codec_info[7] << 8) +
+ p_msg->msg.reconfig_cfm.p_cfg->codec_info[8],
+ p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]);
+ }
+ break;
+
+ case AVDT_CONFIG_IND_EVT:
+ /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on
+ * one L2CAP.
+ * If we already have a signalling connection with the bd_addr and the
+ * streaming
+ * SST is at INIT state, change it to INCOMING state to handle the
+ * signalling
+ * from the 2nd SEP. */
+ if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) &&
+ (bta_av_is_scb_init(p_scb))) {
+ bta_av_set_scb_sst_incoming(p_scb);
+
+ /* When ACP_CONNECT_EVT was received, we put first available scb to
+ * incoming state.
+ * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and
+ * set its state to
+ * incoming which we do it above.
+ * We also have to set the old p_scb state to init to be used later
+ */
+ for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+ if ((bta_av_cb.p_scb[i]) && (i != index)) {
+ if (bta_av_cb.p_scb[i]->state == BTA_AV_INCOMING_SST) {
+ bta_av_cb.p_scb[i]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[i]->coll_mask = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG));
+ break;
+
+ case AVDT_SECURITY_IND_EVT:
+ p_msg->msg.security_ind.p_data = (uint8_t*)(p_msg + 1);
+ memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data,
+ sec_len);
+ break;
+
+ case AVDT_SECURITY_CFM_EVT:
+ p_msg->msg.security_cfm.p_data = (uint8_t*)(p_msg + 1);
+ if (p_data->hdr.err_code == 0) {
+ memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data,
+ sec_len);
+ }
+ break;
+
+ case AVDT_SUSPEND_IND_EVT:
+ p_msg->msg.hdr.err_code = 0;
+ break;
+
+ case AVDT_CONNECT_IND_EVT:
+ p_scb->recfg_sup = true;
+ p_scb->suspend_sup = true;
+ break;
+
+ default:
+ break;
+ }
+ } else
+ p_msg->msg.hdr.err_code = 0;
+
+ /* look up application event */
+ if ((p_data == NULL) || (p_data->hdr.err_code == 0)) {
+ p_msg->hdr.event = bta_av_stream_evt_ok[event];
+ } else {
+ p_msg->hdr.event = bta_av_stream_evt_fail[event];
+ }
+
+ p_msg->initiator = false;
+ if (event == AVDT_SUSPEND_CFM_EVT) p_msg->initiator = true;
+
+ APPL_TRACE_VERBOSE("%s: hndl:x%x", __func__, p_scb->hndl);
+ p_msg->hdr.layer_specific = p_scb->hndl;
+ p_msg->handle = handle;
+ p_msg->avdt_event = event;
+ bta_sys_sendmsg(p_msg);
+ }
+
+/** M: Bug fix for not disconnect signal channel @{ */
+ if (event == AVDT_CLOSE_IND_EVT && bta_av_cb.p_scb[index]
+ && bta_av_cb.p_scb[index]->state == BTA_AV_INCOMING_SST){
+ APPL_TRACE_WARNING("Receive disconnect_ind as incoming connection setup procedure, notify btif_av");
+ tBTA_AV_REJECT reject;
+ bdcpy(reject.bd_addr, bd_addr);
+ reject.hndl = bta_av_cb.p_scb[index]->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject);
+
+ AVDT_ULCloseReq(bd_addr);
+ }
+/** @} */
+
+ if (p_data) {
+ bta_av_conn_cback(handle, bd_addr, event, p_data);
+ } else {
+ APPL_TRACE_ERROR("%s: p_data is null", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sink_data_cback
+ *
+ * Description This is the AVDTP callback function for sink stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
+ uint8_t m_pt) {
+ int index = 0;
+ tBTA_AV_SCB* p_scb;
+ APPL_TRACE_DEBUG(
+ "%s: avdt_handle: %d pkt_len=0x%x offset = 0x%x "
+ "number of frames 0x%x sequence number 0x%x",
+ __func__, handle, p_pkt->len, p_pkt->offset,
+ *((uint8_t*)(p_pkt + 1) + p_pkt->offset), p_pkt->layer_specific);
+ /* Get SCB and correct sep type */
+ for (index = 0; index < BTA_AV_NUM_STRS; index++) {
+ p_scb = bta_av_cb.p_scb[index];
+ if ((p_scb->avdt_handle == handle) &&
+ (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) {
+ break;
+ }
+ }
+ if (index == BTA_AV_NUM_STRS) {
+ /* cannot find correct handler */
+ osi_free(p_pkt);
+ return;
+ }
+ p_pkt->event = BTA_AV_SINK_MEDIA_DATA_EVT;
+ p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(BTA_AV_SINK_MEDIA_DATA_EVT,
+ (tBTA_AV_MEDIA*)p_pkt);
+ /* Free the buffer: a copy of the packet has been delivered */
+ osi_free(p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_stream0_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_stream0_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_VERBOSE("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_stream1_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_stream1_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1);
+}
+
+#if BTA_AV_NUM_STRS > 2
+/*******************************************************************************
+ *
+ * Function bta_av_stream2_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_stream2_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2);
+}
+#endif
+
+#if BTA_AV_NUM_STRS > 3
+/*******************************************************************************
+ *
+ * Function bta_av_stream3_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_stream3_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_av_stream4_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if BTA_AV_NUM_STRS > 4
+static void bta_av_stream4_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_av_stream5_cback
+ *
+ * Description This is the AVDTP callback function for stream events.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if BTA_AV_NUM_STRS > 5
+static void bta_av_stream5_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data) {
+ APPL_TRACE_EVENT("%s: avdt_handle: %d event=0x%x", __func__, handle, event);
+ bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_av_a2dp_sdp_cback
+ *
+ * Description A2DP service discovery callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_a2dp_sdp_cback(bool found, tA2DP_Service* p_service) {
+ tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(bta_av_cb.handle);
+
+ if (p_scb == NULL) {
+ APPL_TRACE_ERROR("%s: no scb found for handle(0x%x)", __func__,
+ bta_av_cb.handle);
+ return;
+ }
+
+ tBTA_AV_SDP_RES* p_msg =
+ (tBTA_AV_SDP_RES*)osi_malloc(sizeof(tBTA_AV_SDP_RES));
+ p_msg->hdr.event =
+ (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT;
+ if (found && (p_service != NULL))
+ p_scb->avdt_version = p_service->avdt_version;
+ else
+ p_scb->avdt_version = 0x00;
+ p_msg->hdr.layer_specific = bta_av_cb.handle;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_adjust_seps_idx
+ *
+ * Description adjust the sep_idx
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_av_adjust_seps_idx(tBTA_AV_SCB* p_scb, uint8_t avdt_handle) {
+ APPL_TRACE_DEBUG("%s: codec: %s", __func__,
+ A2DP_CodecName(p_scb->cfg.codec_info));
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = 0; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ APPL_TRACE_DEBUG("%s: av_handle: %d codec: %s", __func__,
+ p_scb->seps[i].av_handle,
+ A2DP_CodecName(p_scb->seps[i].codec_info));
+ if (p_scb->seps[i].av_handle && (p_scb->seps[i].av_handle == avdt_handle) &&
+ A2DP_CodecTypeEquals(p_scb->seps[i].codec_info,
+ p_scb->cfg.codec_info)) {
+ p_scb->sep_idx = i;
+ p_scb->avdt_handle = p_scb->seps[i].av_handle;
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_switch_role
+ *
+ * Description Switch role was not started and a timer was started.
+ * another attempt to switch role now - still opening.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_switch_role(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE;
+ tBTA_AV_API_OPEN* p_buf = &p_scb->q_info.open;
+
+ APPL_TRACE_DEBUG("%s: wait:x%x", __func__, p_scb->wait);
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY;
+
+ /* clear the masks set when the timer is started */
+ p_scb->wait &=
+ ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START);
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+ if (bta_av_switch_if_needed(p_scb) ||
+ !bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ } else {
+ /* this should not happen in theory. Just in case...
+ * continue to do_disc_a2dp */
+ switch_res = BTA_AV_RS_DONE;
+ }
+ } else {
+ /* report failure on OPEN */
+ switch_res = BTA_AV_RS_FAIL;
+ }
+
+ if (switch_res != BTA_AV_RS_NONE) {
+ if (bta_av_cb.rs_idx == (p_scb->hdi + 1)) {
+ bta_av_cb.rs_idx = 0;
+ }
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY;
+ p_scb->q_tag = 0;
+ p_buf->switch_res = switch_res;
+ bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_role_res
+ *
+ * Description Handle the role changed event
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ bool initiator = false;
+ tBTA_AV_START start;
+ tBTA_AV_OPEN av_open;
+
+ APPL_TRACE_DEBUG("%s: q_tag:%d, wait:x%x, role:x%x", __func__, p_scb->q_tag,
+ p_scb->wait, p_scb->role);
+ if (p_scb->role & BTA_AV_ROLE_START_INT) initiator = true;
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_START) {
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED) {
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ if (p_data->role_res.hci_status != HCI_SUCCESS) {
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ /* start failed because of role switch. */
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.hndl = p_scb->hndl;
+ start.initiator = initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+ } else {
+ bta_av_start_ok(p_scb, p_data);
+ }
+ } else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START)
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED;
+ } else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN) {
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+ if (p_data->role_res.hci_status != HCI_SUCCESS) {
+ /* Open failed because of role switch. */
+ bdcpy(av_open.bd_addr, p_scb->peer_addr);
+ av_open.chnl = p_scb->chnl;
+ av_open.hndl = p_scb->hndl;
+ start.status = BTA_AV_FAIL_ROLE;
+ if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+ av_open.sep = AVDT_TSEP_SNK;
+ else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+ av_open.sep = AVDT_TSEP_SRC;
+ (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&av_open);
+ } else {
+ /* Continue av open process */
+ p_scb->q_info.open.switch_res = BTA_AV_RS_DONE;
+ bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open));
+ }
+ } else {
+ APPL_TRACE_WARNING(
+ "%s: unexpected role switch event: q_tag = %d wait = %d", __func__,
+ p_scb->q_tag, p_scb->wait);
+ }
+ }
+
+ APPL_TRACE_DEBUG("%s: wait:x%x, role:x%x", __func__, p_scb->wait,
+ p_scb->role);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_delay_co
+ *
+ * Description Call the delay call-out function to report the delay report
+ * from SNK
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_do_disc_a2dp
+ *
+ * Description Do service discovery for A2DP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ bool ok_continue = false;
+ tA2DP_SDP_DB_PARAMS db_params;
+ uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST};
+ uint16_t sdp_uuid = 0; /* UUID for which SDP has to be done */
+
+ APPL_TRACE_DEBUG("%s: use_rc: %d rs:%d, oc:%d", __func__,
+ p_data->api_open.use_rc, p_data->api_open.switch_res,
+ bta_av_cb.audio_open_cnt);
+
+ memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+ switch (p_data->api_open.switch_res) {
+ case BTA_AV_RS_NONE:
+ if (bta_av_switch_if_needed(p_scb) ||
+ !bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+ /* waiting for role switch result. save the api to control block */
+ memcpy(&p_scb->q_info.open, &p_data->api_open,
+ sizeof(tBTA_AV_API_OPEN));
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ p_scb->q_tag = BTA_AV_Q_TAG_OPEN;
+ } else {
+ ok_continue = true;
+ }
+ break;
+
+ case BTA_AV_RS_FAIL:
+ /* report a new failure event */
+ p_scb->open_status = BTA_AV_FAIL_ROLE;
+ bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL);
+ break;
+
+ case BTA_AV_RS_OK:
+ p_data = (tBTA_AV_DATA*)&p_scb->q_info.open;
+ /* continue to open if link role is ok */
+ if (bta_av_link_role_ok(p_scb, A2DP_SET_MULTL_BIT)) {
+ ok_continue = true;
+ } else {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN;
+ }
+ break;
+
+ case BTA_AV_RS_DONE:
+ ok_continue = true;
+ break;
+ }
+
+ APPL_TRACE_DEBUG("%s: ok_continue: %d wait:x%x, q_tag: %d", __func__,
+ ok_continue, p_scb->wait, p_scb->q_tag);
+ if (!ok_continue) return;
+
+ /* clear the role switch bits */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+
+ if (p_scb->wait & BTA_AV_WAIT_CHECK_RC) {
+ p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC;
+ bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+ BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+ }
+
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER) {
+ L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH);
+
+ if (bta_av_cb.audio_open_cnt == 1) {
+ /* there's already an A2DP connection. do not allow switch */
+ bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ }
+ }
+ /* store peer addr other parameters */
+ bta_av_save_addr(p_scb, p_data->api_open.bd_addr);
+ p_scb->sec_mask = p_data->api_open.sec_mask;
+ p_scb->use_rc = p_data->api_open.use_rc;
+
+ bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+ if (p_scb->skip_sdp == true) {
+ tA2DP_Service a2dp_ser;
+ a2dp_ser.avdt_version = AVDT_VERSION;
+ p_scb->skip_sdp = false;
+ p_scb->uuid_int = p_data->api_open.uuid;
+ /* only one A2DP find service is active at a time */
+ bta_av_cb.handle = p_scb->hndl;
+ APPL_TRACE_WARNING("%s: Skip Sdp for incoming A2dp connection", __func__);
+ bta_av_a2dp_sdp_cback(true, &a2dp_ser);
+ return;
+ }
+
+ /* only one A2DP find service is active at a time */
+ bta_av_cb.handle = p_scb->hndl;
+
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_attrs = attr_list;
+ p_scb->uuid_int = p_data->api_open.uuid;
+ p_scb->sdp_discovery_started = true;
+ if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+ else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+ sdp_uuid = UUID_SERVCLASS_AUDIO_SINK;
+
+ APPL_TRACE_DEBUG("%s: uuid_int 0x%x, Doing SDP For 0x%x", __func__,
+ p_scb->uuid_int, sdp_uuid);
+ if (A2DP_FindService(sdp_uuid, p_scb->peer_addr, &db_params,
+ bta_av_a2dp_sdp_cback) == A2DP_SUCCESS)
+ return;
+
+ /* when the code reaches here, either the DB is NULL
+ * or A2DP_FindService is not successful */
+ bta_av_a2dp_sdp_cback(false, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_cleanup
+ *
+ * Description cleanup AV stream control block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_cleanup(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_CONN_CHG msg;
+ uint8_t role = BTA_AV_ROLE_AD_INT;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* free any buffers */
+ osi_free_and_reset((void**)&p_scb->p_cap);
+ p_scb->sdp_discovery_started = false;
+ p_scb->avdt_version = 0;
+
+ /* initialize some control block variables */
+ p_scb->open_status = BTA_AV_SUCCESS;
+
+ /* if de-registering shut everything down */
+ msg.hdr.layer_specific = p_scb->hndl;
+ p_scb->started = false;
+ p_scb->current_codec = nullptr;
+ p_scb->cong = false;
+ p_scb->role = role;
+ p_scb->cur_psc_mask = 0;
+ p_scb->wait = 0;
+ p_scb->num_disc_snks = 0;
+ alarm_cancel(p_scb->avrc_ct_timer);
+
+ /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
+ vendor_get_interface()->send_command(
+ (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+ }
+ */
+
+ p_scb->offload_start_pending = false;
+
+ p_scb->skip_sdp = false;
+ if (p_scb->deregistring) {
+ /* remove stream */
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = 0; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ if (p_scb->seps[i].av_handle) AVDT_RemoveStream(p_scb->seps[i].av_handle);
+ p_scb->seps[i].av_handle = 0;
+ }
+
+ bta_av_dereg_comp((tBTA_AV_DATA*)&msg);
+ } else {
+ /* report stream closed to main SM */
+ msg.is_up = false;
+ bdcpy(msg.peer_addr, p_scb->peer_addr);
+ bta_av_conn_chg((tBTA_AV_DATA*)&msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_free_sdb
+ *
+ * Description Free service discovery db buffer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_free_sdb(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ p_scb->sdp_discovery_started = false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_config_ind
+ *
+ * Description Handle a stream configuration indication from the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_CI_SETCONFIG setconfig;
+ tAVDT_SEP_INFO* p_info;
+ tAVDT_CFG* p_evt_cfg = &p_data->str_msg.cfg;
+ uint8_t psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
+ uint8_t
+ local_sep; /* sep type of local handle on which connection was received */
+ tBTA_AV_STR_MSG* p_msg = (tBTA_AV_STR_MSG*)p_data;
+
+ local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle);
+ p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+ memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE);
+ bta_av_save_addr(p_scb, p_data->str_msg.bd_addr);
+
+ /* Clear collision mask */
+ p_scb->coll_mask = 0;
+ alarm_cancel(bta_av_cb.accept_signalling_timer);
+
+ /* if no codec parameters in configuration, fail */
+ if ((p_evt_cfg->num_codec == 0) ||
+ /* or the peer requests for a service we do not support */
+ ((psc_mask != p_scb->cfg.psc_mask) &&
+ (psc_mask != (p_scb->cfg.psc_mask & ~AVDT_PSC_DELAY_RPT)))) {
+ setconfig.hndl = p_scb->hndl; /* we may not need this */
+ setconfig.err_code = AVDT_ERR_UNSUP_CFG;
+ bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT,
+ (tBTA_AV_DATA*)&setconfig);
+ } else {
+ p_info = &p_scb->sep_info[0];
+ p_info->in_use = 0;
+ p_info->media_type = p_scb->media_type;
+ p_info->seid = p_data->str_msg.msg.config_ind.int_seid;
+
+ /* Sep type of Peer will be oppsite role to our local sep */
+ if (local_sep == AVDT_TSEP_SRC)
+ p_info->tsep = AVDT_TSEP_SNK;
+ else if (local_sep == AVDT_TSEP_SNK)
+ p_info->tsep = AVDT_TSEP_SRC;
+
+ p_scb->role |= BTA_AV_ROLE_AD_ACP;
+ p_scb->cur_psc_mask = p_evt_cfg->psc_mask;
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ p_scb->use_rc = true;
+ else
+ p_scb->use_rc = false;
+
+ p_scb->num_seps = 1;
+ p_scb->sep_info_idx = 0;
+ APPL_TRACE_DEBUG("%s: SEID: %d use_rc: %d cur_psc_mask:0x%x", __func__,
+ p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask);
+ /* in case of A2DP SINK this is the first time peer data is being sent to
+ * co functions */
+ if (local_sep == AVDT_TSEP_SNK) {
+ p_scb->p_cos->setcfg(p_scb->hndl, p_evt_cfg->codec_info, p_info->seid,
+ p_scb->peer_addr, p_evt_cfg->num_protect,
+ p_evt_cfg->protect_info, AVDT_TSEP_SNK,
+ p_msg->handle);
+ } else {
+ p_scb->p_cos->setcfg(p_scb->hndl, p_evt_cfg->codec_info, p_info->seid,
+ p_scb->peer_addr, p_evt_cfg->num_protect,
+ p_evt_cfg->protect_info, AVDT_TSEP_SRC,
+ p_msg->handle);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_disconnect_req
+ *
+ * Description Disconnect AVDTP connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_disconnect_req(tBTA_AV_SCB* p_scb,
+ UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_RCB* p_rcb;
+
+ APPL_TRACE_DEBUG("%s: conn_lcb: 0x%x", __func__, bta_av_cb.conn_lcb);
+
+ alarm_cancel(bta_av_cb.link_signalling_timer);
+ alarm_cancel(p_scb->avrc_ct_timer);
+
+ if (bta_av_cb.conn_lcb) {
+ p_rcb = bta_av_get_rcb_by_shdl((uint8_t)(p_scb->hdi + 1));
+ if (p_rcb) bta_av_del_rc(p_rcb);
+ AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+ } else {
+ bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_security_req
+ *
+ * Description Send an AVDTP security request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_security_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+ AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data,
+ p_data->api_protect_req.len);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_security_rsp
+ *
+ * Description Send an AVDTP security response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_security_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label,
+ p_data->api_protect_rsp.error_code,
+ p_data->api_protect_rsp.p_data,
+ p_data->api_protect_rsp.len);
+ } else {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL,
+ 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_setconfig_rsp
+ *
+ * Description setconfig is OK
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t num = p_data->ci_setconfig.num_seid + 1;
+ uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
+ uint8_t* p_seid = p_data->ci_setconfig.p_seid;
+ int i;
+ uint8_t local_sep;
+
+ /* we like this codec_type. find the sep_idx */
+ local_sep = bta_av_get_scb_sep_type(p_scb, avdt_handle);
+ bta_av_adjust_seps_idx(p_scb, avdt_handle);
+ APPL_TRACE_DEBUG("%s: sep_idx: %d cur_psc_mask:0x%x", __func__,
+ p_scb->sep_idx, p_scb->cur_psc_mask);
+
+ if ((AVDT_TSEP_SNK == local_sep) &&
+ (p_data->ci_setconfig.err_code == AVDT_SUCCESS) &&
+ (p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
+ tBTA_AV_MEDIA av_sink_codec_info;
+ memcpy(av_sink_codec_info.avk_config.bd_addr, p_scb->peer_addr,
+ sizeof(BD_ADDR));
+ av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
+ p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(BTA_AV_SINK_MEDIA_CFG_EVT,
+ &av_sink_codec_info);
+ }
+
+ AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label,
+ p_data->ci_setconfig.err_code, p_data->ci_setconfig.category);
+
+ alarm_cancel(bta_av_cb.link_signalling_timer);
+
+ if (p_data->ci_setconfig.err_code == AVDT_SUCCESS) {
+ p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON;
+ if (p_data->ci_setconfig.recfg_needed)
+ p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT;
+ APPL_TRACE_DEBUG("%s: recfg_needed:%d role:x%x num:%d", __func__,
+ p_data->ci_setconfig.recfg_needed, p_scb->role, num);
+ /* callout module tells BTA the number of "good" SEPs and their SEIDs.
+ * getcap on these SEID */
+ p_scb->num_seps = num;
+
+ if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT)
+ p_scb->avdt_version = AVDT_VERSION_SYNC;
+
+ if (A2DP_GetCodecType(p_scb->cfg.codec_info) == A2DP_MEDIA_CT_SBC ||
+ num > 1) {
+ /* if SBC is used by the SNK as INT, discover req is not sent in
+ * bta_av_config_ind.
+ * call disc_res now */
+ /* this is called in A2DP SRC path only, In case of SINK we don't need it
+ */
+ /** M: Bug fix for avoid reset discover result@{ */
+ if ((local_sep == AVDT_TSEP_SRC)
+ && (p_scb->num_disc_snks == 0))
+ /** @} */
+ {
+ p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr,
+ UUID_SERVCLASS_AUDIO_SOURCE);
+ /** M: Bug fix for DUT doesnot get peer's capability because of uuid_int=0 @{ */
+ if (p_scb->uuid_int == 0)
+ p_scb->uuid_int = UUID_SERVCLASS_AUDIO_SOURCE;
+ /** @} */
+ }
+ } else {
+ /* we do not know the peer device and it is using non-SBC codec
+ * we need to know all the SEPs on SNK */
+ /** M: Bug skip discover for blocking thread @{ */
+ //bta_av_discover_req(p_scb, NULL);
+ //return;
+ APPL_TRACE_DEBUG("%s: skip discover action", __func__);
+ /** @} */
+ }
+
+ for (i = 1; i < num; i++) {
+ APPL_TRACE_DEBUG("%s: sep_info[%d] SEID: %d", __func__, i, p_seid[i - 1]);
+ /* initialize the sep_info[] to get capabilities */
+ p_scb->sep_info[i].in_use = false;
+ p_scb->sep_info[i].tsep = AVDT_TSEP_SNK;
+ p_scb->sep_info[i].media_type = p_scb->media_type;
+ p_scb->sep_info[i].seid = p_seid[i - 1];
+ }
+
+ /* only in case of local sep as SRC we need to look for other SEPs, In case
+ * of SINK we don't */
+ if (local_sep == AVDT_TSEP_SRC) {
+ /* Make sure UUID has been initialized... */
+ if (p_scb->uuid_int == 0) p_scb->uuid_int = p_scb->open_api.uuid;
+ bta_av_next_getcap(p_scb, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_str_opened
+ *
+ * Description Stream opened OK (incoming/outgoing).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_CONN_CHG msg;
+ tBTA_AV_OPEN open;
+ uint8_t* p;
+ uint16_t mtu;
+
+ msg.hdr.layer_specific = p_scb->hndl;
+ msg.is_up = true;
+ bdcpy(msg.peer_addr, p_scb->peer_addr);
+ p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+ bta_av_conn_chg((tBTA_AV_DATA*)&msg);
+ /* set the congestion flag, so AV would not send media packets by accident */
+ p_scb->cong = true;
+ p_scb->offload_start_pending = false;
+
+ p_scb->stream_mtu =
+ p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
+ mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+ APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d mtu: %d", __func__,
+ p_scb->l2c_cid, p_scb->stream_mtu, mtu);
+ /** M: Bug fix for update avrcp version @{ */
+ bta_av_rc_disc((uint8_t)(p_scb->hdi + 1), true);
+ /** @} */
+ if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
+
+ /* Set the media channel as medium priority */
+
+ /**M:Bug fix for A2DP not smooth @{*/
+ /*L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM);*/
+ L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_HIGH);
+ /**@}*/
+
+ L2CA_SetChnlFlushability(p_scb->l2c_cid, true);
+
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO));
+
+ p_scb->l2c_bufs = 0;
+ p_scb->p_cos->open(p_scb->hndl, mtu);
+
+ {
+ /* TODO check if other audio channel is open.
+ * If yes, check if reconfig is needed
+ * Rigt now we do not do this kind of checking.
+ * BTA-AV is INT for 2nd audio connection.
+ * The application needs to make sure the current codec_info is proper.
+ * If one audio connection is open and another SNK attempts to connect to
+ * AV,
+ * the connection will be rejected.
+ */
+ /* check if other audio channel is started. If yes, start */
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ open.chnl = p_scb->chnl;
+ open.hndl = p_scb->hndl;
+ open.status = BTA_AV_SUCCESS;
+ open.starting = bta_av_chk_start(p_scb);
+ open.edr = 0;
+ p = BTM_ReadRemoteFeatures(p_scb->peer_addr);
+ if (p != NULL) {
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_2MBPS;
+ if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) open.edr |= BTA_AV_EDR_3MBPS;
+ }
+#if (BTA_AR_INCLUDED == TRUE)
+ bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr);
+#endif
+ if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+ open.sep = AVDT_TSEP_SNK;
+ else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+ open.sep = AVDT_TSEP_SRC;
+
+ (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&open);
+ if (open.starting) {
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ }
+
+ // This code is used to pass PTS TC for AVDTP ABORT
+ char value[PROPERTY_VALUE_MAX] = {0};
+ if ((osi_property_get("bluetooth.pts.force_a2dp_abort", value, "false")) &&
+ (!strcmp(value, "true"))) {
+ APPL_TRACE_ERROR("%s: Calling AVDT_AbortReq", __func__);
+ AVDT_AbortReq(p_scb->avdt_handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_security_ind
+ *
+ * Description Handle an AVDTP security indication.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_security_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_PROTECT_REQ protect_req;
+
+ p_scb->avdt_label = p_data->str_msg.msg.hdr.label;
+
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+ protect_req.chnl = p_scb->chnl;
+ protect_req.hndl = p_scb->hndl;
+ protect_req.p_data = p_data->str_msg.msg.security_ind.p_data;
+ protect_req.len = p_data->str_msg.msg.security_ind.len;
+
+ (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV*)&protect_req);
+ }
+ /* app doesn't support security indication; respond with failure */
+ else {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL,
+ 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_security_cfm
+ *
+ * Description Handle an AVDTP security confirm.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_PROTECT_RSP protect_rsp;
+
+ if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) {
+ protect_rsp.chnl = p_scb->chnl;
+ protect_rsp.hndl = p_scb->hndl;
+ protect_rsp.p_data = p_data->str_msg.msg.security_cfm.p_data;
+ protect_rsp.len = p_data->str_msg.msg.security_cfm.len;
+ protect_rsp.err_code = p_data->str_msg.msg.hdr.err_code;
+
+ (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV*)&protect_rsp);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_do_close
+ *
+ * Description Close stream.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_do_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ /* stop stream if started */
+ if (p_scb->co_started) {
+ bta_av_str_stopped(p_scb, NULL);
+ }
+ alarm_cancel(bta_av_cb.link_signalling_timer);
+
+ /* close stream */
+ p_scb->started = false;
+ p_scb->current_codec = nullptr;
+
+/** M: Bug fix for When doing A2DP close, cancel SDP if it has been started to avoid NE @{ */
+ /* Cancel SDP if it had been started. */
+ if(p_scb->sdp_discovery_started)
+ {
+ APPL_TRACE_EVENT("bta_av_do_close: Cancel SDP if it had been started.");
+ (void)SDP_CancelServiceSearch (A2D_Get_Disc_DB());
+ }
+/** @} */
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+ AVDT_CloseReq(p_scb->avdt_handle);
+ /* just in case that the link is congested, link is flow controled by peer or
+ * for whatever reason the the close request can not be sent in time.
+ * when this timer expires, AVDT_DisconnectReq will be called to disconnect
+ * the link
+ */
+ bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_CLOSE_REQ_TIME_VAL,
+ BTA_AV_API_CLOSE_EVT, p_scb->hndl);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_connect_req
+ *
+ * Description Connect AVDTP connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_connect_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ p_scb->sdp_discovery_started = false;
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+ /* SNK initiated L2C connection while SRC was doing SDP. */
+ /* Wait until timeout to check if SNK starts signalling. */
+ APPL_TRACE_EVENT("%s: coll_mask = 0x%2X", __func__, p_scb->coll_mask);
+ p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+ APPL_TRACE_EVENT("%s: updated coll_mask = 0x%2X", __func__,
+ p_scb->coll_mask);
+ return;
+ }
+
+ /** M: Bug fix for a2dp connect collision fail @{ */
+ uint16_t ret;
+ ret = AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+ bta_av_dt_cback[p_scb->hdi]);
+ if (AVDT_BUSY == ret) {
+ bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+ /** @}*/
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sdp_failed
+ *
+ * Description Service discovery failed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ if (!p_scb->open_status) p_scb->open_status = BTA_AV_FAIL_SDP;
+
+ p_scb->sdp_discovery_started = false;
+ bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_disc_results
+ *
+ * Description Handle the AVDTP discover results. Search through the
+ * results and find the first available stream, and get
+ * its capabilities.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t num_snks = 0, num_srcs = 0, i;
+ /* our uuid in case we initiate connection */
+ uint16_t uuid_int = p_scb->uuid_int;
+
+ APPL_TRACE_DEBUG("%s: initiator UUID 0x%x", __func__, uuid_int);
+ /* store number of stream endpoints returned */
+ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+ for (i = 0; i < p_scb->num_seps; i++) {
+ /* steam not in use, is a sink, and is audio */
+ if ((p_scb->sep_info[i].in_use == false) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+ if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+ (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE))
+ num_snks++;
+
+ if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) &&
+ (uuid_int == UUID_SERVCLASS_AUDIO_SINK))
+ num_srcs++;
+ }
+ }
+
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs,
+ p_scb->peer_addr, uuid_int);
+ p_scb->num_disc_snks = num_snks;
+ p_scb->num_disc_srcs = num_srcs;
+
+ /* if we got any */
+ if (p_scb->num_seps > 0) {
+ /* initialize index into discovery results */
+ p_scb->sep_info_idx = 0;
+
+ /* get the capabilities of the first available stream */
+ bta_av_next_getcap(p_scb, p_data);
+ }
+ /* else we got discover response but with no streams; we're done */
+ else {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_disc_res_as_acp
+ *
+ * Description Handle the AVDTP discover results. Search through the
+ * results and find the first available stream, and get
+ * its capabilities.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t num_snks = 0, i;
+
+ /* store number of stream endpoints returned */
+ p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps;
+
+ for (i = 0; i < p_scb->num_seps; i++) {
+ /* steam is a sink, and is audio */
+ if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) &&
+ (p_scb->sep_info[i].media_type == p_scb->media_type)) {
+ p_scb->sep_info[i].in_use = false;
+ num_snks++;
+ }
+ }
+ p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0,
+ p_scb->peer_addr, UUID_SERVCLASS_AUDIO_SOURCE);
+ p_scb->num_disc_snks = num_snks;
+ p_scb->num_disc_srcs = 0;
+
+ /* if we got any */
+ if (p_scb->num_seps > 0) {
+ /* initialize index into discovery results */
+ p_scb->sep_info_idx = 0;
+
+ /* get the capabilities of the first available stream */
+ bta_av_next_getcap(p_scb, p_data);
+ }
+ /* else we got discover response but with no streams; we're done */
+ else {
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_save_caps
+ *
+ * Description report the SNK SEP capabilities to application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tAVDT_CFG cfg;
+ tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+ uint8_t old_wait = p_scb->wait;
+ bool getcap_done = false;
+
+ APPL_TRACE_DEBUG("%s: num_seps:%d sep_info_idx:%d wait:x%x", __func__,
+ p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait);
+ memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG));
+ /* let application know the capability of the SNK */
+ p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
+ p_info->seid, &cfg.num_protect, cfg.protect_info);
+
+ p_scb->sep_info_idx++;
+ if (p_scb->num_seps > p_scb->sep_info_idx) {
+ /* Some devices have seps at the end of the discover list, which is not */
+ /* matching media type(video not audio). */
+ /* In this case, we are done with getcap without sending another */
+ /* request to AVDT. */
+ if (!bta_av_next_getcap(p_scb, p_data)) getcap_done = true;
+ } else
+ getcap_done = true;
+
+ if (getcap_done) {
+ /* we are done getting capabilities. restore the p_cb->sep_info_idx */
+ p_scb->sep_info_idx = 0;
+ p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED);
+ if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) {
+ bta_av_start_ok(p_scb, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_set_use_rc
+ *
+ * Description set to use AVRC for this stream control block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_set_use_rc(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ p_scb->use_rc = true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_cco_close
+ *
+ * Description call close call-out function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_cco_close(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ uint16_t mtu;
+
+ mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU);
+
+ p_scb->p_cos->close(p_scb->hndl);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_open_failed
+ *
+ * Description Failed to open an AVDT stream
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ bool is_av_opened = false;
+ tBTA_AV_SCB* p_opened_scb = NULL;
+ uint8_t idx;
+ tBTA_AV_OPEN open;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ p_scb->open_status = BTA_AV_FAIL_STREAM;
+ bta_av_cco_close(p_scb, p_data);
+
+ /* check whether there is already an opened audio or video connection with the
+ * same device */
+ for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == false); idx++) {
+ p_opened_scb = bta_av_cb.p_scb[idx];
+ if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) &&
+ (!bdcmp(p_opened_scb->peer_addr, p_scb->peer_addr)))
+ is_av_opened = true;
+ }
+
+ /* if there is already an active AV connnection with the same bd_addr,
+ don't send disconnect req, just report the open event with
+ BTA_AV_FAIL_GET_CAP status */
+ if (is_av_opened == true) {
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ open.chnl = p_scb->chnl;
+ open.hndl = p_scb->hndl;
+ open.status = BTA_AV_FAIL_GET_CAP;
+ open.starting = bta_av_chk_start(p_scb);
+ open.edr = 0;
+ /* set the state back to initial state */
+ bta_av_set_scb_sst_init(p_scb);
+
+ if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+ open.sep = AVDT_TSEP_SNK;
+ else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+ open.sep = AVDT_TSEP_SRC;
+
+ (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV*)&open);
+
+ } else {
+ /** M: Bug fix for Bta and btif state not change to idle, when signal channel disconnect @{ */
+ uint16_t ret;
+ ret = AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+ if (AVDT_BAD_PARAMS == ret) {
+ APPL_TRACE_WARNING("ccb is null, notify bta and btif to change state");
+ tBTA_AV_REJECT reject;
+ bdcpy(reject.bd_addr, p_scb->peer_addr);
+ reject.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject);
+
+ bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+ /** @} */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_getcap_results
+ *
+ * Description Handle the AVDTP get capabilities results. Check the codec
+ * type and see if it matches ours. If it does not, get the
+ * capabilities of the next stream, if any.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tAVDT_CFG cfg;
+ uint8_t media_type;
+ tAVDT_SEP_INFO* p_info = &p_scb->sep_info[p_scb->sep_info_idx];
+ uint16_t uuid_int; /* UUID for which connection was initiatied */
+
+ memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+ cfg.num_codec = 1;
+ cfg.num_protect = p_scb->p_cap->num_protect;
+ memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+ memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE);
+ media_type = A2DP_GetMediaType(p_scb->p_cap->codec_info);
+
+ APPL_TRACE_DEBUG("%s: num_codec %d", __func__, p_scb->p_cap->num_codec);
+ APPL_TRACE_DEBUG("%s: media type x%x, x%x", __func__, media_type,
+ p_scb->media_type);
+
+ /* if codec present and we get a codec configuration */
+ if ((p_scb->p_cap->num_codec != 0) && (media_type == p_scb->media_type) &&
+ (p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info, &p_scb->sep_info_idx,
+ p_info->seid, &cfg.num_protect,
+ cfg.protect_info) == A2DP_SUCCESS)) {
+ /* save copy of codec configuration */
+ memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG));
+
+ uuid_int = p_scb->uuid_int;
+ APPL_TRACE_DEBUG("%s: initiator UUID = 0x%x", __func__, uuid_int);
+ if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)
+ bta_av_adjust_seps_idx(p_scb,
+ bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
+ else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK)
+ bta_av_adjust_seps_idx(p_scb,
+ bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK));
+
+ /* use only the services peer supports */
+ cfg.psc_mask &= p_scb->p_cap->psc_mask;
+ p_scb->cur_psc_mask = cfg.psc_mask;
+
+ if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) &&
+ (p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback != NULL)) {
+ APPL_TRACE_DEBUG("%s: configure decoder for Sink connection", __func__);
+ tBTA_AV_MEDIA av_sink_codec_info;
+ memcpy(av_sink_codec_info.avk_config.bd_addr, p_scb->peer_addr,
+ sizeof(BD_ADDR));
+ av_sink_codec_info.avk_config.codec_info = p_scb->cfg.codec_info;
+ p_scb->seps[p_scb->sep_idx].p_app_sink_data_cback(
+ BTA_AV_SINK_MEDIA_CFG_EVT, &av_sink_codec_info);
+ }
+
+ if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) {
+ A2DP_AdjustCodec(cfg.codec_info);
+ }
+
+ /* open the stream */
+ AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr,
+ p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg);
+
+ if (!bta_av_is_rcfg_sst(p_scb)) {
+ /* free capabilities buffer */
+ osi_free_and_reset((void**)&p_scb->p_cap);
+ }
+ } else {
+ /* try the next stream, if any */
+ p_scb->sep_info_idx++;
+ bta_av_next_getcap(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_setconfig_rej
+ *
+ * Description Send AVDTP set config reject.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_REJECT reject;
+ uint8_t avdt_handle = p_data->ci_setconfig.avdt_handle;
+
+ bta_av_adjust_seps_idx(p_scb, avdt_handle);
+ APPL_TRACE_DEBUG("%s: sep_idx: %d", __func__, p_scb->sep_idx);
+ AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0);
+
+ bdcpy(reject.bd_addr, p_data->str_msg.bd_addr);
+ reject.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV*)&reject);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_discover_req
+ *
+ * Description Send an AVDTP discover request to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_discover_req(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ /* send avdtp discover request */
+
+ AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
+ bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_conn_failed
+ *
+ * Description AVDTP connection failed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ p_scb->open_status = BTA_AV_FAIL_STREAM;
+ bta_av_str_closed(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_do_start
+ *
+ * Description Start stream.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_do_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t cur_role;
+
+ APPL_TRACE_DEBUG("%s: sco_occupied:%d, role:x%x, started:%d", __func__,
+ bta_av_cb.sco_occupied, p_scb->role, p_scb->started);
+ if (bta_av_cb.sco_occupied) {
+ bta_av_start_failed(p_scb, p_data);
+ return;
+ }
+
+ /* disallow role switch during streaming, only if we are the master role
+ * i.e. allow role switch, if we are slave.
+ * It would not hurt us, if the peer device wants us to be master */
+ if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+ (cur_role == BTM_ROLE_MASTER)) {
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+
+ bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ if ((p_scb->started == false) &&
+ ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) {
+ p_scb->role |= BTA_AV_ROLE_START_INT;
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+ AVDT_StartReq(&p_scb->avdt_handle, 1);
+ } else if (p_scb->started) {
+ p_scb->role |= BTA_AV_ROLE_START_INT;
+ if (p_scb->wait == 0) {
+ if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+ notify_start_failed(p_scb);
+ } else {
+ bta_av_start_ok(p_scb, NULL);
+ }
+ }
+ }
+ APPL_TRACE_DEBUG("%s: started %d role:x%x", __func__, p_scb->started,
+ p_scb->role);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_str_stopped
+ *
+ * Description Stream stopped.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_SUSPEND suspend_rsp;
+ uint8_t start = p_scb->started;
+ bool sus_evt = true;
+ BT_HDR* p_buf;
+ uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+ APPL_TRACE_ERROR("%s: audio_open_cnt=%d, p_data %p", __func__,
+ bta_av_cb.audio_open_cnt, p_data);
+
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+ bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ if (p_scb->co_started) {
+ /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
+ vendor_get_interface()->send_command(
+ (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+ }
+ p_scb->offload_start_pending = false;
+ */
+
+ bta_av_stream_chg(p_scb, false);
+ p_scb->co_started = false;
+
+ p_scb->p_cos->stop(p_scb->hndl);
+ L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ }
+
+ /* if q_info.a2dp_list is not empty, drop it now */
+ if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
+ while (!list_is_empty(p_scb->a2dp_list)) {
+ p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+ list_remove(p_scb->a2dp_list, p_buf);
+ osi_free(p_buf);
+ }
+
+ /* drop the audio buffers queued in L2CAP */
+ if (p_data && p_data->api_stop.flush)
+ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+ }
+
+ suspend_rsp.chnl = p_scb->chnl;
+ suspend_rsp.hndl = p_scb->hndl;
+
+ if (p_data && p_data->api_stop.suspend) {
+ APPL_TRACE_DEBUG("%s: suspending: %d, sup:%d", __func__, start,
+ p_scb->suspend_sup);
+ if ((start) && (p_scb->suspend_sup)) {
+ sus_evt = false;
+ p_scb->l2c_bufs = 0;
+ AVDT_SuspendReq(&p_scb->avdt_handle, 1);
+ }
+
+ /* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is
+ * true*/
+ if ((sus_evt) && (p_scb->state != BTA_AV_RCFG_SST)) {
+ suspend_rsp.status = BTA_AV_SUCCESS;
+ suspend_rsp.initiator = true;
+ (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV*)&suspend_rsp);
+ }
+ } else {
+ suspend_rsp.status = BTA_AV_SUCCESS;
+ suspend_rsp.initiator = true;
+ APPL_TRACE_EVENT("%s: status %d", __func__, suspend_rsp.status);
+
+ // Send STOP_EVT event only if not in reconfiguring state.
+ // However, we should send STOP_EVT if we are reconfiguring when taking
+ // the Close->Configure->Open->Start path.
+ if (p_scb->state != BTA_AV_RCFG_SST ||
+ (p_data && p_data->api_stop.reconfig_stop)) {
+ (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV*)&suspend_rsp);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_reconfig
+ *
+ * Description process the reconfigure request.
+ * save the parameter in control block and
+ * suspend, reconfigure or close the stream
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tAVDT_CFG* p_cfg;
+ tBTA_AV_API_STOP stop;
+ tBTA_AV_API_RCFG* p_rcfg = &p_data->api_reconfig;
+
+ APPL_TRACE_DEBUG("%s: r:%d, s:%d idx: %d (o:%d)", __func__, p_scb->recfg_sup,
+ p_scb->suspend_sup, p_scb->rcfg_idx, p_scb->sep_info_idx);
+
+ p_scb->num_recfg = 0;
+ /* store the new configuration in control block */
+ if (p_scb->p_cap == NULL)
+ p_scb->p_cap = (tAVDT_CFG*)osi_malloc(sizeof(tAVDT_CFG));
+ p_cfg = p_scb->p_cap;
+
+ alarm_cancel(p_scb->avrc_ct_timer);
+
+ memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG));
+ p_cfg->num_protect = p_rcfg->num_protect;
+ memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE);
+ memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect);
+ p_scb->rcfg_idx = p_rcfg->sep_info_idx;
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+
+ // If the requested SEP index is same as the current one, then we
+ // can Suspend->Reconfigure->Start.
+ // Otherwise, we have to Close->Configure->Open->Start or
+ // Close->Configure->Open for streams that are / are not started.
+ if ((p_scb->rcfg_idx == p_scb->sep_info_idx) && p_rcfg->suspend &&
+ p_scb->recfg_sup && p_scb->suspend_sup) {
+ if (p_scb->started) {
+ // Suspend->Reconfigure->Start
+ stop.flush = false;
+ stop.suspend = true;
+ stop.reconfig_stop = false;
+ bta_av_str_stopped(p_scb, (tBTA_AV_DATA*)&stop);
+ } else {
+ // Reconfigure
+ APPL_TRACE_DEBUG("%s: reconfig", __func__);
+ AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ }
+ } else {
+ // Close the stream first, and then Configure it
+ APPL_TRACE_DEBUG("%s: Close/Open started: %d state: %d num_protect: %d",
+ __func__, p_scb->started, p_scb->state,
+ p_cfg->num_protect);
+ if (p_scb->started) {
+ // Close->Configure->Open->Start
+ if ((p_scb->rcfg_idx != p_scb->sep_info_idx) && p_scb->recfg_sup) {
+ // Make sure we trigger STOP_EVT when taking the longer road to
+ // reconfiguration, otherwise we don't call Start.
+ stop.flush = false;
+ stop.suspend = false;
+ stop.reconfig_stop = true;
+ bta_av_str_stopped(p_scb, (tBTA_AV_DATA*)&stop);
+ } else {
+ bta_av_str_stopped(p_scb, NULL);
+ }
+ p_scb->started = false;
+ } else {
+ // Close->Configure->Open
+ bta_av_str_stopped(p_scb, NULL);
+ }
+ // Drop the buffers queued in L2CAP
+ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+ AVDT_CloseReq(p_scb->avdt_handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_data_path
+ *
+ * Description Handle stream data path.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_data_path(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ BT_HDR* p_buf = NULL;
+ uint32_t timestamp;
+ bool new_buf = false;
+ uint8_t m_pt = 0x60;
+ tAVDT_DATA_OPT_MASK opt;
+
+ if (p_scb->cong) return;
+
+ if (p_scb->current_codec->useRtpHeaderMarkerBit()) {
+ m_pt |= AVDT_MARKER_SET;
+ }
+
+ // Always get the current number of bufs que'd up
+ p_scb->l2c_bufs =
+ (uint8_t)L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET);
+
+ if (!list_is_empty(p_scb->a2dp_list)) {
+ p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+ list_remove(p_scb->a2dp_list, p_buf);
+ /* use q_info.a2dp data, read the timestamp */
+ timestamp = *(uint32_t*)(p_buf + 1);
+ } else {
+ new_buf = true;
+ /* A2DP_list empty, call co_data, dup data to other channels */
+ p_buf = (BT_HDR*)p_scb->p_cos->data(p_scb->cfg.codec_info, &timestamp);
+
+ if (p_buf) {
+ /* use the offset area for the time stamp */
+ *(uint32_t*)(p_buf + 1) = timestamp;
+
+ /* dup the data to other channels */
+ bta_av_dup_audio_buf(p_scb, p_buf);
+ }
+ }
+
+ if (p_buf) {
+ if (p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) {
+ /* There's a buffer, just queue it to L2CAP.
+ * There's no need to increment it here, it is always read from
+ * L2CAP (see above).
+ */
+
+ /* opt is a bit mask, it could have several options set */
+ opt = AVDT_DATA_OPT_NONE;
+ if (p_scb->no_rtp_hdr) {
+ opt |= AVDT_DATA_OPT_NO_RTP;
+ }
+
+ //
+ // Fragment the payload if larger than the MTU.
+ // NOTE: The fragmentation is RTP-compatibie.
+ //
+ size_t extra_fragments_n = 0;
+ if (p_buf->len > 0) {
+ extra_fragments_n = (p_buf->len / p_scb->stream_mtu) +
+ ((p_buf->len % p_scb->stream_mtu) ? 1 : 0) - 1;
+ }
+ std::vector<BT_HDR*> extra_fragments;
+ extra_fragments.reserve(extra_fragments_n);
+
+ uint8_t* data_begin = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint8_t* data_end = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+ while (extra_fragments_n-- > 0) {
+ data_begin += p_scb->stream_mtu;
+ size_t fragment_len = data_end - data_begin;
+ if (fragment_len > p_scb->stream_mtu) fragment_len = p_scb->stream_mtu;
+
+ BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ p_buf2->offset = p_buf->offset;
+ p_buf2->len = 0;
+ p_buf2->layer_specific = 0;
+ uint8_t* packet2 =
+ (uint8_t*)(p_buf2 + 1) + p_buf2->offset + p_buf2->len;
+ memcpy(packet2, data_begin, fragment_len);
+ p_buf2->len += fragment_len;
+ extra_fragments.push_back(p_buf2);
+ p_buf->len -= fragment_len;
+ }
+
+ if (!extra_fragments.empty()) {
+ // Reset the RTP Marker bit for all fragments except the last one
+ m_pt &= ~AVDT_MARKER_SET;
+ }
+ AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt);
+ for (size_t i = 0; i < extra_fragments.size(); i++) {
+ if (i + 1 == extra_fragments.size()) {
+ // Set the RTP Marker bit for the last fragment
+ m_pt |= AVDT_MARKER_SET;
+ }
+ BT_HDR* p_buf2 = extra_fragments[i];
+ AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf2, timestamp, m_pt, opt);
+ }
+ p_scb->cong = true;
+ } else {
+ /* there's a buffer, but L2CAP does not seem to be moving data */
+ if (new_buf) {
+ /* just got this buffer from co_data,
+ * put it in queue */
+ list_append(p_scb->a2dp_list, p_buf);
+ } else {
+ /* just dequeue it from the a2dp_list */
+ if (list_length(p_scb->a2dp_list) < 3) {
+ /* put it back to the queue */
+ list_prepend(p_scb->a2dp_list, p_buf);
+ } else {
+ /* too many buffers in a2dp_list, drop it. */
+ bta_av_co_audio_drop(p_scb->hndl);
+ osi_free(p_buf);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_start_ok
+ *
+ * Description Stream started.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_START start;
+ bool initiator = false;
+ bool suspend = false;
+ uint16_t flush_to;
+ uint8_t new_role = p_scb->role;
+ BT_HDR hdr;
+ uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+ uint8_t cur_role;
+
+ APPL_TRACE_DEBUG("%s: wait:x%x, role:x%x", __func__, p_scb->wait,
+ p_scb->role);
+
+ p_scb->started = true;
+ p_scb->current_codec = bta_av_get_a2dp_current_codec();
+
+ if (p_scb->sco_suspend) {
+ p_scb->sco_suspend = false;
+ }
+
+ if (new_role & BTA_AV_ROLE_START_INT) initiator = true;
+
+ /* for A2DP SINK we do not send get_caps */
+ if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) &&
+ (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) {
+ p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON);
+ APPL_TRACE_DEBUG("%s: local SEP type is SNK new wait is 0x%x", __func__,
+ p_scb->wait);
+ }
+ if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) {
+ /* role switch has failed */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED;
+ p_data = (tBTA_AV_DATA*)&hdr;
+ hdr.offset = BTA_AV_RS_FAIL;
+ }
+ APPL_TRACE_DEBUG("%s: wait:x%x", __func__, p_scb->wait);
+
+ if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) {
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ if (p_data->hdr.offset == BTA_AV_RS_FAIL) {
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.hndl = p_scb->hndl;
+ start.initiator = initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+ return;
+ }
+ }
+
+ if (!bta_av_link_role_ok(p_scb, A2DP_SET_ONE_BIT))
+ p_scb->q_tag = BTA_AV_Q_TAG_START;
+ else {
+ /* The wait flag may be set here while we are already master on the link */
+ /* this could happen if a role switch complete event occurred during
+ * reconfig */
+ /* if we are now master on the link, there is no need to wait for the role
+ * switch, */
+ /* complete anymore so we can clear the wait for role switch flag */
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ }
+
+ if (p_scb->wait &
+ (BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START)) {
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED;
+ p_scb->q_tag = BTA_AV_Q_TAG_START;
+ }
+
+ if (p_scb->wait) {
+ APPL_TRACE_ERROR("%s: wait:x%x q_tag:%d- not started", __func__,
+ p_scb->wait, p_scb->q_tag);
+ /* Clear first bit of p_scb->wait and not to return from this point else
+ * HAL layer gets blocked. And if there is delay in Get Capability response
+ * as
+ * first bit of p_scb->wait is cleared hence it ensures bt_av_start_ok is
+ * not called
+ * again from bta_av_save_caps.
+ */
+ p_scb->wait &= ~BTA_AV_WAIT_ACP_CAPS_ON;
+ }
+
+ /* tell role manager to check M/S role */
+ bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+
+ bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+
+ if (p_scb->media_type == AVDT_MEDIA_TYPE_AUDIO) {
+ /* in normal logic, conns should be bta_av_cb.audio_count - 1,
+ * However, bta_av_stream_chg is not called to increase
+ * bta_av_cb.audio_count yet.
+ * If the code were to be re-arranged for some reasons, this number may need
+ * to be changed
+ */
+ p_scb->co_started = bta_av_cb.audio_open_cnt;
+ flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1];
+ } else {
+ flush_to = p_bta_av_cfg->video_flush_to;
+ }
+ L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to);
+
+ /* clear the congestion flag */
+ p_scb->cong = false;
+
+ if (new_role & BTA_AV_ROLE_START_INT) {
+ new_role &= ~BTA_AV_ROLE_START_INT;
+ } else if ((new_role & BTA_AV_ROLE_AD_ACP) &&
+ (new_role & BTA_AV_ROLE_SUSPEND_OPT)) {
+ suspend = true;
+ }
+
+ if (!suspend) {
+ p_scb->q_tag = BTA_AV_Q_TAG_STREAM;
+ bta_av_stream_chg(p_scb, true);
+ }
+
+ {
+ /* If sink starts stream, disable sniff mode here */
+ if (!initiator) {
+ /* If souce is the master role, disable role switch during streaming.
+ * Otherwise allow role switch, if source is slave.
+ * Because it would not hurt source, if the peer device wants source to be
+ * master */
+ if ((BTM_GetRole(p_scb->peer_addr, &cur_role) == BTM_SUCCESS) &&
+ (cur_role == BTM_ROLE_MASTER)) {
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ }
+
+ bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ }
+
+ p_scb->role = new_role;
+ p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+
+ p_scb->no_rtp_hdr = false;
+ p_scb->p_cos->start(p_scb->hndl, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr);
+ p_scb->co_started = true;
+
+ APPL_TRACE_DEBUG("%s: suspending: %d, role:x%x, init %d", __func__, suspend,
+ p_scb->role, initiator);
+
+ start.suspending = suspend;
+ start.initiator = initiator;
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_SUCCESS;
+ start.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+
+ if (suspend) {
+ tBTA_AV_API_STOP stop;
+ p_scb->role |= BTA_AV_ROLE_SUSPEND;
+ p_scb->cong = true; /* do not allow the media data to go through */
+ /* do not duplicate the media packets to this channel */
+ p_scb->p_cos->stop(p_scb->hndl);
+ p_scb->co_started = false;
+ stop.flush = false;
+ stop.suspend = true;
+ stop.reconfig_stop = false;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA*)&stop);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_start_failed
+ *
+ * Description Stream start failed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_start_failed(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ if (p_scb->started == false && p_scb->co_started == false) {
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ notify_start_failed(p_scb);
+ }
+
+ bta_sys_set_policy(BTA_ID_AV,
+ (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH),
+ p_scb->peer_addr);
+ p_scb->sco_suspend = false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_str_closed
+ *
+ * Description Stream closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV data;
+ tBTA_AV_EVT event;
+ uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+ bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+ if (bta_av_cb.audio_open_cnt <= 1) {
+ /* last connection - restore the allow switch flag */
+ L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH);
+ }
+
+ if (p_scb->open_status) {
+ /* must be failure when opening the stream */
+ bdcpy(data.open.bd_addr, p_scb->peer_addr);
+ data.open.status = p_scb->open_status;
+ data.open.chnl = p_scb->chnl;
+ data.open.hndl = p_scb->hndl;
+
+ if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC)
+ data.open.sep = AVDT_TSEP_SNK;
+ else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)
+ data.open.sep = AVDT_TSEP_SRC;
+
+ event = BTA_AV_OPEN_EVT;
+ p_scb->open_status = BTA_AV_SUCCESS;
+
+ /** M: Bug fix for a2dp stream channel not close @{ */
+ if (bta_av_cb.audio_open_cnt >= 1)
+ bta_sys_conn_close(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ /** @} */
+
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_av_cleanup(p_scb, p_data);
+ (*bta_av_cb.p_cback)(event, &data);
+ } else {
+ /* do stop if we were started */
+ if (p_scb->co_started) {
+ bta_av_str_stopped(p_scb, NULL);
+ }
+
+ {
+ p_scb->p_cos->close(p_scb->hndl);
+ data.close.chnl = p_scb->chnl;
+ data.close.hndl = p_scb->hndl;
+ event = BTA_AV_CLOSE_EVT;
+
+ /** M: Bug fix for a2dp stream channel not close @{ */
+ if (bta_av_cb.audio_open_cnt >= 1)
+ bta_sys_conn_close(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ /** @} */
+
+ bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr);
+ bta_av_cleanup(p_scb, p_data);
+ (*bta_av_cb.p_cback)(event, &data);
+ }
+/** M: Bug fix for blacklist that peer only disconnect data channel without signaling channel @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if(interop_mtk_match_addr_name(INTEROP_MTK_CLOSE_AVDTP_SIG_CH, (const bt_bdaddr_t *)&p_scb->peer_addr))
+ {
+ APPL_TRACE_DEBUG("Close signaling channel while peer close data channel ");
+ AVDT_ULCloseReq(p_scb->peer_addr);
+ }
+#endif
+/** @} */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_clr_cong
+ *
+ * Description Clear stream congestion flag.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_clr_cong(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ if (p_scb->co_started) p_scb->cong = false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_suspend_cfm
+ *
+ * Description process the suspend response
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_SUSPEND suspend_rsp;
+ uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+ uint8_t policy = HCI_ENABLE_SNIFF_MODE;
+
+ APPL_TRACE_DEBUG("%s: audio_open_cnt = %d, err_code = %d", __func__,
+ bta_av_cb.audio_open_cnt, err_code);
+
+ if (p_scb->started == false) {
+ /* handle the condition where there is a collision of SUSPEND req from
+ *either side
+ ** Second SUSPEND req could be rejected. Do not treat this as a failure
+ */
+ APPL_TRACE_WARNING("%s: already suspended, ignore, err_code %d", __func__,
+ err_code);
+ return;
+ }
+
+ suspend_rsp.status = BTA_AV_SUCCESS;
+ if (err_code && (err_code != AVDT_ERR_BAD_STATE)) {
+ /* Disable suspend feature only with explicit rejection(not with timeout) */
+ /** M: Bug fix for should not disable suspend feature @{ */
+ if (err_code != AVDT_ERR_TIMEOUT && err_code != AVDT_ERR_CONNECT) {
+ /** @} */
+ p_scb->suspend_sup = false;
+ }
+ suspend_rsp.status = BTA_AV_FAIL;
+
+ APPL_TRACE_ERROR("%s: suspend failed, closing connection", __func__);
+
+ /* SUSPEND failed. Close connection. */
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+ } else {
+ /* only set started to false when suspend is successful */
+ p_scb->started = false;
+ }
+
+ if (p_scb->role & BTA_AV_ROLE_SUSPEND) {
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND;
+ p_scb->cong = false;
+ }
+
+ bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr);
+ if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 ||
+ bta_av_cb.audio_open_cnt == 1)
+ policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr);
+
+ /* in case that we received suspend_ind, we may need to call co_stop here */
+ if (p_scb->co_started) {
+ /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
+ vendor_get_interface()->send_command(
+ (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
+ if (p_scb->offload_start_pending) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+ }
+ p_scb->offload_start_pending = false;
+ */
+
+ bta_av_stream_chg(p_scb, false);
+
+ {
+ p_scb->co_started = false;
+ p_scb->p_cos->stop(p_scb->hndl);
+ }
+ L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO);
+ }
+
+ {
+ suspend_rsp.chnl = p_scb->chnl;
+ suspend_rsp.hndl = p_scb->hndl;
+ suspend_rsp.initiator = p_data->str_msg.initiator;
+ (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV*)&suspend_rsp);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_str_ok
+ *
+ * Description report reconfigure successful
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RECONFIG evt;
+
+ p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle);
+ APPL_TRACE_DEBUG("%s: l2c_cid: %d", __func__, p_scb->l2c_cid);
+
+ if (p_data != NULL) {
+ // p_data could be NULL if the reconfig was triggered by the local device
+ p_scb->stream_mtu =
+ p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE;
+ uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+ APPL_TRACE_DEBUG("%s: l2c_cid: 0x%x stream_mtu: %d mtu: %d", __func__,
+ p_scb->l2c_cid, p_scb->stream_mtu, mtu);
+ if (mtu == 0 || mtu > p_scb->stream_mtu) mtu = p_scb->stream_mtu;
+ p_scb->p_cos->update_mtu(p_scb->hndl, mtu);
+ }
+
+ /* rc listen */
+ bta_av_st_rc_timer(p_scb, NULL);
+ osi_free_and_reset((void**)&p_scb->p_cap);
+
+ /* No need to keep the role bits once reconfig is done. */
+ p_scb->role &= ~BTA_AV_ROLE_AD_ACP;
+ p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT;
+ p_scb->role &= ~BTA_AV_ROLE_START_INT;
+
+ {
+ /* reconfigure success */
+ evt.status = BTA_AV_SUCCESS;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_failed
+ *
+ * Description process reconfigure failed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RECONFIG evt;
+
+ APPL_TRACE_DEBUG("%s: num_recfg: %d, conn_lcb:0x%x", __func__,
+ p_scb->num_recfg, bta_av_cb.conn_lcb);
+ if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+ bta_av_cco_close(p_scb, p_data);
+ /* report failure */
+ evt.status = BTA_AV_FAIL_STREAM;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+ /* go to closing state */
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL);
+ } else {
+ /* open failed. try again */
+ p_scb->num_recfg++;
+ if (bta_av_cb.conn_lcb) {
+ AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]);
+ } else {
+ bta_av_connect_req(p_scb, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_connect
+ *
+ * Description stream closed. reconnect the stream
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ p_scb->cong = false;
+ p_scb->num_recfg++;
+ APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg);
+ if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+ /* let bta_av_rcfg_failed report fail */
+ bta_av_rcfg_failed(p_scb, NULL);
+ } else
+ AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+ bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_discntd
+ *
+ * Description AVDT disconnected. reconnect the stream
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_RECONFIG evt;
+
+ APPL_TRACE_DEBUG("%s: num_recfg: %d", __func__, p_scb->num_recfg);
+ p_scb->num_recfg++;
+ if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) {
+ /* report failure */
+ evt.status = BTA_AV_FAIL_STREAM;
+ evt.chnl = p_scb->chnl;
+ evt.hndl = p_scb->hndl;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+ /* report close event & go to init state */
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+ } else
+ AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask,
+ bta_av_dt_cback[p_scb->hdi]);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_suspend_cont
+ *
+ * Description received the suspend response.
+ * continue to reconfigure the stream
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+ tBTA_AV_RECONFIG evt;
+
+ p_scb->started = false;
+ p_scb->cong = false;
+ if (err_code) {
+ if (AVDT_ERR_CONNECT == err_code) {
+ /* report failure */
+ evt.status = BTA_AV_FAIL;
+ (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV*)&evt);
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL);
+ } else {
+ APPL_TRACE_ERROR("%s: suspend rejected, try close", __func__);
+ /* Disable suspend feature only with explicit rejection(not with timeout)
+ */
+ /** M: Bug fix for should not disable suspend feature @{ */
+ if (err_code != AVDT_ERR_TIMEOUT && err_code != AVDT_ERR_CONNECT) {
+ /** @} */
+ p_scb->suspend_sup = false;
+ }
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+
+ AVDT_CloseReq(p_scb->avdt_handle);
+ }
+ } else {
+ APPL_TRACE_DEBUG("%s: calling AVDT_ReconfigReq", __func__);
+ /* reconfig the stream */
+
+ AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap);
+ p_scb->p_cap->psc_mask = p_scb->cur_psc_mask;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_cfm
+ *
+ * Description if reconfigure is successful, report the event
+ * otherwise, close the stream.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ uint8_t err_code = p_data->str_msg.msg.hdr.err_code;
+
+ APPL_TRACE_DEBUG("%s: err_code = %d", __func__, err_code);
+
+ // Disable AVDTP RECONFIGURE for blacklisted devices
+ bool disable_avdtp_reconfigure = false;
+ {
+ char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
+ bt_bdaddr_t bd_addr;
+ for (int i = 0; i < 6; i++) bd_addr.address[i] = p_scb->peer_addr[i];
+ if (btif_storage_get_stored_remote_name(bd_addr, remote_name)) {
+ if (interop_match_name(INTEROP_DISABLE_AVDTP_RECONFIGURE, remote_name) ||
+ interop_match_addr(INTEROP_DISABLE_AVDTP_RECONFIGURE,
+ (const bt_bdaddr_t*)&p_scb->peer_addr)) {
+ APPL_TRACE_DEBUG(
+ "%s: disable AVDTP RECONFIGURE: interop matched "
+ "name %s address %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, remote_name, p_scb->peer_addr[0], p_scb->peer_addr[1],
+ p_scb->peer_addr[2], p_scb->peer_addr[3], p_scb->peer_addr[4],
+ p_scb->peer_addr[5]);
+ disable_avdtp_reconfigure = true;
+ }
+ }
+ }
+
+ if ((err_code != 0) || disable_avdtp_reconfigure) {
+ APPL_TRACE_ERROR("%s: reconfig rejected, try close", __func__);
+ /* Disable reconfiguration feature only with explicit rejection(not with
+ * timeout) */
+ if ((err_code != AVDT_ERR_TIMEOUT) || disable_avdtp_reconfigure) {
+ p_scb->recfg_sup = false;
+ }
+ /* started flag is false when reconfigure command is sent */
+ /* drop the buffers queued in L2CAP */
+ L2CA_FlushChannel(p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL);
+ AVDT_CloseReq(p_scb->avdt_handle);
+ } else {
+ /* update the codec info after rcfg cfm */
+ APPL_TRACE_DEBUG(
+ "%s: updating from codec %s to codec %s", __func__,
+ A2DP_CodecName(p_scb->cfg.codec_info),
+ A2DP_CodecName(p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info));
+ memcpy(p_scb->cfg.codec_info,
+ p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info, AVDT_CODEC_SIZE);
+ /* take the SSM back to OPEN state */
+ bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rcfg_open
+ *
+ * Description AVDT is connected. open the stream with the new
+ * configuration
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s: num_disc_snks = %d", __func__, p_scb->num_disc_snks);
+
+ if (p_scb->num_disc_snks == 0) {
+ /* Need to update call-out module so that it will be ready for discover */
+ p_scb->p_cos->stop(p_scb->hndl);
+
+ /* send avdtp discover request */
+ AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS,
+ bta_av_dt_cback[p_scb->hdi]);
+ } else {
+ memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE);
+ /* we may choose to use a different SEP at reconfig.
+ * adjust the sep_idx now */
+ bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC));
+
+ /* open the stream with the new config */
+ p_scb->sep_info_idx = p_scb->rcfg_idx;
+ AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr,
+ p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_security_rej
+ *
+ * Description Send an AVDTP security reject.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_security_rej(tBTA_AV_SCB* p_scb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE,
+ NULL, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_chk_2nd_start
+ *
+ * Description check if this is 2nd stream and if it needs to be started.
+ * This function needs to be kept very similar to
+ * bta_av_chk_start
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb,
+ UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_SCB* p_scbi;
+ int i;
+ bool new_started = false;
+
+ if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2)) {
+ /* more than one audio channel is connected */
+ if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT)) {
+ /* this channel does not need to be reconfigured.
+ * if there is other channel streaming, start the stream now */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scbi = bta_av_cb.p_scb[i];
+ if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+ if (!new_started) {
+ /* start the new stream */
+ new_started = true;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ /* may need to update the flush timeout of this already started stream
+ */
+ if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(
+ p_scbi->peer_addr,
+ p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_open_rc
+ *
+ * Description Send a message to main SM to open RC channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_START start;
+
+ APPL_TRACE_DEBUG("%s: use_rc: %d, wait: x%x role:x%x", __func__,
+ p_scb->use_rc, p_scb->wait, p_scb->role);
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) &&
+ (p_scb->q_tag == BTA_AV_Q_TAG_START)) {
+ /* waiting for role switch for some reason & the timer expires */
+ if (!bta_av_link_role_ok(p_scb, A2DP_SET_ONE_BIT)) {
+ APPL_TRACE_ERROR(
+ "%s: failed to start streaming for role management reasons!!",
+ __func__);
+ alarm_cancel(p_scb->avrc_ct_timer);
+ start.chnl = p_scb->chnl;
+ start.status = BTA_AV_FAIL_ROLE;
+ start.initiator = true;
+ start.hndl = p_scb->hndl;
+ p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS;
+ bta_av_cb.rs_idx = 0;
+ (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV*)&start);
+ } else {
+ /* role switch is done. continue to start streaming */
+ bta_av_cb.rs_idx = 0;
+ p_data->hdr.offset = BTA_AV_RS_OK;
+ bta_av_start_ok(p_scb, p_data);
+ }
+ return;
+ }
+
+ if (p_scb->use_rc == true || (p_scb->role & BTA_AV_ROLE_AD_ACP)) {
+ if (bta_av_cb.disc) {
+ /* AVRC discover db is in use */
+ if (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) {
+ /* AVRC channel is not connected. delay a little bit */
+ if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) {
+ bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RC_DISC_TIME_VAL,
+ BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+ } else {
+ p_scb->wait |= BTA_AV_WAIT_CHECK_RC;
+ }
+ }
+ } else {
+ /* use main SM for AVRC SDP activities */
+ bta_av_rc_disc((uint8_t)(p_scb->hdi + 1));
+ }
+ } else {
+ if (BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle) {
+ /* the open API said that this handle does not want a RC connection.
+ * disconnect it now */
+ AVRC_Close(p_scb->rc_handle);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_open_at_inc
+ *
+ * Description This function is called if API open is called by application
+ * while state-machine is at incoming state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ memcpy(&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN));
+
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+ p_scb->coll_mask |= BTA_AV_COLL_API_CALLED;
+
+ /* API open will be handled at timeout if SNK did not start signalling. */
+ /* API open will be ignored if SNK starts signalling. */
+ } else {
+ /* SNK did not start signalling, API was called N seconds timeout. */
+ /* We need to switch to INIT state and start opening connection. */
+ p_scb->coll_mask = 0;
+ bta_av_set_scb_sst_init(p_scb);
+
+ tBTA_AV_API_OPEN* p_buf =
+ (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+ memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+ p_scb->skip_sdp = true;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_offload_req
+ *
+ * Description This function is called if application requests offload of
+ * a2dp audio.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;
+
+ APPL_TRACE_DEBUG("%s: stream %s, audio channels open %d", __func__,
+ p_scb->started ? "STARTED" : "STOPPED",
+ bta_av_cb.audio_open_cnt);
+
+ /* Check if stream has already been started. */
+ /* Support offload if only one audio source stream is open. */
+ if (p_scb->started != true) {
+ status = BTA_AV_FAIL_STREAM;
+ }
+
+ /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
+ uint16_t mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu);
+ else if (bta_av_cb.audio_open_cnt == 1 &&
+ p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
+ p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ bt_vendor_op_a2dp_offload_t a2dp_offload_start;
+
+ if (L2CA_GetConnectionConfig(
+ p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
+ &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
+ APPL_TRACE_DEBUG("%s: l2cmtu %d lcid 0x%02X rcid 0x%02X lm_handle
+ 0x%02X",
+ __func__, a2dp_offload_start.acl_data_size,
+ p_scb->l2c_cid, a2dp_offload_start.remote_cid,
+ a2dp_offload_start.lm_handle);
+
+ a2dp_offload_start.bta_av_handle = p_scb->hndl;
+ a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
+ a2dp_offload_start.stream_mtu =
+ (mtu < p_scb->stream_mtu) ? mtu : p_scb->stream_mtu;
+ a2dp_offload_start.local_cid = p_scb->l2c_cid;
+ a2dp_offload_start.is_flushable = true;
+ a2dp_offload_start.stream_source =
+ ((uint32_t)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
+
+ memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
+ sizeof(a2dp_offload_start.codec_info));
+
+ if (!vendor_get_interface()->send_command(
+ (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_START,
+ &a2dp_offload_start)) {
+ status = BTA_AV_SUCCESS;
+ p_scb->offload_start_pending = true;
+ }
+ }
+ }
+ */
+ if (status != BTA_AV_SUCCESS)
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_offload_rsp
+ *
+ * Description This function is called when the vendor lib responds to
+ * BT_VND_OP_A2DP_OFFLOAD_START.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_STATUS status = p_data->api_status_rsp.status;
+
+ APPL_TRACE_DEBUG("%s: stream %s status %s", __func__,
+ p_scb->started ? "STARTED" : "STOPPED",
+ status ? "FAIL" : "SUCCESS");
+
+ /* Check if stream has already been started. */
+ if (status == BTA_AV_SUCCESS && p_scb->started != true) {
+ status = BTA_AV_FAIL_STREAM;
+ }
+
+ p_scb->offload_start_pending = false;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, (tBTA_AV*)&status);
+}
diff --git a/mtkbt/code/bt/bta/av/bta_av_act.cc b/mtkbt/code/bt/bta/av/bta_av_act.cc
new file mode 100755
index 0000000..798623f
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_act.cc
@@ -0,0 +1,2347 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for advanced audio/video main state
+ * machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_av"
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "avdt_api.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "l2c_api.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "utl.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/* the timeout to wait for open req after setconfig for incoming connections */
+#ifndef BTA_AV_SIGNALLING_TIMEOUT_MS
+#define BTA_AV_SIGNALLING_TIMEOUT_MS (8 * 1000) /* 8 seconds */
+#endif
+
+/* Time to wait for signalling from SNK when it is initiated from SNK. */
+/* If not, we will start signalling from SRC. */
+#ifndef BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS
+#define BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#endif
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+/** M: Bug fix for update avrcp version @{ */
+#ifndef AVRCP_VERSION_PROPERTY
+#define AVRCP_VERSION_PROPERTY "persist.bluetooth.avrcpversion"
+#endif
+
+#ifndef AVRCP_1_6_STRING
+#define AVRCP_1_6_STRING "avrcp16"
+#endif
+
+#ifndef AVRCP_1_5_STRING
+#define AVRCP_1_5_STRING "avrcp15"
+#endif
+
+#ifndef AVRCP_1_4_STRING
+#define AVRCP_1_4_STRING "avrcp14"
+#endif
+
+static bool get_peer_rc_version = false;
+/** @} */
+static void bta_av_accept_signalling_timer_cback(void* data);
+
+#ifndef AVRC_MIN_META_CMD_LEN
+#define AVRC_MIN_META_CMD_LEN 20
+#endif
+
+/** M: Bug fix for peer device not setup browsing channel @{ */
+#define BTA_AV_BROWSING_TIMEOUT_MS (2 * 1000)
+static alarm_t* av_open_browsing_timer = NULL;
+static void bta_av_open_browsing_timer_timeout(UNUSED_ATTR void* data);
+/** @} */
+
+/*******************************************************************************
+ *
+ * Function bta_av_get_rcb_by_shdl
+ *
+ * Description find the RCB associated with the given SCB handle.
+ *
+ * Returns tBTA_AV_RCB
+ *
+ ******************************************************************************/
+tBTA_AV_RCB* bta_av_get_rcb_by_shdl(uint8_t shdl) {
+ tBTA_AV_RCB* p_rcb = NULL;
+ int i;
+
+ for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+ if (bta_av_cb.rcb[i].shdl == shdl &&
+ bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE) {
+ p_rcb = &bta_av_cb.rcb[i];
+ break;
+ }
+ }
+ return p_rcb;
+}
+#define BTA_AV_STS_NO_RSP 0xFF /* a number not used by tAVRC_STS */
+
+/*******************************************************************************
+ *
+ * Function bta_av_del_rc
+ *
+ * Description delete the given AVRC handle.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_del_rc(tBTA_AV_RCB* p_rcb) {
+ tBTA_AV_SCB* p_scb;
+ uint8_t rc_handle; /* connected AVRCP handle */
+
+ p_scb = NULL;
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+ if (p_rcb->shdl) {
+ /* Validate array index*/
+ if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ }
+ if (p_scb) {
+ APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d",
+ p_rcb->shdl, p_scb->rc_handle, p_rcb->handle);
+ if (p_scb->rc_handle == p_rcb->handle)
+ p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ /* just in case the RC timer is active
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl ==
+ BTA_AV_CHNL_AUDIO) */
+ alarm_cancel(p_scb->avrc_ct_timer);
+ }
+ }
+
+ APPL_TRACE_EVENT(
+ "bta_av_del_rc handle: %d status=0x%x, rc_acp_handle:%d, idx:%d",
+ p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle,
+ bta_av_cb.rc_acp_idx);
+ rc_handle = p_rcb->handle;
+ if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) ||
+ ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
+ p_rcb->status = 0;
+ p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+ p_rcb->shdl = 0;
+ p_rcb->lidx = 0;
+ }
+ /* else ACP && connected. do not clear the handle yet */
+ AVRC_Close(rc_handle);
+ if (rc_handle == bta_av_cb.rc_acp_handle)
+ bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+ APPL_TRACE_EVENT(
+ "end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d",
+ p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_close_all_rc
+ *
+ * Description close the all AVRC handle.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_close_all_rc(tBTA_AV_CB* p_cb) {
+ int i;
+
+ for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+ if ((p_cb->disabling == true) || (bta_av_cb.rcb[i].shdl != 0))
+ bta_av_del_rc(&bta_av_cb.rcb[i]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_del_sdp_rec
+ *
+ * Description delete the given SDP record handle.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_del_sdp_rec(uint32_t* p_sdp_handle) {
+ if (*p_sdp_handle != 0) {
+ SDP_DeleteRecord(*p_sdp_handle);
+ *p_sdp_handle = 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_avrc_sdp_cback
+ *
+ * Description AVRCP service discovery callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_avrc_sdp_cback(UNUSED_ATTR uint16_t status) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_ctrl_cback
+ *
+ * Description AVRCP control callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_rc_ctrl_cback(uint8_t handle, uint8_t event,
+ UNUSED_ATTR uint16_t result,
+ BD_ADDR peer_addr) {
+ uint16_t msg_event = 0;
+
+ APPL_TRACE_EVENT("%s handle: %d event=0x%x", __func__, handle, event);
+ if (event == AVRC_OPEN_IND_EVT) {
+ /* save handle of opened connection
+ bta_av_cb.rc_handle = handle;*/
+
+ msg_event = BTA_AV_AVRC_OPEN_EVT;
+ } else if (event == AVRC_CLOSE_IND_EVT) {
+ msg_event = BTA_AV_AVRC_CLOSE_EVT;
+ } else if (event == AVRC_BROWSE_OPEN_IND_EVT) {
+ msg_event = BTA_AV_AVRC_BROWSE_OPEN_EVT;
+ } else if (event == AVRC_BROWSE_CLOSE_IND_EVT) {
+ msg_event = BTA_AV_AVRC_BROWSE_CLOSE_EVT;
+ }
+
+ if (msg_event) {
+ tBTA_AV_RC_CONN_CHG* p_msg =
+ (tBTA_AV_RC_CONN_CHG*)osi_malloc(sizeof(tBTA_AV_RC_CONN_CHG));
+ p_msg->hdr.event = msg_event;
+ p_msg->handle = handle;
+ if (peer_addr) bdcpy(p_msg->peer_addr, peer_addr);
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_msg_cback
+ *
+ * Description AVRCP message callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_rc_msg_cback(uint8_t handle, uint8_t label, uint8_t opcode,
+ tAVRC_MSG* p_msg) {
+ uint8_t* p_data_src = NULL;
+ uint16_t data_len = 0;
+
+ APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode);
+
+ /* Copy avrc packet into BTA message buffer (for sending to BTA state machine)
+ */
+
+ /* Get size of payload data (for vendor and passthrough messages only; for
+ * browsing
+ * messages, use zero-copy) */
+ if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) {
+ p_data_src = p_msg->vendor.p_vendor_data;
+ data_len = (uint16_t)p_msg->vendor.vendor_len;
+ } else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) {
+ p_data_src = p_msg->pass.p_pass_data;
+ data_len = (uint16_t)p_msg->pass.pass_len;
+ }
+
+ /* Create a copy of the message */
+ tBTA_AV_RC_MSG* p_buf =
+ (tBTA_AV_RC_MSG*)osi_malloc(sizeof(tBTA_AV_RC_MSG) + data_len);
+
+ p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT;
+ p_buf->handle = handle;
+ p_buf->label = label;
+ p_buf->opcode = opcode;
+ memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG));
+ /* Copy the data payload, and set the pointer to it */
+ if (p_data_src != NULL) {
+ uint8_t* p_data_dst = (uint8_t*)(p_buf + 1);
+ memcpy(p_data_dst, p_data_src, data_len);
+
+ /* Update bta message buffer to point to payload data */
+ /* (Note AVRC_OP_BROWSING uses zero-copy: p_buf->msg.browse.p_browse_data
+ * already points to original avrc buffer) */
+ if (opcode == AVRC_OP_VENDOR)
+ p_buf->msg.vendor.p_vendor_data = p_data_dst;
+ else if (opcode == AVRC_OP_PASS_THRU)
+ p_buf->msg.pass.p_pass_data = p_data_dst;
+ }
+
+ if (opcode == AVRC_OP_BROWSE) {
+ /* set p_pkt to NULL, so avrc would not free the buffer */
+ p_msg->browse.p_browse_pkt = NULL;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_create
+ *
+ * Description alloc RCB and call AVRC_Open
+ *
+ * Returns the created rc handle
+ *
+ ******************************************************************************/
+uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
+ uint8_t lidx) {
+ tAVRC_CONN_CB ccb;
+ BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any;
+ uint8_t status = BTA_AV_RC_ROLE_ACP;
+ tBTA_AV_SCB* p_scb = p_cb->p_scb[shdl - 1];
+ int i;
+ uint8_t rc_handle;
+ tBTA_AV_RCB* p_rcb;
+
+ if (role == AVCT_INT) {
+ bda = p_scb->peer_addr;
+ status = BTA_AV_RC_ROLE_INT;
+ } else {
+ p_rcb = bta_av_get_rcb_by_shdl(shdl);
+ if (p_rcb != NULL) {
+ APPL_TRACE_ERROR("bta_av_rc_create ACP handle exist for shdl:%d", shdl);
+ return p_rcb->handle;
+ }
+ }
+
+ ccb.p_ctrl_cback = bta_av_rc_ctrl_cback;
+ ccb.p_msg_cback = bta_av_rc_msg_cback;
+ ccb.company_id = p_bta_av_cfg->company_id;
+ ccb.conn = role;
+ /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL
+ */
+ ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT |
+ BTA_AV_FEAT_METADATA | AVRC_CT_PASSIVE);
+
+ if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS)
+ return BTA_AV_RC_HANDLE_NONE;
+
+ i = rc_handle;
+ p_rcb = &p_cb->rcb[i];
+
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+ APPL_TRACE_ERROR("bta_av_rc_create found duplicated handle:%d", rc_handle);
+ }
+
+ p_rcb->handle = rc_handle;
+ p_rcb->status = status;
+ p_rcb->shdl = shdl;
+ p_rcb->lidx = lidx;
+ p_rcb->peer_features = 0;
+ if (lidx == (BTA_AV_NUM_LINKS + 1)) {
+ /* this LIDX is reserved for the AVRCP ACP connection */
+ p_cb->rc_acp_handle = p_rcb->handle;
+ p_cb->rc_acp_idx = (i + 1);
+ APPL_TRACE_DEBUG("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle,
+ p_cb->rc_acp_idx);
+ }
+ APPL_TRACE_DEBUG(
+ "create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", i,
+ role, shdl, p_rcb->handle, lidx, p_rcb->status);
+
+ return rc_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_valid_group_navi_msg
+ *
+ * Description Check if it is Group Navigation Msg for Metadata
+ *
+ * Returns BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL.
+ *
+ ******************************************************************************/
+static tBTA_AV_CODE bta_av_group_navi_supported(uint8_t len, uint8_t* p_data,
+ bool is_inquiry) {
+ tBTA_AV_CODE ret = BTA_AV_RSP_NOT_IMPL;
+ uint8_t* p_ptr = p_data;
+ uint16_t u16;
+ uint32_t u32;
+
+ if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN) {
+ BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr);
+ BE_STREAM_TO_UINT16(u16, p_ptr);
+
+ if (u32 == AVRC_CO_METADATA) {
+ if (is_inquiry) {
+ if (u16 <= AVRC_PDU_PREV_GROUP) ret = BTA_AV_RSP_IMPL_STBL;
+ } else {
+ if (u16 <= AVRC_PDU_PREV_GROUP)
+ ret = BTA_AV_RSP_ACCEPT;
+ else
+ ret = BTA_AV_RSP_REJ;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_op_supported
+ *
+ * Description Check if remote control operation is supported.
+ *
+ * Returns BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not.
+ *
+ ******************************************************************************/
+static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, bool is_inquiry) {
+ tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL;
+
+ if (p_bta_av_rc_id) {
+ if (is_inquiry) {
+ if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+ ret_code = BTA_AV_RSP_IMPL_STBL;
+ }
+ } else {
+ if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+ ret_code = BTA_AV_RSP_ACCEPT;
+ } else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) &&
+ p_bta_av_rc_id_ac) {
+ if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) {
+ ret_code = BTA_AV_RSP_INTERIM;
+ }
+ }
+ }
+ }
+ return ret_code;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_find_lcb
+ *
+ * Description Given BD_addr, find the associated LCB.
+ *
+ * Returns NULL, if not found.
+ *
+ ******************************************************************************/
+tBTA_AV_LCB* bta_av_find_lcb(BD_ADDR addr, uint8_t op) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ int xx;
+ uint8_t mask;
+ tBTA_AV_LCB* p_lcb = NULL;
+
+ for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+ mask = 1 << xx; /* the used mask for this lcb */
+ if ((mask & p_cb->conn_lcb) && 0 == (bdcmp(p_cb->lcb[xx].addr, addr))) {
+ p_lcb = &p_cb->lcb[xx];
+ if (op == BTA_AV_LCB_FREE) {
+ p_cb->conn_lcb &= ~mask; /* clear the connect mask */
+ APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+ }
+ break;
+ }
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_opened
+ *
+ * Description Set AVRCP state to opened.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_SCB* p_scb;
+ int i;
+ uint8_t shdl = 0;
+ tBTA_AV_LCB* p_lcb;
+ tBTA_AV_RCB* p_rcb;
+ uint8_t tmp;
+ uint8_t disc = 0;
+
+ /* find the SCB & stop the timer */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scb = p_cb->p_scb[i];
+ if (p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0) {
+ p_scb->rc_handle = p_data->rc_conn_chg.handle;
+ APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1,
+ p_scb->rc_handle);
+ shdl = i + 1;
+ LOG_INFO(LOG_TAG, "%s allow incoming AVRCP connections:%d", __func__,
+ p_scb->use_rc);
+ alarm_cancel(p_scb->avrc_ct_timer);
+ disc = p_scb->hndl;
+ break;
+ }
+ }
+
+ i = p_data->rc_conn_chg.handle;
+ if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) {
+ APPL_TRACE_ERROR("not a valid handle:%d any more", i);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s local features %d peer features %d", __func__,
+ p_cb->features, p_cb->rcb[i].peer_features);
+
+ /* listen to browsing channel when the connection is open,
+ * if peer initiated AVRCP connection and local device supports browsing
+ * channel */
+ AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_ACP);
+
+ if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0) {
+ /* rc is opened on the RC only ACP channel, but is for a specific
+ * SCB -> need to switch RCBs */
+ p_rcb = bta_av_get_rcb_by_shdl(shdl);
+ if (p_rcb) {
+ p_rcb->shdl = p_cb->rcb[i].shdl;
+ tmp = p_rcb->lidx;
+ p_rcb->lidx = p_cb->rcb[i].lidx;
+ p_cb->rcb[i].lidx = tmp;
+ p_cb->rc_acp_handle = p_rcb->handle;
+ p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1;
+ APPL_TRACE_DEBUG("switching RCB rc_acp_handle:%d idx:%d",
+ p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ }
+ }
+
+ p_cb->rcb[i].shdl = shdl;
+ rc_open.rc_handle = i;
+ APPL_TRACE_ERROR("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d", i, shdl,
+ p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx);
+ p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK;
+
+ if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx) {
+ /* no associated SCB -> connected to an RC only device
+ * update the index to the extra LCB */
+ p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr);
+ APPL_TRACE_DEBUG("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_lcb->addr[0], p_lcb->addr[1], p_lcb->addr[2],
+ p_lcb->addr[3], p_lcb->addr[4], p_lcb->addr[5]);
+ p_lcb->lidx = BTA_AV_NUM_LINKS + 1;
+ p_cb->rcb[i].lidx = p_lcb->lidx;
+ p_lcb->conn_msk = 1;
+ APPL_TRACE_ERROR("rcb[%d].lidx=%d, lcb.conn_msk=x%x", i, p_cb->rcb[i].lidx,
+ p_lcb->conn_msk);
+ disc = p_data->rc_conn_chg.handle | BTA_AV_CHNL_MSK;
+ }
+
+ bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr);
+ rc_open.peer_features = p_cb->rcb[i].peer_features;
+ rc_open.status = BTA_AV_SUCCESS;
+ APPL_TRACE_DEBUG("%s local features:x%x peer_features:x%x", __func__,
+ p_cb->features, rc_open.peer_features);
+ if (rc_open.peer_features == 0) {
+ /* we have not done SDP on peer RC capabilities.
+ * peer must have initiated the RC connection */
+ if (p_cb->features & BTA_AV_FEAT_RCCT)
+ rc_open.peer_features |= BTA_AV_FEAT_RCTG;
+ if (p_cb->features & BTA_AV_FEAT_RCTG)
+ rc_open.peer_features |= BTA_AV_FEAT_RCCT;
+
+ bta_av_rc_disc(disc);
+ }
+ (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)&rc_open);
+
+ /* if local initiated AVRCP connection and both peer and locals device support
+ * browsing channel, open the browsing channel now
+ * TODO (sanketa): Some TG would not broadcast browse feature hence check
+ * inter-op. */
+ if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
+ (rc_open.peer_features & BTA_AV_FEAT_BROWSE) &&
+ ((p_cb->rcb[i].status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT)) {
+ APPL_TRACE_DEBUG("%s opening AVRC Browse channel", __func__);
+ AVRC_OpenBrowse(p_data->rc_conn_chg.handle, AVCT_INT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_remote_cmd
+ *
+ * Description Send an AVRCP remote control command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_remote_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RCB* p_rcb;
+ if (p_cb->features & BTA_AV_FEAT_RCCT) {
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ if (p_rcb->status & BTA_AV_RC_CONN_MASK) {
+ AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label,
+ &p_data->api_remote_cmd.msg);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_vendor_cmd
+ *
+ * Description Send an AVRCP vendor specific command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_vendor_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RCB* p_rcb;
+ if ((p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) ==
+ (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) {
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label,
+ &p_data->api_vendor.msg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_vendor_rsp
+ *
+ * Description Send an AVRCP vendor specific response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_vendor_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RCB* p_rcb;
+ if ((p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) ==
+ (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) {
+ if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label,
+ &p_data->api_vendor.msg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_meta_rsp
+ *
+ * Description Send an AVRCP metadata/advanced control command/response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_meta_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_RCB* p_rcb;
+ bool do_free = true;
+
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+ (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)) {
+ if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) ||
+ (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT))) {
+ p_rcb = &p_cb->rcb[p_data->hdr.layer_specific];
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+ AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label,
+ p_data->api_meta_rsp.rsp_code, p_data->api_meta_rsp.p_pkt);
+ do_free = false;
+ }
+ }
+ }
+
+ if (do_free) osi_free_and_reset((void**)&p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_free_rsp
+ *
+ * Description free an AVRCP metadata command buffer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_free_rsp(UNUSED_ATTR tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ osi_free_and_reset((void**)&p_data->api_meta_rsp.p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_free_browse_msg
+ *
+ * Description free an AVRCP browse message buffer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_free_browse_msg(UNUSED_ATTR tBTA_AV_CB* p_cb,
+ tBTA_AV_DATA* p_data) {
+ if (p_data->rc_msg.opcode == AVRC_OP_BROWSE) {
+ osi_free_and_reset((void**)&p_data->rc_msg.msg.browse.p_browse_pkt);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_chk_notif_evt_id
+ *
+ * Description make sure the requested player id is valid.
+ *
+ * Returns BTA_AV_STS_NO_RSP, if no error
+ *
+ ******************************************************************************/
+static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR* p_vendor) {
+ tAVRC_STS status = BTA_AV_STS_NO_RSP;
+ uint8_t xx;
+ uint16_t u16;
+ uint8_t* p = p_vendor->p_vendor_data + 2;
+
+ BE_STREAM_TO_UINT16(u16, p);
+ /* double check the fixed length */
+ if ((u16 != 5) || (p_vendor->vendor_len != 9)) {
+ status = AVRC_STS_INTERNAL_ERR;
+ } else {
+ /* make sure the player_id is valid */
+ for (xx = 0; xx < p_bta_av_cfg->num_evt_ids; xx++) {
+ if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) {
+ break;
+ }
+ }
+ if (xx == p_bta_av_cfg->num_evt_ids) {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_proc_meta_cmd
+ *
+ * Description Process an AVRCP metadata command from the peer.
+ *
+ * Returns true to respond immediately
+ *
+ ******************************************************************************/
+tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE* p_rc_rsp,
+ tBTA_AV_RC_MSG* p_msg, uint8_t* p_ctype) {
+ tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT;
+ uint8_t u8, pdu, *p;
+ uint16_t u16;
+ tAVRC_MSG_VENDOR* p_vendor = &p_msg->msg.vendor;
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ pdu = *(p_vendor->p_vendor_data);
+ p_rc_rsp->pdu = pdu;
+ *p_ctype = AVRC_RSP_REJ;
+
+ /* Check to ansure a valid minimum meta data length */
+ if ((AVRC_MIN_META_CMD_LEN + p_vendor->vendor_len) > AVRC_META_CMD_BUF_SIZE) {
+ /* reject it */
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
+ APPL_TRACE_ERROR("%s Invalid meta-command length: %d", __func__,
+ p_vendor->vendor_len);
+ return 0;
+ }
+
+ /* Metadata messages only use PANEL sub-unit type */
+ if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) {
+ APPL_TRACE_DEBUG("SUBUNIT must be PANEL");
+ /* reject it */
+ evt = 0;
+ p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+ p_vendor->vendor_len = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_PARAM;
+ } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype)) {
+ APPL_TRACE_DEBUG("Invalid pdu/ctype: 0x%x, %d", pdu, p_vendor->hdr.ctype);
+ /* reject invalid message without reporting to app */
+ evt = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+ } else {
+ switch (pdu) {
+ case AVRC_PDU_GET_CAPABILITIES:
+ /* process GetCapabilities command without reporting the event to app */
+ evt = 0;
+ u8 = *(p_vendor->p_vendor_data + 4);
+ p = p_vendor->p_vendor_data + 2;
+ p_rc_rsp->get_caps.capability_id = u8;
+ BE_STREAM_TO_UINT16(u16, p);
+ if ((u16 != 1) || (p_vendor->vendor_len != 5)) {
+ p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR;
+ } else {
+ p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR;
+ if (u8 == AVRC_CAP_COMPANY_ID) {
+ *p_ctype = AVRC_RSP_IMPL_STBL;
+ p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids;
+ memcpy(p_rc_rsp->get_caps.param.company_id,
+ p_bta_av_cfg->p_meta_co_ids,
+ (p_bta_av_cfg->num_co_ids << 2));
+ } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) {
+ *p_ctype = AVRC_RSP_IMPL_STBL;
+ p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids;
+ memcpy(p_rc_rsp->get_caps.param.event_id,
+ p_bta_av_cfg->p_meta_evt_ids, p_bta_av_cfg->num_evt_ids);
+ } else {
+ APPL_TRACE_DEBUG("Invalid capability ID: 0x%x", u8);
+ /* reject - unknown capability ID */
+ p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM;
+ }
+ }
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ /* make sure the event_id is implemented */
+ p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id(p_vendor);
+ if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) evt = 0;
+ break;
+ }
+ }
+#else
+ APPL_TRACE_DEBUG("AVRCP 1.3 Metadata not supporteed. Reject command.");
+ /* reject invalid message without reporting to app */
+ evt = 0;
+ p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD;
+#endif
+
+ return evt;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_msg
+ *
+ * Description Process an AVRCP message from the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ tBTA_AV_EVT evt = 0;
+ tBTA_AV av;
+ BT_HDR* p_pkt = NULL;
+ tAVRC_MSG_VENDOR* p_vendor = &p_data->rc_msg.msg.vendor;
+ bool is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+ p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ);
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ uint8_t ctype = 0;
+ tAVRC_RESPONSE rc_rsp;
+
+ rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
+#endif
+
+ if (NULL == p_data) {
+ APPL_TRACE_ERROR("Message from peer with no data in %s", __func__);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: opcode=%x, ctype=%x", __func__, p_data->rc_msg.opcode,
+ p_data->rc_msg.msg.hdr.ctype);
+
+ if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) {
+ /* if this is a pass thru command */
+ if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) ||
+ (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) ||
+ (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ)) {
+ /* check if operation is supported */
+ char avrcp_ct_support[PROPERTY_VALUE_MAX];
+ osi_property_get("bluetooth.pts.avrcp_ct.support", avrcp_ct_support,
+ "false");
+ if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if (p_cb->features & BTA_AV_FEAT_METADATA)
+ p_data->rc_msg.msg.hdr.ctype = bta_av_group_navi_supported(
+ p_data->rc_msg.msg.pass.pass_len,
+ p_data->rc_msg.msg.pass.p_pass_data, is_inquiry);
+#endif
+ } else if (((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_UP) ||
+ (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VOL_DOWN)) &&
+ !strcmp(avrcp_ct_support, "true")) {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_ACCEPT;
+ } else {
+ p_data->rc_msg.msg.hdr.ctype =
+ bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry);
+ }
+
+ APPL_TRACE_DEBUG("ctype %d", p_data->rc_msg.msg.hdr.ctype)
+
+ /* send response */
+ if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM)
+ AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+ &p_data->rc_msg.msg.pass);
+
+ /* set up for callback if supported */
+ if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT ||
+ p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM) {
+ evt = BTA_AV_REMOTE_CMD_EVT;
+ av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id;
+ av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state;
+ av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data;
+ av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len;
+ memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof(tAVRC_HDR));
+ av.remote_cmd.label = p_data->rc_msg.label;
+ }
+ }
+ /* else if this is a pass thru response */
+ /* id response type is not impl, we have to release label */
+ else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
+ /* set up for callback */
+ evt = BTA_AV_REMOTE_RSP_EVT;
+ av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id;
+ av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state;
+ av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype;
+ av.remote_rsp.label = p_data->rc_msg.label;
+
+ /* If this response is for vendor unique command */
+ if ((p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) &&
+ (p_data->rc_msg.msg.pass.pass_len > 0)) {
+ av.remote_rsp.p_data =
+ (uint8_t*)osi_malloc(p_data->rc_msg.msg.pass.pass_len);
+ APPL_TRACE_DEBUG("Vendor Unique data len = %d",
+ p_data->rc_msg.msg.pass.pass_len);
+ memcpy(av.remote_rsp.p_data, p_data->rc_msg.msg.pass.p_pass_data,
+ p_data->rc_msg.msg.pass.pass_len);
+ }
+ }
+ /* must be a bad ctype -> reject*/
+ else {
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+ AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+ &p_data->rc_msg.msg.pass);
+ }
+ }
+ /* else if this is a vendor specific command or response */
+ else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR) {
+ /* set up for callback */
+ av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype;
+ av.vendor_cmd.company_id = p_vendor->company_id;
+ av.vendor_cmd.label = p_data->rc_msg.label;
+ av.vendor_cmd.p_data = p_vendor->p_vendor_data;
+ av.vendor_cmd.len = p_vendor->vendor_len;
+
+ /* if configured to support vendor specific and it's a command */
+ if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+ (p_vendor->company_id == AVRC_CO_METADATA)) {
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ rc_rsp.rsp.status = BTA_AV_STS_NO_RSP;
+ evt = bta_av_proc_meta_cmd(&rc_rsp, &p_data->rc_msg, &ctype);
+ } else
+#endif
+ evt = BTA_AV_VENDOR_CMD_EVT;
+ }
+ /* else if configured to support vendor specific and it's a response */
+ else if ((p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_NOT_IMPL) {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if ((p_cb->features & BTA_AV_FEAT_METADATA) &&
+ (p_vendor->company_id == AVRC_CO_METADATA)) {
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ evt = BTA_AV_META_MSG_EVT;
+ } else
+#endif
+ evt = BTA_AV_VENDOR_RSP_EVT;
+
+ }
+ /* else if not configured to support vendor specific and it's a command */
+ else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) &&
+ p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) {
+ if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) {
+ /* reject it */
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ;
+ p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD;
+ } else
+ p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL;
+ AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label,
+ &p_data->rc_msg.msg.vendor);
+ }
+ } else if (p_data->rc_msg.opcode == AVRC_OP_BROWSE) {
+ /* set up for callback */
+ av.meta_msg.rc_handle = p_data->rc_msg.handle;
+ av.meta_msg.company_id = p_vendor->company_id;
+ av.meta_msg.code = p_data->rc_msg.msg.hdr.ctype;
+ av.meta_msg.label = p_data->rc_msg.label;
+ av.meta_msg.p_msg = &p_data->rc_msg.msg;
+ av.meta_msg.p_data = p_data->rc_msg.msg.browse.p_browse_data;
+ av.meta_msg.len = p_data->rc_msg.msg.browse.browse_len;
+ evt = BTA_AV_META_MSG_EVT;
+ }
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP) {
+ if (!p_pkt) {
+ rc_rsp.rsp.opcode = p_data->rc_msg.opcode;
+ AVRC_BldResponse(0, &rc_rsp, &p_pkt);
+ }
+ if (p_pkt)
+ AVRC_MsgReq(p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt);
+ }
+#endif
+
+ /* call callback */
+ if (evt != 0) {
+ av.remote_cmd.rc_handle = p_data->rc_msg.handle;
+ (*p_cb->p_cback)(evt, &av);
+ /* If browsing message, then free the browse message buffer */
+ bta_av_rc_free_browse_msg(p_cb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_close
+ *
+ * Description close the specified AVRC handle.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ uint16_t handle = p_data->hdr.layer_specific;
+ tBTA_AV_SCB* p_scb;
+ tBTA_AV_RCB* p_rcb;
+
+ if (handle < BTA_AV_NUM_RCB) {
+ p_rcb = &p_cb->rcb[handle];
+
+ APPL_TRACE_DEBUG("%s handle: %d, status=0x%x", __func__, p_rcb->handle,
+ p_rcb->status);
+ if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) {
+ if (p_rcb->shdl) {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ if (p_scb) {
+ /* just in case the RC timer is active
+ if (bta_av_cb.features & BTA_AV_FEAT_RCCT &&
+ p_scb->chnl == BTA_AV_CHNL_AUDIO) */
+ alarm_cancel(p_scb->avrc_ct_timer);
+
+ /** M: Bug fix for peer device not setup browsing channel @{ */
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+ /** @} */
+ }
+ }
+
+ AVRC_Close(p_rcb->handle);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_browse_close
+ *
+ * Description Empty placeholder.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data) {
+ APPL_TRACE_WARNING("%s empty placeholder does nothing!", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_get_shdl
+ *
+ * Returns The index to p_scb[]
+ *
+ ******************************************************************************/
+static uint8_t bta_av_get_shdl(tBTA_AV_SCB* p_scb) {
+ int i;
+ uint8_t shdl = 0;
+ /* find the SCB & stop the timer */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ if (p_scb == bta_av_cb.p_scb[i]) {
+ shdl = i + 1;
+ break;
+ }
+ }
+ return shdl;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_stream_chg
+ *
+ * Description audio streaming status changed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started) {
+ uint8_t started_msk;
+ int i;
+ uint8_t* p_streams;
+ bool no_streams = false;
+ tBTA_AV_SCB* p_scbi;
+
+ started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ APPL_TRACE_DEBUG("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x",
+ started, started_msk, p_scb->chnl);
+ if (BTA_AV_CHNL_AUDIO == p_scb->chnl)
+ p_streams = &bta_av_cb.audio_streams;
+ else
+ p_streams = &bta_av_cb.video_streams;
+
+ if (started) {
+ /* Let L2CAP know this channel is processed with high priority */
+ L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH);
+ (*p_streams) |= started_msk;
+ } else {
+ (*p_streams) &= ~started_msk;
+ }
+
+ if (!started) {
+ i = 0;
+ if (BTA_AV_CHNL_AUDIO == p_scb->chnl) {
+ if (bta_av_cb.video_streams == 0) no_streams = true;
+ } else {
+ no_streams = true;
+ if (bta_av_cb.audio_streams) {
+ for (; i < BTA_AV_NUM_STRS; i++) {
+ p_scbi = bta_av_cb.p_scb[i];
+ /* scb is used and started */
+ if (p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) &&
+ bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0) {
+ no_streams = false;
+ break;
+ }
+ }
+ }
+ }
+
+ APPL_TRACE_DEBUG("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x",
+ no_streams, i, bta_av_cb.audio_streams,
+ bta_av_cb.video_streams);
+ if (no_streams) {
+ /* Let L2CAP know this channel is processed with low priority */
+ L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_conn_chg
+ *
+ * Description connetion status changed.
+ * Open an AVRCP acceptor channel, if new conn.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_conn_chg(tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_SCB* p_scb = NULL;
+ tBTA_AV_SCB* p_scbi;
+ uint8_t mask;
+ uint8_t conn_msk;
+ uint8_t old_msk;
+ int i;
+ int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1;
+ tBTA_AV_LCB* p_lcb;
+ tBTA_AV_LCB* p_lcb_rc;
+ tBTA_AV_RCB *p_rcb, *p_rcb2;
+ bool chk_restore = false;
+
+ /* Validate array index*/
+ if (index < BTA_AV_NUM_STRS) {
+ p_scb = p_cb->p_scb[index];
+ }
+ mask = BTA_AV_HNDL_TO_MSK(index);
+ p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND);
+ conn_msk = 1 << (index + 1);
+ if (p_data->conn_chg.is_up) {
+ /* set the conned mask for this channel */
+ if (p_scb) {
+ if (p_lcb) {
+ p_lcb->conn_msk |= conn_msk;
+ for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+ if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) {
+ bta_av_cb.rcb[i].shdl = index + 1;
+ APPL_TRACE_DEBUG(
+ "conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+ bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+ bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+ break;
+ }
+ }
+ }
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ old_msk = p_cb->conn_audio;
+ p_cb->conn_audio |= mask;
+ } else {
+ old_msk = p_cb->conn_video;
+ p_cb->conn_video |= mask;
+ }
+
+ if ((old_msk & mask) == 0) {
+ /* increase the audio open count, if not set yet */
+ bta_av_cb.audio_open_cnt++;
+ }
+
+ APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle,
+ p_cb->rc_acp_idx);
+ /* check if the AVRCP ACP channel is already connected */
+ if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE &&
+ p_cb->rc_acp_idx) {
+ p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ APPL_TRACE_DEBUG(
+ "rc_acp is connected && conn_chg on same addr "
+ "p_lcb_rc->conn_msk:x%x",
+ p_lcb_rc->conn_msk);
+ /* check if the RC is connected to the scb addr */
+ APPL_TRACE_DEBUG("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_lcb_rc->addr[0], p_lcb_rc->addr[1],
+ p_lcb_rc->addr[2], p_lcb_rc->addr[3],
+ p_lcb_rc->addr[4], p_lcb_rc->addr[5]);
+ APPL_TRACE_DEBUG(
+ "conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1],
+ p_data->conn_chg.peer_addr[2], p_data->conn_chg.peer_addr[3],
+ p_data->conn_chg.peer_addr[4], p_data->conn_chg.peer_addr[5]);
+ if (p_lcb_rc->conn_msk &&
+ bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0) {
+ /* AVRCP is already connected.
+ * need to update the association betwen SCB and RCB */
+ p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */
+ p_lcb_rc->lidx = 0;
+ p_scb->rc_handle = p_cb->rc_acp_handle;
+ p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1];
+ p_rcb->shdl = bta_av_get_shdl(p_scb);
+ APPL_TRACE_DEBUG("update rc_acp shdl:%d/%d srch:%d", index + 1,
+ p_rcb->shdl, p_scb->rc_handle);
+
+ p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl);
+ if (p_rcb2) {
+ /* found the RCB that was created to associated with this SCB */
+ p_cb->rc_acp_handle = p_rcb2->handle;
+ p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1;
+ APPL_TRACE_DEBUG("new rc_acp_handle:%d, idx:%d",
+ p_cb->rc_acp_handle, p_cb->rc_acp_idx);
+ p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1);
+ APPL_TRACE_DEBUG("rc2 handle:%d lidx:%d/%d", p_rcb2->handle,
+ p_rcb2->lidx, p_cb->lcb[p_rcb2->lidx - 1].lidx);
+ }
+ p_rcb->lidx = p_lcb->lidx;
+ APPL_TRACE_DEBUG("rc handle:%d lidx:%d/%d", p_rcb->handle,
+ p_rcb->lidx, p_cb->lcb[p_rcb->lidx - 1].lidx);
+ }
+ }
+ }
+ } else {
+ if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
+ /* this channel is still marked as open. decrease the count */
+ bta_av_cb.audio_open_cnt--;
+ }
+
+ /* clear the conned mask for this channel */
+ p_cb->conn_audio &= ~mask;
+ p_cb->conn_video &= ~mask;
+ if (p_scb) {
+ /* the stream is closed.
+ * clear the peer address, so it would not mess up the AVRCP for the next
+ * round of operation */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ if (p_lcb) {
+ p_lcb->conn_msk &= ~conn_msk;
+ }
+ /* audio channel is down. make sure the INT channel is down */
+ /* just in case the RC timer is active
+ if (p_cb->features & BTA_AV_FEAT_RCCT) */
+ { alarm_cancel(p_scb->avrc_ct_timer); }
+ /* one audio channel goes down. check if we need to restore high
+ * priority */
+ chk_restore = true;
+ }
+ }
+
+ APPL_TRACE_DEBUG("bta_av_conn_chg shdl:%d", index + 1);
+ for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+ APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i,
+ bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status,
+ bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx);
+ if (bta_av_cb.rcb[i].shdl == index + 1) {
+ bta_av_del_rc(&bta_av_cb.rcb[i]);
+ /* since the connection is already down and info was removed, clean
+ * reference */
+ bta_av_cb.rcb[i].shdl = 0;
+ break;
+ }
+ }
+
+ if (p_cb->conn_audio == 0 && p_cb->conn_video == 0) {
+ /* if both channels are not connected,
+ * close all RC channels */
+ bta_av_close_all_rc(p_cb);
+ }
+
+ /* if the AVRCP is no longer listening, create the listening channel */
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE &&
+ bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ }
+
+ APPL_TRACE_DEBUG(
+ "bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d "
+ "audio_open_cnt:%d",
+ p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk,
+ chk_restore, p_cb->audio_open_cnt);
+
+ if (chk_restore) {
+ if (p_cb->audio_open_cnt == 1) {
+ /* one audio channel goes down and there's one audio channel remains open.
+ * restore the switch role in default link policy */
+ bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ /* allow role switch, if this is the last connection */
+ bta_av_restore_switch();
+ }
+ if (p_cb->audio_open_cnt) {
+ /* adjust flush timeout settings to longer period */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scbi = bta_av_cb.p_scb[i];
+ if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+ /* may need to update the flush timeout of this already started stream
+ */
+ if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(
+ p_scbi->peer_addr,
+ p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_disable
+ *
+ * Description disable AV.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_disable(tBTA_AV_CB* p_cb, UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ BT_HDR hdr;
+ uint16_t xx;
+
+ p_cb->disabling = true;
+
+ bta_av_close_all_rc(p_cb);
+
+/** M: Bug fix for Before av disable, Cancel the AVRCP service search procedure if it has been started. @{ */
+ if(p_cb->p_disc_db)
+ {
+ APPL_TRACE_EVENT("bta_av_disable: AVRC find service started, cancel it before disable");
+ (void)SDP_CancelServiceSearch (p_cb->p_disc_db);
+ osi_free_and_reset((void**)&p_cb->p_disc_db);
+ }
+ else
+/** @} */
+ osi_free_and_reset((void**)&p_cb->p_disc_db);
+
+ /* disable audio/video - de-register all channels,
+ * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ if (p_cb->p_scb[xx] != NULL) {
+ hdr.layer_specific = xx + 1;
+ bta_av_api_deregister((tBTA_AV_DATA*)&hdr);
+ }
+ }
+
+ alarm_free(p_cb->link_signalling_timer);
+ p_cb->link_signalling_timer = NULL;
+ alarm_free(p_cb->accept_signalling_timer);
+ p_cb->accept_signalling_timer = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_api_disconnect
+ *
+ * Description .
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_api_disconnect(tBTA_AV_DATA* p_data) {
+ AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback);
+ alarm_cancel(bta_av_cb.link_signalling_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sig_chg
+ *
+ * Description process AVDT signal channel up/down.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_sig_chg(tBTA_AV_DATA* p_data) {
+ uint16_t event = p_data->str_msg.hdr.layer_specific;
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ uint32_t xx;
+ uint8_t mask;
+ tBTA_AV_LCB* p_lcb = NULL;
+
+ APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event);
+ if (event == AVDT_CONNECT_IND_EVT) {
+ p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND);
+ if (!p_lcb) {
+ /* if the address does not have an LCB yet, alloc one */
+ for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+ mask = 1 << xx;
+ APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb);
+ /* look for a p_lcb with its p_scb registered */
+ if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL)) {
+
+ /** M: Bug fix for dual a2dp signal channel setup @{ */
+ //BTA_AV_INIT_SST is 0: no other connection exist for a2dp incoming
+ APPL_TRACE_DEBUG("state: %d", p_cb->p_scb[xx]->state);
+ if ((p_data->hdr.offset == AVDT_ACP) &&
+ (p_cb->p_scb[xx]->state != 0))
+ continue;
+ /** @} */
+
+ p_lcb = &p_cb->lcb[xx];
+ p_lcb->lidx = xx + 1;
+ bdcpy(p_lcb->addr, p_data->str_msg.bd_addr);
+ p_lcb->conn_msk = 0; /* clear the connect mask */
+ /* start listening when the signal channel is open */
+ if (p_cb->features & BTA_AV_FEAT_RCTG) {
+ bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx);
+ }
+ /* this entry is not used yet. */
+ p_cb->conn_lcb |= mask; /* mark it as used */
+ APPL_TRACE_DEBUG("start sig timer %d", p_data->hdr.offset);
+ if (p_data->hdr.offset == AVDT_ACP) {
+ APPL_TRACE_DEBUG("Incoming L2CAP acquired, set state as incoming",
+ NULL);
+ bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr);
+ p_cb->p_scb[xx]->use_rc =
+ true; /* allowing RC for incoming connection */
+ bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data);
+
+ /* The Pending Event should be sent as soon as the L2CAP signalling
+ * channel
+ * is set up, which is NOW. Earlier this was done only after
+ * BTA_AV_SIGNALLING_TIMEOUT_MS.
+ * The following function shall send the event and start the
+ * recurring timer
+ */
+ bta_av_signalling_timer(NULL);
+
+ APPL_TRACE_DEBUG("%s: Re-start timer for AVDTP service", __func__);
+ bta_sys_conn_open(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
+ p_cb->p_scb[xx]->peer_addr);
+ /* Possible collision : need to avoid outgoing processing while the
+ * timer is running */
+ p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR;
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ period_ms_t ms_t = BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS;
+ if (interop_mtk_match_addr_name(INTEROP_MTK_A2DP_CHANGE_ACCEPT_SIGNALLING_TMS, (const bt_bdaddr_t *)&p_cb->p_scb[xx]->peer_addr))
+ {
+ ms_t = 6000;
+ }
+ alarm_set_on_queue(p_cb->accept_signalling_timer,
+ ms_t,
+ bta_av_accept_signalling_timer_cback,
+ UINT_TO_PTR(xx), btu_bta_alarm_queue);
+#else
+ alarm_set_on_queue(p_cb->accept_signalling_timer,
+ BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+ bta_av_accept_signalling_timer_cback,
+ UINT_TO_PTR(xx), btu_bta_alarm_queue);
+#endif
+ }
+ break;
+ }
+ }
+
+ /* check if we found something */
+ if (xx == BTA_AV_NUM_LINKS) {
+ /* We do not have scb for this avdt connection. */
+ /* Silently close the connection. */
+ APPL_TRACE_ERROR("av scb not available for avdt connection");
+ AVDT_DisconnectReq(p_data->str_msg.bd_addr, NULL);
+ return;
+ }
+ }
+ }
+#if (BTA_AR_INCLUDED == TRUE)
+ else if (event == BTA_AR_AVDT_CONN_EVT) {
+ alarm_cancel(bta_av_cb.link_signalling_timer);
+ }
+#endif
+ else {
+ /* disconnected. */
+ APPL_TRACE_DEBUG("%s: bta_av_cb.conn_lcb is %d", __func__,
+ bta_av_cb.conn_lcb);
+
+ p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE);
+ if (p_lcb && (p_lcb->conn_msk || bta_av_cb.conn_lcb)) {
+ APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk);
+ /* clean up ssm */
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ if ((p_cb->p_scb[xx]) &&
+ (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) {
+ APPL_TRACE_DEBUG("%s: Closing timer for AVDTP service", __func__);
+ bta_sys_conn_close(BTA_ID_AV, p_cb->p_scb[xx]->app_id,
+ p_cb->p_scb[xx]->peer_addr);
+ }
+ mask = 1 << (xx + 1);
+ if (((mask & p_lcb->conn_msk) || bta_av_cb.conn_lcb) &&
+ (p_cb->p_scb[xx]) &&
+ (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) {
+ APPL_TRACE_DEBUG("%s: Sending AVDT_DISCONNECT_EVT", __func__);
+ bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+ }
+ }
+ /** M: Bug fix for avoid signal channel not disconnect@{ */
+ else
+ {
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++)
+ {
+ if ((p_cb->p_scb[xx]) &&
+ (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0) &&
+ p_cb->p_scb[xx]->state == 2)
+ {
+ bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL);
+ }
+ }
+ }
+ /** @} */
+ }
+ APPL_TRACE_DEBUG("%s: sig_chg conn_lcb: 0x%x", __func__, p_cb->conn_lcb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_signalling_timer
+ *
+ * Description process the signal channel timer. This timer is started
+ * when the AVDTP signal channel is connected. If no profile
+ * is connected, the timer goes off every
+ * BTA_AV_SIGNALLING_TIMEOUT_MS.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_signalling_timer(UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ int xx;
+ uint8_t mask;
+ tBTA_AV_LCB* p_lcb = NULL;
+ tBTA_AV_PEND pend;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) {
+ mask = 1 << xx;
+ if (mask & p_cb->conn_lcb) {
+ /* this entry is used. check if it is connected */
+ p_lcb = &p_cb->lcb[xx];
+ if (!p_lcb->conn_msk) {
+ bta_sys_start_timer(p_cb->link_signalling_timer,
+ BTA_AV_SIGNALLING_TIMEOUT_MS,
+ BTA_AV_SIGNALLING_TIMER_EVT, 0);
+ bdcpy(pend.bd_addr, p_lcb->addr);
+ (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV*)&pend);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_accept_signalling_timer_cback
+ *
+ * Description Process the timeout when SRC is accepting connection
+ * and SNK did not start signalling.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_accept_signalling_timer_cback(void* data) {
+ uint32_t inx = PTR_TO_UINT(data);
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_SCB* p_scb = NULL;
+ if (inx < BTA_AV_NUM_STRS) {
+ p_scb = p_cb->p_scb[inx];
+ }
+ if (p_scb) {
+ APPL_TRACE_DEBUG("%s coll_mask = 0x%02X", __func__, p_scb->coll_mask);
+
+ if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) {
+ p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR;
+
+ if (bta_av_is_scb_opening(p_scb)) {
+ APPL_TRACE_DEBUG("%s: stream state opening: SDP started = %d", __func__,
+ p_scb->sdp_discovery_started);
+ if (p_scb->sdp_discovery_started) {
+ /* We are still doing SDP. Run the timer again. */
+ p_scb->coll_mask |= BTA_AV_COLL_INC_TMR;
+
+ alarm_set_on_queue(p_cb->accept_signalling_timer,
+ BTA_AV_ACCEPT_SIGNALLING_TIMEOUT_MS,
+ bta_av_accept_signalling_timer_cback,
+ UINT_TO_PTR(inx), btu_bta_alarm_queue);
+ } else {
+ /* SNK did not start signalling, resume signalling process. */
+ bta_av_discover_req(p_scb, NULL);
+ }
+ } else if (bta_av_is_scb_incoming(p_scb)) {
+ /* Stay in incoming state if SNK does not start signalling */
+
+ APPL_TRACE_DEBUG("%s: stream state incoming", __func__);
+ /* API open was called right after SNK opened L2C connection. */
+ if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED) {
+ p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED;
+
+ /* BTA_AV_API_OPEN_EVT */
+ tBTA_AV_API_OPEN* p_buf =
+ (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+ memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN));
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_check_peer_features
+ *
+ * Description check supported features on the peer device from the SDP
+ * record and return the feature mask
+ *
+ * Returns tBTA_AV_FEAT peer device feature mask
+ *
+ ******************************************************************************/
+tBTA_AV_FEAT bta_av_check_peer_features(uint16_t service_uuid) {
+ tBTA_AV_FEAT peer_features = 0;
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tSDP_DISC_REC* p_rec = NULL;
+ tSDP_DISC_ATTR* p_attr;
+ uint16_t peer_rc_version = 0;
+ uint16_t categories = 0;
+
+ APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid);
+ /* loop through all records we found */
+ while (true) {
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+ if (p_rec == NULL) {
+ break;
+ }
+
+ if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) !=
+ NULL) {
+ /* find peer features */
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ NULL)) {
+ peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (SDP_FindServiceInDb(p_cb->p_disc_db,
+ UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) {
+ peer_features |= BTA_AV_FEAT_RCTG;
+ }
+ }
+
+ if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) {
+ /* get profile version (if failure, version parameter is not updated) */
+ SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ &peer_rc_version);
+ APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version);
+
+ /** M: Bug fix for update avrcp version @{ */
+ tBTA_AV_SCB* p_scb = NULL;
+ uint8_t rc_handle;
+ if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
+ /* this is the rc handle/index to tBTA_AV_RCB */
+ rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK);
+ } else {
+ /* Validate array index*/
+ if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) {
+ p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
+ }
+ if (p_scb) {
+ rc_handle = p_scb->rc_handle;
+ }
+ }
+ if (get_peer_rc_version && (rc_handle == BTA_AV_RC_HANDLE_NONE) &&
+ (peer_rc_version == AVRC_REV_1_4)) {
+ bta_ar_update_avrc_version(peer_rc_version, BTA_ID_AV);
+ }
+ /** @} */
+ if (peer_rc_version >= AVRC_REV_1_3)
+ peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+ if (peer_rc_version >= AVRC_REV_1_4) {
+ /* get supported categories */
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ categories = p_attr->attr_value.v.u16;
+ if (categories & AVRC_SUPF_CT_CAT2)
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+ if (categories & AVRC_SUPF_CT_BROWSE)
+ peer_features |= (BTA_AV_FEAT_BROWSE);
+ }
+ }
+ }
+ }
+ APPL_TRACE_DEBUG("peer_features:x%x", peer_features);
+ return peer_features;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_avk_check_peer_features
+ *
+ * Description check supported features on the peer device from the SDP
+ * record and return the feature mask
+ *
+ * Returns tBTA_AV_FEAT peer device feature mask
+ *
+ ******************************************************************************/
+tBTA_AV_FEAT bta_avk_check_peer_features(uint16_t service_uuid) {
+ tBTA_AV_FEAT peer_features = 0;
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+
+ APPL_TRACE_DEBUG("%s service_uuid:x%x", __func__, service_uuid);
+
+ /* loop through all records we found */
+ tSDP_DISC_REC* p_rec =
+ SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, NULL);
+ while (p_rec) {
+ APPL_TRACE_DEBUG("%s found Service record for x%x", __func__, service_uuid);
+
+ if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) !=
+ NULL) {
+ /* find peer features */
+ if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ NULL)) {
+ peer_features |= BTA_AV_FEAT_RCCT;
+ }
+ if (SDP_FindServiceInDb(p_cb->p_disc_db,
+ UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) {
+ peer_features |= BTA_AV_FEAT_RCTG;
+ }
+ }
+
+ if ((SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) {
+ /* get profile version (if failure, version parameter is not updated) */
+ uint16_t peer_rc_version = 0;
+ bool val = SDP_FindProfileVersionInRec(
+ p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version);
+ APPL_TRACE_DEBUG("%s peer_rc_version for TG 0x%x, profile_found %d",
+ __func__, peer_rc_version, val);
+
+ if (peer_rc_version >= AVRC_REV_1_3)
+ peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA);
+
+ /*
+ * Though Absolute Volume came after in 1.4 and above, but there are few
+ * devices
+ * in market which supports absolute Volume and they are still 1.3
+ * TO avoid IOT issuses with those devices, we check for 1.3 as minimum
+ * version
+ */
+ if (peer_rc_version >= AVRC_REV_1_3) {
+ /* get supported features */
+ tSDP_DISC_ATTR* p_attr =
+ SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ uint16_t categories = p_attr->attr_value.v.u16;
+ if (categories & AVRC_SUPF_CT_CAT2)
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL);
+ if (categories & AVRC_SUPF_CT_APP_SETTINGS)
+ peer_features |= (BTA_AV_FEAT_APP_SETTING);
+ if (categories & AVRC_SUPF_CT_BROWSE)
+ peer_features |= (BTA_AV_FEAT_BROWSE);
+ }
+ }
+ }
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec);
+ }
+ APPL_TRACE_DEBUG("%s peer_features:x%x", __func__, peer_features);
+ return peer_features;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_disc_done
+ *
+ * Description Handle AVRCP service discovery results. If matching
+ * service found, open AVRCP connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_disc_done(UNUSED_ATTR tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_SCB* p_scb = NULL;
+ tBTA_AV_LCB* p_lcb;
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_RC_FEAT rc_feat;
+ uint8_t rc_handle;
+ tBTA_AV_FEAT peer_features = 0; /* peer features mask */
+
+ APPL_TRACE_DEBUG("%s bta_av_rc_disc_done disc:x%x", __func__, p_cb->disc);
+ if (!p_cb->disc) {
+ /** M: Bug fix for update avrcp version @{ */
+ get_peer_rc_version = false;
+ /** @} */
+ return;
+ }
+
+ if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
+ /* this is the rc handle/index to tBTA_AV_RCB */
+ rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK);
+ } else {
+ /* Validate array index*/
+ if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) {
+ p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1];
+ }
+ if (p_scb) {
+ rc_handle = p_scb->rc_handle;
+ } else {
+ p_cb->disc = 0;
+ /** M: Bug fix for update avrcp version @{ */
+ get_peer_rc_version = false;
+ /** @} */
+ return;
+ }
+ }
+
+ APPL_TRACE_DEBUG("%s rc_handle %d", __func__, rc_handle);
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+ if (p_cb->sdp_a2dp_snk_handle) {
+ /* This is Sink + CT + TG(Abs Vol) */
+ peer_features =
+ bta_avk_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ APPL_TRACE_DEBUG("%s populating rem ctrl target features %d", __func__,
+ peer_features);
+ if (BTA_AV_FEAT_ADV_CTRL &
+ bta_avk_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL))
+ peer_features |= (BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCCT);
+ } else
+#endif
+ if (p_cb->sdp_a2dp_handle) {
+ /* check peer version and whether support CT and TG role */
+ peer_features =
+ bta_av_check_peer_features(UUID_SERVCLASS_AV_REMOTE_CONTROL);
+ if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) &&
+ ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0)) {
+ /* if we support advance control and peer does not, check their support on
+ * TG role
+ * some implementation uses 1.3 on CT ans 1.4 on TG */
+ peer_features |=
+ bta_av_check_peer_features(UUID_SERVCLASS_AV_REM_CTRL_TARGET);
+ }
+ }
+
+ p_cb->disc = 0;
+ osi_free_and_reset((void**)&p_cb->p_disc_db);
+
+ APPL_TRACE_DEBUG("peer_features 0x%x, features 0x%x", peer_features,
+ p_cb->features);
+ /** M: Bug fix for update avrcp version @{ */
+ if ((rc_handle == BTA_AV_RC_HANDLE_NONE) && (get_peer_rc_version)) {
+ get_peer_rc_version = false;
+ return;
+ }
+ /** @} */
+
+ /* if we have no rc connection */
+ if (rc_handle == BTA_AV_RC_HANDLE_NONE) {
+ if (p_scb) {
+ /* if peer remote control service matches ours and USE_RC is true */
+ if ((((p_cb->features & BTA_AV_FEAT_RCCT) &&
+ (peer_features & BTA_AV_FEAT_RCTG)) ||
+ ((p_cb->features & BTA_AV_FEAT_RCTG) &&
+ (peer_features & BTA_AV_FEAT_RCCT)))) {
+ p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND);
+ if (p_lcb) {
+ rc_handle = bta_av_rc_create(p_cb, AVCT_INT,
+ (uint8_t)(p_scb->hdi + 1), p_lcb->lidx);
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ } else {
+ APPL_TRACE_ERROR("can not find LCB!!");
+ }
+ } else if (p_scb->use_rc) {
+ /* can not find AVRC on peer device. report failure */
+ p_scb->use_rc = false;
+ bdcpy(rc_open.peer_addr, p_scb->peer_addr);
+ rc_open.peer_features = 0;
+ rc_open.status = BTA_AV_FAIL_SDP;
+ (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV*)&rc_open);
+ }
+ }
+ } else {
+ p_cb->rcb[rc_handle].peer_features = peer_features;
+ rc_feat.rc_handle = rc_handle;
+ rc_feat.peer_features = peer_features;
+ if (p_scb == NULL) {
+ /*
+ * In case scb is not created by the time we are done with SDP
+ * we still need to send RC feature event. So we need to get BD
+ * from Message
+ */
+ bdcpy(rc_feat.peer_addr, p_cb->lcb[p_cb->rcb[rc_handle].lidx].addr);
+ } else
+ bdcpy(rc_feat.peer_addr, p_scb->peer_addr);
+ (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV*)&rc_feat);
+
+ /** M: Bug fix for peer device not setup browsing channel @{ */
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+
+ if ((p_cb->features & BTA_AV_FEAT_BROWSE) &&
+ (peer_features & BTA_AV_FEAT_BROWSE))
+ {
+ APPL_TRACE_DEBUG("%s start opening AVRC Browse channel timer", __func__);
+ av_open_browsing_timer = alarm_new("av_open_browsing_timer");
+ alarm_set_on_queue(av_open_browsing_timer, BTA_AV_BROWSING_TIMEOUT_MS,
+ bta_av_open_browsing_timer_timeout, UINT_TO_PTR(rc_handle),
+ btu_bta_alarm_queue);
+ }
+ /** @} */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_closed
+ *
+ * Description Set AVRCP state to closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_closed(tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_RC_CLOSE rc_close;
+ tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+ tBTA_AV_RCB* p_rcb;
+ tBTA_AV_SCB* p_scb;
+ int i;
+ bool conn = false;
+ tBTA_AV_LCB* p_lcb;
+
+ rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE;
+ p_scb = NULL;
+ APPL_TRACE_DEBUG("bta_av_rc_closed rc_handle:%d", p_msg->handle);
+ for (i = 0; i < BTA_AV_NUM_RCB; i++) {
+ p_rcb = &p_cb->rcb[i];
+ APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i,
+ p_rcb->handle, p_rcb->status);
+ if (p_rcb->handle == p_msg->handle) {
+ rc_close.rc_handle = i;
+ p_rcb->status &= ~BTA_AV_RC_CONN_MASK;
+ p_rcb->peer_features = 0;
+ APPL_TRACE_DEBUG(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx);
+ if (p_rcb->shdl) {
+ if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) {
+ p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1];
+ }
+ if (p_scb) {
+ bdcpy(rc_close.peer_addr, p_scb->peer_addr);
+ if (p_scb->rc_handle == p_rcb->handle)
+ p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ APPL_TRACE_DEBUG("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle);
+ }
+ p_rcb->shdl = 0;
+ } else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1)) {
+ /* if the RCB uses the extra LCB, use the addr for event and clean it */
+ p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS];
+ bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+ APPL_TRACE_DEBUG("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_msg->peer_addr[0], p_msg->peer_addr[1],
+ p_msg->peer_addr[2], p_msg->peer_addr[3],
+ p_msg->peer_addr[4], p_msg->peer_addr[5]);
+ p_lcb->conn_msk = 0;
+ p_lcb->lidx = 0;
+ }
+ p_rcb->lidx = 0;
+
+ if ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) {
+ /* AVCT CCB is deallocated */
+ p_rcb->handle = BTA_AV_RC_HANDLE_NONE;
+ p_rcb->status = 0;
+ } else {
+ /* AVCT CCB is still there. dealloc */
+ bta_av_del_rc(p_rcb);
+
+ /* if the AVRCP is no longer listening, create the listening channel */
+ if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE &&
+ bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ }
+ } else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) &&
+ (p_rcb->status & BTA_AV_RC_CONN_MASK)) {
+ /* at least one channel is still connected */
+ conn = true;
+ }
+ }
+
+ if (!conn) {
+ /* no AVRC channels are connected, go back to INIT state */
+ bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL);
+ }
+
+ if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE) {
+ rc_close.rc_handle = p_msg->handle;
+ bdcpy(rc_close.peer_addr, p_msg->peer_addr);
+ }
+ (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV*)&rc_close);
+ /** M: Bug fix for peer device not setup browsing channel @{ */
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+ /** @} */
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_browse_opened
+ *
+ * Description AVRC browsing channel is opened
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_opened(tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+ tBTA_AV_RC_BROWSE_OPEN rc_browse_open;
+
+ APPL_TRACE_DEBUG(
+ "bta_av_rc_browse_opened bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_msg->peer_addr[0], p_msg->peer_addr[1], p_msg->peer_addr[2],
+ p_msg->peer_addr[3], p_msg->peer_addr[4], p_msg->peer_addr[5]);
+ APPL_TRACE_DEBUG("bta_av_rc_browse_opened rc_handle:%d", p_msg->handle);
+
+ /** M: Bug fix for peer device not setup browsing channel @{ */
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+ /** @} */
+
+ rc_browse_open.status = BTA_AV_SUCCESS;
+ rc_browse_open.rc_handle = p_msg->handle;
+ bdcpy(rc_browse_open.peer_addr, p_msg->peer_addr);
+
+ (*p_cb->p_cback)(BTA_AV_RC_BROWSE_OPEN_EVT, (tBTA_AV*)&rc_browse_open);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_browse_closed
+ *
+ * Description AVRC browsing channel is closed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_browse_closed(tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_RC_CONN_CHG* p_msg = (tBTA_AV_RC_CONN_CHG*)p_data;
+ tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
+
+ APPL_TRACE_DEBUG(
+ "bta_av_rc_browse_closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ p_msg->peer_addr[0], p_msg->peer_addr[1], p_msg->peer_addr[2],
+ p_msg->peer_addr[3], p_msg->peer_addr[4], p_msg->peer_addr[5]);
+ APPL_TRACE_DEBUG("bta_av_rc_browse_closed rc_handle:%d", p_msg->handle);
+
+ rc_browse_close.rc_handle = p_msg->handle;
+ bdcpy(rc_browse_close.peer_addr, p_msg->peer_addr);
+
+ (*p_cb->p_cback)(BTA_AV_RC_BROWSE_CLOSE_EVT, (tBTA_AV*)&rc_browse_close);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rc_disc
+ *
+ * Description start AVRC SDP discovery.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_disc(uint8_t disc) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tAVRC_SDP_DB_PARAMS db_params;
+ uint16_t attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST,
+ ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SUPPORTED_FEATURES};
+ uint8_t hdi;
+ tBTA_AV_SCB* p_scb;
+ uint8_t* p_addr = NULL;
+ uint8_t rc_handle;
+
+ APPL_TRACE_DEBUG("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc);
+ if ((bta_av_cb.disc != 0) || (disc == 0)) return;
+
+ if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) {
+ /* this is the rc handle/index to tBTA_AV_RCB */
+ rc_handle = disc & (~BTA_AV_CHNL_MSK);
+ if (p_cb->rcb[rc_handle].lidx) {
+ p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr;
+ }
+ } else {
+ hdi = (disc & BTA_AV_HNDL_MSK) - 1;
+ p_scb = p_cb->p_scb[hdi];
+
+ if (p_scb) {
+ APPL_TRACE_DEBUG("rc_handle %d", p_scb->rc_handle);
+ p_addr = p_scb->peer_addr;
+ }
+ }
+
+ if (p_addr) {
+ /* allocate discovery database */
+ if (p_cb->p_disc_db == NULL)
+ p_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_AV_DISC_BUF_SIZE);
+
+ /* set up parameters */
+ db_params.db_len = BTA_AV_DISC_BUF_SIZE;
+ db_params.num_attr = 3;
+ db_params.p_db = p_cb->p_disc_db;
+ db_params.p_attrs = attr_list;
+
+ /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */
+ if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params,
+ bta_av_avrc_sdp_cback) == AVRC_SUCCESS) {
+ p_cb->disc = disc;
+ APPL_TRACE_DEBUG("disc %d", p_cb->disc);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_dereg_comp
+ *
+ * Description deregister complete. free the stream control block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_dereg_comp(tBTA_AV_DATA* p_data) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ tBTA_AV_SCB* p_scb;
+ tBTA_UTL_COD cod;
+ uint8_t mask;
+ BT_HDR* p_buf;
+
+ /* find the stream control block */
+ p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+ if (p_scb) {
+ APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl);
+ mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ p_cb->reg_audio &= ~mask;
+ if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) {
+ /* this channel is still marked as open. decrease the count */
+ bta_av_cb.audio_open_cnt--;
+ }
+ p_cb->conn_audio &= ~mask;
+
+ if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2dp_list) {
+ /* make sure no buffers are in a2dp_list */
+ while (!list_is_empty(p_scb->a2dp_list)) {
+ p_buf = (BT_HDR*)list_front(p_scb->a2dp_list);
+ list_remove(p_scb->a2dp_list, p_buf);
+ osi_free(p_buf);
+ }
+ }
+
+ /* remove the A2DP SDP record, if no more audio stream is left */
+ if (!p_cb->reg_audio) {
+#if (BTA_AR_INCLUDED == TRUE)
+ bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV);
+#endif
+ if (p_cb->sdp_a2dp_handle) {
+ bta_av_del_sdp_rec(&p_cb->sdp_a2dp_handle);
+ p_cb->sdp_a2dp_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+ if (p_cb->sdp_a2dp_snk_handle) {
+ bta_av_del_sdp_rec(&p_cb->sdp_a2dp_snk_handle);
+ p_cb->sdp_a2dp_snk_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK);
+ }
+#endif
+ }
+ } else {
+ p_cb->reg_video &= ~mask;
+ /* make sure that this channel is not connected */
+ p_cb->conn_video &= ~mask;
+ /* remove the VDP SDP record, (only one video stream at most) */
+ bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE);
+ }
+
+ /* make sure that the timer is not active */
+ alarm_cancel(p_scb->avrc_ct_timer);
+ /** M: Bug fix for peer device not setup browsing channel @{ */
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+ /** @} */
+ osi_free_and_reset((void**)&p_cb->p_scb[p_scb->hdi]);
+ }
+
+ APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d", p_cb->reg_audio,
+ p_cb->reg_video, p_cb->disabling);
+ /* if no stream control block is active */
+ if ((p_cb->reg_audio + p_cb->reg_video) == 0) {
+#if (BTA_AR_INCLUDED == TRUE)
+ /* deregister from AVDT */
+ bta_ar_dereg_avdt(BTA_ID_AV);
+
+ /* deregister from AVCT */
+ bta_ar_dereg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV);
+ bta_ar_dereg_avct(BTA_ID_AV);
+#endif
+
+ if (p_cb->disabling) {
+ p_cb->disabling = false;
+ bta_av_cb.features = 0;
+ }
+
+ /* Clear the Capturing service class bit */
+ cod.service = BTM_COD_SERVICE_CAPTURING;
+ utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS);
+ }
+}
+
+/** M: Bug fix for peer device not setup browsing channel @{ */
+/*******************************************************************************
+ *
+ * Function bta_av_open_browsing_timer_timeout
+ *
+ * Description Timer to trigger browsing channel open if the remote headset not establishes
+ * browsing connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_open_browsing_timer_timeout(UNUSED_ATTR void* data) {
+ uint8_t rc_handle = PTR_TO_UINT(data);
+ APPL_TRACE_DEBUG("%s AVRC Browse channel timeout", __func__);
+ AVRC_OpenBrowse(rc_handle, AVCT_INT);
+ if (alarm_is_scheduled(av_open_browsing_timer))
+ {
+ alarm_free(av_open_browsing_timer);
+ av_open_browsing_timer = NULL;
+ }
+}
+/** @} */
+
+/** M: Bug fix for update avrcp version @{ */
+/*******************************************************************************
+ *
+ * Function bta_av_rc_disc
+ *
+ * Description start AVRC SDP discovery.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_rc_disc(uint8_t disc, bool get_rc_version) {
+ uint16_t profile_version = AVRC_REV_1_0;
+
+ // This check can override the AVRCP profile version with a property
+ char avrcp_version[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version,
+ AVRCP_1_4_STRING);
+ LOG_INFO(LOG_TAG, "bta_av_rc_disc AVRCP version: \"%s\"",
+ avrcp_version);
+
+ if (!strncmp(AVRCP_1_6_STRING, avrcp_version,
+ sizeof(AVRCP_1_6_STRING))) {
+ profile_version = AVRC_REV_1_6;
+ } else if (!strncmp(AVRCP_1_5_STRING, avrcp_version,
+ sizeof(AVRCP_1_5_STRING))) {
+ profile_version = AVRC_REV_1_5;
+ } else {
+ profile_version = AVRC_REV_1_4;
+ }
+ if (profile_version > AVRC_REV_1_4) {
+ get_peer_rc_version = get_rc_version;
+ bta_av_rc_disc(disc);
+ }
+}
+/** @} */ \ No newline at end of file
diff --git a/mtkbt/code/bt/bta/av/bta_av_api.cc b/mtkbt/code/bt/bta/av/bta_av_api.cc
new file mode 100755
index 0000000..581a920
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_api.cc
@@ -0,0 +1,601 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for the advanced audio/video (AV)
+ * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_av_int.h"
+#include "bta_sys.h"
+
+#include "osi/include/allocator.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_av_reg = {bta_av_hdl_event, BTA_AvDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_AvEnable
+ *
+ * Description Enable the advanced audio/video service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_AV_ENABLE_EVT. This function must
+ * be called before other function in the AV API are
+ * called.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features,
+ tBTA_AV_CBACK* p_cback) {
+ tBTA_AV_API_ENABLE* p_buf =
+ (tBTA_AV_API_ENABLE*)osi_malloc(sizeof(tBTA_AV_API_ENABLE));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_AV, &bta_av_reg);
+
+ p_buf->hdr.event = BTA_AV_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->features = features;
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDisable
+ *
+ * Description Disable the advanced audio/video service.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ bta_sys_deregister(BTA_ID_AV);
+ p_buf->event = BTA_AV_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRegister
+ *
+ * Description Register the audio or video service to stack. When the
+ * operation is complete the callback function will be
+ * called with a BTA_AV_REGISTER_EVT. This function must
+ * be called before AVDT stream is open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name,
+ uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback,
+ uint16_t service_uuid) {
+ tBTA_AV_API_REG* p_buf =
+ (tBTA_AV_API_REG*)osi_malloc(sizeof(tBTA_AV_API_REG));
+
+ p_buf->hdr.layer_specific = chnl;
+ p_buf->hdr.event = BTA_AV_API_REGISTER_EVT;
+ if (p_service_name)
+ strlcpy(p_buf->p_service_name, p_service_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->p_service_name[0] = 0;
+ p_buf->app_id = app_id;
+ p_buf->p_app_sink_data_cback = p_sink_data_cback;
+ p_buf->service_uuid = service_uuid;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDeregister
+ *
+ * Description Deregister the audio or video service
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->layer_specific = hndl;
+ p_buf->event = BTA_AV_API_DEREGISTER_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOpen
+ *
+ * Description Opens an advanced audio/video connection to a peer device.
+ * When connection is open callback function is called
+ * with a BTA_AV_OPEN_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, bool use_rc,
+ tBTA_SEC sec_mask, uint16_t uuid) {
+ tBTA_AV_API_OPEN* p_buf =
+ (tBTA_AV_API_OPEN*)osi_malloc(sizeof(tBTA_AV_API_OPEN));
+
+ p_buf->hdr.event = BTA_AV_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->use_rc = use_rc;
+ p_buf->sec_mask = sec_mask;
+ p_buf->switch_res = BTA_AV_RS_NONE;
+ p_buf->uuid = uuid;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvClose
+ *
+ * Description Close the current streams.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AV_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDisconnect
+ *
+ * Description Close the connection to the address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr) {
+ tBTA_AV_API_DISCNT* p_buf =
+ (tBTA_AV_API_DISCNT*)osi_malloc(sizeof(tBTA_AV_API_DISCNT));
+
+ p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT;
+ bdcpy(p_buf->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvStart
+ *
+ * Description Start audio/video stream data transfer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvStart(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AV_API_START_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOffloadStart
+ *
+ * Description Start a2dp audio offloading.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_AV_API_OFFLOAD_START_EVT;
+ p_buf->layer_specific = hndl;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOffloadStartRsp
+ *
+ * Description Response from vendor lib for A2DP Offload Start request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status) {
+ tBTA_AV_API_STATUS_RSP* p_buf =
+ (tBTA_AV_API_STATUS_RSP*)osi_malloc(sizeof(tBTA_AV_API_STATUS_RSP));
+
+ p_buf->hdr.event = BTA_AV_API_OFFLOAD_START_RSP_EVT;
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->status = status;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvStop
+ *
+ * Description Stop audio/video stream data transfer.
+ * If suspend is true, this function sends AVDT suspend signal
+ * to the connected peer(s).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvStop(bool suspend) {
+ tBTA_AV_API_STOP* p_buf =
+ (tBTA_AV_API_STOP*)osi_malloc(sizeof(tBTA_AV_API_STOP));
+
+ p_buf->hdr.event = BTA_AV_API_STOP_EVT;
+ p_buf->flush = true;
+ p_buf->suspend = suspend;
+ p_buf->reconfig_stop = false;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvReconfig
+ *
+ * Description Reconfigure the audio/video stream.
+ * If suspend is true, this function tries the
+ * suspend/reconfigure procedure first.
+ * If suspend is false or when suspend/reconfigure fails,
+ * this function closes and re-opens the AVDT connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
+ uint8_t* p_codec_info, uint8_t num_protect,
+ const uint8_t* p_protect_info) {
+ tBTA_AV_API_RCFG* p_buf =
+ (tBTA_AV_API_RCFG*)osi_malloc(sizeof(tBTA_AV_API_RCFG) + num_protect);
+
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_RECONFIG_EVT;
+ p_buf->num_protect = num_protect;
+ p_buf->suspend = suspend;
+ p_buf->sep_info_idx = sep_info_idx;
+ p_buf->p_protect_info = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+ memcpy(p_buf->p_protect_info, p_protect_info, num_protect);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvProtectReq
+ *
+ * Description Send a content protection request. This function can only
+ * be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len) {
+ tBTA_AV_API_PROTECT_REQ* p_buf = (tBTA_AV_API_PROTECT_REQ*)osi_malloc(
+ sizeof(tBTA_AV_API_PROTECT_REQ) + len);
+
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT;
+ p_buf->len = len;
+ if (p_data == NULL) {
+ p_buf->p_data = NULL;
+ } else {
+ p_buf->p_data = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->p_data, p_data, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvProtectRsp
+ *
+ * Description Send a content protection response. This function must
+ * be called if a BTA_AV_PROTECT_REQ_EVT is received.
+ * This function can only be used if AV is enabled with
+ * feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data,
+ uint16_t len) {
+ tBTA_AV_API_PROTECT_RSP* p_buf = (tBTA_AV_API_PROTECT_RSP*)osi_malloc(
+ sizeof(tBTA_AV_API_PROTECT_RSP) + len);
+
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = BTA_AV_API_PROTECT_RSP_EVT;
+ p_buf->len = len;
+ p_buf->error_code = error_code;
+ if (p_data == NULL) {
+ p_buf->p_data = NULL;
+ } else {
+ p_buf->p_data = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->p_data, p_data, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRemoteCmd
+ *
+ * Description Send a remote control command. This function can only
+ * be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+ tBTA_AV_STATE key_state) {
+ tBTA_AV_API_REMOTE_CMD* p_buf =
+ (tBTA_AV_API_REMOTE_CMD*)osi_malloc(sizeof(tBTA_AV_API_REMOTE_CMD));
+
+ p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.op_id = rc_id;
+ p_buf->msg.state = key_state;
+ p_buf->msg.p_pass_data = NULL;
+ p_buf->msg.pass_len = 0;
+ p_buf->label = label;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRemoteVendorUniqueCmd
+ *
+ * Description Send a remote control command with Vendor Unique rc_id.
+ * This function can only be used if AV is enabled with
+ * feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+ tBTA_AV_STATE key_state, uint8_t* p_msg,
+ uint8_t buf_len) {
+ tBTA_AV_API_REMOTE_CMD* p_buf = (tBTA_AV_API_REMOTE_CMD*)osi_malloc(
+ sizeof(tBTA_AV_API_REMOTE_CMD) + buf_len);
+
+ p_buf->label = label;
+ p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.op_id = AVRC_ID_VENDOR;
+ p_buf->msg.state = key_state;
+ p_buf->msg.pass_len = buf_len;
+ if (p_msg == NULL) {
+ p_buf->msg.p_pass_data = NULL;
+ } else {
+ p_buf->msg.p_pass_data = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->msg.p_pass_data, p_msg, buf_len);
+ }
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvVendorCmd
+ *
+ * Description Send a vendor dependent remote control command. This
+ * function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_VENDOR.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+ uint8_t* p_data, uint16_t len) {
+ tBTA_AV_API_VENDOR* p_buf =
+ (tBTA_AV_API_VENDOR*)osi_malloc(sizeof(tBTA_AV_API_VENDOR) + len);
+
+ p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.hdr.ctype = cmd_code;
+ p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+ p_buf->msg.hdr.subunit_id = 0;
+ p_buf->msg.company_id = p_bta_av_cfg->company_id;
+ p_buf->label = label;
+ p_buf->msg.vendor_len = len;
+ if (p_data == NULL) {
+ p_buf->msg.p_vendor_data = NULL;
+ } else {
+ p_buf->msg.p_vendor_data = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->msg.p_vendor_data, p_data, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvVendorRsp
+ *
+ * Description Send a vendor dependent remote control response.
+ * This function must be called if a BTA_AV_VENDOR_CMD_EVT
+ * is received. This function can only be used if AV is
+ * enabled with feature BTA_AV_FEAT_VENDOR.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ uint8_t* p_data, uint16_t len, uint32_t company_id) {
+ tBTA_AV_API_VENDOR* p_buf =
+ (tBTA_AV_API_VENDOR*)osi_malloc(sizeof(tBTA_AV_API_VENDOR) + len);
+
+ p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->msg.hdr.ctype = rsp_code;
+ p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL;
+ p_buf->msg.hdr.subunit_id = 0;
+ if (company_id)
+ p_buf->msg.company_id = company_id;
+ else
+ p_buf->msg.company_id = p_bta_av_cfg->company_id;
+ p_buf->label = label;
+ p_buf->msg.vendor_len = len;
+ if (p_data == NULL) {
+ p_buf->msg.p_vendor_data = NULL;
+ } else {
+ p_buf->msg.p_vendor_data = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->msg.p_vendor_data, p_data, len);
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOpenRc
+ *
+ * Description Open an AVRCP connection toward the device with the
+ * specified handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle) {
+ tBTA_AV_API_OPEN_RC* p_buf =
+ (tBTA_AV_API_OPEN_RC*)osi_malloc(sizeof(tBTA_AV_API_OPEN_RC));
+
+ p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvCloseRc
+ *
+ * Description Close an AVRCP connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvCloseRc(uint8_t rc_handle) {
+ tBTA_AV_API_CLOSE_RC* p_buf =
+ (tBTA_AV_API_CLOSE_RC*)osi_malloc(sizeof(tBTA_AV_API_CLOSE_RC));
+
+ p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvMetaRsp
+ *
+ * Description Send a Metadata/Advanced Control response. The message
+ * contained in p_pkt can be composed with AVRC utility
+ * functions.
+ * This function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_METADATA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ BT_HDR* p_pkt) {
+ tBTA_AV_API_META_RSP* p_buf =
+ (tBTA_AV_API_META_RSP*)osi_malloc(sizeof(tBTA_AV_API_META_RSP));
+
+ p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->rsp_code = rsp_code;
+ p_buf->p_pkt = p_pkt;
+ p_buf->is_rsp = true;
+ p_buf->label = label;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_AvMetaCmd
+ *
+ * Description Send a Metadata/Advanced Control command. The message
+*contained
+ * in p_pkt can be composed with AVRC utility functions.
+ * This function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_METADATA.
+ * This message is sent only when the peer supports the TG
+*role.
+*8 The only command makes sense right now is the absolute
+*volume command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+ BT_HDR* p_pkt) {
+ tBTA_AV_API_META_RSP* p_buf =
+ (tBTA_AV_API_META_RSP*)osi_malloc(sizeof(tBTA_AV_API_META_RSP));
+
+ p_buf->hdr.event = BTA_AV_API_META_RSP_EVT;
+ p_buf->hdr.layer_specific = rc_handle;
+ p_buf->p_pkt = p_pkt;
+ p_buf->rsp_code = cmd_code;
+ p_buf->is_rsp = false;
+ p_buf->label = label;
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/av/bta_av_cfg.cc b/mtkbt/code/bt/bta/av/bta_av_cfg.cc
new file mode 100755
index 0000000..5fc75ba
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_cfg.cc
@@ -0,0 +1,281 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for advanced
+ * audio/video
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+
+#ifndef BTA_AV_RC_COMP_ID
+#define BTA_AV_RC_COMP_ID AVRC_CO_GOOGLE
+#endif
+
+#ifndef BTA_AV_RC_PASS_RSP_CODE
+#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL
+#endif
+
+const uint32_t bta_av_meta_caps_co_ids[] = {AVRC_CO_METADATA, AVRC_CO_BROADCOM};
+
+/* AVRCP supported categories */
+#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2)
+#define BTA_AVK_RC_SUPF_CT (AVRC_SUPF_CT_CAT1 | AVRC_SUPF_CT_BROWSE)
+#define BTA_AVK_RC_SUPF_TG (AVRC_SUPF_TG_CAT2)
+
+/* AVRCP Controller and Targer default name */
+#ifndef BTA_AV_RC_CT_NAME
+#define BTA_AV_RC_CT_NAME "AVRC Controller"
+#endif
+
+#ifndef BTA_AV_RC_TG_NAME
+#define BTA_AV_RC_TG_NAME "AVRC Target"
+#endif
+
+/* Added to modify
+ * 1. flush timeout
+ * 2. Remove Group navigation support in SupportedFeatures
+ * 3. GetCapabilities supported event_ids list
+ * 4. GetCapabilities supported event_ids count
+*/
+/* Flushing partial avdtp packets can cause some headsets to disconnect the link
+ if receiving partial a2dp frames */
+const uint16_t bta_av_audio_flush_to[] = {
+ 0, /* 1 stream */
+ 0, /* 2 streams */
+ 0, /* 3 streams */
+ 0, /* 4 streams */
+ 0 /* 5 streams */
+}; /* AVDTP audio transport channel flush timeout */
+
+/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */
+/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be true
+ */
+#ifndef BTA_AV_RC_SUPF_TG
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#define BTA_AV_RC_SUPF_TG \
+ (AVRC_SUPF_TG_CAT1 | AVRC_SUPF_TG_MULTI_PLAYER | \
+ AVRC_SUPF_TG_BROWSE) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */
+#else
+#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1)
+#endif
+#endif
+
+/*
+ * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS
+ * also needs to be changed.
+ */
+const uint8_t bta_av_meta_caps_evt_ids[] = {
+ AVRC_EVT_PLAY_STATUS_CHANGE, AVRC_EVT_TRACK_CHANGE,
+ AVRC_EVT_PLAY_POS_CHANGED, AVRC_EVT_AVAL_PLAYERS_CHANGE,
+ AVRC_EVT_ADDR_PLAYER_CHANGE, AVRC_EVT_UIDS_CHANGE,
+ AVRC_EVT_NOW_PLAYING_CHANGE,
+ /* TODO: Add support for these events
+ AVRC_EVT_APP_SETTING_CHANGE,
+ */
+};
+#ifndef BTA_AV_NUM_RC_EVT_IDS
+#define BTA_AV_NUM_RC_EVT_IDS \
+ (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0]))
+#endif /* BTA_AV_NUM_RC_EVT_IDS */
+
+const uint8_t bta_avk_meta_caps_evt_ids[] = {
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ AVRC_EVT_VOLUME_CHANGE,
+#endif
+};
+#ifndef BTA_AVK_NUM_RC_EVT_IDS
+#define BTA_AVK_NUM_RC_EVT_IDS \
+ (sizeof(bta_avk_meta_caps_evt_ids) / sizeof(bta_avk_meta_caps_evt_ids[0]))
+#endif /* BTA_AVK_NUM_RC_EVT_IDS */
+
+/* the MTU for the AVRCP browsing channel */
+#ifndef BTA_AV_MAX_RC_BR_MTU
+#define BTA_AV_MAX_RC_BR_MTU 1008
+#endif
+
+/* This configuration to be used when we are Src + TG + CT( only for abs vol) */
+const tBTA_AV_CFG bta_av_cfg = {
+ BTA_AV_RC_COMP_ID, /* AVRCP Company ID */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ 512, /* AVRCP MTU at L2CAP for control channel */
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#else
+ 48, /* AVRCP MTU at L2CAP for control channel */
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+#endif
+ BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */
+ BTA_AV_RC_SUPF_TG, /* AVRCP target categories */
+ 672, /* AVDTP signaling channel MTU at L2CAP */
+ BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP
+ */
+ bta_av_audio_flush_to, /* AVDTP audio transport channel flush
+ timeout */
+ 6, /* AVDTP audio channel max data queue size */
+ BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */
+ 600, /* AVDTP video transport channel flush timeout */
+ false, /* true, to accept AVRC 1.3 group nevigation command */
+ 2, /* company id count in p_meta_co_ids */
+ BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+ BTA_AV_RC_PASS_RSP_CODE, /* the default response code for pass
+ through commands */
+ bta_av_meta_caps_co_ids, /* the metadata Get Capabilities response
+ for company id */
+ bta_av_meta_caps_evt_ids, /* the the metadata Get Capabilities
+ response for event id */
+ NULL, /* the action function table for VDP stream */
+ NULL, /* action function to register VDP */
+ BTA_AV_RC_CT_NAME, /* Default AVRCP controller name */
+ BTA_AV_RC_TG_NAME /* Default AVRCP target name */
+};
+
+/* This configuration to be used when we are Sink + CT + TG( only for abs vol)
+ */
+const tBTA_AV_CFG bta_avk_cfg = {
+ AVRC_CO_METADATA, /* AVRCP Company ID */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ 512, /* AVRCP MTU at L2CAP for control channel */
+#else
+ 48, /* AVRCP MTU at L2CAP for control channel */
+#endif
+ BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */
+ BTA_AVK_RC_SUPF_CT, /* AVRCP controller categories */
+ BTA_AVK_RC_SUPF_TG, /* AVRCP target categories */
+ 672, /* AVDTP signaling channel MTU at L2CAP */
+ BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP
+ */
+ bta_av_audio_flush_to, /* AVDTP audio transport channel flush
+ timeout */
+ 6, /* AVDTP audio channel max data queue size */
+ BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */
+ 600, /* AVDTP video transport channel flush timeout */
+ false, /* true, to accept AVRC 1.3 group nevigation command */
+ 2, /* company id count in p_meta_co_ids */
+ BTA_AVK_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */
+ BTA_AV_RC_PASS_RSP_CODE, /* the default response code for pass
+ through commands */
+ bta_av_meta_caps_co_ids, /* the metadata Get Capabilities response
+ for company id */
+ bta_avk_meta_caps_evt_ids, /* the the metadata Get Capabilities
+ response for event id */
+ NULL, /* the action function table for VDP stream */
+ NULL, /* action function to register VDP */
+ {0}, /* Default AVRCP controller name */
+ {0}, /* Default AVRCP target name */
+};
+
+tBTA_AV_CFG* p_bta_av_cfg = NULL;
+
+const uint16_t bta_av_rc_id[] = {
+ 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+ 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP,
+ 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU,
+ 12=FAV_MENU, 13=EXIT */
+
+ 0, /* not used */
+
+ 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+ 4=4, 5=5, 6=6, 7=7,
+ 8=8, 9=9, 10=DOT, 11=ENTER,
+ 12=CLEAR */
+
+ 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL,
+ 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP,
+ 8=PAGE_DOWN */
+
+/* btui_app provides an example of how to leave the decision of rejecting a
+ command or not
+ * based on which media player is currently addressed (this is only applicable
+ for AVRCP 1.4 or later)
+ * If the decision is per player for a particular rc_id, the related bit is
+ clear (not set)
+ * bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, 4=PLAY, 5=STOP,
+ 6=PAUSE, 7=RECORD, 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+ 0x0070, /* PLAY | STOP | PAUSE */
+#else /* BTA_AV_RC_PASS_RSP_CODE != BTA_AV_RSP_INTERIM */
+#if (BTA_AVRCP_FF_RW_SUPPORT == TRUE)
+ 0x1b7E, /* PLAY | STOP | PAUSE | FF | RW | VOL_UP | VOL_DOWN | MUTE | FW |
+ BACK */
+#else /* BTA_AVRCP_FF_RW_SUPPORT == FALSE */
+ 0x187E, /* PLAY | STOP | PAUSE | VOL_UP | VOL_DOWN | MUTE | FW | BACK */
+#endif /* BTA_AVRCP_FF_RW_SUPPORT */
+#endif /* BTA_AV_RC_PASS_RSP_CODE */
+
+ 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+ 0, /* not used */
+
+ 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+ 4=F4, 5=F5 */
+};
+
+#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM)
+const uint16_t bta_av_rc_id_ac[] = {
+ 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT,
+ 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN,
+ 7=LEFT_UP,
+ 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU,
+ 11=CONT_MENU,
+ 12=FAV_MENU, 13=EXIT */
+
+ 0, /* not used */
+
+ 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3,
+ 4=4, 5=5, 6=6, 7=7,
+ 8=8, 9=9, 10=DOT, 11=ENTER,
+ 12=CLEAR */
+
+ 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN,
+ 3=SOUND_SEL,
+ 4=INPUT_SEL, 5=DISP_INFO, 6=HELP,
+ 7=PAGE_UP,
+ 8=PAGE_DOWN */
+
+ /* btui_app provides an example of how to leave the decision of
+ * rejecting a command or not
+ * based on which media player is currently addressed (this is
+ * only applicable for AVRCP 1.4 or later)
+ * If the decision is per player for a particular rc_id, the
+ * related bit is set */
+ 0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE,
+ 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD,
+ 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD,
+ 12=BACKWARD */
+
+ 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */
+
+ 0, /* not used */
+
+ 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3,
+ 4=F4, 5=F5 */
+};
+uint16_t* p_bta_av_rc_id_ac = (uint16_t*)bta_av_rc_id_ac;
+#else
+uint16_t* p_bta_av_rc_id_ac = NULL;
+#endif
+
+uint16_t* p_bta_av_rc_id = (uint16_t*)bta_av_rc_id;
diff --git a/mtkbt/code/bt/bta/av/bta_av_ci.cc b/mtkbt/code/bt/bta/av/bta_av_ci.cc
new file mode 100755
index 0000000..a215046
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_ci.cc
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for advanced audio/video call-in
+ * functions.
+ *
+ ******************************************************************************/
+
+#include "bta_av_ci.h"
+#include "bta_api.h"
+#include "bta_av_int.h"
+#include "bta_sys.h"
+
+#include <string.h>
+
+/*******************************************************************************
+ *
+ * Function bta_av_ci_src_data_ready
+ *
+ * Description This function sends an event to the AV indicating that
+ * the phone has audio stream data ready to send and AV
+ * should call bta_av_co_audio_src_data_path().
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->layer_specific = chnl;
+ p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_ci_setconfig
+ *
+ * Description This function must be called in response to function
+ * bta_av_co_audio_setconfig().
+ * Parameter err_code is set to an AVDTP status value;
+ * AVDT_SUCCESS if the codec configuration is ok,
+ * otherwise error.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code, uint8_t category,
+ uint8_t num_seid, uint8_t* p_seid, bool recfg_needed,
+ uint8_t avdt_handle) {
+ tBTA_AV_CI_SETCONFIG* p_buf =
+ (tBTA_AV_CI_SETCONFIG*)osi_malloc(sizeof(tBTA_AV_CI_SETCONFIG));
+
+ p_buf->hdr.layer_specific = hndl;
+ p_buf->hdr.event = (err_code == A2DP_SUCCESS) ? BTA_AV_CI_SETCONFIG_OK_EVT
+ : BTA_AV_CI_SETCONFIG_FAIL_EVT;
+ p_buf->err_code = err_code;
+ p_buf->category = category;
+ p_buf->recfg_needed = recfg_needed;
+ p_buf->num_seid = num_seid;
+ p_buf->avdt_handle = avdt_handle;
+ if (p_seid && num_seid) {
+ p_buf->p_seid = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->p_seid, p_seid, num_seid);
+ } else {
+ p_buf->p_seid = NULL;
+ p_buf->num_seid = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/av/bta_av_int.h b/mtkbt/code/bt/bta/av/bta_av_int.h
new file mode 100755
index 0000000..d6727f0
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_int.h
@@ -0,0 +1,710 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_INT_H
+#define BTA_AV_INT_H
+
+#include "avdt_api.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_av_co.h"
+#include "bta_sys.h"
+#include "osi/include/list.h"
+#include "stack/include/a2dp_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+enum {
+ /* these events are handled by the AV main state machine */
+ BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV),
+ BTA_AV_API_REMOTE_CMD_EVT,
+ BTA_AV_API_VENDOR_CMD_EVT,
+ BTA_AV_API_VENDOR_RSP_EVT,
+ BTA_AV_API_META_RSP_EVT,
+ BTA_AV_API_RC_CLOSE_EVT,
+ BTA_AV_AVRC_OPEN_EVT,
+ BTA_AV_AVRC_MSG_EVT,
+ BTA_AV_AVRC_NONE_EVT,
+
+ /* these events are handled by the AV stream state machine */
+ BTA_AV_API_OPEN_EVT,
+ BTA_AV_API_CLOSE_EVT,
+ BTA_AV_AP_START_EVT, /* the following 2 events must be in the same order as
+ the *API_*EVT */
+ BTA_AV_AP_STOP_EVT,
+ BTA_AV_API_RECONFIG_EVT,
+ BTA_AV_API_PROTECT_REQ_EVT,
+ BTA_AV_API_PROTECT_RSP_EVT,
+ BTA_AV_API_RC_OPEN_EVT,
+ BTA_AV_SRC_DATA_READY_EVT,
+ BTA_AV_CI_SETCONFIG_OK_EVT,
+ BTA_AV_CI_SETCONFIG_FAIL_EVT,
+ BTA_AV_SDP_DISC_OK_EVT,
+ BTA_AV_SDP_DISC_FAIL_EVT,
+ BTA_AV_STR_DISC_OK_EVT,
+ BTA_AV_STR_DISC_FAIL_EVT,
+ BTA_AV_STR_GETCAP_OK_EVT,
+ BTA_AV_STR_GETCAP_FAIL_EVT,
+ BTA_AV_STR_OPEN_OK_EVT,
+ BTA_AV_STR_OPEN_FAIL_EVT,
+ BTA_AV_STR_START_OK_EVT,
+ BTA_AV_STR_START_FAIL_EVT,
+ BTA_AV_STR_CLOSE_EVT,
+ BTA_AV_STR_CONFIG_IND_EVT,
+ BTA_AV_STR_SECURITY_IND_EVT,
+ BTA_AV_STR_SECURITY_CFM_EVT,
+ BTA_AV_STR_WRITE_CFM_EVT,
+ BTA_AV_STR_SUSPEND_CFM_EVT,
+ BTA_AV_STR_RECONFIG_CFM_EVT,
+ BTA_AV_AVRC_TIMER_EVT,
+ BTA_AV_AVDT_CONNECT_EVT,
+ BTA_AV_AVDT_DISCONNECT_EVT,
+ BTA_AV_ROLE_CHANGE_EVT,
+ BTA_AV_AVDT_DELAY_RPT_EVT,
+ BTA_AV_ACP_CONNECT_EVT,
+ BTA_AV_API_OFFLOAD_START_EVT,
+ BTA_AV_API_OFFLOAD_START_RSP_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_AV_API_ENABLE_EVT,
+ BTA_AV_API_REGISTER_EVT,
+ BTA_AV_API_DEREGISTER_EVT,
+ BTA_AV_API_DISCONNECT_EVT,
+ BTA_AV_CI_SRC_DATA_READY_EVT,
+ BTA_AV_SIG_CHG_EVT,
+ BTA_AV_SIGNALLING_TIMER_EVT,
+ BTA_AV_SDP_AVRC_DISC_EVT,
+ BTA_AV_AVRC_CLOSE_EVT,
+ BTA_AV_AVRC_BROWSE_OPEN_EVT,
+ BTA_AV_AVRC_BROWSE_CLOSE_EVT,
+ BTA_AV_CONN_CHG_EVT,
+ BTA_AV_DEREG_COMP_EVT,
+#if (AVDT_REPORTING == TRUE)
+ BTA_AV_AVDT_RPT_CONN_EVT,
+#endif
+ BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as
+ the *AP_*EVT */
+ BTA_AV_API_STOP_EVT
+};
+
+/* events for AV control block state machine */
+#define BTA_AV_FIRST_SM_EVT BTA_AV_API_DISABLE_EVT
+#define BTA_AV_LAST_SM_EVT BTA_AV_AVRC_NONE_EVT
+
+/* events for AV stream control block state machine */
+#define BTA_AV_FIRST_SSM_EVT BTA_AV_API_OPEN_EVT
+
+/* events that do not go through state machine */
+#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT
+#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT
+
+/* API events passed to both SSMs (by bta_av_api_to_ssm) */
+#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT
+#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT
+
+#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT
+
+/* maximum number of SEPS in stream discovery results */
+#define BTA_AV_NUM_SEPS 32
+
+/* initialization value for AVRC handle */
+#define BTA_AV_RC_HANDLE_NONE 0xFF
+
+/* size of database for service discovery */
+#define BTA_AV_DISC_BUF_SIZE 1000
+
+/* maximum length of AVDTP security data */
+#define BTA_AV_SECURITY_MAX_LEN 400
+
+/* check number of buffers queued at L2CAP when this amount of buffers are
+ * queued to L2CAP */
+#define BTA_AV_QUEUE_DATA_CHK_NUM L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
+
+/* the number of ACL links with AVDT */
+#define BTA_AV_NUM_LINKS AVDT_NUM_LINKS
+
+#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + \
+ (((uint32_t)(*(p))) << 16)); \
+ (p) += 3; \
+ }
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+
+/* function types for call-out functions */
+typedef bool (*tBTA_AV_CO_INIT)(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg);
+typedef void (*tBTA_AV_CO_DISC_RES)(tBTA_AV_HNDL hndl, uint8_t num_seps,
+ uint8_t num_snk, uint8_t num_src,
+ BD_ADDR addr, uint16_t uuid_local);
+typedef tA2DP_STATUS (*tBTA_AV_CO_GETCFG)(tBTA_AV_HNDL hndl,
+ uint8_t* p_codec_info,
+ uint8_t* p_sep_info_idx, uint8_t seid,
+ uint8_t* p_num_protect,
+ uint8_t* p_protect_info);
+typedef void (*tBTA_AV_CO_SETCFG)(tBTA_AV_HNDL hndl,
+ const uint8_t* p_codec_info, uint8_t seid,
+ BD_ADDR addr, uint8_t num_protect,
+ const uint8_t* p_protect_info,
+ uint8_t t_local_sep, uint8_t avdt_handle);
+typedef void (*tBTA_AV_CO_OPEN)(tBTA_AV_HNDL hndl, uint16_t mtu);
+typedef void (*tBTA_AV_CO_CLOSE)(tBTA_AV_HNDL hndl);
+typedef void (*tBTA_AV_CO_START)(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+ bool* p_no_rtp_hdr);
+typedef void (*tBTA_AV_CO_STOP)(tBTA_AV_HNDL hndl);
+typedef void* (*tBTA_AV_CO_DATAPATH)(const uint8_t* p_codec_info,
+ uint32_t* p_timestamp);
+typedef void (*tBTA_AV_CO_DELAY)(tBTA_AV_HNDL hndl, uint16_t delay);
+typedef void (*tBTA_AV_CO_UPDATE_MTU)(tBTA_AV_HNDL hndl, uint16_t mtu);
+
+/* the call-out functions for one stream */
+typedef struct {
+ tBTA_AV_CO_INIT init;
+ tBTA_AV_CO_DISC_RES disc_res;
+ tBTA_AV_CO_GETCFG getcfg;
+ tBTA_AV_CO_SETCFG setcfg;
+ tBTA_AV_CO_OPEN open;
+ tBTA_AV_CO_CLOSE close;
+ tBTA_AV_CO_START start;
+ tBTA_AV_CO_STOP stop;
+ tBTA_AV_CO_DATAPATH data;
+ tBTA_AV_CO_DELAY delay;
+ tBTA_AV_CO_UPDATE_MTU update_mtu;
+} tBTA_AV_CO_FUNCTS;
+
+/* data type for BTA_AV_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AV_CBACK* p_cback;
+ tBTA_AV_FEAT features;
+ tBTA_SEC sec_mask;
+} tBTA_AV_API_ENABLE;
+
+/* data type for BTA_AV_API_REGISTER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ char p_service_name[BTA_SERVICE_NAME_LEN + 1];
+ uint8_t app_id;
+ tBTA_AV_SINK_DATA_CBACK* p_app_sink_data_cback;
+ uint16_t service_uuid;
+} tBTA_AV_API_REG;
+
+enum {
+ BTA_AV_RS_NONE, /* straight API call */
+ BTA_AV_RS_OK, /* the role switch result - successful */
+ BTA_AV_RS_FAIL, /* the role switch result - failed */
+ BTA_AV_RS_DONE /* the role switch is done - continue */
+};
+typedef uint8_t tBTA_AV_RS_RES;
+/* data type for BTA_AV_API_OPEN_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ bool use_rc;
+ tBTA_SEC sec_mask;
+ tBTA_AV_RS_RES switch_res;
+ uint16_t uuid; /* uuid of initiator */
+} tBTA_AV_API_OPEN;
+
+/* data type for BTA_AV_API_STOP_EVT */
+typedef struct {
+ BT_HDR hdr;
+ bool suspend;
+ bool flush;
+ bool reconfig_stop; // True if the stream is stopped for reconfiguration
+} tBTA_AV_API_STOP;
+
+/* data type for BTA_AV_API_DISCONNECT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_AV_API_DISCNT;
+
+/* data type for BTA_AV_API_PROTECT_REQ_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t* p_data;
+ uint16_t len;
+} tBTA_AV_API_PROTECT_REQ;
+
+/* data type for BTA_AV_API_PROTECT_RSP_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t* p_data;
+ uint16_t len;
+ uint8_t error_code;
+} tBTA_AV_API_PROTECT_RSP;
+
+/* data type for BTA_AV_API_REMOTE_CMD_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tAVRC_MSG_PASS msg;
+ uint8_t label;
+} tBTA_AV_API_REMOTE_CMD;
+
+/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */
+typedef struct {
+ BT_HDR hdr;
+ tAVRC_MSG_VENDOR msg;
+ uint8_t label;
+} tBTA_AV_API_VENDOR;
+
+/* data type for BTA_AV_API_RC_OPEN_EVT */
+typedef struct { BT_HDR hdr; } tBTA_AV_API_OPEN_RC;
+
+/* data type for BTA_AV_API_RC_CLOSE_EVT */
+typedef struct { BT_HDR hdr; } tBTA_AV_API_CLOSE_RC;
+
+/* data type for BTA_AV_API_META_RSP_EVT */
+typedef struct {
+ BT_HDR hdr;
+ bool is_rsp;
+ uint8_t label;
+ tBTA_AV_CODE rsp_code;
+ BT_HDR* p_pkt;
+} tBTA_AV_API_META_RSP;
+
+/* data type for BTA_AV_API_RECONFIG_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t codec_info[AVDT_CODEC_SIZE]; /* codec configuration */
+ uint8_t* p_protect_info;
+ uint8_t num_protect;
+ bool suspend;
+ uint8_t sep_info_idx;
+} tBTA_AV_API_RCFG;
+
+/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AV_HNDL hndl;
+ uint8_t err_code;
+ uint8_t category;
+ uint8_t num_seid;
+ uint8_t* p_seid;
+ bool recfg_needed;
+ uint8_t avdt_handle; /* local sep type for which this stream will be set up */
+} tBTA_AV_CI_SETCONFIG;
+
+/* data type for all stream events from AVDTP */
+typedef struct {
+ BT_HDR hdr;
+ tAVDT_CFG cfg; /* configuration/capabilities parameters */
+ tAVDT_CTRL msg; /* AVDTP callback message parameters */
+ BD_ADDR bd_addr; /* bd address */
+ uint8_t handle;
+ uint8_t avdt_event;
+ bool initiator; /* true, if local device initiates the SUSPEND */
+} tBTA_AV_STR_MSG;
+
+/* data type for BTA_AV_AVRC_MSG_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tAVRC_MSG msg;
+ uint8_t handle;
+ uint8_t label;
+ uint8_t opcode;
+} tBTA_AV_RC_MSG;
+
+/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR peer_addr;
+ uint8_t handle;
+} tBTA_AV_RC_CONN_CHG;
+
+/* data type for BTA_AV_CONN_CHG_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR peer_addr;
+ bool is_up;
+} tBTA_AV_CONN_CHG;
+
+/* data type for BTA_AV_ROLE_CHANGE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t new_role;
+ uint8_t hci_status;
+} tBTA_AV_ROLE_RES;
+
+/* data type for BTA_AV_SDP_DISC_OK_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t avdt_version; /* AVDTP protocol version */
+} tBTA_AV_SDP_RES;
+
+/* data type for BTA_AV_API_OFFLOAD_RSP_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_AV_STATUS status;
+} tBTA_AV_API_STATUS_RSP;
+
+/* type for SEP control block */
+typedef struct {
+ uint8_t av_handle; /* AVDTP handle */
+ uint8_t tsep; /* SEP type of local SEP */
+ uint8_t codec_info[AVDT_CODEC_SIZE]; /* Codec info */
+ tBTA_AV_SINK_DATA_CBACK*
+ p_app_sink_data_cback; /* Sink application callback for media packets */
+} tBTA_AV_SEP;
+
+/* initiator/acceptor role for adaption */
+#define BTA_AV_ROLE_AD_INT 0x00 /* initiator */
+#define BTA_AV_ROLE_AD_ACP 0x01 /* acceptor */
+
+/* initiator/acceptor signaling roles */
+#define BTA_AV_ROLE_START_ACP 0x00
+#define BTA_AV_ROLE_START_INT 0x10 /* do not change this value */
+
+#define BTA_AV_ROLE_SUSPEND 0x20 /* suspending on start */
+#define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */
+
+/* union of all event datatypes */
+typedef union {
+ BT_HDR hdr;
+ tBTA_AV_API_ENABLE api_enable;
+ tBTA_AV_API_REG api_reg;
+ tBTA_AV_API_OPEN api_open;
+ tBTA_AV_API_STOP api_stop;
+ tBTA_AV_API_DISCNT api_discnt;
+ tBTA_AV_API_PROTECT_REQ api_protect_req;
+ tBTA_AV_API_PROTECT_RSP api_protect_rsp;
+ tBTA_AV_API_REMOTE_CMD api_remote_cmd;
+ tBTA_AV_API_VENDOR api_vendor;
+ tBTA_AV_API_RCFG api_reconfig;
+ tBTA_AV_CI_SETCONFIG ci_setconfig;
+ tBTA_AV_STR_MSG str_msg;
+ tBTA_AV_RC_MSG rc_msg;
+ tBTA_AV_RC_CONN_CHG rc_conn_chg;
+ tBTA_AV_CONN_CHG conn_chg;
+ tBTA_AV_ROLE_RES role_res;
+ tBTA_AV_SDP_RES sdp_res;
+ tBTA_AV_API_META_RSP api_meta_rsp;
+ tBTA_AV_API_STATUS_RSP api_status_rsp;
+} tBTA_AV_DATA;
+
+typedef union {
+ tBTA_AV_API_OPEN open; /* used only before open and role switch
+ is needed on another AV channel */
+} tBTA_AV_Q_INFO;
+
+#define BTA_AV_Q_TAG_OPEN 0x01 /* after API_OPEN, before STR_OPENED */
+#define BTA_AV_Q_TAG_START 0x02 /* before start sending media packets */
+#define BTA_AV_Q_TAG_STREAM 0x03 /* during streaming */
+
+#define BTA_AV_WAIT_ACP_CAPS_ON 0x01 /* retriving the peer capabilities */
+#define BTA_AV_WAIT_ACP_CAPS_STARTED \
+ 0x02 /* started while retriving peer capabilities */
+#define BTA_AV_WAIT_ROLE_SW_RES_OPEN \
+ 0x04 /* waiting for role switch result after API_OPEN, before STR_OPENED */
+#define BTA_AV_WAIT_ROLE_SW_RES_START \
+ 0x08 /* waiting for role switch result before streaming */
+#define BTA_AV_WAIT_ROLE_SW_STARTED \
+ 0x10 /* started while waiting for role switch result */
+#define BTA_AV_WAIT_ROLE_SW_RETRY 0x20 /* set when retry on timeout */
+#define BTA_AV_WAIT_CHECK_RC \
+ 0x40 /* set when the timer is used by role switch */
+#define BTA_AV_WAIT_ROLE_SW_FAILED 0x80 /* role switch failed */
+
+#define BTA_AV_WAIT_ROLE_SW_BITS \
+ (BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START | \
+ BTA_AV_WAIT_ROLE_SW_STARTED | BTA_AV_WAIT_ROLE_SW_RETRY)
+
+/* Bitmap for collision, coll_mask */
+#define BTA_AV_COLL_INC_TMR \
+ 0x01 /* Timer is running for incoming L2C connection */
+#define BTA_AV_COLL_API_CALLED \
+ 0x02 /* API open was called while incoming timer is running */
+
+/* type for AV stream control block */
+typedef struct {
+ const tBTA_AV_ACT* p_act_tbl; /* the action table for stream state machine */
+ const tBTA_AV_CO_FUNCTS* p_cos; /* the associated callout functions */
+ bool sdp_discovery_started; /* variable to determine whether SDP is started */
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tBTA_AV_SEP seps[BTAV_A2DP_CODEC_INDEX_MAX + 1];
+#else
+ tBTA_AV_SEP seps[BTAV_A2DP_CODEC_INDEX_MAX];
+#endif
+ tAVDT_CFG* p_cap; /* buffer used for get capabilities */
+ list_t* a2dp_list; /* used for audio channels only */
+ tBTA_AV_Q_INFO q_info;
+ tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */
+ tAVDT_CFG cfg; /* local SEP configuration */
+ alarm_t* avrc_ct_timer; /* delay timer for AVRC CT */
+ BD_ADDR peer_addr; /* peer BD address */
+ uint16_t l2c_cid; /* L2CAP channel ID */
+ uint16_t stream_mtu; /* MTU of stream */
+ uint16_t avdt_version; /* the avdt version of peer device */
+ tBTA_SEC sec_mask; /* security mask */
+ uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
+ bool cong; /* true if AVDTP congested */
+ tBTA_AV_STATUS open_status; /* open failure status */
+ tBTA_AV_CHNL chnl; /* the channel: audio/video */
+ tBTA_AV_HNDL hndl; /* the handle: ((hdi + 1)|chnl) */
+ uint16_t cur_psc_mask; /* Protocol service capabilities mask for current
+ connection */
+ uint8_t avdt_handle; /* AVDTP handle */
+ uint8_t hdi; /* the index to SCB[] */
+ uint8_t num_seps; /* number of seps returned by stream discovery */
+ uint8_t num_disc_snks; /* number of discovered snks */
+ uint8_t num_disc_srcs; /* number of discovered srcs */
+ uint8_t sep_info_idx; /* current index into sep_info */
+ uint8_t sep_idx; /* current index into local seps[] */
+ uint8_t rcfg_idx; /* reconfig requested index into sep_info */
+ uint8_t state; /* state machine state */
+ uint8_t avdt_label; /* AVDTP label */
+ uint8_t app_id; /* application id */
+ uint8_t num_recfg; /* number of reconfigure sent */
+ uint8_t role;
+ uint8_t l2c_bufs; /* the number of buffers queued to L2CAP */
+ uint8_t rc_handle; /* connected AVRCP handle */
+ bool use_rc; /* true if AVRCP is allowed */
+ bool started; /* true if stream started */
+ A2dpCodecConfig* current_codec; /* The current A2DP codec */
+ uint8_t
+ co_started; /* non-zero, if stream started from call-out perspective */
+ bool recfg_sup; /* true if the first attempt to reconfigure the stream was
+ successfull, else False if command fails */
+ bool suspend_sup; /* true if Suspend stream is supported, else false if
+ suspend command fails */
+ bool deregistring; /* true if deregistering */
+ bool sco_suspend; /* true if SUSPEND is issued automatically for SCO */
+ uint8_t coll_mask; /* Mask to check incoming and outgoing collision */
+ tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */
+ uint8_t wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */
+ uint8_t q_tag; /* identify the associated q_info union member */
+ bool no_rtp_hdr; /* true if add no RTP header*/
+ uint16_t uuid_int; /*intended UUID of Initiator to connect to */
+ bool offload_start_pending;
+ bool skip_sdp; /* Decides if sdp to be done prior to profile connection */
+} tBTA_AV_SCB;
+
+#define BTA_AV_RC_ROLE_MASK 0x10
+#define BTA_AV_RC_ROLE_INT 0x00
+#define BTA_AV_RC_ROLE_ACP 0x10
+
+#define BTA_AV_RC_CONN_MASK 0x20
+
+/* type for AV RCP control block */
+/* index to this control block is the rc handle */
+typedef struct {
+ uint8_t status;
+ uint8_t handle;
+ uint8_t shdl; /* stream handle (hdi + 1) */
+ uint8_t lidx; /* (index+1) to LCB */
+ tBTA_AV_FEAT peer_features; /* peer features mask */
+} tBTA_AV_RCB;
+#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2)
+
+enum { BTA_AV_LCB_FREE, BTA_AV_LCB_FIND };
+
+/* type for AV ACL Link control block */
+typedef struct {
+ BD_ADDR addr; /* peer BD address */
+ uint8_t conn_msk; /* handle mask of connected stream handle */
+ uint8_t lidx; /* index + 1 */
+} tBTA_AV_LCB;
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_SACT)(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+
+/* type for AV control block */
+typedef struct {
+ tBTA_AV_SCB* p_scb[BTA_AV_NUM_STRS]; /* stream control block */
+ tSDP_DISCOVERY_DB* p_disc_db; /* pointer to discovery database */
+ tBTA_AV_CBACK* p_cback; /* application callback function */
+ tBTA_AV_RCB rcb[BTA_AV_NUM_RCB]; /* RCB control block */
+ tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS + 1]; /* link control block */
+ alarm_t* link_signalling_timer;
+ alarm_t*
+ accept_signalling_timer; /* timer to monitor signalling when accepting */
+ uint32_t sdp_a2dp_handle; /* SDP record handle for audio src */
+ uint32_t sdp_a2dp_snk_handle; /* SDP record handle for audio snk */
+ uint32_t sdp_vdp_handle; /* SDP record handle for video src */
+ tBTA_AV_FEAT features; /* features mask */
+ tBTA_SEC sec_mask; /* security mask */
+ tBTA_AV_HNDL handle; /* the handle for SDP activity */
+ bool disabling; /* true if api disabled called */
+ uint8_t
+ disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */
+ uint8_t state; /* state machine state */
+ uint8_t conn_rc; /* handle mask of connected RCP channels */
+ uint8_t conn_audio; /* handle mask of connected audio channels */
+ uint8_t conn_video; /* handle mask of connected video channels */
+ uint8_t conn_lcb; /* index mask of used LCBs */
+ uint8_t audio_open_cnt; /* number of connected audio channels */
+ uint8_t reg_audio; /* handle mask of registered audio channels */
+ uint8_t reg_video; /* handle mask of registered video channels */
+ uint8_t rc_acp_handle;
+ uint8_t rc_acp_idx; /* (index + 1) to RCB */
+ uint8_t rs_idx; /* (index + 1) to SCB for the one waiting for RS on open */
+ bool sco_occupied; /* true if SCO is being used or call is in progress */
+ uint8_t audio_streams; /* handle mask of streaming audio channels */
+ uint8_t video_streams; /* handle mask of streaming video channels */
+} tBTA_AV_CB;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* control block declaration */
+extern tBTA_AV_CB bta_av_cb;
+
+/* config struct */
+extern tBTA_AV_CFG* p_bta_av_cfg;
+extern const tBTA_AV_CFG bta_avk_cfg;
+extern const tBTA_AV_CFG bta_av_cfg;
+
+/* rc id config struct */
+extern uint16_t* p_bta_av_rc_id;
+extern uint16_t* p_bta_av_rc_id_ac;
+
+extern const tBTA_AV_SACT bta_av_a2dp_action[];
+extern const tBTA_AV_CO_FUNCTS bta_av_a2dp_cos;
+extern tAVDT_CTRL_CBACK* const bta_av_dt_cback[];
+extern void bta_av_sink_data_cback(uint8_t handle, BT_HDR* p_pkt,
+ uint32_t time_stamp, uint8_t m_pt);
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+/* utility functions */
+extern tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle);
+extern bool bta_av_chk_start(tBTA_AV_SCB* p_scb);
+extern void bta_av_restore_switch(void);
+extern uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, uint16_t mtu);
+extern void bta_av_conn_cback(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+extern uint8_t bta_av_rc_create(tBTA_AV_CB* p_cb, uint8_t role, uint8_t shdl,
+ uint8_t lidx);
+extern void bta_av_stream_chg(tBTA_AV_SCB* p_scb, bool started);
+extern bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb);
+extern bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb);
+extern void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb);
+extern bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb);
+extern void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb);
+extern tBTA_AV_LCB* bta_av_find_lcb(BD_ADDR addr, uint8_t op);
+
+/* main functions */
+extern void bta_av_api_deregister(tBTA_AV_DATA* p_data);
+extern void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf);
+extern void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event,
+ tBTA_AV_DATA* p_data);
+extern void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
+ tBTA_AV_DATA* p_data);
+extern bool bta_av_hdl_event(BT_HDR* p_msg);
+extern const char* bta_av_evt_code(uint16_t evt_code);
+extern bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb);
+extern bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits);
+extern bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb);
+
+/* nsm action functions */
+extern void bta_av_api_disconnect(tBTA_AV_DATA* p_data);
+extern void bta_av_sig_chg(tBTA_AV_DATA* p_data);
+extern void bta_av_signalling_timer(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_disc_done(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_closed(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_browse_opened(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_browse_closed(tBTA_AV_DATA* p_data);
+extern void bta_av_rc_disc(uint8_t disc);
+extern void bta_av_conn_chg(tBTA_AV_DATA* p_data);
+extern void bta_av_dereg_comp(tBTA_AV_DATA* p_data);
+
+/* sm action functions */
+extern void bta_av_disable(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_opened(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_remote_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_vendor_cmd(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_vendor_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_close(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_meta_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_free_rsp(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+extern void bta_av_rc_free_browse_msg(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+
+extern tBTA_AV_RCB* bta_av_get_rcb_by_shdl(uint8_t shdl);
+extern void bta_av_del_rc(tBTA_AV_RCB* p_rcb);
+
+/* ssm action functions */
+extern void bta_av_do_disc_a2dp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_free_sdb(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disconnect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_setconfig_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_do_close(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_connect_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_sdp_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disc_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_disc_res_as_acp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_getcap_results(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_setconfig_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_discover_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_conn_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_do_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_stopped(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_reconfig(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_data_path(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_start_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_start_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_str_closed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_clr_cong(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_suspend_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_str_ok(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_failed(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_connect(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_discntd(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_suspend_cont(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_cfm(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rcfg_open(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_security_rej(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_chk_2nd_start(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_save_caps(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rej_conn(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_rej_conn(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_set_use_rc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_cco_close(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_switch_role(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_role_res(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_delay_co(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_open_at_inc(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+extern void bta_av_offload_rsp(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data);
+/** M: Bug fix for update avrcp version @{ */
+extern void bta_av_rc_disc(uint8_t disc, bool get_rc_version);
+/** @} */
+
+#endif /* BTA_AV_INT_H */
diff --git a/mtkbt/code/bt/bta/av/bta_av_main.cc b/mtkbt/code/bt/bta/av/bta_av_main.cc
new file mode 100755
index 0000000..0610394
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_main.cc
@@ -0,0 +1,1357 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_av"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+#include "bta_av_co.h"
+#include "bta_av_int.h"
+#include "btif/include/btif_av_co.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "utl.h"
+
+#if (BTA_AR_INCLUDED == TRUE)
+#include "bta_ar_api.h"
+#endif
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+#ifndef BTA_AV_RET_TOUT
+#define BTA_AV_RET_TOUT 4
+#endif
+
+#ifndef BTA_AV_SIG_TOUT
+#define BTA_AV_SIG_TOUT 4
+#endif
+
+#ifndef BTA_AV_IDLE_TOUT
+#define BTA_AV_IDLE_TOUT 10
+#endif
+
+/* the delay time in milliseconds to retry role switch */
+#ifndef BTA_AV_RS_TIME_VAL
+#define BTA_AV_RS_TIME_VAL 1000
+#endif
+
+#ifndef AVRCP_VERSION_PROPERTY
+#define AVRCP_VERSION_PROPERTY "persist.bluetooth.avrcpversion"
+#endif
+
+#ifndef AVRCP_1_6_STRING
+#define AVRCP_1_6_STRING "avrcp16"
+#endif
+
+#ifndef AVRCP_1_5_STRING
+#define AVRCP_1_5_STRING "avrcp15"
+#endif
+
+#ifndef AVRCP_1_4_STRING
+#define AVRCP_1_4_STRING "avrcp14"
+#endif
+
+/* state machine states */
+enum { BTA_AV_INIT_ST, BTA_AV_OPEN_ST };
+
+/* state machine action enumeration list */
+enum {
+ BTA_AV_DISABLE,
+ BTA_AV_RC_OPENED,
+ BTA_AV_RC_REMOTE_CMD,
+ BTA_AV_RC_VENDOR_CMD,
+ BTA_AV_RC_VENDOR_RSP,
+ BTA_AV_RC_FREE_RSP,
+ BTA_AV_RC_FREE_BROWSE_MSG,
+ BTA_AV_RC_META_RSP,
+ BTA_AV_RC_MSG,
+ BTA_AV_RC_CLOSE,
+ BTA_AV_RC_BROWSE_CLOSE,
+ BTA_AV_NUM_ACTIONS
+};
+
+#define BTA_AV_IGNORE BTA_AV_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AV_ACTION)(tBTA_AV_CB* p_cb, tBTA_AV_DATA* p_data);
+
+/* action functions */
+const tBTA_AV_ACTION bta_av_action[] = {
+ bta_av_disable,
+ bta_av_rc_opened,
+ bta_av_rc_remote_cmd,
+ bta_av_rc_vendor_cmd,
+ bta_av_rc_vendor_rsp,
+ bta_av_rc_free_rsp,
+ bta_av_rc_free_browse_msg,
+ bta_av_rc_meta_rsp,
+ bta_av_rc_msg,
+ bta_av_rc_close,
+};
+
+/* state table information */
+#define BTA_AV_ACTION_COL 0 /* position of actions */
+#define BTA_AV_NEXT_STATE 1 /* position of next state */
+#define BTA_AV_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for init state */
+static const uint8_t bta_av_st_init[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST},
+ /* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+ /* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+ /* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+ /* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST},
+ /* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+ /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST},
+ /* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_BROWSE_MSG, BTA_AV_INIT_ST},
+ /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+};
+
+/* state table for open state */
+static const uint8_t bta_av_st_open[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST},
+ /* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST},
+ /* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST},
+ /* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST},
+ /* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST},
+ /* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST},
+ /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST},
+ /* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST},
+ /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AV_ST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_ST_TBL bta_av_st_tbl[] = {bta_av_st_init, bta_av_st_open};
+
+typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA* p_data);
+static void bta_av_api_enable(tBTA_AV_DATA* p_data);
+static void bta_av_api_register(tBTA_AV_DATA* p_data);
+static void bta_av_ci_data(tBTA_AV_DATA* p_data);
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(tBTA_AV_DATA* p_data);
+#endif
+static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data);
+
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+static void bta_av_sys_rs_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+
+/* action functions */
+const tBTA_AV_NSM_ACT bta_av_nsm_act[] = {
+ bta_av_api_enable, /* BTA_AV_API_ENABLE_EVT */
+ bta_av_api_register, /* BTA_AV_API_REGISTER_EVT */
+ bta_av_api_deregister, /* BTA_AV_API_DEREGISTER_EVT */
+ bta_av_api_disconnect, /* BTA_AV_API_DISCONNECT_EVT */
+ bta_av_ci_data, /* BTA_AV_CI_SRC_DATA_READY_EVT */
+ bta_av_sig_chg, /* BTA_AV_SIG_CHG_EVT */
+ bta_av_signalling_timer, /* BTA_AV_SIGNALLING_TIMER_EVT */
+ bta_av_rc_disc_done, /* BTA_AV_SDP_AVRC_DISC_EVT */
+ bta_av_rc_closed, /* BTA_AV_AVRC_CLOSE_EVT */
+ bta_av_rc_browse_opened, /* BTA_AV_AVRC_BROWSE_OPEN_EVT */
+ bta_av_rc_browse_closed, /* BTA_AV_AVRC_BROWSE_CLOSE_EVT */
+ bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */
+ bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */
+#if (AVDT_REPORTING == TRUE)
+ bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */
+#endif
+ bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */
+ bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */
+};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* AV control block */
+tBTA_AV_CB bta_av_cb;
+
+static const char* bta_av_st_code(uint8_t state);
+
+/*******************************************************************************
+ *
+ * Function bta_av_api_enable
+ *
+ * Description Handle an API enable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_api_enable(tBTA_AV_DATA* p_data) {
+ /* initialize control block */
+ memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB));
+
+ for (int i = 0; i < BTA_AV_NUM_RCB; i++)
+ bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE;
+
+ bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE;
+
+ /*
+ * TODO: The "disable" event handling is missing - there we need
+ * to alarm_free() the alarms below.
+ */
+ bta_av_cb.link_signalling_timer = alarm_new("bta_av.link_signalling_timer");
+ bta_av_cb.accept_signalling_timer =
+ alarm_new("bta_av.accept_signalling_timer");
+
+ /* store parameters */
+ bta_av_cb.p_cback = p_data->api_enable.p_cback;
+ bta_av_cb.features = p_data->api_enable.features;
+ bta_av_cb.sec_mask = p_data->api_enable.sec_mask;
+
+ tBTA_AV_ENABLE enable;
+ enable.features = bta_av_cb.features;
+
+ /* Register for SCO change event */
+ if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) {
+ bta_sys_sco_register(bta_av_sco_chg_cback);
+ }
+
+ /* call callback with enable event */
+ (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV*)&enable);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_addr_to_scb
+ *
+ * Description find the stream control block by the peer addr
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTA_AV_SCB* bta_av_addr_to_scb(BD_ADDR bd_addr) {
+ tBTA_AV_SCB* p_scb = NULL;
+ int xx;
+
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ if (bta_av_cb.p_scb[xx]) {
+ if (!bdcmp(bd_addr, bta_av_cb.p_scb[xx]->peer_addr)) {
+ p_scb = bta_av_cb.p_scb[xx];
+ break;
+ }
+ }
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_hndl_to_scb
+ *
+ * Description find the stream control block by the handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_AV_SCB* bta_av_hndl_to_scb(uint16_t handle) {
+ tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle;
+ tBTA_AV_SCB* p_scb = NULL;
+ uint8_t idx = (hndl & BTA_AV_HNDL_MSK);
+
+ if (idx && (idx <= BTA_AV_NUM_STRS)) {
+ p_scb = bta_av_cb.p_scb[idx - 1];
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_alloc_scb
+ *
+ * Description allocate stream control block,
+ * register the service to stack
+ * create SDP record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTA_AV_SCB* bta_av_alloc_scb(tBTA_AV_CHNL chnl) {
+ tBTA_AV_SCB* p_ret = NULL;
+ int xx;
+ tBTA_AV_STATUS sts = BTA_AV_SUCCESS;
+
+ if (chnl == BTA_AV_CHNL_VIDEO) {
+ if (p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL) {
+ APPL_TRACE_ERROR("Video streaming not supported");
+ sts = BTA_AV_FAIL;
+ } else {
+ /* allow only one Video channel */
+ if (bta_av_cb.reg_video) {
+ APPL_TRACE_ERROR("Already registered");
+ sts = BTA_AV_FAIL;
+ }
+ }
+ } else if (chnl != BTA_AV_CHNL_AUDIO) {
+ APPL_TRACE_ERROR("bad channel: %d", chnl);
+ sts = BTA_AV_FAIL;
+ }
+
+ if (sts == BTA_AV_SUCCESS) {
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ if (bta_av_cb.p_scb[xx] == NULL) {
+ /* found an empty spot */
+ p_ret = (tBTA_AV_SCB*)osi_calloc(sizeof(tBTA_AV_SCB));
+ p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE;
+ p_ret->chnl = chnl;
+ p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl);
+ p_ret->hdi = xx;
+ p_ret->a2dp_list = list_new(NULL);
+ p_ret->avrc_ct_timer = alarm_new("bta_av.avrc_ct_timer");
+ bta_av_cb.p_scb[xx] = p_ret;
+ break;
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+void bta_av_conn_cback(UNUSED_ATTR uint8_t handle, BD_ADDR bd_addr,
+ uint8_t event, tAVDT_CTRL* p_data) {
+ uint16_t evt = 0;
+ tBTA_AV_SCB* p_scb = NULL;
+
+#if (BTA_AR_INCLUDED == TRUE)
+ if (event == BTA_AR_AVDT_CONN_EVT || event == AVDT_CONNECT_IND_EVT ||
+ event == AVDT_DISCONNECT_IND_EVT)
+#else
+ if (event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT)
+#endif
+ {
+ evt = BTA_AV_SIG_CHG_EVT;
+ if (event == AVDT_DISCONNECT_IND_EVT) {
+ p_scb = bta_av_addr_to_scb(bd_addr);
+ } else if (event == AVDT_CONNECT_IND_EVT) {
+ APPL_TRACE_DEBUG("%s: CONN_IND is ACP:%d", __func__,
+ p_data->hdr.err_param);
+ }
+
+ tBTA_AV_STR_MSG* p_msg =
+ (tBTA_AV_STR_MSG*)osi_malloc(sizeof(tBTA_AV_STR_MSG));
+ p_msg->hdr.event = evt;
+ p_msg->hdr.layer_specific = event;
+ p_msg->hdr.offset = p_data->hdr.err_param;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ if (p_scb) {
+ APPL_TRACE_DEBUG("scb hndl x%x, role x%x", p_scb->hndl, p_scb->role);
+ }
+ APPL_TRACE_DEBUG("conn_cback bd_addr:%02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_av_a2dp_report_cback
+ *
+ * Description A2DP report callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_a2dp_report_cback(UNUSED_ATTR uint8_t handle,
+ UNUSED_ATTR AVDT_REPORT_TYPE type,
+ UNUSED_ATTR tAVDT_REPORT_DATA* p_data) {
+ /* Do not need to handle report data for now.
+ * This empty function is here for conformance reasons. */
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_av_api_register
+ *
+ * Description allocate stream control block,
+ * register the service to stack
+ * create SDP record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_api_register(tBTA_AV_DATA* p_data) {
+ tBTA_AV_REGISTER registr;
+ tBTA_AV_SCB* p_scb; /* stream control block */
+ tAVDT_REG reg;
+ tAVDT_CS cs;
+ char* p_service_name;
+ tBTA_UTL_COD cod;
+
+ memset(&cs, 0, sizeof(tAVDT_CS));
+
+ registr.status = BTA_AV_FAIL_RESOURCES;
+ registr.app_id = p_data->api_reg.app_id;
+ registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific;
+
+ uint16_t profile_initialized = p_data->api_reg.service_uuid;
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+ p_bta_av_cfg = (tBTA_AV_CFG*)&bta_avk_cfg;
+ } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+ p_bta_av_cfg = (tBTA_AV_CFG*)&bta_av_cfg;
+ }
+
+ APPL_TRACE_DEBUG("%s: profile: 0x%x", __func__, profile_initialized);
+ if (p_bta_av_cfg == NULL) {
+ APPL_TRACE_ERROR("AV configuration is null!");
+ return;
+ }
+
+ do {
+ p_scb = bta_av_alloc_scb(registr.chnl);
+ if (p_scb == NULL) {
+ APPL_TRACE_ERROR("failed to alloc SCB");
+ break;
+ }
+
+ registr.hndl = p_scb->hndl;
+ p_scb->app_id = registr.app_id;
+
+ /* initialize the stream control block */
+ registr.status = BTA_AV_SUCCESS;
+
+ if ((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0) {
+ /* the first channel registered. register to AVDTP */
+ reg.ctrl_mtu = p_bta_av_cfg->sig_mtu;
+ reg.ret_tout = BTA_AV_RET_TOUT;
+ reg.sig_tout = BTA_AV_SIG_TOUT;
+ reg.idle_tout = BTA_AV_IDLE_TOUT;
+ reg.sec_mask = bta_av_cb.sec_mask;
+#if (BTA_AR_INCLUDED == TRUE)
+ bta_ar_reg_avdt(&reg, bta_av_conn_cback, BTA_ID_AV);
+#endif
+ bta_sys_role_chg_register(&bta_av_sys_rs_cback);
+
+ /* create remote control TG service if required */
+ if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) {
+/* register with no authorization; let AVDTP use authorization instead */
+#if (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
+ BTA_ID_AV);
+#endif
+
+ /* For the Audio Sink role we support additional TG 1.3 to support
+ * absolute volume.
+ */
+ uint16_t profile_version = AVRC_REV_1_0;
+
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+ // This check can override the AVRCP profile version with a property
+ char avrcp_version[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(AVRCP_VERSION_PROPERTY, avrcp_version,
+ AVRCP_1_4_STRING);
+ LOG_INFO(LOG_TAG, "AVRCP version used for sdp: \"%s\"",
+ avrcp_version);
+
+ if (!strncmp(AVRCP_1_6_STRING, avrcp_version,
+ sizeof(AVRCP_1_6_STRING))) {
+ profile_version = AVRC_REV_1_6;
+ } else if (!strncmp(AVRCP_1_5_STRING, avrcp_version,
+ sizeof(AVRCP_1_5_STRING))) {
+ profile_version = AVRC_REV_1_5;
+ } else {
+ profile_version = AVRC_REV_1_4;
+ }
+ } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+ // Initialize AVRCP1.4 to provide Absolute Volume control.
+ profile_version = AVRC_REV_1_4;
+ }
+
+ bta_ar_reg_avrc(
+ UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target", NULL,
+ p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE), profile_version);
+#endif
+ }
+
+ /* Set the Capturing service class bit */
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE)
+ cod.service = BTM_COD_SERVICE_CAPTURING;
+ else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK)
+ cod.service = BTM_COD_SERVICE_RENDERING;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+ } /* if 1st channel */
+
+ /* get stream configuration and create stream */
+ cs.cfg.num_codec = 1;
+ cs.nsc_mask =
+ AVDT_NSC_RECONFIG |
+ ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY);
+ APPL_TRACE_DEBUG("nsc_mask: 0x%x", cs.nsc_mask);
+
+ if (p_data->api_reg.p_service_name[0] == 0) {
+ p_service_name = NULL;
+ } else {
+ p_service_name = p_data->api_reg.p_service_name;
+ }
+
+ p_scb->suspend_sup = true;
+ p_scb->recfg_sup = true;
+ p_scb->skip_sdp = false;
+
+ cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi];
+ if (registr.chnl == BTA_AV_CHNL_AUDIO) {
+ /* set up the audio stream control block */
+ p_scb->p_act_tbl = (const tBTA_AV_ACT*)bta_av_a2dp_action;
+ p_scb->p_cos = &bta_av_a2dp_cos;
+ p_scb->media_type = AVDT_MEDIA_TYPE_AUDIO;
+ cs.cfg.psc_mask = AVDT_PSC_TRANS;
+ cs.media_type = AVDT_MEDIA_TYPE_AUDIO;
+ cs.mtu = p_bta_av_cfg->audio_mtu;
+ cs.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ btav_a2dp_codec_index_t codec_index_min =
+ BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
+ btav_a2dp_codec_index_t codec_index_max =
+ BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
+
+#if (AVDT_REPORTING == TRUE)
+ if (bta_av_cb.features & BTA_AV_FEAT_REPORT) {
+ cs.cfg.psc_mask |= AVDT_PSC_REPORT;
+ cs.p_report_cback = bta_av_a2dp_report_cback;
+ }
+#endif
+ if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT)
+ cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT;
+
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+ cs.tsep = AVDT_TSEP_SRC;
+ codec_index_min = BTAV_A2DP_CODEC_INDEX_SOURCE_MIN;
+ codec_index_max = BTAV_A2DP_CODEC_INDEX_SOURCE_MAX;
+ } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+ cs.tsep = AVDT_TSEP_SNK;
+ cs.p_sink_data_cback = bta_av_sink_data_cback;
+ codec_index_min = BTAV_A2DP_CODEC_INDEX_SINK_MIN;
+ codec_index_max = BTAV_A2DP_CODEC_INDEX_SINK_MAX;
+ }
+
+ /* Initialize handles to zero */
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int xx = 0; xx < (BTAV_A2DP_CODEC_INDEX_MAX + 1); xx++) {
+#else
+ for (int xx = 0; xx < BTAV_A2DP_CODEC_INDEX_MAX; xx++) {
+#endif
+ p_scb->seps[xx].av_handle = 0;
+ }
+
+ /* keep the configuration in the stream control block */
+ memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG));
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = codec_index_min; i < (codec_index_max + 1); i++) {
+
+#else
+ for (int i = codec_index_min; i < codec_index_max; i++) {
+#endif
+ btav_a2dp_codec_index_t codec_index =
+ static_cast<btav_a2dp_codec_index_t>(i);
+ if (!(*bta_av_a2dp_cos.init)(codec_index, &cs.cfg)) {
+ continue;
+ }
+ if (AVDT_CreateStream(&p_scb->seps[codec_index].av_handle, &cs) !=
+ AVDT_SUCCESS) {
+ continue;
+ }
+ /* Save a copy of the codec */
+ memcpy(p_scb->seps[codec_index].codec_info, cs.cfg.codec_info,
+ AVDT_CODEC_SIZE);
+ p_scb->seps[codec_index].tsep = cs.tsep;
+ if (cs.tsep == AVDT_TSEP_SNK) {
+ p_scb->seps[codec_index].p_app_sink_data_cback =
+ p_data->api_reg.p_app_sink_data_cback;
+ } else {
+ /* In case of A2DP SOURCE we don't need a callback to
+ * handle media packets.
+ */
+ p_scb->seps[codec_index].p_app_sink_data_cback = NULL;
+ }
+ }
+
+ if (!bta_av_cb.reg_audio) {
+ bta_av_cb.sdp_a2dp_handle = 0;
+ bta_av_cb.sdp_a2dp_snk_handle = 0;
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+ /* create the SDP records on the 1st audio channel */
+ bta_av_cb.sdp_a2dp_handle = SDP_CreateRecord();
+ A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL,
+ A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_handle);
+ bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE);
+ } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+#if (BTA_AV_SINK_INCLUDED == TRUE)
+ bta_av_cb.sdp_a2dp_snk_handle = SDP_CreateRecord();
+ A2DP_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL,
+ A2DP_SUPF_PLAYER, bta_av_cb.sdp_a2dp_snk_handle);
+ bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK);
+#endif
+ }
+ /* start listening when A2DP is registered */
+ if (bta_av_cb.features & BTA_AV_FEAT_RCTG)
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+
+ /* if the AV and AVK are both supported, it cannot support the CT role
+ */
+ if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) {
+ /* if TG is not supported, we need to register to AVCT now */
+ if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) {
+#if (BTA_AR_INCLUDED == TRUE)
+#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE)
+ bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ bta_av_cb.sec_mask, BTA_ID_AV);
+#else
+ bta_ar_reg_avct(
+ p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu,
+ (uint8_t)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)),
+ BTA_ID_AV);
+#endif
+#endif
+ bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1);
+ }
+#if (BTA_AR_INCLUDED == TRUE)
+ /* create an SDP record as AVRC CT. We create 1.3 for SOURCE
+ * because we rely on feature bits being scanned by external
+ * devices more than the profile version itself.
+ *
+ * We create 1.4 for SINK since we support browsing.
+ */
+ if (profile_initialized == UUID_SERVCLASS_AUDIO_SOURCE) {
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+ AVRC_REV_1_3);
+ } else if (profile_initialized == UUID_SERVCLASS_AUDIO_SINK) {
+ bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL,
+ p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV,
+ (bta_av_cb.features & BTA_AV_FEAT_BROWSE),
+ AVRC_REV_1_6);
+ }
+#endif
+ }
+ }
+ bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
+ } else {
+ bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi);
+ bta_av_cb.sdp_vdp_handle = SDP_CreateRecord();
+ /* register the video channel */
+ /* no need to verify the function pointer here. it's verified prior */
+ (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb);
+ }
+ } while (0);
+
+ /* call callback with register event */
+ (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV*)&registr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_api_deregister
+ *
+ * Description de-register a channel
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_api_deregister(tBTA_AV_DATA* p_data) {
+ tBTA_AV_SCB* p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific);
+
+ if (p_scb) {
+ p_scb->deregistring = true;
+ bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data);
+ } else {
+ bta_av_dereg_comp(p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_ci_data
+ *
+ * Description Forward the BTA_AV_CI_SRC_DATA_READY_EVT to stream state
+ * machine.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_ci_data(tBTA_AV_DATA* p_data) {
+ tBTA_AV_SCB* p_scb;
+ int i;
+ uint8_t chnl = (uint8_t)p_data->hdr.layer_specific;
+
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if (p_scb && p_scb->chnl == chnl) {
+ bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_rpc_conn
+ *
+ * Description report report channel open
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (AVDT_REPORTING == TRUE)
+static void bta_av_rpc_conn(UNUSED_ATTR tBTA_AV_DATA* p_data) {}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_av_api_to_ssm
+ *
+ * Description forward the API request to stream state machine
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_api_to_ssm(tBTA_AV_DATA* p_data) {
+ int xx;
+ uint16_t event =
+ p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT;
+
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_chk_start
+ *
+ * Description if this is audio channel, check if more than one audio
+ * channel is connected & already started.
+ *
+ * Returns true, if need api_start
+ *
+ ******************************************************************************/
+bool bta_av_chk_start(tBTA_AV_SCB* p_scb) {
+ bool start = false;
+ tBTA_AV_SCB* p_scbi;
+ int i;
+
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ if ((bta_av_cb.audio_open_cnt >= 2) &&
+ ((0 ==
+ (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or */
+ (bta_av_cb.features &
+ BTA_AV_FEAT_ACP_START))) /* auto-starting option */
+ {
+ /* more than one audio channel is connected */
+ /* if this is the 2nd stream as ACP, give INT a chance to issue the START
+ * command */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scbi = bta_av_cb.p_scb[i];
+ if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) {
+ start = true;
+ /* may need to update the flush timeout of this already started stream
+ */
+ if (p_scbi->co_started != bta_av_cb.audio_open_cnt) {
+ p_scbi->co_started = bta_av_cb.audio_open_cnt;
+ L2CA_SetFlushTimeout(
+ p_scbi->peer_addr,
+ p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1]);
+ }
+ }
+ }
+ }
+ }
+ return start;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_restore_switch
+ *
+ * Description assume that the caller of this function already makes
+ * sure that there's only one ACL connection left
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_restore_switch(void) {
+ tBTA_AV_CB* p_cb = &bta_av_cb;
+ int i;
+ uint8_t mask;
+
+ APPL_TRACE_DEBUG("reg_audio: 0x%x", bta_av_cb.reg_audio);
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ if (p_cb->conn_audio == mask) {
+ if (p_cb->p_scb[i]) {
+ bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+ p_cb->p_scb[i]->peer_addr);
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sys_rs_cback
+ *
+ * Description Receives the role change event from dm
+ *
+ * Returns (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda)
+ *
+ ******************************************************************************/
+static void bta_av_sys_rs_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
+ uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ int i;
+ tBTA_AV_SCB* p_scb = NULL;
+ uint8_t cur_role;
+ uint8_t peer_idx = 0;
+
+ APPL_TRACE_DEBUG("bta_av_sys_rs_cback: %d", bta_av_cb.rs_idx);
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ /* loop through all the SCBs to find matching peer addresses and report the
+ * role change event */
+ /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */
+ p_scb = bta_av_cb.p_scb[i];
+ if (p_scb && (bdcmp(peer_addr, p_scb->peer_addr) == 0)) {
+ tBTA_AV_ROLE_RES* p_buf =
+ (tBTA_AV_ROLE_RES*)osi_malloc(sizeof(tBTA_AV_ROLE_RES));
+ APPL_TRACE_DEBUG("new_role:%d, hci_status:x%x hndl: x%x", id, app_id,
+ p_scb->hndl);
+ /*
+ if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS))
+ {
+ bta_sys_set_policy(BTA_ID_AV,
+ (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr);
+ }
+ */
+ p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT;
+ p_buf->hdr.layer_specific = p_scb->hndl;
+ p_buf->new_role = id;
+ p_buf->hci_status = app_id;
+ bta_sys_sendmsg(p_buf);
+
+ peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */
+ }
+ }
+
+ /* restore role switch policy, if role switch failed */
+ if ((HCI_SUCCESS != app_id) &&
+ (BTM_GetRole(peer_addr, &cur_role) == BTM_SUCCESS) &&
+ (cur_role == BTM_ROLE_SLAVE)) {
+ bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr);
+ }
+
+ /* if BTA_AvOpen() was called for other device, which caused the role switch
+ * of the peer_addr, */
+ /* we need to continue opening process for the BTA_AvOpen(). */
+ if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx)) {
+ if ((bta_av_cb.rs_idx - 1) < BTA_AV_NUM_STRS) {
+ p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1];
+ }
+ if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) {
+ APPL_TRACE_DEBUG("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d",
+ bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag);
+
+ if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id)
+ p_scb->q_info.open.switch_res = BTA_AV_RS_OK;
+ else
+ p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL;
+
+ /* Continue av open process */
+ bta_av_do_disc_a2dp(p_scb, (tBTA_AV_DATA*)&(p_scb->q_info.open));
+ }
+
+ bta_av_cb.rs_idx = 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sco_chg_cback
+ *
+ * Description receive & process the SCO connection up/down event from sys.
+ * call setup also triggers this callback, to suspend av before
+ * SCO activity happens, or to resume av once call ends.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ UNUSED_ATTR uint8_t app_id,
+ UNUSED_ATTR BD_ADDR peer_addr) {
+ tBTA_AV_SCB* p_scb;
+ int i;
+ tBTA_AV_API_STOP stop;
+
+ APPL_TRACE_DEBUG("bta_av_sco_chg_cback:%d status:%d", id, status);
+ if (id) {
+ bta_av_cb.sco_occupied = true;
+
+ /* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if (p_scb && p_scb->co_started && (p_scb->sco_suspend == false)) {
+ APPL_TRACE_DEBUG("suspending scb:%d", i);
+ /* scb is used and started, not suspended automatically */
+ p_scb->sco_suspend = true;
+ stop.flush = false;
+ stop.suspend = true;
+ stop.reconfig_stop = false;
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA*)&stop);
+ }
+ }
+ } else {
+ bta_av_cb.sco_occupied = false;
+
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scb = bta_av_cb.p_scb[i];
+
+ if (p_scb && p_scb->sco_suspend) /* scb is used and suspended for SCO */
+ {
+ APPL_TRACE_DEBUG("starting scb:%d", i);
+ bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_switch_if_needed
+ *
+ * Description This function checks if there is another existing AV
+ * channel that is local as slave role.
+ * If so, role switch and remove it from link policy.
+ *
+ * Returns true, if role switch is done
+ *
+ ******************************************************************************/
+bool bta_av_switch_if_needed(tBTA_AV_SCB* p_scb) {
+ uint8_t role;
+ bool needed = false;
+ tBTA_AV_SCB* p_scbi;
+ int i;
+ uint8_t mask;
+
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ p_scbi = bta_av_cb.p_scb[i];
+ if (p_scbi && (p_scb->hdi != i) && /* not the original channel */
+ ((bta_av_cb.conn_audio & mask) || /* connected audio */
+ (bta_av_cb.conn_video & mask))) /* connected video */
+ {
+ BTM_GetRole(p_scbi->peer_addr, &role);
+ /* this channel is open - clear the role switch link policy for this link
+ */
+ if (BTM_ROLE_MASTER != role) {
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+ bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+ p_scbi->peer_addr);
+ if (BTM_CMD_STARTED !=
+ BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL)) {
+ /* can not switch role on SCBI
+ * start the timer on SCB - because this function is ONLY called when
+ * SCB gets API_OPEN */
+ bta_sys_start_timer(p_scb->avrc_ct_timer, BTA_AV_RS_TIME_VAL,
+ BTA_AV_AVRC_TIMER_EVT, p_scb->hndl);
+ }
+ needed = true;
+ /* mark the original channel as waiting for RS result */
+ bta_av_cb.rs_idx = p_scb->hdi + 1;
+ break;
+ }
+ }
+ }
+ return needed;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_link_role_ok
+ *
+ * Description This function checks if the SCB has existing ACL connection
+ * If so, check if the link role fits the requirements.
+ *
+ * Returns true, if role is ok
+ *
+ ******************************************************************************/
+bool bta_av_link_role_ok(tBTA_AV_SCB* p_scb, uint8_t bits) {
+ uint8_t role;
+ bool is_ok = true;
+
+ if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS) {
+ LOG_INFO(LOG_TAG, "%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x",
+ __func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits,
+ bta_av_cb.features);
+ if (BTM_ROLE_MASTER != role &&
+ (A2DP_BitsSet(bta_av_cb.conn_audio) > bits ||
+ (bta_av_cb.features & BTA_AV_FEAT_MASTER))) {
+ if (bta_av_cb.features & BTA_AV_FEAT_MASTER)
+ bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+ p_scb->peer_addr);
+
+ if (BTM_CMD_STARTED !=
+ BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL)) {
+ /* can not switch role on SCB - start the timer on SCB */
+ }
+ is_ok = false;
+ p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+ }
+ }
+
+ return is_ok;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_chk_mtu
+ *
+ * Description if this is audio channel, check if more than one audio
+ * channel is connected.
+ *
+ * Returns The smallest mtu of the connected audio channels
+ *
+ ******************************************************************************/
+uint16_t bta_av_chk_mtu(tBTA_AV_SCB* p_scb, UNUSED_ATTR uint16_t mtu) {
+ uint16_t ret_mtu = BTA_AV_MAX_A2DP_MTU;
+ tBTA_AV_SCB* p_scbi;
+ int i;
+ uint8_t mask;
+
+ /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets
+ */
+ if (p_scb->chnl == BTA_AV_CHNL_AUDIO) {
+ if (bta_av_cb.audio_open_cnt >= 2) {
+ /* more than one audio channel is connected */
+ for (i = 0; i < BTA_AV_NUM_STRS; i++) {
+ p_scbi = bta_av_cb.p_scb[i];
+ if ((p_scb != p_scbi) && p_scbi &&
+ (p_scbi->chnl == BTA_AV_CHNL_AUDIO)) {
+ mask = BTA_AV_HNDL_TO_MSK(i);
+ APPL_TRACE_DEBUG("[%d] mtu: %d, mask:0x%x", i, p_scbi->stream_mtu,
+ mask);
+ if (bta_av_cb.conn_audio & mask) {
+ if (ret_mtu > p_scbi->stream_mtu) ret_mtu = p_scbi->stream_mtu;
+ }
+ }
+ }
+ }
+ APPL_TRACE_DEBUG("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d",
+ bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu);
+ }
+ return ret_mtu;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_dup_audio_buf
+ *
+ * Description dup the audio data to the q_info.a2dp of other audio
+ * channels
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_dup_audio_buf(tBTA_AV_SCB* p_scb, BT_HDR* p_buf) {
+ /* Test whether there is more than one audio channel connected */
+ if ((p_buf == NULL) || (bta_av_cb.audio_open_cnt < 2)) return;
+
+ uint16_t copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset;
+ for (int i = 0; i < BTA_AV_NUM_STRS; i++) {
+ tBTA_AV_SCB* p_scbi = bta_av_cb.p_scb[i];
+
+ if (i == p_scb->hdi) continue; /* Ignore the original channel */
+ if ((p_scbi == NULL) || !p_scbi->co_started)
+ continue; /* Ignore if SCB is not used or started */
+ if (!(bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)))
+ continue; /* Audio is not connected */
+
+ /* Enqueue the data */
+ BT_HDR* p_new = (BT_HDR*)osi_malloc(copy_size);
+ memcpy(p_new, p_buf, copy_size);
+ list_append(p_scbi->a2dp_list, p_new);
+
+ if (list_length(p_scbi->a2dp_list) > p_bta_av_cfg->audio_mqs) {
+ // Drop the oldest packet
+ bta_av_co_audio_drop(p_scbi->hndl);
+ BT_HDR* p_buf_drop = static_cast<BT_HDR*>(list_front(p_scbi->a2dp_list));
+ list_remove(p_scbi->a2dp_list, p_buf_drop);
+ osi_free(p_buf_drop);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_sm_execute
+ *
+ * Description State machine event handling function for AV
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_sm_execute(tBTA_AV_CB* p_cb, uint16_t event, tBTA_AV_DATA* p_data) {
+ tBTA_AV_ST_TBL state_table;
+ uint8_t action;
+
+ APPL_TRACE_EVENT("%s: AV event=0x%x(%s) state=%d(%s)", __func__, event,
+ bta_av_evt_code(event), p_cb->state,
+ bta_av_st_code(p_cb->state));
+
+ /* look up the state table for the current state */
+ state_table = bta_av_st_tbl[p_cb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->state = state_table[event][BTA_AV_NEXT_STATE];
+ APPL_TRACE_EVENT("next state=%d event offset:%d", p_cb->state, event);
+
+ /* execute action functions */
+ action = state_table[event][BTA_AV_ACTION_COL];
+ if (action != BTA_AV_IGNORE) {
+ APPL_TRACE_EVENT("%s action executed %d", __func__, action);
+ (*bta_av_action[action])(p_cb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_hdl_event
+ *
+ * Description Advanced audio/video main event handling function.
+ *
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool bta_av_hdl_event(BT_HDR* p_msg) {
+ if (p_msg->event > BTA_AV_LAST_EVT) {
+ return true; /* to free p_msg */
+ }
+ if (p_msg->event >= BTA_AV_FIRST_NSM_EVT) {
+ APPL_TRACE_VERBOSE("%s: AV nsm event=0x%x(%s)", __func__, p_msg->event,
+ bta_av_evt_code(p_msg->event));
+ /* non state machine events */
+ (*bta_av_nsm_act[p_msg->event - BTA_AV_FIRST_NSM_EVT])(
+ (tBTA_AV_DATA*)p_msg);
+ } else if (p_msg->event >= BTA_AV_FIRST_SM_EVT &&
+ p_msg->event <= BTA_AV_LAST_SM_EVT) {
+ APPL_TRACE_VERBOSE("%s: AV sm event=0x%x(%s)", __func__, p_msg->event,
+ bta_av_evt_code(p_msg->event));
+ /* state machine events */
+ bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA*)p_msg);
+ } else {
+ APPL_TRACE_VERBOSE("handle=0x%x", p_msg->layer_specific);
+ /* stream state machine events */
+ bta_av_ssm_execute(bta_av_hndl_to_scb(p_msg->layer_specific), p_msg->event,
+ (tBTA_AV_DATA*)p_msg);
+ }
+ return true;
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_av_st_code
+ *
+ * Description
+ *
+ * Returns char *
+ *
+ ******************************************************************************/
+static const char* bta_av_st_code(uint8_t state) {
+ switch (state) {
+ case BTA_AV_INIT_ST:
+ return "INIT";
+ case BTA_AV_OPEN_ST:
+ return "OPEN";
+ default:
+ return "unknown";
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_av_evt_code
+ *
+ * Description
+ *
+ * Returns char *
+ *
+ ******************************************************************************/
+const char* bta_av_evt_code(uint16_t evt_code) {
+ switch (evt_code) {
+ case BTA_AV_API_DISABLE_EVT:
+ return "API_DISABLE";
+ case BTA_AV_API_REMOTE_CMD_EVT:
+ return "API_REMOTE_CMD";
+ case BTA_AV_API_VENDOR_CMD_EVT:
+ return "API_VENDOR_CMD";
+ case BTA_AV_API_VENDOR_RSP_EVT:
+ return "API_VENDOR_RSP";
+ case BTA_AV_API_META_RSP_EVT:
+ return "API_META_RSP_EVT";
+ case BTA_AV_API_RC_CLOSE_EVT:
+ return "API_RC_CLOSE";
+ case BTA_AV_AVRC_OPEN_EVT:
+ return "AVRC_OPEN";
+ case BTA_AV_AVRC_MSG_EVT:
+ return "AVRC_MSG";
+ case BTA_AV_AVRC_NONE_EVT:
+ return "AVRC_NONE";
+
+ case BTA_AV_API_OPEN_EVT:
+ return "API_OPEN";
+ case BTA_AV_API_CLOSE_EVT:
+ return "API_CLOSE";
+ case BTA_AV_AP_START_EVT:
+ return "AP_START";
+ case BTA_AV_AP_STOP_EVT:
+ return "AP_STOP";
+ case BTA_AV_API_RECONFIG_EVT:
+ return "API_RECONFIG";
+ case BTA_AV_API_PROTECT_REQ_EVT:
+ return "API_PROTECT_REQ";
+ case BTA_AV_API_PROTECT_RSP_EVT:
+ return "API_PROTECT_RSP";
+ case BTA_AV_API_RC_OPEN_EVT:
+ return "API_RC_OPEN";
+ case BTA_AV_SRC_DATA_READY_EVT:
+ return "SRC_DATA_READY";
+ case BTA_AV_CI_SETCONFIG_OK_EVT:
+ return "CI_SETCONFIG_OK";
+ case BTA_AV_CI_SETCONFIG_FAIL_EVT:
+ return "CI_SETCONFIG_FAIL";
+ case BTA_AV_SDP_DISC_OK_EVT:
+ return "SDP_DISC_OK";
+ case BTA_AV_SDP_DISC_FAIL_EVT:
+ return "SDP_DISC_FAIL";
+ case BTA_AV_STR_DISC_OK_EVT:
+ return "STR_DISC_OK";
+ case BTA_AV_STR_DISC_FAIL_EVT:
+ return "STR_DISC_FAIL";
+ case BTA_AV_STR_GETCAP_OK_EVT:
+ return "STR_GETCAP_OK";
+ case BTA_AV_STR_GETCAP_FAIL_EVT:
+ return "STR_GETCAP_FAIL";
+ case BTA_AV_STR_OPEN_OK_EVT:
+ return "STR_OPEN_OK";
+ case BTA_AV_STR_OPEN_FAIL_EVT:
+ return "STR_OPEN_FAIL";
+ case BTA_AV_STR_START_OK_EVT:
+ return "STR_START_OK";
+ case BTA_AV_STR_START_FAIL_EVT:
+ return "STR_START_FAIL";
+ case BTA_AV_STR_CLOSE_EVT:
+ return "STR_CLOSE";
+ case BTA_AV_STR_CONFIG_IND_EVT:
+ return "STR_CONFIG_IND";
+ case BTA_AV_STR_SECURITY_IND_EVT:
+ return "STR_SECURITY_IND";
+ case BTA_AV_STR_SECURITY_CFM_EVT:
+ return "STR_SECURITY_CFM";
+ case BTA_AV_STR_WRITE_CFM_EVT:
+ return "STR_WRITE_CFM";
+ case BTA_AV_STR_SUSPEND_CFM_EVT:
+ return "STR_SUSPEND_CFM";
+ case BTA_AV_STR_RECONFIG_CFM_EVT:
+ return "STR_RECONFIG_CFM";
+ case BTA_AV_AVRC_TIMER_EVT:
+ return "AVRC_TIMER";
+ case BTA_AV_AVDT_CONNECT_EVT:
+ return "AVDT_CONNECT";
+ case BTA_AV_AVDT_DISCONNECT_EVT:
+ return "AVDT_DISCONNECT";
+ case BTA_AV_ROLE_CHANGE_EVT:
+ return "ROLE_CHANGE";
+ case BTA_AV_AVDT_DELAY_RPT_EVT:
+ return "AVDT_DELAY_RPT";
+ case BTA_AV_ACP_CONNECT_EVT:
+ return "ACP_CONNECT";
+
+ case BTA_AV_API_ENABLE_EVT:
+ return "API_ENABLE";
+ case BTA_AV_API_REGISTER_EVT:
+ return "API_REG";
+ case BTA_AV_API_DEREGISTER_EVT:
+ return "API_DEREG";
+ case BTA_AV_API_DISCONNECT_EVT:
+ return "API_DISCNT";
+ case BTA_AV_CI_SRC_DATA_READY_EVT:
+ return "CI_DATA_READY";
+ case BTA_AV_SIG_CHG_EVT:
+ return "SIG_CHG";
+ case BTA_AV_SIGNALLING_TIMER_EVT:
+ return "SIGNALLING_TIMER";
+ case BTA_AV_SDP_AVRC_DISC_EVT:
+ return "SDP_AVRC_DISC";
+ case BTA_AV_AVRC_CLOSE_EVT:
+ return "AVRC_CLOSE";
+ case BTA_AV_AVRC_BROWSE_OPEN_EVT:
+ return "AVRC_BROWSE_OPEN";
+ case BTA_AV_AVRC_BROWSE_CLOSE_EVT:
+ return "AVRC_BROWSE_CLOSE";
+ case BTA_AV_CONN_CHG_EVT:
+ return "CONN_CHG";
+ case BTA_AV_DEREG_COMP_EVT:
+ return "DEREG_COMP";
+#if (AVDT_REPORTING == TRUE)
+ case BTA_AV_AVDT_RPT_CONN_EVT:
+ return "RPT_CONN";
+#endif
+ case BTA_AV_API_START_EVT:
+ return "API_START";
+ case BTA_AV_API_STOP_EVT:
+ return "API_STOP";
+ default:
+ return "unknown";
+ }
+}
diff --git a/mtkbt/code/bt/bta/av/bta_av_ssm.cc b/mtkbt/code/bt/bta/av/bta_av_ssm.cc
new file mode 100755
index 0000000..3036e71
--- a/dev/null
+++ b/mtkbt/code/bt/bta/av/bta_av_ssm.cc
@@ -0,0 +1,674 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the stream state machine for the BTA advanced audio/video.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bta_av_co.h"
+#include "bta_av_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine states */
+enum {
+ BTA_AV_INIT_SST,
+ BTA_AV_INCOMING_SST,
+ BTA_AV_OPENING_SST,
+ BTA_AV_OPEN_SST,
+ BTA_AV_RCFG_SST,
+ BTA_AV_CLOSING_SST
+};
+
+/* state machine action enumeration list */
+enum {
+ BTA_AV_DO_DISC,
+ BTA_AV_CLEANUP,
+ BTA_AV_FREE_SDB,
+ BTA_AV_CONFIG_IND,
+ BTA_AV_DISCONNECT_REQ,
+ BTA_AV_SECURITY_REQ,
+ BTA_AV_SECURITY_RSP,
+ BTA_AV_SETCONFIG_RSP,
+ BTA_AV_ST_RC_TIMER,
+ BTA_AV_STR_OPENED,
+ BTA_AV_SECURITY_IND,
+ BTA_AV_SECURITY_CFM,
+ BTA_AV_DO_CLOSE,
+ BTA_AV_CONNECT_REQ,
+ BTA_AV_SDP_FAILED,
+ BTA_AV_DISC_RESULTS,
+ BTA_AV_DISC_RES_AS_ACP,
+ BTA_AV_OPEN_FAILED,
+ BTA_AV_GETCAP_RESULTS,
+ BTA_AV_SETCONFIG_REJ,
+ BTA_AV_DISCOVER_REQ,
+ BTA_AV_CONN_FAILED,
+ BTA_AV_DO_START,
+ BTA_AV_STR_STOPPED,
+ BTA_AV_RECONFIG,
+ BTA_AV_DATA_PATH,
+ BTA_AV_START_OK,
+ BTA_AV_START_FAILED,
+ BTA_AV_STR_CLOSED,
+ BTA_AV_CLR_CONG,
+ BTA_AV_SUSPEND_CFM,
+ BTA_AV_RCFG_STR_OK,
+ BTA_AV_RCFG_FAILED,
+ BTA_AV_RCFG_CONNECT,
+ BTA_AV_RCFG_DISCNTD,
+ BTA_AV_SUSPEND_CONT,
+ BTA_AV_RCFG_CFM,
+ BTA_AV_RCFG_OPEN,
+ BTA_AV_SECURITY_REJ,
+ BTA_AV_OPEN_RC,
+ BTA_AV_CHK_2ND_START,
+ BTA_AV_SAVE_CAPS,
+ BTA_AV_SET_USE_RC,
+ BTA_AV_CCO_CLOSE,
+ BTA_AV_SWITCH_ROLE,
+ BTA_AV_ROLE_RES,
+ BTA_AV_DELAY_CO,
+ BTA_AV_OPEN_AT_INC,
+ BTA_AV_OFFLOAD_REQ,
+ BTA_AV_OFFLOAD_RSP,
+ BTA_AV_NUM_SACTIONS
+};
+
+#define BTA_AV_SIGNORE BTA_AV_NUM_SACTIONS
+
+/* state table information */
+/* #define BTA_AV_SACTION_COL 0 position of actions */
+#define BTA_AV_SACTIONS 2 /* number of actions */
+#define BTA_AV_SNEXT_STATE 2 /* position of next state */
+#define BTA_AV_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+static const uint8_t bta_av_sst_init[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST}};
+
+/* state table for incoming state */
+static const uint8_t bta_av_sst_incoming[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
+ BTA_AV_CLOSING_SST},
+ /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER,
+ BTA_AV_INCOMING_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP,
+ BTA_AV_INIT_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ,
+ BTA_AV_CLOSING_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST}};
+
+/* state table for opening state */
+static const uint8_t bta_av_sst_opening[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED,
+ BTA_AV_OPEN_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE,
+ BTA_AV_INCOMING_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_OPENING_SST}};
+
+/* state table for open state */
+static const uint8_t bta_av_sst_open[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH,
+ BTA_AV_OPEN_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START,
+ BTA_AV_OPEN_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_OPEN_SST}};
+
+/* state table for reconfig state */
+static const uint8_t bta_av_sst_rcfg[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SUSPEND_CONT,
+ BTA_AV_RCFG_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_RCFG_SST}};
+
+/* state table for closing state */
+static const uint8_t bta_av_sst_closing[][BTA_AV_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
+ /* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE,
+ BTA_AV_INIT_SST},
+ /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST},
+ /* API_OFFLOAD_START_EVT */ {BTA_AV_OFFLOAD_REQ, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST},
+ /* API_OFFLOAD_START_RSP_EVT */ {BTA_AV_OFFLOAD_RSP, BTA_AV_SIGNORE,
+ BTA_AV_CLOSING_SST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS];
+
+/* state table */
+static const tBTA_AV_SST_TBL bta_av_sst_tbl[] = {
+ bta_av_sst_init, bta_av_sst_incoming, bta_av_sst_opening,
+ bta_av_sst_open, bta_av_sst_rcfg, bta_av_sst_closing};
+
+static const char* bta_av_sst_code(uint8_t state);
+
+/*******************************************************************************
+ *
+ * Function bta_av_is_rcfg_sst
+ *
+ * Description Check if stream state machine is in reconfig state.
+ *
+ *
+ * Returns true if stream state machine is in reconfig state.
+ *
+ ******************************************************************************/
+bool bta_av_is_rcfg_sst(tBTA_AV_SCB* p_scb) {
+ bool is_rcfg_sst = false;
+
+ if (p_scb != NULL) {
+ if (p_scb->state == BTA_AV_RCFG_SST) is_rcfg_sst = true;
+ }
+
+ return is_rcfg_sst;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_ssm_execute
+ *
+ * Description Stream state machine event handling function for AV
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_ssm_execute(tBTA_AV_SCB* p_scb, uint16_t event,
+ tBTA_AV_DATA* p_data) {
+ tBTA_AV_SST_TBL state_table;
+ uint8_t action;
+ int i, xx;
+
+ if (p_scb == NULL) {
+ /* this stream is not registered */
+ APPL_TRACE_EVENT("AV channel not registered");
+ return;
+ }
+
+ /* In case incoming connection is for VDP, we need to swap scb. */
+ /* When ACP_CONNECT_EVT was received, we put first available scb to */
+ /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we */
+ /* know if it is A2DP or VDP. */
+ if ((p_scb->state == BTA_AV_INIT_SST) &&
+ (event == BTA_AV_STR_CONFIG_IND_EVT)) {
+ for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) {
+ if (bta_av_cb.p_scb[xx]) {
+ if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) {
+ bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST;
+ bta_av_cb.p_scb[xx]->coll_mask = 0;
+ p_scb->state = BTA_AV_INCOMING_SST;
+ break;
+ }
+ }
+ }
+ }
+
+ APPL_TRACE_VERBOSE("%s: AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", __func__,
+ p_scb->hndl, event, bta_av_evt_code(event), p_scb->state,
+ bta_av_sst_code(p_scb->state));
+
+ /* look up the state table for the current state */
+ state_table = bta_av_sst_tbl[p_scb->state];
+
+ event -= BTA_AV_FIRST_SSM_EVT;
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_AV_SNEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_AV_SACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_AV_SIGNORE) {
+ (*p_scb->p_act_tbl[action])(p_scb, p_data);
+ } else
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_is_scb_opening
+ *
+ * Description Returns true is scb is in opening state.
+ *
+ *
+ * Returns true if scb is in opening state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_opening(tBTA_AV_SCB* p_scb) {
+ bool is_opening = false;
+
+ if (p_scb) {
+ if (p_scb->state == BTA_AV_OPENING_SST) is_opening = true;
+ }
+
+ return is_opening;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_is_scb_incoming
+ *
+ * Description Returns true is scb is in incoming state.
+ *
+ *
+ * Returns true if scb is in incoming state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_incoming(tBTA_AV_SCB* p_scb) {
+ bool is_incoming = false;
+
+ if (p_scb) {
+ if (p_scb->state == BTA_AV_INCOMING_SST) is_incoming = true;
+ }
+
+ return is_incoming;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_set_scb_sst_init
+ *
+ * Description Set SST state to INIT.
+ * Use this function to change SST outside of state machine.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_av_set_scb_sst_init(tBTA_AV_SCB* p_scb) {
+ if (p_scb) {
+ p_scb->state = BTA_AV_INIT_SST;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_is_scb_init
+ *
+ * Description Returns true is scb is in init state.
+ *
+ *
+ * Returns true if scb is in incoming state.
+ *
+ ******************************************************************************/
+bool bta_av_is_scb_init(tBTA_AV_SCB* p_scb) {
+ bool is_init = false;
+
+ if (p_scb) {
+ if (p_scb->state == BTA_AV_INIT_SST) is_init = true;
+ }
+
+ return is_init;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_av_set_scb_sst_incoming
+ *
+ * Description Set SST state to incoming.
+ * Use this function to change SST outside of state machine.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_av_set_scb_sst_incoming(tBTA_AV_SCB* p_scb) {
+ if (p_scb) {
+ p_scb->state = BTA_AV_INCOMING_SST;
+ }
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_av_sst_code
+ *
+ * Description
+ *
+ * Returns char *
+ *
+ ******************************************************************************/
+static const char* bta_av_sst_code(uint8_t state) {
+ switch (state) {
+ case BTA_AV_INIT_SST:
+ return "INIT";
+ case BTA_AV_INCOMING_SST:
+ return "INCOMING";
+ case BTA_AV_OPENING_SST:
+ return "OPENING";
+ case BTA_AV_OPEN_SST:
+ return "OPEN";
+ case BTA_AV_RCFG_SST:
+ return "RCFG";
+ case BTA_AV_CLOSING_SST:
+ return "CLOSING";
+ default:
+ return "unknown";
+ }
+}
diff --git a/mtkbt/code/bt/bta/closure/bta_closure.cc b/mtkbt/code/bt/bta/closure/bta_closure.cc
new file mode 100755
index 0000000..599ee33
--- a/dev/null
+++ b/mtkbt/code/bt/bta/closure/bta_closure.cc
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "base/pending_task.h"
+#include "base/time/time.h"
+#include "bta_closure_int.h"
+#include "bta_sys.h"
+
+using base::PendingTask;
+using base::TaskQueue;
+using base::TimeTicks;
+
+namespace {
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_CLOSURE_EXECUTE_EVT = BTA_SYS_EVT_START(BTA_ID_CLOSURE),
+};
+
+struct tBTA_CLOSURE_EXECUTE {
+ BT_HDR hdr;
+ PendingTask pending_task;
+};
+
+static const tBTA_SYS_REG bta_closure_hw_reg = {bta_closure_execute, NULL};
+tBTA_SYS_SENDMSG bta_closure_sys_sendmsg = NULL;
+
+} // namespace
+
+/* Accept bta_sys_register, and bta_sys_sendmsg. Those parameters can be used to
+ * override system methods for tests.
+ */
+void bta_closure_init(tBTA_SYS_REGISTER registerer, tBTA_SYS_SENDMSG sender) {
+ /* register closure message handler */
+ registerer(BTA_ID_CLOSURE, &bta_closure_hw_reg);
+ bta_closure_sys_sendmsg = sender;
+}
+
+bool bta_closure_execute(BT_HDR* p_raw_msg) {
+ if (p_raw_msg->event != BTA_CLOSURE_EXECUTE_EVT) {
+ APPL_TRACE_ERROR("%s: don't know how to execute event type %d", __func__,
+ p_raw_msg->event);
+ return false;
+ }
+
+ tBTA_CLOSURE_EXECUTE* p_msg = ((tBTA_CLOSURE_EXECUTE*)p_raw_msg);
+
+ APPL_TRACE_API("%s: executing closure %s", __func__,
+ p_msg->pending_task.posted_from.ToString().c_str());
+ p_msg->pending_task.task.Run();
+
+ p_msg->pending_task.~PendingTask();
+ return true;
+}
+
+/*
+ * This function posts a closure for execution on the btu_bta_msg_queue. Please
+ * see documentation at
+ * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
+ * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
+ * base::Passed(), base::ConstRef() and others.
+ */
+void do_in_bta_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ APPL_TRACE_API("%s: posting %s", __func__, from_here.ToString().c_str());
+ tBTA_CLOSURE_EXECUTE* p_msg =
+ (tBTA_CLOSURE_EXECUTE*)osi_malloc(sizeof(tBTA_CLOSURE_EXECUTE));
+
+ new (&p_msg->pending_task) PendingTask(from_here, task, TimeTicks(), true);
+ p_msg->hdr.event = BTA_CLOSURE_EXECUTE_EVT;
+ bta_closure_sys_sendmsg(p_msg);
+}
diff --git a/mtkbt/code/bt/bta/closure/bta_closure_int.h b/mtkbt/code/bt/bta/closure/bta_closure_int.h
new file mode 100755
index 0000000..b0cc726
--- a/dev/null
+++ b/mtkbt/code/bt/bta/closure/bta_closure_int.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_CLOSURE_INT_H
+#define BTA_CLOSURE_INT_H
+
+#include <stdbool.h>
+
+#include "bta/sys/bta_sys.h"
+#include "bta_api.h"
+#include "include/bt_trace.h"
+
+/* Accept bta_sys_register, and bta_sys_sendmsg. Those parameters can be used to
+ * override system methods for tests.
+ */
+void bta_closure_init(tBTA_SYS_REGISTER registerer, tBTA_SYS_SENDMSG sender);
+bool bta_closure_execute(BT_HDR* p_msg);
+
+#endif /* BTA_CLOSURE_INT_H */
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_act.cc b/mtkbt/code/bt/bta/dm/bta_dm_act.cc
new file mode 100755
index 0000000..0bf8113
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_act.cc
@@ -0,0 +1,4830 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the action functions for device manager state
+ * machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_dm"
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_dm_co.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+#if (GAP_INCLUDED == TRUE)
+#include "gap_api.h"
+#endif
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
+ uint16_t eir_len);
+static void bta_dm_inq_cmpl_cb(void* p_result);
+static void bta_dm_service_search_remname_cback(BD_ADDR bd_addr, DEV_CLASS dc,
+ BD_NAME bd_name);
+static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name);
+static void bta_dm_find_services(BD_ADDR bd_addr);
+static void bta_dm_discover_next_device(void);
+static void bta_dm_sdp_callback(uint16_t sdp_status);
+static uint8_t bta_dm_authorize_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, uint8_t* service_name,
+ uint8_t service_id, bool is_originator);
+static uint8_t bta_dm_pin_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, bool min_16_digit);
+static uint8_t bta_dm_new_link_key_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, LINK_KEY key,
+ uint8_t key_type);
+static uint8_t bta_dm_authentication_complete_cback(BD_ADDR bd_addr,
+ DEV_CLASS dev_class,
+ BD_NAME bd_name,
+ int result);
+static void bta_dm_local_name_cback(BD_ADDR bd_addr);
+static bool bta_dm_check_av(uint16_t event);
+static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data);
+
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+
+/* Extended Inquiry Response */
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
+#endif
+
+static void bta_dm_set_eir(char* local_name);
+
+static void bta_dm_eir_search_services(tBTM_INQ_RESULTS* p_result,
+ tBTA_SERVICE_MASK* p_services_to_search,
+ tBTA_SERVICE_MASK* p_services_found);
+
+static void bta_dm_search_timer_cback(void* data);
+static void bta_dm_disable_conn_down_timer_cback(void* data);
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+static void bta_dm_adjust_roles(bool delay_role_switch);
+static char* bta_dm_get_remname(void);
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result);
+
+static bool bta_dm_read_remote_device_name(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport);
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr);
+
+static void bta_dm_sys_hw_cback(tBTA_SYS_HW_EVT status);
+static void bta_dm_disable_search_and_disc(void);
+
+static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, BD_ADDR bda,
+ tBTM_LE_EVT_DATA* p_data);
+static void bta_dm_ble_id_key_cback(uint8_t key_type,
+ tBTM_BLE_LOCAL_KEYS* p_key);
+static void bta_dm_gattc_register(void);
+static void btm_dm_start_gatt_discovery(BD_ADDR bd_addr);
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr);
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+extern tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void);
+
+#if (BLE_VND_INCLUDED == TRUE)
+static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result);
+#endif
+
+#ifndef BTA_DM_BLE_ADV_CHNL_MAP
+#define BTA_DM_BLE_ADV_CHNL_MAP \
+ (BTM_BLE_ADV_CHNL_37 | BTM_BLE_ADV_CHNL_38 | BTM_BLE_ADV_CHNL_39)
+#endif
+
+/* Disable timer interval (in milliseconds) */
+#ifndef BTA_DM_DISABLE_TIMER_MS
+#define BTA_DM_DISABLE_TIMER_MS 5000
+#endif
+
+/* Disable timer retrial interval (in milliseconds) */
+#ifndef BTA_DM_DISABLE_TIMER_RETRIAL_MS
+#define BTA_DM_DISABLE_TIMER_RETRIAL_MS 1500
+#endif
+
+/* Disable connection down timer (in milliseconds) */
+#ifndef BTA_DM_DISABLE_CONN_DOWN_TIMER_MS
+#define BTA_DM_DISABLE_CONN_DOWN_TIMER_MS 1000
+#endif
+
+/* Switch delay timer (in milliseconds) */
+#ifndef BTA_DM_SWITCH_DELAY_TIMER_MS
+#define BTA_DM_SWITCH_DELAY_TIMER_MS 500
+#endif
+
+static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr);
+static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr);
+static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
+ uint16_t eir_len);
+static void bta_dm_observe_cmpl_cb(void* p_result);
+static void bta_dm_delay_role_switch_cback(void* data);
+static void bta_dm_disable_timer_cback(void* data);
+
+const uint16_t bta_service_id_to_uuid_lkup_tbl[BTA_MAX_SERVICE_ID] = {
+ UUID_SERVCLASS_PNP_INFORMATION, /* Reserved */
+ UUID_SERVCLASS_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ UUID_SERVCLASS_DIALUP_NETWORKING, /* BTA_DUN_SERVICE_ID */
+ UUID_SERVCLASS_AUDIO_SOURCE, /* BTA_A2DP_SOURCE_SERVICE_ID */
+ UUID_SERVCLASS_LAN_ACCESS_USING_PPP, /* BTA_LAP_SERVICE_ID */
+ UUID_SERVCLASS_HEADSET, /* BTA_HSP_HS_SERVICE_ID */
+ UUID_SERVCLASS_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH, /* BTA_OPP_SERVICE_ID */
+ UUID_SERVCLASS_OBEX_FILE_TRANSFER, /* BTA_FTP_SERVICE_ID */
+ UUID_SERVCLASS_CORDLESS_TELEPHONY, /* BTA_CTP_SERVICE_ID */
+ UUID_SERVCLASS_INTERCOM, /* BTA_ICP_SERVICE_ID */
+ UUID_SERVCLASS_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */
+ UUID_SERVCLASS_DIRECT_PRINTING, /* BTA_BPP_SERVICE_ID */
+ UUID_SERVCLASS_IMAGING_RESPONDER, /* BTA_BIP_SERVICE_ID */
+ UUID_SERVCLASS_PANU, /* BTA_PANU_SERVICE_ID */
+ UUID_SERVCLASS_NAP, /* BTA_NAP_SERVICE_ID */
+ UUID_SERVCLASS_GN, /* BTA_GN_SERVICE_ID */
+ UUID_SERVCLASS_SAP, /* BTA_SAP_SERVICE_ID */
+ UUID_SERVCLASS_AUDIO_SINK, /* BTA_A2DP_SERVICE_ID */
+ UUID_SERVCLASS_AV_REMOTE_CONTROL, /* BTA_AVRCP_SERVICE_ID */
+ UUID_SERVCLASS_HUMAN_INTERFACE, /* BTA_HID_SERVICE_ID */
+ UUID_SERVCLASS_VIDEO_SINK, /* BTA_VDP_SERVICE_ID */
+ UUID_SERVCLASS_PBAP_PSE, /* BTA_PBAP_SERVICE_ID */
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY, /* BTA_HSP_SERVICE_ID */
+ UUID_SERVCLASS_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */
+ UUID_SERVCLASS_MESSAGE_ACCESS, /* BTA_MAP_SERVICE_ID */
+ UUID_SERVCLASS_MESSAGE_NOTIFICATION, /* BTA_MN_SERVICE_ID */
+ UUID_SERVCLASS_HDP_PROFILE, /* BTA_HDP_SERVICE_ID */
+ UUID_SERVCLASS_PBAP_PCE, /* BTA_PCE_SERVICE_ID */
+ UUID_PROTOCOL_ATT /* BTA_GATT_SERVICE_ID */
+};
+
+/*
+ * NOTE : The number of element in bta_service_id_to_btm_srv_id_lkup_tbl should
+ * be matching with
+ * the value BTA_MAX_SERVICE_ID in bta_api.h
+ *
+ * i.e., If you add new Service ID for BTA, the correct security ID of
+ * the new service
+ * from Security service definitions (btm_api.h) should be added to
+ * this lookup table.
+ */
+const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[BTA_MAX_SERVICE_ID] = {
+ 0, /* Reserved */
+ BTM_SEC_SERVICE_SERIAL_PORT, /* BTA_SPP_SERVICE_ID */
+ BTM_SEC_SERVICE_DUN, /* BTA_DUN_SERVICE_ID */
+ BTM_SEC_SERVICE_AVDTP, /* BTA_AUDIO_SOURCE_SERVICE_ID */
+ BTM_SEC_SERVICE_LAN_ACCESS, /* BTA_LAP_SERVICE_ID */
+ BTM_SEC_SERVICE_HEADSET_AG, /* BTA_HSP_SERVICE_ID */
+ BTM_SEC_SERVICE_AG_HANDSFREE, /* BTA_HFP_SERVICE_ID */
+ BTM_SEC_SERVICE_OBEX, /* BTA_OPP_SERVICE_ID */
+ BTM_SEC_SERVICE_OBEX_FTP, /* BTA_FTP_SERVICE_ID */
+ BTM_SEC_SERVICE_CORDLESS, /* BTA_CTP_SERVICE_ID */
+ BTM_SEC_SERVICE_INTERCOM, /* BTA_ICP_SERVICE_ID */
+ BTM_SEC_SERVICE_IRMC_SYNC, /* BTA_SYNC_SERVICE_ID */
+ BTM_SEC_SERVICE_BPP_JOB, /* BTA_BPP_SERVICE_ID */
+ BTM_SEC_SERVICE_BIP, /* BTA_BIP_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_PANU, /* BTA_PANU_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_NAP, /* BTA_NAP_SERVICE_ID */
+ BTM_SEC_SERVICE_BNEP_GN, /* BTA_GN_SERVICE_ID */
+ BTM_SEC_SERVICE_SAP, /* BTA_SAP_SERVICE_ID */
+ BTM_SEC_SERVICE_AVDTP, /* BTA_A2DP_SERVICE_ID */
+ BTM_SEC_SERVICE_AVCTP, /* BTA_AVRCP_SERVICE_ID */
+ BTM_SEC_SERVICE_HIDH_SEC_CTRL, /* BTA_HID_SERVICE_ID */
+ BTM_SEC_SERVICE_AVDTP, /* BTA_VDP_SERVICE_ID */
+ BTM_SEC_SERVICE_PBAP, /* BTA_PBAP_SERVICE_ID */
+ BTM_SEC_SERVICE_HEADSET, /* BTA_HSP_HS_SERVICE_ID */
+ BTM_SEC_SERVICE_HF_HANDSFREE, /* BTA_HFP_HS_SERVICE_ID */
+ BTM_SEC_SERVICE_MAP, /* BTA_MAP_SERVICE_ID */
+ BTM_SEC_SERVICE_MAP, /* BTA_MN_SERVICE_ID */
+ BTM_SEC_SERVICE_HDP_SNK, /* BTA_HDP_SERVICE_ID */
+ BTM_SEC_SERVICE_PBAP, /* BTA_PCE_SERVICE_ID */
+ BTM_SEC_SERVICE_ATT /* BTA_GATT_SERVICE_ID */
+};
+
+/* bta security callback */
+const tBTM_APPL_INFO bta_security = {&bta_dm_authorize_cback,
+ &bta_dm_pin_cback,
+ &bta_dm_new_link_key_cback,
+ &bta_dm_authentication_complete_cback,
+ &bta_dm_bond_cancel_complete_cback,
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ &bta_dm_sp_cback,
+#else
+ NULL,
+#endif
+ &bta_dm_ble_smp_cback,
+ &bta_dm_ble_id_key_cback};
+
+#define MAX_DISC_RAW_DATA_BUF (4096)
+uint8_t g_disc_raw_data_buf[MAX_DISC_RAW_DATA_BUF];
+
+extern DEV_CLASS local_device_default_class;
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function bta_dm_enable
+ *
+ * Description Initialises the BT device manager
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_enable(tBTA_DM_MSG* p_data) {
+ tBTA_DM_ENABLE enable_event;
+
+ /* if already in use, return an error */
+ if (bta_dm_cb.is_bta_dm_active == true) {
+ APPL_TRACE_WARNING("%s Device already started by another application",
+ __func__);
+ memset(&enable_event, 0, sizeof(tBTA_DM_ENABLE));
+ enable_event.status = BTA_FAILURE;
+ if (p_data->enable.p_sec_cback != NULL)
+ p_data->enable.p_sec_cback(BTA_DM_ENABLE_EVT,
+ (tBTA_DM_SEC*)&enable_event);
+ return;
+ }
+
+ /* first, register our callback to SYS HW manager */
+ bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback);
+
+ /* make sure security callback is saved - if no callback, do not erase the
+ previous one,
+ it could be an error recovery mechanism */
+ if (p_data->enable.p_sec_cback != NULL)
+ bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;
+ /* notify BTA DM is now active */
+ bta_dm_cb.is_bta_dm_active = true;
+
+ /* send a message to BTA SYS */
+ tBTA_SYS_HW_MSG* sys_enable_event =
+ (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+ sys_enable_event->hdr.event = BTA_SYS_API_ENABLE_EVT;
+ sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+
+ bta_sys_sendmsg(sys_enable_event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_init_cb
+ *
+ * Description Initializes the bta_dm_cb control block
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_init_cb(void) {
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+ bta_dm_cb.disable_timer = alarm_new("bta_dm.disable_timer");
+ bta_dm_cb.switch_delay_timer = alarm_new("bta_dm.switch_delay_timer");
+ for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ bta_dm_cb.pm_timer[i].timer[j] = alarm_new("bta_dm.pm_timer");
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_deinit_cb
+ *
+ * Description De-initializes the bta_dm_cb control block
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_deinit_cb(void) {
+ /*
+ * TODO: Should alarm_free() the bta_dm_cb timers during graceful
+ * shutdown.
+ */
+ alarm_free(bta_dm_cb.disable_timer);
+ alarm_free(bta_dm_cb.switch_delay_timer);
+ for (size_t i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ for (size_t j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ alarm_free(bta_dm_cb.pm_timer[i].timer[j]);
+ }
+ }
+ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sys_hw_cback
+ *
+ * Description callback register to SYS to get HW status updates
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_sys_hw_cback(tBTA_SYS_HW_EVT status) {
+ DEV_CLASS dev_class;
+ tBTA_DM_SEC_CBACK* temp_cback;
+ uint8_t key_mask = 0;
+ BT_OCTET16 er;
+ tBTA_BLE_LOCAL_ID_KEYS id_key;
+
+ APPL_TRACE_DEBUG("%s with event: %i", __func__, status);
+
+ /* On H/W error evt, report to the registered DM application callback */
+ if (status == BTA_SYS_HW_ERROR_EVT) {
+ if (bta_dm_cb.p_sec_cback != NULL)
+ bta_dm_cb.p_sec_cback(BTA_DM_HW_ERROR_EVT, NULL);
+ return;
+ }
+
+ if (status == BTA_SYS_HW_OFF_EVT) {
+ if (bta_dm_cb.p_sec_cback != NULL)
+ bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+
+ /* reinitialize the control block */
+ bta_dm_deinit_cb();
+
+ /* hw is ready, go on with BTA DM initialization */
+ alarm_free(bta_dm_search_cb.search_timer);
+ alarm_free(bta_dm_search_cb.gatt_close_timer);
+ memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
+
+ /* unregister from SYS */
+ bta_sys_hw_unregister(BTA_SYS_HW_BLUETOOTH);
+ /* notify BTA DM is now unactive */
+ bta_dm_cb.is_bta_dm_active = false;
+ } else if (status == BTA_SYS_HW_ON_EVT) {
+ /* FIXME: We should not unregister as the SYS shall invoke this callback on
+ * a H/W error.
+ * We need to revisit when this platform has more than one BLuetooth H/W
+ * chip
+ */
+ // bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH);
+
+ /* save security callback */
+ temp_cback = bta_dm_cb.p_sec_cback;
+ /* make sure the control block is properly initialized */
+ bta_dm_init_cb();
+ /* and retrieve the callback */
+ bta_dm_cb.p_sec_cback = temp_cback;
+ bta_dm_cb.is_bta_dm_active = true;
+
+ /* hw is ready, go on with BTA DM initialization */
+ alarm_free(bta_dm_search_cb.search_timer);
+ alarm_free(bta_dm_search_cb.gatt_close_timer);
+ memset(&bta_dm_search_cb, 0, sizeof(bta_dm_search_cb));
+ /*
+ * TODO: Should alarm_free() the bta_dm_search_cb timers during
+ * graceful shutdown.
+ */
+ bta_dm_search_cb.search_timer = alarm_new("bta_dm_search.search_timer");
+ bta_dm_search_cb.gatt_close_timer =
+ alarm_new("bta_dm_search.gatt_close_timer");
+
+ memset(&bta_dm_conn_srvcs, 0, sizeof(bta_dm_conn_srvcs));
+ memset(&bta_dm_di_cb, 0, sizeof(tBTA_DM_DI_CB));
+
+ memcpy(dev_class, p_bta_dm_cfg->dev_class, sizeof(dev_class));
+ BTM_SetDeviceClass(dev_class);
+
+ /* load BLE local information: ID keys, ER if available */
+ bta_dm_co_ble_load_local_keys(&key_mask, er, &id_key);
+
+ if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ER) {
+ BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ER,
+ (tBTM_BLE_LOCAL_KEYS*)&er);
+ }
+ if (key_mask & BTA_BLE_LOCAL_KEY_TYPE_ID) {
+ BTM_BleLoadLocalKeys(BTA_BLE_LOCAL_KEY_TYPE_ID,
+ (tBTM_BLE_LOCAL_KEYS*)&id_key);
+ }
+ bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+
+ BTM_SecRegister((tBTM_APPL_INFO*)&bta_security);
+ BTM_SetDefaultLinkSuperTout(p_bta_dm_cfg->link_timeout);
+ BTM_WritePageTimeout(p_bta_dm_cfg->page_timeout);
+ bta_dm_cb.cur_policy = p_bta_dm_cfg->policy_settings;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+ BTM_RegBusyLevelNotif(bta_dm_bl_change_cback, NULL,
+ BTM_BL_UPDATE_MASK | BTM_BL_ROLE_CHG_MASK);
+
+#if (BLE_VND_INCLUDED == TRUE)
+ BTM_BleReadControllerFeatures(bta_dm_ctrl_features_rd_cmpl_cback);
+#else
+ /* If VSC multi adv commands are available, advertising will be initialized
+ * when capabilities are read. If they are not avaliable, initialize
+ * advertising here */
+ btm_ble_adv_init();
+#endif
+
+ /* Earlier, we used to invoke BTM_ReadLocalAddr which was just copying the
+ bd_addr
+ from the control block and invoking the callback which was sending the
+ DM_ENABLE_EVT.
+ But then we have a few HCI commands being invoked above which were still
+ in progress
+ when the ENABLE_EVT was sent. So modified this to fetch the local name
+ which forces
+ the DM_ENABLE_EVT to be sent only after all the init steps are complete
+ */
+ BTM_ReadLocalDeviceNameFromController(
+ (tBTM_CMPL_CB*)bta_dm_local_name_cback);
+
+ bta_sys_rm_register((tBTA_SYS_CONN_CBACK*)bta_dm_rm_cback);
+
+ /* initialize bluetooth low power manager */
+ bta_dm_init_pm();
+
+ bta_sys_policy_register((tBTA_SYS_CONN_CBACK*)bta_dm_policy_cback);
+
+ bta_dm_gattc_register();
+
+ } else
+ APPL_TRACE_DEBUG(" --- ignored event");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable
+ *
+ * Description Disables the BT device manager
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_disable(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after
+ * last channel is closed) */
+ L2CA_SetIdleTimeoutByBdAddr((uint8_t*)BT_BD_ANY, 0, BT_TRANSPORT_BR_EDR);
+ L2CA_SetIdleTimeoutByBdAddr((uint8_t*)BT_BD_ANY, 0, BT_TRANSPORT_LE);
+
+ /* disable all active subsystems */
+ bta_sys_disable(BTA_SYS_HW_BLUETOOTH);
+
+ BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0);
+ BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0);
+
+ bta_dm_disable_pm();
+ bta_dm_disable_search_and_disc();
+ bta_dm_cb.disabling = true;
+
+ BTM_BleClearBgConnDev();
+
+ if (BTM_GetNumAclLinks() == 0) {
+#if (BTA_DISABLE_DELAY > 0)
+ /* If BTA_DISABLE_DELAY is defined and greater than zero, then delay the
+ * shutdown by
+ * BTA_DISABLE_DELAY milliseconds
+ */
+ APPL_TRACE_WARNING("%s BTA_DISABLE_DELAY set to %d ms", __func__,
+ BTA_DISABLE_DELAY);
+ alarm_set_on_queue(bta_dm_cb.disable_timer, BTA_DISABLE_DELAY,
+ bta_dm_disable_conn_down_timer_cback, NULL,
+ btu_bta_alarm_queue);
+#else
+ bta_dm_disable_conn_down_timer_cback(NULL);
+#endif
+ } else {
+ alarm_set_on_queue(bta_dm_cb.disable_timer, BTA_DM_DISABLE_TIMER_MS,
+ bta_dm_disable_timer_cback, UINT_TO_PTR(0),
+ btu_bta_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable_timer_cback
+ *
+ * Description Called if the disable timer expires
+ * Used to close ACL connections which are still active
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_timer_cback(void* data) {
+ uint8_t i;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+ bool trigger_disc = false;
+ uint32_t param = PTR_TO_UINT(data);
+
+ APPL_TRACE_EVENT("%s trial %u", __func__, param);
+
+ if (BTM_GetNumAclLinks() && (param == 0)) {
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ transport = bta_dm_cb.device_list.peer_device[i].transport;
+ btm_remove_acl(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ transport);
+ trigger_disc = true;
+ }
+
+ /* Retrigger disable timer in case ACL disconnect failed, DISABLE_EVT still
+ need
+ to be sent out to avoid jave layer disable timeout */
+ if (trigger_disc) {
+ alarm_set_on_queue(
+ bta_dm_cb.disable_timer, BTA_DM_DISABLE_TIMER_RETRIAL_MS,
+ bta_dm_disable_timer_cback, UINT_TO_PTR(1), btu_bta_alarm_queue);
+ }
+ } else {
+ bta_dm_cb.disabling = false;
+
+ bta_sys_remove_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+ bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_set_dev_name
+ *
+ * Description Sets local device name
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_set_dev_name(tBTA_DM_MSG* p_data) {
+ BTM_SetLocalDeviceName((char*)p_data->set_name.name);
+ bta_dm_set_eir((char*)p_data->set_name.name);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_set_visibility
+ *
+ * Description Sets discoverability, connectability and pairability
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_set_visibility(tBTA_DM_MSG* p_data) {
+ uint16_t window, interval;
+ uint16_t le_disc_mode = BTM_BleReadDiscoverability();
+ uint16_t le_conn_mode = BTM_BleReadConnectability();
+ uint16_t disc_mode = BTM_ReadDiscoverability(&window, &interval);
+ uint16_t conn_mode = BTM_ReadConnectability(&window, &interval);
+
+ /* set modes for Discoverability and connectability if not ignore */
+ if (p_data->set_visibility.disc_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+ if ((p_data->set_visibility.disc_mode & BTA_DM_LE_IGNORE) ==
+ BTA_DM_LE_IGNORE)
+ p_data->set_visibility.disc_mode =
+ ((p_data->set_visibility.disc_mode & ~BTA_DM_LE_IGNORE) |
+ le_disc_mode);
+ if ((p_data->set_visibility.disc_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+ p_data->set_visibility.disc_mode =
+ ((p_data->set_visibility.disc_mode & ~BTA_DM_IGNORE) | disc_mode);
+
+ BTM_SetDiscoverability(p_data->set_visibility.disc_mode,
+ bta_dm_cb.inquiry_scan_window,
+ bta_dm_cb.inquiry_scan_interval);
+ }
+
+ if (p_data->set_visibility.conn_mode != (BTA_DM_IGNORE | BTA_DM_LE_IGNORE)) {
+ if ((p_data->set_visibility.conn_mode & BTA_DM_LE_IGNORE) ==
+ BTA_DM_LE_IGNORE)
+ p_data->set_visibility.conn_mode =
+ ((p_data->set_visibility.conn_mode & ~BTA_DM_LE_IGNORE) |
+ le_conn_mode);
+ if ((p_data->set_visibility.conn_mode & BTA_DM_IGNORE) == BTA_DM_IGNORE)
+ p_data->set_visibility.conn_mode =
+ ((p_data->set_visibility.conn_mode & ~BTA_DM_IGNORE) | conn_mode);
+
+ BTM_SetConnectability(p_data->set_visibility.conn_mode,
+ bta_dm_cb.page_scan_window,
+ bta_dm_cb.page_scan_interval);
+ }
+
+ /* Send False or True if not ignore */
+ if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE) {
+ if (p_data->set_visibility.pair_mode == BTA_DM_NON_PAIRABLE)
+ bta_dm_cb.disable_pair_mode = true;
+ else
+ bta_dm_cb.disable_pair_mode = false;
+ }
+
+ /* Send False or True if not ignore */
+ if (p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE) {
+ if (p_data->set_visibility.conn_paired_only == BTA_DM_CONN_ALL)
+ bta_dm_cb.conn_paired_only = false;
+ else
+ bta_dm_cb.conn_paired_only = true;
+ }
+
+ /* Change mode if either mode is not ignore */
+ if (p_data->set_visibility.pair_mode != BTA_DM_IGNORE ||
+ p_data->set_visibility.conn_paired_only != BTA_DM_IGNORE)
+ BTM_SetPairableMode((bool)(!(bta_dm_cb.disable_pair_mode)),
+ bta_dm_cb.conn_paired_only);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_process_remove_device
+ *
+ * Description Removes device, Disconnects ACL link if required.
+ ***
+ ******************************************************************************/
+void bta_dm_process_remove_device(BD_ADDR bd_addr) {
+ /* need to remove all pending background connection before unpair */
+ BTA_GATTC_CancelOpen(0, bd_addr, false);
+
+ BTM_SecDeleteDevice(bd_addr);
+
+ /* remove all cached GATT information */
+ BTA_GATTC_Refresh(bd_addr);
+
+ if (bta_dm_cb.p_sec_cback) {
+ tBTA_DM_SEC sec_event;
+ bdcpy(sec_event.link_down.bd_addr, bd_addr);
+ /* No connection, set status to success (acl disc code not valid) */
+ sec_event.link_down.status = HCI_SUCCESS;
+ bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &sec_event);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_remove_device
+ *
+ * Description Removes device, disconnects ACL link if required.
+ ***
+ ******************************************************************************/
+void bta_dm_remove_device(tBTA_DM_MSG* p_data) {
+ tBTA_DM_API_REMOVE_DEVICE* p_dev = &p_data->remove_dev;
+ bool continue_delete_other_dev = false;
+ if (p_dev == NULL) return;
+
+ BD_ADDR other_address;
+ bdcpy(other_address, p_dev->bd_addr);
+
+ /* If ACL exists for the device in the remove_bond message*/
+ bool continue_delete_dev = false;
+ uint8_t other_transport = BT_TRANSPORT_INVALID;
+
+ if (BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_LE) ||
+ BTM_IsAclConnectionUp(p_dev->bd_addr, BT_TRANSPORT_BR_EDR)) {
+ APPL_TRACE_DEBUG("%s: ACL Up count %d", __func__,
+ bta_dm_cb.device_list.count);
+ continue_delete_dev = false;
+
+ /* Take the link down first, and mark the device for removal when
+ * disconnected */
+ for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ p_dev->bd_addr)) {
+ uint8_t transport = BT_TRANSPORT_BR_EDR;
+
+ transport = bta_dm_cb.device_list.peer_device[i].transport;
+ bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
+ btm_remove_acl(p_dev->bd_addr, transport);
+ APPL_TRACE_DEBUG("%s:transport = %d", __func__,
+ bta_dm_cb.device_list.peer_device[i].transport);
+
+ /* save the other transport to check if device is connected on
+ * other_transport */
+ if (bta_dm_cb.device_list.peer_device[i].transport == BT_TRANSPORT_LE)
+ other_transport = BT_TRANSPORT_BR_EDR;
+ else
+ other_transport = BT_TRANSPORT_LE;
+
+ break;
+ }
+ }
+ } else {
+ continue_delete_dev = true;
+ }
+ // If it is DUMO device and device is paired as different address, unpair that
+ // device
+ // if different address
+ if ((other_transport &&
+ (BTM_ReadConnectedTransportAddress(other_address, other_transport))) ||
+ (!other_transport &&
+ (BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_BR_EDR) ||
+ BTM_ReadConnectedTransportAddress(other_address, BT_TRANSPORT_LE)))) {
+ continue_delete_other_dev = false;
+ /* Take the link down first, and mark the device for removal when
+ * disconnected */
+ for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ other_address)) {
+ bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_UNPAIRING;
+ btm_remove_acl(other_address,
+ bta_dm_cb.device_list.peer_device[i].transport);
+ break;
+ }
+ }
+ } else {
+ APPL_TRACE_DEBUG("%s: continue to delete the other dev ", __func__);
+ continue_delete_other_dev = true;
+ }
+ /* Delete the device mentioned in the msg */
+ if (continue_delete_dev) bta_dm_process_remove_device(p_dev->bd_addr);
+
+ /* Delete the other paired device too */
+ BD_ADDR dummy_bda = {0};
+ if (continue_delete_other_dev && (bdcmp(other_address, dummy_bda) != 0))
+ bta_dm_process_remove_device(other_address);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_add_device
+ *
+ * Description This function adds a Link Key to an security database entry.
+ * It is normally called during host startup to restore all
+ * required information stored in the NVRAM.
+ ***
+ ******************************************************************************/
+void bta_dm_add_device(tBTA_DM_MSG* p_data) {
+ tBTA_DM_API_ADD_DEVICE* p_dev = &p_data->add_dev;
+ uint8_t* p_dc = NULL;
+ uint8_t* p_lc = NULL;
+ uint32_t trusted_services_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+ uint8_t index = 0;
+ uint8_t btm_mask_index = 0;
+
+ memset(trusted_services_mask, 0, sizeof(trusted_services_mask));
+
+ /* If not all zeros, the device class has been specified */
+ if (p_dev->dc_known) p_dc = (uint8_t*)p_dev->dc;
+
+ if (p_dev->link_key_known) p_lc = (uint8_t*)p_dev->link_key;
+
+ if (p_dev->is_trusted) {
+ /* covert BTA service mask to BTM mask */
+ while (p_dev->tm && (index < BTA_MAX_SERVICE_ID)) {
+ if (p_dev->tm & (uint32_t)(1 << index)) {
+ btm_mask_index =
+ bta_service_id_to_btm_srv_id_lkup_tbl[index] / BTM_SEC_ARRAY_BITS;
+ trusted_services_mask[btm_mask_index] |=
+ (uint32_t)(1 << (bta_service_id_to_btm_srv_id_lkup_tbl[index] -
+ (uint32_t)(btm_mask_index * 32)));
+
+ p_dev->tm &= (uint32_t)(~(1 << index));
+ }
+ index++;
+ }
+ }
+
+ if (!BTM_SecAddDevice(p_dev->bd_addr, p_dc, p_dev->bd_name, p_dev->features,
+ trusted_services_mask, p_lc, p_dev->key_type,
+ p_dev->io_cap, p_dev->pin_length)) {
+ APPL_TRACE_ERROR("BTA_DM: Error adding device %08x%04x",
+ (p_dev->bd_addr[0] << 24) + (p_dev->bd_addr[1] << 16) +
+ (p_dev->bd_addr[2] << 8) + p_dev->bd_addr[3],
+ (p_dev->bd_addr[4] << 8) + p_dev->bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_close_acl
+ *
+ * Description This function forces to close the connection to a remote
+ * device and optionaly remove the device from security
+ * database if required.
+ ***
+ ******************************************************************************/
+void bta_dm_close_acl(tBTA_DM_MSG* p_data) {
+ tBTA_DM_API_REMOVE_ACL* p_remove_acl = &p_data->remove_acl;
+ uint8_t index;
+
+ APPL_TRACE_DEBUG("bta_dm_close_acl");
+
+ if (BTM_IsAclConnectionUp(p_remove_acl->bd_addr, p_remove_acl->transport)) {
+ for (index = 0; index < bta_dm_cb.device_list.count; index++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[index].peer_bdaddr,
+ p_remove_acl->bd_addr))
+ break;
+ }
+ if (index != bta_dm_cb.device_list.count) {
+ if (p_remove_acl->remove_dev)
+ bta_dm_cb.device_list.peer_device[index].remove_dev_pending = true;
+ } else {
+ APPL_TRACE_ERROR("unknown device, remove ACL failed");
+ }
+ /* Disconnect the ACL link */
+ btm_remove_acl(p_remove_acl->bd_addr, p_remove_acl->transport);
+ }
+ /* if to remove the device from security database ? do it now */
+ else if (p_remove_acl->remove_dev) {
+ if (!BTM_SecDeleteDevice(p_remove_acl->bd_addr)) {
+ APPL_TRACE_ERROR("delete device from security database failed.");
+ }
+ /* need to remove all pending background connection if any */
+ BTA_GATTC_CancelOpen(0, p_remove_acl->bd_addr, false);
+ /* remove all cached GATT information */
+ BTA_GATTC_Refresh(p_remove_acl->bd_addr);
+ }
+ /* otherwise, no action needed */
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_remove_all_acl
+ *
+ * Description This function forces to close all the ACL links specified by
+ * link type
+ ***
+ ******************************************************************************/
+void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data) {
+ const tBTA_DM_LINK_TYPE link_type = p_data->remove_all_acl.link_type;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ APPL_TRACE_DEBUG("%s link type = %d", __func__, link_type);
+
+ for (uint8_t i = 0; i < bta_dm_cb.device_list.count; i++) {
+ BD_ADDR addr = {0};
+ bdcpy(addr, bta_dm_cb.device_list.peer_device[i].peer_bdaddr);
+ transport = bta_dm_cb.device_list.peer_device[i].transport;
+ if ((link_type == BTA_DM_LINK_TYPE_ALL) ||
+ ((link_type == BTA_DM_LINK_TYPE_LE) &&
+ (transport == BT_TRANSPORT_LE)) ||
+ ((link_type == BTA_DM_LINK_TYPE_BR_EDR) &&
+ (transport == BT_TRANSPORT_BR_EDR))) {
+ /* Disconnect the ACL link */
+ btm_remove_acl(addr, transport);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_bond
+ *
+ * Description Bonds with peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_bond(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS status;
+ tBTA_DM_SEC sec_event;
+ char* p_name;
+
+ if (p_data->bond.transport == BTA_TRANSPORT_UNKNOWN)
+ status = BTM_SecBond(p_data->bond.bd_addr, 0, NULL, 0);
+ else
+ status = BTM_SecBondByTransport(p_data->bond.bd_addr,
+ p_data->bond.transport, 0, NULL, 0);
+
+ if (bta_dm_cb.p_sec_cback && (status != BTM_CMD_STARTED)) {
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ bdcpy(sec_event.auth_cmpl.bd_addr, p_data->bond.bd_addr);
+ p_name = BTM_SecReadDevName(p_data->bond.bd_addr);
+ if (p_name != NULL) {
+ memcpy(sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN - 1));
+ sec_event.auth_cmpl.bd_name[BD_NAME_LEN - 1] = 0;
+ }
+
+ /* taken care of by memset [above]
+ sec_event.auth_cmpl.key_present = false;
+ sec_event.auth_cmpl.success = false;
+ */
+ sec_event.auth_cmpl.fail_reason = HCI_ERR_ILLEGAL_COMMAND;
+ if (status == BTM_SUCCESS) {
+ sec_event.auth_cmpl.success = true;
+ } else {
+ /* delete this device entry from Sec Dev DB */
+ bta_dm_remove_sec_dev_entry(p_data->bond.bd_addr);
+ }
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_bond_cancel
+ *
+ * Description Cancels bonding with a peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_bond_cancel(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS status;
+ tBTA_DM_SEC sec_event;
+
+ APPL_TRACE_EVENT(" bta_dm_bond_cancel ");
+ status = BTM_SecBondCancel(p_data->bond_cancel.bd_addr);
+
+ if (bta_dm_cb.p_sec_cback &&
+ (status != BTM_CMD_STARTED && status != BTM_SUCCESS)) {
+ sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pin_reply
+ *
+ * Description Send the pin_reply to a request from BTM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_pin_reply(tBTA_DM_MSG* p_data) {
+ uint32_t trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE];
+ uint32_t* current_trusted_mask;
+
+ current_trusted_mask = BTM_ReadTrustedMask(p_data->pin_reply.bd_addr);
+
+ if (current_trusted_mask) {
+ memcpy(trusted_mask, current_trusted_mask, sizeof(trusted_mask));
+ } else {
+ memset(trusted_mask, 0, sizeof(trusted_mask));
+ }
+
+ if (p_data->pin_reply.accept) {
+ BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_SUCCESS,
+ p_data->pin_reply.pin_len, p_data->pin_reply.p_pin,
+ trusted_mask);
+ } else {
+ BTM_PINCodeReply(p_data->pin_reply.bd_addr, BTM_NOT_AUTHORIZED, 0, NULL,
+ trusted_mask);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_policy_cback
+ *
+ * Description process the link policy changes
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr) {
+ tBTA_DM_PEER_DEVICE* p_dev = NULL;
+ uint16_t policy = app_id;
+ uint32_t mask = (uint32_t)(1 << id);
+
+ if (peer_addr) p_dev = bta_dm_find_peer_device(peer_addr);
+
+ APPL_TRACE_DEBUG(" bta_dm_policy_cback cmd:%d, policy:0x%x", status, policy);
+ switch (status) {
+ case BTA_SYS_PLCY_SET:
+ if (!p_dev) return;
+ /* restore the default link policy */
+ p_dev->link_policy |= policy;
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+ break;
+
+ case BTA_SYS_PLCY_CLR:
+ if (!p_dev) return;
+ /* clear the policy from the default link policy */
+ p_dev->link_policy &= (~policy);
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &(p_dev->link_policy));
+
+ if (policy & (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)) {
+ /* if clearing sniff/park, wake the link */
+ bta_dm_pm_active(p_dev->peer_bdaddr);
+ }
+ break;
+
+ case BTA_SYS_PLCY_DEF_SET:
+ /* want to restore/set the role switch policy */
+ bta_dm_cb.role_policy_mask &= ~mask;
+ if (0 == bta_dm_cb.role_policy_mask) {
+ /* if nobody wants to insist on the role */
+ bta_dm_cb.cur_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+ }
+ break;
+
+ case BTA_SYS_PLCY_DEF_CLR:
+ /* want to remove the role switch policy */
+ bta_dm_cb.role_policy_mask |= mask;
+ bta_dm_cb.cur_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_SetDefaultLinkPolicy(bta_dm_cb.cur_policy);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_confirm
+ *
+ * Description Send the user confirm request reply in response to a
+ * request from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_confirm(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+ if (p_data->confirm.accept == true) res = BTM_SUCCESS;
+ BTM_ConfirmReqReply(res, p_data->confirm.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_loc_oob
+ *
+ * Description Retrieve the OOB data from the local LM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_loc_oob(UNUSED_ATTR tBTA_DM_MSG* p_data) { BTM_ReadLocalOobData(); }
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_io_req_act
+ *
+ * Description respond to the IO capabilities request from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data) {
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+ if (p_data->ci_io_req.auth_req) auth_req = BTM_AUTH_AP_YES;
+ BTM_IoCapRsp(p_data->ci_io_req.bd_addr, p_data->ci_io_req.io_cap,
+ p_data->ci_io_req.oob_data, auth_req);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_rmt_oob_act
+ *
+ * Description respond to the OOB data request for the remote device from
+ * BTM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS res = BTM_NOT_AUTHORIZED;
+
+ if (p_data->ci_rmt_oob.accept == true) res = BTM_SUCCESS;
+ BTM_RemoteOobDataReply(res, p_data->ci_rmt_oob.bd_addr, p_data->ci_rmt_oob.c,
+ p_data->ci_rmt_oob.r);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_start
+ *
+ * Description Starts an inquiry
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_start(tBTA_DM_MSG* p_data) {
+ tBTM_INQUIRY_CMPL result;
+
+ size_t len = sizeof(tBT_UUID) * p_data->search.num_uuid;
+ bta_dm_gattc_register();
+
+ APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__,
+ p_bta_dm_cfg->avoid_scatter);
+
+ if (p_bta_dm_cfg->avoid_scatter &&
+ (p_data->search.rs_res == BTA_DM_RS_NONE) &&
+ bta_dm_check_av(BTA_DM_API_SEARCH_EVT)) {
+ memcpy(&bta_dm_cb.search_msg, &p_data->search, sizeof(tBTA_DM_API_SEARCH));
+ return;
+ }
+
+ BTM_ClearInqDb(NULL);
+ /* save search params */
+ bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
+ bta_dm_search_cb.services = p_data->search.services;
+
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+
+ if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) != 0 &&
+ p_data->search.p_uuid != NULL) {
+ bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
+ memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->search.p_uuid, len);
+ }
+ result.status = BTM_StartInquiry((tBTM_INQ_PARMS*)&p_data->search.inq_params,
+ bta_dm_inq_results_cb,
+ (tBTM_CMPL_CB*)bta_dm_inq_cmpl_cb);
+
+ APPL_TRACE_EVENT("%s status=%d", __func__, result.status);
+ if (result.status != BTM_CMD_STARTED) {
+ result.num_resp = 0;
+ bta_dm_inq_cmpl_cb((void*)&result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_cancel
+ *
+ * Description Cancels an ongoing search for devices
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ tBTA_DM_MSG* p_msg;
+
+ if (BTM_IsInquiryActive()) {
+ if (BTM_CancelInquiry() == BTM_SUCCESS) {
+ bta_dm_search_cancel_notify(NULL);
+ p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ } else {
+ /* flag a search cancel is pending */
+ bta_dm_search_cb.cancel_pending = true;
+ }
+ }
+ /* If no Service Search going on then issue cancel remote name in case it is
+ active */
+ else if (!bta_dm_search_cb.name_discover_done) {
+ BTM_CancelRemoteDeviceName();
+
+ p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ } else {
+ p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+
+ if (bta_dm_search_cb.gatt_disc_active) {
+ bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_discover
+ *
+ * Description Discovers services on a remote device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_discover(tBTA_DM_MSG* p_data) {
+ size_t len = sizeof(tBT_UUID) * p_data->discover.num_uuid;
+ APPL_TRACE_EVENT("%s services_to_search=0x%04X, sdp_search=%d", __func__,
+ p_data->discover.services, p_data->discover.sdp_search);
+
+ /* save the search condition */
+ bta_dm_search_cb.services = p_data->discover.services;
+
+ bta_dm_gattc_register();
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+ if ((bta_dm_search_cb.num_uuid = p_data->discover.num_uuid) != 0 &&
+ p_data->discover.p_uuid != NULL) {
+ bta_dm_search_cb.p_srvc_uuid = (tBT_UUID*)osi_malloc(len);
+ memcpy(bta_dm_search_cb.p_srvc_uuid, p_data->discover.p_uuid, len);
+ }
+ bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+
+ bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
+ bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+ bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+ bta_dm_search_cb.service_index = 0;
+ bta_dm_search_cb.services_found = 0;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_search_cb.sdp_search = p_data->discover.sdp_search;
+ bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead(p_data->discover.bd_addr);
+ bta_dm_search_cb.transport = p_data->discover.transport;
+
+ bta_dm_search_cb.name_discover_done = false;
+ memcpy(&bta_dm_search_cb.uuid, &p_data->discover.uuid, sizeof(tSDP_UUID));
+ bta_dm_discover_device(p_data->discover.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_di_disc_cmpl
+ *
+ * Description Sends event to application when DI discovery complete
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_di_disc_cmpl(tBTA_DM_MSG* p_data) {
+ tBTA_DM_DI_DISC_CMPL di_disc;
+
+ memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL));
+ bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr);
+
+ if ((p_data->hdr.offset == SDP_SUCCESS) ||
+ (p_data->hdr.offset == SDP_DB_FULL)) {
+ di_disc.num_record = SDP_GetNumDiRecords(bta_dm_di_cb.p_di_db);
+ } else
+ di_disc.result = BTA_FAILURE;
+
+ bta_dm_di_cb.p_di_db = NULL;
+ bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT,
+ (tBTA_DM_SEARCH*)&di_disc);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_di_disc_callback
+ *
+ * Description This function queries a remote device for DI information.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_di_disc_callback(uint16_t result) {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+ p_msg->hdr.offset = result;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable_search_and_disc
+ *
+ * Description Cancels an ongoing search or discovery for devices in case
+ * of a Bluetooth disable
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_search_and_disc(void) {
+ tBTA_DM_DI_DISC_CMPL di_disc;
+
+ if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) bta_dm_search_cancel(NULL);
+
+ if (bta_dm_di_cb.p_di_db != NULL) {
+ memset(&di_disc, 0, sizeof(tBTA_DM_DI_DISC_CMPL));
+ bdcpy(di_disc.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ di_disc.result = BTA_FAILURE;
+
+ bta_dm_di_cb.p_di_db = NULL;
+ bta_dm_search_cb.p_search_cback(BTA_DM_DI_DISC_CMPL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_di_disc
+ *
+ * Description This function queries a remote device for DI information.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_di_disc(tBTA_DM_MSG* p_data) {
+ uint16_t result = BTA_FAILURE;
+
+ bta_dm_search_cb.p_search_cback = p_data->di_disc.p_cback;
+ bdcpy(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.bd_addr);
+ bta_dm_di_cb.p_di_db = p_data->di_disc.p_sdp_db;
+
+ bta_dm_search_cb.p_sdp_db =
+ (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE);
+ if (SDP_DiDiscover(bta_dm_search_cb.peer_bdaddr, p_data->di_disc.p_sdp_db,
+ p_data->di_disc.len,
+ bta_dm_di_disc_callback) == SDP_SUCCESS) {
+ result = BTA_SUCCESS;
+ }
+
+ if (result == BTA_FAILURE) {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DI_DISCOVER_EVT;
+ p_data->hdr.offset = result;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_read_remote_device_name
+ *
+ * Description Initiate to get remote device name
+ *
+ * Returns true if started to get remote name
+ *
+ ******************************************************************************/
+static bool bta_dm_read_remote_device_name(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport) {
+ tBTM_STATUS btm_status;
+
+ APPL_TRACE_DEBUG("bta_dm_read_remote_device_name");
+
+ bdcpy(bta_dm_search_cb.peer_bdaddr, bd_addr);
+ bta_dm_search_cb.peer_name[0] = 0;
+
+ btm_status =
+ BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+ (tBTM_CMPL_CB*)bta_dm_remname_cback, transport);
+
+ if (btm_status == BTM_CMD_STARTED) {
+ APPL_TRACE_DEBUG(
+ "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is started");
+
+ return (true);
+ } else if (btm_status == BTM_BUSY) {
+ APPL_TRACE_DEBUG(
+ "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName is busy");
+
+ /* Remote name discovery is on going now so BTM cannot notify through
+ * "bta_dm_remname_cback" */
+ /* adding callback to get notified that current reading remore name done */
+ BTM_SecAddRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ return (true);
+ } else {
+ APPL_TRACE_WARNING(
+ "bta_dm_read_remote_device_name: BTM_ReadRemoteDeviceName returns "
+ "0x%02X",
+ btm_status);
+
+ return (false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_inq_cmpl
+ *
+ * Description Process the inquiry complete event from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_inq_cmpl(tBTA_DM_MSG* p_data) {
+ tBTA_DM_SEARCH data;
+
+ APPL_TRACE_DEBUG("bta_dm_inq_cmpl");
+
+ data.inq_cmpl.num_resps = p_data->inq_cmpl.num;
+ bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
+
+ bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst();
+ if (bta_dm_search_cb.p_btm_inq_info != NULL) {
+ /* start name and service discovery from the first device on inquiry result
+ */
+ bta_dm_search_cb.name_discover_done = false;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_discover_device(
+ bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+ } else {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ /* no devices, search complete */
+ bta_dm_search_cb.services = 0;
+
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_rmt_name
+ *
+ * Description Process the remote name result from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_rmt_name(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_DEBUG("bta_dm_rmt_name");
+
+ if (p_data->rem_name.result.disc_res.bd_name[0] &&
+ bta_dm_search_cb.p_btm_inq_info) {
+ bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name = true;
+ }
+
+ bta_dm_discover_device(bta_dm_search_cb.peer_bdaddr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disc_rmt_name
+ *
+ * Description Process the remote name result from BTM when application
+ * wants to find the name for a bdaddr
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data) {
+ tBTM_INQ_INFO* p_btm_inq_info;
+
+ APPL_TRACE_DEBUG("bta_dm_disc_rmt_name");
+
+ p_btm_inq_info = BTM_InqDbRead(p_data->rem_name.result.disc_res.bd_addr);
+ if (p_btm_inq_info) {
+ if (p_data->rem_name.result.disc_res.bd_name[0]) {
+ p_btm_inq_info->appl_knows_rem_name = true;
+ }
+ }
+
+ bta_dm_discover_device(p_data->rem_name.result.disc_res.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sdp_result
+ *
+ * Description Process the discovery result from sdp
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
+ tSDP_DISC_REC* p_sdp_rec = NULL;
+ tBTA_DM_MSG* p_msg;
+ bool scn_found = false;
+ uint16_t service = 0xFFFF;
+ tSDP_PROTOCOL_ELEM pe;
+
+ tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid;
+ tBTA_DM_SEARCH result;
+ tBT_UUID service_uuid;
+
+ uint32_t num_uuids = 0;
+ uint8_t uuid_list[32][MAX_UUID_SIZE]; // assuming a max of 32 services
+
+ if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
+ (p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) ||
+ (p_data->sdp_event.sdp_result == SDP_DB_FULL)) {
+ APPL_TRACE_DEBUG("sdp_result::0x%x", p_data->sdp_event.sdp_result);
+ do {
+ p_sdp_rec = NULL;
+ if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) {
+ p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
+ &bta_dm_search_cb.uuid, p_sdp_rec);
+
+ if (p_sdp_rec && SDP_FindProtocolListElemInRec(
+ p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ bta_dm_search_cb.peer_scn = (uint8_t)pe.params[0];
+ scn_found = true;
+ }
+ } else {
+ service =
+ bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index - 1];
+ p_sdp_rec =
+ SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, service, p_sdp_rec);
+ }
+ /* finished with BR/EDR services, now we check the result for GATT based
+ * service UUID */
+ if (bta_dm_search_cb.service_index == BTA_MAX_SERVICE_ID) {
+ if (bta_dm_search_cb.uuid_to_search != 0 && p_uuid != NULL) {
+ p_uuid +=
+ (bta_dm_search_cb.num_uuid - bta_dm_search_cb.uuid_to_search);
+ /* only support 16 bits UUID for now */
+ service = p_uuid->uu.uuid16;
+ }
+ /* all GATT based services */
+ do {
+ /* find a service record, report it */
+ p_sdp_rec =
+ SDP_FindServiceInDb(bta_dm_search_cb.p_sdp_db, 0, p_sdp_rec);
+ if (p_sdp_rec) {
+ if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
+ /* send result back to app now, one by one */
+ bdcpy(result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
+ BD_NAME_LEN);
+ result.disc_ble_res.service.len = service_uuid.len;
+ result.disc_ble_res.service.uu.uuid16 = service_uuid.uu.uuid16;
+
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+ }
+ }
+
+ if (bta_dm_search_cb.uuid_to_search > 0) break;
+
+ } while (p_sdp_rec);
+ } else {
+ /* SDP_DB_FULL means some records with the
+ required attributes were received */
+ if (((p_data->sdp_event.sdp_result == SDP_DB_FULL) &&
+ bta_dm_search_cb.services != BTA_ALL_SERVICE_MASK) ||
+ (p_sdp_rec != NULL)) {
+ if (service != UUID_SERVCLASS_PNP_INFORMATION) {
+ uint16_t tmp_svc = 0xFFFF;
+ bta_dm_search_cb.services_found |=
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(
+ bta_dm_search_cb.service_index - 1));
+ tmp_svc =
+ bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index -
+ 1];
+ /* Add to the list of UUIDs */
+ sdpu_uuid16_to_uuid128(tmp_svc, uuid_list[num_uuids]);
+ num_uuids++;
+ }
+ }
+ }
+
+ if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK &&
+ bta_dm_search_cb.services_to_search == 0) {
+ if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+ bta_dm_search_cb.uuid_to_search > 0)
+ bta_dm_search_cb.uuid_to_search--;
+
+ if (bta_dm_search_cb.uuid_to_search == 0 ||
+ bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+ bta_dm_search_cb.service_index++;
+ } else /* regular one service per search or PNP search */
+ break;
+
+ } while (bta_dm_search_cb.service_index <= BTA_MAX_SERVICE_ID);
+
+ APPL_TRACE_DEBUG("%s services_found = %04x", __func__,
+ bta_dm_search_cb.services_found);
+
+ /* Collect the 128-bit services here and put them into the list */
+ if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
+ p_sdp_rec = NULL;
+ do {
+ tBT_UUID temp_uuid;
+ /* find a service record, report it */
+ p_sdp_rec =
+ SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec);
+ if (p_sdp_rec) {
+ if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) {
+ memcpy(uuid_list[num_uuids], temp_uuid.uu.uuid128, MAX_UUID_SIZE);
+ num_uuids++;
+ }
+ }
+ } while (p_sdp_rec);
+ }
+ /* if there are more services to search for */
+ if (bta_dm_search_cb.services_to_search) {
+ /* Free up the p_sdp_db before checking the next one */
+ bta_dm_free_sdp_db(NULL);
+ bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+ } else {
+ /* callbacks */
+ /* start next bd_addr if necessary */
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+ p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+ p_msg->disc_result.result.disc_res.raw_data_size = 0;
+ p_msg->disc_result.result.disc_res.num_uuids = num_uuids;
+ p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
+ if (num_uuids > 0) {
+ p_msg->disc_result.result.disc_res.p_uuid_list =
+ (uint8_t*)osi_malloc(num_uuids * MAX_UUID_SIZE);
+ memcpy(p_msg->disc_result.result.disc_res.p_uuid_list, uuid_list,
+ num_uuids * MAX_UUID_SIZE);
+ }
+ // Copy the raw_data to the discovery result structure
+ if (bta_dm_search_cb.p_sdp_db != NULL &&
+ bta_dm_search_cb.p_sdp_db->raw_used != 0 &&
+ bta_dm_search_cb.p_sdp_db->raw_data != NULL) {
+ APPL_TRACE_DEBUG("%s raw_data used = 0x%x raw_data_ptr = 0x%x",
+ __func__, bta_dm_search_cb.p_sdp_db->raw_used,
+ bta_dm_search_cb.p_sdp_db->raw_data);
+
+ p_msg->disc_result.result.disc_res.p_raw_data =
+ (uint8_t*)osi_malloc(bta_dm_search_cb.p_sdp_db->raw_used);
+ memcpy(p_msg->disc_result.result.disc_res.p_raw_data,
+ bta_dm_search_cb.p_sdp_db->raw_data,
+ bta_dm_search_cb.p_sdp_db->raw_used);
+
+ p_msg->disc_result.result.disc_res.raw_data_size =
+ bta_dm_search_cb.p_sdp_db->raw_used;
+
+ bta_dm_search_cb.p_sdp_db->raw_data =
+ NULL; // no need to free this - it is a global assigned.
+ bta_dm_search_cb.p_sdp_db->raw_used = 0;
+ bta_dm_search_cb.p_sdp_db->raw_size = 0;
+ } else {
+ APPL_TRACE_DEBUG("%s raw data size is 0 or raw_data is null!!",
+ __func__);
+ }
+ /* Done with p_sdp_db. Free it */
+ bta_dm_free_sdp_db(NULL);
+ p_msg->disc_result.result.disc_res.services =
+ bta_dm_search_cb.services_found;
+
+ // Piggy back the SCN over result field
+ if (scn_found) {
+ p_msg->disc_result.result.disc_res.result =
+ (3 + bta_dm_search_cb.peer_scn);
+ p_msg->disc_result.result.disc_res.services |= BTA_USER_SERVICE_MASK;
+
+ APPL_TRACE_EVENT(" Piggy back the SCN over result field SCN=%d",
+ bta_dm_search_cb.peer_scn);
+ }
+ bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+ bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+ bta_dm_get_remname(), BD_NAME_LEN);
+
+ bta_sys_sendmsg(p_msg);
+ }
+ } else {
+ /* conn failed. No need for timer */
+ if (p_data->sdp_event.sdp_result == SDP_CONN_FAILED ||
+ p_data->sdp_event.sdp_result == SDP_CONN_REJECTED ||
+ p_data->sdp_event.sdp_result == SDP_SECURITY_ERR)
+ bta_dm_search_cb.wait_disc = false;
+
+ /* not able to connect go to next device */
+ if (bta_dm_search_cb.p_sdp_db)
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result = BTA_FAILURE;
+ p_msg->disc_result.result.disc_res.services =
+ bta_dm_search_cb.services_found;
+ bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+ bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+ bta_dm_get_remname(), BD_NAME_LEN);
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_cmpl
+ *
+ * Description Sends event to application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_cmpl(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_EVENT("%s", __func__);
+
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid);
+
+ if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT)
+ bta_dm_di_disc_cmpl(p_data);
+ else
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disc_result
+ *
+ * Description Service discovery result when discovering services on a
+ * device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_disc_result(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_EVENT("%s", __func__);
+
+ /* if any BR/EDR service discovery has been done, report the event */
+ if ((bta_dm_search_cb.services &
+ ((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) &
+ ~BTA_BLE_SERVICE_MASK)))
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
+ &p_data->disc_result.result);
+
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ /* send a message to change state */
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_result
+ *
+ * Description Service discovery result while searching for devices
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_result(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_DEBUG("%s searching:0x%04x, result:0x%04x", __func__,
+ bta_dm_search_cb.services,
+ p_data->disc_result.result.disc_res.services);
+
+ /* call back if application wants name discovery or found services that
+ * application is searching */
+ if ((!bta_dm_search_cb.services) ||
+ ((bta_dm_search_cb.services) &&
+ (p_data->disc_result.result.disc_res.services))) {
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
+ &p_data->disc_result.result);
+ }
+
+ /* if searching did not initiate to create link */
+ if (!bta_dm_search_cb.wait_disc) {
+ /* if service searching is done with EIR, don't search next device */
+ if (bta_dm_search_cb.p_btm_inq_info) bta_dm_discover_next_device();
+ } else {
+ /* wait until link is disconnected or timeout */
+ bta_dm_search_cb.sdp_results = true;
+ alarm_set_on_queue(bta_dm_search_cb.search_timer,
+ 1000 * (L2CAP_LINK_INACTIVITY_TOUT + 1),
+ bta_dm_search_timer_cback, NULL, btu_bta_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_timer_cback
+ *
+ * Description Called when ACL disconnect time is over
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_search_timer_cback(UNUSED_ATTR void* data) {
+ APPL_TRACE_EVENT("%s", __func__);
+ bta_dm_search_cb.wait_disc = false;
+
+ /* proceed with next device */
+ bta_dm_discover_next_device();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_free_sdp_db
+ *
+ * Description Frees SDP data base
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_free_sdp_db(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_queue_search
+ *
+ * Description Queues search command while search is being cancelled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_queue_search(tBTA_DM_MSG* p_data) {
+ osi_free(bta_dm_search_cb.p_search_queue);
+ bta_dm_search_cb.p_search_queue =
+ (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_SEARCH));
+ memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_SEARCH));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_queue_disc
+ *
+ * Description Queues discovery command while search is being cancelled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_queue_disc(tBTA_DM_MSG* p_data) {
+ osi_free(bta_dm_search_cb.p_search_queue);
+ bta_dm_search_cb.p_search_queue =
+ (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
+ memcpy(bta_dm_search_cb.p_search_queue, p_data, sizeof(tBTA_DM_API_DISCOVER));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_clear_queue
+ *
+ * Description Clears the queue if API search cancel is called
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_clear_queue(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_search_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_cancel_cmpl
+ *
+ * Description Search cancel is complete
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_cmpl(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ if (bta_dm_search_cb.p_search_queue) {
+ bta_sys_sendmsg(bta_dm_search_cb.p_search_queue);
+ bta_dm_search_cb.p_search_queue = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_cancel_transac_cmpl
+ *
+ * Description Current Service Discovery or remote name procedure is
+ * completed after search cancellation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_transac_cmpl(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cancel_notify(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_cancel_notify
+ *
+ * Description Notify application that search has been cancelled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_cancel_notify(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ if (bta_dm_search_cb.p_search_cback) {
+ bta_dm_search_cb.p_search_cback(BTA_DM_SEARCH_CANCEL_CMPL_EVT, NULL);
+ }
+ if (!bta_dm_search_cb.name_discover_done) {
+ BTM_CancelRemoteDeviceName();
+ }
+ if (bta_dm_search_cb.gatt_disc_active) {
+ bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_find_services
+ *
+ * Description Starts discovery on a device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_find_services(BD_ADDR bd_addr) {
+ tSDP_UUID uuid;
+
+ memset(&uuid, 0, sizeof(tSDP_UUID));
+
+ while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
+ if (bta_dm_search_cb.services_to_search &
+ (tBTA_SERVICE_MASK)(
+ BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) {
+ bta_dm_search_cb.p_sdp_db =
+ (tSDP_DISCOVERY_DB*)osi_malloc(BTA_DM_SDP_DB_SIZE);
+ APPL_TRACE_DEBUG("bta_dm_search_cb.services = %04x***********",
+ bta_dm_search_cb.services);
+ /* try to search all services by search based on L2CAP UUID */
+ if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
+ LOG_INFO(LOG_TAG, "%s services_to_search=%08x", __func__,
+ bta_dm_search_cb.services_to_search);
+ if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
+ uuid.uu.uuid16 = bta_service_id_to_uuid_lkup_tbl[0];
+ bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
+ } else {
+ uuid.uu.uuid16 = UUID_PROTOCOL_L2CAP;
+ bta_dm_search_cb.services_to_search = 0;
+ }
+ } else {
+ /* for LE only profile */
+ if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
+ if (bta_dm_search_cb.uuid_to_search > 0 &&
+ bta_dm_search_cb.p_srvc_uuid) {
+ memcpy(&uuid, (const void*)(bta_dm_search_cb.p_srvc_uuid +
+ bta_dm_search_cb.num_uuid -
+ bta_dm_search_cb.uuid_to_search),
+ sizeof(tBT_UUID));
+
+ bta_dm_search_cb.uuid_to_search--;
+ } else {
+ uuid.uu.uuid16 =
+ bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+ }
+
+ /* last one? clear the BLE service bit if all discovery has been done
+ */
+ if (bta_dm_search_cb.uuid_to_search == 0)
+ bta_dm_search_cb.services_to_search &=
+ (tBTA_SERVICE_MASK)(~(BTA_SERVICE_ID_TO_SERVICE_MASK(
+ bta_dm_search_cb.service_index)));
+
+ } else {
+ /* remove the service from services to be searched */
+ bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
+ BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
+ uuid.uu.uuid16 =
+ bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index];
+ }
+ }
+
+ if (uuid.len == 0) uuid.len = LEN_UUID_16;
+
+ if (bta_dm_search_cb.service_index == BTA_USER_SERVICE_ID) {
+ memcpy(&uuid, &bta_dm_search_cb.uuid, sizeof(tSDP_UUID));
+ }
+
+ LOG_INFO(LOG_TAG, "%s search UUID = %04x", __func__, uuid.uu.uuid16);
+ SDP_InitDiscoveryDb(bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1,
+ &uuid, 0, NULL);
+
+ memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+ bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf;
+
+ bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF;
+
+ if (!SDP_ServiceSearchAttributeRequest(bd_addr, bta_dm_search_cb.p_sdp_db,
+ &bta_dm_sdp_callback)) {
+ /*
+ * If discovery is not successful with this device, then
+ * proceed with the next one.
+ */
+ osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
+ bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID;
+
+ } else {
+ if ((bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID &&
+ bta_dm_search_cb.uuid_to_search == 0) ||
+ bta_dm_search_cb.service_index != BTA_BLE_SERVICE_ID)
+ bta_dm_search_cb.service_index++;
+ return;
+ }
+ }
+
+ bta_dm_search_cb.service_index++;
+ }
+
+ /* no more services to be discovered */
+ if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ /* initialize the data structure - includes p_raw_data and raw_data_size */
+ memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.services =
+ bta_dm_search_cb.services_found;
+ bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+ bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+ bta_dm_get_remname(), BD_NAME_LEN);
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_discover_next_device
+ *
+ * Description Starts discovery on the next device in Inquiry data base
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_discover_next_device(void) {
+ APPL_TRACE_DEBUG("bta_dm_discover_next_device");
+
+ /* searching next device on inquiry result */
+ bta_dm_search_cb.p_btm_inq_info =
+ BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info);
+ if (bta_dm_search_cb.p_btm_inq_info != NULL) {
+ bta_dm_search_cb.name_discover_done = false;
+ bta_dm_search_cb.peer_name[0] = 0;
+ bta_dm_discover_device(
+ bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);
+ } else {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ /* no devices, search complete */
+ bta_dm_search_cb.services = 0;
+
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_discover_device
+ *
+ * Description Starts name and service discovery on the device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_discover_device(BD_ADDR remote_bd_addr) {
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+ if (bta_dm_search_cb.transport == BTA_TRANSPORT_UNKNOWN) {
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM)
+ transport = BT_TRANSPORT_LE;
+ } else {
+ transport = bta_dm_search_cb.transport;
+ }
+
+ /* Reset transport state for next discovery */
+ bta_dm_search_cb.transport = BTA_TRANSPORT_UNKNOWN;
+
+ APPL_TRACE_DEBUG("%s BDA:0x%02X%02X%02X%02X%02X%02X", __func__,
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+ bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr);
+
+ APPL_TRACE_DEBUG(
+ "%s name_discover_done = %d p_btm_inq_info 0x%x state = %d, transport=%d",
+ __func__, bta_dm_search_cb.name_discover_done,
+ bta_dm_search_cb.p_btm_inq_info, bta_dm_search_cb.state, transport);
+
+ if (bta_dm_search_cb.p_btm_inq_info) {
+ APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__,
+ bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
+ }
+ if ((bta_dm_search_cb.p_btm_inq_info) &&
+ (bta_dm_search_cb.p_btm_inq_info->results.device_type ==
+ BT_DEVICE_TYPE_BLE) &&
+ (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) {
+ /* Do not perform RNR for LE devices at inquiry complete*/
+ bta_dm_search_cb.name_discover_done = true;
+ }
+ /* if name discovery is not done and application needs remote name */
+ if ((!bta_dm_search_cb.name_discover_done) &&
+ ((bta_dm_search_cb.p_btm_inq_info == NULL) ||
+ (bta_dm_search_cb.p_btm_inq_info &&
+ (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name)))) {
+ if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr,
+ transport) == true)
+ return;
+
+ /* starting name discovery failed */
+ bta_dm_search_cb.name_discover_done = true;
+ }
+
+ /* if application wants to discover service */
+ if (bta_dm_search_cb.services) {
+ /* initialize variables */
+ bta_dm_search_cb.service_index = 0;
+ bta_dm_search_cb.services_found = 0;
+ bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
+ bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid;
+ if ((bta_dm_search_cb.p_btm_inq_info != NULL) &&
+ bta_dm_search_cb.services != BTA_USER_SERVICE_MASK &&
+ (bta_dm_search_cb.sdp_search == false)) {
+ /* check if EIR provides the information of supported services */
+ bta_dm_eir_search_services(&bta_dm_search_cb.p_btm_inq_info->results,
+ &bta_dm_search_cb.services_to_search,
+ &bta_dm_search_cb.services_found);
+ }
+
+ /* if seaching with EIR is not completed */
+ if (bta_dm_search_cb.services_to_search) {
+ /* check whether connection already exists to the device
+ if connection exists, we don't have to wait for ACL
+ link to go down to start search on next device */
+
+ /** M: only check BR device */
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr,
+ BT_TRANSPORT_BR_EDR))
+ bta_dm_search_cb.wait_disc = false;
+ else
+ bta_dm_search_cb.wait_disc = true;
+ }
+
+ if (bta_dm_search_cb.p_btm_inq_info) {
+ APPL_TRACE_DEBUG(
+ "%s p_btm_inq_info 0x%x results.device_type 0x%x "
+ "services_to_search 0x%x",
+ __func__, bta_dm_search_cb.p_btm_inq_info,
+ bta_dm_search_cb.p_btm_inq_info->results.device_type,
+ bta_dm_search_cb.services_to_search);
+ }
+
+ if (transport == BT_TRANSPORT_LE) {
+ if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) {
+ // set the raw data buffer here
+ memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
+ bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf;
+
+ bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF;
+ bta_dm_search_cb.ble_raw_used = 0;
+
+ /* start GATT for service discovery */
+ btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
+ return;
+ }
+ } else {
+ bta_dm_search_cb.sdp_results = false;
+ bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
+ return;
+ }
+ }
+ }
+
+ /* name discovery and service discovery are done for this device */
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ /* initialize the data structure - includes p_raw_data and raw_data_size */
+ memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES));
+ p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
+ p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
+ bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+ bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+ (char*)bta_dm_search_cb.peer_name, BD_NAME_LEN);
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sdp_callback
+ *
+ * Description Callback from sdp with discovery status
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_sdp_callback(uint16_t sdp_status) {
+ tBTA_DM_SDP_RESULT* p_msg =
+ (tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT));
+
+ p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
+ p_msg->sdp_result = sdp_status;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_inq_results_cb
+ *
+ * Description Inquiry results callback from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_inq_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
+ uint16_t eir_len) {
+ tBTA_DM_SEARCH result;
+ tBTM_INQ_INFO* p_inq_info;
+ uint16_t service_class;
+
+ bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
+ memcpy(result.inq_res.dev_class, p_inq->dev_class, DEV_CLASS_LEN);
+ BTM_COD_SERVICE_CLASS(service_class, p_inq->dev_class);
+ result.inq_res.is_limited =
+ (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false;
+ result.inq_res.rssi = p_inq->rssi;
+
+ result.inq_res.ble_addr_type = p_inq->ble_addr_type;
+ result.inq_res.inq_result_type = p_inq->inq_result_type;
+ result.inq_res.device_type = p_inq->device_type;
+ result.inq_res.flag = p_inq->flag;
+
+ /* application will parse EIR to find out remote device name */
+ result.inq_res.p_eir = p_eir;
+ result.inq_res.eir_len = eir_len;
+
+ p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr);
+ if (p_inq_info != NULL) {
+ /* initialize remt_name_not_required to false so that we get the name by
+ * default */
+ result.inq_res.remt_name_not_required = false;
+ }
+
+ if (bta_dm_search_cb.p_search_cback)
+ bta_dm_search_cb.p_search_cback(BTA_DM_INQ_RES_EVT, &result);
+
+ if (p_inq_info) {
+ /* application indicates if it knows the remote name, inside the callback
+ copy that to the inquiry data base*/
+ if (result.inq_res.remt_name_not_required)
+ p_inq_info->appl_knows_rem_name = true;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_inq_cmpl_cb
+ *
+ * Description Inquiry complete callback from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_inq_cmpl_cb(void* p_result) {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (bta_dm_search_cb.cancel_pending == false) {
+ p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
+ p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
+ } else {
+ bta_dm_search_cb.cancel_pending = false;
+ bta_dm_search_cancel_notify(NULL);
+ p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
+ p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
+ }
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_service_search_remname_cback
+ *
+ * Description Remote name call back from BTM during service discovery
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_service_search_remname_cback(BD_ADDR bd_addr,
+ UNUSED_ATTR DEV_CLASS dc,
+ BD_NAME bd_name) {
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_STATUS btm_status;
+
+ APPL_TRACE_DEBUG("bta_dm_service_search_remname_cback name=<%s>", bd_name);
+
+ /* if this is what we are looking for */
+ if (!bdcmp(bta_dm_search_cb.peer_bdaddr, bd_addr)) {
+ rem_name.length = strlen((char*)bd_name);
+ if (rem_name.length > (BD_NAME_LEN - 1)) {
+ rem_name.length = (BD_NAME_LEN - 1);
+ rem_name.remote_bd_name[(BD_NAME_LEN - 1)] = 0;
+ }
+ strlcpy((char*)rem_name.remote_bd_name, (char*)bd_name, BD_NAME_LEN);
+ rem_name.status = BTM_SUCCESS;
+
+ bta_dm_remname_cback(&rem_name);
+ } else {
+ /* get name of device */
+ btm_status = BTM_ReadRemoteDeviceName(bta_dm_search_cb.peer_bdaddr,
+ (tBTM_CMPL_CB*)bta_dm_remname_cback,
+ BT_TRANSPORT_BR_EDR);
+ if (btm_status == BTM_BUSY) {
+ /* wait for next chance(notification of remote name discovery done) */
+ APPL_TRACE_DEBUG(
+ "bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName is "
+ "busy");
+ } else if (btm_status != BTM_CMD_STARTED) {
+ /* if failed to start getting remote name then continue */
+ APPL_TRACE_WARNING(
+ "bta_dm_service_search_remname_cback: BTM_ReadRemoteDeviceName "
+ "returns 0x%02X",
+ btm_status);
+
+ rem_name.length = 0;
+ rem_name.remote_bd_name[0] = 0;
+ rem_name.status = btm_status;
+ bta_dm_remname_cback(&rem_name);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_remname_cback
+ *
+ * Description Remote name complete call back from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_remname_cback(tBTM_REMOTE_DEV_NAME* p_remote_name) {
+ APPL_TRACE_DEBUG("bta_dm_remname_cback len = %d name=<%s>",
+ p_remote_name->length, p_remote_name->remote_bd_name);
+
+ /* remote name discovery is done but it could be failed */
+ bta_dm_search_cb.name_discover_done = true;
+ strlcpy((char*)bta_dm_search_cb.peer_name,
+ (char*)p_remote_name->remote_bd_name, BD_NAME_LEN);
+
+ BTM_SecDeleteRmtNameNotifyCallback(&bta_dm_service_search_remname_cback);
+
+ if (bta_dm_search_cb.transport == BT_TRANSPORT_LE) {
+ GAP_BleReadPeerPrefConnParams(bta_dm_search_cb.peer_bdaddr);
+ }
+
+ tBTA_DM_REM_NAME* p_msg =
+ (tBTA_DM_REM_NAME*)osi_malloc(sizeof(tBTA_DM_REM_NAME));
+ bdcpy(p_msg->result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->result.disc_res.bd_name,
+ (char*)p_remote_name->remote_bd_name, BD_NAME_LEN);
+ p_msg->hdr.event = BTA_DM_REMT_NAME_EVT;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_authorize_cback
+ *
+ * Description cback requesting authorization
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_authorize_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name,
+ UNUSED_ATTR uint8_t* service_name,
+ uint8_t service_id,
+ UNUSED_ATTR bool is_originator) {
+ tBTA_DM_SEC sec_event;
+ uint8_t index = 1;
+
+ bdcpy(sec_event.authorize.bd_addr, bd_addr);
+ memcpy(sec_event.authorize.dev_class, dev_class, DEV_CLASS_LEN);
+ strlcpy((char*)sec_event.authorize.bd_name, (char*)bd_name, BD_NAME_LEN);
+
+#if (BTA_JV_INCLUDED == TRUE)
+ sec_event.authorize.service = service_id;
+#endif
+
+ while (index < BTA_MAX_SERVICE_ID) {
+ /* get the BTA service id corresponding to BTM id */
+ if (bta_service_id_to_btm_srv_id_lkup_tbl[index] == service_id) {
+ sec_event.authorize.service = index;
+ break;
+ }
+ index++;
+ }
+
+ /* if supported service callback otherwise not authorized */
+ if (bta_dm_cb.p_sec_cback && (index < BTA_MAX_SERVICE_ID
+#if (BTA_JV_INCLUDED == TRUE)
+ /* pass through JV service ID */
+ || (service_id >= BTA_FIRST_JV_SERVICE_ID &&
+ service_id <= BTA_LAST_JV_SERVICE_ID)
+#endif
+ )) {
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTHORIZE_EVT, &sec_event);
+ return BTM_CMD_STARTED;
+ } else {
+ return BTM_NOT_AUTHORIZED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pinname_cback
+ *
+ * Description Callback requesting pin_key
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pinname_cback(void* p_data) {
+ tBTM_REMOTE_DEV_NAME* p_result = (tBTM_REMOTE_DEV_NAME*)p_data;
+ tBTA_DM_SEC sec_event;
+ uint32_t bytes_to_copy;
+ tBTA_DM_SEC_EVT event = bta_dm_cb.pin_evt;
+ /** M: restore the authentication requirement @{ */
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ /** @} */
+
+ /** M: make sure the variable correct @{ */
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ /** @} */
+ /** M: restore the authentication requirement @{ */
+ p_dev_rec = btm_find_or_alloc_dev(bta_dm_cb.pin_bd_addr);
+ /** @} */
+
+ if (BTA_DM_SP_CFM_REQ_EVT == event) {
+ /* Retrieved saved device class and bd_addr */
+ bdcpy(sec_event.cfm_req.bd_addr, bta_dm_cb.pin_bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class, bta_dm_cb.pin_dev_class);
+
+ if (p_result && p_result->status == BTM_SUCCESS) {
+ bytes_to_copy = (p_result->length < (BD_NAME_LEN - 1))
+ ? p_result->length
+ : (BD_NAME_LEN - 1);
+ memcpy(sec_event.cfm_req.bd_name, p_result->remote_bd_name,
+ bytes_to_copy);
+ sec_event.pin_req.bd_name[BD_NAME_LEN - 1] = 0;
+ } else /* No name found */
+ sec_event.cfm_req.bd_name[0] = 0;
+
+ sec_event.key_notif.passkey =
+ bta_dm_cb.num_val; /* get PIN code numeric number */
+
+ /** M: restore the authentication requirement @{ */
+ sec_event.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req;
+ sec_event.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req;
+ /** @} */
+ /* 1 additional event data fields for this event */
+ sec_event.cfm_req.just_works = bta_dm_cb.just_works;
+ } else {
+ /* Retrieved saved device class and bd_addr */
+ bdcpy(sec_event.pin_req.bd_addr, bta_dm_cb.pin_bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, bta_dm_cb.pin_dev_class);
+
+ if (p_result && p_result->status == BTM_SUCCESS) {
+ bytes_to_copy = (p_result->length < (BD_NAME_LEN - 1))
+ ? p_result->length
+ : (BD_NAME_LEN - 1);
+ memcpy(sec_event.pin_req.bd_name, p_result->remote_bd_name,
+ bytes_to_copy);
+ sec_event.pin_req.bd_name[BD_NAME_LEN - 1] = 0;
+ /** M: fill correct info before callback @{ */
+ if (BTA_DM_PIN_REQ_EVT == event)
+ {
+ sec_event.pin_req.min_16_digit = (p_dev_rec->p_cur_service == NULL) ? FALSE
+ : (p_dev_rec->p_cur_service->security_flags & BTM_SEC_IN_MIN_16_DIGIT_PIN);
+ APPL_TRACE_DEBUG(" bta_dm_pinname_cback() min_16_digit=%d", sec_event.pin_req.min_16_digit);
+ }
+ /** @} */
+ } else /* No name found */
+ sec_event.pin_req.bd_name[0] = 0;
+
+ event = bta_dm_cb.pin_evt;
+ sec_event.key_notif.passkey =
+ bta_dm_cb.num_val; /* get PIN code numeric number */
+ }
+
+ if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pin_cback
+ *
+ * Description Callback requesting pin_key
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_pin_cback(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, bool min_16_digit) {
+ tBTA_DM_SEC sec_event;
+
+ if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+ /* If the device name is not known, save bdaddr and devclass and initiate a
+ * name request */
+ if (bd_name[0] == 0) {
+ bta_dm_cb.pin_evt = BTA_DM_PIN_REQ_EVT;
+ bdcpy(bta_dm_cb.pin_bd_addr, bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class, dev_class);
+ if ((BTM_ReadRemoteDeviceName(bd_addr, bta_dm_pinname_cback,
+ BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+
+ APPL_TRACE_WARNING(
+ " bta_dm_pin_cback() -> Failed to start Remote Name Request ");
+ }
+
+ bdcpy(sec_event.pin_req.bd_addr, bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.pin_req.dev_class, dev_class);
+ strlcpy((char*)sec_event.pin_req.bd_name, (char*)bd_name, BD_NAME_LEN);
+ sec_event.pin_req.min_16_digit = min_16_digit;
+
+ bta_dm_cb.p_sec_cback(BTA_DM_PIN_REQ_EVT, &sec_event);
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_new_link_key_cback
+ *
+ * Description Callback from BTM to notify new link key
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_new_link_key_cback(BD_ADDR bd_addr,
+ UNUSED_ATTR DEV_CLASS dev_class,
+ BD_NAME bd_name, LINK_KEY key,
+ uint8_t key_type) {
+ tBTA_DM_SEC sec_event;
+ tBTA_DM_AUTH_CMPL* p_auth_cmpl;
+ uint8_t event;
+
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+
+ /* Not AMP Key type */
+ if (key_type != HCI_LKEY_TYPE_AMP_WIFI && key_type != HCI_LKEY_TYPE_AMP_UWB) {
+ event = BTA_DM_AUTH_CMPL_EVT;
+ p_auth_cmpl = &sec_event.auth_cmpl;
+
+ bdcpy(p_auth_cmpl->bd_addr, bd_addr);
+
+ memcpy(p_auth_cmpl->bd_name, bd_name, (BD_NAME_LEN - 1));
+ p_auth_cmpl->bd_name[BD_NAME_LEN - 1] = 0;
+
+ p_auth_cmpl->key_present = true;
+ p_auth_cmpl->key_type = key_type;
+ p_auth_cmpl->success = true;
+
+ memcpy(p_auth_cmpl->key, key, LINK_KEY_LEN);
+ sec_event.auth_cmpl.fail_reason = HCI_SUCCESS;
+
+ // Report the BR link key based on the BR/EDR address and type
+ BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type,
+ &sec_event.auth_cmpl.addr_type);
+ if (bta_dm_cb.p_sec_cback) bta_dm_cb.p_sec_cback(event, &sec_event);
+
+ // Setting remove_dev_pending flag to false, where it will avoid deleting
+ // the
+ // security device record when the ACL connection link goes down in case of
+ // reconnection.
+ if (bta_dm_cb.device_list.count)
+ bta_dm_reset_sec_dev_pending(p_auth_cmpl->bd_addr);
+ } else {
+ APPL_TRACE_WARNING("%s() Received AMP Key", __func__);
+ }
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_authentication_complete_cback
+ *
+ * Description Authentication complete callback from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_authentication_complete_cback(
+ BD_ADDR bd_addr, UNUSED_ATTR DEV_CLASS dev_class, BD_NAME bd_name,
+ int result) {
+ tBTA_DM_SEC sec_event;
+
+ if (result != BTM_SUCCESS) {
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ bdcpy(sec_event.auth_cmpl.bd_addr, bd_addr);
+
+ memcpy(sec_event.auth_cmpl.bd_name, bd_name, (BD_NAME_LEN - 1));
+ sec_event.auth_cmpl.bd_name[BD_NAME_LEN - 1] = 0;
+
+ // Report the BR link key based on the BR/EDR address and type
+ BTM_ReadDevInfo(bd_addr, &sec_event.auth_cmpl.dev_type,
+ &sec_event.auth_cmpl.addr_type);
+ sec_event.auth_cmpl.fail_reason = (uint8_t)result;
+
+ if (bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+
+ if (result != HCI_ERR_LMP_RESPONSE_TIMEOUT &&
+ result != HCI_ERR_PAGE_TIMEOUT &&
+ result != HCI_ERR_CONN_FAILED_ESTABLISHMENT) {
+ bta_dm_remove_sec_dev_entry(bd_addr);
+ }
+ }
+
+ return BTM_SUCCESS;
+}
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+/*******************************************************************************
+ *
+ * Function bta_dm_sp_cback
+ *
+ * Description simple pairing callback from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_sp_cback(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data) {
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTA_DM_SEC sec_event;
+ tBTA_DM_SEC_EVT pin_evt = BTA_DM_SP_KEY_NOTIF_EVT;
+ /** M: use the correct addr and transfer it to uplayer @{ */
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ /** @} */
+
+ APPL_TRACE_EVENT("bta_dm_sp_cback: %d", event);
+ if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+ /* TODO_SP */
+ switch (event) {
+ case BTM_SP_IO_REQ_EVT:
+ /* translate auth_req */
+ bta_dm_co_io_req(p_data->io_req.bd_addr, &p_data->io_req.io_cap,
+ &p_data->io_req.oob_data, &p_data->io_req.auth_req,
+ p_data->io_req.is_orig);
+ APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
+ p_data->io_req.oob_data);
+ break;
+ case BTM_SP_IO_RSP_EVT:
+ bta_dm_co_io_rsp(p_data->io_rsp.bd_addr, p_data->io_rsp.io_cap,
+ p_data->io_rsp.oob_data, p_data->io_rsp.auth_req);
+ break;
+
+ case BTM_SP_CFM_REQ_EVT:
+ pin_evt = BTA_DM_SP_CFM_REQ_EVT;
+ bta_dm_cb.just_works = sec_event.cfm_req.just_works =
+ p_data->cfm_req.just_works;
+ sec_event.cfm_req.loc_auth_req = p_data->cfm_req.loc_auth_req;
+ sec_event.cfm_req.rmt_auth_req = p_data->cfm_req.rmt_auth_req;
+ sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps;
+ sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
+
+ /* continue to next case */
+ /* Passkey entry mode, mobile device with output capability is very
+ unlikely to receive key request, so skip this event */
+ /*case BTM_SP_KEY_REQ_EVT: */
+ case BTM_SP_KEY_NOTIF_EVT:
+ bta_dm_cb.num_val = sec_event.key_notif.passkey =
+ p_data->key_notif.passkey;
+
+ if (BTM_SP_CFM_REQ_EVT == event) {
+ /** M: use the correct addr and transfer it to uplayer @{ */
+ bdcpy(sec_event.cfm_req.bd_addr,p_data->cfm_req.bd_addr);
+ /** @} */
+ /* Due to the switch case falling through below to BTM_SP_KEY_NOTIF_EVT,
+ call remote name request using values from cfm_req */
+ if (p_data->cfm_req.bd_name[0] == 0) {
+ bta_dm_cb.pin_evt = pin_evt;
+ bdcpy(bta_dm_cb.pin_bd_addr, p_data->cfm_req.bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+ p_data->cfm_req.dev_class);
+ if ((BTM_ReadRemoteDeviceName(
+ p_data->cfm_req.bd_addr, bta_dm_pinname_cback,
+ BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+ APPL_TRACE_WARNING(
+ " bta_dm_sp_cback() -> Failed to start Remote Name Request ");
+ } else {
+ /* Due to the switch case falling through below to
+ BTM_SP_KEY_NOTIF_EVT,
+ copy these values into key_notif from cfm_req */
+ /** M: use the correct addr and transfer it to uplayer @{ */
+ BTA_COPY_DEVICE_CLASS(sec_event.cfm_req.dev_class,
+ p_data->cfm_req.dev_class);
+ strlcpy((char*)sec_event.cfm_req.bd_name,
+ (char*)p_data->cfm_req.bd_name, BD_NAME_LEN);
+ /** @} */
+ }
+ }
+
+ if (BTM_SP_KEY_NOTIF_EVT == event) {
+ /** M: use the correct addr and transfer it to uplayer @{ */
+ bdcpy(sec_event.key_notif.bd_addr, p_data->key_notif.bd_addr);
+ /** @} */
+ /* If the device name is not known, save bdaddr and devclass
+ and initiate a name request with values from key_notif */
+ if (p_data->key_notif.bd_name[0] == 0) {
+ bta_dm_cb.pin_evt = pin_evt;
+ bdcpy(bta_dm_cb.pin_bd_addr, p_data->key_notif.bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+ p_data->key_notif.dev_class);
+ if ((BTM_ReadRemoteDeviceName(
+ p_data->key_notif.bd_addr, bta_dm_pinname_cback,
+ BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+ APPL_TRACE_WARNING(
+ " bta_dm_sp_cback() -> Failed to start Remote Name Request ");
+ } else {
+ BTA_COPY_DEVICE_CLASS(sec_event.key_notif.dev_class,
+ p_data->key_notif.dev_class);
+ strlcpy((char*)sec_event.key_notif.bd_name,
+ (char*)p_data->key_notif.bd_name, BD_NAME_LEN);
+ sec_event.key_notif.bd_name[BD_NAME_LEN - 1] = 0;
+ }
+ }
+
+ bta_dm_cb.p_sec_cback(pin_evt, &sec_event);
+
+ break;
+
+ case BTM_SP_LOC_OOB_EVT:
+ bta_dm_co_loc_oob((bool)(p_data->loc_oob.status == BTM_SUCCESS),
+ p_data->loc_oob.c, p_data->loc_oob.r);
+ break;
+
+ case BTM_SP_RMT_OOB_EVT:
+ /* If the device name is not known, save bdaddr and devclass and initiate
+ * a name request */
+ if (p_data->rmt_oob.bd_name[0] == 0) {
+ bta_dm_cb.pin_evt = BTA_DM_SP_RMT_OOB_EVT;
+ bdcpy(bta_dm_cb.pin_bd_addr, p_data->rmt_oob.bd_addr);
+ BTA_COPY_DEVICE_CLASS(bta_dm_cb.pin_dev_class,
+ p_data->rmt_oob.dev_class);
+ if ((BTM_ReadRemoteDeviceName(p_data->rmt_oob.bd_addr,
+ bta_dm_pinname_cback,
+ BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
+ return BTM_CMD_STARTED;
+ APPL_TRACE_WARNING(
+ " bta_dm_sp_cback() -> Failed to start Remote Name Request ");
+ }
+
+ bdcpy(sec_event.rmt_oob.bd_addr, p_data->rmt_oob.bd_addr);
+ BTA_COPY_DEVICE_CLASS(sec_event.rmt_oob.dev_class,
+ p_data->rmt_oob.dev_class);
+ strlcpy((char*)sec_event.rmt_oob.bd_name, (char*)p_data->rmt_oob.bd_name,
+ BD_NAME_LEN);
+
+ bta_dm_cb.p_sec_cback(BTA_DM_SP_RMT_OOB_EVT, &sec_event);
+
+ bta_dm_co_rmt_oob(p_data->rmt_oob.bd_addr);
+ break;
+
+ case BTM_SP_COMPLT_EVT:
+ /* do not report this event - handled by link_key_callback or
+ * auth_complete_callback */
+ break;
+
+ case BTM_SP_KEYPRESS_EVT:
+ memcpy(&sec_event.key_press, &p_data->key_press,
+ sizeof(tBTM_SP_KEYPRESS));
+ bta_dm_cb.p_sec_cback(BTA_DM_SP_KEYPRESS_EVT, &sec_event);
+ break;
+
+ case BTM_SP_UPGRADE_EVT:
+ bta_dm_co_lk_upgrade(p_data->upgrade.bd_addr, &p_data->upgrade.upgrade);
+ break;
+
+ default:
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+ APPL_TRACE_EVENT("dm status: %d", status);
+ return status;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_dm_local_name_cback
+ *
+ * Description Callback from btm after local name is read
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_local_name_cback(UNUSED_ATTR uint8_t* p_name) {
+ tBTA_DM_SEC sec_event;
+
+ sec_event.enable.status = BTA_SUCCESS;
+
+ if (bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_ENABLE_EVT, &sec_event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_bl_change_cback
+ *
+ * Description Callback from btm when acl connection goes up or down
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_bl_change_cback(tBTM_BL_EVENT_DATA* p_data) {
+ tBTA_DM_ACL_CHANGE* p_msg =
+ (tBTA_DM_ACL_CHANGE*)osi_malloc(sizeof(tBTA_DM_ACL_CHANGE));
+
+ p_msg->event = p_data->event;
+ p_msg->is_new = false;
+
+ switch (p_msg->event) {
+ case BTM_BL_CONN_EVT:
+ p_msg->is_new = true;
+ bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+ p_msg->transport = p_data->conn.transport;
+ p_msg->handle = p_data->conn.handle;
+ break;
+ case BTM_BL_DISCN_EVT:
+ bdcpy(p_msg->bd_addr, p_data->discn.p_bda);
+ p_msg->transport = p_data->discn.transport;
+ p_msg->handle = p_data->discn.handle;
+ break;
+ case BTM_BL_UPDATE_EVT:
+ p_msg->busy_level = p_data->update.busy_level;
+ p_msg->busy_level_flags = p_data->update.busy_level_flags;
+ break;
+ case BTM_BL_ROLE_CHG_EVT:
+ p_msg->new_role = p_data->role_chg.new_role;
+ p_msg->hci_status = p_data->role_chg.hci_status;
+ bdcpy(p_msg->bd_addr, p_data->role_chg.p_bda);
+ break;
+ case BTM_BL_COLLISION_EVT:
+ bdcpy(p_msg->bd_addr, p_data->conn.p_bda);
+ break;
+ }
+
+ p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_rs_cback
+ *
+ * Description Receives the role switch complete event
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_dm_rs_cback(UNUSED_ATTR tBTM_ROLE_SWITCH_CMPL* p1) {
+ APPL_TRACE_WARNING("bta_dm_rs_cback:%d", bta_dm_cb.rs_event);
+ if (bta_dm_cb.rs_event == BTA_DM_API_SEARCH_EVT) {
+ bta_dm_cb.search_msg.rs_res =
+ BTA_DM_RS_OK; /* do not care about the result for now */
+ bta_dm_cb.rs_event = 0;
+ bta_dm_search_start((tBTA_DM_MSG*)&bta_dm_cb.search_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_check_av
+ *
+ * Description This function checks if AV is active
+ * if yes, make sure the AV link is master
+ *
+ * Returns bool - true, if switch is in progress
+ *
+ ******************************************************************************/
+static bool bta_dm_check_av(uint16_t event) {
+ bool avoid_roleswitch = false;
+ bool switching = false;
+ uint8_t i;
+ tBTA_DM_PEER_DEVICE* p_dev;
+
+#if (BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY == TRUE)
+
+ /* avoid role switch upon inquiry if a2dp is actively streaming as it
+ introduces an audioglitch due to FW scheduling delays (unavoidable) */
+ if (event == BTA_DM_API_SEARCH_EVT) {
+ avoid_roleswitch = true;
+ }
+#endif
+
+ APPL_TRACE_WARNING("bta_dm_check_av:%d", bta_dm_cb.cur_av_count);
+ if (bta_dm_cb.cur_av_count) {
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ p_dev = &bta_dm_cb.device_list.peer_device[i];
+ APPL_TRACE_WARNING("[%d]: state:%d, info:x%x, avoid_rs %d", i,
+ p_dev->conn_state, p_dev->info, avoid_roleswitch);
+ if ((p_dev->conn_state == BTA_DM_CONNECTED) &&
+ (p_dev->info & BTA_DM_DI_AV_ACTIVE) && (avoid_roleswitch == false)) {
+ /* make master and take away the role switch policy */
+ if (BTM_CMD_STARTED == BTM_SwitchRole(p_dev->peer_bdaddr,
+ HCI_ROLE_MASTER,
+ (tBTM_CMPL_CB*)bta_dm_rs_cback)) {
+ /* the role switch command is actually sent */
+ bta_dm_cb.rs_event = event;
+ switching = true;
+ }
+ /* else either already master or can not switch for some reasons */
+ bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0, HCI_ENABLE_MASTER_SLAVE_SWITCH,
+ p_dev->peer_bdaddr);
+ break;
+ }
+ }
+ }
+ return switching;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_acl_change
+ *
+ * Description Process BTA_DM_ACL_CHANGE_EVT
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_acl_change(tBTA_DM_MSG* p_data) {
+ uint8_t i;
+ uint8_t* p;
+ tBTA_DM_SEC conn;
+ bool is_new = p_data->acl_change.is_new;
+ BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr;
+ bool need_policy_change = false;
+ bool issue_unpair_cb = false;
+
+ tBTA_DM_PEER_DEVICE* p_dev;
+ memset(&conn, 0, sizeof(tBTA_DM_SEC));
+
+ switch (p_data->acl_change.event) {
+ case BTM_BL_UPDATE_EVT: /* busy level update */
+ if (bta_dm_cb.p_sec_cback) {
+ conn.busy_level.level = p_data->acl_change.busy_level;
+ conn.busy_level.level_flags = p_data->acl_change.busy_level_flags;
+ bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
+ }
+ return;
+
+ case BTM_BL_ROLE_CHG_EVT: /* role change event */
+ p_dev = bta_dm_find_peer_device(p_bda);
+ if (p_dev) {
+ APPL_TRACE_DEBUG(
+ "bta_dm_acl_change role chg info:x%x new_role:%d dev count:%d",
+ p_dev->info, p_data->acl_change.new_role,
+ bta_dm_cb.device_list.count);
+ if (p_dev->info & BTA_DM_DI_AV_ACTIVE) {
+ /* there's AV activity on this link */
+ if (p_data->acl_change.new_role == HCI_ROLE_SLAVE &&
+ bta_dm_cb.device_list.count > 1 &&
+ p_data->acl_change.hci_status == HCI_SUCCESS) {
+ /* more than one connections and the AV connection is role switched
+ * to slave
+ * switch it back to master and remove the switch policy */
+ BTM_SwitchRole(p_bda, BTM_ROLE_MASTER, NULL);
+ need_policy_change = true;
+ } else if (p_bta_dm_cfg->avoid_scatter &&
+ (p_data->acl_change.new_role == HCI_ROLE_MASTER)) {
+ /* if the link updated to be master include AV activities, remove
+ * the switch policy */
+ need_policy_change = true;
+ }
+
+ if (need_policy_change) {
+ bta_dm_policy_cback(BTA_SYS_PLCY_CLR, 0,
+ HCI_ENABLE_MASTER_SLAVE_SWITCH,
+ p_dev->peer_bdaddr);
+ }
+ } else {
+ /* there's AV no activity on this link and role switch happened
+ * check if AV is active
+ * if so, make sure the AV link is master */
+ bta_dm_check_av(0);
+ }
+ bta_sys_notify_role_chg(p_data->acl_change.bd_addr,
+ p_data->acl_change.new_role,
+ p_data->acl_change.hci_status);
+ bdcpy(conn.role_chg.bd_addr, p_bda);
+ conn.role_chg.new_role = (uint8_t)p_data->acl_change.new_role;
+ if (bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_ROLE_CHG_EVT, (tBTA_DM_SEC*)&conn);
+ }
+ return;
+ }
+
+ /* Collision report from Stack: Notify profiles */
+ if (p_data->acl_change.event == BTM_BL_COLLISION_EVT) {
+ bta_sys_notify_collision(p_bda);
+ return;
+ }
+
+ if (is_new) {
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda) &&
+ bta_dm_cb.device_list.peer_device[i].conn_handle ==
+ p_data->acl_change.handle)
+ break;
+ }
+
+ if (i == bta_dm_cb.device_list.count) {
+ if (bta_dm_cb.device_list.count < BTA_DM_NUM_PEER_DEVICE) {
+ bdcpy(bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+ .peer_bdaddr,
+ p_bda);
+ bta_dm_cb.device_list.peer_device[bta_dm_cb.device_list.count]
+ .link_policy = bta_dm_cb.cur_policy;
+ bta_dm_cb.device_list.count++;
+ bta_dm_cb.device_list.peer_device[i].conn_handle =
+ p_data->acl_change.handle;
+ if (p_data->acl_change.transport == BT_TRANSPORT_LE)
+ bta_dm_cb.device_list.le_count++;
+ } else {
+ APPL_TRACE_ERROR("%s max active connection reached, no resources",
+ __func__);
+ return;
+ }
+ }
+
+ bta_dm_cb.device_list.peer_device[i].conn_state = BTA_DM_CONNECTED;
+ bta_dm_cb.device_list.peer_device[i].pref_role = BTA_ANY_ROLE;
+ bdcpy(conn.link_up.bd_addr, p_bda);
+ bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_NONE;
+ conn.link_up.link_type = p_data->acl_change.transport;
+ bta_dm_cb.device_list.peer_device[i].transport =
+ p_data->acl_change.transport;
+
+ if (((NULL != (p = BTM_ReadLocalFeatures())) &&
+ HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ (!interop_mtk_match_addr_name(INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING, (const bt_bdaddr_t *)p_bda)) &&
+#endif
+ ((NULL != (p = BTM_ReadRemoteFeatures(p_bda))) &&
+ HCI_SNIFF_SUB_RATE_SUPPORTED(p))) {
+ /* both local and remote devices support SSR */
+ bta_dm_cb.device_list.peer_device[i].info = BTA_DM_DI_USE_SSR;
+ }
+ APPL_TRACE_WARNING("%s info: 0x%x", __func__,
+ bta_dm_cb.device_list.peer_device[i].info);
+
+ if (bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_LINK_UP_EVT, (tBTA_DM_SEC*)&conn);
+ } else {
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda) ||
+ bta_dm_cb.device_list.peer_device[i].transport !=
+ p_data->acl_change.transport)
+ continue;
+
+ if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING) {
+ if (BTM_SecDeleteDevice(
+ bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
+ {
+ /** M: clean gatt DB when unbond the device @{ */
+ BTA_GATTC_Refresh(p_bda);
+ /** @} */
+ issue_unpair_cb = true;
+ }
+
+ APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__,
+ issue_unpair_cb);
+ }
+
+ conn.link_down.is_removed =
+ bta_dm_cb.device_list.peer_device[i].remove_dev_pending;
+
+ // Iterate to the one before the last when shrinking the list,
+ // otherwise we memcpy garbage data into the record.
+ // Then clear out the last item in the list since we are shrinking.
+ for (; i < bta_dm_cb.device_list.count - 1; i++) {
+ memcpy(&bta_dm_cb.device_list.peer_device[i],
+ &bta_dm_cb.device_list.peer_device[i + 1],
+ sizeof(bta_dm_cb.device_list.peer_device[i]));
+ }
+ if (bta_dm_cb.device_list.count > 0) {
+ int clear_index = bta_dm_cb.device_list.count - 1;
+ memset(&bta_dm_cb.device_list.peer_device[clear_index], 0,
+ sizeof(bta_dm_cb.device_list.peer_device[clear_index]));
+ }
+ break;
+ }
+ if (bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--;
+ if ((p_data->acl_change.transport == BT_TRANSPORT_LE) &&
+ (bta_dm_cb.device_list.le_count))
+ bta_dm_cb.device_list.le_count--;
+ conn.link_down.link_type = p_data->acl_change.transport;
+
+ if (bta_dm_search_cb.wait_disc &&
+ !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda)) {
+ bta_dm_search_cb.wait_disc = false;
+
+ if (bta_dm_search_cb.sdp_results) {
+ APPL_TRACE_EVENT(" timer stopped ");
+ alarm_cancel(bta_dm_search_cb.search_timer);
+ bta_dm_discover_next_device();
+ }
+ }
+
+ if (bta_dm_cb.disabling) {
+ if (!BTM_GetNumAclLinks()) {
+ /*
+ * Start a timer to make sure that the profiles
+ * get the disconnect event.
+ */
+ alarm_set_on_queue(
+ bta_dm_cb.disable_timer, BTA_DM_DISABLE_CONN_DOWN_TIMER_MS,
+ bta_dm_disable_conn_down_timer_cback, NULL, btu_bta_alarm_queue);
+ }
+ }
+ if (conn.link_down.is_removed) {
+ BTM_SecDeleteDevice(p_bda);
+ /* need to remove all pending background connection */
+ BTA_GATTC_CancelOpen(0, p_bda, false);
+ /* remove all cached GATT information */
+ BTA_GATTC_Refresh(p_bda);
+ }
+
+ bdcpy(conn.link_down.bd_addr, p_bda);
+ conn.link_down.status = (uint8_t)btm_get_acl_disc_reason_code();
+ if (bta_dm_cb.p_sec_cback) {
+ bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);
+ if (issue_unpair_cb)
+ bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn);
+ }
+ }
+
+ bta_dm_adjust_roles(true);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable_conn_down_timer_cback
+ *
+ * Description Sends disable event to application
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_disable_conn_down_timer_cback(UNUSED_ATTR void* data) {
+ tBTA_SYS_HW_MSG* sys_enable_event =
+ (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+
+ /* disable the power managment module */
+ bta_dm_disable_pm();
+
+ /* register our callback to SYS HW manager */
+ bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback);
+
+ /* send a message to BTA SYS */
+ sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT;
+ sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH;
+ bta_sys_sendmsg(sys_enable_event);
+
+ bta_dm_cb.disabling = false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_rm_cback
+ *
+ * Description Role management callback from sys
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_rm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr) {
+ uint8_t j;
+ tBTA_PREF_ROLES role;
+ tBTA_DM_PEER_DEVICE* p_dev;
+
+ p_dev = bta_dm_find_peer_device(peer_addr);
+ if (status == BTA_SYS_CONN_OPEN) {
+ if (p_dev) {
+ /* Do not set to connected if we are in the middle of unpairing. When AV
+ * stream is
+ * started it fakes out a SYS_CONN_OPEN to potentially trigger a role
+ * switch command.
+ * But this should not be done if we are in the middle of unpairing.
+ */
+ if (p_dev->conn_state != BTA_DM_UNPAIRING)
+ p_dev->conn_state = BTA_DM_CONNECTED;
+
+ for (j = 1; j <= p_bta_dm_rm_cfg[0].app_id; j++) {
+ if (((p_bta_dm_rm_cfg[j].app_id == app_id) ||
+ (p_bta_dm_rm_cfg[j].app_id == BTA_ALL_APP_ID)) &&
+ (p_bta_dm_rm_cfg[j].id == id)) {
+ role = p_bta_dm_rm_cfg[j].cfg;
+
+ if (role > p_dev->pref_role) p_dev->pref_role = role;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((BTA_ID_AV == id) || (BTA_ID_AVK == id)) {
+ if (status == BTA_SYS_CONN_BUSY) {
+ if (p_dev) p_dev->info |= BTA_DM_DI_AV_ACTIVE;
+ /* AV calls bta_sys_conn_open with the A2DP stream count as app_id */
+ if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count();
+ } else if (status == BTA_SYS_CONN_IDLE) {
+ if (p_dev) p_dev->info &= ~BTA_DM_DI_AV_ACTIVE;
+
+ /* get cur_av_count from connected services */
+ if (BTA_ID_AV == id) bta_dm_cb.cur_av_count = bta_dm_get_av_count();
+ }
+ APPL_TRACE_WARNING("bta_dm_rm_cback:%d, status:%d", bta_dm_cb.cur_av_count,
+ status);
+ }
+
+ /* Don't adjust roles for each busy/idle state transition to avoid
+ excessive switch requests when individual profile busy/idle status
+ changes */
+ if ((status != BTA_SYS_CONN_BUSY) && (status != BTA_SYS_CONN_IDLE))
+ bta_dm_adjust_roles(false);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_delay_role_switch_cback
+ *
+ * Description Callback from btm to delay a role switch
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_delay_role_switch_cback(UNUSED_ATTR void* data) {
+ APPL_TRACE_EVENT("%s: initiating Delayed RS", __func__);
+ bta_dm_adjust_roles(false);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_reset_sec_dev_pending
+ *
+ * Description Setting the remove device pending status to false from
+ * security device DB, when the link key notification
+ * event comes.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_reset_sec_dev_pending(BD_ADDR remote_bd_addr) {
+ for (size_t i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ remote_bd_addr) == 0) {
+ bta_dm_cb.device_list.peer_device[i].remove_dev_pending = false;
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_remove_sec_dev_entry
+ *
+ * Description Removes device entry from Security device DB if ACL
+ connection with
+ * remtoe device does not exist, else schedule for dev entry
+ removal upon
+ ACL close
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_remove_sec_dev_entry(BD_ADDR remote_bd_addr) {
+ if (BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_LE) ||
+ BTM_IsAclConnectionUp(remote_bd_addr, BT_TRANSPORT_BR_EDR)) {
+ APPL_TRACE_DEBUG(
+ "%s ACL is not down. Schedule for Dev Removal when ACL closes",
+ __func__);
+ BTM_SecClearSecurityFlags(remote_bd_addr);
+ for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ remote_bd_addr)) {
+ bta_dm_cb.device_list.peer_device[i].remove_dev_pending = TRUE;
+ break;
+ }
+ }
+ } else {
+ BTM_SecDeleteDevice(remote_bd_addr);
+ /* need to remove all pending background connection */
+ BTA_GATTC_CancelOpen(0, remote_bd_addr, false);
+ /* remove all cached GATT information */
+ BTA_GATTC_Refresh(remote_bd_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_adjust_roles
+ *
+ * Description Adjust roles
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_adjust_roles(bool delay_role_switch) {
+ uint8_t i;
+ bool set_master_role = false;
+ uint8_t br_count =
+ bta_dm_cb.device_list.count - bta_dm_cb.device_list.le_count;
+ if (br_count) {
+ /* the configuration is no scatternet
+ * or AV connection exists and there are more than one ACL link */
+ if ((p_bta_dm_rm_cfg[0].cfg == BTA_DM_NO_SCATTERNET) ||
+ (bta_dm_cb.cur_av_count && br_count > 1)) {
+ L2CA_SetDesireRole(HCI_ROLE_MASTER);
+ set_master_role = true;
+ }
+
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED &&
+ bta_dm_cb.device_list.peer_device[i].transport ==
+ BT_TRANSPORT_BR_EDR) {
+ if (!set_master_role &&
+ (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_ANY_ROLE) &&
+ (p_bta_dm_rm_cfg[0].cfg == BTA_DM_PARTIAL_SCATTERNET)) {
+ L2CA_SetDesireRole(HCI_ROLE_MASTER);
+ set_master_role = true;
+ }
+
+ if ((bta_dm_cb.device_list.peer_device[i].pref_role ==
+ BTA_MASTER_ROLE_ONLY) ||
+ (br_count > 1)) {
+ /* Initiating immediate role switch with certain remote devices
+ has caused issues due to role switch colliding with link encryption
+ setup and
+ causing encryption (and in turn the link) to fail . These device .
+ Firmware
+ versions are stored in a blacklist and role switch with these
+ devices are
+ delayed to avoid the collision with link encryption setup */
+
+ if (bta_dm_cb.device_list.peer_device[i].pref_role !=
+ BTA_SLAVE_ROLE_ONLY &&
+ delay_role_switch == false) {
+ BTM_SwitchRole(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ HCI_ROLE_MASTER, NULL);
+ } else {
+ alarm_set_on_queue(
+ bta_dm_cb.switch_delay_timer, BTA_DM_SWITCH_DELAY_TIMER_MS,
+ bta_dm_delay_role_switch_cback, NULL, btu_bta_alarm_queue);
+ }
+ }
+ }
+ }
+
+ if (!set_master_role) {
+ L2CA_SetDesireRole(L2CAP_DESIRED_LINK_ROLE);
+ }
+
+ } else {
+ L2CA_SetDesireRole(L2CAP_DESIRED_LINK_ROLE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_get_remname
+ *
+ * Description Returns a pointer to the remote name stored in the DM
+ * control block if it exists, or from the BTM memory.
+ *
+ * Returns char * - Pointer to the remote device name
+ ******************************************************************************/
+static char* bta_dm_get_remname(void) {
+ char* p_name = (char*)bta_dm_search_cb.peer_name;
+ char* p_temp;
+
+ /* If the name isn't already stored, try retrieving from BTM */
+ if (*p_name == '\0') {
+ p_temp = BTM_SecReadDevName(bta_dm_search_cb.peer_bdaddr);
+ if (p_temp != NULL) p_name = p_temp;
+ }
+
+ return p_name;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_bond_cancel_complete_cback
+ *
+ * Description Authentication complete callback from BTM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_bond_cancel_complete_cback(tBTM_STATUS result) {
+ tBTA_DM_SEC sec_event;
+
+ if (result == BTM_SUCCESS)
+ sec_event.bond_cancel_cmpl.result = BTA_SUCCESS;
+ else
+ sec_event.bond_cancel_cmpl.result = BTA_FAILURE;
+
+ if (bta_dm_cb.p_sec_cback) {
+ bta_dm_cb.p_sec_cback(BTA_DM_BOND_CANCEL_CMPL_EVT, &sec_event);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function find_utf8_char_boundary
+ *
+ * Description This function checks a UTF8 string |utf8str| starting at
+ * |offset|, moving backwards and returns the offset of the
+ * next valid UTF8 character boundary found.
+ *
+ * Returns Offset of UTF8 character boundary
+ *
+ ******************************************************************************/
+static size_t find_utf8_char_boundary(const char* utf8str, size_t offset) {
+ CHECK(utf8str);
+ CHECK(offset > 0);
+
+ while (--offset) {
+ uint8_t ch = (uint8_t)utf8str[offset];
+ if ((ch & 0x80) == 0x00) // ASCII
+ return offset + 1;
+ if ((ch & 0xC0) == 0xC0) // Multi-byte sequence start
+ return offset;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_set_eir
+ *
+ * Description This function creates EIR tagged data and writes it to
+ * controller.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void bta_dm_set_eir(char* local_name) {
+ uint8_t* p;
+ uint8_t* p_length;
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ uint8_t* p_type;
+ uint8_t max_num_uuid;
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ uint8_t custom_uuid_idx;
+#endif // BTA_EIR_SERVER_NUM_CUSTOM_UUID
+#endif // BTA_EIR_CANNED_UUID_LIST
+#if (BTM_EIR_DEFAULT_FEC_REQUIRED == FALSE)
+ uint8_t free_eir_length = HCI_EXT_INQ_RESPONSE_LEN;
+#else // BTM_EIR_DEFAULT_FEC_REQUIRED
+ uint8_t free_eir_length = HCI_DM5_PACKET_SIZE;
+#endif // BTM_EIR_DEFAULT_FEC_REQUIRED
+ uint8_t num_uuid;
+ uint8_t data_type;
+ uint8_t local_name_len;
+
+ /* wait until complete to disable */
+ if (alarm_is_scheduled(bta_dm_cb.disable_timer)) return;
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ /* if local name is not provided, get it from controller */
+ if (local_name == NULL) {
+ if (BTM_ReadLocalDeviceName(&local_name) != BTM_SUCCESS) {
+ APPL_TRACE_ERROR("Fail to read local device name for EIR");
+ }
+ }
+#endif // BTA_EIR_CANNED_UUID_LIST
+
+ /* Allocate a buffer to hold HCI command */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BTM_CMD_BUF_SIZE);
+ p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET;
+
+ memset(p, 0x00, HCI_EXT_INQ_RESPONSE_LEN);
+
+ APPL_TRACE_DEBUG("BTA is generating EIR");
+
+ if (local_name)
+ local_name_len = strlen(local_name);
+ else
+ local_name_len = 0;
+
+ data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ /* if local name is longer than minimum length of shortened name */
+ /* check whether it needs to be shortened or not */
+ if (local_name_len > p_bta_dm_eir_cfg->bta_dm_eir_min_name_len) {
+/* get number of UUID 16-bit list */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+#else // BTA_EIR_CANNED_UUID_LIST
+ max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+ data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
+ max_num_uuid, &num_uuid);
+ p = (uint8_t*)p_buf + BTM_HCI_EIR_OFFSET; /* reset p */
+#endif // BTA_EIR_CANNED_UUID_LIST
+
+ /* if UUID doesn't fit remaing space, shorten local name */
+ if (local_name_len > (free_eir_length - 4 - num_uuid * LEN_UUID_16)) {
+ local_name_len = find_utf8_char_boundary(
+ local_name, p_bta_dm_eir_cfg->bta_dm_eir_min_name_len);
+ APPL_TRACE_WARNING("%s local name is shortened (%d)", __func__,
+ local_name_len);
+ data_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+ } else {
+ data_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ }
+ }
+
+ UINT8_TO_STREAM(p, local_name_len + 1);
+ UINT8_TO_STREAM(p, data_type);
+
+ if (local_name != NULL) {
+ memcpy(p, local_name, local_name_len);
+ p += local_name_len;
+ }
+ free_eir_length -= local_name_len + 2;
+
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ /* if UUID list is provided as static data in configuration */
+ if ((p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len > 0) &&
+ (p_bta_dm_eir_cfg->bta_dm_eir_uuid16)) {
+ if (free_eir_length > LEN_UUID_16 + 2) {
+ free_eir_length -= 2;
+
+ if (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len) {
+ num_uuid = p_bta_dm_eir_cfg->bta_dm_eir_uuid16_len / LEN_UUID_16;
+ data_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+ } else /* not enough room for all UUIDs */
+ {
+ APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+ num_uuid = free_eir_length / LEN_UUID_16;
+ data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ }
+ UINT8_TO_STREAM(p, num_uuid * LEN_UUID_16 + 1);
+ UINT8_TO_STREAM(p, data_type);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_uuid16, num_uuid * LEN_UUID_16);
+ p += num_uuid * LEN_UUID_16;
+ free_eir_length -= num_uuid * LEN_UUID_16;
+ }
+ }
+#else /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+ /* if UUID list is dynamic */
+ if (free_eir_length >= 2) {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+
+ max_num_uuid = (free_eir_length - 2) / LEN_UUID_16;
+ data_type = BTM_GetEirSupportedServices(bta_dm_cb.eir_uuid, &p,
+ max_num_uuid, &num_uuid);
+
+ if (data_type == BTM_EIR_MORE_16BITS_UUID_TYPE) {
+ APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+ }
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ else {
+ for (custom_uuid_idx = 0;
+ custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+ custom_uuid_idx++) {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_16) {
+ if (num_uuid < max_num_uuid) {
+ UINT16_TO_STREAM(p,
+ bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid16);
+ num_uuid++;
+ } else {
+ data_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ APPL_TRACE_WARNING("BTA EIR: UUID 16-bit list is truncated");
+ break;
+ }
+ }
+ }
+ }
+#endif /* (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_16 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_16 + 2;
+ }
+#endif /* (BTA_EIR_CANNED_UUID_LIST == TRUE) */
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE && BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ /* Adding 32-bit UUID list */
+ if (free_eir_length >= 2) {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+ data_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+
+ max_num_uuid = (free_eir_length - 2) / LEN_UUID_32;
+
+ for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+ custom_uuid_idx++) {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_32) {
+ if (num_uuid < max_num_uuid) {
+ UINT32_TO_STREAM(p, bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid32);
+ num_uuid++;
+ } else {
+ data_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+ APPL_TRACE_WARNING("BTA EIR: UUID 32-bit list is truncated");
+ break;
+ }
+ }
+ }
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_32 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_32 + 2;
+ }
+
+ /* Adding 128-bit UUID list */
+ if (free_eir_length >= 2) {
+ p_length = p++;
+ p_type = p++;
+ num_uuid = 0;
+ data_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+
+ max_num_uuid = (free_eir_length - 2) / LEN_UUID_128;
+
+ for (custom_uuid_idx = 0; custom_uuid_idx < BTA_EIR_SERVER_NUM_CUSTOM_UUID;
+ custom_uuid_idx++) {
+ if (bta_dm_cb.custom_uuid[custom_uuid_idx].len == LEN_UUID_128) {
+ if (num_uuid < max_num_uuid) {
+ ARRAY16_TO_STREAM(p,
+ bta_dm_cb.custom_uuid[custom_uuid_idx].uu.uuid128);
+ num_uuid++;
+ } else {
+ data_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+ APPL_TRACE_WARNING("BTA EIR: UUID 128-bit list is truncated");
+ break;
+ }
+ }
+ }
+
+ UINT8_TO_STREAM(p_length, num_uuid * LEN_UUID_128 + 1);
+ UINT8_TO_STREAM(p_type, data_type);
+ free_eir_length -= num_uuid * LEN_UUID_128 + 2;
+ }
+#endif /* ( BTA_EIR_CANNED_UUID_LIST != TRUE \
+ )&&(BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0) */
+
+ /* if Flags are provided in configuration */
+ if ((p_bta_dm_eir_cfg->bta_dm_eir_flag_len > 0) &&
+ (p_bta_dm_eir_cfg->bta_dm_eir_flags) &&
+ (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2)) {
+ UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 1);
+ UINT8_TO_STREAM(p, BTM_EIR_FLAGS_TYPE);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_flags,
+ p_bta_dm_eir_cfg->bta_dm_eir_flag_len);
+ p += p_bta_dm_eir_cfg->bta_dm_eir_flag_len;
+ free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_flag_len + 2;
+ }
+
+ /* if Manufacturer Specific are provided in configuration */
+ if ((p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len > 0) &&
+ (p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec) &&
+ (free_eir_length >= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2)) {
+ p_length = p;
+
+ UINT8_TO_STREAM(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 1);
+ UINT8_TO_STREAM(p, BTM_EIR_MANUFACTURER_SPECIFIC_TYPE);
+ memcpy(p, p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec,
+ p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len);
+ p += p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len;
+ free_eir_length -= p_bta_dm_eir_cfg->bta_dm_eir_manufac_spec_len + 2;
+
+ } else {
+ p_length = NULL;
+ }
+
+ /* if Inquiry Tx Resp Power compiled */
+ if ((p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power) && (free_eir_length >= 3)) {
+ UINT8_TO_STREAM(p, 2); /* Length field */
+ UINT8_TO_STREAM(p, BTM_EIR_TX_POWER_LEVEL_TYPE);
+ UINT8_TO_STREAM(p, *(p_bta_dm_eir_cfg->bta_dm_eir_inq_tx_power));
+ free_eir_length -= 3;
+ }
+
+ if (free_eir_length)
+ UINT8_TO_STREAM(p, 0); /* terminator of significant part */
+
+ BTM_WriteEIR(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_eir_search_services
+ *
+ * Description This function searches services in received EIR
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void bta_dm_eir_search_services(tBTM_INQ_RESULTS* p_result,
+ tBTA_SERVICE_MASK* p_services_to_search,
+ tBTA_SERVICE_MASK* p_services_found) {
+ tBTA_SERVICE_MASK service_index = 0;
+ tBTM_EIR_SEARCH_RESULT result;
+
+ APPL_TRACE_DEBUG(
+ "BTA searching services in EIR of BDA:0x%02X%02X%02X%02X%02X%02X",
+ p_result->remote_bd_addr[0], p_result->remote_bd_addr[1],
+ p_result->remote_bd_addr[2], p_result->remote_bd_addr[3],
+ p_result->remote_bd_addr[4], p_result->remote_bd_addr[5]);
+
+ APPL_TRACE_DEBUG(" with services_to_search=0x%08X", *p_services_to_search);
+
+ /* always do GATT based service discovery by SDP instead of from EIR */
+ /* if GATT based service is also to be put in EIR, need to modify this */
+ while (service_index < (BTA_MAX_SERVICE_ID - 1)) {
+ if (*p_services_to_search &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index))) {
+ result = BTM_HasInquiryEirService(
+ p_result, bta_service_id_to_uuid_lkup_tbl[service_index]);
+
+ /* Searching for HSP v1.2 only device */
+ if ((result != BTM_EIR_FOUND) &&
+ (bta_service_id_to_uuid_lkup_tbl[service_index] ==
+ UUID_SERVCLASS_HEADSET)) {
+ result = BTM_HasInquiryEirService(p_result, UUID_SERVCLASS_HEADSET_HS);
+ }
+
+ if (result == BTM_EIR_FOUND) {
+ /* If Plug and Play service record, need to check to see if Broadcom
+ * stack */
+ /* However, EIR data doesn't have EXT_BRCM_VERSION so just skip it */
+ if (bta_service_id_to_uuid_lkup_tbl[service_index] !=
+ UUID_SERVCLASS_PNP_INFORMATION) {
+ *p_services_found |= (tBTA_SERVICE_MASK)(
+ BTA_SERVICE_ID_TO_SERVICE_MASK(service_index));
+ /* remove the service from services to be searched */
+ *p_services_to_search &= (tBTA_SERVICE_MASK)(
+ ~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+ }
+ } else if (result == BTM_EIR_NOT_FOUND) {
+ /* remove the service from services to be searched */
+ *p_services_to_search &= (tBTA_SERVICE_MASK)(
+ ~(BTA_SERVICE_ID_TO_SERVICE_MASK(service_index)));
+ }
+ }
+
+ service_index++;
+ }
+
+ APPL_TRACE_ERROR(
+ "BTA EIR search result, services_to_search=0x%08X, services_found=0x%08X",
+ *p_services_to_search, *p_services_found);
+}
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+ *
+ * Function bta_dm_eir_update_uuid
+ *
+ * Description This function adds or removes service UUID in EIR database.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding) {
+ /* if this UUID is not advertised in EIR */
+ if (!BTM_HasEirService(p_bta_dm_eir_cfg->uuid_mask, uuid16)) return;
+
+ if (adding) {
+ APPL_TRACE_EVENT("Adding UUID=0x%04X into EIR", uuid16);
+
+ BTM_AddEirService(bta_dm_cb.eir_uuid, uuid16);
+ } else {
+ APPL_TRACE_EVENT("Removing UUID=0x%04X from EIR", uuid16);
+
+ BTM_RemoveEirService(bta_dm_cb.eir_uuid, uuid16);
+ }
+
+ bta_dm_set_eir(NULL);
+
+ APPL_TRACE_EVENT("bta_dm_eir_update_uuid UUID bit mask=0x%08X %08X",
+ bta_dm_cb.eir_uuid[1], bta_dm_cb.eir_uuid[0]);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_dm_enable_test_mode
+ *
+ * Description enable test mode
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_enable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ BTM_EnableTestMode();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable_test_mode
+ *
+ * Description disable test mode
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_disable_test_mode(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_execute_callback
+ *
+ * Description Just execute a generic call back in the context of the
+ * BTU/BTA tack
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_execute_callback(tBTA_DM_MSG* p_data) {
+ /* sanity check */
+ if (p_data->exec_cback.p_exec_cback == NULL) {
+ return;
+ }
+
+ p_data->exec_cback.p_exec_cback(p_data->exec_cback.p_param);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_encrypt_cback
+ *
+ * Description link encryption complete callback.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_dm_encrypt_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
+ tBTA_STATUS bta_status = BTA_SUCCESS;
+ tBTA_DM_ENCRYPT_CBACK* p_callback = NULL;
+ uint8_t i;
+
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, bd_addr) == 0 &&
+ bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
+ break;
+ }
+
+ if (i < bta_dm_cb.device_list.count) {
+ p_callback = bta_dm_cb.device_list.peer_device[i].p_encrypt_cback;
+ bta_dm_cb.device_list.peer_device[i].p_encrypt_cback = NULL;
+ }
+
+ switch (result) {
+ case BTM_SUCCESS:
+ break;
+ case BTM_WRONG_MODE:
+ bta_status = BTA_WRONG_MODE;
+ break;
+ case BTM_NO_RESOURCES:
+ bta_status = BTA_NO_RESOURCES;
+ break;
+ case BTM_BUSY:
+ bta_status = BTA_BUSY;
+ break;
+ default:
+ bta_status = BTA_FAILURE;
+ break;
+ }
+
+ APPL_TRACE_DEBUG("bta_dm_encrypt_cback status =%d p_callback=0x%x",
+ bta_status, p_callback);
+
+ if (p_callback) {
+ (*p_callback)(bd_addr, transport, bta_status);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_set_encryption
+ *
+ * Description This function to encrypt the link
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_dm_set_encryption(tBTA_DM_MSG* p_data) {
+ uint8_t i;
+
+ APPL_TRACE_DEBUG("bta_dm_set_encryption"); // todo
+ if (!p_data->set_encryption.p_callback) {
+ APPL_TRACE_ERROR("bta_dm_set_encryption callback is not provided");
+ return;
+ }
+ for (i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
+ p_data->set_encryption.bd_addr) == 0 &&
+ bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_CONNECTED)
+ break;
+ }
+ if (i < bta_dm_cb.device_list.count) {
+ if (bta_dm_cb.device_list.peer_device[i].p_encrypt_cback) {
+ APPL_TRACE_ERROR("earlier enc was not done for same device");
+ (*p_data->set_encryption.p_callback)(p_data->set_encryption.bd_addr,
+ p_data->set_encryption.transport,
+ BTA_BUSY);
+ return;
+ }
+
+ if (BTM_SetEncryption(p_data->set_encryption.bd_addr,
+ p_data->set_encryption.transport,
+ bta_dm_encrypt_cback, NULL,
+ p_data->set_encryption.sec_act) == BTM_CMD_STARTED) {
+ bta_dm_cb.device_list.peer_device[i].p_encrypt_cback =
+ p_data->set_encryption.p_callback;
+ }
+ }
+}
+
+bool bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr) {
+ APPL_TRACE_DEBUG("%s: count(%d)", __func__, bta_dm_conn_srvcs.count);
+
+ for (uint8_t j = 0; j < bta_dm_conn_srvcs.count; j++) {
+ // Check if profiles other than hid are connected
+ if ((bta_dm_conn_srvcs.conn_srvc[j].id != BTA_ID_HD) &&
+ !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
+ APPL_TRACE_DEBUG("%s: Another profile (id=%d) is connected", __func__,
+ bta_dm_conn_srvcs.conn_srvc[j].id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_observe_results_cb
+ *
+ * Description Callback for BLE Observe result
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_observe_results_cb(tBTM_INQ_RESULTS* p_inq, uint8_t* p_eir,
+ uint16_t eir_len) {
+ tBTA_DM_SEARCH result;
+ tBTM_INQ_INFO* p_inq_info;
+ APPL_TRACE_DEBUG("bta_dm_observe_results_cb");
+
+ bdcpy(result.inq_res.bd_addr, p_inq->remote_bd_addr);
+ result.inq_res.rssi = p_inq->rssi;
+ result.inq_res.ble_addr_type = p_inq->ble_addr_type;
+ result.inq_res.inq_result_type = p_inq->inq_result_type;
+ result.inq_res.device_type = p_inq->device_type;
+ result.inq_res.flag = p_inq->flag;
+ result.inq_res.ble_evt_type = p_inq->ble_evt_type;
+ result.inq_res.ble_primary_phy = p_inq->ble_primary_phy;
+ result.inq_res.ble_secondary_phy = p_inq->ble_secondary_phy;
+ result.inq_res.ble_advertising_sid = p_inq->ble_advertising_sid;
+ result.inq_res.ble_tx_power = p_inq->ble_tx_power;
+ result.inq_res.ble_periodic_adv_int = p_inq->ble_periodic_adv_int;
+
+ /* application will parse EIR to find out remote device name */
+ result.inq_res.p_eir = p_eir;
+ result.inq_res.eir_len = eir_len;
+
+ p_inq_info = BTM_InqDbRead(p_inq->remote_bd_addr);
+ if (p_inq_info != NULL) {
+ /* initialize remt_name_not_required to false so that we get the name by
+ * default */
+ result.inq_res.remt_name_not_required = false;
+ }
+
+ if (bta_dm_search_cb.p_scan_cback)
+ bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_RES_EVT, &result);
+
+ if (p_inq_info) {
+ /* application indicates if it knows the remote name, inside the callback
+ copy that to the inquiry data base*/
+ if (result.inq_res.remt_name_not_required)
+ p_inq_info->appl_knows_rem_name = true;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_observe_cmpl_cb
+ *
+ * Description Callback for BLE Observe complete
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_observe_cmpl_cb(void* p_result) {
+ tBTA_DM_SEARCH data;
+
+ APPL_TRACE_DEBUG("bta_dm_observe_cmpl_cb");
+
+ data.inq_cmpl.num_resps = ((tBTM_INQUIRY_CMPL*)p_result)->num_resp;
+ if (bta_dm_search_cb.p_scan_cback) {
+ bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_smp_cback
+ *
+ * Description Callback for BLE SMP
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static uint8_t bta_dm_ble_smp_cback(tBTM_LE_EVT event, BD_ADDR bda,
+ tBTM_LE_EVT_DATA* p_data) {
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTA_DM_SEC sec_event;
+ char* p_name = NULL;
+
+ if (!bta_dm_cb.p_sec_cback) return BTM_NOT_AUTHORIZED;
+
+ memset(&sec_event, 0, sizeof(tBTA_DM_SEC));
+ switch (event) {
+ case BTM_LE_IO_REQ_EVT:
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+
+ bta_dm_co_ble_io_req(
+ bda, &p_data->io_req.io_cap, &p_data->io_req.oob_data,
+ &p_data->io_req.auth_req, &p_data->io_req.max_key_size,
+ &p_data->io_req.init_keys, &p_data->io_req.resp_keys);
+#endif
+ APPL_TRACE_EVENT("io mitm: %d oob_data:%d", p_data->io_req.auth_req,
+ p_data->io_req.oob_data);
+
+ break;
+
+ case BTM_LE_SEC_REQUEST_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ p_name = BTM_SecReadDevName(bda);
+ if (p_name != NULL)
+ strlcpy((char*)sec_event.ble_req.bd_name, p_name, BD_NAME_LEN);
+ else
+ sec_event.ble_req.bd_name[0] = 0;
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_SEC_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_NOTIF_EVT:
+ bdcpy(sec_event.key_notif.bd_addr, bda);
+ p_name = BTM_SecReadDevName(bda);
+ if (p_name != NULL)
+ strlcpy((char*)sec_event.key_notif.bd_name, p_name, BD_NAME_LEN);
+ else
+ sec_event.key_notif.bd_name[0] = 0;
+ sec_event.key_notif.passkey = p_data->key_notif;
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_NOTIF_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_PASSKEY_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_OOB_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_OOB_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_NC_REQ_EVT:
+ bdcpy(sec_event.key_notif.bd_addr, bda);
+ strlcpy((char*)sec_event.key_notif.bd_name, bta_dm_get_remname(),
+ (BD_NAME_LEN));
+ sec_event.key_notif.passkey = p_data->key_notif;
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_NC_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_SC_OOB_REQ_EVT:
+ bdcpy(sec_event.ble_req.bd_addr, bda);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_SC_OOB_REQ_EVT, &sec_event);
+ break;
+
+ case BTM_LE_KEY_EVT:
+ bdcpy(sec_event.ble_key.bd_addr, bda);
+ sec_event.ble_key.key_type = p_data->key.key_type;
+ sec_event.ble_key.p_key_value = p_data->key.p_key_value;
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_KEY_EVT, &sec_event);
+ break;
+
+ case BTM_LE_COMPLT_EVT:
+ bdcpy(sec_event.auth_cmpl.bd_addr, bda);
+ BTM_ReadDevInfo(bda, &sec_event.auth_cmpl.dev_type,
+ &sec_event.auth_cmpl.addr_type);
+ p_name = BTM_SecReadDevName(bda);
+ if (p_name != NULL)
+ strlcpy((char*)sec_event.auth_cmpl.bd_name, p_name, (BD_NAME_LEN));
+ else
+ sec_event.auth_cmpl.bd_name[0] = 0;
+
+ if (p_data->complt.reason != 0) {
+ sec_event.auth_cmpl.fail_reason =
+ BTA_DM_AUTH_CONVERT_SMP_CODE(((uint8_t)p_data->complt.reason));
+ /* delete this device entry from Sec Dev DB */
+ bta_dm_remove_sec_dev_entry(bda);
+ } else {
+ sec_event.auth_cmpl.success = true;
+ /** M: Bug fix for ble sec db delete bug @{ */
+ bta_dm_reset_sec_dev_pending(bda);
+ /** @} */
+ }
+
+ if (bta_dm_cb.p_sec_cback) {
+ // bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+ bta_dm_cb.p_sec_cback(BTA_DM_BLE_AUTH_CMPL_EVT, &sec_event);
+ }
+ break;
+
+ default:
+ status = BTM_NOT_AUTHORIZED;
+ break;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_id_key_cback
+ *
+ * Description Callback for BLE local ID keys
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_ble_id_key_cback(uint8_t key_type,
+ tBTM_BLE_LOCAL_KEYS* p_key) {
+ uint8_t evt;
+ tBTA_DM_SEC dm_key;
+
+ switch (key_type) {
+ case BTM_BLE_KEY_TYPE_ID:
+ case BTM_BLE_KEY_TYPE_ER:
+ if (bta_dm_cb.p_sec_cback) {
+ memcpy(&dm_key.ble_id_keys, p_key, sizeof(tBTM_BLE_LOCAL_KEYS));
+
+ evt = (key_type == BTM_BLE_KEY_TYPE_ID) ? BTA_DM_BLE_LOCAL_IR_EVT
+ : BTA_DM_BLE_LOCAL_ER_EVT;
+ bta_dm_cb.p_sec_cback(evt, &dm_key);
+ }
+ break;
+
+ default:
+ APPL_TRACE_DEBUG("Unknown key type %d", key_type);
+ break;
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_add_blekey
+ *
+ * Description This function adds an BLE Key to an security database entry.
+ * This function shall only be called AFTER BTA_DmAddBleDevice
+ * has been called.
+ * It is normally called during host startup to restore all
+ * required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_add_blekey(tBTA_DM_MSG* p_data) {
+ if (!BTM_SecAddBleKey(p_data->add_ble_key.bd_addr,
+ (tBTM_LE_KEY_VALUE*)&p_data->add_ble_key.blekey,
+ p_data->add_ble_key.key_type)) {
+ APPL_TRACE_ERROR(
+ "BTA_DM: Error adding BLE Key for device %08x%04x",
+ (p_data->add_ble_key.bd_addr[0] << 24) +
+ (p_data->add_ble_key.bd_addr[1] << 16) +
+ (p_data->add_ble_key.bd_addr[2] << 8) +
+ p_data->add_ble_key.bd_addr[3],
+ (p_data->add_ble_key.bd_addr[4] << 8) + p_data->add_ble_key.bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_add_ble_device
+ *
+ * Description This function adds an BLE device to an security database
+ * entry.
+ * It is normally called during host startup to restore all
+ * required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_add_ble_device(tBTA_DM_MSG* p_data) {
+ if (!BTM_SecAddBleDevice(p_data->add_ble_device.bd_addr, NULL,
+ p_data->add_ble_device.dev_type,
+ p_data->add_ble_device.addr_type)) {
+ APPL_TRACE_ERROR("BTA_DM: Error adding BLE Device for device %08x%04x",
+ (p_data->add_ble_device.bd_addr[0] << 24) +
+ (p_data->add_ble_device.bd_addr[1] << 16) +
+ (p_data->add_ble_device.bd_addr[2] << 8) +
+ p_data->add_ble_device.bd_addr[3],
+ (p_data->add_ble_device.bd_addr[4] << 8) +
+ p_data->add_ble_device.bd_addr[5]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_add_ble_device
+ *
+ * Description This function adds an BLE device to an security database
+ * entry.
+ * It is normally called during host startup to restore all
+ * required information stored in the NVRAM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data) {
+ if (p_data->pin_reply.accept) {
+ BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_SUCCESS,
+ p_data->ble_passkey_reply.passkey);
+ } else {
+ BTM_BlePasskeyReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED,
+ p_data->ble_passkey_reply.passkey);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_confirm_reply
+ *
+ * Description This is response to SM numeric comparison request submitted
+ * to application.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data) {
+ if (p_data->confirm.accept) {
+ BTM_BleConfirmReply(p_data->confirm.bd_addr, BTM_SUCCESS);
+ } else {
+ BTM_BleConfirmReply(p_data->ble_passkey_reply.bd_addr, BTM_NOT_AUTHORIZED);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_security_grant
+ *
+ * Description This function grant SMP security request access.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_security_grant(tBTA_DM_MSG* p_data) {
+ BTM_SecurityGrant(p_data->ble_sec_grant.bd_addr, p_data->ble_sec_grant.res);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_set_bg_conn_type
+ *
+ * Description This function set the BLE background connection type
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data) {
+ BTM_BleStartAutoConn();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_set_conn_params
+ *
+ * Description This function set the preferred connection parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data) {
+ BTM_BleSetPrefConnParams(p_data->ble_set_conn_params.peer_bda,
+ p_data->ble_set_conn_params.conn_int_min,
+ p_data->ble_set_conn_params.conn_int_max,
+ p_data->ble_set_conn_params.slave_latency,
+ p_data->ble_set_conn_params.supervision_tout);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_set_conn_scan_params
+ *
+ * Description This function set the preferred connection scan parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data) {
+ BTM_BleSetConnScanParams(p_data->ble_set_conn_scan_params.scan_int,
+ p_data->ble_set_conn_scan_params.scan_window);
+}
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_update_conn_params
+ *
+ * Description This function update LE connection parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data) {
+ if (!L2CA_UpdateBleConnParams(p_data->ble_update_conn_params.bd_addr,
+ p_data->ble_update_conn_params.min_int,
+ p_data->ble_update_conn_params.max_int,
+ p_data->ble_update_conn_params.latency,
+ p_data->ble_update_conn_params.timeout)) {
+ APPL_TRACE_ERROR("Update connection parameters failed!");
+ }
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_config_local_privacy
+ *
+ * Description This function set the local device LE privacy settings.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data) {
+ BTM_BleConfigPrivacy(p_data->ble_local_privacy.privacy_enable);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_observe
+ *
+ * Description This function set the preferred connection scan parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_observe(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS status;
+ if (p_data->ble_observe.start) {
+ /*Save the callback to be called when a scan results are available */
+ bta_dm_search_cb.p_scan_cback = p_data->ble_observe.p_cback;
+ status = BTM_BleObserve(true, p_data->ble_observe.duration,
+ bta_dm_observe_results_cb, bta_dm_observe_cmpl_cb);
+ if (status != BTM_CMD_STARTED) {
+ tBTA_DM_SEARCH data;
+ APPL_TRACE_WARNING(" %s BTM_BleObserve failed. status %d", __func__,
+ status);
+ data.inq_cmpl.num_resps = 0;
+ if (bta_dm_search_cb.p_scan_cback) {
+ bta_dm_search_cb.p_scan_cback(BTA_DM_INQ_CMPL_EVT, &data);
+ }
+ }
+ } else {
+ bta_dm_search_cb.p_scan_cback = NULL;
+ BTM_BleObserve(false, 0, NULL, NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_set_adv_params
+ *
+ * Description This function set the adv parameters.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_adv_params(uint16_t adv_int_min, uint16_t adv_int_max,
+ tBLE_BD_ADDR* p_dir_bda) {
+ BTM_BleSetAdvParams(adv_int_min, adv_int_max, p_dir_bda,
+ BTA_DM_BLE_ADV_CHNL_MAP);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_set_data_length
+ *
+ * Description This function set the maximum transmission packet size
+ *
+ * Parameters
+ *
+ ******************************************************************************/
+void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data) {
+ if (BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
+ p_data->ble_set_data_length.tx_data_length) !=
+ BTM_SUCCESS) {
+ APPL_TRACE_ERROR("%s failed", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ble_enable_scan_cmpl
+ *
+ * Description ADV payload filtering enable / disable complete callback
+ *
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void bta_ble_energy_info_cmpl(tBTM_BLE_TX_TIME_MS tx_time,
+ tBTM_BLE_RX_TIME_MS rx_time,
+ tBTM_BLE_IDLE_TIME_MS idle_time,
+ tBTM_BLE_ENERGY_USED energy_used,
+ tBTM_STATUS status) {
+ tBTA_STATUS st = (status == BTM_SUCCESS) ? BTA_SUCCESS : BTA_FAILURE;
+ tBTA_DM_CONTRL_STATE ctrl_state = 0;
+
+ if (BTA_SUCCESS == st) ctrl_state = bta_dm_pm_obtain_controller_state();
+
+ if (bta_dm_cb.p_energy_info_cback)
+ bta_dm_cb.p_energy_info_cback(tx_time, rx_time, idle_time, energy_used,
+ ctrl_state, st);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ble_get_energy_info
+ *
+ * Description This function obtains the energy info
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data) {
+ tBTM_STATUS btm_status = 0;
+
+ bta_dm_cb.p_energy_info_cback = p_data->ble_energy_info.p_energy_info_cback;
+ btm_status = BTM_BleGetEnergyInfo(bta_ble_energy_info_cmpl);
+ if (BTM_CMD_STARTED != btm_status)
+ bta_ble_energy_info_cmpl(0, 0, 0, 0, btm_status);
+}
+
+#ifndef BTA_DM_GATT_CLOSE_DELAY_TOUT
+#define BTA_DM_GATT_CLOSE_DELAY_TOUT 1000
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_dm_gattc_register
+ *
+ * Description Register with GATTC in DM if BLE is needed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_gattc_register(void) {
+ if (bta_dm_search_cb.client_if == BTA_GATTS_INVALID_IF) {
+ BTA_GATTC_AppRegister(bta_dm_gattc_callback,
+ base::Bind([](uint8_t client_id, uint8_t status) {
+ if (status == BTA_GATT_OK)
+ bta_dm_search_cb.client_if = client_id;
+ else
+ bta_dm_search_cb.client_if = BTA_GATTS_INVALID_IF;
+
+ }));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_dm_start_disc_gatt_services
+ *
+ * Description This function starts a GATT service search request.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void btm_dm_start_disc_gatt_services(uint16_t conn_id) {
+ tBT_UUID* p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+ bta_dm_search_cb.uuid_to_search;
+
+ p_uuid = bta_dm_search_cb.p_srvc_uuid + bta_dm_search_cb.num_uuid -
+ bta_dm_search_cb.uuid_to_search;
+
+ /* always search for all services */
+ BTA_GATTC_ServiceSearchRequest(conn_id, p_uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_gatt_disc_result
+ *
+ * Description This function process the GATT service search result.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gatt_disc_result(tBTA_GATT_ID service_id) {
+ tBTA_DM_SEARCH result;
+
+ /*
+ * This logic will not work for gatt case. We are checking against the
+ * bluetooth profiles here
+ * just copy the GATTID in raw data field and send it across.
+ */
+
+ if (bta_dm_search_cb.ble_raw_used + sizeof(tBTA_GATT_ID) <
+ bta_dm_search_cb.ble_raw_size) {
+ APPL_TRACE_DEBUG(
+ "ADDING BLE SERVICE uuid=0x%x, ble_ptr = 0x%x, ble_raw_used = 0x%x",
+ service_id.uuid.uu.uuid16, bta_dm_search_cb.p_ble_rawdata,
+ bta_dm_search_cb.ble_raw_used);
+
+ if (bta_dm_search_cb.p_ble_rawdata) {
+ memcpy((bta_dm_search_cb.p_ble_rawdata + bta_dm_search_cb.ble_raw_used),
+ &service_id, sizeof(service_id));
+
+ bta_dm_search_cb.ble_raw_used += sizeof(service_id);
+ } else {
+ APPL_TRACE_ERROR("p_ble_rawdata is NULL");
+ }
+
+ } else {
+ APPL_TRACE_ERROR(
+ "%s out of room to accomodate more service ids ble_raw_size = %d "
+ "ble_raw_used = %d",
+ __func__, bta_dm_search_cb.ble_raw_size, bta_dm_search_cb.ble_raw_used);
+ }
+
+ LOG_INFO(LOG_TAG, "%s service_id_uuid_len=%d ", __func__,
+ service_id.uuid.len);
+ if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) {
+ /* send result back to app now, one by one */
+ bdcpy(result.disc_ble_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
+ BD_NAME_LEN);
+ memcpy(&result.disc_ble_res.service, &service_id.uuid, sizeof(tBT_UUID));
+
+ bta_dm_search_cb.p_search_cback(BTA_DM_DISC_BLE_RES_EVT, &result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_gatt_disc_complete
+ *
+ * Description This function process the GATT service search complete.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gatt_disc_complete(uint16_t conn_id,
+ tBTA_GATT_STATUS status) {
+ APPL_TRACE_DEBUG("%s conn_id = %d", __func__, conn_id);
+
+ if (bta_dm_search_cb.uuid_to_search > 0) bta_dm_search_cb.uuid_to_search--;
+
+ if (status == BTA_GATT_OK && bta_dm_search_cb.uuid_to_search > 0) {
+ btm_dm_start_disc_gatt_services(conn_id);
+ } else {
+ tBTA_DM_MSG* p_msg = (tBTA_DM_MSG*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ bta_dm_search_cb.uuid_to_search = 0;
+
+ /* no more services to be discovered */
+ p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
+ p_msg->disc_result.result.disc_res.result =
+ (status == BTA_GATT_OK) ? BTA_SUCCESS : BTA_FAILURE;
+ APPL_TRACE_DEBUG("%s service found: 0x%08x", __func__,
+ bta_dm_search_cb.services_found);
+ p_msg->disc_result.result.disc_res.services =
+ bta_dm_search_cb.services_found;
+ p_msg->disc_result.result.disc_res.num_uuids = 0;
+ p_msg->disc_result.result.disc_res.p_uuid_list = NULL;
+ bdcpy(p_msg->disc_result.result.disc_res.bd_addr,
+ bta_dm_search_cb.peer_bdaddr);
+ strlcpy((char*)p_msg->disc_result.result.disc_res.bd_name,
+ bta_dm_get_remname(), BD_NAME_LEN);
+
+ p_msg->disc_result.result.disc_res.device_type |= BT_DEVICE_TYPE_BLE;
+ if (bta_dm_search_cb.ble_raw_used > 0) {
+ p_msg->disc_result.result.disc_res.p_raw_data =
+ (uint8_t*)osi_malloc(bta_dm_search_cb.ble_raw_used);
+
+ memcpy(p_msg->disc_result.result.disc_res.p_raw_data,
+ bta_dm_search_cb.p_ble_rawdata, bta_dm_search_cb.ble_raw_used);
+
+ p_msg->disc_result.result.disc_res.raw_data_size =
+ bta_dm_search_cb.ble_raw_used;
+ } else {
+ p_msg->disc_result.result.disc_res.p_raw_data = NULL;
+ bta_dm_search_cb.p_ble_rawdata = 0;
+ }
+
+ bta_sys_sendmsg(p_msg);
+
+ if (conn_id != BTA_GATT_INVALID_CONN_ID) {
+ /* start a GATT channel close delay timer */
+ bta_sys_start_timer(bta_dm_search_cb.gatt_close_timer,
+ BTA_DM_GATT_CLOSE_DELAY_TOUT,
+ BTA_DM_DISC_CLOSE_TOUT_EVT, 0);
+ bdcpy(bta_dm_search_cb.pending_close_bda, bta_dm_search_cb.peer_bdaddr);
+ }
+ bta_dm_search_cb.gatt_disc_active = false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_close_gatt_conn
+ *
+ * Description This function close the GATT connection after delay
+ *timeout.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_close_gatt_conn(UNUSED_ATTR tBTA_DM_MSG* p_data) {
+ if (bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID)
+ BTA_GATTC_Close(bta_dm_search_cb.conn_id);
+
+ memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN);
+ bta_dm_search_cb.conn_id = BTA_GATT_INVALID_CONN_ID;
+}
+/*******************************************************************************
+ *
+ * Function btm_dm_start_gatt_discovery
+ *
+ * Description This is GATT initiate the service search by open a GATT
+ * connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void btm_dm_start_gatt_discovery(BD_ADDR bd_addr) {
+ bta_dm_search_cb.gatt_disc_active = true;
+
+ /* connection is already open */
+ if (bdcmp(bta_dm_search_cb.pending_close_bda, bd_addr) == 0 &&
+ bta_dm_search_cb.conn_id != BTA_GATT_INVALID_CONN_ID) {
+ memset(bta_dm_search_cb.pending_close_bda, 0, BD_ADDR_LEN);
+ alarm_cancel(bta_dm_search_cb.gatt_close_timer);
+ btm_dm_start_disc_gatt_services(bta_dm_search_cb.conn_id);
+ } else {
+ if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
+ BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, true,
+ BTA_GATT_TRANSPORT_LE, true);
+ } else {
+ BTA_GATTC_Open(bta_dm_search_cb.client_if, bd_addr, true,
+ BTA_GATT_TRANSPORT_LE, false);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_cancel_gatt_discovery
+ *
+ * Description This is GATT cancel the GATT service search.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_cancel_gatt_discovery(BD_ADDR bd_addr) {
+ if (bta_dm_search_cb.conn_id == BTA_GATT_INVALID_CONN_ID) {
+ BTA_GATTC_CancelOpen(bta_dm_search_cb.client_if, bd_addr, true);
+ }
+
+ bta_dm_gatt_disc_complete(bta_dm_search_cb.conn_id,
+ (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_proc_open_evt
+ *
+ * Description process BTA_GATTC_OPEN_EVT in DM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_dm_proc_open_evt(tBTA_GATTC_OPEN* p_data) {
+ uint8_t* p1;
+ uint8_t* p2;
+
+ p1 = bta_dm_search_cb.peer_bdaddr;
+ p2 = p_data->remote_bda;
+
+ APPL_TRACE_DEBUG(
+ "DM Search state= %d search_cb.peer_dbaddr: [%08x%04x] connected_bda= "
+ "[%08x%04x] ",
+ bta_dm_search_cb.state,
+ ((p1[0]) << 24) + ((p1[1]) << 16) + ((p1[2]) << 8) + (p1[3]),
+ ((p1[4]) << 8) + p1[5],
+ ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]),
+ ((p2[4]) << 8) + p2[5]);
+
+ APPL_TRACE_DEBUG("BTA_GATTC_OPEN_EVT conn_id = %d client_if=%d status = %d",
+ p_data->conn_id, p_data->client_if, p_data->status);
+
+ bta_dm_search_cb.conn_id = p_data->conn_id;
+
+ if (p_data->status == BTA_GATT_OK) {
+ btm_dm_start_disc_gatt_services(p_data->conn_id);
+ } else {
+ bta_dm_gatt_disc_complete(BTA_GATT_INVALID_CONN_ID, p_data->status);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_gattc_callback
+ *
+ * Description This is GATT client callback function used in DM.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+ APPL_TRACE_DEBUG("bta_dm_gattc_callback event = %d", event);
+
+ switch (event) {
+ case BTA_GATTC_OPEN_EVT:
+ bta_dm_proc_open_evt(&p_data->open);
+ break;
+
+ case BTA_GATTC_SEARCH_RES_EVT:
+ bta_dm_gatt_disc_result(p_data->srvc_res.service_uuid);
+ break;
+
+ case BTA_GATTC_SEARCH_CMPL_EVT:
+ if (bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE)
+ bta_dm_gatt_disc_complete(p_data->search_cmpl.conn_id,
+ p_data->search_cmpl.status);
+ break;
+
+ case BTA_GATTC_CLOSE_EVT:
+ APPL_TRACE_DEBUG("BTA_GATTC_CLOSE_EVT reason = %d", p_data->close.reason);
+ /* in case of disconnect before search is completed */
+ if ((bta_dm_search_cb.state != BTA_DM_SEARCH_IDLE) &&
+ (bta_dm_search_cb.state != BTA_DM_SEARCH_ACTIVE) &&
+ !memcmp(p_data->close.remote_bda, bta_dm_search_cb.peer_bdaddr,
+ BD_ADDR_LEN)) {
+ bta_dm_gatt_disc_complete((uint16_t)BTA_GATT_INVALID_CONN_ID,
+ (tBTA_GATT_STATUS)BTA_GATT_ERROR);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+#if (BLE_VND_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_dm_ctrl_features_rd_cmpl_cback
+ *
+ * Description callback to handle controller feature read complete
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_dm_ctrl_features_rd_cmpl_cback(tBTM_STATUS result) {
+ APPL_TRACE_DEBUG("%s status = %d ", __func__, result);
+ if (result == BTM_SUCCESS) {
+ if (bta_dm_cb.p_sec_cback)
+ bta_dm_cb.p_sec_cback(BTA_DM_LE_FEATURES_READ, NULL);
+ } else {
+ APPL_TRACE_ERROR("%s Ctrl BLE feature read failed: status :%d", __func__,
+ result);
+ }
+}
+#endif /* BLE_VND_INCLUDED */
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_api.cc b/mtkbt/code/bt/bta/dm/bta_dm_api.cc
new file mode 100755
index 0000000..90ca94b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_api.cc
@@ -0,0 +1,1201 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the API implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+#include <base/bind_helpers.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_closure_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_dm_reg = {bta_dm_sm_execute, bta_dm_sm_disable};
+
+static const tBTA_SYS_REG bta_dm_search_reg = {bta_dm_search_sm_execute,
+ bta_dm_search_sm_disable};
+
+/*******************************************************************************
+ *
+ * Function BTA_EnableBluetooth
+ *
+ * Description Enables bluetooth service. This function must be
+ * called before any other functions in the BTA API are called.
+ *
+ *
+ * Returns tBTA_STATUS
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback) {
+ /* Bluetooth disabling is in progress */
+ if (bta_dm_cb.disabling) return BTA_FAILURE;
+
+ bta_sys_register(BTA_ID_DM, &bta_dm_reg);
+ bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg);
+
+ /* if UUID list is not provided as static data */
+ bta_sys_eir_register(bta_dm_eir_update_uuid);
+
+ tBTA_DM_API_ENABLE* p_msg =
+ (tBTA_DM_API_ENABLE*)osi_malloc(sizeof(tBTA_DM_API_ENABLE));
+ p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
+ p_msg->p_sec_cback = p_cback;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DisableBluetooth
+ *
+ * Description Disables bluetooth service. This function is called when
+ * the application no longer needs bluetooth service
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DisableBluetooth(void) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_msg->event = BTA_DM_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_EnableTestMode
+ *
+ * Description Enables bluetooth device under test mode
+ *
+ *
+ * Returns tBTA_STATUS
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_EnableTestMode(void) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->event = BTA_DM_API_ENABLE_TEST_MODE_EVT;
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DisableTestMode
+ *
+ * Description Disable bluetooth device under test mode
+ *
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_DisableTestMode(void) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->event = BTA_DM_API_DISABLE_TEST_MODE_EVT;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetDeviceName
+ *
+ * Description This function sets the Bluetooth name of local device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSetDeviceName(char* p_name) {
+ tBTA_DM_API_SET_NAME* p_msg =
+ (tBTA_DM_API_SET_NAME*)osi_malloc(sizeof(tBTA_DM_API_SET_NAME));
+
+ p_msg->hdr.event = BTA_DM_API_SET_NAME_EVT;
+ strlcpy((char*)p_msg->name, p_name, BD_NAME_LEN);
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetVisibility
+ *
+ * Description This function sets the Bluetooth connectable,
+ * discoverable, pairable and conn paired only modes of local
+ * device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
+ uint8_t pairable_mode, uint8_t conn_filter) {
+ tBTA_DM_API_SET_VISIBILITY* p_msg =
+ (tBTA_DM_API_SET_VISIBILITY*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT;
+ p_msg->disc_mode = disc_mode;
+ p_msg->conn_mode = conn_mode;
+ p_msg->pair_mode = pairable_mode;
+ p_msg->conn_paired_only = conn_filter;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearch
+ *
+ * Description This function searches for peer Bluetooth devices. It
+ * performs an inquiry and gets the remote name for devices.
+ * Service discovery is done if services is non zero
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK* p_cback) {
+ tBTA_DM_API_SEARCH* p_msg =
+ (tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH));
+
+ p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+ memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+ p_msg->services = services;
+ p_msg->p_cback = p_cback;
+ p_msg->rs_res = BTA_DM_RS_NONE;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearchCancel
+ *
+ * Description This function cancels a search initiated by BTA_DmSearch
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSearchCancel(void) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_msg->event = BTA_DM_API_SEARCH_CANCEL_EVT;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscover
+ *
+ * Description This function does service discovery for services of a
+ * peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+ tBTA_DM_API_DISCOVER* p_msg =
+ (tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER));
+
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->services = services;
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverUUID
+ *
+ * Description This function does service discovery for services of a
+ * peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID* uuid,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+ tBTA_DM_API_DISCOVER* p_msg =
+ (tBTA_DM_API_DISCOVER*)osi_malloc(sizeof(tBTA_DM_API_DISCOVER));
+
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->services = BTA_USER_SERVICE_MASK; // Not exposed at API level
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+
+ p_msg->num_uuid = 0;
+ p_msg->p_uuid = NULL;
+
+ memcpy(&p_msg->uuid, uuid, sizeof(tSDP_UUID));
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBond
+ *
+ * Description This function initiates a bonding procedure with a peer
+ * device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBond(BD_ADDR bd_addr) {
+ tBTA_DM_API_BOND* p_msg =
+ (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
+
+ p_msg->hdr.event = BTA_DM_API_BOND_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->transport = BTA_TRANSPORT_UNKNOWN;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBondByTransports
+ *
+ * Description This function initiates a bonding procedure with a peer
+ * device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport) {
+ tBTA_DM_API_BOND* p_msg =
+ (tBTA_DM_API_BOND*)osi_malloc(sizeof(tBTA_DM_API_BOND));
+
+ p_msg->hdr.event = BTA_DM_API_BOND_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->transport = transport;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBondCancel
+ *
+ * Description This function cancels the bonding procedure with a peer
+ * device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBondCancel(BD_ADDR bd_addr) {
+ tBTA_DM_API_BOND_CANCEL* p_msg =
+ (tBTA_DM_API_BOND_CANCEL*)osi_malloc(sizeof(tBTA_DM_API_BOND_CANCEL));
+
+ p_msg->hdr.event = BTA_DM_API_BOND_CANCEL_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmPinReply
+ *
+ * Description This function provides a pincode for a remote device when
+ * one is requested by DM through BTA_DM_PIN_REQ_EVT
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmPinReply(BD_ADDR bd_addr, bool accept, uint8_t pin_len,
+ uint8_t* p_pin)
+
+{
+ tBTA_DM_API_PIN_REPLY* p_msg =
+ (tBTA_DM_API_PIN_REPLY*)osi_malloc(sizeof(tBTA_DM_API_PIN_REPLY));
+
+ p_msg->hdr.event = BTA_DM_API_PIN_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+ if (accept) {
+ p_msg->pin_len = pin_len;
+ memcpy(p_msg->p_pin, p_pin, pin_len);
+ }
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmLocalOob
+ *
+ * Description This function retrieves the OOB data from local controller.
+ * The result is reported by:
+ * - bta_dm_co_loc_oob_ext() if device supports secure
+ * connections (SC)
+ * - bta_dm_co_loc_oob() if device doesn't support SC
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmLocalOob(void) {
+ tBTA_DM_API_LOC_OOB* p_msg =
+ (tBTA_DM_API_LOC_OOB*)osi_malloc(sizeof(tBTA_DM_API_LOC_OOB));
+
+ p_msg->hdr.event = BTA_DM_API_LOC_OOB_EVT;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmConfirm
+ *
+ * Description This function accepts or rejects the numerical value of the
+ * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmConfirm(BD_ADDR bd_addr, bool accept) {
+ tBTA_DM_API_CONFIRM* p_msg =
+ (tBTA_DM_API_CONFIRM*)osi_malloc(sizeof(tBTA_DM_API_CONFIRM));
+
+ p_msg->hdr.event = BTA_DM_API_CONFIRM_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddDevice
+ *
+ * Description This function adds a device to the security database list of
+ * peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, LINK_KEY link_key,
+ tBTA_SERVICE_MASK trusted_mask, bool is_trusted,
+ uint8_t key_type, tBTA_IO_CAP io_cap, uint8_t pin_length) {
+ tBTA_DM_API_ADD_DEVICE* p_msg =
+ (tBTA_DM_API_ADD_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_ADD_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_DEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->tm = trusted_mask;
+ p_msg->is_trusted = is_trusted;
+ p_msg->io_cap = io_cap;
+
+ if (link_key) {
+ p_msg->link_key_known = true;
+ p_msg->key_type = key_type;
+ memcpy(p_msg->link_key, link_key, LINK_KEY_LEN);
+ }
+
+ /* Load device class if specified */
+ if (dev_class) {
+ p_msg->dc_known = true;
+ memcpy(p_msg->dc, dev_class, DEV_CLASS_LEN);
+ }
+
+ memset(p_msg->bd_name, 0, BD_NAME_LEN + 1);
+ memset(p_msg->features, 0, sizeof(p_msg->features));
+ p_msg->pin_length = pin_length;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmRemoveDevice
+ *
+ * Description This function removes a device fromthe security database
+ * list of peer device. It manages unpairing even while
+ * connected.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr) {
+ tBTA_DM_API_REMOVE_DEVICE* p_msg =
+ (tBTA_DM_API_REMOVE_DEVICE*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_REMOVE_DEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GetEirService
+ *
+ * Description This function is called to get BTA service mask from EIR.
+ *
+ * Parameters p_eir - pointer of EIR significant part
+ * p_services - return the BTA service mask
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern const uint16_t bta_service_id_to_uuid_lkup_tbl[];
+void BTA_GetEirService(uint8_t* p_eir, size_t eir_len,
+ tBTA_SERVICE_MASK* p_services) {
+ uint8_t xx, yy;
+ uint8_t num_uuid, max_num_uuid = 32;
+ uint8_t uuid_list[32 * LEN_UUID_16];
+ uint16_t* p_uuid16 = (uint16_t*)uuid_list;
+ tBTA_SERVICE_MASK mask;
+
+ BTM_GetEirUuidList(p_eir, eir_len, LEN_UUID_16, &num_uuid, uuid_list,
+ max_num_uuid);
+ for (xx = 0; xx < num_uuid; xx++) {
+ mask = 1;
+ for (yy = 0; yy < BTA_MAX_SERVICE_ID; yy++) {
+ if (*(p_uuid16 + xx) == bta_service_id_to_uuid_lkup_tbl[yy]) {
+ *p_services |= mask;
+ break;
+ }
+ mask <<= 1;
+ }
+
+ /* for HSP v1.2 only device */
+ if (*(p_uuid16 + xx) == UUID_SERVCLASS_HEADSET_HS)
+ *p_services |= BTA_HSP_SERVICE_MASK;
+
+ if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SOURCE)
+ *p_services |= BTA_HL_SERVICE_MASK;
+
+ if (*(p_uuid16 + xx) == UUID_SERVCLASS_HDP_SINK)
+ *p_services |= BTA_HL_SERVICE_MASK;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmGetConnectionState
+ *
+ * Description Returns whether the remote device is currently connected.
+ *
+ * Returns 0 if the device is NOT connected.
+ *
+ ******************************************************************************/
+uint16_t BTA_DmGetConnectionState(const BD_ADDR bd_addr) {
+ tBTA_DM_PEER_DEVICE* p_dev = bta_dm_find_peer_device(bd_addr);
+ return (p_dev && p_dev->conn_state == BTA_DM_CONNECTED);
+}
+
+/*******************************************************************************
+ * Device Identification (DI) Server Functions
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTA_DmSetLocalDiRecord
+ *
+ * Description This function adds a DI record to the local SDP database.
+ *
+ * Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+ uint32_t* p_handle) {
+ tBTA_STATUS status = BTA_FAILURE;
+
+ if (bta_dm_di_cb.di_num < BTA_DI_NUM_MAX) {
+ if (SDP_SetLocalDiRecord((tSDP_DI_RECORD*)p_device_info, p_handle) ==
+ SDP_SUCCESS) {
+ if (!p_device_info->primary_record) {
+ bta_dm_di_cb.di_handle[bta_dm_di_cb.di_num] = *p_handle;
+ bta_dm_di_cb.di_num++;
+ }
+
+ bta_sys_add_uuid(UUID_SERVCLASS_PNP_INFORMATION);
+ status = BTA_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dmexecutecallback
+ *
+ * Description This function will request BTA to execute a call back in the
+ * context of BTU task.
+ * This API was named in lower case because it is only intended
+ * for the internal customers(like BTIF).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback, void* p_param) {
+ tBTA_DM_API_EXECUTE_CBACK* p_msg =
+ (tBTA_DM_API_EXECUTE_CBACK*)osi_malloc(sizeof(tBTA_DM_MSG));
+
+ p_msg->hdr.event = BTA_DM_API_EXECUTE_CBACK_EVT;
+ p_msg->p_param = p_param;
+ p_msg->p_exec_cback = p_callback;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+ *
+ * Returns BTA_SUCCESS if successful
+ * BTA_FAIL if operation failed.
+ *
+ ******************************************************************************/
+void BTA_DmAddBleKey(BD_ADDR bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
+ tBTA_LE_KEY_TYPE key_type) {
+ tBTA_DM_API_ADD_BLEKEY* p_msg =
+ (tBTA_DM_API_ADD_BLEKEY*)osi_calloc(sizeof(tBTA_DM_API_ADD_BLEKEY));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_BLEKEY_EVT;
+ p_msg->key_type = key_type;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ memcpy(&p_msg->blekey, p_le_key, sizeof(tBTA_LE_KEY_VALUE));
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddBleDevice
+ *
+ * Description Add a BLE device. This function will be normally called
+ * during host startup to restore all required information
+ * for a LE device stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * dev_type - Remote device's device type.
+ * addr_type - LE device address type.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
+ tBT_DEVICE_TYPE dev_type) {
+ tBTA_DM_API_ADD_BLE_DEVICE* p_msg = (tBTA_DM_API_ADD_BLE_DEVICE*)osi_calloc(
+ sizeof(tBTA_DM_API_ADD_BLE_DEVICE));
+
+ p_msg->hdr.event = BTA_DM_API_ADD_BLEDEVICE_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->addr_type = addr_type;
+ p_msg->dev_type = dev_type;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBlePasskeyReply
+ *
+ * Description Send BLE SMP passkey reply.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * accept - passkey entry sucessful or declined.
+ * passkey - passkey value, must be a 6 digit number,
+ * can be lead by 0.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, bool accept, uint32_t passkey) {
+ tBTA_DM_API_PASSKEY_REPLY* p_msg =
+ (tBTA_DM_API_PASSKEY_REPLY*)osi_calloc(sizeof(tBTA_DM_API_PASSKEY_REPLY));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_PASSKEY_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+
+ if (accept) p_msg->passkey = passkey;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleConfirmReply
+ *
+ * Description Send BLE SMP SC user confirmation reply.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * accept - numbers to compare are the same or
+ * different.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleConfirmReply(BD_ADDR bd_addr, bool accept) {
+ tBTA_DM_API_CONFIRM* p_msg =
+ (tBTA_DM_API_CONFIRM*)osi_calloc(sizeof(tBTA_DM_API_CONFIRM));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_CONFIRM_REPLY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleSecurityGrant
+ *
+ * Description Grant security request access.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * res - security grant status.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res) {
+ tBTA_DM_API_BLE_SEC_GRANT* p_msg =
+ (tBTA_DM_API_BLE_SEC_GRANT*)osi_calloc(sizeof(tBTA_DM_API_BLE_SEC_GRANT));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_SEC_GRANT_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->res = res;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetBlePrefConnParams
+ *
+ * Description This function is called to set the preferred connection
+ * parameters when default connection parameter is not desired.
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * scan_interval - scan interval
+ * scan_window - scan window
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSetBlePrefConnParams(const BD_ADDR bd_addr, uint16_t min_conn_int,
+ uint16_t max_conn_int, uint16_t slave_latency,
+ uint16_t supervision_tout) {
+ tBTA_DM_API_BLE_CONN_PARAMS* p_msg = (tBTA_DM_API_BLE_CONN_PARAMS*)osi_calloc(
+ sizeof(tBTA_DM_API_BLE_CONN_PARAMS));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_CONN_PARAM_EVT;
+ memcpy(p_msg->peer_bda, bd_addr, BD_ADDR_LEN);
+ p_msg->conn_int_max = max_conn_int;
+ p_msg->conn_int_min = min_conn_int;
+ p_msg->slave_latency = slave_latency;
+ p_msg->supervision_tout = supervision_tout;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetBleConnScanParams
+ *
+ * Description This function is called to set scan parameters used in
+ * BLE connection request
+ *
+ * Parameters: scan_interval - scan interval
+ * scan_window - scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSetBleConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
+ tBTA_DM_API_BLE_SCAN_PARAMS* p_msg = (tBTA_DM_API_BLE_SCAN_PARAMS*)osi_calloc(
+ sizeof(tBTA_DM_API_BLE_SCAN_PARAMS));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT;
+ p_msg->scan_int = scan_interval;
+ p_msg->scan_window = scan_window;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/**
+ * Set BLE connectable mode to auto connect
+ */
+void BTA_DmBleStartAutoConn() {
+ tBTA_DM_API_SET_NAME* p_msg =
+ (tBTA_DM_API_SET_NAME*)osi_calloc(sizeof(tBTA_DM_API_SET_NAME));
+
+ p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE;
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_discover_send_msg
+ *
+ * Description This function send discover message to BTA task.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_discover_send_msg(BD_ADDR bd_addr,
+ tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback,
+ bool sdp_search,
+ tBTA_TRANSPORT transport) {
+ const size_t len = p_services ? (sizeof(tBTA_DM_API_DISCOVER) +
+ sizeof(tBT_UUID) * p_services->num_uuid)
+ : sizeof(tBTA_DM_API_DISCOVER);
+ tBTA_DM_API_DISCOVER* p_msg = (tBTA_DM_API_DISCOVER*)osi_calloc(len);
+
+ p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->p_cback = p_cback;
+ p_msg->sdp_search = sdp_search;
+ p_msg->transport = transport;
+
+ if (p_services != NULL) {
+ p_msg->services = p_services->srvc_mask;
+ p_msg->num_uuid = p_services->num_uuid;
+ if (p_services->num_uuid != 0) {
+ p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+ memcpy(p_msg->p_uuid, p_services->p_uuid,
+ sizeof(tBT_UUID) * p_services->num_uuid);
+ }
+ }
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverByTransport
+ *
+ * Description This function does service discovery on particular transport
+ * for services of a
+ * peer device. When services.num_uuid is 0, it indicates all
+ * GATT based services are to be searched; otherwise a list of
+ * UUID of interested services should be provided through
+ * p_services->p_uuid.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverByTransport(BD_ADDR bd_addr,
+ tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search,
+ tBTA_TRANSPORT transport) {
+ bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search, transport);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverExt
+ *
+ * Description This function does service discovery for services of a
+ * peer device. When services.num_uuid is 0, it indicates all
+ * GATT based services are to be searched; other wise a list of
+ * UUID of interested services should be provided through
+ * p_services->p_uuid.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmDiscoverExt(BD_ADDR bd_addr, tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search) {
+ bta_dm_discover_send_msg(bd_addr, p_services, p_cback, sdp_search,
+ BTA_TRANSPORT_UNKNOWN);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearchExt
+ *
+ * Description This function searches for peer Bluetooth devices. It
+ * performs an inquiry and gets the remote name for devices.
+ * Service discovery is done if services is non zero
+ *
+ * Parameters p_dm_inq: inquiry conditions
+ * p_services: if service is not empty, service discovery will
+ * be done. For all GATT based service conditions,
+ * put num_uuid, and p_uuid is the pointer to the
+ * list of UUID values.
+ * p_cback: callback function when search is completed.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSearchExt(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback) {
+ const size_t len = p_services ? (sizeof(tBTA_DM_API_SEARCH) +
+ sizeof(tBT_UUID) * p_services->num_uuid)
+ : sizeof(tBTA_DM_API_SEARCH);
+ tBTA_DM_API_SEARCH* p_msg = (tBTA_DM_API_SEARCH*)osi_calloc(len);
+
+ p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
+ memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
+ p_msg->p_cback = p_cback;
+ p_msg->rs_res = BTA_DM_RS_NONE;
+
+ if (p_services != NULL) {
+ p_msg->services = p_services->srvc_mask;
+ p_msg->num_uuid = p_services->num_uuid;
+
+ if (p_services->num_uuid != 0) {
+ p_msg->p_uuid = (tBT_UUID*)(p_msg + 1);
+ memcpy(p_msg->p_uuid, p_services->p_uuid,
+ sizeof(tBT_UUID) * p_services->num_uuid);
+ } else {
+ p_msg->p_uuid = NULL;
+ }
+ }
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleUpdateConnectionParam
+ *
+ * Description Update connection parameters, can only be used when
+ * connection is up.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * min_int - minimum connection interval,
+ * [0x0004 ~ 0x4000]
+ * max_int - maximum connection interval,
+ * [0x0004 ~ 0x4000]
+ * latency - slave latency [0 ~ 500]
+ * timeout - supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleUpdateConnectionParam(BD_ADDR bd_addr, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout) {
+ tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
+ (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
+ sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
+
+ p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->min_int = min_int;
+ p_msg->max_int = max_int;
+ p_msg->latency = latency;
+ p_msg->timeout = timeout;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleConfigLocalPrivacy
+ *
+ * Description Enable/disable privacy on the local device
+ *
+ * Parameters: privacy_enable - enable/disabe privacy on remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleConfigLocalPrivacy(bool privacy_enable) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ tBTA_DM_API_LOCAL_PRIVACY* p_msg = (tBTA_DM_API_LOCAL_PRIVACY*)osi_calloc(
+ sizeof(tBTA_DM_API_ENABLE_PRIVACY));
+
+ p_msg->hdr.event = BTA_DM_API_LOCAL_PRIVACY_EVT;
+ p_msg->privacy_enable = privacy_enable;
+
+ bta_sys_sendmsg(p_msg);
+#else
+ UNUSED(privacy_enable);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleGetEnergyInfo
+ *
+ * Description This function is called to obtain the energy info
+ *
+ * Parameters p_cmpl_cback - Command complete callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback) {
+ const size_t len = sizeof(tBTA_DM_API_ENERGY_INFO) + sizeof(tBLE_BD_ADDR);
+ tBTA_DM_API_ENERGY_INFO* p_msg = (tBTA_DM_API_ENERGY_INFO*)osi_calloc(len);
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_DM_API_BLE_ENERGY_INFO_EVT;
+ p_msg->p_energy_info_cback = p_cmpl_cback;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleUpdateConnectionParams
+ *
+ * Description Update connection parameters, can only be used when
+ * connection is up.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * min_int - minimum connection interval,
+ * [0x0004 ~ 0x4000]
+ * max_int - maximum connection interval,
+ * [0x0004 ~ 0x4000]
+ * latency - slave latency [0 ~ 500]
+ * timeout - supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmBleUpdateConnectionParams(const BD_ADDR bd_addr, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout) {
+ tBTA_DM_API_UPDATE_CONN_PARAM* p_msg =
+ (tBTA_DM_API_UPDATE_CONN_PARAM*)osi_calloc(
+ sizeof(tBTA_DM_API_UPDATE_CONN_PARAM));
+
+ p_msg->hdr.event = BTA_DM_API_UPDATE_CONN_PARAM_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->min_int = min_int;
+ p_msg->max_int = max_int;
+ p_msg->latency = latency;
+ p_msg->timeout = timeout;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleSetDataLength
+ *
+ * Description This function is to set maximum LE data packet size
+ *
+ * Returns void
+ *
+ *
+ ******************************************************************************/
+void BTA_DmBleSetDataLength(BD_ADDR remote_device, uint16_t tx_data_length) {
+ tBTA_DM_API_BLE_SET_DATA_LENGTH* p_msg =
+ (tBTA_DM_API_BLE_SET_DATA_LENGTH*)osi_malloc(
+ sizeof(tBTA_DM_API_BLE_SET_DATA_LENGTH));
+
+ bdcpy(p_msg->remote_bda, remote_device);
+ p_msg->hdr.event = BTA_DM_API_SET_DATA_LENGTH_EVT;
+ p_msg->tx_data_length = tx_data_length;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetEncryption
+ *
+ * Description This function is called to ensure that connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - transport of the link to be encruypted
+ * p_callback - Pointer to callback function to indicat the
+ * link encryption status
+ * sec_act - This is the security action to indicate
+ * what kind of BLE security level is required
+ * for the BLE link if BLE is supported.
+ * Note: This parameter is ignored for the
+ * BR/EDR or if BLE is not supported.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+ tBTA_DM_ENCRYPT_CBACK* p_callback,
+ tBTA_DM_BLE_SEC_ACT sec_act) {
+ tBTA_DM_API_SET_ENCRYPTION* p_msg = (tBTA_DM_API_SET_ENCRYPTION*)osi_calloc(
+ sizeof(tBTA_DM_API_SET_ENCRYPTION));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_DM_API_SET_ENCRYPTION_EVT;
+ memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_msg->transport = transport;
+ p_msg->p_callback = p_callback;
+ p_msg->sec_act = sec_act;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmCloseACL
+ *
+ * Description This function force to close an ACL connection and remove
+ * the device from the security database list of known devices.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * remove_dev - remove device or not after link down
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_DmCloseACL(BD_ADDR bd_addr, bool remove_dev,
+ tBTA_TRANSPORT transport) {
+ tBTA_DM_API_REMOVE_ACL* p_msg =
+ (tBTA_DM_API_REMOVE_ACL*)osi_calloc(sizeof(tBTA_DM_API_REMOVE_ACL));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_DM_API_REMOVE_ACL_EVT;
+ memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_msg->remove_dev = remove_dev;
+ p_msg->transport = transport;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleObserve
+ *
+ * Description This procedure keep the device listening for advertising
+ * events from a broadcast device.
+ *
+ * Parameters start: start or stop observe.
+ *
+ * Returns void
+
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void BTA_DmBleObserve(bool start, uint8_t duration,
+ tBTA_DM_SEARCH_CBACK* p_results_cb) {
+ tBTA_DM_API_BLE_OBSERVE* p_msg =
+ (tBTA_DM_API_BLE_OBSERVE*)osi_calloc(sizeof(tBTA_DM_API_BLE_OBSERVE));
+
+ APPL_TRACE_API("%s:start = %d ", __func__, start);
+
+ p_msg->hdr.event = BTA_DM_API_BLE_OBSERVE_EVT;
+ p_msg->start = start;
+ p_msg->duration = duration;
+ p_msg->p_cback = p_results_cb;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_VendorInit
+ *
+ * Description This function initializes vendor specific
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_VendorInit(void) { APPL_TRACE_API("BTA_VendorInit"); }
+
+/*******************************************************************************
+ *
+ * Function BTA_VendorCleanup
+ *
+ * Description This function frees up Broadcom specific VS specific dynamic
+ * memory
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_VendorCleanup(void) {
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (cmn_ble_vsc_cb.max_filter > 0) {
+ btm_ble_adv_filter_cleanup();
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_resolving_list_cleanup();
+#endif
+ }
+
+ if (cmn_ble_vsc_cb.tot_scan_results_strg > 0) btm_ble_batchscan_cleanup();
+
+ if (cmn_ble_vsc_cb.adv_inst_max > 0) btm_ble_multi_adv_cleanup();
+}
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_cfg.cc b/mtkbt/code/bt/bta/dm/bta_dm_cfg.cc
new file mode 100755
index 0000000..175c894
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_cfg.cc
@@ -0,0 +1,629 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for the device
+ * manager.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_jv_api.h"
+#include "bta_sys.h"
+
+#ifndef BTA_DM_LINK_POLICY_SETTINGS
+#define BTA_DM_LINK_POLICY_SETTINGS \
+ (HCI_ENABLE_MASTER_SLAVE_SWITCH | HCI_ENABLE_HOLD_MODE | \
+ HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_PARK_MODE)
+#endif
+
+/* page timeout in 625uS */
+#ifndef BTA_DM_PAGE_TIMEOUT
+#define BTA_DM_PAGE_TIMEOUT 8192
+#endif
+
+/* link supervision timeout in 625uS (5 secs) */
+#ifndef BTA_DM_LINK_TIMEOUT
+#define BTA_DM_LINK_TIMEOUT 8000
+#endif
+
+/* TRUE to avoid scatternet when av is streaming (be the master) */
+#ifndef BTA_DM_AVOID_SCATTER_A2DP
+#define BTA_DM_AVOID_SCATTER_A2DP TRUE
+#endif
+
+/* For Insight, PM cfg lookup tables are runtime configurable (to allow tweaking
+ * of params for power consumption measurements) */
+#ifndef BTE_SIM_APP
+#define tBTA_DM_PM_TYPE_QUALIFIER const
+#else
+#define tBTA_DM_PM_TYPE_QUALIFIER
+#endif
+
+const tBTA_DM_CFG bta_dm_cfg = {
+ /* mobile phone COD */
+ BTA_DM_COD,
+ /* link policy settings */
+ BTA_DM_LINK_POLICY_SETTINGS,
+ /* page timeout in 625uS */
+ BTA_DM_PAGE_TIMEOUT,
+ /* link supervision timeout in 625uS*/
+ BTA_DM_LINK_TIMEOUT,
+ /* true to avoid scatternet when av is streaming (be the master) */
+ BTA_DM_AVOID_SCATTER_A2DP};
+
+#ifndef BTA_DM_SCATTERNET
+/* By default, allow partial scatternet */
+#define BTA_DM_SCATTERNET BTA_DM_PARTIAL_SCATTERNET
+#endif
+
+#ifndef BTA_HH_ROLE
+/* By default, do not specify HH role (backward compatibility) */
+#define BTA_HH_ROLE BTA_ANY_ROLE
+#endif
+
+#ifndef BTA_AV_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
+#endif
+
+#ifndef BTA_PANU_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY
+#endif
+#define BTA_DM_NUM_RM_ENTRY 6
+
+/* appids for PAN used by insight sample application
+ these have to be same as defined in btui_int.h */
+#define BTUI_PAN_ID_PANU 0
+#define BTUI_PAN_ID_NAP 1
+#define BTUI_PAN_ID_GN 2
+
+/* First element is always for SYS:
+ app_id = # of entries table, cfg is
+ device scatternet support */
+const tBTA_DM_RM bta_dm_rm_cfg[] = {
+ {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
+ {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE},
+ {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE},
+ {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY},
+ {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE},
+ {BTA_ID_HH, BTA_ALL_APP_ID, BTA_HH_ROLE},
+ {BTA_ID_AV, BTA_ALL_APP_ID, BTA_AV_ROLE}};
+
+tBTA_DM_CFG* p_bta_dm_cfg = (tBTA_DM_CFG*)&bta_dm_cfg;
+
+tBTA_DM_RM* p_bta_dm_rm_cfg = (tBTA_DM_RM*)&bta_dm_rm_cfg;
+
+#define BTA_DM_NUM_PM_ENTRY \
+ 23 /* number of entries in bta_dm_pm_cfg except the first */
+#define BTA_DM_NUM_PM_SPEC 15 /* number of entries in bta_dm_pm_spec */
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG
+ bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = {
+ {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY,
+ 0}, /* reserved: specifies length of this table. */
+ {BTA_ID_AG, BTA_ALL_APP_ID,
+ 0}, /* ag uses first spec table for app id 0 */
+ {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */
+ {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */
+ {BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */
+ {BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */
+ {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */
+ {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */
+ {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */
+ {BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */
+ {BTA_ID_HH, BTA_ALL_APP_ID, 5}, /* hh spec table */
+ {BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */
+ {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */
+ {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_JV, BTA_JV_PM_ID_1,
+ 6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
+ {BTA_ID_JV, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_HL, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
+ {BTA_ID_PAN, BTUI_PAN_ID_PANU, 9}, /* PANU spec table */
+ {BTA_ID_PAN, BTUI_PAN_ID_NAP, 10}, /* NAP spec table */
+ {BTA_ID_HS, BTA_ALL_APP_ID, 11}, /* HS spec table */
+ {BTA_ID_GATTC, BTA_ALL_APP_ID, 13}, /* gattc spec table */
+ {BTA_ID_GATTS, BTA_ALL_APP_ID, 14} /* gatts spec table */
+};
+
+tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
+ /* AG : 0 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
+ {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_RETRY, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* CT, CG : 1 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_PARK, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */
+ {{BTA_DM_PM_PARK, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_RETRY, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* DG, PBC : 2 */
+ {(BTA_DM_PM_ACTIVE), /* no power saving mode allowed */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF, 1000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* HD : 3 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR3), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* AV : 4 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* HH : 5 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR1), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */
+ {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* FTC, OPC, JV : 6 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* FTS, PBS, OPS, MSE, BTA_JV_PM_ID_1 : 7 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* HL : 8 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* PANU : 9 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* NAP : 10 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_ACTIVE, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* HS : 11 */
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_SNIFF3, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */
+ {{BTA_DM_PM_SNIFF, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */
+ {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_RETRY, 7000},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }},
+
+ /* AVK : 12 */
+ {(BTA_DM_PM_SNIFF), /* allow sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF, 3000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF4, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+ {{BTA_DM_PM_NO_ACTION, 0},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }}
+
+ /* GATTC : 13 */
+ ,
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+#if (AMP_INCLUDED == TRUE)
+ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
+#endif
+ {{BTA_DM_PM_RETRY, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }}
+ /* GATTS : 14 */
+ ,
+ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */
+#if (BTM_SSR_INCLUDED == TRUE)
+ (BTA_DM_PM_SSR2), /* the SSR entry */
+#endif
+ {
+ {{BTA_DM_PM_NO_PREF, 0},
+ {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */
+#if (AMP_INCLUDED == TRUE)
+ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */
+#endif
+ {{BTA_DM_PM_RETRY, 5000},
+ {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */
+ }}
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+ /* Entries at the end of the pm_spec table are user-defined (runtime
+ configurable),
+ for power consumption experiments.
+ Insight finds the first user-defined entry by looking for the first
+ BTA_DM_PM_NO_PREF.
+ The number of user_defined specs is defined by
+ BTA_SWRAP_UD_PM_SPEC_COUNT */
+ ,
+ {BTA_DM_PM_NO_PREF}, /* pm_spec USER_DEFINED_0 */
+ {BTA_DM_PM_NO_PREF} /* pm_spec USER_DEFINED_1 */
+#endif /* BTE_SIM_APP */
+};
+
+/* Please refer to the SNIFF table definitions in bta_api.h.
+ *
+ * Adding to or Modifying the Table
+ * Additional sniff parameter entries can be added for BTA_DM_PM_SNIFF5 -
+ * BTA_DM_PM_SNIFF7.
+ * Overrides of additional table entries can be specified in bdroid_buildcfg.h.
+ * If additional
+ * sniff parameter entries are added or an override of an existing entry is
+ * specified in
+ * bdroid_buildcfg.h then the BTA_DM_PM_*_IDX defines in bta_api.h will need to
+ * be match the new
+ * ordering.
+ *
+ * Table Ordering
+ * Sniff Table entries must be ordered from highest latency (biggest interval)
+ * to lowest latency.
+ * If there is a conflict among the connected services the setting with the
+ * lowest latency will
+ * be selected.
+ */
+tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = {
+ /*
+ * More sniff parameter entries can be added for
+ * BTA_DM_PM_SNIFF3 - BTA_DM_PM_SNIFF7, if needed. When entries are added or
+ * removed, BTA_DM_PM_PARK_IDX needs to be updated to reflect the actual
+ * index
+ * BTA_DM_PM_PARK_IDX is defined in bta_api.h and can be override by the
+ * bdroid_buildcfg.h settings.
+ * The SNIFF table entries must be in the order from highest latency
+ * (biggest
+ * interval) to lowest latency. If there's a conflict among the connected
+ * services, the setting with lowest latency wins.
+ */
+ /* sniff modes: max interval, min interval, attempt, timeout */
+ {BTA_DM_PM_SNIFF_MAX, BTA_DM_PM_SNIFF_MIN, BTA_DM_PM_SNIFF_ATTEMPT,
+ BTA_DM_PM_SNIFF_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF - A2DP */
+ {BTA_DM_PM_SNIFF1_MAX, BTA_DM_PM_SNIFF1_MIN, BTA_DM_PM_SNIFF1_ATTEMPT,
+ BTA_DM_PM_SNIFF1_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF1 */
+ {BTA_DM_PM_SNIFF2_MAX, BTA_DM_PM_SNIFF2_MIN, BTA_DM_PM_SNIFF2_ATTEMPT,
+ BTA_DM_PM_SNIFF2_TIMEOUT,
+ BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF2- HD idle */
+ {BTA_DM_PM_SNIFF3_MAX, BTA_DM_PM_SNIFF3_MIN, BTA_DM_PM_SNIFF3_ATTEMPT,
+ BTA_DM_PM_SNIFF3_TIMEOUT,
+ BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF3- SCO open */
+ {BTA_DM_PM_SNIFF4_MAX, BTA_DM_PM_SNIFF4_MIN, BTA_DM_PM_SNIFF4_ATTEMPT,
+ BTA_DM_PM_SNIFF4_TIMEOUT,
+ BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF4- HD active */
+ {BTA_DM_PM_SNIFF5_MAX, BTA_DM_PM_SNIFF5_MIN, BTA_DM_PM_SNIFF5_ATTEMPT,
+ BTA_DM_PM_SNIFF5_TIMEOUT,
+ BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF5- HD active */
+ {BTA_DM_PM_PARK_MAX, BTA_DM_PM_PARK_MIN, BTA_DM_PM_PARK_ATTEMPT,
+ BTA_DM_PM_PARK_TIMEOUT, BTM_PM_MD_PARK}
+
+#ifdef BTE_SIM_APP /* For Insight builds only */
+ /* Entries at the end of the bta_dm_pm_md table are user-defined (runtime
+ configurable),
+ for power consumption experiments.
+ Insight finds the first user-defined entry by looking for the first
+ 'max=0'.
+ The number of user_defined specs is defined by BTA_SWRAP_UD_PM_DM_COUNT
+ */
+ ,
+ {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_0
+ */
+ {0}, /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_0 */
+
+ {0}, /* CONN_OPEN/SCO_CLOSE power mode settings for pm_spec USER_DEFINED_1
+ */
+ {0} /* SCO_OPEN power mode settings for pm_spec USER_DEFINED_1 */
+#endif /* BTE_SIM_APP */
+};
+
+/* 0=max_lat -> no SSR */
+/* the smaller of the SSR max latency wins.
+ * the entries in this table must be from highest latency (biggest interval) to
+ * lowest latency */
+#if (BTM_SSR_INCLUDED == TRUE)
+tBTA_DM_SSR_SPEC bta_dm_ssr_spec[] = {
+ /*max_lat, min_rmt_to, min_loc_to*/
+ {0, 0, 0}, /* BTA_DM_PM_SSR0 - do not use SSR */
+ /* BTA_DM_PM_SSR1 - HH, can NOT share entry with any other profile, seting
+ default max latency and min remote timeout as 0, and always read
+ individual device preference from HH module */
+ {0, 0, 2},
+ {1200, 2, 2}, /* BTA_DM_PM_SSR2 - others (as long as sniff is allowed)*/
+ {360, 160, 1600} /* BTA_DM_PM_SSR3 - HD */
+};
+
+tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec = (tBTA_DM_SSR_SPEC*)&bta_dm_ssr_spec;
+#endif
+
+tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = (tBTA_DM_PM_CFG*)&bta_dm_pm_cfg;
+tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = (tBTA_DM_PM_SPEC*)&bta_dm_pm_spec;
+tBTM_PM_PWR_MD* p_bta_dm_pm_md = (tBTM_PM_PWR_MD*)&bta_dm_pm_md;
+
+/* The performance impact of EIR packet size
+ *
+ * When BTM_EIR_DEFAULT_FEC_REQUIRED is true,
+ * 1 to 17 bytes, DM1 is used and most robust.
+ * 18 to 121 bytes, DM3 is used but impacts inquiry scan time with large number
+ * of devices.(almost double with 150 users)
+ * 122 to 224 bytes, DM5 is used but cause quite big performance loss even with
+ * small number of users. so it is not recommended.
+ * 225 to 240 bytes, DH5 is used without FEC but it not recommended.
+ * (same reason of DM5)
+ *
+ * When BTM_EIR_DEFAULT_FEC_REQUIRED is false,
+ * 1 to 27 bytes, DH1 is used but only robust at short range.
+ * 28 to 183 bytes, DH3 is used but only robust at short range and impacts
+ * inquiry
+ * scan time with large number of devices.
+ * 184 to 240 bytes, DH5 is used but it not recommended.
+*/
+
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+/* for example */
+const uint8_t bta_dm_eir_uuid16_list[] = {
+ 0x08, 0x11, /* Headset */
+ 0x1E, 0x11, /* Handsfree */
+ 0x0E, 0x11, /* AV Remote Control */
+ 0x0B, 0x11, /* Audio Sink */
+};
+#endif // BTA_EIR_CANNED_UUID_LIST
+
+/* Extended Inquiry Response */
+const tBTA_DM_EIR_CONF bta_dm_eir_cfg = {
+ 50, /* minimum length of local name when it is shortened */
+ /* if length of local name is longer than this and EIR has not enough */
+ /* room for all UUID list then local name is shortened to this length */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ 8, (uint8_t*)bta_dm_eir_uuid16_list,
+#else // BTA_EIR_CANNED_UUID_LIST
+ {
+ /* mask of UUID list in EIR */
+ 0xFFFFFFFF, /* LSB is the first UUID of the first 32 UUIDs in
+ BTM_EIR_UUID_LKUP_TBL */
+ 0xFFFFFFFF /* LSB is the first UUID of the next 32 UUIDs in
+ BTM_EIR_UUID_LKUP_TBL */
+ /* BTM_EIR_UUID_LKUP_TBL can be overrided */
+ },
+#endif // BTA_EIR_CANNED_UUID_LIST
+ NULL, /* Inquiry TX power */
+ 0, /* length of flags in bytes */
+ NULL, /* flags for EIR */
+ 0, /* length of manufacturer specific in bytes */
+ NULL, /* manufacturer specific */
+ 0, /* length of additional data in bytes */
+ NULL /* additional data */
+};
+tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg = (tBTA_DM_EIR_CONF*)&bta_dm_eir_cfg;
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_ci.cc b/mtkbt/code/bt/bta/dm/bta_dm_ci.cc
new file mode 100755
index 0000000..d3616d4
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_ci.cc
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the API implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_dm_ci.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_io_req
+ *
+ * Description This function must be called in response to function
+ * bta_dm_co_io_req(), if *p_oob_data to BTA_OOB_UNKNOWN
+ * by bta_dm_co_io_req().
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req)
+
+{
+ tBTA_DM_CI_IO_REQ* p_msg =
+ (tBTA_DM_CI_IO_REQ*)osi_malloc(sizeof(tBTA_DM_CI_IO_REQ));
+
+ p_msg->hdr.event = BTA_DM_CI_IO_REQ_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->io_cap = io_cap;
+ p_msg->oob_data = oob_data;
+ p_msg->auth_req = auth_req;
+
+ bta_sys_sendmsg(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_rmt_oob
+ *
+ * Description This function must be called in response to function
+ * bta_dm_co_rmt_oob() to provide the OOB data associated
+ * with the remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_ci_rmt_oob(bool accept, BD_ADDR bd_addr, BT_OCTET16 c,
+ BT_OCTET16 r) {
+ tBTA_DM_CI_RMT_OOB* p_msg =
+ (tBTA_DM_CI_RMT_OOB*)osi_malloc(sizeof(tBTA_DM_CI_RMT_OOB));
+
+ p_msg->hdr.event = BTA_DM_CI_RMT_OOB_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->accept = accept;
+ memcpy(p_msg->c, c, BT_OCTET16_LEN);
+ memcpy(p_msg->r, r, BT_OCTET16_LEN);
+
+ bta_sys_sendmsg(p_msg);
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_ci_data_ready
+ *
+ * Description This function sends an event to indicating that the phone
+ * has SCO data ready.
+ *
+ * Parameters event: is obtained from bta_dm_sco_co_open() function, which
+ * is the BTA event we want to send back to BTA module
+ * when there is encoded data ready.
+ * sco_handle: is the BTA sco handle which indicate a specific
+ * SCO connection.
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sco_ci_data_ready(uint16_t event, uint16_t sco_handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = event;
+ p_buf->layer_specific = sco_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+#endif
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_int.h b/mtkbt/code/bt/bta/dm/bta_dm_int.h
new file mode 100755
index 0000000..2338e7b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_int.h
@@ -0,0 +1,875 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA device manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_INT_H
+#define BTA_DM_INT_H
+
+#include <memory>
+#include "bt_target.h"
+#include "bta_sys.h"
+
+#include "bta_gatt_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+#define BTA_COPY_DEVICE_CLASS(coddst, codsrc) \
+ { \
+ ((uint8_t*)(coddst))[0] = ((uint8_t*)(codsrc))[0]; \
+ ((uint8_t*)(coddst))[1] = ((uint8_t*)(codsrc))[1]; \
+ ((uint8_t*)(coddst))[2] = ((uint8_t*)(codsrc))[2]; \
+ }
+
+#define BTA_DM_MSG_LEN 50
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+/* DM events */
+enum {
+ /* device manager local device API events */
+ BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),
+ BTA_DM_API_DISABLE_EVT,
+ BTA_DM_API_SET_NAME_EVT,
+ BTA_DM_API_SET_VISIBILITY_EVT,
+
+ BTA_DM_ACL_CHANGE_EVT,
+ BTA_DM_API_ADD_DEVICE_EVT,
+ BTA_DM_API_REMOVE_ACL_EVT,
+
+ /* security API events */
+ BTA_DM_API_BOND_EVT,
+ BTA_DM_API_BOND_CANCEL_EVT,
+ BTA_DM_API_PIN_REPLY_EVT,
+
+ /* power manger events */
+ BTA_DM_PM_BTM_STATUS_EVT,
+ BTA_DM_PM_TIMER_EVT,
+
+ /* simple pairing events */
+ BTA_DM_API_CONFIRM_EVT,
+
+ BTA_DM_API_SET_ENCRYPTION_EVT,
+
+ BTA_DM_API_LOC_OOB_EVT,
+ BTA_DM_CI_IO_REQ_EVT,
+ BTA_DM_CI_RMT_OOB_EVT,
+
+ BTA_DM_API_ADD_BLEKEY_EVT,
+ BTA_DM_API_ADD_BLEDEVICE_EVT,
+ BTA_DM_API_BLE_PASSKEY_REPLY_EVT,
+ BTA_DM_API_BLE_CONFIRM_REPLY_EVT,
+ BTA_DM_API_BLE_SEC_GRANT_EVT,
+ BTA_DM_API_BLE_SET_BG_CONN_TYPE,
+ BTA_DM_API_BLE_CONN_PARAM_EVT,
+ BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT,
+ BTA_DM_API_BLE_OBSERVE_EVT,
+ BTA_DM_API_UPDATE_CONN_PARAM_EVT,
+#if (BLE_PRIVACY_SPT == TRUE)
+ BTA_DM_API_LOCAL_PRIVACY_EVT,
+#endif
+ BTA_DM_API_SET_DATA_LENGTH_EVT,
+ BTA_DM_API_BLE_ENERGY_INFO_EVT,
+
+ BTA_DM_API_ENABLE_TEST_MODE_EVT,
+ BTA_DM_API_DISABLE_TEST_MODE_EVT,
+ BTA_DM_API_EXECUTE_CBACK_EVT,
+ BTA_DM_API_REMOVE_ALL_ACL_EVT,
+ BTA_DM_API_REMOVE_DEVICE_EVT,
+ BTA_DM_MAX_EVT
+};
+
+/* DM search events */
+enum {
+ /* DM search API events */
+ BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH),
+ BTA_DM_API_SEARCH_CANCEL_EVT,
+ BTA_DM_API_DISCOVER_EVT,
+ BTA_DM_INQUIRY_CMPL_EVT,
+ BTA_DM_REMT_NAME_EVT,
+ BTA_DM_SDP_RESULT_EVT,
+ BTA_DM_SEARCH_CMPL_EVT,
+ BTA_DM_DISCOVERY_RESULT_EVT,
+ BTA_DM_API_DI_DISCOVER_EVT,
+ BTA_DM_DISC_CLOSE_TOUT_EVT
+
+};
+
+/* data type for BTA_DM_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_SEC_CBACK* p_sec_cback;
+} tBTA_DM_API_ENABLE;
+
+/* data type for BTA_DM_API_SET_NAME_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_NAME name; /* max 248 bytes name, plus must be Null terminated */
+} tBTA_DM_API_SET_NAME;
+
+/* data type for BTA_DM_API_SET_VISIBILITY_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+ uint8_t pair_mode;
+ uint8_t conn_paired_only;
+} tBTA_DM_API_SET_VISIBILITY;
+
+enum {
+ BTA_DM_RS_NONE, /* straight API call */
+ BTA_DM_RS_OK, /* the role switch result - successful */
+ BTA_DM_RS_FAIL /* the role switch result - failed */
+};
+typedef uint8_t tBTA_DM_RS_RES;
+
+/* data type for BTA_DM_API_SEARCH_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_INQ inq_params;
+ tBTA_SERVICE_MASK services;
+ tBTA_DM_SEARCH_CBACK* p_cback;
+ tBTA_DM_RS_RES rs_res;
+ uint8_t num_uuid;
+ tBT_UUID* p_uuid;
+} tBTA_DM_API_SEARCH;
+
+/* data type for BTA_DM_API_DISCOVER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_MASK services;
+ tBTA_DM_SEARCH_CBACK* p_cback;
+ bool sdp_search;
+ tBTA_TRANSPORT transport;
+ uint8_t num_uuid;
+ tBT_UUID* p_uuid;
+ tSDP_UUID uuid;
+} tBTA_DM_API_DISCOVER;
+
+/* data type for BTA_DM_API_DI_DISC_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_DISCOVERY_DB* p_sdp_db;
+ uint32_t len;
+ tBTA_DM_SEARCH_CBACK* p_cback;
+} tBTA_DM_API_DI_DISC;
+
+/* data type for BTA_DM_API_BOND_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_TRANSPORT transport;
+} tBTA_DM_API_BOND;
+
+/* data type for BTA_DM_API_BOND_CANCEL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_TRANSPORT transport;
+} tBTA_DM_API_BOND_CANCEL;
+
+/* data type for BTA_DM_API_PIN_REPLY_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ bool accept;
+ uint8_t pin_len;
+ uint8_t p_pin[PIN_CODE_LEN];
+} tBTA_DM_API_PIN_REPLY;
+
+/* data type for BTA_DM_API_LOC_OOB_EVT */
+typedef struct { BT_HDR hdr; } tBTA_DM_API_LOC_OOB;
+
+/* data type for BTA_DM_API_CONFIRM_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ bool accept;
+} tBTA_DM_API_CONFIRM;
+
+/* data type for BTA_DM_CI_IO_REQ_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_IO_CAP io_cap;
+ tBTA_OOB_DATA oob_data;
+ tBTA_AUTH_REQ auth_req;
+} tBTA_DM_CI_IO_REQ;
+
+/* data type for BTA_DM_CI_RMT_OOB_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ BT_OCTET16 c;
+ BT_OCTET16 r;
+ bool accept;
+} tBTA_DM_CI_RMT_OOB;
+
+/* data type for BTA_DM_REMT_NAME_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_SEARCH result;
+} tBTA_DM_REM_NAME;
+
+/* data type for tBTA_DM_DISC_RESULT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_SEARCH result;
+} tBTA_DM_DISC_RESULT;
+
+/* data type for BTA_DM_INQUIRY_CMPL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t num;
+} tBTA_DM_INQUIRY_CMPL;
+
+/* data type for BTA_DM_SDP_RESULT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t sdp_result;
+} tBTA_DM_SDP_RESULT;
+
+/* data type for BTA_DM_ACL_CHANGE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTM_BL_EVENT event;
+ uint8_t busy_level;
+ uint8_t busy_level_flags;
+ bool is_new;
+ uint8_t new_role;
+ BD_ADDR bd_addr;
+ uint8_t hci_status;
+ uint16_t handle;
+ tBT_TRANSPORT transport;
+} tBTA_DM_ACL_CHANGE;
+
+/* data type for BTA_DM_PM_BTM_STATUS_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTM_PM_STATUS status;
+ uint16_t value;
+ uint8_t hci_status;
+
+} tBTA_DM_PM_BTM_STATUS;
+
+/* data type for BTA_DM_PM_TIMER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_DM_PM_ACTION pm_request;
+} tBTA_DM_PM_TIMER;
+
+/* data type for BTA_DM_API_ADD_DEVICE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ DEV_CLASS dc;
+ LINK_KEY link_key;
+ tBTA_SERVICE_MASK tm;
+ bool is_trusted;
+ uint8_t key_type;
+ tBTA_IO_CAP io_cap;
+ bool link_key_known;
+ bool dc_known;
+ BD_NAME bd_name;
+ uint8_t
+ features[BTA_FEATURE_BYTES_PER_PAGE * (BTA_EXT_FEATURES_PAGE_MAX + 1)];
+ uint8_t pin_length;
+} tBTA_DM_API_ADD_DEVICE;
+
+/* data type for BTA_DM_API_REMOVE_ACL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_REMOVE_DEVICE;
+
+/* data type for BTA_DM_API_EXECUTE_CBACK_EVT */
+typedef struct {
+ BT_HDR hdr;
+ void* p_param;
+ tBTA_DM_EXEC_CBACK* p_exec_cback;
+} tBTA_DM_API_EXECUTE_CBACK;
+
+/* data type for tBTA_DM_API_SET_ENCRYPTION */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_TRANSPORT transport;
+ tBTA_DM_ENCRYPT_CBACK* p_callback;
+ tBTA_DM_BLE_SEC_ACT sec_act;
+ BD_ADDR bd_addr;
+} tBTA_DM_API_SET_ENCRYPTION;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_LE_KEY_VALUE blekey;
+ tBTA_LE_KEY_TYPE key_type;
+
+} tBTA_DM_API_ADD_BLEKEY;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+} tBTA_DM_API_ADD_BLE_DEVICE;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ bool accept;
+ uint32_t passkey;
+} tBTA_DM_API_PASSKEY_REPLY;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_DM_BLE_SEC_GRANT res;
+} tBTA_DM_API_BLE_SEC_GRANT;
+
+/* set prefered BLE connection parameters for a device */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR peer_bda;
+ uint16_t conn_int_min;
+ uint16_t conn_int_max;
+ uint16_t supervision_tout;
+ uint16_t slave_latency;
+
+} tBTA_DM_API_BLE_CONN_PARAMS;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR peer_bda;
+ bool privacy_enable;
+
+} tBTA_DM_API_ENABLE_PRIVACY;
+
+typedef struct {
+ BT_HDR hdr;
+ bool privacy_enable;
+} tBTA_DM_API_LOCAL_PRIVACY;
+
+/* set scan parameter for BLE connections */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATTC_IF client_if;
+ uint32_t scan_int;
+ uint32_t scan_window;
+ tBLE_SCAN_MODE scan_mode;
+ tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
+} tBTA_DM_API_BLE_SCAN_PARAMS;
+
+/* set scan parameter for BLE connections */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t scan_int;
+ uint16_t scan_window;
+} tBTA_DM_API_BLE_CONN_SCAN_PARAMS;
+
+/* Data type for start/stop observe */
+typedef struct {
+ BT_HDR hdr;
+ bool start;
+ uint16_t duration;
+ tBTA_DM_SEARCH_CBACK* p_cback;
+} tBTA_DM_API_BLE_OBSERVE;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ uint16_t tx_data_length;
+} tBTA_DM_API_BLE_SET_DATA_LENGTH;
+
+/* set adv parameter for BLE advertising */
+
+typedef struct {
+ BT_HDR hdr;
+ bool enable;
+
+} tBTA_DM_API_BLE_FEATURE;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback;
+} tBTA_DM_API_ENERGY_INFO;
+
+/* data type for BTA_DM_API_REMOVE_ACL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ bool remove_dev;
+ tBTA_TRANSPORT transport;
+
+} tBTA_DM_API_REMOVE_ACL;
+
+/* data type for BTA_DM_API_REMOVE_ALL_ACL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_DM_LINK_TYPE link_type;
+
+} tBTA_DM_API_REMOVE_ALL_ACL;
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ uint16_t min_int;
+ uint16_t max_int;
+ uint16_t latency;
+ uint16_t timeout;
+} tBTA_DM_API_UPDATE_CONN_PARAM;
+
+/* union of all data types */
+typedef union {
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_DM_API_ENABLE enable;
+
+ tBTA_DM_API_SET_NAME set_name;
+
+ tBTA_DM_API_SET_VISIBILITY set_visibility;
+
+ tBTA_DM_API_ADD_DEVICE add_dev;
+
+ tBTA_DM_API_REMOVE_DEVICE remove_dev;
+
+ tBTA_DM_API_SEARCH search;
+
+ tBTA_DM_API_DISCOVER discover;
+
+ tBTA_DM_API_BOND bond;
+
+ tBTA_DM_API_BOND_CANCEL bond_cancel;
+
+ tBTA_DM_API_PIN_REPLY pin_reply;
+
+ tBTA_DM_API_LOC_OOB loc_oob;
+ tBTA_DM_API_CONFIRM confirm;
+ tBTA_DM_CI_IO_REQ ci_io_req;
+ tBTA_DM_CI_RMT_OOB ci_rmt_oob;
+
+ tBTA_DM_REM_NAME rem_name;
+
+ tBTA_DM_DISC_RESULT disc_result;
+
+ tBTA_DM_INQUIRY_CMPL inq_cmpl;
+
+ tBTA_DM_SDP_RESULT sdp_event;
+
+ tBTA_DM_ACL_CHANGE acl_change;
+
+ tBTA_DM_PM_BTM_STATUS pm_status;
+
+ tBTA_DM_PM_TIMER pm_timer;
+
+ tBTA_DM_API_DI_DISC di_disc;
+
+ tBTA_DM_API_EXECUTE_CBACK exec_cback;
+
+ tBTA_DM_API_SET_ENCRYPTION set_encryption;
+
+ tBTA_DM_API_ADD_BLEKEY add_ble_key;
+ tBTA_DM_API_ADD_BLE_DEVICE add_ble_device;
+ tBTA_DM_API_PASSKEY_REPLY ble_passkey_reply;
+ tBTA_DM_API_BLE_SEC_GRANT ble_sec_grant;
+ tBTA_DM_API_BLE_CONN_PARAMS ble_set_conn_params;
+ tBTA_DM_API_BLE_CONN_SCAN_PARAMS ble_set_conn_scan_params;
+ tBTA_DM_API_BLE_OBSERVE ble_observe;
+ tBTA_DM_API_ENABLE_PRIVACY ble_remote_privacy;
+ tBTA_DM_API_LOCAL_PRIVACY ble_local_privacy;
+ tBTA_DM_API_UPDATE_CONN_PARAM ble_update_conn_params;
+ tBTA_DM_API_BLE_SET_DATA_LENGTH ble_set_data_length;
+
+ tBTA_DM_API_ENERGY_INFO ble_energy_info;
+
+ tBTA_DM_API_REMOVE_ACL remove_acl;
+ tBTA_DM_API_REMOVE_ALL_ACL remove_all_acl;
+
+} tBTA_DM_MSG;
+
+/** M: Feature change for FW multi-links, 7BR+32BLE @{ */
+#define BTA_DM_NUM_PEER_DEVICE MAX_L2CAP_LINKS
+/** @} */
+
+#define BTA_DM_NOT_CONNECTED 0
+#define BTA_DM_CONNECTED 1
+#define BTA_DM_UNPAIRING 2
+typedef uint8_t tBTA_DM_CONN_STATE;
+
+#define BTA_DM_DI_NONE 0x00 /* nothing special */
+#define BTA_DM_DI_USE_SSR \
+ 0x10 /* set this bit if ssr is supported for this link */
+#define BTA_DM_DI_AV_ACTIVE \
+ 0x20 /* set this bit if AV is active for this link */
+#define BTA_DM_DI_SET_SNIFF \
+ 0x01 /* set this bit if call BTM_SetPowerMode(sniff) */
+#define BTA_DM_DI_INT_SNIFF \
+ 0x02 /* set this bit if call BTM_SetPowerMode(sniff) & enter sniff mode */
+#define BTA_DM_DI_ACP_SNIFF 0x04 /* set this bit if peer init sniff */
+typedef uint8_t tBTA_DM_DEV_INFO;
+
+/* set power mode request type */
+#define BTA_DM_PM_RESTART 1
+#define BTA_DM_PM_NEW_REQ 2
+#define BTA_DM_PM_EXECUTE 3
+typedef uint8_t tBTA_DM_PM_REQ;
+
+typedef struct {
+ BD_ADDR peer_bdaddr;
+ uint16_t link_policy;
+ tBTA_DM_CONN_STATE conn_state;
+ tBTA_PREF_ROLES pref_role;
+ bool in_use;
+ tBTA_DM_DEV_INFO info;
+ tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback;
+#if (BTM_SSR_INCLUDED == TRUE)
+ tBTM_PM_STATUS prev_low; /* previous low power mode used */
+#endif
+ tBTA_DM_PM_ACTION pm_mode_attempted;
+ tBTA_DM_PM_ACTION pm_mode_failed;
+ bool remove_dev_pending;
+ uint16_t conn_handle;
+ tBT_TRANSPORT transport;
+} tBTA_DM_PEER_DEVICE;
+
+/* structure to store list of
+ active connections */
+typedef struct {
+ tBTA_DM_PEER_DEVICE peer_device[BTA_DM_NUM_PEER_DEVICE];
+ uint8_t count;
+ uint8_t le_count;
+} tBTA_DM_ACTIVE_LINK;
+
+typedef struct {
+ BD_ADDR peer_bdaddr;
+ tBTA_SYS_ID id;
+ uint8_t app_id;
+ tBTA_SYS_CONN_STATUS state;
+ bool new_request;
+
+} tBTA_DM_SRVCS;
+
+#ifndef BTA_DM_NUM_CONN_SRVS
+#define BTA_DM_NUM_CONN_SRVS 10
+#endif
+
+typedef struct {
+ uint8_t count;
+ tBTA_DM_SRVCS conn_srvc[BTA_DM_NUM_CONN_SRVS];
+
+} tBTA_DM_CONNECTED_SRVCS;
+
+typedef struct {
+#define BTA_DM_PM_SNIFF_TIMER_IDX 0
+#define BTA_DM_PM_PARK_TIMER_IDX 1
+#define BTA_DM_PM_SUSPEND_TIMER_IDX 2
+#define BTA_DM_PM_MODE_TIMER_MAX 3
+ /*
+ * Keep three different timers for PARK, SNIFF and SUSPEND if TBFC is
+ * supported.
+ */
+ alarm_t* timer[BTA_DM_PM_MODE_TIMER_MAX];
+
+ uint8_t srvc_id[BTA_DM_PM_MODE_TIMER_MAX];
+ uint8_t pm_action[BTA_DM_PM_MODE_TIMER_MAX];
+ uint8_t active; /* number of active timer */
+
+ BD_ADDR peer_bdaddr;
+ bool in_use;
+} tBTA_PM_TIMER;
+
+extern tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+#define BTA_DM_NUM_PM_TIMER 7
+
+/* DM control block */
+typedef struct {
+ bool is_bta_dm_active;
+ tBTA_DM_ACTIVE_LINK device_list;
+ tBTA_DM_SEC_CBACK* p_sec_cback;
+ tBTA_BLE_ENERGY_INFO_CBACK* p_energy_info_cback;
+ uint16_t state;
+ bool disabling;
+ alarm_t* disable_timer;
+ uint32_t wbt_sdp_handle; /* WIDCOMM Extensions SDP record handle */
+ uint8_t wbt_scn; /* WIDCOMM Extensions SCN */
+ uint8_t num_master_only;
+ uint8_t pm_id;
+ tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER];
+ uint32_t
+ role_policy_mask; /* the bits set indicates the modules that wants to
+ remove role switch from the default link policy */
+ uint16_t cur_policy; /* current default link policy */
+ uint16_t rs_event; /* the event waiting for role switch */
+ uint8_t cur_av_count; /* current AV connecions */
+ bool disable_pair_mode; /* disable pair mode or not */
+ bool conn_paired_only; /* allow connectable to paired device only or not */
+ tBTA_DM_API_SEARCH search_msg;
+ uint16_t page_scan_interval;
+ uint16_t page_scan_window;
+ uint16_t inquiry_scan_interval;
+ uint16_t inquiry_scan_window;
+
+ /* Storage for pin code request parameters */
+ BD_ADDR pin_bd_addr;
+ DEV_CLASS pin_dev_class;
+ tBTA_DM_SEC_EVT pin_evt;
+ uint32_t num_val; /* the numeric value for comparison. If just_works, do not
+ show this number to UI */
+ bool just_works; /* true, if "Just Works" association model */
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ /* store UUID list for EIR */
+ uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+#if (BTA_EIR_SERVER_NUM_CUSTOM_UUID > 0)
+ tBT_UUID custom_uuid[BTA_EIR_SERVER_NUM_CUSTOM_UUID];
+#endif
+
+#endif
+
+ tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback;
+ alarm_t* switch_delay_timer;
+
+} tBTA_DM_CB;
+
+/* DM search control block */
+typedef struct {
+ tBTA_DM_SEARCH_CBACK* p_search_cback;
+ tBTM_INQ_INFO* p_btm_inq_info;
+ tBTA_SERVICE_MASK services;
+ tBTA_SERVICE_MASK services_to_search;
+ tBTA_SERVICE_MASK services_found;
+ tSDP_DISCOVERY_DB* p_sdp_db;
+ uint16_t state;
+ BD_ADDR peer_bdaddr;
+ bool name_discover_done;
+ BD_NAME peer_name;
+ alarm_t* search_timer;
+ uint8_t service_index;
+ tBTA_DM_MSG* p_search_queue; /* search or discover commands during search
+ cancel stored here */
+ bool wait_disc;
+ bool sdp_results;
+ tSDP_UUID uuid;
+ uint8_t peer_scn;
+ bool sdp_search;
+ bool cancel_pending; /* inquiry cancel is pending */
+ tBTA_TRANSPORT transport;
+ tBTA_DM_SEARCH_CBACK* p_scan_cback;
+ tBTA_GATTC_IF client_if;
+ uint8_t num_uuid;
+ tBT_UUID* p_srvc_uuid;
+ uint8_t uuid_to_search;
+ bool gatt_disc_active;
+ uint16_t conn_id;
+ uint8_t* p_ble_rawdata;
+ uint32_t ble_raw_size;
+ uint32_t ble_raw_used;
+ alarm_t* gatt_close_timer; /* GATT channel close delay timer */
+ BD_ADDR pending_close_bda; /* pending GATT channel remote device address */
+
+} tBTA_DM_SEARCH_CB;
+
+/* DI control block */
+typedef struct {
+ tSDP_DISCOVERY_DB* p_di_db; /* pointer to the DI discovery database */
+ uint8_t di_num; /* total local DI record number */
+ uint32_t di_handle[BTA_DI_NUM_MAX]; /* local DI record handle, the first one
+ is primary record */
+} tBTA_DM_DI_CB;
+
+/* DM search state */
+enum {
+
+ BTA_DM_SEARCH_IDLE,
+ BTA_DM_SEARCH_ACTIVE,
+ BTA_DM_SEARCH_CANCELLING,
+ BTA_DM_DISCOVER_ACTIVE
+
+};
+
+typedef struct {
+ DEV_CLASS dev_class; /* local device class */
+ uint16_t
+ policy_settings; /* link policy setting hold, sniff, park, MS switch */
+ uint16_t page_timeout; /* timeout for page in slots */
+ uint16_t link_timeout; /* link supervision timeout in slots */
+ bool avoid_scatter; /* true to avoid scatternet when av is streaming (be the
+ master) */
+
+} tBTA_DM_CFG;
+
+extern const uint32_t bta_service_id_to_btm_srv_id_lkup_tbl[];
+
+typedef struct {
+ uint8_t id;
+ uint8_t app_id;
+ uint8_t cfg;
+
+} tBTA_DM_RM;
+
+extern tBTA_DM_CFG* p_bta_dm_cfg;
+extern tBTA_DM_RM* p_bta_dm_rm_cfg;
+
+typedef struct {
+ uint8_t id;
+ uint8_t app_id;
+ uint8_t spec_idx; /* index of spec table to use */
+
+} tBTA_DM_PM_CFG;
+
+typedef struct {
+ tBTA_DM_PM_ACTION power_mode;
+ uint16_t timeout;
+
+} tBTA_DM_PM_ACTN;
+
+typedef struct {
+ uint8_t allow_mask; /* mask of sniff/hold/park modes to allow */
+#if (BTM_SSR_INCLUDED == TRUE)
+ uint8_t ssr; /* set SSR on conn open/unpark */
+#endif
+ tBTA_DM_PM_ACTN actn_tbl[BTA_DM_PM_NUM_EVTS][2];
+
+} tBTA_DM_PM_SPEC;
+
+typedef struct {
+ uint16_t max_lat;
+ uint16_t min_rmt_to;
+ uint16_t min_loc_to;
+} tBTA_DM_SSR_SPEC;
+
+typedef struct {
+ uint16_t manufacturer;
+ uint16_t lmp_sub_version;
+ uint8_t lmp_version;
+} tBTA_DM_LMP_VER_INFO;
+
+extern const uint16_t bta_service_id_to_uuid_lkup_tbl[];
+
+extern tBTA_DM_PM_CFG* p_bta_dm_pm_cfg;
+extern tBTA_DM_PM_SPEC* p_bta_dm_pm_spec;
+extern tBTM_PM_PWR_MD* p_bta_dm_pm_md;
+#if (BTM_SSR_INCLUDED == TRUE)
+extern tBTA_DM_SSR_SPEC* p_bta_dm_ssr_spec;
+#endif
+
+/* update dynamic BRCM Aware EIR data */
+extern const tBTA_DM_EIR_CONF bta_dm_eir_cfg;
+extern tBTA_DM_EIR_CONF* p_bta_dm_eir_cfg;
+
+/* DM control block */
+extern tBTA_DM_CB bta_dm_cb;
+
+/* DM search control block */
+extern tBTA_DM_SEARCH_CB bta_dm_search_cb;
+
+/* DI control block */
+extern tBTA_DM_DI_CB bta_dm_di_cb;
+
+extern bool bta_dm_sm_execute(BT_HDR* p_msg);
+extern void bta_dm_sm_disable(void);
+extern bool bta_dm_search_sm_execute(BT_HDR* p_msg);
+extern void bta_dm_search_sm_disable(void);
+
+extern void bta_dm_enable(tBTA_DM_MSG* p_data);
+extern void bta_dm_disable(tBTA_DM_MSG* p_data);
+extern void bta_dm_init_cb(void);
+extern void bta_dm_set_dev_name(tBTA_DM_MSG* p_data);
+extern void bta_dm_set_visibility(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_set_scan_config(tBTA_DM_MSG* p_data);
+extern void bta_dm_vendor_spec_command(tBTA_DM_MSG* p_data);
+extern void bta_dm_bond(tBTA_DM_MSG* p_data);
+extern void bta_dm_bond_cancel(tBTA_DM_MSG* p_data);
+extern void bta_dm_pin_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_acl_change(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_remove_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_close_acl(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data);
+extern void bta_dm_pm_timer(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_ampkey(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_add_blekey(tBTA_DM_MSG* p_data);
+extern void bta_dm_add_ble_device(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_passkey_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_confirm_reply(tBTA_DM_MSG* p_data);
+extern void bta_dm_security_grant(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_bg_conn_type(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_conn_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_conn_scan_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_close_gatt_conn(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_observe(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_update_conn_params(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_config_local_privacy(tBTA_DM_MSG* p_data);
+extern void bta_dm_ble_set_adv_params(uint16_t adv_int_min,
+ uint16_t adv_int_max,
+ tBLE_BD_ADDR* p_dir_bda);
+
+extern void bta_dm_ble_set_data_length(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_ble_get_energy_info(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_set_encryption(tBTA_DM_MSG* p_data);
+extern void bta_dm_confirm(tBTA_DM_MSG* p_data);
+extern void bta_dm_loc_oob(tBTA_DM_MSG* p_data);
+extern void bta_dm_ci_io_req_act(tBTA_DM_MSG* p_data);
+extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_init_pm(void);
+extern void bta_dm_disable_pm(void);
+
+extern uint8_t bta_dm_get_av_count(void);
+extern void bta_dm_search_start(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel(tBTA_DM_MSG* p_data);
+extern void bta_dm_discover(tBTA_DM_MSG* p_data);
+extern void bta_dm_di_disc(tBTA_DM_MSG* p_data);
+extern void bta_dm_inq_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_rmt_name(tBTA_DM_MSG* p_data);
+extern void bta_dm_sdp_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_free_sdp_db(tBTA_DM_MSG* p_data);
+extern void bta_dm_disc_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_result(tBTA_DM_MSG* p_data);
+extern void bta_dm_discovery_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_queue_search(tBTA_DM_MSG* p_data);
+extern void bta_dm_queue_disc(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_clear_queue(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_notify(tBTA_DM_MSG* p_data);
+extern void bta_dm_search_cancel_transac_cmpl(tBTA_DM_MSG* p_data);
+extern void bta_dm_disc_rmt_name(tBTA_DM_MSG* p_data);
+extern tBTA_DM_PEER_DEVICE* bta_dm_find_peer_device(const BD_ADDR peer_addr);
+
+void bta_dm_eir_update_uuid(uint16_t uuid16, bool adding);
+
+extern void bta_dm_enable_test_mode(tBTA_DM_MSG* p_data);
+extern void bta_dm_disable_test_mode(tBTA_DM_MSG* p_data);
+extern void bta_dm_execute_callback(tBTA_DM_MSG* p_data);
+
+extern void bta_dm_remove_all_acl(tBTA_DM_MSG* p_data);
+#endif /* BTA_DM_INT_H */
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_main.cc b/mtkbt/code/bt/bta/dm/bta_dm_main.cc
new file mode 100755
index 0000000..d91eaba
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_main.cc
@@ -0,0 +1,343 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA device manager.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_DM_CB bta_dm_cb;
+tBTA_DM_SEARCH_CB bta_dm_search_cb;
+tBTA_DM_DI_CB bta_dm_di_cb;
+
+#define BTA_DM_NUM_ACTIONS (BTA_DM_MAX_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_DM_ACTION)(tBTA_DM_MSG* p_data);
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_action[] = {
+
+ /* device manager local device API events */
+ bta_dm_enable, /* 0 BTA_DM_API_ENABLE_EVT */
+ bta_dm_disable, /* 1 BTA_DM_API_DISABLE_EVT */
+ bta_dm_set_dev_name, /* 2 BTA_DM_API_SET_NAME_EVT */
+ bta_dm_set_visibility, /* 3 BTA_DM_API_SET_VISIBILITY_EVT */
+ bta_dm_acl_change, /* 8 BTA_DM_ACL_CHANGE_EVT */
+ bta_dm_add_device, /* 9 BTA_DM_API_ADD_DEVICE_EVT */
+ bta_dm_close_acl, /* 10 BTA_DM_API_ADD_DEVICE_EVT */
+
+ /* security API events */
+ bta_dm_bond, /* 11 BTA_DM_API_BOND_EVT */
+ bta_dm_bond_cancel, /* 12 BTA_DM_API_BOND_CANCEL_EVT */
+ bta_dm_pin_reply, /* 13 BTA_DM_API_PIN_REPLY_EVT */
+
+ /* power manger events */
+ bta_dm_pm_btm_status, /* 16 BTA_DM_PM_BTM_STATUS_EVT */
+ bta_dm_pm_timer, /* 17 BTA_DM_PM_TIMER_EVT*/
+
+ /* simple pairing events */
+ bta_dm_confirm, /* 18 BTA_DM_API_CONFIRM_EVT */
+
+ bta_dm_set_encryption, /* BTA_DM_API_SET_ENCRYPTION_EVT */
+
+ /* out of band pairing events */
+ bta_dm_loc_oob, /* 20 BTA_DM_API_LOC_OOB_EVT */
+ bta_dm_ci_io_req_act, /* 21 BTA_DM_CI_IO_REQ_EVT */
+ bta_dm_ci_rmt_oob_act, /* 22 BTA_DM_CI_RMT_OOB_EVT */
+
+ bta_dm_add_blekey, /* BTA_DM_API_ADD_BLEKEY_EVT */
+ bta_dm_add_ble_device, /* BTA_DM_API_ADD_BLEDEVICE_EVT */
+ bta_dm_ble_passkey_reply, /* BTA_DM_API_BLE_PASSKEY_REPLY_EVT */
+ bta_dm_ble_confirm_reply, /* BTA_DM_API_BLE_CONFIRM_REPLY_EVT */
+ bta_dm_security_grant, bta_dm_ble_set_bg_conn_type,
+ bta_dm_ble_set_conn_params, /* BTA_DM_API_BLE_CONN_PARAM_EVT */
+ bta_dm_ble_set_conn_scan_params, /* BTA_DM_API_BLE_CONN_SCAN_PARAM_EVT */
+ bta_dm_ble_observe,
+ bta_dm_ble_update_conn_params, /* BTA_DM_API_UPDATE_CONN_PARAM_EVT */
+#if (BLE_PRIVACY_SPT == TRUE)
+ bta_dm_ble_config_local_privacy, /* BTA_DM_API_LOCAL_PRIVACY_EVT */
+#endif
+ bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */
+ bta_dm_ble_get_energy_info, /* BTA_DM_API_BLE_ENERGY_INFO_EVT */
+
+ bta_dm_enable_test_mode, /* BTA_DM_API_ENABLE_TEST_MODE_EVT */
+ bta_dm_disable_test_mode, /* BTA_DM_API_DISABLE_TEST_MODE_EVT */
+ bta_dm_execute_callback, /* BTA_DM_API_EXECUTE_CBACK_EVT */
+
+ bta_dm_remove_all_acl, /* BTA_DM_API_REMOVE_ALL_ACL_EVT */
+ bta_dm_remove_device, /* BTA_DM_API_REMOVE_DEVICE_EVT */
+};
+
+/* state machine action enumeration list */
+enum {
+ BTA_DM_API_SEARCH, /* 0 bta_dm_search_start */
+ BTA_DM_API_SEARCH_CANCEL, /* 1 bta_dm_search_cancel */
+ BTA_DM_API_DISCOVER, /* 2 bta_dm_discover */
+ BTA_DM_INQUIRY_CMPL, /* 3 bta_dm_inq_cmpl */
+ BTA_DM_REMT_NAME, /* 4 bta_dm_rmt_name */
+ BTA_DM_SDP_RESULT, /* 5 bta_dm_sdp_result */
+ BTA_DM_SEARCH_CMPL, /* 6 bta_dm_search_cmpl*/
+ BTA_DM_FREE_SDP_DB, /* 7 bta_dm_free_sdp_db */
+ BTA_DM_DISC_RESULT, /* 8 bta_dm_disc_result */
+ BTA_DM_SEARCH_RESULT, /* 9 bta_dm_search_result */
+ BTA_DM_QUEUE_SEARCH, /* 10 bta_dm_queue_search */
+ BTA_DM_QUEUE_DISC, /* 11 bta_dm_queue_disc */
+ BTA_DM_SEARCH_CLEAR_QUEUE, /* 12 bta_dm_search_clear_queue */
+ BTA_DM_SEARCH_CANCEL_CMPL, /* 13 bta_dm_search_cancel_cmpl */
+ BTA_DM_SEARCH_CANCEL_NOTIFY, /* 14 bta_dm_search_cancel_notify */
+ BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL, /* 15 bta_dm_search_cancel_transac_cmpl */
+ BTA_DM_DISC_RMT_NAME, /* 16 bta_dm_disc_rmt_name */
+ BTA_DM_API_DI_DISCOVER, /* 17 bta_dm_di_disc */
+ BTA_DM_CLOSE_GATT_CONN, /* 18 bta_dm_close_gatt_conn */
+ BTA_DM_SEARCH_NUM_ACTIONS /* 19 */
+};
+
+/* action function list */
+const tBTA_DM_ACTION bta_dm_search_action[] = {
+
+ bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */
+ bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */
+ bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */
+ bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */
+ bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */
+ bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */
+ bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */
+ bta_dm_free_sdp_db, /* 7 BTA_DM_FREE_SDP_DB */
+ bta_dm_disc_result, /* 8 BTA_DM_DISC_RESULT */
+ bta_dm_search_result, /* 9 BTA_DM_SEARCH_RESULT */
+ bta_dm_queue_search, /* 10 BTA_DM_QUEUE_SEARCH */
+ bta_dm_queue_disc, /* 11 BTA_DM_QUEUE_DISC */
+ bta_dm_search_clear_queue, /* 12 BTA_DM_SEARCH_CLEAR_QUEUE */
+ bta_dm_search_cancel_cmpl, /* 13 BTA_DM_SEARCH_CANCEL_CMPL */
+ bta_dm_search_cancel_notify, /* 14 BTA_DM_SEARCH_CANCEL_NOTIFY */
+ bta_dm_search_cancel_transac_cmpl, /* 15 BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL
+ */
+ bta_dm_disc_rmt_name, /* 16 BTA_DM_DISC_RMT_NAME */
+ bta_dm_di_disc, /* 17 BTA_DM_API_DI_DISCOVER */
+ bta_dm_close_gatt_conn};
+
+#define BTA_DM_SEARCH_IGNORE BTA_DM_SEARCH_NUM_ACTIONS
+/* state table information */
+#define BTA_DM_SEARCH_ACTIONS 2 /* number of actions */
+#define BTA_DM_SEARCH_NEXT_STATE 2 /* position of next state */
+#define BTA_DM_SEARCH_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for listen state */
+const uint8_t bta_dm_search_idle_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+ /* Event Action 1
+ Action 2 Next State */
+ /* API_SEARCH */ {BTA_DM_API_SEARCH, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* API_SEARCH_DISC */ {BTA_DM_API_DISCOVER, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* REMT_NAME_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* SDP_RESULT_EVT */ {BTA_DM_FREE_SDP_DB, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* DISCV_RES_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* API_DI_DISCOVER_EVT */ {BTA_DM_API_DI_DISCOVER, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* DISC_CLOSE_TOUT_EVT */
+ {BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IDLE}};
+const uint8_t bta_dm_search_search_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+ /* Event Action 1
+ Action 2 Next State */
+ /* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* API_SEARCH_CANCEL */ {BTA_DM_API_SEARCH_CANCEL, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_CANCELLING},
+ /* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* INQUIRY_CMPL */ {BTA_DM_INQUIRY_CMPL, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* REMT_NAME_EVT */ {BTA_DM_REMT_NAME, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* DISCV_RES_EVT */ {BTA_DM_SEARCH_RESULT, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_ACTIVE},
+ /* DISC_CLOSE_TOUT_EVT */
+ {BTA_DM_CLOSE_GATT_CONN, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_ACTIVE}
+
+};
+
+const uint8_t
+ bta_dm_search_search_cancelling_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+ /* Event Action 1
+ Action 2 Next State */
+ /* API_SEARCH */ {BTA_DM_QUEUE_SEARCH, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_CANCELLING},
+ /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CLEAR_QUEUE,
+ BTA_DM_SEARCH_CANCEL_NOTIFY,
+ BTA_DM_SEARCH_CANCELLING},
+ /* API_SEARCH_DISC */ {BTA_DM_QUEUE_DISC, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_CANCELLING},
+ /* INQUIRY_CMPL */ {BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* REMT_NAME_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+ BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+ /* SDP_RESULT_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+ BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+ /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+ BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+ /* DISCV_RES_EVT */ {BTA_DM_SEARCH_CANCEL_TRANSAC_CMPL,
+ BTA_DM_SEARCH_CANCEL_CMPL, BTA_DM_SEARCH_IDLE},
+ /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_CANCELLING},
+ /* DISC_CLOSE_TOUT_EVT */
+ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_CANCELLING}};
+
+const uint8_t bta_dm_search_disc_active_st_table[][BTA_DM_SEARCH_NUM_COLS] = {
+
+ /* Event Action 1
+ Action 2 Next State */
+ /* API_SEARCH */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* API_SEARCH_CANCEL */ {BTA_DM_SEARCH_CANCEL_NOTIFY, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_CANCELLING},
+ /* API_SEARCH_DISC */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* INQUIRY_CMPL */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* REMT_NAME_EVT */ {BTA_DM_DISC_RMT_NAME, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* SDP_RESULT_EVT */ {BTA_DM_SDP_RESULT, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* SEARCH_CMPL_EVT */ {BTA_DM_SEARCH_CMPL, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_SEARCH_IDLE},
+ /* DISCV_RES_EVT */ {BTA_DM_DISC_RESULT, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* API_DI_DISCOVER_EVT */ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE,
+ BTA_DM_DISCOVER_ACTIVE},
+ /* DISC_CLOSE_TOUT_EVT */
+ {BTA_DM_SEARCH_IGNORE, BTA_DM_SEARCH_IGNORE, BTA_DM_DISCOVER_ACTIVE}};
+
+typedef const uint8_t (*tBTA_DM_ST_TBL)[BTA_DM_SEARCH_NUM_COLS];
+
+/* state table */
+const tBTA_DM_ST_TBL bta_dm_search_st_tbl[] = {
+ bta_dm_search_idle_st_table, bta_dm_search_search_active_st_table,
+ bta_dm_search_search_cancelling_st_table,
+ bta_dm_search_disc_active_st_table};
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sm_disable
+ *
+ * Description unregister BTA DM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sm_disable() { bta_sys_deregister(BTA_ID_DM); }
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sm_execute
+ *
+ * Description State machine event handling function for DM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_dm_sm_execute(BT_HDR* p_msg) {
+ uint16_t event = p_msg->event & 0x00ff;
+
+ APPL_TRACE_EVENT("bta_dm_sm_execute event:0x%x", event);
+
+ /* execute action functions */
+ if (event < BTA_DM_NUM_ACTIONS) {
+ (*bta_dm_action[event])((tBTA_DM_MSG*)p_msg);
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sm_search_disable
+ *
+ * Description unregister BTA SEARCH DM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_search_sm_disable() { bta_sys_deregister(BTA_ID_DM_SEARCH); }
+
+/*******************************************************************************
+ *
+ * Function bta_dm_search_sm_execute
+ *
+ * Description State machine event handling function for DM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_dm_search_sm_execute(BT_HDR* p_msg) {
+ tBTA_DM_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ APPL_TRACE_EVENT("bta_dm_search_sm_execute state:%d, event:0x%x",
+ bta_dm_search_cb.state, p_msg->event);
+
+ /* look up the state table for the current state */
+ state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state];
+
+ bta_dm_search_cb.state =
+ state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) {
+ action = state_table[p_msg->event & 0x00ff][i];
+ if (action != BTA_DM_SEARCH_IGNORE) {
+ (*bta_dm_search_action[action])((tBTA_DM_MSG*)p_msg);
+ } else {
+ break;
+ }
+ }
+ return true;
+}
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_pm.cc b/mtkbt/code/bt/bta/dm/bta_dm_pm.cc
new file mode 100755
index 0000000..403406d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_pm.cc
@@ -0,0 +1,1180 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the action functions for device manager state
+ * machine.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_dm_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_mode,
+ tBTA_DM_PM_REQ pm_req);
+static void bta_dm_pm_timer_cback(void* data);
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status,
+ uint16_t value, uint8_t hci_status);
+static bool bta_dm_pm_park(BD_ADDR peer_addr);
+static bool bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index);
+static bool bta_dm_pm_is_sco_active();
+static int bta_dm_get_sco_index();
+static void bta_dm_pm_hid_check(bool bScoActive);
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE* p_dev,
+ bool bDisable);
+static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer,
+ uint8_t timer_idx);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+#if (BTA_HH_INCLUDED == TRUE)
+#include "../hh/bta_hh_int.h"
+/* BTA_DM_PM_SSR1 will be dedicated for HH SSR setting entry, no other profile
+ * can use it */
+#define BTA_DM_PM_SSR_HH BTA_DM_PM_SSR1
+#endif
+static void bta_dm_pm_ssr(BD_ADDR peer_addr);
+#endif
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+tBTA_DM_CONNECTED_SRVCS bta_dm_conn_srvcs;
+
+/*******************************************************************************
+ *
+ * Function bta_dm_init_pm
+ *
+ * Description Initializes the BT low power manager
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_init_pm(void) {
+ memset(&bta_dm_conn_srvcs, 0x00, sizeof(bta_dm_conn_srvcs));
+
+ /* if there are no power manger entries, so not register */
+ if (p_bta_dm_pm_cfg[0].app_id != 0) {
+ bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)bta_dm_pm_cback);
+
+ BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,
+ bta_dm_pm_btm_cback);
+ }
+
+ /* Need to initialize all PM timer service IDs */
+ for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++)
+ bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_disable_pm
+ *
+ * Description Disable PM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_disable_pm(void) {
+ BTM_PmRegister(BTM_PM_DEREG, &bta_dm_cb.pm_id, NULL);
+
+ /*
+ * Deregister the PM callback from the system handling to prevent
+ * re-enabling the PM timers after this call if the callback is invoked.
+ */
+ bta_sys_pm_register((tBTA_SYS_CONN_CBACK*)NULL);
+
+ /* Need to stop all active timers. */
+ for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+ bta_dm_cb.pm_timer[i].pm_action[j] = BTA_DM_PM_NO_ACTION;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_get_av_count
+ *
+ * Description Get the number of connected AV
+ *
+ *
+ * Returns number of av connections
+ *
+ ******************************************************************************/
+uint8_t bta_dm_get_av_count(void) {
+ uint8_t count = 0;
+ for (int i = 0; i < bta_dm_conn_srvcs.count; i++) {
+ if (bta_dm_conn_srvcs.conn_srvc[i].id == BTA_ID_AV) ++count;
+ }
+ return count;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_stop_timer
+ *
+ * Description stop a PM timer
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer(BD_ADDR peer_addr) {
+ APPL_TRACE_DEBUG("%s: ", __func__);
+
+ for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ if (bta_dm_cb.pm_timer[i].in_use &&
+ !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+ for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+ /*
+ * TODO: For now, stopping the timer does not reset
+ * pm_action[j].
+ * The reason is because some of the internal logic that
+ * (re)assigns the pm_action[] values is taking into account
+ * the older value; e.g., see the pm_action[] assignment in
+ * function bta_dm_pm_start_timer().
+ * Such subtlety in the execution logic is error prone, and
+ * should be eliminiated in the future.
+ */
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pm_action_to_timer_idx
+ *
+ * Description convert power mode into timer index for each connected
+ * device
+ *
+ *
+ * Returns index of the power mode delay timer
+ *
+ ******************************************************************************/
+static uint8_t bta_pm_action_to_timer_idx(uint8_t pm_action) {
+ if (pm_action == BTA_DM_PM_SUSPEND)
+ return BTA_DM_PM_SUSPEND_TIMER_IDX;
+ else if (pm_action == BTA_DM_PM_PARK)
+ return BTA_DM_PM_PARK_TIMER_IDX;
+ else if ((pm_action & BTA_DM_PM_SNIFF) == BTA_DM_PM_SNIFF)
+ return BTA_DM_PM_SNIFF_TIMER_IDX;
+
+ /* Active, no preference, no action and retry */
+ return BTA_DM_PM_MODE_TIMER_MAX;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_stop_timer_by_mode
+ *
+ * Description stop a PM timer
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_mode(BD_ADDR peer_addr,
+ uint8_t power_mode) {
+ const uint8_t timer_idx = bta_pm_action_to_timer_idx(power_mode);
+ if (timer_idx == BTA_DM_PM_MODE_TIMER_MAX) return;
+
+ for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ if (bta_dm_cb.pm_timer[i].in_use &&
+ !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+ if (bta_dm_cb.pm_timer[i].srvc_id[timer_idx] != BTA_ID_MAX) {
+ bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], timer_idx);
+ /*
+ * TODO: Intentionally setting pm_action[timer_idx].
+ * This assignment should be eliminated in the future - see the
+ * pm_action[] related comment inside function
+ * bta_dm_pm_stop_timer().
+ */
+ bta_dm_cb.pm_timer[i].pm_action[timer_idx] = power_mode;
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_stop_timer_by_srvc_id
+ *
+ * Description stop all timer started by the service ID.
+ *
+ *
+ * Returns index of the power mode delay timer
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_srvc_id(BD_ADDR peer_addr,
+ uint8_t srvc_id) {
+ for (int i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ if (bta_dm_cb.pm_timer[i].in_use &&
+ !bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr)) {
+ for (int j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ if (bta_dm_cb.pm_timer[i].srvc_id[j] == srvc_id) {
+ bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], j);
+ bta_dm_cb.pm_timer[i].pm_action[j] = BTA_DM_PM_NO_ACTION;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_start_timer
+ *
+ * Description start a PM timer
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_start_timer(tBTA_PM_TIMER* p_timer, uint8_t timer_idx,
+ period_ms_t timeout_ms, uint8_t srvc_id,
+ uint8_t pm_action) {
+ p_timer->in_use = true;
+
+ if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX) p_timer->active++;
+
+ if (p_timer->pm_action[timer_idx] < pm_action)
+ p_timer->pm_action[timer_idx] = pm_action;
+
+ p_timer->srvc_id[timer_idx] = srvc_id;
+
+ alarm_set_on_queue(p_timer->timer[timer_idx], timeout_ms,
+ bta_dm_pm_timer_cback, p_timer->timer[timer_idx],
+ btu_bta_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_stop_timer_by_index
+ *
+ * Description stop a PM timer
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_stop_timer_by_index(tBTA_PM_TIMER* p_timer,
+ uint8_t timer_idx) {
+ if ((p_timer == NULL) || (timer_idx >= BTA_DM_PM_MODE_TIMER_MAX)) return;
+
+ if (p_timer->srvc_id[timer_idx] == BTA_ID_MAX)
+ return; /* The timer was not scheduled */
+
+ CHECK(p_timer->in_use && (p_timer->active > 0));
+
+ alarm_cancel(p_timer->timer[timer_idx]);
+ p_timer->srvc_id[timer_idx] = BTA_ID_MAX;
+ /* NOTE: pm_action[timer_idx] intentionally not reset */
+
+ p_timer->active--;
+ if (p_timer->active == 0) p_timer->in_use = false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_cback
+ *
+ * Description Conn change callback from sys for low power management
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr) {
+ uint8_t i, j;
+ uint8_t* p = NULL;
+ tBTA_DM_PEER_DEVICE* p_dev;
+ tBTA_DM_PM_REQ pm_req = BTA_DM_PM_NEW_REQ;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ int index = BTA_DM_PM_SSR0;
+#endif
+
+ APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id,
+ app_id);
+
+ p_dev = bta_dm_find_peer_device(peer_addr);
+
+ /* find if there is an power mode entry for the service */
+ for (i = 1; i <= p_bta_dm_pm_cfg[0].app_id; i++) {
+ if ((p_bta_dm_pm_cfg[i].id == id) &&
+ ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID) ||
+ (p_bta_dm_pm_cfg[i].app_id == app_id)))
+ break;
+ }
+
+ /* if no entries are there for the app_id and subsystem in p_bta_dm_pm_spec*/
+ if (i > p_bta_dm_pm_cfg[0].app_id) return;
+
+ bta_dm_pm_stop_timer_by_srvc_id(peer_addr, id);
+/*p_dev = bta_dm_find_peer_device(peer_addr);*/
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ /* set SSR parameters on SYS CONN OPEN */
+ if ((BTA_SYS_CONN_OPEN == status) && p_dev &&
+ (p_dev->info & BTA_DM_DI_USE_SSR)) {
+ index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr;
+ }
+#endif
+
+ /* if no action for the event */
+ if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx]
+ .actn_tbl[status][0]
+ .power_mode == BTA_DM_PM_NO_ACTION) {
+#if (BTM_SSR_INCLUDED == TRUE)
+ if (BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */
+#endif
+ return;
+ }
+
+ for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+ /* check if an entry already present */
+ if ((bta_dm_conn_srvcs.conn_srvc[j].id == id) &&
+ (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id) &&
+ !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) {
+ bta_dm_conn_srvcs.conn_srvc[j].new_request = true;
+ break;
+ }
+ }
+
+ /* if subsystem has no more preference on the power mode remove
+ the cb */
+ if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx]
+ .actn_tbl[status][0]
+ .power_mode == BTA_DM_PM_NO_PREF) {
+ if (j != bta_dm_conn_srvcs.count) {
+ bta_dm_conn_srvcs.count--;
+
+ for (; j < bta_dm_conn_srvcs.count; j++) {
+ memcpy(&bta_dm_conn_srvcs.conn_srvc[j],
+ &bta_dm_conn_srvcs.conn_srvc[j + 1],
+ sizeof(bta_dm_conn_srvcs.conn_srvc[j]));
+ }
+ } else {
+ APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs");
+ return;
+ }
+ } else if (j == bta_dm_conn_srvcs.count) {
+ /* check if we have more connected service that cbs */
+ if (bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS) {
+ APPL_TRACE_WARNING("bta_dm_act no more connected service cbs");
+ return;
+ }
+
+ /* fill in a new cb */
+ bta_dm_conn_srvcs.conn_srvc[j].id = id;
+ bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id;
+ bta_dm_conn_srvcs.conn_srvc[j].new_request = true;
+ bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr);
+
+ APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d", id, app_id);
+
+ bta_dm_conn_srvcs.count++;
+ bta_dm_conn_srvcs.conn_srvc[j].state = status;
+ } else {
+ /* no service is added or removed. only updating status. */
+ bta_dm_conn_srvcs.conn_srvc[j].state = status;
+ }
+
+ /* stop timer */
+ bta_dm_pm_stop_timer(peer_addr);
+ if (bta_dm_conn_srvcs.count > 0) {
+ pm_req = BTA_DM_PM_RESTART;
+ APPL_TRACE_DEBUG(
+ "%s bta_dm_pm_stop_timer for current service, restart other "
+ "service timers: count = %d",
+ __func__, bta_dm_conn_srvcs.count);
+ }
+
+ if (p_dev) {
+ p_dev->pm_mode_attempted = 0;
+ p_dev->pm_mode_failed = 0;
+ }
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ if (p_bta_dm_ssr_spec[index].max_lat
+#if (BTA_HH_INCLUDED == TRUE)
+ || index == BTA_DM_PM_SSR_HH
+#endif
+ ) {
+ bta_dm_pm_ssr(peer_addr);
+ } else {
+ if (((NULL != (p = BTM_ReadLocalFeatures())) &&
+ HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ (!interop_mtk_match_addr_name(INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING, (const bt_bdaddr_t *)peer_addr)) &&
+#endif
+ ((NULL != (p = BTM_ReadRemoteFeatures(peer_addr))) &&
+ HCI_SNIFF_SUB_RATE_SUPPORTED(p)) &&
+ (index == BTA_DM_PM_SSR0)) {
+ if (status == BTA_SYS_SCO_OPEN) {
+ APPL_TRACE_DEBUG("%s: SCO inactive, reset SSR to zero", __func__);
+ BTM_SetSsrParams(peer_addr, 0, 0, 0);
+ } else if (status == BTA_SYS_SCO_CLOSE) {
+ APPL_TRACE_DEBUG("%s: SCO active, back to old SSR", __func__);
+ bta_dm_pm_ssr(peer_addr);
+ }
+ }
+ }
+#endif
+
+ bta_dm_pm_set_mode(peer_addr, BTA_DM_PM_NO_ACTION, pm_req);
+
+ /* perform the HID link workaround if needed
+ ** 1. If SCO up/down event is received OR
+ ** 2. If HID connection open is received and SCO is already active.
+ ** This will handle the case where HID connects when SCO already active
+ */
+ if (BTM_IsDeviceUp() &&
+ (((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ||
+ ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) &&
+ bta_dm_pm_is_sco_active()))) {
+ bool bScoActive;
+ if (status == BTA_SYS_CONN_OPEN)
+ bScoActive = true;
+ else
+ bScoActive = (status == BTA_SYS_SCO_OPEN);
+
+ bta_dm_pm_hid_check(bScoActive);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_set_mode
+ *
+ * Description Set the power mode for the device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bta_dm_pm_set_mode(BD_ADDR peer_addr, tBTA_DM_PM_ACTION pm_request,
+ tBTA_DM_PM_REQ pm_req) {
+ tBTA_DM_PM_ACTION pm_action = BTA_DM_PM_NO_ACTION;
+ period_ms_t timeout_ms = 0;
+ uint8_t i, j;
+ tBTA_DM_PM_ACTION failed_pm = 0;
+ tBTA_DM_PEER_DEVICE* p_peer_device = NULL;
+ tBTA_DM_PM_ACTION allowed_modes = 0;
+ tBTA_DM_PM_ACTION pref_modes = 0;
+ tBTA_DM_PM_CFG* p_pm_cfg;
+ tBTA_DM_PM_SPEC* p_pm_spec;
+ tBTA_DM_PM_ACTN *p_act0, *p_act1;
+ tBTA_DM_SRVCS* p_srvcs = NULL;
+ bool timer_started = false;
+ uint8_t timer_idx, available_timer = BTA_DM_PM_MODE_TIMER_MAX;
+ period_ms_t remaining_ms = 0;
+
+ if (!bta_dm_cb.device_list.count) return;
+
+ /* see if any attempt to put device in low power mode failed */
+ p_peer_device = bta_dm_find_peer_device(peer_addr);
+ /* if no peer device found return */
+ if (p_peer_device == NULL) return;
+
+ failed_pm = p_peer_device->pm_mode_failed;
+
+ for (i = 0; i < bta_dm_conn_srvcs.count; i++) {
+ p_srvcs = &bta_dm_conn_srvcs.conn_srvc[i];
+ if (!bdcmp(p_srvcs->peer_bdaddr, peer_addr)) {
+ /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+ for (j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
+ if ((p_bta_dm_pm_cfg[j].id == p_srvcs->id) &&
+ ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID) ||
+ (p_bta_dm_pm_cfg[j].app_id == p_srvcs->app_id)))
+ break;
+ }
+
+ p_pm_cfg = &p_bta_dm_pm_cfg[j];
+ p_pm_spec = &p_bta_dm_pm_spec[p_pm_cfg->spec_idx];
+ p_act0 = &p_pm_spec->actn_tbl[p_srvcs->state][0];
+ p_act1 = &p_pm_spec->actn_tbl[p_srvcs->state][1];
+
+ APPL_TRACE_DEBUG("bta_dm_pm_set_mode: srvcsid: %d, state: %d, j: %d",
+ p_srvcs->id, p_srvcs->state, j);
+ allowed_modes |= p_pm_spec->allow_mask;
+
+ /* PM actions are in the order of strictness */
+
+ /* first check if the first preference is ok */
+ if (!(failed_pm & p_act0->power_mode)) {
+ pref_modes |= p_act0->power_mode;
+
+ if (p_act0->power_mode >= pm_action) {
+ pm_action = p_act0->power_mode;
+
+ if (pm_req != BTA_DM_PM_NEW_REQ || p_srvcs->new_request) {
+ p_srvcs->new_request = false;
+ timeout_ms = p_act0->timeout;
+ }
+ }
+ }
+ /* if first preference has already failed, try second preference */
+ else if (!(failed_pm & p_act1->power_mode)) {
+ pref_modes |= p_act1->power_mode;
+
+ if (p_act1->power_mode > pm_action) {
+ pm_action = p_act1->power_mode;
+ timeout_ms = p_act1->timeout;
+ }
+ }
+ }
+ }
+
+ if (pm_action & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) {
+ /* some service don't like the mode */
+ if (!(allowed_modes & pm_action)) {
+ /* select the other mode if its allowed and preferred, otherwise 0 which
+ * is BTA_DM_PM_NO_ACTION */
+ pm_action =
+ (allowed_modes & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & pref_modes);
+
+ /* no timeout needed if no action is required */
+ if (pm_action == BTA_DM_PM_NO_ACTION) {
+ timeout_ms = 0;
+ }
+ }
+ }
+ /* if need to start a timer */
+ if ((pm_req != BTA_DM_PM_EXECUTE) && (timeout_ms > 0)) {
+ for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ if (bta_dm_cb.pm_timer[i].in_use &&
+ bdcmp(bta_dm_cb.pm_timer[i].peer_bdaddr, peer_addr) == 0) {
+ timer_idx = bta_pm_action_to_timer_idx(pm_action);
+ if (timer_idx != BTA_DM_PM_MODE_TIMER_MAX) {
+ remaining_ms =
+ alarm_get_remaining_ms(bta_dm_cb.pm_timer[i].timer[timer_idx]);
+ if (remaining_ms < timeout_ms) {
+ /* Cancel and restart the timer */
+ /*
+ * TODO: The value of pm_action[timer_idx] is
+ * conditionally updated between the two function
+ * calls below when the timer is restarted.
+ * This logic is error-prone and should be eliminated
+ * in the future.
+ */
+ bta_dm_pm_stop_timer_by_index(&bta_dm_cb.pm_timer[i], timer_idx);
+ bta_dm_pm_start_timer(&bta_dm_cb.pm_timer[i], timer_idx, timeout_ms,
+ p_srvcs->id, pm_action);
+ }
+ timer_started = true;
+ }
+ break;
+ } else if (!bta_dm_cb.pm_timer[i].in_use) {
+ APPL_TRACE_DEBUG("%s dm_pm_timer:%d, %d ms", __func__, i, timeout_ms);
+ if (available_timer == BTA_DM_PM_MODE_TIMER_MAX) available_timer = i;
+ }
+ }
+ /* new power mode for a new active connection */
+ if (!timer_started) {
+ if (available_timer != BTA_DM_PM_MODE_TIMER_MAX) {
+ bdcpy(bta_dm_cb.pm_timer[available_timer].peer_bdaddr, peer_addr);
+ timer_idx = bta_pm_action_to_timer_idx(pm_action);
+ if (timer_idx != BTA_DM_PM_MODE_TIMER_MAX) {
+ bta_dm_pm_start_timer(&bta_dm_cb.pm_timer[available_timer], timer_idx,
+ timeout_ms, p_srvcs->id, pm_action);
+ timer_started = true;
+ }
+ }
+ /* no more timers */
+ else {
+ APPL_TRACE_WARNING("bta_dm_act dm_pm_timer no more");
+ }
+ }
+ return;
+ }
+ /* if pending power mode timer expires, and currecnt link is in a
+ lower power mode than current profile requirement, igonre it */
+ if (pm_req == BTA_DM_PM_EXECUTE && pm_request < pm_action) {
+ APPL_TRACE_ERROR("Ignore the power mode request: %d", pm_request)
+ return;
+ }
+ if (pm_action == BTA_DM_PM_PARK) {
+ p_peer_device->pm_mode_attempted = BTA_DM_PM_PARK;
+ bta_dm_pm_park(peer_addr);
+ } else if (pm_action & BTA_DM_PM_SNIFF) {
+ /* dont initiate SNIFF, if link_policy has it disabled */
+ if (p_peer_device->link_policy & HCI_ENABLE_SNIFF_MODE) {
+ p_peer_device->pm_mode_attempted = BTA_DM_PM_SNIFF;
+ bta_dm_pm_sniff(p_peer_device, (uint8_t)(pm_action & 0x0F));
+ } else {
+ APPL_TRACE_DEBUG(
+ "bta_dm_pm_set_mode: Link policy disallows SNIFF, ignore request");
+ }
+ } else if (pm_action == BTA_DM_PM_ACTIVE) {
+ bta_dm_pm_active(peer_addr);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_ag_pm_park
+ *
+ * Description Switch to park mode.
+ *
+ *
+ * Returns true if park attempted, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_park(BD_ADDR peer_addr) {
+ tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+
+ /* if not in park mode, switch to park */
+ BTM_ReadPowerMode(peer_addr, &mode);
+
+ if (mode != BTM_PM_MD_PARK) {
+ BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr,
+ &p_bta_dm_pm_md[BTA_DM_PM_PARK_IDX]);
+ }
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_pm_sniff
+ *
+ * Description Switch to sniff mode.
+ *
+ *
+ * Returns true if sniff attempted, false otherwise.
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_sniff(tBTA_DM_PEER_DEVICE* p_peer_dev, uint8_t index) {
+ tBTM_PM_MODE mode = BTM_PM_STS_ACTIVE;
+ tBTM_PM_PWR_MD pwr_md;
+ tBTM_STATUS status;
+#if (BTM_SSR_INCLUDED == TRUE)
+ uint8_t* p_rem_feat = NULL;
+#endif
+
+ BTM_ReadPowerMode(p_peer_dev->peer_bdaddr, &mode);
+ p_rem_feat = BTM_ReadRemoteFeatures(p_peer_dev->peer_bdaddr);
+#if (BTM_SSR_INCLUDED == TRUE)
+ APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d, info:x%x", mode, index,
+ p_peer_dev->info);
+ if (mode != BTM_PM_MD_SNIFF ||
+ (HCI_SNIFF_SUB_RATE_SUPPORTED(BTM_ReadLocalFeatures()) && p_rem_feat &&
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ (!interop_mtk_match_addr_name(INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING, (const bt_bdaddr_t *)&p_peer_dev->peer_bdaddr)) &&
+#endif
+ HCI_SNIFF_SUB_RATE_SUPPORTED(p_rem_feat) &&
+ !(p_peer_dev->info & BTA_DM_DI_USE_SSR)))
+#else
+ APPL_TRACE_DEBUG("bta_dm_pm_sniff cur:%d, idx:%d", mode, index);
+ if (mode != BTM_PM_MD_SNIFF)
+#endif
+ {
+#if (BTM_SSR_INCLUDED == TRUE)
+ /* Dont initiate Sniff if controller has alreay accepted
+ * remote sniff params. This avoid sniff loop issue with
+ * some agrresive headsets who use sniff latencies more than
+ * DUT supported range of Sniff intervals.*/
+ if ((mode == BTM_PM_MD_SNIFF) && (p_peer_dev->info & BTA_DM_DI_ACP_SNIFF)) {
+ APPL_TRACE_DEBUG("%s: already in remote initiate sniff", __func__);
+ return true;
+ }
+#endif
+ /* if the current mode is not sniff, issue the sniff command.
+ * If sniff, but SSR is not used in this link, still issue the command */
+ memcpy(&pwr_md, &p_bta_dm_pm_md[index], sizeof(tBTM_PM_PWR_MD));
+ if (p_peer_dev->info & BTA_DM_DI_INT_SNIFF) {
+ pwr_md.mode |= BTM_PM_MD_FORCE;
+ }
+ status =
+ BTM_SetPowerMode(bta_dm_cb.pm_id, p_peer_dev->peer_bdaddr, &pwr_md);
+ if (status == BTM_CMD_STORED || status == BTM_CMD_STARTED) {
+ p_peer_dev->info &= ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF);
+ p_peer_dev->info |= BTA_DM_DI_SET_SNIFF;
+ } else if (status == BTM_SUCCESS) {
+ APPL_TRACE_DEBUG(
+ "bta_dm_pm_sniff BTM_SetPowerMode() returns BTM_SUCCESS");
+ p_peer_dev->info &=
+ ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+ } else /* error */
+ {
+ APPL_TRACE_ERROR(
+ "bta_dm_pm_sniff BTM_SetPowerMode() returns ERROR status=%d", status);
+ p_peer_dev->info &=
+ ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+ }
+ }
+ return true;
+}
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_ssr
+ *
+ * Description checks and sends SSR parameters
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+static void bta_dm_pm_ssr(BD_ADDR peer_addr) {
+ tBTA_DM_SSR_SPEC *p_spec, *p_spec_cur;
+ uint8_t i, j;
+ int ssr = BTA_DM_PM_SSR0;
+
+ /* go through the connected services */
+ for (i = 0; i < bta_dm_conn_srvcs.count; i++) {
+ if (!bdcmp(bta_dm_conn_srvcs.conn_srvc[i].peer_bdaddr, peer_addr)) {
+ /* p_bta_dm_pm_cfg[0].app_id is the number of entries */
+ for (j = 1; j <= p_bta_dm_pm_cfg[0].app_id; j++) {
+ /* find the associated p_bta_dm_pm_cfg */
+ if ((p_bta_dm_pm_cfg[j].id == bta_dm_conn_srvcs.conn_srvc[i].id) &&
+ ((p_bta_dm_pm_cfg[j].app_id == BTA_ALL_APP_ID) ||
+ (p_bta_dm_pm_cfg[j].app_id ==
+ bta_dm_conn_srvcs.conn_srvc[i].app_id))) {
+ APPL_TRACE_WARNING("bta_dm_pm_ssr conn_srvc id:%d, app_id:%d",
+ bta_dm_conn_srvcs.conn_srvc[i].id,
+ bta_dm_conn_srvcs.conn_srvc[i].app_id);
+ break;
+ }
+ }
+
+ /* find the ssr index with the smallest max latency. */
+ p_spec_cur =
+ &p_bta_dm_ssr_spec[p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr];
+ p_spec = &p_bta_dm_ssr_spec[ssr];
+
+#if (BTA_HH_INCLUDED == TRUE)
+ /* HH has the per connection SSR preference, already read the SSR params
+ * from BTA HH */
+ if (p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr ==
+ BTA_DM_PM_SSR_HH) {
+ if (bta_hh_read_ssr_param(peer_addr, &p_spec_cur->max_lat,
+ &p_spec_cur->min_rmt_to) == BTA_HH_ERR)
+ continue;
+ }
+#endif
+ if (p_spec_cur->max_lat < p_spec->max_lat ||
+ (ssr == BTA_DM_PM_SSR0 &&
+ p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr !=
+ BTA_DM_PM_SSR0)) {
+ ssr = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[j].spec_idx].ssr;
+ }
+ }
+ }
+
+ p_spec = &p_bta_dm_ssr_spec[ssr];
+ APPL_TRACE_WARNING("%s ssr:%d, lat:%d", __func__, ssr, p_spec->max_lat);
+
+ if (p_spec->max_lat) {
+ /* Avoid SSR reset on device which has SCO connected */
+ if (bta_dm_pm_is_sco_active()) {
+ int idx = bta_dm_get_sco_index();
+ if (idx != -1) {
+ if (bdcmp(bta_dm_conn_srvcs.conn_srvc[idx].peer_bdaddr, peer_addr) ==
+ 0) {
+ APPL_TRACE_WARNING("%s SCO is active on device, ignore SSR",
+ __func__);
+ return;
+ }
+ }
+ }
+
+ /* set the SSR parameters. */
+ BTM_SetSsrParams(peer_addr, p_spec->max_lat, p_spec->min_rmt_to,
+ p_spec->min_loc_to);
+ }
+}
+#endif
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_active
+ *
+ * Description Brings connection to active mode
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_pm_active(BD_ADDR peer_addr) {
+ tBTM_PM_PWR_MD pm;
+
+ memset((void*)&pm, 0, sizeof(pm));
+
+ /* switch to active mode */
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(bta_dm_cb.pm_id, peer_addr, &pm);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_btm_cback
+ *
+ * Description BTM power manager callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_btm_cback(BD_ADDR bd_addr, tBTM_PM_STATUS status,
+ uint16_t value, uint8_t hci_status) {
+ tBTA_DM_PM_BTM_STATUS* p_buf =
+ (tBTA_DM_PM_BTM_STATUS*)osi_malloc(sizeof(tBTA_DM_PM_BTM_STATUS));
+
+ p_buf->hdr.event = BTA_DM_PM_BTM_STATUS_EVT;
+ p_buf->status = status;
+ p_buf->value = value;
+ p_buf->hci_status = hci_status;
+ bdcpy(p_buf->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_timer_cback
+ *
+ * Description Power management timer callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_dm_pm_timer_cback(void* data) {
+ uint8_t i, j;
+ alarm_t* alarm = (alarm_t*)data;
+
+ for (i = 0; i < BTA_DM_NUM_PM_TIMER; i++) {
+ APPL_TRACE_DEBUG("dm_pm_timer[%d] in use? %d", i,
+ bta_dm_cb.pm_timer[i].in_use);
+ if (bta_dm_cb.pm_timer[i].in_use) {
+ for (j = 0; j < BTA_DM_PM_MODE_TIMER_MAX; j++) {
+ if (bta_dm_cb.pm_timer[i].timer[j] == alarm) {
+ bta_dm_cb.pm_timer[i].active--;
+ bta_dm_cb.pm_timer[i].srvc_id[j] = BTA_ID_MAX;
+ APPL_TRACE_DEBUG("dm_pm_timer[%d] expires, timer_idx=%d", i, j);
+ break;
+ }
+ }
+ if (bta_dm_cb.pm_timer[i].active == 0)
+ bta_dm_cb.pm_timer[i].in_use = false;
+ if (j < BTA_DM_PM_MODE_TIMER_MAX) break;
+ }
+ }
+
+ /* no more timers */
+ if (i == BTA_DM_NUM_PM_TIMER) return;
+
+ tBTA_DM_PM_TIMER* p_buf =
+ (tBTA_DM_PM_TIMER*)osi_malloc(sizeof(tBTA_DM_PM_TIMER));
+ p_buf->hdr.event = BTA_DM_PM_TIMER_EVT;
+ p_buf->pm_request = bta_dm_cb.pm_timer[i].pm_action[j];
+ bdcpy(p_buf->bd_addr, bta_dm_cb.pm_timer[i].peer_bdaddr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_btm_status
+ *
+ * Description Process pm status event from btm
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_pm_btm_status(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_DEBUG("%s status: %d", __func__, p_data->pm_status.status);
+
+ tBTA_DM_PEER_DEVICE* p_dev =
+ bta_dm_find_peer_device(p_data->pm_status.bd_addr);
+ if (NULL == p_dev) return;
+
+ tBTA_DM_DEV_INFO info = p_dev->info;
+ /* check new mode */
+ switch (p_data->pm_status.status) {
+ case BTM_PM_STS_ACTIVE:
+ /* if our sniff or park attempt failed
+ we should not try it again*/
+ if (p_data->pm_status.hci_status != 0) {
+ APPL_TRACE_ERROR("%s hci_status=%d", __func__,
+ p_data->pm_status.hci_status);
+ p_dev->info &=
+ ~(BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF | BTA_DM_DI_SET_SNIFF);
+
+ if (p_dev->pm_mode_attempted & (BTA_DM_PM_PARK | BTA_DM_PM_SNIFF)) {
+ p_dev->pm_mode_failed |=
+ ((BTA_DM_PM_PARK | BTA_DM_PM_SNIFF) & p_dev->pm_mode_attempted);
+ bta_dm_pm_stop_timer_by_mode(p_data->pm_status.bd_addr,
+ p_dev->pm_mode_attempted);
+ bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
+ BTA_DM_PM_RESTART);
+ }
+ } else {
+#if (BTM_SSR_INCLUDED == TRUE)
+ if (p_dev->prev_low) {
+ /* need to send the SSR paramaters to controller again */
+ bta_dm_pm_ssr(p_dev->peer_bdaddr);
+ }
+ p_dev->prev_low = BTM_PM_STS_ACTIVE;
+#endif
+ /* link to active mode, need to restart the timer for next low power
+ * mode if needed */
+ bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+ bta_dm_pm_set_mode(p_data->pm_status.bd_addr, BTA_DM_PM_NO_ACTION,
+ BTA_DM_PM_RESTART);
+ }
+ break;
+
+#if (BTM_SSR_INCLUDED == TRUE)
+ case BTM_PM_STS_PARK:
+ case BTM_PM_STS_HOLD:
+ /* save the previous low power mode - for SSR.
+ * SSR parameters are sent to controller on "conn open".
+ * the numbers stay good until park/hold/detach */
+ if (p_dev->info & BTA_DM_DI_USE_SSR)
+ p_dev->prev_low = p_data->pm_status.status;
+ break;
+
+ case BTM_PM_STS_SSR:
+ if (p_data->pm_status.value)
+ p_dev->info |= BTA_DM_DI_USE_SSR;
+ else
+ p_dev->info &= ~BTA_DM_DI_USE_SSR;
+ break;
+#endif
+ case BTM_PM_STS_SNIFF:
+ if (p_data->pm_status.hci_status == 0) {
+ /* Stop PM timer now if already active for
+ * particular device since link is already
+ * put in sniff mode by remote device, and
+ * PM timer sole purpose is to put the link
+ * in sniff mode from host side.
+ */
+ bta_dm_pm_stop_timer(p_data->pm_status.bd_addr);
+ } else {
+ p_dev->info &=
+ ~(BTA_DM_DI_SET_SNIFF | BTA_DM_DI_INT_SNIFF | BTA_DM_DI_ACP_SNIFF);
+ if (info & BTA_DM_DI_SET_SNIFF)
+ p_dev->info |= BTA_DM_DI_INT_SNIFF;
+ else
+ p_dev->info |= BTA_DM_DI_ACP_SNIFF;
+ }
+ break;
+
+ case BTM_PM_STS_ERROR:
+ p_dev->info &= ~BTA_DM_DI_SET_SNIFF;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_timer
+ *
+ * Description Process pm timer event from btm
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_pm_timer(tBTA_DM_MSG* p_data) {
+ APPL_TRACE_EVENT("%s", __func__);
+ bta_dm_pm_set_mode(p_data->pm_timer.bd_addr, p_data->pm_timer.pm_request,
+ BTA_DM_PM_EXECUTE);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_find_peer_device
+ *
+ * Description Given an address, find the associated control block.
+ *
+ * Returns tBTA_DM_PEER_DEVICE
+ *
+ ******************************************************************************/
+tBTA_DM_PEER_DEVICE* bta_dm_find_peer_device(const BD_ADDR peer_addr) {
+ tBTA_DM_PEER_DEVICE* p_dev = NULL;
+
+ for (int i = 0; i < bta_dm_cb.device_list.count; i++) {
+ if (!bdcmp(bta_dm_cb.device_list.peer_device[i].peer_bdaddr, peer_addr)) {
+ p_dev = &bta_dm_cb.device_list.peer_device[i];
+ break;
+ }
+ }
+ return p_dev;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_is_sco_active
+ *
+ * Description Loop through connected services for HFP+State=SCO
+ *
+ * Returns bool. true if SCO active, else false
+ *
+ ******************************************************************************/
+static bool bta_dm_pm_is_sco_active() {
+ int j;
+ bool bScoActive = false;
+
+ for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+ /* check if an entry already present */
+ if ((bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG) &&
+ (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN)) {
+ bScoActive = true;
+ break;
+ }
+ }
+
+ APPL_TRACE_DEBUG("bta_dm_is_sco_active: SCO active: %d", bScoActive);
+ return bScoActive;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_get_sco_index
+ *
+ * Description Loop through connected services for HFP+State=SCO
+ *
+ * Returns index at which SCO is connected, in absence of SCO return -1
+ *
+ ******************************************************************************/
+static int bta_dm_get_sco_index() {
+ for (int j = 0; j < bta_dm_conn_srvcs.count; j++) {
+ /* check for SCO connected index */
+ if ((bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_AG) &&
+ (bta_dm_conn_srvcs.conn_srvc[j].state == BTA_SYS_SCO_OPEN)) {
+ return j;
+ }
+ }
+ return -1;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_hid_check
+ *
+ * Description Disables/Enables sniff in link policy based on SCO Up/Down
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void bta_dm_pm_hid_check(bool bScoActive) {
+ int j;
+
+ /* if HID is active, disable the link policy */
+ for (j = 0; j < bta_dm_conn_srvcs.count; j++) {
+ /* check if an entry already present */
+ if (bta_dm_conn_srvcs.conn_srvc[j].id == BTA_ID_HH) {
+ APPL_TRACE_DEBUG(
+ "SCO status change(Active: %d), modify HID link policy. state: %d",
+ bScoActive, bta_dm_conn_srvcs.conn_srvc[j].state);
+ bta_dm_pm_set_sniff_policy(
+ bta_dm_find_peer_device(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr),
+ bScoActive);
+
+ /* if we had disabled link policy, seems like the hid device stop retrying
+ * SNIFF after a few tries. force sniff if needed */
+ if (!bScoActive)
+ bta_dm_pm_set_mode(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr,
+ BTA_DM_PM_NO_ACTION, BTA_DM_PM_RESTART);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_set_sniff_policy
+ *
+ * Description Disables/Enables sniff in link policy for the give device
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void bta_dm_pm_set_sniff_policy(tBTA_DM_PEER_DEVICE* p_dev,
+ bool bDisable) {
+ uint16_t policy_setting;
+
+ if (!p_dev) return;
+
+ if (bDisable) {
+ policy_setting =
+ bta_dm_cb.cur_policy & (HCI_ENABLE_MASTER_SLAVE_SWITCH |
+ HCI_ENABLE_HOLD_MODE | HCI_ENABLE_PARK_MODE);
+
+ } else {
+ /* allow sniff after sco is closed */
+ policy_setting = bta_dm_cb.cur_policy;
+ }
+
+ /* if disabling SNIFF, make sure link is Active */
+ if (bDisable) bta_dm_pm_active(p_dev->peer_bdaddr);
+
+ /* update device record and set link policy */
+ p_dev->link_policy = policy_setting;
+ BTM_SetLinkPolicy(p_dev->peer_bdaddr, &policy_setting);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_pm_obtain_controller_state
+ *
+ * Description This function obtains the consolidated controller power
+ * state
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+tBTA_DM_CONTRL_STATE bta_dm_pm_obtain_controller_state(void) {
+ /* Did not use counts as it is not sure, how accurate the count values are
+ *in
+ ** bta_dm_cb.device_list.count > 0 || bta_dm_cb.device_list.le_count > 0 */
+
+ tBTA_DM_CONTRL_STATE cur_state = BTA_DM_CONTRL_UNKNOWN;
+ cur_state = BTM_PM_ReadControllerState();
+
+ APPL_TRACE_DEBUG("bta_dm_pm_obtain_controller_state: %d", cur_state);
+ return cur_state;
+}
diff --git a/mtkbt/code/bt/bta/dm/bta_dm_sco.cc b/mtkbt/code/bt/bta/dm/bta_dm_sco.cc
new file mode 100755
index 0000000..4757a53
--- a/dev/null
+++ b/mtkbt/code/bt/bta/dm/bta_dm_sco.cc
@@ -0,0 +1,667 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the down sampling utility to convert PCM samples in
+ * 16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples
+ * required for SCO channel format. One API function isprovided and only
+ * possible to be used when transmitting SCO data is sent via HCI
+ * interface.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bta_api.h"
+#include "bta_sys.h"
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+
+#ifndef BTA_DM_SCO_DEBUG
+#define BTA_DM_SCO_DEBUG false
+#endif
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+#define BTA_DM_PCM_OVERLAP_SIZE 48
+
+#define BTA_DM_PCM_SMPL_RATE_44100 44100
+#define BTA_DM_PCM_SMPL_RATE_22050 22050
+#define BTA_DM_PCM_SMPL_RATE_11025 11025
+
+/*****************************************************************************
+ * Data types for PCM Resampling utility
+ ****************************************************************************/
+
+typedef int32_t (*PCONVERT_TO_BT_FILTERED)(uint8_t* pSrc, void* pDst,
+ uint32_t dwSrcSamples,
+ uint32_t dwSrcSps,
+ int32_t* pLastCurPos,
+ uint8_t* pOverlapArea);
+typedef int32_t (*PCONVERT_TO_BT_NOFILTER)(void* pSrc, void* pDst,
+ uint32_t dwSrcSamples,
+ uint32_t dwSrcSps);
+typedef struct {
+ uint8_t overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4];
+ uint32_t cur_pos; /* current position */
+ uint32_t src_sps; /* samples per second (source audio data) */
+ PCONVERT_TO_BT_FILTERED filter; /* the action function to do the
+ conversion 44100, 22050, 11025*/
+ PCONVERT_TO_BT_NOFILTER nofilter; /* the action function to do
+ the conversion 48000, 32000, 16000*/
+ uint32_t bits; /* number of bits per pcm sample */
+ uint32_t n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
+ uint32_t sample_size;
+ uint32_t can_be_filtered;
+ uint32_t divisor;
+} tBTA_DM_PCM_RESAMPLE_CB;
+
+tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb;
+
+/*****************************************************************************
+ * Macro Definition
+ ****************************************************************************/
+
+#define CHECK_SATURATION16(x) \
+ do { \
+ if ((x) > 32767) \
+ (x) = 32767; \
+ else if ((x) < -32768) \
+ (x) = -32768; \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd) \
+ do { \
+ int32_t out1, out2, out3, out4, out5; \
+ SRC_TYPE* pS = (SRC_TYPE*)(pStart); \
+ SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd); \
+ \
+ while (pS < pSEnd) { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 1587) + \
+ ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522) + \
+ ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337) + \
+ ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058); \
+ \
+ out1 = out1 / 30000; \
+ \
+ out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725) + \
+ ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384) + \
+ ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79); \
+ \
+ out2 = out2 / 30000; \
+ \
+ out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156) + \
+ ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298) + \
+ ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345); \
+ \
+ out3 = out3 / 30000; \
+ \
+ out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306) + \
+ ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207) + \
+ ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78); \
+ \
+ out4 = out4 / 30000; \
+ \
+ out5 = out1 + out2 - out3 - out4; \
+ \
+ CHECK_SATURATION16(out5); \
+ *psBtOut++ = (int16_t)out5; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd) \
+ do { \
+ int32_t out1, out2, out3, out4, out5; \
+ SRC_TYPE* pS = (SRC_TYPE*)(pStart); \
+ SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd); \
+ \
+ while (pS < pSEnd) { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 2993) + \
+ ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568) + \
+ ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509) + \
+ ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331); \
+ \
+ out1 = out1 / 30000; \
+ \
+ out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454) + \
+ ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620) + \
+ ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305); \
+ \
+ out2 = out2 / 30000; \
+ \
+ out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127) + \
+ ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350) + \
+ ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265) + \
+ ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6); \
+ \
+ out3 = out3 / 30000; \
+ \
+ out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201); \
+ \
+ out4 = out4 / 30000; \
+ \
+ out5 = out1 - out2 + out3 - out4; \
+ \
+ CHECK_SATURATION16(out5); \
+ *psBtOut++ = (int16_t)out5; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd) \
+ do { \
+ int32_t out1; \
+ SRC_TYPE* pS = (SRC_TYPE*)(pStart); \
+ SRC_TYPE* pSEnd = (SRC_TYPE*)(pEnd); \
+ \
+ while (pS < pSEnd) { \
+ CurrentPos -= 8000; \
+ \
+ if (CurrentPos >= 0) { \
+ pS += SRC_CHANNELS; \
+ continue; \
+ } \
+ CurrentPos += dwSrcSps; \
+ \
+ out1 = (SRC_SAMPLE(0) * 6349) + \
+ ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874) - \
+ ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148) - \
+ ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287) + \
+ ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675) - \
+ ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258) - \
+ ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206) + \
+ ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266); \
+ \
+ out1 = out1 / 30000; \
+ \
+ CHECK_SATURATION16(out1); \
+ *psBtOut++ = (int16_t)out1; \
+ \
+ pS += SRC_CHANNELS; \
+ } \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE uint8_t
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) ((pS[x] - 0x80) << 8)
+
+/*****************************************************************************
+ * Local Function
+ ****************************************************************************/
+int32_t Convert_8M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+ uint32_t dwSrcSamples, uint32_t dwSrcSps,
+ int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+ int32_t CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ int16_t* psBtOut = (int16_t*)pDst;
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("Convert_8M_ToBT_Filtered, CurrentPos %d\n", CurrentPos);
+#endif
+ memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ (BTA_DM_PCM_OVERLAP_SIZE * 2),
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_8M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+ uint32_t dwSrcSps) {
+ int32_t CurrentPos;
+ uint8_t* pbSrc = (uint8_t*)pSrc;
+ int16_t* psDst = (int16_t*)pDst;
+ int16_t sWorker;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--) {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ pbSrc++;
+ else {
+ sWorker = *pbSrc++;
+ sWorker -= 0x80;
+ sWorker <<= 8;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE int16_t
+#define SRC_CHANNELS 1
+#define SRC_SAMPLE(x) pS[x]
+
+int32_t Convert_16M_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+ uint32_t dwSrcSamples, uint32_t dwSrcSps,
+ int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+ int32_t CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ int16_t* psBtOut = (int16_t*)pDst;
+
+ memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ (BTA_DM_PCM_OVERLAP_SIZE * 2),
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_16M_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+ uint32_t dwSrcSps) {
+ int32_t CurrentPos;
+ int16_t* psSrc = (int16_t*)pSrc;
+ int16_t* psDst = (int16_t*)pDst;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--) {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ psSrc++;
+ else {
+ *psDst++ = *psSrc++;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE uint8_t
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) \
+ ((((pS[x * 2] - 0x80) << 8) + ((pS[(x * 2) + 1] - 0x80) << 8)) >> 1)
+
+int32_t Convert_8S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+ uint32_t dwSrcSamples, uint32_t dwSrcSps,
+ int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+ int32_t CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ int16_t* psBtOut = (int16_t*)pDst;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \
+ dwSrcSamples %d, dwSrcSps %d",
+ CurrentPos, sizeof(SRC_TYPE), SRC_CHANNELS, dwSrcSamples, dwSrcSps);
+#endif
+ memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ (BTA_DM_PCM_OVERLAP_SIZE * 2),
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_8S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+ uint32_t dwSrcSps) {
+ int32_t CurrentPos;
+ uint8_t* pbSrc = (uint8_t*)pSrc;
+ int16_t* psDst = (int16_t*)pDst;
+ int16_t sWorker, sWorker2;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--) {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ pbSrc += 2;
+ else {
+ sWorker = *(unsigned char*)pbSrc;
+ sWorker -= 0x80;
+ sWorker <<= 8;
+ pbSrc++;
+
+ sWorker2 = *(unsigned char*)pbSrc;
+ sWorker2 -= 0x80;
+ sWorker2 <<= 8;
+ pbSrc++;
+
+ sWorker += sWorker2;
+ sWorker >>= 1;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (int16_t*)pDst);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+#undef SRC_CHANNELS
+#undef SRC_SAMPLE
+#undef SRC_TYPE
+
+#define SRC_TYPE int16_t
+#define SRC_CHANNELS 2
+#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1)
+
+int32_t Convert_16S_ToBT_Filtered(uint8_t* pSrc, void* pDst,
+ uint32_t dwSrcSamples, uint32_t dwSrcSps,
+ int32_t* pLastCurPos, uint8_t* pOverlapArea) {
+ int32_t CurrentPos = *pLastCurPos;
+ SRC_TYPE *pIn, *pInEnd;
+ SRC_TYPE *pOv, *pOvEnd;
+ int16_t* psBtOut = (int16_t*)pDst;
+
+ memcpy(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc,
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ pOv = (SRC_TYPE*)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
+ pOvEnd = (SRC_TYPE*)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));
+
+ pIn = (SRC_TYPE*)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
+ pInEnd = (SRC_TYPE*)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ BTA_DM_PCM_OVERLAP_SIZE);
+
+ if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100) {
+ CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050) {
+ CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
+ } else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025) {
+ CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
+ CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
+ }
+
+ memcpy(pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof(SRC_TYPE)) -
+ (BTA_DM_PCM_OVERLAP_SIZE * 2),
+ BTA_DM_PCM_OVERLAP_SIZE * 2);
+
+ *pLastCurPos = CurrentPos;
+
+ return (psBtOut - (int16_t*)pDst);
+}
+
+int32_t Convert_16S_ToBT_NoFilter(void* pSrc, void* pDst, uint32_t dwSrcSamples,
+ uint32_t dwSrcSps) {
+ int32_t CurrentPos;
+ int16_t* psSrc = (int16_t*)pSrc;
+ int16_t* psDst = (int16_t*)pDst;
+ int16_t sWorker;
+
+ // start at dwSpsSrc / 2, decrement by 8000
+ //
+ CurrentPos = (dwSrcSps >> 1);
+
+ while (dwSrcSamples--) {
+ CurrentPos -= 8000;
+
+ if (CurrentPos >= 0)
+ psSrc += 2;
+ else {
+ /* CR 82894, to avoid overflow, divide before add */
+ sWorker = ((*psSrc) >> 1);
+ psSrc++;
+ sWorker += ((*psSrc) >> 1);
+ psSrc++;
+
+ *psDst++ = sWorker;
+
+ CurrentPos += dwSrcSps;
+ }
+ }
+
+ return (psDst - (int16_t*)pDst);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_DmPcmInitSamples
+ *
+ * Description initialize the down sample converter.
+ *
+ * src_sps: original samples per second (source audio data)
+ * (ex. 44100, 48000)
+ * bits: number of bits per pcm sample (16)
+ * n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
+ uint32_t n_channels) {
+ tBTA_DM_PCM_RESAMPLE_CB* p_cb = &bta_dm_pcm_cb;
+
+ p_cb->cur_pos = src_sps / 2;
+ p_cb->src_sps = src_sps;
+ p_cb->bits = bits;
+ p_cb->n_channels = n_channels;
+ p_cb->sample_size = 2;
+ p_cb->divisor = 2;
+
+ memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area));
+
+ if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) ||
+ (src_sps == BTA_DM_PCM_SMPL_RATE_22050) ||
+ (src_sps == BTA_DM_PCM_SMPL_RATE_11025))
+ p_cb->can_be_filtered = 1;
+ else
+ p_cb->can_be_filtered = 0;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_dm_pcm_init_samples: n_channels = %d bits = %d",
+ n_channels, bits);
+#endif
+ if (n_channels == 1) {
+ /* mono */
+ if (bits == 8) {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8M_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8M_ToBT_NoFilter;
+ p_cb->divisor = 1;
+ } else {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16M_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16M_ToBT_NoFilter;
+ }
+ } else {
+ /* stereo */
+ if (bits == 8) {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_8S_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_8S_ToBT_NoFilter;
+ } else {
+ p_cb->filter = (PCONVERT_TO_BT_FILTERED)Convert_16S_ToBT_Filtered;
+ p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER)Convert_16S_ToBT_NoFilter;
+ p_cb->divisor = 4;
+ }
+ }
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d",
+ p_cb->cur_pos, p_cb->src_sps);
+ APPL_TRACE_DEBUG(
+ "bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ",
+ p_cb->bits, p_cb->n_channels, p_cb->sample_size);
+ APPL_TRACE_DEBUG(
+ "bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \
+ divisor %d",
+ p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor);
+#endif
+}
+
+/*******************************************************************************
+ * Function BTA_DmPcmResample
+ *
+ * Description Down sampling utility to convert higher sampling rate into
+ * 8K/16bits PCM samples.
+ *
+ * Parameters p_src: pointer to the buffer where the original sampling PCM
+ * are stored.
+ * in_bytes: Length of the input PCM sample buffer in byte.
+ * p_dst: pointer to the buffer which is to be used to
+ * store the converted PCM samples.
+ *
+ *
+ * Returns int32_t: number of samples converted.
+ *
+ ******************************************************************************/
+int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst) {
+ uint32_t out_sample;
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_pcm_resample : insamples %d",
+ (in_bytes / bta_dm_pcm_cb.divisor));
+#endif
+ if (bta_dm_pcm_cb.can_be_filtered) {
+ out_sample = (*bta_dm_pcm_cb.filter)(
+ p_src, p_dst, (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps,
+ (int32_t*)&bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area);
+ } else {
+ out_sample = (*bta_dm_pcm_cb.nofilter)(p_src, p_dst,
+ (in_bytes / bta_dm_pcm_cb.divisor),
+ bta_dm_pcm_cb.src_sps);
+ }
+
+#if (BTA_DM_SCO_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_pcm_resample : outsamples %d", out_sample);
+#endif
+
+ return (out_sample * bta_dm_pcm_cb.sample_size);
+}
+#endif
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_act.cc b/mtkbt/code/bt/bta/gatt/bta_gattc_act.cc
new file mode 100755
index 0000000..cc12f33
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_act.cc
@@ -0,0 +1,1765 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT client action functions for the state
+ * machine.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include <string.h>
+
+#include <base/callback.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btif/include/btif_debug_conn.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/l2cap/l2c_int.h"
+#include "utl.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "bta_hh_int.h"
+#endif
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport);
+
+static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data);
+static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
+ tBTA_GATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data);
+
+static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg);
+static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda);
+static void bta_gattc_cong_cback(uint16_t conn_id, bool congested);
+static void bta_gattc_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status);
+static void bta_gattc_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout, uint8_t status);
+
+static tGATT_CBACK bta_gattc_cl_cback = {bta_gattc_conn_cback,
+ bta_gattc_cmpl_cback,
+ bta_gattc_disc_res_cback,
+ bta_gattc_disc_cmpl_cback,
+ NULL,
+ bta_gattc_enc_cmpl_cback,
+ bta_gattc_cong_cback,
+ bta_gattc_phy_update_cback,
+ bta_gattc_conn_update_cback};
+
+/* opcode(tGATTC_OPTYPE) order has to be comply with internal event order */
+static uint16_t bta_gattc_opcode_to_int_evt[] = {
+ BTA_GATTC_API_READ_EVT, BTA_GATTC_API_WRITE_EVT, BTA_GATTC_API_EXEC_EVT,
+ BTA_GATTC_API_CFG_MTU_EVT};
+
+static const char* bta_gattc_op_code_name[] = {
+ "Unknown", "Discovery", "Read", "Write",
+ "Exec", "Config", "Notification", "Indication"};
+/*****************************************************************************
+ * Action Functions
+ ****************************************************************************/
+
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATT_STATUS status);
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_enable
+ *
+ * Description Enables GATTC module
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_gattc_enable() {
+ APPL_TRACE_DEBUG("bta_gattc_enable");
+
+ if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
+ /* initialize control block */
+ memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+ bta_gattc_cb.state = BTA_GATTC_STATE_ENABLED;
+ } else {
+ APPL_TRACE_DEBUG("GATTC is arelady enabled");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_disable
+ *
+ * Description Disable GATTC module by cleaning up all active connections
+ * and deregister all application.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_disable() {
+ uint8_t i;
+
+ APPL_TRACE_DEBUG("bta_gattc_disable");
+
+ if (bta_gattc_cb.state != BTA_GATTC_STATE_ENABLED) {
+ APPL_TRACE_ERROR("not enabled or disable in pogress");
+ return;
+ }
+
+ for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
+ if (bta_gattc_cb.cl_rcb[i].in_use) {
+ bta_gattc_cb.state = BTA_GATTC_STATE_DISABLING;
+/* don't deregister HH GATT IF */
+/* HH GATT IF will be deregistered by bta_hh_le_deregister when disable HH */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (!bta_hh_le_is_hh_gatt_if(bta_gattc_cb.cl_rcb[i].client_if)) {
+#endif
+ bta_gattc_deregister(&bta_gattc_cb.cl_rcb[i]);
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ }
+#endif
+ }
+ }
+
+ /* no registered apps, indicate disable completed */
+ if (bta_gattc_cb.state != BTA_GATTC_STATE_DISABLING) {
+ memset(&bta_gattc_cb, 0, sizeof(tBTA_GATTC_CB));
+ bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_register
+ *
+ * Description Register a GATT client application with BTA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_cback,
+ BtaAppRegisterCallback cb) {
+ tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+ uint8_t client_if = 0;
+ APPL_TRACE_DEBUG("bta_gattc_register state %d", bta_gattc_cb.state);
+
+ /* check if GATTC module is already enabled . Else enable */
+ if (bta_gattc_cb.state == BTA_GATTC_STATE_DISABLED) {
+ bta_gattc_enable();
+ }
+ /* todo need to check duplicate uuid */
+ for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) {
+ if (!bta_gattc_cb.cl_rcb[i].in_use) {
+ if ((p_app_uuid == NULL) ||
+ (bta_gattc_cb.cl_rcb[i].client_if =
+ GATT_Register(p_app_uuid, &bta_gattc_cl_cback)) == 0) {
+ APPL_TRACE_ERROR("Register with GATT stack failed.");
+ status = BTA_GATT_ERROR;
+ } else {
+ bta_gattc_cb.cl_rcb[i].in_use = true;
+ bta_gattc_cb.cl_rcb[i].p_cback = p_cback;
+ memcpy(&bta_gattc_cb.cl_rcb[i].app_uuid, p_app_uuid, sizeof(tBT_UUID));
+
+ /* BTA use the same client interface as BTE GATT statck */
+ client_if = bta_gattc_cb.cl_rcb[i].client_if;
+
+ tBTA_GATTC_INT_START_IF* p_buf = (tBTA_GATTC_INT_START_IF*)osi_malloc(
+ sizeof(tBTA_GATTC_INT_START_IF));
+ p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT;
+ p_buf->client_if = bta_gattc_cb.cl_rcb[i].client_if;
+
+ bta_sys_sendmsg(p_buf);
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ }
+
+ if (!cb.is_null()) cb.Run(client_if, status);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_start_if
+ *
+ * Description start an application interface.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gattc_start_if(tBTA_GATTC_DATA* p_msg) {
+ if (bta_gattc_cl_get_regcb(p_msg->int_start_if.client_if) != NULL) {
+ GATT_StartIf(p_msg->int_start_if.client_if);
+ } else {
+ APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
+ p_msg->int_start_if.client_if);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_deregister
+ *
+ * Description De-Register a GATT client application with BTA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg) {
+ uint8_t i;
+ BT_HDR buf;
+
+ if (p_clreg != NULL) {
+ /* remove bg connection associated with this rcb */
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
+ if (bta_gattc_cb.bg_track[i].in_use) {
+ if (bta_gattc_cb.bg_track[i].cif_mask &
+ (1 << (p_clreg->client_if - 1))) {
+ bta_gattc_mark_bg_conn(p_clreg->client_if,
+ bta_gattc_cb.bg_track[i].remote_bda, false);
+ GATT_CancelConnect(p_clreg->client_if,
+ bta_gattc_cb.bg_track[i].remote_bda, false);
+ }
+ }
+ }
+
+ if (p_clreg->num_clcb > 0) {
+ /* close all CLCB related to this app */
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+ if (bta_gattc_cb.clcb[i].in_use &&
+ (bta_gattc_cb.clcb[i].p_rcb == p_clreg)) {
+ p_clreg->dereg_pending = true;
+
+ buf.event = BTA_GATTC_API_CLOSE_EVT;
+ buf.layer_specific = bta_gattc_cb.clcb[i].bta_conn_id;
+ bta_gattc_close(&bta_gattc_cb.clcb[i], (tBTA_GATTC_DATA*)&buf);
+ }
+ }
+ } else
+ bta_gattc_deregister_cmpl(p_clreg);
+ } else {
+ APPL_TRACE_ERROR("%s: Deregister Failed unknown client cif", __func__);
+ bta_hh_cleanup_disable(BTA_HH_OK);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_api_open
+ *
+ * Description process connect API request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg) {
+ uint16_t event = ((BT_HDR*)p_msg)->event;
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+ tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);
+
+ if (p_clreg != NULL) {
+ if (p_msg->api_conn.is_direct) {
+ p_clcb = bta_gattc_find_alloc_clcb(p_msg->api_conn.client_if,
+ p_msg->api_conn.remote_bda,
+ p_msg->api_conn.transport);
+ if (p_clcb != NULL) {
+ bta_gattc_sm_execute(p_clcb, event, p_msg);
+ } else {
+ APPL_TRACE_ERROR("No resources to open a new connection.");
+
+ bta_gattc_send_open_cback(
+ p_clreg, BTA_GATT_NO_RESOURCES, p_msg->api_conn.remote_bda,
+ BTA_GATT_INVALID_CONN_ID, p_msg->api_conn.transport, 0);
+ }
+ } else {
+ bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg);
+ }
+ } else {
+ APPL_TRACE_ERROR("bta_gattc_process_api_open Failed, unknown client_if: %d",
+ p_msg->api_conn.client_if);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_api_open_cancel
+ *
+ * Description process connect API request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg) {
+ uint16_t event = ((BT_HDR*)p_msg)->event;
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+ tBTA_GATTC_RCB* p_clreg;
+ tBTA_GATTC cb_data;
+
+ if (p_msg->api_cancel_conn.is_direct) {
+ p_clcb = bta_gattc_find_clcb_by_cif(p_msg->api_cancel_conn.client_if,
+ p_msg->api_cancel_conn.remote_bda,
+ BTA_GATT_TRANSPORT_LE);
+ if (p_clcb != NULL) {
+ bta_gattc_sm_execute(p_clcb, event, p_msg);
+ } else {
+ APPL_TRACE_ERROR("No such connection need to be cancelled");
+
+ p_clreg = bta_gattc_cl_get_regcb(p_msg->api_cancel_conn.client_if);
+
+ if (p_clreg && p_clreg->p_cback) {
+ cb_data.status = BTA_GATT_ERROR;
+ (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+ }
+ }
+ } else {
+ bta_gattc_cancel_bk_conn(&p_msg->api_cancel_conn);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_enc_cmpl
+ *
+ * Description process encryption complete message.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg) {
+ tBTA_GATTC_RCB* p_clreg;
+ tBTA_GATTC cb_data;
+
+ p_clreg = bta_gattc_cl_get_regcb(p_msg->enc_cmpl.client_if);
+
+ if (p_clreg && p_clreg->p_cback) {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ cb_data.enc_cmpl.client_if = p_msg->enc_cmpl.client_if;
+ bdcpy(cb_data.enc_cmpl.remote_bda, p_msg->enc_cmpl.remote_bda);
+
+ (*p_clreg->p_cback)(BTA_GATTC_ENC_CMPL_CB_EVT, &cb_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cancel_open_error
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC cb_data;
+
+ cb_data.status = BTA_GATT_ERROR;
+
+ if (p_clcb && p_clcb->p_rcb && p_clcb->p_rcb->p_cback)
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_open_error
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ APPL_TRACE_ERROR("Connection already opened. wrong state");
+
+ bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+ p_clcb->bta_conn_id, p_clcb->transport, 0);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_open_fail
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_ERROR, p_clcb->bda,
+ p_clcb->bta_conn_id, p_clcb->transport, 0);
+ /* open failure, remove clcb */
+ bta_gattc_clcb_dealloc(p_clcb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_open
+ *
+ * Description Process API connection function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC_DATA gattc_data;
+
+ /* open/hold a connection */
+ if (!GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, true,
+ p_data->api_conn.transport, p_data->api_conn.opportunistic,
+ p_data->api_conn.initiating_phys)) {
+ APPL_TRACE_ERROR("Connection open failure");
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_OPEN_FAIL_EVT, p_data);
+ } else {
+ /* a connected remote device */
+ if (GATT_GetConnIdIfConnected(
+ p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda,
+ &p_clcb->bta_conn_id, p_data->api_conn.transport)) {
+ gattc_data.int_conn.hdr.layer_specific = p_clcb->bta_conn_id;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+ }
+ /* else wait for the callback event */
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_init_bk_conn
+ *
+ * Description Process API Open for a background connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
+ tBTA_GATTC_RCB* p_clreg) {
+ tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES;
+ uint16_t conn_id;
+ tBTA_GATTC_CLCB* p_clcb;
+ tBTA_GATTC_DATA gattc_data;
+
+ if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, true)) {
+ /* always call open to hold a connection */
+ if (!GATT_Connect(p_data->client_if, p_data->remote_bda, false,
+ p_data->transport, false)) {
+ uint8_t* bda = (uint8_t*)p_data->remote_bda;
+ status = BTA_GATT_ERROR;
+ APPL_TRACE_ERROR(
+ "%s unable to connect to remote "
+ "bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ } else {
+ status = BTA_GATT_OK;
+
+ /* if is a connected remote device */
+ if (GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda,
+ &conn_id, p_data->transport)) {
+ p_clcb = bta_gattc_find_alloc_clcb(
+ p_data->client_if, p_data->remote_bda, BTA_GATT_TRANSPORT_LE);
+ if (p_clcb != NULL) {
+ gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id;
+
+ /* open connection */
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, &gattc_data);
+ status = BTA_GATT_OK;
+ }
+ }
+ }
+ }
+
+ /* open failure, report OPEN_EVT */
+ if (status != BTA_GATT_OK) {
+ bta_gattc_send_open_cback(p_clreg, status, p_data->remote_bda,
+ BTA_GATT_INVALID_CONN_ID, BTA_GATT_TRANSPORT_LE,
+ 0);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_cancel_bk_conn
+ *
+ * Description Process API Cancel Open for a background connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data) {
+ tBTA_GATTC_RCB* p_clreg;
+ tBTA_GATTC cb_data;
+ cb_data.status = BTA_GATT_ERROR;
+
+ /* remove the device from the bg connection mask */
+ if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, false)) {
+ if (GATT_CancelConnect(p_data->client_if, p_data->remote_bda, false)) {
+ cb_data.status = BTA_GATT_OK;
+ } else {
+ APPL_TRACE_ERROR("bta_gattc_cancel_bk_conn failed");
+ }
+ }
+ p_clreg = bta_gattc_cl_get_regcb(p_data->client_if);
+
+ if (p_clreg && p_clreg->p_cback) {
+ (*p_clreg->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_int_cancel_open_ok
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC cb_data;
+
+ if (p_clcb->p_rcb->p_cback) {
+ cb_data.status = BTA_GATT_OK;
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+ }
+
+ bta_gattc_clcb_dealloc(p_clcb);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_cancel_open
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC cb_data;
+
+ if (GATT_CancelConnect(p_clcb->p_rcb->client_if,
+ p_data->api_cancel_conn.remote_bda, true)) {
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CANCEL_OPEN_OK_EVT, p_data);
+ } else {
+ if (p_clcb->p_rcb->p_cback) {
+ cb_data.status = BTA_GATT_ERROR;
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CANCEL_OPEN_EVT, &cb_data);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn
+ *
+ * Description receive connection callback from stack
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC_IF gatt_if;
+ APPL_TRACE_DEBUG("bta_gattc_conn server cache state=%d",
+ p_clcb->p_srcb->state);
+
+ if (p_data != NULL) {
+ APPL_TRACE_DEBUG("bta_gattc_conn conn_id=%d", p_data->hdr.layer_specific);
+ p_clcb->bta_conn_id = p_data->int_conn.hdr.layer_specific;
+
+ GATT_GetConnectionInfor(p_data->hdr.layer_specific, &gatt_if, p_clcb->bda,
+ &p_clcb->transport);
+ }
+
+ p_clcb->p_srcb->connected = true;
+
+ if (p_clcb->p_srcb->mtu == 0) p_clcb->p_srcb->mtu = GATT_DEF_BLE_MTU_SIZE;
+
+ /* start database cache if needed */
+ if (p_clcb->p_srcb->p_srvc_cache == NULL ||
+ p_clcb->p_srcb->state != BTA_GATTC_SERV_IDLE) {
+ if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) {
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_LOAD;
+ if (bta_gattc_cache_load(p_clcb)) {
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+ } else {
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC;
+ /* cache load failure, start discovery */
+ bta_gattc_start_discover(p_clcb, NULL);
+ }
+ } else /* cache is building */
+ p_clcb->state = BTA_GATTC_DISCOVER_ST;
+ }
+
+ else {
+ /* a pending service handle change indication */
+ if (p_clcb->p_srcb->srvc_hdl_chg) {
+ p_clcb->p_srcb->srvc_hdl_chg = false;
+ /* start discovery */
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ }
+
+ if (p_clcb->p_rcb) {
+ /* there is no RM for GATT */
+ if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
+ bta_sys_conn_open(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+
+ bta_gattc_send_open_cback(p_clcb->p_rcb, BTA_GATT_OK, p_clcb->bda,
+ p_clcb->bta_conn_id, p_clcb->transport,
+ p_clcb->p_srcb->mtu);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_close_fail
+ *
+ * Description close a connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC cb_data;
+
+ if (p_clcb->p_rcb->p_cback) {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+ cb_data.close.client_if = p_clcb->p_rcb->client_if;
+ cb_data.close.conn_id = p_data->hdr.layer_specific;
+ bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+ cb_data.close.status = BTA_GATT_ERROR;
+ cb_data.close.reason = BTA_GATT_CONN_NONE;
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CLOSE_EVT, &cb_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_api_close
+ *
+ * Description close a GATTC connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC_CBACK* p_cback = p_clcb->p_rcb->p_cback;
+ tBTA_GATTC_RCB* p_clreg = p_clcb->p_rcb;
+ tBTA_GATTC cb_data;
+
+ APPL_TRACE_DEBUG("bta_gattc_close conn_id=%d", p_clcb->bta_conn_id);
+
+ cb_data.close.client_if = p_clcb->p_rcb->client_if;
+ cb_data.close.conn_id = p_clcb->bta_conn_id;
+ cb_data.close.reason = p_clcb->reason;
+ cb_data.close.status = p_clcb->status;
+ bdcpy(cb_data.close.remote_bda, p_clcb->bda);
+
+ if (p_clcb->transport == BTA_TRANSPORT_BR_EDR)
+ bta_sys_conn_close(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+
+ bta_gattc_clcb_dealloc(p_clcb);
+
+ if (p_data->hdr.event == BTA_GATTC_API_CLOSE_EVT) {
+ cb_data.close.status = GATT_Disconnect(p_data->hdr.layer_specific);
+ } else if (p_data->hdr.event == BTA_GATTC_INT_DISCONN_EVT) {
+ cb_data.close.status = p_data->int_conn.reason;
+ cb_data.close.reason = p_data->int_conn.reason;
+ }
+
+ if (p_cback) (*p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC*)&cb_data);
+
+ if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) {
+ bta_gattc_deregister_cmpl(p_clreg);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_reset_discover_st
+ *
+ * Description when a SRCB finished discovery, tell all related clcb.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATT_STATUS status) {
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+ if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
+ bta_gattc_cb.clcb[i].status = status;
+ bta_gattc_sm_execute(&bta_gattc_cb.clcb[i], BTA_GATTC_DISCOVER_CMPL_EVT,
+ NULL);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_disc_close
+ *
+ * Description close a GATTC connection while in discovery state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s: Discovery cancel conn_id=%d", __func__,
+ p_clcb->bta_conn_id);
+
+ if (p_clcb->disc_active)
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_ERROR);
+ else
+ p_clcb->state = BTA_GATTC_CONN_ST;
+
+ // This function only gets called as the result of a BTA_GATTC_API_CLOSE_EVT
+ // while in the BTA_GATTC_DISCOVER_ST state. Once the state changes, the
+ // connection itself still needs to be closed to resolve the original event.
+ if (p_clcb->state == BTA_GATTC_CONN_ST) {
+ APPL_TRACE_DEBUG(
+ "State is back to BTA_GATTC_CONN_ST. "
+ "Trigger connection close");
+ bta_gattc_close(p_clcb, p_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_set_discover_st
+ *
+ * Description when a SRCB start discovery, tell all related clcb and set
+ * the state.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_set_discover_st(tBTA_GATTC_SERV* p_srcb) {
+ uint8_t i;
+
+ L2CA_EnableUpdateBleConnParams(p_srcb->server_bda, false);
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+ if (bta_gattc_cb.clcb[i].p_srcb == p_srcb) {
+ bta_gattc_cb.clcb[i].status = BTA_GATT_OK;
+ bta_gattc_cb.clcb[i].state = BTA_GATTC_DISCOVER_ST;
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_restart_discover
+ *
+ * Description process service change in discovery state, mark up the auto
+ * update flag and set status to be discovery cancel for
+ * current discovery.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ p_clcb->status = BTA_GATT_CANCEL;
+ p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cfg_mtu
+ *
+ * Description Configure MTU size on the GATT connection.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATT_STATUS status;
+
+ if (bta_gattc_enqueue(p_clcb, p_data)) {
+ status = GATTC_ConfigureMTU(p_clcb->bta_conn_id, p_data->api_mtu.mtu);
+
+ /* if failed, return callback here */
+ if (status != GATT_SUCCESS && status != GATT_CMD_STARTED) {
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, status,
+ NULL);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_start_discover
+ *
+ * Description Start a discovery on server.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ APPL_TRACE_DEBUG(
+ "bta_gattc_start_discover conn_id=%d p_clcb->p_srcb->state = %d ",
+ p_clcb->bta_conn_id, p_clcb->p_srcb->state);
+
+ if (((p_clcb->p_q_cmd == NULL ||
+ p_clcb->auto_update == BTA_GATTC_REQ_WAITING) &&
+ p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE) ||
+ p_clcb->p_srcb->state == BTA_GATTC_SERV_DISC)
+ /* no pending operation, start discovery right away */
+ {
+ p_clcb->auto_update = BTA_GATTC_NO_SCHEDULE;
+
+ if (p_clcb->p_srcb != NULL) {
+ /* clear the service change mask */
+ p_clcb->p_srcb->srvc_hdl_chg = false;
+ p_clcb->p_srcb->update_count = 0;
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_DISC_ACT;
+
+ if (p_clcb->transport == BTA_TRANSPORT_LE)
+ L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, false);
+
+ /* set all srcb related clcb into discovery ST */
+ bta_gattc_set_discover_st(p_clcb->p_srcb);
+
+ p_clcb->status = bta_gattc_init_cache(p_clcb->p_srcb);
+ if (p_clcb->status == BTA_GATT_OK) {
+ p_clcb->status = bta_gattc_discover_pri_service(
+ p_clcb->bta_conn_id, p_clcb->p_srcb, GATT_DISC_SRVC_ALL);
+ }
+ if (p_clcb->status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("discovery on server failed");
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, p_clcb->status);
+ } else
+ p_clcb->disc_active = true;
+ } else {
+ APPL_TRACE_ERROR("unknown device, can not start discovery");
+ }
+ }
+ /* pending operation, wait until it finishes */
+ else {
+ p_clcb->auto_update = BTA_GATTC_DISC_WAITING;
+
+ if (p_clcb->p_srcb->state == BTA_GATTC_SERV_IDLE)
+ p_clcb->state = BTA_GATTC_CONN_ST; /* set clcb state */
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_disc_cmpl
+ *
+ * Description discovery on server is finished
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd;
+
+ APPL_TRACE_DEBUG("bta_gattc_disc_cmpl conn_id=%d", p_clcb->bta_conn_id);
+
+ if (p_clcb->transport == BTA_TRANSPORT_LE)
+ L2CA_EnableUpdateBleConnParams(p_clcb->p_srcb->server_bda, true);
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_IDLE;
+ p_clcb->disc_active = false;
+
+ if (p_clcb->status != GATT_SUCCESS) {
+ /* clean up cache */
+ if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
+ list_free(p_clcb->p_srcb->p_srvc_cache);
+ p_clcb->p_srcb->p_srvc_cache = NULL;
+ }
+
+ /* used to reset cache in application */
+ bta_gattc_cache_reset(p_clcb->p_srcb->server_bda);
+ }
+ if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_list) {
+ /* release pending attribute list buffer */
+ osi_free_and_reset((void**)&p_clcb->p_srcb->p_srvc_list);
+ }
+
+ if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
+ /* start discovery again */
+ p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ /* get any queued command to proceed */
+ else if (p_q_cmd != NULL) {
+ p_clcb->p_q_cmd = NULL;
+ /* execute pending operation of link block still present */
+ /** M: Bug fix for bad transport type assumption @{ */
+ if (l2cu_find_lcb_by_bd_addr(p_clcb->p_srcb->server_bda, p_clcb->transport) !=
+ /** @} */
+ NULL) {
+ bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd);
+ }
+ /* if the command executed requeued the cmd, we don't
+ * want to free the underlying buffer that's being
+ * referenced by p_clcb->p_q_cmd
+ */
+ if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_read
+ *
+ * Description Read an attribute
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ if (!bta_gattc_enqueue(p_clcb, p_data)) return;
+
+ tBTA_GATT_STATUS status;
+ if (p_data->api_read.handle != 0) {
+ tGATT_READ_PARAM read_param;
+ memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+ read_param.by_handle.handle = p_data->api_read.handle;
+ read_param.by_handle.auth_req = p_data->api_read.auth_req;
+ status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_HANDLE, &read_param);
+ } else {
+ tGATT_READ_PARAM read_param;
+ memset(&read_param, 0, sizeof(tGATT_READ_BY_TYPE));
+
+ read_param.char_type.s_handle = p_data->api_read.s_handle;
+ read_param.char_type.e_handle = p_data->api_read.e_handle;
+ read_param.char_type.uuid = p_data->api_read.uuid;
+ read_param.char_type.auth_req = p_data->api_read.auth_req;
+ status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_BY_TYPE, &read_param);
+ }
+
+ /* read fail */
+ if (status != BTA_GATT_OK) {
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
+ NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_read_multi
+ *
+ * Description read multiple
+ *
+ * Returns None.
+ ******************************************************************************/
+void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ tGATT_READ_PARAM read_param;
+
+ if (bta_gattc_enqueue(p_clcb, p_data)) {
+ memset(&read_param, 0, sizeof(tGATT_READ_PARAM));
+
+ if (status == BTA_GATT_OK) {
+ read_param.read_multiple.num_handles = p_data->api_read_multi.num_attr;
+ read_param.read_multiple.auth_req = p_data->api_read_multi.auth_req;
+ memcpy(&read_param.read_multiple.handles, p_data->api_read_multi.handles,
+ sizeof(uint16_t) * p_data->api_read_multi.num_attr);
+
+ status = GATTC_Read(p_clcb->bta_conn_id, GATT_READ_MULTIPLE, &read_param);
+ }
+
+ /* read fail */
+ if (status != BTA_GATT_OK) {
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_READ, status,
+ NULL);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_write
+ *
+ * Description Write an attribute
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ if (!bta_gattc_enqueue(p_clcb, p_data)) return;
+
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ tGATT_VALUE attr;
+
+ attr.conn_id = p_clcb->bta_conn_id;
+ attr.handle = p_data->api_write.handle;
+ attr.offset = p_data->api_write.offset;
+ attr.len = p_data->api_write.len;
+ attr.auth_req = p_data->api_write.auth_req;
+
+ if (p_data->api_write.p_value)
+ memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
+
+ status =
+ GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
+
+ /* write fail */
+ if (status != BTA_GATT_OK) {
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_WRITE, status,
+ NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_execute
+ *
+ * Description send execute write
+ *
+ * Returns None.
+ ******************************************************************************/
+void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATT_STATUS status;
+
+ if (bta_gattc_enqueue(p_clcb, p_data)) {
+ status =
+ GATTC_ExecuteWrite(p_clcb->bta_conn_id, p_data->api_exec.is_execute);
+
+ if (status != BTA_GATT_OK) {
+ /* Dequeue the data, if it was enqueued */
+ if (p_clcb->p_q_cmd == p_data) p_clcb->p_q_cmd = NULL;
+
+ bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_EXE_WRITE,
+ status, NULL);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_confirm
+ *
+ * Description send handle value confirmation
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ uint16_t handle = p_data->api_confirm.handle;
+
+ if (GATTC_SendHandleValueConfirm(p_data->api_confirm.hdr.layer_specific,
+ handle) != GATT_SUCCESS) {
+ APPL_TRACE_ERROR("bta_gattc_confirm to handle [0x%04x] failed", handle);
+ } else {
+ /* if over BR_EDR, inform PM for mode change */
+ if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) {
+ bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+ bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_read_cmpl
+ *
+ * Description read complete
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_read_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+ GATT_READ_OP_CB cb = p_clcb->p_q_cmd->api_read.read_cb;
+ void* my_cb_data = p_clcb->p_q_cmd->api_read.read_cb_data;
+
+ // if it was read by handle, return the handle requested, if read by UUID, use
+ // handle returned from remote
+ uint16_t handle = p_clcb->p_q_cmd->api_read.handle;
+ if (handle == 0) handle = p_data->p_cmpl->att_value.handle;
+
+ osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+ if (cb) {
+ cb(p_clcb->bta_conn_id, p_data->status, handle,
+ p_data->p_cmpl->att_value.len, p_data->p_cmpl->att_value.value,
+ my_cb_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_write_cmpl
+ *
+ * Description write complete
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_write_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+ GATT_WRITE_OP_CB cb = p_clcb->p_q_cmd->api_write.write_cb;
+ void* my_cb_data = p_clcb->p_q_cmd->api_write.write_cb_data;
+
+ osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+ if (cb) {
+ cb(p_clcb->bta_conn_id, p_data->status, p_data->p_cmpl->att_value.handle,
+ my_cb_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_exec_cmpl
+ *
+ * Description execute write complete
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_exec_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_OP_CMPL* p_data) {
+ tBTA_GATTC cb_data;
+
+ osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+ p_clcb->status = BTA_GATT_OK;
+
+ /* execute complete, callback */
+ cb_data.exec_cmpl.conn_id = p_clcb->bta_conn_id;
+ cb_data.exec_cmpl.status = p_data->status;
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_EXEC_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cfg_mtu_cmpl
+ *
+ * Description configure MTU operation complete
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_cfg_mtu_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_OP_CMPL* p_data) {
+ tBTA_GATTC cb_data;
+
+ osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+
+ if (p_data->p_cmpl && p_data->status == BTA_GATT_OK)
+ p_clcb->p_srcb->mtu = p_data->p_cmpl->mtu;
+
+ /* configure MTU complete, callback */
+ p_clcb->status = p_data->status;
+ cb_data.cfg_mtu.conn_id = p_clcb->bta_conn_id;
+ cb_data.cfg_mtu.status = p_data->status;
+ cb_data.cfg_mtu.mtu = p_clcb->p_srcb->mtu;
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CFG_MTU_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_op_cmpl
+ *
+ * Description operation completed.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ uint8_t op = (uint8_t)p_data->op_cmpl.op_code;
+ uint8_t mapped_op = 0;
+
+ APPL_TRACE_DEBUG("bta_gattc_op_cmpl op = %d", op);
+
+ if (op == GATTC_OPTYPE_INDICATION || op == GATTC_OPTYPE_NOTIFICATION) {
+ APPL_TRACE_ERROR("unexpected operation, ignored");
+ } else if (op >= GATTC_OPTYPE_READ) {
+ if (p_clcb->p_q_cmd == NULL) {
+ APPL_TRACE_ERROR("No pending command");
+ return;
+ }
+ if (p_clcb->p_q_cmd->hdr.event !=
+ bta_gattc_opcode_to_int_evt[op - GATTC_OPTYPE_READ]) {
+ mapped_op = p_clcb->p_q_cmd->hdr.event - BTA_GATTC_API_READ_EVT +
+ GATTC_OPTYPE_READ;
+ if (mapped_op > GATTC_OPTYPE_INDICATION) mapped_op = 0;
+
+ APPL_TRACE_ERROR(
+ "expect op:(%s :0x%04x), receive unexpected operation (%s).",
+ bta_gattc_op_code_name[mapped_op], p_clcb->p_q_cmd->hdr.event,
+ bta_gattc_op_code_name[op]);
+ return;
+ }
+
+ /* Except for MTU configuration, discard responses if service change
+ * indication is received before operation completed */
+ if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING &&
+ p_clcb->p_srcb->srvc_hdl_chg && op != GATTC_OPTYPE_CONFIG) {
+ APPL_TRACE_DEBUG(
+ "Discard all responses when service change indication is received.");
+ p_data->op_cmpl.status = GATT_ERROR;
+ }
+
+ /* service handle change void the response, discard it */
+ if (op == GATTC_OPTYPE_READ)
+ bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl);
+
+ else if (op == GATTC_OPTYPE_WRITE)
+ bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl);
+
+ else if (op == GATTC_OPTYPE_EXE_WRITE)
+ bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl);
+
+ else if (op == GATTC_OPTYPE_CONFIG)
+ bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl);
+
+ if (p_clcb->auto_update == BTA_GATTC_DISC_WAITING) {
+ p_clcb->auto_update = BTA_GATTC_REQ_WAITING;
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_op_cmpl
+ *
+ * Description operation completed.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_ignore_op_cmpl(UNUSED_ATTR tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data) {
+ /* receive op complete when discovery is started, ignore the response,
+ and wait for discovery finish and resent */
+ APPL_TRACE_DEBUG("bta_gattc_ignore_op_cmpl op = %d",
+ p_data->hdr.layer_specific);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_search
+ *
+ * Description start a search in the local server cache
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ tBTA_GATT_STATUS status = GATT_INTERNAL_ERROR;
+ tBTA_GATTC cb_data;
+ APPL_TRACE_DEBUG("bta_gattc_search conn_id=%d", p_clcb->bta_conn_id);
+ if (p_clcb->p_srcb && p_clcb->p_srcb->p_srvc_cache) {
+ status = BTA_GATT_OK;
+ /* search the local cache of a server device */
+ bta_gattc_search_service(p_clcb, p_data->api_search.p_srvc_uuid);
+ }
+ cb_data.search_cmpl.status = status;
+ cb_data.search_cmpl.conn_id = p_clcb->bta_conn_id;
+
+ /* end of search or no server cache available */
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_CMPL_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_q_cmd
+ *
+ * Description enqueue a command into control block, usually because
+ * discovery operation is busy.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ bta_gattc_enqueue(p_clcb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_fail
+ *
+ * Description report API call failure back to apps
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb,
+ UNUSED_ATTR tBTA_GATTC_DATA* p_data) {
+ if (p_clcb->status == BTA_GATT_OK) {
+ APPL_TRACE_ERROR("operation not supported at current state [%d]",
+ p_clcb->state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_deregister_cmpl
+ *
+ * Description De-Register a GATT client application with BTA completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg) {
+ tBTA_GATTC_IF client_if = p_clreg->client_if;
+ tBTA_GATTC cb_data;
+ tBTA_GATTC_CBACK* p_cback = p_clreg->p_cback;
+
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ GATT_Deregister(p_clreg->client_if);
+ memset(p_clreg, 0, sizeof(tBTA_GATTC_RCB));
+
+ cb_data.reg_oper.client_if = client_if;
+ cb_data.reg_oper.status = BTA_GATT_OK;
+
+ if (p_cback) /* callback with de-register event */
+ (*p_cback)(BTA_GATTC_DEREG_EVT, (tBTA_GATTC*)&cb_data);
+
+ if (bta_gattc_num_reg_app() == 0 &&
+ bta_gattc_cb.state == BTA_GATTC_STATE_DISABLING) {
+ bta_gattc_cb.state = BTA_GATTC_STATE_DISABLED;
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn_cback
+ *
+ * Description callback functions to GATT client stack.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_gattc_conn_cback(tGATT_IF gattc_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport) {
+ if (reason != 0) {
+ APPL_TRACE_WARNING("%s() - cif=%d connected=%d conn_id=%d reason=0x%04x",
+ __func__, gattc_if, connected, conn_id, reason);
+ }
+
+ bt_bdaddr_t bdaddr;
+ bdcpy(bdaddr.address, bda);
+ if (connected)
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+ else
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason);
+
+ tBTA_GATTC_DATA* p_buf =
+ (tBTA_GATTC_DATA*)osi_calloc(sizeof(tBTA_GATTC_DATA));
+ p_buf->int_conn.hdr.event =
+ connected ? BTA_GATTC_INT_CONN_EVT : BTA_GATTC_INT_DISCONN_EVT;
+ p_buf->int_conn.hdr.layer_specific = conn_id;
+ p_buf->int_conn.client_if = gattc_if;
+ p_buf->int_conn.role = L2CA_GetBleConnRole(bda);
+ p_buf->int_conn.reason = reason;
+ p_buf->int_conn.transport = transport;
+ bdcpy(p_buf->int_conn.remote_bda, bda);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_enc_cmpl_cback
+ *
+ * Description encryption complete callback function to GATT client stack.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda) {
+ tBTA_GATTC_CLCB* p_clcb =
+ bta_gattc_find_clcb_by_cif(gattc_if, bda, BTA_GATT_TRANSPORT_LE);
+
+ if (p_clcb == NULL) return;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ /* filter this event just for BTA HH LE GATT client,
+ In the future, if we want to enable encryption complete event
+ for all GATT clients, we can remove this code */
+ if (!bta_hh_le_is_hh_gatt_if(gattc_if)) {
+ return;
+ }
+#endif
+
+ APPL_TRACE_DEBUG("%s: cif = %d", __func__, gattc_if);
+
+ tBTA_GATTC_DATA* p_buf =
+ (tBTA_GATTC_DATA*)osi_calloc(sizeof(tBTA_GATTC_DATA));
+ p_buf->enc_cmpl.hdr.event = BTA_GATTC_ENC_CMPL_EVT;
+ p_buf->enc_cmpl.hdr.layer_specific = p_clcb->bta_conn_id;
+ p_buf->enc_cmpl.client_if = gattc_if;
+ bdcpy(p_buf->enc_cmpl.remote_bda, bda);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_api_refresh
+ *
+ * Description process refresh API to delete cache and start a new
+ * discovery if currently connected.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg) {
+ tBTA_GATTC_SERV* p_srvc_cb =
+ bta_gattc_find_srvr_cache(p_msg->api_conn.remote_bda);
+ tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+ bool found = false;
+ uint8_t i;
+
+ if (p_srvc_cb != NULL) {
+ /* try to find a CLCB */
+ if (p_srvc_cb->connected && p_srvc_cb->num_clcb != 0) {
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->p_srcb == p_srvc_cb) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ return;
+ }
+ }
+ /* in all other cases, mark it and delete the cache */
+ if (p_srvc_cb->p_srvc_cache != NULL) {
+ list_free(p_srvc_cb->p_srvc_cache);
+ p_srvc_cb->p_srvc_cache = NULL;
+ }
+ }
+ /* used to reset cache in application */
+ bta_gattc_cache_reset(p_msg->api_conn.remote_bda);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_srvc_chg_ind
+ *
+ * Description process service change indication.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+bool bta_gattc_process_srvc_chg_ind(uint16_t conn_id, tBTA_GATTC_RCB* p_clrcb,
+ tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_NOTIFY* p_notify,
+ tGATT_VALUE* att_value) {
+ tBT_UUID gattp_uuid, srvc_chg_uuid;
+ bool processed = false;
+ uint8_t i;
+
+ gattp_uuid.len = 2;
+ gattp_uuid.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+
+ srvc_chg_uuid.len = 2;
+ srvc_chg_uuid.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ bta_gattc_get_characteristic_srcb(p_srcb, p_notify->handle);
+ if (p_char &&
+ bta_gattc_uuid_compare(&p_char->service->uuid, &gattp_uuid, true) &&
+ bta_gattc_uuid_compare(&p_char->uuid, &srvc_chg_uuid, true)) {
+ if (att_value->len != BTA_GATTC_SERVICE_CHANGED_LEN) {
+ APPL_TRACE_ERROR(
+ "%s: received malformed service changed indication, skipping",
+ __func__);
+ return false;
+ }
+
+ uint8_t* p = att_value->value;
+ uint16_t s_handle = ((uint16_t)(*(p)) + (((uint16_t)(*(p + 1))) << 8));
+ uint16_t e_handle = ((uint16_t)(*(p + 2)) + (((uint16_t)(*(p + 3))) << 8));
+
+ APPL_TRACE_ERROR("%s: service changed s_handle:0x%04x e_handle:0x%04x",
+ __func__, s_handle, e_handle);
+
+ processed = true;
+ /* mark service handle change pending */
+ p_srcb->srvc_hdl_chg = true;
+ /* clear up all notification/indication registration */
+ bta_gattc_clear_notif_registration(p_srcb, conn_id, s_handle, e_handle);
+ /* service change indication all received, do discovery update */
+ if (++p_srcb->update_count == bta_gattc_num_reg_app()) {
+ /* not an opened connection; or connection busy */
+ /* search for first available clcb and start discovery */
+ if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++) {
+ if (bta_gattc_cb.clcb[i].in_use &&
+ bta_gattc_cb.clcb[i].p_srcb == p_srcb &&
+ bta_gattc_cb.clcb[i].p_q_cmd == NULL) {
+ p_clcb = &bta_gattc_cb.clcb[i];
+ break;
+ }
+ }
+ }
+ /* send confirmation here if this is an indication, it should always be */
+ GATTC_SendHandleValueConfirm(conn_id, att_value->handle);
+
+ /* if connection available, refresh cache by doing discovery now */
+ if (p_clcb != NULL)
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_DISCOVER_EVT, NULL);
+ }
+ /* notify applicationf or service change */
+ if (p_clrcb->p_cback != NULL) {
+ (*p_clrcb->p_cback)(BTA_GATTC_SRVC_CHG_EVT,
+ (tBTA_GATTC*)p_srcb->server_bda);
+ }
+ }
+
+ return processed;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_proc_other_indication
+ *
+ * Description process all non-service change indication/notification.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_proc_other_indication(tBTA_GATTC_CLCB* p_clcb, uint8_t op,
+ tGATT_CL_COMPLETE* p_data,
+ tBTA_GATTC_NOTIFY* p_notify) {
+ APPL_TRACE_DEBUG(
+ "bta_gattc_proc_other_indication check \
+ p_data->att_value.handle=%d p_data->handle=%d",
+ p_data->att_value.handle, p_data->handle);
+ APPL_TRACE_DEBUG("is_notify", p_notify->is_notify);
+
+ p_notify->is_notify = (op == GATTC_OPTYPE_INDICATION) ? false : true;
+ p_notify->len = p_data->att_value.len;
+ bdcpy(p_notify->bda, p_clcb->bda);
+ memcpy(p_notify->value, p_data->att_value.value, p_data->att_value.len);
+ p_notify->conn_id = p_clcb->bta_conn_id;
+
+ if (p_clcb->p_rcb->p_cback)
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_NOTIF_EVT, (tBTA_GATTC*)p_notify);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_process_indicate
+ *
+ * Description process indication/notification.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_process_indicate(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_CL_COMPLETE* p_data) {
+ uint16_t handle = p_data->att_value.handle;
+ tBTA_GATTC_CLCB* p_clcb;
+ tBTA_GATTC_RCB* p_clrcb = NULL;
+ tBTA_GATTC_SERV* p_srcb = NULL;
+ tBTA_GATTC_NOTIFY notify;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF gatt_if;
+ tBTA_TRANSPORT transport;
+
+ if (!GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) {
+ APPL_TRACE_ERROR("%s indication/notif for unknown app", __func__);
+ if (op == GATTC_OPTYPE_INDICATION)
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+ return;
+ }
+
+ p_clrcb = bta_gattc_cl_get_regcb(gatt_if);
+ if (p_clrcb == NULL) {
+ APPL_TRACE_ERROR("%s indication/notif for unregistered app", __func__);
+ if (op == GATTC_OPTYPE_INDICATION)
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+ return;
+ }
+
+ p_srcb = bta_gattc_find_srcb(remote_bda);
+ if (p_srcb == NULL) {
+ APPL_TRACE_ERROR("%s indication/notif for unknown device, ignore",
+ __func__);
+ if (op == GATTC_OPTYPE_INDICATION)
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+ return;
+ }
+
+ p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ notify.handle = handle;
+ /* if non-service change indication/notification, forward to application */
+ if (!bta_gattc_process_srvc_chg_ind(conn_id, p_clrcb, p_srcb, p_clcb, &notify,
+ &p_data->att_value)) {
+ /* if app registered for the notification */
+ if (bta_gattc_check_notif_registry(p_clrcb, p_srcb, &notify)) {
+ /* connection not open yet */
+ if (p_clcb == NULL) {
+ p_clcb = bta_gattc_clcb_alloc(gatt_if, remote_bda, transport);
+
+ if (p_clcb == NULL) {
+ APPL_TRACE_ERROR("No resources");
+ return;
+ }
+
+ p_clcb->bta_conn_id = conn_id;
+ p_clcb->transport = transport;
+
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_INT_CONN_EVT, NULL);
+ }
+
+ if (p_clcb != NULL)
+ bta_gattc_proc_other_indication(p_clcb, op, p_data, &notify);
+ }
+ /* no one intersted and need ack? */
+ else if (op == GATTC_OPTYPE_INDICATION) {
+ APPL_TRACE_DEBUG("%s no one interested, ack now", __func__);
+ GATTC_SendHandleValueConfirm(conn_id, handle);
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_cmpl_cback
+ *
+ * Description client operation complete callback register with BTE GATT.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ tBTA_GATTC_CLCB* p_clcb;
+ APPL_TRACE_DEBUG("bta_gattc_cmpl_cback: conn_id = %d op = %d status = %d",
+ conn_id, op, status);
+
+ /* notification and indication processed right away */
+ if (op == GATTC_OPTYPE_NOTIFICATION || op == GATTC_OPTYPE_INDICATION) {
+ bta_gattc_process_indicate(conn_id, op, p_data);
+ return;
+ }
+ /* for all other operation, not expected if w/o connection */
+ else {
+ p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (p_clcb == NULL) {
+ APPL_TRACE_ERROR(
+ "bta_gattc_cmpl_cback unknown conn_id = %d, ignore data", conn_id);
+ return;
+ }
+ }
+
+ /* if over BR_EDR, inform PM for mode change */
+ if (p_clcb->transport == BTA_TRANSPORT_BR_EDR) {
+ bta_sys_busy(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+ bta_sys_idle(BTA_ID_GATTC, BTA_ALL_APP_ID, p_clcb->bda);
+ }
+
+ bta_gattc_cmpl_sendmsg(conn_id, op, status, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cmpl_sendmsg
+ *
+ * Description client operation complete send message
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op,
+ tBTA_GATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ const size_t len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE);
+ tBTA_GATTC_OP_CMPL* p_buf = (tBTA_GATTC_OP_CMPL*)osi_calloc(len);
+
+ p_buf->hdr.event = BTA_GATTC_OP_CMPL_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->status = status;
+ p_buf->op_code = op;
+
+ if (p_data != NULL) {
+ p_buf->p_cmpl = (tGATT_CL_COMPLETE*)(p_buf + 1);
+ memcpy(p_buf->p_cmpl, p_data, sizeof(tGATT_CL_COMPLETE));
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cong_cback
+ *
+ * Description congestion callback for BTA GATT client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_gattc_cong_cback(uint16_t conn_id, bool congested) {
+ tBTA_GATTC_CLCB* p_clcb;
+ tBTA_GATTC cb_data;
+
+ p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ if (p_clcb != NULL) {
+ if (p_clcb->p_rcb->p_cback) {
+ cb_data.congest.conn_id = conn_id;
+ cb_data.congest.congested = congested;
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CONGEST_EVT, &cb_data);
+ }
+ }
+}
+
+static void bta_gattc_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status) {
+ tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(gatt_if);
+
+ if (!p_clreg || !p_clreg->p_cback) {
+ APPL_TRACE_ERROR("%s: client_if=%d not found", __func__, gatt_if);
+ return;
+ }
+
+ tBTA_GATTC cb_data;
+ cb_data.phy_update.conn_id = conn_id;
+ cb_data.phy_update.server_if = gatt_if;
+ cb_data.phy_update.tx_phy = tx_phy;
+ cb_data.phy_update.rx_phy = rx_phy;
+ cb_data.phy_update.status = status;
+ (*p_clreg->p_cback)(BTA_GATTC_PHY_UPDATE_EVT, &cb_data);
+}
+
+static void bta_gattc_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout, uint8_t status) {
+ tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(gatt_if);
+
+ if (!p_clreg || !p_clreg->p_cback) {
+ APPL_TRACE_ERROR("%s: client_if=%d not found", __func__, gatt_if);
+ return;
+ }
+
+ tBTA_GATTC cb_data;
+ cb_data.conn_update.conn_id = conn_id;
+ cb_data.conn_update.interval = interval;
+ cb_data.conn_update.latency = latency;
+ cb_data.conn_update.timeout = timeout;
+ cb_data.conn_update.status = status;
+ (*p_clreg->p_cback)(BTA_GATTC_CONN_UPDATE_EVT, &cb_data);
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_api.cc b/mtkbt/code/bt/bta/gatt/bta_gattc_api.cc
new file mode 100755
index 0000000..01f17c9
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_api.cc
@@ -0,0 +1,749 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2010-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for GATT module of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include <base/bind.h>
+#include <base/bind_helpers.h>
+#include <base/callback.h>
+#include "bt_common.h"
+#include "bta_closure_api.h"
+#include "bta_gatt_api.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "device/include/controller.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_gattc_reg = {bta_gattc_hdl_event,
+ BTA_GATTC_Disable};
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Disable
+ *
+ * Description This function is called to disable GATTC module
+ *
+ * Parameters None.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_Disable(void) {
+ if (bta_sys_is_register(BTA_ID_GATTC) == false) {
+ APPL_TRACE_WARNING("GATTC Module not enabled/already disabled");
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_GATTC_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+ bta_sys_deregister(BTA_ID_GATTC);
+}
+
+static void create_random_uuid(tBT_UUID* uuid) {
+ uuid->len = LEN_UUID_128;
+
+ for (int i = 0; i < 16; ++i) {
+ uuid->uu.uuid128[i] = (uint8_t)(rand() % 256);
+ }
+}
+
+/**
+ * This function is called to register application callbacks with BTA GATTC
+ * module. |client_cb| pointer to the application callback function.
+ * |cb| one time callback when registration is finished
+ */
+void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
+ BtaAppRegisterCallback cb) {
+ if (bta_sys_is_register(BTA_ID_GATTC) == false)
+ bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg);
+
+ // base::Owned will own and free app_uuid
+ tBT_UUID* uuid = new tBT_UUID;
+ create_random_uuid(uuid);
+ do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_register, base::Owned(uuid),
+ p_client_cb, std::move(cb)));
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_AppDeregister
+ *
+ * Description This function is called to deregister an application
+ * from BTA GATTC module.
+ *
+ * Parameters client_if - client interface identifier.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if) {
+ tBTA_GATTC_API_DEREG* p_buf =
+ (tBTA_GATTC_API_DEREG*)osi_malloc(sizeof(tBTA_GATTC_API_DEREG));
+
+ p_buf->hdr.event = BTA_GATTC_API_DEREG_EVT;
+ p_buf->client_if = client_if;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Open
+ *
+ * Description Open a direct connection or add a background auto connection
+ * bd address
+ *
+ * Parameters client_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ * transport: Transport to be used for GATT connection
+ * (BREDR/LE)
+ * initiating_phys: LE PHY to use, optional
+ * opportunistic: wether the connection shall be opportunistic,
+ * and don't impact the disconnection timer
+ *
+ ******************************************************************************/
+void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, bool is_direct,
+ tBTA_GATT_TRANSPORT transport, bool opportunistic) {
+ uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
+ BTA_GATTC_Open(client_if, remote_bda, is_direct, transport, opportunistic,
+ phy);
+}
+
+void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, bool is_direct,
+ tBTA_GATT_TRANSPORT transport, bool opportunistic,
+ uint8_t initiating_phys) {
+ tBTA_GATTC_API_OPEN* p_buf =
+ (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
+
+ p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
+ p_buf->client_if = client_if;
+ p_buf->is_direct = is_direct;
+ p_buf->transport = transport;
+ p_buf->initiating_phys = initiating_phys;
+ p_buf->opportunistic = opportunistic;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_CancelOpen
+ *
+ * Description Cancel a direct open connection or remove a background auto
+ * connection
+ * bd address
+ *
+ * Parameters client_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ bool is_direct) {
+ tBTA_GATTC_API_CANCEL_OPEN* p_buf = (tBTA_GATTC_API_CANCEL_OPEN*)osi_malloc(
+ sizeof(tBTA_GATTC_API_CANCEL_OPEN));
+
+ p_buf->hdr.event = BTA_GATTC_API_CANCEL_OPEN_EVT;
+ p_buf->client_if = client_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Close
+ *
+ * Description Close a connection to a GATT server.
+ *
+ * Parameters conn_id: connectino ID to be closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTC_Close(uint16_t conn_id) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_GATTC_API_CLOSE_EVT;
+ p_buf->layer_specific = conn_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ConfigureMTU
+ *
+ * Description Configure the MTU size in the GATT channel. This can be done
+ * only once per connection.
+ *
+ * Parameters conn_id: connection ID.
+ * mtu: desired MTU size to use.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
+ tBTA_GATTC_API_CFG_MTU* p_buf =
+ (tBTA_GATTC_API_CFG_MTU*)osi_malloc(sizeof(tBTA_GATTC_API_CFG_MTU));
+
+ p_buf->hdr.event = BTA_GATTC_API_CFG_MTU_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->mtu = mtu;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ServiceSearchRequest
+ *
+ * Description This function is called to request a GATT service discovery
+ * on a GATT server. This function report service search
+ * result by a callback event, and followed by a service search
+ * complete event.
+ *
+ * Parameters conn_id: connection ID.
+ * p_srvc_uuid: a UUID of the service application is interested
+ * in.
+ * If Null, discover for all services.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id, tBT_UUID* p_srvc_uuid) {
+ const size_t len = sizeof(tBTA_GATTC_API_SEARCH) + sizeof(tBT_UUID);
+ tBTA_GATTC_API_SEARCH* p_buf = (tBTA_GATTC_API_SEARCH*)osi_calloc(len);
+
+ p_buf->hdr.event = BTA_GATTC_API_SEARCH_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ if (p_srvc_uuid) {
+ p_buf->p_srvc_uuid = (tBT_UUID*)(p_buf + 1);
+ memcpy(p_buf->p_srvc_uuid, p_srvc_uuid, sizeof(tBT_UUID));
+ } else {
+ p_buf->p_srvc_uuid = NULL;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id, tBT_UUID* p_srvc_uuid) {
+ tGATT_DISC_PARAM* param = new tGATT_DISC_PARAM;
+ param->s_handle = 0x0001;
+ param->e_handle = 0xFFFF;
+ param->service = *p_srvc_uuid;
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(base::IgnoreResult(&GATTC_Discover), conn_id,
+ GATT_DISC_SRVC_BY_UUID, base::Owned(param)));
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetServices
+ *
+ * Description This function is called to find the services on the given
+ * server.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ *
+ * Returns returns list_t of tBTA_GATTC_SERVICE or NULL.
+ *
+ ******************************************************************************/
+const list_t* BTA_GATTC_GetServices(uint16_t conn_id) {
+ return bta_gattc_get_services(conn_id);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetCharacteristic
+ *
+ * Description This function is called to find the characteristic on the
+ * given server.
+ *
+ * Parameters conn_id - connection ID which identify the server.
+ * handle - characteristic handle
+ *
+ * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ *
+ ******************************************************************************/
+const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(uint16_t conn_id,
+ uint16_t handle) {
+ return bta_gattc_get_characteristic(conn_id, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetDescriptor
+ *
+ * Description This function is called to find the characteristic on the
+ * given server.
+ *
+ * Parameters conn_id - connection ID which identify the server.
+ * handle - descriptor handle
+ *
+ * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ *
+ ******************************************************************************/
+const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle) {
+ return bta_gattc_get_descriptor(conn_id, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetGattDb
+ *
+ * Description This function is called to get the GATT database.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ * db: output parameter which will contain the GATT database
+ * copy. Caller is responsible for freeing it.
+ * count: number of elements in database.
+ *
+ ******************************************************************************/
+void BTA_GATTC_GetGattDb(uint16_t conn_id, uint16_t start_handle,
+ uint16_t end_handle, btgatt_db_element_t** db,
+ int* count) {
+ bta_gattc_get_gatt_db(conn_id, start_handle, end_handle, db, count);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadCharacteristic
+ *
+ * Description This function is called to read a characteristics value
+ *
+ * Parameters conn_id - connection ID.
+ * handle - characteritic handle to read.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_READ* p_buf =
+ (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = handle;
+ p_buf->read_cb = callback;
+ p_buf->read_cb_data = cb_data;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/**
+ * This function is called to read a value of characteristic with uuid equal to
+ * |uuid|
+ */
+void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, tBT_UUID uuid,
+ uint16_t s_handle, uint16_t e_handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_READ* p_buf =
+ (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = 0;
+ p_buf->uuid = uuid;
+ p_buf->s_handle = s_handle;
+ p_buf->e_handle = e_handle;
+ p_buf->read_cb = callback;
+ p_buf->read_cb_data = cb_data;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadCharDescr
+ *
+ * Description This function is called to read a descriptor value.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - descriptor handle to read.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_READ* p_buf =
+ (tBTA_GATTC_API_READ*)osi_calloc(sizeof(tBTA_GATTC_API_READ));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = handle;
+ p_buf->read_cb = callback;
+ p_buf->read_cb_data = cb_data;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadMultiple
+ *
+ * Description This function is called to read multiple characteristic or
+ * characteristic descriptors.
+ *
+ * Parameters conn_id - connectino ID.
+ * p_read_multi - pointer to the read multiple parameter.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadMultiple(uint16_t conn_id, tBTA_GATTC_MULTI* p_read_multi,
+ tBTA_GATT_AUTH_REQ auth_req) {
+ tBTA_GATTC_API_READ_MULTI* p_buf =
+ (tBTA_GATTC_API_READ_MULTI*)osi_calloc(sizeof(tBTA_GATTC_API_READ_MULTI));
+
+ p_buf->hdr.event = BTA_GATTC_API_READ_MULTI_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->num_attr = p_read_multi->num_attr;
+
+ if (p_buf->num_attr > 0)
+ memcpy(p_buf->handles, p_read_multi->handles,
+ sizeof(uint16_t) * p_read_multi->num_attr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_WriteCharValue
+ *
+ * Description This function is called to write characteristic value.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - characteristic handle to write.
+ * write_type - type of write.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ std::vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+ sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = handle;
+ p_buf->write_type = write_type;
+ p_buf->len = value.size();
+ p_buf->write_cb = callback;
+ p_buf->write_cb_data = cb_data;
+
+ if (value.size() > 0) {
+ p_buf->p_value = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->p_value, value.data(), value.size());
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_WriteCharDescr
+ *
+ * Description This function is called to write descriptor value.
+ *
+ * Parameters conn_id - connection ID
+ * handle - descriptor hadle to write.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
+ std::vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+ sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = handle;
+ p_buf->write_type = BTA_GATTC_TYPE_WRITE;
+ p_buf->write_cb = callback;
+ p_buf->write_cb_data = cb_data;
+
+ if (value.size() != 0) {
+ p_buf->p_value = (uint8_t*)(p_buf + 1);
+ p_buf->len = value.size();
+ memcpy(p_buf->p_value, value.data(), value.size());
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_PrepareWrite
+ *
+ * Description This function is called to prepare write a characteristic
+ * value.
+ *
+ * Parameters conn_id - connection ID.
+ * p_char_id - GATT characteritic ID of the service.
+ * offset - offset of the write value.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle, uint16_t offset,
+ std::vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data) {
+ tBTA_GATTC_API_WRITE* p_buf = (tBTA_GATTC_API_WRITE*)osi_calloc(
+ sizeof(tBTA_GATTC_API_WRITE) + value.size());
+
+ p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->auth_req = auth_req;
+ p_buf->handle = handle;
+ p_buf->write_cb = callback;
+ p_buf->write_cb_data = cb_data;
+
+ p_buf->write_type = BTA_GATTC_WRITE_PREPARE;
+ p_buf->offset = offset;
+ p_buf->len = value.size();
+
+ if (value.size() > 0) {
+ p_buf->p_value = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->p_value, value.data(), value.size());
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ExecuteWrite
+ *
+ * Description This function is called to execute write a prepare write
+ * sequence.
+ *
+ * Parameters conn_id - connection ID.
+ * is_execute - execute or cancel.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
+ tBTA_GATTC_API_EXEC* p_buf =
+ (tBTA_GATTC_API_EXEC*)osi_calloc(sizeof(tBTA_GATTC_API_EXEC));
+
+ p_buf->hdr.event = BTA_GATTC_API_EXEC_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->is_execute = is_execute;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_SendIndConfirm
+ *
+ * Description This function is called to send handle value confirmation.
+ *
+ * Parameters conn_id - connection ID.
+ * p_char_id - characteristic ID to confirm.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_SendIndConfirm(uint16_t conn_id, uint16_t handle) {
+ tBTA_GATTC_API_CONFIRM* p_buf =
+ (tBTA_GATTC_API_CONFIRM*)osi_calloc(sizeof(tBTA_GATTC_API_CONFIRM));
+
+ APPL_TRACE_API("%s conn_id=%d handle=0x%04x", __func__, conn_id, handle);
+
+ p_buf->hdr.event = BTA_GATTC_API_CONFIRM_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->handle = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_RegisterForNotifications
+ *
+ * Description This function is called to register for notification of a
+ * service.
+ *
+ * Parameters client_if - client interface.
+ * bda - target GATT server.
+ * handle - GATT characteristic handle.
+ *
+ * Returns OK if registration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(tBTA_GATTC_IF client_if,
+ const BD_ADDR bda,
+ uint16_t handle) {
+ tBTA_GATTC_RCB* p_clreg;
+ tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+ uint8_t i;
+
+ if (!handle) {
+ APPL_TRACE_ERROR("deregistration failed, handle is 0");
+ return status;
+ }
+
+ p_clreg = bta_gattc_cl_get_regcb(client_if);
+ if (p_clreg != NULL) {
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (p_clreg->notif_reg[i].in_use &&
+ !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
+ p_clreg->notif_reg[i].handle == handle) {
+ APPL_TRACE_WARNING("notification already registered");
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ if (status != BTA_GATT_OK) {
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (!p_clreg->notif_reg[i].in_use) {
+ memset((void*)&p_clreg->notif_reg[i], 0,
+ sizeof(tBTA_GATTC_NOTIF_REG));
+
+ p_clreg->notif_reg[i].in_use = true;
+ memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN);
+
+ p_clreg->notif_reg[i].handle = handle;
+ status = BTA_GATT_OK;
+ break;
+ }
+ }
+ if (i == BTA_GATTC_NOTIF_REG_MAX) {
+ status = BTA_GATT_NO_RESOURCES;
+ APPL_TRACE_ERROR("Max Notification Reached, registration failed.");
+ }
+ }
+ } else {
+ APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_DeregisterForNotifications
+ *
+ * Description This function is called to de-register for notification of a
+ * service.
+ *
+ * Parameters client_if - client interface.
+ * remote_bda - target GATT server.
+ * handle - GATT characteristic handle.
+ *
+ * Returns OK if deregistration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(tBTA_GATTC_IF client_if,
+ const BD_ADDR bda,
+ uint16_t handle) {
+ if (!handle) {
+ APPL_TRACE_ERROR("%s: deregistration failed, handle is 0", __func__);
+ return BTA_GATT_ILLEGAL_PARAMETER;
+ }
+
+ tBTA_GATTC_RCB* p_clreg = bta_gattc_cl_get_regcb(client_if);
+ if (p_clreg == NULL) {
+ APPL_TRACE_ERROR(
+ "%s client_if: %d not registered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, client_if, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ return BTA_GATT_ILLEGAL_PARAMETER;
+ }
+
+ for (int i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (p_clreg->notif_reg[i].in_use &&
+ !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&
+ p_clreg->notif_reg[i].handle == handle) {
+ APPL_TRACE_DEBUG("%s deregistered bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, bda[0], bda[1], bda[2], bda[3], bda[4],
+ bda[5]);
+ memset(&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+ return BTA_GATT_OK;
+ }
+ }
+
+ APPL_TRACE_ERROR(
+ "%s registration not found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ return BTA_GATT_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Refresh
+ *
+ * Description Refresh the server cache of the remote device
+ *
+ * Parameters remote_bda: remote device BD address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTC_Refresh(const BD_ADDR remote_bda) {
+ tBTA_GATTC_API_OPEN* p_buf =
+ (tBTA_GATTC_API_OPEN*)osi_malloc(sizeof(tBTA_GATTC_API_OPEN));
+
+ p_buf->hdr.event = BTA_GATTC_API_REFRESH_EVT;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_cache.cc b/mtkbt/code/bt/bta/gatt/bta_gattc_cache.cc
new file mode 100755
index 0000000..97e384d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_cache.cc
@@ -0,0 +1,1544 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT client discovery procedures and cache
+ * related functions.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include "bt_target.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+#include "utl.h"
+
+static void bta_gattc_cache_write(BD_ADDR server_bda, uint16_t num_attr,
+ tBTA_GATTC_NV_ATTR* attr);
+static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb);
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
+ uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb);
+extern void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
+tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
+ uint16_t handle);
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle);
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+
+#define BTA_GATT_SDP_DB_SIZE 4096
+
+#define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
+#define GATT_CACHE_VERSION 2
+
+static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
+ BD_ADDR bda) {
+ snprintf(buffer, buffer_len, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX,
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+}
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+typedef struct {
+ tSDP_DISCOVERY_DB* p_sdp_db;
+ uint16_t sdp_conn_id;
+} tBTA_GATTC_CB_DATA;
+
+#if (BTA_GATT_DEBUG == TRUE)
+static char* bta_gattc_attr_type[] = {
+ "I", /* Included Service */
+ "C", /* Characteristic */
+ "D" /* Characteristic Descriptor */
+};
+/* utility functions */
+
+bool display_cache_attribute(void* data, void* context) {
+ tBTA_GATTC_CACHE_ATTR* p_attr = data;
+ APPL_TRACE_ERROR("\t Attr handle[%d] uuid[0x%04x] type[%s] prop[0x%1x]",
+ p_attr->handle, p_attr->uuid.uu.uuid16,
+ bta_gattc_attr_type[p_attr->attr_type], p_attr->property);
+ return true;
+}
+
+bool display_cache_service(void* data, void* context) {
+ tBTA_GATTC_SERVICE* p_cur_srvc = data;
+ APPL_TRACE_ERROR("Service: handle[%d ~ %d] %s[0x%04x] inst[%d]",
+ p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+ ((p_cur_srvc->uuid.len == 2) ? "uuid16" : "uuid128"),
+ p_cur_srvc->uuid.uu.uuid16, p_cur_srvc->handle);
+
+ if (p_cur_srvc->characteristics != NULL) {
+ list_foreach(p_cur_srvc->characteristics, display_cache_attribute, NULL);
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_display_cache_server
+ *
+ * Description debug function to display the server cache.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gattc_display_cache_server(list_t* p_cache) {
+ APPL_TRACE_ERROR("<================Start Server Cache =============>");
+ list_foreach(p_cache, display_cache_service, NULL);
+ APPL_TRACE_ERROR("<================End Server Cache =============>");
+ APPL_TRACE_ERROR(" ");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_display_explore_record
+ *
+ * Description debug function to display the exploration list
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gattc_display_explore_record(tBTA_GATTC_ATTR_REC* p_rec,
+ uint8_t num_rec) {
+ uint8_t i;
+ tBTA_GATTC_ATTR_REC* pp = p_rec;
+
+ APPL_TRACE_ERROR("<================Start Explore Queue =============>");
+ for (i = 0; i < num_rec; i++, pp++) {
+ APPL_TRACE_ERROR(
+ "\t rec[%d] uuid[0x%04x] s_handle[%d] e_handle[%d] is_primary[%d]",
+ i + 1, pp->uuid.uu.uuid16, pp->s_handle, pp->e_handle, pp->is_primary);
+ }
+ APPL_TRACE_ERROR("<================ End Explore Queue =============>");
+ APPL_TRACE_ERROR(" ");
+}
+#endif /* BTA_GATT_DEBUG == TRUE */
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_init_cache
+ *
+ * Description Initialize the database cache and discovery related
+ * resources.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb) {
+ if (p_srvc_cb->p_srvc_cache != NULL) {
+ list_free(p_srvc_cb->p_srvc_cache);
+ p_srvc_cb->p_srvc_cache = NULL;
+ }
+
+ osi_free(p_srvc_cb->p_srvc_list);
+ p_srvc_cb->p_srvc_list =
+ (tBTA_GATTC_ATTR_REC*)osi_malloc(BTA_GATTC_ATTR_LIST_SIZE);
+ p_srvc_cb->total_srvc = 0;
+ p_srvc_cb->cur_srvc_idx = 0;
+ p_srvc_cb->cur_char_idx = 0;
+ p_srvc_cb->next_avail_idx = 0;
+
+ return BTA_GATT_OK;
+}
+
+static void characteristic_free(void* ptr) {
+ tBTA_GATTC_CHARACTERISTIC* p_char = (tBTA_GATTC_CHARACTERISTIC*)ptr;
+ list_free(p_char->descriptors);
+ osi_free(p_char);
+}
+
+static void service_free(void* ptr) {
+ tBTA_GATTC_SERVICE* srvc = (tBTA_GATTC_SERVICE*)ptr;
+ list_free(srvc->characteristics);
+ list_free(srvc->included_svc);
+ osi_free(srvc);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_add_srvc_to_cache
+ *
+ * Description Add a service into database cache.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t s_handle,
+ uint16_t e_handle,
+ tBT_UUID* p_uuid,
+ bool is_primary) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("Add a service into Service");
+#endif
+
+ tBTA_GATTC_SERVICE* p_new_srvc =
+ (tBTA_GATTC_SERVICE*)osi_malloc(sizeof(tBTA_GATTC_SERVICE));
+
+ /* update service information */
+ p_new_srvc->s_handle = s_handle;
+ p_new_srvc->e_handle = e_handle;
+ p_new_srvc->is_primary = is_primary;
+ memcpy(&p_new_srvc->uuid, p_uuid, sizeof(tBT_UUID));
+ p_new_srvc->handle = s_handle;
+ p_new_srvc->characteristics = list_new(characteristic_free);
+ p_new_srvc->included_svc = list_new(osi_free);
+
+ if (p_srvc_cb->p_srvc_cache == NULL) {
+ p_srvc_cb->p_srvc_cache = list_new(service_free);
+ }
+
+ list_append(p_srvc_cb->p_srvc_cache, p_new_srvc);
+ return BTA_GATT_OK;
+}
+
+static tBTA_GATT_STATUS bta_gattc_add_char_to_cache(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t attr_handle,
+ uint16_t value_handle,
+ tBT_UUID* p_uuid,
+ uint8_t property) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: Add a characteristic into Service", __func__);
+ APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x", value_handle,
+ p_uuid->uu.uuid16, property);
+#endif
+
+ tBTA_GATTC_SERVICE* service =
+ bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, attr_handle);
+ if (!service) {
+ APPL_TRACE_ERROR(
+ "Illegal action to add char/descr/incl srvc for non-existing service!");
+ return GATT_WRONG_STATE;
+ }
+
+ /* TODO(jpawlowski): We should use attribute handle, not value handle to refer
+ to characteristic.
+ This is just a temporary workaround.
+ */
+ if (service->e_handle < value_handle) service->e_handle = value_handle;
+
+ tBTA_GATTC_CHARACTERISTIC* characteristic =
+ (tBTA_GATTC_CHARACTERISTIC*)osi_malloc(sizeof(tBTA_GATTC_CHARACTERISTIC));
+
+ characteristic->handle = value_handle;
+ characteristic->properties = property;
+ characteristic->descriptors = list_new(osi_free);
+ memcpy(&characteristic->uuid, p_uuid, sizeof(tBT_UUID));
+
+ characteristic->service = service;
+ list_append(service->characteristics, characteristic);
+
+ return BTA_GATT_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_add_attr_to_cache
+ *
+ * Description Add an attribute into database cache buffer.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_attr_to_cache(
+ tBTA_GATTC_SERV* p_srvc_cb, uint16_t handle, tBT_UUID* p_uuid,
+ uint8_t property, uint16_t incl_srvc_s_handle, tBTA_GATTC_ATTR_TYPE type) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: Add a [%s] into Service", __func__,
+ bta_gattc_attr_type[type]);
+ APPL_TRACE_DEBUG("handle=%d uuid16=0x%x property=0x%x type=%d", handle,
+ p_uuid->uu.uuid16, property, type);
+#endif
+
+ tBTA_GATTC_SERVICE* service =
+ bta_gattc_find_matching_service(p_srvc_cb->p_srvc_cache, handle);
+ if (!service) {
+ APPL_TRACE_ERROR(
+ "Illegal action to add char/descr/incl srvc for non-existing service!");
+ return GATT_WRONG_STATE;
+ }
+
+ if (type == BTA_GATTC_ATTR_TYPE_INCL_SRVC) {
+ tBTA_GATTC_INCLUDED_SVC* isvc =
+ (tBTA_GATTC_INCLUDED_SVC*)osi_malloc(sizeof(tBTA_GATTC_INCLUDED_SVC));
+
+ isvc->handle = handle;
+ memcpy(&isvc->uuid, p_uuid, sizeof(tBT_UUID));
+
+ isvc->owning_service = service;
+ isvc->included_service = bta_gattc_find_matching_service(
+ p_srvc_cb->p_srvc_cache, incl_srvc_s_handle);
+ if (!isvc->included_service) {
+ APPL_TRACE_ERROR(
+ "%s: Illegal action to add non-existing included service!", __func__);
+ osi_free(isvc);
+ return GATT_WRONG_STATE;
+ }
+
+ list_append(service->included_svc, isvc);
+ } else if (type == BTA_GATTC_ATTR_TYPE_CHAR_DESCR) {
+ tBTA_GATTC_DESCRIPTOR* descriptor =
+ (tBTA_GATTC_DESCRIPTOR*)osi_malloc(sizeof(tBTA_GATTC_DESCRIPTOR));
+
+ descriptor->handle = handle;
+ memcpy(&descriptor->uuid, p_uuid, sizeof(tBT_UUID));
+
+ if (service->characteristics == NULL ||
+ list_is_empty(service->characteristics)) {
+ APPL_TRACE_ERROR(
+ "%s: Illegal action to add descriptor before adding a "
+ "characteristic!",
+ __func__);
+ osi_free(descriptor);
+ return GATT_WRONG_STATE;
+ }
+
+ tBTA_GATTC_CHARACTERISTIC* char_node =
+ (tBTA_GATTC_CHARACTERISTIC*)list_back(service->characteristics);
+
+ descriptor->characteristic = char_node;
+ list_append(char_node->descriptors, descriptor);
+ }
+ return BTA_GATT_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_get_disc_range
+ *
+ * Description get discovery stating and ending handle range.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_get_disc_range(tBTA_GATTC_SERV* p_srvc_cb, uint16_t* p_s_hdl,
+ uint16_t* p_e_hdl, bool is_srvc) {
+ tBTA_GATTC_ATTR_REC* p_rec = NULL;
+
+ if (is_srvc) {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+ *p_s_hdl = p_rec->s_handle;
+ } else {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+ *p_s_hdl = p_rec->s_handle + 1;
+ }
+
+ *p_e_hdl = p_rec->e_handle;
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("discover range [%d ~ %d]", p_rec->s_handle,
+ p_rec->e_handle);
+#endif
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_discover_pri_service
+ *
+ * Description Start primary service discovery
+ *
+ * Returns status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_pri_service(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_server_cb,
+ uint8_t disc_type) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+ if (p_clcb) {
+ if (p_clcb->transport == BTA_TRANSPORT_LE)
+ status = bta_gattc_discover_procedure(conn_id, p_server_cb, disc_type);
+ else
+ status = bta_gattc_sdp_service_disc(conn_id, p_server_cb);
+ }
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_discover_procedure
+ *
+ * Description Start a particular type of discovery procedure on server.
+ *
+ * Returns status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_discover_procedure(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_server_cb,
+ uint8_t disc_type) {
+ tGATT_DISC_PARAM param;
+ bool is_service = true;
+
+ memset(&param, 0, sizeof(tGATT_DISC_PARAM));
+
+ if (disc_type == GATT_DISC_SRVC_ALL || disc_type == GATT_DISC_SRVC_BY_UUID) {
+ param.s_handle = 1;
+ param.e_handle = 0xFFFF;
+ } else {
+ if (disc_type == GATT_DISC_CHAR_DSCPT) is_service = false;
+
+ bta_gattc_get_disc_range(p_server_cb, &param.s_handle, &param.e_handle,
+ is_service);
+
+ if (param.s_handle > param.e_handle) {
+ return GATT_ERROR;
+ }
+ }
+ return GATTC_Discover(conn_id, disc_type, &param);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_start_disc_include_srvc
+ *
+ * Description Start discovery for included service
+ *
+ * Returns status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_include_srvc(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_INC_SRVC);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_start_disc_char
+ *
+ * Description Start discovery for characteristic
+ *
+ * Returns status of the operation.
+ *
+ ******************************************************************************/
+tBTA_GATT_STATUS bta_gattc_start_disc_char(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ p_srvc_cb->total_char = 0;
+
+ return bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_start_disc_char_dscp
+ *
+ * Description Start discovery for characteristic descriptor
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gattc_start_disc_char_dscp(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ APPL_TRACE_DEBUG("starting discover characteristics descriptor");
+
+ if (bta_gattc_discover_procedure(conn_id, p_srvc_cb, GATT_DISC_CHAR_DSCPT) !=
+ 0)
+ bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_explore_srvc
+ *
+ * Description process the service discovery complete event
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static void bta_gattc_explore_srvc(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx;
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ APPL_TRACE_DEBUG("Start service discovery: srvc_idx = %d",
+ p_srvc_cb->cur_srvc_idx);
+
+ p_srvc_cb->cur_char_idx = p_srvc_cb->next_avail_idx = p_srvc_cb->total_srvc;
+
+ if (p_clcb == NULL) {
+ APPL_TRACE_ERROR("unknown connection ID");
+ return;
+ }
+ /* start expore a service if there is service not been explored */
+ if (p_srvc_cb->cur_srvc_idx < p_srvc_cb->total_srvc) {
+ /* add the first service into cache */
+ if (bta_gattc_add_srvc_to_cache(p_srvc_cb, p_rec->s_handle, p_rec->e_handle,
+ &p_rec->uuid, p_rec->is_primary) == 0) {
+ /* start discovering included services */
+ bta_gattc_start_disc_include_srvc(conn_id, p_srvc_cb);
+ return;
+ }
+ }
+ /* no service found at all, the end of server discovery*/
+ LOG_WARN(LOG_TAG, "%s no more services found", __func__);
+
+#if (BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_cache_server(p_srvc_cb->p_srvc_cache);
+#endif
+ /* save cache to NV */
+ p_clcb->p_srcb->state = BTA_GATTC_SERV_SAVE;
+
+ if (btm_sec_is_a_bonded_dev(p_srvc_cb->server_bda)) {
+ bta_gattc_cache_save(p_clcb->p_srcb, p_clcb->bta_conn_id);
+ }
+
+ bta_gattc_reset_discover_st(p_clcb->p_srcb, BTA_GATT_OK);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_incl_srvc_disc_cmpl
+ *
+ * Description process the relationship discovery complete event
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static void bta_gattc_incl_srvc_disc_cmpl(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ p_srvc_cb->cur_char_idx = p_srvc_cb->total_srvc;
+
+ /* start discoverying characteristic */
+ bta_gattc_start_disc_char(conn_id, p_srvc_cb);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_char_disc_cmpl
+ *
+ * Description process the characteristic discovery complete event
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static void bta_gattc_char_disc_cmpl(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_ATTR_REC* p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->cur_char_idx;
+
+ /* if there are characteristic needs to be explored */
+ if (p_srvc_cb->total_char > 0) {
+ /* add the first characteristic into cache */
+ bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
+ p_rec->s_handle, &p_rec->uuid, p_rec->property);
+
+ /* start discoverying characteristic descriptor , if failed, disc for next
+ * char*/
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+ } else /* otherwise start with next service */
+ {
+ p_srvc_cb->cur_srvc_idx++;
+
+ bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_char_dscpt_disc_cmpl
+ *
+ * Description process the char descriptor discovery complete event
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static void bta_gattc_char_dscpt_disc_cmpl(uint16_t conn_id,
+ tBTA_GATTC_SERV* p_srvc_cb) {
+ tBTA_GATTC_ATTR_REC* p_rec = NULL;
+
+ if (--p_srvc_cb->total_char > 0) {
+ p_rec = p_srvc_cb->p_srvc_list + (++p_srvc_cb->cur_char_idx);
+ /* add the next characteristic into cache */
+ bta_gattc_add_char_to_cache(p_srvc_cb, p_rec->char_decl_handle,
+ p_rec->s_handle, &p_rec->uuid, p_rec->property);
+
+ /* start discoverying next characteristic for char descriptor */
+ bta_gattc_start_disc_char_dscp(conn_id, p_srvc_cb);
+ } else
+ /* all characteristic has been explored, start with next service if any */
+ {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_ERROR("all char has been explored");
+#endif
+ p_srvc_cb->cur_srvc_idx++;
+ bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ }
+}
+static bool bta_gattc_srvc_in_list(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t s_handle, uint16_t e_handle,
+ UNUSED_ATTR tBT_UUID uuid) {
+ tBTA_GATTC_ATTR_REC* p_rec = NULL;
+ uint8_t i;
+ bool exist_srvc = false;
+
+ if (!GATT_HANDLE_IS_VALID(s_handle) || !GATT_HANDLE_IS_VALID(e_handle)) {
+ APPL_TRACE_ERROR("invalid included service handle: [0x%04x ~ 0x%04x]",
+ s_handle, e_handle);
+ exist_srvc = true;
+ } else {
+ for (i = 0; i < p_srvc_cb->next_avail_idx; i++) {
+ p_rec = p_srvc_cb->p_srvc_list + i;
+
+ /* a new service should not have any overlap with other service handle
+ * range */
+ if (p_rec->s_handle == s_handle || p_rec->e_handle == e_handle) {
+ exist_srvc = true;
+ break;
+ }
+ }
+ }
+ return exist_srvc;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_add_srvc_to_list
+ *
+ * Description Add a service into explore pending list
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_srvc_to_list(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t s_handle,
+ uint16_t e_handle,
+ tBT_UUID uuid,
+ bool is_primary) {
+ tBTA_GATTC_ATTR_REC* p_rec = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if (p_srvc_cb->p_srvc_list &&
+ p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+ APPL_TRACE_DEBUG("%s handle=%d, service type=0x%04x", __func__, s_handle,
+ uuid.uu.uuid16);
+
+ p_rec->s_handle = s_handle;
+ p_rec->e_handle = e_handle;
+ p_rec->is_primary = is_primary;
+ memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+ p_srvc_cb->total_srvc++;
+ p_srvc_cb->next_avail_idx++;
+ } else { /* allocate bigger buffer ?? */
+ status = GATT_DB_FULL;
+
+ APPL_TRACE_ERROR("service not added, no resources or wrong state");
+ }
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_add_char_to_list
+ *
+ * Description Add a characteristic into explore pending list
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_add_char_to_list(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t decl_handle,
+ uint16_t value_handle,
+ tBT_UUID uuid,
+ uint8_t property) {
+ tBTA_GATTC_ATTR_REC* p_rec = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+
+ if (p_srvc_cb->p_srvc_list == NULL) {
+ APPL_TRACE_ERROR("No service available, unexpected char discovery result");
+ status = BTA_GATT_INTERNAL_ERROR;
+ } else if (p_srvc_cb->next_avail_idx < BTA_GATTC_MAX_CACHE_CHAR) {
+ p_rec = p_srvc_cb->p_srvc_list + p_srvc_cb->next_avail_idx;
+
+ p_srvc_cb->total_char++;
+
+ p_rec->s_handle = value_handle;
+ p_rec->char_decl_handle = decl_handle;
+ p_rec->property = property;
+ p_rec->e_handle =
+ (p_srvc_cb->p_srvc_list + p_srvc_cb->cur_srvc_idx)->e_handle;
+ memcpy(&p_rec->uuid, &uuid, sizeof(tBT_UUID));
+
+ /* update the endind handle of pervious characteristic if available */
+ if (p_srvc_cb->total_char > 1) {
+ p_rec -= 1;
+ p_rec->e_handle = decl_handle - 1;
+ }
+ p_srvc_cb->next_avail_idx++;
+ } else {
+ APPL_TRACE_ERROR("char not added, no resources");
+ /* allocate bigger buffer ?? */
+ status = BTA_GATT_DB_FULL;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_sdp_callback
+ *
+ * Description Process the discovery result from sdp
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_sdp_callback(uint16_t sdp_status, void* user_data) {
+ tSDP_DISC_REC* p_sdp_rec = NULL;
+ tBT_UUID service_uuid;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t start_handle = 0, end_handle = 0;
+ tBTA_GATTC_CB_DATA* cb_data = (tBTA_GATTC_CB_DATA*)user_data;
+ tBTA_GATTC_SERV* p_srvc_cb = bta_gattc_find_scb_by_cid(cb_data->sdp_conn_id);
+
+ if (((sdp_status == SDP_SUCCESS) || (sdp_status == SDP_DB_FULL)) &&
+ p_srvc_cb != NULL) {
+ do {
+ /* find a service record, report it */
+ p_sdp_rec = SDP_FindServiceInDb(cb_data->p_sdp_db, 0, p_sdp_rec);
+ if (p_sdp_rec) {
+ if (SDP_FindServiceUUIDInRec(p_sdp_rec, &service_uuid)) {
+ if (SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_ATT,
+ &pe)) {
+ start_handle = (uint16_t)pe.params[0];
+ end_handle = (uint16_t)pe.params[1];
+
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_EVENT(
+ "Found ATT service [0x%04x] handle[0x%04x ~ 0x%04x]",
+ service_uuid.uu.uuid16, start_handle, end_handle);
+#endif
+
+ if (GATT_HANDLE_IS_VALID(start_handle) &&
+ GATT_HANDLE_IS_VALID(end_handle) && p_srvc_cb != NULL) {
+ /* discover services result, add services into a service list */
+ bta_gattc_add_srvc_to_list(p_srvc_cb, start_handle, end_handle,
+ service_uuid, true);
+ } else {
+ APPL_TRACE_ERROR("invalid start_handle = %d end_handle = %d",
+ start_handle, end_handle);
+ }
+ }
+ }
+ }
+ } while (p_sdp_rec);
+ }
+
+ if (p_srvc_cb != NULL) {
+ /* start discover primary service */
+ bta_gattc_explore_srvc(cb_data->sdp_conn_id, p_srvc_cb);
+ } else {
+ APPL_TRACE_ERROR("GATT service discovery is done on unknown connection");
+ }
+
+ /* both were allocated in bta_gattc_sdp_service_disc */
+ osi_free(cb_data->p_sdp_db);
+ osi_free(cb_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_sdp_service_disc
+ *
+ * Description Start DSP Service Discovert
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTA_GATT_STATUS bta_gattc_sdp_service_disc(
+ uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb) {
+ tSDP_UUID uuid;
+ uint16_t num_attrs = 2;
+ uint16_t attr_list[2];
+
+ memset(&uuid, 0, sizeof(tSDP_UUID));
+
+ uuid.len = LEN_UUID_16;
+ uuid.uu.uuid16 = UUID_PROTOCOL_ATT;
+
+ /*
+ * On success, cb_data will be freed inside bta_gattc_sdp_callback,
+ * otherwise it will be freed within this function.
+ */
+ tBTA_GATTC_CB_DATA* cb_data =
+ (tBTA_GATTC_CB_DATA*)osi_malloc(sizeof(tBTA_GATTC_CB_DATA));
+
+ cb_data->p_sdp_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_GATT_SDP_DB_SIZE);
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+
+ SDP_InitDiscoveryDb(cb_data->p_sdp_db, BTA_GATT_SDP_DB_SIZE, 1, &uuid,
+ num_attrs, attr_list);
+
+ if (!SDP_ServiceSearchAttributeRequest2(p_server_cb->server_bda,
+ cb_data->p_sdp_db,
+ &bta_gattc_sdp_callback, cb_data)) {
+ osi_free(cb_data->p_sdp_db);
+ osi_free(cb_data);
+ return BTA_GATT_ERROR;
+ }
+
+ cb_data->sdp_conn_id = conn_id;
+ return BTA_GATT_OK;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_disc_res_cback
+ * bta_gattc_disc_cmpl_cback
+ *
+ * Description callback functions to GATT client stack.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_gattc_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data) {
+ tBTA_GATTC_SERV* p_srvc_cb = NULL;
+ bool pri_srvc;
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+ if (p_srvc_cb != NULL && p_clcb != NULL &&
+ p_clcb->state == BTA_GATTC_DISCOVER_ST) {
+ switch (disc_type) {
+ case GATT_DISC_SRVC_ALL:
+ /* discover services result, add services into a service list */
+ bta_gattc_add_srvc_to_list(
+ p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
+ p_data->value.group_value.service_type, true);
+
+ break;
+ case GATT_DISC_SRVC_BY_UUID:
+ bta_gattc_add_srvc_to_list(
+ p_srvc_cb, p_data->handle, p_data->value.group_value.e_handle,
+ p_data->value.group_value.service_type, true);
+ break;
+
+ case GATT_DISC_INC_SRVC:
+ /* add included service into service list if it's secondary or it never
+ showed up
+ in the primary service search */
+ pri_srvc = bta_gattc_srvc_in_list(
+ p_srvc_cb, p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle,
+ p_data->value.incl_service.service_type);
+
+ if (!pri_srvc)
+ bta_gattc_add_srvc_to_list(
+ p_srvc_cb, p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle,
+ p_data->value.incl_service.service_type, false);
+ /* add into database */
+ bta_gattc_add_attr_to_cache(
+ p_srvc_cb, p_data->handle, &p_data->value.incl_service.service_type,
+ pri_srvc, p_data->value.incl_service.s_handle,
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC);
+ break;
+
+ case GATT_DISC_CHAR:
+ /* add char value into database */
+ bta_gattc_add_char_to_list(p_srvc_cb, p_data->handle,
+ p_data->value.dclr_value.val_handle,
+ p_data->value.dclr_value.char_uuid,
+ p_data->value.dclr_value.char_prop);
+ break;
+
+ case GATT_DISC_CHAR_DSCPT:
+ bta_gattc_add_attr_to_cache(p_srvc_cb, p_data->handle, &p_data->type, 0,
+ 0 /* incl_srvc_handle */,
+ BTA_GATTC_ATTR_TYPE_CHAR_DESCR);
+ break;
+ }
+ }
+}
+void bta_gattc_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status) {
+ tBTA_GATTC_SERV* p_srvc_cb;
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb && (status != GATT_SUCCESS || p_clcb->status != GATT_SUCCESS)) {
+ if (status == GATT_SUCCESS) p_clcb->status = status;
+ bta_gattc_sm_execute(p_clcb, BTA_GATTC_DISCOVER_CMPL_EVT, NULL);
+ return;
+ }
+ p_srvc_cb = bta_gattc_find_scb_by_cid(conn_id);
+
+ if (p_srvc_cb != NULL) {
+ switch (disc_type) {
+ case GATT_DISC_SRVC_ALL:
+ case GATT_DISC_SRVC_BY_UUID:
+#if (BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
+ p_srvc_cb->next_avail_idx);
+#endif
+ bta_gattc_explore_srvc(conn_id, p_srvc_cb);
+ break;
+
+ case GATT_DISC_INC_SRVC:
+ bta_gattc_incl_srvc_disc_cmpl(conn_id, p_srvc_cb);
+
+ break;
+
+ case GATT_DISC_CHAR:
+#if (BTA_GATT_DEBUG == TRUE)
+ bta_gattc_display_explore_record(p_srvc_cb->p_srvc_list,
+ p_srvc_cb->next_avail_idx);
+#endif
+ bta_gattc_char_disc_cmpl(conn_id, p_srvc_cb);
+ break;
+
+ case GATT_DISC_CHAR_DSCPT:
+ bta_gattc_char_dscpt_disc_cmpl(conn_id, p_srvc_cb);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_search_service
+ *
+ * Description search local cache for matching service record.
+ *
+ * Returns false if map can not be found.
+ *
+ ******************************************************************************/
+void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid) {
+ tBTA_GATTC cb_data;
+
+ if (!p_clcb->p_srcb->p_srvc_cache ||
+ list_is_empty(p_clcb->p_srcb->p_srvc_cache))
+ return;
+
+ for (list_node_t* sn = list_begin(p_clcb->p_srcb->p_srvc_cache);
+ sn != list_end(p_clcb->p_srcb->p_srvc_cache); sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* p_cache = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (!bta_gattc_uuid_compare(p_uuid, &p_cache->uuid, false)) continue;
+
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("found service [0x%04x], inst[%d] handle [%d]",
+ p_cache->uuid.uu.uuid16, p_cache->handle,
+ p_cache->s_handle);
+#endif
+ if (!p_clcb->p_rcb->p_cback) continue;
+
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ cb_data.srvc_res.conn_id = p_clcb->bta_conn_id;
+ cb_data.srvc_res.service_uuid.inst_id = p_cache->handle;
+ memcpy(&cb_data.srvc_res.service_uuid.uuid, &p_cache->uuid,
+ sizeof(tBTA_GATT_ID));
+
+ (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SEARCH_RES_EVT, &cb_data);
+ }
+}
+
+list_t* bta_gattc_get_services_srcb(tBTA_GATTC_SERV* p_srcb) {
+ if (!p_srcb || !p_srcb->p_srvc_cache || list_is_empty(p_srcb->p_srvc_cache))
+ return NULL;
+
+ return p_srcb->p_srvc_cache;
+}
+
+const list_t* bta_gattc_get_services(uint16_t conn_id) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) return NULL;
+
+ tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+
+ return bta_gattc_get_services_srcb(p_srcb);
+}
+
+tBTA_GATTC_SERVICE* bta_gattc_find_matching_service(const list_t* services,
+ uint16_t handle) {
+ if (!services || list_is_empty(services)) return NULL;
+
+ for (list_node_t* sn = list_begin(services); sn != list_end(services);
+ sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (handle >= service->s_handle && handle <= service->e_handle)
+ return service;
+ }
+
+ return NULL;
+}
+
+const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
+ const list_t* services = bta_gattc_get_services_srcb(p_srcb);
+
+ return bta_gattc_find_matching_service(services, handle);
+}
+
+const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(uint16_t conn_id,
+ uint16_t handle) {
+ const list_t* services = bta_gattc_get_services(conn_id);
+
+ return bta_gattc_find_matching_service(services, handle);
+}
+
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle) {
+ const tBTA_GATTC_SERVICE* service =
+ bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
+
+ if (!service) return NULL;
+
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+ if (handle == p_char->handle) return p_char;
+ }
+
+ return NULL;
+}
+
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
+ uint16_t handle) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) return NULL;
+
+ tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+ return bta_gattc_get_characteristic_srcb(p_srcb, handle);
+}
+
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor_srcb(tBTA_GATTC_SERV* p_srcb,
+ uint16_t handle) {
+ const tBTA_GATTC_SERVICE* service =
+ bta_gattc_get_service_for_handle_srcb(p_srcb, handle);
+
+ if (!service) {
+ return NULL;
+ }
+
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+ for (list_node_t* dn = list_begin(p_char->descriptors);
+ dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+ tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+ if (handle == p_desc->handle) return p_desc;
+ }
+ }
+
+ return NULL;
+}
+
+tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+ uint16_t handle) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) return NULL;
+
+ tBTA_GATTC_SERV* p_srcb = p_clcb->p_srcb;
+ return bta_gattc_get_descriptor_srcb(p_srcb, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_fill_gatt_db_el
+ *
+ * Description fill a btgatt_db_element_t value
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_fill_gatt_db_el(btgatt_db_element_t* p_attr,
+ bt_gatt_db_attribute_type_t type,
+ uint16_t att_handle, uint16_t s_handle,
+ uint16_t e_handle, uint16_t id, tBT_UUID uuid,
+ uint8_t prop) {
+ p_attr->type = type;
+ p_attr->attribute_handle = att_handle;
+ p_attr->start_handle = s_handle;
+ p_attr->end_handle = e_handle;
+ p_attr->id = id;
+ p_attr->properties = prop;
+ bta_to_btif_uuid(&p_attr->uuid, &uuid);
+}
+
+/*******************************************************************************
+ * Returns number of elements inside db from start_handle to end_handle
+ ******************************************************************************/
+static size_t bta_gattc_get_db_size(list_t* services, uint16_t start_handle,
+ uint16_t end_handle) {
+ if (!services || list_is_empty(services)) return 0;
+
+ size_t db_size = 0;
+
+ for (list_node_t* sn = list_begin(services); sn != list_end(services);
+ sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (p_cur_srvc->s_handle < start_handle) continue;
+
+ if (p_cur_srvc->e_handle > end_handle) break;
+
+ db_size++;
+ if (!p_cur_srvc->characteristics ||
+ list_is_empty(p_cur_srvc->characteristics))
+ continue;
+
+ for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+ cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+ db_size++;
+
+ if (p_char->descriptors) db_size += list_length(p_char->descriptors);
+ }
+
+ if (p_cur_srvc->included_svc) {
+ db_size += list_length(p_cur_srvc->included_svc);
+ }
+ }
+
+ return db_size;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_get_gatt_db_impl
+ *
+ * Description copy the server GATT database into db parameter.
+ *
+ * Parameters p_srvc_cb: server.
+ * db: output parameter which will contain GATT database copy.
+ * Caller is responsible for freeing it.
+ * count: output parameter which will contain number of
+ * elements in database.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+static void bta_gattc_get_gatt_db_impl(tBTA_GATTC_SERV* p_srvc_cb,
+ uint16_t start_handle,
+ uint16_t end_handle,
+ btgatt_db_element_t** db, int* count) {
+ APPL_TRACE_DEBUG("%s: start_handle 0x%04x, end_handle 0x%04x", __func__,
+ start_handle, end_handle);
+
+ if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache)) {
+ *count = 0;
+ *db = NULL;
+ return;
+ }
+
+ size_t db_size =
+ bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, start_handle, end_handle);
+
+ void* buffer = osi_malloc(db_size * sizeof(btgatt_db_element_t));
+ btgatt_db_element_t* curr_db_attr = (btgatt_db_element_t*)buffer;
+
+ for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+ sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (p_cur_srvc->s_handle < start_handle) continue;
+
+ if (p_cur_srvc->e_handle > end_handle) break;
+
+ bta_gattc_fill_gatt_db_el(
+ curr_db_attr, p_cur_srvc->is_primary ? BTGATT_DB_PRIMARY_SERVICE
+ : BTGATT_DB_SECONDARY_SERVICE,
+ 0 /* att_handle */, p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+ p_cur_srvc->s_handle, p_cur_srvc->uuid, 0 /* prop */);
+ curr_db_attr++;
+
+ if (!p_cur_srvc->characteristics ||
+ list_is_empty(p_cur_srvc->characteristics))
+ continue;
+
+ for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+ cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+ bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_CHARACTERISTIC,
+ p_char->handle, 0 /* s_handle */,
+ 0 /* e_handle */, p_char->handle, p_char->uuid,
+ p_char->properties);
+ curr_db_attr++;
+
+ if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
+
+ for (list_node_t* dn = list_begin(p_char->descriptors);
+ dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+ tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+ bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_DESCRIPTOR,
+ p_desc->handle, 0 /* s_handle */,
+ 0 /* e_handle */, p_desc->handle,
+ p_desc->uuid, 0 /* property */);
+ curr_db_attr++;
+ }
+ }
+
+ if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
+ continue;
+
+ for (list_node_t* isn = list_begin(p_cur_srvc->included_svc);
+ isn != list_end(p_cur_srvc->included_svc); isn = list_next(isn)) {
+ tBTA_GATTC_INCLUDED_SVC* p_isvc =
+ (tBTA_GATTC_INCLUDED_SVC*)list_node(isn);
+
+ bta_gattc_fill_gatt_db_el(curr_db_attr, BTGATT_DB_INCLUDED_SERVICE,
+ p_isvc->handle, 0 /* s_handle */,
+ 0 /* e_handle */, p_isvc->handle, p_isvc->uuid,
+ 0 /* property */);
+ curr_db_attr++;
+ }
+ }
+
+ *db = (btgatt_db_element_t*)buffer;
+ *count = db_size;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_get_gatt_db
+ *
+ * Description copy the server GATT database into db parameter.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ * db: output parameter which will contain GATT database copy.
+ * Caller is responsible for freeing it.
+ * count: number of elements in database.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
+ uint16_t end_handle, btgatt_db_element_t** db,
+ int* count) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+ if (p_clcb == NULL) {
+ APPL_TRACE_ERROR("Unknown conn ID: %d", conn_id);
+ return;
+ }
+
+ if (p_clcb->state != BTA_GATTC_CONN_ST) {
+ APPL_TRACE_ERROR("server cache not available, CLCB state = %d",
+ p_clcb->state);
+ return;
+ }
+
+ if (!p_clcb->p_srcb ||
+ p_clcb->p_srcb->p_srvc_list || /* no active discovery */
+ !p_clcb->p_srcb->p_srvc_cache) {
+ APPL_TRACE_ERROR("No server cache available");
+ return;
+ }
+
+ bta_gattc_get_gatt_db_impl(p_clcb->p_srcb, start_handle, end_handle, db,
+ count);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_rebuild_cache
+ *
+ * Description rebuild server cache from NV cache.
+ *
+ * Parameters
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srvc_cb, uint16_t num_attr,
+ tBTA_GATTC_NV_ATTR* p_attr) {
+ /* first attribute loading, initialize buffer */
+ APPL_TRACE_ERROR("%s: bta_gattc_rebuild_cache", __func__);
+
+ list_free(p_srvc_cb->p_srvc_cache);
+ p_srvc_cb->p_srvc_cache = NULL;
+
+ while (num_attr > 0 && p_attr != NULL) {
+ switch (p_attr->attr_type) {
+ case BTA_GATTC_ATTR_TYPE_SRVC:
+ bta_gattc_add_srvc_to_cache(p_srvc_cb, p_attr->s_handle,
+ p_attr->e_handle, &p_attr->uuid,
+ p_attr->is_primary);
+ break;
+
+ case BTA_GATTC_ATTR_TYPE_CHAR:
+ // TODO(jpawlowski): store decl_handle properly.
+ bta_gattc_add_char_to_cache(p_srvc_cb, p_attr->s_handle,
+ p_attr->s_handle, &p_attr->uuid,
+ p_attr->prop);
+ break;
+
+ case BTA_GATTC_ATTR_TYPE_CHAR_DESCR:
+ case BTA_GATTC_ATTR_TYPE_INCL_SRVC:
+ bta_gattc_add_attr_to_cache(p_srvc_cb, p_attr->s_handle, &p_attr->uuid,
+ p_attr->prop, p_attr->incl_srvc_handle,
+ p_attr->attr_type);
+ break;
+ }
+ p_attr++;
+ num_attr--;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_fill_nv_attr
+ *
+ * Description fill a NV attribute entry value
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_fill_nv_attr(tBTA_GATTC_NV_ATTR* p_attr, uint8_t type,
+ uint16_t s_handle, uint16_t e_handle, tBT_UUID uuid,
+ uint8_t prop, uint16_t incl_srvc_handle,
+ bool is_primary) {
+ p_attr->s_handle = s_handle;
+ p_attr->e_handle = e_handle;
+ p_attr->attr_type = type;
+ p_attr->is_primary = is_primary;
+ p_attr->id = 0;
+ p_attr->prop = prop;
+ p_attr->incl_srvc_handle = incl_srvc_handle;
+
+ memcpy(&p_attr->uuid, &uuid, sizeof(tBT_UUID));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cache_save
+ *
+ * Description save the server cache into NV
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id) {
+ if (!p_srvc_cb->p_srvc_cache || list_is_empty(p_srvc_cb->p_srvc_cache))
+ return;
+
+ int i = 0;
+ size_t db_size =
+ bta_gattc_get_db_size(p_srvc_cb->p_srvc_cache, 0x0000, 0xFFFF);
+ tBTA_GATTC_NV_ATTR* nv_attr =
+ (tBTA_GATTC_NV_ATTR*)osi_malloc(db_size * sizeof(tBTA_GATTC_NV_ATTR));
+
+ for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+ sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_SRVC,
+ p_cur_srvc->s_handle, p_cur_srvc->e_handle,
+ p_cur_srvc->uuid, 0 /* properties */,
+ 0 /* incl_srvc_handle */, p_cur_srvc->is_primary);
+ }
+
+ for (list_node_t* sn = list_begin(p_srvc_cb->p_srvc_cache);
+ sn != list_end(p_srvc_cb->p_srvc_cache); sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* p_cur_srvc = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (!p_cur_srvc->characteristics ||
+ list_is_empty(p_cur_srvc->characteristics))
+ continue;
+
+ for (list_node_t* cn = list_begin(p_cur_srvc->characteristics);
+ cn != list_end(p_cur_srvc->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+ bta_gattc_fill_nv_attr(
+ &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR, p_char->handle, 0,
+ p_char->uuid, p_char->properties, 0 /* incl_srvc_handle */, false);
+
+ if (!p_char->descriptors || list_is_empty(p_char->descriptors)) continue;
+
+ for (list_node_t* dn = list_begin(p_char->descriptors);
+ dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+ tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+ bta_gattc_fill_nv_attr(
+ &nv_attr[i++], BTA_GATTC_ATTR_TYPE_CHAR_DESCR, p_desc->handle, 0,
+ p_desc->uuid, 0 /* properties */, 0 /* incl_srvc_handle */, false);
+ }
+ }
+
+ if (!p_cur_srvc->included_svc || list_is_empty(p_cur_srvc->included_svc))
+ continue;
+
+ for (list_node_t* an = list_begin(p_cur_srvc->included_svc);
+ an != list_end(p_cur_srvc->included_svc); an = list_next(an)) {
+ tBTA_GATTC_INCLUDED_SVC* p_isvc = (tBTA_GATTC_INCLUDED_SVC*)list_node(an);
+
+ bta_gattc_fill_nv_attr(&nv_attr[i++], BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+ p_isvc->handle, 0, p_isvc->uuid,
+ 0 /* properties */,
+ p_isvc->included_service->s_handle, false);
+ }
+ }
+
+ bta_gattc_cache_write(p_srvc_cb->server_bda, db_size, nv_attr);
+ osi_free(nv_attr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cache_load
+ *
+ * Description Load GATT cache from storage for server.
+ *
+ * Parameter p_clcb: pointer to server clcb, that will
+ * be filled from storage
+ * Returns true on success, false otherwise
+ *
+ ******************************************************************************/
+bool bta_gattc_cache_load(tBTA_GATTC_CLCB* p_clcb) {
+ char fname[255] = {0};
+ bta_gattc_generate_cache_file_name(fname, sizeof(fname),
+ p_clcb->p_srcb->server_bda);
+
+ FILE* fd = fopen(fname, "rb");
+ if (!fd) {
+ APPL_TRACE_ERROR("%s: can't open GATT cache file %s for reading, error: %s",
+ __func__, fname, strerror(errno));
+ return false;
+ }
+
+ uint16_t cache_ver = 0;
+ tBTA_GATTC_NV_ATTR* attr = NULL;
+ bool success = false;
+ uint16_t num_attr = 0;
+
+ if (fread(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
+ APPL_TRACE_ERROR("%s: can't read GATT cache version from: %s", __func__,
+ fname);
+ goto done;
+ }
+
+ if (cache_ver != GATT_CACHE_VERSION) {
+ APPL_TRACE_ERROR("%s: wrong GATT cache version: %s", __func__, fname);
+ goto done;
+ }
+
+ if (fread(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
+ APPL_TRACE_ERROR("%s: can't read number of GATT attributes: %s", __func__,
+ fname);
+ goto done;
+ }
+
+ attr = (tBTA_GATTC_NV_ATTR*)osi_malloc(sizeof(tBTA_GATTC_NV_ATTR) * num_attr);
+
+ if (fread(attr, sizeof(tBTA_GATTC_NV_ATTR), 0xFF, fd) != num_attr) {
+ APPL_TRACE_ERROR("%s: can't read GATT attributes: %s", __func__, fname);
+ goto done;
+ }
+
+ bta_gattc_rebuild_cache(p_clcb->p_srcb, num_attr, attr);
+
+ success = true;
+
+done:
+ osi_free(attr);
+ fclose(fd);
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cache_write
+ *
+ * Description This callout function is executed by GATT when a server
+ * cache is available to save.
+ *
+ * Parameter server_bda: server bd address of this cache belongs to
+ * num_attr: number of attribute to be save.
+ * attr: pointer to the list of attributes to save.
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_gattc_cache_write(BD_ADDR server_bda, uint16_t num_attr,
+ tBTA_GATTC_NV_ATTR* attr) {
+ char fname[255] = {0};
+ bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
+
+ FILE* fd = fopen(fname, "wb");
+ if (!fd) {
+ APPL_TRACE_ERROR("%s: can't open GATT cache file for writing: %s", __func__,
+ fname);
+ return;
+ }
+
+ uint16_t cache_ver = GATT_CACHE_VERSION;
+ if (fwrite(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
+ APPL_TRACE_ERROR("%s: can't write GATT cache version: %s", __func__, fname);
+ fclose(fd);
+ return;
+ }
+
+ if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
+ APPL_TRACE_ERROR("%s: can't write GATT cache attribute count: %s", __func__,
+ fname);
+ fclose(fd);
+ return;
+ }
+
+ if (fwrite(attr, sizeof(tBTA_GATTC_NV_ATTR), num_attr, fd) != num_attr) {
+ APPL_TRACE_ERROR("%s: can't write GATT cache attributes: %s", __func__,
+ fname);
+ fclose(fd);
+ return;
+ }
+
+ fclose(fd);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cache_reset
+ *
+ * Description This callout function is executed by GATTC to reset cache in
+ * application
+ *
+ * Parameter server_bda: server bd address of this cache belongs to
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_gattc_cache_reset(BD_ADDR server_bda) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ char fname[255] = {0};
+ bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
+ unlink(fname);
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_int.h b/mtkbt/code/bt/bta/gatt/bta_gattc_int.h
new file mode 100755
index 0000000..24d8046
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_int.h
@@ -0,0 +1,510 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private file for the file transfer client (FTC).
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTC_INT_H
+#define BTA_GATTC_INT_H
+
+#include "bt_target.h"
+
+#include "bta_gatt_api.h"
+#include "bta_sys.h"
+#include "osi/include/fixed_queue.h"
+
+#include "bt_common.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+enum {
+ BTA_GATTC_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_GATTC),
+ BTA_GATTC_INT_OPEN_FAIL_EVT,
+ BTA_GATTC_API_CANCEL_OPEN_EVT,
+ BTA_GATTC_INT_CANCEL_OPEN_OK_EVT,
+
+ BTA_GATTC_API_READ_EVT,
+ BTA_GATTC_API_WRITE_EVT,
+ BTA_GATTC_API_EXEC_EVT,
+ BTA_GATTC_API_CFG_MTU_EVT,
+
+ BTA_GATTC_API_CLOSE_EVT,
+
+ BTA_GATTC_API_SEARCH_EVT,
+ BTA_GATTC_API_CONFIRM_EVT,
+ BTA_GATTC_API_READ_MULTI_EVT,
+ BTA_GATTC_API_REFRESH_EVT,
+
+ BTA_GATTC_INT_CONN_EVT,
+ BTA_GATTC_INT_DISCOVER_EVT,
+ BTA_GATTC_DISCOVER_CMPL_EVT,
+ BTA_GATTC_OP_CMPL_EVT,
+ BTA_GATTC_INT_DISCONN_EVT,
+
+ BTA_GATTC_INT_START_IF_EVT,
+ BTA_GATTC_API_DEREG_EVT,
+ BTA_GATTC_API_DISABLE_EVT,
+ BTA_GATTC_ENC_CMPL_EVT
+};
+typedef uint16_t tBTA_GATTC_INT_EVT;
+
+#define BTA_GATTC_SERVICE_CHANGED_LEN 4
+
+/* max client application GATTC can support */
+#ifndef BTA_GATTC_CL_MAX
+#define BTA_GATTC_CL_MAX 32
+#endif
+
+/* max known devices GATTC can support */
+#ifndef BTA_GATTC_KNOWN_SR_MAX
+#define BTA_GATTC_KNOWN_SR_MAX 10
+#endif
+
+#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
+
+#ifndef BTA_GATTC_CLCB_MAX
+#define BTA_GATTC_CLCB_MAX GATT_CL_MAX_LCB
+#endif
+
+#define BTA_GATTC_WRITE_PREPARE GATT_WRITE_PREPARE
+
+/* internal strucutre for GATTC register API */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATTC_IF client_if;
+} tBTA_GATTC_INT_START_IF;
+
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_API_DEREG;
+typedef tBTA_GATTC_INT_START_IF tBTA_GATTC_INT_DEREG;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF client_if;
+ bool is_direct;
+ tBTA_TRANSPORT transport;
+ uint8_t initiating_phys;
+ bool opportunistic;
+} tBTA_GATTC_API_OPEN;
+
+typedef tBTA_GATTC_API_OPEN tBTA_GATTC_API_CANCEL_OPEN;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+
+ // read by handle data
+ uint16_t handle;
+
+ // read by UUID data
+ tBT_UUID uuid;
+ uint16_t s_handle;
+ uint16_t e_handle;
+
+ tBTA_GATTC_EVT cmpl_evt;
+ GATT_READ_OP_CB read_cb;
+ void* read_cb_data;
+} tBTA_GATTC_API_READ;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+ uint16_t handle;
+ tBTA_GATTC_WRITE_TYPE write_type;
+ uint16_t offset;
+ uint16_t len;
+ uint8_t* p_value;
+ GATT_WRITE_OP_CB write_cb;
+ void* write_cb_data;
+} tBTA_GATTC_API_WRITE;
+
+typedef struct {
+ BT_HDR hdr;
+ bool is_execute;
+} tBTA_GATTC_API_EXEC;
+
+typedef struct {
+ BT_HDR hdr;
+ uint16_t handle;
+} tBTA_GATTC_API_CONFIRM;
+
+typedef tGATT_CL_COMPLETE tBTA_GATTC_CMPL;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t op_code;
+ tGATT_STATUS status;
+ tBTA_GATTC_CMPL* p_cmpl;
+} tBTA_GATTC_OP_CMPL;
+
+typedef struct {
+ BT_HDR hdr;
+ tBT_UUID* p_srvc_uuid;
+} tBTA_GATTC_API_SEARCH;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATT_AUTH_REQ auth_req;
+ uint8_t num_attr;
+ uint16_t handles[GATT_MAX_READ_MULTI_HANDLES];
+} tBTA_GATTC_API_READ_MULTI;
+
+typedef struct {
+ BT_HDR hdr;
+ uint16_t mtu;
+} tBTA_GATTC_API_CFG_MTU;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF client_if;
+ uint8_t role;
+ tBT_TRANSPORT transport;
+ tGATT_DISCONN_REASON reason;
+} tBTA_GATTC_INT_CONN;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF client_if;
+} tBTA_GATTC_ENC_CMPL;
+
+typedef union {
+ BT_HDR hdr;
+ tBTA_GATTC_API_DEREG api_dereg;
+ tBTA_GATTC_API_OPEN api_conn;
+ tBTA_GATTC_API_CANCEL_OPEN api_cancel_conn;
+ tBTA_GATTC_API_READ api_read;
+ tBTA_GATTC_API_SEARCH api_search;
+ tBTA_GATTC_API_WRITE api_write;
+ tBTA_GATTC_API_CONFIRM api_confirm;
+ tBTA_GATTC_API_EXEC api_exec;
+ tBTA_GATTC_API_READ_MULTI api_read_multi;
+ tBTA_GATTC_API_CFG_MTU api_mtu;
+ tBTA_GATTC_OP_CMPL op_cmpl;
+ tBTA_GATTC_INT_CONN int_conn;
+ tBTA_GATTC_ENC_CMPL enc_cmpl;
+
+ tBTA_GATTC_INT_START_IF int_start_if;
+ tBTA_GATTC_INT_DEREG int_dereg;
+
+} tBTA_GATTC_DATA;
+
+/* GATT server cache on the client */
+
+typedef struct {
+ tBT_UUID uuid;
+ uint16_t s_handle;
+ uint16_t e_handle;
+ // this field is set only for characteristic
+ uint16_t char_decl_handle;
+ bool is_primary;
+ tBTA_GATT_CHAR_PROP property;
+} tBTA_GATTC_ATTR_REC;
+
+#define BTA_GATTC_MAX_CACHE_CHAR 40
+#define BTA_GATTC_ATTR_LIST_SIZE \
+ (BTA_GATTC_MAX_CACHE_CHAR * sizeof(tBTA_GATTC_ATTR_REC))
+
+#ifndef BTA_GATTC_CACHE_SRVR_SIZE
+#define BTA_GATTC_CACHE_SRVR_SIZE 600
+#endif
+
+enum {
+ BTA_GATTC_IDLE_ST = 0, /* Idle */
+ BTA_GATTC_W4_CONN_ST, /* Wait for connection - (optional) */
+ BTA_GATTC_CONN_ST, /* connected state */
+ BTA_GATTC_DISCOVER_ST /* discover is in progress */
+};
+typedef uint8_t tBTA_GATTC_STATE;
+
+typedef struct {
+ bool in_use;
+ BD_ADDR server_bda;
+ bool connected;
+
+#define BTA_GATTC_SERV_IDLE 0
+#define BTA_GATTC_SERV_LOAD 1
+#define BTA_GATTC_SERV_SAVE 2
+#define BTA_GATTC_SERV_DISC 3
+#define BTA_GATTC_SERV_DISC_ACT 4
+
+ uint8_t state;
+
+ list_t* p_srvc_cache; /* list of tBTA_GATTC_SERVICE */
+ uint8_t update_count; /* indication received */
+ uint8_t num_clcb; /* number of associated CLCB */
+
+ tBTA_GATTC_ATTR_REC* p_srvc_list;
+ uint8_t cur_srvc_idx;
+ uint8_t cur_char_idx;
+ uint8_t next_avail_idx;
+ uint8_t total_srvc;
+ uint8_t total_char;
+
+ uint8_t srvc_hdl_chg; /* service handle change indication pending */
+ uint16_t attr_index; /* cahce NV saving/loading attribute index */
+
+ uint16_t mtu;
+} tBTA_GATTC_SERV;
+
+#ifndef BTA_GATTC_NOTIF_REG_MAX
+#define BTA_GATTC_NOTIF_REG_MAX 15
+#endif
+
+typedef struct {
+ bool in_use;
+ BD_ADDR remote_bda;
+ uint16_t handle;
+} tBTA_GATTC_NOTIF_REG;
+
+typedef struct {
+ tBTA_GATTC_CBACK* p_cback;
+ bool in_use;
+ tBTA_GATTC_IF
+ client_if; /* client interface with BTE stack for this application */
+ uint8_t num_clcb; /* number of associated CLCB */
+ bool dereg_pending;
+ tBT_UUID app_uuid;
+ tBTA_GATTC_NOTIF_REG notif_reg[BTA_GATTC_NOTIF_REG_MAX];
+} tBTA_GATTC_RCB;
+
+/* client channel is a mapping between a BTA client(cl_id) and a remote BD
+ * address */
+typedef struct {
+ uint16_t bta_conn_id; /* client channel ID, unique for clcb */
+ BD_ADDR bda;
+ tBTA_TRANSPORT transport; /* channel transport */
+ tBTA_GATTC_RCB* p_rcb; /* pointer to the registration CB */
+ tBTA_GATTC_SERV* p_srcb; /* server cache CB */
+ tBTA_GATTC_DATA* p_q_cmd; /* command in queue waiting for execution */
+
+#define BTA_GATTC_NO_SCHEDULE 0
+#define BTA_GATTC_DISC_WAITING 0x01
+#define BTA_GATTC_REQ_WAITING 0x10
+
+ uint8_t auto_update; /* auto update is waiting */
+ bool disc_active;
+ bool in_use;
+ tBTA_GATTC_STATE state;
+ tBTA_GATT_STATUS status;
+ uint16_t reason;
+} tBTA_GATTC_CLCB;
+
+/* back ground connection tracking information */
+#if GATT_MAX_APPS <= 8
+typedef uint8_t tBTA_GATTC_CIF_MASK;
+#elif GATT_MAX_APPS <= 16
+typedef uint16_t tBTA_GATTC_CIF_MASK;
+#elif GATT_MAX_APPS <= 32
+typedef uint32_t tBTA_GATTC_CIF_MASK;
+/** M: Feature change for FW multi-links, 7BR+32BLE @{ */
+#elif GATT_MAX_APPS <= 64
+typedef uint64_t tBTA_GATTC_CIF_MASK;
+/** @} */
+#endif
+
+typedef struct {
+ bool in_use;
+ BD_ADDR remote_bda;
+ tBTA_GATTC_CIF_MASK cif_mask;
+
+} tBTA_GATTC_BG_TCK;
+
+typedef struct {
+ bool in_use;
+ BD_ADDR remote_bda;
+} tBTA_GATTC_CONN;
+
+enum {
+ BTA_GATTC_STATE_DISABLED,
+ BTA_GATTC_STATE_ENABLING,
+ BTA_GATTC_STATE_ENABLED,
+ BTA_GATTC_STATE_DISABLING
+};
+
+typedef struct {
+ uint8_t state;
+
+ tBTA_GATTC_CONN conn_track[BTA_GATTC_CONN_MAX];
+ tBTA_GATTC_BG_TCK bg_track[BTA_GATTC_KNOWN_SR_MAX];
+ tBTA_GATTC_RCB cl_rcb[BTA_GATTC_CL_MAX];
+
+ tBTA_GATTC_CLCB clcb[BTA_GATTC_CLCB_MAX];
+ tBTA_GATTC_SERV known_server[BTA_GATTC_KNOWN_SR_MAX];
+} tBTA_GATTC_CB;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+extern tBTA_GATTC_CB bta_gattc_cb;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+extern bool bta_gattc_hdl_event(BT_HDR* p_msg);
+extern bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
+ tBTA_GATTC_DATA* p_data);
+
+/* function processed outside SM */
+extern void bta_gattc_disable();
+extern void bta_gattc_register(tBT_UUID* p_app_uuid, tBTA_GATTC_CBACK* p_data,
+ BtaAppRegisterCallback cb);
+extern void bta_gattc_start_if(tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_process_api_open(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_process_api_open_cancel(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_deregister(tBTA_GATTC_RCB* p_clreg);
+extern void bta_gattc_process_enc_cmpl(tBTA_GATTC_DATA* p_msg);
+
+/* function within state machine */
+extern void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_cancel_open(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_cancel_open_ok(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_cancel_open_error(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_conn(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_close(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_close_fail(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_disc_close(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+
+extern void bta_gattc_start_discover(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_read(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_write(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_q_cmd(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_search(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_fail(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_confirm(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_execute(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_read_multi(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ci_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ci_close(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_ignore_op_cmpl(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN* p_data,
+ tBTA_GATTC_RCB* p_clreg);
+extern void bta_gattc_cancel_bk_conn(tBTA_GATTC_API_CANCEL_OPEN* p_data);
+extern void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg,
+ tBTA_GATT_STATUS status,
+ BD_ADDR remote_bda, uint16_t conn_id,
+ tBTA_TRANSPORT transport, uint16_t mtu);
+extern void bta_gattc_process_api_refresh(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+extern void bta_gattc_listen(tBTA_GATTC_DATA* p_msg);
+extern void bta_gattc_broadcast(tBTA_GATTC_DATA* p_msg);
+
+/* utility functions */
+extern tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport);
+extern tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id);
+extern tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport);
+extern void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb);
+extern tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport);
+extern tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if);
+extern tBTA_GATTC_SERV* bta_gattc_find_srcb(BD_ADDR bda);
+extern tBTA_GATTC_SERV* bta_gattc_srcb_alloc(BD_ADDR bda);
+extern tBTA_GATTC_SERV* bta_gattc_find_scb_by_cid(uint16_t conn_id);
+extern tBTA_GATTC_CLCB* bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA* p_msg);
+extern tBTA_GATTC_CLCB* bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA* p_msg);
+
+extern bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data);
+
+extern bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
+ bool is_precise);
+extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
+ tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATTC_NOTIFY* p_notify);
+extern bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if,
+ BD_ADDR_PTR remote_bda, bool add);
+extern bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ uint8_t role);
+extern uint8_t bta_gattc_num_reg_app(void);
+extern void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV* p_srcb,
+ uint16_t conn_id,
+ uint16_t start_handle,
+ uint16_t end_handle);
+extern tBTA_GATTC_SERV* bta_gattc_find_srvr_cache(BD_ADDR bda);
+
+/* discovery functions */
+extern void bta_gattc_disc_res_cback(uint16_t conn_id,
+ tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data);
+extern void bta_gattc_disc_cmpl_cback(uint16_t conn_id,
+ tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status);
+extern tBTA_GATT_STATUS bta_gattc_discover_procedure(
+ uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
+extern tBTA_GATT_STATUS bta_gattc_discover_pri_service(
+ uint16_t conn_id, tBTA_GATTC_SERV* p_server_cb, uint8_t disc_type);
+extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb, tBT_UUID* p_uuid);
+extern const list_t* bta_gattc_get_services(uint16_t conn_id);
+extern const tBTA_GATTC_SERVICE* bta_gattc_get_service_for_handle(
+ uint16_t conn_id, uint16_t handle);
+tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic_srcb(
+ tBTA_GATTC_SERV* p_srcb, uint16_t handle);
+extern tBTA_GATTC_CHARACTERISTIC* bta_gattc_get_characteristic(uint16_t conn_id,
+ uint16_t handle);
+extern tBTA_GATTC_DESCRIPTOR* bta_gattc_get_descriptor(uint16_t conn_id,
+ uint16_t handle);
+extern void bta_gattc_get_gatt_db(uint16_t conn_id, uint16_t start_handle,
+ uint16_t end_handle, btgatt_db_element_t** db,
+ int* count);
+extern tBTA_GATT_STATUS bta_gattc_init_cache(tBTA_GATTC_SERV* p_srvc_cb);
+extern void bta_gattc_rebuild_cache(tBTA_GATTC_SERV* p_srcv, uint16_t num_attr,
+ tBTA_GATTC_NV_ATTR* attr);
+extern void bta_gattc_cache_save(tBTA_GATTC_SERV* p_srvc_cb, uint16_t conn_id);
+extern void bta_gattc_reset_discover_st(tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATT_STATUS status);
+
+extern tBTA_GATTC_CONN* bta_gattc_conn_alloc(BD_ADDR remote_bda);
+extern tBTA_GATTC_CONN* bta_gattc_conn_find(BD_ADDR remote_bda);
+extern tBTA_GATTC_CONN* bta_gattc_conn_find_alloc(BD_ADDR remote_bda);
+extern bool bta_gattc_conn_dealloc(BD_ADDR remote_bda);
+
+extern bool bta_gattc_cache_load(tBTA_GATTC_CLCB* p_clcb);
+extern void bta_gattc_cache_reset(BD_ADDR server_bda);
+
+#endif /* BTA_GATTC_INT_H */
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_main.cc b/mtkbt/code/bt/bta/gatt/bta_gattc_main.cc
new file mode 100755
index 0000000..16efce0
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_main.cc
@@ -0,0 +1,509 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT client main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+ BTA_GATTC_OPEN,
+ BTA_GATTC_OPEN_FAIL,
+ BTA_GATTC_OPEN_ERROR,
+ BTA_GATTC_CANCEL_OPEN,
+ BTA_GATTC_CANCEL_OPEN_OK,
+ BTA_GATTC_CANCEL_OPEN_ERROR,
+ BTA_GATTC_CONN,
+ BTA_GATTC_START_DISCOVER,
+ BTA_GATTC_DISC_CMPL,
+
+ BTA_GATTC_Q_CMD,
+ BTA_GATTC_CLOSE,
+ BTA_GATTC_CLOSE_FAIL,
+ BTA_GATTC_READ,
+ BTA_GATTC_WRITE,
+
+ BTA_GATTC_OP_CMPL,
+ BTA_GATTC_SEARCH,
+ BTA_GATTC_FAIL,
+ BTA_GATTC_CONFIRM,
+ BTA_GATTC_EXEC,
+ BTA_GATTC_READ_MULTI,
+ BTA_GATTC_IGNORE_OP_CMPL,
+ BTA_GATTC_DISC_CLOSE,
+ BTA_GATTC_RESTART_DISCOVER,
+ BTA_GATTC_CFG_MTU,
+
+ BTA_GATTC_IGNORE
+};
+/* type for action functions */
+typedef void (*tBTA_GATTC_ACTION)(tBTA_GATTC_CLCB* p_clcb,
+ tBTA_GATTC_DATA* p_data);
+
+/* action function list */
+const tBTA_GATTC_ACTION bta_gattc_action[] = {bta_gattc_open,
+ bta_gattc_open_fail,
+ bta_gattc_open_error,
+ bta_gattc_cancel_open,
+ bta_gattc_cancel_open_ok,
+ bta_gattc_cancel_open_error,
+ bta_gattc_conn,
+ bta_gattc_start_discover,
+ bta_gattc_disc_cmpl,
+
+ bta_gattc_q_cmd,
+ bta_gattc_close,
+ bta_gattc_close_fail,
+ bta_gattc_read,
+ bta_gattc_write,
+
+ bta_gattc_op_cmpl,
+ bta_gattc_search,
+ bta_gattc_fail,
+ bta_gattc_confirm,
+ bta_gattc_execute,
+ bta_gattc_read_multi,
+ bta_gattc_ignore_op_cmpl,
+ bta_gattc_disc_close,
+ bta_gattc_restart_discover,
+ bta_gattc_cfg_mtu};
+
+/* state table information */
+#define BTA_GATTC_ACTIONS 1 /* number of actions */
+#define BTA_GATTC_NEXT_STATE 1 /* position of next state */
+#define BTA_GATTC_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const uint8_t bta_gattc_st_idle[][BTA_GATTC_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE_FAIL,
+ BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL, BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_IGNORE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for wait for open state */
+static const uint8_t bta_gattc_st_w4_conn[][BTA_GATTC_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_OPEN_FAIL,
+ BTA_GATTC_IDLE_ST},
+ /* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_CANCEL_OPEN_OK,
+ BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_W4_CONN_ST},
+
+ /* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CANCEL_OPEN,
+ BTA_GATTC_W4_CONN_ST},
+
+ /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_W4_CONN_ST},
+
+ /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_W4_CONN_ST},
+ /* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_OPEN_FAIL,
+ BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for open state */
+static const uint8_t bta_gattc_st_connected[][BTA_GATTC_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_CONN_ST},
+
+ /* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_READ, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_WRITE, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_EXEC, BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_CFG_MTU,
+ BTA_GATTC_CONN_ST},
+
+ /* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+ /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_SEARCH,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_READ_MULTI,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_CONN_ST},
+
+ /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_START_DISCOVER,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_OP_CMPL,
+ BTA_GATTC_CONN_ST},
+
+ /* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* state table for discover state */
+static const uint8_t bta_gattc_st_discover[][BTA_GATTC_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_GATTC_API_OPEN_EVT */ {BTA_GATTC_OPEN,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_INT_OPEN_FAIL_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_CANCEL_OPEN_EVT */ {BTA_GATTC_CANCEL_OPEN_ERROR,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_INT_CANCEL_OPEN_OK_EVT */ {BTA_GATTC_FAIL,
+ BTA_GATTC_DISCOVER_ST},
+
+ /* BTA_GATTC_API_READ_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_WRITE_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_EXEC_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_CFG_MTU_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+
+ /* BTA_GATTC_API_CLOSE_EVT */ {BTA_GATTC_DISC_CLOSE,
+ BTA_GATTC_DISCOVER_ST},
+
+ /* BTA_GATTC_API_SEARCH_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_CONFIRM_EVT */ {BTA_GATTC_CONFIRM,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_READ_MULTI_EVT */ {BTA_GATTC_Q_CMD,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_API_REFRESH_EVT */ {BTA_GATTC_IGNORE,
+ BTA_GATTC_DISCOVER_ST},
+
+ /* BTA_GATTC_INT_CONN_EVT */ {BTA_GATTC_CONN,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_INT_DISCOVER_EVT */ {BTA_GATTC_RESTART_DISCOVER,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_DISCOVER_CMPL_EVT */ {BTA_GATTC_DISC_CMPL,
+ BTA_GATTC_CONN_ST},
+ /* BTA_GATTC_OP_CMPL_EVT */ {BTA_GATTC_IGNORE_OP_CMPL,
+ BTA_GATTC_DISCOVER_ST},
+ /* BTA_GATTC_INT_DISCONN_EVT */ {BTA_GATTC_CLOSE, BTA_GATTC_IDLE_ST},
+
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_GATTC_ST_TBL)[BTA_GATTC_NUM_COLS];
+
+/* state table */
+const tBTA_GATTC_ST_TBL bta_gattc_st_tbl[] = {
+ bta_gattc_st_idle, bta_gattc_st_w4_conn, bta_gattc_st_connected,
+ bta_gattc_st_discover};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+tBTA_GATTC_CB bta_gattc_cb;
+
+#if (BTA_GATT_DEBUG == TRUE)
+static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code);
+static char* gattc_state_code(tBTA_GATTC_STATE state_code);
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_sm_execute
+ *
+ * Description State machine event handling function for GATTC
+ *
+ *
+ * Returns bool : true if queued client request buffer can be
+ * immediately released, else false
+ *
+ ******************************************************************************/
+bool bta_gattc_sm_execute(tBTA_GATTC_CLCB* p_clcb, uint16_t event,
+ tBTA_GATTC_DATA* p_data) {
+ tBTA_GATTC_ST_TBL state_table;
+ uint8_t action;
+ int i;
+ bool rt = true;
+#if (BTA_GATT_DEBUG == TRUE)
+ tBTA_GATTC_STATE in_state = p_clcb->state;
+ uint16_t in_event = event;
+ APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]",
+ in_state, gattc_state_code(in_state), in_event,
+ gattc_evt_code(in_event));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_gattc_st_tbl[p_clcb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_GATTC_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_GATTC_IGNORE) {
+ (*bta_gattc_action[action])(p_clcb, p_data);
+ if (p_clcb->p_q_cmd == p_data) {
+ /* buffer is queued, don't free in the bta dispatcher.
+ * we free it ourselves when a completion event is received.
+ */
+ rt = false;
+ }
+ } else {
+ break;
+ }
+ }
+
+#if (BTA_GATT_DEBUG == TRUE)
+ if (in_state != p_clcb->state) {
+ APPL_TRACE_DEBUG("GATTC State Change: [%s] -> [%s] after Event [%s]",
+ gattc_state_code(in_state),
+ gattc_state_code(p_clcb->state), gattc_evt_code(in_event));
+ }
+#endif
+ return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_hdl_event
+ *
+ * Description GATT client main event handling function.
+ *
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool bta_gattc_hdl_event(BT_HDR* p_msg) {
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+ tBTA_GATTC_RCB* p_clreg;
+ bool rt = true;
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]",
+ gattc_evt_code(p_msg->event));
+#endif
+ switch (p_msg->event) {
+ case BTA_GATTC_API_DISABLE_EVT:
+ bta_gattc_disable();
+ break;
+
+ case BTA_GATTC_INT_START_IF_EVT:
+ bta_gattc_start_if((tBTA_GATTC_DATA*)p_msg);
+ break;
+
+ case BTA_GATTC_API_DEREG_EVT:
+ p_clreg = bta_gattc_cl_get_regcb(
+ ((tBTA_GATTC_DATA*)p_msg)->api_dereg.client_if);
+ bta_gattc_deregister(p_clreg);
+ break;
+
+ case BTA_GATTC_API_OPEN_EVT:
+ bta_gattc_process_api_open((tBTA_GATTC_DATA*)p_msg);
+ break;
+
+ case BTA_GATTC_API_CANCEL_OPEN_EVT:
+ bta_gattc_process_api_open_cancel((tBTA_GATTC_DATA*)p_msg);
+ break;
+
+ case BTA_GATTC_API_REFRESH_EVT:
+ bta_gattc_process_api_refresh((tBTA_GATTC_DATA*)p_msg);
+ break;
+
+ case BTA_GATTC_ENC_CMPL_EVT:
+ bta_gattc_process_enc_cmpl((tBTA_GATTC_DATA*)p_msg);
+ break;
+
+ default:
+ if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
+ p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA*)p_msg);
+ else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
+ p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA*)p_msg);
+ else
+ p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
+
+ if (p_clcb != NULL) {
+ rt =
+ bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA*)p_msg);
+ } else {
+ APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
+ }
+
+ break;
+ }
+
+ return rt;
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+#if (BTA_GATT_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function gattc_evt_code
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static char* gattc_evt_code(tBTA_GATTC_INT_EVT evt_code) {
+ switch (evt_code) {
+ case BTA_GATTC_API_OPEN_EVT:
+ return "BTA_GATTC_API_OPEN_EVT";
+ case BTA_GATTC_INT_OPEN_FAIL_EVT:
+ return "BTA_GATTC_INT_OPEN_FAIL_EVT";
+ case BTA_GATTC_API_CANCEL_OPEN_EVT:
+ return "BTA_GATTC_API_CANCEL_OPEN_EVT";
+ case BTA_GATTC_INT_CANCEL_OPEN_OK_EVT:
+ return "BTA_GATTC_INT_CANCEL_OPEN_OK_EVT";
+ case BTA_GATTC_API_READ_EVT:
+ return "BTA_GATTC_API_READ_EVT";
+ case BTA_GATTC_API_WRITE_EVT:
+ return "BTA_GATTC_API_WRITE_EVT";
+ case BTA_GATTC_API_EXEC_EVT:
+ return "BTA_GATTC_API_EXEC_EVT";
+ case BTA_GATTC_API_CLOSE_EVT:
+ return "BTA_GATTC_API_CLOSE_EVT";
+ case BTA_GATTC_API_SEARCH_EVT:
+ return "BTA_GATTC_API_SEARCH_EVT";
+ case BTA_GATTC_API_CONFIRM_EVT:
+ return "BTA_GATTC_API_CONFIRM_EVT";
+ case BTA_GATTC_API_READ_MULTI_EVT:
+ return "BTA_GATTC_API_READ_MULTI_EVT";
+ case BTA_GATTC_INT_CONN_EVT:
+ return "BTA_GATTC_INT_CONN_EVT";
+ case BTA_GATTC_INT_DISCOVER_EVT:
+ return "BTA_GATTC_INT_DISCOVER_EVT";
+ case BTA_GATTC_DISCOVER_CMPL_EVT:
+ return "BTA_GATTC_DISCOVER_CMPL_EVT";
+ case BTA_GATTC_OP_CMPL_EVT:
+ return "BTA_GATTC_OP_CMPL_EVT";
+ case BTA_GATTC_INT_DISCONN_EVT:
+ return "BTA_GATTC_INT_DISCONN_EVT";
+ case BTA_GATTC_INT_START_IF_EVT:
+ return "BTA_GATTC_INT_START_IF_EVT";
+ case BTA_GATTC_API_DEREG_EVT:
+ return "BTA_GATTC_API_DEREG_EVT";
+ case BTA_GATTC_API_REFRESH_EVT:
+ return "BTA_GATTC_API_REFRESH_EVT";
+ case BTA_GATTC_API_DISABLE_EVT:
+ return "BTA_GATTC_API_DISABLE_EVT";
+ case BTA_GATTC_API_CFG_MTU_EVT:
+ return "BTA_GATTC_API_CFG_MTU_EVT";
+ default:
+ return "unknown GATTC event code";
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gattc_state_code
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static char* gattc_state_code(tBTA_GATTC_STATE state_code) {
+ switch (state_code) {
+ case BTA_GATTC_IDLE_ST:
+ return "GATTC_IDLE_ST";
+ case BTA_GATTC_W4_CONN_ST:
+ return "GATTC_W4_CONN_ST";
+ case BTA_GATTC_CONN_ST:
+ return "GATTC_CONN_ST";
+ case BTA_GATTC_DISCOVER_ST:
+ return "GATTC_DISCOVER_ST";
+ default:
+ return "unknown GATTC state code";
+ }
+}
+
+#endif /* Debug Functions */
diff --git a/mtkbt/code/bt/bta/gatt/bta_gattc_utils.cc b/mtkbt/code/bt/bta/gatt/bta_gattc_utils.cc
new file mode 100755
index 0000000..53e4c18
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gattc_utils.cc
@@ -0,0 +1,746 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT client utility function.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_gattc"
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gattc_int.h"
+#include "bta_sys.h"
+#include "btcore/include/bdaddr.h"
+#include "l2c_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const uint8_t base_uuid[LEN_UUID_128] = {
+ 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const BD_ADDR dummy_bda = {0, 0, 0, 0, 0, 0};
+
+/*******************************************************************************
+ *
+ * Function bta_gatt_convert_uuid16_to_uuid128
+ *
+ * Description Convert a 16 bits UUID to be an standard 128 bits one.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint16_t uuid_16) {
+ uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_uuid_compare
+ *
+ * Description Compare two UUID to see if they are the same.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_uuid_compare(const tBT_UUID* p_src, const tBT_UUID* p_tar,
+ bool is_precise) {
+ uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+ const uint8_t *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (p_src == 0 || p_tar == 0) {
+ if (is_precise)
+ return false;
+ else
+ return true;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (p_src->len == 2 && p_tar->len == 2) {
+ return p_src->uu.uuid16 == p_tar->uu.uuid16;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (p_src->len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(su, p_src->uu.uuid16);
+ ps = su;
+ } else
+ ps = p_src->uu.uuid128;
+
+ if (p_tar->len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(tu, p_tar->uu.uuid16);
+ pt = tu;
+ } else
+ pt = p_tar->uu.uuid128;
+
+ return (memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_cl_get_regcb
+ *
+ * Description get registration control block by client interface.
+ *
+ * Returns pointer to the regcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_RCB* bta_gattc_cl_get_regcb(uint8_t client_if) {
+ uint8_t i = 0;
+ tBTA_GATTC_RCB* p_clrcb = &bta_gattc_cb.cl_rcb[0];
+
+ for (i = 0; i < BTA_GATTC_CL_MAX; i++, p_clrcb++) {
+ if (p_clrcb->in_use && p_clrcb->client_if == client_if) return p_clrcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_num_reg_app
+ *
+ * Description find the number of registered application.
+ *
+ * Returns pointer to the regcb
+ *
+ ******************************************************************************/
+uint8_t bta_gattc_num_reg_app(void) {
+ uint8_t i = 0, j = 0;
+
+ for (i = 0; i < BTA_GATTC_CL_MAX; i++) {
+ if (bta_gattc_cb.cl_rcb[i].in_use) j++;
+ }
+ return j;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_clcb_by_cif
+ *
+ * Description get clcb by client interface and remote bd adddress
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_cif(uint8_t client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport) {
+ tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->p_rcb->client_if == client_if &&
+ p_clcb->transport == transport && bdcmp(p_clcb->bda, remote_bda) == 0)
+ return p_clcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_clcb_by_conn_id
+ *
+ * Description get clcb by connection ID
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(uint16_t conn_id) {
+ tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_CLCB_MAX; i++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) return p_clcb;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_clcb_alloc
+ *
+ * Description allocate CLCB
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_clcb_alloc(tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport) {
+ uint8_t i_clcb = 0;
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0; i_clcb < BTA_GATTC_CLCB_MAX; i_clcb++) {
+ if (!bta_gattc_cb.clcb[i_clcb].in_use) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_gattc_clcb_alloc: found clcb[%d] available",
+ i_clcb);
+#endif
+ p_clcb = &bta_gattc_cb.clcb[i_clcb];
+ p_clcb->in_use = true;
+ p_clcb->status = BTA_GATT_OK;
+ p_clcb->transport = transport;
+ bdcpy(p_clcb->bda, remote_bda);
+
+ p_clcb->p_rcb = bta_gattc_cl_get_regcb(client_if);
+
+ p_clcb->p_srcb = bta_gattc_find_srcb(remote_bda);
+ if (p_clcb->p_srcb == NULL)
+ p_clcb->p_srcb = bta_gattc_srcb_alloc(remote_bda);
+
+ if (p_clcb->p_rcb != NULL && p_clcb->p_srcb != NULL) {
+ p_clcb->p_srcb->num_clcb++;
+ p_clcb->p_rcb->num_clcb++;
+ } else {
+ /* release this clcb if clcb or srcb allocation failed */
+ p_clcb->in_use = false;
+ p_clcb = NULL;
+ }
+ break;
+ }
+ }
+ return p_clcb;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_alloc_clcb
+ *
+ * Description find or allocate CLCB if not found.
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_alloc_clcb(tBTA_GATTC_IF client_if,
+ BD_ADDR remote_bda,
+ tBTA_TRANSPORT transport) {
+ tBTA_GATTC_CLCB* p_clcb;
+
+ p_clcb = bta_gattc_find_clcb_by_cif(client_if, remote_bda, transport);
+ if (p_clcb == NULL) {
+ p_clcb = bta_gattc_clcb_alloc(client_if, remote_bda, transport);
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_clcb_dealloc
+ *
+ * Description Deallocte a clcb
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB* p_clcb) {
+ tBTA_GATTC_SERV* p_srcb = NULL;
+
+ if (p_clcb) {
+ p_srcb = p_clcb->p_srcb;
+ if (p_srcb->num_clcb) p_srcb->num_clcb--;
+
+ if (p_clcb->p_rcb->num_clcb) p_clcb->p_rcb->num_clcb--;
+
+ /* if the srcb is no longer needed, reset the state */
+ if (p_srcb->num_clcb == 0) {
+ p_srcb->connected = false;
+ p_srcb->state = BTA_GATTC_SERV_IDLE;
+ p_srcb->mtu = 0;
+
+ /* clean up cache */
+ if (p_srcb->p_srvc_cache) {
+ list_free(p_srcb->p_srvc_cache);
+ p_srcb->p_srvc_cache = NULL;
+ }
+ }
+
+ osi_free_and_reset((void**)&p_clcb->p_q_cmd);
+ memset(p_clcb, 0, sizeof(tBTA_GATTC_CLCB));
+ } else {
+ APPL_TRACE_ERROR("bta_gattc_clcb_dealloc p_clcb=NULL");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_srcb
+ *
+ * Description find server cache by remote bd address currently in use
+ *
+ * Returns pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_srcb(BD_ADDR bda) {
+ tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+ if (p_srcb->in_use && bdcmp(p_srcb->server_bda, bda) == 0) return p_srcb;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_srvr_cache
+ *
+ * Description find server cache by remote bd address
+ *
+ * Returns pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_srvr_cache(BD_ADDR bda) {
+ tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+ if (bdcmp(p_srcb->server_bda, bda) == 0) return p_srcb;
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_scb_by_cid
+ *
+ * Description find server control block by connection ID
+ *
+ * Returns pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_find_scb_by_cid(uint16_t conn_id) {
+ tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb)
+ return p_clcb->p_srcb;
+ else
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_srcb_alloc
+ *
+ * Description allocate server cache control block
+ *
+ * Returns pointer to the server cache.
+ *
+ ******************************************************************************/
+tBTA_GATTC_SERV* bta_gattc_srcb_alloc(BD_ADDR bda) {
+ tBTA_GATTC_SERV *p_tcb = &bta_gattc_cb.known_server[0], *p_recycle = NULL;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_tcb++) {
+ if (!p_tcb->in_use) {
+ found = true;
+ break;
+ } else if (!p_tcb->connected) {
+ p_recycle = p_tcb;
+ }
+ }
+
+ /* if not found, try to recycle one known device */
+ if (!found && !p_recycle)
+ p_tcb = NULL;
+ else if (!found && p_recycle)
+ p_tcb = p_recycle;
+
+ if (p_tcb != NULL) {
+ if (p_tcb->p_srvc_cache != NULL) list_free(p_tcb->p_srvc_cache);
+
+ osi_free_and_reset((void**)&p_tcb->p_srvc_list);
+ memset(p_tcb, 0, sizeof(tBTA_GATTC_SERV));
+
+ p_tcb->in_use = true;
+ bdcpy(p_tcb->server_bda, bda);
+ }
+ return p_tcb;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_enqueue
+ *
+ * Description enqueue a client request in clcb.
+ *
+ * Returns success or failure.
+ *
+ ******************************************************************************/
+bool bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) {
+ if (p_clcb->p_q_cmd == NULL) {
+ p_clcb->p_q_cmd = p_data;
+ return true;
+ }
+
+ APPL_TRACE_ERROR("%s: already has a pending command!!", __func__);
+ /* skip the callback now. ----- need to send callback ? */
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_check_notif_registry
+ *
+ * Description check if the service notificaition has been registered.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg,
+ tBTA_GATTC_SERV* p_srcb,
+ tBTA_GATTC_NOTIFY* p_notify) {
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (p_clreg->notif_reg[i].in_use &&
+ bdcmp(p_clreg->notif_reg[i].remote_bda, p_srcb->server_bda) == 0 &&
+ p_clreg->notif_reg[i].handle == p_notify->handle) {
+ APPL_TRACE_DEBUG("Notification registered!");
+ return true;
+ }
+ }
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_clear_notif_registration
+ *
+ * Description Clear up the notification registration information by
+ * BD_ADDR.
+ * Where handle is between start_handle and end_handle, and
+ * start_handle and end_handle are boundaries of service
+ * containing characteristic.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void bta_gattc_clear_notif_registration(tBTA_GATTC_SERV* p_srcb,
+ uint16_t conn_id, uint16_t start_handle,
+ uint16_t end_handle) {
+ BD_ADDR remote_bda;
+ tBTA_GATTC_IF gatt_if;
+ tBTA_GATTC_RCB* p_clrcb;
+ uint8_t i;
+ tGATT_TRANSPORT transport;
+ uint16_t handle;
+
+ if (GATT_GetConnectionInfor(conn_id, &gatt_if, remote_bda, &transport)) {
+ p_clrcb = bta_gattc_cl_get_regcb(gatt_if);
+ if (p_clrcb != NULL) {
+ for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i++) {
+ if (p_clrcb->notif_reg[i].in_use &&
+ !bdcmp(p_clrcb->notif_reg[i].remote_bda, remote_bda)) {
+ /* It's enough to get service or characteristic handle, as
+ * clear boundaries are always around service.
+ */
+ handle = p_clrcb->notif_reg[i].handle;
+ if (handle >= start_handle && handle <= end_handle)
+ memset(&p_clrcb->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));
+ }
+ }
+ }
+ } else {
+ APPL_TRACE_ERROR(
+ "can not clear indication/notif registration for unknown app");
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_mark_bg_conn
+ *
+ * Description mark background connection status when a bg connection is
+ * initiated or terminated.
+ *
+ * Returns true if success; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_mark_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR_PTR remote_bda_ptr,
+ bool add) {
+ tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
+ uint8_t i = 0;
+ tBTA_GATTC_CIF_MASK* p_cif_mask;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+ if (p_bg_tck->in_use &&
+ ((remote_bda_ptr != NULL &&
+ bdcmp(p_bg_tck->remote_bda, remote_bda_ptr) == 0) ||
+ (remote_bda_ptr == NULL &&
+ bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0))) {
+ p_cif_mask = &p_bg_tck->cif_mask;
+
+ if (add) /* mask on the cif bit */
+ *p_cif_mask |= (1 << (client_if - 1));
+ else {
+ if (client_if != 0)
+ *p_cif_mask &= (~(1 << (client_if - 1)));
+ else
+ *p_cif_mask = 0;
+ }
+ /* no BG connection for this device, make it available */
+ if (p_bg_tck->cif_mask == 0) {
+ memset(p_bg_tck, 0, sizeof(tBTA_GATTC_BG_TCK));
+ }
+ return true;
+ }
+ }
+ if (!add) {
+ if (remote_bda_ptr) {
+ bdstr_t bdstr = {0};
+ APPL_TRACE_ERROR(
+ "%s unable to find the bg connection mask for: %s", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)remote_bda_ptr, bdstr, sizeof(bdstr)));
+ }
+ return false;
+ } else /* adding a new device mask */
+ {
+ for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0];
+ i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+ if (!p_bg_tck->in_use) {
+ p_bg_tck->in_use = true;
+ if (remote_bda_ptr)
+ bdcpy(p_bg_tck->remote_bda, remote_bda_ptr);
+ else
+ bdcpy(p_bg_tck->remote_bda, dummy_bda);
+
+ p_cif_mask = &p_bg_tck->cif_mask;
+
+ *p_cif_mask = (1 << (client_if - 1));
+ return true;
+ }
+ }
+ APPL_TRACE_ERROR("no available space to mark the bg connection status");
+ return false;
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_check_bg_conn
+ *
+ * Description check if this is a background connection background
+ * connection.
+ *
+ * Returns true if success; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gattc_check_bg_conn(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ uint8_t role) {
+ tBTA_GATTC_BG_TCK* p_bg_tck = &bta_gattc_cb.bg_track[0];
+ uint8_t i = 0;
+ bool is_bg_conn = false;
+
+ for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX && !is_bg_conn; i++, p_bg_tck++) {
+ if (p_bg_tck->in_use && (bdcmp(p_bg_tck->remote_bda, remote_bda) == 0 ||
+ bdcmp(p_bg_tck->remote_bda, dummy_bda) == 0)) {
+ if (((p_bg_tck->cif_mask & (1 << (client_if - 1))) != 0) &&
+ role == HCI_ROLE_MASTER)
+ is_bg_conn = true;
+ }
+ }
+ return is_bg_conn;
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_send_open_cback
+ *
+ * Description send open callback
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_gattc_send_open_cback(tBTA_GATTC_RCB* p_clreg, tBTA_GATT_STATUS status,
+ BD_ADDR remote_bda, uint16_t conn_id,
+ tBTA_TRANSPORT transport, uint16_t mtu) {
+ tBTA_GATTC cb_data;
+
+ if (p_clreg->p_cback) {
+ memset(&cb_data, 0, sizeof(tBTA_GATTC));
+
+ cb_data.open.status = status;
+ cb_data.open.client_if = p_clreg->client_if;
+ cb_data.open.conn_id = conn_id;
+ cb_data.open.mtu = mtu;
+ cb_data.open.transport = transport;
+ bdcpy(cb_data.open.remote_bda, remote_bda);
+
+ (*p_clreg->p_cback)(BTA_GATTC_OPEN_EVT, &cb_data);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn_alloc
+ *
+ * Description allocate connection tracking spot
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_alloc(BD_ADDR remote_bda) {
+ uint8_t i_conn = 0;
+ tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
+
+ for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+ if (!p_conn->in_use) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_gattc_conn_alloc: found conn_track[%d] available",
+ i_conn);
+#endif
+ p_conn->in_use = true;
+ bdcpy(p_conn->remote_bda, remote_bda);
+ return p_conn;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn_find
+ *
+ * Description allocate connection tracking spot
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_find(BD_ADDR remote_bda) {
+ uint8_t i_conn = 0;
+ tBTA_GATTC_CONN* p_conn = &bta_gattc_cb.conn_track[0];
+
+ for (i_conn = 0; i_conn < BTA_GATTC_CONN_MAX; i_conn++, p_conn++) {
+ if (p_conn->in_use && bdcmp(remote_bda, p_conn->remote_bda) == 0) {
+#if (BTA_GATT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_gattc_conn_find: found conn_track[%d] matched",
+ i_conn);
+#endif
+ return p_conn;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn_find_alloc
+ *
+ * Description find or allocate connection tracking spot
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CONN* bta_gattc_conn_find_alloc(BD_ADDR remote_bda) {
+ tBTA_GATTC_CONN* p_conn = bta_gattc_conn_find(remote_bda);
+
+ if (p_conn == NULL) {
+ p_conn = bta_gattc_conn_alloc(remote_bda);
+ }
+ return p_conn;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_conn_dealloc
+ *
+ * Description de-allocate connection tracking spot
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+bool bta_gattc_conn_dealloc(BD_ADDR remote_bda) {
+ tBTA_GATTC_CONN* p_conn = bta_gattc_conn_find(remote_bda);
+
+ if (p_conn != NULL) {
+ p_conn->in_use = false;
+ memset(p_conn->remote_bda, 0, BD_ADDR_LEN);
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_int_conn_clcb
+ *
+ * Description try to locate a clcb when an internal connecion event
+ * arrives.
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_int_conn_clcb(tBTA_GATTC_DATA* p_msg) {
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+
+ if (p_msg->int_conn.role == HCI_ROLE_SLAVE)
+ bta_gattc_conn_find_alloc(p_msg->int_conn.remote_bda);
+
+ /* try to locate a logic channel */
+ p_clcb = bta_gattc_find_clcb_by_cif(p_msg->int_conn.client_if,
+ p_msg->int_conn.remote_bda,
+ p_msg->int_conn.transport);
+ if (p_clcb == NULL) {
+ /* for a background connection or listening connection */
+ if (/*p_msg->int_conn.role == HCI_ROLE_SLAVE || */
+ bta_gattc_check_bg_conn(p_msg->int_conn.client_if,
+ p_msg->int_conn.remote_bda,
+ p_msg->int_conn.role)) {
+ /* allocate a new channel */
+ p_clcb = bta_gattc_clcb_alloc(p_msg->int_conn.client_if,
+ p_msg->int_conn.remote_bda,
+ p_msg->int_conn.transport);
+ }
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gattc_find_int_disconn_clcb
+ *
+ * Description try to locate a clcb when an internal disconnect callback
+ * arrives.
+ *
+ * Returns pointer to the clcb
+ *
+ ******************************************************************************/
+tBTA_GATTC_CLCB* bta_gattc_find_int_disconn_clcb(tBTA_GATTC_DATA* p_msg) {
+ tBTA_GATTC_CLCB* p_clcb = NULL;
+
+ bta_gattc_conn_dealloc(p_msg->int_conn.remote_bda);
+ p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->int_conn.hdr.layer_specific);
+ if (p_clcb == NULL) {
+ /* connection attempt failed, send connection callback event */
+ p_clcb = bta_gattc_find_clcb_by_cif(p_msg->int_conn.client_if,
+ p_msg->int_conn.remote_bda,
+ p_msg->int_conn.transport);
+ }
+ if (p_clcb == NULL) {
+ APPL_TRACE_DEBUG(" disconnection ID: [%d] not used by BTA",
+ p_msg->int_conn.hdr.layer_specific);
+ }
+ return p_clcb;
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gatts_act.cc b/mtkbt/code/bt/bta/gatt/bta_gatts_act.cc
new file mode 100755
index 0000000..86dfd9a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gatts_act.cc
@@ -0,0 +1,683 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT Server action functions for the state
+ * machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "bt_common.h"
+#include "bta_gatts_co.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+#include "btif/include/btif_debug_conn.h"
+#include "btm_ble_api.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+static void bta_gatts_nv_save_cback(bool is_saved,
+ tGATTS_HNDL_RANGE* p_hndl_range);
+static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
+ tGATTS_SRV_CHG_REQ* p_req,
+ tGATTS_SRV_CHG_RSP* p_rsp);
+
+static void bta_gatts_conn_cback(tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tGATT_TRANSPORT transport);
+static void bta_gatts_send_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE req_type,
+ tGATTS_DATA* p_data);
+static void bta_gatts_cong_cback(uint16_t conn_id, bool congested);
+static void bta_gatts_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status);
+static void bta_gatts_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout, uint8_t status);
+
+static tGATT_CBACK bta_gatts_cback = {bta_gatts_conn_cback,
+ NULL,
+ NULL,
+ NULL,
+ bta_gatts_send_request_cback,
+ NULL,
+ bta_gatts_cong_cback,
+ bta_gatts_phy_update_cback,
+ bta_gatts_conn_update_cback};
+
+tGATT_APPL_INFO bta_gatts_nv_cback = {bta_gatts_nv_save_cback,
+ bta_gatts_nv_srv_chg_cback};
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_nv_save_cback
+ *
+ * Description NV save callback function.
+ *
+ * Parameter is_add: true is to add a handle range; otherwise is to
+ * delete.
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gatts_nv_save_cback(bool is_add,
+ tGATTS_HNDL_RANGE* p_hndl_range) {
+ bta_gatts_co_update_handle_range(is_add,
+ (tBTA_GATTS_HNDL_RANGE*)p_hndl_range);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_nv_srv_chg_cback
+ *
+ * Description NV save callback function.
+ *
+ * Parameter is_add: true is to add a handle range; otherwise is to
+ * delete.
+ * Returns none.
+ *
+ ******************************************************************************/
+static bool bta_gatts_nv_srv_chg_cback(tGATTS_SRV_CHG_CMD cmd,
+ tGATTS_SRV_CHG_REQ* p_req,
+ tGATTS_SRV_CHG_RSP* p_rsp) {
+ return bta_gatts_co_srv_chg((tBTA_GATTS_SRV_CHG_CMD)cmd,
+ (tBTA_GATTS_SRV_CHG_REQ*)p_req,
+ (tBTA_GATTS_SRV_CHG_RSP*)p_rsp);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_enable
+ *
+ * Description enable BTA GATTS module.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_enable(tBTA_GATTS_CB* p_cb) {
+ uint8_t index = 0;
+ tBTA_GATTS_HNDL_RANGE handle_range;
+
+ if (p_cb->enabled) {
+ APPL_TRACE_DEBUG("GATTS already enabled.");
+ } else {
+ memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
+
+ p_cb->enabled = true;
+
+ while (bta_gatts_co_load_handle_range(index, &handle_range)) {
+ GATTS_AddHandleRange((tGATTS_HNDL_RANGE*)&handle_range);
+ memset(&handle_range, 0, sizeof(tGATTS_HNDL_RANGE));
+ index++;
+ }
+
+ APPL_TRACE_DEBUG("bta_gatts_enable: num of handle range added=%d", index);
+
+ if (!GATTS_NVRegister(&bta_gatts_nv_cback)) {
+ APPL_TRACE_ERROR("BTA GATTS NV register failed.");
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_api_disable
+ *
+ * Description disable BTA GATTS module.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb) {
+ uint8_t i;
+
+ if (p_cb->enabled) {
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+ if (p_cb->rcb[i].in_use) {
+ GATT_Deregister(p_cb->rcb[i].gatt_if);
+ }
+ }
+ memset(p_cb, 0, sizeof(tBTA_GATTS_CB));
+ } else {
+ APPL_TRACE_ERROR("GATTS not enabled");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_register
+ *
+ * Description register an application.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_register(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS cb_data;
+ tBTA_GATT_STATUS status = BTA_GATT_OK;
+ uint8_t i, first_unuse = 0xff;
+
+ if (p_cb->enabled == false) {
+ bta_gatts_enable(p_cb);
+ }
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+ if (p_cb->rcb[i].in_use) {
+ if (bta_gatts_uuid_compare(p_cb->rcb[i].app_uuid,
+ p_msg->api_reg.app_uuid)) {
+ APPL_TRACE_ERROR("application already registered.");
+ status = BTA_GATT_DUP_REG;
+ break;
+ }
+ }
+ }
+
+ if (status == BTA_GATT_OK) {
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+ if (first_unuse == 0xff && !p_cb->rcb[i].in_use) {
+ first_unuse = i;
+ break;
+ }
+ }
+
+ cb_data.reg_oper.server_if = BTA_GATTS_INVALID_IF;
+ memcpy(&cb_data.reg_oper.uuid, &p_msg->api_reg.app_uuid, sizeof(tBT_UUID));
+ if (first_unuse != 0xff) {
+ APPL_TRACE_ERROR("register application first_unuse rcb_idx = %d",
+ first_unuse);
+
+ p_cb->rcb[first_unuse].in_use = true;
+ p_cb->rcb[first_unuse].p_cback = p_msg->api_reg.p_cback;
+ memcpy(&p_cb->rcb[first_unuse].app_uuid, &p_msg->api_reg.app_uuid,
+ sizeof(tBT_UUID));
+ cb_data.reg_oper.server_if = p_cb->rcb[first_unuse].gatt_if =
+ GATT_Register(&p_msg->api_reg.app_uuid, &bta_gatts_cback);
+ if (!p_cb->rcb[first_unuse].gatt_if) {
+ status = BTA_GATT_NO_RESOURCES;
+ } else {
+ tBTA_GATTS_INT_START_IF* p_buf = (tBTA_GATTS_INT_START_IF*)osi_malloc(
+ sizeof(tBTA_GATTS_INT_START_IF));
+ p_buf->hdr.event = BTA_GATTS_INT_START_IF_EVT;
+ p_buf->server_if = p_cb->rcb[first_unuse].gatt_if;
+
+ bta_sys_sendmsg(p_buf);
+ }
+ } else {
+ status = BTA_GATT_NO_RESOURCES;
+ }
+ }
+ cb_data.reg_oper.status = status;
+ if (p_msg->api_reg.p_cback)
+ (*p_msg->api_reg.p_cback)(BTA_GATTS_REG_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_start_if
+ *
+ * Description start an application interface.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_start_if(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_DATA* p_msg) {
+ if (bta_gatts_find_app_rcb_by_app_if(p_msg->int_start_if.server_if)) {
+ GATT_StartIf(p_msg->int_start_if.server_if);
+ } else {
+ APPL_TRACE_ERROR("Unable to start app.: Unknown interface =%d",
+ p_msg->int_start_if.server_if);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_deregister
+ *
+ * Description deregister an application.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_deregister(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+ tBTA_GATTS_CBACK* p_cback = NULL;
+ uint8_t i;
+ tBTA_GATTS cb_data;
+
+ cb_data.reg_oper.server_if = p_msg->api_dereg.server_if;
+ cb_data.reg_oper.status = status;
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+ if (p_cb->rcb[i].in_use &&
+ p_cb->rcb[i].gatt_if == p_msg->api_dereg.server_if) {
+ p_cback = p_cb->rcb[i].p_cback;
+ status = BTA_GATT_OK;
+
+ /* deregister the app */
+ GATT_Deregister(p_cb->rcb[i].gatt_if);
+
+ /* reset cb */
+ memset(&p_cb->rcb[i], 0, sizeof(tBTA_GATTS_RCB));
+ cb_data.reg_oper.status = status;
+ break;
+ }
+ }
+
+ if (p_cback) {
+ (*p_cback)(BTA_GATTS_DEREG_EVT, &cb_data);
+ } else {
+ APPL_TRACE_ERROR("application not registered.");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_delete_service
+ *
+ * Description action function to delete a service.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+ tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_RCB* p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ tBTA_GATTS cb_data;
+
+ cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+ // cb_data.srvc_oper.service_id = p_msg->api_add_incl_srvc.hdr.layer_specific;
+
+ if (GATTS_DeleteService(p_rcb->gatt_if, &p_srvc_cb->service_uuid,
+ p_srvc_cb->service_id)) {
+ cb_data.srvc_oper.status = BTA_GATT_OK;
+ memset(p_srvc_cb, 0, sizeof(tBTA_GATTS_SRVC_CB));
+ } else {
+ cb_data.srvc_oper.status = BTA_GATT_ERROR;
+ }
+
+ if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_DELELTE_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_stop_service
+ *
+ * Description action function to stop a service.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+ UNUSED_ATTR tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_RCB* p_rcb = &bta_gatts_cb.rcb[p_srvc_cb->rcb_idx];
+ tBTA_GATTS cb_data;
+
+ GATTS_StopService(p_srvc_cb->service_id);
+ cb_data.srvc_oper.server_if = p_rcb->gatt_if;
+ cb_data.srvc_oper.service_id = p_srvc_cb->service_id;
+ cb_data.srvc_oper.status = BTA_GATT_OK;
+ APPL_TRACE_ERROR("bta_gatts_stop_service service_id= %d",
+ p_srvc_cb->service_id);
+
+ if (p_rcb->p_cback) (*p_rcb->p_cback)(BTA_GATTS_STOP_EVT, &cb_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_send_rsp
+ *
+ * Description GATTS send response.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_send_rsp(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_DATA* p_msg) {
+ if (GATTS_SendRsp(p_msg->api_rsp.hdr.layer_specific, p_msg->api_rsp.trans_id,
+ p_msg->api_rsp.status,
+ (tGATTS_RSP*)p_msg->api_rsp.p_rsp) != GATT_SUCCESS) {
+ APPL_TRACE_ERROR("Sending response failed");
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_indicate_handle
+ *
+ * Description GATTS send handle value indication or notification.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_indicate_handle(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_SRVC_CB* p_srvc_cb;
+ tBTA_GATTS_RCB* p_rcb = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_ILLEGAL_PARAMETER;
+ tGATT_IF gatt_if;
+ BD_ADDR remote_bda;
+ tBTA_TRANSPORT transport;
+ tBTA_GATTS cb_data;
+
+ p_srvc_cb =
+ bta_gatts_find_srvc_cb_by_attr_id(p_cb, p_msg->api_indicate.attr_id);
+
+ if (p_srvc_cb) {
+ if (GATT_GetConnectionInfor(p_msg->api_indicate.hdr.layer_specific,
+ &gatt_if, remote_bda, &transport)) {
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_msg->api_indicate.need_confirm)
+
+ status = GATTS_HandleValueIndication(
+ p_msg->api_indicate.hdr.layer_specific, p_msg->api_indicate.attr_id,
+ p_msg->api_indicate.len, p_msg->api_indicate.value);
+ else
+ status = GATTS_HandleValueNotification(
+ p_msg->api_indicate.hdr.layer_specific, p_msg->api_indicate.attr_id,
+ p_msg->api_indicate.len, p_msg->api_indicate.value);
+
+ /* if over BR_EDR, inform PM for mode change */
+ if (transport == BTA_TRANSPORT_BR_EDR) {
+ bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+ bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+ }
+ } else {
+ APPL_TRACE_ERROR("Unknown connection ID: %d fail sending notification",
+ p_msg->api_indicate.hdr.layer_specific);
+ }
+
+ if ((status != GATT_SUCCESS || !p_msg->api_indicate.need_confirm) &&
+ p_rcb && p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) {
+ cb_data.req_data.status = status;
+ cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific;
+
+ (*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",
+ p_msg->api_indicate.attr_id);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_open
+ *
+ * Description
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_RCB* p_rcb = NULL;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+ uint16_t conn_id;
+
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_open.server_if);
+ if (p_rcb != NULL) {
+ /* should always get the connection ID */
+ if (GATT_Connect(p_rcb->gatt_if, p_msg->api_open.remote_bda,
+ p_msg->api_open.is_direct, p_msg->api_open.transport,
+ false)) {
+ status = BTA_GATT_OK;
+
+ if (GATT_GetConnIdIfConnected(p_rcb->gatt_if, p_msg->api_open.remote_bda,
+ &conn_id, p_msg->api_open.transport)) {
+ status = BTA_GATT_ALREADY_OPEN;
+ }
+ }
+ } else {
+ APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_open.server_if);
+ }
+
+ if (p_rcb && p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_OPEN_EVT, (tBTA_GATTS*)&status);
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_cancel_open
+ *
+ * Description
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_cancel_open(UNUSED_ATTR tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_RCB* p_rcb;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(p_msg->api_cancel_open.server_if);
+ if (p_rcb != NULL) {
+ if (!GATT_CancelConnect(p_rcb->gatt_if, p_msg->api_cancel_open.remote_bda,
+ p_msg->api_cancel_open.is_direct)) {
+ APPL_TRACE_ERROR("bta_gatts_cancel_open failed for open request");
+ } else {
+ status = BTA_GATT_OK;
+ }
+ } else {
+ APPL_TRACE_ERROR("Inavlide server_if=%d", p_msg->api_cancel_open.server_if);
+ }
+
+ if (p_rcb && p_rcb->p_cback)
+ (*p_rcb->p_cback)(BTA_GATTS_CANCEL_OPEN_EVT, (tBTA_GATTS*)&status);
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_close
+ *
+ * Description
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void bta_gatts_close(UNUSED_ATTR tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg) {
+ tBTA_GATTS_RCB* p_rcb;
+ tBTA_GATT_STATUS status = BTA_GATT_ERROR;
+ tGATT_IF gatt_if;
+ BD_ADDR remote_bda;
+ tBTA_GATT_TRANSPORT transport;
+
+ if (GATT_GetConnectionInfor(p_msg->hdr.layer_specific, &gatt_if, remote_bda,
+ &transport)) {
+ if (GATT_Disconnect(p_msg->hdr.layer_specific) != GATT_SUCCESS) {
+ APPL_TRACE_ERROR("bta_gatts_close fail conn_id=%d",
+ p_msg->hdr.layer_specific);
+ } else {
+ status = BTA_GATT_OK;
+ }
+
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_rcb && p_rcb->p_cback) {
+ if (transport == BTA_TRANSPORT_BR_EDR)
+ bta_sys_conn_close(BTA_ID_GATTS, BTA_ALL_APP_ID, remote_bda);
+
+ (*p_rcb->p_cback)(BTA_GATTS_CLOSE_EVT, (tBTA_GATTS*)&status);
+ }
+ } else {
+ APPL_TRACE_ERROR("Unknown connection ID: %d", p_msg->hdr.layer_specific);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_request_cback
+ *
+ * Description GATTS attribute request callback.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gatts_send_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE req_type,
+ tGATTS_DATA* p_data) {
+ tBTA_GATTS cb_data;
+ tBTA_GATTS_RCB* p_rcb;
+ tGATT_IF gatt_if;
+ tBTA_GATT_TRANSPORT transport;
+
+ memset(&cb_data, 0, sizeof(tBTA_GATTS));
+
+ if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda,
+ &transport)) {
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ APPL_TRACE_DEBUG("%s: conn_id=%d trans_id=%d req_type=%d", __func__,
+ conn_id, trans_id, req_type);
+
+ if (p_rcb && p_rcb->p_cback) {
+ /* if over BR_EDR, inform PM for mode change */
+ if (transport == BTA_TRANSPORT_BR_EDR) {
+ bta_sys_busy(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda);
+ bta_sys_idle(BTA_ID_GATTS, BTA_ALL_APP_ID, cb_data.req_data.remote_bda);
+ }
+
+ cb_data.req_data.conn_id = conn_id;
+ cb_data.req_data.trans_id = trans_id;
+ cb_data.req_data.p_data = (tBTA_GATTS_REQ_DATA*)p_data;
+
+ (*p_rcb->p_cback)(req_type, &cb_data);
+ } else {
+ APPL_TRACE_ERROR("connection request on gatt_if[%d] is not interested",
+ gatt_if);
+ }
+ } else {
+ APPL_TRACE_ERROR("request received on unknown connectino ID: %d", conn_id);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_conn_cback
+ *
+ * Description connection callback.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gatts_conn_cback(tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tGATT_TRANSPORT transport) {
+ tBTA_GATTS cb_data;
+ uint8_t evt = connected ? BTA_GATTS_CONNECT_EVT : BTA_GATTS_DISCONNECT_EVT;
+ tBTA_GATTS_RCB* p_reg;
+
+ APPL_TRACE_DEBUG(
+ "bta_gatts_conn_cback gatt_if=%d conn_id=%d connected=%d reason = 0x%04d",
+ gatt_if, conn_id, connected, reason);
+ APPL_TRACE_DEBUG("bta_gatts_conn_cback bda :%02x-%02x-%02x-%02x-%02x-%02x ",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ bt_bdaddr_t bdaddr;
+ bdcpy(bdaddr.address, bda);
+ if (connected)
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_CONNECTED, GATT_CONN_UNKNOWN);
+ else
+ btif_debug_conn_state(bdaddr, BTIF_DEBUG_DISCONNECTED, reason);
+
+ p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_reg && p_reg->p_cback) {
+ /* there is no RM for GATT */
+ if (transport == BTA_TRANSPORT_BR_EDR) {
+ if (connected)
+ bta_sys_conn_open(BTA_ID_GATTS, BTA_ALL_APP_ID, bda);
+ else
+ bta_sys_conn_close(BTA_ID_GATTS, BTA_ALL_APP_ID, bda);
+ }
+
+ cb_data.conn.conn_id = conn_id;
+ cb_data.conn.server_if = gatt_if;
+ cb_data.conn.reason = reason;
+ cb_data.conn.transport = transport;
+ memcpy(cb_data.conn.remote_bda, bda, BD_ADDR_LEN);
+ (*p_reg->p_cback)(evt, &cb_data);
+ } else {
+ APPL_TRACE_ERROR("bta_gatts_conn_cback server_if=%d not found", gatt_if);
+ }
+}
+
+static void bta_gatts_phy_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status) {
+ tBTA_GATTS_RCB* p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+ if (!p_reg || !p_reg->p_cback) {
+ APPL_TRACE_ERROR("%s: server_if=%d not found", __func__, gatt_if);
+ return;
+ }
+
+ tBTA_GATTS cb_data;
+ cb_data.phy_update.conn_id = conn_id;
+ cb_data.phy_update.server_if = gatt_if;
+ cb_data.phy_update.tx_phy = tx_phy;
+ cb_data.phy_update.rx_phy = rx_phy;
+ cb_data.phy_update.status = status;
+ (*p_reg->p_cback)(BTA_GATTS_PHY_UPDATE_EVT, &cb_data);
+}
+
+static void bta_gatts_conn_update_cback(tGATT_IF gatt_if, uint16_t conn_id,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout, uint8_t status) {
+ tBTA_GATTS_RCB* p_reg = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+ if (!p_reg || !p_reg->p_cback) {
+ APPL_TRACE_ERROR("%s: server_if=%d not found", __func__, gatt_if);
+ return;
+ }
+
+ tBTA_GATTS cb_data;
+ cb_data.conn_update.conn_id = conn_id;
+ cb_data.conn_update.server_if = gatt_if;
+ cb_data.conn_update.interval = interval;
+ cb_data.conn_update.latency = latency;
+ cb_data.conn_update.timeout = timeout;
+ cb_data.conn_update.status = status;
+ (*p_reg->p_cback)(BTA_GATTS_CONN_UPDATE_EVT, &cb_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_cong_cback
+ *
+ * Description congestion callback.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void bta_gatts_cong_cback(uint16_t conn_id, bool congested) {
+ tBTA_GATTS_RCB* p_rcb;
+ tGATT_IF gatt_if;
+ tBTA_GATT_TRANSPORT transport;
+ tBTA_GATTS cb_data;
+
+ if (GATT_GetConnectionInfor(conn_id, &gatt_if, cb_data.req_data.remote_bda,
+ &transport)) {
+ p_rcb = bta_gatts_find_app_rcb_by_app_if(gatt_if);
+
+ if (p_rcb && p_rcb->p_cback) {
+ cb_data.congest.conn_id = conn_id;
+ cb_data.congest.congested = congested;
+
+ (*p_rcb->p_cback)(BTA_GATTS_CONGEST_EVT, &cb_data);
+ }
+ }
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gatts_api.cc b/mtkbt/code/bt/bta/gatt/bta_gatts_api.cc
new file mode 100755
index 0000000..556185d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gatts_api.cc
@@ -0,0 +1,343 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2010-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for GATT server of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatt_api.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_gatts_reg = {bta_gatts_hdl_event,
+ BTA_GATTS_Disable};
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Disable
+ *
+ * Description This function is called to disable GATTS module
+ *
+ * Parameters None.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTS_Disable(void) {
+ if (bta_sys_is_register(BTA_ID_GATTS) == false) {
+ APPL_TRACE_WARNING("GATTS Module not enabled/already disabled");
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_GATTS_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ bta_sys_deregister(BTA_ID_GATTS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AppRegister
+ *
+ * Description This function is called to register application callbacks
+ * with BTA GATTS module.
+ *
+ * Parameters p_app_uuid - applicaiton UUID
+ * p_cback - pointer to the application callback function.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid, tBTA_GATTS_CBACK* p_cback) {
+ tBTA_GATTS_API_REG* p_buf =
+ (tBTA_GATTS_API_REG*)osi_malloc(sizeof(tBTA_GATTS_API_REG));
+
+ /* register with BTA system manager */
+ if (bta_sys_is_register(BTA_ID_GATTS) == false)
+ bta_sys_register(BTA_ID_GATTS, &bta_gatts_reg);
+
+ p_buf->hdr.event = BTA_GATTS_API_REG_EVT;
+ if (p_app_uuid != NULL)
+ memcpy(&p_buf->app_uuid, p_app_uuid, sizeof(tBT_UUID));
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AppDeregister
+ *
+ * Description De-register with GATT Server.
+ *
+ * Parameters app_id: applicatino ID.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if) {
+ tBTA_GATTS_API_DEREG* p_buf =
+ (tBTA_GATTS_API_DEREG*)osi_malloc(sizeof(tBTA_GATTS_API_DEREG));
+
+ p_buf->hdr.event = BTA_GATTS_API_DEREG_EVT;
+ p_buf->server_if = server_if;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AddService
+ *
+ * Description Add the given |service| and all included elements to the
+ * GATT database. a |BTA_GATTS_ADD_SRVC_EVT| is triggered to
+ * report the status and attribute handles.
+ *
+ * Parameters server_if: server interface.
+ * service: pointer vector describing service.
+ *
+ * Returns Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ * service cannot be added.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
+ vector<btgatt_db_element_t>& service) {
+ uint8_t rcb_idx =
+ bta_gatts_find_app_rcb_idx_by_app_if(&bta_gatts_cb, server_if);
+
+ APPL_TRACE_ERROR("%s: rcb_idx = %d", __func__, rcb_idx);
+
+ if (rcb_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
+
+ uint8_t srvc_idx = bta_gatts_alloc_srvc_cb(&bta_gatts_cb, rcb_idx);
+ if (srvc_idx == BTA_GATTS_INVALID_APP) return BTA_GATT_ERROR;
+
+ uint16_t status = GATTS_AddService(server_if, service.data(), service.size());
+
+ if (status == GATT_SERVICE_STARTED) {
+ btif_to_bta_uuid(&bta_gatts_cb.srvc_cb[srvc_idx].service_uuid,
+ &service[0].uuid);
+
+ // service_id is equal to service start handle
+ bta_gatts_cb.srvc_cb[srvc_idx].service_id = service[0].attribute_handle;
+ bta_gatts_cb.srvc_cb[srvc_idx].idx = srvc_idx;
+
+ return BTA_GATT_OK;
+ } else {
+ memset(&bta_gatts_cb.srvc_cb[srvc_idx], 0, sizeof(tBTA_GATTS_SRVC_CB));
+ APPL_TRACE_ERROR("%s: service creation failed.", __func__);
+ return BTA_GATT_ERROR;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_DeleteService
+ *
+ * Description This function is called to delete a service. When this is
+ * done, a callback event BTA_GATTS_DELETE_EVT is report with
+ * the status.
+ *
+ * Parameters service_id: service_id to be deleted.
+ *
+ * Returns returns none.
+ *
+ ******************************************************************************/
+void BTA_GATTS_DeleteService(uint16_t service_id) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_GATTS_API_DEL_SRVC_EVT;
+ p_buf->layer_specific = service_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_StopService
+ *
+ * Description This function is called to stop a service.
+ *
+ * Parameters service_id - service to be topped.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTS_StopService(uint16_t service_id) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_GATTS_API_STOP_SRVC_EVT;
+ p_buf->layer_specific = service_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_HandleValueIndication
+ *
+ * Description This function is called to read a characteristics
+ * descriptor.
+ *
+ * Parameters bda - remote device bd address to indicate.
+ * attr_id - attribute ID to indicate.
+ * value - data to indicate.
+ * need_confirm - if this indication expects a confirmation or
+ * not.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_id,
+ std::vector<uint8_t> value,
+ bool need_confirm) {
+ tBTA_GATTS_API_INDICATION* p_buf =
+ (tBTA_GATTS_API_INDICATION*)osi_calloc(sizeof(tBTA_GATTS_API_INDICATION));
+
+ p_buf->hdr.event = BTA_GATTS_API_INDICATION_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->attr_id = attr_id;
+ p_buf->need_confirm = need_confirm;
+ if (value.size() > 0) {
+ p_buf->len = value.size();
+ memcpy(p_buf->value, value.data(), value.size());
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_SendRsp
+ *
+ * Description This function is called to send a response to a request.
+ *
+ * Parameters conn_id - connection identifier.
+ * trans_id - transaction ID.
+ * status - response status
+ * p_msg - response data.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+ tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg) {
+ const size_t len = sizeof(tBTA_GATTS_API_RSP) + sizeof(tBTA_GATTS_RSP);
+ tBTA_GATTS_API_RSP* p_buf = (tBTA_GATTS_API_RSP*)osi_calloc(len);
+
+ p_buf->hdr.event = BTA_GATTS_API_RSP_EVT;
+ p_buf->hdr.layer_specific = conn_id;
+ p_buf->trans_id = trans_id;
+ p_buf->status = status;
+ if (p_msg != NULL) {
+ p_buf->p_rsp = (tBTA_GATTS_RSP*)(p_buf + 1);
+ memcpy(p_buf->p_rsp, p_msg, sizeof(tBTA_GATTS_RSP));
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Open
+ *
+ * Description Open a direct open connection or add a background auto
+ * connection bd address
+ *
+ * Parameters server_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ * transport : Transport on which GATT connection to be opened
+ * (BR/EDR or LE)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda, bool is_direct,
+ tBTA_GATT_TRANSPORT transport) {
+ tBTA_GATTS_API_OPEN* p_buf =
+ (tBTA_GATTS_API_OPEN*)osi_malloc(sizeof(tBTA_GATTS_API_OPEN));
+
+ p_buf->hdr.event = BTA_GATTS_API_OPEN_EVT;
+ p_buf->server_if = server_if;
+ p_buf->is_direct = is_direct;
+ p_buf->transport = transport;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_CancelOpen
+ *
+ * Description Cancel a direct open connection or remove a background auto
+ * connection bd address
+ *
+ * Parameters server_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+ bool is_direct) {
+ tBTA_GATTS_API_CANCEL_OPEN* p_buf = (tBTA_GATTS_API_CANCEL_OPEN*)osi_malloc(
+ sizeof(tBTA_GATTS_API_CANCEL_OPEN));
+
+ p_buf->hdr.event = BTA_GATTS_API_CANCEL_OPEN_EVT;
+ p_buf->server_if = server_if;
+ p_buf->is_direct = is_direct;
+ memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Close
+ *
+ * Description Close a connection a remote device.
+ *
+ * Parameters conn_id: connectino ID to be closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_GATTS_Close(uint16_t conn_id) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_GATTS_API_CLOSE_EVT;
+ p_buf->layer_specific = conn_id;
+
+ bta_sys_sendmsg(p_buf);
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gatts_int.h b/mtkbt/code/bt/bta/gatt/bta_gatts_int.h
new file mode 100755
index 0000000..91bd9fe
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gatts_int.h
@@ -0,0 +1,189 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private file for the BTA GATT server.
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTS_INT_H
+#define BTA_GATTS_INT_H
+
+#include "bt_target.h"
+#include "bta_gatt_api.h"
+#include "bta_sys.h"
+#include "gatt_api.h"
+
+#include "bt_common.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+enum {
+ BTA_GATTS_API_REG_EVT = BTA_SYS_EVT_START(BTA_ID_GATTS),
+ BTA_GATTS_INT_START_IF_EVT,
+ BTA_GATTS_API_DEREG_EVT,
+ BTA_GATTS_API_INDICATION_EVT,
+
+ BTA_GATTS_API_DEL_SRVC_EVT,
+ BTA_GATTS_API_STOP_SRVC_EVT,
+ BTA_GATTS_API_RSP_EVT,
+ BTA_GATTS_API_OPEN_EVT,
+ BTA_GATTS_API_CANCEL_OPEN_EVT,
+ BTA_GATTS_API_CLOSE_EVT,
+ BTA_GATTS_API_DISABLE_EVT
+};
+typedef uint16_t tBTA_GATTS_INT_EVT;
+
+/* max number of application allowed on device */
+#define BTA_GATTS_MAX_APP_NUM GATT_MAX_SR_PROFILES
+
+/* max number of services allowed in the device */
+#define BTA_GATTS_MAX_SRVC_NUM GATT_MAX_SR_PROFILES
+
+/* internal strucutre for GATTC register API */
+typedef struct {
+ BT_HDR hdr;
+ tBT_UUID app_uuid;
+ tBTA_GATTS_CBACK* p_cback;
+} tBTA_GATTS_API_REG;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATTS_IF server_if;
+} tBTA_GATTS_INT_START_IF;
+
+typedef tBTA_GATTS_INT_START_IF tBTA_GATTS_API_DEREG;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATTS_IF server_if;
+ btgatt_db_element_t* service;
+ uint16_t count;
+} tBTA_GATTS_API_ADD_SERVICE;
+
+typedef struct {
+ BT_HDR hdr;
+ uint16_t attr_id;
+ uint16_t len;
+ bool need_confirm;
+ uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+} tBTA_GATTS_API_INDICATION;
+
+typedef struct {
+ BT_HDR hdr;
+ uint32_t trans_id;
+ tBTA_GATT_STATUS status;
+ tBTA_GATTS_RSP* p_rsp;
+} tBTA_GATTS_API_RSP;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_GATT_TRANSPORT transport;
+} tBTA_GATTS_API_START;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR remote_bda;
+ tBTA_GATTS_IF server_if;
+ bool is_direct;
+ tBTA_GATT_TRANSPORT transport;
+
+} tBTA_GATTS_API_OPEN;
+
+typedef tBTA_GATTS_API_OPEN tBTA_GATTS_API_CANCEL_OPEN;
+
+typedef union {
+ BT_HDR hdr;
+ tBTA_GATTS_API_REG api_reg;
+ tBTA_GATTS_API_DEREG api_dereg;
+ tBTA_GATTS_API_ADD_SERVICE api_add_service;
+ tBTA_GATTS_API_INDICATION api_indicate;
+ tBTA_GATTS_API_RSP api_rsp;
+ tBTA_GATTS_API_OPEN api_open;
+ tBTA_GATTS_API_CANCEL_OPEN api_cancel_open;
+
+ tBTA_GATTS_INT_START_IF int_start_if;
+} tBTA_GATTS_DATA;
+
+/* application registration control block */
+typedef struct {
+ bool in_use;
+ tBT_UUID app_uuid;
+ tBTA_GATTS_CBACK* p_cback;
+ tBTA_GATTS_IF gatt_if;
+} tBTA_GATTS_RCB;
+
+/* service registration control block */
+typedef struct {
+ tBT_UUID service_uuid; /* service UUID */
+ uint16_t service_id; /* service start handle */
+ uint8_t rcb_idx;
+ uint8_t idx; /* self index of serviec CB */
+ bool in_use;
+} tBTA_GATTS_SRVC_CB;
+
+/* GATT server control block */
+typedef struct {
+ bool enabled;
+ tBTA_GATTS_RCB rcb[BTA_GATTS_MAX_APP_NUM];
+ tBTA_GATTS_SRVC_CB srvc_cb[BTA_GATTS_MAX_SRVC_NUM];
+} tBTA_GATTS_CB;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* GATTC control block */
+extern tBTA_GATTS_CB bta_gatts_cb;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+extern bool bta_gatts_hdl_event(BT_HDR* p_msg);
+
+extern void bta_gatts_api_disable(tBTA_GATTS_CB* p_cb);
+extern void bta_gatts_api_enable(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_data);
+extern void bta_gatts_register(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_start_if(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_deregister(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_delete_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+ tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_stop_service(tBTA_GATTS_SRVC_CB* p_srvc_cb,
+ tBTA_GATTS_DATA* p_msg);
+
+extern void bta_gatts_send_rsp(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_indicate_handle(tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_DATA* p_msg);
+
+extern void bta_gatts_open(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_cancel_open(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+extern void bta_gatts_close(tBTA_GATTS_CB* p_cb, tBTA_GATTS_DATA* p_msg);
+
+extern bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src);
+extern tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(
+ tBTA_GATTS_IF server_if);
+extern uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_IF server_if);
+extern uint8_t bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB* p_cb, uint8_t rcb_idx);
+extern tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(
+ tBTA_GATTS_CB* p_cb, uint16_t service_id);
+extern tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_attr_id(
+ tBTA_GATTS_CB* p_cb, uint16_t attr_id);
+
+#endif /* BTA_GATTS_INT_H */
diff --git a/mtkbt/code/bt/bta/gatt/bta_gatts_main.cc b/mtkbt/code/bt/bta/gatt/bta_gatts_main.cc
new file mode 100755
index 0000000..ac82878
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gatts_main.cc
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT server main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatts_int.h"
+
+/* GATTS control block */
+tBTA_GATTS_CB bta_gatts_cb;
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_hdl_event
+ *
+ * Description BTA GATT server main event handling function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_gatts_hdl_event(BT_HDR* p_msg) {
+ tBTA_GATTS_CB* p_cb = &bta_gatts_cb;
+
+ switch (p_msg->event) {
+ case BTA_GATTS_API_DISABLE_EVT:
+ bta_gatts_api_disable(p_cb);
+ break;
+
+ case BTA_GATTS_API_REG_EVT:
+ bta_gatts_register(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_INT_START_IF_EVT:
+ bta_gatts_start_if(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_DEREG_EVT:
+ bta_gatts_deregister(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_INDICATION_EVT:
+ bta_gatts_indicate_handle(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_OPEN_EVT:
+ bta_gatts_open(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_CANCEL_OPEN_EVT:
+ bta_gatts_cancel_open(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_CLOSE_EVT:
+ bta_gatts_close(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_RSP_EVT:
+ bta_gatts_send_rsp(p_cb, (tBTA_GATTS_DATA*)p_msg);
+ break;
+
+ case BTA_GATTS_API_DEL_SRVC_EVT: {
+ tBTA_GATTS_SRVC_CB* p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(
+ p_cb, ((tBTA_GATTS_DATA*)p_msg)->api_add_service.hdr.layer_specific);
+
+ if (p_srvc_cb != NULL)
+ bta_gatts_delete_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
+ else
+ APPL_TRACE_ERROR("%s: can't delete service - no srvc_cb found",
+ __func__);
+
+ break;
+ }
+
+ case BTA_GATTS_API_STOP_SRVC_EVT: {
+ tBTA_GATTS_SRVC_CB* p_srvc_cb = bta_gatts_find_srvc_cb_by_srvc_id(
+ p_cb, ((tBTA_GATTS_DATA*)p_msg)->api_add_service.hdr.layer_specific);
+
+ if (p_srvc_cb != NULL)
+ bta_gatts_stop_service(p_srvc_cb, (tBTA_GATTS_DATA*)p_msg);
+ else
+ APPL_TRACE_ERROR("%s: can't stop service - no srvc_cb found", __func__);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return (true);
+}
diff --git a/mtkbt/code/bt/bta/gatt/bta_gatts_utils.cc b/mtkbt/code/bt/bta/gatt/bta_gatts_utils.cc
new file mode 100755
index 0000000..23cc7c7
--- a/dev/null
+++ b/mtkbt/code/bt/bta/gatt/bta_gatts_utils.cc
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the GATT client utility function.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_gatts_int.h"
+#include "bta_sys.h"
+#include "utl.h"
+
+static const uint8_t base_uuid[LEN_UUID_128] = {
+ 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*******************************************************************************
+ *
+ * Function bta_gatt_convert_uuid16_to_uuid128
+ *
+ * Description Convert a 16 bits UUID to be an standard 128 bits one.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+static void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint16_t uuid_16) {
+ uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_alloc_srvc_cb
+ *
+ * Description allocate a service control block.
+ *
+ * Returns pointer to the control block, or otherwise NULL when failed.
+ *
+ ******************************************************************************/
+uint8_t bta_gatts_alloc_srvc_cb(tBTA_GATTS_CB* p_cb, uint8_t rcb_idx) {
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i++) {
+ if (!p_cb->srvc_cb[i].in_use) {
+ p_cb->srvc_cb[i].in_use = true;
+ p_cb->srvc_cb[i].rcb_idx = rcb_idx;
+ return i;
+ }
+ }
+ return BTA_GATTS_INVALID_APP;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_find_app_rcb_by_app_if
+ *
+ * Description find the index of the application control block by app ID.
+ *
+ * Returns pointer to the control block if success, otherwise NULL
+ *
+ ******************************************************************************/
+tBTA_GATTS_RCB* bta_gatts_find_app_rcb_by_app_if(tBTA_GATTS_IF server_if) {
+ uint8_t i;
+ tBTA_GATTS_RCB* p_reg;
+
+ for (i = 0, p_reg = bta_gatts_cb.rcb; i < BTA_GATTS_MAX_APP_NUM;
+ i++, p_reg++) {
+ if (p_reg->in_use && p_reg->gatt_if == server_if) return p_reg;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_find_app_rcb_idx_by_app_if
+ *
+ * Description find the index of the application control block by app ID.
+ *
+ * Returns index of the control block, or BTA_GATTS_INVALID_APP if
+ * failed.
+ *
+ ******************************************************************************/
+
+uint8_t bta_gatts_find_app_rcb_idx_by_app_if(tBTA_GATTS_CB* p_cb,
+ tBTA_GATTS_IF server_if) {
+ uint8_t i;
+
+ for (i = 0; i < BTA_GATTS_MAX_APP_NUM; i++) {
+ if (p_cb->rcb[i].in_use && p_cb->rcb[i].gatt_if == server_if) return i;
+ }
+ return BTA_GATTS_INVALID_APP;
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_find_srvc_cb_by_srvc_id
+ *
+ * Description find the service control block by service ID.
+ *
+ * Returns pointer to the rcb.
+ *
+ ******************************************************************************/
+tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_srvc_id(tBTA_GATTS_CB* p_cb,
+ uint16_t service_id) {
+ uint8_t i;
+ APPL_TRACE_DEBUG("bta_gatts_find_srvc_cb_by_srvc_id service_id=%d",
+ service_id);
+ for (i = 0; i < BTA_GATTS_MAX_SRVC_NUM; i++) {
+ if (p_cb->srvc_cb[i].in_use && p_cb->srvc_cb[i].service_id == service_id) {
+ APPL_TRACE_DEBUG(
+ "bta_gatts_find_srvc_cb_by_srvc_id found service cb index =%d", i);
+ return &p_cb->srvc_cb[i];
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_find_srvc_cb_by_attr_id
+ *
+ * Description find the service control block by attribute ID.
+ *
+ * Returns pointer to the rcb.
+ *
+ ******************************************************************************/
+tBTA_GATTS_SRVC_CB* bta_gatts_find_srvc_cb_by_attr_id(tBTA_GATTS_CB* p_cb,
+ uint16_t attr_id) {
+ uint8_t i;
+
+ for (i = 0; i < (BTA_GATTS_MAX_SRVC_NUM); i++) {
+ if (/* middle service */
+ (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && p_cb->srvc_cb[i].in_use &&
+ p_cb->srvc_cb[i + 1].in_use &&
+ attr_id >= p_cb->srvc_cb[i].service_id &&
+ attr_id < p_cb->srvc_cb[i + 1].service_id) ||
+ /* last active service */
+ (i < (BTA_GATTS_MAX_SRVC_NUM - 1) && p_cb->srvc_cb[i].in_use &&
+ !p_cb->srvc_cb[i + 1].in_use &&
+ attr_id >= p_cb->srvc_cb[i].service_id) ||
+ /* last service incb */
+ (i == (BTA_GATTS_MAX_SRVC_NUM - 1) &&
+ attr_id >= p_cb->srvc_cb[i].service_id)) {
+ return &p_cb->srvc_cb[i];
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function bta_gatts_uuid_compare
+ *
+ * Description Compare two UUID to see if they are the same.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+bool bta_gatts_uuid_compare(tBT_UUID tar, tBT_UUID src) {
+ uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+ uint8_t *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (src.len == 0 || tar.len == 0) {
+ return true;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (src.len == 2 && tar.len == 2) {
+ return src.uu.uuid16 == tar.uu.uuid16;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (src.len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+ ps = su;
+ } else
+ ps = src.uu.uuid128;
+
+ if (tar.len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ bta_gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+ pt = tu;
+ } else
+ pt = tar.uu.uuid128;
+
+ return (memcmp(ps, pt, LEN_UUID_128) == 0);
+}
diff --git a/mtkbt/code/bt/bta/hd/bta_hd_act.cc b/mtkbt/code/bt/bta/hd/bta_hd_act.cc
new file mode 100755
index 0000000..75e4ea5
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hd/bta_hd_act.cc
@@ -0,0 +1,738 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID device action functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_hd_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+#include "osi/include/osi.h"
+
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data,
+ BT_HDR* pdata);
+
+static bool check_descriptor(uint8_t* data, uint16_t length,
+ bool* has_report_id) {
+ uint8_t* ptr = data;
+
+ *has_report_id = FALSE;
+
+ while (ptr < data + length) {
+ uint8_t item = *ptr++;
+
+ switch (item) {
+ case 0xfe: // long item indicator
+ if (ptr < data + length) {
+ ptr += ((*ptr) + 2);
+ } else {
+ return false;
+ }
+ break;
+
+ case 0x85: // Report ID
+ *has_report_id = TRUE;
+
+ default:
+ ptr += (item & 0x03);
+ break;
+ }
+ }
+
+ return (ptr == data + length);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_api_enable
+ *
+ * Description Enables HID device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_api_enable(tBTA_HD_DATA* p_data) {
+ tBTA_HD_STATUS status = BTA_HD_ERROR;
+ tHID_STATUS ret;
+
+ APPL_TRACE_API("%s", __func__);
+
+ HID_DevInit();
+
+ memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+
+ HID_DevSetSecurityLevel(BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+ /* store parameters */
+ bta_hd_cb.p_cback = p_data->api_enable.p_cback;
+
+ ret = HID_DevRegister(bta_hd_cback);
+ if (ret == HID_SUCCESS) {
+ status = BTA_HD_OK;
+ } else {
+ APPL_TRACE_ERROR("%s: Failed to register HID device (%d)", __func__, ret);
+ }
+
+ /* signal BTA call back event */
+ (*bta_hd_cb.p_cback)(BTA_HD_ENABLE_EVT, (tBTA_HD*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_api_disable
+ *
+ * Description Disables HID device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_api_disable(void) {
+ tBTA_HD_STATUS status = BTA_HD_ERROR;
+ tHID_STATUS ret;
+
+ APPL_TRACE_API("%s", __func__);
+
+ /* service is not enabled */
+ if (bta_hd_cb.p_cback == NULL) return;
+
+ /* Remove service record */
+ if (bta_hd_cb.sdp_handle != 0) {
+ SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+ bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+ }
+
+ /* Deregister with lower layer */
+ ret = HID_DevDeregister();
+ if (ret == HID_SUCCESS) {
+ status = BTA_HD_OK;
+ } else {
+ APPL_TRACE_ERROR("%s: Failed to deregister HID device (%s)", __func__, ret);
+ }
+
+ (*bta_hd_cb.p_cback)(BTA_HD_DISABLE_EVT, (tBTA_HD*)&status);
+
+ memset(&bta_hd_cb, 0, sizeof(tBTA_HD_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_register_act
+ *
+ * Description Registers SDP record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_register_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD ret;
+ tBTA_HD_REGISTER_APP* p_app_data = (tBTA_HD_REGISTER_APP*)p_data;
+ bool use_report_id = FALSE;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret.reg_status.in_use = FALSE;
+
+ /* Check if len doesn't exceed BTA_HD_APP_DESCRIPTOR_LEN and descriptor
+ * itself is well-formed. Also check if descriptor has Report Id item so we
+ * know if report will have prefix or not. */
+ if (p_app_data->d_len > BTA_HD_APP_DESCRIPTOR_LEN ||
+ !check_descriptor(p_app_data->d_data, p_app_data->d_len,
+ &use_report_id)) {
+ APPL_TRACE_ERROR("%s: Descriptor is too long or malformed", __func__);
+ ret.reg_status.status = BTA_HD_ERROR;
+ (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+ return;
+ }
+
+ ret.reg_status.status = BTA_HD_OK;
+
+ /* Remove old record if for some reason it's already registered */
+ if (bta_hd_cb.sdp_handle != 0) {
+ SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+ }
+
+ bta_hd_cb.use_report_id = use_report_id;
+ bta_hd_cb.sdp_handle = SDP_CreateRecord();
+ HID_DevAddRecord(bta_hd_cb.sdp_handle, p_app_data->name,
+ p_app_data->description, p_app_data->provider,
+ p_app_data->subclass, p_app_data->d_len, p_app_data->d_data);
+ bta_sys_add_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+ HID_DevSetIncomingQos(
+ p_app_data->in_qos.service_type, p_app_data->in_qos.token_rate,
+ p_app_data->in_qos.token_bucket_size, p_app_data->in_qos.peak_bandwidth,
+ p_app_data->in_qos.access_latency, p_app_data->in_qos.delay_variation);
+
+ HID_DevSetOutgoingQos(
+ p_app_data->out_qos.service_type, p_app_data->out_qos.token_rate,
+ p_app_data->out_qos.token_bucket_size, p_app_data->out_qos.peak_bandwidth,
+ p_app_data->out_qos.access_latency, p_app_data->out_qos.delay_variation);
+
+ // application is registered so we can accept incoming connections
+ HID_DevSetIncomingPolicy(TRUE);
+
+ if (HID_DevGetDevice(&ret.reg_status.bda) == HID_SUCCESS) {
+ ret.reg_status.in_use = TRUE;
+ }
+
+ (*bta_hd_cb.p_cback)(BTA_HD_REGISTER_APP_EVT, &ret);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_unregister_act
+ *
+ * Description Unregisters SDP record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_unregister_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+ tBTA_HD_STATUS status = BTA_HD_OK;
+
+ APPL_TRACE_API("%s", __func__);
+
+ // application is no longer registered so we do not want incoming connections
+ HID_DevSetIncomingPolicy(FALSE);
+
+ if (bta_hd_cb.sdp_handle != 0) {
+ SDP_DeleteRecord(bta_hd_cb.sdp_handle);
+ }
+
+ bta_hd_cb.sdp_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_HUMAN_INTERFACE);
+
+ (*bta_hd_cb.p_cback)(BTA_HD_UNREGISTER_APP_EVT, (tBTA_HD*)&status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_unregister2_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_unregister2_act(tBTA_HD_DATA* p_data) {
+ APPL_TRACE_API("%s", __func__);
+
+ // close first
+ bta_hd_close_act(p_data);
+
+ // then unregister
+ bta_hd_unregister_act(p_data);
+
+ if (bta_hd_cb.disable_w4_close) {
+ bta_hd_api_disable();
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_connect_act
+ *
+ * Description Connect to device (must be virtually plugged)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_connect_act(tBTA_HD_DATA* p_data) {
+ tHID_STATUS ret;
+ tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret = HID_DevPlugDevice(p_ctrl->addr);
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevPlugDevice returned %d", __func__, ret);
+ return;
+ }
+
+ ret = HID_DevConnect();
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevConnect returned %d", __func__, ret);
+ return;
+ }
+
+ bdcpy(cback_data.conn.bda, p_ctrl->addr);
+ cback_data.conn.status = BTHD_CONN_STATE_CONNECTING;
+
+ bta_hd_cb.p_cback(BTA_HD_CONN_STATE_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_disconnect_act
+ *
+ * Description Disconnect from device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_disconnect_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+ tHID_STATUS ret;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret = HID_DevDisconnect();
+
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevDisconnect returned %d", __func__, ret);
+ return;
+ }
+
+ if (HID_DevGetDevice(&cback_data.conn.bda) == HID_SUCCESS) {
+ cback_data.conn.status = BTHD_CONN_STATE_DISCONNECTING;
+ bta_hd_cb.p_cback(BTA_HD_CONN_STATE_EVT, &cback_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_add_device_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_add_device_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ HID_DevPlugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_remove_device_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_remove_device_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_DEVICE_CTRL* p_ctrl = (tBTA_HD_DEVICE_CTRL*)p_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ HID_DevUnplugDevice(p_ctrl->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_send_report_act
+ *
+ * Description Sends report
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_send_report_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_SEND_REPORT* p_report = (tBTA_HD_SEND_REPORT*)p_data;
+ uint8_t channel;
+ uint8_t report_id;
+
+ APPL_TRACE_VERBOSE("%s", __func__);
+
+ channel = p_report->use_intr ? HID_CHANNEL_INTR : HID_CHANNEL_CTRL;
+ report_id =
+ (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) ? p_report->id : 0x00;
+
+ HID_DevSendReport(channel, p_report->type, report_id, p_report->len,
+ p_report->data);
+
+ /* trigger PM */
+ bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+ bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_report_error_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_report_error_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_REPORT_ERR* p_report = (tBTA_HD_REPORT_ERR*)p_data;
+ tHID_STATUS ret;
+
+ APPL_TRACE_API("%s: error = %d", __func__, p_report->error);
+
+ ret = HID_DevReportError(p_report->error);
+
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevReportError returned %d", __func__, ret);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_vc_unplug_act
+ *
+ * Description Sends Virtual Cable Unplug
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_act(UNUSED_ATTR tBTA_HD_DATA* p_data) {
+ tHID_STATUS ret;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_hd_cb.vc_unplug = TRUE;
+
+ ret = HID_DevVirtualCableUnplug();
+
+ if (ret != HID_SUCCESS) {
+ APPL_TRACE_WARNING("%s: HID_DevVirtualCableUnplug returned %d", __func__,
+ ret);
+ }
+
+ /* trigger PM */
+ bta_sys_busy(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+ bta_sys_idle(BTA_ID_HD, 1, bta_hd_cb.bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_open_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_open_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ HID_DevPlugDevice(p_cback->addr);
+ bta_sys_conn_open(BTA_ID_HD, 1, p_cback->addr);
+
+ bdcpy(cback_data.conn.bda, p_cback->addr);
+ bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+
+ bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_close_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_close_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ tBTA_HD cback_data;
+ tBTA_HD_EVT cback_event = BTA_HD_CLOSE_EVT;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+ if (bta_hd_cb.vc_unplug) {
+ bta_hd_cb.vc_unplug = FALSE;
+ HID_DevUnplugDevice(p_cback->addr);
+ cback_event = BTA_HD_VC_UNPLUG_EVT;
+ }
+
+ bdcpy(cback_data.conn.bda, p_cback->addr);
+ memset(bta_hd_cb.bd_addr, 0, sizeof(BD_ADDR));
+
+ bta_hd_cb.p_cback(cback_event, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_intr_data_act
+ *
+ * Description Handles incoming DATA request on intr
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_intr_data_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ BT_HDR* p_msg = p_cback->p_data;
+ uint16_t len = p_msg->len;
+ uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ tBTA_HD_INTR_DATA ret;
+
+ APPL_TRACE_API("%s", __func__);
+
+ if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+ ret.report_id = *p_buf;
+
+ len--;
+ p_buf++;
+ } else {
+ ret.report_id = 0;
+ }
+
+ ret.len = len;
+ ret.p_data = p_buf;
+
+ (*bta_hd_cb.p_cback)(BTA_HD_INTR_DATA_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_get_report_act
+ *
+ * Description Handles incoming GET_REPORT request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_get_report_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ bool rep_size_follows = p_cback->data;
+ BT_HDR* p_msg = p_cback->p_data;
+ uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ tBTA_HD_GET_REPORT ret = {0, 0, 0};
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+ p_buf++;
+
+ if (bta_hd_cb.use_report_id) {
+ ret.report_id = *p_buf;
+ p_buf++;
+ }
+
+ if (rep_size_follows) {
+ ret.buffer_size = *p_buf | (*(p_buf + 1) << 8);
+ }
+
+ (*bta_hd_cb.p_cback)(BTA_HD_GET_REPORT_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_set_report_act
+ *
+ * Description Handles incoming SET_REPORT request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_report_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ BT_HDR* p_msg = p_cback->p_data;
+ uint16_t len = p_msg->len;
+ uint8_t* p_buf = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ tBTA_HD_SET_REPORT ret = {0, 0, 0, NULL};
+
+ APPL_TRACE_API("%s", __func__);
+
+ ret.report_type = *p_buf & HID_PAR_REP_TYPE_MASK;
+ p_buf++;
+ len--;
+
+ if (bta_hd_cb.use_report_id || bta_hd_cb.boot_mode) {
+ ret.report_id = *p_buf;
+
+ len--;
+ p_buf++;
+ } else {
+ ret.report_id = 0;
+ }
+
+ ret.len = len;
+ ret.p_data = p_buf;
+
+ (*bta_hd_cb.p_cback)(BTA_HD_SET_REPORT_EVT, (tBTA_HD*)&ret);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_set_protocol_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_hd_cb.boot_mode = (p_cback->data == HID_PAR_PROTOCOL_BOOT_MODE);
+ cback_data.set_protocol = p_cback->data;
+
+ (*bta_hd_cb.p_cback)(BTA_HD_SET_PROTOCOL_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_vc_unplug_done_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_conn_close(BTA_ID_HD, 1, p_cback->addr);
+
+ HID_DevUnplugDevice(p_cback->addr);
+
+ bdcpy(cback_data.conn.bda, p_cback->addr);
+ bdcpy(bta_hd_cb.bd_addr, p_cback->addr);
+
+ (*bta_hd_cb.p_cback)(BTA_HD_VC_UNPLUG_EVT, &cback_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_suspend_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_suspend_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_exit_suspend_act
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA* p_data) {
+ tBTA_HD_CBACK_DATA* p_cback = (tBTA_HD_CBACK_DATA*)p_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_busy(BTA_ID_HD, 1, p_cback->addr);
+ bta_sys_idle(BTA_ID_HD, 1, p_cback->addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_cback
+ *
+ * Description BTA HD callback function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hd_cback(BD_ADDR bd_addr, uint8_t event, uint32_t data,
+ BT_HDR* pdata) {
+ tBTA_HD_CBACK_DATA* p_buf = NULL;
+ uint16_t sm_event = BTA_HD_INVALID_EVT;
+
+ APPL_TRACE_API("%s: event=%d", __func__, event);
+
+ switch (event) {
+ case HID_DHOST_EVT_OPEN:
+ sm_event = BTA_HD_INT_OPEN_EVT;
+ break;
+
+ case HID_DHOST_EVT_CLOSE:
+ sm_event = BTA_HD_INT_CLOSE_EVT;
+ break;
+
+ case HID_DHOST_EVT_GET_REPORT:
+ sm_event = BTA_HD_INT_GET_REPORT_EVT;
+ break;
+
+ case HID_DHOST_EVT_SET_REPORT:
+ sm_event = BTA_HD_INT_SET_REPORT_EVT;
+ break;
+
+ case HID_DHOST_EVT_SET_PROTOCOL:
+ sm_event = BTA_HD_INT_SET_PROTOCOL_EVT;
+ break;
+
+ case HID_DHOST_EVT_INTR_DATA:
+ sm_event = BTA_HD_INT_INTR_DATA_EVT;
+ break;
+
+ case HID_DHOST_EVT_VC_UNPLUG:
+ sm_event = BTA_HD_INT_VC_UNPLUG_EVT;
+ break;
+
+ case HID_DHOST_EVT_SUSPEND:
+ sm_event = BTA_HD_INT_SUSPEND_EVT;
+ break;
+
+ case HID_DHOST_EVT_EXIT_SUSPEND:
+ sm_event = BTA_HD_INT_EXIT_SUSPEND_EVT;
+ break;
+ }
+
+ if (sm_event != BTA_HD_INVALID_EVT &&
+ (p_buf = (tBTA_HD_CBACK_DATA*)osi_malloc(sizeof(tBTA_HD_CBACK_DATA) +
+ sizeof(BT_HDR))) != NULL) {
+ p_buf->hdr.event = sm_event;
+ bdcpy(p_buf->addr, bd_addr);
+ p_buf->data = data;
+ p_buf->p_data = pdata;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hd/bta_hd_api.cc b/mtkbt/code/bt/bta/hd/bta_hd_api.cc
new file mode 100755
index 0000000..773348d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hd/bta_hd_api.cc
@@ -0,0 +1,309 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID DEVICE API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hd_reg = {bta_hd_hdl_event, BTA_HdDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_HdEnable
+ *
+ * Description Enables HID device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HdEnable(tBTA_HD_CBACK* p_cback) {
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_register(BTA_ID_HD, &bta_hd_reg);
+
+ tBTA_HD_API_ENABLE* p_buf =
+ (tBTA_HD_API_ENABLE*)osi_malloc((uint16_t)sizeof(tBTA_HD_API_ENABLE));
+
+ memset(p_buf, 0, sizeof(tBTA_HD_API_ENABLE));
+
+ p_buf->hdr.event = BTA_HD_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdDisable
+ *
+ * Description Disables HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HdDisable(void) {
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_deregister(BTA_ID_HD);
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HD_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdRegisterApp
+ *
+ * Description This function is called when application should be
+*registered
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info,
+ tBTA_HD_QOS_INFO* p_in_qos,
+ tBTA_HD_QOS_INFO* p_out_qos) {
+ APPL_TRACE_API("%s", __func__);
+
+ tBTA_HD_REGISTER_APP* p_buf =
+ (tBTA_HD_REGISTER_APP*)osi_malloc(sizeof(tBTA_HD_REGISTER_APP));
+ p_buf->hdr.event = BTA_HD_API_REGISTER_APP_EVT;
+
+ if (p_app_info->p_name) {
+ strncpy(p_buf->name, p_app_info->p_name, BTA_HD_APP_NAME_LEN);
+ p_buf->name[BTA_HD_APP_NAME_LEN] = '\0';
+ } else {
+ p_buf->name[0] = '\0';
+ }
+
+ if (p_app_info->p_description) {
+ strncpy(p_buf->description, p_app_info->p_description,
+ BTA_HD_APP_DESCRIPTION_LEN);
+ p_buf->description[BTA_HD_APP_DESCRIPTION_LEN] = '\0';
+ } else {
+ p_buf->description[0] = '\0';
+ }
+
+ if (p_app_info->p_provider) {
+ strncpy(p_buf->provider, p_app_info->p_provider, BTA_HD_APP_PROVIDER_LEN);
+ p_buf->provider[BTA_HD_APP_PROVIDER_LEN] = '\0';
+ } else {
+ p_buf->provider[0] = '\0';
+ }
+
+ p_buf->subclass = p_app_info->subclass;
+
+ p_buf->d_len = p_app_info->descriptor.dl_len;
+ memcpy(p_buf->d_data, p_app_info->descriptor.dsc_list,
+ p_app_info->descriptor.dl_len);
+
+ // copy qos data as-is
+ memcpy(&p_buf->in_qos, p_in_qos, sizeof(tBTA_HD_QOS_INFO));
+ memcpy(&p_buf->out_qos, p_out_qos, sizeof(tBTA_HD_QOS_INFO));
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdUnregisterApp
+ *
+ * Description This function is called when application should be
+*unregistered
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdUnregisterApp(void) {
+ APPL_TRACE_API("%s", __func__);
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HD_API_UNREGISTER_APP_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdSendReport
+ *
+ * Description This function is called when report is to be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdSendReport(tBTA_HD_REPORT* p_report) {
+ APPL_TRACE_VERBOSE("%s", __func__);
+
+ if (p_report->len > BTA_HD_REPORT_LEN) {
+ APPL_TRACE_WARNING(
+ "%s, report len (%d) > MTU len (%d), can't send report."
+ " Increase value of HID_DEV_MTU_SIZE to send larger reports",
+ __func__, p_report->len, BTA_HD_REPORT_LEN);
+ return;
+ }
+
+ tBTA_HD_SEND_REPORT* p_buf =
+ (tBTA_HD_SEND_REPORT*)osi_malloc(sizeof(tBTA_HD_SEND_REPORT));
+ p_buf->hdr.event = BTA_HD_API_SEND_REPORT_EVT;
+
+ p_buf->use_intr = p_report->use_intr;
+ p_buf->type = p_report->type;
+ p_buf->id = p_report->id;
+ p_buf->len = p_report->len;
+ memcpy(p_buf->data, p_report->p_data, p_report->len);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdVirtualCableUnplug
+ *
+ * Description This function is called when VCU shall be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdVirtualCableUnplug(void) {
+ APPL_TRACE_API("%s", __func__);
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HD_API_VC_UNPLUG_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdConnect
+ *
+ * Description This function is called when connection to host shall be
+*made
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdConnect(BD_ADDR addr) {
+ APPL_TRACE_API("%s", __func__);
+
+ tBTA_HD_DEVICE_CTRL* p_buf =
+ (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL));
+ p_buf->hdr.event = BTA_HD_API_CONNECT_EVT;
+
+ memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdDisconnect
+ *
+ * Description This function is called when host shall be disconnected
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisconnect(void) {
+ APPL_TRACE_API("%s", __func__);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HD_API_DISCONNECT_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdAddDevice
+ *
+ * Description This function is called when a device is virtually cabled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdAddDevice(BD_ADDR addr) {
+ APPL_TRACE_API("%s", __func__);
+ tBTA_HD_DEVICE_CTRL* p_buf =
+ (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL));
+ p_buf->hdr.event = BTA_HD_API_ADD_DEVICE_EVT;
+
+ memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdRemoveDevice
+ *
+ * Description This function is called when a device is virtually uncabled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdRemoveDevice(BD_ADDR addr) {
+ APPL_TRACE_API("%s", __func__);
+ tBTA_HD_DEVICE_CTRL* p_buf =
+ (tBTA_HD_DEVICE_CTRL*)osi_malloc(sizeof(tBTA_HD_DEVICE_CTRL));
+ p_buf->hdr.event = BTA_HD_API_REMOVE_DEVICE_EVT;
+
+ memcpy(p_buf->addr, addr, sizeof(BD_ADDR));
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HdReportError
+ *
+ * Description This function is called when reporting error for set report
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdReportError(uint8_t error) {
+ APPL_TRACE_API("%s", __func__);
+ tBTA_HD_REPORT_ERR* p_buf =
+ (tBTA_HD_REPORT_ERR*)osi_malloc(sizeof(tBTA_HD_REPORT_ERR));
+ p_buf->hdr.event = BTA_HD_API_REPORT_ERROR_EVT;
+ p_buf->error = error;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hd/bta_hd_int.h b/mtkbt/code/bt/bta/hd/bta_hd_int.h
new file mode 100755
index 0000000..d024709
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hd/bta_hd_int.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains BTA HID Device internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef BTA_HD_INT_H
+#define BTA_HD_INT_H
+
+#include "bta_hd_api.h"
+#include "bta_sys.h"
+#include "hiddefs.h"
+
+enum {
+ BTA_HD_API_REGISTER_APP_EVT = BTA_SYS_EVT_START(BTA_ID_HD),
+ BTA_HD_API_UNREGISTER_APP_EVT,
+ BTA_HD_API_CONNECT_EVT,
+ BTA_HD_API_DISCONNECT_EVT,
+ BTA_HD_API_ADD_DEVICE_EVT,
+ BTA_HD_API_REMOVE_DEVICE_EVT,
+ BTA_HD_API_SEND_REPORT_EVT,
+ BTA_HD_API_REPORT_ERROR_EVT,
+ BTA_HD_API_VC_UNPLUG_EVT,
+ BTA_HD_INT_OPEN_EVT,
+ BTA_HD_INT_CLOSE_EVT,
+ BTA_HD_INT_INTR_DATA_EVT,
+ BTA_HD_INT_GET_REPORT_EVT,
+ BTA_HD_INT_SET_REPORT_EVT,
+ BTA_HD_INT_SET_PROTOCOL_EVT,
+ BTA_HD_INT_VC_UNPLUG_EVT,
+ BTA_HD_INT_SUSPEND_EVT,
+ BTA_HD_INT_EXIT_SUSPEND_EVT,
+
+ /* handled outside state machine */
+ BTA_HD_API_ENABLE_EVT,
+ BTA_HD_API_DISABLE_EVT
+};
+typedef uint16_t tBTA_HD_INT_EVT;
+
+#define BTA_HD_INVALID_EVT (BTA_HD_API_DISABLE_EVT + 1)
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HD_CBACK* p_cback;
+} tBTA_HD_API_ENABLE;
+
+#define BTA_HD_APP_NAME_LEN 50
+#define BTA_HD_APP_DESCRIPTION_LEN 50
+#define BTA_HD_APP_PROVIDER_LEN 50
+#define BTA_HD_APP_DESCRIPTOR_LEN 2048
+
+#define BTA_HD_STATE_DISABLED 0x00
+#define BTA_HD_STATE_ENABLED 0x01
+#define BTA_HD_STATE_IDLE 0x02
+#define BTA_HD_STATE_CONNECTED 0x03
+#define BTA_HD_STATE_DISABLING 0x04
+#define BTA_HD_STATE_REMOVING 0x05
+
+typedef struct {
+ BT_HDR hdr;
+ char name[BTA_HD_APP_NAME_LEN + 1];
+ char description[BTA_HD_APP_DESCRIPTION_LEN + 1];
+ char provider[BTA_HD_APP_PROVIDER_LEN + 1];
+ uint8_t subclass;
+ uint16_t d_len;
+ uint8_t d_data[BTA_HD_APP_DESCRIPTOR_LEN];
+
+ tBTA_HD_QOS_INFO in_qos;
+ tBTA_HD_QOS_INFO out_qos;
+} tBTA_HD_REGISTER_APP;
+
+#define BTA_HD_REPORT_LEN HID_DEV_MTU_SIZE
+
+typedef struct {
+ BT_HDR hdr;
+ bool use_intr;
+ uint8_t type;
+ uint8_t id;
+ uint16_t len;
+ uint8_t data[BTA_HD_REPORT_LEN];
+} tBTA_HD_SEND_REPORT;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR addr;
+} tBTA_HD_DEVICE_CTRL;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t error;
+} tBTA_HD_REPORT_ERR;
+
+/* union of all event data types */
+typedef union {
+ BT_HDR hdr;
+ tBTA_HD_API_ENABLE api_enable;
+ tBTA_HD_REGISTER_APP register_app;
+ tBTA_HD_SEND_REPORT send_report;
+ tBTA_HD_DEVICE_CTRL device_ctrl;
+ tBTA_HD_REPORT_ERR report_err;
+} tBTA_HD_DATA;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR addr;
+ uint32_t data;
+ BT_HDR* p_data;
+} tBTA_HD_CBACK_DATA;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+typedef struct {
+ tBTA_HD_CBACK* p_cback;
+ uint32_t sdp_handle;
+ uint8_t trace_level;
+ uint8_t state;
+ BD_ADDR bd_addr;
+ bool use_report_id;
+ bool boot_mode;
+ bool vc_unplug;
+ bool disable_w4_close;
+} tBTA_HD_CB;
+
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_HD_CB bta_hd_cb;
+#else
+extern tBTA_HD_CB* bta_hd_cb_ptr;
+#define bta_hd_cb (*bta_hd_cb_ptr)
+#endif
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+extern bool bta_hd_hdl_event(BT_HDR* p_msg);
+
+extern void bta_hd_api_enable(tBTA_HD_DATA* p_data);
+extern void bta_hd_api_disable(void);
+
+extern void bta_hd_register_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_unregister_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_unregister2_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_connect_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_disconnect_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_add_device_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_remove_device_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_send_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_report_error_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_vc_unplug_act(tBTA_HD_DATA* p_data);
+
+extern void bta_hd_open_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_close_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_intr_data_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_get_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_set_report_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_set_protocol_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_suspend_act(tBTA_HD_DATA* p_data);
+extern void bta_hd_exit_suspend_act(tBTA_HD_DATA* p_data);
+
+#endif
diff --git a/mtkbt/code/bt/bta/hd/bta_hd_main.cc b/mtkbt/code/bt/bta/hd/bta_hd_main.cc
new file mode 100755
index 0000000..dff5d9c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hd/bta_hd_main.cc
@@ -0,0 +1,365 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID host main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hd_api.h"
+#include "bta_hd_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine states */
+enum {
+ BTA_HD_INIT_ST,
+ BTA_HD_IDLE_ST, /* not connected, waiting for connection */
+ BTA_HD_CONN_ST, /* host connected */
+ BTA_HD_TRANSIENT_TO_INIT_ST, /* transient state: going back from CONN to INIT
+ */
+};
+typedef uint8_t tBTA_HD_STATE;
+
+/* state machine actions */
+enum {
+ BTA_HD_REGISTER_ACT,
+ BTA_HD_UNREGISTER_ACT,
+ BTA_HD_UNREGISTER2_ACT,
+ BTA_HD_CONNECT_ACT,
+ BTA_HD_DISCONNECT_ACT,
+ BTA_HD_ADD_DEVICE_ACT,
+ BTA_HD_REMOVE_DEVICE_ACT,
+ BTA_HD_SEND_REPORT_ACT,
+ BTA_HD_REPORT_ERROR_ACT,
+ BTA_HD_VC_UNPLUG_ACT,
+
+ BTA_HD_OPEN_ACT,
+ BTA_HD_CLOSE_ACT,
+ BTA_HD_INTR_DATA_ACT,
+ BTA_HD_GET_REPORT_ACT,
+ BTA_HD_SET_REPORT_ACT,
+ BTA_HD_SET_PROTOCOL_ACT,
+ BTA_HD_VC_UNPLUG_DONE_ACT,
+ BTA_HD_SUSPEND_ACT,
+ BTA_HD_EXIT_SUSPEND_ACT,
+
+ BTA_HD_NUM_ACTIONS
+};
+
+#define BTA_HD_IGNORE BTA_HD_NUM_ACTIONS
+
+typedef void (*tBTA_HD_ACTION)(tBTA_HD_DATA* p_data);
+
+/* action functions */
+const tBTA_HD_ACTION bta_hd_action[] = {
+ bta_hd_register_act, bta_hd_unregister_act, bta_hd_unregister2_act,
+ bta_hd_connect_act, bta_hd_disconnect_act, bta_hd_add_device_act,
+ bta_hd_remove_device_act, bta_hd_send_report_act, bta_hd_report_error_act,
+ bta_hd_vc_unplug_act,
+
+ bta_hd_open_act, bta_hd_close_act, bta_hd_intr_data_act,
+ bta_hd_get_report_act, bta_hd_set_report_act, bta_hd_set_protocol_act,
+ bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act,
+};
+
+/* state table information */
+#define BTA_HD_ACTION 0 /* position of action */
+#define BTA_HD_NEXT_STATE 1 /* position of next state */
+#define BTA_HD_NUM_COLS 2 /* number of columns */
+
+const uint8_t bta_hd_st_init[][BTA_HD_NUM_COLS] = {
+ /* Event Action Next state
+ */
+ /* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_REGISTER_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_INIT_ST},
+ /* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_INIT_ST},
+ /* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+ /* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_INIT_ST},
+};
+
+const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = {
+ /* Event Action Next state
+ */
+ /* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_UNREGISTER_ACT, BTA_HD_INIT_ST},
+ /* BTA_HD_API_CONNECT_EVT */ {BTA_HD_CONNECT_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST},
+};
+
+const uint8_t bta_hd_st_conn[][BTA_HD_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+ /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_DISCONNECT_ACT,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+ /* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_DISCONNECT_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_ADD_DEVICE_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_REMOVE_DEVICE_ACT,
+ BTA_HD_CONN_ST},
+ /* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_SEND_REPORT_ACT,
+ BTA_HD_CONN_ST},
+ /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_REPORT_ERROR_ACT,
+ BTA_HD_CONN_ST},
+ /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_CLOSE_ACT, BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_INTR_DATA_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_GET_REPORT_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_SET_REPORT_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_SET_PROTOCOL_ACT,
+ BTA_HD_CONN_ST},
+ /* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_DONE_ACT,
+ BTA_HD_IDLE_ST},
+ /* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_SUSPEND_ACT, BTA_HD_CONN_ST},
+ /* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_EXIT_SUSPEND_ACT,
+ BTA_HD_CONN_ST},
+};
+
+const uint8_t bta_hd_st_transient_to_init[][BTA_HD_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HD_API_REGISTER_APP_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_UNREGISTER_APP_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_CONNECT_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_DISCONNECT_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_ADD_DEVICE_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_REMOVE_DEVICE_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_SEND_REPORT_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_UNREGISTER2_ACT,
+ BTA_HD_INIT_ST},
+ /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_SET_PROTOCOL_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_VC_UNPLUG_EVT */ {BTA_HD_UNREGISTER2_ACT,
+ BTA_HD_INIT_ST},
+ /* BTA_HD_INT_SUSPEND_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+ /* BTA_HD_INT_EXIT_SUSPEND_EVT */ {BTA_HD_IGNORE,
+ BTA_HD_TRANSIENT_TO_INIT_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HD_ST_TBL)[BTA_HD_NUM_COLS];
+
+/* state table */
+const tBTA_HD_ST_TBL bta_hd_st_tbl[] = {bta_hd_st_init, bta_hd_st_idle,
+ bta_hd_st_conn,
+ bta_hd_st_transient_to_init};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_HD_CB bta_hd_cb;
+#endif
+
+static const char* bta_hd_evt_code(tBTA_HD_INT_EVT evt_code);
+static const char* bta_hd_state_code(tBTA_HD_STATE state_code);
+
+/*******************************************************************************
+ *
+ * Function bta_hd_sm_execute
+ *
+ * Description State machine event handling function for HID Device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hd_sm_execute(uint16_t event, tBTA_HD_DATA* p_data) {
+ tBTA_HD_ST_TBL state_table;
+ tBTA_HD_STATE prev_state;
+ uint8_t action;
+ tBTA_HD cback_data;
+
+ APPL_TRACE_EVENT("%s: state=%s (%d) event=%s (%d)", __func__,
+ bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state,
+ bta_hd_evt_code(event), event);
+
+ prev_state = bta_hd_cb.state;
+
+ memset(&cback_data, 0, sizeof(tBTA_HD));
+
+ state_table = bta_hd_st_tbl[bta_hd_cb.state];
+
+ event &= 0xff;
+
+ action = state_table[event][BTA_HD_ACTION];
+ if (action < BTA_HD_IGNORE) {
+ (*bta_hd_action[action])(p_data);
+ }
+
+ bta_hd_cb.state = state_table[event][BTA_HD_NEXT_STATE];
+
+ if (bta_hd_cb.state != prev_state) {
+ APPL_TRACE_EVENT("%s: [new] state=%s (%d)", __func__,
+ bta_hd_state_code(bta_hd_cb.state), bta_hd_cb.state);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hd_hdl_event
+ *
+ * Description HID device main event handling function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_hd_hdl_event(BT_HDR* p_msg) {
+ APPL_TRACE_API("%s: p_msg->event=%d", __func__, p_msg->event);
+
+ switch (p_msg->event) {
+ case BTA_HD_API_ENABLE_EVT:
+ bta_hd_api_enable((tBTA_HD_DATA*)p_msg);
+ break;
+
+ case BTA_HD_API_DISABLE_EVT:
+ if (bta_hd_cb.state == BTA_HD_CONN_ST) {
+ APPL_TRACE_WARNING("%s: host connected, disconnect before disabling",
+ __func__);
+
+ // unregister (and disconnect)
+ bta_hd_cb.disable_w4_close = TRUE;
+ bta_hd_sm_execute(BTA_HD_API_UNREGISTER_APP_EVT, (tBTA_HD_DATA*)p_msg);
+ } else {
+ bta_hd_api_disable();
+ }
+ break;
+
+ default:
+ bta_hd_sm_execute(p_msg->event, (tBTA_HD_DATA*)p_msg);
+ }
+ return (TRUE);
+}
+
+static const char* bta_hd_evt_code(tBTA_HD_INT_EVT evt_code) {
+ switch (evt_code) {
+ case BTA_HD_API_REGISTER_APP_EVT:
+ return "BTA_HD_API_REGISTER_APP_EVT";
+ case BTA_HD_API_UNREGISTER_APP_EVT:
+ return "BTA_HD_API_UNREGISTER_APP_EVT";
+ case BTA_HD_API_CONNECT_EVT:
+ return "BTA_HD_API_CONNECT_EVT";
+ case BTA_HD_API_DISCONNECT_EVT:
+ return "BTA_HD_API_DISCONNECT_EVT";
+ case BTA_HD_API_ADD_DEVICE_EVT:
+ return "BTA_HD_API_ADD_DEVICE_EVT";
+ case BTA_HD_API_REMOVE_DEVICE_EVT:
+ return "BTA_HD_API_REMOVE_DEVICE_EVT";
+ case BTA_HD_API_SEND_REPORT_EVT:
+ return "BTA_HD_API_SEND_REPORT_EVT";
+ case BTA_HD_API_REPORT_ERROR_EVT:
+ return "BTA_HD_API_REPORT_ERROR_EVT";
+ case BTA_HD_API_VC_UNPLUG_EVT:
+ return "BTA_HD_API_VC_UNPLUG_EVT";
+ case BTA_HD_INT_OPEN_EVT:
+ return "BTA_HD_INT_OPEN_EVT";
+ case BTA_HD_INT_CLOSE_EVT:
+ return "BTA_HD_INT_CLOSE_EVT";
+ case BTA_HD_INT_INTR_DATA_EVT:
+ return "BTA_HD_INT_INTR_DATA_EVT";
+ case BTA_HD_INT_GET_REPORT_EVT:
+ return "BTA_HD_INT_GET_REPORT_EVT";
+ case BTA_HD_INT_SET_REPORT_EVT:
+ return "BTA_HD_INT_SET_REPORT_EVT";
+ case BTA_HD_INT_SET_PROTOCOL_EVT:
+ return "BTA_HD_INT_SET_PROTOCOL_EVT";
+ case BTA_HD_INT_VC_UNPLUG_EVT:
+ return "BTA_HD_INT_VC_UNPLUG_EVT";
+ case BTA_HD_INT_SUSPEND_EVT:
+ return "BTA_HD_INT_SUSPEND_EVT";
+ case BTA_HD_INT_EXIT_SUSPEND_EVT:
+ return "BTA_HD_INT_EXIT_SUSPEND_EVT";
+ default:
+ return "<unknown>";
+ }
+}
+
+static const char* bta_hd_state_code(tBTA_HD_STATE state_code) {
+ switch (state_code) {
+ case BTA_HD_INIT_ST:
+ return "BTA_HD_INIT_ST";
+ case BTA_HD_IDLE_ST:
+ return "BTA_HD_IDLE_ST";
+ case BTA_HD_CONN_ST:
+ return "BTA_HD_CONN_ST";
+ case BTA_HD_TRANSIENT_TO_INIT_ST:
+ return "BTA_HD_TRANSIENT_TO_INIT_ST";
+ default:
+ return "<unknown>";
+ }
+}
+
+#endif /* BTA_HD_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_act.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_act.cc
new file mode 100755
index 0000000..6b82f13
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_act.cc
@@ -0,0 +1,463 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for the handsfree client.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_dm_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "l2c_api.h"
+#include "osi/include/compat.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_HF_CLIENT_RFC_READ_MAX 512
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_start_close
+ *
+ * Description Start the process of closing SCO and RFCOMM connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* Take the link out of sniff and set L2C idle time to 0 */
+ bta_dm_pm_active(client_cb->peer_addr);
+ L2CA_SetIdleTimeoutByBdAddr(client_cb->peer_addr, 0, BT_TRANSPORT_BR_EDR);
+
+ /* if SCO is open close SCO and wait on RFCOMM close */
+ if (client_cb->sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
+ client_cb->sco_close_rfc = true;
+ } else {
+ bta_hf_client_rfc_do_close(p_data);
+ }
+
+ /* always do SCO shutdown to handle all SCO corner cases */
+ bta_hf_client_sco_shutdown(client_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_start_open
+ *
+ * Description This starts an HF Client open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* store parameters */
+ if (p_data) {
+ bdcpy(client_cb->peer_addr, p_data->api_open.bd_addr);
+ client_cb->cli_sec_mask = p_data->api_open.sec_mask;
+ }
+
+ /* Check if RFCOMM has any incoming connection to avoid collision. */
+ BD_ADDR pending_bd_addr;
+ if (PORT_IsOpening(pending_bd_addr)) {
+ /* Let the incoming connection goes through. */
+ /* Issue collision for now. */
+ /* We will decide what to do when we find incoming connection later.*/
+ bta_hf_client_collision_cback(0, BTA_ID_HS, 0, client_cb->peer_addr);
+ return;
+ }
+
+ /* set role */
+ client_cb->role = BTA_HF_CLIENT_INT;
+
+ /* do service search */
+ bta_hf_client_do_disc(client_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_open
+ *
+ * Description Handle RFCOMM channel open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ bta_sys_conn_open(BTA_ID_HS, 1, client_cb->peer_addr);
+
+ /* start SLC procedure */
+ bta_hf_client_slc_seq(client_cb, false);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_acp_open
+ *
+ * Description Handle RFCOMM channel open when accepting connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ uint16_t lcid;
+ BD_ADDR dev_addr;
+ int status;
+
+ /* set role */
+ client_cb->role = BTA_HF_CLIENT_ACP;
+
+ APPL_TRACE_DEBUG("%s: conn_handle %d", __func__, client_cb->conn_handle);
+
+ /* get bd addr of peer */
+ if (PORT_SUCCESS != (status = PORT_CheckConnection(client_cb->conn_handle,
+ dev_addr, &lcid))) {
+ APPL_TRACE_DEBUG("%s: error PORT_CheckConnection returned status %d",
+ __func__, status);
+ }
+
+ /* Collision Handling */
+ if (alarm_is_scheduled(client_cb->collision_timer)) {
+ alarm_cancel(client_cb->collision_timer);
+
+ if (bdcmp(dev_addr, client_cb->peer_addr) == 0) {
+ /* If incoming and outgoing device are same, nothing more to do. */
+ /* Outgoing conn will be aborted because we have successful incoming conn.
+ */
+ } else {
+ /* Resume outgoing connection. */
+ bta_hf_client_resume_open(client_cb);
+ }
+ }
+
+ bdcpy(client_cb->peer_addr, dev_addr);
+
+ /* do service discovery to get features */
+ bta_hf_client_do_disc(client_cb);
+
+ /* continue with open processing */
+ bta_hf_client_rfc_open(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_fail
+ *
+ * Description RFCOMM connection failed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* reinitialize stuff */
+ client_cb->peer_features = 0;
+ client_cb->chld_features = 0;
+ client_cb->role = BTA_HF_CLIENT_ACP;
+ client_cb->svc_conn = false;
+ client_cb->send_at_reply = false;
+ client_cb->negotiated_codec = BTM_SCO_CODEC_CVSD;
+
+ bta_hf_client_at_reset(client_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_disc_fail
+ *
+ * Description This function handles a discovery failure.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_open_fail
+ *
+ * Description open connection failed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_close
+ *
+ * Description RFCOMM connection closed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ bta_hf_client_at_reset(client_cb);
+
+ bta_sys_conn_close(BTA_ID_HS, 1, client_cb->peer_addr);
+
+ /* call close cback */
+ tBTA_HF_CLIENT evt;
+ memset(&evt, 0, sizeof(evt));
+ bdcpy(evt.conn.bd_addr, client_cb->peer_addr);
+
+ /* if not deregistering reopen server */
+ if (bta_hf_client_cb_arr.deregister == false) {
+ /* Make sure SCO is shutdown */
+ bta_hf_client_sco_shutdown(client_cb);
+
+ bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
+ }
+ /* else close port and deallocate scb */
+ else {
+ tBTA_HF_CLIENT evt;
+ memset(&evt, 0, sizeof(evt));
+ bdcpy(evt.reg.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_DISABLE_EVT, &evt);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_disc_int_res
+ *
+ * Description This function handles a discovery result when initiator.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA* p_data) {
+ uint16_t event = BTA_HF_CLIENT_DISC_FAIL_EVT;
+
+ APPL_TRACE_DEBUG("%s: Status: %d", __func__, p_data->disc_result.status);
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ if (bta_hf_client_sdp_find_attr(client_cb)) {
+ event = BTA_HF_CLIENT_DISC_OK_EVT;
+ }
+ }
+
+ /* free discovery db */
+ bta_hf_client_free_db(p_data);
+
+ /* send ourselves sdp ok/fail event */
+ bta_hf_client_sm_execute(event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_disc_acp_res
+ *
+ * Description This function handles a discovery result when acceptor.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ bta_hf_client_sdp_find_attr(client_cb);
+ }
+
+ /* free discovery db */
+ bta_hf_client_free_db(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_data
+ *
+ * Description Read and process data from RFCOMM.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ uint16_t len;
+ char buf[BTA_HF_CLIENT_RFC_READ_MAX];
+ memset(buf, 0, sizeof(buf));
+ /* read data from rfcomm; if bad status, we're done */
+ while (PORT_ReadData(client_cb->conn_handle, buf, BTA_HF_CLIENT_RFC_READ_MAX,
+ &len) == PORT_SUCCESS) {
+ /* if no data, we're done */
+ if (len == 0) {
+ break;
+ }
+
+ bta_hf_client_at_parse(client_cb, buf, len);
+
+ /* no more data to read, we're done */
+ if (len < BTA_HF_CLIENT_RFC_READ_MAX) {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_svc_conn_open
+ *
+ * Description Service level connection opened
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ if (!client_cb->svc_conn) {
+ /* set state variable */
+ client_cb->svc_conn = true;
+
+ /* call callback */
+ bdcpy(evt.conn.bd_addr, client_cb->peer_addr);
+ evt.conn.peer_feat = client_cb->peer_features;
+ evt.conn.chld_feat = client_cb->chld_features;
+
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CONN_EVT, &evt);
+ }
+}
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_api.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_api.cc
new file mode 100755
index 0000000..7c90255
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_api.cc
@@ -0,0 +1,199 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for the handsfree (HF role)
+ * subsystem of BTA
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/compat.h"
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientEnable
+ *
+ * Description Enable the HF CLient service. It does the following:
+ * 1. Sets the state to initialized (control blocks)
+ * 2. Starts the SDP for the client role (HF)
+ * 3. Starts the RFCOMM server to accept incoming connections
+ * The function is synchronous and returns with an error code
+ * if anything went wrong. This should be the first call to the
+ * API before doing an BTA_HfClientOpen
+ *
+ * Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback, tBTA_SEC sec_mask,
+ tBTA_HF_CLIENT_FEAT features,
+ const char* p_service_name) {
+ return bta_hf_client_api_enable(p_cback, sec_mask, features, p_service_name);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientDisable
+ *
+ * Description Disable the HF Client service
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientDisable(void) { bta_hf_client_api_disable(); }
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientOpen
+ *
+ * Description Opens up a RF connection to the remote device and
+ * subsequently set it up for a HF SLC
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, uint16_t* p_handle) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_HF_CLIENT_API_OPEN* p_buf =
+ (tBTA_HF_CLIENT_API_OPEN*)osi_malloc(sizeof(tBTA_HF_CLIENT_API_OPEN));
+
+ if (!bta_hf_client_allocate_handle(bd_addr, p_handle)) {
+ APPL_TRACE_ERROR("%s: could not allocate handle", __func__);
+ return;
+ }
+
+ p_buf->hdr.event = BTA_HF_CLIENT_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = *p_handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientClose
+ *
+ * Description Close the current connection to an audio gateway.
+ * Any current audio connection will also be closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientClose(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_HF_CLIENT_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfCllientAudioOpen
+ *
+ * Description Opens an audio connection to the currently connected
+ * audio gateway
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioOpen(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_HF_CLIENT_API_AUDIO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientAudioClose
+ *
+ * Description Close the currently active audio connection to an audio
+ * gateway. The data connection remains open
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioClose(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientSendAT
+ *
+ * Description send AT command
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientSendAT(uint16_t handle, tBTA_HF_CLIENT_AT_CMD_TYPE at,
+ uint32_t val1, uint32_t val2, const char* str) {
+ tBTA_HF_CLIENT_DATA_VAL* p_buf =
+ (tBTA_HF_CLIENT_DATA_VAL*)osi_malloc(sizeof(tBTA_HF_CLIENT_DATA_VAL));
+
+ p_buf->hdr.event = BTA_HF_CLIENT_SEND_AT_CMD_EVT;
+ p_buf->uint8_val = at;
+ p_buf->uint32_val1 = val1;
+ p_buf->uint32_val2 = val2;
+
+ if (str) {
+ strlcpy(p_buf->str, str, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ p_buf->str[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+ } else {
+ p_buf->str[0] = '\0';
+ }
+
+ p_buf->hdr.layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientDumpStatistics
+ *
+ * Description Dump statistics about the various control blocks
+ * and other relevant connection statistics
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void BTA_HfClientDumpStatistics(int fd) { bta_hf_client_dump_statistics(fd); }
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.cc
new file mode 100755
index 0000000..4076e1e
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.cc
@@ -0,0 +1,2112 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hf_client"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+/* Uncomment to enable AT traffic dumping */
+/* #define BTA_HF_CLIENT_AT_DUMP 1 */
+
+/* minimum length of AT event */
+#define BTA_HF_CLIENT_AT_EVENT_MIN_LEN 3
+
+/* timeout (in milliseconds) for AT response */
+#define BTA_HF_CLIENT_AT_TIMEOUT 29989
+
+/* timeout (in milliseconds) for AT hold timer */
+#define BTA_HF_CLIENT_AT_HOLD_TIMEOUT 41
+
+/******************************************************************************
+ *
+ * DATA TYPES AND CONTAINERS
+ *
+ ******************************************************************************/
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+/******************************************************************************
+ * SUPPORTED EVENT MESSAGES
+ ******************************************************************************/
+
+/* CIND: supported indicator names */
+#define BTA_HF_CLIENT_INDICATOR_BATTERYCHG "battchg"
+#define BTA_HF_CLIENT_INDICATOR_SIGNAL "signal"
+#define BTA_HF_CLIENT_INDICATOR_SERVICE "service"
+#define BTA_HF_CLIENT_INDICATOR_CALL "call"
+#define BTA_HF_CLIENT_INDICATOR_ROAM "roam"
+#define BTA_HF_CLIENT_INDICATOR_CALLSETUP "callsetup"
+#define BTA_HF_CLIENT_INDICATOR_CALLHELD "callheld"
+
+#define MIN(a, b) \
+ ({ \
+ __typeof__(a) _a = (a); \
+ __typeof__(b) _b = (b); \
+ (_a < _b) ? _a : _b; \
+ })
+
+/* CIND: represents each indicators boundaries */
+typedef struct {
+ const char* name;
+ uint8_t min;
+ uint8_t max;
+ uint8_t namelen;
+} tBTA_HF_CLIENT_INDICATOR;
+
+#define BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT 7
+
+/* CIND: storage room for indicators value range and their statuses */
+static const tBTA_HF_CLIENT_INDICATOR
+ bta_hf_client_indicators[BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT] = {
+ /* name | min | max | name length -
+ used by parser */
+ {BTA_HF_CLIENT_INDICATOR_BATTERYCHG, 0, 5,
+ sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
+ {BTA_HF_CLIENT_INDICATOR_SIGNAL, 0, 5,
+ sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
+ {BTA_HF_CLIENT_INDICATOR_SERVICE, 0, 1,
+ sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
+ {BTA_HF_CLIENT_INDICATOR_CALL, 0, 1,
+ sizeof(BTA_HF_CLIENT_INDICATOR_CALL)},
+ {BTA_HF_CLIENT_INDICATOR_ROAM, 0, 1,
+ sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
+ {BTA_HF_CLIENT_INDICATOR_CALLSETUP, 0, 3,
+ sizeof(BTA_HF_CLIENT_INDICATOR_CALLSETUP)},
+ {BTA_HF_CLIENT_INDICATOR_CALLHELD, 0, 2,
+ sizeof(BTA_HF_CLIENT_INDICATOR_CALLHELD)}};
+
+/* +VGM/+VGS - gain min/max values */
+#define BTA_HF_CLIENT_VGS_MIN 0
+#define BTA_HF_CLIENT_VGS_MAX 15
+#define BTA_HF_CLIENT_VGM_MIN 0
+#define BTA_HF_CLIENT_VGM_MAX 15
+
+uint32_t service_index = 0;
+bool service_availability = true;
+/* helper functions for handling AT commands queueing */
+
+static void bta_hf_client_handle_ok(tBTA_HF_CLIENT_CB* client_cb);
+
+static void bta_hf_client_clear_queued_at(tBTA_HF_CLIENT_CB* client_cb) {
+ tBTA_HF_CLIENT_AT_QCMD* cur = client_cb->at_cb.queued_cmd;
+ tBTA_HF_CLIENT_AT_QCMD* next;
+
+ while (cur != NULL) {
+ next = cur->next;
+ osi_free(cur);
+ cur = next;
+ }
+
+ client_cb->at_cb.queued_cmd = NULL;
+}
+
+static void bta_hf_client_queue_at(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_AT_CMD cmd, const char* buf,
+ uint16_t buf_len) {
+ tBTA_HF_CLIENT_AT_QCMD* new_cmd =
+ (tBTA_HF_CLIENT_AT_QCMD*)osi_malloc(sizeof(tBTA_HF_CLIENT_AT_QCMD));
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ new_cmd->cmd = cmd;
+ new_cmd->buf_len = buf_len;
+ new_cmd->next = NULL;
+ memcpy(new_cmd->buf, buf, buf_len);
+
+ if (client_cb->at_cb.queued_cmd != NULL) {
+ tBTA_HF_CLIENT_AT_QCMD* qcmd = client_cb->at_cb.queued_cmd;
+
+ while (qcmd->next != NULL) qcmd = qcmd->next;
+
+ qcmd->next = new_cmd;
+ } else {
+ client_cb->at_cb.queued_cmd = new_cmd;
+ }
+}
+
+static void bta_hf_client_at_resp_timer_cback(void* data) {
+ tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;
+ if (client_cb->at_cb.current_cmd == BTA_HF_CLIENT_AT_CNUM) {
+ LOG_INFO(LOG_TAG,
+ "%s: timed out waiting for AT+CNUM response; spoofing OK.",
+ __func__);
+ bta_hf_client_handle_ok(client_cb);
+ } else {
+ APPL_TRACE_ERROR("HFPClient: AT response timeout, disconnecting");
+
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
+ }
+}
+
+static void bta_hf_client_start_at_resp_timer(tBTA_HF_CLIENT_CB* client_cb) {
+ alarm_set_on_queue(client_cb->at_cb.resp_timer, BTA_HF_CLIENT_AT_TIMEOUT,
+ bta_hf_client_at_resp_timer_cback, (void*)client_cb,
+ btu_bta_alarm_queue);
+}
+
+static void bta_hf_client_stop_at_resp_timer(tBTA_HF_CLIENT_CB* client_cb) {
+ alarm_cancel(client_cb->at_cb.resp_timer);
+}
+
+static void bta_hf_client_send_at(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_AT_CMD cmd, const char* buf,
+ uint16_t buf_len) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ if ((client_cb->at_cb.current_cmd == BTA_HF_CLIENT_AT_NONE ||
+ client_cb->svc_conn == false) &&
+ !alarm_is_scheduled(client_cb->at_cb.hold_timer)) {
+ uint16_t len;
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+ APPL_TRACE_DEBUG("%s: %.*s", __func__, buf_len - 1, buf);
+#endif
+
+ client_cb->at_cb.current_cmd = cmd;
+ /* Generate fake responses for these because they won't reliably work */
+ if (!service_availability &&
+ (cmd == BTA_HF_CLIENT_AT_CNUM || cmd == BTA_HF_CLIENT_AT_COPS)) {
+ APPL_TRACE_WARNING("%s: No service, skipping %d command", __func__, cmd);
+ bta_hf_client_handle_ok(client_cb);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: writing port data to %d", __func__,
+ client_cb->conn_handle);
+ PORT_WriteData(client_cb->conn_handle, buf, buf_len, &len);
+
+ bta_hf_client_start_at_resp_timer(client_cb);
+
+ return;
+ }
+
+ bta_hf_client_queue_at(client_cb, cmd, buf, buf_len);
+}
+
+static void bta_hf_client_send_queued_at(tBTA_HF_CLIENT_CB* client_cb) {
+ tBTA_HF_CLIENT_AT_QCMD* cur = client_cb->at_cb.queued_cmd;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (cur != NULL) {
+ client_cb->at_cb.queued_cmd = cur->next;
+
+ bta_hf_client_send_at(client_cb, cur->cmd, cur->buf, cur->buf_len);
+
+ osi_free(cur);
+ }
+}
+
+static void bta_hf_client_at_hold_timer_cback(void* data) {
+ tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;
+ APPL_TRACE_DEBUG("%s", __func__);
+ bta_hf_client_send_queued_at(client_cb);
+}
+
+static void bta_hf_client_stop_at_hold_timer(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(client_cb->at_cb.hold_timer);
+}
+
+static void bta_hf_client_start_at_hold_timer(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ alarm_set_on_queue(client_cb->at_cb.hold_timer, BTA_HF_CLIENT_AT_HOLD_TIMEOUT,
+ bta_hf_client_at_hold_timer_cback, (void*)client_cb,
+ btu_bta_alarm_queue);
+}
+
+/******************************************************************************
+ *
+ * COMMON AT EVENT HANDLING funcS
+ *
+ * Receives data (strings, ints, etc.) from the parser and processes this
+ * data. No buffer parsing is being done here.
+ ******************************************************************************/
+
+static void bta_hf_client_handle_ok(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ bta_hf_client_stop_at_resp_timer(client_cb);
+
+ if (!client_cb->svc_conn) {
+ bta_hf_client_slc_seq(client_cb, false);
+ return;
+ }
+
+ switch (client_cb->at_cb.current_cmd) {
+ case BTA_HF_CLIENT_AT_BIA:
+ case BTA_HF_CLIENT_AT_BCC:
+ break;
+ case BTA_HF_CLIENT_AT_BCS:
+ bta_hf_client_start_at_hold_timer(client_cb);
+ client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+ return;
+ case BTA_HF_CLIENT_AT_CLIP: // last cmd is post slc seq
+ if (client_cb->send_at_reply == false) {
+ client_cb->send_at_reply = true;
+ }
+ break;
+ case BTA_HF_CLIENT_AT_NONE:
+ bta_hf_client_stop_at_hold_timer(client_cb);
+ break;
+ default:
+ if (client_cb->send_at_reply) {
+ bta_hf_client_at_result(client_cb, BTA_HF_CLIENT_AT_RESULT_OK, 0);
+ }
+ break;
+ }
+
+ client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+ bta_hf_client_send_queued_at(client_cb);
+}
+
+static void bta_hf_client_handle_error(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_AT_RESULT_TYPE type,
+ uint16_t cme) {
+ APPL_TRACE_DEBUG("%s: %u %u", __func__, type, cme);
+
+ bta_hf_client_stop_at_resp_timer(client_cb);
+
+ if (!client_cb->svc_conn) {
+ bta_hf_client_slc_seq(client_cb, true);
+ return;
+ }
+
+ switch (client_cb->at_cb.current_cmd) {
+ case BTA_HF_CLIENT_AT_BIA:
+ break;
+ case BTA_HF_CLIENT_AT_BCC:
+ case BTA_HF_CLIENT_AT_BCS:
+ bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+ break;
+ case BTA_HF_CLIENT_AT_CLIP: // last cmd is post slc seq
+ if (client_cb->send_at_reply == false) {
+ client_cb->send_at_reply = true;
+ }
+ break;
+ default:
+ if (client_cb->send_at_reply) {
+ bta_hf_client_at_result(client_cb, type, cme);
+ }
+ break;
+ }
+
+ client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+ bta_hf_client_send_queued_at(client_cb);
+}
+
+static void bta_hf_client_handle_ring(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_RING_INDICATION, 0);
+}
+
+static void bta_hf_client_handle_brsf(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t value) {
+ APPL_TRACE_DEBUG("%s: 0x%x", __func__, value);
+ client_cb->peer_features = value;
+}
+
+/* handles a single indicator descriptor - registers it for value changing
+ * events */
+static void bta_hf_client_handle_cind_list_item(tBTA_HF_CLIENT_CB* client_cb,
+ char* name, uint32_t min,
+ uint32_t max, uint32_t index) {
+ uint8_t i = 0;
+
+ APPL_TRACE_DEBUG("%s: %lu.%s <%lu:%lu>", __func__, index, name, min, max);
+
+ /* look for a matching indicator on list of supported ones */
+ for (i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++) {
+ if (strcmp(name, BTA_HF_CLIENT_INDICATOR_SERVICE) == 0) {
+ service_index = index;
+ }
+ /* look for a match - search one sign further than indicators name to check
+ * for string end */
+ /* It will distinguish 'callheld' which could be matched by strncmp as
+ * 'call'. */
+ if (strncmp(name, bta_hf_client_indicators[i].name,
+ bta_hf_client_indicators[i].namelen) != 0)
+ continue;
+
+ /* index - enumerates value position in the incoming sequence */
+ /* if name matches one of the known indicators, add its incoming position */
+ /* to lookup table for easy value->indicator matching later, when only
+ * values come */
+ client_cb->at_cb.indicator_lookup[index] = i;
+
+ return;
+ }
+}
+
+static void bta_hf_client_handle_cind_value(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t index, uint32_t value) {
+ APPL_TRACE_DEBUG("%s: index: %u value: %u", __func__, index, value);
+
+ if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+ return;
+ }
+
+ if (service_index == index) {
+ if (value == 0) {
+ service_availability = false;
+ } else {
+ service_availability = true;
+ }
+ }
+ if (client_cb->at_cb.indicator_lookup[index] == -1) {
+ return;
+ }
+
+ /* get the real array index from lookup table */
+ index = client_cb->at_cb.indicator_lookup[index];
+
+ /* Ignore out of range values */
+ if (value > bta_hf_client_indicators[index].max ||
+ value < bta_hf_client_indicators[index].min) {
+ return;
+ }
+
+ /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+ bta_hf_client_ind(client_cb, index, value);
+}
+
+static void bta_hf_client_handle_chld(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t mask) {
+ APPL_TRACE_DEBUG("%s: 0x%x", __func__, mask);
+
+ client_cb->chld_features |= mask;
+}
+
+static void bta_hf_client_handle_ciev(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t index, uint32_t value) {
+ int8_t realind = -1;
+
+ APPL_TRACE_DEBUG("%s: index: %u value: %u", __func__, index, value);
+
+ if (index == 0 || index > BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
+ return;
+ }
+
+ if (service_index == index - 1) {
+ service_availability = value == 0 ? false : true;
+ }
+
+ realind = client_cb->at_cb.indicator_lookup[index - 1];
+
+ if (realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT) {
+ /* get the real in-array index from lookup table by index it comes at */
+ /* if there is no bug it should automatically be correctly calculated */
+ if (value > bta_hf_client_indicators[realind].max ||
+ value < bta_hf_client_indicators[realind].min) {
+ return;
+ }
+
+ /* update service availability on +ciev from AG. */
+ if (service_index == (index - 1)) {
+ if (value == 1) {
+ service_availability = true;
+ } else {
+ service_availability = false;
+ }
+ }
+
+ /* tBTA_HF_CLIENT_IND_TYPE match index in bta_hf_client_indicators */
+ bta_hf_client_ind(client_cb, realind, value);
+ }
+}
+
+static void bta_hf_client_handle_bcs(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t codec) {
+ APPL_TRACE_DEBUG("%s: codec: %u sco listen state: %d", __func__, codec,
+ client_cb->sco_state);
+ if (codec == BTM_SCO_CODEC_CVSD || codec == BTM_SCO_CODEC_MSBC) {
+ client_cb->negotiated_codec = codec;
+ bta_hf_client_send_at_bcs(client_cb, codec);
+ } else {
+ client_cb->negotiated_codec = BTM_SCO_CODEC_CVSD;
+ bta_hf_client_send_at_bac(client_cb);
+ }
+}
+
+static void bta_hf_client_handle_bsir(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t provided) {
+ APPL_TRACE_DEBUG("%s: %u", __func__, provided);
+
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_BSIR_EVT, provided);
+}
+
+static void bta_hf_client_handle_cmeerror(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t code) {
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_CME, code);
+}
+
+static void bta_hf_client_handle_vgm(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t value) {
+ APPL_TRACE_DEBUG("%s: %lu", __func__, value);
+
+ if (value <= BTA_HF_CLIENT_VGM_MAX) {
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_MIC_EVT, value);
+ }
+}
+
+static void bta_hf_client_handle_vgs(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t value) {
+ APPL_TRACE_DEBUG("%s: %lu", __func__, value);
+
+ if (value <= BTA_HF_CLIENT_VGS_MAX) {
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_SPK_EVT, value);
+ }
+}
+
+static void bta_hf_client_handle_bvra(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t value) {
+ APPL_TRACE_DEBUG("%s: %lu", __func__, value);
+
+ if (value > 1) {
+ return;
+ }
+
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_VOICE_REC_EVT, value);
+}
+
+static void bta_hf_client_handle_clip(tBTA_HF_CLIENT_CB* client_cb,
+ char* numstr, uint32_t type) {
+ APPL_TRACE_DEBUG("%s: %u %s", __func__, type, numstr);
+
+ bta_hf_client_clip(client_cb, numstr);
+}
+
+static void bta_hf_client_handle_ccwa(tBTA_HF_CLIENT_CB* client_cb,
+ char* numstr, uint32_t type) {
+ APPL_TRACE_DEBUG("%s: %u %s", __func__, type, numstr);
+
+ bta_hf_client_ccwa(client_cb, numstr);
+}
+
+static void bta_hf_client_handle_cops(tBTA_HF_CLIENT_CB* client_cb, char* opstr,
+ uint32_t mode) {
+ APPL_TRACE_DEBUG("%s: %u %s", __func__, mode, opstr);
+
+ bta_hf_client_operator_name(client_cb, opstr);
+}
+
+static void bta_hf_client_handle_binp(tBTA_HF_CLIENT_CB* client_cb,
+ char* numstr) {
+ APPL_TRACE_DEBUG("%s: %s", __func__, numstr);
+
+ bta_hf_client_binp(client_cb, numstr);
+}
+
+static void bta_hf_client_handle_clcc(tBTA_HF_CLIENT_CB* client_cb,
+ uint16_t idx, uint16_t dir,
+ uint16_t status, uint16_t mode,
+ uint16_t mpty, char* numstr,
+ uint16_t type) {
+ APPL_TRACE_DEBUG("%s: idx: %u dir: %u status: %u mode: %u mpty: %u", __func__,
+ idx, dir, status, mode, mpty);
+
+ if (numstr) {
+ APPL_TRACE_DEBUG("%s: number: %s type: %u", __func__, numstr, type);
+ }
+
+ bta_hf_client_clcc(client_cb, idx, dir, status, mpty, numstr);
+}
+
+static void bta_hf_client_handle_cnum(tBTA_HF_CLIENT_CB* client_cb,
+ char* numstr, uint16_t type,
+ uint16_t service) {
+ APPL_TRACE_DEBUG("%s: number: %s type: %u service: %u", __func__, numstr,
+ type, service);
+
+ /* TODO: should number be modified according to type? */
+ bta_hf_client_cnum(client_cb, numstr, service);
+}
+
+static void bta_hf_client_handle_btrh(tBTA_HF_CLIENT_CB* client_cb,
+ uint16_t code) {
+ APPL_TRACE_DEBUG("%s: %lu", __func__, code);
+
+ bta_hf_client_evt_val(client_cb, BTA_HF_CLIENT_BTRH_EVT, code);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_cback_ind
+ *
+ * Description Send indicator callback event to application.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_ind(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_IND_TYPE type, uint16_t value) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ evt.ind.type = type;
+ evt.ind.value = value;
+
+ bdcpy(evt.ind.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_IND_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_evt_val
+ *
+ * Description Send event to application.
+ * This is a generic helper for events with common data.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_evt_val(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_EVT type, uint16_t value) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ bdcpy(evt.val.bd_addr, client_cb->peer_addr);
+ evt.val.value = value;
+
+ bta_hf_client_app_callback(type, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_operator_name
+ *
+ * Description Send operator name event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_operator_name(tBTA_HF_CLIENT_CB* client_cb, char* name) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.operator_name.name, name, BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1);
+ evt.operator_name.name[BTA_HF_CLIENT_OPERATOR_NAME_LEN] = '\0';
+
+ bdcpy(evt.operator_name.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_OPERATOR_NAME_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_clip
+ *
+ * Description Send CLIP event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_clip(tBTA_HF_CLIENT_CB* client_cb, char* number) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+ bdcpy(evt.number.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CLIP_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_ccwa
+ *
+ * Description Send CLIP event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_ccwa(tBTA_HF_CLIENT_CB* client_cb, char* number) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+ bdcpy(evt.number.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CCWA_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_at_result
+ *
+ * Description Send AT result event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_at_result(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_AT_RESULT_TYPE type, uint16_t cme) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ evt.result.type = type;
+ evt.result.cme = cme;
+
+ bdcpy(evt.result.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_AT_RESULT_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_clcc
+ *
+ * Description Send clcc event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_clcc(tBTA_HF_CLIENT_CB* client_cb, uint32_t idx,
+ bool incoming, uint8_t status, bool mpty,
+ char* number) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ evt.clcc.idx = idx;
+ evt.clcc.inc = incoming;
+ evt.clcc.status = status;
+ evt.clcc.mpty = mpty;
+
+ if (number) {
+ evt.clcc.number_present = true;
+ strlcpy(evt.clcc.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ evt.clcc.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+ }
+
+ bdcpy(evt.clcc.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CLCC_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_cnum
+ *
+ * Description Send cnum event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_cnum(tBTA_HF_CLIENT_CB* client_cb, char* number,
+ uint16_t service) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ evt.cnum.service = service;
+ strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ evt.cnum.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+ bdcpy(evt.cnum.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CNUM_EVT, &evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_binp
+ *
+ * Description Send BINP event to application.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_binp(tBTA_HF_CLIENT_CB* client_cb, char* number) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+
+ strlcpy(evt.number.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
+ evt.number.number[BTA_HF_CLIENT_NUMBER_LEN] = '\0';
+
+ bdcpy(evt.number.bd_addr, client_cb->peer_addr);
+ bta_hf_client_app_callback(BTA_HF_CLIENT_BINP_EVT, &evt);
+}
+
+/******************************************************************************
+ *
+ * COMMON AT EVENTS PARSING FUNCTIONS
+ *
+ ******************************************************************************/
+
+/* Check if prefix match and skip spaces if any */
+#define AT_CHECK_EVENT(buf, event) \
+ do { \
+ if (strncmp("\r\n" event, buf, sizeof("\r\n" event) - 1) != 0) return buf; \
+ (buf) += sizeof("\r\n" event) - 1; \
+ while (*(buf) == ' ') (buf)++; \
+ } while (0)
+
+/* check for <cr><lf> and forward buffer if match */
+#define AT_CHECK_RN(buf) \
+ do { \
+ if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \
+ APPL_TRACE_DEBUG("%s: missing end <cr><lf>", __func__); \
+ return NULL; \
+ } \
+ (buf) += sizeof("\r\n") - 1; \
+ } while (0)
+
+/* skip rest of AT string up to <cr> */
+#define AT_SKIP_REST(buf) \
+ do { \
+ while (*(buf) != '\r') (buf)++; \
+ } while (0)
+
+static char* bta_hf_client_parse_ok(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok(client_cb);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_error(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "ERROR");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_ERROR, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_ring(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "RING");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ring(client_cb);
+
+ return buffer;
+}
+
+/* generic uint32 parser */
+static char* bta_hf_client_parse_uint32(
+ tBTA_HF_CLIENT_CB* client_cb, char* buffer,
+ void (*handler_callback)(tBTA_HF_CLIENT_CB*, uint32_t)) {
+ uint32_t value;
+ int res;
+ int offset;
+
+ res = sscanf(buffer, "%u%n", &value, &offset);
+ if (res < 1) {
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_CHECK_RN(buffer);
+
+ handler_callback(client_cb, value);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_brsf(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+BRSF:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_brsf);
+}
+
+static char* bta_hf_client_parse_cind_values(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ /* value and its position */
+ uint16_t index = 0;
+ uint32_t value = 0;
+
+ int offset;
+ int res;
+
+ while ((res = sscanf(buffer, "%u%n", &value, &offset)) > 0) {
+ /* decides if its valid index and value, if yes stores it */
+ bta_hf_client_handle_cind_value(client_cb, index, value);
+
+ buffer += offset;
+
+ /* check if more values are present */
+ if (*buffer != ',') {
+ break;
+ }
+
+ index++;
+ buffer++;
+ }
+
+ if (res > 0) {
+ AT_CHECK_RN(buffer);
+ return buffer;
+ }
+
+ return NULL;
+}
+
+static char* bta_hf_client_parse_cind_list(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ int offset = 0;
+ char name[129];
+ uint32_t min, max;
+ uint32_t index = 0;
+ int res;
+
+ while ((res = sscanf(buffer, "(\"%128[^\"]\",(%u%*[-,]%u))%n", name, &min,
+ &max, &offset)) > 2) {
+ bta_hf_client_handle_cind_list_item(client_cb, name, min, max, index);
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+ index++;
+
+ if (*buffer != ',') {
+ break;
+ }
+
+ buffer++;
+ }
+
+ if (res > 2) {
+ AT_CHECK_RN(buffer);
+ return buffer;
+ }
+
+ return NULL;
+}
+
+static char* bta_hf_client_parse_cind(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+CIND:");
+
+ if (*buffer == '(') return bta_hf_client_parse_cind_list(client_cb, buffer);
+
+ return bta_hf_client_parse_cind_values(client_cb, buffer);
+}
+
+static char* bta_hf_client_parse_chld(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+CHLD:");
+
+ if (*buffer != '(') {
+ return NULL;
+ }
+
+ buffer++;
+
+ while (*buffer != '\0') {
+ if (strncmp("0", buffer, 1) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_REL);
+ buffer++;
+ } else if (strncmp("1x", buffer, 2) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_REL_X);
+ buffer += 2;
+ } else if (strncmp("1", buffer, 1) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_REL_ACC);
+ buffer++;
+ } else if (strncmp("2x", buffer, 2) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_PRIV_X);
+ buffer += 2;
+ } else if (strncmp("2", buffer, 1) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_HOLD_ACC);
+ buffer++;
+ } else if (strncmp("3", buffer, 1) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_MERGE);
+ buffer++;
+ } else if (strncmp("4", buffer, 1) == 0) {
+ bta_hf_client_handle_chld(client_cb, BTA_HF_CLIENT_CHLD_MERGE_DETACH);
+ buffer++;
+ } else {
+ return NULL;
+ }
+
+ if (*buffer == ',') {
+ buffer++;
+ continue;
+ }
+
+ if (*buffer == ')') {
+ buffer++;
+ break;
+ }
+
+ return NULL;
+ }
+
+ AT_CHECK_RN(buffer);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_ciev(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ uint32_t index, value;
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+CIEV:");
+
+ res = sscanf(buffer, "%u,%u%n", &index, &value, &offset);
+ if (res < 2) {
+ return NULL;
+ }
+
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ciev(client_cb, index, value);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_bcs(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+BCS:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_bcs);
+}
+
+static char* bta_hf_client_parse_bsir(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+BSIR:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_bsir);
+}
+
+static char* bta_hf_client_parse_cmeerror(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+CME ERROR:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_cmeerror);
+}
+
+static char* bta_hf_client_parse_vgm(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+VGM:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_vgm);
+}
+
+static char* bta_hf_client_parse_vgme(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+VGM=");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_vgm);
+}
+
+static char* bta_hf_client_parse_vgs(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+VGS:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_vgs);
+}
+
+static char* bta_hf_client_parse_vgse(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+VGS=");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_vgs);
+}
+
+static char* bta_hf_client_parse_bvra(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "+BVRA:");
+
+ return bta_hf_client_parse_uint32(client_cb, buffer,
+ bta_hf_client_handle_bvra);
+}
+
+static char* bta_hf_client_parse_clip(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ /* spec forces 32 chars, plus \0 here */
+ char number[33];
+ uint32_t type = 0;
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+CLIP:");
+
+ /* there might be something more after %lu but HFP doesn't care */
+ res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+ if (res < 2) {
+ return NULL;
+ }
+
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_SKIP_REST(buffer);
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_clip(client_cb, number, type);
+ return buffer;
+}
+
+/* in HFP context there is no difference between ccwa and clip */
+static char* bta_hf_client_parse_ccwa(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ /* ac to spec 32 chars max, plus \0 here */
+ char number[33];
+ uint32_t type = 0;
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+CCWA:");
+
+ /* there might be something more after %lu but HFP doesn't care */
+ res = sscanf(buffer, "\"%32[^\"]\",%u%n", number, &type, &offset);
+ if (res < 2) {
+ return NULL;
+ }
+
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_SKIP_REST(buffer);
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ccwa(client_cb, number, type);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_cops(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ uint8_t mode;
+ /* spec forces 16 chars max, plus \0 here */
+ char opstr[17];
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+COPS:");
+
+ /* TODO: Not sure if operator string actually can contain escaped " char
+ * inside */
+ res = sscanf(buffer, "%hhi,0,\"%16[^\"]\"%n", &mode, opstr, &offset);
+ if (res < 2) {
+ return NULL;
+ }
+ /* Abort in case offset not set because of format error */
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_SKIP_REST(buffer);
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_cops(client_cb, opstr, mode);
+ // check for OK Response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok(client_cb);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_binp(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ /* HFP only supports phone number as BINP data */
+ /* phone number is 32 chars plus one for \0*/
+ char numstr[33];
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+BINP:");
+
+ res = sscanf(buffer, "\"%32[^\"]\"\r\n%n", numstr, &offset);
+ if (res < 1) {
+ return NULL;
+ }
+
+ /* Abort in case offset not set because of format error */
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ /* some phones might sent type as well, just skip it */
+ AT_SKIP_REST(buffer);
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_binp(client_cb, numstr);
+
+ // check for OK response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok(client_cb);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_clcc(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ uint16_t idx, dir, status, mode, mpty;
+ char numstr[33]; /* spec forces 32 chars, plus one for \0*/
+ uint16_t type;
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+CLCC:");
+
+ res = sscanf(buffer, "%hu,%hu,%hu,%hu,%hu%n", &idx, &dir, &status, &mode,
+ &mpty, &offset);
+ if (res < 5) {
+ return NULL;
+ }
+
+ /* Abort in case offset not set because of format error */
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+ offset = 0;
+
+ /* check optional part */
+ if (*buffer == ',') {
+ int res2 = sscanf(buffer, ",\"%32[^\"]\",%hu%n", numstr, &type, &offset);
+ if (res2 < 0) return NULL;
+
+ if (res2 == 0) {
+ res2 = sscanf(buffer, ",\"\",%hu%n", &type, &offset);
+ if (res2 < 0) return NULL;
+
+ /* numstr is not matched in second attempt, correct this */
+ res2++;
+ numstr[0] = '\0';
+ }
+
+ if (res2 >= 2) {
+ res += res2;
+ /* Abort in case offset not set because of format error */
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+ }
+ }
+
+ /* Skip any remaing param,as they are not defined by BT HFP spec */
+ AT_SKIP_REST(buffer);
+ AT_CHECK_RN(buffer);
+
+ if (res > 6) {
+ /* we also have last two optional parameters */
+ bta_hf_client_handle_clcc(client_cb, idx, dir, status, mode, mpty, numstr,
+ type);
+ } else {
+ /* we didn't get the last two parameters */
+ bta_hf_client_handle_clcc(client_cb, idx, dir, status, mode, mpty, NULL, 0);
+ }
+
+ // check for OK response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok(client_cb);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_cnum(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ char numstr[33]; /* spec forces 32 chars, plus one for \0*/
+ uint16_t type;
+ uint16_t service =
+ 0; /* 0 in case this optional parameter is not being sent */
+ int res;
+ int offset = 0;
+
+ AT_CHECK_EVENT(buffer, "+CNUM:");
+
+ res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service,
+ &offset);
+ if (res < 0) {
+ return NULL;
+ }
+
+ if (res == 0) {
+ res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
+ if (res < 0) {
+ return NULL;
+ }
+
+ /* numstr is not matched in second attempt, correct this */
+ res++;
+ numstr[0] = '\0';
+ }
+
+ if (res < 3) {
+ return NULL;
+ }
+
+ /* Abort in case offset not set because of format error */
+ if (offset == 0) {
+ APPL_TRACE_ERROR("%s: Format Error %s", __func__, buffer);
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_CHECK_RN(buffer);
+
+ /* service is optional */
+ if (res == 2) {
+ bta_hf_client_handle_cnum(client_cb, numstr, type, service);
+ return buffer;
+ }
+
+ if (service != 4 && service != 5) {
+ return NULL;
+ }
+
+ bta_hf_client_handle_cnum(client_cb, numstr, type, service);
+
+ // check for OK response in end
+ AT_CHECK_EVENT(buffer, "OK");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_ok(client_cb);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_btrh(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ uint16_t code = 0;
+ int res;
+ int offset;
+
+ AT_CHECK_EVENT(buffer, "+BTRH:");
+
+ res = sscanf(buffer, "%hu%n", &code, &offset);
+ if (res < 1) {
+ return NULL;
+ }
+
+ buffer += offset;
+
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_btrh(client_cb, code);
+ return buffer;
+}
+
+static char* bta_hf_client_parse_busy(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "BUSY");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_BUSY, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_delayed(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "DELAYED");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_DELAY, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_no_carrier(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "NO CARRIER");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_NO_CARRIER, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_no_answer(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "NO ANSWER");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_NO_ANSWER, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_parse_blacklisted(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ AT_CHECK_EVENT(buffer, "BLACKLISTED");
+ AT_CHECK_RN(buffer);
+
+ bta_hf_client_handle_error(client_cb, BTA_HF_CLIENT_AT_RESULT_BLACKLISTED, 0);
+
+ return buffer;
+}
+
+static char* bta_hf_client_skip_unknown(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ char* start;
+ char* tmp;
+
+ tmp = strstr(buffer, "\r\n");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ buffer += 2;
+ start = buffer;
+
+ tmp = strstr(buffer, "\r\n");
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ buffer = tmp + 2;
+
+ APPL_TRACE_DEBUG("%s: %.*s", __func__, buffer - start - 2, start);
+
+ return buffer;
+}
+
+/******************************************************************************
+ * SUPPORTED EVENT MESSAGES
+ ******************************************************************************/
+
+/* returned values are as follow:
+ * != NULL && != buf : match and parsed ok
+ * == NULL : match but parse failed
+ * != NULL && == buf : no match
+ */
+typedef char* (*tBTA_HF_CLIENT_PARSER_CALLBACK)(tBTA_HF_CLIENT_CB*, char*);
+
+static const tBTA_HF_CLIENT_PARSER_CALLBACK bta_hf_client_parser_cb[] = {
+ bta_hf_client_parse_ok, bta_hf_client_parse_error,
+ bta_hf_client_parse_ring, bta_hf_client_parse_brsf,
+ bta_hf_client_parse_cind, bta_hf_client_parse_ciev,
+ bta_hf_client_parse_chld, bta_hf_client_parse_bcs,
+ bta_hf_client_parse_bsir, bta_hf_client_parse_cmeerror,
+ bta_hf_client_parse_vgm, bta_hf_client_parse_vgme,
+ bta_hf_client_parse_vgs, bta_hf_client_parse_vgse,
+ bta_hf_client_parse_bvra, bta_hf_client_parse_clip,
+ bta_hf_client_parse_ccwa, bta_hf_client_parse_cops,
+ bta_hf_client_parse_binp, bta_hf_client_parse_clcc,
+ bta_hf_client_parse_cnum, bta_hf_client_parse_btrh,
+ bta_hf_client_parse_busy, bta_hf_client_parse_delayed,
+ bta_hf_client_parse_no_carrier, bta_hf_client_parse_no_answer,
+ bta_hf_client_parse_blacklisted, bta_hf_client_skip_unknown};
+
+/* calculate supported event list length */
+static const uint16_t bta_hf_client_parser_cb_count =
+ sizeof(bta_hf_client_parser_cb) / sizeof(bta_hf_client_parser_cb[0]);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+static void bta_hf_client_dump_at(tBTA_HF_CLIENT_CB* client_cb) {
+ char dump[(4 * BTA_HF_CLIENT_AT_PARSER_MAX_LEN) + 1];
+ char *p1, *p2;
+
+ p1 = client_cb->at_cb.buf;
+ p2 = dump;
+
+ while (*p1 != '\0') {
+ if (*p1 == '\r') {
+ strlcpy(p2, "<cr>", 4);
+ p2 += 4;
+ } else if (*p1 == '\n') {
+ strlcpy(p2, "<lf>", 4);
+ p2 += 4;
+ } else {
+ *p2 = *p1;
+ p2++;
+ }
+ p1++;
+ }
+
+ *p2 = '\0';
+
+ APPL_TRACE_DEBUG("%s: %s", __func__, dump);
+}
+#endif
+
+static void bta_hf_client_at_parse_start(tBTA_HF_CLIENT_CB* client_cb) {
+ char* buf = client_cb->at_cb.buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+#ifdef BTA_HF_CLIENT_AT_DUMP
+ bta_hf_client_dump_at(client_cb);
+#endif
+
+ while (*buf != '\0') {
+ int i;
+ char* tmp = NULL;
+
+ for (i = 0; i < bta_hf_client_parser_cb_count; i++) {
+ tmp = bta_hf_client_parser_cb[i](client_cb, buf);
+ if (tmp == NULL) {
+ APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping");
+ tmp = bta_hf_client_skip_unknown(client_cb, buf);
+ break;
+ }
+
+ /* matched or unknown skipped, if unknown failed tmp is NULL so
+ this is also handled */
+ if (tmp != buf) {
+ buf = tmp;
+ break;
+ }
+ }
+
+ /* could not skip unknown (received garbage?)... disconnect */
+ if (tmp == NULL) {
+ APPL_TRACE_ERROR(
+ "HFPCient: could not skip unknown AT event, disconnecting");
+ bta_hf_client_at_reset(client_cb);
+
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
+ return;
+ }
+
+ buf = tmp;
+ }
+}
+
+static bool bta_hf_client_check_at_complete(tBTA_HF_CLIENT_CB* client_cb) {
+ bool ret = false;
+ tBTA_HF_CLIENT_AT_CB* at_cb = &client_cb->at_cb;
+
+ if (at_cb->offset >= BTA_HF_CLIENT_AT_EVENT_MIN_LEN) {
+ if (at_cb->buf[at_cb->offset - 2] == '\r' &&
+ at_cb->buf[at_cb->offset - 1] == '\n') {
+ ret = true;
+ }
+ }
+
+ APPL_TRACE_DEBUG("%s: %d", __func__, ret);
+
+ return ret;
+}
+
+static void bta_hf_client_at_clear_buf(tBTA_HF_CLIENT_CB* client_cb) {
+ memset(client_cb->at_cb.buf, 0, sizeof(client_cb->at_cb.buf));
+ client_cb->at_cb.offset = 0;
+}
+
+/******************************************************************************
+ *
+ * MAIN PARSING FUNCTION
+ *
+ *
+ ******************************************************************************/
+void bta_hf_client_at_parse(tBTA_HF_CLIENT_CB* client_cb, char* buf,
+ unsigned int len) {
+ APPL_TRACE_DEBUG("%s: offset: %u len: %u", __func__, client_cb->at_cb.offset,
+ len);
+
+ if (len + client_cb->at_cb.offset > BTA_HF_CLIENT_AT_PARSER_MAX_LEN) {
+ char tmp_buff[BTA_HF_CLIENT_AT_PARSER_MAX_LEN];
+ unsigned int tmp = client_cb->at_cb.offset;
+ unsigned int space_left =
+ BTA_HF_CLIENT_AT_PARSER_MAX_LEN - client_cb->at_cb.offset;
+
+ APPL_TRACE_DEBUG("%s: overrun, trying to recover", __func__);
+
+ /* fill up parser buffer */
+ memcpy(client_cb->at_cb.buf + client_cb->at_cb.offset, buf, space_left);
+ len -= space_left;
+ buf += space_left;
+ client_cb->at_cb.offset += space_left;
+
+ /* find end of last complete command before proceeding */
+ while (bta_hf_client_check_at_complete(client_cb) == false) {
+ if (client_cb->at_cb.offset == 0) {
+ APPL_TRACE_ERROR("HFPClient: AT parser buffer overrun, disconnecting");
+
+ bta_hf_client_at_reset(client_cb);
+
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
+ return;
+ }
+
+ client_cb->at_cb.offset--;
+ }
+
+ /* cut buffer to complete AT event and keep cut data */
+ tmp += space_left - client_cb->at_cb.offset;
+ memcpy(tmp_buff, client_cb->at_cb.buf + client_cb->at_cb.offset, tmp);
+ client_cb->at_cb.buf[client_cb->at_cb.offset] = '\0';
+
+ /* parse */
+ bta_hf_client_at_parse_start(client_cb);
+ bta_hf_client_at_clear_buf(client_cb);
+
+ /* recover cut data */
+ memcpy(client_cb->at_cb.buf, tmp_buff, tmp);
+ client_cb->at_cb.offset += tmp;
+ }
+
+ memcpy(client_cb->at_cb.buf + client_cb->at_cb.offset, buf, len);
+ client_cb->at_cb.offset += len;
+
+ /* If last event is complete, parsing can be started */
+ if (bta_hf_client_check_at_complete(client_cb) == true) {
+ bta_hf_client_at_parse_start(client_cb);
+ bta_hf_client_at_clear_buf(client_cb);
+ }
+}
+
+void bta_hf_client_send_at_brsf(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_FEAT features) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+BRSF=%u\r", features);
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BRSF, buf, at_len);
+}
+
+void bta_hf_client_send_at_bac(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+BAC=1,2\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BAC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bcs(tBTA_HF_CLIENT_CB* client_cb, uint32_t codec) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+BCS=%u\r", codec);
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BCS, buf, at_len);
+}
+
+void bta_hf_client_send_at_cind(tBTA_HF_CLIENT_CB* client_cb, bool status) {
+ const char* buf;
+ tBTA_HF_CLIENT_AT_CMD cmd;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (status) {
+ buf = "AT+CIND?\r";
+ cmd = BTA_HF_CLIENT_AT_CIND_STATUS;
+ } else {
+ buf = "AT+CIND=?\r";
+ cmd = BTA_HF_CLIENT_AT_CIND;
+ }
+
+ bta_hf_client_send_at(client_cb, cmd, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmer(tBTA_HF_CLIENT_CB* client_cb, bool activate) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (activate)
+ buf = "AT+CMER=3,0,0,1\r";
+ else
+ buf = "AT+CMER=3,0,0,0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CMER, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chld(tBTA_HF_CLIENT_CB* client_cb, char cmd,
+ uint32_t idx) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (idx > 0)
+ at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c%u\r", cmd, idx);
+ else
+ at_len = snprintf(buf, sizeof(buf), "AT+CHLD=%c\r", cmd);
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CHLD, buf, at_len);
+}
+
+void bta_hf_client_send_at_clip(tBTA_HF_CLIENT_CB* client_cb, bool activate) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (activate)
+ buf = "AT+CLIP=1\r";
+ else
+ buf = "AT+CLIP=0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CLIP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ccwa(tBTA_HF_CLIENT_CB* client_cb, bool activate) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (activate)
+ buf = "AT+CCWA=1\r";
+ else
+ buf = "AT+CCWA=0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CCWA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cmee(tBTA_HF_CLIENT_CB* client_cb, bool activate) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (activate)
+ buf = "AT+CMEE=1\r";
+ else
+ buf = "AT+CMEE=0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CMEE, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_cops(tBTA_HF_CLIENT_CB* client_cb, bool query) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (query)
+ buf = "AT+COPS?\r";
+ else
+ buf = "AT+COPS=3,0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_COPS, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_clcc(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+CLCC\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CLCC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_bvra(tBTA_HF_CLIENT_CB* client_cb, bool enable) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (enable)
+ buf = "AT+BVRA=1\r";
+ else
+ buf = "AT+BVRA=0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BVRA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_vgs(tBTA_HF_CLIENT_CB* client_cb, uint32_t volume) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+VGS=%u\r", volume);
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_VGS, buf, at_len);
+}
+
+void bta_hf_client_send_at_vgm(tBTA_HF_CLIENT_CB* client_cb, uint32_t volume) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+VGM=%u\r", volume);
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_VGM, buf, at_len);
+}
+
+void bta_hf_client_send_at_atd(tBTA_HF_CLIENT_CB* client_cb, char* number,
+ uint32_t memory) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (number[0] != '\0') {
+ at_len = snprintf(buf, sizeof(buf), "ATD%s;\r", number);
+ } else {
+ at_len = snprintf(buf, sizeof(buf), "ATD>%u;\r", memory);
+ }
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: error preparing ATD command", __func__);
+ return;
+ }
+
+ at_len = MIN((size_t)at_len, sizeof(buf));
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_ATD, buf, at_len);
+}
+
+void bta_hf_client_send_at_bldn(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+BLDN\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BLDN, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_ata(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "ATA\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_ATA, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_chup(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+CHUP\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CHUP, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_btrh(tBTA_HF_CLIENT_CB* client_cb, bool query,
+ uint32_t val) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (query == true) {
+ at_len = snprintf(buf, sizeof(buf), "AT+BTRH?\r");
+ } else {
+ at_len = snprintf(buf, sizeof(buf), "AT+BTRH=%u\r", val);
+ }
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BTRH, buf, at_len);
+}
+
+void bta_hf_client_send_at_vts(tBTA_HF_CLIENT_CB* client_cb, char code) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+VTS=%c\r", code);
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_VTS, buf, at_len);
+}
+
+void bta_hf_client_send_at_bcc(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+BCC\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BCC, buf, strlen(buf));
+
+ // At this point we should also open up an incoming SCO connection
+ tBTA_HF_CLIENT_DATA p_data;
+ p_data.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sco_listen(&p_data);
+}
+
+void bta_hf_client_send_at_cnum(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ buf = "AT+CNUM\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_CNUM, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_nrec(tBTA_HF_CLIENT_CB* client_cb) {
+ const char* buf;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (!(client_cb->peer_features & BTA_HF_CLIENT_PEER_FEAT_ECNR)) {
+ APPL_TRACE_ERROR("%s: Remote does not support NREC.", __func__);
+ return;
+ }
+
+ buf = "AT+NREC=0\r";
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_NREC, buf, strlen(buf));
+}
+
+void bta_hf_client_send_at_binp(tBTA_HF_CLIENT_CB* client_cb, uint32_t action) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ at_len = snprintf(buf, sizeof(buf), "AT+BINP=%u\r", action);
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BINP, buf, at_len);
+}
+
+void bta_hf_client_send_at_bia(tBTA_HF_CLIENT_CB* client_cb) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ int at_len;
+ int i;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ if (client_cb->peer_version < HFP_VERSION_1_6) {
+ APPL_TRACE_DEBUG("Remote does not Support AT+BIA");
+ return;
+ }
+
+ at_len = snprintf(buf, sizeof(buf), "AT+BIA=");
+
+ for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+ int sup = client_cb->at_cb.indicator_lookup[i] == -1 ? 0 : 1;
+
+ at_len += snprintf(buf + at_len, sizeof(buf) - at_len, "%u,", sup);
+ }
+
+ buf[at_len - 1] = '\r';
+
+ if (at_len < 0) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BIA, buf, at_len);
+}
+
+void bta_hf_client_at_init(tBTA_HF_CLIENT_CB* client_cb) {
+ alarm_free(client_cb->at_cb.resp_timer);
+ alarm_free(client_cb->at_cb.hold_timer);
+ memset(&(client_cb->at_cb), 0, sizeof(tBTA_HF_CLIENT_AT_CB));
+ client_cb->at_cb.resp_timer = alarm_new("bta_hf_client.scb_at_resp_timer");
+ client_cb->at_cb.hold_timer = alarm_new("bta_hf_client.scb_at_hold_timer");
+ bta_hf_client_at_reset(client_cb);
+}
+
+void bta_hf_client_at_reset(tBTA_HF_CLIENT_CB* client_cb) {
+ int i;
+
+ bta_hf_client_stop_at_resp_timer(client_cb);
+ bta_hf_client_stop_at_hold_timer(client_cb);
+
+ bta_hf_client_clear_queued_at(client_cb);
+
+ bta_hf_client_at_clear_buf(client_cb);
+
+ for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) {
+ client_cb->at_cb.indicator_lookup[i] = -1;
+ }
+
+ client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+}
+
+void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (!client_cb) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ tBTA_HF_CLIENT_DATA_VAL* p_val = (tBTA_HF_CLIENT_DATA_VAL*)p_data;
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+
+ APPL_TRACE_DEBUG("%s: at cmd: %d", __func__, p_val->uint8_val);
+ switch (p_val->uint8_val) {
+ case BTA_HF_CLIENT_AT_CMD_VTS:
+ bta_hf_client_send_at_vts(client_cb, (char)p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_BTRH:
+ bta_hf_client_send_at_btrh(client_cb, false, p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_CHUP:
+ bta_hf_client_send_at_chup(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_CHLD:
+ /* expects ascii code for command */
+ bta_hf_client_send_at_chld(client_cb, '0' + p_val->uint32_val1,
+ p_val->uint32_val2);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_BCC:
+ bta_hf_client_send_at_bcc(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_CNUM:
+ bta_hf_client_send_at_cnum(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_ATA:
+ bta_hf_client_send_at_ata(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_COPS:
+ bta_hf_client_send_at_cops(client_cb, true);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_ATD:
+ bta_hf_client_send_at_atd(client_cb, p_val->str, p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_VGM:
+ bta_hf_client_send_at_vgm(client_cb, p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_VGS:
+ bta_hf_client_send_at_vgs(client_cb, p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_BVRA:
+ bta_hf_client_send_at_bvra(client_cb,
+ p_val->uint32_val1 == 0 ? false : true);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_CLCC:
+ bta_hf_client_send_at_clcc(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_BINP:
+ bta_hf_client_send_at_binp(client_cb, p_val->uint32_val1);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_BLDN:
+ bta_hf_client_send_at_bldn(client_cb);
+ break;
+ case BTA_HF_CLIENT_AT_CMD_NREC:
+ bta_hf_client_send_at_nrec(client_cb);
+ break;
+ default:
+ APPL_TRACE_ERROR("Default case");
+ snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN,
+ "Cmd %d 1st arg %u 2nd arg %u string arg %s", p_val->uint8_val,
+ p_val->uint32_val1, p_val->uint32_val2, p_val->str);
+ APPL_TRACE_ERROR("%s: AT buffer: %s ", __func__, buf);
+ break;
+ }
+}
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.h b/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.h
new file mode 100755
index 0000000..7b52336
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_at.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+
+/* ASCII character string of arguments to the AT command */
+#define BTA_HF_CLIENT_AT_MAX_LEN 512
+
+typedef uint8_t tBTA_HF_CLIENT_AT_CMD;
+
+/* Maximum combined buffer for received AT events string */
+#define BTA_HF_CLIENT_AT_PARSER_MAX_LEN 4096
+
+/* This structure holds prepared AT command queued for sending */
+struct queued_at_cmd {
+ tBTA_HF_CLIENT_AT_CMD cmd;
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+ uint16_t buf_len;
+ struct queued_at_cmd* next;
+};
+typedef struct queued_at_cmd tBTA_HF_CLIENT_AT_QCMD;
+
+/* Maximum number of indicators */
+#define BTA_HF_CLIENT_AT_INDICATOR_COUNT 20
+
+/* AT command parsing control block */
+typedef struct {
+ char buf[BTA_HF_CLIENT_AT_PARSER_MAX_LEN +
+ 1]; /* extra byte to always have \0 at the end */
+ unsigned int offset;
+ tBTA_HF_CLIENT_AT_CMD current_cmd;
+ tBTA_HF_CLIENT_AT_QCMD* queued_cmd;
+ alarm_t* resp_timer; /* AT response timer */
+ alarm_t* hold_timer; /* AT hold timer */
+
+ /* CIND: lookup table to store the sequence of incoming indicators and their
+ values
+ so when their values come later, we know which value in sequence match
+ certain indicator */
+ int indicator_lookup[BTA_HF_CLIENT_AT_INDICATOR_COUNT];
+
+} tBTA_HF_CLIENT_AT_CB;
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_int.h b/mtkbt/code/bt/bta/hf_client/bta_hf_client_int.h
new file mode 100755
index 0000000..6a03d45
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_int.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_at.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+
+/* RFCOMM MTU SIZE */
+#define BTA_HF_CLIENT_MTU 256
+
+/* profile role for connection */
+#define BTA_HF_CLIENT_ACP 0 /* accepted connection */
+#define BTA_HF_CLIENT_INT 1 /* initiating connection */
+
+/* Time (in milliseconds) to wait for retry in case of collision */
+#ifndef BTA_HF_CLIENT_COLLISION_TIMER_MS
+#define BTA_HF_CLIENT_COLLISION_TIMER_MS 2411
+#endif
+
+/* Maximum number of HF devices supported simultaneously */
+#define HF_CLIENT_MAX_DEVICES 10
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
+ BTA_HF_CLIENT_API_CLOSE_EVT,
+ BTA_HF_CLIENT_API_AUDIO_OPEN_EVT,
+ BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT,
+ BTA_HF_CLIENT_RFC_OPEN_EVT,
+ BTA_HF_CLIENT_RFC_CLOSE_EVT,
+ BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT,
+ BTA_HF_CLIENT_RFC_DATA_EVT,
+ BTA_HF_CLIENT_DISC_ACP_RES_EVT,
+ BTA_HF_CLIENT_DISC_INT_RES_EVT,
+ BTA_HF_CLIENT_DISC_OK_EVT,
+ BTA_HF_CLIENT_DISC_FAIL_EVT,
+ BTA_HF_CLIENT_SCO_OPEN_EVT,
+ BTA_HF_CLIENT_SCO_CLOSE_EVT,
+ BTA_HF_CLIENT_SEND_AT_CMD_EVT,
+ BTA_HF_CLIENT_MAX_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_HF_CLIENT_API_ENABLE_EVT,
+ BTA_HF_CLIENT_API_DISABLE_EVT
+};
+
+/* AT Command enum */
+enum {
+ BTA_HF_CLIENT_AT_NONE,
+ BTA_HF_CLIENT_AT_BRSF,
+ BTA_HF_CLIENT_AT_BAC,
+ BTA_HF_CLIENT_AT_CIND,
+ BTA_HF_CLIENT_AT_CIND_STATUS,
+ BTA_HF_CLIENT_AT_CMER,
+ BTA_HF_CLIENT_AT_CHLD,
+ BTA_HF_CLIENT_AT_CMEE,
+ BTA_HF_CLIENT_AT_BIA,
+ BTA_HF_CLIENT_AT_CLIP,
+ BTA_HF_CLIENT_AT_CCWA,
+ BTA_HF_CLIENT_AT_COPS,
+ BTA_HF_CLIENT_AT_CLCC,
+ BTA_HF_CLIENT_AT_BVRA,
+ BTA_HF_CLIENT_AT_VGS,
+ BTA_HF_CLIENT_AT_VGM,
+ BTA_HF_CLIENT_AT_ATD,
+ BTA_HF_CLIENT_AT_BLDN,
+ BTA_HF_CLIENT_AT_ATA,
+ BTA_HF_CLIENT_AT_CHUP,
+ BTA_HF_CLIENT_AT_BTRH,
+ BTA_HF_CLIENT_AT_VTS,
+ BTA_HF_CLIENT_AT_BCC,
+ BTA_HF_CLIENT_AT_BCS,
+ BTA_HF_CLIENT_AT_CNUM,
+ BTA_HF_CLIENT_AT_NREC,
+ BTA_HF_CLIENT_AT_BINP,
+};
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+/* data type for BTA_HF_CLIENT_API_OPEN_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ uint16_t* handle;
+ tBTA_SEC sec_mask;
+} tBTA_HF_CLIENT_API_OPEN;
+
+/* data type for BTA_HF_CLIENT_DISC_RESULT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t status;
+} tBTA_HF_CLIENT_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t port_handle;
+} tBTA_HF_CLIENT_RFC;
+
+/* generic purpose data type for other events */
+typedef struct {
+ BT_HDR hdr;
+ bool bool_val;
+ uint8_t uint8_val;
+ uint32_t uint32_val1;
+ uint32_t uint32_val2;
+ char str[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_DATA_VAL;
+
+/* union of all event datatypes */
+typedef union {
+ BT_HDR hdr;
+ tBTA_HF_CLIENT_API_OPEN api_open;
+ tBTA_HF_CLIENT_DISC_RESULT disc_result;
+ tBTA_HF_CLIENT_RFC rfc;
+ tBTA_HF_CLIENT_DATA_VAL val;
+
+} tBTA_HF_CLIENT_DATA;
+
+/* First handle for the control block */
+#define BTA_HF_CLIENT_CB_FIRST_HANDLE 1
+
+/* sco states */
+enum {
+ BTA_HF_CLIENT_SCO_SHUTDOWN_ST, /* no listening, no connection */
+ BTA_HF_CLIENT_SCO_LISTEN_ST, /* listening */
+ BTA_HF_CLIENT_SCO_OPENING_ST, /* connection opening */
+ BTA_HF_CLIENT_SCO_OPEN_CL_ST, /* opening connection being closed */
+ BTA_HF_CLIENT_SCO_OPEN_ST, /* open */
+ BTA_HF_CLIENT_SCO_CLOSING_ST, /* closing */
+ BTA_HF_CLIENT_SCO_CLOSE_OP_ST, /* closing sco being opened */
+ BTA_HF_CLIENT_SCO_SHUTTING_ST /* sco shutting down */
+};
+
+/* type for HF control block */
+typedef struct {
+ // Fields useful for particular control block.
+ uint8_t handle; /* Handle of the control block to be
+ used by upper layer */
+ BD_ADDR peer_addr; /* peer bd address */
+ tSDP_DISCOVERY_DB* p_disc_db; /* pointer to discovery database */
+ uint16_t conn_handle; /* RFCOMM handle of connected service */
+ tBTA_SEC cli_sec_mask; /* client security mask */
+ tBTA_HF_CLIENT_PEER_FEAT peer_features; /* peer device features */
+ tBTA_HF_CLIENT_CHLD_FEAT chld_features; /* call handling features */
+ uint16_t peer_version; /* profile version of peer device */
+ uint8_t peer_scn; /* peer scn */
+ uint8_t role; /* initiator/acceptor role */
+ uint16_t sco_idx; /* SCO handle */
+ uint8_t sco_state; /* SCO state variable */
+ bool sco_close_rfc; /* true if also close RFCOMM after SCO */
+ tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
+ bool svc_conn; /* set to true when service level connection is up */
+ bool send_at_reply; /* set to true to notify framework about AT results */
+ tBTA_HF_CLIENT_AT_CB at_cb; /* AT Parser control block */
+ uint8_t state; /* state machine state */
+ bool is_allocated; /* if the control block is already allocated */
+ alarm_t* collision_timer; /* Collision timer */
+} tBTA_HF_CLIENT_CB;
+
+typedef struct {
+ // Common fields, should be taken out.
+ uint32_t sdp_handle;
+ uint8_t scn;
+ tBTA_HF_CLIENT_CBACK* p_cback; /* application callback */
+ tBTA_HF_CLIENT_FEAT features; /* features registered by application */
+ tBTA_SEC serv_sec_mask; /* server security mask */
+ uint16_t serv_handle; /* RFCOMM server handle */
+ bool deregister; /* true if service shutting down */
+
+ // Maximum number of control blocks supported by the BTA layer.
+ tBTA_HF_CLIENT_CB cb[HF_CLIENT_MAX_DEVICES];
+} tBTA_HF_CLIENT_CB_ARR;
+
+extern tBTA_HF_CLIENT_CB_ARR bta_hf_client_cb_arr;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+
+/* main functions */
+extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle);
+extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_bda(const BD_ADDR bd_addr);
+extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle);
+extern tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle);
+extern bool bta_hf_client_hdl_event(BT_HDR* p_msg);
+extern void bta_hf_client_sm_execute(uint16_t event,
+ tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error);
+extern bool bta_hf_client_allocate_handle(const BD_ADDR bd_addr,
+ uint16_t* p_handle);
+extern void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data);
+extern void bta_hf_client_collision_cback(tBTA_SYS_CONN_STATUS status,
+ uint8_t id, uint8_t app_id,
+ BD_ADDR peer_addr);
+extern void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb);
+extern tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback,
+ tBTA_SEC sec_mask,
+ tBTA_HF_CLIENT_FEAT features,
+ const char* p_service_name);
+
+extern void bta_hf_client_api_disable(void);
+extern void bta_hf_client_dump_statistics(int fd);
+extern void bta_hf_client_cb_arr_init(void);
+
+/* SDP functions */
+extern bool bta_hf_client_add_record(char* p_service_name, uint8_t scn,
+ tBTA_HF_CLIENT_FEAT features,
+ uint32_t sdp_handle);
+extern void bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR* client_cb,
+ const char* p_data);
+extern void bta_hf_client_del_record(tBTA_HF_CLIENT_CB_ARR* client_cb);
+extern bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data);
+
+/* RFCOMM functions */
+extern void bta_hf_client_setup_port(uint16_t handle);
+extern void bta_hf_client_start_server();
+extern void bta_hf_client_close_server();
+extern void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data);
+
+/* SCO functions */
+extern void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb,
+ uint8_t event);
+
+/* AT command functions */
+extern void bta_hf_client_at_parse(tBTA_HF_CLIENT_CB* client_cb, char* buf,
+ unsigned int len);
+extern void bta_hf_client_send_at_brsf(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_FEAT features);
+extern void bta_hf_client_send_at_bac(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_cind(tBTA_HF_CLIENT_CB* client_cb,
+ bool status);
+extern void bta_hf_client_send_at_cmer(tBTA_HF_CLIENT_CB* client_cb,
+ bool activate);
+extern void bta_hf_client_send_at_chld(tBTA_HF_CLIENT_CB* client_cb, char cmd,
+ uint32_t idx);
+extern void bta_hf_client_send_at_clip(tBTA_HF_CLIENT_CB* client_cb,
+ bool activate);
+extern void bta_hf_client_send_at_ccwa(tBTA_HF_CLIENT_CB* client_cb,
+ bool activate);
+extern void bta_hf_client_send_at_cmee(tBTA_HF_CLIENT_CB* client_cb,
+ bool activate);
+extern void bta_hf_client_send_at_cops(tBTA_HF_CLIENT_CB* client_cb,
+ bool query);
+extern void bta_hf_client_send_at_clcc(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_bvra(tBTA_HF_CLIENT_CB* client_cb,
+ bool enable);
+extern void bta_hf_client_send_at_vgs(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t volume);
+extern void bta_hf_client_send_at_vgm(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t volume);
+extern void bta_hf_client_send_at_atd(tBTA_HF_CLIENT_CB* client_cb,
+ char* number, uint32_t memory);
+extern void bta_hf_client_send_at_bldn(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_ata(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_chup(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_btrh(tBTA_HF_CLIENT_CB* client_cb, bool query,
+ uint32_t val);
+extern void bta_hf_client_send_at_vts(tBTA_HF_CLIENT_CB* client_cb, char code);
+extern void bta_hf_client_send_at_bcc(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_bcs(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t codec);
+extern void bta_hf_client_send_at_cnum(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_nrec(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_send_at_binp(tBTA_HF_CLIENT_CB* client_cb,
+ uint32_t action);
+extern void bta_hf_client_send_at_bia(tBTA_HF_CLIENT_CB* client_cb);
+
+/* AT API Functions */
+void bta_hf_client_at_init(tBTA_HF_CLIENT_CB* client_cb);
+void bta_hf_client_at_reset(tBTA_HF_CLIENT_CB* client_cb);
+extern void bta_hf_client_ind(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_IND_TYPE type, uint16_t value);
+extern void bta_hf_client_evt_val(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_EVT type, uint16_t value);
+extern void bta_hf_client_operator_name(tBTA_HF_CLIENT_CB* client_name,
+ char* name);
+extern void bta_hf_client_clip(tBTA_HF_CLIENT_CB* client_cb, char* number);
+extern void bta_hf_client_ccwa(tBTA_HF_CLIENT_CB* client_cb, char* number);
+extern void bta_hf_client_at_result(tBTA_HF_CLIENT_CB* client_cb,
+ tBTA_HF_CLIENT_AT_RESULT_TYPE type,
+ uint16_t cme);
+extern void bta_hf_client_clcc(tBTA_HF_CLIENT_CB* client_cb, uint32_t idx,
+ bool incoming, uint8_t status, bool mpty,
+ char* number);
+extern void bta_hf_client_cnum(tBTA_HF_CLIENT_CB* client_cb, char* number,
+ uint16_t service);
+extern void bta_hf_client_binp(tBTA_HF_CLIENT_CB* client_cb, char* number);
+
+/* Action functions */
+extern void bta_hf_client_start_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_start_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_acp_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_open(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_open_fail(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_close(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_acp_res(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_disc_int_res(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_svc_conn_open(tBTA_HF_CLIENT_DATA* p_data);
+
+/* Commands handling functions */
+extern void bta_hf_client_dial(tBTA_HF_CLIENT_DATA* p_data);
+extern void bta_hf_client_send_at_cmd(tBTA_HF_CLIENT_DATA* p_data);
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_main.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_main.cc
new file mode 100755
index 0000000..7c9293e
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_main.cc
@@ -0,0 +1,957 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2016 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "btcore/include/bdaddr.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "utl.h"
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+static const char* bta_hf_client_evt_str(uint16_t event);
+static const char* bta_hf_client_state_str(uint8_t state);
+void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle);
+
+/* state machine states */
+enum {
+ BTA_HF_CLIENT_INIT_ST,
+ BTA_HF_CLIENT_OPENING_ST,
+ BTA_HF_CLIENT_OPEN_ST,
+ BTA_HF_CLIENT_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ BTA_HF_CLIENT_RFC_DO_CLOSE,
+ BTA_HF_CLIENT_START_CLOSE,
+ BTA_HF_CLIENT_START_OPEN,
+ BTA_HF_CLIENT_RFC_ACP_OPEN,
+ BTA_HF_CLIENT_SCO_LISTEN,
+ BTA_HF_CLIENT_SCO_CONN_OPEN,
+ BTA_HF_CLIENT_SCO_CONN_CLOSE,
+ BTA_HF_CLIENT_SCO_OPEN,
+ BTA_HF_CLIENT_SCO_CLOSE,
+ BTA_HF_CLIENT_FREE_DB,
+ BTA_HF_CLIENT_OPEN_FAIL,
+ BTA_HF_CLIENT_RFC_OPEN,
+ BTA_HF_CLIENT_RFC_FAIL,
+ BTA_HF_CLIENT_DISC_INT_RES,
+ BTA_HF_CLIENT_RFC_DO_OPEN,
+ BTA_HF_CLIENT_DISC_FAIL,
+ BTA_HF_CLIENT_RFC_CLOSE,
+ BTA_HF_CLIENT_RFC_DATA,
+ BTA_HF_CLIENT_DISC_ACP_RES,
+ BTA_HF_CLIENT_SVC_CONN_OPEN,
+ BTA_HF_CLIENT_SEND_AT_CMD,
+ BTA_HF_CLIENT_NUM_ACTIONS,
+};
+
+#define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA* p_data);
+
+/* action functions table, indexed with action enum */
+const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
+ /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close,
+ /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close,
+ /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open,
+ /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open,
+ /* BTA_HF_CLIENT_SCO_LISTEN */ NULL,
+ /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
+ /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
+ /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
+ /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
+ /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
+ /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
+ /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
+ /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
+ /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,
+ /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open,
+ /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail,
+ /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close,
+ /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
+ /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res,
+ /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
+ /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd,
+};
+
+/* state table information */
+#define BTA_HF_CLIENT_ACTIONS 2 /* number of actions */
+#define BTA_HF_CLIENT_NEXT_STATE 2 /* position of next state */
+#define BTA_HF_CLIENT_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+const uint8_t bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next state */
+ /* API_OPEN_EVT */ {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+};
+
+/* state table for opening state */
+const uint8_t bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next state */
+ /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* API_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+ /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPENING_ST},
+};
+
+/* state table for open state */
+const uint8_t bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next state */
+ /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* API_CLOSE_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+ /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_OPEN_ST},
+};
+
+/* state table for closing state */
+const uint8_t bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next state */
+ /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_INIT_ST},
+ /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+ /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
+ BTA_HF_CLIENT_CLOSING_ST},
+};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS];
+
+/* state table */
+const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
+ bta_hf_client_st_init, bta_hf_client_st_opening, bta_hf_client_st_open,
+ bta_hf_client_st_closing};
+
+/* HF Client control block */
+tBTA_HF_CLIENT_CB_ARR bta_hf_client_cb_arr;
+
+/* Event handler for the state machine */
+static const tBTA_SYS_REG bta_hf_client_reg = {bta_hf_client_hdl_event,
+ BTA_HfClientDisable};
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_cb_arr_init
+ *
+ * Description Initialize entire control block array set
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_cb_arr_init() {
+ memset(&bta_hf_client_cb_arr, 0, sizeof(tBTA_HF_CLIENT_CB_ARR));
+
+ // reset the handles and make the CBs non-allocated
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ // Allocate the handles in increasing order of indices
+ bta_hf_client_cb_init(&(bta_hf_client_cb_arr.cb[i]), i);
+ bta_hf_client_cb_arr.cb[i].handle = BTA_HF_CLIENT_CB_FIRST_HANDLE + i;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_cb_init
+ *
+ * Description Initialize an HF_Client service control block. Assign the
+ * handle to cb->handle.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ // Free any memory we need to explicity release
+ alarm_free(client_cb->collision_timer);
+
+ // Memset the rest of the block
+ memset(client_cb, 0, sizeof(tBTA_HF_CLIENT_CB));
+
+ // Re allocate any variables required
+ client_cb->collision_timer = alarm_new("bta_hf_client.scb_collision_timer");
+ client_cb->handle = handle;
+ client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_resume_open
+ *
+ * Description Resume opening process.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* resume opening process. */
+ if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
+ client_cb->state = BTA_HF_CLIENT_OPENING_ST;
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_start_open(&msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_collision_timer_cback
+ *
+ * Description HF Client connection collision timer callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_collision_timer_cback(void* data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;
+
+ /* If the peer haven't opened connection, restart opening process */
+ bta_hf_client_resume_open(client_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_collision_cback
+ *
+ * Description Get notified about collision.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
+ uint8_t id, UNUSED_ATTR uint8_t app_id,
+ BD_ADDR peer_addr) {
+ tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_bda(peer_addr);
+ if (client_cb != NULL && client_cb->state == BTA_HF_CLIENT_OPENING_ST) {
+ if (id == BTA_ID_SYS) /* ACL collision */
+ {
+ APPL_TRACE_WARNING("HF Client found collision (ACL) ...");
+ } else if (id == BTA_ID_HS) /* RFCOMM collision */
+ {
+ APPL_TRACE_WARNING("HF Client found collision (RFCOMM) ...");
+ } else {
+ APPL_TRACE_WARNING("HF Client found collision (\?\?\?) ...");
+ }
+
+ client_cb->state = BTA_HF_CLIENT_INIT_ST;
+
+ /* Cancel SDP if it had been started. */
+ if (client_cb->p_disc_db) {
+ (void)SDP_CancelServiceSearch(client_cb->p_disc_db);
+ bta_hf_client_free_db(NULL);
+ }
+
+ /* reopen registered server */
+ /* Collision may be detected before or after we close servers. */
+ // bta_hf_client_start_server();
+
+ /* Start timer to handle connection opening restart */
+ alarm_set_on_queue(client_cb->collision_timer,
+ BTA_HF_CLIENT_COLLISION_TIMER_MS,
+ bta_hf_client_collision_timer_cback, (void*)client_cb,
+ btu_bta_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_api_enable
+ *
+ * Description Handle an API enable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback,
+ tBTA_SEC sec_mask,
+ tBTA_HF_CLIENT_FEAT features,
+ const char* p_service_name) {
+ /* If already registered then return error */
+ if (bta_sys_is_register(BTA_ID_HS)) {
+ APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ...");
+ return BTA_FAILURE;
+ }
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_HS, &bta_hf_client_reg);
+
+ /* reset the control blocks */
+ bta_hf_client_cb_arr_init();
+
+ bta_hf_client_cb_arr.p_cback = p_cback;
+ bta_hf_client_cb_arr.serv_sec_mask = sec_mask;
+ bta_hf_client_cb_arr.features = features;
+
+ /* create SDP records */
+ bta_hf_client_create_record(&bta_hf_client_cb_arr, p_service_name);
+
+ /* set same setting as AG does */
+ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+
+ bta_sys_collision_register(BTA_ID_HS, bta_hf_client_collision_cback);
+
+ /* Set the Audio service class bit */
+ tBTA_UTL_COD cod;
+ cod.service = BTM_COD_SERVICE_AUDIO;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ /* start RFCOMM server */
+ bta_hf_client_start_server();
+
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_find_cb_by_handle
+ *
+ * Description Finds the control block by handle provided
+ *
+ * handle: Handle as obtained from BTA_HfClientOpen call
+ *
+ *
+ * Returns Control block corresponding to the handle and NULL if
+ * none exists
+ *
+ ******************************************************************************/
+tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle) {
+ // Handles are limited from 1 through HF_CLIENT_MAX_DEVICES
+ if (handle < 1 || handle > HF_CLIENT_MAX_DEVICES) {
+ APPL_TRACE_ERROR("%s: handle out of range (%d, %d) %d", __func__, 1,
+ HF_CLIENT_MAX_DEVICES, handle);
+ return NULL;
+ }
+
+ // Check if the associated index is allocated. Index is (handle - 1).
+ if (bta_hf_client_cb_arr.cb[handle - 1].is_allocated)
+ return &(bta_hf_client_cb_arr.cb[handle - 1]);
+
+ APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_find_cb_by_bda
+ *
+ * Description Finds the control block by handle provided
+ *
+ * bda: BD_ADDR of the device to find the handle for.
+ * Since there can only be one HF connection for a device
+ * we should always find a unique block
+ *
+ * Returns Control block corresponding to the BD_ADDR and NULL if
+ * none exists
+ *
+ ******************************************************************************/
+tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_bda(const BD_ADDR peer_addr) {
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ // Check if the associated index is allocated and that BD ADDR matches
+ tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
+ if (client_cb->is_allocated && !bdcmp(peer_addr, client_cb->peer_addr)) {
+ return client_cb;
+ } else {
+ APPL_TRACE_WARNING("%s: bdaddr mismatch for handle %d alloc %d", __func__,
+ i, client_cb->is_allocated);
+ }
+ }
+ APPL_TRACE_ERROR("%s: block not found", __func__);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_find_cb_by_rfc_handle
+ *
+ * Description Finds the control block by RFC handle provided.
+ *
+ * handle: RFC handle for the established connection
+ *
+ *
+ * Returns Control block corresponding to the handle and NULL if none
+ * exists
+ *
+ ******************************************************************************/
+tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle) {
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
+ bool is_allocated = client_cb->is_allocated;
+ uint16_t conn_handle = client_cb->conn_handle;
+
+ APPL_TRACE_DEBUG("%s: cb rfc_handle %d alloc %d conn_handle %d", __func__,
+ handle, is_allocated, conn_handle);
+
+ if (is_allocated && conn_handle == handle) {
+ return client_cb;
+ }
+
+ APPL_TRACE_WARNING("%s: no cb yet %d alloc %d conn_handle %d", __func__,
+ handle, is_allocated, conn_handle);
+ }
+
+ APPL_TRACE_ERROR("%s: no cb found for rfc handle %d", __func__, handle);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_find_cb_by_sco_handle
+ *
+ * Description Finds the control block by sco handle provided
+ *
+ * handle: sco handle
+ *
+ *
+ * Returns Control block corresponding to the sco handle and
+ * none if none exists
+ *
+ ******************************************************************************/
+tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle) {
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
+ if (client_cb->is_allocated && client_cb->sco_idx == handle) {
+ return client_cb;
+ }
+ }
+ APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_allocate_handle
+ *
+ * Description Allocates a handle for the new BD ADDR that needs a new RF
+ * channel for HF connection. If the channel cannot be created
+ * for a reason then false is returned
+ *
+ * bd_addr: Address of the device for which this block is
+ * being created. Single device can only have one block.
+ * p_handle: OUT variable to store the outcome of allocate. If
+ * allocate failed then value is not valid
+ *
+ *
+ * Returns true if the creation of p_handle succeeded, false otherwise
+ *
+ ******************************************************************************/
+bool bta_hf_client_allocate_handle(const BD_ADDR bd_addr, uint16_t* p_handle) {
+ tBTA_HF_CLIENT_CB* existing_cb = bta_hf_client_find_cb_by_bda(bd_addr);
+ if (existing_cb != NULL) {
+ BTIF_TRACE_ERROR("%s: cannot allocate handle since BDADDR already exists",
+ __func__);
+ return false;
+ }
+ /* Check that we do not have a request to for same device in the control
+ * blocks */
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
+ if (client_cb->is_allocated) {
+ APPL_TRACE_WARNING("%s: control block already used index %d", __func__,
+ i);
+ continue;
+ }
+
+ // Reset the client control block
+ bta_hf_client_cb_init(client_cb, client_cb->handle);
+
+ *p_handle = client_cb->handle;
+ APPL_TRACE_DEBUG("%s: marking CB handle %d to true", __func__,
+ client_cb->handle);
+
+ client_cb->is_allocated = true;
+ bdcpy(client_cb->peer_addr, bd_addr);
+ bta_hf_client_at_init(client_cb);
+ return true;
+ }
+
+ return false;
+ APPL_TRACE_ERROR("%s: all control blocks in use!", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_app_callback
+ *
+ * Description Calls the application callback
+ *
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data) {
+ if (bta_hf_client_cb_arr.p_cback != NULL) {
+ bta_hf_client_cb_arr.p_cback(event, data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_api_disable
+ *
+ * Description Handle an API disable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_api_disable() {
+ if (!bta_sys_is_register(BTA_ID_HS)) {
+ APPL_TRACE_WARNING("BTA HF Client is already disabled, ignoring ...");
+ return;
+ }
+
+ /* Remove the collision handler */
+ bta_sys_collision_register(BTA_ID_HS, NULL);
+
+ bta_hf_client_cb_arr.deregister = true;
+
+ /* remove sdp record */
+ bta_hf_client_del_record(&bta_hf_client_cb_arr);
+
+ /* remove rfcomm server */
+ bta_hf_client_close_server();
+
+ /* reinit the control block */
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ if (bta_hf_client_cb_arr.cb[i].is_allocated) {
+ bta_hf_client_cb_init(&(bta_hf_client_cb_arr.cb[i]), i);
+ }
+ }
+
+ /* De-register with BTA system manager */
+ bta_sys_deregister(BTA_ID_HS);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_hdl_event
+ *
+ * Description Data HF Client main event handling function.
+ *
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool bta_hf_client_hdl_event(BT_HDR* p_msg) {
+ APPL_TRACE_DEBUG("%s: %s (0x%x)", __func__,
+ bta_hf_client_evt_str(p_msg->event), p_msg->event);
+ bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA*)p_msg);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sm_execute
+ *
+ * Description State machine event handling function for HF Client
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ tBTA_HF_CLIENT_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ uint16_t in_event = event;
+ uint8_t in_state = client_cb->state;
+
+ /* Ignore displaying of AT results when not connected (Ignored in state
+ * machine) */
+ if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
+ APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)",
+ client_cb->state,
+ bta_hf_client_state_str(client_cb->state), event,
+ bta_hf_client_evt_str(event));
+ }
+
+ event &= 0x00FF;
+ if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) {
+ APPL_TRACE_ERROR("HF Client evt out of range, ignoring...");
+ return;
+ }
+
+ /* look up the state table for the current state */
+ state_table = bta_hf_client_st_tbl[client_cb->state];
+
+ /* set next state */
+ client_cb->state = state_table[event][BTA_HF_CLIENT_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_HF_CLIENT_IGNORE) {
+ (*bta_hf_client_action[action])(p_data);
+ } else {
+ break;
+ }
+ }
+
+ /* If the state has changed then notify the app of the corresponding change */
+ if (in_state != client_cb->state) {
+ APPL_TRACE_DEBUG(
+ "%s: notifying state change to %d -> %d "
+ "device %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, in_state, client_cb->state, client_cb->peer_addr[0],
+ client_cb->peer_addr[1], client_cb->peer_addr[2],
+ client_cb->peer_addr[3], client_cb->peer_addr[4],
+ client_cb->peer_addr[5]);
+ tBTA_HF_CLIENT evt;
+ memset(&evt, 0, sizeof(evt));
+ bdcpy(evt.bd_addr, client_cb->peer_addr);
+ if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
+ bta_hf_client_app_callback(BTA_HF_CLIENT_CLOSE_EVT, &evt);
+ } else if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
+ evt.open.handle = client_cb->handle;
+ bta_hf_client_app_callback(BTA_HF_CLIENT_OPEN_EVT, &evt);
+ }
+ }
+
+ /* if the next state is INIT then release the cb for future use */
+ if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
+ APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__,
+ client_cb->handle);
+ client_cb->is_allocated = false;
+ }
+
+ APPL_TRACE_EVENT(
+ "%s: device %02x:%02x:%02x:%02x:%02x:%02x "
+ "state change: [%s] -> [%s] after Event [%s]",
+ __func__, client_cb->peer_addr[0], client_cb->peer_addr[1],
+ client_cb->peer_addr[2], client_cb->peer_addr[3], client_cb->peer_addr[4],
+ client_cb->peer_addr[5], bta_hf_client_state_str(in_state),
+ bta_hf_client_state_str(client_cb->state),
+ bta_hf_client_evt_str(in_event));
+}
+
+static void send_post_slc_cmd(tBTA_HF_CLIENT_CB* client_cb) {
+ client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
+
+ bta_hf_client_send_at_bia(client_cb);
+ bta_hf_client_send_at_ccwa(client_cb, true);
+ bta_hf_client_send_at_cmee(client_cb, true);
+ bta_hf_client_send_at_cops(client_cb, false);
+ bta_hf_client_send_at_btrh(client_cb, true, 0);
+ bta_hf_client_send_at_clip(client_cb, true);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_slc_seq
+ *
+ * Description Handles AT commands sequence required for SLC creation
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error) {
+ APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u",
+ client_cb->at_cb.current_cmd);
+
+ if (error) {
+ /* SLC establishment error, sent close rfcomm event */
+ APPL_TRACE_ERROR(
+ "HFPClient: Failed to create SLC due to AT error, disconnecting (%u)",
+ client_cb->at_cb.current_cmd);
+
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
+ return;
+ }
+
+ if (client_cb->svc_conn) {
+ APPL_TRACE_WARNING("%s: SLC already connected for CB handle %d", __func__,
+ client_cb->handle);
+ return;
+ }
+
+ switch (client_cb->at_cb.current_cmd) {
+ case BTA_HF_CLIENT_AT_NONE:
+ bta_hf_client_send_at_brsf(client_cb, bta_hf_client_cb_arr.features);
+ break;
+
+ case BTA_HF_CLIENT_AT_BRSF:
+ if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_CODEC) &&
+ (client_cb->peer_features & BTA_HF_CLIENT_PEER_CODEC)) {
+ bta_hf_client_send_at_bac(client_cb);
+ break;
+ }
+
+ bta_hf_client_send_at_cind(client_cb, false);
+ break;
+
+ case BTA_HF_CLIENT_AT_BAC:
+ bta_hf_client_send_at_cind(client_cb, false);
+ break;
+
+ case BTA_HF_CLIENT_AT_CIND:
+ bta_hf_client_send_at_cind(client_cb, true);
+ break;
+
+ case BTA_HF_CLIENT_AT_CIND_STATUS:
+ bta_hf_client_send_at_cmer(client_cb, true);
+ break;
+
+ case BTA_HF_CLIENT_AT_CMER:
+ if (client_cb->peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY &&
+ bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_3WAY) {
+ bta_hf_client_send_at_chld(client_cb, '?', 0);
+ } else {
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_svc_conn_open(&msg);
+ send_post_slc_cmd(client_cb);
+ }
+ break;
+
+ case BTA_HF_CLIENT_AT_CHLD: {
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_svc_conn_open(&msg);
+ send_post_slc_cmd(client_cb);
+ break;
+ }
+
+ default: {
+ /* If happen there is a bug in SLC creation procedure... */
+ APPL_TRACE_ERROR(
+ "HFPClient: Failed to create SLCdue to unexpected AT command, "
+ "disconnecting (%u)",
+ client_cb->at_cb.current_cmd);
+
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
+ break;
+ }
+ }
+}
+
+#ifndef CASE_RETURN_STR
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+#endif
+
+static const char* bta_hf_client_evt_str(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT)
+ default:
+ return "Unknown HF Client Event";
+ }
+}
+
+static const char* bta_hf_client_state_str(uint8_t state) {
+ switch (state) {
+ CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST)
+ CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST)
+ CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST)
+ default:
+ return "Unknown HF Client State";
+ }
+}
+
+void bta_hf_client_dump_statistics(int fd) {
+ dprintf(fd, "\nBluetooth HF Client BTA Statistics\n");
+
+ // We dump statistics for all control blocks
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
+ if (!client_cb->is_allocated) {
+ // Skip the blocks which are not allocated
+ continue;
+ }
+
+ dprintf(fd, " Control block #%d\n", i + 1);
+
+ // Device name
+ dprintf(fd, " Peer Device: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ client_cb->peer_addr[0], client_cb->peer_addr[1],
+ client_cb->peer_addr[2], client_cb->peer_addr[3],
+ client_cb->peer_addr[4], client_cb->peer_addr[5]);
+
+ // State machine state
+ dprintf(fd, " State Machine State: %s\n",
+ bta_hf_client_state_str(client_cb->state));
+
+ // Local RFC channelfor communication
+ dprintf(fd, " RFCOMM Channel (local) %d\n", client_cb->conn_handle);
+
+ // BTA Handle shared between BTA and client (ex BTIF)
+ dprintf(fd, " BTA Generated handle %d\n", client_cb->handle);
+ }
+}
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_rfc.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_rfc.cc
new file mode 100755
index 0000000..7a0d356
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_rfc.cc
@@ -0,0 +1,293 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions controlling the RFCOMM
+ * connections.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_int.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_port_cback
+ *
+ * Description RFCOMM Port callback. The handle in this function is
+ * specified by BTA layer via the PORT_SetEventCallback
+ * method
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_port_cback(UNUSED_ATTR uint32_t code,
+ uint16_t port_handle) {
+ /* ignore port events for port handles other than connected handle */
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_rfc_handle(port_handle);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__, port_handle);
+ return;
+ }
+
+ tBTA_HF_CLIENT_RFC* p_buf =
+ (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_DATA_EVT;
+ p_buf->hdr.layer_specific = client_cb->handle;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_mgmt_cback
+ *
+ * Description RFCOMM management callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_rfc_handle(port_handle);
+
+ APPL_TRACE_DEBUG("%s: code = %d, port_handle = %d serv = %d", __func__, code,
+ port_handle, bta_hf_client_cb_arr.serv_handle);
+
+ /* ignore close event for port handles other than connected handle */
+ if (code != PORT_SUCCESS && client_cb != NULL &&
+ port_handle != client_cb->conn_handle) {
+ APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d",
+ port_handle);
+ return;
+ }
+
+ tBTA_HF_CLIENT_RFC* p_buf =
+ (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
+
+ if (code == PORT_SUCCESS) {
+ if (client_cb && port_handle == client_cb->conn_handle) { /* out conn */
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_OPEN_EVT;
+ } else if (port_handle == bta_hf_client_cb_arr.serv_handle) {
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_OPEN_EVT;
+
+ APPL_TRACE_DEBUG("%s: allocating a new CB for incoming connection",
+ __func__);
+ // Find the BDADDR of the peer device
+ BD_ADDR peer_addr;
+ uint16_t lcid;
+ PORT_CheckConnection(port_handle, peer_addr, &lcid);
+
+ // Since we accepted a remote request we should allocate a handle first.
+ uint16_t tmp_handle = -1;
+ bta_hf_client_allocate_handle(peer_addr, &tmp_handle);
+ client_cb = bta_hf_client_find_cb_by_handle(tmp_handle);
+
+ // If allocation fails then we abort.
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: error allocating a new handle", __func__);
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+ } else {
+ // Set the connection fields for this new CB
+ client_cb->conn_handle = port_handle;
+
+ // Since we have accepted an incoming RFCOMM connection:
+ // a) Release the current server from it duties
+ // b) Start a new server for more new incoming connection
+ bta_hf_client_cb_arr.serv_handle = 0;
+ bta_hf_client_start_server();
+ }
+ } else {
+ APPL_TRACE_ERROR("%s: PORT_SUCCESS, ignoring handle = %d", __func__,
+ port_handle);
+ return;
+ }
+ } else if (client_cb != NULL &&
+ port_handle == client_cb->conn_handle) { /* code != PORT_SUC */
+ APPL_TRACE_ERROR(
+ "%s: closing port handle %d "
+ "dev %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, port_handle, client_cb->peer_addr[0], client_cb->peer_addr[1],
+ client_cb->peer_addr[2], client_cb->peer_addr[3],
+ client_cb->peer_addr[4], client_cb->peer_addr[5]);
+
+ RFCOMM_RemoveServer(port_handle);
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+ }
+
+ p_buf->hdr.layer_specific = client_cb != NULL ? client_cb->handle : 0;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_setup_port
+ *
+ * Description Setup RFCOMM port for use by HF Client.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_setup_port(uint16_t handle) {
+ PORT_SetEventMask(handle, PORT_EV_RXCHAR);
+ PORT_SetEventCallback(handle, bta_hf_client_port_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_start_server
+ *
+ * Description Setup RFCOMM server for use by HF Client.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_start_server() {
+ int port_status;
+
+ if (bta_hf_client_cb_arr.serv_handle > 0) {
+ APPL_TRACE_DEBUG("%s: already started, handle: %d", __func__,
+ bta_hf_client_cb_arr.serv_handle);
+ return;
+ }
+
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+ bta_hf_client_cb_arr.serv_sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb_arr.scn);
+
+ port_status = RFCOMM_CreateConnection(
+ UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb_arr.scn, true,
+ BTA_HF_CLIENT_MTU, (uint8_t*)bd_addr_any,
+ &(bta_hf_client_cb_arr.serv_handle), bta_hf_client_mgmt_cback);
+
+ APPL_TRACE_DEBUG("%s: started rfcomm server with handle %d", __func__,
+ bta_hf_client_cb_arr.serv_handle);
+
+ if (port_status == PORT_SUCCESS) {
+ bta_hf_client_setup_port(bta_hf_client_cb_arr.serv_handle);
+ } else {
+ APPL_TRACE_DEBUG("%s: RFCOMM_CreateConnection returned error:%d", __func__,
+ port_status);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_close_server
+ *
+ * Description Close RFCOMM server port for use by HF Client.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_close_server() {
+ APPL_TRACE_DEBUG("%s: %d", __func__, bta_hf_client_cb_arr.serv_handle);
+
+ if (bta_hf_client_cb_arr.serv_handle == 0) {
+ APPL_TRACE_DEBUG("%s: already stopped", __func__);
+ return;
+ }
+
+ RFCOMM_RemoveServer(bta_hf_client_cb_arr.serv_handle);
+ bta_hf_client_cb_arr.serv_handle = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_do_open
+ *
+ * Description Open an RFCOMM connection to the peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_HF_HANDSFREE,
+ client_cb->cli_sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, client_cb->peer_scn);
+ if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn,
+ false, BTA_HF_CLIENT_MTU, client_cb->peer_addr,
+ &(client_cb->conn_handle),
+ bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
+ bta_hf_client_setup_port(client_cb->conn_handle);
+ APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d",
+ client_cb->conn_handle);
+ }
+ /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ else {
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_rfc_do_close
+ *
+ * Description Close RFCOMM connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ if (client_cb->conn_handle) {
+ RFCOMM_RemoveConnection(client_cb->conn_handle);
+ } else {
+ /* Close API was called while HF Client is in Opening state. */
+ /* Need to trigger the state machine to send callback to the app */
+ /* and move back to INIT state. */
+ tBTA_HF_CLIENT_RFC* p_buf =
+ (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+ bta_sys_sendmsg(p_buf);
+
+ /* Cancel SDP if it had been started. */
+ if (client_cb->p_disc_db) {
+ (void)SDP_CancelServiceSearch(client_cb->p_disc_db);
+ bta_hf_client_free_db(NULL);
+ }
+ }
+}
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_sco.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_sco.cc
new file mode 100755
index 0000000..e792c3f
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_sco.cc
@@ -0,0 +1,654 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_trace.h"
+#include "bt_utils.h"
+#include "bta_ag_api.h"
+#include "bta_hf_client_int.h"
+#include "device/include/esco_parameters.h"
+#include "osi/include/osi.h"
+
+#define BTA_HF_CLIENT_NO_EDR_ESCO \
+ (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+enum {
+ BTA_HF_CLIENT_SCO_LISTEN_E,
+ BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
+ BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
+ BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
+ BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* sco opened */
+ BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* sco closed */
+};
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_remove_sco
+ *
+ * Description Removes the specified SCO from the system.
+ *
+ * Returns bool - true if SCO removal was started
+ *
+ ******************************************************************************/
+static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
+ bool removed_started = false;
+ tBTM_STATUS status;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
+ status = BTM_RemoveSco(client_cb->sco_idx);
+
+ APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__,
+ client_cb->sco_idx, status);
+
+ if (status == BTM_CMD_STARTED) {
+ removed_started = true;
+ }
+ /* If no connection reset the sco handle */
+ else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
+ client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
+ }
+ }
+ return removed_started;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_cback_sco
+ *
+ * Description Call application callback function with SCO event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
+ tBTA_HF_CLIENT evt;
+
+ memset(&evt, 0, sizeof(evt));
+ bdcpy(evt.bd_addr, client_cb->peer_addr);
+
+ /* call app cback */
+ bta_hf_client_app_callback(event, (tBTA_HF_CLIENT*)&evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_conn_rsp
+ *
+ * Description Process the SCO connection request
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
+ tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
+ enh_esco_params_t resp;
+ uint8_t hci_status = HCI_SUCCESS;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
+ if (p_data->link_type == BTM_LINK_TYPE_SCO) {
+ resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ } else {
+ if (client_cb->negotiated_codec == BTA_AG_CODEC_CVSD)
+ resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC)
+ resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1);
+ }
+
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
+ } else {
+ hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+ }
+
+ BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_connreq_cback
+ *
+ * Description BTM eSCO connection requests and eSCO change requests
+ * Only the connection requests are processed by BTA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
+ tBTM_ESCO_EVT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s: %d", __func__, event);
+
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong sco handle to control block %d", __func__,
+ p_data->conn_evt.sco_inx);
+ return;
+ }
+
+ if (event != BTM_ESCO_CONN_REQ_EVT) {
+ return;
+ }
+
+ bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
+
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_conn_cback
+ *
+ * Description BTM SCO connection callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
+ APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx);
+
+ tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
+ sco_idx);
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
+ p_buf->layer_specific = client_cb->handle;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_disc_cback
+ *
+ * Description BTM SCO disconnection callback.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
+ APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx);
+
+ tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx);
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
+ p_buf->layer_specific = client_cb->handle;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_create_sco
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
+ bool is_orig) {
+ tBTM_STATUS status;
+ uint8_t* p_bd_addr = NULL;
+
+ APPL_TRACE_DEBUG("%s: %d", __func__, is_orig);
+
+ /* Make sure this sco handle is not already in use */
+ if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
+ APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
+ client_cb->sco_idx);
+ return;
+ }
+
+ enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_MSBC_T1);
+
+ /* if initiating set current scb and peer bd addr */
+ if (is_orig) {
+ BTM_SetEScoMode(&params);
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
+ }
+
+ p_bd_addr = client_cb->peer_addr;
+
+ status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
+ &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
+ bta_hf_client_sco_disc_cback);
+ if (status == BTM_CMD_STARTED && !is_orig) {
+ if (!BTM_RegForEScoEvts(client_cb->sco_idx,
+ bta_hf_client_esco_connreq_cback))
+ APPL_TRACE_DEBUG("%s: SCO registration success", __func__);
+ }
+
+ APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+ __func__, is_orig, client_cb->sco_idx, status,
+ params.packet_types);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_event
+ *
+ * Description Handle SCO events
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
+ uint8_t event) {
+ APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__,
+ client_cb->sco_state, event);
+
+ switch (client_cb->sco_state) {
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
+ switch (event) {
+ // For WBS we only listen to SCO requests. Even for outgoing SCO
+ // requests we first do a AT+BCC and wait for remote to initiate SCO
+ case BTA_HF_CLIENT_SCO_LISTEN_E:
+ /* create sco listen connection */
+ bta_hf_client_sco_create(client_cb, false);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+ break;
+
+ // For non WBS cases and enabling outgoing SCO requests we need to force
+ // open a SCO channel
+ case BTA_HF_CLIENT_SCO_OPEN_E:
+ /* remove listening connection */
+ bta_hf_client_sco_remove(client_cb);
+
+ /* create sco connection to peer */
+ bta_hf_client_sco_create(client_cb, true);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_LISTEN_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_OPEN_E:
+ /* remove listening connection */
+ bta_hf_client_sco_remove(client_cb);
+
+ /* create sco connection to peer */
+ bta_hf_client_sco_create(client_cb, true);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ case BTA_HF_CLIENT_SCO_CLOSE_E:
+ /* remove listening connection */
+ bta_hf_client_sco_remove(client_cb);
+
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_hf_client_sco_create(client_cb, false);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING(
+ "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_OPENING_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_CLOSE_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ // bta_hf_client_sco_create(client_cb, false);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_OPEN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+ /* close sco connection */
+ bta_hf_client_sco_remove(client_cb);
+
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_OPEN_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_CLOSE_E:
+ if (bta_hf_client_sco_remove(client_cb)) {
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_hf_client_sco_remove(client_cb);
+
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* peer closed sco */
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_CLOSING_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_OPEN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_CLOSE_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ /* open sco connection */
+ bta_hf_client_sco_create(client_cb, true);
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTTING_ST:
+ switch (event) {
+ case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
+ /* close sco connection; wait for conn close event */
+ bta_hf_client_sco_remove(client_cb);
+ break;
+
+ case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
+ client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
+ event);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_listen
+ *
+ * Description Initialize SCO listener
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_shutdown
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_conn_open
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
+
+ bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
+
+ if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
+ bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
+ } else {
+ bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_conn_close
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ /* clear current scb */
+ client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
+
+ bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
+
+ bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
+
+ /* call app callback */
+ bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
+
+ if (client_cb->sco_close_rfc == true) {
+ client_cb->sco_close_rfc = false;
+ bta_hf_client_rfc_do_close(p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_open
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sco_close
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
+
+ if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
+ bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);
+ }
+}
diff --git a/mtkbt/code/bt/bta/hf_client/bta_hf_client_sdp.cc b/mtkbt/code/bt/bta/hf_client/bta_hf_client_sdp.cc
new file mode 100755
index 0000000..36f5436
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hf_client/bta_hf_client_sdp.cc
@@ -0,0 +1,362 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions performing SDP
+ * operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hf_client_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_HF_CLIENT_NUM_SVC_ELEMS 2
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sdp_cback
+ *
+ * Description SDP callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hf_client_sdp_cback(uint16_t status, void* data) {
+ uint16_t event;
+ tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc(
+ sizeof(tBTA_HF_CLIENT_DISC_RESULT));
+
+ APPL_TRACE_DEBUG("bta_hf_client_sdp_cback status:0x%x", status);
+ tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;
+
+ /* set event according to int/acp */
+ if (client_cb->role == BTA_HF_CLIENT_ACP)
+ event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
+ else
+ event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
+
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = client_cb->handle;
+ p_buf->status = status;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hf_client_add_record
+ *
+ * Description This function is called by a server application to add
+ * HFP Client information to an SDP record. Prior to
+ * calling this function the application must call
+ * SDP_CreateRecord() to create an SDP record.
+ *
+ * Returns true if function execution succeeded,
+ * false if function execution failed.
+ *
+ *****************************************************************************/
+bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn,
+ tBTA_HF_CLIENT_FEAT features,
+ uint32_t sdp_handle) {
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
+ uint16_t svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
+ uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ uint16_t version;
+ uint16_t profile_uuid;
+ bool result = true;
+ uint8_t buf[2];
+ uint16_t sdp_features = 0;
+
+ APPL_TRACE_DEBUG("bta_hf_client_add_record");
+
+ memset(proto_elem_list, 0,
+ BTA_HF_CLIENT_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = scn;
+ result &= SDP_AddProtocolList(sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS,
+ proto_elem_list);
+
+ /* add service class id list */
+ svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
+ svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+ result &= SDP_AddServiceClassIdList(sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS,
+ svc_class_id_list);
+
+ /* add profile descriptor list */
+ profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ version = HFP_VERSION_1_6;
+
+ result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+ /* add service name */
+ if (p_service_name != NULL && p_service_name[0] != 0) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+ }
+
+ /* add features */
+ if (features & BTA_HF_CLIENT_FEAT_ECNR)
+ sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
+
+ if (features & BTA_HF_CLIENT_FEAT_3WAY)
+ sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
+
+ if (features & BTA_HF_CLIENT_FEAT_CLI) sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
+
+ if (features & BTA_HF_CLIENT_FEAT_VREC)
+ sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
+
+ if (features & BTA_HF_CLIENT_FEAT_VOL) sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
+
+ /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
+ if (features & BTA_HF_CLIENT_FEAT_CODEC) sdp_features |= 0x0020;
+
+ UINT16_TO_BE_FIELD(buf, sdp_features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, 2, buf);
+
+ /* add browse group list */
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+ browse_list);
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_create_record
+ *
+ * Description Create SDP record for registered service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR* client_cb_arr,
+ const char* p_service_name) {
+ /* add sdp record if not already registered */
+ if (client_cb_arr->sdp_handle == 0) {
+ client_cb_arr->sdp_handle = SDP_CreateRecord();
+ client_cb_arr->scn = BTM_AllocateSCN();
+ bta_hf_client_add_record(p_service_name, client_cb_arr->scn,
+ client_cb_arr->features,
+ client_cb_arr->sdp_handle);
+
+ bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_del_record
+ *
+ * Description Delete SDP record for registered service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_del_record(tBTA_HF_CLIENT_CB_ARR* client_cb) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (client_cb->sdp_handle != 0) {
+ SDP_DeleteRecord(client_cb->sdp_handle);
+ client_cb->sdp_handle = 0;
+ BTM_FreeSCN(client_cb->scn);
+ BTM_SecClrService(BTM_SEC_SERVICE_HF_HANDSFREE);
+ bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_sdp_find_attr
+ *
+ * Description Process SDP discovery results to find requested attribute
+ *
+ *
+ * Returns true if results found, false otherwise.
+ *
+ ******************************************************************************/
+bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) {
+ tSDP_DISC_REC* p_rec = NULL;
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ bool result = false;
+
+ client_cb->peer_version = HFP_VERSION_1_1; /* Default version */
+
+ /* loop through all records we found */
+ while (true) {
+ /* get next record; if none found, we're done */
+ p_rec = SDP_FindServiceInDb(client_cb->p_disc_db,
+ UUID_SERVCLASS_AG_HANDSFREE, p_rec);
+ if (p_rec == NULL) {
+ break;
+ }
+
+ /* get scn from proto desc list if initiator */
+ if (client_cb->role == BTA_HF_CLIENT_INT) {
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ client_cb->peer_scn = (uint8_t)pe.params[0];
+ } else {
+ continue;
+ }
+ }
+
+ /* get profile version (if failure, version parameter is not updated) */
+ SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE,
+ &client_cb->peer_version);
+
+ /* get features */
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ /* Found attribute. Get value. */
+ /* There might be race condition between SDP and BRSF. */
+ /* Do not update if we already received BRSF. */
+ if (client_cb->peer_features == 0) {
+ client_cb->peer_features = p_attr->attr_value.v.u16;
+
+ /* SDP and BRSF WBS bit are different, correct it if set */
+ if (client_cb->peer_features & 0x0020) {
+ client_cb->peer_features &= ~0x0020;
+ client_cb->peer_features |= BTA_HF_CLIENT_PEER_CODEC;
+ }
+
+ /* get network for ability to reject calls */
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK);
+ if (p_attr != NULL) {
+ if (p_attr->attr_value.v.u16 == 0x01) {
+ client_cb->peer_features |= BTA_HF_CLIENT_PEER_REJECT;
+ }
+ }
+ }
+ }
+
+ /* found what we needed */
+ result = true;
+ break;
+ }
+
+ APPL_TRACE_DEBUG("%s: peer_version=0x%x peer_features=0x%x", __func__,
+ client_cb->peer_version, client_cb->peer_features);
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_do_disc
+ *
+ * Description Do service discovery.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
+ tSDP_UUID uuid_list[2];
+ uint16_t num_uuid = 1;
+ uint16_t attr_list[4];
+ uint8_t num_attr;
+ bool db_inited = false;
+
+ /* initiator; get proto list and features */
+ if (client_cb->role == BTA_HF_CLIENT_INT) {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 4;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+ }
+ /* acceptor; get features */
+ else {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 3;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_AG_HANDSFREE;
+ }
+
+ /* allocate buffer for sdp database */
+ client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ uuid_list[1].len = LEN_UUID_16;
+ db_inited = SDP_InitDiscoveryDb(client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE,
+ num_uuid, uuid_list, num_attr, attr_list);
+
+ if (db_inited) {
+ /*Service discovery not initiated */
+ db_inited = SDP_ServiceSearchAttributeRequest2(
+ client_cb->peer_addr, client_cb->p_disc_db, bta_hf_client_sdp_cback,
+ (void*)client_cb);
+ }
+
+ if (!db_inited) {
+ /*free discover db */
+ bta_hf_client_free_db(NULL);
+ /* sent failed event */
+ tBTA_HF_CLIENT_DATA msg;
+ msg.hdr.layer_specific = client_cb->handle;
+ bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, &msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_free_db
+ *
+ * Description Free discovery database.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data) {
+ tBTA_HF_CLIENT_CB* client_cb =
+ bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
+ if (client_cb == NULL) {
+ APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
+ p_data->hdr.layer_specific);
+ return;
+ }
+
+ osi_free_and_reset((void**)&client_cb->p_disc_db);
+}
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_act.cc b/mtkbt/code/bt/bta/hh/bta_hh_act.cc
new file mode 100755
index 0000000..b0aa4df
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_act.cc
@@ -0,0 +1,1275 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID host action functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bta_hh_co.h"
+#include "bta_hh_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Local Function prototypes
+ ****************************************************************************/
+static void bta_hh_cback(uint8_t dev_handle, BD_ADDR addr, uint8_t event,
+ uint32_t data, BT_HDR* pdata);
+static tBTA_HH_STATUS bta_hh_get_trans_status(uint32_t result);
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_get_w4_event(uint16_t event);
+static const char* bta_hh_hid_event_name(uint16_t event);
+#endif
+
+/*****************************************************************************
+ * Action Functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_hh_api_enable
+ *
+ * Description Perform necessary operations to enable HID host.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_api_enable(tBTA_HH_DATA* p_data) {
+ tBTA_HH_STATUS status = BTA_HH_ERR;
+ uint8_t xx;
+
+ /* initialize BTE HID */
+ HID_HostInit();
+
+ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+
+ HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask);
+
+ /* Register with L2CAP */
+ if (HID_HostRegister(bta_hh_cback) == HID_SUCCESS) {
+ /* store parameters */
+ bta_hh_cb.p_cback = p_data->api_enable.p_cback;
+
+ status = BTA_HH_OK;
+ /* initialize device CB */
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ bta_hh_cb.kdev[xx].state = BTA_HH_IDLE_ST;
+ bta_hh_cb.kdev[xx].hid_handle = BTA_HH_INVALID_HANDLE;
+ bta_hh_cb.kdev[xx].index = xx;
+ }
+
+ /* initialize control block map */
+ for (xx = 0; xx < BTA_HH_MAX_KNOWN; xx++)
+ bta_hh_cb.cb_index[xx] = BTA_HH_IDX_INVALID;
+ }
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (status == BTA_HH_OK) {
+ bta_hh_le_enable();
+ } else
+#endif
+ /* signal BTA call back event */
+ (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT, (tBTA_HH*)&status);
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_api_disable
+ *
+ * Description Perform necessary operations to disable HID host.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_api_disable(void) {
+ uint8_t xx;
+
+ /* service is not enabled */
+ if (bta_hh_cb.p_cback == NULL) return;
+
+ /* no live connection, signal DISC_CMPL_EVT directly */
+ if (!bta_hh_cb.cnt_num) {
+ bta_hh_disc_cmpl();
+ } else /* otherwise, disconnect all live connections */
+ {
+ bta_hh_cb.w4_disable = true;
+
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ /* send API_CLOSE event to every connected device */
+ if (bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST) {
+ /* disconnect all connected devices */
+ bta_hh_sm_execute(&bta_hh_cb.kdev[xx], BTA_HH_API_CLOSE_EVT, NULL);
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_disc_cmpl
+ *
+ * Description All connections have been closed, disable service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_disc_cmpl(void) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ HID_HostDeregister();
+ bta_hh_le_deregister();
+#else
+ tBTA_HH_STATUS status = BTA_HH_OK;
+
+ /* Deregister with lower layer */
+ if (HID_HostDeregister() != HID_SUCCESS) status = BTA_HH_ERR;
+
+ bta_hh_cleanup_disable(status);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_sdp_cback
+ *
+ * Description SDP callback function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hh_sdp_cback(uint16_t result, uint16_t attr_mask,
+ tHID_DEV_SDP_INFO* sdp_rec) {
+ tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
+ uint8_t hdl = 0;
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+
+ /* make sure sdp succeeded and hh has not been disabled */
+ if ((result == SDP_SUCCESS) && (p_cb != NULL)) {
+ /* security is required for the connection, add attr_mask bit*/
+ if (p_cb->sec_mask) attr_mask |= HID_SEC_REQUIRED;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_EVENT(
+ "bta_hh_sdp_cback: p_cb: %d result 0x%02x, \
+ attr_mask 0x%02x, handle %x",
+ p_cb, result, attr_mask, p_cb->hid_handle);
+#endif
+
+ /* check to see type of device is supported , and should not been added
+ * before */
+ if (bta_hh_tod_spt(p_cb, sdp_rec->sub_class)) {
+ /* if not added before */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+ /* add device/update attr_mask information */
+ if (HID_HostAddDev(p_cb->addr, attr_mask, &hdl) == HID_SUCCESS) {
+ status = BTA_HH_OK;
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ } else {
+ p_cb->app_id = 0;
+ }
+ } else {
+ hdl = p_cb->hid_handle;
+ }
+ /* else : incoming connection after SDP should update the SDP information
+ * as well */
+
+ if (p_cb->app_id != 0) {
+ /* update cb information with attr_mask, dscp_info etc. */
+ bta_hh_add_device_to_list(p_cb, hdl, attr_mask, &sdp_rec->dscp_info,
+ sdp_rec->sub_class, sdp_rec->ssr_max_latency,
+ sdp_rec->ssr_min_tout, p_cb->app_id);
+
+ p_cb->dscp_info.ctry_code = sdp_rec->ctry_code;
+
+ status = BTA_HH_OK;
+ }
+
+ } else /* type of device is not supported */
+ status = BTA_HH_ERR_TOD_UNSPT;
+ }
+
+ /* free disc_db when SDP is completed */
+ osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_di_sdp_cback
+ *
+ * Description SDP DI callback function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hh_di_sdp_cback(uint16_t result) {
+ tBTA_HH_DEV_CB* p_cb = bta_hh_cb.p_cur;
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+ tSDP_DI_GET_RECORD di_rec;
+ tHID_STATUS ret;
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_EVENT("bta_hh_di_sdp_cback: p_cb: %d result 0x%02x", p_cb, result);
+#endif
+
+ /* if DI record does not exist on remote device, vendor_id in
+ * tBTA_HH_DEV_DSCP_INFO will be
+ * set to 0xffff and we will allow the connection to go through. Spec
+ * mandates that DI
+ * record be set, but many HID devices do not set this. So for IOP
+ * purposes, we allow the
+ * connection to go through and update the DI record to invalid DI
+ * entry.*/
+ if (((result == SDP_SUCCESS) || (result == SDP_NO_RECS_MATCH)) &&
+ (p_cb != NULL)) {
+ if (result == SDP_SUCCESS &&
+ SDP_GetNumDiRecords(bta_hh_cb.p_disc_db) != 0) {
+ /* always update information with primary DI record */
+ if (SDP_GetDiRecord(1, &di_rec, bta_hh_cb.p_disc_db) == SDP_SUCCESS) {
+ bta_hh_update_di_info(p_cb, di_rec.rec.vendor, di_rec.rec.product,
+ di_rec.rec.version, 0);
+ }
+
+ } else /* no DI recrod available */
+ {
+ bta_hh_update_di_info(p_cb, BTA_HH_VENDOR_ID_INVALID, 0, 0, 0);
+ }
+
+ ret = HID_HostGetSDPRecord(p_cb->addr, bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size, bta_hh_sdp_cback);
+ if (ret == HID_SUCCESS) {
+ status = BTA_HH_OK;
+ } else {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "bta_hh_di_sdp_cback: HID_HostGetSDPRecord failed: Status 0x%2x",
+ ret);
+#endif
+ }
+ }
+
+ if (status != BTA_HH_OK) {
+ osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+ /* send SDP_CMPL_EVT into state machine */
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_start_sdp
+ *
+ * Description Start SDP service search, and obtain necessary SDP records.
+ * Only one SDP service search request is allowed at the same
+ * time. For every BTA_HhOpen API call, do SDP first unless SDP
+ * has been done previously.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_STATUS status = BTA_HH_ERR_SDP;
+ uint8_t hdl;
+
+ p_cb->sec_mask = p_data->api_conn.sec_mask;
+ p_cb->mode = p_data->api_conn.mode;
+ bta_hh_cb.p_cur = p_cb;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+ bta_hh_le_open_conn(p_cb, p_data->api_conn.bd_addr);
+ return;
+ }
+#endif
+
+ /* if previously virtually cabled device, skip SDP */
+ if (p_cb->app_id) {
+ status = BTA_HH_OK;
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_start_sdp:: skip SDP for known devices");
+#endif
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+ if (HID_HostAddDev(p_cb->addr, p_cb->attr_mask, &hdl) == HID_SUCCESS) {
+ /* update device CB with newly register device handle */
+ bta_hh_add_device_to_list(p_cb, hdl, p_cb->attr_mask, NULL,
+ p_cb->sub_class,
+ p_cb->dscp_info.ssr_max_latency,
+ p_cb->dscp_info.ssr_min_tout, p_cb->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[hdl] = p_cb->index;
+ } else
+ status = BTA_HH_ERR_NO_RES;
+ }
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+ return;
+ }
+ /* GetSDPRecord. at one time only one SDP precedure can be active */
+ else if (!bta_hh_cb.p_disc_db) {
+ bta_hh_cb.p_disc_db =
+ (tSDP_DISCOVERY_DB*)osi_malloc(p_bta_hh_cfg->sdp_db_size);
+ bta_hh_cb.p_cur = p_cb;
+ /* do DI discovery first */
+ if (SDP_DiDiscover(p_data->api_conn.bd_addr, bta_hh_cb.p_disc_db,
+ p_bta_hh_cfg->sdp_db_size,
+ bta_hh_di_sdp_cback) != SDP_SUCCESS) {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "bta_hh_start_sdp: SDP_DiDiscover failed: \
+ Status 0x%2X",
+ status);
+#endif
+ status = BTA_HH_ERR_SDP;
+ osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+ } else {
+ status = BTA_HH_OK;
+ }
+ } else if (bta_hh_cb.p_disc_db) {
+ /* It is possible that there is incoming/outgoing collision case. DUT
+ * initiated
+ * HID connection at same time remote has connected L2CAP for HID control,
+ * so SDP would be in progress, when this flow reaches here. Just do nothing
+ * when the code reaches here, and ongoing SDP completion or failure will
+ * handle this case.
+ */
+ APPL_TRACE_DEBUG("%s: ignoring as SDP already in progress", __func__);
+ return;
+ }
+
+ if (status != BTA_HH_OK)
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_sdp_cmpl
+ *
+ * Description When SDP completes, initiate a connection or report an error
+ * depending on the SDP result.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CONN conn_dat;
+ tBTA_HH_STATUS status = p_data->status;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_sdp_cmpl: status 0x%2X", p_data->status);
+#endif
+
+ /* initialize call back data */
+ memset((void*)&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ bdcpy(conn_dat.bda, p_cb->addr);
+
+ /* if SDP compl success */
+ if (status == BTA_HH_OK) {
+ /* not incoming connection doing SDP, initiate a HID connection */
+ if (!p_cb->incoming_conn) {
+ tHID_STATUS ret;
+ /* set security level */
+ HID_HostSetSecurityLevel("", p_cb->sec_mask);
+
+ /* open HID connection */
+ ret = HID_HostOpenDev(p_cb->hid_handle);
+ APPL_TRACE_DEBUG("%s: HID_HostOpenDev returned=%d", __func__, ret);
+ if (ret == HID_SUCCESS || ret == HID_ERR_ALREADY_CONN) {
+ status = BTA_HH_OK;
+ } else if (ret == HID_ERR_CONN_IN_PROCESS) {
+ /* Connection already in progress, return from here, SDP
+ * will be performed after connection is completed.
+ */
+ APPL_TRACE_DEBUG("%s: connection already in progress", __func__);
+ return;
+ } else {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: HID_HostOpenDev failed: Status 0x%2X", __func__,
+ ret);
+#endif
+ /* open fail, remove device from management device list */
+ HID_HostRemoveDev(p_cb->hid_handle);
+ status = BTA_HH_ERR;
+ }
+ } else /* incoming connection SDP finish */
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+ }
+ }
+
+ if (status != BTA_HH_OK) {
+ /* Check if this was incoming connection request from an unknown device
+ **and connection failed due to missing HID Device SDP UUID
+ **In above condition, disconnect the link as well as remove the
+ **device from list of HID devices*/
+ if ((status == BTA_HH_ERR_SDP) && (p_cb->incoming_conn) &&
+ (p_cb->app_id == 0)) {
+ APPL_TRACE_DEBUG("bta_hh_sdp_cmpl:SDP failed for incoming conn :hndl %d",
+ p_cb->incoming_hid_handle);
+ HID_HostRemoveDev(p_cb->incoming_hid_handle);
+ }
+ conn_dat.status = status;
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+ /* move state machine W4_CONN ->IDLE */
+ bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+
+ /* if this is an outgoing connection to an unknown device, clean up cb */
+ if (p_cb->app_id == 0 && !p_cb->incoming_conn) {
+ /* clean up device control block */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_api_disc_act
+ *
+ * Description HID Host initiate a disconnection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CBDATA disc_dat;
+ tHID_STATUS status;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device)
+ bta_hh_le_api_disc_act(p_cb);
+ else
+#endif
+ {
+ /* found an active connection */
+ disc_dat.handle =
+ p_data ? (uint8_t)p_data->hdr.layer_specific : p_cb->hid_handle;
+ disc_dat.status = BTA_HH_ERR;
+
+ status = HID_HostCloseDev(disc_dat.handle);
+
+ if (status) (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
+ }
+
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_open_cmpl_act
+ *
+ * Description HID host connection completed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CONN conn;
+ uint8_t dev_handle =
+ p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
+
+ memset((void*)&conn, 0, sizeof(tBTA_HH_CONN));
+ conn.handle = dev_handle;
+ bdcpy(conn.bda, p_cb->addr);
+
+ /* increase connection number */
+ bta_hh_cb.cnt_num++;
+
+ /* initialize device driver */
+ bta_hh_co_open(p_cb->hid_handle, p_cb->sub_class, p_cb->attr_mask,
+ p_cb->app_id);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ conn.status = p_cb->status;
+ conn.le_hid = p_cb->is_le_device;
+ conn.scps_supported = p_cb->scps_supported;
+
+ if (!p_cb->is_le_device)
+#endif
+ {
+ /* inform role manager */
+ bta_sys_conn_open(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ /* set protocol mode when not default report mode */
+ if (p_cb->mode != BTA_HH_PROTO_RPT_MODE
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ && !p_cb->is_le_device
+#endif
+ ) {
+ if ((HID_HostWriteDev(dev_handle, HID_TRANS_SET_PROTOCOL,
+ HID_PAR_PROTOCOL_BOOT_MODE, 0, 0, NULL)) !=
+ HID_SUCCESS) {
+ /* HID connection is up, while SET_PROTO fail */
+ conn.status = BTA_HH_ERR_PROTO;
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn);
+ } else {
+ conn.status = BTA_HH_OK;
+ p_cb->w4_evt = BTA_HH_OPEN_EVT;
+ }
+ } else
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn);
+
+ p_cb->incoming_conn = false;
+ p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_open_act
+ *
+ * Description HID host receive HID_OPEN_EVT .
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_API_CONN conn_data;
+
+ uint8_t dev_handle =
+ p_data ? (uint8_t)p_data->hid_cback.hdr.layer_specific : p_cb->hid_handle;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_EVENT("bta_hh_open_act: Device[%d] connected", dev_handle);
+#endif
+
+ /* SDP has been done */
+ if (p_cb->app_id != 0) {
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, p_data);
+ } else
+ /* app_id == 0 indicates an incoming conenction request arrives without SDP
+ performed, do it first */
+ {
+ p_cb->incoming_conn = true;
+ /* store the handle here in case sdp fails - need to disconnect */
+ p_cb->incoming_hid_handle = dev_handle;
+
+ memset(&conn_data, 0, sizeof(tBTA_HH_API_CONN));
+ bdcpy(conn_data.bd_addr, p_cb->addr);
+ bta_hh_start_sdp(p_cb, (tBTA_HH_DATA*)&conn_data);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_data_act
+ *
+ * Description HID Host process a data report
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ BT_HDR* pdata = p_data->hid_cback.p_data;
+ uint8_t* p_rpt = (uint8_t*)(pdata + 1) + pdata->offset;
+
+ bta_hh_co_data((uint8_t)p_data->hid_cback.hdr.layer_specific, p_rpt,
+ pdata->len, p_cb->mode, p_cb->sub_class,
+ p_cb->dscp_info.ctry_code, p_cb->addr, p_cb->app_id);
+
+ osi_free_and_reset((void**)&pdata);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_handsk_act
+ *
+ * Description HID Host process a handshake acknoledgement.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CBDATA cback_data;
+ tBTA_HH_HSDATA hs_data;
+ tBTA_HH_CONN conn;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("HANDSHAKE received for: event = %s data= %d",
+ bta_hh_get_w4_event(p_cb->w4_evt), p_data->hid_cback.data);
+#endif
+
+ memset(&hs_data, 0, sizeof(tBTA_HH_HSDATA));
+ memset(&cback_data, 0, sizeof(tBTA_HH_CBDATA));
+
+ switch (p_cb->w4_evt) {
+ /* GET_ transsaction, handshake indicate unsupported request */
+ case BTA_HH_GET_PROTO_EVT:
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_UNKNOWN;
+ /* fall through */
+ case BTA_HH_GET_RPT_EVT:
+ case BTA_HH_GET_IDLE_EVT:
+ hs_data.handle = p_cb->hid_handle;
+ /* if handshake gives an OK code for these transaction, fill in UNSUPT */
+ hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+ if (hs_data.status == BTA_HH_OK) hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
+
+ (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&hs_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* acknoledgement from HID device for SET_ transaction */
+ case BTA_HH_SET_RPT_EVT:
+ case BTA_HH_SET_PROTO_EVT:
+ case BTA_HH_SET_IDLE_EVT:
+ cback_data.handle = p_cb->hid_handle;
+ cback_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
+ (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&cback_data);
+ p_cb->w4_evt = 0;
+ break;
+
+ /* SET_PROTOCOL when open connection */
+ case BTA_HH_OPEN_EVT:
+ conn.status = p_data->hid_cback.data ? BTA_HH_ERR_PROTO : BTA_HH_OK;
+ conn.handle = p_cb->hid_handle;
+ bdcpy(conn.bda, p_cb->addr);
+ (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&conn);
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+ p_cb->w4_evt = 0;
+ break;
+
+ default:
+ /* unknow transaction handshake response */
+ APPL_TRACE_DEBUG("unknown transaction type");
+ break;
+ }
+
+ /* transaction achknoledgement received, inform PM for mode change */
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_ctrl_dat_act
+ *
+ * Description HID Host process a data report from control channel.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ BT_HDR* pdata = p_data->hid_cback.p_data;
+ uint8_t* data = (uint8_t*)(pdata + 1) + pdata->offset;
+ tBTA_HH_HSDATA hs_data;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("Ctrl DATA received w4: event[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ hs_data.status = BTA_HH_OK;
+ hs_data.handle = p_cb->hid_handle;
+
+ switch (p_cb->w4_evt) {
+ case BTA_HH_GET_IDLE_EVT:
+ hs_data.rsp_data.idle_rate = *data;
+ break;
+ case BTA_HH_GET_RPT_EVT:
+ hs_data.rsp_data.p_rpt_data = pdata;
+ break;
+ case BTA_HH_GET_PROTO_EVT:
+ /* match up BTE/BTA report/boot mode def*/
+ hs_data.rsp_data.proto_mode = ((*data) == HID_PAR_PROTOCOL_REPORT)
+ ? BTA_HH_PROTO_RPT_MODE
+ : BTA_HH_PROTO_BOOT_MODE;
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("GET_PROTOCOL Mode = [%s]",
+ (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+ ? "Report"
+ : "Boot");
+#endif
+ break;
+ /* should not expect control DATA for SET_ transaction */
+ case BTA_HH_SET_PROTO_EVT:
+ /* fall through */
+ case BTA_HH_SET_RPT_EVT:
+ /* fall through */
+ case BTA_HH_SET_IDLE_EVT:
+ /* fall through */
+ default:
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("invalid transaction type for DATA payload: 4_evt[%s]",
+ bta_hh_get_w4_event(p_cb->w4_evt));
+#endif
+ break;
+ }
+
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+
+ (*bta_hh_cb.p_cback)(p_cb->w4_evt, (tBTA_HH*)&hs_data);
+
+ p_cb->w4_evt = 0;
+ osi_free_and_reset((void**)&pdata);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_open_failure
+ *
+ * Description report HID open failure when at wait for connection state
+ * and receive device close event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CONN conn_dat;
+ uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+ memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status =
+ (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = false;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+ bta_hh_disc_cmpl();
+ }
+
+ /* Error in opening hid connection, reset flags */
+ p_cb->incoming_conn = false;
+ p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+}
+
+/**M: HID device reconnect fail for collision @{*/
+/*******************************************************************************
+**
+** Function bta_hh_open_collision_failure
+**
+** Description report HID open failure when at wait for connection state and receive
+** device close event after firmware layer collision.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_open_collision_failure(tBTA_HH_DEV_CB *p_cb, uint32_t data)
+{
+ tBTA_HH_CONN conn_dat ;
+ uint32_t reason = data; /* Reason for closing (32-bit) */
+
+ memset(&conn_dat, 0, sizeof(tBTA_HH_CONN));
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status = (reason == HID_ERR_AUTH_FAILED) ?
+ BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseCollisionDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH *)&conn_dat);
+
+#if BTA_HH_DEBUG
+ bta_hh_trace_dev_db();
+#endif
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = FALSE;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable)
+ {
+ bta_hh_disc_cmpl();
+ }
+
+ /* Error in opening hid connection, reset flags */
+ p_cb->incoming_conn = FALSE;
+ p_cb->incoming_hid_handle = BTA_HH_INVALID_HANDLE;
+}
+/**@}*/
+
+
+/*******************************************************************************
+ *
+ * Function bta_hh_close_act
+ *
+ * Description HID Host process a close event
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CONN conn_dat;
+ tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+ uint32_t reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */
+
+ /* if HID_HDEV_EVT_VC_UNPLUG was received, report BTA_HH_VC_UNPLUG_EVT */
+ uint16_t event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT;
+
+ disc_dat.handle = p_cb->hid_handle;
+ disc_dat.status = p_data->hid_cback.data;
+
+ /* Check reason for closing */
+ if ((reason & (HID_L2CAP_CONN_FAIL |
+ HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection
+ (page timeout or l2cap error) */
+ (reason ==
+ HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */
+ (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */
+ {
+ /* Failure in opening connection */
+ conn_dat.handle = p_cb->hid_handle;
+ conn_dat.status =
+ (reason == HID_ERR_AUTH_FAILED) ? BTA_HH_ERR_AUTH_FAILED : BTA_HH_ERR;
+ bdcpy(conn_dat.bda, p_cb->addr);
+ HID_HostCloseDev(p_cb->hid_handle);
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+ return;
+ }
+ /* otherwise report CLOSE/VC_UNPLUG event */
+ else {
+ /* finaliza device driver */
+ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+ /* inform role manager */
+ bta_sys_conn_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ /* update total conn number */
+ bta_hh_cb.cnt_num--;
+
+ if (disc_dat.status) disc_dat.status = BTA_HH_ERR;
+
+ (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&disc_dat);
+
+ /* if virtually unplug, remove device */
+ if (p_cb->vp) {
+ HID_HostRemoveDev(p_cb->hid_handle);
+ bta_hh_clean_up_kdev(p_cb);
+ }
+
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+ }
+
+ /* clean up control block, but retain SDP info and device handle */
+ p_cb->vp = false;
+ p_cb->w4_evt = 0;
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+ bta_hh_disc_cmpl();
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_get_dscp_act
+ *
+ * Description Get device report descriptor
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb,
+ UNUSED_ATTR tBTA_HH_DATA* p_data) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device) {
+ bta_hh_le_get_dscp_act(p_cb);
+ } else
+#endif
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH*)&p_cb->dscp_info);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_maint_dev_act
+ *
+ * Description HID Host maintain device list.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_MAINT_DEV* p_dev_info = &p_data->api_maintdev;
+ tBTA_HH_DEV_INFO dev_info;
+ uint8_t dev_handle;
+
+ dev_info.status = BTA_HH_ERR;
+ dev_info.handle = BTA_HH_INVALID_HANDLE;
+
+ switch (p_dev_info->sub_event) {
+ case BTA_HH_ADD_DEV_EVT: /* add a device */
+ bdcpy(dev_info.bda, p_dev_info->bda);
+ /* initialize callback data */
+ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) {
+ dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
+ dev_info.status = BTA_HH_OK;
+ } else
+#endif
+
+ if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask,
+ &dev_handle) == HID_SUCCESS) {
+ dev_info.handle = dev_handle;
+ dev_info.status = BTA_HH_OK;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ /* update DI information */
+ bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id,
+ p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version,
+ p_dev_info->dscp_info.flag);
+#else
+ bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id,
+ p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version, 0);
+
+#endif
+ /* add to BTA device list */
+ bta_hh_add_device_to_list(
+ p_cb, dev_handle, p_dev_info->attr_mask,
+ &p_dev_info->dscp_info.descriptor, p_dev_info->sub_class,
+ p_dev_info->dscp_info.ssr_max_latency,
+ p_dev_info->dscp_info.ssr_min_tout, p_dev_info->app_id);
+ /* update cb_index[] map */
+ bta_hh_cb.cb_index[dev_handle] = p_cb->index;
+ }
+ } else /* device already been added */
+ {
+ dev_info.handle = p_cb->hid_handle;
+ dev_info.status = BTA_HH_OK;
+ }
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_trace_dev_db();
+#endif
+
+ break;
+ case BTA_HH_RMV_DEV_EVT: /* remove device */
+ dev_info.handle = (uint8_t)p_dev_info->hdr.layer_specific;
+ bdcpy(dev_info.bda, p_cb->addr);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device) {
+ bta_hh_le_remove_dev_bg_conn(p_cb);
+ bta_hh_sm_execute(p_cb, BTA_HH_API_CLOSE_EVT, NULL);
+ bta_hh_clean_up_kdev(p_cb);
+ } else
+#endif
+ {
+ if (HID_HostRemoveDev(dev_info.handle) == HID_SUCCESS) {
+ dev_info.status = BTA_HH_OK;
+
+ /* remove from known device list in BTA */
+ bta_hh_clean_up_kdev(p_cb);
+ }
+ }
+ break;
+
+ default:
+ APPL_TRACE_DEBUG("invalid command");
+ break;
+ }
+
+ (*bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH*)&dev_info);
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_write_dev_act
+ *
+ * Description Write device action. can be SET/GET/DATA transaction.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CBDATA cbdata = {BTA_HH_OK, 0};
+ uint16_t event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device)
+ bta_hh_le_write_dev_act(p_cb, p_data);
+ else
+#endif
+ {
+
+ cbdata.handle = p_cb->hid_handle;
+
+ /* match up BTE/BTA report/boot mode def */
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) {
+ p_data->api_sndcmd.param =
+ (p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE)
+ ? HID_PAR_PROTOCOL_REPORT
+ : HID_PAR_PROTOCOL_BOOT_MODE;
+ }
+
+ if (HID_HostWriteDev(p_cb->hid_handle, p_data->api_sndcmd.t_type,
+ p_data->api_sndcmd.param, p_data->api_sndcmd.data,
+ p_data->api_sndcmd.rpt_id,
+ p_data->api_sndcmd.p_data) != HID_SUCCESS) {
+ APPL_TRACE_ERROR("HID_HostWriteDev Error ");
+ cbdata.status = BTA_HH_ERR;
+
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
+ p_data->api_sndcmd.t_type != HID_TRANS_DATA)
+ (*bta_hh_cb.p_cback)(event, (tBTA_HH*)&cbdata);
+ else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ (*bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH*)&cbdata);
+ } else {
+ switch (p_data->api_sndcmd.t_type) {
+ case HID_TRANS_SET_PROTOCOL:
+ /* fall through */
+ case HID_TRANS_GET_REPORT:
+ /* fall through */
+ case HID_TRANS_SET_REPORT:
+ /* fall through */
+ case HID_TRANS_GET_PROTOCOL:
+ /* fall through */
+ case HID_TRANS_GET_IDLE:
+ /* fall through */
+ case HID_TRANS_SET_IDLE: /* set w4_handsk event name for callback
+ function use */
+ p_cb->w4_evt = event;
+ break;
+ case HID_TRANS_DATA: /* output report */
+ /* fall through */
+ case HID_TRANS_CONTROL:
+ /* no handshake event will be generated */
+ /* if VC_UNPLUG is issued, set flag */
+ if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
+ p_cb->vp = true;
+
+ break;
+ /* currently not expected */
+ case HID_TRANS_DATAC:
+ default:
+ APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d",
+ p_data->api_sndcmd.t_type);
+ break;
+ }
+
+ /* if not control type transaction, notify PM for energy control */
+ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
+ /* inform PM for mode change */
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) {
+ bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) {
+ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
+ }
+ }
+ }
+ return;
+}
+
+/*****************************************************************************
+ * Static Function
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_hh_cback
+ *
+ * Description BTA HH callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hh_cback(uint8_t dev_handle, BD_ADDR addr, uint8_t event,
+ uint32_t data, BT_HDR* pdata) {
+ uint16_t sm_event = BTA_HH_INVALID_EVT;
+ uint8_t xx = 0;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_cback::HID_event [%s]",
+ bta_hh_hid_event_name(event));
+#endif
+
+ switch (event) {
+ case HID_HDEV_EVT_OPEN:
+ sm_event = BTA_HH_INT_OPEN_EVT;
+ break;
+ case HID_HDEV_EVT_CLOSE:
+ sm_event = BTA_HH_INT_CLOSE_EVT;
+ break;
+ case HID_HDEV_EVT_INTR_DATA:
+ sm_event = BTA_HH_INT_DATA_EVT;
+ break;
+ case HID_HDEV_EVT_HANDSHAKE:
+ sm_event = BTA_HH_INT_HANDSK_EVT;
+ break;
+ case HID_HDEV_EVT_CTRL_DATA:
+ sm_event = BTA_HH_INT_CTRL_DATA;
+ break;
+ case HID_HDEV_EVT_RETRYING:
+ break;
+ case HID_HDEV_EVT_INTR_DATC:
+ case HID_HDEV_EVT_CTRL_DATC:
+ /* Unhandled events: Free buffer for DATAC */
+ osi_free_and_reset((void**)&pdata);
+ break;
+ case HID_HDEV_EVT_VC_UNPLUG:
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ if (bta_hh_cb.kdev[xx].hid_handle == dev_handle) {
+ bta_hh_cb.kdev[xx].vp = true;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (sm_event != BTA_HH_INVALID_EVT) {
+ tBTA_HH_CBACK_DATA* p_buf = (tBTA_HH_CBACK_DATA*)osi_malloc(
+ sizeof(tBTA_HH_CBACK_DATA) + sizeof(BT_HDR));
+ p_buf->hdr.event = sm_event;
+ p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+ p_buf->data = data;
+ bdcpy(p_buf->addr, addr);
+ p_buf->p_data = pdata;
+
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_get_trans_status
+ *
+ * Description translate a handshake result code into BTA HH
+ * status code
+ *
+ ******************************************************************************/
+static tBTA_HH_STATUS bta_hh_get_trans_status(uint32_t result) {
+ switch (result) {
+ case HID_PAR_HANDSHAKE_RSP_SUCCESS: /* (0) */
+ return BTA_HH_OK;
+ case HID_PAR_HANDSHAKE_RSP_NOT_READY: /* (1) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: /* (2) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ: /* (3) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM: /* (4) */
+ return (tBTA_HH_STATUS)result;
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN: /* (14) */
+ case HID_PAR_HANDSHAKE_RSP_ERR_FATAL: /* (15) */
+ default:
+ return BTA_HH_HS_ERROR;
+ break;
+ }
+}
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_get_w4_event(uint16_t event) {
+ switch (event) {
+ case BTA_HH_GET_RPT_EVT:
+ return "BTA_HH_GET_RPT_EVT";
+ case BTA_HH_SET_RPT_EVT:
+ return "BTA_HH_SET_RPT_EVT";
+ case BTA_HH_GET_PROTO_EVT:
+ return "BTA_HH_GET_PROTO_EVT";
+ case BTA_HH_SET_PROTO_EVT:
+ return "BTA_HH_SET_PROTO_EVT";
+ case BTA_HH_GET_IDLE_EVT:
+ return "BTA_HH_GET_IDLE_EVT";
+ case BTA_HH_SET_IDLE_EVT:
+ return "BTA_HH_SET_IDLE_EVT";
+ case BTA_HH_OPEN_EVT:
+ return "BTA_HH_OPEN_EVT";
+ default:
+ return "Unknown event";
+ }
+}
+
+static const char* bta_hh_hid_event_name(uint16_t event) {
+ switch (event) {
+ case HID_HDEV_EVT_OPEN:
+ return "HID_HDEV_EVT_OPEN";
+ case HID_HDEV_EVT_CLOSE:
+ return "HID_HDEV_EVT_CLOSE";
+ case HID_HDEV_EVT_RETRYING:
+ return "HID_HDEV_EVT_RETRYING";
+ case HID_HDEV_EVT_INTR_DATA:
+ return "HID_HDEV_EVT_INTR_DATA";
+ case HID_HDEV_EVT_INTR_DATC:
+ return "HID_HDEV_EVT_INTR_DATC";
+ case HID_HDEV_EVT_CTRL_DATA:
+ return "HID_HDEV_EVT_CTRL_DATA";
+ case HID_HDEV_EVT_CTRL_DATC:
+ return "HID_HDEV_EVT_CTRL_DATC";
+ case HID_HDEV_EVT_HANDSHAKE:
+ return "HID_HDEV_EVT_HANDSHAKE";
+ case HID_HDEV_EVT_VC_UNPLUG:
+ return "HID_HDEV_EVT_VC_UNPLUG";
+ default:
+ return "Unknown HID event";
+ }
+}
+#endif
+#endif /* BTA_HH_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_api.cc b/mtkbt/code/bt/bta/hh/bta_hh_api.cc
new file mode 100755
index 0000000..be30ccb
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_api.cc
@@ -0,0 +1,411 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID HOST API in the subsystem of BTA.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_hh"
+
+#include "bta_hh_api.h"
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bta_hh_int.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hh_reg = {bta_hh_hdl_event, BTA_HhDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_HhEnable
+ *
+ * Description Enable the HID host. This function must be called before
+ * any other functions in the HID host API are called. When the
+ * enable operation is complete the callback function will be
+ * called with BTA_HH_ENABLE_EVT.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK* p_cback) {
+ tBTA_HH_API_ENABLE* p_buf =
+ (tBTA_HH_API_ENABLE*)osi_calloc(sizeof(tBTA_HH_API_ENABLE));
+
+ LOG_INFO(LOG_TAG, "%s sec_mask:0x%x p_cback:%p", __func__, sec_mask, p_cback);
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_HH, &bta_hh_reg);
+
+ p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ p_buf->sec_mask = sec_mask;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhDisable
+ *
+ * Description Disable the HID host. If the server is currently
+ * connected, the connection will be closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ bta_sys_deregister(BTA_ID_HH);
+ p_buf->event = BTA_HH_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhClose
+ *
+ * Description Disconnect a connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhClose(uint8_t dev_handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_HH_API_CLOSE_EVT;
+ p_buf->layer_specific = (uint16_t)dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhOpen
+ *
+ * Description Connect to a device of specified BD address in specified
+ * protocol mode and security level.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode, tBTA_SEC sec_mask) {
+ tBTA_HH_API_CONN* p_buf =
+ (tBTA_HH_API_CONN*)osi_calloc(sizeof(tBTA_HH_API_CONN));
+
+ p_buf->hdr.event = BTA_HH_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+ p_buf->sec_mask = sec_mask;
+ p_buf->mode = mode;
+ bdcpy(p_buf->bd_addr, dev_bda);
+
+ bta_sys_sendmsg((void*)p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_snd_write_dev
+ *
+ ******************************************************************************/
+static void bta_hh_snd_write_dev(uint8_t dev_handle, uint8_t t_type,
+ uint8_t param, uint16_t data, uint8_t rpt_id,
+ BT_HDR* p_data) {
+ tBTA_HH_CMD_DATA* p_buf =
+ (tBTA_HH_CMD_DATA*)osi_calloc(sizeof(tBTA_HH_CMD_DATA));
+
+ p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
+ p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+ p_buf->t_type = t_type;
+ p_buf->data = data;
+ p_buf->param = param;
+ p_buf->p_data = p_data;
+ p_buf->rpt_id = rpt_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhSetReport
+ *
+ * Description send SET_REPORT to device.
+ *
+ * Parameter dev_handle: device handle
+ * r_type: report type, could be BTA_HH_RPTT_OUTPUT or
+ * BTA_HH_RPTT_FEATURE.
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhSetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+ BT_HDR* p_data) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_REPORT, r_type, 0, 0, p_data);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhGetReport
+ *
+ * Description Send a GET_REPORT to HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhGetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+ uint8_t rpt_id, uint16_t buf_size) {
+ uint8_t param = (buf_size) ? (r_type | 0x08) : r_type;
+
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_REPORT, param, buf_size,
+ rpt_id, NULL);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhSetProtoMode
+ *
+ * Description This function set the protocol mode at specified HID handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhSetProtoMode(uint8_t dev_handle, tBTA_HH_PROTO_MODE p_type) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_PROTOCOL, (uint8_t)p_type, 0,
+ 0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhGetProtoMode
+ *
+ * Description This function get protocol mode information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhGetProtoMode(uint8_t dev_handle) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_PROTOCOL, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhSetIdle
+ *
+ * Description send SET_IDLE to device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_SET_IDLE, 0, idle_rate, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetIdle
+ *
+ * Description Send a GET_IDLE from HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhGetIdle(uint8_t dev_handle) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_GET_IDLE, 0, 0, 0, NULL);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhSendCtrl
+ *
+ * Description Send a control command to HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type) {
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_CONTROL, (uint8_t)c_type, 0, 0,
+ NULL);
+}
+/*******************************************************************************
+ *
+ * Function BTA_HhSendData
+ *
+ * Description This function send DATA transaction to HID device.
+ *
+ * Parameter dev_handle: device handle
+ * dev_bda: remote device address
+ * p_data: data to be sent in the DATA transaction; or
+ * the data to be write into the Output Report of a LE
+ * HID device. The report is identified the report ID
+ * which is the value of the byte
+ * (uint8_t *)(p_buf + 1) + *p_buf->offset.
+ * p_data->layer_specific needs to be set to the report
+ * type. It can be OUTPUT report, or FEATURE report.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhSendData(uint8_t dev_handle, UNUSED_ATTR BD_ADDR dev_bda,
+ BT_HDR* p_data) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT) {
+ APPL_TRACE_ERROR(
+ "ERROR! Wrong report type! Write Command only valid for output "
+ "report!");
+ return;
+ }
+#endif
+ bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA,
+ (uint8_t)p_data->layer_specific, 0, 0, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetDscpInfo
+ *
+ * Description Get HID device report descriptor
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhGetDscpInfo(uint8_t dev_handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_calloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_HH_API_GET_DSCP_EVT;
+ p_buf->layer_specific = (uint16_t)dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhAddDev
+ *
+ * Description Add a virtually cabled device into HID-Host device list
+ * to manage and assign a device handle for future API call,
+ * host applciation call this API at start-up to initialize its
+ * virtually cabled devices.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, uint8_t sub_class,
+ uint8_t app_id, tBTA_HH_DEV_DSCP_INFO dscp_info) {
+ size_t len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len;
+ tBTA_HH_MAINT_DEV* p_buf = (tBTA_HH_MAINT_DEV*)osi_calloc(len);
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_ADD_DEV_EVT;
+ p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE;
+
+ p_buf->attr_mask = (uint16_t)attr_mask;
+ p_buf->sub_class = sub_class;
+ p_buf->app_id = app_id;
+ bdcpy(p_buf->bda, bda);
+
+ memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO));
+ if (dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) {
+ p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len;
+ p_buf->dscp_info.descriptor.dsc_list = (uint8_t*)(p_buf + 1);
+ memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list,
+ dscp_info.descriptor.dl_len);
+ } else {
+ p_buf->dscp_info.descriptor.dsc_list = NULL;
+ p_buf->dscp_info.descriptor.dl_len = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HhRemoveDev
+ *
+ * Description Remove a device from the HID host devices list.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhRemoveDev(uint8_t dev_handle) {
+ tBTA_HH_MAINT_DEV* p_buf =
+ (tBTA_HH_MAINT_DEV*)osi_calloc(sizeof(tBTA_HH_MAINT_DEV));
+
+ p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;
+ p_buf->sub_event = BTA_HH_RMV_DEV_EVT;
+ p_buf->hdr.layer_specific = (uint16_t)dev_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/******************************************************************************/
+/* Utility Function */
+/******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_HhParseBootRpt
+ *
+ * Description This utility function parse a boot mode report.
+ * For keyboard report, report data will carry the keycode max
+ * up to 6 key press in one report. Application need to convert
+ * the keycode into keypress character according to keyboard
+ * language.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT* p_data, uint8_t* p_report,
+ uint16_t report_len) {
+ p_data->dev_type = BTA_HH_DEVT_UNKNOWN;
+
+ if (p_report) {
+ /* first byte is report ID */
+ switch (p_report[0]) {
+ case BTA_HH_KEYBD_RPT_ID: /* key board report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_keybd_rpt(p_data, p_report + 1,
+ (uint16_t)(report_len - 1));
+ break;
+
+ case BTA_HH_MOUSE_RPT_ID: /* mouse report ID */
+ p_data->dev_type = p_report[0];
+ bta_hh_parse_mice_rpt(p_data, p_report + 1, (uint16_t)(report_len - 1));
+ break;
+
+ default:
+ APPL_TRACE_DEBUG("Unknown boot report: %d", p_report[0]);
+ ;
+ break;
+ }
+ }
+
+ return;
+}
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_cfg.cc b/mtkbt/code/bt/bta/hh/bta_hh_cfg.cc
new file mode 100755
index 0000000..9479e8b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_cfg.cc
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for the BTA Hid
+ * Host.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bta_hh_api.h"
+
+/* max number of device types supported by BTA */
+#define BTA_HH_MAX_DEVT_SPT 9
+
+/* size of database for service discovery */
+#ifndef BTA_HH_DISC_BUF_SIZE
+#define BTA_HH_DISC_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* The type of devices supported by BTA HH and corresponding application ID */
+tBTA_HH_SPT_TOD p_devt_list[BTA_HH_MAX_DEVT_SPT] = {
+ {BTA_HH_DEVT_MIC, BTA_HH_APP_ID_MI},
+ {BTA_HH_DEVT_KBD, BTA_HH_APP_ID_KB},
+ {BTA_HH_DEVT_KBD | BTA_HH_DEVT_MIC, BTA_HH_APP_ID_KB},
+ {BTA_HH_DEVT_RMC, BTA_HH_APP_ID_RMC},
+ {BTA_HH_DEVT_RMC | BTA_HH_DEVT_KBD, BTA_HH_APP_ID_RMC},
+ {BTA_HH_DEVT_MIC | BTA_HH_DEVT_DGT, BTA_HH_APP_ID_MI},
+ {BTA_HH_DEVT_JOS, BTA_HH_APP_ID_JOY},
+ {BTA_HH_DEVT_GPD, BTA_HH_APP_ID_GPAD},
+ {BTA_HH_DEVT_UNKNOWN, BTA_HH_APP_ID_3DSG}};
+
+const tBTA_HH_CFG bta_hh_cfg = {
+ BTA_HH_MAX_DEVT_SPT, /* number of supported type of devices */
+ p_devt_list, /* ToD & AppID list */
+ BTA_HH_DISC_BUF_SIZE /* HH SDP discovery database size */
+};
+
+tBTA_HH_CFG* p_bta_hh_cfg = (tBTA_HH_CFG*)&bta_hh_cfg;
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_int.h b/mtkbt/code/bt/bta/hh/bta_hh_int.h
new file mode 100755
index 0000000..e5c9b13
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_int.h
@@ -0,0 +1,396 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains BTA HID Host internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef BTA_HH_INT_H
+#define BTA_HH_INT_H
+
+#include "bta_hh_api.h"
+#include "bta_sys.h"
+#include "utl.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "bta_gatt_api.h"
+#endif
+
+/* can be moved to bta_api.h */
+#define BTA_HH_MAX_RPT_CHARS 8
+
+/* state machine events, these events are handled by the state machine */
+enum {
+ BTA_HH_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HH),
+ BTA_HH_API_CLOSE_EVT,
+ BTA_HH_INT_OPEN_EVT,
+ BTA_HH_INT_CLOSE_EVT,
+ BTA_HH_INT_DATA_EVT,
+ BTA_HH_INT_CTRL_DATA,
+ BTA_HH_INT_HANDSK_EVT,
+ BTA_HH_SDP_CMPL_EVT,
+ BTA_HH_API_WRITE_DEV_EVT,
+ BTA_HH_API_GET_DSCP_EVT,
+ BTA_HH_API_MAINT_DEV_EVT,
+ BTA_HH_OPEN_CMPL_EVT,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ BTA_HH_GATT_CLOSE_EVT,
+ BTA_HH_GATT_OPEN_EVT,
+ BTA_HH_START_ENC_EVT,
+ BTA_HH_ENC_CMPL_EVT,
+ BTA_HH_GATT_ENC_CMPL_EVT,
+#endif
+
+ /* not handled by execute state machine */
+ BTA_HH_API_ENABLE_EVT,
+ BTA_HH_API_DISABLE_EVT,
+ BTA_HH_DISC_CMPL_EVT
+};
+typedef uint16_t tBTA_HH_INT_EVT; /* HID host internal events */
+
+#define BTA_HH_INVALID_EVT (BTA_HH_DISC_CMPL_EVT + 1)
+
+/* event used to map between BTE event and BTA event */
+#define BTA_HH_FST_TRANS_CB_EVT BTA_HH_GET_RPT_EVT
+#define BTA_HH_FST_BTE_TRANS_EVT HID_TRANS_GET_REPORT
+
+/* sub event code used for device maintainence API call */
+#define BTA_HH_ADD_DEV 0
+#define BTA_HH_REMOVE_DEV 1
+
+/* state machine states */
+enum {
+ BTA_HH_NULL_ST,
+ BTA_HH_IDLE_ST,
+ BTA_HH_W4_CONN_ST,
+ BTA_HH_CONN_ST
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ ,
+ BTA_HH_W4_SEC
+#endif
+ ,
+ BTA_HH_INVALID_ST /* Used to check invalid states before executing SM function
+ */
+
+};
+typedef uint8_t tBTA_HH_STATE;
+
+/* data structure used to send a command/data to HID device */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t t_type;
+ uint8_t param;
+ uint8_t rpt_id;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ uint8_t srvc_id;
+#endif
+ uint16_t data;
+ BT_HDR* p_data;
+} tBTA_HH_CMD_DATA;
+
+/* data type for BTA_HH_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t sec_mask;
+ uint8_t service_name[BTA_SERVICE_NAME_LEN + 1];
+ tBTA_HH_CBACK* p_cback;
+} tBTA_HH_API_ENABLE;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ uint8_t sec_mask;
+ tBTA_HH_PROTO_MODE mode;
+} tBTA_HH_API_CONN;
+
+/* internal event data from BTE HID callback */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR addr;
+ uint32_t data;
+ BT_HDR* p_data;
+} tBTA_HH_CBACK_DATA;
+
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bda;
+ uint16_t attr_mask;
+ uint16_t sub_event;
+ uint8_t sub_class;
+ uint8_t app_id;
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+} tBTA_HH_MAINT_DEV;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+typedef struct {
+ BT_HDR hdr;
+ uint16_t conn_id;
+ tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
+ event is reported */
+
+} tBTA_HH_LE_CLOSE;
+
+typedef struct {
+ BT_HDR hdr;
+ uint16_t scan_int;
+ uint16_t scan_win;
+} tBTA_HH_SCPP_UPDATE;
+#endif
+/* union of all event data types */
+typedef union {
+ BT_HDR hdr;
+ tBTA_HH_API_ENABLE api_enable;
+ tBTA_HH_API_CONN api_conn;
+ tBTA_HH_CMD_DATA api_sndcmd;
+ tBTA_HH_CBACK_DATA hid_cback;
+ tBTA_HH_STATUS status;
+ tBTA_HH_MAINT_DEV api_maintdev;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ tBTA_HH_LE_CLOSE le_close;
+ tBTA_GATTC_OPEN le_open;
+ tBTA_HH_SCPP_UPDATE le_scpp_update;
+ tBTA_GATTC_ENC_CMPL_CB le_enc_cmpl;
+#endif
+} tBTA_HH_DATA;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+typedef struct {
+ uint8_t index;
+ bool in_use;
+ uint8_t srvc_inst_id;
+ uint8_t char_inst_id;
+ tBTA_HH_RPT_TYPE rpt_type;
+ uint16_t uuid;
+ uint8_t rpt_id;
+ bool client_cfg_exist;
+ uint16_t client_cfg_value;
+} tBTA_HH_LE_RPT;
+
+#ifndef BTA_HH_LE_RPT_MAX
+#define BTA_HH_LE_RPT_MAX 20
+#endif
+
+typedef struct {
+ bool in_use;
+ uint8_t srvc_inst_id;
+ tBTA_HH_LE_RPT report[BTA_HH_LE_RPT_MAX];
+
+ uint16_t proto_mode_handle;
+ uint8_t control_point_handle;
+
+ uint8_t
+ incl_srvc_inst; /* assuming only one included service : battery service */
+ uint8_t cur_expl_char_idx; /* currently discovering service index */
+ uint8_t* rpt_map;
+ uint16_t ext_rpt_ref;
+ tBTA_HH_DEV_DESCR descriptor;
+
+} tBTA_HH_LE_HID_SRVC;
+
+/* convert a HID handle to the LE CB index */
+#define BTA_HH_GET_LE_CB_IDX(x) (((x) >> 4) - 1)
+/* convert a GATT connection ID to HID device handle, it is the hi 4 bits of a
+ * uint8_t */
+#define BTA_HH_GET_LE_DEV_HDL(x) (uint8_t)(((x) + 1) << 4)
+/* check to see if th edevice handle is a LE device handle */
+#define BTA_HH_IS_LE_DEV_HDL(x) ((x)&0xf0)
+#define BTA_HH_IS_LE_DEV_HDL_VALID(x) (((x) >> 4) <= BTA_HH_LE_MAX_KNOWN)
+#endif
+
+/* device control block */
+typedef struct {
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* report descriptor and DI information */
+ BD_ADDR addr; /* BD-Addr of the HID device */
+ uint16_t attr_mask; /* attribute mask */
+ uint16_t w4_evt; /* W4_handshake event name */
+ uint8_t index; /* index number referenced to handle index */
+ uint8_t sub_class; /* Cod sub class */
+ uint8_t sec_mask; /* security mask */
+ uint8_t app_id; /* application ID for this connection */
+ uint8_t hid_handle; /* device handle : low 4 bits for regular HID:
+ HID_HOST_MAX_DEVICES can not exceed 15;
+ high 4 bits for LE HID:
+ GATT_MAX_PHY_CHANNEL can not exceed 15 */
+ bool vp; /* virtually unplug flag */
+ bool in_use; /* control block currently in use */
+ bool incoming_conn; /* is incoming connection? */
+ uint8_t incoming_hid_handle; /* temporary handle for incoming connection? */
+ bool opened; /* true if device successfully opened HID connection */
+ tBTA_HH_PROTO_MODE mode; /* protocol mode */
+ tBTA_HH_STATE state; /* CB state */
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_DISC_NONE 0x00
+#define BTA_HH_LE_DISC_HIDS 0x01
+#define BTA_HH_LE_DISC_DIS 0x02
+#define BTA_HH_LE_DISC_SCPS 0x04
+
+ uint8_t disc_active;
+ tBTA_HH_STATUS status;
+ tBTA_GATT_REASON reason;
+ bool is_le_device;
+ tBTA_HH_LE_HID_SRVC hid_srvc;
+ uint16_t conn_id;
+ bool in_bg_conn;
+ uint8_t clt_cfg_idx;
+ uint16_t scan_refresh_char_handle;
+ bool scps_supported;
+
+#define BTA_HH_LE_SCPS_NOTIFY_NONE 0
+#define BTA_HH_LE_SCPS_NOTIFY_SPT 0x01
+#define BTA_HH_LE_SCPS_NOTIFY_ENB 0x02
+ uint8_t scps_notify; /* scan refresh supported/notification enabled */
+
+ /** M: Bug fix for HOGP connection taking too long time @{ */
+ uint16_t min_conn_int;
+ uint16_t max_conn_int;
+ uint16_t slave_latency;
+ uint16_t supervision_tout;
+ /** @} */
+#endif
+
+ bool security_pending;
+} tBTA_HH_DEV_CB;
+
+/* key board parsing control block */
+typedef struct {
+ bool mod_key[4]; /* ctrl, shift(upper), Alt, GUI */
+ bool num_lock;
+ bool caps_lock;
+ uint8_t last_report[BTA_HH_MAX_RPT_CHARS];
+} tBTA_HH_KB_CB;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+typedef struct {
+ tBTA_HH_KB_CB kb_cb; /* key board control block,
+ suppose BTA will connect
+ to only one keyboard at
+ the same time */
+ tBTA_HH_DEV_CB kdev[BTA_HH_MAX_DEVICE]; /* device control block */
+ tBTA_HH_DEV_CB* p_cur; /* current device control
+ block idx, used in sdp */
+ uint8_t cb_index[BTA_HH_MAX_KNOWN]; /* maintain a CB index
+ map to dev handle */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ uint8_t le_cb_index[BTA_HH_MAX_DEVICE]; /* maintain a CB index map to LE dev
+ handle */
+ tBTA_GATTC_IF gatt_if;
+#endif
+ tBTA_HH_CBACK* p_cback; /* Application callbacks */
+ tSDP_DISCOVERY_DB* p_disc_db;
+ uint8_t trace_level; /* tracing level */
+ uint8_t cnt_num; /* connected device number */
+ bool w4_disable; /* w4 disable flag */
+} tBTA_HH_CB;
+
+extern tBTA_HH_CB bta_hh_cb;
+
+/* from bta_hh_cfg.c */
+extern tBTA_HH_CFG* p_bta_hh_cfg;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+extern bool bta_hh_hdl_event(BT_HDR* p_msg);
+extern void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
+ tBTA_HH_DATA* p_data);
+
+/* action functions */
+extern void bta_hh_api_disc_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_close_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_start_sdp(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_sdp_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_get_dscp_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_maint_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_cmpl_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_open_failure(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+/**M: HID device reconnect fail for collision@{*/
+extern void bta_hh_open_collision_failure(tBTA_HH_DEV_CB *p_cb, uint32_t data);
+extern void bta_hh_collision_cback (tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+/**@}*/
+
+
+/* utility functions */
+extern uint8_t bta_hh_find_cb(BD_ADDR bda);
+extern void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
+ uint8_t* p_report, uint16_t report_len);
+extern void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_kb_data,
+ uint8_t* p_report, uint16_t report_len);
+extern bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class);
+extern void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb);
+
+extern void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
+ uint16_t attr_mask,
+ tHID_DEV_DSCP_INFO* p_dscp_info,
+ uint8_t sub_class, uint16_t max_latency,
+ uint16_t min_tout, uint8_t app_id);
+extern void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
+ uint16_t product_id, uint16_t version,
+ uint8_t flag);
+extern void bta_hh_cleanup_disable(tBTA_HH_STATUS status);
+
+extern uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle);
+
+/* action functions used outside state machine */
+extern void bta_hh_api_enable(tBTA_HH_DATA* p_data);
+extern void bta_hh_api_disable(void);
+extern void bta_hh_disc_cmpl(void);
+
+extern tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr,
+ uint16_t* p_max_ssr_lat,
+ uint16_t* p_min_ssr_tout);
+
+/* functions for LE HID */
+extern void bta_hh_le_enable(void);
+extern bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if);
+extern void bta_hh_le_deregister(void);
+extern bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda);
+extern void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_MAINT_DEV* p_dev_info);
+extern void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_cb);
+extern void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_start_srvc_discovery(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_DATA* p_buf);
+extern void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+extern void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_DATA* p_data);
+extern void bta_hh_ci_load_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf);
+
+#if (BTA_HH_DEBUG == TRUE)
+extern void bta_hh_trace_dev_db(void);
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_le.cc b/mtkbt/code/bt/bta/hh/bta_hh_le.cc
new file mode 100755
index 0000000..7bf66ea
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_le.cc
@@ -0,0 +1,2438 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_hh"
+
+#include "bta_api.h"
+#include "bta_hh_int.h"
+#include "osi/include/osi.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "bta_gatt_api.h"
+#include "bta_hh_co.h"
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "device/include/interop.h"
+#include "osi/include/log.h"
+#include "srvc_api.h"
+#include "stack/include/l2c_api.h"
+#include "utl.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+#include "bta_dm_int.h"
+#endif
+#endif
+
+using std::vector;
+
+#ifndef BTA_HH_LE_RECONN
+#define BTA_HH_LE_RECONN TRUE
+#endif
+
+#define BTA_HH_APP_ID_LE 0xff
+
+#define BTA_HH_LE_RPT_TYPE_VALID(x) \
+ ((x) <= BTA_LE_HID_RPT_FEATURE && (x) >= BTA_LE_HID_RPT_INPUT)
+
+#define BTA_HH_LE_PROTO_BOOT_MODE 0x00
+#define BTA_HH_LE_PROTO_REPORT_MODE 0x01
+
+#define BTA_LE_HID_RTP_UUID_MAX 5
+static const uint16_t bta_hh_uuid_to_rtp_type[BTA_LE_HID_RTP_UUID_MAX][2] = {
+ {GATT_UUID_HID_REPORT, BTA_HH_RPTT_INPUT},
+ {GATT_UUID_HID_BT_KB_INPUT, BTA_HH_RPTT_INPUT},
+ {GATT_UUID_HID_BT_KB_OUTPUT, BTA_HH_RPTT_OUTPUT},
+ {GATT_UUID_HID_BT_MOUSE_INPUT, BTA_HH_RPTT_INPUT},
+ {GATT_UUID_BATTERY_LEVEL, BTA_HH_RPTT_INPUT}};
+
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond);
+// TODO(jpawlowski): uncomment when fixed
+// static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb,
+// tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache,
+// uint8_t num_rpt);
+
+#define GATT_READ_CHAR 0
+#define GATT_READ_DESC 1
+#define GATT_WRITE_CHAR 2
+#define GATT_WRITE_DESC 3
+
+/* Holds pending GATT operations */
+struct gatt_operation {
+ uint8_t type;
+ uint16_t handle;
+ GATT_READ_OP_CB read_cb;
+ void* read_cb_data;
+ GATT_WRITE_OP_CB write_cb;
+ void* write_cb_data;
+
+ /* write-specific fields */
+ tBTA_GATTC_WRITE_TYPE write_type;
+ vector<uint8_t> value;
+};
+
+// maps connection id to operations waiting for execution
+static std::unordered_map<uint16_t, std::list<gatt_operation>> gatt_op_queue;
+// contain connection ids that currently execute operations
+static std::unordered_set<uint16_t> gatt_op_queue_executing;
+
+static void mark_as_not_executing(uint16_t conn_id) {
+ gatt_op_queue_executing.erase(conn_id);
+}
+
+static void gatt_op_queue_clean(uint16_t conn_id) {
+ gatt_op_queue.erase(conn_id);
+ gatt_op_queue_executing.erase(conn_id);
+}
+
+static void gatt_execute_next_op(uint16_t conn_id);
+GATT_READ_OP_CB act_read_cb = NULL;
+void* act_read_cb_data = NULL;
+static void gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ GATT_READ_OP_CB tmp_cb = act_read_cb;
+ void* tmp_cb_data = act_read_cb_data;
+
+ act_read_cb = NULL;
+ act_read_cb_data = NULL;
+
+ mark_as_not_executing(conn_id);
+ gatt_execute_next_op(conn_id);
+
+ if (tmp_cb) {
+ tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
+ return;
+ }
+}
+
+GATT_WRITE_OP_CB act_write_cb = NULL;
+void* act_write_cb_data = NULL;
+static void gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ GATT_WRITE_OP_CB tmp_cb = act_write_cb;
+ void* tmp_cb_data = act_write_cb_data;
+ act_write_cb = NULL;
+ act_write_cb_data = NULL;
+
+ mark_as_not_executing(conn_id);
+ gatt_execute_next_op(conn_id);
+
+ if (tmp_cb) {
+ tmp_cb(conn_id, status, handle, tmp_cb_data);
+ return;
+ }
+}
+
+static void gatt_execute_next_op(uint16_t conn_id) {
+ APPL_TRACE_DEBUG("%s:", __func__, conn_id);
+ if (gatt_op_queue.empty()) {
+ APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
+ return;
+ }
+
+ auto map_ptr = gatt_op_queue.find(conn_id);
+ if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
+ APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
+ conn_id);
+ return;
+ }
+
+ if (gatt_op_queue_executing.count(conn_id)) {
+ APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
+ return;
+ }
+
+ gatt_op_queue_executing.insert(conn_id);
+
+ std::list<gatt_operation>& gatt_ops = map_ptr->second;
+
+ gatt_operation& op = gatt_ops.front();
+
+ if (op.type == GATT_READ_CHAR) {
+ act_read_cb = op.read_cb;
+ act_read_cb_data = op.read_cb_data;
+ BTA_GATTC_ReadCharacteristic(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
+ gatt_read_op_finished, NULL);
+
+ } else if (op.type == GATT_READ_DESC) {
+ act_read_cb = op.read_cb;
+ act_read_cb_data = op.read_cb_data;
+ BTA_GATTC_ReadCharDescr(conn_id, op.handle, BTA_GATT_AUTH_REQ_NONE,
+ gatt_read_op_finished, NULL);
+
+ } else if (op.type == GATT_WRITE_CHAR) {
+ act_write_cb = op.write_cb;
+ act_write_cb_data = op.write_cb_data;
+ BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
+ std::move(op.value), BTA_GATT_AUTH_REQ_NONE,
+ gatt_write_op_finished, NULL);
+
+ } else if (op.type == GATT_WRITE_DESC) {
+ act_write_cb = op.write_cb;
+ act_write_cb_data = op.write_cb_data;
+ BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
+ BTA_GATT_AUTH_REQ_NONE, gatt_write_op_finished,
+ NULL);
+ }
+
+ gatt_ops.pop_front();
+}
+
+static void gatt_queue_read_op(uint8_t op_type, uint16_t conn_id,
+ uint16_t handle, GATT_READ_OP_CB cb,
+ void* cb_data) {
+ gatt_operation op;
+ op.type = op_type;
+ op.handle = handle;
+ op.read_cb = cb;
+ op.read_cb_data = cb_data;
+ gatt_op_queue[conn_id].push_back(op);
+ gatt_execute_next_op(conn_id);
+}
+
+static void gatt_queue_write_op(uint8_t op_type, uint16_t conn_id,
+ uint16_t handle, vector<uint8_t> value,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ GATT_WRITE_OP_CB cb, void* cb_data) {
+ gatt_operation op;
+ op.type = op_type;
+ op.handle = handle;
+ op.write_type = write_type;
+ op.write_cb = cb;
+ op.write_cb_data = cb_data;
+ op.value = std::move(value);
+
+ gatt_op_queue[conn_id].push_back(op);
+ gatt_execute_next_op(conn_id);
+}
+
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_le_rpt_name[4] = {"UNKNOWN", "INPUT", "OUTPUT",
+ "FEATURE"};
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_hid_report_dbg
+ *
+ * Description debug function to print out all HID report available on
+ * remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hh_le_hid_report_dbg(tBTA_HH_DEV_CB* p_cb) {
+ APPL_TRACE_DEBUG("%s: HID Report DB", __func__);
+
+ if (!p_cb->hid_srvc.in_use) return;
+
+ tBTA_HH_LE_RPT* p_rpt = &p_cb->hid_srvc.report[0];
+
+ for (int j = 0; j < BTA_HH_LE_RPT_MAX; j++, p_rpt++) {
+ const char* rpt_name = "Unknown";
+
+ if (!p_rpt->in_use) break;
+
+ if (p_rpt->uuid == GATT_UUID_HID_REPORT) rpt_name = "Report";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT) rpt_name = "Boot KB Input";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_KB_OUTPUT) rpt_name = "Boot KB Output";
+ if (p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) rpt_name = "Boot MI Input";
+
+ APPL_TRACE_DEBUG(
+ "\t\t [%s- 0x%04x] [Type: %s], [ReportID: %d] [srvc_inst_id: %d] "
+ "[char_inst_id: %d] [Clt_cfg: %d]",
+ rpt_name, p_rpt->uuid,
+ ((p_rpt->rpt_type < 4) ? bta_hh_le_rpt_name[p_rpt->rpt_type]
+ : "UNKNOWN"),
+ p_rpt->rpt_id, p_rpt->srvc_inst_id, p_rpt->char_inst_id,
+ p_rpt->client_cfg_value);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_uuid_to_str
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static const char* bta_hh_uuid_to_str(uint16_t uuid) {
+ switch (uuid) {
+ case GATT_UUID_HID_INFORMATION:
+ return "GATT_UUID_HID_INFORMATION";
+ case GATT_UUID_HID_REPORT_MAP:
+ return "GATT_UUID_HID_REPORT_MAP";
+ case GATT_UUID_HID_CONTROL_POINT:
+ return "GATT_UUID_HID_CONTROL_POINT";
+ case GATT_UUID_HID_REPORT:
+ return "GATT_UUID_HID_REPORT";
+ case GATT_UUID_HID_PROTO_MODE:
+ return "GATT_UUID_HID_PROTO_MODE";
+ case GATT_UUID_HID_BT_KB_INPUT:
+ return "GATT_UUID_HID_BT_KB_INPUT";
+ case GATT_UUID_HID_BT_KB_OUTPUT:
+ return "GATT_UUID_HID_BT_KB_OUTPUT";
+ case GATT_UUID_HID_BT_MOUSE_INPUT:
+ return "GATT_UUID_HID_BT_MOUSE_INPUT";
+ case GATT_UUID_CHAR_CLIENT_CONFIG:
+ return "GATT_UUID_CHAR_CLIENT_CONFIG";
+ case GATT_UUID_EXT_RPT_REF_DESCR:
+ return "GATT_UUID_EXT_RPT_REF_DESCR";
+ case GATT_UUID_RPT_REF_DESCR:
+ return "GATT_UUID_RPT_REF_DESCR";
+ default:
+ return "Unknown UUID";
+ }
+}
+
+#endif
+/*******************************************************************************
+ *
+ * Function bta_hh_le_enable
+ *
+ * Description initialize LE HID related functionality
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_enable(void) {
+ uint8_t xx;
+
+ bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++)
+ bta_hh_cb.le_cb_index[xx] = BTA_HH_IDX_INVALID;
+
+ BTA_GATTC_AppRegister(bta_hh_gattc_callback,
+ base::Bind([](uint8_t client_id, uint8_t r_status) {
+ tBTA_HH_STATUS status = BTA_HH_ERR;
+
+ if (r_status == BTA_GATT_OK) {
+ bta_hh_cb.gatt_if = client_id;
+ status = BTA_HH_OK;
+ } else
+ bta_hh_cb.gatt_if = BTA_GATTS_INVALID_IF;
+
+ /* signal BTA call back event */
+ (*bta_hh_cb.p_cback)(BTA_HH_ENABLE_EVT,
+ (tBTA_HH*)&status);
+ }));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_is_hh_gatt_if
+ *
+ * Description Check to see if client_if is BTA HH LE GATT interface
+ *
+ *
+ * Returns whether it is HH GATT IF
+ *
+ ******************************************************************************/
+bool bta_hh_le_is_hh_gatt_if(tBTA_GATTC_IF client_if) {
+ return (bta_hh_cb.gatt_if == client_if);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_deregister
+ *
+ * Description De-register BTA HH from BTA GATTC
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_deregister(void) { BTA_GATTC_AppDeregister(bta_hh_cb.gatt_if); }
+
+/*******************************************************************************
+ *
+ * Function bta_hh_is_le_device
+ *
+ * Description Check to see if the remote device is a LE only device
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+bool bta_hh_is_le_device(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda) {
+ p_cb->is_le_device = BTM_UseLeLink(remote_bda);
+
+ return p_cb->is_le_device;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_open_conn
+ *
+ * Description open a GATT connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_open_conn(tBTA_HH_DEV_CB* p_cb, BD_ADDR remote_bda) {
+ /* update cb_index[] map */
+ p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+ memcpy(p_cb->addr, remote_bda, BD_ADDR_LEN);
+ bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+ p_cb->in_use = true;
+
+ BTA_GATTC_Open(bta_hh_cb.gatt_if, remote_bda, true, BTA_GATT_TRANSPORT_LE,
+ false);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_dev_cb_by_conn_id
+ *
+ * Description Utility function find a device control block by connection
+ * ID.
+ *
+ ******************************************************************************/
+tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_conn_id(uint16_t conn_id) {
+ uint8_t i;
+ tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0];
+
+ for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) {
+ if (p_dev_cb->in_use && p_dev_cb->conn_id == conn_id) return p_dev_cb;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_dev_cb_by_bda
+ *
+ * Description Utility function find a device control block by BD address.
+ *
+ ******************************************************************************/
+tBTA_HH_DEV_CB* bta_hh_le_find_dev_cb_by_bda(BD_ADDR bda) {
+ uint8_t i;
+ tBTA_HH_DEV_CB* p_dev_cb = &bta_hh_cb.kdev[0];
+
+ for (i = 0; i < BTA_HH_MAX_DEVICE; i++, p_dev_cb++) {
+ if (p_dev_cb->in_use && memcmp(p_dev_cb->addr, bda, BD_ADDR_LEN) == 0)
+ return p_dev_cb;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_service_inst_by_battery_inst_id
+ *
+ * Description find HID service instance ID by battery service instance ID
+ *
+ ******************************************************************************/
+uint8_t bta_hh_le_find_service_inst_by_battery_inst_id(tBTA_HH_DEV_CB* p_cb,
+ uint8_t ba_inst_id) {
+ if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.incl_srvc_inst == ba_inst_id) {
+ return p_cb->hid_srvc.srvc_inst_id;
+ }
+ return BTA_HH_IDX_INVALID;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_report_entry
+ *
+ * Description find the report entry by service instance and report UUID
+ * and instance ID
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_report_entry(
+ tBTA_HH_DEV_CB* p_cb, uint8_t srvc_inst_id, /* service instance ID */
+ uint16_t rpt_uuid, uint8_t char_inst_id) {
+ uint8_t i;
+ uint8_t hid_inst_id = srvc_inst_id;
+ tBTA_HH_LE_RPT* p_rpt;
+
+ if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) {
+ hid_inst_id =
+ bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+ if (hid_inst_id == BTA_HH_IDX_INVALID) return NULL;
+ }
+
+ p_rpt = &p_cb->hid_srvc.report[0];
+
+ for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+ if (p_rpt->uuid == rpt_uuid && p_rpt->srvc_inst_id == srvc_inst_id &&
+ p_rpt->char_inst_id == char_inst_id) {
+ return p_rpt;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_rpt_by_idtype
+ *
+ * Description find a report entry by report ID and protocol mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_rpt_by_idtype(tBTA_HH_LE_RPT* p_head,
+ uint8_t mode,
+ tBTA_HH_RPT_TYPE r_type,
+ uint8_t rpt_id) {
+ tBTA_HH_LE_RPT* p_rpt = p_head;
+ uint8_t i;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_le_find_rpt_by_idtype: r_type: %d rpt_id: %d",
+ r_type, rpt_id);
+#endif
+
+ for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+ if (p_rpt->in_use && p_rpt->rpt_id == rpt_id && r_type == p_rpt->rpt_type) {
+ /* return battery report w/o condition */
+ if (p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) return p_rpt;
+
+ if (mode == BTA_HH_PROTO_RPT_MODE && p_rpt->uuid == GATT_UUID_HID_REPORT)
+ return p_rpt;
+
+ if (mode == BTA_HH_PROTO_BOOT_MODE &&
+ (p_rpt->uuid >= GATT_UUID_HID_BT_KB_INPUT &&
+ p_rpt->uuid <= GATT_UUID_HID_BT_MOUSE_INPUT))
+ return p_rpt;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_find_alloc_report_entry
+ *
+ * Description find or allocate a report entry in the HID service report
+ * list.
+ *
+ ******************************************************************************/
+tBTA_HH_LE_RPT* bta_hh_le_find_alloc_report_entry(tBTA_HH_DEV_CB* p_cb,
+ uint8_t srvc_inst_id,
+ uint16_t rpt_uuid,
+ uint8_t inst_id) {
+ uint8_t i, hid_inst_id = srvc_inst_id;
+ tBTA_HH_LE_RPT* p_rpt;
+
+ if (rpt_uuid == GATT_UUID_BATTERY_LEVEL) {
+ hid_inst_id =
+ bta_hh_le_find_service_inst_by_battery_inst_id(p_cb, srvc_inst_id);
+
+ if (hid_inst_id == BTA_HH_IDX_INVALID) return NULL;
+ }
+ p_rpt = &p_cb->hid_srvc.report[0];
+
+ for (i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+ if (!p_rpt->in_use ||
+ (p_rpt->uuid == rpt_uuid && p_rpt->srvc_inst_id == srvc_inst_id &&
+ p_rpt->char_inst_id == inst_id)) {
+ if (!p_rpt->in_use) {
+ p_rpt->in_use = true;
+ p_rpt->index = i;
+ p_rpt->srvc_inst_id = srvc_inst_id;
+ p_rpt->char_inst_id = inst_id;
+ p_rpt->uuid = rpt_uuid;
+
+ /* assign report type */
+ for (i = 0; i < BTA_LE_HID_RTP_UUID_MAX; i++) {
+ if (bta_hh_uuid_to_rtp_type[i][0] == rpt_uuid) {
+ p_rpt->rpt_type = (tBTA_HH_RPT_TYPE)bta_hh_uuid_to_rtp_type[i][1];
+
+ if (rpt_uuid == GATT_UUID_HID_BT_KB_INPUT ||
+ rpt_uuid == GATT_UUID_HID_BT_KB_OUTPUT)
+ p_rpt->rpt_id = BTA_HH_KEYBD_RPT_ID;
+
+ if (rpt_uuid == GATT_UUID_HID_BT_MOUSE_INPUT)
+ p_rpt->rpt_id = BTA_HH_MOUSE_RPT_ID;
+
+ break;
+ }
+ }
+ }
+ return p_rpt;
+ }
+ }
+ return NULL;
+}
+
+static tBTA_GATTC_DESCRIPTOR* find_descriptor_by_short_uuid(
+ uint16_t conn_id, uint16_t char_handle, uint16_t short_uuid) {
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ BTA_GATTC_GetCharacteristic(conn_id, char_handle);
+
+ if (!p_char) {
+ LOG_WARN(LOG_TAG, "%s No such characteristic: %d", __func__, char_handle);
+ return NULL;
+ }
+
+ if (!p_char->descriptors || list_is_empty(p_char->descriptors)) return NULL;
+
+ for (list_node_t* dn = list_begin(p_char->descriptors);
+ dn != list_end(p_char->descriptors); dn = list_next(dn)) {
+ tBTA_GATTC_DESCRIPTOR* p_desc = (tBTA_GATTC_DESCRIPTOR*)list_node(dn);
+
+ if (p_char->uuid.len == LEN_UUID_16 && p_desc->uuid.uu.uuid16 == short_uuid)
+ return p_desc;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_read_char_descriptor
+ *
+ * Description read characteristic descriptor
+ *
+ ******************************************************************************/
+static tBTA_HH_STATUS bta_hh_le_read_char_descriptor(tBTA_HH_DEV_CB* p_cb,
+ uint16_t char_handle,
+ uint16_t short_uuid,
+ GATT_READ_OP_CB cb,
+ void* cb_data) {
+ const tBTA_GATTC_DESCRIPTOR* p_desc =
+ find_descriptor_by_short_uuid(p_cb->conn_id, char_handle, short_uuid);
+ if (!p_desc) return BTA_HH_ERR;
+
+ gatt_queue_read_op(GATT_READ_DESC, p_cb->conn_id, p_desc->handle, cb,
+ cb_data);
+ return BTA_HH_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_save_report_ref
+ *
+ * Description save report reference information and move to next one.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_save_report_ref(tBTA_HH_DEV_CB* p_dev_cb, tBTA_HH_LE_RPT* p_rpt,
+ tGATT_STATUS status, uint8_t* value,
+ uint16_t len) {
+ if (status == BTA_GATT_INSUF_AUTHENTICATION) {
+ /* close connection right away */
+ p_dev_cb->status = BTA_HH_ERR_AUTH_FAILED;
+ /* close the connection and report service discovery complete with error */
+ bta_hh_le_api_disc_act(p_dev_cb);
+ return;
+ }
+
+ /* if the length of the descriptor value is right, parse it */
+ if (status == BTA_GATT_OK && len == 2) {
+ uint8_t* pp = value;
+
+ STREAM_TO_UINT8(p_rpt->rpt_id, pp);
+ STREAM_TO_UINT8(p_rpt->rpt_type, pp);
+
+ if (p_rpt->rpt_type > BTA_HH_RPTT_FEATURE) /* invalid report type */
+ p_rpt->rpt_type = BTA_HH_RPTT_RESRV;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: report ID: %d", __func__, p_rpt->rpt_id);
+#endif
+ tBTA_HH_RPT_CACHE_ENTRY rpt_entry;
+ rpt_entry.rpt_id = p_rpt->rpt_id;
+ rpt_entry.rpt_type = p_rpt->rpt_type;
+ rpt_entry.rpt_uuid = p_rpt->uuid;
+ rpt_entry.srvc_inst_id = p_rpt->srvc_inst_id;
+ rpt_entry.char_inst_id = p_rpt->char_inst_id;
+
+ bta_hh_le_co_rpt_info(p_dev_cb->addr, &rpt_entry, p_dev_cb->app_id);
+ }
+
+ if (p_rpt->index < BTA_HH_LE_RPT_MAX - 1)
+ p_rpt++;
+ else
+ p_rpt = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_register_input_notif
+ *
+ * Description Register for all notifications for the report applicable
+ * for the protocol mode.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_register_input_notif(tBTA_HH_DEV_CB* p_dev_cb,
+ uint8_t proto_mode, bool register_ba) {
+ tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0];
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: bta_hh_le_register_input_notif mode: %d", __func__,
+ proto_mode);
+#endif
+
+ for (int i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+ if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+ if (register_ba && p_rpt->uuid == GATT_UUID_BATTERY_LEVEL) {
+ BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+ p_rpt->char_inst_id);
+ }
+ /* boot mode, deregister report input notification */
+ else if (proto_mode == BTA_HH_PROTO_BOOT_MODE) {
+ if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+ p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+ APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_DeregisterForNotifications(
+ bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id);
+ }
+ /* register boot reports notification */
+ else if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+ p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) {
+ APPL_TRACE_DEBUG("%s <--- Register Boot Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+ p_rpt->char_inst_id);
+ }
+ } else if (proto_mode == BTA_HH_PROTO_RPT_MODE) {
+ if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+ p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
+ p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+ APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_DeregisterForNotifications(
+ bta_hh_cb.gatt_if, p_dev_cb->addr, p_rpt->char_inst_id);
+ } else if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+ p_rpt->client_cfg_value ==
+ BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+ APPL_TRACE_DEBUG("%s <--- Register Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_RegisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+ p_rpt->char_inst_id);
+ }
+ }
+ /*
+ else unknow protocol mode */
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_deregister_input_notif
+ *
+ * Description Deregister all notifications
+ *
+ ******************************************************************************/
+void bta_hh_le_deregister_input_notif(tBTA_HH_DEV_CB* p_dev_cb) {
+ tBTA_HH_LE_RPT* p_rpt = &p_dev_cb->hid_srvc.report[0];
+
+ for (uint8_t i = 0; i < BTA_HH_LE_RPT_MAX; i++, p_rpt++) {
+ if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+ if (p_rpt->uuid == GATT_UUID_HID_REPORT &&
+ p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+ APPL_TRACE_DEBUG("%s ---> Deregister Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+ p_rpt->char_inst_id);
+ } else if ((p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+ p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT) &&
+ p_rpt->client_cfg_value == BTA_GATT_CLT_CONFIG_NOTIFICATION) {
+ APPL_TRACE_DEBUG("%s ---> Deregister Boot Report ID: %d", __func__,
+ p_rpt->rpt_id);
+ BTA_GATTC_DeregisterForNotifications(bta_hh_cb.gatt_if, p_dev_cb->addr,
+ p_rpt->char_inst_id);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_open_cmpl
+ *
+ * Description HID over GATT connection sucessfully opened
+ *
+ ******************************************************************************/
+void bta_hh_le_open_cmpl(tBTA_HH_DEV_CB* p_cb) {
+ if (p_cb->disc_active == BTA_HH_LE_DISC_NONE) {
+#if (BTA_HH_DEBUG == TRUE)
+ bta_hh_le_hid_report_dbg(p_cb);
+#endif
+ bta_hh_le_register_input_notif(p_cb, p_cb->mode, true);
+ bta_hh_sm_execute(p_cb, BTA_HH_OPEN_CMPL_EVT, NULL);
+
+ /** M: Bug fix for HOGP connection taking too long time @{ */
+ if (BTM_BLE_ISVALID_PARAM(p_cb->min_conn_int, BTM_BLE_CONN_INT_MIN,
+ BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(p_cb->max_conn_int, BTM_BLE_CONN_INT_MIN,
+ BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(p_cb->supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN,
+ BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ (p_cb->slave_latency <= BTM_BLE_CONN_LATENCY_MAX) &&
+ (p_cb->min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) &&
+ (p_cb->max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)) {
+ L2CA_UpdateBleConnParams(p_cb->addr, p_cb->min_conn_int,
+ p_cb->max_conn_int, p_cb->slave_latency,
+ p_cb->supervision_tout);
+ }
+ /** @} */
+
+#if (BTA_HH_LE_RECONN == TRUE)
+ if (p_cb->status == BTA_HH_OK) {
+ bta_hh_le_add_dev_bg_conn(p_cb, true);
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_write_ccc
+ *
+ * Description Utility function to find and write client configuration of
+ * a characteristic
+ *
+ ******************************************************************************/
+bool bta_hh_le_write_ccc(tBTA_HH_DEV_CB* p_cb, uint8_t char_handle,
+ uint16_t clt_cfg_value, GATT_WRITE_OP_CB cb,
+ void* cb_data) {
+ tBTA_GATTC_DESCRIPTOR* p_desc = find_descriptor_by_short_uuid(
+ p_cb->conn_id, char_handle, GATT_UUID_CHAR_CLIENT_CONFIG);
+ if (!p_desc) return false;
+
+ vector<uint8_t> value(2);
+ uint8_t* ptr = value.data();
+ UINT16_TO_STREAM(ptr, clt_cfg_value);
+
+ gatt_queue_write_op(GATT_WRITE_DESC, p_cb->conn_id, p_desc->handle,
+ std::move(value), BTA_GATTC_TYPE_WRITE, cb, cb_data);
+ return true;
+}
+
+bool bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB* p_cb);
+
+static void write_rpt_ctl_cfg_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ uint8_t srvc_inst_id, hid_inst_id;
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ const tBTA_GATTC_DESCRIPTOR* p_desc =
+ BTA_GATTC_GetDescriptor(conn_id, handle);
+
+ uint16_t char_uuid = p_desc->characteristic->uuid.uu.uuid16;
+
+ srvc_inst_id = p_desc->characteristic->service->handle;
+ hid_inst_id = srvc_inst_id;
+ switch (char_uuid) {
+ case GATT_UUID_BATTERY_LEVEL: /* battery level clt cfg registered */
+ hid_inst_id = bta_hh_le_find_service_inst_by_battery_inst_id(
+ p_dev_cb, srvc_inst_id);
+ /* FALLTHROUGH */
+ case GATT_UUID_HID_BT_KB_INPUT:
+ case GATT_UUID_HID_BT_MOUSE_INPUT:
+ case GATT_UUID_HID_REPORT:
+ if (status == BTA_GATT_OK)
+ p_dev_cb->hid_srvc.report[p_dev_cb->clt_cfg_idx].client_cfg_value =
+ BTA_GATT_CLT_CONFIG_NOTIFICATION;
+ p_dev_cb->clt_cfg_idx++;
+ bta_hh_le_write_rpt_clt_cfg(p_dev_cb);
+ break;
+
+ default:
+ APPL_TRACE_ERROR("Unknown char ID clt cfg: 0x%04x", char_uuid);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_le_write_rpt_clt_cfg
+ *
+ * Description write client configuration. This is only for input report
+ * enable all input notification upon connection open.
+ *
+ ******************************************************************************/
+bool bta_hh_le_write_rpt_clt_cfg(tBTA_HH_DEV_CB* p_cb) {
+ uint8_t i;
+ tBTA_HH_LE_RPT* p_rpt = &p_cb->hid_srvc.report[p_cb->clt_cfg_idx];
+
+ for (i = p_cb->clt_cfg_idx; i < BTA_HH_LE_RPT_MAX && p_rpt->in_use;
+ i++, p_rpt++) {
+ /* enable notification for all input report, regardless mode */
+ if (p_rpt->rpt_type == BTA_HH_RPTT_INPUT) {
+ if (bta_hh_le_write_ccc(p_cb, p_rpt->char_inst_id,
+ BTA_GATT_CLT_CONFIG_NOTIFICATION,
+ write_rpt_ctl_cfg_cb, p_cb)) {
+ p_cb->clt_cfg_idx = i;
+ return true;
+ }
+ }
+ }
+ p_cb->clt_cfg_idx = 0;
+
+ /* client configuration is completed, send open callback */
+ if (p_cb->state == BTA_HH_W4_CONN_ST) {
+ p_cb->disc_active &= ~BTA_HH_LE_DISC_HIDS;
+
+ bta_hh_le_open_cmpl(p_cb);
+ }
+ return false;
+}
+
+static void write_proto_mode_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+
+ if (p_dev_cb->state == BTA_HH_CONN_ST) {
+ /* Set protocol finished in CONN state*/
+
+ uint16_t cb_evt = p_dev_cb->w4_evt;
+ if (cb_evt == 0) return;
+
+ tBTA_HH_CBDATA cback_data;
+
+ cback_data.handle = p_dev_cb->hid_handle;
+ cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+
+ if (status == BTA_GATT_OK)
+ bta_hh_le_register_input_notif(p_dev_cb, p_dev_cb->mode, false);
+
+ p_dev_cb->w4_evt = 0;
+ (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
+ } else if (p_dev_cb->state == BTA_HH_W4_CONN_ST) {
+ p_dev_cb->status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+
+ if ((p_dev_cb->disc_active & BTA_HH_LE_DISC_HIDS) == 0)
+ bta_hh_le_open_cmpl(p_dev_cb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_set_protocol_mode
+ *
+ * Description Set remote device protocol mode.
+ *
+ ******************************************************************************/
+bool bta_hh_le_set_protocol_mode(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_PROTO_MODE mode) {
+ tBTA_HH_CBDATA cback_data;
+
+ APPL_TRACE_DEBUG("%s attempt mode: %s", __func__,
+ (mode == BTA_HH_PROTO_RPT_MODE) ? "Report" : "Boot");
+
+ cback_data.handle = p_cb->hid_handle;
+ /* boot mode is not supported in the remote device */
+ if (p_cb->hid_srvc.proto_mode_handle == 0) {
+ p_cb->mode = BTA_HH_PROTO_RPT_MODE;
+
+ if (mode == BTA_HH_PROTO_BOOT_MODE) {
+ APPL_TRACE_ERROR("Set Boot Mode failed!! No PROTO_MODE Char!");
+ cback_data.status = BTA_HH_ERR;
+ } else {
+ /* if set to report mode, need to de-register all input report
+ * notification */
+ bta_hh_le_register_input_notif(p_cb, p_cb->mode, false);
+ cback_data.status = BTA_HH_OK;
+ }
+ if (p_cb->state == BTA_HH_W4_CONN_ST) {
+ p_cb->status =
+ (cback_data.status == BTA_HH_OK) ? BTA_HH_OK : BTA_HH_ERR_PROTO;
+ } else
+ (*bta_hh_cb.p_cback)(BTA_HH_SET_PROTO_EVT, (tBTA_HH*)&cback_data);
+ } else if (p_cb->mode != mode) {
+ p_cb->mode = mode;
+ mode = (mode == BTA_HH_PROTO_BOOT_MODE) ? BTA_HH_LE_PROTO_BOOT_MODE
+ : BTA_HH_LE_PROTO_REPORT_MODE;
+
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
+ p_cb->hid_srvc.proto_mode_handle, {mode},
+ BTA_GATTC_TYPE_WRITE_NO_RSP, write_proto_mode_cb, p_cb);
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ * Function get_protocol_mode_cb
+ *
+ * Description Process the Read protocol mode, send GET_PROTO_EVT to
+ * application with the protocol mode.
+ *
+ ******************************************************************************/
+static void get_protocol_mode_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ tBTA_HH_HSDATA hs_data;
+
+ hs_data.status = BTA_HH_ERR;
+ hs_data.handle = p_dev_cb->hid_handle;
+ hs_data.rsp_data.proto_mode = p_dev_cb->mode;
+
+ if (status == BTA_GATT_OK && len) {
+ hs_data.status = BTA_HH_OK;
+ /* match up BTE/BTA report/boot mode def*/
+ hs_data.rsp_data.proto_mode = *(value);
+ /* LE repot mode is the opposite value of BR/EDR report mode, flip it here
+ */
+ if (hs_data.rsp_data.proto_mode == 0)
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_BOOT_MODE;
+ else
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+
+ p_dev_cb->mode = hs_data.rsp_data.proto_mode;
+ }
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("LE GET_PROTOCOL Mode = [%s]",
+ (hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+ ? "Report"
+ : "Boot");
+#endif
+
+ p_dev_cb->w4_evt = 0;
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_get_protocol_mode
+ *
+ * Description Get remote device protocol mode.
+ *
+ ******************************************************************************/
+void bta_hh_le_get_protocol_mode(tBTA_HH_DEV_CB* p_cb) {
+ tBTA_HH_HSDATA hs_data;
+ p_cb->w4_evt = BTA_HH_GET_PROTO_EVT;
+
+ if (p_cb->hid_srvc.in_use && p_cb->hid_srvc.proto_mode_handle != 0) {
+ gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id,
+ p_cb->hid_srvc.proto_mode_handle, get_protocol_mode_cb,
+ p_cb);
+ return;
+ }
+
+ /* no service support protocol_mode, by default report mode */
+ hs_data.status = BTA_HH_OK;
+ hs_data.handle = p_cb->hid_handle;
+ hs_data.rsp_data.proto_mode = BTA_HH_PROTO_RPT_MODE;
+ p_cb->w4_evt = 0;
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_PROTO_EVT, (tBTA_HH*)&hs_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_dis_cback
+ *
+ * Description DIS read complete callback
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_dis_cback(BD_ADDR addr, tDIS_VALUE* p_dis_value) {
+ tBTA_HH_DEV_CB* p_cb = bta_hh_le_find_dev_cb_by_bda(addr);
+
+ if (p_cb == NULL || p_dis_value == NULL) {
+ APPL_TRACE_ERROR("received unexpected/error DIS callback");
+ return;
+ }
+
+ p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+ /* plug in the PnP info for this device */
+ if (p_dis_value->attr_mask & DIS_ATTR_PNP_ID_BIT) {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "Plug in PnP info: product_id = %02x, vendor_id = %04x, version = %04x",
+ p_dis_value->pnp_id.product_id, p_dis_value->pnp_id.vendor_id,
+ p_dis_value->pnp_id.product_version);
+#endif
+ p_cb->dscp_info.product_id = p_dis_value->pnp_id.product_id;
+ p_cb->dscp_info.vendor_id = p_dis_value->pnp_id.vendor_id;
+ p_cb->dscp_info.version = p_dis_value->pnp_id.product_version;
+ }
+ bta_hh_le_open_cmpl(p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_pri_service_discovery
+ *
+ * Description Initialize GATT discovery on the remote LE HID device by
+ * opening a GATT connection first.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_pri_service_discovery(tBTA_HH_DEV_CB* p_cb) {
+ tBT_UUID pri_srvc;
+
+ bta_hh_le_co_reset_rpt_cache(p_cb->addr, p_cb->app_id);
+
+ p_cb->disc_active |= (BTA_HH_LE_DISC_HIDS | BTA_HH_LE_DISC_DIS);
+
+ /* read DIS info */
+ if (!DIS_ReadDISInfo(p_cb->addr, bta_hh_le_dis_cback, DIS_ATTR_PNP_ID_BIT)) {
+ APPL_TRACE_ERROR("read DIS failed");
+ p_cb->disc_active &= ~BTA_HH_LE_DISC_DIS;
+ }
+
+ /* in parallel */
+ /* start primary service discovery for HID service */
+ pri_srvc.len = LEN_UUID_16;
+ pri_srvc.uu.uuid16 = UUID_SERVCLASS_LE_HID;
+ BTA_GATTC_ServiceSearchRequest(p_cb->conn_id, &pri_srvc);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_encrypt_cback
+ *
+ * Description link encryption complete callback for bond verification.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hh_le_encrypt_cback(BD_ADDR bd_addr,
+ UNUSED_ATTR tBTA_GATT_TRANSPORT transport,
+ UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
+ uint8_t idx = bta_hh_find_cb(bd_addr);
+ tBTA_HH_DEV_CB* p_dev_cb;
+
+ if (idx != BTA_HH_IDX_INVALID)
+ p_dev_cb = &bta_hh_cb.kdev[idx];
+ else {
+ APPL_TRACE_ERROR("unexpected encryption callback, ignore");
+ return;
+ }
+ p_dev_cb->status = (result == BTM_SUCCESS) ? BTA_HH_OK : BTA_HH_ERR_SEC;
+ p_dev_cb->reason = result;
+
+ bta_hh_sm_execute(p_dev_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_security_cmpl
+ *
+ * Description Security check completed, start the service discovery
+ * if no cache available, otherwise report connection open
+ * completed
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_security_cmpl(tBTA_HH_DEV_CB* p_cb,
+ UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ if (p_cb->status == BTA_HH_OK) {
+ if (!p_cb->hid_srvc.in_use) {
+ APPL_TRACE_DEBUG("bta_hh_security_cmpl no reports loaded, try to load");
+
+ /* start loading the cache if not in stack */
+ // TODO(jpawlowski): cache storage is broken, fix it
+ // tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache;
+ // uint8_t num_rpt = 0;
+ // if ((p_rpt_cache = bta_hh_le_co_cache_load(p_cb->addr, &num_rpt,
+ // p_cb->app_id)) != NULL)
+ // {
+ // bta_hh_process_cache_rpt(p_cb, p_rpt_cache, num_rpt);
+ // }
+ }
+ /* discovery has been done for HID service */
+ if (p_cb->app_id != 0 && p_cb->hid_srvc.in_use) {
+ APPL_TRACE_DEBUG("%s: discovery has been done for HID service", __func__);
+ /* configure protocol mode */
+ if (bta_hh_le_set_protocol_mode(p_cb, p_cb->mode) == false) {
+ bta_hh_le_open_cmpl(p_cb);
+ }
+ }
+ /* start primary service discovery for HID service */
+ else {
+ APPL_TRACE_DEBUG("%s: Starting service discovery", __func__);
+ bta_hh_le_pri_service_discovery(p_cb);
+ }
+ }
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(HANDLE_KEY_MISSING) && (HANDLE_KEY_MISSING == TRUE)
+ else if(p_cb->reason == BTM_ERR_KEY_MISSING)
+ {
+ APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
+ __FUNCTION__, p_cb->status, p_cb->reason);
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+
+ tBTA_DM_SEC param;
+ bdcpy(param.delete_key_RC_to_unpair.bd_addr, p_cb->addr);
+ APPL_TRACE_DEBUG("Received encryption changed(OFF) from RC");
+ bta_dm_cb.p_sec_cback(BTA_DM_REPORT_BONDING_EVT, &param);
+#else
+ bta_hh_le_api_disc_act(p_cb);
+#endif
+
+ }
+ else
+ {
+ APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
+ __FUNCTION__, p_cb->status, p_cb->reason);
+ if (!(p_cb->status == BTA_HH_ERR_SEC && p_cb->reason == BTM_ERR_PROCESSING))
+ bta_hh_le_api_disc_act(p_cb);
+ }
+#else
+ else
+ {
+ APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
+ __FUNCTION__, p_cb->status, p_cb->reason);
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+
+ tBTA_DM_SEC param;
+ bdcpy(param.delete_key_RC_to_unpair.bd_addr, p_cb->addr);
+ APPL_TRACE_DEBUG("Received encryption changed(OFF) from RC");
+ bta_dm_cb.p_sec_cback(BTA_DM_REPORT_BONDING_EVT, &param);
+#else
+ bta_hh_le_api_disc_act(p_cb);
+#endif
+
+ }
+
+#endif
+#else
+ else
+ {
+ APPL_TRACE_ERROR("%s() - encryption failed; status=0x%04x, reason=0x%04x",
+ __FUNCTION__, p_cb->status, p_cb->reason);
+ if (!(p_cb->status == BTA_HH_ERR_SEC && p_cb->reason == BTM_ERR_PROCESSING))
+ bta_hh_le_api_disc_act(p_cb);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_notify_enc_cmpl
+ *
+ * Description process GATT encryption complete event
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_hh_le_notify_enc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
+ if (p_cb == NULL || p_cb->security_pending == false || p_buf == NULL ||
+ p_buf->le_enc_cmpl.client_if != bta_hh_cb.gatt_if) {
+ return;
+ }
+
+ p_cb->security_pending = false;
+ bta_hh_start_security(p_cb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_clear_service_cache
+ *
+ * Description clear the service cache
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_clear_service_cache(tBTA_HH_DEV_CB* p_cb) {
+ tBTA_HH_LE_HID_SRVC* p_hid_srvc = &p_cb->hid_srvc;
+
+ p_cb->app_id = 0;
+ p_cb->dscp_info.descriptor.dsc_list = NULL;
+
+ osi_free_and_reset((void**)&p_hid_srvc->rpt_map);
+ memset(p_hid_srvc, 0, sizeof(tBTA_HH_LE_HID_SRVC));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_start_security
+ *
+ * Description start the security check of the established connection
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_start_security(tBTA_HH_DEV_CB* p_cb,
+ UNUSED_ATTR tBTA_HH_DATA* p_buf) {
+ uint8_t sec_flag = 0;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ p_dev_rec = btm_find_dev(p_cb->addr);
+ if (p_dev_rec) {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ /* if security collision happened, wait for encryption done */
+ p_cb->security_pending = true;
+ return;
+ }
+ }
+
+ /* verify bond */
+ BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE);
+
+ /* if link has been encrypted */
+ if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
+ bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+ }
+ /* if bonded and link not encrypted */
+ else if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) {
+ sec_flag = BTM_BLE_SEC_ENCRYPT;
+ p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+ BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback,
+ NULL, sec_flag);
+ }
+ /* unbonded device, report security error here */
+ else if (p_cb->sec_mask != BTA_SEC_NONE) {
+ sec_flag = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+ p_cb->status = BTA_HH_ERR_AUTH_FAILED;
+ bta_hh_clear_service_cache(p_cb);
+ BTM_SetEncryption(p_cb->addr, BTA_TRANSPORT_LE, bta_hh_le_encrypt_cback,
+ NULL, sec_flag);
+ }
+ /* otherwise let it go through */
+ else {
+ bta_hh_sm_execute(p_cb, BTA_HH_ENC_CMPL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_gatt_open
+ *
+ * Description process GATT open event.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_gatt_open(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_buf) {
+ tBTA_GATTC_OPEN* p_data = &p_buf->le_open;
+ uint8_t* p2;
+ tHID_STATUS status = BTA_HH_ERR;
+
+ /* if received invalid callback data , ignore it */
+ if (p_cb == NULL || p_data == NULL) return;
+
+ p2 = p_data->remote_bda;
+
+ APPL_TRACE_DEBUG(
+ "bta_hh_gatt_open BTA_GATTC_OPEN_EVT bda= [%08x%04x] status =%d",
+ ((p2[0]) << 24) + ((p2[1]) << 16) + ((p2[2]) << 8) + (p2[3]),
+ ((p2[4]) << 8) + p2[5], p_data->status);
+
+ if (p_data->status == BTA_GATT_OK) {
+ p_cb->is_le_device = true;
+ p_cb->in_use = true;
+ p_cb->conn_id = p_data->conn_id;
+ p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+
+ bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+
+ gatt_op_queue_clean(p_cb->conn_id);
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("hid_handle = %2x conn_id = %04x cb_index = %d",
+ p_cb->hid_handle, p_cb->conn_id, p_cb->index);
+#endif
+
+ bta_hh_sm_execute(p_cb, BTA_HH_START_ENC_EVT, NULL);
+
+ } else /* open failure */
+ {
+ bta_hh_sm_execute(p_cb, BTA_HH_SDP_CMPL_EVT, (tBTA_HH_DATA*)&status);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_close
+ *
+ * Description This function process the GATT close event and post it as a
+ * BTA HH internal event
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_close(tBTA_GATTC_CLOSE* p_data) {
+ tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->remote_bda);
+ uint16_t sm_event = BTA_HH_GATT_CLOSE_EVT;
+
+ if (p_dev_cb != NULL) {
+ tBTA_HH_LE_CLOSE* p_buf =
+ (tBTA_HH_LE_CLOSE*)osi_malloc(sizeof(tBTA_HH_LE_CLOSE));
+ p_buf->hdr.event = sm_event;
+ p_buf->hdr.layer_specific = (uint16_t)p_dev_cb->hid_handle;
+ p_buf->conn_id = p_data->conn_id;
+ p_buf->reason = p_data->reason;
+
+ p_dev_cb->conn_id = BTA_GATT_INVALID_CONN_ID;
+ p_dev_cb->security_pending = false;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_gatt_disc_cmpl
+ *
+ * Description Check to see if the remote device is a LE only device
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_gatt_disc_cmpl(tBTA_HH_DEV_CB* p_cb, tBTA_HH_STATUS status) {
+ APPL_TRACE_DEBUG("bta_hh_le_gatt_disc_cmpl ");
+
+ /* if open sucessful or protocol mode not desired, keep the connection open
+ * but inform app */
+ if (status == BTA_HH_OK || status == BTA_HH_ERR_PROTO) {
+ /* assign a special APP ID temp, since device type unknown */
+ p_cb->app_id = BTA_HH_APP_ID_LE;
+
+ /* set report notification configuration */
+ p_cb->clt_cfg_idx = 0;
+ bta_hh_le_write_rpt_clt_cfg(p_cb);
+ } else /* error, close the GATT connection */
+ {
+ /* close GATT connection if it's on */
+ bta_hh_le_api_disc_act(p_cb);
+ }
+}
+
+static void read_hid_info_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ if (status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+ return;
+ }
+
+ if (len != 4) {
+ APPL_TRACE_ERROR("%s: wrong length: %d", __func__, len);
+ return;
+ }
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ uint8_t* pp = value;
+ /* save device information */
+ STREAM_TO_UINT16(p_dev_cb->dscp_info.version, pp);
+ STREAM_TO_UINT8(p_dev_cb->dscp_info.ctry_code, pp);
+ STREAM_TO_UINT8(p_dev_cb->dscp_info.flag, pp);
+}
+
+static void read_hid_report_map_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len,
+ uint8_t* value, void* data) {
+ if (status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("%s: error reading characteristic: %d", __func__, status);
+ return;
+ }
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ tBTA_HH_LE_HID_SRVC* p_srvc = &p_dev_cb->hid_srvc;
+
+ osi_free_and_reset((void**)&p_srvc->rpt_map);
+
+ if (len > 0) {
+ p_srvc->rpt_map = (uint8_t*)osi_malloc(len);
+
+ uint8_t* pp = value;
+ STREAM_TO_ARRAY(p_srvc->rpt_map, pp, len);
+ p_srvc->descriptor.dl_len = len;
+ p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc.rpt_map;
+ }
+}
+
+static void read_ext_rpt_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len,
+ uint8_t* value, void* data) {
+ if (status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+ return;
+ }
+
+ /* if the length of the descriptor value is right, parse it assume it's a 16
+ * bits UUID */
+ if (len != LEN_UUID_16) {
+ APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len);
+ return;
+ }
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ uint8_t* pp = value;
+
+ STREAM_TO_UINT16(p_dev_cb->hid_srvc.ext_rpt_ref, pp);
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s: External Report Reference UUID 0x%04x", __func__,
+ p_dev_cb->hid_srvc.ext_rpt_ref);
+#endif
+}
+
+static void read_report_ref_desc_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len,
+ uint8_t* value, void* data) {
+ if (status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+ return;
+ }
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ const tBTA_GATTC_DESCRIPTOR* p_desc =
+ BTA_GATTC_GetDescriptor(conn_id, handle);
+
+ if (!p_desc) {
+ APPL_TRACE_ERROR("%s: error: descriptor is null!", __func__);
+ return;
+ }
+
+ tBTA_HH_LE_RPT* p_rpt;
+ p_rpt = bta_hh_le_find_report_entry(
+ p_dev_cb, p_desc->characteristic->service->handle, GATT_UUID_HID_REPORT,
+ p_desc->characteristic->handle);
+ if (p_rpt) bta_hh_le_save_report_ref(p_dev_cb, p_rpt, status, value, len);
+}
+
+void read_pref_conn_params_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ if (status != BTA_GATT_OK) {
+ APPL_TRACE_ERROR("%s: error: %d", __func__, status);
+ return;
+ }
+
+ if (len != 8) {
+ APPL_TRACE_ERROR("%s: we support only 16bit UUID: %d", __func__, len);
+ return;
+ }
+
+ // TODO(jpawlowski): this should be done by GAP profile, remove when GAP is
+ // fixed.
+ uint8_t* pp = value;
+ uint16_t min, max, latency, tout;
+ STREAM_TO_UINT16(min, pp);
+ STREAM_TO_UINT16(max, pp);
+ STREAM_TO_UINT16(latency, pp);
+ STREAM_TO_UINT16(tout, pp);
+
+ // Make sure both min, and max are bigger than 11.25ms, lower values can
+ // introduce
+ // audio issues if A2DP is also active.
+ if (min < BTM_BLE_CONN_INT_MIN_LIMIT) min = BTM_BLE_CONN_INT_MIN_LIMIT;
+ if (max < BTM_BLE_CONN_INT_MIN_LIMIT) max = BTM_BLE_CONN_INT_MIN_LIMIT;
+
+ // If the device has no preferred connection timeout, use the default.
+ if (tout == BTM_BLE_CONN_PARAM_UNDEF) tout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+
+ if (interop_match_addr(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S,
+ (bt_bdaddr_t*)&p_dev_cb->addr) == true) {
+ if (tout < 300) tout = 300;
+ }
+
+ /** M: Bug fix for HOGP connection taking too long time @{ */
+
+ // BTM_BleSetPrefConnParams(p_dev_cb->addr, min, max, latency, tout);
+ // L2CA_UpdateBleConnParams(p_dev_cb->addr, min, max, latency, tout);
+ p_dev_cb->min_conn_int = min;
+ p_dev_cb->max_conn_int = max;
+ p_dev_cb->slave_latency = latency;
+ p_dev_cb->supervision_tout = tout;
+
+ if (min == BTM_BLE_CONN_PARAM_UNDEF || max == BTM_BLE_CONN_PARAM_UNDEF) {
+ if (min != BTM_BLE_CONN_PARAM_UNDEF) p_dev_cb->max_conn_int = min;
+
+ if (max != BTM_BLE_CONN_PARAM_UNDEF) p_dev_cb->min_conn_int = max;
+ }
+
+ if (latency == BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_cb->slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+ /** @} */
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_search_hid_chars
+ *
+ * Description This function discover all characteristics a service and
+ * all descriptors available.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_hh_le_search_hid_chars(tBTA_HH_DEV_CB* p_dev_cb,
+ tBTA_GATTC_SERVICE* service) {
+ tBTA_HH_LE_RPT* p_rpt;
+
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+ if (p_char->uuid.len != LEN_UUID_16) continue;
+
+ LOG_DEBUG(LOG_TAG, "%s: %s 0x%04d", __func__,
+ bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
+ p_char->uuid.uu.uuid16);
+
+ switch (p_char->uuid.uu.uuid16) {
+ case GATT_UUID_HID_CONTROL_POINT:
+ p_dev_cb->hid_srvc.control_point_handle = p_char->handle;
+ break;
+ case GATT_UUID_HID_INFORMATION:
+ /* only one instance per HID service */
+ gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+ read_hid_info_cb, p_dev_cb);
+ break;
+ case GATT_UUID_HID_REPORT_MAP:
+ /* only one instance per HID service */
+ gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+ read_hid_report_map_cb, p_dev_cb);
+ /* descriptor is optional */
+ bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+ GATT_UUID_EXT_RPT_REF_DESCR,
+ read_ext_rpt_ref_desc_cb, p_dev_cb);
+ break;
+
+ case GATT_UUID_HID_REPORT:
+ p_rpt = bta_hh_le_find_alloc_report_entry(
+ p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id, GATT_UUID_HID_REPORT,
+ p_char->handle);
+ if (p_rpt == NULL) {
+ APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
+ break;
+ }
+
+ if (p_rpt->rpt_type != BTA_HH_RPTT_INPUT) break;
+
+ bta_hh_le_read_char_descriptor(p_dev_cb, p_char->handle,
+ GATT_UUID_RPT_REF_DESCR,
+ read_report_ref_desc_cb, p_dev_cb);
+ break;
+
+ /* found boot mode report types */
+ case GATT_UUID_HID_BT_KB_OUTPUT:
+ case GATT_UUID_HID_BT_MOUSE_INPUT:
+ case GATT_UUID_HID_BT_KB_INPUT:
+ if (bta_hh_le_find_alloc_report_entry(p_dev_cb, service->handle,
+ p_char->uuid.uu.uuid16,
+ p_char->handle) == NULL)
+ APPL_TRACE_ERROR("%s: Add report entry failed !!!", __func__);
+
+ break;
+
+ default:
+ APPL_TRACE_DEBUG("%s: not processing %s 0x%04d", __func__,
+ bta_hh_uuid_to_str(p_char->uuid.uu.uuid16),
+ p_char->uuid.uu.uuid16);
+ }
+ }
+
+ /* Make sure PROTO_MODE is processed as last */
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+
+ if (p_char->uuid.len == LEN_UUID_16 &&
+ p_char->uuid.uu.uuid16 == GATT_UUID_HID_PROTO_MODE) {
+ p_dev_cb->hid_srvc.proto_mode_handle = p_char->handle;
+ bta_hh_le_set_protocol_mode(p_dev_cb, p_dev_cb->mode);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_srvc_search_cmpl
+ *
+ * Description This function process the GATT service search complete.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_srvc_search_cmpl(tBTA_GATTC_SEARCH_CMPL* p_data) {
+ tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+
+ /* service search exception or no HID service is supported on remote */
+ if (p_dev_cb == NULL) return;
+
+ if (p_data->status != BTA_GATT_OK) {
+ p_dev_cb->status = BTA_HH_ERR_SDP;
+ /* close the connection and report service discovery complete with error */
+ bta_hh_le_api_disc_act(p_dev_cb);
+ return;
+ }
+
+ const list_t* services = BTA_GATTC_GetServices(p_data->conn_id);
+
+ bool have_hid = false;
+ for (list_node_t* sn = list_begin(services); sn != list_end(services);
+ sn = list_next(sn)) {
+ tBTA_GATTC_SERVICE* service = (tBTA_GATTC_SERVICE*)list_node(sn);
+
+ if (service->uuid.uu.uuid16 == UUID_SERVCLASS_LE_HID &&
+ service->is_primary && !have_hid) {
+ have_hid = true;
+
+ /* found HID primamry service */
+ p_dev_cb->hid_srvc.in_use = true;
+ p_dev_cb->hid_srvc.srvc_inst_id = service->handle;
+ p_dev_cb->hid_srvc.proto_mode_handle = 0;
+ p_dev_cb->hid_srvc.control_point_handle = 0;
+
+ bta_hh_le_search_hid_chars(p_dev_cb, service);
+
+ APPL_TRACE_DEBUG("%s: have HID service inst_id= %d", __func__,
+ p_dev_cb->hid_srvc.srvc_inst_id);
+ } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_SCAN_PARAM) {
+ p_dev_cb->scan_refresh_char_handle = 0;
+
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+ if (p_char->uuid.len == LEN_UUID_16 &&
+ p_char->uuid.uu.uuid16 == GATT_UUID_SCAN_REFRESH) {
+ p_dev_cb->scan_refresh_char_handle = p_char->handle;
+
+ if (p_char->properties & BTA_GATT_CHAR_PROP_BIT_NOTIFY)
+ p_dev_cb->scps_notify |= BTA_HH_LE_SCPS_NOTIFY_SPT;
+ else
+ p_dev_cb->scps_notify = BTA_HH_LE_SCPS_NOTIFY_NONE;
+
+ break;
+ }
+ }
+ } else if (service->uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER) {
+ // TODO(jpawlowski): this should be done by GAP profile, remove when GAP
+ // is fixed.
+ for (list_node_t* cn = list_begin(service->characteristics);
+ cn != list_end(service->characteristics); cn = list_next(cn)) {
+ tBTA_GATTC_CHARACTERISTIC* p_char =
+ (tBTA_GATTC_CHARACTERISTIC*)list_node(cn);
+ if (p_char->uuid.len == LEN_UUID_16 &&
+ p_char->uuid.uu.uuid16 == GATT_UUID_GAP_PREF_CONN_PARAM) {
+ /* read the char value */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (!interop_mtk_match_addr_name(
+ INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS,
+ (const bt_bdaddr_t*)&p_dev_cb->addr))
+#endif
+ gatt_queue_read_op(GATT_READ_CHAR, p_dev_cb->conn_id, p_char->handle,
+ read_pref_conn_params_cb, p_dev_cb);
+
+ break;
+ }
+ }
+ }
+ }
+
+ bta_hh_le_gatt_disc_cmpl(p_dev_cb, p_dev_cb->status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_input_rpt_notify
+ *
+ * Description process the notificaton event, most likely for input report.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+void bta_hh_le_input_rpt_notify(tBTA_GATTC_NOTIFY* p_data) {
+ tBTA_HH_DEV_CB* p_dev_cb = bta_hh_le_find_dev_cb_by_conn_id(p_data->conn_id);
+ uint8_t app_id;
+ uint8_t* p_buf;
+ tBTA_HH_LE_RPT* p_rpt;
+
+ if (p_dev_cb == NULL) {
+ APPL_TRACE_ERROR(
+ "%s: notification received from Unknown device, conn_id: 0x%04x",
+ __func__, p_data->conn_id);
+ return;
+ }
+
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ BTA_GATTC_GetCharacteristic(p_dev_cb->conn_id, p_data->handle);
+ if (p_char == NULL) {
+ APPL_TRACE_ERROR(
+ "%s: notification received for Unknown Characteristic, conn_id: "
+ "0x%04x, handle: 0x%04x",
+ __func__, p_dev_cb->conn_id, p_data->handle);
+ return;
+ }
+
+ app_id = p_dev_cb->app_id;
+
+ p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_dev_cb->hid_srvc.srvc_inst_id,
+ p_char->uuid.uu.uuid16, p_char->handle);
+ if (p_rpt == NULL) {
+ APPL_TRACE_ERROR(
+ "%s: notification received for Unknown Report, uuid: 0x%04x, handle: "
+ "0x%04x",
+ __func__, p_char->uuid.uu.uuid16, p_char->handle);
+ return;
+ }
+
+ if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_MOUSE_INPUT)
+ app_id = BTA_HH_APP_ID_MI;
+ else if (p_char->uuid.uu.uuid16 == GATT_UUID_HID_BT_KB_INPUT)
+ app_id = BTA_HH_APP_ID_KB;
+
+ APPL_TRACE_DEBUG("Notification received on report ID: %d", p_rpt->rpt_id);
+
+ /* need to append report ID to the head of data */
+ if (p_rpt->rpt_id != 0) {
+ p_buf = (uint8_t*)osi_malloc(p_data->len + 1);
+
+ p_buf[0] = p_rpt->rpt_id;
+ memcpy(&p_buf[1], p_data->value, p_data->len);
+ ++p_data->len;
+ } else {
+ p_buf = p_data->value;
+ }
+
+ bta_hh_co_data((uint8_t)p_dev_cb->hid_handle, p_buf, p_data->len,
+ p_dev_cb->mode, 0, /* no sub class*/
+ p_dev_cb->dscp_info.ctry_code, p_dev_cb->addr, app_id);
+
+ if (p_buf != p_data->value) osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_gatt_open_fail
+ *
+ * Description action function to process the open fail
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_open_fail(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CONN conn_dat;
+
+ /* open failure in the middle of service discovery, clear all services */
+ if (p_cb->disc_active & BTA_HH_LE_DISC_HIDS) {
+ bta_hh_clear_service_cache(p_cb);
+ }
+
+ p_cb->disc_active = BTA_HH_LE_DISC_NONE;
+ /* Failure in opening connection or GATT discovery failure */
+ conn_dat.handle = p_cb->hid_handle;
+ memcpy(conn_dat.bda, p_cb->addr, BD_ADDR_LEN);
+ conn_dat.le_hid = true;
+ conn_dat.scps_supported = p_cb->scps_supported;
+
+ if (p_cb->status == BTA_HH_OK)
+ conn_dat.status = (p_data->le_close.reason == BTA_GATT_CONN_UNKNOWN)
+ ? p_cb->status
+ : BTA_HH_ERR;
+ else
+ conn_dat.status = p_cb->status;
+
+ /* Report OPEN fail event */
+ (*bta_hh_cb.p_cback)(BTA_HH_OPEN_EVT, (tBTA_HH*)&conn_dat);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_gatt_close
+ *
+ * Description action function to process the GATT close int he state
+ * machine.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_gatt_close(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0};
+
+ /* deregister all notification */
+ bta_hh_le_deregister_input_notif(p_cb);
+ /* finaliza device driver */
+ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);
+ /* update total conn number */
+ bta_hh_cb.cnt_num--;
+
+ disc_dat.handle = p_cb->hid_handle;
+ disc_dat.status = p_cb->status;
+
+ (*bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH*)&disc_dat);
+
+ /* if no connection is active and HH disable is signaled, disable service */
+ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) {
+ bta_hh_disc_cmpl();
+ } else {
+#if (BTA_HH_LE_RECONN == TRUE)
+ if (p_data->le_close.reason == BTA_GATT_CONN_TIMEOUT) {
+ bta_hh_le_add_dev_bg_conn(p_cb, false);
+ }
+#endif
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_api_disc_act
+ *
+ * Description initaite a Close API to a remote HID device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb) {
+ if (p_cb->conn_id != BTA_GATT_INVALID_CONN_ID) {
+ gatt_op_queue_clean(p_cb->conn_id);
+ BTA_GATTC_Close(p_cb->conn_id);
+ /* remove device from background connection if intended to disconnect,
+ do not allow reconnection */
+ bta_hh_le_remove_dev_bg_conn(p_cb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function read_report_cb
+ *
+ * Description Process the Read report complete, send GET_REPORT_EVT to
+ * application with the report data.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ BTA_GATTC_GetCharacteristic(conn_id, handle);
+
+ if (p_char == NULL) return;
+
+ uint16_t char_uuid = p_char->uuid.uu.uuid16;
+
+ if (char_uuid != GATT_UUID_HID_REPORT &&
+ char_uuid != GATT_UUID_HID_BT_KB_INPUT &&
+ char_uuid != GATT_UUID_HID_BT_KB_OUTPUT &&
+ char_uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
+ char_uuid != GATT_UUID_BATTERY_LEVEL) {
+ APPL_TRACE_ERROR("%s: Unexpected Read UUID: 0x%04x", __func__, char_uuid);
+ return;
+ }
+
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT) {
+ APPL_TRACE_ERROR("Unexpected READ cmpl, w4_evt = %d", p_dev_cb->w4_evt);
+ return;
+ }
+
+ /* GET_REPORT */
+ BT_HDR* p_buf = NULL;
+ tBTA_HH_LE_RPT* p_rpt;
+ tBTA_HH_HSDATA hs_data;
+ uint8_t* pp;
+
+ memset(&hs_data, 0, sizeof(hs_data));
+ hs_data.status = BTA_HH_ERR;
+ hs_data.handle = p_dev_cb->hid_handle;
+
+ if (status == BTA_GATT_OK) {
+ p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_char->service->handle,
+ p_char->uuid.uu.uuid16, p_char->handle);
+
+ if (p_rpt != NULL && len) {
+ p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
+ /* pack data send to app */
+ hs_data.status = BTA_HH_OK;
+ p_buf->len = len + 1;
+ p_buf->layer_specific = 0;
+ p_buf->offset = 0;
+
+ /* attach report ID as the first byte of the report before sending it to
+ * USB HID driver */
+ pp = (uint8_t*)(p_buf + 1);
+ UINT8_TO_STREAM(pp, p_rpt->rpt_id);
+ memcpy(pp, value, len);
+
+ hs_data.rsp_data.p_rpt_data = p_buf;
+ }
+ }
+
+ p_dev_cb->w4_evt = 0;
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH*)&hs_data);
+
+ osi_free_and_reset((void**)&p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_get_rpt
+ *
+ * Description GET_REPORT on a LE HID Report
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_get_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type,
+ uint8_t rpt_id) {
+ tBTA_HH_LE_RPT* p_rpt = bta_hh_le_find_rpt_by_idtype(
+ p_cb->hid_srvc.report, p_cb->mode, r_type, rpt_id);
+
+ if (p_rpt == NULL) {
+ APPL_TRACE_ERROR("%s: no matching report", __func__);
+ return;
+ }
+
+ p_cb->w4_evt = BTA_HH_GET_RPT_EVT;
+ gatt_queue_read_op(GATT_READ_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
+ read_report_cb, p_cb);
+}
+
+static void write_report_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data) {
+ tBTA_HH_CBDATA cback_data;
+ tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
+ uint16_t cb_evt = p_dev_cb->w4_evt;
+
+ if (cb_evt == 0) return;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_le_write_cmpl w4_evt: %d", p_dev_cb->w4_evt);
+#endif
+
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ BTA_GATTC_GetCharacteristic(conn_id, handle);
+ uint16_t uuid = p_char->uuid.uu.uuid16;
+ if (uuid != GATT_UUID_HID_REPORT && uuid != GATT_UUID_HID_BT_KB_INPUT &&
+ uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
+ uuid != GATT_UUID_HID_BT_KB_OUTPUT) {
+ return;
+ }
+
+ /* Set Report finished */
+ cback_data.handle = p_dev_cb->hid_handle;
+ cback_data.status = (status == BTA_GATT_OK) ? BTA_HH_OK : BTA_HH_ERR;
+ p_dev_cb->w4_evt = 0;
+ (*bta_hh_cb.p_cback)(cb_evt, (tBTA_HH*)&cback_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_le_write_rpt
+ *
+ * Description SET_REPORT/or DATA output on a LE HID Report
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_write_rpt(tBTA_HH_DEV_CB* p_cb, tBTA_HH_RPT_TYPE r_type,
+ BT_HDR* p_buf, uint16_t w4_evt) {
+ tBTA_HH_LE_RPT* p_rpt;
+ uint8_t rpt_id;
+
+ if (p_buf == NULL || p_buf->len == 0) {
+ APPL_TRACE_ERROR("%s: Illegal data", __func__);
+ return;
+ }
+
+ /* strip report ID from the data */
+ uint8_t* vec_start = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT8(rpt_id, vec_start);
+ vector<uint8_t> value(vec_start, vec_start + p_buf->len - 1);
+
+ p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode,
+ r_type, rpt_id);
+ if (p_rpt == NULL) {
+ APPL_TRACE_ERROR("%s: no matching report", __func__);
+ osi_free(p_buf);
+ return;
+ }
+
+ p_cb->w4_evt = w4_evt;
+
+ const tBTA_GATTC_CHARACTERISTIC* p_char =
+ BTA_GATTC_GetCharacteristic(p_cb->conn_id, p_rpt->char_inst_id);
+
+ tBTA_GATTC_WRITE_TYPE write_type = BTA_GATTC_TYPE_WRITE;
+ if (p_char && (p_char->properties & BTA_GATT_CHAR_PROP_BIT_WRITE_NR))
+ write_type = BTA_GATTC_TYPE_WRITE_NO_RSP;
+
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id, p_rpt->char_inst_id,
+ std::move(value), write_type, write_report_cb, p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_suspend
+ *
+ * Description send LE suspend or exit suspend mode to remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_suspend(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_TRANS_CTRL_TYPE ctrl_type) {
+ ctrl_type -= BTA_HH_CTRL_SUSPEND;
+
+ // We don't care about response
+ gatt_queue_write_op(GATT_WRITE_CHAR, p_cb->conn_id,
+ p_cb->hid_srvc.control_point_handle, {(uint8_t)ctrl_type},
+ BTA_GATTC_TYPE_WRITE_NO_RSP, NULL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_write_dev_act
+ *
+ * Description Write LE device action. can be SET/GET/DATA transaction.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
+ switch (p_data->api_sndcmd.t_type) {
+ case HID_TRANS_SET_PROTOCOL:
+ p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
+ bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
+ break;
+
+ case HID_TRANS_GET_PROTOCOL:
+ bta_hh_le_get_protocol_mode(p_cb);
+ break;
+
+ case HID_TRANS_GET_REPORT:
+ bta_hh_le_get_rpt(p_cb, p_data->api_sndcmd.param,
+ p_data->api_sndcmd.rpt_id);
+ break;
+
+ case HID_TRANS_SET_REPORT:
+ bta_hh_le_write_rpt(p_cb, p_data->api_sndcmd.param,
+ p_data->api_sndcmd.p_data, BTA_HH_SET_RPT_EVT);
+ break;
+
+ case HID_TRANS_DATA: /* output report */
+
+ bta_hh_le_write_rpt(p_cb, p_data->api_sndcmd.param,
+ p_data->api_sndcmd.p_data, BTA_HH_DATA_EVT);
+ break;
+
+ case HID_TRANS_CONTROL:
+ /* no handshake event will be generated */
+ /* if VC_UNPLUG is issued, set flag */
+ if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
+ p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) {
+ bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
+ }
+ break;
+
+ default:
+ APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d",
+ __func__, p_data->api_sndcmd.t_type);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_get_dscp_act
+ *
+ * Description Send ReportDescriptor to application for all HID services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_get_dscp_act(tBTA_HH_DEV_CB* p_cb) {
+ if (p_cb->hid_srvc.in_use) {
+ p_cb->dscp_info.descriptor.dl_len = p_cb->hid_srvc.descriptor.dl_len;
+ p_cb->dscp_info.descriptor.dsc_list = p_cb->hid_srvc.descriptor.dsc_list;
+
+ (*bta_hh_cb.p_cback)(BTA_HH_GET_DSCP_EVT, (tBTA_HH*)&p_cb->dscp_info);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_add_dev_bg_conn
+ *
+ * Description Remove a LE HID device from back ground connection
+ * procedure.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB* p_cb, bool check_bond) {
+ uint8_t sec_flag = 0;
+ bool to_add = true;
+
+ if (check_bond) {
+ /* start reconnection if remote is a bonded device */
+ /* verify bond */
+ BTM_GetSecurityFlagsByTransport(p_cb->addr, &sec_flag, BT_TRANSPORT_LE);
+
+ if ((sec_flag & BTM_SEC_FLAG_LKEY_KNOWN) == 0) to_add = false;
+ }
+
+ if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/
+ !p_cb->in_bg_conn && to_add) {
+ /* add device into BG connection to accept remote initiated connection */
+ BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, false, BTA_GATT_TRANSPORT_LE,
+ false);
+ p_cb->in_bg_conn = true;
+
+ BTA_DmBleStartAutoConn();
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_add_device
+ *
+ * Description Add a LE HID device as a known device, and also add the
+ * address
+ * into back ground connection WL for incoming connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t bta_hh_le_add_device(tBTA_HH_DEV_CB* p_cb,
+ tBTA_HH_MAINT_DEV* p_dev_info) {
+ p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index);
+ bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index;
+
+ /* update DI information */
+ bta_hh_update_di_info(
+ p_cb, p_dev_info->dscp_info.vendor_id, p_dev_info->dscp_info.product_id,
+ p_dev_info->dscp_info.version, p_dev_info->dscp_info.flag);
+
+ /* add to BTA device list */
+ bta_hh_add_device_to_list(
+ p_cb, p_cb->hid_handle, p_dev_info->attr_mask,
+ &p_dev_info->dscp_info.descriptor, p_dev_info->sub_class,
+ p_dev_info->dscp_info.ssr_max_latency, p_dev_info->dscp_info.ssr_min_tout,
+ p_dev_info->app_id);
+
+ bta_hh_le_add_dev_bg_conn(p_cb, false);
+
+ p_cb->sec_mask = BTA_SEC_ENCRYPT;
+
+ return p_cb->hid_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_remove_dev_bg_conn
+ *
+ * Description Remove a LE HID device from back ground connection
+ * procedure.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_remove_dev_bg_conn(tBTA_HH_DEV_CB* p_dev_cb) {
+ if (p_dev_cb->in_bg_conn) {
+ p_dev_cb->in_bg_conn = false;
+
+ BTA_GATTC_CancelOpen(bta_hh_cb.gatt_if, p_dev_cb->addr, false);
+ }
+
+ /* deregister all notifications */
+ bta_hh_le_deregister_input_notif(p_dev_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_gattc_callback
+ *
+ * Description This is GATT client callback function used in BTA HH.
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+static void bta_hh_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+ tBTA_HH_DEV_CB* p_dev_cb;
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_gattc_callback event = %d", event);
+#endif
+ if (p_data == NULL) return;
+
+ switch (event) {
+ case BTA_GATTC_DEREG_EVT: /* 1 */
+ bta_hh_cleanup_disable(p_data->reg_oper.status);
+ break;
+
+ case BTA_GATTC_OPEN_EVT: /* 2 */
+ p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->open.remote_bda);
+ if (p_dev_cb) {
+ bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_OPEN_EVT,
+ (tBTA_HH_DATA*)&p_data->open);
+ }
+ break;
+
+ case BTA_GATTC_CLOSE_EVT: /* 5 */
+ bta_hh_le_close(&p_data->close);
+ break;
+
+ case BTA_GATTC_SEARCH_CMPL_EVT: /* 6 */
+ bta_hh_le_srvc_search_cmpl(&p_data->search_cmpl);
+ break;
+
+ case BTA_GATTC_NOTIF_EVT: /* 10 */
+ bta_hh_le_input_rpt_notify(&p_data->notify);
+ break;
+
+ case BTA_GATTC_ENC_CMPL_CB_EVT: /* 17 */
+ p_dev_cb = bta_hh_le_find_dev_cb_by_bda(p_data->enc_cmpl.remote_bda);
+ if (p_dev_cb) {
+ bta_hh_sm_execute(p_dev_cb, BTA_HH_GATT_ENC_CMPL_EVT,
+ (tBTA_HH_DATA*)&p_data->enc_cmpl);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void read_report_descriptor_ccc_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len,
+ uint8_t* value, void* data) {
+ tBTA_HH_LE_RPT* p_rpt = (tBTA_HH_LE_RPT*)data;
+ uint8_t* pp = value;
+ STREAM_TO_UINT16(p_rpt->client_cfg_value, pp);
+
+ APPL_TRACE_DEBUG("Read Client Configuration: 0x%04x",
+ p_rpt->client_cfg_value);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_hid_read_rpt_clt_cfg
+ *
+ * Description a test command to read report descriptor client
+ * configuration
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, uint8_t rpt_id) {
+ tBTA_HH_DEV_CB* p_cb = NULL;
+ tBTA_HH_LE_RPT* p_rpt;
+ uint8_t index = BTA_HH_IDX_INVALID;
+
+ index = bta_hh_find_cb(bd_addr);
+ if (index == BTA_HH_IDX_INVALID) {
+ APPL_TRACE_ERROR("%s: unknown device", __func__);
+ return;
+ }
+
+ p_cb = &bta_hh_cb.kdev[index];
+
+ p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc.report, p_cb->mode,
+ BTA_HH_RPTT_INPUT, rpt_id);
+
+ if (p_rpt == NULL) {
+ APPL_TRACE_ERROR("%s: no matching report", __func__);
+ return;
+ }
+
+ bta_hh_le_read_char_descriptor(p_cb, p_rpt->char_inst_id,
+ GATT_UUID_CHAR_CLIENT_CONFIG,
+ read_report_descriptor_ccc_cb, p_rpt);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_process_cache_rpt
+ *
+ * Description Process the cached reports
+ *
+ * Parameters:
+ *
+ ******************************************************************************/
+// TODO(jpawlowski): uncomment when fixed
+// static void bta_hh_process_cache_rpt (tBTA_HH_DEV_CB *p_cb,
+// tBTA_HH_RPT_CACHE_ENTRY *p_rpt_cache,
+// uint8_t num_rpt)
+// {
+// uint8_t i = 0;
+// tBTA_HH_LE_RPT *p_rpt;
+
+// if (num_rpt != 0) /* no cache is found */
+// {
+// p_cb->hid_srvc.in_use = true;
+
+// /* set the descriptor info */
+// p_cb->hid_srvc.descriptor.dl_len =
+// p_cb->dscp_info.descriptor.dl_len;
+// p_cb->hid_srvc.descriptor.dsc_list =
+// p_cb->dscp_info.descriptor.dsc_list;
+
+// for (; i <num_rpt; i ++, p_rpt_cache ++)
+// {
+// if ((p_rpt = bta_hh_le_find_alloc_report_entry (p_cb,
+// p_rpt_cache->srvc_inst_id,
+// p_rpt_cache->rpt_uuid,
+// p_rpt_cache->char_inst_id,
+// p_rpt_cache->prop)) == NULL)
+// {
+// APPL_TRACE_ERROR("bta_hh_process_cache_rpt: allocation report
+// entry failure");
+// break;
+// }
+// else
+// {
+// p_rpt->rpt_type = p_rpt_cache->rpt_type;
+// p_rpt->rpt_id = p_rpt_cache->rpt_id;
+
+// if (p_rpt->uuid == GATT_UUID_HID_BT_KB_INPUT ||
+// p_rpt->uuid == GATT_UUID_HID_BT_MOUSE_INPUT ||
+// (p_rpt->uuid == GATT_UUID_HID_REPORT && p_rpt->rpt_type
+// == BTA_HH_RPTT_INPUT))
+// {
+// p_rpt->client_cfg_value =
+// BTA_GATT_CLT_CONFIG_NOTIFICATION;
+// }
+// }
+// }
+// }
+// }
+
+#endif
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_main.cc b/mtkbt/code/bt/bta/hh/bta_hh_main.cc
new file mode 100755
index 0000000..4dae1f9
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_main.cc
@@ -0,0 +1,595 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID host main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_hh_api.h"
+#include "bta_hh_int.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+ BTA_HH_API_DISC_ACT, /* HID host process API close action */
+ BTA_HH_OPEN_ACT, /* HID host process BTA_HH_EVT_OPEN */
+ BTA_HH_CLOSE_ACT, /* HID host process BTA_HH_EVT_CLOSE */
+ BTA_HH_DATA_ACT, /* HID host receive data report */
+ BTA_HH_CTRL_DAT_ACT,
+ BTA_HH_HANDSK_ACT,
+ BTA_HH_START_SDP, /* HID host inquery */
+ BTA_HH_SDP_CMPL,
+ BTA_HH_WRITE_DEV_ACT,
+ BTA_HH_GET_DSCP_ACT,
+ BTA_HH_MAINT_DEV_ACT,
+ BTA_HH_OPEN_CMPL_ACT,
+ BTA_HH_OPEN_FAILURE,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ BTA_HH_GATT_CLOSE,
+ BTA_HH_LE_OPEN_FAIL,
+ BTA_HH_GATT_OPEN,
+ BTA_HH_START_SEC,
+ BTA_HH_SEC_CMPL,
+ BTA_HH_GATT_ENC_CMPL,
+#endif
+ BTA_HH_NUM_ACTIONS
+};
+
+#define BTA_HH_IGNORE BTA_HH_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_HH_ACTION)(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data);
+
+/* action functions */
+const tBTA_HH_ACTION bta_hh_action[] = {
+ bta_hh_api_disc_act, bta_hh_open_act, bta_hh_close_act, bta_hh_data_act,
+ bta_hh_ctrl_dat_act, bta_hh_handsk_act, bta_hh_start_sdp, bta_hh_sdp_cmpl,
+ bta_hh_write_dev_act, bta_hh_get_dscp_act, bta_hh_maint_dev_act,
+ bta_hh_open_cmpl_act, bta_hh_open_failure
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ ,
+ bta_hh_gatt_close, bta_hh_le_open_fail, bta_hh_gatt_open,
+ bta_hh_start_security, bta_hh_security_cmpl, bta_hh_le_notify_enc_cmpl
+#endif
+};
+
+/* state table information */
+#define BTA_HH_ACTION 0 /* position of action */
+#define BTA_HH_NEXT_STATE 1 /* position of next state */
+#define BTA_HH_NUM_COLS 2 /* number of columns */
+
+/* state table for idle state */
+const uint8_t bta_hh_st_idle[][BTA_HH_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_START_SDP, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST},
+ /* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ /* BTA_HH_GATT_CLOSE_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+ /* BTA_HH_GATT_OPEN_EVT */,
+ {BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST}
+ /* BTA_HH_START_ENC_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+ /* BTA_HH_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+ /* BTA_HH_GATT_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_IDLE_ST}
+#endif
+
+};
+
+const uint8_t bta_hh_st_w4_conn[][BTA_HH_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_IGNORE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_SDP_CMPL, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST},
+ /* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_OPEN_CMPL_ACT, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ /* BTA_HH_GATT_CLOSE_EVT */,
+ {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST}
+ /* BTA_HH_GATT_OPEN_EVT */,
+ {BTA_HH_GATT_OPEN, BTA_HH_W4_CONN_ST}
+ /* BTA_HH_START_ENC_EVT */,
+ {BTA_HH_START_SEC, BTA_HH_W4_SEC}
+ /* BTA_HH_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST}
+ /* BTA_HH_GATT_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_W4_CONN_ST}
+#endif
+};
+
+const uint8_t bta_hh_st_connected[][BTA_HH_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST},
+ /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST},
+ /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST},
+ /* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ /* BTA_HH_GATT_CLOSE_EVT */,
+ {BTA_HH_GATT_CLOSE, BTA_HH_IDLE_ST}
+ /* BTA_HH_GATT_OPEN_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+ /* BTA_HH_START_ENC_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+ /* BTA_HH_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+ /* BTA_HH_GATT_ENC_CMPL_EVT */,
+ {BTA_HH_IGNORE, BTA_HH_CONN_ST}
+#endif
+};
+#if (BTA_HH_LE_INCLUDED == TRUE)
+const uint8_t bta_hh_st_w4_sec[][BTA_HH_NUM_COLS] = {
+ /* Event Action Next state */
+ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_W4_SEC},
+ /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_OPEN_FAILURE, BTA_HH_IDLE_ST},
+ /* BTA_HH_INT_DATA_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_INT_CTRL_DATA */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_W4_SEC},
+ /* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_GATT_CLOSE_EVT */ {BTA_HH_LE_OPEN_FAIL, BTA_HH_IDLE_ST},
+ /* BTA_HH_GATT_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_START_ENC_EVT */ {BTA_HH_IGNORE, BTA_HH_W4_SEC},
+ /* BTA_HH_ENC_CMPL_EVT */ {BTA_HH_SEC_CMPL, BTA_HH_W4_CONN_ST},
+ /* BTA_HH_GATT_ENC_CMPL_EVT */ {BTA_HH_GATT_ENC_CMPL, BTA_HH_W4_SEC}};
+#endif
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HH_ST_TBL)[BTA_HH_NUM_COLS];
+
+/* state table */
+const tBTA_HH_ST_TBL bta_hh_st_tbl[] = {bta_hh_st_idle, bta_hh_st_w4_conn,
+ bta_hh_st_connected
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ ,
+ bta_hh_st_w4_sec
+#endif
+};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+tBTA_HH_CB bta_hh_cb;
+
+/*****************************************************************************
+ * Static functions
+ ****************************************************************************/
+#if (BTA_HH_DEBUG == TRUE)
+static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code);
+static const char* bta_hh_state_code(tBTA_HH_STATE state_code);
+#endif
+
+/*******************************************************************************
+ *
+ * Function bta_hh_sm_execute
+ *
+ * Description State machine event handling function for HID Host
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_sm_execute(tBTA_HH_DEV_CB* p_cb, uint16_t event,
+ tBTA_HH_DATA* p_data) {
+ tBTA_HH_ST_TBL state_table;
+ uint8_t action;
+ tBTA_HH cback_data;
+ tBTA_HH_EVT cback_event = 0;
+#if (BTA_HH_DEBUG == TRUE)
+ tBTA_HH_STATE in_state;
+ uint16_t debug_event = event;
+#endif
+
+ memset(&cback_data, 0, sizeof(tBTA_HH));
+
+ /* handle exception, no valid control block was found */
+ if (!p_cb) {
+ /* BTA HH enabled already? otherwise ignore the event although it's bad*/
+ if (bta_hh_cb.p_cback != NULL) {
+ switch (event) {
+ /* no control block available for new connection */
+ case BTA_HH_API_OPEN_EVT:
+ cback_event = BTA_HH_OPEN_EVT;
+ /* build cback data */
+ bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN*)p_data)->bd_addr);
+ cback_data.conn.status = BTA_HH_ERR_DB_FULL;
+ cback_data.conn.handle = BTA_HH_INVALID_HANDLE;
+ break;
+ /* DB full, BTA_HhAddDev */
+ case BTA_HH_API_MAINT_DEV_EVT:
+ cback_event = p_data->api_maintdev.sub_event;
+
+ if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT) {
+ bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
+ cback_data.dev_info.status = BTA_HH_ERR_DB_FULL;
+ cback_data.dev_info.handle = BTA_HH_INVALID_HANDLE;
+ } else {
+ cback_data.dev_info.status = BTA_HH_ERR_HDL;
+ cback_data.dev_info.handle =
+ (uint8_t)p_data->api_maintdev.hdr.layer_specific;
+ }
+ break;
+ case BTA_HH_API_WRITE_DEV_EVT:
+ cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
+ BTA_HH_FST_TRANS_CB_EVT;
+ osi_free_and_reset((void**)&p_data->api_sndcmd.p_data);
+ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
+ p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE) {
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle =
+ (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+ } else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
+ p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) {
+ cback_data.hs_data.handle =
+ (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+ cback_data.hs_data.status = BTA_HH_ERR_HDL;
+ /* hs_data.rsp_data will be all zero, which is not valid value */
+ } else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
+ p_data->api_sndcmd.param ==
+ BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) {
+ cback_data.status = BTA_HH_ERR_HDL;
+ cback_event = BTA_HH_VC_UNPLUG_EVT;
+ } else
+ cback_event = 0;
+ break;
+
+ case BTA_HH_API_CLOSE_EVT:
+ cback_event = BTA_HH_CLOSE_EVT;
+
+ cback_data.dev_status.status = BTA_HH_ERR_HDL;
+ cback_data.dev_status.handle =
+ (uint8_t)p_data->api_sndcmd.hdr.layer_specific;
+ break;
+
+ default:
+ /* invalid handle, call bad API event */
+ APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+ APPL_TRACE_ERROR("wrong device handle event: [%lu]", event);
+ if ((event == BTA_HH_INT_OPEN_EVT) || (event == BTA_HH_INT_CLOSE_EVT) ||
+ (event == BTA_HH_INT_DATA_EVT) || (event == BTA_HH_INT_CTRL_DATA) ||
+ (event == BTA_HH_INT_HANDSK_EVT) )
+ {
+ /* Free the callback buffer now */
+ if (p_data != NULL)
+ osi_free_and_reset((void **)&p_data->hid_cback.p_data);
+ }
+#else
+ /* Free the callback buffer now */
+ if (p_data != NULL)
+ osi_free_and_reset((void**)&p_data->hid_cback.p_data);
+#endif
+ break;
+ }
+ if (cback_event) (*bta_hh_cb.p_cback)(cback_event, &cback_data);
+ }
+ }
+ /* corresponding CB is found, go to state machine */
+ else {
+#if (BTA_HH_DEBUG == TRUE)
+ in_state = p_cb->state;
+ APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hh_state_code(in_state),
+ bta_hh_evt_code(debug_event));
+#endif
+
+ if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) {
+ APPL_TRACE_ERROR(
+ "bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
+ p_cb->state, event);
+ return;
+ }
+ state_table = bta_hh_st_tbl[p_cb->state - 1];
+
+ event &= 0xff;
+
+ p_cb->state = state_table[event][BTA_HH_NEXT_STATE];
+
+ action = state_table[event][BTA_HH_ACTION];
+ if (action != BTA_HH_IGNORE) {
+ (*bta_hh_action[action])(p_cb, p_data);
+ }
+
+#if (BTA_HH_DEBUG == TRUE)
+ if (in_state != p_cb->state) {
+ APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
+ bta_hh_state_code(in_state),
+ bta_hh_state_code(p_cb->state),
+ bta_hh_evt_code(debug_event));
+ }
+#endif
+ }
+
+ return;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_hdl_event
+ *
+ * Description HID host main event handling function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_hh_hdl_event(BT_HDR* p_msg) {
+ uint8_t index = BTA_HH_IDX_INVALID;
+ tBTA_HH_DEV_CB* p_cb = NULL;
+
+ switch (p_msg->event) {
+ case BTA_HH_API_ENABLE_EVT:
+ bta_hh_api_enable((tBTA_HH_DATA*)p_msg);
+ /**M: hid device reconnect fail when collision@{*/
+ bta_sys_collision_register (BTA_ID_HH, bta_hh_collision_cback);
+ /**@}*/
+ break;
+
+ case BTA_HH_API_DISABLE_EVT:
+ bta_hh_api_disable();
+ /**M: hid device reconnect fail when collision@{*/
+ bta_sys_collision_register (BTA_ID_HH, NULL);
+ /**@}*/
+ break;
+
+ case BTA_HH_DISC_CMPL_EVT: /* disable complete */
+ bta_hh_disc_cmpl();
+ break;
+
+ default:
+ /* all events processed in state machine need to find corresponding
+ CB before proceed */
+ if (p_msg->event == BTA_HH_API_OPEN_EVT) {
+ index = bta_hh_find_cb(((tBTA_HH_API_CONN*)p_msg)->bd_addr);
+ } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT) {
+ /* if add device */
+ if (((tBTA_HH_MAINT_DEV*)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) {
+ index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV*)p_msg)->bda);
+ } else /* else remove device by handle */
+ {
+ index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific);
+ /* If BT disable is done while the HID device is connected and
+ * Link_Key uses unauthenticated combination
+ * then we can get into a situation where remove_bonding is called
+ * with the index set to 0 (without getting
+ * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the
+ * index and make it MAX_KNOWN.
+ * So if REMOVE_DEVICE is called and in_use is false then we should
+ * treat this as a NULL p_cb. Hence we
+ * force the index to be IDX_INVALID
+ */
+ if ((index != BTA_HH_IDX_INVALID) &&
+ (bta_hh_cb.kdev[index].in_use == false)) {
+ index = BTA_HH_IDX_INVALID;
+ }
+ }
+ } else if (p_msg->event == BTA_HH_INT_OPEN_EVT) {
+ index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA*)p_msg)->addr);
+ } else
+ index = bta_hh_dev_handle_to_cb_idx((uint8_t)p_msg->layer_specific);
+
+ if (index != BTA_HH_IDX_INVALID) p_cb = &bta_hh_cb.kdev[index];
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ",
+ p_msg->layer_specific, index);
+#endif
+ bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA*)p_msg);
+ }
+ return (true);
+}
+
+/**M: hid device reconnect fail when collision@{*/
+/*******************************************************************************
+**
+** Function bta_hh_collision_timer_cback
+**
+** Description Handle hid connection collision and disconnect hid host and
+** receive connection from HID device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_hh_collision_timer_cback(void *data)
+{
+ tBTA_HH_DEV_CB *p_cb = (tBTA_HH_DEV_CB*)data;
+
+ APPL_TRACE_WARNING ("HH collision, drawback host initiate connection");
+
+ /* Disconnect HID host connection */
+ bta_hh_open_collision_failure(p_cb, HID_ERR_HOST_UNKNOWN);
+}
+
+/*******************************************************************************
+**
+** Function bta_hh_collision_cback
+**
+** Description Get notified about collision.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_hh_collision_cback (tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr)
+{
+ uint16_t handle = 0xff;
+ tBTA_HH_DEV_CB *p_cb = NULL;
+
+ /* Check if we have opening cb for the peer device. */
+ handle = bta_hh_find_cb (peer_addr);
+
+ if (handle != BTA_HH_IDX_INVALID)
+ p_cb = &bta_hh_cb.kdev[handle];
+
+ if (p_cb && (p_cb->state == BTA_HH_W4_CONN_ST))
+ {
+ if (id == BTA_ID_SYS) /* ACL collision */
+ {
+ APPL_TRACE_WARNING ("HH found collision (ACL) ...");
+ }
+ else if (id == BTA_ID_HH) /* HID profile collision */
+ {
+ APPL_TRACE_WARNING ("HH found collision (HID) ...");
+ }
+ else
+ {
+ APPL_TRACE_WARNING ("HH found collision (\?\?\?) ...");
+ }
+
+ p_cb->state = BTA_HH_IDLE_ST;
+ bta_hh_collision_timer_cback(p_cb);
+ }
+}
+/**@}*/
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+#if (BTA_HH_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_hh_evt_code
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static const char* bta_hh_evt_code(tBTA_HH_INT_EVT evt_code) {
+ switch (evt_code) {
+ case BTA_HH_API_DISABLE_EVT:
+ return "BTA_HH_API_DISABLE_EVT";
+ case BTA_HH_API_ENABLE_EVT:
+ return "BTA_HH_API_ENABLE_EVT";
+ case BTA_HH_API_OPEN_EVT:
+ return "BTA_HH_API_OPEN_EVT";
+ case BTA_HH_API_CLOSE_EVT:
+ return "BTA_HH_API_CLOSE_EVT";
+ case BTA_HH_INT_OPEN_EVT:
+ return "BTA_HH_INT_OPEN_EVT";
+ case BTA_HH_INT_CLOSE_EVT:
+ return "BTA_HH_INT_CLOSE_EVT";
+ case BTA_HH_INT_HANDSK_EVT:
+ return "BTA_HH_INT_HANDSK_EVT";
+ case BTA_HH_INT_DATA_EVT:
+ return "BTA_HH_INT_DATA_EVT";
+ case BTA_HH_INT_CTRL_DATA:
+ return "BTA_HH_INT_CTRL_DATA";
+ case BTA_HH_API_WRITE_DEV_EVT:
+ return "BTA_HH_API_WRITE_DEV_EVT";
+ case BTA_HH_SDP_CMPL_EVT:
+ return "BTA_HH_SDP_CMPL_EVT";
+ case BTA_HH_DISC_CMPL_EVT:
+ return "BTA_HH_DISC_CMPL_EVT";
+ case BTA_HH_API_MAINT_DEV_EVT:
+ return "BTA_HH_API_MAINT_DEV_EVT";
+ case BTA_HH_API_GET_DSCP_EVT:
+ return "BTA_HH_API_GET_DSCP_EVT";
+ case BTA_HH_OPEN_CMPL_EVT:
+ return "BTA_HH_OPEN_CMPL_EVT";
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ case BTA_HH_GATT_CLOSE_EVT:
+ return "BTA_HH_GATT_CLOSE_EVT";
+ case BTA_HH_GATT_OPEN_EVT:
+ return "BTA_HH_GATT_OPEN_EVT";
+ case BTA_HH_START_ENC_EVT:
+ return "BTA_HH_START_ENC_EVT";
+ case BTA_HH_ENC_CMPL_EVT:
+ return "BTA_HH_ENC_CMPL_EVT";
+#endif
+ default:
+ return "unknown HID Host event code";
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_state_code
+ *
+ * Description get string representation of HID host state code.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static const char* bta_hh_state_code(tBTA_HH_STATE state_code) {
+ switch (state_code) {
+ case BTA_HH_NULL_ST:
+ return "BTA_HH_NULL_ST";
+ case BTA_HH_IDLE_ST:
+ return "BTA_HH_IDLE_ST";
+ case BTA_HH_W4_CONN_ST:
+ return "BTA_HH_W4_CONN_ST";
+ case BTA_HH_CONN_ST:
+ return "BTA_HH_CONN_ST";
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ case BTA_HH_W4_SEC:
+ return "BTA_HH_W4_SEC";
+#endif
+ default:
+ return "unknown HID Host state";
+ }
+}
+
+#endif /* Debug Functions */
+
+#endif /* BTA_HH_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hh/bta_hh_utils.cc b/mtkbt/code/bt/bta/hh/bta_hh_utils.cc
new file mode 100755
index 0000000..320a2d1
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hh/bta_hh_utils.cc
@@ -0,0 +1,506 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if (BTA_HH_INCLUDED == TRUE)
+
+#include "bta_hh_int.h"
+#include "osi/include/osi.h"
+
+/* if SSR max latency is not defined by remote device, set the default value
+ as half of the link supervision timeout */
+#define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x) >> 1)
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+#define BTA_HH_KB_CTRL_MASK 0x11
+#define BTA_HH_KB_SHIFT_MASK 0x22
+#define BTA_HH_KB_ALT_MASK 0x44
+#define BTA_HH_KB_GUI_MASK 0x88
+
+#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */
+#define BTA_HH_KB_NUM_LOCK 0x53 /* num lock */
+
+#define BTA_HH_MAX_RPT_CHARS 8
+
+static const uint8_t bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = {
+ BTA_HH_KB_CTRL_MASK, BTA_HH_KB_SHIFT_MASK, BTA_HH_KB_ALT_MASK,
+ BTA_HH_KB_GUI_MASK};
+
+/*******************************************************************************
+ *
+ * Function bta_hh_find_cb
+ *
+ * Description Find best available control block according to BD address.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t bta_hh_find_cb(BD_ADDR bda) {
+ uint8_t xx;
+
+ /* See how many active devices there are. */
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ /* check if any active/known devices is a match */
+ if ((!bdcmp(bda, bta_hh_cb.kdev[xx].addr) &&
+ bdcmp(bda, bd_addr_null) != 0)) {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("found kdev_cb[%d] hid_handle = %d ", xx,
+ bta_hh_cb.kdev[xx].hid_handle)
+#endif
+ return xx;
+ }
+#if (BTA_HH_DEBUG == TRUE)
+ else
+ APPL_TRACE_DEBUG("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]",
+ bta_hh_cb.kdev[xx].in_use, xx,
+ bta_hh_cb.kdev[xx].hid_handle, bta_hh_cb.kdev[xx].state);
+#endif
+ }
+
+ /* if no active device match, find a spot for it */
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ if (!bta_hh_cb.kdev[xx].in_use
+ /** M: Bug Check state item for connection conflict @{ */
+ && bta_hh_cb.kdev[xx].state == BTA_HH_IDLE_ST
+ /** @} */) {
+ bdcpy(bta_hh_cb.kdev[xx].addr, bda);
+ break;
+ }
+ }
+/* If device list full, report BTA_HH_IDX_INVALID */
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_find_cb:: index = %d while max = %d", xx,
+ BTA_HH_MAX_DEVICE);
+#endif
+
+ if (xx == BTA_HH_MAX_DEVICE) xx = BTA_HH_IDX_INVALID;
+
+ return xx;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_clean_up_kdev
+ *
+ * Description Clean up device control block when device is removed from
+ * manitainace list, and update control block index map.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) {
+ uint8_t index;
+
+ if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE) {
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (p_cb->is_le_device)
+ bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] =
+ BTA_HH_IDX_INVALID;
+ else
+#endif
+ bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID;
+ }
+
+ /* reset device control block */
+ index = p_cb->index; /* Preserve index for this control block */
+
+ /* Free buffer for report descriptor info */
+ osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
+
+ memset(p_cb, 0, sizeof(tBTA_HH_DEV_CB)); /* Reset control block */
+
+ p_cb->index = index; /* Restore index for this control block */
+ p_cb->state = BTA_HH_IDLE_ST;
+ p_cb->hid_handle = BTA_HH_INVALID_HANDLE;
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_update_di_info
+ *
+ * Description Maintain a known device list for BTA HH.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
+ uint16_t product_id, uint16_t version,
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ uint8_t flag)
+#else
+ UNUSED_ATTR uint8_t flag)
+#endif
+{
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x",
+ vendor_id, product_id, version);
+#endif
+ p_cb->dscp_info.vendor_id = vendor_id;
+ p_cb->dscp_info.product_id = product_id;
+ p_cb->dscp_info.version = version;
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ p_cb->dscp_info.flag = flag;
+#endif
+}
+/*******************************************************************************
+ *
+ * Function bta_hh_add_device_to_list
+ *
+ * Description Maintain a known device list for BTA HH.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
+ uint16_t attr_mask,
+ tHID_DEV_DSCP_INFO* p_dscp_info,
+ uint8_t sub_class, uint16_t ssr_max_latency,
+ uint16_t ssr_min_tout, uint8_t app_id) {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class);
+#endif
+
+ p_cb->hid_handle = handle;
+ p_cb->in_use = true;
+ p_cb->attr_mask = attr_mask;
+
+ p_cb->sub_class = sub_class;
+ p_cb->app_id = app_id;
+
+ p_cb->dscp_info.ssr_max_latency = ssr_max_latency;
+ p_cb->dscp_info.ssr_min_tout = ssr_min_tout;
+
+ /* store report descriptor info */
+ if (p_dscp_info) {
+ osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
+
+ if (p_dscp_info->dl_len) {
+ p_cb->dscp_info.descriptor.dsc_list =
+ (uint8_t*)osi_malloc(p_dscp_info->dl_len);
+ p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len;
+ memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list,
+ p_dscp_info->dl_len);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_tod_spt
+ *
+ * Description Check to see if this type of device is supported
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class) {
+ uint8_t xx;
+ uint8_t cod = (sub_class >> 2); /* lower two bits are reserved */
+
+ for (xx = 0; xx < p_bta_hh_cfg->max_devt_spt; xx++) {
+ if (cod == (uint8_t)p_bta_hh_cfg->p_devt_list[xx].tod) {
+ p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id;
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x supported", sub_class);
+#endif
+ return true;
+ }
+ }
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
+#endif
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_parse_keybd_rpt
+ *
+ * Description This utility function parse a boot mode keyboard report.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data, uint8_t* p_report,
+ uint16_t report_len) {
+ tBTA_HH_KB_CB* p_kb = &bta_hh_cb.kb_cb;
+ tBTA_HH_KEYBD_RPT* p_data = &p_kb_data->data_rpt.keybd_rpt;
+
+ uint8_t this_char, ctl_shift;
+ uint16_t xx, yy, key_idx = 0;
+ uint8_t this_report[BTA_HH_MAX_RPT_CHARS];
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt: (report=%p, report_len=%d) called",
+ p_report, report_len);
+#endif
+
+ if (report_len < 2) return;
+
+ ctl_shift = *p_report++;
+ report_len--;
+
+ if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
+
+ memset(this_report, 0, BTA_HH_MAX_RPT_CHARS);
+ memset(p_data, 0, sizeof(tBTA_HH_KEYBD_RPT));
+ memcpy(this_report, p_report, report_len);
+
+ /* Take care of shift, control, GUI and alt, modifier keys */
+ for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx++) {
+ if (ctl_shift & bta_hh_mod_key_mask[xx]) {
+ APPL_TRACE_DEBUG("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx]);
+ p_kb->mod_key[xx] = true;
+ } else if (p_kb->mod_key[xx]) {
+ p_kb->mod_key[xx] = false;
+ }
+ /* control key flag is set */
+ p_data->mod_key[xx] = p_kb->mod_key[xx];
+ }
+
+ /***************************************************************************/
+ /* First step is to remove all characters we saw in the last report */
+ /***************************************************************************/
+ for (xx = 0; xx < report_len; xx++) {
+ for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) {
+ if (this_report[xx] == p_kb->last_report[yy]) {
+ this_report[xx] = 0;
+ }
+ }
+ }
+ /***************************************************************************/
+ /* Now, process all the characters in the report, up to 6 keycodes */
+ /***************************************************************************/
+ for (xx = 0; xx < report_len; xx++) {
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("this_char = %02x", this_report[xx]);
+#endif
+ this_char = this_report[xx];
+ if (this_char == 0) continue;
+ /* take the key code as the report data */
+ if (this_report[xx] == BTA_HH_KB_CAPS_LOCK)
+ p_kb->caps_lock = p_kb->caps_lock ? false : true;
+ else if (this_report[xx] == BTA_HH_KB_NUM_LOCK)
+ p_kb->num_lock = p_kb->num_lock ? false : true;
+ else
+ p_data->this_char[key_idx++] = this_char;
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("found keycode %02x ", this_report[xx]);
+#endif
+ p_data->caps_lock = p_kb->caps_lock;
+ p_data->num_lock = p_kb->num_lock;
+ }
+
+ memset(p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS);
+ memcpy(p_kb->last_report, p_report, report_len);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_parse_mice_rpt
+ *
+ * Description This utility function parse a boot mode mouse report.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_mice_data, uint8_t* p_report,
+ uint16_t report_len) {
+ tBTA_HH_MICE_RPT* p_data = &p_mice_data->data_rpt.mice_rpt;
+#if (BTA_HH_DEBUG == TRUE)
+ uint8_t xx;
+
+ APPL_TRACE_DEBUG(
+ "bta_hh_parse_mice_rpt: bta_keybd_rpt_rcvd(report=%p, \
+ report_len=%d) called",
+ p_report, report_len);
+#endif
+
+ if (report_len < 3) return;
+
+ if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
+
+#if (BTA_HH_DEBUG == TRUE)
+ for (xx = 0; xx < report_len; xx++) {
+ APPL_TRACE_DEBUG("this_char = %02x", p_report[xx]);
+ }
+#endif
+
+ /* only first bytes lower 3 bits valid */
+ p_data->mouse_button = (p_report[0] & 0x07);
+
+ /* x displacement */
+ p_data->delta_x = p_report[1];
+
+ /* y displacement */
+ p_data->delta_y = p_report[2];
+
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("mice button: 0x%2x", p_data->mouse_button);
+ APPL_TRACE_DEBUG("mice move: x = %d y = %d", p_data->delta_x,
+ p_data->delta_y);
+#endif
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_read_ssr_param
+ *
+ * Description Read the SSR Parameter for the remote device
+ *
+ * Returns tBTA_HH_STATUS operation status
+ *
+ ******************************************************************************/
+tBTA_HH_STATUS bta_hh_read_ssr_param(BD_ADDR bd_addr, uint16_t* p_max_ssr_lat,
+ uint16_t* p_min_ssr_tout) {
+ tBTA_HH_STATUS status = BTA_HH_ERR;
+ tBTA_HH_CB* p_cb = &bta_hh_cb;
+ uint8_t i;
+ uint16_t ssr_max_latency;
+ for (i = 0; i < BTA_HH_MAX_KNOWN; i++) {
+ if (memcmp(p_cb->kdev[i].addr, bd_addr, BD_ADDR_LEN) == 0) {
+ /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP,
+ set SSR max latency default value here. */
+ if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) {
+ /* The default is calculated as half of link supervision timeout.*/
+
+ BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency);
+ ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
+
+ /* per 1.1 spec, if the newly calculated max latency is greater than
+ BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use
+ BTA_HH_SSR_MAX_LATENCY_DEF */
+ if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
+ ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
+
+ *p_max_ssr_lat = ssr_max_latency;
+ } else
+ *p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency;
+
+ if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID)
+ *p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF;
+ else
+ *p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout;
+
+ status = BTA_HH_OK;
+
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_cleanup_disable
+ *
+ * Description when disable finished, cleanup control block and send
+ * callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hh_cleanup_disable(tBTA_HH_STATUS status) {
+ uint8_t xx;
+ /* free buffer in CB holding report descriptors */
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ osi_free_and_reset(
+ (void**)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
+ }
+
+ if (bta_hh_cb.p_disc_db) {
+ /* Cancel SDP if it had been started. */
+ (void)SDP_CancelServiceSearch (bta_hh_cb.p_disc_db);
+ osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
+ }
+
+ if (bta_hh_cb.p_cback) {
+ (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
+ /* all connections are down, no waiting for diconnect */
+ memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_dev_handle_to_cb_idx
+ *
+ * Description convert a HID device handle to the device control block
+ * index.
+ *
+ *
+ * Returns uint8_t: index of the device control block.
+ *
+ ******************************************************************************/
+uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) {
+ uint8_t index = BTA_HH_IDX_INVALID;
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) {
+ if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle))
+ index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)];
+#if (BTA_HH_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d",
+ dev_handle, index);
+#endif
+ } else
+#endif
+ /* regular HID device checking */
+ if (dev_handle < BTA_HH_MAX_KNOWN)
+ index = bta_hh_cb.cb_index[dev_handle];
+
+ return index;
+}
+#if (BTA_HH_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_hh_trace_dev_db
+ *
+ * Description Check to see if this type of device is supported
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_hh_trace_dev_db(void) {
+ uint8_t xx;
+
+ APPL_TRACE_DEBUG("bta_hh_trace_dev_db:: Device DB list********************");
+
+ for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
+ APPL_TRACE_DEBUG("kdev[%d] in_use[%d] handle[%d] ", xx,
+ bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle);
+
+ APPL_TRACE_DEBUG(
+ "\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d",
+ bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state,
+ bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index);
+ }
+ APPL_TRACE_DEBUG("*********************************************************");
+}
+#endif
+#endif /* HL_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_act.cc b/mtkbt/code/bt/bta/hl/bta_hl_act.cc
new file mode 100755
index 0000000..569f66c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_act.cc
@@ -0,0 +1,2377 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HeaLth device profile (HL) action functions for
+ * the state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "bta_sys.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Local Function prototypes
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+static const char* bta_hl_mcap_evt_code(uint8_t evt_code);
+static const char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code);
+static const char* bta_hl_cback_evt_code(uint8_t evt_code);
+#endif
+static void bta_hl_sdp_cback(uint8_t sdp_op, uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, uint16_t status);
+static void bta_hl_sdp_cback0(uint16_t status);
+static void bta_hl_sdp_cback1(uint16_t status);
+static void bta_hl_sdp_cback2(uint16_t status);
+static void bta_hl_sdp_cback3(uint16_t status);
+static void bta_hl_sdp_cback4(uint16_t status);
+static void bta_hl_sdp_cback5(uint16_t status);
+static void bta_hl_sdp_cback6(uint16_t status);
+
+static tSDP_DISC_CMPL_CB* const bta_hl_sdp_cback_arr[] = {
+ bta_hl_sdp_cback0, bta_hl_sdp_cback1, bta_hl_sdp_cback2, bta_hl_sdp_cback3,
+ bta_hl_sdp_cback4, bta_hl_sdp_cback5, bta_hl_sdp_cback6};
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_cong_change
+ *
+ * Description Action routine for processing congestion change notification
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CONG_CHG* p_cong_chg = &p_data->mca_evt.mca_data.cong_chg;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_cong_change mdl_id=%d cong=%d",
+ p_cong_chg->mdl_id, p_cong_chg->cong);
+#endif
+ evt_data.dch_cong_ind.cong = p_dcb->cong = p_cong_chg->cong;
+ evt_data.dch_cong_ind.mdl_handle = p_dcb->mdl_handle;
+ evt_data.dch_cong_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_cong_ind.app_handle = p_acb->app_handle;
+
+ p_acb->p_cback(BTA_HL_CONG_CHG_IND_EVT, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_echo_test
+ *
+ * Description Action routine for processing echo test request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ UNUSED_ATTR tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_echo_test");
+#endif
+
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_GET_ECHO_DATA;
+ p_dcb->cout_oper |= BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+ bta_hl_co_get_echo_data(
+ p_acb->app_id, p_mcb->mcl_handle, p_dcb->p_echo_tx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_echo_tx_pkt), BTA_HL_CI_GET_ECHO_DATA_EVT);
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_sdp_init
+ *
+ * Description Action routine for processing DCH SDP initiation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_sdp_init");
+#endif
+ if (p_mcb->sdp_oper == BTA_HL_SDP_OP_NONE) {
+ p_mcb->sdp_mdl_idx = mdl_idx;
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_OPEN_INIT;
+
+ } else {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_DCH_RECONNECT_INIT;
+ }
+
+ if (bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, mdl_idx) !=
+ BTA_HL_STATUS_OK) {
+ APPL_TRACE_ERROR("SDP INIT failed");
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_NONE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
+ p_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("SDP in use");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_SDP_FAIL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_close_echo_test
+ *
+ * Description Action routine for processing the closing of echo test
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_close_echo_test");
+#endif
+
+ switch (p_dcb->echo_oper) {
+ case BTA_HL_ECHO_OP_DCH_CLOSE_CFM:
+ case BTA_HL_ECHO_OP_OPEN_IND:
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST;
+ break;
+ case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+ case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+ default:
+ break;
+ }
+
+ if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) != MCA_SUCCESS) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_rcv_data
+ *
+ * Description Action routine for processing the received data
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_rcv_data");
+#endif
+
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ switch (p_dcb->echo_oper) {
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+
+ if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle,
+ p_data->mca_rcv_data_evt.p_pkt) != MCA_SUCCESS) {
+ osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+ }
+ break;
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+
+ p_dcb->p_echo_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA;
+ p_dcb->cout_oper |= BTA_HL_CO_PUT_ECHO_DATA_MASK;
+ p_dcb->ci_put_echo_data_status = BTA_HL_STATUS_FAIL;
+
+ bta_hl_co_put_echo_data(p_acb->app_id, p_mcb->mcl_handle,
+ p_dcb->p_echo_rx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_echo_rx_pkt),
+ BTA_HL_CI_PUT_ECHO_DATA_EVT);
+ break;
+ default:
+ APPL_TRACE_ERROR("Unknonw echo_oper=%d", p_dcb->echo_oper);
+ break;
+ }
+
+ } else {
+ p_dcb->cout_oper |= BTA_HL_CO_PUT_RX_DATA_MASK;
+ p_dcb->p_rx_pkt = p_data->mca_rcv_data_evt.p_pkt;
+
+ bta_hl_co_put_rx_data(
+ p_acb->app_id, p_dcb->mdl_handle, p_dcb->p_rx_pkt->len,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_rx_pkt), BTA_HL_CI_PUT_RX_DATA_EVT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_ci_put_echo_data
+ *
+ * Description Action routine for processing the call-in of the
+ * put echo data event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_ci_put_echo_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_PUT_ECHO_DATA_MASK;
+ osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
+ p_dcb->ci_put_echo_data_status = p_data->ci_get_put_echo_data.status;
+
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_CLOSE_CFM;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_ci_get_echo_data
+ *
+ * Description Action routine for processing the call-in of the
+ * get echo data event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_ci_get_echo_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_GET_ECHO_DATA_MASK;
+
+ if (!p_dcb->abort_oper) {
+ status = p_data->ci_get_put_echo_data.status;
+ if (status == BTA_HL_STATUS_OK) {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_MDL_CREATE_CFM;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT,
+ p_data);
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_ci_put_rx_data
+ *
+ * Description Action routine for processing the call-in of the
+ * put rx data event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_ci_put_rx_data");
+#endif
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_PUT_RX_DATA_MASK;
+ osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+ bta_hl_build_rcv_data_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ p_dcb->mdl_handle);
+ p_acb->p_cback(BTA_HL_DCH_RCV_DATA_IND_EVT, (tBTA_HL*)&evt_data);
+ if (p_dcb->close_pending) {
+ if (!p_dcb->cout_oper) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+ p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_ci_get_tx_data
+ *
+ * Description Action routine for processing the call-in of the
+ * get tx data event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT result;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ bool free_buf = false;
+ bool close_dch = false;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_ci_get_tx_data");
+#endif
+
+ if (p_data != NULL) {
+ status = p_data->ci_get_put_data.status;
+ APPL_TRACE_WARNING("%s: status=%d", __func__, status);
+ }
+
+ p_dcb->cout_oper &= ~BTA_HL_CO_GET_TX_DATA_MASK;
+
+ if (p_dcb->close_pending) {
+ status = BTA_HL_STATUS_FAIL;
+ free_buf = true;
+
+ if (!p_dcb->cout_oper) {
+ close_dch = true;
+ }
+ } else if (status == BTA_HL_STATUS_FAIL) {
+ free_buf = TRUE;
+ } else {
+ result = MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_tx_pkt);
+ if (result != MCA_SUCCESS) {
+ if (result == MCA_BUSY) {
+ status = BTA_HL_STATUS_DCH_BUSY;
+ } else {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ free_buf = true;
+ } else {
+ p_dcb->p_tx_pkt = NULL;
+ }
+ }
+
+ if (free_buf) osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+
+ bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ p_dcb->mdl_handle, status);
+ p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
+
+ if (close_dch) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_send_data
+ *
+ * Description Action routine for processing api send data request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+ bool success = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_send_data");
+#endif
+
+ if (!(p_dcb->cout_oper & BTA_HL_CO_GET_TX_DATA_MASK)) {
+ // p_dcb->chnl_cfg.fcs may be BTA_HL_MCA_USE_FCS (0x11) or BTA_HL_MCA_NO_FCS
+ // (0x10) or BTA_HL_DEFAULT_SOURCE_FCS (1)
+ bool fcs_use = (bool)(p_dcb->chnl_cfg.fcs & BTA_HL_MCA_FCS_USE_MASK);
+ p_dcb->p_tx_pkt = bta_hl_get_buf(p_data->api_send_data.pkt_size, fcs_use);
+ if (p_dcb->p_tx_pkt != NULL) {
+ bta_hl_co_get_tx_data(
+ p_acb->app_id, p_dcb->mdl_handle, p_data->api_send_data.pkt_size,
+ BTA_HL_GET_BUF_PTR(p_dcb->p_tx_pkt), BTA_HL_CI_GET_TX_DATA_EVT);
+ p_dcb->cout_oper |= BTA_HL_CO_GET_TX_DATA_MASK;
+ } else {
+ success = false;
+ }
+ } else {
+ success = false;
+ }
+
+ if (!success) {
+ bta_hl_build_send_data_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ p_dcb->mdl_handle, BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_SEND_DATA_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_close_cmpl
+ *
+ * Description Action routine for processing the close complete event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event = 0;
+ bool send_evt = true;
+ tBTA_HL_STATUS status;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_close_cmpl dch oper=%s",
+ bta_hl_dch_oper_code(p_dcb->dch_oper));
+#endif
+
+ switch (p_dcb->dch_oper) {
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+ bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_ABORT_CFM_EVT;
+ } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
+ bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
+ event = BTA_HL_DCH_ABORT_IND_EVT;
+ } else {
+ bta_hl_build_dch_open_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, BTA_HL_INVALID_MDL_HANDLE,
+ 0, 0, 0, 0, 0, BTA_HL_STATUS_FAIL);
+ event = BTA_HL_DCH_OPEN_CFM_EVT;
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
+ event = BTA_HL_DCH_RECONNECT_CFM_EVT;
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_CLOSE:
+ case BTA_HL_DCH_OP_REMOTE_DELETE:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+ case BTA_HL_DCH_OP_NONE:
+
+ bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, p_dcb->mdl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_CLOSE_CFM_EVT;
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_CLOSE:
+ bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, p_dcb->mdl_handle,
+ p_dcb->intentional_close);
+ event = BTA_HL_DCH_CLOSE_IND_EVT;
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+ bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_DCH_ABORT_CFM_EVT;
+ } else if (p_dcb->abort_oper & BTA_HL_ABORT_REMOTE_MASK) {
+ bta_hl_build_abort_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle);
+ event = BTA_HL_DCH_ABORT_IND_EVT;
+ } else {
+ bta_hl_build_dch_close_ind(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, p_dcb->mdl_handle,
+ p_dcb->intentional_close);
+ event = BTA_HL_DCH_CLOSE_IND_EVT;
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+ /* this is normal echo test close */
+ case BTA_HL_DCH_OP_REMOTE_CREATE:
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+ send_evt = false;
+ break;
+
+ default:
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_ERROR("DCH operation not found oper=%s",
+ bta_hl_dch_oper_code(p_dcb->dch_oper));
+#endif
+ send_evt = false;
+ break;
+ }
+
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ p_mcb->echo_test = false;
+ send_evt = false;
+
+ if (p_dcb->dch_oper != BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST) {
+ switch (p_dcb->echo_oper) {
+ case BTA_HL_ECHO_OP_CI_GET_ECHO_DATA:
+ case BTA_HL_ECHO_OP_SDP_INIT:
+ case BTA_HL_ECHO_OP_MDL_CREATE_CFM:
+ case BTA_HL_ECHO_OP_DCH_OPEN_CFM:
+ case BTA_HL_ECHO_OP_LOOP_BACK:
+
+ status = BTA_HL_STATUS_FAIL;
+ send_evt = true;
+ break;
+ case BTA_HL_ECHO_OP_OPEN_IND:
+ case BTA_HL_ECHO_OP_ECHO_PKT:
+ break;
+ default:
+ APPL_TRACE_ERROR("Invalid echo_oper=%d", p_dcb->echo_oper);
+ break;
+ }
+ } else {
+ status = p_dcb->ci_put_echo_data_status;
+ send_evt = true;
+ }
+
+ if (send_evt) {
+ bta_hl_build_echo_test_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, status);
+ event = BTA_HL_DCH_ECHO_TEST_CFM_EVT;
+ }
+ }
+
+ bta_hl_clean_mdl_cb(app_idx, mcl_idx, mdl_idx);
+
+ if (send_evt) {
+ if (p_acb->p_cback) {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("Send Event: %s", bta_hl_cback_evt_code(event));
+#endif
+ p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+ }
+ }
+ /* check cch close is in progress or not */
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_close_ind
+ *
+ * Description Action routine for processing the close indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_close_ind dch oper=%s",
+ bta_hl_dch_oper_code(p_dcb->dch_oper));
+#endif
+
+ p_dcb->intentional_close = false;
+ if (p_data->mca_evt.mca_data.close_ind.reason == L2CAP_DISC_OK) {
+ p_dcb->intentional_close = true;
+ }
+
+ if (!p_dcb->cout_oper) {
+ if ((p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_OPEN) &&
+ (p_dcb->dch_oper != BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CLOSE;
+ }
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ } else {
+ p_dcb->close_pending = true;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_close_cfm
+ *
+ * Description Action routine for processing the close confirmation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_close_cfm dch_oper=%s",
+ bta_hl_dch_oper_code(p_dcb->dch_oper));
+#endif
+
+ switch (p_dcb->dch_oper) {
+ case BTA_HL_DCH_OP_LOCAL_CLOSE:
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST:
+ case BTA_HL_DCH_OP_REMOTE_DELETE:
+ case BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT:
+ case BTA_HL_DCH_OP_NONE:
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ break;
+ default:
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_ERROR("Invalid dch_oper=%s for close cfm",
+ bta_hl_dch_oper_code(p_dcb->dch_oper));
+#endif
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_close
+ *
+ * Description Action routine for processing the DCH close request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_close");
+#endif
+ if (!p_dcb->cout_oper) {
+ p_dcb->close_pending = false;
+ if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE;
+ } else {
+ status = BTA_HL_STATUS_FAIL;
+ }
+
+ if ((status != BTA_HL_STATUS_OK) &&
+ (p_mcb->cch_close_dch_oper != BTA_HL_CCH_CLOSE_OP_DCH_CLOSE)) {
+ bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_data->api_dch_close.mdl_handle, status);
+ p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+ } else {
+ p_dcb->close_pending = true;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_open_ind
+ *
+ * Description Action routine for processing the open indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_DL_OPEN* p_open_ind = &p_data->mca_evt.mca_data.open_ind;
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
+ bool send_event = false;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_open_ind");
+#endif
+ if ((p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_OPEN) ||
+ (p_dcb->dch_oper == BTA_HL_DCH_OP_REMOTE_RECONNECT)) {
+ p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_ind->mdl;
+ p_dcb->mtu = p_open_ind->mtu;
+
+ evt_data.dch_open_ind.mdl_handle = p_dcb->mdl_handle;
+ evt_data.dch_open_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_open_ind.app_handle = p_acb->app_handle;
+
+ evt_data.dch_open_ind.local_mdep_id = p_dcb->local_mdep_id;
+ evt_data.dch_open_ind.mdl_id = p_dcb->mdl_id;
+ evt_data.dch_open_ind.mtu = p_dcb->mtu;
+
+ if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
+ evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+ p_dcb->is_the_first_reliable = true;
+ }
+ } else {
+ evt_data.dch_open_ind.dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ }
+ evt_data.dch_open_ind.first_reliable = p_dcb->is_the_first_reliable;
+
+ old_dch_oper = p_dcb->dch_oper;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+ }
+
+ switch (old_dch_oper) {
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+
+ p_dcb->dch_mode = evt_data.dch_open_ind.dch_mode;
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+ event = BTA_HL_DCH_OPEN_IND_EVT;
+ send_event = true;
+ } else {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_ECHO_PKT;
+ }
+
+ break;
+
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+
+ if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+ event = BTA_HL_DCH_RECONNECT_IND_EVT;
+ send_event = true;
+ } else {
+ if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+ } else {
+ APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (send_event) {
+ p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_open_cfm
+ *
+ * Description Action routine for processing the open confirmation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_DL_OPEN* p_open_cfm = &p_data->mca_evt.mca_data.open_cfm;
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ uint8_t old_dch_oper = BTA_HL_DCH_OP_NONE;
+ tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ bool send_event = false;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_open_cfm");
+#endif
+ if ((p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) ||
+ (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT)) {
+ p_dcb->mdl_handle = (tBTA_HL_MDL_HANDLE)p_open_cfm->mdl;
+ p_dcb->mtu = p_open_cfm->mtu;
+
+ /*todo verify dch_mode, mtu and fcs for reconnect */
+ if (p_dcb->chnl_cfg.fcr_opt.mode == L2CAP_FCR_ERTM_MODE) {
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ }
+
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+ if (dch_mode == BTA_HL_DCH_MODE_RELIABLE) {
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+ p_dcb->is_the_first_reliable = true;
+ }
+ }
+ }
+
+ bta_hl_build_dch_open_cfm(
+ &evt_data, p_acb->app_handle, p_mcb->mcl_handle, p_dcb->mdl_handle,
+ p_dcb->local_mdep_id, p_dcb->mdl_id, dch_mode,
+ p_dcb->is_the_first_reliable, p_dcb->mtu, BTA_HL_STATUS_OK);
+
+ old_dch_oper = p_dcb->dch_oper;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_NONE;
+ } else {
+ APPL_TRACE_ERROR("Error dch oper =%d", p_dcb->dch_oper);
+ return;
+ }
+
+ switch (old_dch_oper) {
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+
+ p_dcb->dch_mode = dch_mode;
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+ event = BTA_HL_DCH_OPEN_CFM_EVT;
+ send_event = true;
+ } else {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_LOOP_BACK;
+ if (MCA_WriteReq((tMCA_DL)p_dcb->mdl_handle, p_dcb->p_echo_tx_pkt) !=
+ MCA_SUCCESS) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_ECHO_TEST_EVT, p_data);
+ } else {
+ p_dcb->p_echo_tx_pkt = NULL;
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+
+ if (bta_hl_validate_chan_cfg(app_idx, mcl_idx, mdl_idx)) {
+ bta_hl_save_mdl_cfg(app_idx, mcl_idx, mdl_idx);
+ event = BTA_HL_DCH_RECONNECT_CFM_EVT;
+ send_event = true;
+ } else {
+ if (MCA_CloseReq((tMCA_DL)p_dcb->mdl_handle) == MCA_SUCCESS) {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT;
+ } else {
+ APPL_TRACE_ERROR("Unabel to close DCH for reconnect cfg mismatch");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_abort_ind
+ *
+ * Description Action routine for processing the abort indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_ind");
+#endif
+
+ p_dcb->abort_oper |= BTA_HL_ABORT_REMOTE_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_abort_cfm
+ *
+ * Description Action routine for processing the abort confirmation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_abort_cfm");
+#endif
+
+ if (p_dcb->abort_oper) {
+ if (p_data->mca_evt.mca_data.abort_cfm.rsp_code != MCA_RSP_SUCCESS) {
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+ bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("Not expecting Abort CFM ");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_abort
+ *
+ * Description Action routine for processing the abort request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT mca_result;
+ tBTA_HL evt_data;
+
+ if (((p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) ||
+ (p_mcb->sdp_oper == BTA_HL_SDP_OP_DCH_RECONNECT_INIT)) &&
+ (p_mcb->sdp_mdl_idx == mdl_idx)) {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ return;
+ } else if (p_dcb->echo_oper == BTA_HL_ECHO_OP_CI_GET_ECHO_DATA) {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ return;
+ }
+
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+
+ mca_result = MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+ if (mca_result != MCA_SUCCESS) {
+ if (mca_result == MCA_NO_RESOURCES) {
+ p_dcb->abort_oper |= BTA_HL_ABORT_PENDING_MASK;
+ } else {
+ if (p_dcb->abort_oper & BTA_HL_ABORT_LOCAL_MASK) {
+ bta_hl_build_abort_cfm(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, false);
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_abort abort_oper=0x%x", p_dcb->abort_oper);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_reconnect_ind
+ *
+ * Description Action routine for processing the reconnect indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_MDL_CFG* p_mdl_cfg;
+ tMCA_EVT_HDR* p_reconnect_ind = &p_data->mca_evt.mca_data.reconnect_ind;
+ uint8_t mdl_cfg_idx, in_use_mdl_idx, mdep_cfg_idx;
+ uint8_t rsp_code = MCA_RSP_SUCCESS;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_ind mdl_id=%d",
+ p_reconnect_ind->mdl_id);
+#endif
+
+ if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
+ &mdl_cfg_idx)) {
+ if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect_ind->mdl_id,
+ &in_use_mdl_idx)) {
+ p_mdl_cfg = BTA_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+
+ if (bta_hl_find_mdep_cfg_idx(app_idx, p_mdl_cfg->local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_RECONNECT;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->peer_mdep_id = 0xFF;
+ p_dcb->local_mdep_id = p_mdl_cfg->local_mdep_id;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->mdl_id = p_reconnect_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = true;
+ p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+ p_dcb->dch_mode = p_mdl_cfg->dch_mode;
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ } else {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+ } else {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+ } else {
+ rsp_code = MCA_RSP_BAD_MDL;
+ }
+
+ if (MCA_ReconnectMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+ p_dcb->mdl_id, rsp_code,
+ &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+ MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_reconnect_cfm
+ *
+ * Description Action routine for processing the reconenct confirmation
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RSP_EVT* p_reconnect_cfm = &p_data->mca_evt.mca_data.reconnect_cfm;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect_cfm");
+#endif
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+ p_data);
+ return;
+ }
+
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_RECONNECT) {
+ if (p_reconnect_cfm->rsp_code == MCA_RSP_SUCCESS) {
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+ if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
+ MCA_SUCCESS) {
+ /* should be able to abort so no checking of the return code */
+ MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_reconnect
+ *
+ * Description Action routine for processing the reconnect request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CHNL_CFG* p_chnl_cfg = NULL;
+ uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_reconnect");
+#endif
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
+ &sdp_idx)) {
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ if (MCA_ReconnectMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+ p_mcb->data_psm, p_dcb->mdl_id,
+ p_chnl_cfg) != MCA_SUCCESS) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_create_rsp
+ *
+ * Description Action routine for processing BTA_HL_API_DCH_CREATE_RSP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_API_DCH_CREATE_RSP* p_create_rsp = &p_data->api_dch_create_rsp;
+ uint8_t mca_rsp_code = MCA_RSP_SUCCESS;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_create_rsp");
+#endif
+ if (p_create_rsp->rsp_code == BTA_HL_DCH_CREATE_RSP_SUCCESS) {
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+ p_dcb->local_cfg = p_create_rsp->cfg_rsp;
+
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ } else {
+ mca_rsp_code = MCA_RSP_CFG_REJ;
+ }
+
+ if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+ p_dcb->mdl_id, p_dcb->local_cfg, mca_rsp_code,
+ &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_create_ind
+ *
+ * Description Action routine for processing
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CREATE_IND* p_create_ind = &p_data->mca_evt.mca_data.create_ind;
+ uint8_t mdep_cfg_idx;
+ uint8_t cfg_rsp;
+ uint8_t rsp_code = MCA_RSP_SUCCESS;
+ bool send_create_ind_evt = false;
+ tBTA_HL evt_data;
+ tBTA_HL_ECHO_CFG* p_echo_cfg;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_create_ind");
+#endif
+
+ if (bta_hl_find_mdep_cfg_idx(app_idx, p_create_ind->dep_id, &mdep_cfg_idx)) {
+ if (p_create_ind->dep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ if (bta_hl_find_echo_cfg_rsp(app_idx, mcl_idx, mdep_cfg_idx,
+ p_create_ind->cfg, &cfg_rsp)) {
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_OPEN;
+ p_dcb->local_mdep_id = p_create_ind->dep_id;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = cfg_rsp;
+ p_dcb->remote_cfg = p_create_ind->cfg;
+ p_dcb->mdl_id = p_create_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = false;
+ p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+ p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+ p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+ } else {
+ rsp_code = MCA_RSP_CFG_REJ;
+ }
+ } else
+
+ {
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_CREATE;
+ p_dcb->local_mdep_id = p_create_ind->dep_id;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->remote_cfg = p_create_ind->cfg;
+ p_dcb->mdl_id = p_create_ind->mdl_id;
+ p_dcb->mdl_cfg_idx_included = false;
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ send_create_ind_evt = true;
+ }
+ } else {
+ rsp_code = MCA_RSP_BAD_MDEP;
+ }
+
+ if (send_create_ind_evt) {
+ evt_data.dch_create_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.dch_create_ind.app_handle = p_acb->app_handle;
+ evt_data.dch_create_ind.local_mdep_id = p_dcb->local_mdep_id;
+ evt_data.dch_create_ind.mdl_id = p_dcb->mdl_id;
+ evt_data.dch_create_ind.cfg = p_dcb->remote_cfg;
+ bdcpy(evt_data.dch_create_ind.bd_addr, p_mcb->bd_addr);
+ p_acb->p_cback(BTA_HL_DCH_CREATE_IND_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ if (MCA_CreateMdlRsp((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+ p_dcb->mdl_id, p_dcb->local_cfg, rsp_code,
+ &p_dcb->chnl_cfg) != MCA_SUCCESS) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ } else {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ p_mcb->echo_test = true;
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_OPEN_IND;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_create_cfm
+ *
+ * Description Action routine for processing
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_CREATE_CFM* p_create_cfm = &p_data->mca_evt.mca_data.create_cfm;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_create_cfm");
+#endif
+
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+ p_data);
+ return;
+ }
+
+ if (p_dcb->dch_oper == BTA_HL_DCH_OP_LOCAL_OPEN) {
+ if (p_create_cfm->rsp_code == MCA_RSP_SUCCESS) {
+ if (bta_hl_validate_cfg(app_idx, mcl_idx, mdl_idx, p_create_cfm->cfg)) {
+ bta_hl_set_dch_chan_cfg(app_idx, mcl_idx, mdl_idx, p_data);
+
+ if (MCA_DataChnlCfg((tMCA_CL)p_mcb->mcl_handle, &p_dcb->chnl_cfg) !=
+ MCA_SUCCESS) {
+ /* this should not happen */
+ APPL_TRACE_ERROR("Unable to create data channel");
+ MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ } else {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ p_dcb->echo_oper = BTA_HL_ECHO_OP_DCH_OPEN_CFM;
+ }
+ }
+ } else {
+ MCA_Abort((tMCA_CL)p_mcb->mcl_handle);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("MCA Create- failed");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_mca_create
+ *
+ * Description Action routine for processing the MDL create request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tMCA_RESULT result;
+ uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_mca_create");
+#endif
+
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->ctrl_psm,
+ &sdp_idx) &&
+ bta_hl_validate_peer_cfg(app_idx, mcl_idx, mdl_idx, p_dcb->peer_mdep_id,
+ p_dcb->peer_mdep_role, sdp_idx)) {
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ result = MCA_CreateMdl((tMCA_CL)p_mcb->mcl_handle, p_dcb->local_mdep_id,
+ p_mcb->data_psm, p_dcb->mdl_id, p_dcb->peer_mdep_id,
+ p_dcb->local_cfg, NULL);
+ if (result != MCA_SUCCESS) {
+ APPL_TRACE_ERROR("MCA_CreateMdl FAIL mca_result=%d", result);
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("MCA Create- SDP idx or peer MDEP cfg not found");
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_sdp_fail
+ *
+ * Description Action routine for processing the SDP failed event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_dch_sdp_fail");
+#endif
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback
+ *
+ * Description This is the SDP callback function used by HL.
+ * This function will be executed by SDP when the service
+ * search is completed. If the search is successful, it
+ * finds the first record in the database that matches the
+ * UUID of the search. Then retrieves the scn from the
+ * record.
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback(uint8_t sdp_oper, uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, uint16_t status) {
+ tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_SDP_REC* p_hdp_rec;
+ tBTA_HL_CCH_SDP* p_cch_buf;
+ tBTA_HL_DCH_SDP* p_dch_buf;
+ tSDP_DISC_REC* p_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ tSDP_DISC_ATTR* p_attr;
+ uint8_t i, rec_cnt;
+ tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature;
+ bool sdp_parsing_ok = false, result = false;
+ uint16_t event;
+ tBTA_HL_MDL_CB* p_dcb;
+ uint16_t service_uuid;
+ uint16_t name_len;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "bta_hl_sdp_cback status:%d sdp_oper=%d app_idx=%d, mcl_idx=%d, "
+ "mdl_idx=%d",
+ status, sdp_oper, app_idx, mcl_idx, mdl_idx);
+#endif
+
+ rec_cnt = 0;
+ service_uuid = bta_hl_get_service_uuids(sdp_oper, app_idx, mcl_idx, mdl_idx);
+
+ if (status == SDP_SUCCESS || status == SDP_DB_FULL) {
+ memset(&p_cb->sdp, 0, sizeof(tBTA_HL_SDP));
+ do {
+ if (bta_hl_find_service_in_db(app_idx, mcl_idx, service_uuid, &p_rec)) {
+ p_hdp_rec = &p_cb->sdp.sdp_rec[rec_cnt];
+ p_cb->sdp.num_recs = rec_cnt + 1;
+ } else {
+ break;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
+ p_hdp_rec->ctrl_psm = (uint16_t)pe.params[0];
+ } else {
+ APPL_TRACE_WARNING("Control PSM not found");
+ break;
+ }
+ if (SDP_FindAddProtoListsElemInRec(p_rec, UUID_PROTOCOL_L2CAP, &pe)) {
+ p_hdp_rec->data_psm = (uint16_t)pe.params[0];
+ } else {
+ APPL_TRACE_WARNING("Data PSM not found");
+ break;
+ }
+
+ p_hdp_rec->srv_name[0] = '\0';
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->srv_name, p_attr->attr_value.v.array, name_len);
+ }
+
+ p_hdp_rec->srv_desp[0] = '\0';
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_DESCRIPTION);
+ if (p_attr != NULL) {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->srv_desp, p_attr->attr_value.v.array, name_len);
+ }
+
+ p_hdp_rec->provider_name[0] = '\0';
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME);
+ if (p_attr != NULL) {
+ if (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) < BT_MAX_SERVICE_NAME_LEN)
+ name_len = (uint16_t)SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ else
+ name_len = BT_MAX_SERVICE_NAME_LEN;
+ memcpy(p_hdp_rec->provider_name, p_attr->attr_value.v.array, name_len);
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_MCAP_SUP_PROC);
+ if (p_attr != NULL) {
+ p_hdp_rec->mcap_sup_proc = p_attr->attr_value.v.u8;
+ } else {
+ APPL_TRACE_WARNING("MCAP SUP PROC not found");
+ break;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HDP_SUP_FEAT_LIST);
+ if (p_attr != NULL) {
+ if (bta_hl_fill_sup_feature_list(p_attr, &sup_feature)) {
+ p_hdp_rec->num_mdeps = (uint8_t)sup_feature.num_elems;
+ APPL_TRACE_WARNING("bta_hl_sdp_cback num_mdeps %d",
+ sup_feature.num_elems);
+ for (i = 0; i < sup_feature.num_elems; i++) {
+ p_hdp_rec->mdep_cfg[i].data_type =
+ sup_feature.list_elem[i].data_type;
+ p_hdp_rec->mdep_cfg[i].mdep_id = sup_feature.list_elem[i].mdep_id;
+ p_hdp_rec->mdep_cfg[i].mdep_role =
+ sup_feature.list_elem[i].mdep_role;
+ /* Check MDEP Description pointer to prevent crash due to null
+ * pointer */
+ if (sup_feature.list_elem[i].p_mdep_desp != NULL) {
+ strlcpy(p_hdp_rec->mdep_cfg[i].mdep_desp,
+ sup_feature.list_elem[i].p_mdep_desp,
+ BTA_HL_MDEP_DESP_LEN);
+ } else {
+ APPL_TRACE_ERROR(
+ "bta_hl_sdp_cback Incorrect Mdep[%d] Description (Null ptr)",
+ i);
+ }
+ }
+
+ sdp_parsing_ok = true;
+ } else {
+ APPL_TRACE_WARNING("HDP supported feature list fill failed");
+ break;
+ }
+ } else {
+ APPL_TRACE_WARNING("HDP supported feature list not found");
+ break;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("record=%d ctrl_psm=%0x data_psm=%x", rec_cnt + 1,
+ p_hdp_rec->ctrl_psm, p_hdp_rec->data_psm);
+ APPL_TRACE_DEBUG("srv_name=[%s]", (p_hdp_rec->srv_name[0] != '\0')
+ ? p_hdp_rec->srv_name
+ : "NULL");
+ APPL_TRACE_DEBUG("srv_desp=[%s]", (p_hdp_rec->srv_desp[0] != '\0')
+ ? p_hdp_rec->srv_desp
+ : "NULL");
+ for (i = 0; i < sup_feature.num_elems; i++) {
+ APPL_TRACE_DEBUG(
+ "index=0x%02x mdep_id=0x%04x data type=0x%04x mdep role=%s(0x%02x)",
+ (i + 1), p_hdp_rec->mdep_cfg[i].mdep_id,
+ p_hdp_rec->mdep_cfg[i].data_type,
+ (p_hdp_rec->mdep_cfg[i].mdep_role == BTA_HL_MDEP_ROLE_SOURCE)
+ ? "Src"
+ : "Snk",
+ p_hdp_rec->mdep_cfg[i].mdep_role);
+ }
+ APPL_TRACE_DEBUG("provider_name=[%s]",
+ (p_hdp_rec->provider_name[0] != '\0')
+ ? p_hdp_rec->provider_name
+ : "NULL");
+ APPL_TRACE_DEBUG("found MCAP sup procedure=%d",
+ p_cb->sdp.sdp_rec[rec_cnt].mcap_sup_proc);
+#endif
+ rec_cnt++;
+ if (rec_cnt >= BTA_HL_NUM_SDP_RECS) {
+ APPL_TRACE_WARNING("No more spaces for SDP recs max_rec_cnt=%d",
+ BTA_HL_NUM_SDP_RECS);
+ break;
+ }
+
+ } while (true);
+ }
+
+ osi_free_and_reset((void**)&p_cb->p_db);
+
+ if ((status == SDP_SUCCESS || status == SDP_DB_FULL) && p_cb->sdp.num_recs &&
+ sdp_parsing_ok) {
+ result = true;
+ } else {
+ APPL_TRACE_WARNING(
+ "SDP Failed sdp_status=%d num_recs=%d sdp_parsing_ok=%d ", status,
+ p_cb->sdp.num_recs, sdp_parsing_ok);
+ }
+
+ p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+
+ switch (sdp_oper) {
+ case BTA_HL_SDP_OP_CCH_INIT:
+ case BTA_HL_SDP_OP_SDP_QUERY_NEW:
+ case BTA_HL_SDP_OP_SDP_QUERY_CURRENT:
+
+ /* send result in event back to BTA */
+ p_cch_buf = (tBTA_HL_CCH_SDP*)osi_malloc(sizeof(tBTA_HL_CCH_SDP));
+ if (result) {
+ if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT) {
+ event = BTA_HL_CCH_SDP_OK_EVT;
+ if (p_cb->close_pending) event = BTA_HL_CCH_SDP_FAIL_EVT;
+ } else {
+ event = BTA_HL_SDP_QUERY_OK_EVT;
+ }
+ } else {
+ if (sdp_oper == BTA_HL_SDP_OP_CCH_INIT)
+ event = BTA_HL_CCH_SDP_FAIL_EVT;
+ else
+ event = BTA_HL_SDP_QUERY_FAIL_EVT;
+ }
+ p_cch_buf->hdr.event = event;
+
+ p_cch_buf->app_idx = app_idx;
+ p_cch_buf->mcl_idx = mcl_idx;
+ p_cch_buf->release_mcl_cb = false;
+ if (sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)
+ p_cch_buf->release_mcl_cb = true;
+
+ bta_sys_sendmsg(p_cch_buf);
+ break;
+ case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+ case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+ p_dch_buf = (tBTA_HL_DCH_SDP*)osi_malloc(sizeof(tBTA_HL_DCH_SDP));
+ p_dch_buf->hdr.event = BTA_HL_DCH_SDP_FAIL_EVT;
+ p_dch_buf->app_idx = app_idx;
+ p_dch_buf->mcl_idx = mcl_idx;
+ p_dch_buf->mdl_idx = mdl_idx;
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->abort_oper & BTA_HL_ABORT_PENDING_MASK) {
+ p_dcb->abort_oper &= ~BTA_HL_ABORT_PENDING_MASK;
+ result = false;
+ }
+ if (result) {
+ if (sdp_oper == BTA_HL_SDP_OP_DCH_OPEN_INIT) {
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ p_dch_buf->hdr.event = BTA_HL_DCH_ECHO_TEST_EVT;
+ } else {
+ p_dch_buf->hdr.event = BTA_HL_DCH_OPEN_EVT;
+ }
+ } else {
+ p_dch_buf->hdr.event = BTA_HL_DCH_RECONNECT_EVT;
+ }
+ }
+ bta_sys_sendmsg(p_dch_buf);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback0
+ *
+ * Description This is the SDP callback function used by index = 0
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback0(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[0].sdp_oper, bta_hl_cb.scb[0].app_idx,
+ bta_hl_cb.scb[0].mcl_idx, bta_hl_cb.scb[0].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(0);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback1
+ *
+ * Description This is the SDP callback function used by index = 1
+ *
+ * Parameters status - status of the SDP callabck
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback1(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[1].sdp_oper, bta_hl_cb.scb[1].app_idx,
+ bta_hl_cb.scb[1].mcl_idx, bta_hl_cb.scb[1].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(1);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback2
+ *
+ * Description This is the SDP callback function used by index = 2
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback2(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[2].sdp_oper, bta_hl_cb.scb[2].app_idx,
+ bta_hl_cb.scb[2].mcl_idx, bta_hl_cb.scb[2].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(2);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback3
+ *
+ * Description This is the SDP callback function used by index = 3
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback3(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[3].sdp_oper, bta_hl_cb.scb[3].app_idx,
+ bta_hl_cb.scb[3].mcl_idx, bta_hl_cb.scb[3].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(3);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback4
+ *
+ * Description This is the SDP callback function used by index = 4
+ *
+ * Parameters status - status of the SDP callabck
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback4(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[4].sdp_oper, bta_hl_cb.scb[4].app_idx,
+ bta_hl_cb.scb[4].mcl_idx, bta_hl_cb.scb[4].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(4);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback5
+ *
+ * Description This is the SDP callback function used by index = 5
+ *
+ * Parameters status - status of the SDP callabck
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback5(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[5].sdp_oper, bta_hl_cb.scb[5].app_idx,
+ bta_hl_cb.scb[5].mcl_idx, bta_hl_cb.scb[5].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(5);
+}
+
+/******************************************************************************
+ *
+ * Function bta_hl_sdp_cback6
+ *
+ * Description This is the SDP callback function used by index = 6
+ *
+ * Returns void.
+ *
+ *****************************************************************************/
+static void bta_hl_sdp_cback6(uint16_t status) {
+ bta_hl_sdp_cback(bta_hl_cb.scb[6].sdp_oper, bta_hl_cb.scb[6].app_idx,
+ bta_hl_cb.scb[6].mcl_idx, bta_hl_cb.scb[6].mdl_idx, status);
+ bta_hl_deallocate_spd_cback(6);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_deallocate_spd_cback
+ *
+ * Description Deallocate a SDP control block
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx) {
+ tBTA_HL_SDP_CB* p_spd_cb = &bta_hl_cb.scb[sdp_cback_idx];
+
+ memset(p_spd_cb, 0, sizeof(tBTA_HL_SDP_CB));
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_deallocate_spd_cback index=%d", sdp_cback_idx);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_allocate_spd_cback
+ *
+ * Description Finds a not in used SDP control block index
+ *
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
+ uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx,
+ uint8_t* p_sdp_cback_idx) {
+ uint8_t i;
+ tSDP_DISC_CMPL_CB* p_cbcak = NULL;
+
+ for (i = 0; i < BTA_HL_NUM_SDP_CBACKS; i++) {
+ if (!bta_hl_cb.scb[i].in_use) {
+ p_cbcak = bta_hl_sdp_cback_arr[i];
+ bta_hl_cb.scb[i].in_use = true;
+ bta_hl_cb.scb[i].sdp_oper = sdp_oper;
+ bta_hl_cb.scb[i].app_idx = app_idx;
+ bta_hl_cb.scb[i].mcl_idx = mcl_idx;
+ bta_hl_cb.scb[i].mdl_idx = mdl_idx;
+ *p_sdp_cback_idx = i;
+ break;
+ }
+ }
+
+ if (i == BTA_HL_NUM_SDP_CBACKS) {
+ APPL_TRACE_WARNING("No scb is available to allocate")
+ } else {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_allocate_spd_cback cback_idx=%d ", i);
+ APPL_TRACE_DEBUG("sdp_oper=%d, app_idx=%d, mcl_idx=%d, mdl_idx=%d",
+ bta_hl_cb.scb[i].sdp_oper, bta_hl_cb.scb[i].app_idx,
+ bta_hl_cb.scb[i].mcl_idx, bta_hl_cb.scb[i].mdl_idx);
+#endif
+ }
+ return p_cbcak;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_init_sdp
+ *
+ * Description Action routine for processing the SDP initiattion request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper, uint8_t app_idx,
+ uint8_t mcl_idx, uint8_t mdl_idx) {
+ tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tSDP_UUID uuid_list;
+ uint16_t attr_list[BTA_HL_NUM_SRCH_ATTR];
+ uint16_t num_attrs = BTA_HL_NUM_SRCH_ATTR;
+ tBTA_HL_STATUS status;
+ uint8_t sdp_cback_idx;
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "bta_hl_init_sdp sdp_oper=%d app_idx=%d mcl_idx=%d, mdl_idx=%d", sdp_oper,
+ app_idx, mcl_idx, mdl_idx);
+#endif
+ p_cb->sdp_cback = bta_hl_allocate_spd_cback(sdp_oper, app_idx, mcl_idx,
+ mdl_idx, &sdp_cback_idx);
+ if (p_cb->sdp_cback != NULL) {
+ if (p_cb->p_db == NULL)
+ (p_cb->p_db = (tSDP_DISCOVERY_DB*)osi_malloc(BTA_HL_DISC_SIZE));
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_ADDITION_PROTO_DESC_LISTS;
+ attr_list[4] = ATTR_ID_SERVICE_NAME;
+ attr_list[5] = ATTR_ID_SERVICE_DESCRIPTION;
+ attr_list[6] = ATTR_ID_PROVIDER_NAME;
+ attr_list[7] = ATTR_ID_HDP_SUP_FEAT_LIST;
+ attr_list[8] = ATTR_ID_HDP_DATA_EXCH_SPEC;
+ attr_list[9] = ATTR_ID_HDP_MCAP_SUP_PROC;
+
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_HDP_PROFILE;
+ SDP_InitDiscoveryDb(p_cb->p_db, BTA_HL_DISC_SIZE, 1, &uuid_list, num_attrs,
+ attr_list);
+
+ if (!SDP_ServiceSearchAttributeRequest(p_cb->bd_addr, p_cb->p_db,
+ p_cb->sdp_cback)) {
+ status = BTA_HL_STATUS_FAIL;
+ } else {
+ status = BTA_HL_STATUS_OK;
+ }
+ } else {
+ status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+
+ if (status != BTA_HL_STATUS_OK) {
+ osi_free_and_reset((void**)&p_cb->p_db);
+ if (status != BTA_HL_STATUS_SDP_NO_RESOURCE)
+ bta_hl_deallocate_spd_cback(sdp_cback_idx);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_sdp_init
+ *
+ * Description Action routine for processing the CCH SDP init event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_init_sdp");
+#endif
+ if (p_cb->sdp_oper == BTA_HL_SDP_OP_NONE) {
+ p_cb->app_id = p_data->api_cch_open.app_id;
+ p_cb->sdp_oper = BTA_HL_SDP_OP_CCH_INIT;
+
+ if (bta_hl_init_sdp(p_cb->sdp_oper, app_idx, mcl_idx, 0xFF) !=
+ BTA_HL_STATUS_OK) {
+ p_cb->sdp_oper = BTA_HL_SDP_OP_NONE;
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+ }
+ } else {
+ APPL_TRACE_ERROR("SDP in use");
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_SDP_FAIL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_open
+ *
+ * Description Action routine for processing the CCH open request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ uint8_t sdp_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_open");
+#endif
+
+ if (bta_hl_find_sdp_idx_using_ctrl_psm(&p_mcb->sdp, p_mcb->req_ctrl_psm,
+ &sdp_idx)) {
+ p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+ p_mcb->data_psm = p_mcb->sdp.sdp_rec[sdp_idx].data_psm;
+ if (MCA_ConnectReq((tMCA_HANDLE)p_acb->app_handle, p_mcb->bd_addr,
+ p_mcb->ctrl_psm, p_mcb->sec_mask) != MCA_SUCCESS) {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+ } else {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_close
+ *
+ * Description Action routine for processing the CCH close request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_close mcl_handle=%d", p_mcb->mcl_handle);
+#endif
+ if (p_mcb->sdp_oper != BTA_HL_SDP_OP_CCH_INIT) {
+ if (p_mcb->mcl_handle) {
+ if (MCA_DisconnectReq((tMCA_HANDLE)p_mcb->mcl_handle) != MCA_SUCCESS) {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT,
+ p_data);
+ }
+ } else {
+ p_mcb->close_pending = true;
+ APPL_TRACE_DEBUG(
+ "No valid mcl_handle to stop the CCH setup now so wait until CCH is "
+ "up then close it");
+ }
+ } else {
+ p_mcb->close_pending = true;
+ APPL_TRACE_DEBUG(
+ "can not stop the CCH setup becasue SDP is in progress so wait until "
+ "it is done");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_close_cmpl
+ *
+ * Description Action routine for processing the CCH close complete event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ bool send_evt = true;
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_close_cmpl");
+#endif
+ bta_sys_conn_close(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+
+ if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE &&
+ p_mcb->force_close_local_cch_opening) {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
+ APPL_TRACE_DEBUG(
+ "change cch_oper from BTA_HL_CCH_OP_LOCAL_CLOSE to "
+ "BTA_HL_CCH_OP_LOCAL_OPEN");
+ }
+
+ switch (p_mcb->cch_oper) {
+ case BTA_HL_CCH_OP_LOCAL_OPEN:
+ bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+ p_mcb->mcl_handle, p_mcb->bd_addr,
+ BTA_HL_STATUS_FAIL);
+ event = BTA_HL_CCH_OPEN_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_LOCAL_CLOSE:
+ bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, BTA_HL_STATUS_OK);
+ event = BTA_HL_CCH_CLOSE_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_REMOTE_CLOSE:
+ bta_hl_build_cch_close_ind(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, p_mcb->intentional_close);
+ event = BTA_HL_CCH_CLOSE_IND_EVT;
+ break;
+ default:
+ send_evt = false;
+ break;
+ }
+
+ memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+
+ if (send_evt) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+
+ bta_hl_check_deregistration(app_idx, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_disconnect
+ *
+ * Description Action routine for processing the CCH disconnect indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb;
+ uint8_t i;
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_disconnect");
+#endif
+
+ p_mcb->intentional_close = false;
+ if (p_data->mca_evt.mca_data.disconnect_ind.reason == L2CAP_DISC_OK) {
+ p_mcb->intentional_close = true;
+ }
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+ if (p_dcb->in_use && (p_dcb->dch_state != BTA_HL_DCH_IDLE_ST)) {
+ if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_DCH_CLOSE_CMPL_EVT,
+ p_data);
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, i, BTA_HL_MCA_CLOSE_IND_EVT,
+ p_data);
+ }
+ }
+ }
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_CMPL_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_disc_open
+ *
+ * Description Action routine for disconnect the just opened Control
+ * channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_disc_open mcl_handle=0x%x close_pending=%d",
+ p_data->mca_evt.mcl_handle, p_mcb->close_pending);
+#endif
+
+ p_mcb->close_pending = false;
+ p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
+ bta_hl_cch_mca_close(app_idx, mcl_idx, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_rsp_tout
+ *
+ * Description Action routine for processing the MCAP response timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_rsp_tout");
+#endif
+
+ p_mcb->rsp_tout = true;
+
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_mca_connect
+ *
+ * Description Action routine for processing the CCH connect indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL evt_data;
+ tBTA_HL_EVT event;
+ bool send_event = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_cch_mca_connect mcl_handle=%d ",
+ p_data->mca_evt.mcl_handle);
+#endif
+
+ p_mcb->mcl_handle = p_data->mca_evt.mcl_handle;
+ bdcpy(p_mcb->bd_addr, p_data->mca_evt.mca_data.connect_ind.bd_addr);
+ p_mcb->cch_mtu = p_data->mca_evt.mca_data.connect_ind.mtu;
+
+ bta_sys_conn_open(BTA_ID_HL, p_acb->app_id, p_mcb->bd_addr);
+ switch (p_mcb->cch_oper) {
+ case BTA_HL_CCH_OP_LOCAL_OPEN:
+ bta_hl_build_cch_open_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+ p_mcb->mcl_handle, p_mcb->bd_addr,
+ BTA_HL_STATUS_OK);
+ event = BTA_HL_CCH_OPEN_CFM_EVT;
+ break;
+ case BTA_HL_CCH_OP_REMOTE_OPEN:
+ bta_hl_build_cch_open_ind(&evt_data, p_acb->app_handle, p_mcb->mcl_handle,
+ p_mcb->bd_addr);
+ event = BTA_HL_CCH_OPEN_IND_EVT;
+ break;
+ default:
+ send_event = false;
+ break;
+ }
+
+ p_mcb->cch_oper = BTA_HL_CCH_OP_NONE;
+ if (send_event) p_acb->p_cback(event, (tBTA_HL*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_mcap_ctrl_cback
+ *
+ * Description MCAP control callback function for HL.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+ tMCA_CTRL* p_data) {
+ bool send_event = true;
+ uint16_t mca_event;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_EVENT("bta_hl_mcap_ctrl_cback event[%s]",
+ bta_hl_mcap_evt_code(event));
+#endif
+
+ switch (event) {
+ case MCA_CREATE_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CREATE_IND_EVT;
+ break;
+ case MCA_CREATE_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CREATE_CFM_EVT;
+ break;
+ case MCA_RECONNECT_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_IND_EVT;
+ break;
+ case MCA_RECONNECT_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_RECONNECT_CFM_EVT;
+ break;
+ case MCA_ABORT_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_ABORT_IND_EVT;
+ break;
+ case MCA_ABORT_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_ABORT_CFM_EVT;
+ break;
+ case MCA_DELETE_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_DELETE_IND_EVT;
+ break;
+ case MCA_DELETE_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_DELETE_CFM_EVT;
+ break;
+ case MCA_CONNECT_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CONNECT_IND_EVT;
+ break;
+ case MCA_DISCONNECT_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_DISCONNECT_IND_EVT;
+ break;
+ case MCA_OPEN_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_OPEN_IND_EVT;
+ break;
+ case MCA_OPEN_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_OPEN_CFM_EVT;
+ break;
+ case MCA_CLOSE_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CLOSE_IND_EVT;
+ break;
+ case MCA_CLOSE_CFM_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CLOSE_CFM_EVT;
+ break;
+ case MCA_CONG_CHG_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_CONG_CHG_EVT;
+ break;
+ case MCA_RSP_TOUT_IND_EVT:
+ mca_event = (uint16_t)BTA_HL_MCA_RSP_TOUT_IND_EVT;
+ break;
+ case MCA_ERROR_RSP_EVT:
+
+ default:
+ send_event = false;
+ break;
+ }
+
+ if (send_event) {
+ tBTA_HL_MCA_EVT* p_msg =
+ (tBTA_HL_MCA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_EVT));
+ p_msg->hdr.event = mca_event;
+ p_msg->app_handle = (tBTA_HL_APP_HANDLE)handle;
+ p_msg->mcl_handle = (tBTA_HL_MCL_HANDLE)mcl;
+ memcpy(&p_msg->mca_data, p_data, sizeof(tMCA_CTRL));
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_mcap_data_cback
+ *
+ * Description MCAP data callback function for HL.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt) {
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ if (bta_hl_find_mdl_idx_using_handle((tBTA_HL_MDL_HANDLE)mdl, &app_idx,
+ &mcl_idx, &mdl_idx)) {
+ tBTA_HL_MCA_RCV_DATA_EVT* p_msg =
+ (tBTA_HL_MCA_RCV_DATA_EVT*)osi_malloc(sizeof(tBTA_HL_MCA_RCV_DATA_EVT));
+ p_msg->hdr.event = BTA_HL_MCA_RCV_DATA_EVT;
+ p_msg->app_idx = app_idx;
+ p_msg->mcl_idx = mcl_idx;
+ p_msg->mdl_idx = mdl_idx;
+ p_msg->p_pkt = p_pkt;
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+/*******************************************************************************
+ *
+ * Function bta_hl_mcap_evt_code
+ *
+ * Description get the MCAP event string pointer
+ *
+ * Returns char * - event string pointer
+ *
+ ******************************************************************************/
+static const char* bta_hl_mcap_evt_code(uint8_t evt_code) {
+ switch (evt_code) {
+ CASE_RETURN_STR(MCA_ERROR_RSP_EVT)
+ CASE_RETURN_STR(MCA_CREATE_IND_EVT)
+ CASE_RETURN_STR(MCA_CREATE_CFM_EVT)
+ CASE_RETURN_STR(MCA_RECONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_RECONNECT_CFM_EVT)
+ CASE_RETURN_STR(MCA_ABORT_IND_EVT)
+ CASE_RETURN_STR(MCA_ABORT_CFM_EVT)
+ CASE_RETURN_STR(MCA_DELETE_IND_EVT)
+ CASE_RETURN_STR(MCA_DELETE_CFM_EVT)
+ CASE_RETURN_STR(MCA_CONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_DISCONNECT_IND_EVT)
+ CASE_RETURN_STR(MCA_OPEN_IND_EVT)
+ CASE_RETURN_STR(MCA_OPEN_CFM_EVT)
+ CASE_RETURN_STR(MCA_CLOSE_IND_EVT)
+ CASE_RETURN_STR(MCA_CLOSE_CFM_EVT)
+ CASE_RETURN_STR(MCA_CONG_CHG_EVT)
+ CASE_RETURN_STR(MCA_RSP_TOUT_IND_EVT)
+ default:
+ return "Unknown MCAP event code";
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cback_evt_code
+ *
+ * Description get the HDP event string pointer
+ *
+ * Returns char * - event string pointer
+ *
+ ******************************************************************************/
+static const char* bta_hl_cback_evt_code(uint8_t evt_code) {
+ switch (evt_code) {
+ CASE_RETURN_STR(BTA_HL_CCH_OPEN_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_CCH_OPEN_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_CCH_CLOSE_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_CCH_CLOSE_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_OPEN_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_OPEN_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_CLOSE_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_CLOSE_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_RCV_DATA_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_REGISTER_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DEREGISTER_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_RECONNECT_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_RECONNECT_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_ECHO_TEST_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_SDP_QUERY_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_CONG_CHG_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_CREATE_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DELETE_MDL_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DELETE_MDL_CFM_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_ABORT_IND_EVT)
+ CASE_RETURN_STR(BTA_HL_DCH_ABORT_CFM_EVT)
+ default:
+ return "Unknown HDP event code";
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_oper_code
+ *
+ * Description Get the DCH operation string
+ *
+ * Returns char * - DCH operation string pointer
+ *
+ ******************************************************************************/
+static const char* bta_hl_dch_oper_code(tBTA_HL_DCH_OPER oper_code) {
+ switch (oper_code) {
+ CASE_RETURN_STR(BTA_HL_DCH_OP_NONE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_CREATE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_OPEN)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_OPEN)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_CLOSE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_DELETE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_DELETE)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_RECONNECT)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_REMOTE_RECONNECT)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST)
+ CASE_RETURN_STR(BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT)
+ default:
+ return "Unknown DCH oper code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_api.cc b/mtkbt/code/bt/bta/hl/bta_hl_api.cc
new file mode 100755
index 0000000..cc0ae06
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_api.cc
@@ -0,0 +1,489 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for the HeaLth device profile (HL)
+ * subsystem of BTA, Broadcom Corp's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_hl_reg = {bta_hl_hdl_event, BTA_HlDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_HlEnable
+ *
+ * Description Enable the HL subsystems. This function must be
+ * called before any other functions in the HL API are called.
+ * When the enable operation is completed the callback function
+ * will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+ *
+ * Parameters p_cback - HL event call back function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback) {
+ tBTA_HL_API_ENABLE* p_buf =
+ (tBTA_HL_API_ENABLE*)osi_malloc(sizeof(tBTA_HL_API_ENABLE));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_HL, &bta_hl_reg);
+
+ p_buf->hdr.event = BTA_HL_API_ENABLE_EVT;
+ p_buf->p_cback = p_ctrl_cback;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDisable
+ *
+ * Description Disable the HL subsystem.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ bta_sys_deregister(BTA_ID_HL);
+ p_buf->event = BTA_HL_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlUpdate
+ *
+ * Description Register an HDP application
+ *
+ * Parameters app_id - Application ID
+ * p_reg_param - non-platform related parameters for the
+ * HDP application
+ * p_cback - HL event callback fucntion
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+ bool is_register, tBTA_HL_CBACK* p_cback) {
+ tBTA_HL_API_UPDATE* p_buf =
+ (tBTA_HL_API_UPDATE*)osi_malloc(sizeof(tBTA_HL_API_UPDATE));
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ p_buf->hdr.event = BTA_HL_API_UPDATE_EVT;
+ p_buf->app_id = app_id;
+ p_buf->is_register = is_register;
+
+ if (is_register) {
+ p_buf->sec_mask =
+ (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_buf->p_cback = p_cback;
+ if (p_reg_param->p_srv_name)
+ strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->srv_name[0] = 0;
+
+ if (p_reg_param->p_srv_desp)
+ strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
+ else
+ p_buf->srv_desp[0] = 0;
+
+ if (p_reg_param->p_provider_name)
+ strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
+ BTA_PROVIDER_NAME_LEN);
+ else
+ p_buf->provider_name[0] = 0;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlRegister
+ *
+ * Description Register an HDP application
+ *
+ * Parameters app_id - Application ID
+ * p_reg_param - non-platform related parameters for the
+ * HDP application
+ * p_cback - HL event callback fucntion
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+ tBTA_HL_CBACK* p_cback) {
+ tBTA_HL_API_REGISTER* p_buf =
+ (tBTA_HL_API_REGISTER*)osi_malloc(sizeof(tBTA_HL_API_REGISTER));
+
+ p_buf->hdr.event = BTA_HL_API_REGISTER_EVT;
+ p_buf->app_id = app_id;
+ p_buf->sec_mask =
+ (p_reg_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_buf->p_cback = p_cback;
+
+ if (p_reg_param->p_srv_name)
+ strlcpy(p_buf->srv_name, p_reg_param->p_srv_name, BTA_SERVICE_NAME_LEN);
+ else
+ p_buf->srv_name[0] = 0;
+
+ if (p_reg_param->p_srv_desp)
+ strlcpy(p_buf->srv_desp, p_reg_param->p_srv_desp, BTA_SERVICE_DESP_LEN);
+ else
+ p_buf->srv_desp[0] = 0;
+
+ if (p_reg_param->p_provider_name)
+ strlcpy(p_buf->provider_name, p_reg_param->p_provider_name,
+ BTA_PROVIDER_NAME_LEN);
+ else
+ p_buf->provider_name[0] = 0;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDeregister
+ *
+ * Description Deregister an HDP application
+ *
+ * Parameters app_handle - Application handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle) {
+ tBTA_HL_API_DEREGISTER* p_buf =
+ (tBTA_HL_API_DEREGISTER*)osi_malloc(sizeof(tBTA_HL_API_DEREGISTER));
+
+ p_buf->hdr.event = BTA_HL_API_DEREGISTER_EVT;
+ p_buf->app_id = app_id;
+ p_buf->app_handle = app_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlCchOpen
+ *
+ * Description Open a Control channel connection with the specified BD
+ * address
+ *
+ * Parameters app_handle - Application Handle
+ * p_open_param - parameters for opening a control channel
+ *
+ * Returns void
+ *
+ * Note: The control PSM value is used to select which
+ * HDP insatnce should be used in case the peer device support
+ * multiple HDP instances. Also, if the control PSM value is
+ * zero then the first HDP instance is used for the control
+ * channel setup
+ ******************************************************************************/
+void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_CCH_OPEN_PARAM* p_open_param) {
+ tBTA_HL_API_CCH_OPEN* p_buf =
+ (tBTA_HL_API_CCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_CCH_OPEN));
+
+ p_buf->hdr.event = BTA_HL_API_CCH_OPEN_EVT;
+ p_buf->app_id = app_id;
+ p_buf->app_handle = app_handle;
+ p_buf->sec_mask =
+ (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ bdcpy(p_buf->bd_addr, p_open_param->bd_addr);
+ p_buf->ctrl_psm = p_open_param->ctrl_psm;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlCchClose
+ *
+ * Description Close a Control channel connection with the specified MCL
+ * handle
+ *
+ * Parameters mcl_handle - MCL handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle) {
+ tBTA_HL_API_CCH_CLOSE* p_buf =
+ (tBTA_HL_API_CCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_CCH_CLOSE));
+
+ p_buf->hdr.event = BTA_HL_API_CCH_CLOSE_EVT;
+ p_buf->mcl_handle = mcl_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchOpen
+ *
+ * Description Open a data channel connection with the specified DCH
+ * parameters
+ *
+ * Parameters mcl_handle - MCL handle
+ * p_open_param - parameters for opening a data channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_OPEN_PARAM* p_open_param) {
+ tBTA_HL_API_DCH_OPEN* p_buf =
+ (tBTA_HL_API_DCH_OPEN*)osi_malloc(sizeof(tBTA_HL_API_DCH_OPEN));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_OPEN_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_open_param->ctrl_psm;
+ p_buf->local_mdep_id = p_open_param->local_mdep_id;
+ p_buf->peer_mdep_id = p_open_param->peer_mdep_id;
+ p_buf->local_cfg = p_open_param->local_cfg;
+ p_buf->sec_mask =
+ (p_open_param->sec_mask | BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchReconnect
+ *
+ * Description Reconnect a data channel with the specified MDL_ID
+ *
+ * Parameters mcl_handle - MCL handle
+*8 p_recon_param - parameters for reconnecting a data channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param) {
+ tBTA_HL_API_DCH_RECONNECT* p_buf =
+ (tBTA_HL_API_DCH_RECONNECT*)osi_malloc(sizeof(tBTA_HL_API_DCH_RECONNECT));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_RECONNECT_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_recon_param->ctrl_psm;
+ p_buf->mdl_id = p_recon_param->mdl_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchClose
+ *
+ * Description Close a data channel with the specified MDL handle
+ *
+ * Parameters mdl_handle - MDL handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle) {
+ tBTA_HL_API_DCH_CLOSE* p_buf =
+ (tBTA_HL_API_DCH_CLOSE*)osi_malloc(sizeof(tBTA_HL_API_DCH_CLOSE));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_CLOSE_EVT;
+ p_buf->mdl_handle = mdl_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchAbort
+ *
+ * Description Abort the current data channel setup with the specified MCL
+ * handle
+ *
+ * Parameters mcl_handle - MCL handle
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle) {
+ tBTA_HL_API_DCH_ABORT* p_buf =
+ (tBTA_HL_API_DCH_ABORT*)osi_malloc(sizeof(tBTA_HL_API_DCH_ABORT));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_ABORT_EVT;
+ p_buf->mcl_handle = mcl_handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlSendData
+ *
+ * Description Send an APDU to the peer device
+ *
+ * Parameters mdl_handle - MDL handle
+ * pkt_size - size of the data packet to be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size) {
+ tBTA_HL_API_SEND_DATA* p_buf =
+ (tBTA_HL_API_SEND_DATA*)osi_malloc(sizeof(tBTA_HL_API_SEND_DATA));
+
+ p_buf->hdr.event = BTA_HL_API_SEND_DATA_EVT;
+ p_buf->mdl_handle = mdl_handle;
+ p_buf->pkt_size = pkt_size;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDeleteMdl
+ *
+ * Description Delete the specified MDL_ID within the specified MCL handle
+ *
+ * Parameters mcl_handle - MCL handle
+ * mdl_id - MDL ID
+ *
+ * Returns void
+ *
+ * note: If mdl_id = 0xFFFF then this means to delete all MDLs
+ * and this value can only be used with DeleteMdl request
+ * only not other requests
+ *
+ ******************************************************************************/
+void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_ID mdl_id) {
+ tBTA_HL_API_DELETE_MDL* p_buf =
+ (tBTA_HL_API_DELETE_MDL*)osi_malloc(sizeof(tBTA_HL_API_DELETE_MDL));
+
+ p_buf->hdr.event = BTA_HL_API_DELETE_MDL_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->mdl_id = mdl_id;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchEchoTest
+ *
+ * Description Initiate an echo test with the specified MCL handle
+ *
+ * Parameters mcl_handle - MCL handle
+*8 p_echo_test_param - parameters for echo testing
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param) {
+ tBTA_HL_API_DCH_ECHO_TEST* p_buf =
+ (tBTA_HL_API_DCH_ECHO_TEST*)osi_malloc(sizeof(tBTA_HL_API_DCH_ECHO_TEST));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_ECHO_TEST_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->ctrl_psm = p_echo_test_param->ctrl_psm;
+ p_buf->local_cfg = p_echo_test_param->local_cfg;
+ p_buf->pkt_size = p_echo_test_param->pkt_size;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlSdpQuery
+ *
+ * Description SDP query request for the specified BD address
+ *
+ * Parameters app_handle - application handle
+ * bd_addr - BD address
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr) {
+ tBTA_HL_API_SDP_QUERY* p_buf =
+ (tBTA_HL_API_SDP_QUERY*)osi_malloc(sizeof(tBTA_HL_API_SDP_QUERY));
+
+ p_buf->hdr.event = BTA_HL_API_SDP_QUERY_EVT;
+ p_buf->app_id = app_id;
+ p_buf->app_handle = app_handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchCreateMdlRsp
+ *
+ * Description Set the Response and configuration values for the Create MDL
+ * request
+ *
+ * Parameters mcl_handle - MCL handle
+ * p_rsp_param - parameters specified whether the request
+ * should be accepted or not and if it should be
+ * accepted, then it also specified the
+ * configuration response value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param) {
+ tBTA_HL_API_DCH_CREATE_RSP* p_buf = (tBTA_HL_API_DCH_CREATE_RSP*)osi_malloc(
+ sizeof(tBTA_HL_API_DCH_CREATE_RSP));
+
+ p_buf->hdr.event = BTA_HL_API_DCH_CREATE_RSP_EVT;
+ p_buf->mcl_handle = mcl_handle;
+ p_buf->mdl_id = p_rsp_param->mdl_id;
+ p_buf->local_mdep_id = p_rsp_param->local_mdep_id;
+ p_buf->rsp_code = p_rsp_param->rsp_code;
+ p_buf->cfg_rsp = p_rsp_param->cfg_rsp;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+#endif /* HL_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_ci.cc b/mtkbt/code/bt/bta/hl/bta_hl_ci.cc
new file mode 100755
index 0000000..b7bc2fd
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_ci.cc
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the HeaLth device profile (HL)
+ * subsystem call-in functions.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_ci.h"
+#include "bta_hl_co.h"
+#include "bta_hl_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_get_tx_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_get_tx_data call-out function.
+ *
+ * Parameters mdl_handle -MDL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle, tBTA_HL_STATUS status,
+ uint16_t evt) {
+ tBTA_HL_CI_GET_PUT_DATA* p_evt =
+ (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
+ status, evt);
+#endif
+
+ p_evt->hdr.event = evt;
+ p_evt->mdl_handle = mdl_handle;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_put_rx_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_put_rx_data call-out function.
+ *
+ * Parameters mdl_handle -MDL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status, uint16_t evt) {
+ tBTA_HL_CI_GET_PUT_DATA* p_evt =
+ (tBTA_HL_CI_GET_PUT_DATA*)osi_malloc(sizeof(tBTA_HL_CI_GET_PUT_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s mdl_handle=%d status=%d evt=%d\n", __func__, mdl_handle,
+ status, evt);
+#endif
+
+ p_evt->hdr.event = evt;
+ p_evt->mdl_handle = mdl_handle;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_get_echo_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_get_echo_data call-out function.
+ *
+ * Parameters mcl_handle -MCL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status, uint16_t evt) {
+ tBTA_HL_CI_ECHO_DATA* p_evt =
+ (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
+ status, evt);
+#endif
+
+ p_evt->hdr.event = evt;
+ p_evt->mcl_handle = mcl_handle;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_put_echo_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_put_echo_data call-out function.
+ *
+ * Parameters mcl_handle -MCL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status, uint16_t evt) {
+ tBTA_HL_CI_ECHO_DATA* p_evt =
+ (tBTA_HL_CI_ECHO_DATA*)osi_malloc(sizeof(tBTA_HL_CI_ECHO_DATA));
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("%s mcl_handle=%d status=%d evt=%d\n", __func__, mcl_handle,
+ status, evt);
+#endif
+
+ p_evt->hdr.event = evt;
+ p_evt->mcl_handle = mcl_handle;
+ p_evt->status = status;
+
+ bta_sys_sendmsg(p_evt);
+}
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_int.h b/mtkbt/code/bt/bta/hl/bta_hl_int.h
new file mode 100755
index 0000000..4d5168d
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_int.h
@@ -0,0 +1,853 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1998-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private file for the message access equipment (MSE)
+ * subsystem.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_INT_H
+#define BTA_HL_INT_H
+
+#include "bt_target.h"
+#include "bta_hl_api.h"
+#include "bta_hl_co.h"
+#include "bta_sys.h"
+#include "l2cdefs.h"
+
+typedef uint16_t(tBTA_HL_ALLOCATE_PSM)(void);
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+#ifndef BTA_HL_DISC_SIZE
+#define BTA_HL_DISC_SIZE 1600
+#endif
+#define BTA_HL_NUM_SRCH_ATTR 10
+#define BTA_HL_MIN_SDP_MDEP_LEN 7
+
+/* L2CAP defualt parameters */
+#define BTA_HL_L2C_TX_WIN_SIZE 10
+#define BTA_HL_L2C_MAX_TRANSMIT 32
+#define BTA_HL_L2C_RTRANS_TOUT 2000
+#define BTA_HL_L2C_MON_TOUT 12000
+#define BTA_HL_L2C_MPS 1017
+
+/* L2CAP FCS setting*/
+#define BTA_HL_MCA_USE_FCS MCA_FCS_USE
+#define BTA_HL_MCA_NO_FCS MCA_FCS_BYPASS
+#define BTA_HL_L2C_USE_FCS 1
+#define BTA_HL_L2C_NO_FCS 0
+#define BTA_HL_DEFAULT_SOURCE_FCS BTA_HL_L2C_USE_FCS
+#define BTA_HL_MCA_FCS_USE_MASK MCA_FCS_USE_MASK
+
+/* SDP Operations */
+#define BTA_HL_SDP_OP_NONE 0
+#define BTA_HL_SDP_OP_CCH_INIT 1
+#define BTA_HL_SDP_OP_DCH_OPEN_INIT 2
+#define BTA_HL_SDP_OP_DCH_RECONNECT_INIT 3
+#define BTA_HL_SDP_OP_SDP_QUERY_NEW 4
+#define BTA_HL_SDP_OP_SDP_QUERY_CURRENT 5
+
+typedef uint8_t tBTA_HL_SDP_OPER;
+
+/* CCH Operations */
+#define BTA_HL_CCH_OP_NONE 0
+#define BTA_HL_CCH_OP_LOCAL_OPEN 1
+#define BTA_HL_CCH_OP_REMOTE_OPEN 2
+#define BTA_HL_CCH_OP_LOCAL_CLOSE 3
+#define BTA_HL_CCH_OP_REMOTE_CLOSE 4
+
+typedef uint8_t tBTA_HL_CCH_OPER;
+
+/* Pending DCH close operations when closing a CCH */
+#define BTA_HL_CCH_CLOSE_OP_DCH_NONE 0
+#define BTA_HL_CCH_CLOSE_OP_DCH_ABORT 1
+#define BTA_HL_CCH_CLOSE_OP_DCH_CLOSE 2
+typedef uint8_t tBTA_HL_CCH_CLOSE_DCH_OPER;
+
+/* DCH Operations */
+#define BTA_HL_DCH_OP_NONE 0
+#define BTA_HL_DCH_OP_REMOTE_CREATE 1
+#define BTA_HL_DCH_OP_LOCAL_OPEN 2
+#define BTA_HL_DCH_OP_REMOTE_OPEN 3
+#define BTA_HL_DCH_OP_LOCAL_CLOSE 4
+#define BTA_HL_DCH_OP_REMOTE_CLOSE 5
+#define BTA_HL_DCH_OP_LOCAL_DELETE 6
+#define BTA_HL_DCH_OP_REMOTE_DELETE 7
+#define BTA_HL_DCH_OP_LOCAL_RECONNECT 8
+#define BTA_HL_DCH_OP_REMOTE_RECONNECT 9
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_ECHO_TEST 10
+#define BTA_HL_DCH_OP_LOCAL_CLOSE_RECONNECT 11
+
+typedef uint8_t tBTA_HL_DCH_OPER;
+
+/* Echo test Operations */
+#define BTA_HL_ECHO_OP_NONE 0
+#define BTA_HL_ECHO_OP_CI_GET_ECHO_DATA 1
+#define BTA_HL_ECHO_OP_SDP_INIT 2
+#define BTA_HL_ECHO_OP_MDL_CREATE_CFM 3
+#define BTA_HL_ECHO_OP_DCH_OPEN_CFM 4
+#define BTA_HL_ECHO_OP_LOOP_BACK 5
+#define BTA_HL_ECHO_OP_CI_PUT_ECHO_DATA 6
+#define BTA_HL_ECHO_OP_DCH_CLOSE_CFM 7
+#define BTA_HL_ECHO_OP_OPEN_IND 8
+#define BTA_HL_ECHO_OP_ECHO_PKT 9
+
+typedef uint8_t tBTA_HL_ECHO_OPER;
+
+/* abort status mask for abort_oper */
+
+#define BTA_HL_ABORT_NONE_MASK 0x00
+#define BTA_HL_ABORT_PENDING_MASK 0x01
+#define BTA_HL_ABORT_LOCAL_MASK 0x10
+#define BTA_HL_ABORT_REMOTE_MASK 0x20
+#define BTA_HL_ABORT_CCH_CLOSE_MASK 0x40
+
+/* call out mask for cout_oper */
+#define BTA_HL_CO_NONE_MASK 0x00
+#define BTA_HL_CO_GET_TX_DATA_MASK 0x01
+#define BTA_HL_CO_PUT_RX_DATA_MASK 0x02
+#define BTA_HL_CO_GET_ECHO_DATA_MASK 0x04
+#define BTA_HL_CO_PUT_ECHO_DATA_MASK 0x08
+
+typedef struct {
+ uint16_t mtu;
+ uint8_t fcs; /* '0' No FCS, otherwise '1' */
+} tBTA_HL_L2CAP_CFG_INFO;
+
+/* State Machine Events */
+enum {
+ /* these events are handled by the state machine */
+ BTA_HL_CCH_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HL),
+ BTA_HL_CCH_SDP_OK_EVT,
+ BTA_HL_CCH_SDP_FAIL_EVT,
+ BTA_HL_MCA_CONNECT_IND_EVT,
+ BTA_HL_MCA_DISCONNECT_IND_EVT,
+ BTA_HL_CCH_CLOSE_EVT,
+ BTA_HL_CCH_CLOSE_CMPL_EVT,
+ BTA_HL_MCA_RSP_TOUT_IND_EVT,
+ /* DCH EVENT */
+ BTA_HL_DCH_SDP_INIT_EVT,
+ BTA_HL_DCH_OPEN_EVT,
+ BTA_HL_MCA_CREATE_IND_EVT,
+ BTA_HL_MCA_CREATE_CFM_EVT,
+ BTA_HL_MCA_OPEN_IND_EVT,
+
+ BTA_HL_MCA_OPEN_CFM_EVT,
+ BTA_HL_DCH_CLOSE_EVT,
+ BTA_HL_MCA_CLOSE_IND_EVT,
+ BTA_HL_MCA_CLOSE_CFM_EVT,
+ BTA_HL_API_SEND_DATA_EVT,
+
+ BTA_HL_MCA_RCV_DATA_EVT,
+ BTA_HL_DCH_CLOSE_CMPL_EVT,
+ BTA_HL_DCH_RECONNECT_EVT,
+ BTA_HL_DCH_SDP_FAIL_EVT,
+ BTA_HL_MCA_RECONNECT_IND_EVT,
+
+ BTA_HL_MCA_RECONNECT_CFM_EVT,
+ BTA_HL_DCH_CLOSE_ECHO_TEST_EVT,
+ BTA_HL_API_DCH_CREATE_RSP_EVT,
+ BTA_HL_DCH_ABORT_EVT,
+ BTA_HL_MCA_ABORT_IND_EVT,
+
+ BTA_HL_MCA_ABORT_CFM_EVT,
+ BTA_HL_MCA_CONG_CHG_EVT,
+ BTA_HL_CI_GET_TX_DATA_EVT,
+ BTA_HL_CI_PUT_RX_DATA_EVT,
+ BTA_HL_CI_GET_ECHO_DATA_EVT,
+ BTA_HL_DCH_ECHO_TEST_EVT,
+ BTA_HL_CI_PUT_ECHO_DATA_EVT,
+
+ /* these events are handled outside the state machine */
+ BTA_HL_API_ENABLE_EVT,
+ BTA_HL_API_DISABLE_EVT,
+ BTA_HL_API_UPDATE_EVT,
+ BTA_HL_API_REGISTER_EVT,
+ BTA_HL_API_DEREGISTER_EVT,
+ BTA_HL_API_CCH_OPEN_EVT,
+ BTA_HL_API_CCH_CLOSE_EVT,
+ BTA_HL_API_DCH_OPEN_EVT,
+ BTA_HL_API_DCH_RECONNECT_EVT,
+ BTA_HL_API_DCH_CLOSE_EVT,
+ BTA_HL_API_DELETE_MDL_EVT,
+ BTA_HL_API_DCH_ABORT_EVT,
+
+ BTA_HL_API_DCH_ECHO_TEST_EVT,
+ BTA_HL_API_SDP_QUERY_EVT,
+ BTA_HL_SDP_QUERY_OK_EVT,
+ BTA_HL_SDP_QUERY_FAIL_EVT,
+ BTA_HL_MCA_DELETE_IND_EVT,
+ BTA_HL_MCA_DELETE_CFM_EVT
+};
+typedef uint16_t tBTA_HL_INT_EVT;
+
+#define BTA_HL_DCH_EVT_MIN BTA_HL_DCH_SDP_INIT_EVT
+#define BTA_HL_DCH_EVT_MAX 0xFFFF
+
+/* state machine states */
+enum {
+ BTA_HL_CCH_IDLE_ST = 0, /* Idle */
+ BTA_HL_CCH_OPENING_ST, /* Opening a connection*/
+ BTA_HL_CCH_OPEN_ST, /* Connection is open */
+ BTA_HL_CCH_CLOSING_ST /* Closing is in progress */
+};
+typedef uint8_t tBTA_HL_CCH_STATE;
+
+enum {
+ BTA_HL_DCH_IDLE_ST = 0, /* Idle */
+ BTA_HL_DCH_OPENING_ST, /* Opening a connection*/
+ BTA_HL_DCH_OPEN_ST, /* Connection is open */
+ BTA_HL_DCH_CLOSING_ST /* Closing is in progress */
+};
+typedef uint8_t tBTA_HL_DCH_STATE;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_CTRL_CBACK* p_cback; /* pointer to control callback function */
+} tBTA_HL_API_ENABLE;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_id;
+ bool is_register; /* Update HL application due to register or deregister */
+ tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
+ tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+ tBTA_SEC sec_mask; /* security mask for accepting conenction*/
+ char srv_name[BTA_SERVICE_NAME_LEN +
+ 1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+ the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+ the SDP; null terminated */
+
+} tBTA_HL_API_UPDATE;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_id;
+ tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
+ tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+ tBTA_SEC sec_mask; /* security mask for accepting conenction*/
+ char srv_name[BTA_SERVICE_NAME_LEN +
+ 1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+ the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+ the SDP; null terminated */
+} tBTA_HL_API_REGISTER;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_id;
+ tBTA_HL_CBACK* p_cback; /* pointer to application callback function */
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_API_DEREGISTER;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_id;
+ tBTA_HL_APP_HANDLE app_handle;
+ uint16_t ctrl_psm;
+ BD_ADDR bd_addr; /* Address of peer device */
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_CCH_OPEN;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_CCH_CLOSE;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ uint16_t ctrl_psm;
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_API_DCH_OPEN;
+
+typedef struct {
+ BT_HDR hdr;
+
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ uint16_t ctrl_psm;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DCH_RECONNECT;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+} tBTA_HL_API_DCH_CLOSE;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_API_DELETE_MDL;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_API_DCH_ABORT;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ uint16_t pkt_size;
+} tBTA_HL_API_SEND_DATA;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ uint16_t ctrl_psm;
+ uint16_t pkt_size;
+ tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_API_DCH_ECHO_TEST;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+ bool release_mcl_cb;
+} tBTA_HL_CCH_SDP;
+
+/* MCA callback event parameters. */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tMCA_CTRL mca_data;
+} tBTA_HL_MCA_EVT;
+
+/* MCA callback event parameters. */
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+ uint8_t mdl_idx;
+ BT_HDR* p_pkt;
+} tBTA_HL_MCA_RCV_DATA_EVT;
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+ uint8_t mdl_idx;
+} tBTA_HL_DCH_SDP;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_APP_HANDLE app_handle;
+ uint8_t app_id;
+ BD_ADDR bd_addr; /* Address of peer device */
+} tBTA_HL_API_SDP_QUERY;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_DCH_CREATE_RSP rsp_code;
+ tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_API_DCH_CREATE_RSP;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_STATUS status;
+} tBTA_HL_CI_GET_PUT_DATA;
+
+typedef struct {
+ BT_HDR hdr;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_STATUS status;
+} tBTA_HL_CI_ECHO_DATA;
+
+/* union of all state machine event data types */
+typedef union {
+ BT_HDR hdr;
+ tBTA_HL_API_ENABLE api_enable; /* data for BTA_MSE_API_ENABLE_EVT */
+ tBTA_HL_API_UPDATE api_update;
+ tBTA_HL_API_REGISTER api_reg;
+ tBTA_HL_API_DEREGISTER api_dereg;
+ tBTA_HL_API_CCH_OPEN api_cch_open;
+ tBTA_HL_API_CCH_CLOSE api_cch_close;
+ tBTA_HL_API_DCH_CREATE_RSP api_dch_create_rsp;
+ tBTA_HL_API_DCH_OPEN api_dch_open;
+ tBTA_HL_API_DCH_RECONNECT api_dch_reconnect;
+ tBTA_HL_API_DCH_CLOSE api_dch_close;
+ tBTA_HL_API_DELETE_MDL api_delete_mdl;
+ tBTA_HL_API_DCH_ABORT api_dch_abort;
+ tBTA_HL_API_SEND_DATA api_send_data;
+ tBTA_HL_API_DCH_ECHO_TEST api_dch_echo_test;
+ tBTA_HL_API_SDP_QUERY api_sdp_query;
+
+ tBTA_HL_CCH_SDP cch_sdp;
+ tBTA_HL_MCA_EVT mca_evt;
+ tBTA_HL_MCA_RCV_DATA_EVT mca_rcv_data_evt;
+ tBTA_HL_DCH_SDP dch_sdp; /* for DCH_OPEN_EVT and DCH_RECONNECT_EVT */
+ tBTA_HL_CI_GET_PUT_DATA ci_get_put_data;
+ tBTA_HL_CI_ECHO_DATA ci_get_put_echo_data;
+} tBTA_HL_DATA;
+
+typedef struct {
+ bool in_use;
+ uint16_t mdl_id;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_DCH_OPER dch_oper;
+ bool intentional_close;
+ tBTA_HL_DCH_STATE dch_state;
+ uint8_t abort_oper;
+ uint16_t req_data_psm;
+ uint16_t max_rx_apdu_size;
+ uint16_t max_tx_apdu_size;
+ BT_HDR* p_tx_pkt;
+ BT_HDR* p_rx_pkt;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ uint8_t local_mdep_cfg_idx;
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_HL_DCH_CFG remote_cfg;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+ uint16_t peer_data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ tBTA_HL_DCH_MODE dch_mode;
+ tBTA_SEC sec_mask;
+ bool is_the_first_reliable;
+ bool delete_mdl;
+ uint16_t mtu;
+ tMCA_CHNL_CFG chnl_cfg;
+ bool mdl_cfg_idx_included;
+ uint8_t mdl_cfg_idx;
+ uint8_t echo_oper;
+ bool cong;
+ bool close_pending;
+ uint8_t cout_oper;
+ BT_HDR* p_echo_tx_pkt;
+ BT_HDR* p_echo_rx_pkt;
+ tBTA_HL_STATUS ci_put_echo_data_status;
+} tBTA_HL_MDL_CB;
+
+typedef struct {
+ tBTA_HL_MDL_CB mdl[BTA_HL_NUM_MDLS_PER_MCL];
+ tBTA_HL_DELETE_MDL delete_mdl;
+ bool in_use;
+ tBTA_HL_CCH_STATE cch_state;
+ uint16_t req_ctrl_psm;
+ uint16_t ctrl_psm;
+ uint16_t data_psm;
+ BD_ADDR bd_addr;
+ uint16_t cch_mtu;
+ uint16_t sec_mask;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */
+ tSDP_DISC_CMPL_CB* sdp_cback;
+ tBTA_HL_SDP_OPER sdp_oper;
+ bool close_pending;
+ uint8_t sdp_mdl_idx;
+ tBTA_HL_SDP sdp;
+ uint8_t cch_oper;
+ uint8_t force_close_local_cch_opening;
+ bool intentional_close;
+ bool rsp_tout;
+ uint8_t timer_oper;
+ bool echo_test;
+ uint8_t echo_mdl_idx;
+ uint8_t cch_close_dch_oper;
+ uint8_t app_id;
+} tBTA_HL_MCL_CB;
+
+typedef struct {
+ tBTA_HL_MCL_CB mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+ tBTA_HL_CBACK* p_cback; /* pointer to control callback function */
+ bool in_use; /* this CB is in use*/
+ bool deregistering;
+ uint8_t app_id;
+ uint32_t sdp_handle; /* SDP record handle */
+ tBTA_HL_SUP_FEATURE sup_feature;
+ tBTA_HL_MDL_CFG mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+ tBTA_HL_DEVICE_TYPE dev_type;
+ tBTA_HL_APP_HANDLE app_handle;
+ uint16_t ctrl_psm; /* L2CAP PSM for the MCAP control channel */
+ uint16_t data_psm; /* L2CAP PSM for the MCAP data channel */
+ uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+
+ char srv_name[BTA_SERVICE_NAME_LEN +
+ 1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+ the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+ the SDP; null terminated */
+
+ tMCA_CTRL_CBACK* p_mcap_cback; /* pointer to MCAP callback function */
+ tMCA_DATA_CBACK* p_data_cback;
+} tBTA_HL_APP_CB;
+
+typedef struct {
+ bool in_use;
+ tBTA_HL_SDP_OPER sdp_oper;
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+ uint8_t mdl_idx;
+} tBTA_HL_SDP_CB;
+
+typedef struct {
+ bool in_use;
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+} tBTA_HL_TIMER_CB;
+
+typedef struct {
+ tBTA_HL_APP_CB acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+ tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
+ bool enable;
+ bool disabling;
+
+ tBTA_HL_SDP_CB scb[BTA_HL_NUM_SDP_CBACKS];
+ tBTA_HL_TIMER_CB tcb[BTA_HL_NUM_TIMERS];
+ bool enable_random_psm;
+ tBTA_HL_ALLOCATE_PSM* p_alloc_psm;
+} tBTA_HL_CB;
+
+/******************************************************************************
+ * Configuration Definitions
+ ******************************************************************************/
+/* Configuration structure */
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* HL control block */
+extern tBTA_HL_CB bta_hl_cb;
+
+#define BTA_HL_GET_CB_PTR() &(bta_hl_cb)
+#define BTA_HL_GET_APP_CB_PTR(app_idx) &(bta_hl_cb.acb[(app_idx)])
+#define BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
+ &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
+ &(bta_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[(mdl_idx)])
+#define BTA_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
+ &(bta_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTA_HL_GET_ECHO_CFG_PTR(app_idx) \
+ &(bta_hl_cb.acb[(app_idx)].sup_feature.echo_cfg)
+#define BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx) \
+ &(bta_hl_cb.acb[(app_idx)].sup_feature.mdep[(mdep_cfg_idx)].mdep_cfg)
+#define BTA_HL_GET_DATA_CFG_PTR(app_idx, mdep_cfg_idx, data_cfg_idx) \
+ &(bta_hl_cb.acb[(app_idx)] \
+ .sup_feature.mdep[(mdep_cfg_idx)] \
+ .mdep_cfg.data_cfg[(data_cfg_idx)])
+#define BTA_HL_GET_BUF_PTR(p_pkt) \
+ ((uint8_t*)((uint8_t*)((p_pkt) + 1) + (p_pkt)->offset))
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+/* main */
+extern bool bta_hl_hdl_event(BT_HDR* p_msg);
+/* sdp */
+extern bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
+ tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list);
+extern tBTA_HL_STATUS bta_hl_sdp_update(uint8_t app_id);
+extern tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx);
+extern tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
+ const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec);
+
+/* action routines */
+extern void bta_hl_dch_ci_get_tx_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_put_rx_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_get_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+extern void bta_hl_dch_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_ci_put_echo_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_send_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sdp_fail(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_cong_change(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_reconnect(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_close_echo_test(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_create_rsp(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_rcv_data(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_delete_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+extern void bta_hl_dch_mca_delete_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_delete(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_abort(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_open_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_open_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create_ind(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create_cfm(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_mca_create(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_deallocate_spd_cback(uint8_t sdp_cback_idx);
+extern tSDP_DISC_CMPL_CB* bta_hl_allocate_spd_cback(tBTA_HL_SDP_OPER sdp_oper,
+ uint8_t app_idx,
+ uint8_t mcl_idx,
+ uint8_t mdl_idx,
+ uint8_t* p_sdp_cback_idx);
+extern tBTA_HL_STATUS bta_hl_init_sdp(tBTA_HL_SDP_OPER sdp_oper,
+ uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern void bta_hl_cch_sdp_init(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_open(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_close(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_close_cmpl(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_disconnect(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_disc_open(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_rsp_tout(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+extern void bta_hl_cch_mca_connect(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+
+/* State machine drivers */
+extern void bta_hl_cch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
+ uint16_t event, tBTA_HL_DATA* p_data);
+extern void bta_hl_dch_sm_execute(uint8_t inst_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, uint16_t event,
+ tBTA_HL_DATA* p_data);
+/* MCAP callback functions */
+extern void bta_hl_mcap_ctrl_cback(tMCA_HANDLE handle, tMCA_CL mcl,
+ uint8_t event, tMCA_CTRL* p_data);
+
+extern void bta_hl_mcap_data_cback(tMCA_DL mdl, BT_HDR* p_pkt);
+
+/* utility functions */
+extern bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, uint16_t ctrl_psm);
+extern bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp,
+ uint16_t ctrl_psm,
+ uint8_t* p_sdp_idx);
+extern uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size);
+extern uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu);
+extern uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps);
+extern uint16_t bta_hl_set_mps(uint16_t mtu);
+extern void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use);
+extern bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
+ uint16_t service_uuid,
+ tSDP_DISC_REC** pp_rec);
+extern uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
+ uint8_t mcl_idx, uint8_t mdl_idx);
+extern bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdep_idx, uint8_t cfg,
+ uint8_t* p_cfg_rsp);
+extern bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, uint8_t cfg);
+extern bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx);
+extern bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx, uint8_t* p_mdl_idx);
+extern uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx,
+ uint8_t* p_mdl_idx);
+extern bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint16_t mdl_id, uint8_t* p_mdl_idx);
+extern bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx);
+extern bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx);
+extern bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx);
+extern bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
+extern bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ uint8_t* p_app_idx);
+extern bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+ uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx);
+extern bool bta_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+ uint8_t* p_mcl_idx);
+extern bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx,
+ uint8_t mcl_idx);
+extern bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx,
+ uint8_t start_mdl_cfg_idx,
+ uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_MDL_ID mdl_id,
+ uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time);
+extern void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n);
+extern void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id);
+extern bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_delete_mdl_cfg(uint8_t app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id);
+extern bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx,
+ tBTA_HL_MDEP_ID local_mdep_id,
+ uint8_t* p_mdep_cfg_idx);
+extern void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
+ uint16_t* p_rx_apu_size,
+ uint16_t* p_tx_apu_size);
+extern bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx,
+ tBTA_HL_MDEP_ID peer_mdep_id,
+ tBTA_HL_MDEP_ROLE peer_mdep_role,
+ uint8_t sdp_idx);
+extern tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdep_cfg_idx,
+ tBTA_HL_DCH_CFG local_cfg);
+
+extern bool bta_hl_validate_reconnect_params(
+ uint8_t app_idx, uint8_t mcl_idx, tBTA_HL_API_DCH_RECONNECT* p_reconnect,
+ uint8_t* p_mdep_cfg_idx, uint8_t* p_mdl_cfg_idx);
+extern bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx);
+extern bool bta_hl_is_a_duplicate_id(uint8_t app_id);
+extern bool bta_hl_find_avail_app_idx(uint8_t* p_idx);
+extern tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register);
+extern tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx);
+extern void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data);
+extern void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+extern bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
+ tBTA_HL_L2CAP_CFG_INFO* p_cfg);
+extern bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern bool bta_hl_is_cong_on(uint8_t app_id, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id);
+extern void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data, bool check_dch_setup);
+extern void bta_hl_clean_app(uint8_t app_idx);
+extern void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data);
+extern void bta_hl_check_disable(tBTA_HL_DATA* p_data);
+extern void bta_hl_build_abort_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle);
+extern void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ bool intentional);
+extern void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle);
+extern void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr, tBTA_HL_STATUS status);
+extern void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ BD_ADDR bd_addr);
+extern void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ bool intentional);
+
+extern void bta_hl_build_dch_open_cfm(
+ tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle, tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_MDEP_ID local_mdep_id, tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_DCH_MODE dch_mode, bool first_reliable, uint16_t mtu,
+ tBTA_HL_STATUS status);
+
+extern void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status);
+extern void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+ tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr, tBTA_HL_SDP* p_sdp,
+ tBTA_HL_STATUS status);
+
+#if (BTA_HL_DEBUG == TRUE)
+extern const char* bta_hl_status_code(tBTA_HL_STATUS status);
+extern const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code);
+#endif
+
+#endif /* BTA_MSE_INT_H */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_main.cc b/mtkbt/code/bt/bta/hl/bta_hl_main.cc
new file mode 100755
index 0000000..bc8f396
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_main.cc
@@ -0,0 +1,1872 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1998-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HeaLth device profile main functions and state
+ * machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "bta_hl_int.h"
+#include "l2c_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+#if (BTA_HL_DEBUG == TRUE)
+static const char* bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code);
+static const char* bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code);
+#endif
+
+extern uint16_t L2CA_AllocateRandomPsm(void);
+extern uint16_t L2CA_AllocatePsm(void);
+/*****************************************************************************
+ * DCH State Table
+ ****************************************************************************/
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+/* state machine action enumeration list for DCH */
+/* The order of this enumeration must be the same as bta_hl_dch_act_tbl[] */
+enum {
+ BTA_HL_DCH_MCA_CREATE,
+ BTA_HL_DCH_MCA_CREATE_CFM,
+ BTA_HL_DCH_MCA_CREATE_IND,
+ BTA_HL_DCH_MCA_OPEN_CFM,
+ BTA_HL_DCH_MCA_OPEN_IND,
+ BTA_HL_DCH_MCA_CLOSE,
+ BTA_HL_DCH_MCA_CLOSE_CFM,
+ BTA_HL_DCH_MCA_CLOSE_IND,
+ BTA_HL_DCH_CLOSE_CMPL,
+ BTA_HL_DCH_MCA_RCV_DATA,
+
+ BTA_HL_DCH_SDP_INIT,
+ BTA_HL_DCH_MCA_RECONNECT,
+ BTA_HL_DCH_MCA_RECONNECT_IND,
+ BTA_HL_DCH_MCA_RECONNECT_CFM,
+ BTA_HL_DCH_CLOSE_ECHO_TEST,
+ BTA_HL_DCH_CREATE_RSP,
+ BTA_HL_DCH_MCA_ABORT,
+ BTA_HL_DCH_MCA_ABORT_IND,
+ BTA_HL_DCH_MCA_ABORT_CFM,
+ BTA_HL_DCH_MCA_CONG_CHANGE,
+
+ BTA_HL_DCH_SDP_FAIL,
+ BTA_HL_DCH_SEND_DATA,
+ BTA_HL_DCH_CI_GET_TX_DATA,
+ BTA_HL_DCH_CI_PUT_RX_DATA,
+ BTA_HL_DCH_CI_GET_ECHO_DATA,
+ BTA_HL_DCH_ECHO_TEST,
+ BTA_HL_DCH_CI_PUT_ECHO_DATA,
+ BTA_HL_DCH_IGNORE
+};
+
+typedef void (*tBTA_HL_DCH_ACTION)(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx, tBTA_HL_DATA* p_data);
+
+static const tBTA_HL_DCH_ACTION bta_hl_dch_action[] = {
+ bta_hl_dch_mca_create, bta_hl_dch_mca_create_cfm,
+ bta_hl_dch_mca_create_ind, bta_hl_dch_mca_open_cfm,
+ bta_hl_dch_mca_open_ind, bta_hl_dch_mca_close,
+ bta_hl_dch_mca_close_cfm, bta_hl_dch_mca_close_ind,
+ bta_hl_dch_close_cmpl, bta_hl_dch_mca_rcv_data,
+
+ bta_hl_dch_sdp_init, bta_hl_dch_mca_reconnect,
+ bta_hl_dch_mca_reconnect_ind, bta_hl_dch_mca_reconnect_cfm,
+ bta_hl_dch_close_echo_test, bta_hl_dch_create_rsp,
+ bta_hl_dch_mca_abort, bta_hl_dch_mca_abort_ind,
+ bta_hl_dch_mca_abort_cfm, bta_hl_dch_mca_cong_change,
+
+ bta_hl_dch_sdp_fail, bta_hl_dch_send_data,
+ bta_hl_dch_ci_get_tx_data, bta_hl_dch_ci_put_rx_data,
+ bta_hl_dch_ci_get_echo_data, bta_hl_dch_echo_test,
+ bta_hl_dch_ci_put_echo_data,
+};
+
+/* state table information */
+#define BTA_HL_DCH_ACTIONS 1 /* number of actions */
+#define BTA_HL_DCH_ACTION_COL 0 /* position of action */
+#define BTA_HL_DCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_DCH_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for idle state */
+static const uint8_t bta_hl_dch_st_idle[][BTA_HL_DCH_NUM_COLS] = {
+ /* Event Action 1 Next
+ state */
+ /* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_MCA_CREATE_IND,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+ /* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+ /* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_IND,
+ BTA_HL_DCH_OPENING_ST},
+
+ /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+
+ /* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST}};
+
+/* state table for opening state */
+static const uint8_t bta_hl_dch_st_opening[][BTA_HL_DCH_NUM_COLS] = {
+ /* Event Action 1 Next
+ state */
+ /* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_SDP_INIT,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_MCA_CREATE,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_MCA_CREATE_CFM,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_MCA_OPEN_IND,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_MCA_OPEN_CFM,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+ /* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_MCA_RECONNECT,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_SDP_FAIL,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_MCA_RECONNECT_CFM,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_CREATE_RSP,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_MCA_ABORT, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_MCA_ABORT_IND,
+ BTA_HL_DCH_OPENING_ST},
+
+ /* BTA_HL_MCA_ABORT_CFM_EVT */ {BTA_HL_DCH_MCA_ABORT_CFM,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_ECHO_TEST,
+ BTA_HL_DCH_OPENING_ST},
+ /* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_OPENING_ST}};
+
+/* state table for open state */
+static const uint8_t bta_hl_dch_st_open[][BTA_HL_DCH_NUM_COLS] = {
+ /* Event Action 1 Next
+ state */
+ /* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_MCA_CLOSE_IND,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_SEND_DATA, BTA_HL_DCH_OPEN_ST},
+
+ /* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_MCA_RCV_DATA,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_CLOSE_ECHO_TEST,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+
+ /* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_MCA_CONG_CHANGE,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+ BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_OPEN_ST},
+ /* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA,
+ BTA_HL_DCH_OPEN_ST}};
+
+/* state table for closing state */
+static const uint8_t bta_hl_dch_st_closing[][BTA_HL_DCH_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_HL_DCH_SDP_INIT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_OPEN_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CREATE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CREATE_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_OPEN_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_OPEN_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_CLOSE_EVT */ {BTA_HL_DCH_MCA_CLOSE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CLOSE_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CLOSE_CFM_EVT */ {BTA_HL_DCH_MCA_CLOSE_CFM,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_API_SEND_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+ /* BTA_HL_MCA_RCV_DATA_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_CLOSE_CMPL_EVT */ {BTA_HL_DCH_CLOSE_CMPL, BTA_HL_DCH_IDLE_ST},
+ /* BTA_HL_DCH_RECONNECT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_SDP_FAIL_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_RECONNECT_IND_EVT*/ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_RECONNECT_CFM_EVT*/ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_CLOSE_ECHO_TEST_EVT*/ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_API_DCH_CREATE_RSP_EVT */ {BTA_HL_DCH_IGNORE,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_ABORT_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_ABORT_IND_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+
+ /* BTA_HL_DCH_ABORT_CFM_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_MCA_CONG_CHG_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_CI_GET_TX_DATA_EVT */ {BTA_HL_DCH_CI_GET_TX_DATA,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_CI_PUT_RX_DATA_EVT */ {BTA_HL_DCH_CI_PUT_RX_DATA,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_CI_GET_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_GET_ECHO_DATA,
+ BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_DCH_ECHO_TEST_EVT */ {BTA_HL_DCH_IGNORE, BTA_HL_DCH_CLOSING_ST},
+ /* BTA_HL_CI_PUT_ECHO_DATA_EVT */ {BTA_HL_DCH_CI_PUT_ECHO_DATA,
+ BTA_HL_DCH_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_HL_DCH_ST_TBL)[BTA_HL_DCH_NUM_COLS];
+
+/* state table */
+const tBTA_HL_DCH_ST_TBL bta_hl_dch_st_tbl[] = {
+ bta_hl_dch_st_idle, bta_hl_dch_st_opening, bta_hl_dch_st_open,
+ bta_hl_dch_st_closing};
+
+/*****************************************************************************
+ * CCH State Table
+ ****************************************************************************/
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+/* state machine action enumeration list for CCH */
+enum {
+ BTA_HL_CCH_SDP_INIT,
+ BTA_HL_CCH_MCA_OPEN,
+ BTA_HL_CCH_MCA_CLOSE,
+ BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_MCA_CONNECT,
+ BTA_HL_CCH_MCA_DISCONNECT,
+ BTA_HL_CCH_MCA_RSP_TOUT,
+ BTA_HL_CCH_MCA_DISC_OPEN,
+ BTA_HL_CCH_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_HL_CCH_ACTION)(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data);
+
+/* action function list for MAS */
+const tBTA_HL_CCH_ACTION bta_hl_cch_action[] = {
+ bta_hl_cch_sdp_init, bta_hl_cch_mca_open, bta_hl_cch_mca_close,
+ bta_hl_cch_close_cmpl, bta_hl_cch_mca_connect, bta_hl_cch_mca_disconnect,
+ bta_hl_cch_mca_rsp_tout, bta_hl_cch_mca_disc_open};
+
+/* state table information */
+#define BTA_HL_CCH_ACTIONS 1 /* number of actions */
+#define BTA_HL_CCH_NEXT_STATE 1 /* position of next state */
+#define BTA_HL_CCH_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for MAS idle state */
+static const uint8_t bta_hl_cch_st_idle[][BTA_HL_CCH_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_SDP_INIT,
+ BTA_HL_CCH_OPENING_ST},
+ /* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT,
+ BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE,
+ BTA_HL_CCH_IDLE_ST}};
+
+/* state table for obex/rfcomm connection state */
+static const uint8_t bta_hl_cch_st_opening[][BTA_HL_CCH_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE,
+ BTA_HL_CCH_OPENING_ST},
+ /* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_MCA_OPEN,
+ BTA_HL_CCH_OPENING_ST},
+ /* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_CONNECT,
+ BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT,
+ BTA_HL_CCH_CLOSING_ST}};
+
+/* state table for open state */
+static const uint8_t bta_hl_cch_st_open[][BTA_HL_CCH_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_IGNORE, BTA_HL_CCH_OPEN_ST},
+ /* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_MCA_RSP_TOUT,
+ BTA_HL_CCH_CLOSING_ST}};
+
+/* state table for closing state */
+static const uint8_t bta_hl_cch_st_closing[][BTA_HL_CCH_NUM_COLS] = {
+ /* Event Action 1 Next state */
+ /* BTA_HL_CCH_OPEN_EVT */ {BTA_HL_CCH_IGNORE,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_SDP_OK_EVT */ {BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_CCH_SDP_FAIL_EVT */ {BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_MCA_CONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISC_OPEN,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_MCA_DISCONNECT_IND_EVT */ {BTA_HL_CCH_MCA_DISCONNECT,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_EVT */ {BTA_HL_CCH_MCA_CLOSE,
+ BTA_HL_CCH_CLOSING_ST},
+ /* BTA_HL_CCH_CLOSE_CMPL_EVT */ {BTA_HL_CCH_CLOSE_CMPL,
+ BTA_HL_CCH_IDLE_ST},
+ /* BTA_HL_MCA_RSP_TOUT_IND_EVT */ {BTA_HL_CCH_IGNORE,
+ BTA_HL_CCH_CLOSING_ST}};
+
+/* type for state table CCH */
+typedef const uint8_t (*tBTA_HL_CCH_ST_TBL)[BTA_HL_CCH_NUM_COLS];
+
+/* MAS state table */
+const tBTA_HL_CCH_ST_TBL bta_hl_cch_st_tbl[] = {
+ bta_hl_cch_st_idle, bta_hl_cch_st_opening, bta_hl_cch_st_open,
+ bta_hl_cch_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* HL control block */
+tBTA_HL_CB bta_hl_cb;
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_sm_execute
+ *
+ * Description State machine event handling function for CCH
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_cch_sm_execute(uint8_t app_idx, uint8_t mcl_idx, uint16_t event,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_CCH_ST_TBL state_table;
+ uint8_t action;
+ int i;
+ tBTA_HL_MCL_CB* p_cb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ tBTA_HL_CCH_STATE in_state = p_cb->cch_state;
+ uint16_t cur_evt = event;
+ APPL_TRACE_DEBUG("HDP CCH Event Handler: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hl_cch_state_code(in_state),
+ bta_hl_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_hl_cch_st_tbl[p_cb->cch_state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_cb->cch_state = state_table[event][BTA_HL_CCH_NEXT_STATE];
+
+ for (i = 0; i < BTA_HL_CCH_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_HL_CCH_IGNORE) {
+ (*bta_hl_cch_action[action])(app_idx, mcl_idx, p_data);
+ } else {
+ /* discard HDP data */
+ bta_hl_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (in_state != p_cb->cch_state) {
+ APPL_TRACE_DEBUG("HL CCH State Change: [%s] -> [%s] after [%s]",
+ bta_hl_cch_state_code(in_state),
+ bta_hl_cch_state_code(p_cb->cch_state),
+ bta_hl_evt_code(cur_evt));
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_sm_execute
+ *
+ * Description State machine event handling function for DCH
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_dch_sm_execute(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ uint16_t event, tBTA_HL_DATA* p_data) {
+ tBTA_HL_DCH_ST_TBL state_table;
+ uint8_t action;
+ int i;
+ tBTA_HL_MDL_CB* p_cb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+#if (BTA_HL_DEBUG == TRUE)
+ tBTA_HL_DCH_STATE in_state = p_cb->dch_state;
+ uint16_t cur_evt = event;
+ APPL_TRACE_DEBUG("HDP DCH Event Handler: State 0x%02x [%s], Event [%s]",
+ in_state, bta_hl_dch_state_code(in_state),
+ bta_hl_evt_code(cur_evt));
+#endif
+
+ /* look up the state table for the current state */
+ state_table = bta_hl_dch_st_tbl[p_cb->dch_state];
+ event -= BTA_HL_DCH_EVT_MIN;
+
+ /* set next state */
+ p_cb->dch_state = state_table[event][BTA_HL_DCH_NEXT_STATE];
+
+ for (i = 0; i < BTA_HL_DCH_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_HL_DCH_IGNORE) {
+ (*bta_hl_dch_action[action])(app_idx, mcl_idx, mdl_idx, p_data);
+ } else {
+ /* discard mas data */
+ bta_hl_discard_data(p_data->hdr.event, p_data);
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (in_state != p_cb->dch_state) {
+ APPL_TRACE_DEBUG("HL DCH State Change: [%s] -> [%s] after [%s]",
+ bta_hl_dch_state_code(in_state),
+ bta_hl_dch_state_code(p_cb->dch_state),
+ bta_hl_evt_code(cur_evt));
+ }
+#endif
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_api_enable
+ *
+ * Description Process the API enable request to enable the HL subsystem
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_enable(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+ tBTA_HL_CTRL evt_data;
+
+ /* If already enabled then reject this request */
+ if (p_cb->enable) {
+ APPL_TRACE_ERROR("HL is already enabled");
+ evt_data.enable_cfm.status = BTA_HL_STATUS_FAIL;
+ if (p_data->api_enable.p_cback)
+ p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT,
+ (tBTA_HL_CTRL*)&evt_data);
+ return;
+ }
+
+ /* Done with checking. now perform the enable oepration*/
+ /* initialize control block */
+ memset(p_cb, 0, sizeof(tBTA_HL_CB));
+ p_cb->enable = true;
+ p_cb->p_ctrl_cback = p_data->api_enable.p_cback;
+ evt_data.enable_cfm.status = BTA_HL_STATUS_OK;
+ if (p_data->api_enable.p_cback)
+ p_data->api_enable.p_cback(BTA_HL_CTRL_ENABLE_CFM_EVT,
+ (tBTA_HL_CTRL*)&evt_data);
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_api_disable
+ *
+ * Description Process the API disable request to disable the HL subsystem
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_disable(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+ tBTA_HL_CTRL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+ if (p_cb->enable) {
+ p_cb->disabling = true;
+ bta_hl_check_disable(p_data);
+ } else {
+ status = BTA_HL_STATUS_FAIL;
+ evt_data.disable_cfm.status = status;
+ if (p_cb->p_ctrl_cback)
+ p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT, (tBTA_HL_CTRL*)&evt_data);
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_disable status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_update
+ *
+ * Description Process the API registration request to register an HDP
+ * application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_update(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(0);
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ APPL_TRACE_DEBUG("bta_hl_api_update");
+ if (p_cb->enable) {
+ status = bta_hl_app_update(p_data->api_update.app_id,
+ p_data->api_update.is_register);
+ if (!p_data->api_update.is_register) {
+ APPL_TRACE_DEBUG("Deregister");
+ memset(&evt_data, 0, sizeof(tBTA_HL));
+ evt_data.dereg_cfm.status = status;
+ evt_data.dereg_cfm.app_id = p_data->api_update.app_id;
+ if (status == BTA_HL_STATUS_OK)
+ evt_data.dereg_cfm.app_handle = p_acb->app_handle;
+ if (p_acb->p_cback) {
+ p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+ return;
+ }
+ }
+
+ if (status != BTA_HL_STATUS_OK) {
+ if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) &&
+ (status != BTA_HL_STATUS_NO_RESOURCE)) {
+ if (p_acb) memset(p_acb, 0, sizeof(tBTA_HL_APP_CB));
+ }
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_register status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ memset(&evt_data, 0, sizeof(tBTA_HL));
+ evt_data.reg_cfm.status = status;
+ evt_data.reg_cfm.app_id = p_data->api_update.app_id;
+ if (status == BTA_HL_STATUS_OK)
+ evt_data.reg_cfm.app_handle = p_acb->app_handle;
+ if (p_data->api_reg.p_cback) {
+ p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+
+ if (status == BTA_HL_STATUS_OK) {
+ evt_data.sdp_info_ind.app_handle = p_acb->app_handle;
+ evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm;
+ evt_data.sdp_info_ind.data_psm = p_acb->data_psm;
+ evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601;
+ evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK;
+
+ if (p_data->api_reg.p_cback) {
+ p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL*)&evt_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_register
+ *
+ * Description Process the API registration request to register an HDP
+ * application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_register(tBTA_HL_CB* p_cb, tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ uint8_t app_idx;
+ tBTA_HL_APP_CB* p_acb = NULL;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ if (p_cb->enable) {
+ if (!bta_hl_is_a_duplicate_id(p_data->api_reg.app_id)) {
+ if (bta_hl_find_avail_app_idx(&app_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->in_use = true;
+ p_acb->app_id = p_data->api_reg.app_id;
+ p_acb->p_cback = p_data->api_reg.p_cback;
+ p_acb->sec_mask = p_data->api_reg.sec_mask;
+ p_acb->dev_type = p_data->api_reg.dev_type;
+ strlcpy(p_acb->srv_name, p_data->api_reg.srv_name,
+ BTA_SERVICE_NAME_LEN);
+ strlcpy(p_acb->srv_desp, p_data->api_reg.srv_desp,
+ BTA_SERVICE_DESP_LEN);
+ strlcpy(p_acb->provider_name, p_data->api_reg.provider_name,
+ BTA_PROVIDER_NAME_LEN);
+ bta_hl_cb.p_alloc_psm = L2CA_AllocatePSM;
+ p_acb->ctrl_psm = bta_hl_cb.p_alloc_psm();
+ p_acb->data_psm = bta_hl_cb.p_alloc_psm();
+ p_acb->p_mcap_cback = bta_hl_mcap_ctrl_cback;
+ status = bta_hl_app_registration(app_idx);
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ status = BTA_HL_STATUS_DUPLICATE_APP_ID;
+ }
+ }
+
+ if (status != BTA_HL_STATUS_OK) {
+ if ((status != BTA_HL_STATUS_DUPLICATE_APP_ID) &&
+ (status != BTA_HL_STATUS_NO_RESOURCE)) {
+ if (p_acb) memset(p_acb, 0, sizeof(tBTA_HL_APP_CB));
+ }
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_register status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ memset(&evt_data, 0, sizeof(tBTA_HL));
+ evt_data.reg_cfm.status = status;
+ evt_data.reg_cfm.app_id = p_data->api_reg.app_id;
+ if (status == BTA_HL_STATUS_OK)
+ evt_data.reg_cfm.app_handle = p_acb->app_handle;
+ if (p_data->api_reg.p_cback) {
+ p_data->api_reg.p_cback(BTA_HL_REGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+ }
+
+ if (status == BTA_HL_STATUS_OK) {
+ evt_data.sdp_info_ind.app_handle = p_acb->app_handle;
+ evt_data.sdp_info_ind.ctrl_psm = p_acb->ctrl_psm;
+ evt_data.sdp_info_ind.data_psm = p_acb->data_psm;
+ evt_data.sdp_info_ind.data_x_spec = BTA_HL_SDP_IEEE_11073_20601;
+ evt_data.sdp_info_ind.mcap_sup_procs = BTA_HL_MCAP_SUP_PROC_MASK;
+
+ if (p_data->api_reg.p_cback) {
+ p_data->api_reg.p_cback(BTA_HL_SDP_INFO_IND_EVT, (tBTA_HL*)&evt_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_deregister
+ *
+ * Description Process the API de-registration request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_deregister(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ uint8_t app_idx;
+ tBTA_HL_APP_CB* p_acb;
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_dereg.app_handle,
+ &app_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->deregistering = true;
+ bta_hl_check_deregistration(app_idx, p_data);
+ } else {
+ APPL_TRACE_ERROR("Invalid app_handle=%d", p_data->api_dereg.app_handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_cch_open
+ *
+ * Description Process the API CCH open request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_cch_open(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_cch_open.app_handle,
+ &app_idx)) {
+ if (!bta_hl_find_mcl_idx(app_idx, p_data->api_cch_open.bd_addr, &mcl_idx)) {
+ if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = true;
+ p_mcb->req_ctrl_psm = p_data->api_cch_open.ctrl_psm;
+ p_mcb->sec_mask = p_data->api_cch_open.sec_mask;
+ bdcpy(p_mcb->bd_addr, p_data->api_cch_open.bd_addr);
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_OPEN;
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ /* Only one MCL per BD_ADDR */
+ status = BTA_HL_STATUS_DUPLICATE_CCH_OPEN;
+ APPL_TRACE_DEBUG("bta_hl_api_cch_open: CCH already open: status =%d",
+ status)
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_id,
+ p_data->api_cch_open.app_handle,
+ p_mcb->mcl_handle,
+ p_data->api_cch_open.bd_addr, status);
+ p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_cch_open Null Callback");
+ }
+ return;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_cch_open status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_OPEN_EVT, p_data);
+ break;
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_cch_open_cfm(&evt_data, p_data->api_cch_open.app_id,
+ p_data->api_cch_open.app_handle, 0,
+ p_data->api_cch_open.bd_addr, status);
+ p_acb->p_cback(BTA_HL_CCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_cch_open Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_cch_close
+ *
+ * Description Process the API CCH close request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_cch_close(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_cch_close.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ } else {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_cch_close status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+ break;
+
+ case BTA_HL_STATUS_INVALID_MCL_HANDLE:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_cch_close_cfm(&evt_data, p_acb->app_handle,
+ p_data->api_cch_close.mcl_handle, status);
+ p_acb->p_cback(BTA_HL_CCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_cch_close Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_dch_open
+ *
+ * Description Process the API DCH open request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_open(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb = NULL;
+ tBTA_HL_MDL_CB* p_dcb;
+ tBTA_HL_MDEP_CFG* p_mdep_cfg;
+ uint8_t mdep_cfg_idx;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_open.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ APPL_TRACE_DEBUG(
+ "bta_hl_api_dch_open: app_ix=%d, mcl_idx=%d, cch_state=%d, "
+ "mcl_handle=%d",
+ app_idx, mcl_idx, p_mcb->cch_state, p_data->api_dch_open.mcl_handle);
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (bta_hl_find_mdep_cfg_idx(
+ app_idx, p_data->api_dch_open.local_mdep_id, &mdep_cfg_idx)) {
+ if (mdep_cfg_idx &&
+ (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SINK)) {
+ p_data->api_dch_open.local_cfg = BTA_HL_DCH_CFG_NO_PREF;
+ }
+
+ status = bta_hl_chk_local_cfg(app_idx, mcl_idx, mdep_cfg_idx,
+ p_data->api_dch_open.local_cfg);
+ if (status == BTA_HL_STATUS_OK) {
+ if (p_data->api_dch_open.local_mdep_id !=
+ BTA_HL_ECHO_TEST_MDEP_ID) {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+ p_data->api_dch_open.ctrl_psm)) {
+ p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx);
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+ p_dcb->sec_mask = p_data->api_dch_open.sec_mask;
+ p_dcb->local_mdep_id = p_data->api_dch_open.local_mdep_id;
+ p_dcb->peer_mdep_id = p_data->api_dch_open.peer_mdep_id;
+
+ if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ } else {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+ }
+
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = p_data->api_dch_open.local_cfg;
+
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ p_dcb->mdl_id =
+ bta_hl_allocate_mdl_id(app_idx, mcl_idx, mdl_idx);
+ p_dcb->mdl_cfg_idx_included = false;
+ } else {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+
+ } else {
+ status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+ }
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_dch_open status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_OPEN_EVT,
+ p_data);
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ case BTA_HL_STATUS_NO_CCH:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+ case BTA_HL_STATUS_INVALID_CTRL_PSM:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_dch_open_cfm(
+ &evt_data, p_acb->app_handle, p_data->api_dch_open.mcl_handle,
+ BTA_HL_INVALID_MDL_HANDLE, 0, 0, 0, 0, 0, status);
+ p_acb->p_cback(BTA_HL_DCH_OPEN_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_dch_open Null Callback");
+ }
+
+ break;
+ default:
+ APPL_TRACE_ERROR("Status code=%d", status);
+ break;
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_api_dch_close
+ *
+ * Description Process the API DCH close request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_close(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+ tBTA_HL_MDL_CB* p_dcb;
+
+ if (bta_hl_find_mdl_idx_using_handle(p_data->api_dch_close.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->dch_state != BTA_HL_DCH_OPEN_ST) {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MDL_HANDLE;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_dch_close status =%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+ p_data);
+ break;
+ case BTA_HL_STATUS_FAIL:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bta_hl_build_dch_close_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle,
+ p_data->api_dch_close.mdl_handle, status);
+
+ p_acb->p_cback(BTA_HL_DCH_CLOSE_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_dch_close Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_dch_reconnect
+ *
+ * Description Process the API DCH reconnect request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_reconnect(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb = NULL;
+ tBTA_HL_MDL_CB* p_dcb;
+ uint8_t mdep_cfg_idx;
+ uint8_t mdl_cfg_idx;
+ tBTA_HL_MDEP_CFG* p_mdep_cfg;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_reconnect.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (bta_hl_validate_reconnect_params(app_idx, mcl_idx,
+ &(p_data->api_dch_reconnect),
+ &mdep_cfg_idx, &mdl_cfg_idx)) {
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode !=
+ BTA_HL_DCH_MODE_RELIABLE)) {
+ status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+ } else {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+ p_data->api_dch_open.ctrl_psm)) {
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_RECONNECT;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->local_mdep_id = p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ p_dcb->mdl_id = p_data->api_dch_reconnect.mdl_id;
+ p_dcb->mdl_cfg_idx_included = true;
+ p_dcb->mdl_cfg_idx = mdl_cfg_idx;
+ p_dcb->dch_mode = p_acb->mdl_cfg[mdl_cfg_idx].dch_mode;
+
+ p_mdep_cfg = BTA_HL_GET_MDEP_CFG_PTR(app_idx, mdep_cfg_idx);
+
+ if (p_mdep_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ APPL_TRACE_DEBUG("peer mdep role = SOURCE ");
+ } else {
+ p_dcb->peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+ APPL_TRACE_DEBUG("peer mdep role = SINK ");
+ }
+
+ bta_hl_find_rxtx_apdu_size(app_idx, mdep_cfg_idx,
+ &p_dcb->max_rx_apdu_size,
+ &p_dcb->max_tx_apdu_size);
+ } else {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_RECONNECT_CFG;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_dch_reconnect status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_RECONNECT_EVT, p_data);
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ case BTA_HL_STATUS_NO_CCH:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_dch_open_cfm(
+ &evt_data, p_acb->app_handle, p_data->api_dch_reconnect.mcl_handle,
+ BTA_HL_INVALID_MDL_HANDLE, 0, p_data->api_dch_reconnect.mdl_id, 0,
+ 0, 0, status);
+ p_acb->p_cback(BTA_HL_DCH_RECONNECT_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_dch_reconnect Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_dch_echo_test
+ *
+ * Description Process the API Echo test request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_echo_test(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb = NULL;
+ tBTA_HL_MDL_CB* p_dcb;
+ tBTA_HL_ECHO_CFG* p_echo_cfg;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_echo_test.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_state == BTA_HL_CCH_OPEN_ST) {
+ if (!p_mcb->echo_test) {
+ if (bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if ((p_data->api_dch_echo_test.local_cfg ==
+ BTA_HL_DCH_CFG_RELIABLE) ||
+ (p_data->api_dch_echo_test.local_cfg ==
+ BTA_HL_DCH_CFG_STREAMING)) {
+ bool fcs_use =
+ (bool)(p_dcb->chnl_cfg.fcs & BTA_HL_MCA_FCS_USE_MASK);
+ p_dcb->p_echo_tx_pkt =
+ bta_hl_get_buf(p_data->api_dch_echo_test.pkt_size, fcs_use);
+ if (p_dcb->p_echo_tx_pkt != NULL) {
+ if (bta_hl_set_ctrl_psm_for_dch(app_idx, mcl_idx, mdl_idx,
+ p_data->api_dch_open.ctrl_psm)) {
+ p_dcb->in_use = true;
+ p_dcb->dch_oper = BTA_HL_DCH_OP_LOCAL_OPEN;
+ p_dcb->sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ p_dcb->local_mdep_cfg_idx = BTA_HL_ECHO_TEST_MDEP_CFG_IDX;
+ p_dcb->local_cfg = p_data->api_dch_echo_test.local_cfg;
+ p_dcb->local_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+ p_dcb->peer_mdep_id = BTA_HL_ECHO_TEST_MDEP_ID;
+ p_dcb->mdl_id =
+ bta_hl_allocate_mdl_id(app_idx, mcl_idx, mdl_idx);
+ p_dcb->mdl_cfg_idx_included = false;
+ p_echo_cfg = BTA_HL_GET_ECHO_CFG_PTR(app_idx);
+ p_dcb->max_rx_apdu_size = p_echo_cfg->max_rx_apdu_size;
+ p_dcb->max_tx_apdu_size = p_echo_cfg->max_tx_apdu_size;
+ p_mcb->echo_test = true;
+ p_mcb->echo_mdl_idx = mdl_idx;
+ } else {
+ status = BTA_HL_STATUS_INVALID_CTRL_PSM;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_DCH_CFG;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ status = BTA_HL_STATUS_ECHO_TEST_BUSY;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_CCH;
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_MCL;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_dch_echo_test status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ if (p_mcb->sdp.num_recs) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_ECHO_TEST_EVT, p_data);
+ } else {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_SDP_INIT_EVT, p_data);
+ }
+ break;
+ case BTA_HL_STATUS_ECHO_TEST_BUSY:
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_echo_test_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, status);
+ p_acb->p_cback(BTA_HL_DCH_ECHO_TEST_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_dch_echo_test Null Callback");
+ }
+ break;
+
+ default:
+ APPL_TRACE_ERROR("Status code=%s", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_sdp_query
+ *
+ * Description Process the API SDP query request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_sdp_query(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+
+ if (bta_hl_find_app_idx_using_handle(p_data->api_sdp_query.app_handle,
+ &app_idx)) {
+ if (!bta_hl_find_mcl_idx(app_idx, p_data->api_sdp_query.bd_addr,
+ &mcl_idx)) {
+ if (bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = true;
+ bdcpy(p_mcb->bd_addr, p_data->api_sdp_query.bd_addr);
+ APPL_TRACE_DEBUG(
+ "bta_hl_api_sdp_query p_mcb->app_id %d app_idx %d mcl_idx %d",
+ p_mcb->app_id, app_idx, mcl_idx);
+ p_mcb->app_id = p_data->api_sdp_query.app_id;
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_NEW;
+ } else {
+ status = BTA_HL_STATUS_NO_RESOURCE;
+ }
+ } else {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->app_id = p_data->api_sdp_query.app_id;
+ if (p_mcb->sdp_oper != BTA_HL_SDP_OP_NONE) {
+ status = BTA_HL_STATUS_SDP_NO_RESOURCE;
+ } else {
+ p_mcb->sdp_oper = BTA_HL_SDP_OP_SDP_QUERY_CURRENT;
+ }
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_APP_HANDLE;
+ }
+
+ if (status == BTA_HL_STATUS_OK) {
+ status = bta_hl_init_sdp(p_mcb->sdp_oper, app_idx, mcl_idx, 0xFF);
+ if ((status != BTA_HL_STATUS_OK) &&
+ (p_mcb->sdp_oper == BTA_HL_SDP_OP_SDP_QUERY_NEW)) {
+ memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+ }
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_sdp_query status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_NO_RESOURCE:
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_SDP_NO_RESOURCE:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_sdp_query_cfm(&evt_data, p_data->api_sdp_query.app_id,
+ p_data->api_sdp_query.app_handle,
+ p_data->api_sdp_query.bd_addr, NULL, status);
+ p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_sdp_query Null Callback");
+ }
+ break;
+ case BTA_HL_STATUS_OK:
+ break;
+ default:
+ APPL_TRACE_ERROR("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_sdp_query_results
+ *
+ * Description Process the SDP query results
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_sdp_query_results(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx = p_data->cch_sdp.app_idx;
+ uint8_t mcl_idx = p_data->cch_sdp.mcl_idx;
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_SDP* p_sdp = NULL;
+ uint16_t event;
+ bool release_sdp_buf = false;
+
+ event = p_data->hdr.event;
+
+ if (event == BTA_HL_SDP_QUERY_OK_EVT) {
+ p_sdp = (tBTA_HL_SDP*)osi_malloc(sizeof(tBTA_HL_SDP));
+ memcpy(p_sdp, &p_mcb->sdp, sizeof(tBTA_HL_SDP));
+ release_sdp_buf = true;
+ } else {
+ status = BTA_HL_STATUS_SDP_FAIL;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_sdp_query_results status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ APPL_TRACE_DEBUG(
+ "bta_hl_sdp_query_results p_mcb->app_id %d app_idx %d mcl_idx %d",
+ p_mcb->app_id, app_idx, mcl_idx);
+ bta_hl_build_sdp_query_cfm(&evt_data, p_mcb->app_id, p_acb->app_handle,
+ p_mcb->bd_addr, p_sdp, status);
+ p_acb->p_cback(BTA_HL_SDP_QUERY_CFM_EVT, (tBTA_HL*)&evt_data);
+
+ if (release_sdp_buf) osi_free_and_reset((void**)&p_sdp);
+
+ if (p_data->cch_sdp.release_mcl_cb) {
+ memset(p_mcb, 0, sizeof(tBTA_HL_MCL_CB));
+ } else {
+ if (p_mcb->close_pending)
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+
+ if (!p_mcb->ctrl_psm) {
+ /* Control channel acceptor: do not store the SDP records */
+ memset(&p_mcb->sdp, 0, sizeof(tBTA_HL_SDP));
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_delete_mdl
+ *
+ * Description Process the API DELETE MDL request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_delete_mdl(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_delete_mdl.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ if (bta_hl_is_mdl_value_valid(p_data->api_delete_mdl.mdl_id)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (bta_hl_is_mdl_exsit_in_mcl(app_idx, p_mcb->bd_addr,
+ p_data->api_delete_mdl.mdl_id)) {
+ p_mcb->delete_mdl.mcl_handle = p_data->api_delete_mdl.mcl_handle;
+ p_mcb->delete_mdl.mdl_id = p_data->api_delete_mdl.mdl_id;
+ p_mcb->delete_mdl.delete_req_pending = true;
+
+ if (MCA_Delete((tMCA_CL)p_mcb->mcl_handle,
+ p_data->api_delete_mdl.mdl_id) != MCA_SUCCESS) {
+ status = BTA_HL_STATUS_FAIL;
+ memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+ }
+ } else {
+ status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MDL_ID;
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_delete_mdl status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ break;
+ case BTA_HL_STATUS_FAIL:
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ case BTA_HL_STATUS_INVALID_MDL_ID:
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_delete_mdl_cfm(&evt_data, p_acb->app_handle,
+ p_data->api_delete_mdl.mcl_handle,
+ p_data->api_delete_mdl.mdl_id, status);
+ p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_delete_mdl Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("status code =%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_mca_delete_mdl_cfm
+ *
+ * Description Process the DELETE MDL confirmation event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_mca_delete_mdl_cfm(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx;
+ tMCA_RSP_EVT* p_delete_cfm = &p_data->mca_evt.mca_data.delete_cfm;
+ tBTA_HL_MCL_CB* p_mcb;
+ bool send_cfm_evt = true;
+ tBTA_HL_APP_CB* p_acb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->delete_mdl.delete_req_pending) {
+ if (p_delete_cfm->rsp_code == MCA_RSP_SUCCESS) {
+ if (!bta_hl_delete_mdl_cfg(app_idx, p_mcb->bd_addr,
+ p_delete_cfm->mdl_id)) {
+ status = BTA_HL_STATUS_FAIL;
+ }
+ } else {
+ status = BTA_HL_STATUS_FAIL;
+ }
+
+ memset(&p_mcb->delete_mdl, 0, sizeof(tBTA_HL_DELETE_MDL));
+ } else {
+ send_cfm_evt = false;
+ }
+ } else {
+ send_cfm_evt = false;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_delete_mdl status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+
+ if (send_cfm_evt) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ bta_hl_build_delete_mdl_cfm(&evt_data, p_acb->app_handle,
+ p_mcb->mcl_handle, p_delete_cfm->mdl_id,
+ status);
+
+ p_acb->p_cback(BTA_HL_DELETE_MDL_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_mca_delete_mdl_cfm Null Callback");
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_mca_delete_mdl_ind
+ *
+ * Description Process the DELETE MDL indication event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_mca_delete_mdl_ind(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL evt_data;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tMCA_EVT_HDR* p_delete_ind = &p_data->mca_evt.mca_data.delete_ind;
+ tBTA_HL_MCL_CB* p_mcb;
+ tBTA_HL_MDL_CB* p_dcb;
+ bool send_ind_evt = false;
+ tBTA_HL_APP_CB* p_acb;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ if (bta_hl_find_mdl_idx(app_idx, mcl_idx, p_delete_ind->mdl_id, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ p_dcb->dch_oper = BTA_HL_DCH_OP_REMOTE_DELETE;
+ }
+ if (bta_hl_delete_mdl_cfg(app_idx, p_mcb->bd_addr, p_delete_ind->mdl_id)) {
+ send_ind_evt = true;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!send_ind_evt) {
+ APPL_TRACE_DEBUG("bta_hl_mca_delete_mdl_ind is_send_ind_evt =%d",
+ send_ind_evt);
+ }
+#endif
+
+ if (send_ind_evt) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ evt_data.delete_mdl_ind.mcl_handle = p_mcb->mcl_handle;
+ evt_data.delete_mdl_ind.app_handle = p_acb->app_handle;
+ evt_data.delete_mdl_ind.mdl_id = p_delete_ind->mdl_id;
+ p_acb->p_cback(BTA_HL_DELETE_MDL_IND_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_mca_delete_mdl_ind Null Callback");
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_api_dch_abort
+ *
+ * Description Process the API DCH abort request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_hl_api_dch_abort(UNUSED_ATTR tBTA_HL_CB* p_cb,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+ tBTA_HL_MDL_CB* p_dcb;
+ tBTA_HL evt_data;
+
+ if (bta_hl_find_mcl_idx_using_handle(p_data->api_dch_abort.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ if (!bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ status = BTA_HL_STATUS_NO_MDL_ID_FOUND;
+ } else {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->abort_oper) {
+ /* abort already in progress*/
+ status = BTA_HL_STATUS_FAIL;
+ } else {
+ p_dcb->abort_oper = BTA_HL_ABORT_LOCAL_MASK;
+ }
+ }
+ } else {
+ status = BTA_HL_STATUS_INVALID_MCL_HANDLE;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (status != BTA_HL_STATUS_OK) {
+ APPL_TRACE_DEBUG("bta_hl_api_dch_abort status=%s",
+ bta_hl_status_code(status));
+ }
+#endif
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+ p_data);
+ break;
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ case BTA_HL_STATUS_FAIL:
+
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb->p_cback) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bta_hl_build_abort_cfm(&evt_data,
+
+ p_acb->app_handle, p_mcb->mcl_handle,
+ BTA_HL_STATUS_FAIL);
+ p_acb->p_cback(BTA_HL_DCH_ABORT_CFM_EVT, (tBTA_HL*)&evt_data);
+ } else {
+ APPL_TRACE_ERROR("bta_hl_api_dch_abort Null Callback");
+ }
+ break;
+ default:
+ APPL_TRACE_ERROR("Status code=%d", status);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_hdl_event
+ *
+ * Description HL main event handling function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_hl_hdl_event(BT_HDR* p_msg) {
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ bool success = true;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("BTA HL Event Handler: Event [%s]",
+ bta_hl_evt_code(p_msg->event));
+#endif
+
+ switch (p_msg->event) {
+ case BTA_HL_API_ENABLE_EVT:
+ bta_hl_api_enable(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DISABLE_EVT:
+ bta_hl_api_disable(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_UPDATE_EVT:
+ bta_hl_api_update(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_REGISTER_EVT:
+ bta_hl_api_register(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DEREGISTER_EVT:
+ bta_hl_api_deregister(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_CCH_OPEN_EVT:
+ bta_hl_api_cch_open(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_CCH_CLOSE_EVT:
+ bta_hl_api_cch_close(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DCH_OPEN_EVT:
+ bta_hl_api_dch_open(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DCH_CLOSE_EVT:
+ bta_hl_api_dch_close(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DELETE_MDL_EVT:
+ bta_hl_api_delete_mdl(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DCH_RECONNECT_EVT:
+ bta_hl_api_dch_reconnect(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ case BTA_HL_API_DCH_ECHO_TEST_EVT:
+ bta_hl_api_dch_echo_test(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ case BTA_HL_API_SDP_QUERY_EVT:
+ bta_hl_api_sdp_query(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ case BTA_HL_MCA_DELETE_CFM_EVT:
+ bta_hl_mca_delete_mdl_cfm(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ case BTA_HL_MCA_DELETE_IND_EVT:
+ bta_hl_mca_delete_mdl_ind(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ case BTA_HL_SDP_QUERY_OK_EVT:
+ case BTA_HL_SDP_QUERY_FAIL_EVT:
+ bta_hl_sdp_query_results(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+ case BTA_HL_API_DCH_ABORT_EVT:
+ bta_hl_api_dch_abort(&bta_hl_cb, (tBTA_HL_DATA*)p_msg);
+ break;
+
+ default:
+ if (p_msg->event < BTA_HL_DCH_EVT_MIN) {
+ if (bta_hl_find_cch_cb_indexes((tBTA_HL_DATA*)p_msg, &app_idx,
+ &mcl_idx)) {
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, p_msg->event,
+ (tBTA_HL_DATA*)p_msg);
+ } else {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_ERROR(
+ "unable to find control block indexes for CCH: [event=%s]",
+ bta_hl_evt_code(p_msg->event));
+#else
+ APPL_TRACE_ERROR(
+ "unable to find control block indexes for CCH: [event=%d]",
+ p_msg->event);
+#endif
+ success = false;
+ }
+ } else {
+ if (bta_hl_find_dch_cb_indexes((tBTA_HL_DATA*)p_msg, &app_idx, &mcl_idx,
+ &mdl_idx)) {
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, p_msg->event,
+ (tBTA_HL_DATA*)p_msg);
+ } else {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_ERROR(
+ "unable to find control block indexes for DCH : [event=%s]",
+ bta_hl_evt_code(p_msg->event));
+#else
+ APPL_TRACE_ERROR(
+ "unable to find control block indexes for DCH: [event=%d]",
+ p_msg->event);
+#endif
+ success = false;
+ }
+ }
+
+ break;
+ }
+
+ return (success);
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function bta_hl_cch_state_code
+ *
+ * Description Map CCH state code to the corresponding state string
+ *
+ * Returns string pointer for the associated state name
+ *
+ ******************************************************************************/
+static const char* bta_hl_cch_state_code(tBTA_HL_CCH_STATE state_code) {
+ switch (state_code) {
+ case BTA_HL_CCH_IDLE_ST:
+ return "BTA_HL_CCH_IDLE_ST";
+ case BTA_HL_CCH_OPENING_ST:
+ return "BTA_HL_CCH_OPENING_ST";
+ case BTA_HL_CCH_OPEN_ST:
+ return "BTA_HL_CCH_OPEN_ST";
+ case BTA_HL_CCH_CLOSING_ST:
+ return "BTA_HL_CCH_CLOSING_ST";
+ default:
+ return "Unknown CCH state code";
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_dch_state_code
+ *
+ * Description Map DCH state code to the corresponding state string
+ *
+ * Returns string pointer for the associated state name
+ *
+ ******************************************************************************/
+static const char* bta_hl_dch_state_code(tBTA_HL_DCH_STATE state_code) {
+ switch (state_code) {
+ case BTA_HL_DCH_IDLE_ST:
+ return "BTA_HL_DCH_IDLE_ST";
+ case BTA_HL_DCH_OPENING_ST:
+ return "BTA_HL_DCH_OPENING_ST";
+ case BTA_HL_DCH_OPEN_ST:
+ return "BTA_HL_DCH_OPEN_ST";
+ case BTA_HL_DCH_CLOSING_ST:
+ return "BTA_HL_DCH_CLOSING_ST";
+ default:
+ return "Unknown DCH state code";
+ }
+}
+#endif /* Debug Functions */
+#endif /* HL_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_sdp.cc b/mtkbt/code/bt/bta/hl/bta_hl_sdp.cc
new file mode 100755
index 0000000..fe3da58
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_sdp.cc
@@ -0,0 +1,574 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1998-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bta_hl_int.h"
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function bta_hl_fill_sup_feature_list
+ *
+ * Description Fill the supported features from teh SDP record
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool bta_hl_fill_sup_feature_list(const tSDP_DISC_ATTR* p_attr,
+ tBTA_HL_SUP_FEATURE_LIST_ELEM* p_list) {
+ tSDP_DISC_ATTR* p_sattr;
+ uint8_t item_cnt;
+ uint8_t list_cnt = 0;
+ bool status = true;
+
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
+ p_attr = p_attr->p_next_attr) {
+ /* mdep sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+ return (false);
+ }
+
+ item_cnt = 0;
+
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4);
+ p_sattr = p_sattr->p_next_attr) {
+ /* for each mdep list */
+
+ p_list->list_elem[list_cnt].p_mdep_desp = NULL;
+ switch (item_cnt) {
+ case 0:
+ p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8;
+ break;
+ case 1:
+ p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16;
+ break;
+ case 2:
+ p_list->list_elem[list_cnt].mdep_role =
+ (tBTA_HL_MDEP_ROLE)p_sattr->attr_value.v.u8;
+ break;
+ case 3:
+ p_list->list_elem[list_cnt].p_mdep_desp =
+ (char*)p_sattr->attr_value.v.array;
+ break;
+ }
+
+ item_cnt++;
+ }
+ list_cnt++;
+ }
+ p_list->num_elems = list_cnt;
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_compose_supported_feature_list
+ *
+ * Description This function is called to compose a data sequence from
+ * the supported feature element list struct pointer
+ *
+ * Returns the length of the data sequence
+ *
+ ******************************************************************************/
+int bta_hl_compose_supported_feature_list(
+ uint8_t* p, uint16_t num_elem,
+ const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
+ uint16_t xx, str_len, seq_len;
+ uint8_t* p_head = p;
+
+ for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
+ UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ seq_len = 7;
+ str_len = 0;
+ if (p_elem_list->p_mdep_desp) {
+ str_len = strlen(p_elem_list->p_mdep_desp) + 1;
+ seq_len += str_len + 2; /* todo add a # symbol for 2 */
+ }
+
+ *p++ = (uint8_t)seq_len;
+
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM(p, p_elem_list->mdep_id);
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, p_elem_list->data_type);
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM(p, p_elem_list->mdep_role);
+
+ if (str_len) {
+ UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p, str_len);
+ ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len);
+ }
+ }
+
+ return (p - p_head);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_add_sup_feature_list
+ *
+ * Description This function is called to add a protocol descriptor list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the protocol list already exists in the record, it
+ * is replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool bta_hl_add_sup_feature_list(uint32_t handle, uint16_t num_elem,
+ const tBTA_HL_SUP_FEATURE_ELEM* p_elem_list) {
+ int offset;
+ bool result;
+ uint8_t* p_buf = (uint8_t*)osi_malloc(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE);
+
+ offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, p_elem_list);
+ result = SDP_AddAttribute(handle, ATTR_ID_HDP_SUP_FEAT_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buf);
+ osi_free(p_buf);
+
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Function: bta_hl_sdp_update
+ *
+ * Purpose: Register an HDP application with SDP
+ *
+ * Parameters:
+ *
+ * Returns: void
+ *
+ ****************************************************************************/
+tBTA_HL_STATUS bta_hl_sdp_update(UNUSED_ATTR uint8_t app_id) {
+ uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
+ tSDP_PROTO_LIST_ELEM add_proto_list;
+ tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
+ uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ uint8_t i, j, cnt, mdep_id, mdep_role;
+ uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
+ uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
+ uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
+ uint16_t version = BTA_HL_VERSION;
+ uint8_t num_services = 1;
+ tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(0);
+ bool result = true;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+ if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
+ (!p_cb->sup_feature.advertize_source_sdp)) {
+ return BTA_HL_STATUS_OK;
+ }
+
+ num_services = 1;
+ svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
+ if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
+ svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
+ } else {
+ if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
+ /* dual role */
+ num_services = 2;
+ svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
+ }
+ }
+ result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
+ svc_class_id_list);
+
+ if (result) {
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 1;
+ proto_elem_list[0].params[0] = p_cb->ctrl_psm;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = version;
+ result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
+ proto_elem_list);
+
+ result &=
+ SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
+ }
+
+ if (result) {
+ add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
+ add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ add_proto_list.list_elem[0].num_params = 1;
+ add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
+ add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
+ add_proto_list.list_elem[1].num_params = 0;
+ result &=
+ SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
+ (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+ }
+
+ if (result) {
+ if (p_cb->srv_name[0]) {
+ result &= SDP_AddAttribute(
+ p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
+ (uint8_t*)p_cb->srv_name);
+ } /* end of setting optional service name */
+ }
+
+ if (result) {
+ if (p_cb->srv_desp[0]) {
+ result &= SDP_AddAttribute(
+ p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
+ (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
+ (uint8_t*)p_cb->srv_desp);
+
+ } /* end of setting optional service description */
+ }
+
+ if (result) {
+ if (p_cb->provider_name[0]) {
+ result &=
+ SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_cb->provider_name) + 1),
+ (uint8_t*)p_cb->provider_name);
+ } /* end of setting optional provider name */
+ }
+
+ /* add supported feture list */
+
+ if (result) {
+ cnt = 0;
+ for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
+ if (p_cb->sup_feature.mdep[i].mdep_id) {
+ mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
+ mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
+
+ APPL_TRACE_DEBUG(
+ "num_of_mdep_data_types %d ",
+ p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types);
+ for (j = 0;
+ j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
+ j++) {
+ sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
+ sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
+ sup_feature_list.list_elem[cnt].data_type =
+ p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
+ if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
+ sup_feature_list.list_elem[cnt].p_mdep_desp =
+ p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
+ } else {
+ sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
+ }
+
+ cnt++;
+ if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
+ result = false;
+ break;
+ }
+ }
+ }
+ }
+ sup_feature_list.num_elems = cnt;
+ result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
+ sup_feature_list.num_elems,
+ sup_feature_list.list_elem);
+ }
+ if (result) {
+ result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
+ UINT_DESC_TYPE, (uint32_t)1,
+ (uint8_t*)&data_exchange_spec);
+ }
+
+ if (result) {
+ result &=
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
+ UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
+ }
+
+ if (result) {
+ result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, browse_list);
+ }
+
+ if (result) {
+ for (i = 0; i < num_services; i++) {
+ bta_sys_add_uuid(svc_class_id_list[i]);
+ APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
+ svc_class_id_list[i]); // todo
+ }
+ } else {
+ if (p_cb->sdp_handle) {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ p_cb->sdp_handle = 0;
+ }
+ status = BTA_HL_STATUS_SDP_FAIL;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_sdp_update status=%s", bta_hl_status_code(status));
+#endif
+ return status;
+}
+
+/*****************************************************************************
+ *
+ * Function: bta_hl_sdp_register
+ *
+ * Purpose: Register an HDP application with SDP
+ *
+ * Parameters: p_cb - Pointer to MA instance control block
+ * p_service_name - MA server name
+ * inst_id - MAS instance ID
+ * msg_type - Supported message type(s)
+ *
+ *
+ * Returns: void
+ *
+ ****************************************************************************/
+tBTA_HL_STATUS bta_hl_sdp_register(uint8_t app_idx) {
+ uint16_t svc_class_id_list[BTA_HL_NUM_SVC_ELEMS];
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS];
+ tSDP_PROTO_LIST_ELEM add_proto_list;
+ tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list;
+ uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ uint8_t i, j, cnt, mdep_id, mdep_role;
+ uint8_t data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601;
+ uint8_t mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK;
+ uint16_t profile_uuid = UUID_SERVCLASS_HDP_PROFILE;
+ uint16_t version = BTA_HL_VERSION;
+ uint8_t num_services = 1;
+ tBTA_HL_APP_CB* p_cb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ bool result = true;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_sdp_register app_idx=%d", app_idx);
+#endif
+
+ if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) &&
+ (!p_cb->sup_feature.advertize_source_sdp)) {
+ return BTA_HL_STATUS_OK;
+ }
+
+ p_cb->sdp_handle = SDP_CreateRecord();
+ if (p_cb->sdp_handle == 0) {
+ return BTA_HL_STATUS_SDP_NO_RESOURCE;
+ }
+
+ num_services = 1;
+ svc_class_id_list[0] = UUID_SERVCLASS_HDP_SOURCE;
+ if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) {
+ svc_class_id_list[0] = UUID_SERVCLASS_HDP_SINK;
+ } else {
+ if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) {
+ /* dual role */
+ num_services = 2;
+ svc_class_id_list[1] = UUID_SERVCLASS_HDP_SINK;
+ }
+ }
+ result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services,
+ svc_class_id_list);
+
+ if (result) {
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 1;
+ proto_elem_list[0].params[0] = p_cb->ctrl_psm;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = version;
+ result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS,
+ proto_elem_list);
+
+ result &=
+ SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version);
+ }
+
+ if (result) {
+ add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS;
+ add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ add_proto_list.list_elem[0].num_params = 1;
+ add_proto_list.list_elem[0].params[0] = p_cb->data_psm;
+ add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA;
+ add_proto_list.list_elem[1].num_params = 0;
+ result &=
+ SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS,
+ (tSDP_PROTO_LIST_ELEM*)&add_proto_list);
+ }
+
+ if (result) {
+ if (p_cb->srv_name[0]) {
+ result &= SDP_AddAttribute(
+ p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_name) + 1),
+ (uint8_t*)p_cb->srv_name);
+ } /* end of setting optional service name */
+ }
+
+ if (result) {
+ if (p_cb->srv_desp[0]) {
+ result &= SDP_AddAttribute(
+ p_cb->sdp_handle, (uint16_t)ATTR_ID_SERVICE_DESCRIPTION,
+ (uint8_t)TEXT_STR_DESC_TYPE, (uint32_t)(strlen(p_cb->srv_desp) + 1),
+ (uint8_t*)p_cb->srv_desp);
+
+ } /* end of setting optional service description */
+ }
+
+ if (result) {
+ if (p_cb->provider_name[0]) {
+ result &=
+ SDP_AddAttribute(p_cb->sdp_handle, (uint16_t)ATTR_ID_PROVIDER_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_cb->provider_name) + 1),
+ (uint8_t*)p_cb->provider_name);
+ } /* end of setting optional provider name */
+ }
+
+ /* add supported feture list */
+
+ if (result) {
+ cnt = 0;
+ for (i = 1; i <= p_cb->sup_feature.num_of_mdeps; i++) {
+ mdep_id = (uint8_t)p_cb->sup_feature.mdep[i].mdep_id;
+ mdep_role = (uint8_t)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role;
+
+ for (j = 0; j < p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types;
+ j++) {
+ sup_feature_list.list_elem[cnt].mdep_id = mdep_id;
+ sup_feature_list.list_elem[cnt].mdep_role = mdep_role;
+ sup_feature_list.list_elem[cnt].data_type =
+ p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type;
+ if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') {
+ sup_feature_list.list_elem[cnt].p_mdep_desp =
+ p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp;
+ } else {
+ sup_feature_list.list_elem[cnt].p_mdep_desp = NULL;
+ }
+
+ cnt++;
+ if (cnt == BTA_HL_NUM_SUP_FEATURE_ELEMS) {
+ result = false;
+ break;
+ }
+ }
+ }
+ sup_feature_list.num_elems = cnt;
+ result &= bta_hl_add_sup_feature_list(p_cb->sdp_handle,
+ sup_feature_list.num_elems,
+ sup_feature_list.list_elem);
+ }
+ if (result) {
+ result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC,
+ UINT_DESC_TYPE, (uint32_t)1,
+ (uint8_t*)&data_exchange_spec);
+ }
+
+ if (result) {
+ result &=
+ SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC,
+ UINT_DESC_TYPE, (uint32_t)1, (uint8_t*)&mcap_sup_proc);
+ }
+
+ if (result) {
+ result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST,
+ 1, browse_list);
+ }
+
+ if (result) {
+ for (i = 0; i < num_services; i++) {
+ bta_sys_add_uuid(svc_class_id_list[i]);
+ APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i,
+ svc_class_id_list[i]); // todo
+ }
+ } else {
+ if (p_cb->sdp_handle) {
+ SDP_DeleteRecord(p_cb->sdp_handle);
+ p_cb->sdp_handle = 0;
+ }
+ status = BTA_HL_STATUS_SDP_FAIL;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_sdp_register status=%s", bta_hl_status_code(status));
+#endif
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_sink_or_src_srv_class_in_db
+ *
+ * Description This function queries an SDP database for either a HDP Sink
+ * or Source service class ID.
+ * If the p_start_rec pointer is NULL, it looks from the
+ * beginning of the database, else it continues from the next
+ * record after p_start_rec.
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* bta_hl_find_sink_or_src_srv_class_in_db(
+ const tSDP_DISCOVERY_DB* p_db, const tSDP_DISC_REC* p_start_rec) {
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL) return (NULL);
+
+ if (!p_start_rec) {
+ p_rec = p_db->p_first_rec;
+ } else {
+ p_rec = p_start_rec->p_next_rec;
+ }
+
+ while (p_rec) {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) &&
+ ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) ||
+ (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE))) {
+ return (p_rec);
+ }
+ }
+ break;
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+/* If here, no matching UUID found */
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_find_sink_or_src_srv_class_in_db failed");
+#endif
+
+ return (NULL);
+}
+#endif /* HL_INCLUDED */
diff --git a/mtkbt/code/bt/bta/hl/bta_hl_utils.cc b/mtkbt/code/bt/bta/hl/bta_hl_utils.cc
new file mode 100755
index 0000000..2161bd2
--- a/dev/null
+++ b/mtkbt/code/bt/bta/hl/bta_hl_utils.cc
@@ -0,0 +1,3093 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file implements utility functions for the HeaLth device profile
+ * (HL).
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "bt_target.h"
+#if (HL_INCLUDED == TRUE)
+
+#include "bt_common.h"
+#include "bta_hl_co.h"
+#include "bta_hl_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_ctrl_psm_for_dch
+ *
+ * Description This function set the control PSM for the DCH setup
+ *
+ * Returns bool - true - control PSM setting is successful
+ ******************************************************************************/
+bool bta_hl_set_ctrl_psm_for_dch(uint8_t app_idx, uint8_t mcl_idx,
+ UNUSED_ATTR uint8_t mdl_idx,
+ uint16_t ctrl_psm) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool success = true, update_ctrl_psm = false;
+
+ if (p_mcb->sdp.num_recs) {
+ if (p_mcb->ctrl_psm != ctrl_psm) {
+ /* can not use a different ctrl PSM than the current one*/
+ success = false;
+ }
+ } else {
+ /* No SDP info control i.e. channel was opened by the peer */
+ update_ctrl_psm = true;
+ }
+
+ if (success && update_ctrl_psm) {
+ p_mcb->ctrl_psm = ctrl_psm;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!success) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_set_ctrl_psm_for_dch num_recs=%d success=%d update_ctrl_psm=%d "
+ "ctrl_psm=0x%x ",
+ p_mcb->sdp.num_recs, success, update_ctrl_psm, ctrl_psm);
+ }
+#endif
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_sdp_idx_using_ctrl_psm
+ *
+ * Description
+ *
+ * Returns true if found
+ *
+ ******************************************************************************/
+bool bta_hl_find_sdp_idx_using_ctrl_psm(tBTA_HL_SDP* p_sdp, uint16_t ctrl_psm,
+ uint8_t* p_sdp_idx) {
+ bool found = false;
+ tBTA_HL_SDP_REC* p_rec;
+ uint8_t i;
+
+ if (ctrl_psm != 0) {
+ for (i = 0; i < p_sdp->num_recs; i++) {
+ p_rec = &p_sdp->sdp_rec[i];
+ if (p_rec->ctrl_psm == ctrl_psm) {
+ *p_sdp_idx = i;
+ found = true;
+ break;
+ }
+ }
+ } else {
+ *p_sdp_idx = 0;
+ found = true;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_sdp_idx_using_ctrl_psm found=%d sdp_idx=%d ctrl_psm=0x%x ",
+ found, *p_sdp_idx, ctrl_psm);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_user_tx_buf_size
+ *
+ * Description This function sets the user tx buffer size
+ *
+ * Returns uint16_t buf_size
+ *
+ ******************************************************************************/
+
+uint16_t bta_hl_set_user_tx_buf_size(uint16_t max_tx_size) {
+ if (max_tx_size > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
+ return L2CAP_INVALID_ERM_BUF_SIZE;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_user_rx_buf_size
+ *
+ * Description This function sets the user rx buffer size
+ *
+ * Returns uint16_t buf_size
+ *
+ ******************************************************************************/
+
+uint16_t bta_hl_set_user_rx_buf_size(uint16_t mtu) {
+ if (mtu > BT_DEFAULT_BUFFER_SIZE) return BTA_HL_LRG_DATA_BUF_SIZE;
+ return L2CAP_INVALID_ERM_BUF_SIZE;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_tx_win_size
+ *
+ * Description This function sets the tx window size
+ *
+ * Returns uint8_t tx_win_size
+ *
+ ******************************************************************************/
+uint8_t bta_hl_set_tx_win_size(uint16_t mtu, uint16_t mps) {
+ uint8_t tx_win_size;
+
+ if (mtu <= mps) {
+ tx_win_size = 1;
+ } else {
+ if (mps > 0) {
+ tx_win_size = (mtu / mps) + 1;
+ } else {
+ APPL_TRACE_ERROR("The MPS is zero");
+ tx_win_size = 10;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_set_tx_win_size win_size=%d mtu=%d mps=%d",
+ tx_win_size, mtu, mps);
+#endif
+ return tx_win_size;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_mps
+ *
+ * Description This function sets the MPS
+ *
+ * Returns uint16_t MPS
+ *
+ ******************************************************************************/
+uint16_t bta_hl_set_mps(uint16_t mtu) {
+ uint16_t mps;
+ if (mtu > BTA_HL_L2C_MPS) {
+ mps = BTA_HL_L2C_MPS;
+ } else {
+ mps = mtu;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_set_mps mps=%d mtu=%d", mps, mtu);
+#endif
+ return mps;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_clean_mdl_cb
+ *
+ * Description This function clean up the specified MDL control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_clean_mdl_cb(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_clean_mdl_cb app_idx=%d mcl_idx=%d mdl_idx=%d",
+ app_idx, mcl_idx, mdl_idx);
+#endif
+ osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+ osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+ osi_free_and_reset((void**)&p_dcb->p_echo_tx_pkt);
+ osi_free_and_reset((void**)&p_dcb->p_echo_rx_pkt);
+
+ memset((void*)p_dcb, 0, sizeof(tBTA_HL_MDL_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_get_buf
+ *
+ * Description This function allocate a buffer based on the specified data size
+ *
+ * Returns BT_HDR *.
+ *
+ ******************************************************************************/
+BT_HDR* bta_hl_get_buf(uint16_t data_size, bool fcs_use) {
+ size_t size = data_size + L2CAP_MIN_OFFSET + BT_HDR_SIZE + L2CAP_FCS_LEN +
+ L2CAP_EXT_CONTROL_OVERHEAD;
+
+ if (fcs_use) size += L2CAP_FCS_LEN;
+
+ BT_HDR* p_new = (BT_HDR*)osi_malloc(size);
+ p_new->len = data_size;
+ p_new->offset = L2CAP_MIN_OFFSET;
+
+ return p_new;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_service_in_db
+ *
+ * Description This function check the specified service class(es) can be find
+ * in the received SDP database
+ *
+ * Returns bool true - found
+ * false - not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_service_in_db(uint8_t app_idx, uint8_t mcl_idx,
+ uint16_t service_uuid, tSDP_DISC_REC** pp_rec) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = true;
+
+ switch (service_uuid) {
+ case UUID_SERVCLASS_HDP_SINK:
+ case UUID_SERVCLASS_HDP_SOURCE:
+ *pp_rec = SDP_FindServiceInDb(p_mcb->p_db, service_uuid, *pp_rec);
+ if (*pp_rec == NULL) {
+ found = false;
+ }
+ break;
+ default:
+ *pp_rec = bta_hl_find_sink_or_src_srv_class_in_db(p_mcb->p_db, *pp_rec);
+ if (*pp_rec == NULL) {
+ found = false;
+ }
+ break;
+ }
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_get_service_uuids
+ *
+ *
+ * Description This function finds the service class(es) for both CCH and DCH
+ * operations
+ *
+ * Returns uint16_t - service_id
+ * if service_uuid = 0xFFFF then it means service uuid
+ * can be either Sink or Source
+ *
+ ******************************************************************************/
+uint16_t bta_hl_get_service_uuids(uint8_t sdp_oper, uint8_t app_idx,
+ uint8_t mcl_idx, uint8_t mdl_idx) {
+ tBTA_HL_MDL_CB* p_dcb;
+ uint16_t service_uuid = 0xFFFF; /* both Sink and Source */
+
+ switch (sdp_oper) {
+ case BTA_HL_SDP_OP_DCH_OPEN_INIT:
+ case BTA_HL_SDP_OP_DCH_RECONNECT_INIT:
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (p_dcb->local_mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+ if (p_dcb->peer_mdep_role == BTA_HL_MDEP_ROLE_SINK) {
+ service_uuid = UUID_SERVCLASS_HDP_SINK;
+ } else {
+ service_uuid = UUID_SERVCLASS_HDP_SOURCE;
+ }
+ }
+ break;
+ case BTA_HL_SDP_OP_CCH_INIT:
+ default:
+ /* use default that is both Sink and Source */
+ break;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_get_service_uuids service_uuid=0x%x", service_uuid);
+#endif
+ return service_uuid;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_echo_cfg_rsp
+ *
+ *
+ * Description This function finds the configuration response for the echo test
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_echo_cfg_rsp(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdep_idx, uint8_t cfg,
+ uint8_t* p_cfg_rsp) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDEP* p_mdep = &p_acb->sup_feature.mdep[mdep_idx];
+ bool status = true;
+
+ if (p_mdep->mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ if ((cfg == BTA_HL_DCH_CFG_RELIABLE) || (cfg == BTA_HL_DCH_CFG_STREAMING)) {
+ *p_cfg_rsp = cfg;
+ } else if (cfg == BTA_HL_DCH_CFG_NO_PREF) {
+ *p_cfg_rsp = BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG;
+ } else {
+ status = false;
+ APPL_TRACE_ERROR("Inavlid echo cfg value");
+ }
+ return status;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!status) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_echo_cfg_rsp status=failed app_idx=%d mcl_idx=%d "
+ "mdep_idx=%d cfg=%d",
+ app_idx, mcl_idx, mdep_idx, cfg);
+ }
+#endif
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_validate_dch_cfg
+ *
+ * Description This function validate the DCH configuration
+ *
+ * Returns bool - true cfg is valid
+ * false not valid
+ *
+ ******************************************************************************/
+bool bta_hl_validate_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ uint8_t cfg) {
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ bool is_valid = false;
+
+ if (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx) &&
+ (cfg != BTA_HL_DCH_CFG_RELIABLE)) {
+ APPL_TRACE_ERROR("the first DCH should be a reliable channel");
+ return is_valid;
+ }
+
+ switch (p_dcb->local_cfg) {
+ case BTA_HL_DCH_CFG_NO_PREF:
+
+ if ((cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+ (cfg == BTA_HL_DCH_CFG_STREAMING)) {
+ is_valid = true;
+ }
+ break;
+ case BTA_HL_DCH_CFG_RELIABLE:
+ case BTA_HL_DCH_CFG_STREAMING:
+ if (p_dcb->local_cfg == cfg) {
+ is_valid = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!is_valid) {
+ APPL_TRACE_DEBUG("bta_hl_validate_dch_open_cfg is_valid=%d, cfg=%d",
+ is_valid, cfg);
+ }
+#endif
+ return is_valid;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_cch_cb_indexes
+ *
+ * Description This function finds the indexes needed for the CCH state machine
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_cch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx) {
+ bool found = false;
+ tBTA_HL_MCL_CB* p_mcb;
+ uint8_t app_idx = 0, mcl_idx = 0;
+
+ switch (p_msg->hdr.event) {
+ case BTA_HL_CCH_SDP_OK_EVT:
+ case BTA_HL_CCH_SDP_FAIL_EVT:
+ app_idx = p_msg->cch_sdp.app_idx;
+ mcl_idx = p_msg->cch_sdp.mcl_idx;
+ found = true;
+ break;
+
+ case BTA_HL_MCA_CONNECT_IND_EVT:
+
+ if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
+ &app_idx)) {
+ if (bta_hl_find_mcl_idx(app_idx,
+ p_msg->mca_evt.mca_data.connect_ind.bd_addr,
+ &mcl_idx)) {
+ /* local initiated */
+ found = true;
+ } else if (!bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle,
+ &app_idx, &mcl_idx) &&
+ bta_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+ /* remote initiated */
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ p_mcb->in_use = true;
+ p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_OPEN;
+ found = true;
+ }
+ }
+ break;
+
+ case BTA_HL_MCA_DISCONNECT_IND_EVT:
+
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx)) {
+ found = true;
+ } else if (bta_hl_find_app_idx_using_handle(p_msg->mca_evt.app_handle,
+ &app_idx) &&
+ bta_hl_find_mcl_idx(
+ app_idx, p_msg->mca_evt.mca_data.disconnect_ind.bd_addr,
+ &mcl_idx)) {
+ found = true;
+ }
+
+ if (found) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if ((p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) &&
+ (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_REMOTE_CLOSE;
+ }
+ }
+ break;
+
+ case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx)) {
+ found = true;
+ }
+
+ if (found) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if ((p_mcb->cch_oper != BTA_HL_CCH_OP_REMOTE_CLOSE) &&
+ (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_OPEN)) {
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (found) {
+ *p_app_idx = app_idx;
+ *p_mcl_idx = mcl_idx;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_cch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d",
+ bta_hl_evt_code(p_msg->hdr.event), found, app_idx, mcl_idx);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_dch_cb_indexes
+ *
+ * Description This function finds the indexes needed for the DCH state machine
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_dch_cb_indexes(tBTA_HL_DATA* p_msg, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx, uint8_t* p_mdl_idx) {
+ bool found = false;
+ tBTA_HL_MCL_CB* p_mcb;
+ uint8_t app_idx = 0, mcl_idx = 0, mdl_idx = 0;
+
+ switch (p_msg->hdr.event) {
+ case BTA_HL_MCA_CREATE_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.create_cfm.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+
+ case BTA_HL_MCA_CREATE_IND_EVT:
+ case BTA_HL_MCA_RECONNECT_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+ break;
+
+ case BTA_HL_MCA_OPEN_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.open_cfm.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+
+ case BTA_HL_MCA_OPEN_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.open_ind.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+
+ case BTA_HL_MCA_CLOSE_CFM_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle(
+ (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_cfm.mdl,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_MCA_CLOSE_IND_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle(
+ (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.close_ind.mdl,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_API_SEND_DATA_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle(p_msg->api_send_data.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+
+ break;
+
+ case BTA_HL_MCA_CONG_CHG_EVT:
+
+ if (bta_hl_find_mdl_idx_using_handle(
+ (tBTA_HL_MDL_HANDLE)p_msg->mca_evt.mca_data.cong_chg.mdl,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+
+ break;
+
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ app_idx = p_msg->mca_rcv_data_evt.app_idx;
+ mcl_idx = p_msg->mca_rcv_data_evt.mcl_idx;
+ mdl_idx = p_msg->mca_rcv_data_evt.mdl_idx;
+ found = true;
+ break;
+ case BTA_HL_DCH_RECONNECT_EVT:
+ case BTA_HL_DCH_OPEN_EVT:
+ case BTA_HL_DCH_ECHO_TEST_EVT:
+ case BTA_HL_DCH_SDP_FAIL_EVT:
+ app_idx = p_msg->dch_sdp.app_idx;
+ mcl_idx = p_msg->dch_sdp.mcl_idx;
+ mdl_idx = p_msg->dch_sdp.mdl_idx;
+ found = true;
+ break;
+ case BTA_HL_MCA_RECONNECT_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.reconnect_cfm.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+
+ case BTA_HL_API_DCH_CREATE_RSP_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->api_dch_create_rsp.mcl_handle,
+ &app_idx, &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->api_dch_create_rsp.mdl_id, &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_MCA_ABORT_IND_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.abort_ind.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_MCA_ABORT_CFM_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(p_msg->mca_evt.mcl_handle, &app_idx,
+ &mcl_idx) &&
+ bta_hl_find_mdl_idx(app_idx, mcl_idx,
+ p_msg->mca_evt.mca_data.abort_cfm.mdl_id,
+ &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_CI_GET_TX_DATA_EVT:
+ case BTA_HL_CI_PUT_RX_DATA_EVT:
+ if (bta_hl_find_mdl_idx_using_handle(p_msg->ci_get_put_data.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ found = true;
+ }
+ break;
+ case BTA_HL_CI_GET_ECHO_DATA_EVT:
+ case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+ if (bta_hl_find_mcl_idx_using_handle(
+ p_msg->ci_get_put_echo_data.mcl_handle, &app_idx, &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ mdl_idx = p_mcb->echo_mdl_idx;
+ found = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (found) {
+ *p_app_idx = app_idx;
+ *p_mcl_idx = mcl_idx;
+ *p_mdl_idx = mdl_idx;
+ }
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_dch_cb_indexes event=%s found=%d app_idx=%d mcl_idx=%d "
+ "mdl_idx=%d",
+ bta_hl_evt_code(p_msg->hdr.event), found, *p_app_idx, *p_mcl_idx,
+ *p_mdl_idx);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_allocate_mdl_id
+ *
+ * Description This function allocates a MDL ID
+ *
+ * Returns uint16_t - MDL ID
+ *
+ ******************************************************************************/
+uint16_t bta_hl_allocate_mdl_id(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx) {
+ uint16_t mdl_id = 0;
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool duplicate_id;
+ uint8_t i, mdl_cfg_idx;
+
+ do {
+ duplicate_id = false;
+ mdl_id = ((mdl_id + 1) & 0xFEFF);
+ /* check mdl_ids that are used for the current conenctions */
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use && (i != mdl_idx) &&
+ (p_mcb->mdl[i].mdl_id == mdl_id)) {
+ duplicate_id = true;
+ break;
+ }
+ }
+
+ if (duplicate_id) {
+ /* start from the beginning to get another MDL value*/
+ continue;
+ } else {
+ /* check mdl_ids that are stored in the persistent memory */
+ if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
+ duplicate_id = true;
+ } else {
+ /* found a new MDL value */
+ break;
+ }
+ }
+
+ } while (true);
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_allocate_mdl OK mdl_id=%d", mdl_id);
+#endif
+ return mdl_id;
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mdl_idx
+ *
+ * Description This function finds the MDL index based on mdl_id
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx, uint16_t mdl_id,
+ uint8_t* p_mdl_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use && (mdl_id != 0) &&
+ (p_mcb->mdl[i].mdl_id == mdl_id)) {
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_mdl_idx found=%d mdl_id=%d mdl_idx=%d ",
+ found, mdl_id, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_an_active_mdl_idx
+ *
+ * Description This function finds an active MDL
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_active_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use &&
+ (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPEN_ST)) {
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_an_opened_mdl_idx found=%d app_idx=%d mcl_idx=%d "
+ "mdl_idx=%d",
+ found, app_idx, mcl_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_dch_setup_mdl_idx
+ *
+ * Description This function finds a MDL which in the DCH setup state
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_dch_setup_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use &&
+ (p_mcb->mdl[i].dch_state == BTA_HL_DCH_OPENING_ST)) {
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_dch_setup_mdl_idx found=%d app_idx=%d mcl_idx=%d "
+ "mdl_idx=%d",
+ found, app_idx, mcl_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_an_in_use_mcl_idx
+ *
+ * Description This function finds an in-use MCL control block index
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_in_use_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+ tBTA_HL_MCL_CB* p_mcb;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, i);
+ if (p_mcb->in_use && (p_mcb->cch_state != BTA_HL_CCH_IDLE_ST)) {
+ found = true;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_an_in_use_mcl_idx found=%d app_idx=%d mcl_idx=%d ", found,
+ app_idx, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_an_in_use_app_idx
+ *
+ * Description This function finds an in-use application control block index
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_an_in_use_app_idx(uint8_t* p_app_idx) {
+ tBTA_HL_APP_CB* p_acb;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (found) {
+ APPL_TRACE_DEBUG("bta_hl_find_an_in_use_app_idx found=%d app_idx=%d ",
+ found, i);
+ }
+#endif
+
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_find_app_idx
+ *
+ * Description This function finds the application control block index based on
+ * the application ID
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_find_app_idx found=%d app_id=%d idx=%d ", found,
+ app_id, i);
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_app_idx_using_handle
+ *
+ * Description This function finds the application control block index based on
+ * the application handle
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (bta_hl_cb.acb[i].in_use &&
+ (bta_hl_cb.acb[i].app_handle == app_handle)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_app_idx_using_mca_handle status=%d handle=%d app_idx=%d ",
+ found, app_handle, i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mcl_idx_using_handle
+ *
+ * Description This function finds the MCL control block index based on
+ * the MCL handle
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+ uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+ tBTA_HL_APP_CB* p_acb;
+ bool found = false;
+ uint8_t i = 0, j = 0;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) {
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].mcl_handle == mcl_handle) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_mcl_idx_using_handle found=%d app_idx=%d mcl_idx=%d",
+ found, i, j);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mcl_idx
+ *
+ * Description This function finds the MCL control block index based on
+ * the peer BD address
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+ uint8_t* p_mcl_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+ if (bta_hl_cb.acb[app_idx].mcb[i].in_use &&
+ (!memcmp(bta_hl_cb.acb[app_idx].mcb[i].bd_addr, p_bd_addr,
+ BD_ADDR_LEN))) {
+ found = true;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_mcl_idx found=%d idx=%d", found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mdl_idx_using_handle
+ *
+ * Description This function finds the MDL control block index based on
+ * the MDL handle
+ *
+ * Returns bool true-found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ uint8_t* p_app_idx, uint8_t* p_mcl_idx,
+ uint8_t* p_mdl_idx) {
+ tBTA_HL_APP_CB* p_acb;
+ tBTA_HL_MCL_CB* p_mcb;
+ tBTA_HL_MDL_CB* p_dcb;
+ bool found = false;
+ uint8_t i, j, k;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) {
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(i, j);
+ if (p_mcb->in_use) {
+ for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(i, j, k);
+ if (p_dcb->in_use) {
+ if (p_dcb->mdl_handle == mdl_handle) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_mdl_idx_using_handle found=%d mdl_handle=%d ", found,
+ mdl_handle);
+ }
+#endif
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_is_the_first_reliable_existed
+ *
+ * Description This function checks whether the first reliable DCH channel
+ * has been setup on the MCL or not
+ *
+ * Returns bool - true exist
+ * false does not exist
+ *
+ ******************************************************************************/
+bool bta_hl_is_the_first_reliable_existed(uint8_t app_idx, uint8_t mcl_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool is_existed = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) {
+ is_existed = true;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d ",
+ is_existed);
+#endif
+ return is_existed;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_non_active_mdl_cfg
+ *
+ * Description This function finds a valid MDL configiration index and this
+ * MDL ID is not active
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_non_active_mdl_cfg(uint8_t app_idx, uint8_t start_mdl_cfg_idx,
+ uint8_t* p_mdl_cfg_idx) {
+ tBTA_HL_MCL_CB* p_mcb;
+ tBTA_HL_MDL_CB* p_dcb;
+ tBTA_HL_MDL_CFG* p_mdl;
+ bool mdl_in_use;
+ bool found = false;
+ uint8_t i, j, k;
+
+ for (i = start_mdl_cfg_idx; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ mdl_in_use = false;
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, j);
+ if (p_mcb->in_use &&
+ !memcmp(p_mdl->peer_bd_addr, p_mcb->bd_addr, BD_ADDR_LEN)) {
+ for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, j, k);
+
+ if (p_dcb->in_use && p_mdl->mdl_id == p_dcb->mdl_id) {
+ mdl_in_use = true;
+ break;
+ }
+ }
+ }
+
+ if (mdl_in_use) {
+ break;
+ }
+ }
+
+ if (!mdl_in_use) {
+ *p_mdl_cfg_idx = i;
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mdl_cfg_idx
+ *
+ * Description This function finds an available MDL configuration index
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mdl_cfg_idx(uint8_t app_idx, UNUSED_ATTR uint8_t mcl_idx,
+ uint8_t* p_mdl_cfg_idx) {
+ tBTA_HL_MDL_CFG *p_mdl, *p_mdl1, *p_mdl2;
+ uint8_t i;
+ bool found = false;
+ uint8_t first_mdl_cfg_idx, second_mdl_cfg_idx, older_mdl_cfg_idx;
+ bool done;
+
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (!p_mdl->active) {
+ /* found an unused space to store mdl cfg*/
+ found = true;
+ *p_mdl_cfg_idx = i;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* all available mdl cfg spaces are in use so we need to find the mdl cfg
+ which is
+ not currently in use and has the the oldest time stamp to remove*/
+
+ found = true;
+ if (bta_hl_find_non_active_mdl_cfg(app_idx, 0, &first_mdl_cfg_idx)) {
+ if (bta_hl_find_non_active_mdl_cfg(
+ app_idx, (uint8_t)(first_mdl_cfg_idx + 1), &second_mdl_cfg_idx)) {
+ done = false;
+ while (!done) {
+ p_mdl1 = BTA_HL_GET_MDL_CFG_PTR(app_idx, first_mdl_cfg_idx);
+ p_mdl2 = BTA_HL_GET_MDL_CFG_PTR(app_idx, second_mdl_cfg_idx);
+
+ if (p_mdl1->time < p_mdl2->time) {
+ older_mdl_cfg_idx = first_mdl_cfg_idx;
+ } else {
+ older_mdl_cfg_idx = second_mdl_cfg_idx;
+ }
+
+ if (bta_hl_find_non_active_mdl_cfg(app_idx,
+ (uint8_t)(second_mdl_cfg_idx + 1),
+ &second_mdl_cfg_idx)) {
+ first_mdl_cfg_idx = older_mdl_cfg_idx;
+ } else {
+ done = true;
+ }
+ }
+
+ *p_mdl_cfg_idx = older_mdl_cfg_idx;
+
+ } else {
+ *p_mdl_cfg_idx = first_mdl_cfg_idx;
+ }
+
+ } else {
+ found = false;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_cfg_idx found=%d mdl_cfg_idx=%d ",
+ found, *p_mdl_cfg_idx);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mdl_cfg_idx
+ *
+ * Description This function finds the MDL configuration index based on
+ * the MDL ID
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdl_cfg_idx(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_MDL_ID mdl_id, uint8_t* p_mdl_cfg_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CFG* p_mdl;
+ uint8_t i;
+ bool found = false;
+
+ *p_mdl_cfg_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active)
+ APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx: mdl_id =%d, p_mdl->mdl_id=%d",
+ mdl_id, p_mdl->mdl_id);
+ if (p_mdl->active &&
+ (!memcmp(p_mcb->bd_addr, p_mdl->peer_bd_addr, BD_ADDR_LEN)) &&
+ (p_mdl->mdl_id == mdl_id)) {
+ found = true;
+ *p_mdl_cfg_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_mdl_cfg_idx found=%d mdl_cfg_idx=%d ", found,
+ i);
+ }
+#endif
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_get_cur_time
+ *
+ * Description This function get the cuurent time value
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_get_cur_time(uint8_t app_idx, uint8_t* p_cur_time) {
+ tBTA_HL_MDL_CFG* p_mdl;
+ uint8_t i, j, time_latest, time;
+ bool found = false, result = true;
+
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active) {
+ found = true;
+ time_latest = p_mdl->time;
+ for (j = (i + 1); j < BTA_HL_NUM_MDL_CFGS; j++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, j);
+ if (p_mdl->active) {
+ time = p_mdl->time;
+ if (time > time_latest) {
+ time_latest = time;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (found) {
+ if (time_latest < BTA_HL_MAX_TIME) {
+ *p_cur_time = time_latest + 1;
+ } else {
+ /* need to wrap around */
+ result = false;
+ }
+ } else {
+ *p_cur_time = BTA_HL_MIN_TIME;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!result) {
+ APPL_TRACE_DEBUG("bta_hl_get_cur_time result=%s cur_time=%d",
+ (result ? "OK" : "FAIL"), *p_cur_time);
+ }
+#endif
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_sort_cfg_time_idx
+ *
+ * Description This function sort the mdl configuration idx stored in array a
+ * based on decending time value
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+void bta_hl_sort_cfg_time_idx(uint8_t app_idx, uint8_t* a, uint8_t n) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ uint8_t temp_time, temp_idx;
+ int16_t i, j;
+ for (i = 1; i < n; ++i) {
+ temp_idx = a[i];
+ temp_time = p_acb->mdl_cfg[temp_idx].time;
+ j = i - 1;
+ while ((j >= 0) && (temp_time < p_acb->mdl_cfg[a[j]].time)) {
+ a[j + 1] = a[j];
+ --j;
+ }
+ a[j + 1] = temp_idx;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_compact_mdl_cfg_time
+ *
+ * Description This function finds the MDL configuration index based on
+ * the MDL ID
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+void bta_hl_compact_mdl_cfg_time(uint8_t app_idx, uint8_t mdep_id) {
+ tBTA_HL_MDL_CFG* p_mdl;
+ uint8_t i, time_min, cnt = 0;
+ uint8_t s_arr[BTA_HL_NUM_MDL_CFGS];
+
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active) {
+ s_arr[cnt] = i;
+ cnt++;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_compact_mdl_cfg_time cnt=%d ", cnt);
+#endif
+
+ if (cnt) {
+ bta_hl_sort_cfg_time_idx(app_idx, s_arr, cnt);
+ time_min = BTA_HL_MIN_TIME;
+ for (i = 0; i < cnt; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, s_arr[i]);
+ p_mdl->time = time_min + i;
+ bta_hl_co_save_mdl(mdep_id, s_arr[i], p_mdl);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_is_mdl_exsit_in_mcl
+ *
+ * Description This function checks whether the MDL ID
+ * has already existed in teh MCL or not
+ *
+ * Returns bool - true exist
+ * false does not exist
+ *
+ ******************************************************************************/
+bool bta_hl_is_mdl_exsit_in_mcl(uint8_t app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id) {
+ tBTA_HL_MDL_CFG* p_mdl;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active && !memcmp(p_mdl->peer_bd_addr, bd_addr, BD_ADDR_LEN)) {
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+ if (p_mdl->mdl_id == mdl_id) {
+ found = true;
+ break;
+ }
+ } else {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_delete_mdl_cfg
+ *
+ * Description This function delete the specified MDL ID
+ *
+ * Returns bool - true Success
+ * false Failed
+ *
+ ******************************************************************************/
+bool bta_hl_delete_mdl_cfg(uint8_t app_idx, BD_ADDR bd_addr,
+ tBTA_HL_MDL_ID mdl_id) {
+ tBTA_HL_MDL_CFG* p_mdl;
+ bool success = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDL_CFGS; i++) {
+ p_mdl = BTA_HL_GET_MDL_CFG_PTR(app_idx, i);
+ if (p_mdl->active && !memcmp(p_mdl->peer_bd_addr, bd_addr, BD_ADDR_LEN)) {
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+ if (p_mdl->mdl_id == mdl_id) {
+ bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
+ memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+ success = true;
+ break;
+ }
+ } else {
+ bta_hl_co_delete_mdl(p_mdl->local_mdep_id, i);
+ memset(p_mdl, 0, sizeof(tBTA_HL_MDL_CFG));
+ success = true;
+ }
+ }
+ }
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_is_mdl_value_valid
+ *
+ *
+ * Description This function checks the specified MDL ID is in valid range.
+ *
+ * Returns bool - true Success
+ * false Failed
+ *
+ * note: mdl_id range 0x0000 reserved,
+ * 0x0001-oxFEFF dynamic range,
+ * 0xFF00-0xFFFE reserved,
+ * 0xFFFF indicates all MDLs (for delete operation only)
+ *
+ ******************************************************************************/
+bool bta_hl_is_mdl_value_valid(tBTA_HL_MDL_ID mdl_id) {
+ bool status = true;
+
+ if (mdl_id != BTA_HL_DELETE_ALL_MDL_IDS) {
+ if (mdl_id != 0) {
+ if (mdl_id > BTA_HL_MAX_MDL_VAL) {
+ status = false;
+ }
+ } else {
+ status = false;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_mdep_cfg_idx
+ *
+ * Description This function finds the MDEP configuration index based
+ * on the local MDEP ID
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_mdep_cfg_idx(uint8_t app_idx, tBTA_HL_MDEP_ID local_mdep_id,
+ uint8_t* p_mdep_cfg_idx) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < p_sup_feature->num_of_mdeps; i++) {
+ if (p_sup_feature->mdep[i].mdep_id == local_mdep_id) {
+ found = true;
+ *p_mdep_cfg_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_mdep_cfg_idx found=%d mdep_idx=%d local_mdep_id=%d ",
+ found, i, local_mdep_id);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_rxtx_apdu_size
+ *
+ * Description This function finds the maximum APDU rx and tx sizes based on
+ * the MDEP configuration data
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_find_rxtx_apdu_size(uint8_t app_idx, uint8_t mdep_cfg_idx,
+ uint16_t* p_rx_apu_size,
+ uint16_t* p_tx_apu_size) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDEP_CFG* p_mdep_cfg;
+ uint8_t i;
+ uint16_t max_rx_apdu_size = 0, max_tx_apdu_size = 0;
+
+ p_mdep_cfg = &p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg;
+
+ for (i = 0; i < p_mdep_cfg->num_of_mdep_data_types; i++) {
+ if (max_rx_apdu_size < p_mdep_cfg->data_cfg[i].max_rx_apdu_size) {
+ max_rx_apdu_size = p_mdep_cfg->data_cfg[i].max_rx_apdu_size;
+ }
+
+ if (max_tx_apdu_size < p_mdep_cfg->data_cfg[i].max_tx_apdu_size) {
+ max_tx_apdu_size = p_mdep_cfg->data_cfg[i].max_tx_apdu_size;
+ }
+ }
+
+ *p_rx_apu_size = max_rx_apdu_size;
+ *p_tx_apu_size = max_tx_apdu_size;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG(
+ "bta_hl_find_rxtx_apdu_size max_rx_apdu_size=%d max_tx_apdu_size=%d ",
+ max_rx_apdu_size, max_tx_apdu_size);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_validate_peer_cfg
+ *
+ * Description This function validates the peer DCH configuration
+ *
+ * Returns bool - true validation is successful
+ * false validation failed
+ *
+ ******************************************************************************/
+bool bta_hl_validate_peer_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_MDEP_ID peer_mdep_id,
+ tBTA_HL_MDEP_ROLE peer_mdep_role,
+ uint8_t sdp_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ tBTA_HL_SDP_REC* p_rec;
+ bool peer_found = false;
+ uint8_t i;
+
+ APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg sdp_idx=%d app_idx %d", sdp_idx,
+ app_idx);
+
+ if (p_dcb->local_mdep_id == BTA_HL_ECHO_TEST_MDEP_ID) {
+ return true;
+ }
+
+ p_rec = &p_mcb->sdp.sdp_rec[sdp_idx];
+ for (i = 0; i < p_rec->num_mdeps; i++) {
+ APPL_TRACE_DEBUG("mdep_id %d peer_mdep_id %d", p_rec->mdep_cfg[i].mdep_id,
+ peer_mdep_id);
+ APPL_TRACE_DEBUG("mdep_role %d peer_mdep_role %d",
+ p_rec->mdep_cfg[i].mdep_role, peer_mdep_role)
+ if ((p_rec->mdep_cfg[i].mdep_id == peer_mdep_id) &&
+ (p_rec->mdep_cfg[i].mdep_role == peer_mdep_role)) {
+ peer_found = true;
+
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!peer_found) {
+ APPL_TRACE_DEBUG("bta_hl_validate_peer_cfg failed num_mdeps=%d",
+ p_rec->num_mdeps);
+ }
+#endif
+ return peer_found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_chk_local_cfg
+ *
+ * Description This function check whether the local DCH configuration is OK.
+ *
+ * Returns tBTA_HL_STATUS - OK - local DCH configuration is OK
+ * NO_FIRST_RELIABLE - the streaming DCH
+ * configuration is not OK and
+ * it needs to use reliable
+ * DCH configuration
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_chk_local_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdep_cfg_idx,
+ tBTA_HL_DCH_CFG local_cfg) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+
+ if (mdep_cfg_idx &&
+ (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE) &&
+ (!bta_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) &&
+ (local_cfg != BTA_HL_DCH_CFG_RELIABLE)) {
+ status = BTA_HL_STATUS_NO_FIRST_RELIABLE;
+ APPL_TRACE_ERROR("BTA_HL_STATUS_INVALID_DCH_CFG");
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_validate_reconnect_params
+ *
+ * Description This function validates the reconnect parameters
+ *
+ * Returns bool - true validation is successful
+ * false validation failed
+ ******************************************************************************/
+bool bta_hl_validate_reconnect_params(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_API_DCH_RECONNECT* p_reconnect,
+ uint8_t* p_mdep_cfg_idx,
+ uint8_t* p_mdl_cfg_idx) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+ uint8_t num_mdeps;
+ uint8_t mdl_cfg_idx;
+ bool local_mdep_id_found = false;
+ bool mdl_cfg_found = false;
+ bool status = false;
+ uint8_t i, in_use_mdl_idx = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_validate_reconnect_params mdl_id=%d app_idx=%d",
+ p_reconnect->mdl_id, app_idx);
+#endif
+ if (bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
+ &mdl_cfg_idx)) {
+ mdl_cfg_found = true;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!mdl_cfg_found) {
+ APPL_TRACE_DEBUG("mdl_cfg_found not found");
+ }
+#endif
+
+ if (mdl_cfg_found) {
+ num_mdeps = p_sup_feature->num_of_mdeps;
+ for (i = 0; i < num_mdeps; i++) {
+ if (p_sup_feature->mdep[i].mdep_id ==
+ p_acb->mdl_cfg[mdl_cfg_idx].local_mdep_id) {
+ local_mdep_id_found = true;
+ *p_mdep_cfg_idx = i;
+ *p_mdl_cfg_idx = mdl_cfg_idx;
+ break;
+ }
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!local_mdep_id_found) {
+ APPL_TRACE_DEBUG("local_mdep_id not found");
+ }
+#endif
+
+ if (local_mdep_id_found) {
+ if (!bta_hl_find_mdl_idx(app_idx, mcl_idx, p_reconnect->mdl_id,
+ &in_use_mdl_idx)) {
+ status = true;
+ } else {
+ APPL_TRACE_ERROR("mdl_id=%d is curreltly in use", p_reconnect->mdl_id);
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!status) {
+ APPL_TRACE_DEBUG(
+ "Reconnect validation failed local_mdep_id found=%d mdl_cfg_idx "
+ "found=%d in_use_mdl_idx=%d ",
+ local_mdep_id_found, mdl_cfg_found, in_use_mdl_idx);
+ }
+#endif
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_avail_mcl_idx
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+ if (!bta_hl_cb.acb[app_idx].mcb[i].in_use) {
+ found = true;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_avail_mcl_idx found=%d idx=%d", found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_avail_mdl_idx
+ *
+ * Description This function finds an available MDL control block index
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (!p_mcb->mdl[i].in_use) {
+ memset((void*)&p_mcb->mdl[i], 0, sizeof(tBTA_HL_MDL_CB));
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_avail_mdl_idx found=%d idx=%d", found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_is_a_duplicate_id
+ *
+ * Description This function finds the application has been used or not
+ *
+ * Returns bool - true the app_id is a duplicate ID
+ * false not a duplicate ID
+ ******************************************************************************/
+bool bta_hl_is_a_duplicate_id(uint8_t app_id) {
+ bool is_duplicate = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (bta_hl_cb.acb[i].in_use && (bta_hl_cb.acb[i].app_id == app_id)) {
+ is_duplicate = true;
+
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (is_duplicate) {
+ APPL_TRACE_DEBUG("bta_hl_is_a_duplicate_id app_id=%d is_duplicate=%d",
+ app_id, is_duplicate);
+ }
+#endif
+
+ return is_duplicate;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_find_avail_app_idx
+ *
+ * Description This function finds an available application control block index
+ *
+ * Returns bool - true found
+ * false not found
+ *
+ ******************************************************************************/
+bool bta_hl_find_avail_app_idx(uint8_t* p_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (!bta_hl_cb.acb[i].in_use) {
+ found = true;
+ *p_idx = i;
+ break;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!found) {
+ APPL_TRACE_DEBUG("bta_hl_find_avail_app_idx found=%d app_idx=%d", found, i);
+ }
+#endif
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_app_update
+ *
+ * Description This function registers an HDP application MCAP and DP
+ *
+ * Returns tBTA_HL_STATUS -registration status
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_app_update(uint8_t app_id, bool is_register) {
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(0);
+ tMCA_CS mca_cs;
+ uint8_t i, mdep_idx, num_of_mdeps;
+ uint8_t mdep_counter = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_app_update app_id=%d", app_id);
+#endif
+
+ if (is_register) {
+ if ((status == BTA_HL_STATUS_OK) &&
+ bta_hl_co_get_num_of_mdep(app_id, &num_of_mdeps)) {
+ for (i = 0; i < num_of_mdeps; i++) {
+ mca_cs.type = MCA_TDEP_DATA;
+ mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+ mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+ /* Find the first available mdep index, and create a MDL Endpoint */
+ // make a function later if needed
+ for (mdep_idx = 1; mdep_idx < BTA_HL_NUM_MDEPS; mdep_idx++) {
+ if (p_acb->sup_feature.mdep[mdep_idx].mdep_id == 0) {
+ break; /* We found an available index */
+ } else {
+ mdep_counter++;
+ }
+ }
+ /* If no available MDEPs, return error */
+ if (mdep_idx == BTA_HL_NUM_MDEPS) {
+ APPL_TRACE_ERROR("bta_hl_app_update: Out of MDEP IDs");
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ break;
+ }
+ if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+ &(p_acb->sup_feature.mdep[mdep_idx].mdep_id),
+ &mca_cs) == MCA_SUCCESS) {
+ if (bta_hl_co_get_mdep_config(
+ app_id, mdep_idx, mdep_counter,
+ p_acb->sup_feature.mdep[mdep_idx].mdep_id,
+ &p_acb->sup_feature.mdep[mdep_idx].mdep_cfg)) {
+ p_acb->sup_feature.mdep[mdep_idx].ori_app_id = app_id;
+ APPL_TRACE_DEBUG("mdep idx %d id %d ori_app_id %d num data type %d",
+ mdep_idx,
+ p_acb->sup_feature.mdep[mdep_idx].mdep_id,
+ p_acb->sup_feature.mdep[mdep_idx].ori_app_id,
+ p_acb->sup_feature.mdep[mdep_idx]
+ .mdep_cfg.num_of_mdep_data_types);
+ if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE) {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+ } else if (p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SINK) {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+ } else {
+ APPL_TRACE_ERROR(
+ "bta_hl_app_registration: Invalid Role %d",
+ p_acb->sup_feature.mdep[mdep_idx].mdep_cfg.mdep_role);
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ } else {
+ APPL_TRACE_ERROR("bta_hl_app_registration: Cfg callout failed");
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ } else {
+ APPL_TRACE_ERROR("bta_hl_app_registration: MCA_CreateDep failed");
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ break;
+ }
+ }
+ p_acb->sup_feature.num_of_mdeps += num_of_mdeps;
+ APPL_TRACE_DEBUG("num_of_mdeps %d", p_acb->sup_feature.num_of_mdeps);
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+ p_acb->sup_feature.advertize_source_sdp =
+ bta_hl_co_advrtise_source_sdp(app_id);
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (!bta_hl_co_get_echo_config(app_id, &p_acb->sup_feature.echo_cfg))) {
+ status = BTA_HL_STATUS_ECHO_CO_FAIL;
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (!bta_hl_co_load_mdl_config(app_id, BTA_HL_NUM_MDL_CFGS,
+ &p_acb->mdl_cfg[0]))) {
+ status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
+ }
+ } else {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ }
+ } else {
+ for (i = 1; i < BTA_HL_NUM_MDEPS; i++) {
+ if (p_acb->sup_feature.mdep[i].ori_app_id == app_id) {
+ APPL_TRACE_DEBUG("Found index %", i);
+
+ if (MCA_DeleteDep((tMCA_HANDLE)p_acb->app_handle,
+ (p_acb->sup_feature.mdep[i].mdep_id)) !=
+ MCA_SUCCESS) {
+ APPL_TRACE_ERROR("Error deregistering");
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ return status;
+ }
+ memset(&p_acb->sup_feature.mdep[i], 0, sizeof(tBTA_HL_MDEP));
+ }
+ }
+ }
+
+ if (status == BTA_HL_STATUS_OK) {
+ /* Register/Update MDEP(s) in SDP Record */
+ status = bta_hl_sdp_update(app_id);
+ }
+ /* else do cleanup */
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_app_registration
+ *
+ * Description This function registers an HDP application MCAP and DP
+ *
+ * Returns tBTA_HL_STATUS -registration status
+ *
+ ******************************************************************************/
+tBTA_HL_STATUS bta_hl_app_registration(uint8_t app_idx) {
+ tBTA_HL_STATUS status = BTA_HL_STATUS_OK;
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tMCA_REG reg;
+ tMCA_CS mca_cs;
+ uint8_t i, num_of_mdeps;
+ uint8_t mdep_counter = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_app_registration app_idx=%d", app_idx);
+#endif
+
+ reg.ctrl_psm = p_acb->ctrl_psm;
+ reg.data_psm = p_acb->data_psm;
+ reg.sec_mask = p_acb->sec_mask;
+ reg.rsp_tout = BTA_HL_MCAP_RSP_TOUT;
+
+ p_acb->app_handle =
+ (tBTA_HL_APP_HANDLE)MCA_Register(&reg, bta_hl_mcap_ctrl_cback);
+ if (p_acb->app_handle != 0) {
+ mca_cs.type = MCA_TDEP_ECHO;
+ mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+ mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+ if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+ &(p_acb->sup_feature.mdep[0].mdep_id),
+ &mca_cs) == MCA_SUCCESS) {
+ if (p_acb->sup_feature.mdep[0].mdep_id != BTA_HL_ECHO_TEST_MDEP_ID) {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ APPL_TRACE_ERROR("BAD MDEP ID for echo test mdep_id=%d",
+ p_acb->sup_feature.mdep[0].mdep_id);
+ }
+ } else {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ APPL_TRACE_ERROR("MCA_CreateDep for echo test(mdep_id=0) failed");
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ bta_hl_co_get_num_of_mdep(p_acb->app_id, &num_of_mdeps)) {
+ p_acb->sup_feature.num_of_mdeps = num_of_mdeps + 1;
+
+ for (i = 1; i < p_acb->sup_feature.num_of_mdeps; i++) {
+ mca_cs.type = MCA_TDEP_DATA;
+ mca_cs.max_mdl = BTA_HL_NUM_MDLS_PER_MDEP;
+ mca_cs.p_data_cback = bta_hl_mcap_data_cback;
+
+ if (MCA_CreateDep((tMCA_HANDLE)p_acb->app_handle,
+ &(p_acb->sup_feature.mdep[i].mdep_id),
+ &mca_cs) == MCA_SUCCESS) {
+ if (bta_hl_co_get_mdep_config(p_acb->app_id, i, mdep_counter,
+ p_acb->sup_feature.mdep[i].mdep_id,
+ &p_acb->sup_feature.mdep[i].mdep_cfg)) {
+ if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE) {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+ } else if (p_acb->sup_feature.mdep[i].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SINK) {
+ p_acb->sup_feature.app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+ } else {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ p_acb->sup_feature.mdep[i].ori_app_id = p_acb->app_id;
+ APPL_TRACE_DEBUG("index %d ori_app_id %d", i,
+ p_acb->sup_feature.mdep[i].ori_app_id);
+ } else {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ break;
+ }
+ } else {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ break;
+ }
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (p_acb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+ /* this is a source only applciation */
+ p_acb->sup_feature.advertize_source_sdp =
+ bta_hl_co_advrtise_source_sdp(p_acb->app_id);
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (!bta_hl_co_get_echo_config(p_acb->app_id,
+ &p_acb->sup_feature.echo_cfg))) {
+ status = BTA_HL_STATUS_ECHO_CO_FAIL;
+ }
+
+ if ((status == BTA_HL_STATUS_OK) &&
+ (!bta_hl_co_load_mdl_config(p_acb->app_id, BTA_HL_NUM_MDL_CFGS,
+ &p_acb->mdl_cfg[0]))) {
+ status = BTA_HL_STATUS_MDL_CFG_CO_FAIL;
+ }
+ } else {
+ status = BTA_HL_STATUS_MDEP_CO_FAIL;
+ }
+ } else {
+ status = BTA_HL_STATUS_MCAP_REG_FAIL;
+ }
+
+ if (status == BTA_HL_STATUS_OK) {
+ status = bta_hl_sdp_register(app_idx);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_discard_data
+ *
+ * Description This function discard an HDP event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_discard_data(uint16_t event, tBTA_HL_DATA* p_data) {
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_ERROR("BTA HL Discard event=%s", bta_hl_evt_code(event));
+
+#endif
+
+ switch (event) {
+ case BTA_HL_API_SEND_DATA_EVT:
+ break;
+
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ osi_free_and_reset((void**)&p_data->mca_rcv_data_evt.p_pkt);
+ break;
+
+ default:
+ /*Nothing to free*/
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_save_mdl_cfg
+ *
+ * Description This function saves the MDL configuration
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_save_mdl_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ uint8_t mdl_cfg_idx;
+ tBTA_HL_MDL_ID mdl_id;
+ bool found = true;
+ tBTA_HL_MDL_CFG mdl_cfg;
+ tBTA_HL_MDEP* p_mdep_cfg;
+ tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+ uint8_t time_val = 0;
+ mdl_id = p_dcb->mdl_id;
+ if (!bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, mdl_id, &mdl_cfg_idx)) {
+ if (!bta_hl_find_avail_mdl_cfg_idx(app_idx, mcl_idx, &mdl_cfg_idx)) {
+ APPL_TRACE_ERROR("No space to save the MDL config");
+ found = false; /*no space available*/
+ }
+ }
+
+ if (found) {
+ bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
+ if (!bta_hl_get_cur_time(app_idx, &time_val)) {
+ bta_hl_compact_mdl_cfg_time(app_idx, p_dcb->local_mdep_id);
+ bta_hl_get_cur_time(app_idx, &time_val);
+ }
+ mdl_cfg.active = true;
+ mdl_cfg.time = time_val;
+ mdl_cfg.mdl_id = p_dcb->mdl_id;
+ mdl_cfg.dch_mode = p_dcb->dch_mode;
+ mdl_cfg.mtu = l2cap_cfg.mtu;
+ mdl_cfg.fcs = l2cap_cfg.fcs;
+
+ bdcpy(mdl_cfg.peer_bd_addr, p_mcb->bd_addr);
+ mdl_cfg.local_mdep_id = p_dcb->local_mdep_id;
+ p_mdep_cfg = &p_acb->sup_feature.mdep[p_dcb->local_mdep_cfg_idx];
+ mdl_cfg.local_mdep_role = p_mdep_cfg->mdep_cfg.mdep_role;
+ memcpy(&p_acb->mdl_cfg[mdl_cfg_idx], &mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+ bta_hl_co_save_mdl(mdl_cfg.local_mdep_id, mdl_cfg_idx, &mdl_cfg);
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (found) {
+ if (p_dcb->mtu != l2cap_cfg.mtu) {
+ APPL_TRACE_WARNING(
+ "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from "
+ "l2cap mtu=%d",
+ p_dcb->mtu, l2cap_cfg.mtu);
+ }
+ APPL_TRACE_DEBUG("bta_hl_save_mdl_cfg saved=%d", found);
+ APPL_TRACE_DEBUG("Saved. L2cap cfg mdl_id=%d mtu=%d fcs=%d dch_mode=%d",
+ mdl_cfg.mdl_id, mdl_cfg.mtu, mdl_cfg.fcs,
+ mdl_cfg.dch_mode);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_set_dch_chan_cfg
+ *
+ * Description This function setups the L2CAP DCH channel configuration
+ *
+ * Returns void
+ ******************************************************************************/
+void bta_hl_set_dch_chan_cfg(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx,
+ tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ uint8_t l2cap_mode = L2CAP_FCR_ERTM_MODE;
+ tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+ uint8_t local_mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+
+ switch (p_dcb->dch_oper) {
+ case BTA_HL_DCH_OP_LOCAL_RECONNECT:
+ case BTA_HL_DCH_OP_REMOTE_RECONNECT:
+ if (p_dcb->dch_mode == BTA_HL_DCH_MODE_STREAMING)
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ case BTA_HL_DCH_OP_LOCAL_OPEN:
+ if (p_data->mca_evt.mca_data.create_cfm.cfg == BTA_HL_DCH_CFG_STREAMING)
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ case BTA_HL_DCH_OP_REMOTE_OPEN:
+ if (p_dcb->local_cfg == BTA_HL_DCH_CFG_STREAMING)
+ l2cap_mode = L2CAP_FCR_STREAM_MODE;
+ break;
+ default:
+ APPL_TRACE_ERROR("Invalid dch oper=%d for set dch chan cfg",
+ p_dcb->dch_oper);
+ break;
+ }
+ p_dcb->chnl_cfg.fcr_opt.mode = l2cap_mode;
+ p_dcb->chnl_cfg.fcr_opt.mps = bta_hl_set_mps(p_dcb->max_rx_apdu_size);
+ p_dcb->chnl_cfg.fcr_opt.tx_win_sz = bta_hl_set_tx_win_size(
+ p_dcb->max_rx_apdu_size, p_dcb->chnl_cfg.fcr_opt.mps);
+ p_dcb->chnl_cfg.fcr_opt.max_transmit = BTA_HL_L2C_MAX_TRANSMIT;
+ p_dcb->chnl_cfg.fcr_opt.rtrans_tout = BTA_HL_L2C_RTRANS_TOUT;
+ p_dcb->chnl_cfg.fcr_opt.mon_tout = BTA_HL_L2C_MON_TOUT;
+
+ p_dcb->chnl_cfg.user_rx_buf_size =
+ bta_hl_set_user_rx_buf_size(p_dcb->max_rx_apdu_size);
+ p_dcb->chnl_cfg.user_tx_buf_size =
+ bta_hl_set_user_tx_buf_size(p_dcb->max_tx_apdu_size);
+ p_dcb->chnl_cfg.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ p_dcb->chnl_cfg.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ p_dcb->chnl_cfg.data_mtu = p_dcb->max_rx_apdu_size;
+
+ p_dcb->chnl_cfg.fcs = BTA_HL_MCA_NO_FCS;
+ if (local_mdep_cfg_idx != BTA_HL_ECHO_TEST_MDEP_CFG_IDX) {
+ if (p_sup_feature->mdep[local_mdep_cfg_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE) {
+ p_dcb->chnl_cfg.fcs = BTA_HL_DEFAULT_SOURCE_FCS;
+ }
+ } else {
+ p_dcb->chnl_cfg.fcs = BTA_HL_MCA_USE_FCS;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("L2CAP Params l2cap_mode[3-ERTM 4-STREAM]=%d", l2cap_mode);
+ APPL_TRACE_DEBUG("Use FCS =%s mtu=%d",
+ ((p_dcb->chnl_cfg.fcs & 1) ? "YES" : "NO"),
+ p_dcb->chnl_cfg.data_mtu);
+ APPL_TRACE_DEBUG(
+ "tx_win_sz=%d, max_transmit=%d, rtrans_tout=%d, mon_tout=%d, mps=%d",
+ p_dcb->chnl_cfg.fcr_opt.tx_win_sz, p_dcb->chnl_cfg.fcr_opt.max_transmit,
+ p_dcb->chnl_cfg.fcr_opt.rtrans_tout, p_dcb->chnl_cfg.fcr_opt.mon_tout,
+ p_dcb->chnl_cfg.fcr_opt.mps);
+
+ APPL_TRACE_DEBUG(
+ "USER rx_buf_size=%d, tx_buf_size=%d, FCR rx_buf_size=%d, tx_buf_size=%d",
+ p_dcb->chnl_cfg.user_rx_buf_size, p_dcb->chnl_cfg.user_tx_buf_size,
+ p_dcb->chnl_cfg.fcr_rx_buf_size, p_dcb->chnl_cfg.fcr_tx_buf_size);
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_get_l2cap_cfg
+ *
+ * Description This function get the current L2CAP channel configuration
+ *
+ * Returns bool - true - operation is successful
+ ******************************************************************************/
+bool bta_hl_get_l2cap_cfg(tBTA_HL_MDL_HANDLE mdl_hnd,
+ tBTA_HL_L2CAP_CFG_INFO* p_cfg) {
+ bool success = false;
+ uint16_t lcid;
+ tL2CAP_CFG_INFO* p_our_cfg;
+ tL2CAP_CH_CFG_BITS our_cfg_bits;
+ tL2CAP_CFG_INFO* p_peer_cfg;
+ tL2CAP_CH_CFG_BITS peer_cfg_bits;
+
+ lcid = MCA_GetL2CapChannel((tMCA_DL)mdl_hnd);
+ if (lcid && L2CA_GetCurrentConfig(lcid, &p_our_cfg, &our_cfg_bits,
+ &p_peer_cfg, &peer_cfg_bits)) {
+ p_cfg->fcs = BTA_HL_MCA_NO_FCS;
+ if (our_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
+ p_cfg->fcs |= p_our_cfg->fcs;
+ } else {
+ p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+ }
+
+ if (p_cfg->fcs != BTA_HL_MCA_USE_FCS) {
+ if (peer_cfg_bits & L2CAP_CH_CFG_MASK_FCS) {
+ p_cfg->fcs |= p_peer_cfg->fcs;
+ } else {
+ p_cfg->fcs = BTA_HL_MCA_USE_FCS;
+ }
+ }
+
+ p_cfg->mtu = 0;
+ if (peer_cfg_bits & L2CAP_CH_CFG_MASK_MTU) {
+ p_cfg->mtu = p_peer_cfg->mtu;
+ } else {
+ p_cfg->mtu = L2CAP_DEFAULT_MTU;
+ }
+ success = true;
+ } else {
+ p_cfg->mtu = L2CAP_DEFAULT_MTU;
+ p_cfg->fcs = BTA_HL_L2C_NO_FCS;
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+ if (!success) {
+ APPL_TRACE_DEBUG("bta_hl_get_l2cap_cfg success=%d mdl=%d lcid=%d", success,
+ mdl_hnd, lcid);
+ APPL_TRACE_DEBUG("l2cap mtu=%d fcs=%d", p_cfg->mtu, p_cfg->fcs);
+ }
+#endif
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_validate_chan_cfg
+ *
+ * Description This function validates the L2CAP channel configuration
+ *
+ * Returns bool - true - validation is successful
+ ******************************************************************************/
+bool bta_hl_validate_chan_cfg(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MDL_CB* p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ bool success = false;
+ uint8_t mdl_cfg_idx = 0;
+ tBTA_HL_L2CAP_CFG_INFO l2cap_cfg;
+ bool get_l2cap_result, get_mdl_result;
+
+ get_l2cap_result = bta_hl_get_l2cap_cfg(p_dcb->mdl_handle, &l2cap_cfg);
+ get_mdl_result =
+ bta_hl_find_mdl_cfg_idx(app_idx, mcl_idx, p_dcb->mdl_id, &mdl_cfg_idx);
+
+ if (get_l2cap_result && get_mdl_result) {
+ if ((p_acb->mdl_cfg[mdl_cfg_idx].mtu <= l2cap_cfg.mtu) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].fcs == l2cap_cfg.fcs) &&
+ (p_acb->mdl_cfg[mdl_cfg_idx].dch_mode == p_dcb->dch_mode)) {
+ success = true;
+ }
+ }
+
+#if (BTA_HL_DEBUG == TRUE)
+
+ if (p_dcb->mtu != l2cap_cfg.mtu) {
+ APPL_TRACE_WARNING(
+ "MCAP and L2CAP peer mtu size out of sync from MCAP mtu=%d from l2cap "
+ "mtu=%d",
+ p_dcb->mtu, l2cap_cfg.mtu);
+ }
+
+ if (!success) {
+ APPL_TRACE_DEBUG(
+ "bta_hl_validate_chan_cfg success=%d app_idx=%d mcl_idx=%d mdl_idx=%d",
+ success, app_idx, mcl_idx, mdl_idx);
+ APPL_TRACE_DEBUG("Cur. L2cap cfg mtu=%d fcs=%d dch_mode=%d", l2cap_cfg.mtu,
+ l2cap_cfg.fcs, p_dcb->dch_mode);
+ APPL_TRACE_DEBUG("From saved: L2cap cfg mtu=%d fcs=%d dch_mode=%d",
+ p_acb->mdl_cfg[mdl_cfg_idx].mtu,
+ p_acb->mdl_cfg[mdl_cfg_idx].fcs,
+ p_acb->mdl_cfg[mdl_cfg_idx].dch_mode);
+ }
+#endif
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_is_cong_on
+ *
+ * Description This function checks whether the congestion condition is on.
+ *
+ * Returns bool - true DCH is congested
+ * false not congested
+ *
+ ******************************************************************************/
+bool bta_hl_is_cong_on(uint8_t app_id, BD_ADDR bd_addr, tBTA_HL_MDL_ID mdl_id)
+
+{
+ tBTA_HL_MDL_CB* p_dcb;
+ uint8_t app_idx = 0, mcl_idx, mdl_idx;
+ bool cong_status = true;
+
+ if (bta_hl_find_app_idx(app_id, &app_idx)) {
+ if (bta_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+ if (bta_hl_find_mdl_idx(app_idx, mcl_idx, mdl_id, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ cong_status = p_dcb->cong;
+ }
+ }
+ }
+
+ return cong_status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_check_cch_close
+ *
+ * Description This function checks whether there is a pending CCH close
+ * request or not
+ *
+ * Returns void
+ ******************************************************************************/
+void bta_hl_check_cch_close(uint8_t app_idx, uint8_t mcl_idx,
+ tBTA_HL_DATA* p_data, bool check_dch_setup) {
+ tBTA_HL_MCL_CB* p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_MDL_CB* p_dcb;
+ uint8_t mdl_idx;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_check_cch_close cch_close_dch_oper=%d",
+ p_mcb->cch_close_dch_oper);
+#endif
+
+ if (p_mcb->cch_oper == BTA_HL_CCH_OP_LOCAL_CLOSE) {
+ if (check_dch_setup &&
+ bta_hl_find_dch_setup_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTA_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ if (!p_mcb->rsp_tout) {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_ABORT;
+
+ if (!p_dcb->abort_oper) {
+ p_dcb->abort_oper |= BTA_HL_ABORT_CCH_CLOSE_MASK;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_ABORT_EVT,
+ p_data);
+ }
+ } else {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx,
+ BTA_HL_DCH_CLOSE_CMPL_EVT, p_data);
+ }
+ } else if (bta_hl_find_an_active_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_CLOSE;
+ bta_hl_dch_sm_execute(app_idx, mcl_idx, mdl_idx, BTA_HL_DCH_CLOSE_EVT,
+ p_data);
+ } else {
+ p_mcb->cch_close_dch_oper = BTA_HL_CCH_CLOSE_OP_DCH_NONE;
+ bta_hl_cch_sm_execute(app_idx, mcl_idx, BTA_HL_CCH_CLOSE_EVT, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_clean_app
+ *
+ * Description Cleans up the HDP application resources and control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_clean_app(uint8_t app_idx) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ int i, num_act_apps = 0;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_clean_app");
+#endif
+ MCA_Deregister((tMCA_HANDLE)p_acb->app_handle);
+
+ if (p_acb->sdp_handle) SDP_DeleteRecord(p_acb->sdp_handle);
+
+ memset((void*)p_acb, 0, sizeof(tBTA_HL_APP_CB));
+
+ /* check any application is still active */
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) num_act_apps++;
+ }
+
+ if (!num_act_apps) {
+ bta_sys_remove_uuid(UUID_SERVCLASS_HDP_PROFILE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_check_deregistration
+ *
+ * Description This function checks whether there is a pending deregistration
+ * request or not
+ *
+ * Returns void
+ ******************************************************************************/
+void bta_hl_check_deregistration(uint8_t app_idx, tBTA_HL_DATA* p_data) {
+ tBTA_HL_APP_CB* p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_MCL_CB* p_mcb;
+ uint8_t mcl_idx;
+ tBTA_HL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_check_deregistration");
+#endif
+
+ if (p_acb->deregistering) {
+ if (bta_hl_find_an_in_use_mcl_idx(app_idx, &mcl_idx)) {
+ p_mcb = BTA_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTA_HL_CCH_OP_LOCAL_CLOSE) {
+ if (p_mcb->cch_state == BTA_HL_CCH_OPENING_ST)
+ p_mcb->force_close_local_cch_opening = true;
+ p_mcb->cch_oper = BTA_HL_CCH_OP_LOCAL_CLOSE;
+ APPL_TRACE_DEBUG("p_mcb->force_close_local_cch_opening=%d",
+ p_mcb->force_close_local_cch_opening);
+ bta_hl_check_cch_close(app_idx, mcl_idx, p_data, true);
+ }
+ } else {
+ /* all cchs are closed */
+ evt_data.dereg_cfm.app_handle = p_acb->app_handle;
+ evt_data.dereg_cfm.app_id = p_data->api_dereg.app_id;
+ evt_data.dereg_cfm.status = BTA_HL_STATUS_OK;
+ p_acb->p_cback(BTA_HL_DEREGISTER_CFM_EVT, (tBTA_HL*)&evt_data);
+ bta_hl_clean_app(app_idx);
+ bta_hl_check_disable(p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_check_disable
+ *
+ * Description This function checks whether there is a pending disable
+ * request or not
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_check_disable(tBTA_HL_DATA* p_data) {
+ tBTA_HL_CB* p_cb = &bta_hl_cb;
+ tBTA_HL_APP_CB* p_acb;
+ uint8_t app_idx;
+ tBTA_HL_CTRL evt_data;
+
+#if (BTA_HL_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("bta_hl_check_disable");
+#endif
+
+ if (bta_hl_cb.disabling) {
+ if (bta_hl_find_an_in_use_app_idx(&app_idx)) {
+ p_acb = BTA_HL_GET_APP_CB_PTR(app_idx);
+ if (!p_acb->deregistering) {
+ p_acb->deregistering = true;
+ bta_hl_check_deregistration(app_idx, p_data);
+ }
+ } else {
+ /* all apps are deregistered */
+ bta_sys_deregister(BTA_ID_HL);
+ evt_data.disable_cfm.status = BTA_HL_STATUS_OK;
+ if (p_cb->p_ctrl_cback)
+ p_cb->p_ctrl_cback(BTA_HL_CTRL_DISABLE_CFM_EVT,
+ (tBTA_HL_CTRL*)&evt_data);
+ memset((void*)p_cb, 0, sizeof(tBTA_HL_CB));
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_abort_cfm
+ *
+ * Description This function builds the abort confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_abort_cfm(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status) {
+ p_evt_data->dch_abort_cfm.status = status;
+ p_evt_data->dch_abort_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_abort_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_abort_ind
+ *
+ * Description This function builds the abort indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_abort_ind(tBTA_HL* p_evt_data, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle) {
+ p_evt_data->dch_abort_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_abort_ind.app_handle = app_handle;
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_build_close_cfm
+ *
+ * Description This function builds the close confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_close_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status) {
+ p_evt_data->dch_close_cfm.status = status;
+ p_evt_data->dch_close_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_close_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_close_cfm.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_dch_close_ind
+ *
+ * Description This function builds the close indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_close_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ bool intentional) {
+ p_evt_data->dch_close_ind.mdl_handle = mdl_handle;
+ p_evt_data->dch_close_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_close_ind.app_handle = app_handle;
+ p_evt_data->dch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_send_data_cfm
+ *
+ * Description This function builds the send data confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_send_data_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status) {
+ p_evt_data->dch_send_data_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_send_data_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_send_data_cfm.app_handle = app_handle;
+ p_evt_data->dch_send_data_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_rcv_data_ind
+ *
+ * Description This function builds the received data indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_rcv_data_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle) {
+ p_evt_data->dch_rcv_data_ind.mdl_handle = mdl_handle;
+ p_evt_data->dch_rcv_data_ind.mcl_handle = mcl_handle;
+ p_evt_data->dch_rcv_data_ind.app_handle = app_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_cch_open_cfm
+ *
+ * Description This function builds the CCH open confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_open_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle, BD_ADDR bd_addr,
+ tBTA_HL_STATUS status) {
+ p_evt_data->cch_open_cfm.app_id = app_id;
+ p_evt_data->cch_open_cfm.app_handle = app_handle;
+ p_evt_data->cch_open_cfm.mcl_handle = mcl_handle;
+ bdcpy(p_evt_data->cch_open_cfm.bd_addr, bd_addr);
+ p_evt_data->cch_open_cfm.status = status;
+ APPL_TRACE_DEBUG("bta_hl_build_cch_open_cfm: status=%d", status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_cch_open_ind
+ *
+ * Description This function builds the CCH open indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_open_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle, BD_ADDR bd_addr) {
+ p_evt_data->cch_open_ind.app_handle = app_handle;
+ p_evt_data->cch_open_ind.mcl_handle = mcl_handle;
+ bdcpy(p_evt_data->cch_open_ind.bd_addr, bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_cch_close_cfm
+ *
+ * Description This function builds the CCH close confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_close_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status) {
+ p_evt_data->cch_close_cfm.mcl_handle = mcl_handle;
+ p_evt_data->cch_close_cfm.app_handle = app_handle;
+ p_evt_data->cch_close_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_cch_close_ind
+ *
+ * Description This function builds the CCH colse indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_cch_close_ind(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ bool intentional) {
+ p_evt_data->cch_close_ind.mcl_handle = mcl_handle;
+ p_evt_data->cch_close_ind.app_handle = app_handle;
+ p_evt_data->cch_close_ind.intentional = intentional;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_dch_open_cfm
+ *
+ * Description This function builds the DCH open confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_dch_open_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_MDEP_ID local_mdep_id,
+ tBTA_HL_MDL_ID mdl_id, tBTA_HL_DCH_MODE dch_mode,
+ bool first_reliable, uint16_t mtu,
+ tBTA_HL_STATUS status)
+
+{
+ p_evt_data->dch_open_cfm.mdl_handle = mdl_handle;
+ p_evt_data->dch_open_cfm.mcl_handle = mcl_handle;
+ p_evt_data->dch_open_cfm.app_handle = app_handle;
+ p_evt_data->dch_open_cfm.local_mdep_id = local_mdep_id;
+ p_evt_data->dch_open_cfm.mdl_id = mdl_id;
+ p_evt_data->dch_open_cfm.dch_mode = dch_mode;
+ p_evt_data->dch_open_cfm.first_reliable = first_reliable;
+ p_evt_data->dch_open_cfm.mtu = mtu;
+ p_evt_data->dch_open_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_sdp_query_cfm
+ *
+ * Description This function builds the SDP query indication event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_sdp_query_cfm(tBTA_HL* p_evt_data, uint8_t app_id,
+ tBTA_HL_APP_HANDLE app_handle, BD_ADDR bd_addr,
+ tBTA_HL_SDP* p_sdp, tBTA_HL_STATUS status)
+
+{
+ APPL_TRACE_DEBUG("bta_hl_build_sdp_query_cfm: app_id = %d, app_handle=%d",
+ app_id, app_handle);
+ p_evt_data->sdp_query_cfm.app_id = app_id;
+ p_evt_data->sdp_query_cfm.app_handle = app_handle;
+ bdcpy(p_evt_data->sdp_query_cfm.bd_addr, bd_addr);
+ p_evt_data->sdp_query_cfm.p_sdp = p_sdp;
+ /** M: Bug fix for SDP fail to copy right @{*/
+ if(status == BTA_HL_STATUS_OK)
+ {
+ memcpy(&g_bta_sdp, p_sdp, sizeof(tBTA_HL_SDP));
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("bta_hl_build_sdp_query_cfm: status = %d",status);
+ }
+ /**@}*/
+
+ p_evt_data->sdp_query_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_delete_mdl_cfm
+ *
+ * Description This function builds the delete MDL confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_delete_mdl_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id, tBTA_HL_STATUS status)
+
+{
+ p_evt_data->delete_mdl_cfm.mcl_handle = mcl_handle;
+ p_evt_data->delete_mdl_cfm.app_handle = app_handle;
+ p_evt_data->delete_mdl_cfm.mdl_id = mdl_id;
+ p_evt_data->delete_mdl_cfm.status = status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_build_echo_test_cfm
+ *
+ * Description This function builds the echo test confirmation event data
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bta_hl_build_echo_test_cfm(tBTA_HL* p_evt_data,
+ tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status) {
+ p_evt_data->echo_test_cfm.mcl_handle = mcl_handle;
+ p_evt_data->echo_test_cfm.app_handle = app_handle;
+ p_evt_data->echo_test_cfm.status = status;
+}
+
+/*****************************************************************************
+ * Debug Functions
+ ****************************************************************************/
+#if (BTA_HL_DEBUG == TRUE)
+
+/*******************************************************************************
+ *
+ * Function bta_hl_status_code
+ *
+ * Description get the status string pointer
+ *
+ * Returns char * - status string pointer
+ *
+ ******************************************************************************/
+const char* bta_hl_status_code(tBTA_HL_STATUS status) {
+ switch (status) {
+ case BTA_HL_STATUS_OK:
+ return "BTA_HL_STATUS_OK";
+ case BTA_HL_STATUS_FAIL:
+ return "BTA_HL_STATUS_FAIL";
+ case BTA_HL_STATUS_ABORTED:
+ return "BTA_HL_STATUS_ABORTED";
+ case BTA_HL_STATUS_NO_RESOURCE:
+ return "BTA_HL_STATUS_NO_RESOURCE";
+ case BTA_HL_STATUS_LAST_ITEM:
+ return "BTA_HL_STATUS_LAST_ITEM";
+ case BTA_HL_STATUS_DUPLICATE_APP_ID:
+ return "BTA_HL_STATUS_DUPLICATE_APP_ID";
+ case BTA_HL_STATUS_INVALID_APP_HANDLE:
+ return "BTA_HL_STATUS_INVALID_APP_HANDLE";
+ case BTA_HL_STATUS_INVALID_MCL_HANDLE:
+ return "BTA_HL_STATUS_INVALID_MCL_HANDLE";
+ case BTA_HL_STATUS_MCAP_REG_FAIL:
+ return "BTA_HL_STATUS_MCAP_REG_FAIL";
+ case BTA_HL_STATUS_MDEP_CO_FAIL:
+ return "BTA_HL_STATUS_MDEP_CO_FAIL";
+ case BTA_HL_STATUS_ECHO_CO_FAIL:
+ return "BTA_HL_STATUS_ECHO_CO_FAIL";
+ case BTA_HL_STATUS_MDL_CFG_CO_FAIL:
+ return "BTA_HL_STATUS_MDL_CFG_CO_FAIL";
+ case BTA_HL_STATUS_SDP_NO_RESOURCE:
+ return "BTA_HL_STATUS_SDP_NO_RESOURCE";
+ case BTA_HL_STATUS_SDP_FAIL:
+ return "BTA_HL_STATUS_SDP_FAIL";
+ case BTA_HL_STATUS_NO_CCH:
+ return "BTA_HL_STATUS_NO_CCH";
+ case BTA_HL_STATUS_NO_MCL:
+ return "BTA_HL_STATUS_NO_MCL";
+
+ case BTA_HL_STATUS_NO_FIRST_RELIABLE:
+ return "BTA_HL_STATUS_NO_FIRST_RELIABLE";
+ case BTA_HL_STATUS_INVALID_DCH_CFG:
+ return "BTA_HL_STATUS_INVALID_DCH_CFG";
+ case BTA_HL_STATUS_INVALID_BD_ADDR:
+ return "BTA_HL_STATUS_INVALID_BD_ADDR";
+ case BTA_HL_STATUS_INVALID_RECONNECT_CFG:
+ return "BTA_HL_STATUS_INVALID_RECONNECT_CFG";
+ case BTA_HL_STATUS_ECHO_TEST_BUSY:
+ return "BTA_HL_STATUS_ECHO_TEST_BUSY";
+ case BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID:
+ return "BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID";
+ case BTA_HL_STATUS_INVALID_MDL_ID:
+ return "BTA_HL_STATUS_INVALID_MDL_ID";
+ case BTA_HL_STATUS_NO_MDL_ID_FOUND:
+ return "BTA_HL_STATUS_NO_MDL_ID_FOUND";
+ case BTA_HL_STATUS_DCH_BUSY:
+ return "BTA_HL_STATUS_DCH_BUSY";
+ default:
+ return "Unknown status code";
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_evt_code
+ *
+ * Description Maps HL event code to the corresponding event string
+ *
+ * Returns string pointer for the associated event name
+ *
+ ******************************************************************************/
+const char* bta_hl_evt_code(tBTA_HL_INT_EVT evt_code) {
+ switch (evt_code) {
+ case BTA_HL_CCH_OPEN_EVT:
+ return "BTA_HL_CCH_OPEN_EVT";
+ case BTA_HL_CCH_SDP_OK_EVT:
+ return "BTA_HL_CCH_SDP_OK_EVT";
+ case BTA_HL_CCH_SDP_FAIL_EVT:
+ return "BTA_HL_CCH_SDP_FAIL_EVT";
+ case BTA_HL_MCA_CONNECT_IND_EVT:
+ return "BTA_HL_MCA_CONNECT_IND_EVT";
+ case BTA_HL_MCA_DISCONNECT_IND_EVT:
+ return "BTA_HL_MCA_DISCONNECT_IND_EVT";
+
+ case BTA_HL_CCH_CLOSE_EVT:
+ return "BTA_HL_CCH_CLOSE_EVT";
+ case BTA_HL_CCH_CLOSE_CMPL_EVT:
+ return "BTA_HL_CCH_CLOSE_CMPL_EVT";
+ case BTA_HL_DCH_OPEN_EVT:
+ return "BTA_HL_DCH_OPEN_EVT";
+ case BTA_HL_MCA_CREATE_IND_EVT:
+ return "BTA_HL_MCA_CREATE_IND_EVT";
+ case BTA_HL_MCA_CREATE_CFM_EVT:
+ return "BTA_HL_MCA_CREATE_CFM_EVT";
+ case BTA_HL_MCA_OPEN_IND_EVT:
+ return "BTA_HL_MCA_OPEN_IND_EVT";
+ case BTA_HL_MCA_OPEN_CFM_EVT:
+ return "BTA_HL_MCA_OPEN_CFM_EVT";
+ case BTA_HL_DCH_CLOSE_EVT:
+ return "BTA_HL_DCH_CLOSE_EVT";
+ case BTA_HL_MCA_CLOSE_IND_EVT:
+ return "BTA_HL_MCA_CLOSE_IND_EVT";
+ case BTA_HL_MCA_CLOSE_CFM_EVT:
+ return "BTA_HL_MCA_CLOSE_CFM_EVT";
+ case BTA_HL_API_SEND_DATA_EVT:
+ return "BTA_HL_API_SEND_DATA_EVT";
+ case BTA_HL_MCA_RCV_DATA_EVT:
+ return "BTA_HL_MCA_RCV_DATA_EVT";
+ case BTA_HL_DCH_CLOSE_CMPL_EVT:
+ return "BTA_HL_DCH_CLOSE_CMPL_EVT";
+
+ case BTA_HL_API_ENABLE_EVT:
+ return "BTA_HL_API_ENABLE_EVT";
+ case BTA_HL_API_DISABLE_EVT:
+ return "BTA_HL_API_DISABLE_EVT";
+ case BTA_HL_API_UPDATE_EVT:
+ return "BTA_HL_API_UPDATE_EVT";
+ case BTA_HL_API_REGISTER_EVT:
+ return "BTA_HL_API_REGISTER_EVT";
+ case BTA_HL_API_DEREGISTER_EVT:
+ return "BTA_HL_API_DEREGISTER_EVT";
+
+ case BTA_HL_API_CCH_OPEN_EVT:
+ return "BTA_HL_API_CCH_OPEN_EVT";
+
+ case BTA_HL_API_CCH_CLOSE_EVT:
+ return "BTA_HL_API_CCH_CLOSE_EVT";
+ case BTA_HL_API_DCH_OPEN_EVT:
+ return "BTA_HL_API_DCH_OPEN_EVT";
+
+ case BTA_HL_API_DCH_RECONNECT_EVT:
+ return "BTA_HL_API_DCH_RECONNECT_EVT";
+ case BTA_HL_API_DCH_CLOSE_EVT:
+ return "BTA_HL_API_DCH_CLOSE_EVT";
+ case BTA_HL_API_DELETE_MDL_EVT:
+ return "BTA_HL_API_DELETE_MDL_EVT";
+ case BTA_HL_API_DCH_ABORT_EVT:
+ return "BTA_HL_API_DCH_ABORT_EVT";
+
+ case BTA_HL_DCH_RECONNECT_EVT:
+ return "BTA_HL_DCH_RECONNECT_EVT";
+ case BTA_HL_DCH_SDP_INIT_EVT:
+ return "BTA_HL_DCH_SDP_INIT_EVT";
+ case BTA_HL_DCH_SDP_FAIL_EVT:
+ return "BTA_HL_DCH_SDP_FAIL_EVT";
+ case BTA_HL_API_DCH_ECHO_TEST_EVT:
+ return "BTA_HL_API_DCH_ECHO_TEST_EVT";
+ case BTA_HL_DCH_CLOSE_ECHO_TEST_EVT:
+ return "BTA_HL_DCH_CLOSE_ECHO_TEST_EVT";
+ case BTA_HL_MCA_RECONNECT_IND_EVT:
+ return "BTA_HL_MCA_RECONNECT_IND_EVT";
+ case BTA_HL_MCA_RECONNECT_CFM_EVT:
+ return "BTA_HL_MCA_RECONNECT_CFM_EVT";
+ case BTA_HL_API_DCH_CREATE_RSP_EVT:
+ return "BTA_HL_API_DCH_CREATE_RSP_EVT";
+ case BTA_HL_DCH_ABORT_EVT:
+ return "BTA_HL_DCH_ABORT_EVT";
+ case BTA_HL_MCA_ABORT_IND_EVT:
+ return "BTA_HL_MCA_ABORT_IND_EVT";
+ case BTA_HL_MCA_ABORT_CFM_EVT:
+ return "BTA_HL_MCA_ABORT_CFM_EVT";
+ case BTA_HL_MCA_DELETE_IND_EVT:
+ return "BTA_HL_MCA_DELETE_IND_EVT";
+ case BTA_HL_MCA_DELETE_CFM_EVT:
+ return "BTA_HL_MCA_DELETE_CFM_EVT";
+ case BTA_HL_MCA_CONG_CHG_EVT:
+ return "BTA_HL_MCA_CONG_CHG_EVT";
+ case BTA_HL_CI_GET_TX_DATA_EVT:
+ return "BTA_HL_CI_GET_TX_DATA_EVT";
+ case BTA_HL_CI_PUT_RX_DATA_EVT:
+ return "BTA_HL_CI_PUT_RX_DATA_EVT";
+ case BTA_HL_CI_GET_ECHO_DATA_EVT:
+ return "BTA_HL_CI_GET_ECHO_DATA_EVT";
+ case BTA_HL_DCH_ECHO_TEST_EVT:
+ return "BTA_HL_DCH_ECHO_TEST_EVT";
+ case BTA_HL_CI_PUT_ECHO_DATA_EVT:
+ return "BTA_HL_CI_PUT_ECHO_DATA_EVT";
+ case BTA_HL_API_SDP_QUERY_EVT:
+ return "BTA_HL_API_SDP_QUERY_EVT";
+ case BTA_HL_SDP_QUERY_OK_EVT:
+ return "BTA_HL_SDP_QUERY_OK_EVT";
+ case BTA_HL_SDP_QUERY_FAIL_EVT:
+ return "BTA_HL_SDP_QUERY_FAIL_EVT";
+ case BTA_HL_MCA_RSP_TOUT_IND_EVT:
+ return "BTA_HL_MCA_RSP_TOUT_IND_EVT";
+
+ default:
+ return "Unknown HL event code";
+ }
+}
+
+#endif /* Debug Functions */
+#endif // HL_INCLUDED
diff --git a/mtkbt/code/bt/bta/include/bta_ag_api.h b/mtkbt/code/bt/bta/include/bta_ag_api.h
new file mode 100755
index 0000000..88f9d60
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_ag_api.h
@@ -0,0 +1,586 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the audio gateway (AG) subsystem
+ * of BTA, Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_API_H
+#define BTA_AG_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+#define HFP_VERSION_1_7 0x0107
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
+/* Note, if you change the default version here, please also change the one in
+ * bta_hs_api.h, they are meant to be the same.
+ */
+#ifndef BTA_HFP_VERSION
+#define BTA_HFP_VERSION HFP_VERSION_1_7
+#endif
+
+/* AG feature masks */
+#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_AG_FEAT_ECNR 0x00000002 /* Echo cancellation/noise reduction */
+#define BTA_AG_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTA_AG_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTA_AG_FEAT_VTAG 0x00000010 /* Attach a phone number to a voice tag */
+#define BTA_AG_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */
+#define BTA_AG_FEAT_ECS 0x00000040 /* Enhanced Call Status */
+#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */
+#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
+
+/* Valid feature bit mask for HFP 1.6 (and below) */
+#define HFP_1_6_FEAT_MASK 0x000003FF
+
+/* HFP 1.7+ */
+#define BTA_AG_FEAT_HF_IND 0x00000400 /* HF Indicators */
+#define BTA_AG_FEAT_ESCO 0x00000800 /* eSCO S4 (and T2) setting supported */
+
+/* Proprietary features: using 31 ~ 16 bits */
+#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
+#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to app */
+#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */
+#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
+#define BTA_AG_FEAT_VOIP 0x00100000 /* VoIP call */
+
+typedef uint32_t tBTA_AG_FEAT;
+
+/* AG parse mode */
+#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */
+
+/* Pass data directly to phone's AT command interpreter */
+#define BTA_AG_PASS_THROUGH 1
+
+typedef uint8_t tBTA_AG_PARSE_MODE;
+
+/* AG open status */
+#define BTA_AG_SUCCESS 0 /* Connection successfully opened */
+#define BTA_AG_FAIL_SDP 1 /* Open failed due to SDP */
+#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
+#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */
+
+/* Status to disallow passing AT Events after BTIF */
+#define BTA_AG_DISALLOW_AT 5
+
+typedef uint8_t tBTA_AG_STATUS;
+
+/* handle values used with BTA_AgResult */
+#define BTA_AG_HANDLE_NONE 0
+#define BTA_AG_HANDLE_ALL 0xFFFF
+/* It is safe to use the same value as BTA_AG_HANDLE_ALL
+ * HANDLE_ALL is used for delivering indication
+ * SCO_NO_CHANGE is used for changing sco behavior
+ * They donot interfere with each other
+ */
+
+/* Number of supported HF indicators, there is one HF indicator so far i.e.
+ enhanced driver status. */
+/* Number of supported HF indicators,
+ 1 for Enhanced Safety Status
+ 2 for Battery Level Status */
+#ifndef BTA_AG_NUM_LOCAL_HF_IND
+#define BTA_AG_NUM_LOCAL_HF_IND 2
+#endif
+
+#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
+
+/* AG result codes used with BTA_AgResult */
+#define BTA_AG_SPK_RES 0 /* Update speaker volume */
+#define BTA_AG_MIC_RES 1 /* Update microphone volume */
+#define BTA_AG_INBAND_RING_RES 2 /* Update inband ring state */
+#define BTA_AG_CIND_RES 3 /* Send indicator response for AT+CIND */
+#define BTA_AG_BINP_RES 4 /* Send phone number for voice tag for AT+BINP */
+#define BTA_AG_IND_RES 5 /* Update an indicator value */
+#define BTA_AG_BVRA_RES 6 /* Update voice recognition state */
+#define BTA_AG_CNUM_RES 7 /* Send subscriber number response for AT+CNUM */
+#define BTA_AG_BTRH_RES 8 /* Send CCAP incoming call hold */
+#define BTA_AG_CLCC_RES 9 /* Query list of calls */
+#define BTA_AG_COPS_RES 10 /* Read network operator */
+#define BTA_AG_IN_CALL_RES 11 /* Indicate incoming phone call */
+#define BTA_AG_IN_CALL_CONN_RES 12 /* Incoming phone call connected */
+#define BTA_AG_CALL_WAIT_RES 13 /* Call waiting notification */
+#define BTA_AG_OUT_CALL_ORIG_RES 14 /* Outgoing phone call origination */
+
+/* Outgoing phone call alerting remote party */
+#define BTA_AG_OUT_CALL_ALERT_RES 15
+#define BTA_AG_OUT_CALL_CONN_RES 16 /* Outgoing phone call connected */
+
+/* Incoming/outgoing 3-way canceled before connected */
+#define BTA_AG_CALL_CANCEL_RES 17
+#define BTA_AG_END_CALL_RES 18 /* End call */
+#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held */
+#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event */
+#define BTA_AG_MULTI_CALL_RES 21 /* SLC at three way call */
+#define BTA_AG_BIND_RES 22 /* Activate/Deactivate HF indicator */
+
+typedef uint8_t tBTA_AG_RES;
+
+/* HFP peer features */
+#define BTA_AG_PEER_FEAT_ECNR 0x0001 /* Echo cancellation/noise reduction */
+#define BTA_AG_PEER_FEAT_3WAY 0x0002 /* Call waiting and three-way calling */
+#define BTA_AG_PEER_FEAT_CLI 0x0004 /* Caller ID presentation capability */
+#define BTA_AG_PEER_FEAT_VREC 0x0008 /* Voice recognition activation */
+#define BTA_AG_PEER_FEAT_VOL 0x0010 /* Remote volume control */
+#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */
+#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */
+#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */
+#define BTA_AG_PEER_FEAT_HF_IND 0x0100 /* HF Indicators */
+#define BTA_AG_PEER_FEAT_ESCO 0x0200 /* eSCO S4 (and T2) setting supported */
+
+/* Proprietary features: using bits after 12 */
+
+/* Pass unknown AT command responses to application */
+#define BTA_AG_PEER_FEAT_UNAT 0x1000
+#define BTA_AG_PEER_FEAT_VOIP 0x2000 /* VoIP call */
+
+typedef uint16_t tBTA_AG_PEER_FEAT;
+
+/* HFP peer supported codec masks */
+// TODO(google) This should use common definitions
+#define BTA_AG_CODEC_NONE BTM_SCO_CODEC_NONE
+#define BTA_AG_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */
+#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */
+typedef uint16_t tBTA_AG_PEER_CODEC;
+
+/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
+#define BTA_AG_ERR_PHONE_FAILURE 0 /* Phone Failure */
+#define BTA_AG_ERR_NO_CONN_PHONE 1 /* No connection to phone */
+#define BTA_AG_ERR_OP_NOT_ALLOWED 3 /* Operation not allowed */
+#define BTA_AG_ERR_OP_NOT_SUPPORTED 4 /* Operation not supported */
+#define BTA_AG_ERR_PHSIM_PIN_REQ 5 /* PH-SIM PIN required */
+#define BTA_AG_ERR_SIM_NOT_INSERTED 10 /* SIM not inserted */
+#define BTA_AG_ERR_SIM_PIN_REQ 11 /* SIM PIN required */
+#define BTA_AG_ERR_SIM_PUK_REQ 12 /* SIM PUK required */
+#define BTA_AG_ERR_SIM_FAILURE 13 /* SIM failure */
+#define BTA_AG_ERR_SIM_BUSY 14 /* SIM busy */
+#define BTA_AG_ERR_INCORRECT_PWD 16 /* Incorrect password */
+#define BTA_AG_ERR_SIM_PIN2_REQ 17 /* SIM PIN2 required */
+#define BTA_AG_ERR_SIM_PUK2_REQ 18 /* SIM PUK2 required */
+#define BTA_AG_ERR_MEMORY_FULL 20 /* Memory full */
+#define BTA_AG_ERR_INVALID_INDEX 21 /* Invalid index */
+#define BTA_AG_ERR_MEMORY_FAILURE 23 /* Memory failure */
+#define BTA_AG_ERR_TEXT_TOO_LONG 24 /* Text string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25 /* Invalid characters in text string */
+#define BTA_AG_ERR_DSTR_TOO_LONG 26 /* Dial string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27 /* Invalid characters in dial string */
+#define BTA_AG_ERR_NO_NETWORK_SERV 30 /* No network service */
+#define BTA_AG_ERR_NETWORK_TIME_OUT 31 /* Network timeout */
+/* Network not allowed - emergency service only */
+#define BTA_AG_ERR_NO_NET_EMG_ONLY 32
+/* AG cannot create simultaneous VoIP and CS calls */
+#define BTA_AG_ERR_VOIP_CS_CALLS 33
+#define BTA_AG_ERR_NOT_FOR_VOIP 34 /* Not supported on this call type(VoIP) */
+#define BTA_AG_ERR_SIP_RESP_CODE 35 /* SIP 3 digit response code */
+
+#if 0 /* Not Used in Bluetooth HFP 1.5 Specification */
+#define BTA_AG_ERR_PHADAP_LNK_RES 2 /* Phone-adapter link reserved */
+#define BTA_AG_ERR_PHFSIM_PIN_REQ 6 /* PH-FSIM PIN required */
+#define BTA_AG_ERR_PHFSIM_PUK_REQ 7 /* PH-FSIM PUK required */
+#define BTA_AG_ERR_SIM_WRONG 15 /* SIM wrong */
+#define BTA_AG_ERR_NOT_FOUND 22 /* Not found */
+#define BTA_AG_ERR_NETWORK_TIMEOUT 31 /* Network timeout */
+#define BTA_AG_ERR_NET_PIN_REQ 40 /* Network personalization PIN required */
+#define BTA_AG_ERR_NET_PUK_REQ 41 /* Network personalization PUK required */
+/* Network subset personalization PIN required */
+#define BTA_AG_ERR_SUBSET_PIN_REQ 42
+/* Network subset personalization PUK required */
+#define BTA_AG_ERR_SUBSET_PUK_REQ 43
+/* Service provider personalization PIN required */
+#define BTA_AG_ERR_SERVPRO_PIN_REQ 44
+/* Service provider personalization PUK required */
+#define BTA_AG_ERR_SERVPRO_PUK_REQ 45
+/* Corporate personalization PIN required */
+#define BTA_AG_ERR_CORP_PIN_REQ 46
+/* Corporate personalization PUK required */
+#define BTA_AG_ERR_CORP_PUK_REQ 47
+#define BTA_AG_ERR_UNKNOWN 100 /* Unknown error */
+
+/* GPRS-related errors */
+#define BTA_AG_ERR_ILL_MS 103 /* Illegal MS (#3) */
+#define BTA_AG_ERR_ILL_ME 106 /* Illegal ME (#6) */
+#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107 /* GPRS services not allowed (#7) */
+#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111 /* PLMN services not allowed (#11) */
+#define BTA_AG_ERR_LOC_NOT_ALLOWED 112 /* Location area not allowed (#12) */
+/* Roaming not allowed in this location area (#13) */
+#define BTA_AG_ERR_ROAM_NOT_ALLOWED 113
+/* Errors related to a failure to Activate a Context */
+#define BTA_AG_ERR_OPT_NOT_SUPP 132 /* Service option not supported (#32) */
+/* Requested service option not subscribed (#33) */
+#define BTA_AG_ERR_OPT_NOT_SUBSCR 133
+/* Service option temporarily out of order (#34) */
+#define BTA_AG_ERR_OPT_OUT_OF_ORDER 134
+#define BTA_AG_ERR_PDP_AUTH_FAILURE 149 /* PDP authentication failure */
+/* Other GPRS errors */
+#define BTA_AG_ERR_INV_MOBILE_CLASS 150 /* Invalid mobile class */
+#define BTA_AG_ERR_UNSPEC_GPRS_ERR 148 /* Unspecified GPRS error */
+#endif /* Unused error codes */
+
+/* HFP result data 'ok_flag' */
+#define BTA_AG_OK_CONTINUE 0 /* Send out response (more responses coming) */
+#define BTA_AG_OK_DONE 1 /* Send out response followed by OK (finished) */
+#define BTA_AG_OK_ERROR 2 /* Error response */
+
+/* BTRH values */
+#define BTA_AG_BTRH_SET_HOLD 0 /* Put incoming call on hold */
+#define BTA_AG_BTRH_SET_ACC 1 /* Accept incoming call on hold */
+#define BTA_AG_BTRH_SET_REJ 2 /* Reject incoming call on hold */
+#define BTA_AG_BTRH_READ 3 /* Read the current value */
+#define BTA_AG_BTRH_NO_RESP 4 /* Not in RH States (reply to read) */
+
+/* ASCII character string of arguments to the AT command or result */
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 256
+#endif
+
+/* data associated with BTA_AG_IND_RES */
+typedef struct {
+ uint16_t id;
+ uint16_t value;
+ bool on_demand;
+} tBTA_AG_IND;
+
+/* data type for BTA_AgResult() */
+typedef struct {
+ char str[BTA_AG_AT_MAX_LEN + 1];
+ tBTA_AG_IND ind;
+ uint16_t num;
+ uint16_t audio_handle;
+ uint16_t errcode; /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */
+ uint8_t
+ ok_flag; /* Indicates if response is finished, and if error occurred */
+ bool state;
+} tBTA_AG_RES_DATA;
+
+/* AG callback events */
+#define BTA_AG_ENABLE_EVT 0 /* AG enabled */
+#define BTA_AG_REGISTER_EVT 1 /* AG registered */
+#define BTA_AG_OPEN_EVT 2 /* AG connection open */
+#define BTA_AG_CLOSE_EVT 3 /* AG connection closed */
+#define BTA_AG_CONN_EVT 4 /* Service level connection opened */
+#define BTA_AG_AUDIO_OPEN_EVT 5 /* Audio connection open */
+#define BTA_AG_AUDIO_CLOSE_EVT 6 /* Audio connection closed */
+#define BTA_AG_SPK_EVT 7 /* Speaker volume changed */
+#define BTA_AG_MIC_EVT 8 /* Microphone volume changed */
+#define BTA_AG_AT_CKPD_EVT 9 /* CKPD from the HS */
+#define BTA_AG_DISABLE_EVT 30 /* AG disabled */
+#define BTA_AG_WBS_EVT 31 /* SCO codec info */
+/* Values below are for HFP only */
+#define BTA_AG_AT_A_EVT 10 /* Answer a call */
+#define BTA_AG_AT_D_EVT 11 /* Place a call using number or memory dial */
+#define BTA_AG_AT_CHLD_EVT 12 /* Call hold */
+#define BTA_AG_AT_CHUP_EVT 13 /* Hang up a call */
+#define BTA_AG_AT_CIND_EVT 14 /* Read indicator settings */
+#define BTA_AG_AT_VTS_EVT 15 /* Transmit DTMF tone */
+#define BTA_AG_AT_BINP_EVT 16 /* Retrieve number from voice tag */
+#define BTA_AG_AT_BLDN_EVT 17 /* Place call to last dialed number */
+#define BTA_AG_AT_BVRA_EVT 18 /* Enable/disable voice recognition */
+#define BTA_AG_AT_NREC_EVT 19 /* Disable echo canceling */
+#define BTA_AG_AT_CNUM_EVT 20 /* Retrieve subscriber number */
+#define BTA_AG_AT_BTRH_EVT 21 /* CCAP-style incoming call hold */
+#define BTA_AG_AT_CLCC_EVT 22 /* Query list of current calls */
+#define BTA_AG_AT_COPS_EVT 23 /* Query list of current calls */
+#define BTA_AG_AT_UNAT_EVT 24 /* Unknown AT command */
+#define BTA_AG_AT_CBC_EVT 25 /* Battery Level report from HF */
+#define BTA_AG_AT_BAC_EVT 26 /* avablable codec */
+#define BTA_AG_AT_BCS_EVT 27 /* Codec select */
+#define BTA_AG_AT_BIND_EVT 28 /* HF indicator */
+#define BTA_AG_AT_BIEV_EVT 29 /* HF indicator updates from peer */
+
+typedef uint8_t tBTA_AG_EVT;
+
+/* data associated with most non-AT events */
+typedef struct {
+ uint16_t handle;
+ uint8_t app_id;
+ tBTA_AG_STATUS status;
+} tBTA_AG_HDR;
+
+/* data associated with BTA_AG_REGISTER_EVT */
+typedef struct {
+ tBTA_AG_HDR hdr;
+ tBTA_AG_STATUS status;
+} tBTA_AG_REGISTER;
+
+/* data associated with BTA_AG_OPEN_EVT */
+typedef struct {
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_ID service_id;
+ tBTA_AG_STATUS status;
+} tBTA_AG_OPEN;
+
+/* data associated with BTA_AG_CLOSE_EVT */
+typedef struct {
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_AG_CLOSE;
+
+/* data associated with BTA_AG_CONN_EVT */
+typedef struct {
+ tBTA_AG_HDR hdr;
+ tBTA_AG_PEER_FEAT peer_feat;
+ BD_ADDR bd_addr;
+ tBTA_AG_PEER_CODEC peer_codec;
+} tBTA_AG_CONN;
+
+/* data associated with AT command event */
+typedef struct {
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+ char str[BTA_AG_AT_MAX_LEN + 1];
+ uint16_t num;
+ uint8_t idx; /* call number used by CLCC and CHLD */
+ uint16_t lidx; /* long index, ex, HF indicator */
+} tBTA_AG_VAL;
+
+/* union of data associated with AG callback */
+typedef union {
+ tBTA_AG_HDR hdr;
+ tBTA_AG_REGISTER reg;
+ tBTA_AG_OPEN open;
+ tBTA_AG_CLOSE close;
+ tBTA_AG_CONN conn;
+ tBTA_AG_VAL val;
+} tBTA_AG;
+
+/* AG callback */
+typedef void(tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG* p_data);
+
+/* indicator constants HFP 1.1 and later */
+#define BTA_AG_IND_CALL 1 /* position of call indicator */
+#define BTA_AG_IND_CALLSETUP 2 /* position of callsetup indicator */
+#define BTA_AG_IND_SERVICE 3 /* position of service indicator */
+
+/* indicator constants HFP 1.5 and later */
+#define BTA_AG_IND_SIGNAL 4 /* position of signal strength indicator */
+#define BTA_AG_IND_ROAM 5 /* position of roaming indicator */
+#define BTA_AG_IND_BATTCHG 6 /* position of battery charge indicator */
+#define BTA_AG_IND_CALLHELD 7 /* position of callheld indicator */
+#define BTA_AG_IND_BEARER 8 /* position of bearer indicator */
+
+/* call indicator values */
+#define BTA_AG_CALL_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_CALL_ACTIVE 1 /* Phone call active */
+
+/* callsetup indicator values */
+#define BTA_AG_CALLSETUP_NONE 0 /* Not currently in call set up */
+#define BTA_AG_CALLSETUP_INCOMING 1 /* Incoming call process ongoing */
+#define BTA_AG_CALLSETUP_OUTGOING 2 /* Outgoing call set up is ongoing */
+/* Remote party being alerted in an outgoing call */
+#define BTA_AG_CALLSETUP_ALERTING 3
+
+/* service indicator values */
+#define BTA_AG_SERVICE_NONE 0 /* Neither CS nor VoIP service is available */
+#define BTA_AG_SERVICE_CS 1 /* Only CS service is available */
+#define BTA_AG_SERVICE_VOIP 2 /* Only VoIP service is available */
+#define BTA_AG_SERVICE_CS_VOIP 3 /* Both CS and VoIP services available */
+
+/* callheld indicator values */
+#define BTA_AG_CALLHELD_INACTIVE 0 /* No held calls */
+#define BTA_AG_CALLHELD_ACTIVE 1 /* Call held and call active */
+#define BTA_AG_CALLHELD_NOACTIVE 2 /* Call held and no call active */
+
+/* signal strength indicator values */
+#define BTA_AG_ROAMING_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_ROAMING_ACTIVE 1 /* Phone call active */
+
+/* bearer indicator values */
+#define BTA_AG_BEARER_WLAN 0 /* WLAN */
+#define BTA_AG_BEARER_BLUETOOTH 1 /* Bluetooth */
+#define BTA_AG_BEARER_WIRED 2 /* Wired */
+#define BTA_AG_BEARER_2G3G 3 /* 2G 3G */
+#define BTA_AG_BEARER_WIMAX 4 /* WIMAX */
+#define BTA_AG_BEARER_RES1 5 /* Reserved */
+#define BTA_AG_BEARER_RES2 6 /* Reserved */
+#define BTA_AG_BEARER_RES3 7 /* Reserved */
+
+/* type for HF indicator */
+typedef struct {
+ uint16_t ind_id;
+ bool is_supported;
+ bool is_enable;
+ uint32_t ind_min_val;
+ uint32_t ind_max_val;
+} tBTA_AG_HF_IND;
+
+/* AG configuration structure */
+typedef struct {
+ const char* cind_info;
+ const char* bind_info;
+ uint8_t num_local_hf_ind;
+ int32_t conn_tout;
+ uint16_t sco_pkt_types;
+ const char* chld_val_ecc;
+ const char* chld_val;
+} tBTA_AG_CFG;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_AgEnable
+ *
+ * Description Enable the audio gateway service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_AG_ENABLE_EVT. This function must
+ * be called before other function in the AG API are
+ * called.
+ *
+ * Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgDisable
+ *
+ * Description Disable the audio gateway service
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgRegister
+ *
+ * Description Register an Audio Gateway service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+ tBTA_AG_FEAT features, const char* p_service_names[],
+ uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgDeregister
+ *
+ * Description Deregister an audio gateway service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgDeregister(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgOpen
+ *
+ * Description Opens a connection to a headset or hands-free device.
+ * When connection is open callback function is called
+ * with a BTA_AG_OPEN_EVT. Only the data connection is
+ * opened. The audio connection is not opened.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgOpen(uint16_t handle, BD_ADDR bd_addr, tBTA_SEC sec_mask,
+ tBTA_SERVICE_MASK services);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgClose
+ *
+ * Description Close the current connection to a headset or a handsfree
+ * Any current audio connection will also be closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgAudioOpen
+ *
+ * Description Opens an audio connection to the currently connected
+ * headset or hnadsfree
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgAudioOpen(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgAudioClose
+ *
+ * Description Close the currently active audio connection to a headset
+ * or hnadsfree. The data connection remains open
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgAudioClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgResult
+ *
+ * Description Send an AT result code to a headset or hands-free device.
+ * This function is only used when the AG parse mode is set
+ * to BTA_AG_PARSE.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgResult(uint16_t handle, tBTA_AG_RES result,
+ tBTA_AG_RES_DATA* p_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_AgSetCodec
+ *
+ * Description Specify the codec type to be used for the subsequent
+ * audio connection.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AgSetCodec(uint16_t handle, tBTA_AG_PEER_CODEC codec);
+
+#endif /* BTA_AG_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_ag_ci.h b/mtkbt/code/bt/bta/include/bta_ag_ci.h
new file mode 100755
index 0000000..01e3870
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_ag_ci.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for audio gateway call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_CI_H
+#define BTA_AG_CI_H
+
+#include "bta_ag_api.h"
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_ag_ci_rx_write
+ *
+ * Description This function is called to send data to the AG when the AG
+ * is configured for AT command pass-through. The function
+ * copies data to an event buffer and sends it.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ag_ci_rx_write(uint16_t handle, char* p_data, uint16_t len);
+
+/******************************************************************************
+ *
+ * Function bta_ag_ci_slc_ready
+ *
+ * Description This function is called to notify AG that SLC is up at
+ * the application. This funcion is only used when the app
+ * is running in pass-through mode.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+extern void bta_ag_ci_slc_ready(uint16_t handle);
+
+/******************************************************************************
+ *
+ * Function bta_ag_ci_wbs_command
+ *
+ * Description This function is called to notify AG that a WBS command is
+ * received
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+extern void bta_ag_ci_wbs_command(uint16_t handle, char* p_data, uint16_t len);
+
+#endif /* BTA_AG_CI_H */
diff --git a/mtkbt/code/bt/bta/include/bta_ag_co.h b/mtkbt/code/bt/bta/include/bta_ag_co.h
new file mode 100755
index 0000000..aed7def
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_ag_co.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for audio gateway call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_CO_H
+#define BTA_AG_CO_H
+
+#include "bta_ag_api.h"
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_init
+ *
+ * Description This callout function is executed by AG when it is
+ * started by calling BTA_AgEnable(). This function can be
+ * used by the phone to initialize audio paths or for other
+ * initialization purposes.
+ *
+ *
+ * Returns Void.
+ *
+ ******************************************************************************/
+extern void bta_ag_co_init(void);
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_data_open
+ *
+ * Description This function is executed by AG when a service level
+ * connection
+ * is opened. The phone can use this function to set
+ * up data paths or perform any required initialization or
+ * set up particular to the connected service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service);
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_data_close
+ *
+ * Description This function is called by AG when a service level
+ * connection is closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_data_close(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_tx_write
+ *
+ * Description This function is called by the AG to send data to the
+ * phone when the AG is configured for AT command pass-through.
+ * The implementation of this function must copy the data to
+ * the phone's memory.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ag_co_tx_write(uint16_t handle, uint8_t* p_data, uint16_t len);
+
+#endif /* BTA_AG_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_api.h b/mtkbt/code/bt/bta/include/bta_api.h
new file mode 100755
index 0000000..560abf5
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_api.h
@@ -0,0 +1,1770 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for BTA, Broadcom's Bluetooth
+ * application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_API_H
+#define BTA_API_H
+
+#include <hardware/bt_common_types.h>
+#include <memory>
+#include "bt_target.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_ble_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/* Status Return Value */
+#define BTA_SUCCESS 0 /* Successful operation. */
+#define BTA_FAILURE 1 /* Generic failure. */
+#define BTA_PENDING 2 /* API cannot be completed right now */
+#define BTA_BUSY 3
+#define BTA_NO_RESOURCES 4
+#define BTA_WRONG_MODE 5
+
+typedef uint8_t tBTA_STATUS;
+
+/*
+ * Service ID
+ *
+ * NOTES: When you add a new Service ID for BTA AND require to change the value
+ * of BTA_MAX_SERVICE_ID,
+ * make sure that the correct security ID of the new service from
+ * Security service definitions (btm_api.h)
+ * should be added to bta_service_id_to_btm_srv_id_lkup_tbl table in
+ * bta_dm_act.c.
+ */
+
+#define BTA_RES_SERVICE_ID 0 /* Reserved */
+#define BTA_SPP_SERVICE_ID 1 /* Serial port profile. */
+#define BTA_DUN_SERVICE_ID 2 /* Dial-up networking profile. */
+#define BTA_A2DP_SOURCE_SERVICE_ID 3 /* A2DP Source profile. */
+#define BTA_LAP_SERVICE_ID 4 /* LAN access profile. */
+#define BTA_HSP_SERVICE_ID 5 /* Headset profile. */
+#define BTA_HFP_SERVICE_ID 6 /* Hands-free profile. */
+#define BTA_OPP_SERVICE_ID 7 /* Object push */
+#define BTA_FTP_SERVICE_ID 8 /* File transfer */
+#define BTA_CTP_SERVICE_ID 9 /* Cordless Terminal */
+#define BTA_ICP_SERVICE_ID 10 /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_ID 11 /* Synchronization */
+#define BTA_BPP_SERVICE_ID 12 /* Basic printing profile */
+#define BTA_BIP_SERVICE_ID 13 /* Basic Imaging profile */
+#define BTA_PANU_SERVICE_ID 14 /* PAN User */
+#define BTA_NAP_SERVICE_ID 15 /* PAN Network access point */
+#define BTA_GN_SERVICE_ID 16 /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_ID 17 /* SIM Access profile */
+#define BTA_A2DP_SINK_SERVICE_ID 18 /* A2DP Sink */
+#define BTA_AVRCP_SERVICE_ID 19 /* A/V remote control */
+#define BTA_HID_SERVICE_ID 20 /* HID */
+#define BTA_VDP_SERVICE_ID 21 /* Video distribution */
+#define BTA_PBAP_SERVICE_ID 22 /* PhoneBook Access Server*/
+#define BTA_HSP_HS_SERVICE_ID 23 /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_ID 24 /* HSP HS role */
+#define BTA_MAP_SERVICE_ID 25 /* Message Access Profile */
+#define BTA_MN_SERVICE_ID 26 /* Message Notification Service */
+#define BTA_HDP_SERVICE_ID 27 /* Health Device Profile */
+#define BTA_PCE_SERVICE_ID 28 /* PhoneBook Access Client */
+#define BTA_SDP_SERVICE_ID 29 /* SDP Search */
+#define BTA_HIDD_SERVICE_ID 30 /* HID Device */
+
+/* BLE profile service ID */
+#define BTA_BLE_SERVICE_ID 31 /* GATT profile */
+#define BTA_USER_SERVICE_ID 32 /* User requested UUID */
+#define BTA_MAX_SERVICE_ID 33
+
+/* service IDs (BTM_SEC_SERVICE_FIRST_EMPTY + 1) to (BTM_SEC_MAX_SERVICES - 1)
+ * are used by BTA JV */
+#define BTA_FIRST_JV_SERVICE_ID (BTM_SEC_SERVICE_FIRST_EMPTY + 1)
+#define BTA_LAST_JV_SERVICE_ID (BTM_SEC_MAX_SERVICES - 1)
+
+typedef uint8_t tBTA_SERVICE_ID;
+
+/* Service ID Mask */
+#define BTA_RES_SERVICE_MASK 0x00000001 /* Reserved */
+#define BTA_SPP_SERVICE_MASK 0x00000002 /* Serial port profile. */
+#define BTA_DUN_SERVICE_MASK 0x00000004 /* Dial-up networking profile. */
+#define BTA_FAX_SERVICE_MASK 0x00000008 /* Fax profile. */
+#define BTA_LAP_SERVICE_MASK 0x00000010 /* LAN access profile. */
+#define BTA_HSP_SERVICE_MASK 0x00000020 /* HSP AG role. */
+#define BTA_HFP_SERVICE_MASK 0x00000040 /* HFP AG role */
+#define BTA_OPP_SERVICE_MASK 0x00000080 /* Object push */
+#define BTA_FTP_SERVICE_MASK 0x00000100 /* File transfer */
+#define BTA_CTP_SERVICE_MASK 0x00000200 /* Cordless Terminal */
+#define BTA_ICP_SERVICE_MASK 0x00000400 /* Intercom Terminal */
+#define BTA_SYNC_SERVICE_MASK 0x00000800 /* Synchronization */
+#define BTA_BPP_SERVICE_MASK 0x00001000 /* Print server */
+#define BTA_BIP_SERVICE_MASK 0x00002000 /* Basic Imaging */
+#define BTA_PANU_SERVICE_MASK 0x00004000 /* PAN User */
+#define BTA_NAP_SERVICE_MASK 0x00008000 /* PAN Network access point */
+#define BTA_GN_SERVICE_MASK 0x00010000 /* PAN Group Ad-hoc networks */
+#define BTA_SAP_SERVICE_MASK 0x00020000 /* PAN Group Ad-hoc networks */
+#define BTA_A2DP_SERVICE_MASK 0x00040000 /* Advanced audio distribution */
+#define BTA_AVRCP_SERVICE_MASK 0x00080000 /* A/V remote control */
+#define BTA_HID_SERVICE_MASK 0x00100000 /* HID */
+#define BTA_VDP_SERVICE_MASK 0x00200000 /* Video distribution */
+#define BTA_PBAP_SERVICE_MASK 0x00400000 /* Phone Book Server */
+#define BTA_HSP_HS_SERVICE_MASK 0x00800000 /* HFP HS role */
+#define BTA_HFP_HS_SERVICE_MASK 0x01000000 /* HSP HS role */
+#define BTA_MAS_SERVICE_MASK 0x02000000 /* Message Access Profile */
+#define BTA_MN_SERVICE_MASK 0x04000000 /* Message Notification Profile */
+#define BTA_HL_SERVICE_MASK 0x08000000 /* Health Device Profile */
+#define BTA_PCE_SERVICE_MASK 0x10000000 /* Phone Book Client */
+#define BTA_HIDD_SERVICE_MASK 0x20000000 /* HID Device */
+
+#define BTA_BLE_SERVICE_MASK 0x40000000 /* GATT based service */
+#define BTA_ALL_SERVICE_MASK 0x7FFFFFFF /* All services supported by BTA. */
+#define BTA_USER_SERVICE_MASK 0x80000000 /* Message Notification Profile */
+
+typedef uint32_t tBTA_SERVICE_MASK;
+
+/* extended service mask, including mask with one or more GATT UUID */
+typedef struct {
+ tBTA_SERVICE_MASK srvc_mask;
+ uint8_t num_uuid;
+ tBT_UUID* p_uuid;
+} tBTA_SERVICE_MASK_EXT;
+
+/* Security Setting Mask */
+#define BTA_SEC_NONE BTM_SEC_NONE /* No security. */
+#define BTA_SEC_AUTHORIZE \
+ (BTM_SEC_IN_AUTHORIZE) /* Authorization required (only needed for out \
+ going connection )*/
+#define BTA_SEC_AUTHENTICATE \
+ (BTM_SEC_IN_AUTHENTICATE | \
+ BTM_SEC_OUT_AUTHENTICATE) /* Authentication required. */
+#define BTA_SEC_ENCRYPT \
+ (BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT) /* Encryption required. */
+#define BTA_SEC_MODE4_LEVEL4 \
+ (BTM_SEC_MODE4_LEVEL4) /* Mode 4 level 4 service, i.e. incoming/outgoing \
+ MITM and P-256 encryption */
+#define BTA_SEC_MITM \
+ (BTM_SEC_IN_MITM | BTM_SEC_OUT_MITM) /* Man-In-The_Middle protection */
+#define BTA_SEC_IN_16_DIGITS \
+ (BTM_SEC_IN_MIN_16_DIGIT_PIN) /* Min 16 digit for pin code */
+
+typedef uint16_t tBTA_SEC;
+
+/* Ignore for Discoverable, Connectable, Pairable and Connectable Paired only
+ * device modes */
+#define BTA_DM_IGNORE 0x00FF
+
+/* Ignore for Discoverable, Connectable only for LE modes */
+#define BTA_DM_LE_IGNORE 0xFF00
+
+#define BTA_APP_ID_PAN_MULTI 0xFE /* app id for pan multiple connection */
+#define BTA_ALL_APP_ID 0xFF
+
+/* Discoverable Modes */
+#define BTA_DM_NON_DISC BTM_NON_DISCOVERABLE /* Device is not discoverable. */
+#define BTA_DM_GENERAL_DISC \
+ BTM_GENERAL_DISCOVERABLE /* General discoverable. \
+ */
+#define BTA_DM_BLE_NON_DISCOVERABLE \
+ BTM_BLE_NON_DISCOVERABLE /* Device is not LE discoverable */
+#define BTA_DM_BLE_GENERAL_DISCOVERABLE \
+ BTM_BLE_GENERAL_DISCOVERABLE /* Device is LE General discoverable */
+#define BTA_DM_BLE_LIMITED_DISCOVERABLE \
+ BTM_BLE_LIMITED_DISCOVERABLE /* Device is LE Limited discoverable */
+typedef uint16_t
+ tBTA_DM_DISC; /* this discoverability mode is a bit mask among BR mode and
+ LE mode */
+
+/* Connectable Modes */
+#define BTA_DM_NON_CONN BTM_NON_CONNECTABLE /* Device is not connectable. */
+#define BTA_DM_CONN BTM_CONNECTABLE /* Device is connectable. */
+#define BTA_DM_BLE_NON_CONNECTABLE \
+ BTM_BLE_NON_CONNECTABLE /* Device is LE non-connectable. */
+#define BTA_DM_BLE_CONNECTABLE \
+ BTM_BLE_CONNECTABLE /* Device is LE connectable. */
+
+typedef uint16_t tBTA_DM_CONN;
+
+#define BTA_TRANSPORT_UNKNOWN 0
+#define BTA_TRANSPORT_BR_EDR BT_TRANSPORT_BR_EDR
+#define BTA_TRANSPORT_LE BT_TRANSPORT_LE
+typedef tBT_TRANSPORT tBTA_TRANSPORT;
+
+/* Pairable Modes */
+#define BTA_DM_PAIRABLE 1
+#define BTA_DM_NON_PAIRABLE 0
+
+/* Connectable Paired Only Mode */
+#define BTA_DM_CONN_ALL 0
+#define BTA_DM_CONN_PAIRED 1
+
+/* Inquiry Modes */
+#define BTA_DM_INQUIRY_NONE BTM_INQUIRY_NONE /*No BR inquiry. */
+#define BTA_DM_GENERAL_INQUIRY \
+ BTM_GENERAL_INQUIRY /* Perform general inquiry. */
+#define BTA_DM_LIMITED_INQUIRY \
+ BTM_LIMITED_INQUIRY /* Perform limited inquiry. */
+
+#define BTA_BLE_INQUIRY_NONE BTM_BLE_INQUIRY_NONE
+#define BTA_BLE_GENERAL_INQUIRY \
+ BTM_BLE_GENERAL_INQUIRY /* Perform LE general inquiry. */
+#define BTA_BLE_LIMITED_INQUIRY \
+ BTM_BLE_LIMITED_INQUIRY /* Perform LE limited inquiry. */
+typedef uint8_t tBTA_DM_INQ_MODE;
+
+/* Inquiry Filter Type */
+#define BTA_DM_INQ_CLR BTM_CLR_INQUIRY_FILTER /* Clear inquiry filter. */
+#define BTA_DM_INQ_DEV_CLASS \
+ BTM_FILTER_COND_DEVICE_CLASS /* Filter on device class. */
+#define BTA_DM_INQ_BD_ADDR \
+ BTM_FILTER_COND_BD_ADDR /* Filter on a specific BD address. */
+
+typedef uint8_t tBTA_DM_INQ_FILT;
+
+/* Authorize Response */
+#define BTA_DM_AUTH_PERM \
+ 0 /* Authorized for future connections to the service */
+#define BTA_DM_AUTH_TEMP 1 /* Authorized for current connection only */
+#define BTA_DM_NOT_AUTH 2 /* Not authorized for the service */
+
+typedef uint8_t tBTA_AUTH_RESP;
+
+/* M/S preferred roles */
+#define BTA_ANY_ROLE 0x00
+#define BTA_MASTER_ROLE_PREF 0x01
+#define BTA_MASTER_ROLE_ONLY 0x02
+#define BTA_SLAVE_ROLE_ONLY \
+ 0x03 /* Used for PANU only, skip role switch to master */
+
+typedef uint8_t tBTA_PREF_ROLES;
+
+enum {
+
+ BTA_DM_NO_SCATTERNET, /* Device doesn't support scatternet, it might
+ support "role switch during connection" for
+ an incoming connection, when it already has
+ another connection in master role */
+ BTA_DM_PARTIAL_SCATTERNET, /* Device supports partial scatternet. It can have
+ simulateous connection in Master and Slave roles
+ for short period of time */
+ BTA_DM_FULL_SCATTERNET /* Device can have simultaneous connection in master
+ and slave roles */
+
+};
+
+/* Inquiry filter device class condition */
+typedef struct {
+ DEV_CLASS dev_class; /* device class of interest */
+ DEV_CLASS dev_class_mask; /* mask to determine the bits of device class of
+ interest */
+} tBTA_DM_COD_COND;
+
+/* Inquiry Filter Condition */
+typedef union {
+ BD_ADDR bd_addr; /* BD address of device to filter. */
+ tBTA_DM_COD_COND dev_class_cond; /* Device class filter condition */
+} tBTA_DM_INQ_COND;
+
+/* Inquiry Parameters */
+typedef struct {
+ tBTA_DM_INQ_MODE mode; /* Inquiry mode, limited or general. */
+ uint8_t duration; /* Inquiry duration in 1.28 sec units. */
+ uint8_t max_resps; /* Maximum inquiry responses. Set to zero for unlimited
+ responses. */
+ bool report_dup; /* report duplicated inquiry response with higher RSSI value
+ */
+ tBTA_DM_INQ_FILT filter_type; /* Filter condition type. */
+ tBTA_DM_INQ_COND filter_cond; /* Filter condition data. */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ uint8_t intl_duration
+ [4]; /*duration array storing the interleave scan's time portions*/
+#endif
+} tBTA_DM_INQ;
+
+typedef struct {
+ uint8_t bta_dm_eir_min_name_len; /* minimum length of local name when it is
+ shortened */
+#if (BTA_EIR_CANNED_UUID_LIST == TRUE)
+ uint8_t bta_dm_eir_uuid16_len; /* length of 16-bit UUIDs */
+ uint8_t* bta_dm_eir_uuid16; /* 16-bit UUIDs */
+#else
+ uint32_t uuid_mask[BTM_EIR_SERVICE_ARRAY_SIZE]; /* mask of UUID list in EIR */
+#endif
+ int8_t* bta_dm_eir_inq_tx_power; /* Inquiry TX power */
+ uint8_t bta_dm_eir_flag_len; /* length of flags in bytes */
+ uint8_t* bta_dm_eir_flags; /* flags for EIR */
+ uint8_t bta_dm_eir_manufac_spec_len; /* length of manufacturer specific in
+ bytes */
+ uint8_t* bta_dm_eir_manufac_spec; /* manufacturer specific */
+ uint8_t bta_dm_eir_additional_len; /* length of additional data in bytes */
+ uint8_t* bta_dm_eir_additional; /* additional data */
+} tBTA_DM_EIR_CONF;
+
+/* advertising filter policy */
+typedef tBTM_BLE_AFP tBTA_BLE_AFP;
+
+enum {
+ BTA_BLE_BATCH_SCAN_MODE_PASS = 1,
+ BTA_BLE_BATCH_SCAN_MODE_ACTI = 2,
+ BTA_BLE_BATCH_SCAN_MODE_PASS_ACTI = 3
+};
+typedef uint8_t tBTA_BLE_BATCH_SCAN_MODE;
+
+enum { BTA_BLE_DISCARD_OLD_ITEMS = 0, BTA_BLE_DISCARD_LOWER_RSSI_ITEMS = 1 };
+typedef uint8_t tBTA_BLE_DISCARD_RULE;
+
+enum { BTA_BLE_ADV_SEEN_FIRST_TIME = 0, BTA_BLE_ADV_TRACKING_TIMEOUT = 1 };
+typedef uint8_t tBTA_BLE_ADV_CHANGE_REASON;
+
+/* BLE customer specific feature function type definitions */
+/* data type used on customer specific feature for RSSI monitoring */
+#define BTA_BLE_RSSI_ALERT_HI 0
+#define BTA_BLE_RSSI_ALERT_RANGE 1
+#define BTA_BLE_RSSI_ALERT_LO 2
+typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_TYPE;
+
+#define BTA_BLE_RSSI_ALERT_NONE BTM_BLE_RSSI_ALERT_NONE /* (0) */
+#define BTA_BLE_RSSI_ALERT_HI_BIT BTM_BLE_RSSI_ALERT_HI_BIT /* (1) */
+#define BTA_BLE_RSSI_ALERT_RANGE_BIT \
+ BTM_BLE_RSSI_ALERT_RANGE_BIT /* (1 << 1) */
+#define BTA_BLE_RSSI_ALERT_LO_BIT BTM_BLE_RSSI_ALERT_LO_BIT /* (1 << 2) */
+typedef uint8_t tBTA_DM_BLE_RSSI_ALERT_MASK;
+
+typedef void(tBTA_DM_BLE_RSSI_CBACK)(BD_ADDR bd_addr,
+ tBTA_DM_BLE_RSSI_ALERT_TYPE alert_type,
+ int8_t rssi);
+
+typedef int8_t tBTA_DM_RSSI_VALUE;
+typedef uint8_t tBTA_DM_LINK_QUALITY_VALUE;
+
+typedef uint8_t tBTA_SIG_STRENGTH_MASK;
+
+/* Security Callback Events */
+#define BTA_DM_ENABLE_EVT 0 /* Enable Event */
+#define BTA_DM_DISABLE_EVT 1 /* Disable Event */
+#define BTA_DM_PIN_REQ_EVT 2 /* PIN request. */
+#define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */
+#define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */
+#define BTA_DM_LINK_UP_EVT 5 /* Connection UP event */
+#define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */
+#define BTA_DM_SIG_STRENGTH_EVT \
+ 7 /* Signal strength for bluetooth connection \
+ */
+#define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */
+#define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */
+#define BTA_DM_SP_CFM_REQ_EVT \
+ 10 /* Simple Pairing User Confirmation request. \
+ */
+#define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */
+#define BTA_DM_SP_RMT_OOB_EVT 12 /* Simple Pairing Remote OOB Data request. */
+#define BTA_DM_SP_KEYPRESS_EVT 13 /* Key press notification event. */
+#define BTA_DM_ROLE_CHG_EVT 14 /* Role Change event. */
+#define BTA_DM_BLE_KEY_EVT 15 /* BLE SMP key event for peer device keys */
+#define BTA_DM_BLE_SEC_REQ_EVT 16 /* BLE SMP security request */
+#define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */
+#define BTA_DM_BLE_PASSKEY_REQ_EVT 18 /* SMP passkey request event */
+#define BTA_DM_BLE_OOB_REQ_EVT 19 /* SMP OOB request event */
+#define BTA_DM_BLE_LOCAL_IR_EVT 20 /* BLE local IR event */
+#define BTA_DM_BLE_LOCAL_ER_EVT 21 /* BLE local ER event */
+#define BTA_DM_BLE_NC_REQ_EVT 22 /* SMP Numeric Comparison request event */
+#define BTA_DM_SP_RMT_OOB_EXT_EVT \
+ 23 /* Simple Pairing Remote OOB Extended Data request. */
+#define BTA_DM_BLE_AUTH_CMPL_EVT 24 /* BLE Auth complete */
+#define BTA_DM_DEV_UNPAIRED_EVT 25
+#define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */
+#define BTA_DM_LE_FEATURES_READ \
+ 27 /* Cotroller specific LE features are read \
+ */
+#define BTA_DM_ENER_INFO_READ 28 /* Energy info read */
+#define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+#define BTA_DM_REPORT_BONDING_EVT 30 /*handle for pin or key missing*/
+#endif
+#endif
+
+typedef uint8_t tBTA_DM_SEC_EVT;
+
+/* Structure associated with BTA_DM_ENABLE_EVT */
+typedef struct { tBTA_STATUS status; } tBTA_DM_ENABLE;
+
+/* Structure associated with BTA_DM_PIN_REQ_EVT */
+typedef struct {
+ /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+ * order */
+ BD_ADDR bd_addr; /* BD address peer device. */
+ DEV_CLASS dev_class; /* Class of Device */
+ BD_NAME bd_name; /* Name of peer device. */
+ bool min_16_digit; /* true if the pin returned must be at least 16 digits */
+} tBTA_DM_PIN_REQ;
+
+/* BLE related definition */
+
+#define BTA_DM_AUTH_FAIL_BASE (HCI_ERR_MAX_ERR + 10)
+
+/* Converts SMP error codes defined in smp_api.h to SMP auth fail reasons below.
+ */
+#define BTA_DM_AUTH_CONVERT_SMP_CODE(x) (BTA_DM_AUTH_FAIL_BASE + (x))
+
+#define BTA_DM_AUTH_SMP_PASSKEY_FAIL \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_PASSKEY_ENTRY_FAIL)
+#define BTA_DM_AUTH_SMP_OOB_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_OOB_FAIL)
+#define BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_AUTH_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_VALUE_ERR)
+#define BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_NOT_SUPPORT)
+#define BTA_DM_AUTH_SMP_ENC_KEY_SIZE (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_KEY_SIZE)
+#define BTA_DM_AUTH_SMP_INVALID_CMD (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_CMD)
+#define BTA_DM_AUTH_SMP_UNKNOWN_ERR \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_FAIL_UNKNOWN)
+#define BTA_DM_AUTH_SMP_REPEATED_ATTEMPT \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_REPEATED_ATTEMPTS)
+#define BTA_DM_AUTH_SMP_INVALID_PARAMETERS \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_INVALID_PARAMETERS)
+#define BTA_DM_AUTH_SMP_INTERNAL_ERR \
+ (BTA_DM_AUTH_FAIL_BASE + SMP_PAIR_INTERNAL_ERR)
+#define BTA_DM_AUTH_SMP_UNKNOWN_IO (BTA_DM_AUTH_FAIL_BASE + SMP_UNKNOWN_IO_CAP)
+#define BTA_DM_AUTH_SMP_INIT_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_INIT_FAIL)
+#define BTA_DM_AUTH_SMP_CONFIRM_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_CONFIRM_FAIL)
+#define BTA_DM_AUTH_SMP_BUSY (BTA_DM_AUTH_FAIL_BASE + SMP_BUSY)
+#define BTA_DM_AUTH_SMP_ENC_FAIL (BTA_DM_AUTH_FAIL_BASE + SMP_ENC_FAIL)
+#define BTA_DM_AUTH_SMP_RSP_TIMEOUT (BTA_DM_AUTH_FAIL_BASE + SMP_RSP_TIMEOUT)
+#define BTA_DM_AUTH_SMP_CONN_TOUT (BTA_DM_AUTH_FAIL_BASE + SMP_CONN_TOUT)
+
+/* connection parameter boundary value and dummy value */
+#define BTA_DM_BLE_SCAN_INT_MIN BTM_BLE_SCAN_INT_MIN
+#define BTA_DM_BLE_SCAN_INT_MAX BTM_BLE_SCAN_INT_MAX
+#define BTA_DM_BLE_SCAN_WIN_MIN BTM_BLE_SCAN_WIN_MIN
+#define BTA_DM_BLE_SCAN_WIN_MAX BTM_BLE_SCAN_WIN_MAX
+#define BTA_DM_BLE_CONN_INT_MIN BTM_BLE_CONN_INT_MIN
+#define BTA_DM_BLE_CONN_INT_MAX BTM_BLE_CONN_INT_MAX
+#define BTA_DM_BLE_CONN_LATENCY_MAX BTM_BLE_CONN_LATENCY_MAX
+#define BTA_DM_BLE_CONN_SUP_TOUT_MIN BTM_BLE_CONN_SUP_TOUT_MIN
+#define BTA_DM_BLE_CONN_SUP_TOUT_MAX BTM_BLE_CONN_SUP_TOUT_MAX
+#define BTA_DM_BLE_CONN_PARAM_UNDEF \
+ BTM_BLE_CONN_PARAM_UNDEF /* use this value when a specific value not to be \
+ overwritten */
+
+#define BTA_LE_KEY_PENC \
+ BTM_LE_KEY_PENC /* encryption information of peer device */
+#define BTA_LE_KEY_PID BTM_LE_KEY_PID /* identity key of the peer device */
+#define BTA_LE_KEY_PCSRK BTM_LE_KEY_PCSRK /* peer SRK */
+#define BTA_LE_KEY_LENC \
+ BTM_LE_KEY_LENC /* master role security information:div */
+#define BTA_LE_KEY_LID BTM_LE_KEY_LID /* master device ID key */
+#define BTA_LE_KEY_LCSRK \
+ BTM_LE_KEY_LCSRK /* local CSRK has been deliver to peer */
+typedef uint8_t tBTA_LE_KEY_TYPE; /* can be used as a bit mask */
+
+typedef tBTM_LE_PENC_KEYS tBTA_LE_PENC_KEYS;
+typedef tBTM_LE_PCSRK_KEYS tBTA_LE_PCSRK_KEYS;
+typedef tBTM_LE_LENC_KEYS tBTA_LE_LENC_KEYS;
+typedef tBTM_LE_LCSRK_KEYS tBTA_LE_LCSRK_KEYS;
+typedef tBTM_LE_PID_KEYS tBTA_LE_PID_KEYS;
+
+typedef union {
+ tBTA_LE_PENC_KEYS penc_key; /* received peer encryption key */
+ tBTA_LE_PCSRK_KEYS psrk_key; /* received peer device SRK */
+ tBTA_LE_PID_KEYS pid_key; /* peer device ID key */
+ tBTA_LE_LENC_KEYS
+ lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+ tBTA_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+ tBTA_LE_PID_KEYS lid_key; /* local device ID key for the particular remote */
+} tBTA_LE_KEY_VALUE;
+
+#define BTA_BLE_LOCAL_KEY_TYPE_ID 1
+#define BTA_BLE_LOCAL_KEY_TYPE_ER 2
+typedef uint8_t tBTA_DM_BLE_LOCAL_KEY_MASK;
+
+typedef struct {
+ BT_OCTET16 ir;
+ BT_OCTET16 irk;
+ BT_OCTET16 dhk;
+} tBTA_BLE_LOCAL_ID_KEYS;
+
+#define BTA_DM_SEC_GRANTED BTA_SUCCESS
+#define BTA_DM_SEC_PAIR_NOT_SPT BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT
+#define BTA_DM_SEC_REP_ATTEMPTS BTA_DM_AUTH_SMP_REPEATED_ATTEMPT
+typedef uint8_t tBTA_DM_BLE_SEC_GRANT;
+
+/* Structure associated with BTA_DM_BLE_SEC_REQ_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ BD_NAME bd_name; /* peer device name */
+} tBTA_DM_BLE_SEC_REQ;
+
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_LE_KEY_TYPE key_type;
+ tBTM_LE_KEY_VALUE* p_key_value;
+} tBTA_DM_BLE_KEY;
+
+/* Structure associated with BTA_DM_AUTH_CMPL_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ bool key_present; /* Valid link key value in key element */
+ LINK_KEY key; /* Link key associated with peer device. */
+ uint8_t key_type; /* The type of Link Key */
+ bool success; /* true of authentication succeeded, false if failed. */
+ uint8_t fail_reason; /* The HCI reason/error code for when success=false */
+ tBLE_ADDR_TYPE addr_type; /* Peer device address type */
+ tBT_DEVICE_TYPE dev_type;
+} tBTA_DM_AUTH_CMPL;
+
+/* Structure associated with BTA_DM_AUTHORIZE_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBTA_SERVICE_ID service; /* Service ID to authorize. */
+ DEV_CLASS dev_class;
+} tBTA_DM_AUTHORIZE;
+
+/* Structure associated with BTA_DM_LINK_UP_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ tBTA_TRANSPORT link_type;
+} tBTA_DM_LINK_UP;
+
+/* Structure associated with BTA_DM_LINK_DOWN_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ uint8_t status; /* connection open/closed */
+ bool is_removed; /* true if device is removed when link is down */
+ tBTA_TRANSPORT link_type;
+} tBTA_DM_LINK_DOWN;
+
+/* Structure associated with BTA_DM_ROLE_CHG_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ uint8_t new_role; /* the new connection role */
+} tBTA_DM_ROLE_CHG;
+
+/* Structure associated with BTA_DM_BUSY_LEVEL_EVT */
+typedef struct {
+ uint8_t level; /* when paging or inquiring, level is 10.
+ Otherwise, the number of ACL links */
+ uint8_t level_flags; /* indicates individual flags */
+} tBTA_DM_BUSY_LEVEL;
+
+#define BTA_IO_CAP_OUT BTM_IO_CAP_OUT /* 0 DisplayOnly */
+#define BTA_IO_CAP_IO BTM_IO_CAP_IO /* 1 DisplayYesNo */
+#define BTA_IO_CAP_IN BTM_IO_CAP_IN /* 2 KeyboardOnly */
+#define BTA_IO_CAP_NONE BTM_IO_CAP_NONE /* 3 NoInputNoOutput */
+#define BTA_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* 4 Keyboard display */
+typedef tBTM_IO_CAP tBTA_IO_CAP;
+
+#define BTA_AUTH_SP_NO \
+ BTM_AUTH_SP_NO /* 0 MITM Protection Not Required - Single \
+ Profile/non-bonding \
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SP_YES \
+ BTM_AUTH_SP_YES /* 1 MITM Protection Required - Single Profile/non-bonding \
+ Use IO Capabilities to determine authentication procedure \
+ */
+#define BTA_AUTH_AP_NO \
+ BTM_AUTH_AP_NO /* 2 MITM Protection Not Required - All Profiles/dedicated \
+ bonding \
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_AP_YES \
+ BTM_AUTH_AP_YES /* 3 MITM Protection Required - All Profiles/dedicated \
+ bonding \
+ Use IO Capabilities to determine authentication procedure \
+ */
+#define BTA_AUTH_SPGB_NO \
+ BTM_AUTH_SPGB_NO /* 4 MITM Protection Not Required - Single Profiles/general \
+ bonding \
+ Numeric comparison with automatic accept allowed */
+#define BTA_AUTH_SPGB_YES \
+ BTM_AUTH_SPGB_YES /* 5 MITM Protection Required - Single Profiles/general \
+ bonding \
+ Use IO Capabilities to determine authentication \
+ procedure */
+typedef tBTM_AUTH_REQ tBTA_AUTH_REQ;
+
+#define BTA_AUTH_DD_BOND \
+ BTM_AUTH_DD_BOND /* 2 this bit is set for dedicated bonding */
+#define BTA_AUTH_GEN_BOND \
+ BTM_AUTH_SPGB_NO /* 4 this bit is set for general bonding */
+#define BTA_AUTH_BONDS \
+ BTM_AUTH_BONDS /* 6 the general/dedicated bonding bits */
+
+#define BTA_LE_AUTH_NO_BOND BTM_LE_AUTH_REQ_NO_BOND /* 0*/
+#define BTA_LE_AUTH_BOND BTM_LE_AUTH_REQ_BOND /* 1 << 0 */
+#define BTA_LE_AUTH_REQ_MITM BTM_LE_AUTH_REQ_MITM /* 1 << 2 */
+
+#define BTA_LE_AUTH_REQ_SC_ONLY BTM_LE_AUTH_REQ_SC_ONLY /* 1 << 3 */
+#define BTA_LE_AUTH_REQ_SC_BOND BTM_LE_AUTH_REQ_SC_BOND /* 1001 */
+#define BTA_LE_AUTH_REQ_SC_MITM BTM_LE_AUTH_REQ_SC_MITM /* 1100 */
+#define BTA_LE_AUTH_REQ_SC_MITM_BOND BTM_LE_AUTH_REQ_SC_MITM_BOND /* 1101 */
+typedef tBTM_LE_AUTH_REQ
+ tBTA_LE_AUTH_REQ; /* combination of the above bit pattern */
+
+#define BTA_OOB_NONE BTM_OOB_NONE
+#define BTA_OOB_PRESENT BTM_OOB_PRESENT
+#define BTA_OOB_UNKNOWN BTM_OOB_UNKNOWN
+
+typedef tBTM_OOB_DATA tBTA_OOB_DATA;
+
+/* Structure associated with BTA_DM_SP_CFM_REQ_EVT */
+typedef struct {
+ /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+ * order */
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+ uint32_t num_val; /* the numeric value for comparison. If just_works, do not
+ show this number to UI */
+ bool just_works; /* true, if "Just Works" association model */
+ tBTA_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+ tBTA_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
+ tBTA_IO_CAP loc_io_caps; /* IO Capabilities of local device */
+ tBTA_AUTH_REQ rmt_io_caps; /* IO Capabilities of remote device */
+} tBTA_DM_SP_CFM_REQ;
+
+enum {
+ BTA_SP_KEY_STARTED, /* passkey entry started */
+ BTA_SP_KEY_ENTERED, /* passkey digit entered */
+ BTA_SP_KEY_ERASED, /* passkey digit erased */
+ BTA_SP_KEY_CLEARED, /* passkey cleared */
+ BTA_SP_KEY_COMPLT /* passkey entry completed */
+};
+typedef uint8_t tBTA_SP_KEY_TYPE;
+
+/* Structure associated with BTA_DM_SP_KEYPRESS_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ tBTA_SP_KEY_TYPE notif_type;
+} tBTA_DM_SP_KEY_PRESS;
+
+/* Structure associated with BTA_DM_SP_KEY_NOTIF_EVT */
+typedef struct {
+ /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+ * order */
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+ uint32_t passkey; /* the numeric value for comparison. If just_works, do not
+ show this number to UI */
+} tBTA_DM_SP_KEY_NOTIF;
+
+/* Structure associated with BTA_DM_SP_RMT_OOB_EVT */
+typedef struct {
+ /* Note: First 3 data members must be, bd_addr, dev_class, and bd_name in
+ * order */
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ BD_NAME bd_name; /* peer device name */
+} tBTA_DM_SP_RMT_OOB;
+
+/* Structure associated with BTA_DM_BOND_CANCEL_CMPL_EVT */
+typedef struct {
+ tBTA_STATUS result; /* true of bond cancel succeeded, false if failed. */
+} tBTA_DM_BOND_CANCEL_CMPL;
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+typedef struct
+{
+ BD_ADDR bd_addr;
+}tBTA_DM_RC_UNPAIR;
+#endif
+#endif
+
+/* Union of all security callback structures */
+typedef union {
+ tBTA_DM_ENABLE enable; /* BTA enabled */
+ tBTA_DM_PIN_REQ pin_req; /* PIN request. */
+ tBTA_DM_AUTH_CMPL auth_cmpl; /* Authentication complete indication. */
+ tBTA_DM_AUTHORIZE authorize; /* Authorization request. */
+ tBTA_DM_LINK_UP link_up; /* ACL connection down event */
+ tBTA_DM_LINK_DOWN link_down; /* ACL connection down event */
+ tBTA_DM_BUSY_LEVEL busy_level; /* System busy level */
+ tBTA_DM_SP_CFM_REQ cfm_req; /* user confirm request */
+ tBTA_DM_SP_KEY_NOTIF key_notif; /* passkey notification */
+ tBTA_DM_SP_RMT_OOB rmt_oob; /* remote oob */
+ tBTA_DM_BOND_CANCEL_CMPL
+ bond_cancel_cmpl; /* Bond Cancel Complete indication */
+ tBTA_DM_SP_KEY_PRESS key_press; /* key press notification event */
+ tBTA_DM_ROLE_CHG role_chg; /* role change event */
+ tBTA_DM_BLE_SEC_REQ ble_req; /* BLE SMP related request */
+ tBTA_DM_BLE_KEY ble_key; /* BLE SMP keys used when pairing */
+ tBTA_BLE_LOCAL_ID_KEYS ble_id_keys; /* IR event */
+ BT_OCTET16 ble_er; /* ER event data */
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+ tBTA_DM_RC_UNPAIR delete_key_RC_to_unpair;
+#endif
+#endif
+} tBTA_DM_SEC;
+
+/* Security callback */
+typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
+
+#define BTA_DM_BLE_PF_LIST_LOGIC_OR 1
+#define BTA_DM_BLE_PF_FILT_LOGIC_OR 0
+
+/* Search callback events */
+#define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */
+#define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */
+#define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */
+#define BTA_DM_DISC_BLE_RES_EVT \
+ 3 /* Discovery result for BLE GATT based servoce on a peer device. */
+#define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */
+#define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */
+#define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
+
+typedef uint8_t tBTA_DM_SEARCH_EVT;
+
+#define BTA_DM_INQ_RES_IGNORE_RSSI \
+ BTM_INQ_RES_IGNORE_RSSI /* 0x7f RSSI value not supplied (ignore it) */
+
+/* Structure associated with BTA_DM_INQ_RES_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ DEV_CLASS dev_class; /* Device class of peer device. */
+ bool remt_name_not_required; /* Application sets this flag if it already knows
+ the name of the device */
+ /* If the device name is known to application BTA skips the remote name
+ * request */
+ bool is_limited; /* true, if the limited inquiry bit is set in the CoD */
+ int8_t rssi; /* The rssi value */
+ uint8_t* p_eir; /* received EIR */
+ uint16_t eir_len; /* received EIR length */
+ uint8_t inq_result_type;
+ uint8_t ble_addr_type;
+ uint16_t ble_evt_type;
+ uint8_t ble_primary_phy;
+ uint8_t ble_secondary_phy;
+ uint8_t ble_advertising_sid;
+ int8_t ble_tx_power;
+ uint16_t ble_periodic_adv_int;
+ tBT_DEVICE_TYPE device_type;
+ uint8_t flag;
+} tBTA_DM_INQ_RES;
+
+/* Structure associated with BTA_DM_INQ_CMPL_EVT */
+typedef struct {
+ uint8_t num_resps; /* Number of inquiry responses. */
+} tBTA_DM_INQ_CMPL;
+
+/* Structure associated with BTA_DM_DI_DISC_CMPL_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ uint8_t num_record; /* Number of DI record */
+ tBTA_STATUS result;
+} tBTA_DM_DI_DISC_CMPL;
+
+/* Structure associated with BTA_DM_DISC_RES_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBTA_SERVICE_MASK services; /* Services found on peer device. */
+ uint8_t* p_raw_data; /* Raw data for discovery DB */
+ uint32_t raw_data_size; /* size of raw data */
+ tBT_DEVICE_TYPE device_type; /* device type in case it is BLE device */
+ uint32_t num_uuids;
+ uint8_t* p_uuid_list;
+ tBTA_STATUS result;
+} tBTA_DM_DISC_RES;
+
+/* Structure associated with tBTA_DM_DISC_BLE_RES */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address peer device. */
+ BD_NAME bd_name; /* Name of peer device. */
+ tBT_UUID service; /* GATT based Services UUID found on peer device. */
+} tBTA_DM_DISC_BLE_RES;
+
+/* Union of all search callback structures */
+typedef union {
+ tBTA_DM_INQ_RES inq_res; /* Inquiry result for a peer device. */
+ tBTA_DM_INQ_CMPL inq_cmpl; /* Inquiry complete. */
+ tBTA_DM_DISC_RES disc_res; /* Discovery result for a peer device. */
+ tBTA_DM_DISC_BLE_RES
+ disc_ble_res; /* discovery result for GATT based service */
+ tBTA_DM_DI_DISC_CMPL di_disc; /* DI discovery result for a peer device */
+
+} tBTA_DM_SEARCH;
+
+/* Search callback */
+typedef void(tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event,
+ tBTA_DM_SEARCH* p_data);
+
+/* Execute call back */
+typedef void(tBTA_DM_EXEC_CBACK)(void* p_param);
+
+/* Encryption callback*/
+typedef void(tBTA_DM_ENCRYPT_CBACK)(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+ tBTA_STATUS result);
+
+#define BTA_DM_BLE_SEC_NONE BTM_BLE_SEC_NONE
+#define BTA_DM_BLE_SEC_ENCRYPT BTM_BLE_SEC_ENCRYPT
+#define BTA_DM_BLE_SEC_NO_MITM BTM_BLE_SEC_ENCRYPT_NO_MITM
+#define BTA_DM_BLE_SEC_MITM BTM_BLE_SEC_ENCRYPT_MITM
+typedef tBTM_BLE_SEC_ACT tBTA_DM_BLE_SEC_ACT;
+
+typedef tBTM_BLE_TX_TIME_MS tBTA_DM_BLE_TX_TIME_MS;
+typedef tBTM_BLE_RX_TIME_MS tBTA_DM_BLE_RX_TIME_MS;
+typedef tBTM_BLE_IDLE_TIME_MS tBTA_DM_BLE_IDLE_TIME_MS;
+typedef tBTM_BLE_ENERGY_USED tBTA_DM_BLE_ENERGY_USED;
+
+#define BTA_DM_CONTRL_UNKNOWN 0 /* Unknown state */
+#define BTA_DM_CONTRL_ACTIVE 1 /* ACL link on, SCO link ongoing, sniff mode */
+#define BTA_DM_CONTRL_SCAN \
+ 2 /* Scan state - paging/inquiry/trying to \
+ connect*/
+#define BTA_DM_CONTRL_IDLE \
+ 3 /* Idle state - page scan, LE advt, inquiry scan \
+ */
+
+typedef uint8_t tBTA_DM_CONTRL_STATE;
+
+typedef uint8_t tBTA_DM_BLE_ADV_STATE;
+typedef uint8_t tBTA_DM_BLE_ADV_INFO_PRESENT;
+typedef uint8_t tBTA_DM_BLE_RSSI_VALUE;
+typedef uint16_t tBTA_DM_BLE_ADV_INFO_TIMESTAMP;
+
+typedef void(tBTA_BLE_ENERGY_INFO_CBACK)(tBTA_DM_BLE_TX_TIME_MS tx_time,
+ tBTA_DM_BLE_RX_TIME_MS rx_time,
+ tBTA_DM_BLE_IDLE_TIME_MS idle_time,
+ tBTA_DM_BLE_ENERGY_USED energy_used,
+ tBTA_DM_CONTRL_STATE ctrl_state,
+ tBTA_STATUS status);
+
+/* Maximum service name length */
+#define BTA_SERVICE_NAME_LEN 35
+#define BTA_SERVICE_DESP_LEN BTA_SERVICE_NAME_LEN
+#define BTA_PROVIDER_NAME_LEN BTA_SERVICE_NAME_LEN
+
+/* link policy masks */
+#define BTA_DM_LP_SWITCH HCI_ENABLE_MASTER_SLAVE_SWITCH
+#define BTA_DM_LP_HOLD HCI_ENABLE_HOLD_MODE
+#define BTA_DM_LP_SNIFF HCI_ENABLE_SNIFF_MODE
+#define BTA_DM_LP_PARK HCI_ENABLE_PARK_MODE
+typedef uint16_t tBTA_DM_LP_MASK;
+
+/* power mode actions */
+#define BTA_DM_PM_NO_ACTION 0x00 /* no change to the current pm setting */
+#define BTA_DM_PM_PARK 0x10 /* prefers park mode */
+#define BTA_DM_PM_SNIFF 0x20 /* prefers sniff mode */
+#define BTA_DM_PM_SNIFF1 0x21 /* prefers sniff1 mode */
+#define BTA_DM_PM_SNIFF2 0x22 /* prefers sniff2 mode */
+#define BTA_DM_PM_SNIFF3 0x23 /* prefers sniff3 mode */
+#define BTA_DM_PM_SNIFF4 0x24 /* prefers sniff4 mode */
+#define BTA_DM_PM_SNIFF5 0x25 /* prefers sniff5 mode */
+#define BTA_DM_PM_SNIFF6 0x26 /* prefers sniff6 mode */
+#define BTA_DM_PM_SNIFF7 0x27 /* prefers sniff7 mode */
+#define BTA_DM_PM_SNIFF_USER0 \
+ 0x28 /* prefers user-defined sniff0 mode (testtool only) */
+#define BTA_DM_PM_SNIFF_USER1 \
+ 0x29 /* prefers user-defined sniff1 mode (testtool only) */
+#define BTA_DM_PM_ACTIVE 0x40 /* prefers active mode */
+#define BTA_DM_PM_RETRY 0x80 /* retry power mode based on current settings */
+#define BTA_DM_PM_SUSPEND 0x04 /* prefers suspend mode */
+#define BTA_DM_PM_NO_PREF \
+ 0x01 /* service has no prefernce on power mode setting. eg. connection to \
+ service got closed */
+
+typedef uint8_t tBTA_DM_PM_ACTION;
+
+/* index to bta_dm_ssr_spec */
+#define BTA_DM_PM_SSR0 0
+#define BTA_DM_PM_SSR1 \
+ 1 /* BTA_DM_PM_SSR1 will be dedicated for \
+ HH SSR setting entry, no other profile can use it */
+#define BTA_DM_PM_SSR2 2
+#define BTA_DM_PM_SSR3 3
+#define BTA_DM_PM_SSR4 4
+#define BTA_DM_PM_SSR5 5
+#define BTA_DM_PM_SSR6 6
+
+#define BTA_DM_PM_NUM_EVTS 9
+
+#ifndef BTA_DM_PM_PARK_IDX
+#define BTA_DM_PM_PARK_IDX \
+ 5 /* the actual index to bta_dm_pm_md[] for PARK mode */
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_A2DP_IDX
+#define BTA_DM_PM_SNIFF_A2DP_IDX BTA_DM_PM_SNIFF
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HD_IDLE_IDX
+#define BTA_DM_PM_SNIFF_HD_IDLE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_SCO_OPEN_IDX
+#define BTA_DM_PM_SNIFF_SCO_OPEN_IDX BTA_DM_PM_SNIFF3
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HD_ACTIVE_IDX
+#define BTA_DM_PM_SNIFF_HD_ACTIVE_IDX BTA_DM_PM_SNIFF4
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_OPEN_IDX
+#define BTA_DM_PM_SNIFF_HH_OPEN_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_ACTIVE_IDX
+#define BTA_DM_PM_SNIFF_HH_ACTIVE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_SNIFF_HH_IDLE_IDX
+#define BTA_DM_PM_SNIFF_HH_IDLE_IDX BTA_DM_PM_SNIFF2
+#endif
+
+#ifndef BTA_DM_PM_HH_OPEN_DELAY
+#define BTA_DM_PM_HH_OPEN_DELAY 30000
+#endif
+
+#ifndef BTA_DM_PM_HH_ACTIVE_DELAY
+#define BTA_DM_PM_HH_ACTIVE_DELAY 30000
+#endif
+
+#ifndef BTA_DM_PM_HH_IDLE_DELAY
+#define BTA_DM_PM_HH_IDLE_DELAY 30000
+#endif
+
+/* The Sniff Parameters defined below must be ordered from highest
+ * latency (biggest interval) to lowest latency. If there is a conflict
+ * among the connected services the setting with the lowest latency will
+ * be selected. If a device should override a sniff parameter then it
+ * must insure that order is maintained.
+ */
+#ifndef BTA_DM_PM_SNIFF_MAX
+#define BTA_DM_PM_SNIFF_MAX 800
+#define BTA_DM_PM_SNIFF_MIN 400
+#define BTA_DM_PM_SNIFF_ATTEMPT 4
+#define BTA_DM_PM_SNIFF_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF1_MAX
+#define BTA_DM_PM_SNIFF1_MAX 400
+#define BTA_DM_PM_SNIFF1_MIN 200
+#define BTA_DM_PM_SNIFF1_ATTEMPT 4
+#define BTA_DM_PM_SNIFF1_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF2_MAX
+#define BTA_DM_PM_SNIFF2_MAX 54
+#define BTA_DM_PM_SNIFF2_MIN 30
+#define BTA_DM_PM_SNIFF2_ATTEMPT 4
+#define BTA_DM_PM_SNIFF2_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF3_MAX
+#define BTA_DM_PM_SNIFF3_MAX 150
+#define BTA_DM_PM_SNIFF3_MIN 50
+#define BTA_DM_PM_SNIFF3_ATTEMPT 4
+#define BTA_DM_PM_SNIFF3_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF4_MAX
+#define BTA_DM_PM_SNIFF4_MAX 18
+#define BTA_DM_PM_SNIFF4_MIN 10
+#define BTA_DM_PM_SNIFF4_ATTEMPT 4
+#define BTA_DM_PM_SNIFF4_TIMEOUT 1
+#endif
+
+#ifndef BTA_DM_PM_SNIFF5_MAX
+#define BTA_DM_PM_SNIFF5_MAX 36
+#define BTA_DM_PM_SNIFF5_MIN 30
+#define BTA_DM_PM_SNIFF5_ATTEMPT 2
+#define BTA_DM_PM_SNIFF5_TIMEOUT 0
+#endif
+
+#ifndef BTA_DM_PM_PARK_MAX
+#define BTA_DM_PM_PARK_MAX 800
+#define BTA_DM_PM_PARK_MIN 400
+#define BTA_DM_PM_PARK_ATTEMPT 0
+#define BTA_DM_PM_PARK_TIMEOUT 0
+#endif
+
+/* Switch callback events */
+#define BTA_DM_SWITCH_CMPL_EVT 0 /* Completion of the Switch API */
+
+typedef uint8_t tBTA_DM_SWITCH_EVT;
+typedef void(tBTA_DM_SWITCH_CBACK)(tBTA_DM_SWITCH_EVT event,
+ tBTA_STATUS status);
+
+/* Audio routing out configuration */
+#define BTA_DM_ROUTE_NONE 0x00 /* No Audio output */
+#define BTA_DM_ROUTE_DAC 0x01 /* routing over analog output */
+#define BTA_DM_ROUTE_I2S 0x02 /* routing over digital (I2S) output */
+#define BTA_DM_ROUTE_BT_MONO 0x04 /* routing over SCO */
+#define BTA_DM_ROUTE_BT_STEREO 0x08 /* routing over BT Stereo */
+#define BTA_DM_ROUTE_HOST 0x10 /* routing over Host */
+#define BTA_DM_ROUTE_FMTX 0x20 /* routing over FMTX */
+#define BTA_DM_ROUTE_FMRX 0x40 /* routing over FMRX */
+#define BTA_DM_ROUTE_BTSNK 0x80 /* routing over BT SNK */
+
+typedef uint8_t tBTA_DM_ROUTE_PATH;
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef tSDP_DI_RECORD tBTA_DI_RECORD;
+/* Used to get the DI record */
+typedef tSDP_DI_GET_RECORD tBTA_DI_GET_RECORD;
+/* SDP discovery database */
+typedef tSDP_DISCOVERY_DB tBTA_DISCOVERY_DB;
+
+#ifndef BTA_DI_NUM_MAX
+#define BTA_DI_NUM_MAX 3
+#endif
+
+/* Device features mask definitions */
+#define BTA_FEATURE_BYTES_PER_PAGE BTM_FEATURE_BYTES_PER_PAGE
+#define BTA_EXT_FEATURES_PAGE_MAX BTM_EXT_FEATURES_PAGE_MAX
+/* ACL type
+*/
+#define BTA_DM_LINK_TYPE_BR_EDR 0x01
+#define BTA_DM_LINK_TYPE_LE 0x02
+#define BTA_DM_LINK_TYPE_ALL 0xFF
+typedef uint8_t tBTA_DM_LINK_TYPE;
+
+#define IMMEDIATE_DELY_MODE 0x00
+#define ONFOUND_DELY_MODE 0x01
+#define BATCH_DELY_MODE 0x02
+#define ALLOW_ALL_FILTER 0x00
+#define LOWEST_RSSI_VALUE 129
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_EnableBluetooth
+ *
+ * Description This function initializes BTA and prepares BTA and the
+ * Bluetooth protocol stack for use. This function is
+ * typically called at startup or when Bluetooth services
+ * are required by the phone. This function must be called
+ * before calling any other API function.
+ *
+ *
+ * Returns BTA_SUCCESS if successful.
+ * BTA_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_DisableBluetooth
+ *
+ * Description This function disables BTA and the Bluetooth protocol
+ * stack. It is called when BTA is no longer being used
+ * by any application in the system.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DisableBluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_EnableTestMode
+ *
+ * Description Enables bluetooth device under test mode
+ *
+ *
+ * Returns tBTA_STATUS
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_EnableTestMode(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_DisableTestMode
+ *
+ * Description Disable bluetooth device under test mode
+ *
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_DisableTestMode(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetDeviceName
+ *
+ * Description This function sets the Bluetooth name of the local device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetDeviceName(char* p_name);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetVisibility
+ *
+ * Description This function sets the Bluetooth connectable,discoverable,
+ * pairable and conn paired only modesmodes of the local
+ * device.
+ * This controls whether other Bluetooth devices can find and
+ * connect to the local device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode,
+ uint8_t pairable_mode, uint8_t conn_filter);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearch
+ *
+ * Description This function searches for peer Bluetooth devices. It
+ * first performs an inquiry; for each device found from the
+ * inquiry it gets the remote name of the device. If
+ * parameter services is nonzero, service discovery will be
+ * performed on each device for the services specified.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearchCancel
+ *
+ * Description This function cancels a search that has been initiated
+ * by calling BTA_DmSearch().
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearchCancel(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscover
+ *
+ * Description This function performs service discovery for the services
+ * of a particular peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscover(BD_ADDR bd_addr, tBTA_SERVICE_MASK services,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverUUID
+ *
+ * Description This function performs service discovery for the services
+ * of a particular peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverUUID(BD_ADDR bd_addr, tSDP_UUID* uuid,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmGetCachedRemoteName
+ *
+ * Description Retieve cached remote name if available
+ *
+ * Returns BTA_SUCCESS if cached name was retrieved
+ * BTA_FAILURE if cached name is not available
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_DmGetCachedRemoteName(BD_ADDR remote_device,
+ uint8_t** pp_cached_name);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBond
+ *
+ * Description This function initiates a bonding procedure with a peer
+ * device. The bonding procedure enables authentication
+ * and optionally encryption on the Bluetooth link.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBond(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBondByTransport
+ *
+ * Description This function initiates a bonding procedure with a peer
+ * device by designated transport. The bonding procedure
+ * enables authentication and optionally encryption on the
+ * Bluetooth link.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBondByTransport(BD_ADDR bd_addr, tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBondCancel
+ *
+ * Description This function cancels a bonding procedure with a peer
+ * device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBondCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmPinReply
+ *
+ * Description This function provides a PIN when one is requested by DM
+ * during a bonding procedure. The application should call
+ * this function after the security callback is called with
+ * a BTA_DM_PIN_REQ_EVT.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmPinReply(BD_ADDR bd_addr, bool accept, uint8_t pin_len,
+ uint8_t* p_pin);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmLocalOob
+ *
+ * Description This function retrieves the OOB data from local controller.
+ * The result is reported by bta_dm_co_loc_oob().
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmLocalOob(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmConfirm
+ *
+ * Description This function accepts or rejects the numerical value of the
+ * Simple Pairing process on BTA_DM_SP_CFM_REQ_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmConfirm(BD_ADDR bd_addr, bool accept);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddDevice
+ *
+ * Description This function adds a device to the security database list
+ * of peer devices. This function would typically be called
+ * at system startup to initialize the security database with
+ * known peer devices. This is a direct execution function
+ * that may lock task scheduling on some platforms.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ LINK_KEY link_key, tBTA_SERVICE_MASK trusted_mask,
+ bool is_trusted, uint8_t key_type,
+ tBTA_IO_CAP io_cap, uint8_t pin_length);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmRemoveDevice
+ *
+ * Description This function removes a device from the security database.
+ * This is a direct execution function that may lock task
+ * scheduling on some platforms.
+ *
+ *
+ * Returns BTA_SUCCESS if successful.
+ * BTA_FAIL if operation failed.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DmRemoveDevice(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_GetEirService
+ *
+ * Description This function is called to get BTA service mask from EIR.
+ *
+ * Parameters p_eir - pointer of EIR significant part
+ * eir_len - EIR length
+ * p_services - return the BTA service mask
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GetEirService(uint8_t* p_eir, size_t eir_len,
+ tBTA_SERVICE_MASK* p_services);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmGetConnectionState
+ *
+ * Description Returns whether the remote device is currently connected.
+ *
+ * Returns 0 if the device is NOT connected.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_DmGetConnectionState(const BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetLocalDiRecord
+ *
+ * Description This function adds a DI record to the local SDP database.
+ *
+ * Returns BTA_SUCCESS if record set sucessfully, otherwise error code.
+ *
+ ******************************************************************************/
+extern tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info,
+ uint32_t* p_handle);
+
+/*******************************************************************************
+ *
+ *
+ * Function BTA_DmCloseACL
+ *
+ * Description This function force to close an ACL connection and remove
+ the
+ * device from the security database list of known devices.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * remove_dev - remove device or not after link down
+ * transport - which transport to close
+
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void BTA_DmCloseACL(BD_ADDR bd_addr, bool remove_dev,
+ tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function bta_dmexecutecallback
+ *
+ * Description This function will request BTA to execute a call back in the
+ * context of BTU task.
+ * This API was named in lower case because it is only intended
+ * for the internal customers(like BTIF).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dmexecutecallback(tBTA_DM_EXEC_CBACK* p_callback,
+ void* p_param);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function BTA_DmPcmInitSamples
+ *
+ * Description initialize the down sample converter.
+ *
+ * src_sps: original samples per second (source audio data)
+ * (ex. 44100, 48000)
+ * bits: number of bits per pcm sample (16)
+ * n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+extern void BTA_DmPcmInitSamples(uint32_t src_sps, uint32_t bits,
+ uint32_t n_channels);
+
+/*******************************************************************************
+ * Function BTA_DmPcmResample
+ *
+ * Description Down sampling utility to convert higher sampling rate into
+ * 8K/16bits
+ * PCM samples.
+ *
+ * Parameters p_src: pointer to the buffer where the original sampling PCM
+ * are stored.
+ * in_bytes: Length of the input PCM sample buffer in byte.
+ * p_dst: pointer to the buffer which is to be used to store
+ * the converted PCM samples.
+ *
+ *
+ * Returns int32_t: number of samples converted.
+ *
+ ******************************************************************************/
+extern int32_t BTA_DmPcmResample(void* p_src, uint32_t in_bytes, void* p_dst);
+#endif
+
+/* BLE related API functions */
+/*******************************************************************************
+ *
+ * Function BTA_DmBleSecurityGrant
+ *
+ * Description Grant security request access.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * res - security grant status.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSecurityGrant(BD_ADDR bd_addr, tBTA_DM_BLE_SEC_GRANT res);
+
+/**
+ * Set BLE connectable mode to auto connect
+ */
+extern void BTA_DmBleStartAutoConn();
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBlePasskeyReply
+ *
+ * Description Send BLE SMP passkey reply.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * accept - passkey entry sucessful or declined.
+ * passkey - passkey value, must be a 6 digit number,
+ * can be lead by 0.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBlePasskeyReply(BD_ADDR bd_addr, bool accept,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleConfirmReply
+ *
+ * Description Send BLE SMP SC user confirmation reply.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * accept - numbers to compare are the same or
+ * different.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleConfirmReply(BD_ADDR bd_addr, bool accept);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddBleDevice
+ *
+ * Description Add a BLE device. This function will be normally called
+ * during host startup to restore all required information
+ * for a LE device stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * dev_type - Remote device's device type.
+ * addr_type - LE device address type.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddBleDevice(BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type,
+ tBT_DEVICE_TYPE dev_type);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmAddBleKey(BD_ADDR bd_addr, tBTA_LE_KEY_VALUE* p_le_key,
+ tBTA_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetBlePrefConnParams
+ *
+ * Description This function is called to set the preferred connection
+ * parameters when default connection parameter is not desired.
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBlePrefConnParams(const BD_ADDR bd_addr,
+ uint16_t min_conn_int,
+ uint16_t max_conn_int,
+ uint16_t slave_latency,
+ uint16_t supervision_tout);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetBleConnScanParams
+ *
+ * Description This function is called to set scan parameters used in
+ * BLE connection request
+ *
+ * Parameters: scan_interval - scan interval
+ * scan_window - scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSetBleConnScanParams(uint32_t scan_interval,
+ uint32_t scan_window);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSearchExt
+ *
+ * Description This function searches for peer Bluetooth devices. It
+ * performs an inquiry and gets the remote name for devices.
+ * Service discovery is done if services is non zero
+ *
+ * Parameters p_dm_inq: inquiry conditions
+ * services: if service is not empty, service discovery will be
+ * done.
+ * for all GATT based service condition, put
+ * num_uuid, and p_uuid is the pointer to the list of
+ * UUID values.
+ * p_cback: callback functino when search is completed.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmSearchExt(tBTA_DM_INQ* p_dm_inq,
+ tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverExt
+ *
+ * Description This function does service discovery for services of a
+ * peer device. When services.num_uuid is 0, it indicates all
+ * GATT based services are to be searched; other wise a list of
+ * UUID of interested services should be provided through
+ * services.p_uuid.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverExt(BD_ADDR bd_addr,
+ tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmDiscoverByTransport
+ *
+ * Description This function does service discovery on particular transport
+ * for services of a
+ * peer device. When services.num_uuid is 0, it indicates all
+ * GATT based services are to be searched; other wise a list of
+ * UUID of interested services should be provided through
+ * p_services->p_uuid.
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmDiscoverByTransport(BD_ADDR bd_addr,
+ tBTA_SERVICE_MASK_EXT* p_services,
+ tBTA_DM_SEARCH_CBACK* p_cback,
+ bool sdp_search,
+ tBTA_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmSetEncryption
+ *
+ * Description This function is called to ensure that connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - transport of the link to be encruypted
+ * p_callback - Pointer to callback function to indicat the
+ * link encryption status
+ * sec_act - This is the security action to indicate
+ * what kind of BLE security level is required
+ * for the BLE link if BLE is supported
+ * Note: This parameter is ignored for
+ * BR/EDR or if BLE is not supported.
+ *
+ * Returns void
+ *
+ *
+ ******************************************************************************/
+extern void BTA_DmSetEncryption(BD_ADDR bd_addr, tBTA_TRANSPORT transport,
+ tBTA_DM_ENCRYPT_CBACK* p_callback,
+ tBTA_DM_BLE_SEC_ACT sec_act);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleObserve
+ *
+ * Description This procedure keep the device listening for advertising
+ * events from a broadcast device.
+ *
+ * Parameters start: start or stop observe.
+ * duration : Duration of the scan. Continuous scan if 0 is
+ * passed
+ * p_results_cb: Callback to be called with scan results
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleObserve(bool start, uint8_t duration,
+ tBTA_DM_SEARCH_CBACK* p_results_cb);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleConfigLocalPrivacy
+ *
+ * Description Enable/disable privacy on the local device
+ *
+ * Parameters: privacy_enable - enable/disabe privacy on remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleConfigLocalPrivacy(bool privacy_enable);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleEnableRemotePrivacy
+ *
+ * Description Enable/disable privacy on a remote device
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * privacy_enable - enable/disabe privacy on remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleEnableRemotePrivacy(BD_ADDR bd_addr, bool privacy_enable);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleUpdateConnectionParams
+ *
+ * Description Update connection parameters, can only be used when
+ * connection is up.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * min_int - minimum connection interval, [0x0004 ~ 0x4000]
+ * max_int - maximum connection interval, [0x0004 ~ 0x4000]
+ * latency - slave latency [0 ~ 500]
+ * timeout - supervision timeout [0x000a ~ 0xc80]
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleUpdateConnectionParams(const BD_ADDR bd_addr,
+ uint16_t min_int, uint16_t max_int,
+ uint16_t latency, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleSetDataLength
+ *
+ * Description This function is to set maximum LE data packet size
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleSetDataLength(BD_ADDR remote_device,
+ uint16_t tx_data_length);
+
+/*******************************************************************************
+ *
+ * Function BTA_DmBleGetEnergyInfo
+ *
+ * Description This function is called to obtain the energy info
+ *
+ * Parameters p_cmpl_cback - Command complete callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_DmBleGetEnergyInfo(tBTA_BLE_ENERGY_INFO_CBACK* p_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_BrcmInit
+ *
+ * Description This function initializes Broadcom specific VS handler in
+ * BTA
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_VendorInit(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_BrcmCleanup
+ *
+ * Description This function frees up Broadcom specific VS specific dynamic
+ * memory
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_VendorCleanup(void);
+
+#endif /* BTA_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_ar_api.h b/mtkbt/code/bt/bta/include/bta_ar_api.h
new file mode 100755
index 0000000..e3e3735
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_ar_api.h
@@ -0,0 +1,153 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the simulatenous advanced
+ * audio/video streaming (AV) source and sink of BTA, Broadcom's Bluetooth
+ * application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AR_API_H
+#define BTA_AR_API_H
+
+#include "avct_api.h"
+#include "avdt_api.h"
+#include "avrc_api.h"
+#include "bta_av_api.h"
+#include "bta_sys.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* This event signal to AR user that other profile is connected */
+#define BTA_AR_AVDT_CONN_EVT (AVDT_MAX_EVT + 1)
+
+/*******************************************************************************
+ *
+ * Function bta_ar_init
+ *
+ * Description This function is called from bta_sys_init().
+ * to initialize the control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_init(void);
+
+/*******************************************************************************
+ *
+ * Function bta_ar_reg_avdt
+ *
+ * Description This function is called to register to AVDTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_reg_avdt(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback,
+ tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function bta_ar_dereg_avdt
+ *
+ * Description This function is called to de-register from AVDTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function bta_ar_avdt_conn
+ *
+ * Description This function is called to let ar know that some AVDTP
+ * profile is connected for this sys_id.
+ * If the other sys modules started a timer for PENDING_EVT,
+ * the timer can be stopped now.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function bta_ar_reg_avct
+ *
+ * Description This function is called to register to AVCTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_reg_avct(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask,
+ tBTA_SYS_ID sys_id);
+
+/*******************************************************************************
+ *
+ * Function bta_ar_dereg_avct
+ *
+ * Description This function is called to deregister from AVCTP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_ar_dereg_avct(tBTA_SYS_ID sys_id);
+
+/******************************************************************************
+ *
+ * Function bta_ar_reg_avrc
+ *
+ * Description This function is called to register an SDP record for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+extern void bta_ar_reg_avrc(uint16_t service_uuid, const char* p_service_name,
+ const char* p_provider_name, uint16_t categories,
+ tBTA_SYS_ID sys_id, bool browse_supported,
+ uint16_t profile_version);
+
+/******************************************************************************
+ *
+ * Function bta_ar_dereg_avrc
+ *
+ * Description This function is called to de-register/delete an SDP record
+ * for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+extern void bta_ar_dereg_avrc(uint16_t service_uuid, tBTA_SYS_ID sys_id);
+
+/** M: Bug fix for update avrcp version @{ */
+/******************************************************************************
+ *
+ * Function bta_ar_update_avrc_version
+ *
+ * Description This function is called when need update to remote
+ * version update for AVRCP.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+extern void bta_ar_update_avrc_version(uint16_t peer_rc_version, tBTA_SYS_ID sys_id);
+/** @} */
+#endif /* BTA_AR_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_av_api.h b/mtkbt/code/bt/bta/include/bta_av_api.h
new file mode 100755
index 0000000..7bd57f3
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_av_api.h
@@ -0,0 +1,792 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the advanced audio/video streaming
+ * (AV) subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_API_H
+#define BTA_AV_API_H
+
+#include "a2dp_codec_api.h"
+#include "avdt_api.h"
+#include "avrc_api.h"
+#include "bta_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* Set to TRUE if seperate authorization prompt desired for AVCTP besides A2DP
+ * authorization */
+/* Typically FALSE when AVRCP is used in conjunction with A2DP */
+#ifndef BTA_AV_WITH_AVCTP_AUTHORIZATION
+#define BTA_AV_WITH_AVCTP_AUTHORIZATION FALSE
+#endif
+
+/* AV status values */
+#define BTA_AV_SUCCESS 0 /* successful operation */
+#define BTA_AV_FAIL 1 /* generic failure */
+#define BTA_AV_FAIL_SDP 2 /* service not found */
+#define BTA_AV_FAIL_STREAM 3 /* stream connection failed */
+#define BTA_AV_FAIL_RESOURCES 4 /* no resources */
+#define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */
+#define BTA_AV_FAIL_GET_CAP \
+ 6 /* get capability failed due to no SEP availale on the peer */
+
+typedef uint8_t tBTA_AV_STATUS;
+
+/* AV features masks */
+#define BTA_AV_FEAT_RCTG 0x0001 /* remote control target */
+#define BTA_AV_FEAT_RCCT 0x0002 /* remote control controller */
+#define BTA_AV_FEAT_PROTECT 0x0004 /* streaming media contect protection */
+#define BTA_AV_FEAT_VENDOR \
+ 0x0008 /* remote control vendor dependent commands \
+ */
+#define BTA_AV_FEAT_REPORT 0x0020 /* use reporting service for VDP */
+#define BTA_AV_FEAT_METADATA \
+ 0x0040 /* remote control Metadata Transfer command/response */
+#define BTA_AV_FEAT_MULTI_AV \
+ 0x0080 /* use multi-av, if controller supports it */
+#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */
+#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */
+#define BTA_AV_FEAT_ADV_CTRL \
+ 0x0200 /* remote control Advanced Control command/response */
+#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */
+#define BTA_AV_FEAT_ACP_START \
+ 0x0800 /* start stream when 2nd SNK was accepted */
+#define BTA_AV_FEAT_APP_SETTING 0x2000 /* Player app setting support */
+
+/* Internal features */
+#define BTA_AV_FEAT_NO_SCO_SSPD \
+ 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */
+
+typedef uint16_t tBTA_AV_FEAT;
+
+/* AV channel values */
+#define BTA_AV_CHNL_MSK 0xC0
+#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel */
+#define BTA_AV_CHNL_VIDEO 0x80 /* video channel */
+typedef uint8_t tBTA_AV_CHNL;
+
+#define BTA_AV_HNDL_MSK 0x3F
+typedef uint8_t tBTA_AV_HNDL;
+/* handle index to mask */
+#define BTA_AV_HNDL_TO_MSK(h) ((uint8_t)(1 << (h)))
+
+/* maximum number of streams created: 1 for audio, 1 for video */
+#ifndef BTA_AV_NUM_STRS
+#define BTA_AV_NUM_STRS 2
+#endif
+
+#ifndef BTA_AV_MAX_A2DP_MTU
+/*#define BTA_AV_MAX_A2DP_MTU 668 //224 (DM5) * 3 - 4(L2CAP header) */
+#define BTA_AV_MAX_A2DP_MTU 1008
+#endif
+
+#ifndef BTA_AV_MAX_VDP_MTU
+#define BTA_AV_MAX_VDP_MTU 1008
+#endif
+
+/* operation id list for BTA_AvRemoteCmd */
+#define BTA_AV_RC_SELECT AVRC_ID_SELECT /* select */
+#define BTA_AV_RC_UP AVRC_ID_UP /* up */
+#define BTA_AV_RC_DOWN AVRC_ID_DOWN /* down */
+#define BTA_AV_RC_LEFT AVRC_ID_LEFT /* left */
+#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT /* right */
+#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP /* right-up */
+#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */
+#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP /* left-up */
+#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN /* left-down */
+#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU /* root menu */
+#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */
+#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU /* contents menu */
+#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU /* favorite menu */
+#define BTA_AV_RC_EXIT AVRC_ID_EXIT /* exit */
+#define BTA_AV_RC_0 AVRC_ID_0 /* 0 */
+#define BTA_AV_RC_1 AVRC_ID_1 /* 1 */
+#define BTA_AV_RC_2 AVRC_ID_2 /* 2 */
+#define BTA_AV_RC_3 AVRC_ID_3 /* 3 */
+#define BTA_AV_RC_4 AVRC_ID_4 /* 4 */
+#define BTA_AV_RC_5 AVRC_ID_5 /* 5 */
+#define BTA_AV_RC_6 AVRC_ID_6 /* 6 */
+#define BTA_AV_RC_7 AVRC_ID_7 /* 7 */
+#define BTA_AV_RC_8 AVRC_ID_8 /* 8 */
+#define BTA_AV_RC_9 AVRC_ID_9 /* 9 */
+#define BTA_AV_RC_DOT AVRC_ID_DOT /* dot */
+#define BTA_AV_RC_ENTER AVRC_ID_ENTER /* enter */
+#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR /* clear */
+#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP /* channel up */
+#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN /* channel down */
+#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN /* previous channel */
+#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL /* sound select */
+#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL /* input select */
+#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO /* display information */
+#define BTA_AV_RC_HELP AVRC_ID_HELP /* help */
+#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP /* page up */
+#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN /* page down */
+#define BTA_AV_RC_POWER AVRC_ID_POWER /* power */
+#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP /* volume up */
+#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN /* volume down */
+#define BTA_AV_RC_MUTE AVRC_ID_MUTE /* mute */
+#define BTA_AV_RC_PLAY AVRC_ID_PLAY /* play */
+#define BTA_AV_RC_STOP AVRC_ID_STOP /* stop */
+#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE /* pause */
+#define BTA_AV_RC_RECORD AVRC_ID_RECORD /* record */
+#define BTA_AV_RC_REWIND AVRC_ID_REWIND /* rewind */
+#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR /* fast forward */
+#define BTA_AV_RC_EJECT AVRC_ID_EJECT /* eject */
+#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD /* forward */
+#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD /* backward */
+#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE /* angle */
+#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT /* subpicture */
+#define BTA_AV_RC_F1 AVRC_ID_F1 /* F1 */
+#define BTA_AV_RC_F2 AVRC_ID_F2 /* F2 */
+#define BTA_AV_RC_F3 AVRC_ID_F3 /* F3 */
+#define BTA_AV_RC_F4 AVRC_ID_F4 /* F4 */
+#define BTA_AV_RC_F5 AVRC_ID_F5 /* F5 */
+#define BTA_AV_VENDOR AVRC_ID_VENDOR /* vendor unique */
+
+typedef uint8_t tBTA_AV_RC;
+
+/* state flag for pass through command */
+#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS /* key pressed */
+#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */
+
+typedef uint8_t tBTA_AV_STATE;
+
+/* command codes for BTA_AvVendorCmd */
+#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL
+#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS
+#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ
+#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF
+#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ
+
+typedef uint8_t tBTA_AV_CMD;
+
+/* response codes for BTA_AvVendorRsp */
+#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL
+#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT
+#define BTA_AV_RSP_REJ AVRC_RSP_REJ
+#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS
+#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL
+#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED
+#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM
+
+typedef uint8_t tBTA_AV_CODE;
+
+/* error codes for BTA_AvProtectRsp */
+#define BTA_AV_ERR_NONE A2DP_SUCCESS /* Success, no error */
+#define BTA_AV_ERR_BAD_STATE \
+ AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */
+#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */
+#define BTA_AV_ERR_BAD_CP_TYPE \
+ A2DP_BAD_CP_TYPE /* The requested Content Protection Type is not supported \
+ */
+#define BTA_AV_ERR_BAD_CP_FORMAT \
+ A2DP_BAD_CP_FORMAT /* The format of Content Protection Data is not correct \
+ */
+
+typedef uint8_t tBTA_AV_ERR;
+
+/* AV callback events */
+#define BTA_AV_ENABLE_EVT 0 /* AV enabled */
+#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */
+#define BTA_AV_OPEN_EVT 2 /* connection opened */
+#define BTA_AV_CLOSE_EVT 3 /* connection closed */
+#define BTA_AV_START_EVT 4 /* stream data transfer started */
+#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */
+#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */
+#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */
+#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */
+#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */
+#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */
+#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */
+#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */
+#define BTA_AV_VENDOR_RSP_EVT \
+ 13 /* vendor dependent remote control response \
+ */
+#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */
+#define BTA_AV_SUSPEND_EVT 15 /* suspend response */
+#define BTA_AV_PENDING_EVT \
+ 16 /* incoming connection pending: \
+ * signal channel is open and stream is \
+ * not open after \
+ * BTA_AV_SIGNALLING_TIMEOUT_MS */
+#define BTA_AV_META_MSG_EVT 17 /* metadata messages */
+#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */
+#define BTA_AV_RC_FEAT_EVT \
+ 19 /* remote control channel peer supported features update */
+#define BTA_AV_SINK_MEDIA_CFG_EVT 20 /* command to configure codec */
+#define BTA_AV_SINK_MEDIA_DATA_EVT 21 /* sending data to Media Task */
+#define BTA_AV_OFFLOAD_START_RSP_EVT 22 /* a2dp offload start response */
+#define BTA_AV_RC_BROWSE_OPEN_EVT 23 /* remote control channel open */
+#define BTA_AV_RC_BROWSE_CLOSE_EVT 24 /* remote control channel closed */
+/* Max BTA event */
+#define BTA_AV_MAX_EVT 25
+
+typedef uint8_t tBTA_AV_EVT;
+
+/* Event associated with BTA_AV_ENABLE_EVT */
+typedef struct { tBTA_AV_FEAT features; } tBTA_AV_ENABLE;
+
+/* Event associated with BTA_AV_REGISTER_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl; /* audio/video */
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream. */
+ uint8_t app_id; /* ID associated with call to BTA_AvRegister() */
+ tBTA_AV_STATUS status;
+} tBTA_AV_REGISTER;
+
+/* data associated with BTA_AV_OPEN_EVT */
+#define BTA_AV_EDR_2MBPS 0x01
+#define BTA_AV_EDR_3MBPS 0x02
+typedef uint8_t tBTA_AV_EDR;
+
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ BD_ADDR bd_addr;
+ tBTA_AV_STATUS status;
+ bool starting;
+ tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */
+ uint8_t sep; /* sep type of peer device */
+} tBTA_AV_OPEN;
+
+/* data associated with BTA_AV_CLOSE_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+} tBTA_AV_CLOSE;
+
+/* data associated with BTA_AV_START_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ tBTA_AV_STATUS status;
+ bool initiator; /* true, if local device initiates the START */
+ bool suspending;
+} tBTA_AV_START;
+
+/* data associated with BTA_AV_SUSPEND_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ bool initiator; /* true, if local device initiates the SUSPEND */
+ tBTA_AV_STATUS status;
+} tBTA_AV_SUSPEND;
+
+/* data associated with BTA_AV_RECONFIG_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ tBTA_AV_STATUS status;
+} tBTA_AV_RECONFIG;
+
+/* data associated with BTA_AV_PROTECT_REQ_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ uint8_t* p_data;
+ uint16_t len;
+} tBTA_AV_PROTECT_REQ;
+
+/* data associated with BTA_AV_PROTECT_RSP_EVT */
+typedef struct {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_HNDL hndl;
+ uint8_t* p_data;
+ uint16_t len;
+ tBTA_AV_ERR err_code;
+} tBTA_AV_PROTECT_RSP;
+
+/* data associated with BTA_AV_RC_OPEN_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ tBTA_AV_FEAT peer_features;
+ BD_ADDR peer_addr;
+ tBTA_AV_STATUS status;
+} tBTA_AV_RC_OPEN;
+
+/* data associated with BTA_AV_RC_CLOSE_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ BD_ADDR peer_addr;
+} tBTA_AV_RC_CLOSE;
+
+/* data associated with BTA_AV_RC_BROWSE_OPEN_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ BD_ADDR peer_addr;
+ tBTA_AV_STATUS status;
+} tBTA_AV_RC_BROWSE_OPEN;
+
+/* data associated with BTA_AV_RC_BROWSE_CLOSE_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ BD_ADDR peer_addr;
+} tBTA_AV_RC_BROWSE_CLOSE;
+
+/* data associated with BTA_AV_RC_FEAT_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ tBTA_AV_FEAT peer_features;
+ BD_ADDR peer_addr;
+} tBTA_AV_RC_FEAT;
+
+/* data associated with BTA_AV_REMOTE_CMD_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ tBTA_AV_RC rc_id;
+ tBTA_AV_STATE key_state;
+ uint8_t len;
+ uint8_t* p_data;
+ tAVRC_HDR hdr; /* Message header. */
+ uint8_t label;
+} tBTA_AV_REMOTE_CMD;
+
+/* data associated with BTA_AV_REMOTE_RSP_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ tBTA_AV_RC rc_id;
+ tBTA_AV_STATE key_state;
+ uint8_t len;
+ uint8_t* p_data;
+ tBTA_AV_CODE rsp_code;
+ uint8_t label;
+} tBTA_AV_REMOTE_RSP;
+
+/* data associated with BTA_AV_VENDOR_CMD_EVT, BTA_AV_VENDOR_RSP_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ uint16_t len; /* Max vendor dependent message is 512 */
+ uint8_t label;
+ tBTA_AV_CODE code;
+ uint32_t company_id;
+ uint8_t* p_data;
+} tBTA_AV_VENDOR;
+
+/* data associated with BTA_AV_META_MSG_EVT */
+typedef struct {
+ uint8_t rc_handle;
+ uint16_t len;
+ uint8_t label;
+ tBTA_AV_CODE code;
+ uint32_t company_id;
+ uint8_t* p_data;
+ tAVRC_MSG* p_msg;
+} tBTA_AV_META_MSG;
+
+/* data associated with BTA_AV_PENDING_EVT */
+typedef struct { BD_ADDR bd_addr; } tBTA_AV_PEND;
+
+/* data associated with BTA_AV_REJECT_EVT */
+typedef struct {
+ BD_ADDR bd_addr;
+ tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the
+ connection. */
+} tBTA_AV_REJECT;
+
+/* union of data associated with AV callback */
+typedef union {
+ tBTA_AV_CHNL chnl;
+ tBTA_AV_ENABLE enable;
+ tBTA_AV_REGISTER registr;
+ tBTA_AV_OPEN open;
+ tBTA_AV_CLOSE close;
+ tBTA_AV_START start;
+ tBTA_AV_PROTECT_REQ protect_req;
+ tBTA_AV_PROTECT_RSP protect_rsp;
+ tBTA_AV_RC_OPEN rc_open;
+ tBTA_AV_RC_CLOSE rc_close;
+ tBTA_AV_RC_BROWSE_OPEN rc_browse_open;
+ tBTA_AV_RC_BROWSE_CLOSE rc_browse_close;
+ tBTA_AV_REMOTE_CMD remote_cmd;
+ tBTA_AV_REMOTE_RSP remote_rsp;
+ tBTA_AV_VENDOR vendor_cmd;
+ tBTA_AV_VENDOR vendor_rsp;
+ tBTA_AV_RECONFIG reconfig;
+ tBTA_AV_SUSPEND suspend;
+ tBTA_AV_PEND pend;
+ tBTA_AV_META_MSG meta_msg;
+ tBTA_AV_REJECT reject;
+ tBTA_AV_RC_FEAT rc_feat;
+ tBTA_AV_STATUS status;
+} tBTA_AV;
+
+typedef struct {
+ uint8_t* codec_info;
+ BD_ADDR bd_addr;
+ ;
+} tBTA_AVK_CONFIG;
+
+/* union of data associated with AV Media callback */
+typedef union {
+ BT_HDR* p_data;
+ tBTA_AVK_CONFIG avk_config;
+} tBTA_AV_MEDIA;
+
+#define BTA_GROUP_NAVI_MSG_OP_DATA_LEN 5
+
+/* AV callback */
+typedef void(tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV* p_data);
+typedef void(tBTA_AV_SINK_DATA_CBACK)(tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data);
+
+/* type for stream state machine action functions */
+typedef void (*tBTA_AV_ACT)(void* p_cb, void* p_data);
+
+/* type for registering VDP */
+typedef void(tBTA_AV_REG)(tAVDT_CS* p_cs, char* p_service_name, void* p_data);
+
+/* AV configuration structure */
+typedef struct {
+ uint32_t company_id; /* AVRCP Company ID */
+ uint16_t avrc_mtu; /* AVRCP MTU at L2CAP for control channel */
+ uint16_t avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */
+ uint16_t avrc_ct_cat; /* AVRCP controller categories */
+ uint16_t avrc_tg_cat; /* AVRCP target categories */
+ uint16_t sig_mtu; /* AVDTP signaling channel MTU at L2CAP */
+ uint16_t audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */
+ const uint16_t*
+ p_audio_flush_to; /* AVDTP audio transport channel flush timeout */
+ uint16_t audio_mqs; /* AVDTP audio channel max data queue size */
+ uint16_t video_mtu; /* AVDTP video transport channel MTU at L2CAP */
+ uint16_t video_flush_to; /* AVDTP video transport channel flush timeout */
+ bool avrc_group; /* true, to accept AVRC 1.3 group nevigation command */
+ uint8_t num_co_ids; /* company id count in p_meta_co_ids */
+ uint8_t num_evt_ids; /* event id count in p_meta_evt_ids */
+ tBTA_AV_CODE
+ rc_pass_rsp; /* the default response code for pass through commands */
+ const uint32_t*
+ p_meta_co_ids; /* the metadata Get Capabilities response for company id */
+ const uint8_t* p_meta_evt_ids; /* the the metadata Get Capabilities response
+ for event id */
+ const tBTA_AV_ACT* p_act_tbl; /* the action function table for VDP stream */
+ tBTA_AV_REG* p_reg; /* action function to register VDP */
+ char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller
+ name */
+ char avrc_target_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP target name*/
+} tBTA_AV_CFG;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_AvEnable
+ *
+ * Description Enable the advanced audio/video service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_AV_ENABLE_EVT. This function must
+ * be called before other function in the AV API are
+ * called.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features,
+ tBTA_AV_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDisable
+ *
+ * Description Disable the advanced audio/video service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRegister
+ *
+ * Description Register the audio or video service to stack. When the
+ * operation is complete the callback function will be
+ * called with a BTA_AV_REGISTER_EVT. This function must
+ * be called before AVDT stream is open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRegister(tBTA_AV_CHNL chnl, const char* p_service_name,
+ uint8_t app_id, tBTA_AV_SINK_DATA_CBACK* p_sink_data_cback,
+ uint16_t service_uuid);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDeregister
+ *
+ * Description Deregister the audio or video service
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDeregister(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOpen
+ *
+ * Description Opens an advanced audio/video connection to a peer device.
+ * When connection is open callback function is called
+ * with a BTA_AV_OPEN_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, bool use_rc,
+ tBTA_SEC sec_mask, uint16_t uuid);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvClose
+ *
+ * Description Close the current streams.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvClose(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvDisconnect
+ *
+ * Description Close the connection to the address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvDisconnect(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvStart
+ *
+ * Description Start audio/video stream data transfer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvStart(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvStop
+ *
+ * Description Stop audio/video stream data transfer.
+ * If suspend is true, this function sends AVDT suspend signal
+ * to the connected peer(s).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvStop(bool suspend);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvReconfig
+ *
+ * Description Reconfigure the audio/video stream.
+ * If suspend is true, this function tries the
+ * suspend/reconfigure procedure first.
+ * If suspend is false or when suspend/reconfigure fails,
+ * this function closes and re-opens the AVDT connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvReconfig(tBTA_AV_HNDL hndl, bool suspend, uint8_t sep_info_idx,
+ uint8_t* p_codec_info, uint8_t num_protect,
+ const uint8_t* p_protect_info);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvProtectReq
+ *
+ * Description Send a content protection request. This function can only
+ * be used if AV is enabled with feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvProtectReq(tBTA_AV_HNDL hndl, uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvProtectRsp
+ *
+ * Description Send a content protection response. This function must
+ * be called if a BTA_AV_PROTECT_REQ_EVT is received.
+ * This function can only be used if AV is enabled with
+ * feature BTA_AV_FEAT_PROTECT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, uint8_t error_code, uint8_t* p_data,
+ uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRemoteCmd
+ *
+ * Description Send a remote control command. This function can only
+ * be used if AV is enabled with feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+ tBTA_AV_STATE key_state);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvRemoteVendorUniqueCmd
+ *
+ * Description Send a remote control command with Vendor Unique rc_id.
+ * This function can only be used if AV is enabled with
+ * feature BTA_AV_FEAT_RCCT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+ tBTA_AV_STATE key_state, uint8_t* p_msg,
+ uint8_t buf_len);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvVendorCmd
+ *
+ * Description Send a vendor dependent remote control command. This
+ * function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_VENDOR.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+ uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvVendorRsp
+ *
+ * Description Send a vendor dependent remote control response.
+ * This function must be called if a BTA_AV_VENDOR_CMD_EVT
+ * is received. This function can only be used if AV is
+ * enabled with feature BTA_AV_FEAT_VENDOR.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ uint8_t* p_data, uint16_t len, uint32_t company_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOpenRc
+ *
+ * Description Open an AVRCP connection toward the device with the
+ * specified handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOpenRc(tBTA_AV_HNDL handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvCloseRc
+ *
+ * Description Close an AVRCP connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvCloseRc(uint8_t rc_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvMetaRsp
+ *
+ * Description Send a Metadata command/response. The message contained
+ * in p_pkt can be composed with AVRC utility functions.
+ * This function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_METADATA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ BT_HDR* p_pkt);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvMetaCmd
+ *
+ * Description Send a Metadata/Advanced Control command. The message
+*contained
+ * in p_pkt can be composed with AVRC utility functions.
+ * This function can only be used if AV is enabled with feature
+ * BTA_AV_FEAT_METADATA.
+ * This message is sent only when the peer supports the TG
+*role.
+*8 The only command makes sense right now is the absolute
+*volume command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+ BT_HDR* p_pkt);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOffloadStart
+ *
+ * Description Request Starting of A2DP Offload.
+ * This function is used to start A2DP offload if vendor lib
+ * has the feature enabled.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStart(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function BTA_AvOffloadStartRsp
+ *
+ * Description Response from vendor library indicating response for
+ * OffloadStart.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_AvOffloadStartRsp(tBTA_AV_HNDL hndl, tBTA_AV_STATUS status);
+
+#endif /* BTA_AV_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_av_ci.h b/mtkbt/code/bt/bta/include/bta_av_ci.h
new file mode 100755
index 0000000..3b68f05
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_av_ci.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for advanced audio/video call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_CI_H
+#define BTA_AV_CI_H
+
+#include "bta_av_api.h"
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_av_ci_src_data_ready
+ *
+ * Description This function sends an event to the AV indicating that
+ * the phone has audio stream data ready to send and AV
+ * should call bta_av_co_audio_src_data_path().
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl);
+
+/*******************************************************************************
+ *
+ * Function bta_av_ci_setconfig
+ *
+ * Description This function must be called in response to function
+ * bta_av_co_audio_setconfig().
+ * Parameter err_code is set to an AVDTP status value;
+ * AVDT_SUCCESS if the codec configuration is ok,
+ * otherwise error.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, uint8_t err_code,
+ uint8_t category, uint8_t num_seid,
+ uint8_t* p_seid, bool recfg_needed,
+ uint8_t avdt_handle);
+
+#endif /* BTA_AV_CI_H */
diff --git a/mtkbt/code/bt/bta/include/bta_av_co.h b/mtkbt/code/bt/bta/include/bta_av_co.h
new file mode 100755
index 0000000..5817e4c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_av_co.h
@@ -0,0 +1,215 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for advanced audio call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AV_CO_H
+#define BTA_AV_CO_H
+
+#include "bta_av_api.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_init
+ *
+ * Description This callout function is executed by AV when it is
+ * started by calling BTA_AvEnable(). This function can be
+ * used by the phone to initialize audio paths or for other
+ * initialization purposes.
+ *
+ *
+ * Returns Stream codec and content protection capabilities info.
+ *
+ ******************************************************************************/
+bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_disc_res
+ *
+ * Description This callout function is executed by AV to report the
+ * number of stream end points (SEP) were found during the
+ * AVDT stream discovery process.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
+ uint8_t num_snk, uint8_t num_src, BD_ADDR addr,
+ uint16_t uuid_local);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_getconfig
+ *
+ * Description This callout function is executed by AV to retrieve the
+ * desired codec and content protection configuration for the
+ * audio stream.
+ *
+ *
+ * Returns Stream codec and content protection configuration info.
+ *
+ ******************************************************************************/
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+ uint8_t* p_sep_info_idx, uint8_t seid,
+ uint8_t* p_num_protect,
+ uint8_t* p_protect_info);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_setconfig
+ *
+ * Description This callout function is executed by AV to set the
+ * codec and content protection configuration of the audio
+ * stream.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
+ uint8_t seid, BD_ADDR addr, uint8_t num_protect,
+ const uint8_t* p_protect_info,
+ uint8_t t_local_sep, uint8_t avdt_handle);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_open
+ *
+ * Description This function is called by AV when the audio stream
+ * connection is opened.
+ * BTA-AV maintains the MTU of A2DP streams.
+ * If this is the 2nd audio stream, mtu is the smaller of the 2
+ * streams.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint16_t mtu);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_close
+ *
+ * Description This function is called by AV when the audio stream
+ * connection is closed.
+ * BTA-AV maintains the MTU of A2DP streams.
+ * When one stream is closed and no other audio stream is open,
+ * mtu is reported as 0.
+ * Otherwise, the MTU remains open is reported.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_close(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_start
+ *
+ * Description This function is called by AV when the audio streaming data
+ * transfer is started.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_start(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+ bool* p_no_rtp_hdr);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_stop
+ *
+ * Description This function is called by AV when the audio streaming data
+ * transfer is stopped.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_stop(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_src_data_path
+ *
+ * Description This function is called to get the next data buffer from
+ * the audio codec
+ *
+ * Returns NULL if data is not ready.
+ * Otherwise, a buffer (BT_HDR*) containing the audio data.
+ *
+ ******************************************************************************/
+void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
+ uint32_t* p_timestamp);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_drop
+ *
+ * Description An Audio packet is dropped. .
+ * It's very likely that the connected headset with this handle
+ * is moved far away. The implementation may want to reduce
+ * the encoder bit rate setting to reduce the packet size.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_drop(tBTA_AV_HNDL hndl);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_delay
+ *
+ * Description This function is called by AV when the audio stream
+ * connection needs to send the initial delay report to the
+ * connected SRC.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay);
+
+/*******************************************************************************
+ *
+ * Function bta_av_co_audio_update_mtu
+ *
+ * Description This function is called by AV when the audio stream
+ * connection MTU needs to be updated.
+ * BTA-AV maintains the MTU of A2DP streams.
+ * If this is the 2nd audio stream, mtu is the smaller of the 2
+ * streams.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_av_co_audio_update_mtu(tBTA_AV_HNDL hndl, uint16_t mtu);
+
+#endif /* BTA_AV_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_closure_api.h b/mtkbt/code/bt/bta/include/bta_closure_api.h
new file mode 100755
index 0000000..8c4e11a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_closure_api.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_CLOSURE_API_H
+#define BTA_CLOSURE_API_H
+
+#include <base/bind.h>
+#include <base/callback_forward.h>
+#include <base/location.h>
+
+/*
+ * This method post a closure for execution on bta thread. Please see
+ * documentation at
+ * https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures
+ * for how to handle dynamic memory ownership/smart pointers with base::Owned(),
+ * base::Passed(), base::ConstRef() and others.
+ */
+void do_in_bta_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task);
+
+#endif /* BTA_CLOSURE_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_dm_api.h b/mtkbt/code/bt/bta/include/bta_dm_api.h
new file mode 100755
index 0000000..5a42f27
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_dm_api.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for device mananger functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_API_H
+#define BTA_DM_API_H
+
+#include "stack/include/bt_types.h"
+
+// Brings connection to active mode
+void bta_dm_pm_active(BD_ADDR peer_addr);
+
+#endif /* BTA_DM_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_dm_ci.h b/mtkbt/code/bt/bta/include/bta_dm_ci.h
new file mode 100755
index 0000000..f6f0abd
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_dm_ci.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for device mananger call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_CI_H
+#define BTA_DM_CI_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_io_req
+ *
+ * Description This function must be called in response to function
+ * bta_dm_co_io_req(), if *p_oob_data is set to BTA_OOB_UNKNOWN
+ * by bta_dm_co_io_req().
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_ci_io_req(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_ci_rmt_oob
+ *
+ * Description This function must be called in response to function
+ * bta_dm_co_rmt_oob() to provide the OOB data associated
+ * with the remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_ci_rmt_oob(bool accept, BD_ADDR bd_addr, BT_OCTET16 c,
+ BT_OCTET16 r);
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_ci_data_ready
+ *
+ * Description This function sends an event to indicating that the phone
+ * has SCO data ready..
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_ci_data_ready(uint16_t event, uint16_t sco_handle);
+
+#endif
diff --git a/mtkbt/code/bt/bta/include/bta_dm_co.h b/mtkbt/code/bt/bta/include/bta_dm_co.h
new file mode 100755
index 0000000..5e7dacd
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_dm_co.h
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for device mananger callout functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_DM_CO_H
+#define BTA_DM_CO_H
+
+#include "bta_sys.h"
+#include "btm_api.h"
+
+#ifndef BTA_SCO_OUT_PKT_SIZE
+#define BTA_SCO_OUT_PKT_SIZE BTM_SCO_DATA_SIZE_MAX
+#endif
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_io_req
+ *
+ * Description This callout function is executed by DM to get IO
+ * capabilities of the local device for the Simple Pairing
+ * process
+ *
+ * Parameters bd_addr - The peer device
+ * *p_io_cap - The local Input/Output capabilities
+ * *p_oob_data - true, if OOB data is available for the peer
+ * device.
+ * *p_auth_req - true, if MITM protection is required.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data,
+ tBTA_AUTH_REQ* p_auth_req, bool is_orig);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_io_rsp
+ *
+ * Description This callout function is executed by DM to report IO
+ * capabilities of the peer device for the Simple Pairing
+ * process
+ *
+ * Parameters bd_addr - The peer device
+ * io_cap - The remote Input/Output capabilities
+ * oob_data - true, if OOB data is available for the peer
+ * device.
+ * auth_req - true, if MITM protection is required.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_lk_upgrade
+ *
+ * Description This callout function is executed by DM to check if the
+ * platform wants allow link key upgrade
+ *
+ * Parameters bd_addr - The peer device
+ * *p_upgrade - true, if link key upgrade is desired.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_lk_upgrade(BD_ADDR bd_addr, bool* p_upgrade);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_loc_oob
+ *
+ * Description This callout function is executed by DM to report the OOB
+ * data of the local device for the Simple Pairing process
+ *
+ * Parameters valid - true, if the local OOB data is retrieved from LM
+ * c - Simple Pairing Hash C
+ * r - Simple Pairing Randomnizer R
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_rmt_oob
+ *
+ * Description This callout function is executed by DM to request the OOB
+ * data for the remote device for the Simple Pairing process
+ *
+ * Parameters bd_addr - The peer device
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_rmt_oob(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_open
+ *
+ * Description This function is executed when a SCO connection is open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size,
+ uint16_t event);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_close
+ *
+ * Description This function is called when a SCO connection is closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_close(void);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_out_data
+ *
+ * Description This function is called to send SCO data over HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_out_data(BT_HDR** p_buf);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_in_data
+ *
+ * Description This function is called to send incoming SCO data to
+ * application.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_dm_sco_co_in_data(BT_HDR* p_buf, tBTM_SCO_DATA_FLAG status);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_ble_io_req
+ *
+ * Description This callout function is executed by DM to get BLE IO
+ * capabilities before SMP pairing gets going.
+ *
+ * Parameters bd_addr - The peer device
+ * *p_io_cap - The local Input/Output capabilities
+ * *p_oob_data - true, if OOB data is available for the peer
+ * device.
+ * *p_auth_req - Auth request setting (Bonding and MITM
+ * required or not)
+ * *p_max_key_size - max key size local device supported.
+ * *p_init_key - initiator keys.
+ * *p_resp_key - responder keys.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data,
+ tBTA_LE_AUTH_REQ* p_auth_req,
+ uint8_t* p_max_key_size,
+ tBTA_LE_KEY_TYPE* p_init_key,
+ tBTA_LE_KEY_TYPE* p_resp_key);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_ble_local_key_reload
+ *
+ * Description This callout function is to load the local BLE keys if
+ * available on the device.
+ *
+ * Parameters none
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_load_local_keys(
+ tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_ble_io_req
+ *
+ * Description This callout function is executed by DM to get BLE IO
+ * capabilities before SMP pairing gets going.
+ *
+ * Parameters bd_addr - The peer device
+ * *p_io_cap - The local Input/Output capabilities
+ * *p_oob_data - true, if OOB data is available for the peer
+ * device.
+ * *p_auth_req - Auth request setting (Bonding and MITM
+ * required or not)
+ * *p_max_key_size - max key size local device supported.
+ * *p_init_key - initiator keys.
+ * *p_resp_key - responder keys.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data,
+ tBTA_LE_AUTH_REQ* p_auth_req,
+ uint8_t* p_max_key_size,
+ tBTA_LE_KEY_TYPE* p_init_key,
+ tBTA_LE_KEY_TYPE* p_resp_key);
+
+#endif /* BTA_DM_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_gatt_api.h b/mtkbt/code/bt/bta/include/bta_gatt_api.h
new file mode 100755
index 0000000..40f274a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_gatt_api.h
@@ -0,0 +1,1168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for BTA GATT.
+ *
+ ******************************************************************************/
+
+#ifndef BTA_GATT_API_H
+#define BTA_GATT_API_H
+
+#include "bta_api.h"
+#include "gatt_api.h"
+#include "osi/include/list.h"
+
+#include <base/callback_forward.h>
+#include <vector>
+
+using std::vector;
+
+#ifndef BTA_GATT_DEBUG
+#define BTA_GATT_DEBUG false
+#endif
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/**************************
+ * Common Definitions
+ **************************/
+/* GATT ID */
+typedef struct {
+ tBT_UUID uuid; /* uuid of the attribute */
+ uint8_t inst_id; /* instance ID */
+} __attribute__((packed)) tBTA_GATT_ID;
+
+/* Success code and error codes */
+#define BTA_GATT_OK GATT_SUCCESS
+#define BTA_GATT_INVALID_HANDLE GATT_INVALID_HANDLE /* 0x0001 */
+#define BTA_GATT_READ_NOT_PERMIT GATT_READ_NOT_PERMIT /* 0x0002 */
+#define BTA_GATT_WRITE_NOT_PERMIT GATT_WRITE_NOT_PERMIT /* 0x0003 */
+#define BTA_GATT_INVALID_PDU GATT_INVALID_PDU /* 0x0004 */
+#define BTA_GATT_INSUF_AUTHENTICATION GATT_INSUF_AUTHENTICATION /* 0x0005 */
+#define BTA_GATT_REQ_NOT_SUPPORTED GATT_REQ_NOT_SUPPORTED /* 0x0006 */
+#define BTA_GATT_INVALID_OFFSET GATT_INVALID_OFFSET /* 0x0007 */
+#define BTA_GATT_INSUF_AUTHORIZATION GATT_INSUF_AUTHORIZATION /* 0x0008 */
+#define BTA_GATT_PREPARE_Q_FULL GATT_PREPARE_Q_FULL /* 0x0009 */
+#define BTA_GATT_NOT_FOUND GATT_NOT_FOUND /* 0x000a */
+#define BTA_GATT_NOT_LONG GATT_NOT_LONG /* 0x000b */
+#define BTA_GATT_INSUF_KEY_SIZE GATT_INSUF_KEY_SIZE /* 0x000c */
+#define BTA_GATT_INVALID_ATTR_LEN GATT_INVALID_ATTR_LEN /* 0x000d */
+#define BTA_GATT_ERR_UNLIKELY GATT_ERR_UNLIKELY /* 0x000e */
+#define BTA_GATT_INSUF_ENCRYPTION GATT_INSUF_ENCRYPTION /* 0x000f */
+#define BTA_GATT_UNSUPPORT_GRP_TYPE GATT_UNSUPPORT_GRP_TYPE /* 0x0010 */
+#define BTA_GATT_INSUF_RESOURCE GATT_INSUF_RESOURCE /* 0x0011 */
+
+#define BTA_GATT_NO_RESOURCES GATT_NO_RESOURCES /* 0x80 */
+#define BTA_GATT_INTERNAL_ERROR GATT_INTERNAL_ERROR /* 0x81 */
+#define BTA_GATT_WRONG_STATE GATT_WRONG_STATE /* 0x82 */
+#define BTA_GATT_DB_FULL GATT_DB_FULL /* 0x83 */
+#define BTA_GATT_BUSY GATT_BUSY /* 0x84 */
+#define BTA_GATT_ERROR GATT_ERROR /* 0x85 */
+#define BTA_GATT_CMD_STARTED GATT_CMD_STARTED /* 0x86 */
+#define BTA_GATT_ILLEGAL_PARAMETER GATT_ILLEGAL_PARAMETER /* 0x87 */
+#define BTA_GATT_PENDING GATT_PENDING /* 0x88 */
+#define BTA_GATT_AUTH_FAIL GATT_AUTH_FAIL /* 0x89 */
+#define BTA_GATT_MORE GATT_MORE /* 0x8a */
+#define BTA_GATT_INVALID_CFG GATT_INVALID_CFG /* 0x8b */
+#define BTA_GATT_SERVICE_STARTED GATT_SERVICE_STARTED /* 0x8c */
+#define BTA_GATT_ENCRYPED_MITM GATT_ENCRYPED_MITM /* GATT_SUCCESS */
+#define BTA_GATT_ENCRYPED_NO_MITM GATT_ENCRYPED_NO_MITM /* 0x8d */
+#define BTA_GATT_NOT_ENCRYPTED GATT_NOT_ENCRYPTED /* 0x8e */
+#define BTA_GATT_CONGESTED GATT_CONGESTED /* 0x8f */
+
+#define BTA_GATT_DUP_REG 0x90 /* 0x90 */
+#define BTA_GATT_ALREADY_OPEN 0x91 /* 0x91 */
+#define BTA_GATT_CANCEL 0x92 /* 0x92 */
+
+/* 0xE0 ~ 0xFC reserved for future use */
+#define BTA_GATT_CCC_CFG_ERR \
+ GATT_CCC_CFG_ERR /* 0xFD Client Characteristic Configuration Descriptor \
+ Improperly Configured */
+#define BTA_GATT_PRC_IN_PROGRESS \
+ GATT_PRC_IN_PROGRESS /* 0xFE Procedure Already in progress */
+#define BTA_GATT_OUT_OF_RANGE \
+ GATT_OUT_OF_RANGE /* 0xFFAttribute value out of range */
+
+typedef uint8_t tBTA_GATT_STATUS;
+
+#define BTA_GATT_INVALID_CONN_ID GATT_INVALID_CONN_ID
+
+/* Client callback function events */
+#define BTA_GATTC_DEREG_EVT 1 /* GATT client deregistered event */
+#define BTA_GATTC_OPEN_EVT 2 /* GATTC open request status event */
+#define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */
+#define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */
+#define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */
+#define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */
+#define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */
+#define BTA_GATTC_ACL_EVT 13 /* ACL up event */
+#define BTA_GATTC_CANCEL_OPEN_EVT 14 /* cancel open event */
+#define BTA_GATTC_SRVC_CHG_EVT 15 /* service change event */
+#define BTA_GATTC_ENC_CMPL_CB_EVT 17 /* encryption complete callback event */
+#define BTA_GATTC_CFG_MTU_EVT 18 /* configure MTU complete event */
+#define BTA_GATTC_CONGEST_EVT 24 /* Congestion event */
+#define BTA_GATTC_PHY_UPDATE_EVT 25 /* PHY change event */
+#define BTA_GATTC_CONN_UPDATE_EVT 26 /* Connection parameters update event */
+
+typedef uint8_t tBTA_GATTC_EVT;
+
+typedef tGATT_IF tBTA_GATTC_IF;
+
+typedef struct {
+ uint16_t unit; /* as UUIUD defined by SIG */
+ uint16_t descr; /* as UUID as defined by SIG */
+ tGATT_FORMAT format;
+ int8_t exp;
+ uint8_t name_spc; /* The name space of the description */
+} tBTA_GATT_CHAR_PRES;
+
+#define BTA_GATT_CLT_CONFIG_NONE GATT_CLT_CONFIG_NONE /* 0x0000 */
+#define BTA_GATT_CLT_CONFIG_NOTIFICATION \
+ GATT_CLT_CONFIG_NOTIFICATION /* 0x0001 */
+#define BTA_GATT_CLT_CONFIG_INDICATION GATT_CLT_CONFIG_INDICATION /* 0x0002 */
+typedef uint16_t tBTA_GATT_CLT_CHAR_CONFIG;
+
+/* characteristic descriptor: server configuration value
+*/
+#define BTA_GATT_SVR_CONFIG_NONE GATT_SVR_CONFIG_NONE /* 0x0000 */
+#define BTA_GATT_SVR_CONFIG_BROADCAST GATT_SVR_CONFIG_BROADCAST /* 0x0001 */
+typedef uint16_t tBTA_GATT_SVR_CHAR_CONFIG;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define BTA_GATT_AGGR_HANDLE_NUM_MAX 10
+typedef struct {
+ uint8_t num_handle;
+ uint16_t handle_list[BTA_GATT_AGGR_HANDLE_NUM_MAX];
+} tBTA_GATT_CHAR_AGGRE;
+typedef tGATT_VALID_RANGE tBTA_GATT_VALID_RANGE;
+
+typedef struct {
+ uint16_t len;
+ uint8_t* p_value;
+} tBTA_GATT_UNFMT;
+
+#define BTA_GATT_MAX_ATTR_LEN GATT_MAX_ATTR_LEN
+
+#define BTA_GATTC_TYPE_WRITE GATT_WRITE
+#define BTA_GATTC_TYPE_WRITE_NO_RSP GATT_WRITE_NO_RSP
+typedef uint8_t tBTA_GATTC_WRITE_TYPE;
+
+#define BTA_GATT_CONN_UNKNOWN 0
+#define BTA_GATT_CONN_L2C_FAILURE \
+ GATT_CONN_L2C_FAILURE /* general l2cap resource failure */
+#define BTA_GATT_CONN_TIMEOUT GATT_CONN_TIMEOUT /* 0x08 connection timeout */
+#define BTA_GATT_CONN_TERMINATE_PEER_USER \
+ GATT_CONN_TERMINATE_PEER_USER /* 0x13 connection terminate by peer user */
+#define BTA_GATT_CONN_TERMINATE_LOCAL_HOST \
+ GATT_CONN_TERMINATE_LOCAL_HOST /* 0x16 connectionterminated by local host */
+#define BTA_GATT_CONN_FAIL_ESTABLISH \
+ GATT_CONN_FAIL_ESTABLISH /* 0x03E connection fail to establish */
+#define BTA_GATT_CONN_LMP_TIMEOUT \
+ GATT_CONN_LMP_TIMEOUT /* 0x22 connection fail for LMP response tout */
+#define BTA_GATT_CONN_CANCEL \
+ GATT_CONN_CANCEL /* 0x0100 L2CAP connection cancelled */
+#define BTA_GATT_CONN_NONE 0x0101 /* 0x0101 no connection to cancel */
+typedef uint16_t tBTA_GATT_REASON;
+
+#define BTA_GATTC_MULTI_MAX GATT_MAX_READ_MULTI_HANDLES
+
+typedef struct {
+ uint8_t num_attr;
+ uint16_t handles[BTA_GATTC_MULTI_MAX];
+} tBTA_GATTC_MULTI;
+
+#define BTA_GATT_AUTH_REQ_NONE GATT_AUTH_REQ_NONE
+#define BTA_GATT_AUTH_REQ_NO_MITM \
+ GATT_AUTH_REQ_NO_MITM /* unauthenticated encryption */
+#define BTA_GATT_AUTH_REQ_MITM \
+ GATT_AUTH_REQ_MITM /* authenticated encryption \
+ */
+#define BTA_GATT_AUTH_REQ_SIGNED_NO_MITM GATT_AUTH_REQ_SIGNED_NO_MITM
+#define BTA_GATT_AUTH_REQ_SIGNED_MITM GATT_AUTH_REQ_SIGNED_MITM
+
+typedef tGATT_AUTH_REQ tBTA_GATT_AUTH_REQ;
+
+enum {
+ BTA_GATTC_ATTR_TYPE_INCL_SRVC,
+ BTA_GATTC_ATTR_TYPE_CHAR,
+ BTA_GATTC_ATTR_TYPE_CHAR_DESCR,
+ BTA_GATTC_ATTR_TYPE_SRVC
+};
+typedef uint8_t tBTA_GATTC_ATTR_TYPE;
+
+typedef struct {
+ tBT_UUID uuid;
+ uint16_t s_handle;
+ uint16_t e_handle; /* used for service only */
+ uint8_t attr_type;
+ uint8_t id;
+ uint8_t prop; /* used when attribute type is characteristic */
+ bool is_primary; /* used when attribute type is service */
+ uint16_t incl_srvc_handle; /* used when attribute type is included service */
+} tBTA_GATTC_NV_ATTR;
+
+/* callback data structure */
+typedef struct {
+ tBTA_GATT_STATUS status;
+ tBTA_GATTC_IF client_if;
+ tBT_UUID app_uuid;
+} tBTA_GATTC_REG;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_STATUS status;
+ uint16_t handle;
+ uint16_t len;
+ uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+} tBTA_GATTC_READ;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_STATUS status;
+ uint16_t handle;
+} tBTA_GATTC_WRITE;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTC_EXEC_CMPL;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTC_SEARCH_CMPL;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_ID service_uuid;
+} tBTA_GATTC_SRVC_RES;
+
+typedef struct {
+ uint16_t conn_id;
+ tBTA_GATT_STATUS status;
+ uint16_t mtu;
+} tBTA_GATTC_CFG_MTU;
+
+typedef struct {
+ tBTA_GATT_STATUS status;
+ uint16_t conn_id;
+ tBTA_GATTC_IF client_if;
+ BD_ADDR remote_bda;
+ tBTA_TRANSPORT transport;
+ uint16_t mtu;
+} tBTA_GATTC_OPEN;
+
+typedef struct {
+ tBTA_GATT_STATUS status;
+ uint16_t conn_id;
+ tBTA_GATTC_IF client_if;
+ BD_ADDR remote_bda;
+ tBTA_GATT_REASON reason; /* disconnect reason code, not useful when connect
+ event is reported */
+} tBTA_GATTC_CLOSE;
+
+typedef struct {
+ uint16_t conn_id;
+ BD_ADDR bda;
+ uint16_t handle;
+ uint16_t len;
+ uint8_t value[BTA_GATT_MAX_ATTR_LEN];
+ bool is_notify;
+} tBTA_GATTC_NOTIFY;
+
+typedef struct {
+ uint16_t conn_id;
+ bool congested; /* congestion indicator */
+} tBTA_GATTC_CONGEST;
+
+typedef struct {
+ tBTA_GATT_STATUS status;
+ tBTA_GATTC_IF client_if;
+ uint16_t conn_id;
+ BD_ADDR remote_bda;
+} tBTA_GATTC_OPEN_CLOSE;
+
+typedef struct {
+ tBTA_GATTC_IF client_if;
+ BD_ADDR remote_bda;
+} tBTA_GATTC_ENC_CMPL_CB;
+
+typedef struct {
+ tBTA_GATTC_IF server_if;
+ uint16_t conn_id;
+ uint8_t tx_phy;
+ uint8_t rx_phy;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTC_PHY_UPDATE;
+
+typedef struct {
+ tBTA_GATTC_IF server_if;
+ uint16_t conn_id;
+ uint16_t interval;
+ uint16_t latency;
+ uint16_t timeout;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTC_CONN_UPDATE;
+
+typedef union {
+ tBTA_GATT_STATUS status;
+
+ tBTA_GATTC_SEARCH_CMPL search_cmpl; /* discovery complete */
+ tBTA_GATTC_SRVC_RES srvc_res; /* discovery result */
+ tBTA_GATTC_REG reg_oper; /* registration data */
+ tBTA_GATTC_OPEN open;
+ tBTA_GATTC_CLOSE close;
+ tBTA_GATTC_READ read; /* read attribute/descriptor data */
+ tBTA_GATTC_WRITE write; /* write complete data */
+ tBTA_GATTC_EXEC_CMPL exec_cmpl; /* execute complete */
+ tBTA_GATTC_NOTIFY notify; /* notification/indication event data */
+ tBTA_GATTC_ENC_CMPL_CB enc_cmpl;
+ BD_ADDR remote_bda; /* service change event */
+ tBTA_GATTC_CFG_MTU cfg_mtu; /* configure MTU operation */
+ tBTA_GATTC_CONGEST congest;
+ tBTA_GATTC_PHY_UPDATE phy_update;
+ tBTA_GATTC_CONN_UPDATE conn_update;
+} tBTA_GATTC;
+
+/* GATTC enable callback function */
+typedef void(tBTA_GATTC_ENB_CBACK)(tBTA_GATT_STATUS status);
+
+/* Client callback function */
+typedef void(tBTA_GATTC_CBACK)(tBTA_GATTC_EVT event, tBTA_GATTC* p_data);
+
+/* GATT Server Data Structure */
+/* Server callback function events */
+#define BTA_GATTS_REG_EVT 0
+#define BTA_GATTS_READ_CHARACTERISTIC_EVT \
+ GATTS_REQ_TYPE_READ_CHARACTERISTIC /* 1 */
+#define BTA_GATTS_READ_DESCRIPTOR_EVT GATTS_REQ_TYPE_READ_DESCRIPTOR /* 2 */
+#define BTA_GATTS_WRITE_CHARACTERISTIC_EVT \
+ GATTS_REQ_TYPE_WRITE_CHARACTERISTIC /* 3 */
+#define BTA_GATTS_WRITE_DESCRIPTOR_EVT GATTS_REQ_TYPE_WRITE_DESCRIPTOR /* 4 */
+#define BTA_GATTS_EXEC_WRITE_EVT GATTS_REQ_TYPE_WRITE_EXEC /* 5 */
+#define BTA_GATTS_MTU_EVT GATTS_REQ_TYPE_MTU /* 6 */
+#define BTA_GATTS_CONF_EVT GATTS_REQ_TYPE_CONF /* 7 */
+#define BTA_GATTS_DEREG_EVT 8
+#define BTA_GATTS_DELELTE_EVT 11
+#define BTA_GATTS_STOP_EVT 13
+#define BTA_GATTS_CONNECT_EVT 14
+#define BTA_GATTS_DISCONNECT_EVT 15
+#define BTA_GATTS_OPEN_EVT 16
+#define BTA_GATTS_CANCEL_OPEN_EVT 17
+#define BTA_GATTS_CLOSE_EVT 18
+#define BTA_GATTS_CONGEST_EVT 20
+#define BTA_GATTS_PHY_UPDATE_EVT 21
+#define BTA_GATTS_CONN_UPDATE_EVT 22
+
+typedef uint8_t tBTA_GATTS_EVT;
+typedef tGATT_IF tBTA_GATTS_IF;
+
+/* Attribute permissions
+*/
+#define BTA_GATT_PERM_READ GATT_PERM_READ /* bit 0 - 0x0001 */
+#define BTA_GATT_PERM_READ_ENCRYPTED \
+ GATT_PERM_READ_ENCRYPTED /* bit 1 - 0x0002 */
+#define BTA_GATT_PERM_READ_ENC_MITM \
+ GATT_PERM_READ_ENC_MITM /* bit 2 - 0x0004 */
+#define BTA_GATT_PERM_WRITE GATT_PERM_WRITE /* bit 4 - 0x0010 */
+#define BTA_GATT_PERM_WRITE_ENCRYPTED \
+ GATT_PERM_WRITE_ENCRYPTED /* bit 5 - 0x0020 */
+#define BTA_GATT_PERM_WRITE_ENC_MITM \
+ GATT_PERM_WRITE_ENC_MITM /* bit 6 - 0x0040 */
+#define BTA_GATT_PERM_WRITE_SIGNED \
+ GATT_PERM_WRITE_SIGNED /* bit 7 - 0x0080 \
+ */
+#define BTA_GATT_PERM_WRITE_SIGNED_MITM \
+ GATT_PERM_WRITE_SIGNED_MITM /* bit 8 - 0x0100 */
+typedef uint16_t tBTA_GATT_PERM;
+
+#define BTA_GATTS_INVALID_APP 0xff
+
+#define BTA_GATTS_INVALID_IF 0
+
+/* definition of characteristic properties */
+#define BTA_GATT_CHAR_PROP_BIT_BROADCAST \
+ GATT_CHAR_PROP_BIT_BROADCAST /* 0x01 \
+ */
+#define BTA_GATT_CHAR_PROP_BIT_READ GATT_CHAR_PROP_BIT_READ /* 0x02 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE_NR GATT_CHAR_PROP_BIT_WRITE_NR /* 0x04 */
+#define BTA_GATT_CHAR_PROP_BIT_WRITE GATT_CHAR_PROP_BIT_WRITE /* 0x08 */
+#define BTA_GATT_CHAR_PROP_BIT_NOTIFY GATT_CHAR_PROP_BIT_NOTIFY /* 0x10 */
+#define BTA_GATT_CHAR_PROP_BIT_INDICATE GATT_CHAR_PROP_BIT_INDICATE /* 0x20 */
+#define BTA_GATT_CHAR_PROP_BIT_AUTH GATT_CHAR_PROP_BIT_AUTH /* 0x40 */
+#define BTA_GATT_CHAR_PROP_BIT_EXT_PROP GATT_CHAR_PROP_BIT_EXT_PROP /* 0x80 */
+typedef uint8_t tBTA_GATT_CHAR_PROP;
+
+#ifndef BTA_GATTC_CHAR_DESCR_MAX
+#define BTA_GATTC_CHAR_DESCR_MAX 7
+#endif
+
+/*********************** NV callback Data Definitions **********************
+*/
+typedef struct {
+ tBT_UUID app_uuid128;
+ tBT_UUID svc_uuid;
+ uint16_t svc_inst;
+ uint16_t s_handle;
+ uint16_t e_handle;
+ bool is_primary; /* primary service or secondary */
+} tBTA_GATTS_HNDL_RANGE;
+
+#define BTA_GATTS_SRV_CHG_CMD_ADD_CLIENT GATTS_SRV_CHG_CMD_ADD_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_UPDATE_CLIENT GATTS_SRV_CHG_CMD_UPDATE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_REMOVE_CLIENT GATTS_SRV_CHG_CMD_REMOVE_CLIENT
+#define BTA_GATTS_SRV_CHG_CMD_READ_NUM_CLENTS GATTS_SRV_CHG_CMD_READ_NUM_CLENTS
+#define BTA_GATTS_SRV_CHG_CMD_READ_CLENT GATTS_SRV_CHG_CMD_READ_CLENT
+typedef tGATTS_SRV_CHG_CMD tBTA_GATTS_SRV_CHG_CMD;
+
+typedef tGATTS_SRV_CHG tBTA_GATTS_SRV_CHG;
+typedef tGATTS_SRV_CHG_REQ tBTA_GATTS_SRV_CHG_REQ;
+typedef tGATTS_SRV_CHG_RSP tBTA_GATTS_SRV_CHG_RSP;
+
+#define BTA_GATT_TRANSPORT_LE GATT_TRANSPORT_LE
+#define BTA_GATT_TRANSPORT_BR_EDR GATT_TRANSPORT_BR_EDR
+#define BTA_GATT_TRANSPORT_LE_BR_EDR GATT_TRANSPORT_LE_BR_EDR
+typedef uint8_t tBTA_GATT_TRANSPORT;
+
+/* attribute value */
+typedef tGATT_VALUE tBTA_GATT_VALUE;
+
+/* attribute response data */
+typedef tGATTS_RSP tBTA_GATTS_RSP;
+
+/* attribute request data from the client */
+#define BTA_GATT_PREP_WRITE_CANCEL 0x00
+#define BTA_GATT_PREP_WRITE_EXEC 0x01
+typedef tGATT_EXEC_FLAG tBTA_GATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef tGATT_READ_REQ tTA_GBATT_READ_REQ;
+
+/* write request data */
+typedef tGATT_WRITE_REQ tBTA_GATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef tGATTS_DATA tBTA_GATTS_REQ_DATA;
+
+typedef struct {
+ tBTA_GATT_STATUS status;
+ BD_ADDR remote_bda;
+ uint32_t trans_id;
+ uint16_t conn_id;
+ tBTA_GATTS_REQ_DATA* p_data;
+} tBTA_GATTS_REQ;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ tBTA_GATT_STATUS status;
+ tBT_UUID uuid;
+} tBTA_GATTS_REG_OPER;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ uint16_t service_id;
+ uint16_t svc_instance;
+ bool is_primary;
+ tBTA_GATT_STATUS status;
+ tBT_UUID uuid;
+} tBTA_GATTS_CREATE;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ uint16_t service_id;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTS_SRVC_OPER;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ BD_ADDR remote_bda;
+ uint16_t conn_id;
+ tBTA_GATT_REASON reason; /* report disconnect reason */
+ tBTA_GATT_TRANSPORT transport;
+} tBTA_GATTS_CONN;
+
+typedef struct {
+ uint16_t conn_id;
+ bool congested; /* report channel congestion indicator */
+} tBTA_GATTS_CONGEST;
+
+typedef struct {
+ uint16_t conn_id; /* connection ID */
+ tBTA_GATT_STATUS status; /* notification/indication status */
+} tBTA_GATTS_CONF;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ uint16_t conn_id;
+ uint8_t tx_phy;
+ uint8_t rx_phy;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTS_PHY_UPDATE;
+
+typedef struct {
+ tBTA_GATTS_IF server_if;
+ uint16_t conn_id;
+ uint16_t interval;
+ uint16_t latency;
+ uint16_t timeout;
+ tBTA_GATT_STATUS status;
+} tBTA_GATTS_CONN_UPDATE;
+
+/* GATTS callback data */
+typedef union {
+ tBTA_GATTS_REG_OPER reg_oper;
+ tBTA_GATTS_CREATE create;
+ tBTA_GATTS_SRVC_OPER srvc_oper;
+ tBTA_GATT_STATUS status; /* BTA_GATTS_LISTEN_EVT */
+ tBTA_GATTS_REQ req_data;
+ tBTA_GATTS_CONN conn; /* BTA_GATTS_CONN_EVT */
+ tBTA_GATTS_CONGEST congest; /* BTA_GATTS_CONGEST_EVT callback data */
+ tBTA_GATTS_CONF confirm; /* BTA_GATTS_CONF_EVT callback data */
+ tBTA_GATTS_PHY_UPDATE phy_update; /* BTA_GATTS_PHY_UPDATE_EVT callback data */
+ tBTA_GATTS_CONN_UPDATE
+ conn_update; /* BTA_GATTS_CONN_UPDATE_EVT callback data */
+} tBTA_GATTS;
+
+/* GATTS enable callback function */
+typedef void(tBTA_GATTS_ENB_CBACK)(tBTA_GATT_STATUS status);
+
+/* Server callback function */
+typedef void(tBTA_GATTS_CBACK)(tBTA_GATTS_EVT event, tBTA_GATTS* p_data);
+
+typedef struct {
+ tBT_UUID uuid;
+ bool is_primary;
+ uint16_t handle;
+ uint16_t s_handle;
+ uint16_t e_handle;
+ list_t* characteristics; /* list of tBTA_GATTC_CHARACTERISTIC */
+ list_t* included_svc; /* list of tBTA_GATTC_INCLUDED_SVC */
+} __attribute__((packed, aligned(alignof(tBT_UUID)))) tBTA_GATTC_SERVICE;
+
+typedef struct {
+ tBT_UUID uuid;
+ uint16_t handle;
+ tBTA_GATT_CHAR_PROP properties;
+ tBTA_GATTC_SERVICE* service; /* owning service*/
+ list_t* descriptors; /* list of tBTA_GATTC_DESCRIPTOR */
+} __attribute__((packed, aligned(alignof(tBT_UUID)))) tBTA_GATTC_CHARACTERISTIC;
+
+typedef struct {
+ tBT_UUID uuid;
+ uint16_t handle;
+ tBTA_GATTC_CHARACTERISTIC* characteristic; /* owning characteristic */
+} __attribute__((packed)) tBTA_GATTC_DESCRIPTOR;
+
+typedef struct {
+ tBT_UUID uuid;
+ uint16_t handle;
+ tBTA_GATTC_SERVICE* owning_service; /* owning service*/
+ tBTA_GATTC_SERVICE* included_service;
+} __attribute__((packed)) tBTA_GATTC_INCLUDED_SVC;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/**************************
+ * Client Functions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Disable
+ *
+ * Description This function is called to disable the GATTC module
+ *
+ * Parameters None.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Disable(void);
+
+using BtaAppRegisterCallback =
+ base::Callback<void(uint8_t /* app_id */, uint8_t /* status */)>;
+
+/**
+ * This function is called to register application callbacks with BTA GATTC
+ *module.
+ * p_client_cb - pointer to the application callback function.
+ **/
+extern void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
+ BtaAppRegisterCallback cb);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_AppDeregister
+ *
+ * Description This function is called to deregister an application
+ * from BTA GATTC module.
+ *
+ * Parameters client_if - client interface identifier.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_AppDeregister(tBTA_GATTC_IF client_if);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Open
+ *
+ * Description Open a direct connection or add a background auto connection
+ * bd address
+ *
+ * Parameters client_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ * initiating_phys: LE PHY to use, optional
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ bool is_direct, tBTA_GATT_TRANSPORT transport,
+ bool opportunistic);
+extern void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ bool is_direct, tBTA_GATT_TRANSPORT transport,
+ bool opportunistic, uint8_t initiating_phys);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_CancelOpen
+ *
+ * Description Open a direct connection or add a background auto connection
+ * bd address
+ *
+ * Parameters client_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_CancelOpen(tBTA_GATTC_IF client_if, BD_ADDR remote_bda,
+ bool is_direct);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Close
+ *
+ * Description Close a connection to a GATT server.
+ *
+ * Parameters conn_id: connectino ID to be closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Close(uint16_t conn_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ServiceSearchRequest
+ *
+ * Description This function is called to request a GATT service discovery
+ * on a GATT server. This function report service search result
+ * by a callback event, and followed by a service search
+ * complete event.
+ *
+ * Parameters conn_id: connection ID.
+ * p_srvc_uuid: a UUID of the service application is interested
+ * in. If Null, discover for all services.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ServiceSearchRequest(uint16_t conn_id,
+ tBT_UUID* p_srvc_uuid);
+
+/**
+ * This function is called to send "Find service by UUID" request. Used only for
+ * PTS tests.
+ */
+extern void BTA_GATTC_DiscoverServiceByUuid(uint16_t conn_id,
+ tBT_UUID* p_srvc_uuid);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetServices
+ *
+ * Description This function is called to find the services on the given
+ * server.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ *
+ * Returns returns list_t of tBTA_GATTC_SERVICE or NULL.
+ *
+ ******************************************************************************/
+extern const list_t* BTA_GATTC_GetServices(uint16_t conn_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetCharacteristic
+ *
+ * Description This function is called to find the characteristic on the
+ * given server.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ * handle: characteristic handle
+ *
+ * Returns returns pointer to tBTA_GATTC_CHARACTERISTIC or NULL.
+ *
+ ******************************************************************************/
+extern const tBTA_GATTC_CHARACTERISTIC* BTA_GATTC_GetCharacteristic(
+ uint16_t conn_id, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetDescriptor
+ *
+ * Description This function is called to find the characteristic on the
+ * given server.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ * handle: descriptor handle
+ *
+ * Returns returns pointer to tBTA_GATTC_DESCRIPTOR or NULL.
+ *
+ ******************************************************************************/
+extern const tBTA_GATTC_DESCRIPTOR* BTA_GATTC_GetDescriptor(uint16_t conn_id,
+ uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_GetGattDb
+ *
+ * Description This function is called to get gatt db.
+ *
+ * Parameters conn_id: connection ID which identify the server.
+ * db: output parameter which will contain gatt db copy.
+ * Caller is responsible for freeing it.
+ * count: number of elements in db.
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_GetGattDb(uint16_t conn_id, uint16_t start_handle,
+ uint16_t end_handle, btgatt_db_element_t** db,
+ int* count);
+
+typedef void (*GATT_READ_OP_CB)(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data);
+typedef void (*GATT_WRITE_OP_CB)(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, void* data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadCharacteristic
+ *
+ * Description This function is called to read a characteristics value
+ *
+ * Parameters conn_id - connectino ID.
+ * handle - characteritic handle to read.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharacteristic(uint16_t conn_id, uint16_t handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data);
+
+/**
+ * This function is called to read a value of characteristic with uuid equal to
+ * |uuid|
+ */
+void BTA_GATTC_ReadUsingCharUuid(uint16_t conn_id, tBT_UUID uuid,
+ uint16_t s_handle, uint16_t e_handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadCharDescr
+ *
+ * Description This function is called to read a descriptor value.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - descriptor handle to read.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_ReadCharDescr(uint16_t conn_id, uint16_t handle,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_READ_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_WriteCharValue
+ *
+ * Description This function is called to write characteristic value.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - characteristic handle to write.
+ * write_type - type of write.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharValue(uint16_t conn_id, uint16_t handle,
+ tBTA_GATTC_WRITE_TYPE write_type,
+ vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_WriteCharDescr
+ *
+ * Description This function is called to write descriptor value.
+ *
+ * Parameters conn_id - connection ID
+ * handle - descriptor handle to write.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTA_GATTC_WriteCharDescr(uint16_t conn_id, uint16_t handle,
+ vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_SendIndConfirm
+ *
+ * Description This function is called to send handle value confirmation.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - characteristic handle to confirm.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_SendIndConfirm(uint16_t conn_id, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_RegisterForNotifications
+ *
+ * Description This function is called to register for notification of a
+ * service.
+ *
+ * Parameters client_if - client interface.
+ * remote_bda - target GATT server.
+ * handle - GATT characteristic handle.
+ *
+ * Returns OK if registration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+extern tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications(
+ tBTA_GATTC_IF client_if, const BD_ADDR remote_bda, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_DeregisterForNotifications
+ *
+ * Description This function is called to de-register for notification of a
+ * service.
+ *
+ * Parameters client_if - client interface.
+ * remote_bda - target GATT server.
+ * handle - GATT characteristic handle.
+ *
+ * Returns OK if deregistration succeed, otherwise failed.
+ *
+ ******************************************************************************/
+extern tBTA_GATT_STATUS BTA_GATTC_DeregisterForNotifications(
+ tBTA_GATTC_IF client_if, const BD_ADDR remote_bda, uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_PrepareWrite
+ *
+ * Description This function is called to prepare write a characteristic
+ * value.
+ *
+ * Parameters conn_id - connection ID.
+ * handle - GATT characteritic handle.
+ * offset - offset of the write value.
+ * value - the value to be written.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_PrepareWrite(uint16_t conn_id, uint16_t handle,
+ uint16_t offset, vector<uint8_t> value,
+ tBTA_GATT_AUTH_REQ auth_req,
+ GATT_WRITE_OP_CB callback, void* cb_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ExecuteWrite
+ *
+ * Description This function is called to execute write a prepare write
+ * sequence.
+ *
+ * Parameters conn_id - connection ID.
+ * is_execute - execute or cancel.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ReadMultiple
+ *
+ * Description This function is called to read multiple characteristic or
+ * characteristic descriptors.
+ *
+ * Parameters conn_id - connectino ID.
+ * p_read_multi - read multiple parameters.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ReadMultiple(uint16_t conn_id,
+ tBTA_GATTC_MULTI* p_read_multi,
+ tBTA_GATT_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_Refresh
+ *
+ * Description Refresh the server cache of the remote device
+ *
+ * Parameters remote_bda: remote device BD address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_Refresh(const BD_ADDR remote_bda);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTC_ConfigureMTU
+ *
+ * Description Configure the MTU size in the GATT channel. This can be done
+ * only once per connection.
+ *
+ * Parameters conn_id: connection ID.
+ * mtu: desired MTU size to use.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu);
+
+/*******************************************************************************
+ * BTA GATT Server API
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Init
+ *
+ * Description This function is called to initalize GATTS module
+ *
+ * Parameters None
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Init();
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Disable
+ *
+ * Description This function is called to disable GATTS module
+ *
+ * Parameters None.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Disable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AppRegister
+ *
+ * Description This function is called to register application callbacks
+ * with BTA GATTS module.
+ *
+ * Parameters p_app_uuid - applicaiton UUID
+ * p_cback - pointer to the application callback function.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_AppRegister(tBT_UUID* p_app_uuid,
+ tBTA_GATTS_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AppDeregister
+ *
+ * Description De-register with BTA GATT Server.
+ *
+ * Parameters server_if: server interface
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_AppDeregister(tBTA_GATTS_IF server_if);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AddService
+ *
+ * Description Add the given |service| and all included elements to the
+ * GATT database. a |BTA_GATTS_ADD_SRVC_EVT| is triggered to
+ * report the status and attribute handles.
+ *
+ * Parameters server_if: server interface.
+ * service: pointer to vector describing service.
+ *
+ * Returns Returns |BTA_GATT_OK| on success or |BTA_GATT_ERROR| if the
+ * service cannot be added.
+ *
+ ******************************************************************************/
+extern uint16_t BTA_GATTS_AddService(tBTA_GATTS_IF server_if,
+ vector<btgatt_db_element_t>& service);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_DeleteService
+ *
+ * Description This function is called to delete a service. When this is
+ * done, a callback event BTA_GATTS_DELETE_EVT is report with
+ * the status.
+ *
+ * Parameters service_id: service_id to be deleted.
+ *
+ * Returns returns none.
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_DeleteService(uint16_t service_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_StopService
+ *
+ * Description This function is called to stop a service.
+ *
+ * Parameters service_id - service to be topped.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_StopService(uint16_t service_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_HandleValueIndication
+ *
+ * Description This function is called to read a characteristics
+ * descriptor.
+ *
+ * Parameters conn_id - connection identifier.
+ * attr_id - attribute ID to indicate.
+ * value - data to indicate.
+ * need_confirm - if this indication expects a confirmation or
+ * not.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_id,
+ vector<uint8_t> value,
+ bool need_confirm);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_SendRsp
+ *
+ * Description This function is called to send a response to a request.
+ *
+ * Parameters conn_id - connection identifier.
+ * trans_id - transaction ID.
+ * status - response status
+ * p_msg - response data.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+ tBTA_GATT_STATUS status, tBTA_GATTS_RSP* p_msg);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Open
+ *
+ * Description Open a direct open connection or add a background auto
+ * connection bd address
+ *
+ * Parameters server_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Open(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+ bool is_direct, tBTA_GATT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_CancelOpen
+ *
+ * Description Cancel a direct open connection or remove a background auto
+ * connection bd address
+ *
+ * Parameters server_if: server interface.
+ * remote_bda: remote device BD address.
+ * is_direct: direct connection or background auto connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_CancelOpen(tBTA_GATTS_IF server_if, BD_ADDR remote_bda,
+ bool is_direct);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_Close
+ *
+ * Description Close a connection a remote device.
+ *
+ * Parameters conn_id: connectino ID to be closed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_GATTS_Close(uint16_t conn_id);
+
+#endif /* BTA_GATT_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_gatts_co.h b/mtkbt/code/bt/bta/include/bta_gatts_co.h
new file mode 100755
index 0000000..bf8277f
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_gatts_co.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2010-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for BTA GATT server call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_GATTS_CO_H
+#define BTA_GATTS_CO_H
+
+#include "bta_gatt_api.h"
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_update_handle_range
+ *
+ * Description This callout function is executed by GATTS when a GATT
+ * server handle range ios to be added or removed.
+ *
+ * Parameter is_add: true is to add a handle range; otherwise is to
+ * delete.
+ * p_hndl_range: handle range.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_gatts_co_update_handle_range(
+ bool is_add, tBTA_GATTS_HNDL_RANGE* p_hndl_range);
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_srv_chg
+ *
+ * Description This call-out is to read/write/remove service change related
+ * informaiton. The request consists of the cmd and p_req and
+ * the response is returned in p_rsp
+ *
+ * Parameter cmd - request command
+ * p_req - request paramters
+ * p_rsp - response data for the request
+ *
+ * Returns true - if the request is processed successfully and
+ * the response is returned in p_rsp.
+ * false - if the request can not be processed
+ *
+ ******************************************************************************/
+extern bool bta_gatts_co_srv_chg(tBTA_GATTS_SRV_CHG_CMD cmd,
+ tBTA_GATTS_SRV_CHG_REQ* p_req,
+ tBTA_GATTS_SRV_CHG_RSP* p_rsp);
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_load_handle_range
+ *
+ * Description This callout function is executed by GATTS when a GATT
+ * server handle range is requested to be loaded from NV.
+ *
+ * Parameter
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern bool bta_gatts_co_load_handle_range(uint8_t index,
+ tBTA_GATTS_HNDL_RANGE* p_handle);
+
+#endif /* BTA_GATTS_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hd_api.h b/mtkbt/code/bt/bta/include/bta_hd_api.h
new file mode 100755
index 0000000..8dcca7c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hd_api.h
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef BTA_HD_API_H
+#define BTA_HD_API_H
+
+#include "bta_api.h"
+#include "hidd_api.h"
+
+/*****************************************************************************
+ * Constants and Type Definitions
+ ****************************************************************************/
+#ifndef BTA_HD_DEBUG
+#define BTA_HD_DEBUG FALSE
+#endif
+
+/* BTA HID Device callback events */
+#define BTA_HD_ENABLE_EVT 0 /* BT-HD enabled */
+#define BTA_HD_DISABLE_EVT 1 /* BT-HD disabled */
+#define BTA_HD_REGISTER_APP_EVT 2 /* application registered */
+#define BTA_HD_UNREGISTER_APP_EVT 3 /* application unregistered */
+#define BTA_HD_OPEN_EVT 4 /* connection to host opened */
+#define BTA_HD_CLOSE_EVT 5 /* connection to host closed */
+#define BTA_HD_GET_REPORT_EVT 6 /* GET_REPORT request from host */
+#define BTA_HD_SET_REPORT_EVT 7 /* SET_REPORT request from host */
+#define BTA_HD_SET_PROTOCOL_EVT 8 /* SET_PROTOCOL request from host */
+#define BTA_HD_INTR_DATA_EVT 9 /* DATA received from host on intr */
+#define BTA_HD_VC_UNPLUG_EVT 10 /* Virtual Cable Unplug */
+#define BTA_HD_CONN_STATE_EVT 11 /* Report connection state change */
+#define BTA_HD_API_ERR_EVT 99 /* BT-HD API error */
+
+typedef uint16_t tBTA_HD_EVT;
+
+enum { BTA_HD_OK, BTA_HD_ERROR };
+typedef uint8_t tBTA_HD_STATUS;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HD_DEV_DESCR;
+
+typedef struct {
+ char* p_name;
+ char* p_description;
+ char* p_provider;
+ uint8_t subclass;
+ tBTA_HD_DEV_DESCR descriptor;
+} tBTA_HD_APP_INFO;
+
+typedef struct {
+ uint8_t service_type;
+ uint32_t token_rate;
+ uint32_t token_bucket_size;
+ uint32_t peak_bandwidth;
+ uint32_t access_latency;
+ uint32_t delay_variation;
+} tBTA_HD_QOS_INFO;
+
+typedef struct {
+ bool use_intr;
+ uint8_t type;
+ uint8_t id;
+ uint16_t len;
+ uint8_t* p_data;
+} tBTA_HD_REPORT;
+
+typedef struct {
+ tBTA_HD_STATUS status;
+ bool in_use;
+ BD_ADDR bda;
+} tBTA_HD_REG_STATUS;
+
+typedef struct {
+ BD_ADDR bda;
+ tBTA_HD_STATUS status;
+} tBTA_HD_CONN;
+
+typedef struct {
+ uint8_t report_type;
+ uint8_t report_id;
+ uint16_t buffer_size;
+} tBTA_HD_GET_REPORT;
+
+typedef struct {
+ uint8_t report_type;
+ uint8_t report_id;
+ uint16_t len;
+ uint8_t* p_data;
+} tBTA_HD_SET_REPORT;
+
+typedef uint8_t tBTA_HD_SET_PROTOCOL;
+
+typedef struct {
+ uint8_t report_id;
+ uint16_t len;
+ uint8_t* p_data;
+} tBTA_HD_INTR_DATA;
+
+/* union of data associated with HD callback */
+typedef union {
+ tBTA_HD_STATUS status; /* BTA_HD_ENABLE_EVT
+ BTA_HD_DISABLE_EVT
+ BTA_HD_UNREGISTER_APP_EVT */
+ tBTA_HD_REG_STATUS reg_status; /* BTA_HD_REGISTER_APP_EVT */
+ tBTA_HD_CONN conn; /* BTA_HD_OPEN_EVT
+ BTA_HD_CLOSE_EVT
+ BTA_HD_VC_UNPLUG_EVT
+ BTA_HD_OWN_VC_UNPLUG_EVT */
+ tBTA_HD_GET_REPORT get_report; /* BTA_HD_GET_REPORT */
+ tBTA_HD_SET_REPORT set_report; /* BTA_HD_SET_REPORT */
+ tBTA_HD_SET_PROTOCOL set_protocol; /* BTA_HD_SETPROTOCOL */
+ tBTA_HD_INTR_DATA intr_data; /* BTA_HD_INTR_DATA_EVT */
+} tBTA_HD;
+
+/* BTA HD callback function */
+typedef void(tBTA_HD_CBACK)(tBTA_HD_EVT event, tBTA_HD* p_data);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function BTA_HhRegister
+ *
+ * Description This function enable HID host and registers HID-Host with
+ * lower layers.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdEnable(tBTA_HD_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhDeregister
+ *
+ * Description This function is called when the host is about power down.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdRegisterApp
+ *
+ * Description This function is called when application should be
+*registered
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdRegisterApp(tBTA_HD_APP_INFO* p_app_info,
+ tBTA_HD_QOS_INFO* p_in_qos,
+ tBTA_HD_QOS_INFO* p_out_qos);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdUnregisterApp
+ *
+ * Description This function is called when application should be
+*unregistered
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdUnregisterApp(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdSendReport
+ *
+ * Description This function is called when report is to be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdSendReport(tBTA_HD_REPORT* p_report);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdVirtualCableUnplug
+ *
+ * Description This function is called when VCU shall be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdVirtualCableUnplug(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdConnect
+ *
+ * Description This function is called when connection to host shall be
+ * made
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdConnect(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdDisconnect
+ *
+ * Description This function is called when host shall be disconnected
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdDisconnect(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdAddDevice
+ *
+ * Description This function is called when a device is virtually cabled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdAddDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdRemoveDevice
+ *
+ * Description This function is called when a device is virtually uncabled
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdRemoveDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_HdReportError
+ *
+ * Description This function is called when reporting error for set report
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HdReportError(uint8_t error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BTA_HD_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hf_client_api.h b/mtkbt/code/bt/bta/include/bta_hf_client_api.h
new file mode 100755
index 0000000..10db4ec
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hf_client_api.h
@@ -0,0 +1,372 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the handsfree (HF role) subsystem
+ *
+ ******************************************************************************/
+#ifndef BTA_HF_CLIENT_API_H
+#define BTA_HF_CLIENT_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/* HFP peer (AG) features*/
+#define BTA_HF_CLIENT_PEER_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_HF_CLIENT_PEER_FEAT_ECNR \
+ 0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_PEER_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTA_HF_CLIENT_PEER_INBAND 0x00000008 /* In-band ring tone */
+#define BTA_HF_CLIENT_PEER_VTAG \
+ 0x00000010 /* Attach a phone number to a voice tag */
+#define BTA_HF_CLIENT_PEER_REJECT \
+ 0x00000020 /* Ability to reject incoming call */
+#define BTA_HF_CLIENT_PEER_ECS 0x00000040 /* Enhanced Call Status */
+#define BTA_HF_CLIENT_PEER_ECC 0x00000080 /* Enhanced Call Control */
+#define BTA_HF_CLIENT_PEER_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_HF_CLIENT_PEER_CODEC 0x00000200 /* Codec Negotiation */
+
+typedef uint16_t tBTA_HF_CLIENT_PEER_FEAT;
+
+/* HFP HF features */
+#define BTA_HF_CLIENT_FEAT_ECNR \
+ 0x00000001 /* Echo cancellation and/or noise reduction */
+#define BTA_HF_CLIENT_FEAT_3WAY \
+ 0x00000002 /* Call waiting and three-way calling */
+#define BTA_HF_CLIENT_FEAT_CLI \
+ 0x00000004 /* Caller ID presentation capability */
+#define BTA_HF_CLIENT_FEAT_VREC 0x00000008 /* Voice recognition activation */
+#define BTA_HF_CLIENT_FEAT_VOL 0x00000010 /* Remote volume control */
+#define BTA_HF_CLIENT_FEAT_ECS 0x00000020 /* Enhanced Call Status */
+#define BTA_HF_CLIENT_FEAT_ECC 0x00000040 /* Enhanced Call Control */
+#define BTA_HF_CLIENT_FEAT_CODEC 0x00000080 /* Codec Negotiation */
+
+/* HFP HF extended call handling - masks not related to any spec */
+#define BTA_HF_CLIENT_CHLD_REL \
+ 0x00000001 /* 0 Release waiting call or held calls */
+#define BTA_HF_CLIENT_CHLD_REL_ACC \
+ 0x00000002 /* 1 Release active calls and accept other (waiting or held) cal \
+ */
+#define BTA_HF_CLIENT_CHLD_REL_X 0x00000004 /* 1x Release x call*/
+#define BTA_HF_CLIENT_CHLD_HOLD_ACC \
+ 0x00000008 /* 2 Active calls on hold and accept other call */
+#define BTA_HF_CLIENT_CHLD_PRIV_X \
+ 0x00000010 /* 2x Active multiparty call on hold except call x */
+#define BTA_HF_CLIENT_CHLD_MERGE \
+ 0x00000020 /* 3 Add held call to multiparty \
+ */
+#define BTA_HF_CLIENT_CHLD_MERGE_DETACH \
+ 0x00000040 /* 4 Add held call to multiparty */
+
+typedef uint16_t tBTA_HF_CLIENT_CHLD_FEAT;
+
+/* HFP AG errors ot OK sent to HF Unit */
+#define BTA_HF_CLIENT_AT_RESULT_OK 0
+#define BTA_HF_CLIENT_AT_RESULT_ERROR 1
+#define BTA_HF_CLIENT_AT_RESULT_NO_CARRIER 2
+#define BTA_HF_CLIENT_AT_RESULT_BUSY 3
+#define BTA_HF_CLIENT_AT_RESULT_NO_ANSWER 4
+#define BTA_HF_CLIENT_AT_RESULT_DELAY 5
+#define BTA_HF_CLIENT_AT_RESULT_BLACKLISTED 6
+#define BTA_HF_CLIENT_AT_RESULT_CME 7
+
+typedef uint8_t tBTA_HF_CLIENT_AT_RESULT_TYPE;
+
+/* HF Client callback events */
+#define BTA_HF_CLIENT_ENABLE_EVT 0 /* HF Client enabled */
+#define BTA_HF_CLIENT_REGISTER_EVT 1 /* HF Client registered */
+#define BTA_HF_CLIENT_OPEN_EVT 2 /* HF Client connection open */
+#define BTA_HF_CLIENT_CLOSE_EVT 3 /* HF Client connection closed */
+#define BTA_HF_CLIENT_CONN_EVT 4 /* Service level connection opened */
+#define BTA_HF_CLIENT_AUDIO_OPEN_EVT 5 /* Audio connection open */
+#define BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT \
+ 6 /* Audio connection with mSBC codec open */
+#define BTA_HF_CLIENT_AUDIO_CLOSE_EVT 7 /* Audio connection closed */
+#define BTA_HF_CLIENT_SPK_EVT 8 /* Speaker volume changed */
+#define BTA_HF_CLIENT_MIC_EVT 9 /* Microphone volume changed */
+#define BTA_HF_CLIENT_IND_EVT 10 /* Indicator */
+#define BTA_HF_CLIENT_VOICE_REC_EVT \
+ 11 /* AG changed voice recognition setting */
+#define BTA_HF_CLIENT_OPERATOR_NAME_EVT 12 /* Operator name acquired */
+#define BTA_HF_CLIENT_CLIP_EVT 13 /* Calling line identification event */
+#define BTA_HF_CLIENT_CCWA_EVT 14 /* Call waiting notification */
+#define BTA_HF_CLIENT_AT_RESULT_EVT 15 /* Call waiting notification */
+#define BTA_HF_CLIENT_CLCC_EVT 16 /* current call event */
+#define BTA_HF_CLIENT_CNUM_EVT 17 /* subscriber information event */
+#define BTA_HF_CLIENT_BTRH_EVT 18 /* bluetooth response and hold event */
+#define BTA_HF_CLIENT_BSIR_EVT \
+ 19 /* in-band ring tone setting changed event \
+ */
+#define BTA_HF_CLIENT_BINP_EVT 20 /* binp number event */
+#define BTA_HF_CLIENT_RING_INDICATION 21 /* HF Client ring indication */
+#define BTA_HF_CLIENT_DISABLE_EVT 30 /* HF Client disabled */
+
+typedef uint8_t tBTA_HF_CLIENT_EVT;
+
+/* HF Client open status */
+#define BTA_HF_CLIENT_SUCCESS 0 /* Connection successfully opened */
+#define BTA_HF_CLIENT_FAIL_SDP 1 /* Open failed due to SDP */
+#define BTA_HF_CLIENT_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
+#define BTA_HF_CLIENT_FAIL_RESOURCES 3 /* out of resources failure */
+
+typedef uint8_t tBTA_HF_CLIENT_STATUS;
+
+/* indicator type */
+#define BTA_HF_CLIENT_IND_BATTCH 0 /* Battery charge indicator */
+#define BTA_HF_CLIENT_IND_SIGNAL 1 /* Signal Strength indicator */
+#define BTA_HF_CLIENT_IND_SERVICE 2 /* Service availability indicator */
+#define BTA_HF_CLIENT_IND_CALL 3 /* Standard call status indicator*/
+#define BTA_HF_CLIENT_IND_ROAM 4 /* Roaming status indicator */
+#define BTA_HF_CLIENT_IND_CALLSETUP 5 /* Call setup status indicator */
+#define BTA_HF_CLIENT_IND_CALLHELD 6 /* Call hold status indicator */
+
+typedef uint8_t tBTA_HF_CLIENT_IND_TYPE;
+
+/* AT commands */
+#define BTA_HF_CLIENT_AT_CMD_VTS 0
+#define BTA_HF_CLIENT_AT_CMD_BTRH 1
+#define BTA_HF_CLIENT_AT_CMD_CHUP 2
+#define BTA_HF_CLIENT_AT_CMD_CHLD 3
+#define BTA_HF_CLIENT_AT_CMD_BCC 4
+#define BTA_HF_CLIENT_AT_CMD_CNUM 5
+#define BTA_HF_CLIENT_AT_CMD_ATA 6
+#define BTA_HF_CLIENT_AT_CMD_COPS 7
+#define BTA_HF_CLIENT_AT_CMD_ATD 8
+#define BTA_HF_CLIENT_AT_CMD_VGM 9
+#define BTA_HF_CLIENT_AT_CMD_VGS 10
+#define BTA_HF_CLIENT_AT_CMD_BVRA 11
+#define BTA_HF_CLIENT_AT_CMD_CLCC 12
+#define BTA_HF_CLIENT_AT_CMD_BINP 13
+#define BTA_HF_CLIENT_AT_CMD_BLDN 14
+#define BTA_HF_CLIENT_AT_CMD_NREC 15
+
+typedef uint8_t tBTA_HF_CLIENT_AT_CMD_TYPE;
+
+/* data associated with BTA_HF_CLIENT_REGISTER_EVT */
+typedef struct {
+ BD_ADDR bd_addr;
+ tBTA_HF_CLIENT_STATUS status;
+} tBTA_HF_CLIENT_REGISTER;
+
+/* data associated with BTA_HF_CLIENT_OPEN_EVT */
+typedef struct {
+ BD_ADDR bd_addr;
+ uint16_t handle; // Handle for client control block
+ tBTA_HF_CLIENT_STATUS status;
+} tBTA_HF_CLIENT_OPEN;
+
+/* data associated with BTA_HF_CLIENT_CONN_EVT */
+typedef struct {
+ BD_ADDR bd_addr;
+ tBTA_HF_CLIENT_PEER_FEAT peer_feat;
+ tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
+} tBTA_HF_CLIENT_CONN;
+
+/* data associated with BTA_HF_CLIENT_IND_EVT event */
+typedef struct {
+ BD_ADDR bd_addr;
+ tBTA_HF_CLIENT_IND_TYPE type;
+ uint16_t value;
+} tBTA_HF_CLIENT_IND;
+
+/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */
+#define BTA_HF_CLIENT_OPERATOR_NAME_LEN 16
+typedef struct {
+ BD_ADDR bd_addr;
+ char name[BTA_HF_CLIENT_OPERATOR_NAME_LEN + 1];
+} tBTA_HF_CLIENT_OPERATOR_NAME;
+
+/* data associated with BTA_HF_CLIENT_CLIP_EVT and BTA_HF_CLIENT_CCWA_EVT*/
+#define BTA_HF_CLIENT_NUMBER_LEN 32
+typedef struct {
+ BD_ADDR bd_addr;
+ char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_NUMBER;
+
+/* data associated with BTA_HF_CLIENT_AT_RESULT_EVT event */
+typedef struct {
+ BD_ADDR bd_addr;
+ tBTA_HF_CLIENT_AT_RESULT_TYPE type;
+ uint16_t cme;
+} tBTA_HF_CLIENT_AT_RESULT;
+
+/* data associated with BTA_HF_CLIENT_CLCC_EVT event */
+typedef struct {
+ BD_ADDR bd_addr;
+ uint32_t idx;
+ bool inc;
+ uint8_t status;
+ bool mpty;
+ bool number_present;
+ char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CLCC;
+
+/* data associated with BTA_HF_CLIENT_CNUM_EVT event */
+typedef struct {
+ BD_ADDR bd_addr;
+ uint16_t service;
+ char number[BTA_HF_CLIENT_NUMBER_LEN + 1];
+} tBTA_HF_CLIENT_CNUM;
+
+/* data associated with other events */
+typedef struct {
+ BD_ADDR bd_addr;
+ uint16_t value;
+} tBTA_HF_CLIENT_VAL;
+
+/* union of data associated with AG callback */
+typedef union {
+ // Common BD ADDR field for all tyepdefs
+ BD_ADDR bd_addr;
+ tBTA_HF_CLIENT_REGISTER reg;
+ tBTA_HF_CLIENT_OPEN open;
+ tBTA_HF_CLIENT_CONN conn;
+ tBTA_HF_CLIENT_IND ind;
+ tBTA_HF_CLIENT_VAL val;
+ tBTA_HF_CLIENT_OPERATOR_NAME operator_name;
+ tBTA_HF_CLIENT_NUMBER number;
+ tBTA_HF_CLIENT_AT_RESULT result;
+ tBTA_HF_CLIENT_CLCC clcc;
+ tBTA_HF_CLIENT_CNUM cnum;
+} tBTA_HF_CLIENT;
+
+typedef uint32_t tBTA_HF_CLIENT_FEAT;
+
+/* HF Client callback */
+typedef void(tBTA_HF_CLIENT_CBACK)(tBTA_HF_CLIENT_EVT event,
+ tBTA_HF_CLIENT* p_data);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientEnable
+ *
+ * Description Enable the HF CLient service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_HF_CLIENT_ENABLE_EVT. This function must
+ * be called before other function in the HF CLient API are
+ * called.
+ *
+ * Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+ *
+ ******************************************************************************/
+tBTA_STATUS BTA_HfClientEnable(tBTA_HF_CLIENT_CBACK* p_cback, tBTA_SEC sec_mask,
+ tBTA_HF_CLIENT_FEAT features,
+ const char* p_service_name);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientDisable
+ *
+ * Description Disable the HF Client service.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientOpen
+ *
+ * Description Opens a connection to an audio gateway.
+ * When connection is open callback function is called
+ * with a BTA_HF_CLIENT_OPEN_EVT. Only the data connection is
+ * opened. The audio connection is not opened. The handle
+ * is stored in p_handle and should be used for subsequent
+ * calls to do any AT operations
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientOpen(BD_ADDR bd_addr, tBTA_SEC sec_mask, uint16_t* p_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientClose
+ *
+ * Description Close the current connection to an audio gateway.
+ * Any current audio connection will also be closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfCllientAudioOpen
+ *
+ * Description Opens an audio connection to the currently connected
+ * audio gateway
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioOpen(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientAudioClose
+ *
+ * Description Close the currently active audio connection to an audio
+ * gateway. The data connection remains open
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientAudioClose(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientSendAT
+ *
+ * Description send AT command
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_HfClientSendAT(uint16_t handle, tBTA_HF_CLIENT_AT_CMD_TYPE at,
+ uint32_t val1, uint32_t val2, const char* str);
+
+/*******************************************************************************
+ *
+ * Function BTA_HfClientDumpStatistics
+ *
+ * Description Dump statistics about the various control blocks
+ * and other relevant connection statistics
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void BTA_HfClientDumpStatistics(int fd);
+
+#endif /* BTA_HF_CLIENT_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hh_api.h b/mtkbt/code/bt/bta/include/bta_hh_api.h
new file mode 100755
index 0000000..1e68a9a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hh_api.h
@@ -0,0 +1,514 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef BTA_HH_API_H
+#define BTA_HH_API_H
+
+#include "bta_api.h"
+#include "hidh_api.h"
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "gatt_api.h"
+#endif
+
+/*****************************************************************************
+ * Constants and Type Definitions
+ ****************************************************************************/
+#ifndef BTA_HH_DEBUG
+#define BTA_HH_DEBUG TRUE
+#endif
+
+#ifndef BTA_HH_SSR_MAX_LATENCY_DEF
+#define BTA_HH_SSR_MAX_LATENCY_DEF 800 /* 500 ms*/
+#endif
+
+#ifndef BTA_HH_SSR_MIN_TOUT_DEF
+#define BTA_HH_SSR_MIN_TOUT_DEF 2
+#endif
+
+/* BTA HID Host callback events */
+#define BTA_HH_ENABLE_EVT 0 /* HH enabled */
+#define BTA_HH_DISABLE_EVT 1 /* HH disabled */
+#define BTA_HH_OPEN_EVT 2 /* connection opened */
+#define BTA_HH_CLOSE_EVT 3 /* connection closed */
+#define BTA_HH_GET_RPT_EVT 4 /* BTA_HhGetReport callback */
+#define BTA_HH_SET_RPT_EVT 5 /* BTA_HhSetReport callback */
+#define BTA_HH_GET_PROTO_EVT 6 /* BTA_GetProtoMode callback */
+#define BTA_HH_SET_PROTO_EVT 7 /* BTA_HhSetProtoMode callback */
+#define BTA_HH_GET_IDLE_EVT 8 /* BTA_HhGetIdle comes callback */
+#define BTA_HH_SET_IDLE_EVT 9 /* BTA_HhSetIdle finish callback */
+#define BTA_HH_GET_DSCP_EVT 10 /* Get report descriptor */
+#define BTA_HH_ADD_DEV_EVT 11 /* Add Device callback */
+#define BTA_HH_RMV_DEV_EVT 12 /* remove device finished */
+#define BTA_HH_VC_UNPLUG_EVT 13 /* virtually unplugged */
+#define BTA_HH_DATA_EVT 15
+#define BTA_HH_API_ERR_EVT 16 /* API error is caught */
+#define BTA_HH_UPDATE_SCPP_EVT 17 /* update scan paramter complete */
+
+typedef uint16_t tBTA_HH_EVT;
+
+/* application ID(none-zero) for each type of device */
+#define BTA_HH_APP_ID_MI 1
+#define BTA_HH_APP_ID_KB 2
+#define BTA_HH_APP_ID_RMC 3
+#define BTA_HH_APP_ID_3DSG 4
+#define BTA_HH_APP_ID_JOY 5
+#define BTA_HH_APP_ID_GPAD 6
+#define BTA_HH_APP_ID_LE 0xff
+
+/* defined the minimum offset */
+#define BTA_HH_MIN_OFFSET (L2CAP_MIN_OFFSET + 1)
+
+/* HID_HOST_MAX_DEVICES can not exceed 15 for th design of BTA HH */
+#define BTA_HH_IDX_INVALID 0xff
+#define BTA_HH_MAX_KNOWN HID_HOST_MAX_DEVICES
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+/* GATT_MAX_PHY_CHANNEL can not exceed 14 for the design of BTA HH */
+#define BTA_HH_LE_MAX_KNOWN GATT_MAX_PHY_CHANNEL
+#define BTA_HH_MAX_DEVICE (HID_HOST_MAX_DEVICES + GATT_MAX_PHY_CHANNEL)
+#else
+#define BTA_HH_MAX_DEVICE HID_HOST_MAX_DEVICES
+#endif
+/* invalid device handle */
+#define BTA_HH_INVALID_HANDLE 0xff
+
+/* type of protocol mode */
+#define BTA_HH_PROTO_RPT_MODE (0x00)
+#define BTA_HH_PROTO_BOOT_MODE (0x01)
+#define BTA_HH_PROTO_UNKNOWN (0xff)
+typedef uint8_t tBTA_HH_PROTO_MODE;
+
+enum { BTA_HH_KEYBD_RPT_ID = 1, BTA_HH_MOUSE_RPT_ID };
+typedef uint8_t tBTA_HH_BOOT_RPT_ID;
+
+/* type of devices, bit mask */
+#define BTA_HH_DEVT_UNKNOWN 0x00
+#define BTA_HH_DEVT_JOS 0x01 /* joy stick */
+#define BTA_HH_DEVT_GPD 0x02 /* game pad */
+#define BTA_HH_DEVT_RMC 0x03 /* remote control */
+#define BTA_HH_DEVT_SED 0x04 /* sensing device */
+#define BTA_HH_DEVT_DGT 0x05 /* Digitizer tablet */
+#define BTA_HH_DEVT_CDR 0x06 /* card reader */
+#define BTA_HH_DEVT_KBD 0x10 /* keyboard */
+#define BTA_HH_DEVT_MIC 0x20 /* pointing device */
+#define BTA_HH_DEVT_COM 0x30 /* Combo keyboard/pointing */
+#define BTA_HH_DEVT_OTHER 0x80
+typedef uint8_t tBTA_HH_DEVT;
+
+enum {
+ BTA_HH_OK,
+ BTA_HH_HS_HID_NOT_READY, /* handshake error : device not ready */
+ BTA_HH_HS_INVALID_RPT_ID, /* handshake error : invalid report ID */
+ BTA_HH_HS_TRANS_NOT_SPT, /* handshake error : transaction not spt */
+ BTA_HH_HS_INVALID_PARAM, /* handshake error : invalid paremter */
+ BTA_HH_HS_ERROR, /* handshake error : unspecified HS error */
+ BTA_HH_ERR, /* general BTA HH error */
+ BTA_HH_ERR_SDP, /* SDP error */
+ BTA_HH_ERR_PROTO, /* SET_Protocol error,
+ only used in BTA_HH_OPEN_EVT callback */
+
+ BTA_HH_ERR_DB_FULL, /* device database full error, used in
+ BTA_HH_OPEN_EVT/BTA_HH_ADD_DEV_EVT */
+ BTA_HH_ERR_TOD_UNSPT, /* type of device not supported */
+ BTA_HH_ERR_NO_RES, /* out of system resources */
+ BTA_HH_ERR_AUTH_FAILED, /* authentication fail */
+ BTA_HH_ERR_HDL,
+ BTA_HH_ERR_SEC
+};
+typedef uint8_t tBTA_HH_STATUS;
+
+#define BTA_HH_VIRTUAL_CABLE HID_VIRTUAL_CABLE
+#define BTA_HH_NORMALLY_CONNECTABLE HID_NORMALLY_CONNECTABLE
+#define BTA_HH_RECONN_INIT HID_RECONN_INIT
+#define BTA_HH_SDP_DISABLE HID_SDP_DISABLE
+#define BTA_HH_BATTERY_POWER HID_BATTERY_POWER
+#define BTA_HH_REMOTE_WAKE HID_REMOTE_WAKE
+#define BTA_HH_SUP_TOUT_AVLBL HID_SUP_TOUT_AVLBL
+#define BTA_HH_SEC_REQUIRED HID_SEC_REQUIRED
+typedef uint16_t tBTA_HH_ATTR_MASK;
+
+/* supported type of device and corresponding application ID */
+typedef struct {
+ tBTA_HH_DEVT tod; /* type of device */
+ uint8_t app_id; /* corresponding application ID */
+} tBTA_HH_SPT_TOD;
+
+/* configuration struct */
+typedef struct {
+ uint8_t max_devt_spt; /* max number of types of devices spt */
+ tBTA_HH_SPT_TOD* p_devt_list; /* supported types of device list */
+ uint16_t sdp_db_size;
+} tBTA_HH_CFG;
+
+enum {
+ BTA_HH_RPTT_RESRV, /* reserved */
+ BTA_HH_RPTT_INPUT, /* input report */
+ BTA_HH_RPTT_OUTPUT, /* output report */
+ BTA_HH_RPTT_FEATURE /* feature report */
+};
+typedef uint8_t tBTA_HH_RPT_TYPE;
+
+/* HID_CONTROL operation code used in BTA_HhSendCtrl()
+*/
+enum {
+ BTA_HH_CTRL_NOP = 0 + HID_PAR_CONTROL_NOP, /* mapping from BTE */
+ BTA_HH_CTRL_HARD_RESET, /* hard reset */
+ BTA_HH_CTRL_SOFT_RESET, /* soft reset */
+ BTA_HH_CTRL_SUSPEND, /* enter suspend */
+ BTA_HH_CTRL_EXIT_SUSPEND, /* exit suspend */
+ BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG /* virtual unplug */
+};
+typedef uint8_t tBTA_HH_TRANS_CTRL_TYPE;
+
+typedef tHID_DEV_DSCP_INFO tBTA_HH_DEV_DESCR;
+
+#define BTA_HH_SSR_PARAM_INVALID HID_SSR_PARAM_INVALID
+
+/* id DI is not existing in remote device, vendor_id in tBTA_HH_DEV_DSCP_INFO
+ * will be set to 0xffff */
+#define BTA_HH_VENDOR_ID_INVALID 0xffff
+
+/* report descriptor information */
+typedef struct {
+ uint16_t vendor_id; /* vendor ID */
+ uint16_t product_id; /* product ID */
+ uint16_t version; /* version */
+ uint16_t ssr_max_latency; /* SSR max latency, BTA_HH_SSR_PARAM_INVALID if
+ unknown */
+ uint16_t
+ ssr_min_tout; /* SSR min timeout, BTA_HH_SSR_PARAM_INVALID if unknown */
+ uint8_t ctry_code; /*Country Code.*/
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#define BTA_HH_LE_REMOTE_WAKE 0x01
+#define BTA_HH_LE_NORMAL_CONN 0x02
+
+ uint8_t flag;
+#endif
+ tBTA_HH_DEV_DESCR descriptor;
+} tBTA_HH_DEV_DSCP_INFO;
+
+/* callback event data for BTA_HH_OPEN_EVT */
+typedef struct {
+ BD_ADDR bda; /* HID device bd address */
+ tBTA_HH_STATUS status; /* operation status */
+ uint8_t handle; /* device handle */
+#if (BTA_HH_LE_INCLUDED == TRUE)
+ bool le_hid; /* is LE devices? */
+ bool scps_supported; /* scan parameter service supported */
+#endif
+
+} tBTA_HH_CONN;
+
+typedef tBTA_HH_CONN tBTA_HH_DEV_INFO;
+
+/* callback event data */
+typedef struct {
+ tBTA_HH_STATUS status; /* operation status */
+ uint8_t handle; /* device handle */
+} tBTA_HH_CBDATA;
+
+enum {
+ BTA_HH_MOD_CTRL_KEY,
+ BTA_HH_MOD_SHFT_KEY,
+ BTA_HH_MOD_ALT_KEY,
+ BTA_HH_MOD_GUI_KEY,
+ BTA_HH_MOD_MAX_KEY
+};
+
+/* parsed boot mode keyboard report */
+typedef struct {
+ uint8_t this_char[6]; /* virtual key code */
+ bool mod_key[BTA_HH_MOD_MAX_KEY];
+ /* ctrl, shift, Alt, GUI */
+ /* modifier key: is Shift key pressed */
+ /* modifier key: is Ctrl key pressed */
+ /* modifier key: is Alt key pressed */
+ /* modifier key: GUI up/down */
+ bool caps_lock; /* is caps locked */
+ bool num_lock; /* is Num key pressed */
+} tBTA_HH_KEYBD_RPT;
+
+/* parsed boot mode mouse report */
+typedef struct {
+ uint8_t mouse_button; /* mouse button is clicked */
+ int8_t delta_x; /* displacement x */
+ int8_t delta_y; /* displacement y */
+} tBTA_HH_MICE_RPT;
+
+/* parsed Boot report */
+typedef struct {
+ tBTA_HH_BOOT_RPT_ID dev_type; /* type of device report */
+ union {
+ tBTA_HH_KEYBD_RPT keybd_rpt; /* keyboard report */
+ tBTA_HH_MICE_RPT mice_rpt; /* mouse report */
+ } data_rpt;
+} tBTA_HH_BOOT_RPT;
+
+/* handshake data */
+typedef struct {
+ tBTA_HH_STATUS status; /* handshake status */
+ uint8_t handle; /* device handle */
+ union {
+ tBTA_HH_PROTO_MODE proto_mode; /* GET_PROTO_EVT :protocol mode */
+ BT_HDR* p_rpt_data; /* GET_RPT_EVT : report data */
+ uint8_t idle_rate; /* GET_IDLE_EVT : idle rate */
+ } rsp_data;
+
+} tBTA_HH_HSDATA;
+
+/* union of data associated with HD callback */
+typedef union {
+ tBTA_HH_DEV_INFO dev_info; /* BTA_HH_ADD_DEV_EVT, BTA_HH_RMV_DEV_EVT */
+ tBTA_HH_CONN conn; /* BTA_HH_OPEN_EVT */
+ tBTA_HH_CBDATA dev_status; /* BTA_HH_CLOSE_EVT,
+ BTA_HH_SET_PROTO_EVT
+ BTA_HH_SET_RPT_EVT
+ BTA_HH_SET_IDLE_EVT
+ BTA_HH_UPDATE_SCPP_EVT */
+
+ tBTA_HH_STATUS status; /* BTA_HH_ENABLE_EVT */
+ tBTA_HH_DEV_DSCP_INFO dscp_info; /* BTA_HH_GET_DSCP_EVT */
+ tBTA_HH_HSDATA hs_data; /* GET_ transaction callback
+ BTA_HH_GET_RPT_EVT
+ BTA_HH_GET_PROTO_EVT
+ BTA_HH_GET_IDLE_EVT */
+} tBTA_HH;
+
+/* BTA HH callback function */
+typedef void(tBTA_HH_CBACK)(tBTA_HH_EVT event, tBTA_HH* p_data);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_HhRegister
+ *
+ * Description This function enable HID host and registers HID-Host with
+ * lower layers.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhDeregister
+ *
+ * Description This function is called when the host is about power down.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhOpen
+ *
+ * Description This function is called to start an inquiry and read SDP
+ * record of responding devices; connect to a device if only
+ * one active HID device is found.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhOpen(BD_ADDR dev_bda, tBTA_HH_PROTO_MODE mode,
+ tBTA_SEC sec_mask);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhClose
+ *
+ * Description This function disconnects the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhClose(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhSetProtoMode
+ *
+ * Description This function set the protocol mode at specified HID handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetProtoMode(uint8_t handle, tBTA_HH_PROTO_MODE t_type);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetProtoMode
+ *
+ * Description This function get the protocol mode of a specified HID
+ * device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetProtoMode(uint8_t dev_handle);
+/*******************************************************************************
+ *
+ * Function BTA_HhSetReport
+ *
+ * Description send SET_REPORT to device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+ BT_HDR* p_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetReport
+ *
+ * Description Send a GET_REPORT to HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetReport(uint8_t dev_handle, tBTA_HH_RPT_TYPE r_type,
+ uint8_t rpt_id, uint16_t buf_size);
+/*******************************************************************************
+ *
+ * Function BTA_HhSetIdle
+ *
+ * Description send SET_IDLE to device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetIdle
+ *
+ * Description Send a GET_IDLE to HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetIdle(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhSendCtrl
+ *
+ * Description Send HID_CONTROL request to a HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSendCtrl(uint8_t dev_handle, tBTA_HH_TRANS_CTRL_TYPE c_type);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhSetIdle
+ *
+ * Description send SET_IDLE to device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSetIdle(uint8_t dev_handle, uint16_t idle_rate);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetIdle
+ *
+ * Description Send a GET_IDLE from HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetIdle(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhSendData
+ *
+ * Description Send DATA transaction to a HID device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhSendData(uint8_t dev_handle, BD_ADDR dev_bda, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function BTA_HhGetDscpInfo
+ *
+ * Description Get report descriptor of the device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhGetDscpInfo(uint8_t dev_handle);
+
+/*******************************************************************************
+ * Function BTA_HhAddDev
+ *
+ * Description Add a virtually cabled device into HID-Host device list
+ * to manage and assign a device handle for future API call,
+ * host applciation call this API at start-up to initialize its
+ * virtually cabled devices.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask,
+ uint8_t sub_class, uint8_t app_id,
+ tBTA_HH_DEV_DSCP_INFO dscp_info);
+/*******************************************************************************
+ *
+ * Function BTA_HhRemoveDev
+ *
+ * Description Remove a device from the HID host devices list.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhRemoveDev(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Parsing Utility Functions
+ *
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTA_HhParseBootRpt
+ *
+ * Description This utility function parse a boot mode report.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HhParseBootRpt(tBTA_HH_BOOT_RPT* p_data, uint8_t* p_report,
+ uint16_t report_len);
+
+/* test commands */
+extern void bta_hh_le_hid_read_rpt_clt_cfg(BD_ADDR bd_addr, uint8_t rpt_id);
+
+#endif /* BTA_HH_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hh_co.h b/mtkbt/code/bt/bta/include/bta_hh_co.h
new file mode 100755
index 0000000..d2b0382
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hh_co.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2005-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for hid host call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HH_CO_H
+#define BTA_HH_CO_H
+
+#include "bta_hh_api.h"
+
+typedef struct {
+ uint16_t rpt_uuid;
+ uint8_t rpt_id;
+ tBTA_HH_RPT_TYPE rpt_type;
+ uint8_t srvc_inst_id;
+ uint8_t char_inst_id;
+} tBTA_HH_RPT_CACHE_ENTRY;
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_data
+ *
+ * Description This callout function is executed by HH when data is
+ * received
+ * in interupt channel.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
+ tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
+ uint8_t ctry_code, BD_ADDR peer_addr,
+ uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_open
+ *
+ * Description This callout function is executed by HH when connection is
+ * opened, and application may do some device specific
+ * initialization.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
+ uint16_t attr_mask, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_close
+ *
+ * Description This callout function is executed by HH when connection is
+ * closed, and device specific finalizatio nmay be needed.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id);
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_rpt_info
+ *
+ * Description This callout function is to convey the report information on
+ * a HOGP device to the application. Application can save this
+ * information in NV if device is bonded and load it back when
+ * stack reboot.
+ *
+ * Parameters remote_bda - remote device address
+ * p_entry - report entry pointer
+ * app_id - application id
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void bta_hh_le_co_rpt_info(BD_ADDR remote_bda,
+ tBTA_HH_RPT_CACHE_ENTRY* p_entry,
+ uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_cache_load
+ *
+ * Description This callout function is to request the application to load
+ * the cached HOGP report if there is any. When cache reading
+ * is completed, bta_hh_le_ci_cache_load() is called by the
+ * application.
+ *
+ * Parameters remote_bda - remote device address
+ * p_num_rpt: number of cached report
+ * app_id - application id
+ *
+ * Returns the acched report array
+ *
+ ******************************************************************************/
+extern tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(BD_ADDR remote_bda,
+ uint8_t* p_num_rpt,
+ uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_reset_rpt_cache
+ *
+ * Description This callout function is to reset the HOGP device cache.
+ *
+ * Parameters remote_bda - remote device address
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+extern void bta_hh_le_co_reset_rpt_cache(BD_ADDR remote_bda, uint8_t app_id);
+
+#endif /* #if (BTA_HH_LE_INCLUDED == TRUE) */
+
+#endif /* BTA_HH_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hl_api.h b/mtkbt/code/bt/bta/include/bta_hl_api.h
new file mode 100755
index 0000000..429aa8a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hl_api.h
@@ -0,0 +1,827 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the HeaLth device profile (HL)
+ * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_API_H
+#define BTA_HL_API_H
+
+#include "bta_api.h"
+#include "btm_api.h"
+#include "mca_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_HL_DEBUG
+#define BTA_HL_DEBUG TRUE
+#endif
+
+#ifndef BTA_HL_NUM_APPS
+#define BTA_HL_NUM_APPS 12
+#endif
+
+#ifndef BTA_HL_NUM_MDEPS
+#define BTA_HL_NUM_MDEPS 13
+#endif
+
+#ifndef BTA_HL_NUM_MCLS
+#define BTA_HL_NUM_MCLS 7
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MDEP
+#define BTA_HL_NUM_MDLS_PER_MDEP 4
+#endif
+
+#ifndef BTA_HL_NUM_MDLS_PER_MCL
+#define BTA_HL_NUM_MDLS_PER_MCL 10
+#endif
+
+#ifndef BTA_HL_NUM_DATA_TYPES
+#define BTA_HL_NUM_DATA_TYPES \
+ 5 /* maximum number of data types can be supported \
+ per MDEP ID */
+#endif
+
+#define BTA_HL_MCAP_RSP_TOUT 2 /* 2 seconds */
+
+#ifndef BTA_HL_CCH_NUM_FILTER_ELEMS
+#define BTA_HL_CCH_NUM_FILTER_ELEMS 3
+#endif
+
+#ifndef BTA_HL_NUM_SDP_CBACKS
+#define BTA_HL_NUM_SDP_CBACKS 7
+#endif
+
+#ifndef BTA_HL_NUM_SDP_RECS
+#define BTA_HL_NUM_SDP_RECS 5
+#endif
+
+#ifndef BTA_HL_NUM_SDP_MDEPS
+#define BTA_HL_NUM_SDP_MDEPS 12
+#endif
+
+#ifndef BTA_HL_NUM_SVC_ELEMS
+#define BTA_HL_NUM_SVC_ELEMS 2
+#endif
+
+#ifndef BTA_HL_NUM_PROTO_ELEMS
+#define BTA_HL_NUM_PROTO_ELEMS 2
+#endif
+
+#define BTA_HL_VERSION 0x0101
+#define BTA_HL_NUM_ADD_PROTO_LISTS 1
+#define BTA_HL_NUM_ADD_PROTO_ELEMS 2
+#define BTA_HL_MDEP_SEQ_SIZE 20
+#define BTA_HL_VAL_ARRY_SIZE 320
+
+#ifndef BTA_HL_NUM_MDL_CFGS
+#define BTA_HL_NUM_MDL_CFGS \
+ 16 /* numer of MDL cfg saved in the persistent memory*/
+#endif
+
+#define BTA_HL_NUM_TIMERS 7
+
+#define BTA_HL_CCH_RSP_TOUT 2000
+#define BTA_HL_MAX_TIME 255
+#define BTA_HL_MIN_TIME 1
+#define BTA_HL_INVALID_APP_HANDLE 0xFF
+#define BTA_HL_INVALID_MCL_HANDLE 0xFF
+#define BTA_HL_INVALID_MDL_HANDLE 0xFFFF
+
+#define BTA_HL_STATUS_OK 0
+#define BTA_HL_STATUS_FAIL 1 /* Used to pass all other errors */
+#define BTA_HL_STATUS_ABORTED 2
+#define BTA_HL_STATUS_NO_RESOURCE 3
+#define BTA_HL_STATUS_LAST_ITEM 4
+#define BTA_HL_STATUS_DUPLICATE_APP_ID 5
+#define BTA_HL_STATUS_INVALID_APP_HANDLE 6
+#define BTA_HL_STATUS_INVALID_MCL_HANDLE 7
+#define BTA_HL_STATUS_MCAP_REG_FAIL 8
+#define BTA_HL_STATUS_MDEP_CO_FAIL 9
+#define BTA_HL_STATUS_ECHO_CO_FAIL 10
+#define BTA_HL_STATUS_MDL_CFG_CO_FAIL 11
+#define BTA_HL_STATUS_SDP_NO_RESOURCE 12
+#define BTA_HL_STATUS_SDP_FAIL 13
+#define BTA_HL_STATUS_NO_CCH 14
+#define BTA_HL_STATUS_NO_MCL 15
+
+#define BTA_HL_STATUS_NO_FIRST_RELIABLE 17
+#define BTA_HL_STATUS_INVALID_DCH_CFG 18
+#define BTA_HL_STATUS_INVALID_MDL_HANDLE 19
+#define BTA_HL_STATUS_INVALID_BD_ADDR 20
+#define BTA_HL_STATUS_INVALID_RECONNECT_CFG 21
+#define BTA_HL_STATUS_ECHO_TEST_BUSY 22
+#define BTA_HL_STATUS_INVALID_LOCAL_MDEP_ID 23
+#define BTA_HL_STATUS_INVALID_MDL_ID 24
+#define BTA_HL_STATUS_NO_MDL_ID_FOUND 25
+#define BTA_HL_STATUS_DCH_BUSY 26 /* DCH is congested*/
+#define BTA_HL_STATUS_INVALID_CTRL_PSM 27
+#define BTA_HL_STATUS_DUPLICATE_CCH_OPEN 28
+
+typedef uint8_t tBTA_HL_STATUS;
+typedef tMCA_HANDLE tBTA_HL_APP_HANDLE;
+typedef tMCA_CL tBTA_HL_MCL_HANDLE;
+typedef tMCA_DL tBTA_HL_MDL_HANDLE;
+enum {
+ BTA_HL_DEVICE_TYPE_SINK,
+ BTA_HL_DEVICE_TYPE_SOURCE,
+ BTA_HL_DEVICE_TYPE_DUAL
+};
+
+typedef uint8_t tBTA_HL_DEVICE_TYPE;
+
+#define BTA_HL_SDP_IEEE_11073_20601 0x01
+
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT 2 /* 0x02 */
+#define BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT 4 /* 0x04 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE 0 /* 0x08 */
+#define BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER 0 /* 0x10 */
+
+#define BTA_HL_MCAP_SUP_PROC_MASK \
+ (BTA_HL_MCAP_SUP_RECONNECT_MASK_INIT | \
+ BTA_HL_MCAP_SUP_RECONNECT_MASK_ACCEPT | \
+ BTA_HL_MCAP_SUP_CSP_MASK_SYNC_SLAVE | BTA_HL_MCAP_SUP_CSP_MASK_SYNC_MASTER)
+#define BTA_HL_MDEP_ROLE_SOURCE 0x00
+#define BTA_HL_MDEP_ROLE_SINK 0x01
+
+typedef uint8_t tBTA_HL_MDEP_ROLE;
+
+#define BTA_HL_MDEP_ROLE_MASK_SOURCE 0x01 /* bit mask */
+#define BTA_HL_MDEP_ROLE_MASK_SINK 0x02
+typedef uint8_t tBTA_HL_MDEP_ROLE_MASK;
+
+#define BTA_HL_ECHO_TEST_MDEP_ID 0
+#define BTA_HL_ECHO_TEST_MDEP_CFG_IDX 0
+
+#define BTA_HL_INVALID_MDEP_ID 0xFF
+typedef tMCA_DEP tBTA_HL_MDEP_ID; /* 0 is for echo test,
+ 0x01-0x7F availave for use,
+ 0x80-0xFF reserved*/
+
+#define BTA_HL_DELETE_ALL_MDL_IDS 0xFFFF
+#define BTA_HL_MAX_MDL_VAL 0xFEFF
+typedef uint16_t tBTA_HL_MDL_ID; /* 0x0000 reserved,
+ 0x0001-0xFEFF dynamic range,
+ 0xFF00-0xFFFE reserved,
+ 0xFFFF indicates all MDLs*/
+
+#define BTA_HL_MDEP_DESP_LEN 35
+
+#define BTA_HL_DCH_MODE_RELIABLE 0
+#define BTA_HL_DCH_MODE_STREAMING 1
+
+typedef uint8_t tBTA_HL_DCH_MODE;
+
+#define BTA_HL_DCH_CFG_NO_PREF 0
+#define BTA_HL_DCH_CFG_RELIABLE 1
+#define BTA_HL_DCH_CFG_STREAMING 2
+#define BTA_HL_DCH_CFG_UNKNOWN 0xFF
+
+typedef uint8_t tBTA_HL_DCH_CFG;
+
+/* The Default DCH CFG for the echo test when the device is a Source */
+#define BTA_HL_DEFAULT_ECHO_TEST_SRC_DCH_CFG BTA_HL_DCH_CFG_RELIABLE
+
+#define BTA_HL_DCH_CREATE_RSP_SUCCESS 0
+#define BTA_HL_DCH_CREATE_RSP_CFG_REJ 1
+
+typedef uint8_t tBTA_HL_DCH_CREATE_RSP;
+
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_INIT 0x02
+#define BTA_HL_MCAP_SUP_PROC_RECONNECT_APT 0x04
+#define BTA_HL_MCAP_SUP_PROC_CSP_SLAVE 0x08
+#define BTA_HL_MCAP_SUP_PROC_CSP_MASTER 0x10
+
+typedef uint8_t tBTA_HL_SUP_PROC_MASK;
+
+typedef struct {
+ uint16_t max_rx_apdu_size; /* local rcv MTU */
+ uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
+} tBTA_HL_ECHO_CFG;
+
+typedef struct {
+ uint16_t data_type;
+ uint16_t max_rx_apdu_size; /* local rcv MTU */
+ uint16_t max_tx_apdu_size; /* maximum TX APDU size*/
+ char desp[BTA_HL_MDEP_DESP_LEN + 1];
+} tBTA_HL_MDEP_DATA_TYPE_CFG;
+
+typedef struct {
+ tBTA_HL_MDEP_ROLE mdep_role;
+ uint8_t num_of_mdep_data_types;
+ tBTA_HL_MDEP_DATA_TYPE_CFG data_cfg[BTA_HL_NUM_DATA_TYPES];
+} tBTA_HL_MDEP_CFG;
+
+typedef struct {
+ tBTA_HL_MDEP_ID mdep_id; /* MDEP ID 0x01-0x7F */
+ tBTA_HL_MDEP_CFG mdep_cfg;
+ uint8_t ori_app_id;
+} tBTA_HL_MDEP;
+
+typedef struct {
+ tBTA_HL_MDEP mdep[BTA_HL_NUM_MDEPS];
+ tBTA_HL_ECHO_CFG echo_cfg;
+ tBTA_HL_MDEP_ROLE_MASK app_role_mask;
+ bool advertize_source_sdp;
+ uint8_t num_of_mdeps;
+} tBTA_HL_SUP_FEATURE;
+
+typedef struct {
+ bool delete_req_pending;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+} tBTA_HL_DELETE_MDL;
+
+typedef struct {
+ uint8_t time;
+ uint16_t mtu;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDEP_ROLE local_mdep_role;
+ bool active; /* true if this item is in use */
+ tBTA_HL_DCH_MODE dch_mode;
+ uint8_t fcs;
+ BD_ADDR peer_bd_addr;
+} tBTA_HL_MDL_CFG;
+
+/* Maximum number of supported feature list items (list_elem in
+ * tSDP_SUP_FEATURE_ELEM) */
+#define BTA_HL_NUM_SUP_FEATURE_ELEMS 13
+#define BTA_HL_SUP_FEATURE_SDP_BUF_SIZE 512
+/* This structure is used to add supported feature lists and find supported
+ * feature elements */
+typedef struct {
+ uint8_t mdep_id;
+ uint16_t data_type;
+ tBTA_HL_MDEP_ROLE mdep_role;
+ char* p_mdep_desp;
+} tBTA_HL_SUP_FEATURE_ELEM;
+
+typedef struct {
+ uint16_t num_elems;
+ tBTA_HL_SUP_FEATURE_ELEM list_elem[BTA_HL_NUM_SUP_FEATURE_ELEMS];
+} tBTA_HL_SUP_FEATURE_LIST_ELEM;
+
+typedef struct {
+ tBTA_HL_DEVICE_TYPE dev_type; /* sink, source or dual roles */
+ tBTA_SEC sec_mask; /* security mask for accepting conenction*/
+ const char*
+ p_srv_name; /* service name to be used in the SDP; null terminated*/
+ const char* p_srv_desp; /* service description to be used in the SDP; null
+ terminated */
+ const char*
+ p_provider_name; /* provide name to be used in the SDP; null terminated */
+} tBTA_HL_REG_PARAM;
+
+typedef struct {
+ uint16_t ctrl_psm;
+ BD_ADDR bd_addr; /* Address of peer device */
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_CCH_OPEN_PARAM;
+
+typedef struct {
+ uint16_t ctrl_psm;
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDEP_ID peer_mdep_id; /* peer mdep id */
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_SEC sec_mask; /* security mask for initiating connection*/
+} tBTA_HL_DCH_OPEN_PARAM;
+
+typedef struct {
+ uint16_t ctrl_psm;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DCH_RECONNECT_PARAM;
+
+typedef struct {
+ uint16_t ctrl_psm;
+ uint16_t pkt_size;
+ tBTA_HL_DCH_CFG local_cfg;
+} tBTA_HL_DCH_ECHO_TEST_PARAM;
+
+typedef struct {
+ uint16_t buf_size;
+ uint8_t p_buf; /* buffer pointer */
+} tBTA_HL_DCH_BUF_INFO;
+
+typedef struct {
+ tBTA_HL_MDEP_ID local_mdep_id; /* local MDEP ID */
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_CREATE_RSP rsp_code;
+ tBTA_HL_DCH_CFG cfg_rsp;
+} tBTA_HL_DCH_CREATE_RSP_PARAM;
+
+typedef struct {
+ uint16_t data_type;
+ uint8_t mdep_id;
+ tBTA_HL_MDEP_ROLE mdep_role;
+ char mdep_desp[BTA_HL_MDEP_DESP_LEN + 1];
+} tBTA_HL_SDP_MDEP_CFG;
+
+typedef struct {
+ uint16_t ctrl_psm;
+ uint16_t data_psm;
+ uint8_t mcap_sup_proc;
+ uint8_t num_mdeps; /* number of mdep elements from SDP*/
+ char srv_name[BTA_SERVICE_NAME_LEN + 1];
+ char srv_desp[BTA_SERVICE_DESP_LEN + 1];
+ char provider_name[BTA_PROVIDER_NAME_LEN + 1];
+ tBTA_HL_SDP_MDEP_CFG mdep_cfg[BTA_HL_NUM_SDP_MDEPS];
+} tBTA_HL_SDP_REC;
+
+typedef struct {
+ uint8_t num_recs;
+ tBTA_HL_SDP_REC sdp_rec[BTA_HL_NUM_SDP_RECS];
+} tBTA_HL_SDP;
+
+/* HL control callback function events */
+enum { BTA_HL_CTRL_ENABLE_CFM_EVT = 0, BTA_HL_CTRL_DISABLE_CFM_EVT };
+typedef uint8_t tBTA_HL_CTRL_EVT;
+/* Structure associated with BTA_HL_ENABLE_EVT
+ BTA_HL_DISABLE_EVT */
+
+typedef struct { tBTA_HL_STATUS status; } tBTA_HL_CTRL_ENABLE_DISABLE;
+
+typedef union {
+ tBTA_HL_CTRL_ENABLE_DISABLE enable_cfm;
+ tBTA_HL_CTRL_ENABLE_DISABLE disable_cfm;
+} tBTA_HL_CTRL;
+
+/* HL instance callback function events */
+enum {
+ BTA_HL_REGISTER_CFM_EVT = 0,
+ BTA_HL_DEREGISTER_CFM_EVT,
+ BTA_HL_CCH_OPEN_IND_EVT,
+ BTA_HL_CCH_OPEN_CFM_EVT,
+ BTA_HL_CCH_CLOSE_IND_EVT,
+ BTA_HL_CCH_CLOSE_CFM_EVT,
+ BTA_HL_DCH_CREATE_IND_EVT,
+ BTA_HL_DCH_OPEN_IND_EVT,
+ BTA_HL_DCH_OPEN_CFM_EVT,
+ BTA_HL_DCH_CLOSE_IND_EVT,
+ BTA_HL_DCH_CLOSE_CFM_EVT,
+ BTA_HL_DCH_RECONNECT_IND_EVT,
+ BTA_HL_DCH_RECONNECT_CFM_EVT,
+
+ BTA_HL_DCH_ABORT_IND_EVT,
+ BTA_HL_DCH_ABORT_CFM_EVT,
+ BTA_HL_DELETE_MDL_IND_EVT,
+ BTA_HL_DELETE_MDL_CFM_EVT,
+ BTA_HL_DCH_SEND_DATA_CFM_EVT,
+ BTA_HL_DCH_RCV_DATA_IND_EVT,
+ BTA_HL_CONG_CHG_IND_EVT,
+ BTA_HL_DCH_ECHO_TEST_CFM_EVT,
+ BTA_HL_SDP_QUERY_CFM_EVT,
+ BTA_HL_SDP_INFO_IND_EVT
+};
+typedef uint8_t tBTA_HL_EVT;
+
+typedef struct {
+ tBTA_HL_STATUS status; /* start status */
+ uint8_t app_id;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_REGISTER_CFM;
+
+typedef struct {
+ tBTA_HL_STATUS status; /* start status */
+ uint8_t app_id;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DEREGISTER_CFM;
+
+typedef struct {
+ bool intentional;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_CCH_CLOSE_IND;
+
+typedef struct {
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status; /* connection status */
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MCL_CFM;
+
+typedef struct {
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status; /* connection status */
+ uint8_t app_id;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr; /* address of peer device */
+} tBTA_HL_CCH_OPEN_CFM;
+
+typedef struct {
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_CFG cfg; /* dch cfg requested by the peer device */
+ BD_ADDR bd_addr; /* address of peer device */
+
+} tBTA_HL_DCH_CREATE_IND;
+
+typedef struct {
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+
+ bool first_reliable; /* whether this is the first reliable data channel */
+ uint16_t mtu;
+} tBTA_HL_DCH_OPEN_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status; /* connection status */
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ tBTA_HL_MDL_ID mdl_id; /* MCAP data link ID for this
+ data channel conenction */
+ tBTA_HL_DCH_MODE dch_mode; /* data channel mode - reliable or streaming*/
+ bool first_reliable; /* whether this is the first reliable data channel */
+ uint16_t mtu;
+} tBTA_HL_DCH_OPEN_CFM;
+
+typedef struct {
+ bool intentional;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_DCH_CLOSE_IND;
+
+typedef struct {
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+} tBTA_HL_MDL_CFM;
+
+typedef struct {
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ tBTA_HL_MDL_ID mdl_id;
+} tBTA_HL_DELETE_MDL_CFM;
+
+typedef struct {
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ tBTA_HL_APP_HANDLE app_handle;
+ bool cong;
+} tBTA_HL_DCH_CONG_IND;
+
+typedef struct {
+ tBTA_HL_APP_HANDLE app_handle;
+ uint16_t ctrl_psm;
+ uint16_t data_psm;
+ uint8_t data_x_spec;
+ uint8_t mcap_sup_procs;
+} tBTA_HL_SDP_INFO_IND;
+
+typedef struct {
+ tBTA_HL_STATUS status;
+ uint8_t app_id;
+ tBTA_HL_APP_HANDLE app_handle;
+ BD_ADDR bd_addr;
+ tBTA_HL_SDP* p_sdp;
+} tBTA_HL_SDP_QUERY_CFM;
+
+typedef union {
+ tBTA_HL_REGISTER_CFM reg_cfm;
+ tBTA_HL_DEREGISTER_CFM dereg_cfm;
+ tBTA_HL_CCH_OPEN_IND cch_open_ind;
+ tBTA_HL_CCH_OPEN_CFM cch_open_cfm;
+ tBTA_HL_CCH_CLOSE_IND cch_close_ind;
+ tBTA_HL_MCL_CFM cch_close_cfm;
+ tBTA_HL_DCH_CREATE_IND dch_create_ind;
+ tBTA_HL_DCH_OPEN_IND dch_open_ind;
+ tBTA_HL_DCH_OPEN_CFM dch_open_cfm;
+ tBTA_HL_DCH_CLOSE_IND dch_close_ind;
+ tBTA_HL_MDL_CFM dch_close_cfm;
+ tBTA_HL_DCH_OPEN_IND dch_reconnect_ind;
+ tBTA_HL_DCH_OPEN_CFM dch_reconnect_cfm;
+ tBTA_HL_MCL_IND dch_abort_ind;
+ tBTA_HL_MCL_CFM dch_abort_cfm;
+ tBTA_HL_DELETE_MDL_IND delete_mdl_ind;
+ tBTA_HL_DELETE_MDL_CFM delete_mdl_cfm;
+ tBTA_HL_MDL_CFM dch_send_data_cfm;
+ tBTA_HL_MDL_IND dch_rcv_data_ind;
+ tBTA_HL_DCH_CONG_IND dch_cong_ind;
+ tBTA_HL_MCL_CFM echo_test_cfm;
+ tBTA_HL_SDP_QUERY_CFM sdp_query_cfm;
+ tBTA_HL_SDP_INFO_IND sdp_info_ind;
+
+} tBTA_HL;
+
+/* HL callback functions */
+typedef void tBTA_HL_CTRL_CBACK(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data);
+typedef void tBTA_HL_CBACK(tBTA_HL_EVT event, tBTA_HL* p_data);
+
+/**M: Bug fix for add a global value @{*/
+extern tBTA_HL_SDP g_bta_sdp;
+/**@}*/
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/**************************
+ * API Functions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_HlEnable
+ *
+ * Description Enable the HL subsystems. This function must be
+ * called before any other functions in the HL API are called.
+ * When the enable operation is completed the callback function
+ * will be called with an BTA_HL_CTRL_ENABLE_CFM_EVT event.
+ *
+ * Parameters p_cback - HL event call back function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlEnable(tBTA_HL_CTRL_CBACK* p_ctrl_cback);
+/*******************************************************************************
+ *
+ * Function BTA_HlDisable
+ *
+ * Description Disable the HL subsystem.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlUpdate
+ *
+ * Description Register an HDP application
+ *
+ * Parameters app_id - Application ID
+ * p_reg_param - non-platform related parameters for the
+ * HDP application
+ * p_cback - HL event callback fucntion
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlUpdate(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+ bool is_register, tBTA_HL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlRegister
+ *
+ * Description Register a HDP application
+ *
+ *
+ * Parameters app_id - hdp application ID
+ * p_reg_param - non-platform related parameters for the
+ * HDP application
+ * p_cback - HL event callback fucntion
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlRegister(uint8_t app_id, tBTA_HL_REG_PARAM* p_reg_param,
+ tBTA_HL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDeregister
+ *
+ * Description Deregister an HDP application
+ *
+ * Parameters app_handle - Application handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDeregister(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlCchOpen
+ *
+ * Description Open a Control channel connection with the specified BD
+ * address and the control PSM value is used to select which
+ * HDP insatnce should be used in case the peer device support
+ * multiple HDP instances.
+ *
+ *
+ * Parameters app_handle - Application Handle
+ * p_open_param - parameters for opening a control channel
+ *
+ * Returns void
+ *
+ * Note: If the control PSM value is zero then the first HDP
+ * instance is used for the control channel setup
+ ******************************************************************************/
+extern void BTA_HlCchOpen(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+ tBTA_HL_CCH_OPEN_PARAM* p_open_param);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlCchClose
+ *
+ * Description Close a Control channel connection with the specified MCL
+ * handle
+ *
+ * Parameters mcl_handle - MCL handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlCchClose(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchOpen
+ *
+ * Description Open a data channel connection with the specified DCH
+ * parameters
+ *
+ * Parameters mcl_handle - MCL handle
+ * p_open_param - parameters for opening a data channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchOpen(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_OPEN_PARAM* p_open_param);
+/*******************************************************************************
+ *
+ * Function BTA_HlDchReconnect
+ *
+ * Description Reconnect a data channel with the specified MDL_ID
+ *
+ * Parameters mcl_handle - MCL handle
+*8 p_recon_param - parameters for reconnecting a data channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchReconnect(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_RECONNECT_PARAM* p_recon_param);
+/*******************************************************************************
+ *
+ * Function BTA_HlDchClose
+ *
+ * Description Close a data channel with the specified MDL handle
+ *
+ * Parameters mdl_handle - MDL handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchClose(tBTA_HL_MDL_HANDLE mdl_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchAbort
+ *
+ * Description Abort the current data channel setup with the specified MCL
+ * handle
+ *
+ * Parameters mcl_handle - MCL handle
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchAbort(tBTA_HL_MCL_HANDLE mcl_handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlSendData
+ *
+ * Description Send an APDU to the peer device
+ *
+ * Parameters mdl_handle - MDL handle
+ * pkt_size - size of the data packet to be sent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlSendData(tBTA_HL_MDL_HANDLE mdl_handle, uint16_t pkt_size);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDeleteMdl
+ *
+ * Description Delete the specified MDL_ID within the specified MCL handle
+ *
+ * Parameters mcl_handle - MCL handle
+ * mdl_id - MDL ID
+ *
+ * Returns void
+ *
+ * note: If mdl_id = 0xFFFF then this means to delete all MDLs
+ * and this value can only be used with DeleteMdl request
+ * only not other requests
+ *
+ ******************************************************************************/
+extern void BTA_HlDeleteMdl(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_MDL_ID mdl_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchEchoTest
+ *
+ * Description Initiate an echo test with the specified MCL handle
+ *
+ * Parameters mcl_handle - MCL handle
+*8 p_echo_test_param - parameters for echo testing
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchEchoTest(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_ECHO_TEST_PARAM* p_echo_test_param);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlSdpQuery
+ *
+ * Description SDP query request for the specified BD address
+ *
+ * Parameters app_id
+ app_handle - application handle
+ * bd_addr - BD address
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlSdpQuery(uint8_t app_id, tBTA_HL_APP_HANDLE app_handle,
+ BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_HlDchCreateMdlRsp
+ *
+ * Description Set the Response and configuration values for the Create MDL
+ * request
+ *
+ * Parameters mcl_handle - MCL handle
+ * p_rsp_param - parameters specified whether the request
+ * should be accepted or not and if it should be
+ * accepted then it also specified the
+ * configuration response value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_HlDchCreateRsp(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_DCH_CREATE_RSP_PARAM* p_rsp_param);
+
+#endif /* BTA_HL_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hl_ci.h b/mtkbt/code/bt/bta/include/bta_hl_ci.h
new file mode 100755
index 0000000..ad1499f
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hl_ci.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for the HL (HeaLth device profile) subsystem
+ * call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_CI_H
+#define BTA_HL_CI_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+/*****************************************************************************
+ * Constants and Data Types
+ ****************************************************************************/
+/**************************
+ * Common Definitions
+ **************************/
+/* Read Ready Event */
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+/**************************
+ * Common Functions
+ **************************/
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_get_tx_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_get_tx_data call-out function.
+ *
+ * Parameters mdl_handle -MDL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_tx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_put_rx_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_put_rx_data call-out function.
+ *
+ * Parameters mdl_handle -MDL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_rx_data(tBTA_HL_MDL_HANDLE mdl_handle,
+ tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_get_echo_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_get_echo_data call-out function.
+ *
+ * Parameters mcl_handle -MCL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_get_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status, uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_ci_put_echo_data
+ *
+ * Description This function is called in response to the
+ * bta_hl_co_put_echo_data call-out function.
+ *
+ * Parameters mcl_handle -MCL handle
+ * status - BTA_MA_STATUS_OK if operation is successful
+ * BTA_MA_STATUS_FAIL if any errors have occurred.
+ * evt - evt from the call-out function
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_ci_put_echo_data(tBTA_HL_MCL_HANDLE mcl_handle,
+ tBTA_HL_STATUS status, uint16_t evt);
+
+#endif /* BTA_HL_CI_H */
diff --git a/mtkbt/code/bt/bta/include/bta_hl_co.h b/mtkbt/code/bt/bta/include/bta_hl_co.h
new file mode 100755
index 0000000..82b6243
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_hl_co.h
@@ -0,0 +1,240 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for the HL (HeaLth device profile) subsystem
+ * call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_HL_CO_H
+#define BTA_HL_CO_H
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+
+/*****************************************************************************
+ * Constants and Data Types
+ ****************************************************************************/
+/**************************
+ * Common Definitions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_num_of_mdep
+ *
+ * Description This function is called to get the number of MDEPs for this
+ * application ID
+ *
+ * Parameters app_id - application ID
+ * p_num_of_mdep (output) - number of MDEP configurations
+ * supported
+ * by the application
+ *
+ * Returns Bloolean - true success
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep);
+/*******************************************************************************
+ *
+ * Function bta_hl_co_advrtise_source_sdp
+ *
+ * Description This function is called to find out whether the SOURCE MDEP
+ * configuration information should be advertize in the SDP or
+ * not
+ *
+ * Parameters app_id - application ID
+ *
+ * Returns Bloolean - true advertise the SOURCE MDEP configuration
+ * information
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_advrtise_source_sdp(uint8_t app_id);
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_mdep_config
+ *
+ * Description This function is called to get the supported feature
+ * configuration for the specified mdep index and it also
+ * assigns
+ * the MDEP ID for the specified mdep index
+ *
+ * Parameters app_id - HDP application ID
+ * mdep_idx - the mdep index
+ * mdep_counter - mdep_counter
+ * mdep_id - the assigned MDEP ID for the specified medp_idx
+ * p_mdl_cfg (output) - pointer to the MDEP configuration
+ *
+ *
+ * Returns Bloolean - true success
+ ******************************************************************************/
+extern bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
+ uint8_t mdep_counter,
+ tBTA_HL_MDEP_ID mdep_id,
+ tBTA_HL_MDEP_CFG* p_mdep_cfg);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_echo_config
+ *
+ * Description This function is called to get the echo test
+ * maximum APDU size configuration
+ *
+ * Parameters app_id - HDP application ID
+ * p_echo_cfg (output) - pointer to the Echo test maximum APDU
+ * size configuration
+ *
+ * Returns Bloolean - true success
+ ******************************************************************************/
+extern bool bta_hl_co_get_echo_config(uint8_t app_id,
+ tBTA_HL_ECHO_CFG* p_echo_cfg);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_save_mdl
+ *
+ * Description This function is called to save a MDL configuration item in
+ * persistent storage
+ *
+ * Parameters app_id - HDP application ID
+ * item_idx - the MDL configuration storage index
+ * p_mdl_cfg - pointer to the MDL configuration data
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_save_mdl(uint8_t app_id, uint8_t item_idx,
+ tBTA_HL_MDL_CFG* p_mdl_cfg);
+/*******************************************************************************
+ *
+ * Function bta_hl_co_delete_mdl
+ *
+ * Description This function is called to delete a MDL configuration item in
+ * persistent storage
+ *
+ * Parameters app_id - HDP application ID
+ * item_idx - the MDL configuration storage index
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_delete_mdl(uint8_t app_id, uint8_t item_idx);
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_mdl_config
+ *
+ * Description This function is called to get the MDL configuration
+ * from teh persistent memory. This function shall only be
+*called
+*8 once after the device is powered up
+ *
+ * Parameters app_id - HDP application ID
+ * buffer_size - the unit of the buffer size is
+*sizeof(tBTA_HL_MDL_CFG)
+ * p_mdl_buf - Point to the starting location of the buffer
+ *
+ * Returns bool
+ *
+ *
+ ******************************************************************************/
+extern bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+ tBTA_HL_MDL_CFG* p_mdl_buf);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_tx_data
+ *
+ * Description Get the data to be sent
+ *
+ * Parameters app_id - HDP application ID
+ * mdl_handle - MDL handle
+ * buf_size - the size of the buffer
+ * p_buf - the buffer pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ uint16_t buf_size, uint8_t* p_buf,
+ uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_put_rx_data
+ *
+ * Description Put the received data
+ *
+ * Parameters app_id - HDP application ID
+ * mdl_handle - MDL handle
+ * data_size - the size of the data
+ * p_data - the data pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_put_rx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ uint16_t data_size, uint8_t* p_data,
+ uint16_t evt);
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_tx_data
+ *
+ * Description Get the Echo data to be sent
+ *
+ * Parameters app_id - HDP application ID
+ * mcl_handle - MCL handle
+ * buf_size - the size of the buffer
+ * p_buf - the buffer pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_get_echo_data(uint8_t app_id,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ uint16_t buf_size, uint8_t* p_buf,
+ uint16_t evt);
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_put_echo_data
+ *
+ * Description Put the received loopback echo data
+ *
+ * Parameters app_id - HDP application ID
+ * mcl_handle - MCL handle
+ * data_size - the size of the data
+ * p_data - the data pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_put_echo_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+extern void bta_hl_co_put_echo_data(uint8_t app_id,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ uint16_t data_size, uint8_t* p_data,
+ uint16_t evt);
+
+#endif /* BTA_HL_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_jv_api.h b/mtkbt/code/bt/bta/include/bta_jv_api.h
new file mode 100755
index 0000000..046ed81
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_jv_api.h
@@ -0,0 +1,832 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_API_H
+#define BTA_JV_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* status values */
+#define BTA_JV_SUCCESS 0 /* Successful operation. */
+#define BTA_JV_FAILURE 1 /* Generic failure. */
+#define BTA_JV_BUSY 2 /* Temporarily can not handle this request. */
+#define BTA_JV_NO_DATA 3 /* no data. */
+#define BTA_JV_NO_RESOURCE 4 /* No more set pm control block */
+
+typedef uint8_t tBTA_JV_STATUS;
+#define BTA_JV_INTERNAL_ERR (-1) /* internal error. */
+
+#define BTA_JV_MAX_UUIDS SDP_MAX_UUID_FILTERS
+#define BTA_JV_MAX_ATTRS SDP_MAX_ATTR_FILTERS
+#define BTA_JV_MAX_SDP_REC SDP_MAX_RECORDS
+#define BTA_JV_MAX_L2C_CONN \
+ GAP_MAX_CONNECTIONS /* GAP handle is used as index, hence do not change this \
+ value */
+#define BTA_JV_MAX_SCN \
+ PORT_MAX_RFC_PORTS /* same as BTM_MAX_SCN (in btm_int.h) */
+#define BTA_JV_MAX_RFC_CONN MAX_RFC_PORTS
+
+#ifndef BTA_JV_DEF_RFC_MTU
+#define BTA_JV_DEF_RFC_MTU (3 * 330)
+#endif
+
+#ifndef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS
+#endif
+
+/* BTA_JV_MAX_RFC_SR_SESSION can not be bigger than MAX_BD_CONNECTIONS */
+#if (BTA_JV_MAX_RFC_SR_SESSION > MAX_BD_CONNECTIONS)
+#undef BTA_JV_MAX_RFC_SR_SESSION
+#define BTA_JV_MAX_RFC_SR_SESSION MAX_BD_CONNECTIONS
+#endif
+
+#define BTA_JV_FIRST_SERVICE_ID BTA_FIRST_JV_SERVICE_ID
+#define BTA_JV_LAST_SERVICE_ID BTA_LAST_JV_SERVICE_ID
+#define BTA_JV_NUM_SERVICE_ID \
+ (BTA_LAST_JV_SERVICE_ID - BTA_FIRST_JV_SERVICE_ID + 1)
+
+/* Discoverable modes */
+enum { BTA_JV_DISC_NONE, BTA_JV_DISC_LIMITED, BTA_JV_DISC_GENERAL };
+typedef uint16_t tBTA_JV_DISC;
+
+#define BTA_JV_ROLE_SLAVE BTM_ROLE_SLAVE
+#define BTA_JV_ROLE_MASTER BTM_ROLE_MASTER
+typedef uint32_t tBTA_JV_ROLE;
+
+#define BTA_JV_SERVICE_LMTD_DISCOVER \
+ BTM_COD_SERVICE_LMTD_DISCOVER /* 0x0020 \
+ */
+#define BTA_JV_SERVICE_POSITIONING BTM_COD_SERVICE_POSITIONING /* 0x0100 */
+#define BTA_JV_SERVICE_NETWORKING BTM_COD_SERVICE_NETWORKING /* 0x0200 */
+#define BTA_JV_SERVICE_RENDERING BTM_COD_SERVICE_RENDERING /* 0x0400 */
+#define BTA_JV_SERVICE_CAPTURING BTM_COD_SERVICE_CAPTURING /* 0x0800 */
+#define BTA_JV_SERVICE_OBJ_TRANSFER BTM_COD_SERVICE_OBJ_TRANSFER /* 0x1000 */
+#define BTA_JV_SERVICE_AUDIO BTM_COD_SERVICE_AUDIO /* 0x2000 */
+#define BTA_JV_SERVICE_TELEPHONY BTM_COD_SERVICE_TELEPHONY /* 0x4000 */
+#define BTA_JV_SERVICE_INFORMATION BTM_COD_SERVICE_INFORMATION /* 0x8000 */
+
+/* JV ID type */
+#define BTA_JV_PM_ID_1 1 /* PM example profile 1 */
+#define BTA_JV_PM_ID_2 2 /* PM example profile 2 */
+#define BTA_JV_PM_ID_CLEAR 0 /* Special JV ID used to clear PM profile */
+#define BTA_JV_PM_ALL 0xFF /* Generic match all id, see bta_dm_cfg.c */
+typedef uint8_t tBTA_JV_PM_ID;
+
+#define BTA_JV_PM_HANDLE_CLEAR \
+ 0xFF /* Special JV ID used to clear PM profile */
+
+/* define maximum number of registered PM entities. should be in sync with bta
+ * pm! */
+#ifndef BTA_JV_PM_MAX_NUM
+#define BTA_JV_PM_MAX_NUM 5
+#endif
+
+/* JV pm connection states */
+enum {
+ BTA_JV_CONN_OPEN = 0, /* Connection opened state */
+ BTA_JV_CONN_CLOSE, /* Connection closed state */
+ BTA_JV_APP_OPEN, /* JV Application opened state */
+ BTA_JV_APP_CLOSE, /* JV Application closed state */
+ BTA_JV_SCO_OPEN, /* SCO connection opened state */
+ BTA_JV_SCO_CLOSE, /* SCO connection opened state */
+ BTA_JV_CONN_IDLE, /* Connection idle state */
+ BTA_JV_CONN_BUSY, /* Connection busy state */
+ BTA_JV_MAX_CONN_STATE /* Max number of connection state */
+};
+typedef uint8_t tBTA_JV_CONN_STATE;
+
+/* JV Connection types */
+#define BTA_JV_CONN_TYPE_RFCOMM 0
+#define BTA_JV_CONN_TYPE_L2CAP 1
+#define BTA_JV_CONN_TYPE_L2CAP_LE 2
+
+/* Java I/F callback events */
+/* events received by tBTA_JV_DM_CBACK */
+#define BTA_JV_ENABLE_EVT 0 /* JV enabled */
+#define BTA_JV_GET_SCN_EVT 6 /* Reserved an SCN */
+#define BTA_JV_GET_PSM_EVT 7 /* Reserved a PSM */
+#define BTA_JV_DISCOVERY_COMP_EVT 8 /* SDP discovery complete */
+#define BTA_JV_CREATE_RECORD_EVT 11 /* the result for BTA_JvCreateRecord */
+/* events received by tBTA_JV_L2CAP_CBACK */
+#define BTA_JV_L2CAP_OPEN_EVT 16 /* open status of L2CAP connection */
+#define BTA_JV_L2CAP_CLOSE_EVT 17 /* L2CAP connection closed */
+#define BTA_JV_L2CAP_START_EVT 18 /* L2CAP server started */
+#define BTA_JV_L2CAP_CL_INIT_EVT 19 /* L2CAP client initiated a connection */
+#define BTA_JV_L2CAP_DATA_IND_EVT 20 /* L2CAP connection received data */
+#define BTA_JV_L2CAP_CONG_EVT \
+ 21 /* L2CAP connection congestion status changed */
+#define BTA_JV_L2CAP_READ_EVT 22 /* the result for BTA_JvL2capRead */
+#define BTA_JV_L2CAP_WRITE_EVT 24 /* the result for BTA_JvL2capWrite*/
+#define BTA_JV_L2CAP_WRITE_FIXED_EVT \
+ 25 /* the result for BTA_JvL2capWriteFixed */
+
+/* events received by tBTA_JV_RFCOMM_CBACK */
+#define BTA_JV_RFCOMM_OPEN_EVT \
+ 26 /* open status of RFCOMM Client connection \
+ */
+#define BTA_JV_RFCOMM_CLOSE_EVT 27 /* RFCOMM connection closed */
+#define BTA_JV_RFCOMM_START_EVT 28 /* RFCOMM server started */
+#define BTA_JV_RFCOMM_CL_INIT_EVT \
+ 29 /* RFCOMM client initiated a connection \
+ */
+#define BTA_JV_RFCOMM_DATA_IND_EVT 30 /* RFCOMM connection received data */
+#define BTA_JV_RFCOMM_CONG_EVT \
+ 31 /* RFCOMM connection congestion status changed */
+#define BTA_JV_RFCOMM_WRITE_EVT 33 /* the result for BTA_JvRfcommWrite*/
+#define BTA_JV_RFCOMM_SRV_OPEN_EVT \
+ 34 /* open status of Server RFCOMM connection */
+#define BTA_JV_MAX_EVT 35 /* max number of JV events */
+
+typedef uint16_t tBTA_JV_EVT;
+
+/* data associated with BTA_JV_SET_DISCOVER_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ tBTA_JV_DISC disc_mode; /* The current discoverable mode */
+} tBTA_JV_SET_DISCOVER;
+
+/* data associated with BTA_JV_DISCOVERY_COMP_EVT_ */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ int scn; /* channel # */
+} tBTA_JV_DISCOVERY_COMP;
+
+/* data associated with BTA_JV_CREATE_RECORD_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+} tBTA_JV_CREATE_RECORD;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ BD_ADDR rem_bda; /* The peer address */
+ int32_t tx_mtu; /* The transmit MTU */
+} tBTA_JV_L2CAP_OPEN;
+
+/* data associated with BTA_JV_L2CAP_OPEN_EVT for LE sockets */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ BD_ADDR rem_bda; /* The peer address */
+ int32_t tx_mtu; /* The transmit MTU */
+ void** p_p_cback; /* set them for new socket */
+ void** p_user_data; /* set them for new socket */
+
+} tBTA_JV_L2CAP_LE_OPEN;
+
+/* data associated with BTA_JV_L2CAP_CLOSE_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ bool async; /* false, if local initiates disconnect */
+} tBTA_JV_L2CAP_CLOSE;
+
+/* data associated with BTA_JV_L2CAP_START_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint8_t sec_id; /* security ID used by this server */
+} tBTA_JV_L2CAP_START;
+
+/* data associated with BTA_JV_L2CAP_CL_INIT_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint8_t sec_id; /* security ID used by this client */
+} tBTA_JV_L2CAP_CL_INIT;
+
+/* data associated with BTA_JV_L2CAP_CONG_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ bool cong; /* true, congested. false, uncongested */
+} tBTA_JV_L2CAP_CONG;
+
+/* data associated with BTA_JV_L2CAP_READ_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint32_t req_id; /* The req_id in the associated BTA_JvL2capRead() */
+ uint8_t* p_data; /* This points the same location as the p_data
+ * parameter in BTA_JvL2capRead () */
+ uint16_t len; /* The length of the data read. */
+} tBTA_JV_L2CAP_READ;
+
+/* data associated with BTA_JV_L2CAP_WRITE_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint32_t req_id; /* The req_id in the associated BTA_JvL2capWrite() */
+ uint16_t len; /* The length of the data written. */
+ uint8_t* p_data; /* The buffer where data is held */
+ bool cong; /* congestion status */
+} tBTA_JV_L2CAP_WRITE;
+
+/* data associated with BTA_JV_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint16_t channel; /* The connection channel */
+ BD_ADDR addr; /* The peer address */
+ uint32_t req_id; /* The req_id in the associated BTA_JvL2capWrite() */
+ uint8_t* p_data; /* The buffer where data is held */
+ uint16_t len; /* The length of the data written. */
+ bool cong; /* congestion status */
+} tBTA_JV_L2CAP_WRITE_FIXED;
+
+/* data associated with BTA_JV_RFCOMM_OPEN_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ BD_ADDR rem_bda; /* The peer address */
+} tBTA_JV_RFCOMM_OPEN;
+/* data associated with BTA_JV_RFCOMM_SRV_OPEN_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint32_t new_listen_handle; /* The new listen handle */
+ BD_ADDR rem_bda; /* The peer address */
+} tBTA_JV_RFCOMM_SRV_OPEN;
+
+/* data associated with BTA_JV_RFCOMM_CLOSE_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t port_status; /* PORT status */
+ uint32_t handle; /* The connection handle */
+ bool async; /* false, if local initiates disconnect */
+} tBTA_JV_RFCOMM_CLOSE;
+
+/* data associated with BTA_JV_RFCOMM_START_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint8_t sec_id; /* security ID used by this server */
+ bool use_co; /* true to use co_rfc_data */
+} tBTA_JV_RFCOMM_START;
+
+/* data associated with BTA_JV_RFCOMM_CL_INIT_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint8_t sec_id; /* security ID used by this client */
+ bool use_co; /* true to use co_rfc_data */
+} tBTA_JV_RFCOMM_CL_INIT;
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT & BTA_JV_RFCOMM_DATA_IND_EVT */
+typedef struct {
+ uint32_t handle; /* The connection handle */
+} tBTA_JV_DATA_IND;
+
+/*data associated with BTA_JV_L2CAP_DATA_IND_EVT if used for LE */
+typedef struct {
+ uint32_t handle; /* The connection handle */
+ BT_HDR* p_buf; /* The incoming data */
+} tBTA_JV_LE_DATA_IND;
+
+/* data associated with BTA_JV_RFCOMM_CONG_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ bool cong; /* true, congested. false, uncongested */
+} tBTA_JV_RFCOMM_CONG;
+
+/* data associated with BTA_JV_RFCOMM_WRITE_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Whether the operation succeeded or failed. */
+ uint32_t handle; /* The connection handle */
+ uint32_t req_id; /* The req_id in the associated BTA_JvRfcommWrite() */
+ int len; /* The length of the data written. */
+ bool cong; /* congestion status */
+} tBTA_JV_RFCOMM_WRITE;
+
+/* data associated with BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+ tBTA_JV_STATUS status; /* Status of the operation */
+ uint32_t handle; /* Connection handle */
+ tBTA_JV_PM_ID app_id; /* JV app ID */
+} tBTA_JV_SET_PM_PROFILE;
+
+/* data associated with BTA_JV_API_NOTIFY_PM_STATE_CHANGE_EVT */
+typedef struct {
+ uint32_t handle; /* Connection handle */
+ tBTA_JV_CONN_STATE state; /* JV connection stata */
+} tBTA_JV_NOTIFY_PM_STATE_CHANGE;
+
+/* union of data associated with JV callback */
+typedef union {
+ tBTA_JV_STATUS status; /* BTA_JV_ENABLE_EVT */
+ tBTA_JV_DISCOVERY_COMP disc_comp; /* BTA_JV_DISCOVERY_COMP_EVT */
+ tBTA_JV_SET_DISCOVER set_discover; /* BTA_JV_SET_DISCOVER_EVT */
+ uint8_t scn; /* BTA_JV_GET_SCN_EVT */
+ uint16_t psm; /* BTA_JV_GET_PSM_EVT */
+ tBTA_JV_CREATE_RECORD create_rec; /* BTA_JV_CREATE_RECORD_EVT */
+ tBTA_JV_L2CAP_OPEN l2c_open; /* BTA_JV_L2CAP_OPEN_EVT */
+ tBTA_JV_L2CAP_CLOSE l2c_close; /* BTA_JV_L2CAP_CLOSE_EVT */
+ tBTA_JV_L2CAP_START l2c_start; /* BTA_JV_L2CAP_START_EVT */
+ tBTA_JV_L2CAP_CL_INIT l2c_cl_init; /* BTA_JV_L2CAP_CL_INIT_EVT */
+ tBTA_JV_L2CAP_CONG l2c_cong; /* BTA_JV_L2CAP_CONG_EVT */
+ tBTA_JV_L2CAP_READ l2c_read; /* BTA_JV_L2CAP_READ_EVT */
+ tBTA_JV_L2CAP_WRITE l2c_write; /* BTA_JV_L2CAP_WRITE_EVT */
+ tBTA_JV_RFCOMM_OPEN rfc_open; /* BTA_JV_RFCOMM_OPEN_EVT */
+ tBTA_JV_RFCOMM_SRV_OPEN rfc_srv_open; /* BTA_JV_RFCOMM_SRV_OPEN_EVT */
+ tBTA_JV_RFCOMM_CLOSE rfc_close; /* BTA_JV_RFCOMM_CLOSE_EVT */
+ tBTA_JV_RFCOMM_START rfc_start; /* BTA_JV_RFCOMM_START_EVT */
+ tBTA_JV_RFCOMM_CL_INIT rfc_cl_init; /* BTA_JV_RFCOMM_CL_INIT_EVT */
+ tBTA_JV_RFCOMM_CONG rfc_cong; /* BTA_JV_RFCOMM_CONG_EVT */
+ tBTA_JV_RFCOMM_WRITE rfc_write; /* BTA_JV_RFCOMM_WRITE_EVT */
+ tBTA_JV_DATA_IND data_ind; /* BTA_JV_L2CAP_DATA_IND_EVT
+ BTA_JV_RFCOMM_DATA_IND_EVT */
+ tBTA_JV_LE_DATA_IND le_data_ind; /* BTA_JV_L2CAP_LE_DATA_IND_EVT */
+ tBTA_JV_L2CAP_LE_OPEN l2c_le_open; /* BTA_JV_L2CAP_OPEN_EVT */
+ tBTA_JV_L2CAP_WRITE_FIXED l2c_write_fixed; /* BTA_JV_L2CAP_WRITE_FIXED_EVT */
+} tBTA_JV;
+
+/* JAVA DM Interface callback */
+typedef void(tBTA_JV_DM_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id);
+
+/* JAVA RFCOMM interface callback */
+typedef uint32_t(tBTA_JV_RFCOMM_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t rfcomm_slot_id);
+
+/* JAVA L2CAP interface callback */
+typedef void(tBTA_JV_L2CAP_CBACK)(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t l2cap_socket_id);
+
+/* JV configuration structure */
+typedef struct {
+ uint16_t sdp_raw_size; /* The size of p_sdp_raw_data */
+ uint16_t sdp_db_size; /* The size of p_sdp_db */
+ uint8_t* p_sdp_raw_data; /* The data buffer to keep raw data */
+ tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_JV_CFG;
+
+/*******************************************************************************
+ *
+ * Function BTA_JvEnable
+ *
+ * Description Enable the Java I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_JV_ENABLE_EVT. This function must
+ * be called before other functions in the JV API are
+ * called.
+ *
+ * Returns BTA_JV_SUCCESS if successful.
+ * BTA_JV_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvDisable
+ *
+ * Description Disable the Java I/F
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_JvDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvIsEncrypted
+ *
+ * Description This function checks if the link to peer device is encrypted
+ *
+ * Returns true if encrypted.
+ * false if not.
+ *
+ ******************************************************************************/
+bool BTA_JvIsEncrypted(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvGetChannelId
+ *
+ * Description This function reserves a SCN/PSM for applications running
+ * over RFCOMM or L2CAP. It is primarily called by
+ * server profiles/applications to register their SCN/PSM into
+ * the SDP database. The SCN is reported by the
+ * tBTA_JV_DM_CBACK callback with a BTA_JV_GET_SCN_EVT.
+ * If the SCN/PSM reported is 0, that means all SCN resources
+ * are exhausted.
+ * The channel parameter can be used to request a specific
+ * channel. If the request on the specific channel fails, the
+ * SCN/PSM returned in the EVT will be 0 - no attempt to
+ * request a new channel will be made. set channel to <= 0 to
+ * automatically assign an channel ID.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvFreeChannel
+ *
+ * Description This function frees a SCN/PSM that was used
+ * by an application running over RFCOMM or L2CAP.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvStartDiscovery
+ *
+ * Description This function performs service discovery for the services
+ * provided by the given peer device. When the operation is
+ * complete the tBTA_JV_DM_CBACK callback function will be
+ * called with a BTA_JV_DISCOVERY_COMP_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, uint16_t num_uuid,
+ tSDP_UUID* p_uuid_list,
+ uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvCreateRecordByUser
+ *
+ * Description Create a service record in the local SDP database by user in
+ * tBTA_JV_DM_CBACK callback with a BTA_JV_CREATE_RECORD_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvCreateRecordByUser(uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvDeleteRecord
+ *
+ * Description Delete a service record in the local SDP database.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capConnectLE
+ *
+ * Description Initiate a connection as an LE L2CAP client to the given BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t remote_chan, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capConnect
+ *
+ * Description Initiate a connection as a L2CAP client to the given BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask,
+ tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t remote_psm, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capClose
+ *
+ * Description This function closes an L2CAP client connection
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capCloseLE
+ *
+ * Description This function closes an L2CAP client connection for Fixed
+ * Channels Function is idempotent and no callbacks are called!
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStartServer
+ *
+ * Description This function starts an L2CAP server and listens for an
+ * L2CAP connection from a remote Bluetooth device. When the
+ * server is started successfully, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_START_EVT. When the connection is
+ * established, tBTA_JV_L2CAP_CBACK is called with
+ * BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask,
+ tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t local_psm, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStartServerLE
+ *
+ * Description This function starts an LE L2CAP server and listens for an
+ * L2CAP connection from a remote Bluetooth device on a fixed
+ * channel over an LE link. When the server
+ * is started successfully, tBTA_JV_L2CAP_CBACK is called with
+ * BTA_JV_L2CAP_START_EVT. When the connection is established,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t local_chan, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStopServerLE
+ *
+ * Description This function stops the LE L2CAP server. If the server has
+ * an active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(uint16_t local_chan,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStopServer
+ *
+ * Description This function stops the L2CAP server. If the server has
+ * an active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(uint16_t local_psm,
+ uint32_t l2cap_socket_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capRead
+ *
+ * Description This function reads data from an L2CAP connection
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_READ_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(uint32_t handle, uint32_t req_id,
+ uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capReady
+ *
+ * Description This function determined if there is data to read from
+ * an L2CAP connection
+ *
+ * Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+ * BTA_JV_FAILURE, if error.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(uint32_t handle, uint32_t* p_data_size);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capWrite
+ *
+ * Description This function writes data to an L2CAP connection
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ * PSM-based connections
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
+ uint8_t* p_data, uint16_t len,
+ uint32_t user_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capWriteFixed
+ *
+ * Description This function writes data to an L2CAP connection
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_WRITE_FIXED_EVT. Works for
+ * fixed-channel connections
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, BD_ADDR* addr,
+ uint32_t req_id,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint8_t* p_data, uint16_t len,
+ uint32_t user_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommConnect
+ *
+ * Description This function makes an RFCOMM conection to a remote BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_RFCOMM_CBACK is called with
+ * BTA_JV_RFCOMM_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ uint8_t remote_scn, BD_ADDR peer_bd_addr,
+ tBTA_JV_RFCOMM_CBACK* p_cback,
+ uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommClose
+ *
+ * Description This function closes an RFCOMM connection
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommStartServer
+ *
+ * Description This function starts listening for an RFCOMM connection
+ * request from a remote Bluetooth device. When the server is
+ * started successfully, tBTA_JV_RFCOMM_CBACK is called
+ * with BTA_JV_RFCOMM_START_EVT.
+ * When the connection is established, tBTA_JV_RFCOMM_CBACK
+ * is called with BTA_JV_RFCOMM_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ uint8_t local_scn, uint8_t max_session,
+ tBTA_JV_RFCOMM_CBACK* p_cback,
+ uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommStopServer
+ *
+ * Description This function stops the RFCOMM server. If the server has an
+ * active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStopServer(uint32_t handle, uint32_t rfcomm_slot_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommWrite
+ *
+ * Description This function writes data to an RFCOMM connection
+ * When the operation is complete, tBTA_JV_RFCOMM_CBACK is
+ * called with BTA_JV_RFCOMM_WRITE_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommWrite(uint32_t handle, uint32_t req_id);
+
+/*******************************************************************************
+ *
+ * Function BTA_JVSetPmProfile
+ *
+ * Description This function set or free power mode profile for different JV
+ * application
+ *
+ * Parameters: handle, JV handle from RFCOMM or L2CAP
+ * app_id: app specific pm ID, can be BTA_JV_PM_ALL, see
+ * bta_dm_cfg.c for details
+ * BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st
+ * is ignored and BTA_JV_CONN_CLOSE is called
+ * implicitly
+ * init_st: state after calling this API. typically it should be
+ * BTA_JV_CONN_OPEN
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ * NOTE: BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm
+ * calls automatically
+ * BTA_JV_CONN_CLOSE to remove in case of connection close!
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id,
+ tBTA_JV_CONN_STATE init_st);
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommGetPortHdl
+ *
+ * Description This function fetches the rfcomm port handle
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+uint16_t BTA_JvRfcommGetPortHdl(uint32_t handle);
+
+#endif /* BTA_JV_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_jv_co.h b/mtkbt/code/bt/bta/include/bta_jv_co.h
new file mode 100755
index 0000000..e3a4130
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_jv_co.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2007-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for java interface call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_CO_H
+#define BTA_JV_CO_H
+
+#include "bta_jv_api.h"
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bta_jv_co_rfc_data
+ *
+ * Description This function is called by JV to send data to the java glue
+ * code when the RX data path is configured to use a call-out
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+extern int bta_co_rfc_data_incoming(uint32_t rfcomm_slot_id, BT_HDR* p_buf);
+extern int bta_co_rfc_data_outgoing_size(uint32_t rfcomm_slot_id, int* size);
+extern int bta_co_rfc_data_outgoing(uint32_t rfcomm_slot_id, uint8_t* buf,
+ uint16_t size);
+
+#endif /* BTA_DG_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_mce_api.h b/mtkbt/code/bt/bta/include/bta_mce_api.h
new file mode 100755
index 0000000..e773689
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_mce_api.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file the BTA MCE I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_MCE_API_H
+#define BTA_MCE_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* status values */
+#define BTA_MCE_SUCCESS 0 /* Successful operation. */
+#define BTA_MCE_FAILURE 1 /* Generic failure. */
+#define BTA_MCE_BUSY 2 /* Temporarily can not handle this request. */
+
+typedef uint8_t tBTA_MCE_STATUS;
+
+/* MCE I/F callback events */
+/* events received by tBTA_MCE_DM_CBACK */
+#define BTA_MCE_ENABLE_EVT 0 /* MCE enabled */
+#define BTA_MCE_MAS_DISCOVERY_COMP_EVT 1 /* SDP MAS discovery complete */
+#define BTA_MCE_MAX_EVT 2 /* max number of MCE events */
+
+#define BTA_MCE_MAX_MAS_INSTANCES 12
+
+typedef uint16_t tBTA_MCE_EVT;
+
+typedef struct {
+ uint8_t scn;
+ char* p_srv_name;
+ uint16_t srv_name_len;
+ uint8_t instance_id;
+ uint8_t msg_type;
+} tBTA_MCE_MAS_INFO;
+
+/* data associated with BTA_MCE_MAS_DISCOVERY_COMP_EVT */
+typedef struct {
+ tBTA_MCE_STATUS status;
+ BD_ADDR remote_addr;
+ int num_mas;
+ tBTA_MCE_MAS_INFO mas[BTA_MCE_MAX_MAS_INSTANCES];
+} tBTA_MCE_MAS_DISCOVERY_COMP;
+
+/* union of data associated with MCE callback */
+typedef union {
+ tBTA_MCE_STATUS status; /* BTA_MCE_ENABLE_EVT */
+ tBTA_MCE_MAS_DISCOVERY_COMP
+ mas_disc_comp; /* BTA_MCE_MAS_DISCOVERY_COMP_EVT */
+} tBTA_MCE;
+
+/* MCE DM Interface callback */
+typedef void(tBTA_MCE_DM_CBACK)(tBTA_MCE_EVT event, tBTA_MCE* p_data,
+ void* user_data);
+
+/* MCE configuration structure */
+typedef struct {
+ uint16_t sdp_db_size; /* The size of p_sdp_db */
+ tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_MCE_CFG;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_MceEnable
+ *
+ * Description Enable the MCE I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_MCE_ENABLE_EVT. This function must
+ * be called before other functions in the MCE API are
+ * called.
+ *
+ * Returns BTA_MCE_SUCCESS if successful.
+ * BTA_MCE_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_MCE_STATUS BTA_MceEnable(tBTA_MCE_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_MceGetRemoteMasInstances
+ *
+ * Description This function performs service discovery for the MAS service
+ * by the given peer device. When the operation is completed
+ * the tBTA_MCE_DM_CBACK callback function will be called with
+ * a BTA_MCE_MAS_DISCOVERY_COMP_EVT.
+ *
+ * Returns BTA_MCE_SUCCESS, if the request is being processed.
+ * BTA_MCE_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_MCE_STATUS BTA_MceGetRemoteMasInstances(BD_ADDR bd_addr);
+
+#endif /* BTA_MCE_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_op_api.h b/mtkbt/code/bt/bta/include/bta_op_api.h
new file mode 100755
index 0000000..3918568
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_op_api.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the object push (OP) client and
+ * server subsystem of BTA, Broadcom's Bluetooth application layer for
+ * mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_OP_API_H
+#define BTA_OP_API_H
+
+#include "bta_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+/* Extra Debug Code */
+#ifndef BTA_OPS_DEBUG
+#define BTA_OPS_DEBUG false
+#endif
+
+#ifndef BTA_OPC_DEBUG
+#define BTA_OPC_DEBUG false
+#endif
+
+/* Object format */
+#define BTA_OP_VCARD21_FMT 1 /* vCard 2.1 */
+#define BTA_OP_VCARD30_FMT 2 /* vCard 3.0 */
+#define BTA_OP_VCAL_FMT 3 /* vCal 1.0 */
+#define BTA_OP_ICAL_FMT 4 /* iCal 2.0 */
+#define BTA_OP_VNOTE_FMT 5 /* vNote */
+#define BTA_OP_VMSG_FMT 6 /* vMessage */
+#define BTA_OP_OTHER_FMT 0xFF /* other format */
+
+typedef uint8_t tBTA_OP_FMT;
+
+/* Object format mask */
+#define BTA_OP_VCARD21_MASK 0x01 /* vCard 2.1 */
+#define BTA_OP_VCARD30_MASK 0x02 /* vCard 3.0 */
+#define BTA_OP_VCAL_MASK 0x04 /* vCal 1.0 */
+#define BTA_OP_ICAL_MASK 0x08 /* iCal 2.0 */
+#define BTA_OP_VNOTE_MASK 0x10 /* vNote */
+#define BTA_OP_VMSG_MASK 0x20 /* vMessage */
+#define BTA_OP_ANY_MASK 0x40 /* Any type of object. */
+
+typedef uint8_t tBTA_OP_FMT_MASK;
+
+#endif /* BTA_OP_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_pan_api.h b/mtkbt/code/bt/bta/include/bta_pan_api.h
new file mode 100755
index 0000000..bb4e724
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_pan_api.h
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the Personal Area Networking (PAN)
+ * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_API_H
+#define BTA_PAN_API_H
+
+#include "bta_api.h"
+#include "pan_api.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+#define BTA_PAN_SUCCESS 0
+#define BTA_PAN_FAIL 1
+
+typedef uint8_t tBTA_PAN_STATUS;
+
+/* PAN Callback events */
+#define BTA_PAN_ENABLE_EVT 0 /* PAN service is enabled. */
+#define BTA_PAN_SET_ROLE_EVT 1 /* PAN roles registered */
+#define BTA_PAN_OPENING_EVT 2 /* Connection is being opened. */
+#define BTA_PAN_OPEN_EVT 3 /* Connection has been opened. */
+#define BTA_PAN_CLOSE_EVT 4 /* Connection has been closed. */
+
+typedef uint8_t tBTA_PAN_EVT;
+
+/* pan roles */
+#define BTA_PAN_ROLE_PANU PAN_ROLE_CLIENT
+#define BTA_PAN_ROLE_GN PAN_ROLE_GN_SERVER
+#define BTA_PAN_ROLE_NAP PAN_ROLE_NAP_SERVER
+
+typedef uint8_t tBTA_PAN_ROLE;
+
+/* information regarding PAN roles */
+typedef struct {
+ const char* p_srv_name; /* service name for the PAN role */
+ uint8_t app_id; /* application id */
+ tBTA_SEC sec_mask; /* security setting for the role */
+
+} tBTA_PAN_ROLE_INFO;
+
+/* Event associated with BTA_PAN_SET_ROLE_EVT */
+typedef struct {
+ tBTA_PAN_STATUS status; /* status of set role event */
+ tBTA_PAN_ROLE role; /* PAN roles successfully registered */
+} tBTA_PAN_SET_ROLE;
+
+/* Event associated with BTA_PAN_OPENING_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address of peer device. */
+ uint16_t handle; /* Handle associated with this connection. */
+
+} tBTA_PAN_OPENING;
+
+/* Event associated with BTA_PAN_OPEN_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* BD address of peer device. */
+ uint16_t handle; /* Handle associated with this connection. */
+ tBTA_PAN_STATUS status; /* status of open event */
+ tBTA_PAN_ROLE local_role; /* Local device PAN role for the connection */
+ tBTA_PAN_ROLE peer_role; /* Peer device PAN role for the connection */
+
+} tBTA_PAN_OPEN;
+
+/* Event associated with BTA_PAN_CLOSE_EVT */
+typedef struct {
+ uint16_t handle; /* Handle associated with the connection. */
+} tBTA_PAN_CLOSE;
+
+/* Union of all PAN callback structures */
+typedef union {
+ tBTA_PAN_SET_ROLE set_role; /* set_role event */
+ tBTA_PAN_OPEN open; /* Connection has been opened. */
+ tBTA_PAN_OPENING opening; /* Connection being opened */
+ tBTA_PAN_CLOSE close; /* Connection has been closed. */
+} tBTA_PAN;
+
+/* Number of PAN connections */
+#ifndef BTA_PAN_NUM_CONN
+#define BTA_PAN_NUM_CONN 4
+#endif
+
+/* PAN callback */
+typedef void(tBTA_PAN_CBACK)(tBTA_PAN_EVT event, tBTA_PAN* p_data);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTA_PanEnable
+ *
+ * Description Enable PAN service. This function must be
+ * called before any other functions in the PAN API are called.
+ * When the enable operation is complete the callback function
+ * will be called with a BTA_PAN_ENABLE_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_PanEnable(tBTA_PAN_CBACK p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_PanDisable
+ *
+ * Description Disable PAN service.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_PanDisable(void);
+
+/*******************************************************************************
+ *
+ * Function BTA_PanSetRole
+ *
+ * Description Sets PAN roles. When the enable operation is complete
+ * the callback function will be called with a
+ * BTA_PAN_SET_ROLE_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO* p_user_info,
+ tBTA_PAN_ROLE_INFO* p_gn_info,
+ tBTA_PAN_ROLE_INFO* p_nap_info);
+
+/*******************************************************************************
+ *
+ * Function BTA_PanOpen
+ *
+ * Description Opens a connection to a peer device.
+ * When connection is open callback function is called
+ * with a BTA_PAN_OPEN_EVT.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role,
+ tBTA_PAN_ROLE peer_role);
+
+/*******************************************************************************
+ *
+ * Function BTA_PanClose
+ *
+ * Description Close a PAN connection to a peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTA_PanClose(uint16_t handle);
+
+#endif /* BTA_PAN_API_H */
diff --git a/mtkbt/code/bt/bta/include/bta_pan_ci.h b/mtkbt/code/bt/bta/include/bta_pan_ci.h
new file mode 100755
index 0000000..d14ea2b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_pan_ci.h
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for pan call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_CI_H
+#define BTA_PAN_CI_H
+
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_tx_ready
+ *
+ * Description This function sends an event to PAN indicating the phone is
+ * ready for more data and PAN should call
+ * bta_pan_co_tx_path().
+ * This function is used when the TX data path is configured
+ * to use a pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_tx_ready(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_rx_ready
+ *
+ * Description This function sends an event to PAN indicating the phone
+ * has data available to send to PAN and PAN should call
+ * bta_pan_co_rx_path(). This function is used when the RX
+ * data path is configured to use a pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_rx_ready(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_tx_flow
+ *
+ * Description This function is called to enable or disable data flow on
+ * the TX path. The phone should call this function to
+ * disable data flow when it is congested and cannot handle
+ * any more data sent by bta_pan_co_tx_write() or
+ * bta_pan_co_tx_writebuf(). This function is used when the
+ * TX data path is configured to use a push interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_tx_flow(uint16_t handle, bool enable);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_rx_writebuf
+ *
+ * Description This function is called to send data to the phone when
+ * the RX path is configured to use a push interface with
+ * zero copy. The function sends an event to PAN containing
+ * the data buffer. The buffer will be freed by BTA; the
+ * phone must not free the buffer.
+ *
+ *
+ * Returns true if flow enabled
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_rx_writebuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+ uint16_t protocol, BT_HDR* p_buf, bool ext);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_readbuf
+ *
+ * Description This function is called by the phone to read data from PAN
+ * when the TX path is configured to use a pull interface.
+ * The caller must free the buffer when it is through
+ * processing the buffer.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern BT_HDR* bta_pan_ci_readbuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+ uint16_t* p_protocol, bool* p_ext,
+ bool* p_forward);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_set_pfilters
+ *
+ * Description This function is called to set protocol filters
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_set_pfilters(uint16_t handle, uint16_t num_filters,
+ uint16_t* p_start_array,
+ uint16_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_set_mfilters
+ *
+ * Description This function is called to set multicast filters
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_ci_set_mfilters(uint16_t handle, uint16_t num_mcast_filters,
+ uint8_t* p_start_array,
+ uint8_t* p_end_array);
+
+#endif /* BTA_PAN_CI_H */
diff --git a/mtkbt/code/bt/bta/include/bta_pan_co.h b/mtkbt/code/bt/bta/include/bta_pan_co.h
new file mode 100755
index 0000000..14a45b3
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_pan_co.h
@@ -0,0 +1,199 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for data gateway call-out functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_CO_H
+#define BTA_PAN_CO_H
+
+#include "bta_pan_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* BT_HDR buffer offset */
+#define BTA_PAN_MIN_OFFSET PAN_MINIMUM_OFFSET
+
+/* Data Flow Mask */
+#define BTA_PAN_RX_PUSH 0x00 /* RX push. */
+#define BTA_PAN_RX_PUSH_BUF 0x01 /* RX push with zero copy. */
+#define BTA_PAN_RX_PULL 0x02 /* RX pull. */
+#define BTA_PAN_TX_PUSH 0x00 /* TX push. */
+#define BTA_PAN_TX_PUSH_BUF 0x10 /* TX push with zero copy. */
+#define BTA_PAN_TX_PULL 0x20 /* TX pull. */
+
+/*****************************************************************************
+ * Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_init
+ *
+ * Description This callout function is executed by PAN when a server is
+ * started by calling BTA_PanEnable(). This function can be
+ * used by the phone to initialize data paths or for other
+ * initialization purposes. The function must return the
+ * data flow mask as described below.
+ *
+ *
+ * Returns Data flow mask.
+ *
+ ******************************************************************************/
+extern uint8_t bta_pan_co_init(uint8_t* q_level);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_open
+ *
+ * Description This function is executed by PAN when a connection
+ * is opened. The phone can use this function to set
+ * up data paths or perform any required initialization.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_open(uint16_t handle, uint8_t app_id,
+ tBTA_PAN_ROLE local_role, tBTA_PAN_ROLE peer_role,
+ BD_ADDR peer_addr);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_close
+ *
+ * Description This function is called by PAN when a connection to a
+ * server is closed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_close(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_path
+ *
+ * Description This function is called by PAN to transfer data on the
+ * TX path; that is, data being sent from BTA to the phone.
+ * This function is used when the TX data path is configured
+ * to use the pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_rx_path
+ *
+ * Description This function is called by PAN to transfer data on the
+ * RX path; that is, data being sent from the phone to BTA.
+ * This function is used when the RX data path is configured
+ * to use the pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_rx_path(uint16_t handle, uint8_t app_id);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_write
+ *
+ * Description This function is called by PAN to send data to the phone
+ * when the TX path is configured to use a push interface.
+ * The implementation of this function must copy the data to
+ * the phone's memory.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_write(uint16_t handle, uint8_t app_id, BD_ADDR src,
+ BD_ADDR dst, uint16_t protocol, uint8_t* p_data,
+ uint16_t len, bool ext, bool forward);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_writebuf
+ *
+ * Description This function is called by PAN to send data to the phone
+ * when the TX path is configured to use a push interface with
+ * zero copy. The phone must free the buffer using function
+ * osi_free() when it is through processing the buffer.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_tx_writebuf(uint16_t handle, uint8_t app_id, BD_ADDR src,
+ BD_ADDR dst, uint16_t protocol,
+ BT_HDR* p_buf, bool ext, bool forward);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_rx_flow
+ *
+ * Description This function is called by PAN to enable or disable
+ * data flow on the RX path when it is configured to use
+ * a push interface. If data flow is disabled the phone must
+ * not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+ * until data flow is enabled again.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_rx_flow(uint16_t handle, uint8_t app_id, bool enable);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_filt_ind
+ *
+ * Description protocol filter indication from peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_pfilt_ind(uint16_t handle, bool indication,
+ tBTA_PAN_STATUS result, uint16_t len,
+ uint8_t* p_filters);
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_mfilt_ind
+ *
+ * Description multicast filter indication from peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_pan_co_mfilt_ind(uint16_t handle, bool indication,
+ tBTA_PAN_STATUS result, uint16_t len,
+ uint8_t* p_filters);
+
+#endif /* BTA_PAN_CO_H */
diff --git a/mtkbt/code/bt/bta/include/bta_sdp_api.h b/mtkbt/code/bt/bta/include/bta_sdp_api.h
new file mode 100755
index 0000000..1b98787
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/bta_sdp_api.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_API_H
+#define BTA_SDP_API_H
+
+#include <hardware/bt_sdp.h>
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "btm_api.h"
+
+/* status values */
+#define BTA_SDP_SUCCESS 0 /* Successful operation. */
+#define BTA_SDP_FAILURE 1 /* Generic failure. */
+#define BTA_SDP_BUSY 2 /* Temporarily can not handle this request. */
+
+typedef uint8_t tBTA_SDP_STATUS;
+
+/* SDP I/F callback events */
+/* events received by tBTA_SDP_DM_CBACK */
+#define BTA_SDP_ENABLE_EVT 0 /* SDP service i/f enabled*/
+#define BTA_SDP_SEARCH_EVT 1 /* SDP Service started */
+#define BTA_SDP_SEARCH_COMP_EVT 2 /* SDP search complete */
+#define BTA_SDP_CREATE_RECORD_USER_EVT 3 /* SDP search complete */
+#define BTA_SDP_REMOVE_RECORD_USER_EVT 4 /* SDP search complete */
+#define BTA_SDP_MAX_EVT 5 /* max number of SDP events */
+
+#define BTA_SDP_MAX_RECORDS 15
+
+typedef uint16_t tBTA_SDP_EVT;
+
+/* data associated with BTA_SDP_DISCOVERY_COMP_EVT */
+typedef struct {
+ tBTA_SDP_STATUS status;
+ BD_ADDR remote_addr;
+ tBT_UUID uuid;
+ int record_count;
+ bluetooth_sdp_record records[BTA_SDP_MAX_RECORDS];
+} tBTA_SDP_SEARCH_COMP;
+
+typedef union {
+ tBTA_SDP_STATUS status; /* BTA_SDP_SEARCH_EVT */
+ tBTA_SDP_SEARCH_COMP sdp_search_comp; /* BTA_SDP_SEARCH_COMP_EVT */
+} tBTA_SDP;
+
+/* SDP DM Interface callback */
+typedef void(tBTA_SDP_DM_CBACK)(tBTA_SDP_EVT event, tBTA_SDP* p_data,
+ void* user_data);
+
+/* MCE configuration structure */
+typedef struct {
+ uint16_t sdp_db_size; /* The size of p_sdp_db */
+ tSDP_DISCOVERY_DB* p_sdp_db; /* The data buffer to keep SDP database */
+} tBTA_SDP_CFG;
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpEnable
+ *
+ * Description Enable the SDP I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_SDP_ENABLE_EVT. This function must
+ * be called before other functions in the MCE API are
+ * called.
+ *
+ * Returns BTA_SDP_SUCCESS if successful.
+ * BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpSearch
+ *
+ * Description Start a search for sdp records for a specific BD_ADDR with a
+ * specific profile uuid.
+ * When the search operation is completed, the callback
+ * function will be called with a BTA_SDP_SEARCH_EVT.
+ * Returns BTA_SDP_SUCCESS if successful.
+ * BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr, tSDP_UUID* uuid);
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpCreateRecordByUser
+ *
+ * Description This function is used to request a callback to create a SDP
+ * record. The registered callback will be called with event
+ * BTA_SDP_CREATE_RECORD_USER_EVT.
+ *
+ * Returns BTA_SDP_SUCCESS, if the request is being processed.
+ * BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data);
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpRemoveRecordByUser
+ *
+ * Description This function is used to request a callback to remove a SDP
+ * record. The registered callback will be called with event
+ * BTA_SDP_REMOVE_RECORD_USER_EVT.
+ *
+ * Returns BTA_SDP_SUCCESS, if the request is being processed.
+ * BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+extern tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data);
+
+#endif /* BTA_SDP_API_H */
diff --git a/mtkbt/code/bt/bta/include/utl.h b/mtkbt/code/bt/bta/include/utl.h
new file mode 100755
index 0000000..88ec332
--- a/dev/null
+++ b/mtkbt/code/bt/bta/include/utl.h
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Basic utility functions.
+ *
+ ******************************************************************************/
+#ifndef UTL_H
+#define UTL_H
+
+#include "bt_types.h"
+#include "bt_utils.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/*** class of device settings ***/
+#define BTA_UTL_SET_COD_MAJOR_MINOR 0x01
+#define BTA_UTL_SET_COD_SERVICE_CLASS \
+ 0x02 /* only set the bits in the input \
+ */
+#define BTA_UTL_CLR_COD_SERVICE_CLASS 0x04
+#define BTA_UTL_SET_COD_ALL \
+ 0x08 /* take service class as the input (may clear some set bits!!) */
+#define BTA_UTL_INIT_COD 0x0a
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/** for utl_set_device_class() **/
+typedef struct {
+ uint8_t minor;
+ uint8_t major;
+ uint16_t service;
+} tBTA_UTL_COD;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function utl_str2int
+ *
+ * Description This utility function converts a character string to an
+ * integer. Acceptable values in string are 0-9. If invalid
+ * string or string value too large, -1 is returned.
+ *
+ *
+ * Returns Integer value or -1 on error.
+ *
+ ******************************************************************************/
+extern int16_t utl_str2int(const char* p_s);
+
+/*******************************************************************************
+ *
+ * Function utl_strucmp
+ *
+ * Description This utility function compares two strings in uppercase.
+ * String p_s must be uppercase. String p_t is converted to
+ * uppercase if lowercase. If p_s ends first, the substring
+ * match is counted as a match.
+ *
+ *
+ * Returns 0 if strings match, nonzero otherwise.
+ *
+ ******************************************************************************/
+extern int utl_strucmp(const char* p_s, const char* p_t);
+
+/*******************************************************************************
+ *
+ * Function utl_itoa
+ *
+ * Description This utility function converts a uint16_t to a string. The
+ * string is NULL-terminated. The length of the string is
+ * returned.
+ *
+ *
+ * Returns Length of string.
+ *
+ ******************************************************************************/
+extern uint8_t utl_itoa(uint16_t i, char* p_s);
+
+/*******************************************************************************
+ *
+ * Function utl_set_device_class
+ *
+ * Description This function updates the local Device Class.
+ *
+ * Parameters:
+ * p_cod - Pointer to the device class to set to
+ *
+ * cmd - the fields of the device class to update.
+ * BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major,
+ * minor class
+ * BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in
+ * the input
+ * BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in
+ * the input
+ * BTA_UTL_SET_COD_ALL - overwrite major, minor, set
+ * the bits in service class
+ * BTA_UTL_INIT_COD - overwrite major, minor, and
+ * service class
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_set_device_class(tBTA_UTL_COD* p_cod, uint8_t cmd);
+
+/*******************************************************************************
+ *
+ * Function utl_isintstr
+ *
+ * Description This utility function checks if the given string is an
+ * integer string or not
+ *
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isintstr(const char* p_s);
+
+/*******************************************************************************
+ *
+ * Function utl_isdialchar
+ *
+ * Description This utility function checks if the given character
+ * is an acceptable dial digit
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isdialchar(const char d);
+
+/*******************************************************************************
+ *
+ * Function utl_isdialstr
+ *
+ * Description This utility function checks if the given string contains
+ * only dial digits or not
+ *
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+extern bool utl_isdialstr(const char* p_s);
+
+#endif /* UTL_H */
diff --git a/mtkbt/code/bt/bta/jv/bta_jv_act.cc b/mtkbt/code/bt/bta/jv/bta_jv_act.cc
new file mode 100755
index 0000000..dccb37a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/jv/bta_jv_act.cc
@@ -0,0 +1,2537 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for BTA JV APIs.
+ *
+ ******************************************************************************/
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avct_api.h"
+#include "avdt_api.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "gap_api.h"
+#include "l2c_api.h"
+#include "osi/include/allocator.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+#include "osi/include/osi.h"
+
+/* one of these exists for each client */
+struct fc_client {
+ struct fc_client* next_all_list;
+ struct fc_client* next_chan_list;
+ BD_ADDR remote_addr;
+ uint32_t id;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint32_t l2cap_socket_id;
+ uint16_t handle;
+ uint16_t chan;
+ uint8_t sec_id;
+ unsigned server : 1;
+ unsigned init_called : 1;
+};
+
+/* one of these exists for each channel we're dealing with */
+struct fc_channel {
+ struct fc_channel* next;
+ struct fc_client* clients;
+ uint8_t has_server : 1;
+ uint16_t chan;
+};
+
+static struct fc_client* fc_clients;
+static struct fc_channel* fc_channels;
+static uint32_t fc_next_id;
+
+static void fcchan_conn_chng_cbk(uint16_t chan, BD_ADDR bd_addr, bool connected,
+ uint16_t reason, tBT_TRANSPORT);
+static void fcchan_data_cbk(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf);
+
+extern void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
+static inline void logu(const char* title, const uint8_t* p_uuid) {
+ char uuids[128];
+ uuid_to_string_legacy((bt_uuid_t*)p_uuid, uuids, sizeof(uuids));
+ APPL_TRACE_DEBUG("%s: %s", title, uuids);
+}
+
+static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
+ tBTA_JV_PCB* p_pcb_open);
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle);
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB* p_cb);
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB* p_cb);
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
+ const tBTA_JV_CONN_STATE state);
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
+ const tBTA_JV_CONN_STATE new_st);
+
+/*******************************************************************************
+ *
+ * Function bta_jv_alloc_sec_id
+ *
+ * Description allocate a security id
+ *
+ * Returns
+ *
+ ******************************************************************************/
+uint8_t bta_jv_alloc_sec_id(void) {
+ uint8_t ret = 0;
+ int i;
+ for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+ if (0 == bta_jv_cb.sec_id[i]) {
+ bta_jv_cb.sec_id[i] = BTA_JV_FIRST_SERVICE_ID + i;
+ ret = bta_jv_cb.sec_id[i];
+ break;
+ }
+ }
+ return ret;
+}
+static int get_sec_id_used(void) {
+ int i;
+ int used = 0;
+ for (i = 0; i < BTA_JV_NUM_SERVICE_ID; i++) {
+ if (bta_jv_cb.sec_id[i]) used++;
+ }
+ if (used == BTA_JV_NUM_SERVICE_ID)
+ APPL_TRACE_ERROR("get_sec_id_used, sec id exceeds the limit:%d",
+ BTA_JV_NUM_SERVICE_ID);
+ return used;
+}
+static int get_rfc_cb_used(void) {
+ int i;
+ int used = 0;
+ for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+ if (bta_jv_cb.rfc_cb[i].handle) used++;
+ }
+ if (used == BTA_JV_MAX_RFC_CONN)
+ APPL_TRACE_ERROR("get_sec_id_used, rfc ctrl block exceeds the limit:%d",
+ BTA_JV_MAX_RFC_CONN);
+ return used;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_free_sec_id
+ *
+ * Description free the given security id
+ *
+ * Returns
+ *
+ ******************************************************************************/
+static void bta_jv_free_sec_id(uint8_t* p_sec_id) {
+ uint8_t sec_id = *p_sec_id;
+ *p_sec_id = 0;
+ if (sec_id >= BTA_JV_FIRST_SERVICE_ID && sec_id <= BTA_JV_LAST_SERVICE_ID) {
+ BTM_SecClrService(sec_id);
+ bta_jv_cb.sec_id[sec_id - BTA_JV_FIRST_SERVICE_ID] = 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_alloc_rfc_cb
+ *
+ * Description allocate a control block for the given port handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_RFC_CB* bta_jv_alloc_rfc_cb(uint16_t port_handle,
+ tBTA_JV_PCB** pp_pcb) {
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ tBTA_JV_PCB* p_pcb;
+ int i, j;
+ for (i = 0; i < BTA_JV_MAX_RFC_CONN; i++) {
+ if (0 == bta_jv_cb.rfc_cb[i].handle) {
+ p_cb = &bta_jv_cb.rfc_cb[i];
+ /* mask handle to distinguish it with L2CAP handle */
+ p_cb->handle = (i + 1) | BTA_JV_RFCOMM_MASK;
+
+ p_cb->max_sess = 1;
+ p_cb->curr_sess = 1;
+ for (j = 0; j < BTA_JV_MAX_RFC_SR_SESSION; j++) p_cb->rfc_hdl[j] = 0;
+ p_cb->rfc_hdl[0] = port_handle;
+ APPL_TRACE_DEBUG("bta_jv_alloc_rfc_cb port_handle:%d handle:0x%2x",
+ port_handle, p_cb->handle);
+
+ p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+ p_pcb->handle = p_cb->handle;
+ p_pcb->port_handle = port_handle;
+ p_pcb->p_pm_cb = NULL;
+ *pp_pcb = p_pcb;
+ break;
+ }
+ }
+ if (p_cb == NULL) {
+ APPL_TRACE_ERROR(
+ "bta_jv_alloc_rfc_cb: port_handle:%d, ctrl block exceeds "
+ "limit:%d",
+ port_handle, BTA_JV_MAX_RFC_CONN);
+ }
+ return p_cb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfc_port_to_pcb
+ *
+ * Description find the port control block associated with the given port
+ * handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_PCB* bta_jv_rfc_port_to_pcb(uint16_t port_handle) {
+ tBTA_JV_PCB* p_pcb = NULL;
+
+ if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) &&
+ bta_jv_cb.port_cb[port_handle - 1].handle) {
+ p_pcb = &bta_jv_cb.port_cb[port_handle - 1];
+ }
+
+ return p_pcb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfc_port_to_cb
+ *
+ * Description find the RFCOMM control block associated with the given port
+ * handle
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_RFC_CB* bta_jv_rfc_port_to_cb(uint16_t port_handle) {
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ uint32_t handle;
+
+ if ((port_handle > 0) && (port_handle <= MAX_RFC_PORTS) &&
+ bta_jv_cb.port_cb[port_handle - 1].handle) {
+ handle = bta_jv_cb.port_cb[port_handle - 1].handle;
+ handle &= BTA_JV_RFC_HDL_MASK;
+ handle &= ~BTA_JV_RFCOMM_MASK;
+ if (handle) p_cb = &bta_jv_cb.rfc_cb[handle - 1];
+ } else {
+ APPL_TRACE_WARNING(
+ "bta_jv_rfc_port_to_cb(port_handle:0x%x):jv handle:0x%x not"
+ " FOUND",
+ port_handle, bta_jv_cb.port_cb[port_handle - 1].handle);
+ }
+ return p_cb;
+}
+
+static tBTA_JV_STATUS bta_jv_free_rfc_cb(tBTA_JV_RFC_CB* p_cb,
+ tBTA_JV_PCB* p_pcb) {
+ tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+ bool remove_server = false;
+ int close_pending = 0;
+
+ if (!p_cb || !p_pcb) {
+ APPL_TRACE_ERROR("bta_jv_free_sr_rfc_cb, p_cb or p_pcb cannot be null");
+ return BTA_JV_FAILURE;
+ }
+ APPL_TRACE_DEBUG(
+ "bta_jv_free_sr_rfc_cb: max_sess:%d, curr_sess:%d, p_pcb:%p, user:"
+ "%p, state:%d, jv handle: 0x%x",
+ p_cb->max_sess, p_cb->curr_sess, p_pcb, p_pcb->rfcomm_slot_id,
+ p_pcb->state, p_pcb->handle);
+
+ if (p_cb->curr_sess <= 0) return BTA_JV_SUCCESS;
+
+ switch (p_pcb->state) {
+ case BTA_JV_ST_CL_CLOSING:
+ case BTA_JV_ST_SR_CLOSING:
+ APPL_TRACE_WARNING(
+ "bta_jv_free_sr_rfc_cb: return on closing, port state:%d, "
+ "scn:%d, p_pcb:%p, user_data:%p",
+ p_pcb->state, p_cb->scn, p_pcb, p_pcb->rfcomm_slot_id);
+ status = BTA_JV_FAILURE;
+ return status;
+ case BTA_JV_ST_CL_OPEN:
+ case BTA_JV_ST_CL_OPENING:
+ APPL_TRACE_DEBUG(
+ "bta_jv_free_sr_rfc_cb: state: %d, scn:%d,"
+ " user_data:%p",
+ p_pcb->state, p_cb->scn, p_pcb->rfcomm_slot_id);
+ p_pcb->state = BTA_JV_ST_CL_CLOSING;
+ break;
+ case BTA_JV_ST_SR_LISTEN:
+ p_pcb->state = BTA_JV_ST_SR_CLOSING;
+ remove_server = true;
+ APPL_TRACE_DEBUG(
+ "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_LISTEN, scn:%d,"
+ " user_data:%p",
+ p_cb->scn, p_pcb->rfcomm_slot_id);
+ break;
+ case BTA_JV_ST_SR_OPEN:
+ p_pcb->state = BTA_JV_ST_SR_CLOSING;
+ APPL_TRACE_DEBUG(
+ "bta_jv_free_sr_rfc_cb: state: BTA_JV_ST_SR_OPEN, scn:%d,"
+ " user_data:%p",
+ p_cb->scn, p_pcb->rfcomm_slot_id);
+ break;
+ default:
+ APPL_TRACE_WARNING(
+ "bta_jv_free_sr_rfc_cb():failed, ignore port state:%d, scn:"
+ "%d, p_pcb:%p, jv handle: 0x%x, port_handle: %d, user_data:%p",
+ p_pcb->state, p_cb->scn, p_pcb, p_pcb->handle, p_pcb->port_handle,
+ p_pcb->rfcomm_slot_id);
+ status = BTA_JV_FAILURE;
+ break;
+ }
+ if (BTA_JV_SUCCESS == status) {
+ int port_status;
+
+ if (!remove_server)
+ port_status = RFCOMM_RemoveConnection(p_pcb->port_handle);
+ else
+ port_status = RFCOMM_RemoveServer(p_pcb->port_handle);
+ if (port_status != PORT_SUCCESS) {
+ status = BTA_JV_FAILURE;
+ APPL_TRACE_WARNING(
+ "bta_jv_free_rfc_cb(jv handle: 0x%x, state %d)::"
+ "port_status: %d, port_handle: %d, close_pending: %d:Remove",
+ p_pcb->handle, p_pcb->state, port_status, p_pcb->port_handle,
+ close_pending);
+ }
+ }
+ if (!close_pending) {
+ p_pcb->port_handle = 0;
+ p_pcb->state = BTA_JV_ST_NONE;
+ bta_jv_free_set_pm_profile_cb(p_pcb->handle);
+
+ // Initialize congestion flags
+ p_pcb->cong = false;
+ p_pcb->rfcomm_slot_id = 0;
+ int si = BTA_JV_RFC_HDL_TO_SIDX(p_pcb->handle);
+ if (0 <= si && si < BTA_JV_MAX_RFC_SR_SESSION) p_cb->rfc_hdl[si] = 0;
+ p_pcb->handle = 0;
+ p_cb->curr_sess--;
+ if (p_cb->curr_sess == 0) {
+ p_cb->scn = 0;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ p_cb->p_cback = NULL;
+ p_cb->handle = 0;
+ p_cb->curr_sess = -1;
+ }
+ if (remove_server) {
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_free_l2c_cb
+ *
+ * Description free the given L2CAP control block
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS bta_jv_free_l2c_cb(tBTA_JV_L2C_CB* p_cb) {
+ tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+
+ if (BTA_JV_ST_NONE != p_cb->state) {
+ bta_jv_free_set_pm_profile_cb((uint32_t)p_cb->handle);
+ if (GAP_ConnClose(p_cb->handle) != BT_PASS) status = BTA_JV_FAILURE;
+ }
+ p_cb->psm = 0;
+ p_cb->state = BTA_JV_ST_NONE;
+ p_cb->cong = false;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ p_cb->p_cback = NULL;
+ return status;
+}
+
+/*******************************************************************************
+ *
+ *
+ * Function bta_jv_clear_pm_cb
+ *
+ * Description clears jv pm control block and optionally calls
+ * bta_sys_conn_close()
+ * In general close_conn should be set to true to remove registering
+ * with dm pm!
+ *
+ * WARNING: Make sure to clear pointer form port or l2c to this control block
+ * too!
+ *
+ ******************************************************************************/
+static void bta_jv_clear_pm_cb(tBTA_JV_PM_CB* p_pm_cb, bool close_conn) {
+ /* needs to be called if registered with bta pm, otherwise we may run out of
+ * dm pm slots! */
+ if (close_conn)
+ bta_sys_conn_close(BTA_ID_JV, p_pm_cb->app_id, p_pm_cb->peer_bd_addr);
+ p_pm_cb->state = BTA_JV_PM_FREE_ST;
+ p_pm_cb->app_id = BTA_JV_PM_ALL;
+ p_pm_cb->handle = BTA_JV_PM_HANDLE_CLEAR;
+ bdcpy(p_pm_cb->peer_bd_addr, bd_addr_null);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_free_set_pm_profile_cb
+ *
+ * Description free pm profile control block
+ *
+ * Returns BTA_JV_SUCCESS if cb has been freed correctly,
+ * BTA_JV_FAILURE in case of no profile has been registered or
+ * already freed
+ *
+ ******************************************************************************/
+static tBTA_JV_STATUS bta_jv_free_set_pm_profile_cb(uint32_t jv_handle) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_PM_CB** p_cb;
+ int i, j, bd_counter = 0, appid_counter = 0;
+
+ for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+ p_cb = NULL;
+ if ((bta_jv_cb.pm_cb[i].state != BTA_JV_PM_FREE_ST) &&
+ (jv_handle == bta_jv_cb.pm_cb[i].handle)) {
+ for (j = 0; j < BTA_JV_PM_MAX_NUM; j++) {
+ if (bdcmp(bta_jv_cb.pm_cb[j].peer_bd_addr,
+ bta_jv_cb.pm_cb[i].peer_bd_addr) == 0)
+ bd_counter++;
+ if (bta_jv_cb.pm_cb[j].app_id == bta_jv_cb.pm_cb[i].app_id)
+ appid_counter++;
+ }
+
+ APPL_TRACE_API(
+ "%s(jv_handle: 0x%2x), idx: %d, "
+ "app_id: 0x%x",
+ __func__, jv_handle, i, bta_jv_cb.pm_cb[i].app_id);
+ APPL_TRACE_API(
+ "%s, bd_counter = %d, "
+ "appid_counter = %d",
+ __func__, bd_counter, appid_counter);
+ if (bd_counter > 1) {
+ bta_jv_pm_conn_idle(&bta_jv_cb.pm_cb[i]);
+ }
+
+ if (bd_counter <= 1 || (appid_counter <= 1)) {
+ bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], true);
+ } else {
+ bta_jv_clear_pm_cb(&bta_jv_cb.pm_cb[i], false);
+ }
+
+ if (BTA_JV_RFCOMM_MASK & jv_handle) {
+ uint32_t hi =
+ ((jv_handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+ uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(jv_handle);
+ if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+ si < BTA_JV_MAX_RFC_SR_SESSION &&
+ bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+ tBTA_JV_PCB* p_pcb =
+ bta_jv_rfc_port_to_pcb(bta_jv_cb.rfc_cb[hi].rfc_hdl[si]);
+ if (p_pcb) {
+ if (NULL == p_pcb->p_pm_cb)
+ APPL_TRACE_WARNING(
+ "%s(jv_handle:"
+ " 0x%x):port_handle: 0x%x, p_pm_cb: %d: no link to "
+ "pm_cb?",
+ __func__, jv_handle, p_pcb->port_handle, i);
+ p_cb = &p_pcb->p_pm_cb;
+ }
+ }
+ } else {
+ if (jv_handle < BTA_JV_MAX_L2C_CONN) {
+ tBTA_JV_L2C_CB* p_l2c_cb = &bta_jv_cb.l2c_cb[jv_handle];
+ if (NULL == p_l2c_cb->p_pm_cb)
+ APPL_TRACE_WARNING(
+ "%s(jv_handle: "
+ "0x%x): p_pm_cb: %d: no link to pm_cb?",
+ __func__, jv_handle, i);
+ p_cb = &p_l2c_cb->p_pm_cb;
+ }
+ }
+ if (p_cb) {
+ *p_cb = NULL;
+ status = BTA_JV_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_alloc_set_pm_profile_cb
+ *
+ * Description set PM profile control block
+ *
+ * Returns pointer to allocated cb or NULL in case of failure
+ *
+ ******************************************************************************/
+static tBTA_JV_PM_CB* bta_jv_alloc_set_pm_profile_cb(uint32_t jv_handle,
+ tBTA_JV_PM_ID app_id) {
+ bool bRfcHandle = (jv_handle & BTA_JV_RFCOMM_MASK) != 0;
+ BD_ADDR peer_bd_addr;
+ int i, j;
+ tBTA_JV_PM_CB** pp_cb;
+
+ for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+ pp_cb = NULL;
+ if (bta_jv_cb.pm_cb[i].state == BTA_JV_PM_FREE_ST) {
+ /* rfc handle bd addr retrieval requires core stack handle */
+ if (bRfcHandle) {
+ for (j = 0; j < BTA_JV_MAX_RFC_CONN; j++) {
+ if (jv_handle == bta_jv_cb.port_cb[j].handle) {
+ pp_cb = &bta_jv_cb.port_cb[j].p_pm_cb;
+ if (PORT_SUCCESS !=
+ PORT_CheckConnection(bta_jv_cb.port_cb[j].port_handle,
+ peer_bd_addr, NULL))
+ i = BTA_JV_PM_MAX_NUM;
+ break;
+ }
+ }
+ } else {
+ /* use jv handle for l2cap bd address retrieval */
+ for (j = 0; j < BTA_JV_MAX_L2C_CONN; j++) {
+ if (jv_handle == bta_jv_cb.l2c_cb[j].handle) {
+ pp_cb = &bta_jv_cb.l2c_cb[j].p_pm_cb;
+ uint8_t* p_bd_addr = GAP_ConnGetRemoteAddr((uint16_t)jv_handle);
+ if (NULL != p_bd_addr)
+ bdcpy(peer_bd_addr, p_bd_addr);
+ else
+ i = BTA_JV_PM_MAX_NUM;
+ break;
+ }
+ }
+ }
+ APPL_TRACE_API(
+ "bta_jv_alloc_set_pm_profile_cb(handle 0x%2x, app_id %d): "
+ "idx: %d, (BTA_JV_PM_MAX_NUM: %d), pp_cb: 0x%x",
+ jv_handle, app_id, i, BTA_JV_PM_MAX_NUM, pp_cb);
+ break;
+ }
+ }
+
+ if ((i != BTA_JV_PM_MAX_NUM) && (NULL != pp_cb)) {
+ *pp_cb = &bta_jv_cb.pm_cb[i];
+ bta_jv_cb.pm_cb[i].handle = jv_handle;
+ bta_jv_cb.pm_cb[i].app_id = app_id;
+ bdcpy(bta_jv_cb.pm_cb[i].peer_bd_addr, peer_bd_addr);
+ bta_jv_cb.pm_cb[i].state = BTA_JV_PM_IDLE_ST;
+ return &bta_jv_cb.pm_cb[i];
+ }
+ APPL_TRACE_WARNING(
+ "bta_jv_alloc_set_pm_profile_cb(jv_handle: 0x%x, app_id: %d) "
+ "return NULL",
+ jv_handle, app_id);
+ return (tBTA_JV_PM_CB*)NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_check_psm
+ *
+ * Description for now use only the legal PSM per JSR82 spec
+ *
+ * Returns true, if allowed
+ *
+ ******************************************************************************/
+bool bta_jv_check_psm(uint16_t psm) {
+ bool ret = false;
+
+ if (L2C_IS_VALID_PSM(psm)) {
+ if (psm < 0x1001) {
+ /* see if this is defined by spec */
+ switch (psm) {
+ case SDP_PSM: /* 1 */
+ case BT_PSM_RFCOMM: /* 3 */
+ /* do not allow java app to use these 2 PSMs */
+ break;
+
+ case TCS_PSM_INTERCOM: /* 5 */
+ case TCS_PSM_CORDLESS: /* 7 */
+ if (false == bta_sys_is_register(BTA_ID_CT) &&
+ false == bta_sys_is_register(BTA_ID_CG))
+ ret = true;
+ break;
+
+ case BT_PSM_BNEP: /* F */
+ if (false == bta_sys_is_register(BTA_ID_PAN)) ret = true;
+ break;
+
+ case HID_PSM_CONTROL: /* 0x11 */
+ case HID_PSM_INTERRUPT: /* 0x13 */
+ // FIX: allow HID Device and HID Host to coexist
+ if (false == bta_sys_is_register(BTA_ID_HD) ||
+ false == bta_sys_is_register(BTA_ID_HH))
+ ret = true;
+ break;
+
+ case AVCT_PSM: /* 0x17 */
+ case AVDT_PSM: /* 0x19 */
+ if ((false == bta_sys_is_register(BTA_ID_AV)) &&
+ (false == bta_sys_is_register(BTA_ID_AVK)))
+ ret = true;
+ break;
+
+ default:
+ ret = true;
+ break;
+ }
+ } else {
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_enable
+ *
+ * Description Initialises the JAVA I/F
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_enable(tBTA_JV_MSG* p_data) {
+ tBTA_JV_STATUS status = BTA_JV_SUCCESS;
+ bta_jv_cb.p_dm_cback = p_data->enable.p_cback;
+ bta_jv_cb.p_dm_cback(BTA_JV_ENABLE_EVT, (tBTA_JV*)&status, 0);
+ memset(bta_jv_cb.free_psm_list, 0, sizeof(bta_jv_cb.free_psm_list));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_disable
+ *
+ * Description Disables the BT device manager
+ * free the resources used by java
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_disable(UNUSED_ATTR tBTA_JV_MSG* p_data) {
+ APPL_TRACE_ERROR("%s", __func__);
+}
+
+/**
+ * We keep a list of PSM's that have been freed from JAVA, for reuse.
+ * This function will return a free PSM, and delete it from the free
+ * list.
+ * If no free PSMs exist, 0 will be returned.
+ */
+static uint16_t bta_jv_get_free_psm() {
+ const int cnt =
+ sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ uint16_t psm = bta_jv_cb.free_psm_list[i];
+ if (psm != 0) {
+ APPL_TRACE_DEBUG("%s(): Reusing PSM: 0x%04d", __func__, psm)
+ bta_jv_cb.free_psm_list[i] = 0;
+ return psm;
+ }
+ }
+ return 0;
+}
+
+static void bta_jv_set_free_psm(uint16_t psm) {
+ int free_index = -1;
+ const int cnt =
+ sizeof(bta_jv_cb.free_psm_list) / sizeof(bta_jv_cb.free_psm_list[0]);
+ for (int i = 0; i < cnt; i++) {
+ if (bta_jv_cb.free_psm_list[i] == 0) {
+ free_index = i;
+ } else if (psm == bta_jv_cb.free_psm_list[i]) {
+ return; // PSM already freed?
+ }
+ }
+ if (free_index != -1) {
+ bta_jv_cb.free_psm_list[free_index] = psm;
+ APPL_TRACE_DEBUG("%s(): Recycling PSM: 0x%04d", __func__, psm)
+ } else {
+ APPL_TRACE_ERROR("%s unable to free psm 0x%x no more free slots", __func__,
+ psm);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_get_channel_id
+ *
+ * Description Obtain a free SCN (Server Channel Number)
+ * (RFCOMM channel or L2CAP PSM)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_get_channel_id(tBTA_JV_MSG* p_data) {
+ uint16_t psm = 0;
+
+ switch (p_data->alloc_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ int32_t channel = p_data->alloc_channel.channel;
+ uint8_t scn = 0;
+ if (channel > 0) {
+ if (BTM_TryAllocateSCN(channel) == false) {
+ APPL_TRACE_ERROR("rfc channel:%d already in use or invalid", channel);
+ channel = 0;
+ }
+ } else {
+ channel = BTM_AllocateSCN();
+ if (channel == 0) {
+ APPL_TRACE_ERROR("run out of rfc channels");
+ channel = 0;
+ }
+ }
+ if (channel != 0) {
+ bta_jv_cb.scn[channel - 1] = true;
+ scn = (uint8_t)channel;
+ }
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_SCN_EVT, (tBTA_JV*)&scn,
+ p_data->alloc_channel.rfcomm_slot_id);
+ return;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ psm = bta_jv_get_free_psm();
+ if (psm == 0) {
+ psm = L2CA_AllocatePSM();
+ APPL_TRACE_DEBUG("%s() returned PSM: 0x%04x", __func__, psm);
+ }
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ break;
+ default:
+ break;
+ }
+
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_GET_PSM_EVT, (tBTA_JV*)&psm,
+ p_data->alloc_channel.l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_free_scn
+ *
+ * Description free a SCN
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_free_scn(tBTA_JV_MSG* p_data) {
+ uint16_t scn = p_data->free_channel.scn;
+
+ switch (p_data->free_channel.type) {
+ case BTA_JV_CONN_TYPE_RFCOMM: {
+ if (scn > 0 && scn <= BTA_JV_MAX_SCN && bta_jv_cb.scn[scn - 1]) {
+ /* this scn is used by JV */
+ bta_jv_cb.scn[scn - 1] = false;
+ BTM_FreeSCN(scn);
+ }
+ break;
+ }
+ case BTA_JV_CONN_TYPE_L2CAP:
+ bta_jv_set_free_psm(scn);
+ break;
+ case BTA_JV_CONN_TYPE_L2CAP_LE:
+ // TODO: Not yet implemented...
+ break;
+ default:
+ break;
+ }
+}
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
+ static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+
+ logu("in, uuid:", u->uu.uuid128);
+ APPL_TRACE_DEBUG("uuid len:%d", u->len);
+ if (u->len == 16) {
+ if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) == 0) {
+ tBT_UUID su;
+ memset(&su, 0, sizeof(su));
+ if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
+ su.len = 2;
+ uint16_t u16;
+ memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+ su.uu.uuid16 = ntohs(u16);
+ APPL_TRACE_DEBUG("shorten to 16 bits uuid: %x", su.uu.uuid16);
+ } else {
+ su.len = 4;
+ uint32_t u32;
+ memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+ su.uu.uuid32 = ntohl(u32);
+ APPL_TRACE_DEBUG("shorten to 32 bits uuid: %x", su.uu.uuid32);
+ }
+ return su;
+ }
+ }
+ APPL_TRACE_DEBUG("cannot shorten none-reserved 128 bits uuid");
+ return *u;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_start_discovery_cback
+ *
+ * Description Callback for Start Discovery
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_start_discovery_cback(uint16_t result, void* user_data) {
+ tBTA_JV_STATUS status;
+ uint32_t* p_rfcomm_slot_id = static_cast<uint32_t*>(user_data);
+
+ APPL_TRACE_DEBUG("bta_jv_start_discovery_cback res: 0x%x", result);
+
+ bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+ if (bta_jv_cb.p_dm_cback) {
+ tBTA_JV_DISCOVERY_COMP dcomp;
+ dcomp.scn = 0;
+ status = BTA_JV_FAILURE;
+ if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+ tSDP_DISC_REC* p_sdp_rec = NULL;
+ tSDP_PROTOCOL_ELEM pe;
+ logu("bta_jv_cb.uuid", bta_jv_cb.uuid.uu.uuid128);
+ tBT_UUID su = shorten_sdp_uuid(&bta_jv_cb.uuid);
+ logu("shorten uuid:", su.uu.uuid128);
+ p_sdp_rec =
+ SDP_FindServiceUUIDInDb(p_bta_jv_cfg->p_sdp_db, &su, p_sdp_rec);
+ APPL_TRACE_DEBUG("p_sdp_rec:%p", p_sdp_rec);
+ if (p_sdp_rec &&
+ SDP_FindProtocolListElemInRec(p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ dcomp.scn = (uint8_t)pe.params[0];
+ status = BTA_JV_SUCCESS;
+ }
+ }
+
+ dcomp.status = status;
+ bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&dcomp,
+ *p_rfcomm_slot_id);
+ osi_free(p_rfcomm_slot_id);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_start_discovery
+ *
+ * Description Discovers services on a remote device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_start_discovery(tBTA_JV_MSG* p_data) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ APPL_TRACE_DEBUG("bta_jv_start_discovery in, sdp_active:%d",
+ bta_jv_cb.sdp_active);
+ if (bta_jv_cb.sdp_active != BTA_JV_SDP_ACT_NONE) {
+ /* SDP is still in progress */
+ status = BTA_JV_BUSY;
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&status,
+ p_data->start_discovery.rfcomm_slot_id);
+ return;
+ }
+
+ /* init the database/set up the filter */
+ APPL_TRACE_DEBUG(
+ "call SDP_InitDiscoveryDb, p_data->start_discovery.num_uuid:%d",
+ p_data->start_discovery.num_uuid);
+ SDP_InitDiscoveryDb(p_bta_jv_cfg->p_sdp_db, p_bta_jv_cfg->sdp_db_size,
+ p_data->start_discovery.num_uuid,
+ p_data->start_discovery.uuid_list, 0, NULL);
+
+ /* tell SDP to keep the raw data */
+ p_bta_jv_cfg->p_sdp_db->raw_data = p_bta_jv_cfg->p_sdp_raw_data;
+ p_bta_jv_cfg->p_sdp_db->raw_size = p_bta_jv_cfg->sdp_raw_size;
+
+ bta_jv_cb.p_sel_raw_data = 0;
+ bta_jv_cb.uuid = p_data->start_discovery.uuid_list[0];
+
+ bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_YES;
+
+ uint32_t* rfcomm_slot_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
+ *rfcomm_slot_id = p_data->start_discovery.rfcomm_slot_id;
+
+ if (!SDP_ServiceSearchAttributeRequest2(
+ p_data->start_discovery.bd_addr, p_bta_jv_cfg->p_sdp_db,
+ bta_jv_start_discovery_cback, (void*)rfcomm_slot_id)) {
+ bta_jv_cb.sdp_active = BTA_JV_SDP_ACT_NONE;
+ /* failed to start SDP. report the failure right away */
+ if (bta_jv_cb.p_dm_cback)
+ bta_jv_cb.p_dm_cback(BTA_JV_DISCOVERY_COMP_EVT, (tBTA_JV*)&status,
+ p_data->start_discovery.rfcomm_slot_id);
+ }
+ /*
+ else report the result when the cback is called
+ */
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_create_record
+ *
+ * Description Create an SDP record with the given attributes
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_create_record(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_CREATE_RECORD* cr = &(p_data->create_record);
+ tBTA_JV_CREATE_RECORD evt_data;
+ evt_data.status = BTA_JV_SUCCESS;
+ if (bta_jv_cb.p_dm_cback)
+ // callback user immediately to create his own sdp record in stack thread
+ // context
+ bta_jv_cb.p_dm_cback(BTA_JV_CREATE_RECORD_EVT, (tBTA_JV*)&evt_data,
+ cr->rfcomm_slot_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_delete_record
+ *
+ * Description Delete an SDP record
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_delete_record(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_ADD_ATTRIBUTE* dr = &(p_data->add_attr);
+ if (dr->handle) {
+ /* this is a record created by btif layer*/
+ SDP_DeleteRecord(dr->handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_client_cback
+ *
+ * Description handles the l2cap client events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_l2cap_client_cback(uint16_t gap_handle, uint16_t event) {
+ tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
+
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
+
+ APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+ evt_data.l2c_open.status = BTA_JV_SUCCESS;
+ evt_data.l2c_open.handle = gap_handle;
+
+ switch (event) {
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_CL_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->l2cap_socket_id);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ p_cb->state = BTA_JV_ST_NONE;
+ bta_jv_free_sec_id(&p_cb->sec_id);
+ evt_data.l2c_close.async = true;
+ p_cb->p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, p_cb->l2cap_socket_id);
+ p_cb->p_cback = NULL;
+ break;
+
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data,
+ p_cb->l2cap_socket_id);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_TX_EMPTY:
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? true : false;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->l2cap_socket_id);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_connect
+ *
+ * Description makes an l2cap client connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2C_CB* p_cb;
+ tBTA_JV_L2CAP_CL_INIT evt_data;
+ uint16_t handle = GAP_INVALID_HANDLE;
+ uint8_t sec_id;
+ tL2CAP_CFG_INFO cfg;
+ tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
+ uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO* ertm_info = NULL;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ if (cc->has_cfg == true) {
+ cfg = cc->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (cc->has_ertm_info == true) {
+ ertm_info = &(cc->ertm_info);
+ }
+
+ /* We need to use this value for MTU to be able to handle cases where cfg is
+ * not set in req. */
+ cfg.mtu_present = true;
+ cfg.mtu = cc->rx_mtu;
+
+ /* TODO: DM role manager
+ L2CA_SetDesireRole(cc->role);
+ */
+
+ sec_id = bta_jv_alloc_sec_id();
+ evt_data.sec_id = sec_id;
+ evt_data.status = BTA_JV_FAILURE;
+
+ if (sec_id) {
+ /* PSM checking is not required for LE COC */
+ if ((cc->type != BTA_JV_CONN_TYPE_L2CAP) ||
+ (bta_jv_check_psm(cc->remote_psm))) /* allowed */
+ {
+ handle = GAP_ConnOpen("", sec_id, 0, cc->peer_bd_addr, cc->remote_psm,
+ &cfg, ertm_info, cc->sec_mask, chan_mode_mask,
+ bta_jv_l2cap_client_cback, cc->type);
+ if (handle != GAP_INVALID_HANDLE) {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ }
+ }
+
+ if (evt_data.status == BTA_JV_SUCCESS) {
+ p_cb = &bta_jv_cb.l2c_cb[handle];
+ p_cb->handle = handle;
+ p_cb->p_cback = cc->p_cback;
+ p_cb->l2cap_socket_id = cc->l2cap_socket_id;
+ p_cb->psm = 0; /* not a server */
+ p_cb->sec_id = sec_id;
+ p_cb->state = BTA_JV_ST_CL_OPENING;
+ } else {
+ bta_jv_free_sec_id(&sec_id);
+ }
+
+ evt_data.handle = handle;
+ if (cc->p_cback)
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, (tBTA_JV*)&evt_data,
+ cc->l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_close
+ *
+ * Description Close an L2CAP client connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_close(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2CAP_CLOSE evt_data;
+ tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
+ tBTA_JV_L2CAP_CBACK* p_cback = cc->p_cb->p_cback;
+ uint32_t l2cap_socket_id = cc->p_cb->l2cap_socket_id;
+
+ evt_data.handle = cc->handle;
+ evt_data.status = bta_jv_free_l2c_cb(cc->p_cb);
+ evt_data.async = false;
+
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV*)&evt_data, l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_server_cback
+ *
+ * Description handles the l2cap server callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_l2cap_server_cback(uint16_t gap_handle, uint16_t event) {
+ tBTA_JV_L2C_CB* p_cb = &bta_jv_cb.l2c_cb[gap_handle];
+ tBTA_JV evt_data;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint32_t socket_id;
+
+ if (gap_handle >= BTA_JV_MAX_L2C_CONN && !p_cb->p_cback) return;
+
+ APPL_TRACE_DEBUG("%s: %d evt:x%x", __func__, gap_handle, event);
+ evt_data.l2c_open.status = BTA_JV_SUCCESS;
+ evt_data.l2c_open.handle = gap_handle;
+
+ switch (event) {
+ case GAP_EVT_CONN_OPENED:
+ bdcpy(evt_data.l2c_open.rem_bda, GAP_ConnGetRemoteAddr(gap_handle));
+ evt_data.l2c_open.tx_mtu = GAP_ConnGetRemMtuSize(gap_handle);
+ p_cb->state = BTA_JV_ST_SR_OPEN;
+ p_cb->p_cback(BTA_JV_L2CAP_OPEN_EVT, &evt_data, p_cb->l2cap_socket_id);
+ break;
+
+ case GAP_EVT_CONN_CLOSED:
+ evt_data.l2c_close.async = true;
+ evt_data.l2c_close.handle = p_cb->handle;
+ p_cback = p_cb->p_cback;
+ socket_id = p_cb->l2cap_socket_id;
+ evt_data.l2c_close.status = bta_jv_free_l2c_cb(p_cb);
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt_data, socket_id);
+ break;
+
+ case GAP_EVT_CONN_DATA_AVAIL:
+ evt_data.data_ind.handle = gap_handle;
+ /* Reset idle timer to avoid requesting sniff mode while receiving data */
+ bta_jv_pm_conn_busy(p_cb->p_pm_cb);
+ p_cb->p_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data,
+ p_cb->l2cap_socket_id);
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_TX_EMPTY:
+ bta_jv_pm_conn_idle(p_cb->p_pm_cb);
+ break;
+
+ case GAP_EVT_CONN_CONGESTED:
+ case GAP_EVT_CONN_UNCONGESTED:
+ p_cb->cong = (event == GAP_EVT_CONN_CONGESTED) ? true : false;
+ evt_data.l2c_cong.cong = p_cb->cong;
+ p_cb->p_cback(BTA_JV_L2CAP_CONG_EVT, &evt_data, p_cb->l2cap_socket_id);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_start_server
+ *
+ * Description starts an L2CAP server
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2C_CB* p_cb;
+ uint8_t sec_id;
+ uint16_t handle;
+ tL2CAP_CFG_INFO cfg;
+ tBTA_JV_L2CAP_START evt_data;
+ tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+ uint8_t chan_mode_mask = GAP_FCR_CHAN_OPT_BASIC;
+ tL2CAP_ERTM_INFO* ertm_info = NULL;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ if (ls->has_cfg == true) {
+ cfg = ls->cfg;
+ if (cfg.fcr_present && cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ chan_mode_mask = GAP_FCR_CHAN_OPT_ERTM;
+ }
+ }
+
+ if (ls->has_ertm_info == true) {
+ ertm_info = &(ls->ertm_info);
+ }
+
+ // FIX: MTU=0 means not present
+ if (ls->rx_mtu > 0) {
+ cfg.mtu_present = true;
+ cfg.mtu = ls->rx_mtu;
+ } else {
+ cfg.mtu_present = false;
+ cfg.mtu = 0;
+ }
+
+ /* TODO DM role manager
+ L2CA_SetDesireRole(ls->role);
+ */
+
+ sec_id = bta_jv_alloc_sec_id();
+ /* PSM checking is not required for LE COC */
+ if (0 == sec_id || ((ls->type == BTA_JV_CONN_TYPE_L2CAP) &&
+ (false == bta_jv_check_psm(ls->local_psm))) ||
+ (handle = GAP_ConnOpen("JV L2CAP", sec_id, 1, 0, ls->local_psm, &cfg,
+ ertm_info, ls->sec_mask, chan_mode_mask,
+ bta_jv_l2cap_server_cback, ls->type)) ==
+ GAP_INVALID_HANDLE) {
+ bta_jv_free_sec_id(&sec_id);
+ evt_data.status = BTA_JV_FAILURE;
+ } else {
+ p_cb = &bta_jv_cb.l2c_cb[handle];
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = handle;
+ evt_data.sec_id = sec_id;
+ p_cb->p_cback = ls->p_cback;
+ p_cb->l2cap_socket_id = ls->l2cap_socket_id;
+ p_cb->handle = handle;
+ p_cb->sec_id = sec_id;
+ p_cb->state = BTA_JV_ST_SR_LISTEN;
+ p_cb->psm = ls->local_psm;
+ }
+
+ if (ls->p_cback)
+ ls->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV*)&evt_data,
+ ls->l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_stop_server
+ *
+ * Description stops an L2CAP server
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2C_CB* p_cb;
+ tBTA_JV_L2CAP_CLOSE evt_data;
+ tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ for (int i = 0; i < BTA_JV_MAX_L2C_CONN; i++) {
+ if (bta_jv_cb.l2c_cb[i].psm == ls->local_psm) {
+ p_cb = &bta_jv_cb.l2c_cb[i];
+ p_cback = p_cb->p_cback;
+ uint32_t l2cap_socket_id = p_cb->l2cap_socket_id;
+ evt_data.handle = p_cb->handle;
+ evt_data.status = bta_jv_free_l2c_cb(p_cb);
+ evt_data.async = false;
+ if (p_cback)
+ p_cback(BTA_JV_L2CAP_CLOSE_EVT, (tBTA_JV*)&evt_data, l2cap_socket_id);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_read
+ *
+ * Description Read data from an L2CAP connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_read(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2CAP_READ evt_data;
+ tBTA_JV_API_L2CAP_READ* rc = &(p_data->l2cap_read);
+
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = rc->handle;
+ evt_data.req_id = rc->req_id;
+ evt_data.p_data = rc->p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS ==
+ GAP_ConnReadData(rc->handle, rc->p_data, rc->len, &evt_data.len)) {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+
+ rc->p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data, rc->l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_write
+ *
+ * Description Write data to an L2CAP connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_write(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2CAP_WRITE evt_data;
+ tBTA_JV_API_L2CAP_WRITE* ls = &(p_data->l2cap_write);
+
+ /* As we check this callback exists before the tBTA_JV_API_L2CAP_WRITE can be
+ * send through the
+ * API this check should not be needed.
+ * But the API is not designed to be used (safely at least) in a
+ * multi-threaded scheduler, hence
+ * if the peer device disconnects the l2cap link after the API is called, but
+ * before this
+ * message is handled, the ->p_cback will be cleared at this point. At first
+ * glanch this seems
+ * highly unlikely, but for all obex-profiles with two channels connected -
+ * e.g. MAP, this
+ * happens around 1 of 4 disconnects, as a disconnect on the server channel
+ * causes a disconnect
+ * to be send on the client (notification) channel, but at the peer typically
+ * disconnects both
+ * the OBEX disconnect request crosses the incoming l2cap disconnect.
+ * If p_cback is cleared, we simply discard the data.
+ * RISK: The caller must handle any cleanup based on another signal than
+ * BTA_JV_L2CAP_WRITE_EVT,
+ * which is typically not possible, as the pointer to the allocated
+ * buffer is stored
+ * in this message, and can therefore not be freed, hence we have a
+ * mem-leak-by-design.*/
+ if (ls->p_cb->p_cback != NULL) {
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = ls->handle;
+ evt_data.req_id = ls->req_id;
+ evt_data.p_data = ls->p_data;
+ evt_data.cong = ls->p_cb->cong;
+ evt_data.len = 0;
+ bta_jv_pm_conn_busy(ls->p_cb->p_pm_cb);
+ if (!evt_data.cong &&
+ BT_PASS ==
+ GAP_ConnWriteData(ls->handle, ls->p_data, ls->len, &evt_data.len)) {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ ls->p_cb->p_cback(BTA_JV_L2CAP_WRITE_EVT, (tBTA_JV*)&evt_data, ls->user_id);
+ } else {
+ /* As this pointer is checked in the API function, this occurs only when the
+ * channel is
+ * disconnected after the API function is called, but before the message is
+ * handled. */
+ APPL_TRACE_ERROR("%s() ls->p_cb->p_cback == NULL", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_write_fixed
+ *
+ * Description Write data to an L2CAP connection using Fixed channels
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data) {
+ tBTA_JV_L2CAP_WRITE_FIXED evt_data;
+ tBTA_JV_API_L2CAP_WRITE_FIXED* ls = &(p_data->l2cap_write_fixed);
+ BT_HDR* msg =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + ls->len + L2CAP_MIN_OFFSET);
+
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.channel = ls->channel;
+ memcpy(evt_data.addr, ls->addr, sizeof(evt_data.addr));
+ evt_data.req_id = ls->req_id;
+ evt_data.p_data = ls->p_data;
+ evt_data.len = 0;
+
+ memcpy(((uint8_t*)(msg + 1)) + L2CAP_MIN_OFFSET, ls->p_data, ls->len);
+ msg->len = ls->len;
+ msg->offset = L2CAP_MIN_OFFSET;
+
+ L2CA_SendFixedChnlData(ls->channel, ls->addr, msg);
+
+ ls->p_cback(BTA_JV_L2CAP_WRITE_FIXED_EVT, (tBTA_JV*)&evt_data, ls->user_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_port_data_co_cback
+ *
+ * Description port data callback function of rfcomm
+ * connections
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static int bta_jv_port_data_co_cback(uint16_t port_handle, uint8_t* buf,
+ uint16_t len, int type) {
+ tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+ tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ APPL_TRACE_DEBUG("%s, p_cb:%p, p_pcb:%p, len:%d, type:%d", __func__, p_cb,
+ p_pcb, len, type);
+ if (p_pcb != NULL) {
+ switch (type) {
+ case DATA_CO_CALLBACK_TYPE_INCOMING:
+ return bta_co_rfc_data_incoming(p_pcb->rfcomm_slot_id, (BT_HDR*)buf);
+ case DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE:
+ return bta_co_rfc_data_outgoing_size(p_pcb->rfcomm_slot_id, (int*)buf);
+ case DATA_CO_CALLBACK_TYPE_OUTGOING:
+ return bta_co_rfc_data_outgoing(p_pcb->rfcomm_slot_id, buf, len);
+ default:
+ APPL_TRACE_ERROR("unknown callout type:%d", type);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_port_mgmt_cl_cback
+ *
+ * Description callback for port mamangement function of rfcomm
+ * client connections
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_port_mgmt_cl_cback(uint32_t code, uint16_t port_handle) {
+ tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+ tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ tBTA_JV evt_data;
+ BD_ADDR rem_bda;
+ uint16_t lcid;
+ tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
+
+ APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback:code:%d, port_handle%d", code,
+ port_handle);
+ if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+ APPL_TRACE_DEBUG("bta_jv_port_mgmt_cl_cback code=%d port_handle:%d handle:%d",
+ code, port_handle, p_cb->handle);
+
+ PORT_CheckConnection(port_handle, rem_bda, &lcid);
+
+ if (code == PORT_SUCCESS) {
+ evt_data.rfc_open.handle = p_cb->handle;
+ evt_data.rfc_open.status = BTA_JV_SUCCESS;
+ bdcpy(evt_data.rfc_open.rem_bda, rem_bda);
+ p_pcb->state = BTA_JV_ST_CL_OPEN;
+ p_cb->p_cback(BTA_JV_RFCOMM_OPEN_EVT, &evt_data, p_pcb->rfcomm_slot_id);
+ } else {
+ evt_data.rfc_close.handle = p_cb->handle;
+ evt_data.rfc_close.status = BTA_JV_FAILURE;
+ evt_data.rfc_close.port_status = code;
+ evt_data.rfc_close.async = true;
+ if (p_pcb->state == BTA_JV_ST_CL_CLOSING) {
+ evt_data.rfc_close.async = false;
+ }
+ // p_pcb->state = BTA_JV_ST_NONE;
+ // p_pcb->cong = false;
+ p_cback = p_cb->p_cback;
+ p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, p_pcb->rfcomm_slot_id);
+ // bta_jv_free_rfc_cb(p_cb, p_pcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_port_event_cl_cback
+ *
+ * Description Callback for RFCOMM client port events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_port_event_cl_cback(uint32_t code, uint16_t port_handle) {
+ tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+ tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ tBTA_JV evt_data;
+
+ APPL_TRACE_DEBUG("bta_jv_port_event_cl_cback:%d", port_handle);
+ if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+ APPL_TRACE_DEBUG(
+ "bta_jv_port_event_cl_cback code=x%x port_handle:%d handle:%d", code,
+ port_handle, p_cb->handle);
+ if (code & PORT_EV_RXCHAR) {
+ evt_data.data_ind.handle = p_cb->handle;
+ p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, p_pcb->rfcomm_slot_id);
+ }
+
+ if (code & PORT_EV_FC) {
+ p_pcb->cong = (code & PORT_EV_FCS) ? false : true;
+ evt_data.rfc_cong.cong = p_pcb->cong;
+ evt_data.rfc_cong.handle = p_cb->handle;
+ evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+ p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, p_pcb->rfcomm_slot_id);
+ }
+
+ if (code & PORT_EV_TXEMPTY) {
+ bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfcomm_connect
+ *
+ * Description Client initiates an RFCOMM connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data) {
+ uint16_t handle = 0;
+ uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+ tPORT_STATE port_state;
+ uint8_t sec_id = 0;
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ tBTA_JV_PCB* p_pcb;
+ tBTA_JV_API_RFCOMM_CONNECT* cc = &(p_data->rfcomm_connect);
+ tBTA_JV_RFCOMM_CL_INIT evt_data;
+
+ /* TODO DM role manager
+ L2CA_SetDesireRole(cc->role);
+ */
+
+ sec_id = bta_jv_alloc_sec_id();
+ memset(&evt_data, 0, sizeof(evt_data));
+ evt_data.sec_id = sec_id;
+ evt_data.status = BTA_JV_SUCCESS;
+ if (0 == sec_id ||
+ BTM_SetSecurityLevel(true, "", sec_id, cc->sec_mask, BT_PSM_RFCOMM,
+ BTM_SEC_PROTO_RFCOMM, cc->remote_scn) == false) {
+ evt_data.status = BTA_JV_FAILURE;
+ APPL_TRACE_ERROR(
+ "sec_id:%d is zero or BTM_SetSecurityLevel failed, remote_scn:%d",
+ sec_id, cc->remote_scn);
+ }
+
+ if (evt_data.status == BTA_JV_SUCCESS &&
+ RFCOMM_CreateConnection(UUID_SERVCLASS_SERIAL_PORT, cc->remote_scn, false,
+ BTA_JV_DEF_RFC_MTU, cc->peer_bd_addr, &handle,
+ bta_jv_port_mgmt_cl_cback) != PORT_SUCCESS) {
+ APPL_TRACE_ERROR("bta_jv_rfcomm_connect, RFCOMM_CreateConnection failed");
+ evt_data.status = BTA_JV_FAILURE;
+ }
+ if (evt_data.status == BTA_JV_SUCCESS) {
+ p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+ if (p_cb) {
+ p_cb->p_cback = cc->p_cback;
+ p_cb->sec_id = sec_id;
+ p_cb->scn = 0;
+ p_pcb->state = BTA_JV_ST_CL_OPENING;
+ p_pcb->rfcomm_slot_id = cc->rfcomm_slot_id;
+ evt_data.use_co = true;
+
+ PORT_SetEventCallback(handle, bta_jv_port_event_cl_cback);
+ PORT_SetEventMask(handle, event_mask);
+ PORT_SetDataCOCallback(handle, bta_jv_port_data_co_cback);
+
+ PORT_GetState(handle, &port_state);
+
+ port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+ PORT_SetState(handle, &port_state);
+
+ evt_data.handle = p_cb->handle;
+ } else {
+ evt_data.status = BTA_JV_FAILURE;
+ APPL_TRACE_ERROR("run out of rfc control block");
+ }
+ }
+ cc->p_cback(BTA_JV_RFCOMM_CL_INIT_EVT, (tBTA_JV*)&evt_data,
+ cc->rfcomm_slot_id);
+ if (evt_data.status == BTA_JV_FAILURE) {
+ if (sec_id) bta_jv_free_sec_id(&sec_id);
+ if (handle) RFCOMM_RemoveConnection(handle);
+ }
+}
+
+static int find_rfc_pcb(uint32_t rfcomm_slot_id, tBTA_JV_RFC_CB** cb,
+ tBTA_JV_PCB** pcb) {
+ *cb = NULL;
+ *pcb = NULL;
+ int i;
+ for (i = 0; i < MAX_RFC_PORTS; i++) {
+ uint32_t rfc_handle = bta_jv_cb.port_cb[i].handle & BTA_JV_RFC_HDL_MASK;
+ rfc_handle &= ~BTA_JV_RFCOMM_MASK;
+ if (rfc_handle && bta_jv_cb.port_cb[i].rfcomm_slot_id == rfcomm_slot_id) {
+ *pcb = &bta_jv_cb.port_cb[i];
+ *cb = &bta_jv_cb.rfc_cb[rfc_handle - 1];
+ APPL_TRACE_DEBUG(
+ "find_rfc_pcb(): FOUND rfc_cb_handle 0x%x, port.jv_handle:"
+ " 0x%x, state: %d, rfc_cb->handle: 0x%x",
+ rfc_handle, (*pcb)->handle, (*pcb)->state, (*cb)->handle);
+ return 1;
+ }
+ }
+ APPL_TRACE_DEBUG("find_rfc_pcb: cannot find rfc_cb from user data: %u",
+ rfcomm_slot_id);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfcomm_close
+ *
+ * Description Close an RFCOMM connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_RFCOMM_CLOSE* cc = &(p_data->rfcomm_close);
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ tBTA_JV_PCB* p_pcb = NULL;
+ APPL_TRACE_DEBUG("bta_jv_rfcomm_close, rfc handle:%d", cc->handle);
+ if (!cc->handle) {
+ APPL_TRACE_ERROR("bta_jv_rfcomm_close, rfc handle is null");
+ return;
+ }
+
+ if (!find_rfc_pcb(cc->rfcomm_slot_id, &p_cb, &p_pcb)) return;
+ bta_jv_free_rfc_cb(p_cb, p_pcb);
+ APPL_TRACE_DEBUG("bta_jv_rfcomm_close: sec id in use:%d, rfc_cb in use:%d",
+ get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_port_mgmt_sr_cback
+ *
+ * Description callback for port mamangement function of rfcomm
+ * server connections
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_port_mgmt_sr_cback(uint32_t code, uint16_t port_handle) {
+ tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+ tBTA_JV evt_data;
+ BD_ADDR rem_bda;
+ uint16_t lcid;
+ APPL_TRACE_DEBUG("bta_jv_port_mgmt_sr_cback, code:%d, port_handle:%d", code,
+ port_handle);
+ if (NULL == p_cb || NULL == p_cb->p_cback) {
+ APPL_TRACE_ERROR("bta_jv_port_mgmt_sr_cback, p_cb:%p, p_cb->p_cback%p",
+ p_cb, p_cb ? p_cb->p_cback : NULL);
+ return;
+ }
+ uint32_t rfcomm_slot_id = p_pcb->rfcomm_slot_id;
+ APPL_TRACE_DEBUG(
+ "bta_jv_port_mgmt_sr_cback code=%d port_handle:0x%x handle:0x%x, "
+ "p_pcb:%p, user:%d",
+ code, port_handle, p_cb->handle, p_pcb, p_pcb->rfcomm_slot_id);
+
+ PORT_CheckConnection(port_handle, rem_bda, &lcid);
+ int failed = true;
+ if (code == PORT_SUCCESS) {
+ evt_data.rfc_srv_open.handle = p_pcb->handle;
+ evt_data.rfc_srv_open.status = BTA_JV_SUCCESS;
+ bdcpy(evt_data.rfc_srv_open.rem_bda, rem_bda);
+ tBTA_JV_PCB* p_pcb_new_listen = bta_jv_add_rfc_port(p_cb, p_pcb);
+ if (p_pcb_new_listen) {
+ evt_data.rfc_srv_open.new_listen_handle = p_pcb_new_listen->handle;
+ p_pcb_new_listen->rfcomm_slot_id =
+ p_cb->p_cback(BTA_JV_RFCOMM_SRV_OPEN_EVT, &evt_data, rfcomm_slot_id);
+ APPL_TRACE_DEBUG("PORT_SUCCESS: curr_sess:%d, max_sess:%d",
+ p_cb->curr_sess, p_cb->max_sess);
+ failed = false;
+ } else
+ APPL_TRACE_ERROR("bta_jv_add_rfc_port failed to create new listen port");
+ }
+ if (failed) {
+ evt_data.rfc_close.handle = p_cb->handle;
+ evt_data.rfc_close.status = BTA_JV_FAILURE;
+ evt_data.rfc_close.async = true;
+ evt_data.rfc_close.port_status = code;
+ p_pcb->cong = false;
+
+ tBTA_JV_RFCOMM_CBACK* p_cback = p_cb->p_cback;
+ APPL_TRACE_DEBUG(
+ "PORT_CLOSED before BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+ p_cb->curr_sess, p_cb->max_sess);
+ if (BTA_JV_ST_SR_CLOSING == p_pcb->state) {
+ evt_data.rfc_close.async = false;
+ evt_data.rfc_close.status = BTA_JV_SUCCESS;
+ }
+ // p_pcb->state = BTA_JV_ST_NONE;
+ p_cback(BTA_JV_RFCOMM_CLOSE_EVT, &evt_data, rfcomm_slot_id);
+ // bta_jv_free_rfc_cb(p_cb, p_pcb);
+
+ APPL_TRACE_DEBUG(
+ "PORT_CLOSED after BTA_JV_RFCOMM_CLOSE_EVT: curr_sess:%d, max_sess:%d",
+ p_cb->curr_sess, p_cb->max_sess);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_port_event_sr_cback
+ *
+ * Description Callback for RFCOMM server port events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_port_event_sr_cback(uint32_t code, uint16_t port_handle) {
+ tBTA_JV_PCB* p_pcb = bta_jv_rfc_port_to_pcb(port_handle);
+ tBTA_JV_RFC_CB* p_cb = bta_jv_rfc_port_to_cb(port_handle);
+ tBTA_JV evt_data;
+
+ if (NULL == p_cb || NULL == p_cb->p_cback) return;
+
+ APPL_TRACE_DEBUG(
+ "bta_jv_port_event_sr_cback code=x%x port_handle:%d handle:%d", code,
+ port_handle, p_cb->handle);
+
+ uint32_t user_data = p_pcb->rfcomm_slot_id;
+ if (code & PORT_EV_RXCHAR) {
+ evt_data.data_ind.handle = p_cb->handle;
+ p_cb->p_cback(BTA_JV_RFCOMM_DATA_IND_EVT, &evt_data, user_data);
+ }
+
+ if (code & PORT_EV_FC) {
+ p_pcb->cong = (code & PORT_EV_FCS) ? false : true;
+ evt_data.rfc_cong.cong = p_pcb->cong;
+ evt_data.rfc_cong.handle = p_cb->handle;
+ evt_data.rfc_cong.status = BTA_JV_SUCCESS;
+ p_cb->p_cback(BTA_JV_RFCOMM_CONG_EVT, &evt_data, user_data);
+ }
+
+ if (code & PORT_EV_TXEMPTY) {
+ bta_jv_pm_conn_idle(p_pcb->p_pm_cb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_add_rfc_port
+ *
+ * Description add a port for server when the existing posts is open
+ *
+ * Returns return a pointer to tBTA_JV_PCB just added
+ *
+ ******************************************************************************/
+static tBTA_JV_PCB* bta_jv_add_rfc_port(tBTA_JV_RFC_CB* p_cb,
+ tBTA_JV_PCB* p_pcb_open) {
+ uint8_t used = 0, i, listen = 0;
+ uint32_t si = 0;
+ tPORT_STATE port_state;
+ uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+ tBTA_JV_PCB* p_pcb = NULL;
+ if (p_cb->max_sess > 1) {
+ for (i = 0; i < p_cb->max_sess; i++) {
+ if (p_cb->rfc_hdl[i] != 0) {
+ p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[i] - 1];
+ if (p_pcb->state == BTA_JV_ST_SR_LISTEN) {
+ listen++;
+ if (p_pcb_open == p_pcb) {
+ APPL_TRACE_DEBUG(
+ "bta_jv_add_rfc_port, port_handle:%d, change the listen port "
+ "to open state",
+ p_pcb->port_handle);
+ p_pcb->state = BTA_JV_ST_SR_OPEN;
+
+ } else {
+ APPL_TRACE_ERROR(
+ "bta_jv_add_rfc_port, open pcb not matching listen one,"
+ "listen count:%d, listen pcb handle:%d, open pcb:%d",
+ listen, p_pcb->port_handle, p_pcb_open->handle);
+ return NULL;
+ }
+ }
+ used++;
+ } else if (si == 0) {
+ si = i + 1;
+ }
+ }
+
+ APPL_TRACE_DEBUG(
+ "bta_jv_add_rfc_port max_sess=%d used:%d curr_sess:%d, listen:%d si:%d",
+ p_cb->max_sess, used, p_cb->curr_sess, listen, si);
+ if (used < p_cb->max_sess && listen == 1 && si) {
+ si--;
+ if (RFCOMM_CreateConnection(p_cb->sec_id, p_cb->scn, true,
+ BTA_JV_DEF_RFC_MTU, (uint8_t*)bd_addr_any,
+ &(p_cb->rfc_hdl[si]),
+ bta_jv_port_mgmt_sr_cback) == PORT_SUCCESS) {
+ p_cb->curr_sess++;
+ p_pcb = &bta_jv_cb.port_cb[p_cb->rfc_hdl[si] - 1];
+ p_pcb->state = BTA_JV_ST_SR_LISTEN;
+ p_pcb->port_handle = p_cb->rfc_hdl[si];
+ p_pcb->rfcomm_slot_id = p_pcb_open->rfcomm_slot_id;
+
+ PORT_ClearKeepHandleFlag(p_pcb->port_handle);
+ PORT_SetEventCallback(p_pcb->port_handle, bta_jv_port_event_sr_cback);
+ PORT_SetDataCOCallback(p_pcb->port_handle, bta_jv_port_data_co_cback);
+ PORT_SetEventMask(p_pcb->port_handle, event_mask);
+ PORT_GetState(p_pcb->port_handle, &port_state);
+
+ port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+ PORT_SetState(p_pcb->port_handle, &port_state);
+ p_pcb->handle = BTA_JV_RFC_H_S_TO_HDL(p_cb->handle, si);
+ APPL_TRACE_DEBUG(
+ "bta_jv_add_rfc_port: p_pcb->handle:0x%x, curr_sess:%d",
+ p_pcb->handle, p_cb->curr_sess);
+ }
+ } else
+ APPL_TRACE_ERROR(
+ "bta_jv_add_rfc_port, cannot create new rfc listen port");
+ }
+ APPL_TRACE_DEBUG("bta_jv_add_rfc_port: sec id in use:%d, rfc_cb in use:%d",
+ get_sec_id_used(), get_rfc_cb_used());
+ return p_pcb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfcomm_start_server
+ *
+ * Description waits for an RFCOMM client to connect
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data) {
+ uint16_t handle = 0;
+ uint32_t event_mask = BTA_JV_RFC_EV_MASK;
+ tPORT_STATE port_state;
+ uint8_t sec_id = 0;
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ tBTA_JV_PCB* p_pcb;
+ tBTA_JV_API_RFCOMM_SERVER* rs = &(p_data->rfcomm_server);
+ tBTA_JV_RFCOMM_START evt_data;
+
+ /* TODO DM role manager
+ L2CA_SetDesireRole(rs->role);
+ */
+ memset(&evt_data, 0, sizeof(evt_data));
+ evt_data.status = BTA_JV_FAILURE;
+ APPL_TRACE_DEBUG(
+ "bta_jv_rfcomm_start_server: sec id in use:%d, rfc_cb in use:%d",
+ get_sec_id_used(), get_rfc_cb_used());
+
+ do {
+ sec_id = bta_jv_alloc_sec_id();
+
+ if (0 == sec_id ||
+ BTM_SetSecurityLevel(false, "JV PORT", sec_id, rs->sec_mask,
+ BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM,
+ rs->local_scn) == false) {
+ APPL_TRACE_ERROR("bta_jv_rfcomm_start_server, run out of sec_id");
+ break;
+ }
+
+ if (RFCOMM_CreateConnection(sec_id, rs->local_scn, true, BTA_JV_DEF_RFC_MTU,
+ (uint8_t*)bd_addr_any, &handle,
+ bta_jv_port_mgmt_sr_cback) != PORT_SUCCESS) {
+ APPL_TRACE_ERROR(
+ "bta_jv_rfcomm_start_server, RFCOMM_CreateConnection failed");
+ break;
+ }
+
+ p_cb = bta_jv_alloc_rfc_cb(handle, &p_pcb);
+ if (!p_cb) {
+ APPL_TRACE_ERROR(
+ "bta_jv_rfcomm_start_server, run out of rfc control block");
+ break;
+ }
+
+ p_cb->max_sess = rs->max_session;
+ p_cb->p_cback = rs->p_cback;
+ p_cb->sec_id = sec_id;
+ p_cb->scn = rs->local_scn;
+ p_pcb->state = BTA_JV_ST_SR_LISTEN;
+ p_pcb->rfcomm_slot_id = rs->rfcomm_slot_id;
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = p_cb->handle;
+ evt_data.sec_id = sec_id;
+ evt_data.use_co = true;
+
+ PORT_ClearKeepHandleFlag(handle);
+ PORT_SetEventCallback(handle, bta_jv_port_event_sr_cback);
+ PORT_SetEventMask(handle, event_mask);
+ PORT_GetState(handle, &port_state);
+
+ port_state.fc_type = (PORT_FC_CTS_ON_INPUT | PORT_FC_CTS_ON_OUTPUT);
+
+ PORT_SetState(handle, &port_state);
+ } while (0);
+
+ rs->p_cback(BTA_JV_RFCOMM_START_EVT, (tBTA_JV*)&evt_data, rs->rfcomm_slot_id);
+ if (evt_data.status == BTA_JV_SUCCESS) {
+ PORT_SetDataCOCallback(handle, bta_jv_port_data_co_cback);
+ } else {
+ if (sec_id) bta_jv_free_sec_id(&sec_id);
+ if (handle) RFCOMM_RemoveConnection(handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfcomm_stop_server
+ *
+ * Description stops an RFCOMM server
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_RFCOMM_SERVER* ls = &(p_data->rfcomm_server);
+ tBTA_JV_RFC_CB* p_cb = NULL;
+ tBTA_JV_PCB* p_pcb = NULL;
+ APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server");
+ if (!ls->handle) {
+ APPL_TRACE_ERROR("bta_jv_rfcomm_stop_server, jv handle is null");
+ return;
+ }
+
+ if (!find_rfc_pcb(ls->rfcomm_slot_id, &p_cb, &p_pcb)) return;
+ APPL_TRACE_DEBUG("bta_jv_rfcomm_stop_server: p_pcb:%p, p_pcb->port_handle:%d",
+ p_pcb, p_pcb->port_handle);
+ bta_jv_free_rfc_cb(p_cb, p_pcb);
+ APPL_TRACE_DEBUG(
+ "bta_jv_rfcomm_stop_server: sec id in use:%d, rfc_cb in use:%d",
+ get_sec_id_used(), get_rfc_cb_used());
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_rfcomm_write
+ *
+ * Description write data to an RFCOMM connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_RFCOMM_WRITE* wc = &(p_data->rfcomm_write);
+ tBTA_JV_RFC_CB* p_cb = wc->p_cb;
+ tBTA_JV_PCB* p_pcb = wc->p_pcb;
+
+ if (p_pcb->state == BTA_JV_ST_NONE) {
+ APPL_TRACE_ERROR("%s in state BTA_JV_ST_NONE - cannot write", __func__);
+ return;
+ }
+
+ tBTA_JV_RFCOMM_WRITE evt_data;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = p_cb->handle;
+ evt_data.req_id = wc->req_id;
+ evt_data.cong = p_pcb->cong;
+ evt_data.len = 0;
+
+ bta_jv_pm_conn_busy(p_pcb->p_pm_cb);
+
+ if (!evt_data.cong &&
+ PORT_WriteDataCO(p_pcb->port_handle, &evt_data.len) == PORT_SUCCESS) {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+
+ // Update congestion flag
+ evt_data.cong = p_pcb->cong;
+
+ if (p_cb->p_cback) {
+ p_cb->p_cback(BTA_JV_RFCOMM_WRITE_EVT, (tBTA_JV*)&evt_data,
+ p_pcb->rfcomm_slot_id);
+ } else {
+ APPL_TRACE_ERROR("%s No JV callback set", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_set_pm_profile
+ *
+ * Description Set or free power mode profile for a JV application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data) {
+ tBTA_JV_STATUS status;
+ tBTA_JV_PM_CB* p_cb;
+
+ APPL_TRACE_API("bta_jv_set_pm_profile(handle: 0x%x, app_id: %d, init_st: %d)",
+ p_data->set_pm.handle, p_data->set_pm.app_id,
+ p_data->set_pm.init_st);
+
+ /* clear PM control block */
+ if (p_data->set_pm.app_id == BTA_JV_PM_ID_CLEAR) {
+ status = bta_jv_free_set_pm_profile_cb(p_data->set_pm.handle);
+
+ if (status != BTA_JV_SUCCESS) {
+ APPL_TRACE_WARNING("bta_jv_set_pm_profile() free pm cb failed: reason %d",
+ status);
+ }
+ } else /* set PM control block */
+ {
+ p_cb = bta_jv_alloc_set_pm_profile_cb(p_data->set_pm.handle,
+ p_data->set_pm.app_id);
+
+ if (NULL != p_cb)
+ bta_jv_pm_state_change(p_cb, p_data->set_pm.init_st);
+ else
+ APPL_TRACE_WARNING("bta_jv_alloc_set_pm_profile_cb() failed");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_change_pm_state
+ *
+ * Description change jv pm connect state, used internally
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_change_pm_state(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)p_data;
+
+ if (p_msg->p_cb) bta_jv_pm_state_change(p_msg->p_cb, p_msg->state);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_set_pm_conn_state
+ *
+ * Description Send pm event state change to jv state machine to serialize jv pm
+ * changes in relation to other jv messages. internal API use
+ * mainly.
+ *
+ * Params: p_cb: jv pm control block, NULL pointer returns failure
+ * new_state: new PM connections state, setting is forced by action
+ * function
+ *
+ * Returns BTA_JV_SUCCESS, BTA_JV_FAILURE (buffer allocation, or NULL ptr!)
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS bta_jv_set_pm_conn_state(tBTA_JV_PM_CB* p_cb,
+ const tBTA_JV_CONN_STATE new_st) {
+ if (p_cb == NULL) return BTA_JV_FAILURE;
+
+ APPL_TRACE_API("%s: handle:0x%x, state: %d", __func__, p_cb->handle, new_st);
+
+ tBTA_JV_API_PM_STATE_CHANGE* p_msg = (tBTA_JV_API_PM_STATE_CHANGE*)osi_malloc(
+ sizeof(tBTA_JV_API_PM_STATE_CHANGE));
+ p_msg->hdr.event = BTA_JV_API_PM_STATE_CHANGE_EVT;
+ p_msg->p_cb = p_cb;
+ p_msg->state = new_st;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_pm_conn_busy
+ *
+ * Description set pm connection busy state (input param safe)
+ *
+ * Params p_cb: pm control block of jv connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_pm_conn_busy(tBTA_JV_PM_CB* p_cb) {
+ if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST == p_cb->state))
+ bta_jv_pm_state_change(p_cb, BTA_JV_CONN_BUSY);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_pm_conn_busy
+ *
+ * Description set pm connection busy state (input param safe)
+ *
+ * Params p_cb: pm control block of jv connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_pm_conn_idle(tBTA_JV_PM_CB* p_cb) {
+ if ((NULL != p_cb) && (BTA_JV_PM_IDLE_ST != p_cb->state))
+ bta_jv_pm_state_change(p_cb, BTA_JV_CONN_IDLE);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_pm_state_change
+ *
+ * Description Notify power manager there is state change
+ *
+ * Params p_cb: must be NONE NULL
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_jv_pm_state_change(tBTA_JV_PM_CB* p_cb,
+ const tBTA_JV_CONN_STATE state) {
+ APPL_TRACE_API(
+ "bta_jv_pm_state_change(p_cb: 0x%x, handle: 0x%x, busy/idle_state: %d"
+ ", app_id: %d, conn_state: %d)",
+ p_cb, p_cb->handle, p_cb->state, p_cb->app_id, state);
+
+ switch (state) {
+ case BTA_JV_CONN_OPEN:
+ bta_sys_conn_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_CONN_CLOSE:
+ bta_sys_conn_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_APP_OPEN:
+ bta_sys_app_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_APP_CLOSE:
+ bta_sys_app_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_SCO_OPEN:
+ bta_sys_sco_open(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_SCO_CLOSE:
+ bta_sys_sco_close(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_CONN_IDLE:
+ p_cb->state = BTA_JV_PM_IDLE_ST;
+ bta_sys_idle(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ case BTA_JV_CONN_BUSY:
+ p_cb->state = BTA_JV_PM_BUSY_ST;
+ bta_sys_busy(BTA_ID_JV, p_cb->app_id, p_cb->peer_bd_addr);
+ break;
+
+ default:
+ APPL_TRACE_WARNING("bta_jv_pm_state_change(state: %d): Invalid state",
+ state);
+ break;
+ }
+}
+/******************************************************************************/
+
+static struct fc_channel* fcchan_get(uint16_t chan, char create) {
+ struct fc_channel* t = fc_channels;
+ static tL2CAP_FIXED_CHNL_REG fcr = {
+ .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
+ .pL2CA_FixedData_Cb = fcchan_data_cbk,
+ .default_idle_tout = 0xffff,
+ .fixed_chnl_opts =
+ {
+ .mode = L2CAP_FCR_BASIC_MODE,
+ .max_transmit = 0xFF,
+ .rtrans_tout = 2000,
+ .mon_tout = 12000,
+ .mps = 670,
+ .tx_win_sz = 1,
+ },
+ };
+
+ while (t && t->chan != chan) t = t->next;
+
+ if (t)
+ return t;
+ else if (!create)
+ return NULL; /* we cannot alloc a struct if not asked to */
+
+ t = static_cast<struct fc_channel*>(osi_calloc(sizeof(*t)));
+ t->chan = chan;
+
+ if (!L2CA_RegisterFixedChannel(chan, &fcr)) {
+ osi_free(t);
+ return NULL;
+ }
+
+ // link it in
+ t->next = fc_channels;
+ fc_channels = t;
+
+ return t;
+}
+
+/* pass NULL to find servers */
+static struct fc_client* fcclient_find_by_addr(struct fc_client* start,
+ BD_ADDR addr) {
+ struct fc_client* t = start;
+
+ while (t) {
+ /* match client if have addr */
+ if (addr && !memcmp(addr, &t->remote_addr, sizeof(t->remote_addr))) break;
+
+ /* match server if do not have addr */
+ if (!addr && t->server) break;
+
+ t = t->next_all_list;
+ }
+
+ return t;
+}
+
+static struct fc_client* fcclient_find_by_id(uint32_t id) {
+ struct fc_client* t = fc_clients;
+
+ while (t && t->id != id) t = t->next_all_list;
+
+ return t;
+}
+
+static struct fc_client* fcclient_alloc(uint16_t chan, char server,
+ const uint8_t* sec_id_to_use) {
+ struct fc_channel* fc = fcchan_get(chan, true);
+ struct fc_client* t;
+ uint8_t sec_id;
+
+ if (!fc) return NULL;
+
+ if (fc->has_server && server)
+ return NULL; /* no way to have multiple servers on same channel */
+
+ if (sec_id_to_use)
+ sec_id = *sec_id_to_use;
+ else
+ sec_id = bta_jv_alloc_sec_id();
+
+ t = static_cast<fc_client*>(osi_calloc(sizeof(*t)));
+ // Allocate it a unique ID
+ do {
+ t->id = ++fc_next_id;
+ } while (!t->id || fcclient_find_by_id(t->id));
+
+ // Populate some params
+ t->chan = chan;
+ t->server = server;
+
+ // Get a security id
+ t->sec_id = sec_id;
+
+ // Link it in to global list
+ t->next_all_list = fc_clients;
+ fc_clients = t;
+
+ // Link it in to channel list
+ t->next_chan_list = fc->clients;
+ fc->clients = t;
+
+ // Update channel if needed
+ if (server) fc->has_server = true;
+
+ return t;
+}
+
+static void fcclient_free(struct fc_client* fc) {
+ struct fc_client* t = fc_clients;
+ struct fc_channel* tc = fcchan_get(fc->chan, false);
+
+ // remove from global list
+ while (t && t->next_all_list != fc) t = t->next_all_list;
+
+ if (!t && fc != fc_clients) return; /* prevent double-free */
+
+ if (t)
+ t->next_all_list = fc->next_all_list;
+ else
+ fc_clients = fc->next_all_list;
+
+ // remove from channel list
+ if (tc) {
+ t = tc->clients;
+
+ while (t && t->next_chan_list != fc) t = t->next_chan_list;
+
+ if (t)
+ t->next_chan_list = fc->next_chan_list;
+ else
+ tc->clients = fc->next_chan_list;
+
+ // if was server then channel no longer has a server
+ if (fc->server) tc->has_server = false;
+ }
+
+ // free security id
+ bta_jv_free_sec_id(&fc->sec_id);
+
+ osi_free(fc);
+}
+
+static void fcchan_conn_chng_cbk(uint16_t chan, BD_ADDR bd_addr, bool connected,
+ uint16_t reason, tBT_TRANSPORT transport) {
+ tBTA_JV init_evt;
+ tBTA_JV open_evt;
+ struct fc_channel* tc;
+ struct fc_client *t = NULL, *new_conn;
+ tBTA_JV_L2CAP_CBACK* p_cback = NULL;
+ char call_init = false;
+ uint32_t l2cap_socket_id;
+
+ tc = fcchan_get(chan, false);
+ if (tc) {
+ t = fcclient_find_by_addr(
+ tc->clients, bd_addr); // try to find an open socked for that addr
+ if (t) {
+ p_cback = t->p_cback;
+ l2cap_socket_id = t->l2cap_socket_id;
+ } else {
+ t = fcclient_find_by_addr(
+ tc->clients,
+ NULL); // try to find a listening socked for that channel
+ if (t) {
+ // found: create a normal connection socket and assign the connection to
+ // it
+ new_conn = fcclient_alloc(chan, false, &t->sec_id);
+ if (new_conn) {
+ memcpy(&new_conn->remote_addr, bd_addr,
+ sizeof(new_conn->remote_addr));
+ new_conn->p_cback = NULL; // for now
+ new_conn->init_called = true; /*nop need to do it again */
+
+ p_cback = t->p_cback;
+ l2cap_socket_id = t->l2cap_socket_id;
+
+ t = new_conn;
+ }
+ } else {
+ // drop it
+ return;
+ }
+ }
+ }
+
+ if (t) {
+ if (!t->init_called) {
+ call_init = true;
+ t->init_called = true;
+
+ init_evt.l2c_cl_init.handle = t->id;
+ init_evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ init_evt.l2c_cl_init.sec_id = t->sec_id;
+ }
+
+ open_evt.l2c_open.handle = t->id;
+ open_evt.l2c_open.tx_mtu = 23; /* 23, why not ?*/
+ memcpy(&open_evt.l2c_le_open.rem_bda, &t->remote_addr,
+ sizeof(open_evt.l2c_le_open.rem_bda));
+ // TODO: (apanicke) Change the way these functions work so that casting
+ // isn't needed
+ open_evt.l2c_le_open.p_p_cback = (void**)&t->p_cback;
+ open_evt.l2c_le_open.p_user_data = (void**)&t->l2cap_socket_id;
+ open_evt.l2c_le_open.status = BTA_JV_SUCCESS;
+
+ if (connected) {
+ open_evt.l2c_open.status = BTA_JV_SUCCESS;
+ } else {
+ fcclient_free(t);
+ open_evt.l2c_open.status = BTA_JV_FAILURE;
+ }
+ }
+
+ if (call_init) p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &init_evt, l2cap_socket_id);
+
+ // call this with lock taken so socket does not disappear from under us */
+ if (p_cback) {
+ p_cback(BTA_JV_L2CAP_OPEN_EVT, &open_evt, l2cap_socket_id);
+ if (!t->p_cback) /* no callback set, means they do not want this one... */
+ fcclient_free(t);
+ }
+}
+
+static void fcchan_data_cbk(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf) {
+ tBTA_JV evt_data;
+ struct fc_channel* tc;
+ struct fc_client* t = NULL;
+ tBTA_JV_L2CAP_CBACK* sock_cback = NULL;
+ uint32_t sock_id;
+
+ tc = fcchan_get(chan, false);
+ if (tc) {
+ t = fcclient_find_by_addr(
+ tc->clients,
+ bd_addr); // try to find an open socked for that addr and channel
+ if (!t) {
+ // no socket -> drop it
+ return;
+ }
+ }
+
+ sock_cback = t->p_cback;
+ sock_id = t->l2cap_socket_id;
+ evt_data.le_data_ind.handle = t->id;
+ evt_data.le_data_ind.p_buf = p_buf;
+
+ if (sock_cback) sock_cback(BTA_JV_L2CAP_DATA_IND_EVT, &evt_data, sock_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_connect_le
+ *
+ * Description makes an le l2cap client connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_L2CAP_CONNECT* cc = &(p_data->l2cap_connect);
+ tBTA_JV evt;
+ uint32_t id;
+ char call_init_f = true;
+ struct fc_client* t;
+
+ evt.l2c_cl_init.handle = GAP_INVALID_HANDLE;
+ evt.l2c_cl_init.status = BTA_JV_FAILURE;
+
+ t = fcclient_alloc(cc->remote_chan, false, NULL);
+ if (!t) {
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->l2cap_socket_id);
+ return;
+ }
+
+ t->p_cback = cc->p_cback;
+ t->l2cap_socket_id = cc->l2cap_socket_id;
+ memcpy(&t->remote_addr, &cc->peer_bd_addr, sizeof(t->remote_addr));
+ id = t->id;
+ t->init_called = false;
+
+ if (L2CA_ConnectFixedChnl(t->chan, t->remote_addr)) {
+ evt.l2c_cl_init.status = BTA_JV_SUCCESS;
+ evt.l2c_cl_init.handle = id;
+ }
+
+ // it could have been deleted/moved from under us, so re-find it */
+ t = fcclient_find_by_id(id);
+ if (t) {
+ if (evt.l2c_cl_init.status == BTA_JV_SUCCESS)
+ call_init_f = !t->init_called;
+ else
+ fcclient_free(t);
+ }
+ if (call_init_f)
+ cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->l2cap_socket_id);
+ t->init_called = true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_stop_server_le
+ *
+ * Description stops an LE L2CAP server
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data) {
+ tBTA_JV evt;
+ tBTA_JV_API_L2CAP_SERVER* ls = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_CBACK* p_cback = NULL;
+ struct fc_channel* fcchan;
+ struct fc_client* fcclient;
+ uint32_t l2cap_socket_id;
+
+ evt.l2c_close.status = BTA_JV_FAILURE;
+ evt.l2c_close.async = false;
+ evt.l2c_close.handle = GAP_INVALID_HANDLE;
+
+ fcchan = fcchan_get(ls->local_chan, false);
+ if (fcchan) {
+ while ((fcclient = fcchan->clients)) {
+ p_cback = fcclient->p_cback;
+ l2cap_socket_id = fcclient->l2cap_socket_id;
+
+ evt.l2c_close.handle = fcclient->id;
+ evt.l2c_close.status = BTA_JV_SUCCESS;
+ evt.l2c_close.async = false;
+
+ fcclient_free(fcclient);
+
+ if (p_cback) p_cback(BTA_JV_L2CAP_CLOSE_EVT, &evt, l2cap_socket_id);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_start_server_le
+ *
+ * Description starts an LE L2CAP server
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_L2CAP_SERVER* ss = &(p_data->l2cap_server);
+ tBTA_JV_L2CAP_START evt_data;
+ struct fc_client* t;
+
+ evt_data.handle = GAP_INVALID_HANDLE;
+ evt_data.status = BTA_JV_FAILURE;
+
+ t = fcclient_alloc(ss->local_chan, true, NULL);
+ if (!t) goto out;
+
+ t->p_cback = ss->p_cback;
+ t->l2cap_socket_id = ss->l2cap_socket_id;
+
+ // if we got here, we're registered...
+ evt_data.status = BTA_JV_SUCCESS;
+ evt_data.handle = t->id;
+ evt_data.sec_id = t->sec_id;
+
+out:
+ ss->p_cback(BTA_JV_L2CAP_START_EVT, (tBTA_JV*)&evt_data, ss->l2cap_socket_id);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_jv_l2cap_close_fixed
+ *
+ * Description close a fixed channel connection. calls no callbacks. idempotent
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data) {
+ tBTA_JV_API_L2CAP_CLOSE* cc = &(p_data->l2cap_close);
+ struct fc_client* t;
+
+ t = fcclient_find_by_id(cc->handle);
+ if (t) fcclient_free(t);
+}
diff --git a/mtkbt/code/bt/bta/jv/bta_jv_api.cc b/mtkbt/code/bt/bta/jv/bta_jv_api.cc
new file mode 100755
index 0000000..4633a28
--- a/dev/null
+++ b/mtkbt/code/bt/bta/jv/bta_jv_api.cc
@@ -0,0 +1,989 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the JAVA API for Bluetooth Wireless
+ * Technology (JABWT) as specified by the JSR82 specificiation
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+#include "gap_api.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_jv_reg = {bta_jv_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function BTA_JvEnable
+ *
+ * Description Enable the Java I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_JV_ENABLE_EVT. This function must
+ * be called before other function in the JV API are
+ * called.
+ *
+ * Returns BTA_JV_SUCCESS if successful.
+ * BTA_JV_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvEnable(tBTA_JV_DM_CBACK* p_cback) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ int i;
+
+ APPL_TRACE_API("BTA_JvEnable");
+ if (p_cback && false == bta_sys_is_register(BTA_ID_JV)) {
+ memset(&bta_jv_cb, 0, sizeof(tBTA_JV_CB));
+ /* set handle to invalid value by default */
+ for (i = 0; i < BTA_JV_PM_MAX_NUM; i++) {
+ bta_jv_cb.pm_cb[i].handle = BTA_JV_PM_HANDLE_CLEAR;
+ }
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_JV, &bta_jv_reg);
+
+ if (p_cback) {
+ tBTA_JV_API_ENABLE* p_buf =
+ (tBTA_JV_API_ENABLE*)osi_malloc(sizeof(tBTA_JV_API_ENABLE));
+ p_buf->hdr.event = BTA_JV_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ status = BTA_JV_SUCCESS;
+ }
+ } else {
+ APPL_TRACE_ERROR("JVenable fails");
+ }
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvDisable
+ *
+ * Description Disable the Java I/F
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_JvDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ APPL_TRACE_API("%s", __func__);
+
+ bta_sys_deregister(BTA_ID_JV);
+ p_buf->event = BTA_JV_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvIsEncrypted
+ *
+ * Description This function checks if the link to peer device is encrypted
+ *
+ * Returns true if encrypted.
+ * false if not.
+ *
+ ******************************************************************************/
+bool BTA_JvIsEncrypted(BD_ADDR bd_addr) {
+ bool is_encrypted = false;
+ uint8_t sec_flags, le_flags;
+
+ if (BTM_GetSecurityFlags(bd_addr, &sec_flags) &&
+ BTM_GetSecurityFlagsByTransport(bd_addr, &le_flags, BT_TRANSPORT_LE)) {
+ if (sec_flags & BTM_SEC_FLAG_ENCRYPTED || le_flags & BTM_SEC_FLAG_ENCRYPTED)
+ is_encrypted = true;
+ }
+ return is_encrypted;
+}
+/*******************************************************************************
+ *
+ * Function BTA_JvGetChannelId
+ *
+ * Description This function reserves a SCN (server channel number) for
+ * applications running over RFCOMM, L2CAP of L2CAP_LE.
+ * It is primarily called by server profiles/applications to
+ * register their SCN into the SDP database. The SCN is
+ * reported by the tBTA_JV_DM_CBACK callback with a
+ * BTA_JV_GET_SCN_EVT for RFCOMM channels and
+ * BTA_JV_GET_PSM_EVT for L2CAP and LE.
+ * If the SCN/PSM reported is 0, that means all resources are
+ * exhausted.
+ * Parameters
+ * conn_type one of BTA_JV_CONN_TYPE_
+ * user_data Any uservalue - will be returned in the resulting event.
+ * channel Only used for RFCOMM - to try to allocate a specific RFCOMM
+ * channel.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvGetChannelId(int conn_type, uint32_t id, int32_t channel) {
+ tBTA_JV_API_ALLOC_CHANNEL* p_msg =
+ (tBTA_JV_API_ALLOC_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_ALLOC_CHANNEL));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_GET_CHANNEL_EVT;
+ p_msg->type = conn_type;
+ p_msg->channel = channel;
+ if (conn_type == BTA_JV_CONN_TYPE_RFCOMM) {
+ p_msg->rfcomm_slot_id = id;
+ } else if (conn_type == BTA_JV_CONN_TYPE_L2CAP ||
+ conn_type == BTA_JV_CONN_TYPE_L2CAP_LE) {
+ p_msg->l2cap_socket_id = id;
+ } else {
+ APPL_TRACE_ERROR("%s: Invalid connection type");
+ return BTA_JV_FAILURE;
+ }
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvFreeChannel
+ *
+ * Description This function frees a server channel number that was used
+ * by an application running over RFCOMM.
+ * Parameters
+ * channel The channel to free
+ * conn_type one of BTA_JV_CONN_TYPE_
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvFreeChannel(uint16_t channel, int conn_type) {
+ tBTA_JV_API_FREE_CHANNEL* p_msg =
+ (tBTA_JV_API_FREE_CHANNEL*)osi_malloc(sizeof(tBTA_JV_API_FREE_CHANNEL));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_FREE_SCN_EVT;
+ p_msg->scn = channel;
+ p_msg->type = conn_type;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvStartDiscovery
+ *
+ * Description This function performs service discovery for the services
+ * provided by the given peer device. When the operation is
+ * complete the tBTA_JV_DM_CBACK callback function will be
+ * called with a BTA_JV_DISCOVERY_COMP_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvStartDiscovery(BD_ADDR bd_addr, uint16_t num_uuid,
+ tSDP_UUID* p_uuid_list,
+ uint32_t rfcomm_slot_id) {
+ tBTA_JV_API_START_DISCOVERY* p_msg = (tBTA_JV_API_START_DISCOVERY*)osi_malloc(
+ sizeof(tBTA_JV_API_START_DISCOVERY));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_START_DISCOVERY_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ p_msg->num_uuid = num_uuid;
+ memcpy(p_msg->uuid_list, p_uuid_list, num_uuid * sizeof(tSDP_UUID));
+ p_msg->num_attr = 0;
+ p_msg->rfcomm_slot_id = rfcomm_slot_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvCreateRecord
+ *
+ * Description Create a service record in the local SDP database.
+ * When the operation is complete the tBTA_JV_DM_CBACK callback
+ * function will be called with a BTA_JV_CREATE_RECORD_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvCreateRecordByUser(uint32_t rfcomm_slot_id) {
+ tBTA_JV_API_CREATE_RECORD* p_msg =
+ (tBTA_JV_API_CREATE_RECORD*)osi_malloc(sizeof(tBTA_JV_API_CREATE_RECORD));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_CREATE_RECORD_EVT;
+ p_msg->rfcomm_slot_id = rfcomm_slot_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvDeleteRecord
+ *
+ * Description Delete a service record in the local SDP database.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvDeleteRecord(uint32_t handle) {
+ tBTA_JV_API_ADD_ATTRIBUTE* p_msg =
+ (tBTA_JV_API_ADD_ATTRIBUTE*)osi_malloc(sizeof(tBTA_JV_API_ADD_ATTRIBUTE));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_DELETE_RECORD_EVT;
+ p_msg->handle = handle;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capConnectLE
+ *
+ * Description Initiate an LE connection as a L2CAP client to the given BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnectLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t remote_chan, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_L2CAP_CONNECT* p_msg =
+ (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_chan = remote_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if (cfg != NULL) {
+ p_msg->has_cfg = true;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = false;
+ }
+ if (ertm_info != NULL) {
+ p_msg->has_ertm_info = true;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = false;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capConnect
+ *
+ * Description Initiate a connection as a L2CAP client to the given BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_L2CAP_CBACK is called with BTA_JV_L2CAP_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capConnect(int conn_type, tBTA_SEC sec_mask,
+ tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t remote_psm, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg, BD_ADDR peer_bd_addr,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_L2CAP_CONNECT* p_msg =
+ (tBTA_JV_API_L2CAP_CONNECT*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CONNECT));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CONNECT_EVT;
+ p_msg->type = conn_type;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_psm = remote_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if (cfg != NULL) {
+ p_msg->has_cfg = true;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = false;
+ }
+ if (ertm_info != NULL) {
+ p_msg->has_ertm_info = true;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = false;
+ }
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capClose
+ *
+ * Description This function closes an L2CAP client connection
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capClose(uint32_t handle) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+ APPL_TRACE_API("%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+ tBTA_JV_API_L2CAP_CLOSE* p_msg =
+ (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_EVT;
+ p_msg->handle = handle;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capCloseLE
+ *
+ * Description This function closes an L2CAP client connection for Fixed
+ * Channels Function is idempotent and no callbacks are called!
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capCloseLE(uint32_t handle) {
+ tBTA_JV_API_L2CAP_CLOSE* p_msg =
+ (tBTA_JV_API_L2CAP_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_CLOSE));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_L2CAP_CLOSE_FIXED_EVT;
+ p_msg->handle = handle;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStartServer
+ *
+ * Description This function starts an L2CAP server and listens for an
+ * L2CAP connection from a remote Bluetooth device. When the
+ * server is started successfully, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_START_EVT. When the connection is
+ * established tBTA_JV_L2CAP_CBACK is called with
+ * BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServer(int conn_type, tBTA_SEC sec_mask,
+ tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t local_psm, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_L2CAP_SERVER* p_msg =
+ (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_EVT;
+ p_msg->type = conn_type;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_psm = local_psm;
+ p_msg->rx_mtu = rx_mtu;
+ if (cfg != NULL) {
+ p_msg->has_cfg = true;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = false;
+ }
+ if (ertm_info != NULL) {
+ p_msg->has_ertm_info = true;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = false;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStartServerLE
+ *
+ * Description This function starts an LE L2CAP server and listens for an
+ * L2CAP connection from a remote Bluetooth device. When the
+ * server is started successfully, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_START_EVT. When the connection is
+ * established, tBTA_JV_L2CAP_CBACK is called with
+ * BTA_JV_L2CAP_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStartServerLE(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ const tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t local_chan, uint16_t rx_mtu,
+ tL2CAP_CFG_INFO* cfg,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_L2CAP_SERVER* p_msg =
+ (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_START_SERVER_LE_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_chan = local_chan;
+ p_msg->rx_mtu = rx_mtu;
+ if (cfg != NULL) {
+ p_msg->has_cfg = true;
+ p_msg->cfg = *cfg;
+ } else {
+ p_msg->has_cfg = false;
+ }
+ if (ertm_info != NULL) {
+ p_msg->has_ertm_info = true;
+ p_msg->ertm_info = *ertm_info;
+ } else {
+ p_msg->has_ertm_info = false;
+ }
+ p_msg->p_cback = p_cback;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStopServer
+ *
+ * Description This function stops the L2CAP server. If the server has an
+ * active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServer(uint16_t local_psm,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ tBTA_JV_API_L2CAP_SERVER* p_msg =
+ (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_EVT;
+ p_msg->local_psm = local_psm;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capStopServerLE
+ *
+ * Description This function stops the LE L2CAP server. If the server has
+ * an active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capStopServerLE(uint16_t local_chan,
+ uint32_t l2cap_socket_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ tBTA_JV_API_L2CAP_SERVER* p_msg =
+ (tBTA_JV_API_L2CAP_SERVER*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_SERVER));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT;
+ p_msg->local_chan = local_chan;
+ p_msg->l2cap_socket_id = l2cap_socket_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capRead
+ *
+ * Description This function reads data from an L2CAP connecti;
+ tBTA_JV_RFC_CB *p_cb = rc->p_cb;
+on
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_READ_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capRead(uint32_t handle, uint32_t req_id,
+ uint8_t* p_data, uint16_t len) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ tBTA_JV_L2CAP_READ evt_data;
+
+ APPL_TRACE_API("%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+ status = BTA_JV_SUCCESS;
+ evt_data.status = BTA_JV_FAILURE;
+ evt_data.handle = handle;
+ evt_data.req_id = req_id;
+ evt_data.p_data = p_data;
+ evt_data.len = 0;
+
+ if (BT_PASS ==
+ GAP_ConnReadData((uint16_t)handle, p_data, len, &evt_data.len)) {
+ evt_data.status = BTA_JV_SUCCESS;
+ }
+ bta_jv_cb.l2c_cb[handle].p_cback(BTA_JV_L2CAP_READ_EVT, (tBTA_JV*)&evt_data,
+ bta_jv_cb.l2c_cb[handle].l2cap_socket_id);
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capReady
+ *
+ * Description This function determined if there is data to read from
+ * an L2CAP connection
+ *
+ * Returns BTA_JV_SUCCESS, if data queue size is in *p_data_size.
+ * BTA_JV_FAILURE, if error.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capReady(uint32_t handle, uint32_t* p_data_size) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+ APPL_TRACE_API("%s: %d", __func__, handle);
+ if (p_data_size && handle < BTA_JV_MAX_L2C_CONN &&
+ bta_jv_cb.l2c_cb[handle].p_cback) {
+ *p_data_size = 0;
+ if (BT_PASS == GAP_GetRxQueueCnt((uint16_t)handle, p_data_size)) {
+ status = BTA_JV_SUCCESS;
+ }
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capWrite
+ *
+ * Description This function writes data to an L2CAP connection
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ * PSM-based connections
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWrite(uint32_t handle, uint32_t req_id,
+ uint8_t* p_data, uint16_t len,
+ uint32_t user_id) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+
+ APPL_TRACE_API("%s", __func__);
+
+ if (handle < BTA_JV_MAX_L2C_CONN && bta_jv_cb.l2c_cb[handle].p_cback) {
+ tBTA_JV_API_L2CAP_WRITE* p_msg =
+ (tBTA_JV_API_L2CAP_WRITE*)osi_malloc(sizeof(tBTA_JV_API_L2CAP_WRITE));
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_EVT;
+ p_msg->handle = handle;
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cb = &bta_jv_cb.l2c_cb[handle];
+ p_msg->len = len;
+ p_msg->user_id = user_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ status = BTA_JV_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvL2capWriteFixed
+ *
+ * Description This function writes data to an L2CAP connection
+ * When the operation is complete, tBTA_JV_L2CAP_CBACK is
+ * called with BTA_JV_L2CAP_WRITE_EVT. Works for
+ * fixed-channel connections
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvL2capWriteFixed(uint16_t channel, BD_ADDR* addr,
+ uint32_t req_id,
+ tBTA_JV_L2CAP_CBACK* p_cback,
+ uint8_t* p_data, uint16_t len,
+ uint32_t user_id) {
+ tBTA_JV_API_L2CAP_WRITE_FIXED* p_msg =
+ (tBTA_JV_API_L2CAP_WRITE_FIXED*)osi_malloc(
+ sizeof(tBTA_JV_API_L2CAP_WRITE_FIXED));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_L2CAP_WRITE_FIXED_EVT;
+ p_msg->channel = channel;
+ memcpy(p_msg->addr, addr, sizeof(p_msg->addr));
+ p_msg->req_id = req_id;
+ p_msg->p_data = p_data;
+ p_msg->p_cback = p_cback;
+ p_msg->len = len;
+ p_msg->user_id = user_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommConnect
+ *
+ * Description This function makes an RFCOMM conection to a remote BD
+ * Address.
+ * When the connection is initiated or failed to initiate,
+ * tBTA_JV_RFCOMM_CBACK is called with
+ * BTA_JV_RFCOMM_CL_INIT_EVT
+ * When the connection is established or failed,
+ * tBTA_JV_RFCOMM_CBACK is called with BTA_JV_RFCOMM_OPEN_EVT
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommConnect(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ uint8_t remote_scn, BD_ADDR peer_bd_addr,
+ tBTA_JV_RFCOMM_CBACK* p_cback,
+ uint32_t rfcomm_slot_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_RFCOMM_CONNECT* p_msg = (tBTA_JV_API_RFCOMM_CONNECT*)osi_malloc(
+ sizeof(tBTA_JV_API_RFCOMM_CONNECT));
+ p_msg->hdr.event = BTA_JV_API_RFCOMM_CONNECT_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->remote_scn = remote_scn;
+ memcpy(p_msg->peer_bd_addr, peer_bd_addr, sizeof(BD_ADDR));
+ p_msg->p_cback = p_cback;
+ p_msg->rfcomm_slot_id = rfcomm_slot_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommClose
+ *
+ * Description This function closes an RFCOMM connection
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommClose(uint32_t handle, uint32_t rfcomm_slot_id) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+ uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+ APPL_TRACE_API("%s", __func__);
+
+ if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+ si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+ tBTA_JV_API_RFCOMM_CLOSE* p_msg =
+ (tBTA_JV_API_RFCOMM_CLOSE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_CLOSE));
+ p_msg->hdr.event = BTA_JV_API_RFCOMM_CLOSE_EVT;
+ p_msg->handle = handle;
+ p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
+ p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
+ p_msg->rfcomm_slot_id = rfcomm_slot_id;
+
+ bta_sys_sendmsg(p_msg);
+
+ status = BTA_JV_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommStartServer
+ *
+ * Description This function starts listening for an RFCOMM connection
+ * request from a remote Bluetooth device. When the server is
+ * started successfully, tBTA_JV_RFCOMM_CBACK is called
+ * with BTA_JV_RFCOMM_START_EVT.
+ * When the connection is established, tBTA_JV_RFCOMM_CBACK
+ * is called with BTA_JV_RFCOMM_OPEN_EVT.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStartServer(tBTA_SEC sec_mask, tBTA_JV_ROLE role,
+ uint8_t local_scn, uint8_t max_session,
+ tBTA_JV_RFCOMM_CBACK* p_cback,
+ uint32_t rfcomm_slot_id) {
+ APPL_TRACE_API("%s", __func__);
+
+ if (p_cback == NULL) return BTA_JV_FAILURE; /* Nothing to do */
+
+ tBTA_JV_API_RFCOMM_SERVER* p_msg =
+ (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
+ if (max_session == 0) max_session = 1;
+ if (max_session > BTA_JV_MAX_RFC_SR_SESSION) {
+ APPL_TRACE_DEBUG("max_session is too big. use max (%d)", max_session,
+ BTA_JV_MAX_RFC_SR_SESSION);
+ max_session = BTA_JV_MAX_RFC_SR_SESSION;
+ }
+ p_msg->hdr.event = BTA_JV_API_RFCOMM_START_SERVER_EVT;
+ p_msg->sec_mask = sec_mask;
+ p_msg->role = role;
+ p_msg->local_scn = local_scn;
+ p_msg->max_session = max_session;
+ p_msg->p_cback = p_cback;
+ p_msg->rfcomm_slot_id = rfcomm_slot_id; // caller's private data
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommStopServer
+ *
+ * Description This function stops the RFCOMM server. If the server has an
+ * active connection, it would be closed.
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommStopServer(uint32_t handle,
+ uint32_t rfcomm_slot_id) {
+ tBTA_JV_API_RFCOMM_SERVER* p_msg =
+ (tBTA_JV_API_RFCOMM_SERVER*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_SERVER));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_JV_API_RFCOMM_STOP_SERVER_EVT;
+ p_msg->handle = handle;
+ p_msg->rfcomm_slot_id = rfcomm_slot_id; // caller's private data
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommGetPortHdl
+ *
+ * Description This function fetches the rfcomm port handle
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+uint16_t BTA_JvRfcommGetPortHdl(uint32_t handle) {
+ uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+ uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+ if (hi < BTA_JV_MAX_RFC_CONN && si < BTA_JV_MAX_RFC_SR_SESSION &&
+ bta_jv_cb.rfc_cb[hi].rfc_hdl[si])
+ return bta_jv_cb.port_cb[bta_jv_cb.rfc_cb[hi].rfc_hdl[si] - 1].port_handle;
+ else
+ return 0xffff;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JvRfcommWrite
+ *
+ * Description This function writes data to an RFCOMM connection
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvRfcommWrite(uint32_t handle, uint32_t req_id) {
+ tBTA_JV_STATUS status = BTA_JV_FAILURE;
+ uint32_t hi = ((handle & BTA_JV_RFC_HDL_MASK) & ~BTA_JV_RFCOMM_MASK) - 1;
+ uint32_t si = BTA_JV_RFC_HDL_TO_SIDX(handle);
+
+ APPL_TRACE_API("%s", __func__);
+
+ APPL_TRACE_DEBUG("handle:0x%x, hi:%d, si:%d", handle, hi, si);
+ if (hi < BTA_JV_MAX_RFC_CONN && bta_jv_cb.rfc_cb[hi].p_cback &&
+ si < BTA_JV_MAX_RFC_SR_SESSION && bta_jv_cb.rfc_cb[hi].rfc_hdl[si]) {
+ tBTA_JV_API_RFCOMM_WRITE* p_msg =
+ (tBTA_JV_API_RFCOMM_WRITE*)osi_malloc(sizeof(tBTA_JV_API_RFCOMM_WRITE));
+ p_msg->hdr.event = BTA_JV_API_RFCOMM_WRITE_EVT;
+ p_msg->handle = handle;
+ p_msg->req_id = req_id;
+ p_msg->p_cb = &bta_jv_cb.rfc_cb[hi];
+ p_msg->p_pcb = &bta_jv_cb.port_cb[p_msg->p_cb->rfc_hdl[si] - 1];
+ APPL_TRACE_API("write ok");
+
+ bta_sys_sendmsg(p_msg);
+ status = BTA_JV_SUCCESS;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_JVSetPmProfile
+ *
+ * Description: This function set or free power mode profile for different JV
+ * application.
+ *
+ * Parameters: handle, JV handle from RFCOMM or L2CAP
+ * app_id: app specific pm ID, can be BTA_JV_PM_ALL, see
+ * bta_dm_cfg.c for details
+ * BTA_JV_PM_ID_CLEAR: removes pm management on the handle. init_st
+ * is ignored and BTA_JV_CONN_CLOSE is called implicitly
+ * init_st: state after calling this API. typically it should be
+ * BTA_JV_CONN_OPEN
+ *
+ * Returns BTA_JV_SUCCESS, if the request is being processed.
+ * BTA_JV_FAILURE, otherwise.
+ *
+ * NOTE: BTA_JV_PM_ID_CLEAR: In general no need to be called as jv pm
+ * calls automatically
+ * BTA_JV_CONN_CLOSE to remove in case of connection close!
+ *
+ ******************************************************************************/
+tBTA_JV_STATUS BTA_JvSetPmProfile(uint32_t handle, tBTA_JV_PM_ID app_id,
+ tBTA_JV_CONN_STATE init_st) {
+ tBTA_JV_API_SET_PM_PROFILE* p_msg = (tBTA_JV_API_SET_PM_PROFILE*)osi_malloc(
+ sizeof(tBTA_JV_API_SET_PM_PROFILE));
+
+ APPL_TRACE_API("%s handle:0x%x, app_id:%d", __func__, handle, app_id);
+
+ p_msg->hdr.event = BTA_JV_API_SET_PM_PROFILE_EVT;
+ p_msg->handle = handle;
+ p_msg->app_id = app_id;
+ p_msg->init_st = init_st;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_JV_SUCCESS;
+}
diff --git a/mtkbt/code/bt/bta/jv/bta_jv_cfg.cc b/mtkbt/code/bt/bta/jv/bta_jv_cfg.cc
new file mode 100755
index 0000000..b43b035
--- a/dev/null
+++ b/mtkbt/code/bt/bta/jv/bta_jv_cfg.cc
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for advanced
+ * audio
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+
+#ifndef BTA_JV_SDP_DB_SIZE
+#define BTA_JV_SDP_DB_SIZE 4500
+#endif
+
+#ifndef BTA_JV_SDP_RAW_DATA_SIZE
+#define BTA_JV_SDP_RAW_DATA_SIZE 1800
+#endif
+
+/* The platform may choose to use dynamic memory for these data buffers.
+ * p_bta_jv_cfg->p_sdp_db must be allocated/stay allocated
+ * between BTA_JvEnable and BTA_JvDisable
+ * p_bta_jv_cfg->p_sdp_raw_data can be allocated before calling
+ * BTA_JvStartDiscovery
+ * it can be de-allocated after the last call to access the database */
+static uint8_t bta_jv_sdp_raw_data[BTA_JV_SDP_RAW_DATA_SIZE];
+static uint8_t __attribute__((aligned(4)))
+bta_jv_sdp_db_data[BTA_JV_SDP_DB_SIZE];
+
+/* JV configuration structure */
+const tBTA_JV_CFG bta_jv_cfg = {
+ BTA_JV_SDP_RAW_DATA_SIZE, /* The size of p_sdp_raw_data */
+ BTA_JV_SDP_DB_SIZE, /* The size of p_sdp_db_data */
+ bta_jv_sdp_raw_data, /* The data buffer to keep raw data */
+ (tSDP_DISCOVERY_DB*)
+ bta_jv_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_JV_CFG* p_bta_jv_cfg = (tBTA_JV_CFG*)&bta_jv_cfg;
diff --git a/mtkbt/code/bt/bta/jv/bta_jv_int.h b/mtkbt/code/bt/bta/jv/bta_jv_int.h
new file mode 100755
index 0000000..6b445ab
--- a/dev/null
+++ b/mtkbt/code/bt/bta/jv/bta_jv_int.h
@@ -0,0 +1,409 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA Java I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_JV_INT_H
+#define BTA_JV_INT_H
+
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_JV_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_JV),
+ BTA_JV_API_DISABLE_EVT,
+ BTA_JV_API_GET_CHANNEL_EVT,
+ BTA_JV_API_FREE_SCN_EVT,
+ BTA_JV_API_START_DISCOVERY_EVT,
+ BTA_JV_API_CREATE_RECORD_EVT,
+ BTA_JV_API_DELETE_RECORD_EVT,
+ BTA_JV_API_L2CAP_CONNECT_EVT,
+ BTA_JV_API_L2CAP_CLOSE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_EVT,
+ BTA_JV_API_L2CAP_READ_EVT,
+ BTA_JV_API_L2CAP_WRITE_EVT,
+ BTA_JV_API_RFCOMM_CONNECT_EVT,
+ BTA_JV_API_RFCOMM_CLOSE_EVT,
+ BTA_JV_API_RFCOMM_START_SERVER_EVT,
+ BTA_JV_API_RFCOMM_STOP_SERVER_EVT,
+ BTA_JV_API_RFCOMM_WRITE_EVT,
+ BTA_JV_API_SET_PM_PROFILE_EVT,
+ BTA_JV_API_PM_STATE_CHANGE_EVT,
+ BTA_JV_API_L2CAP_CONNECT_LE_EVT,
+ BTA_JV_API_L2CAP_START_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT,
+ BTA_JV_API_L2CAP_WRITE_FIXED_EVT,
+ BTA_JV_API_L2CAP_CLOSE_FIXED_EVT,
+ BTA_JV_MAX_INT_EVT
+};
+
+#ifndef BTA_JV_RFC_EV_MASK
+#define BTA_JV_RFC_EV_MASK \
+ (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_FC | PORT_EV_FCS)
+#endif
+
+/* data type for BTA_JV_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_JV_DM_CBACK* p_cback;
+} tBTA_JV_API_ENABLE;
+
+/* data type for BTA_JV_API_START_DISCOVERY_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ uint16_t num_uuid;
+ tSDP_UUID uuid_list[BTA_JV_MAX_UUIDS];
+ uint16_t num_attr;
+ uint16_t attr_list[BTA_JV_MAX_ATTRS];
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_START_DISCOVERY;
+
+enum {
+ BTA_JV_PM_FREE_ST = 0, /* empty PM slot */
+ BTA_JV_PM_IDLE_ST,
+ BTA_JV_PM_BUSY_ST
+};
+
+/* BTA JV PM control block */
+typedef struct {
+ uint32_t handle; /* The connection handle */
+ uint8_t state; /* state: see above enum */
+ tBTA_JV_PM_ID app_id; /* JV app specific id indicating power table to use */
+ BD_ADDR peer_bd_addr; /* Peer BD address */
+} tBTA_JV_PM_CB;
+
+enum {
+ BTA_JV_ST_NONE = 0,
+ BTA_JV_ST_CL_OPENING,
+ BTA_JV_ST_CL_OPEN,
+ BTA_JV_ST_CL_CLOSING,
+ BTA_JV_ST_SR_LISTEN,
+ BTA_JV_ST_SR_OPEN,
+ BTA_JV_ST_SR_CLOSING
+};
+typedef uint8_t tBTA_JV_STATE;
+#define BTA_JV_ST_CL_MAX BTA_JV_ST_CL_CLOSING
+/* JV L2CAP control block */
+typedef struct {
+ tBTA_JV_L2CAP_CBACK* p_cback; /* the callback function */
+ uint16_t psm; /* the psm used for this server connection */
+ tBTA_JV_STATE state; /* the state of this control block */
+ tBTA_SERVICE_ID sec_id; /* service id */
+ uint32_t handle; /* the handle reported to java app (same as gap handle) */
+ bool cong; /* true, if congested */
+ tBTA_JV_PM_CB* p_pm_cb; /* ptr to pm control block, NULL: unused */
+ uint32_t l2cap_socket_id;
+} tBTA_JV_L2C_CB;
+
+#define BTA_JV_RFC_HDL_MASK 0xFF
+#define BTA_JV_RFCOMM_MASK 0x80
+#define BTA_JV_ALL_APP_ID 0xFF
+#define BTA_JV_RFC_HDL_TO_SIDX(r) (((r)&0xFF00) >> 8)
+#define BTA_JV_RFC_H_S_TO_HDL(h, s) ((h) | ((s) << 8))
+
+/* port control block */
+typedef struct {
+ uint32_t handle; /* the rfcomm session handle at jv */
+ uint16_t port_handle; /* port handle */
+ tBTA_JV_STATE state; /* the state of this control block */
+ uint8_t max_sess; /* max sessions */
+ uint32_t rfcomm_slot_id;
+ bool cong; /* true, if congested */
+ tBTA_JV_PM_CB* p_pm_cb; /* ptr to pm control block, NULL: unused */
+} tBTA_JV_PCB;
+
+/* JV RFCOMM control block */
+typedef struct {
+ tBTA_JV_RFCOMM_CBACK* p_cback; /* the callback function */
+ uint16_t rfc_hdl[BTA_JV_MAX_RFC_SR_SESSION];
+ tBTA_SERVICE_ID sec_id; /* service id */
+ uint8_t handle; /* index: the handle reported to java app */
+ uint8_t scn; /* the scn of the server */
+ uint8_t max_sess; /* max sessions */
+ int curr_sess; /* current sessions count*/
+} tBTA_JV_RFC_CB;
+
+/* data type for BTA_JV_API_L2CAP_CONNECT_EVT & BTA_JV_API_L2CAP_CONNECT_LE_EVT
+ */
+typedef struct {
+ BT_HDR hdr;
+ int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ uint16_t remote_psm;
+ uint16_t remote_chan;
+ };
+ uint16_t rx_mtu;
+ BD_ADDR peer_bd_addr;
+ int32_t has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ int32_t has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint32_t l2cap_socket_id;
+} tBTA_JV_API_L2CAP_CONNECT;
+
+/* data type for BTA_JV_API_L2CAP_SERVER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ union {
+ uint16_t local_psm;
+ uint16_t local_chan;
+ };
+ uint16_t rx_mtu;
+ int32_t has_cfg;
+ tL2CAP_CFG_INFO cfg;
+ int32_t has_ertm_info;
+ tL2CAP_ERTM_INFO ertm_info;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint32_t l2cap_socket_id;
+} tBTA_JV_API_L2CAP_SERVER;
+
+/* data type for BTA_JV_API_L2CAP_CLOSE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ tBTA_JV_L2C_CB* p_cb;
+} tBTA_JV_API_L2CAP_CLOSE;
+
+/* data type for BTA_JV_API_L2CAP_READ_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ uint32_t req_id;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint8_t* p_data;
+ uint16_t len;
+ uint32_t l2cap_socket_id;
+} tBTA_JV_API_L2CAP_READ;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ uint32_t req_id;
+ tBTA_JV_L2C_CB* p_cb;
+ uint8_t* p_data;
+ uint16_t len;
+ uint32_t user_id;
+} tBTA_JV_API_L2CAP_WRITE;
+
+/* data type for BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint16_t channel;
+ BD_ADDR addr;
+ uint32_t req_id;
+ tBTA_JV_L2CAP_CBACK* p_cback;
+ uint8_t* p_data;
+ uint16_t len;
+ uint32_t user_id;
+} tBTA_JV_API_L2CAP_WRITE_FIXED;
+
+/* data type for BTA_JV_API_RFCOMM_CONNECT_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ uint8_t remote_scn;
+ BD_ADDR peer_bd_addr;
+ tBTA_JV_RFCOMM_CBACK* p_cback;
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_RFCOMM_CONNECT;
+
+/* data type for BTA_JV_API_RFCOMM_SERVER_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_SEC sec_mask;
+ tBTA_JV_ROLE role;
+ uint8_t local_scn;
+ uint8_t max_session;
+ uint32_t handle;
+ tBTA_JV_RFCOMM_CBACK* p_cback;
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_RFCOMM_SERVER;
+
+/* data type for BTA_JV_API_SET_PM_PROFILE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ tBTA_JV_PM_ID app_id;
+ tBTA_JV_CONN_STATE init_st;
+} tBTA_JV_API_SET_PM_PROFILE;
+
+/* data type for BTA_JV_API_PM_STATE_CHANGE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_JV_PM_CB* p_cb;
+ tBTA_JV_CONN_STATE state;
+} tBTA_JV_API_PM_STATE_CHANGE;
+
+/* data type for BTA_JV_API_RFCOMM_WRITE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ uint32_t req_id;
+ uint8_t* p_data;
+ int len;
+ tBTA_JV_RFC_CB* p_cb;
+ tBTA_JV_PCB* p_pcb;
+} tBTA_JV_API_RFCOMM_WRITE;
+
+/* data type for BTA_JV_API_RFCOMM_CLOSE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ tBTA_JV_RFC_CB* p_cb;
+ tBTA_JV_PCB* p_pcb;
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_RFCOMM_CLOSE;
+
+/* data type for BTA_JV_API_CREATE_RECORD_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_CREATE_RECORD;
+
+/* data type for BTA_JV_API_ADD_ATTRIBUTE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ uint32_t handle;
+ uint16_t attr_id;
+ uint8_t* p_value;
+ int32_t value_size;
+} tBTA_JV_API_ADD_ATTRIBUTE;
+
+/* data type for BTA_JV_API_FREE_SCN_EVT */
+typedef struct {
+ BT_HDR hdr;
+ int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+ uint16_t scn;
+} tBTA_JV_API_FREE_CHANNEL;
+
+/* data type for BTA_JV_API_ALLOC_CHANNEL_EVT */
+typedef struct {
+ BT_HDR hdr;
+ int32_t type; /* One of BTA_JV_CONN_TYPE_ */
+ int32_t channel; /* optionally request a specific channel */
+ uint32_t l2cap_socket_id;
+ uint32_t rfcomm_slot_id;
+} tBTA_JV_API_ALLOC_CHANNEL;
+/* union of all data types */
+typedef union {
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_JV_API_ENABLE enable;
+ tBTA_JV_API_START_DISCOVERY start_discovery;
+ tBTA_JV_API_ALLOC_CHANNEL alloc_channel;
+ tBTA_JV_API_FREE_CHANNEL free_channel;
+ tBTA_JV_API_CREATE_RECORD create_record;
+ tBTA_JV_API_ADD_ATTRIBUTE add_attr;
+ tBTA_JV_API_L2CAP_CONNECT l2cap_connect;
+ tBTA_JV_API_L2CAP_READ l2cap_read;
+ tBTA_JV_API_L2CAP_WRITE l2cap_write;
+ tBTA_JV_API_L2CAP_CLOSE l2cap_close;
+ tBTA_JV_API_L2CAP_SERVER l2cap_server;
+ tBTA_JV_API_RFCOMM_CONNECT rfcomm_connect;
+ tBTA_JV_API_RFCOMM_WRITE rfcomm_write;
+ tBTA_JV_API_SET_PM_PROFILE set_pm;
+ tBTA_JV_API_PM_STATE_CHANGE change_pm_state;
+ tBTA_JV_API_RFCOMM_CLOSE rfcomm_close;
+ tBTA_JV_API_RFCOMM_SERVER rfcomm_server;
+ tBTA_JV_API_L2CAP_WRITE_FIXED l2cap_write_fixed;
+} tBTA_JV_MSG;
+
+/* JV control block */
+typedef struct {
+ /* the SDP handle reported to JV user is the (index + 1) to sdp_handle[].
+ * if sdp_handle[i]==0, it's not used.
+ * otherwise sdp_handle[i] is the stack SDP handle. */
+ uint32_t sdp_handle[BTA_JV_MAX_SDP_REC]; /* SDP records created */
+ uint8_t* p_sel_raw_data; /* the raw data of last service select */
+ tBTA_JV_DM_CBACK* p_dm_cback;
+ tBTA_JV_L2C_CB l2c_cb[BTA_JV_MAX_L2C_CONN]; /* index is GAP handle (index) */
+ tBTA_JV_RFC_CB rfc_cb[BTA_JV_MAX_RFC_CONN];
+ tBTA_JV_PCB port_cb[MAX_RFC_PORTS]; /* index of this array is
+ the port_handle, */
+ uint8_t sec_id[BTA_JV_NUM_SERVICE_ID]; /* service ID */
+ bool scn[BTA_JV_MAX_SCN]; /* SCN allocated by java */
+ uint16_t free_psm_list[BTA_JV_MAX_L2C_CONN]; /* PSMs freed by java
+ (can be reused) */
+ uint8_t sdp_active; /* see BTA_JV_SDP_ACT_* */
+ tSDP_UUID uuid; /* current uuid of sdp discovery*/
+ tBTA_JV_PM_CB pm_cb[BTA_JV_PM_MAX_NUM]; /* PM on a per JV handle bases */
+} tBTA_JV_CB;
+
+enum {
+ BTA_JV_SDP_ACT_NONE = 0,
+ BTA_JV_SDP_ACT_YES, /* waiting for SDP result */
+ BTA_JV_SDP_ACT_CANCEL /* waiting for cancel complete */
+};
+
+/* JV control block */
+extern tBTA_JV_CB bta_jv_cb;
+
+/* config struct */
+extern tBTA_JV_CFG* p_bta_jv_cfg;
+
+extern bool bta_jv_sm_execute(BT_HDR* p_msg);
+
+extern void bta_jv_enable(tBTA_JV_MSG* p_data);
+extern void bta_jv_disable(tBTA_JV_MSG* p_data);
+extern void bta_jv_get_channel_id(tBTA_JV_MSG* p_data);
+extern void bta_jv_free_scn(tBTA_JV_MSG* p_data);
+extern void bta_jv_start_discovery(tBTA_JV_MSG* p_data);
+extern void bta_jv_create_record(tBTA_JV_MSG* p_data);
+extern void bta_jv_delete_record(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_connect(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_close(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_start_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_stop_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_read(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_write(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_connect(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_close(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_start_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_stop_server(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_read(tBTA_JV_MSG* p_data);
+extern void bta_jv_rfcomm_write(tBTA_JV_MSG* p_data);
+extern void bta_jv_set_pm_profile(tBTA_JV_MSG* p_data);
+extern void bta_jv_change_pm_state(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_connect_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_start_server_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_stop_server_le(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_write_fixed(tBTA_JV_MSG* p_data);
+extern void bta_jv_l2cap_close_fixed(tBTA_JV_MSG* p_data);
+
+#endif /* BTA_JV_INT_H */
diff --git a/mtkbt/code/bt/bta/jv/bta_jv_main.cc b/mtkbt/code/bt/bta/jv/bta_jv_main.cc
new file mode 100755
index 0000000..fd5ce3a
--- a/dev/null
+++ b/mtkbt/code/bt/bta/jv/bta_jv_main.cc
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA Java I/F
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_JV_CB bta_jv_cb;
+
+/* state machine action enumeration list */
+#define BTA_JV_NUM_ACTIONS (BTA_JV_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_JV_ACTION)(tBTA_JV_MSG* p_data);
+
+/* action function list */
+const tBTA_JV_ACTION bta_jv_action[] = {
+ bta_jv_enable, /* BTA_JV_API_ENABLE_EVT */
+ bta_jv_disable, /* BTA_JV_API_DISABLE_EVT */
+ bta_jv_get_channel_id, /* BTA_JV_API_GET_CHANNEL_EVT */
+ bta_jv_free_scn, /* BTA_JV_API_FREE_SCN_EVT */
+ bta_jv_start_discovery, /* BTA_JV_API_START_DISCOVERY_EVT */
+ bta_jv_create_record, /* BTA_JV_API_CREATE_RECORD_EVT */
+ bta_jv_delete_record, /* BTA_JV_API_DELETE_RECORD_EVT */
+ bta_jv_l2cap_connect, /* BTA_JV_API_L2CAP_CONNECT_EVT */
+ bta_jv_l2cap_close, /* BTA_JV_API_L2CAP_CLOSE_EVT */
+ bta_jv_l2cap_start_server, /* BTA_JV_API_L2CAP_START_SERVER_EVT */
+ bta_jv_l2cap_stop_server, /* BTA_JV_API_L2CAP_STOP_SERVER_EVT */
+ bta_jv_l2cap_read, /* BTA_JV_API_L2CAP_READ_EVT */
+ bta_jv_l2cap_write, /* BTA_JV_API_L2CAP_WRITE_EVT */
+ bta_jv_rfcomm_connect, /* BTA_JV_API_RFCOMM_CONNECT_EVT */
+ bta_jv_rfcomm_close, /* BTA_JV_API_RFCOMM_CLOSE_EVT */
+ bta_jv_rfcomm_start_server, /* BTA_JV_API_RFCOMM_START_SERVER_EVT */
+ bta_jv_rfcomm_stop_server, /* BTA_JV_API_RFCOMM_STOP_SERVER_EVT */
+ bta_jv_rfcomm_write, /* BTA_JV_API_RFCOMM_WRITE_EVT */
+ bta_jv_set_pm_profile, /* BTA_JV_API_SET_PM_PROFILE_EVT */
+ bta_jv_change_pm_state, /* BTA_JV_API_PM_STATE_CHANGE_EVT */
+ bta_jv_l2cap_connect_le, /* BTA_JV_API_L2CAP_CONNECT_LE_EVT */
+ bta_jv_l2cap_start_server_le, /* BTA_JV_API_L2CAP_START_SERVER_LE_EVT */
+ bta_jv_l2cap_stop_server_le, /* BTA_JV_API_L2CAP_STOP_SERVER_LE_EVT */
+ bta_jv_l2cap_write_fixed, /* BTA_JV_API_L2CAP_WRITE_FIXED_EVT */
+ bta_jv_l2cap_close_fixed, /* BTA_JV_API_L2CAP_CLOSE_FIXED_EVT */
+};
+
+/*******************************************************************************
+ *
+ * Function bta_jv_sm_execute
+ *
+ * Description State machine event handling function for JV
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_jv_sm_execute(BT_HDR* p_msg) {
+ bool ret = false;
+ uint16_t action = (p_msg->event & 0x00ff);
+ /* execute action functions */
+
+ if (action < BTA_JV_NUM_ACTIONS) {
+ (*bta_jv_action[action])((tBTA_JV_MSG*)p_msg);
+ ret = true;
+ }
+
+ return (ret);
+}
diff --git a/mtkbt/code/bt/bta/mce/bta_mce_act.cc b/mtkbt/code/bt/bta/mce/bta_mce_act.cc
new file mode 100755
index 0000000..7851c76
--- a/dev/null
+++ b/mtkbt/code/bt/bta/mce/bta_mce_act.cc
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for MCE.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBT_UUID bta_mce_mas_uuid = {
+ .len = 2, .uu.uuid16 = UUID_SERVCLASS_MESSAGE_ACCESS};
+
+/*******************************************************************************
+ *
+ * Function bta_mce_search_cback
+ *
+ * Description Callback from btm after search is completed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bta_mce_search_cback(uint16_t result, void* user_data) {
+ tSDP_DISC_REC* p_rec = NULL;
+ tBTA_MCE_MAS_DISCOVERY_COMP evt_data;
+ int found = 0;
+
+ APPL_TRACE_DEBUG("bta_mce_start_discovery_cback res: 0x%x", result);
+
+ bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_NONE;
+
+ if (bta_mce_cb.p_dm_cback == NULL) return;
+
+ evt_data.status = BTA_MCE_FAILURE;
+ bdcpy(evt_data.remote_addr, bta_mce_cb.remote_addr);
+ evt_data.num_mas = 0;
+
+ if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+ do {
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+
+ p_rec = SDP_FindServiceUUIDInDb(p_bta_mce_cfg->p_sdp_db,
+ (tBT_UUID*)&bta_mce_mas_uuid, p_rec);
+
+ APPL_TRACE_DEBUG("p_rec:%p", p_rec);
+
+ if (p_rec == NULL) break;
+
+ if (!SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe))
+ continue;
+
+ evt_data.mas[found].scn = pe.params[0];
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr == NULL) continue;
+
+ evt_data.mas[found].p_srv_name = (char*)p_attr->attr_value.v.array;
+ evt_data.mas[found].srv_name_len =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID);
+ if (p_attr == NULL) break;
+
+ evt_data.mas[found].instance_id = p_attr->attr_value.v.u8;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE);
+ if (p_attr == NULL) break;
+
+ evt_data.mas[found].msg_type = p_attr->attr_value.v.u8;
+
+ found++;
+ } while (p_rec != NULL && found < BTA_MCE_MAX_MAS_INSTANCES);
+
+ evt_data.num_mas = found;
+ evt_data.status = BTA_MCE_SUCCESS;
+ }
+
+ bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&evt_data,
+ user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_mce_enable
+ *
+ * Description Initializes the MCE I/F
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_mce_enable(tBTA_MCE_MSG* p_data) {
+ tBTA_MCE_STATUS status = BTA_MCE_SUCCESS;
+ bta_mce_cb.p_dm_cback = p_data->enable.p_cback;
+ bta_mce_cb.p_dm_cback(BTA_MCE_ENABLE_EVT, (tBTA_MCE*)&status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_mce_get_remote_mas_instances
+ *
+ * Description Discovers MAS instances on remote device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_mce_get_remote_mas_instances(tBTA_MCE_MSG* p_data) {
+ if (p_data == NULL) {
+ APPL_TRACE_DEBUG("MCE control block handle is null");
+ return;
+ }
+ tBTA_MCE_STATUS status = BTA_MCE_FAILURE;
+
+ APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_mce_cb.sdp_active);
+
+ if (bta_mce_cb.sdp_active != BTA_MCE_SDP_ACT_NONE) {
+ /* SDP is still in progress */
+ status = BTA_MCE_BUSY;
+ if (bta_mce_cb.p_dm_cback)
+ bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&status,
+ NULL);
+
+ return;
+ }
+
+ bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_YES;
+ bdcpy(bta_mce_cb.remote_addr, p_data->get_rmt_mas.bd_addr);
+
+ SDP_InitDiscoveryDb(p_bta_mce_cfg->p_sdp_db, p_bta_mce_cfg->sdp_db_size, 1,
+ (tBT_UUID*)&bta_mce_mas_uuid, 0, NULL);
+
+ if (!SDP_ServiceSearchAttributeRequest2(p_data->get_rmt_mas.bd_addr,
+ p_bta_mce_cfg->p_sdp_db,
+ bta_mce_search_cback, NULL)) {
+ bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_NONE;
+
+ /* failed to start SDP. report the failure right away */
+ if (bta_mce_cb.p_dm_cback)
+ bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*)&status,
+ NULL);
+ }
+ /*
+ else report the result when the cback is called
+ */
+}
diff --git a/mtkbt/code/bt/bta/mce/bta_mce_api.cc b/mtkbt/code/bt/bta/mce/bta_mce_api.cc
new file mode 100755
index 0000000..e9233d9
--- a/dev/null
+++ b/mtkbt/code/bt/bta/mce/bta_mce_api.cc
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for MCE subsystem
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_mce_reg = {bta_mce_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function BTA_MceEnable
+ *
+ * Description Enable the MCE I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_MCE_ENABLE_EVT. This function must
+ * be called before other functions in the MCE API are
+ * called.
+ *
+ * Returns BTA_MCE_SUCCESS if successful.
+ * BTA_MCE_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_MCE_STATUS BTA_MceEnable(tBTA_MCE_DM_CBACK* p_cback) {
+ tBTA_MCE_STATUS status = BTA_MCE_FAILURE;
+
+ APPL_TRACE_API("%", __func__);
+
+ if (p_cback && false == bta_sys_is_register(BTA_ID_MCE)) {
+ memset(&bta_mce_cb, 0, sizeof(tBTA_MCE_CB));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_MCE, &bta_mce_reg);
+
+ if (p_cback) {
+ tBTA_MCE_API_ENABLE* p_buf =
+ (tBTA_MCE_API_ENABLE*)osi_malloc(sizeof(tBTA_MCE_API_ENABLE));
+ p_buf->hdr.event = BTA_MCE_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ status = BTA_MCE_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_MceGetRemoteMasInstances
+ *
+ * Description This function performs service discovery for the MAS service
+ * by the given peer device. When the operation is completed
+ * the tBTA_MCE_DM_CBACK callback function will be called with
+ * a BTA_MCE_MAS_DISCOVERY_COMP_EVT.
+ *
+ * Returns BTA_MCE_SUCCESS, if the request is being processed.
+ * BTA_MCE_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_MCE_STATUS BTA_MceGetRemoteMasInstances(BD_ADDR bd_addr) {
+ tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES* p_msg =
+ (tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES*)osi_malloc(
+ sizeof(tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_MCE_SUCCESS;
+}
diff --git a/mtkbt/code/bt/bta/mce/bta_mce_cfg.cc b/mtkbt/code/bt/bta/mce/bta_mce_cfg.cc
new file mode 100755
index 0000000..3beb265
--- a/dev/null
+++ b/mtkbt/code/bt/bta/mce/bta_mce_cfg.cc
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for MCE
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+
+#ifndef BTA_MCE_SDP_DB_SIZE
+#define BTA_MCE_SDP_DB_SIZE 4500
+#endif
+
+static uint8_t __attribute__((aligned(4)))
+bta_mce_sdp_db_data[BTA_MCE_SDP_DB_SIZE];
+
+/* MCE configuration structure */
+const tBTA_MCE_CFG bta_mce_cfg = {
+ BTA_MCE_SDP_DB_SIZE,
+ (tSDP_DISCOVERY_DB*)
+ bta_mce_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_MCE_CFG* p_bta_mce_cfg = (tBTA_MCE_CFG*)&bta_mce_cfg;
diff --git a/mtkbt/code/bt/bta/mce/bta_mce_int.h b/mtkbt/code/bt/bta/mce/bta_mce_int.h
new file mode 100755
index 0000000..e249d74
--- a/dev/null
+++ b/mtkbt/code/bt/bta/mce/bta_mce_int.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_MCE_INT_H
+#define BTA_MCE_INT_H
+
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_MCE_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_MCE),
+ BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT,
+ BTA_MCE_MAX_INT_EVT
+};
+
+/* data type for BTA_MCE_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_MCE_DM_CBACK* p_cback;
+} tBTA_MCE_API_ENABLE;
+
+/* data type for BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES;
+
+/* union of all data types */
+typedef union {
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_MCE_API_ENABLE enable;
+ tBTA_MCE_API_GET_REMOTE_MAS_INSTANCES get_rmt_mas;
+} tBTA_MCE_MSG;
+
+/* MCE control block */
+typedef struct {
+ uint8_t sdp_active; /* see BTA_MCE_SDP_ACT_* */
+ BD_ADDR remote_addr;
+ tBTA_MCE_DM_CBACK* p_dm_cback;
+} tBTA_MCE_CB;
+
+enum {
+ BTA_MCE_SDP_ACT_NONE = 0,
+ BTA_MCE_SDP_ACT_YES /* waiting for SDP result */
+};
+
+/* MCE control block */
+extern tBTA_MCE_CB bta_mce_cb;
+
+/* config struct */
+extern tBTA_MCE_CFG* p_bta_mce_cfg;
+
+extern bool bta_mce_sm_execute(BT_HDR* p_msg);
+
+extern void bta_mce_enable(tBTA_MCE_MSG* p_data);
+extern void bta_mce_get_remote_mas_instances(tBTA_MCE_MSG* p_data);
+
+#endif /* BTA_MCE_INT_H */
diff --git a/mtkbt/code/bt/bta/mce/bta_mce_main.cc b/mtkbt/code/bt/bta/mce/bta_mce_main.cc
new file mode 100755
index 0000000..abd3e5c
--- a/dev/null
+++ b/mtkbt/code/bt/bta/mce/bta_mce_main.cc
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "bta_mce_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_MCE_CB bta_mce_cb;
+
+/* state machine action enumeration list */
+#define BTA_MCE_NUM_ACTIONS (BTA_MCE_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_MCE_ACTION)(tBTA_MCE_MSG* p_data);
+
+/* action function list */
+const tBTA_MCE_ACTION bta_mce_action[] = {
+ bta_mce_enable, /* BTA_MCE_API_ENABLE_EVT */
+ bta_mce_get_remote_mas_instances, /* BTA_MCE_API_GET_REMOTE_MAS_INSTANCES_EVT
+ */
+};
+
+/*******************************************************************************
+ *
+ * Function bta_mce_sm_execute
+ *
+ * Description State machine event handling function for MCE
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_mce_sm_execute(BT_HDR* p_msg) {
+ if (p_msg == NULL) return false;
+
+ bool ret = false;
+ uint16_t action = (p_msg->event & 0x00ff);
+
+ /* execute action functions */
+ if (action < BTA_MCE_NUM_ACTIONS) {
+ (*bta_mce_action[action])((tBTA_MCE_MSG*)p_msg);
+ ret = true;
+ }
+
+ return (ret);
+}
diff --git a/mtkbt/code/bt/bta/pan/bta_pan_act.cc b/mtkbt/code/bt/bta/pan/bta_pan_act.cc
new file mode 100755
index 0000000..a1b31e6
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pan/bta_pan_act.cc
@@ -0,0 +1,707 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the pan action functions for the state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (PAN_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_co.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+#include "utl.h"
+
+/* RX and TX data flow mask */
+#define BTA_PAN_RX_MASK 0x0F
+#define BTA_PAN_TX_MASK 0xF0
+
+/*******************************************************************************
+ *
+ * Function bta_pan_pm_conn_busy
+ *
+ * Description set pan pm connection busy state
+ *
+ * Params p_scb: state machine control block of pan connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_pm_conn_busy(tBTA_PAN_SCB* p_scb) {
+ if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
+ bta_sys_busy(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_pm_conn_idle
+ *
+ * Description set pan pm connection idle state
+ *
+ * Params p_scb: state machine control block of pan connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_pm_conn_idle(tBTA_PAN_SCB* p_scb) {
+ if ((p_scb != NULL) && (p_scb->state != BTA_PAN_IDLE_ST))
+ bta_sys_idle(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_conn_state_cback
+ *
+ * Description Connection state callback from Pan profile
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_conn_state_cback(uint16_t handle, BD_ADDR bd_addr,
+ tPAN_RESULT state, bool is_role_change,
+ uint8_t src_role, uint8_t dst_role) {
+ tBTA_PAN_SCB* p_scb;
+ tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
+
+ if ((state == PAN_SUCCESS) && !is_role_change) {
+ p_buf->hdr.event = BTA_PAN_CONN_OPEN_EVT;
+ p_scb = bta_pan_scb_by_handle(handle);
+ if (p_scb == NULL) {
+ /* allocate an scb */
+ p_scb = bta_pan_scb_alloc();
+ }
+ /* we have exceeded maximum number of connections */
+ if (!p_scb) {
+ PAN_Disconnect(handle);
+ return;
+ }
+
+ p_scb->handle = handle;
+ p_scb->local_role = src_role;
+ p_scb->peer_role = dst_role;
+ p_scb->pan_flow_enable = true;
+ bdcpy(p_scb->bd_addr, bd_addr);
+ p_scb->data_queue = fixed_queue_new(SIZE_MAX);
+
+ if (src_role == PAN_ROLE_CLIENT)
+ p_scb->app_id = bta_pan_cb.app_id[0];
+ else if (src_role == PAN_ROLE_GN_SERVER)
+ p_scb->app_id = bta_pan_cb.app_id[1];
+ else if (src_role == PAN_ROLE_NAP_SERVER)
+ p_scb->app_id = bta_pan_cb.app_id[2];
+ } else if ((state != PAN_SUCCESS) && !is_role_change) {
+ p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+ } else {
+ return;
+ }
+
+ p_buf->result = state;
+ p_buf->hdr.layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_data_flow_cb
+ *
+ * Description Data flow status callback from PAN
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_data_flow_cb(uint16_t handle, tPAN_RESULT result) {
+ tBTA_PAN_SCB* p_scb;
+
+ p_scb = bta_pan_scb_by_handle(handle);
+ if (p_scb == NULL) return;
+
+ if (result == PAN_TX_FLOW_ON) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_BNEP_FLOW_ENABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ bta_pan_co_rx_flow(handle, p_scb->app_id, true);
+ } else if (result == PAN_TX_FLOW_OFF) {
+ p_scb->pan_flow_enable = false;
+ bta_pan_co_rx_flow(handle, p_scb->app_id, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_data_buf_ind_cback
+ *
+ * Description data indication callback from pan profile
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_data_buf_ind_cback(uint16_t handle, BD_ADDR src,
+ BD_ADDR dst, uint16_t protocol,
+ BT_HDR* p_buf, bool ext, bool forward) {
+ tBTA_PAN_SCB* p_scb;
+ BT_HDR* p_new_buf;
+ /** M: Bug fix for abnormal memory release @{ */
+ BD_ADDR dst_temp;
+ bdcpy(dst_temp,dst);
+ /** @} */
+ if (sizeof(tBTA_PAN_DATA_PARAMS) > p_buf->offset) {
+ /* offset smaller than data structure in front of actual data */
+ if (sizeof(BT_HDR) + sizeof(tBTA_PAN_DATA_PARAMS) + p_buf->len >
+ PAN_BUF_SIZE) {
+ APPL_TRACE_ERROR("%s: received buffer length too large: %d", __func__,
+ p_buf->len);
+ osi_free(p_buf);
+ return;
+ }
+ p_new_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+ memcpy((uint8_t*)(p_new_buf + 1) + sizeof(tBTA_PAN_DATA_PARAMS),
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+ p_new_buf->len = p_buf->len;
+ p_new_buf->offset = sizeof(tBTA_PAN_DATA_PARAMS);
+ osi_free(p_buf);
+ } else {
+ p_new_buf = p_buf;
+ }
+ /* copy params into the space before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS*)p_new_buf)->src, src);
+ /** M: Bug fix for abnormal memory release @{ */
+ //bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst);
+ bdcpy(((tBTA_PAN_DATA_PARAMS *)p_new_buf)->dst, dst_temp);
+ /** @} */
+ ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->ext = ext;
+ ((tBTA_PAN_DATA_PARAMS*)p_new_buf)->forward = forward;
+
+ p_scb = bta_pan_scb_by_handle(handle);
+ if (p_scb == NULL) {
+ osi_free(p_new_buf);
+ return;
+ }
+
+ fixed_queue_enqueue(p_scb->data_queue, p_new_buf);
+ BT_HDR* p_event = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_event->layer_specific = handle;
+ p_event->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+ bta_sys_sendmsg(p_event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_pfilt_ind_cback
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_pfilt_ind_cback(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters) {
+ bta_pan_co_pfilt_ind(
+ handle, indication,
+ (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
+ : BTA_PAN_FAIL),
+ num_filters, p_filters);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_mfilt_ind_cback
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_mfilt_ind_cback(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_mfilters,
+ uint8_t* p_mfilters) {
+ bta_pan_co_mfilt_ind(
+ handle, indication,
+ (tBTA_PAN_STATUS)((result == BNEP_SUCCESS) ? BTA_PAN_SUCCESS
+ : BTA_PAN_FAIL),
+ num_mfilters, p_mfilters);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_has_multiple_connections
+ *
+ * Description Check whether there are multiple GN/NAP connections to
+ * different devices
+ *
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool bta_pan_has_multiple_connections(uint8_t app_id) {
+ tBTA_PAN_SCB* p_scb = NULL;
+ bool found = false;
+ BD_ADDR bd_addr;
+
+ for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
+ p_scb = &bta_pan_cb.scb[index];
+ if (p_scb->in_use == true && app_id == p_scb->app_id) {
+ /* save temp bd_addr */
+ bdcpy(bd_addr, p_scb->bd_addr);
+ found = true;
+ break;
+ }
+ }
+
+ /* If cannot find a match then there is no connection at all */
+ if (found == false) return false;
+
+ /* Find whether there is another connection with different device other than
+ PANU.
+ Could be same service or different service */
+ for (uint8_t index = 0; index < BTA_PAN_NUM_CONN; index++) {
+ p_scb = &bta_pan_cb.scb[index];
+ if (p_scb->in_use == true && p_scb->app_id != bta_pan_cb.app_id[0] &&
+ bdcmp(bd_addr, p_scb->bd_addr)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_enable
+ *
+ * Description
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_enable(tBTA_PAN_DATA* p_data) {
+ tPAN_REGISTER reg_data;
+ uint16_t initial_discoverability;
+ uint16_t initial_connectability;
+ uint16_t d_window;
+ uint16_t d_interval;
+ uint16_t c_window;
+ uint16_t c_interval;
+
+ bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+
+ reg_data.pan_conn_state_cb = bta_pan_conn_state_cback;
+ reg_data.pan_bridge_req_cb = NULL;
+ reg_data.pan_data_buf_ind_cb = bta_pan_data_buf_ind_cback;
+ reg_data.pan_data_ind_cb = NULL;
+ reg_data.pan_pfilt_ind_cb = bta_pan_pfilt_ind_cback;
+ reg_data.pan_mfilt_ind_cb = bta_pan_mfilt_ind_cback;
+ reg_data.pan_tx_data_flow_cb = bta_pan_data_flow_cb;
+
+ /* read connectability and discoverability settings.
+ Pan profile changes the settings. We have to change it back to
+ be consistent with other bta subsystems */
+ initial_connectability = BTM_ReadConnectability(&c_window, &c_interval);
+ initial_discoverability = BTM_ReadDiscoverability(&d_window, &d_interval);
+
+ PAN_Register(&reg_data);
+
+ /* set it back to original value */
+ BTM_SetDiscoverability(initial_discoverability, d_window, d_interval);
+ BTM_SetConnectability(initial_connectability, c_window, c_interval);
+
+ bta_pan_cb.flow_mask = bta_pan_co_init(&bta_pan_cb.q_level);
+ bta_pan_cb.p_cback(BTA_PAN_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_set_role
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_set_role(tBTA_PAN_DATA* p_data) {
+ tPAN_RESULT status;
+ tBTA_PAN bta_pan;
+ uint8_t sec[3];
+
+ bta_pan_cb.app_id[0] = p_data->api_set_role.user_app_id;
+ bta_pan_cb.app_id[1] = p_data->api_set_role.gn_app_id;
+ bta_pan_cb.app_id[2] = p_data->api_set_role.nap_app_id;
+
+ sec[0] = p_data->api_set_role.user_sec_mask;
+ sec[1] = p_data->api_set_role.gn_sec_mask;
+ sec[2] = p_data->api_set_role.nap_sec_mask;
+
+ /* set security correctly in api and here */
+ status = PAN_SetRole(
+ p_data->api_set_role.role, sec, p_data->api_set_role.user_name,
+ p_data->api_set_role.gn_name, p_data->api_set_role.nap_name);
+
+ bta_pan.set_role.role = p_data->api_set_role.role;
+ if (status == PAN_SUCCESS) {
+ if (p_data->api_set_role.role & PAN_ROLE_NAP_SERVER)
+ bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+
+ if (p_data->api_set_role.role & PAN_ROLE_GN_SERVER)
+ bta_sys_add_uuid(UUID_SERVCLASS_GN);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+
+ if (p_data->api_set_role.role & PAN_ROLE_CLIENT)
+ bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+ else
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+
+ bta_pan.set_role.status = BTA_PAN_SUCCESS;
+ }
+ /* if status is not success clear everything */
+ else {
+ PAN_SetRole(0, 0, NULL, NULL, NULL);
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+ bta_pan.set_role.status = BTA_PAN_FAIL;
+ }
+ bta_pan_cb.p_cback(BTA_PAN_SET_ROLE_EVT, &bta_pan);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_disable
+ *
+ * Description
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_disable(void) {
+ BT_HDR* p_buf;
+ tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+ uint8_t i;
+
+ /* close all connections */
+ PAN_SetRole(0, NULL, NULL, NULL, NULL);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+#endif // BTA_EIR_CANNED_UUID_LIST
+ /* free all queued up data buffers */
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+ if (p_scb->in_use) {
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) !=
+ NULL)
+ osi_free(p_buf);
+
+ bta_pan_co_close(p_scb->handle, p_scb->app_id);
+ }
+ }
+
+ PAN_Deregister();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_open
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ tPAN_RESULT status;
+ tBTA_PAN bta_pan;
+
+ status = PAN_Connect(p_data->api_open.bd_addr, p_data->api_open.local_role,
+ p_data->api_open.peer_role, &p_scb->handle);
+ APPL_TRACE_DEBUG("%s pan connect status: %d", __func__, status);
+
+ if (status == PAN_SUCCESS) {
+ bdcpy(p_scb->bd_addr, p_data->api_open.bd_addr);
+ p_scb->local_role = p_data->api_open.local_role;
+ p_scb->peer_role = p_data->api_open.peer_role;
+ bdcpy(bta_pan.opening.bd_addr, p_data->api_open.bd_addr);
+ bta_pan.opening.handle = p_scb->handle;
+ bta_pan_cb.p_cback(BTA_PAN_OPENING_EVT, &bta_pan);
+
+ } else {
+ bta_pan_scb_dealloc(p_scb);
+ bdcpy(bta_pan.open.bd_addr, p_data->api_open.bd_addr);
+ bta_pan.open.status = BTA_PAN_FAIL;
+ bta_pan.open.local_role = p_data->api_open.local_role;
+ bta_pan.open.peer_role = p_data->api_open.peer_role;
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, &bta_pan);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_close
+ *
+ * Description
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_api_close(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+ tBTA_PAN_CONN* p_buf = (tBTA_PAN_CONN*)osi_malloc(sizeof(tBTA_PAN_CONN));
+
+ PAN_Disconnect(p_scb->handle);
+
+ /*
+ * Send an event to BTA so that application will get the connection
+ * close event.
+ */
+ p_buf->hdr.event = BTA_PAN_CONN_CLOSE_EVT;
+ p_buf->hdr.layer_specific = p_scb->handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_conn_open
+ *
+ * Description process connection open event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ tBTA_PAN bta_pan;
+
+ APPL_TRACE_DEBUG("%s pan connection result: %d", __func__,
+ p_data->conn.result);
+
+ bdcpy(bta_pan.open.bd_addr, p_scb->bd_addr);
+ bta_pan.open.handle = p_scb->handle;
+ bta_pan.open.local_role = p_scb->local_role;
+ bta_pan.open.peer_role = p_scb->peer_role;
+
+ if (p_data->conn.result == PAN_SUCCESS) {
+ bta_pan.open.status = BTA_PAN_SUCCESS;
+ p_scb->pan_flow_enable = true;
+ p_scb->app_flow_enable = true;
+ bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+ } else {
+ bta_pan_scb_dealloc(p_scb);
+ bta_pan.open.status = BTA_PAN_FAIL;
+ }
+
+ p_scb->pan_flow_enable = true;
+ p_scb->app_flow_enable = true;
+
+ /* If app_id is NAP/GN, check whether there are multiple connections.
+ If there are, provide a special app_id to dm to enforce master role only.
+ */
+ if ((p_scb->app_id == bta_pan_cb.app_id[1] ||
+ p_scb->app_id == bta_pan_cb.app_id[2]) &&
+ bta_pan_has_multiple_connections(p_scb->app_id)) {
+ p_scb->app_id = BTA_APP_ID_PAN_MULTI;
+ }
+
+ bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, &bta_pan);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_conn_close
+ *
+ * Description process connection close event
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_conn_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ tBTA_PAN bta_pan;
+ BT_HDR* p_buf;
+
+ bta_pan.close.handle = p_data->hdr.layer_specific;
+
+ bta_sys_conn_close(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
+
+ /* free all queued up data buffers */
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue)) != NULL)
+ osi_free(p_buf);
+
+ bta_pan_scb_dealloc(p_scb);
+
+ bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, &bta_pan);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_rx_path
+ *
+ * Description Handle data on the RX path (data sent from the phone to
+ * BTA).
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_rx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+ /* if data path configured for rx pull */
+ if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PULL) {
+ /* if we can accept data */
+ if (p_scb->pan_flow_enable == true) {
+ /* call application callout function for rx path */
+ bta_pan_co_rx_path(p_scb->handle, p_scb->app_id);
+ }
+ }
+ /* else data path configured for rx push */
+ else {
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_tx_path
+ *
+ * Description Handle the TX data path (data sent from BTA to the phone).
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_tx_path(tBTA_PAN_SCB* p_scb, UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+ /* if data path configured for tx pull */
+ if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PULL) {
+ bta_pan_pm_conn_busy(p_scb);
+ /* call application callout function for tx path */
+ bta_pan_co_tx_path(p_scb->handle, p_scb->app_id);
+
+ /* free data that exceeds queue level */
+ while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
+ osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
+ bta_pan_pm_conn_idle(p_scb);
+ }
+ /* if configured for zero copy push */
+ else if ((bta_pan_cb.flow_mask & BTA_PAN_TX_MASK) == BTA_PAN_TX_PUSH_BUF) {
+ /* if app can accept data */
+ if (p_scb->app_flow_enable == true) {
+ BT_HDR* p_buf;
+
+ /* read data from the queue */
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue);
+ if (p_buf != NULL) {
+ /* send data to application */
+ bta_pan_co_tx_writebuf(p_scb->handle, p_scb->app_id,
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->src,
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->dst,
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol, p_buf,
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext,
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->forward);
+ }
+ /* free data that exceeds queue level */
+ while (fixed_queue_length(p_scb->data_queue) > bta_pan_cb.q_level)
+ osi_free(fixed_queue_try_dequeue(p_scb->data_queue));
+
+ /* if there is more data to be passed to
+ upper layer */
+ if (!fixed_queue_is_empty(p_scb->data_queue)) {
+ p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+ p_buf->layer_specific = p_scb->handle;
+ p_buf->event = BTA_PAN_RX_FROM_BNEP_READY_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_tx_flow
+ *
+ * Description Set the application flow control state.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_tx_flow(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ p_scb->app_flow_enable = p_data->ci_tx_flow.enable;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_write_buf
+ *
+ * Description Handle a bta_pan_ci_rx_writebuf() and send data to PAN.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_write_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ if ((bta_pan_cb.flow_mask & BTA_PAN_RX_MASK) == BTA_PAN_RX_PUSH_BUF) {
+ bta_pan_pm_conn_busy(p_scb);
+
+ PAN_WriteBuf(p_scb->handle, ((tBTA_PAN_DATA_PARAMS*)p_data)->dst,
+ ((tBTA_PAN_DATA_PARAMS*)p_data)->src,
+ ((tBTA_PAN_DATA_PARAMS*)p_data)->protocol, (BT_HDR*)p_data,
+ ((tBTA_PAN_DATA_PARAMS*)p_data)->ext);
+ bta_pan_pm_conn_idle(p_scb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_free_buf
+ *
+ * Description Frees the data buffer during closing state
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_free_buf(UNUSED_ATTR tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data) {
+ osi_free(p_data);
+}
+
+#endif /* PAN_INCLUDED */
diff --git a/mtkbt/code/bt/bta/pan/bta_pan_api.cc b/mtkbt/code/bt/bta/pan/bta_pan_api.cc
new file mode 100755
index 0000000..cfb0588
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pan/bta_pan_api.cc
@@ -0,0 +1,193 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for PAN subsystem of BTA,
+ * Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+static const tBTA_SYS_REG bta_pan_reg = {bta_pan_hdl_event, BTA_PanDisable};
+
+/*******************************************************************************
+ *
+ * Function BTA_PanEnable
+ *
+ * Description Enable PAN service. This function must be
+ * called before any other functions in the PAN API are called.
+ * When the enable operation is complete the callback function
+ * will be called with a BTA_PAN_ENABLE_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanEnable(tBTA_PAN_CBACK p_cback) {
+ tBTA_PAN_API_ENABLE* p_buf =
+ (tBTA_PAN_API_ENABLE*)osi_malloc(sizeof(tBTA_PAN_API_ENABLE));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_PAN, &bta_pan_reg);
+
+ p_buf->hdr.event = BTA_PAN_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_PanDisable
+ *
+ * Description Disables PAN service.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanDisable(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ bta_sys_deregister(BTA_ID_PAN);
+ p_buf->event = BTA_PAN_API_DISABLE_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_PanSetRole
+ *
+ * Description Sets PAN roles. When the enable operation is complete
+ * the callback function will be called with a
+ * BTA_PAN_SET_ROLE_EVT.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanSetRole(tBTA_PAN_ROLE role, tBTA_PAN_ROLE_INFO* p_user_info,
+ tBTA_PAN_ROLE_INFO* p_gn_info,
+ tBTA_PAN_ROLE_INFO* p_nap_info) {
+ tBTA_PAN_API_SET_ROLE* p_buf =
+ (tBTA_PAN_API_SET_ROLE*)osi_calloc(sizeof(tBTA_PAN_API_SET_ROLE));
+
+ p_buf->hdr.event = BTA_PAN_API_SET_ROLE_EVT;
+ p_buf->role = role;
+
+ if (p_user_info && (role & BTA_PAN_ROLE_PANU)) {
+ if (p_user_info->p_srv_name)
+ strlcpy(p_buf->user_name, p_user_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+ p_buf->user_app_id = p_user_info->app_id;
+ p_buf->user_sec_mask = p_user_info->sec_mask;
+ }
+
+ if (p_gn_info && (role & BTA_PAN_ROLE_GN)) {
+ if (p_gn_info->p_srv_name)
+ strlcpy(p_buf->gn_name, p_gn_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+ p_buf->gn_app_id = p_gn_info->app_id;
+ p_buf->gn_sec_mask = p_gn_info->sec_mask;
+ }
+
+ if (p_nap_info && (role & BTA_PAN_ROLE_NAP)) {
+ if (p_nap_info->p_srv_name)
+ strlcpy(p_buf->nap_name, p_nap_info->p_srv_name, BTA_SERVICE_NAME_LEN);
+
+ p_buf->nap_app_id = p_nap_info->app_id;
+ p_buf->nap_sec_mask = p_nap_info->sec_mask;
+ }
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_PanOpen
+ *
+ * Description Opens a connection to a peer device.
+ * When connection is open callback function is called
+ * with a BTA_PAN_OPEN_EVT.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanOpen(BD_ADDR bd_addr, tBTA_PAN_ROLE local_role,
+ tBTA_PAN_ROLE peer_role) {
+ tBTA_PAN_API_OPEN* p_buf =
+ (tBTA_PAN_API_OPEN*)osi_malloc(sizeof(tBTA_PAN_API_OPEN));
+
+ p_buf->hdr.event = BTA_PAN_API_OPEN_EVT;
+ p_buf->local_role = local_role;
+ p_buf->peer_role = peer_role;
+ bdcpy(p_buf->bd_addr, bd_addr);
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_PanClose
+ *
+ * Description Close a PAN connection to a peer device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTA_PanClose(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTA_PAN_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+
+ bta_sys_sendmsg(p_buf);
+}
+#else
+
+void BTA_PanEnable(UNUSED_ATTR tBTA_PAN_CBACK p_cback) {}
+
+void BTA_PanDisable(void) {}
+
+void BTA_PanSetRole(UNUSED_ATTR tBTA_PAN_ROLE role,
+ UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_user_info,
+ UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_gn_info,
+ UNUSED_ATTR tBTA_PAN_ROLE_INFO* p_nap_info) {}
+
+void BTA_PanOpen(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBTA_PAN_ROLE local_role,
+ UNUSED_ATTR tBTA_PAN_ROLE peer_role) {}
+
+void BTA_PanClose(UNUSED_ATTR uint16_t handle) {}
+
+#endif /* BTA_PAN_INCLUDED */
diff --git a/mtkbt/code/bt/bta/pan/bta_pan_ci.cc b/mtkbt/code/bt/bta/pan/bta_pan_ci.cc
new file mode 100755
index 0000000..f44ebee
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pan/bta_pan_ci.cc
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for data gateway call-in functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "bta_pan_int.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_tx_ready
+ *
+ * Description This function sends an event to PAN indicating the phone is
+ * ready for more data and PAN should call
+ * bta_pan_co_tx_path().
+ * This function is used when the TX data path is configured
+ * to use a pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_tx_ready(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_TX_READY_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_rx_ready
+ *
+ * Description This function sends an event to PAN indicating the phone
+ * has data available to send to PAN and PAN should call
+ * bta_pan_co_rx_path(). This function is used when the RX
+ * data path is configured to use a pull interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_ready(uint16_t handle) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_READY_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_tx_flow
+ *
+ * Description This function is called to enable or disable data flow on
+ * the TX path. The phone should call this function to
+ * disable data flow when it is congested and cannot handle
+ * any more data sent by bta_pan_co_tx_write() or
+ * bta_pan_co_tx_writebuf(). This function is used when the
+ * TX data path is configured to use a push interface.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_tx_flow(uint16_t handle, bool enable) {
+ tBTA_PAN_CI_TX_FLOW* p_buf =
+ (tBTA_PAN_CI_TX_FLOW*)osi_malloc(sizeof(tBTA_PAN_CI_TX_FLOW));
+
+ p_buf->hdr.layer_specific = handle;
+ p_buf->hdr.event = BTA_PAN_CI_TX_FLOW_EVT;
+ p_buf->enable = enable;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_rx_write
+ *
+ * Description This function is called to send data to PAN when the RX path
+ * is configured to use a push interface. The function copies
+ * data to an event buffer and sends it to PAN.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_write(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool ext) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+
+ p_buf->offset = PAN_MINIMUM_OFFSET;
+
+ /* copy all other params before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->src, src);
+ bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->dst, dst);
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext = ext;
+ p_buf->len = len;
+
+ /* copy data */
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, len);
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_rx_writebuf
+ *
+ * Description This function is called to send data to the phone when
+ * the RX path is configured to use a push interface with
+ * zero copy. The function sends an event to PAN containing
+ * the data buffer. The buffer will be freed by BTA; the
+ * phone must not free the buffer.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_rx_writebuf(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, BT_HDR* p_buf, bool ext) {
+ /* copy all other params before the data */
+ bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->src, src);
+ bdcpy(((tBTA_PAN_DATA_PARAMS*)p_buf)->dst, dst);
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol = protocol;
+ ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext = ext;
+
+ p_buf->layer_specific = handle;
+ p_buf->event = BTA_PAN_CI_RX_WRITEBUF_EVT;
+ bta_sys_sendmsg(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_readbuf
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+BT_HDR* bta_pan_ci_readbuf(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+ uint16_t* p_protocol, bool* p_ext, bool* p_forward) {
+ tBTA_PAN_SCB* p_scb;
+ BT_HDR* p_buf;
+
+ p_scb = bta_pan_scb_by_handle(handle);
+
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_scb->data_queue);
+ if (p_buf != NULL) {
+ bdcpy(src, ((tBTA_PAN_DATA_PARAMS*)p_buf)->src);
+ bdcpy(dst, ((tBTA_PAN_DATA_PARAMS*)p_buf)->dst);
+ *p_protocol = ((tBTA_PAN_DATA_PARAMS*)p_buf)->protocol;
+ *p_ext = ((tBTA_PAN_DATA_PARAMS*)p_buf)->ext;
+ *p_forward = ((tBTA_PAN_DATA_PARAMS*)p_buf)->forward;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_set_mfilters
+ *
+ * Description This function is called to set multicast filters
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_set_mfilters(uint16_t handle, uint16_t num_mcast_filters,
+ uint8_t* p_start_array, uint8_t* p_end_array) {
+ PAN_SetMulticastFilters(handle, num_mcast_filters, p_start_array,
+ p_end_array);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_ci_set_mfilters
+ *
+ * Description This function is called to set protocol filters
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_ci_set_pfilters(uint16_t handle, uint16_t num_filters,
+ uint16_t* p_start_array, uint16_t* p_end_array) {
+ PAN_SetProtocolFilters(handle, num_filters, p_start_array, p_end_array);
+}
+#else
+
+void bta_pan_ci_tx_ready(UNUSED_ATTR uint16_t handle) {}
+
+void bta_pan_ci_rx_ready(UNUSED_ATTR uint16_t handle) {}
+
+void bta_pan_ci_tx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR bool enable) {}
+
+void bta_pan_ci_rx_writebuf(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR BD_ADDR src, UNUSED_ATTR BD_ADDR dst,
+ UNUSED_ATTR uint16_t protocol,
+ UNUSED_ATTR BT_HDR* p_buf, UNUSED_ATTR bool ext) {}
+
+BT_HDR* bta_pan_ci_readbuf(UNUSED_ATTR uint16_t handle, UNUSED_ATTR BD_ADDR src,
+ UNUSED_ATTR BD_ADDR dst,
+ UNUSED_ATTR uint16_t* p_protocol,
+ UNUSED_ATTR bool* p_ext,
+ UNUSED_ATTR bool* p_forward) {
+ return NULL;
+}
+
+void bta_pan_ci_set_pfilters(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR uint16_t num_filters,
+ UNUSED_ATTR uint16_t* p_start_array,
+ UNUSED_ATTR uint16_t* p_end_array) {}
+
+void bta_pan_ci_set_mfilters(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR uint16_t num_mcast_filters,
+ UNUSED_ATTR uint8_t* p_start_array,
+ UNUSED_ATTR uint8_t* p_end_array) {}
+
+#endif /* BTA_PAN_API */
diff --git a/mtkbt/code/bt/bta/pan/bta_pan_int.h b/mtkbt/code/bt/bta/pan/bta_pan_int.h
new file mode 100755
index 0000000..71658f2
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pan/bta_pan_int.h
@@ -0,0 +1,186 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA data gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_PAN_INT_H
+#define BTA_PAN_INT_H
+
+#include "bta_pan_api.h"
+#include "bta_sys.h"
+#include "osi/include/fixed_queue.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* PAN events */
+enum {
+ /* these events are handled by the state machine */
+ BTA_PAN_API_CLOSE_EVT = BTA_SYS_EVT_START(BTA_ID_PAN),
+ BTA_PAN_CI_TX_READY_EVT,
+ BTA_PAN_CI_RX_READY_EVT,
+ BTA_PAN_CI_TX_FLOW_EVT,
+ BTA_PAN_CI_RX_WRITE_EVT,
+ BTA_PAN_CI_RX_WRITEBUF_EVT,
+ BTA_PAN_CONN_OPEN_EVT,
+ BTA_PAN_CONN_CLOSE_EVT,
+ BTA_PAN_BNEP_FLOW_ENABLE_EVT,
+ BTA_PAN_RX_FROM_BNEP_READY_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_PAN_API_ENABLE_EVT,
+ BTA_PAN_API_DISABLE_EVT,
+ BTA_PAN_API_SET_ROLE_EVT,
+ BTA_PAN_API_OPEN_EVT
+};
+
+/* state machine states */
+enum { BTA_PAN_IDLE_ST, BTA_PAN_OPEN_ST, BTA_PAN_CLOSING_ST };
+
+/*****************************************************************************
+ * Data types
+ ****************************************************************************/
+
+/* data type for BTA_PAN_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ tBTA_PAN_CBACK* p_cback; /* PAN callback function */
+} tBTA_PAN_API_ENABLE;
+
+/* data type for BTA_PAN_API_REG_ROLE_EVT */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ char user_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
+ char gn_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
+ char nap_name[BTA_SERVICE_NAME_LEN + 1]; /* Service name */
+ tBTA_PAN_ROLE role;
+ uint8_t user_app_id;
+ uint8_t gn_app_id;
+ uint8_t nap_app_id;
+ tBTA_SEC user_sec_mask; /* Security mask */
+ tBTA_SEC gn_sec_mask; /* Security mask */
+ tBTA_SEC nap_sec_mask; /* Security mask */
+
+} tBTA_PAN_API_SET_ROLE;
+
+/* data type for BTA_PAN_API_OPEN_EVT */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ tBTA_PAN_ROLE local_role; /* local role */
+ tBTA_PAN_ROLE peer_role; /* peer role */
+ BD_ADDR bd_addr; /* peer bdaddr */
+} tBTA_PAN_API_OPEN;
+
+/* data type for BTA_PAN_CI_TX_FLOW_EVT */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ bool enable; /* Flow control setting */
+} tBTA_PAN_CI_TX_FLOW;
+
+/* data type for BTA_PAN_CONN_OPEN_EVT */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ tPAN_RESULT result;
+
+} tBTA_PAN_CONN;
+
+/* union of all data types */
+typedef union {
+ BT_HDR hdr;
+ tBTA_PAN_API_ENABLE api_enable;
+ tBTA_PAN_API_SET_ROLE api_set_role;
+ tBTA_PAN_API_OPEN api_open;
+ tBTA_PAN_CI_TX_FLOW ci_tx_flow;
+ tBTA_PAN_CONN conn;
+} tBTA_PAN_DATA;
+
+/* state machine control block */
+typedef struct {
+ BD_ADDR bd_addr; /* peer bdaddr */
+ fixed_queue_t*
+ data_queue; /* Queue of buffers waiting to be passed to application */
+ uint16_t handle; /* BTA PAN/BNEP handle */
+ bool in_use; /* scb in use */
+ tBTA_SEC sec_mask; /* Security mask */
+ bool pan_flow_enable; /* BNEP flow control state */
+ bool app_flow_enable; /* Application flow control state */
+ uint8_t state; /* State machine state */
+ tBTA_PAN_ROLE local_role; /* local role */
+ tBTA_PAN_ROLE peer_role; /* peer role */
+ uint8_t app_id; /* application id for the connection */
+
+} tBTA_PAN_SCB;
+
+/* main control block */
+typedef struct {
+ tBTA_PAN_SCB scb[BTA_PAN_NUM_CONN]; /* state machine control blocks */
+ tBTA_PAN_CBACK* p_cback; /* PAN callback function */
+ uint8_t app_id[3]; /* application id for PAN roles */
+ uint8_t flow_mask; /* Data flow mask */
+ uint8_t q_level; /* queue level set by application for TX data */
+
+} tBTA_PAN_CB;
+
+/* pan data param */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR src;
+ BD_ADDR dst;
+ uint16_t protocol;
+ bool ext;
+ bool forward;
+
+} tBTA_PAN_DATA_PARAMS;
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* PAN control block */
+extern tBTA_PAN_CB bta_pan_cb;
+
+/*****************************************************************************
+ * Function prototypes
+ ****************************************************************************/
+extern tBTA_PAN_SCB* bta_pan_scb_alloc(void);
+extern void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb);
+extern uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb);
+extern tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle);
+extern bool bta_pan_hdl_event(BT_HDR* p_msg);
+
+/* action functions */
+extern void bta_pan_enable(tBTA_PAN_DATA* p_data);
+extern void bta_pan_disable(void);
+extern void bta_pan_set_role(tBTA_PAN_DATA* p_data);
+extern void bta_pan_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_api_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_set_shutdown(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_rx_path(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_tx_path(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_tx_flow(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_conn_open(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_conn_close(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_writebuf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_write_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+extern void bta_pan_free_buf(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+
+#endif /* BTA_PAN_INT_H */
diff --git a/mtkbt/code/bt/bta/pan/bta_pan_main.cc b/mtkbt/code/bt/bta/pan/bta_pan_main.cc
new file mode 100755
index 0000000..276e842
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pan/bta_pan_main.cc
@@ -0,0 +1,362 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the PAN main functions and state machine.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#if (BTA_PAN_INCLUDED == TRUE)
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_int.h"
+#include "bta_sys.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+/* state machine action enumeration list */
+enum {
+ BTA_PAN_API_CLOSE,
+ BTA_PAN_TX_PATH,
+ BTA_PAN_RX_PATH,
+ BTA_PAN_TX_FLOW,
+ BTA_PAN_WRITE_BUF,
+ BTA_PAN_CONN_OPEN,
+ BTA_PAN_CONN_CLOSE,
+ BTA_PAN_FREE_BUF,
+ BTA_PAN_IGNORE
+};
+
+/* type for action functions */
+typedef void (*tBTA_PAN_ACTION)(tBTA_PAN_SCB* p_scb, tBTA_PAN_DATA* p_data);
+
+/* action function list */
+const tBTA_PAN_ACTION bta_pan_action[] = {
+ bta_pan_api_close, bta_pan_tx_path, bta_pan_rx_path, bta_pan_tx_flow,
+ bta_pan_write_buf, bta_pan_conn_open, bta_pan_conn_close, bta_pan_free_buf,
+
+};
+
+/* state table information */
+#define BTA_PAN_ACTIONS 1 /* number of actions */
+#define BTA_PAN_NEXT_STATE 1 /* position of next state */
+#define BTA_PAN_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for listen state */
+const uint8_t bta_pan_st_idle[][BTA_PAN_NUM_COLS] = {
+ /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_IDLE_ST},
+ /* CI_TX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_READY */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_CONN_OPEN, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_OPEN, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST},
+ /* BNEP_DATA */ {BTA_PAN_IGNORE, BTA_PAN_IDLE_ST}
+
+};
+
+/* state table for open state */
+const uint8_t bta_pan_st_open[][BTA_PAN_NUM_COLS] = {
+ /* API_CLOSE */ {BTA_PAN_API_CLOSE, BTA_PAN_OPEN_ST},
+ /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST},
+ /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_OPEN_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_WRITE_BUF, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_OPEN_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_OPEN_ST},
+ /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t bta_pan_st_closing[][BTA_PAN_NUM_COLS] = {
+ /* API_CLOSE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* CI_TX_READY */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST},
+ /* CI_RX_READY */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+ /* CI_TX_FLOW */ {BTA_PAN_TX_FLOW, BTA_PAN_CLOSING_ST},
+ /* CI_RX_WRITE */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* CI_RX_WRITEBUF */ {BTA_PAN_FREE_BUF, BTA_PAN_CLOSING_ST},
+ /* PAN_CONN_OPEN */ {BTA_PAN_IGNORE, BTA_PAN_CLOSING_ST},
+ /* PAN_CONN_CLOSE */ {BTA_PAN_CONN_CLOSE, BTA_PAN_IDLE_ST},
+ /* FLOW_ENABLE */ {BTA_PAN_RX_PATH, BTA_PAN_CLOSING_ST},
+ /* BNEP_DATA */ {BTA_PAN_TX_PATH, BTA_PAN_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tBTA_PAN_ST_TBL)[BTA_PAN_NUM_COLS];
+
+/* state table */
+const tBTA_PAN_ST_TBL bta_pan_st_tbl[] = {bta_pan_st_idle, bta_pan_st_open,
+ bta_pan_st_closing};
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* PAN control block */
+tBTA_PAN_CB bta_pan_cb;
+
+/*******************************************************************************
+ *
+ * Function bta_pan_scb_alloc
+ *
+ * Description Allocate a PAN server control block.
+ *
+ *
+ * Returns pointer to the scb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tBTA_PAN_SCB* bta_pan_scb_alloc(void) {
+ tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+ if (!p_scb->in_use) {
+ p_scb->in_use = true;
+ APPL_TRACE_DEBUG("bta_pan_scb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == BTA_PAN_NUM_CONN) {
+ /* out of scbs */
+ p_scb = NULL;
+ APPL_TRACE_WARNING("Out of scbs");
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_sm_execute
+ *
+ * Description State machine event handling function for PAN
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_sm_execute(tBTA_PAN_SCB* p_scb, uint16_t event,
+ tBTA_PAN_DATA* p_data) {
+ tBTA_PAN_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ APPL_TRACE_EVENT("PAN scb=%d event=0x%x state=%d", bta_pan_scb_to_idx(p_scb),
+ event, p_scb->state);
+
+ /* look up the state table for the current state */
+ state_table = bta_pan_st_tbl[p_scb->state];
+
+ event &= 0x00FF;
+
+ /* set next state */
+ p_scb->state = state_table[event][BTA_PAN_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_PAN_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != BTA_PAN_IGNORE) {
+ (*bta_pan_action[action])(p_scb, p_data);
+ } else {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_api_enable
+ *
+ * Description Handle an API enable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_api_enable(tBTA_PAN_DATA* p_data) {
+ /* initialize control block */
+ memset(&bta_pan_cb, 0, sizeof(bta_pan_cb));
+
+ /* store callback function */
+ bta_pan_cb.p_cback = p_data->api_enable.p_cback;
+ bta_pan_enable(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_api_disable
+ *
+ * Description Handle an API disable event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_api_disable(UNUSED_ATTR tBTA_PAN_DATA* p_data) {
+ bta_pan_disable();
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_api_open
+ *
+ * Description Handle an API listen event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_pan_api_open(tBTA_PAN_DATA* p_data) {
+ tBTA_PAN_SCB* p_scb;
+ tBTA_PAN bta_pan;
+
+ /* allocate an scb */
+ p_scb = bta_pan_scb_alloc();
+ if (p_scb != NULL) {
+ bta_pan_open(p_scb, p_data);
+ } else {
+ bdcpy(bta_pan.open.bd_addr, p_data->api_open.bd_addr);
+ bta_pan.open.status = BTA_PAN_FAIL;
+ bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, &bta_pan);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_pan_scb_dealloc
+ *
+ * Description Deallocate a link control block.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_scb_dealloc(tBTA_PAN_SCB* p_scb) {
+ APPL_TRACE_DEBUG("bta_pan_scb_dealloc %d", bta_pan_scb_to_idx(p_scb));
+ fixed_queue_free(p_scb->data_queue, NULL);
+ memset(p_scb, 0, sizeof(tBTA_PAN_SCB));
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_scb_to_idx
+ *
+ * Description Given a pointer to an scb, return its index.
+ *
+ *
+ * Returns Index of scb.
+ *
+ ******************************************************************************/
+uint8_t bta_pan_scb_to_idx(tBTA_PAN_SCB* p_scb) {
+ return ((uint8_t)(p_scb - bta_pan_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_scb_by_handle
+ *
+ * Description Find scb associated with handle.
+ *
+ *
+ * Returns Pointer to scb or NULL if not found.
+ *
+ ******************************************************************************/
+tBTA_PAN_SCB* bta_pan_scb_by_handle(uint16_t handle) {
+ tBTA_PAN_SCB* p_scb = &bta_pan_cb.scb[0];
+ uint8_t i;
+
+ for (i = 0; i < BTA_PAN_NUM_CONN; i++, p_scb++) {
+ if (p_scb->handle == handle) {
+ return p_scb;
+ ;
+ }
+ }
+
+ APPL_TRACE_WARNING("No scb for handle %d", handle);
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_hdl_event
+ *
+ * Description Data gateway main event handling function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_pan_hdl_event(BT_HDR* p_msg) {
+ tBTA_PAN_SCB* p_scb;
+ bool freebuf = true;
+
+ switch (p_msg->event) {
+ /* handle enable event */
+ case BTA_PAN_API_ENABLE_EVT:
+ bta_pan_api_enable((tBTA_PAN_DATA*)p_msg);
+ break;
+
+ /* handle disable event */
+ case BTA_PAN_API_DISABLE_EVT:
+ bta_pan_api_disable((tBTA_PAN_DATA*)p_msg);
+ break;
+
+ /* handle set role event */
+ case BTA_PAN_API_SET_ROLE_EVT:
+ bta_pan_set_role((tBTA_PAN_DATA*)p_msg);
+ break;
+
+ /* handle open event */
+ case BTA_PAN_API_OPEN_EVT:
+ bta_pan_api_open((tBTA_PAN_DATA*)p_msg);
+ break;
+
+ /* events that require buffer not be released */
+ case BTA_PAN_CI_RX_WRITEBUF_EVT:
+ freebuf = false;
+ p_scb = bta_pan_scb_by_handle(p_msg->layer_specific);
+ if (p_scb != NULL) {
+ bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA*)p_msg);
+ }
+ break;
+
+ /* all other events */
+ default:
+ p_scb = bta_pan_scb_by_handle(p_msg->layer_specific);
+ if (p_scb != NULL) {
+ bta_pan_sm_execute(p_scb, p_msg->event, (tBTA_PAN_DATA*)p_msg);
+ }
+ break;
+ }
+ return freebuf;
+}
+#endif /* BTA_PAN_INCLUDED */
diff --git a/mtkbt/code/bt/bta/pb/bta_pbs_int.h b/mtkbt/code/bt/bta/pb/bta_pbs_int.h
new file mode 100755
index 0000000..ae21ce4
--- a/dev/null
+++ b/mtkbt/code/bt/bta/pb/bta_pbs_int.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private file for the phone book access server (PBS).
+ *
+ ******************************************************************************/
+#ifndef BTA_PBS_INT_H
+#define BTA_PBS_INT_H
+
+#include "bt_target.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/* Profile supported features */
+#define BTA_PBS_SUPF_DOWNLOAD 0x0001
+#define BTA_PBS_SURF_BROWSE 0x0002
+
+/* Profile supported repositories */
+#define BTA_PBS_REPOSIT_LOCAL 0x01 /* Local PhoneBook */
+#define BTA_PBS_REPOSIT_SIM 0x02 /* SIM card PhoneBook */
+
+#define BTA_PBS_TARGET_UUID \
+ "\x79\x61\x35\xf0\xf0\xc5\x11\xd8\x09\x66\x08\x00\x20\x0c\x9a\x66"
+#define BTA_PBS_UUID_LENGTH 16
+#define BTA_PBS_MAX_AUTH_KEY_SIZE \
+ 16 /* Must not be greater than OBX_MAX_AUTH_KEY_SIZE */
+
+#define BTA_PBS_DEFAULT_VERSION 0x0101 /* for PBAP PSE version 1.1 */
+
+/* Configuration structure */
+typedef struct {
+ uint8_t realm_charset; /* Server only */
+ bool userid_req; /* true if user id is required during obex authentication
+ (Server only) */
+ uint8_t supported_features; /* Server supported features */
+ uint8_t supported_repositories; /* Server supported repositories */
+
+} tBTA_PBS_CFG;
+
+#endif /* BTA_PBS_INT_H */
diff --git a/mtkbt/code/bt/bta/sdp/bta_sdp.cc b/mtkbt/code/bt/bta/sdp/bta_sdp.cc
new file mode 100755
index 0000000..735d0b7
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sdp/bta_sdp.cc
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA MCE I/F
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants and types
+ ****************************************************************************/
+
+tBTA_SDP_CB bta_sdp_cb;
+
+/* state machine action enumeration list */
+#define BTA_SDP_NUM_ACTIONS (BTA_SDP_MAX_INT_EVT & 0x00ff)
+
+/* type for action functions */
+typedef void (*tBTA_SDP_ACTION)(tBTA_SDP_MSG* p_data);
+
+/* action function list */
+const tBTA_SDP_ACTION bta_sdp_action[] = {
+ bta_sdp_enable, /* BTA_SDP_API_ENABLE_EVT */
+ bta_sdp_search, /* BTA_SDP_API_SEARCH_EVT */
+ bta_sdp_create_record, /* BTA_SDP_API_CREATE_RECORD_USER_EVT */
+ bta_sdp_remove_record, /* BTA_SDP_API_REMOVE_RECORD_USER_EVT */
+};
+
+/*******************************************************************************
+ * Function bta_sdp_sm_execute
+ *
+ * Description State machine event handling function for SDP search
+ *
+ * Returns void
+ ******************************************************************************/
+bool bta_sdp_sm_execute(BT_HDR* p_msg) {
+ if (p_msg == NULL) return false;
+
+ bool ret = false;
+ uint16_t action = (p_msg->event & 0x00ff);
+
+ /* execute action functions */
+ if (action < BTA_SDP_NUM_ACTIONS) {
+ (*bta_sdp_action[action])((tBTA_SDP_MSG*)p_msg);
+ ret = true;
+ }
+
+ return (ret);
+}
diff --git a/mtkbt/code/bt/bta/sdp/bta_sdp_act.cc b/mtkbt/code/bt/bta/sdp/bta_sdp_act.cc
new file mode 100755
index 0000000..9b8a8e0
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sdp/bta_sdp_act.cc
@@ -0,0 +1,569 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ * This file contains action functions for SDP search.
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "osi/include/allocator.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
+ 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MNS[] = {0x00, 0x00, 0x11, 0x33, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+// TODO:
+// Both the fact that the UUIDs are declared in multiple places, plus the fact
+// that there is a mess of UUID comparison and shortening methods will have to
+// be fixed.
+// The btcore->uuid module should be used for all instances.
+
+#define UUID_MAX_LENGTH 16
+#define IS_UUID(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+
+static inline tBT_UUID shorten_sdp_uuid(const tBT_UUID* u) {
+ static uint8_t bt_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+
+ APPL_TRACE_DEBUG("%s() - uuid len:%d", __func__, u->len);
+ if (u->len != 16) return *u;
+
+ if (memcmp(&u->uu.uuid128[4], &bt_base_uuid[4], 12) != 0) return *u;
+
+ tBT_UUID su;
+ memset(&su, 0, sizeof(su));
+ if (u->uu.uuid128[0] == 0 && u->uu.uuid128[1] == 0) {
+ su.len = 2;
+ uint16_t u16;
+ memcpy(&u16, &u->uu.uuid128[2], sizeof(u16));
+ su.uu.uuid16 = ntohs(u16);
+ } else {
+ su.len = 4;
+ uint32_t u32;
+ memcpy(&u32, &u->uu.uuid128[0], sizeof(u32));
+ su.uu.uuid32 = ntohl(u32);
+ }
+ return su;
+}
+
+static void bta_create_mns_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t pversion = 0;
+ record->mns.hdr.type = SDP_TYPE_MAP_MNS;
+ record->mns.hdr.service_name_length = 0;
+ record->mns.hdr.service_name = NULL;
+ record->mns.hdr.rfcomm_channel_number = 0;
+ record->mns.hdr.l2cap_psm = -1;
+ record->mns.hdr.profile_version = 0;
+ record->mns.supported_features = 0x0000001F; // default value if not found
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ record->mns.supported_features = p_attr->attr_value.v.u32;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->mns.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->mns.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE,
+ &pversion)) {
+ record->mns.hdr.profile_version = pversion;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->mns.hdr.rfcomm_channel_number = pe.params[0];
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM);
+ if (p_attr != NULL) {
+ record->mns.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ }
+}
+
+static void bta_create_mas_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t pversion = -1;
+
+ record->mas.hdr.type = SDP_TYPE_MAP_MAS;
+ record->mas.hdr.service_name_length = 0;
+ record->mas.hdr.service_name = NULL;
+ record->mas.hdr.rfcomm_channel_number = 0;
+ record->mas.hdr.l2cap_psm = -1;
+ record->mas.hdr.profile_version = 0;
+ record->mas.mas_instance_id = 0;
+ record->mas.supported_features = 0x0000001F;
+ record->mas.supported_message_types = 0;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID);
+ if (p_attr != NULL) {
+ record->mas.mas_instance_id = p_attr->attr_value.v.u8;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE);
+ if (p_attr != NULL) {
+ record->mas.supported_message_types = p_attr->attr_value.v.u8;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAP_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ record->mas.supported_features = p_attr->attr_value.v.u32;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->mas.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->mas.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_MAP_PROFILE,
+ &pversion)) {
+ record->mas.hdr.profile_version = pversion;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->mas.hdr.rfcomm_channel_number = pe.params[0];
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM);
+ if (p_attr != NULL) {
+ record->mas.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ }
+}
+
+static void bta_create_pse_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR* p_attr;
+ uint16_t pversion;
+ tSDP_PROTOCOL_ELEM pe;
+
+ record->pse.hdr.type = SDP_TYPE_PBAP_PSE;
+ record->pse.hdr.service_name_length = 0;
+ record->pse.hdr.service_name = NULL;
+ record->pse.hdr.rfcomm_channel_number = 0;
+ record->pse.hdr.l2cap_psm = -1;
+ record->pse.hdr.profile_version = 0;
+ record->pse.supported_features = 0x00000003;
+ record->pse.supported_repositories = 0;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_REPOSITORIES);
+ if (p_attr != NULL) {
+ record->pse.supported_repositories = p_attr->attr_value.v.u8;
+ }
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PBAP_SUPPORTED_FEATURES);
+ if (p_attr != NULL) {
+ record->pse.supported_features = p_attr->attr_value.v.u32;
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->pse.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->pse.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_PHONE_ACCESS,
+ &pversion)) {
+ record->pse.hdr.profile_version = pversion;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->pse.hdr.rfcomm_channel_number = pe.params[0];
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM);
+ if (p_attr != NULL) {
+ record->pse.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ }
+}
+
+static void bta_create_ops_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t pversion = -1;
+
+ record->ops.hdr.type = SDP_TYPE_OPP_SERVER;
+ record->ops.hdr.service_name_length = 0;
+ record->ops.hdr.service_name = NULL;
+ record->ops.hdr.rfcomm_channel_number = 0;
+ record->ops.hdr.l2cap_psm = -1;
+ record->ops.hdr.profile_version = 0;
+ record->ops.supported_formats_list_len = 0;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->ops.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->ops.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ &pversion)) {
+ record->ops.hdr.profile_version = pversion;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->ops.hdr.rfcomm_channel_number = pe.params[0];
+ }
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_GOEP_L2CAP_PSM);
+ if (p_attr != NULL) {
+ record->ops.hdr.l2cap_psm = p_attr->attr_value.v.u16;
+ }
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FORMATS_LIST);
+ if (p_attr != NULL) {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
+ record->ops.supported_formats_list_len = 0;
+ APPL_TRACE_ERROR(
+ "%s() - supported_formats_list - wrong attribute length/type:"
+ " 0x%02x - expected 0x06",
+ __func__, p_attr->attr_len_type);
+ } else {
+ int count = 0;
+ /* 1 byte for type/length 1 byte for value */
+ record->ops.supported_formats_list_len =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type) / 2;
+
+ /* Extract each value into */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr != NULL;
+ p_sattr = p_sattr->p_next_attr) {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 1)) {
+ if (count == sizeof(record->ops.supported_formats_list)) {
+ APPL_TRACE_ERROR(
+ "%s() - supported_formats_list - count overflow - "
+ "too many sub attributes!!",
+ __func__);
+ /* If you hit this, new formats have been added,
+ * update SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH */
+ break;
+ }
+ record->ops.supported_formats_list[count] = p_sattr->attr_value.v.u8;
+ count++;
+ } else {
+ APPL_TRACE_ERROR(
+ "%s() - supported_formats_list - wrong sub attribute "
+ "length/type: 0x%02x - expected 0x80",
+ __func__, p_sattr->attr_len_type);
+ break;
+ }
+ }
+ if (record->ops.supported_formats_list_len != count) {
+ APPL_TRACE_WARNING(
+ "%s() - supported_formats_list - Length of attribute different "
+ "from the actual number of sub-attributes in the sequence "
+ "att-length: %d - number of elements: %d",
+ __func__, record->ops.supported_formats_list_len, count);
+ }
+ record->ops.supported_formats_list_len = count;
+ }
+ }
+}
+
+static void bta_create_sap_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ uint16_t pversion = -1;
+
+ record->sap.hdr.type = SDP_TYPE_MAP_MAS;
+ record->sap.hdr.service_name_length = 0;
+ record->sap.hdr.service_name = NULL;
+ record->sap.hdr.rfcomm_channel_number = 0;
+ record->sap.hdr.l2cap_psm = -1;
+ record->sap.hdr.profile_version = 0;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->sap.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->sap.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ if (SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_SAP, &pversion)) {
+ record->sap.hdr.profile_version = pversion;
+ }
+
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->sap.hdr.rfcomm_channel_number = pe.params[0];
+ }
+}
+
+static void bta_create_raw_sdp_record(bluetooth_sdp_record* record,
+ tSDP_DISC_REC* p_rec) {
+ tSDP_DISC_ATTR* p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+
+ record->hdr.type = SDP_TYPE_RAW;
+ record->hdr.service_name_length = 0;
+ record->hdr.service_name = NULL;
+ record->hdr.rfcomm_channel_number = -1;
+ record->hdr.l2cap_psm = -1;
+ record->hdr.profile_version = -1;
+
+ /* Try to extract a service name */
+ p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME);
+ if (p_attr != NULL) {
+ record->pse.hdr.service_name_length =
+ SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ record->pse.hdr.service_name = (char*)p_attr->attr_value.v.array;
+ }
+
+ /* Try to extract an RFCOMM channel */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ record->pse.hdr.rfcomm_channel_number = pe.params[0];
+ }
+ record->hdr.user1_ptr_len = p_bta_sdp_cfg->p_sdp_db->raw_size;
+ record->hdr.user1_ptr = p_bta_sdp_cfg->p_sdp_db->raw_data;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sdp_search_cback
+ *
+ * Description Callback from btm after search is completed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_sdp_search_cback(uint16_t result, void* user_data) {
+ tSDP_DISC_REC* p_rec = NULL;
+ tBTA_SDP_SEARCH_COMP evt_data;
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+ int count = 0;
+ tBT_UUID su;
+ APPL_TRACE_DEBUG("%s() - res: 0x%x", __func__, result);
+
+ memset(&evt_data, 0, sizeof(evt_data));
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+ if (bta_sdp_cb.p_dm_cback == NULL) return;
+
+ bdcpy(evt_data.remote_addr, bta_sdp_cb.remote_addr);
+ tBT_UUID* uuid = (tBT_UUID*)user_data;
+ memcpy(&evt_data.uuid, uuid, sizeof(tBT_UUID));
+ su = shorten_sdp_uuid(uuid);
+
+ if (result == SDP_SUCCESS || result == SDP_DB_FULL) {
+ do {
+ p_rec = SDP_FindServiceUUIDInDb(p_bta_sdp_cfg->p_sdp_db, &su, p_rec);
+ /* generate the matching record data pointer */
+ if (p_rec != NULL) {
+ status = BTA_SDP_SUCCESS;
+ if (IS_UUID(UUID_MAP_MAS, uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found MAP (MAS) uuid", __func__);
+ bta_create_mas_sdp_record(&evt_data.records[count], p_rec);
+ } else if (IS_UUID(UUID_MAP_MNS, uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found MAP (MNS) uuid", __func__);
+ bta_create_mns_sdp_record(&evt_data.records[count], p_rec);
+ } else if (IS_UUID(UUID_PBAP_PSE, uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found PBAP (PSE) uuid", __func__);
+ bta_create_pse_sdp_record(&evt_data.records[count], p_rec);
+ } else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found Object Push Server (OPS) uuid",
+ __func__);
+ bta_create_ops_sdp_record(&evt_data.records[count], p_rec);
+ } else if (IS_UUID(UUID_SAP, uuid->uu.uuid128)) {
+ APPL_TRACE_DEBUG("%s() - found SAP uuid", __func__);
+ bta_create_sap_sdp_record(&evt_data.records[count], p_rec);
+ } else {
+ /* we do not have specific structure for this */
+ APPL_TRACE_DEBUG("%s() - profile not identified. using raw data",
+ __func__);
+ bta_create_raw_sdp_record(&evt_data.records[count], p_rec);
+ p_rec = NULL; // Terminate loop
+ /* For raw, we only extract the first entry, and then return the
+ entire
+ raw data chunk.
+ TODO: Find a way to split the raw data into record chunks, and
+ iterate
+ to extract generic data for each chunk - e.g. rfcomm channel
+ and
+ service name. */
+ }
+ count++;
+ } else {
+ APPL_TRACE_DEBUG("%s() - UUID not found", __func__);
+ }
+ } while (p_rec != NULL && count < BTA_SDP_MAX_RECORDS);
+
+ evt_data.record_count = count;
+ }
+ evt_data.status = status;
+
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&evt_data,
+ (void*)&uuid->uu.uuid128);
+ osi_free(user_data); // We no longer need the user data to track the search
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sdp_enable
+ *
+ * Description Initializes the SDP I/F
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sdp_enable(tBTA_SDP_MSG* p_data) {
+ APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+ tBTA_SDP_STATUS status = BTA_SDP_SUCCESS;
+ bta_sdp_cb.p_dm_cback = p_data->enable.p_cback;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_ENABLE_EVT, (tBTA_SDP*)&status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sdp_search
+ *
+ * Description Discovers all sdp records for an uuid on remote device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sdp_search(tBTA_SDP_MSG* p_data) {
+ if (p_data == NULL) {
+ APPL_TRACE_DEBUG("SDP control block handle is null");
+ return;
+ }
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+
+ APPL_TRACE_DEBUG("%s in, sdp_active:%d", __func__, bta_sdp_cb.sdp_active);
+
+ if (bta_sdp_cb.sdp_active != BTA_SDP_ACTIVE_NONE) {
+ /* SDP is still in progress */
+ status = BTA_SDP_BUSY;
+ if (bta_sdp_cb.p_dm_cback) {
+ tBTA_SDP_SEARCH_COMP result;
+ memset(&result, 0, sizeof(result));
+ result.uuid = p_data->get_search.uuid;
+ bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+ result.status = status;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&result, NULL);
+ }
+ return;
+ }
+
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_YES;
+ bdcpy(bta_sdp_cb.remote_addr, p_data->get_search.bd_addr);
+ /* set the uuid used in the search */
+ tBT_UUID* bta_sdp_search_uuid =
+ static_cast<tBT_UUID*>(osi_malloc(sizeof(tBT_UUID)));
+ memcpy(bta_sdp_search_uuid, &(p_data->get_search.uuid), sizeof(tBT_UUID));
+
+ /* initialize the search for the uuid */
+ APPL_TRACE_DEBUG("%s init discovery with UUID(len: %d):", __func__,
+ bta_sdp_search_uuid->len);
+ for (int x = 0; x < bta_sdp_search_uuid->len; x++) {
+ APPL_TRACE_DEBUG("%X", bta_sdp_search_uuid->uu.uuid128[x]);
+ }
+ SDP_InitDiscoveryDb(p_bta_sdp_cfg->p_sdp_db, p_bta_sdp_cfg->sdp_db_size, 1,
+ bta_sdp_search_uuid, 0, NULL);
+
+ if (!SDP_ServiceSearchAttributeRequest2(
+ p_data->get_search.bd_addr, p_bta_sdp_cfg->p_sdp_db,
+ bta_sdp_search_cback, (void*)bta_sdp_search_uuid)) {
+ bta_sdp_cb.sdp_active = BTA_SDP_ACTIVE_NONE;
+
+ /* failed to start SDP. report the failure right away */
+ if (bta_sdp_cb.p_dm_cback) {
+ tBTA_SDP_SEARCH_COMP result;
+ memset(&result, 0, sizeof(result));
+ result.uuid = p_data->get_search.uuid;
+ bdcpy(result.remote_addr, p_data->get_search.bd_addr);
+ result.status = status;
+ bta_sdp_cb.p_dm_cback(BTA_SDP_SEARCH_COMP_EVT, (tBTA_SDP*)&result, NULL);
+ }
+ }
+ /*
+ else report the result when the cback is called
+ */
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sdp_record
+ *
+ * Description Discovers all sdp records for an uuid on remote device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sdp_create_record(tBTA_SDP_MSG* p_data) {
+ APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+ if (bta_sdp_cb.p_dm_cback)
+ bta_sdp_cb.p_dm_cback(BTA_SDP_CREATE_RECORD_USER_EVT, NULL,
+ p_data->record.user_data);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sdp_create_record
+ *
+ * Description Discovers all sdp records for an uuid on remote device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sdp_remove_record(tBTA_SDP_MSG* p_data) {
+ APPL_TRACE_DEBUG("%s() event: %d", __func__, p_data->record.hdr.event);
+ if (bta_sdp_cb.p_dm_cback)
+ bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL,
+ p_data->record.user_data);
+}
diff --git a/mtkbt/code/bt/bta/sdp/bta_sdp_api.cc b/mtkbt/code/bt/bta/sdp/bta_sdp_api.cc
new file mode 100755
index 0000000..7160423
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sdp/bta_sdp_api.cc
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for SDP search subsystem
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sdp_int.h"
+#include "bta_sys.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+static const tBTA_SYS_REG bta_sdp_reg = {bta_sdp_sm_execute, NULL};
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpEnable
+ *
+ * Description Enable the SDP search I/F service. When the enable
+ * operation is complete the callback function will be
+ * called with a BTA_SDP_ENABLE_EVT. This function must
+ * be called before other functions in the SDP search API are
+ * called.
+ *
+ * Returns BTA_SDP_SUCCESS if successful.
+ * BTA_SDP_FAIL if internal failure.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpEnable(tBTA_SDP_DM_CBACK* p_cback) {
+ tBTA_SDP_STATUS status = BTA_SDP_FAILURE;
+
+ APPL_TRACE_API(__func__);
+ if (p_cback && false == bta_sys_is_register(BTA_ID_SDP)) {
+ memset(&bta_sdp_cb, 0, sizeof(tBTA_SDP_CB));
+
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_SDP, &bta_sdp_reg);
+
+ if (p_cback) {
+ tBTA_SDP_API_ENABLE* p_buf =
+ (tBTA_SDP_API_ENABLE*)osi_malloc(sizeof(tBTA_SDP_API_ENABLE));
+ p_buf->hdr.event = BTA_SDP_API_ENABLE_EVT;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ status = BTA_SDP_SUCCESS;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpSearch
+ *
+ * Description This function performs service discovery for a specific
+ * service on given peer device. When the operation is
+ * completed the tBTA_SDP_DM_CBACK callback function will be
+ * called with a BTA_SDP_SEARCH_COMPLETE_EVT.
+ *
+ * Returns BTA_SDP_SUCCESS, if the request is being processed.
+ * BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpSearch(BD_ADDR bd_addr, tSDP_UUID* uuid) {
+ tBTA_SDP_API_SEARCH* p_msg =
+ (tBTA_SDP_API_SEARCH*)osi_malloc(sizeof(tBTA_SDP_API_SEARCH));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_SDP_API_SEARCH_EVT;
+ bdcpy(p_msg->bd_addr, bd_addr);
+ // p_msg->uuid = uuid;
+ memcpy(&(p_msg->uuid), uuid, sizeof(tSDP_UUID));
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SDP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpCreateRecordByUser
+ *
+ * Description This function is used to request a callback to create a SDP
+ * record. The registered callback will be called with event
+ * BTA_SDP_CREATE_RECORD_USER_EVT.
+ *
+ * Returns BTA_SDP_SUCCESS, if the request is being processed.
+ * BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpCreateRecordByUser(void* user_data) {
+ tBTA_SDP_API_RECORD_USER* p_msg =
+ (tBTA_SDP_API_RECORD_USER*)osi_malloc(sizeof(tBTA_SDP_API_RECORD_USER));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_SDP_API_CREATE_RECORD_USER_EVT;
+ p_msg->user_data = user_data;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SDP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTA_SdpRemoveRecordByUser
+ *
+ * Description This function is used to request a callback to remove a SDP
+ * record. The registered callback will be called with event
+ * BTA_SDP_REMOVE_RECORD_USER_EVT.
+ *
+ * Returns BTA_SDP_SUCCESS, if the request is being processed.
+ * BTA_SDP_FAILURE, otherwise.
+ *
+ ******************************************************************************/
+tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void* user_data) {
+ tBTA_SDP_API_RECORD_USER* p_msg =
+ (tBTA_SDP_API_RECORD_USER*)osi_malloc(sizeof(tBTA_SDP_API_RECORD_USER));
+
+ APPL_TRACE_API("%s", __func__);
+
+ p_msg->hdr.event = BTA_SDP_API_REMOVE_RECORD_USER_EVT;
+ p_msg->user_data = user_data;
+
+ bta_sys_sendmsg(p_msg);
+
+ return BTA_SDP_SUCCESS;
+}
diff --git a/mtkbt/code/bt/bta/sdp/bta_sdp_cfg.cc b/mtkbt/code/bt/bta/sdp/bta_sdp_cfg.cc
new file mode 100755
index 0000000..5be6755
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sdp/bta_sdp_cfg.cc
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ * This file contains compile-time configurable constants for SDP Search
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+
+#ifndef BTA_SDP_DB_SIZE
+#define BTA_SDP_DB_SIZE 4500
+#endif
+
+static uint8_t __attribute__((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE];
+
+/* SDP configuration structure */
+const tBTA_SDP_CFG bta_sdp_cfg = {
+ BTA_SDP_DB_SIZE,
+ (tSDP_DISCOVERY_DB*)
+ bta_sdp_db_data /* The data buffer to keep SDP database */
+};
+
+tBTA_SDP_CFG* p_bta_sdp_cfg = (tBTA_SDP_CFG*)&bta_sdp_cfg;
diff --git a/mtkbt/code/bt/bta/sdp/bta_sdp_int.h b/mtkbt/code/bt/bta/sdp/bta_sdp_int.h
new file mode 100755
index 0000000..21d814b
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sdp/bta_sdp_int.h
@@ -0,0 +1,100 @@
+
+
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA SDP I/F
+ *
+ ******************************************************************************/
+#ifndef BTA_SDP_INT_H
+#define BTA_SDP_INT_H
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "bta_sys.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+enum {
+ /* these events are handled by the state machine */
+ BTA_SDP_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SDP),
+ BTA_SDP_API_SEARCH_EVT,
+ BTA_SDP_API_CREATE_RECORD_USER_EVT,
+ BTA_SDP_API_REMOVE_RECORD_USER_EVT,
+ BTA_SDP_MAX_INT_EVT
+};
+
+enum {
+ BTA_SDP_ACTIVE_NONE = 0,
+ BTA_SDP_ACTIVE_YES /* waiting for SDP result */
+};
+
+/* data type for BTA_SDP_API_ENABLE_EVT */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_SDP_DM_CBACK* p_cback;
+} tBTA_SDP_API_ENABLE;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct {
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tSDP_UUID uuid;
+} tBTA_SDP_API_SEARCH;
+
+/* data type for BTA_SDP_API_SEARCH_EVT */
+typedef struct {
+ BT_HDR hdr;
+ void* user_data;
+} tBTA_SDP_API_RECORD_USER;
+
+/* union of all data types */
+typedef union {
+ /* GKI event buffer header */
+ BT_HDR hdr;
+ tBTA_SDP_API_ENABLE enable;
+ tBTA_SDP_API_SEARCH get_search;
+ tBTA_SDP_API_RECORD_USER record;
+} tBTA_SDP_MSG;
+
+/* SDP control block */
+typedef struct {
+ uint8_t sdp_active; /* see BTA_SDP_SDP_ACT_* */
+ BD_ADDR remote_addr;
+ tBTA_SDP_DM_CBACK* p_dm_cback;
+} tBTA_SDP_CB;
+
+/* SDP control block */
+extern tBTA_SDP_CB bta_sdp_cb;
+
+/* config struct */
+extern tBTA_SDP_CFG* p_bta_sdp_cfg;
+
+extern bool bta_sdp_sm_execute(BT_HDR* p_msg);
+
+extern void bta_sdp_enable(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_search(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_create_record(tBTA_SDP_MSG* p_data);
+extern void bta_sdp_remove_record(tBTA_SDP_MSG* p_data);
+
+#endif /* BTA_SDP_INT_H */
diff --git a/mtkbt/code/bt/bta/sys/bta_sys.h b/mtkbt/code/bt/bta/sys/bta_sys.h
new file mode 100755
index 0000000..093952e
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sys/bta_sys.h
@@ -0,0 +1,277 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the BTA system manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_SYS_H
+#define BTA_SYS_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/* vendor specific event handler function type */
+typedef bool(tBTA_SYS_VS_EVT_HDLR)(uint16_t evt, void* p);
+
+/* event handler function type */
+typedef bool(tBTA_SYS_EVT_HDLR)(BT_HDR* p_msg);
+
+/* disable function type */
+typedef void(tBTA_SYS_DISABLE)(void);
+
+/* HW modules */
+enum {
+ BTA_SYS_HW_BLUETOOTH,
+ BTA_SYS_HW_RT,
+
+ BTA_SYS_MAX_HW_MODULES
+};
+
+typedef uint16_t tBTA_SYS_HW_MODULE;
+
+#ifndef BTA_DM_NUM_JV_ID
+#define BTA_DM_NUM_JV_ID 2
+#endif
+
+/* SW sub-systems */
+#define BTA_ID_SYS 0 /* system manager */
+/* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */
+#define BTA_ID_DM 1 /* device manager */
+#define BTA_ID_DM_SEARCH 2 /* device manager search */
+#define BTA_ID_DM_SEC 3 /* device manager security */
+#define BTA_ID_DG 4 /* data gateway */
+#define BTA_ID_AG 5 /* audio gateway */
+#define BTA_ID_OPC 6 /* object push client */
+#define BTA_ID_OPS 7 /* object push server */
+#define BTA_ID_FTS 8 /* file transfer server */
+#define BTA_ID_CT 9 /* cordless telephony terminal */
+#define BTA_ID_FTC 10 /* file transfer client */
+#define BTA_ID_SS 11 /* synchronization server */
+#define BTA_ID_PR 12 /* Printer client */
+#define BTA_ID_BIC 13 /* Basic Imaging Client */
+#define BTA_ID_PAN 14 /* Personal Area Networking */
+#define BTA_ID_BIS 15 /* Basic Imaging Server */
+#define BTA_ID_ACC 16 /* Advanced Camera Client */
+#define BTA_ID_SC 17 /* SIM Card Access server */
+#define BTA_ID_AV 18 /* Advanced audio/video */
+#define BTA_ID_AVK 19 /* Audio/video sink */
+#define BTA_ID_HD 20 /* HID Device */
+#define BTA_ID_CG 21 /* Cordless Gateway */
+#define BTA_ID_BP 22 /* Basic Printing Client */
+#define BTA_ID_HH 23 /* Human Interface Device Host */
+#define BTA_ID_PBS 24 /* Phone Book Access Server */
+#define BTA_ID_PBC 25 /* Phone Book Access Client */
+#define BTA_ID_JV 26 /* Java */
+#define BTA_ID_HS 27 /* Headset */
+#define BTA_ID_MSE 28 /* Message Server Equipment */
+#define BTA_ID_MCE 29 /* Message Client Equipment */
+#define BTA_ID_HL 30 /* Health Device Profile*/
+#define BTA_ID_GATTC 31 /* GATT Client */
+#define BTA_ID_GATTS 32 /* GATT Client */
+#define BTA_ID_SDP 33 /* SDP Client */
+#define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */
+
+/* GENERIC */
+#define BTA_ID_PRM 38
+#define BTA_ID_SYSTEM 39 /* platform-specific */
+#define BTA_ID_SWRAP 40 /* Insight script wrapper */
+#define BTA_ID_MIP 41 /* Multicase Individual Polling */
+#define BTA_ID_RT 42 /* Audio Routing module: This module is always on. */
+#define BTA_ID_CLOSURE 43 /* Generic C++ closure */
+
+/* JV */
+#define BTA_ID_JV1 44 /* JV1 */
+#define BTA_ID_JV2 45 /* JV2 */
+
+#define BTA_ID_MAX (44 + BTA_DM_NUM_JV_ID)
+
+typedef uint8_t tBTA_SYS_ID;
+
+#define BTA_SYS_CONN_OPEN 0x00
+#define BTA_SYS_CONN_CLOSE 0x01
+#define BTA_SYS_APP_OPEN 0x02
+#define BTA_SYS_APP_CLOSE 0x03
+#define BTA_SYS_SCO_OPEN 0x04
+#define BTA_SYS_SCO_CLOSE 0x05
+#define BTA_SYS_CONN_IDLE 0x06
+#define BTA_SYS_CONN_BUSY 0x07
+
+/* for link policy */
+#define BTA_SYS_PLCY_SET 0x10 /* set the link policy to the given addr */
+#define BTA_SYS_PLCY_CLR 0x11 /* clear the link policy to the given addr */
+#define BTA_SYS_PLCY_DEF_SET 0x12 /* set the default link policy */
+#define BTA_SYS_PLCY_DEF_CLR 0x13 /* clear the default link policy */
+#define BTA_SYS_ROLE_CHANGE 0x14 /* role change */
+
+typedef uint8_t tBTA_SYS_CONN_STATUS;
+
+/* Bitmask of sys features */
+#define BTA_SYS_FEAT_PCM2 0x0001
+#define BTA_SYS_FEAT_PCM2_MASTER 0x0002
+
+/* tBTA_PREF_ROLES */
+typedef uint8_t tBTA_SYS_PREF_ROLES;
+
+/* conn callback for role / low power manager*/
+typedef void(tBTA_SYS_CONN_CBACK)(tBTA_SYS_CONN_STATUS status, uint8_t id,
+ uint8_t app_id, BD_ADDR peer_addr);
+
+/* conn callback for role / low power manager*/
+typedef void(tBTA_SYS_SSR_CFG_CBACK)(uint8_t id, uint8_t app_id,
+ uint16_t latency, uint16_t tout);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/* eir callback for adding/removeing UUID */
+typedef void(tBTA_SYS_EIR_CBACK)(uint16_t uuid16, bool adding);
+#endif
+
+/* registration structure */
+typedef struct {
+ tBTA_SYS_EVT_HDLR* evt_hdlr;
+ tBTA_SYS_DISABLE* disable;
+} tBTA_SYS_REG;
+
+/* data type to send events to BTA SYS HW manager */
+typedef struct {
+ BT_HDR hdr;
+ tBTA_SYS_HW_MODULE hw_module;
+} tBTA_SYS_HW_MSG;
+
+typedef void (*tBTA_SYS_REGISTER)(uint8_t id, const tBTA_SYS_REG* p_reg);
+typedef void (*tBTA_SYS_SENDMSG)(void* p_msg);
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+/* trace level */
+extern uint8_t appl_trace_level;
+
+/*****************************************************************************
+ * Macros
+ ****************************************************************************/
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTA_SYS_EVT_START(id) ((id) << 8)
+
+/*****************************************************************************
+ * events for BTA SYS HW manager
+ ****************************************************************************/
+
+/* events sent to SYS HW manager - must be kept synchronized with tables in
+ * bta_sys_main.cc */
+enum {
+ /* device manager local device API events */
+ BTA_SYS_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_SYS),
+ BTA_SYS_EVT_ENABLED_EVT,
+ BTA_SYS_EVT_STACK_ENABLED_EVT,
+ BTA_SYS_API_DISABLE_EVT,
+ BTA_SYS_EVT_DISABLED_EVT,
+ BTA_SYS_ERROR_EVT,
+
+ BTA_SYS_MAX_EVT
+};
+
+/* SYS HW status events - returned by SYS HW manager to other modules. */
+enum {
+ BTA_SYS_HW_OFF_EVT,
+ BTA_SYS_HW_ON_EVT,
+ BTA_SYS_HW_STARTING_EVT,
+ BTA_SYS_HW_STOPPING_EVT,
+ BTA_SYS_HW_ERROR_EVT
+
+};
+typedef uint8_t tBTA_SYS_HW_EVT;
+
+/* HW enable callback type */
+typedef void(tBTA_SYS_HW_CBACK)(tBTA_SYS_HW_EVT status);
+
+/*****************************************************************************
+ * Function declarations
+ ****************************************************************************/
+
+extern void bta_sys_init(void);
+extern void bta_sys_free(void);
+extern void bta_sys_event(BT_HDR* p_msg);
+extern void bta_sys_set_trace_level(uint8_t level);
+extern void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg);
+extern void bta_sys_deregister(uint8_t id);
+extern bool bta_sys_is_register(uint8_t id);
+extern uint16_t bta_sys_get_sys_features(void);
+extern void bta_sys_sendmsg(void* p_msg);
+extern void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval,
+ uint16_t event, uint16_t layer_specific);
+extern void bta_sys_disable(tBTA_SYS_HW_MODULE module);
+
+extern void bta_sys_hw_register(tBTA_SYS_HW_MODULE module,
+ tBTA_SYS_HW_CBACK* cback);
+extern void bta_sys_hw_unregister(tBTA_SYS_HW_MODULE module);
+
+extern void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback);
+
+extern void bta_sys_policy_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback);
+
+extern void bta_sys_conn_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_conn_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_app_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_use(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_idle(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+extern void bta_sys_busy(uint8_t id, uint8_t app_id, BD_ADDR peer_addr);
+
+#if (BTM_SSR_INCLUDED == TRUE)
+extern void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK* p_cback);
+extern void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id,
+ uint16_t max_latency, uint16_t min_tout);
+#endif
+
+extern void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, uint8_t new_role,
+ uint8_t hci_status);
+extern void bta_sys_collision_register(uint8_t bta_id,
+ tBTA_SYS_CONN_CBACK* p_cback);
+extern void bta_sys_notify_collision(BD_ADDR_PTR p_bda);
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+extern void bta_sys_eir_register(tBTA_SYS_EIR_CBACK* p_cback);
+extern void bta_sys_add_uuid(uint16_t uuid16);
+extern void bta_sys_remove_uuid(uint16_t uuid16);
+#else
+#define bta_sys_eir_register(ut)
+#define bta_sys_add_uuid(ut)
+#define bta_sys_remove_uuid(ut)
+#endif
+
+extern void bta_sys_set_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr);
+extern void bta_sys_clear_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr);
+extern void bta_sys_set_default_policy(uint8_t id, uint8_t policy);
+extern void bta_sys_clear_default_policy(uint8_t id, uint8_t policy);
+
+#endif /* BTA_SYS_H */
diff --git a/mtkbt/code/bt/bta/sys/bta_sys_conn.cc b/mtkbt/code/bt/bta/sys/bta_sys_conn.cc
new file mode 100755
index 0000000..27967cc
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sys/bta_sys_conn.cc
@@ -0,0 +1,505 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Routes connection status callbacks from various sub systems to DM
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "osi/include/osi.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function bta_sys_rm_register
+ *
+ * Description Called by BTA DM to register role management callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_rm_register(tBTA_SYS_CONN_CBACK* p_cback) {
+ bta_sys_cb.prm_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_policy_register
+ *
+ * Description Called by BTA DM to register link policy change callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_policy_register(tBTA_SYS_CONN_CBACK* p_cback) {
+ bta_sys_cb.p_policy_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_role_chg_register
+ *
+ * Description Called by BTA AV to register role change callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_role_chg_register(tBTA_SYS_CONN_CBACK* p_cback) {
+ bta_sys_cb.p_role_cb = p_cback;
+}
+/*******************************************************************************
+ *
+ * Function bta_sys_ssr_cfg_register
+ *
+ * Description Called by BTA DM to register SSR configuration callback
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_ssr_cfg_register(tBTA_SYS_SSR_CFG_CBACK* p_cback) {
+ bta_sys_cb.p_ssr_cb = p_cback;
+}
+#endif
+/*******************************************************************************
+ *
+ * Function bta_sys_role_chg_register
+ *
+ * Description Called by BTA AV to register role change callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_notify_role_chg(BD_ADDR_PTR p_bda, uint8_t new_role,
+ uint8_t hci_status) {
+ if (bta_sys_cb.p_role_cb) {
+ bta_sys_cb.p_role_cb(BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_collision_register
+ *
+ * Description Called by any BTA module to register for collision event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_collision_register(uint8_t bta_id, tBTA_SYS_CONN_CBACK* p_cback) {
+ uint8_t index;
+
+ for (index = 0; index < MAX_COLLISION_REG; index++) {
+ if ((bta_sys_cb.colli_reg.id[index] == bta_id) ||
+ (bta_sys_cb.colli_reg.id[index] == 0)) {
+ bta_sys_cb.colli_reg.id[index] = bta_id;
+ bta_sys_cb.colli_reg.p_coll_cback[index] = p_cback;
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_notify_collision
+ *
+ * Description Called by BTA DM to notify collision event.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_notify_collision(BD_ADDR_PTR p_bda) {
+ uint8_t index;
+
+ for (index = 0; index < MAX_COLLISION_REG; index++) {
+ if ((bta_sys_cb.colli_reg.id[index] != 0) &&
+ (bta_sys_cb.colli_reg.p_coll_cback[index] != NULL)) {
+ bta_sys_cb.colli_reg.p_coll_cback[index](0, BTA_ID_SYS, 0, p_bda);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sco_register
+ *
+ * Description Called by BTA AV to register sco connection change callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sco_register(tBTA_SYS_CONN_CBACK* p_cback) {
+ bta_sys_cb.p_sco_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_pm_register
+ *
+ * Description Called by BTA DM to register power management callbacks
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_pm_register(tBTA_SYS_CONN_CBACK* p_cback) {
+ bta_sys_cb.ppm_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_conn_open
+ *
+ * Description Called by BTA subsystems when a connection is made to
+ * the service
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_conn_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.prm_cb) {
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_OPEN, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_conn_close
+ *
+ * Description Called by BTA subsystems when a connection to the service
+ * is closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_conn_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.prm_cb) {
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_CLOSE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_app_open
+ *
+ * Description Called by BTA subsystems when application initiates
+ * connection to a peer device
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_app_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_APP_OPEN, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_app_close
+ *
+ * Description Called by BTA subsystems when application initiates close
+ * of connection to peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_app_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_APP_CLOSE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sco_open
+ *
+ * Description Called by BTA subsystems when sco connection for that
+ * service is open
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sco_open(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ /* AG triggers p_sco_cb by bta_sys_sco_use. */
+ if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
+ /* without querying BTM_GetNumScoLinks() */
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_SCO_OPEN, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sco_close
+ *
+ * Description Called by BTA subsystems when sco connection for that
+ * service is closed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sco_close(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ uint8_t num_sco_links;
+
+ if ((id != BTA_ID_AG) && (bta_sys_cb.p_sco_cb)) {
+ num_sco_links = BTM_GetNumScoLinks();
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_SCO_CLOSE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sco_use
+ *
+ * Description Called by BTA subsystems when that service needs to use sco.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sco_use(UNUSED_ATTR uint8_t id, uint8_t app_id,
+ BD_ADDR peer_addr) {
+ /* AV streaming need to be suspended before SCO is connected. */
+ if (bta_sys_cb.p_sco_cb) {
+ /* without querying BTM_GetNumScoLinks() */
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_OPEN, 1, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sco_unuse
+ *
+ * Description Called by BTA subsystems when sco connection for that
+ * service is no longer needed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sco_unuse(UNUSED_ATTR uint8_t id, uint8_t app_id,
+ BD_ADDR peer_addr) {
+ uint8_t num_sco_links;
+
+ if ((bta_sys_cb.p_sco_cb)) {
+ num_sco_links = BTM_GetNumScoLinks();
+ bta_sys_cb.p_sco_cb(BTA_SYS_SCO_CLOSE, num_sco_links, app_id, peer_addr);
+ }
+}
+/*******************************************************************************
+ *
+ * Function bta_sys_chg_ssr_config
+ *
+ * Description Called by BTA subsystems to indicate that the given app SSR
+ * setting needs to be changed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void bta_sys_chg_ssr_config(uint8_t id, uint8_t app_id, uint16_t max_latency,
+ uint16_t min_tout) {
+ if (bta_sys_cb.p_ssr_cb) {
+ bta_sys_cb.p_ssr_cb(id, app_id, max_latency, min_tout);
+ }
+}
+#endif
+/*******************************************************************************
+ *
+ * Function bta_sys_set_policy
+ *
+ * Description Called by BTA subsystems to indicate that the given link
+ * policy to peer device should be set
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_set_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr) {
+ if (bta_sys_cb.p_policy_cb) {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_SET, id, policy, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_clear_policy
+ *
+ * Description Called by BTA subsystems to indicate that the given link
+ * policy to peer device should be clear
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_clear_policy(uint8_t id, uint8_t policy, BD_ADDR peer_addr) {
+ if (bta_sys_cb.p_policy_cb) {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_CLR, id, policy, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_set_default_policy
+ *
+ * Description Called by BTA subsystems to indicate that the given default
+ * link policy should be set
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_set_default_policy(uint8_t id, uint8_t policy) {
+ if (bta_sys_cb.p_policy_cb) {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_SET, id, policy, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_clear_default_policy
+ *
+ * Description Called by BTA subsystems to indicate that the given default
+ * link policy should be clear
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_clear_default_policy(uint8_t id, uint8_t policy) {
+ if (bta_sys_cb.p_policy_cb) {
+ bta_sys_cb.p_policy_cb(BTA_SYS_PLCY_DEF_CLR, id, policy, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_idle
+ *
+ * Description Called by BTA subsystems to indicate that the connection to
+ * peer device is idle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_idle(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.prm_cb) {
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_IDLE, id, app_id, peer_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_busy
+ *
+ * Description Called by BTA subsystems to indicate that the connection to
+ * peer device is busy
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_busy(uint8_t id, uint8_t app_id, BD_ADDR peer_addr) {
+ if (bta_sys_cb.prm_cb) {
+ bta_sys_cb.prm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+ }
+
+ if (bta_sys_cb.ppm_cb) {
+ bta_sys_cb.ppm_cb(BTA_SYS_CONN_BUSY, id, app_id, peer_addr);
+ }
+}
+
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+/*******************************************************************************
+ *
+ * Function bta_sys_eir_register
+ *
+ * Description Called by BTA DM to register EIR utility function that can
+ * be used by the other BTA modules to add/remove UUID.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_eir_register(tBTA_SYS_EIR_CBACK* p_cback) {
+ bta_sys_cb.eir_cb = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_add_uuid
+ *
+ * Description Called by BTA subsystems to indicate to DM that new service
+ * class UUID is added.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_add_uuid(uint16_t uuid16) {
+ if (bta_sys_cb.eir_cb) {
+ bta_sys_cb.eir_cb(uuid16, true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_remove_uuid
+ *
+ * Description Called by BTA subsystems to indicate to DM that the service
+ * class UUID is removed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_remove_uuid(uint16_t uuid16) {
+ if (bta_sys_cb.eir_cb) {
+ bta_sys_cb.eir_cb(uuid16, false);
+ }
+}
+#endif
diff --git a/mtkbt/code/bt/bta/sys/bta_sys_int.h b/mtkbt/code/bt/bta/sys/bta_sys_int.h
new file mode 100755
index 0000000..dc88e45
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sys/bta_sys_int.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA system manager.
+ *
+ ******************************************************************************/
+#ifndef BTA_SYS_INT_H
+#define BTA_SYS_INT_H
+
+/*****************************************************************************
+ * Constants and data types
+ ****************************************************************************/
+
+/*****************************************************************************
+ * state table
+ ****************************************************************************/
+
+/* SYS HW state */
+enum {
+ BTA_SYS_HW_OFF,
+ BTA_SYS_HW_STARTING,
+ BTA_SYS_HW_ON,
+ BTA_SYS_HW_STOPPING
+};
+typedef uint8_t tBTA_SYS_HW_STATE;
+
+/* Collision callback */
+#define MAX_COLLISION_REG 5
+
+typedef struct {
+ uint8_t id[MAX_COLLISION_REG];
+ tBTA_SYS_CONN_CBACK* p_coll_cback[MAX_COLLISION_REG];
+} tBTA_SYS_COLLISION;
+
+/* system manager control block */
+typedef struct {
+ tBTA_SYS_REG* reg[BTA_ID_MAX]; /* registration structures */
+ bool is_reg[BTA_ID_MAX]; /* registration structures */
+ tBTA_SYS_HW_STATE state;
+ tBTA_SYS_HW_CBACK* sys_hw_cback[BTA_SYS_MAX_HW_MODULES]; /* enable callback
+ for each HW
+ modules */
+ uint32_t sys_hw_module_active; /* bitmask of all active modules */
+ uint16_t sys_features; /* Bitmask of sys features */
+
+ tBTA_SYS_CONN_CBACK* prm_cb; /* role management callback registered by DM */
+ tBTA_SYS_CONN_CBACK*
+ ppm_cb; /* low power management callback registered by DM */
+ tBTA_SYS_CONN_CBACK*
+ p_policy_cb; /* link policy change callback registered by DM */
+ tBTA_SYS_CONN_CBACK*
+ p_sco_cb; /* SCO connection change callback registered by AV */
+ tBTA_SYS_CONN_CBACK* p_role_cb; /* role change callback registered by AV */
+ tBTA_SYS_COLLISION colli_reg; /* collision handling module */
+#if (BTA_EIR_CANNED_UUID_LIST != TRUE)
+ tBTA_SYS_EIR_CBACK* eir_cb; /* add/remove UUID into EIR */
+#endif
+#if (BTM_SSR_INCLUDED == TRUE)
+ tBTA_SYS_SSR_CFG_CBACK* p_ssr_cb;
+#endif
+ /* VS event handler */
+ tBTA_SYS_VS_EVT_HDLR* p_vs_evt_hdlr;
+
+} tBTA_SYS_CB;
+
+/*****************************************************************************
+ * Global variables
+ ****************************************************************************/
+
+/* system manager control block */
+extern tBTA_SYS_CB bta_sys_cb;
+
+/* functions used for BTA SYS HW state machine */
+void bta_sys_hw_btm_cback(tBTM_DEV_STATUS status);
+void bta_sys_hw_error(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_api_enable(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+void bta_sys_hw_evt_stack_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg);
+
+bool bta_sys_sm_execute(BT_HDR* p_msg);
+
+#endif /* BTA_SYS_INT_H */
diff --git a/mtkbt/code/bt/bta/sys/bta_sys_main.cc b/mtkbt/code/bt/bta/sys/bta_sys_main.cc
new file mode 100755
index 0000000..32985e8
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sys/bta_sys_main.cc
@@ -0,0 +1,619 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA system manager.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bta_sys_main"
+
+#include <base/logging.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_closure_int.h"
+#include "bta_sys.h"
+#include "bta_sys_int.h"
+#include "btm_api.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "utl.h"
+
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+#include "bta_ar_api.h"
+#endif
+
+/* system manager control block definition */
+tBTA_SYS_CB bta_sys_cb;
+
+fixed_queue_t* btu_bta_alarm_queue;
+extern thread_t* bt_workqueue_thread;
+
+/* trace level */
+/* TODO Hard-coded trace levels - Needs to be configurable */
+uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING; // APPL_INITIAL_TRACE_LEVEL;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING;
+
+// Communication queue between btu_task and bta.
+extern fixed_queue_t* btu_bta_msg_queue;
+
+static const tBTA_SYS_REG bta_sys_hw_reg = {bta_sys_sm_execute, NULL};
+
+/* type for action functions */
+typedef void (*tBTA_SYS_ACTION)(tBTA_SYS_HW_MSG* p_data);
+
+/* action function list */
+const tBTA_SYS_ACTION bta_sys_action[] = {
+ /* device manager local device API events - cf bta_sys.h for events */
+ bta_sys_hw_api_enable, /* 0 BTA_SYS_HW_API_ENABLE_EVT */
+ bta_sys_hw_evt_enabled, /* 1 BTA_SYS_HW_EVT_ENABLED_EVT */
+ bta_sys_hw_evt_stack_enabled, /* 2 BTA_SYS_HW_EVT_STACK_ENABLED_EVT */
+ bta_sys_hw_api_disable, /* 3 BTA_SYS_HW_API_DISABLE_EVT */
+ bta_sys_hw_evt_disabled, /* 4 BTA_SYS_HW_EVT_DISABLED_EVT */
+ bta_sys_hw_error /* 5 BTA_SYS_HW_ERROR_EVT */
+};
+
+/* state machine action enumeration list */
+enum {
+ /* device manager local device API events */
+ BTA_SYS_HW_API_ENABLE,
+ BTA_SYS_HW_EVT_ENABLED,
+ BTA_SYS_HW_EVT_STACK_ENABLED,
+ BTA_SYS_HW_API_DISABLE,
+ BTA_SYS_HW_EVT_DISABLED,
+ BTA_SYS_HW_ERROR
+};
+
+#define BTA_SYS_NUM_ACTIONS (BTA_SYS_MAX_EVT & 0x00ff)
+#define BTA_SYS_IGNORE BTA_SYS_NUM_ACTIONS
+
+/* state table information */
+#define BTA_SYS_ACTIONS 2 /* number of actions */
+#define BTA_SYS_NEXT_STATE 2 /* position of next state */
+#define BTA_SYS_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for OFF state */
+const uint8_t bta_sys_hw_off[][BTA_SYS_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next State */
+ /* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STARTING},
+ /* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING},
+ /* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+ /* API_DISABLE */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE,
+ BTA_SYS_HW_OFF},
+ /* EVT_DISABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF},
+ /* EVT_ERROR */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}};
+
+const uint8_t bta_sys_hw_starting[][BTA_SYS_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next State */
+ /* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STARTING}, /* wait for completion event */
+ /* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STARTING},
+ /* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_IGNORE,
+ BTA_SYS_HW_ON},
+ /* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STOPPING}, /* successive disable/enable:
+ change state wait for
+ completion to disable */
+ /* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_HW_API_ENABLE,
+ BTA_SYS_HW_STARTING}, /* successive enable/disable:
+ notify, then restart HW */
+ /* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}};
+
+const uint8_t bta_sys_hw_on[][BTA_SYS_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next State */
+ /* API_ENABLE */ {BTA_SYS_HW_API_ENABLE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+ /* EVT_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+ /* STACK_ENABLED */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+ /* API_DISABLE */
+ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_ON}, /* don't change the state here, as some
+ other modules might be active */
+ /* EVT_DISABLED */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON},
+ /* EVT_ERROR */ {BTA_SYS_HW_ERROR, BTA_SYS_IGNORE, BTA_SYS_HW_ON}};
+
+const uint8_t bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] = {
+ /* Event Action 1 Action 2
+ Next State */
+ /* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STARTING}, /* change state, and wait for
+ completion event to enable */
+ /* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STOPPING}, /* successive enable/disable:
+ finish the enable before
+ disabling */
+ /* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE,
+ BTA_SYS_HW_STOPPING}, /* successive enable/disable:
+ notify, then stop */
+ /* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STOPPING}, /* wait for completion event */
+ /* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE,
+ BTA_SYS_HW_OFF},
+ /* EVT_ERROR */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE,
+ BTA_SYS_HW_STOPPING}};
+
+typedef const uint8_t (*tBTA_SYS_ST_TBL)[BTA_SYS_NUM_COLS];
+
+/* state table */
+const tBTA_SYS_ST_TBL bta_sys_st_tbl[] = {bta_sys_hw_off, bta_sys_hw_starting,
+ bta_sys_hw_on, bta_sys_hw_stopping};
+
+/*******************************************************************************
+ *
+ * Function bta_sys_init
+ *
+ * Description BTA initialization; called from task initialization.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_init(void) {
+ memset(&bta_sys_cb, 0, sizeof(tBTA_SYS_CB));
+
+ btu_bta_alarm_queue = fixed_queue_new(SIZE_MAX);
+
+ alarm_register_processing_queue(btu_bta_alarm_queue, bt_workqueue_thread);
+
+ appl_trace_level = APPL_INITIAL_TRACE_LEVEL;
+
+ /* register BTA SYS message handler */
+ bta_sys_register(BTA_ID_SYS, &bta_sys_hw_reg);
+
+ /* register for BTM notifications */
+ BTM_RegisterForDeviceStatusNotif((tBTM_DEV_STATUS_CB*)&bta_sys_hw_btm_cback);
+
+#if (defined BTA_AR_INCLUDED) && (BTA_AR_INCLUDED == true)
+ bta_ar_init();
+#endif
+
+ bta_closure_init(bta_sys_register, bta_sys_sendmsg);
+}
+
+void bta_sys_free(void) {
+ alarm_unregister_processing_queue(btu_bta_alarm_queue);
+ fixed_queue_free(btu_bta_alarm_queue, NULL);
+ btu_bta_alarm_queue = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sm_execute
+ *
+ * Description State machine event handling function for DM
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_sys_sm_execute(BT_HDR* p_msg) {
+ bool freebuf = true;
+ tBTA_SYS_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ APPL_TRACE_EVENT("bta_sys_sm_execute state:%d, event:0x%x", bta_sys_cb.state,
+ p_msg->event);
+
+ /* look up the state table for the current state */
+ state_table = bta_sys_st_tbl[bta_sys_cb.state];
+ /* update state */
+ bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < BTA_SYS_ACTIONS; i++) {
+ action = state_table[p_msg->event & 0x00ff][i];
+ if (action != BTA_SYS_IGNORE) {
+ (*bta_sys_action[action])((tBTA_SYS_HW_MSG*)p_msg);
+ } else {
+ break;
+ }
+ }
+ return freebuf;
+}
+
+void bta_sys_hw_register(tBTA_SYS_HW_MODULE module, tBTA_SYS_HW_CBACK* cback) {
+ bta_sys_cb.sys_hw_cback[module] = cback;
+}
+
+void bta_sys_hw_unregister(tBTA_SYS_HW_MODULE module) {
+ bta_sys_cb.sys_hw_cback[module] = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_btm_cback
+ *
+ * Description This function is registered by BTA SYS to BTM in order to get
+ * status notifications
+ *
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void bta_sys_hw_btm_cback(tBTM_DEV_STATUS status) {
+ tBTA_SYS_HW_MSG* sys_event =
+ (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+
+ APPL_TRACE_DEBUG("%s was called with parameter: %i", __func__, status);
+
+ /* send a message to BTA SYS */
+ if (status == BTM_DEV_STATUS_UP) {
+ sys_event->hdr.event = BTA_SYS_EVT_STACK_ENABLED_EVT;
+ } else if (status == BTM_DEV_STATUS_DOWN) {
+ sys_event->hdr.event = BTA_SYS_ERROR_EVT;
+ } else {
+ /* BTM_DEV_STATUS_CMD_TOUT is ignored for now. */
+ osi_free_and_reset((void**)&sys_event);
+ }
+
+ if (sys_event) bta_sys_sendmsg(sys_event);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_error
+ *
+ * Description In case the HW device stops answering... Try to turn it off,
+ * then re-enable all
+ * previously active SW modules.
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_error(UNUSED_ATTR tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ uint8_t module_index;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ for (module_index = 0; module_index < BTA_SYS_MAX_HW_MODULES;
+ module_index++) {
+ if (bta_sys_cb.sys_hw_module_active & ((uint32_t)1 << module_index)) {
+ switch (module_index) {
+ case BTA_SYS_HW_BLUETOOTH:
+ /* Send BTA_SYS_HW_ERROR_EVT to DM */
+ if (bta_sys_cb.sys_hw_cback[module_index] != NULL)
+ bta_sys_cb.sys_hw_cback[module_index](BTA_SYS_HW_ERROR_EVT);
+ break;
+ default:
+ /* not yet supported */
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_enable
+ *
+ * Description this function is called after API enable and HW has been
+ * turned on
+ *
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+
+void bta_sys_hw_api_enable(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ if ((!bta_sys_cb.sys_hw_module_active) &&
+ (bta_sys_cb.state != BTA_SYS_HW_ON)) {
+ /* register which HW module was turned on */
+ bta_sys_cb.sys_hw_module_active |= ((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+ tBTA_SYS_HW_MSG* p_msg =
+ (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+ p_msg->hdr.event = BTA_SYS_EVT_ENABLED_EVT;
+ p_msg->hw_module = p_sys_hw_msg->hw_module;
+
+ bta_sys_sendmsg(p_msg);
+ } else {
+ /* register which HW module was turned on */
+ bta_sys_cb.sys_hw_module_active |= ((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+ /* HW already in use, so directly notify the caller */
+ if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module] != NULL)
+ bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module](BTA_SYS_HW_ON_EVT);
+ }
+
+ APPL_TRACE_EVENT("bta_sys_hw_api_enable for %d, active modules 0x%04X",
+ p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_disable
+ *
+ * Description if no other module is using the HW, this function will call
+ * (if defined) a user-macro to turn off the HW
+ *
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ APPL_TRACE_DEBUG("bta_sys_hw_api_disable for %d, active modules: 0x%04X",
+ p_sys_hw_msg->hw_module, bta_sys_cb.sys_hw_module_active);
+
+ /* make sure the related SW blocks were stopped */
+ bta_sys_disable(p_sys_hw_msg->hw_module);
+
+ /* register which module we turn off */
+ bta_sys_cb.sys_hw_module_active &= ~((uint32_t)1 << p_sys_hw_msg->hw_module);
+
+ /* if there are still some SW modules using the HW, just provide an answer to
+ * the calling */
+ if (bta_sys_cb.sys_hw_module_active != 0) {
+ /* if there are still some SW modules using the HW, directly notify the
+ * caller */
+ if (bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module] != NULL)
+ bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module](BTA_SYS_HW_OFF_EVT);
+ } else {
+ /* manually update the state of our system */
+ bta_sys_cb.state = BTA_SYS_HW_STOPPING;
+
+ tBTA_SYS_HW_MSG* p_msg =
+ (tBTA_SYS_HW_MSG*)osi_malloc(sizeof(tBTA_SYS_HW_MSG));
+ p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT;
+ p_msg->hw_module = p_sys_hw_msg->hw_module;
+
+ bta_sys_sendmsg(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_event_enabled
+ *
+ * Description
+ *
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_enabled(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ APPL_TRACE_EVENT("bta_sys_hw_evt_enabled for %i", p_sys_hw_msg->hw_module);
+ BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_event_disabled
+ *
+ * Description
+ *
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ uint8_t hw_module_index;
+
+ APPL_TRACE_DEBUG("bta_sys_hw_evt_disabled - module 0x%X",
+ p_sys_hw_msg->hw_module);
+
+ for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES;
+ hw_module_index++) {
+ if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+ bta_sys_cb.sys_hw_cback[hw_module_index](BTA_SYS_HW_OFF_EVT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_hw_event_stack_enabled
+ *
+ * Description we receive this event once the SW side is ready (stack, FW
+ * download,... ), i.e. we can really start using the device. So
+ * notify the app.
+ *
+ * Returns success or failure
+ *
+ ******************************************************************************/
+void bta_sys_hw_evt_stack_enabled(UNUSED_ATTR tBTA_SYS_HW_MSG* p_sys_hw_msg) {
+ uint8_t hw_module_index;
+
+ APPL_TRACE_DEBUG(" bta_sys_hw_evt_stack_enabled!notify the callers");
+
+ for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES;
+ hw_module_index++) {
+ if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL)
+ bta_sys_cb.sys_hw_cback[hw_module_index](BTA_SYS_HW_ON_EVT);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_event
+ *
+ * Description BTA event handler; called from task event handler.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_event(BT_HDR* p_msg) {
+ uint8_t id;
+ bool freebuf = true;
+
+ APPL_TRACE_EVENT("%s: Event 0x%x", __func__, p_msg->event);
+
+ /* get subsystem id from event */
+ id = (uint8_t)(p_msg->event >> 8);
+
+ /* verify id and call subsystem event handler */
+ if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL)) {
+ freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
+ } else {
+ APPL_TRACE_WARNING("%s: Received unregistered event id %d", __func__, id);
+ }
+
+ if (freebuf) {
+ osi_free(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_register
+ *
+ * Description Called by other BTA subsystems to register their event
+ * handler.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
+ bta_sys_cb.reg[id] = (tBTA_SYS_REG*)p_reg;
+ bta_sys_cb.is_reg[id] = true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_deregister
+ *
+ * Description Called by other BTA subsystems to de-register
+ * handler.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_deregister(uint8_t id) { bta_sys_cb.is_reg[id] = false; }
+
+/*******************************************************************************
+ *
+ * Function bta_sys_is_register
+ *
+ * Description Called by other BTA subsystems to get registeration
+ * status.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool bta_sys_is_register(uint8_t id) { return bta_sys_cb.is_reg[id]; }
+
+/*******************************************************************************
+ *
+ * Function bta_sys_sendmsg
+ *
+ * Description Send a GKI message to BTA. This function is designed to
+ * optimize sending of messages to BTA. It is called by BTA
+ * API functions and call-in functions.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_sendmsg(void* p_msg) {
+ // There is a race condition that occurs if the stack is shut down while
+ // there is a procedure in progress that can schedule a task via this
+ // message queue. This causes |btu_bta_msg_queue| to get cleaned up before
+ // it gets used here; hence we check for NULL before using it.
+ if (btu_bta_msg_queue) fixed_queue_enqueue(btu_bta_msg_queue, p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_start_timer
+ *
+ * Description Start a protocol timer for the specified amount
+ * of time in milliseconds.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_start_timer(alarm_t* alarm, period_ms_t interval, uint16_t event,
+ uint16_t layer_specific) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = event;
+ p_buf->layer_specific = layer_specific;
+ alarm_set_on_queue(alarm, interval, bta_sys_sendmsg, p_buf,
+ btu_bta_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_disable
+ *
+ * Description For each registered subsystem execute its disable function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_disable(tBTA_SYS_HW_MODULE module) {
+ int bta_id = 0;
+ int bta_id_max = 0;
+
+ APPL_TRACE_DEBUG("bta_sys_disable: module %i", module);
+
+ switch (module) {
+ case BTA_SYS_HW_BLUETOOTH:
+ bta_id = BTA_ID_DM;
+ bta_id_max = BTA_ID_BLUETOOTH_MAX;
+ break;
+ default:
+ APPL_TRACE_WARNING("bta_sys_disable: unkown module");
+ return;
+ }
+
+ for (; bta_id <= bta_id_max; bta_id++) {
+ if (bta_sys_cb.reg[bta_id] != NULL) {
+ if (bta_sys_cb.is_reg[bta_id] == true &&
+ bta_sys_cb.reg[bta_id]->disable != NULL) {
+ (*bta_sys_cb.reg[bta_id]->disable)();
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_sys_set_trace_level
+ *
+ * Description Set trace level for BTA
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_sys_set_trace_level(uint8_t level) { appl_trace_level = level; }
+
+/*******************************************************************************
+ *
+ * Function bta_sys_get_sys_features
+ *
+ * Description Returns sys_features to other BTA modules.
+ *
+ * Returns sys_features
+ *
+ ******************************************************************************/
+uint16_t bta_sys_get_sys_features(void) { return bta_sys_cb.sys_features; }
diff --git a/mtkbt/code/bt/bta/sys/utl.cc b/mtkbt/code/bt/bta/sys/utl.cc
new file mode 100755
index 0000000..7feda33
--- a/dev/null
+++ b/mtkbt/code/bt/bta/sys/utl.cc
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains utility functions.
+ *
+ ******************************************************************************/
+#include <stddef.h>
+
+#include "bt_common.h"
+#include "btm_api.h"
+#include "utl.h"
+
+/*******************************************************************************
+ *
+ * Function utl_str2int
+ *
+ * Description This utility function converts a character string to an
+ * integer. Acceptable values in string are 0-9. If invalid
+ * string or string value too large, -1 is returned. Leading
+ * spaces are skipped.
+ *
+ *
+ * Returns Integer value or -1 on error.
+ *
+ ******************************************************************************/
+int16_t utl_str2int(const char* p_s) {
+ int32_t val = 0;
+
+ for (; *p_s == ' ' && *p_s != 0; p_s++)
+ ;
+
+ if (*p_s == 0) return -1;
+
+ for (;;) {
+ if ((*p_s < '0') || (*p_s > '9')) return -1;
+
+ val += (int32_t)(*p_s++ - '0');
+
+ if (val > 32767) return -1;
+
+ if (*p_s == 0) {
+ return (int16_t)val;
+ } else {
+ val *= 10;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function utl_strucmp
+ *
+ * Description This utility function compares two strings in uppercase.
+ * String p_s must be uppercase. String p_t is converted to
+ * uppercase if lowercase. If p_s ends first, the substring
+ * match is counted as a match.
+ *
+ *
+ * Returns 0 if strings match, nonzero otherwise.
+ *
+ ******************************************************************************/
+int utl_strucmp(const char* p_s, const char* p_t) {
+ char c;
+
+ while (*p_s && *p_t) {
+ c = *p_t++;
+ if (c >= 'a' && c <= 'z') {
+ c -= 0x20;
+ }
+ if (*p_s++ != c) {
+ return -1;
+ }
+ }
+ /* if p_t hit null first, no match */
+ if (*p_t == 0 && *p_s != 0) {
+ return 1;
+ }
+ /* else p_s hit null first, count as match */
+ else {
+ return 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function utl_itoa
+ *
+ * Description This utility function converts a uint16_t to a string. The
+ * string is NULL-terminated. The length of the string is
+ * returned;
+ *
+ *
+ * Returns Length of string.
+ *
+ ******************************************************************************/
+uint8_t utl_itoa(uint16_t i, char* p_s) {
+ uint16_t j, k;
+ char* p = p_s;
+ bool fill = false;
+
+ if (i == 0) {
+ /* take care of zero case */
+ *p++ = '0';
+ } else {
+ for (j = 10000; j > 0; j /= 10) {
+ k = i / j;
+ i %= j;
+ if (k > 0 || fill) {
+ *p++ = k + '0';
+ fill = true;
+ }
+ }
+ }
+ *p = 0;
+ return (uint8_t)(p - p_s);
+}
+
+/*******************************************************************************
+ *
+ * Function utl_set_device_class
+ *
+ * Description This function updates the local Device Class.
+ *
+ * Parameters:
+ * p_cod - Pointer to the device class to set to
+ *
+ * cmd - the fields of the device class to update.
+ * BTA_UTL_SET_COD_MAJOR_MINOR, - overwrite major,
+ * minor class
+ * BTA_UTL_SET_COD_SERVICE_CLASS - set the bits in
+ * the input
+ * BTA_UTL_CLR_COD_SERVICE_CLASS - clear the bits in
+ * the input
+ * BTA_UTL_SET_COD_ALL - overwrite major, minor, set
+ * the bits in service class
+ * BTA_UTL_INIT_COD - overwrite major, minor, and
+ * service class
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_set_device_class(tBTA_UTL_COD* p_cod, uint8_t cmd) {
+ uint8_t* dev;
+ uint16_t service;
+ uint8_t minor, major;
+ DEV_CLASS dev_class;
+
+ dev = BTM_ReadDeviceClass();
+ BTM_COD_SERVICE_CLASS(service, dev);
+ BTM_COD_MINOR_CLASS(minor, dev);
+ BTM_COD_MAJOR_CLASS(major, dev);
+
+ switch (cmd) {
+ case BTA_UTL_SET_COD_MAJOR_MINOR:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ break;
+
+ case BTA_UTL_SET_COD_SERVICE_CLASS:
+ /* clear out the bits that is not SERVICE_CLASS bits */
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service | p_cod->service;
+ break;
+
+ case BTA_UTL_CLR_COD_SERVICE_CLASS:
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service & (~p_cod->service);
+ break;
+
+ case BTA_UTL_SET_COD_ALL:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ p_cod->service &= BTM_COD_SERVICE_CLASS_MASK;
+ service = service | p_cod->service;
+ break;
+
+ case BTA_UTL_INIT_COD:
+ minor = p_cod->minor & BTM_COD_MINOR_CLASS_MASK;
+ major = p_cod->major & BTM_COD_MAJOR_CLASS_MASK;
+ service = p_cod->service & BTM_COD_SERVICE_CLASS_MASK;
+ break;
+
+ default:
+ return false;
+ }
+
+ /* convert the fields into the device class type */
+ FIELDS_TO_COD(dev_class, minor, major, service);
+
+ if (BTM_SetDeviceClass(dev_class) == BTM_SUCCESS) return true;
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function utl_isintstr
+ *
+ * Description This utility function checks if the given string is an
+ * integer string or not
+ *
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isintstr(const char* p_s) {
+ uint16_t i = 0;
+
+ for (i = 0; p_s[i] != 0; i++) {
+ if (((p_s[i] < '0') || (p_s[i] > '9')) && (p_s[i] != ';')) return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function utl_isdialchar
+ *
+ * Description This utility function checks if the given character
+ * is an acceptable dial digit
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isdialchar(const char d) {
+ return (((d >= '0') && (d <= '9')) || (d == '*') || (d == '+') ||
+ (d == '#') || (d == ';') || ((d >= 'A') && (d <= 'C')) ||
+ ((d == 'p') || (d == 'P') || (d == 'w') || (d == 'W')));
+}
+
+/*******************************************************************************
+ *
+ * Function utl_isdialstr
+ *
+ * Description This utility function checks if the given string contains
+ * only dial digits or not
+ *
+ *
+ * Returns true if successful, Otherwise false
+ *
+ ******************************************************************************/
+bool utl_isdialstr(const char* p_s) {
+ for (uint16_t i = 0; p_s[i] != 0; i++) {
+ // include chars not in spec that work sent by some headsets.
+ if (!(utl_isdialchar(p_s[i]) || (p_s[i] == '-'))) return false;
+ }
+ return true;
+}
diff --git a/mtkbt/code/bt/bta/test/bta_closure_test.cc b/mtkbt/code/bt/bta/test/bta_closure_test.cc
new file mode 100755
index 0000000..9e1e4bb
--- a/dev/null
+++ b/mtkbt/code/bt/bta/test/bta_closure_test.cc
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+#include <queue>
+
+#include "bta/closure/bta_closure_int.h"
+#include "bta/include/bta_closure_api.h"
+#include "include/bt_trace.h"
+
+namespace {
+
+/* There is no test class, because we talk to C code that accepts plain
+ * functions as arguments.
+ */
+
+int test_counter = 0;
+tBTA_SYS_EVT_HDLR* closure_handler = NULL;
+std::queue<BT_HDR*> msgs;
+
+void test_plus_one_task() { test_counter++; }
+
+void test_plus_two_task() { test_counter += 2; }
+
+void fake_bta_sys_sendmsg(void* p_msg) { msgs.push((BT_HDR*)p_msg); }
+
+void fake_bta_sys_register(uint8_t id, const tBTA_SYS_REG* p_reg) {
+ closure_handler = p_reg->evt_hdlr;
+}
+
+bool fake_bta_sys_sendmsg_execute() {
+ BT_HDR* p_msg = msgs.front();
+ msgs.pop();
+ return closure_handler(p_msg);
+}
+
+} // namespace
+
+// TODO(jpawlowski): there is some weird dependency issue in tests, and the
+// tests here fail to compile without this definition.
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+
+TEST(ClosureTest, test_post_task) {
+ test_counter = 0;
+
+ bta_closure_init(fake_bta_sys_register, fake_bta_sys_sendmsg);
+
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+ EXPECT_EQ(1U, msgs.size()) << "Message should not be NULL";
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(1, test_counter);
+}
+
+TEST(ClosureTest, test_post_multiple_tasks) {
+ test_counter = 0;
+
+ bta_closure_init(fake_bta_sys_register, fake_bta_sys_sendmsg);
+
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_one_task));
+ do_in_bta_thread(FROM_HERE, base::Bind(&test_plus_two_task));
+
+ EXPECT_EQ(6U, msgs.size());
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(1, test_counter);
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(3, test_counter);
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(4, test_counter);
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(6, test_counter);
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(7, test_counter);
+
+ EXPECT_TRUE(fake_bta_sys_sendmsg_execute());
+ EXPECT_EQ(9, test_counter);
+}
diff --git a/mtkbt/code/bt/bta/test/bta_hf_client_test.cc b/mtkbt/code/bt/bta/test/bta_hf_client_test.cc
new file mode 100755
index 0000000..72a60a3
--- a/dev/null
+++ b/mtkbt/code/bt/bta/test/bta_hf_client_test.cc
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "bta/hf_client/bta_hf_client_int.h"
+#include "bta/include/bta_hf_client_api.h"
+
+namespace {
+const BD_ADDR bdaddr1 = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+const BD_ADDR bdaddr2 = {0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+} // namespace
+
+class BtaHfClientTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ // Reset the memory block, this is the state on which the allocate handle
+ // would start operating
+ bta_hf_client_cb_arr_init();
+ }
+};
+
+// Test that when we can allocate a device on the block and then check
+// the status of the blocks
+TEST_F(BtaHfClientTest, test_allocate_block_one_device) {
+ uint16_t p_handle = 0;
+ bool status = bta_hf_client_allocate_handle(bdaddr1, &p_handle);
+
+ // Allocation should succeed
+ EXPECT_EQ(true, status);
+ EXPECT_GT(p_handle, 0);
+}
+
+// Test that we cannot allocate the same device on two separate control blocks
+TEST_F(BtaHfClientTest, test_no_allocate_block_same_device) {
+ uint16_t p_handle;
+ bool status = bta_hf_client_allocate_handle(bdaddr1, &p_handle);
+
+ // Allocation should succeed
+ EXPECT_EQ(true, status);
+ EXPECT_GT(p_handle, 0);
+
+ EXPECT_TRUE(bta_hf_client_find_cb_by_bda(bdaddr1) != NULL);
+
+ status = bta_hf_client_allocate_handle(bdaddr1, &p_handle);
+
+ // Allocation should fail
+ EXPECT_EQ(false, status);
+}
+
+// Test that we can allocate two different devices as separate control blocks
+TEST_F(BtaHfClientTest, test_allocate_block_diff_device) {
+ uint16_t p_handle_first;
+ bool status = bta_hf_client_allocate_handle(bdaddr1, &p_handle_first);
+
+ // Allocation should succeed
+ EXPECT_EQ(true, status);
+ EXPECT_GT(p_handle_first, 0);
+
+ EXPECT_TRUE(bta_hf_client_find_cb_by_bda(bdaddr2) == NULL);
+
+ uint16_t p_handle_second;
+ status = bta_hf_client_allocate_handle(bdaddr2, &p_handle_second);
+
+ // Allocation should succeed
+ EXPECT_EQ(true, status);
+ EXPECT_GT(p_handle_second, 0);
+ EXPECT_NE(p_handle_first, p_handle_second);
+}
diff --git a/mtkbt/code/bt/btcore/Android.bp b/mtkbt/code/bt/btcore/Android.bp
new file mode 100755
index 0000000..4f858dd
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/Android.bp
@@ -0,0 +1,60 @@
+// libbtcore static library for target and host
+// ========================================================
+cc_library_static {
+ name: "libbtcore",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: ["include"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs: [
+ "src/bdaddr.cc",
+ "src/device_class.cc",
+ "src/hal_util.cc",
+ "src/module.cc",
+ "src/osi_module.cc",
+ "src/property.cc",
+ "src/uuid.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ linux: {
+ cflags: ["-D_GNU_SOURCE"],
+ },
+ },
+}
+
+// Note: It's good to get the tests compiled both for the host and the target so
+// we get to test with both Bionic libc and glibc
+// libbtcore unit tests for target and host
+// ========================================================
+cc_test {
+ name: "net_test_btcore",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: ["include"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs: [
+ "test/bdaddr_test.cc",
+ "test/device_class_test.cc",
+ "test/property_test.cc",
+ "test/uuid_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libosi-AllocationTestHarness",
+ "libosi",
+ ],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ }
+}
diff --git a/mtkbt/code/bt/btcore/BUILD.gn b/mtkbt/code/bt/btcore/BUILD.gn
new file mode 100755
index 0000000..dc4da9e
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/BUILD.gn
@@ -0,0 +1,64 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("btcore") {
+ sources = [
+ "src/bdaddr.cc",
+ "src/device_class.cc",
+ "src/hal_util.cc",
+ "src/module.cc",
+ "src/property.cc",
+ "src/uuid.cc",
+ "src/osi_module.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_btcore") {
+ testonly = true
+ sources = [
+ "test/device_class_test.cc",
+ "test/property_test.cc",
+ "test/uuid_test.cc",
+ "//osi/test/AllocationTestHarness.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ ]
+
+ deps = [
+ "//btcore",
+ "//osi",
+ "//third_party/googletest:gtest_main",
+ "//third_party/libchrome:base",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ ]
+}
diff --git a/mtkbt/code/bt/btcore/include/bdaddr.h b/mtkbt/code/bt/btcore/include/bdaddr.h
new file mode 100755
index 0000000..9dabc5d
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/bdaddr.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+// Note: the string representation of a bdaddr is expected to have the format
+// xx:xx:xx:xx:xx:xx
+// where each 'x' is a hex digit. The API presented in this header will accept
+// both uppercase and lowercase digits but will only ever produce lowercase
+// digits.
+
+typedef char bdstr_t[sizeof("xx:xx:xx:xx:xx:xx")];
+
+// Returns true if |addr| is the empty address (00:00:00:00:00:00).
+// |addr| may not be NULL.
+bool bdaddr_is_empty(const bt_bdaddr_t* addr);
+
+// Returns true if |first| and |second| refer to the same address. Neither
+// may be NULL.
+bool bdaddr_equals(const bt_bdaddr_t* first, const bt_bdaddr_t* second);
+
+// Returns destination bdaddr |dest| after copying |src| to |dest|.
+// |dest| and |src| must not be NULL.
+bt_bdaddr_t* bdaddr_copy(bt_bdaddr_t* dest, const bt_bdaddr_t* src);
+
+// Makes a string representation of |addr| and places it into |string|. |size|
+// refers to the size of |string|'s buffer and must be >= 18. On success, this
+// function returns |string|, otherwise it returns NULL. Neither |addr| nor
+// |string| may be NULL.
+const char* bdaddr_to_string(const bt_bdaddr_t* addr, char* string,
+ size_t size);
+
+// Returns true if |string| represents a Bluetooth address. |string| may not be
+// NULL.
+bool string_is_bdaddr(const char* string);
+
+// Converts |string| to bt_bdaddr_t and places it in |addr|. If |string| does
+// not represent a Bluetooth address, |addr| is not modified and this function
+// returns false. Otherwise, it returns true. Neither |string| nor |addr| may be
+// NULL.
+bool string_to_bdaddr(const char* string, bt_bdaddr_t* addr);
diff --git a/mtkbt/code/bt/btcore/include/device_class.h b/mtkbt/code/bt/btcore/include/device_class.h
new file mode 100755
index 0000000..2a11400
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/device_class.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// Provides Class Of Device primitive as specified in the bluetooth spec.
+// [Class Of Device]
+// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+
+// Device class may be defined in other structures.
+// Only use defined methods to manipulate internals.
+typedef struct bt_device_class_t {
+ uint8_t _[3]; // Do not access directly; use methods below.
+} bt_device_class_t;
+
+// Copies the |data| class of device stream into device class |dc|. |dc|
+// and |data| must not be NULL.
+void device_class_from_stream(bt_device_class_t* dc, const uint8_t* data);
+
+// Serializes the device class |dc| to pointer argument |data| in big endian
+// format. |len| must contain the buffer size of |data|. Returns the actual
+// number of bytes copied into |data|. |dc| and |data| must not be NULL.
+int device_class_to_stream(const bt_device_class_t* dc, uint8_t* data,
+ size_t len);
+
+// Copies the |data| class of device integer into device class |dc|. |dc|
+// must not be NULL.
+void device_class_from_int(bt_device_class_t* dc, int data);
+
+// Returns the device class |dc| in integer format. |dc| must not be NULL.
+int device_class_to_int(const bt_device_class_t* dc);
+
+// Compares and returns |true| if two device classes |p1| and |p2| are equal.
+// False otherwise.
+bool device_class_equals(const bt_device_class_t* p1,
+ const bt_device_class_t* p2);
+
+// Copies and returns |true| if the device class was successfully copied from
+// |p2| into |p1|. False otherwise.
+bool device_class_copy(bt_device_class_t* dest, const bt_device_class_t* src);
+
+// Query, getters and setters for the major device class. |dc| must not be
+// NULL.
+int device_class_get_major_device(const bt_device_class_t* dc);
+void device_class_set_major_device(bt_device_class_t* dc, int val);
+
+// Query, getters and setters for the minor device class. |dc| must not be NULL.
+int device_class_get_minor_device(const bt_device_class_t* dc);
+void device_class_set_minor_device(bt_device_class_t* dc, int val);
+
+// Query, getters and setters for the various major service class features.
+// |dc| must not be NULL.
+bool device_class_get_limited(const bt_device_class_t* dc);
+void device_class_set_limited(bt_device_class_t* dc, bool set);
+
+bool device_class_get_positioning(const bt_device_class_t* dc);
+void device_class_set_positioning(bt_device_class_t* dc, bool set);
+
+bool device_class_get_networking(const bt_device_class_t* dc);
+void device_class_set_networking(bt_device_class_t* dc, bool set);
+
+bool device_class_get_rendering(const bt_device_class_t* dc);
+void device_class_set_rendering(bt_device_class_t* dc, bool set);
+
+bool device_class_get_capturing(const bt_device_class_t* dc);
+void device_class_set_capturing(bt_device_class_t* dc, bool set);
+
+bool device_class_get_object_transfer(const bt_device_class_t* dc);
+void device_class_set_object_transfer(bt_device_class_t* dc, bool set);
+
+bool device_class_get_audio(const bt_device_class_t* dc);
+void device_class_set_audio(bt_device_class_t* dc, bool set);
+
+bool device_class_get_telephony(const bt_device_class_t* dc);
+void device_class_set_telephony(bt_device_class_t* dc, bool set);
+
+bool device_class_get_information(const bt_device_class_t* dc);
+void device_class_set_information(bt_device_class_t* dc, bool set);
diff --git a/mtkbt/code/bt/btcore/include/device_features.h b/mtkbt/code/bt/btcore/include/device_features.h
new file mode 100755
index 0000000..bf62949
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/device_features.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Represents a page of device feature enabled/disabled bits returned
+// by the local controller. See the bluetooth spec for bit indexes.
+typedef struct { uint8_t as_array[8]; } bt_device_features_t;
diff --git a/mtkbt/code/bt/btcore/include/event_mask.h b/mtkbt/code/bt/btcore/include/event_mask.h
new file mode 100755
index 0000000..cabac9e
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/event_mask.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Represents a mask which can be used to tell the controller which
+// HCI events the stack wishes to be informed about. See the bluetooth
+// spec for more information on what each bit means.
+typedef struct { const uint8_t as_array[8]; } bt_event_mask_t;
diff --git a/mtkbt/code/bt/btcore/include/hal_util.h b/mtkbt/code/bt/btcore/include/hal_util.h
new file mode 100755
index 0000000..46e4906
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/hal_util.h
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+struct hw_module_t;
+
+// Loads the Bluetooth library. If OS_GENERIC is defined, this function looks
+// explicitly for libbluetooth.default.so and loads it. On Android, this calls
+// the hw_get_module routine with the Bluetooth stack module id.
+int hal_util_load_bt_library(const struct hw_module_t** module);
diff --git a/mtkbt/code/bt/btcore/include/iac.h b/mtkbt/code/bt/btcore/include/iac.h
new file mode 100755
index 0000000..6272b0a
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/iac.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Inquiry Access Code
+// [Bluetooth Baseband]
+// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+typedef struct {
+ uint8_t iac[3];
+} __attribute__((packed)) bt_inquiry_access_code_t;
diff --git a/mtkbt/code/bt/btcore/include/module.h b/mtkbt/code/bt/btcore/include/module.h
new file mode 100755
index 0000000..1b29fbb
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/module.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "osi/include/future.h"
+#include "osi/include/thread.h"
+
+typedef future_t* (*module_lifecycle_fn)(void);
+
+#define BTCORE_MAX_MODULE_DEPENDENCIES 10
+
+typedef struct {
+ const char* name;
+ module_lifecycle_fn init;
+ module_lifecycle_fn start_up;
+ module_lifecycle_fn shut_down;
+ module_lifecycle_fn clean_up;
+ const char* dependencies[BTCORE_MAX_MODULE_DEPENDENCIES];
+} module_t;
+
+// Prepares module management. Must be called before doing anything with
+// modules.
+void module_management_start(void);
+// Cleans up all module management resources.
+void module_management_stop(void);
+
+const module_t* get_module(const char* name);
+
+// Initialize the provided module. |module| may not be NULL
+// and must not be initialized.
+bool module_init(const module_t* module);
+// Start up the provided module. |module| may not be NULL
+// and must be initialized or have no init function.
+bool module_start_up(const module_t* module);
+// Shut down the provided module. |module| may not be NULL.
+// If not started, does nothing.
+void module_shut_down(const module_t* module);
+// Clean up the provided module. |module| may not be NULL.
+// If not initialized, does nothing.
+void module_clean_up(const module_t* module);
+
+// Temporary callbacked wrapper for module start up, so real modules can be
+// spliced into the current janky startup sequence. Runs on a separate thread,
+// which terminates when the module start up has finished. When module startup
+// has finished, |callback| is called within the context of |callback_thread|
+// with |FUTURE_SUCCESS| or |FUTURE_FAIL| depending on whether startup succeeded
+// or not.
+void module_start_up_callbacked_wrapper(const module_t* module,
+ thread_t* callback_thread,
+ thread_fn callback);
diff --git a/mtkbt/code/bt/btcore/include/osi_module.h b/mtkbt/code/bt/btcore/include/osi_module.h
new file mode 100755
index 0000000..964a3fa
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/osi_module.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+static const char OSI_MODULE[] = "osi_module";
diff --git a/mtkbt/code/bt/btcore/include/property.h b/mtkbt/code/bt/btcore/include/property.h
new file mode 100755
index 0000000..010c995
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/property.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "btcore/include/device_class.h"
+
+// Copies an array of consecutive properties of |count| to a newly
+// allocated array. |properties| must not be NULL.
+bt_property_t* property_copy_array(const bt_property_t* properties,
+ size_t count);
+
+// Copies |src| to |dest|. Returns the value of |dest|.
+// |src| and |dest| must not be NULL.
+bt_property_t* property_copy(bt_property_t* dest, const bt_property_t* src);
+
+// Returns true if the value of the two properties |p1| and |p2| are equal.
+// |p1| and |p2| must not be NULL.
+bool property_equals(const bt_property_t* p1, const bt_property_t* p2);
+
+// Property resource allocations. Caller is expected to free |property|
+// using |property_free| or |property_free_array|.
+// Parameter must not be NULL. A copy of the parameter is made and
+// stored in the property.
+bt_property_t* property_new_addr(const bt_bdaddr_t* addr);
+bt_property_t* property_new_device_class(const bt_device_class_t* dc);
+bt_property_t* property_new_device_type(bt_device_type_t device_type);
+bt_property_t* property_new_discovery_timeout(const uint32_t timeout);
+bt_property_t* property_new_name(const char* name);
+bt_property_t* property_new_rssi(const int8_t rssi);
+bt_property_t* property_new_scan_mode(bt_scan_mode_t scan_mode);
+bt_property_t* property_new_uuids(const bt_uuid_t* uuid, size_t count);
+
+// Property resource frees both property and value.
+void property_free(bt_property_t* property);
+void property_free_array(bt_property_t* properties, size_t count);
+
+// Value check convenience methods. The contents of the property are
+// checked for the respective validity and returns true, false otherwise.
+// |property| must not be NULL.
+bool property_is_addr(const bt_property_t* property);
+bool property_is_device_class(const bt_property_t* property);
+bool property_is_device_type(const bt_property_t* property);
+bool property_is_discovery_timeout(const bt_property_t* property);
+bool property_is_name(const bt_property_t* property);
+bool property_is_rssi(const bt_property_t* property);
+bool property_is_scan_mode(const bt_property_t* property);
+bool property_is_uuids(const bt_property_t* property);
+
+// Value conversion convenience methods. The contents of the property are
+// properly typed and returned to the caller. |property| must not be NULL.
+const bt_bdaddr_t* property_as_addr(const bt_property_t* property);
+const bt_device_class_t* property_as_device_class(
+ const bt_property_t* property);
+bt_device_type_t property_as_device_type(const bt_property_t* property);
+uint32_t property_as_discovery_timeout(const bt_property_t* property);
+const bt_bdname_t* property_as_name(const bt_property_t* property);
+int8_t property_as_rssi(const bt_property_t* property);
+bt_scan_mode_t property_as_scan_mode(const bt_property_t* property);
+const bt_uuid_t* property_as_uuids(const bt_property_t* property,
+ size_t* count);
diff --git a/mtkbt/code/bt/btcore/include/uuid.h b/mtkbt/code/bt/btcore/include/uuid.h
new file mode 100755
index 0000000..6114ab3
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/uuid.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <stdbool.h>
+
+typedef struct uuid_string_t uuid_string_t;
+
+// Creates uuid string structure to hold a well formed UUID
+// string. Must release resources with |uuid_string_free|.
+// Returns NULL if no memory.
+uuid_string_t* uuid_string_new(void);
+
+// Frees a uuid string structure created from |uuid_string_new|.
+// |uuid_string| may be NULL.
+void uuid_string_free(uuid_string_t* uuid_string);
+
+// Returns a string pointer to the well formed UUID string
+// entry. |uuid_string| must not be NULL.
+const char* uuid_string_data(const uuid_string_t* uuid_string);
+
+// Creates uuid structure from a well formed UUID string
+// |uuid_string|. The caller takes ownership of the uuid
+// structure and must release resources with |uuid_free|.
+// |uuid_string| must not be NULL.
+//
+// Returns NULL if |uuid_string| is malformed or no memory.
+//
+// A well formed UUID string is structured like this:
+// "00112233-4455-6677-8899-aabbccddeeff"
+bt_uuid_t* uuid_new(const char* uuid_string);
+
+// Frees a uuid structure created from |uuid_new| and friends.
+// |uuid| may be NULL.
+void uuid_free(bt_uuid_t* uuid);
+
+// Returns true if the UUID is all zeros, false otherwise.
+// |uuid| may not be NULL.
+bool uuid_is_empty(const bt_uuid_t* uuid);
+
+// Returns true if the two UUIDs are equal, false otherwise.
+// |first| and |second| may not be NULL.
+bool uuid_is_equal(const bt_uuid_t* first, const bt_uuid_t* second);
+
+// Copies uuid |src| into |dest| and returns a pointer to |dest|.
+// |src| and |dest| must not be NULL.
+bt_uuid_t* uuid_copy(bt_uuid_t* dest, const bt_uuid_t* src);
+
+// Converts contents of |uuid| to a well formed UUID string
+// |uuid_string| using numbers and lower case letter. |uuid|
+// and |uuid_string| must not be NULL.
+void uuid_to_string(const bt_uuid_t* uuid, uuid_string_t* uuid_string);
+
+// Converts contents of |uuid| to a short uuid if possible. Returns
+// true if conversion is possible, false otherwise.
+// |uuid|, |uuid16| and |uuid32| must not be NULL.
+bool uuid_128_to_16(const bt_uuid_t* uuid, uint16_t* uuid16);
+bool uuid_128_to_32(const bt_uuid_t* uuid, uint32_t* uuid32);
diff --git a/mtkbt/code/bt/btcore/include/version.h b/mtkbt/code/bt/btcore/include/version.h
new file mode 100755
index 0000000..a0696ad
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/include/version.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+typedef struct {
+ uint8_t hci_version;
+ uint16_t hci_revision;
+ uint8_t lmp_version;
+ uint16_t manufacturer;
+ uint16_t lmp_subversion;
+} bt_version_t;
diff --git a/mtkbt/code/bt/btcore/src/bdaddr.cc b/mtkbt/code/bt/btcore/src/bdaddr.cc
new file mode 100755
index 0000000..c0fb2f0
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/bdaddr.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "btcore/include/bdaddr.h"
+
+bool bdaddr_is_empty(const bt_bdaddr_t* addr) {
+ CHECK(addr != NULL);
+
+ uint8_t zero[sizeof(bt_bdaddr_t)] = {0};
+ return memcmp(addr, &zero, sizeof(bt_bdaddr_t)) == 0;
+}
+
+bool bdaddr_equals(const bt_bdaddr_t* first, const bt_bdaddr_t* second) {
+ CHECK(first != NULL);
+ CHECK(second != NULL);
+
+ return memcmp(first, second, sizeof(bt_bdaddr_t)) == 0;
+}
+
+bt_bdaddr_t* bdaddr_copy(bt_bdaddr_t* dest, const bt_bdaddr_t* src) {
+ CHECK(dest != NULL);
+ CHECK(src != NULL);
+
+ return (bt_bdaddr_t*)memcpy(dest, src, sizeof(bt_bdaddr_t));
+}
+
+const char* bdaddr_to_string(const bt_bdaddr_t* addr, char* string,
+ size_t size) {
+ CHECK(addr != NULL);
+ CHECK(string != NULL);
+
+ if (size < 18) return NULL;
+
+ const uint8_t* ptr = addr->address;
+ snprintf(string, size, "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1],
+ ptr[2], ptr[3], ptr[4], ptr[5]);
+ return string;
+}
+
+bool string_is_bdaddr(const char* string) {
+ CHECK(string != NULL);
+
+ size_t len = strlen(string);
+ if (len != 17) return false;
+
+ for (size_t i = 0; i < len; ++i) {
+ // Every 3rd char must be ':'.
+ if (((i + 1) % 3) == 0 && string[i] != ':') return false;
+
+ // All other chars must be a hex digit.
+ if (((i + 1) % 3) != 0 && !isxdigit(string[i])) return false;
+ }
+ return true;
+}
+
+bool string_to_bdaddr(const char* string, bt_bdaddr_t* addr) {
+ CHECK(string != NULL);
+ CHECK(addr != NULL);
+
+ bt_bdaddr_t new_addr;
+ uint8_t* ptr = new_addr.address;
+ bool ret = sscanf(string, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &ptr[0], &ptr[1], &ptr[2], &ptr[3], &ptr[4], &ptr[5]) == 6;
+
+ if (ret) memcpy(addr, &new_addr, sizeof(bt_bdaddr_t));
+
+ return ret;
+}
diff --git a/mtkbt/code/bt/btcore/src/device_class.cc b/mtkbt/code/bt/btcore/src/device_class.cc
new file mode 100755
index 0000000..d421b6d
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/device_class.cc
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <base/logging.h>
+#include <string.h>
+
+#include "btcore/include/device_class.h"
+#include "osi/include/osi.h"
+
+typedef struct _bt_device_class_t {
+ uint32_t unused : 2; // LSBs
+ uint32_t minor_device : 6;
+ uint32_t major_device : 5;
+ uint32_t major_service : 11; // MSBs
+} __attribute__((__packed__)) _bt_device_class_t;
+
+// Convenience to interpret raw device class bytes.
+#define DC(x) ((_bt_device_class_t*)(x))
+
+// Ensure the internal device class implementation and public one
+// have equal size.
+COMPILE_ASSERT(sizeof(_bt_device_class_t) == sizeof(bt_device_class_t));
+
+// [Major Service Classes]
+// (https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband)
+enum {
+ DC_LIMITED_DISCOVERABLE_MODE = 0x0001,
+ DC_RESERVED14 = 0x0002,
+ DC_RESERVED15 = 0x0004,
+ DC_POSITIONING = 0x0008,
+ DC_NETWORKING = 0x0010,
+ DC_RENDERING = 0x0020,
+ DC_CAPTURING = 0x0040,
+ DC_OBJECT_TRANSFER = 0x0080,
+ DC_AUDIO = 0x0100,
+ DC_TELEPHONY = 0x0200,
+ DC_INFORMATION = 0x0400,
+};
+
+static bool device_class_get_major_service_(const bt_device_class_t* dc,
+ int bitmask);
+static void device_class_clr_major_service_(bt_device_class_t* dc, int bitmask);
+static void device_class_set_major_service_(bt_device_class_t* dc, int bitmask);
+
+void device_class_from_stream(bt_device_class_t* dc, const uint8_t* data) {
+ CHECK(dc != NULL);
+ CHECK(data != NULL);
+ *dc = *(bt_device_class_t*)data;
+}
+
+int device_class_to_stream(const bt_device_class_t* dc, uint8_t* data,
+ size_t len) {
+ CHECK(dc != NULL);
+ CHECK(data != NULL);
+ CHECK(len >= sizeof(bt_device_class_t));
+ for (size_t i = 0; i < sizeof(bt_device_class_t); ++i) {
+ data[i] = dc->_[i];
+ }
+ return sizeof(bt_device_class_t);
+}
+
+void device_class_from_int(bt_device_class_t* dc, int data) {
+ CHECK(dc != NULL);
+ CHECK(data != 0);
+ // Careful with endianess.
+ dc->_[0] = data & 0xff;
+ dc->_[1] = (data >> 8) & 0xff;
+ dc->_[2] = (data >> 16) & 0xff;
+}
+
+int device_class_to_int(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ // Careful with endianess.
+ return (int)(le32toh(*(int*)dc) & 0xffffff);
+}
+
+bool device_class_equals(const bt_device_class_t* p1,
+ const bt_device_class_t* p2) {
+ CHECK(p1 != NULL);
+ CHECK(p2 != NULL);
+ return (memcmp(p1, p2, sizeof(bt_device_class_t)) == 0);
+}
+
+bool device_class_copy(bt_device_class_t* dest, const bt_device_class_t* src) {
+ CHECK(dest != NULL);
+ CHECK(src != NULL);
+ return (memcpy(dest, src, sizeof(bt_device_class_t)) == dest);
+}
+
+int device_class_get_major_device(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ return DC(dc)->major_device;
+}
+
+void device_class_set_major_device(bt_device_class_t* dc, int val) {
+ CHECK(dc != NULL);
+ DC(dc)->major_device = val;
+}
+
+int device_class_get_minor_device(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ return DC(dc)->minor_device;
+}
+
+void device_class_set_minor_device(bt_device_class_t* dc, int val) {
+ CHECK(dc != NULL);
+ DC(dc)->minor_device = val;
+}
+
+bool device_class_get_information(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ return device_class_get_major_service_(dc, DC_INFORMATION);
+}
+
+void device_class_set_information(bt_device_class_t* dc, bool set) {
+ CHECK(dc != NULL);
+ if (set)
+ device_class_set_major_service_(dc, DC_INFORMATION);
+ else
+ device_class_clr_major_service_(dc, DC_INFORMATION);
+}
+
+bool device_class_get_limited(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ return device_class_get_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+}
+
+void device_class_set_limited(bt_device_class_t* dc, bool set) {
+ CHECK(dc != NULL);
+ if (set)
+ device_class_set_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+ else
+ device_class_clr_major_service_(dc, DC_LIMITED_DISCOVERABLE_MODE);
+}
+
+static bool device_class_get_major_service_(const bt_device_class_t* dc,
+ int bitmask) {
+ return (DC(dc)->major_service & bitmask);
+}
+
+static void device_class_clr_major_service_(bt_device_class_t* dc,
+ int bitmask) {
+ DC(dc)->major_service &= ~bitmask;
+}
+
+static void device_class_set_major_service_(bt_device_class_t* dc,
+ int bitmask) {
+ DC(dc)->major_service |= bitmask;
+}
diff --git a/mtkbt/code/bt/btcore/src/hal_util.cc b/mtkbt/code/bt/btcore/src/hal_util.cc
new file mode 100755
index 0000000..21be613
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/hal_util.cc
@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "hal_util"
+
+#include <hardware/bluetooth.h>
+#include <hardware/hardware.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include "btcore/include/hal_util.h"
+#include "osi/include/log.h"
+
+#if defined(OS_GENERIC)
+
+// TODO(armansito): All logging macros should include __func__ by default (see
+// Bug: 22671731)
+#define HULOGERR(fmt, args...) \
+ LOG_ERROR(LOG_TAG, "[%s] failed to load the Bluetooth library: " fmt, \
+ __func__, ##args)
+
+// TODO(armansito): It might be better to pass the library name in a more
+// generic manner as opposed to hard-coding it here.
+static const char kBluetoothLibraryName[] = "libbluetooth.default.so";
+
+static int load_bt_library(const struct hw_module_t** module) {
+ const char* id = BT_STACK_MODULE_ID;
+ const char* sym = HAL_MODULE_INFO_SYM_AS_STR;
+ struct hw_module_t* hmi = nullptr;
+
+ // Always try to load the default Bluetooth stack on GN builds.
+ void* handle = dlopen(kBluetoothLibraryName, RTLD_NOW);
+ if (!handle) {
+ char const* err_str = dlerror();
+ HULOGERR("%s", err_str ? err_str : "error unknown");
+ goto error;
+ }
+
+ // Get the address of the struct hal_module_info.
+ hmi = (struct hw_module_t*)dlsym(handle, sym);
+ if (!hmi) {
+ HULOGERR("%s", sym);
+ goto error;
+ }
+
+ // Check that the id matches.
+ if (strcmp(id, hmi->id) != 0) {
+ HULOGERR("id=%s does not match HAL module ID: %s", id, hmi->id);
+ goto error;
+ }
+
+ hmi->dso = handle;
+
+ // Success.
+ LOG_INFO(LOG_TAG, "[%s] loaded HAL id=%s path=%s hmi=%p handle=%p", __func__,
+ id, kBluetoothLibraryName, hmi, handle);
+
+ *module = hmi;
+ return 0;
+
+error:
+ *module = NULL;
+ if (handle) dlclose(handle);
+
+ return -EINVAL;
+}
+
+#endif // defined(OS_GENERIC)
+
+int hal_util_load_bt_library(const struct hw_module_t** module) {
+#if defined(OS_GENERIC)
+ return load_bt_library(module);
+#else // !defined(OS_GENERIC)
+ return hw_get_module(BT_STACK_MODULE_ID, module);
+#endif // defined(OS_GENERIC)
+}
diff --git a/mtkbt/code/bt/btcore/src/module.cc b/mtkbt/code/bt/btcore/src/module.cc
new file mode 100755
index 0000000..1a0674a
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/module.cc
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_core_module"
+
+#include <base/logging.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include <mutex>
+#include <unordered_map>
+
+#include "btcore/include/module.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+typedef enum {
+ MODULE_STATE_NONE = 0,
+ MODULE_STATE_INITIALIZED = 1,
+ MODULE_STATE_STARTED = 2
+} module_state_t;
+
+static std::unordered_map<const module_t*, module_state_t> metadata;
+
+// TODO(jamuraa): remove this lock after the startup sequence is clean
+static std::mutex metadata_mutex;
+
+static bool call_lifecycle_function(module_lifecycle_fn function);
+static module_state_t get_module_state(const module_t* module);
+static void set_module_state(const module_t* module, module_state_t state);
+
+void module_management_start(void) {}
+
+void module_management_stop(void) {
+ metadata.clear();
+}
+
+const module_t* get_module(const char* name) {
+ module_t* module = (module_t*)dlsym(RTLD_DEFAULT, name);
+ CHECK(module);
+ return module;
+}
+
+bool module_init(const module_t* module) {
+ CHECK(module != NULL);
+ CHECK(get_module_state(module) == MODULE_STATE_NONE);
+
+ if (!call_lifecycle_function(module->init)) {
+ LOG_ERROR(LOG_TAG, "%s Failed to initialize module \"%s\"", __func__,
+ module->name);
+ return false;
+ }
+
+ set_module_state(module, MODULE_STATE_INITIALIZED);
+ return true;
+}
+
+bool module_start_up(const module_t* module) {
+ CHECK(module != NULL);
+ // TODO(zachoverflow): remove module->init check once automagic order/call is
+ // in place.
+ // This hack is here so modules which don't require init don't have to have
+ // useless calls
+ // as we're converting the startup sequence.
+ CHECK(get_module_state(module) == MODULE_STATE_INITIALIZED ||
+ module->init == NULL);
+
+ LOG_INFO(LOG_TAG, "%s Starting module \"%s\"", __func__, module->name);
+ if (!call_lifecycle_function(module->start_up)) {
+ LOG_ERROR(LOG_TAG, "%s Failed to start up module \"%s\"", __func__,
+ module->name);
+ return false;
+ }
+ LOG_INFO(LOG_TAG, "%s Started module \"%s\"", __func__, module->name);
+
+ set_module_state(module, MODULE_STATE_STARTED);
+ return true;
+}
+
+void module_shut_down(const module_t* module) {
+ CHECK(module != NULL);
+ module_state_t state = get_module_state(module);
+ CHECK(state <= MODULE_STATE_STARTED);
+
+ // Only something to do if the module was actually started
+ if (state < MODULE_STATE_STARTED) return;
+
+ LOG_INFO(LOG_TAG, "%s Shutting down module \"%s\"", __func__, module->name);
+ if (!call_lifecycle_function(module->shut_down)) {
+ LOG_ERROR(LOG_TAG,
+ "%s Failed to shutdown module \"%s\". Continuing anyway.",
+ __func__, module->name);
+ }
+ LOG_INFO(LOG_TAG, "%s Shutdown of module \"%s\" completed", __func__,
+ module->name);
+
+ set_module_state(module, MODULE_STATE_INITIALIZED);
+}
+
+void module_clean_up(const module_t* module) {
+ CHECK(module != NULL);
+ module_state_t state = get_module_state(module);
+ CHECK(state <= MODULE_STATE_INITIALIZED);
+
+ // Only something to do if the module was actually initialized
+ if (state < MODULE_STATE_INITIALIZED) return;
+
+ LOG_INFO(LOG_TAG, "%s Cleaning up module \"%s\"", __func__, module->name);
+ if (!call_lifecycle_function(module->clean_up)) {
+ LOG_ERROR(LOG_TAG, "%s Failed to cleanup module \"%s\". Continuing anyway.",
+ __func__, module->name);
+ }
+ LOG_INFO(LOG_TAG, "%s Cleanup of module \"%s\" completed", __func__,
+ module->name);
+
+ set_module_state(module, MODULE_STATE_NONE);
+}
+
+static bool call_lifecycle_function(module_lifecycle_fn function) {
+ // A NULL lifecycle function means it isn't needed, so assume success
+ if (!function) return true;
+
+ future_t* future = function();
+
+ // A NULL future means synchronous success
+ if (!future) return true;
+
+ // Otherwise fall back to the future
+ return future_await(future);
+}
+
+static module_state_t get_module_state(const module_t* module) {
+ std::lock_guard<std::mutex> lock(metadata_mutex);
+ auto map_ptr = metadata.find(module);
+
+ return (map_ptr != metadata.end()) ? map_ptr->second : MODULE_STATE_NONE;
+}
+
+static void set_module_state(const module_t* module, module_state_t state) {
+ std::lock_guard<std::mutex> lock(metadata_mutex);
+ metadata[module] = state;
+}
+
+// TODO(zachoverflow): remove when everything modulized
+// Temporary callback-wrapper-related code
+
+typedef struct {
+ const module_t* module;
+ thread_t* lifecycle_thread;
+ thread_t* callback_thread; // we don't own this thread
+ thread_fn callback;
+ bool success;
+} callbacked_wrapper_t;
+
+static void run_wrapped_start_up(void* context);
+static void post_result_to_callback(void* context);
+
+void module_start_up_callbacked_wrapper(const module_t* module,
+ thread_t* callback_thread,
+ thread_fn callback) {
+ callbacked_wrapper_t* wrapper =
+ (callbacked_wrapper_t*)osi_calloc(sizeof(callbacked_wrapper_t));
+
+ wrapper->module = module;
+ wrapper->lifecycle_thread = thread_new("module_wrapper");
+ wrapper->callback_thread = callback_thread;
+ wrapper->callback = callback;
+
+ // Run the actual module start up
+ thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper);
+}
+
+static void run_wrapped_start_up(void* context) {
+ CHECK(context);
+
+ callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
+ wrapper->success = module_start_up(wrapper->module);
+
+ // Post the result back to the callback
+ thread_post(wrapper->callback_thread, post_result_to_callback, wrapper);
+}
+
+static void post_result_to_callback(void* context) {
+ CHECK(context);
+
+ callbacked_wrapper_t* wrapper = (callbacked_wrapper_t*)context;
+
+ // Save the values we need for callback
+ void* result = wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL;
+ thread_fn callback = wrapper->callback;
+
+ // Clean up the resources we used
+ thread_free(wrapper->lifecycle_thread);
+ osi_free(wrapper);
+
+ callback(result);
+}
diff --git a/mtkbt/code/bt/btcore/src/osi_module.cc b/mtkbt/code/bt/btcore/src/osi_module.cc
new file mode 100755
index 0000000..1938d3f
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/osi_module.cc
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_module"
+
+#include "btcore/include/osi_module.h"
+#include "btcore/include/module.h"
+#include "osi/include/alarm.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/wakelock.h"
+
+future_t* osi_init(void) {
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+future_t* osi_clean_up(void) {
+ alarm_cleanup();
+ wakelock_cleanup();
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t osi_module = {.name = OSI_MODULE,
+ .init = osi_init,
+ .start_up = NULL,
+ .shut_down = NULL,
+ .clean_up = osi_clean_up,
+ .dependencies = {NULL}};
diff --git a/mtkbt/code/bt/btcore/src/property.cc b/mtkbt/code/bt/btcore/src/property.cc
new file mode 100755
index 0000000..2049131
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/property.cc
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "btcore/include/property.h"
+#include <base/logging.h>
+#include <string.h>
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/device_class.h"
+#include "btcore/include/uuid.h"
+#include "osi/include/allocator.h"
+
+static bt_property_t* property_new_(void* val, size_t len,
+ bt_property_type_t type);
+
+bt_property_t* property_copy_array(const bt_property_t* properties,
+ size_t count) {
+ CHECK(properties != NULL);
+ bt_property_t* clone =
+ static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t) * count));
+
+ memcpy(&clone[0], &properties[0], sizeof(bt_property_t) * count);
+ for (size_t i = 0; i < count; ++i) {
+ clone[i].val = osi_calloc(clone[i].len);
+ memcpy(clone[i].val, properties[i].val, clone[i].len);
+ }
+
+ return clone;
+}
+
+bt_property_t* property_copy(bt_property_t* dest, const bt_property_t* src) {
+ CHECK(dest != NULL);
+ CHECK(src != NULL);
+ return (bt_property_t*)memcpy(dest, src, sizeof(bt_property_t));
+}
+
+bool property_equals(const bt_property_t* p1, const bt_property_t* p2) {
+ // Two null properties are not the same. May need to revisit that
+ // decision when we have a test case that exercises that condition.
+ if (!p1 || !p2 || p1->type != p2->type) {
+ return false;
+ }
+
+ // Although the Bluetooth name is a 249-byte array, the implementation
+ // treats it like a variable-length array with its size specified in the
+ // property's `len` field. We special-case the equivalence of BDNAME
+ // types here by truncating the larger, zero-padded name to its string
+ // length and comparing against the shorter name.
+ //
+ // Note: it may be the case that both strings are zero-padded but that
+ // hasn't come up yet so this implementation doesn't handle it.
+ if (p1->type == BT_PROPERTY_BDNAME && p1->len != p2->len) {
+ const bt_property_t *shorter = p1, *longer = p2;
+ if (p1->len > p2->len) {
+ shorter = p2;
+ longer = p1;
+ }
+ return strlen((const char*)longer->val) == (size_t)shorter->len &&
+ !memcmp(longer->val, shorter->val, shorter->len);
+ }
+
+ return p1->len == p2->len && !memcmp(p1->val, p2->val, p1->len);
+}
+
+bt_property_t* property_new_addr(const bt_bdaddr_t* addr) {
+ CHECK(addr != NULL);
+ return property_new_((void*)addr, sizeof(bt_bdaddr_t), BT_PROPERTY_BDADDR);
+}
+
+bt_property_t* property_new_device_class(const bt_device_class_t* dc) {
+ CHECK(dc != NULL);
+ return property_new_((void*)dc, sizeof(bt_device_class_t),
+ BT_PROPERTY_CLASS_OF_DEVICE);
+}
+
+bt_property_t* property_new_device_type(bt_device_type_t type) {
+ return property_new_((void*)&type, sizeof(bt_device_type_t),
+ BT_PROPERTY_TYPE_OF_DEVICE);
+}
+
+bt_property_t* property_new_discovery_timeout(const uint32_t timeout) {
+ return property_new_((void*)&timeout, sizeof(uint32_t),
+ BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT);
+}
+
+bt_property_t* property_new_name(const char* name) {
+ CHECK(name != NULL);
+ return property_new_((void*)name, sizeof(bt_bdname_t), BT_PROPERTY_BDNAME);
+}
+
+bt_property_t* property_new_rssi(int8_t rssi) {
+ return property_new_((void*)&rssi, sizeof(int8_t), BT_PROPERTY_REMOTE_RSSI);
+}
+
+bt_property_t* property_new_scan_mode(bt_scan_mode_t scan_mode) {
+ return property_new_((void*)&scan_mode, sizeof(bt_scan_mode_t),
+ BT_PROPERTY_ADAPTER_SCAN_MODE);
+}
+
+bt_property_t* property_new_uuids(const bt_uuid_t* uuid, size_t count) {
+ CHECK(uuid != NULL);
+ return property_new_((void*)uuid, sizeof(bt_uuid_t) * count,
+ BT_PROPERTY_UUIDS);
+}
+
+void property_free(bt_property_t* property) {
+ property_free_array(property, 1);
+}
+
+void property_free_array(bt_property_t* properties, size_t count) {
+ if (properties == NULL) return;
+
+ for (size_t i = 0; i < count; ++i) {
+ osi_free(properties[i].val);
+ }
+
+ osi_free(properties);
+}
+
+bool property_is_addr(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_BDADDR;
+}
+
+bool property_is_device_class(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_CLASS_OF_DEVICE;
+}
+
+bool property_is_device_type(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_TYPE_OF_DEVICE;
+}
+
+bool property_is_discovery_timeout(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
+}
+
+bool property_is_name(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_BDNAME;
+}
+
+bool property_is_rssi(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_REMOTE_RSSI;
+}
+
+bool property_is_scan_mode(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_ADAPTER_SCAN_MODE;
+}
+
+bool property_is_uuids(const bt_property_t* property) {
+ CHECK(property != NULL);
+ return property->type == BT_PROPERTY_UUIDS;
+}
+
+// Convenience conversion methods to property values
+const bt_bdaddr_t* property_as_addr(const bt_property_t* property) {
+ CHECK(property_is_addr(property));
+ return (const bt_bdaddr_t*)property->val;
+}
+
+const bt_device_class_t* property_as_device_class(
+ const bt_property_t* property) {
+ CHECK(property_is_device_class(property));
+ return (const bt_device_class_t*)property->val;
+}
+
+bt_device_type_t property_as_device_type(const bt_property_t* property) {
+ CHECK(property_is_device_type(property));
+ return *(const bt_device_type_t*)property->val;
+}
+
+uint32_t property_as_discovery_timeout(const bt_property_t* property) {
+ CHECK(property_is_discovery_timeout(property));
+ return *(const uint32_t*)property->val;
+}
+
+const bt_bdname_t* property_as_name(const bt_property_t* property) {
+ CHECK(property_is_name(property));
+ return (const bt_bdname_t*)property->val;
+}
+
+int8_t property_as_rssi(const bt_property_t* property) {
+ CHECK(property_is_rssi(property));
+ return *(const int8_t*)property->val;
+}
+
+bt_scan_mode_t property_as_scan_mode(const bt_property_t* property) {
+ CHECK(property_is_scan_mode(property));
+ return *(const bt_scan_mode_t*)property->val;
+}
+
+const bt_uuid_t* property_as_uuids(const bt_property_t* property,
+ size_t* count) {
+ CHECK(property_is_uuids(property));
+ *count = sizeof(bt_uuid_t) / property->len;
+ return (const bt_uuid_t*)property->val;
+}
+
+static bt_property_t* property_new_(void* val, size_t len,
+ bt_property_type_t type) {
+ bt_property_t* property =
+ static_cast<bt_property_t*>(osi_calloc(sizeof(bt_property_t)));
+
+ property->val = osi_malloc(len);
+ memcpy(property->val, val, len);
+
+ property->type = type;
+ property->len = len;
+
+ return property;
+}
diff --git a/mtkbt/code/bt/btcore/src/uuid.cc b/mtkbt/code/bt/btcore/src/uuid.cc
new file mode 100755
index 0000000..9985fe6
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/src/uuid.cc
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "btcore/include/uuid.h"
+#include "osi/include/allocator.h"
+
+static const size_t UUID_WELL_FORMED_STRING_LEN = 36;
+static const size_t UUID_WELL_FORMED_STRING_LEN_WITH_NULL = 36 + 1;
+
+typedef struct uuid_string_t { char string[0]; } uuid_string_t;
+
+static const bt_uuid_t empty_uuid = {{0}};
+
+// The base UUID is used for calculating 128-bit UUIDs from 16 and
+// 32 bit UUIDs as described in the SDP specification.
+static const bt_uuid_t base_uuid = {{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5f, 0x9b, 0x34, 0xfb,
+}};
+
+static bool uuid_is_base(const bt_uuid_t* uuid);
+
+uuid_string_t* uuid_string_new(void) {
+ return static_cast<uuid_string_t*>(
+ osi_calloc(UUID_WELL_FORMED_STRING_LEN_WITH_NULL));
+}
+
+void uuid_string_free(uuid_string_t* uuid_string) { osi_free(uuid_string); }
+
+const char* uuid_string_data(const uuid_string_t* uuid_string) {
+ CHECK(uuid_string != NULL);
+ return (const char*)uuid_string->string;
+}
+
+bt_uuid_t* uuid_new(const char* uuid_string) {
+ CHECK(uuid_string != NULL);
+
+ if (strlen(uuid_string) < UUID_WELL_FORMED_STRING_LEN) return NULL;
+ if (uuid_string[8] != '-' || uuid_string[13] != '-' ||
+ uuid_string[18] != '-' || uuid_string[23] != '-')
+ return NULL;
+
+ bt_uuid_t* uuid = static_cast<bt_uuid_t*>(osi_calloc(sizeof(bt_uuid_t)));
+
+ const char* s = uuid_string;
+ for (size_t i = 0; i < sizeof(bt_uuid_t); ++i, s += 2) {
+ char buf[3] = {0};
+ buf[0] = s[0];
+ buf[1] = s[1];
+ uuid->uu[i] = strtoul(buf, NULL, 16);
+ // Adjust by skipping the dashes
+ switch (i) {
+ case 3:
+ case 5:
+ case 7:
+ case 9:
+ s++;
+ break;
+ }
+ }
+ return uuid;
+}
+
+void uuid_free(bt_uuid_t* uuid) { osi_free(uuid); }
+
+bool uuid_is_empty(const bt_uuid_t* uuid) {
+ return !uuid || !memcmp(uuid, &empty_uuid, sizeof(bt_uuid_t));
+}
+
+bool uuid_is_equal(const bt_uuid_t* first, const bt_uuid_t* second) {
+ CHECK(first != NULL);
+ CHECK(second != NULL);
+ return !memcmp(first, second, sizeof(bt_uuid_t));
+}
+
+bt_uuid_t* uuid_copy(bt_uuid_t* dest, const bt_uuid_t* src) {
+ CHECK(dest != NULL);
+ CHECK(src != NULL);
+ return (bt_uuid_t*)memcpy(dest, src, sizeof(bt_uuid_t));
+}
+
+bool uuid_128_to_16(const bt_uuid_t* uuid, uint16_t* uuid16) {
+ CHECK(uuid != NULL);
+ CHECK(uuid16 != NULL);
+
+ if (!uuid_is_base(uuid)) return false;
+
+ *uuid16 = (uuid->uu[2] << 8) + uuid->uu[3];
+ return true;
+}
+
+bool uuid_128_to_32(const bt_uuid_t* uuid, uint32_t* uuid32) {
+ CHECK(uuid != NULL);
+ CHECK(uuid32 != NULL);
+
+ if (!uuid_is_base(uuid)) return false;
+
+ *uuid32 = (uuid->uu[0] << 24) + (uuid->uu[1] << 16) + (uuid->uu[2] << 8) +
+ uuid->uu[3];
+ return true;
+}
+
+void uuid_to_string(const bt_uuid_t* uuid, uuid_string_t* uuid_string) {
+ CHECK(uuid != NULL);
+ CHECK(uuid_string != NULL);
+
+ char* string = uuid_string->string;
+ char* end = string + UUID_WELL_FORMED_STRING_LEN_WITH_NULL;
+
+ // XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
+ for (int i = 0; i < 4; i++) {
+ string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+ }
+ *string = '-';
+ ++string;
+ for (int i = 4; i < 6; i++) {
+ string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+ }
+ *string = '-';
+ ++string;
+ for (int i = 6; i < 8; i++) {
+ string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+ }
+ *string = '-';
+ ++string;
+ for (int i = 8; i < 10; i++) {
+ string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+ }
+ *string = '-';
+ ++string;
+ for (int i = 10; i < 16; i++) {
+ string += snprintf(string, end - string, "%02x", uuid->uu[i]);
+ }
+}
+
+static bool uuid_is_base(const bt_uuid_t* uuid) {
+ if (!uuid) return false;
+
+ for (int i = 4; i < 16; i++) {
+ if (uuid->uu[i] != base_uuid.uu[i]) return false;
+ }
+ return true;
+}
diff --git a/mtkbt/code/bt/btcore/test/bdaddr_test.cc b/mtkbt/code/bt/btcore/test/bdaddr_test.cc
new file mode 100755
index 0000000..573a09b
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/test/bdaddr_test.cc
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "btcore/include/bdaddr.h"
+
+static const char* test_addr = "12:34:56:78:9a:bc";
+static const char* test_addr2 = "cb:a9:87:65:43:21";
+
+TEST(BdaddrTest, test_empty) {
+ bt_bdaddr_t empty;
+ string_to_bdaddr("00:00:00:00:00:00", &empty);
+ ASSERT_TRUE(bdaddr_is_empty(&empty));
+
+ bt_bdaddr_t not_empty;
+ string_to_bdaddr("00:00:00:00:00:01", &not_empty);
+ ASSERT_FALSE(bdaddr_is_empty(&not_empty));
+}
+
+TEST(BdaddrTest, test_to_from_str) {
+ char ret[19];
+ bt_bdaddr_t bdaddr;
+ string_to_bdaddr(test_addr, &bdaddr);
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ bdaddr_to_string(&bdaddr, ret, sizeof(ret));
+
+ ASSERT_STREQ(test_addr, ret);
+}
+
+TEST(BdaddrTest, test_equals) {
+ bt_bdaddr_t bdaddr1;
+ bt_bdaddr_t bdaddr2;
+ bt_bdaddr_t bdaddr3;
+ string_to_bdaddr(test_addr, &bdaddr1);
+ string_to_bdaddr(test_addr, &bdaddr2);
+ EXPECT_TRUE(bdaddr_equals(&bdaddr1, &bdaddr2));
+
+ string_to_bdaddr(test_addr2, &bdaddr3);
+ EXPECT_FALSE(bdaddr_equals(&bdaddr2, &bdaddr3));
+}
+
+TEST(BdaddrTest, test_copy) {
+ bt_bdaddr_t bdaddr1;
+ bt_bdaddr_t bdaddr2;
+ string_to_bdaddr(test_addr, &bdaddr1);
+ bdaddr_copy(&bdaddr2, &bdaddr1);
+
+ EXPECT_TRUE(bdaddr_equals(&bdaddr1, &bdaddr2));
+}
diff --git a/mtkbt/code/bt/btcore/test/device_class_test.cc b/mtkbt/code/bt/btcore/test/device_class_test.cc
new file mode 100755
index 0000000..434f9ca
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/test/device_class_test.cc
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+#include "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/device_class.h"
+
+// Device Class is 3 bytes.
+static const int DC_MASK = 0xffffff;
+
+::testing::AssertionResult check_bitfield(const char* m_expr,
+ const char* n_expr, int m, int n) {
+ if (m == n) return ::testing::AssertionSuccess();
+
+ std::stringstream ss;
+
+ ss.str("");
+ ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << m;
+ std::string expected_str = ss.str();
+
+ ss.str("");
+ ss << std::showbase << std::hex << std::setw(8) << std::setfill('0') << n;
+ std::string actual_str = ss.str();
+
+ return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " ( "
+ << expected_str << " vs " << actual_str
+ << " )";
+}
+
+class DeviceClassTest : public AllocationTestHarness {};
+
+TEST_F(DeviceClassTest, cod_sizeof) {
+ uint8_t dc_stream[] = {0x00, 0x00, 0x00, 0x00};
+ bt_device_class_t dc0;
+ device_class_from_stream(&dc0, dc_stream);
+ EXPECT_EQ((size_t)3, sizeof(dc0));
+}
+
+TEST_F(DeviceClassTest, simple) {
+ uint8_t dc_stream[][sizeof(bt_device_class_t)] = {
+ {0x00, 0x00, 0x00}, {0xff, 0xff, 0xff}, {0xaa, 0x55, 0xaa},
+ {0x01, 0x23, 0x45}, {0x20, 0x07, 0x14},
+ };
+
+ for (size_t i = 0; i < sizeof(dc_stream) / sizeof(bt_device_class_t); i++) {
+ bt_device_class_t dc;
+ device_class_from_stream(&dc, (uint8_t*)&dc_stream[i]);
+
+ uint8_t* to_stream = (uint8_t*)&dc;
+ EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][0],
+ to_stream[0]);
+ EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][1],
+ to_stream[1]);
+ EXPECT_PRED_FORMAT2(check_bitfield, (unsigned)dc_stream[i][2],
+ to_stream[2]);
+ }
+}
+
+TEST_F(DeviceClassTest, to_stream) {
+ {
+ bt_device_class_t dc;
+
+ uint8_t dc_stream0[] = {0x00, 0x00, 0x00, 0xaa};
+ device_class_from_stream(&dc, dc_stream0);
+
+ uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00};
+ int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+ EXPECT_EQ(3, rc);
+
+ uint32_t* val = (uint32_t*)&dc;
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, *val & 0xffffff);
+
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[0]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[1]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00, dc_stream1[2]);
+ }
+
+ {
+ uint8_t dc_stream0[] = {0xaa, 0x55, 0xaa, 0x55};
+ uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00};
+
+ bt_device_class_t dc;
+ device_class_from_stream(&dc, dc_stream0);
+
+ int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+ EXPECT_EQ(3, rc);
+ uint32_t* val = (uint32_t*)&dc;
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00aa55aa, *val & 0xffffff);
+
+ EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[0]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x55, dc_stream1[1]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0xaa, dc_stream1[2]);
+ }
+
+ {
+ uint8_t dc_stream0[] = {0x01, 0x23, 0x45, 0x67};
+ uint8_t dc_stream1[] = {0x00, 0x00, 0x00, 0x00};
+
+ bt_device_class_t dc;
+ device_class_from_stream(&dc, dc_stream0);
+
+ int rc = device_class_to_stream(&dc, dc_stream1, sizeof(dc_stream1));
+ EXPECT_EQ(3, rc);
+ uint32_t* val = (uint32_t*)&dc;
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x452301, *val & 0xffffff);
+
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x01, dc_stream1[0]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x23, dc_stream1[1]);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x45, dc_stream1[2]);
+ }
+}
+
+TEST_F(DeviceClassTest, limited_discoverable_mode) {
+ uint8_t dc_stream[] = {0x00, 0x00, 0x00};
+ bt_device_class_t dc;
+ device_class_from_stream(&dc, dc_stream);
+ uint32_t* test = (uint32_t*)&dc;
+
+ EXPECT_FALSE(device_class_get_limited(&dc));
+ EXPECT_EQ((unsigned)0x00000000, *test & DC_MASK);
+
+ device_class_set_limited(&dc, true);
+ EXPECT_TRUE(device_class_get_limited(&dc));
+ EXPECT_EQ((unsigned)0x00002000, *test & DC_MASK);
+
+ device_class_set_limited(&dc, false);
+ EXPECT_FALSE(device_class_get_limited(&dc));
+ EXPECT_EQ((unsigned)0x00000000, *test & DC_MASK);
+
+ device_class_set_limited(&dc, true);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00002000, *test & DC_MASK);
+
+ device_class_set_limited(&dc, false);
+ EXPECT_PRED_FORMAT2(check_bitfield, 0x00000000, *test & DC_MASK);
+}
+
+TEST_F(DeviceClassTest, equals) {
+ uint8_t dc_stream0[] = {0x00, 0x01, 0x02};
+ uint8_t dc_stream1[] = {0x00, 0x02, 0x03};
+
+ bt_device_class_t dc0;
+ device_class_from_stream(&dc0, dc_stream0);
+ bt_device_class_t dc1;
+ device_class_from_stream(&dc1, dc_stream1);
+ EXPECT_FALSE(device_class_equals(&dc0, &dc1));
+}
+
+TEST_F(DeviceClassTest, copy) {
+ uint8_t dc_stream0[] = {0xaa, 0x55, 0x33};
+ bt_device_class_t dc0;
+ device_class_from_stream(&dc0, dc_stream0);
+ bt_device_class_t dc1;
+ EXPECT_TRUE(device_class_copy(&dc1, &dc0));
+ EXPECT_TRUE(device_class_equals(&dc0, &dc1));
+}
+
+TEST_F(DeviceClassTest, from_int) {
+ bt_device_class_t dc1;
+ int cod1 = 0x5a020c; // 5898764
+ device_class_from_int(&dc1, cod1);
+
+ uint8_t dc_stream[] = {0x0c, 0x02, 0x5a};
+ bt_device_class_t dc2;
+ device_class_from_stream(&dc2, dc_stream);
+ EXPECT_TRUE(device_class_equals(&dc1, &dc2));
+}
+
+TEST_F(DeviceClassTest, to_int) {
+ bt_device_class_t dc1 = {{0x0c, 0x02, 0x5a}};
+ int cod1 = device_class_to_int(&dc1);
+
+ EXPECT_EQ(dc1._[0], 0x0c);
+ EXPECT_EQ(dc1._[1], 0x02);
+ EXPECT_EQ(dc1._[2], 0x5a);
+
+ bt_device_class_t dc2;
+ uint8_t dc_stream[] = {0x0c, 0x02, 0x5a};
+ device_class_from_stream(&dc2, dc_stream);
+
+ EXPECT_EQ(dc2._[0], 0x0c);
+ EXPECT_EQ(dc2._[1], 0x02);
+ EXPECT_EQ(dc2._[2], 0x5a);
+
+ int cod2 = device_class_to_int(&dc2);
+ EXPECT_EQ(cod1, cod2);
+ EXPECT_EQ(cod1, 0x5a020c); // 5898764
+}
+
+TEST_F(DeviceClassTest, endian) {
+ bt_device_class_t dc;
+ int cod1 = 0x200714; // 2098964
+ device_class_from_int(&dc, cod1);
+
+ EXPECT_EQ(dc._[0], 0x14);
+ EXPECT_EQ(dc._[1], 0x07);
+ EXPECT_EQ(dc._[2], 0x20);
+
+ int cod2 = device_class_to_int(&dc);
+ EXPECT_EQ(cod1, cod2);
+ EXPECT_EQ(cod2, 0x200714); // 2098964
+}
diff --git a/mtkbt/code/bt/btcore/test/property_test.cc b/mtkbt/code/bt/btcore/test/property_test.cc
new file mode 100755
index 0000000..fbf5f9a
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/test/property_test.cc
@@ -0,0 +1,238 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+#include "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/property.h"
+
+class PropertyTest : public AllocationTestHarness {};
+
+TEST_F(PropertyTest, addr) {
+ bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+ bt_property_t* property = property_new_addr(&addr0);
+
+ EXPECT_EQ(addr0.address[0], ((uint8_t*)property->val)[0]);
+ EXPECT_EQ(addr0.address[1], ((uint8_t*)property->val)[1]);
+ EXPECT_EQ(addr0.address[2], ((uint8_t*)property->val)[2]);
+ EXPECT_EQ(addr0.address[3], ((uint8_t*)property->val)[3]);
+ EXPECT_EQ(addr0.address[4], ((uint8_t*)property->val)[4]);
+ EXPECT_EQ(addr0.address[5], ((uint8_t*)property->val)[5]);
+ EXPECT_EQ(BT_PROPERTY_BDADDR, property->type);
+ EXPECT_EQ((int)sizeof(bt_bdaddr_t), property->len);
+
+ const bt_bdaddr_t* addr1 = property_as_addr(property);
+ EXPECT_EQ(addr0.address[0], addr1->address[0]);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, device_class) {
+ bt_device_class_t dc0 = {{0x01, 0x23, 0x45}};
+ bt_property_t* property = property_new_device_class(&dc0);
+
+ EXPECT_EQ(dc0._[0], ((uint8_t*)property->val)[0]);
+ EXPECT_EQ(dc0._[1], ((uint8_t*)property->val)[1]);
+ EXPECT_EQ(dc0._[2], ((uint8_t*)property->val)[2]);
+ EXPECT_EQ(BT_PROPERTY_CLASS_OF_DEVICE, property->type);
+ EXPECT_EQ((int)sizeof(bt_device_class_t), property->len);
+
+ const bt_device_class_t* dc1 = property_as_device_class(property);
+ int dc_int = device_class_to_int(dc1);
+ EXPECT_EQ(0x452301, dc_int);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, device_type) {
+ bt_device_type_t dt0 = (bt_device_type_t)1;
+ bt_property_t* property = property_new_device_type(dt0);
+
+ EXPECT_EQ((int)dt0, *(int*)property->val);
+ EXPECT_EQ(BT_PROPERTY_TYPE_OF_DEVICE, property->type);
+ EXPECT_EQ((int)sizeof(bt_device_type_t), property->len);
+
+ bt_device_type_t dt1 = property_as_device_type(property);
+ EXPECT_EQ(1, (int)dt1);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, discovery_timeout) {
+ uint32_t timeout0 = 12345;
+ bt_property_t* property = property_new_discovery_timeout(timeout0);
+
+ EXPECT_EQ(timeout0, *(uint32_t*)property->val);
+ EXPECT_EQ(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT, property->type);
+ EXPECT_EQ((int)sizeof(uint32_t), property->len);
+
+ uint32_t timeout1 = property_as_discovery_timeout(property);
+ EXPECT_EQ(timeout0, timeout1);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, name) {
+ const char* name0 = "My btcore name";
+ bt_property_t* property = property_new_name(name0);
+
+ EXPECT_EQ(0, strcmp((char*)name0, (char*)property->val));
+ EXPECT_EQ(BT_PROPERTY_BDNAME, property->type);
+ EXPECT_EQ((int)sizeof(bt_bdname_t), property->len);
+
+ const bt_bdname_t* name1 = property_as_name(property);
+ EXPECT_EQ(0, strcmp((char*)name0, (char*)name1->name));
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, rssi) {
+ int8_t rssi0 = -56;
+ bt_property_t* property = property_new_rssi(rssi0);
+
+ EXPECT_EQ(*(int8_t*)property->val, rssi0);
+ EXPECT_EQ(BT_PROPERTY_REMOTE_RSSI, property->type);
+ EXPECT_EQ((int)sizeof(int8_t), property->len);
+
+ int8_t rss1 = property_as_rssi(property);
+ EXPECT_EQ(rssi0, rss1);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, scan_mode) {
+ bt_scan_mode_t mode0 = (bt_scan_mode_t)3;
+ bt_property_t* property = property_new_scan_mode(mode0);
+
+ EXPECT_EQ(*(int*)property->val, mode0);
+ EXPECT_EQ(BT_PROPERTY_ADAPTER_SCAN_MODE, property->type);
+ EXPECT_EQ((int)sizeof(int), property->len);
+
+ bt_scan_mode_t mode1 = property_as_scan_mode(property);
+ EXPECT_EQ((int)mode0, (int)mode1);
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, uuids) {
+ bt_uuid_t uuid0 = {{
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+ 0xcc, 0xdd, 0xee, 0xff,
+ }};
+ bt_property_t* property = property_new_uuids(&uuid0, 1);
+
+ EXPECT_EQ(0, strcmp((const char*)uuid0.uu, (char*)property->val));
+ EXPECT_EQ(BT_PROPERTY_UUIDS, property->type);
+ EXPECT_EQ((int)sizeof(bt_uuid_t), property->len);
+
+ size_t uuid_cnt1;
+ const bt_uuid_t* uuid1 = property_as_uuids(property, &uuid_cnt1);
+ EXPECT_EQ(0, memcmp(uuid1->uu, uuid1->uu, sizeof(bt_uuid_t)));
+
+ property_free(property);
+}
+
+TEST_F(PropertyTest, copy) {
+ {
+ bt_uuid_t uuids[] = {
+ {{
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+ 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ }},
+ {{
+ 0xf0, 0xe1, 0xd2, 0xc3, 0xf4, 0xe5, 0xd6, 0xc7, 0xf8, 0xe9, 0xda,
+ 0xcb, 0xfc, 0xed, 0xde, 0xcf,
+ }},
+ };
+
+ bt_property_t* property0 =
+ property_new_uuids(uuids, sizeof(bt_uuid_t) / sizeof(uuids));
+
+ bt_property_t property1;
+ property_copy(&property1, property0);
+ EXPECT_TRUE(property_equals(property0, &property1));
+
+ property_free(property0);
+ }
+}
+
+TEST_F(PropertyTest, equals) {
+ {
+ bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+ bt_property_t* property0 = property_new_addr(&addr0);
+
+ bt_device_class_t dc0 = {{0x01, 0x23, 0x45}};
+ bt_property_t* property1 = property_new_device_class(&dc0);
+
+ EXPECT_FALSE(property_equals(property0, property1));
+
+ property_free(property0);
+ property_free(property1);
+ }
+
+ {
+ bt_bdaddr_t addr = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+ bt_property_t* property0 = property_new_addr(&addr);
+ bt_property_t* property1 = property_new_addr(&addr);
+
+ EXPECT_TRUE(property_equals(property0, property1));
+
+ property_free(property0);
+ property_free(property1);
+ }
+
+ {
+ bt_bdaddr_t addr0 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}};
+ bt_property_t* property0 = property_new_addr(&addr0);
+
+ bt_bdaddr_t addr1 = {{0x1, 0x2, 0x3, 0x4, 0x5, 0xff}};
+ bt_property_t* property1 = property_new_addr(&addr1);
+
+ EXPECT_FALSE(property_equals(property0, property1));
+
+ property_free(property0);
+ property_free(property1);
+ }
+
+ {
+ const char* name0 = "My btcore name";
+ bt_property_t* property0 = property_new_name(name0);
+
+ const char* name1 = "My btcore name";
+ bt_property_t* property1 = property_new_name(name1);
+
+ EXPECT_TRUE(property_equals(property0, property1));
+
+ property_free(property0);
+ property_free(property1);
+ }
+
+ {
+ const char* name0 = "My btcore name";
+ bt_property_t* property0 = property_new_name(name0);
+
+ const char* name1 = "My btcore name ";
+ bt_property_t* property1 = property_new_name(name1);
+
+ EXPECT_FALSE(property_equals(property0, property1));
+
+ property_free(property0);
+ property_free(property1);
+ }
+}
diff --git a/mtkbt/code/bt/btcore/test/uuid_test.cc b/mtkbt/code/bt/btcore/test/uuid_test.cc
new file mode 100755
index 0000000..e9a40ed
--- a/dev/null
+++ b/mtkbt/code/bt/btcore/test/uuid_test.cc
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+#include "osi/test/AllocationTestHarness.h"
+
+#include "btcore/include/uuid.h"
+
+static const char* UUID_EMPTY = "00000000-0000-0000-0000-000000000000";
+static const char* UUID_ONES = "11111111-1111-1111-1111-111111111111";
+static const char* UUID_SEQUENTIAL = "01234567-89ab-cdef-ABCD-EF0123456789";
+static const char* UUID_BASE = "00000000-0000-1000-8000-00805f9b34fb";
+
+class UuidTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() {}
+
+ virtual void TearDown() {}
+};
+
+TEST_F(UuidTest, new_from_string) {
+ bt_uuid_t* uuid;
+
+ uuid = uuid_new("incorrect length");
+ EXPECT_EQ(NULL, uuid);
+
+ uuid = uuid_new("correct length but missing dashes --");
+ EXPECT_EQ(NULL, uuid);
+
+ uuid = uuid_new(UUID_ONES);
+ ASSERT_TRUE(uuid != NULL);
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(0x11, uuid->uu[i]);
+ }
+ uuid_free(uuid);
+
+ uuid = uuid_new(UUID_SEQUENTIAL);
+ EXPECT_EQ(0x01, uuid->uu[0]);
+ EXPECT_EQ(0x23, uuid->uu[1]);
+ EXPECT_EQ(0x45, uuid->uu[2]);
+ EXPECT_EQ(0x67, uuid->uu[3]);
+ EXPECT_EQ(0x89, uuid->uu[4]);
+ EXPECT_EQ(0xAB, uuid->uu[5]);
+ EXPECT_EQ(0xCD, uuid->uu[6]);
+ EXPECT_EQ(0xEF, uuid->uu[7]);
+ EXPECT_EQ(0xab, uuid->uu[8]);
+ EXPECT_EQ(0xcd, uuid->uu[9]);
+ EXPECT_EQ(0xef, uuid->uu[10]);
+ EXPECT_EQ(0x01, uuid->uu[11]);
+ EXPECT_EQ(0x23, uuid->uu[12]);
+ EXPECT_EQ(0x45, uuid->uu[13]);
+ EXPECT_EQ(0x67, uuid->uu[14]);
+ EXPECT_EQ(0x89, uuid->uu[15]);
+ uuid_free(uuid);
+
+ uuid = uuid_new(UUID_BASE);
+ EXPECT_EQ(0x00, uuid->uu[0]);
+ EXPECT_EQ(0x00, uuid->uu[1]);
+ EXPECT_EQ(0x00, uuid->uu[2]);
+ EXPECT_EQ(0x00, uuid->uu[3]);
+ EXPECT_EQ(0x00, uuid->uu[4]);
+ EXPECT_EQ(0x00, uuid->uu[5]);
+ EXPECT_EQ(0x10, uuid->uu[6]);
+ EXPECT_EQ(0x00, uuid->uu[7]);
+ EXPECT_EQ(0x80, uuid->uu[8]);
+ EXPECT_EQ(0x00, uuid->uu[9]);
+ EXPECT_EQ(0x00, uuid->uu[10]);
+ EXPECT_EQ(0x80, uuid->uu[11]);
+ EXPECT_EQ(0x5f, uuid->uu[12]);
+ EXPECT_EQ(0x9b, uuid->uu[13]);
+ EXPECT_EQ(0x34, uuid->uu[14]);
+ EXPECT_EQ(0xfb, uuid->uu[15]);
+ uuid_free(uuid);
+}
+
+TEST_F(UuidTest, uuid_is_empty) {
+ bt_uuid_t* uuid = NULL;
+
+ uuid = uuid_new(UUID_EMPTY);
+ ASSERT_TRUE(uuid != NULL);
+ EXPECT_TRUE(uuid_is_empty(uuid));
+ uuid_free(uuid);
+
+ uuid = uuid_new(UUID_BASE);
+ ASSERT_TRUE(uuid != NULL);
+ EXPECT_FALSE(uuid_is_empty(uuid));
+ uuid_free(uuid);
+}
+
+TEST_F(UuidTest, uuid_128_to_16) {
+ bt_uuid_t* uuid = NULL;
+ uint16_t uuid16 = 0xffff;
+
+ uuid = uuid_new(UUID_ONES);
+ EXPECT_FALSE(uuid_128_to_16(uuid, &uuid16));
+ uuid_free(uuid);
+ EXPECT_EQ((uint16_t)0xffff, uuid16);
+
+ uuid = uuid_new(UUID_BASE);
+ EXPECT_TRUE(uuid_128_to_16(uuid, &uuid16));
+ uuid_free(uuid);
+ EXPECT_NE((uint16_t)0xffff, uuid16);
+ EXPECT_EQ((uint16_t)0, uuid16);
+}
+
+TEST_F(UuidTest, uuid_128_to_32) {
+ bt_uuid_t* uuid = NULL;
+ uint32_t uuid32 = 0xffffffff;
+
+ uuid = uuid_new(UUID_ONES);
+ EXPECT_FALSE(uuid_128_to_32(uuid, &uuid32));
+ uuid_free(uuid);
+ EXPECT_EQ((uint32_t)0xffffffff, uuid32);
+
+ uuid = uuid_new(UUID_BASE);
+ EXPECT_TRUE(uuid_128_to_32(uuid, &uuid32));
+ uuid_free(uuid);
+ EXPECT_NE((uint32_t)0xffffffff, uuid32);
+ EXPECT_EQ((uint32_t)0, uuid32);
+}
+
+TEST_F(UuidTest, uuid_to_string) {
+ bt_uuid_t* uuid = NULL;
+
+ uuid_string_t* uuid_string = uuid_string_new();
+ EXPECT_TRUE(uuid_string != NULL);
+
+ uuid = uuid_new(UUID_BASE);
+ EXPECT_TRUE(uuid != NULL);
+ uuid_to_string(uuid, uuid_string);
+ uuid_free(uuid);
+
+ EXPECT_TRUE(!strcmp(UUID_BASE, uuid_string_data(uuid_string)));
+
+ uuid = uuid_new(UUID_SEQUENTIAL);
+ EXPECT_TRUE(uuid != NULL);
+
+ uuid_to_string(uuid, uuid_string);
+ uuid_free(uuid);
+
+ char lower_case_buf[36 + 1];
+ for (int i = 0; i < 36 + 1; i++) {
+ lower_case_buf[i] = tolower(UUID_SEQUENTIAL[i]);
+ }
+ EXPECT_TRUE(!strcmp(lower_case_buf, uuid_string_data(uuid_string)));
+ uuid_string_free(uuid_string);
+}
diff --git a/mtkbt/code/bt/btif/Android.bp b/mtkbt/code/bt/btif/Android.bp
new file mode 100755
index 0000000..3c15cce
--- a/dev/null
+++ b/mtkbt/code/bt/btif/Android.bp
@@ -0,0 +1,123 @@
+// Common variables
+// ========================================================
+btifCommonIncludes = [
+ "external/aac/libAACdec/include",
+ "external/aac/libSYS/include",
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/bta/include",
+ "vendor/mediatek/limit_open/system/bt/bta/sys",
+ "vendor/mediatek/limit_open/system/bt/bta/dm",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/device/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ "vendor/mediatek/limit_open/system/bt/stack/l2cap",
+ "vendor/mediatek/limit_open/system/bt/stack/a2dp",
+ "vendor/mediatek/limit_open/system/bt/stack/btm",
+ "vendor/mediatek/limit_open/system/bt/stack/avdt",
+ "vendor/mediatek/limit_open/system/bt/udrv/include",
+ "vendor/mediatek/limit_open/system/bt/btif/include",
+ "vendor/mediatek/limit_open/system/bt/btif/co",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/vnd/include",
+ "vendor/mediatek/limit_open/system/bt/embdrv/sbc/encoder/include",
+ "vendor/mediatek/limit_open/system/bt/embdrv/sbc/decoder/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+]
+
+// libbtif static library for target
+// ========================================================
+cc_library_static {
+ name: "libbtif",
+ defaults: ["fluoride_defaults"],
+ include_dirs: btifCommonIncludes,
+ srcs: [
+ // HAL layer
+ "src/bluetooth.cc",
+ // BTIF implementation
+ "src/btif_a2dp.cc",
+ "src/btif_a2dp_control.cc",
+ "src/btif_a2dp_sink.cc",
+ "src/btif_a2dp_source.cc",
+ "src/btif_av.cc",
+ "src/btif_avrcp_audio_track.cc",
+ "src/btif_ble_advertiser.cc",
+ "src/btif_ble_scanner.cc",
+ "src/btif_config.cc",
+ "src/btif_config_transcode.cc",
+ "src/btif_core.cc",
+ "src/btif_debug.cc",
+ "src/btif_debug_btsnoop.cc",
+ "src/btif_debug_conn.cc",
+ "src/btif_dm.cc",
+ "src/btif_gatt.cc",
+ "src/btif_gatt_client.cc",
+ "src/btif_gatt_server.cc",
+ "src/btif_gatt_test.cc",
+ "src/btif_gatt_util.cc",
+ "src/btif_hf.cc",
+ "src/btif_hf_client.cc",
+ "src/btif_hh.cc",
+ "src/btif_hd.cc",
+ "src/btif_hl.cc",
+ "src/btif_mce.cc",
+ "src/btif_pan.cc",
+ "src/btif_profile_queue.cc",
+ "src/btif_rc.cc",
+ "src/btif_sdp.cc",
+ "src/btif_sdp_server.cc",
+ "src/btif_sm.cc",
+ "src/btif_sock.cc",
+ "src/btif_sock_rfc.cc",
+ "src/btif_sock_l2cap.cc",
+ "src/btif_sock_sco.cc",
+ "src/btif_sock_sdp.cc",
+ "src/btif_sock_thread.cc",
+ "src/btif_sock_util.cc",
+ "src/btif_storage.cc",
+ "src/btif_uid.cc",
+ "src/btif_util.cc",
+ "src/stack_manager.cc",
+ // Callouts
+ "co/bta_ag_co.cc",
+ "co/bta_dm_co.cc",
+ "co/bta_av_co.cc",
+ "co/bta_hh_co.cc",
+ "co/bta_hl_co.cc",
+ "co/bta_pan_co.cc",
+ "co/bta_gatts_co.cc",
+ ],
+ shared_libs: [
+ "libaudioclient",
+ "libcutils",
+ "liblog",
+ "libz",
+ "libtinyxml2",
+ ],
+ whole_static_libs: [
+ "libaudio-a2dp-hw-utils",
+ ],
+ cflags: ["-DBUILDCFG"],
+
+}
+
+// btif unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_btif",
+ defaults: ["fluoride_defaults"],
+ include_dirs: btifCommonIncludes,
+ srcs: ["test/btif_storage_test.cc"],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcutils",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libbtif",
+ "libbt-stack",
+ "libosi",
+ ],
+ cflags: ["-DBUILDCFG"],
+}
diff --git a/mtkbt/code/bt/btif/BUILD.gn b/mtkbt/code/bt/btif/BUILD.gn
new file mode 100755
index 0000000..6f29584
--- a/dev/null
+++ b/mtkbt/code/bt/btif/BUILD.gn
@@ -0,0 +1,102 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("btif") {
+ sources = [
+ "//audio_a2dp_hw/src/audio_a2dp_hw_utils.cc",
+ "src/btif_a2dp.cc",
+ "src/btif_a2dp_control.cc",
+ "src/btif_a2dp_sink.cc",
+ "src/btif_a2dp_source.cc",
+ "src/btif_av.cc",
+
+ #TODO(jpawlowski): heavily depends on Android,
+ # "src/btif_avrcp_audio_track.cc",
+ "src/btif_ble_advertiser.cc",
+ "src/btif_ble_scanner.cc",
+ "src/btif_config.cc",
+ "src/btif_config_transcode.cc",
+ "src/btif_core.cc",
+ "src/btif_debug.cc",
+ "src/btif_debug_btsnoop.cc",
+ "src/btif_debug_conn.cc",
+ "src/btif_dm.cc",
+ "src/btif_gatt.cc",
+ "src/btif_gatt_client.cc",
+ "src/btif_gatt_server.cc",
+ "src/btif_gatt_test.cc",
+ "src/btif_gatt_util.cc",
+ "src/btif_hf.cc",
+ "src/btif_hf_client.cc",
+ "src/btif_hh.cc",
+ "src/btif_hd.cc",
+ "src/btif_hl.cc",
+ "src/btif_mce.cc",
+ "src/btif_pan.cc",
+ "src/btif_profile_queue.cc",
+ "src/btif_rc.cc",
+ "src/btif_sdp.cc",
+ "src/btif_sdp_server.cc",
+ "src/btif_sm.cc",
+ "src/btif_sock.cc",
+ "src/btif_sock_l2cap.cc",
+ "src/btif_sock_rfc.cc",
+ "src/btif_sock_sco.cc",
+ "src/btif_sock_sdp.cc",
+ "src/btif_sock_thread.cc",
+ "src/btif_sock_util.cc",
+ "src/btif_storage.cc",
+ "src/btif_uid.cc",
+ "src/btif_util.cc",
+ "src/stack_manager.cc",
+ ]
+
+ # BTIF callouts
+ sources += [
+ "co/bta_ag_co.cc",
+ "co/bta_dm_co.cc",
+ "co/bta_av_co.cc",
+ "co/bta_hh_co.cc",
+ "co/bta_hl_co.cc",
+ "co/bta_pan_co.cc",
+ "co/bta_gatts_co.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//audio_a2dp_hw/include",
+ "//bta/include",
+ "//bta/sys",
+ "//btcore/include",
+ "//device/include",
+ "//embdrv/sbc/encoder/include",
+ "//embdrv/sbc/decoder/include",
+ "//hci/include",
+ "//stack/a2dp",
+ "//stack/btm",
+ "//stack/include",
+ "//third_party/tinyxml2",
+ "//include",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base"
+ ]
+}
diff --git a/mtkbt/code/bt/btif/co/bta_ag_co.cc b/mtkbt/code/bt/btif/co/bta_ag_co.cc
new file mode 100755
index 0000000..b27e57e
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_ag_co.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_bta_ag"
+
+#include "bta/include/bta_ag_co.h"
+#include "bta/ag/bta_ag_int.h"
+#include "bta/include/bta_ag_api.h"
+#include "bta/include/bta_ag_ci.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_init
+ *
+ * Description This callout function is executed by AG when it is
+ * started by calling BTA_AgEnable(). This function can be
+ * used by the phone to initialize audio paths or for other
+ * initialization purposes.
+ *
+ *
+ * Returns Void.
+ *
+ ******************************************************************************/
+void bta_ag_co_init(void) { BTM_WriteVoiceSettings(AG_VOICE_SETTINGS); }
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_data_open
+ *
+ * Description This function is executed by AG when a service level
+ * connection is opened. The phone can use this function to
+ * set up data paths or perform any required initialization or
+ * set up particular to the connected service.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_co_data_open(uint16_t handle, tBTA_SERVICE_ID service) {
+ BTIF_TRACE_DEBUG("bta_ag_co_data_open handle:%d service:%d", handle, service);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_ag_co_data_close
+ *
+ * Description This function is called by AG when a service level
+ * connection is closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_ag_co_data_close(uint16_t handle) {
+ BTIF_TRACE_DEBUG("bta_ag_co_data_close handle:%d", handle);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_ag_co_tx_write
+ **
+ ** Description This function is called by the AG to send data to the
+ ** phone when the AG is configured for AT command
+ ** pass-through. The implementation of this function must copy
+ ** the data to the phones memory.
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_ag_co_tx_write(uint16_t handle, UNUSED_ATTR uint8_t* p_data,
+ uint16_t len) {
+ BTIF_TRACE_DEBUG("bta_ag_co_tx_write: handle: %d, len: %d", handle, len);
+}
diff --git a/mtkbt/code/bt/btif/co/bta_av_co.cc b/mtkbt/code/bt/btif/co/bta_av_co.cc
new file mode 100755
index 0000000..9a43986
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_av_co.cc
@@ -0,0 +1,1361 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the advanced audio/video call-out function implementation for
+ * BTIF.
+ *
+ ******************************************************************************/
+
+#include "bta_av_co.h"
+#include <base/logging.h>
+#include <string.h>
+#include "a2dp_api.h"
+#include "a2dp_sbc.h"
+#include "bt_target.h"
+#include "bta_av_api.h"
+#include "bta_av_ci.h"
+#include "bta_sys.h"
+
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_util.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ ** Constants
+ *****************************************************************************/
+
+/* Macro to retrieve the number of elements in a statically allocated array */
+#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a) / sizeof((__a)[0]))
+
+/* Macro to convert audio handle to index and vice versa */
+#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1)
+#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO)
+
+/* SCMS-T protect info */
+const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00};
+
+/*****************************************************************************
+ * Local data
+ ****************************************************************************/
+typedef struct {
+ uint8_t sep_info_idx; /* local SEP index (in BTA tables) */
+ uint8_t seid; /* peer SEP index (in peer tables) */
+ uint8_t codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */
+ uint8_t num_protect; /* peer SEP number of CP elements */
+ uint8_t protect_info[AVDT_CP_INFO_LEN]; /* peer SEP content protection info */
+} tBTA_AV_CO_SINK;
+
+typedef struct {
+ BD_ADDR addr; /* address of audio/video peer */
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tBTA_AV_CO_SINK
+ sinks[BTAV_A2DP_CODEC_INDEX_MAX + 1]; /* array of supported sinks */
+ tBTA_AV_CO_SINK srcs[BTAV_A2DP_CODEC_INDEX_MAX + 1]; /* array of supported srcs */
+#else
+ tBTA_AV_CO_SINK
+ sinks[BTAV_A2DP_CODEC_INDEX_MAX]; /* array of supported sinks */
+ tBTA_AV_CO_SINK srcs[BTAV_A2DP_CODEC_INDEX_MAX]; /* array of supported srcs */
+#endif
+ uint8_t num_sinks; /* total number of sinks at peer */
+ uint8_t num_srcs; /* total number of srcs at peer */
+ uint8_t num_seps; /* total number of seids at peer */
+ uint8_t num_rx_sinks; /* number of received sinks */
+ uint8_t num_rx_srcs; /* number of received srcs */
+ uint8_t num_sup_sinks; /* number of supported sinks in the sinks array */
+ uint8_t num_sup_srcs; /* number of supported srcs in the srcs array */
+ const tBTA_AV_CO_SINK* p_sink; /* currently selected sink */
+ const tBTA_AV_CO_SINK* p_src; /* currently selected src */
+ uint8_t codec_config[AVDT_CODEC_SIZE]; /* current codec configuration */
+ bool cp_active; /* current CP configuration */
+ bool acp; /* acceptor */
+ bool reconfig_needed; /* reconfiguration is needed */
+ bool opened; /* opened */
+ uint16_t mtu; /* maximum transmit unit size */
+ uint16_t uuid_to_connect; /* uuid of peer device */
+ tBTA_AV_HNDL handle; /* handle to use */
+} tBTA_AV_CO_PEER;
+
+typedef struct {
+ bool active;
+ uint8_t flag;
+} tBTA_AV_CO_CP;
+
+class BtaAvCoCb {
+ public:
+ BtaAvCoCb() : codecs(nullptr) { reset(); }
+
+ /* Connected peer information */
+ tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS];
+ /* Current codec configuration - access to this variable must be protected */
+ uint8_t codec_config[AVDT_CODEC_SIZE];
+ A2dpCodecs* codecs; /* Locally supported codecs */
+ tBTA_AV_CO_CP cp;
+
+ void reset() {
+ delete codecs;
+ codecs = nullptr;
+ // TODO: Ugly leftover reset from the original C code. Should go away once
+ // the rest of the code in this file migrates to C++.
+ memset(peers, 0, sizeof(peers));
+ memset(codec_config, 0, sizeof(codec_config));
+ memset(&cp, 0, sizeof(cp));
+
+ // Initialize the handles
+ for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers); i++) {
+ tBTA_AV_CO_PEER* p_peer = &peers[i];
+ p_peer->handle = BTA_AV_CO_AUDIO_INDX_TO_HNDL(i);
+ }
+ }
+};
+
+/* Control block instance */
+static BtaAvCoCb bta_av_co_cb;
+static uint8_t sbc_codec_config[AVDT_CODEC_SIZE];
+static uint8_t aac_codec_config[AVDT_CODEC_SIZE];
+
+static bool bta_av_co_cp_is_scmst(const uint8_t* p_protect_info);
+static bool bta_av_co_audio_protect_has_scmst(uint8_t num_protect,
+ const uint8_t* p_protect_info);
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
+ const tBTA_AV_CO_PEER* p_peer);
+static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer);
+static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
+ A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer);
+static bool bta_av_co_audio_update_selectable_codec(
+ A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer);
+static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
+ const uint8_t* new_codec_config,
+ uint8_t num_protect,
+ const uint8_t* p_protect_info);
+static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
+ const uint8_t* p_ota_codec_config,
+ uint8_t num_protect,
+ const uint8_t* p_protect_info,
+ bool* p_restart_output);
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_get_flag
+ **
+ ** Description Get content protection flag
+ ** AVDT_CP_SCMS_COPY_NEVER
+ ** AVDT_CP_SCMS_COPY_ONCE
+ ** AVDT_CP_SCMS_COPY_FREE
+ **
+ ** Returns The current flag value
+ **
+ ******************************************************************************/
+static uint8_t bta_av_co_cp_get_flag(void) { return bta_av_co_cb.cp.flag; }
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_set_flag
+ **
+ ** Description Set content protection flag
+ ** AVDT_CP_SCMS_COPY_NEVER
+ ** AVDT_CP_SCMS_COPY_ONCE
+ ** AVDT_CP_SCMS_COPY_FREE
+ **
+ ** Returns true if setting the SCMS flag is supported else false
+ **
+ ******************************************************************************/
+static bool bta_av_co_cp_set_flag(uint8_t cp_flag) {
+ APPL_TRACE_DEBUG("%s: cp_flag = %d", __func__, cp_flag);
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#else
+ if (cp_flag != AVDT_CP_SCMS_COPY_FREE) {
+ return false;
+ }
+#endif
+ bta_av_co_cb.cp.flag = cp_flag;
+ return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_get_peer
+ **
+ ** Description find the peer entry for a given handle
+ **
+ ** Returns the control block
+ **
+ ******************************************************************************/
+static tBTA_AV_CO_PEER* bta_av_co_get_peer(tBTA_AV_HNDL hndl) {
+ uint8_t index;
+
+ index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl);
+
+ APPL_TRACE_DEBUG("%s: handle = %d index = %d", __func__, hndl, index);
+
+ /* Sanity check */
+ if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) {
+ APPL_TRACE_ERROR("%s: peer index out of bounds: %d", __func__, index);
+ return NULL;
+ }
+
+ return &bta_av_co_cb.peers[index];
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_init
+ **
+ ** Description This callout function is executed by AV when it is
+ ** started by calling BTA_AvRegister(). This function can be
+ ** used by the phone to initialize audio paths or for other
+ ** initialization purposes.
+ **
+ **
+ ** Returns Stream codec and content protection capabilities info.
+ **
+ ******************************************************************************/
+bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg) {
+ return A2DP_InitCodecConfig(codec_index, p_cfg);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_disc_res
+ **
+ ** Description This callout function is executed by AV to report the
+ ** number of stream end points (SEP) were found during the
+ ** AVDT stream discovery process.
+ **
+ **
+ ** Returns void.
+ **
+ ******************************************************************************/
+void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, uint8_t num_seps,
+ uint8_t num_sink, uint8_t num_src, BD_ADDR addr,
+ uint16_t uuid_local) {
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s: h:x%x num_seps:%d num_sink:%d num_src:%d", __func__,
+ hndl, num_seps, num_sink, num_src);
+
+ /* Find the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ return;
+ }
+
+ /* Sanity check : this should never happen */
+ if (p_peer->opened) {
+ APPL_TRACE_ERROR("%s: peer already opened", __func__);
+ }
+
+ /* Copy the discovery results */
+ bdcpy(p_peer->addr, addr);
+ p_peer->num_sinks = num_sink;
+ p_peer->num_srcs = num_src;
+ p_peer->num_seps = num_seps;
+ p_peer->num_rx_sinks = 0;
+ p_peer->num_rx_srcs = 0;
+ p_peer->num_sup_sinks = 0;
+ if (uuid_local == UUID_SERVCLASS_AUDIO_SINK)
+ p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE;
+ else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE)
+ p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_audio_sink_getconfig
+ **
+ ** Description This callout function is executed by AV to retrieve the
+ ** desired codec and content protection configuration for the
+ ** A2DP Sink audio stream in Initiator.
+ **
+ **
+ ** Returns Pass or Fail for current getconfig.
+ **
+ ******************************************************************************/
+static tA2DP_STATUS bta_av_audio_sink_getconfig(
+ tBTA_AV_HNDL hndl, uint8_t* p_codec_info, uint8_t* p_sep_info_idx,
+ uint8_t seid, uint8_t* p_num_protect, uint8_t* p_protect_info) {
+ tA2DP_STATUS result = A2DP_FAIL;
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
+ A2DP_CodecName(p_codec_info), seid);
+ APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+ __func__, *p_num_protect, p_protect_info[0],
+ p_protect_info[1], p_protect_info[2]);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ return A2DP_FAIL;
+ }
+
+ APPL_TRACE_DEBUG("%s: peer(o=%d,n_sinks=%d,n_rx_sinks=%d,n_sup_sinks=%d)",
+ __func__, p_peer->opened, p_peer->num_srcs,
+ p_peer->num_rx_srcs, p_peer->num_sup_srcs);
+
+ p_peer->num_rx_srcs++;
+
+ /* Check the peer's SOURCE codec */
+ if (A2DP_IsPeerSourceCodecValid(p_codec_info)) {
+ /* If there is room for a new one */
+ if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) {
+ tBTA_AV_CO_SINK* p_src = &p_peer->srcs[p_peer->num_sup_srcs++];
+
+ APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+ memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+ p_src->sep_info_idx = *p_sep_info_idx;
+ p_src->seid = seid;
+ p_src->num_protect = *p_num_protect;
+ memcpy(p_src->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
+ } else {
+ APPL_TRACE_ERROR("%s: no more room for SRC info", __func__);
+ }
+ }
+
+ /* If last SINK get capabilities or all supported codec caps retrieved */
+ if ((p_peer->num_rx_srcs == p_peer->num_srcs) ||
+ (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) {
+ APPL_TRACE_DEBUG("%s: last SRC reached", __func__);
+
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_lock();
+
+ /* Find a src that matches the codec config */
+ const tBTA_AV_CO_SINK* p_src =
+ bta_av_co_find_peer_src_supports_codec(p_peer);
+ if (p_src != NULL) {
+ uint8_t pref_config[AVDT_CODEC_SIZE];
+ APPL_TRACE_DEBUG("%s: codec supported", __func__);
+
+ /* Build the codec configuration for this sink */
+ /* Save the new configuration */
+ p_peer->p_src = p_src;
+ /* get preferred config from src_caps */
+ if (A2DP_BuildSrc2SinkConfig(p_src->codec_caps, pref_config) !=
+ A2DP_SUCCESS) {
+ mutex_global_unlock();
+ return A2DP_FAIL;
+ }
+ memcpy(p_peer->codec_config, pref_config, AVDT_CODEC_SIZE);
+
+ APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+ p_peer->codec_config[1], p_peer->codec_config[2],
+ p_peer->codec_config[3], p_peer->codec_config[4],
+ p_peer->codec_config[5], p_peer->codec_config[6]);
+ /* By default, no content protection */
+ *p_num_protect = 0;
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ p_peer->cp_active = false;
+ bta_av_co_cb.cp.active = false;
+#endif
+
+ *p_sep_info_idx = p_src->sep_info_idx;
+ memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
+ result = A2DP_SUCCESS;
+ }
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_unlock();
+ }
+ return result;
+}
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_getconfig
+ **
+ ** Description This callout function is executed by AV to retrieve the
+ ** desired codec and content protection configuration for the
+ ** audio stream.
+ **
+ **
+ ** Returns Stream codec and content protection configuration info.
+ **
+ ******************************************************************************/
+tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, uint8_t* p_codec_info,
+ uint8_t* p_sep_info_idx, uint8_t seid,
+ uint8_t* p_num_protect,
+ uint8_t* p_protect_info) {
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ return A2DP_FAIL;
+ }
+
+ if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) {
+ return bta_av_audio_sink_getconfig(hndl, p_codec_info, p_sep_info_idx, seid,
+ p_num_protect, p_protect_info);
+ }
+ APPL_TRACE_DEBUG("%s: handle:0x%x codec:%s seid:%d", __func__, hndl,
+ A2DP_CodecName(p_codec_info), seid);
+ APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x",
+ __func__, *p_num_protect, p_protect_info[0],
+ p_protect_info[1], p_protect_info[2]);
+ APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
+ __func__, p_peer->opened, p_peer->num_sinks,
+ p_peer->num_rx_sinks, p_peer->num_sup_sinks);
+
+ p_peer->num_rx_sinks++;
+
+ /* Check the peer's SINK codec */
+ if (A2DP_IsPeerSinkCodecValid(p_codec_info)) {
+ /* If there is room for a new one */
+ if (p_peer->num_sup_sinks < BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks)) {
+ tBTA_AV_CO_SINK* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++];
+
+ APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__,
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+ memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE);
+ p_sink->sep_info_idx = *p_sep_info_idx;
+ p_sink->seid = seid;
+ p_sink->num_protect = *p_num_protect;
+ memcpy(p_sink->protect_info, p_protect_info, AVDT_CP_INFO_LEN);
+ } else {
+ APPL_TRACE_ERROR("%s: no more room for SINK info", __func__);
+ }
+ }
+
+ // Check if this is the last SINK get capabilities or all supported codec
+ // capabilities are retrieved.
+ if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
+ (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
+ return A2DP_FAIL;
+ }
+ APPL_TRACE_DEBUG("%s: last sink reached", __func__);
+
+ const tBTA_AV_CO_SINK* p_sink = bta_av_co_audio_set_codec(p_peer);
+ if (p_sink == NULL) {
+ APPL_TRACE_ERROR("%s: cannot set up codec for the peer SINK", __func__);
+ return A2DP_FAIL;
+ }
+
+ // By default, no content protection
+ *p_num_protect = 0;
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (p_peer->cp_active) {
+ *p_num_protect = AVDT_CP_INFO_LEN;
+ memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN);
+ }
+#endif
+
+ // If acceptor -> reconfig otherwise reply for configuration.
+ if (p_peer->acp) {
+ // Stop fetching caps once we retrieved a supported codec.
+ APPL_TRACE_EVENT("%s: no need to fetch more SEPs", __func__);
+ *p_sep_info_idx = p_peer->num_seps;
+ if (p_peer->reconfig_needed) {
+ APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, hndl);
+ BTA_AvReconfig(hndl, true, p_sink->sep_info_idx, p_peer->codec_config,
+ *p_num_protect, bta_av_co_cp_scmst);
+ }
+ } else {
+ *p_sep_info_idx = p_sink->sep_info_idx;
+ memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
+ }
+
+ return A2DP_SUCCESS;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_setconfig
+ **
+ ** Description This callout function is executed by AV to set the codec
+ ** and content protection configuration of the audio stream.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, const uint8_t* p_codec_info,
+ UNUSED_ATTR uint8_t seid,
+ UNUSED_ATTR BD_ADDR addr, uint8_t num_protect,
+ const uint8_t* p_protect_info,
+ uint8_t t_local_sep, uint8_t avdt_handle) {
+ tBTA_AV_CO_PEER* p_peer;
+ tA2DP_STATUS status = A2DP_SUCCESS;
+ uint8_t category = A2DP_SUCCESS;
+ bool reconfig_needed = false;
+
+ APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+ APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x",
+ num_protect, p_protect_info[0], p_protect_info[1],
+ p_protect_info[2]);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ /* Call call-in rejecting the configuration */
+ bta_av_ci_setconfig(hndl, A2DP_BUSY, AVDT_ASC_CODEC, 0, NULL, false,
+ avdt_handle);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)",
+ __func__, p_peer->opened, p_peer->num_sinks,
+ p_peer->num_rx_sinks, p_peer->num_sup_sinks);
+
+ /* Sanity check: should not be opened at this point */
+ if (p_peer->opened) {
+ APPL_TRACE_ERROR("%s: peer already in use", __func__);
+ }
+
+ if (num_protect != 0) {
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* If CP is supported */
+ if ((num_protect != 1) ||
+ (bta_av_co_cp_is_scmst(p_protect_info) == false)) {
+ APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
+ status = A2DP_BAD_CP_TYPE;
+ category = AVDT_ASC_PROTECT;
+ }
+#else
+ /* Do not support content protection for the time being */
+ APPL_TRACE_ERROR("%s: wrong CP configuration", __func__);
+ status = A2DP_BAD_CP_TYPE;
+ category = AVDT_ASC_PROTECT;
+#endif
+ }
+
+ if (status == A2DP_SUCCESS) {
+ bool codec_config_supported = false;
+
+ if (t_local_sep == AVDT_TSEP_SNK) {
+ APPL_TRACE_DEBUG("%s: peer is A2DP SRC", __func__);
+ codec_config_supported = A2DP_IsSinkCodecSupported(p_codec_info);
+ if (codec_config_supported) {
+ // If Peer is SRC, and our config subset matches with what is
+ // requested by peer, then just accept what peer wants.
+ bta_av_co_save_new_codec_config(p_peer, p_codec_info, num_protect,
+ p_protect_info);
+ }
+ }
+ if (t_local_sep == AVDT_TSEP_SRC) {
+ APPL_TRACE_DEBUG("%s: peer is A2DP SINK", __func__);
+ bool restart_output = false;
+ if ((bta_av_co_cb.codecs == nullptr) ||
+ !bta_av_co_set_codec_ota_config(p_peer, p_codec_info, num_protect,
+ p_protect_info, &restart_output)) {
+ APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
+ A2DP_CodecName(p_codec_info));
+ } else {
+ codec_config_supported = true;
+ // Check if reconfiguration is needed
+ /** M: Bug fix avoid reconfig and accept peer device setconfig @{ */
+ //if (restart_output ||
+ /** @} */
+ if (((num_protect == 1) && (!bta_av_co_cb.cp.active))) {
+ reconfig_needed = true;
+ }
+ }
+ }
+
+ /* Check if codec configuration is supported */
+ if (!codec_config_supported) {
+ category = AVDT_ASC_CODEC;
+ status = A2DP_WRONG_CODEC;
+ }
+ }
+
+ if (status != A2DP_SUCCESS) {
+ APPL_TRACE_DEBUG("%s: reject s=%d c=%d", __func__, status, category);
+ /* Call call-in rejecting the configuration */
+ bta_av_ci_setconfig(hndl, status, category, 0, NULL, false, avdt_handle);
+ return;
+ }
+
+ /* Mark that this is an acceptor peer */
+ p_peer->acp = true;
+ p_peer->reconfig_needed = reconfig_needed;
+ APPL_TRACE_DEBUG("%s: accept reconf=%d", __func__, reconfig_needed);
+ /* Call call-in accepting the configuration */
+ bta_av_ci_setconfig(hndl, A2DP_SUCCESS, A2DP_SUCCESS, 0, NULL,
+ reconfig_needed, avdt_handle);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_open
+ **
+ ** Description This function is called by AV when the audio stream
+ ** connection is opened.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_open(tBTA_AV_HNDL hndl, uint16_t mtu) {
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s: handle: %d mtu:%d", __func__, hndl, mtu);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ } else {
+ p_peer->opened = true;
+ p_peer->mtu = mtu;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_close
+ **
+ ** Description This function is called by AV when the audio stream
+ ** connection is closed.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_close(tBTA_AV_HNDL hndl) {
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer) {
+ /* Mark the peer closed and clean the peer info */
+ memset(p_peer, 0, sizeof(*p_peer));
+ } else {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_start
+ **
+ ** Description This function is called by AV when the audio streaming data
+ ** transfer is started.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_start(UNUSED_ATTR tBTA_AV_HNDL hndl,
+ UNUSED_ATTR uint8_t* p_codec_info,
+ UNUSED_ATTR bool* p_no_rtp_hdr) {
+ APPL_TRACE_DEBUG("%s", __func__);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_stop
+ **
+ ** Description This function is called by AV when the audio streaming data
+ ** transfer is stopped.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_stop(UNUSED_ATTR tBTA_AV_HNDL hndl) {
+ APPL_TRACE_DEBUG("%s", __func__);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_src_data_path
+ **
+ ** Description This function is called to manage data transfer from
+ ** the audio codec to AVDTP.
+ **
+ ** Returns Pointer to the GKI buffer to send, NULL if no buffer to
+ ** send
+ **
+ ******************************************************************************/
+void* bta_av_co_audio_src_data_path(const uint8_t* p_codec_info,
+ uint32_t* p_timestamp) {
+ BT_HDR* p_buf;
+
+ APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info));
+
+ p_buf = btif_a2dp_source_audio_readbuf();
+ if (p_buf == NULL) return NULL;
+
+ /*
+ * Retrieve the timestamp information from the media packet,
+ * and set up the packet header.
+ *
+ * In media packet, the following information is available:
+ * p_buf->layer_specific : number of audio frames in the packet
+ * p_buf->word[0] : timestamp
+ */
+ if (!A2DP_GetPacketTimestamp(p_codec_info, (const uint8_t*)(p_buf + 1),
+ p_timestamp) ||
+ !A2DP_BuildCodecHeader(p_codec_info, p_buf, p_buf->layer_specific)) {
+ APPL_TRACE_ERROR("%s: unsupported codec type (%d)", __func__,
+ A2DP_GetCodecType(p_codec_info));
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (bta_av_co_cb.cp.active) {
+ p_buf->len++;
+ p_buf->offset--;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ *p = bta_av_co_cp_get_flag();
+ }
+#endif
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_drop
+ **
+ ** Description An Audio packet is dropped. .
+ ** It's very likely that the connected headset with this
+ ** handle is moved far away. The implementation may want to
+ ** reduce the encoder bit rate setting to reduce the packet
+ ** size.
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) {
+ APPL_TRACE_ERROR("%s: dropped audio packet on handle 0x%x", __func__, hndl);
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_delay
+ **
+ ** Description This function is called by AV when the audio stream
+ ** connection needs to send the initial delay report to the
+ ** connected SRC.
+ **
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, uint16_t delay) {
+ APPL_TRACE_ERROR("%s: handle: x%x, delay:0x%x", __func__, hndl, delay);
+}
+
+void bta_av_co_audio_update_mtu(tBTA_AV_HNDL hndl, uint16_t mtu) {
+ tBTA_AV_CO_PEER* p_peer;
+
+ APPL_TRACE_DEBUG("%s: handle: %d mtu: %d", __func__, hndl, mtu);
+
+ /* Retrieve the peer info */
+ p_peer = bta_av_co_get_peer(hndl);
+ if (p_peer == NULL) {
+ APPL_TRACE_ERROR("%s: could not find peer entry", __func__);
+ return;
+ }
+ p_peer->mtu = mtu;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_cp_is_scmst
+ **
+ ** Description Check if a content protection service is SCMS-T
+ **
+ ** Returns true if this CP is SCMS-T, false otherwise
+ **
+ ******************************************************************************/
+static bool bta_av_co_cp_is_scmst(const uint8_t* p_protect_info) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (*p_protect_info >= AVDT_CP_LOSC) {
+ uint16_t cp_id;
+
+ p_protect_info++;
+ STREAM_TO_UINT16(cp_id, p_protect_info);
+ if (cp_id == AVDT_CP_SCMS_T_ID) {
+ APPL_TRACE_DEBUG("%s: SCMS-T found", __func__);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Check if audio protect info contains SCMS-T Copy Protection
+// Returns true if |p_protect_info| contains SCMS-T, otherwise false.
+static bool bta_av_co_audio_protect_has_scmst(uint8_t num_protect,
+ const uint8_t* p_protect_info) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ while (num_protect--) {
+ if (bta_av_co_cp_is_scmst(p_protect_info)) return true;
+ /* Move to the next SC */
+ p_protect_info += *p_protect_info + 1;
+ }
+ APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_audio_sink_supports_cp
+ **
+ ** Description Check if a sink supports the current content protection
+ **
+ ** Returns true if the sink supports this CP, false otherwise
+ **
+ ******************************************************************************/
+static bool bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK* p_sink) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* Check if content protection is enabled for this stream */
+ if (bta_av_co_cp_get_flag() != AVDT_CP_SCMS_COPY_FREE) {
+ return bta_av_co_audio_protect_has_scmst(p_sink->num_protect,
+ p_sink->protect_info);
+ }
+
+ APPL_TRACE_DEBUG("%s: not required", __func__);
+ return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_av_co_find_peer_src_supports_codec
+ **
+ ** Description Find a peer acting as src that supports codec config
+ **
+ ** Returns The peer source that supports the codec, otherwise NULL.
+ **
+ ******************************************************************************/
+static const tBTA_AV_CO_SINK* bta_av_co_find_peer_src_supports_codec(
+ const tBTA_AV_CO_PEER* p_peer) {
+ APPL_TRACE_DEBUG("%s: peer num_sup_srcs = %d", __func__,
+ p_peer->num_sup_srcs);
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (size_t index = 0; index < p_peer->num_sup_srcs; index++) {
+ const uint8_t* p_codec_caps = p_peer->srcs[index].codec_caps;
+ if (A2DP_CodecTypeEquals(aac_codec_config, p_codec_caps) &&
+ A2DP_IsPeerSourceCodecSupported(p_codec_caps)) {
+ memcpy(bta_av_co_cb.codec_config, aac_codec_config, sizeof(bta_av_co_cb.codec_config));
+ return &p_peer->srcs[index];
+ }
+ }
+
+ for (size_t index = 0; index < p_peer->num_sup_srcs; index++) {
+ const uint8_t* p_codec_caps = p_peer->srcs[index].codec_caps;
+ if (A2DP_CodecTypeEquals(sbc_codec_config, p_codec_caps) &&
+ A2DP_IsPeerSourceCodecSupported(p_codec_caps)) {
+ memcpy(bta_av_co_cb.codec_config, sbc_codec_config, sizeof(bta_av_co_cb.codec_config));
+ return &p_peer->srcs[index];
+ }
+ }
+#else
+ for (size_t index = 0; index < p_peer->num_sup_srcs; index++) {
+ const uint8_t* p_codec_caps = p_peer->srcs[index].codec_caps;
+ if (A2DP_CodecTypeEquals(bta_av_co_cb.codec_config, p_codec_caps) &&
+ A2DP_IsPeerSourceCodecSupported(p_codec_caps)) {
+ return &p_peer->srcs[index];
+ }
+ }
+#endif
+ return NULL;
+}
+
+//
+// Select the current codec configuration based on peer codec support.
+// Furthermore, the local state for the remaining non-selected codecs is
+// updated to reflect whether the codec is selectable.
+// Return a pointer to the corresponding |tBTA_AV_CO_SINK| sink entry
+// on success, otherwise NULL.
+//
+static tBTA_AV_CO_SINK* bta_av_co_audio_set_codec(tBTA_AV_CO_PEER* p_peer) {
+ tBTA_AV_CO_SINK* p_sink = NULL;
+
+ // Update all selectable codecs.
+ // This is needed to update the selectable parameters for each codec.
+ // NOTE: The selectable codec info is used only for informational purpose.
+ for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
+ APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__,
+ iter->name().c_str());
+ bta_av_co_audio_update_selectable_codec(*iter, p_peer);
+ }
+
+ // Select the codec
+ for (const auto& iter : bta_av_co_cb.codecs->orderedSourceCodecs()) {
+ APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
+ p_sink = bta_av_co_audio_codec_selected(*iter, p_peer);
+ if (p_sink != NULL) {
+ APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
+ break;
+ }
+ APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
+ }
+
+ // NOTE: Unconditionally dispatch the event to make sure a callback with
+ // the most recent codec info is generated.
+ btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+
+ return p_sink;
+}
+
+// Select an open device for the preferred codec specified by |codec_config|.
+// Return the corresponding peer that supports the codec, otherwise NULL.
+static tBTA_AV_CO_SINK* bta_av_co_audio_codec_selected(
+ A2dpCodecConfig& codec_config, tBTA_AV_CO_PEER* p_peer) {
+ uint8_t new_codec_config[AVDT_CODEC_SIZE];
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ // Find the peer sink for the codec
+ tBTA_AV_CO_SINK* p_sink = NULL;
+ for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+ btav_a2dp_codec_index_t peer_codec_index =
+ A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
+ if (peer_codec_index != codec_config.codecIndex()) {
+ continue;
+ }
+ if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) {
+ APPL_TRACE_DEBUG(
+ "%s: peer sink for codec %s does not support "
+ "Copy Protection",
+ __func__, codec_config.name().c_str());
+ continue;
+ }
+ p_sink = &p_peer->sinks[index];
+ break;
+ }
+ if (p_sink == NULL) {
+ APPL_TRACE_DEBUG("%s: peer sink for codec %s not found", __func__,
+ codec_config.name().c_str());
+ return NULL;
+ }
+ if (!bta_av_co_cb.codecs->setCodecConfig(
+ p_sink->codec_caps, true /* is_capability */, new_codec_config,
+ true /* select_current_codec */)) {
+ APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__,
+ codec_config.name().c_str());
+ return NULL;
+ }
+ p_peer->p_sink = p_sink;
+
+ bta_av_co_save_new_codec_config(p_peer, new_codec_config, p_sink->num_protect,
+ p_sink->protect_info);
+ // NOTE: Event BTIF_AV_SOURCE_CONFIG_UPDATED_EVT is dispatched by the caller
+
+ return p_sink;
+}
+
+// Update a selectable codec |codec_config| with the corresponding codec
+// information from a peer device |p_peer|.
+// Returns true if the codec is updated, otherwise false.
+static bool bta_av_co_audio_update_selectable_codec(
+ A2dpCodecConfig& codec_config, const tBTA_AV_CO_PEER* p_peer) {
+ uint8_t new_codec_config[AVDT_CODEC_SIZE];
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ // Find the peer sink for the codec
+ const tBTA_AV_CO_SINK* p_sink = NULL;
+ for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+ btav_a2dp_codec_index_t peer_codec_index =
+ A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
+ if (peer_codec_index != codec_config.codecIndex()) {
+ continue;
+ }
+ if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) {
+ APPL_TRACE_DEBUG(
+ "%s: peer sink for codec %s does not support "
+ "Copy Protection",
+ __func__, codec_config.name().c_str());
+ continue;
+ }
+ p_sink = &p_peer->sinks[index];
+ break;
+ }
+ if (p_sink == NULL) {
+ // The peer sink device does not support this codec
+ return false;
+ }
+ if (!bta_av_co_cb.codecs->setCodecConfig(
+ p_sink->codec_caps, true /* is_capability */, new_codec_config,
+ false /* select_current_codec */)) {
+ APPL_TRACE_DEBUG("%s: cannot update source codec %s", __func__,
+ codec_config.name().c_str());
+ return false;
+ }
+ return true;
+}
+
+static void bta_av_co_save_new_codec_config(tBTA_AV_CO_PEER* p_peer,
+ const uint8_t* new_codec_config,
+ uint8_t num_protect,
+ const uint8_t* p_protect_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(new_codec_config);
+#endif
+
+ // Protect access to bta_av_co_cb.codec_config
+ mutex_global_lock();
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (A2DP_MEDIA_CT_SBC == codec_type)
+ {
+ memcpy(sbc_codec_config, new_codec_config, sizeof(sbc_codec_config));
+ }
+ else if (A2DP_MEDIA_CT_AAC == codec_type)
+ {
+ memcpy(aac_codec_config, new_codec_config, sizeof(aac_codec_config));
+ }
+#endif
+ memcpy(bta_av_co_cb.codec_config, new_codec_config,
+ sizeof(bta_av_co_cb.codec_config));
+ memcpy(p_peer->codec_config, new_codec_config, AVDT_CODEC_SIZE);
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Check if this sink supports SCMS */
+ bool cp_active =
+ bta_av_co_audio_protect_has_scmst(num_protect, p_protect_info);
+ bta_av_co_cb.cp.active = cp_active;
+ p_peer->cp_active = cp_active;
+#endif
+
+ // Protect access to bta_av_co_cb.codec_config
+ mutex_global_unlock();
+}
+
+void bta_av_co_get_peer_params(tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) {
+ uint16_t min_mtu = 0xFFFF;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ CHECK(p_peer_params != nullptr);
+
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_lock();
+
+ /* Compute the MTU */
+ for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
+ const tBTA_AV_CO_PEER* p_peer = &bta_av_co_cb.peers[i];
+ if (!p_peer->opened) continue;
+ if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu;
+ }
+ p_peer_params->peer_mtu = min_mtu;
+ p_peer_params->is_peer_edr = btif_av_is_peer_edr();
+ p_peer_params->peer_supports_3mbps = btif_av_peer_supports_3mbps();
+
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_unlock();
+}
+
+const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) {
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_lock();
+
+ const tA2DP_ENCODER_INTERFACE* encoder_interface =
+ A2DP_GetEncoderInterface(bta_av_co_cb.codec_config);
+
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_unlock();
+
+ return encoder_interface;
+}
+
+bool bta_av_co_set_codec_user_config(
+ const btav_a2dp_codec_config_t& codec_user_config) {
+ uint8_t result_codec_config[AVDT_CODEC_SIZE];
+ const tBTA_AV_CO_SINK* p_sink = nullptr;
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ bool success = true;
+
+ // Find the peer that is currently open
+ tBTA_AV_CO_PEER* p_peer = nullptr;
+ for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
+ tBTA_AV_CO_PEER* p_peer_tmp = &bta_av_co_cb.peers[i];
+ if (p_peer_tmp->opened) {
+ p_peer = p_peer_tmp;
+ break;
+ }
+ }
+ if (p_peer == nullptr) {
+ APPL_TRACE_ERROR("%s: no open peer to configure", __func__);
+ success = false;
+ goto done;
+ }
+
+ // Find the peer SEP codec to use
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (codec_user_config.codec_type < (BTAV_A2DP_CODEC_INDEX_MAX + 1)) {
+#else
+ if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) {
+#endif
+ for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+ btav_a2dp_codec_index_t peer_codec_index =
+ A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
+ if (peer_codec_index != codec_user_config.codec_type) continue;
+ if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) continue;
+ p_sink = &p_peer->sinks[index];
+ break;
+ }
+ } else {
+ // Use the current sink codec
+ p_sink = p_peer->p_sink;
+ }
+ if (p_sink == nullptr) {
+ APPL_TRACE_ERROR("%s: cannot find peer SEP to configure for codec type %d",
+ __func__, codec_user_config.codec_type);
+ success = false;
+ goto done;
+ }
+
+ tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+ bta_av_co_get_peer_params(&peer_params);
+ if (!bta_av_co_cb.codecs->setCodecUserConfig(
+ codec_user_config, &peer_params, p_sink->codec_caps,
+ result_codec_config, &restart_input, &restart_output,
+ &config_updated)) {
+ success = false;
+ goto done;
+ }
+
+ if (restart_output) {
+ uint8_t num_protect = 0;
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (p_peer->cp_active) num_protect = AVDT_CP_INFO_LEN;
+#endif
+
+ p_sink = bta_av_co_audio_set_codec(p_peer);
+ if (p_sink == NULL) {
+ APPL_TRACE_ERROR("%s: cannot set up codec for the peer SINK", __func__);
+ success = false;
+ goto done;
+ }
+ APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, p_peer->handle);
+ BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
+ p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
+ }
+
+done:
+ // NOTE: We uncoditionally send the upcall even if there is no change
+ // or the user config failed. Thus, the caller would always know whether the
+ // request succeeded or failed.
+ // NOTE: Currently, the input is restarted by sending an upcall
+ // and informing the Media Framework about the change.
+ btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+
+ return success;
+}
+
+// Sets the Over-The-Air preferred codec configuration.
+// The OTA prefered codec configuration is ignored if the current
+// codec configuration contains explicit user configuration, or if the
+// codec configuration for the same codec contains explicit user
+// configuration.
+// |p_peer| is the peer device that sent the OTA codec configuration.
+// |p_ota_codec_config| contains the received OTA A2DP codec configuration
+// from the remote peer. Note: this is not the peer codec capability,
+// but the codec configuration that the peer would like to use.
+// |num_protect| is the number of content protection methods to use.
+// |p_protect_info| contains the content protection information to use.
+// If there is a change in the encoder configuration tht requires restarting
+// of the A2DP connection, flag |p_restart_output| is set to true.
+// Returns true on success, otherwise false.
+static bool bta_av_co_set_codec_ota_config(tBTA_AV_CO_PEER* p_peer,
+ const uint8_t* p_ota_codec_config,
+ uint8_t num_protect,
+ const uint8_t* p_protect_info,
+ bool* p_restart_output) {
+ uint8_t result_codec_config[AVDT_CODEC_SIZE];
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+
+ *p_restart_output = false;
+
+ // Find the peer SEP codec to use
+ btav_a2dp_codec_index_t ota_codec_index =
+ A2DP_SourceCodecIndex(p_ota_codec_config);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (ota_codec_index == (BTAV_A2DP_CODEC_INDEX_MAX + 1)) {
+#else
+ if (ota_codec_index == BTAV_A2DP_CODEC_INDEX_MAX) {
+#endif
+ APPL_TRACE_WARNING("%s: invalid peer codec config", __func__);
+ return false;
+ }
+ const tBTA_AV_CO_SINK* p_sink = nullptr;
+ for (size_t index = 0; index < p_peer->num_sup_sinks; index++) {
+ btav_a2dp_codec_index_t peer_codec_index =
+ A2DP_SourceCodecIndex(p_peer->sinks[index].codec_caps);
+ if (peer_codec_index != ota_codec_index) continue;
+ if (!bta_av_co_audio_sink_supports_cp(&p_peer->sinks[index])) continue;
+ p_sink = &p_peer->sinks[index];
+ break;
+ }
+ if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) {
+ // There are no peer SEPs if we didn't do the discovery procedure yet.
+ // We have all the information we need from the peer, so we can
+ // proceed with the OTA codec configuration.
+ APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__);
+ return false;
+ }
+
+ tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+ bta_av_co_get_peer_params(&peer_params);
+ if (!bta_av_co_cb.codecs->setCodecOtaConfig(
+ p_ota_codec_config, &peer_params, result_codec_config, &restart_input,
+ &restart_output, &config_updated)) {
+ APPL_TRACE_ERROR("%s: cannot set OTA config", __func__);
+ return false;
+ }
+
+ if (restart_output) {
+ *p_restart_output = true;
+ p_peer->p_sink = p_sink;
+ bta_av_co_save_new_codec_config(p_peer, result_codec_config, num_protect,
+ p_protect_info);
+ }
+
+ if (restart_input || config_updated) {
+ // NOTE: Currently, the input is restarted by sending an upcall
+ // and informing the Media Framework about the change.
+ btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+ }
+
+ return true;
+}
+
+bool bta_av_co_set_codec_audio_config(
+ const btav_a2dp_codec_config_t& codec_audio_config) {
+ uint8_t result_codec_config[AVDT_CODEC_SIZE];
+ bool restart_output = false;
+ bool config_updated = false;
+
+ // Find the peer that is currently open
+ tBTA_AV_CO_PEER* p_peer = nullptr;
+ for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); i++) {
+ tBTA_AV_CO_PEER* p_peer_tmp = &bta_av_co_cb.peers[i];
+ if (p_peer_tmp->opened) {
+ p_peer = p_peer_tmp;
+ break;
+ }
+ }
+ if (p_peer == nullptr) {
+ APPL_TRACE_ERROR("%s: no open peer to configure", __func__);
+ return false;
+ }
+
+ // Use the current sink codec
+ const tBTA_AV_CO_SINK* p_sink = p_peer->p_sink;
+ if (p_sink == nullptr) {
+ APPL_TRACE_ERROR("%s: cannot find peer SEP to configure", __func__);
+ return false;
+ }
+
+ tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+ bta_av_co_get_peer_params(&peer_params);
+ if (!bta_av_co_cb.codecs->setCodecAudioConfig(
+ codec_audio_config, &peer_params, p_sink->codec_caps,
+ result_codec_config, &restart_output, &config_updated)) {
+ return false;
+ }
+
+ if (restart_output) {
+ uint8_t num_protect = 0;
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ if (p_peer->cp_active) num_protect = AVDT_CP_INFO_LEN;
+#endif
+
+ bta_av_co_save_new_codec_config(p_peer, result_codec_config,
+ p_sink->num_protect, p_sink->protect_info);
+
+ APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(x%x)", __func__, p_peer->handle);
+ BTA_AvReconfig(p_peer->handle, true, p_sink->sep_info_idx,
+ p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
+ }
+
+ if (config_updated) {
+ // NOTE: Currently, the input is restarted by sending an upcall
+ // and informing the Media Framework about the change.
+ btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+ }
+
+ return true;
+}
+
+A2dpCodecs* bta_av_get_a2dp_codecs(void) { return bta_av_co_cb.codecs; }
+
+A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) {
+ A2dpCodecConfig* current_codec;
+
+ mutex_global_lock();
+ if (bta_av_co_cb.codecs == nullptr) {
+ mutex_global_unlock();
+ return nullptr;
+ }
+ current_codec = bta_av_co_cb.codecs->getCurrentCodecConfig();
+ mutex_global_unlock();
+
+ return current_codec;
+}
+
+void bta_av_co_init(
+ const std::vector<btav_a2dp_codec_config_t>& codec_priorities) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ /* Reset the control block */
+ bta_av_co_cb.reset();
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_NEVER);
+#else
+ bta_av_co_cp_set_flag(AVDT_CP_SCMS_COPY_FREE);
+#endif
+
+ /* Reset the current config */
+ /* Protect access to bta_av_co_cb.codec_config */
+ mutex_global_lock();
+ bta_av_co_cb.codecs = new A2dpCodecs(codec_priorities);
+ bta_av_co_cb.codecs->init();
+ A2DP_InitDefaultCodec(bta_av_co_cb.codec_config);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ A2DP_InitDefaultCodec(sbc_codec_config);
+ A2DP_InitAacDefaultCodec(aac_codec_config);
+#endif
+ mutex_global_unlock();
+
+ // NOTE: Unconditionally dispatch the event to make sure a callback with
+ // the most recent codec info is generated.
+ btif_dispatch_sm_event(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT, NULL, 0);
+}
diff --git a/mtkbt/code/bt/btif/co/bta_dm_co.cc b/mtkbt/code/bt/btif/co/bta_dm_co.cc
new file mode 100755
index 0000000..7a64bec
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_dm_co.cc
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bta_dm_ci.h"
+#include "bta_dm_co.h"
+#include "bta_sys.h"
+#include "bte_appl.h"
+#include "btif_dm.h"
+#include "osi/include/osi.h"
+
+tBTE_APPL_CFG bte_appl_cfg = {
+ BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements
+ BTM_LOCAL_IO_CAPS_BLE, BTM_BLE_INITIATOR_KEY_SIZE,
+ BTM_BLE_RESPONDER_KEY_SIZE, BTM_BLE_MAX_KEY_SIZE};
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_get_compress_memory
+ *
+ * Description This callout function is executed by DM to get memory for
+ compression
+
+ * Parameters id - BTA SYS ID
+ * memory_p - memory return by callout
+ * memory_size - memory size
+ *
+ * Returns true for success, false for fail.
+ *
+ ******************************************************************************/
+bool bta_dm_co_get_compress_memory(UNUSED_ATTR tBTA_SYS_ID id,
+ UNUSED_ATTR uint8_t** memory_p,
+ UNUSED_ATTR uint32_t* memory_size) {
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_io_req
+ *
+ * Description This callout function is executed by DM to get IO
+ * capabilities of the local device for the Simple Pairing
+ * process.
+ *
+ * Parameters bd_addr - The peer device
+ * *p_io_cap - The local Input/Output capabilities
+ * *p_oob_data - true, if OOB data is available for the peer
+ * device.
+ * *p_auth_req - true, if MITM protection is required.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_io_req(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data, tBTA_AUTH_REQ* p_auth_req,
+ bool is_orig) {
+ btif_dm_set_oob_for_io_req(p_oob_data);
+ btif_dm_proc_io_req(bd_addr, p_io_cap, p_oob_data, p_auth_req, is_orig);
+ BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_oob_data = %d", *p_oob_data);
+ BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_io_cap = %d", *p_io_cap);
+ BTIF_TRACE_DEBUG("bta_dm_co_io_req *p_auth_req = %d", *p_auth_req);
+ BTIF_TRACE_DEBUG("bta_dm_co_io_req is_orig = %d", is_orig);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_io_rsp
+ *
+ * Description This callout function is executed by DM to report IO
+ * capabilities of the peer device for the Simple Pairing
+ * process.
+ *
+ * Parameters bd_addr - The peer device
+ * io_cap - The remote Input/Output capabilities
+ * oob_data - true, if OOB data is available for the peer
+ * device.
+ * auth_req - true, if MITM protection is required.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req) {
+ btif_dm_proc_io_rsp(bd_addr, io_cap, oob_data, auth_req);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_lk_upgrade
+ *
+ * Description This callout function is executed by DM to check if the
+ * platform wants allow link key upgrade
+ *
+ * Parameters bd_addr - The peer device
+ * *p_upgrade - true, if link key upgrade is desired.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_lk_upgrade(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR bool* p_upgrade) {}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_loc_oob
+ *
+ * Description This callout function is executed by DM to report the OOB
+ * data of the local device for the Simple Pairing process
+ *
+ * Parameters valid - true, if the local OOB data is retrieved from LM
+ * c - Simple Pairing Hash C
+ * r - Simple Pairing Randomnizer R
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+ BTIF_TRACE_DEBUG("bta_dm_co_loc_oob, valid = %d", valid);
+#ifdef BTIF_DM_OOB_TEST
+ btif_dm_proc_loc_oob(valid, c, r);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_rmt_oob
+ *
+ * Description This callout function is executed by DM to request the OOB
+ * data for the remote device for the Simple Pairing process
+ * Need to call bta_dm_ci_rmt_oob() in response
+ *
+ * Parameters bd_addr - The peer device
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_rmt_oob(BD_ADDR bd_addr) {
+ BT_OCTET16 p_c;
+ BT_OCTET16 p_r;
+ bool result = false;
+
+#ifdef BTIF_DM_OOB_TEST
+ result = btif_dm_proc_rmt_oob(bd_addr, p_c, p_r);
+#endif
+
+ BTIF_TRACE_DEBUG("bta_dm_co_rmt_oob: result=%d", result);
+ bta_dm_ci_rmt_oob(result, bd_addr, p_c, p_r);
+}
+
+// REMOVE FOR BLUEDROID ?
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function btui_sco_codec_callback
+ *
+ * Description Callback for btui codec.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btui_sco_codec_callback(uint16_t event, uint16_t sco_handle) {
+ bta_dm_sco_ci_data_ready(event, sco_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_open
+ *
+ * Description This function is executed when a SCO connection is open.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_open(uint16_t handle, uint8_t pkt_size, uint16_t event) {
+ tBTUI_SCO_CODEC_CFG cfg;
+
+ if (btui_cb.sco_hci) {
+ BTIF_TRACE_DEBUG("bta_dm_sco_co_open handle:%d pkt_size:%d", handle,
+ pkt_size);
+ cfg.p_cback = btui_sco_codec_callback;
+ cfg.pkt_size = pkt_size;
+ cfg.cb_event = event;
+ /* open and start the codec */
+ btui_sco_codec_open(&cfg);
+ btui_sco_codec_start(handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_close
+ *
+ * Description This function is called when a SCO connection is closed
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_close(void) {
+ if (btui_cb.sco_hci) {
+ BTIF_TRACE_DEBUG("bta_dm_sco_co_close close codec");
+ /* close sco codec */
+ btui_sco_codec_close();
+
+ btui_cb.sco_hci = false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_in_data
+ *
+ * Description This function is called to send incoming SCO data to
+ * application.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_in_data(BT_HDR* p_buf) {
+ if (btui_cfg.sco_use_mic)
+ btui_sco_codec_inqdata(p_buf);
+ else
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_sco_co_out_data
+ *
+ * Description This function is called to send SCO data over HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_dm_sco_co_out_data(BT_HDR** p_buf) { btui_sco_codec_readbuf(p_buf); }
+
+#endif /* (BTM_SCO_HCI_INCLUDED == TRUE) && (BTM_SCO_INCLUDED == TRUE)*/
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_le_io_key_req
+ *
+ * Description This callout function is executed by DM to get BLE key
+ * information
+ * before SMP pairing gets going.
+ *
+ * Parameters bd_addr - The peer device
+ * *p_max_key_size - max key size local device supported.
+ * *p_init_key - initiator keys.
+ * *p_resp_key - responder keys.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_le_io_key_req(UNUSED_ATTR BD_ADDR bd_addr,
+ uint8_t* p_max_key_size,
+ tBTA_LE_KEY_TYPE* p_init_key,
+ tBTA_LE_KEY_TYPE* p_resp_key) {
+ BTIF_TRACE_ERROR("##################################");
+ BTIF_TRACE_ERROR("bta_dm_co_le_io_key_req: only setting max size to 16");
+ BTIF_TRACE_ERROR("##################################");
+ *p_max_key_size = 16;
+ *p_init_key = *p_resp_key =
+ (BTA_LE_KEY_PENC | BTA_LE_KEY_PID | BTA_LE_KEY_PCSRK | BTA_LE_KEY_LENC |
+ BTA_LE_KEY_LID | BTA_LE_KEY_LCSRK);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_ble_local_key_reload
+ *
+ * Description This callout function is to load the local BLE keys if
+ * available on the device.
+ *
+ * Parameters none
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_ble_load_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+ BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
+ BTIF_TRACE_DEBUG("##################################");
+ BTIF_TRACE_DEBUG(
+ "bta_dm_co_ble_load_local_keys: Load local keys if any are persisted");
+ BTIF_TRACE_DEBUG("##################################");
+ btif_dm_get_ble_local_keys(p_key_mask, er, p_id_keys);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_dm_co_ble_io_req
+ *
+ * Description This callout function is executed by DM to get BLE IO
+ * capabilities before SMP pairing gets going.
+ *
+ * Parameters bd_addr - The peer device
+ * *p_io_cap - The local Input/Output capabilities
+ * *p_oob_data - true, if OOB data is available for the peer
+ * device.
+ * *p_auth_req - Auth request setting (Bonding and MITM
+ * required or not)
+ * *p_max_key_size - max key size local device supported.
+ * *p_init_key - initiator keys.
+ * *p_resp_key - responder keys.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_dm_co_ble_io_req(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data,
+ tBTA_LE_AUTH_REQ* p_auth_req, uint8_t* p_max_key_size,
+ tBTA_LE_KEY_TYPE* p_init_key,
+ tBTA_LE_KEY_TYPE* p_resp_key) {
+ /* Retrieve the properties from file system if possible */
+ tBTE_APPL_CFG nv_config;
+ if (btif_dm_get_smp_config(&nv_config)) bte_appl_cfg = nv_config;
+
+ /* *p_auth_req by default is false for devices with NoInputNoOutput; true for
+ * other devices. */
+
+ if (bte_appl_cfg.ble_auth_req)
+ *p_auth_req = bte_appl_cfg.ble_auth_req |
+ (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
+
+ /* if OOB is not supported, this call-out function does not need to do
+ * anything
+ * otherwise, look for the OOB data associated with the address and set
+ * *p_oob_data accordingly.
+ * If the answer can not be obtained right away,
+ * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the
+ * answer is available.
+ */
+
+ btif_dm_set_oob_for_le_io_req(bd_addr, p_oob_data, p_auth_req);
+
+ if (bte_appl_cfg.ble_io_cap <= 4) *p_io_cap = bte_appl_cfg.ble_io_cap;
+
+ if (bte_appl_cfg.ble_init_key <= BTM_BLE_INITIATOR_KEY_SIZE)
+ *p_init_key = bte_appl_cfg.ble_init_key;
+
+ if (bte_appl_cfg.ble_resp_key <= BTM_BLE_RESPONDER_KEY_SIZE)
+ *p_resp_key = bte_appl_cfg.ble_resp_key;
+
+ if (bte_appl_cfg.ble_max_key_size > 7 && bte_appl_cfg.ble_max_key_size <= 16)
+ *p_max_key_size = bte_appl_cfg.ble_max_key_size;
+}
diff --git a/mtkbt/code/bt/btif/co/bta_gatts_co.cc b/mtkbt/code/bt/btif/co/bta_gatts_co.cc
new file mode 100755
index 0000000..09f9167
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_gatts_co.cc
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bta_api.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "bt_common.h"
+#include "bta_gatts_co.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+/** M: Feature change, process CCCD of Service Changed Characteristic @{ */
+#include "mediatek/include/gatts_mtk.h"
+/** @} */
+
+/*****************************************************************************
+ * Local type definitions
+ ****************************************************************************/
+
+#define BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE 50
+
+typedef struct {
+ bool enable;
+ uint8_t num_clients;
+ tBTA_GATTS_SRV_CHG srv_chg[BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE];
+} __attribute__((packed)) btif_gatts_srv_chg_cb_t;
+
+/*****************************************************************************
+ * Static variables
+ ****************************************************************************/
+
+static btif_gatts_srv_chg_cb_t btif_gatts_srv_chg_cb;
+
+/*****************************************************************************
+ * Static functions
+ ****************************************************************************/
+
+static void btif_gatts_check_init(void) {
+ btif_gatts_srv_chg_cb_t* p_cb = &btif_gatts_srv_chg_cb;
+
+ if (!p_cb->enable) {
+ memset(p_cb, 0, sizeof(btif_gatts_srv_chg_cb_t));
+ p_cb->enable = true;
+ }
+}
+
+/*****************************************************************************
+ * Externally called functions
+ ****************************************************************************/
+
+void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda) {
+ btif_gatts_srv_chg_cb_t* p_cb = &btif_gatts_srv_chg_cb;
+ bool found = false;
+ uint8_t i;
+
+ btif_gatts_check_init();
+
+ /** M: Feature change, only Loading bonded clients configured indication @{ */
+ if (false == gatts_srv_chg_ind_get(bda))
+ return;
+ /** @} */
+
+ for (i = 0; i != p_cb->num_clients; ++i) {
+ if (!memcmp(p_cb->srv_chg[i].bda, bda, sizeof(BD_ADDR))) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (p_cb->num_clients < BTIF_GATTS_MAX_SRV_CHG_CLT_SIZE) {
+ bdcpy(p_cb->srv_chg[p_cb->num_clients].bda, bda);
+ p_cb->srv_chg[p_cb->num_clients].srv_changed = false;
+ p_cb->num_clients++;
+ }
+ }
+}
+
+/*****************************************************************************
+ * Call-out functions
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_update_handle_range
+ *
+ * Description This callout function is executed by GATTS when a GATT
+ * server handle range ios to be added or removed.
+ *
+ * Parameter is_add: true is to add a handle range; otherwise is to
+ * delete.
+ * p_hndl_range: handle range.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_gatts_co_update_handle_range(
+ UNUSED_ATTR bool is_add, UNUSED_ATTR tBTA_GATTS_HNDL_RANGE* p_hndl_range) {}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_srv_chg
+ *
+ * Description This call-out is to read/write/remove service change related
+ * informaiton. The request consists of the cmd and p_req and
+ * the response is returned in p_rsp
+ *
+ * Parameter cmd - request command
+ * p_req - request paramters
+ * p_rsp - response data for the request
+ *
+ * Returns true - if the request is processed successfully and
+ * the response is returned in p_rsp.
+ * false - if the request can not be processed
+ *
+ ******************************************************************************/
+bool bta_gatts_co_srv_chg(UNUSED_ATTR tBTA_GATTS_SRV_CHG_CMD cmd,
+ UNUSED_ATTR tBTA_GATTS_SRV_CHG_REQ* p_req,
+ UNUSED_ATTR tBTA_GATTS_SRV_CHG_RSP* p_rsp) {
+ /** M: Feature change, read bonded clients configured indication @{ */
+ btif_gatts_srv_chg_cb_t* p_cb = &btif_gatts_srv_chg_cb;
+ switch (cmd) {
+ case GATTS_SRV_CHG_CMD_READ_NUM_CLENTS:
+ p_rsp->num_clients = p_cb->num_clients;
+ return true;
+ case GATTS_SRV_CHG_CMD_READ_CLENT:
+ if (p_req->client_read_index > p_cb->num_clients) return true;
+ memcpy(&p_rsp->srv_chg, &p_cb->srv_chg[p_req->client_read_index - 1],
+ sizeof(tGATTS_SRV_CHG));
+ return true;
+ }
+ /** @} */
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_gatts_co_load_handle_range
+ *
+ * Description This callout function is executed by GATTS when a GATT
+ * server handle range is requested to be loaded from NV.
+ *
+ * Parameter
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+bool bta_gatts_co_load_handle_range(
+ UNUSED_ATTR uint8_t index,
+ UNUSED_ATTR tBTA_GATTS_HNDL_RANGE* p_handle_range) {
+ return false;
+}
diff --git a/mtkbt/code/bt/btif/co/bta_hh_co.cc b/mtkbt/code/bt/btif/co/bta_hh_co.cc
new file mode 100755
index 0000000..f0467ba
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_hh_co.cc
@@ -0,0 +1,679 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/uhid.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#include "bta_api.h"
+#include "bta_hh_api.h"
+#include "bta_hh_co.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_hh.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+const char* dev_path = "/dev/uhid";
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+#include "btif_config.h"
+#define BTA_HH_NV_LOAD_MAX 16
+static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
+#endif
+
+void uhid_set_non_blocking(int fd) {
+ int opts = fcntl(fd, F_GETFL);
+ if (opts < 0)
+ APPL_TRACE_ERROR("%s() Getting flags failed (%s)", __func__,
+ strerror(errno));
+
+ opts |= O_NONBLOCK;
+
+ if (fcntl(fd, F_SETFL, opts) < 0)
+ APPL_TRACE_EVENT("%s() Setting non-blocking flag failed (%s)", __func__,
+ strerror(errno));
+}
+
+/*Internal function to perform UHID write and error checking*/
+static int uhid_write(int fd, const struct uhid_event* ev) {
+ ssize_t ret;
+ OSI_NO_INTR(ret = write(fd, ev, sizeof(*ev)));
+
+ if (ret < 0) {
+ int rtn = -errno;
+ APPL_TRACE_ERROR("%s: Cannot write to uhid:%s", __func__, strerror(errno));
+ return rtn;
+ } else if (ret != (ssize_t)sizeof(*ev)) {
+ APPL_TRACE_ERROR("%s: Wrong size written to uhid: %zd != %zu", __func__,
+ ret, sizeof(*ev));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* Internal function to parse the events received from UHID driver*/
+static int uhid_read_event(btif_hh_device_t* p_dev) {
+ CHECK(p_dev);
+
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = read(p_dev->fd, &ev, sizeof(ev)));
+
+ if (ret == 0) {
+ APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __func__, strerror(errno));
+ return -EFAULT;
+ } else if (ret < 0) {
+ APPL_TRACE_ERROR("%s: Cannot read uhid-cdev: %s", __func__,
+ strerror(errno));
+ return -errno;
+ }
+
+ switch (ev.type) {
+ case UHID_START:
+ APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
+ p_dev->ready_for_data = true;
+ break;
+ case UHID_STOP:
+ APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
+ p_dev->ready_for_data = false;
+ break;
+ case UHID_OPEN:
+ APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
+ p_dev->ready_for_data = true;
+ break;
+ case UHID_CLOSE:
+ APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
+ p_dev->ready_for_data = false;
+ break;
+ case UHID_OUTPUT:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output))) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ __func__, ret, sizeof(ev.type) + sizeof(ev.u.output));
+ return -EFAULT;
+ }
+
+ APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d",
+ ev.u.output.rtype, ev.u.output.size);
+ // Send SET_REPORT with feature report if the report type in output event
+ // is FEATURE
+ if (ev.u.output.rtype == UHID_FEATURE_REPORT)
+ btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT, ev.u.output.size,
+ ev.u.output.data);
+ else if (ev.u.output.rtype == UHID_OUTPUT_REPORT){
+ /**M: duplicate event send will lead current higher than target @{*/
+ if (ev.u.output.size > BTIF_HH_OUTPUT_REPORT_SIZE)
+ {
+ APPL_TRACE_WARNING("UHID_OUTPUT: Invalid report size %d",
+ ev.u.output.size);
+ return 0;
+ }
+ if (ev.u.output.size == BTIF_HH_OUTPUT_REPORT_SIZE &&
+ !memcmp(&p_dev->last_output_rpt_data, &ev.u.output.data,
+ BTIF_HH_OUTPUT_REPORT_SIZE)) {
+ /* Last output report same as current output report, don't inform to remote
+ * device as this could be the case when reports are being sent due to
+ * device suspend/resume. If same output report is sent to remote device
+ * device which uses UART as transport might not be able to suspend at all
+ * leading to higher battery drain.
+ */
+ APPL_TRACE_VERBOSE("UHID_OUTPUT: data same returning");
+ return 0;
+ }
+ /* Copy new output report data for future tracking */
+ memcpy(&p_dev->last_output_rpt_data, &ev.u.output.data, ev.u.output.size);
+ /**@}*/
+ btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size,
+ ev.u.output.data);
+ }
+ else
+ btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.output.size,
+ ev.u.output.data);
+ break;
+ case UHID_OUTPUT_EV:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ __func__, ret,
+ sizeof(ev.type) + sizeof(ev.u.output_ev));
+ return -EFAULT;
+ }
+ APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
+ break;
+ case UHID_FEATURE:
+ APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
+ break;
+ case UHID_FEATURE_ANSWER:
+ APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
+ break;
+ /**M:Feature for Kernel 3.18 or 4.4@{*/
+ case UHID_SET_REPORT:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ __FUNCTION__, ret,
+ sizeof(ev.type) + sizeof(ev.u.output));
+ return -EFAULT;
+ }
+
+ APPL_TRACE_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d"
+ ,ev.u.set_report.rtype, ev.u.set_report.size);
+ //Send SET_REPORT with feature report if the report type in output event is FEATURE
+ if(ev.u.set_report.rtype == UHID_FEATURE_REPORT)
+ btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else if(ev.u.set_report.rtype == UHID_OUTPUT_REPORT)
+ btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else
+ btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ break;
+ /**@}*/
+ default:
+ APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function create_thread
+ *
+ * Description creat a select loop
+ *
+ * Returns pthread_t
+ *
+ ******************************************************************************/
+static inline pthread_t create_thread(void* (*start_routine)(void*),
+ void* arg) {
+ APPL_TRACE_DEBUG("create_thread: entered");
+ pthread_attr_t thread_attr;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ pthread_t thread_id = -1;
+ if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
+ APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
+ return -1;
+ }
+ APPL_TRACE_DEBUG("create_thread: thread created successfully");
+ return thread_id;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_poll_event_thread
+ *
+ * Description the polling thread which polls for event from UHID driver
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void* btif_hh_poll_event_thread(void* arg) {
+ btif_hh_device_t* p_dev = (btif_hh_device_t*)arg;
+ APPL_TRACE_DEBUG("%s: Thread created fd = %d", __func__, p_dev->fd);
+ struct pollfd pfds[1];
+
+ pfds[0].fd = p_dev->fd;
+ pfds[0].events = POLLIN;
+
+ // Set the uhid fd as non-blocking to ensure we never block the BTU thread
+ uhid_set_non_blocking(p_dev->fd);
+
+ while (p_dev->hh_keep_polling) {
+ int ret;
+ OSI_NO_INTR(ret = poll(pfds, 1, 50));
+ if (ret < 0) {
+ APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __func__,
+ strerror(errno));
+ break;
+ }
+ if (pfds[0].revents & POLLIN) {
+ APPL_TRACE_DEBUG("%s: POLLIN", __func__);
+ ret = uhid_read_event(p_dev);
+ if (ret != 0) break;
+ }
+ }
+
+ p_dev->hh_poll_thread_id = -1;
+ return 0;
+}
+
+static inline void btif_hh_close_poll_thread(btif_hh_device_t* p_dev) {
+ APPL_TRACE_DEBUG("%s", __func__);
+ p_dev->hh_keep_polling = 0;
+ if (p_dev->hh_poll_thread_id > 0)
+ pthread_join(p_dev->hh_poll_thread_id, NULL);
+
+ return;
+}
+
+void bta_hh_co_destroy(int fd) {
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_DESTROY;
+ uhid_write(fd, &ev);
+ APPL_TRACE_DEBUG("%s: Closing fd=%d", __func__, fd);
+ close(fd);
+}
+
+int bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len) {
+ APPL_TRACE_VERBOSE("%s: UHID write %d", __func__, len);
+
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ ev.u.input.size = len;
+ if (len > sizeof(ev.u.input.data)) {
+ APPL_TRACE_WARNING("%s: Report size greater than allowed size", __func__);
+ return -1;
+ }
+ memcpy(ev.u.input.data, rpt, len);
+
+ return uhid_write(fd, &ev);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_open
+ *
+ * Description When connection is opened, this call-out function is executed
+ * by HH to do platform specific initialization.
+ *
+ * Returns void.
+ ******************************************************************************/
+void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
+ tBTA_HH_ATTR_MASK attr_mask, uint8_t app_id) {
+ uint32_t i;
+ btif_hh_device_t* p_dev = NULL;
+
+ if (dev_handle == BTA_HH_INVALID_HANDLE) {
+ APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
+ dev_handle);
+ return;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ p_dev->dev_handle == dev_handle) {
+ // We found a device with the same handle. Must be a device reconnected.
+ APPL_TRACE_WARNING(
+ "%s: Found an existing device with the same handle "
+ "dev_status = %d",
+ __func__, p_dev->dev_status);
+ APPL_TRACE_WARNING("%s: bd_addr = [%02X:%02X:%02X:%02X:%02X:]",
+ __func__, p_dev->bd_addr.address[0],
+ p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
+ p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
+ APPL_TRACE_WARNING(
+ "%s: attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
+ __func__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);
+
+ if (p_dev->fd < 0) {
+ p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+ if (p_dev->fd < 0) {
+ APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
+ strerror(errno));
+ return;
+ } else
+ APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+ }
+
+ p_dev->hh_keep_polling = 1;
+ p_dev->hh_poll_thread_id =
+ create_thread(btif_hh_poll_event_thread, p_dev);
+ break;
+ }
+ p_dev = NULL;
+ }
+
+ if (p_dev == NULL) {
+ // Did not find a device reconnection case. Find an empty slot now.
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
+ p_dev = &btif_hh_cb.devices[i];
+ p_dev->dev_handle = dev_handle;
+ p_dev->attr_mask = attr_mask;
+ p_dev->sub_class = sub_class;
+ p_dev->app_id = app_id;
+ p_dev->local_vup = false;
+
+ btif_hh_cb.device_num++;
+ // This is a new device,open the uhid driver now.
+ p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
+ if (p_dev->fd < 0) {
+ APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s", __func__,
+ strerror(errno));
+ return;
+ } else {
+ APPL_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+ p_dev->hh_keep_polling = 1;
+ p_dev->hh_poll_thread_id =
+ create_thread(btif_hh_poll_event_thread, p_dev);
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (p_dev == NULL) {
+ APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __func__);
+ return;
+ }
+ /**M: duplicate event send will lead current higher than target @{*/
+ memset(&p_dev->last_output_rpt_data, 0, BTIF_HH_OUTPUT_REPORT_SIZE);
+ /**@}*/
+ p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_close
+ *
+ * Description When connection is closed, this call-out function is executed
+ * by HH to do platform specific finalization.
+ *
+ * Parameters dev_handle - device handle
+ * app_id - application id
+ *
+ * Returns void.
+ ******************************************************************************/
+void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {
+ uint32_t i;
+ btif_hh_device_t* p_dev = NULL;
+
+ APPL_TRACE_WARNING("%s: dev_handle = %d, app_id = %d", __func__, dev_handle,
+ app_id);
+ if (dev_handle == BTA_HH_INVALID_HANDLE) {
+ APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __func__,
+ dev_handle);
+ return;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ p_dev->dev_handle == dev_handle) {
+ APPL_TRACE_WARNING(
+ "%s: Found an existing device with the same handle "
+ "dev_status = %d, dev_handle =%d",
+ __func__, p_dev->dev_status, p_dev->dev_handle);
+ /**M: duplicate event send will lead current higher than target @{*/
+ memset(&p_dev->last_output_rpt_data, 0, BTIF_HH_OUTPUT_REPORT_SIZE);
+ /**@}*/
+ btif_hh_close_poll_thread(p_dev);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_data
+ *
+ * Description This function is executed by BTA when HID host receive a
+ * data report.
+ *
+ * Parameters dev_handle - device handle
+ * *p_rpt - pointer to the report data
+ * len - length of report data
+ * mode - Hid host Protocol Mode
+ * sub_clas - Device Subclass
+ * app_id - application id
+ *
+ * Returns void
+ ******************************************************************************/
+void bta_hh_co_data(uint8_t dev_handle, uint8_t* p_rpt, uint16_t len,
+ tBTA_HH_PROTO_MODE mode, uint8_t sub_class,
+ uint8_t ctry_code, UNUSED_ATTR BD_ADDR peer_addr,
+ uint8_t app_id) {
+ btif_hh_device_t* p_dev;
+
+ APPL_TRACE_DEBUG(
+ "%s: dev_handle = %d, subclass = 0x%02X, mode = %d, "
+ "ctry_code = %d, app_id = %d",
+ __func__, dev_handle, sub_class, mode, ctry_code, app_id);
+
+ p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
+ if (p_dev == NULL) {
+ APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
+ dev_handle);
+ return;
+ }
+
+ // Wait a maximum of MAX_POLLING_ATTEMPTS x POLLING_SLEEP_DURATION in case
+ // device creation is pending.
+ if (p_dev->fd >= 0) {
+ uint32_t polling_attempts = 0;
+ while (!p_dev->ready_for_data &&
+ polling_attempts++ < BTIF_HH_MAX_POLLING_ATTEMPTS) {
+ usleep(BTIF_HH_POLLING_SLEEP_DURATION_US);
+ }
+ }
+
+ // Send the HID data to the kernel.
+ if ((p_dev->fd >= 0) && p_dev->ready_for_data) {
+ bta_hh_co_write(p_dev->fd, p_rpt, len);
+ } else {
+ APPL_TRACE_WARNING("%s: Error: fd = %d, ready %d, len = %d", __func__,
+ p_dev->fd, p_dev->ready_for_data, len);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_co_send_hid_info
+ *
+ * Description This function is called in btif_hh.c to process DSCP
+ * received.
+ *
+ * Parameters dev_handle - device handle
+ * dscp_len - report descriptor length
+ * *p_dscp - report descriptor
+ *
+ * Returns void
+ ******************************************************************************/
+void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name,
+ uint16_t vendor_id, uint16_t product_id,
+ uint16_t version, uint8_t ctry_code, int dscp_len,
+ uint8_t* p_dscp) {
+ int result;
+ struct uhid_event ev;
+ /**M:It is a workround hor some HID device @{*/
+ uint8_t temp_buffer_IOT[1024];
+ /**@}*/
+ if (p_dev->fd < 0) {
+ APPL_TRACE_WARNING("%s: Error: fd = %d, dscp_len = %d", __func__, p_dev->fd,
+ dscp_len);
+ return;
+ }
+
+ APPL_TRACE_WARNING("%s: fd = %d, name = [%s], dscp_len = %d", __func__,
+ p_dev->fd, dev_name, dscp_len);
+ APPL_TRACE_WARNING(
+ "%s: vendor_id = 0x%04x, product_id = 0x%04x, version= 0x%04x,"
+ "ctry_code=0x%02x",
+ __func__, vendor_id, product_id, version, ctry_code);
+
+ // Create and send hid descriptor to kernel
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+ strncpy((char*)ev.u.create.name, dev_name, sizeof(ev.u.create.name) - 1);
+ snprintf((char*)ev.u.create.uniq, sizeof(ev.u.create.uniq),
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", p_dev->bd_addr.address[5],
+ p_dev->bd_addr.address[4], p_dev->bd_addr.address[3],
+ p_dev->bd_addr.address[2], p_dev->bd_addr.address[1],
+ p_dev->bd_addr.address[0]);
+ ev.u.create.rd_size = dscp_len;
+ ev.u.create.rd_data = p_dscp;
+ /**M: workround for some special device @{*/
+ //workaround for Logitech M557
+ if(vendor_id == 0x046d && product_id == 0xb010 && dscp_len >= 149)
+ {
+ ev.u.create.rd_size = 149;
+ }
+ //workaround for ThinkPad Bluetooth Touch Mouse
+ if(vendor_id == 0x17ef && product_id == 0x6063 && dscp_len >= 170)
+ {
+ memcpy(temp_buffer_IOT, p_dscp, 66);
+ memcpy(temp_buffer_IOT+66, p_dscp+134, 36);
+
+ ev.u.create.rd_size = 102;
+ ev.u.create.rd_data = temp_buffer_IOT;
+ }
+ //workaround for Microsoft Sculpt Comfort Mouse
+ if(vendor_id == 0x045e && product_id == 0x07a2 && dscp_len >= 311)
+ {
+ ev.u.create.rd_size = 311;
+ }
+ /**@}*/
+ ev.u.create.bus = BUS_BLUETOOTH;
+ ev.u.create.vendor = vendor_id;
+ ev.u.create.product = product_id;
+ ev.u.create.version = version;
+ ev.u.create.country = ctry_code;
+ result = uhid_write(p_dev->fd, &ev);
+
+ APPL_TRACE_WARNING(
+ "%s: wrote descriptor to fd = %d, dscp_len = %d, result = %d", __func__,
+ p_dev->fd, dscp_len, result);
+
+ if (result) {
+ APPL_TRACE_WARNING("%s: Error: failed to send DSCP, result = %d", __func__,
+ result);
+
+ /* The HID report descriptor is corrupted. Close the driver. */
+ close(p_dev->fd);
+ p_dev->fd = -1;
+ }
+}
+
+#if (BTA_HH_LE_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_rpt_info
+ *
+ * Description This callout function is to convey the report information on
+ * a HOGP device to the application. Application can save this
+ * information in NV if device is bonded and load it back when
+ * stack reboot.
+ *
+ * Parameters remote_bda - remote device address
+ * p_entry - report entry pointer
+ * app_id - application id
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void bta_hh_le_co_rpt_info(BD_ADDR remote_bda, tBTA_HH_RPT_CACHE_ENTRY* p_entry,
+ UNUSED_ATTR uint8_t app_id) {
+ unsigned idx = 0;
+
+ bdstr_t bdstr;
+ snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+ remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+ remote_bda[5]);
+
+ size_t len = btif_config_get_bin_length(bdstr, "HidReport");
+ if (len >= sizeof(tBTA_HH_RPT_CACHE_ENTRY) && len <= sizeof(sReportCache)) {
+ btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
+ idx = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
+ }
+
+ if (idx < BTA_HH_NV_LOAD_MAX) {
+ memcpy(&sReportCache[idx++], p_entry, sizeof(tBTA_HH_RPT_CACHE_ENTRY));
+ btif_config_set_bin(bdstr, "HidReport", (const uint8_t*)sReportCache,
+ idx * sizeof(tBTA_HH_RPT_CACHE_ENTRY));
+ BTIF_TRACE_DEBUG("%s() - Saving report; dev=%s, idx=%d", __func__, bdstr,
+ idx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_cache_load
+ *
+ * Description This callout function is to request the application to load
+ * the cached HOGP report if there is any. When cache reading
+ * is completed, bta_hh_le_ci_cache_load() is called by the
+ * application.
+ *
+ * Parameters remote_bda - remote device address
+ * p_num_rpt: number of cached report
+ * app_id - application id
+ *
+ * Returns the acched report array
+ *
+ ******************************************************************************/
+tBTA_HH_RPT_CACHE_ENTRY* bta_hh_le_co_cache_load(BD_ADDR remote_bda,
+ uint8_t* p_num_rpt,
+ UNUSED_ATTR uint8_t app_id) {
+ bdstr_t bdstr;
+ snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+ remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+ remote_bda[5]);
+
+ size_t len = btif_config_get_bin_length(bdstr, "HidReport");
+ if (!p_num_rpt && len < sizeof(tBTA_HH_RPT_CACHE_ENTRY)) return NULL;
+
+ if (len > sizeof(sReportCache)) len = sizeof(sReportCache);
+ btif_config_get_bin(bdstr, "HidReport", (uint8_t*)sReportCache, &len);
+ *p_num_rpt = len / sizeof(tBTA_HH_RPT_CACHE_ENTRY);
+
+ BTIF_TRACE_DEBUG("%s() - Loaded %d reports; dev=%s", __func__, *p_num_rpt,
+ bdstr);
+
+ return sReportCache;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hh_le_co_reset_rpt_cache
+ *
+ * Description This callout function is to reset the HOGP device cache.
+ *
+ * Parameters remote_bda - remote device address
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void bta_hh_le_co_reset_rpt_cache(BD_ADDR remote_bda,
+ UNUSED_ATTR uint8_t app_id) {
+ bdstr_t bdstr;
+ snprintf(bdstr, sizeof(bdstr), "%02x:%02x:%02x:%02x:%02x:%02x", remote_bda[0],
+ remote_bda[1], remote_bda[2], remote_bda[3], remote_bda[4],
+ remote_bda[5]);
+ btif_config_remove(bdstr, "HidReport");
+
+ BTIF_TRACE_DEBUG("%s() - Reset cache for bda %s", __func__, bdstr);
+}
+
+#endif // (BTA_HH_LE_INCLUDED == TRUE)
diff --git a/mtkbt/code/bt/btif/co/bta_hl_co.cc b/mtkbt/code/bt/btif/co/bta_hl_co.cc
new file mode 100755
index 0000000..a4ddbb6
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_hl_co.cc
@@ -0,0 +1,415 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the HeaLth device profile (HL)
+ * subsystem call-out functions.
+ *
+ ******************************************************************************/
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include "bta_api.h"
+#include "bta_hl_api.h"
+#include "bta_hl_ci.h"
+#include "bta_hl_co.h"
+#include "bta_sys.h"
+#include "btif_hl.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * Constants and Data Types
+ ****************************************************************************/
+/**************************
+ * Common Definitions
+ **************************/
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_num_of_mdep
+ *
+ * Description This function is called to get the number of MDEPs for this
+ * application ID
+ *
+ * Parameters app_id - application ID
+ * p_num_of_mdep (output) - number of MDEP configurations
+ * supported by the application
+ *
+ * Returns true on success
+ *
+ ******************************************************************************/
+bool bta_hl_co_get_num_of_mdep(uint8_t app_id, uint8_t* p_num_of_mdep) {
+ uint8_t app_idx;
+ bool success = false;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ *p_num_of_mdep = p_btif_hl_cb->acb[app_idx].sup_feature.num_of_mdeps;
+ success = true;
+ }
+
+ BTIF_TRACE_DEBUG("%s success=%d num_mdeps=%d", __func__, success,
+ *p_num_of_mdep);
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_advrtise_source_sdp
+ *
+ * Description This function is called to find out whether the SOURCE MDEP
+ * configuration information should be advertise in the SDP or
+ * not.
+ *
+ * Parameters app_id - application ID
+ *
+ * Returns true when advertise the SOURCE MDEP configuration
+ * information
+ *
+ ******************************************************************************/
+bool bta_hl_co_advrtise_source_sdp(uint8_t app_id) {
+ bool advertize_source_sdp = false;
+ uint8_t app_idx;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ advertize_source_sdp =
+ p_btif_hl_cb->acb[app_idx].sup_feature.advertize_source_sdp;
+ }
+
+ BTIF_TRACE_DEBUG("%s advertize_flag=%d", __func__, advertize_source_sdp);
+
+ return advertize_source_sdp;
+}
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_mdep_config
+ *
+ * Description This function is called to get the supported feature
+ * configuration for the specified mdep index and it also
+ * assigns the MDEP ID for the specified mdep index
+ *
+ * Parameters app_id - HDP application ID
+ * mdep_idx - the mdep index
+ * mdep_counter - number of mdeps
+ * mdep_id - the assigned MDEP ID for the specified medp_idx
+ * p_mdl_cfg (output) - pointer to the MDEP configuration
+ *
+ *
+ * Returns Bloolean - true success
+ ******************************************************************************/
+bool bta_hl_co_get_mdep_config(uint8_t app_id, uint8_t mdep_idx,
+ uint8_t mdep_counter, tBTA_HL_MDEP_ID mdep_id,
+ tBTA_HL_MDEP_CFG* p_mdep_cfg) {
+ uint8_t idx;
+ uint8_t app_idx;
+ bool success = false;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d mdep_idx=%d mdep_id=%d mdep_counter=%d",
+ __func__, app_id, mdep_idx, mdep_id, mdep_counter);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ idx = mdep_idx - mdep_counter - 1;
+ p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_id = mdep_id;
+ memcpy(p_mdep_cfg,
+ &p_btif_hl_cb->acb[app_idx].sup_feature.mdep[idx].mdep_cfg,
+ sizeof(tBTA_HL_MDEP_CFG));
+
+ success = true;
+ }
+
+ BTIF_TRACE_DEBUG("%s success=%d mdep_idx=%d mdep_id=%d", __func__, success,
+ mdep_idx, mdep_id);
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_echo_config
+ *
+ * Description This function is called to get the echo test
+ * maximum APDU size configurations
+ *
+ * Parameters app_id - HDP application ID
+ * p_echo_cfg (output) - pointer to the Echo test maximum APDU
+ * size configuration
+ *
+ * Returns Bloolean - true success
+ ******************************************************************************/
+bool bta_hl_co_get_echo_config(uint8_t app_id, tBTA_HL_ECHO_CFG* p_echo_cfg) {
+ uint8_t app_idx;
+ bool success = false;
+ btif_hl_app_cb_t* p_acb;
+ tBTA_HL_SUP_FEATURE* p_sup;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d", __func__, app_id);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_sup = &p_acb->sup_feature;
+ p_echo_cfg->max_rx_apdu_size = p_sup->echo_cfg.max_rx_apdu_size;
+ p_echo_cfg->max_tx_apdu_size = p_sup->echo_cfg.max_tx_apdu_size;
+ success = true;
+ }
+
+ BTIF_TRACE_DEBUG("%s success=%d max tx_size=%d rx_size=%d", __func__, success,
+ p_echo_cfg->max_tx_apdu_size, p_echo_cfg->max_rx_apdu_size);
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_save_mdl
+ *
+ * Description This function is called to save a MDL configuration item in
+ * persistent storage
+ *
+ * Parameters app_id - HDP application ID
+ * item_idx - the MDL configuration storage index
+ * p_mdl_cfg - pointer to the MDL configuration data
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_co_save_mdl(uint8_t mdep_id, uint8_t item_idx,
+ tBTA_HL_MDL_CFG* p_mdl_cfg) {
+ BTIF_TRACE_DEBUG("%s mdep_id =%d, item_idx=%d active=%d mdl_id=%d time=%d",
+ __func__, mdep_id, item_idx, p_mdl_cfg->active,
+ p_mdl_cfg->mdl_id, p_mdl_cfg->time);
+
+ btif_hl_save_mdl_cfg(mdep_id, item_idx, p_mdl_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_delete_mdl
+ *
+ * Description This function is called to delete a MDL configuration item in
+ * persistent storage
+ *
+ * Parameters app_id - HDP application ID
+ * item_idx - the MDL configuration storage index
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_hl_co_delete_mdl(uint8_t mdep_id, uint8_t item_idx) {
+ BTIF_TRACE_DEBUG("%s mdep_id=%d, item_idx=%d", __func__, mdep_id, item_idx);
+
+ btif_hl_delete_mdl_cfg(mdep_id, item_idx);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_mdl_config
+ *
+ * Description This function is called to get the MDL configuration
+ * from the persistent memory. This function shall only be
+ * called once after the device is powered up
+ *
+ * Parameters app_id - HDP application ID
+ * buffer_size - the unit of the buffer size is
+ * sizeof(tBTA_HL_MDL_CFG)
+ * p_mdl_buf - Point to the starting location of the buffer
+ *
+ * Returns bool
+ *
+ *
+ ******************************************************************************/
+bool bta_hl_co_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+ tBTA_HL_MDL_CFG* p_mdl_buf) {
+ bool result = true;
+ uint8_t i;
+ tBTA_HL_MDL_CFG* p;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d, num_items=%d", __func__, app_id, buffer_size);
+
+ if (buffer_size > BTA_HL_NUM_MDL_CFGS) {
+ result = false;
+ return result;
+ }
+ result = btif_hl_load_mdl_config(app_id, buffer_size, p_mdl_buf);
+
+ if (result) {
+ for (i = 0, p = p_mdl_buf; i < buffer_size; i++, p++) {
+ if (p->active) {
+ BTIF_TRACE_DEBUG(
+ "i=%d mdl_id=0x%x dch_mode=%d local mdep_role=%d mdep_id=%d mtu=%d",
+ i, p->mdl_id, p->dch_mode, p->local_mdep_role, p->local_mdep_role,
+ p->mtu);
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s success=%d num_items=%d", __func__, result, buffer_size);
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_tx_data
+ *
+ * Description Get the data to be sent
+ *
+ * Parameters app_id - HDP application ID
+ * mdl_handle - MDL handle
+ * buf_size - the size of the buffer
+ * p_buf - the buffer pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void bta_hl_co_get_tx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ uint16_t buf_size, uint8_t* p_buf, uint16_t evt) {
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t* p_dcb;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x buf_size=%d", __func__, app_id,
+ mdl_handle, buf_size);
+
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+ &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if ((p_dcb->tx_size <= buf_size) && p_dcb->p_tx_pkt) {
+ memcpy(p_buf, p_dcb->p_tx_pkt, p_dcb->tx_size);
+ osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+ p_dcb->tx_size = 0;
+ status = BTA_HL_STATUS_OK;
+ }
+ }
+
+ bta_hl_ci_get_tx_data(mdl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_put_rx_data
+ *
+ * Description Put the received data
+ *
+ * Parameters app_id - HDP application ID
+ * mdl_handle - MDL handle
+ * data_size - the size of the data
+ * p_data - the data pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_put_rx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void bta_hl_co_put_rx_data(uint8_t app_id, tBTA_HL_MDL_HANDLE mdl_handle,
+ uint16_t data_size, uint8_t* p_data, uint16_t evt) {
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t* p_dcb;
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s app_id=%d mdl_handle=0x%x data_size=%d", __func__,
+ app_id, mdl_handle, data_size);
+
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+ &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ p_dcb->p_rx_pkt = (uint8_t*)osi_malloc(data_size);
+ memcpy(p_dcb->p_rx_pkt, p_data, data_size);
+ if (p_dcb->p_scb) {
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=0x%x mdl_idx=0x%x data_size=%d",
+ app_idx, mcl_idx, mdl_idx, data_size);
+ ssize_t r;
+ OSI_NO_INTR(
+ r = send(p_dcb->p_scb->socket_id[1], p_dcb->p_rx_pkt, data_size, 0));
+ if (r == data_size) {
+ BTIF_TRACE_DEBUG("socket send success data_size=%d", data_size);
+ status = BTA_HL_STATUS_OK;
+ } else {
+ BTIF_TRACE_ERROR("socket send failed r=%d data_size=%d", r, data_size);
+ }
+ }
+ osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+ }
+
+ bta_hl_ci_put_rx_data(mdl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_get_tx_data
+ *
+ * Description Get the Echo data to be sent
+ *
+ * Parameters app_id - HDP application ID
+ * mcl_handle - MCL handle
+ * buf_size - the size of the buffer
+ * p_buf - the buffer pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_get_tx_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void bta_hl_co_get_echo_data(UNUSED_ATTR uint8_t app_id,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ UNUSED_ATTR uint16_t buf_size,
+ UNUSED_ATTR uint8_t* p_buf, uint16_t evt) {
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_ERROR("%s not supported", __func__);
+ bta_hl_ci_get_echo_data(mcl_handle, status, evt);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hl_co_put_echo_data
+ *
+ * Description Put the received loopback echo data
+ *
+ * Parameters app_id - HDP application ID
+ * mcl_handle - MCL handle
+ * data_size - the size of the data
+ * p_data - the data pointer
+ * evt - the evt to be passed back to the HL in the
+ * bta_hl_ci_put_echo_data call-in function
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void bta_hl_co_put_echo_data(UNUSED_ATTR uint8_t app_id,
+ tBTA_HL_MCL_HANDLE mcl_handle,
+ UNUSED_ATTR uint16_t data_size,
+ UNUSED_ATTR uint8_t* p_data, uint16_t evt) {
+ tBTA_HL_STATUS status = BTA_HL_STATUS_FAIL;
+
+ BTIF_TRACE_ERROR("%s not supported", __func__);
+ bta_hl_ci_put_echo_data(mcl_handle, status, evt);
+}
diff --git a/mtkbt/code/bt/btif/co/bta_pan_co.cc b/mtkbt/code/bt/btif/co/bta_pan_co.cc
new file mode 100755
index 0000000..ea5231a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/co/bta_pan_co.cc
@@ -0,0 +1,316 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bta_pan_co.c
+ *
+ * Description: PAN stack callout api
+ *
+ *
+ ******************************************************************************/
+#include "bta_pan_co.h"
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+#include <string.h>
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "bta_pan_ci.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_pan_internal.h"
+#include "btif_sock_thread.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_init
+ *
+ * Description
+ *
+ *
+ * Returns Data flow mask.
+ *
+ ******************************************************************************/
+uint8_t bta_pan_co_init(uint8_t* q_level) {
+ BTIF_TRACE_API("bta_pan_co_init");
+
+ /* set the q_level to 30 buffers */
+ *q_level = 30;
+
+ // return (BTA_PAN_RX_PULL | BTA_PAN_TX_PULL);
+ return (BTA_PAN_RX_PUSH_BUF | BTA_PAN_RX_PUSH | BTA_PAN_TX_PULL);
+}
+
+/******************************************************************************
+ *
+ * Function bta_pan_co_open
+ *
+ * Description
+ *
+ *
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_open(uint16_t handle, uint8_t app_id, tBTA_PAN_ROLE local_role,
+ tBTA_PAN_ROLE peer_role, BD_ADDR peer_addr) {
+ BTIF_TRACE_API(
+ "bta_pan_co_open:app_id:%d, local_role:%d, peer_role:%d, "
+ "handle:%d",
+ app_id, local_role, peer_role, handle);
+ btpan_conn_t* conn = btpan_find_conn_addr(peer_addr);
+ if (conn == NULL)
+ conn = btpan_new_conn(handle, peer_addr, local_role, peer_role);
+ if (conn) {
+ BTIF_TRACE_DEBUG(
+ "bta_pan_co_open:tap_fd:%d, open_count:%d, "
+ "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+ btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, handle,
+ conn->local_role, conn->remote_role);
+ // refresh the role & bt address
+
+ btpan_cb.open_count++;
+ conn->handle = handle;
+ // bdcpy(conn->peer, peer_addr);
+ if (btpan_cb.tap_fd < 0) {
+ btpan_cb.tap_fd = btpan_tap_open();
+ if (btpan_cb.tap_fd >= 0) create_tap_read_thread(btpan_cb.tap_fd);
+ }
+ if (btpan_cb.tap_fd >= 0) {
+ btpan_cb.flow = 1;
+ conn->state = PAN_STATE_OPEN;
+ bta_pan_ci_rx_ready(handle);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_close
+ *
+ * Description This function is called by PAN when a connection to a
+ * peer is closed.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_close(uint16_t handle, uint8_t app_id) {
+ BTIF_TRACE_API("bta_pan_co_close:app_id:%d, handle:%d", app_id, handle);
+ btpan_conn_t* conn = btpan_find_conn_handle(handle);
+ if (conn && conn->state == PAN_STATE_OPEN) {
+ BTIF_TRACE_DEBUG("bta_pan_co_close");
+
+ // let bta close event reset this handle as it needs
+ // the handle to find the connection upon CLOSE
+ // conn->handle = -1;
+ conn->state = PAN_STATE_CLOSE;
+ btpan_cb.open_count--;
+
+ if (btpan_cb.open_count == 0 && btpan_cb.tap_fd != -1) {
+ btpan_tap_close(btpan_cb.tap_fd);
+ btpan_cb.tap_fd = -1;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_path
+ *
+ * Description This function is called by PAN to transfer data on the
+ * TX path; that is, data being sent from BTA to the phone.
+ * This function is used when the TX data path is configured
+ * to use the pull interface. The implementation of this
+ * function will typically call Bluetooth stack functions
+ * PORT_Read() or PORT_ReadData() to read data from RFCOMM
+ * and then a platform-specific function to send data that
+ * data to the phone.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_path(uint16_t handle, uint8_t app_id) {
+ BT_HDR* p_buf;
+ BD_ADDR src;
+ BD_ADDR dst;
+ uint16_t protocol;
+ bool ext;
+ bool forward;
+
+ BTIF_TRACE_API("%s, handle:%d, app_id:%d", __func__, handle, app_id);
+
+ btpan_conn_t* conn = btpan_find_conn_handle(handle);
+ if (!conn) {
+ BTIF_TRACE_ERROR("%s: cannot find pan connection", __func__);
+ return;
+ } else if (conn->state != PAN_STATE_OPEN) {
+ BTIF_TRACE_ERROR("%s: conn is not opened, conn:%p, conn->state:%d",
+ __func__, conn, conn->state);
+ return;
+ }
+
+ do {
+ /* read next data buffer from pan */
+ p_buf = bta_pan_ci_readbuf(handle, src, dst, &protocol, &ext, &forward);
+ if (p_buf) {
+ bdstr_t bdstr;
+ BTIF_TRACE_DEBUG(
+ "%s, calling btapp_tap_send, "
+ "p_buf->len:%d, offset:%d",
+ __func__, p_buf->len, p_buf->offset);
+ if (is_empty_eth_addr(conn->eth_addr) && is_valid_bt_eth_addr(src)) {
+ BTIF_TRACE_DEBUG(
+ "%s pan bt peer addr: %s", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)conn->peer, bdstr, sizeof(bdstr)));
+ bdaddr_to_string((bt_bdaddr_t*)src, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG(
+ "%s: update its ethernet addr: %s", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)src, bdstr, sizeof(bdstr)));
+ memcpy(conn->eth_addr, src, sizeof(conn->eth_addr));
+ }
+ btpan_tap_send(btpan_cb.tap_fd, src, dst, protocol,
+ (char*)(p_buf + 1) + p_buf->offset, p_buf->len, ext,
+ forward);
+ osi_free(p_buf);
+ }
+
+ } while (p_buf != NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_rx_path
+ *
+ * Description
+ *
+ *
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_rx_path(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR uint8_t app_id) {
+ BTIF_TRACE_API("bta_pan_co_rx_path not used");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_write
+ *
+ * Description This function is called by PAN to send data to the phone
+ * when the TX path is configured to use a push interface.
+ * The implementation of this function must copy the data to
+ * the phone's memory.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_write(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR uint8_t app_id, UNUSED_ATTR BD_ADDR src,
+ UNUSED_ATTR BD_ADDR dst, UNUSED_ATTR uint16_t protocol,
+ UNUSED_ATTR uint8_t* p_data, UNUSED_ATTR uint16_t len,
+ UNUSED_ATTR bool ext, UNUSED_ATTR bool forward) {
+ BTIF_TRACE_API("bta_pan_co_tx_write not used");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_tx_writebuf
+ *
+ * Description This function is called by PAN to send data to the phone
+ * when the TX path is configured to use a push interface with
+ * zero copy. The phone must free the buffer using function
+ * osi_free() when it is through processing the buffer.
+ *
+ *
+ * Returns true if flow enabled
+ *
+ ******************************************************************************/
+void bta_pan_co_tx_writebuf(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR uint8_t app_id, UNUSED_ATTR BD_ADDR src,
+ UNUSED_ATTR BD_ADDR dst,
+ UNUSED_ATTR uint16_t protocol,
+ UNUSED_ATTR BT_HDR* p_buf, UNUSED_ATTR bool ext,
+ UNUSED_ATTR bool forward) {
+ BTIF_TRACE_API("bta_pan_co_tx_writebuf not used");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_rx_flow
+ *
+ * Description This function is called by PAN to enable or disable
+ * data flow on the RX path when it is configured to use
+ * a push interface. If data flow is disabled the phone must
+ * not call bta_pan_ci_rx_write() or bta_pan_ci_rx_writebuf()
+ * until data flow is enabled again.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_rx_flow(UNUSED_ATTR uint16_t handle, UNUSED_ATTR uint8_t app_id,
+ UNUSED_ATTR bool enable) {
+ BTIF_TRACE_API("bta_pan_co_rx_flow, enabled:%d, not used", enable);
+ btpan_conn_t* conn = btpan_find_conn_handle(handle);
+ if (!conn || conn->state != PAN_STATE_OPEN) return;
+ btpan_set_flow_control(enable);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_filt_ind
+ *
+ * Description protocol filter indication from peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_pfilt_ind(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR bool indication,
+ UNUSED_ATTR tBTA_PAN_STATUS result,
+ UNUSED_ATTR uint16_t len,
+ UNUSED_ATTR uint8_t* p_filters) {
+ BTIF_TRACE_API("bta_pan_co_pfilt_ind");
+}
+
+/*******************************************************************************
+ *
+ * Function bta_pan_co_mfilt_ind
+ *
+ * Description multicast filter indication from peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bta_pan_co_mfilt_ind(UNUSED_ATTR uint16_t handle,
+ UNUSED_ATTR bool indication,
+ UNUSED_ATTR tBTA_PAN_STATUS result,
+ UNUSED_ATTR uint16_t len,
+ UNUSED_ATTR uint8_t* p_filters) {
+ BTIF_TRACE_API("bta_pan_co_mfilt_ind");
+}
diff --git a/mtkbt/code/bt/btif/include/btif_a2dp.h b/mtkbt/code/bt/btif/include/btif_a2dp.h
new file mode 100755
index 0000000..26f370a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_a2dp.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_H
+#define BTIF_A2DP_H
+
+#include <stdbool.h>
+
+#include "bta_av_api.h"
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_on_idle(void);
+
+// Process 'start' request from the BTIF state machine to prepare for A2DP
+// streaming.
+// |p_av_start| is the data associated with the request - see |tBTA_AV_START|.
+// |pending_start| should be set to true if the BTIF state machine is in
+// 'pending start' state.
+// Returns true if an ACK for the local command was sent, otherwise false.
+bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'offload start' request from the BTIF state machine to start
+// offloading of the A2DP streaming.
+// |status| is the processing status of the request prior to this call.
+// The value can be |BTA_AV_SUCCESS| if the processing has been successful
+// so far, or |BTA_AV_FAIL*| if the request has already failed.
+void btif_a2dp_on_offload_started(tBTA_AV_STATUS status);
+
+// Dump debug-related information for the A2DP module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_debug_a2dp_dump(int fd);
+
+#endif /* BTIF_A2DP_H */
diff --git a/mtkbt/code/bt/btif/include/btif_a2dp_control.h b/mtkbt/code/bt/btif/include/btif_a2dp_control.h
new file mode 100755
index 0000000..4e59990
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_a2dp_control.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_CONTROL_H
+#define BTIF_A2DP_CONTROL_H
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+
+// Initialize the A2DP control module. It should be called during the
+// startup stage of A2DP streaming.
+void btif_a2dp_control_init(void);
+
+// Cleanup the A2DP control module. It should be called during the shutdown
+// stage of A2DP streaming.
+void btif_a2dp_control_cleanup(void);
+
+// Acknowledge A2DP command to the origin of audio streaming.
+// |status| is the acknowledement status - see |tA2DP_CTRL_ACK|.
+void btif_a2dp_command_ack(tA2DP_CTRL_ACK status);
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/*******************************************************************************
+ **
+ ** Function btif_media_av_delay_start_cmd_hdlr
+ **
+ ** Description It the call back function which need delay send A2DP
+ ** START cmd for special device(ex. Tiggo5).
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+extern void btif_media_av_delay_start_cmd_hdlr(void *data);
+#endif
+
+#endif /* BTIF_A2DP_CONTROL_H */
diff --git a/mtkbt/code/bt/btif/include/btif_a2dp_sink.h b/mtkbt/code/bt/btif/include/btif_a2dp_sink.h
new file mode 100755
index 0000000..5057a39
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_a2dp_sink.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_SINK_H
+#define BTIF_A2DP_SINK_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "bt_types.h"
+#include "bta_av_api.h"
+
+//
+// Audio focus state for audio track.
+//
+// NOTE: The values must be same as:
+// - A2dpSinkStreamingStateMachine.STATE_FOCUS_LOST = 0
+// - A2dpSinkStreamingStateMachine.STATE_FOCUS_GRANTED = 1
+//
+typedef enum {
+ BTIF_A2DP_SINK_FOCUS_NOT_GRANTED = 0,
+ BTIF_A2DP_SINK_FOCUS_GRANTED = 1
+} btif_a2dp_sink_focus_state_t;
+
+// Initialize and startup the A2DP Sink module.
+// This function should be called by the BTIF state machine prior to using the
+// module.
+bool btif_a2dp_sink_startup(void);
+
+// Shutdown and cleanup the A2DP Sink module.
+// This function should be called by the BTIF state machine during
+// graceful shutdown and cleanup.
+void btif_a2dp_sink_shutdown(void);
+
+// Get the audio sample rate for the A2DP Sink module.
+tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void);
+
+// Get the audio channel count for the A2DP Sink module.
+tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void);
+
+// Update the decoder for the A2DP Sink module.
+// |p_codec_info| contains the new codec information.
+void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info);
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_sink_on_idle(void);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_sink_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_sink_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Enable/disable discarding of received A2DP frames.
+// If |enable| is true, the discarding is enabled, otherwise is disabled.
+void btif_a2dp_sink_set_rx_flush(bool enable);
+
+// Enqueue a buffer to the A2DP Sink queue. If the queue has reached its
+// maximum size |MAX_INPUT_A2DP_FRAME_QUEUE_SZ|, the oldest buffer is
+// removed from the queue.
+// |p_buf| is the buffer to enqueue.
+// Returns the number of buffers in the Sink queue after the enqueing.
+uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_buf);
+
+// Dump debug-related information for the A2DP Sink module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_a2dp_sink_debug_dump(int fd);
+
+// Update the A2DP Sink related metrics.
+// This function should be called before collecting the metrics.
+void btif_a2dp_sink_update_metrics(void);
+
+// Create a request to set the audio focus state for the audio track.
+// |state| is the new state value - see |btif_a2dp_sink_focus_state_t|
+// for valid values.
+void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state);
+
+// Set the audio track gain for the audio track.
+// |gain| is the audio track gain value to use.
+void btif_a2dp_sink_set_audio_track_gain(float gain);
+
+#endif /* BTIF_A2DP_SINK_H */
diff --git a/mtkbt/code/bt/btif/include/btif_a2dp_source.h b/mtkbt/code/bt/btif/include/btif_a2dp_source.h
new file mode 100755
index 0000000..2f1763d
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_a2dp_source.h
@@ -0,0 +1,102 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_A2DP_SOURCE_H
+#define BTIF_A2DP_SOURCE_H
+
+#include <stdbool.h>
+
+#include "bta_av_api.h"
+
+// Initialize and startup the A2DP Source module.
+// This function should be called by the BTIF state machine prior to using the
+// module.
+bool btif_a2dp_source_startup(void);
+
+// Shutdown and cleanup the A2DP Source module.
+// This function should be called by the BTIF state machine during
+// graceful shutdown and cleanup.
+void btif_a2dp_source_shutdown(void);
+
+// Check whether the A2DP Source media task is running.
+// Returns true if the A2DP Source media task is running, otherwise false.
+bool btif_a2dp_source_media_task_is_running(void);
+
+// Check whether the A2DP Source media task is shutting down.
+// Returns true if the A2DP Source media task is shutting down.
+bool btif_a2dp_source_media_task_is_shutting_down(void);
+
+// Return true if the A2DP Source module is streaming.
+bool btif_a2dp_source_is_streaming(void);
+
+// Setup the A2DP Source codec, and prepare the encoder.
+// This function should be called prior to starting A2DP streaming.
+void btif_a2dp_source_setup_codec(void);
+
+// Process a request to start the A2DP audio encoding task.
+void btif_a2dp_source_start_audio_req(void);
+
+// Process a request to stop the A2DP audio encoding task.
+void btif_a2dp_source_stop_audio_req(void);
+
+// Process a request to update the A2DP audio encoder with user preferred
+// codec configuration.
+// |codec_user_config| contains the preferred codec user configuration.
+void btif_a2dp_source_encoder_user_config_update_req(
+ const btav_a2dp_codec_config_t& codec_user_config);
+
+// Process a request to update the A2DP audio encoding with new audio
+// configuration feeding parameters stored in |codec_audio_config|.
+// The fields that are used are: |codec_audio_config.sample_rate|,
+// |codec_audio_config.bits_per_sample| and |codec_audio_config.channel_mode|.
+void btif_a2dp_source_feeding_update_req(
+ const btav_a2dp_codec_config_t& codec_audio_config);
+
+// Process 'idle' request from the BTIF state machine during initialization.
+void btif_a2dp_source_on_idle(void);
+
+// Process 'stop' request from the BTIF state machine to stop A2DP streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Process 'suspend' request from the BTIF state machine to suspend A2DP
+// streaming.
+// |p_av_suspend| is the data associated with the request - see
+// |tBTA_AV_SUSPEND|.
+void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend);
+
+// Enable/disable discarding of transmitted frames.
+// If |enable| is true, the discarding is enabled, otherwise is disabled.
+void btif_a2dp_source_set_tx_flush(bool enable);
+
+// Get the next A2DP buffer to send.
+// Returns the next A2DP buffer to send if available, otherwise NULL.
+BT_HDR* btif_a2dp_source_audio_readbuf(void);
+
+// Dump debug-related information for the A2DP Source module.
+// |fd| is the file descriptor to use for writing the ASCII formatted
+// information.
+void btif_a2dp_source_debug_dump(int fd);
+
+// Update the A2DP Source related metrics.
+// This function should be called before collecting the metrics.
+void btif_a2dp_source_update_metrics(void);
+
+#endif /* BTIF_A2DP_SOURCE_H */
diff --git a/mtkbt/code/bt/btif/include/btif_api.h b/mtkbt/code/bt/btif/include/btif_api.h
new file mode 100755
index 0000000..e066b83
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_api.h
@@ -0,0 +1,425 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_api.h
+ *
+ * Description: Main API header file for all BTIF functions accessed
+ * from main bluetooth HAL. All HAL extensions will not
+ * require headerfiles as they would be accessed through
+ * callout/callins.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_API_H
+#define BTIF_API_H
+
+#include <hardware/bluetooth.h>
+
+#include "btif_common.h"
+#include "btif_dm.h"
+
+/*******************************************************************************
+ * BTIF CORE API
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_init_bluetooth
+ *
+ * Description Creates BTIF task and prepares BT scheduler for startup
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_init_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function btif_enable_bluetooth
+ *
+ * Description Performs chip power on and kickstarts OS scheduler
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_enable_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function btif_disable_bluetooth
+ *
+ * Description Inititates shutdown of Bluetooth system.
+ * Any active links will be dropped and device entering
+ * non connectable/discoverable mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function btif_cleanup_bluetooth
+ *
+ * Description Cleanup BTIF state.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bt_status_t btif_cleanup_bluetooth(void);
+
+/*******************************************************************************
+ *
+ * Function is_restricted_mode
+ *
+ * Description Checks if BT was enabled in restriced mode. In restricted
+ * mode, bonds that are created are marked as temporary.
+ * These bonds persist until we leave restricted mode, at
+ * which point they will be deleted from the config. Also
+ * while in restricted mode, the user can access devices
+ * that are already paired before entering restricted mode,
+ * but they cannot remove any of these devices.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool is_restricted_mode(void);
+
+/*******************************************************************************
+ *
+ * Function btif_get_adapter_properties
+ *
+ * Description Fetches all local adapter properties
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_adapter_properties(void);
+
+/*******************************************************************************
+ *
+ * Function btif_get_adapter_property
+ *
+ * Description Fetches property value from local cache
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_adapter_property(bt_property_type_t type);
+
+/*******************************************************************************
+ *
+ * Function btif_set_adapter_property
+ *
+ * Description Updates core stack with property value and stores it in
+ * local cache
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_adapter_property(const bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_device_property
+ *
+ * Description Fetches the remote device property from the NVRAM
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t* remote_addr,
+ bt_property_type_t type);
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_device_properties
+ *
+ * Description Fetches all the remote device properties from NVRAM
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t* remote_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_set_remote_device_property
+ *
+ * Description Writes the remote device property to NVRAM.
+ * Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+ * remote device property that can be set
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t* remote_addr,
+ const bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_service_record
+ *
+ * Description Looks up the service matching uuid on the remote device
+ * and fetches the SCN and service_name if the UUID is found
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t* remote_addr,
+ bt_uuid_t* uuid);
+
+/*******************************************************************************
+ * BTIF DM API
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_dm_start_discovery
+ *
+ * Description Start device discovery/inquiry
+ *
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_start_discovery(void);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cancel_discovery
+ *
+ * Description Cancels search
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_create_bond
+ *
+ * Description Initiate bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t* bd_addr, int transport);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_create_bond_out_of_band
+ *
+ * Description Initiate bonding with the specified device using OOB data.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond_out_of_band(
+ const bt_bdaddr_t* bd_addr, int transport,
+ const bt_out_of_band_data_t* oob_data);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cancel_bond
+ *
+ * Description Initiate bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_remove_bond
+ *
+ * Description Removes bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_connection_state
+ *
+ * Description Returns whether the remote device is currently connected
+ *
+ * Returns 0 if not connected
+ *
+ ******************************************************************************/
+uint16_t btif_dm_get_connection_state(const bt_bdaddr_t* bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_pin_reply
+ *
+ * Description BT legacy pairing - PIN code reply
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t* pin_code);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_passkey_reply
+ *
+ * Description BT SSP passkey reply
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_passkey_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ssp_reply
+ *
+ * Description BT SSP Reply - Just Works, Numeric Comparison & Passkey
+ * Entry
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t* bd_addr,
+ bt_ssp_variant_t variant, uint8_t accept,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_adapter_property
+ *
+ * Description Queries the BTA for the adapter property
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t* prop);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_services
+ *
+ * Description Start SDP to get remote services
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t* remote_addr,
+ bt_uuid_t* uuid);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_services
+ *
+ * Description Start SDP to get remote services
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t* remote_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_services_by_transport
+ *
+ * Description Start SDP to get remote services by transport
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t* remote_addr,
+ int transport);
+
+/*******************************************************************************
+ *
+ * Function btif_dut_mode_configure
+ *
+ * Description Configure Test Mode - 'enable' to 1 puts the device in test
+ * mode and 0 exits test mode
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable);
+
+/*******************************************************************************
+ *
+ * Function btif_dut_mode_send
+ *
+ * Description Sends a HCI Vendor specific command to the controller
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len);
+
+/*******************************************************************************
+ *
+ * Function btif_le_test_mode
+ *
+ * Description Sends a HCI BLE Test command to the Controller
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len);
+
+/*******************************************************************************
+ *
+ * Function btif_dm_read_energy_info
+ *
+ * Description Reads the energy info from controller
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_dm_read_energy_info();
+
+/*******************************************************************************
+ *
+ * Function btif_config_hci_snoop_log
+ *
+ * Description enable or disable HCI snoop log
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_config_hci_snoop_log(uint8_t enable);
+
+/*******************************************************************************
+ *
+ * Function btif_debug_bond_event_dump
+ *
+ * Description Dump bond event information
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_debug_bond_event_dump(int fd);
+
+#endif /* BTIF_API_H */
diff --git a/mtkbt/code/bt/btif/include/btif_av.h b/mtkbt/code/bt/btif/include/btif_av.h
new file mode 100755
index 0000000..207172b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_av.h
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_av.h
+ *
+ * Description: Main API header file for all BTIF AV functions accessed
+ * from internal stack.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_AV_H
+#define BTIF_AV_H
+
+#include "bta_av_api.h"
+#include "btif_common.h"
+#include "btif_sm.h"
+
+/*******************************************************************************
+ * Type definitions for callback functions
+ ******************************************************************************/
+
+typedef enum {
+ /* Reuse BTA_AV_XXX_EVT - No need to redefine them here */
+ BTIF_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT,
+ BTIF_AV_DISCONNECT_REQ_EVT,
+ BTIF_AV_START_STREAM_REQ_EVT,
+ BTIF_AV_STOP_STREAM_REQ_EVT,
+ BTIF_AV_SUSPEND_STREAM_REQ_EVT,
+ BTIF_AV_SOURCE_CONFIG_REQ_EVT,
+ BTIF_AV_SOURCE_CONFIG_UPDATED_EVT,
+ BTIF_AV_SINK_CONFIG_REQ_EVT,
+ BTIF_AV_OFFLOAD_START_REQ_EVT,
+ BTIF_AV_CLEANUP_REQ_EVT,
+} btif_av_sm_event_t;
+
+/*******************************************************************************
+ * BTIF AV API
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_av_get_addr
+ *
+ * Description Fetches current AV BD address
+ *
+ * Returns BD address
+ *
+ ******************************************************************************/
+
+bt_bdaddr_t btif_av_get_addr(void);
+
+/*******************************************************************************
+ * Function btif_av_is_sink_enabled
+ *
+ * Description Checks if A2DP Sink is enabled or not
+ *
+ * Returns true if A2DP Sink is enabled, false otherwise
+ *
+ ******************************************************************************/
+
+bool btif_av_is_sink_enabled(void);
+
+/*******************************************************************************
+ *
+ * Function btif_av_stream_ready
+ *
+ * Description Checks whether AV is ready for starting a stream
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_ready(void);
+
+/*******************************************************************************
+ *
+ * Function btif_av_stream_started_ready
+ *
+ * Description Checks whether AV ready for media start in streaming state
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_started_ready(void);
+
+/*******************************************************************************
+ *
+ * Function btif_dispatch_sm_event
+ *
+ * Description Send event to AV statemachine
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len);
+
+/*******************************************************************************
+ *
+ * Function btif_av_init
+ *
+ * Description Initializes btif AV if not already done
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_av_init(int service_id);
+
+/*******************************************************************************
+ *
+ * Function btif_av_is_connected
+ *
+ * Description Checks if av has a connected sink
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+
+bool btif_av_is_connected(void);
+
+/** M: Bug fix for Block AVRCP key if A2DP is not connected @{ */
+/*******************************************************************************
+ * **
+ * ** Function btif_av_is_idle
+ * **
+ * ** Description Checks if av in idle state
+ * **
+ * ** Returns bool
+ * **
+ * *******************************************************************************/
+bool btif_av_is_idle(void);
+/** @} */
+
+/*******************************************************************************
+ *
+ * Function btif_av_get_peer_sep
+ *
+ * Description Get the stream endpoint type.
+ *
+ * Returns The stream endpoint type: either AVDT_TSEP_SRC or
+ * AVDT_TSEP_SNK.
+ *
+ ******************************************************************************/
+
+uint8_t btif_av_get_peer_sep(void);
+
+/*******************************************************************************
+ *
+ * Function btif_av_is_peer_edr
+ *
+ * Description Check if the connected a2dp device supports
+ * EDR or not. Only when connected this function
+ * will accurately provide a true capability of
+ * remote peer. If not connected it will always be false.
+ *
+ * Returns true if remote device is capable of EDR
+ *
+ ******************************************************************************/
+
+bool btif_av_is_peer_edr(void);
+
+/******************************************************************************
+ *
+ * Function btif_av_clear_remote_suspend_flag
+ *
+ * Description Clears remote suspended flag
+ *
+ * Returns Void
+ ******************************************************************************/
+void btif_av_clear_remote_suspend_flag(void);
+
+/*******************************************************************************
+ *
+ * Function btif_av_peer_supports_3mbps
+ *
+ * Description Check if the connected A2DP device supports
+ * 3 Mbps EDR. This function will only work while connected.
+ * If not connected it will always return false.
+ *
+ * Returns true if remote device is EDR and supports 3 Mbps
+ *
+ ******************************************************************************/
+bool btif_av_peer_supports_3mbps(void);
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/******************************************************************************
+**
+** Function btif_av_is_black_peer
+**
+** Description Some special device want perform START cmd itself first
+** If it not send START cmd, will close current link(ex. Tiggo5).
+** So for this special device, we need delay send START cmd
+** which from DUT to receive the special device cmd.
+** Returns TRUE if it special device.
+********************************************************************************/
+bool btif_av_is_black_peer(void);
+#endif
+
+/** M: Bug Fix for delay creating SCO when A2DP not suspend. @{ */
+/*******************************************************************************
+**
+** Function btif_av_get_sm_handle
+**
+** Description Fetches current av SM handle
+**
+** Returns sm handle
+**
+*******************************************************************************/
+btif_sm_handle_t btif_av_get_sm_handle(void);
+/** @} */
+#endif /* BTIF_AV_H */
diff --git a/mtkbt/code/bt/btif/include/btif_av_co.h b/mtkbt/code/bt/btif/include/btif_av_co.h
new file mode 100755
index 0000000..8c1266f
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_av_co.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_AV_CO_H
+#define BTIF_AV_CO_H
+
+#include "btif/include/btif_a2dp_source.h"
+#include "stack/include/a2dp_codec_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Gets the A2DP peer parameters that are used to initialize the encoder.
+// The parameters are stored in |p_peer_params|.
+// |p_peer_params| cannot be null.
+void bta_av_co_get_peer_params(tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params);
+
+// Gets the current A2DP encoder interface that can be used to encode and
+// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// Returns the A2DP encoder interface if the current codec is setup,
+// otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void);
+
+// Sets the user preferred codec configuration.
+// |codec_user_config| contains the preferred codec configuration.
+// Returns true on success, otherwise false.
+bool bta_av_co_set_codec_user_config(
+ const btav_a2dp_codec_config_t& codec_user_config);
+
+// Sets the Audio HAL selected audio feeding parameters.
+// Those parameters are applied only to the currently selected codec.
+// |codec_audio_config| contains the selected audio feeding configuration.
+// Returns true on success, otherwise false.
+bool bta_av_co_set_codec_audio_config(
+ const btav_a2dp_codec_config_t& codec_audio_config);
+
+// Initializes the control block.
+// |codec_priorities| contains the A2DP Source codec priorities to use.
+void bta_av_co_init(
+ const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+
+// Gets the initialized A2DP codecs.
+// Returns a pointer to the |A2dpCodecs| object with the initialized A2DP
+// codecs, or nullptr if no codecs are initialized.
+A2dpCodecs* bta_av_get_a2dp_codecs(void);
+
+// Gets the current A2DP codec.
+// Returns a pointer to the current |A2dpCodec| if valid, otherwise nullptr.
+A2dpCodecConfig* bta_av_get_a2dp_current_codec(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BTIF_AV_CO_H
diff --git a/mtkbt/code/bt/btif/include/btif_avrcp_audio_track.h b/mtkbt/code/bt/btif/include/btif_avrcp_audio_track.h
new file mode 100755
index 0000000..6986e43
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_avrcp_audio_track.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implements an API to be used by A2DP to do streaming of music over a media
+ * stream. This API provides mechanism to create and control playback of the
+ * media stream depending on the data bits coming from the remote device. The
+ * media stream is played over the default audio media stream type and hence
+ * volume control is handled entirely by the Audio Manager (which is also the
+ * original motivation for this solution.
+ *
+ * TODO: Once the AudioManager provides support for patching audio sources with
+ * volume control we should deprecate this file.
+ */
+
+/**
+ * Creates an audio track object and returns a void handle. Use this handle to
+ * the
+ * following functions.
+ *
+ * The ownership of the handle is maintained by the caller of this API and it
+ * should eventually be
+ * deleted using BtifAvrcpAudioTrackDelete (see below).
+ */
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType);
+
+/**
+ * Starts the audio track.
+ */
+void BtifAvrcpAudioTrackStart(void* handle);
+
+/**
+ * Pauses the audio track.
+ */
+void BtifAvrcpAudioTrackPause(void* handle);
+
+/**
+ * Sets audio track gain.
+ */
+void BtifAvrcpSetAudioTrackGain(void* handle, float gain);
+
+/**
+ * Stop / Delete the audio track.
+ * Delete should usually be called stop.
+ */
+void BtifAvrcpAudioTrackStop(void* handle);
+void BtifAvrcpAudioTrackDelete(void* handle);
+
+/**
+ * Writes the audio track data to file.
+ *
+ * Used only for debugging.
+ */
+int BtifAvrcpAudioTrackWriteData(void* handle, void* audioBuffer,
+ int bufferlen);
diff --git a/mtkbt/code/bt/btif/include/btif_common.h b/mtkbt/code/bt/btif/include/btif_common.h
new file mode 100755
index 0000000..f283e00
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_common.h
@@ -0,0 +1,254 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_COMMON_H
+#define BTIF_COMMON_H
+
+#include <stdlib.h>
+
+#include <base/bind.h>
+#include <base/tracked_objects.h>
+#include <hardware/bluetooth.h>
+
+#include "bt_types.h"
+#include "bta_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define ASSERTC(cond, msg, val) \
+ do { \
+ if (!(cond)) { \
+ LOG_ERROR(LOG_TAG, "### ASSERT : %s %s line %d %s (%d) ###", __FILE__, \
+ __func__, __LINE__, (msg), (val)); \
+ } \
+ } while (0)
+
+/* Calculate start of event enumeration; id is top 8 bits of event */
+#define BTIF_SIG_START(id) ((id) << 8)
+
+/* For upstream the MSB bit is always SET */
+#define BTIF_SIG_CB_BIT (0x8000)
+#define BTIF_SIG_CB_START(id) (((id) << 8) | BTIF_SIG_CB_BIT)
+
+/*
+ * A memcpy(3) wrapper when copying memory that might not be aligned.
+ *
+ * On certain architectures, if the memcpy(3) arguments appear to be
+ * pointing to aligned memory (e.g., struct pointers), the compiler might
+ * generate optimized memcpy(3) code. However, if the original memory was not
+ * aligned (e.g., because of incorrect "char *" to struct pointer casting),
+ * the result code might trigger SIGBUS crash.
+ *
+ * As a short-term solution, we use the help of the maybe_non_aligned_memcpy()
+ * macro to identify and fix such cases. In the future, we should fix the
+ * problematic "char *" to struct pointer casting, and this macro itself should
+ * be removed.
+ */
+#define maybe_non_aligned_memcpy(_a, _b, _c) \
+ memcpy((void*)(_a), (void*)(_b), (_c))
+
+/* BTIF sub-systems */
+#define BTIF_CORE 0
+#define BTIF_DM 1
+#define BTIF_HFP 2
+#define BTIF_AV 3
+#define BTIF_PAN 4
+#define BTIF_HF_CLIENT 5
+
+extern bt_callbacks_t* bt_hal_cbacks;
+
+#define HAL_CBACK(P_CB, P_CBACK, ...) \
+ do { \
+ if ((P_CB) && (P_CB)->P_CBACK) { \
+ BTIF_TRACE_API("HAL %s->%s", #P_CB, #P_CBACK); \
+ (P_CB)->P_CBACK(__VA_ARGS__); \
+ } else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ } while (0)
+
+/**
+ * BTIF events for requests that require context switch to btif task
+ * on downstreams path
+ */
+enum {
+ BTIF_CORE_API_START = BTIF_SIG_START(BTIF_CORE),
+ BTIF_CORE_STORAGE_NO_ACTION,
+ BTIF_CORE_STORAGE_ADAPTER_WRITE,
+ BTIF_CORE_STORAGE_ADAPTER_READ,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL,
+ BTIF_CORE_STORAGE_REMOTE_WRITE,
+ BTIF_CORE_STORAGE_REMOTE_READ,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL,
+ BTIF_CORE_STORAGE_READ_ALL,
+ BTIF_CORE_STORAGE_NOTIFY_STATUS,
+ /* add here */
+
+ BTIF_DM_API_START = BTIF_SIG_START(BTIF_DM),
+ BTIF_DM_ENABLE_SERVICE,
+ BTIF_DM_DISABLE_SERVICE,
+ /* add here */
+
+ BTIF_HFP_API_START = BTIF_SIG_START(BTIF_HFP),
+ /* add here */
+
+ BTIF_AV_API_START = BTIF_SIG_START(BTIF_AV),
+ /* add here */
+};
+
+/**
+ * BTIF events for callbacks that require context switch to btif task
+ * on upstream path - Typically these would be non-BTA events
+ * that are generated by the BTIF layer.
+ */
+enum {
+ BTIF_CORE_CB_START = BTIF_SIG_CB_START(BTIF_CORE),
+ /* add here */
+
+ BTIF_DM_CB_START = BTIF_SIG_CB_START(BTIF_DM),
+ BTIF_DM_CB_DISCOVERY_STARTED, /* Discovery has started */
+ BTIF_DM_CB_CREATE_BOND, /* Create bond */
+ BTIF_DM_CB_REMOVE_BOND, /*Remove bond */
+ BTIF_DM_CB_HID_REMOTE_NAME, /* Remote name callback for HID device */
+ BTIF_DM_CB_BOND_STATE_BONDING,
+ BTIF_DM_CB_LE_TX_TEST, /* BLE Tx Test command complete callback */
+ BTIF_DM_CB_LE_RX_TEST, /* BLE Rx Test command complete callback */
+ BTIF_DM_CB_LE_TEST_END, /* BLE Test mode end callback */
+
+ BTIF_HFP_CB_START = BTIF_SIG_CB_START(BTIF_HFP),
+ BTIF_HFP_CB_AUDIO_CONNECTING, /* HF AUDIO connect has been sent to BTA
+ successfully */
+
+ BTIF_PAN_CB_START = BTIF_SIG_CB_START(BTIF_PAN),
+ BTIF_PAN_CB_DISCONNECTING, /* PAN Disconnect has been sent to BTA successfully
+ */
+
+ BTIF_HF_CLIENT_CLIENT_CB_START = BTIF_SIG_CB_START(BTIF_HF_CLIENT),
+ BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, /* AUDIO connect has been sent to BTA
+ successfully */
+};
+
+/* Macro definitions for BD ADDR persistence */
+
+/**
+ * PROPERTY_BT_BDADDR_PATH
+ * The property key stores the storage location of Bluetooth Device Address
+ */
+#ifndef PROPERTY_BT_BDADDR_PATH
+#define PROPERTY_BT_BDADDR_PATH "ro.bt.bdaddr_path"
+#endif
+
+/**
+ * PERSIST_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH,
+ * generating a random BDADDR and keeping it in the PERSIST_BDADDR_DROP.
+ */
+#ifndef PERSIST_BDADDR_PROPERTY
+#define PERSIST_BDADDR_PROPERTY "persist.service.bdroid.bdaddr"
+#endif
+
+/**
+ * FACTORY_BT_BDADDR_PROPERTY
+ * If there is no valid bdaddr available from PROPERTY_BT_BDADDR_PATH
+ * and there is no available persistent bdaddr available from
+ * PERSIST_BDADDR_PROPERTY use a factory set address
+ */
+#ifndef FACTORY_BT_ADDR_PROPERTY
+#define FACTORY_BT_ADDR_PROPERTY "ro.boot.btmacaddr"
+#endif
+
+#define FACTORY_BT_BDADDR_STORAGE_LEN 17
+
+/*******************************************************************************
+ * Type definitions for callback functions
+ ******************************************************************************/
+
+typedef void(tBTIF_CBACK)(uint16_t event, char* p_param);
+typedef void(tBTIF_COPY_CBACK)(uint16_t event, char* p_dest, char* p_src);
+
+/*******************************************************************************
+ * Type definitions and return values
+ ******************************************************************************/
+
+/* this type handles all btif context switches between BTU and HAL */
+typedef struct {
+ BT_HDR hdr;
+ tBTIF_CBACK* p_cb; /* context switch callback */
+
+ /* parameters passed to callback */
+ uint16_t event; /* message event id */
+ char __attribute__((aligned)) p_param[]; /* parameter area needs to be last */
+} tBTIF_CONTEXT_SWITCH_CBACK;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+extern bt_status_t do_in_jni_thread(const base::Closure& task);
+extern bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task);
+/**
+ * This template wraps callback into callback that will be executed on jni
+ * thread
+ */
+template <typename R, typename... Args>
+base::Callback<R(Args...)> jni_thread_wrapper(
+ const tracked_objects::Location& from_here, base::Callback<R(Args...)> cb) {
+ return base::Bind(
+ [](const tracked_objects::Location& from_here,
+ base::Callback<R(Args...)> cb, Args... args) {
+ do_in_jni_thread(from_here,
+ base::Bind(cb, std::forward<Args>(args)...));
+ },
+ from_here, std::move(cb));
+}
+
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void);
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id);
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id);
+int btif_is_enabled(void);
+
+/**
+ * BTIF_Events
+ */
+void btif_enable_bluetooth_evt(tBTA_STATUS status);
+void btif_disable_bluetooth_evt(void);
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+ bt_property_t* p_props);
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t* remote_addr,
+ uint32_t num_props, bt_property_t* p_props);
+
+void bte_load_did_conf(const char* p_path);
+void bte_main_boot_entry(void);
+void bte_main_enable(void);
+void bte_main_disable(void);
+void bte_main_cleanup(void);
+void bte_main_postload_cfg(void);
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+ char* p_params, int param_len,
+ tBTIF_COPY_CBACK* p_copy_cback);
+
+void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char* p_param);
+
+#endif /* BTIF_COMMON_H */
diff --git a/mtkbt/code/bt/btif/include/btif_config.h b/mtkbt/code/bt/btif/include/btif_config.h
new file mode 100755
index 0000000..5d9ea33
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_config.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "bt_types.h"
+
+static const char BTIF_CONFIG_MODULE[] = "btif_config_module";
+
+typedef struct btif_config_section_iter_t btif_config_section_iter_t;
+
+bool btif_config_has_section(const char* section);
+bool btif_config_exist(const char* section, const char* key);
+bool btif_config_get_int(const char* section, const char* key, int* value);
+bool btif_config_set_int(const char* section, const char* key, int value);
+bool btif_config_get_str(const char* section, const char* key, char* value,
+ int* size_bytes);
+bool btif_config_set_str(const char* section, const char* key,
+ const char* value);
+bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
+ size_t* length);
+bool btif_config_set_bin(const char* section, const char* key,
+ const uint8_t* value, size_t length);
+bool btif_config_remove(const char* section, const char* key);
+
+size_t btif_config_get_bin_length(const char* section, const char* key);
+
+const btif_config_section_iter_t* btif_config_section_begin(void);
+const btif_config_section_iter_t* btif_config_section_end(void);
+const btif_config_section_iter_t* btif_config_section_next(
+ const btif_config_section_iter_t* section);
+const char* btif_config_section_name(const btif_config_section_iter_t* section);
+
+void btif_config_save(void);
+void btif_config_flush(void);
+bool btif_config_clear(void);
+
+// TODO(zachoverflow): Eww...we need to move these out. These are peer specific,
+// not config general.
+bool btif_get_address_type(const BD_ADDR bd_addr, int* p_addr_type);
+bool btif_get_device_type(const BD_ADDR bd_addr, int* p_device_type);
+
+void btif_debug_config_dump(int fd);
diff --git a/mtkbt/code/bt/btif/include/btif_config_transcode.h b/mtkbt/code/bt/btif/include/btif_config_transcode.h
new file mode 100755
index 0000000..66aac8a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_config_transcode.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+typedef struct config_t config_t;
+
+config_t* btif_config_transcode(const char* xml_filename);
diff --git a/mtkbt/code/bt/btif/include/btif_debug.h b/mtkbt/code/bt/btif/include/btif_debug.h
new file mode 100755
index 0000000..463a4a1
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_debug.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Debug API
+
+void btif_debug_init(void);
diff --git a/mtkbt/code/bt/btif/include/btif_debug_btsnoop.h b/mtkbt/code/bt/btif/include/btif_debug_btsnoop.h
new file mode 100755
index 0000000..e82421a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_debug_btsnoop.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+#define BTSNOOZ_CURRENT_VERSION 0x02
+
+// The preamble is stored un-encrypted as the first part
+// of the file.
+typedef struct btsnooz_preamble_t {
+ uint8_t version;
+ uint64_t last_timestamp_ms;
+} __attribute__((__packed__)) btsnooz_preamble_t;
+
+// One header for each HCI packet
+typedef struct btsnooz_header_t {
+ uint16_t length;
+ uint16_t packet_length;
+ uint32_t delta_time_ms;
+ uint8_t type;
+} __attribute__((__packed__)) btsnooz_header_t;
+
+// Initializes btsnoop memory logging and registers
+void btif_debug_btsnoop_init(void);
+
+// Writes btsnoop data base64 encoded to fd
+void btif_debug_btsnoop_dump(int fd);
diff --git a/mtkbt/code/bt/btif/include/btif_debug_conn.h b/mtkbt/code/bt/btif/include/btif_debug_conn.h
new file mode 100755
index 0000000..1823b8a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_debug_conn.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+
+#include "gatt_api.h"
+
+typedef enum {
+ BTIF_DEBUG_CONNECTED = 1,
+ BTIF_DEBUG_DISCONNECTED
+} btif_debug_conn_state_t;
+
+// Report a connection state change
+void btif_debug_conn_state(const bt_bdaddr_t bda,
+ const btif_debug_conn_state_t state,
+ const tGATT_DISCONN_REASON disconnect_reason);
+
+void btif_debug_conn_dump(int fd);
diff --git a/mtkbt/code/bt/btif/include/btif_dm.h b/mtkbt/code/bt/btif/include/btif_dm.h
new file mode 100755
index 0000000..f06272a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_dm.h
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_DM_H
+#define BTIF_DM_H
+
+#include "bta_api.h"
+#include "bte_appl.h"
+#include "btif_uid.h"
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+void btif_dm_init(uid_set_t* set);
+void btif_dm_cleanup(void);
+
+/**
+ * BTIF callback to switch context from bte to btif
+ */
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data);
+
+/**
+ * Notify BT disable being initiated. DM may chose to abort
+ * pending commands, like pairing
+ */
+void btif_dm_on_disable(void);
+
+/**
+ * Callout for handling io_capabilities request
+ */
+void btif_dm_proc_io_req(BD_ADDR bd_addr, tBTA_IO_CAP* p_io_cap,
+ tBTA_OOB_DATA* p_oob_data, tBTA_AUTH_REQ* p_auth_req,
+ bool is_orig);
+/**
+ * Callout for handling io_capabilities response
+ */
+void btif_dm_proc_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ tBTA_OOB_DATA oob_data, tBTA_AUTH_REQ auth_req);
+
+/**
+ * Out-of-band functions
+ */
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA* p_oob_data);
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr, tBTA_OOB_DATA* p_oob_data,
+ tBTA_LE_AUTH_REQ* p_auth_req);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r);
+bool btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r);
+#endif /* BTIF_DM_OOB_TEST */
+
+/*callout for reading SMP properties from Text file*/
+bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg);
+
+typedef struct {
+ bool is_penc_key_rcvd;
+ tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */
+ bool is_pcsrk_key_rcvd;
+ tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */
+ bool is_pid_key_rcvd;
+ tBTM_LE_PID_KEYS pid_key; /* peer device ID key */
+ bool is_lenc_key_rcvd;
+ tBTM_LE_LENC_KEYS
+ lenc_key; /* local encryption reproduction keys LTK = = d1(ER,DIV,0)*/
+ bool is_lcsrk_key_rcvd;
+ tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+ bool is_lidk_key_rcvd; /* local identity key received */
+} btif_dm_ble_cb_t;
+
+#define BTIF_DM_LE_KEY_PENC BTA_LE_KEY_PENC
+#define BTIF_DM_LE_KEY_PID BTA_LE_KEY_PID
+#define BTIF_DM_LE_KEY_PCSRK BTA_LE_KEY_PCSRK
+#define BTIF_DM_LE_KEY_LENC BTA_LE_KEY_LENC
+#define BTIF_DM_LE_KEY_LID BTA_LE_KEY_LID
+#define BTIF_DM_LE_KEY_LCSRK BTA_LE_KEY_LCSRK
+
+#define BTIF_DM_LE_LOCAL_KEY_IR (1 << 0)
+#define BTIF_DM_LE_LOCAL_KEY_IRK (1 << 1)
+#define BTIF_DM_LE_LOCAL_KEY_DHK (1 << 2)
+#define BTIF_DM_LE_LOCAL_KEY_ER (1 << 3)
+
+void btif_dm_load_ble_local_keys(void);
+void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+ BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
+void btif_dm_save_ble_bonding_keys(void);
+void btif_dm_remove_ble_bonding_keys(void);
+void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req);
+
+void btif_dm_update_ble_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_gatt.h b/mtkbt/code/bt/btif/include/btif_gatt.h
new file mode 100755
index 0000000..e84811e
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_gatt.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Name: btif_gatt.h
+ *
+ * Description:
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_GATT_H
+#define BTIF_GATT_H
+
+extern const btgatt_client_interface_t btgattClientInterface;
+extern const btgatt_server_interface_t btgattServerInterface;
+
+BleAdvertiserInterface* get_ble_advertiser_instance();
+BleScannerInterface* get_ble_scanner_instance();
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_gatt_util.h b/mtkbt/code/bt/btif/include/btif_gatt_util.h
new file mode 100755
index 0000000..a875a17
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_gatt_util.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_GATT_UTIL_H
+#define BTIF_GATT_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "bta/include/bta_gatt_api.h"
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src);
+void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src);
+void btif_to_bta_uuid_mask(tBTM_BLE_PF_COND_MASK* p_mask,
+ const bt_uuid_t* p_src, const bt_uuid_t* svc_uuid);
+
+void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src);
+
+uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src);
+uint16_t get_uuid16(tBT_UUID* p_uuid);
+
+void btif_gatt_check_encrypted_link(BD_ADDR bd_addr,
+ tBTA_GATT_TRANSPORT transport);
+extern void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
+ btgatt_track_adv_info_t* p_src);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_hd.h b/mtkbt/code/bt/btif/include/btif_hd.h
new file mode 100755
index 0000000..5697896
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_hd.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HD_H
+#define BTIF_HD_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdint.h>
+#include "bta_hd_api.h"
+
+typedef enum {
+ BTIF_HD_DISABLED = 0,
+ BTIF_HD_ENABLED,
+ BTIF_HD_DISABLING
+} BTIF_HD_STATUS;
+
+/* BTIF-HD control block */
+typedef struct {
+ BTIF_HD_STATUS status;
+ bool app_registered;
+ bool service_dereg_active;
+ bool forced_disc;
+} btif_hd_cb_t;
+
+extern btif_hd_cb_t btif_hd_cb;
+
+extern void btif_hd_remove_device(bt_bdaddr_t bd_addr);
+extern void btif_hd_service_registration();
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_hf.h b/mtkbt/code/bt/btif/include/btif_hf.h
new file mode 100755
index 0000000..1cafb8b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_hf.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HF_H
+#define BTIF_HF_H
+
+#include <stdbool.h>
+
+// Check whether there is a Hands-Free call in progress.
+// Returns true if no call is in progress.
+bool btif_hf_is_call_idle(void);
+
+#endif /* BTIF_HF_H */
diff --git a/mtkbt/code/bt/btif/include/btif_hh.h b/mtkbt/code/bt/btif/include/btif_hh.h
new file mode 100755
index 0000000..6c69f83
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_hh.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HH_H
+#define BTIF_HH_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hh.h>
+#include <pthread.h>
+#include <stdint.h>
+#include "bta_hh_api.h"
+#include "btu.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define BTIF_HH_MAX_HID 8
+#define BTIF_HH_MAX_ADDED_DEV 32
+
+#define BTIF_HH_MAX_KEYSTATES 3
+#define BTIF_HH_KEYSTATE_MASK_NUMLOCK 0x01
+#define BTIF_HH_KEYSTATE_MASK_CAPSLOCK 0x02
+#define BTIF_HH_KEYSTATE_MASK_SCROLLLOCK 0x04
+
+/**M: duplicate event send will lead current higher than target @{*/
+#define BTIF_HH_OUTPUT_REPORT_SIZE 2
+/**@}*/
+
+#define BTIF_HH_MAX_POLLING_ATTEMPTS 10
+#define BTIF_HH_POLLING_SLEEP_DURATION_US 5000
+
+/*******************************************************************************
+ * Type definitions and return values
+ ******************************************************************************/
+
+typedef enum {
+ BTIF_HH_DISABLED = 0,
+ BTIF_HH_ENABLED,
+ BTIF_HH_DISABLING,
+ BTIF_HH_DEV_UNKNOWN,
+ BTIF_HH_DEV_CONNECTING,
+ BTIF_HH_DEV_CONNECTED,
+ BTIF_HH_DEV_DISCONNECTED
+} BTIF_HH_STATUS;
+
+typedef struct {
+ bthh_connection_state_t dev_status;
+ uint8_t dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+ uint8_t sub_class;
+ uint8_t app_id;
+ int fd;
+ bool ready_for_data;
+ pthread_t hh_poll_thread_id;
+ uint8_t hh_keep_polling;
+ alarm_t* vup_timer;
+ bool local_vup; // Indicated locally initiated VUP
+ /**M: duplicate event send will lead current higher than target @{*/
+ uint8_t last_output_rpt_data[BTIF_HH_OUTPUT_REPORT_SIZE];
+ /**@}*/
+} btif_hh_device_t;
+
+/* Control block to maintain properties of devices */
+typedef struct {
+ uint8_t dev_handle;
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_ATTR_MASK attr_mask;
+} btif_hh_added_device_t;
+
+/**
+ * BTIF-HH control block to maintain added devices and currently
+ * connected hid devices
+ */
+typedef struct {
+ BTIF_HH_STATUS status;
+ btif_hh_device_t devices[BTIF_HH_MAX_HID];
+ uint32_t device_num;
+ btif_hh_added_device_t added_devices[BTIF_HH_MAX_ADDED_DEV];
+ btif_hh_device_t* p_curr_dev;
+ bool service_dereg_active;
+} btif_hh_cb_t;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+extern btif_hh_cb_t btif_hh_cb;
+
+extern btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle);
+extern void btif_hh_remove_device(bt_bdaddr_t bd_addr);
+bool btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask);
+extern bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t* bd_addr);
+extern void btif_hh_disconnect(bt_bdaddr_t* bd_addr);
+extern void btif_hh_setreport(btif_hh_device_t* p_dev,
+ bthh_report_type_t r_type, uint16_t size,
+ uint8_t* report);
+extern void btif_hh_service_registration(bool enable);
+
+bool btif_hh_add_added_dev(bt_bdaddr_t bd_addr, tBTA_HH_ATTR_MASK attr_mask);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_hl.h b/mtkbt/code/bt/btif/include/btif_hl.h
new file mode 100755
index 0000000..9dc4df9
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_hl.h
@@ -0,0 +1,315 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_HL_H
+#define BTIF_HL_H
+
+#include <hardware/bluetooth.h>
+
+#include "bt_common.h"
+#include "bta_hl_api.h"
+#include "osi/include/alarm.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define BTIF_HL_DATA_TYPE_NONE 0x0000
+#define BTIF_HL_DATA_TYPE_PULSE_OXIMETER 0x1004 /* from BT assigned number */
+#define BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON 0x1007
+#define BTIF_HL_DATA_TYPE_BODY_THERMOMETER 0x1008
+#define BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE 0x100F
+#define BTIF_HL_DATA_TYPE_GLUCOSE_METER 0x1011
+#define BTIF_HL_DATA_TYPE_STEP_COUNTER 0x1068
+#define BTIF_HL_DATA_TYPE_BCA 0x1014
+#define BTIF_HL_DATA_TYPE_PEAK_FLOW 0x1015
+#define BTIF_HL_DATA_TYPE_CARDIO 0x1029
+#define BTIF_HL_DATA_TYPE_ACTIVITY_HUB 0x1047
+#define BTIF_HL_DATA_TYPE_AMM 0x1048
+
+#define BTIF_HL_CCH_NUM_FILTER_ELEMS 3
+#define BTIF_HL_APPLICATION_NAME_LEN 512
+
+/*******************************************************************************
+ * Type definitions and return values
+ ******************************************************************************/
+
+typedef enum {
+ BTIF_HL_SOC_STATE_IDLE,
+ BTIF_HL_SOC_STATE_W4_ADD,
+ BTIF_HL_SOC_STATE_W4_CONN,
+ BTIF_HL_SOC_STATE_W4_READ,
+ BTIF_HL_SOC_STATE_W4_REL
+} btif_hl_soc_state_t;
+
+typedef enum {
+ BTIF_HL_STATE_DISABLED,
+ BTIF_HL_STATE_DISABLING,
+ BTIF_HL_STATE_ENABLED,
+ BTIF_HL_STATE_ENABLING,
+} btif_hl_state_t;
+
+typedef enum {
+ BTIF_HL_CCH_OP_NONE,
+ BTIF_HL_CCH_OP_MDEP_FILTERING,
+ BTIF_HL_CCH_OP_MATCHED_CTRL_PSM,
+ BTIF_HL_CCH_OP_DCH_OPEN,
+ BTIF_HL_CCH_OP_DCH_RECONNECT,
+ BTIF_HL_CCH_OP_DCH_ECHO_TEST
+} btif_hl_cch_op_t;
+
+typedef enum {
+ BTIF_HL_PEND_DCH_OP_NONE,
+ BTIF_HL_PEND_DCH_OP_DELETE_MDL,
+ BTIF_HL_PEND_DCH_OP_OPEN,
+ BTIF_HL_PEND_DCH_OP_RECONNECT
+} btif_hl_pend_dch_op_t;
+
+typedef enum { BTIF_HL_DCH_OP_NONE, BTIF_HL_DCH_OP_DISC } btif_hl_dch_op_t;
+
+typedef enum {
+ BTIF_HL_CHAN_CB_STATE_NONE,
+ BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING,
+ BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING,
+
+ BTIF_HL_CHAN_CB_STATE_DISCONNECTING_PENDING,
+ BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING,
+ BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING,
+} btif_hl_chan_cb_state_t;
+
+enum {
+ BTIF_HL_SEND_CONNECTED_CB,
+ BTIF_HL_SEND_DISCONNECTED_CB,
+ BTIF_HL_REG_APP,
+ BTIF_HL_UNREG_APP,
+ BTIF_HL_UPDATE_MDL,
+};
+
+typedef struct {
+ uint8_t mdep_cfg_idx;
+ int data_type;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+} btif_hl_extra_mdl_cfg_t;
+
+typedef struct {
+ tBTA_HL_MDL_CFG base;
+ btif_hl_extra_mdl_cfg_t extra;
+} btif_hl_mdl_cfg_t;
+
+typedef struct {
+ bool active;
+ uint8_t app_idx;
+} btif_hl_app_data_t;
+
+typedef struct {
+ int channel_id;
+ BD_ADDR bd_addr;
+ uint8_t mdep_cfg_idx;
+ int max_s;
+ int socket_id[2];
+ uint8_t app_idx;
+ uint8_t mcl_idx;
+ uint8_t mdl_idx;
+ btif_hl_soc_state_t state;
+} btif_hl_soc_cb_t;
+
+typedef struct {
+ uint16_t data_type;
+ uint16_t max_tx_apdu_size;
+ uint16_t max_rx_apdu_size;
+} btif_hl_data_type_cfg_t;
+
+typedef struct {
+ uint16_t data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+} btif_hl_filter_elem_t;
+
+typedef struct {
+ uint8_t num_elems;
+ btif_hl_filter_elem_t elem[BTIF_HL_CCH_NUM_FILTER_ELEMS];
+} btif_hl_cch_filter_t;
+
+typedef struct {
+ bool in_use;
+ uint16_t mdl_id;
+ tBTA_HL_MDL_HANDLE mdl_handle;
+ btif_hl_dch_op_t dch_oper;
+ tBTA_HL_MDEP_ID local_mdep_id;
+ uint8_t local_mdep_cfg_idx;
+ tBTA_HL_DCH_CFG local_cfg;
+ tBTA_HL_MDEP_ID peer_mdep_id;
+ uint16_t peer_data_type;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ tBTA_HL_DCH_MODE dch_mode;
+ tBTA_SEC sec_mask;
+ bool is_the_first_reliable;
+ bool delete_mdl;
+ uint16_t mtu;
+ tMCA_CHNL_CFG chnl_cfg;
+ uint16_t tx_size;
+ uint8_t* p_tx_pkt;
+ uint8_t* p_rx_pkt;
+ bool cong;
+ btif_hl_soc_cb_t* p_scb;
+ int channel_id;
+} btif_hl_mdl_cb_t;
+
+typedef struct {
+ int channel_id;
+ int mdep_cfg_idx;
+ bool in_use;
+ btif_hl_chan_cb_state_t cb_state;
+ btif_hl_pend_dch_op_t op;
+ BD_ADDR bd_addr;
+ bool abort_pending;
+} btif_hl_pending_chan_cb_t;
+
+typedef struct {
+ btif_hl_mdl_cb_t mdl[BTA_HL_NUM_MDLS_PER_MCL];
+ bool in_use;
+ bool is_connected;
+ uint16_t req_ctrl_psm;
+ uint16_t ctrl_psm;
+ uint16_t data_psm;
+ BD_ADDR bd_addr;
+ uint16_t cch_mtu;
+ tBTA_SEC sec_mask;
+ tBTA_HL_MCL_HANDLE mcl_handle;
+ btif_hl_pending_chan_cb_t pcb;
+ bool valid_sdp_idx;
+ uint8_t sdp_idx;
+ tBTA_HL_SDP sdp;
+ btif_hl_cch_op_t cch_oper;
+ alarm_t* cch_timer;
+} btif_hl_mcl_cb_t;
+
+typedef struct {
+ bool active;
+ uint16_t mdl_id;
+ uint8_t mdep_cfg_idx;
+ BD_ADDR bd_addr;
+ int channel_id;
+} btif_hl_delete_mdl_t;
+
+typedef struct {
+ btif_hl_mcl_cb_t mcb[BTA_HL_NUM_MCLS]; /* application Control Blocks */
+ bool in_use; /* this CB is in use*/
+ bool reg_pending;
+ uint8_t app_id;
+
+ tBTA_HL_SUP_FEATURE sup_feature;
+ tBTA_HL_DCH_CFG channel_type[BTA_HL_NUM_MDEPS];
+ tBTA_HL_SDP_INFO_IND sdp_info_ind;
+ btif_hl_cch_filter_t filter;
+
+ btif_hl_mdl_cfg_t mdl_cfg[BTA_HL_NUM_MDL_CFGS];
+ int mdl_cfg_channel_id[BTA_HL_NUM_MDL_CFGS];
+
+ btif_hl_delete_mdl_t delete_mdl;
+ tBTA_HL_DEVICE_TYPE dev_type;
+ tBTA_HL_APP_HANDLE app_handle;
+ uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+ char srv_name[BTA_SERVICE_NAME_LEN +
+ 1]; /* service name to be used in the SDP; null terminated*/
+ char srv_desp[BTA_SERVICE_DESP_LEN + 1]; /* service description to be used in
+ the SDP; null terminated */
+ char provider_name[BTA_PROVIDER_NAME_LEN + 1]; /* provide name to be used in
+ the SDP; null terminated */
+ char
+ application_name[BTIF_HL_APPLICATION_NAME_LEN + 1]; /* applicaiton name */
+} btif_hl_app_cb_t;
+
+typedef struct {
+ bool in_use;
+ uint8_t app_idx;
+} btif_hl_pending_reg_cb_t;
+
+/* BTIF-HL control block */
+typedef struct {
+ btif_hl_app_cb_t acb[BTA_HL_NUM_APPS]; /* HL Control Blocks */
+ tBTA_HL_CTRL_CBACK* p_ctrl_cback; /* pointer to control callback function */
+ uint8_t next_app_id;
+ uint16_t next_channel_id;
+ btif_hl_state_t state;
+} btif_hl_cb_t;
+
+typedef uint8_t btif_hl_evt_t;
+
+typedef struct {
+ int app_id;
+ BD_ADDR bd_addr;
+ int mdep_cfg_index;
+ int channel_id;
+ btif_hl_chan_cb_state_t cb_state;
+ int fd;
+} btif_hl_send_chan_state_cb_t;
+
+typedef struct { uint8_t app_idx; } btif_hl_reg_t;
+
+typedef btif_hl_reg_t btif_hl_unreg_t;
+typedef btif_hl_reg_t btif_hl_update_mdl_t;
+
+typedef union {
+ btif_hl_send_chan_state_cb_t chan_cb;
+ btif_hl_reg_t reg;
+ btif_hl_unreg_t unreg;
+ btif_hl_update_mdl_t update_mdl;
+} btif_hl_evt_cb_t;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+#define BTIF_HL_GET_CB_PTR() &(btif_hl_cb)
+#define BTIF_HL_GET_APP_CB_PTR(app_idx) &(btif_hl_cb.acb[(app_idx)])
+#define BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx) \
+ &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)])
+#define BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx) \
+ &(btif_hl_cb.acb[(app_idx)].mcb[(mcl_idx)].mdl[mdl_idx])
+#define BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx) \
+ &(btif_hl_cb.acb[app_idx].mcb[mcl_idx].pcb)
+#define BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx) \
+ &(btif_hl_cb.acb[(app_idx)].mdl_cfg[(item_idx)])
+#define BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx) \
+ &(btif_hl_cb.acb[(app_idx)].mdl_cfg_channel_id[(item_idx)])
+
+extern btif_hl_cb_t btif_hl_cb;
+extern btif_hl_cb_t* p_btif_hl_cb;
+
+extern bool btif_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+ uint8_t* p_mcl_idx);
+extern bool btif_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx);
+extern bool btif_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx);
+extern bool btif_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx);
+extern bool btif_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+ uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx);
+extern bool btif_hl_save_mdl_cfg(uint8_t app_id, uint8_t item_idx,
+ tBTA_HL_MDL_CFG* p_mdl_cfg);
+extern bool btif_hl_delete_mdl_cfg(uint8_t app_id, uint8_t item_idx);
+extern bool btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx,
+ uint8_t* p_mdl_idx);
+extern void btif_hl_abort_pending_chan_setup(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_proc_pending_op(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+ tBTA_HL_MDL_CFG* p_mdl_buf);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_mce.h b/mtkbt/code/bt/btif/include/btif_mce.h
new file mode 100755
index 0000000..dabcb39
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_mce.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_mce.h
+ *
+ * Description: Bluetooth MCE Interface
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_MCE_H
+#define BTIF_MCE_H
+
+#include <hardware/bt_mce.h>
+
+btmce_interface_t* btif_mce_get_interface();
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_pan.h b/mtkbt/code/bt/btif/include/btif_pan.h
new file mode 100755
index 0000000..96874d6
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_pan.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_pan.h
+ *
+ * Description: Bluetooth pan Interface
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_PAN_H
+#define BTIF_PAN_H
+
+#include <hardware/bt_pan.h>
+
+btpan_interface_t* btif_pan_interface();
+void btif_pan_init();
+void btif_pan_cleanup();
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_pan_internal.h b/mtkbt/code/bt/btif/include/btif_pan_internal.h
new file mode 100755
index 0000000..0f47802
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_pan_internal.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_pan_internal.h
+ *
+ * Description: Bluetooth pan internal
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_PAN_INTERNAL_H
+#define BTIF_PAN_INTERNAL_H
+
+#include "bt_types.h"
+#include "btif_pan.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define PAN_NAP_SERVICE_NAME "Android Network Access Point"
+#define PANU_SERVICE_NAME "Android Network User"
+#define TAP_IF_NAME "bt-pan"
+#define ETH_ADDR_LEN 6
+#define TAP_MAX_PKT_WRITE_LEN 2000
+#ifndef PAN_SECURITY
+#define PAN_SECURITY \
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | \
+ BTM_SEC_OUT_ENCRYPT)
+#endif
+
+#define PAN_STATE_UNKNOWN 0
+#define PAN_STATE_OPEN 1
+#define PAN_STATE_CLOSE 2
+#ifndef PAN_ROLE_INACTIVE
+#define PAN_ROLE_INACTIVE 0
+#endif
+
+/*******************************************************************************
+ * Type definitions and return values
+ ******************************************************************************/
+
+typedef struct eth_hdr {
+ unsigned char h_dest[ETH_ADDR_LEN];
+ unsigned char h_src[ETH_ADDR_LEN];
+ short h_proto;
+} tETH_HDR;
+
+typedef struct {
+ int handle;
+ int state;
+ uint16_t protocol;
+ BD_ADDR peer;
+ int local_role;
+ int remote_role;
+ unsigned char eth_addr[ETH_ADDR_LEN];
+} btpan_conn_t;
+
+typedef struct {
+ int btl_if_handle;
+ int btl_if_handle_panu;
+ int tap_fd;
+ int enabled;
+ int open_count;
+ int flow; // 1: outbound data flow on; 0: outbound data flow off
+ btpan_conn_t conns[MAX_PAN_CONNS];
+ int congest_packet_size;
+ unsigned char congest_packet[1600]; // max ethernet packet size
+} btpan_cb_t;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+extern btpan_cb_t btpan_cb;
+btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role,
+ int peer_role);
+btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr);
+btpan_conn_t* btpan_find_conn_handle(uint16_t handle);
+void btpan_set_flow_control(bool enable);
+int btpan_get_connected_count(void);
+int btpan_tap_open(void);
+void create_tap_read_thread(int tap_fd);
+void destroy_tap_read_thread(void);
+int btpan_tap_close(int tap_fd);
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst,
+ uint16_t protocol, const char* buff, uint16_t size, bool ext,
+ bool forward);
+
+static inline int is_empty_eth_addr(const BD_ADDR addr) {
+ int i;
+ for (i = 0; i < BD_ADDR_LEN; i++)
+ if (addr[i] != 0) return 0;
+ return 1;
+}
+
+static inline int is_valid_bt_eth_addr(const BD_ADDR addr) {
+ if (is_empty_eth_addr(addr)) return 0;
+ return addr[0] & 1 ? 0 : 1; /* Cannot be multicasting address */
+}
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_profile_queue.h b/mtkbt/code/bt/btif/include/btif_profile_queue.h
new file mode 100755
index 0000000..01aa8f0
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_profile_queue.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_profile_queue.h
+ *
+ * Description: Bluetooth remote device connection queuing
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_PROFILE_QUEUE_H
+#define BTIF_PROFILE_QUEUE_H
+
+#include <hardware/bluetooth.h>
+
+typedef bt_status_t (*btif_connect_cb_t)(bt_bdaddr_t* bda, uint16_t uuid);
+
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
+ btif_connect_cb_t connect_cb);
+void btif_queue_advance();
+bt_status_t btif_queue_connect_next(void);
+void btif_queue_release();
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sdp.h b/mtkbt/code/bt/btif/include/btif_sdp.h
new file mode 100755
index 0000000..7e224b0
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sdp.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sdp.h
+ *
+ * Description: Bluetooth SDP search Interface
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SDP_H
+#define BTIF_SDP_H
+
+#include <hardware/bt_sdp.h>
+
+btsdp_interface_t* btif_sdp_get_interface();
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sm.h b/mtkbt/code/bt/btif/include/btif_sm.h
new file mode 100755
index 0000000..129e312
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sm.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: btif_sm.h
+ *
+ * Description: Generic BTIF state machine API
+ *
+ *****************************************************************************/
+
+#ifndef BTIF_SM_H
+#define BTIF_SM_H
+
+#include <hardware/bluetooth.h>
+
+#include "stack/include/bt_types.h"
+
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+/* Generic Enter/Exit state machine events */
+#define BTIF_SM_ENTER_EVT 0xFFFF
+#define BTIF_SM_EXIT_EVT 0xFFFE
+
+/*****************************************************************************
+ * Type definitions and return values
+ *****************************************************************************/
+typedef uint32_t btif_sm_state_t;
+typedef uint32_t btif_sm_event_t;
+typedef void* btif_sm_handle_t;
+typedef bool (*btif_sm_handler_t)(btif_sm_event_t event, void* data);
+
+/*****************************************************************************
+ * Functions
+ *
+ * NOTE: THESE APIs SHOULD BE INVOKED ONLY IN THE BTIF CONTEXT
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function btif_sm_init
+ *
+ * Description Initializes the state machine with the state handlers
+ * The caller should ensure that the table and the corresponding
+ * states match. The location that 'p_handlers' points to shall
+ * be available until the btif_sm_shutdown API is invoked.
+ *
+ * Returns Returns a pointer to the initialized state machine handle.
+ *
+ *****************************************************************************/
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
+ btif_sm_state_t initial_state);
+
+/*****************************************************************************
+ *
+ * Function btif_sm_shutdown
+ *
+ * Description Tears down the state machine
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle);
+
+/*****************************************************************************
+ *
+ * Function btif_sm_get_state
+ *
+ * Description Fetches the current state of the state machine
+ *
+ * Returns Current state
+ *
+ *****************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle);
+
+/*****************************************************************************
+ *
+ * Function btif_sm_dispatch
+ *
+ * Description Dispatches the 'event' along with 'data' to the current state
+ * handler
+ *
+ * Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+ void* data);
+
+/*****************************************************************************
+ *
+ * Function btif_sm_change_state
+ *
+ * Description Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+ * shall be invoked before exiting the current state. The
+ * 'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
+ * state
+ *
+ * Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
+ btif_sm_state_t state);
+
+#endif /* BTIF_SM_H */
diff --git a/mtkbt/code/bt/btif/include/btif_sock.h b/mtkbt/code/bt/btif/include/btif_sock.h
new file mode 100755
index 0000000..e65def6
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "btif_uid.h"
+
+#include <hardware/bt_sock.h>
+
+btsock_interface_t* btif_sock_get_interface(void);
+
+bt_status_t btif_sock_init(uid_set_t* uid_set);
+void btif_sock_cleanup(void);
diff --git a/mtkbt/code/bt/btif/include/btif_sock_l2cap.h b/mtkbt/code/bt/btif/include/btif_sock_l2cap.h
new file mode 100755
index 0000000..37fa90e
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_l2cap.h
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * L2CAP Socket Interface
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_L2CAP_H
+#define BTIF_SOCK_L2CAP_H
+
+#include "btif_uid.h"
+
+#include <hardware/bluetooth.h>
+
+#define L2CAP_MASK_FIXED_CHANNEL 0x10000
+#define L2CAP_MASK_LE_COC_CHANNEL 0x20000
+
+bt_status_t btsock_l2cap_init(int handle, uid_set_t* set);
+bt_status_t btsock_l2cap_cleanup();
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd,
+ int flags, int app_uid);
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t* bd_addr, int channel,
+ int* sock_fd, int flags, int app_uid);
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id);
+void on_l2cap_psm_assigned(int id, int psm);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sock_rfc.h b/mtkbt/code/bt/btif/include/btif_sock_rfc.h
new file mode 100755
index 0000000..50aecd7
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_rfc.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock.h
+ *
+ * Description: Bluetooth socket Interface
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_RFC_H
+#define BTIF_SOCK_RFC_H
+
+#include "btif_uid.h"
+
+bt_status_t btsock_rfc_init(int handle, uid_set_t* set);
+bt_status_t btsock_rfc_cleanup();
+bt_status_t btsock_rfc_listen(const char* name, const uint8_t* uuid,
+ int channel, int* sock_fd, int flags,
+ int app_uid);
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t* bd_addr, const uint8_t* uuid,
+ int channel, int* sock_fd, int flags,
+ int app_uid);
+void btsock_rfc_signaled(int fd, int flags, uint32_t user_id);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sock_sco.h b/mtkbt/code/bt/btif/include/btif_sock_sco.h
new file mode 100755
index 0000000..66859d7
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_sco.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+
+typedef struct thread_t thread_t;
+
+bt_status_t btsock_sco_init(thread_t* thread);
+bt_status_t btsock_sco_cleanup(void);
+bt_status_t btsock_sco_listen(int* sock_fd, int flags);
+bt_status_t btsock_sco_connect(const bt_bdaddr_t* bd_addr, int* sock_fd,
+ int flags);
diff --git a/mtkbt/code/bt/btif/include/btif_sock_sdp.h b/mtkbt/code/bt/btif/include/btif_sock_sdp.h
new file mode 100755
index 0000000..7672c7c
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_sdp.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_SDP_H
+#define BTIF_SOCK_SDP_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+static const uint8_t UUID_OBEX_OBJECT_PUSH[] = {
+ 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+static const uint8_t UUID_SPP[] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+
+static inline bool is_uuid_empty(const uint8_t* uuid) {
+ static uint8_t empty_uuid[16];
+ return uuid == NULL || memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0;
+}
+
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, int scn);
+void del_rfc_sdp_rec(int handle);
+bool is_reserved_rfc_channel(int channel);
+int get_reserved_rfc_channel(const uint8_t* uuid);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sock_thread.h b/mtkbt/code/bt/btif/include/btif_sock_thread.h
new file mode 100755
index 0000000..d50a09d
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_thread.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_THREAD_H
+#define BTIF_SOCK_THREAD_H
+
+#include <stdbool.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define SOCK_THREAD_FD_RD 1 /* BT socket read signal */
+#define SOCK_THREAD_FD_WR (1 << 1) /* BT socket write signal */
+#define SOCK_THREAD_FD_EXCEPTION (1 << 2) /* BT socket exception singal */
+
+/* Add BT socket fd in current socket poll thread context immediately */
+#define SOCK_THREAD_ADD_FD_SYNC (1 << 3)
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+typedef void (*btsock_signaled_cb)(int fd, int type, int flags,
+ uint32_t user_id);
+typedef void (*btsock_cmd_cb)(int cmd_fd, int type, int size, uint32_t user_id);
+
+int btsock_thread_init();
+int btsock_thread_add_fd(int handle, int fd, int type, int flags,
+ uint32_t user_id);
+bool btsock_thread_remove_fd_and_close(int thread_handle, int fd);
+int btsock_thread_wakeup(int handle);
+int btsock_thread_post_cmd(int handle, int cmd_type,
+ const unsigned char* cmd_data, int data_size,
+ uint32_t user_id);
+int btsock_thread_create(btsock_signaled_cb callback,
+ btsock_cmd_cb cmd_callback);
+int btsock_thread_exit(int handle);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_sock_util.h b/mtkbt/code/bt/btif/include/btif_sock_util.h
new file mode 100755
index 0000000..90cfb9a
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_sock_util.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock_util.h
+ *
+ * Description: Bluetooth socket Interface Helper functions
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_SOCK_UTIL_H
+#define BTIF_SOCK_UTIL_H
+
+#include <stdint.h>
+
+void dump_bin(const char* title, const char* data, int size);
+
+int sock_send_fd(int sock_fd, const uint8_t* buffer, int len, int send_fd);
+int sock_send_all(int sock_fd, const uint8_t* buf, int len);
+int sock_recv_all(int sock_fd, uint8_t* buf, int len);
+
+#endif
diff --git a/mtkbt/code/bt/btif/include/btif_storage.h b/mtkbt/code/bt/btif/include/btif_storage.h
new file mode 100755
index 0000000..a787613
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_storage.h
@@ -0,0 +1,278 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_STORAGE_H
+#define BTIF_STORAGE_H
+
+#include <hardware/bluetooth.h>
+
+#include "bt_target.h"
+#include "bt_types.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+#define BTIF_STORAGE_FILL_PROPERTY(p_prop, t, l, p_v) \
+ do { \
+ (p_prop)->type = (t); \
+ (p_prop)->len = (l); \
+ (p_prop)->val = (p_v); \
+ } while (0)
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_adapter_property
+ *
+ * Description BTIF storage API - Fetches the adapter property->type
+ * from NVRAM and fills property->val.
+ * Caller should provide memory for property->val and
+ * set the property->val
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_adapter_property
+ *
+ * Description BTIF storage API - Stores the adapter property
+ * to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_remote_device_property
+ *
+ * Description BTIF storage API - Fetches the remote device property->type
+ * from NVRAM and fills property->val.
+ * Caller should provide memory for property->val and
+ * set the property->val
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+ bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_remote_device_property
+ *
+ * Description BTIF storage API - Stores the remote device property
+ * to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+ bt_property_t* property);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_remote_device
+ *
+ * Description BTIF storage API - Adds a newly discovered device to
+ * track along with the timestamp. Also, stores the various
+ * properties - RSSI, BDADDR, NAME (if found in EIR)
+ *
+ * Returns BT_STATUS_SUCCESS if successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t* remote_bd_addr,
+ uint32_t num_properties,
+ bt_property_t* properties);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_bonded_device
+ *
+ * Description BTIF storage API - Adds the newly bonded device to NVRAM
+ * along with the link-key, Key type and Pin key length
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t* remote_bd_addr,
+ LINK_KEY link_key, uint8_t key_type,
+ uint8_t pin_length);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_bonded_device
+ *
+ * Description BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_bonded_device
+ *
+ * Description BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_hid_device_info
+ *
+ * Description BTIF storage API - Adds the hid information of bonded hid
+ * devices-to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_hid_device_info(
+ bt_bdaddr_t* remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
+ uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
+ uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
+ uint16_t dl_len, uint8_t* dsc_list);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_load_bonded_hid_info
+ *
+ * Description BTIF storage API - Loads hid info for all the bonded devices
+ * from NVRAM and adds those devices to the BTA_HH.
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hid_info
+ *
+ * Description BTIF storage API - Deletes the bonded hid device info from
+ * NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_is_retricted_device
+ *
+ * Description BTIF storage API - checks if this device is a restricted
+ * device
+ *
+ * Returns true if the device is labled as restricted
+ * false otherwise
+ *
+ ******************************************************************************/
+bool btif_storage_is_restricted_device(const bt_bdaddr_t* remote_bd_addr);
+
+bt_status_t btif_storage_add_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+ char* key, uint8_t key_type,
+ uint8_t key_length);
+bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+ uint8_t key_type, char* key_value,
+ int key_length);
+
+bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
+ uint8_t key_length);
+bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t* remote_bd_addr);
+bt_status_t btif_storage_remove_ble_local_keys(void);
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
+ int key_len);
+
+bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+ int* addr_type);
+
+bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+ uint8_t addr_type);
+
+/*******************************************************************************
+ * Function btif_storage_load_hidd
+ *
+ * Description Loads hidd bonded device and "plugs" it into hidd
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_hidd(void);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_hidd
+ *
+ * Description Stores hidd bonded device info in nvram.
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hidd
+ *
+ * Description Removes hidd bonded device info from nvram
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr);
+
+// Gets the device name for a given Bluetooth address |bd_addr|.
+// The device name (if found) is stored in |name|.
+// Returns true if the device name is found, othervise false.
+// Note: |name| should point to a buffer that can store string of length
+// |BTM_MAX_REM_BD_NAME_LEN|.
+bool btif_storage_get_stored_remote_name(const bt_bdaddr_t& bd_addr,
+ char* name);
+
+/******************************************************************************
+ * Exported for unit tests
+ *****************************************************************************/
+size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+ size_t max_uuids);
+
+#endif /* BTIF_STORAGE_H */
diff --git a/mtkbt/code/bt/btif/include/btif_uid.h b/mtkbt/code/bt/btif/include/btif_uid.h
new file mode 100755
index 0000000..35faedb
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_uid.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "bt_common.h"
+
+#include <hardware/bluetooth.h>
+
+struct uid_set_t;
+typedef struct uid_set_t uid_set_t;
+
+/**
+ * Creates a UID set to keep track of traffic per UID.
+ * Caller is responsible for destroying this object via uid_set_destroy().
+ */
+uid_set_t* uid_set_create();
+
+void uid_set_destroy(uid_set_t* set);
+
+void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes);
+void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes);
+
+/**
+ * Returns an array of bt_uid_traffic_t structs, where the end of the array
+ * is signaled by an element with app_uid == -1.
+ *
+ * The caller is responsible for calling osi_free() on the returned array.
+ */
+bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set);
diff --git a/mtkbt/code/bt/btif/include/btif_util.h b/mtkbt/code/bt/btif/include/btif_util.h
new file mode 100755
index 0000000..a1a6492
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/btif_util.h
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTIF_UTIL_H
+#define BTIF_UTIL_H
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+/*******************************************************************************
+ * Type definitions for callback functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+const char* dump_bt_status(bt_status_t status);
+const char* dump_dm_search_event(uint16_t event);
+const char* dump_dm_event(uint16_t event);
+const char* dump_hf_event(uint16_t event);
+const char* dump_hf_client_event(uint16_t event);
+const char* dump_hh_event(uint16_t event);
+const char* dump_hd_event(uint16_t event);
+const char* dump_hf_conn_state(uint16_t event);
+const char* dump_hf_call_state(bthf_call_state_t call_state);
+const char* dump_property_type(bt_property_type_t type);
+const char* dump_hf_audio_state(uint16_t event);
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode);
+const char* dump_thread_evt(bt_cb_thread_evt evt);
+const char* dump_av_conn_state(uint16_t event);
+const char* dump_av_audio_state(uint16_t event);
+const char* dump_rc_event(uint8_t event);
+const char* dump_rc_notification_event_id(uint8_t event_id);
+const char* dump_rc_pdu(uint8_t pdu);
+
+uint32_t devclass2uint(DEV_CLASS dev_class);
+void uint2devclass(uint32_t dev, DEV_CLASS dev_class);
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128);
+
+// Takes a |str| containing a 128-bit GUID formatted UUID and stores the
+// result in |p_uuid|. |str| must be formatted in this format:
+// "12345678-1234-1234-1234-123456789012"
+// |p_uuid| cannot be null. Returns true if parsing was successful, false
+// otherwise. Returns false if |str| is null.
+bool string_to_uuid(const char* str, bt_uuid_t* p_uuid);
+
+int ascii_2_hex(const char* p_ascii, int len, uint8_t* p_hex);
+
+void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len);
+
+#endif /* BTIF_UTIL_H */
diff --git a/mtkbt/code/bt/btif/include/stack_manager.h b/mtkbt/code/bt/btif/include/stack_manager.h
new file mode 100755
index 0000000..90d81c5
--- a/dev/null
+++ b/mtkbt/code/bt/btif/include/stack_manager.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "osi/include/future.h"
+
+typedef struct {
+ void (*init_stack)(void);
+ void (*start_up_stack_async)(void);
+ void (*shut_down_stack_async)(void);
+ void (*clean_up_stack)(void);
+
+ bool (*get_stack_is_running)(void);
+} stack_manager_t;
+
+const stack_manager_t* stack_manager_get_interface();
+
+// TODO(zachoverflow): remove this terrible hack once the startup sequence is
+// more sane
+future_t* stack_manager_get_hack_future();
diff --git a/mtkbt/code/bt/btif/src/bluetooth.cc b/mtkbt/code/bt/btif/src/bluetooth.cc
new file mode 100755
index 0000000..9885117
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/bluetooth.cc
@@ -0,0 +1,486 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: bluetooth.c
+ *
+ * Description: Bluetooth HAL implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif"
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_hd.h>
+#include <hardware/bt_hf.h>
+#include <hardware/bt_hf_client.h>
+#include <hardware/bt_hh.h>
+#include <hardware/bt_hl.h>
+#include <hardware/bt_mce.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_rc.h>
+#include <hardware/bt_sdp.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_utils.h"
+#include "bta/include/bta_hf_client_api.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "btif/include/btif_debug_conn.h"
+#include "btif_a2dp.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_debug.h"
+#include "btif_storage.h"
+#include "btsnoop.h"
+#include "btsnoop_mem.h"
+#include "device/include/interop.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/wakelock.h"
+#include "stack_manager.h"
+
+/* Test interface includes */
+#include "mca_api.h"
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+bt_callbacks_t* bt_hal_cbacks = NULL;
+bool restricted_mode = false;
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+
+/* list all extended interfaces here */
+
+/* handsfree profile */
+extern bthf_interface_t* btif_hf_get_interface();
+/* handsfree profile - client */
+extern bthf_client_interface_t* btif_hf_client_get_interface();
+/* advanced audio profile */
+extern btav_source_interface_t* btif_av_get_src_interface();
+extern btav_sink_interface_t* btif_av_get_sink_interface();
+/*rfc l2cap*/
+extern btsock_interface_t* btif_sock_get_interface();
+/* hid host profile */
+extern bthh_interface_t* btif_hh_get_interface();
+/* hid device profile */
+extern bthd_interface_t* btif_hd_get_interface();
+/* health device profile */
+extern bthl_interface_t* btif_hl_get_interface();
+/*pan*/
+extern btpan_interface_t* btif_pan_get_interface();
+/*map client*/
+extern btmce_interface_t* btif_mce_get_interface();
+/* gatt */
+extern const btgatt_interface_t* btif_gatt_get_interface();
+/* avrc target */
+extern btrc_interface_t* btif_rc_get_interface();
+/* avrc controller */
+extern btrc_interface_t* btif_rc_ctrl_get_interface();
+/*SDP search client*/
+extern btsdp_interface_t* btif_sdp_get_interface();
+
+/* List all test interface here */
+extern btmcap_test_interface_t* stack_mcap_get_interface();
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+static bool interface_ready(void) { return bt_hal_cbacks != NULL; }
+
+static bool is_profile(const char* p1, const char* p2) {
+ CHECK(p1);
+ CHECK(p2);
+ return strlen(p1) == strlen(p2) && strncmp(p1, p2, strlen(p2)) == 0;
+}
+
+/*****************************************************************************
+ *
+ * BLUETOOTH HAL INTERFACE FUNCTIONS
+ *
+ ****************************************************************************/
+
+static int init(bt_callbacks_t* callbacks) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (interface_ready()) return BT_STATUS_DONE;
+
+#ifdef BLUEDROID_DEBUG
+ allocation_tracker_init();
+#endif
+
+ bt_hal_cbacks = callbacks;
+ stack_manager_get_interface()->init_stack();
+ btif_debug_init();
+ return BT_STATUS_SUCCESS;
+}
+
+static int enable(bool start_restricted) {
+ LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);
+
+ restricted_mode = start_restricted;
+
+ if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+ stack_manager_get_interface()->start_up_stack_async();
+ return BT_STATUS_SUCCESS;
+}
+
+static int disable(void) {
+ if (!interface_ready()) return BT_STATUS_NOT_READY;
+
+ stack_manager_get_interface()->shut_down_stack_async();
+ return BT_STATUS_SUCCESS;
+}
+
+static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }
+
+bool is_restricted_mode() { return restricted_mode; }
+
+static int get_adapter_properties(void) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_properties();
+}
+
+static int get_adapter_property(bt_property_type_t type) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_get_adapter_property(type);
+}
+
+static int set_adapter_property(const bt_property_t* property) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_set_adapter_property(property);
+}
+
+int get_remote_device_properties(bt_bdaddr_t* remote_addr) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_properties(remote_addr);
+}
+
+int get_remote_device_property(bt_bdaddr_t* remote_addr,
+ bt_property_type_t type) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_device_property(remote_addr, type);
+}
+
+int set_remote_device_property(bt_bdaddr_t* remote_addr,
+ const bt_property_t* property) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_set_remote_device_property(remote_addr, property);
+}
+
+int get_remote_service_record(bt_bdaddr_t* remote_addr, bt_uuid_t* uuid) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_get_remote_service_record(remote_addr, uuid);
+}
+
+int get_remote_services(bt_bdaddr_t* remote_addr) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_get_remote_services(remote_addr);
+}
+
+static int start_discovery(void) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_start_discovery();
+}
+
+static int cancel_discovery(void) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_discovery();
+}
+
+static int create_bond(const bt_bdaddr_t* bd_addr, int transport) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_create_bond(bd_addr, transport);
+}
+
+static int create_bond_out_of_band(const bt_bdaddr_t* bd_addr, int transport,
+ const bt_out_of_band_data_t* oob_data) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_create_bond_out_of_band(bd_addr, transport, oob_data);
+}
+
+static int cancel_bond(const bt_bdaddr_t* bd_addr) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_cancel_bond(bd_addr);
+}
+
+static int remove_bond(const bt_bdaddr_t* bd_addr) {
+ if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr))
+ return BT_STATUS_SUCCESS;
+
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_remove_bond(bd_addr);
+}
+
+static int get_connection_state(const bt_bdaddr_t* bd_addr) {
+ /* sanity check */
+ if (interface_ready() == false) return 0;
+
+ return btif_dm_get_connection_state(bd_addr);
+}
+
+static int pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t* pin_code) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_pin_reply(bd_addr, accept, pin_len, pin_code);
+}
+
+static int ssp_reply(const bt_bdaddr_t* bd_addr, bt_ssp_variant_t variant,
+ uint8_t accept, uint32_t passkey) {
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dm_ssp_reply(bd_addr, variant, accept, passkey);
+}
+
+static int read_energy_info() {
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+ btif_dm_read_energy_info();
+ return BT_STATUS_SUCCESS;
+}
+
+static void dump(int fd, const char** arguments) {
+ if (arguments != NULL && arguments[0] != NULL) {
+ if (strncmp(arguments[0], "--proto-bin", 11) == 0) {
+ system_bt_osi::BluetoothMetricsLogger::GetInstance()->WriteBase64(fd,
+ true);
+ return;
+ }
+ }
+ btif_debug_conn_dump(fd);
+ btif_debug_bond_event_dump(fd);
+ btif_debug_a2dp_dump(fd);
+ btif_debug_config_dump(fd);
+ BTA_HfClientDumpStatistics(fd);
+ wakelock_debug_dump(fd);
+ osi_allocator_debug_dump(fd);
+ alarm_debug_dump(fd);
+#if (BTSNOOP_MEM == TRUE)
+ btif_debug_btsnoop_dump(fd);
+#endif
+
+ close(fd);
+}
+
+static const void* get_profile_interface(const char* profile_id) {
+ LOG_INFO(LOG_TAG, "%s: id = %s", __func__, profile_id);
+
+ /* sanity check */
+ if (interface_ready() == false) return NULL;
+
+ /* check for supported profile interfaces */
+ if (is_profile(profile_id, BT_PROFILE_HANDSFREE_ID))
+ return btif_hf_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HANDSFREE_CLIENT_ID))
+ return btif_hf_client_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_SOCKETS_ID))
+ return btif_sock_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_PAN_ID))
+ return btif_pan_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_ID))
+ return btif_av_get_src_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_ADVANCED_AUDIO_SINK_ID))
+ return btif_av_get_sink_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
+ return btif_hh_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HIDDEV_ID))
+ return btif_hd_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_HEALTH_ID))
+ return btif_hl_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_SDP_CLIENT_ID))
+ return btif_sdp_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_GATT_ID))
+ return btif_gatt_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_AV_RC_ID))
+ return btif_rc_get_interface();
+
+ if (is_profile(profile_id, BT_PROFILE_AV_RC_CTRL_ID))
+ return btif_rc_ctrl_get_interface();
+
+ if (is_profile(profile_id, BT_TEST_INTERFACE_MCAP_ID))
+ return stack_mcap_get_interface();
+
+ return NULL;
+}
+
+int dut_mode_configure(uint8_t enable) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dut_mode_configure(enable);
+}
+
+int dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_dut_mode_send(opcode, buf, len);
+}
+
+int le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ /* sanity check */
+ if (interface_ready() == false) return BT_STATUS_NOT_READY;
+
+ return btif_le_test_mode(opcode, buf, len);
+}
+
+static int set_os_callouts(bt_os_callouts_t* callouts) {
+ wakelock_set_os_callouts(callouts);
+ return BT_STATUS_SUCCESS;
+}
+
+static int config_clear(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ return btif_config_clear() ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+static const bt_interface_t bluetoothInterface = {
+ sizeof(bluetoothInterface),
+ init,
+ enable,
+ disable,
+ cleanup,
+ get_adapter_properties,
+ get_adapter_property,
+ set_adapter_property,
+ get_remote_device_properties,
+ get_remote_device_property,
+ set_remote_device_property,
+ get_remote_service_record,
+ get_remote_services,
+ start_discovery,
+ cancel_discovery,
+ create_bond,
+ create_bond_out_of_band,
+ remove_bond,
+ cancel_bond,
+ get_connection_state,
+ pin_reply,
+ ssp_reply,
+ get_profile_interface,
+ dut_mode_configure,
+ dut_mode_send,
+ le_test_mode,
+ set_os_callouts,
+ read_energy_info,
+ dump,
+ config_clear,
+ interop_database_clear,
+ interop_database_add,
+};
+
+const bt_interface_t* bluetooth__get_bluetooth_interface() {
+ /* fixme -- add property to disable bt interface ? */
+
+ return &bluetoothInterface;
+}
+
+static int close_bluetooth_stack(UNUSED_ATTR struct hw_device_t* device) {
+ cleanup();
+ return 0;
+}
+
+static int open_bluetooth_stack(const struct hw_module_t* module,
+ UNUSED_ATTR char const* name,
+ struct hw_device_t** abstraction) {
+ static bluetooth_device_t device;
+ device.common.tag = HARDWARE_DEVICE_TAG;
+ device.common.version = 0;
+ device.common.close = close_bluetooth_stack;
+ device.get_bluetooth_interface = bluetooth__get_bluetooth_interface;
+ device.common.module = (struct hw_module_t*)module;
+ *abstraction = (struct hw_device_t*)&device;
+ return 0;
+}
+
+static struct hw_module_methods_t bt_stack_module_methods = {
+ .open = open_bluetooth_stack,
+};
+
+EXPORT_SYMBOL struct hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = BT_HARDWARE_MODULE_ID,
+ .name = "Bluetooth Stack",
+ .author = "The Android Open Source Project",
+ .methods = &bt_stack_module_methods};
diff --git a/mtkbt/code/bt/btif/src/btif_a2dp.cc b/mtkbt/code/bt/btif/src/btif_a2dp.cc
new file mode 100755
index 0000000..7c83ff9
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_a2dp.cc
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp"
+
+#include <stdbool.h>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bta_av_api.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_util.h"
+#include "osi/include/log.h"
+
+void btif_a2dp_on_idle(void) {
+ APPL_TRACE_EVENT("## ON A2DP IDLE ## peer_sep = %d", btif_av_get_peer_sep());
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
+ btif_a2dp_source_on_idle();
+ } else if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_on_idle();
+ }
+}
+
+bool btif_a2dp_on_started(tBTA_AV_START* p_av_start, bool pending_start) {
+ bool ack = false;
+
+ APPL_TRACE_EVENT("## ON A2DP STARTED ##");
+
+ if (p_av_start == NULL) {
+ /* ack back a local start request */
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ return true;
+ }
+
+ if (p_av_start->status == BTA_AV_SUCCESS) {
+ if (!p_av_start->suspending) {
+ if (p_av_start->initiator) {
+ if (pending_start) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ ack = true;
+ }
+ } else {
+ /* We were remotely started, make sure codec
+ * is setup before datapath is started.
+ */
+ btif_a2dp_source_setup_codec();
+ }
+
+ /* media task is autostarted upon a2dp audiopath connection */
+ }
+ } else if (pending_start) {
+ APPL_TRACE_WARNING("%s: A2DP start request failed: status = %d", __func__,
+ p_av_start->status);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ ack = true;
+ }
+ return ack;
+}
+
+void btif_a2dp_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
+ APPL_TRACE_EVENT("## ON A2DP STOPPED ##");
+
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_on_stopped(p_av_suspend);
+ return;
+ }
+
+ btif_a2dp_source_on_stopped(p_av_suspend);
+}
+
+void btif_a2dp_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
+ APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##");
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_on_suspended(p_av_suspend);
+ } else {
+ btif_a2dp_source_on_suspended(p_av_suspend);
+ }
+}
+
+void btif_a2dp_on_offload_started(tBTA_AV_STATUS status) {
+ tA2DP_CTRL_ACK ack;
+ APPL_TRACE_EVENT("%s status %d", __func__, status);
+
+ switch (status) {
+ case BTA_AV_SUCCESS:
+ ack = A2DP_CTRL_ACK_SUCCESS;
+ break;
+ case BTA_AV_FAIL_RESOURCES:
+ APPL_TRACE_ERROR("%s FAILED UNSUPPORTED", __func__);
+ ack = A2DP_CTRL_ACK_UNSUPPORTED;
+ break;
+ default:
+ APPL_TRACE_ERROR("%s FAILED: status = %d", __func__, status);
+ ack = A2DP_CTRL_ACK_FAILURE;
+ break;
+ }
+ btif_a2dp_command_ack(ack);
+}
+
+void btif_debug_a2dp_dump(int fd) {
+ btif_a2dp_source_debug_dump(fd);
+ btif_a2dp_sink_debug_dump(fd);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_a2dp_control.cc b/mtkbt/code/bt/btif/src/btif_a2dp_control.cc
new file mode 100755
index 0000000..84c7cd7
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_a2dp_control.cc
@@ -0,0 +1,424 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_control"
+
+#include <base/logging.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_hf.h"
+#include "osi/include/osi.h"
+#include "uipc.h"
+
+#define A2DP_DATA_READ_POLL_MS 10
+
+static void btif_a2dp_data_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event);
+
+/* We can have max one command pending */
+static tA2DP_CTRL_CMD a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+
+void btif_a2dp_control_init(void) {
+ UIPC_Init(NULL);
+ UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+}
+
+void btif_a2dp_control_cleanup(void) {
+ /* This calls blocks until UIPC is fully closed */
+ UIPC_Close(UIPC_CH_ID_ALL);
+}
+
+static void btif_a2dp_recv_ctrl_data(void) {
+ tA2DP_CTRL_CMD cmd = A2DP_CTRL_CMD_NONE;
+ int n;
+
+ uint8_t read_cmd = 0; /* The read command size is one octet */
+ n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &read_cmd, 1);
+ cmd = static_cast<tA2DP_CTRL_CMD>(read_cmd);
+
+ /* detach on ctrl channel means audioflinger process was terminated */
+ if (n == 0) {
+ APPL_TRACE_EVENT("CTRL CH DETACHED");
+ UIPC_Close(UIPC_CH_ID_AV_CTRL);
+ return;
+ }
+
+ APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s", audio_a2dp_hw_dump_ctrl_event(cmd));
+ a2dp_cmd_pending = cmd;
+
+ switch (cmd) {
+ case A2DP_CTRL_CMD_CHECK_READY:
+ if (btif_a2dp_source_media_task_is_shutting_down()) {
+ APPL_TRACE_WARNING("%s: A2DP command %s while media task shutting down",
+ __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ return;
+ }
+
+ /* check whether AV is ready to setup A2DP datapath */
+ if (btif_av_stream_ready() || btif_av_stream_started_ready()) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ } else {
+ APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
+ __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+ break;
+
+ case A2DP_CTRL_CMD_START:
+ /*
+ * Don't send START request to stack while we are in a call.
+ * Some headsets such as "Sony MW600", don't allow AVDTP START
+ * while in a call, and respond with BAD_STATE.
+ */
+ if (!btif_hf_is_call_idle()) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
+ break;
+ }
+
+ if (btif_a2dp_source_is_streaming()) {
+ APPL_TRACE_WARNING("%s: A2DP command %s while source is streaming",
+ __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ /***
+ * Check the remote device. If it special device, will
+ * break this loop and delay for 1s. After 1s, it will call
+ * btif_media_av_delay_start_cmd_hdlr to go on.
+ */
+ if(btif_av_is_black_peer())
+ {
+ APPL_TRACE_EVENT("Break and delay 1s for START cmd");
+ break;
+ }
+#endif
+ if (btif_av_stream_ready()) {
+ /* Setup audio data channel listener */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+ /*
+ * Post start event and wait for audio path to open.
+ * If we are the source, the ACK will be sent after the start
+ * procedure is completed, othewise send it now.
+ */
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SRC)
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ }
+
+ if (btif_av_stream_started_ready()) {
+ /*
+ * Already started, setup audio data channel listener and ACK
+ * back immediately.
+ */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ }
+ APPL_TRACE_WARNING("%s: A2DP command %s while AV stream is not ready",
+ __func__, audio_a2dp_hw_dump_ctrl_event(cmd));
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ break;
+
+ case A2DP_CTRL_CMD_STOP:
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
+ !btif_a2dp_source_is_streaming()) {
+ /* We are already stopped, just ack back */
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ break;
+ }
+
+ btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ break;
+
+ case A2DP_CTRL_CMD_SUSPEND:
+ /* Local suspend */
+ if (btif_av_stream_started_ready()) {
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ break;
+ }
+ /* If we are not in started state, just ack back ok and let
+ * audioflinger close the channel. This can happen if we are
+ * remotely suspended, clear REMOTE SUSPEND flag.
+ */
+ btif_av_clear_remote_suspend_flag();
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ break;
+
+ case A2DP_CTRL_GET_INPUT_AUDIO_CONFIG: {
+ tA2DP_SAMPLE_RATE sample_rate = btif_a2dp_sink_get_sample_rate();
+ tA2DP_CHANNEL_COUNT channel_count = btif_a2dp_sink_get_channel_count();
+
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<uint8_t*>(&sample_rate),
+ sizeof(tA2DP_SAMPLE_RATE));
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &channel_count,
+ sizeof(tA2DP_CHANNEL_COUNT));
+ break;
+ }
+
+ case A2DP_CTRL_GET_OUTPUT_AUDIO_CONFIG: {
+ btav_a2dp_codec_config_t codec_config;
+ btav_a2dp_codec_config_t codec_capability;
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_capability.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_capability.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_capability.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+
+ A2dpCodecConfig* current_codec = bta_av_get_a2dp_current_codec();
+ if (current_codec != nullptr) {
+ codec_config = current_codec->getCodecConfig();
+ codec_capability = current_codec->getCodecCapability();
+ }
+
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ // Send the current codec config
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<const uint8_t*>(&codec_config.sample_rate),
+ sizeof(btav_a2dp_codec_sample_rate_t));
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<const uint8_t*>(&codec_config.bits_per_sample),
+ sizeof(btav_a2dp_codec_bits_per_sample_t));
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<const uint8_t*>(&codec_config.channel_mode),
+ sizeof(btav_a2dp_codec_channel_mode_t));
+ // Send the current codec capability
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<const uint8_t*>(&codec_capability.sample_rate),
+ sizeof(btav_a2dp_codec_sample_rate_t));
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<const uint8_t*>(
+ &codec_capability.bits_per_sample),
+ sizeof(btav_a2dp_codec_bits_per_sample_t));
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, reinterpret_cast<const uint8_t*>(
+ &codec_capability.channel_mode),
+ sizeof(btav_a2dp_codec_channel_mode_t));
+ break;
+ }
+
+ case A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG: {
+ btav_a2dp_codec_config_t codec_config;
+ codec_config.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ // Send the current codec config
+ if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<uint8_t*>(&codec_config.sample_rate),
+ sizeof(btav_a2dp_codec_sample_rate_t)) !=
+ sizeof(btav_a2dp_codec_sample_rate_t)) {
+ APPL_TRACE_ERROR("Error reading sample rate from audio HAL");
+ break;
+ }
+ if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<uint8_t*>(&codec_config.bits_per_sample),
+ sizeof(btav_a2dp_codec_bits_per_sample_t)) !=
+ sizeof(btav_a2dp_codec_bits_per_sample_t)) {
+ APPL_TRACE_ERROR("Error reading bits per sample from audio HAL");
+ break;
+ }
+ if (UIPC_Read(UIPC_CH_ID_AV_CTRL, 0,
+ reinterpret_cast<uint8_t*>(&codec_config.channel_mode),
+ sizeof(btav_a2dp_codec_channel_mode_t)) !=
+ sizeof(btav_a2dp_codec_channel_mode_t)) {
+ APPL_TRACE_ERROR("Error reading channel mode from audio HAL");
+ break;
+ }
+ APPL_TRACE_DEBUG(
+ "%s: A2DP_CTRL_SET_OUTPUT_AUDIO_CONFIG: "
+ "sample_rate=0x%x bits_per_sample=0x%x "
+ "channel_mode=0x%x",
+ __func__, codec_config.sample_rate, codec_config.bits_per_sample,
+ codec_config.channel_mode);
+ btif_a2dp_source_feeding_update_req(codec_config);
+ break;
+ }
+
+ case A2DP_CTRL_CMD_OFFLOAD_START:
+ btif_dispatch_sm_event(BTIF_AV_OFFLOAD_START_REQ_EVT, NULL, 0);
+ break;
+
+ default:
+ APPL_TRACE_ERROR("UNSUPPORTED CMD (%d)", cmd);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ break;
+ }
+ APPL_TRACE_DEBUG("a2dp-ctrl-cmd : %s DONE",
+ audio_a2dp_hw_dump_ctrl_event(cmd));
+}
+
+static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
+ tUIPC_EVENT event) {
+ APPL_TRACE_DEBUG("A2DP-CTRL-CHANNEL EVENT %s", dump_uipc_event(event));
+
+ switch (event) {
+ case UIPC_OPEN_EVT:
+ break;
+
+ case UIPC_CLOSE_EVT:
+ /* restart ctrl server unless we are shutting down */
+ if (btif_a2dp_source_media_task_is_running())
+ UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);
+ break;
+
+ case UIPC_RX_DATA_READY_EVT:
+ btif_a2dp_recv_ctrl_data();
+ break;
+
+ default:
+ APPL_TRACE_ERROR("### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###", event);
+ break;
+ }
+}
+
+static void btif_a2dp_data_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
+ tUIPC_EVENT event) {
+ APPL_TRACE_DEBUG("BTIF MEDIA (A2DP-DATA) EVENT %s", dump_uipc_event(event));
+
+ switch (event) {
+ case UIPC_OPEN_EVT:
+ /*
+ * Read directly from media task from here on (keep callback for
+ * connection events.
+ */
+ UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REG_REMOVE_ACTIVE_READSET, NULL);
+ UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
+ reinterpret_cast<void*>(A2DP_DATA_READ_POLL_MS));
+
+ /** M: Bug fix for avoid receive event when media task shutting down@{ */
+ if (btif_a2dp_source_media_task_is_shutting_down())
+ {
+ APPL_TRACE_DEBUG("media task is shutting down");
+ return;
+ }
+ /** @} */
+
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SNK) {
+ /* Start the media task to encode the audio */
+ btif_a2dp_source_start_audio_req();
+ }
+
+ /* ACK back when media task is fully started */
+ break;
+
+ case UIPC_CLOSE_EVT:
+ APPL_TRACE_EVENT("## AUDIO PATH DETACHED ##");
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ /*
+ * Send stop request only if we are actively streaming and haven't
+ * received a stop request. Potentially, the audioflinger detached
+ * abnormally.
+ */
+ if (btif_a2dp_source_is_streaming()) {
+ /* Post stop event and wait for audio path to stop */
+ btif_dispatch_sm_event(BTIF_AV_STOP_STREAM_REQ_EVT, NULL, 0);
+ }
+ break;
+
+ default:
+ APPL_TRACE_ERROR("### A2DP-DATA EVENT %d NOT HANDLED ###", event);
+ break;
+ }
+}
+
+void btif_a2dp_command_ack(tA2DP_CTRL_ACK status) {
+ uint8_t ack = status;
+
+ APPL_TRACE_EVENT("## a2dp ack : %s, status %d ##",
+ audio_a2dp_hw_dump_ctrl_event(a2dp_cmd_pending), status);
+
+ /* Sanity check */
+ if (a2dp_cmd_pending == A2DP_CTRL_CMD_NONE) {
+ APPL_TRACE_ERROR("warning : no command pending, ignore ack");
+ return;
+ }
+
+ /* Clear pending */
+ a2dp_cmd_pending = A2DP_CTRL_CMD_NONE;
+
+ /* Acknowledge start request */
+ UIPC_Send(UIPC_CH_ID_AV_CTRL, 0, &ack, sizeof(ack));
+}
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/*******************************************************************************
+**
+** Function btif_media_av_delay_start_cmd_hdlr
+**
+** Description The call back function to ongoing do A2DP_CTRL_CMD_START
+**
+** Returns void
+**
+*******************************************************************************/
+
+void btif_media_av_delay_start_cmd_hdlr(void *data)
+{
+ APPL_TRACE_EVENT("%s start ", __func__);
+ if (NULL != data) {
+ APPL_TRACE_EVENT("%s Stop timer.", __func__);
+ alarm_cancel((alarm_t *)data);
+ }
+ if (btif_av_stream_ready()) {
+ /* Setup audio data channel listener */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+
+ /*
+ * Post start event and wait for audio path to open.
+ * If we are the source, the ACK will be sent after the start
+ * procedure is completed, othewise send it now.
+ */
+ btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);
+ if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ }
+ return;
+ }
+
+ if (btif_av_stream_started_ready()) {
+ /*
+ * Already started, setup audio data channel listener and ACK
+ * back immediately.
+ */
+ UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ return;
+ }
+ APPL_TRACE_WARNING("%s: A2DP command A2DP_CTRL_CMD_START while AV stream is not ready",
+ __func__);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+
+ APPL_TRACE_EVENT("%s DONE", __func__);
+
+}
+#endif
diff --git a/mtkbt/code/bt/btif/src/btif_a2dp_sink.cc b/mtkbt/code/bt/btif/src/btif_a2dp_sink.cc
new file mode 100755
index 0000000..6564d4d
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_a2dp_sink.cc
@@ -0,0 +1,823 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_sink"
+
+#include <string.h>
+
+#include "bt_common.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_sink.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_avrcp_audio_track.h"
+#include "btif_util.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+#include "oi_codec_sbc.h"
+#include "oi_status.h"
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#include "a2dp_sbc.h"
+#include "a2dp_aac.h"
+#include "aacdecoder_lib.h"
+#define MTK_A2DP_SNK_AAC_DUMP 0
+#if MTK_A2DP_SNK_AAC_DUMP
+FILE* outputAacSampleFp = NULL;
+char outputAacFilename[64] = "/data/misc/bluedroid/outputAac_sample.data";
+#endif
+#endif
+/**
+ * The receiving queue buffer size.
+ */
+#define MAX_INPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2)
+
+#define BTIF_SINK_MEDIA_TIME_TICK_MS 20
+
+/* In case of A2DP Sink, we will delay start by 5 AVDTP Packets */
+#define MAX_A2DP_DELAYED_START_FRAME_COUNT 5
+
+enum {
+ BTIF_A2DP_SINK_STATE_OFF,
+ BTIF_A2DP_SINK_STATE_STARTING_UP,
+ BTIF_A2DP_SINK_STATE_RUNNING,
+ BTIF_A2DP_SINK_STATE_SHUTTING_DOWN
+};
+
+/* BTIF Media Sink command event definition */
+enum {
+ BTIF_MEDIA_SINK_DECODER_UPDATE = 1,
+ BTIF_MEDIA_SINK_CLEAR_TRACK,
+ BTIF_MEDIA_SINK_SET_FOCUS_STATE,
+ BTIF_MEDIA_SINK_AUDIO_RX_FLUSH
+};
+
+typedef struct {
+ BT_HDR hdr;
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+} tBTIF_MEDIA_SINK_DECODER_UPDATE;
+
+typedef struct {
+ BT_HDR hdr;
+ btif_a2dp_sink_focus_state_t focus_state;
+} tBTIF_MEDIA_SINK_FOCUS_UPDATE;
+
+typedef struct {
+ uint16_t num_frames_to_be_processed;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+} tBT_SBC_HDR;
+
+/* BTIF A2DP Sink control block */
+typedef struct {
+ thread_t* worker_thread;
+ fixed_queue_t* cmd_msg_queue;
+ fixed_queue_t* rx_audio_queue;
+ bool rx_flush; /* discards any incoming data when true */
+ alarm_t* decode_alarm;
+ uint8_t frames_to_process;
+ tA2DP_SAMPLE_RATE sample_rate;
+ tA2DP_CHANNEL_COUNT channel_count;
+ btif_a2dp_sink_focus_state_t rx_focus_state; /* audio focus state */
+ void* audio_track;
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ uint8_t codec_type;
+#endif
+} tBTIF_A2DP_SINK_CB;
+
+static tBTIF_A2DP_SINK_CB btif_a2dp_sink_cb;
+
+static int btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+
+static OI_CODEC_SBC_DECODER_CONTEXT btif_a2dp_sink_context;
+static uint32_t btif_a2dp_sink_context_data[CODEC_DATA_WORDS(
+ 2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+static int16_t
+ btif_a2dp_sink_pcm_data[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
+
+static void btif_a2dp_sink_startup_delayed(void* context);
+static void btif_a2dp_sink_shutdown_delayed(void* context);
+static void btif_a2dp_sink_command_ready(fixed_queue_t* queue, void* context);
+static void btif_a2dp_sink_audio_handle_stop_decoding(void);
+static void btif_decode_alarm_cb(void* context);
+static void btif_a2dp_sink_audio_handle_start_decoding(void);
+static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context);
+static void btif_a2dp_sink_audio_rx_flush_req(void);
+/* Handle incoming media packets A2DP SINK streaming */
+static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg);
+static void btif_a2dp_sink_decoder_update_event(
+ tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf);
+static void btif_a2dp_sink_clear_track_event(void);
+static void btif_a2dp_sink_set_focus_state_event(
+ btif_a2dp_sink_focus_state_t state);
+static void btif_a2dp_sink_audio_rx_flush_event(void);
+static void btif_a2dp_sink_clear_track_event_req(void);
+
+UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_DECODER_UPDATE)
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_CLEAR_TRACK)
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_SET_FOCUS_STATE)
+ CASE_RETURN_STR(BTIF_MEDIA_SINK_AUDIO_RX_FLUSH)
+ default:
+ break;
+ }
+ return "UNKNOWN A2DP SINK EVENT";
+}
+
+bool btif_a2dp_sink_startup(void) {
+ if (btif_a2dp_sink_state != BTIF_A2DP_SINK_STATE_OFF) {
+ APPL_TRACE_ERROR("%s: A2DP Sink media task already running", __func__);
+ return false;
+ }
+
+ memset(&btif_a2dp_sink_cb, 0, sizeof(btif_a2dp_sink_cb));
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_STARTING_UP;
+
+ APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
+
+ /* Start A2DP Sink media task */
+ btif_a2dp_sink_cb.worker_thread = thread_new("btif_a2dp_sink_worker_thread");
+ if (btif_a2dp_sink_cb.worker_thread == NULL) {
+ APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+ return false;
+ }
+
+ btif_a2dp_sink_cb.rx_focus_state = BTIF_A2DP_SINK_FOCUS_NOT_GRANTED;
+ btif_a2dp_sink_cb.audio_track = NULL;
+ btif_a2dp_sink_cb.rx_audio_queue = fixed_queue_new(SIZE_MAX);
+
+ btif_a2dp_sink_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+ fixed_queue_register_dequeue(
+ btif_a2dp_sink_cb.cmd_msg_queue,
+ thread_get_reactor(btif_a2dp_sink_cb.worker_thread),
+ btif_a2dp_sink_command_ready, NULL);
+
+ APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##");
+
+ /* Schedule the rest of the startup operations */
+ thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_startup_delayed,
+ NULL);
+
+ return true;
+}
+
+static void btif_a2dp_sink_startup_delayed(UNUSED_ATTR void* context) {
+ raise_priority_a2dp(TASK_HIGH_MEDIA);
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_RUNNING;
+}
+
+void btif_a2dp_sink_shutdown(void) {
+ if ((btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) ||
+ (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_SHUTTING_DOWN)) {
+ return;
+ }
+#if MTK_A2DP_SNK_AAC_DUMP
+ if (outputAacSampleFp) {
+ fclose(outputAacSampleFp);
+ outputAacSampleFp = NULL;
+ LOG_ERROR(LOG_TAG, "%s:close %s", __func__, outputAacFilename);
+ }
+#endif
+ /* Make sure no channels are restarted while shutting down */
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_SHUTTING_DOWN;
+
+ APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##");
+
+ // Stop the timer
+ alarm_free(btif_a2dp_sink_cb.decode_alarm);
+ btif_a2dp_sink_cb.decode_alarm = NULL;
+
+ // Exit the thread
+ fixed_queue_free(btif_a2dp_sink_cb.cmd_msg_queue, NULL);
+ btif_a2dp_sink_cb.cmd_msg_queue = NULL;
+ thread_post(btif_a2dp_sink_cb.worker_thread, btif_a2dp_sink_shutdown_delayed,
+ NULL);
+ thread_free(btif_a2dp_sink_cb.worker_thread);
+ btif_a2dp_sink_cb.worker_thread = NULL;
+}
+
+static void btif_a2dp_sink_shutdown_delayed(UNUSED_ATTR void* context) {
+ fixed_queue_free(btif_a2dp_sink_cb.rx_audio_queue, NULL);
+ btif_a2dp_sink_cb.rx_audio_queue = NULL;
+
+ btif_a2dp_sink_state = BTIF_A2DP_SINK_STATE_OFF;
+}
+
+tA2DP_SAMPLE_RATE btif_a2dp_sink_get_sample_rate(void) {
+ return btif_a2dp_sink_cb.sample_rate;
+}
+
+tA2DP_CHANNEL_COUNT btif_a2dp_sink_get_channel_count(void) {
+ return btif_a2dp_sink_cb.channel_count;
+}
+
+static void btif_a2dp_sink_command_ready(fixed_queue_t* queue,
+ UNUSED_ATTR void* context) {
+ BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+
+ LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+ dump_media_event(p_msg->event));
+
+ switch (p_msg->event) {
+ case BTIF_MEDIA_SINK_DECODER_UPDATE:
+ btif_a2dp_sink_decoder_update_event(
+ (tBTIF_MEDIA_SINK_DECODER_UPDATE*)p_msg);
+ break;
+ case BTIF_MEDIA_SINK_CLEAR_TRACK:
+ btif_a2dp_sink_clear_track_event();
+ break;
+ case BTIF_MEDIA_SINK_SET_FOCUS_STATE: {
+ btif_a2dp_sink_focus_state_t state =
+ ((tBTIF_MEDIA_SINK_FOCUS_UPDATE*)p_msg)->focus_state;
+ btif_a2dp_sink_set_focus_state_event(state);
+ break;
+ }
+ case BTIF_MEDIA_SINK_AUDIO_RX_FLUSH:
+ btif_a2dp_sink_audio_rx_flush_event();
+ break;
+ default:
+ APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
+ break;
+ }
+
+ osi_free(p_msg);
+ LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+}
+
+void btif_a2dp_sink_update_decoder(const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ /* If the function is called for the wrong Media Type or Media Codec Type */
+ uint8_t losc;
+ losc = *p_codec_info;
+ if (losc == A2DP_SBC_INFO_LEN && *(p_codec_info + 2) == A2DP_MEDIA_CT_SBC) {
+ btif_a2dp_sink_cb.codec_type = A2DP_MEDIA_CT_SBC;
+ }
+ else if (losc == A2DP_AAC_CODEC_LEN && *(p_codec_info + 2) == A2DP_MEDIA_CT_AAC) {
+ btif_a2dp_sink_cb.codec_type = A2DP_MEDIA_CT_AAC;
+ }
+ APPL_TRACE_EVENT("codec type:%d", btif_a2dp_sink_cb.codec_type);
+#endif
+ tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf =
+ reinterpret_cast<tBTIF_MEDIA_SINK_DECODER_UPDATE*>(
+ osi_malloc(sizeof(tBTIF_MEDIA_SINK_DECODER_UPDATE)));
+
+ APPL_TRACE_EVENT("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+ p_codec_info[1], p_codec_info[2], p_codec_info[3],
+ p_codec_info[4], p_codec_info[5], p_codec_info[6]);
+
+ memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE);
+ p_buf->hdr.event = BTIF_MEDIA_SINK_DECODER_UPDATE;
+
+ fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_sink_on_idle(void) {
+ if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+ btif_a2dp_sink_audio_handle_stop_decoding();
+ btif_a2dp_sink_clear_track_event_req();
+ APPL_TRACE_DEBUG("Stopped BT track");
+}
+
+void btif_a2dp_sink_on_stopped(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+ if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+ btif_a2dp_sink_audio_handle_stop_decoding();
+}
+
+void btif_a2dp_sink_on_suspended(UNUSED_ATTR tBTA_AV_SUSPEND* p_av_suspend) {
+ if (btif_a2dp_sink_state == BTIF_A2DP_SINK_STATE_OFF) return;
+
+ btif_a2dp_sink_audio_handle_stop_decoding();
+}
+
+static void btif_a2dp_sink_audio_handle_stop_decoding(void) {
+ btif_a2dp_sink_cb.rx_flush = true;
+ btif_a2dp_sink_audio_rx_flush_req();
+
+ alarm_free(btif_a2dp_sink_cb.decode_alarm);
+ btif_a2dp_sink_cb.decode_alarm = NULL;
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackPause(btif_a2dp_sink_cb.audio_track);
+#endif
+}
+
+static void btif_decode_alarm_cb(UNUSED_ATTR void* context) {
+ if (btif_a2dp_sink_cb.worker_thread != NULL) {
+ thread_post(btif_a2dp_sink_cb.worker_thread,
+ btif_a2dp_sink_avk_handle_timer, NULL);
+ }
+}
+
+static void btif_a2dp_sink_clear_track_event(void) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackStop(btif_a2dp_sink_cb.audio_track);
+ BtifAvrcpAudioTrackDelete(btif_a2dp_sink_cb.audio_track);
+#endif
+ btif_a2dp_sink_cb.audio_track = NULL;
+}
+
+static void btif_a2dp_sink_audio_handle_start_decoding(void) {
+ if (btif_a2dp_sink_cb.decode_alarm != NULL)
+ return; // Already started decoding
+
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackStart(btif_a2dp_sink_cb.audio_track);
+#endif
+
+ btif_a2dp_sink_cb.decode_alarm = alarm_new_periodic("btif.a2dp_sink_decode");
+ if (btif_a2dp_sink_cb.decode_alarm == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: unable to allocate decode alarm", __func__);
+ return;
+ }
+ alarm_set(btif_a2dp_sink_cb.decode_alarm, BTIF_SINK_MEDIA_TIME_TICK_MS,
+ btif_decode_alarm_cb, NULL);
+}
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+typedef void (*decoded_data_callback_t)(uint8_t* buf, size_t len);
+
+#define DECODE_BUF_LEN (8 * 2 * 1024)
+
+typedef struct {
+ HANDLE_AACDECODER aac_handle;
+ bool has_aac_handle; // True if aac_handle is valid
+ INT_PCM* decode_buf;
+ decoded_data_callback_t decode_callback;
+} tA2DP_AAC_DECODER_CB;
+static tA2DP_AAC_DECODER_CB a2dp_aac_decoder_cb;
+
+void a2dp_aac_decoder_cleanup(void) {
+ if (a2dp_aac_decoder_cb.has_aac_handle)
+ aacDecoder_Close(a2dp_aac_decoder_cb.aac_handle);
+ osi_free(a2dp_aac_decoder_cb.decode_buf);
+ memset(&a2dp_aac_decoder_cb, 0, sizeof(a2dp_aac_decoder_cb));
+}
+
+bool a2dp_aac_decoder_init(decoded_data_callback_t decode_callback) {
+ a2dp_aac_decoder_cleanup();
+
+ a2dp_aac_decoder_cb.aac_handle =
+ aacDecoder_Open(TT_MP4_LATM_MCP1, 1 /* nrOfLayers */);
+ a2dp_aac_decoder_cb.has_aac_handle = true;
+ a2dp_aac_decoder_cb.decode_buf = (INT_PCM*)osi_malloc(sizeof(a2dp_aac_decoder_cb.decode_buf[0]) * DECODE_BUF_LEN);
+ a2dp_aac_decoder_cb.decode_callback = decode_callback;
+ return true;
+}
+
+bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf) {
+ uint8_t* pBuffer = (uint8_t* )(p_buf->data + p_buf->offset);
+ UINT bufferSize = p_buf->len;
+ UINT bytesValid = p_buf->len;
+ LOG_ERROR(LOG_TAG, "%s: +++into++++: %d", __func__,__LINE__);
+ while (bytesValid > 0) {
+ LOG_ERROR(LOG_TAG, "%s: +++into: %d", __func__,__LINE__);
+ AAC_DECODER_ERROR err = aacDecoder_Fill(a2dp_aac_decoder_cb.aac_handle,
+ &pBuffer, &bufferSize, &bytesValid);
+ if (err != AAC_DEC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: aacDecoder_Fill failed: %x", __func__, err);
+ return false;
+ }
+
+ while (true) {
+ err = aacDecoder_DecodeFrame(a2dp_aac_decoder_cb.aac_handle,
+ a2dp_aac_decoder_cb.decode_buf,
+ DECODE_BUF_LEN, 0 /* flags */);
+ if (err == AAC_DEC_NOT_ENOUGH_BITS) {
+ break;
+ }
+ if (err != AAC_DEC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: aacDecoder_DecodeFrame failed: %x", __func__, err);
+ break;
+ }
+ CStreamInfo* info = aacDecoder_GetStreamInfo(a2dp_aac_decoder_cb.aac_handle);
+ LOG_ERROR(LOG_TAG, "%s: info->sampleRate %d frameSize %d numChannels %d aacSampleRate: %d",
+ __func__, info->sampleRate, info->frameSize, info->numChannels, info->aacSampleRate);
+ if (!info || info->sampleRate <= 0) {
+ LOG_ERROR(LOG_TAG, "%s: Invalid stream info", __func__);
+ break;
+ }
+ size_t frame_len = info->frameSize * info->numChannels *
+ sizeof(a2dp_aac_decoder_cb.decode_buf[0]);
+ a2dp_aac_decoder_cb.decode_callback((uint8_t*)a2dp_aac_decoder_cb.decode_buf, frame_len);
+ }
+ LOG_ERROR(LOG_TAG, "%s: len decode_buf[0]):%d", __func__, sizeof(a2dp_aac_decoder_cb.decode_buf[0]));
+ }
+ return true;
+}
+
+
+void btif_a2dp_sink_on_decode_complete(uint8_t* data, size_t len) {
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackWriteData(
+ btif_a2dp_sink_cb.audio_track, (void*)data, len);
+#else
+ NULL;
+#endif
+
+}
+#endif
+static void btif_a2dp_sink_handle_inc_media(tBT_SBC_HDR* p_msg) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ bool a2dp_aac_decoder_decode_packet(BT_HDR* p_buf);
+ uint8_t codec_type = btif_a2dp_sink_cb.codec_type;
+ if (A2DP_MEDIA_CT_SBC == codec_type) {
+#endif
+ uint8_t* sbc_start_frame = ((uint8_t*)(p_msg + 1) + p_msg->offset + 1);
+ int count;
+ uint32_t pcmBytes, availPcmBytes;
+ int16_t* pcmDataPointer =
+ btif_a2dp_sink_pcm_data; /* Will be overwritten on next packet receipt */
+ OI_STATUS status;
+ int num_sbc_frames = p_msg->num_frames_to_be_processed;
+ uint32_t sbc_frame_len = p_msg->len - 1;
+ availPcmBytes = sizeof(btif_a2dp_sink_pcm_data);
+
+ if ((btif_av_get_peer_sep() == AVDT_TSEP_SNK) ||
+ (btif_a2dp_sink_cb.rx_flush)) {
+ APPL_TRACE_DEBUG("State Changed happened in this tick");
+ return;
+ }
+
+ APPL_TRACE_DEBUG("%s Number of SBC frames %d, frame_len %d", __func__,
+ num_sbc_frames, sbc_frame_len);
+
+ for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count++) {
+ pcmBytes = availPcmBytes;
+ status = OI_CODEC_SBC_DecodeFrame(
+ &btif_a2dp_sink_context, (const OI_BYTE**)&sbc_start_frame,
+ (uint32_t*)&sbc_frame_len, (int16_t*)pcmDataPointer,
+ (uint32_t*)&pcmBytes);
+ if (!OI_SUCCESS(status)) {
+ APPL_TRACE_ERROR("%s: Decoding failure: %d", __func__, status);
+ break;
+ }
+ availPcmBytes -= pcmBytes;
+ pcmDataPointer += pcmBytes / 2;
+ p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
+ p_msg->len = sbc_frame_len + 1;
+ }
+
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackWriteData(
+ btif_a2dp_sink_cb.audio_track, (void*)btif_a2dp_sink_pcm_data,
+ (sizeof(btif_a2dp_sink_pcm_data) - availPcmBytes));
+#endif
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ }
+ else if(A2DP_MEDIA_CT_AAC == codec_type) {
+ LOG_ERROR(LOG_TAG, "%s: start to decoding AAC frame", __func__);
+ BT_HDR* p_buf = (BT_HDR*)p_msg;
+ if (p_buf == NULL) {
+ APPL_TRACE_ERROR("[SNK_AAC] dequeue p_buf is empty");
+ return;
+ }
+
+#if MTK_A2DP_SNK_AAC_DUMP
+ if(NULL == outputAacSampleFp) {
+ outputAacSampleFp = fopen(outputAacFilename,"ab");
+ LOG_ERROR(LOG_TAG, "%s:open %s", __func__, outputAacFilename);
+ }
+
+ if (outputAacSampleFp) {
+ fwrite((uint8_t* )(p_buf->data + p_buf->offset), 1, (size_t)p_buf->len, outputAacSampleFp);
+ }
+#endif
+ a2dp_aac_decoder_decode_packet(p_buf);
+ }
+#endif
+}
+
+static void btif_a2dp_sink_avk_handle_timer(UNUSED_ATTR void* context) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#else
+ tBT_SBC_HDR* p_msg;
+ int num_sbc_frames;
+ int num_frames_to_process;
+#endif
+
+ if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
+ APPL_TRACE_DEBUG("%s: empty queue", __func__);
+ return;
+ }
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (btif_a2dp_sink_cb.codec_type == A2DP_MEDIA_CT_SBC) {
+ tBT_SBC_HDR *p_msg;
+ int num_sbc_frames;
+ int num_frames_to_process;
+#endif
+
+ /* Don't do anything in case of focus not granted */
+ if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
+ APPL_TRACE_DEBUG("%s: skipping frames since focus is not present",
+ __func__);
+ return;
+ }
+ /* Play only in BTIF_A2DP_SINK_FOCUS_GRANTED case */
+ if (btif_a2dp_sink_cb.rx_flush) {
+ fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+ return;
+ }
+
+ num_frames_to_process = btif_a2dp_sink_cb.frames_to_process;
+ APPL_TRACE_DEBUG(" Process Frames + ");
+
+ do {
+ p_msg = (tBT_SBC_HDR*)fixed_queue_try_peek_first(
+ btif_a2dp_sink_cb.rx_audio_queue);
+ if (p_msg == NULL) return;
+ /* Number of frames in queue packets */
+ num_sbc_frames = p_msg->num_frames_to_be_processed;
+ APPL_TRACE_DEBUG("Frames left in topmost packet %d", num_sbc_frames);
+ APPL_TRACE_DEBUG("Remaining frames to process in tick %d",
+ num_frames_to_process);
+ APPL_TRACE_DEBUG("Number of packets in queue %d",
+ fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue));
+
+ if (num_sbc_frames > num_frames_to_process) {
+ /* Queue packet has more frames */
+ p_msg->num_frames_to_be_processed = num_frames_to_process;
+ btif_a2dp_sink_handle_inc_media(p_msg);
+ p_msg->num_frames_to_be_processed =
+ num_sbc_frames - num_frames_to_process;
+ num_frames_to_process = 0;
+ break;
+ }
+ /* Queue packet has less frames */
+ btif_a2dp_sink_handle_inc_media(p_msg);
+ p_msg =
+ (tBT_SBC_HDR*)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+ if (p_msg == NULL) {
+ APPL_TRACE_ERROR("Insufficient data in queue");
+ break;
+ }
+ num_frames_to_process =
+ num_frames_to_process - p_msg->num_frames_to_be_processed;
+ osi_free(p_msg);
+ } while (num_frames_to_process > 0);
+
+ APPL_TRACE_DEBUG("Process Frames - ");
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ }
+ else if (btif_a2dp_sink_cb.codec_type == A2DP_MEDIA_CT_AAC) {
+ BT_HDR *p_msg;
+ /* Don't Do anything in case of Not granted */
+ if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
+ APPL_TRACE_DEBUG("%s $d skipping frames since focus is not present#.", __LINE__, __func__);
+ return;
+ }
+ /* play only in BTIF_MEDIA_FOCUS_GRANTED case */
+ if (btif_a2dp_sink_cb.rx_flush == TRUE) {
+ APPL_TRACE_DEBUG("btif_a2dp_sink_cb.rx_flush:%d", btif_a2dp_sink_cb.rx_flush);
+ fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+ return;
+ }
+ while (TRUE) {
+ p_msg = (BT_HDR *)fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue);
+ if (p_msg == NULL) {
+ APPL_TRACE_ERROR("[SNK_AAC] dequeue AAC data fail");
+ return;
+ }
+ btif_a2dp_sink_handle_inc_media((tBT_SBC_HDR*)p_msg);
+ osi_free(p_msg);
+ }
+ }
+#endif
+}
+
+/* when true media task discards any rx frames */
+void btif_a2dp_sink_set_rx_flush(bool enable) {
+ APPL_TRACE_EVENT("## DROP RX %d ##", enable);
+ btif_a2dp_sink_cb.rx_flush = enable;
+}
+
+static void btif_a2dp_sink_audio_rx_flush_event(void) {
+ /* Flush all received SBC buffers (encoded) */
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+}
+
+static void btif_a2dp_sink_decoder_update_event(
+ tBTIF_MEDIA_SINK_DECODER_UPDATE* p_buf) {
+ OI_STATUS status;
+
+ APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__,
+ p_buf->codec_info[1], p_buf->codec_info[2],
+ p_buf->codec_info[3], p_buf->codec_info[4],
+ p_buf->codec_info[5], p_buf->codec_info[6]);
+
+ int sample_rate = A2DP_GetTrackSampleRate(p_buf->codec_info);
+ if (sample_rate == -1) {
+ APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+ return;
+ }
+ int channel_count = A2DP_GetTrackChannelCount(p_buf->codec_info);
+ if (channel_count == -1) {
+ APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+ return;
+ }
+ int channel_type = A2DP_GetSinkTrackChannelType(p_buf->codec_info);
+ if (channel_type == -1) {
+ APPL_TRACE_ERROR("%s: cannot get the Sink channel type", __func__);
+ return;
+ }
+ btif_a2dp_sink_cb.sample_rate = sample_rate;
+ btif_a2dp_sink_cb.channel_count = channel_count;
+
+ btif_a2dp_sink_cb.rx_flush = false;
+ APPL_TRACE_DEBUG("%s: Reset to Sink role", __func__);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_buf->codec_info);
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ if (A2DP_MEDIA_CT_AAC == codec_type)
+ {
+ if (TRUE != a2dp_aac_decoder_init(btif_a2dp_sink_on_decode_complete)) {
+ APPL_TRACE_ERROR("[SNK_AAC] %s: A2dpSink: Failed to initialize decoder", __func__);
+ return;
+ }
+ else {
+ APPL_TRACE_DEBUG("[SNK_AAC] %s: a2dp_aac_decoder_init OK!", __func__);
+ }
+ APPL_TRACE_DEBUG("%s: A2dpSink: AAC create track", __func__);
+ btif_a2dp_sink_cb.audio_track =
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
+#else
+ NULL;
+#endif
+ if (btif_a2dp_sink_cb.audio_track == NULL) {
+ APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
+ return;
+ }
+ btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
+ BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
+ APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
+ btif_a2dp_sink_cb.frames_to_process);
+ if (btif_a2dp_sink_cb.frames_to_process == 0) {
+ APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
+ __func__);
+ }
+ return;
+ }
+#endif
+ status = OI_CODEC_SBC_DecoderReset(
+ &btif_a2dp_sink_context, btif_a2dp_sink_context_data,
+ sizeof(btif_a2dp_sink_context_data), 2, 2, false);
+ if (!OI_SUCCESS(status)) {
+ APPL_TRACE_ERROR("%s: OI_CODEC_SBC_DecoderReset failed with error code %d",
+ __func__, status);
+ }
+
+ APPL_TRACE_DEBUG("%s: A2dpSink: SBC create track", __func__);
+ btif_a2dp_sink_cb.audio_track =
+#ifndef OS_GENERIC
+ BtifAvrcpAudioTrackCreate(sample_rate, channel_type);
+#else
+ NULL;
+#endif
+ if (btif_a2dp_sink_cb.audio_track == NULL) {
+ APPL_TRACE_ERROR("%s: A2dpSink: Track creation failed", __func__);
+ return;
+ }
+
+ btif_a2dp_sink_cb.frames_to_process = A2DP_GetSinkFramesCountToProcess(
+ BTIF_SINK_MEDIA_TIME_TICK_MS, p_buf->codec_info);
+ APPL_TRACE_DEBUG("%s: Frames to be processed in 20 ms %d", __func__,
+ btif_a2dp_sink_cb.frames_to_process);
+ if (btif_a2dp_sink_cb.frames_to_process == 0) {
+ APPL_TRACE_ERROR("%s: Cannot compute the number of frames to process",
+ __func__);
+ }
+}
+
+uint8_t btif_a2dp_sink_enqueue_buf(BT_HDR* p_pkt) {
+ if (btif_a2dp_sink_cb.rx_flush) /* Flush enabled, do not enqueue */
+ return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+
+ if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
+ MAX_INPUT_A2DP_FRAME_QUEUE_SZ) {
+ uint8_t ret = fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+ osi_free(fixed_queue_try_dequeue(btif_a2dp_sink_cb.rx_audio_queue));
+ return ret;
+ }
+
+ BTIF_TRACE_VERBOSE("%s +", __func__);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (A2DP_MEDIA_CT_AAC == btif_a2dp_sink_cb.codec_type) {
+ BTIF_TRACE_VERBOSE("%s btif_a2dp_sink_enqueue_buf AAC******************", __func__);
+ BT_HDR *p_msg = (BT_HDR*)(osi_malloc(sizeof(BT_HDR) + p_pkt->len));
+ memcpy((BT_HDR*)p_msg, p_pkt, sizeof(p_pkt));
+ ((BT_HDR*)p_msg)->offset = 0;
+ memcpy(((BT_HDR*)p_msg)->data, p_pkt->data + p_pkt->offset, p_pkt->len);
+ fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
+
+ if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
+ MAX_A2DP_DELAYED_START_FRAME_COUNT) {
+ BTIF_TRACE_DEBUG("%s: Initiate decoding", __func__);
+ btif_a2dp_sink_audio_handle_start_decoding();
+ }
+
+ return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+ }
+#endif
+ /* Allocate and queue this buffer */
+ tBT_SBC_HDR* p_msg = reinterpret_cast<tBT_SBC_HDR*>(
+ osi_malloc(sizeof(tBT_SBC_HDR) + p_pkt->offset + p_pkt->len));
+ memcpy((uint8_t*)(p_msg + 1), (uint8_t*)(p_pkt + 1) + p_pkt->offset,
+ p_pkt->len);
+ p_msg->num_frames_to_be_processed =
+ (*((uint8_t*)(p_pkt + 1) + p_pkt->offset)) & 0x0f;
+ p_msg->len = p_pkt->len;
+ p_msg->offset = 0;
+ p_msg->layer_specific = p_pkt->layer_specific;
+ BTIF_TRACE_VERBOSE("%s: frames to process %d, len %d", __func__,
+ p_msg->num_frames_to_be_processed, p_msg->len);
+ fixed_queue_enqueue(btif_a2dp_sink_cb.rx_audio_queue, p_msg);
+ if (fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue) ==
+ MAX_A2DP_DELAYED_START_FRAME_COUNT) {
+ BTIF_TRACE_DEBUG("%s: Initiate decoding", __func__);
+ btif_a2dp_sink_audio_handle_start_decoding();
+ }
+
+ return fixed_queue_length(btif_a2dp_sink_cb.rx_audio_queue);
+}
+
+void btif_a2dp_sink_audio_rx_flush_req(void) {
+ if (fixed_queue_is_empty(btif_a2dp_sink_cb.rx_audio_queue)) {
+ /* Queue is already empty */
+ return;
+ }
+
+ BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+ p_buf->event = BTIF_MEDIA_SINK_AUDIO_RX_FLUSH;
+ fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+void btif_a2dp_sink_debug_dump(UNUSED_ATTR int fd) {
+ // Nothing to do
+}
+
+void btif_a2dp_sink_set_focus_state_req(btif_a2dp_sink_focus_state_t state) {
+ tBTIF_MEDIA_SINK_FOCUS_UPDATE* p_buf =
+ reinterpret_cast<tBTIF_MEDIA_SINK_FOCUS_UPDATE*>(
+ osi_malloc(sizeof(tBTIF_MEDIA_SINK_FOCUS_UPDATE)));
+
+ APPL_TRACE_EVENT("%s", __func__);
+
+ p_buf->focus_state = state;
+ p_buf->hdr.event = BTIF_MEDIA_SINK_SET_FOCUS_STATE;
+ fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_sink_set_focus_state_event(
+ btif_a2dp_sink_focus_state_t state) {
+ if (!btif_av_is_connected()) return;
+ APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
+ btif_a2dp_sink_cb.rx_focus_state = state;
+ if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
+ fixed_queue_flush(btif_a2dp_sink_cb.rx_audio_queue, osi_free);
+ btif_a2dp_sink_cb.rx_flush = true;
+ } else if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_GRANTED) {
+ btif_a2dp_sink_cb.rx_flush = false;
+ }
+}
+
+void btif_a2dp_sink_set_audio_track_gain(float gain) {
+ APPL_TRACE_DEBUG("%s set gain to %f", __func__, gain);
+#ifndef OS_GENERIC
+ BtifAvrcpSetAudioTrackGain(btif_a2dp_sink_cb.audio_track, gain);
+#endif
+}
+
+static void btif_a2dp_sink_clear_track_event_req(void) {
+ BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR)));
+
+ p_buf->event = BTIF_MEDIA_SINK_CLEAR_TRACK;
+ fixed_queue_enqueue(btif_a2dp_sink_cb.cmd_msg_queue, p_buf);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_a2dp_source.cc b/mtkbt/code/bt/btif/src/btif_a2dp_source.cc
new file mode 100755
index 0000000..5712543
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_a2dp_source.cc
@@ -0,0 +1,1126 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_a2dp_source"
+
+#include <base/logging.h>
+#include <limits.h>
+#include <string.h>
+#include <algorithm>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bta_av_ci.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_source.h"
+#include "btif_av.h"
+#include "btif_av_co.h"
+#include "btif_util.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "osi/include/time.h"
+#include "uipc.h"
+
+using system_bt_osi::BluetoothMetricsLogger;
+using system_bt_osi::A2dpSessionMetrics;
+
+/**
+ * The typical runlevel of the tx queue size is ~1 buffer
+ * but due to link flow control or thread preemption in lower
+ * layers we might need to temporarily buffer up data.
+ */
+#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (MAX_PCM_FRAME_NUM_PER_TICK * 2)
+
+enum {
+ BTIF_A2DP_SOURCE_STATE_OFF,
+ BTIF_A2DP_SOURCE_STATE_STARTING_UP,
+ BTIF_A2DP_SOURCE_STATE_RUNNING,
+ BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN
+};
+
+/* BTIF Media Source event definition */
+enum {
+ BTIF_MEDIA_AUDIO_TX_START = 1,
+ BTIF_MEDIA_AUDIO_TX_STOP,
+ BTIF_MEDIA_AUDIO_TX_FLUSH,
+ BTIF_MEDIA_SOURCE_ENCODER_INIT,
+ BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE,
+ BTIF_MEDIA_AUDIO_FEEDING_UPDATE
+};
+
+/* tBTIF_A2DP_SOURCE_ENCODER_INIT msg structure */
+typedef struct {
+ BT_HDR hdr;
+ tA2DP_ENCODER_INIT_PEER_PARAMS peer_params;
+} tBTIF_A2DP_SOURCE_ENCODER_INIT;
+
+/* tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE msg structure */
+typedef struct {
+ BT_HDR hdr;
+ btav_a2dp_codec_config_t user_config;
+} tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE;
+
+/* tBTIF_A2DP_AUDIO_FEEDING_UPDATE msg structure */
+typedef struct {
+ BT_HDR hdr;
+ btav_a2dp_codec_config_t feeding_params;
+} tBTIF_A2DP_AUDIO_FEEDING_UPDATE;
+
+typedef struct {
+ // Counter for total updates
+ size_t total_updates;
+
+ // Last update timestamp (in us)
+ uint64_t last_update_us;
+
+ // Counter for overdue scheduling
+ size_t overdue_scheduling_count;
+
+ // Accumulated overdue scheduling deviations (in us)
+ uint64_t total_overdue_scheduling_delta_us;
+
+ // Max. overdue scheduling delta time (in us)
+ uint64_t max_overdue_scheduling_delta_us;
+
+ // Counter for premature scheduling
+ size_t premature_scheduling_count;
+
+ // Accumulated premature scheduling deviations (in us)
+ uint64_t total_premature_scheduling_delta_us;
+
+ // Max. premature scheduling delta time (in us)
+ uint64_t max_premature_scheduling_delta_us;
+
+ // Counter for exact scheduling
+ size_t exact_scheduling_count;
+
+ // Accumulated and counted scheduling time (in us)
+ uint64_t total_scheduling_time_us;
+} scheduling_stats_t;
+
+typedef struct {
+ uint64_t session_start_us;
+ uint64_t session_end_us;
+
+ scheduling_stats_t tx_queue_enqueue_stats;
+ scheduling_stats_t tx_queue_dequeue_stats;
+
+ size_t tx_queue_total_frames;
+ size_t tx_queue_max_frames_per_packet;
+
+ uint64_t tx_queue_total_queueing_time_us;
+ uint64_t tx_queue_max_queueing_time_us;
+
+ size_t tx_queue_total_readbuf_calls;
+ uint64_t tx_queue_last_readbuf_us;
+
+ size_t tx_queue_total_flushed_messages;
+ uint64_t tx_queue_last_flushed_us;
+
+ size_t tx_queue_total_dropped_messages;
+ size_t tx_queue_max_dropped_messages;
+ size_t tx_queue_dropouts;
+ uint64_t tx_queue_last_dropouts_us;
+
+ size_t media_read_total_underflow_bytes;
+ size_t media_read_total_underflow_count;
+ uint64_t media_read_last_underflow_us;
+} btif_media_stats_t;
+
+typedef struct {
+ thread_t* worker_thread;
+ fixed_queue_t* cmd_msg_queue;
+ fixed_queue_t* tx_audio_queue;
+ bool tx_flush; /* Discards any outgoing data when true */
+ alarm_t* media_alarm;
+ const tA2DP_ENCODER_INTERFACE* encoder_interface;
+ period_ms_t encoder_interval_ms; /* Local copy of the encoder interval */
+ btif_media_stats_t stats;
+ btif_media_stats_t accumulated_stats;
+} tBTIF_A2DP_SOURCE_CB;
+
+static tBTIF_A2DP_SOURCE_CB btif_a2dp_source_cb;
+static int btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+
+static void btif_a2dp_source_command_ready(fixed_queue_t* queue, void* context);
+static void btif_a2dp_source_startup_delayed(void* context);
+static void btif_a2dp_source_shutdown_delayed(void* context);
+static void btif_a2dp_source_audio_tx_start_event(void);
+static void btif_a2dp_source_audio_tx_stop_event(void);
+static void btif_a2dp_source_audio_tx_flush_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_user_config_update_event(BT_HDR* p_msg);
+static void btif_a2dp_source_audio_feeding_update_event(BT_HDR* p_msg);
+static void btif_a2dp_source_encoder_init(void);
+static void btif_a2dp_source_encoder_init_req(
+ tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg);
+static bool btif_a2dp_source_audio_tx_flush_req(void);
+static void btif_a2dp_source_alarm_cb(void* context);
+static void btif_a2dp_source_audio_handle_timer(void* context);
+static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len);
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n);
+static void log_tstamps_us(const char* comment, uint64_t timestamp_us);
+static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_us,
+ uint64_t expected_delta);
+static void btm_read_rssi_cb(void* data);
+
+UNUSED_ATTR static const char* dump_media_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_START)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_STOP)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_TX_FLUSH)
+ CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_INIT)
+ CASE_RETURN_STR(BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE)
+ CASE_RETURN_STR(BTIF_MEDIA_AUDIO_FEEDING_UPDATE)
+ default:
+ break;
+ }
+ return "UNKNOWN A2DP SOURCE EVENT";
+}
+
+void btif_a2dp_source_accumulate_scheduling_stats(scheduling_stats_t* src,
+ scheduling_stats_t* dst) {
+ dst->total_updates += src->total_updates;
+ dst->last_update_us = src->last_update_us;
+ dst->overdue_scheduling_count += src->overdue_scheduling_count;
+ dst->total_overdue_scheduling_delta_us +=
+ src->total_overdue_scheduling_delta_us;
+ dst->max_overdue_scheduling_delta_us =
+ std::max(dst->max_overdue_scheduling_delta_us,
+ src->max_overdue_scheduling_delta_us);
+ dst->premature_scheduling_count += src->premature_scheduling_count;
+ dst->total_premature_scheduling_delta_us +=
+ src->total_premature_scheduling_delta_us;
+ dst->max_premature_scheduling_delta_us =
+ std::max(dst->max_premature_scheduling_delta_us,
+ src->max_premature_scheduling_delta_us);
+ dst->exact_scheduling_count += src->exact_scheduling_count;
+ dst->total_scheduling_time_us += src->total_scheduling_time_us;
+}
+
+void btif_a2dp_source_accumulate_stats(btif_media_stats_t* src,
+ btif_media_stats_t* dst) {
+ dst->tx_queue_total_frames += src->tx_queue_total_frames;
+ dst->tx_queue_max_frames_per_packet = std::max(
+ dst->tx_queue_max_frames_per_packet, src->tx_queue_max_frames_per_packet);
+ dst->tx_queue_total_queueing_time_us += src->tx_queue_total_queueing_time_us;
+ dst->tx_queue_max_queueing_time_us = std::max(
+ dst->tx_queue_max_queueing_time_us, src->tx_queue_max_queueing_time_us);
+ dst->tx_queue_total_readbuf_calls += src->tx_queue_total_readbuf_calls;
+ dst->tx_queue_last_readbuf_us = src->tx_queue_last_readbuf_us;
+ dst->tx_queue_total_flushed_messages += src->tx_queue_total_flushed_messages;
+ dst->tx_queue_last_flushed_us = src->tx_queue_last_flushed_us;
+ dst->tx_queue_total_dropped_messages += src->tx_queue_total_dropped_messages;
+ dst->tx_queue_max_dropped_messages = std::max(
+ dst->tx_queue_max_dropped_messages, src->tx_queue_max_dropped_messages);
+ dst->tx_queue_dropouts += src->tx_queue_dropouts;
+ dst->tx_queue_last_dropouts_us = src->tx_queue_last_dropouts_us;
+ dst->media_read_total_underflow_bytes +=
+ src->media_read_total_underflow_bytes;
+ dst->media_read_total_underflow_count +=
+ src->media_read_total_underflow_count;
+ dst->media_read_last_underflow_us = src->media_read_last_underflow_us;
+ btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_enqueue_stats,
+ &dst->tx_queue_enqueue_stats);
+ btif_a2dp_source_accumulate_scheduling_stats(&src->tx_queue_dequeue_stats,
+ &dst->tx_queue_dequeue_stats);
+ memset(src, 0, sizeof(btif_media_stats_t));
+}
+
+bool btif_a2dp_source_startup(void) {
+ if (btif_a2dp_source_state != BTIF_A2DP_SOURCE_STATE_OFF) {
+ APPL_TRACE_ERROR("%s: A2DP Source media task already running", __func__);
+ return false;
+ }
+
+ memset(&btif_a2dp_source_cb, 0, sizeof(btif_a2dp_source_cb));
+ btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_STARTING_UP;
+
+ APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
+
+ /* Start A2DP Source media task */
+ btif_a2dp_source_cb.worker_thread =
+ thread_new("btif_a2dp_source_worker_thread");
+ if (btif_a2dp_source_cb.worker_thread == NULL) {
+ APPL_TRACE_ERROR("%s: unable to start up media thread", __func__);
+ btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+ return false;
+ }
+
+ btif_a2dp_source_cb.tx_audio_queue = fixed_queue_new(SIZE_MAX);
+
+ btif_a2dp_source_cb.cmd_msg_queue = fixed_queue_new(SIZE_MAX);
+ fixed_queue_register_dequeue(
+ btif_a2dp_source_cb.cmd_msg_queue,
+ thread_get_reactor(btif_a2dp_source_cb.worker_thread),
+ btif_a2dp_source_command_ready, NULL);
+
+ APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##");
+
+ /* Schedule the rest of the startup operations */
+ thread_post(btif_a2dp_source_cb.worker_thread,
+ btif_a2dp_source_startup_delayed, NULL);
+
+ return true;
+}
+
+static void btif_a2dp_source_startup_delayed(UNUSED_ATTR void* context) {
+ raise_priority_a2dp(TASK_HIGH_MEDIA);
+ btif_a2dp_control_init();
+ btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_RUNNING;
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+}
+
+void btif_a2dp_source_shutdown(void) {
+ if ((btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) ||
+ (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN)) {
+ return;
+ }
+
+ /* Make sure no channels are restarted while shutting down */
+ btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN;
+
+ APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##");
+
+ /** M: Bug fix for avoid NE/ANR when media task shutting down@{ */
+ // Stop the timer
+ if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm))
+ {
+ alarm_free(btif_a2dp_source_cb.media_alarm);
+ btif_a2dp_source_cb.media_alarm = NULL;
+ }
+ btif_a2dp_source_shutdown_delayed(NULL);
+ // Exit the thread
+ fixed_queue_free(btif_a2dp_source_cb.cmd_msg_queue, NULL);
+ btif_a2dp_source_cb.cmd_msg_queue = NULL;
+ /** @} */
+ thread_free(btif_a2dp_source_cb.worker_thread);
+ btif_a2dp_source_cb.worker_thread = NULL;
+}
+
+static void btif_a2dp_source_shutdown_delayed(UNUSED_ATTR void* context) {
+ btif_a2dp_control_cleanup();
+ fixed_queue_free(btif_a2dp_source_cb.tx_audio_queue, NULL);
+ btif_a2dp_source_cb.tx_audio_queue = NULL;
+
+ /** M: Bug fix for avoid NE that after alarm free, start media timer again but not alarm free@{ */
+ if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+ APPL_TRACE_DEBUG(" free media_alarm ");
+ alarm_free(btif_a2dp_source_cb.media_alarm);
+ btif_a2dp_source_cb.media_alarm = NULL;
+ }
+ /** @} */
+
+ btif_a2dp_source_state = BTIF_A2DP_SOURCE_STATE_OFF;
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+}
+
+bool btif_a2dp_source_media_task_is_running(void) {
+ return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_RUNNING);
+}
+
+bool btif_a2dp_source_media_task_is_shutting_down(void) {
+ return (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_SHUTTING_DOWN);
+}
+
+bool btif_a2dp_source_is_streaming(void) {
+ return alarm_is_scheduled(btif_a2dp_source_cb.media_alarm);
+}
+
+static void btif_a2dp_source_command_ready(fixed_queue_t* queue,
+ UNUSED_ATTR void* context) {
+ BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+
+ LOG_VERBOSE(LOG_TAG, "%s: event %d %s", __func__, p_msg->event,
+ dump_media_event(p_msg->event));
+
+ switch (p_msg->event) {
+ case BTIF_MEDIA_AUDIO_TX_START:
+ btif_a2dp_source_audio_tx_start_event();
+ break;
+ case BTIF_MEDIA_AUDIO_TX_STOP:
+ btif_a2dp_source_audio_tx_stop_event();
+ break;
+ case BTIF_MEDIA_AUDIO_TX_FLUSH:
+ btif_a2dp_source_audio_tx_flush_event(p_msg);
+ break;
+ case BTIF_MEDIA_SOURCE_ENCODER_INIT:
+ btif_a2dp_source_encoder_init_event(p_msg);
+ break;
+ case BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE:
+ btif_a2dp_source_encoder_user_config_update_event(p_msg);
+ break;
+ case BTIF_MEDIA_AUDIO_FEEDING_UPDATE:
+ btif_a2dp_source_audio_feeding_update_event(p_msg);
+ break;
+ default:
+ APPL_TRACE_ERROR("ERROR in %s unknown event %d", __func__, p_msg->event);
+ break;
+ }
+
+ osi_free(p_msg);
+ LOG_VERBOSE(LOG_TAG, "%s: %s DONE", __func__, dump_media_event(p_msg->event));
+}
+
+void btif_a2dp_source_setup_codec(void) {
+ APPL_TRACE_EVENT("## A2DP SOURCE SETUP CODEC ##");
+
+ mutex_global_lock();
+
+ /* Init the encoding task */
+ btif_a2dp_source_encoder_init();
+
+ mutex_global_unlock();
+}
+
+void btif_a2dp_source_start_audio_req(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTIF_MEDIA_AUDIO_TX_START;
+ /** M: Bug fix for avoid NE that after msg queue free@{ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+ /** @} */
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+ memset(&btif_a2dp_source_cb.stats, 0, sizeof(btif_media_stats_t));
+ // Assign session_start_us to 1 when time_get_os_boottime_us() is 0 to
+ // indicate btif_a2dp_source_start_audio_req() has been called
+ btif_a2dp_source_cb.stats.session_start_us = time_get_os_boottime_us();
+ if (btif_a2dp_source_cb.stats.session_start_us == 0) {
+ btif_a2dp_source_cb.stats.session_start_us = 1;
+ }
+ btif_a2dp_source_cb.stats.session_end_us = 0;
+}
+
+void btif_a2dp_source_stop_audio_req(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTIF_MEDIA_AUDIO_TX_STOP;
+
+ /*
+ * Explicitly check whether btif_a2dp_source_cb.cmd_msg_queue is not NULL
+ * to avoid a race condition during shutdown of the Bluetooth stack.
+ * This race condition is triggered when A2DP audio is streaming on
+ * shutdown:
+ * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_stop_audio_req()"
+ * is called to stop the particular audio stream, and this happens right
+ * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
+ * processing during the shutdown of the Bluetooth stack.
+ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL) {
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+ }
+ btif_a2dp_source_cb.stats.session_end_us = time_get_os_boottime_us();
+ btif_a2dp_source_update_metrics();
+ btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
+ &btif_a2dp_source_cb.accumulated_stats);
+}
+
+static void btif_a2dp_source_encoder_init(void) {
+ tBTIF_A2DP_SOURCE_ENCODER_INIT msg;
+
+ // Check to make sure the platform has 8 bits/byte since
+ // we're using that in frame size calculations now.
+ CHECK(CHAR_BIT == 8);
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ bta_av_co_get_peer_params(&msg.peer_params);
+ btif_a2dp_source_encoder_init_req(&msg);
+}
+
+static void btif_a2dp_source_encoder_init_req(
+ tBTIF_A2DP_SOURCE_ENCODER_INIT* p_msg) {
+ tBTIF_A2DP_SOURCE_ENCODER_INIT* p_buf =
+ (tBTIF_A2DP_SOURCE_ENCODER_INIT*)osi_malloc(
+ sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
+
+ memcpy(p_buf, p_msg, sizeof(tBTIF_A2DP_SOURCE_ENCODER_INIT));
+ p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_INIT;
+ /** M: Bug fix for avoid NE that after msg queue free@{ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+ /** @} */
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_encoder_init_event(BT_HDR* p_msg) {
+ tBTIF_A2DP_SOURCE_ENCODER_INIT* p_encoder_init =
+ (tBTIF_A2DP_SOURCE_ENCODER_INIT*)p_msg;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ btif_a2dp_source_cb.encoder_interface = bta_av_co_get_encoder_interface();
+ if (btif_a2dp_source_cb.encoder_interface == NULL) {
+ APPL_TRACE_ERROR("%s: Cannot stream audio: no source encoder interface",
+ __func__);
+ return;
+ }
+
+ A2dpCodecConfig* a2dp_codec_config = bta_av_get_a2dp_current_codec();
+ if (a2dp_codec_config == nullptr) {
+ APPL_TRACE_ERROR("%s: Cannot stream audio: current codec is not set",
+ __func__);
+ return;
+ }
+
+ btif_a2dp_source_cb.encoder_interface->encoder_init(
+ &p_encoder_init->peer_params, a2dp_codec_config,
+ btif_a2dp_source_read_callback, btif_a2dp_source_enqueue_callback);
+
+ // Save a local copy of the encoder_interval_ms
+ btif_a2dp_source_cb.encoder_interval_ms =
+ btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms();
+}
+
+void btif_a2dp_source_encoder_user_config_update_req(
+ const btav_a2dp_codec_config_t& codec_user_config) {
+ tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE* p_buf =
+ (tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE*)osi_malloc(
+ sizeof(tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE));
+
+ p_buf->user_config = codec_user_config;
+ p_buf->hdr.event = BTIF_MEDIA_SOURCE_ENCODER_USER_CONFIG_UPDATE;
+ /** M: Bug fix for avoid NE that after msg queue free@{ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+ /** @} */
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_encoder_user_config_update_event(BT_HDR* p_msg) {
+ tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE* p_user_config =
+ (tBTIF_A2DP_SOURCE_ENCODER_USER_CONFIG_UPDATE*)p_msg;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ if (!bta_av_co_set_codec_user_config(p_user_config->user_config)) {
+ APPL_TRACE_ERROR("%s: cannot update codec user configuration", __func__);
+ }
+}
+
+void btif_a2dp_source_feeding_update_req(
+ const btav_a2dp_codec_config_t& codec_audio_config) {
+ tBTIF_A2DP_AUDIO_FEEDING_UPDATE* p_buf =
+ (tBTIF_A2DP_AUDIO_FEEDING_UPDATE*)osi_malloc(
+ sizeof(tBTIF_A2DP_AUDIO_FEEDING_UPDATE));
+
+ p_buf->feeding_params = codec_audio_config;
+ p_buf->hdr.event = BTIF_MEDIA_AUDIO_FEEDING_UPDATE;
+ /** M: Bug fix for avoid NE that after msg queue free@{ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+ /** @} */
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+}
+
+static void btif_a2dp_source_audio_feeding_update_event(BT_HDR* p_msg) {
+ tBTIF_A2DP_AUDIO_FEEDING_UPDATE* p_feeding =
+ (tBTIF_A2DP_AUDIO_FEEDING_UPDATE*)p_msg;
+
+ APPL_TRACE_DEBUG("%s", __func__);
+ if (!bta_av_co_set_codec_audio_config(p_feeding->feeding_params)) {
+ APPL_TRACE_ERROR("%s: cannot update codec audio feeding parameters",
+ __func__);
+ }
+}
+
+void btif_a2dp_source_on_idle(void) {
+ if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+ /* Make sure media task is stopped */
+ btif_a2dp_source_stop_audio_req();
+}
+
+void btif_a2dp_source_on_stopped(tBTA_AV_SUSPEND* p_av_suspend) {
+ APPL_TRACE_EVENT("## ON A2DP SOURCE STOPPED ##");
+
+ if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+ /* allow using this api for other than suspend */
+ if (p_av_suspend != NULL) {
+ if (p_av_suspend->status != BTA_AV_SUCCESS) {
+ APPL_TRACE_EVENT("AV STOP FAILED (%d)", p_av_suspend->status);
+ if (p_av_suspend->initiator) {
+ APPL_TRACE_WARNING("%s: A2DP stop request failed: status = %d",
+ __func__, p_av_suspend->status);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+ return;
+ }
+ }
+
+ /* ensure tx frames are immediately suspended */
+ btif_a2dp_source_cb.tx_flush = true;
+
+ /* request to stop media task */
+ btif_a2dp_source_audio_tx_flush_req();
+ btif_a2dp_source_stop_audio_req();
+
+ /* once stream is fully stopped we will ack back */
+}
+
+void btif_a2dp_source_on_suspended(tBTA_AV_SUSPEND* p_av_suspend) {
+ APPL_TRACE_EVENT("## ON A2DP SOURCE SUSPENDED ##");
+
+ if (btif_a2dp_source_state == BTIF_A2DP_SOURCE_STATE_OFF) return;
+
+ /* check for status failures */
+ if (p_av_suspend->status != BTA_AV_SUCCESS) {
+ if (p_av_suspend->initiator) {
+ APPL_TRACE_WARNING("%s: A2DP suspend request failed: status = %d",
+ __func__, p_av_suspend->status);
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+ }
+
+ /* once stream is fully stopped we will ack back */
+
+ /* ensure tx frames are immediately flushed */
+ btif_a2dp_source_cb.tx_flush = true;
+
+ /* stop timer tick */
+ btif_a2dp_source_stop_audio_req();
+}
+
+/* when true media task discards any tx frames */
+void btif_a2dp_source_set_tx_flush(bool enable) {
+ APPL_TRACE_EVENT("## DROP TX %d ##", enable);
+ btif_a2dp_source_cb.tx_flush = enable;
+}
+
+static void btif_a2dp_source_audio_tx_start_event(void) {
+ APPL_TRACE_DEBUG(
+ "%s media_alarm is %srunning, streaming %s", __func__,
+ alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+ btif_a2dp_source_is_streaming() ? "true" : "false");
+
+ /* Reset the media feeding state */
+ CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+ btif_a2dp_source_cb.encoder_interface->feeding_reset();
+
+ APPL_TRACE_EVENT(
+ "starting timer %dms",
+ btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms());
+
+ alarm_free(btif_a2dp_source_cb.media_alarm);
+ btif_a2dp_source_cb.media_alarm =
+ alarm_new_periodic("btif.a2dp_source_media_alarm");
+ if (btif_a2dp_source_cb.media_alarm == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate media alarm", __func__);
+ return;
+ }
+
+ alarm_set(btif_a2dp_source_cb.media_alarm,
+ btif_a2dp_source_cb.encoder_interface->get_encoder_interval_ms(),
+ btif_a2dp_source_alarm_cb, NULL);
+}
+
+static void btif_a2dp_source_audio_tx_stop_event(void) {
+ APPL_TRACE_DEBUG(
+ "%s media_alarm is %srunning, streaming %s", __func__,
+ alarm_is_scheduled(btif_a2dp_source_cb.media_alarm) ? "" : "not ",
+ btif_a2dp_source_is_streaming() ? "true" : "false");
+
+ const bool send_ack = btif_a2dp_source_is_streaming();
+
+ /* Stop the timer first */
+ alarm_free(btif_a2dp_source_cb.media_alarm);
+ btif_a2dp_source_cb.media_alarm = NULL;
+
+ UIPC_Close(UIPC_CH_ID_AV_AUDIO);
+
+ /*
+ * Try to send acknowldegment once the media stream is
+ * stopped. This will make sure that the A2DP HAL layer is
+ * un-blocked on wait for acknowledgment for the sent command.
+ * This resolves a corner cases AVDTP SUSPEND collision
+ * when the DUT and the remote device issue SUSPEND simultaneously
+ * and due to the processing of the SUSPEND request from the remote,
+ * the media path is torn down. If the A2DP HAL happens to wait
+ * for ACK for the initiated SUSPEND, it would never receive it casuing
+ * a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
+ * to get the ACK for any pending command in such cases.
+ */
+
+ if (send_ack) btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+
+ /* audio engine stopped, reset tx suspended flag */
+ btif_a2dp_source_cb.tx_flush = false;
+
+ /* Reset the media feeding state */
+ if (btif_a2dp_source_cb.encoder_interface != NULL)
+ btif_a2dp_source_cb.encoder_interface->feeding_reset();
+}
+
+static void btif_a2dp_source_alarm_cb(UNUSED_ATTR void* context) {
+ thread_post(btif_a2dp_source_cb.worker_thread,
+ btif_a2dp_source_audio_handle_timer, NULL);
+}
+
+static void btif_a2dp_source_audio_handle_timer(UNUSED_ATTR void* context) {
+ uint64_t timestamp_us = time_get_os_boottime_us();
+ log_tstamps_us("A2DP Source tx timer", timestamp_us);
+
+ if (alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+ CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+ if (btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length !=
+ NULL) {
+ size_t transmit_queue_length =
+ fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+ btif_a2dp_source_cb.encoder_interface->set_transmit_queue_length(
+ transmit_queue_length);
+ }
+ btif_a2dp_source_cb.encoder_interface->send_frames(timestamp_us);
+ bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
+ update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_enqueue_stats,
+ timestamp_us,
+ btif_a2dp_source_cb.encoder_interval_ms * 1000);
+ } else {
+ APPL_TRACE_ERROR("ERROR Media task Scheduled after Suspend");
+ }
+}
+
+static uint32_t btif_a2dp_source_read_callback(uint8_t* p_buf, uint32_t len) {
+ uint16_t event;
+ uint32_t bytes_read = UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);
+
+ if (bytes_read < len) {
+ LOG_WARN(LOG_TAG, "%s: UNDERFLOW: ONLY READ %d BYTES OUT OF %d", __func__,
+ bytes_read, len);
+ btif_a2dp_source_cb.stats.media_read_total_underflow_bytes +=
+ (len - bytes_read);
+ btif_a2dp_source_cb.stats.media_read_total_underflow_count++;
+ btif_a2dp_source_cb.stats.media_read_last_underflow_us =
+ time_get_os_boottime_us();
+ }
+
+ return bytes_read;
+}
+
+static bool btif_a2dp_source_enqueue_callback(BT_HDR* p_buf, size_t frames_n) {
+ uint64_t now_us = time_get_os_boottime_us();
+
+ /* Check if timer was stopped (media task stopped) */
+ if (!alarm_is_scheduled(btif_a2dp_source_cb.media_alarm)) {
+ osi_free(p_buf);
+ return false;
+ }
+
+ /* Check if the transmission queue has been flushed */
+ if (btif_a2dp_source_cb.tx_flush) {
+ LOG_VERBOSE(LOG_TAG, "%s: tx suspended, discarded frame", __func__);
+
+ btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
+ fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+ btif_a2dp_source_cb.stats.tx_queue_last_flushed_us = now_us;
+ fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
+
+ osi_free(p_buf);
+ return false;
+ }
+
+ // Check for TX queue overflow
+ // TODO: Using frames_n here is probably wrong: should be "+ 1" instead.
+ if (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue) + frames_n >
+ MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
+ LOG_WARN(LOG_TAG, "%s: TX queue buffer size now=%u adding=%u max=%d",
+ __func__,
+ (uint32_t)fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue),
+ (uint32_t)frames_n, MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ);
+ // Keep track of drop-outs
+ btif_a2dp_source_cb.stats.tx_queue_dropouts++;
+ btif_a2dp_source_cb.stats.tx_queue_last_dropouts_us = now_us;
+
+ // Flush all queued buffers
+ size_t drop_n = fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+ btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages = std::max(
+ drop_n, btif_a2dp_source_cb.stats.tx_queue_max_dropped_messages);
+ while (fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue)) {
+ btif_a2dp_source_cb.stats.tx_queue_total_dropped_messages++;
+ osi_free(fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue));
+ }
+
+ // Request RSSI for log purposes if we had to flush buffers
+ bt_bdaddr_t peer_bda = btif_av_get_addr();
+ BTM_ReadRSSI(peer_bda.address, btm_read_rssi_cb);
+ }
+
+ /* Update the statistics */
+ btif_a2dp_source_cb.stats.tx_queue_total_frames += frames_n;
+ btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet = std::max(
+ frames_n, btif_a2dp_source_cb.stats.tx_queue_max_frames_per_packet);
+ CHECK(btif_a2dp_source_cb.encoder_interface != NULL);
+
+ fixed_queue_enqueue(btif_a2dp_source_cb.tx_audio_queue, p_buf);
+
+ return true;
+}
+
+static void btif_a2dp_source_audio_tx_flush_event(UNUSED_ATTR BT_HDR* p_msg) {
+ /* Flush all enqueued audio buffers (encoded) */
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ if (btif_a2dp_source_cb.encoder_interface != NULL)
+ btif_a2dp_source_cb.encoder_interface->feeding_flush();
+
+ btif_a2dp_source_cb.stats.tx_queue_total_flushed_messages +=
+ fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue);
+ btif_a2dp_source_cb.stats.tx_queue_last_flushed_us =
+ time_get_os_boottime_us();
+ fixed_queue_flush(btif_a2dp_source_cb.tx_audio_queue, osi_free);
+
+ UIPC_Ioctl(UIPC_CH_ID_AV_AUDIO, UIPC_REQ_RX_FLUSH, NULL);
+}
+
+static bool btif_a2dp_source_audio_tx_flush_req(void) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
+
+ p_buf->event = BTIF_MEDIA_AUDIO_TX_FLUSH;
+
+ /*
+ * Explicitly check whether the btif_a2dp_source_cb.cmd_msg_queue is not
+ * NULL to avoid a race condition during shutdown of the Bluetooth stack.
+ * This race condition is triggered when A2DP audio is streaming on
+ * shutdown:
+ * "btif_a2dp_source_on_stopped() -> btif_a2dp_source_audio_tx_flush_req()"
+ * is called to stop the particular audio stream, and this happens right
+ * after the "BTIF_AV_CLEANUP_REQ_EVT -> btif_a2dp_source_shutdown()"
+ * processing during the shutdown of the Bluetooth stack.
+ */
+ if (btif_a2dp_source_cb.cmd_msg_queue != NULL)
+ fixed_queue_enqueue(btif_a2dp_source_cb.cmd_msg_queue, p_buf);
+
+ return true;
+}
+
+BT_HDR* btif_a2dp_source_audio_readbuf(void) {
+ uint64_t now_us = time_get_os_boottime_us();
+
+ /** M: Bug fix for avoid ANR when media task shutting down @{ */
+ if (!btif_a2dp_source_media_task_is_running())
+ {
+ APPL_TRACE_DEBUG("btif_a2dp_source_audio_readbuf media task is not running");
+ return NULL;
+ }
+ /** @} */
+
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(btif_a2dp_source_cb.tx_audio_queue);
+
+ btif_a2dp_source_cb.stats.tx_queue_total_readbuf_calls++;
+ btif_a2dp_source_cb.stats.tx_queue_last_readbuf_us = now_us;
+ if (p_buf != NULL) {
+ // Update the statistics
+ update_scheduling_stats(&btif_a2dp_source_cb.stats.tx_queue_dequeue_stats,
+ now_us,
+ btif_a2dp_source_cb.encoder_interval_ms * 1000);
+ }
+
+ return p_buf;
+}
+
+static void log_tstamps_us(const char* comment, uint64_t timestamp_us) {
+ static uint64_t prev_us = 0;
+ APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment,
+ timestamp_us, timestamp_us - prev_us,
+ fixed_queue_length(btif_a2dp_source_cb.tx_audio_queue));
+ prev_us = timestamp_us;
+}
+
+static void update_scheduling_stats(scheduling_stats_t* stats, uint64_t now_us,
+ uint64_t expected_delta) {
+ uint64_t last_us = stats->last_update_us;
+
+ stats->total_updates++;
+ stats->last_update_us = now_us;
+
+ if (last_us == 0) return; // First update: expected delta doesn't apply
+
+ uint64_t deadline_us = last_us + expected_delta;
+ if (deadline_us < now_us) {
+ // Overdue scheduling
+ uint64_t delta_us = now_us - deadline_us;
+ // Ignore extreme outliers
+ if (delta_us < 10 * expected_delta) {
+ stats->max_overdue_scheduling_delta_us =
+ std::max(delta_us, stats->max_overdue_scheduling_delta_us);
+ stats->total_overdue_scheduling_delta_us += delta_us;
+ stats->overdue_scheduling_count++;
+ stats->total_scheduling_time_us += now_us - last_us;
+ }
+ } else if (deadline_us > now_us) {
+ // Premature scheduling
+ uint64_t delta_us = deadline_us - now_us;
+ // Ignore extreme outliers
+ if (delta_us < 10 * expected_delta) {
+ stats->max_premature_scheduling_delta_us =
+ std::max(delta_us, stats->max_premature_scheduling_delta_us);
+ stats->total_premature_scheduling_delta_us += delta_us;
+ stats->premature_scheduling_count++;
+ stats->total_scheduling_time_us += now_us - last_us;
+ }
+ } else {
+ // On-time scheduling
+ stats->exact_scheduling_count++;
+ stats->total_scheduling_time_us += now_us - last_us;
+ }
+}
+
+void btif_a2dp_source_debug_dump(int fd) {
+ btif_a2dp_source_accumulate_stats(&btif_a2dp_source_cb.stats,
+ &btif_a2dp_source_cb.accumulated_stats);
+ uint64_t now_us = time_get_os_boottime_us();
+ btif_media_stats_t* accumulated_stats =
+ &btif_a2dp_source_cb.accumulated_stats;
+ scheduling_stats_t* enqueue_stats =
+ &accumulated_stats->tx_queue_enqueue_stats;
+ scheduling_stats_t* dequeue_stats =
+ &accumulated_stats->tx_queue_dequeue_stats;
+ size_t ave_size;
+ uint64_t ave_time_us;
+
+ dprintf(fd, "\nA2DP State:\n");
+ dprintf(fd, " TxQueue:\n");
+
+ dprintf(fd,
+ " Counts (enqueue/dequeue/readbuf) : %zu / "
+ "%zu / %zu\n",
+ enqueue_stats->total_updates, dequeue_stats->total_updates,
+ accumulated_stats->tx_queue_total_readbuf_calls);
+
+ dprintf(
+ fd,
+ " Last update time ago in ms (enqueue/dequeue/readbuf) : %llu / %llu "
+ "/ %llu\n",
+ (enqueue_stats->last_update_us > 0)
+ ? (unsigned long long)(now_us - enqueue_stats->last_update_us) / 1000
+ : 0,
+ (dequeue_stats->last_update_us > 0)
+ ? (unsigned long long)(now_us - dequeue_stats->last_update_us) / 1000
+ : 0,
+ (accumulated_stats->tx_queue_last_readbuf_us > 0)
+ ? (unsigned long long)(now_us -
+ accumulated_stats->tx_queue_last_readbuf_us) /
+ 1000
+ : 0);
+
+ ave_size = 0;
+ if (enqueue_stats->total_updates != 0)
+ ave_size =
+ accumulated_stats->tx_queue_total_frames / enqueue_stats->total_updates;
+ dprintf(fd,
+ " Frames per packet (total/max/ave) : %zu / "
+ "%zu / %zu\n",
+ accumulated_stats->tx_queue_total_frames,
+ accumulated_stats->tx_queue_max_frames_per_packet, ave_size);
+
+ dprintf(fd,
+ " Counts (flushed/dropped/dropouts) : %zu / "
+ "%zu / %zu\n",
+ accumulated_stats->tx_queue_total_flushed_messages,
+ accumulated_stats->tx_queue_total_dropped_messages,
+ accumulated_stats->tx_queue_dropouts);
+
+ dprintf(fd,
+ " Counts (max dropped) : %zu\n",
+ accumulated_stats->tx_queue_max_dropped_messages);
+
+ dprintf(
+ fd,
+ " Last update time ago in ms (flushed/dropped) : %llu / "
+ "%llu\n",
+ (accumulated_stats->tx_queue_last_flushed_us > 0)
+ ? (unsigned long long)(now_us -
+ accumulated_stats->tx_queue_last_flushed_us) /
+ 1000
+ : 0,
+ (accumulated_stats->tx_queue_last_dropouts_us > 0)
+ ? (unsigned long long)(now_us -
+ accumulated_stats->tx_queue_last_dropouts_us) /
+ 1000
+ : 0);
+
+ dprintf(fd,
+ " Counts (underflow) : %zu\n",
+ accumulated_stats->media_read_total_underflow_count);
+
+ dprintf(fd,
+ " Bytes (underflow) : %zu\n",
+ accumulated_stats->media_read_total_underflow_bytes);
+
+ dprintf(fd,
+ " Last update time ago in ms (underflow) : %llu\n",
+ (accumulated_stats->media_read_last_underflow_us > 0)
+ ? (unsigned long long)(now_us -
+ accumulated_stats
+ ->media_read_last_underflow_us) /
+ 1000
+ : 0);
+
+ //
+ // TxQueue enqueue stats
+ //
+ dprintf(
+ fd,
+ " Enqueue deviation counts (overdue/premature) : %zu / %zu\n",
+ enqueue_stats->overdue_scheduling_count,
+ enqueue_stats->premature_scheduling_count);
+
+ ave_time_us = 0;
+ if (enqueue_stats->overdue_scheduling_count != 0) {
+ ave_time_us = enqueue_stats->total_overdue_scheduling_delta_us /
+ enqueue_stats->overdue_scheduling_count;
+ }
+ dprintf(
+ fd,
+ " Enqueue overdue scheduling time in ms (total/max/ave) : %llu / %llu "
+ "/ %llu\n",
+ (unsigned long long)enqueue_stats->total_overdue_scheduling_delta_us /
+ 1000,
+ (unsigned long long)enqueue_stats->max_overdue_scheduling_delta_us / 1000,
+ (unsigned long long)ave_time_us / 1000);
+
+ ave_time_us = 0;
+ if (enqueue_stats->premature_scheduling_count != 0) {
+ ave_time_us = enqueue_stats->total_premature_scheduling_delta_us /
+ enqueue_stats->premature_scheduling_count;
+ }
+ dprintf(
+ fd,
+ " Enqueue premature scheduling time in ms (total/max/ave) : %llu / %llu "
+ "/ %llu\n",
+ (unsigned long long)enqueue_stats->total_premature_scheduling_delta_us /
+ 1000,
+ (unsigned long long)enqueue_stats->max_premature_scheduling_delta_us /
+ 1000,
+ (unsigned long long)ave_time_us / 1000);
+
+ //
+ // TxQueue dequeue stats
+ //
+ dprintf(
+ fd,
+ " Dequeue deviation counts (overdue/premature) : %zu / %zu\n",
+ dequeue_stats->overdue_scheduling_count,
+ dequeue_stats->premature_scheduling_count);
+
+ ave_time_us = 0;
+ if (dequeue_stats->overdue_scheduling_count != 0) {
+ ave_time_us = dequeue_stats->total_overdue_scheduling_delta_us /
+ dequeue_stats->overdue_scheduling_count;
+ }
+ dprintf(
+ fd,
+ " Dequeue overdue scheduling time in ms (total/max/ave) : %llu / %llu "
+ "/ %llu\n",
+ (unsigned long long)dequeue_stats->total_overdue_scheduling_delta_us /
+ 1000,
+ (unsigned long long)dequeue_stats->max_overdue_scheduling_delta_us / 1000,
+ (unsigned long long)ave_time_us / 1000);
+
+ ave_time_us = 0;
+ if (dequeue_stats->premature_scheduling_count != 0) {
+ ave_time_us = dequeue_stats->total_premature_scheduling_delta_us /
+ dequeue_stats->premature_scheduling_count;
+ }
+ dprintf(
+ fd,
+ " Dequeue premature scheduling time in ms (total/max/ave) : %llu / %llu "
+ "/ %llu\n",
+ (unsigned long long)dequeue_stats->total_premature_scheduling_delta_us /
+ 1000,
+ (unsigned long long)dequeue_stats->max_premature_scheduling_delta_us /
+ 1000,
+ (unsigned long long)ave_time_us / 1000);
+
+ //
+ // Codec-specific stats
+ //
+ A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
+ if (a2dp_codecs != nullptr) {
+ a2dp_codecs->debug_codec_dump(fd);
+ }
+}
+
+void btif_a2dp_source_update_metrics(void) {
+ btif_media_stats_t* stats = &btif_a2dp_source_cb.stats;
+ scheduling_stats_t* enqueue_stats = &stats->tx_queue_enqueue_stats;
+ A2dpSessionMetrics metrics;
+ // session_start_us is 0 when btif_a2dp_source_start_audio_req() is not called
+ // mark the metric duration as invalid (-1) in this case
+ if (stats->session_start_us != 0) {
+ int64_t session_end_us = stats->session_end_us == 0
+ ? time_get_os_boottime_us()
+ : stats->session_end_us;
+ metrics.audio_duration_ms =
+ (session_end_us - stats->session_start_us) / 1000;
+ }
+
+ if (enqueue_stats->total_updates > 1) {
+ metrics.media_timer_min_ms =
+ btif_a2dp_source_cb.encoder_interval_ms -
+ (enqueue_stats->max_premature_scheduling_delta_us / 1000);
+ metrics.media_timer_max_ms =
+ btif_a2dp_source_cb.encoder_interval_ms +
+ (enqueue_stats->max_overdue_scheduling_delta_us / 1000);
+
+ metrics.total_scheduling_count = enqueue_stats->overdue_scheduling_count +
+ enqueue_stats->premature_scheduling_count +
+ enqueue_stats->exact_scheduling_count;
+ if (metrics.total_scheduling_count > 0) {
+ metrics.media_timer_avg_ms = enqueue_stats->total_scheduling_time_us /
+ (1000 * metrics.total_scheduling_count);
+ }
+
+ metrics.buffer_overruns_max_count = stats->tx_queue_max_dropped_messages;
+ metrics.buffer_overruns_total = stats->tx_queue_total_dropped_messages;
+ metrics.buffer_underruns_count = stats->media_read_total_underflow_count;
+ metrics.buffer_underruns_average = 0;
+ if (metrics.buffer_underruns_count > 0) {
+ metrics.buffer_underruns_average =
+ stats->media_read_total_underflow_bytes /
+ metrics.buffer_underruns_count;
+ }
+ }
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics);
+}
+
+static void btm_read_rssi_cb(void* data) {
+ if (data == nullptr) {
+ LOG_ERROR(LOG_TAG, "%s RSSI request timed out", __func__);
+ return;
+ }
+
+ tBTM_RSSI_RESULTS* result = (tBTM_RSSI_RESULTS*)data;
+ if (result->status != BTM_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s unable to read remote RSSI (status %d)", __func__,
+ result->status);
+ return;
+ }
+
+ char temp_buffer[20] = {0};
+ LOG_WARN(LOG_TAG, "%s device: %s, rssi: %d", __func__,
+ bdaddr_to_string((bt_bdaddr_t*)result->rem_bda, temp_buffer,
+ sizeof(temp_buffer)),
+ result->rssi);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_av.cc b/mtkbt/code/bt/btif/src/btif_av.cc
new file mode 100755
index 0000000..7dd5c71
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_av.cc
@@ -0,0 +1,1889 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "btif_av"
+
+#include "btif_av.h"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_av.h>
+#include <hardware/bt_rc.h>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "btif_a2dp.h"
+#include "btif_a2dp_control.h"
+#include "btif_a2dp_sink.h"
+#include "btif_av_co.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#define BTIF_TIMER_A2DP_DELAY_START_CMD (1 * 1000)
+static alarm_t *tle_av_delay_start_cmd = NULL;
+#endif
+
+/** M: add globle value for timing issue @{ */
+static BD_ADDR mtk_rc_peer_addr;
+/** @} */
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+#define BTIF_AV_SERVICE_NAME "Advanced Audio"
+#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink"
+
+#define BTIF_TIMEOUT_AV_OPEN_ON_RC_MS (2 * 1000)
+
+typedef enum {
+ BTIF_AV_STATE_IDLE = 0x0,
+ BTIF_AV_STATE_OPENING,
+ BTIF_AV_STATE_OPENED,
+ BTIF_AV_STATE_STARTED,
+ BTIF_AV_STATE_CLOSING
+} btif_av_state_t;
+
+/* Should not need dedicated suspend state as actual actions are no
+ different than open state. Suspend flags are needed however to prevent
+ media task from trying to restart stream during remote suspend or while
+ we are in the process of a local suspend */
+
+#define BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
+#define BTIF_AV_FLAG_REMOTE_SUSPEND 0x2
+#define BTIF_AV_FLAG_PENDING_START 0x4
+#define BTIF_AV_FLAG_PENDING_STOP 0x8
+/** M: Bug fix for Avoid remote trigger START @{ */
+#define BTIF_AV_FLAG_REMOTE_SUSPENDING 0x20
+/** @} */
+
+/*****************************************************************************
+ * Local type definitions
+ *****************************************************************************/
+
+typedef struct {
+ tBTA_AV_HNDL bta_handle;
+ bt_bdaddr_t peer_bda;
+ btif_sm_handle_t sm_handle;
+ uint8_t flags;
+ tBTA_AV_EDR edr;
+ uint8_t peer_sep; /* sep type of peer device */
+ std::vector<btav_a2dp_codec_config_t> codec_priorities;
+} btif_av_cb_t;
+
+typedef struct {
+ bt_bdaddr_t* target_bda;
+ uint16_t uuid;
+} btif_av_connect_req_t;
+
+typedef struct {
+ int sample_rate;
+ int channel_count;
+ bt_bdaddr_t peer_bd;
+} btif_av_sink_config_req_t;
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+static btav_source_callbacks_t* bt_av_src_callbacks = NULL;
+static btav_sink_callbacks_t* bt_av_sink_callbacks = NULL;
+static btif_av_cb_t btif_av_cb = {
+ 0, {{0}}, 0, 0, 0, 0, std::vector<btav_a2dp_codec_config_t>()};
+static alarm_t* av_open_on_rc_timer = NULL;
+
+/* both interface and media task needs to be ready to alloc incoming request */
+#define CHECK_BTAV_INIT() \
+ do { \
+ if (((bt_av_src_callbacks == NULL) && (bt_av_sink_callbacks == NULL)) || \
+ (btif_av_cb.sm_handle == NULL)) { \
+ BTIF_TRACE_WARNING("%s: BTAV not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+/* Helper macro to avoid code duplication in the state machine handlers */
+#define CHECK_RC_EVENT(e, d) \
+ case BTA_AV_RC_OPEN_EVT: \
+ case BTA_AV_RC_BROWSE_OPEN_EVT: \
+ case BTA_AV_RC_CLOSE_EVT: \
+ case BTA_AV_RC_BROWSE_CLOSE_EVT: \
+ case BTA_AV_REMOTE_CMD_EVT: \
+ case BTA_AV_VENDOR_CMD_EVT: \
+ case BTA_AV_META_MSG_EVT: \
+ case BTA_AV_RC_FEAT_EVT: \
+ case BTA_AV_REMOTE_RSP_EVT: { \
+ btif_rc_handler(e, d); \
+ } break;
+
+static bool btif_av_state_idle_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_opening_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_opened_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_started_handler(btif_sm_event_t event, void* data);
+static bool btif_av_state_closing_handler(btif_sm_event_t event, void* data);
+
+static const btif_sm_handler_t btif_av_state_handlers[] = {
+ btif_av_state_idle_handler, btif_av_state_opening_handler,
+ btif_av_state_opened_handler, btif_av_state_started_handler,
+ btif_av_state_closing_handler};
+
+static void btif_av_event_free_data(btif_sm_event_t event, void* p_data);
+
+/*************************************************************************
+ * Extern functions
+ ************************************************************************/
+extern void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data);
+extern bool btif_rc_get_connected_peer(BD_ADDR peer_addr);
+extern uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr);
+extern void btif_rc_check_handle_pending_play(BD_ADDR peer_addr,
+ bool bSendToApp);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ * Local helper functions
+ *****************************************************************************/
+
+const char* dump_av_sm_state_name(btif_av_state_t state) {
+ switch (state) {
+ CASE_RETURN_STR(BTIF_AV_STATE_IDLE)
+ CASE_RETURN_STR(BTIF_AV_STATE_OPENING)
+ CASE_RETURN_STR(BTIF_AV_STATE_OPENED)
+ CASE_RETURN_STR(BTIF_AV_STATE_STARTED)
+ CASE_RETURN_STR(BTIF_AV_STATE_CLOSING)
+ default:
+ return "UNKNOWN_STATE";
+ }
+}
+
+const char* dump_av_sm_event_name(btif_av_sm_event_t event) {
+ switch ((int)event) {
+ CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AV_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AV_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_START_EVT)
+ CASE_RETURN_STR(BTA_AV_STOP_EVT)
+ CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT)
+ CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_RECONFIG_EVT)
+ CASE_RETURN_STR(BTA_AV_SUSPEND_EVT)
+ CASE_RETURN_STR(BTA_AV_PENDING_EVT)
+ CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+ CASE_RETURN_STR(BTA_AV_REJECT_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ CASE_RETURN_STR(BTA_AV_OFFLOAD_START_RSP_EVT)
+ CASE_RETURN_STR(BTIF_SM_ENTER_EVT)
+ CASE_RETURN_STR(BTIF_SM_EXIT_EVT)
+ CASE_RETURN_STR(BTIF_AV_CONNECT_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_DISCONNECT_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_START_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_STOP_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_SUSPEND_STREAM_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_SOURCE_CONFIG_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_SOURCE_CONFIG_UPDATED_EVT)
+ CASE_RETURN_STR(BTIF_AV_SINK_CONFIG_REQ_EVT)
+ CASE_RETURN_STR(BTIF_AV_OFFLOAD_START_REQ_EVT)
+ default:
+ return "UNKNOWN_EVENT";
+ }
+}
+
+/****************************************************************************
+ * Local helper functions
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function btif_initiate_av_open_timer_timeout
+ *
+ * Description Timer to trigger AV open if the remote headset establishes
+ * RC connection w/o AV connection. The timer is needed to IOP
+ * with headsets that do establish AV after RC connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_initiate_av_open_timer_timeout(UNUSED_ATTR void* data) {
+ /** M: use globle value for timing issue @{ */
+ // use globle value
+ //BD_ADDR peer_addr;
+ /** @} */
+ btif_av_connect_req_t connect_req;
+
+ /* is there at least one RC connection - There should be */
+ /** M: use globle value for timing issue @{ */
+ memset(mtk_rc_peer_addr, 0, sizeof(BD_ADDR));
+ if (btif_rc_get_connected_peer(mtk_rc_peer_addr)) {
+ /** @} */
+ BTIF_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __func__);
+ /* In case of AVRCP connection request, we will initiate SRC connection */
+ /** M: use globle value for timing issue @{ */
+ connect_req.target_bda = (bt_bdaddr_t*)&mtk_rc_peer_addr;
+ /** @} */
+ if (bt_av_sink_callbacks != NULL)
+ connect_req.uuid = UUID_SERVCLASS_AUDIO_SINK;
+ else if (bt_av_src_callbacks != NULL)
+ connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
+ btif_dispatch_sm_event(BTIF_AV_CONNECT_REQ_EVT, (char*)&connect_req,
+ sizeof(connect_req));
+ } else {
+ BTIF_TRACE_ERROR("%s No connected RC peers", __func__);
+ }
+}
+
+/*****************************************************************************
+ * Static functions
+ *****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_report_connection_state
+ *
+ * Description Updates the components via the callbacks about the
+ * connection state of a2dp connection.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void btif_report_connection_state(btav_connection_state_t state,
+ bt_bdaddr_t* bd_addr) {
+ if (bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, connection_state_cb, state, bd_addr);
+ } else if (bt_av_src_callbacks != NULL) {
+ HAL_CBACK(bt_av_src_callbacks, connection_state_cb, state, bd_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_report_audio_state
+ *
+ * Description Updates the components via the callbacks about the audio
+ * state of a2dp connection. The state is updated when either
+ * the remote ends starts streaming (started state) or whenever
+ * it transitions out of started state (to opened or streaming)
+ * state.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void btif_report_audio_state(btav_audio_state_t state,
+ bt_bdaddr_t* bd_addr) {
+ if (bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_state_cb, state, bd_addr);
+ } else if (bt_av_src_callbacks != NULL) {
+ HAL_CBACK(bt_av_src_callbacks, audio_state_cb, state, bd_addr);
+ }
+}
+
+static void btif_update_source_codec(void* p_data) {
+ btav_a2dp_codec_config_t req;
+ // copy to avoid alignment problems
+ memcpy(&req, p_data, sizeof(req));
+
+ BTIF_TRACE_DEBUG("BTIF_AV_SOURCE_CONFIG_REQ_EVT");
+ btif_a2dp_source_encoder_user_config_update_req(req);
+}
+
+static void btif_report_source_codec_state(UNUSED_ATTR void* p_data) {
+ btav_a2dp_codec_config_t codec_config;
+ std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
+ std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
+
+ A2dpCodecs* a2dp_codecs = bta_av_get_a2dp_codecs();
+ if (a2dp_codecs == nullptr) return;
+ if (!a2dp_codecs->getCodecConfigAndCapabilities(
+ &codec_config, &codecs_local_capabilities,
+ &codecs_selectable_capabilities)) {
+ BTIF_TRACE_WARNING(
+ "BTIF_AV_SOURCE_CONFIG_UPDATED_EVT failed: "
+ "cannot get codec config and capabilities");
+ return;
+ }
+ if (bt_av_src_callbacks != NULL) {
+ HAL_CBACK(bt_av_src_callbacks, audio_config_cb, codec_config,
+ codecs_local_capabilities, codecs_selectable_capabilities);
+ }
+}
+
+/*****************************************************************************
+ *
+ * Function btif_av_state_idle_handler
+ *
+ * Description State managing disconnected AV link
+ *
+ * Returns true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_idle_handler(btif_sm_event_t event, void* p_data) {
+ BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event),
+ btif_av_cb.flags);
+
+ switch (event) {
+ case BTIF_SM_ENTER_EVT:
+ /* clear the peer_bda */
+ memset(&btif_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
+ btif_av_cb.flags = 0;
+ btif_av_cb.edr = 0;
+ /**M:Bug fix for A2DP start fail @{*/
+ raise_priority_jni(false);
+ /**@}*/
+ bta_av_co_init(btif_av_cb.codec_priorities);
+ btif_a2dp_on_idle();
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTA_AV_ENABLE_EVT:
+ break;
+
+ case BTA_AV_REGISTER_EVT:
+ btif_av_cb.bta_handle = ((tBTA_AV*)p_data)->registr.hndl;
+ break;
+
+ case BTA_AV_PENDING_EVT:
+ case BTIF_AV_CONNECT_REQ_EVT: {
+ if (event == BTIF_AV_CONNECT_REQ_EVT) {
+ memcpy(&btif_av_cb.peer_bda,
+ ((btif_av_connect_req_t*)p_data)->target_bda,
+ sizeof(bt_bdaddr_t));
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+ BTA_SEC_AUTHENTICATE,
+ ((btif_av_connect_req_t*)p_data)->uuid);
+ } else if (event == BTA_AV_PENDING_EVT) {
+ bdcpy(btif_av_cb.peer_bda.address, ((tBTA_AV*)p_data)->pend.bd_addr);
+ if (bt_av_src_callbacks != NULL) {
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+ BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE);
+ }
+ if (bt_av_sink_callbacks != NULL) {
+ BTA_AvOpen(btif_av_cb.peer_bda.address, btif_av_cb.bta_handle, true,
+ BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SINK);
+ }
+ }
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENING);
+ } break;
+
+ case BTA_AV_RC_OPEN_EVT:
+ /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it
+ * connects. So
+ * as per the AV WP, an AVRC connection cannot exist without an AV
+ * connection. Therefore,
+ * we initiate an AV connection if an RC_OPEN_EVT is received when we are
+ * in AV_CLOSED state.
+ * We initiate the AV connection after a small 3s timeout to avoid any
+ * collisions from the
+ * headsets, as some headsets initiate the AVRC connection first and then
+ * immediately initiate the AV connection
+ *
+ * TODO: We may need to do this only on an AVRCP Play. FixMe
+ */
+
+ BTIF_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
+ alarm_set_on_queue(av_open_on_rc_timer, BTIF_TIMEOUT_AV_OPEN_ON_RC_MS,
+ btif_initiate_av_open_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTA_AV_RC_BROWSE_OPEN_EVT:
+ BTIF_TRACE_DEBUG("BTA_AV_RC_BROWSE_OPEN_EVT received");
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
+ btif_update_source_codec(p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
+ btif_report_source_codec_state(p_data);
+ break;
+
+ /*
+ * In case Signalling channel is not down
+ * and remote started Streaming Procedure
+ * we have to handle config and open event in
+ * idle_state. We hit these scenarios while running
+ * PTS test case for AVRCP Controller
+ */
+ case BTIF_AV_SINK_CONFIG_REQ_EVT: {
+ btif_av_sink_config_req_t req;
+ // copy to avoid alignment problems
+ memcpy(&req, p_data, sizeof(req));
+
+ BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+ req.channel_count);
+ if (bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(req.peer_bd),
+ req.sample_rate, req.channel_count);
+ }
+ } break;
+
+ case BTA_AV_OPEN_EVT: {
+ tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+ btav_connection_state_t state;
+ btif_sm_state_t av_state;
+ BTIF_TRACE_DEBUG("status:%d, edr 0x%x", p_bta_data->open.status,
+ p_bta_data->open.edr);
+
+ if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+ state = BTAV_CONNECTION_STATE_CONNECTED;
+ av_state = BTIF_AV_STATE_OPENED;
+ btif_av_cb.edr = p_bta_data->open.edr;
+
+ btif_av_cb.peer_sep = p_bta_data->open.sep;
+ } else {
+ BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+ p_bta_data->open.status);
+ state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ av_state = BTIF_AV_STATE_IDLE;
+ }
+
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+ /* change state to open/idle based on the status */
+ btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(
+ p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
+ (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+ /* Bring up AVRCP connection too */
+ BTA_AvOpenRc(btif_av_cb.bta_handle);
+ }
+ btif_queue_advance();
+ } break;
+
+ case BTA_AV_REMOTE_CMD_EVT:
+ case BTA_AV_VENDOR_CMD_EVT:
+ case BTA_AV_META_MSG_EVT:
+ case BTA_AV_RC_FEAT_EVT:
+ case BTA_AV_REMOTE_RSP_EVT:
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTA_AV_RC_CLOSE_EVT:
+ BTIF_TRACE_DEBUG("BTA_AV_RC_CLOSE_EVT: Stopping AV timer.");
+ alarm_cancel(av_open_on_rc_timer);
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTIF_TRACE_ERROR(
+ "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started IDLE");
+ btif_a2dp_on_offload_started(BTA_AV_FAIL);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ return false;
+ }
+
+ return true;
+}
+/*****************************************************************************
+ *
+ * Function btif_av_state_opening_handler
+ *
+ * Description Intermediate state managing events during establishment
+ * of avdtp channel
+ *
+ * Returns true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_opening_handler(btif_sm_event_t event, void* p_data) {
+ BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event),
+ btif_av_cb.flags);
+
+ switch (event) {
+ case BTIF_SM_ENTER_EVT:
+ /* inform the application that we are entering connecting state */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_CONNECTING,
+ &(btif_av_cb.peer_bda));
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTA_AV_REJECT_EVT:
+ BTIF_TRACE_DEBUG(" Received BTA_AV_REJECT_EVT ");
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTA_AV_OPEN_EVT: {
+ tBTA_AV* p_bta_data = (tBTA_AV*)p_data;
+ btav_connection_state_t state;
+ btif_sm_state_t av_state;
+ BTIF_TRACE_DEBUG("status:%d, edr 0x%x", p_bta_data->open.status,
+ p_bta_data->open.edr);
+
+ if (p_bta_data->open.status == BTA_AV_SUCCESS) {
+ state = BTAV_CONNECTION_STATE_CONNECTED;
+ av_state = BTIF_AV_STATE_OPENED;
+ btif_av_cb.edr = p_bta_data->open.edr;
+
+ btif_av_cb.peer_sep = p_bta_data->open.sep;
+ } else {
+ BTIF_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d",
+ p_bta_data->open.status);
+ BD_ADDR peer_addr;
+ uint8_t peer_handle = BTRC_HANDLE_NONE;
+ if ((btif_rc_get_connected_peer(peer_addr)) &&
+ (!bdcmp(btif_av_cb.peer_bda.address, peer_addr))) {
+ /*
+ * Disconnect AVRCP connection, if
+ * A2DP conneciton failed, for any reason
+ */
+ BTIF_TRACE_WARNING(" Disconnecting AVRCP ");
+ peer_handle = btif_rc_get_connected_peer_handle(peer_addr);
+ if (peer_handle != BTRC_HANDLE_NONE) {
+ BTA_AvCloseRc(peer_handle);
+ }
+ }
+ state = BTAV_CONNECTION_STATE_DISCONNECTED;
+ av_state = BTIF_AV_STATE_IDLE;
+ /** M: Bug fix for a2dp connect fail @{ */
+ btif_queue_advance();
+ /** @} */
+ }
+
+ /* inform the application of the event */
+ btif_report_connection_state(state, &(btif_av_cb.peer_bda));
+ /* change state to open/idle based on the status */
+ btif_sm_change_state(btif_av_cb.sm_handle, av_state);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ /* if queued PLAY command, send it now */
+ btif_rc_check_handle_pending_play(
+ p_bta_data->open.bd_addr,
+ (p_bta_data->open.status == BTA_AV_SUCCESS));
+ } else if ((btif_av_cb.peer_sep == AVDT_TSEP_SRC) &&
+ (p_bta_data->open.status == BTA_AV_SUCCESS)) {
+ /* Bring up AVRCP connection too */
+ BTA_AvOpenRc(btif_av_cb.bta_handle);
+ }
+ /** M: Bug fix for a2dp connect fail @{ */
+ if (p_bta_data->open.status == BTA_AV_SUCCESS)
+ /** @} */
+ btif_queue_advance();
+ } break;
+
+ case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
+ btif_update_source_codec(p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
+ btif_report_source_codec_state(p_data);
+ break;
+
+ case BTIF_AV_SINK_CONFIG_REQ_EVT: {
+ btif_av_sink_config_req_t req;
+ // copy to avoid alignment problems
+ memcpy(&req, p_data, sizeof(req));
+
+ BTIF_TRACE_WARNING("BTIF_AV_SINK_CONFIG_REQ_EVT %d %d", req.sample_rate,
+ req.channel_count);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC &&
+ bt_av_sink_callbacks != NULL) {
+ HAL_CBACK(bt_av_sink_callbacks, audio_config_cb, &(btif_av_cb.peer_bda),
+ req.sample_rate, req.channel_count);
+ }
+ } break;
+
+ case BTIF_AV_CONNECT_REQ_EVT:
+ // Check for device, if same device which moved to opening then ignore
+ // callback
+ if (memcmp(((btif_av_connect_req_t*)p_data)->target_bda,
+ &(btif_av_cb.peer_bda), sizeof(btif_av_cb.peer_bda)) == 0) {
+ BTIF_TRACE_DEBUG(
+ "%s: Same device moved to Opening state,ignore Connect Req",
+ __func__);
+ btif_queue_advance();
+ break;
+ } else {
+ BTIF_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request",
+ __func__);
+ btif_report_connection_state(
+ BTAV_CONNECTION_STATE_DISCONNECTED,
+ ((btif_av_connect_req_t*)p_data)->target_bda);
+ btif_queue_advance();
+ break;
+ }
+
+ case BTA_AV_PENDING_EVT:
+ // Check for device, if same device which moved to opening then ignore
+ // callback
+ if (memcmp(((tBTA_AV*)p_data)->pend.bd_addr, &(btif_av_cb.peer_bda),
+ sizeof(btif_av_cb.peer_bda)) == 0) {
+ BTIF_TRACE_DEBUG(
+ "%s: Same device moved to Opening state,ignore Pending Req",
+ __func__);
+ break;
+ } else {
+ BTIF_TRACE_DEBUG("%s: Moved from idle by outgoing Connection request",
+ __func__);
+ BTA_AvDisconnect(((tBTA_AV*)p_data)->pend.bd_addr);
+ break;
+ }
+
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTIF_TRACE_ERROR(
+ "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started OPENING");
+ btif_a2dp_on_offload_started(BTA_AV_FAIL);
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+ btif_a2dp_on_stopped(NULL);
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+ default:
+ BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ return false;
+ }
+ return true;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_av_state_closing_handler
+ *
+ * Description Intermediate state managing events during closing
+ * of avdtp channel
+ *
+ * Returns true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_closing_handler(btif_sm_event_t event, void* p_data) {
+ BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event),
+ btif_av_cb.flags);
+
+ switch (event) {
+ case BTIF_SM_ENTER_EVT:
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ /* immediately stop transmission of frames */
+ btif_a2dp_source_set_tx_flush(true);
+ /* wait for audioflinger to stop a2dp */
+ }
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_set_rx_flush(true);
+ }
+ break;
+
+ case BTA_AV_STOP_EVT:
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ btif_a2dp_on_stopped(NULL);
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
+ btif_update_source_codec(p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
+ btif_report_source_codec_state(p_data);
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+
+ /* inform the application that we are disconnecting */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ /* Handle the RC_CLOSE event for the cleanup */
+ case BTA_AV_RC_CLOSE_EVT:
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ /* Handle the RC_BROWSE_CLOSE event for tetsing*/
+ case BTA_AV_RC_BROWSE_CLOSE_EVT:
+ btif_rc_handler(event, (tBTA_AV*)p_data);
+ break;
+
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTIF_TRACE_ERROR(
+ "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Closing");
+ btif_a2dp_on_offload_started(BTA_AV_FAIL);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ return false;
+ }
+ return true;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_av_state_opened_handler
+ *
+ * Description Handles AV events while AVDTP is in OPEN state
+ *
+ * Returns true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_opened_handler(btif_sm_event_t event, void* p_data) {
+ tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+ BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event),
+ btif_av_cb.flags);
+
+ if ((event == BTA_AV_REMOTE_CMD_EVT) &&
+ (btif_av_cb.flags & BTIF_AV_FLAG_REMOTE_SUSPEND) &&
+ (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY)) {
+ BTIF_TRACE_EVENT("%s: Resetting remote suspend flag on RC PLAY", __func__);
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+ }
+ /** M: Bug fix for Avoid remote trigger START @{ */
+ //Occur the AVDTP start event when music is not played.
+ else if (((event == BTA_AV_SUSPEND_EVT) || (event == BTA_AV_STOP_EVT)) && (btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING))
+ {
+ BTIF_TRACE_EVENT("%s: STOP_FOR_START_EVT_FROM_REMOTE ", __FUNCTION__);
+ /* a2dp suspended, stop media task until resumed */
+ btif_a2dp_on_suspended(&p_av->suspend);
+ btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+ /* suspend completed and state changed, clear pending status */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPENDING;
+ }
+ /** @} */
+
+ switch (event) {
+ case BTIF_SM_ENTER_EVT:
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_STOP;
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ /**M:Bug fix for A2DP start fail @{*/
+ raise_priority_jni(true);
+ /**@}*/
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ break;
+
+ case BTIF_AV_START_STREAM_REQ_EVT:
+ if (btif_av_cb.peer_sep != AVDT_TSEP_SRC) btif_a2dp_source_setup_codec();
+ BTA_AvStart();
+ btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_START;
+ break;
+
+ case BTA_AV_START_EVT: {
+ BTIF_TRACE_EVENT("BTA_AV_START_EVT status %d, suspending %d, init %d",
+ p_av->start.status, p_av->start.suspending,
+ p_av->start.initiator);
+
+ if ((p_av->start.status == BTA_SUCCESS) &&
+ (p_av->start.suspending == true))
+ return true;
+
+ /* if remote tries to start a2dp when DUT is a2dp source
+ * then suspend. In case a2dp is sink and call is active
+ * then disconnect the AVDTP channel
+ */
+ if (!(btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START)) {
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ BTIF_TRACE_EVENT("%s: trigger suspend as remote initiated!!",
+ __func__);
+ btif_dispatch_sm_event(BTIF_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
+ }
+ }
+
+ /* In case peer is A2DP SRC we do not want to ack commands on UIPC*/
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ if (btif_a2dp_on_started(
+ &p_av->start,
+ ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) != 0))) {
+ /* only clear pending flag after acknowledgement */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ }
+ }
+
+ /* remain in open state if status failed */
+ if (p_av->start.status != BTA_AV_SUCCESS) return false;
+
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ btif_a2dp_sink_set_rx_flush(
+ false); /* remove flush state, ready for streaming*/
+ }
+
+ /* change state to started, send acknowledgement if start is pending */
+ if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ btif_a2dp_on_started(NULL, true);
+ /* pending start flag will be cleared when exit current state */
+ }
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_STARTED);
+
+ } break;
+
+ case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
+ btif_update_source_codec(p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
+ btif_report_source_codec_state(p_data);
+ break;
+
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+ BTA_AvClose(btif_av_cb.bta_handle);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb.bta_handle);
+ }
+
+ /* inform the application that we are disconnecting */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
+ &(btif_av_cb.peer_bda));
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+ /* avdtp link is closed */
+ btif_a2dp_on_stopped(NULL);
+
+ /* inform the application that we are disconnected */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+
+ /* change state to idle, send acknowledgement if start is pending */
+ if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ /* pending start flag will be cleared when exit current state */
+ }
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTA_AV_RECONFIG_EVT:
+ if ((btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) &&
+ (p_av->reconfig.status == BTA_AV_SUCCESS)) {
+ APPL_TRACE_WARNING("reconfig done BTA_AVstart()");
+ BTA_AvStart();
+ } else if (btif_av_cb.flags & BTIF_AV_FLAG_PENDING_START) {
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_PENDING_START;
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_FAILURE);
+ }
+ break;
+
+ case BTIF_AV_CONNECT_REQ_EVT:
+ /** M: Bug fix for modify parameter at open state for BTIF_AV_CONNECT_REQ_EVT @{ */
+ if (memcmp (((btif_av_connect_req_t*)p_data)->target_bda, &(btif_av_cb.peer_bda),
+ sizeof(btif_av_cb.peer_bda)) == 0) {
+ /** @} */
+ BTIF_TRACE_DEBUG("%s: Ignore BTIF_AV_CONNECT_REQ_EVT for same device",
+ __func__);
+ } else {
+ BTIF_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req",
+ __func__);
+ /** M: Bug fix for modify parameter at open state for BTIF_AV_CONNECT_REQ_EVT @{ */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ ((btif_av_connect_req_t*)p_data)->target_bda);
+ /** @} */
+ }
+ btif_queue_advance();
+ break;
+
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTIF_TRACE_ERROR(
+ "BTIF_AV_OFFLOAD_START_REQ_EVT: Stream not Started Opened");
+ btif_a2dp_on_offload_started(BTA_AV_FAIL);
+ break;
+
+ CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+ default:
+ BTIF_TRACE_WARNING("%s : unhandled event:%s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ return false;
+ }
+ return true;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_av_state_started_handler
+ *
+ * Description Handles AV events while A2DP stream is started
+ *
+ * Returns true if event was processed, false otherwise
+ *
+ ******************************************************************************/
+
+static bool btif_av_state_started_handler(btif_sm_event_t event, void* p_data) {
+ tBTA_AV* p_av = (tBTA_AV*)p_data;
+
+ BTIF_TRACE_DEBUG("%s event:%s flags %x", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event),
+ btif_av_cb.flags);
+
+ switch (event) {
+ case BTIF_SM_ENTER_EVT:
+
+ /* we are again in started state, clear any remote suspend flags */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+ /**
+ * Report to components above that we have entered the streaming
+ * stage, this should usually be followed by focus grant.
+ * see update_audio_focus_state()
+ */
+ btif_report_audio_state(BTAV_AUDIO_STATE_STARTED, &(btif_av_cb.peer_bda));
+ break;
+
+ case BTIF_SM_EXIT_EVT:
+ break;
+
+ case BTIF_AV_START_STREAM_REQ_EVT:
+ /* we were remotely started, just ack back the local request */
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK)
+ btif_a2dp_on_started(NULL, true);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_REQ_EVT:
+ btif_update_source_codec(p_data);
+ break;
+
+ case BTIF_AV_SOURCE_CONFIG_UPDATED_EVT:
+ btif_report_source_codec_state(p_data);
+ break;
+
+ /* fixme -- use suspend = true always to work around issue with BTA AV */
+ case BTIF_AV_STOP_STREAM_REQ_EVT:
+ case BTIF_AV_SUSPEND_STREAM_REQ_EVT:
+
+ /* set pending flag to ensure btif task is not trying to restart
+ stream while suspend is in progress */
+ btif_av_cb.flags |= BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+ /* if we were remotely suspended but suspend locally, local suspend
+ always overrides */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ /*
+ * Immediately stop transmission of frames while suspend is
+ * pending.
+ */
+ btif_a2dp_source_set_tx_flush(true);
+ }
+
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ btif_a2dp_on_stopped(NULL);
+ }
+
+ BTA_AvStop(true);
+ break;
+
+ case BTIF_AV_DISCONNECT_REQ_EVT:
+
+ /* request avdtp to close */
+ BTA_AvClose(btif_av_cb.bta_handle);
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SRC) {
+ BTA_AvCloseRc(btif_av_cb.bta_handle);
+ }
+
+ /* inform the application that we are disconnecting */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTING,
+ &(btif_av_cb.peer_bda));
+
+ /* wait in closing state until fully closed */
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_CLOSING);
+ break;
+
+ case BTA_AV_SUSPEND_EVT:
+
+ BTIF_TRACE_EVENT("BTA_AV_SUSPEND_EVT status %d, init %d",
+ p_av->suspend.status, p_av->suspend.initiator);
+
+ /* a2dp suspended, stop media task until resumed */
+ btif_a2dp_on_suspended(&p_av->suspend);
+
+ /* if not successful, remain in current state */
+ if (p_av->suspend.status != BTA_AV_SUCCESS) {
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+
+ if (btif_av_cb.peer_sep == AVDT_TSEP_SNK) {
+ /* suspend failed, reset back tx flush state */
+ btif_a2dp_source_set_tx_flush(false);
+ }
+ return false;
+ }
+
+ if (p_av->suspend.initiator != true) {
+ /* remote suspend, notify HAL and await audioflinger to
+ suspend/stop stream */
+
+ /* set remote suspend flag to block media task from restarting
+ stream only if we did not already initiate a local suspend */
+ if ((btif_av_cb.flags & BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0)
+ btif_av_cb.flags |= BTIF_AV_FLAG_REMOTE_SUSPEND;
+ /** M: Bug fix for avoid not ack to audioflinger@{ */
+ else
+ btif_a2dp_command_ack(A2DP_CTRL_ACK_SUCCESS);
+ /** @} */
+ btif_report_audio_state(BTAV_AUDIO_STATE_REMOTE_SUSPEND,
+ &(btif_av_cb.peer_bda));
+ } else {
+ btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED,
+ &(btif_av_cb.peer_bda));
+ }
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+ /* suspend completed and state changed, clear pending status */
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING;
+ break;
+
+ case BTA_AV_STOP_EVT:
+
+ btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+ btif_a2dp_on_stopped(&p_av->suspend);
+
+ btif_report_audio_state(BTAV_AUDIO_STATE_STOPPED, &(btif_av_cb.peer_bda));
+
+ /* if stop was successful, change state to open */
+ if (p_av->suspend.status == BTA_AV_SUCCESS)
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_OPENED);
+
+ break;
+
+ case BTA_AV_CLOSE_EVT:
+
+ btif_av_cb.flags |= BTIF_AV_FLAG_PENDING_STOP;
+
+ /* avdtp link is closed */
+ btif_a2dp_on_stopped(NULL);
+
+ /* inform the application that we are disconnected */
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ break;
+
+ case BTIF_AV_OFFLOAD_START_REQ_EVT:
+ BTA_AvOffloadStart(btif_av_cb.bta_handle);
+ break;
+
+ case BTA_AV_OFFLOAD_START_RSP_EVT:
+ btif_a2dp_on_offload_started(p_av->status);
+ break;
+
+ CHECK_RC_EVENT(event, (tBTA_AV*)p_data);
+
+ default:
+ BTIF_TRACE_WARNING("%s: unhandled event: %s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ return false;
+ }
+
+ return true;
+}
+
+/*****************************************************************************
+ * Local event handlers
+ *****************************************************************************/
+
+static void btif_av_handle_event(uint16_t event, char* p_param) {
+ BTIF_TRACE_EVENT("%s event:%s", __func__,
+ dump_av_sm_event_name((btif_av_sm_event_t)event));
+ switch (event) {
+ case BTIF_AV_CLEANUP_REQ_EVT:
+ /** M: Bug fix for shut down the AV state machine@{ */
+ btif_sm_shutdown(btif_av_cb.sm_handle);
+ btif_av_cb.sm_handle = NULL;
+ /** @} */
+ btif_a2dp_source_shutdown();
+ btif_a2dp_sink_shutdown();
+ /** M: Bug fix for avoid NE during cleaning up@{ */
+ if (bt_av_src_callbacks != NULL && bt_av_sink_callbacks == NULL)
+ {
+ bt_av_src_callbacks = NULL;
+ BTIF_TRACE_DEBUG("cleanup bt_av_src_callbacks");
+ }
+ if (bt_av_src_callbacks == NULL && bt_av_sink_callbacks != NULL)
+ {
+ bt_av_sink_callbacks = NULL;
+ BTIF_TRACE_DEBUG("cleanup bt_av_sink_callbacks");
+ }
+ /** @} */
+ break;
+
+ case BTA_AV_REGISTER_EVT:
+ if (btif_av_cb.sm_handle == NULL) {
+ btif_av_cb.bta_handle = ((tBTA_AV*)p_param)->registr.hndl;
+ BTIF_TRACE_DEBUG("%s: BTA AV Handle updated", __func__);
+ }
+ /* FALLTHROUGH */
+ default:
+ btif_sm_dispatch(btif_av_cb.sm_handle, event, (void*)p_param);
+ btif_av_event_free_data(event, p_param);
+ }
+}
+
+void btif_av_event_deep_copy(uint16_t event, char* p_dest, char* p_src) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ tBTA_AV* av_src = (tBTA_AV*)p_src;
+ tBTA_AV* av_dest = (tBTA_AV*)p_dest;
+
+ // First copy the structure
+ maybe_non_aligned_memcpy(av_dest, av_src, sizeof(*av_src));
+ switch (event) {
+ case BTA_AV_META_MSG_EVT:
+ if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
+ av_dest->meta_msg.p_data = (uint8_t*)osi_calloc(av_src->meta_msg.len);
+ memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data,
+ av_src->meta_msg.len);
+ }
+
+ if (av_src->meta_msg.p_msg) {
+ av_dest->meta_msg.p_msg = (tAVRC_MSG*)osi_calloc(sizeof(tAVRC_MSG));
+ memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg,
+ sizeof(tAVRC_MSG));
+
+ tAVRC_MSG* p_msg_src = av_src->meta_msg.p_msg;
+ tAVRC_MSG* p_msg_dest = av_dest->meta_msg.p_msg;
+
+ if ((p_msg_src->hdr.opcode == AVRC_OP_VENDOR) &&
+ (p_msg_src->vendor.p_vendor_data && p_msg_src->vendor.vendor_len)) {
+ p_msg_dest->vendor.p_vendor_data =
+ (uint8_t*)osi_calloc(p_msg_src->vendor.vendor_len);
+ memcpy(p_msg_dest->vendor.p_vendor_data,
+ p_msg_src->vendor.p_vendor_data, p_msg_src->vendor.vendor_len);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void btif_av_event_free_data(btif_sm_event_t event, void* p_data) {
+ switch (event) {
+ case BTA_AV_META_MSG_EVT: {
+ tBTA_AV* av = (tBTA_AV*)p_data;
+ osi_free_and_reset((void**)&av->meta_msg.p_data);
+
+ if (av->meta_msg.p_msg) {
+ if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_VENDOR) {
+ osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
+ }
+ osi_free_and_reset((void**)&av->meta_msg.p_msg);
+ }
+ } break;
+
+ default:
+ break;
+ }
+}
+
+static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV* p_data) {
+ btif_transfer_context(btif_av_handle_event, event, (char*)p_data,
+ sizeof(tBTA_AV), btif_av_event_deep_copy);
+}
+
+static void bte_av_sink_media_callback(tBTA_AV_EVT event,
+ tBTA_AV_MEDIA* p_data) {
+ switch (event) {
+ case BTA_AV_SINK_MEDIA_DATA_EVT: {
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ if ((state == BTIF_AV_STATE_STARTED) || (state == BTIF_AV_STATE_OPENED)) {
+ uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data);
+ BTIF_TRACE_DEBUG("%s: packets in sink queue %d", __func__, queue_len);
+ }
+ break;
+ }
+ case BTA_AV_SINK_MEDIA_CFG_EVT: {
+ btif_av_sink_config_req_t config_req;
+
+ /* send a command to BT Media Task */
+ btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info));
+ /* Switch to BTIF context */
+ config_req.sample_rate =
+ A2DP_GetTrackSampleRate(p_data->avk_config.codec_info);
+ if (config_req.sample_rate == -1) {
+ APPL_TRACE_ERROR("%s: cannot get the track frequency", __func__);
+ break;
+ }
+ config_req.channel_count =
+ A2DP_GetTrackChannelCount(p_data->avk_config.codec_info);
+ if (config_req.channel_count == -1) {
+ APPL_TRACE_ERROR("%s: cannot get the channel count", __func__);
+ break;
+ }
+
+ memcpy(&config_req.peer_bd, (uint8_t*)(p_data->avk_config.bd_addr),
+ sizeof(config_req.peer_bd));
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_SINK_CONFIG_REQ_EVT,
+ (char*)&config_req, sizeof(config_req), NULL);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_init
+ *
+ * Description Initializes btif AV if not already done
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_av_init(int service_id) {
+ if (btif_av_cb.sm_handle == NULL) {
+ alarm_free(av_open_on_rc_timer);
+ av_open_on_rc_timer = alarm_new("btif_av.av_open_on_rc_timer");
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ alarm_free(tle_av_delay_start_cmd);
+ tle_av_delay_start_cmd = alarm_new("btif_av.tle_av_delay_start_cmd");
+#endif
+
+ switch (service_id) {
+ case BTA_A2DP_SOURCE_SERVICE_ID:
+ if (!btif_a2dp_source_startup())
+ return BT_STATUS_FAIL; // Already running
+ break;
+ case BTA_A2DP_SINK_SERVICE_ID:
+ if (!btif_a2dp_sink_startup())
+ return BT_STATUS_FAIL; // Already running
+ break;
+ default:
+ break;
+ }
+
+ /** M: Bug fix for avoid NE when sm_handle is NULL @{ */
+ /* Also initialize the AV state machine */
+ btif_av_cb.sm_handle = btif_sm_init(
+ (const btif_sm_handler_t*)btif_av_state_handlers, BTIF_AV_STATE_IDLE);
+
+ btif_enable_service(service_id);
+ /** @} */
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function init_src
+ *
+ * Description Initializes the AV interface for source mode
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t init_src(
+ btav_source_callbacks_t* callbacks,
+ std::vector<btav_a2dp_codec_config_t> codec_priorities) {
+ BTIF_TRACE_EVENT("%s()", __func__);
+
+ btif_av_cb.codec_priorities = codec_priorities;
+ bt_status_t status = btif_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
+ if (status == BT_STATUS_SUCCESS) bt_av_src_callbacks = callbacks;
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function init_sink
+ *
+ * Description Initializes the AV interface for sink mode
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t init_sink(btav_sink_callbacks_t* callbacks) {
+ BTIF_TRACE_EVENT("%s()", __func__);
+
+ bt_status_t status = btif_av_init(BTA_A2DP_SINK_SERVICE_ID);
+ if (status == BT_STATUS_SUCCESS) bt_av_sink_callbacks = callbacks;
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function update_audio_focus_state
+ *
+ * Description Updates the final focus state reported by components calling
+ * this module.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void update_audio_focus_state(int state) {
+ BTIF_TRACE_DEBUG("%s: state %d", __func__, state);
+ btif_a2dp_sink_set_focus_state_req((btif_a2dp_sink_focus_state_t)state);
+}
+
+/*******************************************************************************
+ *
+ * Function update_audio_track_gain
+ *
+ * Description Updates the track gain (used for ducking).
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void update_audio_track_gain(float gain) {
+ BTIF_TRACE_DEBUG("%s: gain %f", __func__, gain);
+ btif_a2dp_sink_set_audio_track_gain(gain);
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description Establishes the AV signalling channel with the remote
+ * headset
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+ btif_av_connect_req_t connect_req;
+ connect_req.target_bda = bd_addr;
+ connect_req.uuid = uuid;
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ btif_sm_dispatch(btif_av_cb.sm_handle, BTIF_AV_CONNECT_REQ_EVT,
+ (char*)&connect_req);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t src_connect_sink(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ CHECK_BTAV_INIT();
+
+ return btif_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, bd_addr, connect_int);
+}
+
+static bt_status_t sink_connect_src(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ CHECK_BTAV_INIT();
+
+ return btif_queue_connect(UUID_SERVCLASS_AUDIO_SINK, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description Tears down the AV signalling channel with the remote headset
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ CHECK_BTAV_INIT();
+
+ /* Switch to BTIF context */
+ return btif_transfer_context(btif_av_handle_event, BTIF_AV_DISCONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+}
+
+static bt_status_t codec_config_src(
+ std::vector<btav_a2dp_codec_config_t> codec_preferences) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ CHECK_BTAV_INIT();
+
+ for (auto cp : codec_preferences) {
+ BTIF_TRACE_DEBUG(
+ "%s: codec_type=%d codec_priority=%d "
+ "sample_rate=0x%x bits_per_sample=0x%x "
+ "channel_mode=0x%x codec_specific_1=%d "
+ "codec_specific_2=%d codec_specific_3=%d "
+ "codec_specific_4=%d",
+ __func__, cp.codec_type, cp.codec_priority, cp.sample_rate,
+ cp.bits_per_sample, cp.channel_mode, cp.codec_specific_1,
+ cp.codec_specific_2, cp.codec_specific_3, cp.codec_specific_4);
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_SOURCE_CONFIG_REQ_EVT,
+ reinterpret_cast<char*>(&cp), sizeof(cp), NULL);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Shuts down the AV interface and does the cleanup
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void cleanup(int service_uuid) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ btif_transfer_context(btif_av_handle_event, BTIF_AV_CLEANUP_REQ_EVT, NULL, 0,
+ NULL);
+
+ btif_disable_service(service_uuid);
+
+ alarm_free(av_open_on_rc_timer);
+ av_open_on_rc_timer = NULL;
+
+ /** M: Bug fix for avoid NE @{ */
+ BTIF_TRACE_EVENT("return cleanup");
+ return;
+ /** @} */
+
+ /* Also shut down the AV state machine */
+ btif_sm_shutdown(btif_av_cb.sm_handle);
+ btif_av_cb.sm_handle = NULL;
+}
+
+static void cleanup_src(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ if (bt_av_src_callbacks) {
+ /** M: Bug fix for avoid NE @{ */
+ if (bt_av_sink_callbacks == NULL) cleanup(BTA_A2DP_SOURCE_SERVICE_ID);
+ else
+ bt_av_src_callbacks = NULL;
+ /** @} */
+ }
+}
+
+static void cleanup_sink(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ if (bt_av_sink_callbacks) {
+ /** M: Bug fix for avoid NE @{ */
+ if (bt_av_src_callbacks == NULL) cleanup(BTA_A2DP_SINK_SERVICE_ID);
+ else
+ bt_av_sink_callbacks = NULL;
+ /** @} */
+ }
+}
+
+static const btav_source_interface_t bt_av_src_interface = {
+ sizeof(btav_source_interface_t),
+ init_src,
+ src_connect_sink,
+ disconnect,
+ codec_config_src,
+ cleanup_src,
+};
+
+static const btav_sink_interface_t bt_av_sink_interface = {
+ sizeof(btav_sink_interface_t),
+ init_sink,
+ sink_connect_src,
+ disconnect,
+ cleanup_sink,
+ update_audio_focus_state,
+ update_audio_track_gain,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_av_get_addr
+ *
+ * Description Fetches current AV BD address
+ *
+ * Returns BD address
+ *
+ ******************************************************************************/
+
+bt_bdaddr_t btif_av_get_addr(void) { return btif_av_cb.peer_bda; }
+
+/*******************************************************************************
+ * Function btif_av_is_sink_enabled
+ *
+ * Description Checks if A2DP Sink is enabled or not
+ *
+ * Returns true if A2DP Sink is enabled, false otherwise
+ *
+ ******************************************************************************/
+
+bool btif_av_is_sink_enabled(void) {
+ return (bt_av_sink_callbacks != NULL) ? true : false;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_stream_ready
+ *
+ * Description Checks whether AV is ready for starting a stream
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_ready(void) {
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+ BTIF_TRACE_DEBUG("btif_av_stream_ready : sm hdl %d, state %d, flags %x",
+ btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+ /* also make sure main adapter is enabled */
+ if (btif_is_enabled() == 0) {
+ BTIF_TRACE_EVENT("main adapter not enabled");
+ return false;
+ }
+
+ /* check if we are remotely suspended or stop is pending */
+ if (btif_av_cb.flags &
+ (BTIF_AV_FLAG_REMOTE_SUSPEND | BTIF_AV_FLAG_PENDING_STOP))
+ return false;
+
+ return (state == BTIF_AV_STATE_OPENED);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_stream_started_ready
+ *
+ * Description Checks whether AV ready for media start in streaming state
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+bool btif_av_stream_started_ready(void) {
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+
+ BTIF_TRACE_DEBUG("btif_av_stream_started : sm hdl %d, state %d, flags %x",
+ btif_av_cb.sm_handle, state, btif_av_cb.flags);
+
+ /* disallow media task to start if we have pending actions */
+ if (btif_av_cb.flags &
+ (BTIF_AV_FLAG_LOCAL_SUSPEND_PENDING | BTIF_AV_FLAG_REMOTE_SUSPEND |
+ BTIF_AV_FLAG_PENDING_STOP))
+ return false;
+
+ return (state == BTIF_AV_STATE_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dispatch_sm_event
+ *
+ * Description Send event to AV statemachine
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+
+/* used to pass events to AV statemachine from other tasks */
+void btif_dispatch_sm_event(btif_av_sm_event_t event, void* p_data, int len) {
+ /* Switch to BTIF context */
+ btif_transfer_context(btif_av_handle_event, event, (char*)p_data, len, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_av_execute_service(bool b_enable) {
+ if (b_enable) {
+/* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
+ * handle this request in order to allow incoming connections to succeed.
+ * We need to put this back once support for this is added */
+
+/* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
+/* Support for browsing for SDP record should work only if we enable BROWSE
+ * while registering. */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+ BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
+ BTA_AV_FEAT_NO_SCO_SSPD
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL |
+ BTA_AV_FEAT_BROWSE
+#endif
+ ,
+ bte_av_callback);
+#else
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+ (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_NO_SCO_SSPD), bte_av_callback);
+#endif
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AV_SERVICE_NAME, 0, NULL,
+ UUID_SERVCLASS_AUDIO_SOURCE);
+ } else {
+ BTA_AvDeregister(btif_av_cb.bta_handle);
+ BTA_AvDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_sink_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_av_sink_execute_service(bool b_enable) {
+ if (b_enable) {
+ /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
+ * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
+ * be initiated by the app/audioflinger layers */
+ BTA_AvEnable(BTA_SEC_AUTHENTICATE,
+ BTA_AV_FEAT_NO_SCO_SSPD | BTA_AV_FEAT_RCCT |
+ BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
+ BTA_AV_FEAT_ADV_CTRL | BTA_AV_FEAT_RCTG |
+ BTA_AV_FEAT_BROWSE,
+ bte_av_callback);
+ BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTIF_AVK_SERVICE_NAME, 0,
+ bte_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK);
+ } else {
+ BTA_AvDeregister(btif_av_cb.bta_handle);
+ BTA_AvDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_get_src_interface
+ *
+ * Description Get the AV callback interface for A2DP source profile
+ *
+ * Returns btav_source_interface_t
+ *
+ ******************************************************************************/
+const btav_source_interface_t* btif_av_get_src_interface(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bt_av_src_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_get_sink_interface
+ *
+ * Description Get the AV callback interface for A2DP sink profile
+ *
+ * Returns btav_sink_interface_t
+ *
+ ******************************************************************************/
+const btav_sink_interface_t* btif_av_get_sink_interface(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bt_av_sink_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_is_connected
+ *
+ * Description Checks if av has a connected sink
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_av_is_connected(void) {
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ return ((state == BTIF_AV_STATE_OPENED) || (state == BTIF_AV_STATE_STARTED));
+}
+
+/** M: Bug fix for Block AVRCP key if A2DP is not connected @{ */
+/*******************************************************************************
+ * **
+ * ** Function btif_av_is_idle
+ * **
+ * ** Description Checks if av in idle state
+ * **
+ * ** Returns bool
+ * **
+ * *******************************************************************************/
+bool btif_av_is_idle(void)
+{
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ return (state == BTIF_AV_STATE_IDLE);
+}
+/** @} */
+
+uint8_t btif_av_get_peer_sep(void) { return btif_av_cb.peer_sep; }
+
+/*******************************************************************************
+ *
+ * Function btif_av_is_peer_edr
+ *
+ * Description Check if the connected a2dp device supports
+ * EDR or not. Only when connected this function
+ * will accurately provide a true capability of
+ * remote peer. If not connected it will always be false.
+ *
+ * Returns true if remote device is capable of EDR
+ *
+ ******************************************************************************/
+bool btif_av_is_peer_edr(void) {
+ ASSERTC(btif_av_is_connected(), "No active a2dp connection", 0);
+
+ if (btif_av_cb.edr)
+ return true;
+ else
+ return false;
+}
+
+/******************************************************************************
+ *
+ * Function btif_av_clear_remote_suspend_flag
+ *
+ * Description Clears btif_av_cd.flags if BTIF_AV_FLAG_REMOTE_SUSPEND is set
+ *
+ * Returns void
+ *****************************************************************************/
+void btif_av_clear_remote_suspend_flag(void) {
+ BTIF_TRACE_DEBUG("%s: flag :%x", __func__, btif_av_cb.flags);
+ btif_av_cb.flags &= ~BTIF_AV_FLAG_REMOTE_SUSPEND;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_peer_supports_3mbps
+ *
+ * Description Check if the connected A2DP device supports
+ * 3 Mbps EDR. This function only works if connected.
+ * If not connected it will always be false.
+ *
+ * Returns true if remote device is EDR and supports 3 Mbps
+ *
+ ******************************************************************************/
+bool btif_av_peer_supports_3mbps(void) {
+ bool is3mbps = ((btif_av_cb.edr & BTA_AV_EDR_3MBPS) != 0);
+ BTIF_TRACE_DEBUG("%s: connected %d, edr_3mbps %d", __func__,
+ btif_av_is_connected(), is3mbps);
+ return (btif_av_is_connected() && is3mbps);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_av_move_idle
+ *
+ * Description Opening state is intermediate state. It cannot handle
+ * incoming/outgoing connect/disconnect requests.When ACL
+ * is disconnected and we are in opening state then move back
+ * to idle state which is proper to handle connections.
+ *
+ * Returns Void
+ *
+ ******************************************************************************/
+void btif_av_move_idle(bt_bdaddr_t bd_addr) {
+ /* inform the application that ACL is disconnected and move to idle state */
+ btif_sm_state_t state = btif_sm_get_state(btif_av_cb.sm_handle);
+ BTIF_TRACE_DEBUG("%s: ACL Disconnected state %d is same device %d", __func__,
+ state,
+ memcmp(&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)));
+ if (state == BTIF_AV_STATE_OPENING &&
+ (memcmp(&bd_addr, &(btif_av_cb.peer_bda), sizeof(bd_addr)) == 0)) {
+ BTIF_TRACE_DEBUG(
+ "%s: Moving State from Opening to Idle due to ACL disconnect",
+ __func__);
+ btif_report_connection_state(BTAV_CONNECTION_STATE_DISCONNECTED,
+ &(btif_av_cb.peer_bda));
+ btif_sm_change_state(btif_av_cb.sm_handle, BTIF_AV_STATE_IDLE);
+ }
+}
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/*****************************************************************************
+**
+** Function btif_av_is_black_peer
+**
+** Description Some special device want perform START cmd itself first
+** If it not send START cmd, will close current link(ex. Tiggo5).
+** So for this special device, we need delay send START cmd
+** which from DUT to receive the special device cmd.
+**
+** Return TRUE if it is special peer device
+**
+****************************************************************************/
+bool btif_av_is_black_peer(void)
+{
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (sizeof(btif_av_cb.peer_bda) != 0) {
+ if (interop_mtk_match_addr_name(INTEROP_MTK_A2DP_DELAY_START_CMD, (const bt_bdaddr_t *)&btif_av_cb.peer_bda)) {
+ alarm_set_on_queue(tle_av_delay_start_cmd, BTIF_TIMER_A2DP_DELAY_START_CMD,
+ btif_media_av_delay_start_cmd_hdlr, tle_av_delay_start_cmd,
+ btu_general_alarm_queue);
+ BTIF_TRACE_DEBUG("%s return true", __func__);
+ return true;
+ }
+ else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+#endif
+
+/** M: Bug Fix for delay creating SCO when A2DP not suspend. @{ */
+btif_sm_handle_t btif_av_get_sm_handle(void) {
+ return btif_av_cb.sm_handle;
+}
+/** @} */ \ No newline at end of file
diff --git a/mtkbt/code/bt/btif/src/btif_avrcp_audio_track.cc b/mtkbt/code/bt/btif/src/btif_avrcp_audio_track.cc
new file mode 100755
index 0000000..8e192f7
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_avrcp_audio_track.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "bt_btif_avrcp_audio_track"
+
+#include "btif_avrcp_audio_track.h"
+
+#include <base/logging.h>
+#include <media/AudioTrack.h>
+#include <utils/StrongPointer.h>
+
+#include "bt_target.h"
+#include "osi/include/log.h"
+
+using namespace android;
+
+typedef struct { android::sp<android::AudioTrack> track; } BtifAvrcpAudioTrack;
+
+#if (DUMP_PCM_DATA == TRUE)
+FILE* outputPcmSampleFile;
+char outputFilename[50] = "/data/misc/bluedroid/output_sample.pcm";
+#endif
+
+void* BtifAvrcpAudioTrackCreate(int trackFreq, int channelType) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btCreateTrack freq %d channel %d ",
+ __func__, trackFreq, channelType);
+ sp<android::AudioTrack> track = new android::AudioTrack(
+ AUDIO_STREAM_MUSIC, trackFreq, AUDIO_FORMAT_PCM_16_BIT, channelType,
+ (size_t)0 /*frameCount*/, (audio_output_flags_t)AUDIO_OUTPUT_FLAG_FAST,
+ NULL /*callback_t*/, NULL /*void* user*/, 0 /*notificationFrames*/,
+ AUDIO_SESSION_ALLOCATE, android::AudioTrack::TRANSFER_SYNC);
+ CHECK(track != NULL);
+
+ BtifAvrcpAudioTrack* trackHolder = new BtifAvrcpAudioTrack;
+ CHECK(trackHolder != NULL);
+ trackHolder->track = track;
+
+ if (trackHolder->track->initCheck() != 0) {
+ return nullptr;
+ }
+
+#if (DUMP_PCM_DATA == TRUE)
+ outputPcmSampleFile = fopen(outputFilename, "ab");
+#endif
+ trackHolder->track->setVolume(1, 1);
+ return (void*)trackHolder;
+}
+
+void BtifAvrcpAudioTrackStart(void* handle) {
+ if (handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: handle is null!", __func__);
+ return;
+ }
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ CHECK(trackHolder != NULL);
+ CHECK(trackHolder->track != NULL);
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->start();
+}
+
+void BtifAvrcpAudioTrackStop(void* handle) {
+ if (handle == NULL) {
+ LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+ return;
+ }
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->stop();
+ }
+}
+
+void BtifAvrcpAudioTrackDelete(void* handle) {
+ if (handle == NULL) {
+ LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+ return;
+ }
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ delete trackHolder;
+ }
+
+#if (DUMP_PCM_DATA == TRUE)
+ if (outputPcmSampleFile) {
+ fclose(outputPcmSampleFile);
+ }
+ outputPcmSampleFile = NULL;
+#endif
+}
+
+void BtifAvrcpAudioTrackPause(void* handle) {
+ if (handle == NULL) {
+ LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+ return;
+ }
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btStartTrack", __func__);
+ trackHolder->track->pause();
+ trackHolder->track->flush();
+ }
+}
+
+void BtifAvrcpSetAudioTrackGain(void* handle, float gain) {
+ if (handle == NULL) {
+ LOG_DEBUG(LOG_TAG, "%s handle is null.", __func__);
+ return;
+ }
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ if (trackHolder != NULL && trackHolder->track != NULL) {
+ LOG_VERBOSE(LOG_TAG, "%s set gain %f", __func__, gain);
+ trackHolder->track->setVolume(gain);
+ }
+}
+
+int BtifAvrcpAudioTrackWriteData(void* handle, void* audioBuffer,
+ int bufferlen) {
+ BtifAvrcpAudioTrack* trackHolder = static_cast<BtifAvrcpAudioTrack*>(handle);
+ CHECK(trackHolder != NULL);
+ CHECK(trackHolder->track != NULL);
+ int retval = -1;
+#if (DUMP_PCM_DATA == TRUE)
+ if (outputPcmSampleFile) {
+ fwrite((audioBuffer), 1, (size_t)bufferlen, outputPcmSampleFile);
+ }
+#endif
+ retval = trackHolder->track->write(audioBuffer, (size_t)bufferlen);
+ LOG_VERBOSE(LOG_TAG, "%s Track.cpp: btWriteData len = %d ret = %d", __func__,
+ bufferlen, retval);
+ return retval;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_ble_advertiser.cc b/mtkbt/code/bt/btif/src/btif_ble_advertiser.cc
new file mode 100755
index 0000000..a37b095
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_ble_advertiser.cc
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_ble_advertiser"
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include <base/bind.h>
+#include <vector>
+
+#include "ble_advertiser.h"
+#include "bta_closure_api.h"
+#include "btif_common.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+namespace {
+
+template <typename T>
+class OwnedArrayWrapper {
+ public:
+ explicit OwnedArrayWrapper(T* o) : ptr_(o) {}
+ ~OwnedArrayWrapper() { delete[] ptr_; }
+ T* get() const { return ptr_; }
+ OwnedArrayWrapper(OwnedArrayWrapper&& other) {
+ ptr_ = other.ptr_;
+ other.ptr_ = NULL;
+ }
+
+ private:
+ mutable T* ptr_;
+};
+
+template <typename T>
+T* Unwrap(const OwnedArrayWrapper<T>& o) {
+ return o.get();
+}
+
+template <typename T>
+static inline OwnedArrayWrapper<T> OwnedArray(T* o) {
+ return OwnedArrayWrapper<T>(o);
+}
+
+void parseParams(tBTM_BLE_ADV_PARAMS* p_params,
+ const AdvertiseParameters& params) {
+ p_params->advertising_event_properties = params.advertising_event_properties;
+ p_params->adv_int_min = params.min_interval;
+ p_params->adv_int_max = params.max_interval;
+ p_params->channel_map = params.channel_map;
+ p_params->adv_filter_policy = 0;
+ p_params->tx_power = params.tx_power;
+ p_params->primary_advertising_phy = params.primary_advertising_phy;
+ p_params->secondary_advertising_phy = params.secondary_advertising_phy;
+ p_params->scan_request_notification_enable =
+ params.scan_request_notification_enable;
+}
+
+void parsePeriodicParams(tBLE_PERIODIC_ADV_PARAMS* p_periodic_params,
+ PeriodicAdvertisingParameters periodic_params) {
+ p_periodic_params->enable = periodic_params.enable;
+ p_periodic_params->min_interval = periodic_params.min_interval;
+ p_periodic_params->max_interval = periodic_params.max_interval;
+ p_periodic_params->periodic_advertising_properties =
+ periodic_params.periodic_advertising_properties;
+}
+
+class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface {
+ ~BleAdvertiserInterfaceImpl(){};
+
+ void RegisterAdvertiserCb(IdStatusCallback cb, uint8_t advertiser_id,
+ uint8_t status) {
+ LOG(INFO) << __func__ << " status: " << +status
+ << " , adveriser_id: " << +advertiser_id;
+ do_in_jni_thread(Bind(cb, advertiser_id, status));
+ }
+
+ void RegisterAdvertiser(IdStatusCallback cb) override {
+ do_in_bta_thread(
+ FROM_HERE, Bind(&BleAdvertisingManager::RegisterAdvertiser,
+ base::Unretained(BleAdvertisingManager::Get()),
+ Bind(&BleAdvertiserInterfaceImpl::RegisterAdvertiserCb,
+ base::Unretained(this), cb)));
+ }
+
+ void Unregister(uint8_t advertiser_id) override {
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::Unregister,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id));
+ }
+
+ void GetOwnAddress(uint8_t advertiser_id, GetAddressCallback cb) override {
+ do_in_bta_thread(FROM_HERE,
+ Bind(&BleAdvertisingManager::GetOwnAddress,
+ base::Unretained(BleAdvertisingManager::Get()),
+ advertiser_id, jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void SetParameters(uint8_t advertiser_id, AdvertiseParameters params,
+ ParametersCallback cb) override {
+ VLOG(1) << __func__;
+
+ tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
+ parseParams(p_params, params);
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::SetParameters,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ base::Owned(p_params), jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
+ StatusCallback cb) override {
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::SetData,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ set_scan_rsp, std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void Enable(uint8_t advertiser_id, bool enable, StatusCallback cb,
+ uint16_t duration, uint8_t maxExtAdvEvents,
+ StatusCallback timeout_cb) override {
+ VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id
+ << " ,enable: " << enable;
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::Enable,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ enable, jni_thread_wrapper(FROM_HERE, cb), duration,
+ maxExtAdvEvents, jni_thread_wrapper(FROM_HERE, timeout_cb)));
+ }
+
+ void StartAdvertising(uint8_t advertiser_id, StatusCallback cb,
+ AdvertiseParameters params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data, int timeout_s,
+ MultiAdvCb timeout_cb) override {
+ VLOG(1) << __func__;
+
+ tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
+ parseParams(p_params, params);
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::StartAdvertising,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ jni_thread_wrapper(FROM_HERE, cb), base::Owned(p_params),
+ std::move(advertise_data), std::move(scan_response_data),
+ timeout_s * 100, jni_thread_wrapper(FROM_HERE, timeout_cb)));
+ }
+
+ void StartAdvertisingSet(IdTxPowerStatusCallback cb,
+ AdvertiseParameters params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data,
+ PeriodicAdvertisingParameters periodic_params,
+ std::vector<uint8_t> periodic_data,
+ uint16_t duration, uint8_t maxExtAdvEvents,
+ IdStatusCallback timeout_cb) override {
+ VLOG(1) << __func__;
+
+ tBTM_BLE_ADV_PARAMS* p_params = new tBTM_BLE_ADV_PARAMS;
+ parseParams(p_params, params);
+
+ tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS;
+ parsePeriodicParams(p_periodic_params, periodic_params);
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::StartAdvertisingSet,
+ base::Unretained(BleAdvertisingManager::Get()),
+ jni_thread_wrapper(FROM_HERE, cb), base::Owned(p_params),
+ std::move(advertise_data), std::move(scan_response_data),
+ base::Owned(p_periodic_params), std::move(periodic_data), duration,
+ maxExtAdvEvents, jni_thread_wrapper(FROM_HERE, timeout_cb)));
+ }
+
+ void SetPeriodicAdvertisingParameters(
+ int advertiser_id, PeriodicAdvertisingParameters periodic_params,
+ StatusCallback cb) override {
+ VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id;
+
+ tBLE_PERIODIC_ADV_PARAMS* p_periodic_params = new tBLE_PERIODIC_ADV_PARAMS;
+ parsePeriodicParams(p_periodic_params, periodic_params);
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::SetPeriodicAdvertisingParameters,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ base::Owned(p_periodic_params),
+ jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void SetPeriodicAdvertisingData(int advertiser_id, std::vector<uint8_t> data,
+ StatusCallback cb) override {
+ VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id;
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::SetPeriodicAdvertisingData,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ std::move(data), jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void SetPeriodicAdvertisingEnable(int advertiser_id, bool enable,
+ StatusCallback cb) override {
+ VLOG(1) << __func__ << " advertiser_id: " << +advertiser_id
+ << " ,enable: " << enable;
+
+ do_in_bta_thread(
+ FROM_HERE,
+ Bind(&BleAdvertisingManager::SetPeriodicAdvertisingEnable,
+ base::Unretained(BleAdvertisingManager::Get()), advertiser_id,
+ enable, jni_thread_wrapper(FROM_HERE, cb)));
+ }
+};
+
+BleAdvertiserInterface* btLeAdvertiserInstance = nullptr;
+
+} // namespace
+
+BleAdvertiserInterface* get_ble_advertiser_instance() {
+ if (btLeAdvertiserInstance == nullptr)
+ btLeAdvertiserInstance = new BleAdvertiserInterfaceImpl();
+
+ return btLeAdvertiserInstance;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_ble_scanner.cc b/mtkbt/code/bt/btif/src/btif_ble_scanner.cc
new file mode 100755
index 0000000..162935b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_ble_scanner.cc
@@ -0,0 +1,458 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_scanner"
+
+#include <base/bind.h>
+#include <base/threading/thread.h>
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unordered_set>
+#include "device/include/controller.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include <hardware/bt_gatt.h>
+
+#include "advertise_data_parser.h"
+#include "bta_api.h"
+#include "bta_closure_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+#include "vendor_api.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+using RegisterCallback = BleScannerInterface::RegisterCallback;
+
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+#define SCAN_CBACK_IN_JNI(P_CBACK, ...) \
+ do { \
+ if (bt_gatt_callbacks && bt_gatt_callbacks->scanner->P_CBACK) { \
+ BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \
+ do_in_jni_thread( \
+ Bind(bt_gatt_callbacks->scanner->P_CBACK, __VA_ARGS__)); \
+ } else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ } while (0)
+
+namespace std {
+template <>
+struct hash<bt_bdaddr_t> {
+ size_t operator()(const bt_bdaddr_t& f) const {
+ return f.address[0] + f.address[1] + f.address[2] + f.address[3] +
+ f.address[4] + f.address[5];
+ }
+};
+
+template <>
+struct equal_to<bt_bdaddr_t> {
+ size_t operator()(const bt_bdaddr_t& x, const bt_bdaddr_t& y) const {
+ return memcmp(x.address, y.address, BD_ADDR_LEN);
+ }
+};
+}
+
+namespace {
+
+// all access to this variable should be done on the jni thread
+std::unordered_set<bt_bdaddr_t> p_dev_cb;
+
+void btif_gattc_add_remote_bdaddr(BD_ADDR p_bda, uint8_t addr_type) {
+ bt_bdaddr_t bd_addr;
+ memcpy(bd_addr.address, p_bda, BD_ADDR_LEN);
+ p_dev_cb.insert(bd_addr);
+}
+
+bool btif_gattc_find_bdaddr(BD_ADDR p_bda) {
+ bt_bdaddr_t bd_addr;
+ memcpy(bd_addr.address, p_bda, BD_ADDR_LEN);
+ return (p_dev_cb.count(bd_addr) != 0);
+}
+
+void btif_gattc_init_dev_cb(void) { p_dev_cb.clear(); }
+
+void btif_gatts_upstreams_evt(uint16_t event, char* p_param) {
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+ tBTA_GATTC* p_data = (tBTA_GATTC*)p_param;
+ switch (event) {
+ case BTA_GATTC_DEREG_EVT:
+ break;
+
+ case BTA_GATTC_SEARCH_CMPL_EVT: {
+ HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb,
+ p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
+ break;
+ }
+
+ default:
+ LOG_DEBUG(LOG_TAG, "%s: Unhandled event (%d)", __func__, event);
+ break;
+ }
+}
+
+void bta_gatts_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+ bt_status_t status =
+ btif_transfer_context(btif_gatts_upstreams_evt, (uint16_t)event,
+ (char*)p_data, sizeof(tBTA_GATTC), NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+void bta_batch_scan_threshold_cb(tBTM_BLE_REF_VALUE ref_value) {
+ SCAN_CBACK_IN_JNI(batchscan_threshold_cb, ref_value);
+}
+
+void bta_batch_scan_reports_cb(int client_id, tBTA_STATUS status,
+ uint8_t report_format, uint8_t num_records,
+ std::vector<uint8_t> data) {
+ SCAN_CBACK_IN_JNI(batchscan_reports_cb, client_id, status, report_format,
+ num_records, std::move(data));
+}
+
+void bta_scan_results_cb_impl(bt_bdaddr_t bd_addr, tBT_DEVICE_TYPE device_type,
+ int8_t rssi, uint8_t addr_type,
+ uint16_t ble_evt_type, uint8_t ble_primary_phy,
+ uint8_t ble_secondary_phy,
+ uint8_t ble_advertising_sid, int8_t ble_tx_power,
+ uint16_t ble_periodic_adv_int,
+ vector<uint8_t> value) {
+ uint8_t remote_name_len;
+ bt_device_type_t dev_type;
+ bt_property_t properties;
+
+ const uint8_t* p_eir_remote_name = AdvertiseDataParser::GetFieldByType(
+ value, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+
+ if (p_eir_remote_name == NULL) {
+ p_eir_remote_name = AdvertiseDataParser::GetFieldByType(
+ value, BT_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ }
+
+ if ((addr_type != BLE_ADDR_RANDOM) || (p_eir_remote_name)) {
+ if (!btif_gattc_find_bdaddr(bd_addr.address)) {
+ btif_gattc_add_remote_bdaddr(bd_addr.address, addr_type);
+
+ if (p_eir_remote_name) {
+ if (remote_name_len > BD_NAME_LEN + 1 ||
+ (remote_name_len == BD_NAME_LEN + 1 &&
+ p_eir_remote_name[BD_NAME_LEN] != '\0')) {
+ LOG_INFO(LOG_TAG,
+ "%s dropping invalid packet - device name too long: %d",
+ __func__, remote_name_len);
+ return;
+ }
+
+ bt_bdname_t bdname;
+ memcpy(bdname.name, p_eir_remote_name, remote_name_len);
+ if (remote_name_len < BD_NAME_LEN + 1)
+ bdname.name[remote_name_len] = '\0';
+
+ LOG_VERBOSE(LOG_TAG, "%s BLE device name=%s len=%d dev_type=%d",
+ __func__, bdname.name, remote_name_len, device_type);
+ btif_dm_update_ble_remote_properties(bd_addr.address, bdname.name,
+ device_type);
+ }
+ }
+ }
+
+ dev_type = (bt_device_type_t)device_type;
+ BTIF_STORAGE_FILL_PROPERTY(&properties, BT_PROPERTY_TYPE_OF_DEVICE,
+ sizeof(dev_type), &dev_type);
+ btif_storage_set_remote_device_property(&(bd_addr), &properties);
+
+ btif_storage_set_remote_addr_type(&bd_addr, addr_type);
+ HAL_CBACK(bt_gatt_callbacks, scanner->scan_result_cb, ble_evt_type, addr_type,
+ &bd_addr, ble_primary_phy, ble_secondary_phy, ble_advertising_sid,
+ ble_tx_power, rssi, ble_periodic_adv_int, std::move(value));
+}
+
+void bta_scan_results_cb(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data) {
+ uint8_t len;
+
+ if (event == BTA_DM_INQ_CMPL_EVT) {
+ BTIF_TRACE_DEBUG("%s BLE observe complete. Num Resp %d", __func__,
+ p_data->inq_cmpl.num_resps);
+ return;
+ }
+
+ if (event != BTA_DM_INQ_RES_EVT) {
+ BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ return;
+ }
+
+ vector<uint8_t> value;
+ if (p_data->inq_res.p_eir) {
+ value.insert(value.begin(), p_data->inq_res.p_eir,
+ p_data->inq_res.p_eir + p_data->inq_res.eir_len);
+
+ if (AdvertiseDataParser::GetFieldByType(
+ value, BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &len)) {
+ p_data->inq_res.remt_name_not_required = true;
+ }
+ }
+
+ tBTA_DM_INQ_RES* r = &p_data->inq_res;
+ bt_bdaddr_t bdaddr;
+ bdcpy(bdaddr.address, r->bd_addr);
+ do_in_jni_thread(Bind(bta_scan_results_cb_impl, bdaddr, r->device_type,
+ r->rssi, r->ble_addr_type, r->ble_evt_type,
+ r->ble_primary_phy, r->ble_secondary_phy,
+ r->ble_advertising_sid, r->ble_tx_power,
+ r->ble_periodic_adv_int, std::move(value)));
+}
+
+void bta_track_adv_event_cb(tBTM_BLE_TRACK_ADV_DATA* p_track_adv_data) {
+ btgatt_track_adv_info_t* btif_scan_track_cb = new btgatt_track_adv_info_t;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ btif_gatt_move_track_adv_data(btif_scan_track_cb,
+ (btgatt_track_adv_info_t*)p_track_adv_data);
+
+ SCAN_CBACK_IN_JNI(track_adv_event_cb, Owned(btif_scan_track_cb));
+}
+
+class BleScannerInterfaceImpl : public BleScannerInterface {
+ ~BleScannerInterfaceImpl(){};
+
+ void RegisterScanner(RegisterCallback cb) override {
+ do_in_bta_thread(FROM_HERE,
+ Bind(
+ [](RegisterCallback cb) {
+ BTA_GATTC_AppRegister(
+ bta_gatts_cback,
+ jni_thread_wrapper(FROM_HERE, std::move(cb)));
+ },
+ std::move(cb)));
+ }
+
+ void Unregister(int scanner_id) override {
+ do_in_bta_thread(FROM_HERE, Bind(&BTA_GATTC_AppDeregister, scanner_id));
+ }
+
+ void Scan(bool start) override {
+ do_in_jni_thread(Bind(
+ [](bool start) {
+ if (!start) {
+ do_in_bta_thread(FROM_HERE,
+ Bind(&BTA_DmBleObserve, false, 0, nullptr));
+ return;
+ }
+
+ btif_gattc_init_dev_cb();
+ do_in_bta_thread(FROM_HERE,
+ Bind(&BTA_DmBleObserve, true, 0,
+ (tBTA_DM_SEARCH_CBACK*)bta_scan_results_cb));
+ },
+ start));
+ }
+
+ void ScanFilterParamSetup(
+ uint8_t client_if, uint8_t action, uint8_t filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
+ FilterParamSetupCallback cb) override {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (filt_param && filt_param->dely_mode == 1) {
+ do_in_bta_thread(
+ FROM_HERE, base::Bind(BTM_BleTrackAdvertiser, bta_track_adv_event_cb,
+ client_if));
+ }
+
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&BTM_BleAdvFilterParamSetup, action, filt_index,
+ base::Passed(&filt_param),
+ jni_thread_wrapper(FROM_HERE, std::move(cb))));
+ }
+
+ void ScanFilterAddRemove(int action, int filt_type, int filt_index,
+ int company_id, int company_id_mask,
+ const bt_uuid_t* p_uuid,
+ const bt_uuid_t* p_uuid_mask,
+ const bt_bdaddr_t* bd_addr, char addr_type,
+ vector<uint8_t> data, vector<uint8_t> mask,
+ FilterConfigCallback cb) override {
+ BTIF_TRACE_DEBUG("%s, %d, %d", __func__, action, filt_type);
+
+ /* If data is passed, both mask and data have to be the same length */
+ if (data.size() != mask.size() && data.size() != 0 && mask.size() != 0)
+ return;
+
+ switch (filt_type) {
+ case BTM_BLE_PF_ADDR_FILTER: {
+ tBLE_BD_ADDR target_addr;
+ bdcpy(target_addr.bda, bd_addr->address);
+ target_addr.type = addr_type;
+
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_addr_filter, action, filt_index,
+ std::move(target_addr),
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ case BTM_BLE_PF_SRVC_DATA:
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&BTM_LE_PF_srvc_data, action, filt_index));
+ return;
+
+ case BTM_BLE_PF_SRVC_UUID:
+ case BTM_BLE_PF_SRVC_SOL_UUID: {
+ tBT_UUID bt_uuid;
+ btif_to_bta_uuid(&bt_uuid, p_uuid);
+
+ if (p_uuid_mask == NULL) {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type,
+ bt_uuid, BTM_BLE_PF_LOGIC_AND, nullptr,
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ tBTM_BLE_PF_COND_MASK* mask = new tBTM_BLE_PF_COND_MASK;
+ btif_to_bta_uuid_mask(mask, p_uuid_mask, p_uuid);
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_uuid_filter, action, filt_index, filt_type,
+ bt_uuid, BTM_BLE_PF_LOGIC_AND, base::Owned(mask),
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ case BTM_BLE_PF_LOCAL_NAME: {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_local_name, action, filt_index,
+ std::move(data),
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ case BTM_BLE_PF_MANU_DATA: {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_manu_data, action, filt_index, company_id,
+ company_id_mask, std::move(data), std::move(mask),
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ case BTM_BLE_PF_SRVC_DATA_PATTERN: {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_LE_PF_srvc_data_pattern, action, filt_index,
+ std::move(data), std::move(mask),
+ jni_thread_wrapper(FROM_HERE, Bind(cb, filt_type))));
+ return;
+ }
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Unknown filter type (%d)!", __func__, action);
+ return;
+ }
+ }
+
+ void ScanFilterClear(int filter_index, FilterConfigCallback cb) override {
+ BTIF_TRACE_DEBUG("%s: filter_index: %d", __func__, filter_index);
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&BTM_LE_PF_clear, filter_index,
+ jni_thread_wrapper(
+ FROM_HERE, Bind(cb, BTM_BLE_PF_TYPE_ALL))));
+ }
+
+ void ScanFilterEnable(bool enable, EnableCallback cb) override {
+ BTIF_TRACE_DEBUG("%s: enable: %d", __func__, enable);
+
+ uint8_t action = enable ? 1 : 0;
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&BTM_BleEnableDisableFilterFeature, action,
+ jni_thread_wrapper(FROM_HERE, std::move(cb))));
+ }
+
+ void SetScanParameters(int scan_interval, int scan_window,
+ Callback cb) override {
+ do_in_bta_thread(
+ FROM_HERE, base::Bind(&BTM_BleSetScanParams, scan_interval, scan_window,
+ BTM_BLE_SCAN_MODE_ACTI,
+ jni_thread_wrapper(FROM_HERE, std::move(cb))));
+ }
+
+ void BatchscanConfigStorage(int client_if, int batch_scan_full_max,
+ int batch_scan_trunc_max,
+ int batch_scan_notify_threshold,
+ Callback cb) override {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_BleSetStorageConfig, (uint8_t)batch_scan_full_max,
+ (uint8_t)batch_scan_trunc_max,
+ (uint8_t)batch_scan_notify_threshold,
+ jni_thread_wrapper(FROM_HERE, cb),
+ bta_batch_scan_threshold_cb, (tBTM_BLE_REF_VALUE)client_if));
+ }
+
+ void BatchscanEnable(int scan_mode, int scan_interval, int scan_window,
+ int addr_type, int discard_rule, Callback cb) override {
+ do_in_bta_thread(
+ FROM_HERE, base::Bind(&BTM_BleEnableBatchScan, scan_mode, scan_interval,
+ scan_window, discard_rule, addr_type,
+ jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void BatchscanDisable(Callback cb) override {
+ do_in_bta_thread(FROM_HERE, base::Bind(&BTM_BleDisableBatchScan,
+ jni_thread_wrapper(FROM_HERE, cb)));
+ }
+
+ void BatchscanReadReports(int client_if, int scan_mode) override {
+ do_in_bta_thread(FROM_HERE,
+ base::Bind(&BTM_BleReadScanReports, (uint8_t)scan_mode,
+ Bind(bta_batch_scan_reports_cb, client_if)));
+ }
+
+ void StartSync(uint8_t sid, bt_bdaddr_t address, uint16_t skip,
+ uint16_t timeout, StartSyncCb start_cb, SyncReportCb report_cb,
+ SyncLostCb lost_cb) override {}
+
+ void StopSync(uint16_t handle) override {}
+};
+
+BleScannerInterface* btLeScannerInstance = nullptr;
+
+} // namespace
+
+BleScannerInterface* get_ble_scanner_instance() {
+ if (btLeScannerInstance == nullptr)
+ btLeScannerInstance = new BleScannerInterfaceImpl();
+
+ return btLeScannerInstance;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_config.cc b/mtkbt/code/bt/btif/src/btif_config.cc
new file mode 100755
index 0000000..3b3dc4f
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_config.cc
@@ -0,0 +1,555 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_config"
+
+#include "btif_config.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <string>
+
+#include <mutex>
+
+#include "bt_types.h"
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/module.h"
+#include "btif_api.h"
+#include "btif_common.h"
+#include "btif_config_transcode.h"
+#include "btif_util.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+#define BT_CONFIG_SOURCE_TAG_NUM 1010001
+
+#define INFO_SECTION "Info"
+#define FILE_TIMESTAMP "TimeCreated"
+#define FILE_SOURCE "FileSource"
+#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
+static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
+
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+static const char* CONFIG_FILE_PATH = "bt_config.conf";
+static const char* CONFIG_BACKUP_PATH = "bt_config.bak";
+static const char* CONFIG_LEGACY_FILE_PATH = "bt_config.xml";
+#else // !defined(OS_GENERIC)
+static const char* CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
+static const char* CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
+static const char* CONFIG_LEGACY_FILE_PATH =
+ "/data/misc/bluedroid/bt_config.xml";
+#endif // defined(OS_GENERIC)
+static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
+
+static void timer_config_save_cb(void* data);
+static void btif_config_write(uint16_t event, char* p_param);
+static bool is_factory_reset(void);
+static void delete_config_files(void);
+static void btif_config_remove_unpaired(config_t* config);
+static void btif_config_remove_restricted(config_t* config);
+static config_t* btif_config_open(const char* filename);
+
+static enum ConfigSource {
+ NOT_LOADED,
+ ORIGINAL,
+ BACKUP,
+ LEGACY,
+ NEW_FILE,
+ RESET
+} btif_config_source = NOT_LOADED;
+
+static int btif_config_devices_loaded = -1;
+static char btif_config_time_created[TIME_STRING_LENGTH];
+
+// TODO(zachoverflow): Move these two functions out, because they are too
+// specific for this file
+// {grumpy-cat/no, monty-python/you-make-me-sad}
+bool btif_get_device_type(const BD_ADDR bd_addr, int* p_device_type) {
+ if (p_device_type == NULL) return false;
+
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, bd_addr);
+
+ bdstr_t bd_addr_str;
+ bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
+
+ if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) return false;
+
+ LOG_DEBUG(LOG_TAG, "%s: Device [%s] type %d", __func__, bd_addr_str,
+ *p_device_type);
+ return true;
+}
+
+bool btif_get_address_type(const BD_ADDR bd_addr, int* p_addr_type) {
+ if (p_addr_type == NULL) return false;
+
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, bd_addr);
+
+ bdstr_t bd_addr_str;
+ bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
+
+ if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type)) return false;
+
+ LOG_DEBUG(LOG_TAG, "%s: Device [%s] address type %d", __func__, bd_addr_str,
+ *p_addr_type);
+ return true;
+}
+
+static std::mutex config_lock; // protects operations on |config|.
+static config_t* config;
+static alarm_t* config_timer;
+
+// Module lifecycle functions
+
+static future_t* init(void) {
+ std::unique_lock<std::mutex> lock(config_lock);
+
+ if (is_factory_reset()) delete_config_files();
+
+ std::string file_source;
+
+ config = btif_config_open(CONFIG_FILE_PATH);
+ btif_config_source = ORIGINAL;
+ if (!config) {
+ LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
+ __func__, CONFIG_FILE_PATH);
+ config = btif_config_open(CONFIG_BACKUP_PATH);
+ btif_config_source = BACKUP;
+ file_source = "Backup";
+ }
+ if (!config) {
+ LOG_WARN(LOG_TAG,
+ "%s unable to load backup; attempting to transcode legacy file.",
+ __func__);
+ config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH);
+ btif_config_source = LEGACY;
+ file_source = "Legacy";
+ }
+ if (!config) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to transcode legacy file; creating empty config.",
+ __func__);
+ config = config_new_empty();
+ btif_config_source = NEW_FILE;
+ file_source = "Empty";
+ }
+
+ if (!file_source.empty())
+ config_set_string(config, INFO_SECTION, FILE_SOURCE, file_source.c_str());
+
+ if (!config) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
+ goto error;
+ }
+
+ btif_config_remove_unpaired(config);
+
+ // Cleanup temporary pairings if we have left guest mode
+ if (!is_restricted_mode()) btif_config_remove_restricted(config);
+
+ // Read or set config file creation timestamp
+ const char* time_str;
+ time_str = config_get_string(config, INFO_SECTION, FILE_TIMESTAMP, NULL);
+ if (time_str != NULL) {
+ strlcpy(btif_config_time_created, time_str, TIME_STRING_LENGTH);
+ } else {
+ time_t current_time = time(NULL);
+ struct tm* time_created = localtime(&current_time);
+ strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT,
+ time_created);
+ config_set_string(config, INFO_SECTION, FILE_TIMESTAMP,
+ btif_config_time_created);
+ }
+
+ // TODO(sharvil): use a non-wake alarm for this once we have
+ // API support for it. There's no need to wake the system to
+ // write back to disk.
+ config_timer = alarm_new("btif.config");
+ if (!config_timer) {
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
+ goto error;
+ }
+
+ LOG_EVENT_INT(BT_CONFIG_SOURCE_TAG_NUM, btif_config_source);
+
+ return future_new_immediate(FUTURE_SUCCESS);
+
+error:
+ alarm_free(config_timer);
+ config_free(config);
+ config_timer = NULL;
+ config = NULL;
+ btif_config_source = NOT_LOADED;
+ return future_new_immediate(FUTURE_FAIL);
+}
+
+static config_t* btif_config_open(const char* filename) {
+ config_t* config = config_new(filename);
+ if (!config) return NULL;
+
+ if (!config_has_section(config, "Adapter")) {
+ LOG_ERROR(LOG_TAG, "Config is missing adapter section");
+ config_free(config);
+ return NULL;
+ }
+
+ return config;
+}
+
+static future_t* shut_down(void) {
+ btif_config_flush();
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* clean_up(void) {
+ btif_config_flush();
+
+ alarm_free(config_timer);
+ config_free(config);
+ config_timer = NULL;
+ config = NULL;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t btif_config_module = {.name = BTIF_CONFIG_MODULE,
+ .init = init,
+ .start_up = NULL,
+ .shut_down = shut_down,
+ .clean_up = clean_up};
+
+bool btif_config_has_section(const char* section) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ return config_has_section(config, section);
+}
+
+bool btif_config_exist(const char* section, const char* key) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ return config_has_key(config, section, key);
+}
+
+bool btif_config_get_int(const char* section, const char* key, int* value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+ CHECK(value != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ bool ret = config_has_key(config, section, key);
+ if (ret) *value = config_get_int(config, section, key, *value);
+
+ return ret;
+}
+
+bool btif_config_set_int(const char* section, const char* key, int value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ config_set_int(config, section, key, value);
+
+ return true;
+}
+
+bool btif_config_get_str(const char* section, const char* key, char* value,
+ int* size_bytes) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+ CHECK(value != NULL);
+ CHECK(size_bytes != NULL);
+
+ {
+ std::unique_lock<std::mutex> lock(config_lock);
+ const char* stored_value = config_get_string(config, section, key, NULL);
+ if (!stored_value) return false;
+ strlcpy(value, stored_value, *size_bytes);
+ }
+
+ *size_bytes = strlen(value) + 1;
+ return true;
+}
+
+bool btif_config_set_str(const char* section, const char* key,
+ const char* value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+ CHECK(value != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ config_set_string(config, section, key, value);
+ return true;
+}
+
+bool btif_config_get_bin(const char* section, const char* key, uint8_t* value,
+ size_t* length) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+ CHECK(value != NULL);
+ CHECK(length != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ const char* value_str = config_get_string(config, section, key, NULL);
+
+ if (!value_str) return false;
+
+ size_t value_len = strlen(value_str);
+ if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
+
+ for (size_t i = 0; i < value_len; ++i)
+ if (!isxdigit(value_str[i])) return false;
+
+ for (*length = 0; *value_str; value_str += 2, *length += 1)
+ sscanf(value_str, "%02hhx", &value[*length]);
+
+ return true;
+}
+
+size_t btif_config_get_bin_length(const char* section, const char* key) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ const char* value_str = config_get_string(config, section, key, NULL);
+ if (!value_str) return 0;
+
+ size_t value_len = strlen(value_str);
+ return ((value_len % 2) != 0) ? 0 : (value_len / 2);
+}
+
+bool btif_config_set_bin(const char* section, const char* key,
+ const uint8_t* value, size_t length) {
+ const char* lookup = "0123456789abcdef";
+
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ if (length > 0) CHECK(value != NULL);
+
+ char* str = (char*)osi_calloc(length * 2 + 1);
+
+ for (size_t i = 0; i < length; ++i) {
+ str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
+ str[(i * 2) + 1] = lookup[value[i] & 0x0F];
+ }
+
+ {
+ std::unique_lock<std::mutex> lock(config_lock);
+ config_set_string(config, section, key, str);
+ }
+
+ osi_free(str);
+ return true;
+}
+
+const btif_config_section_iter_t* btif_config_section_begin(void) {
+ CHECK(config != NULL);
+ return (const btif_config_section_iter_t*)config_section_begin(config);
+}
+
+const btif_config_section_iter_t* btif_config_section_end(void) {
+ CHECK(config != NULL);
+ return (const btif_config_section_iter_t*)config_section_end(config);
+}
+
+const btif_config_section_iter_t* btif_config_section_next(
+ const btif_config_section_iter_t* section) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ return (const btif_config_section_iter_t*)config_section_next(
+ (const config_section_node_t*)section);
+}
+
+const char* btif_config_section_name(
+ const btif_config_section_iter_t* section) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ return config_section_name((const config_section_node_t*)section);
+}
+
+bool btif_config_remove(const char* section, const char* key) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ return config_remove_key(config, section, key);
+}
+
+void btif_config_save(void) {
+ CHECK(config != NULL);
+ CHECK(config_timer != NULL);
+
+ alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL);
+}
+
+void btif_config_flush(void) {
+ CHECK(config != NULL);
+ CHECK(config_timer != NULL);
+
+ alarm_cancel(config_timer);
+ btif_config_write(0, NULL);
+}
+
+bool btif_config_clear(void) {
+ CHECK(config != NULL);
+ CHECK(config_timer != NULL);
+
+ alarm_cancel(config_timer);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ config_free(config);
+
+ config = config_new_empty();
+ if (config == NULL) return false;
+
+ bool ret = config_save(config, CONFIG_FILE_PATH);
+ btif_config_source = RESET;
+ return ret;
+}
+
+static void timer_config_save_cb(UNUSED_ATTR void* data) {
+ // Moving file I/O to btif context instead of timer callback because
+ // it usually takes a lot of time to be completed, introducing
+ // delays during A2DP playback causing blips or choppiness.
+ btif_transfer_context(btif_config_write, 0, NULL, 0, NULL);
+}
+
+static void btif_config_write(UNUSED_ATTR uint16_t event,
+ UNUSED_ATTR char* p_param) {
+ CHECK(config != NULL);
+ CHECK(config_timer != NULL);
+
+ std::unique_lock<std::mutex> lock(config_lock);
+ rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
+ config_t* config_paired = config_new_clone(config);
+ btif_config_remove_unpaired(config_paired);
+ config_save(config_paired, CONFIG_FILE_PATH);
+ config_free(config_paired);
+}
+
+static void btif_config_remove_unpaired(config_t* conf) {
+ CHECK(conf != NULL);
+ int paired_devices = 0;
+
+ // The paired config used to carry information about
+ // discovered devices during regular inquiry scans.
+ // We remove these now and cache them in memory instead.
+ const config_section_node_t* snode = config_section_begin(conf);
+ while (snode != config_section_end(conf)) {
+ const char* section = config_section_name(snode);
+ if (string_is_bdaddr(section)) {
+ if (!config_has_key(conf, section, "LinkKey") &&
+ !config_has_key(conf, section, "LE_KEY_PENC") &&
+ !config_has_key(conf, section, "LE_KEY_PID") &&
+ !config_has_key(conf, section, "LE_KEY_PCSRK") &&
+ !config_has_key(conf, section, "LE_KEY_LENC") &&
+ !config_has_key(conf, section, "LE_KEY_LCSRK")) {
+ snode = config_section_next(snode);
+ config_remove_section(conf, section);
+ continue;
+ }
+ paired_devices++;
+ }
+ snode = config_section_next(snode);
+ }
+
+ // should only happen once, at initial load time
+ if (btif_config_devices_loaded == -1)
+ btif_config_devices_loaded = paired_devices;
+}
+
+void btif_debug_config_dump(int fd) {
+ dprintf(fd, "\nBluetooth Config:\n");
+
+ dprintf(fd, " Config Source: ");
+ switch (btif_config_source) {
+ case NOT_LOADED:
+ dprintf(fd, "Not loaded\n");
+ break;
+ case ORIGINAL:
+ dprintf(fd, "Original file\n");
+ break;
+ case BACKUP:
+ dprintf(fd, "Backup file\n");
+ break;
+ case LEGACY:
+ dprintf(fd, "Legacy file\n");
+ break;
+ case NEW_FILE:
+ dprintf(fd, "New file\n");
+ break;
+ case RESET:
+ dprintf(fd, "Reset file\n");
+ break;
+ }
+
+ dprintf(fd, " Devices loaded: %d\n", btif_config_devices_loaded);
+ dprintf(fd, " File created/tagged: %s\n", btif_config_time_created);
+ dprintf(fd, " File source: %s\n",
+ config_get_string(config, INFO_SECTION, FILE_SOURCE, "Original"));
+}
+
+static void btif_config_remove_restricted(config_t* config) {
+ CHECK(config != NULL);
+
+ const config_section_node_t* snode = config_section_begin(config);
+ while (snode != config_section_end(config)) {
+ const char* section = config_section_name(snode);
+ if (string_is_bdaddr(section) &&
+ config_has_key(config, section, "Restricted")) {
+ BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__, section);
+ config_remove_section(config, section);
+ }
+ snode = config_section_next(snode);
+ }
+}
+
+static bool is_factory_reset(void) {
+ char factory_reset[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get("persist.bluetooth.factoryreset", factory_reset, "false");
+ return strncmp(factory_reset, "true", 4) == 0;
+}
+
+static void delete_config_files(void) {
+ remove(CONFIG_FILE_PATH);
+ remove(CONFIG_BACKUP_PATH);
+ osi_property_set("persist.bluetooth.factoryreset", "false");
+}
diff --git a/mtkbt/code/bt/btif/src/btif_config_transcode.cc b/mtkbt/code/bt/btif/src/btif_config_transcode.cc
new file mode 100755
index 0000000..102a3af
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_config_transcode.cc
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_config_transcode"
+
+#include <tinyxml2.h>
+
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+
+using namespace tinyxml2;
+
+config_t* btif_config_transcode(const char* xml_filename) {
+ XMLDocument document;
+ int error = document.LoadFile(xml_filename);
+ if (error != XML_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s unable to load XML file '%s': %d", __func__,
+ xml_filename, error);
+ return NULL;
+ }
+
+ XMLElement* rootElement = document.RootElement();
+ if (!rootElement) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to find root element; assuming corrupted config file.",
+ __func__);
+ return NULL;
+ }
+
+ config_t* config = config_new_empty();
+ if (!config) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate config object.", __func__);
+ return NULL;
+ }
+
+ for (XMLElement* i = rootElement->FirstChildElement(); i != NULL;
+ i = i->NextSiblingElement())
+ for (XMLElement* j = i->FirstChildElement(); j != NULL;
+ j = j->NextSiblingElement()) {
+ const char* section = j->Attribute("Tag");
+ for (XMLElement* k = j->FirstChildElement(); k != NULL;
+ k = k->NextSiblingElement()) {
+ const char* key = k->Attribute("Tag");
+ const char* value = k->GetText();
+ if (section && key && value)
+ config_set_string(config, section, key, value);
+ }
+ }
+
+ return config;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_core.cc b/mtkbt/code/bt/btif/src/btif_core.cc
new file mode 100755
index 0000000..6077f46
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_core.cc
@@ -0,0 +1,1185 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_core.c
+ *
+ * Description: Contains core functionality related to interfacing between
+ * Bluetooth HAL and BTE core stack.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_core"
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/run_loop.h>
+#include <base/threading/thread.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <hardware/bluetooth.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "bte.h"
+#include "btif_api.h"
+#include "btif_av.h"
+#include "btif_config.h"
+#include "btif_pan.h"
+#include "btif_profile_queue.h"
+#include "btif_sock.h"
+#include "btif_storage.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "osi/include/thread.h"
+#include "stack_manager.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#ifndef BTE_DID_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_DID_CONF_FILE "bt_did.conf"
+#else // !defined(OS_GENERIC)
+#define BTE_DID_CONF_FILE "/etc/bluetooth/bt_did.conf"
+#endif // defined(OS_GENERIC)
+#endif // BTE_DID_CONF_FILE
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+
+/* These type definitions are used when passing data from the HAL to BTIF
+* context
+* in the downstream path for the adapter and remote_device property APIs */
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_type_t type;
+} btif_storage_read_t;
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_property_t prop;
+} btif_storage_write_t;
+
+typedef union {
+ btif_storage_read_t read_req;
+ btif_storage_write_t write_req;
+} btif_storage_req_t;
+
+typedef enum {
+ BTIF_CORE_STATE_DISABLED = 0,
+ BTIF_CORE_STATE_ENABLING,
+ BTIF_CORE_STATE_ENABLED,
+ BTIF_CORE_STATE_DISABLING
+} btif_core_state_t;
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+static tBTA_SERVICE_MASK btif_enabled_services = 0;
+
+/*
+* This variable should be set to 1, if the Bluedroid+BTIF libraries are to
+* function in DUT mode.
+*
+* To set this, the btif_init_bluetooth needs to be called with argument as 1
+*/
+static uint8_t btif_dut_mode = 0;
+
+static thread_t* bt_jni_workqueue_thread;
+static const char* BT_JNI_WORKQUEUE_NAME = "bt_jni_workqueue";
+static uid_set_t* uid_set = NULL;
+base::MessageLoop* message_loop_ = NULL;
+base::RunLoop* jni_run_loop = NULL;
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+static void btif_jni_associate();
+static void btif_jni_disassociate();
+
+/* sends message to btif task */
+static void btif_sendmsg(void* p_msg);
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+extern fixed_queue_t* btu_hci_msg_queue;
+
+void btif_dm_execute_service_request(uint16_t event, char* p_param);
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void);
+#endif
+
+/*******************************************************************************
+ *
+ * Function btif_context_switched
+ *
+ * Description Callback used to execute transferred context callback
+ *
+ * p_msg : message to be executed in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void btif_context_switched(void* p_msg) {
+ BTIF_TRACE_VERBOSE("btif_context_switched");
+
+ tBTIF_CONTEXT_SWITCH_CBACK* p = (tBTIF_CONTEXT_SWITCH_CBACK*)p_msg;
+
+ /* each callback knows how to parse the data */
+ if (p->p_cb) p->p_cb(p->event, p->p_param);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_transfer_context
+ *
+ * Description This function switches context to btif task
+ *
+ * p_cback : callback used to process message in btif context
+ * event : event id of message
+ * p_params : parameter area passed to callback (copied)
+ * param_len : length of parameter area
+ * p_copy_cback : If set this function will be invoked for deep
+ * copy
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+ char* p_params, int param_len,
+ tBTIF_COPY_CBACK* p_copy_cback) {
+ tBTIF_CONTEXT_SWITCH_CBACK* p_msg = (tBTIF_CONTEXT_SWITCH_CBACK*)osi_malloc(
+ sizeof(tBTIF_CONTEXT_SWITCH_CBACK) + param_len);
+
+ BTIF_TRACE_VERBOSE("btif_transfer_context event %d, len %d", event,
+ param_len);
+
+ /* allocate and send message that will be executed in btif context */
+ p_msg->hdr.event = BT_EVT_CONTEXT_SWITCH_EVT; /* internal event */
+ p_msg->p_cb = p_cback;
+
+ p_msg->event = event; /* callback event */
+
+ /* check if caller has provided a copy callback to do the deep copy */
+ if (p_copy_cback) {
+ p_copy_cback(event, p_msg->p_param, p_params);
+ } else if (p_params) {
+ memcpy(p_msg->p_param, p_params, param_len); /* callback parameter data */
+ }
+
+ btif_sendmsg(p_msg);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/**
+ * This function posts a task into the btif message loop, that executes it in
+ * the JNI message loop.
+ **/
+bt_status_t do_in_jni_thread(const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ if (!message_loop_ || !message_loop_->task_runner().get()) {
+ BTIF_TRACE_WARNING("%s: Dropped message, message_loop not initialized yet!",
+ __func__);
+ return BT_STATUS_FAIL;
+ }
+
+ if (message_loop_->task_runner()->PostTask(from_here, task))
+ return BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_ERROR("%s: Post task to task runner failed!", __func__);
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t do_in_jni_thread(const base::Closure& task) {
+ return do_in_jni_thread(FROM_HERE, task);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_is_dut_mode
+ *
+ * Description checks if BTIF is currently in DUT mode
+ *
+ * Returns 1 if test mode, otherwize 0
+ *
+ ******************************************************************************/
+
+uint8_t btif_is_dut_mode(void) { return (btif_dut_mode == 1); }
+
+/*******************************************************************************
+ *
+ * Function btif_is_enabled
+ *
+ * Description checks if main adapter is fully enabled
+ *
+ * Returns 1 if fully enabled, otherwize 0
+ *
+ ******************************************************************************/
+
+int btif_is_enabled(void) {
+ return ((!btif_is_dut_mode()) &&
+ (stack_manager_get_interface()->get_stack_is_running()));
+}
+
+void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char* p_param) {
+ BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
+ btif_dm_load_ble_local_keys();
+ BTA_EnableBluetooth(bte_dm_evt);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_task
+ *
+ * Description BTIF task handler managing all messages being passed
+ * Bluetooth HAL and BTA.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bt_jni_msg_ready(void* context) {
+ BT_HDR* p_msg = (BT_HDR*)context;
+
+ BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event);
+
+ switch (p_msg->event) {
+ case BT_EVT_CONTEXT_SWITCH_EVT:
+ btif_context_switched(p_msg);
+ break;
+ default:
+ BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
+ break;
+ }
+ osi_free(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_sendmsg
+ *
+ * Description Sends msg to BTIF task
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_sendmsg(void* p_msg) {
+ do_in_jni_thread(base::Bind(&bt_jni_msg_ready, p_msg));
+}
+
+void btif_thread_post(thread_fn func, void* context) {
+ do_in_jni_thread(base::Bind(func, context));
+}
+
+void run_message_loop(UNUSED_ATTR void* context) {
+ // TODO(jpawlowski): exit_manager should be defined in main(), but there is no
+ // main method.
+ // It is therefore defined in bt_jni_workqueue_thread, and will be deleted
+ // when we free it.
+ base::AtExitManager exit_manager;
+
+ message_loop_ = new base::MessageLoop(base::MessageLoop::Type::TYPE_DEFAULT);
+
+ // Associate this workqueue thread with JNI.
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ base::Bind(&btif_jni_associate));
+
+ jni_run_loop = new base::RunLoop();
+ jni_run_loop->Run();
+
+ delete message_loop_;
+ message_loop_ = NULL;
+
+ delete jni_run_loop;
+ jni_run_loop = NULL;
+}
+/*******************************************************************************
+ *
+ * Function btif_init_bluetooth
+ *
+ * Description Creates BTIF task and prepares BT scheduler for startup
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_init_bluetooth() {
+ bte_main_boot_entry();
+
+ bt_jni_workqueue_thread = thread_new(BT_JNI_WORKQUEUE_NAME);
+ if (bt_jni_workqueue_thread == NULL) {
+ LOG_ERROR(LOG_TAG, "%s Unable to create thread %s", __func__,
+ BT_JNI_WORKQUEUE_NAME);
+ goto error_exit;
+ }
+
+ thread_post(bt_jni_workqueue_thread, run_message_loop, nullptr);
+
+ return BT_STATUS_SUCCESS;
+
+error_exit:;
+ thread_free(bt_jni_workqueue_thread);
+
+ bt_jni_workqueue_thread = NULL;
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_enable_bluetooth_evt
+ *
+ * Description Event indicating bluetooth enable is completed
+ * Notifies HAL user with updated adapter state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_enable_bluetooth_evt(tBTA_STATUS status) {
+ BTIF_TRACE_DEBUG("%s: status %d", __func__, status);
+
+ /* Fetch the local BD ADDR */
+ bt_bdaddr_t local_bd_addr;
+ const controller_t* controller = controller_get_interface();
+ bdaddr_copy(&local_bd_addr, controller->get_address());
+
+ bdstr_t bdstr;
+ bdaddr_to_string(&local_bd_addr, bdstr, sizeof(bdstr));
+
+ char val[PROPERTY_VALUE_MAX] = "";
+ int val_size = 0;
+ if ((btif_config_get_str("Adapter", "Address", val, &val_size) == 0) ||
+ strcmp(bdstr, val) == 0) {
+ // This address is not present in the config file, save it there.
+ BTIF_TRACE_WARNING("%s: Saving the Adapter Address", __func__);
+ btif_config_set_str("Adapter", "Address", bdstr);
+ btif_config_save();
+
+ // fire HAL callback for property change
+ bt_property_t prop;
+ prop.type = BT_PROPERTY_BDADDR;
+ prop.val = (void*)&local_bd_addr;
+ prop.len = sizeof(bt_bdaddr_t);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+ &prop);
+ }
+
+ bte_main_postload_cfg();
+
+ /* callback to HAL */
+ if (status == BTA_SUCCESS) {
+ uid_set = uid_set_create();
+
+ btif_dm_init(uid_set);
+
+ /* init rfcomm & l2cap api */
+ btif_sock_init(uid_set);
+
+ /* init pan */
+ btif_pan_init();
+
+ /* load did configuration */
+ bte_load_did_conf(BTE_DID_CONF_FILE);
+
+#ifdef BTIF_DM_OOB_TEST
+ btif_dm_load_local_oob();
+#endif
+
+ future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+ } else {
+ /* cleanup rfcomm & l2cap api */
+ btif_sock_cleanup();
+
+ btif_pan_cleanup();
+
+ future_ready(stack_manager_get_hack_future(), FUTURE_FAIL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_disable_bluetooth
+ *
+ * Description Inititates shutdown of Bluetooth system.
+ * Any active links will be dropped and device entering
+ * non connectable/discoverable mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_bluetooth(void) {
+ BTIF_TRACE_DEBUG("BTIF DISABLE BLUETOOTH");
+
+ btm_ble_multi_adv_cleanup();
+ // TODO(jpawlowski): this should do whole BTA_VendorCleanup(), but it would
+ // kill the stack now.
+
+ btif_dm_on_disable();
+ /* cleanup rfcomm & l2cap api */
+ btif_sock_cleanup();
+ btif_pan_cleanup();
+ BTA_DisableBluetooth();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_disable_bluetooth_evt
+ *
+ * Description Event notifying BT disable is now complete.
+ * Terminates main stack tasks and notifies HAL
+ * user with updated BT state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_disable_bluetooth_evt(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bte_main_disable();
+
+ /* callback to HAL */
+ future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_cleanup_bluetooth
+ *
+ * Description Cleanup BTIF state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_cleanup_bluetooth(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ BTA_VendorCleanup();
+
+ btif_dm_cleanup();
+ btif_jni_disassociate();
+ btif_queue_release();
+
+ if (jni_run_loop && message_loop_) {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ jni_run_loop->QuitClosure());
+ }
+
+ thread_free(bt_jni_workqueue_thread);
+ bt_jni_workqueue_thread = NULL;
+
+ bte_main_cleanup();
+
+ btif_dut_mode = 0;
+
+ BTIF_TRACE_DEBUG("%s done", __func__);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dut_mode_cback
+ *
+ * Description Callback invoked on completion of vendor specific test mode
+ * command
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void btif_dut_mode_cback(UNUSED_ATTR tBTM_VSC_CMPL* p) {
+ /* For now nothing to be done. */
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dut_mode_configure
+ *
+ * Description Configure Test Mode - 'enable' to 1 puts the device in test
+ * mode and 0 exits test mode
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_configure(uint8_t enable) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (!stack_manager_get_interface()->get_stack_is_running()) {
+ BTIF_TRACE_ERROR("btif_dut_mode_configure : Bluetooth not enabled");
+ return BT_STATUS_NOT_READY;
+ }
+
+ btif_dut_mode = enable;
+ if (enable == 1) {
+ BTA_EnableTestMode();
+ } else {
+ BTA_DisableTestMode();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dut_mode_send
+ *
+ * Description Sends a HCI Vendor specific command to the controller
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
+ /* TODO: Check that opcode is a vendor command group */
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (!btif_is_dut_mode()) {
+ BTIF_TRACE_ERROR("Bluedroid HAL needs to be init with test_mode set to 1.");
+ return BT_STATUS_FAIL;
+ }
+ BTM_VendorSpecificCommand(opcode, len, buf, btif_dut_mode_cback);
+ return BT_STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ *
+ * btif api adapter property functions
+ *
+ ****************************************************************************/
+
+static bt_status_t btif_in_get_adapter_properties(void) {
+ bt_property_t properties[6];
+ uint32_t num_props = 0;
+
+ bt_bdaddr_t addr;
+ bt_bdname_t name;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_bdaddr_t bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ bt_status_t status;
+
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDADDR,
+ sizeof(addr), &addr);
+ status = btif_storage_get_adapter_property(&properties[num_props]);
+ // Add BT_PROPERTY_BDADDR property into list only when successful.
+ // Otherwise, skip this property entry.
+ if (status == BT_STATUS_SUCCESS) {
+ num_props++;
+ }
+
+ /* BD_NAME */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+ BT_PROPERTY_ADAPTER_SCAN_MODE, sizeof(mode),
+ &mode);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+ BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ sizeof(disc_timeout), &disc_timeout);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props],
+ BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ sizeof(bonded_devices), bonded_devices);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(local_uuids), local_uuids);
+ btif_storage_get_adapter_property(&properties[num_props]);
+ num_props++;
+
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, num_props,
+ properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_in_get_remote_device_properties(bt_bdaddr_t* bd_addr) {
+ bt_property_t remote_properties[8];
+ uint32_t num_props = 0;
+
+ bt_bdname_t name, alias;
+ uint32_t cod, devtype;
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME,
+ sizeof(name), &name);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+ BT_PROPERTY_REMOTE_FRIENDLY_NAME, sizeof(alias),
+ &alias);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(devtype),
+ &devtype);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS,
+ sizeof(remote_uuids), remote_uuids);
+ btif_storage_get_remote_device_property(bd_addr,
+ &remote_properties[num_props]);
+ num_props++;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+ bd_addr, num_props, remote_properties);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function execute_storage_request
+ *
+ * Description Executes adapter storage request in BTIF context
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+static void execute_storage_request(uint16_t event, char* p_param) {
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_EVENT("execute storage request event : %d", event);
+
+ switch (event) {
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE: {
+ btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+ bt_property_t* p_prop = &(p_req->write_req.prop);
+ BTIF_TRACE_EVENT("type: %d, len %d, 0x%x", p_prop->type, p_prop->len,
+ p_prop->val);
+
+ status = btif_storage_set_adapter_property(p_prop);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, p_prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ: {
+ btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+ char buf[512];
+ bt_property_t prop;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*)buf;
+ prop.len = sizeof(buf);
+ if (prop.type == BT_PROPERTY_LOCAL_LE_FEATURES) {
+ tBTM_BLE_VSC_CB cmn_vsc_cb;
+ bt_local_le_features_t local_le_features;
+
+ /* LE features are not stored in storage. Should be retrived from stack
+ */
+ BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+ local_le_features.local_privacy_enabled = BTM_BleLocalPrivacyEnabled();
+
+ prop.len = sizeof(bt_local_le_features_t);
+ if (cmn_vsc_cb.filter_support == 1)
+ local_le_features.max_adv_filter_supported = cmn_vsc_cb.max_filter;
+ else
+ local_le_features.max_adv_filter_supported = 0;
+ local_le_features.max_adv_instance = cmn_vsc_cb.adv_inst_max;
+ local_le_features.max_irk_list_size = cmn_vsc_cb.max_irk_list_sz;
+ local_le_features.rpa_offload_supported = cmn_vsc_cb.rpa_offloading;
+ local_le_features.scan_result_storage_size =
+ cmn_vsc_cb.tot_scan_results_strg;
+ local_le_features.activity_energy_info_supported =
+ cmn_vsc_cb.energy_support;
+ local_le_features.version_supported = cmn_vsc_cb.version_supported;
+ local_le_features.total_trackable_advertisers =
+ cmn_vsc_cb.total_trackable_advertisers;
+
+ local_le_features.extended_scan_support =
+ cmn_vsc_cb.extended_scan_support > 0;
+ local_le_features.debug_logging_supported =
+ cmn_vsc_cb.debug_logging_supported > 0;
+ memcpy(prop.val, &local_le_features, prop.len);
+ } else {
+ status = btif_storage_get_adapter_property(&prop);
+ }
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, &prop);
+ } break;
+
+ case BTIF_CORE_STORAGE_ADAPTER_READ_ALL: {
+ status = btif_in_get_adapter_properties();
+ } break;
+
+ case BTIF_CORE_STORAGE_NOTIFY_STATUS: {
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 0, NULL);
+ } break;
+
+ default:
+ BTIF_TRACE_ERROR("%s invalid event id (%d)", __func__, event);
+ break;
+ }
+}
+
+static void execute_storage_remote_request(uint16_t event, char* p_param) {
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_property_t prop;
+
+ BTIF_TRACE_EVENT("execute storage remote request event : %d", event);
+
+ switch (event) {
+ case BTIF_CORE_STORAGE_REMOTE_READ: {
+ char buf[1024];
+ btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+ prop.type = p_req->read_req.type;
+ prop.val = (void*)buf;
+ prop.len = sizeof(buf);
+
+ status = btif_storage_get_remote_device_property(
+ &(p_req->read_req.bd_addr), &prop);
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status,
+ &(p_req->read_req.bd_addr), 1, &prop);
+ } break;
+ case BTIF_CORE_STORAGE_REMOTE_WRITE: {
+ btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+ status = btif_storage_set_remote_device_property(
+ &(p_req->write_req.bd_addr), &(p_req->write_req.prop));
+ } break;
+ case BTIF_CORE_STORAGE_REMOTE_READ_ALL: {
+ btif_storage_req_t* p_req = (btif_storage_req_t*)p_param;
+ btif_in_get_remote_device_properties(&p_req->read_req.bd_addr);
+ } break;
+ }
+}
+
+void btif_adapter_properties_evt(bt_status_t status, uint32_t num_props,
+ bt_property_t* p_props) {
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, num_props, p_props);
+}
+void btif_remote_properties_evt(bt_status_t status, bt_bdaddr_t* remote_addr,
+ uint32_t num_props, bt_property_t* p_props) {
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, remote_addr,
+ num_props, p_props);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_in_storage_request_copy_cb
+ *
+ * Description Switch context callback function to perform the deep copy for
+ * both the adapter and remote_device property API
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+static void btif_in_storage_request_copy_cb(uint16_t event, char* p_new_buf,
+ char* p_old_buf) {
+ btif_storage_req_t* new_req = (btif_storage_req_t*)p_new_buf;
+ btif_storage_req_t* old_req = (btif_storage_req_t*)p_old_buf;
+
+ BTIF_TRACE_EVENT("%s", __func__);
+ switch (event) {
+ case BTIF_CORE_STORAGE_REMOTE_WRITE:
+ case BTIF_CORE_STORAGE_ADAPTER_WRITE: {
+ bdcpy(new_req->write_req.bd_addr.address,
+ old_req->write_req.bd_addr.address);
+ /* Copy the member variables one at a time */
+ new_req->write_req.prop.type = old_req->write_req.prop.type;
+ new_req->write_req.prop.len = old_req->write_req.prop.len;
+
+ new_req->write_req.prop.val =
+ (uint8_t*)(p_new_buf + sizeof(btif_storage_req_t));
+ memcpy(new_req->write_req.prop.val, old_req->write_req.prop.val,
+ old_req->write_req.prop.len);
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_adapter_properties
+ *
+ * Description Fetch all available properties (local & remote)
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_get_adapter_properties(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ_ALL, NULL, 0,
+ NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_adapter_property
+ *
+ * Description Fetches property value from local cache
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_get_adapter_property(bt_property_type_t type) {
+ btif_storage_req_t req;
+
+ BTIF_TRACE_EVENT("%s %d", __func__, type);
+
+ /* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */
+ if (!btif_is_enabled() && (type != BT_PROPERTY_BDADDR) &&
+ (type != BT_PROPERTY_BDNAME))
+ return BT_STATUS_NOT_READY;
+
+ memset(&(req.read_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+
+ return btif_transfer_context(execute_storage_request,
+ BTIF_CORE_STORAGE_ADAPTER_READ, (char*)&req,
+ sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_set_adapter_property
+ *
+ * Description Updates core stack with property value and stores it in
+ * local cache
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_set_adapter_property(const bt_property_t* property) {
+ btif_storage_req_t req;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ int storage_req_id = BTIF_CORE_STORAGE_NOTIFY_STATUS; /* default */
+ char bd_name[BTM_MAX_LOC_BD_NAME_LEN + 1];
+ uint16_t name_len = 0;
+
+ BTIF_TRACE_EVENT("btif_set_adapter_property type: %d, len %d, 0x%x",
+ property->type, property->len, property->val);
+
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ switch (property->type) {
+ case BT_PROPERTY_BDNAME: {
+ name_len = property->len > BTM_MAX_LOC_BD_NAME_LEN
+ ? BTM_MAX_LOC_BD_NAME_LEN
+ : property->len;
+ memcpy(bd_name, property->val, name_len);
+ bd_name[name_len] = '\0';
+
+ BTIF_TRACE_EVENT("set property name : %s", (char*)bd_name);
+
+ BTA_DmSetDeviceName((char*)bd_name);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ } break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE: {
+ bt_scan_mode_t mode = *(bt_scan_mode_t*)property->val;
+ tBTA_DM_DISC disc_mode;
+ tBTA_DM_CONN conn_mode;
+
+ switch (mode) {
+ case BT_SCAN_MODE_NONE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_NON_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE:
+ disc_mode = BTA_DM_NON_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ case BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ disc_mode = BTA_DM_GENERAL_DISC;
+ conn_mode = BTA_DM_CONN;
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("invalid scan mode (0x%x)", mode);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ BTIF_TRACE_EVENT("set property scan mode : %x", mode);
+
+ BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE);
+
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ } break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: {
+ /* Nothing to do beside store the value in NV. Java
+ will change the SCAN_MODE property after setting timeout,
+ if required */
+ storage_req_id = BTIF_CORE_STORAGE_ADAPTER_WRITE;
+ } break;
+ case BT_PROPERTY_BDADDR:
+ case BT_PROPERTY_UUIDS:
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ /* no write support through HAL, these properties are only populated from
+ * BTA events */
+ status = BT_STATUS_FAIL;
+ break;
+ default:
+ BTIF_TRACE_ERROR("btif_get_adapter_property : invalid type %d",
+ property->type);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+
+ if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION) {
+ /* pass on to storage for updating local database */
+
+ memset(&(req.write_req.bd_addr), 0, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_request, storage_req_id,
+ (char*)&req,
+ sizeof(btif_storage_req_t) + property->len,
+ btif_in_storage_request_copy_cb);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_device_property
+ *
+ * Description Fetches the remote device property from the NVRAM
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_property(bt_bdaddr_t* remote_addr,
+ bt_property_type_t type) {
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ req.read_req.type = type;
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ, (char*)&req,
+ sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_device_properties
+ *
+ * Description Fetches all the remote device properties from NVRAM
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_device_properties(bt_bdaddr_t* remote_addr) {
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.read_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_READ_ALL, (char*)&req,
+ sizeof(btif_storage_req_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_set_remote_device_property
+ *
+ * Description Writes the remote device property to NVRAM.
+ * Currently, BT_PROPERTY_REMOTE_FRIENDLY_NAME is the only
+ * remote device property that can be set
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_set_remote_device_property(bt_bdaddr_t* remote_addr,
+ const bt_property_t* property) {
+ btif_storage_req_t req;
+
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ memcpy(&(req.write_req.bd_addr), remote_addr, sizeof(bt_bdaddr_t));
+ memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
+
+ return btif_transfer_context(execute_storage_remote_request,
+ BTIF_CORE_STORAGE_REMOTE_WRITE, (char*)&req,
+ sizeof(btif_storage_req_t) + property->len,
+ btif_in_storage_request_copy_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_remote_service_record
+ *
+ * Description Looks up the service matching uuid on the remote device
+ * and fetches the SCN and service_name if the UUID is found
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_get_remote_service_record(bt_bdaddr_t* remote_addr,
+ bt_uuid_t* uuid) {
+ if (!btif_is_enabled()) return BT_STATUS_NOT_READY;
+
+ return btif_dm_get_remote_service_record(remote_addr, uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_get_enabled_services_mask
+ *
+ * Description Fetches currently enabled services
+ *
+ * Returns tBTA_SERVICE_MASK
+ *
+ ******************************************************************************/
+
+tBTA_SERVICE_MASK btif_get_enabled_services_mask(void) {
+ return btif_enabled_services;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_enable_service
+ *
+ * Description Enables the service 'service_ID' to the service_mask.
+ * Upon BT enable, BTIF core shall invoke the BTA APIs to
+ * enable the profiles
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id) {
+ tBTA_SERVICE_ID* p_id = &service_id;
+
+ /* If BT is enabled, we need to switch to BTIF context and trigger the
+ * enable for that profile
+ *
+ * Otherwise, we just set the flag. On BT_Enable, the DM will trigger
+ * enable for the profiles that have been enabled */
+
+ btif_enabled_services |= (1 << service_id);
+
+ BTIF_TRACE_DEBUG("%s: current services:0x%x", __func__,
+ btif_enabled_services);
+
+ if (btif_is_enabled()) {
+ btif_transfer_context(btif_dm_execute_service_request,
+ BTIF_DM_ENABLE_SERVICE, (char*)p_id,
+ sizeof(tBTA_SERVICE_ID), NULL);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+/*******************************************************************************
+ *
+ * Function btif_disable_service
+ *
+ * Description Disables the service 'service_ID' to the service_mask.
+ * Upon BT disable, BTIF core shall invoke the BTA APIs to
+ * disable the profiles
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_disable_service(tBTA_SERVICE_ID service_id) {
+ tBTA_SERVICE_ID* p_id = &service_id;
+
+ /* If BT is enabled, we need to switch to BTIF context and trigger the
+ * disable for that profile so that the appropriate uuid_property_changed will
+ * be triggerred. Otherwise, we just need to clear the service_id in the mask
+ */
+
+ btif_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id));
+
+ BTIF_TRACE_DEBUG("%s: Current Services:0x%x", __func__,
+ btif_enabled_services);
+
+ if (btif_is_enabled()) {
+ btif_transfer_context(btif_dm_execute_service_request,
+ BTIF_DM_DISABLE_SERVICE, (char*)p_id,
+ sizeof(tBTA_SERVICE_ID), NULL);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void btif_jni_associate() {
+ BTIF_TRACE_DEBUG("%s Associating thread to JVM", __func__);
+ HAL_CBACK(bt_hal_cbacks, thread_evt_cb, ASSOCIATE_JVM);
+}
+
+static void btif_jni_disassociate() {
+ BTIF_TRACE_DEBUG("%s Disassociating thread from JVM", __func__);
+ HAL_CBACK(bt_hal_cbacks, thread_evt_cb, DISASSOCIATE_JVM);
+ bt_hal_cbacks = NULL;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_debug.cc b/mtkbt/code/bt/btif/src/btif_debug.cc
new file mode 100755
index 0000000..a26c301
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_debug.cc
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "include/bt_target.h"
+
+void btif_debug_init(void) {
+#if (BTSNOOP_MEM == TRUE)
+ btif_debug_btsnoop_init();
+#endif
+}
diff --git a/mtkbt/code/bt/btif/src/btif_debug_btsnoop.cc b/mtkbt/code/bt/btif/src/btif_debug_btsnoop.cc
new file mode 100755
index 0000000..e52a177
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_debug_btsnoop.cc
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <mutex>
+
+#include <base/logging.h>
+#include <resolv.h>
+#include <zlib.h>
+
+#include "btif/include/btif_debug.h"
+#include "btif/include/btif_debug_btsnoop.h"
+#include "hci/include/btsnoop_mem.h"
+#include "include/bt_target.h"
+#include "osi/include/ringbuffer.h"
+#include "osi/include/time.h"
+
+#define REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type) ((type) >> 8)
+
+// Total btsnoop memory log buffer size
+#ifndef BTSNOOP_MEM_BUFFER_SIZE
+static const size_t BTSNOOP_MEM_BUFFER_SIZE = (256 * 1024);
+#endif
+
+// Block size for copying buffers (for compression/encoding etc.)
+static const size_t BLOCK_SIZE = 16384;
+
+// Maximum line length in bugreport (should be multiple of 4 for base64 output)
+static const uint8_t MAX_LINE_LENGTH = 128;
+
+static std::mutex buffer_mutex;
+static ringbuffer_t* buffer = NULL;
+static uint64_t last_timestamp_ms = 0;
+
+static size_t btsnoop_calculate_packet_length(uint16_t type,
+ const uint8_t* data,
+ size_t length);
+
+static void btsnoop_cb(const uint16_t type, const uint8_t* data,
+ const size_t length, const uint64_t timestamp_us) {
+ btsnooz_header_t header;
+
+ size_t included_length = btsnoop_calculate_packet_length(type, data, length);
+ if (included_length == 0) return;
+
+ std::lock_guard<std::mutex> lock(buffer_mutex);
+
+ // Make room in the ring buffer
+
+ while (ringbuffer_available(buffer) <
+ (included_length + sizeof(btsnooz_header_t))) {
+ ringbuffer_pop(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
+ ringbuffer_delete(buffer, header.length - 1);
+ }
+
+ // Insert data
+ header.type = REDUCE_HCI_TYPE_TO_SIGNIFICANT_BITS(type);
+ header.length = included_length + 1; // +1 for type byte
+ header.packet_length = length + 1; // +1 for type byte.
+ header.delta_time_ms =
+ last_timestamp_ms ? timestamp_us - last_timestamp_ms : 0;
+ last_timestamp_ms = timestamp_us;
+
+ ringbuffer_insert(buffer, (uint8_t*)&header, sizeof(btsnooz_header_t));
+ ringbuffer_insert(buffer, data, included_length);
+}
+
+static size_t btsnoop_calculate_packet_length(uint16_t type,
+ const uint8_t* data,
+ size_t length) {
+ static const size_t HCI_ACL_HEADER_SIZE = 4;
+ static const size_t L2CAP_HEADER_SIZE = 4;
+ static const size_t L2CAP_CID_OFFSET = (HCI_ACL_HEADER_SIZE + 2);
+ static const uint16_t L2CAP_SIGNALING_CID = 0x0001;
+
+ // Maximum amount of ACL data to log.
+ // Enough for an RFCOMM frame up to the frame check;
+ // not enough for a HID report or audio data.
+ static const size_t MAX_HCI_ACL_LEN = 14;
+
+ // Calculate packet length to be included
+
+ switch (type) {
+ case BT_EVT_TO_LM_HCI_CMD:
+ return length;
+
+ case BT_EVT_TO_BTU_HCI_EVT:
+ return length;
+
+ case BT_EVT_TO_LM_HCI_ACL:
+ case BT_EVT_TO_BTU_HCI_ACL: {
+ size_t len_hci_acl = HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE;
+ // Check if we have enough data for an L2CAP header
+ if (length > len_hci_acl) {
+ uint16_t l2cap_cid =
+ data[L2CAP_CID_OFFSET] | (data[L2CAP_CID_OFFSET + 1] << 8);
+ if (l2cap_cid == L2CAP_SIGNALING_CID) {
+ // For the signaling CID, take the full packet.
+ // That way, the PSM setup is captured, allowing decoding of PSMs down
+ // the road.
+ return length;
+ } else {
+ // Otherwise, return as much as we reasonably can
+ len_hci_acl = MAX_HCI_ACL_LEN;
+ }
+ }
+ return len_hci_acl < length ? len_hci_acl : length;
+ }
+
+ case BT_EVT_TO_LM_HCI_SCO:
+ case BT_EVT_TO_BTU_HCI_SCO:
+ // We're not logging SCO packets at this time since they are not currently
+ // used.
+ // FALLTHROUGH
+ default:
+ return 0;
+ }
+}
+
+static bool btsnoop_compress(ringbuffer_t* rb_dst, ringbuffer_t* rb_src) {
+ CHECK(rb_dst != NULL);
+ CHECK(rb_src != NULL);
+
+ z_stream zs;
+ zs.zalloc = Z_NULL;
+ zs.zfree = Z_NULL;
+ zs.opaque = Z_NULL;
+
+ if (deflateInit(&zs, Z_DEFAULT_COMPRESSION) != Z_OK) return false;
+
+ bool rc = true;
+ uint8_t block_src[BLOCK_SIZE];
+ uint8_t block_dst[BLOCK_SIZE];
+
+ const size_t num_blocks =
+ (ringbuffer_size(rb_src) + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ for (size_t i = 0; i < num_blocks; ++i) {
+ zs.avail_in =
+ ringbuffer_peek(rb_src, i * BLOCK_SIZE, block_src, BLOCK_SIZE);
+ zs.next_in = block_src;
+
+ do {
+ zs.avail_out = BLOCK_SIZE;
+ zs.next_out = block_dst;
+
+ int err = deflate(&zs, (i == num_blocks - 1) ? Z_FINISH : Z_NO_FLUSH);
+ if (err == Z_STREAM_ERROR) {
+ rc = false;
+ break;
+ }
+
+ const size_t length = BLOCK_SIZE - zs.avail_out;
+ ringbuffer_insert(rb_dst, block_dst, length);
+ } while (zs.avail_out == 0);
+ }
+
+ deflateEnd(&zs);
+ return rc;
+}
+
+void btif_debug_btsnoop_init(void) {
+ if (buffer == NULL) buffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+ btsnoop_mem_set_callback(btsnoop_cb);
+}
+
+void btif_debug_btsnoop_dump(int fd) {
+ ringbuffer_t* ringbuffer = ringbuffer_init(BTSNOOP_MEM_BUFFER_SIZE);
+ if (ringbuffer == NULL) {
+ dprintf(fd, "%s Unable to allocate memory for compression", __func__);
+ return;
+ }
+
+ // Prepend preamble
+
+ btsnooz_preamble_t preamble;
+ preamble.version = BTSNOOZ_CURRENT_VERSION;
+ preamble.last_timestamp_ms = last_timestamp_ms;
+ ringbuffer_insert(ringbuffer, (uint8_t*)&preamble,
+ sizeof(btsnooz_preamble_t));
+
+ // Compress data
+
+ uint8_t b64_in[3] = {0};
+ char b64_out[5] = {0};
+
+ size_t line_length = 0;
+
+ bool rc;
+ {
+ std::lock_guard<std::mutex> lock(buffer_mutex);
+ dprintf(fd, "--- BEGIN:BTSNOOP_LOG_SUMMARY (%zu bytes in) ---\n",
+ ringbuffer_size(buffer));
+ rc = btsnoop_compress(ringbuffer, buffer);
+ }
+
+ if (rc == false) {
+ dprintf(fd, "%s Log compression failed", __func__);
+ goto error;
+ }
+
+ // Base64 encode & output
+
+ while (ringbuffer_size(ringbuffer) > 0) {
+ size_t read = ringbuffer_pop(ringbuffer, b64_in, 3);
+ if (line_length >= MAX_LINE_LENGTH) {
+ dprintf(fd, "\n");
+ line_length = 0;
+ }
+ line_length += b64_ntop(b64_in, read, b64_out, 5);
+ dprintf(fd, "%s", b64_out);
+ }
+
+ dprintf(fd, "\n--- END:BTSNOOP_LOG_SUMMARY ---\n");
+
+error:
+ ringbuffer_free(ringbuffer);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_debug_conn.cc b/mtkbt/code/bt/btif/src/btif_debug_conn.cc
new file mode 100755
index 0000000..1a59456
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_debug_conn.cc
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "btcore/include/bdaddr.h"
+#include "btif/include/btif_debug_conn.h"
+#include "osi/include/time.h"
+
+#define NUM_CONNECTION_EVENTS 16
+#define TEMP_BUFFER_SIZE 30
+
+typedef struct conn_event_t {
+ uint64_t ts;
+ btif_debug_conn_state_t state;
+ bt_bdaddr_t bda;
+ tGATT_DISCONN_REASON disconnect_reason;
+} conn_event_t;
+
+static conn_event_t connection_events[NUM_CONNECTION_EVENTS];
+static uint8_t current_event = 0;
+
+static char* format_ts(const uint64_t ts, char* buffer, int len) {
+ const uint64_t ms = ts / 1000;
+ const time_t secs = ms / 1000;
+ struct tm* ptm = localtime(&secs);
+
+ char tempbuff[20];
+ strftime(tempbuff, sizeof(tempbuff), "%m-%d %H:%M:%S", ptm);
+ snprintf(buffer, len, "%s.%03u", tempbuff, (uint16_t)(ms % 1000));
+
+ return buffer;
+}
+
+static const char* format_state(const btif_debug_conn_state_t state) {
+ switch (state) {
+ case BTIF_DEBUG_CONNECTED:
+ return "CONNECTED ";
+ case BTIF_DEBUG_DISCONNECTED:
+ return "DISCONNECTED";
+ }
+ return "UNKNOWN";
+}
+
+static void next_event() {
+ ++current_event;
+ if (current_event == NUM_CONNECTION_EVENTS) current_event = 0;
+}
+
+void btif_debug_conn_state(const bt_bdaddr_t bda,
+ const btif_debug_conn_state_t state,
+ const tGATT_DISCONN_REASON disconnect_reason) {
+ next_event();
+
+ conn_event_t* evt = &connection_events[current_event];
+ evt->ts = time_gettimeofday_us();
+ evt->state = state;
+ evt->disconnect_reason = disconnect_reason;
+ memcpy(&evt->bda, &bda, sizeof(bt_bdaddr_t));
+}
+
+void btif_debug_conn_dump(int fd) {
+ const uint8_t current_event_local =
+ current_event; // Cache to avoid threading issues
+ uint8_t dump_event = current_event_local;
+ char ts_buffer[TEMP_BUFFER_SIZE] = {0};
+ char name_buffer[TEMP_BUFFER_SIZE] = {0};
+
+ dprintf(fd, "\nConnection Events:\n");
+ if (connection_events[dump_event].ts == 0) dprintf(fd, " None\n");
+
+ while (connection_events[dump_event].ts) {
+ conn_event_t* evt = &connection_events[dump_event];
+ dprintf(fd, " %s %s %s", format_ts(evt->ts, ts_buffer, sizeof(ts_buffer)),
+ format_state(evt->state),
+ bdaddr_to_string(&evt->bda, name_buffer, sizeof(name_buffer)));
+ if (evt->state == BTIF_DEBUG_DISCONNECTED)
+ dprintf(fd, " reason=%d", evt->disconnect_reason);
+ dprintf(fd, "\n");
+
+ // Go to previous event; wrap if needed
+ if (dump_event > 0)
+ --dump_event;
+ else
+ dump_event = NUM_CONNECTION_EVENTS - 1;
+
+ // Check if we dumped all events
+ if (dump_event == current_event_local) break;
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_dm.cc b/mtkbt/code/bt/btif/src/btif_dm.cc
new file mode 100755
index 0000000..07aae55
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_dm.cc
@@ -0,0 +1,3494 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_dm.c
+ *
+ * Description: Contains Device Management (DM) related functionality
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_dm"
+
+#include "btif_dm.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+
+#include "advertise_data_parser.h"
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_closure_api.h"
+#include "bta_gatt_api.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_hd.h"
+#include "btif_hh.h"
+#include "btif_sdp.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "device/include/interop.h"
+#include "include/stack_config.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "stack/btm/btm_int.h"
+#include "stack_config.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/** M: update the remote version before using it @{ */
+static void btif_update_remote_version_property(bt_bdaddr_t * p_bd);
+/** @} */
+
+/******************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+#define COD_MASK 0x07FF
+
+#define COD_UNCLASSIFIED ((0x1F) << 8)
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_HID_MAJOR 0x0500
+#define COD_HID_MASK 0x0700
+#define COD_AV_HEADSETS 0x0404
+#define COD_AV_HANDSFREE 0x0408
+#define COD_AV_HEADPHONES 0x0418
+#define COD_AV_PORTABLE_AUDIO 0x041C
+#define COD_AV_HIFI_AUDIO 0x0428
+
+#define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
+#define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
+#define BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING 2
+
+#define NUM_TIMEOUT_RETRIES 5
+
+#define PROPERTY_PRODUCT_MODEL "ro.product.model"
+#define DEFAULT_LOCAL_NAME_MAX 31
+#if (DEFAULT_LOCAL_NAME_MAX > BTM_MAX_LOC_BD_NAME_LEN)
+#error "default btif local name size exceeds stack supported length"
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+#define BTIF_DM_INTERLEAVE_DURATION_BR_ONE 2
+#define BTIF_DM_INTERLEAVE_DURATION_LE_ONE 2
+#define BTIF_DM_INTERLEAVE_DURATION_BR_TWO 3
+#define BTIF_DM_INTERLEAVE_DURATION_LE_TWO 4
+#endif
+
+#define ENCRYPTED_BREDR 2
+#define ENCRYPTED_LE 4
+
+typedef struct {
+ bt_bond_state_t state;
+ bt_bdaddr_t static_bdaddr;
+ BD_ADDR bd_addr;
+ tBTM_BOND_TYPE bond_type;
+ uint8_t pin_code_len;
+ uint8_t is_ssp;
+ uint8_t auth_req;
+ uint8_t io_cap;
+ uint8_t autopair_attempts;
+ uint8_t timeout_retries;
+ uint8_t is_local_initiated;
+ uint8_t sdp_attempts;
+ bool is_le_only;
+ bool is_le_nc; /* LE Numeric comparison */
+ btif_dm_ble_cb_t ble;
+} btif_dm_pairing_cb_t;
+
+typedef struct {
+ uint8_t ir[BT_OCTET16_LEN];
+ uint8_t irk[BT_OCTET16_LEN];
+ uint8_t dhk[BT_OCTET16_LEN];
+} btif_dm_local_key_id_t;
+
+typedef struct {
+ bool is_er_rcvd;
+ uint8_t er[BT_OCTET16_LEN];
+ bool is_id_keys_rcvd;
+ btif_dm_local_key_id_t id_keys; /* ID kyes */
+
+} btif_dm_local_key_cb_t;
+
+typedef struct {
+ BD_ADDR bd_addr;
+ BD_NAME bd_name;
+} btif_dm_remote_name_t;
+
+/* this structure holds optional OOB data for remote device */
+typedef struct {
+ BD_ADDR bdaddr; /* peer bdaddr */
+ bt_out_of_band_data_t oob_data;
+} btif_dm_oob_cb_t;
+
+typedef struct {
+ bt_bdaddr_t bdaddr;
+ uint8_t transport; /* 0=Unknown, 1=BR/EDR, 2=LE */
+} btif_dm_create_bond_cb_t;
+
+typedef struct {
+ uint8_t status;
+ uint8_t ctrl_state;
+ uint64_t tx_time;
+ uint64_t rx_time;
+ uint64_t idle_time;
+ uint64_t energy_used;
+} btif_activity_energy_info_cb_t;
+
+typedef struct { unsigned int manufact_id; } skip_sdp_entry_t;
+
+typedef enum {
+ BTIF_DM_FUNC_CREATE_BOND,
+ BTIF_DM_FUNC_CANCEL_BOND,
+ BTIF_DM_FUNC_REMOVE_BOND,
+ BTIF_DM_FUNC_BOND_STATE_CHANGED,
+} bt_bond_function_t;
+
+typedef struct {
+ bt_bdaddr_t bd_addr;
+ bt_bond_function_t function;
+ bt_bond_state_t state;
+ struct timespec timestamp;
+} btif_bond_event_t;
+
+#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id))
+
+#define UUID_HUMAN_INTERFACE_DEVICE "00001124-0000-1000-8000-00805f9b34fb"
+
+#define MAX_BTIF_BOND_EVENT_ENTRIES 15
+
+static skip_sdp_entry_t sdp_blacklist[] = {{76}}; // Apple Mouse and Keyboard
+
+/* This flag will be true if HCI_Inquiry is in progress */
+static bool btif_dm_inquiry_in_progress = false;
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static char btif_default_local_name[DEFAULT_LOCAL_NAME_MAX + 1] = {'\0'};
+static uid_set_t* uid_set = NULL;
+
+/* A circular array to keep track of the most recent bond events */
+static btif_bond_event_t btif_dm_bond_events[MAX_BTIF_BOND_EVENT_ENTRIES + 1];
+
+static std::mutex bond_event_lock;
+
+/* |btif_num_bond_events| keeps track of the total number of events and can be
+ greater than |MAX_BTIF_BOND_EVENT_ENTRIES| */
+static size_t btif_num_bond_events = 0;
+static size_t btif_events_start_index = 0;
+static size_t btif_events_end_index = 0;
+
+/******************************************************************************
+ * Static functions
+ *****************************************************************************/
+static btif_dm_pairing_cb_t pairing_cb;
+static btif_dm_oob_cb_t oob_cb;
+static void btif_dm_generic_evt(uint16_t event, char* p_param);
+static void btif_dm_cb_create_bond(bt_bdaddr_t* bd_addr,
+ tBTA_TRANSPORT transport);
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME* p_remote_name);
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ DEV_CLASS dev_class,
+ tBT_DEVICE_TYPE dev_type);
+static btif_dm_local_key_cb_t ble_local_key_cb;
+static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif);
+static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl);
+static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req);
+static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req);
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type);
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type);
+
+static void bte_scan_filt_param_cfg_evt(uint8_t action_type, uint8_t avbl_space,
+ uint8_t ref_value, uint8_t status);
+
+static char* btif_get_default_local_name();
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t* bd_addr,
+ bt_bond_function_t function,
+ bt_bond_state_t state);
+
+/******************************************************************************
+ * Externs
+ *****************************************************************************/
+extern bt_status_t btif_hf_execute_service(bool b_enable);
+extern bt_status_t btif_av_execute_service(bool b_enable);
+extern bt_status_t btif_av_sink_execute_service(bool b_enable);
+extern bt_status_t btif_hh_execute_service(bool b_enable);
+extern bt_status_t btif_hf_client_execute_service(bool b_enable);
+extern bt_status_t btif_sdp_execute_service(bool b_enable);
+extern int btif_hh_connect(bt_bdaddr_t* bd_addr);
+extern void bta_gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint16_t uuid_16);
+extern void btif_av_move_idle(bt_bdaddr_t bd_addr);
+extern bt_status_t btif_hd_execute_service(bool b_enable);
+
+/******************************************************************************
+ * Functions
+ *****************************************************************************/
+
+static bool is_empty_128bit(uint8_t* data) {
+ static const uint8_t zero[16] = {0};
+ return !memcmp(zero, data, sizeof(zero));
+}
+
+static void btif_dm_data_copy(uint16_t event, char* dst, char* src) {
+ tBTA_DM_SEC* dst_dm_sec = (tBTA_DM_SEC*)dst;
+ tBTA_DM_SEC* src_dm_sec = (tBTA_DM_SEC*)src;
+
+ if (!src_dm_sec) return;
+
+ CHECK(dst_dm_sec);
+ maybe_non_aligned_memcpy(dst_dm_sec, src_dm_sec, sizeof(*src_dm_sec));
+
+ if (event == BTA_DM_BLE_KEY_EVT) {
+ dst_dm_sec->ble_key.p_key_value =
+ (tBTM_LE_KEY_VALUE*)osi_malloc(sizeof(tBTM_LE_KEY_VALUE));
+ CHECK(src_dm_sec->ble_key.p_key_value);
+ memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value,
+ sizeof(tBTM_LE_KEY_VALUE));
+ }
+}
+
+static void btif_dm_data_free(uint16_t event, tBTA_DM_SEC* dm_sec) {
+ if (event == BTA_DM_BLE_KEY_EVT)
+ osi_free_and_reset((void**)&dm_sec->ble_key.p_key_value);
+}
+
+void btif_dm_init(uid_set_t* set) { uid_set = set; }
+
+void btif_dm_cleanup(void) {
+ if (uid_set) {
+ uid_set_destroy(uid_set);
+ uid_set = NULL;
+ }
+}
+
+bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
+ bool b_enable) {
+ BTIF_TRACE_DEBUG("%s service_id: %d", __func__, service_id);
+ /* Check the service_ID and invoke the profile's BT state changed API */
+ switch (service_id) {
+ case BTA_HFP_SERVICE_ID:
+ case BTA_HSP_SERVICE_ID: {
+ btif_hf_execute_service(b_enable);
+ } break;
+ case BTA_A2DP_SOURCE_SERVICE_ID: {
+ btif_av_execute_service(b_enable);
+ } break;
+ case BTA_A2DP_SINK_SERVICE_ID: {
+ btif_av_sink_execute_service(b_enable);
+ } break;
+ case BTA_HID_SERVICE_ID: {
+ btif_hh_execute_service(b_enable);
+ } break;
+ case BTA_HFP_HS_SERVICE_ID: {
+ btif_hf_client_execute_service(b_enable);
+ } break;
+ case BTA_SDP_SERVICE_ID: {
+ btif_sdp_execute_service(b_enable);
+ } break;
+ case BTA_HIDD_SERVICE_ID: {
+ btif_hd_execute_service(b_enable);
+ } break;
+ default:
+ BTIF_TRACE_ERROR("%s: Unknown service %d being %s", __func__, service_id,
+ (b_enable) ? "enabled" : "disabled");
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function check_eir_remote_name
+ *
+ * Description Check if remote name is in the EIR data
+ *
+ * Returns true if remote name found
+ * Populate p_remote_name, if provided and remote name found
+ *
+ ******************************************************************************/
+static bool check_eir_remote_name(tBTA_DM_SEARCH* p_search_data,
+ uint8_t* p_remote_name,
+ uint8_t* p_remote_name_len) {
+ const uint8_t* p_eir_remote_name = NULL;
+ uint8_t remote_name_len = 0;
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir) {
+ p_eir_remote_name = AdvertiseDataParser::GetFieldByType(
+ p_search_data->inq_res.p_eir, p_search_data->inq_res.eir_len,
+ BTM_EIR_COMPLETE_LOCAL_NAME_TYPE, &remote_name_len);
+ if (!p_eir_remote_name) {
+ p_eir_remote_name = AdvertiseDataParser::GetFieldByType(
+ p_search_data->inq_res.p_eir, p_search_data->inq_res.eir_len,
+ BTM_EIR_SHORTENED_LOCAL_NAME_TYPE, &remote_name_len);
+ }
+
+ if (p_eir_remote_name) {
+ if (remote_name_len > BD_NAME_LEN) remote_name_len = BD_NAME_LEN;
+
+ if (p_remote_name && p_remote_name_len) {
+ memcpy(p_remote_name, p_eir_remote_name, remote_name_len);
+ *(p_remote_name + remote_name_len) = 0;
+ *p_remote_name_len = remote_name_len;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function check_cached_remote_name
+ *
+ * Description Check if remote name is in the NVRAM cache
+ *
+ * Returns true if remote name found
+ * Populate p_remote_name, if provided and remote name found
+ *
+ ******************************************************************************/
+static bool check_cached_remote_name(tBTA_DM_SEARCH* p_search_data,
+ uint8_t* p_remote_name,
+ uint8_t* p_remote_name_len) {
+ bt_bdname_t bdname;
+ bt_bdaddr_t remote_bdaddr;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ bdcpy(remote_bdaddr.address, p_search_data->inq_res.bd_addr);
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(&remote_bdaddr, &prop_name) ==
+ BT_STATUS_SUCCESS) {
+ if (p_remote_name && p_remote_name_len) {
+ strcpy((char*)p_remote_name, (char*)bdname.name);
+ *p_remote_name_len = strlen((char*)p_remote_name);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static uint32_t get_cod(const bt_bdaddr_t* remote_bdaddr) {
+ uint32_t remote_cod;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_CLASS_OF_DEVICE,
+ sizeof(uint32_t), &remote_cod);
+ if (btif_storage_get_remote_device_property(
+ (bt_bdaddr_t*)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS) {
+ LOG_INFO(LOG_TAG, "%s remote_cod = 0x%08x", __func__, remote_cod);
+ return remote_cod & COD_MASK;
+ }
+
+ return 0;
+}
+
+bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod) {
+ return get_cod(remote_bdaddr) == cod;
+}
+
+bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr) {
+ return (get_cod(remote_bdaddr) & COD_HID_MASK) == COD_HID_MAJOR;
+}
+
+bool check_hid_le(const bt_bdaddr_t* remote_bdaddr) {
+ uint32_t remote_dev_type;
+ bt_property_t prop_name;
+
+ /* check if we already have it in our btif_storage cache */
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_TYPE_OF_DEVICE,
+ sizeof(uint32_t), &remote_dev_type);
+ if (btif_storage_get_remote_device_property(
+ (bt_bdaddr_t*)remote_bdaddr, &prop_name) == BT_STATUS_SUCCESS) {
+ if (remote_dev_type == BT_DEVICE_DEVTYPE_BLE) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bdaddr, bdstr, sizeof(bdstr));
+ if (btif_config_exist(bdstr, "HidAppId")) return true;
+ }
+ }
+ return false;
+}
+
+/*****************************************************************************
+ *
+ * Function check_sdp_bl
+ *
+ * Description Checks if a given device is blacklisted to skip sdp
+ *
+ * Parameters skip_sdp_entry
+ *
+ * Returns true if the device is present in blacklist, else false
+ *
+ ******************************************************************************/
+bool check_sdp_bl(const bt_bdaddr_t* remote_bdaddr) {
+ uint16_t manufacturer = 0;
+ bt_property_t prop_name;
+ bt_remote_version_t info;
+
+ if (remote_bdaddr == NULL) return false;
+
+ /** M: update the remote version before using it @{ */
+ btif_update_remote_version_property((bt_bdaddr_t *)remote_bdaddr);
+ /** @} */
+
+ /* if not available yet, try fetching from config database */
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_REMOTE_VERSION_INFO,
+ sizeof(bt_remote_version_t), &info);
+
+ if (btif_storage_get_remote_device_property(
+ (bt_bdaddr_t*)remote_bdaddr, &prop_name) != BT_STATUS_SUCCESS) {
+ return false;
+ }
+ manufacturer = info.manufacturer;
+
+ /**M:Bug fix for coding defect@}*/
+ for (unsigned int i = 0; i < ARRAY_SIZE(sdp_blacklist) && i < sizeof(sdp_blacklist)/sizeof(skip_sdp_entry_t); i++) {
+ /**@}*/
+ if (manufacturer == sdp_blacklist[i].manufact_id) return true;
+ }
+ /**M:Workround for disable hid sdp @{*/
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_HID_DISABLE_SDP, remote_bdaddr))
+ {
+ return true;
+ }
+
+ char bdstr[20] = {0};
+ LOG_DEBUG(LOG_TAG, "%s: %s is not in blacklist for skipping sdp", __func__, bdaddr_to_string(remote_bdaddr, bdstr, sizeof(bdstr)));
+#endif
+ /**@}*/
+
+ return false;
+}
+
+static void bond_state_changed(bt_status_t status, bt_bdaddr_t* bd_addr,
+ bt_bond_state_t state) {
+ btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state);
+
+ // Send bonding state only once - based on outgoing/incoming we may receive
+ // duplicates
+ if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {
+ // Cross key pairing so send callback for static address
+ if (!bdaddr_is_empty(&pairing_cb.static_bdaddr)) {
+ HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
+ }
+ return;
+ }
+
+ if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) state = BT_BOND_STATE_NONE;
+
+ BTIF_TRACE_DEBUG("%s: state=%d, prev_state=%d, sdp_attempts = %d", __func__,
+ state, pairing_cb.state, pairing_cb.sdp_attempts);
+
+ /** M: If service discovery in process, postpond reporting bond state changed @{ */
+ if ((state == BT_BOND_STATE_NONE) && (pairing_cb.sdp_attempts !=0)) {
+ BTIF_TRACE_DEBUG("%s: delay this bond state change report after service discovery", __func__);
+ } else {
+ HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, bd_addr, state);
+ }
+ /** @} */
+
+ /** M: fix unexcepted change of pairng addr @{ */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING)
+ {
+ if (bdcmp(bd_addr->address, pairing_cb.bd_addr) != 0) {
+ BTIF_TRACE_WARNING("%s: address is not match", __func__);
+ return;
+ }
+ }
+ /** @} */
+
+ if (state == BT_BOND_STATE_BONDING) {
+ pairing_cb.state = state;
+ bdcpy(pairing_cb.bd_addr, bd_addr->address);
+ } else {
+ if (!pairing_cb.sdp_attempts)
+ memset(&pairing_cb, 0, sizeof(pairing_cb));
+ else
+ BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);
+ }
+}
+
+/* store remote version in bt config to always have access
+ to it post pairing*/
+static void btif_update_remote_version_property(bt_bdaddr_t* p_bd) {
+ bt_property_t property;
+ uint8_t lmp_ver = 0;
+ uint16_t lmp_subver = 0;
+ uint16_t mfct_set = 0;
+ tBTM_STATUS btm_status;
+ bt_remote_version_t info;
+ bt_status_t status;
+ bdstr_t bdstr;
+
+ btm_status =
+ BTM_ReadRemoteVersion(*(BD_ADDR*)p_bd, &lmp_ver, &mfct_set, &lmp_subver);
+
+ LOG_DEBUG(LOG_TAG, "remote version info [%s]: %x, %x, %x",
+ bdaddr_to_string(p_bd, bdstr, sizeof(bdstr)), lmp_ver, mfct_set,
+ lmp_subver);
+
+ if (btm_status == BTM_SUCCESS) {
+ // Always update cache to ensure we have availability whenever BTM API is
+ // not populated
+ info.manufacturer = mfct_set;
+ info.sub_ver = lmp_subver;
+ info.version = lmp_ver;
+ BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_REMOTE_VERSION_INFO,
+ sizeof(bt_remote_version_t), &info);
+ status = btif_storage_set_remote_device_property(p_bd, &property);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote version",
+ status);
+ }
+}
+
+static void btif_update_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ DEV_CLASS dev_class,
+ tBT_DEVICE_TYPE device_type) {
+ int num_properties = 0;
+ bt_property_t properties[3];
+ bt_bdaddr_t bdaddr;
+ bt_status_t status;
+ uint32_t cod;
+ bt_device_type_t dev_type;
+
+ memset(properties, 0, sizeof(properties));
+ bdcpy(bdaddr.address, bd_addr);
+
+ /* remote name */
+ if (strlen((const char*)bd_name)) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties], BT_PROPERTY_BDNAME,
+ strlen((char*)bd_name), bd_name);
+ status = btif_storage_set_remote_device_property(
+ &bdaddr, &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device name",
+ status);
+ num_properties++;
+ }
+
+ /* class of device */
+ cod = devclass2uint(dev_class);
+ BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod);
+ if (cod == 0) {
+ /* Try to retrieve cod from storage */
+ BTIF_TRACE_DEBUG("%s cod is 0, checking cod from storage", __func__);
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ status = btif_storage_get_remote_device_property(
+ &bdaddr, &properties[num_properties]);
+ BTIF_TRACE_DEBUG("%s cod retrieved from storage is 0x%06x", __func__, cod);
+ if (cod == 0) {
+ BTIF_TRACE_DEBUG("%s cod is again 0, set as unclassified", __func__);
+ cod = COD_UNCLASSIFIED;
+ }
+ }
+
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod), &cod);
+ status = btif_storage_set_remote_device_property(&bdaddr,
+ &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device class",
+ status);
+ num_properties++;
+
+ /* device type */
+ bt_property_t prop_name;
+ uint8_t remote_dev_type;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_TYPE_OF_DEVICE,
+ sizeof(uint8_t), &remote_dev_type);
+ if (btif_storage_get_remote_device_property(&bdaddr, &prop_name) ==
+ BT_STATUS_SUCCESS)
+ dev_type = (bt_device_type_t)(remote_dev_type | device_type);
+ else
+ dev_type = (bt_device_type_t)device_type;
+
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type),
+ &dev_type);
+ status = btif_storage_set_remote_device_property(&bdaddr,
+ &properties[num_properties]);
+ ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device type",
+ status);
+ num_properties++;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bdaddr,
+ num_properties, properties);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cb_hid_remote_name
+ *
+ * Description Remote name callback for HID device. Called in btif context
+ * Special handling for HID devices
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_cb_hid_remote_name(tBTM_REMOTE_DEV_NAME* p_remote_name) {
+ BTIF_TRACE_DEBUG("%s: status=%d pairing_cb.state=%d", __func__,
+ p_remote_name->status, pairing_cb.state);
+ if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+ bt_bdaddr_t remote_bd;
+
+ bdcpy(remote_bd.address, pairing_cb.bd_addr);
+
+ if (p_remote_name->status == BTM_SUCCESS) {
+ bond_state_changed(BT_STATUS_SUCCESS, &remote_bd, BT_BOND_STATE_BONDED);
+ } else
+ bond_state_changed(BT_STATUS_FAIL, &remote_bd, BT_BOND_STATE_NONE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cb_create_bond
+ *
+ * Description Create bond initiated from the BTIF thread context
+ * Special handling for HID devices
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_cb_create_bond(bt_bdaddr_t* bd_addr,
+ tBTA_TRANSPORT transport) {
+ bool is_hid = check_cod(bd_addr, COD_HID_POINTING);
+ bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
+
+ int device_type;
+ int addr_type;
+ bdstr_t bdstr;
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr));
+ if (transport == BT_TRANSPORT_LE) {
+ if (!btif_config_get_int((char const*)&bdstr, "DevType", &device_type)) {
+ btif_config_set_int(bdstr, "DevType", BT_DEVICE_TYPE_BLE);
+ }
+ if (btif_storage_get_remote_addr_type(bd_addr, &addr_type) !=
+ BT_STATUS_SUCCESS) {
+ // Try to read address type. OOB pairing might have set it earlier, but
+ // didn't store it, it defaults to BLE_ADDR_PUBLIC
+ uint8_t tmp_dev_type;
+ uint8_t tmp_addr_type;
+ BTM_ReadDevInfo(bd_addr->address, &tmp_dev_type, &tmp_addr_type);
+ addr_type = tmp_addr_type;
+
+ btif_storage_set_remote_addr_type(bd_addr, addr_type);
+ }
+ }
+ if ((btif_config_get_int((char const*)&bdstr, "DevType", &device_type) &&
+ (btif_storage_get_remote_addr_type(bd_addr, &addr_type) ==
+ BT_STATUS_SUCCESS) &&
+ (device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE) ||
+ (transport == BT_TRANSPORT_LE)) {
+ BTA_DmAddBleDevice(bd_addr->address, addr_type, device_type);
+ }
+
+ if (is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) {
+ bt_status_t status;
+ status = (bt_status_t)btif_hh_connect(bd_addr);
+ if (status != BT_STATUS_SUCCESS)
+ bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE);
+ } else {
+ BTA_DmBondByTransport((uint8_t*)bd_addr->address, transport);
+ }
+ /* Track originator of bond creation */
+ pairing_cb.is_local_initiated = true;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cb_remove_bond
+ *
+ * Description remove bond initiated from the BTIF thread context
+ * Special handling for HID devices
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr) {
+/*special handling for HID devices */
+/* VUP needs to be sent if its a HID Device. The HID HOST module will check if
+there
+is a valid hid connection with this bd_addr. If yes VUP will be issued.*/
+#if (BTA_HH_INCLUDED == TRUE)
+ if (btif_hh_virtual_unplug(bd_addr) != BT_STATUS_SUCCESS)
+#endif
+ {
+ BTIF_TRACE_DEBUG("%s: Removing HH device", __func__);
+ BTA_DmRemoveDevice((uint8_t*)bd_addr->address);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_connection_state
+ *
+ * Description Returns whether the remote device is currently connected
+ * and whether encryption is active for the connection
+ *
+ * Returns 0 if not connected; 1 if connected and > 1 if connection is
+ * encrypted
+ *
+ ******************************************************************************/
+uint16_t btif_dm_get_connection_state(const bt_bdaddr_t* bd_addr) {
+ uint8_t* bda = (uint8_t*)bd_addr->address;
+ uint16_t rc = BTA_DmGetConnectionState(bda);
+
+ if (rc != 0) {
+ uint8_t flags = 0;
+
+ BTM_GetSecurityFlagsByTransport(bda, &flags, BT_TRANSPORT_BR_EDR);
+ BTIF_TRACE_DEBUG("%s: security flags (BR/EDR)=0x%02x", __func__, flags);
+ if (flags & BTM_SEC_FLAG_ENCRYPTED) rc |= ENCRYPTED_BREDR;
+
+ BTM_GetSecurityFlagsByTransport(bda, &flags, BT_TRANSPORT_LE);
+ BTIF_TRACE_DEBUG("%s: security flags (LE)=0x%02x", __func__, flags);
+ if (flags & BTM_SEC_FLAG_ENCRYPTED) rc |= ENCRYPTED_LE;
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+ *
+ * Function search_devices_copy_cb
+ *
+ * Description Deep copy callback for search devices event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void search_devices_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+ tBTA_DM_SEARCH* p_dest_data = (tBTA_DM_SEARCH*)p_dest;
+ tBTA_DM_SEARCH* p_src_data = (tBTA_DM_SEARCH*)p_src;
+
+ if (!p_src) return;
+
+ BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_dm_search_event(event));
+ maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+ switch (event) {
+ case BTA_DM_INQ_RES_EVT: {
+ if (p_src_data->inq_res.p_eir) {
+ p_dest_data->inq_res.p_eir =
+ (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->inq_res.p_eir, p_src_data->inq_res.p_eir,
+ p_src_data->inq_res.eir_len);
+ p_dest_data->inq_res.eir_len = p_src_data->inq_res.eir_len;
+ }
+ } break;
+
+ case BTA_DM_DISC_RES_EVT: {
+ if (p_src_data->disc_res.raw_data_size &&
+ p_src_data->disc_res.p_raw_data) {
+ p_dest_data->disc_res.p_raw_data =
+ (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->disc_res.p_raw_data,
+ p_src_data->disc_res.p_raw_data,
+ p_src_data->disc_res.raw_data_size);
+ }
+ } break;
+ }
+}
+
+static void search_services_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+ tBTA_DM_SEARCH* p_dest_data = (tBTA_DM_SEARCH*)p_dest;
+ tBTA_DM_SEARCH* p_src_data = (tBTA_DM_SEARCH*)p_src;
+
+ if (!p_src) return;
+ maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+ switch (event) {
+ case BTA_DM_DISC_RES_EVT: {
+ if (p_src_data->disc_res.result == BTA_SUCCESS) {
+ if (p_src_data->disc_res.num_uuids > 0) {
+ p_dest_data->disc_res.p_uuid_list =
+ (uint8_t*)(p_dest + sizeof(tBTA_DM_SEARCH));
+ memcpy(p_dest_data->disc_res.p_uuid_list,
+ p_src_data->disc_res.p_uuid_list,
+ p_src_data->disc_res.num_uuids * MAX_UUID_SIZE);
+ osi_free_and_reset((void**)&p_src_data->disc_res.p_uuid_list);
+ }
+ osi_free_and_reset((void**)&p_src_data->disc_res.p_raw_data);
+ }
+ } break;
+ }
+}
+/******************************************************************************
+ *
+ * BTIF DM callback events
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_dm_pin_req_evt
+ *
+ * Description Executes pin request event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_pin_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ bt_pin_code_t pin_code;
+ int dev_type;
+
+ /* Remote properties update */
+ if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BREDR;
+ }
+ btif_update_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
+ p_pin_req->dev_class,
+ (tBT_DEVICE_TYPE)dev_type);
+
+ bdcpy(bd_addr.address, p_pin_req->bd_addr);
+ memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+ cod = devclass2uint(p_pin_req->dev_class);
+
+ if (cod == 0) {
+ BTIF_TRACE_DEBUG("%s cod is 0, set as unclassified", __func__);
+ cod = COD_UNCLASSIFIED;
+ }
+
+ /** M: check pairing address @{*/
+ if (pairing_cb.is_local_initiated && (bdcmp(bd_addr.address, pairing_cb.bd_addr) != 0)) {
+ BTIF_TRACE_WARNING("%s local initiated pairing to another device haven't finished", __func__);
+ BTA_DmPinReply((uint8_t*)bd_addr.address, false, 0, NULL);
+ return;
+ }
+ /** @} */
+
+ /* check for auto pair possiblity only if bond was initiated by local device
+ */
+ if (pairing_cb.is_local_initiated && (p_pin_req->min_16_digit == false)) {
+ if (check_cod(&bd_addr, COD_AV_HEADSETS) ||
+ check_cod(&bd_addr, COD_AV_HEADPHONES) ||
+ check_cod(&bd_addr, COD_AV_PORTABLE_AUDIO) ||
+ check_cod(&bd_addr, COD_AV_HIFI_AUDIO) ||
+ check_cod(&bd_addr, COD_HID_POINTING)) {
+ /* Check if this device can be auto paired */
+ if (!interop_match_addr(INTEROP_DISABLE_AUTO_PAIRING, &bd_addr) &&
+ !interop_match_name(INTEROP_DISABLE_AUTO_PAIRING,
+ (const char*)bd_name.name) &&
+ (pairing_cb.autopair_attempts == 0)) {
+ BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__);
+ pin_code.pin[0] = 0x30;
+ pin_code.pin[1] = 0x30;
+ pin_code.pin[2] = 0x30;
+ pin_code.pin[3] = 0x30;
+
+ pairing_cb.autopair_attempts++;
+ BTA_DmPinReply((uint8_t*)bd_addr.address, true, 4, pin_code.pin);
+ return;
+ }
+ } else if (check_cod(&bd_addr, COD_HID_KEYBOARD) ||
+ check_cod(&bd_addr, COD_HID_COMBO)) {
+ if ((interop_match_addr(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN, &bd_addr) ==
+ true) &&
+ (pairing_cb.autopair_attempts == 0)) {
+ BTIF_TRACE_DEBUG("%s() Attempting auto pair", __func__);
+ pin_code.pin[0] = 0x30;
+ pin_code.pin[1] = 0x30;
+ pin_code.pin[2] = 0x30;
+ pin_code.pin[3] = 0x30;
+
+ pairing_cb.autopair_attempts++;
+ BTA_DmPinReply((uint8_t*)bd_addr.address, true, 4, pin_code.pin);
+ return;
+ }
+ }
+ }
+ HAL_CBACK(bt_hal_cbacks, pin_request_cb, &bd_addr, &bd_name, cod,
+ p_pin_req->min_16_digit);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ssp_cfm_req_evt
+ *
+ * Description Executes SSP confirm request event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_ssp_cfm_req_evt(tBTA_DM_SP_CFM_REQ* p_ssp_cfm_req) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ bool is_incoming = !(pairing_cb.state == BT_BOND_STATE_BONDING);
+ int dev_type;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ /* Remote properties update */
+ if (!btif_get_device_type(p_ssp_cfm_req->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BREDR;
+ }
+ btif_update_remote_properties(p_ssp_cfm_req->bd_addr, p_ssp_cfm_req->bd_name,
+ p_ssp_cfm_req->dev_class,
+ (tBT_DEVICE_TYPE)dev_type);
+
+ bdcpy(bd_addr.address, p_ssp_cfm_req->bd_addr);
+ memcpy(bd_name.name, p_ssp_cfm_req->bd_name, BD_NAME_LEN);
+
+ /* Set the pairing_cb based on the local & remote authentication requirements
+ */
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+ /* if just_works and bonding bit is not set treat this as temporary */
+ if (p_ssp_cfm_req->just_works &&
+ !(p_ssp_cfm_req->loc_auth_req & BTM_AUTH_BONDS) &&
+ !(p_ssp_cfm_req->rmt_auth_req & BTM_AUTH_BONDS) &&
+ !(check_cod((bt_bdaddr_t*)&p_ssp_cfm_req->bd_addr, COD_HID_POINTING)))
+ pairing_cb.bond_type = BOND_TYPE_TEMPORARY;
+ else
+ pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+
+ btm_set_bond_type_dev(p_ssp_cfm_req->bd_addr, pairing_cb.bond_type);
+
+ pairing_cb.is_ssp = true;
+
+ /* If JustWorks auto-accept */
+ if (p_ssp_cfm_req->just_works) {
+ /* Pairing consent for JustWorks needed if:
+ * 1. Incoming (non-temporary) pairing is detected AND
+ * 2. local IO capabilities are DisplayYesNo AND
+ * 3. remote IO capabiltiies are DisplayOnly or NoInputNoOutput;
+ */
+ if (is_incoming && pairing_cb.bond_type != BOND_TYPE_TEMPORARY &&
+ ((p_ssp_cfm_req->loc_io_caps == HCI_IO_CAP_DISPLAY_YESNO) &&
+ (p_ssp_cfm_req->rmt_io_caps == HCI_IO_CAP_DISPLAY_ONLY ||
+ p_ssp_cfm_req->rmt_io_caps == HCI_IO_CAP_NO_IO))) {
+ BTIF_TRACE_EVENT(
+ "%s: User consent needed for incoming pairing request. loc_io_caps: "
+ "%d, rmt_io_caps: %d",
+ __func__, p_ssp_cfm_req->loc_io_caps, p_ssp_cfm_req->rmt_io_caps);
+ } else {
+ BTIF_TRACE_EVENT("%s: Auto-accept JustWorks pairing", __func__);
+ btif_dm_ssp_reply(&bd_addr, BT_SSP_VARIANT_CONSENT, true, 0);
+ return;
+ }
+ }
+
+ cod = devclass2uint(p_ssp_cfm_req->dev_class);
+
+ if (cod == 0) {
+ LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
+ cod = COD_UNCLASSIFIED;
+ }
+
+ pairing_cb.sdp_attempts = 0;
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+ (p_ssp_cfm_req->just_works ? BT_SSP_VARIANT_CONSENT
+ : BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+ p_ssp_cfm_req->num_val);
+}
+
+static void btif_dm_ssp_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ int dev_type;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ /* Remote properties update */
+ if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BREDR;
+ }
+ btif_update_remote_properties(
+ p_ssp_key_notif->bd_addr, p_ssp_key_notif->bd_name,
+ p_ssp_key_notif->dev_class, (tBT_DEVICE_TYPE)dev_type);
+
+ bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr);
+ memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = true;
+ cod = devclass2uint(p_ssp_key_notif->dev_class);
+
+ if (cod == 0) {
+ LOG_DEBUG(LOG_TAG, "%s cod is 0, set as unclassified", __func__);
+ cod = COD_UNCLASSIFIED;
+ }
+
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+ BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
+}
+/*******************************************************************************
+ *
+ * Function btif_dm_auth_cmpl_evt
+ *
+ * Description Executes authentication complete event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
+ /* Save link key, if not temporary */
+ bt_bdaddr_t bd_addr;
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_bond_state_t state = BT_BOND_STATE_NONE;
+ bool skip_sdp = false;
+
+ BTIF_TRACE_DEBUG("%s: bond state=%d", __func__, pairing_cb.state);
+
+ bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+ if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+ if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) ||
+ (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) ||
+ (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) ||
+ (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) ||
+ pairing_cb.bond_type == BOND_TYPE_PERSISTENT) {
+ bt_status_t ret;
+ BTIF_TRACE_DEBUG("%s: Storing link key. key_type=0x%x, bond_type=%d",
+ __func__, p_auth_cmpl->key_type, pairing_cb.bond_type);
+ ret = btif_storage_add_bonded_device(&bd_addr, p_auth_cmpl->key,
+ p_auth_cmpl->key_type,
+ pairing_cb.pin_code_len);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret);
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: Temporary key. Not storing. key_type=0x%x, bond_type=%d",
+ __func__, p_auth_cmpl->key_type, pairing_cb.bond_type);
+ if (pairing_cb.bond_type == BOND_TYPE_TEMPORARY) {
+ BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing",
+ __func__);
+ btif_storage_remove_bonded_device(&bd_addr);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
+ return;
+ }
+ }
+ }
+
+ // We could have received a new link key without going through the pairing
+ // flow. If so, we don't want to perform SDP or any other operations on the
+ // authenticated device. Also, make sure that the link key is not derived from
+ // secure LTK, because we will need to perform SDP in case of link key
+ // derivation to allow bond state change notification for the BR/EDR transport
+ // so that the subsequent BR/EDR connections to the remote can use the derived
+ // link key.
+ if ((bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0) &&
+ (!pairing_cb.ble.is_penc_key_rcvd)) {
+ char address[32];
+ bt_bdaddr_t bt_bdaddr;
+
+ memcpy(bt_bdaddr.address, p_auth_cmpl->bd_addr, sizeof(bt_bdaddr.address));
+ bdaddr_to_string(&bt_bdaddr, address, sizeof(address));
+ LOG_INFO(LOG_TAG,
+ "%s skipping SDP since we did not initiate pairing to %s.",
+ __func__, address);
+ return;
+ }
+
+ // Skip SDP for certain HID Devices
+ if (p_auth_cmpl->success) {
+ btif_storage_set_remote_addr_type(&bd_addr, p_auth_cmpl->addr_type);
+ btif_update_remote_properties(p_auth_cmpl->bd_addr, p_auth_cmpl->bd_name,
+ NULL, p_auth_cmpl->dev_type);
+ pairing_cb.timeout_retries = 0;
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+ bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+
+ if (check_sdp_bl(&bd_addr) && check_cod_hid(&bd_addr)
+ /**M:Fix for avoid HID Keyboard skip sdp @{*/
+ && check_cod(&bd_addr, COD_HID_POINTING)
+ /**@}*/
+ ) {
+ LOG_WARN(LOG_TAG, "%s:skip SDP", __func__);
+ skip_sdp = true;
+ }
+
+ /**M:Workround for disable hid sdp @{*/
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (skip_sdp){
+#else
+ if (!pairing_cb.is_local_initiated && skip_sdp) {
+#endif
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
+ /**@}*/
+
+ LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);
+ bt_property_t prop;
+ /**M:disable the local vairiable @{*/
+ //bt_bdaddr_t bd_addr;
+ /**@}*/
+ bt_uuid_t uuid;
+ char uuid_str[128] = UUID_HUMAN_INTERFACE_DEVICE;
+
+ string_to_uuid(uuid_str, &uuid);
+
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.val = uuid.uu;
+ prop.len = MAX_UUID_SIZE;
+ /**M:Workround for disable hid sdp @{*/
+ /* Also write this to the NVRAM */
+ status = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ASSERTC(status == BT_STATUS_SUCCESS, "storing remote services failed", status);
+ /**@}*/
+ /* Send the event to the BTIF */
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+ &bd_addr, 1, &prop);
+ } else {
+ bool is_crosskey = false;
+ /* If bonded due to cross-key, save the static address too*/
+ if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+ (bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0)) {
+ BTIF_TRACE_DEBUG(
+ "%s: bonding initiated due to cross key, adding static address",
+ __func__);
+ bdcpy(pairing_cb.static_bdaddr.address, p_auth_cmpl->bd_addr);
+ is_crosskey = true;
+ }
+ if (!is_crosskey ||
+ !(stack_config_get_interface()->get_pts_crosskey_sdp_disable())) {
+ // Ensure inquiry is stopped before attempting service discovery
+ btif_dm_cancel_discovery();
+
+ /* Trigger SDP on the device */
+ pairing_cb.sdp_attempts = 1;
+ btif_dm_get_remote_services(&bd_addr);
+ }
+ }
+ // Do not call bond_state_changed_cb yet. Wait until remote service
+ // discovery is complete
+ } else {
+ // Map the HCI fail reason to bt status
+ switch (p_auth_cmpl->fail_reason) {
+ case HCI_ERR_PAGE_TIMEOUT:
+ case HCI_ERR_LMP_RESPONSE_TIMEOUT:
+ if (interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &bd_addr) &&
+ pairing_cb.timeout_retries) {
+ BTIF_TRACE_WARNING("%s() - Pairing timeout; retrying (%d) ...",
+ __func__, pairing_cb.timeout_retries);
+ --pairing_cb.timeout_retries;
+ btif_dm_cb_create_bond(&bd_addr, BTA_TRANSPORT_UNKNOWN);
+ return;
+ }
+ /* Fall-through */
+ case HCI_ERR_CONNECTION_TOUT:
+ status = BT_STATUS_RMT_DEV_DOWN;
+ break;
+
+ case HCI_ERR_PAIRING_NOT_ALLOWED:
+ btif_storage_remove_bonded_device(&bd_addr);
+ status = BT_STATUS_AUTH_REJECTED;
+ break;
+
+ /* map the auth failure codes, so we can retry pairing if necessary */
+ case HCI_ERR_AUTH_FAILURE:
+ case HCI_ERR_KEY_MISSING:
+ btif_storage_remove_bonded_device(&bd_addr);
+ case HCI_ERR_HOST_REJECT_SECURITY:
+ case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
+ case HCI_ERR_UNIT_KEY_USED:
+ case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED:
+ case HCI_ERR_INSUFFCIENT_SECURITY:
+ case HCI_ERR_PEER_USER:
+ case HCI_ERR_UNSPECIFIED:
+ BTIF_TRACE_DEBUG(" %s() Authentication fail reason %d", __func__,
+ p_auth_cmpl->fail_reason);
+ if (pairing_cb.autopair_attempts == 1) {
+ /* Create the Bond once again */
+ BTIF_TRACE_WARNING("%s() auto pair failed. Reinitiate Bond",
+ __func__);
+ btif_dm_cb_create_bond(&bd_addr, BTA_TRANSPORT_UNKNOWN);
+ return;
+ } else {
+ /* if autopair attempts are more than 1, or not attempted */
+ status = BT_STATUS_AUTH_FAILURE;
+ }
+ break;
+
+ default:
+ status = BT_STATUS_FAIL;
+ }
+ /* Special Handling for HID Devices */
+ if (check_cod(&bd_addr, COD_HID_POINTING)) {
+ /* Remove Device as bonded in nvram as authentication failed */
+ BTIF_TRACE_DEBUG("%s(): removing hid pointing device from nvram",
+ __func__);
+ btif_storage_remove_bonded_device(&bd_addr);
+ }
+ bond_state_changed(status, &bd_addr, state);
+ }
+}
+
+/******************************************************************************
+ *
+ * Function btif_dm_search_devices_evt
+ *
+ * Description Executes search devices callback events in btif context
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+static void btif_dm_search_devices_evt(uint16_t event, char* p_param) {
+ tBTA_DM_SEARCH* p_search_data;
+ BTIF_TRACE_EVENT("%s event=%s", __func__, dump_dm_search_event(event));
+
+ switch (event) {
+ case BTA_DM_DISC_RES_EVT: {
+ p_search_data = (tBTA_DM_SEARCH*)p_param;
+ /* Remote name update */
+ if (strlen((const char*)p_search_data->disc_res.bd_name)) {
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ bt_property_t properties[3];
+ uint32_t cod;
+#else
+ bt_property_t properties[1];
+#endif
+ bt_bdaddr_t bdaddr;
+ bt_status_t status;
+
+ properties[0].type = BT_PROPERTY_BDNAME;
+ properties[0].val = p_search_data->disc_res.bd_name;
+ properties[0].len = strlen((char*)p_search_data->disc_res.bd_name);
+ bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
+
+ status =
+ btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
+ ASSERTC(status == BT_STATUS_SUCCESS,
+ "failed to save remote device property", status);
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bdaddr,
+ 1, properties);
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ cod = get_cod(&bdaddr);
+ if (cod != 0) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[1], BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
+ BTIF_STORAGE_FILL_PROPERTY(&properties[2], BT_PROPERTY_CLASS_OF_DEVICE, sizeof(uint32_t), &cod);
+ BTIF_TRACE_DEBUG("%s: Now we have name and cod, report to JNI", __FUNCTION__);
+ HAL_CBACK(bt_hal_cbacks, device_found_cb, 3, properties);
+ }
+#endif
+ }
+ /* TODO: Services? */
+ } break;
+
+ case BTA_DM_INQ_RES_EVT: {
+ /* inquiry result */
+ bt_bdname_t bdname;
+ bt_bdaddr_t bdaddr;
+ uint8_t remote_name_len;
+ tBTA_SERVICE_MASK services = 0;
+ bdstr_t bdstr;
+
+ p_search_data = (tBTA_DM_SEARCH*)p_param;
+ bdcpy(bdaddr.address, p_search_data->inq_res.bd_addr);
+
+ BTIF_TRACE_DEBUG("%s() %s device_type = 0x%x\n", __func__,
+ bdaddr_to_string(&bdaddr, bdstr, sizeof(bdstr)),
+ p_search_data->inq_res.device_type);
+ bdname.name[0] = 0;
+
+ if (!check_eir_remote_name(p_search_data, bdname.name, &remote_name_len))
+ check_cached_remote_name(p_search_data, bdname.name, &remote_name_len);
+
+ /* Check EIR for remote name and services */
+ if (p_search_data->inq_res.p_eir) {
+ BTA_GetEirService(p_search_data->inq_res.p_eir,
+ p_search_data->inq_res.eir_len, &services);
+ BTIF_TRACE_DEBUG("%s()EIR BTA services = %08X", __func__,
+ (uint32_t)services);
+ /* TODO: Get the service list and check to see which uuids we got and
+ * send it back to the client. */
+ }
+
+ {
+ bt_property_t properties[5];
+ bt_device_type_t dev_type;
+ uint32_t num_properties = 0;
+ bt_status_t status;
+ int addr_type = 0;
+
+ memset(properties, 0, sizeof(properties));
+ /* BD_ADDR */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDADDR, sizeof(bdaddr), &bdaddr);
+ num_properties++;
+ /* BD_NAME */
+ /* Don't send BDNAME if it is empty */
+ if (bdname.name[0]) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_BDNAME,
+ strlen((char*)bdname.name), &bdname);
+ num_properties++;
+ }
+
+ /* DEV_CLASS */
+ uint32_t cod = devclass2uint(p_search_data->inq_res.dev_class);
+ BTIF_TRACE_DEBUG("%s cod is 0x%06x", __func__, cod);
+ if (cod != 0) {
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_CLASS_OF_DEVICE, sizeof(cod),
+ &cod);
+ num_properties++;
+ }
+
+ /* DEV_TYPE */
+ /* FixMe: Assumption is that bluetooth.h and BTE enums match */
+
+ /* Verify if the device is dual mode in NVRAM */
+ int stored_device_type = 0;
+ if (btif_get_device_type(bdaddr.address, &stored_device_type) &&
+ ((stored_device_type != BT_DEVICE_TYPE_BREDR &&
+ p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BREDR) ||
+ (stored_device_type != BT_DEVICE_TYPE_BLE &&
+ p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE))) {
+ dev_type = (bt_device_type_t)BT_DEVICE_TYPE_DUMO;
+ } else {
+ dev_type = (bt_device_type_t)p_search_data->inq_res.device_type;
+ }
+
+ if (p_search_data->inq_res.device_type == BT_DEVICE_TYPE_BLE)
+ addr_type = p_search_data->inq_res.ble_addr_type;
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_TYPE_OF_DEVICE, sizeof(dev_type),
+ &dev_type);
+ num_properties++;
+ /* RSSI */
+ BTIF_STORAGE_FILL_PROPERTY(&properties[num_properties],
+ BT_PROPERTY_REMOTE_RSSI, sizeof(int8_t),
+ &(p_search_data->inq_res.rssi));
+ num_properties++;
+
+ status =
+ btif_storage_add_remote_device(&bdaddr, num_properties, properties);
+ ASSERTC(status == BT_STATUS_SUCCESS,
+ "failed to save remote device (inquiry)", status);
+ status = btif_storage_set_remote_addr_type(&bdaddr, addr_type);
+ ASSERTC(status == BT_STATUS_SUCCESS,
+ "failed to save remote addr type (inquiry)", status);
+ /* Callback to notify upper layer of device */
+ HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties);
+ }
+ } break;
+
+ case BTA_DM_INQ_CMPL_EVT: {
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
+ nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
+ } break;
+ case BTA_DM_DISC_CMPL_EVT: {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STOPPED);
+ } break;
+ case BTA_DM_SEARCH_CANCEL_CMPL_EVT: {
+ /* if inquiry is not in progress and we get a cancel event, then
+ * it means we are done with inquiry, but remote_name fetches are in
+ * progress
+ *
+ * if inquiry is in progress, then we don't want to act on this
+ * cancel_cmpl_evt
+ * but instead wait for the cancel_cmpl_evt via the Busy Level
+ *
+ */
+ if (btif_dm_inquiry_in_progress == false) {
+ btgatt_filt_param_setup_t adv_filt_param;
+ memset(&adv_filt_param, 0, sizeof(btgatt_filt_param_setup_t));
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
+ nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STOPPED);
+ }
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_search_services_evt
+ *
+ * Description Executes search services event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_search_services_evt(uint16_t event, char* p_param) {
+ tBTA_DM_SEARCH* p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT("%s: event = %d", __func__, event);
+ switch (event) {
+ case BTA_DM_DISC_RES_EVT: {
+ bt_property_t prop;
+ uint32_t i = 0;
+ bt_bdaddr_t bd_addr;
+ bt_status_t ret;
+
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG("%s:(result=0x%x, services 0x%x)", __func__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ if ((p_data->disc_res.result != BTA_SUCCESS) &&
+ (pairing_cb.state == BT_BOND_STATE_BONDING) &&
+ (pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING)) {
+ BTIF_TRACE_WARNING("%s:SDP failed after bonding re-attempting "
+ "when BTA_DM_DISC_CMPL_EVT is received", __func__);
+ return;
+ }
+ prop.type = BT_PROPERTY_UUIDS;
+ prop.len = 0;
+ if ((p_data->disc_res.result == BTA_SUCCESS) &&
+ (p_data->disc_res.num_uuids > 0)) {
+ prop.val = p_data->disc_res.p_uuid_list;
+ prop.len = p_data->disc_res.num_uuids * MAX_UUID_SIZE;
+ for (i = 0; i < p_data->disc_res.num_uuids; i++) {
+ char temp[256];
+ uuid_to_string_legacy(
+ (bt_uuid_t*)(p_data->disc_res.p_uuid_list + (i * MAX_UUID_SIZE)),
+ temp, sizeof(temp));
+ LOG_INFO(LOG_TAG, "%s index:%d uuid:%s", __func__, i, temp);
+ }
+ }
+
+ /* onUuidChanged requires getBondedDevices to be populated.
+ ** bond_state_changed needs to be sent prior to remote_device_property
+ */
+ if ((pairing_cb.state == BT_BOND_STATE_BONDING) &&
+ ((bdcmp(p_data->disc_res.bd_addr, pairing_cb.bd_addr) == 0) ||
+ (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) ==
+ 0)) &&
+ pairing_cb.sdp_attempts > 0) {
+ BTIF_TRACE_DEBUG(
+ "%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
+ __func__);
+ pairing_cb.sdp_attempts = 0;
+
+ // If bonding occured due to cross-key pairing, send bonding callback
+ // for static address now
+ if (bdcmp(p_data->disc_res.bd_addr, pairing_cb.static_bdaddr.address) ==
+ 0)
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr,
+ BT_BOND_STATE_BONDING);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDED);
+ }
+
+ if (p_data->disc_res.num_uuids != 0) {
+ /* Also write this to the NVRAM */
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed",
+ ret);
+ /* Send the event to the BTIF */
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+ &bd_addr, 1, &prop);
+ }
+ } break;
+
+ case BTA_DM_DISC_CMPL_EVT: {
+ /* fixme */
+ /** M: retry when BTA_DM_DISC_CMPL_EVT is received @{ */
+ if ((pairing_cb.state == BT_BOND_STATE_BONDING ) &&
+ (pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING)) {
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ pairing_cb.sdp_attempts++;
+ btif_dm_get_remote_services(&bd_addr);
+ }
+ /** @} */
+ }break;
+
+ case BTA_DM_SEARCH_CANCEL_CMPL_EVT:
+ /* no-op */
+ break;
+
+ case BTA_DM_DISC_BLE_RES_EVT: {
+ BTIF_TRACE_DEBUG("%s:, services 0x%x)", __func__,
+ p_data->disc_ble_res.service.uu.uuid16);
+ bt_uuid_t uuid;
+ int i = 0;
+ int j = 15;
+ int num_properties = 0;
+ if (p_data->disc_ble_res.service.uu.uuid16 == UUID_SERVCLASS_LE_HID) {
+ BTIF_TRACE_DEBUG("%s: Found HOGP UUID", __func__);
+ bt_property_t prop[2];
+ bt_bdaddr_t bd_addr;
+ char temp[256];
+ bt_status_t ret;
+
+ bta_gatt_convert_uuid16_to_uuid128(
+ uuid.uu, p_data->disc_ble_res.service.uu.uuid16);
+
+ while (i < j) {
+ unsigned char c = uuid.uu[j];
+ uuid.uu[j] = uuid.uu[i];
+ uuid.uu[i] = c;
+ i++;
+ j--;
+ }
+
+ uuid_to_string_legacy(&uuid, temp, sizeof(temp));
+ LOG_INFO(LOG_TAG, "%s uuid:%s", __func__, temp);
+
+ bdcpy(bd_addr.address, p_data->disc_ble_res.bd_addr);
+ prop[0].type = BT_PROPERTY_UUIDS;
+ prop[0].val = uuid.uu;
+ prop[0].len = MAX_UUID_SIZE;
+
+ /* Also write this to the NVRAM */
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed",
+ ret);
+ num_properties++;
+
+ /* Remote name update */
+ if (strnlen((const char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN)) {
+ prop[1].type = BT_PROPERTY_BDNAME;
+ prop[1].val = p_data->disc_ble_res.bd_name;
+ prop[1].len =
+ strnlen((char*)p_data->disc_ble_res.bd_name, BD_NAME_LEN);
+
+ ret = btif_storage_set_remote_device_property(&bd_addr, &prop[1]);
+ ASSERTC(ret == BT_STATUS_SUCCESS,
+ "failed to save remote device property", ret);
+ num_properties++;
+ }
+
+ /* Send the event to the BTIF */
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+ &bd_addr, num_properties, prop);
+ }
+ } break;
+
+ default: { ASSERTC(0, "unhandled search services event", event); } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_remote_service_record_evt
+ *
+ * Description Executes search service record event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_remote_service_record_evt(uint16_t event, char* p_param) {
+ tBTA_DM_SEARCH* p_data = (tBTA_DM_SEARCH*)p_param;
+
+ BTIF_TRACE_EVENT("%s: event = %d", __func__, event);
+ switch (event) {
+ case BTA_DM_DISC_RES_EVT: {
+ bt_service_record_t rec;
+ bt_property_t prop;
+ bt_bdaddr_t bd_addr;
+
+ memset(&rec, 0, sizeof(bt_service_record_t));
+ bdcpy(bd_addr.address, p_data->disc_res.bd_addr);
+
+ BTIF_TRACE_DEBUG("%s:(result=0x%x, services 0x%x)", __func__,
+ p_data->disc_res.result, p_data->disc_res.services);
+ prop.type = BT_PROPERTY_SERVICE_RECORD;
+ prop.val = (void*)&rec;
+ prop.len = sizeof(rec);
+
+ /* disc_res.result is overloaded with SCN. Cannot check result */
+ p_data->disc_res.services &= ~BTA_USER_SERVICE_MASK;
+ /* TODO: Get the UUID as well */
+ rec.channel = p_data->disc_res.result - 3;
+ /* TODO: Need to get the service name using p_raw_data */
+ rec.name[0] = 0;
+
+ HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, BT_STATUS_SUCCESS,
+ &bd_addr, 1, &prop);
+ } break;
+
+ default: {
+ ASSERTC(0, "unhandled remote service record event", event);
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_upstreams_cback
+ *
+ * Description Executes UPSTREAMS events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_DM_SEC* p_data = (tBTA_DM_SEC*)p_param;
+ tBTA_SERVICE_MASK service_mask;
+ uint32_t i;
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_EVENT("%s: ev: %s", __func__, dump_dm_event(event));
+
+ switch (event) {
+ case BTA_DM_ENABLE_EVT: {
+ BD_NAME bdname;
+ bt_status_t status;
+ bt_property_t prop;
+ prop.type = BT_PROPERTY_BDNAME;
+ prop.len = BD_NAME_LEN;
+ prop.val = (void*)bdname;
+
+ status = btif_storage_get_adapter_property(&prop);
+ if (status == BT_STATUS_SUCCESS) {
+ /* A name exists in the storage. Make this the device name */
+ BTA_DmSetDeviceName((char*)prop.val);
+ } else {
+ /* Storage does not have a name yet.
+ * Use the default name and write it to the chip
+ */
+ BTA_DmSetDeviceName(btif_get_default_local_name());
+ }
+
+ /* Enable local privacy */
+ BTA_DmBleConfigLocalPrivacy(BLE_LOCAL_PRIVACY_ENABLED);
+
+ /* for each of the enabled services in the mask, trigger the profile
+ * enable */
+ service_mask = btif_get_enabled_services_mask();
+ for (i = 0; i <= BTA_MAX_SERVICE_ID; i++) {
+ if (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) {
+ btif_in_execute_service_request(i, true);
+ }
+ }
+ /* clear control blocks */
+ memset(&pairing_cb, 0, sizeof(btif_dm_pairing_cb_t));
+ pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+
+ /* This function will also trigger the adapter_properties_cb
+ ** and bonded_devices_info_cb
+ */
+ btif_storage_load_bonded_devices();
+
+ btif_enable_bluetooth_evt(p_data->enable.status);
+ } break;
+
+ case BTA_DM_DISABLE_EVT:
+ /* for each of the enabled services in the mask, trigger the profile
+ * disable */
+ service_mask = btif_get_enabled_services_mask();
+ for (i = 0; i <= BTA_MAX_SERVICE_ID; i++) {
+ if (service_mask &
+ (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) {
+ btif_in_execute_service_request(i, false);
+ }
+ }
+ btif_disable_bluetooth_evt();
+ break;
+
+ case BTA_DM_PIN_REQ_EVT:
+ btif_dm_pin_req_evt(&p_data->pin_req);
+ break;
+
+ case BTA_DM_AUTH_CMPL_EVT:
+ btif_dm_auth_cmpl_evt(&p_data->auth_cmpl);
+ break;
+
+ case BTA_DM_BOND_CANCEL_CMPL_EVT:
+ if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ btm_set_bond_type_dev(pairing_cb.bd_addr, BOND_TYPE_UNKNOWN);
+ bond_state_changed((bt_status_t)p_data->bond_cancel_cmpl.result,
+ &bd_addr, BT_BOND_STATE_NONE);
+ }
+ break;
+
+ case BTA_DM_SP_CFM_REQ_EVT:
+ btif_dm_ssp_cfm_req_evt(&p_data->cfm_req);
+ break;
+ case BTA_DM_SP_KEY_NOTIF_EVT:
+ btif_dm_ssp_key_notif_evt(&p_data->key_notif);
+ break;
+
+ case BTA_DM_DEV_UNPAIRED_EVT:
+ bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+ btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+
+/*special handling for HID devices */
+#if (defined(BTA_HH_INCLUDED) && (BTA_HH_INCLUDED == true))
+ btif_hh_remove_device(bd_addr);
+#endif
+#if (defined(BTA_HD_INCLUDED) && (BTA_HD_INCLUDED == TRUE))
+ btif_hd_remove_device(bd_addr);
+#endif
+ btif_storage_remove_bonded_device(&bd_addr);
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_NONE);
+ break;
+
+ case BTA_DM_BUSY_LEVEL_EVT: {
+ if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) {
+ if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED) {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STARTED);
+ btif_dm_inquiry_in_progress = true;
+ } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STOPPED);
+ btif_dm_inquiry_in_progress = false;
+ } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE) {
+ btif_dm_inquiry_in_progress = false;
+ }
+ }
+ } break;
+
+ case BTA_DM_LINK_UP_EVT:
+ bdcpy(bd_addr.address, p_data->link_up.bd_addr);
+ BTIF_TRACE_DEBUG("BTA_DM_LINK_UP_EVT. Sending BT_ACL_STATE_CONNECTED");
+
+ btif_update_remote_version_property(&bd_addr);
+
+ HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+ &bd_addr, BT_ACL_STATE_CONNECTED);
+ break;
+
+ case BTA_DM_LINK_DOWN_EVT:
+ bdcpy(bd_addr.address, p_data->link_down.bd_addr);
+ btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN);
+ btif_av_move_idle(bd_addr);
+ BTIF_TRACE_DEBUG(
+ "BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED");
+ HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS,
+ &bd_addr, BT_ACL_STATE_DISCONNECTED);
+ break;
+
+ case BTA_DM_HW_ERROR_EVT:
+ BTIF_TRACE_ERROR("Received H/W Error. ");
+ /* Flush storage data */
+ btif_config_flush();
+ usleep(100000); /* 100milliseconds */
+ /* Killing the process to force a restart as part of fault tolerance */
+ kill(getpid(), SIGKILL);
+ break;
+
+ case BTA_DM_BLE_KEY_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_KEY_EVT key_type=0x%02x ",
+ p_data->ble_key.key_type);
+
+ /* If this pairing is by-product of local initiated GATT client Read or
+ Write,
+ BTA would not have sent BTA_DM_BLE_SEC_REQ_EVT event and Bond state would
+ not
+ have setup properly. Setup pairing_cb and notify App about Bonding state
+ now*/
+ if (pairing_cb.state != BT_BOND_STATE_BONDING) {
+ BTIF_TRACE_DEBUG(
+ "Bond state not sent to App so far.Notify the app now");
+ bond_state_changed(BT_STATUS_SUCCESS,
+ (bt_bdaddr_t*)p_data->ble_key.bd_addr,
+ BT_BOND_STATE_BONDING);
+ } else if (memcmp(pairing_cb.bd_addr, p_data->ble_key.bd_addr,
+ BD_ADDR_LEN) != 0) {
+ BTIF_TRACE_ERROR("BD mismatch discard BLE key_type=%d ",
+ p_data->ble_key.key_type);
+ break;
+ }
+
+ switch (p_data->ble_key.key_type) {
+ case BTA_LE_KEY_PENC:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PENC");
+ pairing_cb.ble.is_penc_key_rcvd = true;
+ pairing_cb.ble.penc_key = p_data->ble_key.p_key_value->penc_key;
+ break;
+
+ case BTA_LE_KEY_PID:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PID");
+ pairing_cb.ble.is_pid_key_rcvd = true;
+ pairing_cb.ble.pid_key = p_data->ble_key.p_key_value->pid_key;
+ break;
+
+ case BTA_LE_KEY_PCSRK:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_PCSRK");
+ pairing_cb.ble.is_pcsrk_key_rcvd = true;
+ pairing_cb.ble.pcsrk_key = p_data->ble_key.p_key_value->pcsrk_key;
+ break;
+
+ case BTA_LE_KEY_LENC:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LENC");
+ pairing_cb.ble.is_lenc_key_rcvd = true;
+ pairing_cb.ble.lenc_key = p_data->ble_key.p_key_value->lenc_key;
+ break;
+
+ case BTA_LE_KEY_LCSRK:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LCSRK");
+ pairing_cb.ble.is_lcsrk_key_rcvd = true;
+ pairing_cb.ble.lcsrk_key = p_data->ble_key.p_key_value->lcsrk_key;
+ break;
+
+ case BTA_LE_KEY_LID:
+ BTIF_TRACE_DEBUG("Rcv BTA_LE_KEY_LID");
+ pairing_cb.ble.is_lidk_key_rcvd = true;
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("unknown BLE key type (0x%02x)",
+ p_data->ble_key.key_type);
+ break;
+ }
+ break;
+ case BTA_DM_BLE_SEC_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_SEC_REQ_EVT. ");
+ btif_dm_ble_sec_req_evt(&p_data->ble_req);
+ break;
+ case BTA_DM_BLE_PASSKEY_NOTIF_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_NOTIF_EVT. ");
+ btif_dm_ble_key_notif_evt(&p_data->key_notif);
+ break;
+ case BTA_DM_BLE_PASSKEY_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. ");
+ btif_dm_ble_passkey_req_evt(&p_data->pin_req);
+ break;
+ case BTA_DM_BLE_NC_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_PASSKEY_REQ_EVT. ");
+ btif_dm_ble_key_nc_req_evt(&p_data->key_notif);
+ break;
+ case BTA_DM_BLE_OOB_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_OOB_REQ_EVT. ");
+ btif_dm_ble_oob_req_evt(&p_data->rmt_oob);
+ break;
+ case BTA_DM_BLE_SC_OOB_REQ_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_SC_OOB_REQ_EVT. ");
+ btif_dm_ble_sc_oob_req_evt(&p_data->rmt_oob);
+ break;
+ case BTA_DM_BLE_LOCAL_IR_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
+ ble_local_key_cb.is_id_keys_rcvd = true;
+ memcpy(&ble_local_key_cb.id_keys.irk[0], &p_data->ble_id_keys.irk[0],
+ sizeof(BT_OCTET16));
+ memcpy(&ble_local_key_cb.id_keys.ir[0], &p_data->ble_id_keys.ir[0],
+ sizeof(BT_OCTET16));
+ memcpy(&ble_local_key_cb.id_keys.dhk[0], &p_data->ble_id_keys.dhk[0],
+ sizeof(BT_OCTET16));
+ btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.irk[0],
+ BTIF_DM_LE_LOCAL_KEY_IRK, BT_OCTET16_LEN);
+ btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.ir[0],
+ BTIF_DM_LE_LOCAL_KEY_IR, BT_OCTET16_LEN);
+ btif_storage_add_ble_local_key((char*)&ble_local_key_cb.id_keys.dhk[0],
+ BTIF_DM_LE_LOCAL_KEY_DHK, BT_OCTET16_LEN);
+ break;
+ case BTA_DM_BLE_LOCAL_ER_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_ER_EVT. ");
+ ble_local_key_cb.is_er_rcvd = true;
+ memcpy(&ble_local_key_cb.er[0], &p_data->ble_er[0], sizeof(BT_OCTET16));
+ btif_storage_add_ble_local_key((char*)&ble_local_key_cb.er[0],
+ BTIF_DM_LE_LOCAL_KEY_ER, BT_OCTET16_LEN);
+ break;
+
+ case BTA_DM_BLE_AUTH_CMPL_EVT:
+ BTIF_TRACE_DEBUG("BTA_DM_BLE_AUTH_CMPL_EVT. ");
+ btif_dm_ble_auth_cmpl_evt(&p_data->auth_cmpl);
+ break;
+
+ case BTA_DM_LE_FEATURES_READ: {
+ tBTM_BLE_VSC_CB cmn_vsc_cb;
+ bt_local_le_features_t local_le_features;
+ char buf[512];
+ bt_property_t prop;
+ prop.type = BT_PROPERTY_LOCAL_LE_FEATURES;
+ prop.val = (void*)buf;
+ prop.len = sizeof(buf);
+
+ /* LE features are not stored in storage. Should be retrived from stack */
+ BTM_BleGetVendorCapabilities(&cmn_vsc_cb);
+ local_le_features.local_privacy_enabled = BTM_BleLocalPrivacyEnabled();
+
+ prop.len = sizeof(bt_local_le_features_t);
+ if (cmn_vsc_cb.filter_support == 1)
+ local_le_features.max_adv_filter_supported = cmn_vsc_cb.max_filter;
+ else
+ local_le_features.max_adv_filter_supported = 0;
+ local_le_features.max_adv_instance = cmn_vsc_cb.adv_inst_max;
+ local_le_features.max_irk_list_size = cmn_vsc_cb.max_irk_list_sz;
+ local_le_features.rpa_offload_supported = cmn_vsc_cb.rpa_offloading;
+ local_le_features.activity_energy_info_supported =
+ cmn_vsc_cb.energy_support;
+ local_le_features.scan_result_storage_size =
+ cmn_vsc_cb.tot_scan_results_strg;
+ local_le_features.version_supported = cmn_vsc_cb.version_supported;
+ local_le_features.total_trackable_advertisers =
+ cmn_vsc_cb.total_trackable_advertisers;
+
+ local_le_features.extended_scan_support =
+ cmn_vsc_cb.extended_scan_support > 0;
+ local_le_features.debug_logging_supported =
+ cmn_vsc_cb.debug_logging_supported > 0;
+
+ const controller_t* controller = controller_get_interface();
+
+ local_le_features.le_2m_phy_supported = controller->supports_ble_2m_phy();
+ local_le_features.le_coded_phy_supported =
+ controller->supports_ble_coded_phy();
+ local_le_features.le_extended_advertising_supported =
+ controller->supports_ble_extended_advertising();
+ local_le_features.le_periodic_advertising_supported =
+ controller->supports_ble_periodic_advertising();
+ local_le_features.le_maximum_advertising_data_length =
+ controller->get_ble_maxium_advertising_data_length();
+
+ memcpy(prop.val, &local_le_features, prop.len);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+ &prop);
+ break;
+ }
+
+ case BTA_DM_ENER_INFO_READ: {
+ btif_activity_energy_info_cb_t* p_ener_data =
+ (btif_activity_energy_info_cb_t*)p_param;
+ bt_activity_energy_info energy_info;
+ energy_info.status = p_ener_data->status;
+ energy_info.ctrl_state = p_ener_data->ctrl_state;
+ energy_info.rx_time = p_ener_data->rx_time;
+ energy_info.tx_time = p_ener_data->tx_time;
+ energy_info.idle_time = p_ener_data->idle_time;
+ energy_info.energy_used = p_ener_data->energy_used;
+
+ bt_uid_traffic_t* data = uid_set_read_and_clear(uid_set);
+ HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info, data);
+ osi_free(data);
+ break;
+ }
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+
+ case BTA_DM_REPORT_BONDING_EVT:
+ {
+ BTIF_TRACE_DEBUG("Received encryption failed: Report bonding firstly.",__FUNCTION__);
+ bdcpy(bd_addr.address, p_data->delete_key_RC_to_unpair.bd_addr);
+ HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ btif_dm_cb_remove_bond(&bd_addr);
+ break;
+ }
+#endif
+#endif
+
+ case BTA_DM_AUTHORIZE_EVT:
+ case BTA_DM_SIG_STRENGTH_EVT:
+ case BTA_DM_SP_RMT_OOB_EVT:
+ case BTA_DM_SP_KEYPRESS_EVT:
+ case BTA_DM_ROLE_CHG_EVT:
+
+ default:
+ BTIF_TRACE_WARNING("btif_dm_cback : unhandled event (%d)", event);
+ break;
+ }
+
+ btif_dm_data_free(event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_generic_evt
+ *
+ * Description Executes non-BTA upstream events in BTIF context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_generic_evt(uint16_t event, char* p_param) {
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ switch (event) {
+ case BTIF_DM_CB_DISCOVERY_STARTED: {
+ HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
+ BT_DISCOVERY_STARTED);
+ } break;
+
+ case BTIF_DM_CB_CREATE_BOND: {
+ pairing_cb.timeout_retries = NUM_TIMEOUT_RETRIES;
+ btif_dm_create_bond_cb_t* create_bond_cb =
+ (btif_dm_create_bond_cb_t*)p_param;
+ btif_dm_cb_create_bond(&create_bond_cb->bdaddr,
+ create_bond_cb->transport);
+ } break;
+
+ case BTIF_DM_CB_REMOVE_BOND: {
+ btif_dm_cb_remove_bond((bt_bdaddr_t*)p_param);
+ } break;
+
+ case BTIF_DM_CB_HID_REMOTE_NAME: {
+ btif_dm_cb_hid_remote_name((tBTM_REMOTE_DEV_NAME*)p_param);
+ } break;
+
+ case BTIF_DM_CB_BOND_STATE_BONDING: {
+ bond_state_changed(BT_STATUS_SUCCESS, (bt_bdaddr_t*)p_param,
+ BT_BOND_STATE_BONDING);
+ } break;
+ case BTIF_DM_CB_LE_TX_TEST:
+ case BTIF_DM_CB_LE_RX_TEST: {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p_param);
+ HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,
+ (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, 0);
+ } break;
+ case BTIF_DM_CB_LE_TEST_END: {
+ uint8_t status;
+ uint16_t count = 0;
+ STREAM_TO_UINT8(status, p_param);
+ if (status == 0) STREAM_TO_UINT16(count, p_param);
+ HAL_CBACK(bt_hal_cbacks, le_test_mode_cb,
+ (status == 0) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL, count);
+ } break;
+ default: {
+ BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bte_dm_evt
+ *
+ * Description Switches context from BTE to BTIF for all DM events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
+ /* switch context to btif task context (copy full union size for convenience)
+ */
+ bt_status_t status = btif_transfer_context(
+ btif_dm_upstreams_evt, (uint16_t)event, (char*)p_data,
+ sizeof(tBTA_DM_SEC), btif_dm_data_copy);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function bte_search_devices_evt
+ *
+ * Description Switches context from BTE to BTIF for DM search events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event,
+ tBTA_DM_SEARCH* p_data) {
+ uint16_t param_len = 0;
+
+ if (p_data) param_len += sizeof(tBTA_DM_SEARCH);
+ /* Allocate buffer to hold the pointers (deep copy). The pointers will point
+ * to the end of the tBTA_DM_SEARCH */
+ switch (event) {
+ case BTA_DM_INQ_RES_EVT: {
+ if (p_data->inq_res.p_eir) param_len += HCI_EXT_INQ_RESPONSE_LEN;
+ } break;
+
+ case BTA_DM_DISC_RES_EVT: {
+ if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
+ param_len += p_data->disc_res.raw_data_size;
+ } break;
+ }
+ BTIF_TRACE_DEBUG("%s event=%s param_len=%d", __func__,
+ dump_dm_search_event(event), param_len);
+
+ /* if remote name is available in EIR, set teh flag so that stack doesnt
+ * trigger RNR */
+ if (event == BTA_DM_INQ_RES_EVT)
+ p_data->inq_res.remt_name_not_required =
+ check_eir_remote_name(p_data, NULL, NULL);
+
+ btif_transfer_context(
+ btif_dm_search_devices_evt, (uint16_t)event, (char*)p_data, param_len,
+ (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bte_dm_search_services_evt
+ *
+ * Description Switches context from BTE to BTIF for DM search services
+ * event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event,
+ tBTA_DM_SEARCH* p_data) {
+ uint16_t param_len = 0;
+ if (p_data) param_len += sizeof(tBTA_DM_SEARCH);
+ switch (event) {
+ case BTA_DM_DISC_RES_EVT: {
+ if ((p_data->disc_res.result == BTA_SUCCESS) &&
+ (p_data->disc_res.num_uuids > 0)) {
+ param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE);
+ }
+ } break;
+ }
+ /* TODO: The only other member that needs a deep copy is the p_raw_data. But
+ * not sure
+ * if raw_data is needed. */
+ btif_transfer_context(
+ btif_dm_search_services_evt, event, (char*)p_data, param_len,
+ (param_len > sizeof(tBTA_DM_SEARCH)) ? search_services_copy_cb : NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bte_dm_remote_service_record_evt
+ *
+ * Description Switches context from BTE to BTIF for DM search service
+ * record event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event,
+ tBTA_DM_SEARCH* p_data) {
+ /* TODO: The only member that needs a deep copy is the p_raw_data. But not
+ * sure yet if this is needed. */
+ btif_transfer_context(btif_dm_remote_service_record_evt, event, (char*)p_data,
+ sizeof(tBTA_DM_SEARCH), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bta_energy_info_cb
+ *
+ * Description Switches context from BTE to BTIF for DM energy info event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bta_energy_info_cb(tBTA_DM_BLE_TX_TIME_MS tx_time,
+ tBTA_DM_BLE_RX_TIME_MS rx_time,
+ tBTA_DM_BLE_IDLE_TIME_MS idle_time,
+ tBTA_DM_BLE_ENERGY_USED energy_used,
+ tBTA_DM_CONTRL_STATE ctrl_state,
+ tBTA_STATUS status) {
+ BTIF_TRACE_DEBUG(
+ "energy_info_cb-Status:%d,state=%d,tx_t=%ld, rx_t=%ld, "
+ "idle_time=%ld,used=%ld",
+ status, ctrl_state, tx_time, rx_time, idle_time, energy_used);
+
+ btif_activity_energy_info_cb_t btif_cb;
+ btif_cb.status = status;
+ btif_cb.ctrl_state = ctrl_state;
+ btif_cb.tx_time = (uint64_t)tx_time;
+ btif_cb.rx_time = (uint64_t)rx_time;
+ btif_cb.idle_time = (uint64_t)idle_time;
+ btif_cb.energy_used = (uint64_t)energy_used;
+ btif_transfer_context(btif_dm_upstreams_evt, BTA_DM_ENER_INFO_READ,
+ (char*)&btif_cb, sizeof(btif_activity_energy_info_cb_t),
+ NULL);
+}
+
+/* Scan filter param config event */
+static void bte_scan_filt_param_cfg_evt(uint8_t ref_value, uint8_t avbl_space,
+ uint8_t action_type, uint8_t status) {
+ /* This event occurs on calling BTA_DmBleCfgFilterCondition internally,
+ ** and that is why there is no HAL callback
+ */
+ if (BTA_SUCCESS != status) {
+ BTIF_TRACE_ERROR("%s, %d", __func__, status);
+ } else {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ }
+}
+
+/*****************************************************************************
+ *
+ * btif api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_dm_start_discovery
+ *
+ * Description Start device discovery/inquiry
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_start_discovery(void) {
+ tBTA_DM_INQ inq_params;
+ tBTA_SERVICE_MASK services = 0;
+
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ /* Cleanup anything remaining on index 0 */
+ do_in_bta_thread(
+ FROM_HERE,
+ base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_DELETE, 0,
+ nullptr, base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
+
+ auto adv_filt_param = std::make_unique<btgatt_filt_param_setup_t>();
+ /* Add an allow-all filter on index 0*/
+ adv_filt_param->dely_mode = IMMEDIATE_DELY_MODE;
+ adv_filt_param->feat_seln = ALLOW_ALL_FILTER;
+ adv_filt_param->filt_logic_type = BTA_DM_BLE_PF_FILT_LOGIC_OR;
+ adv_filt_param->list_logic_type = BTA_DM_BLE_PF_LIST_LOGIC_OR;
+ adv_filt_param->rssi_low_thres = LOWEST_RSSI_VALUE;
+ adv_filt_param->rssi_high_thres = LOWEST_RSSI_VALUE;
+ do_in_bta_thread(
+ FROM_HERE, base::Bind(&BTM_BleAdvFilterParamSetup, BTM_BLE_SCAN_COND_ADD,
+ 0, base::Passed(&adv_filt_param),
+ base::Bind(&bte_scan_filt_param_cfg_evt, 0)));
+
+ /* TODO: Do we need to handle multiple inquiries at the same time? */
+
+ /* Set inquiry params and call API */
+ inq_params.mode = BTA_DM_GENERAL_INQUIRY | BTA_BLE_GENERAL_INQUIRY;
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ inq_params.intl_duration[0] = BTIF_DM_INTERLEAVE_DURATION_BR_ONE;
+ inq_params.intl_duration[1] = BTIF_DM_INTERLEAVE_DURATION_LE_ONE;
+ inq_params.intl_duration[2] = BTIF_DM_INTERLEAVE_DURATION_BR_TWO;
+ inq_params.intl_duration[3] = BTIF_DM_INTERLEAVE_DURATION_LE_TWO;
+#endif
+ inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
+
+ inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
+ inq_params.report_dup = true;
+
+ inq_params.filter_type = BTA_DM_INQ_CLR;
+ /* TODO: Filter device by BDA needs to be implemented here */
+
+ /* Will be enabled to true once inquiry busy level has been received */
+ btif_dm_inquiry_in_progress = false;
+ /* find nearby devices */
+ BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cancel_discovery
+ *
+ * Description Cancels search
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_cancel_discovery(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ BTA_DmSearchCancel();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_create_bond
+ *
+ * Description Initiate bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond(const bt_bdaddr_t* bd_addr, int transport) {
+ btif_dm_create_bond_cb_t create_bond_cb;
+ create_bond_cb.transport = transport;
+ bdcpy(create_bond_cb.bdaddr.address, bd_addr->address);
+
+ bdstr_t bdstr;
+ BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
+ if (pairing_cb.state != BT_BOND_STATE_NONE) return BT_STATUS_BUSY;
+
+ btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND,
+ pairing_cb.state);
+
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
+ (char*)&create_bond_cb,
+ sizeof(btif_dm_create_bond_cb_t), NULL);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_create_bond_out_of_band
+ *
+ * Description Initiate bonding with the specified device using out of band
+ * data
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_create_bond_out_of_band(
+ const bt_bdaddr_t* bd_addr, int transport,
+ const bt_out_of_band_data_t* oob_data) {
+ bdcpy(oob_cb.bdaddr, bd_addr->address);
+ memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
+
+ uint8_t empty[] = {0, 0, 0, 0, 0, 0, 0};
+ // If LE Bluetooth Device Address is provided, use provided address type
+ // value.
+ if (memcmp(oob_data->le_bt_dev_addr, empty, 7) != 0) {
+ /* byte no 7 is address type in LE Bluetooth Address OOB data */
+ uint8_t address_type = oob_data->le_bt_dev_addr[6];
+ if (address_type == BLE_ADDR_PUBLIC || address_type == BLE_ADDR_RANDOM) {
+ // bd_addr->address is already reversed, so use it instead of
+ // oob_data->le_bt_dev_addr
+ BTM_SecAddBleDevice(bd_addr->address, NULL, BT_DEVICE_TYPE_BLE,
+ address_type);
+ }
+ }
+
+ bdstr_t bdstr;
+ BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
+ return btif_dm_create_bond(bd_addr, transport);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_cancel_bond
+ *
+ * Description Initiate bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t* bd_addr) {
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+ btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CANCEL_BOND,
+ pairing_cb.state);
+
+ /* TODO:
+ ** 1. Restore scan modes
+ ** 2. special handling for HID devices
+ */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+ if (pairing_cb.is_ssp) {
+ if (pairing_cb.is_le_only) {
+ BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address,
+ BTA_DM_SEC_PAIR_NOT_SPT);
+ } else {
+ BTA_DmConfirm((uint8_t*)bd_addr->address, false);
+ BTA_DmBondCancel((uint8_t*)bd_addr->address);
+ btif_storage_remove_bonded_device((bt_bdaddr_t*)bd_addr);
+ }
+ } else {
+ if (pairing_cb.is_le_only) {
+ BTA_DmBondCancel((uint8_t*)bd_addr->address);
+ } else {
+ BTA_DmPinReply((uint8_t*)bd_addr->address, false, 0, NULL);
+ }
+ /* Cancel bonding, in case it is in ACL connection setup state */
+ BTA_DmBondCancel((uint8_t*)bd_addr->address);
+ }
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_hh_open_failed
+ *
+ * Description informs the upper layers if the HH have failed during
+ * bonding
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+
+void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr) {
+ if (pairing_cb.state == BT_BOND_STATE_BONDING &&
+ bdcmp(bdaddr->address, pairing_cb.bd_addr) == 0) {
+ bond_state_changed(BT_STATUS_FAIL, bdaddr, BT_BOND_STATE_NONE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_remove_bond
+ *
+ * Description Removes bonding with the specified device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr) {
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT("%s: bd_addr=%s", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+ btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_REMOVE_BOND,
+ pairing_cb.state);
+
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVE_BOND,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_pin_reply
+ *
+ * Description BT legacy pairing - PIN code reply
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+bt_status_t btif_dm_pin_reply(const bt_bdaddr_t* bd_addr, uint8_t accept,
+ uint8_t pin_len, bt_pin_code_t* pin_code) {
+ BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept);
+ if (pin_code == NULL || pin_len > PIN_CODE_LEN) return BT_STATUS_FAIL;
+ if (pairing_cb.is_le_only) {
+ int i;
+ uint32_t passkey = 0;
+ int multi[] = {100000, 10000, 1000, 100, 10, 1};
+ BD_ADDR remote_bd_addr;
+ bdcpy(remote_bd_addr, bd_addr->address);
+ for (i = 0; i < 6; i++) {
+ passkey += (multi[i] * (pin_code->pin[i] - '0'));
+ }
+ BTIF_TRACE_DEBUG("btif_dm_pin_reply: passkey: %d", passkey);
+ BTA_DmBlePasskeyReply(remote_bd_addr, accept, passkey);
+
+ } else {
+ BTA_DmPinReply((uint8_t*)bd_addr->address, accept, pin_len, pin_code->pin);
+ if (accept) pairing_cb.pin_code_len = pin_len;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ssp_reply
+ *
+ * Description BT SSP Reply - Just Works, Numeric Comparison & Passkey
+ * Entry
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_ssp_reply(const bt_bdaddr_t* bd_addr,
+ bt_ssp_variant_t variant, uint8_t accept,
+ UNUSED_ATTR uint32_t passkey) {
+ if (variant == BT_SSP_VARIANT_PASSKEY_ENTRY) {
+ /* This is not implemented in the stack.
+ * For devices with display, this is not needed
+ */
+ BTIF_TRACE_WARNING("%s: Not implemented", __func__);
+ return BT_STATUS_FAIL;
+ }
+ /* BT_SSP_VARIANT_CONSENT & BT_SSP_VARIANT_PASSKEY_CONFIRMATION supported */
+ BTIF_TRACE_EVENT("%s: accept=%d", __func__, accept);
+ if (pairing_cb.is_le_only) {
+ if (pairing_cb.is_le_nc) {
+ BTA_DmBleConfirmReply((uint8_t*)bd_addr->address, accept);
+ } else {
+ if (accept)
+ BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address, BTA_DM_SEC_GRANTED);
+ else
+ BTA_DmBleSecurityGrant((uint8_t*)bd_addr->address,
+ BTA_DM_SEC_PAIR_NOT_SPT);
+ }
+ } else {
+ BTA_DmConfirm((uint8_t*)bd_addr->address, accept);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_adapter_property
+ *
+ * Description Queries the BTA for the adapter property
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) {
+ BTIF_TRACE_EVENT("%s: type=0x%x", __func__, prop->type);
+ switch (prop->type) {
+ case BT_PROPERTY_BDNAME: {
+ bt_bdname_t* bd_name = (bt_bdname_t*)prop->val;
+ strncpy((char*)bd_name->name, (char*)btif_get_default_local_name(),
+ sizeof(bd_name->name) - 1);
+ bd_name->name[sizeof(bd_name->name) - 1] = 0;
+ prop->len = strlen((char*)bd_name->name);
+ } break;
+
+ case BT_PROPERTY_ADAPTER_SCAN_MODE: {
+ /* if the storage does not have it. Most likely app never set it. Default
+ * is NONE */
+ bt_scan_mode_t* mode = (bt_scan_mode_t*)prop->val;
+ *mode = BT_SCAN_MODE_NONE;
+ prop->len = sizeof(bt_scan_mode_t);
+ } break;
+
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT: {
+ uint32_t* tmt = (uint32_t*)prop->val;
+ *tmt = 120; /* default to 120s, if not found in NV */
+ prop->len = sizeof(uint32_t);
+ } break;
+
+ default:
+ prop->len = 0;
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_services
+ *
+ * Description Start SDP to get remote services
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services(bt_bdaddr_t* remote_addr) {
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+ bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+
+ BTA_DmDiscover(remote_addr->address, BTA_ALL_SERVICE_MASK,
+ bte_dm_search_services_evt, true);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_services_transport
+ *
+ * Description Start SDP to get remote services by transport
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_services_by_transport(bt_bdaddr_t* remote_addr,
+ const int transport) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ /* Set the mask extension */
+ tBTA_SERVICE_MASK_EXT mask_ext;
+ mask_ext.num_uuid = 0;
+ mask_ext.p_uuid = NULL;
+ mask_ext.srvc_mask = BTA_ALL_SERVICE_MASK;
+
+ BTA_DmDiscoverByTransport(remote_addr->address, &mask_ext,
+ bte_dm_search_services_evt, true, transport);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_remote_service_record
+ *
+ * Description Start SDP to get remote service record
+ *
+ *
+ * Returns bt_status_t
+ ******************************************************************************/
+bt_status_t btif_dm_get_remote_service_record(bt_bdaddr_t* remote_addr,
+ bt_uuid_t* uuid) {
+ tSDP_UUID sdp_uuid;
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+ bdaddr_to_string(remote_addr, bdstr, sizeof(bdstr)));
+
+ sdp_uuid.len = MAX_UUID_SIZE;
+ memcpy(sdp_uuid.uu.uuid128, uuid->uu, MAX_UUID_SIZE);
+
+ BTA_DmDiscoverUUID(remote_addr->address, &sdp_uuid,
+ bte_dm_remote_service_record_evt, true);
+
+ return BT_STATUS_SUCCESS;
+}
+
+void btif_dm_execute_service_request(uint16_t event, char* p_param) {
+ bool b_enable = false;
+ bt_status_t status;
+ if (event == BTIF_DM_ENABLE_SERVICE) {
+ b_enable = true;
+ }
+ status =
+ btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable);
+ if (status == BT_STATUS_SUCCESS) {
+ bt_property_t property;
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+
+ /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
+ BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
+ sizeof(local_uuids), local_uuids);
+ btif_storage_get_adapter_property(&property);
+ HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, BT_STATUS_SUCCESS, 1,
+ &property);
+ }
+ return;
+}
+
+void btif_dm_proc_io_req(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBTA_IO_CAP* p_io_cap,
+ UNUSED_ATTR tBTA_OOB_DATA* p_oob_data,
+ tBTA_AUTH_REQ* p_auth_req, bool is_orig) {
+ uint8_t yes_no_bit = BTA_AUTH_SP_YES & *p_auth_req;
+ /* if local initiated:
+ ** 1. set DD + MITM
+ ** if remote initiated:
+ ** 1. Copy over the auth_req from peer's io_rsp
+ ** 2. Set the MITM if peer has it set or if peer has DisplayYesNo
+ *(iPhone)
+ ** as a fallback set MITM+GB if peer had MITM set
+ */
+
+ BTIF_TRACE_DEBUG("+%s: p_auth_req=%d", __func__, *p_auth_req);
+ if (pairing_cb.is_local_initiated) {
+ /* if initing/responding to a dedicated bonding, use dedicate bonding bit */
+ *p_auth_req = BTA_AUTH_DD_BOND | BTA_AUTH_SP_YES;
+ } else if (!is_orig) {
+ /* peer initiated paring. They probably know what they want.
+ ** Copy the mitm from peer device.
+ */
+ BTIF_TRACE_DEBUG("%s: setting p_auth_req to peer's: %d", __func__,
+ pairing_cb.auth_req);
+ *p_auth_req = (pairing_cb.auth_req & BTA_AUTH_BONDS);
+
+ /* copy over the MITM bit as well. In addition if the peer has DisplayYesNo,
+ * force MITM */
+ if ((yes_no_bit) || (pairing_cb.io_cap & BTM_IO_CAP_IO))
+ *p_auth_req |= BTA_AUTH_SP_YES;
+ } else if (yes_no_bit) {
+ /* set the general bonding bit for stored device */
+ *p_auth_req = BTA_AUTH_GEN_BOND | yes_no_bit;
+ }
+ BTIF_TRACE_DEBUG("-%s: p_auth_req=%d", __func__, *p_auth_req);
+}
+
+void btif_dm_proc_io_rsp(UNUSED_ATTR BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
+ UNUSED_ATTR tBTA_OOB_DATA oob_data,
+ tBTA_AUTH_REQ auth_req) {
+ if (auth_req & BTA_AUTH_BONDS) {
+ BTIF_TRACE_DEBUG("%s auth_req:%d", __func__, auth_req);
+ pairing_cb.auth_req = auth_req;
+ pairing_cb.io_cap = io_cap;
+ }
+}
+
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA* p_has_oob_data) {
+ if (is_empty_128bit(oob_cb.oob_data.c192)) {
+ *p_has_oob_data = false;
+ } else {
+ *p_has_oob_data = true;
+ }
+ BTIF_TRACE_DEBUG("%s: *p_has_oob_data=%d", __func__, *p_has_oob_data);
+}
+
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr,
+ tBTA_OOB_DATA* p_has_oob_data,
+ tBTA_LE_AUTH_REQ* p_auth_req) {
+ if (!is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+ !is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+ /* We have LE SC OOB data */
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+ *p_auth_req = ((*p_auth_req) | BTM_LE_AUTH_REQ_SC_ONLY);
+ *p_has_oob_data = true;
+ } else {
+ *p_has_oob_data = false;
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+ __func__);
+ }
+ } else if (!is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+ /* We have security manager TK */
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+ // When using OOB with TK, SC Secure Connections bit must be disabled.
+ tBTA_LE_AUTH_REQ mask = ~BTM_LE_AUTH_REQ_SC_ONLY;
+ *p_auth_req = ((*p_auth_req) & mask);
+
+ *p_has_oob_data = true;
+ } else {
+ *p_has_oob_data = false;
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+ __func__);
+ }
+ } else {
+ *p_has_oob_data = false;
+ }
+ BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data);
+}
+
+#ifdef BTIF_DM_OOB_TEST
+void btif_dm_load_local_oob(void) {
+ char prop_oob[PROPERTY_VALUE_MAX];
+ osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+ if (prop_oob[0] != '3') {
+ if (is_empty_128bit(oob_cb.oob_data.c192)) {
+ BTIF_TRACE_DEBUG("%s: read OOB, call BTA_DmLocalOob()", __func__);
+ BTA_DmLocalOob();
+ }
+ }
+}
+
+void btif_dm_proc_loc_oob(bool valid, BT_OCTET16 c, BT_OCTET16 r) {
+ FILE* fp;
+ const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
+ const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
+ const char* path = NULL;
+ char prop_oob[PROPERTY_VALUE_MAX];
+ BTIF_TRACE_DEBUG("%s: valid=%d", __func__, valid);
+ if (is_empty_128bit(oob_cb.oob_data.c192) && valid) {
+ BTIF_TRACE_DEBUG("save local OOB data in memory");
+ memcpy(oob_cb.oob_data.c192, c, BT_OCTET16_LEN);
+ memcpy(oob_cb.oob_data.r192, r, BT_OCTET16_LEN);
+ osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+ if (prop_oob[0] == '1')
+ path = path_a;
+ else if (prop_oob[0] == '2')
+ path = path_b;
+ if (path) {
+ fp = fopen(path, "wb+");
+ if (fp == NULL) {
+ BTIF_TRACE_DEBUG("%s: failed to save local OOB data to %s", __func__,
+ path);
+ } else {
+ BTIF_TRACE_DEBUG("%s: save local OOB data into file %s", __func__,
+ path);
+ fwrite(c, 1, BT_OCTET16_LEN, fp);
+ fwrite(r, 1, BT_OCTET16_LEN, fp);
+ fclose(fp);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_get_smp_config
+ *
+ * Description Retrieve the SMP pairing options from the bt_stack.conf
+ * file. To provide specific pairing options for the host
+ * add a node with label "SmpOptions" to the config file
+ * and assign it a comma separated list of 5 values in the
+ * format: auth, io, ikey, rkey, ksize, oob
+ * eg: PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+ *
+ * Parameters: tBTE_APPL_CFG*: pointer to struct defining pairing options
+ *
+ * Returns true if the options were successfully read, else false
+ *
+ ******************************************************************************/
+bool btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
+ if (!stack_config_get_interface()->get_pts_smp_options()) {
+ BTIF_TRACE_DEBUG("%s: SMP options not found in configuration", __func__);
+ return false;
+ }
+
+ char conf[64];
+ const char* recv = stack_config_get_interface()->get_pts_smp_options();
+ char* pch;
+ char* endptr;
+
+ strncpy(conf, recv, 64);
+ conf[63] = 0; // null terminate
+
+ pch = strtok(conf, ",");
+ if (pch != NULL)
+ p_cfg->ble_auth_req = (uint8_t)strtoul(pch, &endptr, 16);
+ else
+ return false;
+
+ pch = strtok(NULL, ",");
+ if (pch != NULL)
+ p_cfg->ble_io_cap = (uint8_t)strtoul(pch, &endptr, 16);
+ else
+ return false;
+
+ pch = strtok(NULL, ",");
+ if (pch != NULL)
+ p_cfg->ble_init_key = (uint8_t)strtoul(pch, &endptr, 16);
+ else
+ return false;
+
+ pch = strtok(NULL, ",");
+ if (pch != NULL)
+ p_cfg->ble_resp_key = (uint8_t)strtoul(pch, &endptr, 16);
+ else
+ return false;
+
+ pch = strtok(NULL, ",");
+ if (pch != NULL)
+ p_cfg->ble_max_key_size = (uint8_t)strtoul(pch, &endptr, 16);
+ else
+ return false;
+
+ return true;
+}
+
+bool btif_dm_proc_rmt_oob(BD_ADDR bd_addr, BT_OCTET16 p_c, BT_OCTET16 p_r) {
+ char t[128];
+ FILE* fp;
+ const char* path_a = "/data/misc/bluedroid/LOCAL/a.key";
+ const char* path_b = "/data/misc/bluedroid/LOCAL/b.key";
+ const char* path = NULL;
+ char prop_oob[PROPERTY_VALUE_MAX];
+ bool result = false;
+ bt_bdaddr_t bt_bd_addr;
+ bdcpy(oob_cb.bdaddr, bd_addr);
+ osi_property_get("service.brcm.bt.oob", prop_oob, "3");
+ BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
+ if (prop_oob[0] == '1')
+ path = path_b;
+ else if (prop_oob[0] == '2')
+ path = path_a;
+ if (path) {
+ fp = fopen(path, "rb");
+ if (fp == NULL) {
+ BTIF_TRACE_DEBUG("%s: failed to read OOB keys from %s", __func__, path);
+ return false;
+ } else {
+ BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path);
+ fread(p_c, 1, BT_OCTET16_LEN, fp);
+ fread(p_r, 1, BT_OCTET16_LEN, fp);
+ fclose(fp);
+ }
+ BTIF_TRACE_DEBUG("----%s: true", __func__);
+ snprintf(t, sizeof(t), "%02x:%02x:%02x:%02x:%02x:%02x", oob_cb.bdaddr[0],
+ oob_cb.bdaddr[1], oob_cb.bdaddr[2], oob_cb.bdaddr[3],
+ oob_cb.bdaddr[4], oob_cb.bdaddr[5]);
+ BTIF_TRACE_DEBUG("----%s: peer_bdaddr = %s", __func__, t);
+ snprintf(t, sizeof(t),
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x",
+ p_c[0], p_c[1], p_c[2], p_c[3], p_c[4], p_c[5], p_c[6], p_c[7],
+ p_c[8], p_c[9], p_c[10], p_c[11], p_c[12], p_c[13], p_c[14],
+ p_c[15]);
+ BTIF_TRACE_DEBUG("----%s: c = %s", __func__, t);
+ snprintf(t, sizeof(t),
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x",
+ p_r[0], p_r[1], p_r[2], p_r[3], p_r[4], p_r[5], p_r[6], p_r[7],
+ p_r[8], p_r[9], p_r[10], p_r[11], p_r[12], p_r[13], p_r[14],
+ p_r[15]);
+ BTIF_TRACE_DEBUG("----%s: r = %s", __func__, t);
+ bdcpy(bt_bd_addr.address, bd_addr);
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_BOND_STATE_BONDING,
+ (char*)&bt_bd_addr, sizeof(bt_bdaddr_t), NULL);
+ result = true;
+ }
+ BTIF_TRACE_DEBUG("%s: result=%d", __func__, result);
+ return result;
+}
+#endif /* BTIF_DM_OOB_TEST */
+
+static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ int dev_type;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ /* Remote name update */
+ if (!btif_get_device_type(p_ssp_key_notif->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BLE;
+ }
+ btif_dm_update_ble_remote_properties(p_ssp_key_notif->bd_addr,
+ p_ssp_key_notif->bd_name,
+ (tBT_DEVICE_TYPE)dev_type);
+ bdcpy(bd_addr.address, p_ssp_key_notif->bd_addr);
+ memcpy(bd_name.name, p_ssp_key_notif->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = false;
+ cod = COD_UNCLASSIFIED;
+
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+ BT_SSP_VARIANT_PASSKEY_NOTIFICATION, p_ssp_key_notif->passkey);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ble_auth_cmpl_evt
+ *
+ * Description Executes authentication complete event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_ble_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
+ /* Save link key, if not temporary */
+ bt_bdaddr_t bd_addr;
+ bt_status_t status = BT_STATUS_FAIL;
+ bt_bond_state_t state = BT_BOND_STATE_NONE;
+
+ bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+
+ /* Clear OOB data */
+ memset(&oob_cb, 0, sizeof(oob_cb));
+
+ if ((p_auth_cmpl->success == true) && (p_auth_cmpl->key_present)) {
+ /* store keys */
+ }
+ if (p_auth_cmpl->success) {
+ status = BT_STATUS_SUCCESS;
+ state = BT_BOND_STATE_BONDED;
+ int addr_type;
+ bt_bdaddr_t bdaddr;
+ bdcpy(bdaddr.address, p_auth_cmpl->bd_addr);
+ if (btif_storage_get_remote_addr_type(&bdaddr, &addr_type) !=
+ BT_STATUS_SUCCESS)
+ btif_storage_set_remote_addr_type(&bdaddr, p_auth_cmpl->addr_type);
+
+ /* Test for temporary bonding */
+ if (btm_get_bond_type_dev(p_auth_cmpl->bd_addr) == BOND_TYPE_TEMPORARY) {
+ BTIF_TRACE_DEBUG("%s: sending BT_BOND_STATE_NONE for Temp pairing",
+ __func__);
+ btif_storage_remove_bonded_device(&bdaddr);
+ state = BT_BOND_STATE_NONE;
+ } else {
+ btif_dm_save_ble_bonding_keys();
+ BTA_GATTC_Refresh(bd_addr.address);
+ btif_dm_get_remote_services_by_transport(&bd_addr, BTA_GATT_TRANSPORT_LE);
+ }
+ } else {
+ /*Map the HCI fail reason to bt status */
+ switch (p_auth_cmpl->fail_reason) {
+ case BTA_DM_AUTH_SMP_PAIR_AUTH_FAIL:
+ case BTA_DM_AUTH_SMP_CONFIRM_VALUE_FAIL:
+ case BTA_DM_AUTH_SMP_UNKNOWN_ERR:
+ case BTA_DM_AUTH_SMP_CONN_TOUT:
+ btif_dm_remove_ble_bonding_keys();
+ status = BT_STATUS_AUTH_FAILURE;
+ break;
+ case BTA_DM_AUTH_SMP_PAIR_NOT_SUPPORT:
+ status = BT_STATUS_AUTH_REJECTED;
+ break;
+ default:
+ btif_dm_remove_ble_bonding_keys();
+ status = BT_STATUS_FAIL;
+ break;
+ }
+ }
+ bond_state_changed(status, &bd_addr, state);
+}
+
+void btif_dm_load_ble_local_keys(void) {
+ memset(&ble_local_key_cb, 0, sizeof(btif_dm_local_key_cb_t));
+
+ if (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_ER,
+ (char*)&ble_local_key_cb.er[0],
+ BT_OCTET16_LEN) == BT_STATUS_SUCCESS) {
+ ble_local_key_cb.is_er_rcvd = true;
+ BTIF_TRACE_DEBUG("%s BLE ER key loaded", __func__);
+ }
+
+ if ((btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IR,
+ (char*)&ble_local_key_cb.id_keys.ir[0],
+ BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_IRK,
+ (char*)&ble_local_key_cb.id_keys.irk[0],
+ BT_OCTET16_LEN) == BT_STATUS_SUCCESS) &&
+ (btif_storage_get_ble_local_key(BTIF_DM_LE_LOCAL_KEY_DHK,
+ (char*)&ble_local_key_cb.id_keys.dhk[0],
+ BT_OCTET16_LEN) == BT_STATUS_SUCCESS)) {
+ ble_local_key_cb.is_id_keys_rcvd = true;
+ BTIF_TRACE_DEBUG("%s BLE ID keys loaded", __func__);
+ }
+}
+void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
+ BT_OCTET16 er,
+ tBTA_BLE_LOCAL_ID_KEYS* p_id_keys) {
+ if (ble_local_key_cb.is_er_rcvd) {
+ memcpy(&er[0], &ble_local_key_cb.er[0], sizeof(BT_OCTET16));
+ *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ER;
+ }
+
+ if (ble_local_key_cb.is_id_keys_rcvd) {
+ memcpy(&p_id_keys->ir[0], &ble_local_key_cb.id_keys.ir[0],
+ sizeof(BT_OCTET16));
+ memcpy(&p_id_keys->irk[0], &ble_local_key_cb.id_keys.irk[0],
+ sizeof(BT_OCTET16));
+ memcpy(&p_id_keys->dhk[0], &ble_local_key_cb.id_keys.dhk[0],
+ sizeof(BT_OCTET16));
+ *p_key_mask |= BTA_BLE_LOCAL_KEY_TYPE_ID;
+ }
+ BTIF_TRACE_DEBUG("%s *p_key_mask=0x%02x", __func__, *p_key_mask);
+}
+
+void btif_dm_save_ble_bonding_keys(void) {
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+
+ if (pairing_cb.ble.is_penc_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.penc_key,
+ BTIF_DM_LE_KEY_PENC,
+ sizeof(tBTM_LE_PENC_KEYS));
+ }
+
+ if (pairing_cb.ble.is_pid_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pid_key,
+ BTIF_DM_LE_KEY_PID,
+ sizeof(tBTM_LE_PID_KEYS));
+ }
+
+ if (pairing_cb.ble.is_pcsrk_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.pcsrk_key,
+ BTIF_DM_LE_KEY_PCSRK,
+ sizeof(tBTM_LE_PCSRK_KEYS));
+ }
+
+ if (pairing_cb.ble.is_lenc_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lenc_key,
+ BTIF_DM_LE_KEY_LENC,
+ sizeof(tBTM_LE_LENC_KEYS));
+ }
+
+ if (pairing_cb.ble.is_lcsrk_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, (char*)&pairing_cb.ble.lcsrk_key,
+ BTIF_DM_LE_KEY_LCSRK,
+ sizeof(tBTM_LE_LCSRK_KEYS));
+ }
+
+ if (pairing_cb.ble.is_lidk_key_rcvd) {
+ btif_storage_add_ble_bonding_key(&bd_addr, NULL, BTIF_DM_LE_KEY_LID, 0);
+ }
+/** M: Add for ble device pair on guest mode @{ */
+ if (is_restricted_mode())
+ {
+ bdstr_t bdstr;
+ bdaddr_to_string(&bd_addr, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG("%s: '%s' ble device pairing will be removed if unrestricted",
+ __func__, bdstr);
+ btif_config_set_int(bdstr, "Restricted", 1);
+ btif_config_save();
+ }
+/** @} */
+}
+
+void btif_dm_remove_ble_bonding_keys(void) {
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ btif_storage_remove_ble_bonding_keys(&bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ble_sec_req_evt
+ *
+ * Description Eprocess security request event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ int dev_type;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+ BTIF_TRACE_DEBUG("%s Discard security request", __func__);
+ return;
+ }
+
+ /* Remote name update */
+ if (!btif_get_device_type(p_ble_req->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BLE;
+ }
+ btif_dm_update_ble_remote_properties(p_ble_req->bd_addr, p_ble_req->bd_name,
+ (tBT_DEVICE_TYPE)dev_type);
+
+ bdcpy(bd_addr.address, p_ble_req->bd_addr);
+ memcpy(bd_name.name, p_ble_req->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+
+ pairing_cb.bond_type = BOND_TYPE_PERSISTENT;
+ pairing_cb.is_le_only = true;
+ pairing_cb.is_le_nc = false;
+ pairing_cb.is_ssp = true;
+ btm_set_bond_type_dev(p_ble_req->bd_addr, pairing_cb.bond_type);
+
+ cod = COD_UNCLASSIFIED;
+
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, cod,
+ BT_SSP_VARIANT_CONSENT, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_ble_passkey_req_evt
+ *
+ * Description Executes pin request event in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ* p_pin_req) {
+ bt_bdaddr_t bd_addr;
+ bt_bdname_t bd_name;
+ uint32_t cod;
+ int dev_type;
+
+ /* Remote name update */
+ if (!btif_get_device_type(p_pin_req->bd_addr, &dev_type)) {
+ dev_type = BT_DEVICE_TYPE_BLE;
+ }
+ btif_dm_update_ble_remote_properties(p_pin_req->bd_addr, p_pin_req->bd_name,
+ (tBT_DEVICE_TYPE)dev_type);
+
+ bdcpy(bd_addr.address, p_pin_req->bd_addr);
+ memcpy(bd_name.name, p_pin_req->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_le_only = true;
+
+ cod = COD_UNCLASSIFIED;
+
+ HAL_CBACK(bt_hal_cbacks, pin_request_cb, &bd_addr, &bd_name, cod, false);
+}
+static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF* p_notif_req) {
+ /* TODO implement key notification for numeric comparison */
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ /* Remote name update */
+ btif_update_remote_properties(p_notif_req->bd_addr, p_notif_req->bd_name,
+ NULL, BT_DEVICE_TYPE_BLE);
+
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, p_notif_req->bd_addr);
+
+ bt_bdname_t bd_name;
+ memcpy(bd_name.name, p_notif_req->bd_name, BD_NAME_LEN);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = false;
+ pairing_cb.is_le_only = true;
+ pairing_cb.is_le_nc = true;
+
+ HAL_CBACK(bt_hal_cbacks, ssp_request_cb, &bd_addr, &bd_name, COD_UNCLASSIFIED,
+ BT_SSP_VARIANT_PASSKEY_CONFIRMATION, p_notif_req->passkey);
+}
+
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, req_oob_type->bd_addr);
+ /* We already checked if OOB data is present in
+ * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+ * do nothing, pairing will timeout.
+ */
+ if (is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+ return;
+ }
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+ __func__);
+ return;
+ }
+
+ /* Remote name update */
+ btif_update_remote_properties(req_oob_type->bd_addr, req_oob_type->bd_name,
+ NULL, BT_DEVICE_TYPE_BLE);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = false;
+ pairing_cb.is_le_only = true;
+ pairing_cb.is_le_nc = false;
+
+ BTM_BleOobDataReply(req_oob_type->bd_addr, 0, 16, oob_cb.oob_data.sm_tk);
+}
+
+static void btif_dm_ble_sc_oob_req_evt(tBTA_DM_SP_RMT_OOB* req_oob_type) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, req_oob_type->bd_addr);
+
+ /* We already checked if OOB data is present in
+ * btif_dm_set_oob_for_le_io_req, but check here again. If it's not present
+ * do nothing, pairing will timeout.
+ */
+ if (is_empty_128bit(oob_cb.oob_data.le_sc_c) &&
+ is_empty_128bit(oob_cb.oob_data.le_sc_r)) {
+ BTIF_TRACE_WARNING("%s: LE SC OOB data is empty", __func__);
+ return;
+ }
+
+ /* make sure OOB data is for this particular device */
+ if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+ BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+ __func__);
+ return;
+ }
+
+ /* Remote name update */
+ btif_update_remote_properties(req_oob_type->bd_addr, req_oob_type->bd_name,
+ NULL, BT_DEVICE_TYPE_BLE);
+
+ bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+ pairing_cb.is_ssp = false;
+ pairing_cb.is_le_only =
+ true; // TODO: we can derive classic pairing from this one
+ pairing_cb.is_le_nc = false;
+
+ BTM_BleSecureConnectionOobDataReply(
+ req_oob_type->bd_addr, oob_cb.oob_data.le_sc_c, oob_cb.oob_data.le_sc_r);
+}
+
+void btif_dm_update_ble_remote_properties(BD_ADDR bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type) {
+ btif_update_remote_properties(bd_addr, bd_name, NULL, dev_type);
+}
+
+static void btif_dm_ble_tx_test_cback(void* p) {
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TX_TEST, (char*)p, 1,
+ NULL);
+}
+
+static void btif_dm_ble_rx_test_cback(void* p) {
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_RX_TEST, (char*)p, 1,
+ NULL);
+}
+
+static void btif_dm_ble_test_end_cback(void* p) {
+ btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_LE_TEST_END, (char*)p,
+ 3, NULL);
+}
+/*******************************************************************************
+ *
+ * Function btif_le_test_mode
+ *
+ * Description Sends a HCI BLE Test command to the Controller
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ *
+ ******************************************************************************/
+bt_status_t btif_le_test_mode(uint16_t opcode, uint8_t* buf, uint8_t len) {
+ switch (opcode) {
+ case HCI_BLE_TRANSMITTER_TEST:
+ if (len != 3) return BT_STATUS_PARM_INVALID;
+ BTM_BleTransmitterTest(buf[0], buf[1], buf[2], btif_dm_ble_tx_test_cback);
+ break;
+ case HCI_BLE_RECEIVER_TEST:
+ if (len != 1) return BT_STATUS_PARM_INVALID;
+ BTM_BleReceiverTest(buf[0], btif_dm_ble_rx_test_cback);
+ break;
+ case HCI_BLE_TEST_END:
+ BTM_BleTestEnd((tBTM_CMPL_CB*)btif_dm_ble_test_end_cback);
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s: Unknown LE Test Mode Command 0x%x", __func__,
+ opcode);
+ return BT_STATUS_UNSUPPORTED;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+void btif_dm_on_disable() {
+ /* cancel any pending pairing requests */
+ if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+ bt_bdaddr_t bd_addr;
+
+ BTIF_TRACE_DEBUG("%s: Cancel pending pairing request", __func__);
+ bdcpy(bd_addr.address, pairing_cb.bd_addr);
+ btif_dm_cancel_bond(&bd_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_dm_read_energy_info
+ *
+ * Description Reads the energy info from controller
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_dm_read_energy_info() { BTA_DmBleGetEnergyInfo(bta_energy_info_cb); }
+
+static char* btif_get_default_local_name() {
+ if (btif_default_local_name[0] == '\0') {
+ int max_len = sizeof(btif_default_local_name) - 1;
+ if (BTM_DEF_LOCAL_NAME[0] != '\0') {
+ strncpy(btif_default_local_name, BTM_DEF_LOCAL_NAME, max_len);
+ } else {
+ char prop_model[PROPERTY_VALUE_MAX];
+ osi_property_get(PROPERTY_PRODUCT_MODEL, prop_model, "");
+ strncpy(btif_default_local_name, prop_model, max_len);
+ }
+ btif_default_local_name[max_len] = '\0';
+ }
+ return btif_default_local_name;
+}
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t* bd_addr,
+ bt_bond_function_t function,
+ bt_bond_state_t state) {
+ std::unique_lock<std::mutex> lock(bond_event_lock);
+
+ btif_bond_event_t* event = &btif_dm_bond_events[btif_events_end_index];
+ memcpy(&event->bd_addr, bd_addr, sizeof(bt_bdaddr_t));
+ event->function = function;
+ event->state = state;
+ clock_gettime(CLOCK_REALTIME, &event->timestamp);
+
+ btif_num_bond_events++;
+ btif_events_end_index =
+ (btif_events_end_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+ if (btif_events_end_index == btif_events_start_index) {
+ btif_events_start_index =
+ (btif_events_start_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+ }
+
+ int type;
+ btif_get_device_type(bd_addr->address, &type);
+
+ system_bt_osi::device_type_t device_type;
+ switch (type) {
+ case BT_DEVICE_TYPE_BREDR:
+ device_type = system_bt_osi::DEVICE_TYPE_BREDR;
+ break;
+ case BT_DEVICE_TYPE_BLE:
+ device_type = system_bt_osi::DEVICE_TYPE_LE;
+ break;
+ case BT_DEVICE_TYPE_DUMO:
+ device_type = system_bt_osi::DEVICE_TYPE_DUMO;
+ break;
+ default:
+ device_type = system_bt_osi::DEVICE_TYPE_UNKNOWN;
+ break;
+ }
+
+ uint32_t cod = get_cod(bd_addr);
+ uint64_t ts =
+ event->timestamp.tv_sec * 1000 + event->timestamp.tv_nsec / 1000000;
+ system_bt_osi::BluetoothMetricsLogger::GetInstance()->LogPairEvent(
+ 0, ts, cod, device_type);
+}
+
+void btif_debug_bond_event_dump(int fd) {
+ std::unique_lock<std::mutex> lock(bond_event_lock);
+ dprintf(fd, "\nBond Events: \n");
+ dprintf(fd, " Total Number of events: %zu\n", btif_num_bond_events);
+ if (btif_num_bond_events > 0)
+ dprintf(fd,
+ " Time BD_ADDR Function State\n");
+
+ for (size_t i = btif_events_start_index; i != btif_events_end_index;
+ i = (i + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1)) {
+ btif_bond_event_t* event = &btif_dm_bond_events[i];
+
+ char eventtime[20];
+ char temptime[20];
+ struct tm* tstamp = localtime(&event->timestamp.tv_sec);
+ strftime(temptime, sizeof(temptime), "%H:%M:%S", tstamp);
+ snprintf(eventtime, sizeof(eventtime), "%s.%03ld", temptime,
+ event->timestamp.tv_nsec / 1000000);
+
+ char bdaddr[18];
+ bdaddr_to_string(&event->bd_addr, bdaddr, sizeof(bdaddr));
+
+ const char* func_name;
+ switch (event->function) {
+ case BTIF_DM_FUNC_CREATE_BOND:
+ func_name = "btif_dm_create_bond";
+ break;
+ case BTIF_DM_FUNC_REMOVE_BOND:
+ func_name = "btif_dm_remove_bond";
+ break;
+ case BTIF_DM_FUNC_BOND_STATE_CHANGED:
+ func_name = "bond_state_changed ";
+ break;
+ default:
+ func_name = "Invalid value ";
+ break;
+ }
+
+ const char* bond_state;
+ switch (event->state) {
+ case BT_BOND_STATE_NONE:
+ bond_state = "BOND_STATE_NONE";
+ break;
+ case BT_BOND_STATE_BONDING:
+ bond_state = "BOND_STATE_BONDING";
+ break;
+ case BT_BOND_STATE_BONDED:
+ bond_state = "BOND_STATE_BONDED";
+ break;
+ default:
+ bond_state = "Invalid bond state";
+ break;
+ }
+ dprintf(fd, " %s %s %s %s\n", eventtime, bdaddr, func_name, bond_state);
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_gatt.cc b/mtkbt/code/bt/btif/src/btif_gatt.cc
new file mode 100755
index 0000000..67296f9
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_gatt.cc
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_gatt.c
+ *
+ * Description: GATT Profile Bluetooth Interface
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+
+const btgatt_callbacks_t* bt_gatt_callbacks = NULL;
+
+/*******************************************************************************
+ *
+ * Function btif_gatt_init
+ *
+ * Description Initializes the GATT interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t btif_gatt_init(const btgatt_callbacks_t* callbacks) {
+ bt_gatt_callbacks = callbacks;
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_gatt_cleanup
+ *
+ * Description Closes the GATT interface
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_gatt_cleanup(void) {
+ if (bt_gatt_callbacks) bt_gatt_callbacks = NULL;
+
+ BTA_GATTC_Disable();
+ BTA_GATTS_Disable();
+}
+
+static btgatt_interface_t btgattInterface = {
+ sizeof(btgattInterface),
+
+ btif_gatt_init,
+ btif_gatt_cleanup,
+
+ &btgattClientInterface,
+ &btgattServerInterface,
+ nullptr, // filled in btif_gatt_get_interface
+ nullptr // filled in btif_gatt_get_interface
+};
+
+/*******************************************************************************
+ *
+ * Function btif_gatt_get_interface
+ *
+ * Description Get the gatt callback interface
+ *
+ * Returns btgatt_interface_t
+ *
+ ******************************************************************************/
+const btgatt_interface_t* btif_gatt_get_interface() {
+ // TODO(jpawlowski) right now initializing advertiser field in static
+ // structure cause explosion of dependencies. It must be initialized here
+ // until those dependencies are properly abstracted for tests.
+ btgattInterface.scanner = get_ble_scanner_instance();
+ btgattInterface.advertiser = get_ble_advertiser_instance();
+ return &btgattInterface;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_gatt_client.cc b/mtkbt/code/bt/btif/src/btif_gatt_client.cc
new file mode 100755
index 0000000..70b7d4e
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_gatt_client.cc
@@ -0,0 +1,638 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_gatt_client.c
+ *
+ * Description: GATT client implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gattc"
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/threading/thread.h>
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <stdlib.h>
+#include <string.h>
+#include "device/include/controller.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include <hardware/bt_gatt.h>
+
+#include "bta_api.h"
+#include "bta_closure_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+#include "vendor_api.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+extern bt_status_t btif_gattc_test_command_impl(int command,
+ btgatt_test_params_t* params);
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define CLI_CBACK_IN_JNI(P_CBACK, ...) \
+ do { \
+ if (bt_gatt_callbacks && bt_gatt_callbacks->client->P_CBACK) { \
+ BTIF_TRACE_API("HAL bt_gatt_callbacks->client->%s", #P_CBACK); \
+ do_in_jni_thread(Bind(bt_gatt_callbacks->client->P_CBACK, __VA_ARGS__)); \
+ } else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ } while (0)
+
+#define CHECK_BTGATT_INIT() \
+ do { \
+ if (bt_gatt_callbacks == NULL) { \
+ LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } else { \
+ LOG_VERBOSE(LOG_TAG, "%s", __func__); \
+ } \
+ } while (0)
+
+#define BLE_RESOLVE_ADDR_MSB \
+ 0x40 /* bit7, bit6 is 01 to be resolvable random \
+ */
+#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
+#define BTM_BLE_IS_RESOLVE_BDA(x) \
+ (((x)[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+namespace {
+
+uint8_t rssi_request_client_if;
+
+void btif_gattc_upstreams_evt(uint16_t event, char* p_param) {
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+ tBTA_GATTC* p_data = (tBTA_GATTC*)p_param;
+ switch (event) {
+ case BTA_GATTC_DEREG_EVT:
+ break;
+
+ case BTA_GATTC_EXEC_EVT: {
+ HAL_CBACK(bt_gatt_callbacks, client->execute_write_cb,
+ p_data->exec_cmpl.conn_id, p_data->exec_cmpl.status);
+ break;
+ }
+
+ case BTA_GATTC_SEARCH_CMPL_EVT: {
+ HAL_CBACK(bt_gatt_callbacks, client->search_complete_cb,
+ p_data->search_cmpl.conn_id, p_data->search_cmpl.status);
+ break;
+ }
+
+ case BTA_GATTC_NOTIF_EVT: {
+ btgatt_notify_params_t data;
+
+ bdcpy(data.bda.address, p_data->notify.bda);
+ memcpy(data.value, p_data->notify.value, p_data->notify.len);
+
+ data.handle = p_data->notify.handle;
+ data.is_notify = p_data->notify.is_notify;
+ data.len = p_data->notify.len;
+
+ HAL_CBACK(bt_gatt_callbacks, client->notify_cb, p_data->notify.conn_id,
+ &data);
+
+ if (p_data->notify.is_notify == false)
+ BTA_GATTC_SendIndConfirm(p_data->notify.conn_id, p_data->notify.handle);
+
+ break;
+ }
+
+ case BTA_GATTC_OPEN_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->open.remote_bda);
+
+ HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id,
+ p_data->open.status, p_data->open.client_if, &bda);
+
+ if (GATT_DEF_BLE_MTU_SIZE != p_data->open.mtu && p_data->open.mtu) {
+ HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb,
+ p_data->open.conn_id, p_data->open.status, p_data->open.mtu);
+ }
+
+ if (p_data->open.status == BTA_GATT_OK)
+ btif_gatt_check_encrypted_link(p_data->open.remote_bda,
+ p_data->open.transport);
+ break;
+ }
+
+ case BTA_GATTC_CLOSE_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->close.remote_bda);
+ HAL_CBACK(bt_gatt_callbacks, client->close_cb, p_data->close.conn_id,
+ p_data->status, p_data->close.client_if, &bda);
+ break;
+ }
+
+ case BTA_GATTC_ACL_EVT:
+ LOG_DEBUG(LOG_TAG, "BTA_GATTC_ACL_EVT: status = %d", p_data->status);
+ /* Ignore for now */
+ break;
+
+ case BTA_GATTC_CANCEL_OPEN_EVT:
+ break;
+
+ case BTA_GATTC_CFG_MTU_EVT: {
+ HAL_CBACK(bt_gatt_callbacks, client->configure_mtu_cb,
+ p_data->cfg_mtu.conn_id, p_data->cfg_mtu.status,
+ p_data->cfg_mtu.mtu);
+ break;
+ }
+
+ case BTA_GATTC_CONGEST_EVT:
+ HAL_CBACK(bt_gatt_callbacks, client->congestion_cb,
+ p_data->congest.conn_id, p_data->congest.congested);
+ break;
+
+ case BTA_GATTC_PHY_UPDATE_EVT:
+ HAL_CBACK(bt_gatt_callbacks, client->phy_updated_cb,
+ p_data->phy_update.conn_id, p_data->phy_update.tx_phy,
+ p_data->phy_update.rx_phy, p_data->phy_update.status);
+ break;
+
+ case BTA_GATTC_CONN_UPDATE_EVT:
+ HAL_CBACK(bt_gatt_callbacks, client->conn_updated_cb,
+ p_data->conn_update.conn_id, p_data->conn_update.interval,
+ p_data->conn_update.latency, p_data->conn_update.timeout,
+ p_data->conn_update.status);
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
+ break;
+ }
+}
+
+void bta_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
+ bt_status_t status =
+ btif_transfer_context(btif_gattc_upstreams_evt, (uint16_t)event,
+ (char*)p_data, sizeof(tBTA_GATTC), NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+void btm_read_rssi_cb(tBTM_RSSI_RESULTS* p_result) {
+ if (!p_result) return;
+
+ bt_bdaddr_t* addr = new bt_bdaddr_t;
+ bdcpy(addr->address, p_result->rem_bda);
+ CLI_CBACK_IN_JNI(read_remote_rssi_cb, rssi_request_client_if,
+ base::Owned(addr), p_result->rssi, p_result->status);
+}
+
+/*******************************************************************************
+ * Client API Functions
+ ******************************************************************************/
+
+bt_status_t btif_gattc_register_app(bt_uuid_t* uuid) {
+ CHECK_BTGATT_INIT();
+
+ tBT_UUID bt_uuid;
+ btif_to_bta_uuid(&bt_uuid, uuid);
+
+ return do_in_jni_thread(Bind(
+ [](tBT_UUID bt_uuid) {
+ BTA_GATTC_AppRegister(
+ bta_gattc_cback,
+ base::Bind(
+ [](tBT_UUID bt_uuid, uint8_t client_id, uint8_t status) {
+ do_in_jni_thread(Bind(
+ [](tBT_UUID bt_uuid, uint8_t client_id, uint8_t status) {
+ bt_uuid_t app_uuid;
+ bta_to_btif_uuid(&app_uuid, &bt_uuid);
+ HAL_CBACK(bt_gatt_callbacks, client->register_client_cb,
+ status, client_id, &app_uuid);
+ },
+ bt_uuid, client_id, status));
+ },
+ bt_uuid));
+ },
+ bt_uuid));
+}
+
+void btif_gattc_unregister_app_impl(int client_if) {
+ BTA_GATTC_AppDeregister(client_if);
+}
+
+bt_status_t btif_gattc_unregister_app(int client_if) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&btif_gattc_unregister_app_impl, client_if));
+}
+
+void btif_gattc_open_impl(int client_if, BD_ADDR address, bool is_direct,
+ int transport_p, int initiating_phys) {
+ // Ensure device is in inquiry database
+ int addr_type = 0;
+ int device_type = 0;
+ tBTA_GATT_TRANSPORT transport = (tBTA_GATT_TRANSPORT)BTA_GATT_TRANSPORT_LE;
+
+ if (btif_get_address_type(address, &addr_type) &&
+ btif_get_device_type(address, &device_type) &&
+ device_type != BT_DEVICE_TYPE_BREDR) {
+ BTA_DmAddBleDevice(address, addr_type, device_type);
+ }
+
+ // Check for background connections
+ if (!is_direct) {
+ // Check for privacy 1.0 and 1.1 controller and do not start background
+ // connection if RPA offloading is not supported, since it will not
+ // connect after change of random address
+ if (!controller_get_interface()->supports_ble_privacy() &&
+ (addr_type == BLE_ADDR_RANDOM) && BTM_BLE_IS_RESOLVE_BDA(address)) {
+ tBTM_BLE_VSC_CB vnd_capabilities;
+ BTM_BleGetVendorCapabilities(&vnd_capabilities);
+ if (!vnd_capabilities.rpa_offloading) {
+ HAL_CBACK(bt_gatt_callbacks, client->open_cb, 0, BT_STATUS_UNSUPPORTED,
+ client_if, (bt_bdaddr_t*)&address);
+ return;
+ }
+ }
+ BTA_DmBleStartAutoConn();
+ }
+
+ // Determine transport
+ if (transport_p != GATT_TRANSPORT_AUTO) {
+ transport = transport_p;
+ } else {
+ switch (device_type) {
+ case BT_DEVICE_TYPE_BREDR:
+ transport = BTA_GATT_TRANSPORT_BR_EDR;
+ break;
+
+ case BT_DEVICE_TYPE_BLE:
+ transport = BTA_GATT_TRANSPORT_LE;
+ break;
+
+ case BT_DEVICE_TYPE_DUMO:
+ if (transport_p == GATT_TRANSPORT_LE)
+ transport = BTA_GATT_TRANSPORT_LE;
+ else
+ transport = BTA_GATT_TRANSPORT_BR_EDR;
+ break;
+ }
+ }
+
+ // Connect!
+ BTIF_TRACE_DEBUG("%s Transport=%d, device type=%d, phy=%d", __func__,
+ transport, device_type, initiating_phys);
+ BTA_GATTC_Open(client_if, address, is_direct, transport, false,
+ initiating_phys);
+}
+
+bt_status_t btif_gattc_open(int client_if, const bt_bdaddr_t* bd_addr,
+ bool is_direct, int transport,
+ int initiating_phys) {
+ CHECK_BTGATT_INIT();
+ // Closure will own this value and free it.
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(Bind(&btif_gattc_open_impl, client_if,
+ base::Owned(address), is_direct, transport,
+ initiating_phys));
+}
+
+void btif_gattc_close_impl(int client_if, BD_ADDR address, int conn_id) {
+ // Disconnect established connections
+ if (conn_id != 0)
+ BTA_GATTC_Close(conn_id);
+ else
+ BTA_GATTC_CancelOpen(client_if, address, true);
+
+ // Cancel pending background connections (remove from whitelist)
+ BTA_GATTC_CancelOpen(client_if, address, false);
+}
+
+bt_status_t btif_gattc_close(int client_if, const bt_bdaddr_t* bd_addr,
+ int conn_id) {
+ CHECK_BTGATT_INIT();
+ // Closure will own this value and free it.
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(
+ Bind(&btif_gattc_close_impl, client_if, base::Owned(address), conn_id));
+}
+
+bt_status_t btif_gattc_refresh(int client_if, const bt_bdaddr_t* bd_addr) {
+ CHECK_BTGATT_INIT();
+ // Closure will own this value and free it.
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(Bind(&BTA_GATTC_Refresh, base::Owned(address)));
+}
+
+bt_status_t btif_gattc_search_service(int conn_id, bt_uuid_t* filter_uuid) {
+ CHECK_BTGATT_INIT();
+
+ if (filter_uuid) {
+ tBT_UUID* uuid = new tBT_UUID;
+ btif_to_bta_uuid(uuid, filter_uuid);
+ return do_in_jni_thread(
+ Bind(&BTA_GATTC_ServiceSearchRequest, conn_id, base::Owned(uuid)));
+ } else {
+ return do_in_jni_thread(
+ Bind(&BTA_GATTC_ServiceSearchRequest, conn_id, nullptr));
+ }
+}
+
+void btif_gattc_discover_service_by_uuid(int conn_id, bt_uuid_t* p_uuid) {
+ LOG_ASSERT(p_uuid);
+
+ tBT_UUID* uuid = new tBT_UUID;
+ btif_to_bta_uuid(uuid, p_uuid);
+ do_in_jni_thread(
+ Bind(&BTA_GATTC_DiscoverServiceByUuid, conn_id, base::Owned(uuid)));
+}
+
+void btif_gattc_get_gatt_db_impl(int conn_id) {
+ btgatt_db_element_t* db = NULL;
+ int count = 0;
+ BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count);
+
+ HAL_CBACK(bt_gatt_callbacks, client->get_gatt_db_cb, conn_id, db, count);
+ osi_free(db);
+}
+
+bt_status_t btif_gattc_get_gatt_db(int conn_id) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&btif_gattc_get_gatt_db_impl, conn_id));
+}
+
+void read_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+ uint16_t len, uint8_t* value, void* data) {
+ btgatt_read_params_t* params = new btgatt_read_params_t;
+ params->value_type = 0x00 /* GATTC_READ_VALUE_TYPE_VALUE */;
+ params->status = status;
+ params->handle = handle;
+ params->value.len = len;
+ CHECK(len <= BTGATT_MAX_ATTR_LEN);
+ if (len > 0) memcpy(params->value.value, value, len);
+
+ CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status,
+ base::Owned(params));
+}
+
+bt_status_t btif_gattc_read_char(int conn_id, uint16_t handle, int auth_req) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&BTA_GATTC_ReadCharacteristic, conn_id, handle,
+ auth_req, read_char_cb, nullptr));
+}
+
+void read_using_char_uuid_cb(uint16_t conn_id, tGATT_STATUS status,
+ uint16_t handle, uint16_t len, uint8_t* value,
+ void* data) {
+ btgatt_read_params_t* params = new btgatt_read_params_t;
+ params->value_type = 0x00 /* GATTC_READ_VALUE_TYPE_VALUE */;
+ params->status = status;
+ params->handle = handle;
+ params->value.len = len;
+ CHECK(len <= BTGATT_MAX_ATTR_LEN);
+ if (len > 0) memcpy(params->value.value, value, len);
+
+ CLI_CBACK_IN_JNI(read_characteristic_cb, conn_id, status,
+ base::Owned(params));
+}
+
+bt_status_t btif_gattc_read_using_char_uuid(int conn_id, bt_uuid_t* uuid,
+ uint16_t s_handle,
+ uint16_t e_handle, int auth_req) {
+ CHECK_BTGATT_INIT();
+ tBT_UUID bt_uuid;
+ btif_to_bta_uuid(&bt_uuid, uuid);
+ return do_in_jni_thread(Bind(&BTA_GATTC_ReadUsingCharUuid, conn_id, bt_uuid,
+ s_handle, e_handle, auth_req,
+ read_using_char_uuid_cb, nullptr));
+}
+
+void read_desc_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+ uint16_t len, uint8_t* value, void* data) {
+ btgatt_read_params_t* params = new btgatt_read_params_t;
+ params->value_type = 0x00 /* GATTC_READ_VALUE_TYPE_VALUE */;
+ params->status = status;
+ params->handle = handle;
+ params->value.len = len;
+ CHECK(len <= BTGATT_MAX_ATTR_LEN);
+ if (len > 0) memcpy(params->value.value, value, len);
+
+ CLI_CBACK_IN_JNI(read_descriptor_cb, conn_id, status, base::Owned(params));
+}
+
+bt_status_t btif_gattc_read_char_descr(int conn_id, uint16_t handle,
+ int auth_req) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&BTA_GATTC_ReadCharDescr, conn_id, handle,
+ auth_req, read_desc_cb, nullptr));
+}
+
+void write_char_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+ void* data) {
+ CLI_CBACK_IN_JNI(write_characteristic_cb, conn_id, status, handle);
+}
+
+bt_status_t btif_gattc_write_char(int conn_id, uint16_t handle, int write_type,
+ int auth_req, vector<uint8_t> value) {
+ CHECK_BTGATT_INIT();
+
+ if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+ return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharValue, conn_id, handle,
+ write_type, std::move(value), auth_req,
+ write_char_cb, nullptr));
+}
+
+void write_descr_cb(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
+ void* data) {
+ CLI_CBACK_IN_JNI(write_descriptor_cb, conn_id, status, handle);
+}
+
+bt_status_t btif_gattc_write_char_descr(int conn_id, uint16_t handle,
+ int auth_req, vector<uint8_t> value) {
+ CHECK_BTGATT_INIT();
+
+ if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+ return do_in_jni_thread(Bind(&BTA_GATTC_WriteCharDescr, conn_id, handle,
+ std::move(value), auth_req, write_descr_cb,
+ nullptr));
+}
+
+bt_status_t btif_gattc_execute_write(int conn_id, int execute) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(
+ Bind(&BTA_GATTC_ExecuteWrite, conn_id, (uint8_t)execute));
+}
+
+void btif_gattc_reg_for_notification_impl(tBTA_GATTC_IF client_if,
+ const BD_ADDR bda, uint16_t handle) {
+ tBTA_GATT_STATUS status = BTA_GATTC_RegisterForNotifications(
+ client_if, const_cast<uint8_t*>(bda), handle);
+
+ // TODO(jpawlowski): conn_id is currently unused
+ HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
+ /* conn_id */ 0, 1, status, handle);
+}
+
+bt_status_t btif_gattc_reg_for_notification(int client_if,
+ const bt_bdaddr_t* bd_addr,
+ uint16_t handle) {
+ CHECK_BTGATT_INIT();
+
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(
+ Bind(base::IgnoreResult(&btif_gattc_reg_for_notification_impl), client_if,
+ base::Owned(address), handle));
+}
+
+void btif_gattc_dereg_for_notification_impl(tBTA_GATTC_IF client_if,
+ const BD_ADDR bda,
+ uint16_t handle) {
+ tBTA_GATT_STATUS status = BTA_GATTC_DeregisterForNotifications(
+ client_if, const_cast<uint8_t*>(bda), handle);
+
+ // TODO(jpawlowski): conn_id is currently unused
+ HAL_CBACK(bt_gatt_callbacks, client->register_for_notification_cb,
+ /* conn_id */ 0, 0, status, handle);
+}
+
+bt_status_t btif_gattc_dereg_for_notification(int client_if,
+ const bt_bdaddr_t* bd_addr,
+ uint16_t handle) {
+ CHECK_BTGATT_INIT();
+
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(
+ Bind(base::IgnoreResult(&btif_gattc_dereg_for_notification_impl),
+ client_if, base::Owned(address), handle));
+}
+
+bt_status_t btif_gattc_read_remote_rssi(int client_if,
+ const bt_bdaddr_t* bd_addr) {
+ CHECK_BTGATT_INIT();
+ rssi_request_client_if = client_if;
+ // Closure will own this value and free it.
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+ return do_in_jni_thread(Bind(base::IgnoreResult(&BTM_ReadRSSI),
+ base::Owned(address),
+ (tBTM_CMPL_CB*)btm_read_rssi_cb));
+}
+
+bt_status_t btif_gattc_configure_mtu(int conn_id, int mtu) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(
+ Bind(base::IgnoreResult(&BTA_GATTC_ConfigureMTU), conn_id, mtu));
+}
+
+void btif_gattc_conn_parameter_update_impl(bt_bdaddr_t addr, int min_interval,
+ int max_interval, int latency,
+ int timeout) {
+ if (BTA_DmGetConnectionState(addr.address))
+ BTA_DmBleUpdateConnectionParams(addr.address, min_interval, max_interval,
+ latency, timeout);
+ else
+ BTA_DmSetBlePrefConnParams(addr.address, min_interval, max_interval,
+ latency, timeout);
+}
+
+bt_status_t btif_gattc_conn_parameter_update(const bt_bdaddr_t* bd_addr,
+ int min_interval, int max_interval,
+ int latency, int timeout) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(
+ Bind(base::IgnoreResult(&btif_gattc_conn_parameter_update_impl), *bd_addr,
+ min_interval, max_interval, latency, timeout));
+}
+
+bt_status_t btif_gattc_set_preferred_phy(int conn_id, uint8_t tx_phy,
+ uint8_t rx_phy, uint16_t phy_options) {
+ CHECK_BTGATT_INIT();
+ do_in_bta_thread(FROM_HERE, Bind(&GATTC_SetPreferredPHY, conn_id, tx_phy,
+ rx_phy, phy_options));
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btif_gattc_read_phy(
+ int conn_id,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+ CHECK_BTGATT_INIT();
+ do_in_bta_thread(FROM_HERE, Bind(&GATTC_ReadPHY, conn_id,
+ jni_thread_wrapper(FROM_HERE, cb)));
+ return BT_STATUS_SUCCESS;
+}
+
+int btif_gattc_get_device_type(const bt_bdaddr_t* bd_addr) {
+ int device_type = 0;
+ char bd_addr_str[18] = {0};
+
+ bdaddr_to_string(bd_addr, bd_addr_str, sizeof(bd_addr_str));
+ if (btif_config_get_int(bd_addr_str, "DevType", &device_type))
+ return device_type;
+ return 0;
+}
+
+bt_status_t btif_gattc_test_command(int command, btgatt_test_params_t* params) {
+ return btif_gattc_test_command_impl(command, params);
+}
+
+} // namespace
+
+const btgatt_client_interface_t btgattClientInterface = {
+ btif_gattc_register_app,
+ btif_gattc_unregister_app,
+ btif_gattc_open,
+ btif_gattc_close,
+ btif_gattc_refresh,
+ btif_gattc_search_service,
+ btif_gattc_discover_service_by_uuid,
+ btif_gattc_read_char,
+ btif_gattc_read_using_char_uuid,
+ btif_gattc_write_char,
+ btif_gattc_read_char_descr,
+ btif_gattc_write_char_descr,
+ btif_gattc_execute_write,
+ btif_gattc_reg_for_notification,
+ btif_gattc_dereg_for_notification,
+ btif_gattc_read_remote_rssi,
+ btif_gattc_get_device_type,
+ btif_gattc_configure_mtu,
+ btif_gattc_conn_parameter_update,
+ btif_gattc_set_preferred_phy,
+ btif_gattc_read_phy,
+ btif_gattc_test_command,
+ btif_gattc_get_gatt_db};
diff --git a/mtkbt/code/bt/btif/src/btif_gatt_server.cc b/mtkbt/code/bt/btif/src/btif_gatt_server.cc
new file mode 100755
index 0000000..24f0346
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_gatt_server.cc
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_gatt_server.c
+ *
+ * Description: GATT server implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <base/bind.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_closure_api.h"
+#include "bta_gatt_api.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "osi/include/log.h"
+
+using base::Bind;
+using base::Owned;
+using std::vector;
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#define CHECK_BTGATT_INIT() \
+ do { \
+ if (bt_gatt_callbacks == NULL) { \
+ LOG_WARN(LOG_TAG, "%s: BTGATT not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } else { \
+ LOG_VERBOSE(LOG_TAG, "%s", __func__); \
+ } \
+ } while (0)
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+extern const btgatt_callbacks_t* bt_gatt_callbacks;
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+static void btapp_gatts_copy_req_data(uint16_t event, char* p_dest,
+ char* p_src) {
+ tBTA_GATTS* p_dest_data = (tBTA_GATTS*)p_dest;
+ tBTA_GATTS* p_src_data = (tBTA_GATTS*)p_src;
+
+ if (!p_src_data || !p_dest_data) return;
+
+ // Copy basic structure first
+ maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+ // Allocate buffer for request data if necessary
+ switch (event) {
+ case BTA_GATTS_READ_CHARACTERISTIC_EVT:
+ case BTA_GATTS_READ_DESCRIPTOR_EVT:
+ case BTA_GATTS_WRITE_CHARACTERISTIC_EVT:
+ case BTA_GATTS_WRITE_DESCRIPTOR_EVT:
+ case BTA_GATTS_EXEC_WRITE_EVT:
+ case BTA_GATTS_MTU_EVT:
+ p_dest_data->req_data.p_data =
+ (tBTA_GATTS_REQ_DATA*)osi_malloc(sizeof(tBTA_GATTS_REQ_DATA));
+ memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
+ sizeof(tBTA_GATTS_REQ_DATA));
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void btapp_gatts_free_req_data(uint16_t event, tBTA_GATTS* p_data) {
+ switch (event) {
+ case BTA_GATTS_READ_CHARACTERISTIC_EVT:
+ case BTA_GATTS_READ_DESCRIPTOR_EVT:
+ case BTA_GATTS_WRITE_CHARACTERISTIC_EVT:
+ case BTA_GATTS_WRITE_DESCRIPTOR_EVT:
+ case BTA_GATTS_EXEC_WRITE_EVT:
+ case BTA_GATTS_MTU_EVT:
+ if (p_data != NULL) osi_free_and_reset((void**)&p_data->req_data.p_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void btapp_gatts_handle_cback(uint16_t event, char* p_param) {
+ LOG_VERBOSE(LOG_TAG, "%s: Event %d", __func__, event);
+
+ tBTA_GATTS* p_data = (tBTA_GATTS*)p_param;
+ switch (event) {
+ case BTA_GATTS_REG_EVT: {
+ bt_uuid_t app_uuid;
+ bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.uuid);
+ HAL_CBACK(bt_gatt_callbacks, server->register_server_cb,
+ p_data->reg_oper.status, p_data->reg_oper.server_if, &app_uuid);
+ break;
+ }
+
+ case BTA_GATTS_DEREG_EVT:
+ break;
+
+ case BTA_GATTS_CONNECT_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->conn.remote_bda);
+
+ btif_gatt_check_encrypted_link(p_data->conn.remote_bda,
+ p_data->conn.transport);
+
+ HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id,
+ p_data->conn.server_if, true, &bda);
+ break;
+ }
+
+ case BTA_GATTS_DISCONNECT_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->conn.remote_bda);
+
+ HAL_CBACK(bt_gatt_callbacks, server->connection_cb, p_data->conn.conn_id,
+ p_data->conn.server_if, false, &bda);
+ break;
+ }
+
+ case BTA_GATTS_STOP_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->service_stopped_cb,
+ p_data->srvc_oper.status, p_data->srvc_oper.server_if,
+ p_data->srvc_oper.service_id);
+ break;
+
+ case BTA_GATTS_DELELTE_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->service_deleted_cb,
+ p_data->srvc_oper.status, p_data->srvc_oper.server_if,
+ p_data->srvc_oper.service_id);
+ break;
+
+ case BTA_GATTS_READ_CHARACTERISTIC_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->req_data.remote_bda);
+
+ HAL_CBACK(bt_gatt_callbacks, server->request_read_characteristic_cb,
+ p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+ p_data->req_data.p_data->read_req.handle,
+ p_data->req_data.p_data->read_req.offset,
+ p_data->req_data.p_data->read_req.is_long);
+ break;
+ }
+
+ case BTA_GATTS_READ_DESCRIPTOR_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->req_data.remote_bda);
+
+ HAL_CBACK(bt_gatt_callbacks, server->request_read_descriptor_cb,
+ p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+ p_data->req_data.p_data->read_req.handle,
+ p_data->req_data.p_data->read_req.offset,
+ p_data->req_data.p_data->read_req.is_long);
+ break;
+ }
+
+ case BTA_GATTS_WRITE_CHARACTERISTIC_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->req_data.remote_bda);
+ const auto& req = p_data->req_data.p_data->write_req;
+ vector<uint8_t> value(req.value, req.value + req.len);
+ HAL_CBACK(bt_gatt_callbacks, server->request_write_characteristic_cb,
+ p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+ req.handle, req.offset, req.need_rsp, req.is_prep, value);
+ break;
+ }
+
+ case BTA_GATTS_WRITE_DESCRIPTOR_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->req_data.remote_bda);
+ const auto& req = p_data->req_data.p_data->write_req;
+ vector<uint8_t> value(req.value, req.value + req.len);
+ HAL_CBACK(bt_gatt_callbacks, server->request_write_descriptor_cb,
+ p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+ req.handle, req.offset, req.need_rsp, req.is_prep, value);
+ break;
+ }
+
+ case BTA_GATTS_EXEC_WRITE_EVT: {
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, p_data->req_data.remote_bda);
+
+ HAL_CBACK(bt_gatt_callbacks, server->request_exec_write_cb,
+ p_data->req_data.conn_id, p_data->req_data.trans_id, &bda,
+ p_data->req_data.p_data->exec_write);
+ break;
+ }
+
+ case BTA_GATTS_CONF_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->indication_sent_cb,
+ p_data->req_data.conn_id, p_data->req_data.status);
+ break;
+
+ case BTA_GATTS_CONGEST_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->congestion_cb,
+ p_data->congest.conn_id, p_data->congest.congested);
+ break;
+
+ case BTA_GATTS_MTU_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->mtu_changed_cb,
+ p_data->req_data.conn_id, p_data->req_data.p_data->mtu);
+ break;
+
+ case BTA_GATTS_OPEN_EVT:
+ case BTA_GATTS_CANCEL_OPEN_EVT:
+ case BTA_GATTS_CLOSE_EVT:
+ LOG_DEBUG(LOG_TAG, "%s: Empty event (%d)!", __func__, event);
+ break;
+
+ case BTA_GATTS_PHY_UPDATE_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->phy_updated_cb,
+ p_data->phy_update.conn_id, p_data->phy_update.tx_phy,
+ p_data->phy_update.rx_phy, p_data->phy_update.status);
+ break;
+
+ case BTA_GATTS_CONN_UPDATE_EVT:
+ HAL_CBACK(bt_gatt_callbacks, server->conn_updated_cb,
+ p_data->conn_update.conn_id, p_data->conn_update.interval,
+ p_data->conn_update.latency, p_data->conn_update.timeout,
+ p_data->conn_update.status);
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Unhandled event (%d)!", __func__, event);
+ break;
+ }
+
+ btapp_gatts_free_req_data(event, p_data);
+}
+
+static void btapp_gatts_cback(tBTA_GATTS_EVT event, tBTA_GATTS* p_data) {
+ bt_status_t status;
+ status = btif_transfer_context(btapp_gatts_handle_cback, (uint16_t)event,
+ (char*)p_data, sizeof(tBTA_GATTS),
+ btapp_gatts_copy_req_data);
+ ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
+}
+
+/*******************************************************************************
+ * Server API Functions
+ ******************************************************************************/
+static bt_status_t btif_gatts_register_app(bt_uuid_t* bt_uuid) {
+ CHECK_BTGATT_INIT();
+ tBT_UUID* uuid = new tBT_UUID;
+ btif_to_bta_uuid(uuid, bt_uuid);
+
+ return do_in_jni_thread(
+ Bind(&BTA_GATTS_AppRegister, base::Owned(uuid), &btapp_gatts_cback));
+}
+
+static bt_status_t btif_gatts_unregister_app(int server_if) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&BTA_GATTS_AppDeregister, server_if));
+}
+
+static void btif_gatts_open_impl(int server_if, BD_ADDR address, bool is_direct,
+ int transport_param) {
+ // Ensure device is in inquiry database
+ int addr_type = 0;
+ int device_type = 0;
+ tBTA_GATT_TRANSPORT transport = BTA_GATT_TRANSPORT_LE;
+
+ if (btif_get_address_type(address, &addr_type) &&
+ btif_get_device_type(address, &device_type) &&
+ device_type != BT_DEVICE_TYPE_BREDR) {
+ BTA_DmAddBleDevice(address, addr_type, device_type);
+ }
+
+ // Mark background connections
+ if (!is_direct) BTA_DmBleStartAutoConn();
+
+ // Determine transport
+ if (transport_param != GATT_TRANSPORT_AUTO) {
+ transport = transport_param;
+ } else {
+ switch (device_type) {
+ case BT_DEVICE_TYPE_BREDR:
+ transport = BTA_GATT_TRANSPORT_BR_EDR;
+ break;
+
+ case BT_DEVICE_TYPE_BLE:
+ transport = BTA_GATT_TRANSPORT_LE;
+ break;
+
+ case BT_DEVICE_TYPE_DUMO:
+ if (transport_param == GATT_TRANSPORT_LE)
+ transport = BTA_GATT_TRANSPORT_LE;
+ else
+ transport = BTA_GATT_TRANSPORT_BR_EDR;
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("%s: Invalid device type %d", __func__, device_type);
+ return;
+ }
+ }
+
+ // Connect!
+ BTA_GATTS_Open(server_if, address, is_direct, transport);
+}
+
+static bt_status_t btif_gatts_open(int server_if, const bt_bdaddr_t* bd_addr,
+ bool is_direct, int transport) {
+ CHECK_BTGATT_INIT();
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+
+ return do_in_jni_thread(Bind(&btif_gatts_open_impl, server_if,
+ base::Owned(address), is_direct, transport));
+}
+
+static void btif_gatts_close_impl(int server_if, BD_ADDR address, int conn_id) {
+ // Close active connection
+ if (conn_id != 0)
+ BTA_GATTS_Close(conn_id);
+ else
+ BTA_GATTS_CancelOpen(server_if, address, true);
+
+ // Cancel pending background connections
+ BTA_GATTS_CancelOpen(server_if, address, false);
+}
+
+static bt_status_t btif_gatts_close(int server_if, const bt_bdaddr_t* bd_addr,
+ int conn_id) {
+ CHECK_BTGATT_INIT();
+ uint8_t* address = new BD_ADDR;
+ bdcpy(address, bd_addr->address);
+
+ return do_in_jni_thread(
+ Bind(&btif_gatts_close_impl, server_if, base::Owned(address), conn_id));
+}
+
+static void add_service_impl(int server_if,
+ vector<btgatt_db_element_t> service) {
+ bt_uuid_t restricted_uuid1, restricted_uuid2;
+ uuid_128_from_16(&restricted_uuid1, UUID_SERVCLASS_GATT_SERVER);
+ uuid_128_from_16(&restricted_uuid2, UUID_SERVCLASS_GAP_SERVER);
+
+ // TODO(jpawlowski): btif should be a pass through layer, and no checks should
+ // be made here. This exception is added only until GATT server code is
+ // refactored, and one can distinguish stack-internal aps from external apps
+ if (memcmp(&service[0].uuid, &restricted_uuid1, sizeof(bt_uuid_t)) == 0 ||
+ memcmp(&service[0].uuid, &restricted_uuid2, sizeof(bt_uuid_t)) == 0) {
+ LOG_ERROR(LOG_TAG, "%s: Attept to register restricted service", __func__);
+ HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, BT_STATUS_FAIL,
+ server_if, std::move(service));
+ return;
+ }
+
+ int status = BTA_GATTS_AddService(server_if, service);
+ HAL_CBACK(bt_gatt_callbacks, server->service_added_cb, status, server_if,
+ std::move(service));
+}
+
+static bt_status_t btif_gatts_add_service(int server_if,
+ vector<btgatt_db_element_t> service) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(
+ Bind(&add_service_impl, server_if, std::move(service)));
+}
+
+static bt_status_t btif_gatts_stop_service(int server_if, int service_handle) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&BTA_GATTS_StopService, service_handle));
+}
+
+static bt_status_t btif_gatts_delete_service(int server_if,
+ int service_handle) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&BTA_GATTS_DeleteService, service_handle));
+}
+
+static bt_status_t btif_gatts_send_indication(int server_if,
+ int attribute_handle, int conn_id,
+ int confirm,
+ vector<uint8_t> value) {
+ CHECK_BTGATT_INIT();
+
+ if (value.size() > BTGATT_MAX_ATTR_LEN) value.resize(BTGATT_MAX_ATTR_LEN);
+
+ return do_in_jni_thread(Bind(&BTA_GATTS_HandleValueIndication, conn_id,
+ attribute_handle, std::move(value), confirm));
+ // TODO: Might need to send an ACK if handle value indication is
+ // invoked without need for confirmation.
+}
+
+static void btif_gatts_send_response_impl(int conn_id, int trans_id, int status,
+ btgatt_response_t response) {
+ tBTA_GATTS_RSP rsp_struct;
+ btif_to_bta_response(&rsp_struct, &response);
+
+ BTA_GATTS_SendRsp(conn_id, trans_id, status, &rsp_struct);
+
+ HAL_CBACK(bt_gatt_callbacks, server->response_confirmation_cb, 0,
+ rsp_struct.attr_value.handle);
+}
+
+static bt_status_t btif_gatts_send_response(int conn_id, int trans_id,
+ int status,
+ btgatt_response_t* response) {
+ CHECK_BTGATT_INIT();
+ return do_in_jni_thread(Bind(&btif_gatts_send_response_impl, conn_id,
+ trans_id, status, *response));
+}
+
+static bt_status_t btif_gattc_set_preferred_phy(int conn_id, uint8_t tx_phy,
+ uint8_t rx_phy,
+ uint16_t phy_options) {
+ CHECK_BTGATT_INIT();
+ do_in_bta_thread(FROM_HERE, Bind(&GATTC_SetPreferredPHY, conn_id, tx_phy,
+ rx_phy, phy_options));
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t btif_gattc_read_phy(
+ int conn_id,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+ CHECK_BTGATT_INIT();
+ do_in_bta_thread(FROM_HERE, Bind(&GATTC_ReadPHY, conn_id,
+ jni_thread_wrapper(FROM_HERE, cb)));
+ return BT_STATUS_SUCCESS;
+}
+
+const btgatt_server_interface_t btgattServerInterface = {
+ btif_gatts_register_app, btif_gatts_unregister_app,
+ btif_gatts_open, btif_gatts_close,
+ btif_gatts_add_service, btif_gatts_stop_service,
+ btif_gatts_delete_service, btif_gatts_send_indication,
+ btif_gatts_send_response, btif_gattc_set_preferred_phy,
+ btif_gattc_read_phy};
diff --git a/mtkbt/code/bt/btif/src/btif_gatt_test.cc b/mtkbt/code/bt/btif/src/btif_gatt_test.cc
new file mode 100755
index 0000000..73cffc5
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_gatt_test.cc
@@ -0,0 +1,292 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "btif_common.h"
+#include "btif_util.h"
+
+#include "bta_gatt_api.h"
+#include "bte_appl.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_gatt_util.h"
+#include "btif_storage.h"
+#include "gatt_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ * Typedefs & Macros
+ ******************************************************************************/
+
+typedef struct {
+ tGATT_IF gatt_if;
+ uint16_t conn_id;
+} btif_test_cb_t;
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+static const char* disc_name[GATT_DISC_MAX] = {"Unknown",
+ "GATT_DISC_SRVC_ALL",
+ "GATT_DISC_SRVC_BY_UUID",
+ "GATT_DISC_INC_SRVC",
+ "GATT_DISC_CHAR",
+ "GATT_DISC_CHAR_DSCPT"};
+
+static btif_test_cb_t test_cb;
+
+/*******************************************************************************
+ * Callback functions
+ ******************************************************************************/
+
+static char* format_uuid(tBT_UUID bt_uuid, char* str_buf, size_t buf_size) {
+ if (bt_uuid.len == LEN_UUID_16) {
+ snprintf(str_buf, buf_size, "0x%04x", bt_uuid.uu.uuid16);
+ } else if (bt_uuid.len == LEN_UUID_128) {
+ int x = snprintf(str_buf, buf_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x",
+ bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+ bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+ bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+ bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+ snprintf(&str_buf[x], buf_size - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+ bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+ bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+ bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+ } else {
+ snprintf(str_buf, buf_size, "Unknown (len=%d)", bt_uuid.len);
+ }
+
+ return str_buf;
+}
+
+static void btif_test_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
+ UNUSED_ATTR BD_ADDR bda, uint16_t conn_id,
+ bool connected,
+ UNUSED_ATTR tGATT_DISCONN_REASON reason,
+ UNUSED_ATTR tBT_TRANSPORT transport) {
+ LOG_DEBUG(LOG_TAG, "%s: conn_id=%d, connected=%d", __func__, conn_id,
+ connected);
+ test_cb.conn_id = connected ? conn_id : 0;
+}
+
+static void btif_test_command_complete_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ LOG_DEBUG(LOG_TAG, "%s: op_code=0x%02x, conn_id=0x%x. status=0x%x", __func__,
+ op, conn_id, status);
+
+ switch (op) {
+ case GATTC_OPTYPE_READ:
+ case GATTC_OPTYPE_WRITE:
+ case GATTC_OPTYPE_CONFIG:
+ case GATTC_OPTYPE_EXE_WRITE:
+ case GATTC_OPTYPE_NOTIFICATION:
+ break;
+
+ case GATTC_OPTYPE_INDICATION:
+ GATTC_SendHandleValueConfirm(conn_id, p_data->handle);
+ break;
+
+ default:
+ LOG_DEBUG(LOG_TAG, "%s: Unknown op_code (0x%02x)", __func__, op);
+ break;
+ }
+}
+
+static void btif_test_discovery_result_cback(UNUSED_ATTR uint16_t conn_id,
+ tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data) {
+ char str_buf[50];
+
+ LOG_DEBUG(LOG_TAG, "------ GATT Discovery result %-22s -------",
+ disc_name[disc_type]);
+ LOG_DEBUG(LOG_TAG, " Attribute handle: 0x%04x (%d)", p_data->handle,
+ p_data->handle);
+
+ if (disc_type != GATT_DISC_CHAR_DSCPT) {
+ LOG_DEBUG(LOG_TAG, " Attribute type: %s",
+ format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+ }
+
+ switch (disc_type) {
+ case GATT_DISC_SRVC_ALL:
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ p_data->handle, p_data->value.group_value.e_handle,
+ p_data->handle, p_data->value.group_value.e_handle);
+ LOG_DEBUG(LOG_TAG, " Service UUID: %s",
+ format_uuid(p_data->value.group_value.service_type, str_buf,
+ sizeof(str_buf)));
+ break;
+
+ case GATT_DISC_SRVC_BY_UUID:
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ p_data->handle, p_data->value.handle, p_data->handle,
+ p_data->value.handle);
+ break;
+
+ case GATT_DISC_INC_SRVC:
+ LOG_DEBUG(LOG_TAG, " Handle range: 0x%04x ~ 0x%04x (%d ~ %d)",
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle,
+ p_data->value.incl_service.s_handle,
+ p_data->value.incl_service.e_handle);
+ LOG_DEBUG(LOG_TAG, " Service UUID: %s",
+ format_uuid(p_data->value.incl_service.service_type, str_buf,
+ sizeof(str_buf)));
+ break;
+
+ case GATT_DISC_CHAR:
+ LOG_DEBUG(LOG_TAG, " Properties: 0x%02x",
+ p_data->value.dclr_value.char_prop);
+ LOG_DEBUG(LOG_TAG, " Characteristic UUID: %s",
+ format_uuid(p_data->value.dclr_value.char_uuid, str_buf,
+ sizeof(str_buf)));
+ break;
+
+ case GATT_DISC_CHAR_DSCPT:
+ LOG_DEBUG(LOG_TAG, " Descriptor UUID: %s",
+ format_uuid(p_data->type, str_buf, sizeof(str_buf)));
+ break;
+ }
+
+ LOG_DEBUG(LOG_TAG,
+ "-----------------------------------------------------------");
+}
+
+static void btif_test_discovery_complete_cback(
+ UNUSED_ATTR uint16_t conn_id, UNUSED_ATTR tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status) {
+ LOG_DEBUG(LOG_TAG, "%s: status=%d", __func__, status);
+}
+
+static tGATT_CBACK btif_test_callbacks = {btif_test_connect_cback,
+ btif_test_command_complete_cback,
+ btif_test_discovery_result_cback,
+ btif_test_discovery_complete_cback,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+
+/*******************************************************************************
+ * Implementation
+ ******************************************************************************/
+
+bt_status_t btif_gattc_test_command_impl(int command,
+ btgatt_test_params_t* params) {
+ switch (command) {
+ case 0x01: /* Enable */
+ {
+ LOG_DEBUG(LOG_TAG, "%s: ENABLE - enable=%d", __func__, params->u1);
+ if (params->u1) {
+ tBT_UUID app_uuid = {LEN_UUID_128, {0xAE}};
+ test_cb.gatt_if = GATT_Register(&app_uuid, &btif_test_callbacks);
+ GATT_StartIf(test_cb.gatt_if);
+ } else {
+ GATT_Deregister(test_cb.gatt_if);
+ test_cb.gatt_if = 0;
+ }
+ break;
+ }
+
+ case 0x02: /* Connect */
+ {
+ LOG_DEBUG(LOG_TAG,
+ "%s: CONNECT - device=%02x:%02x:%02x:%02x:%02x:%02x "
+ "(dev_type=%d, addr_type=%d)",
+ __func__, params->bda1->address[0], params->bda1->address[1],
+ params->bda1->address[2], params->bda1->address[3],
+ params->bda1->address[4], params->bda1->address[5], params->u1,
+ params->u2);
+
+ if (params->u1 == BT_DEVICE_TYPE_BLE)
+ BTM_SecAddBleDevice(params->bda1->address, NULL, BT_DEVICE_TYPE_BLE,
+ params->u2);
+
+ if (!GATT_Connect(test_cb.gatt_if, params->bda1->address, true,
+ BT_TRANSPORT_LE, false)) {
+ LOG_ERROR(LOG_TAG, "%s: GATT_Connect failed!", __func__);
+ }
+ break;
+ }
+
+ case 0x03: /* Disconnect */
+ {
+ LOG_DEBUG(LOG_TAG, "%s: DISCONNECT - conn_id=%d", __func__,
+ test_cb.conn_id);
+ GATT_Disconnect(test_cb.conn_id);
+ break;
+ }
+
+ case 0x04: /* Discover */
+ {
+ char buf[50] = {0};
+ tGATT_DISC_PARAM param;
+ memset(&param, 0, sizeof(tGATT_DISC_PARAM));
+
+ if (params->u1 >= GATT_DISC_MAX) {
+ LOG_ERROR(LOG_TAG, "%s: DISCOVER - Invalid type (%d)!", __func__,
+ params->u1);
+ return (bt_status_t)0;
+ }
+
+ param.s_handle = params->u2;
+ param.e_handle = params->u3;
+ btif_to_bta_uuid(&param.service, params->uuid1);
+
+ LOG_DEBUG(LOG_TAG,
+ "%s: DISCOVER (%s), conn_id=%d, uuid=%s, handles=0x%04x-0x%04x",
+ __func__, disc_name[params->u1], test_cb.conn_id,
+ format_uuid(param.service, buf, sizeof(buf)), params->u2,
+ params->u3);
+ GATTC_Discover(test_cb.conn_id, params->u1, &param);
+ break;
+ }
+
+ case 0xF0: /* Pairing configuration */
+ LOG_DEBUG(LOG_TAG,
+ "%s: Setting pairing config auth=%d, iocaps=%d, keys=%d/%d/%d",
+ __func__, params->u1, params->u2, params->u3, params->u4,
+ params->u5);
+
+ bte_appl_cfg.ble_auth_req = params->u1;
+ bte_appl_cfg.ble_io_cap = params->u2;
+ bte_appl_cfg.ble_init_key = params->u3;
+ bte_appl_cfg.ble_resp_key = params->u4;
+ bte_appl_cfg.ble_max_key_size = params->u5;
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: UNKNOWN TEST COMMAND 0x%02x", __func__, command);
+ break;
+ }
+ return (bt_status_t)0;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_gatt_util.cc b/mtkbt/code/bt/btif/src/btif_gatt_util.cc
new file mode 100755
index 0000000..3d0e603
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_gatt_util.cc
@@ -0,0 +1,271 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_gatt"
+
+#include "btif_gatt_util.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_gatt_api.h"
+#include "bta_jv_api.h"
+#include "btif_common.h"
+#include "btif_config.h"
+#include "btif_dm.h"
+#include "btif_gatt.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+
+#define GATTC_READ_VALUE_TYPE_VALUE 0x0000 /* Attribute value itself */
+#define GATTC_READ_VALUE_TYPE_AGG_FORMAT \
+ 0x2905 /* Characteristic Aggregate Format*/
+
+static unsigned char BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
+ 0x00, 0x80, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+int uuidType(const unsigned char* p_uuid) {
+ int i = 0;
+ int match = 0;
+ int all_zero = 1;
+
+ for (i = 0; i != 16; ++i) {
+ if (i == 12 || i == 13) continue;
+
+ if (p_uuid[i] == BASE_UUID[i]) ++match;
+
+ if (p_uuid[i] != 0) all_zero = 0;
+ }
+ if (all_zero) return 0;
+ if (match == 12) return LEN_UUID_32;
+ if (match == 14) return LEN_UUID_16;
+ return LEN_UUID_128;
+}
+
+/*******************************************************************************
+ * BTIF -> BTA conversion functions
+ ******************************************************************************/
+
+void btif_to_bta_uuid(tBT_UUID* p_dest, const bt_uuid_t* p_src) {
+ char* p_byte = (char*)p_src;
+ int i = 0;
+
+ p_dest->len = uuidType(p_src->uu);
+
+ switch (p_dest->len) {
+ case LEN_UUID_16:
+ p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
+ break;
+
+ case LEN_UUID_32:
+ p_dest->uu.uuid32 = (p_src->uu[13] << 8) + p_src->uu[12];
+ p_dest->uu.uuid32 += (p_src->uu[15] << 24) + (p_src->uu[14] << 16);
+ break;
+
+ case LEN_UUID_128:
+ for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_dest->len);
+ break;
+ }
+}
+
+void btif_to_bta_response(tBTA_GATTS_RSP* p_dest, btgatt_response_t* p_src) {
+ p_dest->attr_value.auth_req = p_src->attr_value.auth_req;
+ p_dest->attr_value.handle = p_src->attr_value.handle;
+ p_dest->attr_value.len = p_src->attr_value.len;
+ p_dest->attr_value.offset = p_src->attr_value.offset;
+ memcpy(p_dest->attr_value.value, p_src->attr_value.value, GATT_MAX_ATTR_LEN);
+}
+
+void btif_to_bta_uuid_mask(tBTM_BLE_PF_COND_MASK* p_mask,
+ const bt_uuid_t* uuid_mask,
+ const bt_uuid_t* svc_uuid) {
+ char* p_byte = (char*)uuid_mask;
+ int uuid_len = uuidType(svc_uuid->uu);
+ int i = 0;
+
+ switch (uuid_len) {
+ case LEN_UUID_16:
+ p_mask->uuid16_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
+ break;
+
+ case LEN_UUID_32:
+ p_mask->uuid32_mask = (uuid_mask->uu[13] << 8) + uuid_mask->uu[12];
+ p_mask->uuid32_mask +=
+ (uuid_mask->uu[15] << 24) + (uuid_mask->uu[14] << 16);
+ break;
+
+ case LEN_UUID_128:
+ for (i = 0; i != 16; ++i) p_mask->uuid128_mask[i] = p_byte[i];
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ * BTA -> BTIF conversion functions
+ ******************************************************************************/
+
+void bta_to_btif_uuid(bt_uuid_t* p_dest, tBT_UUID* p_src) {
+ int i = 0;
+
+ if (p_src->len == LEN_UUID_16 || p_src->len == LEN_UUID_32) {
+ for (i = 0; i != 16; ++i) p_dest->uu[i] = BASE_UUID[i];
+ }
+
+ switch (p_src->len) {
+ case 0:
+ break;
+
+ case LEN_UUID_16:
+ p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
+ p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
+ break;
+
+ case LEN_UUID_32:
+ p_dest->uu[12] = p_src->uu.uuid16 & 0xff;
+ p_dest->uu[13] = (p_src->uu.uuid16 >> 8) & 0xff;
+ p_dest->uu[14] = (p_src->uu.uuid32 >> 16) & 0xff;
+ p_dest->uu[15] = (p_src->uu.uuid32 >> 24) & 0xff;
+ break;
+
+ case LEN_UUID_128:
+ for (i = 0; i != 16; ++i) p_dest->uu[i] = p_src->uu.uuid128[i];
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Unknown UUID length %d!", __func__, p_src->len);
+ break;
+ }
+}
+
+/*******************************************************************************
+ * Utility functions
+ ******************************************************************************/
+
+uint16_t get_uuid16(tBT_UUID* p_uuid) {
+ if (p_uuid->len == LEN_UUID_16) {
+ return p_uuid->uu.uuid16;
+ } else if (p_uuid->len == LEN_UUID_128) {
+ uint16_t u16;
+ uint8_t* p = &p_uuid->uu.uuid128[LEN_UUID_128 - 4];
+ STREAM_TO_UINT16(u16, p);
+ return u16;
+ } else /* p_uuid->len == LEN_UUID_32 */
+ {
+ return (uint16_t)p_uuid->uu.uuid32;
+ }
+}
+
+uint16_t set_read_value(btgatt_read_params_t* p_dest, tBTA_GATTC_READ* p_src) {
+ uint16_t len = 0;
+
+ p_dest->status = p_src->status;
+ p_dest->handle = p_src->handle;
+
+ if ((p_src->status == BTA_GATT_OK) && (p_src->len != 0)) {
+ LOG_INFO(LOG_TAG, "%s len = %d ", __func__, p_src->len);
+ p_dest->value.len = p_src->len;
+ memcpy(p_dest->value.value, p_src->value, p_src->len);
+
+ len += p_src->len;
+ } else {
+ p_dest->value.len = 0;
+ }
+
+ p_dest->value_type = GATTC_READ_VALUE_TYPE_VALUE;
+ return len;
+}
+
+/*******************************************************************************
+ * Encrypted link map handling
+ ******************************************************************************/
+
+#if (BLE_DELAY_REQUEST_ENC == FALSE)
+static bool btif_gatt_is_link_encrypted(BD_ADDR bd_addr) {
+ if (bd_addr == NULL) return false;
+
+ return BTA_JvIsEncrypted(bd_addr);
+}
+
+static void btif_gatt_set_encryption_cb(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBTA_TRANSPORT transport,
+ tBTA_STATUS result) {
+ if (result != BTA_SUCCESS && result != BTA_BUSY) {
+ BTIF_TRACE_WARNING("%s() - Encryption failed (%d)", __func__, result);
+ }
+}
+#endif
+
+#if (BLE_DELAY_REQUEST_ENC == FALSE)
+void btif_gatt_check_encrypted_link(BD_ADDR bd_addr,
+ tBTA_GATT_TRANSPORT transport_link) {
+ char buf[100];
+
+ bt_bdaddr_t bda;
+ bdcpy(bda.address, bd_addr);
+
+ if ((btif_storage_get_ble_bonding_key(&bda, BTIF_DM_LE_KEY_PENC, buf,
+ sizeof(tBTM_LE_PENC_KEYS)) ==
+ BT_STATUS_SUCCESS) &&
+ !btif_gatt_is_link_encrypted(bd_addr)) {
+ BTIF_TRACE_DEBUG("%s: transport = %d", __func__, transport_link);
+ BTA_DmSetEncryption(bd_addr, transport_link, &btif_gatt_set_encryption_cb,
+ BTM_BLE_SEC_ENCRYPT);
+ }
+}
+#else
+void btif_gatt_check_encrypted_link(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBTA_GATT_TRANSPORT
+ transport_link) {}
+#endif
+
+void btif_gatt_move_track_adv_data(btgatt_track_adv_info_t* p_dest,
+ btgatt_track_adv_info_t* p_src) {
+ memset(p_dest, 0, sizeof(btgatt_track_adv_info_t));
+
+ memcpy(p_dest, p_src, sizeof(btgatt_track_adv_info_t));
+
+ if (p_src->adv_pkt_len > 0) {
+ p_dest->p_adv_pkt_data = (uint8_t*)osi_malloc(p_src->adv_pkt_len);
+ memcpy(p_dest->p_adv_pkt_data, p_src->p_adv_pkt_data, p_src->adv_pkt_len);
+ osi_free_and_reset((void**)&p_src->p_adv_pkt_data);
+ }
+
+ if (p_src->scan_rsp_len > 0) {
+ p_dest->p_scan_rsp_data = (uint8_t*)osi_malloc(p_src->scan_rsp_len);
+ memcpy(p_dest->p_scan_rsp_data, p_src->p_scan_rsp_data,
+ p_src->scan_rsp_len);
+ osi_free_and_reset((void**)&p_src->p_scan_rsp_data);
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_hd.cc b/mtkbt/code/bt/btif/src/btif_hd.cc
new file mode 100755
index 0000000..c7f0ef4
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_hd.cc
@@ -0,0 +1,685 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/************************************************************************************
+ *
+ * Filename: btif_hd.c
+ *
+ * Description: HID Device Profile Bluetooth Interface
+ *
+ *
+ ***********************************************************************************/
+#include <errno.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "BTIF_HD"
+
+#include "bta_api.h"
+#include "bta_hd_api.h"
+#include "bta_hh_api.h"
+
+#include "btif_common.h"
+#include "btif_hd.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+
+#define BTIF_HD_APP_NAME_LEN 50
+#define BTIF_HD_APP_DESCRIPTION_LEN 50
+#define BTIF_HD_APP_PROVIDER_LEN 50
+#define BTIF_HD_APP_DESCRIPTOR_LEN 2048
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+#define COD_HID_MAJOR 0x0500
+
+extern bool bta_dm_check_if_only_hd_connected(BD_ADDR peer_addr);
+extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
+extern void btif_hh_service_registration(bool enable);
+
+/* HD request events */
+typedef enum { BTIF_HD_DUMMY_REQ_EVT = 0 } btif_hd_req_evt_t;
+
+btif_hd_cb_t btif_hd_cb;
+
+static bthd_callbacks_t* bt_hd_callbacks = NULL;
+static tBTA_HD_APP_INFO app_info;
+static tBTA_HD_QOS_INFO in_qos;
+static tBTA_HD_QOS_INFO out_qos;
+
+static void intr_data_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+ tBTA_HD_INTR_DATA* p_dst_data = (tBTA_HD_INTR_DATA*)p_dst;
+ tBTA_HD_INTR_DATA* p_src_data = (tBTA_HD_INTR_DATA*)p_src;
+ uint8_t* p_data;
+
+ if (!p_src) return;
+
+ if (event != BTA_HD_INTR_DATA_EVT) return;
+
+ memcpy(p_dst, p_src, sizeof(tBTA_HD_INTR_DATA));
+
+ p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_INTR_DATA);
+
+ memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+ p_dst_data->p_data = p_data;
+}
+
+static void set_report_copy_cb(uint16_t event, char* p_dst, char* p_src) {
+ tBTA_HD_SET_REPORT* p_dst_data = (tBTA_HD_SET_REPORT*)p_dst;
+ tBTA_HD_SET_REPORT* p_src_data = (tBTA_HD_SET_REPORT*)p_src;
+ uint8_t* p_data;
+
+ if (!p_src) return;
+
+ if (event != BTA_HD_SET_REPORT_EVT) return;
+
+ memcpy(p_dst, p_src, sizeof(tBTA_HD_SET_REPORT));
+
+ p_data = ((uint8_t*)p_dst_data) + sizeof(tBTA_HD_SET_REPORT);
+
+ memcpy(p_data, p_src_data->p_data, p_src_data->len);
+
+ p_dst_data->p_data = p_data;
+}
+
+static void btif_hd_free_buf() {
+ if (app_info.descriptor.dsc_list) osi_free(app_info.descriptor.dsc_list);
+ if (app_info.p_description) osi_free(app_info.p_description);
+ if (app_info.p_name) osi_free(app_info.p_name);
+ if (app_info.p_provider) osi_free(app_info.p_provider);
+ app_info.descriptor.dsc_list = NULL;
+ app_info.p_description = NULL;
+ app_info.p_name = NULL;
+ app_info.p_provider = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_remove_device
+ *
+ * Description Removes plugged device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hd_remove_device(bt_bdaddr_t bd_addr) {
+ BTA_HdRemoveDevice((uint8_t*)&bd_addr);
+ btif_storage_remove_hidd(&bd_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_upstreams_evt
+ *
+ * Description Executes events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hd_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_HD* p_data = (tBTA_HD*)p_param;
+
+ BTIF_TRACE_API("%s: event=%s", __func__, dump_hd_event(event));
+
+ switch (event) {
+ case BTA_HD_ENABLE_EVT:
+ BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+ if (p_data->status == BTA_HD_OK) {
+ btif_storage_load_hidd();
+ btif_hd_cb.status = BTIF_HD_ENABLED;
+ /* Register the app if not yet registered */
+ if (!btif_hd_cb.app_registered) {
+ BTA_HdRegisterApp(&app_info, &in_qos, &out_qos);
+ btif_hd_free_buf();
+ }
+ } else {
+ btif_hd_cb.status = BTIF_HD_DISABLED;
+ BTIF_TRACE_WARNING("Failed to enable BT-HD, status=%d", p_data->status);
+ }
+ break;
+
+ case BTA_HD_DISABLE_EVT:
+ BTIF_TRACE_DEBUG("%s: status=%d", __func__, p_data->status);
+ btif_hd_cb.status = BTIF_HD_DISABLED;
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("registering hid host now");
+ btif_hh_service_registration(TRUE);
+ btif_hd_cb.service_dereg_active = FALSE;
+ }
+ btif_hd_free_buf();
+ if (p_data->status == BTA_HD_OK)
+ memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+ else
+ BTIF_TRACE_WARNING("Failed to disable BT-HD, status=%d",
+ p_data->status);
+ break;
+
+ case BTA_HD_REGISTER_APP_EVT: {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->reg_status.bda;
+
+ if (!p_data->reg_status.in_use) {
+ addr = NULL;
+ }
+
+ btif_hd_cb.app_registered = TRUE;
+ HAL_CBACK(bt_hd_callbacks, application_state_cb, addr,
+ BTHD_APP_STATE_REGISTERED);
+ } break;
+
+ case BTA_HD_UNREGISTER_APP_EVT:
+ btif_hd_cb.app_registered = FALSE;
+ HAL_CBACK(bt_hd_callbacks, application_state_cb, NULL,
+ BTHD_APP_STATE_NOT_REGISTERED);
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("disabling hid device service now");
+ btif_hd_free_buf();
+ BTA_HdDisable();
+ }
+ break;
+
+ case BTA_HD_OPEN_EVT: {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_WARNING(
+ "BTA_HD_OPEN_EVT, address (%02x:%02x:%02x:%02x:%02x:%02x)",
+ addr->address[0], addr->address[1], addr->address[2],
+ addr->address[3], addr->address[4], addr->address[5]);
+ /* Check if the connection is from hid host and not hid device */
+ if (check_cod_hid(addr)) {
+ /* Incoming connection from hid device, reject it */
+ BTIF_TRACE_WARNING("remote device is not hid host, disconnecting");
+ btif_hd_cb.forced_disc = TRUE;
+ BTA_HdDisconnect();
+ break;
+ }
+ btif_storage_set_hidd((bt_bdaddr_t*)&p_data->conn.bda);
+
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_CONNECTED);
+ } break;
+
+ case BTA_HD_CLOSE_EVT:
+ if (btif_hd_cb.forced_disc) {
+ bt_bdaddr_t* addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_WARNING("remote device was forcefully disconnected");
+ btif_hd_remove_device(*addr);
+ btif_hd_cb.forced_disc = FALSE;
+ break;
+ }
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+ break;
+
+ case BTA_HD_GET_REPORT_EVT:
+ HAL_CBACK(bt_hd_callbacks, get_report_cb, p_data->get_report.report_type,
+ p_data->get_report.report_id, p_data->get_report.buffer_size);
+ break;
+
+ case BTA_HD_SET_REPORT_EVT:
+ HAL_CBACK(bt_hd_callbacks, set_report_cb, p_data->set_report.report_type,
+ p_data->set_report.report_id, p_data->set_report.len,
+ p_data->set_report.p_data);
+ break;
+
+ case BTA_HD_SET_PROTOCOL_EVT:
+ HAL_CBACK(bt_hd_callbacks, set_protocol_cb, p_data->set_protocol);
+ break;
+
+ case BTA_HD_INTR_DATA_EVT:
+ HAL_CBACK(bt_hd_callbacks, intr_data_cb, p_data->intr_data.report_id,
+ p_data->intr_data.len, p_data->intr_data.p_data);
+ break;
+
+ case BTA_HD_VC_UNPLUG_EVT:
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda, BTHD_CONN_STATE_DISCONNECTED);
+ if (bta_dm_check_if_only_hd_connected(p_data->conn.bda)) {
+ BTIF_TRACE_DEBUG("%s: Removing bonding as only HID profile connected",
+ __func__);
+ BTA_DmRemoveDevice((uint8_t*)&p_data->conn.bda);
+ } else {
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)&p_data->conn.bda;
+ BTIF_TRACE_DEBUG(
+ "%s: Only removing HID data as some other profiles "
+ "connected",
+ __func__);
+ btif_hd_remove_device(*bd_addr);
+ }
+ HAL_CBACK(bt_hd_callbacks, vc_unplug_cb);
+ break;
+
+ case BTA_HD_CONN_STATE_EVT:
+ HAL_CBACK(bt_hd_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda,
+ (bthd_connection_state_t)p_data->conn.status);
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s: unknown event (%d)", __func__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bte_hd_evt
+ *
+ * Description Switches context from BTE to BTIF for all BT-HD events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bte_hd_evt(tBTA_HD_EVT event, tBTA_HD* p_data) {
+ bt_status_t status;
+ int param_len = 0;
+ tBTIF_COPY_CBACK* p_copy_cback = NULL;
+
+ BTIF_TRACE_API("%s event=%d", __func__, event);
+
+ switch (event) {
+ case BTA_HD_ENABLE_EVT:
+ case BTA_HD_DISABLE_EVT:
+ case BTA_HD_UNREGISTER_APP_EVT:
+ param_len = sizeof(tBTA_HD_STATUS);
+ break;
+
+ case BTA_HD_REGISTER_APP_EVT:
+ param_len = sizeof(tBTA_HD_REG_STATUS);
+ break;
+
+ case BTA_HD_OPEN_EVT:
+ case BTA_HD_CLOSE_EVT:
+ case BTA_HD_VC_UNPLUG_EVT:
+ case BTA_HD_CONN_STATE_EVT:
+ param_len = sizeof(tBTA_HD_CONN);
+ break;
+
+ case BTA_HD_GET_REPORT_EVT:
+ param_len += sizeof(tBTA_HD_GET_REPORT);
+ break;
+
+ case BTA_HD_SET_REPORT_EVT:
+ param_len = sizeof(tBTA_HD_SET_REPORT) + p_data->set_report.len;
+ p_copy_cback = set_report_copy_cb;
+ break;
+
+ case BTA_HD_SET_PROTOCOL_EVT:
+ param_len += sizeof(p_data->set_protocol);
+ break;
+
+ case BTA_HD_INTR_DATA_EVT:
+ param_len = sizeof(tBTA_HD_INTR_DATA) + p_data->intr_data.len;
+ p_copy_cback = intr_data_copy_cb;
+ break;
+ }
+
+ status = btif_transfer_context(btif_hd_upstreams_evt, (uint16_t)event,
+ (char*)p_data, param_len, p_copy_cback);
+
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function init
+ *
+ * Description Initializes BT-HD interface
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+static bt_status_t init(bthd_callbacks_t* callbacks) {
+ BTIF_TRACE_API("%s", __func__);
+
+ bt_hd_callbacks = callbacks;
+ memset(&btif_hd_cb, 0, sizeof(btif_hd_cb));
+
+ btif_enable_service(BTA_HIDD_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Cleans up BT-HD interface
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_API("hd:%s", __func__);
+
+ if (bt_hd_callbacks) {
+ /* update flag, not to enable hid host service now as BT is switching off */
+ btif_hd_cb.service_dereg_active = FALSE;
+ btif_disable_service(BTA_HIDD_SERVICE_ID);
+ bt_hd_callbacks = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function register_app
+ *
+ * Description Registers HID Device application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t register_app(bthd_app_param_t* p_app_param,
+ bthd_qos_param_t* p_in_qos,
+ bthd_qos_param_t* p_out_qos) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application already registered", __func__);
+ return BT_STATUS_BUSY;
+ }
+
+ app_info.p_name = (char*)osi_malloc(BTIF_HD_APP_NAME_LEN);
+ memcpy(app_info.p_name, p_app_param->name, BTIF_HD_APP_NAME_LEN);
+ app_info.p_description = (char*)osi_malloc(BTIF_HD_APP_DESCRIPTION_LEN);
+ memcpy(app_info.p_description, p_app_param->description,
+ BTIF_HD_APP_DESCRIPTION_LEN);
+ app_info.p_provider = (char*)osi_malloc(BTIF_HD_APP_PROVIDER_LEN);
+ memcpy(app_info.p_provider, p_app_param->provider, BTIF_HD_APP_PROVIDER_LEN);
+ app_info.subclass = p_app_param->subclass;
+ app_info.descriptor.dl_len = p_app_param->desc_list_len;
+ app_info.descriptor.dsc_list =
+ (uint8_t*)osi_malloc(app_info.descriptor.dl_len);
+ memcpy(app_info.descriptor.dsc_list, p_app_param->desc_list,
+ p_app_param->desc_list_len);
+
+ in_qos.service_type = p_in_qos->service_type;
+ in_qos.token_rate = p_in_qos->token_rate;
+ in_qos.token_bucket_size = p_in_qos->token_bucket_size;
+ in_qos.peak_bandwidth = p_in_qos->peak_bandwidth;
+ in_qos.access_latency = p_in_qos->access_latency;
+ in_qos.delay_variation = p_in_qos->delay_variation;
+
+ out_qos.service_type = p_out_qos->service_type;
+ out_qos.token_rate = p_out_qos->token_rate;
+ out_qos.token_bucket_size = p_out_qos->token_bucket_size;
+ out_qos.peak_bandwidth = p_out_qos->peak_bandwidth;
+ out_qos.access_latency = p_out_qos->access_latency;
+ out_qos.delay_variation = p_out_qos->delay_variation;
+
+ /* register HID Device with L2CAP and unregister HID Host with L2CAP */
+ /* Disable HH */
+ btif_hh_service_registration(FALSE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function unregister_app
+ *
+ * Description Unregisters HID Device application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t unregister_app(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.service_dereg_active) {
+ BTIF_TRACE_WARNING("%s: BT-HD deregistering in progress", __func__);
+ return BT_STATUS_BUSY;
+ }
+
+ btif_hd_cb.service_dereg_active = TRUE;
+ BTA_HdUnregisterApp();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description Connects to host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdConnect(bd_addr->address);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description Disconnects from host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdDisconnect();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function send_report
+ *
+ * Description Sends Reports to hid host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_report(bthd_report_type_t type, uint8_t id,
+ uint16_t len, uint8_t* p_data) {
+ tBTA_HD_REPORT report;
+
+ APPL_TRACE_VERBOSE("%s: type=%d id=%d len=%d", __func__, type, id, len);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (type == BTHD_REPORT_TYPE_INTRDATA) {
+ report.type = BTHD_REPORT_TYPE_INPUT;
+ report.use_intr = TRUE;
+ } else {
+ report.type = (type & 0x03);
+ report.use_intr = FALSE;
+ }
+
+ report.id = id;
+ report.len = len;
+ report.p_data = p_data;
+
+ BTA_HdSendReport(&report);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function report_error
+ *
+ * Description Sends HANDSHAKE with error info for invalid SET_REPORT
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t report_error(uint8_t error) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdReportError(error);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function virtual_cable_unplug
+ *
+ * Description Sends Virtual Cable Unplug to host
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t virtual_cable_unplug(void) {
+ BTIF_TRACE_API("%s", __func__);
+
+ if (!btif_hd_cb.app_registered) {
+ BTIF_TRACE_WARNING("%s: application not yet registered", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+
+ if (btif_hd_cb.status != BTIF_HD_ENABLED) {
+ BTIF_TRACE_WARNING("%s: BT-HD not enabled, status=%d", __func__,
+ btif_hd_cb.status);
+ return BT_STATUS_NOT_READY;
+ }
+
+ BTA_HdVirtualCableUnplug();
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const bthd_interface_t bthdInterface = {
+ sizeof(bthdInterface),
+ init,
+ cleanup,
+ register_app,
+ unregister_app,
+ connect,
+ disconnect,
+ send_report,
+ report_error,
+ virtual_cable_unplug,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_hd_execute_service
+ *
+ * Description Enabled/disables BT-HD service
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_hd_execute_service(bool b_enable) {
+ BTIF_TRACE_API("%s: b_enable=%d", __func__, b_enable);
+
+ if (!b_enable) BTA_HdDisable();
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_get_interface
+ *
+ * Description Gets BT-HD interface
+ *
+ * Returns bthd_interface_t
+ *
+ ******************************************************************************/
+const bthd_interface_t* btif_hd_get_interface() {
+ BTIF_TRACE_API("%s", __func__);
+ return &bthdInterface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hd_service_registration
+ *
+ * Description Registers hid device service
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btif_hd_service_registration() {
+ BTIF_TRACE_API("%s", __func__);
+ /* enable HD */
+ if (bt_hd_callbacks != NULL) {
+ BTA_HdEnable(bte_hd_evt);
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_hf.cc b/mtkbt/code/bt/btif/src/btif_hf.cc
new file mode 100755
index 0000000..2be9b8d
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_hf.cc
@@ -0,0 +1,1668 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_hf"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf.h>
+
+#include "bta/include/utl.h"
+#include "bta_ag_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_hf.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+#include "osi/include/properties.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "btif_av.h"
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+#ifndef BTIF_HSAG_SERVICE_NAME
+#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
+#endif
+
+#ifndef BTIF_HFAG_SERVICE_NAME
+#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
+#endif
+
+#ifndef BTIF_HF_SERVICES
+#define BTIF_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK)
+#endif
+
+#ifndef BTIF_HF_SERVICE_NAMES
+#define BTIF_HF_SERVICE_NAMES \
+ { BTIF_HSAG_SERVICE_NAME, BTIF_HFAG_SERVICE_NAME }
+#endif
+
+#ifndef BTIF_HF_SECURITY
+#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_FEATURES
+#define BTIF_HF_FEATURES \
+ (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_CODEC | BTA_AG_FEAT_HF_IND | BTA_AG_FEAT_ESCO | \
+ BTA_AG_FEAT_UNAT)
+#endif
+
+/* HF features supported at runtime */
+static uint32_t btif_hf_features = BTIF_HF_FEATURES;
+
+#define BTIF_HF_CALL_END_TIMEOUT 6
+
+#define BTIF_HF_INVALID_IDX (-1)
+
+/* Number of BTIF-HF control blocks */
+#define BTIF_HF_NUM_CB 2
+
+/* Max HF clients supported from App */
+uint16_t btif_max_hf_clients = 1;
+
+/* HF app ids for service registration */
+typedef enum {
+ BTIF_HF_ID_1 = 0,
+ BTIF_HF_ID_2,
+#if (BTIF_HF_NUM_CB == 3)
+ BTIF_HF_ID_3
+#endif
+} bthf_hf_id_t;
+
+uint16_t bthf_hf_id[BTIF_HF_NUM_CB] = {BTIF_HF_ID_1, BTIF_HF_ID_2,
+#if (BTIF_HF_NUM_CB == 3)
+ BTIF_HF_ID_3
+#endif
+};
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static bthf_callbacks_t* bt_hf_callbacks = NULL;
+static int hf_idx = BTIF_HF_INVALID_IDX;
+
+#define CHECK_BTHF_INIT() \
+ do { \
+ if (bt_hf_callbacks == NULL) { \
+ BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } else { \
+ BTIF_TRACE_EVENT("BTHF: %s", __func__); \
+ } \
+ } while (0)
+
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct _btif_hf_cb {
+ uint16_t handle;
+ bt_bdaddr_t connected_bda;
+ bthf_connection_state_t state;
+ bthf_vr_state_t vr_state;
+ tBTA_AG_PEER_FEAT peer_feat;
+ int num_active;
+ int num_held;
+ struct timespec call_end_timestamp;
+ struct timespec connected_timestamp;
+ bthf_call_state_t call_setup_state;
+} btif_hf_cb_t;
+
+static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+/* By default, even though codec negotiation is enabled, we will not use WBS as
+* the default
+* codec unless this variable is set to true.
+*/
+/** M: Change feature: enalbe the WBS as default. @{ */
+#ifndef BTIF_HF_WBS_PREFERRED
+#define BTIF_HF_WBS_PREFERRED true
+#endif
+/** @} */
+bool btif_conf_hf_force_wbs = BTIF_HF_WBS_PREFERRED;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function is_connected
+ *
+ * Description Internal function to check if HF is connected
+ *
+ * Returns true if connected
+ *
+ ******************************************************************************/
+static bool is_connected(bt_bdaddr_t* bd_addr) {
+ int i;
+ for (i = 0; i < btif_max_hf_clients; ++i) {
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
+ ((bd_addr == NULL) ||
+ (bdcmp(bd_addr->address, btif_hf_cb[i].connected_bda.address) == 0)))
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_idx_by_bdaddr
+ *
+ * Description Internal function to get idx by bdaddr
+ *
+ * Returns idx
+ *
+ ******************************************************************************/
+static int btif_hf_idx_by_bdaddr(bt_bdaddr_t* bd_addr) {
+ int i;
+ for (i = 0; i < btif_max_hf_clients; ++i) {
+ if ((bdcmp(bd_addr->address, btif_hf_cb[i].connected_bda.address) == 0))
+ return i;
+ }
+ return BTIF_HF_INVALID_IDX;
+}
+
+/*******************************************************************************
+ *
+ * Function callstate_to_callsetup
+ *
+ * Description Converts HAL call state to BTA call setup indicator value
+ *
+ * Returns BTA call indicator value
+ *
+ ******************************************************************************/
+static uint8_t callstate_to_callsetup(bthf_call_state_t call_state) {
+ uint8_t call_setup = 0;
+ if (call_state == BTHF_CALL_STATE_INCOMING) call_setup = 1;
+ if (call_state == BTHF_CALL_STATE_DIALING) call_setup = 2;
+ if (call_state == BTHF_CALL_STATE_ALERTING) call_setup = 3;
+
+ return call_setup;
+}
+
+/*******************************************************************************
+ *
+ * Function send_at_result
+ *
+ * Description Send AT result code (OK/ERROR)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void send_at_result(uint8_t ok_flag, uint16_t errcode, int idx) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+
+ ag_res.ok_flag = ok_flag;
+ if (ok_flag == BTA_AG_OK_ERROR) {
+ ag_res.errcode = errcode;
+ }
+
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
+}
+
+/*******************************************************************************
+ *
+ * Function send_indicator_update
+ *
+ * Description Send indicator update (CIEV)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void send_indicator_update(uint16_t indicator, uint16_t value) {
+ tBTA_AG_RES_DATA ag_res;
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.ind.id = indicator;
+ ag_res.ind.value = value;
+
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+void clear_phone_state_multihf(int idx) {
+ btif_hf_cb[idx].call_setup_state = BTHF_CALL_STATE_IDLE;
+ btif_hf_cb[idx].num_active = btif_hf_cb[idx].num_held = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_latest_connected_idx
+ *
+ * Description Returns idx for latest connected HF
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static int btif_hf_latest_connected_idx() {
+ struct timespec now, conn_time_delta;
+ int latest_conn_idx = BTIF_HF_INVALID_IDX, i;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ conn_time_delta.tv_sec = now.tv_sec;
+
+ for (i = 0; i < btif_max_hf_clients; i++) {
+ if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+ if ((now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec) <
+ conn_time_delta.tv_sec) {
+ conn_time_delta.tv_sec =
+ now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec;
+ latest_conn_idx = i;
+ }
+ }
+ }
+ return latest_conn_idx;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_check_if_slc_connected
+ *
+ * Description Returns BT_STATUS_SUCCESS if SLC is up for any HF
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t btif_hf_check_if_slc_connected() {
+ if (bt_hf_callbacks == NULL) {
+ BTIF_TRACE_WARNING("BTHF: %s: BTHF not initialized", __func__);
+ return BT_STATUS_NOT_READY;
+ } else {
+ int i;
+ for (i = 0; i < btif_max_hf_clients; i++) {
+ if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+ BTIF_TRACE_EVENT("BTHF: %s: slc connected for idx = %d", __func__, i);
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ BTIF_TRACE_WARNING("BTHF: %s: No SLC connection up", __func__);
+ return BT_STATUS_NOT_READY;
+ }
+}
+
+/*****************************************************************************
+ * Section name (Group of functions)
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ * btif hf api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_hf_upstreams_evt
+ *
+ * Description Executes HF UPSTREAMS events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hf_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_AG* p_data = (tBTA_AG*)p_param;
+ bdstr_t bdstr;
+
+ /** M: Bug Fix @{ */
+ // For ENABLE and DISABLE events, the p_parame is no data, the access
+ // for hdr.handle will cause Heap Corruption.
+ int idx = -1;
+ if (event != BTA_AG_ENABLE_EVT && event != BTA_AG_DISABLE_EVT) {
+ idx = p_data->hdr.handle - 1;
+ }
+ /** @} */
+
+ BTIF_TRACE_DEBUG("%s: event=%s", __func__, dump_hf_event(event));
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return;
+ }
+
+ switch (event) {
+ case BTA_AG_ENABLE_EVT:
+ case BTA_AG_DISABLE_EVT:
+ break;
+
+ case BTA_AG_REGISTER_EVT:
+ btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
+ BTIF_TRACE_DEBUG(
+ "%s: BTA_AG_REGISTER_EVT,"
+ "btif_hf_cb.handle = %d",
+ __func__, btif_hf_cb[idx].handle);
+ break;
+
+ case BTA_AG_OPEN_EVT:
+ if (p_data->open.status == BTA_AG_SUCCESS) {
+ bdcpy(btif_hf_cb[idx].connected_bda.address, p_data->open.bd_addr);
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
+ btif_hf_cb[idx].peer_feat = 0;
+ clear_phone_state_multihf(idx);
+ } else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING) {
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ } else {
+ BTIF_TRACE_WARNING(
+ "%s: AG open failed, but another device connected. status=%d "
+ "state=%d connected device=%s",
+ __func__, p_data->open.status, btif_hf_cb[idx].state,
+ bdaddr_to_string(&btif_hf_cb[idx].connected_bda, bdstr,
+ sizeof(bdstr)));
+ break;
+ }
+
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
+
+ if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
+ bdsetany(btif_hf_cb[idx].connected_bda.address);
+
+ /** M: Bug fix for avoid a2dp connect delay @{ */
+ btif_queue_advance();
+ /** @} */
+ break;
+
+ case BTA_AG_CLOSE_EVT:
+ btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
+ BTIF_TRACE_DEBUG(
+ "%s: BTA_AG_CLOSE_EVT,"
+ "idx = %d, btif_hf_cb.handle = %d",
+ __func__, idx, btif_hf_cb[idx].handle);
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
+ bdsetany(btif_hf_cb[idx].connected_bda.address);
+ btif_hf_cb[idx].peer_feat = 0;
+ clear_phone_state_multihf(idx);
+ hf_idx = btif_hf_latest_connected_idx();
+ /* If AG_OPEN was received but SLC was not setup in a specified time (10
+ *seconds),
+ ** then AG_CLOSE may be received. We need to advance the queue here
+ */
+ /** M: Change feature For hfp cleanup @{ */
+ // Power off/on bt too fast lead to connect_queue not released, release it in advance.
+ if (bt_hf_callbacks != NULL)
+ /** @} */
+ btif_queue_advance();
+ break;
+
+ case BTA_AG_CONN_EVT:
+ clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[idx].connected_timestamp);
+ BTIF_TRACE_DEBUG("%s: BTA_AG_CONN_EVT, idx = %d ", __func__, idx);
+ btif_hf_cb[idx].peer_feat = p_data->conn.peer_feat;
+ btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
+ hf_idx = btif_hf_latest_connected_idx();
+
+ HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
+ &btif_hf_cb[idx].connected_bda);
+
+ /** M: Bug fix for avoid a2dp connect delay @{ */
+ //btif_queue_advance();
+ /** @} */
+ break;
+
+ case BTA_AG_AUDIO_OPEN_EVT:
+ hf_idx = idx;
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AUDIO_CLOSE_EVT:
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ /* BTA auto-responds, silently discard */
+ case BTA_AG_SPK_EVT:
+ case BTA_AG_MIC_EVT:
+ HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
+ (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK
+ : BTHF_VOLUME_TYPE_MIC,
+ p_data->val.num, &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_A_EVT:
+ if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
+ hf_idx = idx;
+ else
+ BTIF_TRACE_DEBUG("Donot set hf_idx for ATA since already in a call");
+
+ HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_BLDN_EVT:
+ case BTA_AG_AT_D_EVT:
+ if ((btif_hf_cb[0].num_held + btif_hf_cb[0].num_active) == 0)
+ hf_idx = idx;
+ else
+ BTIF_TRACE_DEBUG("Donot set hf_idx for BLDN/D since already in a call");
+
+ HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
+ (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_CHUP_EVT:
+ HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_CIND_EVT:
+ HAL_CBACK(bt_hf_callbacks, cind_cmd_cb, &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_VTS_EVT:
+ HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0],
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_BVRA_EVT:
+ HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED
+ : BTHF_VR_STATE_STOPPED,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_NREC_EVT:
+ HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
+ (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ /* TODO: Add a callback for CBC */
+ case BTA_AG_AT_CBC_EVT:
+ break;
+
+ case BTA_AG_AT_CKPD_EVT:
+ HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_WBS_EVT:
+ BTIF_TRACE_DEBUG(
+ "BTA_AG_WBS_EVT Set codec status %d codec %d 1=CVSD 2=MSBC",
+ p_data->val.hdr.status, p_data->val.num);
+ if (p_data->val.num == BTA_AG_CODEC_CVSD) {
+ HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NO,
+ &btif_hf_cb[idx].connected_bda);
+ } else if (p_data->val.num == BTA_AG_CODEC_MSBC) {
+ HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_YES,
+ &btif_hf_cb[idx].connected_bda);
+ } else {
+ HAL_CBACK(bt_hf_callbacks, wbs_cb, BTHF_WBS_NONE,
+ &btif_hf_cb[idx].connected_bda);
+ }
+ break;
+
+ /* Java needs to send OK/ERROR for these commands */
+ case BTA_AG_AT_CHLD_EVT:
+ HAL_CBACK(bt_hf_callbacks, chld_cmd_cb,
+ (bthf_chld_type_t)atoi(p_data->val.str),
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_CLCC_EVT:
+ HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb, &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_COPS_EVT:
+ HAL_CBACK(bt_hf_callbacks, cops_cmd_cb, &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_UNAT_EVT:
+ HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb, p_data->val.str,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_CNUM_EVT:
+ HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb, &btif_hf_cb[idx].connected_bda);
+ break;
+
+ /* TODO: Some of these commands may need to be sent to app. For now respond
+ * with error */
+ case BTA_AG_AT_BINP_EVT:
+ case BTA_AG_AT_BTRH_EVT:
+ send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED, idx);
+ break;
+ case BTA_AG_AT_BAC_EVT:
+ BTIF_TRACE_DEBUG("AG Bitmap of peer-codecs %d", p_data->val.num);
+ /* If the peer supports mSBC and the BTIF preferred codec is also mSBC,
+ then
+ we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC
+ at the time
+ of SCO connection establishment */
+ if ((btif_conf_hf_force_wbs == true) &&
+ (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+ BTIF_TRACE_EVENT("%s: btif_hf override-Preferred Codec to MSBC",
+ __func__);
+ BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
+ } else {
+ BTIF_TRACE_EVENT("%s btif_hf override-Preferred Codec to CVSD",
+ __func__);
+ BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_CVSD);
+ }
+ break;
+ case BTA_AG_AT_BCS_EVT:
+ BTIF_TRACE_DEBUG("%s: AG final selected codec is 0x%02x 1=CVSD 2=MSBC",
+ __func__, p_data->val.num);
+ /* No BTHF_WBS_NONE case, because HF1.6 supported device can send BCS */
+ /* Only CVSD is considered narrow band speech */
+ HAL_CBACK(
+ bt_hf_callbacks, wbs_cb,
+ (p_data->val.num == BTA_AG_CODEC_CVSD) ? BTHF_WBS_NO : BTHF_WBS_YES,
+ &btif_hf_cb[idx].connected_bda);
+ break;
+
+ case BTA_AG_AT_BIND_EVT:
+ if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
+ HAL_CBACK(bt_hf_callbacks, bind_cb, p_data->val.str,
+ &btif_hf_cb[idx].connected_bda);
+ }
+ break;
+
+ case BTA_AG_AT_BIEV_EVT:
+ if (p_data->val.hdr.status == BTA_AG_SUCCESS) {
+ HAL_CBACK(bt_hf_callbacks, biev_cb,
+ (bthf_hf_ind_type_t)p_data->val.lidx, (int)p_data->val.num,
+ &btif_hf_cb[idx].connected_bda);
+ }
+ break;
+ default:
+ BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bte_hf_evt
+ *
+ * Description Switches context from BTE to BTIF for all HF events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG* p_data) {
+ bt_status_t status;
+ int param_len = 0;
+
+ /* TODO: BTA sends the union members and not tBTA_AG. If using
+ * param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+ if (BTA_AG_REGISTER_EVT == event)
+ param_len = sizeof(tBTA_AG_REGISTER);
+ else if (BTA_AG_OPEN_EVT == event)
+ param_len = sizeof(tBTA_AG_OPEN);
+ else if (BTA_AG_CONN_EVT == event)
+ param_len = sizeof(tBTA_AG_CONN);
+ else if ((BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) ||
+ (BTA_AG_AUDIO_CLOSE_EVT == event))
+ param_len = sizeof(tBTA_AG_HDR);
+ else if (p_data)
+ param_len = sizeof(tBTA_AG_VAL);
+
+ /* switch context to btif task context (copy full union size for convenience)
+ */
+ status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event,
+ (char*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_in_hf_generic_evt
+ *
+ * Description Processes generic events to be sent to JNI that are not
+ * triggered from the BTA.
+ * Always runs in BTIF context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_in_hf_generic_evt(uint16_t event, char* p_param) {
+ int idx = btif_hf_idx_by_bdaddr((bt_bdaddr_t*)p_param);
+
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return;
+ }
+
+ switch (event) {
+ case BTIF_HFP_CB_AUDIO_CONNECTING: {
+ HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
+ &btif_hf_cb[idx].connected_bda);
+ } break;
+ default: {
+ BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ } break;
+ }
+}
+
+static bool inband_ringing_property_enabled() {
+ char inband_ringing_flag[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get("persist.bluetooth.enableinbandringing", inband_ringing_flag,
+ "false");
+ if (strncmp(inband_ringing_flag, "true", 4) == 0) {
+ BTIF_TRACE_DEBUG("%s: In-band ringing enabled by property", __func__);
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_init
+ *
+ * Description initializes the hf interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthf_callbacks_t* callbacks, int max_hf_clients,
+ bool inband_ringing_supported) {
+ bool inband_ringing_property_enable = inband_ringing_property_enabled();
+ if (inband_ringing_supported && inband_ringing_property_enable) {
+ btif_hf_features |= BTA_AG_FEAT_INBAND;
+ } else {
+ btif_hf_features &= ~BTA_AG_FEAT_INBAND;
+ }
+ btif_max_hf_clients = max_hf_clients;
+ BTIF_TRACE_DEBUG(
+ "%s: btif_hf_features=%zu, max_hf_clients=%d, "
+ "inband_ringing=[supported=%d, enabled=%d]",
+ __func__, btif_hf_features, btif_max_hf_clients, inband_ringing_supported,
+ inband_ringing_property_enable);
+ bt_hf_callbacks = callbacks;
+ memset(&btif_hf_cb, 0, sizeof(btif_hf_cb));
+
+/* Invoke the enable service API to the core to set the appropriate service_id
+ * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled
+ * (phone)
+ * othwerwise only HSP is enabled (tablet)
+*/
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+ btif_enable_service(BTA_HFP_SERVICE_ID);
+#else
+ btif_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+
+ for (int i = 0; i < btif_max_hf_clients; i++) clear_phone_state_multihf(i);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description connect to headset
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+ CHECK_BTHF_INIT();
+ int i;
+ for (i = 0; i < btif_max_hf_clients;) {
+ if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
+ (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)))
+ i++;
+ else
+ break;
+ }
+
+ if (i == btif_max_hf_clients) return BT_STATUS_BUSY;
+
+ if (!is_connected(bd_addr)) {
+ btif_hf_cb[i].state = BTHF_CONNECTION_STATE_CONNECTING;
+ bdcpy(btif_hf_cb[i].connected_bda.address, bd_addr->address);
+
+ BTA_AgOpen(btif_hf_cb[i].handle, btif_hf_cb[i].connected_bda.address,
+ BTIF_HF_SECURITY, BTIF_HF_SERVICES);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_BUSY;
+}
+
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+ return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description disconnect from headset
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ BTA_AgClose(btif_hf_cb[idx].handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function connect_audio
+ *
+ * Description create an audio connection
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_audio(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ /* Check if SLC is connected */
+ if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+ return BT_STATUS_NOT_READY;
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ BTA_AgAudioOpen(btif_hf_cb[idx].handle);
+
+ /* Inform the application that the audio connection has been initiated
+ * successfully */
+ btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect_audio
+ *
+ * Description close the audio connection
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect_audio(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ BTA_AgAudioClose(btif_hf_cb[idx].handle);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function start_voice_recognition
+ *
+ * Description start voice recognition
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t start_voice_recognition(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 1;
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ } else {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+ *
+ * Function stop_voice_recognition
+ *
+ * Description stop voice recognition
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t stop_voice_recognition(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = 0;
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ } else {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return BT_STATUS_NOT_READY;
+}
+
+/*******************************************************************************
+ *
+ * Function volume_control
+ *
+ * Description volume control
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t volume_control(bthf_volume_type_t type, int volume,
+ bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ ag_res.num = volume;
+ BTA_AgResult(
+ btif_hf_cb[idx].handle,
+ (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
+ &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function device_status_notification
+ *
+ * Description Combined device status change notification
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
+ bthf_service_type_t svc_type,
+ int signal, int batt_chg) {
+ CHECK_BTHF_INIT();
+
+ if (is_connected(NULL)) {
+ /* send all indicators to BTA.
+ ** BTA will make sure no duplicates are sent out
+ */
+ send_indicator_update(BTA_AG_IND_SERVICE,
+ (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
+ send_indicator_update(BTA_AG_IND_ROAM,
+ (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
+ send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+ send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function cops_response
+ *
+ * Description Response for COPS command
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t cops_response(const char* cops, bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+
+ /* Format the response */
+ snprintf(ag_res.str, sizeof(ag_res.str), "0,0,\"%.16s\"", cops);
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function cind_response
+ *
+ * Description Response for CIND command
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+ bthf_call_state_t call_setup_state, int signal,
+ int roam, int batt_chg, bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+
+ memset(&ag_res, 0, sizeof(ag_res));
+ /* per the errata 2043, call=1 implies atleast one call is in progress
+ *(active/held)
+ ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+ **/
+ snprintf(
+ ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d,%d,%d",
+ (num_active + num_held) ? 1 : 0, /* Call state */
+ callstate_to_callsetup(call_setup_state), /* Callsetup state */
+ svc, /* network service */
+ signal, /* Signal strength */
+ roam, /* Roaming indicator */
+ batt_chg, /* Battery level */
+ ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
+
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CIND_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function bind_response
+ *
+ * Description Send +BIND response
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t bind_response(bthf_hf_ind_type_t ind_id,
+ bthf_hf_ind_status_t ind_status,
+ bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int index = btif_hf_idx_by_bdaddr(bd_addr);
+ if (!is_connected(bd_addr) || index == BTIF_HF_INVALID_IDX)
+ return BT_STATUS_FAIL;
+
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.ind.id = ind_id;
+ ag_res.ind.on_demand = (ind_status == BTHF_HF_IND_ENABLED);
+
+ BTA_AgResult(btif_hf_cb[index].handle, BTA_AG_BIND_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function formatted_at_response
+ *
+ * Description Pre-formatted AT response, typically in response to unknown
+ * AT cmd
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t formatted_at_response(const char* rsp,
+ bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+ tBTA_AG_RES_DATA ag_res;
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ /* Format the response and send */
+ memset(&ag_res, 0, sizeof(ag_res));
+ strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function at_response
+ *
+ * Description ok/error response
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t at_response(bthf_at_response_t response_code, int error_code,
+ bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
+ : BTA_AG_OK_ERROR,
+ error_code, idx);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function clcc_response
+ *
+ * Description response for CLCC command
+ * Can be iteratively called for each call index. Call index
+ * of 0 will be treated as NULL termination (Completes
+ * response)
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+ bthf_call_state_t state, bthf_call_mode_t mode,
+ bthf_call_mpty_type_t mpty, const char* number,
+ bthf_call_addrtype_t type,
+ bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+
+ /* Format the response */
+ if (index == 0) {
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ } else {
+ BTIF_TRACE_EVENT(
+ "clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
+ index, dir, state, mode, number, type);
+ int res_strlen =
+ snprintf(ag_res.str, sizeof(ag_res.str), "%d,%d,%d,%d,%d", index, dir,
+ state, mode, mpty);
+
+ if (number) {
+ size_t rem_bytes = sizeof(ag_res.str) - res_strlen;
+ char dialnum[sizeof(ag_res.str)];
+ size_t newidx = 0;
+ if (type == BTHF_CALL_ADDRTYPE_INTERNATIONAL && *number != '+') {
+ dialnum[newidx++] = '+';
+ }
+ for (size_t i = 0; number[i] != 0; i++) {
+ if (utl_isdialchar(number[i])) {
+ dialnum[newidx++] = number[i];
+ }
+ }
+ dialnum[newidx] = 0;
+ snprintf(&ag_res.str[res_strlen], rem_bytes, ",\"%s\",%d", dialnum,
+ type);
+ }
+ }
+ BTA_AgResult(btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
+
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function phone_state_change
+ *
+ * Description notify of a call state change
+ * number & type: valid only for incoming & waiting call
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+
+static bt_status_t phone_state_change(int num_active, int num_held,
+ bthf_call_state_t call_setup_state,
+ const char* number,
+ bthf_call_addrtype_t type) {
+ tBTA_AG_RES res = 0xff;
+ tBTA_AG_RES_DATA ag_res;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ bool activeCallUpdated = false;
+ int idx, i;
+
+ /* hf_idx is index of connected HS that sent ATA/BLDN,
+ otherwise index of latest connected HS */
+ if (hf_idx != BTIF_HF_INVALID_IDX)
+ idx = hf_idx;
+ else
+ idx = btif_hf_latest_connected_idx();
+
+ BTIF_TRACE_DEBUG("phone_state_change: idx = %d", idx);
+
+ /* Check if SLC is connected */
+ if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
+ return BT_STATUS_NOT_READY;
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_HFP_DEALY_OPEN_SCO,
+ (const bt_bdaddr_t *)&(btif_hf_cb[idx].connected_bda))) {
+ if ((num_active == 0 && num_held == 0)
+ &&( call_setup_state != BTHF_CALL_STATE_IDLE)
+ && (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE )) {
+ if (0x3 == btif_sm_get_state(btif_av_get_sm_handle())) {
+ BTIF_TRACE_DEBUG("phone_state_change: need to wait a2dp suspend!!!");
+ usleep(500 * 1000);
+ BTIF_TRACE_DEBUG("phone_state_change: awake!!!");
+ }
+ }
+ }
+#endif
+
+ BTIF_TRACE_DEBUG(
+ "phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"
+ " call_setup=%s [prev: %s]",
+ num_active, btif_hf_cb[idx].num_active, num_held,
+ btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
+ dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
+
+ /* if all indicators are 0, send end call and return */
+ if (num_active == 0 && num_held == 0 &&
+ call_setup_state == BTHF_CALL_STATE_IDLE) {
+ BTIF_TRACE_DEBUG("%s: Phone on hook", __func__);
+
+ /* record call termination timestamp if there was an active/held call or
+ callsetup state > BTHF_CALL_STATE_IDLE */
+ if ((btif_hf_cb[idx].call_setup_state != BTHF_CALL_STATE_IDLE) ||
+ (btif_hf_cb[idx].num_active) || (btif_hf_cb[idx].num_held)) {
+ BTIF_TRACE_DEBUG("%s: Record call termination timestamp", __func__);
+ clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[0].call_end_timestamp);
+ }
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+ hf_idx = BTIF_HF_INVALID_IDX;
+
+ /* if held call was present, reset that as well */
+ if (btif_hf_cb[idx].num_held) send_indicator_update(BTA_AG_IND_CALLHELD, 0);
+
+ goto update_call_states;
+ }
+
+ /* active state can change when:
+ ** 1. an outgoing/incoming call was answered
+ ** 2. an held was resumed
+ ** 3. without callsetup notifications, call became active
+ ** (3) can happen if call is active and a headset connects to us
+ **
+ ** In the case of (3), we will have to notify the stack of an active
+ ** call, instead of sending an indicator update. This will also
+ ** force the SCO to be setup. Handle this special case here prior to
+ ** call setup handling
+ */
+ if (((num_active + num_held) > 0) && (btif_hf_cb[idx].num_active == 0) &&
+ (btif_hf_cb[idx].num_held == 0) &&
+ (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE)) {
+ BTIF_TRACE_DEBUG(
+ "%s: Active/Held call notification received without call setup update",
+ __func__);
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+ /* Addition call setup with the Active call
+ ** CIND response should have been updated.
+ ** just open SCO connection.
+ */
+ if (call_setup_state != BTHF_CALL_STATE_IDLE)
+ res = BTA_AG_MULTI_CALL_RES;
+ else
+ res = BTA_AG_OUT_CALL_CONN_RES;
+
+/** M: Add for IOT device. @{ */
+// Wait a while for remote device to enter SLC connected state.
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_WAIT_SLC_FOR_SCO,
+ (const bt_bdaddr_t *)&(btif_hf_cb[idx].connected_bda))) {
+ if (BTA_AG_OUT_CALL_CONN_RES == res) {
+ BTIF_TRACE_ERROR("phone_state_change: need to wait SLC ready!!!");
+ usleep(100 * 1000);
+ BTIF_TRACE_ERROR("phone_state_change: Update phone state!!!");
+ }
+ }
+#endif
+/** @} */
+
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+ activeCallUpdated = true;
+ }
+
+ /* Ringing call changed? */
+ if (call_setup_state != btif_hf_cb[idx].call_setup_state) {
+ BTIF_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s", __func__,
+ dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
+ dump_hf_call_state(call_setup_state));
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ switch (call_setup_state) {
+ case BTHF_CALL_STATE_IDLE: {
+ switch (btif_hf_cb[idx].call_setup_state) {
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active > btif_hf_cb[idx].num_active) {
+ res = BTA_AG_IN_CALL_CONN_RES;
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
+ } else if (num_held > btif_hf_cb[idx].num_held)
+ res = BTA_AG_IN_CALL_HELD_RES;
+ else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ case BTHF_CALL_STATE_ALERTING:
+ if (num_active > btif_hf_cb[idx].num_active) {
+ ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ } else
+ res = BTA_AG_CALL_CANCEL_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s: Incorrect Call setup state transition",
+ __func__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ } break;
+
+ case BTHF_CALL_STATE_INCOMING:
+ if (num_active || num_held) {
+ res = BTA_AG_CALL_WAIT_RES;
+ } else {
+ res = BTA_AG_IN_CALL_RES;
+ }
+ if (number) {
+ int xx = 0;
+ if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
+ xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"+%s\"", number);
+ else
+ xx = snprintf(ag_res.str, sizeof(ag_res.str), "\"%s\"", number);
+ ag_res.num = type;
+
+ if (res == BTA_AG_CALL_WAIT_RES)
+ snprintf(&ag_res.str[xx], sizeof(ag_res.str) - xx, ",%d", type);
+ }
+ break;
+ case BTHF_CALL_STATE_DIALING:
+ if (!(num_active + num_held))
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
+ res = BTA_AG_OUT_CALL_ORIG_RES;
+ break;
+ case BTHF_CALL_STATE_ALERTING:
+ /* if we went from idle->alert, force SCO setup here. dialing usually
+ * triggers it */
+ if ((btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) &&
+ !(num_active + num_held))
+ ag_res.audio_handle = btif_hf_cb[idx].handle;
+ res = BTA_AG_OUT_CALL_ALERT_RES;
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s: Incorrect new ringing call state", __func__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ BTIF_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d",
+ __func__, res, ag_res.audio_handle);
+
+ if (res) BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+
+ /* if call setup is idle, we have already updated call indicator, jump out
+ */
+ if (call_setup_state == BTHF_CALL_STATE_IDLE) {
+ /* check & update callheld */
+ if ((num_held > 0) && (num_active > 0))
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ goto update_call_states;
+ }
+ }
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ /* per the errata 2043, call=1 implies atleast one call is in progress
+ *(active/held)
+ ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
+ ** Handle call indicator change
+ **/
+ if (!activeCallUpdated &&
+ ((num_active + num_held) !=
+ (btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held))) {
+ BTIF_TRACE_DEBUG("%s: Active call states changed. old: %d new: %d",
+ __func__, btif_hf_cb[idx].num_active, num_active);
+ send_indicator_update(BTA_AG_IND_CALL,
+ ((num_active + num_held) > 0) ? 1 : 0);
+ }
+
+ /* Held Changed? */
+ if (num_held != btif_hf_cb[idx].num_held ||
+ ((num_active == 0) && ((num_held + btif_hf_cb[idx].num_held) > 1))) {
+ BTIF_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d", __func__,
+ btif_hf_cb[idx].num_held, num_held);
+ send_indicator_update(BTA_AG_IND_CALLHELD,
+ ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
+ }
+
+ /* Calls Swapped? */
+ if ((call_setup_state == btif_hf_cb[idx].call_setup_state) &&
+ (num_active && num_held) && (num_active == btif_hf_cb[idx].num_active) &&
+ (num_held == btif_hf_cb[idx].num_held)) {
+ BTIF_TRACE_DEBUG("%s: Calls swapped", __func__);
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ }
+
+update_call_states:
+ for (i = 0; i < btif_max_hf_clients; i++) {
+ if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
+ btif_hf_cb[i].num_active = num_active;
+ btif_hf_cb[i].num_held = num_held;
+ btif_hf_cb[i].call_setup_state = call_setup_state;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_is_call_idle
+ *
+ * Description returns true if no call is in progress
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bool btif_hf_is_call_idle(void) {
+ if (bt_hf_callbacks == NULL) return true;
+
+ for (int i = 0; i < btif_max_hf_clients; ++i) {
+ if ((btif_hf_cb[i].call_setup_state != BTHF_CALL_STATE_IDLE) ||
+ ((btif_hf_cb[i].num_held + btif_hf_cb[i].num_active) > 0))
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_call_terminated_recently
+ *
+ * Description Checks if a call has been terminated
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+bool btif_hf_call_terminated_recently() {
+ struct timespec now;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (now.tv_sec <
+ btif_hf_cb[0].call_end_timestamp.tv_sec + BTIF_HF_CALL_END_TIMEOUT) {
+ return true;
+ } else {
+ btif_hf_cb[0].call_end_timestamp.tv_sec = 0;
+ return false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Closes the HF interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ if (bt_hf_callbacks) {
+ /** M: Bug fix For hfp cleanup @{ */
+ // NE when bt on/off. Set it to NULL in advance.
+ bt_hf_callbacks = NULL;
+ /** @} */
+#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+ btif_disable_service(BTA_HFP_SERVICE_ID);
+#else
+ btif_disable_service(BTA_HSP_SERVICE_ID);
+#endif
+ /** M: Bug fix For hfp cleanup @{ */
+ // NE when bt on/off. Set it to NULL in advance.
+ //bt_hf_callbacks = NULL;
+ /** @} */
+ }
+ /** M: Change feature For hfp cleanup @{ */
+ // Power off/on bt too fast lead to connect_queue not released, release it in advance.
+ BTIF_TRACE_EVENT("release connect_queue when hfp cleanup");
+ btif_queue_release();
+ /** @} */
+}
+
+/*******************************************************************************
+ *
+ * Function configure_wbs
+ *
+ * Description set to over-ride the current WBS configuration.
+ * It will not send codec setting cmd to the controller now.
+ * It just change the configure.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t configure_wbs(bt_bdaddr_t* bd_addr,
+ bthf_wbs_config_t config) {
+ CHECK_BTHF_INIT();
+
+ int idx = btif_hf_idx_by_bdaddr(bd_addr);
+
+ if ((idx < 0) || (idx >= BTIF_HF_NUM_CB)) {
+ BTIF_TRACE_ERROR("%s: Invalid index %d", __func__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_EVENT("%s config is %d", __func__, config);
+ if (config == BTHF_WBS_YES)
+ BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_MSBC);
+ else if (config == BTHF_WBS_NO)
+ BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_CVSD);
+ else
+ BTA_AgSetCodec(btif_hf_cb[idx].handle, BTA_AG_CODEC_NONE);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const bthf_interface_t bthfInterface = {
+ sizeof(bthfInterface),
+ init,
+ connect,
+ disconnect,
+ connect_audio,
+ disconnect_audio,
+ start_voice_recognition,
+ stop_voice_recognition,
+ volume_control,
+ device_status_notification,
+ cops_response,
+ cind_response,
+ formatted_at_response,
+ at_response,
+ clcc_response,
+ phone_state_change,
+ cleanup,
+ configure_wbs,
+ bind_response,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_hf_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hf_execute_service(bool b_enable) {
+ const char* p_service_names[] = BTIF_HF_SERVICE_NAMES;
+ int i;
+ if (b_enable) {
+ /* Enable and register with BTA-AG */
+ BTA_AgEnable(BTA_AG_PARSE, bte_hf_evt);
+ for (i = 0; i < btif_max_hf_clients; i++) {
+ BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY, btif_hf_features,
+ p_service_names, bthf_hf_id[i]);
+ }
+ } else {
+ /* De-register AG */
+ for (i = 0; i < btif_max_hf_clients; i++) {
+ BTA_AgDeregister(btif_hf_cb[i].handle);
+ }
+ /* Disable AG */
+ BTA_AgDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_get_interface
+ *
+ * Description Get the hf callback interface
+ *
+ * Returns bthf_interface_t
+ *
+ ******************************************************************************/
+const bthf_interface_t* btif_hf_get_interface() {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bthfInterface;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_hf_client.cc b/mtkbt/code/bt/btif/src/btif_hf_client.cc
new file mode 100755
index 0000000..3b86aaa
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_hf_client.cc
@@ -0,0 +1,1059 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_hf_client.c
+ *
+ * Description: Handsfree Profile (HF role) Bluetooth Interface
+ *
+ * Notes:
+ * a) Lifecycle of a control block
+ * Control block handles the lifecycle for a particular remote device's
+ * connection. The connection can go via the classic phases but more
+ * importantly there's only two messages from BTA that affect this.
+ * BTA_HF_CLIENT_OPEN_EVT and BTA_HF_CLIENT_CLOSE_EVT. Since the API between
+ * BTIF and BTA is controlled entirely by handles it's important to know where
+ * the handles are created and destroyed. Handles can be created at two
+ * locations:
+ * -- While connect() is called from BTIF. This is an outgoing connection
+ * -- While accepting an incoming connection (see BTA_HF_CLIENT_OPEN_EVT
+ * handling).
+ *
+ * The destruction or rather reuse of handles can be done when
+ * BTA_HF_CLIENT_CLOSE_EVT is called. Refer to the event handling for details
+ * of this.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_hfc"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_hf_client.h>
+
+#include "bt_utils.h"
+#include "bta_hf_client_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+#ifndef BTIF_HF_CLIENT_SERVICE_NAME
+#define BTIF_HF_CLIENT_SERVICE_NAME ("Handsfree")
+#endif
+
+#ifndef BTIF_HF_CLIENT_SECURITY
+#define BTIF_HF_CLIENT_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTIF_HF_CLIENT_FEATURES
+#define BTIF_HF_CLIENT_FEATURES \
+ (BTA_HF_CLIENT_FEAT_ECNR | BTA_HF_CLIENT_FEAT_3WAY | \
+ BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \
+ BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC)
+#endif
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+/* BTIF-HF control block to map bdaddr to BTA handle */
+typedef struct {
+ uint16_t handle; // Handle obtained frm the BTA
+ bt_bdaddr_t peer_bda; // Device corresponding to handle
+ bthf_client_connection_state_t state; // State of current connection
+ tBTA_HF_CLIENT_PEER_FEAT peer_feat; // HF features
+ tBTA_HF_CLIENT_CHLD_FEAT chld_feat; // AT+CHLD=<> command features
+} btif_hf_client_cb_t;
+
+/* Max devices supported by BTIF (useful to match the value in BTA) */
+#define HF_CLIENT_MAX_DEVICES 10
+typedef struct {
+ btif_hf_client_cb_t cb[HF_CLIENT_MAX_DEVICES];
+} btif_hf_client_cb_arr_t;
+
+/******************************************************************************
+ * Local function declarations
+ ******************************************************************************/
+btif_hf_client_cb_t* btif_hf_client_get_cb_by_handle(uint16_t handle);
+btif_hf_client_cb_t* btif_hf_client_get_cb_by_bda(const uint8_t* addr);
+bool is_connected(const btif_hf_client_cb_t* cb);
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static bthf_client_callbacks_t* bt_hf_client_callbacks = NULL;
+
+char btif_hf_client_version[PROPERTY_VALUE_MAX];
+
+#define CHECK_BTHF_CLIENT_INIT() \
+ do { \
+ if (bt_hf_client_callbacks == NULL) { \
+ BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } else { \
+ BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \
+ } \
+ } while (0)
+
+#define CHECK_BTHF_CLIENT_SLC_CONNECTED(cb) \
+ do { \
+ if (bt_hf_client_callbacks == NULL) { \
+ BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } else if ((cb)->state != BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \
+ BTIF_TRACE_WARNING("BTHF CLIENT: %s: SLC connection not up. state=%s", \
+ __func__, dump_hf_conn_state((cb)->state)); \
+ return BT_STATUS_NOT_READY; \
+ } else { \
+ BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \
+ } \
+ } while (0)
+
+static btif_hf_client_cb_arr_t btif_hf_client_cb_arr;
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_in_hf_client_generic_evt
+ *
+ * Description Processes generic events to be sent to JNI that are not
+ * triggered from the BTA.
+ * Always runs in BTIF context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_in_hf_client_generic_evt(uint16_t event, char* p_param) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)p_param;
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) {
+ BTIF_TRACE_ERROR("%s: failed to find block for bda", __func__);
+ }
+
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ switch (event) {
+ case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING: {
+ HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda,
+ (bthf_client_audio_state_t)BTHF_AUDIO_STATE_CONNECTING);
+ } break;
+ default: {
+ BTIF_TRACE_WARNING("%s: : Unknown event 0x%x", __func__, event);
+ } break;
+ }
+}
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+bool is_connected(const btif_hf_client_cb_t* cb) {
+ if ((cb->state == BTHF_CLIENT_CONNECTION_STATE_CONNECTED) ||
+ (cb->state == BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED))
+ return true;
+
+ BTIF_TRACE_ERROR("%s: not connected!", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_get_cb_by_handle
+ *
+ * Description Get control block by handle
+ *
+ * Returns btif_hf_client_cb_t pointer if available NULL otherwise
+ *
+ ******************************************************************************/
+btif_hf_client_cb_t* btif_hf_client_get_cb_by_handle(uint16_t handle) {
+ BTIF_TRACE_DEBUG("%s: cb by handle %d", __func__, handle);
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ // Block is valid only if it is allocated i.e. state is not DISCONNECTED
+ if (btif_hf_client_cb_arr.cb[i].state !=
+ BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED &&
+ btif_hf_client_cb_arr.cb[i].handle == handle) {
+ return &btif_hf_client_cb_arr.cb[i];
+ }
+ }
+ BTIF_TRACE_ERROR("%s: could not find block for handle %d", __func__, handle);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_get_cb_by_bda
+ *
+ * Description Get control block by bda
+ *
+ * Returns btif_hf_client_cb_t pointer if available NULL otherwise
+ *
+ ******************************************************************************/
+btif_hf_client_cb_t* btif_hf_client_get_cb_by_bda(const uint8_t* bd_addr) {
+ BTIF_TRACE_DEBUG("%s incoming addr %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ // Block is valid only if it is allocated i.e. state is not DISCONNECTED
+ if (btif_hf_client_cb_arr.cb[i].state !=
+ BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED &&
+ !bdcmp(btif_hf_client_cb_arr.cb[i].peer_bda.address, bd_addr)) {
+ return &btif_hf_client_cb_arr.cb[i];
+ }
+ }
+ BTIF_TRACE_ERROR("%s: could not find block for bdaddr", __func__);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_allocate_cb
+ *
+ * Description Get control block by bda
+ *
+ * Returns btif_hf_client_cb_t pointer if available NULL otherwise
+ *
+ ******************************************************************************/
+btif_hf_client_cb_t* btif_hf_client_allocate_cb() {
+ for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
+ btif_hf_client_cb_t* cb = &btif_hf_client_cb_arr.cb[i];
+ if (cb->state == BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED) {
+ return cb;
+ }
+ }
+ BTIF_TRACE_ERROR("%s: unable to allocate control block", __func__);
+ return NULL;
+}
+
+
+/*****************************************************************************
+ *
+ * btif hf api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_init
+ *
+ * Description initializes the hf interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthf_client_callbacks_t* callbacks) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ bt_hf_client_callbacks = callbacks;
+
+ btif_enable_service(BTA_HFP_HS_SERVICE_ID);
+
+ memset(&btif_hf_client_cb_arr, 0, sizeof(btif_hf_client_cb_arr_t));
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description connect to audio gateway
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
+ btif_hf_client_cb_t* cb = btif_hf_client_allocate_cb();
+ if (cb == NULL) {
+ BTIF_TRACE_ERROR("%s: could not allocate block!", __func__);
+ return BT_STATUS_BUSY;
+ }
+
+ bdcpy(cb->peer_bda.address, bd_addr->address);
+ if (is_connected(cb)) return BT_STATUS_BUSY;
+
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_CONNECTING;
+ bdcpy(cb->peer_bda.address, bd_addr->address);
+
+ /* Open HF connection to remote device and get the relevant handle.
+ * The handle is valid until we have called BTA_HfClientClose or the LL
+ * has notified us of channel close due to remote closing, error etc.
+ */
+ BTA_HfClientOpen(cb->peer_bda.address, BTIF_HF_CLIENT_SECURITY, &cb->handle);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_EVENT("HFP Client version is %s", btif_hf_client_version);
+ CHECK_BTHF_CLIENT_INIT();
+ return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description disconnect from audio gateway
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(const bt_bdaddr_t* bd_addr) {
+ CHECK_BTHF_CLIENT_INIT();
+
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb != NULL) {
+ BTA_HfClientClose(cb->handle);
+ return BT_STATUS_SUCCESS;
+ } else {
+ return BT_STATUS_BUSY;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function connect_audio
+ *
+ * Description create an audio connection
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_audio(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if ((BTIF_HF_CLIENT_FEATURES & BTA_HF_CLIENT_FEAT_CODEC) &&
+ (cb->peer_feat & BTA_HF_CLIENT_PEER_CODEC)) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
+ } else {
+ BTA_HfClientAudioOpen(cb->handle);
+ }
+
+ /* Inform the application that the audio connection has been initiated
+ * successfully */
+ btif_transfer_context(btif_in_hf_client_generic_evt,
+ BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, (char*)bd_addr,
+ sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect_audio
+ *
+ * Description close the audio connection
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect_audio(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTA_HfClientAudioClose(cb->handle);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function start_voice_recognition
+ *
+ * Description start voice recognition
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t start_voice_recognition(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1, 0, NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function stop_voice_recognition
+ *
+ * Description stop voice recognition
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t stop_voice_recognition(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0, 0, NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function volume_control
+ *
+ * Description volume control
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t volume_control(const bt_bdaddr_t* bd_addr,
+ bthf_client_volume_type_t type, int volume) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ switch (type) {
+ case BTHF_CLIENT_VOLUME_TYPE_SPK:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_VGS, volume, 0, NULL);
+ break;
+ case BTHF_CLIENT_VOLUME_TYPE_MIC:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_VGM, volume, 0, NULL);
+ break;
+ default:
+ return BT_STATUS_UNSUPPORTED;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function dial
+ *
+ * Description place a call
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t dial(UNUSED_ATTR const bt_bdaddr_t* bd_addr,
+ const char* number) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if (number) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0, number);
+ } else {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0, 0, NULL);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function dial_memory
+ *
+ * Description place a call with number specified by location (speed dial)
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t dial_memory(const bt_bdaddr_t* bd_addr, int location) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_ATD, location, 0, NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function handle_call_action
+ *
+ * Description handle specified call related action
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t handle_call_action(const bt_bdaddr_t* bd_addr,
+ bthf_client_call_action_t action,
+ int idx) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ switch (action) {
+ case BTHF_CLIENT_CALL_ACTION_CHLD_0:
+ if (cb->chld_feat & BTA_HF_CLIENT_CHLD_REL) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 0, 0, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_1:
+ // CHLD 1 is mandatory for 3 way calling
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, 0, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_2:
+ // CHLD 2 is mandatory for 3 way calling
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, 0, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_3:
+ if (cb->chld_feat & BTA_HF_CLIENT_CHLD_MERGE) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 3, 0, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_4:
+ if (cb->chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 4, 0, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_1x:
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_ECC) {
+ if (idx < 1) {
+ return BT_STATUS_FAIL;
+ }
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 1, idx, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_CHLD_2x:
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_ECC) {
+ if (idx < 1) {
+ return BT_STATUS_FAIL;
+ }
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHLD, 2, idx, NULL);
+ break;
+ }
+ return BT_STATUS_UNSUPPORTED;
+ case BTHF_CLIENT_CALL_ACTION_ATA:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_ATA, 0, 0, NULL);
+ break;
+ case BTHF_CLIENT_CALL_ACTION_CHUP:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0, 0, NULL);
+ break;
+ case BTHF_CLIENT_CALL_ACTION_BTRH_0:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0, 0, NULL);
+ break;
+ case BTHF_CLIENT_CALL_ACTION_BTRH_1:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1, 0, NULL);
+ break;
+ case BTHF_CLIENT_CALL_ACTION_BTRH_2:
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2, 0, NULL);
+ break;
+ default:
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function query_current_calls
+ *
+ * Description query list of current calls
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t query_current_calls(UNUSED_ATTR const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_ECS) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0, 0, NULL);
+ return BT_STATUS_SUCCESS;
+ }
+
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function query_current_operator_name
+ *
+ * Description query current selected operator name
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t query_current_operator_name(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0, NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function retieve_subscriber_info
+ *
+ * Description retrieve subscriber number information
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t retrieve_subscriber_info(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function send_dtmf
+ *
+ * Description send dtmf
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_dtmf(const bt_bdaddr_t* bd_addr, char code) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_VTS, code, 0, NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function request_last_voice_tag_number
+ *
+ * Description Request number from AG for VR purposes
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t request_last_voice_tag_number(const bt_bdaddr_t* bd_addr) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_VTAG) {
+ BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BINP, 1, 0, NULL);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Closes the HF interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ if (bt_hf_client_callbacks) {
+ btif_disable_service(BTA_HFP_HS_SERVICE_ID);
+ bt_hf_client_callbacks = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function send_at_cmd
+ *
+ * Description Send requested AT command to rempte device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_at_cmd(const bt_bdaddr_t* bd_addr, int cmd, int val1,
+ int val2, const char* arg) {
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(bd_addr->address);
+ if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
+
+ CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
+
+ BTIF_TRACE_EVENT("%s: Cmd %d val1 %d val2 %d arg %s", __func__, cmd, val1,
+ val2, (arg != NULL) ? arg : "<null>");
+ BTA_HfClientSendAT(cb->handle, cmd, val1, val2, arg);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const bthf_client_interface_t bthfClientInterface = {
+ sizeof(bthf_client_interface_t),
+ .init = init,
+ .connect = connect,
+ .disconnect = disconnect,
+ .connect_audio = connect_audio,
+ .disconnect_audio = disconnect_audio,
+ .start_voice_recognition = start_voice_recognition,
+ .stop_voice_recognition = stop_voice_recognition,
+ .volume_control = volume_control,
+ .dial = dial,
+ .dial_memory = dial_memory,
+ .handle_call_action = handle_call_action,
+ .query_current_calls = query_current_calls,
+ .query_current_operator_name = query_current_operator_name,
+ .retrieve_subscriber_info = retrieve_subscriber_info,
+ .send_dtmf = send_dtmf,
+ .request_last_voice_tag_number = request_last_voice_tag_number,
+ .cleanup = cleanup,
+ .send_at_cmd = send_at_cmd,
+};
+
+static void process_ind_evt(tBTA_HF_CLIENT_IND* ind) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(ind->bd_addr);
+ if (cb == NULL || !is_connected(cb)) return;
+
+ switch (ind->type) {
+ case BTA_HF_CLIENT_IND_CALL:
+ HAL_CBACK(bt_hf_client_callbacks, call_cb, &cb->peer_bda,
+ (bthf_client_call_t)ind->value);
+ break;
+
+ case BTA_HF_CLIENT_IND_CALLSETUP:
+ HAL_CBACK(bt_hf_client_callbacks, callsetup_cb, &cb->peer_bda,
+ (bthf_client_callsetup_t)ind->value);
+ break;
+ case BTA_HF_CLIENT_IND_CALLHELD:
+ HAL_CBACK(bt_hf_client_callbacks, callheld_cb, &cb->peer_bda,
+ (bthf_client_callheld_t)ind->value);
+ break;
+
+ case BTA_HF_CLIENT_IND_SERVICE:
+ HAL_CBACK(bt_hf_client_callbacks, network_state_cb, &cb->peer_bda,
+ (bthf_client_network_state_t)ind->value);
+ break;
+
+ case BTA_HF_CLIENT_IND_SIGNAL:
+ HAL_CBACK(bt_hf_client_callbacks, network_signal_cb, &cb->peer_bda,
+ ind->value);
+ break;
+
+ case BTA_HF_CLIENT_IND_ROAM:
+ HAL_CBACK(bt_hf_client_callbacks, network_roaming_cb, &cb->peer_bda,
+ (bthf_client_service_type_t)ind->value);
+ break;
+
+ case BTA_HF_CLIENT_IND_BATTCH:
+ HAL_CBACK(bt_hf_client_callbacks, battery_level_cb, &cb->peer_bda,
+ ind->value);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_upstreams_evt
+ *
+ * Description Executes HF CLIENT UPSTREAMS events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_HF_CLIENT* p_data = (tBTA_HF_CLIENT*)p_param;
+ bdstr_t bdstr;
+
+ btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(p_data->bd_addr);
+ if (cb == NULL && event == BTA_HF_CLIENT_OPEN_EVT) {
+ BTIF_TRACE_DEBUG("%s: event BTA_HF_CLIENT_OPEN_EVT allocating block",
+ __func__);
+ cb = btif_hf_client_allocate_cb();
+ cb->handle = p_data->open.handle;
+ bdcpy(cb->peer_bda.address, p_data->open.bd_addr);
+ } else if (cb == NULL) {
+ BTIF_TRACE_ERROR("%s: event %d but not allocating block: cb not found",
+ __func__, event);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG("%s: event=%s (%u)", __func__, dump_hf_client_event(event),
+ event);
+
+ switch (event) {
+ case BTA_HF_CLIENT_OPEN_EVT:
+ if (p_data->open.status == BTA_HF_CLIENT_SUCCESS) {
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
+ cb->peer_feat = 0;
+ cb->chld_feat = 0;
+ } else if (cb->state == BTHF_CLIENT_CONNECTION_STATE_CONNECTING) {
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+ } else {
+ BTIF_TRACE_WARNING(
+ "%s: HF CLient open failed, but another device connected. "
+ "status=%d state=%d connected device=%s",
+ __func__, p_data->open.status, cb->state,
+ bdaddr_to_string(&cb->peer_bda, bdstr, sizeof(bdstr)));
+ break;
+ }
+
+ HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, &cb->peer_bda,
+ cb->state, 0, /* peer feat */
+ 0 /* AT+CHLD feat */);
+
+ if (cb->state == BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED)
+ bdsetany(cb->peer_bda.address);
+
+ if (p_data->open.status != BTA_HF_CLIENT_SUCCESS) btif_queue_advance();
+ break;
+
+ case BTA_HF_CLIENT_CONN_EVT:
+ cb->peer_feat = p_data->conn.peer_feat;
+ cb->chld_feat = p_data->conn.chld_feat;
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
+
+ HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, &cb->peer_bda,
+ cb->state, cb->peer_feat, cb->chld_feat);
+
+ /* Inform the application about in-band ringtone */
+ if (cb->peer_feat & BTA_HF_CLIENT_PEER_INBAND) {
+ HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, &cb->peer_bda,
+ BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+ }
+
+ btif_queue_advance();
+ break;
+
+ case BTA_HF_CLIENT_CLOSE_EVT:
+ cb->state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
+ HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, &cb->peer_bda,
+ cb->state, 0, 0);
+ bdsetany(cb->peer_bda.address);
+ cb->peer_feat = 0;
+ cb->chld_feat = 0;
+ btif_queue_advance();
+ break;
+
+ case BTA_HF_CLIENT_IND_EVT:
+ process_ind_evt(&p_data->ind);
+ break;
+
+ case BTA_HF_CLIENT_MIC_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, volume_change_cb, &cb->peer_bda,
+ BTHF_CLIENT_VOLUME_TYPE_MIC, p_data->val.value);
+ break;
+
+ case BTA_HF_CLIENT_SPK_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, volume_change_cb, &cb->peer_bda,
+ BTHF_CLIENT_VOLUME_TYPE_SPK, p_data->val.value);
+ break;
+
+ case BTA_HF_CLIENT_VOICE_REC_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, vr_cmd_cb, &cb->peer_bda,
+ (bthf_client_vr_state_t)p_data->val.value);
+ break;
+
+ case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, current_operator_cb, &cb->peer_bda,
+ p_data->operator_name.name);
+ break;
+
+ case BTA_HF_CLIENT_CLIP_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, clip_cb, &cb->peer_bda,
+ p_data->number.number);
+ break;
+
+ case BTA_HF_CLIENT_BINP_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, last_voice_tag_number_callback,
+ &cb->peer_bda, p_data->number.number);
+ break;
+
+ case BTA_HF_CLIENT_CCWA_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, call_waiting_cb, &cb->peer_bda,
+ p_data->number.number);
+ break;
+
+ case BTA_HF_CLIENT_AT_RESULT_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, cmd_complete_cb, &cb->peer_bda,
+ (bthf_client_cmd_complete_t)p_data->result.type,
+ p_data->result.cme);
+ break;
+
+ case BTA_HF_CLIENT_CLCC_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, current_calls_cb, &cb->peer_bda,
+ p_data->clcc.idx,
+ p_data->clcc.inc ? BTHF_CLIENT_CALL_DIRECTION_INCOMING
+ : BTHF_CLIENT_CALL_DIRECTION_OUTGOING,
+ (bthf_client_call_state_t)p_data->clcc.status,
+ p_data->clcc.mpty ? BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
+ : BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE,
+ p_data->clcc.number_present ? p_data->clcc.number : NULL);
+ break;
+
+ case BTA_HF_CLIENT_CNUM_EVT:
+ if (p_data->cnum.service == 4) {
+ HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, &cb->peer_bda,
+ p_data->cnum.number, BTHF_CLIENT_SERVICE_VOICE);
+ } else if (p_data->cnum.service == 5) {
+ HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, &cb->peer_bda,
+ p_data->cnum.number, BTHF_CLIENT_SERVICE_FAX);
+ } else {
+ HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb, &cb->peer_bda,
+ p_data->cnum.number, BTHF_CLIENT_SERVICE_UNKNOWN);
+ }
+ break;
+
+ case BTA_HF_CLIENT_BTRH_EVT:
+ if (p_data->val.value <= BTRH_CLIENT_RESP_AND_HOLD_REJECT) {
+ HAL_CBACK(bt_hf_client_callbacks, resp_and_hold_cb, &cb->peer_bda,
+ (bthf_client_resp_and_hold_t)p_data->val.value);
+ }
+ break;
+
+ case BTA_HF_CLIENT_BSIR_EVT:
+ if (p_data->val.value != 0) {
+ HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, &cb->peer_bda,
+ BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
+ } else {
+ HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb, &cb->peer_bda,
+ BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED);
+ }
+ break;
+
+ case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda,
+ BTHF_CLIENT_AUDIO_STATE_CONNECTED);
+ break;
+
+ case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda,
+ BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC);
+ break;
+
+ case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, audio_state_cb, &cb->peer_bda,
+ BTHF_CLIENT_AUDIO_STATE_DISCONNECTED);
+ break;
+ case BTA_HF_CLIENT_RING_INDICATION:
+ HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb, &cb->peer_bda);
+ break;
+ default:
+ BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bta_hf_client_evt
+ *
+ * Description Switches context from BTA to BTIF for all HF Client events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void bta_hf_client_evt(tBTA_HF_CLIENT_EVT event,
+ tBTA_HF_CLIENT* p_data) {
+ bt_status_t status;
+
+ /* switch context to btif task context (copy full union size for convenience)
+ */
+ status = btif_transfer_context(btif_hf_client_upstreams_evt, (uint16_t)event,
+ (char*)p_data, sizeof(*p_data), NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_client_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hf_client_execute_service(bool b_enable) {
+ BTIF_TRACE_EVENT("%s: enable: %d", __func__, b_enable);
+
+ if (b_enable) {
+ /* Enable and register with BTA-HFClient */
+ BTIF_TRACE_EVENT("%s: support codec negotiation %d ", __func__,
+ BTIF_HF_CLIENT_FEATURES);
+ BTA_HfClientEnable(bta_hf_client_evt, BTIF_HF_CLIENT_SECURITY,
+ BTIF_HF_CLIENT_FEATURES, BTIF_HF_CLIENT_SERVICE_NAME);
+ } else {
+ BTA_HfClientDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hf_get_interface
+ *
+ * Description Get the hf callback interface
+ *
+ * Returns bthf_interface_t
+ *
+ ******************************************************************************/
+const bthf_client_interface_t* btif_hf_client_get_interface(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bthfClientInterface;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_hh.cc b/mtkbt/code/bt/btif/src/btif_hh.cc
new file mode 100755
index 0000000..b60c8c8
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_hh.cc
@@ -0,0 +1,1697 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_hh.c
+ *
+ * Description: HID Host Profile Bluetooth Interface
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_hh"
+
+#include "btif_hh.h"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "l2c_api.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define BTIF_HH_APP_ID_MI 0x01
+#define BTIF_HH_APP_ID_KB 0x02
+
+#define COD_HID_KEYBOARD 0x0540
+#define COD_HID_POINTING 0x0580
+#define COD_HID_COMBO 0x05C0
+
+#define KEYSTATE_FILEPATH \
+ "/data/misc/bluedroid/bt_hh_ks" // keep this in sync with HID host jni
+
+#define HID_REPORT_CAPSLOCK 0x39
+#define HID_REPORT_NUMLOCK 0x53
+#define HID_REPORT_SCROLLLOCK 0x47
+
+// For Apple Magic Mouse
+#define MAGICMOUSE_VENDOR_ID 0x05ac
+#define MAGICMOUSE_PRODUCT_ID 0x030d
+
+#define LOGITECH_KB_MX5500_VENDOR_ID 0x046D
+#define LOGITECH_KB_MX5500_PRODUCT_ID 0xB30B
+
+extern fixed_queue_t* btu_general_alarm_queue;
+extern const int BT_UID;
+extern const int BT_GID;
+static int btif_hh_keylockstates = 0; // The current key state of each key
+
+#define BTIF_HH_ID_1 0
+#define BTIF_HH_DEV_DISCONNECTED 3
+
+#define BTIF_TIMEOUT_VUP_MS (3 * 1000)
+
+#ifndef BTUI_HH_SECURITY
+#define BTUI_HH_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#ifndef BTUI_HH_MOUSE_SECURITY
+#define BTUI_HH_MOUSE_SECURITY (BTA_SEC_NONE)
+#endif
+
+/* HH request events */
+typedef enum {
+ BTIF_HH_CONNECT_REQ_EVT = 0,
+ BTIF_HH_DISCONNECT_REQ_EVT,
+ BTIF_HH_VUP_REQ_EVT
+} btif_hh_req_evt_t;
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+#define BTIF_HH_SERVICES (BTA_HID_SERVICE_MASK)
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+
+typedef struct hid_kb_list {
+ uint16_t product_id;
+ uint16_t version_id;
+ const char* kb_name;
+} tHID_KB_LIST;
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+btif_hh_cb_t btif_hh_cb;
+
+static bthh_callbacks_t* bt_hh_callbacks = NULL;
+
+/* List of HID keyboards for which the NUMLOCK state needs to be
+ * turned ON by default. Add devices to this list to apply the
+ * NUMLOCK state toggle on fpr first connect.*/
+static tHID_KB_LIST hid_kb_numlock_on_list[] = {{LOGITECH_KB_MX5500_PRODUCT_ID,
+ LOGITECH_KB_MX5500_VENDOR_ID,
+ "Logitech MX5500 Keyboard"}};
+
+#define CHECK_BTHH_INIT() \
+ do { \
+ if (bt_hh_callbacks == NULL) { \
+ BTIF_TRACE_WARNING("BTHH: %s: BTHH not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+extern void bta_hh_co_destroy(int fd);
+extern void bta_hh_co_write(int fd, uint8_t* rpt, uint16_t len);
+extern bt_status_t btif_dm_remove_bond(const bt_bdaddr_t* bd_addr);
+extern void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev,
+ const char* dev_name, uint16_t vendor_id,
+ uint16_t product_id, uint16_t version,
+ uint8_t ctry_code, int dscp_len,
+ uint8_t* p_dscp);
+extern bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod);
+extern void btif_dm_cb_remove_bond(bt_bdaddr_t* bd_addr);
+extern bool check_cod_hid(const bt_bdaddr_t* remote_bdaddr);
+extern int scru_ascii_2_hex(char* p_ascii, int len, uint8_t* p_hex);
+extern void btif_dm_hh_open_failed(bt_bdaddr_t* bdaddr);
+extern void btif_hd_service_registration();
+
+/*****************************************************************************
+ * Local Function prototypes
+ ****************************************************************************/
+static void set_keylockstate(int keymask, bool isSet);
+static void toggle_os_keylockstates(int fd, int changedkeystates);
+static void sync_lockstate_on_connect(btif_hh_device_t* p_dev);
+// static void hh_update_keyboard_lockstates(btif_hh_device_t *p_dev);
+void btif_hh_timer_timeout(void* data);
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data);
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+static int get_keylockstates() { return btif_hh_keylockstates; }
+
+static void set_keylockstate(int keymask, bool isSet) {
+ if (isSet) btif_hh_keylockstates |= keymask;
+}
+
+/*******************************************************************************
+ *
+ * Function toggle_os_keylockstates
+ *
+ * Description Function to toggle the keyboard lock states managed by the
+ linux.
+ * This function is used in by two call paths
+ * (1) if the lock state change occurred from an onscreen
+ keyboard,
+ * this function is called to update the lock state maintained
+ for the HID keyboard(s)
+ * (2) if a HID keyboard is disconnected and reconnected,
+ * this function is called to update the lock state maintained
+ for the HID keyboard(s)
+ * Returns void
+ ******************************************************************************/
+
+static void toggle_os_keylockstates(int fd, int changedlockstates) {
+ BTIF_TRACE_EVENT("%s: fd = %d, changedlockstates = 0x%x", __func__, fd,
+ changedlockstates);
+ uint8_t hidreport[9];
+ int reportIndex;
+ memset(hidreport, 0, 9);
+ hidreport[0] = 1;
+ reportIndex = 4;
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_CAPSLOCK) {
+ BTIF_TRACE_DEBUG("%s Setting CAPSLOCK", __func__);
+ hidreport[reportIndex++] = (uint8_t)HID_REPORT_CAPSLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_NUMLOCK) {
+ BTIF_TRACE_DEBUG("%s Setting NUMLOCK", __func__);
+ hidreport[reportIndex++] = (uint8_t)HID_REPORT_NUMLOCK;
+ }
+
+ if (changedlockstates & BTIF_HH_KEYSTATE_MASK_SCROLLLOCK) {
+ BTIF_TRACE_DEBUG("%s Setting SCROLLLOCK", __func__);
+ hidreport[reportIndex++] = (uint8_t)HID_REPORT_SCROLLLOCK;
+ }
+
+ BTIF_TRACE_DEBUG(
+ "Writing hidreport #1 to os: "
+ "%s: %x %x %x",
+ __func__, hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[3], hidreport[4],
+ hidreport[5]);
+ BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[6], hidreport[7],
+ hidreport[8]);
+ bta_hh_co_write(fd, hidreport, sizeof(hidreport));
+ usleep(200000);
+ memset(hidreport, 0, 9);
+ hidreport[0] = 1;
+ BTIF_TRACE_DEBUG(
+ "Writing hidreport #2 to os: "
+ "%s: %x %x %x",
+ __func__, hidreport[0], hidreport[1], hidreport[2]);
+ BTIF_TRACE_DEBUG("%s: %x %x %x", __func__, hidreport[3], hidreport[4],
+ hidreport[5]);
+ BTIF_TRACE_DEBUG("%s: %x %x %x ", __func__, hidreport[6], hidreport[7],
+ hidreport[8]);
+ bta_hh_co_write(fd, hidreport, sizeof(hidreport));
+}
+
+/*******************************************************************************
+ *
+ * Function create_pbuf
+ *
+ * Description Helper function to create p_buf for send_data or set_report
+ *
+ ******************************************************************************/
+static BT_HDR* create_pbuf(uint16_t len, uint8_t* data) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(len + BTA_HH_MIN_OFFSET + sizeof(BT_HDR));
+ uint8_t* pbuf_data;
+
+ p_buf->len = len;
+ p_buf->offset = BTA_HH_MIN_OFFSET;
+
+ pbuf_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ memcpy(pbuf_data, data, len);
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function update_keyboard_lockstates
+ *
+ * Description Sends a report to the keyboard to set the lock states of
+ * keys.
+ *
+ ******************************************************************************/
+static void update_keyboard_lockstates(btif_hh_device_t* p_dev) {
+ uint8_t len = 2; /* reportid + 1 byte report*/
+ BD_ADDR* bda;
+ BT_HDR* p_buf;
+ uint8_t data[] = {0x01, /* report id */
+ static_cast<uint8_t>(btif_hh_keylockstates)}; /* keystate */
+
+ /* Set report for other keyboards */
+ BTIF_TRACE_EVENT("%s: setting report on dev_handle %d to 0x%x", __func__,
+ p_dev->dev_handle, btif_hh_keylockstates);
+
+ /* Get SetReport buffer */
+ p_buf = create_pbuf(len, data);
+ if (p_buf != NULL) {
+ p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+ bda = (BD_ADDR*)(&p_dev->bd_addr);
+ BTA_HhSendData(p_dev->dev_handle, *bda, p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sync_lockstate_on_connect
+ *
+ * Description Function to update the keyboard lock states managed by the
+ * OS when a HID keyboard is connected or disconnected and
+ * reconnected
+ *
+ * Returns void
+ ******************************************************************************/
+static void sync_lockstate_on_connect(btif_hh_device_t* p_dev) {
+ int keylockstates;
+
+ BTIF_TRACE_EVENT(
+ "%s: Syncing keyboard lock states after "
+ "reconnect...",
+ __func__);
+ /*If the device is connected, update keyboard state */
+ update_keyboard_lockstates(p_dev);
+
+ /*Check if the lockstate of caps,scroll,num is set.
+ If so, send a report to the kernel
+ so the lockstate is in sync */
+ keylockstates = get_keylockstates();
+ if (keylockstates) {
+ BTIF_TRACE_DEBUG(
+ "%s: Sending hid report to kernel "
+ "indicating lock key state 0x%x",
+ __func__, keylockstates);
+ usleep(200000);
+ toggle_os_keylockstates(p_dev->fd, keylockstates);
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: NOT sending hid report to kernel "
+ "indicating lock key state 0x%x",
+ __func__, keylockstates);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_find_connected_dev_by_handle
+ *
+ * Description Return the connected device pointer of the specified device
+ * handle
+ *
+ * Returns Device entry pointer in the device table
+ ******************************************************************************/
+btif_hh_device_t* btif_hh_find_connected_dev_by_handle(uint8_t handle) {
+ uint32_t i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ btif_hh_cb.devices[i].dev_handle == handle) {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_find_dev_by_bda
+ *
+ * Description Return the device pointer of the specified bt_bdaddr_t.
+ *
+ * Returns Device entry pointer in the device table
+ ******************************************************************************/
+static btif_hh_device_t* btif_hh_find_dev_by_bda(bt_bdaddr_t* bd_addr) {
+ uint32_t i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status != BTHH_CONN_STATE_UNKNOWN &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_find_connected_dev_by_bda
+ *
+ * Description Return the connected device pointer of the specified
+ * bt_bdaddr_t.
+ *
+ * Returns Device entry pointer in the device table
+ ******************************************************************************/
+static btif_hh_device_t* btif_hh_find_connected_dev_by_bda(
+ bt_bdaddr_t* bd_addr) {
+ uint32_t i;
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_CONNECTED &&
+ memcmp(&(btif_hh_cb.devices[i].bd_addr), bd_addr, BD_ADDR_LEN) == 0) {
+ return &btif_hh_cb.devices[i];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_stop_vup_timer
+ *
+ * Description stop vitual unplug timer
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hh_stop_vup_timer(bt_bdaddr_t* bd_addr) {
+ btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG("stop VUP timer");
+ alarm_free(p_dev->vup_timer);
+ p_dev->vup_timer = NULL;
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hh_start_vup_timer
+ *
+ * Description start virtual unplug timer
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hh_start_vup_timer(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ CHECK(p_dev != NULL);
+
+ alarm_free(p_dev->vup_timer);
+ p_dev->vup_timer = alarm_new("btif_hh.vup_timer");
+ alarm_set_on_queue(p_dev->vup_timer, BTIF_TIMEOUT_VUP_MS,
+ btif_hh_timer_timeout, p_dev, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_add_added_dev
+ *
+ * Description Add a new device to the added device list.
+ *
+ * Returns true if add successfully, otherwise false.
+ ******************************************************************************/
+bool btif_hh_add_added_dev(bt_bdaddr_t bda, tBTA_HH_ATTR_MASK attr_mask) {
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN) ==
+ 0) {
+ BTIF_TRACE_WARNING(" Device %02X:%02X:%02X:%02X:%02X:%02X already added",
+ bda.address[0], bda.address[1], bda.address[2],
+ bda.address[3], bda.address[4], bda.address[5]);
+ return false;
+ }
+ }
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (btif_hh_cb.added_devices[i].bd_addr.address[0] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[1] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[2] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[3] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[4] == 0 &&
+ btif_hh_cb.added_devices[i].bd_addr.address[5] == 0) {
+ BTIF_TRACE_WARNING(" Added device %02X:%02X:%02X:%02X:%02X:%02X",
+ bda.address[0], bda.address[1], bda.address[2],
+ bda.address[3], bda.address[4], bda.address[5]);
+ memcpy(&(btif_hh_cb.added_devices[i].bd_addr), &bda, BD_ADDR_LEN);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ btif_hh_cb.added_devices[i].attr_mask = attr_mask;
+ return true;
+ }
+ }
+
+ BTIF_TRACE_WARNING("%s: Error, out of space to add device", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function btif_hh_remove_device
+ **
+ ** Description Remove an added device from the stack.
+ **
+ ** Returns void
+ ******************************************************************************/
+void btif_hh_remove_device(bt_bdaddr_t bd_addr) {
+ int i;
+ btif_hh_device_t* p_dev;
+ btif_hh_added_device_t* p_added_dev;
+
+ LOG_INFO(LOG_TAG, "%s: bda = %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2],
+ bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ p_added_dev = &btif_hh_cb.added_devices[i];
+ if (memcmp(&(p_added_dev->bd_addr), &bd_addr, 6) == 0) {
+ BTA_HhRemoveDev(p_added_dev->dev_handle);
+ btif_storage_remove_hid_info(&(p_added_dev->bd_addr));
+ memset(&(p_added_dev->bd_addr), 0, 6);
+ p_added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ break;
+ }
+ }
+
+ p_dev = btif_hh_find_dev_by_bda(&bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING(
+ " Oops, can't find device [%02x:%02x:%02x:%02x:%02x:%02x]",
+ bd_addr.address[0], bd_addr.address[1], bd_addr.address[2],
+ bd_addr.address[3], bd_addr.address[4], bd_addr.address[5]);
+ return;
+ }
+
+ /* need to notify up-layer device is disconnected to avoid state out of sync
+ * with up-layer */
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+ BTHH_CONN_STATE_DISCONNECTED);
+
+ p_dev->dev_status = BTHH_CONN_STATE_UNKNOWN;
+ p_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ p_dev->ready_for_data = false;
+
+ if (btif_hh_cb.device_num > 0) {
+ btif_hh_cb.device_num--;
+ } else {
+ BTIF_TRACE_WARNING("%s: device_num = 0", __func__);
+ }
+
+ p_dev->hh_keep_polling = 0;
+ p_dev->hh_poll_thread_id = -1;
+ BTIF_TRACE_DEBUG("%s: uhid fd = %d", __func__, p_dev->fd);
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+}
+
+bool btif_hh_copy_hid_info(tBTA_HH_DEV_DSCP_INFO* dest,
+ tBTA_HH_DEV_DSCP_INFO* src) {
+ dest->descriptor.dl_len = 0;
+ if (src->descriptor.dl_len > 0) {
+ dest->descriptor.dsc_list = (uint8_t*)osi_malloc(src->descriptor.dl_len);
+ }
+ memcpy(dest->descriptor.dsc_list, src->descriptor.dsc_list,
+ src->descriptor.dl_len);
+ dest->descriptor.dl_len = src->descriptor.dl_len;
+ dest->vendor_id = src->vendor_id;
+ dest->product_id = src->product_id;
+ dest->version = src->version;
+ dest->ctry_code = src->ctry_code;
+ dest->ssr_max_latency = src->ssr_max_latency;
+ dest->ssr_min_tout = src->ssr_min_tout;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_virtual_unplug
+ *
+ * Description Virtual unplug initiated from the BTIF thread context
+ * Special handling for HID mouse-
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+bt_status_t btif_hh_virtual_unplug(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ btif_hh_device_t* p_dev;
+ char bd_str[18];
+ snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
+ bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if ((p_dev != NULL) && (p_dev->dev_status == BTHH_CONN_STATE_CONNECTED) &&
+ (p_dev->attr_mask & HID_VIRTUAL_CABLE)) {
+ BTIF_TRACE_DEBUG("%s Sending BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG", __func__);
+ /* start the timer */
+ btif_hh_start_vup_timer(bd_addr);
+ p_dev->local_vup = true;
+ BTA_HhSendCtrl(p_dev->dev_handle, BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG);
+ return BT_STATUS_SUCCESS;
+ } else {
+ BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_connect
+ *
+ * Description connection initiated from the BTIF thread context
+ *
+ * Returns int status
+ *
+ ******************************************************************************/
+
+bt_status_t btif_hh_connect(bt_bdaddr_t* bd_addr) {
+ btif_hh_device_t* dev;
+ btif_hh_added_device_t* added_dev = NULL;
+ char bda_str[20];
+ int i;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+ CHECK_BTHH_INIT();
+ BTIF_TRACE_EVENT("BTHH: %s", __func__);
+ dev = btif_hh_find_dev_by_bda(bd_addr);
+ snprintf(bda_str, sizeof(bda_str), "%02X:%02X:%02X:%02X:%02X:%02X", (*bda)[0],
+ (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ if (dev == NULL && btif_hh_cb.device_num >= BTIF_HH_MAX_HID) {
+ // No space for more HID device now.
+ BTIF_TRACE_WARNING(
+ "%s: Error, exceeded the maximum supported HID device number %d",
+ __func__, BTIF_HH_MAX_HID);
+ return BT_STATUS_FAIL;
+ }
+
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(&(btif_hh_cb.added_devices[i].bd_addr), bd_addr, BD_ADDR_LEN) ==
+ 0) {
+ added_dev = &btif_hh_cb.added_devices[i];
+ BTIF_TRACE_WARNING("%s: Device %s already added, attr_mask = 0x%x",
+ __func__, bda_str, added_dev->attr_mask);
+ }
+ }
+
+ if (added_dev != NULL) {
+ if (added_dev->dev_handle == BTA_HH_INVALID_HANDLE) {
+ // No space for more HID device now.
+ BTIF_TRACE_ERROR("%s: Error, device %s added but addition failed",
+ __func__, bda_str);
+ memset(&(added_dev->bd_addr), 0, 6);
+ added_dev->dev_handle = BTA_HH_INVALID_HANDLE;
+ return BT_STATUS_FAIL;
+ }
+ }
+
+ /* Not checking the NORMALLY_Connectible flags from sdp record, and anyways
+ sending this
+ request from host, for subsequent user initiated connection. If the remote is
+ not in
+ pagescan mode, we will do 2 retries to connect before giving up */
+ tBTA_SEC sec_mask = BTUI_HH_SECURITY;
+ btif_hh_cb.status = BTIF_HH_DEV_CONNECTING;
+ BTA_HhOpen(*bda, BTA_HH_PROTO_RPT_MODE, sec_mask);
+
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+ BTHH_CONN_STATE_CONNECTING);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_disconnect
+ *
+ * Description disconnection initiated from the BTIF thread context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_hh_disconnect(bt_bdaddr_t* bd_addr) {
+ btif_hh_device_t* p_dev;
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ BTA_HhClose(p_dev->dev_handle);
+ } else
+ BTIF_TRACE_DEBUG("%s-- Error: device not connected:", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_btif_hh_setreport
+ *
+ * Description setreport initiated from the BTIF thread context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hh_setreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type,
+ uint16_t size, uint8_t* report) {
+ BT_HDR* p_buf = create_pbuf(size, report);
+ if (p_buf == NULL) {
+ APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d",
+ __func__, size);
+ return;
+ }
+ BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_service_registration
+ *
+ * Description Registers or derigisters the hid host service
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btif_hh_service_registration(bool enable) {
+ BTIF_TRACE_API("%s", __func__);
+
+ BTIF_TRACE_API("enable = %d", enable);
+ if (bt_hh_callbacks == NULL) {
+ // The HID Host service was never initialized (it is either disabled or not
+ // available in this build). We should proceed directly to changing the HID
+ // Device service state (if needed).
+ if (!enable) {
+ btif_hd_service_registration();
+ }
+ } else if (enable) {
+ BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
+ } else {
+ btif_hh_cb.service_dereg_active = TRUE;
+ BTA_HhDisable();
+ }
+}
+
+/*****************************************************************************
+ * Section name (Group of functions)
+ ****************************************************************************/
+
+/*****************************************************************************
+ *
+ * btif hh api functions (no context switch)
+ *
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_hh_upstreams_evt
+ *
+ * Description Executes HH UPSTREAMS events in btif context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hh_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_HH* p_data = (tBTA_HH*)p_param;
+ btif_hh_device_t* p_dev = NULL;
+ int i;
+ int len, tmplen;
+
+ BTIF_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(event),
+ btif_hh_cb.service_dereg_active);
+
+ switch (event) {
+ case BTA_HH_ENABLE_EVT:
+ BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d", __func__,
+ p_data->status);
+ if (p_data->status == BTA_HH_OK) {
+ btif_hh_cb.status = BTIF_HH_ENABLED;
+ BTIF_TRACE_DEBUG("%s--Loading added devices", __func__);
+ /* Add hid descriptors for already bonded hid devices*/
+ btif_storage_load_bonded_hid_info();
+ } else {
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ BTIF_TRACE_WARNING(
+ "BTA_HH_ENABLE_EVT: Error, HH enabling failed, status = %d",
+ p_data->status);
+ }
+ break;
+
+ case BTA_HH_DISABLE_EVT:
+ btif_hh_cb.status = BTIF_HH_DISABLED;
+ if (btif_hh_cb.service_dereg_active) {
+ BTIF_TRACE_DEBUG("BTA_HH_DISABLE_EVT: enabling HID Device service");
+ btif_hd_service_registration();
+ btif_hh_cb.service_dereg_active = FALSE;
+ }
+ if (p_data->status == BTA_HH_OK) {
+ int i;
+ // Clear the control block
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ alarm_free(btif_hh_cb.devices[i].vup_timer);
+ }
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ } else
+ BTIF_TRACE_WARNING(
+ "BTA_HH_DISABLE_EVT: Error, HH disabling failed, status = %d",
+ p_data->status);
+ break;
+
+ case BTA_HH_OPEN_EVT:
+ BTIF_TRACE_WARNING("%s: BTA_HH_OPN_EVT: handle=%d, status =%d", __func__,
+ p_data->conn.handle, p_data->conn.status);
+ if (p_data->conn.status == BTA_HH_OK) {
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING(
+ "BTA_HH_OPEN_EVT: Error, cannot find device with handle %d",
+ p_data->conn.handle);
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ // The connect request must come from device side and exceeded the
+ // connected
+ // HID device number.
+ BTA_HhClose(p_data->conn.handle);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda,
+ BTHH_CONN_STATE_DISCONNECTED);
+ } else if (p_dev->fd < 0) {
+ BTIF_TRACE_WARNING(
+ "BTA_HH_OPEN_EVT: Error, failed to find the uhid driver...");
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ // remove the connection and then try again to reconnect from the
+ // mouse side to recover
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ BTA_HhClose(p_data->conn.handle);
+ } else {
+ BTIF_TRACE_WARNING(
+ "BTA_HH_OPEN_EVT: Found device...Getting dscp info for handle "
+ "... %d",
+ p_data->conn.handle);
+ memcpy(&(p_dev->bd_addr), p_data->conn.bda, BD_ADDR_LEN);
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_CONNECTED;
+ // Send set_idle if the peer_device is a keyboard
+ if (check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_KEYBOARD) ||
+ check_cod((bt_bdaddr_t*)p_data->conn.bda, COD_HID_COMBO))
+ BTA_HhSetIdle(p_data->conn.handle, 0);
+ btif_hh_cb.p_curr_dev =
+ btif_hh_find_connected_dev_by_handle(p_data->conn.handle);
+ BTA_HhGetDscpInfo(p_data->conn.handle);
+ p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+ p_dev->dev_status);
+ }
+ } else {
+ bt_bdaddr_t* bdaddr = (bt_bdaddr_t*)p_data->conn.bda;
+ btif_dm_hh_open_failed(bdaddr);
+ p_dev = btif_hh_find_dev_by_bda(bdaddr);
+ if (p_dev != NULL) {
+ btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+ }
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb,
+ (bt_bdaddr_t*)&p_data->conn.bda,
+ BTHH_CONN_STATE_DISCONNECTED);
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ }
+ break;
+
+ case BTA_HH_CLOSE_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_CLOSE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG("%s: uhid fd=%d local_vup=%d", __func__, p_dev->fd,
+ p_dev->local_vup);
+ btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+ /* If this is a locally initiated VUP, remove the bond as ACL got
+ * disconnected while VUP being processed.
+ */
+ if (p_dev->local_vup) {
+ p_dev->local_vup = false;
+ BTA_DmRemoveDevice((uint8_t*)p_dev->bd_addr.address);
+ }
+
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+ p_dev->dev_status);
+ } else {
+ BTIF_TRACE_WARNING("Error: cannot find device with handle %d",
+ p_data->dev_status.handle);
+ }
+ break;
+
+ case BTA_HH_GET_RPT_EVT: {
+ BT_HDR* hdr = p_data->hs_data.rsp_data.p_rpt_data;
+ uint8_t* data = NULL;
+ uint16_t len = 0;
+
+ BTIF_TRACE_DEBUG("BTA_HH_GET_RPT_EVT: status = %d, handle = %d",
+ p_data->hs_data.status, p_data->hs_data.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->hs_data.handle);
+ if (p_dev) {
+ /* p_rpt_data is NULL in HANDSHAKE response case */
+ if (hdr) {
+ data = (uint8_t*)(hdr + 1) + hdr->offset;
+ len = hdr->len;
+ HAL_CBACK(bt_hh_callbacks, get_report_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status, data, len);
+ } else {
+ HAL_CBACK(bt_hh_callbacks, handshake_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status);
+ }
+ } else {
+ BTIF_TRACE_WARNING("Error: cannot find device with handle %d",
+ p_data->hs_data.handle);
+ }
+ break;
+ }
+
+ case BTA_HH_SET_RPT_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_SET_RPT_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev != NULL) {
+ HAL_CBACK(bt_hh_callbacks, handshake_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status);
+ }
+ break;
+
+ case BTA_HH_GET_PROTO_EVT:
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ BTIF_TRACE_WARNING(
+ "BTA_HH_GET_PROTO_EVT: status = %d, handle = %d, proto = [%d], %s",
+ p_data->hs_data.status, p_data->hs_data.handle,
+ p_data->hs_data.rsp_data.proto_mode,
+ (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_RPT_MODE)
+ ? "Report Mode"
+ : (p_data->hs_data.rsp_data.proto_mode == BTA_HH_PROTO_BOOT_MODE)
+ ? "Boot Mode"
+ : "Unsupported");
+ if (p_data->hs_data.rsp_data.proto_mode != BTA_HH_PROTO_UNKNOWN) {
+ HAL_CBACK(bt_hh_callbacks, protocol_mode_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status,
+ (bthh_protocol_mode_t)p_data->hs_data.rsp_data.proto_mode);
+ } else {
+ HAL_CBACK(bt_hh_callbacks, handshake_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status);
+ }
+ break;
+
+ case BTA_HH_SET_PROTO_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_SET_PROTO_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ if (p_dev) {
+ HAL_CBACK(bt_hh_callbacks, handshake_cb,
+ (bt_bdaddr_t*)&(p_dev->bd_addr),
+ (bthh_status_t)p_data->hs_data.status);
+ }
+ break;
+
+ case BTA_HH_GET_IDLE_EVT:
+ BTIF_TRACE_DEBUG(
+ "BTA_HH_GET_IDLE_EVT: handle = %d, status = %d, rate = %d",
+ p_data->hs_data.handle, p_data->hs_data.status,
+ p_data->hs_data.rsp_data.idle_rate);
+ break;
+
+ case BTA_HH_SET_IDLE_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_SET_IDLE_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ break;
+
+ case BTA_HH_GET_DSCP_EVT:
+ len = p_data->dscp_info.descriptor.dl_len;
+ BTIF_TRACE_DEBUG("BTA_HH_GET_DSCP_EVT: len = %d", len);
+ p_dev = btif_hh_cb.p_curr_dev;
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR(
+ "BTA_HH_GET_DSCP_EVT: No HID device is currently connected");
+ return;
+ }
+ if (p_dev->fd < 0) {
+ LOG_ERROR(
+ LOG_TAG,
+ "BTA_HH_GET_DSCP_EVT: Error, failed to find the uhid driver...");
+ return;
+ }
+ {
+ const char* cached_name = NULL;
+ bt_bdname_t bdname;
+ bt_property_t prop_name;
+ BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
+ sizeof(bt_bdname_t), &bdname);
+ if (btif_storage_get_remote_device_property(
+ &p_dev->bd_addr, &prop_name) == BT_STATUS_SUCCESS) {
+ cached_name = (char*)bdname.name;
+ } else {
+ cached_name = "Bluetooth HID";
+ }
+
+ BTIF_TRACE_WARNING("%s: name = %s", __func__, cached_name);
+ bta_hh_co_send_hid_info(p_dev, cached_name, p_data->dscp_info.vendor_id,
+ p_data->dscp_info.product_id,
+ p_data->dscp_info.version,
+ p_data->dscp_info.ctry_code, len,
+ p_data->dscp_info.descriptor.dsc_list);
+ if (btif_hh_add_added_dev(p_dev->bd_addr, p_dev->attr_mask)) {
+ BD_ADDR bda;
+ bdcpy(bda, p_dev->bd_addr.address);
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ bt_status_t ret;
+ bdcpy(bda, p_dev->bd_addr.address);
+ btif_hh_copy_hid_info(&dscp_info, &p_data->dscp_info);
+ BTIF_TRACE_DEBUG(
+ "BTA_HH_GET_DSCP_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+ p_dev->bd_addr.address[2], p_dev->bd_addr.address[3],
+ p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ BTA_HhAddDev(bda, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id,
+ dscp_info);
+ // write hid info to nvram
+ ret = btif_storage_add_hid_device_info(
+ &(p_dev->bd_addr), p_dev->attr_mask, p_dev->sub_class,
+ p_dev->app_id, p_data->dscp_info.vendor_id,
+ p_data->dscp_info.product_id, p_data->dscp_info.version,
+ p_data->dscp_info.ctry_code, p_data->dscp_info.ssr_max_latency,
+ p_data->dscp_info.ssr_min_tout, len,
+ p_data->dscp_info.descriptor.dsc_list);
+
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing hid info failed", ret);
+ BTIF_TRACE_WARNING("BTA_HH_GET_DSCP_EVT: Called add device");
+
+ // Free buffer created for dscp_info;
+ if (dscp_info.descriptor.dl_len > 0 &&
+ dscp_info.descriptor.dsc_list != NULL) {
+ osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list);
+ dscp_info.descriptor.dl_len = 0;
+ }
+ } else {
+ // Device already added.
+ BTIF_TRACE_WARNING("%s: Device already added ", __func__);
+ }
+ /*Sync HID Keyboard lockstates */
+ tmplen = sizeof(hid_kb_numlock_on_list) / sizeof(tHID_KB_LIST);
+ for (i = 0; i < tmplen; i++) {
+ if (p_data->dscp_info.vendor_id ==
+ hid_kb_numlock_on_list[i].version_id &&
+ p_data->dscp_info.product_id ==
+ hid_kb_numlock_on_list[i].product_id) {
+ BTIF_TRACE_DEBUG(
+ "%s() idx[%d] Enabling "
+ "NUMLOCK for device :: %s",
+ __func__, i, hid_kb_numlock_on_list[i].kb_name);
+ /* Enable NUMLOCK by default so that numeric
+ keys work from first keyboard connect */
+ set_keylockstate(BTIF_HH_KEYSTATE_MASK_NUMLOCK, true);
+ sync_lockstate_on_connect(p_dev);
+ /* End Sync HID Keyboard lockstates */
+ break;
+ }
+ }
+ }
+ break;
+
+ case BTA_HH_ADD_DEV_EVT:
+ BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",
+ p_data->dev_info.status, p_data->dev_info.handle);
+ int i;
+ for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) {
+ if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address,
+ p_data->dev_info.bda, 6) == 0) {
+ if (p_data->dev_info.status == BTA_HH_OK) {
+ btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;
+ } else {
+ memset(btif_hh_cb.added_devices[i].bd_addr.address, 0, 6);
+ btif_hh_cb.added_devices[i].dev_handle = BTA_HH_INVALID_HANDLE;
+ }
+ break;
+ }
+ }
+ break;
+ case BTA_HH_RMV_DEV_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT: status = %d, handle = %d",
+ p_data->dev_info.status, p_data->dev_info.handle);
+ BTIF_TRACE_DEBUG("BTA_HH_RMV_DEV_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_data->dev_info.bda[0], p_data->dev_info.bda[1],
+ p_data->dev_info.bda[2], p_data->dev_info.bda[3],
+ p_data->dev_info.bda[4], p_data->dev_info.bda[5]);
+ break;
+
+ case BTA_HH_VC_UNPLUG_EVT:
+ BTIF_TRACE_DEBUG("BTA_HH_VC_UNPLUG_EVT: status = %d, handle = %d",
+ p_data->dev_status.status, p_data->dev_status.handle);
+ p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle);
+ btif_hh_cb.status = (BTIF_HH_STATUS)BTIF_HH_DEV_DISCONNECTED;
+ if (p_dev != NULL) {
+ BTIF_TRACE_DEBUG(
+ "BTA_HH_VC_UNPLUG_EVT:bda = %02x:%02x:%02x:%02x:%02x:%02x",
+ p_dev->bd_addr.address[0], p_dev->bd_addr.address[1],
+ p_dev->bd_addr.address[2], p_dev->bd_addr.address[3],
+ p_dev->bd_addr.address[4], p_dev->bd_addr.address[5]);
+ /* Stop the VUP timer */
+ btif_hh_stop_vup_timer(&(p_dev->bd_addr));
+ p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED;
+ BTIF_TRACE_DEBUG("%s---Sending connection state change", __func__);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, &(p_dev->bd_addr),
+ p_dev->dev_status);
+ BTIF_TRACE_DEBUG("%s---Removing HID bond", __func__);
+ /* If it is locally initiated VUP or remote device has its major COD as
+ Peripheral removed the bond.*/
+ if (p_dev->local_vup || check_cod_hid(&(p_dev->bd_addr))) {
+ p_dev->local_vup = false;
+ BTA_DmRemoveDevice((uint8_t*)p_dev->bd_addr.address);
+ } else
+ btif_hh_remove_device(p_dev->bd_addr);
+ HAL_CBACK(bt_hh_callbacks, virtual_unplug_cb, &(p_dev->bd_addr),
+ (bthh_status_t)p_data->dev_status.status);
+ }
+ break;
+
+ case BTA_HH_API_ERR_EVT:
+ LOG_INFO(LOG_TAG, "BTA_HH API_ERR");
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bte_hh_evt
+ *
+ * Description Switches context from BTE to BTIF for all HH events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH* p_data) {
+ bt_status_t status;
+ int param_len = 0;
+
+ if (BTA_HH_ENABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_OPEN_EVT == event)
+ param_len = sizeof(tBTA_HH_CONN);
+ else if (BTA_HH_DISABLE_EVT == event)
+ param_len = sizeof(tBTA_HH_STATUS);
+ else if (BTA_HH_CLOSE_EVT == event)
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if (BTA_HH_GET_DSCP_EVT == event)
+ param_len = sizeof(tBTA_HH_DEV_DSCP_INFO);
+ else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event) ||
+ (BTA_HH_GET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_HSDATA);
+ else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) ||
+ (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event))
+ param_len = sizeof(tBTA_HH_CBDATA);
+ else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event))
+ param_len = sizeof(tBTA_HH_DEV_INFO);
+ else if (BTA_HH_API_ERR_EVT == event)
+ param_len = 0;
+ /* switch context to btif task context (copy full union size for convenience)
+ */
+ status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event,
+ (char*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_handle_evt
+ *
+ * Description Switches context for immediate callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+static void btif_hh_handle_evt(uint16_t event, char* p_param) {
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)p_param;
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ int ret;
+ switch (event) {
+ case BTIF_HH_CONNECT_REQ_EVT: {
+ ret = btif_hh_connect(bd_addr);
+ if (ret == BT_STATUS_SUCCESS) {
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+ BTHH_CONN_STATE_CONNECTING);
+ } else
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+ BTHH_CONN_STATE_DISCONNECTED);
+ } break;
+
+ case BTIF_HH_DISCONNECT_REQ_EVT: {
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ btif_hh_disconnect(bd_addr);
+ HAL_CBACK(bt_hh_callbacks, connection_state_cb, bd_addr,
+ BTHH_CONN_STATE_DISCONNECTING);
+ } break;
+
+ case BTIF_HH_VUP_REQ_EVT: {
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ ret = btif_hh_virtual_unplug(bd_addr);
+ } break;
+
+ default: {
+ BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_timer_timeout
+ *
+ * Description Process timer timeout
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hh_timer_timeout(void* data) {
+ btif_hh_device_t* p_dev = (btif_hh_device_t*)data;
+ tBTA_HH_EVT event = BTA_HH_VC_UNPLUG_EVT;
+ tBTA_HH p_data;
+ int param_len = sizeof(tBTA_HH_CBDATA);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (p_dev->dev_status != BTHH_CONN_STATE_CONNECTED) return;
+
+ memset(&p_data, 0, sizeof(tBTA_HH));
+ p_data.dev_status.status = BTHH_ERR;
+ p_data.dev_status.handle = p_dev->dev_handle;
+
+ /* switch context to btif task context */
+ btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (char*)&p_data,
+ param_len, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_init
+ *
+ * Description initializes the hh interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthh_callbacks_t* callbacks) {
+ uint32_t i;
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ bt_hh_callbacks = callbacks;
+ memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
+ }
+ /* Invoke the enable service API to the core to set the appropriate service_id
+ */
+ btif_enable_service(BTA_HID_SERVICE_ID);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function connect
+ *
+ * Description connect to hid device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect(bt_bdaddr_t* bd_addr) {
+ if (btif_hh_cb.status != BTIF_HH_DEV_CONNECTING) {
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_CONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+ } else
+ return BT_STATUS_BUSY;
+}
+
+/*******************************************************************************
+ *
+ * Function disconnect
+ *
+ * Description disconnect from hid device
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHH_INIT();
+ BTIF_TRACE_EVENT("BTHH: %s", __func__);
+ btif_hh_device_t* p_dev;
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_WARNING("%s: Error, HH status = %d", __func__,
+ btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ return btif_transfer_context(btif_hh_handle_evt, BTIF_HH_DISCONNECT_REQ_EVT,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ } else {
+ BTIF_TRACE_WARNING("%s: Error, device not opened.", __func__);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function virtual_unplug
+ *
+ * Description Virtual UnPlug (VUP) the specified HID device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t virtual_unplug(bt_bdaddr_t* bd_addr) {
+ CHECK_BTHH_INIT();
+ BTIF_TRACE_EVENT("BTHH: %s", __func__);
+ btif_hh_device_t* p_dev;
+ char bd_str[18];
+ snprintf(bd_str, sizeof(bd_str), "%02X:%02X:%02X:%02X:%02X:%02X",
+ bd_addr->address[0], bd_addr->address[1], bd_addr->address[2],
+ bd_addr->address[3], bd_addr->address[4], bd_addr->address[5]);
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+ p_dev = btif_hh_find_dev_by_bda(bd_addr);
+ if (!p_dev) {
+ BTIF_TRACE_ERROR("%s: Error, device %s not opened.", __func__, bd_str);
+ return BT_STATUS_FAIL;
+ }
+ btif_transfer_context(btif_hh_handle_evt, BTIF_HH_VUP_REQ_EVT, (char*)bd_addr,
+ sizeof(bt_bdaddr_t), NULL);
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function set_info
+ *
+ * Description Set the HID device descriptor for the specified HID device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_info(bt_bdaddr_t* bd_addr, bthh_hid_info_t hid_info) {
+ CHECK_BTHH_INIT();
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG("BTHH: %s: addr = %02X:%02X:%02X:%02X:%02X:%02X", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+ (*bda)[5]);
+ BTIF_TRACE_DEBUG(
+ "BTHH: %s: sub_class = 0x%02x, app_id = %d, vendor_id = 0x%04x, "
+ "product_id = 0x%04x, version= 0x%04x",
+ __func__, hid_info.sub_class, hid_info.app_id, hid_info.vendor_id,
+ hid_info.product_id, hid_info.version);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ dscp_info.vendor_id = hid_info.vendor_id;
+ dscp_info.product_id = hid_info.product_id;
+ dscp_info.version = hid_info.version;
+ dscp_info.ctry_code = hid_info.ctry_code;
+
+ dscp_info.descriptor.dl_len = hid_info.dl_len;
+ dscp_info.descriptor.dsc_list =
+ (uint8_t*)osi_malloc(dscp_info.descriptor.dl_len);
+ memcpy(dscp_info.descriptor.dsc_list, &(hid_info.dsc_list), hid_info.dl_len);
+
+ if (btif_hh_add_added_dev(*bd_addr, hid_info.attr_mask)) {
+ BTA_HhAddDev(*bda, hid_info.attr_mask, hid_info.sub_class, hid_info.app_id,
+ dscp_info);
+ }
+
+ osi_free_and_reset((void**)&dscp_info.descriptor.dsc_list);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function get_protocol
+ *
+ * Description Get the HID proto mode.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t get_protocol(bt_bdaddr_t* bd_addr,
+ UNUSED_ATTR bthh_protocol_mode_t protocolMode) {
+ CHECK_BTHH_INIT();
+ btif_hh_device_t* p_dev;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG("BTHH: %s: addr = %02X:%02X:%02X:%02X:%02X:%02X", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+ (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev != NULL) {
+ BTA_HhGetProtoMode(p_dev->dev_handle);
+ } else {
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function set_protocol
+ *
+ * Description Set the HID proto mode.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_protocol(bt_bdaddr_t* bd_addr,
+ bthh_protocol_mode_t protocolMode) {
+ CHECK_BTHH_INIT();
+ btif_hh_device_t* p_dev;
+ uint8_t proto_mode = protocolMode;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG(
+ "BTHH: %s: proto_mode = %d"
+ " addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ __func__, protocolMode, (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3],
+ (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_WARNING(
+ " Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", (*bda)[0],
+ (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ } else if (protocolMode != BTA_HH_PROTO_RPT_MODE &&
+ protocolMode != BTA_HH_PROTO_BOOT_MODE) {
+ BTIF_TRACE_WARNING("%s: Error, device proto_mode = %d.", __func__,
+ proto_mode);
+ return BT_STATUS_FAIL;
+ } else {
+ BTA_HhSetProtoMode(p_dev->dev_handle, protocolMode);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function get_report
+ *
+ * Description Send a GET_REPORT to HID device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t get_report(bt_bdaddr_t* bd_addr,
+ bthh_report_type_t reportType, uint8_t reportId,
+ int bufferSize) {
+ CHECK_BTHH_INIT();
+ btif_hh_device_t* p_dev;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG(
+ "BTHH: %s: r_type = %d, rpt_id = %d, buf_size = %d"
+ " addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ __func__, reportType, reportId, bufferSize, (*bda)[0], (*bda)[1],
+ (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR(
+ "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
+ ((int)reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+ (*bda)[5]);
+ return BT_STATUS_FAIL;
+ } else {
+ BTA_HhGetReport(p_dev->dev_handle, reportType, reportId, bufferSize);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function set_report
+ *
+ * Description Send a SET_REPORT to HID device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t set_report(bt_bdaddr_t* bd_addr,
+ bthh_report_type_t reportType, char* report) {
+ CHECK_BTHH_INIT();
+ btif_hh_device_t* p_dev;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG(
+ "BTHH %s: reportType = %d"
+ " addr = %02X:%02X:%02X:%02X:%02X:%02X",
+ __func__, reportType, (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3],
+ (*bda)[4], (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR(
+ "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ } else if (((int)reportType) <= BTA_HH_RPTT_RESRV ||
+ ((int)reportType) > BTA_HH_RPTT_FEATURE) {
+ BTIF_TRACE_ERROR(" Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.",
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+ (*bda)[5]);
+ return BT_STATUS_FAIL;
+ } else {
+ int hex_bytes_filled;
+ size_t len = (strlen(report) + 1) / 2;
+ uint8_t* hexbuf = (uint8_t*)osi_calloc(len);
+
+ /* Build a SetReport data buffer */
+ // TODO
+ hex_bytes_filled = ascii_2_hex(report, len, hexbuf);
+ LOG_INFO(LOG_TAG, "Hex bytes filled, hex value: %d", hex_bytes_filled);
+ if (hex_bytes_filled) {
+ BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf);
+ if (p_buf == NULL) {
+ BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d",
+ __func__, hex_bytes_filled);
+ osi_free(hexbuf);
+ return BT_STATUS_FAIL;
+ }
+ BTA_HhSetReport(p_dev->dev_handle, reportType, p_buf);
+ osi_free(hexbuf);
+ return BT_STATUS_SUCCESS;
+ }
+ osi_free(hexbuf);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function send_data
+ *
+ * Description Send a SEND_DATA to HID device.
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t send_data(bt_bdaddr_t* bd_addr, char* data) {
+ CHECK_BTHH_INIT();
+ btif_hh_device_t* p_dev;
+ BD_ADDR* bda = (BD_ADDR*)bd_addr;
+
+ BTIF_TRACE_DEBUG("BTHH %s: addr = %02X:%02X:%02X:%02X:%02X:%02X", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4],
+ (*bda)[5]);
+
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_ERROR("%s: Error, HH status = %d", __func__, btif_hh_cb.status);
+ return BT_STATUS_FAIL;
+ }
+
+ p_dev = btif_hh_find_connected_dev_by_bda(bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR(
+ "%s: Error, device %02X:%02X:%02X:%02X:%02X:%02X not opened.", __func__,
+ (*bda)[0], (*bda)[1], (*bda)[2], (*bda)[3], (*bda)[4], (*bda)[5]);
+ return BT_STATUS_FAIL;
+ }
+
+ else {
+ int hex_bytes_filled;
+ size_t len = (strlen(data) + 1) / 2;
+ uint8_t* hexbuf = (uint8_t*)osi_calloc(len);
+
+ /* Build a SendData data buffer */
+ hex_bytes_filled = ascii_2_hex(data, len, hexbuf);
+ BTIF_TRACE_ERROR("Hex bytes filled, hex value: %d, %d", hex_bytes_filled,
+ len);
+
+ if (hex_bytes_filled) {
+ BT_HDR* p_buf = create_pbuf(hex_bytes_filled, hexbuf);
+ if (p_buf == NULL) {
+ BTIF_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, len = %d",
+ __func__, hex_bytes_filled);
+ osi_free(hexbuf);
+ return BT_STATUS_FAIL;
+ }
+ p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
+ BTA_HhSendData(p_dev->dev_handle, *bda, p_buf);
+ osi_free(hexbuf);
+ return BT_STATUS_SUCCESS;
+ }
+ osi_free(hexbuf);
+ return BT_STATUS_FAIL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Closes the HH interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ btif_hh_device_t* p_dev;
+ int i;
+ if (btif_hh_cb.status == BTIF_HH_DISABLED) {
+ BTIF_TRACE_WARNING("%s: HH disabling or disabled already, status = %d",
+ __func__, btif_hh_cb.status);
+ return;
+ }
+ if (bt_hh_callbacks) {
+ btif_hh_cb.status = BTIF_HH_DISABLING;
+ /* update flag, not to enable hid device service now as BT is switching off
+ */
+ btif_hh_cb.service_dereg_active = FALSE;
+ btif_disable_service(BTA_HID_SERVICE_ID);
+ bt_hh_callbacks = NULL;
+ }
+ for (i = 0; i < BTIF_HH_MAX_HID; i++) {
+ p_dev = &btif_hh_cb.devices[i];
+ if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->fd >= 0) {
+ BTIF_TRACE_DEBUG("%s: Closing uhid fd = %d", __func__, p_dev->fd);
+ if (p_dev->fd >= 0) {
+ bta_hh_co_destroy(p_dev->fd);
+ p_dev->fd = -1;
+ }
+ p_dev->hh_keep_polling = 0;
+ p_dev->hh_poll_thread_id = -1;
+ }
+ }
+
+}
+
+static const bthh_interface_t bthhInterface = {
+ sizeof(bthhInterface), init, connect, disconnect, virtual_unplug, set_info,
+ get_protocol, set_protocol,
+ // get_idle_time,
+ // set_idle_time,
+ get_report, set_report, send_data, cleanup,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_hh_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_hh_execute_service(bool b_enable) {
+ if (b_enable) {
+ /* Enable and register with BTA-HH */
+ BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt);
+ } else {
+ /* Disable HH */
+ BTA_HhDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hh_get_interface
+ *
+ * Description Get the hh callback interface
+ *
+ * Returns bthh_interface_t
+ *
+ ******************************************************************************/
+const bthh_interface_t* btif_hh_get_interface() {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bthhInterface;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_hl.cc b/mtkbt/code/bt/btif/src/btif_hl.cc
new file mode 100755
index 0000000..da08092
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_hl.cc
@@ -0,0 +1,4729 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_hl.c
+ *
+ * Description: Health Device Profile Bluetooth Interface
+ *
+ *
+ ******************************************************************************/
+#define LOG_TAG "bt_btif_hl"
+
+#include "btif_hl.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <hardware/bt_hl.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_storage.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "mca_api.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define MAX_DATATYPE_SUPPORTED 8
+
+extern int btif_hl_update_maxfd(int max_org_s);
+extern void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+ UNUSED_ATTR fd_set* p_org_set);
+extern void btif_hl_select_wakeup_callback(fd_set* p_org_set,
+ int wakeup_signal);
+extern int btif_hl_update_maxfd(int max_org_s);
+extern void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+ UNUSED_ATTR fd_set* p_org_set);
+extern void btif_hl_select_wakeup_callback(fd_set* p_org_set,
+ int wakeup_signal);
+extern void btif_hl_soc_thread_init(void);
+extern void btif_hl_release_mcl_sockets(uint8_t app_idx, uint8_t mcl_idx);
+extern bool btif_hl_create_socket(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+extern void btif_hl_release_socket(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+btif_hl_cb_t btif_hl_cb;
+btif_hl_cb_t* p_btif_hl_cb = &btif_hl_cb;
+/**M:Bug fix for fail get SDP record @{*/
+tBTA_HL_SDP g_bta_sdp;
+/**@}*/
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static bthl_callbacks_t bt_hl_callbacks_cb;
+static bthl_callbacks_t* bt_hl_callbacks = NULL;
+
+/* signal socketpair to wake up select loop */
+
+const int btif_hl_signal_select_wakeup = 1;
+const int btif_hl_signal_select_exit = 2;
+const int btif_hl_signal_select_close_connected = 3;
+
+static int listen_s = -1;
+static int connected_s = -1;
+static pthread_t select_thread_id = -1;
+static int signal_fds[2] = {-1, -1};
+static list_t* soc_queue;
+static int reg_counter;
+
+static inline int btif_hl_select_wakeup(void);
+static inline int btif_hl_select_close_connected(void);
+static inline int btif_hl_close_select_thread(void);
+static uint8_t btif_hl_get_next_app_id(void);
+static int btif_hl_get_next_channel_id(uint8_t app_id);
+static void btif_hl_init_next_app_id(void);
+static void btif_hl_init_next_channel_id(void);
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data);
+static void btif_hl_set_state(btif_hl_state_t state);
+static btif_hl_state_t btif_hl_get_state(void);
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL* p_data);
+static void btif_hl_proc_cb_evt(uint16_t event, char* p_param);
+
+#define CHECK_CALL_CBACK(P_CB, P_CBACK, ...) \
+ do { \
+ if ((P_CB) && (P_CB)->P_CBACK) { \
+ (P_CB)->P_CBACK(__VA_ARGS__); \
+ } else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ } while (0)
+
+#define BTIF_HL_CALL_CBACK(P_CB, P_CBACK, ...) \
+ do { \
+ if ((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) && \
+ (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) { \
+ if ((P_CB) && (P_CB)->P_CBACK) { \
+ (P_CB)->P_CBACK(__VA_ARGS__); \
+ } else { \
+ ASSERTC(0, "Callback is NULL", 0); \
+ } \
+ } \
+ } while (0)
+
+#define CHECK_BTHL_INIT() \
+ do { \
+ if (bt_hl_callbacks == NULL) { \
+ BTIF_TRACE_WARNING("BTHL: %s: BTHL not initialized", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+static const btif_hl_data_type_cfg_t data_type_table[] = {
+ /* Data Specilization Ntx Nrx (from Bluetooth SIG's
+ HDP whitepaper)*/
+ {BTIF_HL_DATA_TYPE_PULSE_OXIMETER, 9216, 256},
+ {BTIF_HL_DATA_TYPE_BLOOD_PRESSURE_MON, 896, 224},
+ {BTIF_HL_DATA_TYPE_BODY_THERMOMETER, 896, 224},
+ {BTIF_HL_DATA_TYPE_BODY_WEIGHT_SCALE, 896, 224},
+ {BTIF_HL_DATA_TYPE_GLUCOSE_METER, 896, 224},
+ {BTIF_HL_DATA_TYPE_STEP_COUNTER, 6624, 224},
+ {BTIF_HL_DATA_TYPE_BCA, 7730, 1230},
+ {BTIF_HL_DATA_TYPE_PEAK_FLOW, 2030, 224},
+ {BTIF_HL_DATA_TYPE_ACTIVITY_HUB, 5120, 224},
+ {BTIF_HL_DATA_TYPE_AMM, 1024, 64}};
+
+#define BTIF_HL_DATA_TABLE_SIZE \
+ (sizeof(data_type_table) / sizeof(btif_hl_data_type_cfg_t))
+#define BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE \
+ 10240 /* use this size if the data type is not \
+ defined in the table; for future proof */
+#define BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE \
+ 512 /* use this size if the data type is not \
+ defined in the table; for future proof */
+
+#define BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE 1024
+
+/*******************************************************************************
+ * Static utility functions
+ ******************************************************************************/
+
+#define BTIF_IF_GET_NAME 16
+void btif_hl_display_calling_process_name(void) {
+ char name[16];
+ prctl(BTIF_IF_GET_NAME, name, 0, 0, 0);
+ BTIF_TRACE_DEBUG("Process name (%s)", name);
+}
+#define BTIF_TIMEOUT_CCH_NO_DCH_MS (30 * 1000)
+
+/*******************************************************************************
+ *
+ * Function btif_hl_if_channel_setup_pending
+ *
+ * Description check whether channel id is in setup pending state or not
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_if_channel_setup_pending(int channel_id, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t i, j;
+ bool found = false;
+
+ *p_app_idx = 0;
+ *p_mcl_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use) {
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+ if (p_mcb->in_use && p_mcb->is_connected &&
+ p_mcb->pcb.channel_id == channel_id) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ if (found) break;
+ }
+ BTIF_TRACE_DEBUG("%s found=%d channel_id=0x%08x", __func__, found, channel_id,
+ *p_app_idx, *p_mcl_idx);
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_num_dchs_in_use
+ *
+ * Description find number of DCHs in use
+ *
+ * Returns uint8_t
+ ******************************************************************************/
+uint8_t btif_hl_num_dchs_in_use(uint8_t mcl_handle) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t i, j, x;
+ uint8_t cnt = 0;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ BTIF_TRACE_DEBUG("btif_hl_num_dchs:i = %d", i);
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb && p_acb->in_use) {
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use)
+ BTIF_TRACE_DEBUG(
+ "btif_hl_num_dchs:mcb in use j=%d, mcl_handle=%d,mcb handle=%d",
+ j, mcl_handle, p_acb->mcb[j].mcl_handle);
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ p_mcb = &p_acb->mcb[j];
+ BTIF_TRACE_DEBUG("btif_hl_num_dchs: mcl handle found j =%d", j);
+ for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+ if (p_mcb->mdl[x].in_use) {
+ BTIF_TRACE_DEBUG("btif_hl_num_dchs_in_use:found x =%d", x);
+ cnt++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s dch in use count=%d", __func__, cnt);
+ return cnt;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_timer_timeout
+ *
+ * Description Process timer timeout
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hl_timer_timeout(void* data) {
+ btif_hl_mcl_cb_t* p_mcb = (btif_hl_mcl_cb_t*)data;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (p_mcb->is_connected) {
+ BTIF_TRACE_DEBUG("Idle timeout Close CCH mcl_handle=%d", p_mcb->mcl_handle);
+ BTA_HlCchClose(p_mcb->mcl_handle);
+ } else {
+ BTIF_TRACE_DEBUG("CCH idle timeout But CCH not connected");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_stop_cch_timer
+ *
+ * Description stop CCH timer
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hl_stop_cch_timer(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+ alarm_cancel(p_mcb->cch_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_start_cch_timer
+ *
+ * Description start CCH timer
+ *
+ * Returns void
+ ******************************************************************************/
+void btif_hl_start_cch_timer(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+
+ alarm_free(p_mcb->cch_timer);
+ p_mcb->cch_timer = alarm_new("btif_hl.mcl_cch_timer");
+ alarm_set_on_queue(p_mcb->cch_timer, BTIF_TIMEOUT_CCH_NO_DCH_MS,
+ btif_hl_timer_timeout, p_mcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdl_idx
+ *
+ * Description Find the MDL index using MDL ID
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint16_t mdl_id, uint8_t* p_mdl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use && (mdl_id != 0) &&
+ (p_mcb->mdl[i].mdl_id == mdl_id)) {
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d mdl_id=%d mdl_idx=%d ", __func__, found, mdl_id,
+ i);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_is_the_first_reliable_existed
+ *
+ * Description This function checks whether the first reliable DCH channel
+ * has been setup on the MCL or not
+ *
+ * Returns bool - true exist
+ * false does not exist
+ *
+ ******************************************************************************/
+bool btif_hl_is_the_first_reliable_existed(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool is_existed = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (p_mcb->mdl[i].in_use && p_mcb->mdl[i].is_the_first_reliable) {
+ is_existed = true;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("bta_hl_is_the_first_reliable_existed is_existed=%d ",
+ is_existed);
+ return is_existed;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_clean_delete_mdl
+ *
+ * Description Cleanup the delete mdl control block
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_delete_mdl(btif_hl_delete_mdl_t* p_cb) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ memset(p_cb, 0, sizeof(btif_hl_delete_mdl_t));
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_clean_pcb
+ *
+ * Description Cleanup the pending chan control block
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_pcb(btif_hl_pending_chan_cb_t* p_pcb) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ memset(p_pcb, 0, sizeof(btif_hl_pending_chan_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_clean_mdl_cb
+ *
+ * Description Cleanup the MDL control block
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mdl_cb(btif_hl_mdl_cb_t* p_dcb) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ osi_free_and_reset((void**)&p_dcb->p_rx_pkt);
+ osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+ memset(p_dcb, 0, sizeof(btif_hl_mdl_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_reset_mcb
+ *
+ * Description Reset MCL control block
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mcl_cb(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_mcl_cb_t* p_mcb;
+ BTIF_TRACE_DEBUG("%s app_idx=%d, mcl_idx=%d", __func__, app_idx, mcl_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ alarm_free(p_mcb->cch_timer);
+ memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_sdp_idx_using_mdep_filter
+ *
+ * Description This function finds the SDP record index using MDEP filter
+ * parameters
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static void btif_hl_reset_mdep_filter(uint8_t app_idx) {
+ btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->filter.num_elems = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_sdp_idx_using_mdep_filter
+ *
+ * Description This function finds the SDP record index using MDEP filter
+ * parameters
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_sdp_idx_using_mdep_filter(uint8_t app_idx,
+ uint8_t mcl_idx,
+ uint8_t* p_sdp_idx) {
+ btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ uint8_t i, j, num_recs, num_elems, num_mdeps, mdep_idx;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+ uint16_t data_type;
+ tBTA_HL_SDP_MDEP_CFG* p_mdep;
+ bool found = false;
+ bool elem_found;
+
+ BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter");
+ num_recs = p_mcb->sdp.num_recs;
+ num_elems = p_acb->filter.num_elems;
+ if (!num_elems) {
+ BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter num_elem=0");
+ *p_sdp_idx = 0;
+ found = true;
+ return found;
+ }
+
+ for (i = 0; i < num_recs; i++) {
+ num_mdeps = p_mcb->sdp.sdp_rec[i].num_mdeps;
+ for (j = 0; j < num_elems; j++) {
+ data_type = p_acb->filter.elem[j].data_type;
+ peer_mdep_role = p_acb->filter.elem[j].peer_mdep_role;
+ elem_found = false;
+ mdep_idx = 0;
+ while (!elem_found && mdep_idx < num_mdeps) {
+ p_mdep = &(p_mcb->sdp.sdp_rec[i].mdep_cfg[mdep_idx]);
+ if ((p_mdep->data_type == data_type) &&
+ (p_mdep->mdep_role == peer_mdep_role)) {
+ elem_found = true;
+ } else {
+ mdep_idx++;
+ }
+ }
+
+ if (!elem_found) {
+ found = false;
+ break;
+ } else {
+ found = true;
+ }
+ }
+
+ if (found) {
+ BTIF_TRACE_DEBUG("btif_hl_find_sdp_idx_using_mdep_filter found idx=%d",
+ i);
+ *p_sdp_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d sdp_idx=%d", __func__, found, *p_sdp_idx);
+
+ btif_hl_reset_mdep_filter(app_idx);
+
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_is_reconnect_possible
+ *
+ * Description check reconnect is possible or not
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_is_reconnect_possible(uint8_t app_idx, uint8_t mcl_idx,
+ int mdep_cfg_idx,
+ tBTA_HL_DCH_OPEN_PARAM* p_dch_open_api,
+ tBTA_HL_MDL_ID* p_mdl_id) {
+ btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ tBTA_HL_DCH_CFG local_cfg = p_dch_open_api->local_cfg;
+ tBTA_HL_DCH_MODE dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ bool use_mdl_dch_mode = false;
+ btif_hl_mdl_cfg_t* p_mdl;
+ btif_hl_mdl_cfg_t* p_mdl1;
+ uint8_t i, j;
+ bool is_reconnect_ok = false;
+ bool stream_mode_avail = false;
+ uint16_t data_type =
+ p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.data_cfg[0].data_type;
+ tBTA_HL_MDEP_ID peer_mdep_id = p_dch_open_api->peer_mdep_id;
+ uint8_t mdl_idx;
+
+ BTIF_TRACE_DEBUG("%s app_idx=%d mcl_idx=%d mdep_cfg_idx=%d", __func__,
+ app_idx, mcl_idx, mdep_cfg_idx);
+ switch (local_cfg) {
+ case BTA_HL_DCH_CFG_NO_PREF:
+ if (!btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ } else {
+ use_mdl_dch_mode = true;
+ }
+ break;
+ case BTA_HL_DCH_CFG_RELIABLE:
+ dch_mode = BTA_HL_DCH_MODE_RELIABLE;
+ break;
+ case BTA_HL_DCH_CFG_STREAMING:
+ dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ break;
+ default:
+ BTIF_TRACE_ERROR("Invalid local_cfg=%d", local_cfg);
+ return is_reconnect_ok;
+ break;
+ }
+
+ BTIF_TRACE_DEBUG("local_cfg=%d use_mdl_dch_mode=%d dch_mode=%d ", local_cfg,
+ use_mdl_dch_mode, dch_mode);
+
+ for (i = 0, p_mdl = &p_acb->mdl_cfg[0]; i < BTA_HL_NUM_MDL_CFGS;
+ i++, p_mdl++) {
+ if (p_mdl->base.active && p_mdl->extra.data_type == data_type &&
+ (p_mdl->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID &&
+ p_mdl->extra.peer_mdep_id == peer_mdep_id) &&
+ memcpy(p_mdl->base.peer_bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR)) &&
+ p_mdl->base.mdl_id &&
+ !btif_hl_find_mdl_idx(app_idx, mcl_idx, p_mdl->base.mdl_id, &mdl_idx)) {
+ BTIF_TRACE_DEBUG("i=%d Matched active=%d mdl_id =%d, mdl_dch_mode=%d",
+ i, p_mdl->base.active, p_mdl->base.mdl_id,
+ p_mdl->base.dch_mode);
+ if (!use_mdl_dch_mode) {
+ if (p_mdl->base.dch_mode == dch_mode) {
+ is_reconnect_ok = true;
+ *p_mdl_id = p_mdl->base.mdl_id;
+ BTIF_TRACE_DEBUG("reconnect is possible dch_mode=%d mdl_id=%d",
+ dch_mode, p_mdl->base.mdl_id);
+ break;
+ }
+ } else {
+ is_reconnect_ok = true;
+ for (j = i, p_mdl1 = &p_acb->mdl_cfg[i]; j < BTA_HL_NUM_MDL_CFGS;
+ j++, p_mdl1++) {
+ if (p_mdl1->base.active && p_mdl1->extra.data_type == data_type &&
+ (p_mdl1->extra.peer_mdep_id != BTA_HL_INVALID_MDEP_ID &&
+ p_mdl1->extra.peer_mdep_id == peer_mdep_id) &&
+ memcpy(p_mdl1->base.peer_bd_addr, p_mcb->bd_addr,
+ sizeof(BD_ADDR)) &&
+ p_mdl1->base.dch_mode == BTA_HL_DCH_MODE_STREAMING) {
+ stream_mode_avail = true;
+ BTIF_TRACE_DEBUG("found streaming mode mdl index=%d", j);
+ break;
+ }
+ }
+
+ if (stream_mode_avail) {
+ dch_mode = BTA_HL_DCH_MODE_STREAMING;
+ *p_mdl_id = p_mdl1->base.mdl_id;
+ BTIF_TRACE_DEBUG(
+ "reconnect is ok index=%d dch_mode=streaming mdl_id=%d", j,
+ *p_mdl_id);
+ break;
+ } else {
+ dch_mode = p_mdl->base.dch_mode;
+ *p_mdl_id = p_mdl->base.mdl_id;
+ BTIF_TRACE_DEBUG("reconnect is ok index=%d dch_mode=%d mdl_id=%d", i,
+ p_mdl->base.dch_mode, *p_mdl_id);
+ break;
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG("is_reconnect_ok dch_mode=%d mdl_id=%d", is_reconnect_ok,
+ dch_mode, *p_mdl_id);
+ return is_reconnect_ok;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_dch_open
+ *
+ * Description Process DCH open request using the DCH Open API parameters
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_dch_open(uint8_t app_id, BD_ADDR bd_addr,
+ tBTA_HL_DCH_OPEN_PARAM* p_dch_open_api, int mdep_cfg_idx,
+ btif_hl_pend_dch_op_t op, int* channel_id) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_pending_chan_cb_t* p_pcb;
+ uint8_t app_idx, mcl_idx;
+ bool status = false;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d ", __func__, app_id);
+ BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (!p_pcb->in_use) {
+ p_mcb->req_ctrl_psm = p_dch_open_api->ctrl_psm;
+
+ p_pcb->in_use = true;
+ *channel_id = p_pcb->channel_id =
+ (int)btif_hl_get_next_channel_id(app_id);
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+ p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+ memcpy(p_pcb->bd_addr, bd_addr, sizeof(BD_ADDR));
+ p_pcb->op = op;
+
+ if (p_mcb->sdp.num_recs) {
+ if (p_mcb->valid_sdp_idx) {
+ p_dch_open_api->ctrl_psm = p_mcb->ctrl_psm;
+ }
+
+ if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx, mdep_cfg_idx,
+ p_dch_open_api, &mdl_id)) {
+ BTIF_TRACE_DEBUG("Issue DCH open");
+ BTA_HlDchOpen(p_mcb->mcl_handle, p_dch_open_api);
+ } else {
+ reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+ reconnect_param.mdl_id = mdl_id;
+ ;
+ BTIF_TRACE_DEBUG("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",
+ reconnect_param.ctrl_psm, reconnect_param.mdl_id);
+ BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+ }
+
+ status = true;
+ } else {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_DCH_OPEN;
+ BTA_HlSdpQuery(app_id, p_acb->app_handle, bd_addr);
+ status = true;
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG("status=%d ", status);
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_copy_bda
+ *
+ * Description copy bt_bdaddr_t to BD_ADDR format
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_copy_bda(bt_bdaddr_t* bd_addr, BD_ADDR bda) {
+ uint8_t i;
+ for (i = 0; i < 6; i++) {
+ bd_addr->address[i] = bda[i];
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_copy_bda
+ *
+ * Description display bt_bdaddr_t
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+void btif_hl_display_bt_bda(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr->address[0],
+ bd_addr->address[1], bd_addr->address[2],
+ bd_addr->address[3], bd_addr->address[4],
+ bd_addr->address[5]);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_dch_abort
+ *
+ * Description Process DCH abort request
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+void btif_hl_dch_abort(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_mcl_cb_t* p_mcb;
+
+ BTIF_TRACE_DEBUG("%s app_idx=%d mcl_idx=%d", __func__, app_idx, mcl_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected) {
+ BTA_HlDchAbort(p_mcb->mcl_handle);
+ } else {
+ p_mcb->pcb.abort_pending = true;
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_cch_open
+ *
+ * Description Process CCH open request
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+bool btif_hl_cch_open(uint8_t app_id, BD_ADDR bd_addr, uint16_t ctrl_psm,
+ int mdep_cfg_idx, btif_hl_pend_dch_op_t op,
+ int* channel_id) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_pending_chan_cb_t* p_pcb;
+ uint8_t app_idx, mcl_idx;
+ bool status = true;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d ctrl_psm=%d mdep_cfg_idx=%d op=%d", __func__,
+ app_id, ctrl_psm, mdep_cfg_idx, op);
+ BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ if (!btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+ if (btif_hl_find_avail_mcl_idx(app_idx, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ alarm_free(p_mcb->cch_timer);
+ memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+ p_mcb->in_use = true;
+ bdcpy(p_mcb->bd_addr, bd_addr);
+
+ if (!ctrl_psm) {
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING;
+ } else {
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_MATCHED_CTRL_PSM;
+ p_mcb->req_ctrl_psm = ctrl_psm;
+ }
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ p_pcb->in_use = true;
+ p_pcb->mdep_cfg_idx = mdep_cfg_idx;
+ memcpy(p_pcb->bd_addr, bd_addr, sizeof(BD_ADDR));
+ p_pcb->op = op;
+
+ switch (op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ *channel_id = p_pcb->channel_id =
+ (int)btif_hl_get_next_channel_id(app_id);
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING;
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ p_pcb->channel_id = p_acb->delete_mdl.channel_id;
+ p_pcb->cb_state = BTIF_HL_CHAN_CB_STATE_DESTROYED_PENDING;
+ break;
+ default:
+ break;
+ }
+ BTA_HlSdpQuery(app_id, p_acb->app_handle, bd_addr);
+ } else {
+ status = false;
+ BTIF_TRACE_ERROR("Open CCH request discarded- No mcl cb");
+ }
+ } else {
+ status = false;
+ BTIF_TRACE_ERROR("Open CCH request discarded- already in USE");
+ }
+ } else {
+ status = false;
+ BTIF_TRACE_ERROR("Invalid app_id=%d", app_id);
+ }
+
+ if (channel_id) {
+ BTIF_TRACE_DEBUG("status=%d channel_id=0x%08x", status, *channel_id);
+ } else {
+ BTIF_TRACE_DEBUG("status=%d ", status);
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdl_idx_using_handle
+ *
+ * Description Find the MDL index using channel id
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_cfg_idx_using_channel_id(int channel_id,
+ uint8_t* p_app_idx,
+ uint8_t* p_mdl_cfg_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mdl_cfg_t* p_mdl;
+ bool found = false;
+ uint8_t i, j;
+ int mdl_cfg_channel_id;
+
+ *p_app_idx = 0;
+ *p_mdl_cfg_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MDL_CFGS; j++) {
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(i, j);
+ mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(i, j));
+ if (p_acb->in_use && p_mdl->base.active &&
+ (mdl_cfg_channel_id == channel_id)) {
+ found = true;
+ *p_app_idx = i;
+ *p_mdl_cfg_idx = j;
+ break;
+ }
+ }
+ }
+
+ BTIF_TRACE_EVENT("%s found=%d channel_id=0x%08x, app_idx=%d mdl_cfg_idx=%d ",
+ __func__, found, channel_id, i, j);
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdl_idx_using_handle
+ *
+ * Description Find the MDL index using channel id
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_idx_using_channel_id(int channel_id, uint8_t* p_app_idx,
+ uint8_t* p_mcl_idx,
+ uint8_t* p_mdl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_mdl_cb_t* p_dcb;
+ bool found = false;
+ uint8_t i, j, k;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+ for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(i, j, k);
+ if (p_acb->in_use && p_mcb->in_use && p_dcb->in_use &&
+ (p_dcb->channel_id == channel_id)) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d ", __func__,
+ found, i, j, k);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_channel_id_using_mdl_id
+ *
+ * Description Find channel id using mdl_id'
+ *
+ * Returns bool
+ ******************************************************************************/
+bool btif_hl_find_channel_id_using_mdl_id(uint8_t app_idx,
+ tBTA_HL_MDL_ID mdl_id,
+ int* p_channel_id) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mdl_cfg_t* p_mdl;
+ bool found = false;
+ uint8_t j = 0;
+ int mdl_cfg_channel_id;
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (p_acb && p_acb->in_use) {
+ for (j = 0; j < BTA_HL_NUM_MDL_CFGS; j++) {
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, j);
+ mdl_cfg_channel_id = *(BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, j));
+ if (p_mdl->base.active && (p_mdl->base.mdl_id == mdl_id)) {
+ found = true;
+ *p_channel_id = mdl_cfg_channel_id;
+ break;
+ }
+ }
+ }
+ BTIF_TRACE_EVENT(
+ "%s found=%d channel_id=0x%08x, mdl_id=0x%x app_idx=%d mdl_cfg_idx=%d ",
+ __func__, found, *p_channel_id, mdl_id, app_idx, j);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdl_idx_using_handle
+ *
+ * Description Find the MDL index using handle
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mdl_idx_using_handle(tBTA_HL_MDL_HANDLE mdl_handle,
+ uint8_t* p_app_idx, uint8_t* p_mcl_idx,
+ uint8_t* p_mdl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_mdl_cb_t* p_dcb;
+ bool found = false;
+ uint8_t i, j, k;
+
+ *p_app_idx = 0;
+ *p_mcl_idx = 0;
+ *p_mdl_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, j);
+ for (k = 0; k < BTA_HL_NUM_MDLS_PER_MCL; k++) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(i, j, k);
+ if (p_acb->in_use && p_mcb->in_use && p_dcb->in_use &&
+ (p_dcb->mdl_handle == mdl_handle)) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ *p_mdl_idx = k;
+ break;
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_EVENT("%s found=%d app_idx=%d mcl_idx=%d mdl_idx=%d ", __func__,
+ found, i, j, k);
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_find_peer_mdep_id
+ *
+ * Description Find the peer MDEP ID from the received SPD records
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_peer_mdep_id(uint8_t app_id, BD_ADDR bd_addr,
+ tBTA_HL_MDEP_ROLE local_mdep_role,
+ uint16_t data_type,
+ tBTA_HL_MDEP_ID* p_peer_mdep_id) {
+ uint8_t app_idx, mcl_idx;
+ btif_hl_mcl_cb_t* p_mcb;
+ tBTA_HL_SDP_REC* p_rec;
+ uint8_t i, num_mdeps;
+ bool found = false;
+ tBTA_HL_MDEP_ROLE peer_mdep_role;
+
+ BTIF_TRACE_DEBUG("%s app_id=%d local_mdep_role=%d, data_type=%d", __func__,
+ app_id, local_mdep_role, data_type);
+
+ BTIF_TRACE_DEBUG("DB [%02x:%02x:%02x:%02x:%02x:%02x]", bd_addr[0], bd_addr[1],
+ bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ BTIF_TRACE_DEBUG("local_mdep_role=%d", local_mdep_role);
+ BTIF_TRACE_DEBUG("data_type=%d", data_type);
+
+ if (local_mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ if (btif_hl_find_mcl_idx(app_idx, bd_addr, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d", app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG("valid_spd_idx=%d sdp_idx=%d", p_mcb->valid_sdp_idx,
+ p_mcb->sdp_idx);
+ if (p_mcb->valid_sdp_idx) {
+ p_rec = &p_mcb->sdp.sdp_rec[p_mcb->sdp_idx];
+ num_mdeps = p_rec->num_mdeps;
+ BTIF_TRACE_DEBUG("num_mdeps=%d", num_mdeps);
+
+ for (i = 0; i < num_mdeps; i++) {
+ BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].mdep_role=%d", i,
+ p_rec->mdep_cfg[i].mdep_role);
+ BTIF_TRACE_DEBUG("p_rec->mdep_cfg[%d].data_type =%d", i,
+ p_rec->mdep_cfg[i].data_type);
+ if ((p_rec->mdep_cfg[i].mdep_role == peer_mdep_role) &&
+ (p_rec->mdep_cfg[i].data_type == data_type)) {
+ found = true;
+ *p_peer_mdep_id = p_rec->mdep_cfg[i].mdep_id;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ BTIF_TRACE_DEBUG("found =%d *p_peer_mdep_id=%d", found, *p_peer_mdep_id);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdep_cfg_idx
+ *
+ * Description Find the MDEP configuration index using local MDEP_ID
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_mdep_cfg_idx(uint8_t app_idx,
+ tBTA_HL_MDEP_ID local_mdep_id,
+ uint8_t* p_mdep_cfg_idx) {
+ btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ tBTA_HL_SUP_FEATURE* p_sup_feature = &p_acb->sup_feature;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < p_sup_feature->num_of_mdeps; i++) {
+ BTIF_TRACE_DEBUG("btif_hl_find_mdep_cfg_idx: mdep_id=%d app_idx = %d",
+ p_sup_feature->mdep[i].mdep_id, app_idx);
+ if (p_sup_feature->mdep[i].mdep_id == local_mdep_id) {
+ found = true;
+ *p_mdep_cfg_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d mdep_idx=%d local_mdep_id=%d app_idx=%d ",
+ __func__, found, i, local_mdep_id, app_idx);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mcl_idx
+ *
+ * Description Find the MCL index using BD address
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx(uint8_t app_idx, BD_ADDR p_bd_addr,
+ uint8_t* p_mcl_idx) {
+ bool found = false;
+ uint8_t i;
+ btif_hl_mcl_cb_t* p_mcb;
+
+ *p_mcl_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, i);
+ if (p_mcb->in_use && (!memcmp(p_mcb->bd_addr, p_bd_addr, BD_ADDR_LEN))) {
+ found = true;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d idx=%d", __func__, found, i);
+ return found;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_init
+ *
+ * Description HL initialization function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_init(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+ btif_hl_init_next_app_id();
+ btif_hl_init_next_channel_id();
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_disable
+ *
+ * Description Disable initialization function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_disable(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if ((p_btif_hl_cb->state != BTIF_HL_STATE_DISABLING) &&
+ (p_btif_hl_cb->state != BTIF_HL_STATE_DISABLED)) {
+ btif_hl_set_state(BTIF_HL_STATE_DISABLING);
+ BTA_HlDisable();
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_is_no_active_app
+ *
+ * Description Find whether or not any APP is still in use
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_is_no_active_app(void) {
+ bool no_active_app = true;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (btif_hl_cb.acb[i].in_use) {
+ no_active_app = false;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s no_active_app=%d ", __func__, no_active_app);
+ return no_active_app;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_free_app_idx
+ *
+ * Description free an application control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_free_app_idx(uint8_t app_idx) {
+ if ((app_idx < BTA_HL_NUM_APPS) && btif_hl_cb.acb[app_idx].in_use) {
+ btif_hl_cb.acb[app_idx].in_use = false;
+ for (size_t i = 0; i < BTA_HL_NUM_MCLS; i++)
+ alarm_free(btif_hl_cb.acb[app_idx].mcb[i].cch_timer);
+ memset(&btif_hl_cb.acb[app_idx], 0, sizeof(btif_hl_app_cb_t));
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_set_state
+ *
+ * Description set HL state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_set_state(btif_hl_state_t state) {
+ BTIF_TRACE_DEBUG("btif_hl_set_state: %d ---> %d ", p_btif_hl_cb->state,
+ state);
+ p_btif_hl_cb->state = state;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_set_state
+ *
+ * Description get HL state
+ *
+ * Returns btif_hl_state_t
+ *
+ ******************************************************************************/
+
+static btif_hl_state_t btif_hl_get_state(void) {
+ BTIF_TRACE_DEBUG("btif_hl_get_state: %d ", p_btif_hl_cb->state);
+ return p_btif_hl_cb->state;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_data_type_idx
+ *
+ * Description Find the index in the data type table
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_data_type_idx(uint16_t data_type, uint8_t* p_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTIF_HL_DATA_TABLE_SIZE; i++) {
+ if (data_type_table[i].data_type == data_type) {
+ found = true;
+ *p_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d, data_type=0x%x idx=%d", __func__, found,
+ data_type, i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_get_max_tx_apdu_size
+ *
+ * Description Find the maximum TX APDU size for the specified data type and
+ * MDEP role
+ *
+ * Returns uint16_t
+ *
+ ******************************************************************************/
+uint16_t btif_hl_get_max_tx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+ uint16_t data_type) {
+ uint8_t idx;
+ uint16_t max_tx_apdu_size = 0;
+
+ if (btif_hl_find_data_type_idx(data_type, &idx)) {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+ max_tx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+ } else {
+ max_tx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+ }
+ } else {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+ max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+ } else {
+ max_tx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d", __func__,
+ mdep_role, data_type, max_tx_apdu_size);
+ return max_tx_apdu_size;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_get_max_rx_apdu_size
+ *
+ * Description Find the maximum RX APDU size for the specified data type and
+ * MDEP role
+ *
+ * Returns uint16_t
+ *
+ ******************************************************************************/
+uint16_t btif_hl_get_max_rx_apdu_size(tBTA_HL_MDEP_ROLE mdep_role,
+ uint16_t data_type) {
+ uint8_t idx;
+ uint16_t max_rx_apdu_size = 0;
+
+ if (btif_hl_find_data_type_idx(data_type, &idx)) {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+ max_rx_apdu_size = data_type_table[idx].max_rx_apdu_size;
+ } else {
+ max_rx_apdu_size = data_type_table[idx].max_tx_apdu_size;
+ }
+ } else {
+ if (mdep_role == BTA_HL_MDEP_ROLE_SOURCE) {
+ max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_RX_APDU_SIZE;
+ } else {
+ max_rx_apdu_size = BTIF_HL_DEFAULT_SRC_TX_APDU_SIZE;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s mdep_role=%d data_type=0x%4x size=%d", __func__,
+ mdep_role, data_type, max_rx_apdu_size);
+
+ return max_rx_apdu_size;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_if_channel_setup_pending
+ *
+ * Description
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+
+static bool btif_hl_get_bta_mdep_role(bthl_mdep_role_t mdep,
+ tBTA_HL_MDEP_ROLE* p) {
+ bool status = true;
+ switch (mdep) {
+ case BTHL_MDEP_ROLE_SOURCE:
+ *p = BTA_HL_MDEP_ROLE_SOURCE;
+ break;
+ case BTHL_MDEP_ROLE_SINK:
+ *p = BTA_HL_MDEP_ROLE_SINK;
+ break;
+ default:
+ *p = BTA_HL_MDEP_ROLE_SOURCE;
+ status = false;
+ break;
+ }
+
+ BTIF_TRACE_DEBUG("%s status=%d bta_mdep_role=%d (%d:btif)", __func__, status,
+ *p, mdep);
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_bta_channel_type
+ *
+ * Description convert bthl channel type to BTA DCH channel type
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+
+static bool btif_hl_get_bta_channel_type(bthl_channel_type_t channel_type,
+ tBTA_HL_DCH_CFG* p) {
+ bool status = true;
+ switch (channel_type) {
+ case BTHL_CHANNEL_TYPE_RELIABLE:
+ *p = BTA_HL_DCH_CFG_RELIABLE;
+ break;
+ case BTHL_CHANNEL_TYPE_STREAMING:
+ *p = BTA_HL_DCH_CFG_STREAMING;
+ break;
+ case BTHL_CHANNEL_TYPE_ANY:
+ *p = BTA_HL_DCH_CFG_NO_PREF;
+ break;
+ default:
+ status = false;
+ break;
+ }
+ BTIF_TRACE_DEBUG("%s status = %d BTA DCH CFG=%d (1-rel 2-strm", __func__,
+ status, *p);
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_next_app_id
+ *
+ * Description get next applcation id
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+
+static uint8_t btif_hl_get_next_app_id() {
+ uint8_t next_app_id = btif_hl_cb.next_app_id;
+
+ btif_hl_cb.next_app_id++;
+ return next_app_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_next_channel_id
+ *
+ * Description get next channel id
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static int btif_hl_get_next_channel_id(uint8_t app_id) {
+ uint16_t next_channel_id = btif_hl_cb.next_channel_id;
+ int channel_id;
+ btif_hl_cb.next_channel_id++;
+ channel_id = (app_id << 16) + next_channel_id;
+ BTIF_TRACE_DEBUG("%s channel_id=0x%08x, app_id=0x%02x next_channel_id=0x%04x",
+ __func__, channel_id, app_id, next_channel_id);
+ return channel_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_app_id
+ *
+ * Description get the applicaiton id associated with the channel id
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+
+static uint8_t btif_hl_get_app_id(int channel_id) {
+ uint8_t app_id = (uint8_t)(channel_id >> 16);
+ BTIF_TRACE_DEBUG("%s channel_id=0x%08x, app_id=0x%02x ", __func__, channel_id,
+ app_id);
+ return app_id;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_init_next_app_id
+ *
+ * Description initialize the application id
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_init_next_app_id(void) { btif_hl_cb.next_app_id = 1; }
+/*******************************************************************************
+ *
+ * Function btif_hl_init_next_channel_id
+ *
+ * Description initialize the channel id
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_init_next_channel_id(void) {
+ btif_hl_cb.next_channel_id = 1;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_app_idx_using_handle
+ *
+ * Description Find the applicaiton index using handle
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_handle(tBTA_HL_APP_HANDLE app_handle,
+ uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (btif_hl_cb.acb[i].in_use &&
+ (btif_hl_cb.acb[i].app_handle == app_handle)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_EVENT("%s status=%d handle=%d app_idx=%d ", __func__, found,
+ app_handle, i);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_app_idx_using_app_id
+ *
+ * Description Find the applicaiton index using app_id
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_app_id(uint8_t app_id, uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ *p_app_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (btif_hl_cb.acb[i].in_use && (btif_hl_cb.acb[i].app_id == app_id)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_EVENT("%s found=%d app_id=%d app_idx=%d ", __func__, found, app_id,
+ i);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mcl_idx_using_handle
+ *
+ * Description Find the MCL index using handle
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_handle(tBTA_HL_MCL_HANDLE mcl_handle,
+ uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ bool found = false;
+ uint8_t i, j;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use)
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_handle:app_idx=%d,"
+ "mcl_idx =%d mcl_handle=%d",
+ i, j, p_acb->mcb[j].mcl_handle);
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d", __func__, found, i, j);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mdl_idx_using_mdl_id
+ *
+ * Description Find the mdl index using mdl_id
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_mdl_id(uint8_t mdl_id, uint8_t mcl_handle,
+ uint8_t* p_app_idx, uint8_t* p_mcl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ bool found = false;
+ uint8_t i, j, x;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ p_mcb = &p_acb->mcb[j];
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_mdl_id: mcl handle found j =%d", j);
+ for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+ if (p_mcb->mdl[x].in_use && p_mcb->mdl[x].mdl_id == mdl_id) {
+ BTIF_TRACE_DEBUG("btif_hl_find_mcl_idx_using_mdl_id:found x =%d",
+ x);
+ found = true;
+ *p_app_idx = i;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d mcl_idx=%d", __func__, found, i, j);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mcl_idx_using_deleted_mdl_id
+ *
+ * Description Find the app index deleted_mdl_id
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_deleted_mdl_id(uint8_t mdl_id,
+ uint8_t* p_app_idx) {
+ btif_hl_app_cb_t* p_acb;
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb->delete_mdl.active) {
+ BTIF_TRACE_DEBUG("%s: app_idx=%d, mdl_id=%d", __func__, i, mdl_id);
+ }
+ if (p_acb->delete_mdl.active && (p_acb->delete_mdl.mdl_id == mdl_id)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_stop_timer_using_handle
+ *
+ * Description clean control channel cb using handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_stop_timer_using_handle(tBTA_HL_MCL_HANDLE mcl_handle) {
+ btif_hl_app_cb_t* p_acb;
+ uint8_t i, j;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ btif_hl_stop_cch_timer(i, j);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_mcl_idx_using_app_idx
+ *
+ * Description Find the MCL index using handle
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_mcl_idx_using_app_idx(tBTA_HL_MCL_HANDLE mcl_handle,
+ uint8_t p_app_idx, uint8_t* p_mcl_idx) {
+ btif_hl_app_cb_t* p_acb;
+ bool found = false;
+ uint8_t j;
+
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_app_idx);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ found = true;
+ *p_mcl_idx = j;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%dmcl_idx=%d", __func__, found, j);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_clean_mdls_using_app_idx
+ *
+ * Description clean dch cpntrol bloack using app_idx
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_clean_mdls_using_app_idx(uint8_t app_idx) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_mdl_cb_t* p_dcb;
+ uint8_t j, x, y;
+ bt_bdaddr_t bd_addr;
+
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use) {
+ p_mcb = &p_acb->mcb[j];
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_mdl_id: mcl handle found j =%d", j);
+ for (x = 0; x < BTA_HL_NUM_MDLS_PER_MCL; x++) {
+ if (p_mcb->mdl[x].in_use) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, j, x);
+ btif_hl_release_socket(app_idx, j, x);
+ for (y = 0; y < 6; y++) {
+ bd_addr.address[y] = p_mcb->bd_addr[y];
+ }
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, p_acb->app_id,
+ &bd_addr, p_dcb->local_mdep_cfg_idx,
+ p_dcb->channel_id, BTHL_CONN_STATE_DISCONNECTED,
+ 0);
+ btif_hl_clean_mdl_cb(p_dcb);
+ if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+ BTA_HlCchClose(p_mcb->mcl_handle);
+ BTIF_TRACE_DEBUG("remote DCH close success mdl_idx=%d", x);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_app_idx
+ *
+ * Description Find the application index using application ID
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx(uint8_t app_id, uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (btif_hl_cb.acb[i].in_use && (btif_hl_cb.acb[i].app_id == app_id)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_app_idx
+ *
+ * Description Find the application index using application ID
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_app_idx_using_mdepId(uint8_t mdep_id, uint8_t* p_app_idx) {
+ bool found = false;
+ uint8_t i;
+
+ *p_app_idx = 0;
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ BTIF_TRACE_DEBUG("btif_hl_find_app_idx_using_mdepId: MDEP-ID = %d",
+ btif_hl_cb.acb[i].sup_feature.mdep[0].mdep_id);
+ if (btif_hl_cb.acb[i].in_use &&
+ (btif_hl_cb.acb[i].sup_feature.mdep[0].mdep_id == mdep_id)) {
+ found = true;
+ *p_app_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_avail_mdl_idx
+ *
+ * Description Find a not in-use MDL index
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_avail_mdl_idx(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t* p_mdl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ if (!p_mcb->mdl[i].in_use) {
+ btif_hl_clean_mdl_cb(&p_mcb->mdl[i]);
+ found = true;
+ *p_mdl_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d idx=%d", __func__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_avail_mcl_idx
+ *
+ * Description Find a not in-use MDL index
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_find_avail_mcl_idx(uint8_t app_idx, uint8_t* p_mcl_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_MCLS; i++) {
+ if (!btif_hl_cb.acb[app_idx].mcb[i].in_use) {
+ found = true;
+ *p_mcl_idx = i;
+ break;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s found=%d mcl_idx=%d", __func__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_find_avail_app_idx
+ *
+ * Description Find a not in-use APP index
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btif_hl_find_avail_app_idx(uint8_t* p_idx) {
+ bool found = false;
+ uint8_t i;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (!btif_hl_cb.acb[i].in_use) {
+ found = true;
+ *p_idx = i;
+ break;
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s found=%d app_idx=%d", __func__, found, i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dereg_cfm
+ *
+ * Description Process the de-registration confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dereg_cfm(tBTA_HL* p_data)
+
+{
+ btif_hl_app_cb_t* p_acb;
+ uint8_t app_idx;
+ int app_id = 0;
+ bthl_app_reg_state_t state = BTHL_APP_REG_STATE_DEREG_SUCCESS;
+
+ BTIF_TRACE_DEBUG("%s de-reg status=%d app_handle=%d", __func__,
+ p_data->dereg_cfm.status, p_data->dereg_cfm.app_handle);
+
+ if (btif_hl_find_app_idx_using_app_id(p_data->dereg_cfm.app_id, &app_idx)
+ /**M: Bug fix for hdp can not find app id @{*/
+ ||btif_hl_find_app_idx_using_app_id(p_data->dereg_cfm.app_handle, &app_idx))
+ /**@}*/
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ app_id = (int)p_acb->app_id;
+ if (p_data->dereg_cfm.status == BTA_HL_STATUS_OK) {
+ btif_hl_clean_mdls_using_app_idx(app_idx);
+ for (size_t i = 0; i < BTA_HL_NUM_MCLS; i++)
+ alarm_free(p_acb->mcb[i].cch_timer);
+ memset(p_acb, 0, sizeof(btif_hl_app_cb_t));
+ } else
+ state = BTHL_APP_REG_STATE_DEREG_FAILED;
+
+ BTIF_TRACE_DEBUG("call reg state callback app_id=%d state=%d", app_id,
+ state);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb, app_id, state);
+
+ if (btif_hl_is_no_active_app()) {
+ btif_hl_disable();
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_reg_cfm
+ *
+ * Description Process the registration confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_reg_cfm(tBTA_HL* p_data) {
+ btif_hl_app_cb_t* p_acb;
+ uint8_t app_idx;
+ bthl_app_reg_state_t state = BTHL_APP_REG_STATE_REG_SUCCESS;
+
+ BTIF_TRACE_DEBUG("%s reg status=%d app_handle=%d", __func__,
+ p_data->reg_cfm.status, p_data->reg_cfm.app_handle);
+
+ if (btif_hl_find_app_idx(p_data->reg_cfm.app_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (p_data->reg_cfm.status == BTA_HL_STATUS_OK) {
+ p_acb->app_handle = p_data->reg_cfm.app_handle;
+ } else {
+ btif_hl_free_app_idx(app_idx);
+ state = BTHL_APP_REG_STATE_REG_FAILED;
+ }
+
+ BTIF_TRACE_DEBUG("%s call reg state callback app_id=%d reg state=%d",
+ __func__, p_data->reg_cfm.app_id, state);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, app_reg_state_cb,
+ ((int)p_data->reg_cfm.app_id), state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_set_chan_cb_state
+ *
+ * Description set the channel callback state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_set_chan_cb_state(uint8_t app_idx, uint8_t mcl_idx,
+ btif_hl_chan_cb_state_t state) {
+ btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ btif_hl_chan_cb_state_t cur_state = p_pcb->cb_state;
+
+ if (cur_state != state) {
+ p_pcb->cb_state = state;
+ BTIF_TRACE_DEBUG("%s state %d--->%d", __func__, cur_state, state);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_destroyed_cb
+ *
+ * Description send the channel destroyed callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_destroyed_cb(btif_hl_app_cb_t* p_acb) {
+ bt_bdaddr_t bd_addr;
+ int app_id = (int)btif_hl_get_app_id(p_acb->delete_mdl.channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_acb->delete_mdl.bd_addr);
+ BTIF_TRACE_DEBUG("%s", __func__);
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d, state=%d "
+ "fd=%d",
+ p_acb->delete_mdl.channel_id, p_acb->delete_mdl.mdep_cfg_idx,
+ BTHL_CONN_STATE_DESTROYED, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_acb->delete_mdl.mdep_cfg_idx,
+ p_acb->delete_mdl.channel_id, BTHL_CONN_STATE_DESTROYED,
+ 0);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_disconnecting_cb
+ *
+ * Description send a channel disconnecting callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_disconnecting_cb(uint8_t app_idx, uint8_t mcl_idx,
+ uint8_t mdl_idx) {
+ btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_soc_cb_t* p_scb = p_dcb->p_scb;
+ bt_bdaddr_t bd_addr;
+ int app_id = (int)btif_hl_get_app_id(p_scb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_scb->bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d, "
+ "state=%d fd=%d",
+ p_scb->channel_id, p_scb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTING,
+ p_scb->socket_id[0]);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_scb->mdep_cfg_idx, p_scb->channel_id,
+ BTHL_CONN_STATE_DISCONNECTING, p_scb->socket_id[0]);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_setup_connecting_cb
+ *
+ * Description send a channel connecting callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_setup_connecting_cb(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ bt_bdaddr_t bd_addr;
+ int app_id = (int)btif_hl_get_app_id(p_pcb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+ if (p_pcb->in_use &&
+ p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d "
+ "state=%d fd=%d",
+ p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING, 0);
+ btif_hl_display_bt_bda(&bd_addr);
+
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+ BTHL_CONN_STATE_CONNECTING, 0);
+ btif_hl_set_chan_cb_state(app_idx, mcl_idx,
+ BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_send_setup_disconnected_cb
+ *
+ * Description send a channel disconnected callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_send_setup_disconnected_cb(uint8_t app_idx, uint8_t mcl_idx) {
+ btif_hl_pending_chan_cb_t* p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ bt_bdaddr_t bd_addr;
+ int app_id = (int)btif_hl_get_app_id(p_pcb->channel_id);
+
+ btif_hl_copy_bda(&bd_addr, p_pcb->bd_addr);
+
+ BTIF_TRACE_DEBUG("%s p_pcb->in_use=%d", __func__, p_pcb->in_use);
+ if (p_pcb->in_use) {
+ BTIF_TRACE_DEBUG("%p_pcb->cb_state=%d", p_pcb->cb_state);
+ if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTING_PENDING) {
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d "
+ "state=%d fd=%d",
+ p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_CONNECTING,
+ 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+ BTHL_CONN_STATE_CONNECTING, 0);
+
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d "
+ "state=%d fd=%d",
+ p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED,
+ 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+ BTHL_CONN_STATE_DISCONNECTED, 0);
+ } else if (p_pcb->cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING) {
+ BTIF_TRACE_DEBUG(
+ "call channel state callback channel_id=0x%08x mdep_cfg_idx=%d "
+ "state=%d fd=%d",
+ p_pcb->channel_id, p_pcb->mdep_cfg_idx, BTHL_CONN_STATE_DISCONNECTED,
+ 0);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(bt_hl_callbacks, channel_state_cb, app_id, &bd_addr,
+ p_pcb->mdep_cfg_idx, p_pcb->channel_id,
+ BTHL_CONN_STATE_DISCONNECTED, 0);
+ }
+ btif_hl_clean_pcb(p_pcb);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_sdp_query_cfm
+ *
+ * Description Process the SDP query confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_sdp_query_cfm(tBTA_HL* p_data) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ tBTA_HL_SDP* p_sdp;
+ tBTA_HL_CCH_OPEN_PARAM open_param;
+ uint8_t app_idx, mcl_idx, sdp_idx = 0;
+ uint8_t num_recs, i, num_mdeps, j;
+ btif_hl_cch_op_t old_cch_oper;
+ bool status = false;
+ btif_hl_pending_chan_cb_t* p_pcb;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ /**M: Bug fix for HDP issue fail to get the sdp record @{ */
+ /*p_sdp = p_data->sdp_query_cfm.p_sdp;
+ num_recs = p_sdp->num_recs;*/
+ p_sdp = &g_bta_sdp;
+ num_recs = p_sdp->num_recs;
+ BTIF_TRACE_DEBUG("num of SDP records=%d, ctrl_psm=0x%x)",p_sdp->num_recs,p_sdp->sdp_rec[0].ctrl_psm);
+ /**@}*/
+
+ BTIF_TRACE_DEBUG("num of SDP records=%d", num_recs);
+ for (i = 0; i < num_recs; i++) {
+ BTIF_TRACE_DEBUG("rec_idx=%d ctrl_psm=0x%x data_psm=0x%x", (i + 1),
+ p_sdp->sdp_rec[i].ctrl_psm, p_sdp->sdp_rec[i].data_psm);
+ BTIF_TRACE_DEBUG("MCAP supported procedures=0x%x",
+ p_sdp->sdp_rec[i].mcap_sup_proc);
+ num_mdeps = p_sdp->sdp_rec[i].num_mdeps;
+ BTIF_TRACE_DEBUG("num of mdeps =%d", num_mdeps);
+ for (j = 0; j < num_mdeps; j++) {
+ BTIF_TRACE_DEBUG("mdep_idx=%d mdep_id=0x%x data_type=0x%x mdep_role=0x%x",
+ (j + 1), p_sdp->sdp_rec[i].mdep_cfg[j].mdep_id,
+ p_sdp->sdp_rec[i].mdep_cfg[j].data_type,
+ p_sdp->sdp_rec[i].mdep_cfg[j].mdep_role);
+ }
+ }
+
+ if (btif_hl_find_app_idx_using_app_id(p_data->sdp_query_cfm.app_id,
+ &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+
+ if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr,
+ &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->cch_oper != BTIF_HL_CCH_OP_NONE) {
+ memcpy(&p_mcb->sdp, p_sdp, sizeof(tBTA_HL_SDP));
+ old_cch_oper = p_mcb->cch_oper;
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_NONE;
+
+ switch (old_cch_oper) {
+ case BTIF_HL_CCH_OP_MDEP_FILTERING:
+ status = btif_hl_find_sdp_idx_using_mdep_filter(app_idx, mcl_idx,
+ &sdp_idx);
+ break;
+ default:
+ break;
+ }
+
+ if (status) {
+ p_mcb->sdp_idx = sdp_idx;
+ p_mcb->valid_sdp_idx = true;
+ p_mcb->ctrl_psm = p_mcb->sdp.sdp_rec[sdp_idx].ctrl_psm;
+
+ switch (old_cch_oper) {
+ case BTIF_HL_CCH_OP_MDEP_FILTERING:
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (p_pcb->in_use) {
+ if (!p_pcb->abort_pending) {
+ switch (p_pcb->op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ open_param.ctrl_psm = p_mcb->ctrl_psm;
+ bdcpy(open_param.bd_addr, p_mcb->bd_addr);
+ open_param.sec_mask =
+ (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTA_HlCchOpen(p_acb->app_id, p_acb->app_handle, &open_param);
+ } else {
+ BTIF_TRACE_DEBUG("channel abort pending");
+ }
+ }
+ break;
+
+ case BTIF_HL_CCH_OP_DCH_OPEN:
+ status = btif_hl_proc_pending_op(app_idx, mcl_idx);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("Invalid CCH oper %d", old_cch_oper);
+ break;
+ }
+ } else {
+ BTIF_TRACE_ERROR("Can not find SDP idx discard CCH Open request");
+ }
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_cch_open_ind
+ *
+ * Description Process the CCH open indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_open_ind(tBTA_HL* p_data)
+
+{
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t mcl_idx;
+ int i;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ if (btif_hl_cb.acb[i].in_use) {
+ if (!btif_hl_find_mcl_idx(i, p_data->cch_open_ind.bd_addr, &mcl_idx)) {
+ if (btif_hl_find_avail_mcl_idx(i, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(i, mcl_idx);
+ alarm_free(p_mcb->cch_timer);
+ memset(p_mcb, 0, sizeof(btif_hl_mcl_cb_t));
+ p_mcb->in_use = true;
+ p_mcb->is_connected = true;
+ p_mcb->mcl_handle = p_data->cch_open_ind.mcl_handle;
+ bdcpy(p_mcb->bd_addr, p_data->cch_open_ind.bd_addr);
+ btif_hl_start_cch_timer(i, mcl_idx);
+ }
+ } else {
+ BTIF_TRACE_ERROR("The MCL already exist for cch_open_ind");
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_pending_op
+ *
+ * Description Process the pending dch operation.
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+bool btif_hl_proc_pending_op(uint8_t app_idx, uint8_t mcl_idx)
+
+{
+ btif_hl_app_cb_t* p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ btif_hl_pending_chan_cb_t* p_pcb;
+ bool status = false;
+ tBTA_HL_DCH_OPEN_PARAM dch_open;
+ tBTA_HL_MDL_ID mdl_id;
+ tBTA_HL_DCH_RECONNECT_PARAM reconnect_param;
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ if (p_pcb->in_use) {
+ switch (p_pcb->op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ if (!p_pcb->abort_pending) {
+ BTIF_TRACE_DEBUG("op BTIF_HL_PEND_DCH_OP_OPEN");
+ dch_open.ctrl_psm = p_mcb->ctrl_psm;
+ dch_open.local_mdep_id =
+ p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx].mdep_id;
+ if (btif_hl_find_peer_mdep_id(
+ p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+ .mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+ .mdep_cfg.data_cfg[0]
+ .data_type,
+ &dch_open.peer_mdep_id)) {
+ dch_open.local_cfg = p_acb->channel_type[p_pcb->mdep_cfg_idx];
+ if ((p_acb->sup_feature.mdep[p_pcb->mdep_cfg_idx]
+ .mdep_cfg.mdep_role == BTA_HL_MDEP_ROLE_SOURCE) &&
+ !btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+ dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+ BTIF_TRACE_DEBUG("dch_open.local_cfg=%d ", dch_open.local_cfg);
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+
+ if (!btif_hl_is_reconnect_possible(app_idx, mcl_idx,
+ p_pcb->mdep_cfg_idx, &dch_open,
+ &mdl_id)) {
+ BTIF_TRACE_DEBUG("Issue DCH open, mcl_handle=%d",
+ p_mcb->mcl_handle);
+ BTA_HlDchOpen(p_mcb->mcl_handle, &dch_open);
+ } else {
+ reconnect_param.ctrl_psm = p_mcb->ctrl_psm;
+ reconnect_param.mdl_id = mdl_id;
+ ;
+ BTIF_TRACE_DEBUG("Issue Reconnect ctrl_psm=0x%x mdl_id=0x%x",
+ reconnect_param.ctrl_psm,
+ reconnect_param.mdl_id);
+ BTA_HlDchReconnect(p_mcb->mcl_handle, &reconnect_param);
+ }
+ status = true;
+ }
+ } else {
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ status = true;
+ }
+ break;
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+ status = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_cch_open_cfm
+ *
+ * Description Process the CCH open confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_cch_open_cfm(tBTA_HL* p_data)
+
+{
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t app_idx, mcl_idx;
+ bool status = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (btif_hl_find_app_idx_using_app_id(p_data->cch_open_cfm.app_id,
+ &app_idx)) {
+ BTIF_TRACE_DEBUG("app_idx=%d", app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG("mcl_idx=%d, mcl_handle=%d", mcl_idx,
+ p_data->cch_open_cfm.mcl_handle);
+ p_mcb->mcl_handle = p_data->cch_open_cfm.mcl_handle;
+ p_mcb->is_connected = true;
+ status = btif_hl_proc_pending_op(app_idx, mcl_idx);
+ if (status) btif_hl_start_cch_timer(app_idx, mcl_idx);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_clean_mcb_using_handle
+ *
+ * Description clean control channel cb using handle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_clean_mcb_using_handle(tBTA_HL_MCL_HANDLE mcl_handle) {
+ btif_hl_app_cb_t* p_acb;
+ uint8_t i, j;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use)
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_handle: app_idx=%d,"
+ "mcl_idx =%d mcl_handle=%d",
+ i, j, p_acb->mcb[j].mcl_handle);
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ btif_hl_stop_cch_timer(i, j);
+ btif_hl_release_mcl_sockets(i, j);
+ btif_hl_send_setup_disconnected_cb(i, j);
+ btif_hl_clean_mcl_cb(i, j);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_cch_close_ind
+ *
+ * Description Process the CCH close indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_close_ind(tBTA_HL* p_data)
+
+{
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ btif_hl_clean_mcb_using_handle(p_data->cch_close_ind.mcl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_cch_close_cfm
+ *
+ * Description Process the CCH close confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cch_close_cfm(tBTA_HL* p_data) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ btif_hl_clean_mcb_using_handle(p_data->cch_close_ind.mcl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_create_ind
+ *
+ * Description Process the MDL create indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_create_ind(tBTA_HL* p_data) {
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ tBTA_HL_MDEP* p_mdep;
+ uint8_t orig_app_idx, mcl_idx, mdep_cfg_idx;
+ bool first_reliable_exist;
+ bool success = true;
+ tBTA_HL_DCH_CFG rsp_cfg = BTA_HL_DCH_CFG_UNKNOWN;
+ tBTA_HL_DCH_CREATE_RSP rsp_code = BTA_HL_DCH_CREATE_RSP_CFG_REJ;
+ tBTA_HL_DCH_CREATE_RSP_PARAM create_rsp_param;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ // Find the correct app_idx based on the mdep_id;
+ btif_hl_find_app_idx_using_mdepId(p_data->dch_create_ind.local_mdep_id,
+ &orig_app_idx);
+ if (btif_hl_find_mcl_idx(orig_app_idx, p_data->dch_create_ind.bd_addr,
+ &mcl_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(orig_app_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(orig_app_idx, mcl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(orig_app_idx,
+ p_data->dch_create_ind.local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_mdep = &(p_acb->sup_feature.mdep[mdep_cfg_idx]);
+ first_reliable_exist =
+ btif_hl_is_the_first_reliable_existed(orig_app_idx, mcl_idx);
+ switch (p_mdep->mdep_cfg.mdep_role) {
+ case BTA_HL_MDEP_ROLE_SOURCE:
+ if (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_NO_PREF) {
+ if (first_reliable_exist) {
+ rsp_cfg = p_acb->channel_type[mdep_cfg_idx];
+ } else {
+ rsp_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+ }
+
+ break;
+ case BTA_HL_MDEP_ROLE_SINK:
+
+ BTIF_TRACE_DEBUG("btif_hl_proc_create_ind:BTA_HL_MDEP_ROLE_SINK");
+ if ((p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_RELIABLE) ||
+ (first_reliable_exist &&
+ (p_data->dch_create_ind.cfg == BTA_HL_DCH_CFG_STREAMING))) {
+ rsp_code = BTA_HL_DCH_CREATE_RSP_SUCCESS;
+ rsp_cfg = p_data->dch_create_ind.cfg;
+ BTIF_TRACE_DEBUG(
+ "btif_hl_proc_create_ind:BTA_HL_MDEP_ROLE_SINK cfg = %d",
+ rsp_cfg);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ success = false;
+ }
+
+ if (success) {
+ BTIF_TRACE_DEBUG("create response rsp_code=%d rsp_cfg=%d", rsp_code,
+ rsp_cfg);
+ create_rsp_param.local_mdep_id = p_data->dch_create_ind.local_mdep_id;
+ create_rsp_param.mdl_id = p_data->dch_create_ind.mdl_id;
+ create_rsp_param.rsp_code = rsp_code;
+ create_rsp_param.cfg_rsp = rsp_cfg;
+ BTA_HlDchCreateRsp(p_mcb->mcl_handle, &create_rsp_param);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_open_ind
+ *
+ * Description Process the DCH open indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_open_ind(tBTA_HL* p_data)
+
+{
+ btif_hl_mdl_cb_t* p_dcb;
+ uint8_t orig_app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ bool close_dch = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ // Find the correct app_idx based on the mdep_id;
+ btif_hl_find_app_idx_using_mdepId(p_data->dch_open_ind.local_mdep_id,
+ &orig_app_idx);
+
+ if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_ind.mcl_handle,
+ orig_app_idx, &mcl_idx)) {
+ if (btif_hl_find_avail_mdl_idx(orig_app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(orig_app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(orig_app_idx,
+ p_data->dch_open_ind.local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_dcb->in_use = true;
+ p_dcb->mdl_handle = p_data->dch_open_ind.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_open_ind.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_open_ind.mdl_id;
+ p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+ p_dcb->dch_mode = p_data->dch_open_ind.dch_mode;
+ p_dcb->is_the_first_reliable = p_data->dch_open_ind.first_reliable;
+ p_dcb->mtu = p_data->dch_open_ind.mtu;
+
+ if (btif_hl_find_channel_id_using_mdl_id(orig_app_idx, p_dcb->mdl_id,
+ &p_dcb->channel_id)) {
+ BTIF_TRACE_DEBUG(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+ orig_app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ if (!btif_hl_create_socket(orig_app_idx, mcl_idx, mdl_idx)) {
+ BTIF_TRACE_ERROR("Unable to create socket");
+ close_dch = true;
+ }
+ } else {
+ BTIF_TRACE_ERROR("Unable find channel id for mdl_id=0x%x",
+ p_dcb->mdl_id);
+ close_dch = true;
+ }
+ } else {
+ BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+ p_data->dch_open_cfm.local_mdep_id);
+ close_dch = true;
+ }
+
+ if (close_dch) btif_hl_clean_mdl_cb(p_dcb);
+ } else
+ close_dch = true;
+ } else
+ close_dch = true;
+
+ if (close_dch) BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_open_cfm
+ *
+ * Description Process the DCH close confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_dch_open_cfm(tBTA_HL* p_data)
+
+{
+ btif_hl_mdl_cb_t* p_dcb;
+ btif_hl_pending_chan_cb_t* p_pcb;
+ uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ bool status = false;
+ bool close_dch = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ // Find the correct app_idx based on the mdep_id;
+ btif_hl_find_app_idx_using_mdepId(p_data->dch_open_cfm.local_mdep_id,
+ &app_idx);
+
+ if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_open_cfm.mcl_handle,
+ app_idx, &mcl_idx)) {
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx, p_data->dch_open_cfm.local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_dcb->in_use = true;
+ p_dcb->mdl_handle = p_data->dch_open_cfm.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_open_cfm.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_open_cfm.mdl_id;
+ p_dcb->dch_mode = p_data->dch_open_cfm.dch_mode;
+ p_dcb->is_the_first_reliable = p_data->dch_open_cfm.first_reliable;
+ p_dcb->mtu = p_data->dch_open_cfm.mtu;
+ p_dcb->channel_id = p_pcb->channel_id;
+
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+ mdl_idx);
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+ status = true;
+ BTIF_TRACE_DEBUG(
+ "app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ btif_hl_clean_pcb(p_pcb);
+ } else {
+ BTIF_TRACE_ERROR("Unable to create socket");
+ close_dch = true;
+ }
+ } else {
+ BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+ p_data->dch_open_cfm.local_mdep_id);
+ close_dch = true;
+ }
+
+ if (close_dch) {
+ btif_hl_clean_mdl_cb(p_dcb);
+ BTA_HlDchClose(p_data->dch_open_cfm.mdl_handle);
+ }
+ }
+ }
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_reconnect_cfm
+ *
+ * Description Process the DCH reconnect indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static bool btif_hl_proc_dch_reconnect_cfm(tBTA_HL* p_data) {
+ btif_hl_mdl_cb_t* p_dcb;
+ btif_hl_pending_chan_cb_t* p_pcb;
+ uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ bool status = false;
+ bool close_dch = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ btif_hl_find_app_idx_using_mdepId(p_data->dch_reconnect_cfm.local_mdep_id,
+ &app_idx);
+
+ if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_reconnect_cfm.mcl_handle,
+ app_idx, &mcl_idx)) {
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx,
+ p_data->dch_reconnect_cfm.local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_dcb->in_use = true;
+ p_dcb->mdl_handle = p_data->dch_reconnect_cfm.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_reconnect_cfm.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_reconnect_cfm.mdl_id;
+ p_dcb->dch_mode = p_data->dch_reconnect_cfm.dch_mode;
+ p_dcb->is_the_first_reliable = p_data->dch_reconnect_cfm.first_reliable;
+ p_dcb->mtu = p_data->dch_reconnect_cfm.mtu;
+ p_dcb->channel_id = p_pcb->channel_id;
+
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+ mdl_idx);
+ btif_hl_send_setup_connecting_cb(app_idx, mcl_idx);
+ if (btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+ status = true;
+ BTIF_TRACE_DEBUG(
+ "app_idx=%d mcl_idx=%d mdl_idx=%d p_dcb->channel_id=0x%08x",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ btif_hl_clean_pcb(p_pcb);
+ } else {
+ BTIF_TRACE_ERROR("Unable to create socket");
+ close_dch = true;
+ }
+ } else {
+ BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+ p_data->dch_open_cfm.local_mdep_id);
+ close_dch = true;
+ }
+
+ if (close_dch) {
+ btif_hl_clean_mdl_cb(p_dcb);
+ BTA_HlDchClose(p_data->dch_reconnect_cfm.mdl_handle);
+ }
+ }
+ }
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_reconnect_ind
+ *
+ * Description Process the DCH reconnect indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_reconnect_ind(tBTA_HL* p_data)
+
+{
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mdl_cb_t* p_dcb;
+ uint8_t app_idx, mcl_idx, mdl_idx, mdep_cfg_idx;
+ bool close_dch = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ // Find the correct app_idx based on the mdep_id;
+ btif_hl_find_app_idx_using_mdepId(p_data->dch_reconnect_ind.local_mdep_id,
+ &app_idx);
+
+ if (btif_hl_find_mcl_idx_using_app_idx(p_data->dch_reconnect_ind.mcl_handle,
+ app_idx, &mcl_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ BTIF_TRACE_DEBUG(
+ "btif_hl_proc_dch_reconnect_ind: app_idx = %d, mcl_idx = %d", app_idx,
+ mcl_idx);
+
+ if (btif_hl_find_avail_mdl_idx(app_idx, mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ if (btif_hl_find_mdep_cfg_idx(app_idx,
+ p_data->dch_reconnect_ind.local_mdep_id,
+ &mdep_cfg_idx)) {
+ p_dcb->in_use = true;
+ p_dcb->mdl_handle = p_data->dch_reconnect_ind.mdl_handle;
+ p_dcb->local_mdep_cfg_idx = mdep_cfg_idx;
+ p_dcb->local_mdep_id = p_data->dch_reconnect_ind.local_mdep_id;
+ p_dcb->mdl_id = p_data->dch_reconnect_ind.mdl_id;
+ p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+ p_dcb->dch_mode = p_data->dch_reconnect_ind.dch_mode;
+ p_dcb->is_the_first_reliable = p_data->dch_reconnect_ind.first_reliable;
+ p_dcb->mtu = p_data->dch_reconnect_ind.mtu;
+ p_dcb->channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+
+ BTIF_TRACE_DEBUG(" app_idx=%d mcl_idx=%d mdl_idx=%d channel_id=%d",
+ app_idx, mcl_idx, mdl_idx, p_dcb->channel_id);
+ if (!btif_hl_create_socket(app_idx, mcl_idx, mdl_idx)) {
+ BTIF_TRACE_ERROR("Unable to create socket");
+ close_dch = true;
+ }
+ } else {
+ BTIF_TRACE_ERROR("INVALID_LOCAL_MDEP_ID mdep_id=%d",
+ p_data->dch_open_cfm.local_mdep_id);
+ close_dch = true;
+ }
+
+ if (close_dch) btif_hl_clean_mdl_cb(p_dcb);
+ } else
+ close_dch = true;
+ } else
+ close_dch = true;
+
+ if (close_dch) BTA_HlDchClose(p_data->dch_reconnect_ind.mdl_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_close_ind
+ *
+ * Description Process the DCH close indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_close_ind(tBTA_HL* p_data)
+
+{
+ btif_hl_mdl_cb_t* p_dcb;
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_ind.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_release_socket(app_idx, mcl_idx, mdl_idx);
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ btif_hl_clean_mdl_cb(p_dcb);
+ if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG("remote DCH close success mdl_idx=%d", mdl_idx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_close_cfm
+ *
+ * Description Process the DCH reconnect confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_close_cfm(tBTA_HL* p_data)
+
+{
+ btif_hl_mdl_cb_t* p_dcb;
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_close_cfm.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ btif_hl_release_socket(app_idx, mcl_idx, mdl_idx);
+ btif_hl_clean_mdl_cb(p_dcb);
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (!btif_hl_num_dchs_in_use(p_mcb->mcl_handle))
+ btif_hl_start_cch_timer(app_idx, mcl_idx);
+ BTIF_TRACE_DEBUG(" local DCH close success mdl_idx=%d", mdl_idx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_abort_ind
+ *
+ * Description Process the abort indicaiton
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_abort_ind(tBTA_HL_MCL_HANDLE mcl_handle) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ btif_hl_app_cb_t* p_acb;
+ uint8_t i, j;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use)
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_handle: app_idx=%d,mcl_idx =%d "
+ "mcl_handle=%d",
+ i, j, p_acb->mcb[j].mcl_handle);
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ btif_hl_stop_cch_timer(i, j);
+ btif_hl_send_setup_disconnected_cb(i, j);
+ btif_hl_clean_mcl_cb(i, j);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_abort_cfm
+ *
+ * Description Process the abort confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_abort_cfm(tBTA_HL_MCL_HANDLE mcl_handle) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ btif_hl_app_cb_t* p_acb;
+ uint8_t i, j;
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ for (j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ if (p_acb->mcb[j].in_use)
+ BTIF_TRACE_DEBUG(
+ "btif_hl_find_mcl_idx_using_handle: app_idx=%d,mcl_idx =%d "
+ "mcl_handle=%d",
+ i, j, p_acb->mcb[j].mcl_handle);
+ if (p_acb->mcb[j].in_use && (p_acb->mcb[j].mcl_handle == mcl_handle)) {
+ btif_hl_stop_cch_timer(i, j);
+ btif_hl_send_setup_disconnected_cb(i, j);
+ btif_hl_clean_mcl_cb(i, j);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_send_data_cfm
+ *
+ * Description Process the send data confirmation
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_send_data_cfm(tBTA_HL_MDL_HANDLE mdl_handle,
+ UNUSED_ATTR tBTA_HL_STATUS status) {
+ uint8_t app_idx, mcl_idx, mdl_idx;
+ btif_hl_mdl_cb_t* p_dcb;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (btif_hl_find_mdl_idx_using_handle(mdl_handle, &app_idx, &mcl_idx,
+ &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+ BTIF_TRACE_DEBUG("send success free p_tx_pkt tx_size=%d", p_dcb->tx_size);
+ p_dcb->tx_size = 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_dch_cong_ind
+ *
+ * Description Process the DCH congestion change indication
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+static void btif_hl_proc_dch_cong_ind(tBTA_HL* p_data)
+
+{
+ btif_hl_mdl_cb_t* p_dcb;
+ uint8_t app_idx, mcl_idx, mdl_idx;
+
+ BTIF_TRACE_DEBUG("btif_hl_proc_dch_cong_ind");
+
+ if (btif_hl_find_mdl_idx_using_handle(p_data->dch_cong_ind.mdl_handle,
+ &app_idx, &mcl_idx, &mdl_idx)) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ p_dcb->cong = p_data->dch_cong_ind.cong;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_reg_request
+ *
+ * Description Process registration request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_proc_reg_request(uint8_t app_idx, uint8_t app_id,
+ tBTA_HL_REG_PARAM* p_reg_param,
+ UNUSED_ATTR tBTA_HL_CBACK* p_cback) {
+ BTIF_TRACE_DEBUG("%s app_idx=%d app_id=%d", __func__, app_idx, app_id);
+
+ if (reg_counter > 1) {
+ BTIF_TRACE_DEBUG("btif_hl_proc_reg_request: calling uPDATE");
+ BTA_HlUpdate(app_id, p_reg_param, true, btif_hl_cback);
+ } else
+ BTA_HlRegister(app_id, p_reg_param, btif_hl_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_proc_cb_evt
+ *
+ * Description Process HL callback events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_proc_cb_evt(uint16_t event, char* p_param) {
+ btif_hl_evt_cb_t* p_data = (btif_hl_evt_cb_t*)p_param;
+ bt_bdaddr_t bd_addr;
+ bthl_channel_state_t state = BTHL_CONN_STATE_DISCONNECTED;
+ bool send_chan_cb = true;
+ tBTA_HL_REG_PARAM reg_param;
+ btif_hl_app_cb_t* p_acb;
+
+ BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+ btif_hl_display_calling_process_name();
+
+ switch (event) {
+ case BTIF_HL_SEND_CONNECTED_CB:
+ case BTIF_HL_SEND_DISCONNECTED_CB:
+ if (p_data->chan_cb.cb_state == BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING)
+ state = BTHL_CONN_STATE_CONNECTED;
+ else if (p_data->chan_cb.cb_state ==
+ BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING)
+ state = BTHL_CONN_STATE_DISCONNECTED;
+ else
+ send_chan_cb = false;
+
+ if (send_chan_cb) {
+ btif_hl_copy_bda(&bd_addr, p_data->chan_cb.bd_addr);
+ BTIF_TRACE_DEBUG(
+ "state callbk: ch_id=0x%08x cb_state=%d state=%d fd=%d",
+ p_data->chan_cb.channel_id, p_data->chan_cb.cb_state, state,
+ p_data->chan_cb.fd);
+ btif_hl_display_bt_bda(&bd_addr);
+ BTIF_HL_CALL_CBACK(
+ bt_hl_callbacks, channel_state_cb, p_data->chan_cb.app_id, &bd_addr,
+ p_data->chan_cb.mdep_cfg_index, p_data->chan_cb.channel_id, state,
+ p_data->chan_cb.fd);
+ }
+
+ break;
+
+ case BTIF_HL_REG_APP:
+ reg_counter++;
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->reg.app_idx);
+ BTIF_TRACE_DEBUG("Rcv BTIF_HL_REG_APP app_idx=%d reg_pending=%d",
+ p_data->reg.app_idx, p_acb->reg_pending);
+ if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED && p_acb->reg_pending) {
+ BTIF_TRACE_DEBUG("Rcv BTIF_HL_REG_APP reg_counter=%d", reg_counter);
+ p_acb->reg_pending = false;
+ reg_param.dev_type = p_acb->dev_type;
+ reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+ reg_param.p_srv_name = p_acb->srv_name;
+ reg_param.p_srv_desp = p_acb->srv_desp;
+ reg_param.p_provider_name = p_acb->provider_name;
+ btif_hl_proc_reg_request(p_data->reg.app_idx, p_acb->app_id, &reg_param,
+ btif_hl_cback);
+ } else {
+ BTIF_TRACE_DEBUG("reg request is processed state=%d reg_pending=%d",
+ btif_hl_get_state(), p_acb->reg_pending);
+ }
+ break;
+
+ case BTIF_HL_UNREG_APP:
+ reg_counter--;
+ BTIF_TRACE_DEBUG("Rcv BTIF_HL_UNREG_APP app_idx=%d",
+ p_data->unreg.app_idx);
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->unreg.app_idx);
+ if (btif_hl_get_state() == BTIF_HL_STATE_ENABLED) {
+ if (reg_counter >= 1)
+ BTA_HlUpdate(p_acb->app_id, NULL, false, NULL);
+ else
+ BTA_HlDeregister(p_acb->app_id, p_acb->app_handle);
+ }
+ break;
+
+ case BTIF_HL_UPDATE_MDL:
+ BTIF_TRACE_DEBUG("Rcv BTIF_HL_UPDATE_MDL app_idx=%d",
+ p_data->update_mdl.app_idx);
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_data->update_mdl.app_idx);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("Unknown event %d", event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_upstreams_evt
+ *
+ * Description Process HL events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_upstreams_evt(uint16_t event, char* p_param) {
+ tBTA_HL* p_data = (tBTA_HL*)p_param;
+ uint8_t app_idx, mcl_idx;
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb = NULL;
+ btif_hl_pend_dch_op_t pending_op;
+ bool status;
+
+ BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+ btif_hl_display_calling_process_name();
+ switch (event) {
+ case BTA_HL_REGISTER_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_REGISTER_CFM_EVT");
+ BTIF_TRACE_DEBUG("app_id=%d app_handle=%d status=%d ",
+ p_data->reg_cfm.app_id, p_data->reg_cfm.app_handle,
+ p_data->reg_cfm.status);
+
+ btif_hl_proc_reg_cfm(p_data);
+ break;
+ case BTA_HL_SDP_INFO_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_SDP_INFO_IND_EVT");
+ BTIF_TRACE_DEBUG(
+ "app_handle=%d ctrl_psm=0x%04x data_psm=0x%04x x_spec=%d "
+ "mcap_sup_procs=0x%02x",
+ p_data->sdp_info_ind.app_handle, p_data->sdp_info_ind.ctrl_psm,
+ p_data->sdp_info_ind.data_psm, p_data->sdp_info_ind.data_x_spec,
+ p_data->sdp_info_ind.mcap_sup_procs);
+ // btif_hl_proc_sdp_info_ind(p_data);
+ break;
+
+ case BTA_HL_DEREGISTER_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DEREGISTER_CFM_EVT");
+ BTIF_TRACE_DEBUG("app_handle=%d status=%d ", p_data->dereg_cfm.app_handle,
+ p_data->dereg_cfm.status);
+ btif_hl_proc_dereg_cfm(p_data);
+ break;
+
+ case BTA_HL_SDP_QUERY_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_SDP_QUERY_CFM_EVT");
+ BTIF_TRACE_DEBUG("app_handle=%d app_id =%d,status =%d",
+ p_data->sdp_query_cfm.app_handle,
+ p_data->sdp_query_cfm.app_id,
+ p_data->sdp_query_cfm.status);
+
+ BTIF_TRACE_DEBUG(
+ "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->sdp_query_cfm.bd_addr[0], p_data->sdp_query_cfm.bd_addr[1],
+ p_data->sdp_query_cfm.bd_addr[2], p_data->sdp_query_cfm.bd_addr[3],
+ p_data->sdp_query_cfm.bd_addr[4], p_data->sdp_query_cfm.bd_addr[5]);
+
+ if (p_data->sdp_query_cfm.status == BTA_HL_STATUS_OK)
+ status = btif_hl_proc_sdp_query_cfm(p_data);
+ else
+ status = false;
+
+ if (!status) {
+ BTIF_TRACE_DEBUG("BTA_HL_SDP_QUERY_CFM_EVT Status = %d",
+ p_data->sdp_query_cfm.status);
+ if (btif_hl_find_app_idx_using_app_id(p_data->sdp_query_cfm.app_id,
+ &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->sdp_query_cfm.bd_addr,
+ &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if ((p_mcb->cch_oper == BTIF_HL_CCH_OP_MDEP_FILTERING) ||
+ (p_mcb->cch_oper == BTIF_HL_CCH_OP_DCH_OPEN)) {
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ if (!p_mcb->is_connected) btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+ }
+ }
+ }
+
+ break;
+
+ case BTA_HL_CCH_OPEN_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_CFM_EVT");
+ BTIF_TRACE_DEBUG(
+ "app_id=%d,app_handle=%d mcl_handle=%d status =%d",
+ p_data->cch_open_cfm.app_id, p_data->cch_open_cfm.app_handle,
+ p_data->cch_open_cfm.mcl_handle, p_data->cch_open_cfm.status);
+ BTIF_TRACE_DEBUG(
+ "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->cch_open_cfm.bd_addr[0], p_data->cch_open_cfm.bd_addr[1],
+ p_data->cch_open_cfm.bd_addr[2], p_data->cch_open_cfm.bd_addr[3],
+ p_data->cch_open_cfm.bd_addr[4], p_data->cch_open_cfm.bd_addr[5]);
+
+ if (p_data->cch_open_cfm.status == BTA_HL_STATUS_OK ||
+ p_data->cch_open_cfm.status == BTA_HL_STATUS_DUPLICATE_CCH_OPEN) {
+ status = btif_hl_proc_cch_open_cfm(p_data);
+ } else {
+ status = false;
+ }
+
+ if (!status) {
+ if (btif_hl_find_app_idx_using_app_id(p_data->cch_open_cfm.app_id,
+ &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, p_data->cch_open_cfm.bd_addr,
+ &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ btif_hl_clean_mcl_cb(app_idx, mcl_idx);
+ }
+ }
+ }
+ break;
+
+ case BTA_HL_DCH_OPEN_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_OPEN_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=0x%x status=%d ",
+ p_data->dch_open_cfm.mcl_handle,
+ p_data->dch_open_cfm.mdl_handle,
+ p_data->dch_open_cfm.status);
+ BTIF_TRACE_DEBUG(
+ "first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+ p_data->dch_open_cfm.first_reliable, p_data->dch_open_cfm.dch_mode,
+ p_data->dch_open_cfm.local_mdep_id, p_data->dch_open_cfm.mdl_id,
+ p_data->dch_open_cfm.mtu);
+ if (p_data->dch_open_cfm.status == BTA_HL_STATUS_OK) {
+ status = btif_hl_proc_dch_open_cfm(p_data);
+ } else {
+ status = false;
+ }
+
+ if (!status) {
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case BTA_HL_CCH_OPEN_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_OPEN_IND_EVT");
+ BTIF_TRACE_DEBUG("app_handle=%d mcl_handle=%d",
+ p_data->cch_open_ind.app_handle,
+ p_data->cch_open_ind.mcl_handle);
+ BTIF_TRACE_DEBUG(
+ "DB [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]",
+ p_data->cch_open_ind.bd_addr[0], p_data->cch_open_ind.bd_addr[1],
+ p_data->cch_open_ind.bd_addr[2], p_data->cch_open_ind.bd_addr[3],
+ p_data->cch_open_ind.bd_addr[4], p_data->cch_open_ind.bd_addr[5]);
+
+ btif_hl_proc_cch_open_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CREATE_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CREATE_IND_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d", p_data->dch_create_ind.mcl_handle);
+ BTIF_TRACE_DEBUG("local_mdep_id =%d mdl_id=%d cfg=%d",
+ p_data->dch_create_ind.local_mdep_id,
+ p_data->dch_create_ind.mdl_id,
+ p_data->dch_create_ind.cfg);
+ btif_hl_proc_create_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_OPEN_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_OPEN_IND_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=0x%x",
+ p_data->dch_open_ind.mcl_handle,
+ p_data->dch_open_ind.mdl_handle);
+ BTIF_TRACE_DEBUG(
+ "first_reliable =%d dch_mode=%d local_mdep_id=%d mdl_id=%d mtu=%d",
+ p_data->dch_open_ind.first_reliable, p_data->dch_open_ind.dch_mode,
+ p_data->dch_open_ind.local_mdep_id, p_data->dch_open_ind.mdl_id,
+ p_data->dch_open_ind.mtu);
+
+ btif_hl_proc_dch_open_ind(p_data);
+ break;
+
+ case BTA_HL_DELETE_MDL_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DELETE_MDL_IND_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_id=0x%x",
+ p_data->delete_mdl_ind.mcl_handle,
+ p_data->delete_mdl_ind.mdl_id);
+ break;
+
+ case BTA_HL_DELETE_MDL_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DELETE_MDL_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_id=0x%x status=%d",
+ p_data->delete_mdl_cfm.mcl_handle,
+ p_data->delete_mdl_cfm.mdl_id,
+ p_data->delete_mdl_cfm.status);
+
+ if (btif_hl_find_app_idx_using_deleted_mdl_id(
+ p_data->delete_mdl_cfm.mdl_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ btif_hl_send_destroyed_cb(p_acb);
+ btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+ }
+ break;
+
+ case BTA_HL_DCH_RECONNECT_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RECONNECT_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=%d status=%d ",
+ p_data->dch_reconnect_cfm.mcl_handle,
+ p_data->dch_reconnect_cfm.mdl_handle,
+ p_data->dch_reconnect_cfm.status);
+ BTIF_TRACE_DEBUG("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+ p_data->dch_reconnect_cfm.first_reliable,
+ p_data->dch_reconnect_cfm.dch_mode,
+ p_data->dch_reconnect_cfm.mdl_id,
+ p_data->dch_reconnect_cfm.mtu);
+
+ if (p_data->dch_reconnect_cfm.status == BTA_HL_STATUS_OK) {
+ status = btif_hl_proc_dch_reconnect_cfm(p_data);
+ } else {
+ status = false;
+ }
+
+ if (!status) {
+ if (btif_hl_find_mcl_idx_using_handle(p_data->dch_open_cfm.mcl_handle,
+ &app_idx, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ pending_op = p_mcb->pcb.op;
+ switch (pending_op) {
+ case BTIF_HL_PEND_DCH_OP_OPEN:
+ btif_hl_send_setup_disconnected_cb(app_idx, mcl_idx);
+ break;
+ case BTIF_HL_PEND_DCH_OP_RECONNECT:
+ case BTIF_HL_PEND_DCH_OP_DELETE_MDL:
+ default:
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case BTA_HL_CCH_CLOSE_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_CLOSE_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d status =%d",
+ p_data->cch_close_cfm.mcl_handle,
+ p_data->cch_close_cfm.status);
+ if (p_data->cch_close_cfm.status == BTA_HL_STATUS_OK) {
+ btif_hl_proc_cch_close_cfm(p_data);
+ }
+ break;
+
+ case BTA_HL_CCH_CLOSE_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CCH_CLOSE_IND_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle =%d intentional_close=%s",
+ p_data->cch_close_ind.mcl_handle,
+ (p_data->cch_close_ind.intentional ? "Yes" : "No"));
+
+ btif_hl_proc_cch_close_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CLOSE_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CLOSE_IND_EVT");
+ BTIF_TRACE_DEBUG("mdl_handle=%d intentional_close=%s",
+ p_data->dch_close_ind.mdl_handle,
+ (p_data->dch_close_ind.intentional ? "Yes" : "No"));
+
+ btif_hl_proc_dch_close_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_CLOSE_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_CLOSE_CFM_EVT");
+ BTIF_TRACE_DEBUG("mdl_handle=%d status=%d ",
+ p_data->dch_close_cfm.mdl_handle,
+ p_data->dch_close_cfm.status);
+
+ if (p_data->dch_close_cfm.status == BTA_HL_STATUS_OK) {
+ btif_hl_proc_dch_close_cfm(p_data);
+ }
+ break;
+
+ case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ECHO_TEST_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d status=%d",
+ p_data->echo_test_cfm.mcl_handle,
+ p_data->echo_test_cfm.status);
+ /* not supported */
+ break;
+
+ case BTA_HL_DCH_RECONNECT_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RECONNECT_IND_EVT");
+
+ BTIF_TRACE_DEBUG("mcl_handle=%d mdl_handle=5d",
+ p_data->dch_reconnect_ind.mcl_handle,
+ p_data->dch_reconnect_ind.mdl_handle);
+ BTIF_TRACE_DEBUG("first_reliable =%d dch_mode=%d mdl_id=%d mtu=%d",
+ p_data->dch_reconnect_ind.first_reliable,
+ p_data->dch_reconnect_ind.dch_mode,
+ p_data->dch_reconnect_ind.mdl_id,
+ p_data->dch_reconnect_ind.mtu);
+
+ btif_hl_proc_dch_reconnect_ind(p_data);
+ break;
+
+ case BTA_HL_CONG_CHG_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CONG_CHG_IND_EVT");
+ BTIF_TRACE_DEBUG("mdl_handle=%d cong =%d",
+ p_data->dch_cong_ind.mdl_handle,
+ p_data->dch_cong_ind.cong);
+ btif_hl_proc_dch_cong_ind(p_data);
+ break;
+
+ case BTA_HL_DCH_ABORT_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ABORT_IND_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d", p_data->dch_abort_ind.mcl_handle);
+ btif_hl_proc_abort_ind(p_data->dch_abort_ind.mcl_handle);
+ break;
+ case BTA_HL_DCH_ABORT_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_ABORT_CFM_EVT");
+ BTIF_TRACE_DEBUG("mcl_handle=%d status =%d",
+ p_data->dch_abort_cfm.mcl_handle,
+ p_data->dch_abort_cfm.status);
+ if (p_data->dch_abort_cfm.status == BTA_HL_STATUS_OK) {
+ btif_hl_proc_abort_cfm(p_data->dch_abort_ind.mcl_handle);
+ }
+ break;
+
+ case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_SEND_DATA_CFM_EVT");
+ BTIF_TRACE_DEBUG("mdl_handle=0x%x status =%d",
+ p_data->dch_send_data_cfm.mdl_handle,
+ p_data->dch_send_data_cfm.status);
+ btif_hl_proc_send_data_cfm(p_data->dch_send_data_cfm.mdl_handle,
+ p_data->dch_send_data_cfm.status);
+ break;
+
+ case BTA_HL_DCH_RCV_DATA_IND_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_DCH_RCV_DATA_IND_EVT");
+ BTIF_TRACE_DEBUG("mdl_handle=0x%x ", p_data->dch_rcv_data_ind.mdl_handle);
+ /* do nothing here */
+ break;
+
+ default:
+ BTIF_TRACE_DEBUG("Unknown Event (0x%02x)...", event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_cback
+ *
+ * Description Callback function for HL events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_cback(tBTA_HL_EVT event, tBTA_HL* p_data) {
+ bt_status_t status;
+ int param_len = 0;
+ BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+ btif_hl_display_calling_process_name();
+ switch (event) {
+ case BTA_HL_REGISTER_CFM_EVT:
+ param_len = sizeof(tBTA_HL_REGISTER_CFM);
+ break;
+ case BTA_HL_SDP_INFO_IND_EVT:
+ param_len = sizeof(tBTA_HL_SDP_INFO_IND);
+ break;
+ case BTA_HL_DEREGISTER_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DEREGISTER_CFM);
+ break;
+ case BTA_HL_SDP_QUERY_CFM_EVT:
+ param_len = sizeof(tBTA_HL_SDP_QUERY_CFM);
+ break;
+ case BTA_HL_CCH_OPEN_CFM_EVT:
+ param_len = sizeof(tBTA_HL_CCH_OPEN_CFM);
+ break;
+ case BTA_HL_DCH_OPEN_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+ break;
+ case BTA_HL_CCH_OPEN_IND_EVT:
+ param_len = sizeof(tBTA_HL_CCH_OPEN_IND);
+ break;
+ case BTA_HL_DCH_CREATE_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CREATE_IND);
+ break;
+ case BTA_HL_DCH_OPEN_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+ break;
+ case BTA_HL_DELETE_MDL_IND_EVT:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ case BTA_HL_DELETE_MDL_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_RECONNECT_CFM_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_CFM);
+ break;
+ case BTA_HL_CCH_CLOSE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_CCH_CLOSE_IND_EVT:
+ param_len = sizeof(tBTA_HL_CCH_CLOSE_IND);
+ break;
+ case BTA_HL_DCH_CLOSE_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CLOSE_IND);
+ break;
+ case BTA_HL_DCH_CLOSE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_ECHO_TEST_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_DCH_RECONNECT_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_OPEN_IND);
+ break;
+ case BTA_HL_CONG_CHG_IND_EVT:
+ param_len = sizeof(tBTA_HL_DCH_CONG_IND);
+ break;
+ case BTA_HL_DCH_ABORT_IND_EVT:
+ param_len = sizeof(tBTA_HL_MCL_IND);
+ break;
+ case BTA_HL_DCH_ABORT_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MCL_CFM);
+ break;
+ case BTA_HL_DCH_SEND_DATA_CFM_EVT:
+ param_len = sizeof(tBTA_HL_MDL_CFM);
+ break;
+ case BTA_HL_DCH_RCV_DATA_IND_EVT:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ default:
+ param_len = sizeof(tBTA_HL_MDL_IND);
+ break;
+ }
+ status = btif_transfer_context(btif_hl_upstreams_evt, (uint16_t)event,
+ (char*)p_data, param_len, NULL);
+
+ /* catch any failed context transfers */
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_upstreams_ctrl_evt
+ *
+ * Description Callback function for HL control events in the BTIF task
+ * context
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_upstreams_ctrl_evt(uint16_t event, char* p_param) {
+ tBTA_HL_CTRL* p_data = (tBTA_HL_CTRL*)p_param;
+ uint8_t i;
+ tBTA_HL_REG_PARAM reg_param;
+ btif_hl_app_cb_t* p_acb;
+
+ BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+ btif_hl_display_calling_process_name();
+
+ switch (event) {
+ case BTA_HL_CTRL_ENABLE_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CTRL_ENABLE_CFM_EVT");
+ BTIF_TRACE_DEBUG("status=%d", p_data->enable_cfm.status);
+
+ if (p_data->enable_cfm.status == BTA_HL_STATUS_OK) {
+ btif_hl_set_state(BTIF_HL_STATE_ENABLED);
+
+ for (i = 0; i < BTA_HL_NUM_APPS; i++) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(i);
+ if (p_acb->in_use && p_acb->reg_pending) {
+ p_acb->reg_pending = false;
+ reg_param.dev_type = p_acb->dev_type;
+ reg_param.sec_mask = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT;
+ reg_param.p_srv_name = p_acb->srv_name;
+ reg_param.p_srv_desp = p_acb->srv_desp;
+ reg_param.p_provider_name = p_acb->provider_name;
+
+ BTIF_TRACE_DEBUG("Register pending app_id=%d", p_acb->app_id);
+ btif_hl_proc_reg_request(i, p_acb->app_id, &reg_param,
+ btif_hl_cback);
+ }
+ }
+ }
+
+ break;
+ case BTA_HL_CTRL_DISABLE_CFM_EVT:
+ BTIF_TRACE_DEBUG("Rcv BTA_HL_CTRL_DISABLE_CFM_EVT");
+ BTIF_TRACE_DEBUG("status=%d", p_data->disable_cfm.status);
+
+ if (p_data->disable_cfm.status == BTA_HL_STATUS_OK) {
+ for (size_t i = 0; i < BTA_HL_NUM_APPS; i++) {
+ for (size_t j = 0; j < BTA_HL_NUM_MCLS; j++) {
+ alarm_free(p_btif_hl_cb->acb[i].mcb[j].cch_timer);
+ }
+ }
+ memset(p_btif_hl_cb, 0, sizeof(btif_hl_cb_t));
+ btif_hl_set_state(BTIF_HL_STATE_DISABLED);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_ctrl_cback
+ *
+ * Description Callback function for HL control events
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_ctrl_cback(tBTA_HL_CTRL_EVT event, tBTA_HL_CTRL* p_data) {
+ bt_status_t status;
+ int param_len = 0;
+
+ BTIF_TRACE_DEBUG("%s event %d", __func__, event);
+ btif_hl_display_calling_process_name();
+
+ switch (event) {
+ case BTA_HL_CTRL_ENABLE_CFM_EVT:
+ case BTA_HL_CTRL_DISABLE_CFM_EVT:
+ param_len = sizeof(tBTA_HL_CTRL_ENABLE_DISABLE);
+ break;
+ default:
+ break;
+ }
+
+ status = btif_transfer_context(btif_hl_upstreams_ctrl_evt, (uint16_t)event,
+ (char*)p_data, param_len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+/*******************************************************************************
+ *
+ * Function connect_channel
+ *
+ * Description connect a data channel
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t connect_channel(int app_id, bt_bdaddr_t* bd_addr,
+ int mdep_cfg_index, int* channel_id) {
+ uint8_t app_idx, mcl_idx;
+ btif_hl_app_cb_t* p_acb = NULL;
+ btif_hl_pending_chan_cb_t* p_pcb = NULL;
+ btif_hl_mcl_cb_t* p_mcb = NULL;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ tBTA_HL_DCH_OPEN_PARAM dch_open;
+ BD_ADDR bda;
+ uint8_t i;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT("%s", __func__);
+ btif_hl_display_calling_process_name();
+
+ for (i = 0; i < 6; i++) {
+ bda[i] = (uint8_t)bd_addr->address[i];
+ }
+ if (btif_hl_find_app_idx(((uint8_t)app_id), &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (btif_hl_find_mcl_idx(app_idx, bda, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected) {
+ dch_open.ctrl_psm = p_mcb->ctrl_psm;
+ dch_open.local_mdep_id =
+ p_acb->sup_feature.mdep[mdep_cfg_index].mdep_id;
+ BTIF_TRACE_DEBUG(
+ "connect_channel: app_idx =%d, mdep_cfg_indx =%d, mdep_id =%d "
+ "app_id= %d",
+ app_idx, mdep_cfg_index, dch_open.local_mdep_id, app_id);
+ if (btif_hl_find_peer_mdep_id(
+ p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[mdep_cfg_index]
+ .mdep_cfg.data_cfg[0]
+ .data_type,
+ &dch_open.peer_mdep_id)) {
+ dch_open.local_cfg = p_acb->channel_type[mdep_cfg_index];
+ if ((p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SOURCE) &&
+ !btif_hl_is_the_first_reliable_existed(app_idx, mcl_idx)) {
+ dch_open.local_cfg = BTA_HL_DCH_CFG_RELIABLE;
+ }
+ dch_open.sec_mask = (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
+
+ if (!btif_hl_dch_open(p_acb->app_id, bda, &dch_open, mdep_cfg_index,
+ BTIF_HL_PEND_DCH_OP_OPEN, channel_id)) {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_EVENT("%s loc0 status = BT_STATUS_FAIL", __func__);
+ }
+ } else {
+ p_mcb->cch_oper = BTIF_HL_CCH_OP_MDEP_FILTERING;
+
+ p_pcb = BTIF_HL_GET_PCB_PTR(app_idx, mcl_idx);
+ p_pcb->in_use = true;
+ p_pcb->mdep_cfg_idx = mdep_cfg_index;
+ /**M:Bug fix for fail to get channel id @{*/
+ p_pcb->channel_id = (int) btif_hl_get_next_channel_id(app_id);
+ /**@}*/
+ memcpy(p_pcb->bd_addr, bda, sizeof(BD_ADDR));
+ p_pcb->op = BTIF_HL_PEND_DCH_OP_OPEN;
+ BTA_HlSdpQuery(app_id, p_acb->app_handle, bda);
+ }
+ } else {
+ status = BT_STATUS_FAIL;
+ }
+ } else {
+ p_acb->filter.num_elems = 1;
+ p_acb->filter.elem[0].data_type = p_acb->sup_feature.mdep[mdep_cfg_index]
+ .mdep_cfg.data_cfg[mdep_cfg_index]
+ .data_type;
+ if (p_acb->sup_feature.mdep[mdep_cfg_index].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SINK)
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+
+ if (!btif_hl_cch_open(p_acb->app_id, bda, 0, mdep_cfg_index,
+ BTIF_HL_PEND_DCH_OP_OPEN, channel_id)) {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ } else {
+ status = BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("%s status=%d channel_id=0x%08x", __func__, status,
+ *channel_id);
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function destroy_channel
+ *
+ * Description destroy a data channel
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t destroy_channel(int channel_id) {
+ uint8_t app_idx, mcl_idx, mdl_cfg_idx, mdep_cfg_idx = 0;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_mdl_cfg_t* p_mdl;
+ btif_hl_mcl_cb_t* p_mcb;
+ btif_hl_app_cb_t* p_acb;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT("%s channel_id=0x%08x", __func__, channel_id);
+ btif_hl_display_calling_process_name();
+
+ if (btif_hl_if_channel_setup_pending(channel_id, &app_idx, &mcl_idx)) {
+ btif_hl_dch_abort(app_idx, mcl_idx);
+ } else {
+ if (btif_hl_find_mdl_cfg_idx_using_channel_id(channel_id, &app_idx,
+ &mdl_cfg_idx))
+ // if(btif_hl_find_mdl_idx_using_channel_id(channel_id,
+ // &app_idx,&mcl_idx, &mdl_idx))
+ {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ if (!p_acb->delete_mdl.active) {
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, mdl_cfg_idx);
+ p_acb->delete_mdl.active = true;
+ p_acb->delete_mdl.mdl_id = p_mdl->base.mdl_id;
+ p_acb->delete_mdl.channel_id = channel_id;
+ p_acb->delete_mdl.mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+ memcpy(p_acb->delete_mdl.bd_addr, p_mdl->base.peer_bd_addr,
+ sizeof(BD_ADDR));
+
+ if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->is_connected) {
+ BTIF_TRACE_DEBUG("calling BTA_HlDeleteMdl mdl_id=%d",
+ p_acb->delete_mdl.mdl_id);
+ BTA_HlDeleteMdl(p_mcb->mcl_handle, p_acb->delete_mdl.mdl_id);
+ } else {
+ status = BT_STATUS_FAIL;
+ }
+ } else {
+ BTIF_TRACE_DEBUG("btif_hl_delete_mdl calling btif_hl_cch_open");
+ mdep_cfg_idx = p_mdl->extra.mdep_cfg_idx;
+ p_acb->filter.num_elems = 1;
+ p_acb->filter.elem[0].data_type =
+ p_acb->sup_feature.mdep[mdep_cfg_idx]
+ .mdep_cfg.data_cfg[mdep_cfg_idx]
+ .data_type;
+ if (p_acb->sup_feature.mdep[mdep_cfg_idx].mdep_cfg.mdep_role ==
+ BTA_HL_MDEP_ROLE_SINK)
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SOURCE;
+ else
+ p_acb->filter.elem[0].peer_mdep_role = BTA_HL_MDEP_ROLE_SINK;
+ if (btif_hl_cch_open(p_acb->app_id, p_acb->delete_mdl.bd_addr, 0,
+ mdep_cfg_idx, BTIF_HL_PEND_DCH_OP_DELETE_MDL,
+ NULL)) {
+ status = BT_STATUS_FAIL;
+ }
+ }
+
+ if (status == BT_STATUS_FAIL) {
+ /* fail for now */
+ btif_hl_clean_delete_mdl(&p_acb->delete_mdl);
+ }
+ } else {
+ status = BT_STATUS_BUSY;
+ }
+ } else {
+ status = BT_STATUS_FAIL;
+ }
+ }
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function unregister_application
+ *
+ * Description unregister an HDP application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t unregister_application(int app_id) {
+ uint8_t app_idx;
+ int len;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_evt_cb_t evt_param;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT("%s app_id=%d", __func__, app_id);
+ btif_hl_display_calling_process_name();
+
+ if (btif_hl_find_app_idx(((uint8_t)app_id), &app_idx)) {
+ evt_param.unreg.app_idx = app_idx;
+ reg_counter--;
+ len = sizeof(btif_hl_unreg_t);
+ status = btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_UNREG_APP,
+ (char*)&evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+ } else {
+ status = BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("de-reg return status=%d", status);
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function register_application
+ *
+ * Description register an HDP application
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t register_application(bthl_reg_param_t* p_reg_param,
+ int* app_id) {
+ btif_hl_app_cb_t* p_acb;
+ tBTA_HL_SUP_FEATURE* p_sup;
+ tBTA_HL_MDEP_CFG* p_cfg;
+ tBTA_HL_MDEP_DATA_TYPE_CFG* p_data;
+ uint8_t app_idx = 0, i = 0;
+ bthl_mdep_cfg_t* p_mdep_cfg;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_hl_evt_cb_t evt_param;
+ int len;
+
+ CHECK_BTHL_INIT();
+ BTIF_TRACE_EVENT("%s", __func__);
+ btif_hl_display_calling_process_name();
+
+ if (btif_hl_get_state() == BTIF_HL_STATE_DISABLED) {
+ btif_hl_init();
+ btif_hl_set_state(BTIF_HL_STATE_ENABLING);
+ BTA_HlEnable(btif_hl_ctrl_cback);
+ }
+
+ if (!btif_hl_find_avail_app_idx(&app_idx)) {
+ BTIF_TRACE_ERROR("Unable to allocate a new application control block");
+ return BT_STATUS_FAIL;
+ }
+
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_acb->in_use = true;
+
+ p_acb->app_id = btif_hl_get_next_app_id();
+
+ if (p_reg_param->application_name != NULL)
+ strncpy(p_acb->application_name, p_reg_param->application_name,
+ BTIF_HL_APPLICATION_NAME_LEN);
+
+ if (p_reg_param->provider_name != NULL)
+ strncpy(p_acb->provider_name, p_reg_param->provider_name,
+ BTA_PROVIDER_NAME_LEN);
+
+ if (p_reg_param->srv_name != NULL)
+ strncpy(p_acb->srv_name, p_reg_param->srv_name, BTA_SERVICE_NAME_LEN);
+
+ if (p_reg_param->srv_desp != NULL)
+ strncpy(p_acb->srv_desp, p_reg_param->srv_desp, BTA_SERVICE_DESP_LEN);
+
+ p_sup = &p_acb->sup_feature;
+ p_sup->advertize_source_sdp = true;
+ p_sup->echo_cfg.max_rx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+ p_sup->echo_cfg.max_tx_apdu_size = BTIF_HL_ECHO_MAX_TX_RX_APDU_SIZE;
+ p_sup->num_of_mdeps = p_reg_param->number_of_mdeps;
+
+ for (i = 0, p_mdep_cfg = p_reg_param->mdep_cfg; i < p_sup->num_of_mdeps;
+ i++, p_mdep_cfg++) {
+ p_cfg = &p_sup->mdep[i].mdep_cfg;
+ p_cfg->num_of_mdep_data_types = 1;
+ p_data = &p_cfg->data_cfg[0];
+
+ if (!btif_hl_get_bta_mdep_role(p_mdep_cfg->mdep_role,
+ &(p_cfg->mdep_role))) {
+ BTIF_TRACE_ERROR("Invalid mdep_role=%d", p_mdep_cfg->mdep_role);
+ status = BT_STATUS_FAIL;
+ break;
+ } else {
+ if (p_cfg->mdep_role == BTA_HL_MDEP_ROLE_SINK)
+ p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SINK;
+ else
+ p_sup->app_role_mask |= BTA_HL_MDEP_ROLE_MASK_SOURCE;
+
+ if ((p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) &&
+ (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SOURCE)) {
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_DUAL;
+ } else if (p_sup->app_role_mask & BTA_HL_MDEP_ROLE_MASK_SINK) {
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_SINK;
+ } else {
+ p_acb->dev_type = BTA_HL_DEVICE_TYPE_SOURCE;
+ }
+
+ p_data->data_type = (uint16_t)p_mdep_cfg->data_type;
+ p_data->max_rx_apdu_size =
+ btif_hl_get_max_rx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+ p_data->max_tx_apdu_size =
+ btif_hl_get_max_tx_apdu_size(p_cfg->mdep_role, p_data->data_type);
+
+ if (p_mdep_cfg->mdep_description != NULL)
+ strncpy(p_data->desp, p_mdep_cfg->mdep_description,
+ BTA_SERVICE_DESP_LEN);
+
+ if (!btif_hl_get_bta_channel_type(p_mdep_cfg->channel_type,
+ &(p_acb->channel_type[i]))) {
+ BTIF_TRACE_ERROR("Invalid channel_type=%d", p_mdep_cfg->channel_type);
+ status = BT_STATUS_FAIL;
+ break;
+ }
+ }
+ }
+
+ if (status == BT_STATUS_SUCCESS) {
+ *app_id = (int)p_acb->app_id;
+ evt_param.reg.app_idx = app_idx;
+ len = sizeof(btif_hl_reg_t);
+ p_acb->reg_pending = true;
+ BTIF_TRACE_DEBUG("calling btif_transfer_context status=%d app_id=%d",
+ status, *app_id);
+ status = btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_REG_APP,
+ (char*)&evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+
+ } else {
+ btif_hl_free_app_idx(app_idx);
+ }
+
+ BTIF_TRACE_DEBUG("register_application status=%d app_id=%d", status, *app_id);
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_save_mdl_cfg
+ *
+ * Description Save the MDL configuration
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_save_mdl_cfg(uint8_t mdep_id, uint8_t item_idx,
+ tBTA_HL_MDL_CFG* p_mdl_cfg) {
+ btif_hl_mdl_cfg_t* p_mdl = NULL;
+ bool success = false;
+ btif_hl_app_cb_t* p_acb;
+ btif_hl_mcl_cb_t* p_mcb;
+ uint8_t app_idx, mcl_idx, len;
+ bt_status_t bt_status;
+ btif_hl_evt_cb_t evt_param;
+ int* p_channel_id;
+
+ BTIF_TRACE_DEBUG(
+ "%s mdep_id=%d item_idx=%d, local_mdep_id=%d mdl_id=0x%x dch_mode=%d",
+ __func__, mdep_id, item_idx, p_mdl_cfg->local_mdep_id, p_mdl_cfg->mdl_id,
+ p_mdl_cfg->dch_mode);
+
+ if (btif_hl_find_app_idx_using_mdepId(mdep_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+ p_channel_id = BTIF_HL_GET_MDL_CFG_CHANNEL_ID_PTR(app_idx, item_idx);
+ if (p_mdl) {
+ memcpy(&p_mdl->base, p_mdl_cfg, sizeof(tBTA_HL_MDL_CFG));
+ if (btif_hl_find_mcl_idx(app_idx, p_mdl->base.peer_bd_addr, &mcl_idx)) {
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ if (p_mcb->pcb.in_use)
+ *p_channel_id = p_mcb->pcb.channel_id;
+ else
+ *p_channel_id = btif_hl_get_next_channel_id(p_acb->app_id);
+ p_mdl->extra.mdep_cfg_idx = p_mcb->pcb.mdep_cfg_idx;
+ p_mdl->extra.data_type =
+ p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+ .mdep_cfg.data_cfg[0]
+ .data_type;
+
+ if (!btif_hl_find_peer_mdep_id(
+ p_acb->app_id, p_mcb->bd_addr,
+ p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+ .mdep_cfg.mdep_role,
+ p_acb->sup_feature.mdep[p_mcb->pcb.mdep_cfg_idx]
+ .mdep_cfg.data_cfg[0]
+ .data_type,
+ &p_mdl->extra.peer_mdep_id)) {
+ p_mdl->extra.peer_mdep_id = BTA_HL_INVALID_MDEP_ID;
+ }
+ BTIF_TRACE_DEBUG("%s app_idx=%d item_idx=%d mld_id=0x%x", __func__,
+ app_idx, item_idx, p_mdl->base.mdl_id);
+ evt_param.update_mdl.app_idx = app_idx;
+ len = sizeof(btif_hl_update_mdl_t);
+ BTIF_TRACE_DEBUG("send BTIF_HL_UPDATE_MDL event app_idx=%d ", app_idx);
+ bt_status =
+ btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL,
+ (char*)&evt_param, len, NULL);
+ if (bt_status == BT_STATUS_SUCCESS) {
+ success = true;
+ }
+ ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed",
+ bt_status);
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG("%s success=%d ", __func__, success);
+
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_delete_mdl_cfg
+ *
+ * Description Delete the MDL configuration
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_delete_mdl_cfg(uint8_t mdep_id, uint8_t item_idx) {
+ btif_hl_mdl_cfg_t* p_mdl = NULL;
+ bool success = false;
+ uint8_t app_idx, len;
+ bt_status_t bt_status;
+ btif_hl_evt_cb_t evt_param;
+
+ if (btif_hl_find_app_idx_using_mdepId(mdep_id, &app_idx)) {
+ p_mdl = BTIF_HL_GET_MDL_CFG_PTR(app_idx, item_idx);
+ if (p_mdl) {
+ memset(p_mdl, 0, sizeof(btif_hl_mdl_cfg_t));
+ evt_param.update_mdl.app_idx = app_idx;
+ len = sizeof(btif_hl_update_mdl_t);
+ BTIF_TRACE_DEBUG("send BTIF_HL_UPDATE_MDL event app_idx=%d ", app_idx);
+ bt_status = btif_transfer_context(btif_hl_proc_cb_evt, BTIF_HL_UPDATE_MDL,
+ (char*)&evt_param, len, NULL);
+ if (bt_status == BT_STATUS_SUCCESS) {
+ success = true;
+ }
+ ASSERTC(bt_status == BT_STATUS_SUCCESS, "context transfer failed",
+ bt_status);
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s success=%d ", __func__, success);
+ return success;
+}
+
+/*******************************************************************************
+ *
+ * Function init
+ *
+ * Description initializes the hl interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(bthl_callbacks_t* callbacks) {
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ BTIF_TRACE_EVENT("%s", __func__);
+ btif_hl_display_calling_process_name();
+ bt_hl_callbacks_cb = *callbacks;
+ bt_hl_callbacks = &bt_hl_callbacks_cb;
+ btif_hl_soc_thread_init();
+ reg_counter = 0;
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Closes the HL interface
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void cleanup(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ btif_hl_display_calling_process_name();
+ if (bt_hl_callbacks) {
+ btif_disable_service(BTA_HDP_SERVICE_ID);
+ bt_hl_callbacks = NULL;
+ reg_counter = 0;
+ }
+
+ btif_hl_disable();
+ btif_hl_close_select_thread();
+}
+
+static const bthl_interface_t bthlInterface = {
+ sizeof(bthl_interface_t),
+ init,
+ register_application,
+ unregister_application,
+ connect_channel,
+ destroy_channel,
+ cleanup,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_hl_get_interface
+ *
+ * Description Get the hl callback interface
+ *
+ * Returns bthf_interface_t
+ *
+ ******************************************************************************/
+const bthl_interface_t* btif_hl_get_interface() {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &bthlInterface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_update_maxfd
+ *
+ * Description Update the max fd if the input fd is greater than the current max
+ * fd
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+int btif_hl_update_maxfd(int max_org_s) {
+ int maxfd = max_org_s;
+
+ BTIF_TRACE_DEBUG("btif_hl_update_maxfd max_org_s= %d", max_org_s);
+ for (const list_node_t* node = list_begin(soc_queue);
+ node != list_end(soc_queue); node = list_next(node)) {
+ btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+ if (maxfd < p_scb->max_s) {
+ maxfd = p_scb->max_s;
+ BTIF_TRACE_DEBUG("btif_hl_update_maxfd maxfd=%d", maxfd);
+ }
+ }
+
+ BTIF_TRACE_DEBUG("btif_hl_update_maxfd final *p_max_s=%d", maxfd);
+ return maxfd;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_get_socket_state
+ *
+ * Description get socket state
+ *
+ * Returns btif_hl_soc_state_t
+ *
+ ******************************************************************************/
+btif_hl_soc_state_t btif_hl_get_socket_state(btif_hl_soc_cb_t* p_scb) {
+ BTIF_TRACE_DEBUG("btif_hl_get_socket_state state=%d", p_scb->state);
+ return p_scb->state;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_set_socket_state
+ *
+ * Description set socket state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_set_socket_state(btif_hl_soc_cb_t* p_scb,
+ btif_hl_soc_state_t new_state) {
+ BTIF_TRACE_DEBUG("btif_hl_set_socket_state %d---->%d", p_scb->state,
+ new_state);
+ p_scb->state = new_state;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_release_mcl_sockets
+ *
+ * Description Release all sockets on the MCL
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_release_mcl_sockets(uint8_t app_idx, uint8_t mcl_idx) {
+ uint8_t i;
+ btif_hl_mdl_cb_t* p_dcb;
+ bool found = false;
+ BTIF_TRACE_DEBUG("%s", __func__);
+ for (i = 0; i < BTA_HL_NUM_MDLS_PER_MCL; i++) {
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, i);
+ if (p_dcb && p_dcb->in_use && p_dcb->p_scb) {
+ BTIF_TRACE_DEBUG("found socket for app_idx=%d mcl_id=%d, mdl_idx=%d",
+ app_idx, mcl_idx, i);
+ btif_hl_set_socket_state(p_dcb->p_scb, BTIF_HL_SOC_STATE_W4_REL);
+ p_dcb->p_scb = NULL;
+ found = true;
+ }
+ }
+ if (found) btif_hl_select_close_connected();
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_release_socket
+ *
+ * Description release a specified socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_release_socket(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+ btif_hl_soc_cb_t* p_scb = NULL;
+ btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_idx=%d mdl_idx=%d", app_idx, mcl_idx,
+ mdl_idx);
+
+ if (p_dcb && p_dcb->p_scb) {
+ p_scb = p_dcb->p_scb;
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_REL);
+ p_dcb->p_scb = NULL;
+ btif_hl_select_close_connected();
+ }
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_create_socket
+ *
+ * Description create a socket
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_create_socket(uint8_t app_idx, uint8_t mcl_idx, uint8_t mdl_idx) {
+ btif_hl_mcl_cb_t* p_mcb = BTIF_HL_GET_MCL_CB_PTR(app_idx, mcl_idx);
+ btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(app_idx, mcl_idx, mdl_idx);
+ bool status = false;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (p_dcb) {
+ btif_hl_soc_cb_t* p_scb =
+ (btif_hl_soc_cb_t*)osi_malloc(sizeof(btif_hl_soc_cb_t));
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, p_scb->socket_id) >= 0) {
+ BTIF_TRACE_DEBUG("socket id[0]=%d id[1]=%d", p_scb->socket_id[0],
+ p_scb->socket_id[1]);
+ p_dcb->p_scb = p_scb;
+ p_scb->app_idx = app_idx;
+ p_scb->mcl_idx = mcl_idx;
+ p_scb->mdl_idx = mdl_idx;
+ p_scb->channel_id = p_dcb->channel_id;
+ p_scb->mdep_cfg_idx = p_dcb->local_mdep_cfg_idx;
+ memcpy(p_scb->bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR));
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_ADD);
+ p_scb->max_s = p_scb->socket_id[1];
+ list_append(soc_queue, (void*)p_scb);
+ btif_hl_select_wakeup();
+ status = true;
+ } else {
+ osi_free_and_reset((void**)&p_scb);
+ }
+ }
+
+ BTIF_TRACE_DEBUG("%s status=%d", __func__, status);
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_add_socket_to_set
+ *
+ * Description Add a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_add_socket_to_set(fd_set* p_org_set) {
+ btif_hl_mdl_cb_t* p_dcb = NULL;
+ btif_hl_mcl_cb_t* p_mcb = NULL;
+ btif_hl_app_cb_t* p_acb = NULL;
+ btif_hl_evt_cb_t evt_param;
+ bt_status_t status;
+ int len;
+
+ BTIF_TRACE_DEBUG("entering %s", __func__);
+
+ for (const list_node_t* node = list_begin(soc_queue);
+ node != list_end(soc_queue); node = list_next(node)) {
+ btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+
+ BTIF_TRACE_DEBUG("btif_hl_add_socket_to_set first p_scb=0x%x", p_scb);
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_ADD) {
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_W4_READ);
+ FD_SET(p_scb->socket_id[1], p_org_set);
+ BTIF_TRACE_DEBUG("found and set socket_id=%d is_set=%d",
+ p_scb->socket_id[1],
+ FD_ISSET(p_scb->socket_id[1], p_org_set));
+ p_mcb = BTIF_HL_GET_MCL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx);
+ p_dcb = BTIF_HL_GET_MDL_CB_PTR(p_scb->app_idx, p_scb->mcl_idx,
+ p_scb->mdl_idx);
+ p_acb = BTIF_HL_GET_APP_CB_PTR(p_scb->app_idx);
+ if (p_mcb && p_dcb) {
+ btif_hl_stop_timer_using_handle(p_mcb->mcl_handle);
+ evt_param.chan_cb.app_id = p_acb->app_id;
+ memcpy(evt_param.chan_cb.bd_addr, p_mcb->bd_addr, sizeof(BD_ADDR));
+ evt_param.chan_cb.channel_id = p_dcb->channel_id;
+ evt_param.chan_cb.fd = p_scb->socket_id[0];
+ evt_param.chan_cb.mdep_cfg_index = (int)p_dcb->local_mdep_cfg_idx;
+ evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_CONNECTED_PENDING;
+ len = sizeof(btif_hl_send_chan_state_cb_t);
+ status = btif_transfer_context(btif_hl_proc_cb_evt,
+ BTIF_HL_SEND_CONNECTED_CB,
+ (char*)&evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+ }
+ }
+ }
+ BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_close_socket
+ *
+ * Description close a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_close_socket(fd_set* p_org_set) {
+ BTIF_TRACE_DEBUG("entering %s", __func__);
+ for (const list_node_t* node = list_begin(soc_queue);
+ node != list_end(soc_queue); node = list_next(node)) {
+ btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_REL) {
+ BTIF_TRACE_DEBUG("app_idx=%d mcl_id=%d, mdl_idx=%d", p_scb->app_idx,
+ p_scb->mcl_idx, p_scb->mdl_idx);
+ btif_hl_set_socket_state(p_scb, BTIF_HL_SOC_STATE_IDLE);
+ if (p_scb->socket_id[1] != -1) {
+ FD_CLR(p_scb->socket_id[1], p_org_set);
+ shutdown(p_scb->socket_id[1], SHUT_RDWR);
+ close(p_scb->socket_id[1]);
+
+ btif_hl_evt_cb_t evt_param;
+ evt_param.chan_cb.app_id = (int)btif_hl_get_app_id(p_scb->channel_id);
+ memcpy(evt_param.chan_cb.bd_addr, p_scb->bd_addr, sizeof(BD_ADDR));
+ evt_param.chan_cb.channel_id = p_scb->channel_id;
+ evt_param.chan_cb.fd = p_scb->socket_id[0];
+ evt_param.chan_cb.mdep_cfg_index = (int)p_scb->mdep_cfg_idx;
+ evt_param.chan_cb.cb_state = BTIF_HL_CHAN_CB_STATE_DISCONNECTED_PENDING;
+ int len = sizeof(btif_hl_send_chan_state_cb_t);
+ bt_status_t status = btif_transfer_context(
+ btif_hl_proc_cb_evt, BTIF_HL_SEND_DISCONNECTED_CB,
+ (char*)&evt_param, len, NULL);
+ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+ }
+ }
+ }
+
+ for (const list_node_t* node = list_begin(soc_queue);
+ node != list_end(soc_queue);) {
+ // We may mutate this list so we need keep track of
+ // the current node and only remove items behind.
+ btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+ BTIF_TRACE_DEBUG("p_scb=0x%x", p_scb);
+ node = list_next(node);
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_IDLE) {
+ btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(
+ p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ BTIF_TRACE_DEBUG(
+ "idle socket app_idx=%d mcl_id=%d, mdl_idx=%d p_dcb->in_use=%d",
+ p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx, p_dcb->in_use);
+ list_remove(soc_queue, p_scb);
+ osi_free(p_scb);
+ p_dcb->p_scb = NULL;
+ }
+ }
+ BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup_callback
+ *
+ * Description Select wakup callback to add or close a socket
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+void btif_hl_select_wakeup_callback(fd_set* p_org_set, int wakeup_signal) {
+ BTIF_TRACE_DEBUG("entering %s wakeup_signal=0x%04x", __func__, wakeup_signal);
+
+ if (wakeup_signal == btif_hl_signal_select_wakeup) {
+ btif_hl_add_socket_to_set(p_org_set);
+ } else if (wakeup_signal == btif_hl_signal_select_close_connected) {
+ btif_hl_close_socket(p_org_set);
+ }
+ BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_monitor_callback
+ *
+ * Description Select monitor callback to check pending socket actions
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_select_monitor_callback(fd_set* p_cur_set,
+ UNUSED_ATTR fd_set* p_org_set) {
+ BTIF_TRACE_DEBUG("entering %s", __func__);
+
+ for (const list_node_t* node = list_begin(soc_queue);
+ node != list_end(soc_queue); node = list_next(node)) {
+ btif_hl_soc_cb_t* p_scb = (btif_hl_soc_cb_t*)list_node(node);
+ if (btif_hl_get_socket_state(p_scb) == BTIF_HL_SOC_STATE_W4_READ) {
+ if (FD_ISSET(p_scb->socket_id[1], p_cur_set)) {
+ BTIF_TRACE_DEBUG("read data state= BTIF_HL_SOC_STATE_W4_READ");
+ btif_hl_mdl_cb_t* p_dcb = BTIF_HL_GET_MDL_CB_PTR(
+ p_scb->app_idx, p_scb->mcl_idx, p_scb->mdl_idx);
+ CHECK(p_dcb != NULL);
+ if (p_dcb->p_tx_pkt) {
+ BTIF_TRACE_ERROR(
+ "Rcv new pkt but the last pkt is still not been"
+ " sent tx_size=%d",
+ p_dcb->tx_size);
+ osi_free_and_reset((void**)&p_dcb->p_tx_pkt);
+ }
+ p_dcb->p_tx_pkt = (uint8_t*)osi_malloc(p_dcb->mtu);
+ ssize_t r;
+ OSI_NO_INTR(r = recv(p_scb->socket_id[1], p_dcb->p_tx_pkt, p_dcb->mtu,
+ MSG_DONTWAIT));
+ if (r > 0) {
+ BTIF_TRACE_DEBUG("btif_hl_select_monitor_callback send data r =%d",
+ r);
+ p_dcb->tx_size = r;
+ BTIF_TRACE_DEBUG(
+ "btif_hl_select_monitor_callback send data tx_size=%d",
+ p_dcb->tx_size);
+ BTA_HlSendData(p_dcb->mdl_handle, p_dcb->tx_size);
+ } else {
+ BTIF_TRACE_DEBUG(
+ "btif_hl_select_monitor_callback receive failed r=%d", r);
+ BTA_HlDchClose(p_dcb->mdl_handle);
+ }
+ }
+ }
+ }
+
+ if (list_is_empty(soc_queue))
+ BTIF_TRACE_DEBUG("btif_hl_select_monitor_queue is empty");
+
+ BTIF_TRACE_DEBUG("leaving %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup_init
+ *
+ * Description select loop wakup init
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wakeup_init(fd_set* set) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ if (signal_fds[0] == -1 &&
+ socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds) < 0) {
+ BTIF_TRACE_ERROR("socketpair failed: %s", strerror(errno));
+ return -1;
+ }
+
+ BTIF_TRACE_DEBUG(
+ "btif_hl_select_wakeup_init signal_fds[0]=%d signal_fds[1]=%d",
+ signal_fds[0], signal_fds[1]);
+ FD_SET(signal_fds[0], set);
+
+ return signal_fds[0];
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wakeup
+ *
+ * Description send a signal to wakupo the select loop
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wakeup(void) {
+ char sig_on = btif_hl_signal_select_wakeup;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+ return (int)ret;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_close_connected
+ *
+ * Description send a signal to close a socket
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_close_connected(void) {
+ char sig_on = btif_hl_signal_select_close_connected;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+ return (int)ret;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_close_select_thread
+ *
+ * Description send signal to close the thread and then close all signal FDs
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_close_select_thread(void) {
+ ssize_t result = 0;
+ char sig_on = btif_hl_signal_select_exit;
+
+ BTIF_TRACE_DEBUG("%", __func__);
+
+ OSI_NO_INTR(result = send(signal_fds[1], &sig_on, sizeof(sig_on), 0));
+
+ if (btif_is_enabled()) {
+ /* Wait for the select_thread_id to exit if BT is still enabled
+ and only this profile getting cleaned up*/
+ if (select_thread_id != -1) {
+ pthread_join(select_thread_id, NULL);
+ select_thread_id = -1;
+ }
+ }
+ list_free(soc_queue);
+ soc_queue = NULL;
+
+ return (int)result;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wake_reset
+ *
+ * Description clear the received signal for the select loop
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wake_reset(void) {
+ char sig_recv = 0;
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ ssize_t r;
+ OSI_NO_INTR(
+ r = recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL));
+
+ return (int)sig_recv;
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_select_wake_signaled
+ *
+ * Description check whether a fd is set or not
+ *
+ * Returns int
+ *
+ ******************************************************************************/
+static inline int btif_hl_select_wake_signaled(fd_set* set) {
+ BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled");
+ return FD_ISSET(signal_fds[0], set);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_thread_cleanup
+ *
+ * Description shut down and clean up the select loop
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_hl_thread_cleanup() {
+ if (listen_s != -1) close(listen_s);
+ if (connected_s != -1) {
+ shutdown(connected_s, SHUT_RDWR);
+ close(connected_s);
+ }
+ listen_s = connected_s = -1;
+ BTIF_TRACE_DEBUG("hl thread cleanup");
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_select_thread
+ *
+ * Description the select loop
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void* btif_hl_select_thread(UNUSED_ATTR void* arg) {
+ fd_set org_set, curr_set;
+ int r, max_curr_s, max_org_s;
+
+ BTIF_TRACE_DEBUG("entered btif_hl_select_thread");
+ FD_ZERO(&org_set);
+ max_org_s = btif_hl_select_wakeup_init(&org_set);
+ BTIF_TRACE_DEBUG("max_s=%d ", max_org_s);
+
+ for (;;) {
+ r = 0;
+ BTIF_TRACE_DEBUG("set curr_set = org_set ");
+ curr_set = org_set;
+ max_curr_s = max_org_s;
+ int ret = select((max_curr_s + 1), &curr_set, NULL, NULL, NULL);
+ BTIF_TRACE_DEBUG("select unblocked ret=%d", ret);
+ if (ret == -1) {
+ if (errno == EINTR) continue;
+ BTIF_TRACE_DEBUG("select() ret -1, exit the thread");
+ btif_hl_thread_cleanup();
+ select_thread_id = -1;
+ return 0;
+ } else if (ret) {
+ BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled, signal ret=%d", ret);
+ if (btif_hl_select_wake_signaled(&curr_set)) {
+ r = btif_hl_select_wake_reset();
+ BTIF_TRACE_DEBUG("btif_hl_select_wake_signaled, signal:%d", r);
+ if (r == btif_hl_signal_select_wakeup ||
+ r == btif_hl_signal_select_close_connected) {
+ btif_hl_select_wakeup_callback(&org_set, r);
+ } else if (r == btif_hl_signal_select_exit) {
+ btif_hl_thread_cleanup();
+ BTIF_TRACE_DEBUG(
+ "Exit hl_select_thread for btif_hl_signal_select_exit");
+ return 0;
+ }
+ }
+
+ btif_hl_select_monitor_callback(&curr_set, &org_set);
+ max_org_s = btif_hl_update_maxfd(max_org_s);
+ } else
+ BTIF_TRACE_DEBUG("no data, select ret: %d\n", ret);
+ }
+ BTIF_TRACE_DEBUG("leaving hl_select_thread");
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function create_thread
+ *
+ * Description creat a select loop
+ *
+ * Returns pthread_t
+ *
+ ******************************************************************************/
+static inline pthread_t create_thread(void* (*start_routine)(void*),
+ void* arg) {
+ BTIF_TRACE_DEBUG("create_thread: entered");
+ pthread_attr_t thread_attr;
+
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ pthread_t thread_id = -1;
+ if (pthread_create(&thread_id, &thread_attr, start_routine, arg) != 0) {
+ BTIF_TRACE_ERROR("pthread_create : %s", strerror(errno));
+ return -1;
+ }
+ BTIF_TRACE_DEBUG("create_thread: thread created successfully");
+ return thread_id;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_hl_soc_thread_init
+ *
+ * Description HL select loop init function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_hl_soc_thread_init(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ soc_queue = list_new(NULL);
+ if (soc_queue == NULL)
+ LOG_ERROR(LOG_TAG, "%s unable to allocate resources for thread", __func__);
+ select_thread_id = create_thread(btif_hl_select_thread, NULL);
+}
+/*******************************************************************************
+ *
+ * Function btif_hl_load_mdl_config
+ *
+ * Description load the MDL configuation from the application control block
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btif_hl_load_mdl_config(uint8_t app_id, uint8_t buffer_size,
+ tBTA_HL_MDL_CFG* p_mdl_buf) {
+ uint8_t app_idx;
+ bool result = false;
+ btif_hl_app_cb_t* p_acb;
+ tBTA_HL_MDL_CFG* p;
+ int i;
+ BTIF_TRACE_DEBUG("%s", __func__);
+
+ if (btif_hl_find_app_idx(app_id, &app_idx)) {
+ p_acb = BTIF_HL_GET_APP_CB_PTR(app_idx);
+ for (i = 0, p = p_mdl_buf; i < buffer_size; i++, p++) {
+ memcpy(p, &p_acb->mdl_cfg[i].base, sizeof(tBTA_HL_MDL_CFG));
+ }
+ result = true;
+ }
+
+ BTIF_TRACE_DEBUG("result=%d", result);
+ return result;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_mce.cc b/mtkbt/code/bt/btif/src/btif_mce.cc
new file mode 100755
index 0000000..5c03d71
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_mce.cc
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_mce.c
+ *
+ * Description: Message Access Profile (MCE role) Bluetooth Interface
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_mce"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_mce.h>
+
+#include "bt_types.h"
+#include "bta_api.h"
+#include "bta_mce_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+
+static btmce_callbacks_t* bt_mce_callbacks = NULL;
+
+static void btif_mce_mas_discovery_comp_evt(uint16_t event, char* p_param) {
+ tBTA_MCE_MAS_DISCOVERY_COMP* evt_data = (tBTA_MCE_MAS_DISCOVERY_COMP*)p_param;
+ btmce_mas_instance_t insts[BTA_MCE_MAX_MAS_INSTANCES];
+ bt_bdaddr_t addr;
+ int i;
+
+ BTIF_TRACE_EVENT("%s: event = %d", __func__, event);
+
+ if (event != BTA_MCE_MAS_DISCOVERY_COMP_EVT) return;
+
+ for (i = 0; i < evt_data->num_mas; i++) {
+ insts[i].id = evt_data->mas[i].instance_id;
+ insts[i].scn = evt_data->mas[i].scn;
+ insts[i].msg_types = evt_data->mas[i].msg_type;
+ insts[i].p_name = evt_data->mas[i].p_srv_name;
+ }
+
+ bdcpy(addr.address, evt_data->remote_addr);
+
+ HAL_CBACK(bt_mce_callbacks, remote_mas_instances_cb,
+ (bt_status_t)evt_data->status, &addr, evt_data->num_mas, insts);
+}
+
+static void mas_discovery_comp_copy_cb(uint16_t event, char* p_dest,
+ char* p_src) {
+ tBTA_MCE_MAS_DISCOVERY_COMP* p_dest_data =
+ (tBTA_MCE_MAS_DISCOVERY_COMP*)p_dest;
+ tBTA_MCE_MAS_DISCOVERY_COMP* p_src_data = (tBTA_MCE_MAS_DISCOVERY_COMP*)p_src;
+ char* p_dest_str;
+ int i;
+
+ if (!p_src) return;
+
+ if (event != BTA_MCE_MAS_DISCOVERY_COMP_EVT) return;
+
+ maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+ p_dest_str = p_dest + sizeof(tBTA_MCE_MAS_DISCOVERY_COMP);
+
+ for (i = 0; i < p_src_data->num_mas; i++) {
+ p_dest_data->mas[i].p_srv_name = p_dest_str;
+ memcpy(p_dest_str, p_src_data->mas[i].p_srv_name,
+ p_src_data->mas[i].srv_name_len);
+ p_dest_str += p_src_data->mas[i].srv_name_len;
+ *(p_dest_str++) = '\0';
+ }
+}
+
+static void mce_dm_cback(tBTA_MCE_EVT event, tBTA_MCE* p_data,
+ void* user_data) {
+ switch (event) {
+ case BTA_MCE_MAS_DISCOVERY_COMP_EVT: {
+ int i;
+ uint16_t param_len = sizeof(tBTA_MCE);
+
+ /* include space for all p_srv_name copies including null-termination */
+ for (i = 0; i < p_data->mas_disc_comp.num_mas; i++)
+ param_len += (p_data->mas_disc_comp.mas[i].srv_name_len + 1);
+
+ /* need to deepy copy p_srv_name and null-terminate */
+ btif_transfer_context(btif_mce_mas_discovery_comp_evt, event,
+ (char*)p_data, param_len,
+ mas_discovery_comp_copy_cb);
+
+ break;
+ }
+ }
+}
+
+static bt_status_t init(btmce_callbacks_t* callbacks) {
+ BTIF_TRACE_EVENT("%s", __func__);
+
+ bt_mce_callbacks = callbacks;
+
+ btif_enable_service(BTA_MAP_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t get_remote_mas_instances(bt_bdaddr_t* bd_addr) {
+ bdstr_t bdstr;
+
+ BTIF_TRACE_EVENT("%s: remote_addr=%s", __func__,
+ bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+ BTA_MceGetRemoteMasInstances(bd_addr->address);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const btmce_interface_t mce_if = {
+ sizeof(btmce_interface_t), init, get_remote_mas_instances,
+};
+
+const btmce_interface_t* btif_mce_get_interface(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &mce_if;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_mce_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_mce_execute_service(bool b_enable) {
+ BTIF_TRACE_EVENT("%s enable:%d", __func__, b_enable);
+
+ if (b_enable) {
+ BTA_MceEnable(mce_dm_cback);
+ } else {
+ /* This is called on BT disable so no need to extra cleanup */
+ }
+ return BT_STATUS_SUCCESS;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_pan.cc b/mtkbt/code/bt/btif/src/btif_pan.cc
new file mode 100755
index 0000000..9562a1f
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_pan.cc
@@ -0,0 +1,784 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_pan.c
+ *
+ * Description: PAN Profile Bluetooth Interface
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_pan"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/sockios.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_pan_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_common.h"
+#include "btif_pan_internal.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define FORWARD_IGNORE 1
+#define FORWARD_SUCCESS 0
+#define FORWARD_FAILURE (-1)
+#define FORWARD_CONGEST (-2)
+
+#if (PAN_NAP_DISABLED == TRUE && PANU_DISABLED == TRUE)
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_NONE
+#elif PAN_NAP_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANU
+#elif PANU_DISABLED == TRUE
+#define BTPAN_LOCAL_ROLE BTPAN_ROLE_PANNAP
+#else
+#define BTPAN_LOCAL_ROLE (BTPAN_ROLE_PANU | BTPAN_ROLE_PANNAP)
+#endif
+
+#define asrt(s) \
+ do { \
+ if (!(s)) \
+ BTIF_TRACE_ERROR("btif_pan: ## %s assert %s failed at line:%d ##", \
+ __func__, #s, __LINE__) \
+ } while (0)
+
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+btpan_cb_t btpan_cb;
+
+static bool jni_initialized;
+static bool stack_initialized;
+
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks);
+static void btpan_jni_cleanup();
+static bt_status_t btpan_connect(const bt_bdaddr_t* bd_addr, int local_role,
+ int remote_role);
+static bt_status_t btpan_disconnect(const bt_bdaddr_t* bd_addr);
+static bt_status_t btpan_enable(int local_role);
+static int btpan_get_local_role(void);
+
+static void btpan_tap_fd_signaled(int fd, int type, int flags,
+ uint32_t user_id);
+static void btpan_cleanup_conn(btpan_conn_t* conn);
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN* p_data);
+static void btu_exec_tap_fd_read(void* p_param);
+
+static btpan_interface_t pan_if = {
+ sizeof(pan_if), btpan_jni_init, btpan_enable, btpan_get_local_role,
+ btpan_connect, btpan_disconnect, btpan_jni_cleanup};
+
+btpan_interface_t* btif_pan_get_interface() { return &pan_if; }
+
+/*******************************************************************************
+ **
+ ** Function btif_pan_init
+ **
+ ** Description initializes the pan interface
+ **
+ ** Returns bt_status_t
+ **
+ ******************************************************************************/
+void btif_pan_init() {
+ BTIF_TRACE_DEBUG("jni_initialized = %d, btpan_cb.enabled:%d", jni_initialized,
+ btpan_cb.enabled);
+ stack_initialized = true;
+
+ if (jni_initialized && !btpan_cb.enabled) {
+ BTIF_TRACE_DEBUG("Enabling PAN....");
+ memset(&btpan_cb, 0, sizeof(btpan_cb));
+ btpan_cb.tap_fd = INVALID_FD;
+ btpan_cb.flow = 1;
+ for (int i = 0; i < MAX_PAN_CONNS; i++)
+ btpan_cleanup_conn(&btpan_cb.conns[i]);
+ BTA_PanEnable(bta_pan_callback);
+ btpan_cb.enabled = 1;
+ btpan_enable(BTPAN_LOCAL_ROLE);
+ }
+}
+
+static void pan_disable() {
+ if (btpan_cb.enabled) {
+ btpan_cb.enabled = 0;
+ BTA_PanDisable();
+ if (btpan_cb.tap_fd != INVALID_FD) {
+ btpan_tap_close(btpan_cb.tap_fd);
+ btpan_cb.tap_fd = INVALID_FD;
+ }
+ }
+}
+
+void btif_pan_cleanup() {
+ if (!stack_initialized) return;
+
+ // Bluetooth is shuting down, invalidate all BTA PAN handles
+ for (int i = 0; i < MAX_PAN_CONNS; i++)
+ btpan_cleanup_conn(&btpan_cb.conns[i]);
+
+ pan_disable();
+ stack_initialized = false;
+}
+
+static btpan_callbacks_t callback;
+static bt_status_t btpan_jni_init(const btpan_callbacks_t* callbacks) {
+ BTIF_TRACE_DEBUG("stack_initialized = %d, btpan_cb.enabled:%d",
+ stack_initialized, btpan_cb.enabled);
+ callback = *callbacks;
+ jni_initialized = true;
+ if (stack_initialized && !btpan_cb.enabled) btif_pan_init();
+ return BT_STATUS_SUCCESS;
+}
+
+static void btpan_jni_cleanup() {
+ pan_disable();
+ jni_initialized = false;
+}
+
+static inline int bta_role_to_btpan(int bta_pan_role) {
+ int btpan_role = 0;
+ BTIF_TRACE_DEBUG("bta_pan_role:0x%x", bta_pan_role);
+ if (bta_pan_role & PAN_ROLE_NAP_SERVER) btpan_role |= BTPAN_ROLE_PANNAP;
+ if (bta_pan_role & PAN_ROLE_CLIENT) btpan_role |= BTPAN_ROLE_PANU;
+ return btpan_role;
+}
+
+static inline int btpan_role_to_bta(int btpan_role) {
+ int bta_pan_role = PAN_ROLE_INACTIVE;
+ BTIF_TRACE_DEBUG("btpan_role:0x%x", btpan_role);
+ if (btpan_role & BTPAN_ROLE_PANNAP) bta_pan_role |= PAN_ROLE_NAP_SERVER;
+ if (btpan_role & BTPAN_ROLE_PANU) bta_pan_role |= PAN_ROLE_CLIENT;
+ return bta_pan_role;
+}
+
+static volatile int btpan_dev_local_role;
+#if (BTA_PAN_INCLUDED == TRUE)
+static tBTA_PAN_ROLE_INFO bta_panu_info = {PANU_SERVICE_NAME, 0, PAN_SECURITY};
+static tBTA_PAN_ROLE_INFO bta_pan_nap_info = {PAN_NAP_SERVICE_NAME, 1,
+ PAN_SECURITY};
+#endif
+
+static bt_status_t btpan_enable(int local_role) {
+#if (BTA_PAN_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG("%s - local_role: %d", __func__, local_role);
+ int bta_pan_role = btpan_role_to_bta(local_role);
+ BTA_PanSetRole(bta_pan_role, &bta_panu_info, NULL, &bta_pan_nap_info);
+ btpan_dev_local_role = local_role;
+ return BT_STATUS_SUCCESS;
+#else
+ return BT_STATUS_FAIL;
+#endif
+}
+
+static int btpan_get_local_role() {
+ BTIF_TRACE_DEBUG("btpan_dev_local_role:%d", btpan_dev_local_role);
+ return btpan_dev_local_role;
+}
+
+static bt_status_t btpan_connect(const bt_bdaddr_t* bd_addr, int local_role,
+ int remote_role) {
+ BTIF_TRACE_DEBUG("local_role:%d, remote_role:%d", local_role, remote_role);
+ int bta_local_role = btpan_role_to_bta(local_role);
+ int bta_remote_role = btpan_role_to_bta(remote_role);
+ btpan_new_conn(-1, bd_addr->address, bta_local_role, bta_remote_role);
+ BTA_PanOpen((uint8_t*)bd_addr->address, bta_local_role, bta_remote_role);
+ return BT_STATUS_SUCCESS;
+}
+
+static void btif_in_pan_generic_evt(uint16_t event, char* p_param) {
+ BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
+ switch (event) {
+ case BTIF_PAN_CB_DISCONNECTING: {
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)p_param;
+ btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+ int btpan_conn_local_role;
+ int btpan_remote_role;
+ asrt(conn != NULL);
+ if (conn) {
+ btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(BTPAN_STATE_DISCONNECTING,
+ BT_STATUS_SUCCESS,
+ (const bt_bdaddr_t*)conn->peer,
+ btpan_conn_local_role, btpan_remote_role);
+ }
+ } break;
+ default: {
+ BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
+ } break;
+ }
+}
+
+static bt_status_t btpan_disconnect(const bt_bdaddr_t* bd_addr) {
+ btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
+ if (conn && conn->handle >= 0) {
+ /* Inform the application that the disconnect has been initiated
+ * successfully */
+ btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
+ (char*)bd_addr, sizeof(bt_bdaddr_t), NULL);
+ BTA_PanClose(conn->handle);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+static int pan_pth = -1;
+void create_tap_read_thread(int tap_fd) {
+ if (pan_pth < 0) pan_pth = btsock_thread_create(btpan_tap_fd_signaled, NULL);
+ if (pan_pth >= 0)
+ btsock_thread_add_fd(pan_pth, tap_fd, 0, SOCK_THREAD_FD_RD, 0);
+}
+
+void destroy_tap_read_thread(void) {
+ if (pan_pth >= 0) {
+ btsock_thread_exit(pan_pth);
+ pan_pth = -1;
+ }
+}
+
+static int tap_if_up(const char* devname, const bt_bdaddr_t* addr) {
+ struct ifreq ifr;
+ int sk, err;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sk < 0) return -1;
+
+ // set mac addr
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+ err = ioctl(sk, SIOCGIFHWADDR, &ifr);
+ if (err < 0) {
+ BTIF_TRACE_ERROR(
+ "Could not get network hardware for interface:%s, errno:%s", devname,
+ strerror(errno));
+ close(sk);
+ return -1;
+ }
+
+ strncpy(ifr.ifr_name, devname, IFNAMSIZ - 1);
+ memcpy(ifr.ifr_hwaddr.sa_data, addr->address, 6);
+
+ /* The IEEE has specified that the most significant bit of the most
+ * significant byte is used to
+ * determine a multicast address. If its a 1, that means multicast, 0 means
+ * unicast.
+ * Kernel returns an error if we try to set a multicast address for the
+ * tun-tap ethernet interface.
+ * Mask this bit to avoid any issue with auto generated address.
+ */
+ if (ifr.ifr_hwaddr.sa_data[0] & 0x01) {
+ BTIF_TRACE_WARNING(
+ "Not a unicast MAC address, force multicast bit flipping");
+ ifr.ifr_hwaddr.sa_data[0] &= ~0x01;
+ }
+
+ err = ioctl(sk, SIOCSIFHWADDR, (caddr_t)&ifr);
+
+ if (err < 0) {
+ BTIF_TRACE_ERROR("Could not set bt address for interface:%s, errno:%s",
+ devname, strerror(errno));
+ close(sk);
+ return -1;
+ }
+
+ // bring it up
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+ ifr.ifr_flags |= IFF_UP;
+ ifr.ifr_flags |= IFF_MULTICAST;
+
+ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t)&ifr);
+
+ if (err < 0) {
+ BTIF_TRACE_ERROR("Could not bring up network interface:%s, errno:%d",
+ devname, errno);
+ close(sk);
+ return -1;
+ }
+ close(sk);
+ BTIF_TRACE_DEBUG("network interface: %s is up", devname);
+ return 0;
+}
+
+static int tap_if_down(const char* devname) {
+ struct ifreq ifr;
+ int sk;
+
+ sk = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sk < 0) return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ ioctl(sk, SIOCSIFFLAGS, (caddr_t)&ifr);
+
+ close(sk);
+
+ return 0;
+}
+
+void btpan_set_flow_control(bool enable) {
+ if (btpan_cb.tap_fd == -1) return;
+
+ btpan_cb.flow = enable;
+ if (enable) {
+ btsock_thread_add_fd(pan_pth, btpan_cb.tap_fd, 0, SOCK_THREAD_FD_RD, 0);
+ bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(btpan_cb.tap_fd));
+ }
+}
+
+int btpan_tap_open() {
+ struct ifreq ifr;
+ int fd, err;
+ const char* clonedev = "/dev/tun";
+
+ /* open the clone device */
+
+ fd = open(clonedev, O_RDWR);
+ if (fd < 0) {
+ BTIF_TRACE_DEBUG("could not open %s, err:%d", clonedev, errno);
+ return fd;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+ strncpy(ifr.ifr_name, TAP_IF_NAME, IFNAMSIZ);
+
+ /* try to create the device */
+ err = ioctl(fd, TUNSETIFF, (void*)&ifr);
+ if (err < 0) {
+ BTIF_TRACE_DEBUG("ioctl error:%d, errno:%s", err, strerror(errno));
+ close(fd);
+ return err;
+ }
+ if (tap_if_up(TAP_IF_NAME, controller_get_interface()->get_address()) == 0) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ return fd;
+ }
+ BTIF_TRACE_ERROR("can not bring up tap interface:%s", TAP_IF_NAME);
+ close(fd);
+ return INVALID_FD;
+}
+
+int btpan_tap_send(int tap_fd, const BD_ADDR src, const BD_ADDR dst,
+ uint16_t proto, const char* buf, uint16_t len,
+ UNUSED_ATTR bool ext, UNUSED_ATTR bool forward) {
+ if (tap_fd != INVALID_FD) {
+ tETH_HDR eth_hdr;
+ memcpy(&eth_hdr.h_dest, dst, ETH_ADDR_LEN);
+ memcpy(&eth_hdr.h_src, src, ETH_ADDR_LEN);
+ eth_hdr.h_proto = htons(proto);
+ char packet[TAP_MAX_PKT_WRITE_LEN + sizeof(tETH_HDR)];
+ memcpy(packet, &eth_hdr, sizeof(tETH_HDR));
+ if (len > TAP_MAX_PKT_WRITE_LEN) {
+ LOG_ERROR(LOG_TAG, "btpan_tap_send eth packet size:%d is exceeded limit!",
+ len);
+ return -1;
+ }
+ memcpy(packet + sizeof(tETH_HDR), buf, len);
+
+ /* Send data to network interface */
+ ssize_t ret;
+ OSI_NO_INTR(ret = write(tap_fd, packet, len + sizeof(tETH_HDR)));
+ BTIF_TRACE_DEBUG("ret:%d", ret);
+ return (int)ret;
+ }
+ return -1;
+}
+
+int btpan_tap_close(int fd) {
+ if (tap_if_down(TAP_IF_NAME) == 0) close(fd);
+ if (pan_pth >= 0) btsock_thread_wakeup(pan_pth);
+ return 0;
+}
+
+btpan_conn_t* btpan_find_conn_handle(uint16_t handle) {
+ for (int i = 0; i < MAX_PAN_CONNS; i++) {
+ if (btpan_cb.conns[i].handle == handle) return &btpan_cb.conns[i];
+ }
+ return NULL;
+}
+
+btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr) {
+ for (int i = 0; i < MAX_PAN_CONNS; i++) {
+ if (memcmp(btpan_cb.conns[i].peer, addr, sizeof(BD_ADDR)) == 0)
+ return &btpan_cb.conns[i];
+ }
+ return NULL;
+}
+
+static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN* p_data) {
+ BTIF_TRACE_API(
+ "btpan_open_conn: local_role:%d, peer_role: %d, handle:%d, conn: %p",
+ p_data->open.local_role, p_data->open.peer_role, p_data->open.handle,
+ conn);
+
+ if (conn == NULL)
+ conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr,
+ p_data->open.local_role, p_data->open.peer_role);
+ if (conn) {
+ BTIF_TRACE_DEBUG(
+ "btpan_open_conn:tap_fd:%d, open_count:%d, "
+ "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+ btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, p_data->open.handle,
+ conn->local_role, conn->remote_role);
+
+ btpan_cb.open_count++;
+ conn->handle = p_data->open.handle;
+ if (btpan_cb.tap_fd < 0) {
+ btpan_cb.tap_fd = btpan_tap_open();
+ if (btpan_cb.tap_fd >= 0) create_tap_read_thread(btpan_cb.tap_fd);
+ }
+
+ if (btpan_cb.tap_fd >= 0) {
+ btpan_cb.flow = 1;
+ conn->state = PAN_STATE_OPEN;
+ }
+ }
+}
+
+static void btpan_close_conn(btpan_conn_t* conn) {
+ BTIF_TRACE_API("btpan_close_conn: %p", conn);
+
+ if (conn && conn->state == PAN_STATE_OPEN) {
+ BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN");
+
+ conn->state = PAN_STATE_CLOSE;
+ btpan_cb.open_count--;
+
+ if (btpan_cb.open_count == 0) {
+ destroy_tap_read_thread();
+ if (btpan_cb.tap_fd != INVALID_FD) {
+ btpan_tap_close(btpan_cb.tap_fd);
+ btpan_cb.tap_fd = INVALID_FD;
+ }
+ }
+ }
+}
+
+static void btpan_cleanup_conn(btpan_conn_t* conn) {
+ if (conn) {
+ conn->handle = -1;
+ conn->state = -1;
+ memset(&conn->peer, 0, sizeof(conn->peer));
+ memset(&conn->eth_addr, 0, sizeof(conn->eth_addr));
+ conn->local_role = conn->remote_role = 0;
+ }
+}
+
+btpan_conn_t* btpan_new_conn(int handle, const BD_ADDR addr, int local_role,
+ int remote_role) {
+ for (int i = 0; i < MAX_PAN_CONNS; i++) {
+ BTIF_TRACE_DEBUG("conns[%d]:%d", i, btpan_cb.conns[i].handle);
+ if (btpan_cb.conns[i].handle == -1) {
+ BTIF_TRACE_DEBUG("handle:%d, local_role:%d, remote_role:%d", handle,
+ local_role, remote_role);
+
+ btpan_cb.conns[i].handle = handle;
+ bdcpy(btpan_cb.conns[i].peer, addr);
+ btpan_cb.conns[i].local_role = local_role;
+ btpan_cb.conns[i].remote_role = remote_role;
+ return &btpan_cb.conns[i];
+ }
+ }
+ BTIF_TRACE_DEBUG("MAX_PAN_CONNS:%d exceeded, return NULL as failed",
+ MAX_PAN_CONNS);
+ return NULL;
+}
+
+void btpan_close_handle(btpan_conn_t* p) {
+ BTIF_TRACE_DEBUG("btpan_close_handle : close handle %d", p->handle);
+ p->handle = -1;
+ p->local_role = -1;
+ p->remote_role = -1;
+ memset(&p->peer, 0, 6);
+}
+
+static inline bool should_forward(tETH_HDR* hdr) {
+ uint16_t proto = ntohs(hdr->h_proto);
+ if (proto == ETH_P_IP || proto == ETH_P_ARP || proto == ETH_P_IPV6)
+ return true;
+ BTIF_TRACE_DEBUG("unknown proto:%x", proto);
+ return false;
+}
+
+static int forward_bnep(tETH_HDR* eth_hdr, BT_HDR* hdr) {
+ int broadcast = eth_hdr->h_dest[0] & 1;
+
+ // Find the right connection to send this frame over.
+ for (int i = 0; i < MAX_PAN_CONNS; i++) {
+ uint16_t handle = btpan_cb.conns[i].handle;
+ if (handle != (uint16_t)-1 &&
+ (broadcast ||
+ memcmp(btpan_cb.conns[i].eth_addr, eth_hdr->h_dest, sizeof(BD_ADDR)) ==
+ 0 ||
+ memcmp(btpan_cb.conns[i].peer, eth_hdr->h_dest, sizeof(BD_ADDR)) ==
+ 0)) {
+ int result = PAN_WriteBuf(handle, eth_hdr->h_dest, eth_hdr->h_src,
+ ntohs(eth_hdr->h_proto), hdr, 0);
+ switch (result) {
+ case PAN_Q_SIZE_EXCEEDED:
+ return FORWARD_CONGEST;
+ case PAN_SUCCESS:
+ return FORWARD_SUCCESS;
+ default:
+ return FORWARD_FAILURE;
+ }
+ }
+ }
+ osi_free(hdr);
+ return FORWARD_IGNORE;
+}
+
+static void bta_pan_callback_transfer(uint16_t event, char* p_param) {
+ tBTA_PAN* p_data = (tBTA_PAN*)p_param;
+
+ switch (event) {
+ case BTA_PAN_ENABLE_EVT:
+ BTIF_TRACE_DEBUG("BTA_PAN_ENABLE_EVT");
+ break;
+ case BTA_PAN_SET_ROLE_EVT: {
+ int btpan_role = bta_role_to_btpan(p_data->set_role.role);
+ bt_status_t status = p_data->set_role.status == BTA_PAN_SUCCESS
+ ? BT_STATUS_SUCCESS
+ : BT_STATUS_FAIL;
+ btpan_control_state_t state =
+ btpan_role == 0 ? BTPAN_STATE_DISABLED : BTPAN_STATE_ENABLED;
+ callback.control_state_cb(state, btpan_role, status, TAP_IF_NAME);
+ break;
+ }
+ case BTA_PAN_OPENING_EVT: {
+ btpan_conn_t* conn;
+ bdstr_t bds;
+ bdaddr_to_string((bt_bdaddr_t*)p_data->opening.bd_addr, bds, sizeof(bds));
+ BTIF_TRACE_DEBUG("BTA_PAN_OPENING_EVT handle %d, addr: %s",
+ p_data->opening.handle, bds);
+ conn = btpan_find_conn_addr(p_data->opening.bd_addr);
+
+ asrt(conn != NULL);
+ if (conn) {
+ conn->handle = p_data->opening.handle;
+ int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(
+ BTPAN_STATE_CONNECTING, BT_STATUS_SUCCESS,
+ (const bt_bdaddr_t*)p_data->opening.bd_addr, btpan_conn_local_role,
+ btpan_remote_role);
+ } else
+ BTIF_TRACE_ERROR("connection not found");
+ break;
+ }
+ case BTA_PAN_OPEN_EVT: {
+ btpan_connection_state_t state;
+ bt_status_t status;
+ btpan_conn_t* conn = btpan_find_conn_handle(p_data->open.handle);
+
+ LOG_VERBOSE(LOG_TAG, "%s pan connection open status: %d", __func__,
+ p_data->open.status);
+ if (p_data->open.status == BTA_PAN_SUCCESS) {
+ state = BTPAN_STATE_CONNECTED;
+ status = BT_STATUS_SUCCESS;
+ btpan_open_conn(conn, p_data);
+ } else {
+ state = BTPAN_STATE_DISCONNECTED;
+ status = BT_STATUS_FAIL;
+ btpan_cleanup_conn(conn);
+ }
+ /* debug("BTA_PAN_OPEN_EVT handle:%d, conn:%p", p_data->open.handle,
+ * conn); */
+ /* debug("conn bta local_role:%d, bta remote role:%d", conn->local_role,
+ * conn->remote_role); */
+ int btpan_conn_local_role = bta_role_to_btpan(p_data->open.local_role);
+ int btpan_remote_role = bta_role_to_btpan(p_data->open.peer_role);
+ callback.connection_state_cb(state, status,
+ (const bt_bdaddr_t*)p_data->open.bd_addr,
+ btpan_conn_local_role, btpan_remote_role);
+ break;
+ }
+ case BTA_PAN_CLOSE_EVT: {
+ LOG_INFO(LOG_TAG, "%s: event = BTA_PAN_CLOSE_EVT handle %d", __func__,
+ p_data->close.handle);
+ btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
+ btpan_close_conn(conn);
+
+ if (conn && conn->handle >= 0) {
+ int btpan_conn_local_role = bta_role_to_btpan(conn->local_role);
+ int btpan_remote_role = bta_role_to_btpan(conn->remote_role);
+ callback.connection_state_cb(BTPAN_STATE_DISCONNECTED, (bt_status_t)0,
+ (const bt_bdaddr_t*)conn->peer,
+ btpan_conn_local_role, btpan_remote_role);
+ btpan_cleanup_conn(conn);
+ } else
+ BTIF_TRACE_ERROR("pan handle not found (%d)", p_data->close.handle);
+ break;
+ }
+ default:
+ BTIF_TRACE_WARNING("Unknown pan event %d", event);
+ break;
+ }
+}
+
+static void bta_pan_callback(tBTA_PAN_EVT event, tBTA_PAN* p_data) {
+ btif_transfer_context(bta_pan_callback_transfer, event, (char*)p_data,
+ sizeof(tBTA_PAN), NULL);
+}
+
+#define IS_EXCEPTION(e) ((e) & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL))
+static void btu_exec_tap_fd_read(void* p_param) {
+ struct pollfd ufd;
+ int fd = PTR_TO_INT(p_param);
+
+ if (fd == INVALID_FD || fd != btpan_cb.tap_fd) return;
+
+ // Don't occupy BTU context too long, avoid buffer overruns and
+ // give other profiles a chance to run by limiting the amount of memory
+ // PAN can use.
+ for (int i = 0; i < PAN_BUF_MAX && btif_is_enabled() && btpan_cb.flow; i++) {
+ BT_HDR* buffer = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+ buffer->offset = PAN_MINIMUM_OFFSET;
+ buffer->len = PAN_BUF_SIZE - sizeof(BT_HDR) - buffer->offset;
+
+ uint8_t* packet = (uint8_t*)buffer + sizeof(BT_HDR) + buffer->offset;
+
+ // If we don't have an undelivered packet left over, pull one from the TAP
+ // driver.
+ // We save it in the congest_packet right away in case we can't deliver it
+ // in this
+ // attempt.
+ if (!btpan_cb.congest_packet_size) {
+ ssize_t ret;
+ OSI_NO_INTR(ret = read(fd, btpan_cb.congest_packet,
+ sizeof(btpan_cb.congest_packet)));
+ switch (ret) {
+ case -1:
+ BTIF_TRACE_ERROR("%s unable to read from driver: %s", __func__,
+ strerror(errno));
+ osi_free(buffer);
+ // add fd back to monitor thread to try it again later
+ btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+ return;
+ case 0:
+ BTIF_TRACE_WARNING("%s end of file reached.", __func__);
+ osi_free(buffer);
+ // add fd back to monitor thread to process the exception
+ btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+ return;
+ default:
+ btpan_cb.congest_packet_size = ret;
+ break;
+ }
+ }
+
+ memcpy(packet, btpan_cb.congest_packet,
+ MIN(btpan_cb.congest_packet_size, buffer->len));
+ buffer->len = MIN(btpan_cb.congest_packet_size, buffer->len);
+
+ if (buffer->len > sizeof(tETH_HDR) && should_forward((tETH_HDR*)packet)) {
+ // Extract the ethernet header from the buffer since the PAN_WriteBuf
+ // inside
+ // forward_bnep can't handle two pointers that point inside the same GKI
+ // buffer.
+ tETH_HDR hdr;
+ memcpy(&hdr, packet, sizeof(tETH_HDR));
+
+ // Skip the ethernet header.
+ buffer->len -= sizeof(tETH_HDR);
+ buffer->offset += sizeof(tETH_HDR);
+ if (forward_bnep(&hdr, buffer) != FORWARD_CONGEST)
+ btpan_cb.congest_packet_size = 0;
+ } else {
+ BTIF_TRACE_WARNING("%s dropping packet of length %d", __func__,
+ buffer->len);
+ btpan_cb.congest_packet_size = 0;
+ osi_free(buffer);
+ }
+
+ // Bail out of the loop if reading from the TAP fd would block.
+ ufd.fd = fd;
+ ufd.events = POLLIN;
+ ufd.revents = 0;
+
+ int ret;
+ OSI_NO_INTR(ret = poll(&ufd, 1, 0));
+ if (ret <= 0 || IS_EXCEPTION(ufd.revents)) break;
+ }
+
+ if (btpan_cb.flow) {
+ // add fd back to monitor thread when the flow is on
+ btsock_thread_add_fd(pan_pth, fd, 0, SOCK_THREAD_FD_RD, 0);
+ }
+}
+
+static void btif_pan_close_all_conns() {
+ if (!stack_initialized) return;
+
+ for (int i = 0; i < MAX_PAN_CONNS; ++i) {
+ if (btpan_cb.conns[i].handle != -1) BTA_PanClose(btpan_cb.conns[i].handle);
+ }
+}
+
+static void btpan_tap_fd_signaled(int fd, int type, int flags,
+ uint32_t user_id) {
+ CHECK(btpan_cb.tap_fd == INVALID_FD || btpan_cb.tap_fd == fd);
+
+ if (btpan_cb.tap_fd != fd) {
+ BTIF_TRACE_WARNING("%s Signaled on mismatched fds exp:%d act:%d\n",
+ __func__, btpan_cb.tap_fd, fd);
+ return;
+ }
+
+ if (flags & SOCK_THREAD_FD_EXCEPTION) {
+ btpan_cb.tap_fd = INVALID_FD;
+ btpan_tap_close(fd);
+ btif_pan_close_all_conns();
+ } else if (flags & SOCK_THREAD_FD_RD)
+ bta_dmexecutecallback(btu_exec_tap_fd_read, INT_TO_PTR(fd));
+}
diff --git a/mtkbt/code/bt/btif/src/btif_profile_queue.cc b/mtkbt/code/bt/btif/src/btif_profile_queue.cc
new file mode 100755
index 0000000..1346092
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_profile_queue.cc
@@ -0,0 +1,175 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_profile_queue.c
+ *
+ * Description: Bluetooth remote device connection queuing implementation.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_queue"
+
+#include "btif_profile_queue.h"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "btif_common.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "stack_manager.h"
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+
+typedef enum {
+ BTIF_QUEUE_CONNECT_EVT,
+ BTIF_QUEUE_ADVANCE_EVT,
+} btif_queue_event_t;
+
+typedef struct {
+ bt_bdaddr_t bda;
+ uint16_t uuid;
+ bool busy;
+ btif_connect_cb_t connect_cb;
+} connect_node_t;
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+static list_t* connect_queue;
+
+static const size_t MAX_REASONABLE_REQUESTS = 10;
+
+/*******************************************************************************
+ * Queue helper functions
+ ******************************************************************************/
+
+static void queue_int_add(connect_node_t* p_param) {
+ if (!connect_queue) {
+ connect_queue = list_new(osi_free);
+ CHECK(connect_queue != NULL);
+ }
+
+ // Sanity check to make sure we're not leaking connection requests
+ CHECK(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
+
+ for (const list_node_t* node = list_begin(connect_queue);
+ node != list_end(connect_queue); node = list_next(node)) {
+ if (((connect_node_t*)list_node(node))->uuid == p_param->uuid) {
+ LOG_INFO(LOG_TAG, "%s dropping duplicate connect request for uuid: %04x",
+ __func__, p_param->uuid);
+ return;
+ }
+ }
+
+ connect_node_t* p_node = (connect_node_t*)osi_malloc(sizeof(connect_node_t));
+ memcpy(p_node, p_param, sizeof(connect_node_t));
+ list_append(connect_queue, p_node);
+}
+
+static void queue_int_advance() {
+ if (connect_queue && !list_is_empty(connect_queue))
+ list_remove(connect_queue, list_front(connect_queue));
+}
+
+static void queue_int_handle_evt(uint16_t event, char* p_param) {
+ switch (event) {
+ case BTIF_QUEUE_CONNECT_EVT:
+ queue_int_add((connect_node_t*)p_param);
+ break;
+
+ case BTIF_QUEUE_ADVANCE_EVT:
+ queue_int_advance();
+ break;
+ }
+
+ if (stack_manager_get_interface()->get_stack_is_running())
+ btif_queue_connect_next();
+}
+
+/*******************************************************************************
+ *
+ * Function btif_queue_connect
+ *
+ * Description Add a new connection to the queue and trigger the next
+ * scheduled connection.
+ *
+ * Returns BT_STATUS_SUCCESS if successful
+ *
+ ******************************************************************************/
+bt_status_t btif_queue_connect(uint16_t uuid, const bt_bdaddr_t* bda,
+ btif_connect_cb_t connect_cb) {
+ connect_node_t node;
+ memset(&node, 0, sizeof(connect_node_t));
+ memcpy(&node.bda, bda, sizeof(bt_bdaddr_t));
+ node.uuid = uuid;
+ node.connect_cb = connect_cb;
+
+ return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,
+ (char*)&node, sizeof(connect_node_t), NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_queue_advance
+ *
+ * Description Clear the queue's busy status and advance to the next
+ * scheduled connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_queue_advance() {
+ btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_ADVANCE_EVT, NULL, 0,
+ NULL);
+}
+
+// This function dispatches the next pending connect request. It is called from
+// stack_manager when the stack comes up.
+bt_status_t btif_queue_connect_next(void) {
+ if (!connect_queue || list_is_empty(connect_queue)) return BT_STATUS_FAIL;
+
+ connect_node_t* p_head = (connect_node_t*)list_front(connect_queue);
+
+ // If the queue is currently busy, we return success anyway,
+ // since the connection has been queued...
+ if (p_head->busy) return BT_STATUS_SUCCESS;
+
+ p_head->busy = true;
+ return p_head->connect_cb(&p_head->bda, p_head->uuid);
+}
+
+/*******************************************************************************
+ *
+ * Function btif_queue_release
+ *
+ * Description Free up all the queue nodes and set the queue head to NULL
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btif_queue_release() {
+ list_free(connect_queue);
+ connect_queue = NULL;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_rc.cc b/mtkbt/code/bt/btif/src/btif_rc.cc
new file mode 100755
index 0000000..d6cdd34
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_rc.cc
@@ -0,0 +1,5522 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*****************************************************************************
+ *
+ * Filename: btif_rc.cc
+ *
+ * Description: Bluetooth AVRC implementation
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btif_avrc"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_rc.h>
+
+#include "avrc_defs.h"
+#include "bdaddr.h"
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "btif_av.h"
+#include "btif_common.h"
+#include "btif_util.h"
+#include "btu.h"
+#include "device/include/interop.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#define RC_INVALID_TRACK_ID (0xFFFFFFFFFFFFFFFFULL)
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+/* cod value for Headsets */
+#define COD_AV_HEADSETS 0x0404
+/* for AVRC 1.4 need to change this */
+#define MAX_RC_NOTIFICATIONS AVRC_EVT_VOLUME_CHANGE
+
+#define IDX_GET_PLAY_STATUS_RSP 0
+#define IDX_LIST_APP_ATTR_RSP 1
+#define IDX_LIST_APP_VALUE_RSP 2
+#define IDX_GET_CURR_APP_VAL_RSP 3
+#define IDX_SET_APP_VAL_RSP 4
+#define IDX_GET_APP_ATTR_TXT_RSP 5
+#define IDX_GET_APP_VAL_TXT_RSP 6
+#define IDX_GET_ELEMENT_ATTR_RSP 7
+#define IDX_SET_ADDR_PLAYER_RSP 8
+#define IDX_SET_BROWSED_PLAYER_RSP 9
+#define IDX_GET_FOLDER_ITEMS_RSP 10
+#define IDX_CHG_PATH_RSP 11
+#define IDX_GET_ITEM_ATTR_RSP 12
+#define IDX_PLAY_ITEM_RSP 13
+#define IDX_GET_TOTAL_NUM_OF_ITEMS_RSP 14
+#define IDX_SEARCH_RSP 15
+#define IDX_ADD_TO_NOW_PLAYING_RSP 16
+
+/* Update MAX value whenever IDX will be changed */
+#define MAX_CMD_QUEUE_LEN 17
+
+#define MAX_VOLUME 128
+#define MAX_LABEL 16
+#define MAX_TRANSACTIONS_PER_SESSION 16
+#define PLAY_STATUS_PLAYING 1
+#define BTIF_RC_NUM_CONN BT_RC_NUM_APP
+
+#define CHECK_RC_CONNECTED(p_dev) \
+ do { \
+ if ((p_dev) == NULL || (p_dev)->rc_connected == false) { \
+ BTIF_TRACE_WARNING("%s: called when RC is not connected", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+#define CHECK_BR_CONNECTED(p_dev) \
+ do { \
+ if ((p_dev) == NULL || (p_dev)->br_connected == false) { \
+ BTIF_TRACE_WARNING("%s: called when BR is not connected", __func__); \
+ return BT_STATUS_NOT_READY; \
+ } \
+ } while (0)
+
+/*****************************************************************************
+ * Local type definitions
+ *****************************************************************************/
+typedef struct {
+ uint8_t bNotify;
+ uint8_t label;
+} btif_rc_reg_notifications_t;
+
+typedef struct {
+ uint8_t label;
+ uint8_t ctype;
+ bool is_rsp_pending;
+} btif_rc_cmd_ctxt_t;
+
+/* 2 second timeout to get interim response */
+#define BTIF_TIMEOUT_RC_INTERIM_RSP_MS (2 * 1000)
+#define BTIF_TIMEOUT_RC_STATUS_CMD_MS (2 * 1000)
+#define BTIF_TIMEOUT_RC_CONTROL_CMD_MS (2 * 1000)
+
+typedef enum {
+ eNOT_REGISTERED,
+ eREGISTERED,
+ eINTERIM
+} btif_rc_nfn_reg_status_t;
+
+typedef struct {
+ uint8_t event_id;
+ uint8_t label;
+ btif_rc_nfn_reg_status_t status;
+} btif_rc_supported_event_t;
+
+#define BTIF_RC_STS_TIMEOUT 0xFE
+typedef struct {
+ uint8_t label;
+ uint8_t pdu_id;
+} btif_rc_status_cmd_timer_t;
+
+typedef struct {
+ uint8_t label;
+ uint8_t pdu_id;
+} btif_rc_control_cmd_timer_t;
+
+typedef struct {
+ union {
+ btif_rc_status_cmd_timer_t rc_status_cmd;
+ btif_rc_control_cmd_timer_t rc_control_cmd;
+ };
+ BD_ADDR rc_addr;
+} btif_rc_timer_context_t;
+
+typedef struct {
+ bool query_started;
+ uint8_t num_attrs;
+ uint8_t num_ext_attrs;
+
+ uint8_t attr_index;
+ uint8_t ext_attr_index;
+ uint8_t ext_val_index;
+ btrc_player_app_attr_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btrc_player_app_ext_attr_t ext_attrs[AVRC_MAX_APP_ATTR_SIZE];
+} btif_rc_player_app_settings_t;
+
+/* TODO : Merge btif_rc_reg_notifications_t and btif_rc_cmd_ctxt_t to a single
+ * struct */
+typedef struct {
+ bool rc_connected;
+ bool br_connected; // Browsing channel.
+ uint8_t rc_handle;
+ tBTA_AV_FEAT rc_features;
+ btrc_connection_state_t rc_state;
+ BD_ADDR rc_addr;
+ uint16_t rc_pending_play;
+ btif_rc_cmd_ctxt_t rc_pdu_info[MAX_CMD_QUEUE_LEN];
+ btif_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS];
+ unsigned int rc_volume;
+ uint8_t rc_vol_label;
+ list_t* rc_supported_event_list;
+ btif_rc_player_app_settings_t rc_app_settings;
+ alarm_t* rc_play_status_timer;
+ bool rc_features_processed;
+ uint64_t rc_playing_uid;
+ bool rc_procedure_complete;
+
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ bool rc_disalbe_song_pos;
+#endif
+/** @} */
+} btif_rc_device_cb_t;
+
+typedef struct {
+ std::mutex lock;
+ btif_rc_device_cb_t rc_multi_cb[BTIF_RC_NUM_CONN];
+} rc_cb_t;
+
+typedef struct {
+ bool in_use;
+ uint8_t lbl;
+ uint8_t handle;
+ btif_rc_timer_context_t txn_timer_context;
+ alarm_t* txn_timer;
+} rc_transaction_t;
+
+typedef struct {
+ std::recursive_mutex lbllock;
+ rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION];
+} rc_device_t;
+
+typedef struct {
+ uint8_t label;
+ BD_ADDR rc_addr;
+} rc_context_t;
+
+typedef struct { uint8_t handle; } btif_rc_handle_t;
+
+rc_device_t device;
+
+static void sleep_ms(period_ms_t timeout_ms);
+
+/* Response status code - Unknown Error - this is changed to "reserved" */
+#define BTIF_STS_GEN_ERROR 0x06
+
+/* Utility table to map hal status codes to bta status codes for the response
+ * status */
+static const uint8_t status_code_map[] = {
+ /* BTA_Status codes HAL_Status codes */
+ AVRC_STS_BAD_CMD, /* BTRC_STS_BAD_CMD */
+ AVRC_STS_BAD_PARAM, /* BTRC_STS_BAD_PARAM */
+ AVRC_STS_NOT_FOUND, /* BTRC_STS_NOT_FOUND */
+ AVRC_STS_INTERNAL_ERR, /* BTRC_STS_INTERNAL_ERR */
+ AVRC_STS_NO_ERROR, /* BTRC_STS_NO_ERROR */
+ AVRC_STS_UID_CHANGED, /* BTRC_STS_UID_CHANGED */
+ BTIF_STS_GEN_ERROR, /* BTRC_STS_RESERVED */
+ AVRC_STS_BAD_DIR, /* BTRC_STS_INV_DIRN */
+ AVRC_STS_NOT_DIR, /* BTRC_STS_INV_DIRECTORY */
+ AVRC_STS_NOT_EXIST, /* BTRC_STS_INV_ITEM */
+ AVRC_STS_BAD_SCOPE, /* BTRC_STS_INV_SCOPE */
+ AVRC_STS_BAD_RANGE, /* BTRC_STS_INV_RANGE */
+ AVRC_STS_UID_IS_DIR, /* BTRC_STS_DIRECTORY */
+ AVRC_STS_IN_USE, /* BTRC_STS_MEDIA_IN_USE */
+ AVRC_STS_NOW_LIST_FULL, /* BTRC_STS_PLAY_LIST_FULL */
+ AVRC_STS_SEARCH_NOT_SUP, /* BTRC_STS_SRCH_NOT_SPRTD */
+ AVRC_STS_SEARCH_BUSY, /* BTRC_STS_SRCH_IN_PROG */
+ AVRC_STS_BAD_PLAYER_ID, /* BTRC_STS_INV_PLAYER */
+ AVRC_STS_PLAYER_N_BR, /* BTRC_STS_PLAY_NOT_BROW */
+ AVRC_STS_PLAYER_N_ADDR, /* BTRC_STS_PLAY_NOT_ADDR */
+ AVRC_STS_BAD_SEARCH_RES, /* BTRC_STS_INV_RESULTS */
+ AVRC_STS_NO_AVAL_PLAYER, /* BTRC_STS_NO_AVBL_PLAY */
+ AVRC_STS_ADDR_PLAYER_CHG, /* BTRC_STS_ADDR_PLAY_CHGD */
+};
+
+static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu,
+ uint8_t status, uint8_t opcode);
+static uint8_t opcode_from_pdu(uint8_t pdu);
+static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index,
+ uint8_t label, tBTA_AV_CODE code,
+ tAVRC_RESPONSE* pmetamsg_resp);
+static void register_volumechange(uint8_t label, btif_rc_device_cb_t* p_dev);
+static void lbl_init();
+static void init_all_transactions();
+static bt_status_t get_transaction(rc_transaction_t** ptransaction);
+static void release_transaction(uint8_t label);
+static rc_transaction_t* get_transaction_by_lbl(uint8_t label);
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
+ btif_rc_device_cb_t* p_dev);
+
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg);
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg);
+static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event,
+ tAVRC_COMMAND* pavrc_cmd,
+ uint8_t label,
+ btif_rc_device_cb_t* p_dev);
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev);
+static void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev);
+static void register_for_event_notification(btif_rc_supported_event_t* p_event,
+ btif_rc_device_cb_t* p_dev);
+static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_CAPS_RSP* p_rsp);
+static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_LIST_APP_ATTR_RSP* p_rsp);
+static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_LIST_APP_VALUES_RSP* p_rsp);
+static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_CUR_APP_VALUE_RSP* p_rsp);
+static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
+static void handle_app_attr_val_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp);
+static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_PLAY_STATUS_RSP* p_rsp);
+static void handle_set_addressed_player_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_RSP* p_rsp);
+static void handle_get_elem_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_ATTRS_RSP* p_rsp);
+static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_RSP* p_rsp);
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_attr_text_cmd(
+ uint8_t* attrs, uint8_t num_attrs, btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_value_text_cmd(
+ uint8_t* vals, uint8_t num_vals, btif_rc_device_cb_t* p_dev);
+static bt_status_t register_notification_cmd(uint8_t label, uint8_t event_id,
+ uint32_t event_value,
+ btif_rc_device_cb_t* p_dev);
+static bt_status_t get_element_attribute_cmd(uint8_t num_attribute,
+ uint32_t* p_attr_ids,
+ btif_rc_device_cb_t* p_dev);
+static bt_status_t getcapabilities_cmd(uint8_t cap_id,
+ btif_rc_device_cb_t* p_dev);
+static bt_status_t list_player_app_setting_attrib_cmd(
+ btif_rc_device_cb_t* p_dev);
+static bt_status_t list_player_app_setting_value_cmd(
+ uint8_t attrib_id, btif_rc_device_cb_t* p_dev);
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib,
+ uint8_t* attrib_ids,
+ btif_rc_device_cb_t* p_dev);
+void get_folder_item_type_media(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item);
+void get_folder_item_type_folder(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item);
+void get_folder_item_type_player(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item);
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+ uint8_t start_item, uint8_t num_items);
+
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* p_param,
+ uint8_t ctype, uint8_t label,
+ btif_rc_device_cb_t* p_dev);
+
+static void btif_rc_upstreams_rsp_evt(uint16_t event,
+ tAVRC_RESPONSE* pavrc_resp, uint8_t ctype,
+ uint8_t label,
+ btif_rc_device_cb_t* p_dev);
+
+static void rc_start_play_status_timer(btif_rc_device_cb_t* p_dev);
+static bool absolute_volume_disabled(void);
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+static rc_cb_t btif_rc_cb;
+static btrc_callbacks_t* bt_rc_callbacks = NULL;
+static btrc_ctrl_callbacks_t* bt_rc_ctrl_callbacks = NULL;
+
+/*****************************************************************************
+ * Static functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Externs
+ *****************************************************************************/
+extern bool btif_hf_call_terminated_recently();
+extern bool check_cod(const bt_bdaddr_t* remote_bdaddr, uint32_t cod);
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ * Functions
+ *****************************************************************************/
+static btif_rc_device_cb_t* alloc_device() {
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ if (btif_rc_cb.rc_multi_cb[idx].rc_state ==
+ BTRC_CONNECTION_STATE_DISCONNECTED) {
+ return (&btif_rc_cb.rc_multi_cb[idx]);
+ }
+ }
+ return NULL;
+}
+
+static btif_rc_device_cb_t* get_connected_device(int index) {
+ BTIF_TRACE_DEBUG("%s: index: %d", __func__, index);
+ if (index > BTIF_RC_NUM_CONN) {
+ BTIF_TRACE_ERROR("%s: can't support more than %d connections", __func__,
+ BTIF_RC_NUM_CONN);
+ return NULL;
+ }
+ if (btif_rc_cb.rc_multi_cb[index].rc_state !=
+ BTRC_CONNECTION_STATE_CONNECTED) {
+ BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+ return NULL;
+ }
+ return (&btif_rc_cb.rc_multi_cb[index]);
+}
+
+static int get_num_connected_devices() {
+ int connected_devices = 0;
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ if (btif_rc_cb.rc_multi_cb[idx].rc_state ==
+ BTRC_CONNECTION_STATE_CONNECTED) {
+ connected_devices++;
+ }
+ }
+ BTIF_TRACE_DEBUG("%s: returning connected_devices: %d", __func__,
+ connected_devices);
+ return connected_devices;
+}
+
+btif_rc_device_cb_t* btif_rc_get_device_by_bda(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_DEBUG("%s: bd_addr: %02x-%02x-%02x-%02x-%02x-%02x", __func__,
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ if ((btif_rc_cb.rc_multi_cb[idx].rc_state !=
+ BTRC_CONNECTION_STATE_DISCONNECTED) &&
+ (bdcmp(btif_rc_cb.rc_multi_cb[idx].rc_addr, bd_addr->address) == 0)) {
+ return (&btif_rc_cb.rc_multi_cb[idx]);
+ }
+ }
+ BTIF_TRACE_ERROR("%s: device not found, returning NULL!", __func__);
+ return NULL;
+}
+
+btif_rc_device_cb_t* btif_rc_get_device_by_handle(uint8_t handle) {
+ BTIF_TRACE_DEBUG("%s: handle: 0x%x", __func__, handle);
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ if ((btif_rc_cb.rc_multi_cb[idx].rc_state !=
+ BTRC_CONNECTION_STATE_DISCONNECTED) &&
+ (btif_rc_cb.rc_multi_cb[idx].rc_handle == handle)) {
+ BTIF_TRACE_DEBUG("%s: btif_rc_cb.rc_multi_cb[idx].rc_handle: 0x%x",
+ __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+ return (&btif_rc_cb.rc_multi_cb[idx]);
+ }
+ }
+ BTIF_TRACE_ERROR("%s: returning NULL", __func__);
+ return NULL;
+}
+
+void fill_pdu_queue(int index, uint8_t ctype, uint8_t label, bool pending,
+ btif_rc_device_cb_t* p_dev) {
+ p_dev->rc_pdu_info[index].ctype = ctype;
+ p_dev->rc_pdu_info[index].label = label;
+ p_dev->rc_pdu_info[index].is_rsp_pending = pending;
+}
+
+void fill_avrc_attr_entry(tAVRC_ATTR_ENTRY* attr_vals, int num_attrs,
+ btrc_element_attr_val_t* p_attrs) {
+ for (int attr_cnt = 0; attr_cnt < num_attrs; attr_cnt++) {
+ attr_vals[attr_cnt].attr_id = p_attrs[attr_cnt].attr_id;
+ attr_vals[attr_cnt].name.charset_id = AVRC_CHARSET_ID_UTF8;
+ attr_vals[attr_cnt].name.str_len =
+ (uint16_t)strlen((char*)p_attrs[attr_cnt].text);
+ attr_vals[attr_cnt].name.p_str = p_attrs[attr_cnt].text;
+ BTIF_TRACE_DEBUG(
+ "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
+ (unsigned int)attr_vals[attr_cnt].attr_id,
+ attr_vals[attr_cnt].name.charset_id, attr_vals[attr_cnt].name.str_len,
+ attr_vals[attr_cnt].name.p_str);
+ }
+}
+
+void rc_cleanup_sent_cmd(void* p_data) { BTIF_TRACE_DEBUG("%s: ", __func__); }
+
+void handle_rc_ctrl_features(btif_rc_device_cb_t* p_dev) {
+ if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG) &&
+ (!(p_dev->rc_features & BTA_AV_FEAT_RCCT) ||
+ !(p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL))) {
+ return;
+ }
+
+ bt_bdaddr_t rc_addr;
+ int rc_features = 0;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if ((p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+ (p_dev->rc_features & BTA_AV_FEAT_RCCT)) {
+ rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME;
+ }
+
+ if ((p_dev->rc_features & BTA_AV_FEAT_METADATA) &&
+ (p_dev->rc_features & BTA_AV_FEAT_VENDOR) &&
+ (p_dev->rc_features_processed != true)) {
+ rc_features |= BTRC_FEAT_METADATA;
+
+ /* Mark rc features processed to avoid repeating
+ * the AVRCP procedure every time on receiving this
+ * update.
+ */
+ p_dev->rc_features_processed = true;
+ if (btif_av_is_sink_enabled()) {
+ getcapabilities_cmd(AVRC_CAP_COMPANY_ID, p_dev);
+ }
+ }
+
+ /* Add browsing feature capability */
+ if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+ rc_features |= BTRC_FEAT_BROWSE;
+ }
+
+ BTIF_TRACE_DEBUG("%s: Update rc features to CTRL: %d", __func__, rc_features);
+ HAL_CBACK(bt_rc_ctrl_callbacks, getrcfeatures_cb, &rc_addr, rc_features);
+}
+
+void handle_rc_features(btif_rc_device_cb_t* p_dev) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ bdstr_t addr1, addr2;
+
+ CHECK(bt_rc_callbacks);
+
+ btrc_remote_features_t rc_features = BTRC_FEAT_NONE;
+ bt_bdaddr_t avdtp_addr = btif_av_get_addr();
+
+ BTIF_TRACE_DEBUG("%s: AVDTP Address: %s AVCTP address: %s", __func__,
+ bdaddr_to_string(&avdtp_addr, addr1, sizeof(addr1)),
+ bdaddr_to_string(&rc_addr, addr2, sizeof(addr2)));
+
+ if (interop_match_addr(INTEROP_DISABLE_ABSOLUTE_VOLUME, &rc_addr) ||
+ absolute_volume_disabled() ||
+ bdcmp(avdtp_addr.address, rc_addr.address)) {
+ p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+ }
+
+ if (p_dev->rc_features & BTA_AV_FEAT_BROWSE) {
+ rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_BROWSE);
+ }
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ if ((p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL) &&
+ (p_dev->rc_features & BTA_AV_FEAT_RCTG)) {
+ rc_features =
+ (btrc_remote_features_t)(rc_features | BTRC_FEAT_ABSOLUTE_VOLUME);
+ }
+#endif
+
+ if (p_dev->rc_features & BTA_AV_FEAT_METADATA) {
+ rc_features = (btrc_remote_features_t)(rc_features | BTRC_FEAT_METADATA);
+ }
+
+ BTIF_TRACE_DEBUG("%s: rc_features: 0x%x", __func__, rc_features);
+ HAL_CBACK(bt_rc_callbacks, remote_features_cb, &rc_addr, rc_features);
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ BTIF_TRACE_DEBUG(
+ "%s: Checking for feature flags in btif_rc_handler with label: %d",
+ __func__, p_dev->rc_vol_label);
+ // Register for volume change on connect
+ if (p_dev->rc_features & BTA_AV_FEAT_ADV_CTRL &&
+ p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t status = BT_STATUS_NOT_READY;
+ if (MAX_LABEL == p_dev->rc_vol_label) {
+ status = get_transaction(&p_transaction);
+ } else {
+ p_transaction = get_transaction_by_lbl(p_dev->rc_vol_label);
+ if (NULL != p_transaction) {
+ BTIF_TRACE_DEBUG(
+ "%s: register_volumechange already in progress for label: %d",
+ __func__, p_dev->rc_vol_label);
+ return;
+ }
+ status = get_transaction(&p_transaction);
+ }
+ if (BT_STATUS_SUCCESS == status && NULL != p_transaction) {
+ p_dev->rc_vol_label = p_transaction->lbl;
+ register_volumechange(p_dev->rc_vol_label, p_dev);
+ }
+ }
+#endif
+}
+
+/***************************************************************************
+ * Function handle_rc_connect
+ *
+ * - Argument: tBTA_AV_RC_OPEN browse RC open data structure
+ *
+ * - Description: browse RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_browse_connect(tBTA_AV_RC_BROWSE_OPEN* p_rc_br_open) {
+ BTIF_TRACE_DEBUG("%s: rc_handle %d status %d", __func__,
+ p_rc_br_open->rc_handle, p_rc_br_open->status);
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(p_rc_br_open->rc_handle);
+
+ if (!p_dev) {
+ BTIF_TRACE_ERROR("%s p_dev is null", __func__);
+ return;
+ }
+
+ /* check that we are already connected to this address since being connected
+ * to a browse when not connected to the control channel over AVRCP is
+ * probably not preferred anyways. */
+ if (p_rc_br_open->status == BTA_AV_SUCCESS) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ p_dev->br_connected = true;
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, true, &rc_addr);
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_connect
+ *
+ * - Argument: tBTA_AV_RC_OPEN RC open data structure
+ *
+ * - Description: RC connection event handler
+ *
+ ***************************************************************************/
+void handle_rc_connect(tBTA_AV_RC_OPEN* p_rc_open) {
+ BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_open->rc_handle);
+
+ btif_rc_device_cb_t* p_dev = alloc_device();
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev is NULL", __func__);
+ return;
+ }
+
+ if (!(p_rc_open->status == BTA_AV_SUCCESS)) {
+ BTIF_TRACE_ERROR("%s: Connect failed with error code: %d", __func__,
+ p_rc_open->status);
+ p_dev->rc_connected = false;
+
+ /** M: Bug fix for clear some buffer when AVRCP SDP fail @{ */
+ BTA_AvCloseRc(p_rc_open->rc_handle);
+
+ p_dev->rc_handle = 0;
+ p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+
+ p_dev->rc_features = 0;
+ p_dev->rc_vol_label = MAX_LABEL;
+ p_dev->rc_volume = MAX_VOLUME;
+
+ memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+
+ return;
+ /** @} */
+ }
+
+ // check if already some RC is connected
+ if (p_dev->rc_connected) {
+ BTIF_TRACE_ERROR(
+ "%s: Got RC OPEN in connected state, Connected RC: %d \
+ and Current RC: %d",
+ __func__, p_dev->rc_handle, p_rc_open->rc_handle);
+ if ((p_dev->rc_handle != p_rc_open->rc_handle) &&
+ (bdcmp(p_dev->rc_addr, p_rc_open->peer_addr))) {
+ BTIF_TRACE_DEBUG("%s: Got RC connected for some other handle", __func__);
+ BTA_AvCloseRc(p_rc_open->rc_handle);
+ return;
+ }
+ }
+ memcpy(p_dev->rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR));
+ p_dev->rc_features = p_rc_open->peer_features;
+ BTIF_TRACE_DEBUG("%s: handle_rc_connect in features: 0x%x out features 0x%x",
+ __func__, p_rc_open->peer_features, p_dev->rc_features);
+ p_dev->rc_vol_label = MAX_LABEL;
+ p_dev->rc_volume = MAX_VOLUME;
+
+ p_dev->rc_connected = true;
+ p_dev->rc_handle = p_rc_open->rc_handle;
+ p_dev->rc_state = BTRC_CONNECTION_STATE_CONNECTED;
+ /* on locally initiated connection we will get remote features as part of
+ * connect */
+ if (p_dev->rc_features != 0 && bt_rc_callbacks != NULL) {
+ handle_rc_features(p_dev);
+ }
+
+ p_dev->rc_playing_uid = RC_INVALID_TRACK_ID;
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ if (bt_rc_ctrl_callbacks != NULL) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, true, false, &rc_addr);
+ }
+ /* report connection state if remote device is AVRCP target */
+ handle_rc_ctrl_features(p_dev);
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ p_dev->rc_disalbe_song_pos = false;
+ if (interop_mtk_match_addr(INTEROP_MTK_AVRCP_DISABLE_SONG_POS, (const bt_bdaddr_t *)&p_dev->rc_addr)
+ && interop_mtk_match_name(INTEROP_MTK_AVRCP_DISABLE_SONG_POS, (const bt_bdaddr_t *)&p_dev->rc_addr))
+ {
+ p_dev->rc_disalbe_song_pos = true;
+ BTIF_TRACE_DEBUG("rc_disalbe_song_pos is TRUE!");
+ }
+#endif
+/** @} */
+
+}
+
+/***************************************************************************
+ * Function handle_rc_disconnect
+ *
+ * - Argument: tBTA_AV_RC_CLOSE RC close data structure
+ *
+ * - Description: RC disconnection event handler
+ *
+ ***************************************************************************/
+void handle_rc_disconnect(tBTA_AV_RC_CLOSE* p_rc_close) {
+ btif_rc_device_cb_t* p_dev = NULL;
+ BTIF_TRACE_DEBUG("%s: rc_handle: %d", __func__, p_rc_close->rc_handle);
+
+ p_dev = btif_rc_get_device_by_handle(p_rc_close->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: Got disconnect from invalid rc handle", __func__);
+ return;
+ }
+
+ if ((p_rc_close->rc_handle != p_dev->rc_handle) &&
+ (bdcmp(p_dev->rc_addr, p_rc_close->peer_addr))) {
+ BTIF_TRACE_ERROR("Got disconnect of unknown device");
+ return;
+ }
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ /* Clean up AVRCP procedure flags */
+ memset(&p_dev->rc_app_settings, 0, sizeof(btif_rc_player_app_settings_t));
+ p_dev->rc_features_processed = false;
+ p_dev->rc_procedure_complete = false;
+ rc_stop_play_status_timer(p_dev);
+ /* Check and clear the notification event list */
+ if (p_dev->rc_supported_event_list != NULL) {
+ list_clear(p_dev->rc_supported_event_list);
+ p_dev->rc_supported_event_list = NULL;
+ }
+
+ /* check if there is another device connected */
+ if (p_dev->rc_state == BTRC_CONNECTION_STATE_CONNECTED) {
+ p_dev->rc_handle = 0;
+ p_dev->rc_connected = false;
+ p_dev->rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+
+ memset(p_dev->rc_notif, 0, sizeof(p_dev->rc_notif));
+
+ p_dev->rc_features = 0;
+ p_dev->rc_vol_label = MAX_LABEL;
+ p_dev->rc_volume = MAX_VOLUME;
+
+ memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+ }
+ if (get_num_connected_devices() == 0) {
+ BTIF_TRACE_DEBUG("%s: Closing all handles", __func__);
+ init_all_transactions();
+ }
+
+ memset(p_dev->rc_addr, 0, sizeof(BD_ADDR));
+ /* report connection state if device is AVRCP target */
+ if (bt_rc_ctrl_callbacks != NULL) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, connection_state_cb, false, false,
+ &rc_addr);
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_passthrough_cmd
+ *
+ * - Argument: tBTA_AV_RC rc_id remote control command ID
+ * tBTA_AV_STATE key_state status of key press
+ *
+ * - Description: Remote control command handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_cmd(tBTA_AV_REMOTE_CMD* p_remote_cmd) {
+ if (p_remote_cmd == NULL) {
+ BTIF_TRACE_ERROR("%s: No remote command!", __func__);
+ return;
+ }
+
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(p_remote_cmd->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: Got passthrough command from invalid rc handle",
+ __func__);
+ return;
+ }
+
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ BTIF_TRACE_DEBUG("%s: p_remote_cmd->rc_id: %d", __func__,
+ p_remote_cmd->rc_id);
+
+ /* If AVRC is open and peer sends PLAY but there is no AVDT, then we queue-up
+ * this PLAY */
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PLAY) && (!btif_av_is_connected())) {
+ if (p_remote_cmd->key_state == AVRC_STATE_PRESS) {
+ APPL_TRACE_WARNING("%s: AVDT not open, queuing the PLAY command",
+ __func__);
+ p_dev->rc_pending_play = true;
+ }
+ return;
+ }
+ /** M: Bug fix for Block AVRCP key if A2DP is not connected @{ */
+ if (btif_av_is_idle())
+ {
+ APPL_TRACE_WARNING("%s: AVDT not connection, drop command", __FUNCTION__);
+ return;
+ }
+ /** @} */
+
+ /* If we previously queued a play and we get a PAUSE, clear it. */
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_PAUSE) && (p_dev->rc_pending_play)) {
+ APPL_TRACE_WARNING("%s: Clear the pending PLAY on PAUSE received",
+ __func__);
+ p_dev->rc_pending_play = false;
+ return;
+ }
+
+ if ((p_remote_cmd->rc_id == BTA_AV_RC_STOP) &&
+ (!btif_av_stream_started_ready())) {
+ APPL_TRACE_WARNING("%s: Stream suspended, ignore STOP cmd", __func__);
+ return;
+ }
+
+ int pressed = (p_remote_cmd->key_state == AVRC_STATE_PRESS) ? 1 : 0;
+
+ /* pass all commands up */
+ BTIF_TRACE_DEBUG("%s: rc_features: %d, cmd->rc_id: %d, pressed: %d", __func__,
+ p_dev->rc_features, p_remote_cmd->rc_id, pressed);
+ HAL_CBACK(bt_rc_callbacks, passthrough_cmd_cb, p_remote_cmd->rc_id, pressed,
+ &rc_addr);
+}
+
+/***************************************************************************
+ * Function handle_rc_passthrough_rsp
+ *
+ * - Argument: tBTA_AV_REMOTE_RSP passthrough command response
+ *
+ * - Description: Remote control passthrough response handler
+ *
+ ***************************************************************************/
+void handle_rc_passthrough_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
+ btif_rc_device_cb_t* p_dev = NULL;
+ bt_bdaddr_t rc_addr;
+
+ p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: passthrough response for Invalid rc handle",
+ __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (!(p_dev->rc_features & BTA_AV_FEAT_RCTG)) {
+ BTIF_TRACE_ERROR("%s: DUT does not support AVRCP controller role",
+ __func__);
+ return;
+ }
+
+ const char* status = (p_remote_rsp->key_state == 1) ? "released" : "pressed";
+ BTIF_TRACE_DEBUG("%s: rc_id: %d state: %s", __func__, p_remote_rsp->rc_id,
+ status);
+
+ release_transaction(p_remote_rsp->label);
+ if (bt_rc_ctrl_callbacks != NULL) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, passthrough_rsp_cb, &rc_addr,
+ p_remote_rsp->rc_id, p_remote_rsp->key_state);
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_vendorunique_rsp
+ *
+ * - Argument: tBTA_AV_REMOTE_RSP command response
+ *
+ * - Description: Remote control vendor unique response handler
+ *
+ ***************************************************************************/
+void handle_rc_vendorunique_rsp(tBTA_AV_REMOTE_RSP* p_remote_rsp) {
+ btif_rc_device_cb_t* p_dev = NULL;
+ const char* status;
+ uint8_t vendor_id = 0;
+
+ p_dev = btif_rc_get_device_by_handle(p_remote_rsp->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: Got vendorunique rsp from invalid rc handle",
+ __func__);
+ return;
+ }
+
+ if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+ int key_state;
+ if (p_remote_rsp->key_state == AVRC_STATE_RELEASE) {
+ status = "released";
+ key_state = 1;
+ } else {
+ status = "pressed";
+ key_state = 0;
+ }
+
+ if (p_remote_rsp->len > 0) {
+ if (p_remote_rsp->len >= AVRC_PASS_THRU_GROUP_LEN)
+ vendor_id = p_remote_rsp->p_data[AVRC_PASS_THRU_GROUP_LEN - 1];
+ osi_free_and_reset((void**)&p_remote_rsp->p_data);
+ }
+ BTIF_TRACE_DEBUG("%s: vendor_id: %d status: %s", __func__, vendor_id,
+ status);
+
+ release_transaction(p_remote_rsp->label);
+ HAL_CBACK(bt_rc_ctrl_callbacks, groupnavigation_rsp_cb, vendor_id,
+ key_state);
+ } else {
+ BTIF_TRACE_ERROR("%s: Remote does not support AVRCP TG role", __func__);
+ }
+}
+
+/***************************************************************************
+ * Function handle_rc_metamsg_cmd
+ *
+ * - Argument: tBTA_AV_VENDOR Structure containing the received
+ * metamsg command
+ *
+ * - Description: Remote control metamsg command handler (AVRCP 1.3)
+ *
+ ***************************************************************************/
+void handle_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) {
+ /* Parse the metamsg command and pass it on to BTL-IFS */
+ uint8_t scratch_buf[512] = {0};
+ tAVRC_COMMAND avrc_command = {0};
+ tAVRC_STS status;
+ btif_rc_device_cb_t* p_dev = NULL;
+
+ if (NULL == pmeta_msg) {
+ BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg is NULL", __func__);
+ return;
+ }
+
+ if (NULL == pmeta_msg->p_msg) {
+ BTIF_TRACE_EVENT("%s: Exiting as pmeta_msg->p_msg is NULL", __func__);
+ return;
+ }
+
+ BTIF_TRACE_EVENT("%s: pmeta_msg: opcode: %x, code: %x", __func__,
+ pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+ p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: Meta msg event for Invalid rc handle", __func__);
+ return;
+ }
+
+ if (pmeta_msg->p_msg->hdr.opcode != AVRC_OP_VENDOR &&
+ pmeta_msg->p_msg->hdr.opcode != AVRC_OP_BROWSE) {
+ BTIF_TRACE_WARNING("Invalid opcode: %x", pmeta_msg->p_msg->hdr.opcode);
+ return;
+ }
+
+ if (pmeta_msg->len < 3) {
+ BTIF_TRACE_WARNING("%s: Invalid length. opcode: 0x%x, len: 0x%x", __func__,
+ pmeta_msg->p_msg->hdr.opcode, pmeta_msg->len);
+ return;
+ }
+
+ if (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) {
+ {
+ rc_transaction_t* transaction = NULL;
+ transaction = get_transaction_by_lbl(pmeta_msg->label);
+ if (transaction != NULL) {
+ handle_rc_metamsg_rsp(pmeta_msg, p_dev);
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: Discard vendor dependent rsp. code: %d label: %d.", __func__,
+ pmeta_msg->code, pmeta_msg->label);
+ }
+ return;
+ }
+ }
+
+ status = AVRC_ParsCommand(pmeta_msg->p_msg, &avrc_command, scratch_buf,
+ sizeof(scratch_buf));
+ BTIF_TRACE_DEBUG("%s: Received vendor command.code,PDU and label: %d, %d, %d",
+ __func__, pmeta_msg->code, avrc_command.cmd.pdu,
+ pmeta_msg->label);
+
+ if (status != AVRC_STS_NO_ERROR) {
+ /* return error */
+ BTIF_TRACE_WARNING(
+ "%s: Error in parsing received metamsg command. status: 0x%02x",
+ __func__, status);
+ send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label,
+ avrc_command.pdu, status,
+ pmeta_msg->p_msg->hdr.opcode);
+ } else {
+ /* if RegisterNotification, add it to our registered queue */
+
+ if (avrc_command.cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) {
+ uint8_t event_id = avrc_command.reg_notif.event_id;
+
+ BTIF_TRACE_EVENT(
+ "%s: New register notification received.event_id: %s, label: 0x%x, "
+ "code: %x",
+ __func__, dump_rc_notification_event_id(event_id), pmeta_msg->label,
+ pmeta_msg->code);
+ p_dev->rc_notif[event_id - 1].bNotify = true;
+ p_dev->rc_notif[event_id - 1].label = pmeta_msg->label;
+ }
+
+ BTIF_TRACE_EVENT("%s: Passing received metamsg command to app. pdu: %s",
+ __func__, dump_rc_pdu(avrc_command.cmd.pdu));
+
+ /* Since handle_rc_metamsg_cmd() itself is called from
+ *btif context, no context switching is required. Invoke
+ * btif_rc_upstreams_evt directly from here. */
+ btif_rc_upstreams_evt((uint16_t)avrc_command.cmd.pdu, &avrc_command,
+ pmeta_msg->code, pmeta_msg->label, p_dev);
+ }
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_handler
+ **
+ ** Description RC event handler
+ **
+ ***************************************************************************/
+void btif_rc_handler(tBTA_AV_EVT event, tBTA_AV* p_data) {
+ BTIF_TRACE_DEBUG("%s: event: %s", __func__, dump_rc_event(event));
+ btif_rc_device_cb_t* p_dev = NULL;
+ switch (event) {
+ case BTA_AV_RC_OPEN_EVT: {
+ BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__,
+ p_data->rc_open.peer_features);
+ handle_rc_connect(&(p_data->rc_open));
+ } break;
+
+ case BTA_AV_RC_BROWSE_OPEN_EVT: {
+ /* tell the UL that we have connection to browse channel and that
+ * browse commands can be directed accordingly. */
+ handle_rc_browse_connect(&p_data->rc_browse_open);
+ } break;
+
+ case BTA_AV_RC_CLOSE_EVT: {
+ handle_rc_disconnect(&(p_data->rc_close));
+ } break;
+
+ case BTA_AV_RC_BROWSE_CLOSE_EVT: {
+ BTIF_TRACE_DEBUG("%s: BTA_AV_RC_BROWSE_CLOSE_EVT", __func__);
+ } break;
+
+ case BTA_AV_REMOTE_CMD_EVT: {
+ if (bt_rc_callbacks != NULL) {
+ BTIF_TRACE_DEBUG("%s: rc_id: 0x%x key_state: %d", __func__,
+ p_data->remote_cmd.rc_id,
+ p_data->remote_cmd.key_state);
+ handle_rc_passthrough_cmd((&p_data->remote_cmd));
+ } else {
+ BTIF_TRACE_ERROR("%s: AVRCP TG role not up, drop passthrough commands",
+ __func__);
+ }
+ } break;
+
+ case BTA_AV_REMOTE_RSP_EVT: {
+ BTIF_TRACE_DEBUG("%s: RSP: rc_id: 0x%x key_state: %d", __func__,
+ p_data->remote_rsp.rc_id, p_data->remote_rsp.key_state);
+
+ if (p_data->remote_rsp.rc_id == AVRC_ID_VENDOR) {
+ handle_rc_vendorunique_rsp((&p_data->remote_rsp));
+ } else {
+ handle_rc_passthrough_rsp((&p_data->remote_rsp));
+ }
+ } break;
+
+ case BTA_AV_RC_FEAT_EVT: {
+ BTIF_TRACE_DEBUG("%s: Peer_features: %x", __func__,
+ p_data->rc_feat.peer_features);
+ p_dev = btif_rc_get_device_by_handle(p_data->rc_feat.rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: RC Feature event for Invalid rc handle",
+ __func__);
+ break;
+ }
+
+ p_dev->rc_features = p_data->rc_feat.peer_features;
+ if (bt_rc_callbacks != NULL) {
+ handle_rc_features(p_dev);
+ }
+
+ if ((p_dev->rc_connected) && (bt_rc_ctrl_callbacks != NULL)) {
+ handle_rc_ctrl_features(p_dev);
+ }
+ } break;
+
+ case BTA_AV_META_MSG_EVT: {
+ if (bt_rc_callbacks != NULL) {
+ BTIF_TRACE_DEBUG("%s: BTA_AV_META_MSG_EVT code: %d label: %d", __func__,
+ p_data->meta_msg.code, p_data->meta_msg.label);
+ BTIF_TRACE_DEBUG("%s: company_id: 0x%x len: %d handle: %d", __func__,
+ p_data->meta_msg.company_id, p_data->meta_msg.len,
+ p_data->meta_msg.rc_handle);
+
+ /* handle the metamsg command */
+ handle_rc_metamsg_cmd(&(p_data->meta_msg));
+
+ /* Free the Memory allocated for tAVRC_MSG */
+ } else if (bt_rc_ctrl_callbacks != NULL) {
+ /* This is case of Sink + CT + TG(for abs vol)) */
+ BTIF_TRACE_DEBUG(
+ "%s BTA_AV_META_MSG_EVT code:%d label:%d opcode %d ctype %d",
+ __func__, p_data->meta_msg.code, p_data->meta_msg.label,
+ p_data->meta_msg.p_msg->hdr.opcode,
+ p_data->meta_msg.p_msg->hdr.ctype);
+ BTIF_TRACE_DEBUG("%s company_id:0x%x len:%d handle:%d", __func__,
+ p_data->meta_msg.company_id, p_data->meta_msg.len,
+ p_data->meta_msg.rc_handle);
+ switch (p_data->meta_msg.p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR:
+ if ((p_data->meta_msg.code >= AVRC_RSP_NOT_IMPL) &&
+ (p_data->meta_msg.code <= AVRC_RSP_INTERIM)) {
+ /* Its a response */
+ handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+ } else if (p_data->meta_msg.code <= AVRC_CMD_GEN_INQ) {
+ /* Its a command */
+ handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ }
+ break;
+
+ case AVRC_OP_BROWSE:
+ if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_CMD) {
+ handle_avk_rc_metamsg_cmd(&(p_data->meta_msg));
+ } else if (p_data->meta_msg.p_msg->hdr.ctype == AVRC_RSP) {
+ handle_avk_rc_metamsg_rsp(&(p_data->meta_msg));
+ }
+ break;
+ }
+ } else {
+ BTIF_TRACE_ERROR("Neither CTRL, nor TG is up, drop meta commands");
+ }
+ } break;
+
+ default:
+ BTIF_TRACE_DEBUG("%s: Unhandled RC event : 0x%x", __func__, event);
+ }
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_get_connected_peer
+ **
+ ** Description Fetches the connected headset's BD_ADDR if any
+ **
+ ***************************************************************************/
+bool btif_rc_get_connected_peer(BD_ADDR peer_addr) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, peer_addr);
+ btif_rc_device_cb_t* p_dev = NULL;
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ p_dev = get_connected_device(idx);
+ if (p_dev != NULL && (p_dev->rc_connected == TRUE)) {
+ bdcpy(peer_addr, p_dev->rc_addr);
+ return true;
+ }
+ }
+ return false;
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_get_connected_peer_handle
+ **
+ ** Description Fetches the connected headset's handle if any
+ **
+ ***************************************************************************/
+uint8_t btif_rc_get_connected_peer_handle(BD_ADDR peer_addr) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, peer_addr);
+
+ btif_rc_device_cb_t* p_dev = NULL;
+ p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return BTRC_HANDLE_NONE;
+ }
+ return p_dev->rc_handle;
+}
+
+/***************************************************************************
+ **
+ ** Function btif_rc_check_handle_pending_play
+ **
+ ** Description Clears the queued PLAY command. if |bSendToApp| is true,
+ ** forwards to app
+ **
+ ***************************************************************************/
+
+/* clear the queued PLAY command. if |bSendToApp| is true, forward to app */
+void btif_rc_check_handle_pending_play(BD_ADDR peer_addr, bool bSendToApp) {
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, peer_addr);
+
+ btif_rc_device_cb_t* p_dev = NULL;
+ p_dev = btif_rc_get_device_by_bda(&rc_addr);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG("%s: bSendToApp: %d", __func__, bSendToApp);
+ if (p_dev->rc_pending_play) {
+ /** M: Bug fix for Block AVRCP key if A2DP is not connected @{ */
+ if (bSendToApp && !btif_av_is_idle()) {
+ /** @} */
+ tBTA_AV_REMOTE_CMD remote_cmd;
+ APPL_TRACE_DEBUG("%s: Sending queued PLAYED event to app", __func__);
+
+ memset(&remote_cmd, 0, sizeof(tBTA_AV_REMOTE_CMD));
+ remote_cmd.rc_handle = p_dev->rc_handle;
+ remote_cmd.rc_id = AVRC_ID_PLAY;
+ remote_cmd.hdr.ctype = AVRC_CMD_CTRL;
+ remote_cmd.hdr.opcode = AVRC_OP_PASS_THRU;
+
+ /* delay sending to app, else there is a timing issue in the framework,
+ ** which causes the audio to be on th device's speaker. Delay between
+ ** OPEN & RC_PLAYs
+ */
+ sleep_ms(200);
+ /* send to app - both PRESSED & RELEASED */
+ remote_cmd.key_state = AVRC_STATE_PRESS;
+ handle_rc_passthrough_cmd(&remote_cmd);
+
+ sleep_ms(100);
+
+ remote_cmd.key_state = AVRC_STATE_RELEASE;
+ handle_rc_passthrough_cmd(&remote_cmd);
+ }
+ p_dev->rc_pending_play = false;
+ }
+}
+
+/* Generic reject response */
+static void send_reject_response(uint8_t rc_handle, uint8_t label, uint8_t pdu,
+ uint8_t status, uint8_t opcode) {
+ uint8_t ctype = AVRC_RSP_REJ;
+ tAVRC_RESPONSE avrc_rsp;
+ BT_HDR* p_msg = NULL;
+ memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+
+ avrc_rsp.rsp.opcode = opcode;
+ avrc_rsp.rsp.pdu = pdu;
+ avrc_rsp.rsp.status = status;
+
+ status = AVRC_BldResponse(rc_handle, &avrc_rsp, &p_msg);
+
+ if (status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: status not AVRC_STS_NO_ERROR", __func__);
+ return;
+ }
+
+ BTIF_TRACE_DEBUG(
+ "%s: Sending error notification to handle: %d. pdu: %s,status: 0x%02x",
+ __func__, rc_handle, dump_rc_pdu(pdu), status);
+ BTA_AvMetaRsp(rc_handle, label, ctype, p_msg);
+}
+
+/***************************************************************************
+ * Function get_rsp_type_code
+ *
+ * - Argument: status
+ * - Description: Returns response type codes for particular command code and
+ * status.
+ *
+ ***************************************************************************/
+static tBTA_AV_CODE get_rsp_type_code(tAVRC_STS status, tBTA_AV_CODE code) {
+ if (status != AVRC_STS_NO_ERROR) {
+ return AVRC_RSP_REJ;
+ }
+
+ if (code < AVRC_RSP_NOT_IMPL) {
+ if (code == AVRC_CMD_NOTIF) return AVRC_RSP_INTERIM;
+
+ if (code == AVRC_CMD_STATUS) return AVRC_RSP_IMPL_STBL;
+
+ return AVRC_RSP_ACCEPT;
+ }
+
+ return code;
+}
+
+/***************************************************************************
+ * Function send_metamsg_rsp
+ *
+ * - Argument:
+ * p_dev Dev pointer
+ * index Command index (= -1 if not used)
+ * label Label of the RC response
+ * code Response type
+ * pmetamsg_resp Vendor response
+ *
+ * - Description: Remote control metamsg response handler
+ *
+ ***************************************************************************/
+static void send_metamsg_rsp(btif_rc_device_cb_t* p_dev, int index,
+ uint8_t label, tBTA_AV_CODE code,
+ tAVRC_RESPONSE* pmetamsg_resp) {
+ uint8_t ctype;
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ if (pmetamsg_resp == NULL) {
+ BTIF_TRACE_WARNING("%s: Invalid response received from application",
+ __func__);
+ return;
+ }
+
+ BTIF_TRACE_EVENT(
+ "%s: rc_handle: %d, index: %d, label: %d, code: 0x%02x, pdu: %s",
+ __func__, p_dev->rc_handle, index, label, code,
+ dump_rc_pdu(pmetamsg_resp->rsp.pdu));
+
+ if (index >= 0 && p_dev->rc_pdu_info[index].is_rsp_pending == false) {
+ BTIF_TRACE_ERROR("%s: is_rsp_pending false, returning", __func__);
+ return;
+ }
+
+ ctype = get_rsp_type_code(pmetamsg_resp->rsp.status, code);
+
+ /* if response is for register_notification, make sure the rc has
+ actually registered for this */
+ if ((pmetamsg_resp->rsp.pdu == AVRC_PDU_REGISTER_NOTIFICATION) &&
+ ((code == AVRC_RSP_CHANGED) || (code == AVRC_RSP_INTERIM))) {
+ bool bSent = false;
+ uint8_t event_id = pmetamsg_resp->reg_notif.event_id;
+ bool bNotify =
+ (p_dev->rc_connected) && (p_dev->rc_notif[event_id - 1].bNotify);
+
+ /* de-register this notification for a CHANGED response */
+ p_dev->rc_notif[event_id - 1].bNotify = false;
+ BTIF_TRACE_DEBUG("%s: rc_handle: %d. event_id: 0x%02d bNotify: %u",
+ __func__, p_dev->rc_handle, event_id, bNotify);
+ if (bNotify) {
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status;
+
+ if (AVRC_STS_NO_ERROR == (status = AVRC_BldResponse(
+ p_dev->rc_handle, pmetamsg_resp, &p_msg))) {
+ BTIF_TRACE_DEBUG(
+ "%s: Sending notification to rc_handle: %d. event_id: 0x%02d",
+ __func__, p_dev->rc_handle, event_id);
+ bSent = true;
+ BTA_AvMetaRsp(p_dev->rc_handle, p_dev->rc_notif[event_id - 1].label,
+ ctype, p_msg);
+ } else {
+ BTIF_TRACE_WARNING(
+ "%s: failed to build metamsg response. status: 0x%02x", __func__,
+ status);
+ }
+ }
+
+ if (!bSent) {
+ BTIF_TRACE_DEBUG(
+ "%s: Notification not sent, as there are no RC connections or the \
+ CT has not subscribed for event_id: %s",
+ __func__, dump_rc_notification_event_id(event_id));
+ }
+ } else {
+ /* All other commands go here */
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status;
+
+ status = AVRC_BldResponse(p_dev->rc_handle, pmetamsg_resp, &p_msg);
+
+ if (status == AVRC_STS_NO_ERROR) {
+ BTA_AvMetaRsp(p_dev->rc_handle, label, ctype, p_msg);
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build metamsg response. status: 0x%02x",
+ __func__, status);
+ }
+ }
+
+ if (index >= 0) {
+ p_dev->rc_pdu_info[index].ctype = 0;
+ p_dev->rc_pdu_info[index].label = 0;
+ p_dev->rc_pdu_info[index].is_rsp_pending = false;
+ }
+}
+
+static uint8_t opcode_from_pdu(uint8_t pdu) {
+ uint8_t opcode = 0;
+
+ switch (pdu) {
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ case AVRC_PDU_CHANGE_PATH:
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ case AVRC_PDU_ADD_TO_NOW_PLAYING:
+ case AVRC_PDU_SEARCH:
+ case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+ case AVRC_PDU_GENERAL_REJECT:
+ opcode = AVRC_OP_BROWSE;
+ break;
+
+ case AVRC_PDU_NEXT_GROUP:
+ case AVRC_PDU_PREV_GROUP: /* pass thru */
+ opcode = AVRC_OP_PASS_THRU;
+ break;
+
+ default: /* vendor */
+ opcode = AVRC_OP_VENDOR;
+ break;
+ }
+
+ return opcode;
+}
+
+/***************************************************************************
+ * Function: fill_attribute_id_array
+ *
+ * - Argument:
+ * cmd_attribute_number input attribute number from AVRCP command
+ * cmd_attribute_id_array input attribute list from AVRCP command
+ * out_array_size allocated size of out attribute id array
+ * out_attribute_id_array output attribute list resolved here
+ *
+ * - Description:
+ * Resolve attribute id array as defined by the AVRCP specification.
+ *
+ * - Returns:
+ * The number of attributes filled in
+ *
+ ***************************************************************************/
+static uint8_t fill_attribute_id_array(
+ uint8_t cmd_attribute_number, btrc_media_attr_t* cmd_attribute_id_array,
+ size_t out_array_size, btrc_media_attr_t* out_attribute_id_array) {
+ /* Reset attribute array */
+ memset(out_attribute_id_array, 0, out_array_size);
+ /* Default case for cmd_attribute_number == 0xFF, No attribute */
+ uint8_t out_attribute_number = 0;
+ if (cmd_attribute_number == 0) {
+ /* All attributes */
+ out_attribute_number = out_array_size < AVRC_MAX_NUM_MEDIA_ATTR_ID
+ ? out_array_size
+ : AVRC_MAX_NUM_MEDIA_ATTR_ID;
+ for (int i = 0; i < out_attribute_number; i++) {
+ out_attribute_id_array[i] = (btrc_media_attr_t)(i + 1);
+ }
+ } else if (cmd_attribute_number != 0xFF) {
+ /* Attribute List */
+ out_attribute_number = 0;
+ int filled_id_count = 0;
+ for (int i = 0; (i < cmd_attribute_number) &&
+ (out_attribute_number < out_array_size) &&
+ (out_attribute_number < AVRC_MAX_NUM_MEDIA_ATTR_ID);
+ i++) {
+ /* Fill only valid entries */
+ if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(cmd_attribute_id_array[i])) {
+ /* Skip the duplicate entries */
+ for (filled_id_count = 0; filled_id_count < out_attribute_number;
+ filled_id_count++) {
+ if (out_attribute_id_array[filled_id_count] ==
+ cmd_attribute_id_array[i])
+ break;
+ }
+ /* New ID */
+ if (filled_id_count == out_attribute_number) {
+ out_attribute_id_array[out_attribute_number] =
+ (btrc_media_attr_t)cmd_attribute_id_array[i];
+ out_attribute_number++;
+ }
+ }
+ }
+ }
+ return out_attribute_number;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_rc_upstreams_evt
+ *
+ * Description Executes AVRC UPSTREAMS events in btif context.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_rc_upstreams_evt(uint16_t event, tAVRC_COMMAND* pavrc_cmd,
+ uint8_t ctype, uint8_t label,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_EVENT("%s: pdu: %s handle: 0x%x ctype: %x label: %x event ID: %x",
+ __func__, dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle,
+ ctype, label, pavrc_cmd->reg_notif.event_id);
+ bt_bdaddr_t rc_addr;
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ switch (event) {
+ case AVRC_PDU_GET_PLAY_STATUS: {
+ fill_pdu_queue(IDX_GET_PLAY_STATUS_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, get_play_status_cb, &rc_addr);
+ } break;
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: {
+ /* TODO: Add support for Application Settings */
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
+ } break;
+ case AVRC_PDU_GET_ELEMENT_ATTR: {
+ btrc_media_attr_t element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint8_t num_attr = fill_attribute_id_array(
+ pavrc_cmd->get_elem_attrs.num_attr,
+ (btrc_media_attr_t*)pavrc_cmd->get_elem_attrs.attrs,
+ BTRC_MAX_ELEM_ATTR_SIZE, element_attrs);
+ if (num_attr == 0) {
+ BTIF_TRACE_ERROR(
+ "%s: No valid attributes requested in GET_ELEMENT_ATTRIBUTES",
+ __func__);
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+ return;
+ }
+ fill_pdu_queue(IDX_GET_ELEMENT_ATTR_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, get_element_attr_cb, num_attr, element_attrs,
+ &rc_addr);
+ } break;
+ case AVRC_PDU_REGISTER_NOTIFICATION: {
+ if (pavrc_cmd->reg_notif.event_id == BTRC_EVT_PLAY_POS_CHANGED &&
+ pavrc_cmd->reg_notif.param == 0) {
+ BTIF_TRACE_WARNING(
+ "%s: Device registering position changed with illegal param 0.",
+ __func__);
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+ /* de-register this notification for a rejected response */
+ p_dev->rc_notif[BTRC_EVT_PLAY_POS_CHANGED - 1].bNotify = false;
+ return;
+ }
+ HAL_CBACK(bt_rc_callbacks, register_notification_cb,
+ (btrc_event_id_t)pavrc_cmd->reg_notif.event_id,
+ pavrc_cmd->reg_notif.param, &rc_addr);
+ } break;
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: {
+ tAVRC_RESPONSE avrc_rsp;
+ BTIF_TRACE_EVENT("%s: AVRC_PDU_INFORM_DISPLAY_CHARSET", __func__);
+ if (p_dev->rc_connected == true) {
+ memset(&(avrc_rsp.inform_charset), 0, sizeof(tAVRC_RSP));
+ avrc_rsp.inform_charset.opcode =
+ opcode_from_pdu(AVRC_PDU_INFORM_DISPLAY_CHARSET);
+ avrc_rsp.inform_charset.pdu = AVRC_PDU_INFORM_DISPLAY_CHARSET;
+ avrc_rsp.inform_charset.status = AVRC_STS_NO_ERROR;
+ send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+ }
+ } break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: {
+ uint32_t attr_ids[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint8_t num_attr;
+ num_attr = pavrc_cmd->get_items.attr_count;
+
+ BTIF_TRACE_EVENT(
+ "%s: AVRC_PDU_GET_FOLDER_ITEMS num_attr: %d, start_item [%d] \
+ end_item [%d]",
+ __func__, num_attr, pavrc_cmd->get_items.start_item,
+ pavrc_cmd->get_items.end_item);
+
+ /* num_attr requested:
+ * 0x00: All attributes requested
+ * 0xFF: No Attributes requested
+ * 0x01 to 0x07: Specified number of attributes
+ */
+ if ((num_attr != 0xFF && num_attr > BTRC_MAX_ELEM_ATTR_SIZE)) {
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+ return;
+ }
+
+ /* Except num_attr is None(0xff) / All(0x00), request follows with an
+ * Attribute List */
+ if ((num_attr != 0xFF) && (num_attr != 0x00)) {
+ memcpy(attr_ids, pavrc_cmd->get_items.p_attr_list,
+ sizeof(uint32_t) * num_attr);
+ }
+
+ fill_pdu_queue(IDX_GET_FOLDER_ITEMS_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, get_folder_items_cb,
+ pavrc_cmd->get_items.scope, pavrc_cmd->get_items.start_item,
+ pavrc_cmd->get_items.end_item, num_attr, attr_ids, &rc_addr);
+ } break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: {
+ fill_pdu_queue(IDX_SET_ADDR_PLAYER_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, set_addressed_player_cb,
+ pavrc_cmd->addr_player.player_id, &rc_addr);
+ } break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER: {
+ fill_pdu_queue(IDX_SET_BROWSED_PLAYER_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, set_browsed_player_cb,
+ pavrc_cmd->br_player.player_id, &rc_addr);
+ } break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: {
+ BTIF_TRACE_EVENT("%s() REQUEST CONTINUATION: target_pdu: 0x%02d",
+ __func__, pavrc_cmd->continu.target_pdu);
+ tAVRC_RESPONSE avrc_rsp;
+ if (p_dev->rc_connected == TRUE) {
+ memset(&(avrc_rsp.continu), 0, sizeof(tAVRC_NEXT_RSP));
+ avrc_rsp.continu.opcode =
+ opcode_from_pdu(AVRC_PDU_REQUEST_CONTINUATION_RSP);
+ avrc_rsp.continu.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+ avrc_rsp.continu.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.continu.target_pdu = pavrc_cmd->continu.target_pdu;
+ send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+ }
+ } break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: {
+ BTIF_TRACE_EVENT("%s() ABORT CONTINUATION: target_pdu: 0x%02d", __func__,
+ pavrc_cmd->abort.target_pdu);
+ tAVRC_RESPONSE avrc_rsp;
+ if (p_dev->rc_connected == TRUE) {
+ memset(&(avrc_rsp.abort), 0, sizeof(tAVRC_NEXT_RSP));
+ avrc_rsp.abort.opcode =
+ opcode_from_pdu(AVRC_PDU_ABORT_CONTINUATION_RSP);
+ avrc_rsp.abort.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
+ avrc_rsp.abort.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.abort.target_pdu = pavrc_cmd->continu.target_pdu;
+ send_metamsg_rsp(p_dev, -1, label, ctype, &avrc_rsp);
+ }
+ } break;
+
+ case AVRC_PDU_CHANGE_PATH: {
+ fill_pdu_queue(IDX_CHG_PATH_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, change_path_cb, pavrc_cmd->chg_path.direction,
+ pavrc_cmd->chg_path.folder_uid, &rc_addr);
+ } break;
+
+ case AVRC_PDU_SEARCH: {
+ fill_pdu_queue(IDX_SEARCH_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, search_cb, pavrc_cmd->search.string.charset_id,
+ pavrc_cmd->search.string.str_len,
+ pavrc_cmd->search.string.p_str, &rc_addr);
+ } break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: {
+ btrc_media_attr_t item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint8_t num_attr = fill_attribute_id_array(
+ pavrc_cmd->get_attrs.attr_count,
+ (btrc_media_attr_t*)pavrc_cmd->get_attrs.p_attr_list,
+ BTRC_MAX_ELEM_ATTR_SIZE, item_attrs);
+ if (num_attr == 0) {
+ BTIF_TRACE_ERROR(
+ "%s: No valid attributes requested in GET_ITEM_ATTRIBUTES",
+ __func__);
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_PARAM, pavrc_cmd->cmd.opcode);
+ return;
+ }
+ fill_pdu_queue(IDX_GET_ITEM_ATTR_RSP, ctype, label, true, p_dev);
+ BTIF_TRACE_DEBUG("%s: GET_ITEM_ATTRIBUTES: num_attr: %d", __func__,
+ num_attr);
+ HAL_CBACK(bt_rc_callbacks, get_item_attr_cb, pavrc_cmd->get_attrs.scope,
+ pavrc_cmd->get_attrs.uid, pavrc_cmd->get_attrs.uid_counter,
+ num_attr, item_attrs, &rc_addr);
+ } break;
+
+ case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: {
+ fill_pdu_queue(IDX_GET_TOTAL_NUM_OF_ITEMS_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, get_total_num_of_items_cb,
+ pavrc_cmd->get_num_of_items.scope, &rc_addr);
+ } break;
+
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: {
+ fill_pdu_queue(IDX_ADD_TO_NOW_PLAYING_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, add_to_now_playing_cb,
+ pavrc_cmd->add_to_play.scope, pavrc_cmd->add_to_play.uid,
+ pavrc_cmd->add_to_play.uid_counter, &rc_addr);
+ } break;
+
+ case AVRC_PDU_PLAY_ITEM: {
+ fill_pdu_queue(IDX_PLAY_ITEM_RSP, ctype, label, true, p_dev);
+ HAL_CBACK(bt_rc_callbacks, play_item_cb, pavrc_cmd->play_item.scope,
+ pavrc_cmd->play_item.uid_counter, pavrc_cmd->play_item.uid,
+ &rc_addr);
+ } break;
+
+ default: {
+ send_reject_response(p_dev->rc_handle, label, pavrc_cmd->pdu,
+ AVRC_STS_BAD_CMD, pavrc_cmd->cmd.opcode);
+ return;
+ } break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_rc_ctrl_upstreams_rsp_cmd
+ *
+ * Description Executes AVRC UPSTREAMS response events in btif context.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_rc_ctrl_upstreams_rsp_cmd(uint8_t event,
+ tAVRC_COMMAND* pavrc_cmd,
+ uint8_t label,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: pdu: %s: handle: 0x%x", __func__,
+ dump_rc_pdu(pavrc_cmd->pdu), p_dev->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ switch (event) {
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+ HAL_CBACK(bt_rc_ctrl_callbacks, setabsvol_cmd_cb, &rc_addr,
+ pavrc_cmd->volume.volume, label);
+ break;
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ if (pavrc_cmd->reg_notif.event_id == AVRC_EVT_VOLUME_CHANGE) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, registernotification_absvol_cb,
+ &rc_addr, label);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btif_rc_upstreams_rsp_evt
+ *
+ * Description Executes AVRC UPSTREAMS response events in btif context.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btif_rc_upstreams_rsp_evt(uint16_t event,
+ tAVRC_RESPONSE* pavrc_resp, uint8_t ctype,
+ uint8_t label,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_EVENT("%s: pdu: %s: handle: 0x%x ctype: %x label: %x", __func__,
+ dump_rc_pdu(pavrc_resp->pdu), p_dev->rc_handle, ctype,
+ label);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ switch (event) {
+ case AVRC_PDU_REGISTER_NOTIFICATION: {
+ if (AVRC_RSP_CHANGED == ctype)
+ p_dev->rc_volume = pavrc_resp->reg_notif.param.volume;
+ HAL_CBACK(bt_rc_callbacks, volume_change_cb,
+ pavrc_resp->reg_notif.param.volume, ctype, &rc_addr);
+ } break;
+
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
+ BTIF_TRACE_DEBUG(
+ "%s: Set absolute volume change event received: volume: %d, ctype: "
+ "%d",
+ __func__, pavrc_resp->volume.volume, ctype);
+ if (AVRC_RSP_ACCEPT == ctype)
+ p_dev->rc_volume = pavrc_resp->volume.volume;
+ HAL_CBACK(bt_rc_callbacks, volume_change_cb, pavrc_resp->volume.volume,
+ ctype, &rc_addr);
+ } break;
+
+ default:
+ return;
+ }
+}
+
+/*******************************************************************************
+ * AVRCP API Functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function init
+ *
+ * Description Initializes the AVRC interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init(btrc_callbacks_t* callbacks) {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+ bt_status_t result = BT_STATUS_SUCCESS;
+
+ if (bt_rc_callbacks) return BT_STATUS_DONE;
+
+ bt_rc_callbacks = callbacks;
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+ sizeof(btif_rc_cb.rc_multi_cb[idx]));
+ btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+ btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+ btif_rc_cb.rc_multi_cb[idx].rc_state = BTRC_CONNECTION_STATE_DISCONNECTED;
+ }
+ lbl_init();
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function init_ctrl
+ *
+ * Description Initializes the AVRC interface
+ *
+ * Returns bt_status_t
+ *
+ ******************************************************************************/
+static bt_status_t init_ctrl(btrc_ctrl_callbacks_t* callbacks) {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+ bt_status_t result = BT_STATUS_SUCCESS;
+
+ if (bt_rc_ctrl_callbacks) return BT_STATUS_DONE;
+
+ bt_rc_ctrl_callbacks = callbacks;
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+ sizeof(btif_rc_cb.rc_multi_cb[idx]));
+ btif_rc_cb.rc_multi_cb[idx].rc_vol_label = MAX_LABEL;
+ btif_rc_cb.rc_multi_cb[idx].rc_volume = MAX_VOLUME;
+ }
+ lbl_init();
+
+ return result;
+}
+
+static void rc_ctrl_procedure_complete(btif_rc_device_cb_t* p_dev) {
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ if (p_dev->rc_procedure_complete == true) {
+ return;
+ }
+ p_dev->rc_procedure_complete = true;
+ uint32_t attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM, AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS, AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_play_status_rsp
+ *
+ * Description Returns the current play status.
+ * This method is called in response to
+ * GetPlayStatus request.
+ *
+ * Returns bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_play_status_rsp(bt_bdaddr_t* bd_addr,
+ btrc_play_status_t play_status,
+ uint32_t song_len, uint32_t song_pos) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s: song len %d song pos %d", __func__, song_len, song_pos);
+ CHECK_RC_CONNECTED(p_dev);
+
+ memset(&(avrc_rsp.get_play_status), 0, sizeof(tAVRC_GET_PLAY_STATUS_RSP));
+
+ avrc_rsp.get_play_status.song_len = song_len;
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (p_dev->rc_disalbe_song_pos == true)
+ avrc_rsp.get_play_status.song_pos = (uint32_t)-1;
+ else
+#endif
+/** @} */
+ avrc_rsp.get_play_status.song_pos = song_pos;
+ avrc_rsp.get_play_status.play_status = play_status;
+
+ avrc_rsp.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+ avrc_rsp.get_play_status.opcode = opcode_from_pdu(AVRC_PDU_GET_PLAY_STATUS);
+ avrc_rsp.get_play_status.status =
+ ((play_status != BTRC_PLAYSTATE_ERROR) ? AVRC_STS_NO_ERROR
+ : AVRC_STS_BAD_PARAM);
+
+ /* Send the response */
+ send_metamsg_rsp(p_dev, IDX_GET_PLAY_STATUS_RSP,
+ p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].label,
+ p_dev->rc_pdu_info[IDX_GET_PLAY_STATUS_RSP].ctype,
+ &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function get_element_attr_rsp
+ *
+ * Description Returns the current songs' element attributes
+ * in text.
+ *
+ * Returns bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_element_attr_rsp(bt_bdaddr_t* bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ tAVRC_RESPONSE avrc_rsp;
+ uint32_t i;
+ tAVRC_ATTR_ENTRY element_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+
+ if (num_attr == 0) {
+ avrc_rsp.get_play_status.status = AVRC_STS_BAD_PARAM;
+ } else {
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ {
+ uint32_t j = 0;
+#endif
+/** @} */
+ for (i = 0; i < num_attr; i++) {
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if ((p_dev->rc_disalbe_song_pos == true) && (AVRC_MEDIA_ATTR_ID_PLAYING_TIME == p_attrs[i].attr_id))
+ {
+ BTIF_TRACE_DEBUG("%s skip get_element_attr_rsp invalid attr 0x%08x",
+ __FUNCTION__, p_attrs[i].attr_id);
+ continue;
+ }
+#endif
+/** @} */
+ element_attrs[i].attr_id = p_attrs[i].attr_id;
+ element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
+ element_attrs[i].name.str_len = (uint16_t)strlen((char*)p_attrs[i].text);
+ element_attrs[i].name.p_str = p_attrs[i].text;
+ BTIF_TRACE_DEBUG(
+ "%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
+ (unsigned int)element_attrs[i].attr_id,
+ element_attrs[i].name.charset_id, element_attrs[i].name.str_len,
+ element_attrs[i].name.p_str);
+/** M: Bug fix for blacklist that Some IOT device will have wrong song position when FF/REW @{ */
+// Some IOT device will have wrong song position when FF/REW
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ j++;
+ }
+ num_attr = j;
+#endif
+/** @} */
+ }
+ avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+ }
+ avrc_rsp.get_attrs.num_attrs = num_attr;
+ avrc_rsp.get_attrs.p_attrs = element_attrs;
+ avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+ avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ELEMENT_ATTR);
+
+ /* Send the response */
+ send_metamsg_rsp(p_dev, IDX_GET_ELEMENT_ATTR_RSP,
+ p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].label,
+ p_dev->rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP].ctype,
+ &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function reject_pending_notification
+ *
+ * Description Utility function to reject a pending notification. When
+ * AddressedPlayer change is received, all pending
+ * notifications should be completed.
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void reject_pending_notification(btrc_event_id_t event_id, int idx) {
+ tAVRC_RESPONSE avrc_rsp;
+ memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+ avrc_rsp.reg_notif.event_id = event_id;
+ avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+ avrc_rsp.reg_notif.status = AVRC_STS_ADDR_PLAYER_CHG;
+ BTIF_TRACE_WARNING("%s: Handling event ID: 0x%x", __func__, event_id);
+
+ send_metamsg_rsp(&btif_rc_cb.rc_multi_cb[idx], -1,
+ btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].label,
+ AVRC_RSP_REJ, &avrc_rsp);
+}
+
+/***************************************************************************
+ *
+ * Function register_notification_rsp
+ *
+ * Description Response to the register notification request.
+ *
+ * Returns bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t register_notification_rsp(
+ btrc_event_id_t event_id, btrc_notification_type_t type,
+ btrc_register_notification_t* p_param) {
+ tAVRC_RESPONSE avrc_rsp;
+ BTIF_TRACE_EVENT("%s: event_id: %s", __func__,
+ dump_rc_notification_event_id(event_id));
+ std::unique_lock<std::mutex> lock(btif_rc_cb.lock);
+
+ memset(&(avrc_rsp.reg_notif), 0, sizeof(tAVRC_REG_NOTIF_RSP));
+
+ avrc_rsp.reg_notif.event_id = event_id;
+ avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_rsp.reg_notif.opcode = opcode_from_pdu(AVRC_PDU_REGISTER_NOTIFICATION);
+ avrc_rsp.get_play_status.status = AVRC_STS_NO_ERROR;
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ memset(&(avrc_rsp.reg_notif.param), 0, sizeof(tAVRC_NOTIF_RSP_PARAM));
+
+ if (!(btif_rc_cb.rc_multi_cb[idx].rc_connected)) {
+ BTIF_TRACE_ERROR("%s: Avrcp device is not connected, handle: 0x%x",
+ __func__, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+ continue;
+ }
+
+ if (btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].bNotify == false) {
+ BTIF_TRACE_WARNING(
+ "%s: Avrcp Event id is not registered: event_id: %x, handle: 0x%x",
+ __func__, event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+ continue;
+ }
+
+ BTIF_TRACE_DEBUG(
+ "%s: Avrcp Event id is registered: event_id: %x handle: 0x%x", __func__,
+ event_id, btif_rc_cb.rc_multi_cb[idx].rc_handle);
+
+ switch (event_id) {
+ case BTRC_EVT_PLAY_STATUS_CHANGED:
+ avrc_rsp.reg_notif.param.play_status = p_param->play_status;
+ if (avrc_rsp.reg_notif.param.play_status == PLAY_STATUS_PLAYING)
+ btif_av_clear_remote_suspend_flag();
+ break;
+ case BTRC_EVT_TRACK_CHANGE:
+ memcpy(&(avrc_rsp.reg_notif.param.track), &(p_param->track),
+ sizeof(btrc_uid_t));
+ break;
+ case BTRC_EVT_PLAY_POS_CHANGED:
+ avrc_rsp.reg_notif.param.play_pos = p_param->song_pos;
+ break;
+ case BTRC_EVT_AVAL_PLAYER_CHANGE:
+ break;
+ case BTRC_EVT_ADDR_PLAYER_CHANGE:
+ avrc_rsp.reg_notif.param.addr_player.player_id =
+ p_param->addr_player_changed.player_id;
+ avrc_rsp.reg_notif.param.addr_player.uid_counter =
+ p_param->addr_player_changed.uid_counter;
+ break;
+ case BTRC_EVT_UIDS_CHANGED:
+ avrc_rsp.reg_notif.param.uid_counter =
+ p_param->uids_changed.uid_counter;
+ break;
+ case BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED:
+ break;
+
+ default:
+ BTIF_TRACE_WARNING("%s: Unhandled event ID: 0x%x", __func__, event_id);
+ return BT_STATUS_UNHANDLED;
+ }
+
+ /* Send the response. */
+ send_metamsg_rsp(
+ &btif_rc_cb.rc_multi_cb[idx], -1,
+ btif_rc_cb.rc_multi_cb[idx].rc_notif[event_id - 1].label,
+ ((type == BTRC_NOTIFICATION_TYPE_INTERIM) ? AVRC_CMD_NOTIF
+ : AVRC_RSP_CHANGED),
+ &avrc_rsp);
+
+ /* if notification type is address player changed, then complete all player
+ * specific
+ * notifications with AV/C C-Type REJECTED with error code Addressed Player
+ * Changed. */
+ if (event_id == BTRC_EVT_ADDR_PLAYER_CHANGE &&
+ type == BTRC_NOTIFICATION_TYPE_CHANGED) {
+ /* array includes notifications to be completed on addressed player change
+ */
+ btrc_event_id_t evt_id[] = {
+ BTRC_EVT_PLAY_STATUS_CHANGED, BTRC_EVT_TRACK_CHANGE,
+ BTRC_EVT_PLAY_POS_CHANGED, BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED};
+ for (uint8_t id = 0; id < sizeof(evt_id) / sizeof((evt_id)[0]); id++) {
+ reject_pending_notification(evt_id[id], idx);
+ }
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_items_list_rsp
+ *
+ * Description Returns the list of media items in current folder along with
+ * requested attributes. This is called in response to
+ * GetFolderItems request.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ * BT_STATUS_UNHANDLED - when rsp is not pending for
+ * get_folder_items_list PDU
+ *
+ **************************************************************************/
+static bt_status_t get_folder_items_list_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status,
+ uint16_t uid_counter,
+ uint8_t num_items,
+ btrc_folder_items_t* p_items) {
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_ITEM item;
+ tBTA_AV_CODE code = 0, ctype = 0;
+ BT_HDR* p_msg = NULL;
+ int item_cnt;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ btrc_folder_items_t* cur_item = NULL;
+
+ BTIF_TRACE_DEBUG("%s: uid_counter %d num_items %d", __func__, uid_counter,
+ num_items);
+ CHECK_RC_CONNECTED(p_dev);
+
+ /* check if rsp to previous cmd was completed */
+ if (p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending == false) {
+ BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
+ __func__);
+ return BT_STATUS_UNHANDLED;
+ }
+
+ memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+ memset(&item, 0, sizeof(tAVRC_ITEM));
+
+ avrc_rsp.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+ avrc_rsp.get_items.opcode = opcode_from_pdu(AVRC_PDU_GET_FOLDER_ITEMS);
+ avrc_rsp.get_items.status = status_code_map[rsp_status];
+
+ if (avrc_rsp.get_items.status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_WARNING(
+ "%s: Error in parsing the received getfolderitems cmd. status: 0x%02x",
+ __func__, avrc_rsp.get_items.status);
+ status = avrc_rsp.get_items.status;
+ } else {
+ avrc_rsp.get_items.uid_counter = uid_counter;
+ avrc_rsp.get_items.item_count = 1;
+
+ /* create single item and build response iteratively for all num_items */
+ for (item_cnt = 0; item_cnt < num_items; item_cnt++) {
+ cur_item = &p_items[item_cnt];
+ item.item_type = p_items->item_type;
+ /* build respective item based on item_type. All items should be of same
+ * type within
+ * a response */
+ switch (p_items->item_type) {
+ case AVRC_ITEM_PLAYER: {
+ item.u.player.name.charset_id = cur_item->player.charset_id;
+ memcpy(&(item.u.player.features), &(cur_item->player.features),
+ sizeof(cur_item->player.features));
+ item.u.player.major_type = cur_item->player.major_type;
+ item.u.player.sub_type = cur_item->player.sub_type;
+ item.u.player.play_status = cur_item->player.play_status;
+ item.u.player.player_id = cur_item->player.player_id;
+ item.u.player.name.p_str = cur_item->player.name;
+ item.u.player.name.str_len =
+ (uint16_t)strlen((char*)(cur_item->player.name));
+ } break;
+
+ case AVRC_ITEM_FOLDER: {
+ memcpy(item.u.folder.uid, cur_item->folder.uid, sizeof(tAVRC_UID));
+ item.u.folder.type = cur_item->folder.type;
+ item.u.folder.playable = cur_item->folder.playable;
+ item.u.folder.name.charset_id = AVRC_CHARSET_ID_UTF8;
+ item.u.folder.name.str_len = strlen((char*)cur_item->folder.name);
+ item.u.folder.name.p_str = cur_item->folder.name;
+ } break;
+
+ case AVRC_ITEM_MEDIA: {
+ tAVRC_ATTR_ENTRY attr_vals[BTRC_MAX_ELEM_ATTR_SIZE];
+
+ memcpy(item.u.media.uid, cur_item->media.uid, sizeof(tAVRC_UID));
+ item.u.media.type = cur_item->media.type;
+ item.u.media.name.charset_id = cur_item->media.charset_id;
+ item.u.media.name.str_len = strlen((char*)cur_item->media.name);
+ item.u.media.name.p_str = cur_item->media.name;
+ item.u.media.attr_count = cur_item->media.num_attrs;
+
+ /* Handle attributes of given item */
+ if (item.u.media.attr_count == 0) {
+ item.u.media.p_attr_list = NULL;
+ } else {
+ memset(&attr_vals, 0,
+ sizeof(tAVRC_ATTR_ENTRY) * BTRC_MAX_ELEM_ATTR_SIZE);
+ fill_avrc_attr_entry(attr_vals, item.u.media.attr_count,
+ cur_item->media.p_attrs);
+ item.u.media.p_attr_list = attr_vals;
+ }
+ } break;
+
+ default: {
+ BTIF_TRACE_ERROR("%s: Unknown item_type: %d. Internal Error",
+ __func__, p_items->item_type);
+ status = AVRC_STS_INTERNAL_ERR;
+ } break;
+ }
+
+ avrc_rsp.get_items.p_item_list = &item;
+
+ /* Add current item to buffer and build response if no error in item type
+ */
+ if (status != AVRC_STS_NO_ERROR) {
+ /* Reject response due to error occured for unknown item_type, break the
+ * loop */
+ break;
+ }
+
+ int len_before = p_msg ? p_msg->len : 0;
+ BTIF_TRACE_DEBUG("%s: item_cnt: %d len: %d", __func__, item_cnt,
+ len_before);
+ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+ BTIF_TRACE_DEBUG("%s: Build rsp status: %d len: %d", __func__, status,
+ (p_msg ? p_msg->len : 0));
+ int len_after = p_msg ? p_msg->len : 0;
+ if (status != AVRC_STS_NO_ERROR || len_before == len_after) {
+ /* Error occured in build response or we ran out of buffer so break the
+ * loop */
+ break;
+ }
+ }
+
+ /* setting the error status */
+ avrc_rsp.get_items.status = status;
+ }
+
+ /* if packet built successfully, send the built items to BTA layer */
+ if (status == AVRC_STS_NO_ERROR) {
+ code = p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype;
+ ctype = get_rsp_type_code(avrc_rsp.get_items.status, code);
+ BTA_AvMetaRsp(p_dev->rc_handle,
+ p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label, ctype,
+ p_msg);
+ } else /* Error occured, send reject response */
+ {
+ BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__,
+ avrc_rsp.rsp.status);
+ send_reject_response(
+ p_dev->rc_handle, p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label,
+ avrc_rsp.pdu, avrc_rsp.get_items.status, avrc_rsp.get_items.opcode);
+ }
+
+ /* Reset values for current pdu. */
+ p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].ctype = 0;
+ p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].label = 0;
+ p_dev->rc_pdu_info[IDX_GET_FOLDER_ITEMS_RSP].is_rsp_pending = false;
+
+ return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/***************************************************************************
+ *
+ * Function set_addressed_player_rsp
+ *
+ * Description Response to set the addressed player for specified media
+ * player based on id in the media player list.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t set_addressed_player_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+ avrc_rsp.addr_player.opcode = opcode_from_pdu(AVRC_PDU_SET_ADDRESSED_PLAYER);
+ avrc_rsp.addr_player.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_SET_ADDR_PLAYER_RSP,
+ p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].label,
+ p_dev->rc_pdu_info[IDX_SET_ADDR_PLAYER_RSP].ctype,
+ &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function set_browsed_player_rsp
+ *
+ * Description Response to set the browsed player command which contains
+ * current browsed path of the media player. By default,
+ * current_path = root and folder_depth = 0 for
+ * every set_browsed_player request.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - if RC is connected and reponse
+ * sent successfully
+ * BT_STATUS_UNHANDLED - when rsp is not pending for
+ * set_browsed_player PDU
+ *
+ **************************************************************************/
+static bt_status_t set_browsed_player_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status,
+ uint32_t num_items,
+ uint16_t charset_id,
+ uint8_t folder_depth,
+ btrc_br_folder_name_t* p_folders) {
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_NAME item;
+ BT_HDR* p_msg = NULL;
+ tBTA_AV_CODE code = 0;
+ tBTA_AV_CODE ctype = 0;
+ unsigned int item_cnt;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+
+ memset(&avrc_rsp, 0, sizeof(tAVRC_RESPONSE));
+ memset(&item, 0, sizeof(tAVRC_NAME));
+
+ avrc_rsp.br_player.status = status_code_map[rsp_status];
+ avrc_rsp.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+ avrc_rsp.br_player.opcode = opcode_from_pdu(AVRC_PDU_SET_BROWSED_PLAYER);
+
+ BTIF_TRACE_DEBUG("%s: rsp_status: 0x%02X avrc_rsp.br_player.status: 0x%02X",
+ __func__, rsp_status, avrc_rsp.br_player.status);
+
+ /* check if rsp to previous cmd was completed */
+ if (p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending == false) {
+ BTIF_TRACE_WARNING("%s: Not sending response as no PDU was registered",
+ __func__);
+ return BT_STATUS_UNHANDLED;
+ }
+
+ if (AVRC_STS_NO_ERROR == avrc_rsp.get_items.status) {
+ avrc_rsp.br_player.num_items = num_items;
+ avrc_rsp.br_player.charset_id = charset_id;
+ avrc_rsp.br_player.folder_depth = folder_depth;
+ avrc_rsp.br_player.p_folders = (tAVRC_NAME*)p_folders;
+
+ BTIF_TRACE_DEBUG("%s: folder_depth: 0x%02X num_items: %d", __func__,
+ folder_depth, num_items);
+
+ if (folder_depth > 0) {
+ /* Iteratively build response for all folders across folder depth upto
+ * current path */
+ avrc_rsp.br_player.folder_depth = 1;
+ for (item_cnt = 0; item_cnt < folder_depth; item_cnt++) {
+ BTIF_TRACE_DEBUG("%s: iteration: %d", __func__, item_cnt);
+ item.str_len = p_folders[item_cnt].str_len;
+ item.p_str = p_folders[item_cnt].p_str;
+ avrc_rsp.br_player.p_folders = &item;
+
+ /* Add current item to buffer and build response */
+ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+ if (AVRC_STS_NO_ERROR != status) {
+ BTIF_TRACE_WARNING("%s: Build rsp status: %d", __func__, status);
+ /* if the build fails, it is likely that we ran out of buffer. so if
+ * we have
+ * some items to send, reset this error to no error for sending what we
+ * have */
+ if (item_cnt > 0) status = AVRC_STS_NO_ERROR;
+
+ /* Error occured in build response so break the loop */
+ break;
+ }
+ }
+ } else /* current path is root folder, no folders navigated yet */
+ {
+ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+ }
+
+ /* setting the error status */
+ avrc_rsp.br_player.status = status;
+ } else /* error received from above layer */
+ {
+ BTIF_TRACE_WARNING(
+ "%s: Error in parsing the received setbrowsed command. status: 0x%02x",
+ __func__, avrc_rsp.br_player.status);
+ status = avrc_rsp.br_player.status;
+ }
+
+ /* if packet built successfully, send the built items to BTA layer */
+ if (status == AVRC_STS_NO_ERROR) {
+ code = p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype;
+ ctype = get_rsp_type_code(avrc_rsp.br_player.status, code);
+ BTA_AvMetaRsp(p_dev->rc_handle,
+ p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label, ctype,
+ p_msg);
+ } else /* Error occured, send reject response */
+ {
+ BTIF_TRACE_ERROR("%s: Error status: 0x%02X. Sending reject rsp", __func__,
+ avrc_rsp.br_player.status);
+ send_reject_response(
+ p_dev->rc_handle, p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label,
+ avrc_rsp.pdu, avrc_rsp.br_player.status, avrc_rsp.get_items.opcode);
+ }
+
+ /* Reset values for set_browsed_player pdu.*/
+ p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].ctype = 0;
+ p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].label = 0;
+ p_dev->rc_pdu_info[IDX_SET_BROWSED_PLAYER_RSP].is_rsp_pending = false;
+
+ return status == AVRC_STS_NO_ERROR ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function change_path_rsp
+ *
+ * Description Response to the change path command which
+ * contains number of items in the changed path.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t change_path_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status,
+ uint32_t num_items) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+ avrc_rsp.chg_path.opcode = opcode_from_pdu(AVRC_PDU_CHANGE_PATH);
+ avrc_rsp.chg_path.num_items = num_items;
+ avrc_rsp.chg_path.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_CHG_PATH_RSP,
+ p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].label,
+ p_dev->rc_pdu_info[IDX_CHG_PATH_RSP].ctype, &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function search_rsp
+ *
+ * Description Response to search a string from media content command.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t search_rsp(bt_bdaddr_t* bd_addr, btrc_status_t rsp_status,
+ uint32_t uid_counter, uint32_t num_items) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.search.pdu = AVRC_PDU_SEARCH;
+ avrc_rsp.search.opcode = opcode_from_pdu(AVRC_PDU_SEARCH);
+ avrc_rsp.search.num_items = num_items;
+ avrc_rsp.search.uid_counter = uid_counter;
+ avrc_rsp.search.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_SEARCH_RSP,
+ p_dev->rc_pdu_info[IDX_SEARCH_RSP].label,
+ p_dev->rc_pdu_info[IDX_SEARCH_RSP].ctype, &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+/***************************************************************************
+ *
+ * Function get_item_attr_rsp
+ *
+ * Description Response to the get item's attributes command which
+ * contains number of attributes and values list in text.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t get_item_attr_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status, uint8_t num_attr,
+ btrc_element_attr_val_t* p_attrs) {
+ tAVRC_RESPONSE avrc_rsp;
+ tAVRC_ATTR_ENTRY item_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ memset(item_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
+
+ avrc_rsp.get_attrs.status = status_code_map[rsp_status];
+ if (rsp_status == BTRC_STS_NO_ERROR) {
+ fill_avrc_attr_entry(item_attrs, num_attr, p_attrs);
+ }
+
+ avrc_rsp.get_attrs.num_attrs = num_attr;
+ avrc_rsp.get_attrs.p_attrs = item_attrs;
+ avrc_rsp.get_attrs.pdu = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+ avrc_rsp.get_attrs.opcode = opcode_from_pdu(AVRC_PDU_GET_ITEM_ATTRIBUTES);
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_GET_ITEM_ATTR_RSP,
+ p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].label,
+ p_dev->rc_pdu_info[IDX_GET_ITEM_ATTR_RSP].ctype, &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function add_to_now_playing_rsp
+ *
+ * Description Response to command for adding speciafied media item
+ * to Now Playing queue.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t add_to_now_playing_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.add_to_play.pdu = AVRC_PDU_ADD_TO_NOW_PLAYING;
+ avrc_rsp.add_to_play.opcode = opcode_from_pdu(AVRC_PDU_ADD_TO_NOW_PLAYING);
+ avrc_rsp.add_to_play.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_ADD_TO_NOW_PLAYING_RSP,
+ p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].label,
+ p_dev->rc_pdu_info[IDX_ADD_TO_NOW_PLAYING_RSP].ctype,
+ &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function play_item_rsp
+ *
+ * Description Response to command for playing the specified media item.
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t play_item_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.play_item.pdu = AVRC_PDU_PLAY_ITEM;
+ avrc_rsp.play_item.opcode = opcode_from_pdu(AVRC_PDU_PLAY_ITEM);
+ avrc_rsp.play_item.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_PLAY_ITEM_RSP,
+ p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].label,
+ p_dev->rc_pdu_info[IDX_PLAY_ITEM_RSP].ctype, &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function get_total_num_of_items_rsp
+ *
+ * Description response to command to get the Number of Items
+ * in the selected folder at the selected scope
+ *
+ * Returns bt_status_t
+ * BT_STATUS_NOT_READY - when RC is not connected.
+ * BT_STATUS_SUCCESS - always if RC is connected
+ *
+ **************************************************************************/
+static bt_status_t get_total_num_of_items_rsp(bt_bdaddr_t* bd_addr,
+ btrc_status_t rsp_status,
+ uint32_t uid_counter,
+ uint32_t num_items) {
+ tAVRC_RESPONSE avrc_rsp;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.get_num_of_items.pdu = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS;
+ avrc_rsp.get_num_of_items.opcode =
+ opcode_from_pdu(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS);
+ avrc_rsp.get_num_of_items.num_items = num_items;
+ avrc_rsp.get_num_of_items.uid_counter = uid_counter;
+ avrc_rsp.get_num_of_items.status = status_code_map[rsp_status];
+
+ /* Send the response. */
+ send_metamsg_rsp(p_dev, IDX_GET_TOTAL_NUM_OF_ITEMS_RSP,
+ p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].label,
+ p_dev->rc_pdu_info[IDX_GET_TOTAL_NUM_OF_ITEMS_RSP].ctype,
+ &avrc_rsp);
+
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function set_volume
+ *
+ * Description Send current volume setting to remote side.
+ * Support limited to SetAbsoluteVolume
+ * This can be enhanced to support Relative Volume (AVRCP 1.0).
+ * With RelateVolume, we will send VOLUME_UP/VOLUME_DOWN
+ * as opposed to absolute volume level
+ * volume: Should be in the range 0-127. bit7 is reseved and cannot be set
+ *
+ * Returns bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t set_volume(uint8_t volume) {
+ BTIF_TRACE_DEBUG("%s: volume: %d", __func__, volume);
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t* p_transaction = NULL;
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ if (!btif_rc_cb.rc_multi_cb[idx].rc_connected) {
+ status = BT_STATUS_NOT_READY;
+ BTIF_TRACE_ERROR("%s: RC is not connected for device: 0x%x", __func__,
+ btif_rc_cb.rc_multi_cb[idx].rc_addr);
+ continue;
+ }
+
+ if (btif_rc_cb.rc_multi_cb[idx].rc_volume == volume) {
+ status = BT_STATUS_DONE;
+ BTIF_TRACE_ERROR("%s: volume value already set earlier: 0x%02x", __func__,
+ volume);
+ continue;
+ }
+
+ if ((btif_rc_cb.rc_multi_cb[idx].rc_volume != volume) &&
+ btif_rc_cb.rc_multi_cb[idx].rc_state ==
+ BTRC_CONNECTION_STATE_CONNECTED) {
+ if ((btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_RCTG) == 0) {
+ status = BT_STATUS_NOT_READY;
+ continue;
+ } else {
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR* p_msg = NULL;
+
+ if (btif_rc_cb.rc_multi_cb[idx].rc_features & BTA_AV_FEAT_ADV_CTRL) {
+ BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
+ __func__, volume);
+ avrc_cmd.volume.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+ avrc_cmd.volume.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.volume.volume = volume;
+
+ if (AVRC_BldCommand(&avrc_cmd, &p_msg) == AVRC_STS_NO_ERROR) {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+
+ if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
+ BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d",
+ __func__, p_transaction->lbl);
+ BTA_AvMetaCmd(btif_rc_cb.rc_multi_cb[idx].rc_handle,
+ p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ status = BT_STATUS_SUCCESS;
+ } else {
+ osi_free_and_reset((void**)&p_msg);
+ BTIF_TRACE_ERROR(
+ "%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ status = BT_STATUS_FAIL;
+ }
+ } else {
+ BTIF_TRACE_ERROR(
+ "%s: failed to build absolute volume command. status: 0x%02x",
+ __func__, status);
+ status = BT_STATUS_FAIL;
+ }
+ }
+ }
+ }
+ }
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function register_volumechange
+ *
+ * Description Register for volume change notification from remote side.
+ *
+ * Returns void
+ *
+ **************************************************************************/
+
+static void register_volumechange(uint8_t lbl, btif_rc_device_cb_t* p_dev) {
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS BldResp = AVRC_STS_BAD_CMD;
+ rc_transaction_t* p_transaction = NULL;
+
+ BTIF_TRACE_DEBUG("%s: label: %d", __func__, lbl);
+
+ avrc_cmd.cmd.opcode = 0x00;
+ avrc_cmd.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_cmd.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
+ avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.reg_notif.param = 0;
+
+ BldResp = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (AVRC_STS_NO_ERROR == BldResp && p_msg) {
+ p_transaction = get_transaction_by_lbl(lbl);
+ if (p_transaction != NULL) {
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_NOTIF,
+ p_msg);
+ BTIF_TRACE_DEBUG("%s: BTA_AvMetaCmd called", __func__);
+ } else {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: transaction not obtained with label: %d", __func__,
+ lbl);
+ }
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build command: %d", __func__, BldResp);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_rc_metamsg_rsp
+ *
+ * Description Handle RC metamessage response
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void handle_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg,
+ btif_rc_device_cb_t* p_dev) {
+ tAVRC_RESPONSE avrc_response = {0};
+ uint8_t scratch_buf[512] = {0};
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+
+ BTIF_TRACE_DEBUG("%s: ", __func__);
+
+ if (AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode &&
+ (AVRC_RSP_CHANGED == pmeta_msg->code ||
+ AVRC_RSP_INTERIM == pmeta_msg->code ||
+ AVRC_RSP_ACCEPT == pmeta_msg->code || AVRC_RSP_REJ == pmeta_msg->code ||
+ AVRC_RSP_NOT_IMPL == pmeta_msg->code)) {
+ status = AVRC_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
+ sizeof(scratch_buf));
+ BTIF_TRACE_DEBUG(
+ "%s: code:%d, event ID: %d, PDU: %x, parsing status: %d, label: %d",
+ __func__, pmeta_msg->code, avrc_response.reg_notif.event_id,
+ avrc_response.reg_notif.pdu, status, pmeta_msg->label);
+
+ if (status != AVRC_STS_NO_ERROR) {
+ if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+ AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+ p_dev->rc_vol_label == pmeta_msg->label) {
+ p_dev->rc_vol_label = MAX_LABEL;
+ release_transaction(p_dev->rc_vol_label);
+ } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
+ release_transaction(pmeta_msg->label);
+ }
+ return;
+ }
+
+ if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+ AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+ p_dev->rc_vol_label != pmeta_msg->label) {
+ // Just discard the message, if the device sends back with an incorrect
+ // label
+ BTIF_TRACE_DEBUG(
+ "%s: Discarding register notification in rsp.code: %d and label: %d",
+ __func__, pmeta_msg->code, pmeta_msg->label);
+ return;
+ }
+
+ if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+ AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+ (AVRC_RSP_REJ == pmeta_msg->code ||
+ AVRC_RSP_NOT_IMPL == pmeta_msg->code)) {
+ BTIF_TRACE_DEBUG("%s remove AbsoluteVolume feature flag.", __func__);
+ p_dev->rc_features &= ~BTA_AV_FEAT_ADV_CTRL;
+ handle_rc_features(p_dev);
+ return;
+ }
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: Received vendor dependent in adv ctrl rsp. code: %d len: %d. Not "
+ "processing it.",
+ __func__, pmeta_msg->code, pmeta_msg->len);
+ return;
+ }
+
+ if (AVRC_PDU_REGISTER_NOTIFICATION == avrc_response.rsp.pdu &&
+ AVRC_EVT_VOLUME_CHANGE == avrc_response.reg_notif.event_id &&
+ AVRC_RSP_CHANGED == pmeta_msg->code) {
+ /* re-register for volume change notification */
+ // Do not re-register for rejected case, as it might get into endless loop
+ register_volumechange(p_dev->rc_vol_label, p_dev);
+ } else if (AVRC_PDU_SET_ABSOLUTE_VOLUME == avrc_response.rsp.pdu) {
+ /* free up the label here */
+ release_transaction(pmeta_msg->label);
+ }
+
+ BTIF_TRACE_EVENT("%s: Passing received metamsg response to app. pdu: %s",
+ __func__, dump_rc_pdu(avrc_response.pdu));
+ btif_rc_upstreams_rsp_evt((uint16_t)avrc_response.rsp.pdu, &avrc_response,
+ pmeta_msg->code, pmeta_msg->label, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function iterate_supported_event_list_for_interim_rsp
+ *
+ * Description iterator callback function to match the event and handle
+ * timer cleanup
+ * Returns true to continue iterating, false to stop
+ *
+ **************************************************************************/
+bool iterate_supported_event_list_for_interim_rsp(void* data, void* cb_data) {
+ uint8_t* p_event_id;
+ btif_rc_supported_event_t* p_event = (btif_rc_supported_event_t*)data;
+
+ p_event_id = (uint8_t*)cb_data;
+
+ if (p_event->event_id == *p_event_id) {
+ p_event->status = eINTERIM;
+ return false;
+ }
+ return true;
+}
+
+/***************************************************************************
+ *
+ * Function iterate_supported_event_list_for_timeout
+ *
+ * Description Iterator callback function for timeout handling.
+ * As part of the failure handling, it releases the
+ * transaction label and removes the event from list,
+ * this event will not be requested again during
+ * the lifetime of the connection.
+ * Returns false to stop iterating, true to continue
+ *
+ **************************************************************************/
+bool iterate_supported_event_list_for_timeout(void* data, void* cb_data) {
+ bt_bdaddr_t bd_addr;
+ rc_context_t* cntxt = (rc_context_t*)cb_data;
+ uint8_t label = cntxt->label & 0xFF;
+ bdcpy(bd_addr.address, cntxt->rc_addr);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&bd_addr);
+ btif_rc_supported_event_t* p_event = (btif_rc_supported_event_t*)data;
+
+ if (p_event->label == label) {
+ list_remove(p_dev->rc_supported_event_list, p_event);
+ return false;
+ }
+ return true;
+}
+
+/***************************************************************************
+ *
+ * Function rc_notification_interim_timout
+ *
+ * Description Interim response timeout handler.
+ * Runs the iterator to check and clear the timed out event.
+ * Proceeds to register for the unregistered events.
+ * Returns None
+ *
+ **************************************************************************/
+static void rc_notification_interim_timout(uint8_t label,
+ btif_rc_device_cb_t* p_dev) {
+ list_node_t* node;
+ rc_context_t cntxt;
+ memset(&cntxt, 0, sizeof(rc_context_t));
+ cntxt.label = label;
+ bdcpy(cntxt.rc_addr, p_dev->rc_addr);
+
+ list_foreach(p_dev->rc_supported_event_list,
+ iterate_supported_event_list_for_timeout, &cntxt);
+ /* Timeout happened for interim response for the registered event,
+ * check if there are any pending for registration
+ */
+ node = list_begin(p_dev->rc_supported_event_list);
+ while (node != NULL) {
+ btif_rc_supported_event_t* p_event;
+
+ p_event = (btif_rc_supported_event_t*)list_node(node);
+ if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED)) {
+ register_for_event_notification(p_event, p_dev);
+ break;
+ }
+ node = list_next(node);
+ }
+ /* Todo. Need to initiate application settings query if this
+ * is the last event registration.
+ */
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_status_cmd_timeout_handler
+ *
+ * Description RC status command timeout handler (Runs in BTIF context).
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_status_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
+ char* data) {
+ btif_rc_timer_context_t* p_context;
+ tAVRC_RESPONSE avrc_response = {0};
+ tBTA_AV_META_MSG meta_msg;
+ btif_rc_device_cb_t* p_dev = NULL;
+ bt_bdaddr_t bd_addr;
+
+ p_context = (btif_rc_timer_context_t*)data;
+ bdcpy(bd_addr.address, p_context->rc_addr);
+ memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+ p_dev = btif_rc_get_device_by_bda(&bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+ meta_msg.rc_handle = p_dev->rc_handle;
+
+ switch (p_context->rc_status_cmd.pdu_id) {
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ rc_notification_interim_timout(p_context->rc_status_cmd.label, p_dev);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ avrc_response.get_caps.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_capability_response(&meta_msg, &avrc_response.get_caps);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ avrc_response.list_app_attr.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_response(&meta_msg, &avrc_response.list_app_attr);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ avrc_response.list_app_values.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_val_response(&meta_msg, &avrc_response.list_app_values);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ avrc_response.get_cur_app_val.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_cur_val_response(&meta_msg, &avrc_response.get_cur_app_val);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ avrc_response.get_app_attr_txt.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_attr_txt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ avrc_response.get_app_val_txt.status = BTIF_RC_STS_TIMEOUT;
+ handle_app_attr_txt_response(&meta_msg, &avrc_response.get_app_val_txt);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ avrc_response.get_attrs.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_elem_attr_response(&meta_msg, &avrc_response.get_attrs);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ avrc_response.get_play_status.status = BTIF_RC_STS_TIMEOUT;
+ handle_get_playstatus_response(&meta_msg, &avrc_response.get_play_status);
+ break;
+ }
+ release_transaction(p_context->rc_status_cmd.label);
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_status_cmd_timer_timeout
+ *
+ * Description RC status command timeout callback.
+ * This is called from BTU context and switches to BTIF
+ * context to handle the timeout events
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_status_cmd_timer_timeout(void* data) {
+ btif_rc_timer_context_t* p_data = (btif_rc_timer_context_t*)data;
+
+ btif_transfer_context(btif_rc_status_cmd_timeout_handler, 0, (char*)p_data,
+ sizeof(btif_rc_timer_context_t), NULL);
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_control_cmd_timeout_handler
+ *
+ * Description RC control command timeout handler (Runs in BTIF context).
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_control_cmd_timeout_handler(UNUSED_ATTR uint16_t event,
+ char* data) {
+ btif_rc_timer_context_t* p_context = (btif_rc_timer_context_t*)data;
+ tAVRC_RESPONSE avrc_response = {0};
+ tBTA_AV_META_MSG meta_msg;
+ bt_bdaddr_t bd_addr;
+ bdcpy(bd_addr.address, p_context->rc_addr);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(&bd_addr);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ memset(&meta_msg, 0, sizeof(tBTA_AV_META_MSG));
+ meta_msg.rc_handle = p_dev->rc_handle;
+
+ switch (p_context->rc_control_cmd.pdu_id) {
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ avrc_response.set_app_val.status = BTIF_RC_STS_TIMEOUT;
+ handle_set_app_attr_val_response(&meta_msg, &avrc_response.set_app_val);
+ break;
+ }
+ release_transaction(p_context->rc_control_cmd.label);
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_control_cmd_timer_timeout
+ *
+ * Description RC control command timeout callback.
+ * This is called from BTU context and switches to BTIF
+ * context to handle the timeout events
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_control_cmd_timer_timeout(void* data) {
+ btif_rc_timer_context_t* p_data = (btif_rc_timer_context_t*)data;
+
+ btif_transfer_context(btif_rc_control_cmd_timeout_handler, 0, (char*)p_data,
+ sizeof(btif_rc_timer_context_t), NULL);
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_play_status_timeout_handler
+ *
+ * Description RC play status timeout handler (Runs in BTIF context).
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_play_status_timeout_handler(UNUSED_ATTR uint16_t event,
+ char* p_data) {
+ btif_rc_handle_t* rc_handle = (btif_rc_handle_t*)p_data;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_handle(rc_handle->handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s timeout handler but no device found for handle %d",
+ __func__, rc_handle->handle);
+ return;
+ }
+ get_play_status_cmd(p_dev);
+ rc_start_play_status_timer(p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function btif_rc_play_status_timer_timeout
+ *
+ * Description RC play status timeout callback.
+ * This is called from BTU context and switches to BTIF
+ * context to handle the timeout events
+ * Returns None
+ *
+ **************************************************************************/
+static void btif_rc_play_status_timer_timeout(void* data) {
+ btif_rc_handle_t rc_handle;
+ rc_handle.handle = PTR_TO_UINT(data);
+ BTIF_TRACE_DEBUG("%s called with handle: %d", __func__, rc_handle);
+ btif_transfer_context(btif_rc_play_status_timeout_handler, 0,
+ (char*)(&rc_handle), sizeof(btif_rc_handle_t), NULL);
+}
+
+/***************************************************************************
+ *
+ * Function rc_start_play_status_timer
+ *
+ * Description Helper function to start the timer to fetch play status.
+ * Returns None
+ *
+ **************************************************************************/
+static void rc_start_play_status_timer(btif_rc_device_cb_t* p_dev) {
+ /* Start the Play status timer only if it is not started */
+ if (!alarm_is_scheduled(p_dev->rc_play_status_timer)) {
+ if (p_dev->rc_play_status_timer == NULL) {
+ p_dev->rc_play_status_timer = alarm_new("p_dev->rc_play_status_timer");
+ }
+ alarm_set_on_queue(p_dev->rc_play_status_timer,
+ BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
+ btif_rc_play_status_timer_timeout,
+ UINT_TO_PTR(p_dev->rc_handle), btu_general_alarm_queue);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function rc_stop_play_status_timer
+ *
+ * Description Helper function to stop the play status timer.
+ * Returns None
+ *
+ **************************************************************************/
+void rc_stop_play_status_timer(btif_rc_device_cb_t* p_dev) {
+ alarm_cancel(p_dev->rc_play_status_timer);
+}
+
+/***************************************************************************
+ *
+ * Function register_for_event_notification
+ *
+ * Description Helper function registering notification events
+ * sets an interim response timeout to handle if the remote
+ * does not respond.
+ * Returns None
+ *
+ **************************************************************************/
+static void register_for_event_notification(btif_rc_supported_event_t* p_event,
+ btif_rc_device_cb_t* p_dev) {
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t status = get_transaction(&p_transaction);
+ if (status != BT_STATUS_SUCCESS) {
+ BTIF_TRACE_ERROR("%s: no more transaction labels: %d", __func__, status);
+ return;
+ }
+
+ status = register_notification_cmd(p_transaction->lbl, p_event->event_id, 0,
+ p_dev);
+ if (status != BT_STATUS_SUCCESS) {
+ BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
+ status);
+ release_transaction(p_transaction->lbl);
+ return;
+ }
+
+ btif_rc_timer_context_t* p_context = &p_transaction->txn_timer_context;
+ p_event->label = p_transaction->lbl;
+ p_event->status = eREGISTERED;
+ p_context->rc_status_cmd.label = p_transaction->lbl;
+ p_context->rc_status_cmd.pdu_id = AVRC_PDU_REGISTER_NOTIFICATION;
+ bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+ alarm_free(p_transaction->txn_timer);
+ p_transaction->txn_timer = alarm_new("btif_rc.status_command_txn_timer");
+ alarm_set_on_queue(p_transaction->txn_timer, BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
+ btif_rc_status_cmd_timer_timeout, p_context,
+ btu_general_alarm_queue);
+}
+
+static void start_status_command_timer(uint8_t pdu_id, rc_transaction_t* p_txn,
+ btif_rc_device_cb_t* p_dev) {
+ btif_rc_timer_context_t* p_context = &p_txn->txn_timer_context;
+ p_context->rc_status_cmd.label = p_txn->lbl;
+ p_context->rc_status_cmd.pdu_id = pdu_id;
+ bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+ alarm_free(p_txn->txn_timer);
+ p_txn->txn_timer = alarm_new("btif_rc.status_command_txn_timer");
+ alarm_set_on_queue(p_txn->txn_timer, BTIF_TIMEOUT_RC_STATUS_CMD_MS,
+ btif_rc_status_cmd_timer_timeout, p_context,
+ btu_general_alarm_queue);
+}
+
+static void start_control_command_timer(uint8_t pdu_id, rc_transaction_t* p_txn,
+ btif_rc_device_cb_t* p_dev) {
+ btif_rc_timer_context_t* p_context = &p_txn->txn_timer_context;
+ p_context->rc_control_cmd.label = p_txn->lbl;
+ p_context->rc_control_cmd.pdu_id = pdu_id;
+ bdcpy(p_context->rc_addr, p_dev->rc_addr);
+
+ alarm_free(p_txn->txn_timer);
+ p_txn->txn_timer = alarm_new("btif_rc.control_command_txn_timer");
+ alarm_set_on_queue(p_txn->txn_timer, BTIF_TIMEOUT_RC_CONTROL_CMD_MS,
+ btif_rc_control_cmd_timer_timeout, p_context,
+ btu_general_alarm_queue);
+}
+
+bt_status_t build_and_send_vendor_cmd(tAVRC_COMMAND* avrc_cmd,
+ tBTA_AV_CODE cmd_code,
+ btif_rc_device_cb_t* p_dev) {
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS != tran_status) return BT_STATUS_FAIL;
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status = AVRC_BldCommand(avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR && p_msg != NULL) {
+ uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s: %s msgreq being sent out with label: %d", __func__,
+ dump_rc_pdu(avrc_cmd->pdu), p_transaction->lbl);
+ BTA_AvVendorCmd(p_dev->rc_handle, p_transaction->lbl, cmd_code, data_start,
+ p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ if (cmd_code == AVRC_CMD_STATUS) {
+ start_status_command_timer(avrc_cmd->pdu, p_transaction, p_dev);
+ } else if (cmd_code == AVRC_CMD_CTRL) {
+ start_control_command_timer(avrc_cmd->pdu, p_transaction, p_dev);
+ }
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+ status);
+ }
+ osi_free(p_msg);
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function handle_get_capability_response
+ *
+ * Description Handles the get_cap_response to populate company id info
+ * and query the supported events.
+ * Initiates Notification registration for events supported
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_get_capability_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_CAPS_RSP* p_rsp) {
+ int xx = 0;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: Error capability response: 0x%02X", __func__,
+ p_rsp->status);
+ return;
+ }
+
+ if (p_rsp->capability_id == AVRC_CAP_EVENTS_SUPPORTED) {
+ btif_rc_supported_event_t* p_event;
+
+ /* Todo: Check if list can be active when we hit here */
+ p_dev->rc_supported_event_list = list_new(osi_free);
+ for (xx = 0; xx < p_rsp->count; xx++) {
+ /* Skip registering for Play position change notification */
+ if ((p_rsp->param.event_id[xx] == AVRC_EVT_PLAY_STATUS_CHANGE) ||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_TRACK_CHANGE) ||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_APP_SETTING_CHANGE) ||
+ (p_rsp->param.event_id[xx] == AVRC_EVT_UIDS_CHANGE)) {
+ p_event = (btif_rc_supported_event_t*)osi_malloc(
+ sizeof(btif_rc_supported_event_t));
+ p_event->event_id = p_rsp->param.event_id[xx];
+ p_event->status = eNOT_REGISTERED;
+ list_append(p_dev->rc_supported_event_list, p_event);
+ }
+ }
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+ /* To avoid the condtion: Host and remote device are all sink. In this case, list length is zero */
+ if (list_length(p_dev->rc_supported_event_list) != 0) {
+ BTIF_TRACE_EVENT("supported event list size:%d", list_length(p_dev->rc_supported_event_list));
+ p_event = (btif_rc_supported_event_t*)list_front(p_dev->rc_supported_event_list);
+ }
+#else
+ p_event =
+ (btif_rc_supported_event_t*)list_front(p_dev->rc_supported_event_list);
+#endif
+
+ if (p_event != NULL) {
+ register_for_event_notification(p_event, p_dev);
+ }
+ } else if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) {
+ getcapabilities_cmd(AVRC_CAP_EVENTS_SUPPORTED, p_dev);
+ BTIF_TRACE_EVENT("%s: AVRC_CAP_COMPANY_ID: ", __func__);
+ for (xx = 0; xx < p_rsp->count; xx++) {
+ BTIF_TRACE_EVENT("%s: company_id: %d", __func__,
+ p_rsp->param.company_id[xx]);
+ }
+ }
+}
+
+bool rc_is_track_id_valid(tAVRC_UID uid) {
+ tAVRC_UID invalid_uid = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ if (memcmp(uid, invalid_uid, sizeof(tAVRC_UID)) == 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_notification_response
+ *
+ * Description Main handler for notification responses to registered events
+ * 1. Register for unregistered event(in interim response path)
+ * 2. After registering for all supported events, start
+ * retrieving application settings and values
+ * 3. Reregister for events on getting changed response
+ * 4. Run play status timer for getting position when the
+ * status changes to playing
+ * 5. Get the Media details when the track change happens
+ * or track change interim response is received with
+ * valid track id
+ * 6. HAL callback for play status change and application
+ * setting change
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_REG_NOTIF_RSP* p_rsp) {
+ bt_bdaddr_t rc_addr;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ uint32_t attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM, AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS, AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (pmeta_msg->code == AVRC_RSP_INTERIM) {
+ btif_rc_supported_event_t* p_event;
+ list_node_t* node;
+
+ BTIF_TRACE_DEBUG("%s: Interim response: 0x%2X ", __func__, p_rsp->event_id);
+ switch (p_rsp->event_id) {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ /* Start timer to get play status periodically
+ * if the play state is playing.
+ */
+ if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
+ rc_start_play_status_timer(p_dev);
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
+ (btrc_play_status_t)p_rsp->param.play_status);
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ if (rc_is_track_id_valid(p_rsp->param.track) != true) {
+ break;
+ } else {
+ uint8_t* p_data = p_rsp->param.track;
+ /* Update the UID for current track
+ * Attributes will be fetched after the AVRCP procedure
+ */
+ BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
+ }
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE:
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ BTIF_TRACE_ERROR("%s: Unhandled interim response: 0x%2X", __func__,
+ p_rsp->event_id);
+ return;
+ }
+
+ list_foreach(p_dev->rc_supported_event_list,
+ iterate_supported_event_list_for_interim_rsp,
+ &p_rsp->event_id);
+
+ node = list_begin(p_dev->rc_supported_event_list);
+
+ while (node != NULL) {
+ p_event = (btif_rc_supported_event_t*)list_node(node);
+ if ((p_event != NULL) && (p_event->status == eNOT_REGISTERED)) {
+ register_for_event_notification(p_event, p_dev);
+ break;
+ }
+ node = list_next(node);
+ p_event = NULL;
+ }
+ /* Registered for all events, we can request application settings */
+ if (p_event == NULL && p_dev->rc_app_settings.query_started == false) {
+ /* we need to do this only if remote TG supports
+ * player application settings
+ */
+ p_dev->rc_app_settings.query_started = true;
+ if (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING) {
+ list_player_app_setting_attrib_cmd(p_dev);
+ } else {
+ BTIF_TRACE_DEBUG("%s: App setting not supported, complete procedure",
+ __func__);
+ rc_ctrl_procedure_complete(p_dev);
+ }
+ }
+ } else if (pmeta_msg->code == AVRC_RSP_CHANGED) {
+ btif_rc_supported_event_t* p_event;
+ list_node_t* node;
+
+ BTIF_TRACE_DEBUG("%s: Notification completed: 0x%2X ", __func__,
+ p_rsp->event_id);
+
+ node = list_begin(p_dev->rc_supported_event_list);
+
+ while (node != NULL) {
+ p_event = (btif_rc_supported_event_t*)list_node(node);
+ if (p_event != NULL && p_event->event_id == p_rsp->event_id) {
+ p_event->status = eNOT_REGISTERED;
+ register_for_event_notification(p_event, p_dev);
+ break;
+ }
+ node = list_next(node);
+ }
+
+ switch (p_rsp->event_id) {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ /* Start timer to get play status periodically
+ * if the play state is playing.
+ */
+ if (p_rsp->param.play_status == AVRC_PLAYSTATE_PLAYING) {
+ rc_start_play_status_timer(p_dev);
+ } else {
+ rc_stop_play_status_timer(p_dev);
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_status_changed_cb, &rc_addr,
+ (btrc_play_status_t)p_rsp->param.play_status);
+
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ if (rc_is_track_id_valid(p_rsp->param.track) != true) {
+ break;
+ }
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE: {
+ btrc_player_settings_t app_settings;
+ uint16_t xx;
+
+ app_settings.num_attr = p_rsp->param.player_setting.num_attr;
+ for (xx = 0; xx < app_settings.num_attr; xx++) {
+ app_settings.attr_ids[xx] = p_rsp->param.player_setting.attr_id[xx];
+ app_settings.attr_values[xx] =
+ p_rsp->param.player_setting.attr_value[xx];
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb,
+ &rc_addr, &app_settings);
+ } break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ BTIF_TRACE_ERROR("%s: Unhandled completion response: 0x%2X", __func__,
+ p_rsp->event_id);
+ return;
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_app_attr_response
+ *
+ * Description handles the the application attributes response and
+ * initiates procedure to fetch the attribute values
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_LIST_APP_ATTR_RSP* p_rsp) {
+ uint8_t xx;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: Error getting Player application settings: 0x%2X",
+ __func__, p_rsp->status);
+ rc_ctrl_procedure_complete(p_dev);
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++) {
+ uint8_t st_index;
+
+ if (p_rsp->attrs[xx] > AVRC_PLAYER_SETTING_LOW_MENU_EXT) {
+ st_index = p_dev->rc_app_settings.num_ext_attrs;
+ p_dev->rc_app_settings.ext_attrs[st_index].attr_id = p_rsp->attrs[xx];
+ p_dev->rc_app_settings.num_ext_attrs++;
+ } else {
+ st_index = p_dev->rc_app_settings.num_attrs;
+ p_dev->rc_app_settings.attrs[st_index].attr_id = p_rsp->attrs[xx];
+ p_dev->rc_app_settings.num_attrs++;
+ }
+ }
+ p_dev->rc_app_settings.attr_index = 0;
+ p_dev->rc_app_settings.ext_attr_index = 0;
+ p_dev->rc_app_settings.ext_val_index = 0;
+ if (p_rsp->num_attr) {
+ list_player_app_setting_value_cmd(p_dev->rc_app_settings.attrs[0].attr_id,
+ p_dev);
+ } else {
+ BTIF_TRACE_ERROR("%s: No Player application settings found", __func__);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_app_val_response
+ *
+ * Description handles the the attributes value response and if extended
+ * menu is available, it initiates query for the attribute
+ * text. If not, it initiates procedure to get the current
+ * attribute values and calls the HAL callback for provding
+ * application settings information.
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_app_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_LIST_APP_VALUES_RSP* p_rsp) {
+ uint8_t xx, attr_index;
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t* p_app_settings;
+ bt_bdaddr_t rc_addr;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_dev == NULL || p_rsp->status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: Error fetching attribute values: 0x%02X", __func__,
+ p_rsp->status);
+ return;
+ }
+
+ p_app_settings = &p_dev->rc_app_settings;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_app_settings->attr_index < p_app_settings->num_attrs) {
+ attr_index = p_app_settings->attr_index;
+ p_app_settings->attrs[attr_index].num_val = p_rsp->num_val;
+ for (xx = 0; xx < p_rsp->num_val; xx++) {
+ p_app_settings->attrs[attr_index].attr_val[xx] = p_rsp->vals[xx];
+ }
+ attr_index++;
+ p_app_settings->attr_index++;
+ if (attr_index < p_app_settings->num_attrs) {
+ list_player_app_setting_value_cmd(
+ p_app_settings->attrs[p_app_settings->attr_index].attr_id, p_dev);
+ } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) {
+ attr_index = 0;
+ p_app_settings->ext_attr_index = 0;
+ list_player_app_setting_value_cmd(
+ p_app_settings->ext_attrs[attr_index].attr_id, p_dev);
+ } else {
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ get_player_app_setting_cmd(p_app_settings->num_attrs, attrs, p_dev);
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+ }
+ } else if (p_app_settings->ext_attr_index < p_app_settings->num_ext_attrs) {
+ attr_index = p_app_settings->ext_attr_index;
+ p_app_settings->ext_attrs[attr_index].num_val = p_rsp->num_val;
+ for (xx = 0; xx < p_rsp->num_val; xx++) {
+ p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val =
+ p_rsp->vals[xx];
+ }
+ attr_index++;
+ p_app_settings->ext_attr_index++;
+ if (attr_index < p_app_settings->num_ext_attrs) {
+ list_player_app_setting_value_cmd(
+ p_app_settings->ext_attrs[p_app_settings->ext_attr_index].attr_id,
+ p_dev);
+ } else {
+ uint8_t attr[AVRC_MAX_APP_ATTR_SIZE];
+
+ for (uint8_t xx = 0; xx < p_app_settings->num_ext_attrs; xx++) {
+ attr[xx] = p_app_settings->ext_attrs[xx].attr_id;
+ }
+ get_player_app_setting_attr_text_cmd(attr, p_app_settings->num_ext_attrs,
+ p_dev);
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_app_cur_val_response
+ *
+ * Description handles the the get attributes value response.
+ *
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_app_cur_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_CUR_APP_VALUE_RSP* p_rsp) {
+ btrc_player_settings_t app_settings;
+ bt_bdaddr_t rc_addr;
+ uint16_t xx;
+ btif_rc_device_cb_t* p_dev = NULL;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: Error fetching current settings: 0x%02X", __func__,
+ p_rsp->status);
+ return;
+ }
+ p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: Error in getting Device Address", __func__);
+ osi_free_and_reset((void**)&p_rsp->p_vals);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ app_settings.num_attr = p_rsp->num_val;
+ for (xx = 0; xx < app_settings.num_attr; xx++) {
+ app_settings.attr_ids[xx] = p_rsp->p_vals[xx].attr_id;
+ app_settings.attr_values[xx] = p_rsp->p_vals[xx].attr_val;
+ }
+
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_changed_cb, &rc_addr,
+ &app_settings);
+ /* Application settings are fetched only once for initial values
+ * initiate anything that follows after RC procedure.
+ * Defer it if browsing is supported till players query
+ */
+ rc_ctrl_procedure_complete(p_dev);
+ osi_free_and_reset((void**)&p_rsp->p_vals);
+}
+
+/***************************************************************************
+ *
+ * Function handle_app_attr_txt_response
+ *
+ * Description handles the the get attributes text response, if fails
+ * calls HAL callback with just normal settings and initiates
+ * query for current settings else initiates query for value
+ * text
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_app_attr_txt_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp) {
+ uint8_t xx;
+ uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t* p_app_settings;
+ bt_bdaddr_t rc_addr;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ p_app_settings = &p_dev->rc_app_settings;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR) {
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+ BTIF_TRACE_ERROR("%s: Error fetching attribute text: 0x%02X", __func__,
+ p_rsp->status);
+ /* Not able to fetch Text for extended Menu, skip the process
+ * and cleanup used memory. Proceed to get the current settings
+ * for standard attributes.
+ */
+ p_app_settings->num_ext_attrs = 0;
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+ osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->ext_attr_index = 0;
+
+ if (p_dev) {
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+ get_player_app_setting_cmd(xx, attrs, p_dev);
+ }
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++) {
+ uint8_t x;
+ for (x = 0; x < p_app_settings->num_ext_attrs; x++) {
+ if (p_app_settings->ext_attrs[x].attr_id == p_rsp->p_attrs[xx].attr_id) {
+ p_app_settings->ext_attrs[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+ p_app_settings->ext_attrs[x].str_len = p_rsp->p_attrs[xx].str_len;
+ p_app_settings->ext_attrs[x].p_str = p_rsp->p_attrs[xx].p_str;
+ break;
+ }
+ }
+ }
+
+ for (xx = 0; xx < p_app_settings->ext_attrs[0].num_val; xx++) {
+ vals[xx] = p_app_settings->ext_attrs[0].ext_attr_val[xx].val;
+ }
+ get_player_app_setting_value_text_cmd(vals, xx, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function handle_app_attr_val_txt_response
+ *
+ * Description handles the the get attributes value text response, if fails
+ * calls HAL callback with just normal settings and initiates
+ * query for current settings
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_app_attr_val_txt_response(
+ tBTA_AV_META_MSG* pmeta_msg, tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp) {
+ uint8_t xx, attr_index;
+ uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+ btif_rc_player_app_settings_t* p_app_settings;
+ bt_bdaddr_t rc_addr;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+ p_app_settings = &p_dev->rc_app_settings;
+
+ /* Todo: Do we need to retry on command timeout */
+ if (p_rsp->status != AVRC_STS_NO_ERROR) {
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+
+ BTIF_TRACE_ERROR("%s: Error fetching attribute value text: 0x%02X",
+ __func__, p_rsp->status);
+
+ /* Not able to fetch Text for extended Menu, skip the process
+ * and cleanup used memory. Proceed to get the current settings
+ * for standard attributes.
+ */
+ p_app_settings->num_ext_attrs = 0;
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+ int x;
+ btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+ for (x = 0; x < p_ext_attr->num_val; x++)
+ osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
+ p_ext_attr->num_val = 0;
+ osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->ext_attr_index = 0;
+
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, p_app_settings->attrs, 0, NULL);
+
+ get_player_app_setting_cmd(xx, attrs, p_dev);
+ return;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++) {
+ uint8_t x;
+ btrc_player_app_ext_attr_t* p_ext_attr;
+ p_ext_attr = &p_app_settings->ext_attrs[p_app_settings->ext_val_index];
+ for (x = 0; x < p_rsp->num_attr; x++) {
+ if (p_ext_attr->ext_attr_val[x].val == p_rsp->p_attrs[xx].attr_id) {
+ p_ext_attr->ext_attr_val[x].charset_id = p_rsp->p_attrs[xx].charset_id;
+ p_ext_attr->ext_attr_val[x].str_len = p_rsp->p_attrs[xx].str_len;
+ p_ext_attr->ext_attr_val[x].p_str = p_rsp->p_attrs[xx].p_str;
+ break;
+ }
+ }
+ }
+ p_app_settings->ext_val_index++;
+
+ if (p_app_settings->ext_val_index < p_app_settings->num_ext_attrs) {
+ attr_index = p_app_settings->ext_val_index;
+ for (xx = 0; xx < p_app_settings->ext_attrs[attr_index].num_val; xx++) {
+ vals[xx] = p_app_settings->ext_attrs[attr_index].ext_attr_val[xx].val;
+ }
+ get_player_app_setting_value_text_cmd(vals, xx, p_dev);
+ } else {
+ uint8_t x;
+
+ for (xx = 0; xx < p_app_settings->num_attrs; xx++) {
+ attrs[xx] = p_app_settings->attrs[xx].attr_id;
+ }
+ for (x = 0; x < p_app_settings->num_ext_attrs; x++) {
+ attrs[xx + x] = p_app_settings->ext_attrs[x].attr_id;
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, playerapplicationsetting_cb, &rc_addr,
+ p_app_settings->num_attrs, p_app_settings->attrs,
+ p_app_settings->num_ext_attrs, p_app_settings->ext_attrs);
+ get_player_app_setting_cmd(xx + x, attrs, p_dev);
+
+ /* Free the application settings information after sending to
+ * application.
+ */
+ for (xx = 0; xx < p_app_settings->ext_attr_index; xx++) {
+ int x;
+ btrc_player_app_ext_attr_t* p_ext_attr = &p_app_settings->ext_attrs[xx];
+
+ for (x = 0; x < p_ext_attr->num_val; x++)
+ osi_free_and_reset((void**)&p_ext_attr->ext_attr_val[x].p_str);
+ p_ext_attr->num_val = 0;
+ osi_free_and_reset((void**)&p_app_settings->ext_attrs[xx].p_str);
+ }
+ p_app_settings->num_attrs = 0;
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_set_app_attr_val_response
+ *
+ * Description handles the the set attributes value response, if fails
+ * calls HAL callback to indicate the failure
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_set_app_attr_val_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_RSP* p_rsp) {
+ uint8_t accepted = 0;
+ bt_bdaddr_t rc_addr;
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ /* For timeout pmeta_msg will be NULL, else we need to
+ * check if this is accepted by TG
+ */
+ if (pmeta_msg && (pmeta_msg->code == AVRC_RSP_ACCEPT)) {
+ accepted = 1;
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, setplayerappsetting_rsp_cb, &rc_addr,
+ accepted);
+}
+
+/***************************************************************************
+ *
+ * Function handle_get_elem_attr_response
+ *
+ * Description handles the the element attributes response, calls
+ * HAL callback to update track change information.
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_get_elem_attr_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_ATTRS_RSP* p_rsp) {
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ bt_bdaddr_t rc_addr;
+ size_t buf_size = p_rsp->num_attrs * sizeof(btrc_element_attr_val_t);
+ btrc_element_attr_val_t* p_attr =
+ (btrc_element_attr_val_t*)osi_calloc(buf_size);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ for (int i = 0; i < p_rsp->num_attrs; i++) {
+ p_attr[i].attr_id = p_rsp->p_attrs[i].attr_id;
+ /* Todo. Legth limit check to include null */
+ if (p_rsp->p_attrs[i].name.str_len && p_rsp->p_attrs[i].name.p_str) {
+ memcpy(p_attr[i].text, p_rsp->p_attrs[i].name.p_str,
+ p_rsp->p_attrs[i].name.str_len);
+ osi_free_and_reset((void**)&p_rsp->p_attrs[i].name.p_str);
+ }
+ }
+ HAL_CBACK(bt_rc_ctrl_callbacks, track_changed_cb, &rc_addr,
+ p_rsp->num_attrs, p_attr);
+ osi_free(p_attr);
+ } else if (p_rsp->status == BTIF_RC_STS_TIMEOUT) {
+ /* Retry for timeout case, this covers error handling
+ * for continuation failure also.
+ */
+ uint32_t attr_list[] = {
+ AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM, AVRC_MEDIA_ATTR_ID_TRACK_NUM,
+ AVRC_MEDIA_ATTR_ID_NUM_TRACKS, AVRC_MEDIA_ATTR_ID_GENRE,
+ AVRC_MEDIA_ATTR_ID_PLAYING_TIME};
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list, p_dev);
+ } else {
+ BTIF_TRACE_ERROR("%s: Error in get element attr procedure: %d", __func__,
+ p_rsp->status);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_get_playstatus_response
+ *
+ * Description handles the the play status response, calls
+ * HAL callback to update play position.
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_PLAY_STATUS_RSP* p_rsp) {
+ bt_bdaddr_t rc_addr;
+
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, play_position_changed_cb, &rc_addr,
+ p_rsp->song_len, p_rsp->song_pos);
+ } else {
+ BTIF_TRACE_ERROR("%s: Error in get play status procedure: %d", __func__,
+ p_rsp->status);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_set_addressed_player_response
+ *
+ * Description handles the the set addressed player response, calls
+ * HAL callback
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_set_addressed_player_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_RSP* p_rsp) {
+ bt_bdaddr_t rc_addr;
+
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: p_dev NULL", __func__);
+ return;
+ }
+
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, set_addressed_player_cb, &rc_addr,
+ p_rsp->status);
+ } else {
+ BTIF_TRACE_ERROR("%s: Error in get play status procedure %d", __func__,
+ p_rsp->status);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_get_folder_items_response
+ *
+ * Description handles the the get folder items response, calls
+ * HAL callback to send the folder items.
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_GET_ITEMS_RSP* p_rsp) {
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ /* Convert the internal folder listing into a response that can
+ * be passed onto JNI via HAL_CBACK
+ */
+ uint8_t item_count = p_rsp->item_count;
+ btrc_folder_items_t* btrc_items = (btrc_folder_items_t*)osi_malloc(
+ sizeof(btrc_folder_items_t) * item_count);
+ for (uint8_t i = 0; i < item_count; i++) {
+ const tAVRC_ITEM* avrc_item = &(p_rsp->p_item_list[i]);
+ btrc_folder_items_t* btrc_item = &(btrc_items[i]);
+ BTIF_TRACE_DEBUG("%s folder item type %d", __func__,
+ avrc_item->item_type);
+ switch (avrc_item->item_type) {
+ case AVRC_ITEM_MEDIA:
+ BTIF_TRACE_DEBUG("%s setting type to %d", __func__, BTRC_ITEM_MEDIA);
+ get_folder_item_type_media(avrc_item, btrc_item);
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_FOLDER", __func__);
+ get_folder_item_type_folder(avrc_item, btrc_item);
+ break;
+
+ case AVRC_ITEM_PLAYER:
+ BTIF_TRACE_DEBUG("%s setting type to BTRC_ITEM_PLAYER", __func__);
+ get_folder_item_type_player(avrc_item, btrc_item);
+ break;
+
+ default:
+ BTIF_TRACE_ERROR("%s cannot understand folder item type %d", __func__,
+ avrc_item->item_type);
+ }
+ }
+
+ HAL_CBACK(bt_rc_ctrl_callbacks, get_folder_items_cb, &rc_addr,
+ BTRC_STS_NO_ERROR,
+ /* We want to make the ownership explicit in native */
+ (const btrc_folder_items_t*)btrc_items, item_count);
+ BTIF_TRACE_DEBUG("%s HAL CBACK get_folder_items_cb finished", __func__);
+
+ /* Release the memory block for items since we OWN the object */
+ osi_free(btrc_items);
+ } else {
+ BTIF_TRACE_ERROR("%s: Error %d", __func__, p_rsp->status);
+ HAL_CBACK(bt_rc_ctrl_callbacks, get_folder_items_cb, &rc_addr,
+ (btrc_status_t)p_rsp->status, NULL, 0);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_item_type_media
+ *
+ * Description Converts the AVRC representation of a folder item with
+ * TYPE media to BTIF representation.
+ * Returns None
+ *
+ **************************************************************************/
+void get_folder_item_type_media(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item) {
+ btrc_item->item_type = BTRC_ITEM_MEDIA;
+ const tAVRC_ITEM_MEDIA* avrc_item_media = &(avrc_item->u.media);
+ btrc_item_media_t* btrc_item_media = &(btrc_item->media);
+ /* UID */
+ memset(btrc_item_media->uid, 0, BTRC_UID_SIZE * sizeof(uint8_t));
+ memcpy(btrc_item_media->uid, avrc_item_media->uid,
+ sizeof(uint8_t) * BTRC_UID_SIZE);
+
+ /* Audio/Video type */
+ switch (avrc_item_media->type) {
+ case AVRC_MEDIA_TYPE_AUDIO:
+ btrc_item_media->type = BTRC_MEDIA_TYPE_AUDIO;
+ break;
+ case AVRC_MEDIA_TYPE_VIDEO:
+ btrc_item_media->type = BTRC_MEDIA_TYPE_VIDEO;
+ break;
+ }
+
+ /* Charset ID */
+ btrc_item_media->charset_id = avrc_item_media->name.charset_id;
+
+ /* Copy the name */
+ BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+ avrc_item_media->name.str_len);
+ memset(btrc_item_media->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+ memcpy(btrc_item_media->name, avrc_item_media->name.p_str,
+ sizeof(uint8_t) * (avrc_item_media->name.str_len));
+
+ /* Copy the parameters */
+ btrc_item_media->num_attrs = avrc_item_media->attr_count;
+ btrc_item_media->p_attrs = (btrc_element_attr_val_t*)osi_malloc(
+ btrc_item_media->num_attrs * sizeof(btrc_element_attr_val_t));
+
+ /* Extract each attribute */
+ for (int i = 0; i < avrc_item_media->attr_count; i++) {
+ btrc_element_attr_val_t* btrc_attr_pair = &(btrc_item_media->p_attrs[i]);
+ tAVRC_ATTR_ENTRY* avrc_attr_pair = &(avrc_item_media->p_attr_list[i]);
+
+ BTIF_TRACE_DEBUG("%s media attr id 0x%x", __func__,
+ avrc_attr_pair->attr_id);
+
+ switch (avrc_attr_pair->attr_id) {
+ case AVRC_MEDIA_ATTR_ID_TITLE:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TITLE;
+ break;
+ case AVRC_MEDIA_ATTR_ID_ARTIST:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ARTIST;
+ break;
+ case AVRC_MEDIA_ATTR_ID_ALBUM:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_ALBUM;
+ break;
+ case AVRC_MEDIA_ATTR_ID_TRACK_NUM:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_TRACK_NUM;
+ break;
+ case AVRC_MEDIA_ATTR_ID_NUM_TRACKS:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_NUM_TRACKS;
+ break;
+ case AVRC_MEDIA_ATTR_ID_GENRE:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_GENRE;
+ break;
+ case AVRC_MEDIA_ATTR_ID_PLAYING_TIME:
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_PLAYING_TIME;
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s invalid media attr id: 0x%x", __func__,
+ avrc_attr_pair->attr_id);
+ btrc_attr_pair->attr_id = BTRC_MEDIA_ATTR_ID_INVALID;
+ }
+
+ memset(btrc_attr_pair->text, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+ memcpy(btrc_attr_pair->text, avrc_attr_pair->name.p_str,
+ avrc_attr_pair->name.str_len);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_item_type_folder
+ *
+ * Description Converts the AVRC representation of a folder item with
+ * TYPE folder to BTIF representation.
+ * Returns None
+ *
+ **************************************************************************/
+void get_folder_item_type_folder(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item) {
+ btrc_item->item_type = BTRC_ITEM_FOLDER;
+ const tAVRC_ITEM_FOLDER* avrc_item_folder = &(avrc_item->u.folder);
+ btrc_item_folder_t* btrc_item_folder = &(btrc_item->folder);
+ /* Copy the UID */
+ memset(btrc_item_folder->uid, 0, BTRC_UID_SIZE * sizeof(uint8_t));
+ memcpy(btrc_item_folder->uid, avrc_item_folder->uid,
+ sizeof(uint8_t) * BTRC_UID_SIZE);
+
+ /* Copy the type */
+ switch (avrc_item_folder->type) {
+ case AVRC_FOLDER_TYPE_MIXED:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_MIXED;
+ break;
+ case AVRC_FOLDER_TYPE_TITLES:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_TITLES;
+ break;
+ case AVRC_FOLDER_TYPE_ALNUMS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_ALBUMS;
+ break;
+ case AVRC_FOLDER_TYPE_ARTISTS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_ARTISTS;
+ break;
+ case AVRC_FOLDER_TYPE_GENRES:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_GENRES;
+ break;
+ case AVRC_FOLDER_TYPE_PLAYLISTS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_PLAYLISTS;
+ break;
+ case AVRC_FOLDER_TYPE_YEARS:
+ btrc_item_folder->type = BTRC_FOLDER_TYPE_YEARS;
+ break;
+ }
+
+ /* Copy if playable */
+ btrc_item_folder->playable = avrc_item_folder->playable;
+
+ /* Copy name */
+ BTIF_TRACE_DEBUG("%s max len %d str len %d", __func__, BTRC_MAX_ATTR_STR_LEN,
+ avrc_item_folder->name.str_len);
+ memset(btrc_item_folder->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+ memcpy(btrc_item_folder->name, avrc_item_folder->name.p_str,
+ avrc_item_folder->name.str_len * sizeof(uint8_t));
+
+ /* Copy charset */
+ btrc_item_folder->charset_id = avrc_item_folder->name.charset_id;
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_item_type_player
+ *
+ * Description Converts the AVRC representation of a folder item with
+ * TYPE player to BTIF representation.
+ * Returns None
+ *
+ **************************************************************************/
+void get_folder_item_type_player(const tAVRC_ITEM* avrc_item,
+ btrc_folder_items_t* btrc_item) {
+ btrc_item->item_type = BTRC_ITEM_PLAYER;
+ const tAVRC_ITEM_PLAYER* avrc_item_player = &(avrc_item->u.player);
+ btrc_item_player_t* btrc_item_player = &(btrc_item->player);
+ /* Player ID */
+ btrc_item_player->player_id = avrc_item_player->player_id;
+ /* Major type */
+ btrc_item_player->major_type = avrc_item_player->major_type;
+ /* Sub type */
+ btrc_item_player->sub_type = avrc_item_player->sub_type;
+ /* Features */
+ memcpy(btrc_item_player->features, avrc_item_player->features,
+ BTRC_FEATURE_BIT_MASK_SIZE);
+
+ memset(btrc_item_player->name, 0, BTRC_MAX_ATTR_STR_LEN * sizeof(uint8_t));
+ memcpy(btrc_item_player->name, avrc_item_player->name.p_str,
+ avrc_item_player->name.str_len);
+}
+
+/***************************************************************************
+ *
+ * Function handle_change_path_response
+ *
+ * Description handles the the change path response, calls
+ * HAL callback to send the updated folder
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_change_path_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_CHG_PATH_RSP* p_rsp) {
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, change_folder_path_cb, &rc_addr,
+ p_rsp->num_items);
+ } else {
+ BTIF_TRACE_ERROR("%s error in handle_change_path_response %d", __func__,
+ p_rsp->status);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function handle_set_browsed_player_response
+ *
+ * Description handles the the change path response, calls
+ * HAL callback to send the updated folder
+ * Returns None
+ *
+ **************************************************************************/
+static void handle_set_browsed_player_response(tBTA_AV_META_MSG* pmeta_msg,
+ tAVRC_SET_BR_PLAYER_RSP* p_rsp) {
+ btif_rc_device_cb_t* p_dev =
+ btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ bt_bdaddr_t rc_addr;
+ bdcpy(rc_addr.address, p_dev->rc_addr);
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ HAL_CBACK(bt_rc_ctrl_callbacks, set_browsed_player_cb, &rc_addr,
+ p_rsp->num_items, p_rsp->folder_depth);
+ } else {
+ BTIF_TRACE_ERROR("%s error %d", __func__, p_rsp->status);
+ }
+}
+
+/***************************************************************************
+ *
+ * Function clear_cmd_timeout
+ *
+ * Description helper function to stop the command timeout timer
+ * Returns None
+ *
+ **************************************************************************/
+static void clear_cmd_timeout(uint8_t label) {
+ rc_transaction_t* p_txn;
+
+ p_txn = get_transaction_by_lbl(label);
+ if (p_txn == NULL) {
+ BTIF_TRACE_ERROR("%s: Error in transaction label lookup", __func__);
+ return;
+ }
+
+ if (p_txn->txn_timer != NULL) alarm_cancel(p_txn->txn_timer);
+}
+
+/***************************************************************************
+ *
+ * Function handle_avk_rc_metamsg_rsp
+ *
+ * Description Handle RC metamessage response
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void handle_avk_rc_metamsg_rsp(tBTA_AV_META_MSG* pmeta_msg) {
+ tAVRC_RESPONSE avrc_response = {0};
+ uint8_t scratch_buf[512] = {0}; // this variable is unused
+ uint16_t buf_len;
+ tAVRC_STS status;
+
+ BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d ", __func__,
+ pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+
+ status = AVRC_Ctrl_ParsResponse(pmeta_msg->p_msg, &avrc_response, scratch_buf,
+ &buf_len);
+ if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&
+ (pmeta_msg->code >= AVRC_RSP_NOT_IMPL) &&
+ (pmeta_msg->code <= AVRC_RSP_INTERIM)) {
+ BTIF_TRACE_DEBUG("%s parse status %d pdu = %d rsp_status = %d", __func__,
+ status, avrc_response.pdu,
+ pmeta_msg->p_msg->vendor.hdr.ctype);
+
+ switch (avrc_response.pdu) {
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ handle_notification_response(pmeta_msg, &avrc_response.reg_notif);
+ if (pmeta_msg->code == AVRC_RSP_INTERIM) {
+ /* Don't free the transaction Id */
+ clear_cmd_timeout(pmeta_msg->label);
+ return;
+ }
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ handle_get_capability_response(pmeta_msg, &avrc_response.get_caps);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ handle_app_attr_response(pmeta_msg, &avrc_response.list_app_attr);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ handle_app_val_response(pmeta_msg, &avrc_response.list_app_values);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ handle_app_cur_val_response(pmeta_msg, &avrc_response.get_cur_app_val);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ handle_app_attr_txt_response(pmeta_msg,
+ &avrc_response.get_app_attr_txt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ handle_app_attr_val_txt_response(pmeta_msg,
+ &avrc_response.get_app_val_txt);
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ handle_set_app_attr_val_response(pmeta_msg, &avrc_response.set_app_val);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ handle_get_elem_attr_response(pmeta_msg, &avrc_response.get_attrs);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ handle_get_playstatus_response(pmeta_msg,
+ &avrc_response.get_play_status);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ handle_set_addressed_player_response(pmeta_msg, &avrc_response.rsp);
+ break;
+ }
+ } else if (AVRC_OP_BROWSE == pmeta_msg->p_msg->hdr.opcode) {
+ BTIF_TRACE_DEBUG("%s AVRC_OP_BROWSE pdu %d", __func__, avrc_response.pdu);
+ /* check what kind of command it is for browsing */
+ switch (avrc_response.pdu) {
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ handle_get_folder_items_response(pmeta_msg, &avrc_response.get_items);
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ handle_change_path_response(pmeta_msg, &avrc_response.chg_path);
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ handle_set_browsed_player_response(pmeta_msg, &avrc_response.br_player);
+ break;
+ default:
+ BTIF_TRACE_ERROR("%s cannot handle browse pdu %d", __func__,
+ pmeta_msg->p_msg->hdr.opcode);
+ }
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: Invalid Vendor Command code: %d len: %d. Not processing it.",
+ __func__, pmeta_msg->code, pmeta_msg->len);
+ return;
+ }
+ BTIF_TRACE_DEBUG("XX __func__ release transaction %d", pmeta_msg->label);
+ release_transaction(pmeta_msg->label);
+}
+
+/***************************************************************************
+ *
+ * Function handle_avk_rc_metamsg_cmd
+ *
+ * Description Handle RC metamessage response
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void handle_avk_rc_metamsg_cmd(tBTA_AV_META_MSG* pmeta_msg) {
+ tAVRC_COMMAND avrc_cmd = {0};
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ btif_rc_device_cb_t* p_dev = NULL;
+
+ BTIF_TRACE_DEBUG("%s: opcode: %d rsp_code: %d", __func__,
+ pmeta_msg->p_msg->hdr.opcode, pmeta_msg->code);
+ status = AVRC_Ctrl_ParsCommand(pmeta_msg->p_msg, &avrc_cmd);
+ if ((AVRC_OP_VENDOR == pmeta_msg->p_msg->hdr.opcode) &&
+ (pmeta_msg->code <= AVRC_CMD_GEN_INQ)) {
+ BTIF_TRACE_DEBUG("%s Received vendor command.code %d, PDU %d label %d",
+ __func__, pmeta_msg->code, avrc_cmd.pdu, pmeta_msg->label);
+
+ if (status != AVRC_STS_NO_ERROR) {
+ /* return error */
+ BTIF_TRACE_WARNING(
+ "%s: Error in parsing received metamsg command. status: 0x%02x",
+ __func__, status);
+ send_reject_response(pmeta_msg->rc_handle, pmeta_msg->label, avrc_cmd.pdu,
+ status, pmeta_msg->p_msg->hdr.opcode);
+ } else {
+ p_dev = btif_rc_get_device_by_handle(pmeta_msg->rc_handle);
+ if (p_dev == NULL) {
+ BTIF_TRACE_ERROR("%s: avk rc meta msg cmd for Invalid rc handle",
+ __func__);
+ return;
+ }
+
+ if (avrc_cmd.pdu == AVRC_PDU_REGISTER_NOTIFICATION) {
+ uint8_t event_id = avrc_cmd.reg_notif.event_id;
+ BTIF_TRACE_EVENT("%s: Register notification event_id: %s", __func__,
+ dump_rc_notification_event_id(event_id));
+ } else if (avrc_cmd.pdu == AVRC_PDU_SET_ABSOLUTE_VOLUME) {
+ BTIF_TRACE_EVENT("%s: Abs Volume Cmd Recvd", __func__);
+ }
+
+ btif_rc_ctrl_upstreams_rsp_cmd(avrc_cmd.pdu, &avrc_cmd, pmeta_msg->label,
+ p_dev);
+ }
+ } else {
+ BTIF_TRACE_DEBUG(
+ "%s: Invalid Vendor Command code: %d len: %d. Not processing it.",
+ __func__, pmeta_msg->code, pmeta_msg->len);
+ return;
+ }
+}
+
+/***************************************************************************
+ *
+ * Function cleanup
+ *
+ * Description Closes the AVRC interface
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void cleanup() {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+ if (bt_rc_callbacks) {
+ bt_rc_callbacks = NULL;
+ }
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+ memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+ sizeof(btif_rc_cb.rc_multi_cb[idx]));
+ }
+
+ BTIF_TRACE_EVENT("%s: completed", __func__);
+}
+
+/***************************************************************************
+ *
+ * Function cleanup_ctrl
+ *
+ * Description Closes the AVRC Controller interface
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static void cleanup_ctrl() {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+
+ if (bt_rc_ctrl_callbacks) {
+ bt_rc_ctrl_callbacks = NULL;
+ }
+
+ for (int idx = 0; idx < BTIF_RC_NUM_CONN; idx++) {
+ alarm_free(btif_rc_cb.rc_multi_cb[idx].rc_play_status_timer);
+ memset(&btif_rc_cb.rc_multi_cb[idx], 0,
+ sizeof(btif_rc_cb.rc_multi_cb[idx]));
+ }
+
+ memset(&btif_rc_cb.rc_multi_cb, 0, sizeof(btif_rc_cb.rc_multi_cb));
+ BTIF_TRACE_EVENT("%s: completed", __func__);
+}
+
+/***************************************************************************
+ *
+ * Function getcapabilities_cmd
+ *
+ * Description GetCapabilties from Remote(Company_ID, Events_Supported)
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t getcapabilities_cmd(uint8_t cap_id,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: cap_id: %d", __func__, cap_id);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.get_caps.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_caps.capability_id = cap_id;
+ avrc_cmd.get_caps.pdu = AVRC_PDU_GET_CAPABILITIES;
+ avrc_cmd.get_caps.status = AVRC_STS_NO_ERROR;
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function list_player_app_setting_attrib_cmd
+ *
+ * Description Get supported List Player Attributes
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t list_player_app_setting_attrib_cmd(
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.list_app_attr.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.list_app_attr.pdu = AVRC_PDU_LIST_PLAYER_APP_ATTR;
+ avrc_cmd.list_app_attr.status = AVRC_STS_NO_ERROR;
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function list_player_app_setting_value_cmd
+ *
+ * Description Get values of supported Player Attributes
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t list_player_app_setting_value_cmd(
+ uint8_t attrib_id, btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: attrib_id: %d", __func__, attrib_id);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.list_app_values.attr_id = attrib_id;
+ avrc_cmd.list_app_values.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.list_app_values.pdu = AVRC_PDU_LIST_PLAYER_APP_VALUES;
+ avrc_cmd.list_app_values.status = AVRC_STS_NO_ERROR;
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_player_app_setting_cmd
+ *
+ * Description Get current values of Player Attributes
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_cmd(uint8_t num_attrib,
+ uint8_t* attrib_ids,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: num_attrib: %d", __func__, num_attrib);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.get_cur_app_val.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_cur_app_val.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_cur_app_val.num_attr = num_attrib;
+ avrc_cmd.get_cur_app_val.pdu = AVRC_PDU_GET_CUR_PLAYER_APP_VALUE;
+
+ for (int count = 0; count < num_attrib; count++) {
+ avrc_cmd.get_cur_app_val.attrs[count] = attrib_ids[count];
+ }
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_playback_state_cmd
+ *
+ * Description Fetch the current playback state for the device
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_playback_state_cmd(bt_bdaddr_t* bd_addr) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ return get_play_status_cmd(p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_now_playing_list_cmd
+ *
+ * Description Fetch the now playing list
+ *
+ * Paramters start_item: First item to fetch (0 to fetch from beganning)
+ * end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_now_playing_list_cmd(bt_bdaddr_t* bd_addr,
+ uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_NOW_PLAYING, start_item,
+ num_items);
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_list_cmd
+ *
+ * Description Fetch the currently selected folder list
+ *
+ * Paramters start_item: First item to fetch (0 to fetch from beganning)
+ * end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_folder_list_cmd(bt_bdaddr_t* bd_addr, uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_FILE_SYSTEM, start_item,
+ num_items);
+}
+
+/***************************************************************************
+ *
+ * Function get_player_list_cmd
+ *
+ * Description Fetch the player list
+ *
+ * Paramters start_item: First item to fetch (0 to fetch from beganning)
+ * end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_player_list_cmd(bt_bdaddr_t* bd_addr, uint8_t start_item,
+ uint8_t num_items) {
+ BTIF_TRACE_DEBUG("%s start, end: (%d, %d)", __func__, start_item, num_items);
+ return get_folder_items_cmd(bd_addr, AVRC_SCOPE_PLAYER_LIST, start_item,
+ num_items);
+}
+
+/***************************************************************************
+ *
+ * Function change_folder_path_cmd
+ *
+ * Description Change the folder.
+ *
+ * Paramters direction: Direction (Up/Down) to change folder
+ * uid: The UID of folder to move to
+ * start_item: First item to fetch (0 to fetch from beganning)
+ * end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t change_folder_path_cmd(bt_bdaddr_t* bd_addr,
+ uint8_t direction, uint8_t* uid) {
+ BTIF_TRACE_DEBUG("%s: direction %d", __func__, direction);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+
+ avrc_cmd.chg_path.pdu = AVRC_PDU_CHANGE_PATH;
+ avrc_cmd.chg_path.status = AVRC_STS_NO_ERROR;
+ // TODO(sanketa): Improve for database aware clients.
+ avrc_cmd.chg_path.uid_counter = 0;
+ avrc_cmd.chg_path.direction = direction;
+
+ memset(avrc_cmd.chg_path.folder_uid, 0, AVRC_UID_SIZE * sizeof(uint8_t));
+ memcpy(avrc_cmd.chg_path.folder_uid, uid, AVRC_UID_SIZE * sizeof(uint8_t));
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ return BT_STATUS_FAIL;
+ }
+
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+ p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function set_browsed_player_cmd
+ *
+ * Description Change the browsed player.
+ *
+ * Paramters id: The UID of player to move to
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t set_browsed_player_cmd(bt_bdaddr_t* bd_addr, uint16_t id) {
+ BTIF_TRACE_DEBUG("%s: id %d", __func__, id);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ rc_transaction_t* p_transaction = NULL;
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.br_player.pdu = AVRC_PDU_SET_BROWSED_PLAYER;
+ avrc_cmd.br_player.status = AVRC_STS_NO_ERROR;
+ // TODO(sanketa): Improve for database aware clients.
+ avrc_cmd.br_player.player_id = id;
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ return BT_STATUS_FAIL;
+ }
+
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+ p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ **
+ ** Function set_addressed_player_cmd
+ **
+ ** Description Change the addressed player.
+ **
+ ** Paramters id: The UID of player to move to
+ **
+ ** Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ ** BT_STATUS_FAIL.
+ **
+ ***************************************************************************/
+static bt_status_t set_addressed_player_cmd(bt_bdaddr_t* bd_addr, uint16_t id) {
+ BTIF_TRACE_DEBUG("%s: id %d", __func__, id);
+
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ BT_HDR* p_msg = NULL;
+
+ avrc_cmd.addr_player.pdu = AVRC_PDU_SET_ADDRESSED_PLAYER;
+ avrc_cmd.addr_player.status = AVRC_STS_NO_ERROR;
+ // TODO(sanketa): Improve for database aware clients.
+ avrc_cmd.addr_player.player_id = id;
+
+ tAVRC_STS status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s: failed to build command status %d", __func__, status);
+ return BT_STATUS_FAIL;
+ }
+
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t tran_status = get_transaction(&p_transaction);
+
+ if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain txn details. status: 0x%02x",
+ __func__, tran_status);
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+ p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function get_folder_items_cmd
+ *
+ * Description Helper function to browse the content hierarchy of the
+ * TG device.
+ *
+ * Paramters scope: AVRC_SCOPE_NOW_PLAYING (etc) for various browseable
+ * content
+ * start_item: First item to fetch (0 to fetch from beganning)
+ * end_item: Last item to fetch (0xff to fetch until end)
+ *
+ * Returns BT_STATUS_SUCCESS if command issued successfully otherwise
+ * BT_STATUS_FAIL.
+ *
+ **************************************************************************/
+static bt_status_t get_folder_items_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+ uint8_t start_item, uint8_t end_item) {
+ /* Check that both avrcp and browse channel are connected. */
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+
+ /* Set the layer specific to point to browse although this should really
+ * be done by lower layers and looking at the PDU
+ */
+ avrc_cmd.get_items.pdu = AVRC_PDU_GET_FOLDER_ITEMS;
+ avrc_cmd.get_items.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_items.scope = scope;
+ avrc_cmd.get_items.start_item = start_item;
+ avrc_cmd.get_items.end_item = end_item;
+ avrc_cmd.get_items.attr_count = 0; /* p_attr_list does not matter hence */
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status != AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_ERROR("%s failed to build command status %d", __func__, status);
+ return BT_STATUS_FAIL;
+ }
+
+ rc_transaction_t* p_transaction = NULL;
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (tran_status != BT_STATUS_SUCCESS || p_transaction == NULL) {
+ osi_free(p_msg);
+ BTIF_TRACE_ERROR("%s: failed to obtain transaction details. status: 0x%02x",
+ __func__, tran_status);
+ return BT_STATUS_FAIL;
+ }
+
+ BTIF_TRACE_DEBUG("%s msgreq being sent out with label %d", __func__,
+ p_transaction->lbl);
+ BTA_AvMetaCmd(p_dev->rc_handle, p_transaction->lbl, AVRC_CMD_CTRL, p_msg);
+ return BT_STATUS_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Function change_player_app_setting
+ *
+ * Description Set current values of Player Attributes
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t change_player_app_setting(bt_bdaddr_t* bd_addr,
+ uint8_t num_attrib,
+ uint8_t* attrib_ids,
+ uint8_t* attrib_vals) {
+ BTIF_TRACE_DEBUG("%s: num_attrib: %d", __func__, num_attrib);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.set_app_val.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.set_app_val.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.set_app_val.num_val = num_attrib;
+ avrc_cmd.set_app_val.pdu = AVRC_PDU_SET_PLAYER_APP_VALUE;
+ avrc_cmd.set_app_val.p_vals =
+ (tAVRC_APP_SETTING*)osi_malloc(sizeof(tAVRC_APP_SETTING) * num_attrib);
+ for (int count = 0; count < num_attrib; count++) {
+ avrc_cmd.set_app_val.p_vals[count].attr_id = attrib_ids[count];
+ avrc_cmd.set_app_val.p_vals[count].attr_val = attrib_vals[count];
+ }
+
+ bt_status_t st = build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_CTRL, p_dev);
+ osi_free_and_reset((void**)&avrc_cmd.set_app_val.p_vals);
+ return st;
+}
+
+/***************************************************************************
+ *
+ * Function play_item_cmd
+ *
+ * Description Play the item specified by UID & scope
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t play_item_cmd(bt_bdaddr_t* bd_addr, uint8_t scope,
+ uint8_t* uid, uint16_t uid_counter) {
+ BTIF_TRACE_DEBUG("%s: scope %d uid_counter %d", __func__, scope, uid_counter);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+ CHECK_RC_CONNECTED(p_dev);
+ CHECK_BR_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.pdu = AVRC_PDU_PLAY_ITEM;
+ avrc_cmd.play_item.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.play_item.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.play_item.scope = scope;
+ memcpy(avrc_cmd.play_item.uid, uid, AVRC_UID_SIZE);
+ avrc_cmd.play_item.uid_counter = uid_counter;
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_CTRL, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_player_app_setting_attr_text_cmd
+ *
+ * Description Get text description for app attribute
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_attr_text_cmd(
+ uint8_t* attrs, uint8_t num_attrs, btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: num attrs: %d", __func__, num_attrs);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT;
+ avrc_cmd.get_app_attr_txt.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_app_attr_txt.num_attr = num_attrs;
+
+ for (int count = 0; count < num_attrs; count++) {
+ avrc_cmd.get_app_attr_txt.attrs[count] = attrs[count];
+ }
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_player_app_setting_val_text_cmd
+ *
+ * Description Get text description for app attribute values
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t get_player_app_setting_value_text_cmd(
+ uint8_t* vals, uint8_t num_vals, btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: num_vals: %d", __func__, num_vals);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.pdu = AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT;
+ avrc_cmd.get_app_val_txt.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_app_val_txt.num_val = num_vals;
+
+ for (int count = 0; count < num_vals; count++) {
+ avrc_cmd.get_app_val_txt.vals[count] = vals[count];
+ }
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function register_notification_cmd
+ *
+ * Description Send Command to register for a Notification ID
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t register_notification_cmd(uint8_t label, uint8_t event_id,
+ uint32_t event_value,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: event_id: %d event_value %d", __func__, event_id,
+ event_value);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.reg_notif.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.reg_notif.event_id = event_id;
+ avrc_cmd.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_cmd.reg_notif.param = event_value;
+
+ BT_HDR* p_msg = NULL;
+ tAVRC_STS status = AVRC_BldCommand(&avrc_cmd, &p_msg);
+ if (status == AVRC_STS_NO_ERROR) {
+ uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+ label);
+ if (p_msg != NULL) {
+ BTA_AvVendorCmd(p_dev->rc_handle, label, AVRC_CMD_NOTIF, data_start,
+ p_msg->len);
+ status = BT_STATUS_SUCCESS;
+ }
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+ status);
+ }
+ osi_free(p_msg);
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function get_element_attribute_cmd
+ *
+ * Description Get Element Attribute for attributeIds
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t get_element_attribute_cmd(uint8_t num_attribute,
+ uint32_t* p_attr_ids,
+ btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s: num_attribute: %d attribute_id: %d", __func__,
+ num_attribute, p_attr_ids[0]);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.get_elem_attrs.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_elem_attrs.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.get_elem_attrs.num_attr = num_attribute;
+ avrc_cmd.get_elem_attrs.pdu = AVRC_PDU_GET_ELEMENT_ATTR;
+ for (int count = 0; count < num_attribute; count++) {
+ avrc_cmd.get_elem_attrs.attrs[count] = p_attr_ids[count];
+ }
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function get_play_status_cmd
+ *
+ * Description Get Playing Status of a Device
+ *
+ * Returns bt_status_t
+ *
+ **************************************************************************/
+static bt_status_t get_play_status_cmd(btif_rc_device_cb_t* p_dev) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ CHECK_RC_CONNECTED(p_dev);
+
+ tAVRC_COMMAND avrc_cmd = {0};
+ avrc_cmd.get_play_status.opcode = AVRC_OP_VENDOR;
+ avrc_cmd.get_play_status.pdu = AVRC_PDU_GET_PLAY_STATUS;
+ avrc_cmd.get_play_status.status = AVRC_STS_NO_ERROR;
+
+ return build_and_send_vendor_cmd(&avrc_cmd, AVRC_CMD_STATUS, p_dev);
+}
+
+/***************************************************************************
+ *
+ * Function set_volume_rsp
+ *
+ * Description Rsp for SetAbsoluteVolume Command
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t set_volume_rsp(bt_bdaddr_t* bd_addr, uint8_t abs_vol,
+ uint8_t label) {
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ tAVRC_RESPONSE avrc_rsp;
+ BT_HDR* p_msg = NULL;
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+
+ BTIF_TRACE_DEBUG("%s: abs_vol: %d", __func__, abs_vol);
+
+ avrc_rsp.volume.opcode = AVRC_OP_VENDOR;
+ avrc_rsp.volume.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME;
+ avrc_rsp.volume.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.volume.volume = abs_vol;
+ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR) {
+ uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+ p_dev->rc_vol_label);
+ if (p_msg != NULL) {
+ BTA_AvVendorRsp(p_dev->rc_handle, label, BTA_AV_RSP_ACCEPT, data_start,
+ p_msg->len, 0);
+ status = BT_STATUS_SUCCESS;
+ }
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+ status);
+ }
+ osi_free(p_msg);
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function send_register_abs_vol_rsp
+ *
+ * Description Rsp for Notification of Absolute Volume
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t volume_change_notification_rsp(
+ bt_bdaddr_t* bd_addr, btrc_notification_type_t rsp_type, uint8_t abs_vol,
+ uint8_t label) {
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ tAVRC_RESPONSE avrc_rsp;
+ BT_HDR* p_msg = NULL;
+ BTIF_TRACE_DEBUG("%s: rsp_type: %d abs_vol: %d", __func__, rsp_type, abs_vol);
+
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+
+ avrc_rsp.reg_notif.opcode = AVRC_OP_VENDOR;
+ avrc_rsp.reg_notif.pdu = AVRC_PDU_REGISTER_NOTIFICATION;
+ avrc_rsp.reg_notif.status = AVRC_STS_NO_ERROR;
+ avrc_rsp.reg_notif.param.volume = abs_vol;
+ avrc_rsp.reg_notif.event_id = AVRC_EVT_VOLUME_CHANGE;
+
+ status = AVRC_BldResponse(p_dev->rc_handle, &avrc_rsp, &p_msg);
+ if (status == AVRC_STS_NO_ERROR) {
+ BTIF_TRACE_DEBUG("%s: msgreq being sent out with label: %d", __func__,
+ label);
+ uint8_t* data_start = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ BTA_AvVendorRsp(p_dev->rc_handle, label,
+ (rsp_type == BTRC_NOTIFICATION_TYPE_INTERIM)
+ ? AVRC_RSP_INTERIM
+ : AVRC_RSP_CHANGED,
+ data_start, p_msg->len, 0);
+ status = BT_STATUS_SUCCESS;
+ } else {
+ BTIF_TRACE_ERROR("%s: failed to build command. status: 0x%02x", __func__,
+ status);
+ }
+ osi_free(p_msg);
+
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function send_groupnavigation_cmd
+ *
+ * Description Send Pass-Through command
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t send_groupnavigation_cmd(bt_bdaddr_t* bd_addr,
+ uint8_t key_code,
+ uint8_t key_state) {
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ rc_transaction_t* p_transaction = NULL;
+ BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code,
+ key_state);
+ btif_rc_device_cb_t* p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+
+ if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if ((BT_STATUS_SUCCESS == tran_status) && (NULL != p_transaction)) {
+ uint8_t buffer[AVRC_PASS_THRU_GROUP_LEN] = {0};
+ uint8_t* start = buffer;
+ UINT24_TO_BE_STREAM(start, AVRC_CO_METADATA);
+ *(start)++ = 0;
+ UINT8_TO_BE_STREAM(start, key_code);
+ BTA_AvRemoteVendorUniqueCmd(p_dev->rc_handle, p_transaction->lbl,
+ (tBTA_AV_STATE)key_state, buffer,
+ AVRC_PASS_THRU_GROUP_LEN);
+ status = BT_STATUS_SUCCESS;
+ BTIF_TRACE_DEBUG("%s: succesfully sent group_navigation command to BTA",
+ __func__);
+ } else {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: error in fetching transaction", __func__);
+ }
+ } else {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: feature not supported", __func__);
+ }
+ return (bt_status_t)status;
+}
+
+/***************************************************************************
+ *
+ * Function send_passthrough_cmd
+ *
+ * Description Send Pass-Through command
+ *
+ * Returns void
+ *
+ **************************************************************************/
+static bt_status_t send_passthrough_cmd(bt_bdaddr_t* bd_addr, uint8_t key_code,
+ uint8_t key_state) {
+ tAVRC_STS status = BT_STATUS_UNSUPPORTED;
+ btif_rc_device_cb_t* p_dev = NULL;
+ BTIF_TRACE_ERROR("%s: calling btif_rc_get_device_by_bda", __func__);
+ p_dev = btif_rc_get_device_by_bda(bd_addr);
+
+ CHECK_RC_CONNECTED(p_dev);
+
+ rc_transaction_t* p_transaction = NULL;
+ BTIF_TRACE_DEBUG("%s: key-code: %d, key-state: %d", __func__, key_code,
+ key_state);
+ if (p_dev->rc_features & BTA_AV_FEAT_RCTG) {
+ bt_status_t tran_status = get_transaction(&p_transaction);
+ if (BT_STATUS_SUCCESS == tran_status && NULL != p_transaction) {
+ BTA_AvRemoteCmd(p_dev->rc_handle, p_transaction->lbl,
+ (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state);
+ status = BT_STATUS_SUCCESS;
+ BTIF_TRACE_DEBUG("%s: succesfully sent passthrough command to BTA",
+ __func__);
+ } else {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: error in fetching transaction", __func__);
+ }
+ } else {
+ status = BT_STATUS_FAIL;
+ BTIF_TRACE_DEBUG("%s: feature not supported", __func__);
+ }
+ return (bt_status_t)status;
+}
+
+static const btrc_interface_t bt_rc_interface = {
+ sizeof(bt_rc_interface),
+ init,
+ get_play_status_rsp,
+ NULL, /* list_player_app_attr_rsp */
+ NULL, /* list_player_app_value_rsp */
+ NULL, /* get_player_app_value_rsp */
+ NULL, /* get_player_app_attr_text_rsp */
+ NULL, /* get_player_app_value_text_rsp */
+ get_element_attr_rsp,
+ NULL, /* set_player_app_value_rsp */
+ register_notification_rsp,
+ set_volume,
+ set_addressed_player_rsp,
+ set_browsed_player_rsp,
+ get_folder_items_list_rsp,
+ change_path_rsp,
+ get_item_attr_rsp,
+ play_item_rsp,
+ get_total_num_of_items_rsp,
+ search_rsp,
+ add_to_now_playing_rsp,
+ cleanup,
+};
+
+static const btrc_ctrl_interface_t bt_rc_ctrl_interface = {
+ sizeof(bt_rc_ctrl_interface),
+ init_ctrl,
+ send_passthrough_cmd,
+ send_groupnavigation_cmd,
+ change_player_app_setting,
+ play_item_cmd,
+ get_playback_state_cmd,
+ get_now_playing_list_cmd,
+ get_folder_list_cmd,
+ get_player_list_cmd,
+ change_folder_path_cmd,
+ set_browsed_player_cmd,
+ set_addressed_player_cmd,
+ set_volume_rsp,
+ volume_change_notification_rsp,
+ cleanup_ctrl,
+};
+
+/*******************************************************************************
+ *
+ * Function btif_rc_get_interface
+ *
+ * Description Get the AVRCP Target callback interface
+ *
+ * Returns btrc_interface_t
+ *
+ ******************************************************************************/
+const btrc_interface_t* btif_rc_get_interface(void) {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+ return &bt_rc_interface;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_rc_ctrl_get_interface
+ *
+ * Description Get the AVRCP Controller callback interface
+ *
+ * Returns btrc_ctrl_interface_t
+ *
+ ******************************************************************************/
+const btrc_ctrl_interface_t* btif_rc_ctrl_get_interface(void) {
+ BTIF_TRACE_EVENT("%s: ", __func__);
+ return &bt_rc_ctrl_interface;
+}
+
+/*******************************************************************************
+ * Function initialize_transaction
+ *
+ * Description Initializes fields of the transaction structure
+ *
+ * Returns void
+ ******************************************************************************/
+static void initialize_transaction(int lbl) {
+ std::unique_lock<std::recursive_mutex>(device.lbllock);
+ if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
+ if (alarm_is_scheduled(device.transaction[lbl].txn_timer)) {
+ clear_cmd_timeout(lbl);
+ }
+ device.transaction[lbl].lbl = lbl;
+ device.transaction[lbl].in_use = false;
+ device.transaction[lbl].handle = 0;
+ }
+}
+
+/*******************************************************************************
+ * Function lbl_init
+ *
+ * Description Initializes label structures and mutexes.
+ *
+ * Returns void
+ ******************************************************************************/
+void lbl_init() {
+ memset(&device.transaction, 0, sizeof(device.transaction));
+ init_all_transactions();
+}
+
+/*******************************************************************************
+ *
+ * Function init_all_transactions
+ *
+ * Description Initializes all transactions
+ *
+ * Returns void
+ ******************************************************************************/
+void init_all_transactions() {
+ uint8_t txn_indx = 0;
+ for (txn_indx = 0; txn_indx < MAX_TRANSACTIONS_PER_SESSION; txn_indx++) {
+ initialize_transaction(txn_indx);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function get_transaction_by_lbl
+ *
+ * Description Will return a transaction based on the label. If not inuse
+ * will return an error.
+ *
+ * Returns bt_status_t
+ ******************************************************************************/
+rc_transaction_t* get_transaction_by_lbl(uint8_t lbl) {
+ rc_transaction_t* transaction = NULL;
+ std::unique_lock<std::recursive_mutex> lock(device.lbllock);
+
+ /* Determine if this is a valid label */
+ if (lbl < MAX_TRANSACTIONS_PER_SESSION) {
+ if (false == device.transaction[lbl].in_use) {
+ transaction = NULL;
+ } else {
+ transaction = &(device.transaction[lbl]);
+ BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__, lbl);
+ }
+ }
+
+ return transaction;
+}
+
+/*******************************************************************************
+ *
+ * Function get_transaction
+ *
+ * Description Obtains the transaction details.
+ *
+ * Returns bt_status_t
+ ******************************************************************************/
+
+static bt_status_t get_transaction(rc_transaction_t** ptransaction) {
+ std::unique_lock<std::recursive_mutex> lock(device.lbllock);
+
+ // Check for unused transactions
+ for (uint8_t i = 0; i < MAX_TRANSACTIONS_PER_SESSION; i++) {
+ if (false == device.transaction[i].in_use) {
+ BTIF_TRACE_DEBUG("%s: Got transaction.label: %d", __func__,
+ device.transaction[i].lbl);
+ device.transaction[i].in_use = true;
+ *ptransaction = &(device.transaction[i]);
+ return BT_STATUS_SUCCESS;
+ }
+ }
+ return BT_STATUS_NOMEM;
+}
+
+/*******************************************************************************
+ *
+ * Function release_transaction
+ *
+ * Description Will release a transaction for reuse
+ *
+ * Returns bt_status_t
+ ******************************************************************************/
+void release_transaction(uint8_t lbl) {
+ BTIF_TRACE_DEBUG("%s %d", __func__, lbl);
+ rc_transaction_t* transaction = get_transaction_by_lbl(lbl);
+
+ /* If the transaction is in use... */
+ if (transaction != NULL) {
+ BTIF_TRACE_DEBUG("%s: lbl: %d", __func__, lbl);
+ initialize_transaction(lbl);
+ }
+}
+
+/*******************************************************************************
+ * Function sleep_ms
+ *
+ * Description Sleep the calling thread unconditionally for
+ * |timeout_ms| milliseconds.
+ *
+ * Returns void
+ ******************************************************************************/
+static void sleep_ms(period_ms_t timeout_ms) {
+ struct timespec delay;
+ delay.tv_sec = timeout_ms / 1000;
+ delay.tv_nsec = 1000 * 1000 * (timeout_ms % 1000);
+
+ OSI_NO_INTR(nanosleep(&delay, &delay));
+}
+
+static bool absolute_volume_disabled() {
+ char volume_disabled[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get("persist.bluetooth.disableabsvol", volume_disabled, "false");
+ if (strncmp(volume_disabled, "true", 4) == 0) {
+ BTIF_TRACE_WARNING("%s: Absolute volume disabled by property", __func__);
+ return true;
+ }
+ return false;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sdp.cc b/mtkbt/code/bt/btif/src/btif_sdp.cc
new file mode 100755
index 0000000..81b9a85
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sdp.cc
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sdp.c
+ * Description: SDP Bluetooth Interface.
+ * Implements the generic message handling and search
+ * functionality.
+ * References btif_sdp_server.c for SDP record creation.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sdp"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
+#include "bta_api.h"
+#include "bta_sdp_api.h"
+#include "btif_common.h"
+#include "btif_profile_queue.h"
+#include "btif_util.h"
+
+/*****************************************************************************
+ * Functions implemented in sdp_server.c
+ *****************************************************************************/
+bt_status_t sdp_server_init();
+void sdp_server_cleanup();
+bt_status_t create_sdp_record(bluetooth_sdp_record* records,
+ int* record_handles);
+bt_status_t remove_sdp_record(int record_handle);
+void on_create_record_event(int handle);
+void on_remove_record_event(int handle);
+
+// Utility functions:
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count);
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+ bluetooth_sdp_record* out_records, int count);
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+
+static btsdp_callbacks_t* bt_sdp_callbacks = NULL;
+
+static void btif_sdp_search_comp_evt(uint16_t event, char* p_param) {
+ tBTA_SDP_SEARCH_COMP* evt_data = (tBTA_SDP_SEARCH_COMP*)p_param;
+ bt_bdaddr_t addr;
+ BTIF_TRACE_DEBUG("%s: event = %d", __func__, event);
+
+ if (event != BTA_SDP_SEARCH_COMP_EVT) return;
+
+ bdcpy(addr.address, evt_data->remote_addr);
+
+ HAL_CBACK(bt_sdp_callbacks, sdp_search_cb, (bt_status_t)evt_data->status,
+ &addr, (uint8_t*)(evt_data->uuid.uu.uuid128),
+ evt_data->record_count, evt_data->records);
+}
+
+static void sdp_search_comp_copy_cb(uint16_t event, char* p_dest, char* p_src) {
+ tBTA_SDP_SEARCH_COMP* p_dest_data = (tBTA_SDP_SEARCH_COMP*)p_dest;
+ tBTA_SDP_SEARCH_COMP* p_src_data = (tBTA_SDP_SEARCH_COMP*)p_src;
+
+ if (!p_src) return;
+
+ if (event != BTA_SDP_SEARCH_COMP_EVT) return;
+
+ maybe_non_aligned_memcpy(p_dest_data, p_src_data, sizeof(*p_src_data));
+
+ copy_sdp_records(p_src_data->records, p_dest_data->records,
+ p_src_data->record_count);
+}
+
+static void sdp_dm_cback(tBTA_SDP_EVT event, tBTA_SDP* p_data,
+ void* user_data) {
+ switch (event) {
+ case BTA_SDP_SEARCH_COMP_EVT: {
+ int size = sizeof(tBTA_SDP);
+ size += get_sdp_records_size(p_data->sdp_search_comp.records,
+ p_data->sdp_search_comp.record_count);
+
+ /* need to deep copy the record content */
+ btif_transfer_context(btif_sdp_search_comp_evt, event, (char*)p_data,
+ size, sdp_search_comp_copy_cb);
+ break;
+ }
+ case BTA_SDP_CREATE_RECORD_USER_EVT: {
+ on_create_record_event(PTR_TO_INT(user_data));
+ break;
+ }
+ case BTA_SDP_REMOVE_RECORD_USER_EVT: {
+ on_remove_record_event(PTR_TO_INT(user_data));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static bt_status_t init(btsdp_callbacks_t* callbacks) {
+ BTIF_TRACE_DEBUG("Sdp Search %s", __func__);
+
+ bt_sdp_callbacks = callbacks;
+ sdp_server_init();
+
+ btif_enable_service(BTA_SDP_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t deinit() {
+ BTIF_TRACE_DEBUG("Sdp Search %s", __func__);
+
+ bt_sdp_callbacks = NULL;
+ sdp_server_cleanup();
+ btif_disable_service(BTA_SDP_SERVICE_ID);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t search(bt_bdaddr_t* bd_addr, const uint8_t* uuid) {
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, uuid, sizeof(sdp_uuid.uu.uuid128));
+
+ BTA_SdpSearch(bd_addr->address, &sdp_uuid);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static const btsdp_interface_t sdp_if = {
+ sizeof(btsdp_interface_t), init, deinit, search, create_sdp_record,
+ remove_sdp_record};
+
+const btsdp_interface_t* btif_sdp_get_interface(void) {
+ BTIF_TRACE_DEBUG("%s", __func__);
+ return &sdp_if;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_sdp_execute_service
+ *
+ * Description Initializes/Shuts down the service
+ *
+ * Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_sdp_execute_service(bool b_enable) {
+ BTIF_TRACE_DEBUG("%s enable:%d", __func__, b_enable);
+
+ if (b_enable) {
+ BTA_SdpEnable(sdp_dm_cback);
+ } else {
+ /* This is called on BT disable so no need to extra cleanup */
+ }
+ return BT_STATUS_SUCCESS;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sdp_server.cc b/mtkbt/code/bt/btif/src/btif_sdp_server.cc
new file mode 100755
index 0000000..43d489b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sdp_server.cc
@@ -0,0 +1,767 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Samsung System LSI
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sdp_server.cc
+ * Description: SDP server Bluetooth Interface to create and remove SDP
+ * records.
+ * To be used in combination with the RFCOMM/L2CAP(LE) sockets.
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sdp_server"
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sdp.h>
+
+#include "bta_sdp_api.h"
+#include "bta_sys.h"
+#include "btif_common.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/allocator.h"
+#include "utl.h"
+
+// Protects the sdp_slots array from concurrent access.
+static std::recursive_mutex sdp_lock;
+
+/**
+ * The need for a state variable have been reduced to two states.
+ * The remaining state control is handled by program flow
+ */
+typedef enum {
+ SDP_RECORD_FREE = 0,
+ SDP_RECORD_ALLOCED,
+} sdp_state_t;
+
+typedef struct {
+ sdp_state_t state;
+ int sdp_handle;
+ bluetooth_sdp_record* record_data;
+} sdp_slot_t;
+
+#define MAX_SDP_SLOTS 128
+static sdp_slot_t sdp_slots[MAX_SDP_SLOTS];
+
+/*****************************************************************************
+ * LOCAL Functions
+ *****************************************************************************/
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec);
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec);
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec);
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec);
+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec);
+bt_status_t remove_sdp_record(int record_id);
+static int free_sdp_slot(int id);
+
+/******************************************************************************
+ * WARNING: Functions below are not called in BTU context.
+ * Introduced to make it possible to create SDP records from JAVA with both a
+ * RFCOMM channel and a L2CAP PSM.
+ * Overall architecture:
+ * 1) JAVA calls createRecord() which returns a pseudo ID which at a later
+ * point will be linked to a specific SDP handle.
+ * 2) createRecord() requests the BTU task(thread) to call a callback in SDP
+ * which creates the actual record, and updates the ID<->SDPHandle map
+ * based on the ID beeing passed to BTA as user_data.
+ *****************************************************************************/
+
+static void init_sdp_slots() {
+ int i;
+ memset(sdp_slots, 0, sizeof(sdp_slot_t) * MAX_SDP_SLOTS);
+ /* if SDP_RECORD_FREE is zero - no need to set the value */
+ if (SDP_RECORD_FREE != 0) {
+ for (i = 0; i < MAX_SDP_SLOTS; i++) {
+ sdp_slots[i].state = SDP_RECORD_FREE;
+ }
+ }
+}
+
+bt_status_t sdp_server_init() {
+ BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+ init_sdp_slots();
+ return BT_STATUS_SUCCESS;
+}
+
+void sdp_server_cleanup() {
+ BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ int i;
+ for (i = 0; i < MAX_SDP_SLOTS; i++) {
+ /*remove_sdp_record(i); we cannot send messages to the other threads, since
+ * they might
+ * have been shut down already. Just do local cleanup.
+ */
+ free_sdp_slot(i);
+ }
+}
+
+int get_sdp_records_size(bluetooth_sdp_record* in_record, int count) {
+ bluetooth_sdp_record* record = in_record;
+ int records_size = 0;
+ int i;
+ for (i = 0; i < count; i++) {
+ record = &in_record[i];
+ records_size += sizeof(bluetooth_sdp_record);
+ records_size += record->hdr.service_name_length;
+ if (record->hdr.service_name_length > 0) {
+ records_size++; /* + '\0' termination of string */
+ }
+ records_size += record->hdr.user1_ptr_len;
+ records_size += record->hdr.user2_ptr_len;
+ }
+ return records_size;
+}
+
+/* Deep copy all content of in_records into out_records.
+ * out_records must point to a chunk of memory large enough to contain all
+ * the data. Use getSdpRecordsSize() to calculate the needed size. */
+void copy_sdp_records(bluetooth_sdp_record* in_records,
+ bluetooth_sdp_record* out_records, int count) {
+ int i;
+ bluetooth_sdp_record* in_record;
+ bluetooth_sdp_record* out_record;
+ char* free_ptr =
+ (char*)(&out_records[count]); /* set pointer to after the last entry */
+
+ for (i = 0; i < count; i++) {
+ in_record = &in_records[i];
+ out_record = &out_records[i];
+ *out_record = *in_record;
+
+ if (in_record->hdr.service_name == NULL ||
+ in_record->hdr.service_name_length == 0) {
+ out_record->hdr.service_name = NULL;
+ out_record->hdr.service_name_length = 0;
+ } else {
+ out_record->hdr.service_name = free_ptr; // Update service_name pointer
+ // Copy string
+ memcpy(free_ptr, in_record->hdr.service_name,
+ in_record->hdr.service_name_length);
+ free_ptr += in_record->hdr.service_name_length;
+ *(free_ptr) = '\0'; // Set '\0' termination of string
+ free_ptr++;
+ }
+ if (in_record->hdr.user1_ptr != NULL) {
+ out_record->hdr.user1_ptr = (uint8_t*)free_ptr; // Update pointer
+ memcpy(free_ptr, in_record->hdr.user1_ptr,
+ in_record->hdr.user1_ptr_len); // Copy content
+ free_ptr += in_record->hdr.user1_ptr_len;
+ }
+ if (in_record->hdr.user2_ptr != NULL) {
+ out_record->hdr.user2_ptr = (uint8_t*)free_ptr; // Update pointer
+ memcpy(free_ptr, in_record->hdr.user2_ptr,
+ in_record->hdr.user2_ptr_len); // Copy content
+ free_ptr += in_record->hdr.user2_ptr_len;
+ }
+ }
+ return;
+}
+
+/* Reserve a slot in sdp_slots, copy data and set a reference to the copy.
+ * The record_data will contain both the record and any data pointed to by
+ * the record.
+ * Currently this covers:
+ * service_name string,
+ * user1_ptr and
+ * user2_ptr. */
+static int alloc_sdp_slot(bluetooth_sdp_record* in_record) {
+ int record_size = get_sdp_records_size(in_record, 1);
+ /* We are optimists here, and preallocate the record.
+ * This is to reduce the time we hold the sdp_lock. */
+ bluetooth_sdp_record* record = (bluetooth_sdp_record*)osi_malloc(record_size);
+
+ copy_sdp_records(in_record, record, 1);
+ {
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ for (int i = 0; i < MAX_SDP_SLOTS; i++) {
+ if (sdp_slots[i].state == SDP_RECORD_FREE) {
+ sdp_slots[i].state = SDP_RECORD_ALLOCED;
+ sdp_slots[i].record_data = record;
+ return i;
+ }
+ }
+ }
+ APPL_TRACE_ERROR("%s() failed - no more free slots!", __func__);
+ /* Rearly the optimist is too optimistic, and cleanup is needed...*/
+ osi_free(record);
+ return -1;
+}
+
+static int free_sdp_slot(int id) {
+ int handle = -1;
+ bluetooth_sdp_record* record = NULL;
+ if (id >= MAX_SDP_SLOTS) {
+ APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
+ return handle;
+ }
+
+ {
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ handle = sdp_slots[id].sdp_handle;
+ sdp_slots[id].sdp_handle = 0;
+ if (sdp_slots[id].state != SDP_RECORD_FREE) {
+ /* safe a copy of the pointer, and free after unlock() */
+ record = sdp_slots[id].record_data;
+ }
+ sdp_slots[id].state = SDP_RECORD_FREE;
+ }
+
+ if (record != NULL) {
+ osi_free(record);
+ } else {
+ // Record have already been freed
+ handle = -1;
+ }
+ return handle;
+}
+
+/***
+ * Use this to get a reference to a SDP slot AND change the state to
+ * SDP_RECORD_CREATE_INITIATED.
+ */
+static const sdp_slot_t* start_create_sdp(int id) {
+ if (id >= MAX_SDP_SLOTS) {
+ APPL_TRACE_ERROR("%s() failed - id %d is invalid", __func__, id);
+ return NULL;
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ if (sdp_slots[id].state != SDP_RECORD_ALLOCED) {
+ /* The record have been removed before this event occurred - e.g. deinit */
+ APPL_TRACE_ERROR(
+ "%s() failed - state for id %d is "
+ "sdp_slots[id].state = %d expected %d",
+ __func__, id, sdp_slots[id].state, SDP_RECORD_ALLOCED);
+ return NULL;
+ }
+
+ return &(sdp_slots[id]);
+}
+
+static void set_sdp_handle(int id, int handle) {
+ std::unique_lock<std::recursive_mutex> lock(sdp_lock);
+ sdp_slots[id].sdp_handle = handle;
+ BTIF_TRACE_DEBUG("%s() id=%d to handle=0x%08x", __func__, id, handle);
+}
+
+bt_status_t create_sdp_record(bluetooth_sdp_record* record,
+ int* record_handle) {
+ int handle;
+
+ handle = alloc_sdp_slot(record);
+ BTIF_TRACE_DEBUG("%s() handle = 0x%08x", __func__, handle);
+
+ if (handle < 0) return BT_STATUS_FAIL;
+
+ BTA_SdpCreateRecordByUser(INT_TO_PTR(handle));
+
+ *record_handle = handle;
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t remove_sdp_record(int record_id) {
+ int handle;
+
+ /* Get the Record handle, and free the slot */
+ handle = free_sdp_slot(record_id);
+ BTIF_TRACE_DEBUG("Sdp Server %s id=%d to handle=0x%08x", __func__, record_id,
+ handle);
+
+ /* Pass the actual record handle */
+ if (handle > 0) {
+ BTA_SdpRemoveRecordByUser(INT_TO_PTR(handle));
+ return BT_STATUS_SUCCESS;
+ }
+ BTIF_TRACE_DEBUG("Sdp Server %s - record already removed - or never created",
+ __func__);
+ return BT_STATUS_FAIL;
+}
+
+/******************************************************************************
+ * CALLBACK FUNCTIONS
+ * Called in BTA context to create/remove SDP records.
+ ******************************************************************************/
+
+void on_create_record_event(int id) {
+ /*
+ * 1) Fetch the record pointer, and change its state?
+ * 2) switch on the type to create the correct record
+ * 3) Update state on completion
+ * 4) What to do at fail?
+ * */
+ BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+ const sdp_slot_t* sdp_slot = start_create_sdp(id);
+ /* In the case we are shutting down, sdp_slot is NULL */
+ if (sdp_slot != NULL) {
+ bluetooth_sdp_record* record = sdp_slot->record_data;
+ int handle = -1;
+ switch (record->hdr.type) {
+ case SDP_TYPE_MAP_MAS:
+ handle = add_maps_sdp(&record->mas);
+ break;
+ case SDP_TYPE_MAP_MNS:
+ handle = add_mapc_sdp(&record->mns);
+ break;
+ case SDP_TYPE_PBAP_PSE:
+ handle = add_pbaps_sdp(&record->pse);
+ break;
+ case SDP_TYPE_OPP_SERVER:
+ handle = add_opps_sdp(&record->ops);
+ break;
+ case SDP_TYPE_SAP_SERVER:
+ handle = add_saps_sdp(&record->sap);
+ break;
+ case SDP_TYPE_PBAP_PCE:
+ // break; not yet supported
+ default:
+ BTIF_TRACE_DEBUG("Record type %d is not supported", record->hdr.type);
+ break;
+ }
+ if (handle != -1) {
+ set_sdp_handle(id, handle);
+ }
+ }
+}
+
+void on_remove_record_event(int handle) {
+ BTIF_TRACE_DEBUG("Sdp Server %s", __func__);
+
+ // User data carries the actual SDP handle, not the ID.
+ if (handle != -1 && handle != 0) {
+ bool result;
+ result = SDP_DeleteRecord(handle);
+ if (result == false) {
+ BTIF_TRACE_ERROR(" Unable to remove handle 0x%08x", handle);
+ }
+ }
+}
+
+/****
+ * Below the actual functions accessing BTA context data - hence only call from
+ * BTA context!
+ */
+
+/* Create a MAP MAS SDP record based on information stored in a
+ * bluetooth_sdp_mas_record */
+static int add_maps_sdp(const bluetooth_sdp_mas_record* rec) {
+ tSDP_PROTOCOL_ELEM protoList[3];
+ uint16_t service = UUID_SERVCLASS_MESSAGE_ACCESS;
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ bool status = true;
+ uint32_t sdp_handle = 0;
+ uint8_t temp[4];
+ uint8_t* p_temp = temp;
+
+ APPL_TRACE_DEBUG(
+ "%s(): MASID = 0x%02x, scn 0x%02x, psm = 0x%04x\n service name %s",
+ __func__, rec->mas_instance_id, rec->hdr.rfcomm_channel_number,
+ rec->hdr.l2cap_psm, rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" msg_types: 0x%02x, feature_bits: 0x%08x",
+ rec->supported_message_types, rec->supported_features);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s() - Unable to register MAPS Service", __func__);
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
+ rec->hdr.profile_version);
+
+ /* Add MAS instance ID */
+ status &=
+ SDP_AddAttribute(sdp_handle, ATTR_ID_MAS_INSTANCE_ID, UINT_DESC_TYPE,
+ (uint32_t)1, (uint8_t*)&rec->mas_instance_id);
+
+ /* Add supported message types */
+ status &=
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_MSG_TYPE, UINT_DESC_TYPE,
+ (uint32_t)1, (uint8_t*)&rec->supported_message_types);
+
+ /* Add supported feature */
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if (rec->hdr.l2cap_psm != -1) {
+ p_temp = temp; // The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (uint32_t)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s() FAILED", __func__);
+ } else {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ }
+ return sdp_handle;
+}
+
+/* Create a MAP MNS SDP record based on information stored in a
+ * bluetooth_sdp_mns_record */
+static int add_mapc_sdp(const bluetooth_sdp_mns_record* rec) {
+ tSDP_PROTOCOL_ELEM protoList[3];
+ uint16_t service = UUID_SERVCLASS_MESSAGE_NOTIFICATION;
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ bool status = true;
+ uint32_t sdp_handle = 0;
+ uint8_t temp[4];
+ uint8_t* p_temp = temp;
+
+ APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n service name %s",
+ __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+ rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" feature_bits: 0x%08x", rec->supported_features);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s(): Unable to register MAP Notification Service",
+ __func__);
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_MAP_PROFILE,
+ rec->hdr.profile_version);
+
+ /* Add supported feature */
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_MAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if (rec->hdr.l2cap_psm != -1) {
+ p_temp = temp; // The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (uint32_t)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s() FAILED", __func__);
+ } else {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ }
+ return sdp_handle;
+}
+
+/* Create a PBAP Server SDP record based on information stored in a
+ * bluetooth_sdp_pse_record */
+static int add_pbaps_sdp(const bluetooth_sdp_pse_record* rec) {
+ tSDP_PROTOCOL_ELEM protoList[3];
+ uint16_t service = UUID_SERVCLASS_PBAP_PSE;
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ bool status = true;
+ uint32_t sdp_handle = 0;
+ uint8_t temp[4];
+ uint8_t* p_temp = temp;
+
+ APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n service name %s",
+ __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+ rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" supported_repositories: 0x%08x, feature_bits: 0x%08x",
+ rec->supported_repositories, rec->supported_features);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s(): Unable to register PBAP Server Service", __func__);
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(
+ sdp_handle, UUID_SERVCLASS_PHONE_ACCESS, rec->hdr.profile_version);
+
+ /* Add supported repositories 1 byte */
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_REPOSITORIES,
+ UINT_DESC_TYPE, (uint32_t)1,
+ (uint8_t*)&rec->supported_repositories);
+
+ /* Add supported feature 4 bytes*/
+ UINT32_TO_BE_STREAM(p_temp, rec->supported_features);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_PBAP_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)4, temp);
+
+ /* Add the L2CAP PSM if present */
+ if (rec->hdr.l2cap_psm != -1) {
+ p_temp = temp; // The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (uint32_t)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s() FAILED", __func__);
+ } else {
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_MESSAGE_ACCESS */
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ }
+ return sdp_handle;
+}
+
+/* Create a OPP Server SDP record based on information stored in a
+ * bluetooth_sdp_ops_record */
+static int add_opps_sdp(const bluetooth_sdp_ops_record* rec) {
+ tSDP_PROTOCOL_ELEM protoList[3];
+ uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ uint8_t type_len[rec->supported_formats_list_len];
+ uint8_t desc_type[rec->supported_formats_list_len];
+ uint8_t* type_value[rec->supported_formats_list_len];
+ bool status = true;
+ uint32_t sdp_handle = 0;
+ uint8_t temp[4];
+ uint8_t* p_temp = temp;
+ tBTA_UTL_COD cod;
+ int i, j;
+
+ APPL_TRACE_DEBUG("%s(): scn 0x%02x, psm = 0x%04x\n service name %s",
+ __func__, rec->hdr.rfcomm_channel_number, rec->hdr.l2cap_psm,
+ rec->hdr.service_name);
+
+ APPL_TRACE_DEBUG(" supported formats count: %d",
+ rec->supported_formats_list_len);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s(): Unable to register Object Push Server Service",
+ __func__);
+ return sdp_handle;
+ }
+
+ /* add service class */
+ status &= SDP_AddServiceClassIdList(sdp_handle, 1, &service);
+ memset(protoList, 0, 3 * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol list, including RFCOMM scn */
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ protoList[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ protoList[2].num_params = 0;
+ status &= SDP_AddProtocolList(sdp_handle, 3, protoList);
+
+ /* Add a name entry */
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ /* Add in the Bluetooth Profile Descriptor List */
+ status &= SDP_AddProfileDescriptorList(
+ sdp_handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH, rec->hdr.profile_version);
+
+ /* add sequence for supported types */
+ for (i = 0, j = 0; i < rec->supported_formats_list_len; i++) {
+ type_value[j] = (uint8_t*)&rec->supported_formats_list[i];
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+
+ status &=
+ SDP_AddSequence(sdp_handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST,
+ (uint8_t)rec->supported_formats_list_len, desc_type,
+ type_len, type_value);
+
+ /* Add the L2CAP PSM if present */
+ if (rec->hdr.l2cap_psm != -1) {
+ p_temp = temp; // The macro modifies p_temp, hence rewind.
+ UINT16_TO_BE_STREAM(p_temp, rec->hdr.l2cap_psm);
+ status &= SDP_AddAttribute(sdp_handle, ATTR_ID_GOEP_L2CAP_PSM,
+ UINT_DESC_TYPE, (uint32_t)2, temp);
+ }
+
+ /* Make the service browseable */
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s() FAILED", __func__);
+ } else {
+ /* set class of device */
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
+
+ bta_sys_add_uuid(service); /* UUID_SERVCLASS_OBEX_OBJECT_PUSH */
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ }
+ return sdp_handle;
+}
+
+// Create a Sim Access Profile SDP record based on information stored in a
+// bluetooth_sdp_sap_record.
+static int add_saps_sdp(const bluetooth_sdp_sap_record* rec) {
+ tSDP_PROTOCOL_ELEM protoList[2];
+ uint16_t services[2];
+ uint16_t browse = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ bool status = true;
+ uint32_t sdp_handle = 0;
+
+ APPL_TRACE_DEBUG("%s(): scn 0x%02x, service name %s", __func__,
+ rec->hdr.rfcomm_channel_number, rec->hdr.service_name);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) {
+ APPL_TRACE_ERROR("%s(): Unable to register SAPS Service", __func__);
+ return sdp_handle;
+ }
+
+ services[0] = UUID_SERVCLASS_SAP;
+ services[1] = UUID_SERVCLASS_GENERIC_TELEPHONY;
+
+ // add service class
+ status &= SDP_AddServiceClassIdList(sdp_handle, 2, services);
+ memset(protoList, 0, 2 * sizeof(tSDP_PROTOCOL_ELEM));
+
+ // add protocol list, including RFCOMM scn
+ protoList[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ protoList[0].num_params = 0;
+ protoList[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ protoList[1].num_params = 1;
+ protoList[1].params[0] = rec->hdr.rfcomm_channel_number;
+ status &= SDP_AddProtocolList(sdp_handle, 2, protoList);
+
+ // Add a name entry
+ status &= SDP_AddAttribute(sdp_handle, (uint16_t)ATTR_ID_SERVICE_NAME,
+ (uint8_t)TEXT_STR_DESC_TYPE,
+ (uint32_t)(rec->hdr.service_name_length + 1),
+ (uint8_t*)rec->hdr.service_name);
+
+ // Add in the Bluetooth Profile Descriptor List
+ status &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_SAP,
+ rec->hdr.profile_version);
+
+ // Make the service browseable
+ status &=
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse);
+
+ if (!status) {
+ SDP_DeleteRecord(sdp_handle);
+ sdp_handle = 0;
+ APPL_TRACE_ERROR("%s(): FAILED deleting record", __func__);
+ } else {
+ bta_sys_add_uuid(UUID_SERVCLASS_SAP);
+ APPL_TRACE_DEBUG("%s(): SDP Registered (handle 0x%08x)", __func__,
+ sdp_handle);
+ }
+ return sdp_handle;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sm.cc b/mtkbt/code/bt/btif/src/btif_sm.cc
new file mode 100755
index 0000000..8f7bbb2
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sm.cc
@@ -0,0 +1,181 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: btif_sm.c
+ *
+ * Description: Generic BTIF state machine API
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btif"
+
+#include "btif_sm.h"
+
+#include "bt_common.h"
+#include "btif_common.h"
+#include "osi/include/allocator.h"
+
+/*****************************************************************************
+ * Local type definitions
+ *****************************************************************************/
+typedef struct {
+ btif_sm_state_t state;
+ btif_sm_handler_t* p_handlers;
+} btif_sm_cb_t;
+
+/*****************************************************************************
+ * Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function btif_sm_init
+ *
+ * Description Initializes the state machine with the state handlers
+ * The caller should ensure that the table and the corresponding
+ * states match. The location that 'p_handlers' points to shall
+ * be available until the btif_sm_shutdown API is invoked.
+ *
+ * Returns Returns a pointer to the initialized state machine handle.
+ *
+ *****************************************************************************/
+
+btif_sm_handle_t btif_sm_init(const btif_sm_handler_t* p_handlers,
+ btif_sm_state_t initial_state) {
+ if (p_handlers == NULL) {
+ BTIF_TRACE_ERROR("%s : p_handlers is NULL", __func__);
+ return NULL;
+ }
+
+ btif_sm_cb_t* p_cb = (btif_sm_cb_t*)osi_malloc(sizeof(btif_sm_cb_t));
+ p_cb->state = initial_state;
+ p_cb->p_handlers = (btif_sm_handler_t*)p_handlers;
+
+ /* Send BTIF_SM_ENTER_EVT to the initial state */
+ p_cb->p_handlers[initial_state](BTIF_SM_ENTER_EVT, NULL);
+
+ return (btif_sm_handle_t)p_cb;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_sm_shutdown
+ *
+ * Description Tears down the state machine
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void btif_sm_shutdown(btif_sm_handle_t handle) {
+ btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL) {
+ BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+ return;
+ }
+ osi_free(p_cb);
+}
+
+/*****************************************************************************
+ *
+ * Function btif_sm_get_state
+ *
+ * Description Fetches the current state of the state machine
+ *
+ * Returns Current state
+ *
+ *****************************************************************************/
+btif_sm_state_t btif_sm_get_state(btif_sm_handle_t handle) {
+ btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL) {
+ BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+ return 0;
+ }
+
+ return p_cb->state;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_sm_dispatch
+ *
+ * Description Dispatches the 'event' along with 'data' to the current state
+ * handler
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ * BT_STATUS_UNHANDLED if event was not processed
+ * BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_dispatch(btif_sm_handle_t handle, btif_sm_event_t event,
+ void* data) {
+ bt_status_t status = BT_STATUS_SUCCESS;
+
+ btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL) {
+ BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+ return BT_STATUS_FAIL;
+ }
+
+ if (p_cb->p_handlers[p_cb->state](event, data) == false)
+ return BT_STATUS_UNHANDLED;
+
+ return status;
+}
+
+/*****************************************************************************
+ *
+ * Function btif_sm_change_state
+ *
+ * Description Make a transition to the new 'state'. The 'BTIF_SM_EXIT_EVT'
+ * shall be invoked before exiting the current state. The
+ * 'BTIF_SM_ENTER_EVT' shall be invoked before entering the new
+ * state
+ *
+ * Returns BT_STATUS_SUCCESS on success
+ * BT_STATUS_UNHANDLED if event was not processed
+ * BT_STATUS_FAIL otherwise
+ *
+ *****************************************************************************/
+bt_status_t btif_sm_change_state(btif_sm_handle_t handle,
+ btif_sm_state_t state) {
+ bt_status_t status = BT_STATUS_SUCCESS;
+ btif_sm_cb_t* p_cb = (btif_sm_cb_t*)handle;
+
+ if (p_cb == NULL) {
+ BTIF_TRACE_ERROR("%s : Invalid handle", __func__);
+ return BT_STATUS_FAIL;
+ }
+
+ /* Send exit event to the current state */
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_EXIT_EVT, NULL) == false)
+ status = BT_STATUS_UNHANDLED;
+
+ /* Change to the new state */
+ p_cb->state = state;
+
+ /* Send enter event to the new state */
+ if (p_cb->p_handlers[p_cb->state](BTIF_SM_ENTER_EVT, NULL) == false)
+ status = BT_STATUS_UNHANDLED;
+
+ return status;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock.cc b/mtkbt/code/bt/btif/src/btif_sock.cc
new file mode 100755
index 0000000..2495d46
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock.cc
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include <atomic>
+
+#include <base/logging.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_sock_l2cap.h"
+#include "btif_sock_rfc.h"
+#include "btif_sock_sco.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "osi/include/thread.h"
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+ const uint8_t* uuid, int channel, int* sock_fd,
+ int flags, int app_uid);
+static bt_status_t btsock_connect(const bt_bdaddr_t* bd_addr,
+ btsock_type_t type, const uint8_t* uuid,
+ int channel, int* sock_fd, int flags,
+ int app_uid);
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id);
+
+static std::atomic_int thread_handle{-1};
+static thread_t* thread;
+
+btsock_interface_t* btif_sock_get_interface(void) {
+ static btsock_interface_t interface = {sizeof(interface), btsock_listen,
+ btsock_connect};
+
+ return &interface;
+}
+
+bt_status_t btif_sock_init(uid_set_t* uid_set) {
+ CHECK(thread_handle == -1);
+ CHECK(thread == NULL);
+
+ bt_status_t status;
+ btsock_thread_init();
+ thread_handle = btsock_thread_create(btsock_signaled, NULL);
+ if (thread_handle == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to create btsock_thread.", __func__);
+ goto error;
+ }
+
+ status = btsock_rfc_init(thread_handle, uid_set);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s error initializing RFCOMM sockets: %d", __func__,
+ status);
+ goto error;
+ }
+
+ status = btsock_l2cap_init(thread_handle, uid_set);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s error initializing L2CAP sockets: %d", __func__,
+ status);
+ goto error;
+ }
+
+ thread = thread_new("btif_sock");
+ if (!thread) {
+ LOG_ERROR(LOG_TAG, "%s error creating new thread.", __func__);
+ btsock_rfc_cleanup();
+ goto error;
+ }
+
+ status = btsock_sco_init(thread);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s error initializing SCO sockets: %d", __func__,
+ status);
+ btsock_rfc_cleanup();
+ goto error;
+ }
+
+ return BT_STATUS_SUCCESS;
+
+error:;
+ thread_free(thread);
+ thread = NULL;
+ if (thread_handle != -1) btsock_thread_exit(thread_handle);
+ thread_handle = -1;
+ uid_set = NULL;
+ return BT_STATUS_FAIL;
+}
+
+void btif_sock_cleanup(void) {
+ int saved_handle = thread_handle;
+ if (std::atomic_exchange(&thread_handle, -1) == -1) return;
+
+ btsock_thread_exit(saved_handle);
+ btsock_rfc_cleanup();
+ btsock_sco_cleanup();
+ btsock_l2cap_cleanup();
+ thread_free(thread);
+ thread = NULL;
+}
+
+static bt_status_t btsock_listen(btsock_type_t type, const char* service_name,
+ const uint8_t* service_uuid, int channel,
+ int* sock_fd, int flags, int app_uid) {
+ if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+ CHECK(service_uuid != NULL || channel > 0);
+ CHECK(sock_fd != NULL);
+ }
+
+ *sock_fd = INVALID_FD;
+ bt_status_t status = BT_STATUS_FAIL;
+
+ switch (type) {
+ case BTSOCK_RFCOMM:
+ status = btsock_rfc_listen(service_name, service_uuid, channel, sock_fd,
+ flags, app_uid);
+ break;
+ case BTSOCK_L2CAP:
+ status =
+ btsock_l2cap_listen(service_name, channel, sock_fd, flags, app_uid);
+ break;
+
+ case BTSOCK_SCO:
+ status = btsock_sco_listen(sock_fd, flags);
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__,
+ type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+
+static bt_status_t btsock_connect(const bt_bdaddr_t* bd_addr,
+ btsock_type_t type, const uint8_t* uuid,
+ int channel, int* sock_fd, int flags,
+ int app_uid) {
+ CHECK(uuid != NULL || channel > 0);
+ CHECK(bd_addr != NULL);
+ CHECK(sock_fd != NULL);
+
+ *sock_fd = INVALID_FD;
+ bt_status_t status = BT_STATUS_FAIL;
+
+ switch (type) {
+ case BTSOCK_RFCOMM:
+ status =
+ btsock_rfc_connect(bd_addr, uuid, channel, sock_fd, flags, app_uid);
+ break;
+
+ case BTSOCK_L2CAP:
+ status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
+ break;
+
+ case BTSOCK_SCO:
+ status = btsock_sco_connect(bd_addr, sock_fd, flags);
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s unknown/unsupported socket type: %d", __func__,
+ type);
+ status = BT_STATUS_UNSUPPORTED;
+ break;
+ }
+ return status;
+}
+
+static void btsock_signaled(int fd, int type, int flags, uint32_t user_id) {
+ switch (type) {
+ case BTSOCK_RFCOMM:
+ btsock_rfc_signaled(fd, flags, user_id);
+ break;
+ case BTSOCK_L2CAP:
+ btsock_l2cap_signaled(fd, flags, user_id);
+ break;
+ default:
+ CHECK(false && "Invalid socket type");
+ break;
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_l2cap.cc b/mtkbt/code/bt/btif/src/btif_sock_l2cap.cc
new file mode 100755
index 0000000..d839b55
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_l2cap.cc
@@ -0,0 +1,1081 @@
+/*
+* Copyright (C) 2014 Samsung System LSI
+* Copyright (C) 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_l2cap.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bt_sock.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+struct packet {
+ struct packet *next, *prev;
+ uint32_t len;
+ uint8_t* data;
+};
+
+typedef struct l2cap_socket {
+ struct l2cap_socket* prev; // link to prev list item
+ struct l2cap_socket* next; // link to next list item
+ bt_bdaddr_t addr; // other side's address
+ char name[256]; // user-friendly name of the service
+ uint32_t id; // just a tag to find this struct
+ int app_uid; // The UID of the app who requested this socket
+ int handle; // handle from lower layers
+ unsigned security; // security flags
+ int channel; // channel (fixed_chan) or PSM (!fixed_chan)
+ int our_fd; // fd from our side
+ int app_fd; // fd from app's side
+
+ unsigned bytes_buffered;
+ struct packet* first_packet; // fist packet to be delivered to app
+ struct packet* last_packet; // last packet to be delivered to app
+
+ fixed_queue_t* incoming_que; // data that came in but has not yet been read
+ unsigned fixed_chan : 1; // fixed channel (or psm?)
+ unsigned server : 1; // is a server? (or connecting?)
+ unsigned connected : 1; // is connected?
+ unsigned outgoing_congest : 1; // should we hold?
+ unsigned server_psm_sent : 1; // The server shall only send PSM once.
+ bool is_le_coc; // is le connection oriented channel?
+} l2cap_socket;
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock);
+
+static std::mutex state_lock;
+
+l2cap_socket* socks = NULL;
+static uid_set_t* uid_set = NULL;
+static int pth = -1;
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t l2cap_socket_id);
+
+/* TODO: Consider to remove this buffer, as we have a buffer in l2cap as well,
+ * and we risk
+ * a buffer overflow with this implementation if the socket data is not
+ * read from
+ * JAVA for a while. In such a case we should use flow control to tell the
+ * sender to
+ * back off.
+ * BUT remember we need to avoid blocking the BTA task execution - hence
+ * we cannot
+ * directly write to the socket.
+ * we should be able to change to store the data pointer here, and just
+ * wait
+ * confirming the l2cap_ind until we have more space in the buffer. */
+
+/* returns false if none - caller must free "data" memory when done with it */
+static char packet_get_head_l(l2cap_socket* sock, uint8_t** data,
+ uint32_t* len) {
+ struct packet* p = sock->first_packet;
+
+ if (!p) return false;
+
+ if (data) *data = sock->first_packet->data;
+ if (len) *len = sock->first_packet->len;
+ sock->first_packet = p->next;
+ if (sock->first_packet)
+ sock->first_packet->prev = NULL;
+ else
+ sock->last_packet = NULL;
+
+ if (len) sock->bytes_buffered -= *len;
+
+ osi_free(p);
+
+ return true;
+}
+
+static struct packet* packet_alloc(const uint8_t* data, uint32_t len) {
+ struct packet* p = (struct packet*)osi_calloc(sizeof(*p));
+ uint8_t* buf = (uint8_t*)osi_malloc(len);
+
+ p->data = buf;
+ p->len = len;
+ memcpy(p->data, data, len);
+ return p;
+}
+
+/* makes a copy of the data, returns true on success */
+static char packet_put_head_l(l2cap_socket* sock, const void* data,
+ uint32_t len) {
+ struct packet* p = packet_alloc((const uint8_t*)data, len);
+
+ /*
+ * We do not check size limits here since this is used to undo "getting" a
+ * packet that the user read incompletely. That is to say the packet was
+ * already in the queue. We do check thos elimits in packet_put_tail_l() since
+ * that function is used to put new data into the queue.
+ */
+
+ if (!p) return false;
+
+ p->prev = NULL;
+ p->next = sock->first_packet;
+ sock->first_packet = p;
+ if (p->next)
+ p->next->prev = p;
+ else
+ sock->last_packet = p;
+
+ sock->bytes_buffered += len;
+
+ return true;
+}
+
+/* makes a copy of the data, returns true on success */
+static char packet_put_tail_l(l2cap_socket* sock, const void* data,
+ uint32_t len) {
+ struct packet* p = packet_alloc((const uint8_t*)data, len);
+
+ if (sock->bytes_buffered >= L2CAP_MAX_RX_BUFFER) {
+ LOG_ERROR(LOG_TAG, "packet_put_tail_l: buffer overflow");
+ return false;
+ }
+
+ if (!p) {
+ LOG_ERROR(LOG_TAG, "packet_put_tail_l: unable to allocate packet...");
+ return false;
+ }
+
+ p->next = NULL;
+ p->prev = sock->last_packet;
+ sock->last_packet = p;
+ if (p->prev)
+ p->prev->next = p;
+ else
+ sock->first_packet = p;
+
+ sock->bytes_buffered += len;
+
+ return true;
+}
+
+static inline void bd_copy(uint8_t* dest, uint8_t* src, bool swap) {
+ if (swap) {
+ for (int i = 0; i < 6; i++) dest[i] = src[5 - i];
+ } else {
+ memcpy(dest, src, 6);
+ }
+}
+
+static char is_inited(void) {
+ std::unique_lock<std::mutex> lock(state_lock);
+ return pth != -1;
+}
+
+/* only call with std::mutex taken */
+static l2cap_socket* btsock_l2cap_find_by_id_l(uint32_t id) {
+ l2cap_socket* sock = socks;
+
+ while (sock && sock->id != id) sock = sock->next;
+
+ return sock;
+}
+
+static void btsock_l2cap_free_l(l2cap_socket* sock) {
+ uint8_t* buf;
+ l2cap_socket* t = socks;
+
+ while (t && t != sock) t = t->next;
+
+ if (!t) /* prever double-frees */
+ return;
+
+ if (sock->next) sock->next->prev = sock->prev;
+
+ if (sock->prev)
+ sock->prev->next = sock->next;
+ else
+ socks = sock->next;
+
+ shutdown(sock->our_fd, SHUT_RDWR);
+ close(sock->our_fd);
+ if (sock->app_fd != -1) {
+ close(sock->app_fd);
+ } else {
+ APPL_TRACE_ERROR("SOCK_LIST: free(id = %d) - NO app_fd!", sock->id);
+ }
+
+ while (packet_get_head_l(sock, &buf, NULL)) osi_free(buf);
+
+ // lower-level close() should be idempotent... so let's call it and see...
+ if (sock->is_le_coc) {
+ // Only call if we are non server connections
+ if (sock->handle >= 0 && (sock->server == false)) {
+ BTA_JvL2capClose(sock->handle);
+ }
+ if ((sock->channel >= 0) && (sock->server == true)) {
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+ }
+ } else {
+ // Only call if we are non server connections
+ if ((sock->handle >= 0) && (sock->server == false)) {
+ if (sock->fixed_chan)
+ BTA_JvL2capCloseLE(sock->handle);
+ else
+ BTA_JvL2capClose(sock->handle);
+ }
+ if ((sock->channel >= 0) && (sock->server == true)) {
+ if (sock->fixed_chan)
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP_LE);
+ else
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+
+ if (!sock->fixed_chan) {
+ APPL_TRACE_DEBUG("%s stopping L2CAP server channel %d", __func__,
+ sock->channel);
+ BTA_JvL2capStopServer(sock->channel, sock->id);
+ }
+ }
+ }
+
+ APPL_TRACE_DEBUG("%s: free(id = %d)", __func__, sock->id);
+ osi_free(sock);
+}
+
+static l2cap_socket* btsock_l2cap_alloc_l(const char* name,
+ const bt_bdaddr_t* addr,
+ char is_server, int flags) {
+ unsigned security = 0;
+ int fds[2];
+ l2cap_socket* sock = (l2cap_socket*)osi_calloc(sizeof(*sock));
+
+ if (flags & BTSOCK_FLAG_ENCRYPT)
+ security |= is_server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+ if (flags & BTSOCK_FLAG_AUTH)
+ security |= is_server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+ if (flags & BTSOCK_FLAG_AUTH_MITM)
+ security |= is_server ? BTM_SEC_IN_MITM : BTM_SEC_OUT_MITM;
+ if (flags & BTSOCK_FLAG_AUTH_16_DIGIT)
+ security |= BTM_SEC_IN_MIN_16_DIGIT_PIN;
+
+ if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, fds)) {
+ APPL_TRACE_ERROR("socketpair failed, errno:%d", errno);
+ goto fail_sockpair;
+ }
+
+ sock->our_fd = fds[0];
+ sock->app_fd = fds[1];
+ sock->security = security;
+ sock->server = is_server;
+ sock->connected = false;
+ sock->handle = 0;
+ sock->server_psm_sent = false;
+ sock->app_uid = -1;
+
+ if (name) strncpy(sock->name, name, sizeof(sock->name) - 1);
+ if (addr) sock->addr = *addr;
+
+ sock->first_packet = NULL;
+ sock->last_packet = NULL;
+
+ sock->next = socks;
+ sock->prev = NULL;
+ if (socks) socks->prev = sock;
+ sock->id = (socks ? socks->id : 0) + 1;
+ socks = sock;
+ /* paranoia cap on: verify no ID duplicates due to overflow and fix as needed
+ */
+ while (1) {
+ l2cap_socket* t;
+ t = socks->next;
+ while (t && t->id != sock->id) {
+ t = t->next;
+ }
+ if (!t && sock->id) /* non-zeor handle is unique -> we're done */
+ break;
+ /* if we're here, we found a duplicate */
+ if (!++sock->id) /* no zero IDs allowed */
+ sock->id++;
+ }
+ APPL_TRACE_DEBUG("SOCK_LIST: alloc(id = %d)", sock->id);
+ return sock;
+
+fail_sockpair:
+ osi_free(sock);
+ return NULL;
+}
+
+bt_status_t btsock_l2cap_init(int handle, uid_set_t* set) {
+ APPL_TRACE_DEBUG("%s handle = %d", __func__);
+ std::unique_lock<std::mutex> lock(state_lock);
+ pth = handle;
+ socks = NULL;
+ uid_set = set;
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_l2cap_cleanup() {
+ std::unique_lock<std::mutex> lock(state_lock);
+ pth = -1;
+ while (socks) btsock_l2cap_free_l(socks);
+ return BT_STATUS_SUCCESS;
+}
+
+static inline bool send_app_psm_or_chan_l(l2cap_socket* sock) {
+ return sock_send_all(sock->our_fd, (const uint8_t*)&sock->channel,
+ sizeof(sock->channel)) == sizeof(sock->channel);
+}
+
+static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr,
+ int channel, int status, int send_fd,
+ int tx_mtu) {
+ sock_connect_signal_t cs;
+ cs.size = sizeof(cs);
+ cs.bd_addr = *addr;
+ cs.channel = channel;
+ cs.status = status;
+ cs.max_rx_packet_size = L2CAP_MAX_SDU_LENGTH;
+ cs.max_tx_packet_size = tx_mtu;
+ if (send_fd != -1) {
+ if (sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) ==
+ sizeof(cs))
+ return true;
+ else
+ APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd);
+ } else if (sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) {
+ return true;
+ }
+ return false;
+}
+
+static void on_srv_l2cap_listen_started(tBTA_JV_L2CAP_START* p_start,
+ uint32_t id) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ if (p_start->status != BTA_JV_SUCCESS) {
+ APPL_TRACE_ERROR("Error starting l2cap_listen - status: 0x%04x",
+ p_start->status);
+ btsock_l2cap_free_l(sock);
+ return;
+ }
+
+ sock->handle = p_start->handle;
+ APPL_TRACE_DEBUG("on_srv_l2cap_listen_started() sock->handle =%d id:%d",
+ sock->handle, sock->id);
+
+ if (sock->server_psm_sent == false) {
+ if (!send_app_psm_or_chan_l(sock)) {
+ // closed
+ APPL_TRACE_DEBUG("send_app_psm() failed, close rs->id:%d", sock->id);
+ btsock_l2cap_free_l(sock);
+ } else {
+ sock->server_psm_sent = true;
+ }
+ }
+}
+
+static void on_cl_l2cap_init(tBTA_JV_L2CAP_CL_INIT* p_init, uint32_t id) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ if (p_init->status != BTA_JV_SUCCESS) {
+ btsock_l2cap_free_l(sock);
+ return;
+ }
+
+ sock->handle = p_init->handle;
+}
+
+/**
+ * Here we allocate a new sock instance to mimic the BluetoothSocket. The socket
+ * will be a clone
+ * of the sock representing the BluetoothServerSocket.
+ * */
+static void on_srv_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
+ l2cap_socket* sock) {
+ l2cap_socket* accept_rs;
+ uint32_t new_listen_id;
+
+ // std::mutex locked by caller
+ accept_rs = btsock_l2cap_alloc_l(
+ sock->name, (const bt_bdaddr_t*)p_open->rem_bda, false, 0);
+ accept_rs->connected = true;
+ accept_rs->security = sock->security;
+ accept_rs->fixed_chan = sock->fixed_chan;
+ accept_rs->channel = sock->channel;
+ accept_rs->handle = sock->handle;
+ accept_rs->app_uid = sock->app_uid;
+ sock->handle =
+ -1; /* We should no longer associate this handle with the server socket */
+ accept_rs->is_le_coc = sock->is_le_coc;
+
+ /* Swap IDs to hand over the GAP connection to the accepted socket, and start
+ a new server on
+ the newly create socket ID. */
+ new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+
+ if (accept_rs) {
+ // start monitor the socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_EXCEPTION, sock->id);
+ btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_RD, accept_rs->id);
+ APPL_TRACE_DEBUG(
+ "sending connect signal & app fd: %d to app server to accept() the"
+ " connection",
+ accept_rs->app_fd);
+ APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+ send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+ accept_rs->app_fd, p_open->tx_mtu);
+ accept_rs->app_fd =
+ -1; // The fd is closed after sent to app in send_app_connect_signal()
+ // But for some reason we still leak a FD - either the server socket
+ // one or the accept socket one.
+ if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS) {
+ btsock_l2cap_free_l(sock);
+ }
+ }
+}
+
+static void on_srv_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
+ l2cap_socket* sock) {
+ l2cap_socket* accept_rs;
+ uint32_t new_listen_id;
+
+ // std::mutex locked by caller
+ accept_rs = btsock_l2cap_alloc_l(
+ sock->name, (const bt_bdaddr_t*)p_open->rem_bda, false, 0);
+ if (accept_rs) {
+ // swap IDs
+ new_listen_id = accept_rs->id;
+ accept_rs->id = sock->id;
+ sock->id = new_listen_id;
+
+ accept_rs->handle = p_open->handle;
+ accept_rs->connected = true;
+ accept_rs->security = sock->security;
+ accept_rs->fixed_chan = sock->fixed_chan;
+ accept_rs->channel = sock->channel;
+ accept_rs->app_uid = sock->app_uid;
+
+ // if we do not set a callback, this socket will be dropped */
+ *(p_open->p_p_cback) = (void*)btsock_l2cap_cbk;
+ *(p_open->p_user_data) = UINT_TO_PTR(accept_rs->id);
+
+ // start monitor the socket
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_EXCEPTION, sock->id);
+ btsock_thread_add_fd(pth, accept_rs->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_RD, accept_rs->id);
+ APPL_TRACE_DEBUG(
+ "sending connect signal & app fd:%dto app server to accept() the"
+ " connection",
+ accept_rs->app_fd);
+ APPL_TRACE_DEBUG("server fd:%d, scn:%d", sock->our_fd, sock->channel);
+ send_app_connect_signal(sock->our_fd, &accept_rs->addr, sock->channel, 0,
+ accept_rs->app_fd, p_open->tx_mtu);
+ accept_rs->app_fd = -1; // the fd is closed after sent to app
+ }
+}
+
+static void on_cl_l2cap_psm_connect_l(tBTA_JV_L2CAP_OPEN* p_open,
+ l2cap_socket* sock) {
+ bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+ if (!send_app_psm_or_chan_l(sock)) {
+ APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+ return;
+ }
+
+ if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+ p_open->tx_mtu)) {
+ // start monitoring the socketpair to get call back when app writing data
+ APPL_TRACE_DEBUG(
+ "on_l2cap_connect_ind, connect signal sent, slot id:%d, psm:%d,"
+ " server:%d",
+ sock->id, sock->channel, sock->server);
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ sock->id);
+ sock->connected = true;
+ } else
+ APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_cl_l2cap_le_connect_l(tBTA_JV_L2CAP_LE_OPEN* p_open,
+ l2cap_socket* sock) {
+ bd_copy(sock->addr.address, p_open->rem_bda, 0);
+
+ if (!send_app_psm_or_chan_l(sock)) {
+ APPL_TRACE_ERROR("send_app_psm_or_chan_l failed");
+ return;
+ }
+
+ if (send_app_connect_signal(sock->our_fd, &sock->addr, sock->channel, 0, -1,
+ p_open->tx_mtu)) {
+ // start monitoring the socketpair to get call back when app writing data
+ APPL_TRACE_DEBUG(
+ "on_l2cap_connect_ind, connect signal sent, slot id:%d, Chan:%d,"
+ " server:%d",
+ sock->id, sock->channel, sock->server);
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ sock->id);
+ sock->connected = true;
+ } else
+ APPL_TRACE_ERROR("send_app_connect_signal failed");
+}
+
+static void on_l2cap_connect(tBTA_JV* p_data, uint32_t id) {
+ l2cap_socket* sock;
+ tBTA_JV_L2CAP_OPEN* psm_open = &p_data->l2c_open;
+ tBTA_JV_L2CAP_LE_OPEN* le_open = &p_data->l2c_le_open;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) {
+ APPL_TRACE_ERROR("on_l2cap_connect on unknown socket");
+ return;
+ }
+
+ if (sock->fixed_chan && le_open->status == BTA_JV_SUCCESS) {
+ if (!sock->server)
+ on_cl_l2cap_le_connect_l(le_open, sock);
+ else
+ on_srv_l2cap_le_connect_l(le_open, sock);
+ } else if (!sock->fixed_chan && psm_open->status == BTA_JV_SUCCESS) {
+ if (!sock->server)
+ on_cl_l2cap_psm_connect_l(psm_open, sock);
+ else
+ on_srv_l2cap_psm_connect_l(psm_open, sock);
+ } else
+ btsock_l2cap_free_l(sock);
+}
+
+static void on_l2cap_close(tBTA_JV_L2CAP_CLOSE* p_close, uint32_t id) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ APPL_TRACE_DEBUG("on_l2cap_close, slot id:%d, fd:%d, %s:%d, server:%d",
+ sock->id, sock->our_fd,
+ sock->fixed_chan ? "fixed_chan" : "PSM", sock->channel,
+ sock->server);
+ // TODO: This does not seem to be called...
+ // I'm not sure if this will be called for non-server sockets?
+ if (!sock->fixed_chan && (sock->server == true)) {
+ BTA_JvFreeChannel(sock->channel, BTA_JV_CONN_TYPE_L2CAP);
+ }
+ btsock_l2cap_free_l(sock);
+}
+
+static void on_l2cap_outgoing_congest(tBTA_JV_L2CAP_CONG* p, uint32_t id) {
+ l2cap_socket* sock;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ sock->outgoing_congest = p->cong ? 1 : 0;
+ // mointer the fd for any outgoing data
+ if (!sock->outgoing_congest) {
+ APPL_TRACE_DEBUG(
+ "on_l2cap_outgoing_congest: adding fd to btsock_thread...");
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ sock->id);
+ }
+}
+
+static void on_l2cap_write_done(void* req_id, uint16_t len, uint32_t id) {
+ l2cap_socket* sock;
+
+ if (req_id != NULL) {
+ osi_free(req_id); // free the buffer
+ }
+
+ int app_uid = -1;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ app_uid = sock->app_uid;
+ if (!sock->outgoing_congest) {
+ // monitor the fd for any outgoing data
+ APPL_TRACE_DEBUG("on_l2cap_write_done: adding fd to btsock_thread...");
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ sock->id);
+ }
+
+ uid_set_add_tx(uid_set, app_uid, len);
+}
+
+static void on_l2cap_write_fixed_done(void* req_id, uint16_t len, uint32_t id) {
+ l2cap_socket* sock;
+
+ if (req_id != NULL) {
+ osi_free(req_id); // free the buffer
+ }
+
+ int app_uid = -1;
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ app_uid = sock->app_uid;
+ if (!sock->outgoing_congest) {
+ // monitor the fd for any outgoing data
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD,
+ sock->id);
+ }
+ uid_set_add_tx(uid_set, app_uid, len);
+}
+
+static void on_l2cap_data_ind(tBTA_JV* evt, uint32_t id) {
+ l2cap_socket* sock;
+
+ int app_uid = -1;
+ uint32_t bytes_read = 0;
+
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) return;
+
+ app_uid = sock->app_uid;
+
+ if (sock->fixed_chan) { /* we do these differently */
+
+ tBTA_JV_LE_DATA_IND* p_le_data_ind = &evt->le_data_ind;
+ BT_HDR* p_buf = p_le_data_ind->p_buf;
+ uint8_t* data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ if (packet_put_tail_l(sock, data, p_buf->len)) {
+ bytes_read = p_buf->len;
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
+ sock->id);
+ } else { // connection must be dropped
+ APPL_TRACE_DEBUG(
+ "on_l2cap_data_ind() unable to push data to socket - closing"
+ " fixed channel");
+ BTA_JvL2capCloseLE(sock->handle);
+ btsock_l2cap_free_l(sock);
+ }
+
+ } else {
+ uint8_t buffer[L2CAP_MAX_SDU_LENGTH];
+ uint32_t count;
+
+ if (BTA_JvL2capReady(sock->handle, &count) == BTA_JV_SUCCESS) {
+ if (BTA_JvL2capRead(sock->handle, sock->id, buffer, count) ==
+ BTA_JV_SUCCESS) {
+ if (packet_put_tail_l(sock, buffer, count)) {
+ bytes_read = count;
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_WR, sock->id);
+ } else { // connection must be dropped
+ APPL_TRACE_DEBUG(
+ "on_l2cap_data_ind() unable to push data to socket"
+ " - closing channel");
+ BTA_JvL2capClose(sock->handle);
+ btsock_l2cap_free_l(sock);
+ }
+ }
+ }
+ }
+
+ uid_set_add_rx(uid_set, app_uid, bytes_read);
+}
+
+static void btsock_l2cap_cbk(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t l2cap_socket_id) {
+ switch (event) {
+ case BTA_JV_L2CAP_START_EVT:
+ on_srv_l2cap_listen_started(&p_data->l2c_start, l2cap_socket_id);
+ break;
+
+ case BTA_JV_L2CAP_CL_INIT_EVT:
+ on_cl_l2cap_init(&p_data->l2c_cl_init, l2cap_socket_id);
+ break;
+
+ case BTA_JV_L2CAP_OPEN_EVT:
+ on_l2cap_connect(p_data, l2cap_socket_id);
+ BTA_JvSetPmProfile(p_data->l2c_open.handle, BTA_JV_PM_ID_1,
+ BTA_JV_CONN_OPEN);
+ break;
+
+ case BTA_JV_L2CAP_CLOSE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_CLOSE_EVT: id: %u", l2cap_socket_id);
+ on_l2cap_close(&p_data->l2c_close, l2cap_socket_id);
+ break;
+
+ case BTA_JV_L2CAP_DATA_IND_EVT:
+ on_l2cap_data_ind(p_data, l2cap_socket_id);
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_DATA_IND_EVT");
+ break;
+
+ case BTA_JV_L2CAP_READ_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_READ_EVT not used");
+ break;
+
+ case BTA_JV_L2CAP_WRITE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_EVT: id: %u", l2cap_socket_id);
+ on_l2cap_write_done(p_data->l2c_write.p_data, p_data->l2c_write.len,
+ l2cap_socket_id);
+ break;
+
+ case BTA_JV_L2CAP_WRITE_FIXED_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_L2CAP_WRITE_FIXED_EVT: id: %u", l2cap_socket_id);
+ on_l2cap_write_fixed_done(p_data->l2c_write_fixed.p_data,
+ p_data->l2c_write.len, l2cap_socket_id);
+ break;
+
+ case BTA_JV_L2CAP_CONG_EVT:
+ on_l2cap_outgoing_congest(&p_data->l2c_cong, l2cap_socket_id);
+ break;
+
+ default:
+ APPL_TRACE_ERROR("unhandled event %d, slot id: %u", event,
+ l2cap_socket_id);
+ break;
+ }
+}
+
+/* L2CAP default options for OBEX socket connections */
+const tL2CAP_FCR_OPTS obex_l2c_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
+ OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR, /* Tx window size */
+ OBX_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
+ disconnecting */
+ OBX_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ OBX_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ OBX_FCR_OPT_MAX_PDU_SIZE /* MPS segment size */
+};
+const tL2CAP_ERTM_INFO obex_l2c_etm_opt = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for OBEX over l2cap */
+ L2CAP_FCR_CHAN_OPT_ERTM, /* Mandatory for OBEX over l2cap */
+ OBX_USER_RX_BUF_SIZE, OBX_USER_TX_BUF_SIZE,
+ OBX_FCR_RX_BUF_SIZE, OBX_FCR_TX_BUF_SIZE};
+
+/**
+ * When using a dynamic PSM, a PSM allocation is requested from
+ * btsock_l2cap_listen_or_connect().
+ * The PSM allocation event is refeived in the JV-callback - currently located
+ * in RFC-code -
+ * and this function is called with the newly allocated PSM.
+ */
+void on_l2cap_psm_assigned(int id, int psm) {
+ /* Setup ETM settings:
+ * mtu will be set below */
+ std::unique_lock<std::mutex> lock(state_lock);
+ l2cap_socket* sock = btsock_l2cap_find_by_id_l(id);
+ if (!sock) {
+ APPL_TRACE_ERROR("%s: Error: sock is null", __func__);
+ return;
+ }
+
+ sock->channel = psm;
+
+ if (btSock_start_l2cap_server_l(sock) != BT_STATUS_SUCCESS)
+ btsock_l2cap_free_l(sock);
+}
+
+static bt_status_t btSock_start_l2cap_server_l(l2cap_socket* sock) {
+ tL2CAP_CFG_INFO cfg;
+ bt_status_t stat = BT_STATUS_SUCCESS;
+ /* Setup ETM settings:
+ * mtu will be set below */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.fcr_present = true;
+ cfg.fcr = obex_l2c_fcr_opts_def;
+
+ if (sock->fixed_chan) {
+ if (BTA_JvL2capStartServerLE(sock->security, 0, NULL, sock->channel,
+ L2CAP_DEFAULT_MTU, NULL, btsock_l2cap_cbk,
+ sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+
+ } else {
+ /* If we have a channel specified in the request, just start the server,
+ * else we request a PSM and start the server after we receive a PSM. */
+ if (sock->channel < 0) {
+ if (sock->is_le_coc) {
+ if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP_LE, sock->id, 0) !=
+ BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ } else {
+ if (BTA_JvGetChannelId(BTA_JV_CONN_TYPE_L2CAP, sock->id, 0) !=
+ BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ }
+ } else {
+ if (sock->is_le_coc) {
+ if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
+ NULL, sock->channel, L2CAP_MAX_SDU_LENGTH,
+ &cfg, btsock_l2cap_cbk,
+ sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ } else {
+ if (BTA_JvL2capStartServer(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
+ &obex_l2c_etm_opt, sock->channel,
+ L2CAP_MAX_SDU_LENGTH, &cfg, btsock_l2cap_cbk,
+ sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ }
+ }
+ }
+ return stat;
+}
+
+static bt_status_t btsock_l2cap_listen_or_connect(const char* name,
+ const bt_bdaddr_t* addr,
+ int channel, int* sock_fd,
+ int flags, char listen,
+ int app_uid) {
+ bt_status_t stat;
+ int fixed_chan = 1;
+ l2cap_socket* sock;
+ tL2CAP_CFG_INFO cfg;
+ bool is_le_coc = false;
+
+ if (!sock_fd) return BT_STATUS_PARM_INVALID;
+
+ if (channel < 0) {
+ // We need to auto assign a PSM
+ fixed_chan = 0;
+ } else {
+ fixed_chan = (channel & L2CAP_MASK_FIXED_CHANNEL) != 0;
+ is_le_coc = (channel & L2CAP_MASK_LE_COC_CHANNEL) != 0;
+ channel &= ~(L2CAP_MASK_FIXED_CHANNEL | L2CAP_MASK_LE_COC_CHANNEL);
+ }
+
+ if (!is_inited()) return BT_STATUS_NOT_READY;
+
+ // TODO: This is kind of bad to lock here, but it is needed for the current
+ // design.
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_alloc_l(name, addr, listen, flags);
+ if (!sock) {
+ return BT_STATUS_NOMEM;
+ }
+
+ sock->fixed_chan = fixed_chan;
+ sock->channel = channel;
+ sock->app_uid = app_uid;
+ sock->is_le_coc = is_le_coc;
+
+ stat = BT_STATUS_SUCCESS;
+
+ /* Setup ETM settings:
+ * mtu will be set below */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.fcr_present = true;
+ cfg.fcr = obex_l2c_fcr_opts_def;
+
+ /* "role" is never initialized in rfcomm code */
+ if (listen) {
+ stat = btSock_start_l2cap_server_l(sock);
+ } else {
+ if (fixed_chan) {
+ if (BTA_JvL2capConnectLE(sock->security, 0, NULL, channel,
+ L2CAP_DEFAULT_MTU, NULL, sock->addr.address,
+ btsock_l2cap_cbk, sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+
+ } else {
+ if (sock->is_le_coc) {
+ if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP_LE, sock->security, 0,
+ NULL, channel, L2CAP_MAX_SDU_LENGTH, &cfg,
+ sock->addr.address, btsock_l2cap_cbk,
+ sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ } else {
+ if (BTA_JvL2capConnect(BTA_JV_CONN_TYPE_L2CAP, sock->security, 0,
+ &obex_l2c_etm_opt, channel, L2CAP_MAX_SDU_LENGTH,
+ &cfg, sock->addr.address, btsock_l2cap_cbk,
+ sock->id) != BTA_JV_SUCCESS)
+ stat = BT_STATUS_FAIL;
+ }
+ }
+ }
+
+ if (stat == BT_STATUS_SUCCESS) {
+ *sock_fd = sock->app_fd;
+ /* We pass the FD to JAVA, but since it runs in another process, we need to
+ * also close
+ * it in native, either straight away, as done when accepting an incoming
+ * connection,
+ * or when doing cleanup after this socket */
+ sock->app_fd =
+ -1; /*This leaks the file descriptor. The FD should be closed in
+ JAVA but it apparently do not work */
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP,
+ SOCK_THREAD_FD_EXCEPTION, sock->id);
+ } else {
+ btsock_l2cap_free_l(sock);
+ }
+
+ return stat;
+}
+
+bt_status_t btsock_l2cap_listen(const char* name, int channel, int* sock_fd,
+ int flags, int app_uid) {
+ return btsock_l2cap_listen_or_connect(name, NULL, channel, sock_fd, flags, 1,
+ app_uid);
+}
+
+bt_status_t btsock_l2cap_connect(const bt_bdaddr_t* bd_addr, int channel,
+ int* sock_fd, int flags, int app_uid) {
+ return btsock_l2cap_listen_or_connect(NULL, bd_addr, channel, sock_fd, flags,
+ 0, app_uid);
+}
+
+/* return true if we have more to send and should wait for user readiness, false
+ * else
+ * (for example: unrecoverable error or no data)
+ */
+static bool flush_incoming_que_on_wr_signal_l(l2cap_socket* sock) {
+ uint8_t* buf;
+ uint32_t len;
+
+ while (packet_get_head_l(sock, &buf, &len)) {
+ ssize_t sent;
+ OSI_NO_INTR(sent = send(sock->our_fd, buf, len, MSG_DONTWAIT));
+ int saved_errno = errno;
+
+ if (sent == (signed)len)
+ osi_free(buf);
+ else if (sent >= 0) {
+ packet_put_head_l(sock, buf + sent, len - sent);
+ osi_free(buf);
+ if (!sent) /* special case if other end not keeping up */
+ return true;
+ } else {
+ packet_put_head_l(sock, buf, len);
+ osi_free(buf);
+ return saved_errno == EWOULDBLOCK || saved_errno == EAGAIN;
+ }
+ }
+
+ return false;
+}
+
+void btsock_l2cap_signaled(int fd, int flags, uint32_t user_id) {
+ l2cap_socket* sock;
+ char drop_it = false;
+
+ /* We use MSG_DONTWAIT when sending data to JAVA, hence it can be accepted to
+ * hold the lock. */
+ std::unique_lock<std::mutex> lock(state_lock);
+ sock = btsock_l2cap_find_by_id_l(user_id);
+ if (!sock) return;
+
+ if ((flags & SOCK_THREAD_FD_RD) && !sock->server) {
+ // app sending data
+ if (sock->connected) {
+ int size = 0;
+
+ if (!(flags & SOCK_THREAD_FD_EXCEPTION) ||
+ (ioctl(sock->our_fd, FIONREAD, &size) == 0 && size)) {
+ uint8_t* buffer = (uint8_t*)osi_malloc(L2CAP_MAX_SDU_LENGTH);
+ /* The socket is created with SOCK_SEQPACKET, hence we read one message
+ * at the time. The maximum size of a message is allocated to ensure
+ * data is not lost. This is okay to do as Android uses virtual memory,
+ * hence even if we only use a fraction of the memory it should not
+ * block for others to use the memory. As the definition of
+ * ioctl(FIONREAD) do not clearly define what value will be returned if
+ * multiple messages are written to the socket before any message is
+ * read from the socket, we could potentially risk to allocate way more
+ * memory than needed. One of the use cases for this socket is obex
+ * where multiple 64kbyte messages are typically written to the socket
+ * in a tight loop, hence we risk the ioctl will return the total amount
+ * of data in the buffer, which could be multiple 64kbyte chunks.
+ * UPDATE: As the stack cannot handle 64kbyte buffers, the size is
+ * reduced to around 8kbyte - and using malloc for buffer allocation
+ * here seems to be wrong
+ * UPDATE: Since we are responsible for freeing the buffer in the
+ * write_complete_ind, it is OK to use malloc. */
+ ssize_t count;
+ OSI_NO_INTR(count = recv(fd, buffer, L2CAP_MAX_SDU_LENGTH,
+ MSG_NOSIGNAL | MSG_DONTWAIT));
+ APPL_TRACE_DEBUG(
+ "btsock_l2cap_signaled - %d bytes received from socket", count);
+
+ if (sock->fixed_chan) {
+ if (BTA_JvL2capWriteFixed(sock->channel, (BD_ADDR*)&sock->addr,
+ PTR_TO_UINT(buffer), btsock_l2cap_cbk,
+ buffer, count, user_id) != BTA_JV_SUCCESS) {
+ // On fail, free the buffer
+ on_l2cap_write_fixed_done(buffer, count, user_id);
+ }
+ } else {
+ if (BTA_JvL2capWrite(sock->handle, PTR_TO_UINT(buffer), buffer, count,
+ user_id) != BTA_JV_SUCCESS) {
+ // On fail, free the buffer
+ on_l2cap_write_done(buffer, count, user_id);
+ }
+ }
+ }
+ } else
+ drop_it = true;
+ }
+ if (flags & SOCK_THREAD_FD_WR) {
+ // app is ready to receive more data, tell stack to enable the data flow
+ if (flush_incoming_que_on_wr_signal_l(sock) && sock->connected)
+ btsock_thread_add_fd(pth, sock->our_fd, BTSOCK_L2CAP, SOCK_THREAD_FD_WR,
+ sock->id);
+ }
+ if (drop_it || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+ int size = 0;
+ if (drop_it || ioctl(sock->our_fd, FIONREAD, &size) != 0 || size == 0)
+ btsock_l2cap_free_l(sock);
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_rfc.cc b/mtkbt/code/bt/btif/src/btif_sock_rfc.cc
new file mode 100755
index 0000000..1db39ae
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_rfc.cc
@@ -0,0 +1,929 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock_rfcomm"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <features.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_sock_util.h"
+#include "btif_uid.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "osi/include/compat.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+/* The JV interface can have only one user, hence we need to call a few
+ * L2CAP functions from this file. */
+#include "btif_sock_l2cap.h"
+
+// Maximum number of RFCOMM channels (1-30 inclusive).
+#define MAX_RFC_CHANNEL 30
+
+// Maximum number of devices we can have an RFCOMM connection with.
+#define MAX_RFC_SESSION 7
+
+typedef struct {
+ int outgoing_congest : 1;
+ int pending_sdp_request : 1;
+ int doing_sdp_request : 1;
+ int server : 1;
+ int connected : 1;
+ int closing : 1;
+} flags_t;
+
+typedef struct {
+ flags_t f;
+ uint32_t id; // Non-zero indicates a valid (in-use) slot.
+ int security;
+ int scn; // Server channel number
+ int scn_notified;
+ bt_bdaddr_t addr;
+ int is_service_uuid_valid;
+ uint8_t service_uuid[16];
+ char service_name[256];
+ int fd;
+ int app_fd; // Temporary storage for the half of the socketpair that's sent
+ // back to upper layers.
+ int app_uid; // UID of the app for which this socket was created.
+ int mtu;
+ uint8_t* packet;
+ int sdp_handle;
+ int rfc_handle;
+ int rfc_port_handle;
+ int role;
+ list_t* incoming_queue;
+} rfc_slot_t;
+
+static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL];
+static uint32_t rfc_slot_id;
+static volatile int pth = -1; // poll thread handle
+static std::recursive_mutex slot_lock;
+static uid_set_t* uid_set = NULL;
+
+static rfc_slot_t* find_free_slot(void);
+static void cleanup_rfc_slot(rfc_slot_t* rs);
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id);
+static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t rfcomm_slot_id);
+static bool send_app_scn(rfc_slot_t* rs);
+
+static bool is_init_done(void) { return pth != -1; }
+
+bt_status_t btsock_rfc_init(int poll_thread_handle, uid_set_t* set) {
+ pth = poll_thread_handle;
+ uid_set = set;
+
+ memset(rfc_slots, 0, sizeof(rfc_slots));
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
+ rfc_slots[i].scn = -1;
+ rfc_slots[i].sdp_handle = 0;
+ rfc_slots[i].fd = INVALID_FD;
+ rfc_slots[i].app_fd = INVALID_FD;
+ rfc_slots[i].incoming_queue = list_new(osi_free);
+ CHECK(rfc_slots[i].incoming_queue != NULL);
+ }
+
+ BTA_JvEnable(jv_dm_cback);
+
+ return BT_STATUS_SUCCESS;
+}
+
+void btsock_rfc_cleanup(void) {
+ pth = -1;
+ uid_set = NULL;
+
+ BTA_JvDisable();
+
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) {
+ if (rfc_slots[i].id) cleanup_rfc_slot(&rfc_slots[i]);
+ list_free(rfc_slots[i].incoming_queue);
+ rfc_slots[i].incoming_queue = NULL;
+ }
+}
+
+static rfc_slot_t* find_free_slot(void) {
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+ if (rfc_slots[i].fd == INVALID_FD) return &rfc_slots[i];
+ return NULL;
+}
+
+static rfc_slot_t* find_rfc_slot_by_id(uint32_t id) {
+ CHECK(id != 0);
+
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+ if (rfc_slots[i].id == id) return &rfc_slots[i];
+
+ LOG_ERROR(LOG_TAG, "%s unable to find RFCOMM slot id: %d", __func__, id);
+ return NULL;
+}
+
+static rfc_slot_t* find_rfc_slot_by_pending_sdp(void) {
+ uint32_t min_id = UINT32_MAX;
+ int slot = -1;
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+ if (rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request &&
+ rfc_slots[i].id < min_id) {
+ min_id = rfc_slots[i].id;
+ slot = i;
+ }
+
+ return (slot == -1) ? NULL : &rfc_slots[slot];
+}
+
+static bool is_requesting_sdp(void) {
+ for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i)
+ if (rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request) return true;
+ return false;
+}
+
+static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t* addr, const char* name,
+ const uint8_t* uuid, int channel, int flags,
+ bool server) {
+ int security = 0;
+ if (flags & BTSOCK_FLAG_ENCRYPT)
+ security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT;
+ if (flags & BTSOCK_FLAG_AUTH)
+ security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE;
+ if (flags & BTSOCK_FLAG_AUTH_MITM)
+ security |= server ? BTM_SEC_IN_MITM : BTM_SEC_OUT_MITM;
+ if (flags & BTSOCK_FLAG_AUTH_16_DIGIT)
+ security |= BTM_SEC_IN_MIN_16_DIGIT_PIN;
+
+ rfc_slot_t* slot = find_free_slot();
+ if (!slot) {
+ LOG_ERROR(LOG_TAG, "%s unable to find free RFCOMM slot.", __func__);
+ return NULL;
+ }
+
+ int fds[2] = {INVALID_FD, INVALID_FD};
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) {
+ LOG_ERROR(LOG_TAG, "%s error creating socketpair: %s", __func__,
+ strerror(errno));
+ return NULL;
+ }
+
+ // Increment slot id and make sure we don't use id=0.
+ if (++rfc_slot_id == 0) rfc_slot_id = 1;
+
+ slot->fd = fds[0];
+ slot->app_fd = fds[1];
+ slot->security = security;
+ slot->scn = channel;
+ slot->app_uid = -1;
+
+ if (!is_uuid_empty(uuid)) {
+ memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid));
+ slot->is_service_uuid_valid = true;
+ } else {
+ memset(slot->service_uuid, 0, sizeof(slot->service_uuid));
+ slot->is_service_uuid_valid = false;
+ }
+ if (name && *name) {
+ strlcpy(slot->service_name, name, sizeof(slot->service_name));
+ } else {
+ memset(slot->service_name, 0, sizeof(slot->service_name));
+ }
+ if (addr) slot->addr = *addr;
+
+ slot->id = rfc_slot_id;
+ slot->f.server = server;
+
+ return slot;
+}
+
+static rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs,
+ const bt_bdaddr_t* addr,
+ int open_handle,
+ int new_listen_handle) {
+ rfc_slot_t* accept_rs = alloc_rfc_slot(
+ addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, false);
+ if (!accept_rs) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+ return NULL;
+ }
+
+ accept_rs->f.server = false;
+ accept_rs->f.connected = true;
+ accept_rs->security = srv_rs->security;
+ accept_rs->mtu = srv_rs->mtu;
+ accept_rs->role = srv_rs->role;
+ accept_rs->rfc_handle = open_handle;
+ accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle);
+ accept_rs->app_uid = srv_rs->app_uid;
+
+ srv_rs->rfc_handle = new_listen_handle;
+ srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle);
+
+ CHECK(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle);
+
+ // now swap the slot id
+ uint32_t new_listen_id = accept_rs->id;
+ accept_rs->id = srv_rs->id;
+ srv_rs->id = new_listen_id;
+
+ return accept_rs;
+}
+
+bt_status_t btsock_rfc_listen(const char* service_name,
+ const uint8_t* service_uuid, int channel,
+ int* sock_fd, int flags, int app_uid) {
+ CHECK(sock_fd != NULL);
+ CHECK((service_uuid != NULL) ||
+ (channel >= 1 && channel <= MAX_RFC_CHANNEL) ||
+ ((flags & BTSOCK_FLAG_NO_SDP) != 0));
+
+ *sock_fd = INVALID_FD;
+
+ // TODO(sharvil): not sure that this check makes sense; seems like a logic
+ // error to call
+ // functions on RFCOMM sockets before initializing the module. Probably should
+ // be an assert.
+ if (!is_init_done()) return BT_STATUS_NOT_READY;
+
+ if ((flags & BTSOCK_FLAG_NO_SDP) == 0) {
+ if (is_uuid_empty(service_uuid)) {
+ APPL_TRACE_DEBUG(
+ "BTA_JvGetChannelId: service_uuid not set AND "
+ "BTSOCK_FLAG_NO_SDP is not set - changing to SPP");
+ service_uuid =
+ UUID_SPP; // Use serial port profile to listen to specified channel
+ } else {
+ // Check the service_uuid. overwrite the channel # if reserved
+ int reserved_channel = get_reserved_rfc_channel(service_uuid);
+ if (reserved_channel > 0) {
+ channel = reserved_channel;
+ }
+ }
+ }
+
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+ rfc_slot_t* slot =
+ alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true);
+ if (!slot) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+ return BT_STATUS_FAIL;
+ }
+ APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d",
+ service_name, channel);
+ BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, slot->id, channel);
+ *sock_fd = slot->app_fd; // Transfer ownership of fd to caller.
+ /*TODO:
+ * We are leaking one of the app_fd's - either the listen socket, or the
+ connection socket.
+ * WE need to close this in native, as the FD might belong to another process
+ - This is the server socket FD
+ - For accepted connections, we close the FD after passing it to JAVA.
+ - Try to simply remove the = -1 to free the FD at rs cleanup.*/
+ // close(rs->app_fd);
+ slot->app_fd = INVALID_FD; // Drop our reference to the fd.
+ slot->app_uid = app_uid;
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
+ slot->id);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_rfc_connect(const bt_bdaddr_t* bd_addr,
+ const uint8_t* service_uuid, int channel,
+ int* sock_fd, int flags, int app_uid) {
+ CHECK(sock_fd != NULL);
+ CHECK(service_uuid != NULL || (channel >= 1 && channel <= MAX_RFC_CHANNEL));
+
+ *sock_fd = INVALID_FD;
+
+ // TODO(sharvil): not sure that this check makes sense; seems like a logic
+ // error to call
+ // functions on RFCOMM sockets before initializing the module. Probably should
+ // be an assert.
+ if (!is_init_done()) return BT_STATUS_NOT_READY;
+
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+ rfc_slot_t* slot =
+ alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false);
+ if (!slot) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_uuid_empty(service_uuid)) {
+ tBTA_JV_STATUS ret =
+ BTA_JvRfcommConnect(slot->security, slot->role, slot->scn,
+ slot->addr.address, rfcomm_cback, slot->id);
+ if (ret != BTA_JV_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s unable to initiate RFCOMM connection: %d",
+ __func__, ret);
+ cleanup_rfc_slot(slot);
+ return BT_STATUS_FAIL;
+ }
+
+ if (!send_app_scn(slot)) {
+ LOG_ERROR(LOG_TAG, "%s unable to send channel number.", __func__);
+ cleanup_rfc_slot(slot);
+ return BT_STATUS_FAIL;
+ }
+ } else {
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128));
+
+ if (!is_requesting_sdp()) {
+ BTA_JvStartDiscovery((uint8_t*)bd_addr->address, 1, &sdp_uuid, slot->id);
+ slot->f.pending_sdp_request = false;
+ slot->f.doing_sdp_request = true;
+ } else {
+ slot->f.pending_sdp_request = true;
+ slot->f.doing_sdp_request = false;
+ }
+ }
+
+ *sock_fd = slot->app_fd; // Transfer ownership of fd to caller.
+ slot->app_fd = INVALID_FD; // Drop our reference to the fd.
+ slot->app_uid = app_uid;
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+ slot->id);
+
+ return BT_STATUS_SUCCESS;
+}
+
+static int create_server_sdp_record(rfc_slot_t* slot) {
+ if (slot->scn == 0) {
+ return false;
+ }
+ slot->sdp_handle =
+ add_rfc_sdp_rec(slot->service_name, slot->service_uuid, slot->scn);
+ return (slot->sdp_handle > 0);
+}
+
+static void free_rfc_slot_scn(rfc_slot_t* slot) {
+ if (slot->scn <= 0) return;
+
+ if (slot->f.server && !slot->f.closing && slot->rfc_handle) {
+ BTA_JvRfcommStopServer(slot->rfc_handle, slot->id);
+ slot->rfc_handle = 0;
+ }
+
+ if (slot->f.server) BTM_FreeSCN(slot->scn);
+ slot->scn = 0;
+}
+
+static void cleanup_rfc_slot(rfc_slot_t* slot) {
+ if (slot->fd != INVALID_FD) {
+ shutdown(slot->fd, SHUT_RDWR);
+ close(slot->fd);
+ slot->fd = INVALID_FD;
+ }
+
+ if (slot->app_fd != INVALID_FD) {
+ close(slot->app_fd);
+ slot->app_fd = INVALID_FD;
+ }
+
+ if (slot->sdp_handle > 0) {
+ del_rfc_sdp_rec(slot->sdp_handle);
+ slot->sdp_handle = 0;
+ }
+
+ if (slot->rfc_handle && !slot->f.closing && !slot->f.server) {
+ BTA_JvRfcommClose(slot->rfc_handle, slot->id);
+ slot->rfc_handle = 0;
+ }
+
+ free_rfc_slot_scn(slot);
+ list_clear(slot->incoming_queue);
+
+ slot->rfc_port_handle = 0;
+ memset(&slot->f, 0, sizeof(slot->f));
+ slot->id = 0;
+ slot->scn_notified = false;
+}
+
+static bool send_app_scn(rfc_slot_t* slot) {
+ if (slot->scn_notified == true) {
+ // already send, just return success.
+ return true;
+ }
+ slot->scn_notified = true;
+ return sock_send_all(slot->fd, (const uint8_t*)&slot->scn,
+ sizeof(slot->scn)) == sizeof(slot->scn);
+}
+
+static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr,
+ int channel, int status, int send_fd) {
+ sock_connect_signal_t cs;
+ cs.size = sizeof(cs);
+ cs.bd_addr = *addr;
+ cs.channel = channel;
+ cs.status = status;
+ cs.max_rx_packet_size = 0; // not used for RFCOMM
+ cs.max_tx_packet_size = 0; // not used for RFCOMM
+ if (send_fd == INVALID_FD)
+ return sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs);
+
+ return sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) ==
+ sizeof(cs);
+}
+
+static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT* p_init, uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return;
+
+ if (p_init->status == BTA_JV_SUCCESS) {
+ slot->rfc_handle = p_init->handle;
+ } else {
+ cleanup_rfc_slot(slot);
+ }
+}
+
+static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START* p_start,
+ uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return;
+
+ if (p_start->status == BTA_JV_SUCCESS) {
+ slot->rfc_handle = p_start->handle;
+ } else {
+ cleanup_rfc_slot(slot);
+ }
+}
+
+static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN* p_open,
+ uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* accept_rs;
+ rfc_slot_t* srv_rs = find_rfc_slot_by_id(id);
+ if (!srv_rs) return 0;
+
+ accept_rs =
+ create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda,
+ p_open->handle, p_open->new_listen_handle);
+ if (!accept_rs) return 0;
+
+ // Start monitoring the socket.
+ btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION,
+ srv_rs->id);
+ btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+ accept_rs->id);
+ send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0,
+ accept_rs->app_fd);
+ accept_rs->app_fd =
+ INVALID_FD; // Ownership of the application fd has been transferred.
+ return srv_rs->id;
+}
+
+static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN* p_open, uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return;
+
+ if (p_open->status != BTA_JV_SUCCESS) {
+ cleanup_rfc_slot(slot);
+ return;
+ }
+
+ slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle);
+ memcpy(slot->addr.address, p_open->rem_bda, 6);
+
+ if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) {
+ slot->f.connected = true;
+ } else {
+ LOG_ERROR(LOG_TAG, "%s unable to send connect completion signal to caller.",
+ __func__);
+ }
+}
+
+static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE* p_close,
+ uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+ // rfc_handle already closed when receiving rfcomm close event from stack.
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (slot) cleanup_rfc_slot(slot);
+}
+
+static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE* p, uint32_t id) {
+ if (p->status != BTA_JV_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s error writing to RFCOMM socket with slot %u.",
+ __func__, p->req_id);
+ return;
+ }
+
+ int app_uid = -1;
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (slot) {
+ app_uid = slot->app_uid;
+ if (!slot->f.outgoing_congest) {
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+ slot->id);
+ }
+ }
+
+ uid_set_add_tx(uid_set, app_uid, p->len);
+}
+
+static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG* p, uint32_t id) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (slot) {
+ slot->f.outgoing_congest = p->cong ? 1 : 0;
+ if (!slot->f.outgoing_congest)
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD,
+ slot->id);
+ }
+}
+
+static uint32_t rfcomm_cback(tBTA_JV_EVT event, tBTA_JV* p_data,
+ uint32_t rfcomm_slot_id) {
+ uint32_t id = 0;
+
+ switch (event) {
+ case BTA_JV_RFCOMM_START_EVT:
+ on_srv_rfc_listen_started(&p_data->rfc_start, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_CL_INIT_EVT:
+ on_cl_rfc_init(&p_data->rfc_cl_init, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_OPEN_EVT:
+ BTA_JvSetPmProfile(p_data->rfc_open.handle, BTA_JV_PM_ID_1,
+ BTA_JV_CONN_OPEN);
+ on_cli_rfc_connect(&p_data->rfc_open, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_SRV_OPEN_EVT:
+ BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL,
+ BTA_JV_CONN_OPEN);
+ id = on_srv_rfc_connect(&p_data->rfc_srv_open, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_CLOSE_EVT:
+ APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: rfcomm_slot_id:%d",
+ rfcomm_slot_id);
+ on_rfc_close(&p_data->rfc_close, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_WRITE_EVT:
+ on_rfc_write_done(&p_data->rfc_write, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_CONG_EVT:
+ on_rfc_outgoing_congest(&p_data->rfc_cong, rfcomm_slot_id);
+ break;
+
+ case BTA_JV_RFCOMM_DATA_IND_EVT:
+ // Unused.
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s unhandled event %d, slot id: %zi", __func__, event,
+ rfcomm_slot_id);
+ break;
+ }
+ return id;
+}
+
+static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) {
+ switch (event) {
+ case BTA_JV_GET_SCN_EVT: {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* rs = find_rfc_slot_by_id(id);
+ int new_scn = p_data->scn;
+
+ if (rs && (new_scn != 0)) {
+ rs->scn = new_scn;
+ /* BTA_JvCreateRecordByUser will only create a record if a UUID is
+ * specified,
+ * else it just allocate a RFC channel and start the RFCOMM thread -
+ * needed
+ * for the java
+ * layer to get a RFCOMM channel.
+ * If uuid is null the create_sdp_record() will be called from Java when
+ * it
+ * has received the RFCOMM and L2CAP channel numbers through the
+ * sockets.*/
+
+ // Send channel ID to java layer
+ if (!send_app_scn(rs)) {
+ // closed
+ APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
+ cleanup_rfc_slot(rs);
+ } else {
+ if (rs->is_service_uuid_valid == true) {
+ // We already have data for SDP record, create it (RFC-only
+ // profiles)
+ BTA_JvCreateRecordByUser(rs->id);
+ } else {
+ APPL_TRACE_DEBUG(
+ "is_service_uuid_valid==false - don't set SDP-record, "
+ "just start the RFCOMM server",
+ rs->id);
+ // now start the rfcomm server after sdp & channel # assigned
+ BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn,
+ MAX_RFC_SESSION, rfcomm_cback, rs->id);
+ }
+ }
+ } else if (rs) {
+ APPL_TRACE_ERROR(
+ "jv_dm_cback: Error: allocate channel %d, slot found:%p", rs->scn,
+ rs);
+ cleanup_rfc_slot(rs);
+ }
+ break;
+ }
+ case BTA_JV_GET_PSM_EVT: {
+ APPL_TRACE_DEBUG("Received PSM: 0x%04x", p_data->psm);
+ on_l2cap_psm_assigned(id, p_data->psm);
+ break;
+ }
+ case BTA_JV_CREATE_RECORD_EVT: {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+
+ if (slot && create_server_sdp_record(slot)) {
+ // Start the rfcomm server after sdp & channel # assigned.
+ BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn,
+ MAX_RFC_SESSION, rfcomm_cback, slot->id);
+ } else if (slot) {
+ APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p",
+ slot);
+ cleanup_rfc_slot(slot);
+ }
+ break;
+ }
+
+ case BTA_JV_DISCOVERY_COMP_EVT: {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) {
+ if (slot && slot->f.doing_sdp_request) {
+ // Establish the connection if we successfully looked up a channel
+ // number to connect to.
+ if (BTA_JvRfcommConnect(slot->security, slot->role,
+ p_data->disc_comp.scn, slot->addr.address,
+ rfcomm_cback, slot->id) == BTA_JV_SUCCESS) {
+ slot->scn = p_data->disc_comp.scn;
+ slot->f.doing_sdp_request = false;
+ if (!send_app_scn(slot)) cleanup_rfc_slot(slot);
+ } else {
+ cleanup_rfc_slot(slot);
+ }
+ } else if (slot) {
+ // TODO(sharvil): this is really a logic error and we should probably
+ // assert.
+ LOG_ERROR(LOG_TAG,
+ "%s SDP response returned but RFCOMM slot %d did not "
+ "request SDP record.",
+ __func__, id);
+ }
+ } else if (slot) {
+ cleanup_rfc_slot(slot);
+ }
+
+ // Find the next slot that needs to perform an SDP request and service it.
+ slot = find_rfc_slot_by_pending_sdp();
+ if (slot) {
+ tSDP_UUID sdp_uuid;
+ sdp_uuid.len = 16;
+ memcpy(sdp_uuid.uu.uuid128, slot->service_uuid,
+ sizeof(sdp_uuid.uu.uuid128));
+ BTA_JvStartDiscovery((uint8_t*)slot->addr.address, 1, &sdp_uuid,
+ slot->id);
+ slot->f.pending_sdp_request = false;
+ slot->f.doing_sdp_request = true;
+ }
+ break;
+ }
+
+ default:
+ APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id);
+ break;
+ }
+}
+
+typedef enum {
+ SENT_FAILED,
+ SENT_NONE,
+ SENT_PARTIAL,
+ SENT_ALL,
+} sent_status_t;
+
+static sent_status_t send_data_to_app(int fd, BT_HDR* p_buf) {
+ if (p_buf->len == 0) return SENT_ALL;
+
+ ssize_t sent;
+ OSI_NO_INTR(
+ sent = send(fd, p_buf->data + p_buf->offset, p_buf->len, MSG_DONTWAIT));
+
+ if (sent == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) return SENT_NONE;
+ LOG_ERROR(LOG_TAG, "%s error writing RFCOMM data back to app: %s", __func__,
+ strerror(errno));
+ return SENT_FAILED;
+ }
+
+ if (sent == 0) return SENT_FAILED;
+
+ if (sent == p_buf->len) return SENT_ALL;
+
+ p_buf->offset += sent;
+ p_buf->len -= sent;
+ return SENT_PARTIAL;
+}
+
+static bool flush_incoming_que_on_wr_signal(rfc_slot_t* slot) {
+ while (!list_is_empty(slot->incoming_queue)) {
+ BT_HDR* p_buf = (BT_HDR*)list_front(slot->incoming_queue);
+ switch (send_data_to_app(slot->fd, p_buf)) {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ // monitor the fd to get callback when app is ready to receive data
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR,
+ slot->id);
+ return true;
+
+ case SENT_ALL:
+ list_remove(slot->incoming_queue, p_buf);
+ break;
+
+ case SENT_FAILED:
+ list_remove(slot->incoming_queue, p_buf);
+ return false;
+ }
+ }
+
+ // app is ready to receive data, tell stack to start the data flow
+ // fix me: need a jv flow control api to serialize the call in stack
+ APPL_TRACE_DEBUG(
+ "enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d",
+ slot->rfc_handle, slot->rfc_port_handle, slot->id);
+ PORT_FlowControl_MaxCredit(slot->rfc_port_handle, true);
+ return true;
+}
+
+void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) {
+ bool need_close = false;
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(user_id);
+ if (!slot) return;
+
+ // Data available from app, tell stack we have outgoing data.
+ if (flags & SOCK_THREAD_FD_RD && !slot->f.server) {
+ if (slot->f.connected) {
+ // Make sure there's data pending in case the peer closed the socket.
+ int size = 0;
+ if (!(flags & SOCK_THREAD_FD_EXCEPTION) ||
+ (ioctl(slot->fd, FIONREAD, &size) == 0 && size)) {
+ BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
+ }
+ } else {
+ LOG_ERROR(LOG_TAG,
+ "%s socket signaled for read while disconnected, slot: %d, "
+ "channel: %d",
+ __func__, slot->id, slot->scn);
+ need_close = true;
+ }
+ }
+
+ if (flags & SOCK_THREAD_FD_WR) {
+ // App is ready to receive more data, tell stack to enable data flow.
+ if (!slot->f.connected || !flush_incoming_que_on_wr_signal(slot)) {
+ LOG_ERROR(LOG_TAG,
+ "%s socket signaled for write while disconnected (or write "
+ "failure), slot: %d, channel: %d",
+ __func__, slot->id, slot->scn);
+ need_close = true;
+ }
+ }
+
+ if (need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) {
+ // Clean up if there's no data pending.
+ int size = 0;
+ if (need_close || ioctl(slot->fd, FIONREAD, &size) != 0 || !size)
+ cleanup_rfc_slot(slot);
+ }
+}
+
+int bta_co_rfc_data_incoming(uint32_t id, BT_HDR* p_buf) {
+ int app_uid = -1;
+ uint64_t bytes_rx = 0;
+ int ret = 0;
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return 0;
+
+ app_uid = slot->app_uid;
+ bytes_rx = p_buf->len;
+
+ if (list_is_empty(slot->incoming_queue)) {
+ switch (send_data_to_app(slot->fd, p_buf)) {
+ case SENT_NONE:
+ case SENT_PARTIAL:
+ list_append(slot->incoming_queue, p_buf);
+ btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR,
+ slot->id);
+ break;
+
+ case SENT_ALL:
+ osi_free(p_buf);
+ ret = 1; // Enable data flow.
+ break;
+
+ case SENT_FAILED:
+ osi_free(p_buf);
+ cleanup_rfc_slot(slot);
+ break;
+ }
+ } else {
+ list_append(slot->incoming_queue, p_buf);
+ }
+
+ uid_set_add_rx(uid_set, app_uid, bytes_rx);
+
+ return ret; // Return 0 to disable data flow.
+}
+
+int bta_co_rfc_data_outgoing_size(uint32_t id, int* size) {
+ *size = 0;
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return false;
+
+ if (ioctl(slot->fd, FIONREAD, size) != 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to determine bytes remaining to be read on fd %d: %s",
+ __func__, slot->fd, strerror(errno));
+ cleanup_rfc_slot(slot);
+ return false;
+ }
+
+ return true;
+}
+
+int bta_co_rfc_data_outgoing(uint32_t id, uint8_t* buf, uint16_t size) {
+ std::unique_lock<std::recursive_mutex> lock(slot_lock);
+ rfc_slot_t* slot = find_rfc_slot_by_id(id);
+ if (!slot) return false;
+
+ ssize_t received;
+ OSI_NO_INTR(received = recv(slot->fd, buf, size, 0));
+
+ if (received != size) {
+ LOG_ERROR(LOG_TAG, "%s error receiving RFCOMM data from app: %s", __func__,
+ strerror(errno));
+ cleanup_rfc_slot(slot);
+ return false;
+ }
+
+ return true;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_sco.cc b/mtkbt/code/bt/btif/src/btif_sock_sco.cc
new file mode 100755
index 0000000..60d948b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_sco.cc
@@ -0,0 +1,331 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock_sco"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "btif_common.h"
+#include "device/include/esco_parameters.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket.h"
+#include "osi/include/thread.h"
+
+// This module provides a socket abstraction for SCO connections to a higher
+// layer. It returns file descriptors representing two types of sockets:
+// listening (server) and connected (client) sockets. No SCO data is
+// transferred across these sockets; instead, they are used to manage SCO
+// connection lifecycles while the data routing takes place over the I2S bus.
+//
+// This code bridges the gap between the BTM layer, which implements SCO
+// connections, and the Android HAL. It adapts the BTM representation of SCO
+// connections (integer handles) to a file descriptor representation usable by
+// Android's LocalSocket implementation.
+//
+// Sample flow for an incoming connection:
+// btsock_sco_listen() - listen for incoming connections
+// connection_request_cb() - incoming connection request from remote host
+// connect_completed_cb() - connection successfully established
+// socket_read_ready_cb() - local host closed SCO socket
+// disconnect_completed_cb() - connection terminated
+
+typedef struct {
+ uint16_t sco_handle;
+ socket_t* socket;
+ bool connect_completed;
+} sco_socket_t;
+
+static sco_socket_t* sco_socket_establish_locked(bool is_listening,
+ const bt_bdaddr_t* bd_addr,
+ int* sock_fd);
+static sco_socket_t* sco_socket_new(void);
+static void sco_socket_free_locked(sco_socket_t* socket);
+static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle);
+static void connection_request_cb(tBTM_ESCO_EVT event,
+ tBTM_ESCO_EVT_DATA* data);
+static void connect_completed_cb(uint16_t sco_handle);
+static void disconnect_completed_cb(uint16_t sco_handle);
+static void socket_read_ready_cb(socket_t* socket, void* context);
+
+// |sco_lock| protects all of the static variables below and
+// calls into the BTM layer.
+static std::mutex sco_lock;
+static list_t* sco_sockets; // Owns a collection of sco_socket_t objects.
+static sco_socket_t* listen_sco_socket; // Not owned, do not free.
+static thread_t* thread; // Not owned, do not free.
+
+bt_status_t btsock_sco_init(thread_t* thread_) {
+ CHECK(thread_ != NULL);
+
+ sco_sockets = list_new((list_free_cb)sco_socket_free_locked);
+ if (!sco_sockets) return BT_STATUS_FAIL;
+
+ thread = thread_;
+ enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ BTM_SetEScoMode(&params);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_cleanup(void) {
+ list_free(sco_sockets);
+ sco_sockets = NULL;
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_listen(int* sock_fd, UNUSED_ATTR int flags) {
+ CHECK(sock_fd != NULL);
+
+ std::unique_lock<std::mutex> lock(sco_lock);
+
+ sco_socket_t* sco_socket = sco_socket_establish_locked(true, NULL, sock_fd);
+ if (!sco_socket) return BT_STATUS_FAIL;
+
+ BTM_RegForEScoEvts(sco_socket->sco_handle, connection_request_cb);
+ listen_sco_socket = sco_socket;
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btsock_sco_connect(const bt_bdaddr_t* bd_addr, int* sock_fd,
+ UNUSED_ATTR int flags) {
+ CHECK(bd_addr != NULL);
+ CHECK(sock_fd != NULL);
+
+ std::unique_lock<std::mutex> lock(sco_lock);
+ sco_socket_t* sco_socket =
+ sco_socket_establish_locked(false, bd_addr, sock_fd);
+
+ return (sco_socket != NULL) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+// Must be called with |lock| held.
+static sco_socket_t* sco_socket_establish_locked(bool is_listening,
+ const bt_bdaddr_t* bd_addr,
+ int* sock_fd) {
+ int pair[2] = {INVALID_FD, INVALID_FD};
+ sco_socket_t* sco_socket = NULL;
+ socket_t* socket = NULL;
+ tBTM_STATUS status;
+ enh_esco_params_t params;
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate socket pair: %s", __func__,
+ strerror(errno));
+ goto error;
+ }
+
+ sco_socket = sco_socket_new();
+ if (!sco_socket) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate new SCO socket.", __func__);
+ goto error;
+ }
+
+ params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ status = BTM_CreateSco((uint8_t*)bd_addr, !is_listening, params.packet_types,
+ &sco_socket->sco_handle, connect_completed_cb,
+ disconnect_completed_cb);
+ if (status != BTM_CMD_STARTED) {
+ LOG_ERROR(LOG_TAG, "%s unable to create SCO socket: %d", __func__, status);
+ goto error;
+ }
+
+ socket = socket_new_from_fd(pair[1]);
+ if (!socket) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate socket from file descriptor %d.",
+ __func__, pair[1]);
+ goto error;
+ }
+
+ *sock_fd = pair[0]; // Transfer ownership of one end to caller.
+ sco_socket->socket = socket; // Hang on to the other end.
+ list_append(sco_sockets, sco_socket);
+
+ socket_register(socket, thread_get_reactor(thread), sco_socket,
+ socket_read_ready_cb, NULL);
+ return sco_socket;
+
+error:;
+ if (pair[0] != INVALID_FD) close(pair[0]);
+ if (pair[1] != INVALID_FD) close(pair[1]);
+
+ sco_socket_free_locked(sco_socket);
+ return NULL;
+}
+
+static sco_socket_t* sco_socket_new(void) {
+ sco_socket_t* sco_socket = (sco_socket_t*)osi_calloc(sizeof(sco_socket_t));
+ sco_socket->sco_handle = BTM_INVALID_SCO_INDEX;
+ return sco_socket;
+}
+
+// Must be called with |lock| held except during teardown when we know the
+// socket thread
+// is no longer alive.
+static void sco_socket_free_locked(sco_socket_t* sco_socket) {
+ if (!sco_socket) return;
+
+ if (sco_socket->sco_handle != BTM_INVALID_SCO_INDEX)
+ BTM_RemoveSco(sco_socket->sco_handle);
+ socket_free(sco_socket->socket);
+ osi_free(sco_socket);
+}
+
+// Must be called with |lock| held.
+static sco_socket_t* sco_socket_find_locked(uint16_t sco_handle) {
+ for (const list_node_t* node = list_begin(sco_sockets);
+ node != list_end(sco_sockets); node = list_next(node)) {
+ sco_socket_t* sco_socket = (sco_socket_t*)list_node(node);
+ if (sco_socket->sco_handle == sco_handle) return sco_socket;
+ }
+ return NULL;
+}
+
+static void connection_request_cb(tBTM_ESCO_EVT event,
+ tBTM_ESCO_EVT_DATA* data) {
+ CHECK(data != NULL);
+
+ // Don't care about change of link parameters, only connection requests.
+ if (event != BTM_ESCO_CONN_REQ_EVT) return;
+
+ std::unique_lock<std::mutex> lock(sco_lock);
+
+ const tBTM_ESCO_CONN_REQ_EVT_DATA* conn_data = &data->conn_evt;
+ sco_socket_t* sco_socket = sco_socket_find_locked(conn_data->sco_inx);
+ int client_fd = INVALID_FD;
+
+ uint16_t temp;
+ sco_socket_t* new_sco_socket;
+
+ if (!sco_socket) {
+ LOG_ERROR(LOG_TAG, "%s unable to find sco_socket for handle: %hu", __func__,
+ conn_data->sco_inx);
+ goto error;
+ }
+
+ if (sco_socket != listen_sco_socket) {
+ LOG_ERROR(
+ LOG_TAG,
+ "%s received connection request on non-listening socket handle: %hu",
+ __func__, conn_data->sco_inx);
+ goto error;
+ }
+
+ new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd);
+ if (!new_sco_socket) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate new sco_socket.", __func__);
+ goto error;
+ }
+
+ // Swap socket->sco_handle and new_socket->sco_handle
+ temp = sco_socket->sco_handle;
+ sco_socket->sco_handle = new_sco_socket->sco_handle;
+ new_sco_socket->sco_handle = temp;
+
+ sock_connect_signal_t connect_signal;
+ connect_signal.size = sizeof(connect_signal);
+ memcpy(&connect_signal.bd_addr, conn_data->bd_addr, sizeof(bt_bdaddr_t));
+ connect_signal.channel = 0;
+ connect_signal.status = 0;
+
+ if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal,
+ sizeof(connect_signal),
+ client_fd) != sizeof(connect_signal)) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to send new file descriptor to listening socket.",
+ __func__);
+ goto error;
+ }
+
+ BTM_RegForEScoEvts(listen_sco_socket->sco_handle, connection_request_cb);
+ BTM_EScoConnRsp(conn_data->sco_inx, HCI_SUCCESS, NULL);
+
+ return;
+
+error:;
+ if (client_fd != INVALID_FD) close(client_fd);
+ BTM_EScoConnRsp(conn_data->sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+}
+
+static void connect_completed_cb(uint16_t sco_handle) {
+ std::unique_lock<std::mutex> lock(sco_lock);
+
+ sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
+ if (!sco_socket) {
+ LOG_ERROR(LOG_TAG, "%s SCO socket not found on connect for handle: %hu",
+ __func__, sco_handle);
+ return;
+ }
+
+ // If sco_socket->socket was closed, we should tear down because there is no
+ // app-level
+ // interest in the SCO socket.
+ if (!sco_socket->socket) {
+ BTM_RemoveSco(sco_socket->sco_handle);
+ list_remove(sco_sockets, sco_socket);
+ return;
+ }
+
+ sco_socket->connect_completed = true;
+}
+
+static void disconnect_completed_cb(uint16_t sco_handle) {
+ std::unique_lock<std::mutex> lock(sco_lock);
+
+ sco_socket_t* sco_socket = sco_socket_find_locked(sco_handle);
+ if (!sco_socket) {
+ LOG_ERROR(LOG_TAG, "%s SCO socket not found on disconnect for handle: %hu",
+ __func__, sco_handle);
+ return;
+ }
+
+ list_remove(sco_sockets, sco_socket);
+}
+
+static void socket_read_ready_cb(UNUSED_ATTR socket_t* socket, void* context) {
+ std::unique_lock<std::mutex> lock(sco_lock);
+
+ sco_socket_t* sco_socket = (sco_socket_t*)context;
+ socket_free(sco_socket->socket);
+ sco_socket->socket = NULL;
+
+ // Defer the underlying disconnect until the connection completes
+ // since the BTM code doesn't behave correctly when a disconnect
+ // request is issued while a connect is in progress. The fact that
+ // sco_socket->socket == NULL indicates to the connect callback
+ // routine that the socket is no longer desired and should be torn
+ // down.
+ if (sco_socket->connect_completed || sco_socket == listen_sco_socket) {
+ if (BTM_RemoveSco(sco_socket->sco_handle) == BTM_SUCCESS)
+ list_remove(sco_sockets, sco_socket);
+ if (sco_socket == listen_sco_socket) listen_sco_socket = NULL;
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_sdp.cc b/mtkbt/code/bt/btif/src/btif_sock_sdp.cc
new file mode 100755
index 0000000..21b2c0b
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_sdp.cc
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock_sdp"
+
+#include "btif_sock_sdp.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "../bta/pb/bta_pbs_int.h"
+#include "../include/bta_op_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "btif_common.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "sdp_api.h"
+#include "utl.h"
+
+// This module provides an abstraction on top of the lower-level SDP database
+// code for registration and discovery of various bluetooth sockets.
+//
+// This code also provides for on-demand registration of "pre-registered"
+// services as a backwards compatibility function to third-party applications
+// expecting a bluez stack.
+
+// Realm Character Set -- 0 is ASCII
+#define BTA_PBS_REALM_CHARSET 0
+
+// Specifies whether or not client's user id is required during obex
+// authentication
+#define BTA_PBS_USERID_REQ FALSE
+
+static const tBTA_PBS_CFG bta_pbs_cfg = {
+ BTA_PBS_REALM_CHARSET, // realm_charset: Server only
+ BTA_PBS_USERID_REQ, // userid_req: Server only
+ (BTA_PBS_SUPF_DOWNLOAD | BTA_PBS_SURF_BROWSE), // supported_features
+ BTA_PBS_REPOSIT_LOCAL, // supported_repositories
+};
+
+// object format lookup table
+#define OBEX_PUSH_NUM_FORMATS 7
+
+static const tBTA_OP_FMT bta_ops_obj_fmt[OBEX_PUSH_NUM_FORMATS] = {
+ BTA_OP_VCARD21_FMT, BTA_OP_VCARD30_FMT, BTA_OP_VCAL_FMT, BTA_OP_ICAL_FMT,
+ BTA_OP_VNOTE_FMT, BTA_OP_VMSG_FMT, BTA_OP_OTHER_FMT};
+
+// TODO(jtgans): Figure out if we actually need this define. This is ifndef
+// defined in bt_target.h, but nowhere else, so right now, unless something
+// overrides this before bt_target.h sets it, it will always be bt_target.h's
+// version.
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS \
+ (BTA_OP_VCARD21_MASK | BTA_OP_VCARD30_MASK | BTA_OP_VCAL_MASK | \
+ BTA_OP_ICAL_MASK | BTA_OP_VNOTE_MASK | BTA_OP_VMSG_MASK | BTA_OP_ANY_MASK)
+#endif
+
+#define RESERVED_SCN_PBS 19
+#define RESERVED_SCN_OPS 12
+
+#define UUID_MAX_LENGTH 16
+#define UUID_MATCHES(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH)
+
+// Adds a protocol list and service name (if provided) to an SDP record given by
+// |sdp_handle|, and marks it as browseable. This is a shortcut for defining a
+// set of protocols that includes L2CAP, RFCOMM, and optionally OBEX. If
+// |with_obex| is |true|, then an additional OBEX protocol UUID will be included
+// at the end of the protocol list.
+//
+// Returns true if successful, otherwise false.
+static bool create_base_record(const uint32_t sdp_handle, const char* name,
+ const uint16_t channel, const bool with_obex) {
+ APPL_TRACE_DEBUG("create_base_record: scn: %d, name: %s, with_obex: %d",
+ channel, name, with_obex);
+
+ // Setup the protocol list and add it.
+ tSDP_PROTOCOL_ELEM proto_list[SDP_MAX_LIST_ELEMS];
+ int num_proto_elements = with_obex ? 3 : 2;
+
+ memset(proto_list, 0, num_proto_elements * sizeof(tSDP_PROTOCOL_ELEM));
+
+ proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_list[0].num_params = 0;
+ proto_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_list[1].num_params = 1;
+ proto_list[1].params[0] = channel;
+
+ if (with_obex == true) {
+ proto_list[2].protocol_uuid = UUID_PROTOCOL_OBEX;
+ proto_list[2].num_params = 0;
+ }
+
+ // Mark the service as browseable.
+ uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+
+ const char* stage = "protocol_list";
+ if (!SDP_AddProtocolList(sdp_handle, num_proto_elements, proto_list))
+ goto error;
+
+ // Add the name to the SDP record.
+ if (name[0] != '\0') {
+ stage = "service_name";
+ if (!SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(name) + 1), (uint8_t*)name))
+ goto error;
+ }
+
+ stage = "browseable";
+ if (!SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list))
+ goto error;
+
+ APPL_TRACE_DEBUG(
+ "create_base_record: successfully created base service "
+ "record, handle: 0x%08x, scn: %d, name: %s, with_obex: %d",
+ sdp_handle, channel, name, with_obex);
+ return true;
+
+error:
+ APPL_TRACE_ERROR(
+ "create_base_record: failed to create base service "
+ "record, stage: %s, scn: %d, name: %s, with_obex: %d",
+ stage, channel, name, with_obex);
+ return false;
+}
+
+// Registers a service with the given |name|, |uuid|, and |channel| in the SDP
+// database as a generic L2CAP RFCOMM protocol, storing its |uuid| as a service
+// class sequence.
+static int add_sdp_by_uuid(const char* name, const uint8_t* uuid,
+ const uint16_t channel) {
+ APPL_TRACE_DEBUG("add_sdp_by_uuid: scn: %d, service_name: %s", channel, name);
+
+ uint32_t handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR(
+ "add_sdp_by_uuid: failed to create sdp record, "
+ "scn: %d, service_name: %s",
+ channel, name);
+ return 0;
+ }
+
+ // Convert the |uuid| into a big-endian representation and add it as a
+ // sequence.
+ uint8_t type = UUID_DESC_TYPE;
+ uint8_t type_len = UUID_MAX_LENGTH;
+ uint8_t type_buf[48];
+ // Store the address of type buf in a pointer on the stack, so we can pass
+ // a double pointer to SDP_AddSequence
+ uint8_t* type_buf_ptr = type_buf;
+ uint8_t* tmp = type_buf;
+
+ // Create the base SDP record.
+ const char* stage = "create_base_record";
+ if (!create_base_record(handle, name, channel, false /* with_obex */))
+ goto error;
+
+ // Do the conversion to big-endian -- tmp is only used to iterate through the
+ // UUID array in the macro and serves no other purpose as the conversion
+ // macros are not hygenic.
+ { ARRAY_TO_BE_STREAM(tmp, uuid, UUID_MAX_LENGTH); }
+
+ stage = "service_class_sequence";
+ if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SERVICE_CLASS_ID_LIST, 1,
+ &type, &type_len, &type_buf_ptr))
+ goto error;
+
+ APPL_TRACE_DEBUG(
+ "add_sdp_by_uuid: service registered successfully, "
+ "service_name: %s, handle: 0x%08x",
+ name, handle);
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR(
+ "add_sdp_by_uuid: failed to register service "
+ "stage: %s, service_name: %s",
+ stage, name);
+ return 0;
+}
+
+// Registers a service with the given |name| and |channel| in the SDP
+// database as a PBAP protocol.
+static int add_pbap_sdp(const char* name, const int channel) {
+ APPL_TRACE_DEBUG("add_pbap_sdp: scn %d, service_name %s", channel, name);
+
+ uint32_t handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR(
+ "add_pbap_sdp: failed to create sdp record, "
+ "service_name: %s",
+ name);
+ return 0;
+ }
+
+ uint16_t service = UUID_SERVCLASS_PBAP_PSE;
+
+ // Create the base SDP record.
+ const char* stage = "create_base_record";
+ if (!create_base_record(handle, name, channel, true /* with_obex */))
+ goto error;
+
+ // Add service class
+ stage = "service_class";
+ if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+ // Add in the phone access descriptor
+ stage = "profile_descriptor_list";
+ if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_PHONE_ACCESS,
+ BTA_PBS_DEFAULT_VERSION))
+ goto error;
+
+ // Set up our supported repositories
+ stage = "supported_repositories";
+ if (!SDP_AddAttribute(handle, ATTR_ID_SUPPORTED_REPOSITORIES, UINT_DESC_TYPE,
+ 1, (uint8_t*)&bta_pbs_cfg.supported_repositories))
+ goto error;
+
+ // Notify the system that we've got a new service class UUID.
+ bta_sys_add_uuid(UUID_SERVCLASS_PBAP_PSE);
+ APPL_TRACE_DEBUG(
+ "add_pbap_sdp: service registered successfully, "
+ "service_name: %s, handle: 0x%08x",
+ name, handle);
+
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR(
+ "add_pbap_sdp: failed to register PBAP service, stage: %s, "
+ "service_name: %s",
+ stage, name);
+ return 0;
+}
+// Registers a service with the given |name| and |channel| as an OBEX Push
+// protocol.
+static int add_ops_sdp(const char* name, const int channel) {
+ APPL_TRACE_DEBUG("add_ops_sdp: scn %d, service_name %s", channel, name);
+
+ uint32_t handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR(
+ "add_ops_sdp: failed to create sdp record, "
+ "service_name: %s",
+ name);
+ return 0;
+ }
+
+ // Add sequence for supported types.
+ uint8_t desc_type[OBEX_PUSH_NUM_FORMATS];
+ uint8_t type_len[OBEX_PUSH_NUM_FORMATS];
+ uint8_t* type_value[OBEX_PUSH_NUM_FORMATS];
+ uint8_t j = 0;
+
+ uint16_t service = UUID_SERVCLASS_OBEX_OBJECT_PUSH;
+ tBTA_UTL_COD cod;
+
+ // Create the base SDP record.
+ const char* stage = "create_base_record";
+ if (!create_base_record(handle, name, channel, true /* with_obex */))
+ goto error;
+
+ // Add service class.
+ stage = "service_class";
+ if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+ // Add the OBEX push profile descriptor.
+ stage = "profile_descriptor_list";
+ if (!SDP_AddProfileDescriptorList(handle, UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ 0x0100))
+ goto error;
+
+ for (int i = 0; i < OBEX_PUSH_NUM_FORMATS; i++) {
+ if ((BTUI_OPS_FORMATS >> i) & 1) {
+ type_value[j] = (uint8_t*)(&bta_ops_obj_fmt[i]);
+ desc_type[j] = UINT_DESC_TYPE;
+ type_len[j++] = 1;
+ }
+ }
+
+ stage = "supported_types";
+ if (!SDP_AddSequence(handle, (uint16_t)ATTR_ID_SUPPORTED_FORMATS_LIST, j,
+ desc_type, type_len, type_value))
+ goto error;
+
+ // Set class of device.
+ cod.service = BTM_COD_SERVICE_OBJ_TRANSFER;
+ stage = "class_of_device";
+ if (!utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS)) goto error;
+
+ // Notify the system that we've got a new service class UUID.
+ bta_sys_add_uuid(UUID_SERVCLASS_OBEX_OBJECT_PUSH);
+ APPL_TRACE_DEBUG(
+ "ad_maps_sdp: service registered successfully, "
+ "service_name: %s, handle 0x%08x)",
+ name, handle);
+
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR(
+ "add_ops_sdp: failed to register OPS service, "
+ "stage: %s, service_name: %s",
+ stage, name);
+ return 0;
+}
+
+// Registers a service with the given |name| and |channel| as a serial port
+// profile protocol.
+static int add_spp_sdp(const char* name, const int channel) {
+ APPL_TRACE_DEBUG("add_spp_sdp: scn %d, service_name %s", channel, name);
+
+ int handle = SDP_CreateRecord();
+ if (handle == 0) {
+ APPL_TRACE_ERROR(
+ "add_spp_sdp: failed to create sdp record, "
+ "service_name: %s",
+ name);
+ return 0;
+ }
+
+ // Create the base SDP record.
+ const char* stage = "create_base_record";
+ uint16_t service = UUID_SERVCLASS_SERIAL_PORT;
+
+ if (!create_base_record(handle, name, channel, false /* with_obex */))
+ goto error;
+
+ stage = "service_class";
+ if (!SDP_AddServiceClassIdList(handle, 1, &service)) goto error;
+
+ APPL_TRACE_DEBUG(
+ "add_spp_sdp: service registered successfully, "
+ "service_name: %s, handle 0x%08x)",
+ name, handle);
+
+ return handle;
+
+error:
+ SDP_DeleteRecord(handle);
+ APPL_TRACE_ERROR(
+ "add_spp_sdp: failed to register SPP service, "
+ "stage: %s, service_name: %s",
+ stage, name);
+ return 0;
+}
+
+// Adds an RFCOMM SDP record for a service with the given |name|, |uuid|, and
+// |channel|. This function attempts to identify the type of the service based
+// upon its |uuid|, and will override the |channel| with a reserved channel
+// number if the |uuid| matches one of the preregistered bluez SDP records.
+static int add_rfc_sdp_by_uuid(const char* name, const uint8_t* uuid,
+ const int channel) {
+ APPL_TRACE_DEBUG("add_rfc_sdp_by_uuid: service_name: %s, channel: %d", name,
+ channel);
+
+ /*
+ * Bluetooth Socket API relies on having preregistered bluez sdp records for
+ * HSAG, HFAG, OPP & PBAP that are mapped to rc chan 10, 11,12 & 19. Today
+ * HSAG and HFAG is routed to BRCM AG and are not using BT socket API so for
+ * now we will need to support OPP and PBAP to enable 3rd party developer apps
+ * running on BRCM Android.
+ *
+ * To do this we will check the UUID for the requested service and mimic the
+ * SDP records of bluez upon reception. See functions add_opush() and
+ * add_pbap() in sdptool.c for actual records.
+ */
+
+ int final_channel = get_reserved_rfc_channel(uuid);
+
+ if (final_channel == -1) {
+ final_channel = channel;
+ }
+
+ int handle = 0;
+
+ if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+ handle = add_ops_sdp(name, final_channel);
+ } else if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+ // PBAP Server is always channel 19
+ handle = add_pbap_sdp(name, final_channel);
+ } else if (UUID_MATCHES(UUID_SPP, uuid)) {
+ handle = add_spp_sdp(name, final_channel);
+ } else if (UUID_MATCHES(UUID_MAP_MAS, uuid)) {
+ // Record created by new SDP create record interface
+ handle = 0xff;
+ } else {
+ handle = add_sdp_by_uuid(name, uuid, final_channel);
+ }
+
+ return handle;
+}
+
+bool is_reserved_rfc_channel(const int channel) {
+ switch (channel) {
+ case RESERVED_SCN_PBS:
+ case RESERVED_SCN_OPS:
+ return true;
+ }
+
+ return false;
+}
+
+int get_reserved_rfc_channel(const uint8_t* uuid) {
+ if (UUID_MATCHES(UUID_PBAP_PSE, uuid)) {
+ return RESERVED_SCN_PBS;
+ } else if (UUID_MATCHES(UUID_OBEX_OBJECT_PUSH, uuid)) {
+ return RESERVED_SCN_OPS;
+ }
+
+ return -1;
+}
+
+// Adds an SDP record to the SDP database using the given |name|, |uuid|, and
+// |channel|. Note that if the |uuid| is empty, the |uuid| will be set based
+// upon the |channel| passed in.
+int add_rfc_sdp_rec(const char* name, const uint8_t* uuid, const int channel) {
+ if (is_uuid_empty(uuid)) {
+ switch (channel) {
+ case RESERVED_SCN_PBS: // PBAP Reserved port
+ uuid = UUID_PBAP_PSE;
+ break;
+
+ case RESERVED_SCN_OPS:
+ uuid = UUID_OBEX_OBJECT_PUSH;
+ break;
+
+ default:
+ uuid = UUID_SPP;
+ break;
+ }
+ }
+
+ return add_rfc_sdp_by_uuid(name, uuid, channel);
+}
+
+// Deletes an SDP record with the given |handle|.
+void del_rfc_sdp_rec(int handle) {
+ APPL_TRACE_DEBUG("del_rfc_sdp_rec: handle:0x%x", handle);
+
+ if ((handle != -1) && (handle != 0)) BTA_JvDeleteRecord(handle);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_thread.cc b/mtkbt/code/bt/btif/src/btif_sock_thread.cc
new file mode 100755
index 0000000..b206892
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_thread.cc
@@ -0,0 +1,552 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_sock_thread.cc
+ *
+ * Description: socket select thread
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_thread.h"
+
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <features.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <string>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "btif_sock.h"
+#include "btif_sock_util.h"
+#include "btif_util.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define asrt(s) \
+ do { \
+ if (!(s)) \
+ APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \
+ __LINE__) \
+ } while (0)
+
+#define MAX_THREAD 8
+#define MAX_POLL 64
+#define POLL_EXCEPTION_EVENTS (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)
+#define IS_EXCEPTION(e) ((e)&POLL_EXCEPTION_EVENTS)
+#define IS_READ(e) ((e)&POLLIN)
+#define IS_WRITE(e) ((e)&POLLOUT)
+/*cmd executes in socket poll thread */
+#define CMD_WAKEUP 1
+#define CMD_EXIT 2
+#define CMD_ADD_FD 3
+#define CMD_REMOVE_FD 4
+#define CMD_USER_PRIVATE 5
+
+typedef struct {
+ struct pollfd pfd;
+ uint32_t user_id;
+ int type;
+ int flags;
+} poll_slot_t;
+typedef struct {
+ int cmd_fdr, cmd_fdw;
+ int poll_count;
+ poll_slot_t ps[MAX_POLL];
+ int psi[MAX_POLL]; // index of poll slot
+ pthread_t thread_id;
+ btsock_signaled_cb callback;
+ btsock_cmd_cb cmd_callback;
+ int used;
+} thread_slot_t;
+static thread_slot_t ts[MAX_THREAD];
+
+static void* sock_poll_thread(void* arg);
+static inline void close_cmd_fd(int h);
+
+static inline void add_poll(int h, int fd, int type, int flags,
+ uint32_t user_id);
+
+static std::recursive_mutex thread_slot_lock;
+
+static inline int create_thread(void* (*start_routine)(void*), void* arg,
+ pthread_t* thread_id) {
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
+ int policy;
+ int min_pri = 0;
+ int ret = -1;
+ struct sched_param param;
+
+ ret = pthread_create(thread_id, &thread_attr, start_routine, arg);
+ if (ret != 0) {
+ APPL_TRACE_ERROR("pthread_create : %s", strerror(errno));
+ return ret;
+ }
+ /* We need to lower the priority of this thread to ensure the stack gets
+ * priority over transfer to a socket */
+ pthread_getschedparam(*thread_id, &policy, &param);
+ min_pri = sched_get_priority_min(policy);
+ if (param.sched_priority > min_pri) {
+ param.sched_priority -= 1;
+ }
+ pthread_setschedparam(*thread_id, policy, &param);
+ return ret;
+}
+static void init_poll(int cmd_fd);
+static int alloc_thread_slot() {
+ std::unique_lock<std::recursive_mutex> lock(thread_slot_lock);
+ int i;
+ // reversed order to save guard uninitialized access to 0 index
+ for (i = MAX_THREAD - 1; i >= 0; i--) {
+ APPL_TRACE_DEBUG("ts[%d].used:%d", i, ts[i].used);
+ if (!ts[i].used) {
+ ts[i].used = 1;
+ return i;
+ }
+ }
+ APPL_TRACE_ERROR("execeeded max thread count");
+ return -1;
+}
+static void free_thread_slot(int h) {
+ if (0 <= h && h < MAX_THREAD) {
+ close_cmd_fd(h);
+ ts[h].used = 0;
+ } else
+ APPL_TRACE_ERROR("invalid thread handle:%d", h);
+}
+int btsock_thread_init() {
+ static int initialized;
+ APPL_TRACE_DEBUG("in initialized:%d", initialized);
+ if (!initialized) {
+ initialized = 1;
+ int h;
+ for (h = 0; h < MAX_THREAD; h++) {
+ ts[h].cmd_fdr = ts[h].cmd_fdw = -1;
+ ts[h].used = 0;
+ ts[h].thread_id = -1;
+ ts[h].poll_count = 0;
+ ts[h].callback = NULL;
+ ts[h].cmd_callback = NULL;
+ }
+ }
+ return true;
+}
+int btsock_thread_create(btsock_signaled_cb callback,
+ btsock_cmd_cb cmd_callback) {
+ asrt(callback || cmd_callback);
+ int h = alloc_thread_slot();
+ APPL_TRACE_DEBUG("alloc_thread_slot ret:%d", h);
+ if (h >= 0) {
+ init_poll(h);
+ pthread_t thread;
+ int status = create_thread(sock_poll_thread, (void*)(uintptr_t)h, &thread);
+ if (status) {
+ APPL_TRACE_ERROR("create_thread failed: %s", strerror(status));
+ free_thread_slot(h);
+ return -1;
+ }
+
+ ts[h].thread_id = thread;
+ APPL_TRACE_DEBUG("h:%d, thread id:%d", h, ts[h].thread_id);
+ ts[h].callback = callback;
+ ts[h].cmd_callback = cmd_callback;
+ }
+ return h;
+}
+
+/* create dummy socket pair used to wake up select loop */
+static inline void init_cmd_fd(int h) {
+ asrt(ts[h].cmd_fdr == -1 && ts[h].cmd_fdw == -1);
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, &ts[h].cmd_fdr) < 0) {
+ APPL_TRACE_ERROR("socketpair failed: %s", strerror(errno));
+ return;
+ }
+ APPL_TRACE_DEBUG("h:%d, cmd_fdr:%d, cmd_fdw:%d", h, ts[h].cmd_fdr,
+ ts[h].cmd_fdw);
+ // add the cmd fd for read & write
+ add_poll(h, ts[h].cmd_fdr, 0, SOCK_THREAD_FD_RD, 0);
+}
+static inline void close_cmd_fd(int h) {
+ if (ts[h].cmd_fdr != -1) {
+ close(ts[h].cmd_fdr);
+ ts[h].cmd_fdr = -1;
+ }
+ if (ts[h].cmd_fdw != -1) {
+ close(ts[h].cmd_fdw);
+ ts[h].cmd_fdw = -1;
+ }
+}
+typedef struct {
+ int id;
+ int fd;
+ int type;
+ int flags;
+ uint32_t user_id;
+} sock_cmd_t;
+int btsock_thread_add_fd(int h, int fd, int type, int flags, uint32_t user_id) {
+ if (h < 0 || h >= MAX_THREAD) {
+ APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+ return false;
+ }
+ if (ts[h].cmd_fdw == -1) {
+ APPL_TRACE_ERROR(
+ "cmd socket is not created. socket thread may not initialized");
+ return false;
+ }
+ if (flags & SOCK_THREAD_ADD_FD_SYNC) {
+ // must executed in socket poll thread
+ if (ts[h].thread_id == pthread_self()) {
+ // cleanup one-time flags
+ flags &= ~SOCK_THREAD_ADD_FD_SYNC;
+ add_poll(h, fd, type, flags, user_id);
+ return true;
+ }
+ APPL_TRACE_DEBUG(
+ "THREAD_ADD_FD_SYNC is not called in poll thread, fallback to async");
+ }
+ sock_cmd_t cmd = {CMD_ADD_FD, fd, type, flags, user_id};
+ APPL_TRACE_DEBUG("adding fd:%d, flags:0x%x", fd, flags);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+ return ret == sizeof(cmd);
+}
+
+bool btsock_thread_remove_fd_and_close(int thread_handle, int fd) {
+ if (thread_handle < 0 || thread_handle >= MAX_THREAD) {
+ APPL_TRACE_ERROR("%s invalid thread handle: %d", __func__, thread_handle);
+ return false;
+ }
+ if (fd == -1) {
+ APPL_TRACE_ERROR("%s invalid file descriptor.", __func__);
+ return false;
+ }
+
+ sock_cmd_t cmd = {CMD_REMOVE_FD, fd, 0, 0, 0};
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(ts[thread_handle].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+ return ret == sizeof(cmd);
+}
+
+int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size,
+ uint32_t user_id) {
+ if (h < 0 || h >= MAX_THREAD) {
+ APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+ return false;
+ }
+ if (ts[h].cmd_fdw == -1) {
+ APPL_TRACE_ERROR(
+ "cmd socket is not created. socket thread may not initialized");
+ return false;
+ }
+ sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
+ APPL_TRACE_DEBUG("post cmd type:%d, size:%d, h:%d, ", type, size, h);
+ sock_cmd_t* cmd_send = &cmd;
+ int size_send = sizeof(cmd);
+ if (data && size) {
+ size_send = sizeof(cmd) + size;
+ cmd_send = (sock_cmd_t*)alloca(size_send);
+ if (cmd_send) {
+ *cmd_send = cmd;
+ memcpy(cmd_send + 1, data, size);
+ } else {
+ APPL_TRACE_ERROR("alloca failed at h:%d, cmd type:%d, size:%d", h, type,
+ size_send);
+ return false;
+ }
+ }
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(ts[h].cmd_fdw, cmd_send, size_send, 0));
+
+ return ret == size_send;
+}
+int btsock_thread_wakeup(int h) {
+ if (h < 0 || h >= MAX_THREAD) {
+ APPL_TRACE_ERROR("invalid bt thread handle:%d", h);
+ return false;
+ }
+ if (ts[h].cmd_fdw == -1) {
+ APPL_TRACE_ERROR("thread handle:%d, cmd socket is not created", h);
+ return false;
+ }
+ sock_cmd_t cmd = {CMD_WAKEUP, 0, 0, 0, 0};
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+ return ret == sizeof(cmd);
+}
+int btsock_thread_exit(int h) {
+ if (h < 0 || h >= MAX_THREAD) {
+ APPL_TRACE_ERROR("invalid bt thread slot:%d", h);
+ return false;
+ }
+ if (ts[h].cmd_fdw == -1) {
+ APPL_TRACE_ERROR("cmd socket is not created");
+ return false;
+ }
+ sock_cmd_t cmd = {CMD_EXIT, 0, 0, 0, 0};
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(ts[h].cmd_fdw, &cmd, sizeof(cmd), 0));
+
+ if (ret == sizeof(cmd)) {
+ if (ts[h].thread_id != -1) {
+ pthread_join(ts[h].thread_id, 0);
+ ts[h].thread_id = -1;
+ }
+ free_thread_slot(h);
+ return true;
+ }
+ return false;
+}
+static void init_poll(int h) {
+ int i;
+ ts[h].poll_count = 0;
+ ts[h].thread_id = -1;
+ ts[h].callback = NULL;
+ ts[h].cmd_callback = NULL;
+ for (i = 0; i < MAX_POLL; i++) {
+ ts[h].ps[i].pfd.fd = -1;
+ ts[h].psi[i] = -1;
+ }
+ init_cmd_fd(h);
+}
+static inline unsigned int flags2pevents(int flags) {
+ unsigned int pevents = 0;
+ if (flags & SOCK_THREAD_FD_WR) pevents |= POLLOUT;
+ if (flags & SOCK_THREAD_FD_RD) pevents |= POLLIN;
+ pevents |= POLL_EXCEPTION_EVENTS;
+ return pevents;
+}
+
+static inline void set_poll(poll_slot_t* ps, int fd, int type, int flags,
+ uint32_t user_id) {
+ ps->pfd.fd = fd;
+ ps->user_id = user_id;
+ if (ps->type != 0 && ps->type != type)
+ APPL_TRACE_ERROR(
+ "poll socket type should not changed! type was:%d, type now:%d",
+ ps->type, type);
+ ps->type = type;
+ ps->flags = flags;
+ ps->pfd.events = flags2pevents(flags);
+ ps->pfd.revents = 0;
+}
+static inline void add_poll(int h, int fd, int type, int flags,
+ uint32_t user_id) {
+ asrt(fd != -1);
+ int i;
+ int empty = -1;
+ poll_slot_t* ps = ts[h].ps;
+
+ for (i = 0; i < MAX_POLL; i++) {
+ if (ps[i].pfd.fd == fd) {
+ asrt(ts[h].poll_count < MAX_POLL);
+
+ set_poll(&ps[i], fd, type, flags | ps[i].flags, user_id);
+ return;
+ } else if (empty < 0 && ps[i].pfd.fd == -1)
+ empty = i;
+ }
+ if (empty >= 0) {
+ asrt(ts[h].poll_count < MAX_POLL);
+ set_poll(&ps[empty], fd, type, flags, user_id);
+ ++ts[h].poll_count;
+ return;
+ }
+ APPL_TRACE_ERROR("exceeded max poll slot:%d!", MAX_POLL);
+}
+static inline void remove_poll(int h, poll_slot_t* ps, int flags) {
+ if (flags == ps->flags) {
+ // all monitored events signaled. To remove it, just clear the slot
+ --ts[h].poll_count;
+ memset(ps, 0, sizeof(*ps));
+ ps->pfd.fd = -1;
+ } else {
+ // one read or one write monitor event signaled, removed the accordding bit
+ ps->flags &= ~flags;
+ // update the poll events mask
+ ps->pfd.events = flags2pevents(ps->flags);
+ }
+}
+static int process_cmd_sock(int h) {
+ sock_cmd_t cmd = {-1, 0, 0, 0, 0};
+ int fd = ts[h].cmd_fdr;
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL));
+
+ if (ret != sizeof(cmd)) {
+ APPL_TRACE_ERROR("recv cmd errno:%d", errno);
+ return false;
+ }
+ APPL_TRACE_DEBUG("cmd.id:%d", cmd.id);
+ switch (cmd.id) {
+ case CMD_ADD_FD:
+ add_poll(h, cmd.fd, cmd.type, cmd.flags, cmd.user_id);
+ break;
+ case CMD_REMOVE_FD:
+ for (int i = 1; i < MAX_POLL; ++i) {
+ poll_slot_t* poll_slot = &ts[h].ps[i];
+ if (poll_slot->pfd.fd == cmd.fd) {
+ remove_poll(h, poll_slot, poll_slot->flags);
+ break;
+ }
+ }
+ close(cmd.fd);
+ break;
+ case CMD_WAKEUP:
+ break;
+ case CMD_USER_PRIVATE:
+ asrt(ts[h].cmd_callback);
+ if (ts[h].cmd_callback)
+ ts[h].cmd_callback(fd, cmd.type, cmd.flags, cmd.user_id);
+ break;
+ case CMD_EXIT:
+ return false;
+ default:
+ APPL_TRACE_DEBUG("unknown cmd: %d", cmd.id);
+ break;
+ }
+ return true;
+}
+
+static void print_events(short events) {
+ std::string flags("");
+ if ((events)&POLLIN) flags += " POLLIN";
+ if ((events)&POLLPRI) flags += " POLLPRI";
+ if ((events)&POLLOUT) flags += " POLLOUT";
+ if ((events)&POLLERR) flags += " POLLERR";
+ if ((events)&POLLHUP) flags += " POLLHUP ";
+ if ((events)&POLLNVAL) flags += " POLLNVAL";
+ if ((events)&POLLRDHUP) flags += " POLLRDHUP";
+ APPL_TRACE_DEBUG("print poll event:%x = %s", (events), flags.c_str());
+}
+
+static void process_data_sock(int h, struct pollfd* pfds, int count) {
+ asrt(count <= ts[h].poll_count);
+ int i;
+ for (i = 1; i < ts[h].poll_count; i++) {
+ if (pfds[i].revents) {
+ int ps_i = ts[h].psi[i];
+ asrt(pfds[i].fd == ts[h].ps[ps_i].pfd.fd);
+ uint32_t user_id = ts[h].ps[ps_i].user_id;
+ int type = ts[h].ps[ps_i].type;
+ int flags = 0;
+ print_events(pfds[i].revents);
+ if (IS_READ(pfds[i].revents)) {
+ flags |= SOCK_THREAD_FD_RD;
+ }
+ if (IS_WRITE(pfds[i].revents)) {
+ flags |= SOCK_THREAD_FD_WR;
+ }
+ if (IS_EXCEPTION(pfds[i].revents)) {
+ flags |= SOCK_THREAD_FD_EXCEPTION;
+ // remove the whole slot not flags
+ remove_poll(h, &ts[h].ps[ps_i], ts[h].ps[ps_i].flags);
+ } else if (flags)
+ remove_poll(h, &ts[h].ps[ps_i],
+ flags); // remove the monitor flags that already processed
+ if (flags) ts[h].callback(pfds[i].fd, type, flags, user_id);
+ }
+ }
+}
+
+static void prepare_poll_fds(int h, struct pollfd* pfds) {
+ int count = 0;
+ int ps_i = 0;
+ int pfd_i = 0;
+ asrt(ts[h].poll_count <= MAX_POLL);
+ memset(pfds, 0, sizeof(pfds[0]) * ts[h].poll_count);
+ while (count < ts[h].poll_count) {
+ if (ps_i >= MAX_POLL) {
+ APPL_TRACE_ERROR(
+ "exceed max poll range, ps_i:%d, MAX_POLL:%d, count:%d, "
+ "ts[h].poll_count:%d",
+ ps_i, MAX_POLL, count, ts[h].poll_count);
+ return;
+ }
+ if (ts[h].ps[ps_i].pfd.fd >= 0) {
+ pfds[pfd_i] = ts[h].ps[ps_i].pfd;
+ ts[h].psi[pfd_i] = ps_i;
+ count++;
+ pfd_i++;
+ }
+ ps_i++;
+ }
+}
+static void* sock_poll_thread(void* arg) {
+ struct pollfd pfds[MAX_POLL];
+ memset(pfds, 0, sizeof(pfds));
+ int h = (intptr_t)arg;
+ for (;;) {
+ prepare_poll_fds(h, pfds);
+ int ret;
+ OSI_NO_INTR(ret = poll(pfds, ts[h].poll_count, -1));
+ if (ret == -1) {
+ APPL_TRACE_ERROR("poll ret -1, exit the thread, errno:%d, err:%s", errno,
+ strerror(errno));
+ break;
+ }
+ if (ret != 0) {
+ int need_process_data_fd = true;
+ if (pfds[0].revents) // cmd fd always is the first one
+ {
+ asrt(pfds[0].fd == ts[h].cmd_fdr);
+ if (!process_cmd_sock(h)) {
+ APPL_TRACE_DEBUG("h:%d, process_cmd_sock return false, exit...", h);
+ break;
+ }
+ if (ret == 1)
+ need_process_data_fd = false;
+ else
+ ret--; // exclude the cmd fd
+ }
+ if (need_process_data_fd) process_data_sock(h, pfds, ret);
+ } else {
+ APPL_TRACE_DEBUG("no data, select ret: %d", ret)
+ };
+ }
+ APPL_TRACE_DEBUG("socket poll thread exiting, h:%d", h);
+ return 0;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_sock_util.cc b/mtkbt/code/bt/btif/src/btif_sock_util.cc
new file mode 100755
index 0000000..bf76100
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_sock_util.cc
@@ -0,0 +1,233 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_sock"
+
+#include "btif_sock_util.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_sock.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bta_api.h"
+#include "bta_jv_api.h"
+#include "bta_jv_co.h"
+#include "btif_common.h"
+#include "btif_sock_sdp.h"
+#include "btif_sock_thread.h"
+#include "btif_util.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
+
+#define asrt(s) \
+ do { \
+ if (!(s)) \
+ BTIF_TRACE_ERROR("## %s assert %s failed at line:%d ##", __func__, #s, \
+ __LINE__) \
+ } while (0)
+
+int sock_send_all(int sock_fd, const uint8_t* buf, int len) {
+ int s = len;
+
+ while (s) {
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(sock_fd, buf, s, 0));
+ if (ret <= 0) {
+ BTIF_TRACE_ERROR("sock fd:%d send errno:%d, ret:%d", sock_fd, errno, ret);
+ return -1;
+ }
+ buf += ret;
+ s -= ret;
+ }
+ return len;
+}
+int sock_recv_all(int sock_fd, uint8_t* buf, int len) {
+ int r = len;
+
+ while (r) {
+ ssize_t ret;
+ OSI_NO_INTR(ret = recv(sock_fd, buf, r, MSG_WAITALL));
+ if (ret <= 0) {
+ BTIF_TRACE_ERROR("sock fd:%d recv errno:%d, ret:%d", sock_fd, errno, ret);
+ return -1;
+ }
+ buf += ret;
+ r -= ret;
+ }
+ return len;
+}
+
+int sock_send_fd(int sock_fd, const uint8_t* buf, int len, int send_fd) {
+ struct msghdr msg;
+ unsigned char* buffer = (unsigned char*)buf;
+ memset(&msg, 0, sizeof(msg));
+
+ struct cmsghdr* cmsg;
+ char msgbuf[CMSG_SPACE(1)];
+ asrt(send_fd != -1);
+ if (sock_fd == -1 || send_fd == -1) return -1;
+ // Add any pending outbound file descriptors to the message
+ // See "man cmsg" really
+ msg.msg_control = msgbuf;
+ msg.msg_controllen = sizeof msgbuf;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof send_fd);
+ memcpy(CMSG_DATA(cmsg), &send_fd, sizeof send_fd);
+
+ // We only write our msg_control during the first write
+ int ret_len = len;
+ while (len > 0) {
+ struct iovec iv;
+ memset(&iv, 0, sizeof(iv));
+
+ iv.iov_base = buffer;
+ iv.iov_len = len;
+
+ msg.msg_iov = &iv;
+ msg.msg_iovlen = 1;
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = sendmsg(sock_fd, &msg, MSG_NOSIGNAL));
+ if (ret < 0) {
+ BTIF_TRACE_ERROR("fd:%d, send_fd:%d, sendmsg ret:%d, errno:%d, %s",
+ sock_fd, send_fd, (int)ret, errno, strerror(errno));
+ ret_len = -1;
+ break;
+ }
+
+ buffer += ret;
+ len -= ret;
+
+ // Wipes out any msg_control too
+ memset(&msg, 0, sizeof(msg));
+ }
+ BTIF_TRACE_DEBUG("close fd:%d after sent", send_fd);
+ // TODO: This seems wrong - if the FD is not opened in JAVA before this is
+ // called
+ // we get a "socket closed" exception in java, when reading from the
+ // socket...
+ close(send_fd);
+ return ret_len;
+}
+
+static const char* hex_table = "0123456789abcdef";
+static inline void byte2hex(const char* data, char** str) {
+ **str = hex_table[(*data >> 4) & 0xf];
+ ++*str;
+ **str = hex_table[*data & 0xf];
+ ++*str;
+}
+static inline void byte2char(const char* data, char** str) {
+ **str = *data < ' ' ? '.' : *data > '~' ? '.' : *data;
+ ++(*str);
+}
+static inline void word2hex(const char* data, char** hex) {
+ byte2hex(&data[1], hex);
+ byte2hex(&data[0], hex);
+}
+void dump_bin(const char* title, const char* data, int size) {
+ char line_buff[256];
+ char* line;
+ int i, j, addr;
+ const int width = 16;
+ LOG_DEBUG(LOG_TAG, "%s, size:%d, dump started {", title, size);
+ if (size <= 0) return;
+ // write offset
+ line = line_buff;
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ for (j = 0; j < width; j++) {
+ byte2hex((const char*)&j, &line);
+ *line++ = ' ';
+ }
+ *line = 0;
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
+
+ for (i = 0; i < size / width; i++) {
+ line = line_buff;
+ // write address:
+ addr = i * width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':';
+ *line++ = ' ';
+ // write hex of data
+ for (j = 0; j < width; j++) {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ // write char of data
+ for (j = 0; j < width; j++) byte2char(data++, &line);
+ // wirte the end of line
+ *line = 0;
+ // output the line
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
+ }
+ // last line of left over if any
+ int leftover = size % width;
+ if (leftover > 0) {
+ line = line_buff;
+ // write address:
+ addr = i * width;
+ word2hex((const char*)&addr, &line);
+ *line++ = ':';
+ *line++ = ' ';
+ // write hex of data
+ for (j = 0; j < leftover; j++) {
+ byte2hex(&data[j], &line);
+ *line++ = ' ';
+ }
+ // write hex padding
+ for (; j < width; j++) {
+ *line++ = ' ';
+ *line++ = ' ';
+ *line++ = ' ';
+ }
+ // write char of data
+ for (j = 0; j < leftover; j++) byte2char(data++, &line);
+ // write the end of line
+ *line = 0;
+ // output the line
+ LOG_DEBUG(LOG_TAG, "%s", line_buff);
+ }
+ LOG_DEBUG(LOG_TAG, "%s, size:%d, dump ended }", title, size);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_storage.cc b/mtkbt/code/bt/btif/src/btif_storage.cc
new file mode 100755
index 0000000..921d9d9
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_storage.cc
@@ -0,0 +1,1452 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_storage.c
+ *
+ * Description: Stores the local BT adapter and remote device properties in
+ * NVRAM storage, typically as xml file in the
+ * mobile's filesystem
+ *
+ *
+ */
+
+#define LOG_TAG "bt_btif_storage"
+
+#include "btif_storage.h"
+
+#include <alloca.h>
+#include <base/logging.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bt_common.h"
+#include "bta_hd_api.h"
+#include "bta_hh_api.h"
+#include "btcore/include/bdaddr.h"
+#include "btif_api.h"
+#include "btif_config.h"
+#include "btif_hd.h"
+#include "btif_hh.h"
+#include "btif_util.h"
+#include "device/include/controller.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+// TODO(armansito): Find a better way than using a hardcoded path.
+#define BTIF_STORAGE_PATH_BLUEDROID "/data/misc/bluedroid"
+
+//#define BTIF_STORAGE_PATH_ADAPTER_INFO "adapter_info"
+//#define BTIF_STORAGE_PATH_REMOTE_DEVICES "remote_devices"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTIME "Timestamp"
+#define BTIF_STORAGE_PATH_REMOTE_DEVCLASS "DevClass"
+#define BTIF_STORAGE_PATH_REMOTE_DEVTYPE "DevType"
+#define BTIF_STORAGE_PATH_REMOTE_NAME "Name"
+#define BTIF_STORAGE_PATH_REMOTE_VER_MFCT "Manufacturer"
+#define BTIF_STORAGE_PATH_REMOTE_VER_VER "LmpVer"
+#define BTIF_STORAGE_PATH_REMOTE_VER_SUBVER "LmpSubVer"
+
+//#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS "remote_linkkeys"
+#define BTIF_STORAGE_PATH_REMOTE_ALIASE "Aliase"
+#define BTIF_STORAGE_PATH_REMOTE_SERVICE "Service"
+#define BTIF_STORAGE_PATH_REMOTE_HIDINFO "HidInfo"
+#define BTIF_STORAGE_KEY_ADAPTER_NAME "Name"
+#define BTIF_STORAGE_KEY_ADAPTER_SCANMODE "ScanMode"
+#define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT "DiscoveryTimeout"
+
+/* This is a local property to add a device found */
+#define BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP 0xFF
+
+// TODO: This macro should be converted to a function
+#define BTIF_STORAGE_GET_ADAPTER_PROP(s, t, v, l, p) \
+ do { \
+ (p).type = (t); \
+ (p).val = (v); \
+ (p).len = (l); \
+ s = btif_storage_get_adapter_property(&(p)); \
+ } while (0)
+
+// TODO: This macro should be converted to a function
+#define BTIF_STORAGE_GET_REMOTE_PROP(b, t, v, l, p) \
+ do { \
+ (p).type = (t); \
+ (p).val = (v); \
+ (p).len = (l); \
+ btif_storage_get_remote_device_property((b), &(p)); \
+ } while (0)
+
+#define STORAGE_BDADDR_STRING_SZ (18) /* 00:11:22:33:44:55 */
+#define STORAGE_UUID_STRING_SIZE \
+ (36 + 1) /* 00001200-0000-1000-8000-00805f9b34fb; */
+#define STORAGE_PINLEN_STRING_MAX_SIZE (2) /* ascii pinlen max chars */
+#define STORAGE_KEYTYPE_STRING_MAX_SIZE (1) /* ascii keytype max chars */
+
+#define STORAGE_KEY_TYPE_MAX (10)
+
+#define STORAGE_HID_ATRR_MASK_SIZE (4)
+#define STORAGE_HID_SUB_CLASS_SIZE (2)
+#define STORAGE_HID_APP_ID_SIZE (2)
+#define STORAGE_HID_VENDOR_ID_SIZE (4)
+#define STORAGE_HID_PRODUCT_ID_SIZE (4)
+#define STORAGE_HID_VERSION_SIZE (4)
+#define STORAGE_HID_CTRY_CODE_SIZE (2)
+#define STORAGE_HID_DESC_LEN_SIZE (4)
+#define STORAGE_HID_DESC_MAX_SIZE (2 * 512)
+
+/* <18 char bd addr> <space> LIST< <36 char uuid> <;> > <keytype (dec)> <pinlen>
+ */
+#define BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX \
+ (STORAGE_BDADDR_STRING_SZ + 1 + \
+ STORAGE_UUID_STRING_SIZE * BT_MAX_NUM_UUIDS + \
+ STORAGE_PINLEN_STRING_MAX_SIZE + STORAGE_KEYTYPE_STRING_MAX_SIZE)
+
+#define STORAGE_REMOTE_LINKKEYS_ENTRY_SIZE (LINK_KEY_LEN * 2 + 1 + 2 + 1 + 2)
+
+/* <18 char bd addr> <space>LIST <attr_mask> <space> > <sub_class> <space>
+ <app_id> <space>
+ <vendor_id> <space> > <product_id> <space>
+ <version> <space>
+ <ctry_code> <space> > <desc_len> <space>
+ <desc_list> <space> */
+#define BTIF_HID_INFO_ENTRY_SIZE_MAX \
+ (STORAGE_BDADDR_STRING_SZ + 1 + STORAGE_HID_ATRR_MASK_SIZE + 1 + \
+ STORAGE_HID_SUB_CLASS_SIZE + 1 + STORAGE_HID_APP_ID_SIZE + 1 + \
+ STORAGE_HID_VENDOR_ID_SIZE + 1 + STORAGE_HID_PRODUCT_ID_SIZE + 1 + \
+ STORAGE_HID_VERSION_SIZE + 1 + STORAGE_HID_CTRY_CODE_SIZE + 1 + \
+ STORAGE_HID_DESC_LEN_SIZE + 1 + STORAGE_HID_DESC_MAX_SIZE + 1)
+
+/* currently remote services is the potentially largest entry */
+#define BTIF_STORAGE_MAX_LINE_SZ BTIF_REMOTE_SERVICES_ENTRY_SIZE_MAX
+
+/* check against unv max entry size at compile time */
+#if (BTIF_STORAGE_ENTRY_MAX_SIZE > UNV_MAXLINE_LENGTH)
+#error "btif storage entry size exceeds unv max line size"
+#endif
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+typedef struct {
+ uint32_t num_devices;
+ bt_bdaddr_t devices[BTM_SEC_MAX_DEVICE_RECORDS];
+} btif_bonded_devices_t;
+
+/*******************************************************************************
+ * External functions
+ ******************************************************************************/
+
+extern void btif_gatts_add_bonded_dev_from_nv(BD_ADDR bda);
+
+/*******************************************************************************
+ * Internal Functions
+ ******************************************************************************/
+
+static bt_status_t btif_in_fetch_bonded_ble_device(
+ const char* remote_bd_addr, int add,
+ btif_bonded_devices_t* p_bonded_devices);
+static bt_status_t btif_in_fetch_bonded_device(const char* bdstr);
+
+static bool btif_has_ble_keys(const char* bdstr);
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+static int prop2cfg(bt_bdaddr_t* remote_bd_addr, bt_property_t* prop) {
+ bdstr_t bdstr = {0};
+ if (remote_bd_addr) bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
+ prop->len);
+ char value[1024];
+ if (prop->len <= 0 || prop->len > (int)sizeof(value) - 1) {
+ BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
+ prop->len);
+ return false;
+ }
+ switch (prop->type) {
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,
+ (int)time(NULL));
+ break;
+ case BT_PROPERTY_BDNAME:
+ strncpy(value, (char*)prop->val, prop->len);
+ value[prop->len] = '\0';
+ if (remote_bd_addr)
+ btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, value);
+ else
+ {
+ btif_config_set_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME, value);
+ /** M: save the adapter name immediately @{ */
+ //Adapter property is unrelated with bond, so need to save it immediately.
+ btif_config_save();
+ /** @} */
+ }
+ break;
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ strncpy(value, (char*)prop->val, prop->len);
+ value[prop->len] = '\0';
+ btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, value);
+ break;
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ btif_config_set_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,
+ *(int*)prop->val);
+ break;
+ case BT_PROPERTY_UUIDS: {
+ uint32_t i;
+ char buf[64];
+ value[0] = 0;
+ for (i = 0; i < (prop->len) / sizeof(bt_uuid_t); i++) {
+ bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val + i;
+ memset(buf, 0, sizeof(buf));
+ uuid_to_string_legacy(p_uuid, buf, sizeof(buf));
+ strcat(value, buf);
+ // strcat(value, ";");
+ strcat(value, " ");
+ }
+ btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value);
+ break;
+ }
+ case BT_PROPERTY_REMOTE_VERSION_INFO: {
+ bt_remote_version_t* info = (bt_remote_version_t*)prop->val;
+
+ if (!info) return false;
+
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_MFCT,
+ info->manufacturer);
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_VER,
+ info->version);
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_SUBVER,
+ info->sub_ver);
+ } break;
+
+ default:
+ BTIF_TRACE_ERROR("Unknown prop type:%d", prop->type);
+ return false;
+ }
+
+ /* save changes if the device was bonded */
+ if (btif_in_fetch_bonded_device(bdstr) == BT_STATUS_SUCCESS) {
+ btif_config_flush();
+ }
+
+ return true;
+}
+
+static int cfg2prop(bt_bdaddr_t* remote_bd_addr, bt_property_t* prop) {
+ bdstr_t bdstr = {0};
+ if (remote_bd_addr) bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG("in, bd addr:%s, prop type:%d, len:%d", bdstr, prop->type,
+ prop->len);
+ if (prop->len <= 0) {
+ BTIF_TRACE_ERROR("property type:%d, len:%d is invalid", prop->type,
+ prop->len);
+ return false;
+ }
+ int ret = false;
+ switch (prop->type) {
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_BDNAME: {
+ int len = prop->len;
+ if (remote_bd_addr)
+ ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME,
+ (char*)prop->val, &len);
+ else
+ ret = btif_config_get_str("Adapter", BTIF_STORAGE_KEY_ADAPTER_NAME,
+ (char*)prop->val, &len);
+ if (ret && len && len <= prop->len)
+ prop->len = len - 1;
+ else {
+ prop->len = 0;
+ ret = false;
+ }
+ break;
+ }
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME: {
+ int len = prop->len;
+ ret = btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE,
+ (char*)prop->val, &len);
+ if (ret && len && len <= prop->len)
+ prop->len = len - 1;
+ else {
+ prop->len = 0;
+ ret = false;
+ }
+ break;
+ }
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int("Adapter", BTIF_STORAGE_KEY_ADAPTER_SCANMODE,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int(
+ "Adapter", BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, (int*)prop->val);
+ break;
+ case BT_PROPERTY_CLASS_OF_DEVICE:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_TYPE_OF_DEVICE:
+ if (prop->len >= (int)sizeof(int))
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,
+ (int*)prop->val);
+ break;
+ case BT_PROPERTY_UUIDS: {
+ char value[1280];
+ int size = sizeof(value);
+ if (btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value,
+ &size)) {
+ bt_uuid_t* p_uuid = (bt_uuid_t*)prop->val;
+ size_t num_uuids =
+ btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS);
+ prop->len = num_uuids * sizeof(bt_uuid_t);
+ ret = true;
+ } else {
+ prop->val = NULL;
+ prop->len = 0;
+ }
+ } break;
+
+ case BT_PROPERTY_REMOTE_VERSION_INFO: {
+ bt_remote_version_t* info = (bt_remote_version_t*)prop->val;
+
+ if (prop->len >= (int)sizeof(bt_remote_version_t)) {
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_MFCT,
+ &info->manufacturer);
+
+ if (ret == true)
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_VER,
+ &info->version);
+
+ if (ret == true)
+ ret = btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_VER_SUBVER,
+ &info->sub_ver);
+ }
+ } break;
+
+ default:
+ BTIF_TRACE_ERROR("Unknow prop type:%d", prop->type);
+ return false;
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_in_fetch_bonded_devices
+ *
+ * Description Internal helper function to fetch the bonded devices
+ * from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_device(const char* bdstr) {
+ bool bt_linkkey_file_found = false;
+
+ LINK_KEY link_key;
+ size_t size = sizeof(link_key);
+ if (btif_config_get_bin(bdstr, "LinkKey", (uint8_t*)link_key, &size)) {
+ int linkkey_type;
+ if (btif_config_get_int(bdstr, "LinkKeyType", &linkkey_type)) {
+ bt_linkkey_file_found = true;
+ } else {
+ bt_linkkey_file_found = false;
+ }
+ }
+ if ((btif_in_fetch_bonded_ble_device(bdstr, false, NULL) !=
+ BT_STATUS_SUCCESS) &&
+ (!bt_linkkey_file_found)) {
+ BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", bdstr);
+ return BT_STATUS_FAIL;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_in_fetch_bonded_devices
+ *
+ * Description Internal helper function to fetch the bonded devices
+ * from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+static bt_status_t btif_in_fetch_bonded_devices(
+ btif_bonded_devices_t* p_bonded_devices, int add) {
+ memset(p_bonded_devices, 0, sizeof(btif_bonded_devices_t));
+
+ bool bt_linkkey_file_found = false;
+ int device_type;
+
+ for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+ iter != btif_config_section_end();
+ iter = btif_config_section_next(iter)) {
+ const char* name = btif_config_section_name(iter);
+ if (!string_is_bdaddr(name)) continue;
+
+ BTIF_TRACE_DEBUG("Remote device:%s", name);
+ LINK_KEY link_key;
+ size_t size = sizeof(link_key);
+ if (btif_config_get_bin(name, "LinkKey", link_key, &size)) {
+ int linkkey_type;
+ if (btif_config_get_int(name, "LinkKeyType", &linkkey_type)) {
+ bt_bdaddr_t bd_addr;
+ string_to_bdaddr(name, &bd_addr);
+ if (add) {
+ DEV_CLASS dev_class = {0, 0, 0};
+ int cod;
+ int pin_length = 0;
+ if (btif_config_get_int(name, "DevClass", &cod))
+ uint2devclass((uint32_t)cod, dev_class);
+ btif_config_get_int(name, "PinLength", &pin_length);
+ BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0,
+ (uint8_t)linkkey_type, 0, pin_length);
+
+ if (btif_config_get_int(name, "DevType", &device_type) &&
+ (device_type == BT_DEVICE_TYPE_DUMO)) {
+ btif_gatts_add_bonded_dev_from_nv(bd_addr.address);
+ }
+ }
+ bt_linkkey_file_found = true;
+ memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++],
+ &bd_addr, sizeof(bt_bdaddr_t));
+ } else {
+ bt_linkkey_file_found = false;
+ }
+ }
+ if (!btif_in_fetch_bonded_ble_device(name, add, p_bonded_devices) &&
+ !bt_linkkey_file_found) {
+ BTIF_TRACE_DEBUG("Remote device:%s, no link key or ble key found", name);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+static void btif_read_le_key(const uint8_t key_type, const size_t key_len,
+ bt_bdaddr_t bd_addr, const uint8_t addr_type,
+ const bool add_key, bool* device_added,
+ bool* key_found) {
+ CHECK(device_added);
+ CHECK(key_found);
+
+ char buffer[100];
+ memset(buffer, 0, sizeof(buffer));
+
+ if (btif_storage_get_ble_bonding_key(&bd_addr, key_type, buffer, key_len) ==
+ BT_STATUS_SUCCESS) {
+ if (add_key) {
+ BD_ADDR bta_bd_addr;
+ bdcpy(bta_bd_addr, bd_addr.address);
+
+ if (!*device_added) {
+ BTA_DmAddBleDevice(bta_bd_addr, addr_type, BT_DEVICE_TYPE_BLE);
+ *device_added = true;
+ }
+
+ char bd_str[20] = {0};
+ BTIF_TRACE_DEBUG("%s() Adding key type %d for %s", __func__, key_type,
+ bdaddr_to_string(&bd_addr, bd_str, sizeof(bd_str)));
+ BTA_DmAddBleKey(bta_bd_addr, (tBTA_LE_KEY_VALUE*)buffer, key_type);
+ }
+
+ *key_found = true;
+ }
+}
+
+/*******************************************************************************
+ * Functions
+ *
+ * Functions are synchronous and can be called by both from internal modules
+ * such as BTIF_DM and by external entiries from HAL via BTIF_context_switch.
+ * For OUT parameters, the caller is expected to provide the memory.
+ * Caller is expected to provide a valid pointer to 'property->value' based on
+ * the property->type.
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btif_split_uuids_string
+ *
+ * Description Internal helper function to split the string of UUIDs
+ * read from the NVRAM to an array
+ *
+ * Returns Number of UUIDs parsed from the supplied string
+ *
+ ******************************************************************************/
+size_t btif_split_uuids_string(const char* str, bt_uuid_t* p_uuid,
+ size_t max_uuids) {
+ CHECK(str);
+ CHECK(p_uuid);
+
+ size_t num_uuids = 0;
+ while (str && num_uuids < max_uuids) {
+ bool rc = string_to_uuid(str, p_uuid++);
+ if (!rc) break;
+ num_uuids++;
+ str = strchr(str, ' ');
+ if (str) str++;
+ }
+
+ return num_uuids;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_adapter_property
+ *
+ * Description BTIF storage API - Fetches the adapter property->type
+ * from NVRAM and fills property->val.
+ * Caller should provide memory for property->val and
+ * set the property->val
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_adapter_property(bt_property_t* property) {
+ /* Special handling for adapter BD_ADDR and BONDED_DEVICES */
+ if (property->type == BT_PROPERTY_BDADDR) {
+ bt_bdaddr_t* bd_addr = (bt_bdaddr_t*)property->val;
+ /* Fetch the local BD ADDR */
+ const controller_t* controller = controller_get_interface();
+ if (controller->get_is_ready() == false) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Controller not ready! Unable to return Bluetooth Address",
+ __func__);
+ memset(bd_addr, 0, sizeof(bt_bdaddr_t));
+ return BT_STATUS_FAIL;
+ } else {
+ LOG_ERROR(LOG_TAG, "%s: Controller ready!", __func__);
+ memcpy(bd_addr, controller->get_address(), sizeof(bt_bdaddr_t));
+ }
+ property->len = sizeof(bt_bdaddr_t);
+ return BT_STATUS_SUCCESS;
+ } else if (property->type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
+ btif_bonded_devices_t bonded_devices;
+
+ btif_in_fetch_bonded_devices(&bonded_devices, 0);
+
+ BTIF_TRACE_DEBUG(
+ "%s: Number of bonded devices: %d "
+ "Property:BT_PROPERTY_ADAPTER_BONDED_DEVICES",
+ __func__, bonded_devices.num_devices);
+
+ if (bonded_devices.num_devices > 0) {
+ property->len = bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ memcpy(property->val, bonded_devices.devices, property->len);
+ }
+
+ /* if there are no bonded_devices, then length shall be 0 */
+ return BT_STATUS_SUCCESS;
+ } else if (property->type == BT_PROPERTY_UUIDS) {
+ /* publish list of local supported services */
+ bt_uuid_t* p_uuid = (bt_uuid_t*)property->val;
+ uint32_t num_uuids = 0;
+ uint32_t i;
+
+ tBTA_SERVICE_MASK service_mask = btif_get_enabled_services_mask();
+ LOG_INFO(LOG_TAG, "%s service_mask:0x%x", __func__, service_mask);
+ for (i = 0; i < BTA_MAX_SERVICE_ID; i++) {
+ /* This should eventually become a function when more services are enabled
+ */
+ if (service_mask & (tBTA_SERVICE_MASK)(1 << i)) {
+ switch (i) {
+ case BTA_HFP_SERVICE_ID: {
+ uuid16_to_uuid128(UUID_SERVCLASS_AG_HANDSFREE, p_uuid + num_uuids);
+ num_uuids++;
+ }
+ /* intentional fall through: Send both BFP & HSP UUIDs if HFP is
+ * enabled */
+ case BTA_HSP_SERVICE_ID: {
+ uuid16_to_uuid128(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ p_uuid + num_uuids);
+ num_uuids++;
+ } break;
+ case BTA_A2DP_SOURCE_SERVICE_ID: {
+ uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SOURCE, p_uuid + num_uuids);
+ num_uuids++;
+ } break;
+ case BTA_A2DP_SINK_SERVICE_ID: {
+ uuid16_to_uuid128(UUID_SERVCLASS_AUDIO_SINK, p_uuid + num_uuids);
+ num_uuids++;
+ } break;
+ case BTA_HFP_HS_SERVICE_ID: {
+ uuid16_to_uuid128(UUID_SERVCLASS_HF_HANDSFREE, p_uuid + num_uuids);
+ num_uuids++;
+ } break;
+ }
+ }
+ }
+ property->len = (num_uuids) * sizeof(bt_uuid_t);
+ return BT_STATUS_SUCCESS;
+ }
+
+ /* fall through for other properties */
+ if (!cfg2prop(NULL, property)) {
+ return btif_dm_get_adapter_property(property);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_adapter_property
+ *
+ * Description BTIF storage API - Stores the adapter property
+ * to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_adapter_property(bt_property_t* property) {
+ return prop2cfg(NULL, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_remote_device_property
+ *
+ * Description BTIF storage API - Fetches the remote device property->type
+ * from NVRAM and fills property->val.
+ * Caller should provide memory for property->val and
+ * set the property->val
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+ bt_property_t* property) {
+ return cfg2prop(remote_bd_addr, property) ? BT_STATUS_SUCCESS
+ : BT_STATUS_FAIL;
+}
+/*******************************************************************************
+ *
+ * Function btif_storage_set_remote_device_property
+ *
+ * Description BTIF storage API - Stores the remote device property
+ * to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_remote_device_property(bt_bdaddr_t* remote_bd_addr,
+ bt_property_t* property) {
+ return prop2cfg(remote_bd_addr, property) ? BT_STATUS_SUCCESS
+ : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_remote_device
+ *
+ * Description BTIF storage API - Adds a newly discovered device to NVRAM
+ * along with the timestamp. Also, stores the various
+ * properties - RSSI, BDADDR, NAME (if found in EIR)
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_remote_device(bt_bdaddr_t* remote_bd_addr,
+ uint32_t num_properties,
+ bt_property_t* properties) {
+ uint32_t i = 0;
+ /* TODO: If writing a property, fails do we go back undo the earlier
+ * written properties? */
+ for (i = 0; i < num_properties; i++) {
+ /* Ignore the RSSI as this is not stored in DB */
+ if (properties[i].type == BT_PROPERTY_REMOTE_RSSI) continue;
+
+ /* BD_ADDR for remote device needs special handling as we also store
+ * timestamp */
+ if (properties[i].type == BT_PROPERTY_BDADDR) {
+ bt_property_t addr_prop;
+ memcpy(&addr_prop, &properties[i], sizeof(bt_property_t));
+ addr_prop.type = (bt_property_type_t)BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP;
+ btif_storage_set_remote_device_property(remote_bd_addr, &addr_prop);
+ } else {
+ btif_storage_set_remote_device_property(remote_bd_addr, &properties[i]);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_bonded_device
+ *
+ * Description BTIF storage API - Adds the newly bonded device to NVRAM
+ * along with the link-key, Key type and Pin key length
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_bonded_device(bt_bdaddr_t* remote_bd_addr,
+ LINK_KEY link_key, uint8_t key_type,
+ uint8_t pin_length) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
+ ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
+ ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
+
+ if (is_restricted_mode()) {
+ BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
+ __func__, bdstr);
+ btif_config_set_int(bdstr, "Restricted", 1);
+ }
+
+ /* write bonded info immediately */
+ btif_config_flush();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_bonded_device
+ *
+ * Description BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_bonded_device(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG("in bd addr:%s", bdstr);
+
+ btif_storage_remove_ble_bonding_keys(remote_bd_addr);
+
+ int ret = 1;
+ if (btif_config_exist(bdstr, "LinkKeyType"))
+ ret &= btif_config_remove(bdstr, "LinkKeyType");
+ if (btif_config_exist(bdstr, "PinLength"))
+ ret &= btif_config_remove(bdstr, "PinLength");
+ if (btif_config_exist(bdstr, "LinkKey"))
+ ret &= btif_config_remove(bdstr, "LinkKey");
+ /* write bonded info immediately */
+ btif_config_flush();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_load_bonded_devices
+ *
+ * Description BTIF storage API - Loads all the bonded devices from NVRAM
+ * and adds to the BTA.
+ * Additionally, this API also invokes the adaper_properties_cb
+ * and remote_device_properties_cb for each of the bonded
+ * devices.
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_devices(void) {
+ btif_bonded_devices_t bonded_devices;
+ uint32_t i = 0;
+ bt_property_t adapter_props[6];
+ uint32_t num_props = 0;
+ bt_property_t remote_properties[8];
+ bt_bdaddr_t addr;
+ bt_bdname_t name, alias;
+ bt_scan_mode_t mode;
+ uint32_t disc_timeout;
+ bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];
+ bt_uuid_t remote_uuids[BT_MAX_NUM_UUIDS];
+ bt_status_t status;
+
+ btif_in_fetch_bonded_devices(&bonded_devices, 1);
+
+ /* Now send the adapter_properties_cb with all adapter_properties */
+ {
+ memset(adapter_props, 0, sizeof(adapter_props));
+
+ /* BD_ADDR */
+ BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_BDADDR, &addr,
+ sizeof(addr), adapter_props[num_props]);
+ // Add BT_PROPERTY_BDADDR property into list only when successful.
+ // Otherwise, skip this property entry.
+ if (status == BT_STATUS_SUCCESS) {
+ num_props++;
+ }
+
+ /* BD_NAME */
+ BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_BDNAME, &name,
+ sizeof(name), adapter_props[num_props]);
+ num_props++;
+
+ /* SCAN_MODE */
+ /* TODO: At the time of BT on, always report the scan mode as 0 irrespective
+ of the scan_mode during the previous enable cycle.
+ This needs to be re-visited as part of the app/stack enable sequence
+ synchronization */
+ mode = BT_SCAN_MODE_NONE;
+ adapter_props[num_props].type = BT_PROPERTY_ADAPTER_SCAN_MODE;
+ adapter_props[num_props].len = sizeof(mode);
+ adapter_props[num_props].val = &mode;
+ num_props++;
+
+ /* DISC_TIMEOUT */
+ BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ &disc_timeout, sizeof(disc_timeout),
+ adapter_props[num_props]);
+ num_props++;
+
+ /* BONDED_DEVICES */
+ bt_bdaddr_t* devices_list = (bt_bdaddr_t*)osi_malloc(
+ sizeof(bt_bdaddr_t) * bonded_devices.num_devices);
+ adapter_props[num_props].type = BT_PROPERTY_ADAPTER_BONDED_DEVICES;
+ adapter_props[num_props].len =
+ bonded_devices.num_devices * sizeof(bt_bdaddr_t);
+ adapter_props[num_props].val = devices_list;
+ for (i = 0; i < bonded_devices.num_devices; i++) {
+ memcpy(devices_list + i, &bonded_devices.devices[i], sizeof(bt_bdaddr_t));
+ }
+ num_props++;
+
+ /* LOCAL UUIDs */
+ BTIF_STORAGE_GET_ADAPTER_PROP(status, BT_PROPERTY_UUIDS, local_uuids,
+ sizeof(local_uuids),
+ adapter_props[num_props]);
+ num_props++;
+
+ btif_adapter_properties_evt(BT_STATUS_SUCCESS, num_props, adapter_props);
+
+ osi_free(devices_list);
+ }
+
+ BTIF_TRACE_EVENT("%s: %d bonded devices found", __func__,
+ bonded_devices.num_devices);
+
+ {
+ for (i = 0; i < bonded_devices.num_devices; i++) {
+ bt_bdaddr_t* p_remote_addr;
+
+ /*
+ * TODO: improve handling of missing fields in NVRAM.
+ */
+ uint32_t cod = 0;
+ uint32_t devtype = 0;
+
+ num_props = 0;
+ p_remote_addr = &bonded_devices.devices[i];
+ memset(remote_properties, 0, sizeof(remote_properties));
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_BDNAME, &name,
+ sizeof(name), remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr,
+ BT_PROPERTY_REMOTE_FRIENDLY_NAME, &alias,
+ sizeof(alias), remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_CLASS_OF_DEVICE,
+ &cod, sizeof(cod),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_TYPE_OF_DEVICE,
+ &devtype, sizeof(devtype),
+ remote_properties[num_props]);
+ num_props++;
+
+ BTIF_STORAGE_GET_REMOTE_PROP(p_remote_addr, BT_PROPERTY_UUIDS,
+ remote_uuids, sizeof(remote_uuids),
+ remote_properties[num_props]);
+ num_props++;
+
+ btif_remote_properties_evt(BT_STATUS_SUCCESS, p_remote_addr, num_props,
+ remote_properties);
+ }
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_ble_bonding_key
+ *
+ * Description BTIF storage API - Adds the newly bonded device to NVRAM
+ * along with the ble-key, Key type and Pin key length
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+ char* key, uint8_t key_type,
+ uint8_t key_length) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ const char* name;
+ switch (key_type) {
+ case BTIF_DM_LE_KEY_PENC:
+ name = "LE_KEY_PENC";
+ break;
+ case BTIF_DM_LE_KEY_PID:
+ name = "LE_KEY_PID";
+ break;
+ case BTIF_DM_LE_KEY_PCSRK:
+ name = "LE_KEY_PCSRK";
+ break;
+ case BTIF_DM_LE_KEY_LENC:
+ name = "LE_KEY_LENC";
+ break;
+ case BTIF_DM_LE_KEY_LCSRK:
+ name = "LE_KEY_LCSRK";
+ break;
+ case BTIF_DM_LE_KEY_LID:
+ name = "LE_KEY_LID";
+ break;
+ default:
+ return BT_STATUS_FAIL;
+ }
+ int ret = btif_config_set_bin(bdstr, name, (const uint8_t*)key, key_length);
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_ble_bonding_key
+ *
+ * Description
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_ble_bonding_key(bt_bdaddr_t* remote_bd_addr,
+ uint8_t key_type, char* key_value,
+ int key_length) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ const char* name;
+ switch (key_type) {
+ case BTIF_DM_LE_KEY_PENC:
+ name = "LE_KEY_PENC";
+ break;
+ case BTIF_DM_LE_KEY_PID:
+ name = "LE_KEY_PID";
+ break;
+ case BTIF_DM_LE_KEY_PCSRK:
+ name = "LE_KEY_PCSRK";
+ break;
+ case BTIF_DM_LE_KEY_LENC:
+ name = "LE_KEY_LENC";
+ break;
+ case BTIF_DM_LE_KEY_LCSRK:
+ name = "LE_KEY_LCSRK";
+ break;
+ case BTIF_DM_LE_KEY_LID:
+ name = "LE_KEY_LID";
+ default:
+ return BT_STATUS_FAIL;
+ }
+ size_t length = key_length;
+ int ret = btif_config_get_bin(bdstr, name, (uint8_t*)key_value, &length);
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_ble_keys
+ *
+ * Description BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_ble_bonding_keys(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ BTIF_TRACE_DEBUG(" %s in bd addr:%s", __func__, bdstr);
+ int ret = 1;
+ if (btif_config_exist(bdstr, "LE_KEY_PENC"))
+ ret &= btif_config_remove(bdstr, "LE_KEY_PENC");
+ if (btif_config_exist(bdstr, "LE_KEY_PID"))
+ ret &= btif_config_remove(bdstr, "LE_KEY_PID");
+ if (btif_config_exist(bdstr, "LE_KEY_PCSRK"))
+ ret &= btif_config_remove(bdstr, "LE_KEY_PCSRK");
+ if (btif_config_exist(bdstr, "LE_KEY_LENC"))
+ ret &= btif_config_remove(bdstr, "LE_KEY_LENC");
+ if (btif_config_exist(bdstr, "LE_KEY_LCSRK"))
+ ret &= btif_config_remove(bdstr, "LE_KEY_LCSRK");
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_add_ble_local_key
+ *
+ * Description BTIF storage API - Adds the ble key to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_add_ble_local_key(char* key, uint8_t key_type,
+ uint8_t key_length) {
+ const char* name;
+ switch (key_type) {
+ case BTIF_DM_LE_LOCAL_KEY_IR:
+ name = "LE_LOCAL_KEY_IR";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_IRK:
+ name = "LE_LOCAL_KEY_IRK";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_DHK:
+ name = "LE_LOCAL_KEY_DHK";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_ER:
+ name = "LE_LOCAL_KEY_ER";
+ break;
+ default:
+ return BT_STATUS_FAIL;
+ }
+ int ret =
+ btif_config_set_bin("Adapter", name, (const uint8_t*)key, key_length);
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_ble_local_key
+ *
+ * Description
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_ble_local_key(uint8_t key_type, char* key_value,
+ int key_length) {
+ const char* name;
+ switch (key_type) {
+ case BTIF_DM_LE_LOCAL_KEY_IR:
+ name = "LE_LOCAL_KEY_IR";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_IRK:
+ name = "LE_LOCAL_KEY_IRK";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_DHK:
+ name = "LE_LOCAL_KEY_DHK";
+ break;
+ case BTIF_DM_LE_LOCAL_KEY_ER:
+ name = "LE_LOCAL_KEY_ER";
+ break;
+ default:
+ return BT_STATUS_FAIL;
+ }
+ size_t length = key_length;
+ int ret = btif_config_get_bin("Adapter", name, (uint8_t*)key_value, &length);
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_ble_local_keys
+ *
+ * Description BTIF storage API - Deletes the bonded device from NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_ble_local_keys(void) {
+ int ret = 1;
+ if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IR"))
+ ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IR");
+ if (btif_config_exist("Adapter", "LE_LOCAL_KEY_IRK"))
+ ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_IRK");
+ if (btif_config_exist("Adapter", "LE_LOCAL_KEY_DHK"))
+ ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_DHK");
+ if (btif_config_exist("Adapter", "LE_LOCAL_KEY_ER"))
+ ret &= btif_config_remove("Adapter", "LE_LOCAL_KEY_ER");
+ btif_config_save();
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+static bt_status_t btif_in_fetch_bonded_ble_device(
+ const char* remote_bd_addr, int add,
+ btif_bonded_devices_t* p_bonded_devices) {
+ int device_type;
+ int addr_type;
+ bt_bdaddr_t bd_addr;
+ BD_ADDR bta_bd_addr;
+ bool device_added = false;
+ bool key_found = false;
+
+ if (!btif_config_get_int(remote_bd_addr, "DevType", &device_type))
+ return BT_STATUS_FAIL;
+
+ if ((device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE ||
+ btif_has_ble_keys(remote_bd_addr)) {
+ BTIF_TRACE_DEBUG("%s Found a LE device: %s", __func__, remote_bd_addr);
+
+ string_to_bdaddr(remote_bd_addr, &bd_addr);
+ bdcpy(bta_bd_addr, bd_addr.address);
+
+ if (btif_storage_get_remote_addr_type(&bd_addr, &addr_type) !=
+ BT_STATUS_SUCCESS) {
+ addr_type = BLE_ADDR_PUBLIC;
+ btif_storage_set_remote_addr_type(&bd_addr, BLE_ADDR_PUBLIC);
+ }
+
+ btif_read_le_key(BTIF_DM_LE_KEY_PENC, sizeof(tBTM_LE_PENC_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ btif_read_le_key(BTIF_DM_LE_KEY_PID, sizeof(tBTM_LE_PID_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ btif_read_le_key(BTIF_DM_LE_KEY_LID, sizeof(tBTM_LE_PID_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ btif_read_le_key(BTIF_DM_LE_KEY_PCSRK, sizeof(tBTM_LE_PCSRK_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ btif_read_le_key(BTIF_DM_LE_KEY_LENC, sizeof(tBTM_LE_LENC_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ btif_read_le_key(BTIF_DM_LE_KEY_LCSRK, sizeof(tBTM_LE_LCSRK_KEYS), bd_addr,
+ addr_type, add, &device_added, &key_found);
+
+ // Fill in the bonded devices
+ if (device_added) {
+ memcpy(&p_bonded_devices->devices[p_bonded_devices->num_devices++],
+ &bd_addr, sizeof(bt_bdaddr_t));
+ btif_gatts_add_bonded_dev_from_nv(bta_bd_addr);
+ }
+
+ if (key_found) return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t btif_storage_set_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+ uint8_t addr_type) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ int ret = btif_config_set_int(bdstr, "AddrType", (int)addr_type);
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+bool btif_has_ble_keys(const char* bdstr) {
+ return btif_config_exist(bdstr, "LE_KEY_PENC");
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_get_remote_addr_type
+ *
+ * Description BTIF storage API - Fetches the remote addr type
+ *
+ * Returns BT_STATUS_SUCCESS if the fetch was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_get_remote_addr_type(bt_bdaddr_t* remote_bd_addr,
+ int* addr_type) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ int ret = btif_config_get_int(bdstr, "AddrType", addr_type);
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+/*******************************************************************************
+ *
+ * Function btif_storage_add_hid_device_info
+ *
+ * Description BTIF storage API - Adds the hid information of bonded hid
+ * devices-to NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the store was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+
+bt_status_t btif_storage_add_hid_device_info(
+ bt_bdaddr_t* remote_bd_addr, uint16_t attr_mask, uint8_t sub_class,
+ uint8_t app_id, uint16_t vendor_id, uint16_t product_id, uint16_t version,
+ uint8_t ctry_code, uint16_t ssr_max_latency, uint16_t ssr_min_tout,
+ uint16_t dl_len, uint8_t* dsc_list) {
+ bdstr_t bdstr;
+ BTIF_TRACE_DEBUG("btif_storage_add_hid_device_info:");
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ btif_config_set_int(bdstr, "HidAttrMask", attr_mask);
+ btif_config_set_int(bdstr, "HidSubClass", sub_class);
+ btif_config_set_int(bdstr, "HidAppId", app_id);
+ btif_config_set_int(bdstr, "HidVendorId", vendor_id);
+ btif_config_set_int(bdstr, "HidProductId", product_id);
+ btif_config_set_int(bdstr, "HidVersion", version);
+ btif_config_set_int(bdstr, "HidCountryCode", ctry_code);
+ btif_config_set_int(bdstr, "HidSSRMaxLatency", ssr_max_latency);
+ btif_config_set_int(bdstr, "HidSSRMinTimeout", ssr_min_tout);
+ if (dl_len > 0) btif_config_set_bin(bdstr, "HidDescriptor", dsc_list, dl_len);
+ btif_config_save();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_load_bonded_hid_info
+ *
+ * Description BTIF storage API - Loads hid info for all the bonded devices
+ * from NVRAM and adds those devices to the BTA_HH.
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_bonded_hid_info(void) {
+ bt_bdaddr_t bd_addr;
+ tBTA_HH_DEV_DSCP_INFO dscp_info;
+ uint16_t attr_mask;
+ uint8_t sub_class;
+ uint8_t app_id;
+
+ memset(&dscp_info, 0, sizeof(dscp_info));
+ for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+ iter != btif_config_section_end();
+ iter = btif_config_section_next(iter)) {
+ const char* name = btif_config_section_name(iter);
+ if (!string_is_bdaddr(name)) continue;
+
+ BTIF_TRACE_DEBUG("Remote device:%s", name);
+ int value;
+ if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
+ if (btif_config_get_int(name, "HidAttrMask", &value)) {
+ attr_mask = (uint16_t)value;
+
+ btif_config_get_int(name, "HidSubClass", &value);
+ sub_class = (uint8_t)value;
+
+ btif_config_get_int(name, "HidAppId", &value);
+ app_id = (uint8_t)value;
+
+ btif_config_get_int(name, "HidVendorId", &value);
+ dscp_info.vendor_id = (uint16_t)value;
+
+ btif_config_get_int(name, "HidProductId", &value);
+ dscp_info.product_id = (uint16_t)value;
+
+ btif_config_get_int(name, "HidVersion", &value);
+ dscp_info.version = (uint8_t)value;
+
+ btif_config_get_int(name, "HidCountryCode", &value);
+ dscp_info.ctry_code = (uint8_t)value;
+
+ value = 0;
+ btif_config_get_int(name, "HidSSRMaxLatency", &value);
+ dscp_info.ssr_max_latency = (uint16_t)value;
+
+ value = 0;
+ btif_config_get_int(name, "HidSSRMinTimeout", &value);
+ dscp_info.ssr_min_tout = (uint16_t)value;
+
+ size_t len = btif_config_get_bin_length(name, "HidDescriptor");
+ if (len > 0) {
+ dscp_info.descriptor.dl_len = (uint16_t)len;
+ dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len);
+ btif_config_get_bin(name, "HidDescriptor",
+ (uint8_t*)dscp_info.descriptor.dsc_list, &len);
+ }
+ string_to_bdaddr(name, &bd_addr);
+ // add extracted information to BTA HH
+ if (btif_hh_add_added_dev(bd_addr, attr_mask)) {
+ BTA_HhAddDev(bd_addr.address, attr_mask, sub_class, app_id,
+ dscp_info);
+ }
+ }
+ } else {
+ if (btif_config_get_int(name, "HidAttrMask", &value)) {
+ btif_storage_remove_hid_info(&bd_addr);
+ string_to_bdaddr(name, &bd_addr);
+ }
+ }
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hid_info
+ *
+ * Description BTIF storage API - Deletes the bonded hid device info from
+ * NVRAM
+ *
+ * Returns BT_STATUS_SUCCESS if the deletion was successful,
+ * BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+ btif_config_remove(bdstr, "HidAttrMask");
+ btif_config_remove(bdstr, "HidSubClass");
+ btif_config_remove(bdstr, "HidAppId");
+ btif_config_remove(bdstr, "HidVendorId");
+ btif_config_remove(bdstr, "HidProductId");
+ btif_config_remove(bdstr, "HidVersion");
+ btif_config_remove(bdstr, "HidCountryCode");
+ btif_config_remove(bdstr, "HidSSRMaxLatency");
+ btif_config_remove(bdstr, "HidSSRMinTimeout");
+ btif_config_remove(bdstr, "HidDescriptor");
+ btif_config_save();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_is_restricted_device
+ *
+ * Description BTIF storage API - checks if this device is a restricted
+ * device
+ *
+ * Returns true if the device is labeled as restricted
+ * false otherwise
+ *
+ ******************************************************************************/
+bool btif_storage_is_restricted_device(const bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+ return btif_config_exist(bdstr, "Restricted");
+}
+
+/*******************************************************************************
+ * Function btif_storage_load_hidd
+ *
+ * Description Loads hidd bonded device and "plugs" it into hidd
+ *
+ * Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_load_hidd(void) {
+ bt_bdaddr_t bd_addr;
+
+ for (const btif_config_section_iter_t* iter = btif_config_section_begin();
+ iter != btif_config_section_end();
+ iter = btif_config_section_next(iter)) {
+ const char* name = btif_config_section_name(iter);
+ if (!string_is_bdaddr(name)) continue;
+
+ BTIF_TRACE_DEBUG("Remote device:%s", name);
+ int value;
+ if (btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS) {
+ if (btif_config_get_int(name, "HidDeviceCabled", &value)) {
+ string_to_bdaddr(name, &bd_addr);
+ BTA_HdAddDevice(bd_addr.address);
+ break;
+ }
+ }
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_set_hidd
+ *
+ * Description Stores hidd bonded device info in nvram.
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_set_hidd(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr = {0};
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ btif_config_set_int(bdstr, "HidDeviceCabled", 1);
+ btif_config_save();
+ return BT_STATUS_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btif_storage_remove_hidd
+ *
+ * Description Removes hidd bonded device info from nvram
+ *
+ * Returns BT_STATUS_SUCCESS
+ *
+ ******************************************************************************/
+bt_status_t btif_storage_remove_hidd(bt_bdaddr_t* remote_bd_addr) {
+ bdstr_t bdstr;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+ btif_config_remove(bdstr, "HidDeviceCabled");
+ btif_config_save();
+
+ return BT_STATUS_SUCCESS;
+}
+
+// Get the name of a device from btif for interop database matching.
+bool btif_storage_get_stored_remote_name(const bt_bdaddr_t& bd_addr,
+ char* name) {
+ bt_property_t property;
+ property.type = BT_PROPERTY_BDNAME;
+ property.len = BTM_MAX_REM_BD_NAME_LEN;
+ property.val = name;
+
+ return (btif_storage_get_remote_device_property(
+ const_cast<bt_bdaddr_t*>(&bd_addr), &property) ==
+ BT_STATUS_SUCCESS);
+}
diff --git a/mtkbt/code/bt/btif/src/btif_uid.cc b/mtkbt/code/bt/btif/src/btif_uid.cc
new file mode 100755
index 0000000..45e3456
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_uid.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*******************************************************************************
+ *
+ * Filename: btif_uid.cc
+ *
+ * Description: Contains data structures and functions for keeping track of
+ * socket usage per app UID.
+ *
+ ******************************************************************************/
+#include <mutex>
+
+#include "bt_common.h"
+#include "btif_uid.h"
+
+typedef struct uid_set_node_t {
+ struct uid_set_node_t* next;
+ bt_uid_traffic_t data;
+} uid_set_node_t;
+
+typedef struct uid_set_t {
+ std::mutex lock;
+ uid_set_node_t* head;
+} uid_set_t;
+
+uid_set_t* uid_set_create(void) {
+ uid_set_t* set = (uid_set_t*)osi_calloc(sizeof(uid_set_t));
+ return set;
+}
+
+void uid_set_destroy(uid_set_t* set) {
+ std::unique_lock<std::mutex> lock(set->lock);
+ uid_set_node_t* node = set->head;
+ while (node) {
+ uid_set_node_t* temp = node;
+ node = node->next;
+ osi_free(temp);
+ }
+ set->head = NULL;
+ osi_free(set);
+}
+
+// Lock in uid_set_t must be held.
+static uid_set_node_t* uid_set_find_or_create_node(uid_set_t* set,
+ int32_t app_uid) {
+ uid_set_node_t* node = set->head;
+ while (node && node->data.app_uid != app_uid) {
+ node = node->next;
+ }
+
+ if (!node) {
+ node = (uid_set_node_t*)osi_calloc(sizeof(uid_set_node_t));
+ node->data.app_uid = app_uid;
+ node->next = set->head;
+ set->head = node;
+ }
+ return node;
+}
+
+void uid_set_add_tx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
+ if (app_uid == -1 || bytes == 0) return;
+
+ std::unique_lock<std::mutex> lock(set->lock);
+ uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
+ node->data.tx_bytes += bytes;
+}
+
+void uid_set_add_rx(uid_set_t* set, int32_t app_uid, uint64_t bytes) {
+ if (app_uid == -1 || bytes == 0) return;
+
+ std::unique_lock<std::mutex> lock(set->lock);
+ uid_set_node_t* node = uid_set_find_or_create_node(set, app_uid);
+ node->data.rx_bytes += bytes;
+}
+
+bt_uid_traffic_t* uid_set_read_and_clear(uid_set_t* set) {
+ std::unique_lock<std::mutex> lock(set->lock);
+
+ // Find the length
+ size_t len = 0;
+ uid_set_node_t* node = set->head;
+ while (node) {
+ len++;
+ node = node->next;
+ }
+
+ // Allocate an array of elements + 1, to signify the end with app_uid set to
+ // -1.
+ bt_uid_traffic_t* result =
+ (bt_uid_traffic_t*)osi_calloc(sizeof(bt_uid_traffic_t) * (len + 1));
+
+ bt_uid_traffic_t* data = result;
+ node = set->head;
+ while (node) {
+ // Copy the data.
+ *data = node->data;
+ data++;
+
+ // Clear the counters.
+ node->data.rx_bytes = 0;
+ node->data.tx_bytes = 0;
+ node = node->next;
+ }
+
+ // Mark the last entry
+ data->app_uid = -1;
+
+ return result;
+}
diff --git a/mtkbt/code/bt/btif/src/btif_util.cc b/mtkbt/code/bt/btif/src/btif_util.cc
new file mode 100755
index 0000000..c7d6539
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/btif_util.cc
@@ -0,0 +1,539 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 2009-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: btif_util.c
+ *
+ * Description: Miscellaneous helper functions
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btif_util"
+
+#include "btif_util.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/bt_av.h>
+
+#include "avrc_defs.h"
+#include "bt_common.h"
+#include "bta_ag_api.h"
+#include "bta_api.h"
+#include "bta_av_api.h"
+#include "bta_hd_api.h"
+#include "bta_hf_client_api.h"
+#include "bta_hh_api.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btif_dm.h"
+#include "btu.h"
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9'))
+#define ISXDIGIT(a) \
+ ((((a) >= '0') && ((a) <= '9')) || (((a) >= 'A') && ((a) <= 'F')) || \
+ (((a) >= 'a') && ((a) <= 'f')))
+
+/*******************************************************************************
+ * Local type definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+/*****************************************************************************
+ * Logging helper functions
+ ****************************************************************************/
+
+uint32_t devclass2uint(DEV_CLASS dev_class) {
+ uint32_t cod = 0;
+
+ if (dev_class != NULL) {
+ /* if COD is 0, irrespective of the device type set it to Unclassified
+ * device */
+ cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16);
+ }
+ return cod;
+}
+void uint2devclass(uint32_t cod, DEV_CLASS dev_class) {
+ dev_class[2] = (uint8_t)cod;
+ dev_class[1] = (uint8_t)(cod >> 8);
+ dev_class[0] = (uint8_t)(cod >> 16);
+}
+
+static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+
+void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t* uuid128) {
+ uint16_t uuid16_bo;
+ memset(uuid128, 0, sizeof(bt_uuid_t));
+
+ memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE);
+ uuid16_bo = ntohs(uuid16);
+ memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t));
+}
+
+bool string_to_uuid(const char* str, bt_uuid_t* p_uuid) {
+ CHECK(p_uuid);
+ if (str == NULL) return false;
+
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ int rc = sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx", &uuid0, &uuid1,
+ &uuid2, &uuid3, &uuid4, &uuid5);
+ if (rc != 6) return false;
+
+ uuid0 = htonl(uuid0);
+ uuid1 = htons(uuid1);
+ uuid2 = htons(uuid2);
+ uuid3 = htons(uuid3);
+ uuid4 = htonl(uuid4);
+ uuid5 = htons(uuid5);
+
+ memcpy(&(p_uuid->uu[0]), &uuid0, 4);
+ memcpy(&(p_uuid->uu[4]), &uuid1, 2);
+ memcpy(&(p_uuid->uu[6]), &uuid2, 2);
+ memcpy(&(p_uuid->uu[8]), &uuid3, 2);
+ memcpy(&(p_uuid->uu[10]), &uuid4, 4);
+ memcpy(&(p_uuid->uu[14]), &uuid5, 2);
+
+ return true;
+}
+
+void uuid_to_string_legacy(bt_uuid_t* p_uuid, char* str, size_t str_len) {
+ uint32_t uuid0, uuid4;
+ uint16_t uuid1, uuid2, uuid3, uuid5;
+
+ memcpy(&uuid0, &(p_uuid->uu[0]), 4);
+ memcpy(&uuid1, &(p_uuid->uu[4]), 2);
+ memcpy(&uuid2, &(p_uuid->uu[6]), 2);
+ memcpy(&uuid3, &(p_uuid->uu[8]), 2);
+ memcpy(&uuid4, &(p_uuid->uu[10]), 4);
+ memcpy(&uuid5, &(p_uuid->uu[14]), 2);
+
+ snprintf(str, str_len, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", ntohl(uuid0),
+ ntohs(uuid1), ntohs(uuid2), ntohs(uuid3), ntohl(uuid4),
+ ntohs(uuid5));
+ return;
+}
+
+/*****************************************************************************
+ * Function ascii_2_hex
+ *
+ * Description This function converts an ASCII string into HEX
+ *
+ * Returns the number of hex bytes filled.
+*/
+int ascii_2_hex(const char* p_ascii, int len, uint8_t* p_hex) {
+ int x;
+ uint8_t c;
+
+ for (x = 0; (x < len) && (*p_ascii); x++) {
+ if (ISDIGIT(*p_ascii))
+ c = (*p_ascii - '0') << 4;
+ else
+ c = (toupper(*p_ascii) - 'A' + 10) << 4;
+
+ p_ascii++;
+ if (*p_ascii) {
+ if (ISDIGIT(*p_ascii))
+ c |= (*p_ascii - '0');
+ else
+ c |= (toupper(*p_ascii) - 'A' + 10);
+
+ p_ascii++;
+ }
+ *p_hex++ = c;
+ }
+
+ return (x);
+}
+
+const char* dump_dm_search_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_DM_INQ_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_INQ_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_BLE_RES_EVT)
+ CASE_RETURN_STR(BTA_DM_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DI_DISC_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_SEARCH_CANCEL_CMPL_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_property_type(bt_property_type_t type) {
+ switch (type) {
+ CASE_RETURN_STR(BT_PROPERTY_BDNAME)
+ CASE_RETURN_STR(BT_PROPERTY_BDADDR)
+ CASE_RETURN_STR(BT_PROPERTY_UUIDS)
+ CASE_RETURN_STR(BT_PROPERTY_CLASS_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_TYPE_OF_DEVICE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_RSSI)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_BONDED_DEVICES)
+ CASE_RETURN_STR(BT_PROPERTY_ADAPTER_SCAN_MODE)
+ CASE_RETURN_STR(BT_PROPERTY_REMOTE_FRIENDLY_NAME)
+
+ default:
+ return "UNKNOWN PROPERTY ID";
+ }
+}
+
+const char* dump_dm_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_DM_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_DM_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_DM_PIN_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_AUTH_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_AUTHORIZE_EVT)
+ CASE_RETURN_STR(BTA_DM_LINK_UP_EVT)
+ CASE_RETURN_STR(BTA_DM_LINK_DOWN_EVT)
+ CASE_RETURN_STR(BTA_DM_SIG_STRENGTH_EVT)
+ CASE_RETURN_STR(BTA_DM_BUSY_LEVEL_EVT)
+ CASE_RETURN_STR(BTA_DM_BOND_CANCEL_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_CFM_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_KEY_NOTIF_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_RMT_OOB_EVT)
+ CASE_RETURN_STR(BTA_DM_SP_KEYPRESS_EVT)
+ CASE_RETURN_STR(BTA_DM_ROLE_CHG_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_KEY_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_SEC_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_NOTIF_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_PASSKEY_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_OOB_REQ_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_LOCAL_IR_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_LOCAL_ER_EVT)
+ CASE_RETURN_STR(BTA_DM_BLE_AUTH_CMPL_EVT)
+ CASE_RETURN_STR(BTA_DM_DEV_UNPAIRED_EVT)
+ CASE_RETURN_STR(BTA_DM_HW_ERROR_EVT)
+ CASE_RETURN_STR(BTA_DM_ENER_INFO_READ)
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(PIN_KEY_MISSING_HANDLE_UNPAIR)&&(PIN_KEY_MISSING_HANDLE_UNPAIR == TRUE)
+ CASE_RETURN_STR(BTA_DM_REPORT_BONDING_EVT)
+#endif
+#endif
+
+ default:
+ return "UNKNOWN DM EVENT";
+ }
+}
+
+const char* dump_hf_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_AG_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AG_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AG_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_CONN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_SPK_EVT)
+ CASE_RETURN_STR(BTA_AG_MIC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CKPD_EVT)
+ CASE_RETURN_STR(BTA_AG_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_AG_WBS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_A_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_D_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHLD_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHUP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_VTS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BINP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BLDN_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BVRA_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_NREC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CNUM_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BTRH_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CLCC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_COPS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_UNAT_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BIEV_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_client_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_HF_CLIENT_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CONN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_SPK_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_MIC_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_IND_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_VOICE_REC_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_OPERATOR_NAME_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CLIP_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CCWA_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_AT_RESULT_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CLCC_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_CNUM_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_BTRH_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_BSIR_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_BINP_EVT)
+ CASE_RETURN_STR(BTA_HF_CLIENT_RING_INDICATION)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hh_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_HH_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_HH_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_HH_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HH_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_DSCP_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_PROTO_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_RPT_EVT)
+ CASE_RETURN_STR(BTA_HH_GET_IDLE_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_PROTO_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_RPT_EVT)
+ CASE_RETURN_STR(BTA_HH_SET_IDLE_EVT)
+ CASE_RETURN_STR(BTA_HH_VC_UNPLUG_EVT)
+ CASE_RETURN_STR(BTA_HH_ADD_DEV_EVT)
+ CASE_RETURN_STR(BTA_HH_RMV_DEV_EVT)
+ CASE_RETURN_STR(BTA_HH_API_ERR_EVT)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_conn_state(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_SLC_CONNECTED)
+ CASE_RETURN_STR(BTHF_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hd_event(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_HD_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_HD_DISABLE_EVT)
+ CASE_RETURN_STR(BTA_HD_REGISTER_APP_EVT)
+ CASE_RETURN_STR(BTA_HD_UNREGISTER_APP_EVT)
+ CASE_RETURN_STR(BTA_HD_OPEN_EVT)
+ CASE_RETURN_STR(BTA_HD_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_HD_GET_REPORT_EVT)
+ CASE_RETURN_STR(BTA_HD_SET_REPORT_EVT)
+ CASE_RETURN_STR(BTA_HD_SET_PROTOCOL_EVT)
+ CASE_RETURN_STR(BTA_HD_INTR_DATA_EVT)
+ CASE_RETURN_STR(BTA_HD_VC_UNPLUG_EVT)
+ CASE_RETURN_STR(BTA_HD_CONN_STATE_EVT)
+ CASE_RETURN_STR(BTA_HD_API_ERR_EVT)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_call_state(bthf_call_state_t call_state) {
+ switch (call_state) {
+ CASE_RETURN_STR(BTHF_CALL_STATE_IDLE)
+ CASE_RETURN_STR(BTHF_CALL_STATE_HELD)
+ CASE_RETURN_STR(BTHF_CALL_STATE_DIALING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ALERTING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_INCOMING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_WAITING)
+ CASE_RETURN_STR(BTHF_CALL_STATE_ACTIVE)
+ default:
+ return "UNKNOWN CALL STATE";
+ }
+}
+
+const char* dump_thread_evt(bt_cb_thread_evt evt) {
+ switch (evt) {
+ CASE_RETURN_STR(ASSOCIATE_JVM)
+ CASE_RETURN_STR(DISASSOCIATE_JVM)
+
+ default:
+ return "unknown thread evt";
+ }
+}
+
+const char* dump_hf_audio_state(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTING)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_CONNECTED)
+ CASE_RETURN_STR(BTHF_AUDIO_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_av_conn_state(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(BTAV_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_av_audio_state(uint16_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_REMOTE_SUSPEND)
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_STOPPED)
+ CASE_RETURN_STR(BTAV_AUDIO_STATE_STARTED)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_adapter_scan_mode(bt_scan_mode_t mode) {
+ switch (mode) {
+ CASE_RETURN_STR(BT_SCAN_MODE_NONE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE)
+ CASE_RETURN_STR(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char* dump_bt_status(bt_status_t status) {
+ switch (status) {
+ CASE_RETURN_STR(BT_STATUS_SUCCESS)
+ CASE_RETURN_STR(BT_STATUS_FAIL)
+ CASE_RETURN_STR(BT_STATUS_NOT_READY)
+ CASE_RETURN_STR(BT_STATUS_NOMEM)
+ CASE_RETURN_STR(BT_STATUS_BUSY)
+ CASE_RETURN_STR(BT_STATUS_UNSUPPORTED)
+
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char* dump_rc_event(uint8_t event) {
+ switch (event) {
+ CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_BROWSE_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_BROWSE_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
+ CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
+ CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
+ CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
+ default:
+ return "UNKNOWN_EVENT";
+ }
+}
+
+const char* dump_rc_notification_event_id(uint8_t event_id) {
+ switch (event_id) {
+ CASE_RETURN_STR(AVRC_EVT_PLAY_STATUS_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_TRACK_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_END)
+ CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_START)
+ CASE_RETURN_STR(AVRC_EVT_PLAY_POS_CHANGED)
+ CASE_RETURN_STR(AVRC_EVT_BATTERY_STATUS_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_ADDR_PLAYER_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_AVAL_PLAYERS_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_NOW_PLAYING_CHANGE)
+ CASE_RETURN_STR(AVRC_EVT_UIDS_CHANGE)
+
+ default:
+ return "Unhandled Event ID";
+ }
+}
+
+const char* dump_rc_pdu(uint8_t pdu) {
+ switch (pdu) {
+ CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_ATTR)
+ CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_VALUES)
+ CASE_RETURN_STR(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE)
+ CASE_RETURN_STR(AVRC_PDU_SET_PLAYER_APP_VALUE)
+ CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT)
+ CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT)
+ CASE_RETURN_STR(AVRC_PDU_INFORM_DISPLAY_CHARSET)
+ CASE_RETURN_STR(AVRC_PDU_INFORM_BATTERY_STAT_OF_CT)
+ CASE_RETURN_STR(AVRC_PDU_GET_ELEMENT_ATTR)
+ CASE_RETURN_STR(AVRC_PDU_GET_PLAY_STATUS)
+ CASE_RETURN_STR(AVRC_PDU_REGISTER_NOTIFICATION)
+ CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP)
+ CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP)
+ CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME)
+ CASE_RETURN_STR(AVRC_PDU_SET_ADDRESSED_PLAYER)
+ CASE_RETURN_STR(AVRC_PDU_CHANGE_PATH)
+ CASE_RETURN_STR(AVRC_PDU_GET_CAPABILITIES)
+ CASE_RETURN_STR(AVRC_PDU_SET_BROWSED_PLAYER)
+ CASE_RETURN_STR(AVRC_PDU_GET_FOLDER_ITEMS)
+ CASE_RETURN_STR(AVRC_PDU_GET_ITEM_ATTRIBUTES)
+ CASE_RETURN_STR(AVRC_PDU_PLAY_ITEM)
+ CASE_RETURN_STR(AVRC_PDU_SEARCH)
+ CASE_RETURN_STR(AVRC_PDU_ADD_TO_NOW_PLAYING)
+ CASE_RETURN_STR(AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS)
+ CASE_RETURN_STR(AVRC_PDU_GENERAL_REJECT)
+
+ default:
+ return "Unknown PDU";
+ }
+}
diff --git a/mtkbt/code/bt/btif/src/stack_manager.cc b/mtkbt/code/bt/btif/src/stack_manager.cc
new file mode 100755
index 0000000..83522cb
--- a/dev/null
+++ b/mtkbt/code/bt/btif/src/stack_manager.cc
@@ -0,0 +1,251 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_stack_manager"
+
+#include "stack_manager.h"
+
+#include <hardware/bluetooth.h>
+
+#include "btcore/include/module.h"
+#include "btcore/include/osi_module.h"
+#include "btif_api.h"
+#include "btif_common.h"
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+// Temp includes
+#include "bt_utils.h"
+#include "btif_config.h"
+#include "btif_profile_queue.h"
+
+static thread_t* management_thread;
+
+// If initialized, any of the bluetooth API functions can be called.
+// (e.g. turning logging on and off, enabling/disabling the stack, etc)
+static bool stack_is_initialized;
+// If running, the stack is fully up and able to bluetooth.
+static bool stack_is_running;
+
+static void event_init_stack(void* context);
+static void event_start_up_stack(void* context);
+static void event_shut_down_stack(void* context);
+static void event_clean_up_stack(void* context);
+
+static void event_signal_stack_up(void* context);
+static void event_signal_stack_down(void* context);
+
+// Unvetted includes/imports, etc which should be removed or vetted in the
+// future
+static future_t* hack_future;
+void btif_thread_post(thread_fn func, void* context);
+// End unvetted section
+
+// Interface functions
+
+static void init_stack(void) {
+ // This is a synchronous process. Post it to the thread though, so
+ // state modification only happens there. Using the thread to perform
+ // all stack operations ensures that the operations are done serially
+ // and do not overlap.
+ semaphore_t* semaphore = semaphore_new(0);
+ thread_post(management_thread, event_init_stack, semaphore);
+ semaphore_wait(semaphore);
+ semaphore_free(semaphore);
+}
+
+static void start_up_stack_async(void) {
+ thread_post(management_thread, event_start_up_stack, NULL);
+}
+
+static void shut_down_stack_async(void) {
+ thread_post(management_thread, event_shut_down_stack, NULL);
+}
+
+static void clean_up_stack(void) {
+ // This is a synchronous process. Post it to the thread though, so
+ // state modification only happens there.
+ semaphore_t* semaphore = semaphore_new(0);
+ thread_post(management_thread, event_clean_up_stack, semaphore);
+ semaphore_wait(semaphore);
+ semaphore_free(semaphore);
+}
+
+static bool get_stack_is_running(void) { return stack_is_running; }
+
+// Internal functions
+
+// Synchronous function to initialize the stack
+static void event_init_stack(void* context) {
+ semaphore_t* semaphore = (semaphore_t*)context;
+
+ LOG_INFO(LOG_TAG, "%s is initializing the stack", __func__);
+
+ if (stack_is_initialized) {
+ LOG_INFO(LOG_TAG, "%s found the stack already in initialized state",
+ __func__);
+ } else {
+ module_management_start();
+
+ module_init(get_module(OSI_MODULE));
+ module_init(get_module(BT_UTILS_MODULE));
+ module_init(get_module(BTIF_CONFIG_MODULE));
+ btif_init_bluetooth();
+
+ // stack init is synchronous, so no waiting necessary here
+ stack_is_initialized = true;
+ }
+
+ LOG_INFO(LOG_TAG, "%s finished", __func__);
+
+ if (semaphore) semaphore_post(semaphore);
+}
+
+static void ensure_stack_is_initialized(void) {
+ if (!stack_is_initialized) {
+ LOG_WARN(LOG_TAG, "%s found the stack was uninitialized. Initializing now.",
+ __func__);
+ // No semaphore needed since we are calling it directly
+ event_init_stack(NULL);
+ }
+}
+
+// Synchronous function to start up the stack
+static void event_start_up_stack(UNUSED_ATTR void* context) {
+ if (stack_is_running) {
+ LOG_INFO(LOG_TAG, "%s stack already brought up", __func__);
+ return;
+ }
+
+ ensure_stack_is_initialized();
+
+ LOG_INFO(LOG_TAG, "%s is bringing up the stack", __func__);
+ future_t* local_hack_future = future_new();
+ hack_future = local_hack_future;
+
+ // Include this for now to put btif config into a shutdown-able state
+ module_start_up(get_module(BTIF_CONFIG_MODULE));
+ bte_main_enable();
+
+ if (future_await(local_hack_future) != FUTURE_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s failed to start up the stack", __func__);
+ stack_is_running = true; // So stack shutdown actually happens
+ event_shut_down_stack(NULL);
+ return;
+ }
+
+ stack_is_running = true;
+ LOG_INFO(LOG_TAG, "%s finished", __func__);
+ btif_thread_post(event_signal_stack_up, NULL);
+}
+
+// Synchronous function to shut down the stack
+static void event_shut_down_stack(UNUSED_ATTR void* context) {
+ if (!stack_is_running) {
+ LOG_INFO(LOG_TAG, "%s stack is already brought down", __func__);
+ return;
+ }
+
+ LOG_INFO(LOG_TAG, "%s is bringing down the stack", __func__);
+ future_t* local_hack_future = future_new();
+ hack_future = local_hack_future;
+ stack_is_running = false;
+
+ btif_disable_bluetooth();
+ module_shut_down(get_module(BTIF_CONFIG_MODULE));
+
+ future_await(local_hack_future);
+ module_shut_down(get_module(CONTROLLER_MODULE)); // Doesn't do any work, just
+ // puts it in a restartable
+ // state
+
+ LOG_INFO(LOG_TAG, "%s finished", __func__);
+ hack_future = future_new();
+ btif_thread_post(event_signal_stack_down, NULL);
+ future_await(hack_future);
+}
+
+static void ensure_stack_is_not_running(void) {
+ if (stack_is_running) {
+ LOG_WARN(LOG_TAG,
+ "%s found the stack was still running. Bringing it down now.",
+ __func__);
+ event_shut_down_stack(NULL);
+ }
+}
+
+// Synchronous function to clean up the stack
+static void event_clean_up_stack(void* context) {
+ if (!stack_is_initialized) {
+ LOG_INFO(LOG_TAG, "%s found the stack already in a clean state", __func__);
+ goto cleanup;
+ }
+
+ ensure_stack_is_not_running();
+
+ LOG_INFO(LOG_TAG, "%s is cleaning up the stack", __func__);
+ stack_is_initialized = false;
+
+ btif_cleanup_bluetooth();
+ module_clean_up(get_module(BTIF_CONFIG_MODULE));
+ module_clean_up(get_module(BT_UTILS_MODULE));
+ module_clean_up(get_module(OSI_MODULE));
+ module_management_stop();
+ LOG_INFO(LOG_TAG, "%s finished", __func__);
+
+cleanup:;
+ semaphore_t* semaphore = (semaphore_t*)context;
+ if (semaphore) semaphore_post(semaphore);
+}
+
+static void event_signal_stack_up(UNUSED_ATTR void* context) {
+ // Notify BTIF connect queue that we've brought up the stack. It's
+ // now time to dispatch all the pending profile connect requests.
+ btif_queue_connect_next();
+ HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_ON);
+}
+
+static void event_signal_stack_down(UNUSED_ATTR void* context) {
+ HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF);
+ future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);
+}
+
+static void ensure_manager_initialized(void) {
+ if (management_thread) return;
+
+ management_thread = thread_new("stack_manager");
+ if (!management_thread) {
+ LOG_ERROR(LOG_TAG, "%s unable to create stack management thread", __func__);
+ return;
+ }
+}
+
+static const stack_manager_t interface = {init_stack, start_up_stack_async,
+ shut_down_stack_async, clean_up_stack,
+
+ get_stack_is_running};
+
+const stack_manager_t* stack_manager_get_interface() {
+ ensure_manager_initialized();
+ return &interface;
+}
+
+future_t* stack_manager_get_hack_future() { return hack_future; }
diff --git a/mtkbt/code/bt/btif/test/btif_storage_test.cc b/mtkbt/code/bt/btif/test/btif_storage_test.cc
new file mode 100755
index 0000000..988e23f
--- a/dev/null
+++ b/mtkbt/code/bt/btif/test/btif_storage_test.cc
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "btif/include/btif_storage.h"
+#include "btif/include/btif_util.h"
+
+TEST(BtifStorageTest, test_string_to_uuid) {
+ const char* s1 = "e39c6285-867f-4b1d-9db0-35fbd9aebf22";
+ const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+ 0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+
+ bt_uuid_t uuid;
+ memset(&uuid, 0, sizeof(uuid));
+ EXPECT_FALSE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+
+ bool rc = string_to_uuid(s1, &uuid);
+ EXPECT_TRUE(rc);
+ EXPECT_TRUE(memcmp(&uuid, u1, sizeof(u1)) == 0);
+}
+
+TEST(BtifStorageTest, test_string_to_uuid_invalid) {
+ bt_uuid_t uuid;
+ bool rc = string_to_uuid("This is not a UUID", &uuid);
+ EXPECT_FALSE(rc);
+}
+
+TEST(BtifStorageTest, test_uuid_split_multiple) {
+ const char* s1 =
+ "e39c6285-867f-4b1d-9db0-35fbd9aebf22 "
+ "e39c6285-867f-4b1d-9db0-35fbd9aebf23";
+ const uint8_t u1[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+ 0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x22};
+ const uint8_t u2[] = {0xe3, 0x9c, 0x62, 0x85, 0x86, 0x7f, 0x4b, 0x1d,
+ 0x9d, 0xb0, 0x35, 0xfb, 0xd9, 0xae, 0xbf, 0x23};
+
+ bt_uuid_t uuids[2];
+ size_t num_uuids = btif_split_uuids_string(s1, uuids, 2);
+ EXPECT_EQ(num_uuids, 2u);
+ EXPECT_TRUE(memcmp(&uuids[0], u1, sizeof(u1)) == 0);
+ EXPECT_TRUE(memcmp(&uuids[1], u2, sizeof(u2)) == 0);
+}
+
+TEST(BtifStorageTest, test_uuid_split_partial) {
+ const char* s1 =
+ "e39c6285-867f-4b1d-9db0-35fbd9aebf22 "
+ "e39c6285-867f-4b1d-9db0-35fbd9aebf23";
+
+ bt_uuid_t uuids[2];
+ size_t num_uuids = btif_split_uuids_string(s1, uuids, 1);
+ EXPECT_EQ(num_uuids, 1u);
+}
diff --git a/mtkbt/code/bt/build/Android.bp b/mtkbt/code/bt/build/Android.bp
new file mode 100755
index 0000000..ddf27ac
--- a/dev/null
+++ b/mtkbt/code/bt/build/Android.bp
@@ -0,0 +1,47 @@
+bootstrap_go_package {
+ name: "soong-fluoride",
+ pkgPath: "android/soong/fluoride",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "soong",
+ "soong-android",
+ "soong-cc",
+ ],
+ srcs: [
+ "fluoride.go",
+ "mediatek.go"
+ ],
+ pluginFor: ["soong_build"],
+}
+
+fluoride_defaults {
+ name: "fluoride_defaults",
+ cflags: [
+ "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ // struct BT_HDR is defined as a variable-size header in a struct.
+ "-Wno-gnu-variable-sized-type-not-at-end",
+ // needed because of the way the struct typedef is done in osi/include
+ // header files. This issue can be obsoleted by switching to C11 or C++.
+ "-Wno-typedef-redefinition",
+ // there are too many unused parameters in all the code.
+ "-Wno-unused-parameter",
+ "-DLOG_NDEBUG=1",
+ ],
+ conlyflags: [
+ "-std=c99",
+ ],
+ product_variables: {
+ debuggable: {
+ cflags: [
+ "-DDCHECK_ALWAYS_ON"
+ ],
+ },
+ },
+ shared_libs: [ "libchrome" ]
+ // Setup Bluetooth local make variables for handling configuration
+}
diff --git a/mtkbt/code/bt/build/BUILD.gn b/mtkbt/code/bt/build/BUILD.gn
new file mode 100755
index 0000000..ebebf3d
--- a/dev/null
+++ b/mtkbt/code/bt/build/BUILD.gn
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+config("default_include_dirs") {
+ include_dirs = [
+ "//third_party/libhardware/include/",
+ ]
+}
+
+config("linux") {
+ # TODO(keybuk): AndroidConfig.h or equivalent
+
+ cflags = [
+ #TODO(jpawlowski): uncomment once we have no warnings on linux build
+ # "-Wall",
+ # "-Werror",
+ "-g",
+ "-O0",
+ "-fpic",
+ "-fdata-sections",
+ "-ffunction-sections",
+ "-fvisibility=hidden",
+ ]
+
+ cflags_c = [ "-std=c99" ]
+
+ cflags_cc = [
+#TODO(jpawlowski): we should use same c++ version as Android, which is c++11,
+# but we use some c++14 features. Uncomment when this get fixed in code.:
+ "-std=c++14",
+ "-fno-exceptions",
+ "-fpermissive",
+ ]
+
+ defines = [
+ "_FORTIFY_SOURCE=2",
+ "_GNU_SOURCE",
+ "HAS_NO_BDROID_BUILDCFG",
+ "LOG_NDEBUG=1",
+ "EXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
+ "KERNEL_MISSING_CLOCK_BOOTTIME_ALARM=TRUE",
+
+ # This is a macro to that can be used by android hardware/libhardware
+ # to not include dependencies on core project. This is a temporary
+ # workaround until we get rid of dependency on hardware.
+ "_HW_DONT_INCLUDE_CORE_=1",
+
+ # This is a macro to that can be used by source code to detect if the
+ # current build is done by GN or via Android.mk. This is a temporary
+ # workaround until we can remove all Android-specific dependencies.
+ "OS_GENERIC",
+ ]
+}
+
+config("pic") {
+ cflags = [ "-fPIC" ]
+}
+
+config("gc") {
+ ldflags = [ "-Wl,--gc-sections" ]
+}
diff --git a/mtkbt/code/bt/build/config/BUILDCONFIG.gn b/mtkbt/code/bt/build/config/BUILDCONFIG.gn
new file mode 100755
index 0000000..148230b
--- a/dev/null
+++ b/mtkbt/code/bt/build/config/BUILDCONFIG.gn
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set_default_toolchain("//build/toolchain/clang")
+toolchain_config="//build/toolchain/clang:clang_config"
+
+set_defaults("executable") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ toolchain_config,
+ ]
+}
+
+set_defaults("shared_library") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ toolchain_config,
+ ]
+}
+
+set_defaults("source_set") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ toolchain_config,
+ ]
+}
+
+set_defaults("static_library") {
+ configs = [
+ "//build:linux",
+ "//build:gc",
+ "//build:default_include_dirs",
+ toolchain_config,
+ ]
+}
diff --git a/mtkbt/code/bt/build/fluoride.go b/mtkbt/code/bt/build/fluoride.go
new file mode 100755
index 0000000..5a587ae
--- a/dev/null
+++ b/mtkbt/code/bt/build/fluoride.go
@@ -0,0 +1,69 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package fluoride
+
+import (
+ "strings"
+
+ "android/soong/android"
+ "android/soong/cc"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ android.RegisterModuleType("fluoride_defaults", fluorideDefaultsFactory)
+}
+
+func fluorideDefaultsFactory() (blueprint.Module, []interface{}) {
+ module, props := cc.DefaultsFactory()
+ android.AddLoadHook(module, fluorideDefaults)
+
+ return module, props
+}
+
+func fluorideDefaults(ctx android.LoadHookContext) {
+ type props struct {
+ Include_dirs []string
+ Cflags []string
+ }
+
+ p := &props{}
+ p.Cflags, p.Include_dirs = globalDefaults(ctx)
+
+ ctx.AppendProperties(p)
+}
+
+func globalDefaults(ctx android.BaseContext) ([]string, []string) {
+ var cflags []string
+ var includeDirs []string
+
+ board_bt_buildcfg_include_dir := ctx.DeviceConfig().BtConfigIncludeDir()
+ if (len(board_bt_buildcfg_include_dir) > 0) {
+ cflags = append(cflags, "-DHAS_BDROID_BUILDCFG")
+ board_bt_buildcfg_include_dir_list :=
+ strings.Fields(board_bt_buildcfg_include_dir)
+ for _, buildcfg_dir := range board_bt_buildcfg_include_dir_list {
+ includeDirs = append(includeDirs, buildcfg_dir)
+ }
+ } else {
+ cflags = append(cflags, "-DHAS_NO_BDROID_BUILDCFG")
+ }
+
+ /** M: Load Mediatek defined build config @{ */
+ mtkGlobalDefaults(&cflags, &includeDirs)
+ /** @} */
+
+ return cflags, includeDirs
+}
diff --git a/mtkbt/code/bt/build/install_deps.sh b/mtkbt/code/bt/build/install_deps.sh
new file mode 100755
index 0000000..f1173a9
--- a/dev/null
+++ b/mtkbt/code/bt/build/install_deps.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+CLANG_PACKAGE=clang
+GNSHA1_URL="https://chromium.googlesource.com/chromium/buildtools/\
++/master/linux64/gn.sha1?format=TEXT"
+
+# Check if clang is already installed on current system
+clang_path=`which clang`
+if [ -f "$clang_path" ]; then
+ # if clang binary is avalable, check its version
+ clang_version=$($clang_path --version | grep clang | sed "s/.*version\s*\([0-9]*\.[0-9]*\).*/\1/")
+ IFS="." read -ra clang_version_array <<< "$clang_version"
+ clang_version_major=${clang_version_array[0]}
+ clang_version_minor=${clang_version_array[1]}
+ # if the version is greater than 3.5 then do not install clang here
+ if [ $clang_version_major -ge 3 ] && [ $clang_version_minor -ge 5 ]; then
+ echo "Detected clang $clang_version"
+ CLANG_PACKAGE=""
+ fi
+fi
+
+if [ ! -z "$CLANG_PACKAGE" ]; then
+ # Try to find clang from a known list
+ for clang_version in 3.9 3.8 3.7 3.6 3.5
+ do
+ clang_path=`which clang-$clang_version`
+ if [ -f "$clang_path" ]; then
+ echo "Detected clang-$clang_version"
+ CLANG_PACKAGE=""
+ break
+ fi
+ done
+fi
+
+if [ ! -z "$CLANG_PACKAGE" ]; then
+ echo "clang not found on current system, installing"
+ if [ -f /etc/lsb-release ]; then
+ # Ubuntu
+ ubuntu_version=$(lsb_release --release --short)
+ IFS="." read -ra ubuntu_version_array <<< "$ubuntu_version"
+ ubuntu_version_major=${ubuntu_version_array[0]}
+ ubuntu_version_minor=${ubuntu_version_array[1]}
+ if [ $ubuntu_version_major -lt 15 ]; then
+ echo "Choose clang-3.8 for Ubuntu 14 and below"
+ CLANG_PACKAGE=clang-3.8
+ fi
+ fi
+fi
+
+sudo apt-get -y install $CLANG_PACKAGE libevent-dev libc++-dev libc++abi-dev \
+ ninja-build
+gn_path=`which gn`
+if [ -z $gn_path ]; then
+ gnsha1=$(curl $GNSHA1_URL | base64 -d)
+ wget -O gn http://storage.googleapis.com/chromium-gn/$gnsha1
+ chmod a+x ./gn
+ sudo mv ./gn /usr/bin/
+fi
diff --git a/mtkbt/code/bt/build/mediatek.go b/mtkbt/code/bt/build/mediatek.go
new file mode 100755
index 0000000..e39effa
--- a/dev/null
+++ b/mtkbt/code/bt/build/mediatek.go
@@ -0,0 +1,36 @@
+package fluoride
+
+import (
+ //"android/soong/android"
+)
+
+func mtkGlobalDefaults(cflags *[]string, includeDirs *[]string) {
+ //featureValue :=android.MtkFeatureValues
+ //_ = featureValue
+
+ /************************************************
+ * ** General Config
+ * ***********************************************/
+ *cflags = append(*cflags, "-DHAS_MDROID_BUILDCFG")
+ *includeDirs = append(*includeDirs, "vendor/mediatek/limit_open/system/bt/mediatek/include")
+
+ // MTK interop extension
+ //if v, found := featureValue["MTK_BT_INTEROP_EXTENSION"]; found{
+ //if(v == "yes"){
+ //*cflags = append(*cflags, "-DMTK_INTEROP_EXTENSION=TRUE")
+ //}
+ //}
+ *cflags = append(*cflags, "-DMTK_INTEROP_EXTENSION=TRUE")
+
+ // MTK a2dp hal layer PCM dump
+ *cflags = append(*cflags, "-DMTK_A2DP_PCM_DUMP=TRUE")
+
+ // MTK Enable HID_HOST_ACPT_NEW_CONN
+ *cflags = append(*cflags, "-DHID_HOST_ACPT_NEW_CONN=TRUE")
+
+ // Enable BLE VND Feature for MTK BT
+ *cflags = append(*cflags, "-DBLE_VND_INCLUDED=TRUE")
+
+ // MTK support customized snoop log
+ *cflags = append(*cflags, "-DMTK_STACK_CONFIG_LOG=TRUE")
+}
diff --git a/mtkbt/code/bt/build/toolchain/clang/BUILD.gn b/mtkbt/code/bt/build/toolchain/clang/BUILD.gn
new file mode 100755
index 0000000..fcd6d56
--- a/dev/null
+++ b/mtkbt/code/bt/build/toolchain/clang/BUILD.gn
@@ -0,0 +1,116 @@
+#
+# Copyright (C) 2016 Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+clang_suffix = exec_script("get_clang_suffix.py", [], "list lines")
+clang_suffix = clang_suffix[0]
+assert(clang_suffix != "None",
+ "Cannot find clang, please install clang 3.5 or above")
+if (clang_suffix != "") {
+ clang_suffix = "-" + clang_suffix
+}
+clang = "clang$clang_suffix"
+clangxx = "clang++$clang_suffix"
+
+config("clang_config") {
+ include_dirs = [
+ "/usr/include/libcxxabi",
+ ]
+ cflags_cc = [
+ "-stdlib=libc++",
+ ]
+ ldflags = [
+ "-stdlib=libc++",
+ ]
+}
+
+toolchain("clang") {
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$clang -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CC {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$clangxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CXX {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+ command = "rm -f {{output}} && ar rcs {{output}} @$rspfile"
+ description = "AR {{target_output_name}}{{output_extension}}"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ default_output_extension = ".a"
+
+ output_prefix = "lib"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ rspfile = soname + ".rsp"
+
+ command =
+ "$clangxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile"
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+ description = "SOLINK $soname"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ default_output_extension = ".so"
+
+ outputs = [
+ soname,
+ ]
+ link_output = soname
+ depend_output = soname
+
+ output_prefix = "lib"
+ }
+
+ tool("link") {
+ outfile = "{{target_output_name}}{{output_extension}}"
+ rspfile = "$outfile.rsp"
+ command = "$clangxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+ description = "LINK $outfile"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ outfile,
+ ]
+ }
+
+ tool("stamp") {
+ command = "touch {{output}}"
+ description = "STAMP {{output}}"
+ }
+
+ tool("copy") {
+ command = "cp -af {{source}} {{output}}"
+ description = "COPY {{source}} {{output}}"
+ }
+}
diff --git a/mtkbt/code/bt/build/toolchain/clang/get_clang_suffix.py b/mtkbt/code/bt/build/toolchain/clang/get_clang_suffix.py
new file mode 100755
index 0000000..dedacdd
--- a/dev/null
+++ b/mtkbt/code/bt/build/toolchain/clang/get_clang_suffix.py
@@ -0,0 +1,43 @@
+import os
+import subprocess
+import re
+import sys
+
+def which(cmd):
+ for p in os.environ["PATH"].split(os.pathsep):
+ clang_path = os.path.join(p, cmd)
+ if os.path.exists(clang_path):
+ return clang_path
+ return None
+
+CLANG_VERSION_REGEX=".*version\s*([0-9]*\.[0-9]*)\.*"
+clang_path = which("clang++")
+clang_version_major = 0
+clang_version_minor = 0
+
+if clang_path:
+ clang_version_out = subprocess.Popen([clang_path, "--version"],
+ stdout=subprocess.PIPE).communicate()[0]
+ clang_version_match = re.search(CLANG_VERSION_REGEX, clang_version_out)
+ clang_version_str = clang_version_match.group(1)
+ clang_version_array = clang_version_str.split('.')
+ clang_version_major = int(clang_version_array[0])
+ clang_version_minor = int(clang_version_array[1])
+
+if clang_version_major >= 3 and clang_version_minor >= 5:
+ print ""
+else:
+ # Loop in support clang version only
+ clang_version_major = 3
+ clang_version_minor = 9
+ while clang_version_major >= 3 and clang_version_minor >= 5:
+ clang_version_str = "%d.%d" % (clang_version_major, clang_version_minor)
+ clang_path = which("clang++-" + clang_version_str)
+ if clang_path:
+ print clang_version_str
+ sys.exit(0)
+ clang_version_minor -= 1
+ if clang_version_minor < 0:
+ clang_version_minor = 9
+ clang_version_major -= 1
+ print "None"
diff --git a/mtkbt/code/bt/build/toolchain/gcc/BUILD.gn b/mtkbt/code/bt/build/toolchain/gcc/BUILD.gn
new file mode 100755
index 0000000..888b015
--- a/dev/null
+++ b/mtkbt/code/bt/build/toolchain/gcc/BUILD.gn
@@ -0,0 +1,97 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+cc = "gcc"
+cxx = "g++"
+
+toolchain("gcc") {
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CC {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CXX {{output}}"
+ outputs = [
+ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
+ ]
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+ command = "rm -f {{output}} && ar rcs {{output}} @$rspfile"
+ description = "AR {{target_output_name}}{{output_extension}}"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}",
+ ]
+ default_output_extension = ".a"
+
+ output_prefix = "lib"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ rspfile = soname + ".rsp"
+
+ command =
+ "$cxx -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile"
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+ description = "SOLINK $soname"
+
+ # Use this for {{output_extension}} expansions unless a target manually
+ # overrides it (in which case {{output_extension}} will be what the target
+ # specifies).
+ default_output_extension = ".so"
+
+ outputs = [
+ soname,
+ ]
+ link_output = soname
+ depend_output = soname
+
+ output_prefix = "lib"
+ }
+
+ tool("link") {
+ outfile = "{{target_output_name}}{{output_extension}}"
+ rspfile = "$outfile.rsp"
+ command = "$cxx {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+ description = "LINK $outfile"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ outfile,
+ ]
+ }
+
+ tool("stamp") {
+ command = "touch {{output}}"
+ description = "STAMP {{output}}"
+ }
+
+ tool("copy") {
+ command = "cp -af {{source}} {{output}}"
+ description = "COPY {{source}} {{output}}"
+ }
+}
diff --git a/mtkbt/code/bt/conf/Android.mk b/mtkbt/code/bt/conf/Android.mk
new file mode 100755
index 0000000..6f5037c
--- a/dev/null
+++ b/mtkbt/code/bt/conf/Android.mk
@@ -0,0 +1,24 @@
+# Cannot convert to Android.bp as resource copying has not
+# yet implemented for soong as of 12/16/2016
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth bt_stack.conf config file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := bt_stack.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+# Bluetooth bt_did.conf config file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := bt_did.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
diff --git a/mtkbt/code/bt/conf/bt_did.conf b/mtkbt/code/bt/conf/bt_did.conf
new file mode 100755
index 0000000..942a854
--- a/dev/null
+++ b/mtkbt/code/bt/conf/bt_did.conf
@@ -0,0 +1,88 @@
+# Device ID (DID) configuration
+[DID1]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+primaryRecord = true
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Set right vendorId
+vendorId = 0x0046
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# For example: 1200, v14.3.6
+productId = 0x1200
+version = 0x1436
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
+
+#=================================================================================================#
+# Device ID (DID) configuration
+[DID2]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+#primaryRecord = false
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# Default: 0x0000, v00.0.0
+#productId = 0x0000
+#version = 0x0000
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
+
+#=================================================================================================#
+# Device ID (DID) configuration
+[DID3]
+
+# Primary Record - true or false (default)
+# There can be only one primary record
+#primaryRecord = false
+
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device
+# 0x000F = Broadcom Corporation (default)
+#vendorId = 0x000F
+
+# Vendor ID Source
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default)
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value
+#vendorIdSource = 0x0001
+
+# Product ID & Product Version
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N
+# JJ: major version number, M: minor version number, N: sub-minor version number
+# Default: 0x0000, v00.0.0
+#productId = 0x0000
+#version = 0x0000
+
+# Optional attributes
+#clientExecutableURL =
+#serviceDescription =
+#documentationURL =
diff --git a/mtkbt/code/bt/conf/bt_stack.conf b/mtkbt/code/bt/conf/bt_stack.conf
new file mode 100755
index 0000000..8641434
--- a/dev/null
+++ b/mtkbt/code/bt/conf/bt_stack.conf
@@ -0,0 +1,69 @@
+# Enable trace level reconfiguration function
+# Must be present before any TRC_ trace level settings
+TraceConf=true
+
+# Trace level configuration
+# BT_TRACE_LEVEL_NONE 0 ( No trace messages to be generated )
+# BT_TRACE_LEVEL_ERROR 1 ( Error condition trace messages )
+# BT_TRACE_LEVEL_WARNING 2 ( Warning condition trace messages )
+# BT_TRACE_LEVEL_API 3 ( API traces )
+# BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events )
+# BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages )
+# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only.
+TRC_BTM=2
+TRC_HCI=2
+TRC_L2CAP=2
+TRC_RFCOMM=2
+TRC_OBEX=2
+TRC_AVCT=2
+TRC_AVDT=2
+TRC_AVRC=2
+TRC_AVDT_SCB=2
+TRC_AVDT_CCB=2
+TRC_A2D=2
+TRC_SDP=2
+TRC_GATT=2
+TRC_SMP=2
+TRC_BTAPP=2
+TRC_BTIF=2
+TRC_GAP=2
+TRC_BNEP=2
+TRC_PAN=2
+TRC_HID_HOST=2
+TRC_HID_DEV=2
+
+# This is Log configuration for new C++ code using LOG() macros.
+# See libchrome/base/logging.h for description on how to configure your logs.
+# sample configuration:
+#LoggingV=--v=0
+#LoggingVModule=--vmodule=*/btm/*=1,btm_ble_multi*=2,btif_*=1
+
+# PTS testing helpers
+
+# Secure connections only mode.
+# PTS_SecurePairOnly=true
+
+# Disable LE Connection updates
+#PTS_DisableConnUpdates=true
+
+# Disable BR/EDR discovery after LE pairing to avoid cross key derivation errors
+#PTS_DisableSDPOnLEPair=true
+
+# SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
+#PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+
+# SMP Certification Failure Cases
+# Fail case number range from 1 to 9 will set up remote device for test
+# case execution. Setting PTS_SmpFailureCase to 0 means normal operation.
+# Failure modes:
+# 1 = SMP_CONFIRM_VALUE_ERR
+# 2 = SMP_PAIR_AUTH_FAIL
+# 3 = SMP_PAIR_FAIL_UNKNOWN
+# 4 = SMP_PAIR_NOT_SUPPORT
+# 5 = SMP_PASSKEY_ENTRY_FAIL
+# 6 = SMP_REPEATED_ATTEMPTS
+# 7 = PIN generation failure?
+# 8 = SMP_PASSKEY_ENTRY_FAIL
+# 9 = SMP_NUMERIC_COMPAR_FAIL;
+#PTS_SmpFailureCase=0
+
diff --git a/mtkbt/code/bt/device/Android.bp b/mtkbt/code/bt/device/Android.bp
new file mode 100755
index 0000000..0acc7da
--- a/dev/null
+++ b/mtkbt/code/bt/device/Android.bp
@@ -0,0 +1,46 @@
+// Bluetooth device static library for target
+// ========================================================
+cc_library_static {
+ name: "libbtdevice",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ srcs: [
+ "src/controller.cc",
+ "src/esco_parameters.cc",
+ "src/interop.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+}
+
+// Bluetooth device unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_device",
+ defaults: ["fluoride_defaults"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs: [
+ "test/interop_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libdl",
+ ],
+ static_libs: [
+ "libbtdevice",
+ "libbtcore",
+ "libosi",
+ "libosi-AllocationTestHarness",
+ "libcutils",
+ ],
+}
diff --git a/mtkbt/code/bt/device/BUILD.gn b/mtkbt/code/bt/device/BUILD.gn
new file mode 100755
index 0000000..f93b70d
--- a/dev/null
+++ b/mtkbt/code/bt/device/BUILD.gn
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("device") {
+ sources = [
+ "src/controller.cc",
+ "src/esco_parameters.cc",
+ "src/interop.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//btcore/include",
+ "//hci/include",
+ "//include",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_device") {
+ testonly = true
+ sources = [
+ "//osi/test/AllocationTestHarness.cc",
+ ]
+
+ include_dirs = [ "//" ]
+
+ deps = [
+ "//device",
+ "//btcore",
+ "//osi",
+ "//third_party/googletest:gtest_main",
+ "//third_party/libchrome:base",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ ]
+}
diff --git a/mtkbt/code/bt/device/include/controller.h b/mtkbt/code/bt/device/include/controller.h
new file mode 100755
index 0000000..7088764
--- a/dev/null
+++ b/mtkbt/code/bt/device/include/controller.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bdaddr.h"
+#include "device_features.h"
+#include "hci_layer.h"
+#include "hci_packet_factory.h"
+#include "hci_packet_parser.h"
+
+static const char CONTROLLER_MODULE[] = "controller_module";
+
+typedef struct controller_t {
+ bool (*get_is_ready)(void);
+
+ const bt_bdaddr_t* (*get_address)(void);
+ const bt_version_t* (*get_bt_version)(void);
+
+ const bt_device_features_t* (*get_features_classic)(int index);
+ uint8_t (*get_last_features_classic_index)(void);
+
+ const bt_device_features_t* (*get_features_ble)(void);
+ const uint8_t* (*get_ble_supported_states)(void);
+
+ bool (*supports_simple_pairing)(void);
+ bool (*supports_secure_connections)(void);
+ bool (*supports_simultaneous_le_bredr)(void);
+ bool (*supports_reading_remote_extended_features)(void);
+ bool (*supports_interlaced_inquiry_scan)(void);
+ bool (*supports_rssi_with_inquiry_results)(void);
+ bool (*supports_extended_inquiry_response)(void);
+ bool (*supports_master_slave_role_switch)(void);
+ bool (*supports_enhanced_setup_synchronous_connection)(void);
+ bool (*supports_enhanced_accept_synchronous_connection)(void);
+
+ bool (*supports_ble)(void);
+ bool (*supports_ble_packet_extension)(void);
+ bool (*supports_ble_connection_parameters_request)(void);
+ bool (*supports_ble_privacy)(void);
+ bool (*supports_ble_2m_phy)(void);
+ bool (*supports_ble_coded_phy)(void);
+ bool (*supports_ble_extended_advertising)(void);
+ bool (*supports_ble_periodic_advertising)(void);
+
+ // Get the cached acl data sizes for the controller.
+ uint16_t (*get_acl_data_size_classic)(void);
+ uint16_t (*get_acl_data_size_ble)(void);
+
+ // Get the cached acl packet sizes for the controller.
+ // This is a convenience function for the respective
+ // acl data size + size of the acl header.
+ uint16_t (*get_acl_packet_size_classic)(void);
+ uint16_t (*get_acl_packet_size_ble)(void);
+
+ uint16_t (*get_ble_default_data_packet_length)(void);
+ uint16_t (*get_ble_maxium_advertising_data_length)(void);
+ uint8_t (*get_ble_number_of_supported_advertising_sets)(void);
+
+ // Get the number of acl packets the controller can buffer.
+ uint16_t (*get_acl_buffer_count_classic)(void);
+ uint8_t (*get_acl_buffer_count_ble)(void);
+
+ uint8_t (*get_ble_white_list_size)(void);
+
+ uint8_t (*get_ble_resolving_list_max_size)(void);
+ void (*set_ble_resolving_list_max_size)(int resolving_list_max_size);
+ uint8_t* (*get_local_supported_codecs)(uint8_t* number_of_codecs);
+ uint8_t (*get_le_all_initiating_phys)(void);
+
+} controller_t;
+
+const controller_t* controller_get_interface();
+
+const controller_t* controller_get_test_interface(
+ const hci_t* hci_interface,
+ const hci_packet_factory_t* packet_factory_interface,
+ const hci_packet_parser_t* packet_parser_interface);
diff --git a/mtkbt/code/bt/device/include/esco_parameters.h b/mtkbt/code/bt/device/include/esco_parameters.h
new file mode 100755
index 0000000..f906c8d
--- a/dev/null
+++ b/mtkbt/code/bt/device/include/esco_parameters.h
@@ -0,0 +1,137 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+/*******************
+ * SCO Codec Types
+ *******************/
+typedef enum {
+ SCO_CODEC_NONE = 0x0000,
+ SCO_CODEC_CVSD = 0x0001,
+ SCO_CODEC_MSBC = 0x0002,
+} sco_codec_t;
+
+typedef enum {
+ ESCO_CODEC_CVSD = 0,
+ ESCO_CODEC_MSBC_T1,
+ ESCO_CODEC_MSBC_T2,
+} esco_codec_t;
+
+#define ESCO_NUM_CODECS 3
+
+// Coding Formats (BT 4.1 or later Assigned numbers)
+#define ESCO_CODING_FORMAT_ULAW ((uint8_t)0x00) /* u-Law log */
+#define ESCO_CODING_FORMAT_ALAW ((uint8_t)0x01) /* A-Law log */
+#define ESCO_CODING_FORMAT_CVSD ((uint8_t)0x02) /* CVSD */
+#define ESCO_CODING_FORMAT_TRANSPNT ((uint8_t)0x03) /* Transparent */
+#define ESCO_CODING_FORMAT_LINEAR ((uint8_t)0x04) /* Linear PCM */
+#define ESCO_CODING_FORMAT_MSBC ((uint8_t)0x05) /* MSBC PCM */
+#define ESCO_CODING_FORMAT_VS ((uint8_t)0xFF) /* Specifies VSC used */
+typedef uint8_t esco_coding_format_t;
+
+// PCM Data Formats (BT 4.1 or later Assigned numbers)
+#define ESCO_PCM_DATA_FORMAT_NA \
+ ((uint8_t)0x00) /* N/A to coding format in use */
+#define ESCO_PCM_DATA_FORMAT_1_COMP ((uint8_t)0x01) /* 1's complement */
+#define ESCO_PCM_DATA_FORMAT_2_COMP ((uint8_t)0x02) /* 2's complement */
+#define ESCO_PCM_DATA_FORMAT_SIGN ((uint8_t)0x03) /* Sign-magnitude */
+#define ESCO_PCM_DATA_FORMAT_UNSIGN ((uint8_t)0x04) /* Unsigned */
+typedef uint8_t esco_pcm_data_format_t;
+
+// SCO Data Path
+#define ESCO_DATA_PATH_PCM 1 /* 0x01-0xFE (PCM Chan) */
+#define ESCO_DATA_PATH_HCI ((uint8_t)0x00) /* HCI-0, 0x01-0xFE (PCM Chan) */
+#define ESCO_DATA_PATH_TEST ((uint8_t)0xFF) /* 0xFF-Audio Test */
+typedef uint8_t esco_data_path_t;
+
+// eSCO constants
+#define TXRX_64KBITS_RATE 0x00001f40 /* 64 kbits/sec data rate */
+#define TXRX_128KBITS_RATE 0x00003E80 /* 128 kbits/sec data rate */
+typedef uint32_t esco_txrx_bandwidth_t;
+
+#define INPUT_OUTPUT_64K_RATE 0x00003E80 /* 16000 Bytes/sec over transport */
+#define INPUT_OUTPUT_128K_RATE 0x00007D00 /* 32000 Bytes/sec over transport */
+typedef uint32_t esco_io_bandwidth_t;
+
+// Retransmission effort
+#define ESCO_RETRANSMISSION_OFF 0
+#define ESCO_RETRANSMISSION_POWER 1
+#define ESCO_RETRANSMISSION_QUALITY 2
+#define ESCO_RETRANSMISSION_DONTCARE 0xff
+typedef uint8_t esco_retransmission_effort_t;
+
+// Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions)
+#define ESCO_PKT_TYPES_MASK_HV1 0x0001
+#define ESCO_PKT_TYPES_MASK_HV2 0x0002
+#define ESCO_PKT_TYPES_MASK_HV3 0x0004
+#define ESCO_PKT_TYPES_MASK_EV3 0x0008
+#define ESCO_PKT_TYPES_MASK_EV4 0x0010
+#define ESCO_PKT_TYPES_MASK_EV5 0x0020
+#define ESCO_PKT_TYPES_MASK_NO_2_EV3 0x0040
+#define ESCO_PKT_TYPES_MASK_NO_3_EV3 0x0080
+#define ESCO_PKT_TYPES_MASK_NO_2_EV5 0x0100
+#define ESCO_PKT_TYPES_MASK_NO_3_EV5 0x0200
+typedef uint16_t esco_packet_types_t;
+
+// type definition
+typedef struct {
+ esco_coding_format_t coding_format; /* Coding Format*/
+ uint16_t company_id; /* Company ID from BT SIG Assigned Numbers */
+ uint16_t vendor_specific_codec_id; /* Vendor Specific Codec ID */
+} esco_coding_id_format_t;
+
+// Enhanced setup/accept synchronous connection See BT 4.1 or later HCI spec for
+// details
+typedef struct {
+ esco_txrx_bandwidth_t
+ transmit_bandwidth; /* Transmit Bandwidth (in octets/second) */
+ esco_txrx_bandwidth_t receive_bandwidth; /* RX BW (# of octets/second) */
+ esco_coding_id_format_t transmit_coding_format; /* TX coding format */
+ esco_coding_id_format_t receive_coding_format; /* RX coding format */
+ uint16_t transmit_codec_frame_size; /* TX CODEC frame size (OTA frame size) */
+ uint16_t receive_codec_frame_size; /* RX CODEC frame size (OTA frame size) */
+ esco_io_bandwidth_t input_bandwidth; /* Input BW (nominal rate octets/sec) */
+ esco_io_bandwidth_t
+ output_bandwidth; /* Output BW (nominal rate octets/sec) */
+ esco_coding_id_format_t input_coding_format; /* Input coding format */
+ esco_coding_id_format_t output_coding_format; /* Output coding format */
+ uint16_t input_coded_data_size; /* Input coded data size (in bits) */
+ uint16_t output_coded_data_size; /* Output coded data size (in bits) */
+ esco_pcm_data_format_t
+ input_pcm_data_format; /* Input PCM data format (see hcidefs.h) */
+ esco_pcm_data_format_t
+ output_pcm_data_format; /* Output PCM data format (see hcidefs.h) */
+ uint8_t input_pcm_payload_msb_position; /* Input PCM sample payload MSB
+ position */
+ uint8_t output_pcm_payload_msb_position; /* Output PCM sample payload MSB
+ position */
+ esco_data_path_t input_data_path; /* 0x00 - HCI, or 0x01-0xFE for VS) */
+ esco_data_path_t output_data_path; /* 0x00 - HCI, or 0x01-0xFE for VS) */
+ uint8_t input_transport_unit_size; /* Input transport unit size */
+ uint8_t output_transport_unit_size; /* Output transport unit size */
+ uint16_t max_latency_ms; /* Maximum latency (0x4-0xFFFE in msecs) */
+ esco_packet_types_t packet_types; /* Packet Types */
+ esco_retransmission_effort_t
+ retransmission_effort; /* 0x00-0x02, 0xFF don't care */
+} enh_esco_params_t;
+
+// Get the enhanced eSCO configuration parameters for the provided |codec|
+enh_esco_params_t esco_parameters_for_codec(esco_codec_t codec);
diff --git a/mtkbt/code/bt/device/include/interop.h b/mtkbt/code/bt/device/include/interop.h
new file mode 100755
index 0000000..3bc40c9
--- a/dev/null
+++ b/mtkbt/code/bt/device/include/interop.h
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "btcore/include/bdaddr.h"
+
+static const char INTEROP_MODULE[] = "interop_module";
+
+// NOTE:
+// Only add values at the end of this enum and do NOT delete values
+// as they may be used in dynamic device configuration.
+typedef enum {
+ // Disable secure connections
+ // This is for pre BT 4.1/2 devices that do not handle secure mode
+ // very well.
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS = 0,
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/// Values Added by MTK, @M{
+
+// Added for HOGP/GATT/LE, @start {
+
+ // Some device like Arc Touch BT Mouse will behave abnormally if their
+ // required interval which is less than BTM_BLE_CONN_INT_MIN_LIMIT
+ // is rejected
+ INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT,
+
+ // Some device like Casio watch request a minor link supervision timeout which
+ // can cause the link timeout frequently. So adjust their link supervision timeout
+ // to default value
+ INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST,
+
+ // Devices like BSMBB09DS request a large slave latency which will slow down
+ // the data transmission or break the link during profile establishment. So adjust
+ // the slave latency to default value
+ INTEROP_MTK_LE_CONN_LATENCY_ADJUST,
+
+ //Some device like ELECOM cannot handle fast connection procedure
+ INTEROP_MTK_LE_DISABLE_FAST_CONNECTION,
+
+ // Some device like ELECOM cann't handle the peripheral pereferred
+ // connection parameters update procedure
+ INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS,
+// } @end
+
+// Added for A2DP, @start {
+ // Some device will delay send A2DP signaling. It will occur A2DP connection conflict.
+ // Change accept signaling time out value for above devices.
+ INTEROP_MTK_A2DP_CHANGE_ACCEPT_SIGNALLING_TMS,
+
+ // Some special device want perform START cmd itself first
+ // If it not send START cmd, will close current link.
+ // So for this special device, we need delay send A2DP START cmd
+ // which from DUT to receive the special device cmd.
+ INTEROP_MTK_A2DP_DELAY_START_CMD,
+
+ // Some headset have IOT issue that Peer device only close A2dp data channel
+ // Without closing signaling channel which will result to follow-up connection statemachine confused
+ // So for this special device, we need force to disconnect signaling channel.
+ INTEROP_MTK_CLOSE_AVDTP_SIG_CH,
+
+ // In particular case, IOT device has wrong song position when FF/REW.
+ // Disable song position for IOT device.
+ INTEROP_MTK_AVRCP_DISABLE_SONG_POS,
+// } @end
+
+// Added for HFP, @start {
+
+ // Sony Ericsson HBH-DS205 has some special request for opening
+ // the sco time(if create SCO command be sent before a2dp suspend,
+ // the BT SCO will no voice output for the voice call), so work around
+ // for this device by delay the SCO setup.
+ // (Nexus has the same problem with this device).
+ INTEROP_MTK_HFP_DEALY_OPEN_SCO,
+
+ // Some devices cannot work normal as a master if the connection
+ // is initiated by them self and this will cause ACL collision. For these
+ // devices, extend the ACL collision handler timer to wait it reconnect.
+ INTEROP_MTK_HFP_ACL_COLLISION,
+
+ // Some device check if received the CHLD command when receives
+ // the create SCO command, if no CHLD received, it will not create
+ // SCO, but there is no command or event indicates remote side has
+ // received the command, so just wait for a while.
+ INTEROP_MTK_WAIT_SLC_FOR_SCO,
+
+ // Some device has IOT issue for HFP 1.7 version.
+ // Back to 1.6 for this devices.
+ INTEROP_MTK_HFP_17_TO_16,
+
+ // Xiaomi device set gain equal zero will
+ // lead no sound,so cancel gain update
+ INTEROP_MTK_HFP_GAIN_UPDATE_CANCEL,
+// } @end
+
+// Added for HID, @start {
+ //Some HID device will show connected state too slowly
+ //Because when his connection had setup, HID host process
+ //SDP,when peer device response slowly,it lead show connected slowly
+ INTEROP_MTK_HID_DISABLE_SDP,
+ // Not do sniif mode for HID profile.
+ INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING,
+// } @end
+
+// Added for OPP/RFCOMM, @start {
+ // Some devices can not parse multi AT commands in one rfcomm packet.
+ // So, send data separately.
+ INTEROP_MTK_FORBID_COMBINE_RFCOMM_DATA,
+// } @end
+
+// Added for L2CAP, @start {
+ // Some devices cannot work normally as a master if the connection is initiated by themselves
+ INTEROP_MTK_ACCEPT_CONN_AS_MASTER,
+
+ // Some device cannot work normally as a slave if the connection is initiated by themselves.
+ INTEROP_MTK_ACCEPT_CONN_AS_SLAVE,
+
+// } @end
+
+// Added for GAP, @start {
+ // Uncheck service sercurity requirements for special device
+ // because they did not initiate authentication procedure during
+ // their reconnect.
+ INTEROP_MTK_DISABLE_SERVICE_SECURITY_CHECK,
+
+ // Disable role switch for some IOT devices
+ INTEROP_MTK_LINK_POLICY_DISABLE_ROLE_SWITCH,
+// } @end
+
+// Added for SDP, @start {
+// } @end
+
+// Added for Common, @start {
+// } @end
+
+/// } @M finish
+#endif
+
+ // Some devices have proven problematic during the pairing process, often
+ // requiring multiple retries to complete pairing. To avoid degrading the user
+ // experience for those devices, automatically re-try pairing if page
+ // timeouts are received during pairing.
+ INTEROP_AUTO_RETRY_PAIRING,
+
+ // Devices requiring this workaround do not handle Bluetooth Absolute Volume
+ // control correctly, leading to undesirable (potentially harmful) volume
+ // levels or general lack of controlability.
+ INTEROP_DISABLE_ABSOLUTE_VOLUME,
+
+ // Disable automatic pairing with headsets/car-kits
+ // Some car kits do not react kindly to a failed pairing attempt and
+ // do not allow immediate re-pairing. Blacklist these so that the initial
+ // pairing attempt makes it to the user instead.
+ INTEROP_DISABLE_AUTO_PAIRING,
+
+ // Use a fixed pin for specific keyboards
+ // Keyboards should use a variable pin at all times. However, some keyboards
+ // require a fixed pin of all 0000. This workaround enables auto pairing for
+ // those keyboards.
+ INTEROP_KEYBOARD_REQUIRES_FIXED_PIN,
+
+ // Some headsets have audio jitter issues because of increased
+ // re-transmissions as the 3 Mbps packets have a lower link margin, and are
+ // more prone to interference. We can disable 3DH packets (use only 2DH
+ // packets) for the ACL link to improve sensitivity when streaming A2DP audio
+ // to the headset. Air sniffer logs show reduced re-transmissions after
+ // switching to 2DH packets.
+
+ // Disable 3Mbps packets and use only 2Mbps packets for ACL links when
+ // streaming audio.
+ INTEROP_2MBPS_LINK_ONLY,
+
+ // Do not use supervision timeout value received from preferred connection
+ // parameters, use 3s instead. Use with HID only.
+ INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S,
+
+ // Do not send service changed indications (GATT client).
+ // This should be removed after the characteristic is implmeented b/62088395.
+ INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
+
+ // Do not use AVDTP RECONFIGURE when reconfiguring A2DP streams.
+ // Some A2DP Sink devices report SUCCESS to the AVDTP RECONFIGURE command,
+ // but fail to play the reconfigured audio stream.
+ INTEROP_DISABLE_AVDTP_RECONFIGURE,
+} interop_feature_t;
+
+// Check if a given |addr| matches a known interoperability workaround as
+// identified by the |interop_feature_t| enum. This API is used for simple
+// address based lookups where more information is not available. No
+// look-ups or random address resolution are performed on |addr|.
+bool interop_match_addr(const interop_feature_t feature,
+ const bt_bdaddr_t* addr);
+
+// Check if a given remote device |name| matches a known workaround.
+// Name comparisons are case sensitive and do not allow for partial matches.
+// If |name| is "TEST" and a workaround exists for "TESTING", then this function
+// will return false. But, if |name| is "TESTING" and a workaround exists for
+// "TEST", this function will return true.
+// |name| cannot be null and must be null terminated.
+bool interop_match_name(const interop_feature_t feature, const char* name);
+
+// Add a dynamic interop database entry for a device matching the first |length|
+// bytes of |addr|, implementing the workaround identified by |feature|.
+// |addr| may not be null.
+// |length| must be greater than 0 and less than sizeof(bt_bdaddr_t).
+// As |interop_feature_t| is not exposed in the public API, feature must be a
+// valid integer representing an option in the enum.
+void interop_database_add(const uint16_t feature, const bt_bdaddr_t* addr,
+ size_t length);
+
+// Clear the dynamic portion of the interoperability workaround database.
+void interop_database_clear(void);
diff --git a/mtkbt/code/bt/device/include/interop_database.h b/mtkbt/code/bt/device/include/interop_database.h
new file mode 100755
index 0000000..b9c8cc6
--- a/dev/null
+++ b/mtkbt/code/bt/device/include/interop_database.h
@@ -0,0 +1,358 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "device/include/interop.h"
+
+typedef struct {
+ bt_bdaddr_t addr;
+ size_t length;
+ interop_feature_t feature;
+} interop_addr_entry_t;
+
+static const interop_addr_entry_t interop_addr_database[] = {
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/// Values Added by MTK, @M{
+
+// Added for HOGP/GATT/LE, @start {
+
+ //BSM mouse
+ {{{0x00, 0x1b, 0xdc, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_LATENCY_ADJUST},
+
+ // CASIO watch
+ {{{0xff, 0x40, 0x3a, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+ {{{0xda, 0x58, 0x98, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+ {{{0xc2, 0x80, 0x29, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+ {{{0xff, 0x74, 0xe1, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+ {{{0xd9, 0xe6, 0xea, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+
+ //{0xd0, 0x5f, 0xb8}. /*ELECOM Laser Mouse*/
+ {{{0xd0, 0x5f, 0xb8, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0xd0, 0x5f, 0xb8, 0, 0, 0}}, 3, INTEROP_MTK_LE_DISABLE_FAST_CONNECTION},
+ {{{0xd0, 0x5f, 0xb8, 0, 0, 0}}, 3, INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS},
+ {{{0xd0, 0x5f, 0xb8, 0, 0, 0}}, 3, INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT},
+
+ //Huitong BLE Remote
+ {{{0x7c, 0x66, 0x9d, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+// } @end
+
+// Added for A2DP, @start {
+ // INTEROP_MTK_A2DP_CHANGE_ACCEPT_SIGNALLING_TMS
+ // {0x00, 0x21, 0x3c}, /* Jawbone ICON*/
+ {{{0x00, 0x21, 0x3c, 0,0,0}}, 3, INTEROP_MTK_A2DP_CHANGE_ACCEPT_SIGNALLING_TMS},
+
+ // INTEROP_MTK_A2DP_DELAY_START_CMD
+ // {0x00, 0x17, 0x53} /* Tiggo5 */
+ // {0x00, 0x13, 0x04} /* CASKA */
+ // {0x00, 0x0d, 0x3c} /* Clip Music 801 */
+ {{{0x00, 0x17, 0x53, 0,0,0}}, 3, INTEROP_MTK_A2DP_DELAY_START_CMD},
+ {{{0x00, 0x13, 0x04, 0,0,0}}, 3, INTEROP_MTK_A2DP_DELAY_START_CMD},
+ {{{0x00, 0x0d, 0x3c, 0,0,0}}, 3, INTEROP_MTK_A2DP_DELAY_START_CMD},
+
+ // INTEROP_MTK_CLOSE_AVDTP_SIG_CH
+ // {0x00, 0x18, 0x6b}, /* LG HBM-280 */
+ // {0x00, 0x0B, 0xD5}, /* JABRA DRIVE*/
+ // {0x00, 0x15, 0x83}, /* CarKit_BC06*/
+ {{{0x00, 0x18, 0x6b, 0,0,0}}, 3, INTEROP_MTK_CLOSE_AVDTP_SIG_CH},
+ {{{0x00, 0x0B, 0xD5, 0,0,0}}, 3, INTEROP_MTK_CLOSE_AVDTP_SIG_CH},
+ {{{0x00, 0x15, 0x83, 0,0,0}}, 3, INTEROP_MTK_CLOSE_AVDTP_SIG_CH},
+
+ // INTEROP_MTK_AVRCP_DISABLE_SONG_POS
+ // {0x00, 0x0e, 0x9f}, /* Toyota Touch&Go */
+ {{{0x00, 0x0e, 0x9f, 0,0,0}}, 3, INTEROP_MTK_AVRCP_DISABLE_SONG_POS},
+
+ // INTEROP_DISABLE_ABSOLUTE_VOLUME
+ // Pioneer APS-BH80 - support AVRCP1.4, but absolute volume is not implemented
+ // {0x00, 0x08, 0x7A}, /* APS-BH80 */
+ {{{0x00, 0x08, 0x7A, 0,0,0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+// } @end
+
+// Added for HFP, @start {
+
+ // INTEROP_MTK_HFP_DEALY_OPEN_SCO
+ // {0x00, 0x1E, 0xDC} /* DS205 */
+ // {0x00, 0x58, 0x50} /* BELKIN */
+ {{{0x00, 0x1E, 0xDC, 0,0,0}}, 3, INTEROP_MTK_HFP_DEALY_OPEN_SCO},
+ {{{0x00, 0x58, 0x50, 0,0,0}}, 3, INTEROP_MTK_HFP_DEALY_OPEN_SCO},
+
+ // INTEROP_MTK_HFP_ACL_COLLISION
+ // {0x48, 0xc1, 0xac}, /*PLT M155*/ will reconnect DUT when BT chip reset.
+ // {0x00, 0x0d, 0x18}, /*S1/X3-M*/ Carkit will reconnect.
+ // {0x00, 0x1E, 0x7C}, /*Philips SHB9000*/ Headset will reconnect.
+ // {0x74, 0xDE, 0x2B}, /*Jabra Clipper*/ HFP connect collision.
+ // {0x0C, 0xE0, 0xE4}, /*PLT_M180*/ HFP connect collision.
+ {{{0x48, 0xC1, 0xAC, 0,0,0}}, 3, INTEROP_MTK_HFP_ACL_COLLISION},
+ {{{0x00, 0x0D, 0x18, 0,0,0}}, 3, INTEROP_MTK_HFP_ACL_COLLISION},
+ {{{0x00, 0x1E, 0x7C, 0,0,0}}, 3, INTEROP_MTK_HFP_ACL_COLLISION},
+ {{{0x74, 0xDE, 0x2B, 0,0,0}}, 3, INTEROP_MTK_HFP_ACL_COLLISION},
+ {{{0x0C, 0xE0, 0xE4, 0,0,0}}, 3, INTEROP_MTK_HFP_ACL_COLLISION},
+
+ //INTEROP_MTK_WAIT_SLC_FOR_SCO
+ // {0xFC, 0x58, 0xFA}, /*MEIZU speaker*/ Wait SLC for SCO when connect with active call.
+ {{{0xFC, 0x58, 0xFA, 0,0,0}}, 3, INTEROP_MTK_WAIT_SLC_FOR_SCO},
+
+ // INTEROP_MTK_HFP_17_TO_16
+ // {0x00, 0x17, 0x53} /* Tiggo5 */
+ {{{0x00, 0x17, 0x53, 0,0,0}} ,3, INTEROP_MTK_HFP_17_TO_16},
+
+ //INTEROP_MTK_HFP_GAIN_UPDATE_CANCEL
+ //{0x00, 0x9E, 0xC8} /*BT speaker(Xiaomi)*/
+ {{{0x00, 0x9E, 0xC8, 0,0,0}} ,3, INTEROP_MTK_HFP_GAIN_UPDATE_CANCEL},
+// } @end
+
+// Added for HID, @start {
+ // {0x04, 0x0C, 0xCE}, /* Apple Magic Mouse */
+ // {0x00, 0x07, 0x61}, /* Bluetooth Laser Travel Mouse */
+ // {0x00, 0x1d, 0xd8}, /* Microsoft Bluetooth Notebook Mouse 5000 */
+ // {0x00, 0x1f, 0x20}, /* Logitech MX Revolution Mouse */
+ // {0x6c, 0x5d, 0x63}, /* Rapoo 6080 mouse */
+ // {0x28, 0x18, 0x78} /* Microsoft Sculpt Touch Mouse */
+ // {0x30, 0x59, 0xb7} /* Microsoft Sculpt Comfort Mouse */
+ {{{0x04, 0x0C, 0xCE, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x00, 0x07, 0x61, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x00, 0x1d, 0xd8, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x00, 0x1f, 0x20, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x6c, 0x5d, 0x63, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x28, 0x18, 0x78, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+ {{{0x30, 0x59, 0xb7, 0,0,0}}, 3, INTEROP_MTK_HID_DISABLE_SDP},
+
+ // INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING
+ // {0x54, 0x46, 0x6b}, /* JW MT002 Bluetooth Mouse */
+ // /*LMP version&subversion - 5, 8721 & LMP Manufacturer - 15*/
+ // {0x6c, 0x5d, 0x63}, /* Rapoo 6610 Bluetooth Mouse */
+ // {0x60, 0x8c, 0x2b}, /* FelTouch Magic */
+ {{{0x54, 0x46, 0x6b, 0,0,0}}, 3, INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING},
+ {{{0x6c, 0x5d, 0x63, 0,0,0}}, 3, INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING},
+ {{{0x60, 0x8c, 0x2b, 0,0,0}}, 3, INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING},
+// } @end
+
+// Added for OPP/RFCOMM, @start {
+ // INTEROP_MTK_FORBID_COMBINE_RFCOMM_DATA
+ // {0x00, 0x0A, 0x08}, /*BMW94506*/ Remote device can not parse multi at commands.
+ {{{0x00, 0x0A, 0x08, 0,0,0}}, 3, INTEROP_MTK_FORBID_COMBINE_RFCOMM_DATA},
+// } @end
+
+// Added for L2CAP, @start {
+ // INTEROP_MTK_ACCEPT_CONN_AS_MASTER
+ // {0x6c, 0x5d, 0x63}, /* Rapoo 6610 mouse */
+ // {0x00, 0x02, 0xc7}, /* HANDS FREE carkit of Infineon Technologies AG */
+ // {0x00, 0x58, 0x75}, /* Mifa_F1 */
+ // {0x00, 0x58, 0x76}, /* BT800, this device does not send detach when power off */
+ {{{0x6c, 0x5d, 0x63, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_MASTER},
+ {{{0x00, 0x02, 0xc7, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_MASTER},
+ {{{0x00, 0x58, 0x75, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_MASTER},
+ {{{0x00, 0x58, 0x76, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_MASTER},
+
+ // INTEROP_MTK_ACCEPT_CONN_AS_SLAVE
+ // {0x00, 0x1e, 0xae}, /* SYNC, FORD carkit */
+ // {0x00, 0x26, 0xb4}, /* NAC ford, 2013 Lincoln */
+ // {0x00, 0x26, 0xe8}, /* Nissan Murano */
+ // {0x00, 0x37, 0x6d}, /* Lexus ES300h */
+ // {0x9c, 0x3a, 0xaf}, /* SAMSUNG HM1900 */
+ {{{0x00, 0x1e, 0xae, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+ // {{{0x00, 0x26, 0xb4, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+ // {{{0x00, 0x26, 0xe8, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+ // {{{0x00, 0x37, 0x6d, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+ // {{{0x9c, 0x3a, 0xaf, 0,0,0}}, 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+
+// } @end
+
+// Added for GAP, @start {
+
+ //TEMIC SDS (Porsche,Audi exp(PCM)) - auto-pairing fails
+ {{{0x00, 0x0e, 0x9f, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+ // Jabra STONE2 - reconnect with no sercurity procedure
+ {{{0x50,0xc9,0x71, 0, 0, 0}}, 3, INTEROP_MTK_DISABLE_SERVICE_SECURITY_CHECK},
+ {{{0x00,0x23,0x78, 0, 0, 0}}, 3, INTEROP_MTK_DISABLE_SERVICE_SECURITY_CHECK},
+
+// } @end
+
+// Added for SDP, @start {
+// } @end
+
+// Added for Common, @start {
+// } @end
+
+/// } @M finish
+#endif
+
+ // Nexus Remote (Spike)
+ // Note: May affect other Asus brand devices
+ {{{0x08, 0x62, 0x66, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0x38, 0x2c, 0x4a, 0xc9, 0, 0}},
+ 4,
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0x38, 0x2c, 0x4a, 0xe6, 0, 0}},
+ 4,
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0x54, 0xa0, 0x50, 0xd9, 0, 0}},
+ 4,
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0xac, 0x9e, 0x17, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {{{0xf0, 0x79, 0x59, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+ {{{0x08, 0x62, 0x66, 0, 0, 0}}, 3, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+ {{{0x38, 0x2c, 0x4a, 0xc9, 0, 0}}, 4, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+ {{{0x38, 0x2c, 0x4a, 0xe6, 0, 0}}, 4, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+ {{{0x54, 0xa0, 0x50, 0xd9, 0, 0}}, 4, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+ {{{0xac, 0x9e, 0x17, 0, 0, 0}}, 3, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+ {{{0xf0, 0x79, 0x59, 0, 0, 0}}, 3, INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S},
+
+ // Ausdom M05 - unacceptably loud volume
+ {{{0xa0, 0xe9, 0xdb, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // BMW car kits (Harman/Becker)
+ {{{0x9c, 0xdf, 0x03, 0, 0, 0}}, 3, INTEROP_AUTO_RETRY_PAIRING},
+
+ // Flic smart button
+ {{{0x80, 0xe4, 0xda, 0x70, 0, 0}},
+ 4,
+ INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+ // iKross IKBT83B HS - unacceptably loud volume
+ {{{0x00, 0x14, 0x02, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // JayBird BlueBuds X - low granularity on volume control
+ {{{0x44, 0x5e, 0xf3, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ {{{0xd4, 0x9c, 0x28, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // JayBird Family
+ {{{0x00, 0x18, 0x91, 0, 0, 0}}, 3, INTEROP_2MBPS_LINK_ONLY},
+
+ // LG Tone HBS-730 - unacceptably loud volume
+ {{{0x00, 0x18, 0x6b, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ {{{0xb8, 0xad, 0x3e, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // LG Tone HV-800 - unacceptably loud volume
+ {{{0xa0, 0xe9, 0xdb, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Motorola Key Link
+ {{{0x1c, 0x96, 0x5a, 0, 0, 0}}, 3, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+
+ // Motorola Roadster
+ {{{0x00, 0x24, 0x1C, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Mpow Cheetah - unacceptably loud volume
+ {{{0x00, 0x11, 0xb1, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Nissan car kits (ALPS) - auto-pairing fails and rejects next pairing
+ {{{0x34, 0xc7, 0x31, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // SOL REPUBLIC Tracks Air - unable to adjust volume back off from max
+ {{{0xa4, 0x15, 0x66, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Subaru car kits (ALPS) - auto-pairing fails and rejects next pairing
+ {{{0x00, 0x07, 0x04, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+ {{{0xe0, 0x75, 0x0a, 0, 0, 0}}, 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // Swage Rokitboost HS - unacceptably loud volume
+ {{{0x00, 0x14, 0xf1, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // VW Car Kit - not enough granularity with volume
+ {{{0x00, 0x26, 0x7e, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+ {{{0x90, 0x03, 0xb7, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Unknown keyboard (carried over from auto_pair_devlist.conf)
+ {{{0x00, 0x0F, 0xF6, 0, 0, 0}}, 3, INTEROP_KEYBOARD_REQUIRES_FIXED_PIN},
+
+ // Kinivo BTC-450 - volume is erratic when using Absolute Volume
+ {{{0x00, 0x18, 0x91, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // Kenwood KMM-BT518HD - no audio when A2DP codec sample rate is changed
+ {{{0x00, 0x1d, 0x86, 0, 0, 0}}, 3, INTEROP_DISABLE_AVDTP_RECONFIGURE},
+};
+
+typedef struct {
+ char name[20];
+ size_t length;
+ interop_feature_t feature;
+} interop_name_entry_t;
+
+static const interop_name_entry_t interop_name_database[] = {
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/// Values Added by MTK, @M{
+
+// Added for HOGP/GATT/LE, @start {
+
+ {"honor zero-", 11, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {"小米蓝牙遥控", 18, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {"Arc Touch BT Mouse", 18, INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT},
+ {"BSMBB09DS", 9, INTEROP_MTK_LE_CONN_LATENCY_ADJUST},
+ {"CASIO GB-6900A*", 15, INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST},
+ {"Huitong BLE Remote", 18, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {"ELECOM Laser Mouse", 18, INTEROP_DISABLE_LE_SECURE_CONNECTIONS},
+ {"ELECOM Laser Mouse", 18, INTEROP_MTK_LE_DISABLE_FAST_CONNECTION},
+ {"ELECOM Laser Mouse", 18, INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS},
+ {"ELECOM Laser Mouse", 18, INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT},
+ {"FeiZhi", 6, INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS},
+// } @end
+
+// Added for A2DP, @start {
+ {"Toyota Touch&Go", 15, INTEROP_MTK_AVRCP_DISABLE_SONG_POS},
+
+// } @end
+
+// Added for HFP, @start {
+// } @end
+
+// Added for HID, @start {
+// } @end
+
+// Added for OPP/RFCOMM, @start {
+// } @end
+
+// Added for L2CAP, @start {
+ // D8 perfers to act as master after D8 establishes connection
+ {"D8", 3, INTEROP_MTK_ACCEPT_CONN_AS_SLAVE},
+
+// } @end
+
+// Added for GAP, @start {
+ {"Motorola S9", 11, INTEROP_MTK_LINK_POLICY_DISABLE_ROLE_SWITCH},
+// } @end
+
+// Added for SDP, @start {
+// } @end
+
+// Added for Common, @start {
+// } @end
+
+/// } @M finish
+#endif
+
+ // Carried over from auto_pair_devlist.conf migration
+ {"Audi", 4, INTEROP_DISABLE_AUTO_PAIRING},
+ {"BMW", 3, INTEROP_DISABLE_AUTO_PAIRING},
+ {"Parrot", 6, INTEROP_DISABLE_AUTO_PAIRING},
+ {"Car", 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // Nissan Quest rejects pairing after "0000"
+ {"NISSAN", 6, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // Subaru car kits ("CAR M_MEDIA")
+ {"CAR", 3, INTEROP_DISABLE_AUTO_PAIRING},
+
+ // Pixel C Keyboard doesn't respond to service changed indications.
+ {"Pixel C Keyboard", 16, INTEROP_GATTC_NO_SERVICE_CHANGED_IND},
+
+ // Kenwood KMM-BT518HD - no audio when A2DP codec sample rate is changed
+ {"KMM-BT51*HD", 11, INTEROP_DISABLE_AVDTP_RECONFIGURE},
+};
diff --git a/mtkbt/code/bt/device/src/controller.cc b/mtkbt/code/bt/device/src/controller.cc
new file mode 100755
index 0000000..295791e
--- a/dev/null
+++ b/mtkbt/code/bt/device/src/controller.cc
@@ -0,0 +1,589 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_controller"
+
+#include "device/include/controller.h"
+
+#include <base/logging.h>
+
+#include "bt_types.h"
+#include "btcore/include/event_mask.h"
+#include "btcore/include/module.h"
+#include "btcore/include/version.h"
+#include "hcimsgs.h"
+#include "osi/include/future.h"
+#include "stack/include/btm_ble_api.h"
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+#include "fw_logger_switch.h"
+#include "mtk_stack_config.h"
+using vendor::mediatek::bluetooth::stack::FWLogSwitch;
+using vendor::mediatek::bluetooth::stack::StackConfig;
+#endif
+
+const bt_event_mask_t BLE_EVENT_MASK = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1E, 0x7f}};
+
+const bt_event_mask_t CLASSIC_EVENT_MASK = {HCI_DUMO_EVENT_MASK_EXT};
+
+// TODO(zachoverflow): factor out into common module
+const uint8_t SCO_HOST_BUFFER_SIZE = 0xff;
+
+#define HCI_SUPPORTED_COMMANDS_ARRAY_SIZE 64
+#define MAX_FEATURES_CLASSIC_PAGE_COUNT 3
+#define BLE_SUPPORTED_STATES_SIZE 8
+#define BLE_SUPPORTED_FEATURES_SIZE 8
+#define MAX_LOCAL_SUPPORTED_CODECS_SIZE 8
+
+static const hci_t* hci;
+static const hci_packet_factory_t* packet_factory;
+static const hci_packet_parser_t* packet_parser;
+
+static bt_bdaddr_t address;
+static bt_version_t bt_version;
+
+static uint8_t supported_commands[HCI_SUPPORTED_COMMANDS_ARRAY_SIZE];
+static bt_device_features_t features_classic[MAX_FEATURES_CLASSIC_PAGE_COUNT];
+static uint8_t last_features_classic_page_index;
+
+static uint16_t acl_data_size_classic;
+static uint16_t acl_data_size_ble;
+static uint16_t acl_buffer_count_classic;
+static uint8_t acl_buffer_count_ble;
+
+static uint8_t ble_white_list_size;
+static uint8_t ble_resolving_list_max_size;
+static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
+static bt_device_features_t features_ble;
+static uint16_t ble_suggested_default_data_length;
+static uint16_t ble_maxium_advertising_data_length;
+static uint8_t ble_number_of_supported_advertising_sets;
+static uint8_t local_supported_codecs[MAX_LOCAL_SUPPORTED_CODECS_SIZE];
+static uint8_t number_of_local_supported_codecs = 0;
+
+static bool readable;
+static bool ble_supported;
+static bool simple_pairing_supported;
+static bool secure_connections_supported;
+
+#define AWAIT_COMMAND(command) \
+ static_cast<BT_HDR*>(future_await(hci->transmit_command_futured(command)))
+
+// Module lifecycle functions
+
+static future_t* start_up(void) {
+ BT_HDR* response;
+
+ // Send the initial reset command
+ response = AWAIT_COMMAND(packet_factory->make_reset());
+ packet_parser->parse_generic_command_complete(response);
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ // For low power concern, don't default turn on fwlogger switch
+ if (StackConfig::GetInstance()->IsBTSnoopEnabled()) {
+ FWLogSwitch::GetInstance()->StartUp();
+ }
+#endif
+
+ // Request the classic buffer size next
+ response = AWAIT_COMMAND(packet_factory->make_read_buffer_size());
+ packet_parser->parse_read_buffer_size_response(
+ response, &acl_data_size_classic, &acl_buffer_count_classic);
+
+ // Tell the controller about our buffer sizes and buffer counts next
+ // TODO(zachoverflow): factor this out. eww l2cap contamination. And why just
+ // a hardcoded 10?
+ response = AWAIT_COMMAND(packet_factory->make_host_buffer_size(
+ L2CAP_MTU_SIZE, SCO_HOST_BUFFER_SIZE, L2CAP_HOST_FC_ACL_BUFS, 10));
+
+ packet_parser->parse_generic_command_complete(response);
+
+ // Read the local version info off the controller next, including
+ // information such as manufacturer and supported HCI version
+ response = AWAIT_COMMAND(packet_factory->make_read_local_version_info());
+ packet_parser->parse_read_local_version_info_response(response, &bt_version);
+
+ // Read the bluetooth address off the controller next
+ response = AWAIT_COMMAND(packet_factory->make_read_bd_addr());
+ packet_parser->parse_read_bd_addr_response(response, &address);
+
+ // Request the controller's supported commands next
+ response =
+ AWAIT_COMMAND(packet_factory->make_read_local_supported_commands());
+ packet_parser->parse_read_local_supported_commands_response(
+ response, supported_commands, HCI_SUPPORTED_COMMANDS_ARRAY_SIZE);
+
+ // Read page 0 of the controller features next
+ uint8_t page_number = 0;
+ response = AWAIT_COMMAND(
+ packet_factory->make_read_local_extended_features(page_number));
+ packet_parser->parse_read_local_extended_features_response(
+ response, &page_number, &last_features_classic_page_index,
+ features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT);
+
+ CHECK(page_number == 0);
+ page_number++;
+
+ // Inform the controller what page 0 features we support, based on what
+ // it told us it supports. We need to do this first before we request the
+ // next page, because the controller's response for page 1 may be
+ // dependent on what we configure from page 0
+ simple_pairing_supported =
+ HCI_SIMPLE_PAIRING_SUPPORTED(features_classic[0].as_array);
+ if (simple_pairing_supported) {
+ response = AWAIT_COMMAND(
+ packet_factory->make_write_simple_pairing_mode(HCI_SP_MODE_ENABLED));
+ packet_parser->parse_generic_command_complete(response);
+ }
+
+ if (HCI_LE_SPT_SUPPORTED(features_classic[0].as_array)) {
+ uint8_t simultaneous_le_host =
+ HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array)
+ ? BTM_BLE_SIMULTANEOUS_HOST
+ : 0;
+ response = AWAIT_COMMAND(packet_factory->make_ble_write_host_support(
+ BTM_BLE_HOST_SUPPORT, simultaneous_le_host));
+
+ packet_parser->parse_generic_command_complete(response);
+
+ // If we modified the BT_HOST_SUPPORT, we will need ext. feat. page 1
+ if (last_features_classic_page_index < 1)
+ last_features_classic_page_index = 1;
+ }
+
+ // Done telling the controller about what page 0 features we support
+ // Request the remaining feature pages
+ while (page_number <= last_features_classic_page_index &&
+ page_number < MAX_FEATURES_CLASSIC_PAGE_COUNT) {
+ response = AWAIT_COMMAND(
+ packet_factory->make_read_local_extended_features(page_number));
+ packet_parser->parse_read_local_extended_features_response(
+ response, &page_number, &last_features_classic_page_index,
+ features_classic, MAX_FEATURES_CLASSIC_PAGE_COUNT);
+
+ page_number++;
+ }
+
+#if (SC_MODE_INCLUDED == TRUE)
+ secure_connections_supported =
+ HCI_SC_CTRLR_SUPPORTED(features_classic[2].as_array);
+ if (secure_connections_supported) {
+ response = AWAIT_COMMAND(
+ packet_factory->make_write_secure_connections_host_support(
+ HCI_SC_MODE_ENABLED));
+ packet_parser->parse_generic_command_complete(response);
+ }
+#endif
+
+ ble_supported = last_features_classic_page_index >= 1 &&
+ HCI_LE_HOST_SUPPORTED(features_classic[1].as_array);
+ if (ble_supported) {
+ // Request the ble white list size next
+ response = AWAIT_COMMAND(packet_factory->make_ble_read_white_list_size());
+ packet_parser->parse_ble_read_white_list_size_response(
+ response, &ble_white_list_size);
+
+ // Request the ble buffer size next
+ response = AWAIT_COMMAND(packet_factory->make_ble_read_buffer_size());
+ packet_parser->parse_ble_read_buffer_size_response(
+ response, &acl_data_size_ble, &acl_buffer_count_ble);
+
+ // Response of 0 indicates ble has the same buffer size as classic
+ if (acl_data_size_ble == 0) acl_data_size_ble = acl_data_size_classic;
+
+ // Request the ble supported states next
+ response = AWAIT_COMMAND(packet_factory->make_ble_read_supported_states());
+ packet_parser->parse_ble_read_supported_states_response(
+ response, ble_supported_states, sizeof(ble_supported_states));
+
+ // Request the ble supported features next
+ response =
+ AWAIT_COMMAND(packet_factory->make_ble_read_local_supported_features());
+ packet_parser->parse_ble_read_local_supported_features_response(
+ response, &features_ble);
+
+ if (HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array)) {
+ response =
+ AWAIT_COMMAND(packet_factory->make_ble_read_resolving_list_size());
+ packet_parser->parse_ble_read_resolving_list_size_response(
+ response, &ble_resolving_list_max_size);
+ }
+
+ if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) {
+ response = AWAIT_COMMAND(
+ packet_factory->make_ble_read_suggested_default_data_length());
+ packet_parser->parse_ble_read_suggested_default_data_length_response(
+ response, &ble_suggested_default_data_length);
+ }
+
+ if (HCI_LE_EXTENDED_ADVERTISING_SUPPORTED(features_ble.as_array)) {
+ response = AWAIT_COMMAND(
+ packet_factory->make_ble_read_maximum_advertising_data_length());
+ packet_parser->parse_ble_read_maximum_advertising_data_length(
+ response, &ble_maxium_advertising_data_length);
+
+ response = AWAIT_COMMAND(
+ packet_factory->make_ble_read_number_of_supported_advertising_sets());
+ packet_parser->parse_ble_read_number_of_supported_advertising_sets(
+ response, &ble_number_of_supported_advertising_sets);
+ } else {
+ /* If LE Excended Advertising is not supported, use the default value */
+ ble_maxium_advertising_data_length = 31;
+ }
+
+ // Set the ble event mask next
+ response =
+ AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK));
+ packet_parser->parse_generic_command_complete(response);
+ }
+
+ if (simple_pairing_supported) {
+ response =
+ AWAIT_COMMAND(packet_factory->make_set_event_mask(&CLASSIC_EVENT_MASK));
+ packet_parser->parse_generic_command_complete(response);
+ }
+
+ // read local supported codecs
+ if (HCI_READ_LOCAL_CODECS_SUPPORTED(supported_commands)) {
+ response =
+ AWAIT_COMMAND(packet_factory->make_read_local_supported_codecs());
+ packet_parser->parse_read_local_supported_codecs_response(
+ response, &number_of_local_supported_codecs, local_supported_codecs);
+ }
+
+ readable = true;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ if (FWLogSwitch::GetInstance()->IsStarted()) {
+ FWLogSwitch::GetInstance()->Shutdown();
+ }
+#endif
+
+ readable = false;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t controller_module = {
+ .name = CONTROLLER_MODULE,
+ .init = NULL,
+ .start_up = start_up,
+ .shut_down = shut_down,
+ .clean_up = NULL,
+ .dependencies = {HCI_MODULE, NULL}};
+
+// Interface functions
+
+static bool get_is_ready(void) { return readable; }
+
+static const bt_bdaddr_t* get_address(void) {
+ CHECK(readable);
+ return &address;
+}
+
+static const bt_version_t* get_bt_version(void) {
+ CHECK(readable);
+ return &bt_version;
+}
+
+// TODO(zachoverflow): hide inside, move decoder inside too
+static const bt_device_features_t* get_features_classic(int index) {
+ CHECK(readable);
+ CHECK(index < MAX_FEATURES_CLASSIC_PAGE_COUNT);
+ return &features_classic[index];
+}
+
+static uint8_t get_last_features_classic_index(void) {
+ CHECK(readable);
+ return last_features_classic_page_index;
+}
+
+static uint8_t* get_local_supported_codecs(uint8_t* number_of_codecs) {
+ CHECK(readable);
+ if (number_of_local_supported_codecs) {
+ *number_of_codecs = number_of_local_supported_codecs;
+ return local_supported_codecs;
+ }
+ return NULL;
+}
+
+static const bt_device_features_t* get_features_ble(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return &features_ble;
+}
+
+static const uint8_t* get_ble_supported_states(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_supported_states;
+}
+
+static bool supports_simple_pairing(void) {
+ CHECK(readable);
+ return simple_pairing_supported;
+}
+
+static bool supports_secure_connections(void) {
+ CHECK(readable);
+ return secure_connections_supported;
+}
+
+static bool supports_simultaneous_le_bredr(void) {
+ CHECK(readable);
+ return HCI_SIMUL_LE_BREDR_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_reading_remote_extended_features(void) {
+ CHECK(readable);
+ return HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(supported_commands);
+}
+
+static bool supports_interlaced_inquiry_scan(void) {
+ CHECK(readable);
+ return HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_rssi_with_inquiry_results(void) {
+ CHECK(readable);
+ return HCI_LMP_INQ_RSSI_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_extended_inquiry_response(void) {
+ CHECK(readable);
+ return HCI_EXT_INQ_RSP_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_master_slave_role_switch(void) {
+ CHECK(readable);
+ return HCI_SWITCH_SUPPORTED(features_classic[0].as_array);
+}
+
+static bool supports_enhanced_setup_synchronous_connection(void) {
+ assert(readable);
+ return HCI_ENH_SETUP_SYNCH_CONN_SUPPORTED(supported_commands);
+}
+
+static bool supports_enhanced_accept_synchronous_connection(void) {
+ assert(readable);
+ return HCI_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(supported_commands);
+}
+
+static bool supports_ble(void) {
+ CHECK(readable);
+ return ble_supported;
+}
+
+static bool supports_ble_privacy(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_packet_extension(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_connection_parameters_request(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_CONN_PARAM_REQ_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_2m_phy(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_2M_PHY_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_coded_phy(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_CODED_PHY_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_extended_advertising(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_EXTENDED_ADVERTISING_SUPPORTED(features_ble.as_array);
+}
+
+static bool supports_ble_periodic_advertising(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return HCI_LE_PERIODIC_ADVERTISING_SUPPORTED(features_ble.as_array);
+}
+
+static uint16_t get_acl_data_size_classic(void) {
+ CHECK(readable);
+ return acl_data_size_classic;
+}
+
+static uint16_t get_acl_data_size_ble(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return acl_data_size_ble;
+}
+
+static uint16_t get_acl_packet_size_classic(void) {
+ CHECK(readable);
+ return acl_data_size_classic + HCI_DATA_PREAMBLE_SIZE;
+}
+
+static uint16_t get_acl_packet_size_ble(void) {
+ CHECK(readable);
+ return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE;
+}
+
+static uint16_t get_ble_suggested_default_data_length(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_suggested_default_data_length;
+}
+
+static uint16_t get_ble_maxium_advertising_data_length(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_maxium_advertising_data_length;
+}
+
+static uint8_t get_ble_number_of_supported_advertising_sets(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_number_of_supported_advertising_sets;
+}
+
+static uint16_t get_acl_buffer_count_classic(void) {
+ CHECK(readable);
+ return acl_buffer_count_classic;
+}
+
+static uint8_t get_acl_buffer_count_ble(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return acl_buffer_count_ble;
+}
+
+static uint8_t get_ble_white_list_size(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_white_list_size;
+}
+
+static uint8_t get_ble_resolving_list_max_size(void) {
+ CHECK(readable);
+ CHECK(ble_supported);
+ return ble_resolving_list_max_size;
+}
+
+static void set_ble_resolving_list_max_size(int resolving_list_max_size) {
+ // Setting "resolving_list_max_size" to 0 is done during cleanup,
+ // hence we ignore the "readable" flag already set to false during shutdown.
+ if (resolving_list_max_size != 0) {
+ CHECK(readable);
+ }
+ CHECK(ble_supported);
+ ble_resolving_list_max_size = resolving_list_max_size;
+}
+
+static uint8_t get_le_all_initiating_phys() {
+ uint8_t phy = PHY_LE_1M;
+ // TODO(jpawlowski): uncomment after next FW udpate
+ // if (supports_ble_2m_phy()) phy |= PHY_LE_2M;
+ // if (supports_ble_coded_phy()) phy |= PHY_LE_CODED;
+ return phy;
+}
+
+static const controller_t interface = {
+ get_is_ready,
+
+ get_address,
+ get_bt_version,
+
+ get_features_classic,
+ get_last_features_classic_index,
+
+ get_features_ble,
+ get_ble_supported_states,
+
+ supports_simple_pairing,
+ supports_secure_connections,
+ supports_simultaneous_le_bredr,
+ supports_reading_remote_extended_features,
+ supports_interlaced_inquiry_scan,
+ supports_rssi_with_inquiry_results,
+ supports_extended_inquiry_response,
+ supports_master_slave_role_switch,
+ supports_enhanced_setup_synchronous_connection,
+ supports_enhanced_accept_synchronous_connection,
+
+ supports_ble,
+ supports_ble_packet_extension,
+ supports_ble_connection_parameters_request,
+ supports_ble_privacy,
+ supports_ble_2m_phy,
+ supports_ble_coded_phy,
+ supports_ble_extended_advertising,
+ supports_ble_periodic_advertising,
+
+ get_acl_data_size_classic,
+ get_acl_data_size_ble,
+
+ get_acl_packet_size_classic,
+ get_acl_packet_size_ble,
+ get_ble_suggested_default_data_length,
+ get_ble_maxium_advertising_data_length,
+ get_ble_number_of_supported_advertising_sets,
+
+ get_acl_buffer_count_classic,
+ get_acl_buffer_count_ble,
+
+ get_ble_white_list_size,
+
+ get_ble_resolving_list_max_size,
+ set_ble_resolving_list_max_size,
+ get_local_supported_codecs,
+ get_le_all_initiating_phys};
+
+const controller_t* controller_get_interface() {
+ static bool loaded = false;
+ if (!loaded) {
+ loaded = true;
+
+ hci = hci_layer_get_interface();
+ packet_factory = hci_packet_factory_get_interface();
+ packet_parser = hci_packet_parser_get_interface();
+ }
+
+ return &interface;
+}
+
+const controller_t* controller_get_test_interface(
+ const hci_t* hci_interface,
+ const hci_packet_factory_t* packet_factory_interface,
+ const hci_packet_parser_t* packet_parser_interface) {
+ hci = hci_interface;
+ packet_factory = packet_factory_interface;
+ packet_parser = packet_parser_interface;
+ return &interface;
+}
diff --git a/mtkbt/code/bt/device/src/esco_parameters.cc b/mtkbt/code/bt/device/src/esco_parameters.cc
new file mode 100755
index 0000000..9a7b5d5
--- a/dev/null
+++ b/mtkbt/code/bt/device/src/esco_parameters.cc
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "base/logging.h"
+
+#include "device/include/esco_parameters.h"
+
+static const enh_esco_params_t default_esco_parameters[ESCO_NUM_CODECS] = {
+ // CVSD
+ {.transmit_bandwidth = TXRX_64KBITS_RATE,
+ .receive_bandwidth = TXRX_64KBITS_RATE,
+ .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_CVSD,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_CVSD,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .transmit_codec_frame_size = 60,
+ .receive_codec_frame_size = 60,
+ .input_bandwidth = INPUT_OUTPUT_64K_RATE,
+ .output_bandwidth = INPUT_OUTPUT_64K_RATE,
+ .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .input_coded_data_size = 16,
+ .output_coded_data_size = 16,
+ .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .input_pcm_payload_msb_position = 0,
+ .output_pcm_payload_msb_position = 0,
+ .input_data_path = ESCO_DATA_PATH_PCM,
+ .output_data_path = ESCO_DATA_PATH_PCM,
+ .input_transport_unit_size = 0x00,
+ .output_transport_unit_size = 0x00,
+#if (BTA_HFP_VERSION >= HFP_VERSION_1_7)
+ .max_latency_ms = 12,
+#else
+ .max_latency_ms = 10,
+#endif
+
+ .packet_types =
+ (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 |
+ ESCO_PKT_TYPES_MASK_HV3 | ESCO_PKT_TYPES_MASK_EV3 |
+ ESCO_PKT_TYPES_MASK_EV4 | ESCO_PKT_TYPES_MASK_EV5 |
+ ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 |
+ ESCO_PKT_TYPES_MASK_NO_3_EV5),
+#if (BTA_HFP_VERSION >= HFP_VERSION_1_7)
+ .retransmission_effort = ESCO_RETRANSMISSION_QUALITY
+#else
+ .retransmission_effort = ESCO_RETRANSMISSION_POWER
+#endif
+
+ },
+ // mSBC T1
+ {.transmit_bandwidth = TXRX_64KBITS_RATE,
+ .receive_bandwidth = TXRX_64KBITS_RATE,
+ .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_MSBC,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_MSBC,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .transmit_codec_frame_size = 60,
+ .receive_codec_frame_size = 60,
+ /** M: Change INPUT_OUTPUT_128K_RATE to 0x0100 @{ */
+ .input_bandwidth = 0x0100,
+ .output_bandwidth = 0x0100,
+ /** @} */
+ .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ /** M: Change 16 to 0x01E0 @{ */
+ .input_coded_data_size = 0x01E0,
+ .output_coded_data_size = 0x01E0,
+ /** @} */
+ .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .input_pcm_payload_msb_position = 0,
+ .output_pcm_payload_msb_position = 0,
+ .input_data_path = ESCO_DATA_PATH_PCM,
+ .output_data_path = ESCO_DATA_PATH_PCM,
+ /** M: Change 0x0 to 0x10 @{ */
+ .input_transport_unit_size = 0x10,
+ .output_transport_unit_size = 0x10,
+ /** @} */
+ .max_latency_ms = 8,
+ .packet_types =
+ (ESCO_PKT_TYPES_MASK_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 |
+ ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5 |
+ ESCO_PKT_TYPES_MASK_NO_2_EV3),
+ .retransmission_effort = ESCO_RETRANSMISSION_QUALITY},
+ // mSBC T2
+ {.transmit_bandwidth = TXRX_64KBITS_RATE,
+ .receive_bandwidth = TXRX_64KBITS_RATE,
+ .transmit_coding_format = {.coding_format = ESCO_CODING_FORMAT_MSBC,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .receive_coding_format = {.coding_format = ESCO_CODING_FORMAT_MSBC,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .transmit_codec_frame_size = 60,
+ .receive_codec_frame_size = 60,
+ /** M: Change INPUT_OUTPUT_128K_RATE to 0x0100 @{ */
+ .input_bandwidth = 0x0100,
+ .output_bandwidth = 0x0100,
+ /** @} */
+ .input_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ .output_coding_format = {.coding_format = ESCO_CODING_FORMAT_LINEAR,
+ .company_id = 0x0000,
+ .vendor_specific_codec_id = 0x0000},
+ /** M: Change 16 to 0x01E0 @{ */
+ .input_coded_data_size = 0x01E0,
+ .output_coded_data_size = 0x01E0,
+ /** @} */
+ .input_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .output_pcm_data_format = ESCO_PCM_DATA_FORMAT_2_COMP,
+ .input_pcm_payload_msb_position = 0,
+ .output_pcm_payload_msb_position = 0,
+ .input_data_path = ESCO_DATA_PATH_PCM,
+ .output_data_path = ESCO_DATA_PATH_PCM,
+ /** M: Change 0x0 to 0x10 @{ */
+ .input_transport_unit_size = 0x10,
+ .output_transport_unit_size = 0x10,
+ /** @} */
+ .max_latency_ms = 13,
+ .packet_types =
+ (ESCO_PKT_TYPES_MASK_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 |
+ ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5),
+ .retransmission_effort = ESCO_RETRANSMISSION_QUALITY}};
+
+enh_esco_params_t esco_parameters_for_codec(esco_codec_t codec) {
+ CHECK(codec >= 0) << "codec index " << (int)codec << "< 0";
+ CHECK(codec < ESCO_NUM_CODECS) << "codec index " << (int)codec << " > "
+ << ESCO_NUM_CODECS;
+ return default_esco_parameters[codec];
+}
diff --git a/mtkbt/code/bt/device/src/interop.cc b/mtkbt/code/bt/device/src/interop.cc
new file mode 100755
index 0000000..67ce177
--- a/dev/null
+++ b/mtkbt/code/bt/device/src/interop.cc
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_device_interop"
+
+#include <base/logging.h>
+#include <string.h> // For memcmp
+
+#include "btcore/include/module.h"
+#include "device/include/interop.h"
+#include "device/include/interop_database.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+static list_t* interop_list = NULL;
+
+static const char* interop_feature_string_(const interop_feature_t feature);
+static void interop_free_entry_(void* data);
+static void interop_lazy_init_(void);
+static bool interop_match_fixed_(const interop_feature_t feature,
+ const bt_bdaddr_t* addr);
+static bool interop_match_dynamic_(const interop_feature_t feature,
+ const bt_bdaddr_t* addr);
+
+// Interface functions
+
+bool interop_match_addr(const interop_feature_t feature,
+ const bt_bdaddr_t* addr) {
+ CHECK(addr);
+
+ if (interop_match_fixed_(feature, addr) ||
+ interop_match_dynamic_(feature, addr)) {
+ char bdstr[20] = {0};
+ LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
+ __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)),
+ interop_feature_string_(feature));
+ return true;
+ }
+
+ return false;
+}
+
+bool interop_match_name(const interop_feature_t feature, const char* name) {
+ CHECK(name);
+
+ const size_t db_size =
+ sizeof(interop_name_database) / sizeof(interop_name_entry_t);
+ for (size_t i = 0; i != db_size; ++i) {
+ if (feature == interop_name_database[i].feature &&
+ strlen(name) >= interop_name_database[i].length &&
+ strncmp(name, interop_name_database[i].name,
+ interop_name_database[i].length) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void interop_database_add(const uint16_t feature, const bt_bdaddr_t* addr,
+ size_t length) {
+ CHECK(addr);
+ CHECK(length > 0);
+ CHECK(length < sizeof(bt_bdaddr_t));
+
+ interop_addr_entry_t* entry = static_cast<interop_addr_entry_t*>(
+ osi_calloc(sizeof(interop_addr_entry_t)));
+ memcpy(&entry->addr, addr, length);
+ entry->feature = static_cast<interop_feature_t>(feature);
+ entry->length = length;
+
+ interop_lazy_init_();
+ list_append(interop_list, entry);
+}
+
+void interop_database_clear() {
+ if (interop_list) list_clear(interop_list);
+}
+
+// Module life-cycle functions
+
+static future_t* interop_clean_up(void) {
+ list_free(interop_list);
+ interop_list = NULL;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL module_t interop_module = {
+ .name = INTEROP_MODULE,
+ .init = NULL,
+ .start_up = NULL,
+ .shut_down = NULL,
+ .clean_up = interop_clean_up,
+ .dependencies = {NULL},
+};
+
+// Local functions
+
+static const char* interop_feature_string_(const interop_feature_t feature) {
+ switch (feature) {
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/// Values Added by MTK, @M{
+
+// Added for HOGP/GATT/LE, @start {
+
+ CASE_RETURN_STR(INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT)
+ CASE_RETURN_STR(INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST)
+ CASE_RETURN_STR(INTEROP_MTK_LE_CONN_LATENCY_ADJUST)
+ CASE_RETURN_STR(INTEROP_MTK_LE_DISABLE_FAST_CONNECTION)
+ CASE_RETURN_STR(INTEROP_MTK_LE_DISABLE_PREF_CONN_PARAMS)
+// } @end
+
+// Added for A2DP, @start {
+ CASE_RETURN_STR(INTEROP_MTK_A2DP_CHANGE_ACCEPT_SIGNALLING_TMS)
+ CASE_RETURN_STR(INTEROP_MTK_A2DP_DELAY_START_CMD)
+ CASE_RETURN_STR(INTEROP_MTK_CLOSE_AVDTP_SIG_CH)
+ CASE_RETURN_STR(INTEROP_MTK_AVRCP_DISABLE_SONG_POS)
+// } @end
+
+// Added for HFP, @start {
+ /** M: Add for HFP @{ */
+ CASE_RETURN_STR(INTEROP_MTK_HFP_DEALY_OPEN_SCO)
+ CASE_RETURN_STR(INTEROP_MTK_HFP_ACL_COLLISION)
+ CASE_RETURN_STR(INTEROP_MTK_WAIT_SLC_FOR_SCO)
+ CASE_RETURN_STR(INTEROP_MTK_HFP_17_TO_16)
+ CASE_RETURN_STR(INTEROP_MTK_HFP_GAIN_UPDATE_CANCEL)
+ /** @} */
+// } @end
+
+// Added for HID, @start {
+ /** M: Add for HID @{ */
+ CASE_RETURN_STR(INTEROP_MTK_HID_DISABLE_SDP)
+ CASE_RETURN_STR(INTEROP_MTK_HID_NOT_DO_SNIFF_SUBRATING)
+ /** @} */
+// } @end
+
+// Added for OPP/RFCOMM, @start {
+// } @end
+
+// Added for L2CAP, @start {
+// } @end
+
+// Added for L2CAP, @start {
+ CASE_RETURN_STR(INTEROP_MTK_ACCEPT_CONN_AS_MASTER)
+ CASE_RETURN_STR(INTEROP_MTK_ACCEPT_CONN_AS_SLAVE)
+
+// } @end
+
+// Added for GAP, @start {
+ CASE_RETURN_STR(INTEROP_MTK_DISABLE_SERVICE_SECURITY_CHECK)
+ CASE_RETURN_STR(INTEROP_MTK_LINK_POLICY_DISABLE_ROLE_SWITCH)
+// } @end
+
+// Added for SDP, @start {
+// } @end
+
+// Added for Common, @start {
+ CASE_RETURN_STR(INTEROP_MTK_FORBID_COMBINE_RFCOMM_DATA)
+// } @end
+/// } @M finish
+
+#endif
+ CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
+ CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
+ CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
+ CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
+ CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
+ CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
+ CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
+ CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
+ CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
+ }
+
+ return "UNKNOWN";
+}
+
+static void interop_free_entry_(void* data) {
+ interop_addr_entry_t* entry = (interop_addr_entry_t*)data;
+ osi_free(entry);
+}
+
+static void interop_lazy_init_(void) {
+ if (interop_list == NULL) {
+ interop_list = list_new(interop_free_entry_);
+ }
+}
+
+static bool interop_match_dynamic_(const interop_feature_t feature,
+ const bt_bdaddr_t* addr) {
+ if (interop_list == NULL || list_length(interop_list) == 0) return false;
+
+ const list_node_t* node = list_begin(interop_list);
+ while (node != list_end(interop_list)) {
+ interop_addr_entry_t* entry =
+ static_cast<interop_addr_entry_t*>(list_node(node));
+ CHECK(entry);
+
+ if (feature == entry->feature &&
+ memcmp(addr, &entry->addr, entry->length) == 0)
+ return true;
+
+ node = list_next(node);
+ }
+ return false;
+}
+
+static bool interop_match_fixed_(const interop_feature_t feature,
+ const bt_bdaddr_t* addr) {
+ CHECK(addr);
+
+ const size_t db_size =
+ sizeof(interop_addr_database) / sizeof(interop_addr_entry_t);
+ for (size_t i = 0; i != db_size; ++i) {
+ if (feature == interop_addr_database[i].feature &&
+ memcmp(addr, &interop_addr_database[i].addr,
+ interop_addr_database[i].length) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/mtkbt/code/bt/device/test/interop_test.cc b/mtkbt/code/bt/device/test/interop_test.cc
new file mode 100755
index 0000000..5116f2c
--- a/dev/null
+++ b/mtkbt/code/bt/device/test/interop_test.cc
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "device/include/interop.h"
+
+TEST(InteropTest, test_lookup_hit) {
+ bt_bdaddr_t test_address;
+ string_to_bdaddr("38:2c:4a:e6:67:89", &test_address);
+ EXPECT_TRUE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+ string_to_bdaddr("9c:df:03:12:34:56", &test_address);
+ EXPECT_TRUE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_lookup_miss) {
+ bt_bdaddr_t test_address;
+ string_to_bdaddr("00:00:00:00:00:00", &test_address);
+ EXPECT_FALSE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+ string_to_bdaddr("ff:ff:ff:ff:ff:ff", &test_address);
+ EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+ string_to_bdaddr("42:08:15:ae:ae:ae", &test_address);
+ EXPECT_FALSE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+ string_to_bdaddr("38:2c:4a:59:67:89", &test_address);
+ EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_dynamic) {
+ bt_bdaddr_t test_address;
+
+ string_to_bdaddr("11:22:33:44:55:66", &test_address);
+ EXPECT_FALSE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+
+ interop_database_add(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address, 3);
+ EXPECT_TRUE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+ EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+
+ string_to_bdaddr("66:55:44:33:22:11", &test_address);
+ EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+
+ interop_database_add(INTEROP_AUTO_RETRY_PAIRING, &test_address, 3);
+ EXPECT_TRUE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+ EXPECT_FALSE(
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address));
+
+ interop_database_clear();
+ EXPECT_FALSE(interop_match_addr(INTEROP_AUTO_RETRY_PAIRING, &test_address));
+}
+
+TEST(InteropTest, test_name_hit) {
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "BMW M3"));
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "Audi"));
+ EXPECT_TRUE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING,
+ "Caramel")); // Starts with "Car" ;)
+}
+
+TEST(InteropTest, test_name_miss) {
+ EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "__GOOGLE__"));
+ EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "BM"));
+ EXPECT_FALSE(interop_match_name(INTEROP_DISABLE_AUTO_PAIRING, "audi"));
+ EXPECT_FALSE(interop_match_name(INTEROP_AUTO_RETRY_PAIRING, "BMW M3"));
+}
diff --git a/mtkbt/code/bt/doc/btsnoop_net.md b/mtkbt/code/bt/doc/btsnoop_net.md
new file mode 100755
index 0000000..2500908
--- a/dev/null
+++ b/mtkbt/code/bt/doc/btsnoop_net.md
@@ -0,0 +1,15 @@
+btsnoop_net
+====
+btsnoop_net exposes Bluetooth snoop logs over a local TCP socket which enables
+real-time debugging of HCI data with hcidump.
+
+This feature is enabled by setting `BtSnoopLogOutput=true` in `bt_stack.conf`.
+Once it has been enabled and the stack restarted, the stack will listen for
+incoming TCP connections on port 8872.
+
+To use this feature with hcidump on a Linux host, you can run:
+
+```
+ $ adb forward tcp:8872 tcp:8872
+ $ nc localhost 8872 | hcidump -r /dev/stdin
+```
diff --git a/mtkbt/code/bt/doc/directory_layout.md b/mtkbt/code/bt/doc/directory_layout.md
new file mode 100755
index 0000000..80b17c8
--- a/dev/null
+++ b/mtkbt/code/bt/doc/directory_layout.md
@@ -0,0 +1,29 @@
+## Directory Layout
+
+### General directory layout
+Each directory should be a self contained subsystem consisting
+of one or more modules.
+
+* src/ - All source files for the subsystem.
+* include/ - All include files for the subsystem.
+* test/ - All unit tests for the subsystem.
+
+### Top level directory layout
+* audio_a2dp_hw - A2DP audio HAL implementation.
+* bta - *Bluetooth Application* - Strange collection of a-lot of things **Deprecate?**
+* btcore - *Bluetooth Core* - Bluetooth data type definitions and operations on those data types.
+* btif - *Bluetooth Interface* - JNI interface to Android.
+* conf - *Configuration* - Various configuration text files.
+* doc - *Documentation* - Stack documentation.
+* embdrv - **Deprecated** - Bluetooth SBC Codec.
+* hci - *Host Controller Interface* - Communication protocol with Bluetooth chip.
+* include - **Deprecated** - System global include files.
+* main - *Main stack entrypoint* - Provides HAL for stack access.
+* osi - *Operating System Interface* - General resource support for stack.
+* profiles - *Bluetooth Profiles* - **TBD** Collection of all profiles.
+* stack - **Deprecated** - The Stack - Push to proper spot in *./profiles*
+* test - *Test suite* - Stack level validiation and stress test suite.
+* tools - *Tools* - Various engineering support tools.
+* udrv - **Deprecated** *UIPC implementation*
+* utils - **Deprecated** *Bluetooth utilities* - Eliminate.
+* vnd - *Vendor* - Vendor specific APIs - *to be integrated into rest of stack ?*.
diff --git a/mtkbt/code/bt/doc/log_tags.md b/mtkbt/code/bt/doc/log_tags.md
new file mode 100755
index 0000000..fe6a3e4
--- a/dev/null
+++ b/mtkbt/code/bt/doc/log_tags.md
@@ -0,0 +1,57 @@
+Log Tags
+===
+This document lists all of the log tags used by the Bluetooth stack.
+
+* audio_a2dp_hw
+* BTA_AG_CO:
+* bta_sys_main
+* bt_btif
+* bt_btif_config
+* bt_btif_config_transcode
+* bt_classic_peer
+* bte_conf
+* BtGatt.btif
+* BtGatt.btif_test
+* bt_hci
+* bt_hci_h4
+* bt_hci_inject
+* bt_hci_mct
+* bt_hci_packet_fragmenter
+* BTIF_AV
+* BTIF_CORE
+* BTIF_HF
+* BTIF_HF_CLIENT
+* BTIF_HH
+* BTIF_HL
+* BTIF-MEDIA
+* BTIF_PAN
+* BTIF_QUEUE
+* BTIF_RC
+* BTIF_SM
+* btif_sock
+* BTIF_SOCK
+* btif_sock_rfcomm
+* btif_sock_sco
+* BTIF_SOCK_SDP
+* BTIF_STORAGE
+* BTIF_UTIL
+* BTLD
+* bt_module
+* bt_osi_alarm
+* bt_osi_config
+* bt_osi_data_dispatcher
+* bt_osi_reactor
+* bt_osi_socket
+* bt_profile_manager
+* bt_sdp_client
+* btsnoop
+* btsnoop_net
+* bt_stack_config
+* bt_stack_manager
+* bt_task
+* btu_task
+* BT_UTILS
+* bt_vendor
+* osi_future
+* osi_semaphore
+* osi_thread
diff --git a/mtkbt/code/bt/doc/network_ports.md b/mtkbt/code/bt/doc/network_ports.md
new file mode 100755
index 0000000..03e138e
--- a/dev/null
+++ b/mtkbt/code/bt/doc/network_ports.md
@@ -0,0 +1,8 @@
+Network Ports
+===
+This document lists all of the network ports used by the bluetooth stack.
+It should be used as a reference and as a mechanism to avoid port
+namespace conflicts.
+
+* TCP 8872 (hci/src/btsnoop_net.cc) - read live btsnoop logs
+* TCP 8873 (hci/src/hci_inject.cc) - inject HCI packets into HCI stream
diff --git a/mtkbt/code/bt/doc/power_management.md b/mtkbt/code/bt/doc/power_management.md
new file mode 100755
index 0000000..2b90130
--- a/dev/null
+++ b/mtkbt/code/bt/doc/power_management.md
@@ -0,0 +1,202 @@
+## Power Management
+
+### Overview
+
+Power management (PM) is an event-driven state machine, tickled by various
+`bta/sys` events via a callback. The actual state switching calls are handled
+by the BTM HCI interfacing code, with results being posted back to the PM
+code via the BTA workqueue thread.
+
+Power states are managed per-device, per-profile, so every incoming event
+includes a profile ID, app ID, and a `BD_ADDR`.
+
+The events fired to drive the state machine at the time of this writing are:
+
+ - `BTA_SYS_CONN_OPEN`
+ - `BTA_SYS_CONN_CLOSE`
+ - `BTA_SYS_CONN_IDLE`
+ - `BTA_SYS_CONN_BUSY`
+ - `BTA_SYS_APP_OPEN`
+ - `BTA_SYS_APP_CLOSE`
+ - `BTA_SYS_SCO_OPEN`
+ - `BTA_SYS_SCO_CLOSE`
+
+Each of these correspond to a function name in `bta/sys/bta_sys_conn.cc`, which
+are called by each profile definition in `bta/$PROFILE`.
+
+The PM code makes calls into the BTM module to set various power
+states. Responses are handled in an asynchronous fashion, primarily via the
+callbacks `bta_dm_pm_cback` and `bta_dm_pm_timer_cback`. Responses are handled
+through the BTA workqueue thread and the `bta_dm_pm_btm_status` function. Since
+we might possibly get into a bad state where we never hear back from the
+controller, timers are used to post messages to the BTA workqueue thread as
+well, which filters down through the same status function.
+
+Overall power states are managed *per device*, not per connection, but the power
+policy is determined by the greatest allowable power action defined across all
+currently known connections to a given device. Thus, if RFCOMM specifies that
+it's willing to go to into SNIFF and specifies that as an action, and say, a PAN
+connection is up which specifies it is willing to go into SNIFF, but its action
+states it wants ACTIVE, the power management code will change to ACTIVE.
+
+### Power management tables
+
+The tables that determine which power levels are acceptable for which profiles
+and what actions to take for the above events are defined in the
+`bta/dm/bta_dm_cfg.cc` file, as `bta_dm_pm_cfg`, `bta_dm_pm_spec`, and
+`bta_dm_ssr_spec`.
+
+During a lookup attempt, the code iterates over the `bta_dm_pm_cfg` array,
+looking for a match between the profile and app IDs. When it finds one, it uses
+the `spec_idx` field to index into `bta_dm_pm_spec` array to determine which
+power modes are acceptable and what actions to take for each event.
+
+The action constants are defined in `bta_api.h` and are defined as a series of
+hex bitfields. The actual actions taken are determined by the
+`bta_dm_pm_set_mode` function, but a few of the actions listed deserve some
+additional description:
+
+ - `BTA_DM_PM_NO_ACTION` is effectively a no-op and has a value of zero, so any
+ other profile will override this.
+ - `BTA_DM_PM_NO_PREF` overrides `BTA_DM_PM_NO_ACTION` and if selected as the
+ action that `bta_dm_pm_set_mode` will take, the connection will be removed
+ from `bta_dm_conn_srvcs` and no longer be considered for power management
+ decisions.
+ - `BTA_DM_PM_SNIFF` through `BTA_DM_PM_SNIFF4` are special, in that each
+ level specifies a set of parameters for the SNIFF mode which relate to the
+ min and max intervals, the number of attempts and the timeout. The overall
+ action is still the same, however -- SNIFF mode is attempted. There are
+ definitions available up to SNIFF7, but actual SSR values are only defined
+ up to SNIFF4. Params are defined in `bta_dm_ssr_spec`.
+ - `BTA_DM_PM_ACTIVE` is full-on power.
+ - `BTA_DM_PM_RETRY` has the same effect as `BTA_DM_PM_NO_ACTION`, except a
+ timeout is possible to be set, which effectively allows a power operation to
+ be "retried".
+
+### Initialization
+
+`bta_dm_pm.cc`'s `bta_dm_init_pm` function calls out to register
+`bta_dm_pm_cback` with the bta sys module for incoming power management events,
+and also registers `bta_dm_pm_btm_cback` with the btm module to handle responses
+and timeouts of HCI requests (via `bta_dm_pm_btm_status`).
+
+At this point, the power managment code is basically done until the first set of
+events come in through `bta_dm_pm_cback`.
+
+Throughout the `bta_dm_pm.cc` file, connections whose power management states are
+managed are tracked in a global array called `bta_dm_conn_srvcs`. Unfortunately,
+while this variable is declared as an extern in the `bta_dm_int.h` file, it only
+seems to be used in the `bta_dm_act.cc` file, and only for reinitialization.
+
+### Event flow
+
+#### Events fired from SYS
+
+ 1. An event is fired from one of the methods mentioned above in
+ `bta/sys/bta_sys_conn.cc`
+ 2. The `bta_dm_pm_cback` function is called.
+ - The power mode config is looked up in the `bta_dm_pm_cfg` table. If none
+ are found for the given profile ID and app ID, the function simply
+ returns with no action taken.
+ - If any timers were set for the given `BD_ADDR`, they are stopped.
+ - The SSR params for the CONN_OPEN event are looked up.
+ - The power spec state table (`bta_dm_pm_spec`) is checked to see if
+ there's no action to be performed (`BTA_DM_PM_NO_ACTION`), and if so,
+ returns with no action taken.
+ - `bta_dm_conn_srvcs` is consulted to ensure there's an entry for this
+ connection if it's supposed to be managed according to the power spec
+ state tables. If the spec specifies `BTA_DM_PM_NO_PREF`, then any
+ existing entry in this list is removed, otherwise one is added/updated
+ with the state given to the function.
+ 3. `bta_dm_pm_cback` checks to see if the `bta_dm_ssr_spec` specifies SSR
+ adjustments are to be made, and if so, `bta_dm_pm_ssr` is called with the
+ peer `BD_ADDR`.
+ - `bta_dm_pm_ssr` iterates the managed services array to find all connected
+ services for the given `BD_ADDR`, then looks up the ssr values from the
+ `bta_dm_ssr_spec` tables, looking for the smallest max latency to use.
+ - `bta_dm_pm_ssr` calls `BTM_SetSsrParams` to actually send along the SSR
+ params to the bluetooth chip.
+ 4. `bta_dm_pm_cback` calls `bta_dm_pm_set_mode` with the peer address and the
+ `timed_out` parameter set to `false`.
+ - For each managed connection, `bta_dm_pm_set_mode` grabs
+ both actions specified for the profile in the `bta_dm_pm_spec` tables. If
+ the first power management action didn't timeout (or was never attempted,
+ according to the `tBTA_DM_PEER_DEVICE` `pm_mode_failed` and
+ `pm_mode_attempted` fields), its timeout and mode are used. Otherwise,
+ the same check is done against the second action and it is used
+ instead. If both actions have been attempted, then the action is set to
+ `BTA_DM_PM_NO_ACTION`. Only the highest power mode action is chosen from
+ all connected profiles.
+ - If the chosen action is `BTA_DM_PM_PARK` or `BTA_DM_PM_SNIFF` but the
+ profile doesn't allow it, this function takes no action.
+ - If a timeout is specified in the power spec table, then an unused timer
+ in `bta_dm_cb.pm_timer` is started.
+ - If the action chosen is `BTA_DM_PM_PARK`, `bta_dm_pm_park` is called,
+ which calls `BTM_ReadPowerMode` and `BTM_SetPowerMode` to make an HCI
+ request to enable PARK for the given peer and connection.
+ - If the action chosen is `BTA_DM_PM_SNIFF`, the peer device's link policy
+ is checked to see if it's allowed. If so, then `bta_dm_pm_sniff` is
+ called, which makes various calls to `BTM_ReadLocalFeatures`,
+ `BTM_ReadRemoteFeatures` and `BTM_SetPowerMode` to ensure SNIFF mode is
+ enabled.
+ - If the action chosen is `BTA_DM_PM_ACTIVE`, a call to `bta_dm_pm_active`
+ is made, which calls `BTM_SetPowerMode` to set the link into ACTIVE
+ mode.
+
+At this point, if one of the timers in `bta_dm_cb.pm_timer` times out, a call is
+made through the BTA workqueue thread to `bta_dm_pm_btm_cback`, which then
+triggers `bta_dm_pm_btm_status`, with the timeout field set to TRUE. HCI
+responses are also fired as messages through the BTA workqueue thread, which are
+handled again, through `bta_dm_pm_btm_status`.
+
+#### Events fired through BTM
+
+Essentially these messages eventually go through the same functions as events
+fired from the SYS side of things, except from the initial path they take:
+
+ 1. An event is fired from a callback in BTM to `bta_dm_pm_btm_cback`.
+ 2. `bta_dm_pm_btm_cback` packages up the given parameters into a
+ `tBTA_DM_PM_BTM_STATUS` struct and posts it to the BTA workqueue thread via
+ `bta_sys_sendmsg`, with the event header set to
+ `BTA_DM_PM_BTM_STATUS_EVT`.
+ 3. This is eventually routed to the `bta_dm_pm_btm_status` function.
+ **Determine if this is running on the workqueue thread or not**
+ - The message `status` passed in is actually the current status of the
+ device.
+ - If the status is `BTM_PM_STS_ACTIVE` (still in the ACTIVE power mode),
+ checks the HCI status code:
+ - If that's non-zero and a PARK or SNIFF mode change was attempted,
+ `bta_dm_pm_btm_status` stops any timers started for the device in
+ `bta_dm_pm_set_mode`, clears some status bits in the peer device
+ structure, and then calls back into `bta_dm_pm_set_mode` with the peer
+ device address and timeout set to FALSE.
+ - If the status is zero, and if the peer device `tBTA_DM_PEER_DEVICE`
+ `prev_low` field is set, calls `bta_dm_pm_ssr` to re-send SSR params,
+ stops all timers for the device, and then re-calls `bta_dm_pm_set_mode`
+ with timeout set to FALSE to re-attempt with a second action (if the
+ previous PARK or SNIFF failed, otherwise it'll re-attempt the first
+ action).
+ - If the status is `BTM_PM_STS_PARK` or `BTM_PM_STS_HOLD`, saves the
+ previous low power mode in the peer device's `prev_low` field.
+ - If the status is `BTM_PM_STS_SSR`, simply clears or sets the device
+ `info` field's `BTA_DM_DI_USE_SSR` bit, depending on the value of
+ `tBTA_DM_MSG.value`, which determines if the device can handle SSR.
+ - If the status is `BTM_PM_STS_SNIFF` and the info field has the
+ `BTA_DM_DI_SET_SNIFF` bit set, then `BTA_DM_DI_INT_SNIFF` is set,
+ otherwise `BTA_DM_DI_ACP_SNIFF` is set.
+ - If `BTA_PM_STS_ERROR`, the `BTA_DM_DI_SET_SNIFF` bit is cleared in the
+ device info field.
+
+At this point, either the method simply returns, or has called back into
+`bta_dm_pm_set_mode`, in which case the usual flow takes over.
+
+#### Events fired from timers
+
+Timers are used exclusively for handling HCI command timeouts, and filter
+through to a call to `bta_dm_pm_set_mode`:
+
+ 1. A timer expires, and calls `bta_dm_pm_timer_cback`.
+ 2. `bta_dm_pm_timer_cback` clears the use flag on the timer that fired, and
+ sends off an event to the BTA workqueue thread.
+ 3. The event eventually fires off a call to `bta_dm_pm_timer`, which just
+ calls `bta_dm_pm_set_mode` with timeout set to `TRUE`.
diff --git a/mtkbt/code/bt/doc/properties.md b/mtkbt/code/bt/doc/properties.md
new file mode 100755
index 0000000..c4ab97c
--- a/dev/null
+++ b/mtkbt/code/bt/doc/properties.md
@@ -0,0 +1,20 @@
+Properties
+===
+This document describes all of the Android properties used by the Bluetooth
+stack.
+
+Please keep the following list in alphabetical order.
+
+* ``` bluetooth.enable_timeout_ms ```
+ Maximum amount of time Bluetooth can take to start-up, upload firmware etc.
+ Used in hci/src/hci_layer.cc, default 8000.
+
+### TODO: write descriptions of what each property means and how
+it's used.
+
+* ``` debug.sys.noschedgroups ```
+* ``` persist.service.bdroid.bdaddr ```
+* ``` ro.bluetooth.hfp.ver ```
+* ``` ro.bt.bdaddr_path ```
+* ``` ro.product.model ```
+* ``` service.brcm.bt.oob ```
diff --git a/mtkbt/code/bt/doc/style_guide.md b/mtkbt/code/bt/doc/style_guide.md
new file mode 100755
index 0000000..8490fd2
--- a/dev/null
+++ b/mtkbt/code/bt/doc/style_guide.md
@@ -0,0 +1,429 @@
+# Fluoride Style Guide
+This document outlines the coding conventions and code style used in Fluoride.
+Its primary purpose is to provide explicit guidance on style so that developers
+are consistent with one another and spend less time debating style.
+
+As a rule, we follow the Google C++
+[Style Guide](https://google.github.io/styleguide/cppguide.html).
+Exceptions will be noted below.
+
+## Directory structure
+Directories at the top-level should consist of major subsystems in Fluoride.
+Each subsystem's purpose should be documented in the `doc/directory_layout.md`
+file, even if it seems obvious from the name.
+
+For a subsystem that contains code, its directory structure should look like:
+```
+ Android.mk
+ include/
+ src/
+ test/
+```
+Further, the directory structure inside `src/` and `include/` should be
+mirrored. In other words, if `src/` contains a subdirectory called `foo/`,
+`include/` must also have a subdirectory named `foo/`.
+
+## Target architecture
+Fluoride targets a variety of hardware and cannot make many assumptions about
+memory layout, sizes, byte order, etc. As a result, some operations are
+considered unsafe and this section outlines the most important ones to watch out
+for.
+
+### Pointer / integer casts
+In general, do not cast pointers to integers or vice versa.
+
+The one exception is if an integer needs to be temporarily converted to a
+pointer and then back to the original integer. This style of code is typically
+needed when providing an integral value as the context to a callback, as in the
+following example.
+```
+void my_callback(void *context) {
+ uintptr_t arg = context;
+}
+
+set_up_callback(my_callback, (uintptr_t)5);
+```
+Note, however, that the integral value was written into the pointer and read
+from the pointer as a `uintptr_t` to avoid a loss of precision (or to make the
+loss explicit).
+
+### Byte order
+It is not safe to assume any particular byte order. When serializing or
+deserializing data, it is unsafe to memcpy unless both source and destination
+pointers have the same type.
+
+## Language
+Fluoride is written in C99 and should take advantage of the features offered by
+it. However, not all language features lend themselves well to the type of
+development required by Fluoride. This section provides guidance on some of the
+features to embrace or avoid.
+
+### C Preprocessor
+The use of the C preprocessor should be minimized. In particular:
+* use functions or, if absolutely necessary, inline functions instead of macros
+* use `static const` variables instead of `#define`
+* use `enum` for enumerations, not a collection of `#define`s
+* minimize the use of feature / conditional macros
+
+The last point is perhaps the most contentious. It's well-understood that
+feature macros are useful in reducing code size but it leads to an exponential
+explosion in build configurations. Setting up, testing, and verifying each of
+the `2^n` build configurations is untenable for `n` greater than, say, 4.
+
+### C++
+Although C++ offers constructs that may make Fluoride development faster,
+safer, more pleasant, etc. the decision _for the time being_ is to stick with
+pure C99. The exceptions are when linking against libraries that are written
+in C++. At the time of writing these libraries are `gtest` and `tinyxml2`,
+where the latter is a dependency that should be eliminated in favor of simpler,
+non-XML formats.
+
+### Variadic functions
+Variadic functions are dangerous and should be avoided for most code. The
+exception is when implementing logging since the benefits of readability
+outweigh the cost of safety.
+
+### Functions with zero arguments
+Functions that do not take any arguments (0 arity) should be declared like so:
+```
+void function(void);
+```
+Note that the function explicitly includes `void` in its parameter list to
+indicate to the compiler that it takes no arguments.
+
+### Variable declarations
+Variables should be declared one per line as close to initialization as possible.
+In nearly all cases, variables should be declared and initialized on the same line.
+Variable declarations should not include extra whitespace to line up fields. For
+example, the following style is preferred:
+```
+ int my_long_variable_name = 0;
+ int x = 5;
+```
+whereas this code is not acceptable:
+```
+ int my_long_variable_name = 0;
+ int x = 5;
+```
+
+As a result of the above rule to declare and initialize variables together,
+`for` loops should declare and initialize their iterator variable in the
+initializer statement:
+```
+ for (int i = 0; i < 10; ++i) {
+ // use i
+ }
+```
+
+### Contiguous memory structs
+Use C99 flexible arrays as the last member of a struct if the array needs
+to be allocated in contiguous memory with its containing struct.
+A flexible array member is writen as `array_name[]` without a specified size.
+For example:
+```
+typedef struct {
+ size_t length;
+ uint8_t data[];
+} buffer_t;
+
+// Allocate a buffer with 128 bytes available for my_buffer->data.
+buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
+uint8_t *data = my_buffer->data;
+```
+
+### Pointer arithmetic
+Avoid pointer arithmetic when possible as it results in difficult to read code.
+Prefer array-indexing syntax over pointer arithmetic.
+
+In particular, do not write code like this:
+```
+typedef struct {
+ size_t length;
+} buffer_t;
+
+buffer_t *my_buffer = malloc(sizeof(buffer_t) + 128);
+uint8_t *data = (uint8_t *)(my_buffer + 1);
+```
+Instead, use zero-length arrays as described above to avoid pointer arithmetic
+and array indexing entirely.
+
+### Boolean type
+Use the C99 `bool` type with values `true` and `false` defined in `stdbool.h`.
+Not only is this a standardized type, it is also safer and provides more
+compile-time checks.
+
+### Booleans instead of bitfields
+Use booleans to represent boolean state, instead of a set of masks into an
+integer. It's more transparent and readable, and less error prone.
+
+### Function names as strings
+C99 defines `__func__` as an identifier that represents the function's name
+in which it is used. The magic identifier `__FUNCTION__` should not be used
+as it is a non-standard language extension and an equivalent standardized
+mechanism exists. In other words, use `__func__` over `__FUNCTION__`.
+
+## Fluoride conventions
+This section describes coding conventions that are specific to Fluoride.
+Whereas the _Language_ section describes the use of language features, this
+section describes idioms, best practices, and conventions that are independent
+of language features.
+
+### Memory management
+Use `osi_malloc` or `osi_calloc` to allocate bytes instead of plain `malloc`.
+Likewise, use `osi_free` over `free`. These wrapped functions provide additional
+lightweight memory bounds checks that can help track down memory errors.
+
+By convention, functions that contain `*_new` in their name are allocation
+routines and objects returned from those functions must be freed with the
+corresponding `*_free` function. For example, list objects returned from
+`list_new` should be freed with `list_free` and no other freeing routine.
+
+### Asserts
+Use `CHECK` liberally throughout the code to enforce invariants. Assertions
+should not have any side-effects and should be used to detect programming logic
+errors. Please do not use `assert`.
+
+At minimum, every function should assert expectations on its arguments. The
+following example demonstrates the kinds of assertions one should make on
+function arguments.
+```
+ size_t open_and_read_file(const char *filename, void *target_buffer, size_t max_bytes) {
+ CHECK(filename != NULL);
+ CHECK(filename[0] != '\0');
+ CHECK(target_buffer != NULL);
+ CHECK(max_bytes > 0);
+
+ // function implementation begins here
+ }
+```
+
+## Header files
+In general, every source file (`.c` or `.cpp`) in a `src/` directory should
+have a corresponding header (`.h`) in the `include/` directory.
+
+### Template header file
+```
+[copyright header]
+
+#pragma once
+
+#include <system/a.h>
+#include <system/b.h>
+
+#include "subsystem/include/a.h"
+#include "subsystem/include/b.h"
+
+typedef struct alarm_t alarm_t;
+typedef struct list_t list_t;
+
+// This comment describes the following function. It is not a structured
+// comment, it's English prose. Function arguments can be referred to as
+// |param|. This function returns true if a new object was created, false
+// otherwise.
+bool template_new(const list_t *param);
+
+// Each public function must have a comment describing its semantics. In
+// particular, edge cases, and whether a pointer argument may or may not be
+// NULL.
+void template_use_alarm(alarm_t *alarm);
+```
+
+### License header
+Each header file must begin with the following Apache 2.0 License with `<year>`
+and `<owner>` replaced with the year in which the file was authored and the
+owner of the copyright, respectively.
+```
+/******************************************************************************
+ *
+ * Copyright (C) <year> <owner>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+```
+
+### Include guard
+After the license header, each header file must contain the include guard:
+```
+#pragma once
+```
+This form is used over traditional `#define`-based include guards as it is less
+error-prone, doesn't pollute the global namespace, is more compact, and can
+result in faster compilation.
+
+## Formatting
+Code formatting is done automatically using clang-format.
+
+The style file is located at the root of the source tree in .clang-format. The
+-style=file option instructs clang-format to look for this file. You may find
+clang-format --help useful for more advanced usage. The [Online clang-format
+Documentation](http://clang.llvm.org/docs/ClangFormat.html) can also be helpful.
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+### My Patch Doesn't Apply Anymore!
+Choose one of the options below. The fewer patches that have been applied to
+the tree since the formatting change was applied, the better. In this short
+guide, commands you type will be marked as `code`, with output in *italics*.
+
+#### Option 1: The Best Case
+Use this option if your patch touches only a few files with few intermediate
+patches.
+
+##### Find the formatting patch
+
+`git log --oneline path_to_files/filename_or_* | grep clang-format | head -n 5`
+
+ **15ce1bd** subtree: Apply **clang-format** for the first time*
+
+##### Revert the formatting patch
+
+`git revert HASH -n`
+
+(Replace HASH with 15ce1bd in this example.)
+
+##### Check for conflicts with your patch
+
+`git status | grep both.modified`
+
+If this list contains files modified by your patch, you should give up
+
+`git revert --abort`
+
+and try a different method.
+
+If this list contains files not modified by your patch, you should unstage them
+
+`git reset HEAD both_modified_file`
+
+and remove their changes
+
+`git checkout both_modified_file`
+
+##### Apply your patch
+
+`git cherry-pick your_patch_that_used_to_apply_cleanly`
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit the code that your patch touched
+
+`git add path_to_files/filename_or_*`
+
+`git commit --amend`
+
+##### Clean up any other files
+
+`git checkout .`
+
+##### Review your new patch
+
+`git diff`
+
+#### Option 2: Reformat your patch
+
+##### Start with a tree with your patch applied to the tip of tree
+
+`git log --oneline | head -n 1`
+
+ **dc5f0e2** Unformatted but vital patch*
+
+(**Remember the HASH from this step**)
+
+##### Create a new branch starting from the first unrelated patch
+
+`git checkout HEAD^ -b reformat_my_patch_branch`
+
+`git log --oneline | head -n 1`
+
+ **15ce1bd** First Unrelated patch*
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit your temporary formatting patch
+
+`git add path_to_files/filename_or_*`
+
+`git commit -m tmp_format_patch`
+
+##### Revert your temporary formatting patch (**Bear with me!**)
+
+`git revert HEAD --no-edit`
+
+##### Apply your patch
+
+`git cherry-pick HASH`
+
+(The HASH of your patch, dc5f0e2 in this case)
+
+##### Reformat the code
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Commit your second temporary formatting patch
+
+`git add path_to_files/filename_or_*`
+
+`git commit -m tmp_format_patch_2`
+
+##### Check to see that everything looks right
+
+`git log --oneline | head -n 5`
+
+*04c97cf tmp_format_patch_2*
+
+*cf8560c Unformatted but vital patch*
+
+*04c97cf Revert "tmp_format_patch"*
+
+*d66bb6f tmp_format_patch*
+
+*15ce1bd First Unrelated patch*
+
+##### Squash the last three patches with git rebase
+
+`git rebase -i HEAD^^^`
+
+*pick 04c97cf tmp_format_patch_2*
+
+*squash cf8560c Unformatted but vital patch*
+
+*squash 04c97cf Revert "tmp_format_patch"*
+
+##### Remember to edit the commit message!
+
+`clang-format -style=file -i path_to_files/filename_or_*`
+
+##### Check to see that everything looks right
+
+`git log --oneline | head -n 2`
+
+*523078f Reformatted vital patch*
+
+*d66bb6f tmp_format_patch*
+
+##### Review your new patch
+
+`git show`
+
+##### Checkout the current tree and cherry pick your reformatted patch!
+
+`git checkout aosp/master`
+
+`git cherry-pick HASH`
+
+(HASH is 523078f in this example)
diff --git a/mtkbt/code/bt/doc/supported_features.md b/mtkbt/code/bt/doc/supported_features.md
new file mode 100755
index 0000000..60580e2
--- a/dev/null
+++ b/mtkbt/code/bt/doc/supported_features.md
@@ -0,0 +1,20 @@
+# Fluoride 1.1
+
+Declaration ID: [D024527](https://www.bluetooth.org/tpg/QLI_viewQDL.cfm?qid=24527)
+Qualified Design ID: 83953
+
+Protocol / Profile | Version | Roles
+-------------------+---------+-------
+L2CAP | 4.2 | Initiator, Acceptor, LE Master, LE Slave
+SDP | 4.2 | Server, Client
+GAP | 4.2 | BR/EDR, LE Central, LE Periperhal, LE Observer, LE Broadcaster
+GATT | 4.2 | Client, Server; LE and BR/EDR
+ATT | 4.2 | Client, Server; LE and BR/EDR
+SM | 4.2 | Master (Initiator), Slave (Responder)
+AVCTP | 1.4 | Controller, Target
+AVDTP | 1.2 | Source, Initiator, Acceptor
+BNEP | 1.0 |
+GAVDP | 1.2 | Initiator, Acceptor
+MCAP | 1.0 | Sink
+RFCOMM | 1.2 |
+SPP | 1.2 | A, B
diff --git a/mtkbt/code/bt/embdrv/Android.bp b/mtkbt/code/bt/embdrv/Android.bp
new file mode 100755
index 0000000..7c6328e
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+ "sbc",
+]
diff --git a/mtkbt/code/bt/embdrv/sbc/Android.bp b/mtkbt/code/bt/embdrv/sbc/Android.bp
new file mode 100755
index 0000000..5696377
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+ "decoder",
+ "encoder",
+]
diff --git a/mtkbt/code/bt/embdrv/sbc/BUILD.gn b/mtkbt/code/bt/embdrv/sbc/BUILD.gn
new file mode 100755
index 0000000..7e75633
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/BUILD.gn
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+source_set("sbc_decoder") {
+ sources = [
+ "decoder/srce/alloc.c",
+ "decoder/srce/bitalloc.c",
+ "decoder/srce/bitalloc-sbc.c",
+ "decoder/srce/bitstream-decode.c",
+ "decoder/srce/decoder-oina.c",
+ "decoder/srce/decoder-private.c",
+ "decoder/srce/decoder-sbc.c",
+ "decoder/srce/dequant.c",
+ "decoder/srce/framing.c",
+ "decoder/srce/framing-sbc.c",
+ "decoder/srce/oi_codec_version.c",
+ "decoder/srce/synthesis-8-generated.c",
+ "decoder/srce/synthesis-dct8.c",
+ "decoder/srce/synthesis-sbc.c",
+ ]
+
+ include_dirs = [ "decoder/include" ]
+}
+
+source_set("sbc_encoder") {
+ sources = [
+ "encoder/srce/sbc_analysis.c",
+ "encoder/srce/sbc_dct.c",
+ "encoder/srce/sbc_dct_coeffs.c",
+ "encoder/srce/sbc_enc_bit_alloc_mono.c",
+ "encoder/srce/sbc_enc_bit_alloc_ste.c",
+ "encoder/srce/sbc_enc_coeffs.c",
+ "encoder/srce/sbc_encoder.c",
+ "encoder/srce/sbc_packing.c",
+ ]
+
+ include_dirs = [
+ "encoder/include",
+ "//include",
+ "//stack/include",
+ ]
+}
+
+static_library("sbc") {
+ deps = [
+ ":sbc_decoder",
+ ":sbc_encoder",
+ ]
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/Android.bp b/mtkbt/code/bt/embdrv/sbc/decoder/Android.bp
new file mode 100755
index 0000000..274f2bf
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/Android.bp
@@ -0,0 +1,26 @@
+// Bluetooth SBC decoder static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-sbc-decoder",
+ defaults: ["fluoride_defaults"],
+ srcs: [
+ "srce/alloc.c",
+ "srce/bitalloc.c",
+ "srce/bitalloc-sbc.c",
+ "srce/bitstream-decode.c",
+ "srce/decoder-oina.c",
+ "srce/decoder-private.c",
+ "srce/decoder-sbc.c",
+ "srce/dequant.c",
+ "srce/framing.c",
+ "srce/framing-sbc.c",
+ "srce/oi_codec_version.c",
+ "srce/synthesis-sbc.c",
+ "srce/synthesis-dct8.c",
+ "srce/synthesis-8-generated.c",
+ ],
+ local_include_dirs: [
+ "include",
+ "srce",
+ ],
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_assert.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_assert.h
new file mode 100755
index 0000000..1d18f12
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_assert.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_ASSERT_H
+#define _OI_ASSERT_H
+/** @file
+ This file provides macros and functions for compile-time and run-time
+ assertions.
+
+ When the OI_DEBUG preprocessor value is defined, the macro OI_ASSERT is
+ compiled into
+ the program, providing for a runtime assertion failure check.
+ C_ASSERT is a macro that can be used to perform compile time checks.
+*/
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** \addtogroup Debugging Debugging APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef OI_DEBUG
+
+/** The macro OI_ASSERT takes a condition argument. If the asserted condition
+ does not evaluate to true, the OI_ASSERT macro calls the host-dependent
+ function,
+ OI_AssertFail(), which reports the failure and generates a runtime error.
+*/
+void OI_AssertFail(char* file, int line, char* reason);
+
+#define OI_ASSERT(condition) \
+ { \
+ if (!(condition)) OI_AssertFail(__FILE__, __LINE__, #condition); \
+ }
+
+#define OI_ASSERT_FAIL(msg) \
+ { OI_AssertFail(__FILE__, __LINE__, msg); }
+
+#else
+
+#define OI_ASSERT(condition)
+#define OI_ASSERT_FAIL(msg)
+
+#endif
+
+/**
+ C_ASSERT() can be used to perform many compile-time assertions: type sizes,
+ field offsets, etc.
+ An assertion failure results in compile time error C2118: negative subscript.
+ Unfortunately, this elegant macro doesn't work with GCC, so it's all
+ commented out
+ for now. Perhaps later.....
+*/
+
+#ifndef C_ASSERT
+// #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+// #define C_ASSERT(e)
+#endif
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_ASSERT_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bitstream.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bitstream.h
new file mode 100755
index 0000000..1fb075e
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bitstream.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_BITSTREAM_H
+#define _OI_BITSTREAM_H
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+Function prototypes and macro definitions for manipulating input and output
+bitstreams.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_stddefs.h"
+
+INLINE void OI_BITSTREAM_ReadInit(OI_BITSTREAM* bs, const OI_BYTE* buffer);
+
+INLINE void OI_BITSTREAM_WriteInit(OI_BITSTREAM* bs, OI_BYTE* buffer);
+
+INLINE uint32_t OI_BITSTREAM_ReadUINT(OI_BITSTREAM* bs, OI_UINT bits);
+
+INLINE uint8_t OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM* bs);
+
+INLINE uint8_t OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM* bs);
+
+INLINE void OI_BITSTREAM_WriteUINT(OI_BITSTREAM* bs, uint16_t value,
+ OI_UINT bits);
+
+/*
+ * Use knowledge that the bitstream is aligned to optimize the write of a byte
+ */
+PRIVATE void OI_BITSTREAM_WriteUINT8Aligned(OI_BITSTREAM* bs, uint8_t datum);
+
+/*
+ * Use knowledge that the bitstream is aligned to optimize the writing of a
+ * pair of nibbles.
+ */
+PRIVATE void OI_BITSTREAM_Write2xUINT4Aligned(OI_BITSTREAM* bs, uint8_t datum1,
+ uint8_t datum2);
+
+/** Internally the bitstream looks ahead in the stream. When
+ * OI_SBC_ReadScalefactors() goes to temporarily break the abstraction, it will
+ * need to know where the "logical" pointer is in the stream.
+ */
+#define OI_BITSTREAM_GetWritePtr(bs) ((bs)->ptr.w - 3)
+#define OI_BITSTREAM_GetReadPtr(bs) ((bs)->ptr.r - 3)
+
+/** This is declared here as a macro because decoder.c breaks the bitsream
+ * encapsulation for efficiency reasons.
+ */
+#define OI_BITSTREAM_READUINT(result, bits, ptr, value, bitPtr) \
+ do { \
+ OI_ASSERT((bits) <= 16); \
+ OI_ASSERT((bitPtr) < 16); \
+ OI_ASSERT((bitPtr) >= 8); \
+ \
+ (result) = (value) << (bitPtr); \
+ (result) >>= 32 - (bits); \
+ \
+ (bitPtr) += (bits); \
+ while ((bitPtr) >= 16) { \
+ (value) = ((value) << 8) | *(ptr)++; \
+ (bitPtr) -= 8; \
+ } \
+ OI_ASSERT(((bits) == 0) || ((result) < (1u << (bits)))); \
+ } while (0)
+
+#define OI_BITSTREAM_WRITEUINT(ptr, value, bitPtr, datum, bits) \
+ do { \
+ (bitPtr) -= (bits); \
+ (value) |= (datum) << (bitPtr); \
+ \
+ while ((bitPtr) <= 16) { \
+ (bitPtr) += 8; \
+ *(ptr)++ = (uint8_t)((value) >> 24); \
+ (value) <<= 8; \
+ } \
+ } while (0)
+
+#define OI_BITSTREAM_WRITEFLUSH(ptr, value, bitPtr) \
+ do { \
+ while ((bitPtr) < 32) { \
+ (bitPtr) += 8; \
+ *(ptr)++ = (uint8_t)((value) >> 24); \
+ (value) <<= 8; \
+ } \
+ } while (0)
+
+/**
+@}
+*/
+
+#endif /* _OI_BITSTREAM_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bt_spec.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bt_spec.h
new file mode 100755
index 0000000..f9bb13e
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_bt_spec.h
@@ -0,0 +1,239 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_BT_SPEC_H
+#define _OI_BT_SPEC_H
+/**
+ * @file
+ *
+ * This file contains common definitions from the Bluetooth specification.
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_stddefs.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The maximum number of active slaves in a piconet. */
+#define OI_BT_MAX_ACTIVE_SLAVES 7
+
+/** the number of bytes in a Bluetooth device address (BD_ADDR) */
+#define OI_BD_ADDR_BYTE_SIZE 6
+
+/**
+ * 48-bit Bluetooth device address
+ *
+ * Because 48-bit integers may not be supported on all platforms, the
+ * address is defined as an array of bytes. This array is big-endian,
+ * meaning that
+ * - array[0] contains bits 47-40,
+ * - array[1] contains bits 39-32,
+ * - array[2] contains bits 31-24,
+ * - array[3] contains bits 23-16,
+ * - array[4] contains bits 15-8, and
+ * - array[5] contains bits 7-0.
+ */
+typedef struct {
+ /* Bluetooth device address represented as an array of 8-bit values */
+ uint8_t addr[OI_BD_ADDR_BYTE_SIZE];
+} OI_BD_ADDR;
+
+/**
+ * @name Data types for working with UUIDs
+ * UUIDs are 16 bytes (128 bits).
+ *
+ * To avoid having to pass around 128-bit values all the time, 32-bit and 16-bit
+ * UUIDs are defined, along with a mapping from the shorter versions to the full
+ * version.
+ *
+ * @{
+ */
+
+/**
+ * 16-bit representation of a 128-bit UUID
+ */
+typedef uint16_t OI_UUID16;
+
+/**
+ * 32-bit representation of a 128-bit UUID
+ */
+typedef uint32_t OI_UUID32;
+
+/**
+ * number of bytes in a 128 bit UUID
+ */
+#define OI_BT_UUID128_SIZE 16
+
+/**
+ * number of bytes in IPv6 style addresses
+ */
+#define OI_BT_IPV6ADDR_SIZE 16
+
+/**
+ * type definition for a 128-bit UUID
+ *
+ * To simplify conversion between 128-bit UUIDs and 16-bit and 32-bit UUIDs,
+ * the most significant 32 bits are stored with the same endian-ness as is
+ * native on the target (local) device. The remainder of the 128-bit UUID is
+ * stored as bytes in big-endian order.
+ */
+typedef struct {
+ /* most significant 32 bits of 128-bit UUID */
+ uint32_t ms32bits;
+ /* remainder of 128-bit UUID, array of 8-bit values */
+ uint8_t base[OI_BT_UUID128_SIZE - sizeof(uint32_t)];
+} OI_UUID128;
+
+/** @} */
+
+/** number of bytes in a link key */
+#define OI_BT_LINK_KEY_SIZE 16
+
+/**
+ * type definition for a baseband link key
+ *
+ * Because 128-bit integers may not be supported on all platforms, we define
+ * link keys as an array of bytes. Unlike the Bluetooth device address,
+ * the link key is stored in little-endian order, meaning that
+ * - array[0] contains bits 0 - 7,
+ * - array[1] contains bits 8 - 15,
+ * - array[2] contains bits 16 - 23,
+ * - array[3] contains bits 24 - 31,
+ * - array[4] contains bits 32 - 39,
+ * - array[5] contains bits 40 - 47,
+ * - array[6] contains bits 48 - 55,
+ * - array[7] contains bits 56 - 63,
+ * - array[8] contains bits 64 - 71,
+ * - array[9] contains bits 72 - 79,
+ * - array[10] contains bits 80 - 87,
+ * - array[11] contains bits 88 - 95,
+ * - array[12] contains bits 96 - 103,
+ * - array[13] contains bits 104- 111,
+ * - array[14] contains bits 112- 119, and
+ * - array[15] contains bits 120- 127.
+ */
+typedef struct {
+ /* link key represented as an array of 8-bit values */
+ uint8_t key[OI_BT_LINK_KEY_SIZE];
+} OI_LINK_KEY;
+
+/** Out-of-band data size - C and R values are 16-bytes each */
+#define OI_BT_OOB_NUM_BYTES 16
+
+typedef struct {
+ /* same struct used for C and R values */
+ uint8_t value[OI_BT_OOB_NUM_BYTES];
+} OI_OOB_DATA;
+
+/**
+ * link key types
+ */
+typedef enum {
+ OI_LINK_KEY_TYPE_COMBO = 0, /* combination key */
+ OI_LINK_KEY_TYPE_LOCAL_UNIT = 1, /* local unit key */
+ OI_LINK_KEY_TYPE_REMOTE_UNIT = 2, /* remote unit key */
+ OI_LINK_KEY_TYPE_DEBUG_COMBO = 3, /* debug combination key */
+ OI_LINK_KEY_TYPE_UNAUTHENTICATED = 4, /* Unauthenticated */
+ OI_LINK_KEY_TYPE_AUTHENTICATED = 5, /* Authenticated */
+ OI_LINK_KEY_TYPE_CHANGED_COMBO = 6 /* Changed */
+
+} OI_BT_LINK_KEY_TYPE;
+
+/* Number of bytes allocated for a PIN (personal indentification number) */
+#define OI_BT_PIN_CODE_SIZE 16
+
+/* data type for a PIN (PINs are treated as strings.) */
+typedef struct {
+ /* PIN represented as an array of 8-bit values */
+ uint8_t pin[OI_BT_PIN_CODE_SIZE];
+} OI_PIN_CODE;
+
+/* maximum number of SCO connections per device: 3 as of version 2.0+EDR
+ of the Bluetooth specification (see sec 4.3 of vol 2 part B) */
+#define OI_BT_MAX_SCO_CONNECTIONS 3
+
+/** data type for clock offset */
+typedef uint16_t OI_BT_CLOCK_OFFSET;
+
+/** data type for a LM handle */
+typedef uint16_t OI_HCI_LM_HANDLE;
+
+/** opaque data type for a SCO or ACL connection handle */
+typedef struct _OI_HCI_CONNECTION* OI_HCI_CONNECTION_HANDLE;
+
+/** data type for HCI Error Code, as defined in oi_hcispec.h */
+typedef uint8_t OI_HCI_ERROR_CODE;
+
+/**
+ * The Bluetooth device type is indicated by a 24-bit bitfield, represented as a
+ * 32-bit number in the stack. The bit layout and values for device class are
+ * specified in the file oi_bt_assigned_nos.h and in the Bluetooth "Assigned
+ * Numbers" specification at http://www.bluetooth.org/assigned-numbers/.
+ */
+typedef uint32_t OI_BT_DEVICE_CLASS;
+/* Bits 0-1 contain format type. */
+#define OI_BT_DEV_CLASS_FORMAT_MASK 0x000003
+/* Bits 2-7 contain minor device class value. */
+#define OI_BT_DEV_CLASS_MINOR_DEVICE_MASK 0x0000FC
+/* Bits 8-12 contain major device class value. */
+#define OI_BT_DEV_CLASS_MAJOR_DEVICE_MASK 0x001F00
+/* Bits 13-23 contain major service class value. */
+#define OI_BT_DEV_CLASS_MAJOR_SERVICE_MASK 0xFFE000
+
+/** There is currently only one device class format defined, type 00. */
+#define OI_BT_DEV_CLASS_FORMAT_TYPE 00
+
+/* Bit 13 in device class indicates limited discoverability mode (GAP v2.0+EDR,
+ * section 4.1.2.2)
+ */
+#define OI_BT_DEV_CLASS_LIMITED_DISCO_BIT BIT13
+
+/** macro to test validity of the Device Class Format */
+#define OI_BT_VALID_DEVICE_CLASS_FORMAT(class) \
+ (OI_BT_DEV_CLASS_FORMAT_TYPE == ((class) & OI_BT_DEV_CLASS_FORMAT_MASK))
+
+/* the time between baseband clock ticks, currently 625 microseconds (one slot)
+ */
+#define OI_BT_TICK 625
+/* some macros to convert to/from baseband clock ticks - no floating point! */
+#define OI_SECONDS_TO_BT_TICKS(secs) ((secs)*1600)
+#define OI_BT_TICKS_TO_SECONDS(ticks) ((ticks) / 1600)
+#define OI_MSECS_TO_BT_TICKS(msecs) (((msecs)*8) / 5)
+#define OI_BT_TICKS_TO_MSECS(ticks) (((ticks)*5) / 8)
+
+/** EIR byte order */
+#define OI_EIR_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/*****************************************************************************/
+#endif /* _OI_BT_SPEC_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h
new file mode 100755
index 0000000..61fe510
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc.h
@@ -0,0 +1,515 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#ifndef _OI_CODEC_SBC_CORE_H
+#define _OI_CODEC_SBC_CORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+@file
+Declarations of codec functions, data types, and macros.
+
+@ingroup codec_lib
+*/
+
+/**
+@addtogroup codec_lib
+@{
+*/
+
+/* Non-BM3 users of of the codec must include oi_codec_sbc_bm3defs.h prior to
+ * including this file, or else these includes will fail because the BM3 SDK is
+ * not in the include path */
+#ifndef _OI_CODEC_SBC_BM3DEFS_H
+#include "oi_status.h"
+#include "oi_stddefs.h"
+#endif
+
+#include <stdint.h>
+
+#define SBC_MAX_CHANNELS 2
+#define SBC_MAX_BANDS 8
+#define SBC_MAX_BLOCKS 16
+/* Minimum size of the bit allocation pool used to encode the stream */
+#define SBC_MIN_BITPOOL 2
+/* Maximum size of the bit allocation pool used to encode the stream */
+#define SBC_MAX_BITPOOL 250
+#define SBC_MAX_ONE_CHANNEL_BPS 320000
+#define SBC_MAX_TWO_CHANNEL_BPS 512000
+
+#define SBC_WBS_BITRATE 62000
+#define SBC_WBS_BITPOOL 27
+#define SBC_WBS_NROF_BLOCKS 16
+#define SBC_WBS_FRAME_LEN 62
+#define SBC_WBS_SAMPLES_PER_FRAME 128
+
+#define SBC_HEADER_LEN 4
+#define SBC_MAX_FRAME_LEN \
+ (SBC_HEADER_LEN + \
+ ((SBC_MAX_BANDS * SBC_MAX_CHANNELS / 2) + \
+ (SBC_MAX_BANDS + SBC_MAX_BLOCKS * SBC_MAX_BITPOOL + 7) / 8))
+#define SBC_MAX_SAMPLES_PER_FRAME (SBC_MAX_BANDS * SBC_MAX_BLOCKS)
+
+#define SBC_MAX_SCALEFACTOR_BYTES \
+ ((4 * (SBC_MAX_CHANNELS * SBC_MAX_BANDS) + 7) / 8)
+
+#define OI_SBC_SYNCWORD 0x9c
+#define OI_SBC_ENHANCED_SYNCWORD 0x9d
+
+/**@name Sampling frequencies */
+/**@{*/
+/**< The sampling frequency is 16 kHz. One possible value for the @a frequency
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_16000 0
+/**< The sampling frequency is 32 kHz. One possible value for the @a frequency
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_32000 1
+/**< The sampling frequency is 44.1 kHz. One possible value for the @a frequency
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_44100 2
+/**< The sampling frequency is 48 kHz. One possible value for the @a frequency
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_FREQ_48000 3
+/**@}*/
+
+/**@name Channel modes */
+/**@{*/
+/**< The mode of the encoded channel is mono. One possible value for the @a mode
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_MONO 0
+/**< The mode of the encoded channel is dual-channel. One possible value for the
+ * @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_DUAL_CHANNEL 1
+/**< The mode of the encoded channel is stereo. One possible value for the @a
+ * mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_STEREO 2
+/**< The mode of the encoded channel is joint stereo. One possible value for the
+ * @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_JOINT_STEREO 3
+/**@}*/
+
+/**@name Subbands */
+/**@{*/
+/**< The encoded stream has 4 subbands. One possible value for the @a subbands
+ * parameter of OI_CODEC_SBC_EncoderConfigure()*/
+#define SBC_SUBBANDS_4 0
+/**< The encoded stream has 8 subbands. One possible value for the @a subbands
+ * parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_SUBBANDS_8 1
+/**@}*/
+
+/**@name Block lengths */
+/**@{*/
+/**< A block size of 4 blocks was used to encode the stream. One possible value
+ * for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_4 0
+/**< A block size of 8 blocks was used to encode the stream is. One possible
+ * value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_8 1
+/**< A block size of 12 blocks was used to encode the stream. One possible value
+ * for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_12 2
+/**< A block size of 16 blocks was used to encode the stream. One possible value
+ * for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_BLOCKS_16 3
+/**@}*/
+
+/**@name Bit allocation methods */
+/**@{*/
+/**< The bit allocation method. One possible value for the @a loudness parameter
+ * of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_LOUDNESS 0
+/**< The bit allocation method. One possible value for the @a loudness parameter
+ * of OI_CODEC_SBC_EncoderConfigure() */
+#define SBC_SNR 1
+/**@}*/
+
+/**
+@}
+
+@addtogroup codec_internal
+@{
+*/
+
+typedef int16_t SBC_BUFFER_T;
+
+/** Used internally. */
+typedef struct {
+ uint16_t frequency; /**< The sampling frequency. Input parameter. */
+ uint8_t freqIndex;
+
+ uint8_t nrof_blocks; /**< The block size used to encode the stream. Input
+ parameter. */
+ uint8_t blocks;
+
+ uint8_t nrof_subbands; /**< The number of subbands of the encoded stream.
+ Input parameter. */
+ uint8_t subbands;
+
+ uint8_t mode; /**< The mode of the encoded channel. Input parameter. */
+ uint8_t nrof_channels; /**< The number of channels of the encoded stream. */
+
+ uint8_t alloc; /**< The bit allocation method. Input parameter. */
+ uint8_t bitpool; /**< Size of the bit allocation pool used to encode the
+ stream. Input parameter. */
+ uint8_t crc; /**< Parity check byte used for error detection. */
+ uint8_t join; /**< Whether joint stereo has been used. */
+ uint8_t enhanced;
+ uint8_t min_bitpool; /**< This value is only used when encoding.
+ SBC_MAX_BITPOOL if variable
+ bitpools are disallowed, otherwise the minimum
+ bitpool size that will
+ be used by the bit allocator. */
+
+ uint8_t cachedInfo; /**< Information about the previous frame */
+} OI_CODEC_SBC_FRAME_INFO;
+
+/** Used internally. */
+typedef struct {
+ const OI_CHAR* codecInfo;
+ OI_CODEC_SBC_FRAME_INFO frameInfo;
+ int8_t scale_factor[SBC_MAX_CHANNELS * SBC_MAX_BANDS];
+ uint32_t frameCount;
+ int32_t* subdata;
+
+ SBC_BUFFER_T* filterBuffer[SBC_MAX_CHANNELS];
+ int32_t filterBufferLen;
+ OI_UINT filterBufferOffset;
+
+ union {
+ uint8_t uint8[SBC_MAX_CHANNELS * SBC_MAX_BANDS];
+ uint32_t uint32[SBC_MAX_CHANNELS * SBC_MAX_BANDS / 4];
+ } bits;
+ uint8_t maxBitneed; /**< Running maximum bitneed */
+ OI_BYTE formatByte;
+ uint8_t pcmStride;
+ uint8_t maxChannels;
+} OI_CODEC_SBC_COMMON_CONTEXT;
+
+/*
+ * A smaller value reduces RAM usage at the expense of increased CPU usage.
+ * Values in the range 27..50 are recommended. Beyond 50 there is a diminishing
+ * return on reduced CPU usage.
+ */
+#define SBC_CODEC_MIN_FILTER_BUFFERS 16
+#define SBC_CODEC_FAST_FILTER_BUFFERS 27
+
+/* Expands to the number of uint32_ts needed to ensure enough memory to encode
+ * or decode streams of numChannels channels, using numBuffers buffers.
+ * Example:
+ * uint32_t decoderData[CODEC_DATA_WORDS(SBC_MAX_CHANNELS,
+ * SBC_DECODER_FAST_SYNTHESIS_BUFFERS)];
+ * */
+#define CODEC_DATA_WORDS(numChannels, numBuffers) \
+ (((sizeof(int32_t) * SBC_MAX_BLOCKS * (numChannels)*SBC_MAX_BANDS) + \
+ (sizeof(SBC_BUFFER_T) * SBC_MAX_CHANNELS * SBC_MAX_BANDS * (numBuffers)) + \
+ (sizeof(uint32_t) - 1)) / \
+ sizeof(uint32_t))
+
+/** Opaque parameter to decoding functions; maintains decoder context. */
+typedef struct {
+ OI_CODEC_SBC_COMMON_CONTEXT common;
+ /* Boolean, set by OI_CODEC_SBC_DecoderLimit() */
+ uint8_t limitFrameFormat;
+ uint8_t restrictSubbands;
+ uint8_t enhancedEnabled;
+ uint8_t bufferedBlocks;
+} OI_CODEC_SBC_DECODER_CONTEXT;
+
+typedef struct {
+ uint32_t data[CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS)];
+} OI_CODEC_SBC_CODEC_DATA_MONO;
+
+typedef struct {
+ uint32_t data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
+} OI_CODEC_SBC_CODEC_DATA_STEREO;
+
+/**
+@}
+
+@addtogroup codec_lib
+@{
+*/
+
+/**
+ * This function resets the decoder. The context must be reset when
+ * changing streams, or if the following stream parameters change:
+ * number of subbands, stereo mode, or frequency.
+ *
+ * @param context Pointer to the decoder context structure to be reset.
+ *
+ * @param enhanced If true, enhanced SBC operation is enabled. If enabled,
+ * the codec will recognize the alternative syncword for
+ * decoding an enhanced SBC stream. Enhancements should not
+ * be enabled unless the stream is known to be generated
+ * by an enhanced encoder, or there is a small possibility
+ * for decoding glitches if synchronization were to be lost.
+ */
+OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint32_t* decoderData,
+ uint32_t decoderDataBytes,
+ uint8_t maxChannels, uint8_t pcmStride,
+ OI_BOOL enhanced);
+
+/**
+ * This function restricts the kind of SBC frames that the Decoder will
+ * process. Its use is optional. If used, it must be called after
+ * calling OI_CODEC_SBC_DecoderReset(). After it is called, any calls
+ * to OI_CODEC_SBC_DecodeFrame() with SBC frames that do not conform
+ * to the Subband and Enhanced SBC setting will be rejected with an
+ * OI_STATUS_INVALID_PARAMETERS return.
+ *
+ * @param context Pointer to the decoder context structure to be limited.
+ *
+ * @param enhanced If true, all frames passed to the decoder must be
+ * Enhanced SBC frames. If false, all frames must be
+ * standard SBC frames.
+ *
+ * @param subbands May be set to SBC_SUBBANDS_4 or SBC_SUBBANDS_8. All
+ * frames passed to the decoder must be encoded with
+ * the requested number of subbands.
+ *
+ */
+OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BOOL enhanced, uint8_t subbands);
+
+/**
+ * This function sets the decoder parameters for a raw decode where the decoder
+ * parameters are not available in the sbc data stream.
+ * OI_CODEC_SBC_DecoderReset must be called prior to calling this function.
+ *
+ * @param context Decoder context structure. This must be the context
+ * must be used each time a frame is decoded.
+ *
+ * @param enhanced Set to true to enable Qualcomm proprietary
+ * quality enhancements.
+ *
+ * @param frequency One of SBC_FREQ_16000, SBC_FREQ_32000, SBC_FREQ_44100,
+ * SBC_FREQ_48000
+ *
+ * @param mode One of SBC_MONO, SBC_DUAL_CHANNEL, SBC_STEREO,
+ * SBC_JOINT_STEREO
+ *
+ * @param subbands One of SBC_SUBBANDS_4, SBC_SUBBANDS_8
+ *
+ * @param blocks One of SBC_BLOCKS_4, SBC_BLOCKS_8, SBC_BLOCKS_12,
+ * SBC_BLOCKS_16
+ *
+ * @param alloc One of SBC_LOUDNESS, SBC_SNR
+ *
+ * @param maxBitpool The maximum bitpool size for this context
+ */
+OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(
+ OI_CODEC_SBC_DECODER_CONTEXT* context, OI_BOOL enhanced, uint8_t frequency,
+ uint8_t mode, uint8_t subbands, uint8_t blocks, uint8_t alloc,
+ uint8_t maxBitpool);
+
+/**
+ * Decode one SBC frame. The frame has no header bytes. The context must have
+ * been previously initialized by calling OI_CODEC_SBC_DecoderConfigureRaw().
+ *
+ * @param context Pointer to a decoder context structure. The same context
+ * must be used each time when decoding from the same
+ * stream.
+ *
+ * @param bitpool The actual bitpool size for this frame. Must be <= the
+ * maxbitpool specified in the call to
+ * OI_CODEC_SBC_DecoderConfigureRaw().
+ *
+ * @param frameData Address of a pointer to the SBC data to decode. This
+ * value will be updated to point to the next frame after
+ * successful decoding.
+ *
+ * @param frameBytes Pointer to a uint32_t containing the number of available
+ * bytes of frame data. This value will be updated to
+ * reflect the number of bytes remaining after a decoding
+ * operation.
+ *
+ * @param pcmData Address of an array of int16_t pairs, which will be
+ * populated with the decoded audio data. This address
+ * is not updated.
+ *
+ * @param pcmBytes Pointer to a uint32_t in/out parameter. On input, it
+ * should contain the number of bytes available for pcm
+ * data. On output, it will contain the number of bytes
+ * written. Note that this differs from the semantics of
+ * frameBytes.
+ */
+OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint8_t bitpool, const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes);
+
+/**
+ * Decode one SBC frame.
+ *
+ * @param context Pointer to a decoder context structure. The same context
+ * must be used each time when decoding from the same
+ * stream.
+ *
+ * @param frameData Address of a pointer to the SBC data to decode. This
+ * value will be updated to point to the next frame after
+ * successful decoding.
+ *
+ * @param frameBytes Pointer to a uint32_t containing the number of available
+ * bytes of frame data. This value will be updated to
+ * reflect the number of bytes remaining after a decoding
+ * operation.
+ *
+ * @param pcmData Address of an array of int16_t pairs, which will be
+ * populated with the decoded audio data. This address
+ * is not updated.
+ *
+ * @param pcmBytes Pointer to a uint32_t in/out parameter. On input, it
+ * should contain the number of bytes available for pcm
+ * data. On output, it will contain the number of bytes
+ * written. Note that this differs from the semantics of
+ * frameBytes.
+ */
+OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes);
+
+/**
+ * Calculate the number of SBC frames but don't decode. CRC's are not checked,
+ * but the Sync word is found prior to count calculation.
+ *
+ * @param frameData Pointer to the SBC data.
+ *
+ * @param frameBytes Number of bytes avaiable in the frameData buffer
+ *
+ */
+uint8_t OI_CODEC_SBC_FrameCount(OI_BYTE* frameData, uint32_t frameBytes);
+
+/**
+ * Analyze an SBC frame but don't do the decode.
+ *
+ * @param context Pointer to a decoder context structure. The same context
+ * must be used each time when decoding from the same
+ * stream.
+ *
+ * @param frameData Address of a pointer to the SBC data to decode. This
+ * value will be updated to point to the next frame after
+ * successful decoding.
+ *
+ * @param frameBytes Pointer to a uint32_t containing the number of available
+ * bytes of frame data. This value will be updated to
+ * reflect the number of bytes remaining after a decoding
+ * operation.
+ *
+ */
+OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE** frameData,
+ uint32_t* frameBytes);
+
+/* Common functions */
+
+/**
+ Calculate the frame length.
+
+ @param frame The frame whose length to calculate
+
+ @return the length of an individual encoded frame in
+ bytes
+ */
+uint16_t OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO* frame);
+
+/**
+ * Calculate the maximum bitpool size that fits within a given frame length.
+ *
+ * @param frame The frame to calculate the bitpool size for
+ * @param frameLen The frame length to fit the bitpool to
+ *
+ * @return the maximum bitpool that will fit in the specified frame length
+ */
+uint16_t OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO* frame,
+ uint16_t frameLen);
+
+/**
+ Calculate the bit rate.
+
+ @param frame The frame whose bit rate to calculate
+
+ @return the approximate bit rate in bits per second,
+ assuming that stream parameters are constant
+ */
+uint32_t OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO* frame);
+
+/**
+ Calculate decoded audio data length for one frame.
+
+ @param frame The frame whose audio data length to calculate
+
+ @return length of decoded audio data for a
+ single frame, in bytes
+ */
+uint16_t OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT* common);
+
+/**
+ * Get the codec version text.
+ *
+ * @return pointer to text string containing codec version text
+ *
+ */
+OI_CHAR* OI_CODEC_Version(void);
+
+/**
+@}
+
+@addtogroup codec_internal
+@{
+*/
+
+extern const OI_CHAR* const OI_CODEC_SBC_FreqText[];
+extern const OI_CHAR* const OI_CODEC_SBC_ModeText[];
+extern const OI_CHAR* const OI_CODEC_SBC_SubbandsText[];
+extern const OI_CHAR* const OI_CODEC_SBC_BlocksText[];
+extern const OI_CHAR* const OI_CODEC_SBC_AllocText[];
+
+/**
+@}
+
+@addtogroup codec_lib
+@{
+*/
+
+#ifdef OI_DEBUG
+void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO* frameInfo);
+#else
+#define OI_CODEC_SBC_DumpConfig(f)
+#endif
+
+/**
+@}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OI_CODEC_SBC_CORE_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
new file mode 100755
index 0000000..91d80f1
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_codec_sbc_private.h
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_CODEC_SBC_PRIVATE_H
+#define _OI_CODEC_SBC_PRIVATE_H
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+Function prototypes and macro definitions used internally by the codec.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#ifdef USE_RESTRICT_KEYWORD
+#define RESTRICT restrict
+#else
+#define RESTRICT
+#endif
+
+#ifdef CODEC_DEBUG
+#include <stdio.h>
+#define ERROR(x) \
+ do { \
+ printf x; \
+ printf("\n"); \
+ } while (0)
+#else
+#define ERROR(x)
+#endif
+
+#ifdef TRACE_EXECUTION
+#define TRACE(x) \
+ do { \
+ printf x; \
+ printf("\n"); \
+ } while (0)
+#else
+#define TRACE(x)
+#endif
+
+#ifndef PRIVATE
+#define PRIVATE
+#endif
+
+#ifndef INLINE
+#define INLINE
+#endif
+
+#include "oi_assert.h"
+#include "oi_codec_sbc.h"
+
+#ifndef OI_SBC_SYNCWORD
+#define OI_SBC_SYNCWORD 0x9c
+#endif
+
+#ifndef DIVIDE
+#define DIVIDE(a, b) ((a) / (b))
+#endif
+
+typedef union {
+ uint8_t uint8[SBC_MAX_BANDS];
+ uint32_t uint32[SBC_MAX_BANDS / 4];
+} BITNEED_UNION1;
+
+typedef union {
+ uint8_t uint8[2 * SBC_MAX_BANDS];
+ uint32_t uint32[2 * SBC_MAX_BANDS / 4];
+} BITNEED_UNION2;
+
+static const uint16_t freq_values[] = {16000, 32000, 44100, 48000};
+static const uint8_t block_values[] = {4, 8, 12, 16};
+static const uint8_t channel_values[] = {1, 2, 2, 2};
+static const uint8_t band_values[] = {4, 8};
+
+#define TEST_MODE_SENTINEL "OINA"
+#define TEST_MODE_SENTINEL_LENGTH 4
+
+/** Used internally. */
+typedef struct {
+ union {
+ const uint8_t* r;
+ uint8_t* w;
+ } ptr;
+ uint32_t value;
+ OI_UINT bitPtr;
+} OI_BITSTREAM;
+
+#define VALID_INT16(x) (((x) >= OI_INT16_MIN) && ((x) <= OI_INT16_MAX))
+#define VALID_INT32(x) (((x) >= OI_INT32_MIN) && ((x) <= OI_INT32_MAX))
+
+#define DCTII_8_SHIFT_IN 0
+#define DCTII_8_SHIFT_OUT (16 - DCTII_8_SHIFT_IN)
+
+#define DCTII_8_SHIFT_0 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_1 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_2 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_3 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_4 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_5 (DCTII_8_SHIFT_OUT)
+#define DCTII_8_SHIFT_6 (DCTII_8_SHIFT_OUT - 1)
+#define DCTII_8_SHIFT_7 (DCTII_8_SHIFT_OUT - 2)
+
+#define DCT_SHIFT 15
+
+#define DCTIII_4_SHIFT_IN 2
+#define DCTIII_4_SHIFT_OUT 15
+
+#define DCTIII_8_SHIFT_IN 3
+#define DCTIII_8_SHIFT_OUT 14
+
+OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT* common, uint8_t* bitneeds,
+ OI_UINT ch, OI_UINT* preferredBitpool);
+
+void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ BITNEED_UNION1* bitneeds, OI_UINT ch,
+ OI_UINT bitcount);
+
+OI_INT adjustToFitBitpool(const OI_UINT bitpool, uint32_t* bitneeds,
+ const OI_UINT subbands, OI_UINT bitcount,
+ OI_UINT* excess);
+
+INLINE OI_INT allocAdjustedBits(uint8_t* dest, OI_INT bits, OI_INT excess);
+
+INLINE OI_INT allocExcessBits(uint8_t* dest, OI_INT excess);
+
+PRIVATE uint32_t internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO* frame);
+
+PRIVATE uint16_t internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO* frame);
+
+void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common);
+
+typedef void (*BIT_ALLOC)(OI_CODEC_SBC_COMMON_CONTEXT* common);
+
+PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint8_t bitpool, const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes);
+
+INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint32_t* decoderData,
+ uint32_t decoderDataBytes,
+ OI_BYTE maxChannels, OI_BYTE pcmStride,
+ OI_BOOL enhanced);
+
+INLINE uint16_t OI_SBC_CalculateFrameAndHeaderlen(
+ OI_CODEC_SBC_FRAME_INFO* frame, OI_UINT* headerLen_);
+
+PRIVATE uint32_t OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO* frame);
+
+PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* frame);
+PRIVATE uint8_t OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO* frame,
+ OI_BYTE const* data);
+
+/* Transform functions */
+PRIVATE void shift_buffer(SBC_BUFFER_T* dest, SBC_BUFFER_T* src,
+ OI_UINT wordCount);
+PRIVATE void cosineModulateSynth4(SBC_BUFFER_T* RESTRICT out,
+ int32_t const* RESTRICT in);
+PRIVATE void SynthWindow40_int32_int32_symmetry_with_sum(
+ int16_t* pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift);
+
+INLINE void dct3_4(int32_t* RESTRICT out, int32_t const* RESTRICT in);
+PRIVATE void analyze4_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 40],
+ int16_t* pcm, OI_UINT strideShift,
+ int32_t subband[4]);
+
+INLINE void dct3_8(int32_t* RESTRICT out, int32_t const* RESTRICT in);
+
+PRIVATE void analyze8_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 80],
+ int16_t* pcm, OI_UINT strideShift,
+ int32_t subband[8]);
+
+#ifdef SBC_ENHANCED
+PRIVATE void analyze8_enhanced_generated(
+ SBC_BUFFER_T analysisBuffer[RESTRICT 112], int16_t* pcm,
+ OI_UINT strideShift, int32_t subband[8]);
+#endif
+
+/* Decoder functions */
+
+INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ const OI_BYTE* data);
+PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ const OI_BYTE* b, OI_BITSTREAM* bs);
+PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT* common,
+ OI_BITSTREAM* ob);
+PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT* common,
+ OI_BITSTREAM* global_bs);
+PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ int16_t* pcm, OI_UINT start_block,
+ OI_UINT nrof_blocks);
+INLINE int32_t OI_SBC_Dequant(uint32_t raw, OI_UINT scale_factor, OI_UINT bits);
+PRIVATE OI_BOOL OI_SBC_ExamineCommandPacket(
+ OI_CODEC_SBC_DECODER_CONTEXT* context, const OI_BYTE* data, uint32_t len);
+PRIVATE void OI_SBC_GenerateTestSignal(int16_t pcmData[][2],
+ uint32_t sampleCount);
+
+PRIVATE void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO* frame);
+PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ uint32_t* codecDataAligned,
+ uint32_t codecDataBytes,
+ uint8_t maxChannels, uint8_t pcmStride);
+/**
+@}
+*/
+
+#endif /* _OI_CODEC_SBC_PRIVATE_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_common.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_common.h
new file mode 100755
index 0000000..a4cf20b
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_common.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_COMMON_H
+#define _OI_COMMON_H
+/**
+ * @file
+ *
+ * This file is used to group commonly used BLUEmagic 3.0 software
+ * header files.
+ *
+ * This file should be included in application source code along with the header
+ * files for the specific modules of the protocol stack being used.
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_bt_spec.h"
+#include "oi_osinterface.h"
+#include "oi_status.h"
+#include "oi_stddefs.h"
+#include "oi_time.h"
+
+/*****************************************************************************/
+#endif /* _OI_COMMON_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h
new file mode 100755
index 0000000..21faf5e
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_cpu_dep.h
@@ -0,0 +1,288 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_CPU_DEP_H
+#define _OI_CPU_DEP_H
+
+#include <stdint.h>
+
+/**
+ * @file
+ * This file contains definitions for characteristics of the target CPU and
+ * compiler, including primitive data types and endianness.
+ *
+ * This file defines the byte order and primitive data types for various
+ * CPU families. The preprocessor symbol 'CPU' must be defined to be an
+ * appropriate value or this header will generate a compile-time error.
+ *
+ * @note The documentation for this header file uses the x86 family of
+ * processors as an illustrative example for CPU/compiler-dependent data type
+ * definitions. Go to the source code of this header file to see the details of
+ * primitive type definitions for each platform.
+ *
+ * Additional information is available in the @ref data_types_docpage section.
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+/** @name Definitions indicating family of target OI_CPU_TYPE
+ * @{
+ */
+
+#define OI_CPU_X86 1 /**< x86 processor family */
+#define OI_CPU_ARM \
+ 2 /**< ARM processor family. \
+ @deprecated Use #OI_CPU_ARM7_LEND or \
+ #OI_CPU_ARM7_BEND. */
+#define OI_CPU_ARC \
+ 3 /**< ARC processor family. \
+ @deprecated Use #OI_CPU_ARC_LEND or \
+ #OI_CPU_ARC_BEND. */
+#define OI_CPU_SH3 4 /**< Hitachi SH-3 processor family */
+#define OI_CPU_H8 5 /**< Hitachi H8 processor family */
+#define OI_CPU_MIPS 6 /**< MIPS processor family */
+#define OI_CPU_SPARC 7 /**< SPARC processor family */
+#define OI_CPU_M68000 8 /**< Motorola M68000 processor family */
+#define OI_CPU_PPC 9 /**< PowerPC (PPC) processor family */
+#define OI_CPU_SH4_7750 \
+ 10 /**< Hitachi SH7750 series in SH-4 processor family */
+#define OI_CPU_SH2 11 /**< Hitachi SH-2 processor family */
+#define OI_CPU_ARM7_LEND 12 /**< ARM7, little-endian */
+#define OI_CPU_ARM7_BEND 13 /**< ARM7, big-endian */
+#define OI_CPU_GDM1202 14 /**< GCT GDM1202 */
+#define OI_CPU_ARC_LEND 15 /**< ARC processor family, little-endian */
+#define OI_CPU_ARC_BEND 16 /**< ARC processor family, big-endian */
+#define OI_CPU_M30833F 17 /**< Mitsubishi M308 processor family */
+#define OI_CPU_CR16C 18 /**< National Semiconductor 16 bit processor family */
+#define OI_CPU_M64111 19 /**< Renesas M64111 processor (M32R family) */
+#define OI_CPU_ARMV5_LEND 20 //*< ARM5, little-endian */
+
+#define OI_CPU_TYPE 12
+
+#ifndef OI_CPU_TYPE
+#error "OI_CPU_TYPE type not defined"
+#endif
+
+/**@}*/
+
+/** @name Definitions indicating byte-wise endianness of target CPU
+ * @{
+ */
+
+#define OI_BIG_ENDIAN_BYTE_ORDER \
+ 0 /**< Multiple-byte values are stored in memory beginning with the most \
+ significant byte at the lowest address. */
+#define OI_LITTLE_ENDIAN_BYTE_ORDER \
+ 1 /**< Multiple-byte values are stored in memory beginning with the least \
+ significant byte at the lowest address. */
+
+/**@}*/
+
+/** @name CPU/compiler-independent primitive data type definitions
+ * @{
+ */
+
+typedef int
+ OI_BOOL; /**< Boolean values use native integer data type for target CPU. */
+typedef int
+ OI_INT; /**< Integer values use native integer data type for target CPU. */
+typedef unsigned int OI_UINT; /**< Unsigned integer values use native unsigned
+ integer data type for target CPU. */
+typedef unsigned char OI_BYTE; /**< Raw bytes type uses native character data
+ type for target CPU. */
+typedef uint32_t OI_ELEMENT_UNION; /**< Type for first element of a union to
+ support all data types up to pointer
+ width. */
+
+/**@}*/
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_X86
+
+#define OI_CPU_BYTE_ORDER \
+ OI_LITTLE_ENDIAN_BYTE_ORDER /**< x86 platform byte ordering is little-endian \
+ */
+
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARM
+/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARM7_LEND
+ * or OI_CPU_ARM7_BEND for little-endian or big-endian configurations of the
+ * ARM7, respectively. */
+#error OI_CPU_ARM is deprecated
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARC
+/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARC_LEND
+ * or OI_CPU_ARC_BEND for little-endian or big-endian configurations of the
+ * ARC, respectively. */
+#error OI_CPU_ARC is deprecated
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_SH3
+/* The Hitachi SH C compiler defines _LIT or _BIG, depending on the endianness
+ specified to the compiler on the command line. */
+#if defined(_LIT)
+#define OI_CPU_BYTE_ORDER \
+ OI_LITTLE_ENDIAN_BYTE_ORDER /**< If _LIT is defined, SH-3 platform byte \
+ ordering is little-endian. */
+#elif defined(_BIG)
+#define OI_CPU_BYTE_ORDER \
+ OI_BIG_ENDIAN_BYTE_ORDER /**< If _BIG is defined, SH-3 platform byte \
+ ordering is big-endian. */
+#else
+#error SH compiler endianness undefined
+#endif
+
+#endif
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_SH2
+
+#define OI_CPU_BYTE_ORDER \
+ OI_BIG_ENDIAN_BYTE_ORDER /**< SH-2 platform byte ordering is big-endian. */
+
+#endif
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_H8
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#error basic types not defined
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_MIPS
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_SPARC
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#error basic types not defined
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_M68000
+#define OI_CPU_BYTE_ORDER \
+ OI_BIG_ENDIAN_BYTE_ORDER /**< M68000 platform byte ordering is big-endian. \
+ */
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_PPC
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_SH4_7750
+#define OI_CPU_BYTE_ORDER \
+ OI_BIG_ENDIAN_BYTE_ORDER /**< SH7750 platform byte ordering is big-endian. \
+ */
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARM7_LEND
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARM7_BEND
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_GDM1202
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARC_LEND
+
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARC_BEND
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_M30833F
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_CR16C
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_M64111
+#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#if OI_CPU_TYPE == OI_CPU_ARMV5_LEND
+#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+
+/******************************************************************************/
+
+#ifndef OI_CPU_BYTE_ORDER
+#error "Byte order (endian-ness) not defined"
+#endif
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+/******************************************************************************/
+#endif /* _OI_CPU_DEP_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_modules.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_modules.h
new file mode 100755
index 0000000..3c20285
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_modules.h
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_MODULES_H
+#define _OI_MODULES_H
+/**
+ * @file
+ *
+ * Enumeration type defining the inidivual stack components.
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This enumeration lists constants for referencing the components of
+ * the BLUEmagic 3.0 protocol stack, profiles, and other functionalities.
+ *
+ * In order to distinguish types of modules, items are grouped with markers to
+ * delineate start and end of the groups
+ *
+ * The module type is used for various purposes:
+ * identification in debug print statements
+ * access to initialization flags
+ * access to the configuration table
+ */
+
+typedef enum {
+ /* profiles and protocols --> Updates to oi_debug.c and oi_config_table.c */
+
+ /* XX --> Keep Enum values up-to-date! */
+ OI_MODULE_AT, /**< 00 AT command processing */
+ OI_MODULE_A2DP, /**< 01 Advanced Audio Distribution Profile */
+ OI_MODULE_AVCTP, /**< 02 Audio-Visual Control Transport Profile */
+ OI_MODULE_AVDTP, /**< 03 Audio-Visual Distribution Protocol */
+ OI_MODULE_AVRCP, /**< 04 Audio-Visual Remote Control Profile */
+ OI_MODULE_BIP_CLI, /**< 05 Basic Imaging Profile protocol client */
+ OI_MODULE_BIP_SRV, /**< 06 Basic Imaging Profile protocol server */
+ OI_MODULE_BNEP, /**< 07 Bluetooth Network Encapsulation Protocol */
+ OI_MODULE_BPP_SENDER, /**< 08 Basic Printing Profile */
+ OI_MODULE_BPP_PRINTER, /**< 09 Basic Printing Profile */
+ OI_MODULE_CTP, /**< 10 Cordless Telephony Profile */
+ OI_MODULE_DUN, /**< 11 Dial-Up Networking Profile */
+ OI_MODULE_FAX, /**< 12 Fax Profile */
+ OI_MODULE_FTP_CLI, /**< 13 File Transfer Profile protocol client */
+ OI_MODULE_FTP_SRV, /**< 14 File Transfer Profile protocol server */
+ OI_MODULE_HANDSFREE, /**< 15 Hands-Free Profile */
+ OI_MODULE_HANDSFREE_AG, /**< 16 Hands-Free Profile */
+ OI_MODULE_HCRP_CLI, /**< 17 Hardcopy Cable Replacement Profile */
+ OI_MODULE_HCRP_SRV, /**< 18 Hardcopy Cable Replacement Profile */
+ OI_MODULE_HEADSET, /**< 19 Headset Profile */
+ OI_MODULE_HEADSET_AG, /**< 20 Headset Profile */
+ OI_MODULE_HID, /**< 21 Human Interface Device profile */
+ OI_MODULE_INTERCOM, /**< 22 Intercom Profile */
+ OI_MODULE_OBEX_CLI, /**< 23 OBEX protocol client, Generic Object Exchange
+ Profile */
+ OI_MODULE_OBEX_SRV, /**< 24 OBEX protocol server, Generic Object Exchange
+ Profile */
+ OI_MODULE_OPP_CLI, /**< 25 Object Push Profile protocol client */
+ OI_MODULE_OPP_SRV, /**< 26 Object Push Profile protocol server */
+ OI_MODULE_PAN, /**< 27 PAN profile */
+ OI_MODULE_PBAP_CLI, /**< 28 Phonebook Access Profile client */
+ OI_MODULE_PBAP_SRV, /**< 29 Phonebook Access Profile server */
+ OI_MODULE_SAP_CLI, /**< 30 SIM Access Profile */
+ OI_MODULE_SAP_SRV, /**< 31 SIM Access Profile */
+ OI_MODULE_SPP, /**< 32 Serial Port Profile */
+ OI_MODULE_SYNC_CLI, /**< 33 Synchronization Profile */
+ OI_MODULE_SYNC_SRV, /**< 34 Synchronization Profile */
+ OI_MODULE_SYNC_CMD_CLI, /**< 35 Synchronization Profile */
+ OI_MODULE_SYNC_CMD_SRV, /**< 36 Synchronization Profile */
+ OI_MODULE_SYNCML, /**< 37 SyncML Profile */
+ OI_MODULE_TCS, /**< 38 TCS Binary */
+ OI_MODULE_VDP, /**< 39 Video Distribution Profile */
+
+ /* corestack components --> Updates to oi_debug.c and oi_config_table.c */
+
+ OI_MODULE_COMMON_CONFIG, /**< 40 Common configuration, module has no meaning
+ other than for config struct */
+ OI_MODULE_CMDCHAIN, /**< 41 Command chaining utility */
+ OI_MODULE_DISPATCH, /**< 42 Dispatcher */
+ OI_MODULE_DATAELEM, /**< 43 Data Elements, marshaller */
+ OI_MODULE_DEVMGR, /**< 44 Device Manager */
+ OI_MODULE_DEVMGR_MODES, /**< 45 Device Manager connectability/discoverability
+ modes */
+ OI_MODULE_HCI, /**< 46 Host Controller Interface command layer */
+ OI_MODULE_L2CAP, /**< 47 L2CAP */
+ OI_MODULE_MEMMGR, /**< 48 modules that do memory management */
+ OI_MODULE_POLICYMGR, /**< 49 Policy Manager */
+ OI_MODULE_RFCOMM, /**< 50 RFCOMM */
+ OI_MODULE_RFCOMM_SD, /**< 51 RFCOMM Service discovery */
+ OI_MODULE_SDP_CLI, /**< 52 Service Discovery Protocol client */
+ OI_MODULE_SDP_SRV, /**< 53 Service Discovery Protocol server */
+ OI_MODULE_SDPDB, /**< 54 Service Discovery Protocol database */
+ OI_MODULE_SECMGR, /**< 55 Security Manager */
+ OI_MODULE_SNIFFLOG, /**< 56 sniff log */
+ OI_MODULE_SUPPORT, /**< 57 support functions, including CThru Dispatcher, time
+ functions, and stack initialization */
+ OI_MODULE_TRANSPORT, /**< 58 transport layer between HCI command layer and
+ driver */
+ OI_MODULE_TEST, /**< 59 used to debug output from internal test programs */
+ OI_MODULE_XML, /**< 60 XML/CSS parser */
+
+ OI_MODULE_DI, /**< 61 Device Identification Profile */
+
+ // bhapi components --> Updates to oi_debug.c
+
+ OI_MODULE_BHAPI, /**< 62 BLUEmagic Host API generic */
+ OI_MODULE_BHCLI, /**< 63 BLUEmagic Host API client side */
+ OI_MODULE_BHSRV, /**< 64 BLUEmagic Host API server side */
+ OI_MODULE_MSGQ, /**< 65 module that handles message queuing */
+ OI_MODULE_BHAPI_TRANSPORT, /**< 66 module that handles message queuing */
+ OI_MODULE_BLST_SRV, /**< 67 module that provides server side BHAPI Lightweight
+ Serial Transport */
+ OI_MODULE_BLST_CLI, /**< 68 module that provides client side BHAPI Lightweight
+ Serial Transport */
+
+ // OEM files --> Updates to oi_debug.c
+ OI_MODULE_OEM, /**< 69 Application Memory allocation */
+
+ // Application glue --> Updates to oi_debug.c
+ OI_MODULE_APP, /**< 70 Application Memory allocation */
+
+ /* various pieces of code depend on these last 2 elements occuring in a
+ specific order:
+ OI_MODULE_ALL must be the 2nd to last element
+ OI_MODULE_UNKNOWN must be the last element
+ */
+ OI_MODULE_ALL, /**< 71 special value identifying all modules - used for
+ control of debug print statements */
+ OI_MODULE_UNKNOWN /**< 72 special value - used for debug print statements */
+} OI_MODULE;
+
+/**
+ * This constant is the number of actual modules in the list. ALL and UNKNOWN
+ * are special values that are not actually modules.
+ * Used for debug print and memmgr profiling
+ */
+#define OI_NUM_MODULES OI_MODULE_ALL
+
+/**
+ * This constant is the number of profile and core components. It is used to
+ * size the initialization and configuration tables.
+ */
+#define OI_NUM_STACK_MODULES OI_MODULE_BHAPI
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_MODULES_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_osinterface.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_osinterface.h
new file mode 100755
index 0000000..c0a3ff1
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_osinterface.h
@@ -0,0 +1,198 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_OSINTERFACE_H
+#define _OI_OSINTERFACE_H
+/**
+ @file
+ * This file provides the platform-independent interface for functions for which
+ * implementation is platform-specific.
+ *
+ * The functions in this header file define the operating system or hardware
+ * services needed by the BLUEmagic 3.0 protocol stack. The
+ * actual implementation of these services is platform-dependent.
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_modules.h"
+#include "oi_status.h"
+#include "oi_stddefs.h"
+#include "oi_time.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Terminates execution.
+ *
+ * @param reason Reason for termination
+ */
+void OI_FatalError(OI_STATUS reason);
+
+/**
+ * This function logs an error.
+ *
+ * When built for release mode, BLUEmagic 3 errors are logged to
+ * this function. (in debug mode, errors are logged via
+ * OI_Print()).
+ *
+ * @param module Module in which the error was detected (see
+ * oi_modules.h)
+ * @param lineno Line number of the C file OI_SLOG_ERROR called
+ * @param status Status code associated with the error event
+ */
+void OI_LogError(OI_MODULE module, OI_INT lineno, OI_STATUS status);
+
+/**
+ * This function initializes the debug code handling.
+ *
+ * When built for debug mode, this function performs platform
+ * dependent initialization to handle message codes passed in
+ * via OI_SetMsgCode().
+ */
+void OI_InitDebugCodeHandler(void);
+
+/**
+ * This function reads the time from the real time clock.
+ *
+ * All timing in BM3 is relative, typically a granularity
+ * of 5 or 10 msecs is adequate.
+ *
+ * @param[out] now Pointer to the buffer to which the current
+ * time will be returned
+ */
+void OI_Time_Now(OI_TIME* now);
+
+/**
+ * This function causes the current thread to sleep for the
+ * specified amount of time. This function must be called
+ * without the stack access token.
+ *
+ * @note BM3 corestack and profiles never suspend and never call
+ * OI_Sleep. The use of OI_Sleep is limited to applications and
+ * platform-specific code.
+ *
+ * If your port and applications never use OI_Sleep, this function can be left
+ * unimplemented.
+ *
+ * @param milliseconds Number of milliseconds to sleep
+ */
+void OI_Sleep(uint32_t milliseconds);
+
+/**
+ * Defines for message type codes.
+ */
+#define OI_MSG_CODE_APPLICATION 0 /**< Application output */
+#define OI_MSG_CODE_ERROR 1 /**< Error message output */
+#define OI_MSG_CODE_WARNING 2 /**< Warning message output */
+#define OI_MSG_CODE_TRACE 3 /**< User API function trace output */
+#define OI_MSG_CODE_PRINT1 4 /**< Catagory 1 debug print output */
+#define OI_MSG_CODE_PRINT2 5 /**< Catagory 2 debug print output */
+#define OI_MSG_CODE_HEADER 6 /**< Error/Debug output header */
+
+/**
+ * This function is used to indicate the type of text being output with
+ * OI_Print(). For the Linux and Win32 platforms, it will set
+ * the color of the text. Other possible uses could be to insert
+ * HTML style tags, add some other message type indication, or
+ * be completely ignored altogether.
+ *
+ * @param code OI_MSG_CODE_* indicating setting the message type.
+ */
+void OI_SetMsgCode(uint8_t code);
+
+/**
+ * All output from OI_Printf() and all debug output is sent to OI_Print.
+ * Typically, if the platform has a console, OI_Print() is sent to stdout.
+ * Embedded platforms typically send OI_Print() output to a serial port.
+ *
+ * @param str String to print
+ */
+void OI_Print(OI_CHAR const* str);
+
+/**
+ * In cases where OI_Print() is sending output to a logfile in addition to
+ * console, it is desirable to also put console input into the logfile.
+ * This function can be called by the console input process.
+ *
+ * @note This is an optional API which is strictly
+ * between the platform-specific stack_console and osinterface
+ * modules. This API need only be implemented on those
+ * platforms where is serves a useful purpose, e.g., win32.
+ *
+ * @param str Console input string
+ */
+
+void OI_Print_ConsoleInput(OI_CHAR const* str);
+
+/**
+ * This function computes the CRC16 of the program image.
+ */
+uint16_t OI_ProgramImageCRC16(void);
+
+/**
+ * Writes an integer to stdout in hex. This macro is intended
+ * for selective use when debugging in small memory
+ * configurations or other times when it is not possible to use
+ * OI_DBGPRINT.
+ *
+ * @param n the integer to print
+ */
+
+#define OI_Print_Int(n) \
+ { \
+ static const OI_CHAR _digits[] = "0123456789ABCDEF"; \
+ OI_CHAR _buf[9]; \
+ OI_CHAR* _str = &_buf[8]; \
+ uint32_t _i = n; \
+ *_str = 0; \
+ do { \
+ *(--_str) = _digits[(_i & 0xF)]; \
+ _i >>= 4; \
+ } while (_i); \
+ OI_Print(_str); \
+ }
+
+/**
+ * Application Dynamic Memory allocation.
+ *
+ * These APIs are provided for application use on those
+ * platforms which have no dynamic memory support. Memory is
+ * allocated from the pool-based heap managed by the stack's
+ * internal memory manager.
+ */
+void* OI_APP_Malloc(int32_t size);
+void OI_APP_Free(void* ptr);
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_OSINTERFACE_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_status.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_status.h
new file mode 100755
index 0000000..13a5815
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_status.h
@@ -0,0 +1,873 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_STATUS_H
+#define _OI_STATUS_H
+/**
+ * @file
+ * This file contains status codes for BLUEmagic 3.0 software.
+ */
+
+#include "oi_stddefs.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** test it **/
+
+/**
+ * OI_STATUS is 16 bits, so status codes can range from 0 to 66535, inclusive.
+ */
+
+typedef enum {
+ OI_STATUS_SUCCESS = 0, /**< function call succeeded alias for #OI_OK */
+ OI_OK = 0, /**< function call succeeded alias for #OI_STATUS_SUCCESS */
+ OI_STATUS_INVALID_PARAMETERS = 101, /**< invalid function input parameters */
+ OI_STATUS_NOT_IMPLEMENTED =
+ 102, /**< attempt to use an unimplemented function */
+ OI_STATUS_NOT_INITIALIZED = 103, /**< data not initialized */
+ OI_STATUS_NO_RESOURCES =
+ 104, /**< generic resource allocation failure status */
+ OI_STATUS_INTERNAL_ERROR = 105, /**< internal inconsistency */
+ OI_STATUS_OUT_OF_MEMORY = 106, /**< generally, OI_Malloc failed */
+ OI_ILLEGAL_REENTRANT_CALL =
+ 107, /**< violation of non-reentrant module policy */
+ OI_STATUS_INITIALIZATION_FAILED = 108, /**< module initialization failed */
+ OI_STATUS_INITIALIZATION_PENDING =
+ 109, /**< inititialization not yet complete */
+ OI_STATUS_NO_SCO_SUPPORT =
+ 110, /**< SCO operation rejected; system not configured for SCO */
+ OI_STATUS_OUT_OF_STATIC_MEMORY = 111, /**< static malloc failed */
+ OI_TIMEOUT = 112, /**< generic timeout */
+ OI_OS_ERROR = 113, /**< some operating system error */
+ OI_FAIL = 114, /**< generic failure */
+ OI_STRING_FORMAT_ERROR = 115, /**< error in VarString formatting string */
+ OI_STATUS_PENDING = 116, /**< The operation is pending. */
+ OI_STATUS_INVALID_COMMAND = 117, /**< The command was invalid. */
+ OI_BUSY_FAIL = 118, /**< command rejected due to busy */
+ OI_STATUS_ALREADY_REGISTERED =
+ 119, /**< The registration has already been performed. */
+ OI_STATUS_NOT_FOUND = 120, /**< The referenced resource was not found. */
+ OI_STATUS_NOT_REGISTERED = 121, /**< not registered */
+ OI_STATUS_NOT_CONNECTED = 122, /**< not connected */
+ OI_CALLBACK_FUNCTION_REQUIRED =
+ 123, /**< A callback function parameter was required. */
+ OI_STATUS_MBUF_OVERFLOW =
+ 124, /**< There is no room to add another buffer to an mbuf. */
+ OI_STATUS_MBUF_UNDERFLOW =
+ 125, /**< There was an attempt to pull too many bytes from an mbuf. */
+ OI_STATUS_CONNECTION_EXISTS = 126, /**< connection exists */
+ OI_STATUS_NOT_CONFIGURED = 127, /**< module not configured */
+ OI_LOWER_STACK_ERROR = 128, /**< An error was reported by lower stack API.
+ This is used for embedded platforms. */
+ OI_STATUS_RESET_IN_PROGRESS =
+ 129, /**< Request failed/rejected because we're busy resetting. */
+ OI_STATUS_ACCESS_DENIED = 130, /**< Generic access denied error. */
+ OI_STATUS_DATA_ERROR = 131, /**< Generic data error. */
+ OI_STATUS_INVALID_ROLE = 132, /**< The requested role was invalid. */
+ OI_STATUS_ALREADY_CONNECTED =
+ 133, /**< The requested connection is already established. */
+ OI_STATUS_PARSE_ERROR = 134, /**< Parse error */
+ OI_STATUS_END_OF_FILE = 135, /**< End of file */
+ OI_STATUS_READ_ERROR = 136, /**< Generic read error */
+ OI_STATUS_WRITE_ERROR = 137, /**< Generic write error */
+ OI_STATUS_NEGOTIATION_FAILURE = 138, /**< Error in negotiation */
+ OI_STATUS_READ_IN_PROGRESS = 139, /**< A read is already in progress */
+ OI_STATUS_ALREADY_INITIALIZED =
+ 140, /**< Initialization has already been done */
+ OI_STATUS_STILL_CONNECTED = 141, /**< The service cannot be shutdown because
+ there are still active connections. */
+ OI_STATUS_MTU_EXCEEDED = 142, /**< The packet is too big */
+ OI_STATUS_LINK_TERMINATED = 143, /**< The link was terminated */
+ OI_STATUS_PIN_CODE_TOO_LONG =
+ 144, /**< Application gave us a pin code that is too long */
+ OI_STATUS_STILL_REGISTERED =
+ 145, /**< The service cannot be shutdown because there are still active
+ registrations. */
+ OI_STATUS_SPEC_VIOLATION =
+ 146, /**< Some application behavior contrary to BT specifications */
+
+ OI_STATUS_PSM_ALREADY_REGISTERED =
+ 402, /**< L2CAP: The specified PSM has already been registered. */
+ OI_STATUS_INVALID_CID = 403, /**< L2CAP: CID is invalid or no longer valid
+ (connection terminated) */
+ OI_STATUS_CID_NOT_FOUND =
+ 404, /**< L2CAP: CID does not represent a current connection */
+ OI_STATUS_CHANNEL_NOT_FOUND =
+ 406, /**< L2CAP: CID does not represent a current connection */
+ OI_STATUS_PSM_NOT_FOUND = 407, /**< L2CAP: PSM not found */
+ OI_STATUS_INVALID_STATE = 408, /**< L2CAP: invalid state */
+ OI_STATUS_WRITE_IN_PROGRESS = 410, /**< L2CAP: write in progress */
+ OI_STATUS_INVALID_PACKET = 411, /**< L2CAP: invalid packet */
+ OI_STATUS_SEND_COMPLETE = 412, /**< L2CAP: send is complete */
+ OI_STATUS_INVALID_HANDLE = 414, /**< L2CAP: handle is invalid */
+ OI_STATUS_GROUP_FULL =
+ 418, /**< L2CAP: No more members can be added to the specified group. */
+ OI_STATUS_DEVICE_ALREADY_IN_GROUP =
+ 423, /**< L2CAP: The device already exists in the group. */
+ OI_STATUS_DUPLICATE_GROUP =
+ 425, /**< L2CAP: attempt to add more than one group */
+ OI_STATUS_EMPTY_GROUP = 426, /**< L2CAP: group is empty */
+ OI_STATUS_PACKET_NOT_FOUND = 427, /**< L2CAP: packet not found */
+ OI_STATUS_BUFFER_TOO_SMALL = 428, /**< L2CAP: The buffer size is too small. */
+ OI_STATUS_IDENTIFIER_NOT_FOUND = 429, /**< L2CAP: identifier not found */
+
+ OI_L2CAP_DISCONNECT_LOWER_LAYER =
+ 430, /**< L2CAP: The lower level forced a disconnect. */
+ OI_L2CAP_DISCONNECT_REMOTE_REQUEST =
+ 431, /**< L2CAP: The remote device requested a disconnect. */
+ OI_L2CAP_GROUP_ADD_CONNECT_FAIL = 433, /**< L2CAP: Group add connect faiL */
+ OI_L2CAP_GROUP_REMOVE_FAILURE = 434, /**< L2CAP: Group remove failure */
+ OI_L2CAP_DATA_WRITE_ERROR_LINK_TERM =
+ 435, /**< L2CAP: Data write error LINK_TERM */
+ OI_L2CAP_DISCONNECT_LOCAL_REQUEST =
+ 436, /**< L2CAP: Disconnect local request */
+
+ OI_L2CAP_CONNECT_TIMEOUT = 437, /**< L2CAP: Connect timeout */
+ OI_L2CAP_DISCONNECT_TIMEOUT = 439, /**< L2CAP: Disconnect timeout */
+ OI_L2CAP_PING_TIMEOUT = 440, /**< L2CAP: Ping timeout */
+ OI_L2CAP_GET_INFO_TIMEOUT = 441, /**< L2CAP: Get info timeout */
+ OI_L2CAP_INVALID_ADDRESS = 444, /**< L2CAP: Invalid address */
+ OI_L2CAP_CMD_REJECT_RCVD =
+ 445, /**< L2CAP: remote sent us 'command reject' response */
+
+ OI_L2CAP_CONNECT_BASE = 450, /**< L2CAP: Connect base */
+ OI_L2CAP_CONNECT_PENDING = 451, /**< L2CAP: Connect pending */
+ OI_L2CAP_CONNECT_REFUSED_INVALID_PSM =
+ 452, /**< L2CAP: Connect refused invalid PSM */
+ OI_L2CAP_CONNECT_REFUSED_SECURITY =
+ 453, /**< L2CAP: Connect refused security */
+ OI_L2CAP_CONNECT_REFUSED_NO_RESOURCES =
+ 454, /**< L2CAP: Connect refused no resources */
+
+ OI_L2CAP_CONFIG_BASE = 460, /**< L2CAP: Config base */
+ OI_L2CAP_CONFIG_FAIL_INVALID_PARAMETERS =
+ 461, /**< L2CAP: Config fail invalid parameters */
+ OI_L2CAP_CONFIG_FAIL_NO_REASON = 462, /**< L2CAP: Config fail no reason */
+ OI_L2CAP_CONFIG_FAIL_UNKNOWN_OPTIONS =
+ 463, /**< L2CAP: Config fail unknown options */
+
+ OI_L2CAP_GET_INFO_BASE = 470, /**< L2CAP: Get info base */
+ OI_L2CAP_GET_INFO_NOT_SUPPORTED = 471, /**< L2CAP: Get info not supported */
+ OI_L2CAP_MTU_EXCEEDED =
+ 472, /**< L2CAP: The MTU of the channel was exceeded */
+ OI_L2CAP_INVALID_PSM = 482, /**< L2CAP: Invalid PSM */
+ OI_L2CAP_INVALID_MTU = 483, /**< L2CAP: Invalid MTU */
+ OI_L2CAP_INVALID_FLUSHTO = 484, /**< L2CAP: Invalid flush timeout */
+
+ OI_HCI_NO_SUCH_CONNECTION =
+ 601, /**< HCI: caller specified a non-existent connection handle */
+ OI_HCI_CB_LIST_FULL =
+ 603, /**< HCI: callback list is full, cannot attempt to send command */
+ OI_HCI_EVENT_UNDERRUN =
+ 605, /**< HCI: parsing event packet, premature end-of-parameters */
+ OI_HCI_UNKNOWN_EVENT_CODE =
+ 607, /**< HCI: event received - event code is unknown */
+ OI_HCI_BAD_EVENT_PARM_LEN =
+ 608, /**< HCI: event - parameter length is incorrect */
+ OI_HCI_CMD_QUEUE_FULL = 611, /**< HCI: command queue is full */
+ OI_HCI_SHORT_EVENT =
+ 612, /**< HCI: event received, missing event code and/or parm len */
+ OI_HCI_TRANSMIT_NOT_READY = 613, /**< HCI: ACL/SCO transmit request failed -
+ busy or no buffers available */
+ OI_HCI_ORPHAN_SENT_EVENT =
+ 614, /**< HCI: got spurious 'sent' event from transport layer */
+ OI_HCI_CMD_TABLE_ERROR =
+ 615, /**< HCI: inconsistency in the internal command table */
+ OI_HCI_UNKNOWN_CMD_ID = 616, /**< HCI: HciApi Command - unknown command id */
+ OI_HCI_UNEXPECTED_EVENT =
+ 619, /**< HCI: event received which only occurs in response to our cmd */
+ OI_HCI_EVENT_TABLE_ERROR =
+ 620, /**< HCI: inconsistency in the internal event table */
+ OI_HCI_EXPECTED_EVENT_TIMOUT =
+ 621, /**< HCI: timed out waiting for an expected event */
+ OI_HCI_NO_CMD_DESC_FOR_OPCODE = 622, /**< HCI: event opcode is not known */
+ OI_HCI_INVALID_OPCODE_ERROR = 623, /**< HCI: command opcode is invalid */
+ OI_HCI_FLOW_CONTROL_DISABLED = 624, /**< HCI: can not use host flow control
+ APIs if disabled in configuration */
+ OI_HCI_TX_COMPLETE =
+ 625, /**< HCI: packet delivery to Host Controler complete */
+ OI_HCI_TX_ERROR = 626, /**< HCI: failed to deliver packet to Host Controler */
+ OI_HCI_DEVICE_NOT_INITIALIZED = 627, /**< HCI: commands from upper layers
+ disallowed until device is up and
+ running */
+ OI_HCI_UNSUPPORTED_COMMAND =
+ 628, /**< HCI: command requested is not supported by local device */
+ OI_HCI_PASSTHROUGH_ERROR =
+ 629, /**< HCI: Error processing passthrough command */
+ OI_HCI_PASSTHROUGH_ALREADY_SET =
+ 630, /**< HCI: Passthrough mode already enabled */
+ OI_HCI_RESET_FAILURE = 631, /**< HCI: failed to reset the device/baseband */
+ OI_HCI_TRANSPORT_RESET = 632, /**< HCI: some operation failed because of a
+ reset in the transport */
+ OI_HCIERR_HCIIFC_INIT_FAILURE =
+ 633, /**< HCI: failed to initialize transport layer interface */
+
+ OI_HCIERR_FIRST_ERROR_VALUE = 701, /**< marker for first HCI protocol error */
+ OI_HCIERR_UNKNOWN_HCI_COMMAND = 701, /**< HCI: protocol error 0x01 */
+ OI_HCIERR_NO_CONNECTION = 702, /**< HCI: protocol error 0x02 */
+ OI_HCIERR_HARDWARE_FAILURE = 703, /**< HCI: protocol error 0x03 */
+ OI_HCIERR_PAGE_TIMEOUT = 704, /**< HCI: protocol error 0x04 */
+ OI_HCIERR_AUTHENTICATION_FAILURE = 705, /**< HCI: protocol error 0x05 */
+ OI_HCIERR_KEY_MISSING = 706, /**< HCI: protocol error 0x06 */
+ OI_HCIERR_MEMORY_FULL = 707, /**< HCI: protocol error 0x07 */
+ OI_HCIERR_CONNECTION_TIMEOUT = 708, /**< HCI: protocol error 0x08 */
+ OI_HCIERR_MAX_NUM_OF_CONNECTIONS = 709, /**< HCI: protocol error 0x09 */
+ OI_HCIERR_MAX_NUM_OF_SCO_CONNECTIONS = 710, /**< HCI: protocol error 0x0A */
+ OI_HCIERR_ACL_CONNECTION_ALREADY_EXISTS =
+ 711, /**< HCI: protocol error 0x0B */
+ OI_HCIERR_COMMAND_DISALLOWED = 712, /**< HCI: protocol error 0x0C */
+ OI_HCIERR_HOST_REJECTED_RESOURCES = 713, /**< HCI: protocol error 0x0D */
+ OI_HCIERR_HOST_REJECTED_SECURITY = 714, /**< HCI: protocol error 0x0E */
+ OI_HCIERR_HOST_REJECTED_PERSONAL_DEVICE =
+ 715, /**< HCI: protocol error 0x0F */
+ OI_HCIERR_HOST_TIMEOUT = 716, /**< HCI: protocol error 0x10 */
+ OI_HCIERR_UNSUPPORTED = 717, /**< HCI: protocol error 0x11 */
+ OI_HCIERR_INVALID_PARAMETERS = 718, /**< HCI: protocol error 0x12 */
+ OI_HCIERR_OTHER_END_USER_DISCONNECT = 719, /**< HCI: protocol error 0x13 */
+ OI_HCIERR_OTHER_END_LOW_RESOURCES = 720, /**< HCI: protocol error 0x14 */
+ OI_HCIERR_OTHER_END_POWERING_OFF = 721, /**< HCI: protocol error 0x15 */
+ OI_HCIERR_CONNECTION_TERMINATED_LOCALLY =
+ 722, /**< HCI: protocol error 0x16 */
+ OI_HCIERR_REPEATED_ATTEMPTS = 723, /**< HCI: protocol error 0x17 */
+ OI_HCIERR_PAIRING_NOT_ALLOWED = 724, /**< HCI: protocol error 0x18 */
+ OI_HCIERR_UNKNOWN_LMP_PDU = 725, /**< HCI: protocol error 0x19 */
+ OI_HCIERR_UNSUPPORTED_REMOTE_FEATURE = 726, /**< HCI: protocol error 0x1A */
+ OI_HCIERR_SCO_OFFSET_REJECTED = 727, /**< HCI: protocol error 0x1B */
+ OI_HCIERR_SCO_INTERVAL_REJECTED = 728, /**< HCI: protocol error 0x1C */
+ OI_HCIERR_SCO_AIR_MODE_REJECTED = 729, /**< HCI: protocol error 0x1D */
+ OI_HCIERR_INVALID_LMP_PARMS = 730, /**< HCI: protocol error 0x1E */
+ OI_HCIERR_UNSPECIFIED_ERROR = 731, /**< HCI: protocol error 0x1F */
+ OI_HCIERR_UNSUPPORTED_LMP_PARAMETERS = 732, /**< HCI: protocol error 0x20 */
+ OI_HCIERR_ROLE_CHANGE_NOT_ALLOWED = 733, /**< HCI: protocol error 0x21 */
+ OI_HCIERR_LMP_RESPONSE_TIMEOUT = 734, /**< HCI: protocol error 0x22 */
+ OI_HCIERR_LMP_ERROR_TRANS_COLLISION = 735, /**< HCI: protocol error 0x23 */
+ OI_HCIERR_LMP_PDU_NOT_ALLOWED = 736, /**< HCI: protocol error 0x24 */
+ OI_HCIERR_ENCRYPTION_MODE_NOT_ACCEPTABLE =
+ 737, /**< HCI: protocol error 0x25 */
+ OI_HCIERR_UNIT_KEY_USED = 738, /**< HCI: protocol error 0x26 */
+ OI_HCIERR_QOS_NOT_SUPPORTED = 739, /**< HCI: protocol error 0x27 */
+ OI_HCIERR_INSTANT_PASSED = 740, /**< HCI: protocol error 0x28 */
+ OI_HCIERR_UNIT_KEY_PAIRING_UNSUPPORTED = 741, /**< HCI: protocol error 0x29 */
+ OI_HCIERR_DIFFERENT_TRANS_COLLISION = 742, /**< HCI: protocol error 0x2A */
+ OI_HCIERR_RESERVED_2B = 743, /**< HCI: protocol error 0x2B */
+ OI_HCIERR_QOS_UNACCEPTABLE_PARAMETER = 744, /**< HCI: protocol error 0x2C */
+ OI_HCIERR_QOS_REJECTED = 745, /**< HCI: protocol error 0x2D */
+ OI_HCIERR_CHANNEL_CLASSIFICATION_NS = 746, /**< HCI: protocol error 0x2E */
+ OI_HCIERR_INSUFFICIENT_SECURITY = 747, /**< HCI: protocol error 0x2F */
+ OI_HCIERR_PARM_OUT_OF_MANDATORY_RANGE = 748, /**< HCI: protocol error 0x30 */
+ OI_HCIERR_RESERVED_31 = 749, /**< HCI: protocol error 0x31 */
+ OI_HCIERR_ROLE_SWITCH_PENDING = 750, /**< HCI: protocol error 0x32 */
+ OI_HCIERR_RESERVED_33 = 751, /**< HCI: protocol error 0x33 */
+ OI_HCIERR_RESERVED_SLOT_VIOLATION = 752, /**< HCI: protocol error 0x34 */
+ OI_HCIERR_ROLE_SWITCH_FAILED = 753, /**< HCI: protocol error 0x35 */
+ OI_HCIERR_EIR_TOO_LARGE = 754, /**< HCI: protocol error 0x36 */
+ OI_HCIERR_SSP_NOT_SUPPORTED_BY_HOST = 755, /**< HCI: protocol error 0x37 */
+ OI_HCIERR_HOST_BUSY_PAIRING = 756, /**< HCI: protocol error 0x38 */
+
+ OI_HCIERR_UNKNOWN_ERROR = 757, /**< HCI: unknown error code */
+ OI_HCIERR_LAST_ERROR_VALUE = 757, /**< marker for last HCI protocol error */
+
+ OI_SDP_SPEC_ERROR = 800, /**< SDP: Base error status for mapping OI_STATUS
+ codes to SDP errors */
+ OI_SDP_INVALID_SERVICE_RECORD_HANDLE =
+ (OI_SDP_SPEC_ERROR +
+ 2), /**< SDP: protocol error Invalid Service Record Handle */
+ OI_SDP_INVALID_REQUEST_SYNTAX =
+ (OI_SDP_SPEC_ERROR +
+ 3), /**< SDP: protocol error Invalid Request Syntax */
+ OI_SDP_INVALID_PDU_SIZE =
+ (OI_SDP_SPEC_ERROR + 4), /**< SDP: protocol error Invalid PDU Size */
+ OI_SDP_INVALID_CONTINUATION_STATE =
+ (OI_SDP_SPEC_ERROR +
+ 5), /**< SDP: protocol error Invalid Continuation State */
+ OI_SDP_INSUFFICIENT_RESOURCES =
+ (OI_SDP_SPEC_ERROR +
+ 6), /**< SDP: protocol error Insufficient Resources */
+ OI_SDP_ERROR = 807, /**< SDP: server returned an error code */
+ OI_SDP_CORRUPT_DATA_ELEMENT =
+ 808, /**< SDP: Invalid or corrupt data element representation */
+ OI_SDP_SERVER_NOT_CONNECTED =
+ 810, /**< SDP: Attempt to disconnect from an unconnected server */
+ OI_SDP_ACCESS_DENIED = 811, /**< SDP: Server denied access to server */
+ OI_SDP_ATTRIBUTES_OUT_OF_ORDER =
+ 812, /**< SDP: Attributes in attribute list not in ascending order */
+ OI_SDP_DEVICE_DOES_NOT_SUPPORT_SDP =
+ 813, /**< SDP: Tried to connect to a device that does not support SDP */
+ OI_SDP_NO_MORE_DATA =
+ 815, /**< SDP: Server does not have more continuation data */
+ OI_SDP_REQUEST_PARAMS_TOO_LONG =
+ 816, /**< SDP: Parameters for a request exceed the L2CAP buffer size */
+ OI_SDP_REQUEST_PENDING = 817, /**< SDP: Cannot make a request when another
+ request is being processed */
+ OI_SDP_SERVER_CONNECT_FAILED =
+ 819, /**< SDP: Failed attempt to connect to an SDP server */
+ OI_SDP_SERVER_TOO_MANY_CONNECTIONS =
+ 821, /**< SDP: Exceeded maximum number of simultaneous server connections
+ */
+ OI_SDP_NO_MATCHING_SERVICE_RECORD =
+ 823, /**< SDP: No service record matched the UUID list */
+ OI_SDP_PARTIAL_RESPONSE = 824, /**< SDP: Internal use only */
+ OI_SDP_ILLEGAL_ARGUMENT =
+ 825, /**< SDP: Illegal argument passed to an SDP function */
+ OI_SDP_ATTRIBUTE_NOT_FOUND =
+ 826, /**< SDP: A requested attribute was not found in a service record */
+ OI_SDP_DATABASE_OUT_OF_RESOURCES =
+ 827, /**< SDP: server database is out of memory */
+ OI_SDP_SHORT_PDU = 829, /**< SDP: Not enough bytes in the packet */
+ OI_SDP_TRANSACTION_ID_MISMATCH =
+ 830, /**< SDP: Transaction Id was not as expected */
+ OI_SDP_UNEXPECTED_RESPONSE_PDU_ID =
+ 831, /**< SDP: Did not expect this response PDU */
+ OI_SDP_REQUEST_TIMEOUT =
+ 832, /**< SDP: Did not get a response within the timeout period */
+ OI_SDP_INVALID_RESPONSE_SYNTAX =
+ 833, /**< SDP: Response is not correctly formatted */
+ OI_SDP_CONNECTION_TIMEOUT =
+ 834, /**< SDP: Connection attempt timed out at a lower layer */
+ OI_SDP_RESPONSE_DATA_ERROR =
+ 835, /**< SDP: Response to a service request appears to be corrupt */
+ OI_SDP_TOO_MANY_ATTRIBUTE_BYTES =
+ 836, /**< SDP: Response contained more bytes than requested. */
+ OI_SDP_TOO_MANY_SERVICE_RECORDS =
+ 837, /**< SDP: Response contained more service records than requested. */
+ OI_SDP_INVALID_CONNECTION_ID =
+ 838, /**< SDP: Invalid connection ID in an SDP request */
+ OI_SDP_CANNOT_SET_ATTRIBUTE =
+ 839, /**< SDP: Attempt to set a dynamic attribute value failed */
+ OI_SDP_BADLY_FORMED_ATTRIBUTE_VALUE =
+ 840, /**< SDP: An attribute value has the wrong type or structure */
+ OI_SDP_NO_ATTRIBUTE_LIST_TO_REMOVE =
+ 841, /**< SDP: Attempt to remove a non-existent attribute list from a
+ service record */
+ OI_SDP_ATTRIBUTE_LIST_ALREADY_ADDED = 842, /**< SDP: An attribute list has
+ already been added to the
+ service record */
+ OI_SDP_DATA_ELEMENT_TRUNCATED =
+ 843, /**< SDP: Data element truncated (too few bytes) */
+
+ OI_RFCOMM_WRITE_IN_PROGRESS = 901, /**< RFCOMM: Write in progress */
+ OI_RFCOMM_INVALID_BAUDRATE = 903, /**< RFCOMM: Invalid baudrate */
+ OI_RFCOMM_INVALID_DATABIT = 904, /**< RFCOMM: Invalid databit */
+ OI_RFCOMM_INVALID_STOPBIT = 905, /**< RFCOMM: Invalid stopbit */
+ OI_RFCOMM_INVALID_PARITY = 906, /**< RFCOMM: Invalid parity */
+ OI_RFCOMM_INVALID_PARITYTYPE = 907, /**< RFCOMM: Invalid paritytype */
+ OI_RFCOMM_INVALID_FLOWCONTROL = 908, /**< RFCOMM: Invalid flowcontrol */
+ OI_RFCOMM_SESSION_EXISTS = 909, /**< RFCOMM: Session exists */
+ OI_RFCOMM_INVALID_CHANNEL = 910, /**< RFCOMM: Invalid channel */
+ OI_RFCOMM_DLCI_EXISTS = 911, /**< RFCOMM: DLCI exists */
+ OI_RFCOMM_LINK_NOT_FOUND = 912, /**< RFCOMM: Link not found */
+ OI_RFCOMM_REMOTE_REJECT = 913, /**< RFCOMM: Remote reject */
+ OI_RFCOMM_TEST_IN_PROGRESS = 915, /**< RFCOMM: Test in progress */
+ OI_RFCOMM_SESSION_NOT_FOUND = 916, /**< RFCOMM: Session not found */
+ OI_RFCOMM_INVALID_PACKET = 917, /**< RFCOMM: Invalid packet */
+ OI_RFCOMM_FRAMESIZE_EXCEEDED = 918, /**< RFCOMM: Framesize exceeded */
+ OI_RFCOMM_INVALID_DLCI = 920, /**< RFCOMM: Invalid dlci */
+ OI_RFCOMM_SERVER_NOT_REGISTERED = 921, /**< RFCOMM: Server not registered */
+ OI_RFCOMM_CREDIT_ERROR = 922, /**< RFCOMM: Credit error */
+ OI_RFCOMM_NO_CHANNEL_NUMBER = 923, /**< RFCOMM: No channel number */
+ OI_RFCOMM_QUERY_IN_PROGRESS = 924, /**< RFCOMM: Query in progress */
+ OI_RFCOMM_SESSION_SHUTDOWN = 925, /**< RFCOMM: Session shutdown */
+ OI_RFCOMM_LOCAL_DEVICE_DISCONNECTED =
+ 926, /**< RFCOMM: Local device disconnected */
+ OI_RFCOMM_REMOTE_DEVICE_DISCONNECTED =
+ 927, /**< RFCOMM: Remote device disconnected */
+ OI_RFCOMM_OUT_OF_SERVER_CHANNELS = 928, /**< RFCOMM: Out of server channels */
+
+ OI_DISPATCH_INVALID_CB_HANDLE =
+ 1001, /**< Dispatcher was handed an invalid callback handle */
+ OI_DISPATCH_TABLE_OVERFLOW = 1002, /**< Dispatcher table is full */
+
+ OI_TEST_UNKNOWN_TEST = 1101, /**< TEST: Unknown test */
+ OI_TEST_FAIL = 1102, /**< TEST: Fail */
+
+ OI_HCITRANS_CANNOT_CONNECT_TO_DEVICE =
+ 1201, /**< TRANSPORT: Cannot connect to device */
+ OI_HCITRANS_BUFFER_TOO_SMALL = 1203, /**< TRANSPORT: Buffer too small */
+ OI_HCITRANS_NULL_DEVICE_HANDLE = 1204, /**< TRANSPORT: Null device handle */
+ OI_HCITRANS_IO_ERROR = 1205, /**< TRANSPORT: IO error */
+ OI_HCITRANS_DEVICE_NOT_READY = 1206, /**< TRANSPORT: Device not ready */
+ OI_HCITRANS_FUNCTION_NOT_SUPPORTED =
+ 1207, /**< TRANSPORT: Function not supporteD */
+ OI_HCITRANS_ACCESS_DENIED = 1209, /**< TRANSPORT: win32 */
+ OI_HCITRANS_ACL_DATA_ERROR = 1210, /**< TRANSPORT: ACL data error */
+ OI_HCITRANS_SCO_DATA_ERROR = 1211, /**< TRANSPORT: SCO data error */
+ OI_HCITRANS_EVENT_DATA_ERROR = 1212, /**< TRANSPORT: HCI event data error */
+ OI_HCITRANS_INTERNAL_ERROR =
+ 1214, /**< TRANSPORT: Internal error in the transport */
+ OI_HCITRANS_LINK_NOT_ACTIVE =
+ 1215, /**< TRANSPORT: Link to the device is not currently active */
+ OI_HCITRANS_INITIALIZING = 1216, /**< TRANSPORT: Transport is initializing */
+
+ OI_DEVMGR_NO_CONNECTION = 1301, /**< DEVMGR: No connection */
+ OI_DEVMGR_HARDWARE_ERROR = 1305, /**< DEVMGR: error reported by HCI */
+ OI_DEVMGR_PENDING_CONNECT_LIST_FULL =
+ 1307, /**< DEVMGR: Pending connect list full */
+ OI_DEVMGR_CONNECTION_LIST_FULL = 1309, /**< DEVMGR: Connection list full */
+ OI_DEVMGR_NO_SUCH_CONNECTION = 1310, /**< DEVMGR: No such connection */
+ OI_DEVMGR_INQUIRY_IN_PROGRESS = 1311, /**< DEVMGR: Inquiry in progress */
+ OI_DEVMGR_PERIODIC_INQUIRY_ACTIVE =
+ 1312, /**< DEVMGR: Periodic inquiry active */
+ OI_DEVMGR_NO_INQUIRIES_ACTIVE =
+ 1313, /**< DEVMGR: can not cancel/exit if not active */
+ OI_DEVMGR_DUPLICATE_CONNECTION = 1314, /**< DEVMGR: internal error */
+ OI_DEVMGR_DUPLICATE_EVENT_CALLBACK =
+ 1316, /**< DEVMGR: attempt to register same callback twice */
+ OI_DEVMGR_EVENT_CALLBACK_LIST_FULL =
+ 1317, /**< DEVMGR: can not register event callback, list is full */
+ OI_DEVMGR_EVENT_CALLBACK_NOT_FOUND =
+ 1318, /**< DEVMGR: attempt to unregister callback failed */
+ OI_DEVMGR_BUSY =
+ 1319, /**< DEVMGR: some operations can only execute one at a time */
+ OI_DEVMGR_ENUM_UNEXPECTED_INQ_COMPLETE = 1320, /**< DEVMGR: inquiry complete
+ event in inappropriate
+ enumeration state */
+ OI_DEVMGR_ENUM_UNEXPECTED_INQ_RESULT = 1321, /**< DEVMGR: inquiry result event
+ in inappropriate enumeration
+ state */
+ OI_DEVMGR_ENUM_DATABASE_FULL =
+ 1322, /**< DEVMGR: device enumeration, database is full, couldn't add a
+ new device */
+ OI_DEVMGR_ENUM_INQUIRIES_OVERLAP = 1323, /**< DEVMGR: device enumeration,
+ periodic inquiries occurring too
+ close together */
+ OI_DEVMGR_UNKNOWN_LINK_TYPE =
+ 1324, /**< DEVMGR: HCI connect request with unkown link type */
+ OI_DEVMGR_PARAM_IO_ACTIVE = 1325, /**< DEVMGR: request for parameter
+ read/write while param read/write active
+ */
+ OI_DEVMGR_UNKNOWN_IAC_LAP = 1326, /**< DEVMGR: unrecognized IAC LAP */
+ OI_DEVMGR_SCO_ALREADY_REGISTERED =
+ 1327, /**< DEVMGR: only one application can use SCO */
+ OI_DEVMGR_SCO_NOT_REGISTERED =
+ 1328, /**< DEVMGR: SCO applications must register before using the API */
+ OI_DEVMGR_SCO_WITHOUT_ACL =
+ 1329, /**< DEVMGR: Got SCO connection but there is no underlying ACL
+ connection */
+ OI_DEVMGR_NO_SUPPORT =
+ 1330, /**< DEVMGR: Request is not supported by the device */
+ OI_DEVMGR_WRITE_POLICY_FAILED = 1331, /**< DEVMGR: connection attempt failed -
+ unable to write link policy */
+ OI_DEVMGR_NOT_IN_MASTER_MODE = 1332, /**< DEVMGR: OI_DEVMGR EndMasterMode
+ without prior
+ OI_DEVMGR_BeginMasterMode */
+ OI_DEVMGR_POLICY_VIOLATION =
+ 1333, /**< DEVMGR: low-power request is rejected - link policy does not
+ allow it */
+ OI_DEVMGR_BUSY_TIMEOUT = 1334, /**< DEVMGR: queued operation timed out while
+in the queue; \n
+timeout configurable via @ref OI_CONFIG_DEVMGR::connectQueueTimeoutSecs
+"connectQueueTimeoutSecs" */
+ OI_DEVMGR_REENCRYPT_FAILED =
+ 1335, /**< DEVMGR: failed to re-encrypt link after role switch */
+ OI_DEVMGR_ROLE_POLICY_CONFLICT =
+ 1336, /**< DEVMGR: requested role conflicts with current policy */
+ OI_DEVMGR_BAD_INTERVAL = 1337, /**< DEVMGR: current linkTO outside range of
+ requested min/max interval */
+ OI_DEVMGR_INVALID_SCO_HANDLE =
+ 1338, /**< DEVMGR: HCI SCO event, invalid handle */
+ OI_DEVMGR_CONNECTION_OVERLAP = 1339, /**< DEVMGR: Connection failed due to
+ race condition with remote side */
+ OI_DEVMGR_ORPHAN_SUBRATE_COMPLETE =
+ 1340, /**< DEVMGR: sniff subrate complete, but no callback */
+ OI_DEVMGR_EIR_RESPONSE_2_LARGE =
+ 1341, /**< DEVMGR: eir builder, response length would exceed spec max */
+
+ OI_SECMGR_NO_POLICY =
+ 1401, /**< SECMGR: no security policy has been established */
+ OI_SECMGR_INTERNAL_ERROR = 1402, /**< SECMGR: internal inconsistency */
+ OI_SECMGR_ORPHANED_CALLBACK =
+ 1403, /**< SECMGR: we've been called back, but CB context is gone */
+ OI_SECMGR_BUSY =
+ 1404, /**< SECMGR: configure and access request cannot be concurrent */
+ OI_SECMGR_DEVICE_NOT_TRUSTED =
+ 1405, /**< SECMGR: l2cap access denied - device is not trusted */
+ OI_SECMGR_DEVICE_ENCRYPT_FAIL =
+ 1407, /**< SECMGR: l2cap access denied - failed to start encryption */
+ OI_SECMGR_DISCONNECTED_FAIL =
+ 1408, /**< SECMGR: l2cap access denied - disconnected */
+ OI_SECMGR_ACCESS_PENDING =
+ 1409, /**< SECMGR: l2cap access request is still pending */
+ OI_SECMGR_PIN_CODE_TOO_SHORT =
+ 1410, /**< SECMGR: Higher-layer process gave us a pin code that is too
+ short */
+ OI_SECMGR_UNKNOWN_ENCRYPT_VALUE = 1411, /**< SECMGR: got EncryptionChange
+ event, unknown encryption enable
+ value */
+ OI_SECMGR_INVALID_POLICY = 1412, /**< SECMGR: the specified security policy is
+ not valid for security mode */
+ OI_SECMGR_AUTHORIZATION_FAILED =
+ 1413, /**< SECMGR: device authorization failed */
+ OI_SECMGR_ENCRYPTION_FAILED = 1414, /**< SECMGR: device encryption failed */
+ OI_SECMGR_UNIT_KEY_UNSUPPORTED =
+ 1415, /**< SECMGR: authentication failed due to non-support of unit keys
+ */
+ OI_SECMGR_NOT_REGISTERED =
+ 1416, /**< SECMGR: required registrations have not yet occurred */
+ OI_SECMGR_ILLEGAL_WRITE_SSP_MODE =
+ 1417, /**< SECMGR: 2.1 HCI spec does not allow SSP mode to be disabled */
+ OI_SECMGR_INVALID_SEC_LEVEL =
+ 1418, /**< SECMGR: security level for a service is not a valid value */
+ OI_SECMGR_INSUFFICIENT_LINK_KEY = 1419, /**< SECMGR: link key type is not
+ sufficient to meet service
+ requirements */
+ OI_SECMGR_INVALID_KEY_TYPE =
+ 1420, /**< SECMGR: link key type is not a valid value */
+ OI_SECMGR_SSP_NOT_ENCRYPTED =
+ 1421, /**< SECMGR: ssp required encryption on incoming link */
+ OI_SECMGR_ORPHAN_EVENT = 1422, /**< SECMGR: some HCI security event unrelated
+ to current processes */
+ OI_SECMGR_NOT_BONDABLE = 1423, /**< SECMGR: not in bondable mode */
+
+ OI_TCS_INVALID_ELEMENT_TYPE = 1602, /**< TCS: element type is invalid */
+ OI_TCS_INVALID_PACKET = 1603, /**< TCS: packet is invalide */
+ OI_TCS_CALL_IN_PROGRESS = 1604, /**< TCS: call is in progress */
+ OI_TCS_NO_CALL_IN_PROGRESS = 1605, /**< TCS: no call in progress */
+
+ OI_OBEX_CONTINUE = 1701, /**< OBEX: Continue processing OBEX request */
+ OI_OBEX_COMMAND_ERROR =
+ 1702, /**< OBEX: An unrecognized OBEX command opcode */
+ OI_OBEX_CONNECTION_TIMEOUT =
+ 1703, /**< OBEX: Timeout waiting for a response to a request */
+ OI_OBEX_CONNECT_FAILED =
+ 1704, /**< OBEX: An OBEX connection request did not succeed */
+ OI_OBEX_DISCONNECT_FAILED = 1705, /**< OBEX: A disconnect failed probably
+ because the connection did not exist */
+ OI_OBEX_ERROR = 1706, /**< OBEX: Unspecified OBEX error */
+ OI_OBEX_INCOMPLETE_PACKET = 1707, /**< OBEX: Packet too short or corrupt */
+ OI_OBEX_LENGTH_REQUIRED =
+ 1708, /**< OBEX: Length header required in OBEX command */
+ OI_OBEX_NOT_CONNECTED = 1709, /**< OBEX: No connection to OBEX server */
+ OI_OBEX_NO_MORE_CONNECTIONS =
+ 1710, /**< OBEX: Reached max connections limit */
+ OI_OBEX_OPERATION_IN_PROGRESS =
+ 1711, /**< OBEX: Another operation is still in progress on a connection */
+ OI_OBEX_PUT_RESPONSE_ERROR =
+ 1712, /**< OBEX: An error in the response to a PUT command */
+ OI_OBEX_GET_RESPONSE_ERROR =
+ 1713, /**< OBEX: An error in the response to a GET command */
+ OI_OBEX_REQUIRED_HEADER_NOT_FOUND =
+ 1714, /**< OBEX: packet was missing a required header */
+ OI_OBEX_SERVICE_UNAVAILABLE =
+ 1715, /**< OBEX: Unown OBEX target or required service */
+ OI_OBEX_TOO_MANY_HEADER_BYTES =
+ 1716, /**< OBEX: Headers will not fit in single OBEX packet */
+ OI_OBEX_UNKNOWN_COMMAND = 1717, /**< OBEX: Unrecognized OBEX command */
+ OI_OBEX_UNSUPPORTED_VERSION = 1718, /**< OBEX: Version mismatch */
+ OI_OBEX_CLIENT_ABORTED_COMMAND =
+ 1719, /**< OBEX: server received abort command */
+ OI_OBEX_BAD_PACKET = 1720, /**< OBEX: Any malformed OBEX packet */
+ OI_OBEX_BAD_REQUEST =
+ 1721, /**< OBEX: Maps to OBEX response of the same name */
+ OI_OBEX_OBJECT_OVERFLOW = 1723, /**< OBEX: Too many bytes received. */
+ OI_OBEX_NOT_FOUND = 1724, /**< OBEX: Maps to obex response of same name */
+ OI_OBEX_ACCESS_DENIED =
+ 1735, /**< OBEX: Object could not be read or written. */
+ OI_OBEX_VALUE_NOT_ACCEPTABLE =
+ 1736, /**< OBEX: Value in a command was not in the acceptable range. */
+ OI_OBEX_PACKET_OVERFLOW =
+ 1737, /**< OBEX: Buffer will not fit in a single OBEX packet. */
+ OI_OBEX_NO_SUCH_FOLDER =
+ 1738, /**< OBEX: Error returned by a setpath operation. */
+ OI_OBEX_NAME_REQUIRED =
+ 1739, /**< OBEX: Name must be non-null and non-empty. */
+ OI_OBEX_PASSWORD_TOO_LONG =
+ 1740, /**< OBEX: Password exceeds implementation imposed length limit. */
+ OI_OBEX_PRECONDITION_FAILED = 1741, /**< OBEX: response Precondition Failed */
+ OI_OBEX_UNAUTHORIZED = 1742, /**< OBEX: authentication was not successful. */
+ OI_OBEX_NOT_IMPLEMENTED = 1743, /**< OBEX: Unimplemented feature. */
+ OI_OBEX_INVALID_AUTH_DIGEST =
+ 1744, /**< OBEX: An authentication digest was bad. */
+ OI_OBEX_INVALID_OPERATION =
+ 1745, /**< OBEX: Operation not allowed at this time. */
+ OI_OBEX_DATABASE_FULL = 1746, /**< OBEX: Sync database full. */
+ OI_OBEX_DATABASE_LOCKED = 1747, /**< OBEX: Sync database locked. */
+ OI_OBEX_INTERNAL_SERVER_ERROR =
+ 1748, /**< OBEX: response Internal Server Error */
+ OI_OBEX_UNSUPPORTED_MEDIA_TYPE =
+ 1749, /**< OBEX: response Unsupported Media Type */
+ OI_OBEX_PARTIAL_CONTENT = 1750, /**< OBEX: response Partial Content */
+ OI_OBEX_METHOD_NOT_ALLOWED = 1751, /**< OBEX: response Method Not Allowed */
+ OI_OBEXSRV_INCOMPLETE_GET = 1752, /**< OBEX: Indicates to a GET handler that
+ the request phase is still in progress */
+ OI_OBEX_FOLDER_BROWSING_NOT_ALLOWED = 1753, /**< OBEX: Indicates that an FTP
+ server does not allow folder
+ browsing */
+ OI_OBEX_SERVER_FORCED_DISCONNECT =
+ 1754, /**< OBEX: connection was forcibly terminated by the server */
+ OI_OBEX_OFS_ERROR = 1755, /**< OBEX: OPP object file system error occurred */
+ OI_OBEX_FILEOP_ERROR =
+ 1756, /**< OBEX: FTP/PBAP file operation system error occurred */
+ OI_OBEX_USERID_TOO_LONG =
+ 1757, /**< OBEX: User Id exceeds spec limited length limit. */
+
+ OI_HANDSFREE_EVENT_REPORTING_DISABLED =
+ 1801, /**< HANDSFREE: Event reporting disabled */
+ OI_HANDSFREE_NOT_CONNECTED = 1802, /**< HANDSFREE: Not connected */
+ OI_HANDSFREE_SERVICE_NOT_STARTED = 1803, /**< HANDSFREE: Cannot connect to
+ handsfree AG if handsfree service
+ not started */
+ OI_HANDSFREE_AG_SERVICE_NOT_STARTED =
+ 1804, /**< HANDSFREE: Cannot connect to handsfree device if handsfree AG
+ service not started */
+ OI_HANDSFREE_COMMAND_IN_PROGRESS =
+ 1805, /**< HANDSFREE: Cannot accept a command at this time */
+ OI_HANDSFREE_AUDIO_ALREADY_CONNECTED =
+ 1806, /**< HANDSFREE: Audio is already connected */
+ OI_HANDSFREE_AUDIO_NOT_CONNECTED =
+ 1807, /**< HANDSFREE: Audio is not connected */
+ OI_HANDSFREE_FEATURE_NOT_SUPPORTED = 1808, /**< HANDSFREE: Local or remote
+ feature not supported for
+ requested command */
+
+ OI_HEADSET_SERVICE_NOT_STARTED =
+ 1901, /**< HEADSET: Cannot connect to headset AG if headset service not
+ started */
+ OI_HEADSET_AG_SERVICE_NOT_STARTED = 1902, /**< HEADSET: Cannot connect to
+ headset device if headset AG
+ service not started */
+ OI_HEADSET_COMMAND_IN_PROGRESS =
+ 1903, /**< HEADSET: Cannot accept a command at this time */
+
+ OI_BNEP_INVALID_MTU =
+ 2001, /**< BNEP: The remote device cannot support the minimum BNEP MTU */
+ OI_BNEP_SETUP_TIMEOUT = 2002, /**< BNEP: The setup request timed out. */
+ OI_BNEP_SERVICE_NOT_REGISTERED =
+ 2003, /**< BNEP: The requested service was not found. */
+ OI_BNEP_INVALID_HANDLE =
+ 2004, /**< BNEP: The specified connection handle is not valid. */
+ OI_BNEP_RESPONSE_TIMEOUT =
+ 2005, /**< BNEP: The timer for receiving a response has expired. */
+ OI_BNEP_INVALID_CONNECTION = 2006, /**< BNEP: Invalid connection */
+ OI_BNEP_INVALID_FILTER = 2007, /**< BNEP: The supplied filter was invalid. */
+ OI_BNEP_CONNECTION_EXISTS =
+ 2008, /**< BNEP: An attempt was made to create a duplicate connection. */
+ OI_BNEP_NOT_INITIALIZED = 2009, /**< BNEP: Init has not been called */
+ OI_BNEP_CONNECT_BASE = 2010, /**< BNEP: connection response codes */
+ OI_BNEP_CONNECT_FAILED_INVALID_DEST_UUID =
+ 2011, /**< BNEP: connect response code Invalid Dest UUID */
+ OI_BNEP_CONNECT_FAILED_INVALID_SOURCE_UUID =
+ 2012, /**< BNEP: connect response code Invalid Source UUID */
+ OI_BNEP_CONNECT_FAILED_INVALID_UUID_SIZE =
+ 2013, /**< BNEP: connect response code Invalid UUID Size */
+ OI_BNEP_CONNECT_FAILED_NOT_ALLOWED =
+ 2014, /**< BNEP: connect response code Not Allowed */
+ OI_BNEP_FILTER_NET_BASE = 2020, /**< BNEP: filter response codes */
+ OI_BNEP_FILTER_NET_UNSUPPORTED_REQUEST =
+ 2021, /**< BNEP: filter response code Unsupported Request */
+ OI_BNEP_FILTER_NET_FAILED_INVALID_PROTOCOL_TYPE =
+ 2022, /**< BNEP: filter response code Invalid Protocol Type */
+ OI_BNEP_FILTER_NET_FAILED_MAX_LIMIT_REACHED =
+ 2023, /**< BNEP: filter response code Max Limit Reached */
+ OI_BNEP_FILTER_NET_FAILED_SECURITY =
+ 2024, /**< BNEP: filter response code Security */
+ OI_BNEP_FILTER_MULTI_BASE = 2030, /**< BNEP: multicast response codes */
+ OI_BNEP_FILTER_MULTI_UNSUPPORTED_REQUEST =
+ 2031, /**< BNEP: multicast response code Unsupported Request */
+ OI_BNEP_FILTER_MULTI_FAILED_INVALID_ADDRESS =
+ 2032, /**< BNEP: multicast response code Invalid Address */
+ OI_BNEP_FILTER_MULTI_FAILED_MAX_LIMIT_REACHED =
+ 2033, /**< BNEP: multicast response code Max Limit Reached */
+ OI_BNEP_FILTER_MULTI_FAILED_SECURITY =
+ 2034, /**< BNEP: multicast response code Security */
+ OI_BNEP_LOCAL_DEVICE_MUST_BE_MASTER =
+ 2040, /**< BNEP: Device must be master of the piconet for this function */
+ OI_BNEP_PACKET_FILTERED_OUT =
+ 2041, /**< BNEP: Packet did not pass current filters */
+
+ OI_NETIFC_UP_FAILED =
+ 2101, /**< NETIFC: Could not bring up network interface */
+ OI_NETIFC_COULD_NOT_CREATE_THREAD =
+ 2102, /**< NETIFC: Network interface could not create a read thread */
+ OI_NETIFC_INITIALIZATION_FAILED =
+ 2103, /**< NETIFC: Error in network interface initialization */
+ OI_NETIFC_INTERFACE_ALREADY_UP =
+ 2104, /**< NETIFC: Network interface is already up */
+ OI_NETIFC_INTERFACE_NOT_UP = 2105, /**< NETIFC: Network interface is not up */
+ OI_NETIFC_PACKET_TOO_BIG = 2106, /**< NETIFC: The packet is too big */
+
+ OI_PAN_ROLE_ALREADY_REGISTERED =
+ 2201, /**< PAN: This PAN role was already registered */
+ OI_PAN_ROLE_NOT_ALLOWED =
+ 2202, /**< PAN: The PAN role is not currently allowed */
+ OI_PAN_INCOMPATIBLE_ROLES =
+ 2203, /**< PAN: Only certain local and remote role combinations are
+ permitted */
+ OI_PAN_INVALID_ROLE =
+ 2204, /**< PAN: Role specified is not one the defined PAN roles */
+ OI_PAN_CONNECTION_IN_PROGRESS =
+ 2205, /**< PAN: A PAN connection is currently being established */
+ OI_PAN_USER_ALREADY_CONNECTED =
+ 2206, /**< PAN: PAN user role only allows a single connection */
+ OI_PAN_DEVICE_CONNECTED =
+ 2207, /**< PAN: A PAN connection already exists to specified device */
+
+ OI_CODEC_SBC_NO_SYNCWORD = 2301, /**< CODEC: Couldn't find an SBC SYNCWORD */
+ OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA =
+ 2302, /**< CODEC: Not enough data provided to decode an SBC header */
+ OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA =
+ 2303, /**< CODEC: Decoded the header, but not enough data to contain the
+ rest of the frame */
+ OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA =
+ 2304, /**< CODEC: Not enough audio data for this frame */
+ OI_CODEC_SBC_CHECKSUM_MISMATCH =
+ 2305, /**< CODEC: The frame header didn't match the checksum */
+ OI_CODEC_SBC_PARTIAL_DECODE =
+ 2306, /**< CODEC: Decoding was successful, but frame data still remains.
+ Next call will provide audio without consuming input data. */
+
+ OI_FIFOQ_QUEUE_NOT_ALIGNED = 2401, /**< FIFOQ: queue must be 32-bit aligned */
+ OI_FIFOQ_INVALID_Q = 2402, /**< FIFOQ: queue parameter is not a valid queue */
+ OI_FIFOQ_BUF_TOO_LARGE =
+ 2403, /**< FIFOQ: attempt to queue a buffer which is too large */
+ OI_FIFOQ_FULL = 2404, /**< FIFOQ: enqueue() failed, queue is full */
+ OI_FIFOQ_NOT_ALLOCATED =
+ 2405, /**< FIFOQ: Enqueue QBuf() failed, buffer not allocated */
+ OI_FIFOQ_INVALID_DATA_PTR =
+ 2406, /**< FIFOQ: Enqueue QBuf() failed, data pointer does not match */
+
+ OI_HID_HOST_SERVICE_NOT_STARTED = 2601, /**< HID: Cannot connect to a HID
+ device unless HID host is started
+ */
+ OI_HID_DEVICE_SERVICE_NOT_STARTED =
+ 2602, /**< HID: Cannot connect to a HID host unless HID device is started
+ */
+
+ OI_AT_ERROR = 2701, /**< AT: ERROR response */
+ OI_AT_NO_CARRIER = 2702, /**< AT: NO CARRIER response */
+ OI_AT_BUSY = 2703, /**< AT: BUSY response */
+ OI_AT_NO_ANSWER = 2704, /**< AT: NO ANSWER response */
+ OI_AT_DELAYED = 2705, /**< AT: DELAYED response */
+ OI_AT_BLACKLISTED = 2706, /**< AT: BLACKLISTED response */
+ OI_AT_CME_ERROR = 2707, /**< AT: +CME ERROR response */
+ OI_AT_CMS_ERROR = 2708, /**< AT: +CMS ERROR response */
+
+ OI_BLST_CHARACTER_TIMEOUT =
+ 2801, /**< BLST: Timeout expired while waiting for a character from the
+ client. */
+ OI_BLST_ACKNOWLDGE_TIMEOUT =
+ 2802, /**< BLST: Timeout expired while waiting for event acknowledgment
+ from the client */
+ OI_BLST_TX_NOT_READY = 2803, /**< BLST: BLST is not ready to send a BHAPI
+ message to the client. */
+ OI_BLST_TX_BUSY = 2804, /**< BLST: BLST transmit buffer is in use. */
+
+ OI_AVDTP_CONNECTION_SEQ_ERROR =
+ 2901, /**< AVDTP: sequencing of signalling/media channel connections
+ broken. */
+ OI_AVDTP_OUT_OF_RESOURCES = 2902, /**< AVDTP: Tried to allocate too many
+ endpoints or signalling channels. */
+
+ OI_PBAP_REPOSITORY_NOT_SET =
+ 3001, /**< PBAP: Phonebook repository must be set for operation to
+ complete. */
+ OI_PBAP_PHONEBOOK_NOT_SET =
+ 3002, /**< PBAP: Phonebook be set for operation to complete. */
+
+ OI_AADP_BAD_ENDPOINT = 3101, /**< AADP: Invalid local endpoint specified */
+ OI_AADP_BAD_STATE =
+ 3102, /**< AADP: AADP State is not correct for this operation. */
+
+ OI_UNICODE_INVALID_SOURCE = 3200, /**< Unicode Conversion: Source string has
+ invalid character encoding. */
+ OI_UNICODE_SOURCE_EXHAUSTED = 3201, /**< Unicode Conversion: Incomplete
+ Unicode character at end of source
+ buffer. */
+ OI_UNICODE_DESTINATION_EXHAUSTED = 3202, /**< Unicode Conversion: Destination
+ buffer not large enough to hold
+ resulting Unicode string. */
+
+ OI_AVRCP_TOO_MANY_CONNECTIONS = 3300, /**< AVRCP: Exceeded maximum number of
+ simultaneous AVCTP connections. */
+ OI_AVRCP_NOT_IMPLEMENTED =
+ 3301, /**< AVRCP: The target does not implement the command specified by
+ the opcode and operand. */
+ OI_AVRCP_REJECTED = 3302, /**< AVRCP: The target cannot respond because of
+ invalid operands in command packet. */
+ OI_AVRCP_INVALID_RESPONSE = 3303, /**< AVRCP: The controller received the
+ response with invalid parameters */
+ OI_AVRCP_RESPONSE_PACKET_OVERFLOW =
+ 3304, /**< AVRCP: The response message does not fir in one AVRCP packet
+ (512 bytes), has to be fragmented. */
+ OI_AVRCP_RESPONSE_INVALID_PDU = 3305, /**< AVRCP: Command rejected: target
+ received a PDU that it did not
+ understand. */
+ OI_AVRCP_RESPONSE_INVALID_PARAMETER = 3306, /**< AVRCP: Command rejected:
+ target received a PDU with a
+ parameter ID that it did not
+ understand. */
+ OI_AVRCP_RESPONSE_PARAMETER_NOT_FOUND =
+ 3307, /**< AVRCP: Command rejected: specified parameter not found, sent if
+ the parameter ID is understood, but content is wrong or
+ corrupted.*/
+ OI_AVRCP_RESPONSE_INTERNAL_ERROR =
+ 3308, /**< AVRCP: Command rejected: target detected other error
+ conditions. */
+ OI_MAX_BM3_STATUS_VAL, /* Maximum BM3 status code */
+
+ /* Status code values reserved for BM3 SDK platform-specific implementations
+ */
+ OI_STATUS_RESERVED_FOR_BCOT = 9000,
+
+ /* Status code values reserved for BHAPI products */
+ OI_STATUS_RESERVED_FOR_BHAPI = 9200,
+
+ /* Status code values reserved for Soundabout products */
+ OI_STATUS_RESERVED_FOR_SOUNDABOUT = 9400,
+
+ /*
+ * Status code values greater than or equal to this value are reserved for use
+ * by applications.
+ * However, because of differences between compilers, and differences between
+ * 16-bit and 32-bit
+ * platforms custom status codes should be in the 16-bit range, so status
+ * codes can range from 0
+ * to 65534, inclusive (65535 is reserved)
+ */
+ OI_STATUS_RESERVED_FOR_APPS = 10000,
+
+ OI_STATUS_NONE = 0xffff /**< Special status code to indicate that there is no
+ status. (Only to be used for special cases
+ involving OI_SLOG_ERROR() and OI_SLOG_WARNING().)
+ */
+
+} OI_STATUS;
+
+/* Remeber to update the #define below when new reserved blocks are added to
+ * the list above. */
+#define OI_NUM_RESERVED_STATUS_BLOCKS \
+ 4 /**< Number of status code blocks reserved, including user apps */
+
+/**
+ * Test for success
+ */
+#define OI_SUCCESS(x) ((x) == OI_OK)
+
+/*****************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_STATUS_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_stddefs.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_stddefs.h
new file mode 100755
index 0000000..ade040d
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_stddefs.h
@@ -0,0 +1,331 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef OI_STDDEFS_H
+#define OI_STDDEFS_H
+/**
+ * @file
+ * This file contains BM3 standard type definitions.
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_cpu_dep.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef FALSE
+#define FALSE \
+ 0 /**< This define statement sets FALSE as a preprocessor alias for 0. */
+#endif
+
+#ifndef TRUE
+#define TRUE \
+ (!FALSE) /**< This define statement sets TRUE as a preprocessor alias for \
+ !FALSE. */
+#endif
+
+#ifdef HEW_TOOLCHAIN
+#ifdef NULL
+#undef NULL /**< Override HEW toolchain NULL definition */
+#endif
+#define NULL \
+ 0 /**< HEW toolchain does not allow us to compare (void*) type to function \
+ pointer */
+#else
+#ifndef NULL
+#define NULL \
+ ((void*)0) /**< This define statement sets NULL as a preprocessor alias \
+ for (void*)0 */
+#endif
+#endif
+
+/**
+ * @name Maximum and minimum values for basic types
+ * @{
+ */
+#define OI_INT8_MIN ((int8_t)0x80) /**< decimal value: -128 */
+#define OI_INT8_MAX ((int8_t)0x7F) /**< decimal value: 127 */
+#define OI_INT16_MIN ((int16_t)0x8000) /**< decimal value: -32768 */
+#define OI_INT16_MAX ((int16_t)0x7FFF) /**< decimal value: 32767 */
+#define OI_INT32_MIN \
+ ((int32_t)0x80000000) /**< decimal value: -2,147,483,648 \
+ */
+#define OI_INT32_MAX \
+ ((int32_t)0x7FFFFFFF) /**< decimal value: 2,147,483,647 \
+ */
+#define OI_UINT8_MIN ((uint8_t)0) /**< decimal value: 0 */
+#define OI_UINT8_MAX ((uint8_t)0xFF) /**< decimal value: 255 */
+#define OI_UINT16_MIN ((uint16_t)0) /**< decimal value: 0 */
+#define OI_UINT16_MAX ((uint16_t)0xFFFF) /**< decimal value: 65535 */
+#define OI_UINT32_MIN ((uint32_t)0) /**< decimal value: 0 */
+#define OI_UINT32_MAX \
+ ((uint32_t)0xFFFFFFFF) /**< decimal value: 4,294,967,295 */
+
+/**
+ * @}
+ */
+
+/**
+ * @name Integer types required by the Service Discovery Protocol
+ * @{
+ */
+
+/** unsigned 64-bit integer as a structure of two unsigned 32-bit integers */
+typedef struct {
+ uint32_t I1; /**< most significant 32 bits */
+ uint32_t I2; /**< least significant 32 bits */
+} OI_UINT64;
+
+#define OI_UINT64_MIN \
+ { (uint32_t)0x00000000, (uint32_t)0x00000000 }
+#define OI_UINT64_MAX \
+ { (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/* signed 64-bit integer as a structure of one unsigned 32-bit integer and one
+ * signed 32-bit integer
+ */
+typedef struct {
+ int32_t I1; /**< most significant 32 bits as a signed integer */
+ uint32_t I2; /**< least significant 32 bits as an unsigned integer */
+} OI_INT64;
+
+#define OI_INT64_MIN \
+ { (int32_t)0x80000000, (uint32_t)0x00000000 }
+#define OI_INT64_MAX \
+ { (int32_t)0X7FFFFFFF, (uint32_t)0XFFFFFFFF }
+
+/** unsigned 128-bit integer as a structure of four unsigned 32-bit integers */
+typedef struct {
+ uint32_t I1; /**< most significant 32 bits */
+ uint32_t I2; /**< second-most significant 32 bits */
+ uint32_t I3; /**< third-most significant 32 bits */
+ uint32_t I4; /**< least significant 32 bits */
+} OI_UINT128;
+
+#define OI_UINT128_MIN \
+ { \
+ (uint32_t)0x00000000, (uint32_t)0x00000000, (uint32_t)0x00000000, \
+ (uint32_t)0x00000000 \
+ }
+#define OI_UINT128_MAX \
+ { \
+ (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF, \
+ (uint32_t)0XFFFFFFFF \
+ }
+
+/* signed 128-bit integer as a structure of three unsigned 32-bit integers and
+ * one signed 32-bit integer */
+typedef struct {
+ int32_t I1; /**< most significant 32 bits as a signed integer */
+ uint32_t I2; /**< second-most significant 32 bits as an unsigned integer */
+ uint32_t I3; /**< third-most significant 32 bits as an unsigned integer */
+ uint32_t I4; /**< least significant 32 bits as an unsigned integer */
+} OI_INT128;
+
+#define OI_INT128_MIN \
+ { \
+ (uint32_t)0x80000000, (uint32_t)0x00000000, (uint32_t)0x00000000, \
+ (uint32_t)0x00000000 \
+ }
+#define OI_INT128_MAX \
+ { \
+ (uint32_t)0X7FFFFFFF, (uint32_t)0XFFFFFFFF, (uint32_t)0XFFFFFFFF, \
+ (uint32_t)0XFFFFFFFF \
+ }
+
+/**
+ * @}
+ */
+
+/**
+ * type for ASCII character data items
+ */
+typedef char OI_CHAR;
+
+/**
+ * type for double-byte character data items
+ */
+typedef uint16_t OI_CHAR16;
+
+/**
+ * types for UTF encoded strings.
+ */
+typedef uint8_t OI_UTF8;
+typedef uint16_t OI_UTF16;
+typedef uint32_t OI_UTF32;
+
+/**
+ * @name Single-bit operation macros
+ * @{
+ * In these macros, x is the data item for which a bit is to be tested or set
+ * and y specifies which bit is to be tested or set.
+ */
+
+/* This macro's value is true if the bit specified by y is set in data item x.
+ */
+#define OI_BIT_TEST(x, y) ((x) & (y))
+
+/* This macro's value is true if the bit specified by y is not set in data item
+ * x.
+ */
+#define OI_BIT_CLEAR_TEST(x, y) (((x) & (y)) == 0)
+
+/** This macro sets the bit specified by y in data item x. */
+#define OI_BIT_SET(x, y) ((x) |= (y))
+
+/** This macro clears the bit specified by y in data item x. */
+#define OI_BIT_CLEAR(x, y) ((x) &= ~(y))
+
+/** @} */
+
+/**
+ * The OI_ARRAYSIZE macro is set to the number of elements in an array
+ * (instead of the number of bytes, which is returned by sizeof()).
+ */
+
+#ifndef OI_ARRAYSIZE
+#define OI_ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+/**
+ * @name Preprocessor aliases for individual bit positions
+ * Bits are defined here only if they are not already defined.
+ * @{
+ */
+
+#ifndef BIT0
+
+#define BIT0 \
+ 0x00000001 /**< preprocessor alias for 32-bit value with bit 0 set, used to \
+ specify this single bit */
+#define BIT1 \
+ 0x00000002 /**< preprocessor alias for 32-bit value with bit 1 set, used to \
+ specify this single bit */
+#define BIT2 \
+ 0x00000004 /**< preprocessor alias for 32-bit value with bit 2 set, used to \
+ specify this single bit */
+#define BIT3 \
+ 0x00000008 /**< preprocessor alias for 32-bit value with bit 3 set, used to \
+ specify this single bit */
+#define BIT4 \
+ 0x00000010 /**< preprocessor alias for 32-bit value with bit 4 set, used to \
+ specify this single bit */
+#define BIT5 \
+ 0x00000020 /**< preprocessor alias for 32-bit value with bit 5 set, used to \
+ specify this single bit */
+#define BIT6 \
+ 0x00000040 /**< preprocessor alias for 32-bit value with bit 6 set, used to \
+ specify this single bit */
+#define BIT7 \
+ 0x00000080 /**< preprocessor alias for 32-bit value with bit 7 set, used to \
+ specify this single bit */
+#define BIT8 \
+ 0x00000100 /**< preprocessor alias for 32-bit value with bit 8 set, used to \
+ specify this single bit */
+#define BIT9 \
+ 0x00000200 /**< preprocessor alias for 32-bit value with bit 9 set, used to \
+ specify this single bit */
+#define BIT10 \
+ 0x00000400 /**< preprocessor alias for 32-bit value with bit 10 set, used to \
+ specify this single bit */
+#define BIT11 \
+ 0x00000800 /**< preprocessor alias for 32-bit value with bit 11 set, used to \
+ specify this single bit */
+#define BIT12 \
+ 0x00001000 /**< preprocessor alias for 32-bit value with bit 12 set, used to \
+ specify this single bit */
+#define BIT13 \
+ 0x00002000 /**< preprocessor alias for 32-bit value with bit 13 set, used to \
+ specify this single bit */
+#define BIT14 \
+ 0x00004000 /**< preprocessor alias for 32-bit value with bit 14 set, used to \
+ specify this single bit */
+#define BIT15 \
+ 0x00008000 /**< preprocessor alias for 32-bit value with bit 15 set, used to \
+ specify this single bit */
+#define BIT16 \
+ 0x00010000 /**< preprocessor alias for 32-bit value with bit 16 set, used to \
+ specify this single bit */
+#define BIT17 \
+ 0x00020000 /**< preprocessor alias for 32-bit value with bit 17 set, used to \
+ specify this single bit */
+#define BIT18 \
+ 0x00040000 /**< preprocessor alias for 32-bit value with bit 18 set, used to \
+ specify this single bit */
+#define BIT19 \
+ 0x00080000 /**< preprocessor alias for 32-bit value with bit 19 set, used to \
+ specify this single bit */
+#define BIT20 \
+ 0x00100000 /**< preprocessor alias for 32-bit value with bit 20 set, used to \
+ specify this single bit */
+#define BIT21 \
+ 0x00200000 /**< preprocessor alias for 32-bit value with bit 21 set, used to \
+ specify this single bit */
+#define BIT22 \
+ 0x00400000 /**< preprocessor alias for 32-bit value with bit 22 set, used to \
+ specify this single bit */
+#define BIT23 \
+ 0x00800000 /**< preprocessor alias for 32-bit value with bit 23 set, used to \
+ specify this single bit */
+#define BIT24 \
+ 0x01000000 /**< preprocessor alias for 32-bit value with bit 24 set, used to \
+ specify this single bit */
+#define BIT25 \
+ 0x02000000 /**< preprocessor alias for 32-bit value with bit 25 set, used to \
+ specify this single bit */
+#define BIT26 \
+ 0x04000000 /**< preprocessor alias for 32-bit value with bit 26 set, used to \
+ specify this single bit */
+#define BIT27 \
+ 0x08000000 /**< preprocessor alias for 32-bit value with bit 27 set, used to \
+ specify this single bit */
+#define BIT28 \
+ 0x10000000 /**< preprocessor alias for 32-bit value with bit 28 set, used to \
+ specify this single bit */
+#define BIT29 \
+ 0x20000000 /**< preprocessor alias for 32-bit value with bit 29 set, used to \
+ specify this single bit */
+#define BIT30 \
+ 0x40000000 /**< preprocessor alias for 32-bit value with bit 30 set, used to \
+ specify this single bit */
+#define BIT31 \
+ 0x80000000 /**< preprocessor alias for 32-bit value with bit 31 set, used to \
+ specify this single bit */
+
+#endif /* BIT0 et al */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/*****************************************************************************/
+#endif /* OI_STDDEFS_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_string.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_string.h
new file mode 100755
index 0000000..fe1e4c1
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_string.h
@@ -0,0 +1,193 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef OI_STRING_H
+#define OI_STRING_H
+/**
+ * @file
+ * This file contains BM3 supplied portable string.h functions
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_cpu_dep.h"
+#include "oi_stddefs.h"
+
+#if defined(USE_NATIVE_MEMCPY) || defined(USE_NATIVE_MALLOC)
+#include <string.h>
+#endif
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * If we are using Native malloc(), we must also use
+ * native Ansi string.h functions for memory manipulation.
+ */
+#ifdef USE_NATIVE_MALLOC
+#ifndef USE_NATIVE_MEMCPY
+#define USE_NATIVE_MEMCPY
+#endif
+#endif
+
+#ifdef USE_NATIVE_MEMCPY
+
+#define OI_MemCopy(to, from, size) memcpy((to), (from), (size))
+#define OI_MemSet(block, val, size) memset((block), (val), (size))
+#define OI_MemZero(block, size) memset((block), 0, (size))
+#define OI_MemCmp(s1, s2, n) memcmp((s1), (s2), (n))
+#define OI_Strcpy(dest, src) strcpy((dest), (src))
+#define OI_Strcat(dest, src) strcat((dest), (src))
+#define OI_StrLen(str) strlen((str))
+#define OI_Strcmp(s1, s2) strcmp((s1), (s2))
+#define OI_Strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+
+#else
+
+/*
+ * OI_MemCopy
+ *
+ * Copy an arbitrary number of bytes from one memory address to another.
+ * The underlying implementation is the ANSI memmove() or equivalant, so
+ * overlapping memory copies will work correctly.
+ */
+void OI_MemCopy(void* To, void const* From, uint32_t Size);
+
+/*
+ * OI_MemSet
+ *
+ * Sets all bytes in a block of memory to the same value
+ */
+void OI_MemSet(void* Block, uint8_t Val, uint32_t Size);
+
+/*
+ * OI_MemZero
+ *
+ * Sets all bytes in a block of memory to zero
+ */
+void OI_MemZero(void* Block, uint32_t Size);
+
+/*
+ * OI_MemCmp
+ *
+ * Compare two blocks of memory
+ *
+ * Returns:
+ * 0, if s1 == s2
+ * < 0, if s1 < s2
+ * > 0, if s2 > s2
+ */
+OI_INT OI_MemCmp(void const* s1, void const* s2, uint32_t n);
+
+/*
+ * OI_Strcpy
+ *
+ * Copies the Null terminated string from pStr to pDest, and
+ * returns pDest.
+ */
+
+OI_CHAR* OI_Strcpy(OI_CHAR* pDest, OI_CHAR const* pStr);
+
+/*
+ * OI_Strcat
+ *
+ * Concatonates the pStr string to the end of pDest, and
+ * returns pDest.
+ */
+
+OI_CHAR* OI_Strcat(OI_CHAR* pDest, OI_CHAR const* pStr);
+
+/*
+ * OI_StrLen
+ *
+ * Calculates the number of OI_CHARs in pStr (not including
+ * the Null terminator) and returns the value.
+ */
+OI_UINT OI_StrLen(OI_CHAR const* pStr);
+
+/*
+ * OI_Strcmp
+ *
+ * Compares two Null terminated strings
+ *
+ * Returns:
+ * 0, if s1 == s2
+ * < 0, if s1 < s2
+ * > 0, if s2 > s2
+ */
+OI_INT OI_Strcmp(OI_CHAR const* s1, OI_CHAR const* s2);
+
+/*
+ * OI_Strncmp
+ *
+ * Compares the first "len" OI_CHARs of strings s1 and s2.
+ *
+ * Returns:
+ * 0, if s1 == s2
+ * < 0, if s1 < s2
+ * > 0, if s2 > s2
+ */
+OI_INT OI_Strncmp(OI_CHAR const* s1, OI_CHAR const* s2, uint32_t len);
+
+#endif /* USE_NATIVE_MEMCPY */
+
+/*
+ * OI_StrcmpInsensitive
+ *
+ * Compares two Null terminated strings, treating
+ * the Upper and Lower case of 'A' through 'Z' as
+ * equivilent.
+ *
+ * Returns:
+ * 0, if s1 == s2
+ * < 0, if s1 < s2
+ * > 0, if s2 > s2
+ */
+OI_INT OI_StrcmpInsensitive(OI_CHAR const* s1, OI_CHAR const* s2);
+
+/*
+ * OI_StrncmpInsensitive
+ *
+ * Compares the first "len" OI_CHARs of strings s1 and s2,
+ * treating the Upper and Lower case of 'A' through 'Z' as
+ * equivilent.
+ *
+ *
+ * Returns:
+ * 0, if s1 == s2
+ * < 0, if s1 < s2
+ * > 0, if s2 > s2
+ */
+OI_INT OI_StrncmpInsensitive(OI_CHAR const* s1, OI_CHAR const* s2, OI_UINT len);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+/*****************************************************************************/
+#endif /* OI_STRING_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_time.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_time.h
new file mode 100755
index 0000000..9b189af
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_time.h
@@ -0,0 +1,193 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_TIME_H
+#define _OI_TIME_H
+/** @file
+ *
+ * This file provides time type definitions and time-related functions.
+ *
+ * The stack maintains a 64-bit real-time millisecond clock. The choice of
+ * milliseconds is for convenience, not accuracy.
+ *
+ * Timeouts are specified as tenths of seconds in a 32-bit value. Timeout values
+ * specified by the Bluetooth specification are usually muliple seconds, so
+ * accuracy to a tenth of a second is more than adequate.
+ *
+ * This file also contains macros to convert between seconds and the Link
+ * Manager's 1.28-second units.
+ *
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_stddefs.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Within the core stack, timeouts are specified in intervals of tenths of
+ * seconds.
+ */
+
+typedef uint16_t OI_INTERVAL;
+#define OI_INTERVALS_PER_SECOND 10
+#define MSECS_PER_OI_INTERVAL (1000 / OI_INTERVALS_PER_SECOND)
+
+/** maximum interval (54 min 36.7 sec) */
+#define OI_MAX_INTERVAL 0x7fff
+
+/**
+ * Macro to convert seconds to OI_INTERVAL time units
+ */
+
+#define OI_SECONDS(n) ((OI_INTERVAL)((n)*OI_INTERVALS_PER_SECOND))
+
+/**
+ * Macro to convert milliseconds to OI_INTERVAL time units (Rounded Up)
+ */
+
+#define OI_MSECONDS(n) \
+ ((OI_INTERVAL)(((n) + MSECS_PER_OI_INTERVAL - 1) / MSECS_PER_OI_INTERVAL))
+
+/**
+ * Macro to convert minutes to OI_INTERVAL time units
+ */
+
+#define OI_MINUTES(n) ((OI_INTERVAL)((n)*OI_SECONDS(60)))
+
+/** Convert an OI_INTERVAL to milliseconds. */
+#define OI_INTERVAL_TO_MILLISECONDS(i) ((i)*MSECS_PER_OI_INTERVAL)
+
+/**
+ * The stack depends on relative not absolute time. Any mapping between the
+ * stack's real-time clock and absolute time and date is
+ * implementation-dependent.
+ */
+
+typedef struct {
+ int32_t seconds;
+ int16_t mseconds;
+} OI_TIME;
+
+/**
+ * Convert an OI_TIME to milliseconds.
+ *
+ * @param t the time to convert
+ *
+ * @return the time in milliseconds
+ */
+uint32_t OI_Time_ToMS(OI_TIME* t);
+
+/**
+ * This function compares two time values.
+ *
+ * @param T1 first time to compare.
+ *
+ * @param T2 second time to compare.
+ *
+ * @return
+ @verbatim
+ -1 if t1 < t2
+ 0 if t1 = t2
+ +1 if t1 > t2
+ @endverbatim
+ */
+
+int16_t OI_Time_Compare(OI_TIME* T1, OI_TIME* T2);
+
+/**
+ * This function returns the interval between two times to a granularity of 0.1
+ * seconds.
+ *
+ * @param Sooner a time value more recent that Later
+ *
+ * @param Later a time value later than Sooner
+ *
+ * @note The result is an OI_INTERVAL value so this function only works for time
+ * intervals that are less than about 71 minutes.
+ *
+ * @return the time interval between the two times = (Later - Sooner)
+ */
+
+OI_INTERVAL OI_Time_Interval(OI_TIME* Sooner, OI_TIME* Later);
+
+/**
+ * This function returns the interval between two times to a granularity of
+ * milliseconds.
+ *
+ * @param Sooner a time value more recent that Later
+ *
+ * @param Later a time value later than Sooner
+ *
+ * @note The result is an uint32_t value so this function only works for time
+ * intervals that are less than about 50 days.
+ *
+ * @return the time interval between the two times = (Later - Sooner)
+ */
+
+uint32_t OI_Time_IntervalMsecs(OI_TIME* Sooner, OI_TIME* Later);
+
+/**
+ * This function answers this question:
+ * "Have we reached or gone past the target time?"
+ *
+ * @param pTargetTime target time
+ *
+ * @return true means time now is at or past target time
+ * false means target time is still some time in the future
+ */
+
+OI_BOOL OI_Time_NowReachedTime(OI_TIME* pTargetTime);
+
+/**
+ * Convert seconds to the Link Manager 1.28-second units
+ * Approximate by using 1.25 conversion factor.
+ */
+
+#define OI_SECONDS_TO_LM_TIME_UNITS(lmUnits) \
+ ((lmUnits) < 4 ? (lmUnits) : (lmUnits) - ((lmUnits) >> 2))
+
+/**
+ * Convert Link Manager 1.28-second units to seconds.
+ * Approximate by using 1.25 conversion factor.
+ */
+
+#define OI_LM_TIME_UNITS_TO_SECONDS(lmUnits) ((lmUnits) + ((lmUnits) >> 2))
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+/* Include for OI_Time_Now() prototype
+ * Must be included at end to obtain OI_TIME typedef
+ */
+#include "oi_osinterface.h"
+
+/*****************************************************************************/
+#endif /* _OI_TIME_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_utils.h b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_utils.h
new file mode 100755
index 0000000..d91780f
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/include/oi_utils.h
@@ -0,0 +1,376 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef _OI_UTILS_H
+#define _OI_UTILS_H
+/**
+ * @file
+ *
+ * This file provides the interface for utility functions.
+ * Among the utilities are strlen (string length), strcmp (string compare), and
+ * other string manipulation functions. These are provided for those plaforms
+ * where this functionality is not available in stdlib.
+ */
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include <stdarg.h>
+#include "oi_bt_spec.h"
+#include "oi_common.h"
+#include "oi_string.h"
+
+/** \addtogroup Misc Miscellaneous APIs */
+/**@{*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opaque type for a callback function handle. See OI_ScheduleCallbackFunction()
+ */
+typedef uint32_t OI_CALLBACK_HANDLE;
+
+/**
+ * Function prototype for a timed procedure callback.
+ *
+ * @param arg Value that was passed into the OI_ScheduleCallback() function
+ *
+ */
+typedef void (*OI_SCHEDULED_CALLBACK)(void* arg);
+
+/**
+ * Registers a function to be called when a timeout expires. This API uses
+ * BLUEmagic's internal function dispatch mechanism, so applications that make
+ * extensive use of this facility may need to increase the value of
+ * DispatchTableSize in the configuration block for the dispatcher (see
+ * oi_bt_stack_config.h).
+ *
+ * @param callbackFunction The function that will be called when the timeout
+ * expires
+ *
+ * @param arg Value that will be returned as the parameter to
+ * the callback function.
+ *
+ * @param timeout A timeout expressed in OI_INTERVALs (tenths of
+ * seconds). This can be zero in which case the
+ * callback function will be called as soon as
+ * possible.
+ *
+ * @param handle NULL or a pointer receive the callback handle.
+ *
+ * @return OI_OK if the function was registered, or an error
+ * status.
+ */
+OI_STATUS OI_ScheduleCallbackFunction(OI_SCHEDULED_CALLBACK callbackFunction,
+ void* arg, OI_INTERVAL timeout,
+ OI_CALLBACK_HANDLE* handle);
+
+/**
+ * Cancels a function registered with OI_ScheduleCallbackFunction() before its
+ * timer expires.
+ *
+ * @param handle handle returned by OI_ScheduleCallbackFunction().
+ *
+ * @return OI_OK if the function was cancelled, or an error
+ * status.
+ */
+OI_STATUS OI_CancelCallbackFunction(OI_CALLBACK_HANDLE handle);
+
+/**
+ * Registers a function to be called when a timeout expires. This version does
+ * not return a handle so can only be canceled by calling OI_CancelCallback().
+ *
+ * @param callbackFunction The function that will be called when the timeout
+ * expires
+ *
+ * @param arg Value that will be returned as the parameter to
+ * the callback function.
+ *
+ * @param timeout A timeout expressed in OI_INTERVALs (tenths of
+ * seconds). This can be zero in which case the
+ * callback function will be called as soon as
+ * possible.
+ *
+ * @return OI_OK if the function was reqistered, or an error
+ * status.
+ */
+#define OI_ScheduleCallback(f, a, t) OI_ScheduleCallbackFunction(f, a, t, NULL);
+
+/**
+ * Cancels a function registered with OI_ScheduleCallback() before its timer
+ * expires. This function will cancel the first entry matches the indicated
+ * callback function pointer.
+ *
+ * @param callbackFunction The function that was originally registered
+ *
+ * @return OI_OK if the function was cancelled, or an error
+ * status.
+ */
+OI_STATUS OI_CancelCallback(OI_SCHEDULED_CALLBACK callbackFunction);
+
+/**
+ * Parse a Bluetooth device address from the specified string.
+ *
+ * @param str the string to parse
+ * @param addr the parsed address, if successful
+ *
+ * @return true if an address was successfully parsed, false otherwise
+ */
+
+OI_BOOL OI_ParseBdAddr(const OI_CHAR* str, OI_BD_ADDR* addr);
+
+/**
+ * Printf function for platforms which have no stdio or printf available.
+ * OI_Printf supports the basic formatting types, with the exception of
+ * floating point types. Additionally, OI_Printf supports several formats
+ * specific to BLUEmagic 3.0 software:
+ *
+ * \%! prints the string for an #OI_STATUS value.
+ * @code OI_Printf("There was an error %!", status); @endcode
+ *
+ * \%@ prints a hex dump of a buffer.
+ * Requires a pointer to the buffer and a signed integer length
+ * (0 for default length). If the buffer is large, only an excerpt will
+ * be printed.
+ * @code OI_Printf("Contents of buffer %@", buffer, sizeof(buffer));
+ * @endcode
+ *
+ * \%: prints a Bluetooth address in the form "HH:HH:HH:HH:HH:HH".
+ * Requires a pointer to an #OI_BD_ADDR.
+ * @code OI_Printf("Bluetooth address %:", &bdaddr); @endcode
+ *
+ * \%^ decodes and prints a data element as formatted XML.
+ * Requires a pointer to an #OI_DATAELEM.
+ * @code OI_Printf("Service attribute list is:\n%^", &attributes);
+ * @endcode
+ *
+ * \%/ prints the base file name of a path, that is, the final substring
+ * following a '/' or '\\' character. Requires a pointer to a null
+ * terminated string.
+ * @code OI_Printf("File %/", "c:\\dir1\\dir2\\file.txt"); @endcode
+ *
+ * \%~ prints a string, escaping characters as needed to display it in
+ * ASCII. Requires a pointer to an #OI_PSTR and an #OI_UNICODE_ENCODING
+ * parameter.
+ * @code OI_Printf("Identifier %~", &id, OI_UNICODE_UTF16_BE); @endcode
+ *
+ * \%[ inserts an ANSI color escape sequence. Requires a single character
+ * identifying the color to select. Colors are red (r/R), green (g/G),
+ * blue (b/B), yellow (y/Y), cyan (c/C), magenta (m/M), white (W),
+ * light-gray (l/L), dark-gray (d/D), and black (0). The lower case is
+ * dim, the upper case is bright (except in the case of light-gray and
+ * dark-gray, where bright and dim are identical). Any other value will
+ * select the default color.
+ * @code OI_Printf("%[red text %[black %[normal\n", 'r', '0', 0); @endcode
+ *
+ * \%a same as \%s, except '\\r' and '\\n' are output as "<cr>" and "<lf>".
+ * \%?a is valid, but \%la is not.
+ *
+ * \%b prints an integer in base 2.
+ * @code OI_Printf("Bits are %b", I); @endcode
+ *
+ * \%lb prints a long integer in base 2.
+ *
+ * \%?b prints the least significant N bits of an integer (or long integer)
+ * in base 2. Requires the integer and a length N.
+ * @code OI_Printf("Bottom 4 bits are: %?b", I, 4); @endcode
+ *
+ * \%B prints an integer as boolean text, "TRUE" or "FALSE".
+ * @code OI_Printf("The value 0 is %B, the value 1 is %B", 0, 1); @endcode
+ *
+ * \%?s prints a substring up to a specified maximum length.
+ * Requires a pointer to a string and a length parameter.
+ * @code OI_Printf("String prefix is %?s", str, 3); @endcode
+ *
+ * \%ls same as \%S.
+ *
+ * \%S prints a UTF16 string as UTF8 (plain ASCII, plus 8-bit char sequences
+ * where needed). Requires a pointer to #OI_CHAR16. \%?S is valid. The
+ * length parameter is in OI_CHAR16 characters.
+ *
+ * \%T prints time, formatted as "secs.msecs".
+ * Requires pointer to #OI_TIME struct, NULL pointer prints current time.
+ * @code OI_Printf("The time now is %T", NULL); @endcode
+ *
+ * @param format The format string
+ *
+ */
+void OI_Printf(const OI_CHAR* format, ...);
+
+/**
+ * Var-args version OI_Printf
+ *
+ * @param format Same as for OI_Printf.
+ *
+ * @param argp Var-args list.
+ */
+void OI_VPrintf(const OI_CHAR* format, va_list argp);
+
+/**
+ * Writes a formatted string to a buffer. This function supports the same format
+ * specifiers as OI_Printf().
+ *
+ * @param buffer Destination buffer for the formatted string.
+ *
+ * @param bufLen The length of the destination buffer.
+ *
+ * @param format The format string
+ *
+ * @return Number of characters written or -1 in the case of an error.
+ */
+int32_t OI_SNPrintf(OI_CHAR* buffer, uint16_t bufLen, const OI_CHAR* format,
+ ...);
+
+/**
+ * Var-args version OI_SNPrintf
+ *
+ * @param buffer Destination buffer for the formatted string.
+ *
+ * @param bufLen The length of the destination buffer.
+ *
+ * @param format The format string
+ *
+ * @param argp Var-args list.
+ *
+ * @return Number of characters written or -1 in the case of an error.
+ */
+int32_t OI_VSNPrintf(OI_CHAR* buffer, uint16_t bufLen, const OI_CHAR* format,
+ va_list argp);
+
+/**
+ * Convert a string to an integer.
+ *
+ * @param str the string to parse
+ *
+ * @return the integer value of the string or 0 if the string could not be
+ * parsed
+ */
+OI_INT OI_atoi(const OI_CHAR* str);
+
+/**
+ * Parse a signed integer in a string.
+ *
+ * Skips leading whitespace (space and tabs only) and parses a decimal or hex
+ * string. Hex string must be prefixed by "0x". Returns pointer to first
+ * character following the integer. Returns the pointer passed in if the string
+ * does not describe an integer.
+ *
+ * @param str String to parse.
+ *
+ * @param val Pointer to receive the parsed integer value.
+ *
+ * @return A pointer to the first character following the integer or the
+ * pointer passed in.
+ */
+const OI_CHAR* OI_ScanInt(const OI_CHAR* str, int32_t* val);
+
+/**
+ * Parse an unsigned integer in a string.
+ *
+ * Skips leading whitespace (space and tabs only) and parses a decimal or hex
+ * string. Hex string must be prefixed by "0x". Returns pointer to first
+ * character following the integer. Returns the pointer passed in if the
+ * string does not describe an integer.
+ *
+ * @param str String to parse.
+ *
+ * @param val Pointer to receive the parsed unsigned integer value.
+ *
+ * @return A pointer to the first character following the unsigned
+ * integer or the pointer passed in.
+ */
+const OI_CHAR* OI_ScanUInt(const OI_CHAR* str, uint32_t* val);
+
+/**
+ * Parse a whitespace delimited substring out of a string.
+ *
+ * @param str Input string to parse.
+ * @param outStr Buffer to return the substring
+ * @param len Length of outStr
+ *
+ *
+ * @return A pointer to the first character following the substring or
+ * the pointer passed in.
+ */
+const OI_CHAR* OI_ScanStr(const OI_CHAR* str, OI_CHAR* outStr, uint16_t len);
+
+/**
+ * Parse a string for one of a set of alternative value. Skips leading
+ * whitespace (space and tabs only) and parses text matching one of the
+ * alternative strings. Returns pointer to first character following the
+ * matched text.
+ *
+ * @param str String to parse.
+ *
+ * @param alts Alternative matching strings separated by '|'
+ *
+ * @param index Pointer to receive the index of the matching alternative,
+ * return value is -1 if there is no match.
+ *
+ * @return A pointer to the first character following the matched value or
+ * the pointer passed in if there was no matching text.
+ */
+const OI_CHAR* OI_ScanAlt(const OI_CHAR* str, const OI_CHAR* alts,
+ OI_INT* index);
+
+/**
+ * Parse a string for a BD Addr. Skips leading whitespace (space and tabs only)
+ * and parses a Bluetooth device address with nibbles optionally separated by
+ * colons. Return pointet to first character following the BD Addr.
+ *
+ * @param str String to parse.
+ *
+ * @param addr Pointer to receive the Bluetooth device address
+ *
+ * @return A pointer to the first character following the BD Addr or the
+ * pointer passed in.
+ */
+const OI_CHAR* OI_ScanBdAddr(const OI_CHAR* str, OI_BD_ADDR* addr);
+
+/** Get a character from a digit integer value (0 - 9). */
+#define OI_DigitToChar(d) ((d) + '0')
+
+/**
+ * Determine Maximum and Minimum between two arguments.
+ *
+ * @param a 1st value
+ * @param b 2nd value
+ *
+ * @return the max or min value between a & b
+ */
+#define OI_MAX(a, b) (((a) < (b)) ? (b) : (a))
+#define OI_MIN(a, b) (((a) > (b)) ? (b) : (a))
+
+/**
+ * Compare two BD_ADDRs
+ * SAME_BD_ADDR - Boolean: true if they are the same address
+ */
+
+#define SAME_BD_ADDR(x, y) (0 == OI_MemCmp((x), (y), OI_BD_ADDR_BYTE_SIZE))
+
+#ifdef __cplusplus
+}
+#endif
+
+/**@}*/
+
+#endif /* _OI_UTILS_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/alloc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/alloc.c
new file mode 100755
index 0000000..db0d7f0
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/alloc.c
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+
+#include "oi_codec_sbc_private.h"
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ uint32_t* codecDataAligned,
+ uint32_t codecDataBytes,
+ uint8_t maxChannels, uint8_t pcmStride) {
+ int i;
+ size_t filterBufferCount;
+ size_t subdataSize;
+ OI_BYTE* codecData = (OI_BYTE*)codecDataAligned;
+
+ if (maxChannels < 1 || maxChannels > 2) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (pcmStride < 1 || pcmStride > maxChannels) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ common->maxChannels = maxChannels;
+ common->pcmStride = pcmStride;
+
+ /* Compute sizes needed for the memory regions, and bail if we don't have
+ * enough memory for them. */
+ subdataSize =
+ maxChannels * sizeof(common->subdata[0]) * SBC_MAX_BANDS * SBC_MAX_BLOCKS;
+ if (subdataSize > codecDataBytes) {
+ return OI_STATUS_OUT_OF_MEMORY;
+ }
+
+ filterBufferCount =
+ (codecDataBytes - subdataSize) /
+ (sizeof(common->filterBuffer[0][0]) * SBC_MAX_BANDS * maxChannels);
+ if (filterBufferCount < SBC_CODEC_MIN_FILTER_BUFFERS) {
+ return OI_STATUS_OUT_OF_MEMORY;
+ }
+ common->filterBufferLen = filterBufferCount * SBC_MAX_BANDS;
+
+ /* Allocate memory for the subband data */
+ common->subdata = (int32_t*)codecData;
+ codecData += subdataSize;
+ OI_ASSERT(codecDataBytes >= subdataSize);
+ codecDataBytes -= subdataSize;
+
+ /* Allocate memory for the synthesis buffers */
+ for (i = 0; i < maxChannels; ++i) {
+ size_t allocSize =
+ common->filterBufferLen * sizeof(common->filterBuffer[0][0]);
+ common->filterBuffer[i] = (SBC_BUFFER_T*)codecData;
+ OI_ASSERT(codecDataBytes >= allocSize);
+ codecData += allocSize;
+ codecDataBytes -= allocSize;
+ }
+
+ return OI_OK;
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c
new file mode 100755
index 0000000..3e7e6f4
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc-sbc.c
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+#include <oi_codec_sbc_private.h>
+
+static void dualBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ OI_UINT bitcountL;
+ OI_UINT bitcountR;
+ OI_UINT bitpoolPreferenceL = 0;
+ OI_UINT bitpoolPreferenceR = 0;
+ BITNEED_UNION1 bitneedsL;
+ BITNEED_UNION1 bitneedsR;
+
+ bitcountL = computeBitneed(common, bitneedsL.uint8, 0, &bitpoolPreferenceL);
+ bitcountR = computeBitneed(common, bitneedsR.uint8, 1, &bitpoolPreferenceR);
+
+ oneChannelBitAllocation(common, &bitneedsL, 0, bitcountL);
+ oneChannelBitAllocation(common, &bitneedsR, 1, bitcountR);
+}
+
+static void stereoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+ BITNEED_UNION2 bitneeds;
+ OI_UINT excess;
+ OI_INT bitadjust;
+ OI_UINT bitcount;
+ OI_UINT sbL;
+ OI_UINT sbR;
+ OI_UINT bitpoolPreference = 0;
+
+ bitcount = computeBitneed(common, &bitneeds.uint8[0], 0, &bitpoolPreference);
+ bitcount += computeBitneed(common, &bitneeds.uint8[nrof_subbands], 1,
+ &bitpoolPreference);
+
+ {
+ OI_UINT ex;
+ bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds.uint32,
+ 2 * nrof_subbands, bitcount, &ex);
+ /* We want the compiler to put excess into a register */
+ excess = ex;
+ }
+ sbL = 0;
+ sbR = nrof_subbands;
+ while (sbL < nrof_subbands) {
+ excess = allocAdjustedBits(&common->bits.uint8[sbL],
+ bitneeds.uint8[sbL] + bitadjust, excess);
+ ++sbL;
+ excess = allocAdjustedBits(&common->bits.uint8[sbR],
+ bitneeds.uint8[sbR] + bitadjust, excess);
+ ++sbR;
+ }
+ sbL = 0;
+ sbR = nrof_subbands;
+ while (excess) {
+ excess = allocExcessBits(&common->bits.uint8[sbL], excess);
+ ++sbL;
+ if (!excess) {
+ break;
+ }
+ excess = allocExcessBits(&common->bits.uint8[sbR], excess);
+ ++sbR;
+ }
+}
+
+static const BIT_ALLOC balloc[] = {
+ monoBitAllocation, /* SBC_MONO */
+ dualBitAllocation, /* SBC_DUAL_CHANNEL */
+ stereoBitAllocation, /* SBC_STEREO */
+ stereoBitAllocation /* SBC_JOINT_STEREO */
+};
+
+PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ OI_ASSERT(common->frameInfo.bitpool <= OI_SBC_MaxBitpool(&common->frameInfo));
+ OI_ASSERT(common->frameInfo.mode < OI_ARRAYSIZE(balloc));
+
+ /*
+ * Using an array of function pointers prevents the compiler from creating a
+ * suboptimal
+ * monolithic inlined bit allocation function.
+ */
+ balloc[common->frameInfo.mode](common);
+}
+
+uint32_t OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO* frame) {
+ return internal_CalculateBitrate(frame);
+}
+
+/*
+ * Return the current maximum bitneed and clear it.
+ */
+uint8_t OI_CODEC_SBC_GetMaxBitneed(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ uint8_t max = common->maxBitneed;
+
+ common->maxBitneed = 0;
+ return max;
+}
+
+/*
+ * Calculates the bitpool size for a given frame length
+ */
+uint16_t OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO* frame,
+ uint16_t frameLen) {
+ uint16_t nrof_subbands = frame->nrof_subbands;
+ uint16_t nrof_blocks = frame->nrof_blocks;
+ uint16_t hdr;
+ uint16_t bits;
+
+ if (frame->mode == SBC_JOINT_STEREO) {
+ hdr = 9 * nrof_subbands;
+ } else {
+ if (frame->mode == SBC_MONO) {
+ hdr = 4 * nrof_subbands;
+ } else {
+ hdr = 8 * nrof_subbands;
+ }
+ if (frame->mode == SBC_DUAL_CHANNEL) {
+ nrof_blocks *= 2;
+ }
+ }
+ bits = 8 * (frameLen - SBC_HEADER_LEN) - hdr;
+ return DIVIDE(bits, nrof_blocks);
+}
+
+uint16_t OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ return sizeof(int16_t) * common->pcmStride * common->frameInfo.nrof_subbands *
+ common->frameInfo.nrof_blocks;
+}
+
+uint16_t OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO* frame) {
+ return internal_CalculateFramelen(frame);
+}
+
+/**@}*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc.c
new file mode 100755
index 0000000..75e914a
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitalloc.c
@@ -0,0 +1,379 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+
+The functions in this file relate to the allocation of available bits to
+subbands within the SBC/eSBC frame, along with support functions for computing
+frame length and bitrate.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include <oi_codec_sbc_private.h>
+#include "oi_utils.h"
+
+uint32_t OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO* frame) {
+ switch (frame->mode) {
+ case SBC_MONO:
+ case SBC_DUAL_CHANNEL:
+ return 16 * frame->nrof_subbands;
+ case SBC_STEREO:
+ case SBC_JOINT_STEREO:
+ return 32 * frame->nrof_subbands;
+ }
+
+ ERROR(("Invalid frame mode %d", frame->mode));
+ OI_ASSERT(false);
+ return 0; /* Should never be reached */
+}
+
+PRIVATE uint16_t internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO* frame) {
+ uint16_t nbits = frame->nrof_blocks * frame->bitpool;
+ uint16_t nrof_subbands = frame->nrof_subbands;
+ uint16_t result = nbits;
+
+ if (frame->mode == SBC_JOINT_STEREO) {
+ result += nrof_subbands + (8 * nrof_subbands);
+ } else {
+ if (frame->mode == SBC_DUAL_CHANNEL) {
+ result += nbits;
+ }
+ if (frame->mode == SBC_MONO) {
+ result += 4 * nrof_subbands;
+ } else {
+ result += 8 * nrof_subbands;
+ }
+ }
+ return SBC_HEADER_LEN + (result + 7) / 8;
+}
+
+PRIVATE uint32_t internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO* frame) {
+ OI_UINT blocksbands;
+ blocksbands = frame->nrof_subbands * frame->nrof_blocks;
+
+ return DIVIDE(8 * internal_CalculateFramelen(frame) * frame->frequency,
+ blocksbands);
+}
+
+INLINE uint16_t OI_SBC_CalculateFrameAndHeaderlen(
+ OI_CODEC_SBC_FRAME_INFO* frame, OI_UINT* headerLen_) {
+ OI_UINT headerLen =
+ SBC_HEADER_LEN + frame->nrof_subbands * frame->nrof_channels / 2;
+
+ if (frame->mode == SBC_JOINT_STEREO) {
+ headerLen++;
+ }
+
+ *headerLen_ = headerLen;
+ return internal_CalculateFramelen(frame);
+}
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+/*
+ * Computes the bit need for each sample and as also returns a counts of bit
+ * needs that are greater than one. This count is used in the first phase of bit
+ * allocation.
+ *
+ * We also compute a preferred bitpool value that this is the minimum bitpool
+ * needed to guarantee lossless representation of the audio data. The preferred
+ * bitpool may be larger than the bits actually required but the only input we
+ * have are the scale factors. For example, it takes 2 bits to represent values
+ * in the range -1 .. +1 but the scale factor is 0. To guarantee lossless
+ * representation we add 2 to each scale factor and sum them to come up with the
+ * preferred bitpool. This is not ideal because 0 requires 0 bits but we
+ * currently have no way of knowing this.
+ *
+ * @param bitneed Array to return bitneeds for each subband
+ *
+ * @param ch Channel 0 or 1
+ *
+ * @param preferredBitpool Returns the number of reserved bits
+ *
+ * @return The SBC bit need
+ *
+ */
+OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT* common, uint8_t* bitneeds,
+ OI_UINT ch, OI_UINT* preferredBitpool) {
+ static const int8_t offset4[4][4] = {
+ {-1, 0, 0, 0}, {-2, 0, 0, 1}, {-2, 0, 0, 1}, {-2, 0, 0, 1}};
+
+ static const int8_t offset8[4][8] = {{-2, 0, 0, 0, 0, 0, 0, 1},
+ {-3, 0, 0, 0, 0, 0, 1, 2},
+ {-4, 0, 0, 0, 0, 0, 1, 2},
+ {-4, 0, 0, 0, 0, 0, 1, 2}};
+
+ const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+ OI_UINT sb;
+ int8_t* scale_factor = &common->scale_factor[ch ? nrof_subbands : 0];
+ OI_UINT bitcount = 0;
+ uint8_t maxBits = 0;
+ uint8_t prefBits = 0;
+
+ if (common->frameInfo.alloc == SBC_SNR) {
+ for (sb = 0; sb < nrof_subbands; sb++) {
+ OI_INT bits = scale_factor[sb];
+ if (bits > maxBits) {
+ maxBits = bits;
+ }
+ bitneeds[sb] = bits;
+ if (bitneeds[sb] > 1) {
+ bitcount += bits;
+ }
+ prefBits += 2 + bits;
+ }
+ } else {
+ const int8_t* offset;
+ if (nrof_subbands == 4) {
+ offset = offset4[common->frameInfo.freqIndex];
+ } else {
+ offset = offset8[common->frameInfo.freqIndex];
+ }
+ for (sb = 0; sb < nrof_subbands; sb++) {
+ OI_INT bits = scale_factor[sb];
+ if (bits > maxBits) {
+ maxBits = bits;
+ }
+ prefBits += 2 + bits;
+ if (bits) {
+ bits -= offset[sb];
+ if (bits > 0) {
+ bits /= 2;
+ }
+ bits += 5;
+ }
+ bitneeds[sb] = bits;
+ if (bitneeds[sb] > 1) {
+ bitcount += bits;
+ }
+ }
+ }
+ common->maxBitneed = OI_MAX(maxBits, common->maxBitneed);
+ *preferredBitpool += prefBits;
+ return bitcount;
+}
+
+/*
+ * Explanation of the adjustToFitBitpool inner loop.
+ *
+ * The inner loop computes the effect of adjusting the bit allocation up or
+ * down. Allocations must be 0 or in the range 2..16. This is accomplished by
+ * the following code:
+ *
+ * for (s = bands - 1; s >= 0; --s) {
+ * OI_INT bits = bitadjust + bitneeds[s];
+ * bits = bits < 2 ? 0 : bits;
+ * bits = bits > 16 ? 16 : bits;
+ * count += bits;
+ * }
+ *
+ * This loop can be optimized to perform 4 operations at a time as follows:
+ *
+ * Adjustment is computed as a 7 bit signed value and added to the bitneed.
+ *
+ * Negative allocations are zeroed by masking. (n & 0x40) >> 6 puts the
+ * sign bit into bit 0, adding this to 0x7F give us a mask of 0x80
+ * for -ve values and 0x7F for +ve values.
+ *
+ * n &= 0x7F + (n & 0x40) >> 6)
+ *
+ * Allocations greater than 16 are truncated to 16. Adjusted allocations are in
+ * the range 0..31 so we know that bit 4 indicates values >= 16. We use this bit
+ * to create a mask that zeroes bits 0 .. 3 if bit 4 is set.
+ *
+ * n &= (15 + (n >> 4))
+ *
+ * Allocations of 1 are disallowed. Add and shift creates a mask that
+ * eliminates the illegal value
+ *
+ * n &= ((n + 14) >> 4) | 0x1E
+ *
+ * These operations can be performed in 8 bits without overflowing so we can
+ * operate on 4 values at once.
+ */
+
+/*
+ * Encoder/Decoder
+ *
+ * Computes adjustment +/- of bitneeds to fill bitpool and returns overall
+ * adjustment and excess bits.
+ *
+ * @param bitpool The bitpool we have to work within
+ *
+ * @param bitneeds An array of bit needs (more acturately allocation
+ * prioritities) for each subband across all blocks in the SBC
+ * frame
+ *
+ * @param subbands The number of subbands over which the adkustment is
+ * calculated. For mono and dual mode this is 4 or 8, for
+ * stereo or joint stereo this is 8 or 16.
+ *
+ * @param bitcount A starting point for the adjustment
+ *
+ * @param excess Returns the excess bits after the adjustment
+ *
+ * @return The adjustment.
+ */
+OI_INT adjustToFitBitpool(const OI_UINT bitpool, uint32_t* bitneeds,
+ const OI_UINT subbands, OI_UINT bitcount,
+ OI_UINT* excess) {
+ OI_INT maxBitadjust = 0;
+ OI_INT bitadjust = (bitcount > bitpool) ? -8 : 8;
+ OI_INT chop = 8;
+
+ /*
+ * This is essentially a binary search for the optimal adjustment value.
+ */
+ while ((bitcount != bitpool) && chop) {
+ uint32_t total = 0;
+ OI_UINT count;
+ uint32_t adjust4;
+ OI_INT i;
+
+ adjust4 = bitadjust & 0x7F;
+ adjust4 |= (adjust4 << 8);
+ adjust4 |= (adjust4 << 16);
+
+ for (i = (subbands / 4 - 1); i >= 0; --i) {
+ uint32_t mask;
+ uint32_t n = bitneeds[i] + adjust4;
+ mask = 0x7F7F7F7F + ((n & 0x40404040) >> 6);
+ n &= mask;
+ mask = 0x0F0F0F0F + ((n & 0x10101010) >> 4);
+ n &= mask;
+ mask = (((n + 0x0E0E0E0E) >> 4) | 0x1E1E1E1E);
+ n &= mask;
+ total += n;
+ }
+
+ count = (total & 0xFFFF) + (total >> 16);
+ count = (count & 0xFF) + (count >> 8);
+
+ chop >>= 1;
+ if (count > bitpool) {
+ bitadjust -= chop;
+ } else {
+ maxBitadjust = bitadjust;
+ bitcount = count;
+ bitadjust += chop;
+ }
+ }
+
+ *excess = bitpool - bitcount;
+
+ return maxBitadjust;
+}
+
+/*
+ * The bit allocator trys to avoid single bit allocations except as a last
+ * resort. So in the case where a bitneed of 1 was passed over during the
+ * adsjustment phase 2 bits are now allocated.
+ */
+INLINE OI_INT allocAdjustedBits(uint8_t* dest, OI_INT bits, OI_INT excess) {
+ if (bits < 16) {
+ if (bits > 1) {
+ if (excess) {
+ ++bits;
+ --excess;
+ }
+ } else if ((bits == 1) && (excess > 1)) {
+ bits = 2;
+ excess -= 2;
+ } else {
+ bits = 0;
+ }
+ } else {
+ bits = 16;
+ }
+ *dest = (uint8_t)bits;
+ return excess;
+}
+
+/*
+ * Excess bits not allocated by allocaAdjustedBits are allocated round-robin.
+ */
+INLINE OI_INT allocExcessBits(uint8_t* dest, OI_INT excess) {
+ if (*dest < 16) {
+ *dest += 1;
+ return excess - 1;
+ } else {
+ return excess;
+ }
+}
+
+void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ BITNEED_UNION1* bitneeds, OI_UINT ch,
+ OI_UINT bitcount) {
+ const uint8_t nrof_subbands = common->frameInfo.nrof_subbands;
+ OI_UINT excess;
+ OI_UINT sb;
+ OI_INT bitadjust;
+ uint8_t RESTRICT* allocBits;
+
+ {
+ OI_UINT ex;
+ bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds->uint32,
+ nrof_subbands, bitcount, &ex);
+ /* We want the compiler to put excess into a register */
+ excess = ex;
+ }
+
+ /*
+ * Allocate adjusted bits
+ */
+ allocBits = &common->bits.uint8[ch ? nrof_subbands : 0];
+
+ sb = 0;
+ while (sb < nrof_subbands) {
+ excess = allocAdjustedBits(&allocBits[sb], bitneeds->uint8[sb] + bitadjust,
+ excess);
+ ++sb;
+ }
+ sb = 0;
+ while (excess) {
+ excess = allocExcessBits(&allocBits[sb], excess);
+ ++sb;
+ }
+}
+
+void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common) {
+ BITNEED_UNION1 bitneeds;
+ OI_UINT bitcount;
+ OI_UINT bitpoolPreference = 0;
+
+ bitcount = computeBitneed(common, bitneeds.uint8, 0, &bitpoolPreference);
+
+ oneChannelBitAllocation(common, &bitneeds, 0, bitcount);
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitstream-decode.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitstream-decode.c
new file mode 100755
index 0000000..5c8b664
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/bitstream-decode.c
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+Functions for manipulating input bitstreams.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_assert.h"
+#include "oi_bitstream.h"
+#include "oi_stddefs.h"
+
+PRIVATE void OI_BITSTREAM_ReadInit(OI_BITSTREAM* bs, const OI_BYTE* buffer) {
+ bs->value =
+ ((int32_t)buffer[0] << 16) | ((int32_t)buffer[1] << 8) | (buffer[2]);
+ bs->ptr.r = buffer + 3;
+ bs->bitPtr = 8;
+}
+
+PRIVATE uint32_t OI_BITSTREAM_ReadUINT(OI_BITSTREAM* bs, OI_UINT bits) {
+ uint32_t result;
+
+ OI_BITSTREAM_READUINT(result, bits, bs->ptr.r, bs->value, bs->bitPtr);
+
+ return result;
+}
+
+PRIVATE uint8_t OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM* bs) {
+ uint32_t result;
+
+ OI_ASSERT(bs->bitPtr < 16);
+ OI_ASSERT(bs->bitPtr % 4 == 0);
+
+ if (bs->bitPtr == 8) {
+ result = bs->value << 8;
+ bs->bitPtr = 12;
+ } else {
+ result = bs->value << 12;
+ bs->value = (bs->value << 8) | *bs->ptr.r++;
+ bs->bitPtr = 8;
+ }
+ result >>= 28;
+ OI_ASSERT(result < (1u << 4));
+ return (uint8_t)result;
+}
+
+PRIVATE uint8_t OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM* bs) {
+ uint32_t result;
+ OI_ASSERT(bs->bitPtr == 8);
+
+ result = bs->value >> 16;
+ bs->value = (bs->value << 8) | *bs->ptr.r++;
+
+ return (uint8_t)result;
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-oina.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-oina.c
new file mode 100755
index 0000000..5811584
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-oina.c
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2006 Open Interface North America, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+This file exposes OINA-specific interfaces to decoder functions.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include <oi_codec_sbc_private.h>
+
+OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(
+ OI_CODEC_SBC_DECODER_CONTEXT* context, OI_BOOL enhanced, uint8_t frequency,
+ uint8_t mode, uint8_t subbands, uint8_t blocks, uint8_t alloc,
+ uint8_t maxBitpool) {
+ if (frequency > SBC_FREQ_48000) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (enhanced) {
+#ifdef SBC_ENHANCED
+ if (subbands != SBC_SUBBANDS_8) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+#else
+ return OI_STATUS_INVALID_PARAMETERS;
+#endif
+ }
+
+ if (mode > SBC_JOINT_STEREO) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (subbands > SBC_SUBBANDS_8) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (blocks > SBC_BLOCKS_16) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (alloc > SBC_SNR) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+#ifdef SBC_ENHANCED
+ context->common.frameInfo.enhanced = enhanced;
+#else
+ context->common.frameInfo.enhanced = FALSE;
+#endif
+ context->common.frameInfo.freqIndex = frequency;
+ context->common.frameInfo.mode = mode;
+ context->common.frameInfo.subbands = subbands;
+ context->common.frameInfo.blocks = blocks;
+ context->common.frameInfo.alloc = alloc;
+ context->common.frameInfo.bitpool = maxBitpool;
+
+ OI_SBC_ExpandFrameFields(&context->common.frameInfo);
+
+ if (context->common.frameInfo.nrof_channels >= context->common.pcmStride) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ return OI_OK;
+}
+
+OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint8_t bitpool, const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes) {
+ return internal_DecodeRaw(context, bitpool, frameData, frameBytes, pcmData,
+ pcmBytes);
+}
+
+OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BOOL enhanced, uint8_t subbands) {
+ if (enhanced) {
+#ifdef SBC_ENHANCED
+ context->enhancedEnabled = TRUE;
+#else
+ context->enhancedEnabled = FALSE;
+#endif
+ } else {
+ context->enhancedEnabled = FALSE;
+ }
+ context->restrictSubbands = subbands;
+ context->limitFrameFormat = TRUE;
+ return OI_OK;
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-private.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-private.c
new file mode 100755
index 0000000..686dd6a
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-private.c
@@ -0,0 +1,226 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+This file drives SBC decoding.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include <stdio.h>
+#include "oi_bitstream.h"
+#include "oi_codec_sbc_private.h"
+
+OI_CHAR* const OI_Codec_Copyright =
+ "Copyright 2002-2007 Open Interface North America, Inc. All rights "
+ "reserved";
+
+INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint32_t* decoderData,
+ uint32_t decoderDataBytes,
+ OI_BYTE maxChannels, OI_BYTE pcmStride,
+ OI_BOOL enhanced) {
+ OI_UINT i;
+ OI_STATUS status;
+
+ for (i = 0; i < sizeof(*context); i++) {
+ ((char*)context)[i] = 0;
+ }
+
+#ifdef SBC_ENHANCED
+ context->enhancedEnabled = enhanced ? TRUE : FALSE;
+#else
+ context->enhancedEnabled = FALSE;
+ if (enhanced) {
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+#endif
+
+ status = OI_CODEC_SBC_Alloc(&context->common, decoderData, decoderDataBytes,
+ maxChannels, pcmStride);
+
+ if (!OI_SUCCESS(status)) {
+ return status;
+ }
+
+ context->common.codecInfo = OI_Codec_Copyright;
+ context->common.maxBitneed = 0;
+ context->limitFrameFormat = FALSE;
+ OI_SBC_ExpandFrameFields(&context->common.frameInfo);
+
+ /*PLATFORM_DECODER_RESET(context);*/
+
+ return OI_OK;
+}
+
+/**
+ * Read the SBC header up to but not including the joint stereo mask. The
+ * syncword has already been examined, and the enhanced mode flag set, by
+ * FindSyncword.
+ */
+INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ const OI_BYTE* data) {
+ OI_CODEC_SBC_FRAME_INFO* frame = &common->frameInfo;
+ uint8_t d1;
+
+ OI_ASSERT(data[0] == OI_SBC_SYNCWORD || data[0] == OI_SBC_ENHANCED_SYNCWORD);
+
+ /* Avoid filling out all these strucutures if we already remember the values
+ * from last time. Just in case we get a stream corresponding to data[1] ==
+ * 0, DecoderReset is responsible for ensuring the lookup table entries have
+ * already been populated
+ */
+ d1 = data[1];
+ if (d1 != frame->cachedInfo) {
+ frame->freqIndex = (d1 & (BIT7 | BIT6)) >> 6;
+ frame->frequency = freq_values[frame->freqIndex];
+
+ frame->blocks = (d1 & (BIT5 | BIT4)) >> 4;
+ frame->nrof_blocks = block_values[frame->blocks];
+
+ frame->mode = (d1 & (BIT3 | BIT2)) >> 2;
+ frame->nrof_channels = channel_values[frame->mode];
+
+ frame->alloc = (d1 & BIT1) >> 1;
+
+ frame->subbands = (d1 & BIT0);
+ frame->nrof_subbands = band_values[frame->subbands];
+
+ frame->cachedInfo = d1;
+ }
+ /*
+ * For decode, the bit allocator needs to know the bitpool value
+ */
+ frame->bitpool = data[2];
+ frame->crc = data[3];
+}
+
+#define LOW(x) ((x)&0xf)
+#define HIGH(x) ((x) >> 4)
+
+/*
+ * Read scalefactor values and prepare the bitstream for OI_SBC_ReadSamples
+ */
+PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT* common,
+ const OI_BYTE* b, OI_BITSTREAM* bs) {
+ OI_UINT i = common->frameInfo.nrof_subbands * common->frameInfo.nrof_channels;
+ int8_t* scale_factor = common->scale_factor;
+ OI_UINT f;
+
+ if (common->frameInfo.nrof_subbands == 8 ||
+ common->frameInfo.mode != SBC_JOINT_STEREO) {
+ if (common->frameInfo.mode == SBC_JOINT_STEREO) {
+ common->frameInfo.join = *b++;
+ } else {
+ common->frameInfo.join = 0;
+ }
+ i /= 2;
+ do {
+ *scale_factor++ = HIGH(f = *b++);
+ *scale_factor++ = LOW(f);
+ } while (--i);
+ /*
+ * In this case we know that the scale factors end on a byte boundary so all
+ * we need to do
+ * is initialize the bitstream.
+ */
+ OI_BITSTREAM_ReadInit(bs, b);
+ } else {
+ OI_ASSERT(common->frameInfo.nrof_subbands == 4 &&
+ common->frameInfo.mode == SBC_JOINT_STEREO);
+ common->frameInfo.join = HIGH(f = *b++);
+ i = (i - 1) / 2;
+ do {
+ *scale_factor++ = LOW(f);
+ *scale_factor++ = HIGH(f = *b++);
+ } while (--i);
+ *scale_factor++ = LOW(f);
+ /*
+ * In 4-subband joint stereo mode, the joint stereo information ends on a
+ * half-byte
+ * boundary, so it's necessary to use the bitstream abstraction to read it,
+ * since
+ * OI_SBC_ReadSamples will need to pick up in mid-byte.
+ */
+ OI_BITSTREAM_ReadInit(bs, b);
+ *scale_factor++ = OI_BITSTREAM_ReadUINT4Aligned(bs);
+ }
+}
+
+/** Read quantized subband samples from the input bitstream and expand them. */
+PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BITSTREAM* global_bs) {
+ OI_CODEC_SBC_COMMON_CONTEXT* common = &context->common;
+ OI_UINT nrof_blocks = common->frameInfo.nrof_blocks;
+ int32_t* RESTRICT s = common->subdata;
+ uint8_t* ptr = global_bs->ptr.w;
+ uint32_t value = global_bs->value;
+ OI_UINT bitPtr = global_bs->bitPtr;
+
+ const OI_UINT iter_count =
+ common->frameInfo.nrof_channels * common->frameInfo.nrof_subbands / 4;
+ do {
+ OI_UINT i;
+ for (i = 0; i < iter_count; ++i) {
+ uint32_t sf_by4 = ((uint32_t*)common->scale_factor)[i];
+ uint32_t bits_by4 = common->bits.uint32[i];
+ OI_UINT n;
+ for (n = 0; n < 4; ++n) {
+ int32_t dequant;
+ OI_UINT bits;
+ OI_INT sf;
+
+ if (OI_CPU_BYTE_ORDER == OI_LITTLE_ENDIAN_BYTE_ORDER) {
+ bits = bits_by4 & 0xFF;
+ bits_by4 >>= 8;
+ sf = sf_by4 & 0xFF;
+ sf_by4 >>= 8;
+ } else {
+ bits = (bits_by4 >> 24) & 0xFF;
+ bits_by4 <<= 8;
+ sf = (sf_by4 >> 24) & 0xFF;
+ sf_by4 <<= 8;
+ }
+ if (bits) {
+ uint32_t raw;
+ OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+ dequant = OI_SBC_Dequant(raw, sf, bits);
+ } else {
+ dequant = 0;
+ }
+ *s++ = dequant;
+ }
+ }
+ } while (--nrof_blocks);
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-sbc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-sbc.c
new file mode 100755
index 0000000..85c37d6
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/decoder-sbc.c
@@ -0,0 +1,479 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2006 Open Interface North America, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addtogroup codec_internal */
+/**@{*/
+
+#include "oi_bitstream.h"
+#include "oi_codec_sbc_private.h"
+
+#define SPECIALIZE_READ_SAMPLES_JOINT
+
+/**
+ * Scans through a buffer looking for a codec syncword. If the decoder has been
+ * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search
+ * for both a standard and an enhanced syncword.
+ */
+PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE** frameData,
+ uint32_t* frameBytes) {
+#ifdef SBC_ENHANCED
+ OI_BYTE search1 = OI_SBC_SYNCWORD;
+ OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD;
+#endif // SBC_ENHANCED
+
+ if (*frameBytes == 0) {
+ return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+ }
+
+#ifdef SBC_ENHANCED
+ if (context->limitFrameFormat && context->enhancedEnabled) {
+ /* If the context is restricted, only search for specified SYNCWORD */
+ search1 = search2;
+ } else if (context->enhancedEnabled == FALSE) {
+ /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/
+ search2 = search1;
+ }
+ while (*frameBytes && (**frameData != search1) && (**frameData != search2)) {
+ (*frameBytes)--;
+ (*frameData)++;
+ }
+ if (*frameBytes) {
+ /* Syncword found, *frameData points to it, and *frameBytes correctly
+ * reflects the number of bytes available to read, including the
+ * syncword. */
+ context->common.frameInfo.enhanced =
+ (**frameData == OI_SBC_ENHANCED_SYNCWORD);
+ return OI_OK;
+ } else {
+ /* No syncword was found anywhere in the provided input data.
+ * *frameData points past the end of the original input, and
+ * *frameBytes is 0. */
+ return OI_CODEC_SBC_NO_SYNCWORD;
+ }
+#else // SBC_ENHANCED
+ while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)) {
+ (*frameBytes)--;
+ (*frameData)++;
+ }
+ if (*frameBytes) {
+ /* Syncword found, *frameData points to it, and *frameBytes correctly
+ * reflects the number of bytes available to read, including the
+ * syncword. */
+ context->common.frameInfo.enhanced = FALSE;
+ return OI_OK;
+ } else {
+ /* No syncword was found anywhere in the provided input data.
+ * *frameData points past the end of the original input, and
+ * *frameBytes is 0. */
+ return OI_CODEC_SBC_NO_SYNCWORD;
+ }
+#endif // SBC_ENHANCED
+}
+
+static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE* bodyData, int16_t* pcmData,
+ uint32_t* pcmBytes, OI_BOOL allowPartial) {
+ OI_BITSTREAM bs;
+ OI_UINT frameSamples = context->common.frameInfo.nrof_blocks *
+ context->common.frameInfo.nrof_subbands;
+ OI_UINT decode_block_count;
+
+ /*
+ * Based on the header data, make sure that there is enough room to write the
+ * output samples.
+ */
+ if (*pcmBytes <
+ (sizeof(int16_t) * frameSamples * context->common.pcmStride) &&
+ !allowPartial) {
+ /* If we're not allowing partial decodes, we need room for the entire
+ * codec frame */
+ TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA"));
+ return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
+ } else if (*pcmBytes < sizeof(int16_t) *
+ context->common.frameInfo.nrof_subbands *
+ context->common.pcmStride) {
+ /* Even if we're allowing partials, we can still only decode on a frame
+ * boundary */
+ return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
+ }
+
+ if (context->bufferedBlocks == 0) {
+ TRACE(("Reading scalefactors"));
+ OI_SBC_ReadScalefactors(&context->common, bodyData, &bs);
+
+ TRACE(("Computing bit allocation"));
+ OI_SBC_ComputeBitAllocation(&context->common);
+
+ TRACE(("Reading samples"));
+ if (context->common.frameInfo.mode == SBC_JOINT_STEREO) {
+ OI_SBC_ReadSamplesJoint(context, &bs);
+ } else {
+ OI_SBC_ReadSamples(context, &bs);
+ }
+
+ context->bufferedBlocks = context->common.frameInfo.nrof_blocks;
+ }
+
+ if (allowPartial) {
+ decode_block_count = *pcmBytes / sizeof(int16_t) /
+ context->common.pcmStride /
+ context->common.frameInfo.nrof_subbands;
+
+ if (decode_block_count > context->bufferedBlocks) {
+ decode_block_count = context->bufferedBlocks;
+ }
+
+ } else {
+ decode_block_count = context->common.frameInfo.nrof_blocks;
+ }
+
+ TRACE(("Synthesizing frame"));
+ {
+ OI_UINT start_block =
+ context->common.frameInfo.nrof_blocks - context->bufferedBlocks;
+ OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count);
+ }
+
+ OI_ASSERT(context->bufferedBlocks >= decode_block_count);
+ context->bufferedBlocks -= decode_block_count;
+
+ frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands;
+
+ /*
+ * When decoding mono into a stride-2 array, copy pcm data to second channel
+ */
+ if (context->common.frameInfo.nrof_channels == 1 &&
+ context->common.pcmStride == 2) {
+ OI_UINT i;
+ for (i = 0; i < frameSamples; ++i) {
+ pcmData[2 * i + 1] = pcmData[2 * i];
+ }
+ }
+
+ /*
+ * Return number of pcm bytes generated by the decode operation.
+ */
+ *pcmBytes = frameSamples * sizeof(int16_t) * context->common.pcmStride;
+ if (context->bufferedBlocks > 0) {
+ return OI_CODEC_SBC_PARTIAL_DECODE;
+ } else {
+ return OI_OK;
+ }
+}
+
+PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint8_t bitpool, const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes) {
+ OI_STATUS status;
+ OI_UINT bodyLen;
+
+ TRACE(("+OI_CODEC_SBC_DecodeRaw"));
+
+ if (context->bufferedBlocks == 0) {
+ /*
+ * The bitallocator needs to know the bitpool value.
+ */
+ context->common.frameInfo.bitpool = bitpool;
+ /*
+ * Compute the frame length and check we have enough frame data to proceed
+ */
+ bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) -
+ SBC_HEADER_LEN;
+ if (*frameBytes < bodyLen) {
+ TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
+ return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+ }
+ } else {
+ bodyLen = 0;
+ }
+ /*
+ * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of
+ * tones.
+ */
+ status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE);
+ if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) {
+ *frameData += bodyLen;
+ *frameBytes -= bodyLen;
+ }
+ TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status));
+ return status;
+}
+
+OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ uint32_t* decoderData,
+ uint32_t decoderDataBytes,
+ uint8_t maxChannels, uint8_t pcmStride,
+ OI_BOOL enhanced) {
+ return internal_DecoderReset(context, decoderData, decoderDataBytes,
+ maxChannels, pcmStride, enhanced);
+}
+
+OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE** frameData,
+ uint32_t* frameBytes, int16_t* pcmData,
+ uint32_t* pcmBytes) {
+ OI_STATUS status;
+ OI_UINT framelen;
+ uint8_t crc;
+
+ TRACE(("+OI_CODEC_SBC_DecodeFrame"));
+
+ TRACE(("Finding syncword"));
+ status = FindSyncword(context, frameData, frameBytes);
+ if (!OI_SUCCESS(status)) {
+ return status;
+ }
+
+ /* Make sure enough data remains to read the header. */
+ if (*frameBytes < SBC_HEADER_LEN) {
+ TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA"));
+ return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+ }
+
+ TRACE(("Reading Header"));
+ OI_SBC_ReadHeader(&context->common, *frameData);
+
+ /*
+ * Some implementations load the decoder into RAM and use overlays for 4 vs 8
+ * subbands. We need
+ * to ensure that the SBC parameters for this frame are compatible with the
+ * restrictions imposed
+ * by the loaded overlays.
+ */
+ if (context->limitFrameFormat &&
+ (context->common.frameInfo.subbands != context->restrictSubbands)) {
+ ERROR(("SBC parameters incompatible with loaded overlay"));
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (context->common.frameInfo.nrof_channels > context->common.maxChannels) {
+ ERROR(
+ ("SBC parameters incompatible with number of channels specified during "
+ "reset"));
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ if (context->common.pcmStride < 1 || context->common.pcmStride > 2) {
+ ERROR(("PCM stride not set correctly during reset"));
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+
+ /*
+ * At this point a header has been read. However, it's possible that we found
+ * a false syncword,
+ * so the header data might be invalid. Make sure we have enough bytes to read
+ * in the
+ * CRC-protected header, but don't require we have the whole frame. That way,
+ * if it turns out
+ * that we're acting on bogus header data, we don't stall the decoding process
+ * by waiting for
+ * data that we don't actually need.
+ */
+ framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo);
+ if (*frameBytes < framelen) {
+ TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
+ return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+ }
+
+ TRACE(("Calculating checksum"));
+
+ crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
+ if (crc != context->common.frameInfo.crc) {
+ TRACE(("CRC Mismatch: calc=%02x read=%02x\n", crc,
+ context->common.frameInfo.crc));
+ TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH"));
+ return OI_CODEC_SBC_CHECKSUM_MISMATCH;
+ }
+
+#ifdef OI_DEBUG
+ /*
+ * Make sure the bitpool values are sane.
+ */
+ if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) &&
+ !context->common.frameInfo.enhanced) {
+ ERROR(("Bitpool too small: %d (must be >= 2)",
+ context->common.frameInfo.bitpool));
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+ if (context->common.frameInfo.bitpool >
+ OI_SBC_MaxBitpool(&context->common.frameInfo)) {
+ ERROR(("Bitpool too large: %d (must be <= %ld)",
+ context->common.frameInfo.bitpool,
+ OI_SBC_MaxBitpool(&context->common.frameInfo)));
+ return OI_STATUS_INVALID_PARAMETERS;
+ }
+#endif
+
+ /*
+ * Now decode the SBC data. Partial decode is not yet implemented for an SBC
+ * stream, so pass FALSE to decode body to have it enforce the old rule that
+ * you have to decode a whole packet at a time.
+ */
+ status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes,
+ FALSE);
+ if (OI_SUCCESS(status)) {
+ *frameData += framelen;
+ *frameBytes -= framelen;
+ }
+ TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status));
+
+ return status;
+}
+
+OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ const OI_BYTE** frameData,
+ uint32_t* frameBytes) {
+ OI_STATUS status;
+ OI_UINT framelen;
+ OI_UINT headerlen;
+ uint8_t crc;
+
+ status = FindSyncword(context, frameData, frameBytes);
+ if (!OI_SUCCESS(status)) {
+ return status;
+ }
+ if (*frameBytes < SBC_HEADER_LEN) {
+ return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+ }
+ OI_SBC_ReadHeader(&context->common, *frameData);
+ framelen =
+ OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen);
+ if (*frameBytes < headerlen) {
+ return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
+ }
+ crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
+ if (crc != context->common.frameInfo.crc) {
+ return OI_CODEC_SBC_CHECKSUM_MISMATCH;
+ }
+ if (*frameBytes < framelen) {
+ return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
+ }
+ context->bufferedBlocks = 0;
+ *frameData += framelen;
+ *frameBytes -= framelen;
+ return OI_OK;
+}
+
+uint8_t OI_CODEC_SBC_FrameCount(OI_BYTE* frameData, uint32_t frameBytes) {
+ uint8_t mode;
+ uint8_t blocks;
+ uint8_t subbands;
+ uint8_t frameCount = 0;
+ OI_UINT frameLen;
+
+ while (frameBytes) {
+ while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)) {
+ frameData++;
+ frameBytes--;
+ }
+
+ if (frameBytes < SBC_HEADER_LEN) {
+ return frameCount;
+ }
+
+ /* Extract and translate required fields from Header */
+ subbands = mode = blocks = frameData[1];
+ ;
+ mode = (mode & (BIT3 | BIT2)) >> 2;
+ blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4];
+ subbands = band_values[(subbands & BIT0)];
+
+ /* Inline logic to avoid corrupting context */
+ frameLen = blocks * frameData[2];
+ switch (mode) {
+ case SBC_JOINT_STEREO:
+ frameLen += subbands + (8 * subbands);
+ break;
+
+ case SBC_DUAL_CHANNEL:
+ frameLen *= 2;
+ /* fall through */
+
+ default:
+ if (mode == SBC_MONO) {
+ frameLen += 4 * subbands;
+ } else {
+ frameLen += 8 * subbands;
+ }
+ }
+
+ frameCount++;
+ frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8;
+ if (frameBytes > frameLen) {
+ frameBytes -= frameLen;
+ frameData += frameLen;
+ } else {
+ frameBytes = 0;
+ }
+ }
+ return frameCount;
+}
+
+/** Read quantized subband samples from the input bitstream and expand them. */
+
+#ifdef SPECIALIZE_READ_SAMPLES_JOINT
+
+PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BITSTREAM* global_bs) {
+#define NROF_SUBBANDS 4
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+}
+
+PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BITSTREAM* global_bs) {
+#define NROF_SUBBANDS 8
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+}
+
+typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BITSTREAM* global_bs);
+
+static const READ_SAMPLES SpecializedReadSamples[] = {OI_SBC_ReadSamplesJoint4,
+ OI_SBC_ReadSamplesJoint8};
+
+#endif /* SPECIALIZE_READ_SAMPLES_JOINT */
+
+PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ OI_BITSTREAM* global_bs) {
+ OI_CODEC_SBC_COMMON_CONTEXT* common = &context->common;
+ OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+#ifdef SPECIALIZE_READ_SAMPLES_JOINT
+ OI_ASSERT((nrof_subbands >> 3u) <= 1u);
+ SpecializedReadSamples[nrof_subbands >> 3](context, global_bs);
+#else
+
+#define NROF_SUBBANDS nrof_subbands
+#include "readsamplesjoint.inc"
+#undef NROF_SUBBANDS
+#endif /* SPECIALIZE_READ_SAMPLES_JOINT */
+}
+
+/**@}*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/dequant.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/dequant.c
new file mode 100755
index 0000000..5243477
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/dequant.c
@@ -0,0 +1,215 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+ @file
+
+ Dequantizer for SBC decoder; reconstructs quantized representation of subband
+ samples.
+
+ @ingroup codec_internal
+ */
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+/**
+ This function is a fixed-point approximation of a modification of the following
+ dequantization operation defined in the spec, as inferred from section 12.6.4:
+
+ @code
+ dequant = 2^(scale_factor+1) * ((raw * 2.0 + 1.0) / ((2^bits) - 1) - 1)
+
+ 2 <= bits <= 16
+ 0 <= raw < (2^bits)-1 (the -1 is because quantized values with all 1's are
+ forbidden)
+
+ -65535 < dequant < 65535
+ @endcode
+
+ The code below computes the dequantized value divided by a scaling constant
+ equal to about 1.38. This constant is chosen to ensure that the entry in the
+ dequant_long_scaled table for 16 bits is as accurate as possible, since it has
+ the least relative precision available to it due to its small magnitude.
+
+ This routine outputs in Q16.15 format.
+
+ The helper array dequant_long is defined as follows:
+
+ @code
+ dequant_long_long[bits] = round(2^31 * 1/((2^bits - 1) / 1.38...) for 2 <=
+ bits <= 16
+ @endcode
+
+
+ Additionally, the table entries have the following property:
+
+ @code
+ dequant_long_scaled[bits] <= 2^31 / ((2^bits - 1)) for 2 <= bits <= 16
+ @endcode
+
+ Therefore
+
+ @code
+ d = 2 * raw + 1 1 <= d <= 2^bits - 2
+
+ d' = d * dequant_long[bits]
+
+ d * dequant_long_scaled[bits] <= (2^bits - 2) * (2^31 /
+ (2^bits - 1))
+ d * dequant_long_scaled[bits] <= 2^31 * (2^bits - 2)/(2^bits -
+ 1) < 2^31
+ @endcode
+
+ Therefore, d' doesn't overflow a signed 32-bit value.
+
+ @code
+
+ d' =~ 2^31 * (raw * 2.0 + 1.0) / (2^bits - 1) / 1.38...
+
+ result = d' - 2^31/1.38... =~ 2^31 * ((raw * 2.0 + 1.0) / (2^bits - 1) - 1) /
+ 1.38...
+
+ result is therefore a scaled approximation to dequant. It remains only to
+ turn 2^31 into 2^(scale_factor+1). Since we're aiming for Q16.15 format,
+ this is achieved by shifting right by (15-scale_factor):
+
+ (2^31 * x) >> (15-scale_factor) =~ 2^(31-15+scale_factor) * x = 2^15 *
+ 2^(1+scale_factor) * x
+ @endcode
+
+ */
+
+#include <oi_codec_sbc_private.h>
+
+#ifndef SBC_DEQUANT_LONG_SCALED_OFFSET
+#define SBC_DEQUANT_LONG_SCALED_OFFSET 1555931970
+#endif
+
+#ifndef SBC_DEQUANT_LONG_UNSCALED_OFFSET
+#define SBC_DEQUANT_LONG_UNSCALED_OFFSET 2147483648
+#endif
+
+#ifndef SBC_DEQUANT_SCALING_FACTOR
+#define SBC_DEQUANT_SCALING_FACTOR 1.38019122262781f
+#endif
+
+const uint32_t dequant_long_scaled[17];
+const uint32_t dequant_long_unscaled[17];
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 << ((y)-1))) >> (y))
+#endif
+
+#ifdef DEBUG_DEQUANTIZATION
+
+#include <math.h>
+
+INLINE float dequant_float(uint32_t raw, OI_UINT scale_factor, OI_UINT bits) {
+ float result = (1 << (scale_factor + 1)) *
+ ((raw * 2.0f + 1.0f) / ((1 << bits) - 1.0f) - 1.0f);
+
+ result /= SBC_DEQUANT_SCALING_FACTOR;
+
+ /* Unless the encoder screwed up, all correct dequantized values should
+ * satisfy this inequality. Non-compliant encoders which generate quantized
+ * values with all 1-bits set can, theoretically, trigger this assert. This
+ * is unlikely, however, and only an issue in debug mode.
+ */
+ OI_ASSERT(fabs(result) < 32768 * 1.6);
+
+ return result;
+}
+
+#endif
+
+INLINE int32_t OI_SBC_Dequant(uint32_t raw, OI_UINT scale_factor,
+ OI_UINT bits) {
+ uint32_t d;
+ int32_t result;
+
+ OI_ASSERT(scale_factor <= 15);
+ OI_ASSERT(bits <= 16);
+
+ if (bits <= 1) {
+ return 0;
+ }
+
+ d = (raw * 2) + 1;
+ d *= dequant_long_scaled[bits];
+ result = d - SBC_DEQUANT_LONG_SCALED_OFFSET;
+
+#ifdef DEBUG_DEQUANTIZATION
+ {
+ int32_t integerized_float_result;
+ float float_result;
+
+ float_result = dequant_float(raw, scale_factor, bits);
+ integerized_float_result = (int32_t)floor(0.5f + float_result * (1 << 15));
+
+ /* This detects overflow */
+ OI_ASSERT(((result >= 0) && (integerized_float_result >= 0)) ||
+ ((result <= 0) && (integerized_float_result <= 0)));
+ }
+#endif
+ return result >> (15 - scale_factor);
+}
+
+/* This version of Dequant does not incorporate the scaling factor of 1.38. It
+ * is intended for use with implementations of the filterbank which are
+ * hard-coded into a DSP. Output is Q16.4 format, so that after joint stereo
+ * processing (which leaves the most significant bit equal to the sign bit if
+ * the encoder is conformant) the result will fit a 24 bit fixed point signed
+ * value.*/
+
+INLINE int32_t OI_SBC_Dequant_Unscaled(uint32_t raw, OI_UINT scale_factor,
+ OI_UINT bits) {
+ uint32_t d;
+ int32_t result;
+
+ OI_ASSERT(scale_factor <= 15);
+ OI_ASSERT(bits <= 16);
+
+ if (bits <= 1) {
+ return 0;
+ }
+ if (bits == 16) {
+ result = (raw << 16) + raw - 0x7fff7fff;
+ return SCALE(result, 24 - scale_factor);
+ }
+
+ d = (raw * 2) + 1;
+ d *= dequant_long_unscaled[bits];
+ result = d - 0x80000000;
+
+ return SCALE(result, 24 - scale_factor);
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing-sbc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing-sbc.c
new file mode 100755
index 0000000..e3b1000
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing-sbc.c
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+#include "oi_codec_sbc_private.h"
+
+const OI_CHAR* const OI_CODEC_SBC_FreqText[] = {
+ "SBC_FREQ_16000", "SBC_FREQ_32000", "SBC_FREQ_44100", "SBC_FREQ_48000"};
+const OI_CHAR* const OI_CODEC_SBC_ModeText[] = {
+ "SBC_MONO", "SBC_DUAL_CHANNEL", "SBC_STEREO", "SBC_JOINT_STEREO"};
+const OI_CHAR* const OI_CODEC_SBC_SubbandsText[] = {"SBC_SUBBANDS_4",
+ "SBC_SUBBANDS_8"};
+const OI_CHAR* const OI_CODEC_SBC_BlocksText[] = {
+ "SBC_BLOCKS_4", "SBC_BLOCKS_8", "SBC_BLOCKS_12", "SBC_BLOCKS_16"};
+const OI_CHAR* const OI_CODEC_SBC_AllocText[] = {"SBC_LOUDNESS", "SBC_SNR"};
+
+#ifdef OI_DEBUG
+void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO* frameInfo) {
+ printf("SBC configuration\n");
+ printf(" enhanced: %s\n", frameInfo->enhanced ? "true" : "false");
+ printf(" frequency: %d\n", frameInfo->frequency);
+ printf(" subbands: %d\n", frameInfo->nrof_subbands);
+ printf(" blocks: %d\n", frameInfo->nrof_blocks);
+ printf(" channels: %d\n", frameInfo->nrof_channels);
+ printf(" mode: %s\n", OI_CODEC_SBC_ModeText[frameInfo->mode]);
+ printf(" alloc: %s\n", OI_CODEC_SBC_AllocText[frameInfo->alloc]);
+ printf(" bitpool: %d\n", frameInfo->bitpool);
+}
+#endif /* OI_DEBUG */
+
+/**@}*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing.c
new file mode 100755
index 0000000..f6f762c
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/framing.c
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/**
+@file
+Checksum and header-related functions.
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_assert.h"
+#include "oi_codec_sbc_private.h"
+
+/* asdasd */
+
+#define USE_NIBBLEWISE_CRC
+
+/* #define PRINT_SAMPLES */
+/* #define PRINT_SCALEFACTORS */
+/* #define DEBUG_CRC */
+
+/*
+ * CRC-8 table for X^8 + X^4 + X^3 + X^2 + 1; byte-wise lookup
+ */
+#ifdef USE_WIDE_CRC
+/* Save space if a char is 16 bits, such as on the C54x */
+const OI_BYTE crc8_wide[128] = {
+ 0x001d, 0x3a27, 0x7469, 0x4e53, 0xe8f5, 0xd2cf, 0x9c81, 0xa6bb, 0xcdd0,
+ 0xf7ea, 0xb9a4, 0x839e, 0x2538, 0x1f02, 0x514c, 0x6b76, 0x879a, 0xbda0,
+ 0xf3ee, 0xc9d4, 0x6f72, 0x5548, 0x1b06, 0x213c, 0x4a57, 0x706d, 0x3e23,
+ 0x0419, 0xa2bf, 0x9885, 0xd6cb, 0xecf1, 0x130e, 0x2934, 0x677a, 0x5d40,
+ 0xfbe6, 0xc1dc, 0x8f92, 0xb5a8, 0xdec3, 0xe4f9, 0xaab7, 0x908d, 0x362b,
+ 0x0c11, 0x425f, 0x7865, 0x9489, 0xaeb3, 0xe0fd, 0xdac7, 0x7c61, 0x465b,
+ 0x0815, 0x322f, 0x5944, 0x637e, 0x2d30, 0x170a, 0xb1ac, 0x8b96, 0xc5d8,
+ 0xffe2, 0x263b, 0x1c01, 0x524f, 0x6875, 0xced3, 0xf4e9, 0xbaa7, 0x809d,
+ 0xebf6, 0xd1cc, 0x9f82, 0xa5b8, 0x031e, 0x3924, 0x776a, 0x4d50, 0xa1bc,
+ 0x9b86, 0xd5c8, 0xeff2, 0x4954, 0x736e, 0x3d20, 0x071a, 0x6c71, 0x564b,
+ 0x1805, 0x223f, 0x8499, 0xbea3, 0xf0ed, 0xcad7, 0x3528, 0x0f12, 0x415c,
+ 0x7b66, 0xddc0, 0xe7fa, 0xa9b4, 0x938e, 0xf8e5, 0xc2df, 0x8c91, 0xb6ab,
+ 0x100d, 0x2a37, 0x6479, 0x5e43, 0xb2af, 0x8895, 0xc6db, 0xfce1, 0x5a47,
+ 0x607d, 0x2e33, 0x1409, 0x7f62, 0x4558, 0x0b16, 0x312c, 0x978a, 0xadb0,
+ 0xe3fe, 0xd9c4,
+};
+#elif defined(USE_NIBBLEWISE_CRC)
+const OI_BYTE crc8_narrow[16] = {0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69,
+ 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf,
+ 0x9c, 0x81, 0xa6, 0xbb};
+#else
+const OI_BYTE crc8_narrow[256] = {
+ 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf,
+ 0x9c, 0x81, 0xa6, 0xbb, 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e,
+ 0x25, 0x38, 0x1f, 0x02, 0x51, 0x4c, 0x6b, 0x76, 0x87, 0x9a, 0xbd, 0xa0,
+ 0xf3, 0xee, 0xc9, 0xd4, 0x6f, 0x72, 0x55, 0x48, 0x1b, 0x06, 0x21, 0x3c,
+ 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x04, 0x19, 0xa2, 0xbf, 0x98, 0x85,
+ 0xd6, 0xcb, 0xec, 0xf1, 0x13, 0x0e, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40,
+ 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, 0xde, 0xc3, 0xe4, 0xf9,
+ 0xaa, 0xb7, 0x90, 0x8d, 0x36, 0x2b, 0x0c, 0x11, 0x42, 0x5f, 0x78, 0x65,
+ 0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, 0x7c, 0x61, 0x46, 0x5b,
+ 0x08, 0x15, 0x32, 0x2f, 0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0x0a,
+ 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2, 0x26, 0x3b, 0x1c, 0x01,
+ 0x52, 0x4f, 0x68, 0x75, 0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d,
+ 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, 0x03, 0x1e, 0x39, 0x24,
+ 0x77, 0x6a, 0x4d, 0x50, 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2,
+ 0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x07, 0x1a, 0x6c, 0x71, 0x56, 0x4b,
+ 0x18, 0x05, 0x22, 0x3f, 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7,
+ 0x35, 0x28, 0x0f, 0x12, 0x41, 0x5c, 0x7b, 0x66, 0xdd, 0xc0, 0xe7, 0xfa,
+ 0xa9, 0xb4, 0x93, 0x8e, 0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab,
+ 0x10, 0x0d, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43, 0xb2, 0xaf, 0x88, 0x95,
+ 0xc6, 0xdb, 0xfc, 0xe1, 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x09,
+ 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0,
+ 0xe3, 0xfe, 0xd9, 0xc4};
+#endif
+const uint32_t dequant_long_scaled[17] = {
+ 0, 0,
+ 0x1ee9e116, /* bits=2 0.24151243 1/3 * (1/1.38019122262781)
+ (0x00000008)*/
+ 0x0d3fa99c, /* bits=3 0.10350533 1/7 * (1/1.38019122262781)
+ (0x00000013)*/
+ 0x062ec69e, /* bits=4 0.04830249 1/15 * (1/1.38019122262781)
+ (0x00000029)*/
+ 0x02fddbfa, /* bits=5 0.02337217 1/31 * (1/1.38019122262781)
+ (0x00000055)*/
+ 0x0178d9f5, /* bits=6 0.01150059 1/63 * (1/1.38019122262781)
+ (0x000000ad)*/
+ 0x00baf129, /* bits=7 0.00570502 1/127 * (1/1.38019122262781)
+ (0x0000015e)*/
+ 0x005d1abe, /* bits=8 0.00284132 1/255 * (1/1.38019122262781)
+ (0x000002bf)*/
+ 0x002e760d, /* bits=9 0.00141788 1/511 * (1/1.38019122262781)
+ (0x00000582)*/
+ 0x00173536, /* bits=10 0.00070825 1/1023 * (1/1.38019122262781)
+ (0x00000b07)*/
+ 0x000b9928, /* bits=11 0.00035395 1/2047 * (1/1.38019122262781)
+ (0x00001612)*/
+ 0x0005cc37, /* bits=12 0.00017693 1/4095 * (1/1.38019122262781)
+ (0x00002c27)*/
+ 0x0002e604, /* bits=13 0.00008846 1/8191 * (1/1.38019122262781)
+ (0x00005852)*/
+ 0x000172fc, /* bits=14 0.00004422 1/16383 * (1/1.38019122262781)
+ (0x0000b0a7)*/
+ 0x0000b97d, /* bits=15 0.00002211 1/32767 * (1/1.38019122262781)
+ (0x00016150)*/
+ 0x00005cbe, /* bits=16 0.00001106 1/65535 * (1/1.38019122262781)
+ (0x0002c2a5)*/
+};
+
+const uint32_t dequant_long_unscaled[17] = {
+ 0, 0, 0x2aaaaaab, /* bits=2 0.33333333 1/3 (0x00000005)*/
+ 0x12492492, /* bits=3 0.14285714 1/7 (0x0000000e)*/
+ 0x08888889, /* bits=4 0.06666667 1/15 (0x0000001d)*/
+ 0x04210842, /* bits=5 0.03225806 1/31 (0x0000003e)*/
+ 0x02082082, /* bits=6 0.01587302 1/63 (0x0000007e)*/
+ 0x01020408, /* bits=7 0.00787402 1/127 (0x000000fe)*/
+ 0x00808081, /* bits=8 0.00392157 1/255 (0x000001fd)*/
+ 0x00402010, /* bits=9 0.00195695 1/511 (0x000003fe)*/
+ 0x00200802, /* bits=10 0.00097752 1/1023 (0x000007fe)*/
+ 0x00100200, /* bits=11 0.00048852 1/2047 (0x00000ffe)*/
+ 0x00080080, /* bits=12 0.00024420 1/4095 (0x00001ffe)*/
+ 0x00040020, /* bits=13 0.00012209 1/8191 (0x00003ffe)*/
+ 0x00020008, /* bits=14 0.00006104 1/16383 (0x00007ffe)*/
+ 0x00010002, /* bits=15 0.00003052 1/32767 (0x0000fffe)*/
+ 0x00008001, /* bits=16 0.00001526 1/65535 (0x0001fffc)*/
+};
+
+#if defined(OI_DEBUG) || defined(PRINT_SAMPLES) || defined(PRINT_SCALEFACTORS)
+#include <stdio.h>
+#endif
+
+#ifdef USE_WIDE_CRC
+INLINE OI_CHAR crc_iterate(uint8_t oldcrc, uint8_t next) {
+ OI_UINT crc;
+ OI_UINT idx;
+ idx = oldcrc ^ next;
+ crc = crc8_wide[idx >> 1];
+ if (idx % 2) {
+ crc &= 0xff;
+ } else {
+ crc >>= 8;
+ }
+
+ return crc;
+}
+
+INLINE OI_CHAR crc_iterate_top4(uint8_t oldcrc, uint8_t next) {
+ OI_UINT crc;
+ OI_UINT idx;
+ idx = (oldcrc ^ next) >> 4;
+ crc = crc8_wide[idx >> 1];
+ if (idx % 2) {
+ crc &= 0xff;
+ } else {
+ crc >>= 8;
+ }
+
+ return (oldcrc << 4) ^ crc;
+}
+
+#else // USE_WIDE_CRC
+
+INLINE uint8_t crc_iterate_top4(uint8_t oldcrc, uint8_t next) {
+ return (oldcrc << 4) ^ crc8_narrow[(oldcrc ^ next) >> 4];
+}
+
+#ifdef USE_NIBBLEWISE_CRC
+INLINE uint8_t crc_iterate(uint8_t crc, uint8_t next) {
+ crc = (crc << 4) ^ crc8_narrow[(crc ^ next) >> 4];
+ crc = (crc << 4) ^ crc8_narrow[((crc >> 4) ^ next) & 0xf];
+
+ return crc;
+}
+
+#else // USE_NIBBLEWISE_CRC
+INLINE uint8_t crc_iterate(uint8_t crc, uint8_t next) {
+ return crc8_narrow[crc ^ next];
+}
+
+#endif // USE_NIBBLEWISE_CRC
+
+#endif // USE_WIDE_CRC
+
+PRIVATE uint8_t OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO* frame,
+ OI_BYTE const* data) {
+ OI_UINT i;
+ uint8_t crc = 0x0f;
+ /* Count is the number of whole bytes subject to CRC. Actually, it's one
+ * more than this number, because data[3] is the CRC field itself, which is
+ * explicitly skipped. Since crc_iterate (should be) inlined, it's cheaper
+ * spacewise to include the check in the loop. This shouldn't be much of a
+ * bottleneck routine in the first place. */
+ OI_UINT count = (frame->nrof_subbands * frame->nrof_channels / 2u) + 4;
+
+ if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 8) {
+ count++;
+ }
+
+ for (i = 1; i < count; i++) {
+ if (i != 3) {
+ crc = crc_iterate(crc, data[i]);
+ }
+ }
+
+ if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 4) {
+ crc = crc_iterate_top4(crc, data[i]);
+ }
+
+ return crc;
+}
+
+void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO* frame) {
+ frame->nrof_blocks = block_values[frame->blocks];
+ frame->nrof_subbands = band_values[frame->subbands];
+
+ frame->frequency = freq_values[frame->freqIndex];
+ frame->nrof_channels = channel_values[frame->mode];
+}
+
+/**
+ * Unrolled macro to copy 4 32-bit aligned 32-bit values backward in memory
+ */
+#define COPY4WORDS_BACK(_dest, _src) \
+ do { \
+ int32_t _a, _b, _c, _d; \
+ _a = *--(_src); \
+ _b = *--(_src); \
+ _c = *--(_src); \
+ _d = *--(_src); \
+ *--(_dest) = _a; \
+ *--(_dest) = _b; \
+ *--(_dest) = _c; \
+ *--(_dest) = _d; \
+ } while (0)
+
+#if defined(USE_PLATFORM_MEMMOVE) || defined(USE_PLATFORM_MEMCPY)
+#include <string.h>
+#endif
+PRIVATE void shift_buffer(SBC_BUFFER_T* dest, SBC_BUFFER_T* src,
+ OI_UINT wordCount) {
+#ifdef USE_PLATFORM_MEMMOVE
+ memmove(dest, src, wordCount * sizeof(SBC_BUFFER_T));
+#elif defined(USE_PLATFORM_MEMCPY)
+ OI_ASSERT(((OI_CHAR*)(dest) - (OI_CHAR*)(src)) >= wordCount * sizeof(*dest));
+ memcpy(dest, src, wordCount * sizeof(SBC_BUFFER_T));
+#else
+ OI_UINT n;
+ int32_t* d;
+ int32_t* s;
+ n = wordCount / 4 / (sizeof(int32_t) / sizeof(*dest));
+ OI_ASSERT((n * 4 * (sizeof(int32_t) / sizeof(*dest))) == wordCount);
+
+ d = (void*)(dest + wordCount);
+ s = (void*)(src + wordCount);
+
+ do {
+ COPY4WORDS_BACK(d, s);
+ } while (--n);
+#endif
+}
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/oi_codec_version.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/oi_codec_version.c
new file mode 100755
index 0000000..4b69183
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/oi_codec_version.c
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2002 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/**
+@file
+This file contains a single function, which returns a string indicating the
+version number of the eSBC codec
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+#include "oi_codec_sbc_private.h"
+#include "oi_stddefs.h"
+
+/** Version string for the BLUEmagic 3.0 protocol stack and profiles */
+PRIVATE OI_CHAR* const codecVersion =
+ "v1.5"
+#ifdef OI_SBC_EVAL
+ " (Evaluation version)"
+#endif
+ ;
+
+/* This function returns the version string for the BLUEmagic 3.0 protocol stack
+ and profiles */
+OI_CHAR* OI_CODEC_Version(void) { return codecVersion; }
+
+/******************************************************************************/
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc b/mtkbt/code/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc
new file mode 100755
index 0000000..79151ff
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/readsamplesjoint.inc
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ * @file readsamplesjoint.inc
+ *
+ * This is the body of the generic version of OI_SBC_ReadSamplesJoint().
+ * It is designed to be \#included into a function as follows:
+ \code
+ void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+ {
+ #define NROF_SUBBANDS 4
+ #include "readsamplesjoint.inc"
+ #undef NROF_SUBBANDS
+ }
+
+ void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+ {
+ #define NROF_SUBBANDS 8
+ #include "readsamplesjoint.inc"
+ #undef NROF_SUBBANDS
+ }
+ \endcode
+ * Or to make a generic version:
+ \code
+ void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs)
+ {
+ OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
+
+ #define NROF_SUBBANDS nrof_subbands
+ #include "readsamplesjoint.inc"
+ #undef NROF_SUBBANDS
+ }
+ \endcode
+ * @ingroup codec_internal
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+{
+ OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
+ OI_UINT bl = common->frameInfo.nrof_blocks;
+ int32_t * RESTRICT s = common->subdata;
+ uint8_t *ptr = global_bs->ptr.w;
+ uint32_t value = global_bs->value;
+ OI_UINT bitPtr = global_bs->bitPtr;
+ uint8_t jmask = common->frameInfo.join << (8 - NROF_SUBBANDS);
+
+ do {
+ int8_t *sf_array = &common->scale_factor[0];
+ uint8_t *bits_array = &common->bits.uint8[0];
+ uint8_t joint = jmask;
+ OI_UINT sb;
+ /*
+ * Left channel
+ */
+ sb = NROF_SUBBANDS;
+ do {
+ uint32_t raw;
+ int32_t dequant;
+ uint8_t bits = *bits_array++;
+ OI_INT sf = *sf_array++;
+
+ OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+ dequant = OI_SBC_Dequant(raw, sf, bits);
+ *s++ = dequant;
+ } while (--sb);
+ /*
+ * Right channel
+ */
+ sb = NROF_SUBBANDS;
+ do {
+ uint32_t raw;
+ int32_t dequant;
+ uint8_t bits = *bits_array++;
+ OI_INT sf = *sf_array++;
+
+ OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr);
+ dequant = OI_SBC_Dequant(raw, sf, bits);
+ /*
+ * Check if we need to do mid/side
+ */
+ if (joint & 0x80) {
+ int32_t mid = *(s - NROF_SUBBANDS);
+ int32_t side = dequant;
+ *(s - NROF_SUBBANDS) = mid + side;
+ dequant = mid - side;
+ }
+ joint <<= 1;
+ *s++ = dequant;
+ } while (--sb);
+ } while (--bl);
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c
new file mode 100755
index 0000000..d852c74
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-8-generated.c
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/**
+ @file
+
+ DO NOT EDIT THIS FILE DIRECTLY
+
+ This file is automatically generated by the "synthesis-gen.pl" script.
+ Any changes to this generated file will be lost when the script is re-run.
+
+ These functions are called by functions in synthesis.c to perform the synthesis
+ filterbank computations for the SBC decoder.
+
+
+ */
+
+#include <oi_codec_sbc_private.h>
+
+#ifndef CLIP_INT16
+#define CLIP_INT16(x) \
+ do { \
+ if ((x) > OI_INT16_MAX) { \
+ (x) = OI_INT16_MAX; \
+ } else if ((x) < OI_INT16_MIN) { \
+ (x) = OI_INT16_MIN; \
+ } \
+ } while (0)
+#endif
+
+#define MUL_16S_16S(_x, _y) ((_x) * (_y))
+
+PRIVATE void SynthWindow80_generated(int16_t* pcm,
+ SBC_BUFFER_T const* RESTRICT buffer,
+ OI_UINT strideShift) {
+ int32_t pcm_a, pcm_b;
+ /* 1 - stage 0 */ pcm_b = 0;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(8235, buffer[12])) >> 3;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(-23167, buffer[20])) >> 3;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(26479, buffer[28])) >> 2;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(-17397, buffer[36])) << 1;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(9399, buffer[44])) << 3;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(17397, buffer[52])) << 1;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(26479, buffer[60])) >> 2;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(23167, buffer[68])) >> 3;
+ /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(8235, buffer[76])) >> 3;
+ /* 1 - stage 0 */ pcm_b /= 32768;
+ CLIP_INT16(pcm_b);
+ pcm[0 << strideShift] = (int16_t)pcm_b;
+ /* 1 - stage 1 */ pcm_a = 0;
+ /* 1 - stage 1 */ pcm_b = 0;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-3263, buffer[5])) >> 5;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(9293, buffer[5])) >> 3;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(29293, buffer[11])) >> 5;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(-6087, buffer[11])) >> 2;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-5229, buffer[21]));
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(1247, buffer[21])) << 3;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(30835, buffer[27])) >> 3;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(-2893, buffer[27])) << 3;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-27021, buffer[37])) << 1;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(23671, buffer[37])) << 2;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(31633, buffer[43])) << 1;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(18055, buffer[43])) << 1;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(17319, buffer[53])) << 1;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(11537, buffer[53])) >> 1;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(26663, buffer[59])) >> 2;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(1747, buffer[59])) << 1;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(4555, buffer[69])) >> 1;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(685, buffer[69])) << 1;
+ /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(12419, buffer[75])) >> 4;
+ /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(8721, buffer[75])) >> 7;
+ /* 1 - stage 1 */ pcm_a /= 32768;
+ CLIP_INT16(pcm_a);
+ pcm[1 << strideShift] = (int16_t)pcm_a;
+ /* 1 - stage 1 */ pcm_b /= 32768;
+ CLIP_INT16(pcm_b);
+ pcm[7 << strideShift] = (int16_t)pcm_b;
+ /* 1 - stage 2 */ pcm_a = 0;
+ /* 1 - stage 2 */ pcm_b = 0;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-10385, buffer[6])) >> 6;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(11167, buffer[6])) >> 4;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(24995, buffer[10])) >> 5;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(-10337, buffer[10])) >> 4;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-309, buffer[22])) << 4;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(1917, buffer[22])) << 2;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(9161, buffer[26])) >> 3;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(-30605, buffer[26])) >> 1;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-23063, buffer[38])) << 1;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(8317, buffer[38])) << 3;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(27561, buffer[42])) << 1;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(9553, buffer[42])) << 2;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(2309, buffer[54])) << 3;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(22117, buffer[54])) >> 4;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(12705, buffer[58])) >> 1;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(16383, buffer[58])) >> 2;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(6239, buffer[70])) >> 3;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(7543, buffer[70])) >> 3;
+ /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(9251, buffer[74])) >> 4;
+ /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(8603, buffer[74])) >> 6;
+ /* 1 - stage 2 */ pcm_a /= 32768;
+ CLIP_INT16(pcm_a);
+ pcm[2 << strideShift] = (int16_t)pcm_a;
+ /* 1 - stage 2 */ pcm_b /= 32768;
+ CLIP_INT16(pcm_b);
+ pcm[6 << strideShift] = (int16_t)pcm_b;
+ /* 1 - stage 3 */ pcm_a = 0;
+ /* 1 - stage 3 */ pcm_b = 0;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-16457, buffer[7])) >> 6;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(16913, buffer[7])) >> 5;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(19083, buffer[9])) >> 5;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-8443, buffer[9])) >> 7;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-23641, buffer[23])) >> 2;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(3687, buffer[23])) << 1;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-29015, buffer[25])) >> 4;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-301, buffer[25])) << 5;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-12889, buffer[39])) << 2;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(15447, buffer[39])) << 2;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(6145, buffer[41])) << 3;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(10255, buffer[41])) << 2;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(24211, buffer[55])) >> 1;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-18233, buffer[55])) >> 3;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(23469, buffer[57])) >> 2;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(9405, buffer[57])) >> 1;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(21223, buffer[71])) >> 8;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(1499, buffer[71])) >> 1;
+ /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(26913, buffer[73])) >> 6;
+ /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(26189, buffer[73])) >> 7;
+ /* 1 - stage 3 */ pcm_a /= 32768;
+ CLIP_INT16(pcm_a);
+ pcm[3 << strideShift] = (int16_t)pcm_a;
+ /* 1 - stage 3 */ pcm_b /= 32768;
+ CLIP_INT16(pcm_b);
+ pcm[5 << strideShift] = (int16_t)pcm_b;
+ /* 1 - stage 4 */ pcm_a = 0;
+ /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(10445, buffer[8])) >> 4;
+ /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(-5297, buffer[24])) << 1;
+ /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(22299, buffer[40])) << 2;
+ /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(10603, buffer[56]));
+ /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(9539, buffer[72])) >> 4;
+ /* 1 - stage 4 */ pcm_a /= 32768;
+ CLIP_INT16(pcm_a);
+ pcm[4 << strideShift] = (int16_t)pcm_a;
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c
new file mode 100755
index 0000000..514c900
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-dct8.c
@@ -0,0 +1,347 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** @file
+@ingroup codec_internal
+*/
+
+/**@addgroup codec_internal*/
+/**@{*/
+
+/*
+ * Performs an 8-point Type-II scaled DCT using the Arai-Agui-Nakajima
+ * factorization. The scaling factors are folded into the windowing
+ * constants. 29 adds and 5 16x32 multiplies per 8 samples.
+ */
+
+#include "oi_codec_sbc_private.h"
+
+#define AAN_C4_FIX (759250125) /* S1.30 759250125 0.707107*/
+
+#define AAN_C6_FIX (410903207) /* S1.30 410903207 0.382683*/
+
+#define AAN_Q0_FIX (581104888) /* S1.30 581104888 0.541196*/
+
+#define AAN_Q1_FIX (1402911301) /* S1.30 1402911301 1.306563*/
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 << ((y)-1))) >> (y))
+#endif
+
+/**
+ * Default C language implementation of a 32x32->32 multiply. This function may
+ * be replaced by a platform-specific version for speed.
+ *
+ * @param u A signed 32-bit multiplicand
+ * @param v A signed 32-bit multiplier
+
+ * @return A signed 32-bit value corresponding to the 32 most significant bits
+ * of the 64-bit product of u and v.
+ */
+INLINE int32_t default_mul_32s_32s_hi(int32_t u, int32_t v) {
+ uint32_t u0, v0;
+ int32_t u1, v1, w1, w2, t;
+
+ u0 = u & 0xFFFF;
+ u1 = u >> 16;
+ v0 = v & 0xFFFF;
+ v1 = v >> 16;
+ t = u0 * v0;
+ t = u1 * v0 + ((uint32_t)t >> 16);
+ w1 = t & 0xFFFF;
+ w2 = t >> 16;
+ w1 = u0 * v1 + w1;
+ return u1 * v1 + w2 + (w1 >> 16);
+}
+
+#define MUL_32S_32S_HI(_x, _y) default_mul_32s_32s_hi(_x, _y)
+
+#ifdef DEBUG_DCT
+PRIVATE void float_dct2_8(float* RESTRICT out, int32_t const* RESTRICT in) {
+#define FIX(x, bits) \
+ (((int)floor(0.5f + ((x) * ((float)(1 << bits))))) / ((float)(1 << bits)))
+#define FLOAT_BUTTERFLY(x, y) \
+ x += y; \
+ y = x - (y * 2); \
+ OI_ASSERT(VALID_INT32(x)); \
+ OI_ASSERT(VALID_INT32(y));
+#define FLOAT_MULT_DCT(K, sample) (FIX(K, 20) * sample)
+#define FLOAT_SCALE(x, y) (((x) / (double)(1 << (y))))
+
+ double L00, L01, L02, L03, L04, L05, L06, L07;
+ double L25;
+
+ double in0, in1, in2, in3;
+ double in4, in5, in6, in7;
+
+ in0 = FLOAT_SCALE(in[0], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in0));
+ in1 = FLOAT_SCALE(in[1], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in1));
+ in2 = FLOAT_SCALE(in[2], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in2));
+ in3 = FLOAT_SCALE(in[3], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in3));
+ in4 = FLOAT_SCALE(in[4], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in4));
+ in5 = FLOAT_SCALE(in[5], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in5));
+ in6 = FLOAT_SCALE(in[6], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in6));
+ in7 = FLOAT_SCALE(in[7], DCTII_8_SHIFT_IN);
+ OI_ASSERT(VALID_INT32(in7));
+
+ L00 = (in0 + in7);
+ OI_ASSERT(VALID_INT32(L00));
+ L01 = (in1 + in6);
+ OI_ASSERT(VALID_INT32(L01));
+ L02 = (in2 + in5);
+ OI_ASSERT(VALID_INT32(L02));
+ L03 = (in3 + in4);
+ OI_ASSERT(VALID_INT32(L03));
+
+ L04 = (in3 - in4);
+ OI_ASSERT(VALID_INT32(L04));
+ L05 = (in2 - in5);
+ OI_ASSERT(VALID_INT32(L05));
+ L06 = (in1 - in6);
+ OI_ASSERT(VALID_INT32(L06));
+ L07 = (in0 - in7);
+ OI_ASSERT(VALID_INT32(L07));
+
+ FLOAT_BUTTERFLY(L00, L03);
+ FLOAT_BUTTERFLY(L01, L02);
+
+ L02 += L03;
+ OI_ASSERT(VALID_INT32(L02));
+
+ L02 = FLOAT_MULT_DCT(AAN_C4_FLOAT, L02);
+ OI_ASSERT(VALID_INT32(L02));
+
+ FLOAT_BUTTERFLY(L00, L01);
+
+ out[0] = (float)FLOAT_SCALE(L00, DCTII_8_SHIFT_0);
+ OI_ASSERT(VALID_INT16(out[0]));
+ out[4] = (float)FLOAT_SCALE(L01, DCTII_8_SHIFT_4);
+ OI_ASSERT(VALID_INT16(out[4]));
+
+ FLOAT_BUTTERFLY(L03, L02);
+ out[6] = (float)FLOAT_SCALE(L02, DCTII_8_SHIFT_6);
+ OI_ASSERT(VALID_INT16(out[6]));
+ out[2] = (float)FLOAT_SCALE(L03, DCTII_8_SHIFT_2);
+ OI_ASSERT(VALID_INT16(out[2]));
+
+ L04 += L05;
+ OI_ASSERT(VALID_INT32(L04));
+ L05 += L06;
+ OI_ASSERT(VALID_INT32(L05));
+ L06 += L07;
+ OI_ASSERT(VALID_INT32(L06));
+
+ L04 /= 2;
+ L05 /= 2;
+ L06 /= 2;
+ L07 /= 2;
+
+ L05 = FLOAT_MULT_DCT(AAN_C4_FLOAT, L05);
+ OI_ASSERT(VALID_INT32(L05));
+
+ L25 = L06 - L04;
+ OI_ASSERT(VALID_INT32(L25));
+ L25 = FLOAT_MULT_DCT(AAN_C6_FLOAT, L25);
+ OI_ASSERT(VALID_INT32(L25));
+
+ L04 = FLOAT_MULT_DCT(AAN_Q0_FLOAT, L04);
+ OI_ASSERT(VALID_INT32(L04));
+ L04 -= L25;
+ OI_ASSERT(VALID_INT32(L04));
+
+ L06 = FLOAT_MULT_DCT(AAN_Q1_FLOAT, L06);
+ OI_ASSERT(VALID_INT32(L06));
+ L06 -= L25;
+ OI_ASSERT(VALID_INT32(L25));
+
+ FLOAT_BUTTERFLY(L07, L05);
+
+ FLOAT_BUTTERFLY(L05, L04);
+ out[3] = (float)(FLOAT_SCALE(L04, DCTII_8_SHIFT_3 - 1));
+ OI_ASSERT(VALID_INT16(out[3]));
+ out[5] = (float)(FLOAT_SCALE(L05, DCTII_8_SHIFT_5 - 1));
+ OI_ASSERT(VALID_INT16(out[5]));
+
+ FLOAT_BUTTERFLY(L07, L06);
+ out[7] = (float)(FLOAT_SCALE(L06, DCTII_8_SHIFT_7 - 1));
+ OI_ASSERT(VALID_INT16(out[7]));
+ out[1] = (float)(FLOAT_SCALE(L07, DCTII_8_SHIFT_1 - 1));
+ OI_ASSERT(VALID_INT16(out[1]));
+}
+#undef BUTTERFLY
+#endif
+
+/*
+ * This function calculates the AAN DCT. Its inputs are in S16.15 format, as
+ * returned by OI_SBC_Dequant. In practice, abs(in[x]) < 52429.0 / 1.38
+ * (1244918057 integer). The function it computes is an approximation to the
+ * array defined by:
+ *
+ * diag(aan_s) * AAN= C2
+ *
+ * or
+ *
+ * AAN = diag(1/aan_s) * C2
+ *
+ * where C2 is as it is defined in the comment at the head of this file, and
+ *
+ * aan_s[i] = aan_s = 1/(2*cos(i*pi/16)) with i = 1..7, aan_s[0] = 1;
+ *
+ * aan_s[i] = [ 1.000 0.510 0.541 0.601 0.707 0.900 1.307 2.563 ]
+ *
+ * The output ranges are shown as follows:
+ *
+ * Let Y[0..7] = AAN * X[0..7]
+ *
+ * Without loss of generality, assume the input vector X consists of elements
+ * between -1 and 1. The maximum possible value of a given output element occurs
+ * with some particular combination of input vector elements each of which is -1
+ * or 1. Consider the computation of Y[i]. Y[i] = sum t=0..7 of AAN[t,i]*X[i]. Y
+ * is maximized if the sign of X[i] matches the sign of AAN[t,i], ensuring a
+ * positive contribution to the sum. Equivalently, one may simply sum
+ * abs(AAN)[t,i] over t to get the maximum possible value of Y[i].
+ *
+ * This yields approximately:
+ * [8.00 10.05 9.66 8.52 8.00 5.70 4.00 2.00]
+ *
+ * Given the maximum magnitude sensible input value of +/-37992, this yields the
+ * following vector of maximum output magnitudes:
+ *
+ * [ 303936 381820 367003 323692 303936 216555 151968 75984 ]
+ *
+ * Ultimately, these values must fit into 16 bit signed integers, so they must
+ * be scaled. A non-uniform scaling helps maximize the kept precision. The
+ * relative number of extra bits of precision maintainable with respect to the
+ * largest value is given here:
+ *
+ * [ 0 0 0 0 0 0 1 2 ]
+ *
+ */
+PRIVATE void dct2_8(SBC_BUFFER_T* RESTRICT out, int32_t const* RESTRICT in) {
+#define BUTTERFLY(x, y) \
+ x += (y); \
+ (y) = (x) - ((y) << 1);
+#define FIX_MULT_DCT(K, x) (MUL_32S_32S_HI(K, x) << 2)
+
+ int32_t L00, L01, L02, L03, L04, L05, L06, L07;
+ int32_t L25;
+
+ int32_t in0, in1, in2, in3;
+ int32_t in4, in5, in6, in7;
+
+#if DCTII_8_SHIFT_IN != 0
+ in0 = SCALE(in[0], DCTII_8_SHIFT_IN);
+ in1 = SCALE(in[1], DCTII_8_SHIFT_IN);
+ in2 = SCALE(in[2], DCTII_8_SHIFT_IN);
+ in3 = SCALE(in[3], DCTII_8_SHIFT_IN);
+ in4 = SCALE(in[4], DCTII_8_SHIFT_IN);
+ in5 = SCALE(in[5], DCTII_8_SHIFT_IN);
+ in6 = SCALE(in[6], DCTII_8_SHIFT_IN);
+ in7 = SCALE(in[7], DCTII_8_SHIFT_IN);
+#else
+ in0 = in[0];
+ in1 = in[1];
+ in2 = in[2];
+ in3 = in[3];
+ in4 = in[4];
+ in5 = in[5];
+ in6 = in[6];
+ in7 = in[7];
+#endif
+
+ L00 = in0 + in7;
+ L01 = in1 + in6;
+ L02 = in2 + in5;
+ L03 = in3 + in4;
+
+ L04 = in3 - in4;
+ L05 = in2 - in5;
+ L06 = in1 - in6;
+ L07 = in0 - in7;
+
+ BUTTERFLY(L00, L03);
+ BUTTERFLY(L01, L02);
+
+ L02 += L03;
+
+ L02 = FIX_MULT_DCT(AAN_C4_FIX, L02);
+
+ BUTTERFLY(L00, L01);
+
+ out[0] = (int16_t)SCALE(L00, DCTII_8_SHIFT_0);
+ out[4] = (int16_t)SCALE(L01, DCTII_8_SHIFT_4);
+
+ BUTTERFLY(L03, L02);
+ out[6] = (int16_t)SCALE(L02, DCTII_8_SHIFT_6);
+ out[2] = (int16_t)SCALE(L03, DCTII_8_SHIFT_2);
+
+ L04 += L05;
+ L05 += L06;
+ L06 += L07;
+
+ L04 /= 2;
+ L05 /= 2;
+ L06 /= 2;
+ L07 /= 2;
+
+ L05 = FIX_MULT_DCT(AAN_C4_FIX, L05);
+
+ L25 = L06 - L04;
+ L25 = FIX_MULT_DCT(AAN_C6_FIX, L25);
+
+ L04 = FIX_MULT_DCT(AAN_Q0_FIX, L04);
+ L04 -= L25;
+
+ L06 = FIX_MULT_DCT(AAN_Q1_FIX, L06);
+ L06 -= L25;
+
+ BUTTERFLY(L07, L05);
+
+ BUTTERFLY(L05, L04);
+ out[3] = (int16_t)SCALE(L04, DCTII_8_SHIFT_3 - 1);
+ out[5] = (int16_t)SCALE(L05, DCTII_8_SHIFT_5 - 1);
+
+ BUTTERFLY(L07, L06);
+ out[7] = (int16_t)SCALE(L06, DCTII_8_SHIFT_7 - 1);
+ out[1] = (int16_t)SCALE(L07, DCTII_8_SHIFT_1 - 1);
+#undef BUTTERFLY
+
+#ifdef DEBUG_DCT
+ {
+ float float_out[8];
+ float_dct2_8(float_out, in);
+ }
+#endif
+}
+
+/**@}*/
diff --git a/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c
new file mode 100755
index 0000000..12950c3
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/decoder/srce/synthesis-sbc.c
@@ -0,0 +1,559 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2003 - 2004 Open Interface North America, Inc. All rights
+ * reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ $Revision: #1 $
+ ******************************************************************************/
+
+/** @file
+
+This file, along with synthesis-generated.c, contains the synthesis
+filterbank routines. The operations performed correspond to the
+operations described in A2DP Appendix B, Figure 12.3. Several
+mathematical optimizations are performed, particularly for the
+8-subband case.
+
+One important optimization is to note that the "matrixing" operation
+can be decomposed into the product of a type II discrete cosine kernel
+and another, sparse matrix.
+
+According to Fig 12.3, in the 8-subband case,
+@code
+ N[k][i] = cos((i+0.5)*(k+4)*pi/8), k = 0..15 and i = 0..7
+@endcode
+
+N can be factored as R * C2, where C2 is an 8-point type II discrete
+cosine kernel given by
+@code
+ C2[k][i] = cos((i+0.5)*k*pi/8)), k = 0..7 and i = 0..7
+@endcode
+
+R turns out to be a sparse 16x8 matrix with the following non-zero
+entries:
+@code
+ R[k][k+4] = 1, k = 0..3
+ R[k][abs(12-k)] = -1, k = 5..15
+@endcode
+
+The spec describes computing V[0..15] as N * R.
+@code
+ V[0..15] = N * R = (R * C2) * R = R * (C2 * R)
+@endcode
+
+C2 * R corresponds to computing the discrete cosine transform of R, so
+V[0..15] can be computed by taking the DCT of R followed by assignment
+and selective negation of the DCT result into V.
+
+ Although this was derived empirically using GNU Octave, it is
+ formally demonstrated in, e.g., Liu, Chi-Min and Lee,
+ Wen-Chieh. "A Unified Fast Algorithm for Cosine Modulated
+ Filter Banks in Current Audio Coding Standards." Journal of
+ the AES 47 (December 1999): 1061.
+
+Given the shift operation performed prior to computing V[0..15], it is
+clear that V[0..159] represents a rolling history of the 10 most
+recent groups of blocks input to the synthesis operation. Interpreting
+the matrix N in light of its factorization into C2 and R, R's
+sparseness has implications for interpreting the values in V. In
+particular, there is considerable redundancy in the values stored in
+V. Furthermore, since R[4][0..7] are all zeros, one out of every 16
+values in V will be zero regardless of the input data. Within each
+block of 16 values in V, fully half of them are redundant or
+irrelevant:
+
+@code
+ V[ 0] = DCT[4]
+ V[ 1] = DCT[5]
+ V[ 2] = DCT[6]
+ V[ 3] = DCT[7]
+ V[ 4] = 0
+ V[ 5] = -DCT[7] = -V[3] (redundant)
+ V[ 6] = -DCT[6] = -V[2] (redundant)
+ V[ 7] = -DCT[5] = -V[1] (redundant)
+ V[ 8] = -DCT[4] = -V[0] (redundant)
+ V[ 9] = -DCT[3]
+ V[10] = -DCT[2]
+ V[11] = -DCT[1]
+ V[12] = -DCT[0]
+ V[13] = -DCT[1] = V[11] (redundant)
+ V[14] = -DCT[2] = V[10] (redundant)
+ V[15] = -DCT[3] = V[ 9] (redundant)
+@endcode
+
+Since the elements of V beyond 15 were originally computed the same
+way during a previous run, what holds true for V[x] also holds true
+for V[x+16]. Thus, so long as care is taken to maintain the mapping,
+we need only actually store the unique values, which correspond to the
+output of the DCT, in some cases inverted. In fact, instead of storing
+V[0..159], we could store DCT[0..79] which would contain a history of
+DCT results. More on this in a bit.
+
+Going back to figure 12.3 in the spec, it should be clear that the
+vector U need not actually be explicitly constructed, but that with
+suitable indexing into V during the window operation, the same end can
+be accomplished. In the same spirit of the pseudocode shown in the
+figure, the following is the construction of W without using U:
+
+@code
+ for i=0 to 79 do
+ W[i] = D[i]*VSIGN(i)*V[remap_V(i)] where remap_V(i) = 32*(int(i/16)) +
+(i % 16) + (i % 16 >= 8 ? 16 : 0)
+ and VSIGN(i) maps i%16 into {1, 1,
+1, 1, 0, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1 }
+ These values correspond to the
+ signs of the redundant values as
+ shown in the explanation three
+ paragraphs above.
+@endcode
+
+We saw above how V[4..8,13..15] (and by extension
+V[(4..8,13..15)+16*n]) can be defined in terms of other elements
+within the subblock of V. V[0..3,9..12] correspond to DCT elements.
+
+@code
+ for i=0 to 79 do
+ W[i] = D[i]*DSIGN(i)*DCT[remap_DCT(i)]
+@endcode
+
+The DCT is calculated using the Arai-Agui-Nakajima factorization,
+which saves some computation by producing output that needs to be
+multiplied by scaling factors before being used.
+
+@code
+ for i=0 to 79 do
+ W[i] = D[i]*SCALE[i%8]*AAN_DCT[remap_DCT(i)]
+@endcode
+
+D can be premultiplied with the DCT scaling factors to yield
+
+@code
+ for i=0 to 79 do
+ W[i] = DSCALED[i]*AAN_DCT[remap_DCT(i)] where DSCALED[i] =
+D[i]*SCALE[i%8]
+@endcode
+
+The output samples X[0..7] are defined as sums of W:
+
+@code
+ X[j] = sum{i=0..9}(W[j+8*i])
+@endcode
+
+@ingroup codec_internal
+*/
+
+/**
+@addtogroup codec_internal
+@{
+*/
+
+#include "oi_codec_sbc_private.h"
+
+const int32_t dec_window_4[21] = {
+ 0, /* +0.00000000E+00 */
+ 97, /* +5.36548976E-04 */
+ 270, /* +1.49188357E-03 */
+ 495, /* +2.73370904E-03 */
+ 694, /* +3.83720193E-03 */
+ 704, /* +3.89205149E-03 */
+ 338, /* +1.86581691E-03 */
+ -554, /* -3.06012286E-03 */
+ 1974, /* +1.09137620E-02 */
+ 3697, /* +2.04385087E-02 */
+ 5224, /* +2.88757392E-02 */
+ 5824, /* +3.21939290E-02 */
+ 4681, /* +2.58767811E-02 */
+ 1109, /* +6.13245186E-03 */
+ -5214, /* -2.88217274E-02 */
+ -14047, /* -7.76463494E-02 */
+ 24529, /* +1.35593274E-01 */
+ 35274, /* +1.94987841E-01 */
+ 44618, /* +2.46636662E-01 */
+ 50984, /* +2.81828203E-01 */
+ 53243, /* +2.94315332E-01 */
+};
+
+#define DCTII_4_K06_FIX (11585) /* S1.14 11585 0.707107*/
+
+#define DCTII_4_K08_FIX (21407) /* S1.14 21407 1.306563*/
+
+#define DCTII_4_K09_FIX (-15137) /* S1.14 -15137 -0.923880*/
+
+#define DCTII_4_K10_FIX (-8867) /* S1.14 -8867 -0.541196*/
+
+/** Scales x by y bits to the right, adding a rounding factor.
+ */
+#ifndef SCALE
+#define SCALE(x, y) (((x) + (1 << ((y)-1))) >> (y))
+#endif
+
+#ifndef CLIP_INT16
+#define CLIP_INT16(x) \
+ do { \
+ if ((x) > OI_INT16_MAX) { \
+ (x) = OI_INT16_MAX; \
+ } else if ((x) < OI_INT16_MIN) { \
+ (x) = OI_INT16_MIN; \
+ } \
+ } while (0)
+#endif
+
+/**
+ * Default C language implementation of a 16x32->32 multiply. This function may
+ * be replaced by a platform-specific version for speed.
+ *
+ * @param u A signed 16-bit multiplicand
+ * @param v A signed 32-bit multiplier
+
+ * @return A signed 32-bit value corresponding to the 32 most significant bits
+ * of the 48-bit product of u and v.
+ */
+INLINE int32_t default_mul_16s_32s_hi(int16_t u, int32_t v) {
+ uint16_t v0;
+ int16_t v1;
+
+ int32_t w, x;
+
+ v0 = (uint16_t)(v & 0xffff);
+ v1 = (int16_t)(v >> 16);
+
+ w = v1 * u;
+ x = u * v0;
+
+ return w + (x >> 16);
+}
+
+#define MUL_16S_32S_HI(_x, _y) default_mul_16s_32s_hi(_x, _y)
+
+#define LONG_MULT_DCT(K, sample) (MUL_16S_32S_HI(K, sample) << 2)
+
+PRIVATE void SynthWindow80_generated(int16_t* pcm,
+ SBC_BUFFER_T const* RESTRICT buffer,
+ OI_UINT strideShift);
+PRIVATE void SynthWindow112_generated(int16_t* pcm,
+ SBC_BUFFER_T const* RESTRICT buffer,
+ OI_UINT strideShift);
+PRIVATE void dct2_8(SBC_BUFFER_T* RESTRICT out, int32_t const* RESTRICT x);
+
+typedef void (*SYNTH_FRAME)(OI_CODEC_SBC_DECODER_CONTEXT* context, int16_t* pcm,
+ OI_UINT blkstart, OI_UINT blkcount);
+
+#ifndef COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS
+#define COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(dest, src) \
+ do { \
+ shift_buffer(dest, src, 72); \
+ } while (0)
+#endif
+
+#ifndef DCT2_8
+#define DCT2_8(dst, src) dct2_8(dst, src)
+#endif
+
+#ifndef SYNTH80
+#define SYNTH80 SynthWindow80_generated
+#endif
+
+#ifndef SYNTH112
+#define SYNTH112 SynthWindow112_generated
+#endif
+
+PRIVATE void OI_SBC_SynthFrame_80(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ int16_t* pcm, OI_UINT blkstart,
+ OI_UINT blkcount) {
+ OI_UINT blk;
+ OI_UINT ch;
+ OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+ OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+ OI_UINT offset = context->common.filterBufferOffset;
+ int32_t* s = context->common.subdata + 8 * nrof_channels * blkstart;
+ OI_UINT blkstop = blkstart + blkcount;
+
+ for (blk = blkstart; blk < blkstop; blk++) {
+ if (offset == 0) {
+ COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(
+ context->common.filterBuffer[0] + context->common.filterBufferLen -
+ 72,
+ context->common.filterBuffer[0]);
+ if (nrof_channels == 2) {
+ COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(
+ context->common.filterBuffer[1] + context->common.filterBufferLen -
+ 72,
+ context->common.filterBuffer[1]);
+ }
+ offset = context->common.filterBufferLen - 80;
+ } else {
+ offset -= 1 * 8;
+ }
+
+ for (ch = 0; ch < nrof_channels; ch++) {
+ DCT2_8(context->common.filterBuffer[ch] + offset, s);
+ SYNTH80(pcm + ch, context->common.filterBuffer[ch] + offset,
+ pcmStrideShift);
+ s += 8;
+ }
+ pcm += (8 << pcmStrideShift);
+ }
+ context->common.filterBufferOffset = offset;
+}
+
+PRIVATE void OI_SBC_SynthFrame_4SB(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ int16_t* pcm, OI_UINT blkstart,
+ OI_UINT blkcount) {
+ OI_UINT blk;
+ OI_UINT ch;
+ OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+ OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+ OI_UINT offset = context->common.filterBufferOffset;
+ int32_t* s = context->common.subdata + 8 * nrof_channels * blkstart;
+ OI_UINT blkstop = blkstart + blkcount;
+
+ for (blk = blkstart; blk < blkstop; blk++) {
+ if (offset == 0) {
+ COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(
+ context->common.filterBuffer[0] + context->common.filterBufferLen -
+ 72,
+ context->common.filterBuffer[0]);
+ if (nrof_channels == 2) {
+ COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(
+ context->common.filterBuffer[1] + context->common.filterBufferLen -
+ 72,
+ context->common.filterBuffer[1]);
+ }
+ offset = context->common.filterBufferLen - 80;
+ } else {
+ offset -= 8;
+ }
+ for (ch = 0; ch < nrof_channels; ch++) {
+ cosineModulateSynth4(context->common.filterBuffer[ch] + offset, s);
+ SynthWindow40_int32_int32_symmetry_with_sum(
+ pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift);
+ s += 4;
+ }
+ pcm += (4 << pcmStrideShift);
+ }
+ context->common.filterBufferOffset = offset;
+}
+
+#ifdef SBC_ENHANCED
+
+PRIVATE void OI_SBC_SynthFrame_Enhanced(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ int16_t* pcm, OI_UINT blkstart,
+ OI_UINT blkcount) {
+ OI_UINT blk;
+ OI_UINT ch;
+ OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+ OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
+ OI_UINT offset = context->common.filterBufferOffset;
+ int32_t* s = context->common.subdata + 8 * nrof_channels * blkstart;
+ OI_UINT blkstop = blkstart + blkcount;
+
+ for (blk = blkstart; blk < blkstop; blk++) {
+ if (offset == 0) {
+ COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(
+ context->common.filterBuffer[0] + context->common.filterBufferLen -
+ 104,
+ context->common.filterBuffer[0]);
+ if (nrof_channels == 2) {
+ COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(
+ context->common.filterBuffer[1] + context->common.filterBufferLen -
+ 104,
+ context->common.filterBuffer[1]);
+ }
+ offset = context->common.filterBufferLen - 112;
+ } else {
+ offset -= 8;
+ }
+ for (ch = 0; ch < nrof_channels; ++ch) {
+ DCT2_8(context->common.filterBuffer[ch] + offset, s);
+ SYNTH112(pcm + ch, context->common.filterBuffer[ch] + offset,
+ pcmStrideShift);
+ s += 8;
+ }
+ pcm += (8 << pcmStrideShift);
+ }
+ context->common.filterBufferOffset = offset;
+}
+
+static const SYNTH_FRAME SynthFrameEnhanced[] = {
+ NULL, /* invalid */
+ OI_SBC_SynthFrame_Enhanced, /* mono */
+ OI_SBC_SynthFrame_Enhanced /* stereo */
+};
+
+#endif
+
+static const SYNTH_FRAME SynthFrame8SB[] = {
+ NULL, /* invalid */
+ OI_SBC_SynthFrame_80, /* mono */
+ OI_SBC_SynthFrame_80 /* stereo */
+};
+
+static const SYNTH_FRAME SynthFrame4SB[] = {
+ NULL, /* invalid */
+ OI_SBC_SynthFrame_4SB, /* mono */
+ OI_SBC_SynthFrame_4SB /* stereo */
+};
+
+PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT* context,
+ int16_t* pcm, OI_UINT start_block,
+ OI_UINT nrof_blocks) {
+ OI_UINT nrof_subbands = context->common.frameInfo.nrof_subbands;
+ OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
+
+ OI_ASSERT(nrof_subbands == 4 || nrof_subbands == 8);
+ if (nrof_subbands == 4) {
+ SynthFrame4SB[nrof_channels](context, pcm, start_block, nrof_blocks);
+#ifdef SBC_ENHANCED
+ } else if (context->common.frameInfo.enhanced) {
+ SynthFrameEnhanced[nrof_channels](context, pcm, start_block, nrof_blocks);
+#endif /* SBC_ENHANCED */
+ } else {
+ SynthFrame8SB[nrof_channels](context, pcm, start_block, nrof_blocks);
+ }
+}
+
+void SynthWindow40_int32_int32_symmetry_with_sum(int16_t* pcm,
+ SBC_BUFFER_T buffer[80],
+ OI_UINT strideShift) {
+ int32_t pa;
+ int32_t pb;
+
+ /* These values should be zero, since out[2] of the 4-band cosine modulation
+ * is always zero. */
+ OI_ASSERT(buffer[2] == 0);
+ OI_ASSERT(buffer[10] == 0);
+ OI_ASSERT(buffer[18] == 0);
+ OI_ASSERT(buffer[26] == 0);
+ OI_ASSERT(buffer[34] == 0);
+ OI_ASSERT(buffer[42] == 0);
+ OI_ASSERT(buffer[50] == 0);
+ OI_ASSERT(buffer[58] == 0);
+ OI_ASSERT(buffer[66] == 0);
+ OI_ASSERT(buffer[74] == 0);
+
+ pa = dec_window_4[4] * (buffer[12] + buffer[76]);
+ pa += dec_window_4[8] * (buffer[16] - buffer[64]);
+ pa += dec_window_4[12] * (buffer[28] + buffer[60]);
+ pa += dec_window_4[16] * (buffer[32] - buffer[48]);
+ pa += dec_window_4[20] * buffer[44];
+ pa = SCALE(-pa, 15);
+ CLIP_INT16(pa);
+ pcm[0 << strideShift] = (int16_t)pa;
+
+ pa = dec_window_4[1] * buffer[1];
+ pb = dec_window_4[1] * buffer[79];
+ pb += dec_window_4[3] * buffer[3];
+ pa += dec_window_4[3] * buffer[77];
+ pa += dec_window_4[5] * buffer[13];
+ pb += dec_window_4[5] * buffer[67];
+ pb += dec_window_4[7] * buffer[15];
+ pa += dec_window_4[7] * buffer[65];
+ pa += dec_window_4[9] * buffer[17];
+ pb += dec_window_4[9] * buffer[63];
+ pb += dec_window_4[11] * buffer[19];
+ pa += dec_window_4[11] * buffer[61];
+ pa += dec_window_4[13] * buffer[29];
+ pb += dec_window_4[13] * buffer[51];
+ pb += dec_window_4[15] * buffer[31];
+ pa += dec_window_4[15] * buffer[49];
+ pa += dec_window_4[17] * buffer[33];
+ pb += dec_window_4[17] * buffer[47];
+ pb += dec_window_4[19] * buffer[35];
+ pa += dec_window_4[19] * buffer[45];
+ pa = SCALE(-pa, 15);
+ CLIP_INT16(pa);
+ pcm[1 << strideShift] = (int16_t)(pa);
+ pb = SCALE(-pb, 15);
+ CLIP_INT16(pb);
+ pcm[3 << strideShift] = (int16_t)(pb);
+
+ pa = dec_window_4[2] *
+ (/*buffer[ 2] + */ buffer[78]); /* buffer[ 2] is always zero */
+ pa += dec_window_4[6] *
+ (buffer[14] /* + buffer[66]*/); /* buffer[66] is always zero */
+ pa += dec_window_4[10] *
+ (/*buffer[18] + */ buffer[62]); /* buffer[18] is always zero */
+ pa += dec_window_4[14] *
+ (buffer[30] /* + buffer[50]*/); /* buffer[50] is always zero */
+ pa += dec_window_4[18] *
+ (/*buffer[34] + */ buffer[46]); /* buffer[34] is always zero */
+ pa = SCALE(-pa, 15);
+ CLIP_INT16(pa);
+ pcm[2 << strideShift] = (int16_t)(pa);
+}
+
+/**
+ This routine implements the cosine modulation matrix for 4-subband
+ synthesis. This is called "matrixing" in the SBC specification. This
+ matrix, M4, can be factored into an 8-point Type II Discrete Cosine
+ Transform, DCTII_4 and a matrix S4, given here:
+
+ @code
+ __ __
+ | 0 0 1 0 |
+ | 0 0 0 1 |
+ | 0 0 0 0 |
+ | 0 0 0 -1 |
+ S4 = | 0 0 -1 0 |
+ | 0 -1 0 0 |
+ | -1 0 0 0 |
+ |__ 0 -1 0 0 __|
+
+ M4 * in = S4 * (DCTII_4 * in)
+ @endcode
+
+ (DCTII_4 * in) is computed using a Fast Cosine Transform. The algorithm
+ here is based on an implementation computed by the SPIRAL computer
+ algebra system, manually converted to fixed-point arithmetic. S4 can be
+ implemented using only assignment and negation.
+ */
+PRIVATE void cosineModulateSynth4(SBC_BUFFER_T* RESTRICT out,
+ int32_t const* RESTRICT in) {
+ int32_t f0, f1, f2, f3, f4, f7, f8, f9, f10;
+ int32_t y0, y1, y2, y3;
+
+ f0 = (in[0] - in[3]);
+ f1 = (in[0] + in[3]);
+ f2 = (in[1] - in[2]);
+ f3 = (in[1] + in[2]);
+
+ f4 = f1 - f3;
+
+ y0 = -SCALE(f1 + f3, DCT_SHIFT);
+ y2 = -SCALE(LONG_MULT_DCT(DCTII_4_K06_FIX, f4), DCT_SHIFT);
+ f7 = f0 + f2;
+ f8 = LONG_MULT_DCT(DCTII_4_K08_FIX, f0);
+ f9 = LONG_MULT_DCT(DCTII_4_K09_FIX, f7);
+ f10 = LONG_MULT_DCT(DCTII_4_K10_FIX, f2);
+ y3 = -SCALE(f8 + f9, DCT_SHIFT);
+ y1 = -SCALE(f10 - f9, DCT_SHIFT);
+
+ out[0] = (int16_t)-y2;
+ out[1] = (int16_t)-y3;
+ out[2] = (int16_t)0;
+ out[3] = (int16_t)y3;
+ out[4] = (int16_t)y2;
+ out[5] = (int16_t)y1;
+ out[6] = (int16_t)y0;
+ out[7] = (int16_t)y1;
+}
+
+/**
+@}
+*/
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/Android.bp b/mtkbt/code/bt/embdrv/sbc/encoder/Android.bp
new file mode 100755
index 0000000..42046d4
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/Android.bp
@@ -0,0 +1,23 @@
+cc_library_static {
+ name: "libbt-sbc-encoder",
+ defaults: ["fluoride_defaults"],
+ srcs: [
+ "srce/sbc_analysis.c",
+ "srce/sbc_dct.c",
+ "srce/sbc_dct_coeffs.c",
+ "srce/sbc_enc_bit_alloc_mono.c",
+ "srce/sbc_enc_bit_alloc_ste.c",
+ "srce/sbc_enc_coeffs.c",
+ "srce/sbc_encoder.c",
+ "srce/sbc_packing.c",
+ ],
+ local_include_dirs: [
+ "include",
+ "srce",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_dct.h b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_dct.h
new file mode 100755
index 0000000..10123e5
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_dct.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Definitions for the fast DCT.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_DCT_H
+#define SBC_DCT_H
+
+#include "sbc_enc_func_declare.h"
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow) \
+ { \
+ __asm { \
+ MUL s32OutLow,(int32_t)s16In2, (s32In1>>15) } \
+ }
+#else
+#if (SBC_DSP_OPT == TRUE)
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow) \
+ s32OutLow = SBC_Multiply_32_16_Simplified((int32_t)s16In2, s32In1);
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+/*
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow)
+s32OutLow=(int32_t)((int32_t)(s16In2)*(int32_t)(s32In1>>15));
+*/
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow) \
+ s32OutLow = (int32_t)(((int64_t)(s16In2) * (int64_t)(s32In1)) >> 15);
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow) \
+ { \
+ s64Temp = ((int64_t)s32In2) * ((int64_t)s32In1) >> 31; \
+ s32OutLow = (int32_t)s64Temp; \
+ }
+#endif
+#else
+#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow) \
+ { \
+ s32In1Temp = s32In1; \
+ s32In2Temp = (int32_t)s16In2; \
+ \
+ /* Multiply one +ve and the other -ve number */ \
+ if (s32In1Temp < 0) { \
+ s32In1Temp ^= 0xFFFFFFFF; \
+ s32In1Temp++; \
+ s32OutLow = (s32In2Temp * (s32In1Temp >> 16)); \
+ s32OutLow += ((s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16); \
+ s32OutLow ^= 0xFFFFFFFF; \
+ s32OutLow++; \
+ } else { \
+ s32OutLow = (s32In2Temp * (s32In1Temp >> 16)); \
+ s32OutLow += ((s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16); \
+ } \
+ s32OutLow <<= 1; \
+ }
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+#define SBC_MULT_64(s32In1, s32In2, s32OutLow, s32OutHi) \
+ { \
+ s32OutLow = \
+ (int32_t)(((int64_t)s32In1 * (int64_t)s32In2) & 0x00000000FFFFFFFF); \
+ s32OutHi = (int32_t)(((int64_t)s32In1 * (int64_t)s32In2) >> 32); \
+ }
+#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow) \
+ { \
+ s32HiTemp = 0; \
+ SBC_MULT_64(s32In2, s32In1, s32OutLow, s32HiTemp); \
+ s32OutLow = (((s32OutLow >> 15) & 0x1FFFF) | (s32HiTemp << 17)); \
+ }
+#endif
+
+#endif
+#endif
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
new file mode 100755
index 0000000..3fbe06a
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_enc_func_declare.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Function declarations.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_FUNCDECLARE_H
+#define SBC_FUNCDECLARE_H
+
+#include "sbc_encoder.h"
+/* Global data */
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE)
+extern const int16_t gas32CoeffFor4SBs[];
+extern const int16_t gas32CoeffFor8SBs[];
+#else
+extern const int32_t gas32CoeffFor4SBs[];
+extern const int32_t gas32CoeffFor8SBs[];
+#endif
+
+/* Global functions*/
+
+extern void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS* CodecParams);
+extern void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS* CodecParams);
+
+extern void SbcAnalysisInit(void);
+
+extern void SbcAnalysisFilter4(SBC_ENC_PARAMS* strEncParams, int16_t* input);
+extern void SbcAnalysisFilter8(SBC_ENC_PARAMS* strEncParams, int16_t* input);
+
+extern void SBC_FastIDCT8(int32_t* pInVect, int32_t* pOutVect);
+extern void SBC_FastIDCT4(int32_t* x0, int32_t* pOutVect);
+
+extern uint32_t EncPacking(SBC_ENC_PARAMS* strEncParams, uint8_t* output);
+extern void EncQuantizer(SBC_ENC_PARAMS*);
+#if (SBC_DSP_OPT == TRUE)
+int32_t SBC_Multiply_32_16_Simplified(int32_t s32In2Temp, int32_t s32In1Temp);
+#endif
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_encoder.h b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_encoder.h
new file mode 100755
index 0000000..e53a08a
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_encoder.h
@@ -0,0 +1,208 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains constants and structures used by Encoder.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_ENCODER_H
+#define SBC_ENCODER_H
+
+#define ENCODER_VERSION "0025"
+
+#include "bt_target.h"
+
+/*DEFINES*/
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define SBC_MAX_NUM_OF_SUBBANDS 8
+#define SBC_MAX_NUM_OF_CHANNELS 2
+#define SBC_MAX_NUM_OF_BLOCKS 16
+
+#define SBC_LOUDNESS 0
+#define SBC_SNR 1
+
+#define SUB_BANDS_8 8
+#define SUB_BANDS_4 4
+
+#define SBC_sf16000 0
+#define SBC_sf32000 1
+#define SBC_sf44100 2
+#define SBC_sf48000 3
+
+#define SBC_MONO 0
+#define SBC_DUAL 1
+#define SBC_STEREO 2
+#define SBC_JOINT_STEREO 3
+
+#define SBC_BLOCK_0 4
+#define SBC_BLOCK_1 8
+#define SBC_BLOCK_2 12
+#define SBC_BLOCK_3 16
+
+#define SBC_NULL 0
+
+#ifndef SBC_MAX_NUM_FRAME
+#define SBC_MAX_NUM_FRAME 1
+#endif
+
+#ifndef SBC_DSP_OPT
+#define SBC_DSP_OPT FALSE
+#endif
+
+/* Set SBC_USE_ARM_PRAGMA to TRUE to use "#pragma arm section zidata" */
+#ifndef SBC_USE_ARM_PRAGMA
+#define SBC_USE_ARM_PRAGMA FALSE
+#endif
+
+/* Set SBC_ARM_ASM_OPT to TRUE in case the target is an ARM */
+/* this will replace all the 32 and 64 bit mult by in line assembly code */
+#ifndef SBC_ARM_ASM_OPT
+#define SBC_ARM_ASM_OPT FALSE
+#endif
+
+/* green hill compiler option -> Used to distinguish the syntax for inline
+ * assembly code
+ */
+#ifndef SBC_GHS_COMPILER
+#define SBC_GHS_COMPILER FALSE
+#endif
+
+/* ARM compiler option -> Used to distinguish the syntax for inline assembly
+ * code */
+#ifndef SBC_ARM_COMPILER
+#define SBC_ARM_COMPILER TRUE
+#endif
+
+/* Set SBC_IPAQ_OPT to TRUE in case the target is an ARM */
+/* 32 and 64 bit mult will be performed using int64_t ( usualy __int64 ) cast
+ * that usualy give optimal performance if supported
+ */
+#ifndef SBC_IPAQ_OPT
+#define SBC_IPAQ_OPT TRUE
+#endif
+
+/* Debug only: set SBC_IS_64_MULT_IN_WINDOW_ACCU to TRUE to use 64 bit
+ * multiplication in the windowing
+ */
+/* -> not recomended, more MIPS for the same restitution. */
+#ifndef SBC_IS_64_MULT_IN_WINDOW_ACCU
+#define SBC_IS_64_MULT_IN_WINDOW_ACCU FALSE
+#endif /*SBC_IS_64_MULT_IN_WINDOW_ACCU */
+
+/* Set SBC_IS_64_MULT_IN_IDCT to TRUE to use 64 bits multiplication in the DCT
+ * of Matrixing
+ */
+/* -> more MIPS required for a better audio quality. comparasion with the SIG
+ * utilities shows a division by 10 of the RMS
+ */
+/* CAUTION: It only apply in the if SBC_FAST_DCT is set to TRUE */
+#ifndef SBC_IS_64_MULT_IN_IDCT
+#define SBC_IS_64_MULT_IN_IDCT FALSE
+#endif /*SBC_IS_64_MULT_IN_IDCT */
+
+/* set SBC_IS_64_MULT_IN_QUANTIZER to TRUE to use 64 bits multiplication in the
+ * quantizer
+ */
+/* setting this flag to FALSE adds a whistling noise at 5.5 and 11 KHz usualy
+ * not perceptible by human's hears. */
+#ifndef SBC_IS_64_MULT_IN_QUANTIZER
+#define SBC_IS_64_MULT_IN_QUANTIZER TRUE
+#endif /*SBC_IS_64_MULT_IN_IDCT */
+
+/* Debug only: set this flag to FALSE to disable fast DCT algorithm */
+#ifndef SBC_FAST_DCT
+#define SBC_FAST_DCT TRUE
+#endif /*SBC_FAST_DCT */
+
+/* In case we do not use joint stereo mode the flag save some RAM and ROM in
+ * case it is set to FALSE */
+#ifndef SBC_JOINT_STE_INCLUDED
+#define SBC_JOINT_STE_INCLUDED TRUE
+#endif
+
+#define MINIMUM_ENC_VX_BUFFER_SIZE (8 * 10 * 2)
+#ifndef ENC_VX_BUFFER_SIZE
+#define ENC_VX_BUFFER_SIZE (MINIMUM_ENC_VX_BUFFER_SIZE + 64)
+/*#define ENC_VX_BUFFER_SIZE MINIMUM_ENC_VX_BUFFER_SIZE + 1024*/
+#endif
+
+#ifndef SBC_FOR_EMBEDDED_LINUX
+#define SBC_FOR_EMBEDDED_LINUX FALSE
+#endif
+
+/*constants used for index calculation*/
+#define SBC_BLK (SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS)
+
+#define SBC_MAX_PCM_BUFFER_SIZE \
+ (SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * \
+ SBC_MAX_NUM_OF_SUBBANDS)
+
+#include "sbc_types.h"
+
+typedef struct SBC_ENC_PARAMS_TAG {
+ int16_t s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/
+ int16_t s16ChannelMode; /* mono, dual, streo or joint streo*/
+ int16_t s16NumOfSubBands; /* 4 or 8 */
+ int16_t s16NumOfChannels;
+ int16_t s16NumOfBlocks; /* 4, 8, 12 or 16*/
+ int16_t s16AllocationMethod; /* loudness or SNR*/
+ int16_t s16BitPool; /* 16*numOfSb for mono & dual;
+ 32*numOfSb for stereo & joint stereo */
+ uint16_t u16BitRate;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+ int16_t as16Join[SBC_MAX_NUM_OF_SUBBANDS]; /*1 if JS, 0 otherwise*/
+#endif
+
+ int16_t s16MaxBitNeed;
+ int16_t as16ScaleFactor[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
+
+ int16_t s16ScartchMemForBitAlloc[16];
+
+ int32_t s32SbBuffer[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS *
+ SBC_MAX_NUM_OF_BLOCKS];
+
+ int16_t as16Bits[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
+
+ uint16_t FrameHeader;
+
+} SBC_ENC_PARAMS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Encode the frame using SBC. The output is written into |output|. Return
+ * number of bytes written. */
+extern uint32_t SBC_Encode(SBC_ENC_PARAMS* strEncParams, int16_t* input,
+ uint8_t* output);
+extern void SBC_Encoder_Init(SBC_ENC_PARAMS* strEncParams);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SBC_ENCODER_H */
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_if.h b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_if.h
new file mode 100755
index 0000000..19706d2
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_if.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef _SBC_IF_H
+#define _SBC_IF_H
+
+#define PCM_BUFFER_SIZE 512
+
+/*
+ SBC_Init - called once for each track played
+
+ pcm_sample_freq - 4000 to 48000
+ channels - 1 mono 2 stereo
+ bits_per_sample - 8 or 16
+ return - 0 sucess
+*/
+
+int SBC_init(int pcm_sample_freq, int channels, int bits_per_sample);
+
+/*
+ SBC_write - called repeatedly with pcm_in pointer
+ increasing by length until track is finished.
+
+ pcm_in - pointer to PCM buffer
+ length - any
+ sbc_out - pointer to SBC output buffer
+ return - number of bytes written to sbc_out
+*/
+
+int SBC_write(unsigned char* pcm_in, int length, unsigned char* sbc_out);
+
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_types.h b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_types.h
new file mode 100755
index 0000000..0069a2a
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/include/sbc_types.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Data type declarations.
+ *
+ ******************************************************************************/
+
+#ifndef SBC_TYPES_H
+#define SBC_TYPES_H
+
+#include <stdint.h>
+
+#include "bt_target.h"
+#include "bt_types.h"
+
+#define abs32(x) (((x) >= 0) ? (x) : (-(x)))
+
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_analysis.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_analysis.c
new file mode 100755
index 0000000..ddc9978
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_analysis.c
@@ -0,0 +1,1400 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the code that performs Analysis of the input audio
+ * stream.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "sbc_enc_func_declare.h"
+#include "sbc_encoder.h"
+/*#include <math.h>*/
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WIND_4_SUBBANDS_0_1 \
+ (int32_t)0x01659F45 /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = \
+ 0x01659F45 */
+#define WIND_4_SUBBANDS_0_2 \
+ (int32_t)0x115B1ED2 /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = \
+ 0x115B1ED2 */
+#define WIND_4_SUBBANDS_1_0 \
+ (int32_t)0x001194E6 /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */
+#define WIND_4_SUBBANDS_1_1 \
+ (int32_t)0x029DBAA3 /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */
+#define WIND_4_SUBBANDS_1_2 \
+ (int32_t)0x18F55C90 /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */
+#define WIND_4_SUBBANDS_1_3 \
+ (int32_t)0xF60FAF37 /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */
+#define WIND_4_SUBBANDS_1_4 \
+ (int32_t)0xFF9BB9D5 /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */
+#define WIND_4_SUBBANDS_2_0 \
+ (int32_t)0x0030E2D3 /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */
+#define WIND_4_SUBBANDS_2_1 \
+ (int32_t)0x03B23341 /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */
+#define WIND_4_SUBBANDS_2_2 \
+ (int32_t)0x1F91CA46 /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */
+#define WIND_4_SUBBANDS_2_3 \
+ (int32_t)0xFC4F91D4 /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */
+#define WIND_4_SUBBANDS_2_4 \
+ (int32_t)0x003D239B /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */
+#define WIND_4_SUBBANDS_3_0 \
+ (int32_t)0x00599403 /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */
+#define WIND_4_SUBBANDS_3_1 \
+ (int32_t)0x041EEE40 /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */
+#define WIND_4_SUBBANDS_3_2 \
+ (int32_t)0x2412F251 /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */
+#define WIND_4_SUBBANDS_3_3 \
+ (int32_t)0x00C8F2BC /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */
+#define WIND_4_SUBBANDS_3_4 \
+ (int32_t)0x007F88E4 /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */
+#define WIND_4_SUBBANDS_4_0 \
+ (int32_t)0x007DBCC8 /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */
+#define WIND_4_SUBBANDS_4_1 \
+ (int32_t)0x034FEE2C /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */
+#define WIND_4_SUBBANDS_4_2 \
+ (int32_t)0x25AC1FF2 /* gas32CoeffFor4SBs[20] = 0x25AC1FF2 */
+
+#define WIND_8_SUBBANDS_0_1 (int32_t)0x00B97348 /* 16 0x00B97348 */
+#define WIND_8_SUBBANDS_0_2 (int32_t)0x08B4307A /* 32 0x08B4307A */
+#define WIND_8_SUBBANDS_1_0 (int32_t)0x00052173 /* 1 et 79 = 0x00052173 */
+#define WIND_8_SUBBANDS_1_1 (int32_t)0x01071B96 /* 17 et 63 = 0x01071B96 */
+#define WIND_8_SUBBANDS_1_2 (int32_t)0x0A9F3E9A /* 33 et 47 = 0x0A9F3E9A*/
+#define WIND_8_SUBBANDS_1_3 (int32_t)0xF9312891 /* 31 et 49 = 0xF9312891 */
+#define WIND_8_SUBBANDS_1_4 (int32_t)0xFF8D6793 /* 15 et 65 = 0xFF8D6793 */
+#define WIND_8_SUBBANDS_2_0 (int32_t)0x000B3F71 /* 2 et 78 = 0x000B3F71 */
+#define WIND_8_SUBBANDS_2_1 (int32_t)0x0156B3CA /* 18 et 62 = 0x0156B3CA */
+#define WIND_8_SUBBANDS_2_2 (int32_t)0x0C7D59B6 /* 34 et 46 = 0x0C7D59B6 */
+#define WIND_8_SUBBANDS_2_3 (int32_t)0xFAFF95FC /* 30 et 50 = 0xFAFF95FC */
+#define WIND_8_SUBBANDS_2_4 (int32_t)0xFFC9F10E /* 14 et 66 = 0xFFC9F10E */
+#define WIND_8_SUBBANDS_3_0 (int32_t)0x00122C7D /* 3 et 77 = 0x00122C7D*/
+#define WIND_8_SUBBANDS_3_1 (int32_t)0x01A1B38B /* 19 et 61 = 0x01A1B38B */
+#define WIND_8_SUBBANDS_3_2 (int32_t)0x0E3BB16F /* 35 et 45 = 0x0E3BB16F */
+#define WIND_8_SUBBANDS_3_3 (int32_t)0xFCA86E7E /* 29 et 51 = 0xFCA86E7E */
+#define WIND_8_SUBBANDS_3_4 (int32_t)0xFFFA2413 /* 13 et 67 = 0xFFFA2413 */
+#define WIND_8_SUBBANDS_4_0 (int32_t)0x001AFF89 /* 4 et 66 = 0x001AFF89 */
+#define WIND_8_SUBBANDS_4_1 (int32_t)0x01E0224C /* 20 et 60 = 0x01E0224C */
+#define WIND_8_SUBBANDS_4_2 (int32_t)0x0FC721F9 /* 36 et 44 = 0x0FC721F9 */
+#define WIND_8_SUBBANDS_4_3 (int32_t)0xFE20435D /* 28 et 52 = 0xFE20435D */
+#define WIND_8_SUBBANDS_4_4 (int32_t)0x001D8FD2 /* 12 et 68 = 0x001D8FD2 */
+#define WIND_8_SUBBANDS_5_0 (int32_t)0x00255A62 /* 5 et 75 = 0x00255A62 */
+#define WIND_8_SUBBANDS_5_1 (int32_t)0x0209291F /* 21 et 59 = 0x0209291F */
+#define WIND_8_SUBBANDS_5_2 (int32_t)0x110ECEF0 /* 37 et 43 = 0x110ECEF0 */
+#define WIND_8_SUBBANDS_5_3 (int32_t)0xFF5EEB73 /* 27 et 53 = 0xFF5EEB73 */
+#define WIND_8_SUBBANDS_5_4 (int32_t)0x0034F8B6 /* 11 et 69 = 0x0034F8B6 */
+#define WIND_8_SUBBANDS_6_0 (int32_t)0x003060F4 /* 6 et 74 = 0x003060F4 */
+#define WIND_8_SUBBANDS_6_1 (int32_t)0x02138653 /* 22 et 58 = 0x02138653 */
+#define WIND_8_SUBBANDS_6_2 (int32_t)0x120435FA /* 38 et 42 = 0x120435FA */
+#define WIND_8_SUBBANDS_6_3 (int32_t)0x005FD0FF /* 26 et 54 = 0x005FD0FF */
+#define WIND_8_SUBBANDS_6_4 (int32_t)0x00415B75 /* 10 et 70 = 0x00415B75 */
+#define WIND_8_SUBBANDS_7_0 (int32_t)0x003A72E7 /* 7 et 73 = 0x003A72E7 */
+#define WIND_8_SUBBANDS_7_1 (int32_t)0x01F5F424 /* 23 et 57 = 0x01F5F424 */
+#define WIND_8_SUBBANDS_7_2 (int32_t)0x129C226F /* 39 et 41 = 0x129C226F */
+#define WIND_8_SUBBANDS_7_3 (int32_t)0x01223EBA /* 25 et 55 = 0x01223EBA */
+#define WIND_8_SUBBANDS_7_4 (int32_t)0x0044EF48 /* 9 et 71 = 0x0044EF48 */
+#define WIND_8_SUBBANDS_8_0 (int32_t)0x0041EC6A /* 8 et 72 = 0x0041EC6A */
+#define WIND_8_SUBBANDS_8_1 (int32_t)0x01A7ECEF /* 24 et 56 = 0x01A7ECEF */
+#define WIND_8_SUBBANDS_8_2 (int32_t)0x12CF6C75 /* 40 = 0x12CF6C75 */
+#else
+#define WIND_4_SUBBANDS_0_1 \
+ (int16_t)0x0166 /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = \
+ 0x01659F45 */
+#define WIND_4_SUBBANDS_0_2 \
+ (int16_t)0x115B /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = \
+ 0x115B1ED2 */
+#define WIND_4_SUBBANDS_1_0 \
+ (int16_t)0x0012 /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */
+#define WIND_4_SUBBANDS_1_1 \
+ (int16_t)0x029E /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */
+#define WIND_4_SUBBANDS_1_2 \
+ (int16_t)0x18F5 /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */
+#define WIND_4_SUBBANDS_1_3 \
+ (int16_t)0xF610 /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */
+#define WIND_4_SUBBANDS_1_4 \
+ (int16_t)0xFF9C /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */
+#define WIND_4_SUBBANDS_2_0 \
+ (int16_t)0x0031 /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */
+#define WIND_4_SUBBANDS_2_1 \
+ (int16_t)0x03B2 /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */
+#define WIND_4_SUBBANDS_2_2 \
+ (int16_t)0x1F91 /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */
+#define WIND_4_SUBBANDS_2_3 \
+ (int16_t)0xFC50 /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */
+#define WIND_4_SUBBANDS_2_4 \
+ (int16_t)0x003D /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */
+#define WIND_4_SUBBANDS_3_0 \
+ (int16_t)0x005A /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */
+#define WIND_4_SUBBANDS_3_1 \
+ (int16_t)0x041F /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */
+#define WIND_4_SUBBANDS_3_2 \
+ (int16_t)0x2413 /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */
+#define WIND_4_SUBBANDS_3_3 \
+ (int16_t)0x00C9 /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */
+#define WIND_4_SUBBANDS_3_4 \
+ (int16_t)0x0080 /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */
+#define WIND_4_SUBBANDS_4_0 \
+ (int16_t)0x007E /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */
+#define WIND_4_SUBBANDS_4_1 \
+ (int16_t)0x0350 /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */
+#define WIND_4_SUBBANDS_4_2 \
+ (int16_t)0x25AC /* gas32CoeffFor4SBs[20] = 25AC1FF2 */
+
+#define WIND_8_SUBBANDS_0_1 (int16_t)0x00B9 /* 16 0x12CF6C75 */
+#define WIND_8_SUBBANDS_0_2 (int16_t)0x08B4 /* 32 0x08B4307A */
+#define WIND_8_SUBBANDS_1_0 (int16_t)0x0005 /* 1 et 79 = 0x00052173 */
+#define WIND_8_SUBBANDS_1_1 (int16_t)0x0107 /* 17 et 63 = 0x01071B96 */
+#define WIND_8_SUBBANDS_1_2 (int16_t)0x0A9F /* 33 et 47 = 0x0A9F3E9A*/
+#define WIND_8_SUBBANDS_1_3 (int16_t)0xF931 /* 31 et 49 = 0xF9312891 */
+#define WIND_8_SUBBANDS_1_4 (int16_t)0xFF8D /* 15 et 65 = 0xFF8D6793 */
+#define WIND_8_SUBBANDS_2_0 (int16_t)0x000B /* 2 et 78 = 0x000B3F71 */
+#define WIND_8_SUBBANDS_2_1 (int16_t)0x0157 /* 18 et 62 = 0x0156B3CA */
+#define WIND_8_SUBBANDS_2_2 (int16_t)0x0C7D /* 34 et 46 = 0x0C7D59B6 */
+#define WIND_8_SUBBANDS_2_3 (int16_t)0xFB00 /* 30 et 50 = 0xFAFF95FC */
+#define WIND_8_SUBBANDS_2_4 (int16_t)0xFFCA /* 14 et 66 = 0xFFC9F10E */
+#define WIND_8_SUBBANDS_3_0 (int16_t)0x0012 /* 3 et 77 = 0x00122C7D*/
+#define WIND_8_SUBBANDS_3_1 (int16_t)0x01A2 /* 19 et 61 = 0x01A1B38B */
+#define WIND_8_SUBBANDS_3_2 (int16_t)0x0E3C /* 35 et 45 = 0x0E3BB16F */
+#define WIND_8_SUBBANDS_3_3 (int16_t)0xFCA8 /* 29 et 51 = 0xFCA86E7E */
+#define WIND_8_SUBBANDS_3_4 (int16_t)0xFFFA /* 13 et 67 = 0xFFFA2413 */
+#define WIND_8_SUBBANDS_4_0 (int16_t)0x001B /* 4 et 66 = 0x001AFF89 */
+#define WIND_8_SUBBANDS_4_1 (int16_t)0x01E0 /* 20 et 60 = 0x01E0224C */
+#define WIND_8_SUBBANDS_4_2 (int16_t)0x0FC7 /* 36 et 44 = 0x0FC721F9 */
+#define WIND_8_SUBBANDS_4_3 (int16_t)0xFE20 /* 28 et 52 = 0xFE20435D */
+#define WIND_8_SUBBANDS_4_4 (int16_t)0x001E /* 12 et 68 = 0x001D8FD2 */
+#define WIND_8_SUBBANDS_5_0 (int16_t)0x0025 /* 5 et 75 = 0x00255A62 */
+#define WIND_8_SUBBANDS_5_1 (int16_t)0x0209 /* 21 et 59 = 0x0209291F */
+#define WIND_8_SUBBANDS_5_2 (int16_t)0x110F /* 37 et 43 = 0x110ECEF0 */
+#define WIND_8_SUBBANDS_5_3 (int16_t)0xFF5F /* 27 et 53 = 0xFF5EEB73 */
+#define WIND_8_SUBBANDS_5_4 (int16_t)0x0035 /* 11 et 69 = 0x0034F8B6 */
+#define WIND_8_SUBBANDS_6_0 (int16_t)0x0030 /* 6 et 74 = 0x003060F4 */
+#define WIND_8_SUBBANDS_6_1 (int16_t)0x0214 /* 22 et 58 = 0x02138653 */
+#define WIND_8_SUBBANDS_6_2 (int16_t)0x1204 /* 38 et 42 = 0x120435FA */
+#define WIND_8_SUBBANDS_6_3 (int16_t)0x0060 /* 26 et 54 = 0x005FD0FF */
+#define WIND_8_SUBBANDS_6_4 (int16_t)0x0041 /* 10 et 70 = 0x00415B75 */
+#define WIND_8_SUBBANDS_7_0 (int16_t)0x003A /* 7 et 73 = 0x003A72E7 */
+#define WIND_8_SUBBANDS_7_1 (int16_t)0x01F6 /* 23 et 57 = 0x01F5F424 */
+#define WIND_8_SUBBANDS_7_2 (int16_t)0x129C /* 39 et 41 = 0x129C226F */
+#define WIND_8_SUBBANDS_7_3 (int16_t)0x0122 /* 25 et 55 = 0x01223EBA */
+#define WIND_8_SUBBANDS_7_4 (int16_t)0x0045 /* 9 et 71 = 0x0044EF48 */
+#define WIND_8_SUBBANDS_8_0 (int16_t)0x0042 /* 8 et 72 = 0x0041EC6A */
+#define WIND_8_SUBBANDS_8_1 (int16_t)0x01A8 /* 24 et 56 = 0x01A7ECEF */
+#define WIND_8_SUBBANDS_8_2 (int16_t)0x12CF /* 40 = 0x12CF6C75 */
+#endif
+
+#if (SBC_USE_ARM_PRAGMA == TRUE)
+#pragma arm section zidata = "sbc_s32_analysis_section"
+#endif
+static int32_t s32DCTY[16] = {0};
+static int32_t s32X[ENC_VX_BUFFER_SIZE / 2];
+static int16_t* s16X =
+ (int16_t*)s32X; /* s16X must be 32 bits aligned cf SHIFTUP_X8_2*/
+#if (SBC_USE_ARM_PRAGMA == TRUE)
+#pragma arm section zidata
+#endif
+
+/* This macro is for 4 subbands */
+#define SHIFTUP_X4 \
+ { \
+ ps32X = (int32_t*)(s16X + EncMaxShiftCounter + 38); \
+ for (i = 0; i < 9; i++) { \
+ *ps32X = *(ps32X - 2 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ *ps32X = *(ps32X - 2 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ } \
+ }
+#define SHIFTUP_X4_2 \
+ { \
+ ps32X = (int32_t*)(s16X + EncMaxShiftCounter + 38); \
+ ps32X2 = (int32_t*)(s16X + (EncMaxShiftCounter << 1) + 78); \
+ for (i = 0; i < 9; i++) { \
+ *ps32X = *(ps32X - 2 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 2 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ *ps32X = *(ps32X - 2 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 2 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ } \
+ }
+
+/* This macro is for 8 subbands */
+#define SHIFTUP_X8 \
+ { \
+ ps32X = (int32_t*)(s16X + EncMaxShiftCounter + 78); \
+ for (i = 0; i < 9; i++) { \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ } \
+ }
+#define SHIFTUP_X8_2 \
+ { \
+ ps32X = (int32_t*)(s16X + EncMaxShiftCounter + 78); \
+ ps32X2 = (int32_t*)(s16X + (EncMaxShiftCounter << 1) + 158); \
+ for (i = 0; i < 9; i++) { \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ *ps32X = *(ps32X - 4 - (ShiftCounter >> 1)); \
+ *(ps32X2) = *(ps32X2 - 4 - (ShiftCounter >> 1)); \
+ ps32X--; \
+ ps32X2--; \
+ } \
+ }
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define WINDOW_ACCU_8_0 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_0_1,(s16X[ChOffset+16]-s16X[ChOffset+64]);\
+ MLA s32Hi,WIND_8_SUBBANDS_0_2,(s16X[ChOffset+32]-s16X[ChOffset+48]),s32Hi;\
+ MOV s32DCTY[0],s32Hi; \
+ } \
+ }
+#define WINDOW_ACCU_8_1_15 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_1_0,s16X[ChOffset+1];\
+ MUL s32Hi2,WIND_8_SUBBANDS_1_0,s16X[ChOffset+64+15];\
+ MLA s32Hi,WIND_8_SUBBANDS_1_1,s16X[ChOffset+16+1],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_1_1,s16X[ChOffset+48+15],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+1],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+15],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_1_3,s16X[ChOffset+48+1],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_1_3,s16X[ChOffset+16+15],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_1_4,s16X[ChOffset+64+1],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_1_4,s16X[ChOffset+15],s32Hi2;\
+ MOV s32DCTY[1],s32Hi;\
+ MOV s32DCTY[15],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_2_14 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_2_0,s16X[ChOffset+2];\
+ MUL s32Hi2,WIND_8_SUBBANDS_2_0,s16X[ChOffset+64+14];\
+ MLA s32Hi,WIND_8_SUBBANDS_2_1,s16X[ChOffset+16+2],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_2_1,s16X[ChOffset+48+14],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+2],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+14],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_2_3,s16X[ChOffset+48+2],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_2_3,s16X[ChOffset+16+14],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_2_4,s16X[ChOffset+64+2],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_2_4,s16X[ChOffset+14],s32Hi2;\
+ MOV s32DCTY[2],s32Hi;\
+ MOV s32DCTY[14],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_3_13 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_3_0,s16X[ChOffset+3];\
+ MUL s32Hi2,WIND_8_SUBBANDS_3_0,s16X[ChOffset+64+13];\
+ MLA s32Hi,WIND_8_SUBBANDS_3_1,s16X[ChOffset+16+3],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_3_1,s16X[ChOffset+48+13],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+3],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+13],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_3_3,s16X[ChOffset+48+3],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_3_3,s16X[ChOffset+16+13],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_3_4,s16X[ChOffset+64+3],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_3_4,s16X[ChOffset+13],s32Hi2;\
+ MOV s32DCTY[3],s32Hi;\
+ MOV s32DCTY[13],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_4_12 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_4_0,s16X[ChOffset+4];\
+ MUL s32Hi2,WIND_8_SUBBANDS_4_0,s16X[ChOffset+64+12];\
+ MLA s32Hi,WIND_8_SUBBANDS_4_1,s16X[ChOffset+16+4],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_4_1,s16X[ChOffset+48+12],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+4],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+12],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_4_3,s16X[ChOffset+48+4],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_4_3,s16X[ChOffset+16+12],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_4_4,s16X[ChOffset+64+4],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_4_4,s16X[ChOffset+12],s32Hi2;\
+ MOV s32DCTY[4],s32Hi;\
+ MOV s32DCTY[12],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_5_11 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_5_0,s16X[ChOffset+5];\
+ MUL s32Hi2,WIND_8_SUBBANDS_5_0,s16X[ChOffset+64+11];\
+ MLA s32Hi,WIND_8_SUBBANDS_5_1,s16X[ChOffset+16+5],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_5_1,s16X[ChOffset+48+11],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+5],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+11],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_5_3,s16X[ChOffset+48+5],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_5_3,s16X[ChOffset+16+11],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_5_4,s16X[ChOffset+64+5],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_5_4,s16X[ChOffset+11],s32Hi2;\
+ MOV s32DCTY[5],s32Hi;\
+ MOV s32DCTY[11],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_6_10 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_6_0,s16X[ChOffset+6];\
+ MUL s32Hi2,WIND_8_SUBBANDS_6_0,s16X[ChOffset+64+10];\
+ MLA s32Hi,WIND_8_SUBBANDS_6_1,s16X[ChOffset+16+6],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_6_1,s16X[ChOffset+48+10],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+6],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+10],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_6_3,s16X[ChOffset+48+6],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_6_3,s16X[ChOffset+16+10],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_6_4,s16X[ChOffset+64+6],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_6_4,s16X[ChOffset+10],s32Hi2;\
+ MOV s32DCTY[6],s32Hi;\
+ MOV s32DCTY[10],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_7_9 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_7_0,s16X[ChOffset+7];\
+ MUL s32Hi2,WIND_8_SUBBANDS_7_0,s16X[ChOffset+64+9];\
+ MLA s32Hi,WIND_8_SUBBANDS_7_1,s16X[ChOffset+16+7],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_7_1,s16X[ChOffset+48+9],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+7],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+9],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_7_3,s16X[ChOffset+48+7],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_7_3,s16X[ChOffset+16+9],s32Hi2;\
+ MLA s32Hi,WIND_8_SUBBANDS_7_4,s16X[ChOffset+64+7],s32Hi;\
+ MLA s32Hi2,WIND_8_SUBBANDS_7_4,s16X[ChOffset+9],s32Hi2;\
+ MOV s32DCTY[7],s32Hi;\
+ MOV s32DCTY[9],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_8_8 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_8_SUBBANDS_8_0,(s16X[ChOffset+8]+s16X[ChOffset+8+64]);\
+ MLA s32Hi,WIND_8_SUBBANDS_8_1,(s16X[ChOffset+8+16]+s16X[ChOffset+8+64]),s32Hi;\
+ MLA s32Hi,WIND_8_SUBBANDS_8_2,s16X[ChOffset+8+32],s32Hi;\
+ MOV s32DCTY[8],s32Hi; \
+ } \
+ }
+#define WINDOW_ACCU_4_0 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_4_SUBBANDS_0_1,(s16X[ChOffset+8]-s16X[ChOffset+32]);\
+ MLA s32Hi,WIND_4_SUBBANDS_0_2,(s16X[ChOffset+16]-s16X[ChOffset+24]),s32Hi;\
+ MOV s32DCTY[0],s32Hi; \
+ } \
+ }
+#define WINDOW_ACCU_4_1_7 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_4_SUBBANDS_1_0,s16X[ChOffset+1];\
+ MUL s32Hi2,WIND_4_SUBBANDS_1_0,s16X[ChOffset+32+7];\
+ MLA s32Hi,WIND_4_SUBBANDS_1_1,s16X[ChOffset+8+1],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_1_1,s16X[ChOffset+24+7],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+1],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+7],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_1_3,s16X[ChOffset+24+1],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_1_3,s16X[ChOffset+8+7],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_1_4,s16X[ChOffset+32+1],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_1_4,s16X[ChOffset+7],s32Hi2;\
+ MOV s32DCTY[1],s32Hi;\
+ MOV s32DCTY[7],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_4_2_6 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_4_SUBBANDS_2_0,s16X[ChOffset+2];\
+ MUL s32Hi2,WIND_4_SUBBANDS_2_0,s16X[ChOffset+32+6];\
+ MLA s32Hi,WIND_4_SUBBANDS_2_1,s16X[ChOffset+8+2],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_2_1,s16X[ChOffset+24+6],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+2],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+6],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_2_3,s16X[ChOffset+24+2],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_2_3,s16X[ChOffset+8+6],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_2_4,s16X[ChOffset+32+2],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_2_4,s16X[ChOffset+6],s32Hi2;\
+ MOV s32DCTY[2],s32Hi;\
+ MOV s32DCTY[6],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_4_3_5 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_4_SUBBANDS_3_0,s16X[ChOffset+3];\
+ MUL s32Hi2,WIND_4_SUBBANDS_3_0,s16X[ChOffset+32+5];\
+ MLA s32Hi,WIND_4_SUBBANDS_3_1,s16X[ChOffset+8+3],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_3_1,s16X[ChOffset+24+5],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+3],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+5],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_3_3,s16X[ChOffset+24+3],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_3_3,s16X[ChOffset+8+5],s32Hi2;\
+ MLA s32Hi,WIND_4_SUBBANDS_3_4,s16X[ChOffset+32+3],s32Hi;\
+ MLA s32Hi2,WIND_4_SUBBANDS_3_4,s16X[ChOffset+5],s32Hi2;\
+ MOV s32DCTY[3],s32Hi;\
+ MOV s32DCTY[5],s32Hi2; \
+ } \
+ }
+#define WINDOW_ACCU_4_4 \
+ { \
+ __asm {\
+ MUL s32Hi,WIND_4_SUBBANDS_4_0,(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\
+ MLA s32Hi,WIND_4_SUBBANDS_4_1,(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]),s32Hi;\
+ MLA s32Hi,WIND_4_SUBBANDS_4_2,s16X[ChOffset+4+16],s32Hi;\
+ MOV s32DCTY[4],s32Hi; \
+ } \
+ }
+
+#define WINDOW_PARTIAL_4 \
+ { \
+ WINDOW_ACCU_4_0; \
+ WINDOW_ACCU_4_1_7; \
+ WINDOW_ACCU_4_2_6; \
+ WINDOW_ACCU_4_3_5; \
+ WINDOW_ACCU_4_4; \
+ }
+
+#define WINDOW_PARTIAL_8 \
+ { \
+ WINDOW_ACCU_8_0; \
+ WINDOW_ACCU_8_1_15; \
+ WINDOW_ACCU_8_2_14; \
+ WINDOW_ACCU_8_3_13; \
+ WINDOW_ACCU_8_4_12; \
+ WINDOW_ACCU_8_5_11; \
+ WINDOW_ACCU_8_6_10; \
+ WINDOW_ACCU_8_7_9; \
+ WINDOW_ACCU_8_8; \
+ }
+
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_8_0 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_0_1 * \
+ (int64_t)(s16X[ChOffset + 16] - s16X[ChOffset + 64]); \
+ s64Temp += (int64_t)WIND_8_SUBBANDS_0_2 * \
+ (int64_t)(s16X[ChOffset + 32] - s16X[ChOffset + 48]); \
+ s32DCTY[0] = (int32_t)(s64Temp >> 16); \
+ }
+#define WINDOW_ACCU_8_1_15 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_1_0 * (int64_t)s16X[ChOffset + 1]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_1_0 * (int64_t)s16X[ChOffset + 64 + 15]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_1_1 * (int64_t)s16X[ChOffset + 16 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_1_1 * (int64_t)s16X[ChOffset + 48 + 15]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_1_2 * (int64_t)s16X[ChOffset + 32 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_1_2 * (int64_t)s16X[ChOffset + 32 + 15]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_1_3 * (int64_t)s16X[ChOffset + 48 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_1_3 * (int64_t)s16X[ChOffset + 16 + 15]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_1_4 * (int64_t)s16X[ChOffset + 64 + 1]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_1_4 * (int64_t)s16X[ChOffset + 15]; \
+ s32DCTY[1] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[15] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_2_14 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_2_0 * (int64_t)s16X[ChOffset + 2]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_2_0 * (int64_t)s16X[ChOffset + 64 + 14]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_2_1 * (int64_t)s16X[ChOffset + 16 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_2_1 * (int64_t)s16X[ChOffset + 48 + 14]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_2_2 * (int64_t)s16X[ChOffset + 32 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_2_2 * (int64_t)s16X[ChOffset + 32 + 14]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_2_3 * (int64_t)s16X[ChOffset + 48 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_2_3 * (int64_t)s16X[ChOffset + 16 + 14]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_2_4 * (int64_t)s16X[ChOffset + 64 + 2]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_2_4 * (int64_t)s16X[ChOffset + 14]; \
+ s32DCTY[2] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[14] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_3_13 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_3_0 * (int64_t)s16X[ChOffset + 3]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_3_0 * (int64_t)s16X[ChOffset + 64 + 13]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_3_1 * (int64_t)s16X[ChOffset + 16 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_3_1 * (int64_t)s16X[ChOffset + 48 + 13]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_3_2 * (int64_t)s16X[ChOffset + 32 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_3_2 * (int64_t)s16X[ChOffset + 32 + 13]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_3_3 * (int64_t)s16X[ChOffset + 48 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_3_3 * (int64_t)s16X[ChOffset + 16 + 13]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_3_4 * (int64_t)s16X[ChOffset + 64 + 3]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_3_4 * (int64_t)s16X[ChOffset + 13]; \
+ s32DCTY[3] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[13] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_4_12 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_4_0 * (int64_t)s16X[ChOffset + 4]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_4_0 * (int64_t)s16X[ChOffset + 64 + 12]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_4_1 * (int64_t)s16X[ChOffset + 16 + 4]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_4_1 * (int64_t)s16X[ChOffset + 48 + 12]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_4_2 * (int64_t)s16X[ChOffset + 32 + 4]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_4_2 * (int64_t)s16X[ChOffset + 32 + 12]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_4_3 * (int64_t)s16X[ChOffset + 48 + 4]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_4_3 * (int64_t)s16X[ChOffset + 16 + 12]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_4_4 * (int64_t)s16X[ChOffset + 64 + 4]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_4_4 * (int64_t)s16X[ChOffset + 12]; \
+ s32DCTY[4] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[12] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_5_11 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_5_0 * (int64_t)s16X[ChOffset + 5]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_5_0 * (int64_t)s16X[ChOffset + 64 + 11]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_5_1 * (int64_t)s16X[ChOffset + 16 + 5]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_5_1 * (int64_t)s16X[ChOffset + 48 + 11]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_5_2 * (int64_t)s16X[ChOffset + 32 + 5]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_5_2 * (int64_t)s16X[ChOffset + 32 + 11]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_5_3 * (int64_t)s16X[ChOffset + 48 + 5]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_5_3 * (int64_t)s16X[ChOffset + 16 + 11]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_5_4 * (int64_t)s16X[ChOffset + 64 + 5]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_5_4 * (int64_t)s16X[ChOffset + 11]; \
+ s32DCTY[5] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[11] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_6_10 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_6_0 * (int64_t)s16X[ChOffset + 6]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_6_0 * (int64_t)s16X[ChOffset + 64 + 10]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_6_1 * (int64_t)s16X[ChOffset + 16 + 6]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_6_1 * (int64_t)s16X[ChOffset + 48 + 10]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_6_2 * (int64_t)s16X[ChOffset + 32 + 6]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_6_2 * (int64_t)s16X[ChOffset + 32 + 10]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_6_3 * (int64_t)s16X[ChOffset + 48 + 6]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_6_3 * (int64_t)s16X[ChOffset + 16 + 10]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_6_4 * (int64_t)s16X[ChOffset + 64 + 6]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_6_4 * (int64_t)s16X[ChOffset + 10]; \
+ s32DCTY[6] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[10] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_7_9 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_7_0 * (int64_t)s16X[ChOffset + 7]; \
+ s64Temp2 = \
+ (int64_t)WIND_8_SUBBANDS_7_0 * (int64_t)s16X[ChOffset + 64 + 9]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_7_1 * (int64_t)s16X[ChOffset + 16 + 7]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_7_1 * (int64_t)s16X[ChOffset + 48 + 9]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_7_2 * (int64_t)s16X[ChOffset + 32 + 7]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_7_2 * (int64_t)s16X[ChOffset + 32 + 9]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_7_3 * (int64_t)s16X[ChOffset + 48 + 7]; \
+ s64Temp2 += \
+ (int64_t)WIND_8_SUBBANDS_7_3 * (int64_t)s16X[ChOffset + 16 + 9]; \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_7_4 * (int64_t)s16X[ChOffset + 64 + 7]; \
+ s64Temp2 += (int64_t)WIND_8_SUBBANDS_7_4 * (int64_t)s16X[ChOffset + 9]; \
+ s32DCTY[7] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[9] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_8_8 \
+ { \
+ s64Temp = (int64_t)WIND_8_SUBBANDS_8_0 * \
+ (int64_t)(s16X[ChOffset + 8] + s16X[ChOffset + 64 + 8]); \
+ s64Temp += (int64_t)WIND_8_SUBBANDS_8_1 * \
+ (int64_t)(s16X[ChOffset + 16 + 8] + s16X[ChOffset + 48 + 8]); \
+ s64Temp += \
+ (int64_t)WIND_8_SUBBANDS_8_2 * (int64_t)s16X[ChOffset + 32 + 8]; \
+ s32DCTY[8] = (int32_t)(s64Temp >> 16); \
+ }
+#define WINDOW_ACCU_4_0 \
+ { \
+ s64Temp = (int64_t)WIND_4_SUBBANDS_0_1 * \
+ (int64_t)(s16X[ChOffset + 8] - s16X[ChOffset + 32]); \
+ s64Temp += (int64_t)WIND_4_SUBBANDS_0_2 * \
+ (int64_t)(s16X[ChOffset + 16] - s16X[ChOffset + 24]); \
+ s32DCTY[0] = (int32_t)(s64Temp >> 16); \
+ }
+#define WINDOW_ACCU_4_1_7 \
+ { \
+ s64Temp = (int64_t)WIND_4_SUBBANDS_1_0 * (int64_t)s16X[ChOffset + 1]; \
+ s64Temp2 = \
+ (int64_t)WIND_4_SUBBANDS_1_0 * (int64_t)s16X[ChOffset + 32 + 7]; \
+ s64Temp += (int64_t)WIND_4_SUBBANDS_1_1 * (int64_t)s16X[ChOffset + 8 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_1_1 * (int64_t)s16X[ChOffset + 24 + 7]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_1_2 * (int64_t)s16X[ChOffset + 16 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_1_2 * (int64_t)s16X[ChOffset + 16 + 7]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_1_3 * (int64_t)s16X[ChOffset + 24 + 1]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_1_3 * (int64_t)s16X[ChOffset + 8 + 7]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_1_4 * (int64_t)s16X[ChOffset + 32 + 1]; \
+ s64Temp2 += (int64_t)WIND_4_SUBBANDS_1_4 * (int64_t)s16X[ChOffset + 7]; \
+ s32DCTY[1] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[7] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_4_2_6 \
+ { \
+ s64Temp = (int64_t)WIND_4_SUBBANDS_2_0 * (int64_t)s16X[ChOffset + 2]; \
+ s64Temp2 = \
+ (int64_t)WIND_4_SUBBANDS_2_0 * (int64_t)s16X[ChOffset + 32 + 6]; \
+ s64Temp += (int64_t)WIND_4_SUBBANDS_2_1 * (int64_t)s16X[ChOffset + 8 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_2_1 * (int64_t)s16X[ChOffset + 24 + 6]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_2_2 * (int64_t)s16X[ChOffset + 16 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_2_2 * (int64_t)s16X[ChOffset + 16 + 6]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_2_3 * (int64_t)s16X[ChOffset + 24 + 2]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_2_3 * (int64_t)s16X[ChOffset + 8 + 6]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_2_4 * (int64_t)s16X[ChOffset + 32 + 2]; \
+ s64Temp2 += (int64_t)WIND_4_SUBBANDS_2_4 * (int64_t)s16X[ChOffset + 6]; \
+ s32DCTY[2] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[6] = (int32_t)(s64Temp2 >> 16); \
+ }
+#define WINDOW_ACCU_4_3_5 \
+ { \
+ s64Temp = (int64_t)WIND_4_SUBBANDS_3_0 * (int64_t)s16X[ChOffset + 3]; \
+ s64Temp2 = \
+ (int64_t)WIND_4_SUBBANDS_3_0 * (int64_t)s16X[ChOffset + 32 + 5]; \
+ s64Temp += (int64_t)WIND_4_SUBBANDS_3_1 * (int64_t)s16X[ChOffset + 8 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_3_1 * (int64_t)s16X[ChOffset + 24 + 5]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_3_2 * (int64_t)s16X[ChOffset + 16 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_3_2 * (int64_t)s16X[ChOffset + 16 + 5]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_3_3 * (int64_t)s16X[ChOffset + 24 + 3]; \
+ s64Temp2 += \
+ (int64_t)WIND_4_SUBBANDS_3_3 * (int64_t)s16X[ChOffset + 8 + 5]; \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_3_4 * (int64_t)s16X[ChOffset + 32 + 3]; \
+ s64Temp2 += (int64_t)WIND_4_SUBBANDS_3_4 * (int64_t)s16X[ChOffset + 5]; \
+ s32DCTY[3] = (int32_t)(s64Temp >> 16); \
+ s32DCTY[5] = (int32_t)(s64Temp2 >> 16); \
+ }
+
+#define WINDOW_ACCU_4_4 \
+ { \
+ s64Temp = (int64_t)WIND_4_SUBBANDS_4_0 * \
+ (int64_t)(s16X[ChOffset + 4] + s16X[ChOffset + 4 + 32]); \
+ s64Temp += (int64_t)WIND_4_SUBBANDS_4_1 * \
+ (int64_t)(s16X[ChOffset + 4 + 8] + s16X[ChOffset + 4 + 24]); \
+ s64Temp += \
+ (int64_t)WIND_4_SUBBANDS_4_2 * (int64_t)s16X[ChOffset + 4 + 16]; \
+ s32DCTY[4] = (int32_t)(s64Temp >> 16); \
+ }
+#else /* SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE */
+#define WINDOW_ACCU_8_0 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_0_1 * \
+ (int32_t)(s16X[ChOffset + 16] - s16X[ChOffset + 64]); \
+ s32Temp += (int32_t)WIND_8_SUBBANDS_0_2 * \
+ (int32_t)(s16X[ChOffset + 32] - s16X[ChOffset + 48]); \
+ s32DCTY[0] = (int32_t)s32Temp; \
+ }
+#define WINDOW_ACCU_8_1_15 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_1_0 * (int32_t)s16X[ChOffset + 1]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_1_0 * (int32_t)s16X[ChOffset + 64 + 15]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_1_1 * (int32_t)s16X[ChOffset + 16 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_1_1 * (int32_t)s16X[ChOffset + 48 + 15]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_1_2 * (int32_t)s16X[ChOffset + 32 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_1_2 * (int32_t)s16X[ChOffset + 32 + 15]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_1_3 * (int32_t)s16X[ChOffset + 48 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_1_3 * (int32_t)s16X[ChOffset + 16 + 15]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_1_4 * (int32_t)s16X[ChOffset + 64 + 1]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_1_4 * (int32_t)s16X[ChOffset + 15]; \
+ s32DCTY[1] = (int32_t)s32Temp; \
+ s32DCTY[15] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_2_14 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_2_0 * (int32_t)s16X[ChOffset + 2]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_2_0 * (int32_t)s16X[ChOffset + 64 + 14]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_2_1 * (int32_t)s16X[ChOffset + 16 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_2_1 * (int32_t)s16X[ChOffset + 48 + 14]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_2_2 * (int32_t)s16X[ChOffset + 32 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_2_2 * (int32_t)s16X[ChOffset + 32 + 14]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_2_3 * (int32_t)s16X[ChOffset + 48 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_2_3 * (int32_t)s16X[ChOffset + 16 + 14]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_2_4 * (int32_t)s16X[ChOffset + 64 + 2]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_2_4 * (int32_t)s16X[ChOffset + 14]; \
+ s32DCTY[2] = (int32_t)s32Temp; \
+ s32DCTY[14] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_3_13 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_3_0 * (int32_t)s16X[ChOffset + 3]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_3_0 * (int32_t)s16X[ChOffset + 64 + 13]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_3_1 * (int32_t)s16X[ChOffset + 16 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_3_1 * (int32_t)s16X[ChOffset + 48 + 13]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_3_2 * (int32_t)s16X[ChOffset + 32 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_3_2 * (int32_t)s16X[ChOffset + 32 + 13]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_3_3 * (int32_t)s16X[ChOffset + 48 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_3_3 * (int32_t)s16X[ChOffset + 16 + 13]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_3_4 * (int32_t)s16X[ChOffset + 64 + 3]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_3_4 * (int32_t)s16X[ChOffset + 13]; \
+ s32DCTY[3] = (int32_t)s32Temp; \
+ s32DCTY[13] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_4_12 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_4_0 * (int32_t)s16X[ChOffset + 4]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_4_0 * (int32_t)s16X[ChOffset + 64 + 12]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_4_1 * (int32_t)s16X[ChOffset + 16 + 4]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_4_1 * (int32_t)s16X[ChOffset + 48 + 12]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_4_2 * (int32_t)s16X[ChOffset + 32 + 4]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_4_2 * (int32_t)s16X[ChOffset + 32 + 12]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_4_3 * (int32_t)s16X[ChOffset + 48 + 4]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_4_3 * (int32_t)s16X[ChOffset + 16 + 12]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_4_4 * (int32_t)s16X[ChOffset + 64 + 4]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_4_4 * (int32_t)s16X[ChOffset + 12]; \
+ s32DCTY[4] = (int32_t)s32Temp; \
+ s32DCTY[12] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_5_11 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_5_0 * (int32_t)s16X[ChOffset + 5]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_5_0 * (int32_t)s16X[ChOffset + 64 + 11]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_5_1 * (int32_t)s16X[ChOffset + 16 + 5]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_5_1 * (int32_t)s16X[ChOffset + 48 + 11]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_5_2 * (int32_t)s16X[ChOffset + 32 + 5]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_5_2 * (int32_t)s16X[ChOffset + 32 + 11]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_5_3 * (int32_t)s16X[ChOffset + 48 + 5]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_5_3 * (int32_t)s16X[ChOffset + 16 + 11]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_5_4 * (int32_t)s16X[ChOffset + 64 + 5]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_5_4 * (int32_t)s16X[ChOffset + 11]; \
+ s32DCTY[5] = (int32_t)s32Temp; \
+ s32DCTY[11] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_6_10 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_6_0 * (int32_t)s16X[ChOffset + 6]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_6_0 * (int32_t)s16X[ChOffset + 64 + 10]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_6_1 * (int32_t)s16X[ChOffset + 16 + 6]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_6_1 * (int32_t)s16X[ChOffset + 48 + 10]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_6_2 * (int32_t)s16X[ChOffset + 32 + 6]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_6_2 * (int32_t)s16X[ChOffset + 32 + 10]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_6_3 * (int32_t)s16X[ChOffset + 48 + 6]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_6_3 * (int32_t)s16X[ChOffset + 16 + 10]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_6_4 * (int32_t)s16X[ChOffset + 64 + 6]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_6_4 * (int32_t)s16X[ChOffset + 10]; \
+ s32DCTY[6] = (int32_t)s32Temp; \
+ s32DCTY[10] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_7_9 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_7_0 * (int32_t)s16X[ChOffset + 7]; \
+ s32Temp2 = \
+ (int32_t)WIND_8_SUBBANDS_7_0 * (int32_t)s16X[ChOffset + 64 + 9]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_7_1 * (int32_t)s16X[ChOffset + 16 + 7]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_7_1 * (int32_t)s16X[ChOffset + 48 + 9]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_7_2 * (int32_t)s16X[ChOffset + 32 + 7]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_7_2 * (int32_t)s16X[ChOffset + 32 + 9]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_7_3 * (int32_t)s16X[ChOffset + 48 + 7]; \
+ s32Temp2 += \
+ (int32_t)WIND_8_SUBBANDS_7_3 * (int32_t)s16X[ChOffset + 16 + 9]; \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_7_4 * (int32_t)s16X[ChOffset + 64 + 7]; \
+ s32Temp2 += (int32_t)WIND_8_SUBBANDS_7_4 * (int32_t)s16X[ChOffset + 9]; \
+ s32DCTY[7] = (int32_t)s32Temp; \
+ s32DCTY[9] = (int32_t)s32Temp2; \
+ }
+#define WINDOW_ACCU_8_8 \
+ { \
+ s32Temp = (int32_t)WIND_8_SUBBANDS_8_0 * \
+ (int32_t)(s16X[ChOffset + 8] + s16X[ChOffset + 64 + 8]); \
+ s32Temp += (int32_t)WIND_8_SUBBANDS_8_1 * \
+ (int32_t)(s16X[ChOffset + 16 + 8] + s16X[ChOffset + 48 + 8]); \
+ s32Temp += \
+ (int32_t)WIND_8_SUBBANDS_8_2 * (int32_t)s16X[ChOffset + 32 + 8]; \
+ s32DCTY[8] = (int32_t)s32Temp; \
+ }
+#define WINDOW_ACCU_4_0 \
+ { \
+ s32Temp = (int32_t)WIND_4_SUBBANDS_0_1 * \
+ (int32_t)(s16X[ChOffset + 8] - s16X[ChOffset + 32]); \
+ s32Temp += (int32_t)WIND_4_SUBBANDS_0_2 * \
+ (int32_t)(s16X[ChOffset + 16] - s16X[ChOffset + 24]); \
+ s32DCTY[0] = (int32_t)(s32Temp); \
+ }
+#define WINDOW_ACCU_4_1_7 \
+ { \
+ s32Temp = (int32_t)WIND_4_SUBBANDS_1_0 * (int32_t)s16X[ChOffset + 1]; \
+ s32Temp2 = \
+ (int32_t)WIND_4_SUBBANDS_1_0 * (int32_t)s16X[ChOffset + 32 + 7]; \
+ s32Temp += (int32_t)WIND_4_SUBBANDS_1_1 * (int32_t)s16X[ChOffset + 8 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_1_1 * (int32_t)s16X[ChOffset + 24 + 7]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_1_2 * (int32_t)s16X[ChOffset + 16 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_1_2 * (int32_t)s16X[ChOffset + 16 + 7]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_1_3 * (int32_t)s16X[ChOffset + 24 + 1]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_1_3 * (int32_t)s16X[ChOffset + 8 + 7]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_1_4 * (int32_t)s16X[ChOffset + 32 + 1]; \
+ s32Temp2 += (int32_t)WIND_4_SUBBANDS_1_4 * (int32_t)s16X[ChOffset + 7]; \
+ s32DCTY[1] = (int32_t)(s32Temp); \
+ s32DCTY[7] = (int32_t)(s32Temp2); \
+ }
+#define WINDOW_ACCU_4_2_6 \
+ { \
+ s32Temp = (int32_t)WIND_4_SUBBANDS_2_0 * (int32_t)s16X[ChOffset + 2]; \
+ s32Temp2 = \
+ (int32_t)WIND_4_SUBBANDS_2_0 * (int32_t)s16X[ChOffset + 32 + 6]; \
+ s32Temp += (int32_t)WIND_4_SUBBANDS_2_1 * (int32_t)s16X[ChOffset + 8 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_2_1 * (int32_t)s16X[ChOffset + 24 + 6]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_2_2 * (int32_t)s16X[ChOffset + 16 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_2_2 * (int32_t)s16X[ChOffset + 16 + 6]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_2_3 * (int32_t)s16X[ChOffset + 24 + 2]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_2_3 * (int32_t)s16X[ChOffset + 8 + 6]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_2_4 * (int32_t)s16X[ChOffset + 32 + 2]; \
+ s32Temp2 += (int32_t)WIND_4_SUBBANDS_2_4 * (int32_t)s16X[ChOffset + 6]; \
+ s32DCTY[2] = (int32_t)(s32Temp); \
+ s32DCTY[6] = (int32_t)(s32Temp2); \
+ }
+#define WINDOW_ACCU_4_3_5 \
+ { \
+ s32Temp = (int32_t)WIND_4_SUBBANDS_3_0 * (int32_t)s16X[ChOffset + 3]; \
+ s32Temp2 = \
+ (int32_t)WIND_4_SUBBANDS_3_0 * (int32_t)s16X[ChOffset + 32 + 5]; \
+ s32Temp += (int32_t)WIND_4_SUBBANDS_3_1 * (int32_t)s16X[ChOffset + 8 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_3_1 * (int32_t)s16X[ChOffset + 24 + 5]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_3_2 * (int32_t)s16X[ChOffset + 16 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_3_2 * (int32_t)s16X[ChOffset + 16 + 5]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_3_3 * (int32_t)s16X[ChOffset + 24 + 3]; \
+ s32Temp2 += \
+ (int32_t)WIND_4_SUBBANDS_3_3 * (int32_t)s16X[ChOffset + 8 + 5]; \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_3_4 * (int32_t)s16X[ChOffset + 32 + 3]; \
+ s32Temp2 += (int32_t)WIND_4_SUBBANDS_3_4 * (int32_t)s16X[ChOffset + 5]; \
+ s32DCTY[3] = (int32_t)(s32Temp); \
+ s32DCTY[5] = (int32_t)(s32Temp2); \
+ }
+
+#define WINDOW_ACCU_4_4 \
+ { \
+ s32Temp = (int32_t)WIND_4_SUBBANDS_4_0 * \
+ (int32_t)(s16X[ChOffset + 4] + s16X[ChOffset + 4 + 32]); \
+ s32Temp += (int32_t)WIND_4_SUBBANDS_4_1 * \
+ (int32_t)(s16X[ChOffset + 4 + 8] + s16X[ChOffset + 4 + 24]); \
+ s32Temp += \
+ (int32_t)WIND_4_SUBBANDS_4_2 * (int32_t)s16X[ChOffset + 4 + 16]; \
+ s32DCTY[4] = (int32_t)(s32Temp); \
+ }
+#endif
+#define WINDOW_PARTIAL_4 \
+ { \
+ WINDOW_ACCU_4_0; \
+ WINDOW_ACCU_4_1_7; \
+ WINDOW_ACCU_4_2_6; \
+ WINDOW_ACCU_4_3_5; \
+ WINDOW_ACCU_4_4; \
+ }
+
+#define WINDOW_PARTIAL_8 \
+ { \
+ WINDOW_ACCU_8_0; \
+ WINDOW_ACCU_8_1_15; \
+ WINDOW_ACCU_8_2_14; \
+ WINDOW_ACCU_8_3_13; \
+ WINDOW_ACCU_8_4_12; \
+ WINDOW_ACCU_8_5_11; \
+ WINDOW_ACCU_8_6_10; \
+ WINDOW_ACCU_8_7_9; \
+ WINDOW_ACCU_8_8; \
+ }
+#else
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_4(i) \
+ { \
+ s64Temp = ((int64_t)gas32CoeffFor4SBs[i] * (int64_t)s16X[ChOffset + i]); \
+ s64Temp += ((int64_t)gas32CoeffFor4SBs[(i + 8)] * \
+ (int64_t)s16X[ChOffset + i + 8]); \
+ s64Temp += ((int64_t)gas32CoeffFor4SBs[(i + 16)] * \
+ (int64_t)s16X[ChOffset + i + 16]); \
+ s64Temp += ((int64_t)gas32CoeffFor4SBs[(i + 24)] * \
+ (int64_t)s16X[ChOffset + i + 24]); \
+ s64Temp += ((int64_t)gas32CoeffFor4SBs[(i + 32)] * \
+ (int64_t)s16X[ChOffset + i + 32]); \
+ s32DCTY[i] = (int32_t)(s64Temp >> 16); \
+ /*printf("s32DCTY4: 0x%x \n", s32DCTY[i]);*/ \
+ }
+#else
+#define WINDOW_ACCU_4(i) \
+ { \
+ s32DCTY[i] = (gas32CoeffFor4SBs[i * 2] * s16X[ChOffset + i]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor4SBs[(i * 2) + 1]) * \
+ s16X[ChOffset + i]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor4SBs[(i + 8) * 2] * s16X[ChOffset + i + 8]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i + 8) * 2) + 1]) * \
+ s16X[ChOffset + i + 8]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor4SBs[(i + 16) * 2] * s16X[ChOffset + i + 16]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i + 16) * 2) + 1]) * \
+ s16X[ChOffset + i + 16]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor4SBs[(i + 24) * 2] * s16X[ChOffset + i + 24]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i + 24) * 2) + 1]) * \
+ s16X[ChOffset + i + 24]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor4SBs[(i + 32) * 2] * s16X[ChOffset + i + 32]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor4SBs[((i + 32) * 2) + 1]) * \
+ s16X[ChOffset + i + 32]) >> \
+ 16); \
+ }
+#endif
+#define WINDOW_PARTIAL_4 \
+ { \
+ WINDOW_ACCU_4(0); \
+ WINDOW_ACCU_4(1); \
+ WINDOW_ACCU_4(2); \
+ WINDOW_ACCU_4(3); \
+ WINDOW_ACCU_4(4); \
+ WINDOW_ACCU_4(5); \
+ WINDOW_ACCU_4(6); \
+ WINDOW_ACCU_4(7); \
+ }
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+#define WINDOW_ACCU_8(i) \
+ { \
+ s64Temp = \
+ ((((int64_t)gas32CoeffFor8SBs[i] * (int64_t)s16X[ChOffset + i]))); \
+ s64Temp += ((((int64_t)gas32CoeffFor8SBs[(i + 16)] * \
+ (int64_t)s16X[ChOffset + i + 16]))); \
+ s64Temp += ((((int64_t)gas32CoeffFor8SBs[(i + 32)] * \
+ (int64_t)s16X[ChOffset + i + 32]))); \
+ s64Temp += ((((int64_t)gas32CoeffFor8SBs[(i + 48)] * \
+ (int64_t)s16X[ChOffset + i + 48]))); \
+ s64Temp += ((((int64_t)gas32CoeffFor8SBs[(i + 64)] * \
+ (int64_t)s16X[ChOffset + i + 64]))); \
+ /*printf("s32DCTY8: %d= 0x%x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i], \
+ * s16X[ChOffset+i]);*/ \
+ s32DCTY[i] = (int32_t)(s64Temp >> 16); \
+ }
+#else
+#define WINDOW_ACCU_8(i) \
+ { \
+ s32DCTY[i] = (gas32CoeffFor8SBs[i * 2] * s16X[ChOffset + i]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor8SBs[(i * 2) + 1]) * \
+ s16X[ChOffset + i]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor8SBs[(i + 16) * 2] * s16X[ChOffset + i + 16]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i + 16) * 2) + 1]) * \
+ s16X[ChOffset + i + 16]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor8SBs[(i + 32) * 2] * s16X[ChOffset + i + 32]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i + 32) * 2) + 1]) * \
+ s16X[ChOffset + i + 32]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor8SBs[(i + 48) * 2] * s16X[ChOffset + i + 48]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i + 48) * 2) + 1]) * \
+ s16X[ChOffset + i + 48]) >> \
+ 16); \
+ s32DCTY[i] += \
+ (gas32CoeffFor8SBs[(i + 64) * 2] * s16X[ChOffset + i + 64]) + \
+ (((int32_t)(uint16_t)(gas32CoeffFor8SBs[((i + 64) * 2) + 1]) * \
+ s16X[ChOffset + i + 64]) >> \
+ 16); \
+ /*printf("s32DCTY8: %d = 0x%4x%4x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i \
+ * * 2], (gas32CoeffFor8SBs[(i * 2) + 1]), s16X[ChOffset+i]);*/ \
+ /*s32DCTY[i]=(int32_t)(s64Temp>>16);*/ \
+ }
+#endif
+#define WINDOW_PARTIAL_8 \
+ { \
+ WINDOW_ACCU_8(0); \
+ WINDOW_ACCU_8(1); \
+ WINDOW_ACCU_8(2); \
+ WINDOW_ACCU_8(3); \
+ WINDOW_ACCU_8(4); \
+ WINDOW_ACCU_8(5); \
+ WINDOW_ACCU_8(6); \
+ WINDOW_ACCU_8(7); \
+ WINDOW_ACCU_8(8); \
+ WINDOW_ACCU_8(9); \
+ WINDOW_ACCU_8(10); \
+ WINDOW_ACCU_8(11); \
+ WINDOW_ACCU_8(12); \
+ WINDOW_ACCU_8(13); \
+ WINDOW_ACCU_8(14); \
+ WINDOW_ACCU_8(15); \
+ }
+#endif
+#endif
+
+static int16_t ShiftCounter = 0;
+extern int16_t EncMaxShiftCounter;
+/****************************************************************************
+* SbcAnalysisFilter - performs Analysis of the input audio stream
+*
+* RETURNS : N/A
+*/
+void SbcAnalysisFilter4(SBC_ENC_PARAMS* pstrEncParams, int16_t* input) {
+ int16_t* ps16PcmBuf;
+ int32_t* ps32SbBuf;
+ int32_t s32Blk, s32Ch;
+ int32_t s32NumOfChannels, s32NumOfBlocks;
+ int32_t i, *ps32X, *ps32X2;
+ int32_t Offset, Offset2, ChOffset;
+#if (SBC_ARM_ASM_OPT == TRUE)
+ register int32_t s32Hi, s32Hi2;
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+ register int64_t s64Temp, s64Temp2;
+#else
+ register int32_t s32Temp, s32Temp2;
+#endif
+#else
+
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+ int64_t s64Temp;
+#endif
+
+#endif
+#endif
+
+ s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+ s32NumOfBlocks = pstrEncParams->s16NumOfBlocks;
+
+ ps16PcmBuf = input;
+
+ ps32SbBuf = pstrEncParams->s32SbBuffer;
+ Offset2 = (int32_t)(EncMaxShiftCounter + 40);
+ for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) {
+ Offset = (int32_t)(EncMaxShiftCounter - ShiftCounter);
+ /* Store new samples */
+ if (s32NumOfChannels == 1) {
+ s16X[3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ } else {
+ s16X[3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ }
+ for (s32Ch = 0; s32Ch < s32NumOfChannels; s32Ch++) {
+ ChOffset = s32Ch * Offset2 + Offset;
+
+ WINDOW_PARTIAL_4
+
+ SBC_FastIDCT4(s32DCTY, ps32SbBuf);
+
+ ps32SbBuf += SUB_BANDS_4;
+ }
+ if (s32NumOfChannels == 1) {
+ if (ShiftCounter >= EncMaxShiftCounter) {
+ SHIFTUP_X4;
+ ShiftCounter = 0;
+ } else {
+ ShiftCounter += SUB_BANDS_4;
+ }
+ } else {
+ if (ShiftCounter >= EncMaxShiftCounter) {
+ SHIFTUP_X4_2;
+ ShiftCounter = 0;
+ } else {
+ ShiftCounter += SUB_BANDS_4;
+ }
+ }
+ }
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+void SbcAnalysisFilter8(SBC_ENC_PARAMS* pstrEncParams, int16_t* input) {
+ int16_t* ps16PcmBuf;
+ int32_t* ps32SbBuf;
+ int32_t s32Blk, s32Ch; /* counter for block*/
+ int32_t Offset, Offset2;
+ int32_t s32NumOfChannels, s32NumOfBlocks;
+ int32_t i, *ps32X, *ps32X2;
+ int32_t ChOffset;
+#if (SBC_ARM_ASM_OPT == TRUE)
+ register int32_t s32Hi, s32Hi2;
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+ register int64_t s64Temp, s64Temp2;
+#else
+ register int32_t s32Temp, s32Temp2;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE)
+ int64_t s64Temp;
+#endif
+#endif
+#endif
+
+ s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+ s32NumOfBlocks = pstrEncParams->s16NumOfBlocks;
+
+ ps16PcmBuf = input;
+
+ ps32SbBuf = pstrEncParams->s32SbBuffer;
+ Offset2 = (int32_t)(EncMaxShiftCounter + 80);
+ for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) {
+ Offset = (int32_t)(EncMaxShiftCounter - ShiftCounter);
+ /* Store new samples */
+ if (s32NumOfChannels == 1) {
+ s16X[7 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[6 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[5 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[4 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ } else {
+ s16X[7 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 7 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[6 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 6 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[5 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 5 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[4 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 4 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 3 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 2 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 1 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ s16X[Offset2 + 0 + Offset] = *ps16PcmBuf;
+ ps16PcmBuf++;
+ }
+ for (s32Ch = 0; s32Ch < s32NumOfChannels; s32Ch++) {
+ ChOffset = s32Ch * Offset2 + Offset;
+
+ WINDOW_PARTIAL_8
+
+ SBC_FastIDCT8(s32DCTY, ps32SbBuf);
+
+ ps32SbBuf += SUB_BANDS_8;
+ }
+ if (s32NumOfChannels == 1) {
+ if (ShiftCounter >= EncMaxShiftCounter) {
+ SHIFTUP_X8;
+ ShiftCounter = 0;
+ } else {
+ ShiftCounter += SUB_BANDS_8;
+ }
+ } else {
+ if (ShiftCounter >= EncMaxShiftCounter) {
+ SHIFTUP_X8_2;
+ ShiftCounter = 0;
+ } else {
+ ShiftCounter += SUB_BANDS_8;
+ }
+ }
+ }
+}
+
+void SbcAnalysisInit(void) {
+ memset(s16X, 0, ENC_VX_BUFFER_SIZE * sizeof(int16_t));
+ ShiftCounter = 0;
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct.c
new file mode 100755
index 0000000..4ef5572
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * source file for fast dct operations
+ *
+ ******************************************************************************/
+
+#include "sbc_dct.h"
+#include "sbc_enc_func_declare.h"
+#include "sbc_encoder.h"
+
+/*******************************************************************************
+ *
+ * Function SBC_FastIDCT8
+ *
+ * Description implementation of fast DCT algorithm by Feig and Winograd
+ *
+ *
+ * Returns y = dct(pInVect)
+ *
+ *
+ ******************************************************************************/
+
+#if (SBC_IS_64_MULT_IN_IDCT == FALSE)
+#define SBC_COS_PI_SUR_4 \
+ (0x00005a82) /* ((0x8000) * 0.7071) = cos(pi/4) \
+ */
+#define SBC_COS_PI_SUR_8 \
+ (0x00007641) /* ((0x8000) * 0.9239) = (cos(pi/8)) */
+#define SBC_COS_3PI_SUR_8 \
+ (0x000030fb) /* ((0x8000) * 0.3827) = (cos(3*pi/8)) */
+#define SBC_COS_PI_SUR_16 \
+ (0x00007d8a) /* ((0x8000) * 0.9808)) = (cos(pi/16)) */
+#define SBC_COS_3PI_SUR_16 \
+ (0x00006a6d) /* ((0x8000) * 0.8315)) = (cos(3*pi/16)) */
+#define SBC_COS_5PI_SUR_16 \
+ (0x0000471c) /* ((0x8000) * 0.5556)) = (cos(5*pi/16)) */
+#define SBC_COS_7PI_SUR_16 \
+ (0x000018f8) /* ((0x8000) * 0.1951)) = (cos(7*pi/16)) */
+#define SBC_IDCT_MULT(a, b, c) SBC_MULT_32_16_SIMPLIFIED(a, b, c)
+#else
+#define SBC_COS_PI_SUR_4 \
+ (0x5A827999) /* ((0x80000000) * 0.707106781) = (cos(pi/4) ) */
+#define SBC_COS_PI_SUR_8 \
+ (0x7641AF3C) /* ((0x80000000) * 0.923879533) = (cos(pi/8) ) */
+#define SBC_COS_3PI_SUR_8 \
+ (0x30FBC54D) /* ((0x80000000) * 0.382683432) = (cos(3*pi/8) ) */
+#define SBC_COS_PI_SUR_16 \
+ (0x7D8A5F3F) /* ((0x80000000) * 0.98078528 )) = (cos(pi/16) ) */
+#define SBC_COS_3PI_SUR_16 \
+ (0x6A6D98A4) /* ((0x80000000) * 0.831469612)) = (cos(3*pi/16)) */
+#define SBC_COS_5PI_SUR_16 \
+ (0x471CECE6) /* ((0x80000000) * 0.555570233)) = (cos(5*pi/16)) */
+#define SBC_COS_7PI_SUR_16 \
+ (0x18F8B83C) /* ((0x80000000) * 0.195090322)) = (cos(7*pi/16)) */
+#define SBC_IDCT_MULT(a, b, c) SBC_MULT_32_32(a, b, c)
+#endif /* SBC_IS_64_MULT_IN_IDCT */
+
+#if (SBC_FAST_DCT == FALSE)
+extern const int16_t gas16AnalDCTcoeff8[];
+extern const int16_t gas16AnalDCTcoeff4[];
+#endif
+
+void SBC_FastIDCT8(int32_t* pInVect, int32_t* pOutVect) {
+#if (SBC_FAST_DCT == TRUE)
+#if (SBC_ARM_ASM_OPT == TRUE)
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+ int64_t s64Temp;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+ int32_t s32HiTemp;
+#else
+ int32_t s32In2Temp;
+ register int32_t s32In1Temp;
+#endif
+#endif
+#endif
+
+ register int32_t x0, x1, x2, x3, x4, x5, x6, x7, temp;
+ int32_t res_even[4], res_odd[4];
+ /*x0= (pInVect[4])/2 ;*/
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, pInVect[4], x0);
+ /*printf("x0 0x%x = %d = %d * %d\n", x0, x0, SBC_COS_PI_SUR_4, pInVect[4]);*/
+
+ x1 = (pInVect[3] + pInVect[5]) >> 1;
+ x2 = (pInVect[2] + pInVect[6]) >> 1;
+ x3 = (pInVect[1] + pInVect[7]) >> 1;
+ x4 = (pInVect[0] + pInVect[8]) >> 1;
+ x5 = (pInVect[9] - pInVect[15]) >> 1;
+ x6 = (pInVect[10] - pInVect[14]) >> 1;
+ x7 = (pInVect[11] - pInVect[13]) >> 1;
+
+ /* 2-point IDCT of x0 and x4 as in (11) */
+ temp = x0;
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, (x0 + x4),
+ x0); /*x0 = ( x0 + x4 ) * cos(1*pi/4) ; */
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, (temp - x4),
+ x4); /*x4 = ( temp - x4 ) * cos(1*pi/4) ; */
+
+ /* rearrangement of x2 and x6 as in (15) */
+ x2 -= x6;
+ x6 <<= 1;
+
+ /* 2-point IDCT of x2 and x6 and post-multiplication as in (15) */
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x6, x6); /*x6 = x6 * cos(1*pi/4) ; */
+ temp = x2;
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_8, (x2 + x6),
+ x2); /*x2 = ( x2 + x6 ) * cos(1*pi/8) ; */
+ SBC_IDCT_MULT(SBC_COS_3PI_SUR_8, (temp - x6),
+ x6); /*x6 = ( temp - x6 ) * cos(3*pi/8) ;*/
+
+ /* 4-point IDCT of x0,x2,x4 and x6 as in (11) */
+ res_even[0] = x0 + x2;
+ res_even[1] = x4 + x6;
+ res_even[2] = x4 - x6;
+ res_even[3] = x0 - x2;
+
+ /* rearrangement of x1,x3,x5,x7 as in (15) */
+ x7 <<= 1;
+ x5 = (x5 << 1) - x7;
+ x3 = (x3 << 1) - x5;
+ x1 -= x3 >> 1;
+
+ /* two-dimensional IDCT of x1 and x5 */
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x5, x5); /*x5 = x5 * cos(1*pi/4) ; */
+ temp = x1;
+ x1 = x1 + x5;
+ x5 = temp - x5;
+
+ /* rearrangement of x3 and x7 as in (15) */
+ x3 -= x7;
+ x7 <<= 1;
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x7, x7); /*x7 = x7 * cos(1*pi/4) ; */
+
+ /* 2-point IDCT of x3 and x7 and post-multiplication as in (15) */
+ temp = x3;
+ SBC_IDCT_MULT(SBC_COS_PI_SUR_8, (x3 + x7),
+ x3); /*x3 = ( x3 + x7 ) * cos(1*pi/8) ; */
+ SBC_IDCT_MULT(SBC_COS_3PI_SUR_8, (temp - x7),
+ x7); /*x7 = ( temp - x7 ) * cos(3*pi/8) ;*/
+
+ /* 4-point IDCT of x1,x3,x5 and x7 and post multiplication by diagonal matrix
+ * as in (14) */
+ SBC_IDCT_MULT((SBC_COS_PI_SUR_16), (x1 + x3),
+ res_odd[0]); /*res_odd[ 0 ] = ( x1 + x3 ) * cos(1*pi/16) ; */
+ SBC_IDCT_MULT((SBC_COS_3PI_SUR_16), (x5 + x7),
+ res_odd[1]); /*res_odd[ 1 ] = ( x5 + x7 ) * cos(3*pi/16) ; */
+ SBC_IDCT_MULT((SBC_COS_5PI_SUR_16), (x5 - x7),
+ res_odd[2]); /*res_odd[ 2 ] = ( x5 - x7 ) * cos(5*pi/16) ; */
+ SBC_IDCT_MULT((SBC_COS_7PI_SUR_16), (x1 - x3),
+ res_odd[3]); /*res_odd[ 3 ] = ( x1 - x3 ) * cos(7*pi/16) ; */
+
+ /* additions and subtractions as in (9) */
+ pOutVect[0] = (res_even[0] + res_odd[0]);
+ pOutVect[1] = (res_even[1] + res_odd[1]);
+ pOutVect[2] = (res_even[2] + res_odd[2]);
+ pOutVect[3] = (res_even[3] + res_odd[3]);
+ pOutVect[7] = (res_even[0] - res_odd[0]);
+ pOutVect[6] = (res_even[1] - res_odd[1]);
+ pOutVect[5] = (res_even[2] - res_odd[2]);
+ pOutVect[4] = (res_even[3] - res_odd[3]);
+#else
+ uint8_t Index, k;
+ int32_t temp;
+ /*Calculate 4 subband samples by matrixing*/
+ for (Index = 0; Index < 8; Index++) {
+ temp = 0;
+ for (k = 0; k < 16; k++) {
+ /*temp += (int32_t)(((int64_t)M[(Index*strEncParams->numOfSubBands*2)+k] *
+ * Y[k]) >> 16 );*/
+ temp += (gas16AnalDCTcoeff8[(Index * 8 * 2) + k] * (pInVect[k] >> 16));
+ temp +=
+ ((gas16AnalDCTcoeff8[(Index * 8 * 2) + k] * (pInVect[k] & 0xFFFF)) >>
+ 16);
+ }
+ pOutVect[Index] = temp;
+ }
+#endif
+ /* printf("pOutVect: 0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x\n",\
+ pOutVect[0],pOutVect[1],pOutVect[2],pOutVect[3],pOutVect[4],pOutVect[5],pOutVect[6],pOutVect[7]);*/
+}
+
+/*******************************************************************************
+ *
+ * Function SBC_FastIDCT4
+ *
+ * Description implementation of fast DCT algorithm by Feig and Winograd
+ *
+ *
+ * Returns y = dct(x0)
+ *
+ *
+ ******************************************************************************/
+void SBC_FastIDCT4(int32_t* pInVect, int32_t* pOutVect) {
+#if (SBC_FAST_DCT == TRUE)
+#if (SBC_ARM_ASM_OPT == TRUE)
+#else
+#if (SBC_IPAQ_OPT == TRUE)
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+ int64_t s64Temp;
+#endif
+#else
+#if (SBC_IS_64_MULT_IN_IDCT == TRUE)
+ int32_t s32HiTemp;
+#else
+ uint16_t s32In2Temp;
+ int32_t s32In1Temp;
+#endif
+#endif
+#endif
+ int32_t temp, x2;
+ int32_t tmp[8];
+
+ x2 = pInVect[2] >> 1;
+ temp = (pInVect[0] + pInVect[4]);
+ SBC_IDCT_MULT((SBC_COS_PI_SUR_4 >> 1), temp, tmp[0]);
+ tmp[1] = x2 - tmp[0];
+ tmp[0] += x2;
+ temp = (pInVect[1] + pInVect[3]);
+ SBC_IDCT_MULT((SBC_COS_3PI_SUR_8 >> 1), temp, tmp[3]);
+ SBC_IDCT_MULT((SBC_COS_PI_SUR_8 >> 1), temp, tmp[2]);
+ temp = (pInVect[5] - pInVect[7]);
+ SBC_IDCT_MULT((SBC_COS_3PI_SUR_8 >> 1), temp, tmp[5]);
+ SBC_IDCT_MULT((SBC_COS_PI_SUR_8 >> 1), temp, tmp[4]);
+ tmp[6] = tmp[2] + tmp[5];
+ tmp[7] = tmp[3] - tmp[4];
+ pOutVect[0] = (tmp[0] + tmp[6]);
+ pOutVect[1] = (tmp[1] + tmp[7]);
+ pOutVect[2] = (tmp[1] - tmp[7]);
+ pOutVect[3] = (tmp[0] - tmp[6]);
+#else
+ uint8_t Index, k;
+ int32_t temp;
+ /*Calculate 4 subband samples by matrixing*/
+ for (Index = 0; Index < 4; Index++) {
+ temp = 0;
+ for (k = 0; k < 8; k++) {
+ /*temp += (int32_t)(((int64_t)M[(Index*strEncParams->numOfSubBands*2)+k] *
+ * Y[k]) >> 16 ); */
+ temp += (gas16AnalDCTcoeff4[(Index * 4 * 2) + k] * (pInVect[k] >> 16));
+ temp +=
+ ((gas16AnalDCTcoeff4[(Index * 4 * 2) + k] * (pInVect[k] & 0xFFFF)) >>
+ 16);
+ }
+ pOutVect[Index] = temp;
+ }
+#endif
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
new file mode 100755
index 0000000..287ad4c
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_dct_coeffs.c
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the coefficient table used for DCT computation in
+ * analysis.
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+/*DCT coeff for 4 sub-band case.*/
+#if (SBC_FAST_DCT == FALSE)
+const int16_t gas16AnalDCTcoeff4[] = {
+ (int16_t)(0.7071 * 32768), (int16_t)(0.9239 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.9239 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(0.3827 * 32768),
+ (int16_t)(0.0000 * 32768), (int16_t)(-0.3827 * 32768),
+
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.3827 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.3827 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.9239 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.9239 * 32768),
+
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.3827 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.3827 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.9239 * 32768),
+ (int16_t)(0.0000 * 32768), (int16_t)(-0.9239 * 32768),
+
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.9239 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.9239 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.3827 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.3827 * 32768)};
+
+/*DCT coeff for 8 sub-band case.*/
+const int16_t gas16AnalDCTcoeff8[] = {
+ (int16_t)(0.7071 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.9808 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(0.0000 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.8315 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.5556 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(0.0000 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(0.1951 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.1951 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(0.0000 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.5556 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.8315 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.8315 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(-0.7071 * 32768), (int16_t)(0.9808 * 32768),
+ (int16_t)(-0.9239 * 32768), (int16_t)(0.5556 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(-0.9808 * 32768),
+ (int16_t)(1.0000 * 32767), (int16_t)(-0.9808 * 32768),
+ (int16_t)(0.9239 * 32768), (int16_t)(-0.8315 * 32768),
+ (int16_t)(0.7071 * 32768), (int16_t)(-0.5556 * 32768),
+ (int16_t)(0.3827 * 32768), (int16_t)(-0.1951 * 32768),
+ (int16_t)(-0.0000 * 32768), (int16_t)(0.1951 * 32768),
+ (int16_t)(-0.3827 * 32768), (int16_t)(0.5556 * 32768)};
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
new file mode 100755
index 0000000..f849340
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the code for bit allocation algorithm. It calculates
+ * the number of bits required for the encoded stream of data.
+ *
+ ******************************************************************************/
+
+/*Includes*/
+#include "sbc_enc_func_declare.h"
+#include "sbc_encoder.h"
+
+/*global arrays*/
+const int16_t sbc_enc_as16Offset4[4][4] = {
+ {-1, 0, 0, 0}, {-2, 0, 0, 1}, {-2, 0, 0, 1}, {-2, 0, 0, 1}};
+const int16_t sbc_enc_as16Offset8[4][8] = {{-2, 0, 0, 0, 0, 0, 0, 1},
+ {-3, 0, 0, 0, 0, 0, 1, 2},
+ {-4, 0, 0, 0, 0, 0, 1, 2},
+ {-4, 0, 0, 0, 0, 0, 1, 2}};
+
+/****************************************************************************
+* BitAlloc - Calculates the required number of bits for the given scale factor
+* and the number of subbands.
+*
+* RETURNS : N/A
+*/
+
+void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS* pstrCodecParams) {
+ int32_t s32MaxBitNeed; /*to store the max bits needed per sb*/
+ int32_t s32BitCount; /*the used number of bits*/
+ int32_t s32SliceCount; /*to store hwo many slices can be put in bitpool*/
+ int32_t s32BitSlice; /*number of bitslices in bitpool*/
+ int32_t s32Sb; /*counter for sub-band*/
+ int32_t s32Ch; /*counter for channel*/
+ int16_t* ps16BitNeed; /*temp memory to store required number of bits*/
+ int32_t s32Loudness; /*used in Loudness calculation*/
+ int16_t* ps16GenBufPtr;
+ int16_t* ps16GenArrPtr;
+ int16_t* ps16GenTabPtr;
+ int32_t s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands;
+
+ ps16BitNeed = pstrCodecParams->s16ScartchMemForBitAlloc;
+
+ for (s32Ch = 0; s32Ch < pstrCodecParams->s16NumOfChannels; s32Ch++) {
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * SBC_MAX_NUM_OF_SUBBANDS;
+
+ /* bitneed values are derived from scale factor */
+ if (pstrCodecParams->s16AllocationMethod == SBC_SNR) {
+ ps16BitNeed = pstrCodecParams->as16ScaleFactor;
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ } else {
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ if (s32NumOfSubBands == 4) {
+ ps16GenTabPtr =
+ (int16_t*)sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq];
+ } else {
+ ps16GenTabPtr =
+ (int16_t*)sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq];
+ }
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if (pstrCodecParams
+ ->as16ScaleFactor[s32Ch * s32NumOfSubBands + s32Sb] == 0)
+ *(ps16GenBufPtr) = -5;
+ else {
+ s32Loudness = (int32_t)(
+ pstrCodecParams
+ ->as16ScaleFactor[s32Ch * s32NumOfSubBands + s32Sb] -
+ *ps16GenTabPtr);
+ if (s32Loudness > 0)
+ *(ps16GenBufPtr) = (int16_t)(s32Loudness >> 1);
+ else
+ *(ps16GenBufPtr) = (int16_t)s32Loudness;
+ }
+ ps16GenBufPtr++;
+ ps16GenTabPtr++;
+ }
+ }
+
+ /* max bitneed index is searched*/
+ s32MaxBitNeed = 0;
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if (*(ps16GenBufPtr) > s32MaxBitNeed) s32MaxBitNeed = *(ps16GenBufPtr);
+
+ ps16GenBufPtr++;
+ }
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ /*iterative process to find hwo many bitslices fit into the bitpool*/
+ s32BitSlice = s32MaxBitNeed + 1;
+ s32BitCount = pstrCodecParams->s16BitPool;
+ s32SliceCount = 0;
+ do {
+ s32BitSlice--;
+ s32BitCount -= s32SliceCount;
+ s32SliceCount = 0;
+
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if ((((*ps16GenBufPtr - s32BitSlice) < 16) &&
+ (*ps16GenBufPtr - s32BitSlice) >= 1)) {
+ if ((*ps16GenBufPtr - s32BitSlice) == 1)
+ s32SliceCount += 2;
+ else
+ s32SliceCount++;
+ }
+ ps16GenBufPtr++;
+
+ } /*end of for*/
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ } while (s32BitCount - s32SliceCount > 0);
+
+ if (s32BitCount == 0) {
+ s32BitCount -= s32SliceCount;
+ s32BitSlice--;
+ }
+
+ /*Bits are distributed until the last bitslice is reached*/
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands;
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if (*(ps16GenBufPtr) < s32BitSlice + 2)
+ *(ps16GenArrPtr) = 0;
+ else
+ *(ps16GenArrPtr) = ((*(ps16GenBufPtr)-s32BitSlice) < 16)
+ ? (int16_t)(*(ps16GenBufPtr)-s32BitSlice)
+ : 16;
+
+ ps16GenBufPtr++;
+ ps16GenArrPtr++;
+ }
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands;
+ ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands;
+ /*the remaining bits are allocated starting at subband 0*/
+ s32Sb = 0;
+ while ((s32BitCount > 0) && (s32Sb < s32NumOfSubBands)) {
+ if ((*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16)) {
+ (*(ps16GenArrPtr))++;
+ s32BitCount--;
+ } else if ((*(ps16GenBufPtr) == s32BitSlice + 1) && (s32BitCount > 1)) {
+ *(ps16GenArrPtr) = 2;
+ s32BitCount -= 2;
+ }
+ s32Sb++;
+ ps16GenArrPtr++;
+ ps16GenBufPtr++;
+ }
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands;
+
+ s32Sb = 0;
+ while ((s32BitCount > 0) && (s32Sb < s32NumOfSubBands)) {
+ if (*(ps16GenArrPtr) < 16) {
+ (*(ps16GenArrPtr))++;
+ s32BitCount--;
+ }
+ s32Sb++;
+ ps16GenArrPtr++;
+ }
+ }
+}
+/*End of BitAlloc() function*/
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
new file mode 100755
index 0000000..4e205e2
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the code for bit allocation algorithm. It calculates
+ * the number of bits required for the encoded stream of data.
+ *
+ ******************************************************************************/
+
+/*Includes*/
+#include "sbc_enc_func_declare.h"
+#include "sbc_encoder.h"
+
+/*global arrays*/
+extern const int16_t sbc_enc_as16Offset4[4][4];
+extern const int16_t sbc_enc_as16Offset8[4][8];
+
+/****************************************************************************
+* BitAlloc - Calculates the required number of bits for the given scale factor
+* and the number of subbands.
+*
+* RETURNS : N/A
+*/
+
+void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS* pstrCodecParams) {
+ /* CAUTIOM -> mips optim for arm 32 require to use int32_t instead of int16_t
+ */
+ /* Do not change variable type or name */
+ int32_t s32MaxBitNeed; /*to store the max bits needed per sb*/
+ int32_t s32BitCount; /*the used number of bits*/
+ int32_t s32SliceCount; /*to store hwo many slices can be put in bitpool*/
+ int32_t s32BitSlice; /*number of bitslices in bitpool*/
+ int32_t s32Sb; /*counter for sub-band*/
+ int32_t s32Ch; /*counter for channel*/
+ int16_t* ps16BitNeed; /*temp memory to store required number of bits*/
+ int32_t s32Loudness; /*used in Loudness calculation*/
+ int16_t *ps16GenBufPtr, *pas16ScaleFactor;
+ int16_t* ps16GenArrPtr;
+ int16_t* ps16GenTabPtr;
+ int32_t s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands;
+ int32_t s32BitPool = pstrCodecParams->s16BitPool;
+
+ /* bitneed values are derived from scale factor */
+ if (pstrCodecParams->s16AllocationMethod == SBC_SNR) {
+ ps16BitNeed = pstrCodecParams->as16ScaleFactor;
+ s32MaxBitNeed = pstrCodecParams->s16MaxBitNeed;
+ } else {
+ ps16BitNeed = pstrCodecParams->s16ScartchMemForBitAlloc;
+ pas16ScaleFactor = pstrCodecParams->as16ScaleFactor;
+ s32MaxBitNeed = 0;
+ ps16GenBufPtr = ps16BitNeed;
+ for (s32Ch = 0; s32Ch < 2; s32Ch++) {
+ if (s32NumOfSubBands == 4) {
+ ps16GenTabPtr =
+ (int16_t*)sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq];
+ } else {
+ ps16GenTabPtr =
+ (int16_t*)sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq];
+ }
+
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if (*pas16ScaleFactor == 0)
+ *ps16GenBufPtr = -5;
+ else {
+ s32Loudness = (int32_t)(*pas16ScaleFactor - *ps16GenTabPtr);
+
+ if (s32Loudness > 0)
+ *ps16GenBufPtr = (int16_t)(s32Loudness >> 1);
+ else
+ *ps16GenBufPtr = (int16_t)s32Loudness;
+ }
+
+ if (*ps16GenBufPtr > s32MaxBitNeed) s32MaxBitNeed = *ps16GenBufPtr;
+ pas16ScaleFactor++;
+ ps16GenBufPtr++;
+ ps16GenTabPtr++;
+ }
+ }
+ }
+
+ /* iterative process to find out hwo many bitslices fit into the bitpool */
+ s32BitSlice = s32MaxBitNeed + 1;
+ s32BitCount = s32BitPool;
+ s32SliceCount = 0;
+ do {
+ s32BitSlice--;
+ s32BitCount -= s32SliceCount;
+ s32SliceCount = 0;
+ ps16GenBufPtr = ps16BitNeed;
+
+ for (s32Sb = 0; s32Sb < 2 * s32NumOfSubBands; s32Sb++) {
+ if ((*ps16GenBufPtr >= s32BitSlice + 1) &&
+ (*ps16GenBufPtr < s32BitSlice + 16)) {
+ if (*(ps16GenBufPtr) == s32BitSlice + 1)
+ s32SliceCount += 2;
+ else
+ s32SliceCount++;
+ }
+ ps16GenBufPtr++;
+ }
+ } while (s32BitCount - s32SliceCount > 0);
+
+ if (s32BitCount - s32SliceCount == 0) {
+ s32BitCount -= s32SliceCount;
+ s32BitSlice--;
+ }
+
+ /* Bits are distributed until the last bitslice is reached */
+ ps16GenBufPtr = ps16BitNeed;
+ ps16GenArrPtr = pstrCodecParams->as16Bits;
+ for (s32Ch = 0; s32Ch < 2; s32Ch++) {
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ if (*ps16GenBufPtr < s32BitSlice + 2)
+ *ps16GenArrPtr = 0;
+ else
+ *ps16GenArrPtr = ((*(ps16GenBufPtr)-s32BitSlice) < 16)
+ ? (int16_t)(*(ps16GenBufPtr)-s32BitSlice)
+ : 16;
+ ps16GenBufPtr++;
+ ps16GenArrPtr++;
+ }
+ }
+
+ /* the remaining bits are allocated starting at subband 0 */
+ s32Ch = 0;
+ s32Sb = 0;
+ ps16GenBufPtr = ps16BitNeed;
+ ps16GenArrPtr -= 2 * s32NumOfSubBands;
+
+ while ((s32BitCount > 0) && (s32Sb < s32NumOfSubBands)) {
+ if ((*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16)) {
+ (*(ps16GenArrPtr))++;
+ s32BitCount--;
+ } else if ((*ps16GenBufPtr == s32BitSlice + 1) && (s32BitCount > 1)) {
+ *(ps16GenArrPtr) = 2;
+ s32BitCount -= 2;
+ }
+ if (s32Ch == 1) {
+ s32Ch = 0;
+ s32Sb++;
+ ps16GenBufPtr = ps16BitNeed + s32Sb;
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Sb;
+
+ } else {
+ s32Ch = 1;
+ ps16GenBufPtr = ps16BitNeed + s32NumOfSubBands + s32Sb;
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32NumOfSubBands + s32Sb;
+ }
+ }
+
+ s32Ch = 0;
+ s32Sb = 0;
+ ps16GenArrPtr = pstrCodecParams->as16Bits;
+
+ while ((s32BitCount > 0) && (s32Sb < s32NumOfSubBands)) {
+ if (*(ps16GenArrPtr) < 16) {
+ (*(ps16GenArrPtr))++;
+ s32BitCount--;
+ }
+ if (s32Ch == 1) {
+ s32Ch = 0;
+ s32Sb++;
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32Sb;
+ } else {
+ s32Ch = 1;
+ ps16GenArrPtr = pstrCodecParams->as16Bits + s32NumOfSubBands + s32Sb;
+ }
+ }
+}
+
+/*End of BitAlloc() function*/
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
new file mode 100755
index 0000000..2129fba
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_enc_coeffs.c
@@ -0,0 +1,244 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the Windowing coeffs for synthesis filter
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+
+#if (SBC_ARM_ASM_OPT == FALSE && SBC_IPAQ_OPT == FALSE)
+#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE)
+/*Window coeff for 4 sub band case*/
+const int16_t gas32CoeffFor4SBs[] = {
+ (int16_t)((int32_t)0x00000000 >> 16), (int16_t)0x00000000,
+ (int16_t)((int32_t)0x001194E6 >> 16), (int16_t)0x001194E6,
+ (int16_t)((int32_t)0x0030E2D3 >> 16), (int16_t)0x0030E2D3,
+ (int16_t)((int32_t)0x00599403 >> 16), (int16_t)0x00599403,
+ (int16_t)((int32_t)0x007DBCC8 >> 16), (int16_t)0x007DBCC8,
+ (int16_t)((int32_t)0x007F88E4 >> 16), (int16_t)0x007F88E4,
+ (int16_t)((int32_t)0x003D239B >> 16), (int16_t)0x003D239B,
+ (int16_t)((int32_t)0xFF9BB9D5 >> 16), (int16_t)0xFF9BB9D5,
+
+ (int16_t)((int32_t)0x01659F45 >> 16), (int16_t)0x01659F45,
+ (int16_t)((int32_t)0x029DBAA3 >> 16), (int16_t)0x029DBAA3,
+ (int16_t)((int32_t)0x03B23341 >> 16), (int16_t)0x03B23341,
+ (int16_t)((int32_t)0x041EEE40 >> 16), (int16_t)0x041EEE40,
+ (int16_t)((int32_t)0x034FEE2C >> 16), (int16_t)0x034FEE2C,
+ (int16_t)((int32_t)0x00C8F2BC >> 16), (int16_t)0x00C8F2BC,
+ (int16_t)((int32_t)0xFC4F91D4 >> 16), (int16_t)0xFC4F91D4,
+ (int16_t)((int32_t)0xF60FAF37 >> 16), (int16_t)0xF60FAF37,
+
+ (int16_t)((int32_t)0x115B1ED2 >> 16), (int16_t)0x115B1ED2,
+ (int16_t)((int32_t)0x18F55C90 >> 16), (int16_t)0x18F55C90,
+ (int16_t)((int32_t)0x1F91CA46 >> 16), (int16_t)0x1F91CA46,
+ (int16_t)((int32_t)0x2412F251 >> 16), (int16_t)0x2412F251,
+ (int16_t)((int32_t)0x25AC1FF2 >> 16), (int16_t)0x25AC1FF2,
+ (int16_t)((int32_t)0x2412F251 >> 16), (int16_t)0x2412F251,
+ (int16_t)((int32_t)0x1F91CA46 >> 16), (int16_t)0x1F91CA46,
+ (int16_t)((int32_t)0x18F55C90 >> 16), (int16_t)0x18F55C90,
+
+ (int16_t)((int32_t)0xEEA4E12E >> 16), (int16_t)0xEEA4E12E,
+ (int16_t)((int32_t)0xF60FAF37 >> 16), (int16_t)0xF60FAF37,
+ (int16_t)((int32_t)0xFC4F91D4 >> 16), (int16_t)0xFC4F91D4,
+ (int16_t)((int32_t)0x00C8F2BC >> 16), (int16_t)0x00C8F2BC,
+ (int16_t)((int32_t)0x034FEE2C >> 16), (int16_t)0x034FEE2C,
+ (int16_t)((int32_t)0x041EEE40 >> 16), (int16_t)0x041EEE40,
+ (int16_t)((int32_t)0x03B23341 >> 16), (int16_t)0x03B23341,
+ (int16_t)((int32_t)0x029DBAA3 >> 16), (int16_t)0x029DBAA3,
+
+ (int16_t)((int32_t)0xFE9A60BB >> 16), (int16_t)0xFE9A60BB,
+ (int16_t)((int32_t)0xFF9BB9D5 >> 16), (int16_t)0xFF9BB9D5,
+ (int16_t)((int32_t)0x003D239B >> 16), (int16_t)0x003D239B,
+ (int16_t)((int32_t)0x007F88E4 >> 16), (int16_t)0x007F88E4,
+ (int16_t)((int32_t)0x007DBCC8 >> 16), (int16_t)0x007DBCC8,
+ (int16_t)((int32_t)0x00599403 >> 16), (int16_t)0x00599403,
+ (int16_t)((int32_t)0x0030E2D3 >> 16), (int16_t)0x0030E2D3,
+ (int16_t)((int32_t)0x001194E6 >> 16), (int16_t)0x001194E6};
+
+/*Window coeff for 8 sub band case*/
+const int16_t gas32CoeffFor8SBs[] = {
+ (int16_t)((int32_t)0x00000000 >> 16), (int16_t)0x00000000,
+ (int16_t)((int32_t)0x00052173 >> 16), (int16_t)0x00052173,
+ (int16_t)((int32_t)0x000B3F71 >> 16), (int16_t)0x000B3F71,
+ (int16_t)((int32_t)0x00122C7D >> 16), (int16_t)0x00122C7D,
+ (int16_t)((int32_t)0x001AFF89 >> 16), (int16_t)0x001AFF89,
+ (int16_t)((int32_t)0x00255A62 >> 16), (int16_t)0x00255A62,
+ (int16_t)((int32_t)0x003060F4 >> 16), (int16_t)0x003060F4,
+ (int16_t)((int32_t)0x003A72E7 >> 16), (int16_t)0x003A72E7,
+
+ (int16_t)((int32_t)0x0041EC6A >> 16), (int16_t)0x0041EC6A, /* 8 */
+ (int16_t)((int32_t)0x0044EF48 >> 16), (int16_t)0x0044EF48,
+ (int16_t)((int32_t)0x00415B75 >> 16), (int16_t)0x00415B75,
+ (int16_t)((int32_t)0x0034F8B6 >> 16), (int16_t)0x0034F8B6,
+ (int16_t)((int32_t)0x001D8FD2 >> 16), (int16_t)0x001D8FD2,
+ (int16_t)((int32_t)0xFFFA2413 >> 16), (int16_t)0xFFFA2413,
+ (int16_t)((int32_t)0xFFC9F10E >> 16), (int16_t)0xFFC9F10E,
+ (int16_t)((int32_t)0xFF8D6793 >> 16), (int16_t)0xFF8D6793,
+
+ (int16_t)((int32_t)0x00B97348 >> 16), (int16_t)0x00B97348, /* 16 */
+ (int16_t)((int32_t)0x01071B96 >> 16), (int16_t)0x01071B96,
+ (int16_t)((int32_t)0x0156B3CA >> 16), (int16_t)0x0156B3CA,
+ (int16_t)((int32_t)0x01A1B38B >> 16), (int16_t)0x01A1B38B,
+ (int16_t)((int32_t)0x01E0224C >> 16), (int16_t)0x01E0224C,
+ (int16_t)((int32_t)0x0209291F >> 16), (int16_t)0x0209291F,
+ (int16_t)((int32_t)0x02138653 >> 16), (int16_t)0x02138653,
+ (int16_t)((int32_t)0x01F5F424 >> 16), (int16_t)0x01F5F424,
+
+ (int16_t)((int32_t)0x01A7ECEF >> 16), (int16_t)0x01A7ECEF, /* 24 */
+ (int16_t)((int32_t)0x01223EBA >> 16), (int16_t)0x01223EBA,
+ (int16_t)((int32_t)0x005FD0FF >> 16), (int16_t)0x005FD0FF,
+ (int16_t)((int32_t)0xFF5EEB73 >> 16), (int16_t)0xFF5EEB73,
+ (int16_t)((int32_t)0xFE20435D >> 16), (int16_t)0xFE20435D,
+ (int16_t)((int32_t)0xFCA86E7E >> 16), (int16_t)0xFCA86E7E,
+ (int16_t)((int32_t)0xFAFF95FC >> 16), (int16_t)0xFAFF95FC,
+ (int16_t)((int32_t)0xF9312891 >> 16), (int16_t)0xF9312891,
+
+ (int16_t)((int32_t)0x08B4307A >> 16), (int16_t)0x08B4307A, /* 32 */
+ (int16_t)((int32_t)0x0A9F3E9A >> 16), (int16_t)0x0A9F3E9A,
+ (int16_t)((int32_t)0x0C7D59B6 >> 16), (int16_t)0x0C7D59B6,
+ (int16_t)((int32_t)0x0E3BB16F >> 16), (int16_t)0x0E3BB16F,
+ (int16_t)((int32_t)0x0FC721F9 >> 16), (int16_t)0x0FC721F9,
+ (int16_t)((int32_t)0x110ECEF0 >> 16), (int16_t)0x110ECEF0,
+ (int16_t)((int32_t)0x120435FA >> 16), (int16_t)0x120435FA,
+ (int16_t)((int32_t)0x129C226F >> 16), (int16_t)0x129C226F,
+
+ (int16_t)((int32_t)0x12CF6C75 >> 16), (int16_t)0x12CF6C75, /* 40 */
+ (int16_t)((int32_t)0x129C226F >> 16), (int16_t)0x129C226F,
+ (int16_t)((int32_t)0x120435FA >> 16), (int16_t)0x120435FA,
+ (int16_t)((int32_t)0x110ECEF0 >> 16), (int16_t)0x110ECEF0,
+ (int16_t)((int32_t)0x0FC721F9 >> 16), (int16_t)0x0FC721F9,
+ (int16_t)((int32_t)0x0E3BB16F >> 16), (int16_t)0x0E3BB16F,
+ (int16_t)((int32_t)0x0C7D59B6 >> 16), (int16_t)0x0C7D59B6,
+ (int16_t)((int32_t)0x0A9F3E9A >> 16), (int16_t)0x0A9F3E9A,
+
+ (int16_t)((int32_t)0xF74BCF86 >> 16), (int16_t)0xF74BCF86, /* 48 */
+ (int16_t)((int32_t)0xF9312891 >> 16), (int16_t)0xF9312891,
+ (int16_t)((int32_t)0xFAFF95FC >> 16), (int16_t)0xFAFF95FC,
+ (int16_t)((int32_t)0xFCA86E7E >> 16), (int16_t)0xFCA86E7E,
+ (int16_t)((int32_t)0xFE20435D >> 16), (int16_t)0xFE20435D,
+ (int16_t)((int32_t)0xFF5EEB73 >> 16), (int16_t)0xFF5EEB73,
+ (int16_t)((int32_t)0x005FD0FF >> 16), (int16_t)0x005FD0FF,
+ (int16_t)((int32_t)0x01223EBA >> 16), (int16_t)0x01223EBA,
+
+ (int16_t)((int32_t)0x01A7ECEF >> 16), (int16_t)0x01A7ECEF, /* 56 */
+ (int16_t)((int32_t)0x01F5F424 >> 16), (int16_t)0x01F5F424,
+ (int16_t)((int32_t)0x02138653 >> 16), (int16_t)0x02138653,
+ (int16_t)((int32_t)0x0209291F >> 16), (int16_t)0x0209291F,
+ (int16_t)((int32_t)0x01E0224C >> 16), (int16_t)0x01E0224C,
+ (int16_t)((int32_t)0x01A1B38B >> 16), (int16_t)0x01A1B38B,
+ (int16_t)((int32_t)0x0156B3CA >> 16), (int16_t)0x0156B3CA,
+ (int16_t)((int32_t)0x01071B96 >> 16), (int16_t)0x01071B96,
+
+ (int16_t)((int32_t)0xFF468CB8 >> 16), (int16_t)0xFF468CB8, /* 64 */
+ (int16_t)((int32_t)0xFF8D6793 >> 16), (int16_t)0xFF8D6793,
+ (int16_t)((int32_t)0xFFC9F10E >> 16), (int16_t)0xFFC9F10E,
+ (int16_t)((int32_t)0xFFFA2413 >> 16), (int16_t)0xFFFA2413,
+ (int16_t)((int32_t)0x001D8FD2 >> 16), (int16_t)0x001D8FD2,
+ (int16_t)((int32_t)0x0034F8B6 >> 16), (int16_t)0x0034F8B6,
+ (int16_t)((int32_t)0x00415B75 >> 16), (int16_t)0x00415B75,
+ (int16_t)((int32_t)0x0044EF48 >> 16), (int16_t)0x0044EF48,
+
+ (int16_t)((int32_t)0x0041EC6A >> 16), (int16_t)0x0041EC6A, /* 72 */
+ (int16_t)((int32_t)0x003A72E7 >> 16), (int16_t)0x003A72E7,
+ (int16_t)((int32_t)0x003060F4 >> 16), (int16_t)0x003060F4,
+ (int16_t)((int32_t)0x00255A62 >> 16), (int16_t)0x00255A62,
+ (int16_t)((int32_t)0x001AFF89 >> 16), (int16_t)0x001AFF89,
+ (int16_t)((int32_t)0x00122C7D >> 16), (int16_t)0x00122C7D,
+ (int16_t)((int32_t)0x000B3F71 >> 16), (int16_t)0x000B3F71,
+ (int16_t)((int32_t)0x00052173 >> 16), (int16_t)0x00052173};
+
+#else
+
+/*Window coeff for 4 sub band case*/
+const int32_t gas32CoeffFor4SBs[] = {
+ (int32_t)0x00000000, (int32_t)0x001194E6, (int32_t)0x0030E2D3,
+ (int32_t)0x00599403, (int32_t)0x007DBCC8, (int32_t)0x007F88E4,
+ (int32_t)0x003D239B, (int32_t)0xFF9BB9D5,
+
+ (int32_t)0x01659F45, (int32_t)0x029DBAA3, (int32_t)0x03B23341,
+ (int32_t)0x041EEE40, (int32_t)0x034FEE2C, (int32_t)0x00C8F2BC,
+ (int32_t)0xFC4F91D4, (int32_t)0xF60FAF37,
+
+ (int32_t)0x115B1ED2, (int32_t)0x18F55C90, (int32_t)0x1F91CA46,
+ (int32_t)0x2412F251, (int32_t)0x25AC1FF2, (int32_t)0x2412F251,
+ (int32_t)0x1F91CA46, (int32_t)0x18F55C90,
+
+ (int32_t)0xEEA4E12E, (int32_t)0xF60FAF37, (int32_t)0xFC4F91D4,
+ (int32_t)0x00C8F2BC, (int32_t)0x034FEE2C, (int32_t)0x041EEE40,
+ (int32_t)0x03B23341, (int32_t)0x029DBAA3,
+
+ (int32_t)0xFE9A60BB, (int32_t)0xFF9BB9D5, (int32_t)0x003D239B,
+ (int32_t)0x007F88E4, (int32_t)0x007DBCC8, (int32_t)0x00599403,
+ (int32_t)0x0030E2D3, (int32_t)0x001194E6};
+
+/*Window coeff for 8 sub band case*/
+const int32_t gas32CoeffFor8SBs[] = {
+ (int32_t)0x00000000, (int32_t)0x00052173, (int32_t)0x000B3F71,
+ (int32_t)0x00122C7D, (int32_t)0x001AFF89, (int32_t)0x00255A62,
+ (int32_t)0x003060F4, (int32_t)0x003A72E7,
+
+ (int32_t)0x0041EC6A, /* 8 */
+ (int32_t)0x0044EF48, (int32_t)0x00415B75, (int32_t)0x0034F8B6,
+ (int32_t)0x001D8FD2, (int32_t)0xFFFA2413, (int32_t)0xFFC9F10E,
+ (int32_t)0xFF8D6793,
+
+ (int32_t)0x00B97348, /* 16 */
+ (int32_t)0x01071B96, (int32_t)0x0156B3CA, (int32_t)0x01A1B38B,
+ (int32_t)0x01E0224C, (int32_t)0x0209291F, (int32_t)0x02138653,
+ (int32_t)0x01F5F424,
+
+ (int32_t)0x01A7ECEF, /* 24 */
+ (int32_t)0x01223EBA, (int32_t)0x005FD0FF, (int32_t)0xFF5EEB73,
+ (int32_t)0xFE20435D, (int32_t)0xFCA86E7E, (int32_t)0xFAFF95FC,
+ (int32_t)0xF9312891,
+
+ (int32_t)0x08B4307A, /* 32 */
+ (int32_t)0x0A9F3E9A, (int32_t)0x0C7D59B6, (int32_t)0x0E3BB16F,
+ (int32_t)0x0FC721F9, (int32_t)0x110ECEF0, (int32_t)0x120435FA,
+ (int32_t)0x129C226F,
+
+ (int32_t)0x12CF6C75, /* 40 */
+ (int32_t)0x129C226F, (int32_t)0x120435FA, (int32_t)0x110ECEF0,
+ (int32_t)0x0FC721F9, (int32_t)0x0E3BB16F, (int32_t)0x0C7D59B6,
+ (int32_t)0x0A9F3E9A,
+
+ (int32_t)0xF74BCF86, /* 48 */
+ (int32_t)0xF9312891, (int32_t)0xFAFF95FC, (int32_t)0xFCA86E7E,
+ (int32_t)0xFE20435D, (int32_t)0xFF5EEB73, (int32_t)0x005FD0FF,
+ (int32_t)0x01223EBA,
+
+ (int32_t)0x01A7ECEF, /* 56 */
+ (int32_t)0x01F5F424, (int32_t)0x02138653, (int32_t)0x0209291F,
+ (int32_t)0x01E0224C, (int32_t)0x01A1B38B, (int32_t)0x0156B3CA,
+ (int32_t)0x01071B96,
+
+ (int32_t)0xFF468CB8, /* 64 */
+ (int32_t)0xFF8D6793, (int32_t)0xFFC9F10E, (int32_t)0xFFFA2413,
+ (int32_t)0x001D8FD2, (int32_t)0x0034F8B6, (int32_t)0x00415B75,
+ (int32_t)0x0044EF48,
+
+ (int32_t)0x0041EC6A, /* 72 */
+ (int32_t)0x003A72E7, (int32_t)0x003060F4, (int32_t)0x00255A62,
+ (int32_t)0x001AFF89, (int32_t)0x00122C7D, (int32_t)0x000B3F71,
+ (int32_t)0x00052173};
+
+#endif
+#endif
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_encoder.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_encoder.c
new file mode 100755
index 0000000..978fa71
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_encoder.c
@@ -0,0 +1,258 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * contains code for encoder flow and initalization of encoder
+ *
+ ******************************************************************************/
+
+#include "sbc_encoder.h"
+#include <string.h>
+#include "bt_target.h"
+#include "sbc_enc_func_declare.h"
+
+int16_t EncMaxShiftCounter;
+
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+int32_t s32LRDiff[SBC_MAX_NUM_OF_BLOCKS] = {0};
+int32_t s32LRSum[SBC_MAX_NUM_OF_BLOCKS] = {0};
+#endif
+
+uint32_t SBC_Encode(SBC_ENC_PARAMS* pstrEncParams, int16_t* input,
+ uint8_t* output) {
+ int32_t s32Ch; /* counter for ch*/
+ int32_t s32Sb; /* counter for sub-band*/
+ uint32_t u32Count, maxBit = 0; /* loop count*/
+ int32_t s32MaxValue; /* temp variable to store max value */
+
+ int16_t* ps16ScfL;
+ int32_t* SbBuffer;
+ int32_t s32Blk; /* counter for block*/
+ int32_t s32NumOfBlocks = pstrEncParams->s16NumOfBlocks;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+ int32_t s32MaxValue2;
+ uint32_t u32CountSum, u32CountDiff;
+ int32_t *pSum, *pDiff;
+#endif
+ register int32_t s32NumOfSubBands = pstrEncParams->s16NumOfSubBands;
+
+ /* SBC ananlysis filter*/
+ if (s32NumOfSubBands == 4)
+ SbcAnalysisFilter4(pstrEncParams, input);
+ else
+ SbcAnalysisFilter8(pstrEncParams, input);
+
+ /* compute the scale factor, and save the max */
+ ps16ScfL = pstrEncParams->as16ScaleFactor;
+ s32Ch = pstrEncParams->s16NumOfChannels * s32NumOfSubBands;
+
+ for (s32Sb = 0; s32Sb < s32Ch; s32Sb++) {
+ SbBuffer = pstrEncParams->s32SbBuffer + s32Sb;
+ s32MaxValue = 0;
+ for (s32Blk = s32NumOfBlocks; s32Blk > 0; s32Blk--) {
+ if (s32MaxValue < abs32(*SbBuffer)) s32MaxValue = abs32(*SbBuffer);
+ SbBuffer += s32Ch;
+ }
+
+ u32Count = (s32MaxValue > 0x800000) ? 9 : 0;
+
+ for (; u32Count < 15; u32Count++) {
+ if (s32MaxValue <= (int32_t)(0x8000 << u32Count)) break;
+ }
+ *ps16ScfL++ = (int16_t)u32Count;
+
+ if (u32Count > maxBit) maxBit = u32Count;
+ }
+/* In case of JS processing,check whether to use JS */
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+ if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) {
+ /* Calculate sum and differance scale factors for making JS decision */
+ ps16ScfL = pstrEncParams->as16ScaleFactor;
+ /* calculate the scale factor of Joint stereo max sum and diff */
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands - 1; s32Sb++) {
+ SbBuffer = pstrEncParams->s32SbBuffer + s32Sb;
+ s32MaxValue2 = 0;
+ s32MaxValue = 0;
+ pSum = s32LRSum;
+ pDiff = s32LRDiff;
+ for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) {
+ *pSum = (*SbBuffer + *(SbBuffer + s32NumOfSubBands)) >> 1;
+ if (abs32(*pSum) > s32MaxValue) s32MaxValue = abs32(*pSum);
+ pSum++;
+ *pDiff = (*SbBuffer - *(SbBuffer + s32NumOfSubBands)) >> 1;
+ if (abs32(*pDiff) > s32MaxValue2) s32MaxValue2 = abs32(*pDiff);
+ pDiff++;
+ SbBuffer += s32Ch;
+ }
+ u32Count = (s32MaxValue > 0x800000) ? 9 : 0;
+ for (; u32Count < 15; u32Count++) {
+ if (s32MaxValue <= (int32_t)(0x8000 << u32Count)) break;
+ }
+ u32CountSum = u32Count;
+ u32Count = (s32MaxValue2 > 0x800000) ? 9 : 0;
+ for (; u32Count < 15; u32Count++) {
+ if (s32MaxValue2 <= (int32_t)(0x8000 << u32Count)) break;
+ }
+ u32CountDiff = u32Count;
+ if ((*ps16ScfL + *(ps16ScfL + s32NumOfSubBands)) >
+ (int16_t)(u32CountSum + u32CountDiff)) {
+ if (u32CountSum > maxBit) maxBit = u32CountSum;
+
+ if (u32CountDiff > maxBit) maxBit = u32CountDiff;
+
+ *ps16ScfL = (int16_t)u32CountSum;
+ *(ps16ScfL + s32NumOfSubBands) = (int16_t)u32CountDiff;
+
+ SbBuffer = pstrEncParams->s32SbBuffer + s32Sb;
+ pSum = s32LRSum;
+ pDiff = s32LRDiff;
+
+ for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) {
+ *SbBuffer = *pSum;
+ *(SbBuffer + s32NumOfSubBands) = *pDiff;
+
+ SbBuffer += s32NumOfSubBands << 1;
+ pSum++;
+ pDiff++;
+ }
+
+ pstrEncParams->as16Join[s32Sb] = 1;
+ } else {
+ pstrEncParams->as16Join[s32Sb] = 0;
+ }
+ ps16ScfL++;
+ }
+ pstrEncParams->as16Join[s32Sb] = 0;
+ }
+#endif
+
+ pstrEncParams->s16MaxBitNeed = (int16_t)maxBit;
+
+ /* bit allocation */
+ if ((pstrEncParams->s16ChannelMode == SBC_STEREO) ||
+ (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO))
+ sbc_enc_bit_alloc_ste(pstrEncParams);
+ else
+ sbc_enc_bit_alloc_mono(pstrEncParams);
+
+ /* Quantize the encoded audio */
+ return EncPacking(pstrEncParams, output);
+}
+
+/****************************************************************************
+* InitSbcAnalysisFilt - Initalizes the input data to 0
+*
+* RETURNS : N/A
+*/
+void SBC_Encoder_Init(SBC_ENC_PARAMS* pstrEncParams) {
+ uint16_t s16SamplingFreq; /*temp variable to store smpling freq*/
+ int16_t s16Bitpool; /*to store bit pool value*/
+ int16_t s16BitRate; /*to store bitrate*/
+ int16_t s16FrameLen; /*to store frame length*/
+ uint16_t HeaderParams;
+
+ /* Required number of channels */
+ if (pstrEncParams->s16ChannelMode == SBC_MONO)
+ pstrEncParams->s16NumOfChannels = 1;
+ else
+ pstrEncParams->s16NumOfChannels = 2;
+
+ /* Bit pool calculation */
+ if (pstrEncParams->s16SamplingFreq == SBC_sf16000)
+ s16SamplingFreq = 16000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf32000)
+ s16SamplingFreq = 32000;
+ else if (pstrEncParams->s16SamplingFreq == SBC_sf44100)
+ s16SamplingFreq = 44100;
+ else
+ s16SamplingFreq = 48000;
+
+ if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
+ (pstrEncParams->s16ChannelMode == SBC_STEREO)) {
+ s16Bitpool =
+ (int16_t)((pstrEncParams->u16BitRate * pstrEncParams->s16NumOfSubBands *
+ 1000 / s16SamplingFreq) -
+ ((32 + (4 * pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfChannels) +
+ ((pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands)) /
+ pstrEncParams->s16NumOfBlocks));
+
+ s16FrameLen = 4 +
+ (4 * pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfChannels) /
+ 8 +
+ (((pstrEncParams->s16ChannelMode - 2) *
+ pstrEncParams->s16NumOfSubBands) +
+ (pstrEncParams->s16NumOfBlocks * s16Bitpool)) /
+ 8;
+
+ s16BitRate = (8 * s16FrameLen * s16SamplingFreq) /
+ (pstrEncParams->s16NumOfSubBands *
+ pstrEncParams->s16NumOfBlocks * 1000);
+
+ if (s16BitRate > pstrEncParams->u16BitRate) s16Bitpool--;
+
+ if (pstrEncParams->s16NumOfSubBands == 8)
+ pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool;
+ else
+ pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool;
+ } else {
+ s16Bitpool = (int16_t)(
+ ((pstrEncParams->s16NumOfSubBands * pstrEncParams->u16BitRate * 1000) /
+ (s16SamplingFreq * pstrEncParams->s16NumOfChannels)) -
+ (((32 / pstrEncParams->s16NumOfChannels) +
+ (4 * pstrEncParams->s16NumOfSubBands)) /
+ pstrEncParams->s16NumOfBlocks));
+
+ pstrEncParams->s16BitPool =
+ (s16Bitpool > (16 * pstrEncParams->s16NumOfSubBands))
+ ? (16 * pstrEncParams->s16NumOfSubBands)
+ : s16Bitpool;
+ }
+
+ if (pstrEncParams->s16BitPool < 0) pstrEncParams->s16BitPool = 0;
+ /* sampling freq */
+ HeaderParams = ((pstrEncParams->s16SamplingFreq & 3) << 6);
+
+ /* number of blocks*/
+ HeaderParams |= (((pstrEncParams->s16NumOfBlocks - 4) & 12) << 2);
+
+ /* channel mode: mono, dual...*/
+ HeaderParams |= ((pstrEncParams->s16ChannelMode & 3) << 2);
+
+ /* Loudness or SNR */
+ HeaderParams |= ((pstrEncParams->s16AllocationMethod & 1) << 1);
+ HeaderParams |= ((pstrEncParams->s16NumOfSubBands >> 3) & 1); /*4 or 8*/
+ pstrEncParams->FrameHeader = HeaderParams;
+
+ if (pstrEncParams->s16NumOfSubBands == 4) {
+ if (pstrEncParams->s16NumOfChannels == 1)
+ EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 4 * 10) >> 2) << 2;
+ else
+ EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 4 * 10 * 2) >> 3) << 2;
+ } else {
+ if (pstrEncParams->s16NumOfChannels == 1)
+ EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 8 * 10) >> 3) << 3;
+ else
+ EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 8 * 10 * 2) >> 4) << 3;
+ }
+
+ SbcAnalysisInit();
+}
diff --git a/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_packing.c b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_packing.c
new file mode 100755
index 0000000..5f36ab8
--- a/dev/null
+++ b/mtkbt/code/bt/embdrv/sbc/encoder/srce/sbc_packing.c
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains code for packing the Encoded data into bit streams.
+ *
+ ******************************************************************************/
+
+#include "sbc_enc_func_declare.h"
+#include "sbc_encoder.h"
+
+#if (SBC_ARM_ASM_OPT == TRUE)
+#define Mult32(s32In1, s32In2, s32OutLow) \
+ { \
+ __asm { \
+ MUL s32OutLow,s32In1,s32In2; } \
+ }
+#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi) \
+ { \
+ __asm { \
+ SMULL s32OutLow,s32OutHi,s32In1,s32In2 } \
+ }
+#else
+#define Mult32(s32In1, s32In2, s32OutLow) \
+ s32OutLow = (int32_t)(s32In1) * (int32_t)(s32In2);
+#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi) \
+ { \
+ (s32OutLow) = ((int32_t)(uint16_t)(s32In1) * (uint16_t)(s32In2)); \
+ s32TempVal2 = (int32_t)(((s32In1) >> 16) * (uint16_t)(s32In2)); \
+ s32Carry = ((((uint32_t)(s32OutLow) >> 16) & 0xFFFF) + \
+ +(s32TempVal2 & 0xFFFF)) >> \
+ 16; \
+ (s32OutLow) += (s32TempVal2 << 16); \
+ (s32OutHi) = (s32TempVal2 >> 16) + s32Carry; \
+ }
+#endif
+
+/* return number of bytes written to output */
+uint32_t EncPacking(SBC_ENC_PARAMS* pstrEncParams, uint8_t* output) {
+ uint8_t* pu8PacketPtr; /* packet ptr*/
+ uint8_t Temp;
+ int32_t s32Blk; /* counter for block*/
+ int32_t s32Ch; /* counter for channel*/
+ int32_t s32Sb; /* counter for sub-band*/
+ int32_t s32PresentBit; /* represents bit to be stored*/
+ /*int32_t s32LoopCountI; loop counter*/
+ int32_t s32LoopCountJ; /* loop counter*/
+ uint32_t u32QuantizedSbValue,
+ u32QuantizedSbValue0; /* temp variable to store quantized sb val*/
+ int32_t s32LoopCount; /* loop counter*/
+ uint8_t u8XoredVal; /* to store XORed value in CRC calculation*/
+ uint8_t u8CRC; /* to store CRC value*/
+ int16_t* ps16GenPtr;
+ int32_t s32NumOfBlocks;
+ int32_t s32NumOfSubBands = pstrEncParams->s16NumOfSubBands;
+ int32_t s32NumOfChannels = pstrEncParams->s16NumOfChannels;
+ uint32_t u32SfRaisedToPow2; /*scale factor raised to power 2*/
+ int16_t* ps16ScfPtr;
+ int32_t* ps32SbPtr;
+ uint16_t u16Levels; /*to store levels*/
+ int32_t s32Temp1; /*used in 64-bit multiplication*/
+ int32_t s32Low; /*used in 64-bit multiplication*/
+#if (SBC_IS_64_MULT_IN_QUANTIZER == TRUE)
+ int32_t s32Hi1, s32Low1, s32Carry, s32TempVal2, s32Hi, s32Temp2;
+#endif
+
+ pu8PacketPtr = output; /*Initialize the ptr*/
+ *pu8PacketPtr++ = (uint8_t)0x9C; /*Sync word*/
+ *pu8PacketPtr++ = (uint8_t)(pstrEncParams->FrameHeader);
+
+ *pu8PacketPtr = (uint8_t)(pstrEncParams->s16BitPool & 0x00FF);
+ pu8PacketPtr += 2; /*skip for CRC*/
+
+ /*here it indicate if it is byte boundary or nibble boundary*/
+ s32PresentBit = 8;
+ Temp = 0;
+#if (SBC_JOINT_STE_INCLUDED == TRUE)
+ if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) {
+ /* pack join stero parameters */
+ for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) {
+ Temp <<= 1;
+ Temp |= pstrEncParams->as16Join[s32Sb];
+ }
+
+ /* pack RFA */
+ if (s32NumOfSubBands == SUB_BANDS_4) {
+ s32PresentBit = 4;
+ } else {
+ *(pu8PacketPtr++) = Temp;
+ Temp = 0;
+ }
+ }
+#endif
+
+ /* Pack Scale factor */
+ ps16GenPtr = pstrEncParams->as16ScaleFactor;
+ s32Sb = s32NumOfChannels * s32NumOfSubBands;
+ /*Temp=*pu8PacketPtr;*/
+ for (s32Ch = s32Sb; s32Ch > 0; s32Ch--) {
+ Temp <<= 4;
+ Temp |= *ps16GenPtr++;
+
+ if (s32PresentBit == 4) {
+ s32PresentBit = 8;
+ *(pu8PacketPtr++) = Temp;
+ Temp = 0;
+ } else {
+ s32PresentBit = 4;
+ }
+ }
+
+ /* Pack samples */
+ ps32SbPtr = pstrEncParams->s32SbBuffer;
+ /*Temp=*pu8PacketPtr;*/
+ s32NumOfBlocks = pstrEncParams->s16NumOfBlocks;
+ for (s32Blk = s32NumOfBlocks - 1; s32Blk >= 0; s32Blk--) {
+ ps16GenPtr = pstrEncParams->as16Bits;
+ ps16ScfPtr = pstrEncParams->as16ScaleFactor;
+ for (s32Ch = s32Sb - 1; s32Ch >= 0; s32Ch--) {
+ s32LoopCount = *ps16GenPtr++;
+ if (s32LoopCount != 0) {
+#if (SBC_IS_64_MULT_IN_QUANTIZER == TRUE)
+ /* finding level from reconstruction part of decoder */
+ u32SfRaisedToPow2 = ((uint32_t)1 << ((*ps16ScfPtr) + 1));
+ u16Levels = (uint16_t)(((uint32_t)1 << s32LoopCount) - 1);
+
+ /* quantizer */
+ s32Temp1 = (*ps32SbPtr >> 2) + (u32SfRaisedToPow2 << 12);
+ s32Temp2 = u16Levels;
+
+ Mult64(s32Temp1, s32Temp2, s32Low, s32Hi);
+
+ s32Low1 = s32Low >> ((*ps16ScfPtr) + 2);
+ s32Low1 &= ((uint32_t)1 << (32 - ((*ps16ScfPtr) + 2))) - 1;
+ s32Hi1 = s32Hi << (32 - ((*ps16ScfPtr) + 2));
+
+ u32QuantizedSbValue0 = (uint16_t)((s32Low1 | s32Hi1) >> 12);
+#else
+ /* finding level from reconstruction part of decoder */
+ u32SfRaisedToPow2 = ((uint32_t)1 << *ps16ScfPtr);
+ u16Levels = (uint16_t)(((uint32_t)1 << s32LoopCount) - 1);
+
+ /* quantizer */
+ s32Temp1 = (*ps32SbPtr >> 15) + u32SfRaisedToPow2;
+ Mult32(s32Temp1, u16Levels, s32Low);
+ s32Low >>= (*ps16ScfPtr + 1);
+ u32QuantizedSbValue0 = (uint16_t)s32Low;
+#endif
+ /*store the number of bits required and the quantized s32Sb
+ sample to ease the coding*/
+ u32QuantizedSbValue = u32QuantizedSbValue0;
+
+ if (s32PresentBit >= s32LoopCount) {
+ Temp <<= s32LoopCount;
+ Temp |= u32QuantizedSbValue;
+ s32PresentBit -= s32LoopCount;
+ } else {
+ while (s32PresentBit < s32LoopCount) {
+ s32LoopCount -= s32PresentBit;
+ u32QuantizedSbValue >>= s32LoopCount;
+
+ /*remove the unwanted msbs*/
+ /*u32QuantizedSbValue <<= 16 - s32PresentBit;
+ u32QuantizedSbValue >>= 16 - s32PresentBit;*/
+
+ Temp <<= s32PresentBit;
+
+ Temp |= u32QuantizedSbValue;
+ /*restore the original*/
+ u32QuantizedSbValue = u32QuantizedSbValue0;
+
+ *(pu8PacketPtr++) = Temp;
+ Temp = 0;
+ s32PresentBit = 8;
+ }
+ Temp <<= s32LoopCount;
+
+ /* remove the unwanted msbs */
+ /*u32QuantizedSbValue <<= 16 - s32LoopCount;
+ u32QuantizedSbValue >>= 16 - s32LoopCount;*/
+
+ Temp |= u32QuantizedSbValue;
+
+ s32PresentBit -= s32LoopCount;
+ }
+ }
+ ps16ScfPtr++;
+ ps32SbPtr++;
+ }
+ }
+
+ Temp <<= s32PresentBit;
+ *pu8PacketPtr = Temp;
+ uint32_t u16PacketLength = pu8PacketPtr - output + 1;
+ /*find CRC*/
+ pu8PacketPtr = output + 1; /*Initialize the ptr*/
+ u8CRC = 0x0F;
+ s32LoopCount = s32Sb >> 1;
+
+ /*
+ The loops is run from the start of the packet till the scale factor
+ parameters. In case of JS, 'join' parameter is included in the packet
+ so that many more bytes are included in CRC calculation.
+ */
+ Temp = *pu8PacketPtr;
+ for (s32Ch = 1; s32Ch < (s32LoopCount + 4); s32Ch++) {
+ /* skip sync word and CRC bytes */
+ if (s32Ch != 3) {
+ for (s32LoopCountJ = 7; s32LoopCountJ >= 0; s32LoopCountJ--) {
+ u8XoredVal = ((u8CRC >> 7) & 0x01) ^ ((Temp >> s32LoopCountJ) & 0x01);
+ u8CRC <<= 1;
+ u8CRC ^= (u8XoredVal * 0x1D);
+ u8CRC &= 0xFF;
+ }
+ }
+ Temp = *(++pu8PacketPtr);
+ }
+
+ if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) {
+ for (s32LoopCountJ = 7; s32LoopCountJ >= (8 - s32NumOfSubBands);
+ s32LoopCountJ--) {
+ u8XoredVal = ((u8CRC >> 7) & 0x01) ^ ((Temp >> s32LoopCountJ) & 0x01);
+ u8CRC <<= 1;
+ u8CRC ^= (u8XoredVal * 0x1D);
+ u8CRC &= 0xFF;
+ }
+ }
+
+ /* CRC calculation ends here */
+
+ /* store CRC in packet */
+ output[3] = u8CRC;
+ return u16PacketLength;
+}
diff --git a/mtkbt/code/bt/hci/Android.bp b/mtkbt/code/bt/hci/Android.bp
new file mode 100755
index 0000000..fe18deb
--- a/dev/null
+++ b/mtkbt/code/bt/hci/Android.bp
@@ -0,0 +1,77 @@
+cc_defaults {
+ name: "libbt-hci_defaults",
+ defaults: ["fluoride_defaults"],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ ],
+}
+
+// HCI static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-hci",
+ defaults: ["libbt-hci_defaults"],
+ srcs: [
+ "src/btsnoop.cc",
+ "src/btsnoop_mem.cc",
+ "src/btsnoop_net.cc",
+ "src/buffer_allocator.cc",
+ "src/hci_inject.cc",
+ "src/hci_layer.cc",
+ "src/hci_layer_android.cc",
+ "src/hci_packet_factory.cc",
+ "src/hci_packet_parser.cc",
+ "src/packet_fragmenter.cc",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "vendor/mediatek/limit_open/system/bt/bta/include",
+ "system/libhwbinder/include",
+ ],
+}
+
+// HCI unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_hci",
+ defaults: ["libbt-hci_defaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/osi/test",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "system/libhwbinder/include",
+ ],
+ srcs: [
+ "test/packet_fragmenter_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libdl",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libbt-hci",
+ "libosi",
+ "libosi-AlarmTestHarness",
+ "libosi-AllocationTestHarness",
+ "libcutils",
+ "libbtcore",
+ "libbt-protos",
+ ],
+}
diff --git a/mtkbt/code/bt/hci/BUILD.gn b/mtkbt/code/bt/hci/BUILD.gn
new file mode 100755
index 0000000..ba38134
--- a/dev/null
+++ b/mtkbt/code/bt/hci/BUILD.gn
@@ -0,0 +1,75 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("hci") {
+ sources = [
+ "src/btsnoop.cc",
+ "src/btsnoop_mem.cc",
+ "src/btsnoop_net.cc",
+ "src/buffer_allocator.cc",
+ "src/hci_inject.cc",
+ "src/hci_layer.cc",
+ "src/hci_layer_linux.cc",
+ "src/hci_packet_factory.cc",
+ "src/hci_packet_parser.cc",
+ "src/packet_fragmenter.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//include",
+ "//bta/include",
+ "//btcore/include",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_hci") {
+ testonly = true
+ sources = [
+ "//osi/test/AllocationTestHarness.cc",
+ "//osi/test/AlarmTestHarness.cc",
+ "test/packet_fragmenter_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//include",
+ "//btcore/include",
+ "//hci/include",
+ "//osi/test",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//hci",
+ "//osi",
+ "//btcore",
+ "//third_party/googletest:gtest_main",
+ "//third_party/libchrome:base",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ ]
+}
diff --git a/mtkbt/code/bt/hci/include/bt_hci_bdroid.h b/mtkbt/code/bt/hci/include/bt_hci_bdroid.h
new file mode 100755
index 0000000..b915a82
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/bt_hci_bdroid.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bt_hci_bdroid.h
+ *
+ * Description: A wrapper header file of bt_hci_lib.h
+ *
+ * Contains definitions specific for interfacing with Bluedroid
+ * Bluetooth stack
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef HAS_BDROID_BUILDCFG
+#include "bdroid_buildcfg.h"
+#endif
+
+/******************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+#include <stdbool.h>
+
+#define HCI_ACL_MAX_SIZE 1024
+#define HCI_MAX_FRAME_SIZE (HCI_ACL_MAX_SIZE + 4)
+
+/* Host/Controller lib internal event ID */
+typedef enum {
+ HC_EVENT_LPM_IDLE_TIMEOUT,
+} bthc_event_t;
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */
+#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
+
+/* Message event ID passed from Host/Controller lib to stack */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
+#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
+#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
+
+/* Message event ID passed from stack to vendor lib */
+#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
+#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/******************************************************************************
+ * Type definitions and return values
+ *****************************************************************************/
+
+typedef struct {
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+ uint8_t data[];
+} HC_BT_HDR;
+
+#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR))
+
+/******************************************************************************
+ * Extern variables and functions
+ *****************************************************************************/
+
+/******************************************************************************
+ * Functions
+ *****************************************************************************/
+
+// Called when a buffer has been produced by the serial layer and should be
+// processed by the HCI layer.
+void bthc_rx_ready(void);
+void bthc_tx(HC_BT_HDR* buf);
+void bthc_idle_timeout(void);
diff --git a/mtkbt/code/bt/hci/include/bt_vendor_lib.h b/mtkbt/code/bt/hci/include/bt_vendor_lib.h
new file mode 100755
index 0000000..3c056ab
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/bt_vendor_lib.h
@@ -0,0 +1,413 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BT_VENDOR_LIB_H
+#define BT_VENDOR_LIB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/** Struct types */
+
+/** Typedefs and defines */
+
+/** Vendor specific operations OPCODE */
+typedef enum {
+ /* [operation]
+ * Power on or off the BT Controller.
+ * [input param]
+ * A pointer to int type with content of bt_vendor_power_state_t.
+ * Typecasting conversion: (int *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_POWER_CTRL,
+
+ /* [operation]
+ * Perform any vendor specific initialization or configuration
+ * on the BT Controller. This is called before stack initialization.
+ * [input param]
+ * None.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * Must call fwcfg_cb to notify the stack of the completion of vendor
+ * specific initialization once it has been done.
+ */
+ BT_VND_OP_FW_CFG,
+
+ /* [operation]
+ * Perform any vendor specific SCO/PCM configuration on the BT
+ * Controller.
+ * This is called after stack initialization.
+ * [input param]
+ * None.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * Must call scocfg_cb to notify the stack of the completion of vendor
+ * specific SCO configuration once it has been done.
+ */
+ BT_VND_OP_SCO_CFG,
+
+ /* [operation]
+ * Open UART port on where the BT Controller is attached.
+ * This is called before stack initialization.
+ * [input param]
+ * A pointer to int array type for open file descriptors.
+ * The mapping of HCI channel to fd slot in the int array is given in
+ * bt_vendor_hci_channels_t.
+ * And, it requires the vendor lib to fill up the content before
+ * returning
+ * the call.
+ * Typecasting conversion: (int (*)[]) param.
+ * [return]
+ * Numbers of opened file descriptors.
+ * Valid number:
+ * 1 - CMD/EVT/ACL-In/ACL-Out via the same fd (e.g. UART)
+ * 2 - CMD/EVT on one fd, and ACL-In/ACL-Out on the other fd
+ * 4 - CMD, EVT, ACL-In, ACL-Out are on their individual fd
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_USERIAL_OPEN,
+
+ /* [operation]
+ * Close the previously opened UART port.
+ * [input param]
+ * None.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_USERIAL_CLOSE,
+
+ /* [operation]
+ * Get the LPM idle timeout in milliseconds.
+ * The stack uses this information to launch a timer delay before it
+ * attempts to de-assert LPM WAKE signal once downstream HCI packet
+ * has been delivered.
+ * [input param]
+ * A pointer to uint32_t type which is passed in by the stack. And, it
+ * requires the vendor lib to fill up the content before returning
+ * the call.
+ * Typecasting conversion: (uint32_t *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+
+ /* [operation]
+ * Enable or disable LPM mode on BT Controller.
+ * [input param]
+ * A pointer to uint8_t type with content of bt_vendor_lpm_mode_t.
+ * Typecasting conversion: (uint8_t *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * Must call lpm_cb to notify the stack of the completion of LPM
+ * disable/enable process once it has been done.
+ */
+ BT_VND_OP_LPM_SET_MODE,
+
+ /* [operation]
+ * Assert or Deassert LPM WAKE on BT Controller.
+ * [input param]
+ * A pointer to uint8_t type with content of bt_vendor_lpm_wake_state_t.
+ * Typecasting conversion: (uint8_t *) param.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_LPM_WAKE_SET_STATE,
+
+ /* [operation]
+ * Perform any vendor specific commands related to audio state changes.
+ * [input param]
+ * a pointer to bt_vendor_op_audio_state_t indicating what audio state is
+ * set.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * None.
+ */
+ BT_VND_OP_SET_AUDIO_STATE,
+
+ /* [operation]
+ * The epilog call to the vendor module so that it can perform any
+ * vendor-specific processes (e.g. send a HCI_RESET to BT Controller)
+ * before the caller calls for cleanup().
+ * [input param]
+ * None.
+ * [return]
+ * 0 - default, don't care.
+ * [callback]
+ * Must call epilog_cb to notify the stack of the completion of vendor
+ * specific epilog process once it has been done.
+ */
+ BT_VND_OP_EPILOG,
+
+ /* [operation]
+ * Call to the vendor module so that it can perform all vendor-specific
+ * operations to start offloading a2dp media encode & tx.
+ * [input param]
+ * pointer to bt_vendor_op_a2dp_offload_start_t containing elements
+ * required for VND FW to setup a2dp offload.
+ * [return]
+ * 0 - default, dont care.
+ * [callback]
+ * Must call a2dp_offload_start_cb to notify the stack of the
+ * completion of vendor specific setup process once it has been done.
+ */
+ BT_VND_OP_A2DP_OFFLOAD_START,
+
+ /* [operation]
+ * Call to the vendor module so that it can perform all vendor-specific
+ * operations to suspend offloading a2dp media encode & tx.
+ * [input param]
+ * pointer to bt_vendor_op_a2dp_offload_t containing elements
+ * required for VND FW to setup a2dp offload.
+ * [return]
+ * 0 - default, dont care.
+ * [callback]
+ * Must call a2dp_offload_cb to notify the stack of the
+ * completion of vendor specific setup process once it has been done.
+ */
+ BT_VND_OP_A2DP_OFFLOAD_STOP,
+
+} bt_vendor_opcode_t;
+
+/** Power on/off control states */
+typedef enum {
+ BT_VND_PWR_OFF,
+ BT_VND_PWR_ON,
+} bt_vendor_power_state_t;
+
+/** Define HCI channel identifier in the file descriptors array
+ used in BT_VND_OP_USERIAL_OPEN operation.
+ */
+typedef enum {
+ CH_CMD, // HCI Command channel
+ CH_EVT, // HCI Event channel
+ CH_ACL_OUT, // HCI ACL downstream channel
+ CH_ACL_IN, // HCI ACL upstream channel
+
+ CH_MAX // Total channels
+} bt_vendor_hci_channels_t;
+
+/** LPM disable/enable request */
+typedef enum {
+ BT_VND_LPM_DISABLE,
+ BT_VND_LPM_ENABLE,
+} bt_vendor_lpm_mode_t;
+
+/** LPM WAKE set state request */
+typedef enum {
+ BT_VND_LPM_WAKE_ASSERT,
+ BT_VND_LPM_WAKE_DEASSERT,
+} bt_vendor_lpm_wake_state_t;
+
+/** Callback result values */
+typedef enum {
+ BT_VND_OP_RESULT_SUCCESS,
+ BT_VND_OP_RESULT_FAIL,
+} bt_vendor_op_result_t;
+
+/** audio (SCO) state changes triggering VS commands for configuration */
+typedef struct {
+ uint16_t handle;
+ uint16_t peer_codec;
+ uint16_t state;
+ bool use_enhanced_sco;
+} bt_vendor_op_audio_state_t;
+
+/*
+ * Bluetooth Host/Controller Vendor callback structure.
+ */
+
+/* vendor initialization/configuration callback */
+typedef void (*cfg_result_cb)(bt_vendor_op_result_t result);
+
+/* datapath buffer allocation callback (callout)
+ *
+ * Vendor lib needs to request a buffer through the alloc callout function
+ * from HCI lib if the buffer is for constructing a HCI Command packet which
+ * will be sent through xmit_cb to BT Controller.
+ *
+ * For each buffer allocation, the requested size needs to be big enough to
+ * accommodate the below header plus a complete HCI packet --
+ * typedef struct
+ * {
+ * uint16_t event;
+ * uint16_t len;
+ * uint16_t offset;
+ * uint16_t layer_specific;
+ * } HC_BT_HDR;
+ *
+ * HCI lib returns a pointer to the buffer where Vendor lib should use to
+ * construct a HCI command packet as below format:
+ *
+ * --------------------------------------------
+ * | HC_BT_HDR | HCI command |
+ * --------------------------------------------
+ * where
+ * HC_BT_HDR.event = 0x2000;
+ * HC_BT_HDR.len = Length of HCI command;
+ * HC_BT_HDR.offset = 0;
+ * HC_BT_HDR.layer_specific = 0;
+ *
+ * For example, a HCI_RESET Command will be formed as
+ * ------------------------
+ * | HC_BT_HDR |03|0c|00|
+ * ------------------------
+ * with
+ * HC_BT_HDR.event = 0x2000;
+ * HC_BT_HDR.len = 3;
+ * HC_BT_HDR.offset = 0;
+ * HC_BT_HDR.layer_specific = 0;
+ */
+typedef void* (*malloc_cb)(int size);
+
+/* datapath buffer deallocation callback (callout) */
+typedef void (*mdealloc_cb)(void* p_buf);
+
+/* define callback of the cmd_xmit_cb
+ *
+ * The callback function which HCI lib will call with the return of command
+ * complete packet. Vendor lib is responsible for releasing the buffer passed
+ * in at the p_mem parameter by calling dealloc callout function.
+ */
+typedef void (*tINT_CMD_CBACK)(void* p_mem);
+
+/* hci command packet transmit callback (callout)
+ *
+ * Vendor lib calls xmit_cb callout function in order to send a HCI Command
+ * packet to BT Controller. The buffer carrying HCI Command packet content
+ * needs to be first allocated through the alloc callout function.
+ * HCI lib will release the buffer for Vendor lib once it has delivered the
+ * packet content to BT Controller.
+ *
+ * Vendor lib needs also provide a callback function (p_cback) which HCI lib
+ * will call with the return of command complete packet.
+ *
+ * The opcode parameter gives the HCI OpCode (combination of OGF and OCF) of
+ * HCI Command packet. For example, opcode = 0x0c03 for the HCI_RESET command
+ * packet.
+ */
+typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void* p_buf,
+ tINT_CMD_CBACK p_cback);
+
+typedef void (*cfg_a2dp_cb)(bt_vendor_op_result_t result, bt_vendor_opcode_t op,
+ uint8_t bta_av_handle);
+
+typedef struct {
+ /** set to sizeof(bt_vendor_callbacks_t) */
+ size_t size;
+
+ /*
+ * Callback and callout functions have implemented in HCI libray
+ * (libbt-hci.so).
+ */
+
+ /* notifies caller result of firmware configuration request */
+ cfg_result_cb fwcfg_cb;
+
+ /* notifies caller result of sco configuration request */
+ cfg_result_cb scocfg_cb;
+
+ /* notifies caller result of lpm enable/disable */
+ cfg_result_cb lpm_cb;
+
+ /* notifies the result of codec setting */
+ cfg_result_cb audio_state_cb;
+
+ /* buffer allocation request */
+ malloc_cb alloc;
+
+ /* buffer deallocation request */
+ mdealloc_cb dealloc;
+
+ /* hci command packet transmit request */
+ cmd_xmit_cb xmit_cb;
+
+ /* notifies caller completion of epilog process */
+ cfg_result_cb epilog_cb;
+
+ /* notifies status of a2dp offload cmd's */
+ cfg_a2dp_cb a2dp_offload_cb;
+} bt_vendor_callbacks_t;
+
+/** A2DP offload request */
+typedef struct {
+ uint8_t bta_av_handle; /* BTA_AV Handle for callbacks */
+ uint16_t xmit_quota; /* Total ACL quota for light stack */
+ uint16_t acl_data_size; /* Max ACL data size across HCI transport */
+ uint16_t stream_mtu;
+ uint16_t local_cid;
+ uint16_t remote_cid;
+ uint16_t lm_handle;
+ uint8_t is_flushable; /* true if flushable channel */
+ uint32_t stream_source;
+ uint8_t codec_info[10]; /* Codec capabilities array */
+} bt_vendor_op_a2dp_offload_t;
+
+/*
+ * Bluetooth Host/Controller VENDOR Interface
+ */
+typedef struct {
+ /** Set to sizeof(bt_vndor_interface_t) */
+ size_t size;
+
+ /*
+ * Functions need to be implemented in Vendor libray (libbt-vendor.so).
+ */
+
+ /**
+ * Caller will open the interface and pass in the callback routines
+ * to the implemenation of this interface.
+ */
+ int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char* local_bdaddr);
+
+ /** Vendor specific operations */
+ int (*op)(bt_vendor_opcode_t opcode, void* param);
+
+ /** Closes the interface */
+ void (*cleanup)(void);
+} bt_vendor_interface_t;
+
+/*
+ * External shared lib functions/data
+ */
+
+/* Entry point of DLib --
+ * Vendor library needs to implement the body of bt_vendor_interface_t
+ * structure and uses the below name as the variable name. HCI library
+ * will use this symbol name to get address of the object through the
+ * dlsym call.
+ */
+extern const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE;
+
+#endif /* BT_VENDOR_LIB_H */
diff --git a/mtkbt/code/bt/hci/include/btsnoop.h b/mtkbt/code/bt/hci/include/btsnoop.h
new file mode 100755
index 0000000..1cd35dc
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/btsnoop.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "bt_types.h"
+
+static const char BTSNOOP_MODULE[] = "btsnoop_module";
+
+typedef struct btsnoop_t {
+ // Capture |packet| and dump it to the btsnoop logs. If |is_received| is
+ // true, the packet is marked as incoming. Otherwise, the packet is marked
+ // as outgoing.
+ void (*capture)(const BT_HDR* packet, bool is_received);
+} btsnoop_t;
+
+const btsnoop_t* btsnoop_get_interface(void);
diff --git a/mtkbt/code/bt/hci/include/btsnoop_mem.h b/mtkbt/code/bt/hci/include/btsnoop_mem.h
new file mode 100755
index 0000000..cf42ff7
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/btsnoop_mem.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "bt_types.h"
+
+// Callback invoked for each HCI packet.
+// Highlander mode - there can be only one...
+typedef void (*btsnoop_data_cb)(const uint16_t type, const uint8_t* p_data,
+ const size_t len, const uint64_t timestamp_us);
+
+// This call sets the (one and only) callback that will
+// be invoked once for each HCI packet/event.
+void btsnoop_mem_set_callback(btsnoop_data_cb cb);
+
+// This function is invoked every time an HCI packet
+// is sent/received. Packets will be filtered and then
+// forwarded to the |btsnoop_data_cb|.
+void btsnoop_mem_capture(const BT_HDR* p_buf, const uint64_t timestamp_us);
diff --git a/mtkbt/code/bt/hci/include/buffer_allocator.h b/mtkbt/code/bt/hci/include/buffer_allocator.h
new file mode 100755
index 0000000..63fb217
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/buffer_allocator.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "osi/include/allocator.h"
+
+const allocator_t* buffer_allocator_get_interface();
diff --git a/mtkbt/code/bt/hci/include/hci_hal.h b/mtkbt/code/bt/hci/include/hci_hal.h
new file mode 100755
index 0000000..53595c0
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_hal.h
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/thread.h"
+#include "vendor.h"
+
+typedef enum {
+ DATA_TYPE_UNKNOWN = 0,
+ DATA_TYPE_COMMAND = 1,
+ DATA_TYPE_ACL = 2,
+ DATA_TYPE_SCO = 3,
+ DATA_TYPE_EVENT = 4
+} serial_data_type_t;
+
+typedef void (*data_ready_cb)(serial_data_type_t type);
+
+typedef struct {
+ // Called when the HAL detects inbound data.
+ // Data |type| may be ACL, SCO, or EVENT.
+ // Executes in the context of the thread supplied to |init|.
+ data_ready_cb data_ready;
+
+ /*
+ // Called when the HAL detects inbound astronauts named Dave.
+ // HAL will deny all requests to open the pod bay doors after this.
+ dave_ready_cb dave_ready;
+ */
+} hci_hal_callbacks_t;
+
+typedef struct hci_hal_t {
+ // Initialize the HAL, with |upper_callbacks| and |upper_thread| to run in the
+ // context of.
+ bool (*init)(const hci_hal_callbacks_t* upper_callbacks,
+ thread_t* upper_thread);
+
+ // Connect to the underlying hardware, and let data start flowing.
+ bool (*open)(void);
+ // Disconnect from the underlying hardware, and close the HAL.
+ // "Daisy, Daisy..."
+ void (*close)(void);
+
+ // Retrieve up to |max_size| bytes for ACL, SCO, or EVENT data packets into
+ // |buffer|. Only guaranteed to be correct in the context of a data_ready
+ // callback of the corresponding type.
+ size_t (*read_data)(serial_data_type_t type, uint8_t* buffer,
+ size_t max_size);
+ // The upper layer must call this to notify the HAL that it has finished
+ // reading a packet of the specified |type|. Underlying implementations that
+ // use shared channels for multiple data types depend on this to know when
+ // to reinterpret the data stream.
+ void (*packet_finished)(serial_data_type_t type);
+ // Transmit COMMAND, ACL, or SCO data packets.
+ // |data| may not be NULL. |length| must be greater than zero.
+ //
+ // IMPORTANT NOTE:
+ // Depending on the underlying implementation, the byte right
+ // before the beginning of |data| may be borrowed during this call
+ // and then restored to its original value.
+ // This is safe in the bluetooth context, because there is always a buffer
+ // header that prefixes data you're sending.
+ uint16_t (*transmit_data)(serial_data_type_t type, uint8_t* data,
+ uint16_t length);
+} hci_hal_t;
+
+// Gets the correct hal implementation, as compiled for.
+const hci_hal_t* hci_hal_get_interface(void);
+
+const hci_hal_t* hci_hal_h4_get_interface(void);
+const hci_hal_t* hci_hal_h4_get_test_interface(vendor_t* vendor_interface);
+
+const hci_hal_t* hci_hal_mct_get_interface(void);
+const hci_hal_t* hci_hal_mct_get_test_interface(vendor_t* vendor_interface);
diff --git a/mtkbt/code/bt/hci/include/hci_inject.h b/mtkbt/code/bt/hci/include/hci_inject.h
new file mode 100755
index 0000000..12870d5
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_inject.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+typedef struct hci_t hci_t;
+
+typedef struct hci_inject_t {
+ // Starts the HCI injection module. Returns true on success, false on failure.
+ // Once started, this module must be shut down with |close|.
+ bool (*open)(const hci_t* hci_interface);
+
+ // Shuts down the HCI injection module.
+ void (*close)(void);
+} hci_inject_t;
+
+const hci_inject_t* hci_inject_get_interface();
diff --git a/mtkbt/code/bt/hci/include/hci_internals.h b/mtkbt/code/bt/hci/include/hci_internals.h
new file mode 100755
index 0000000..6b9fb01
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_internals.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+#define HCI_COMMAND_PREAMBLE_SIZE 3
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+#define HCI_ACL_PREAMBLE_SIZE 4
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+#define HCI_SCO_PREAMBLE_SIZE 3
+// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+#define HCI_EVENT_PREAMBLE_SIZE 2
diff --git a/mtkbt/code/bt/hci/include/hci_layer.h b/mtkbt/code/bt/hci/include/hci_layer.h
new file mode 100755
index 0000000..e44c0ae
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_layer.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "bt_types.h"
+#include "osi/include/allocator.h"
+#include "osi/include/data_dispatcher.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+
+static const char HCI_MODULE[] = "hci_module";
+
+///// LEGACY DEFINITIONS /////
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */
+#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
+
+/* Message event ID passed from Host/Controller lib to stack */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
+#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
+#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
+
+/* Message event ID passed from stack to vendor lib */
+#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
+#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+///// END LEGACY DEFINITIONS /////
+
+typedef struct hci_hal_t hci_hal_t;
+typedef struct btsnoop_t btsnoop_t;
+typedef struct controller_t controller_t;
+typedef struct hci_inject_t hci_inject_t;
+typedef struct packet_fragmenter_t packet_fragmenter_t;
+typedef struct vendor_t vendor_t;
+
+typedef unsigned char* bdaddr_t;
+typedef uint16_t command_opcode_t;
+
+typedef void (*command_complete_cb)(BT_HDR* response, void* context);
+typedef void (*command_status_cb)(uint8_t status, BT_HDR* command,
+ void* context);
+
+typedef struct hci_t {
+ // Register with this data dispatcher to receive events flowing upward out of
+ // the HCI layer
+ data_dispatcher_t* event_dispatcher;
+
+ // Set the queue to receive ACL data in
+ void (*set_data_queue)(fixed_queue_t* queue);
+
+ // Send a command through the HCI layer
+ void (*transmit_command)(BT_HDR* command,
+ command_complete_cb complete_callback,
+ command_status_cb status_cb, void* context);
+
+ future_t* (*transmit_command_futured)(BT_HDR* command);
+
+ // Send some data downward through the HCI layer
+ void (*transmit_downward)(data_dispatcher_type_t type, void* data);
+} hci_t;
+
+const hci_t* hci_layer_get_interface();
+
+const hci_t* hci_layer_get_test_interface(
+ const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface);
+
+void hci_layer_cleanup_interface();
diff --git a/mtkbt/code/bt/hci/include/hci_packet_factory.h b/mtkbt/code/bt/hci/include/hci_packet_factory.h
new file mode 100755
index 0000000..ed189d6
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_packet_factory.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "bt_types.h"
+#include "event_mask.h"
+
+typedef struct {
+ BT_HDR* (*make_reset)(void);
+ BT_HDR* (*make_read_buffer_size)(void);
+ BT_HDR* (*make_host_buffer_size)(uint16_t acl_size, uint8_t sco_size,
+ uint16_t acl_count, uint16_t sco_count);
+ BT_HDR* (*make_read_local_version_info)(void);
+ BT_HDR* (*make_read_bd_addr)(void);
+ BT_HDR* (*make_read_local_supported_commands)(void);
+ BT_HDR* (*make_read_local_extended_features)(uint8_t page_number);
+ BT_HDR* (*make_write_simple_pairing_mode)(uint8_t mode);
+ BT_HDR* (*make_write_secure_connections_host_support)(uint8_t mode);
+ BT_HDR* (*make_set_event_mask)(const bt_event_mask_t* event_mask);
+ BT_HDR* (*make_ble_write_host_support)(uint8_t supported_host,
+ uint8_t simultaneous_host);
+ BT_HDR* (*make_ble_read_white_list_size)(void);
+ BT_HDR* (*make_ble_read_buffer_size)(void);
+ BT_HDR* (*make_ble_read_supported_states)(void);
+ BT_HDR* (*make_ble_read_local_supported_features)(void);
+ BT_HDR* (*make_ble_read_resolving_list_size)(void);
+ BT_HDR* (*make_ble_read_suggested_default_data_length)(void);
+ BT_HDR* (*make_ble_read_maximum_advertising_data_length)(void);
+ BT_HDR* (*make_ble_read_number_of_supported_advertising_sets)(void);
+ BT_HDR* (*make_ble_set_event_mask)(const bt_event_mask_t* event_mask);
+ BT_HDR* (*make_read_local_supported_codecs)(void);
+} hci_packet_factory_t;
+
+const hci_packet_factory_t* hci_packet_factory_get_interface();
diff --git a/mtkbt/code/bt/hci/include/hci_packet_parser.h b/mtkbt/code/bt/hci/include/hci_packet_parser.h
new file mode 100755
index 0000000..b5117b9
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/hci_packet_parser.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "bdaddr.h"
+#include "bt_types.h"
+#include "device_features.h"
+#include "features.h"
+#include "osi/include/allocator.h"
+#include "version.h"
+
+typedef struct {
+ void (*parse_generic_command_complete)(BT_HDR* response);
+
+ void (*parse_read_buffer_size_response)(BT_HDR* response,
+ uint16_t* data_size_ptr,
+ uint16_t* acl_buffer_count_ptr);
+
+ void (*parse_read_local_version_info_response)(BT_HDR* response,
+ bt_version_t* bt_version_ptr);
+
+ void (*parse_read_bd_addr_response)(BT_HDR* response,
+ bt_bdaddr_t* address_ptr);
+
+ void (*parse_read_local_supported_commands_response)(
+ BT_HDR* response, uint8_t* supported_commands_ptr,
+ size_t supported_commands_length);
+
+ void (*parse_read_local_extended_features_response)(
+ BT_HDR* response, uint8_t* page_number_ptr, uint8_t* max_page_number_ptr,
+ bt_device_features_t* feature_pages, size_t feature_pages_count);
+
+ void (*parse_ble_read_white_list_size_response)(BT_HDR* response,
+ uint8_t* white_list_size_ptr);
+
+ void (*parse_ble_read_buffer_size_response)(BT_HDR* response,
+ uint16_t* data_size_ptr,
+ uint8_t* acl_buffer_count_ptr);
+
+ void (*parse_ble_read_supported_states_response)(
+ BT_HDR* response, uint8_t* supported_states,
+ size_t supported_states_size);
+
+ void (*parse_ble_read_local_supported_features_response)(
+ BT_HDR* response, bt_device_features_t* supported_features);
+
+ void (*parse_ble_read_resolving_list_size_response)(
+ BT_HDR* response, uint8_t* resolving_list_size_ptr);
+
+ void (*parse_ble_read_suggested_default_data_length_response)(
+ BT_HDR* response, uint16_t* ble_default_packet_length_ptr);
+
+ void (*parse_ble_read_maximum_advertising_data_length)(
+ BT_HDR* response, uint16_t* ble_maximum_advertising_data_length_ptr);
+
+ void (*parse_ble_read_number_of_supported_advertising_sets)(
+ BT_HDR* response, uint8_t* ble_number_of_supported_advertising_sets_ptr);
+
+ void (*parse_read_local_supported_codecs_response)(
+ BT_HDR* response, uint8_t* number_of_local_supported_codecs,
+ uint8_t* local_supported_codecs);
+
+} hci_packet_parser_t;
+
+const hci_packet_parser_t* hci_packet_parser_get_interface();
+
+const hci_packet_parser_t* hci_packet_parser_get_test_interface(
+ allocator_t* buffer_allocator_interface);
diff --git a/mtkbt/code/bt/hci/include/low_power_manager.h b/mtkbt/code/bt/hci/include/low_power_manager.h
new file mode 100755
index 0000000..47e3b6d
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/low_power_manager.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "hci_layer.h"
+
+typedef struct thread_t thread_t;
+typedef struct vendor_t vendor_t;
+
+typedef struct low_power_manager_t {
+ // Initialize the low power manager, and use |post_thread| to synchronize
+ // actions.
+ void (*init)(thread_t* post_thread);
+
+ // Clean up the low power manager and release resources.
+ void (*cleanup)(void);
+
+ // Performs |command| synchronized on the thread that was provided
+ // at initialization time.
+ void (*post_command)(low_power_command_t command);
+
+ // Assert wake (for transmission). Must be called on the thread provided
+ // at initialization time.
+ void (*wake_assert)(void);
+
+ // Tell the low power manager that you're done transmitting data. Must be
+ // called on the thread provided at initialization time.
+ void (*transmit_done)(void);
+} low_power_manager_t;
+
+const low_power_manager_t* low_power_manager_get_interface();
+const low_power_manager_t* low_power_manager_get_test_interface(
+ const vendor_t* vendor_interface);
diff --git a/mtkbt/code/bt/hci/include/packet_fragmenter.h b/mtkbt/code/bt/hci/include/packet_fragmenter.h
new file mode 100755
index 0000000..935ea94
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/packet_fragmenter.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "bt_types.h"
+#include "hci_layer.h"
+#include "osi/include/allocator.h"
+
+typedef void (*transmit_finished_cb)(BT_HDR* packet, bool all_fragments_sent);
+typedef void (*packet_reassembled_cb)(BT_HDR* packet);
+typedef void (*packet_fragmented_cb)(BT_HDR* packet,
+ bool send_transmit_finished);
+
+typedef struct {
+ // Called for every packet fragment.
+ packet_fragmented_cb fragmented;
+
+ // Called for every completely reassembled packet.
+ packet_reassembled_cb reassembled;
+
+ // Called when the fragmenter finishes sending all requested fragments,
+ // but the packet has not been entirely sent.
+ transmit_finished_cb transmit_finished;
+} packet_fragmenter_callbacks_t;
+
+typedef struct packet_fragmenter_t {
+ // Initialize the fragmenter, specifying the |result_callbacks|.
+ void (*init)(const packet_fragmenter_callbacks_t* result_callbacks);
+
+ // Release all resources associated with the fragmenter.
+ void (*cleanup)(void);
+
+ // Fragments |packet| if necessary and hands off everything to the fragmented
+ // callback.
+ void (*fragment_and_dispatch)(BT_HDR* packet);
+ // If |packet| is a complete packet, forwards to the reassembled callback.
+ // Otherwise
+ // holds onto it until all fragments arrive, at which point the reassembled
+ // callback is called
+ // with the reassembled data.
+ void (*reassemble_and_dispatch)(BT_HDR* packet);
+} packet_fragmenter_t;
+
+const packet_fragmenter_t* packet_fragmenter_get_interface();
+
+const packet_fragmenter_t* packet_fragmenter_get_test_interface(
+ const controller_t* controller_interface,
+ const allocator_t* buffer_allocator_interface);
diff --git a/mtkbt/code/bt/hci/include/userial.h b/mtkbt/code/bt/hci/include/userial.h
new file mode 100755
index 0000000..becb407
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/userial.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+// This module manages the serial port over which HCI commands
+// and data are sent/received.
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef enum {
+ USERIAL_PORT_1,
+ USERIAL_PORT_2,
+ USERIAL_PORT_3,
+ USERIAL_PORT_4,
+ USERIAL_PORT_5,
+ USERIAL_PORT_6,
+ USERIAL_PORT_7,
+ USERIAL_PORT_8,
+ USERIAL_PORT_9,
+ USERIAL_PORT_10,
+ USERIAL_PORT_11,
+ USERIAL_PORT_12,
+ USERIAL_PORT_13,
+ USERIAL_PORT_14,
+ USERIAL_PORT_15,
+ USERIAL_PORT_16,
+ USERIAL_PORT_17,
+ USERIAL_PORT_18,
+} userial_port_t;
+
+// Initializes the userial module. This function should only be called once.
+// It returns true if the module was initialized, false if there was an error.
+bool userial_init(void);
+
+// Opens the given serial port. Returns true if successful, false otherwise.
+// Once this function is called, the userial module will begin producing
+// buffers from data read off the serial port. If you wish to pause the
+// production of buffers, call |userial_pause_reading|. You can then resume
+// by calling |userial_resume_reading|. This function returns true if the
+// serial port was successfully opened and buffer production has started. It
+// returns false if there was an error.
+bool userial_open(userial_port_t port);
+void userial_close(void);
+void userial_close_reader(void);
+
+// Reads a maximum of |len| bytes from the serial port into |p_buffer|.
+// This function returns the number of bytes actually read, which may be
+// less than |len|. This function will not block.
+uint16_t userial_read(uint16_t msg_id, uint8_t* p_buffer, uint16_t len);
+
+// Writes a maximum of |len| bytes from |p_data| to the serial port.
+// This function returns the number of bytes actually written, which may be
+// less than |len|. This function may block.
+uint16_t userial_write(uint16_t msg_id, const uint8_t* p_data, uint16_t len);
diff --git a/mtkbt/code/bt/hci/include/vendor.h b/mtkbt/code/bt/hci/include/vendor.h
new file mode 100755
index 0000000..70a2cef
--- a/dev/null
+++ b/mtkbt/code/bt/hci/include/vendor.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bt_types.h"
+#include "bt_vendor_lib.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+
+typedef enum {
+ VENDOR_CHIP_POWER_CONTROL = BT_VND_OP_POWER_CTRL,
+ VENDOR_OPEN_USERIAL = BT_VND_OP_USERIAL_OPEN,
+ VENDOR_CLOSE_USERIAL = BT_VND_OP_USERIAL_CLOSE,
+ VENDOR_GET_LPM_IDLE_TIMEOUT = BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+ VENDOR_SET_LPM_WAKE_STATE = BT_VND_OP_LPM_WAKE_SET_STATE,
+ VENDOR_SET_AUDIO_STATE = BT_VND_OP_SET_AUDIO_STATE
+} vendor_opcode_t;
+
+typedef enum {
+ VENDOR_CONFIGURE_FIRMWARE = BT_VND_OP_FW_CFG,
+ VENDOR_CONFIGURE_SCO = BT_VND_OP_SCO_CFG,
+ VENDOR_SET_LPM_MODE = BT_VND_OP_LPM_SET_MODE,
+ VENDOR_DO_EPILOG = BT_VND_OP_EPILOG,
+ VENDOR_A2DP_OFFLOAD_START = BT_VND_OP_A2DP_OFFLOAD_START,
+ VENDOR_A2DP_OFFLOAD_STOP = BT_VND_OP_A2DP_OFFLOAD_STOP,
+ VENDOR_LAST_OP
+} vendor_async_opcode_t;
+
+typedef void (*vendor_cb)(bool success);
+
+typedef struct vendor_t {
+ // Opens the vendor-specific library and sets the Bluetooth
+ // address of the adapter to |local_bdaddr|. |hci_interface| is
+ // used to send commands on behalf of the vendor library.
+ bool (*open)(const uint8_t* local_bdaddr, const hci_t* hci_interface);
+
+ // Closes the vendor-specific library and frees all associated resources.
+ // Only |vendor_open| may be called after |vendor_close|.
+ void (*close)(void);
+
+ // Sends a vendor-specific command to the library.
+ int (*send_command)(vendor_opcode_t opcode, void* param);
+
+ // Sends an asynchronous vendor-specific command to the library.
+ int (*send_async_command)(vendor_async_opcode_t opcode, void* param);
+
+ // Registers a callback for an asynchronous vendor-specific command.
+ void (*set_callback)(vendor_async_opcode_t opcode, vendor_cb callback);
+} vendor_t;
+
+const vendor_t* vendor_get_interface();
diff --git a/mtkbt/code/bt/hci/src/btsnoop.cc b/mtkbt/code/bt/hci/src/btsnoop.cc
new file mode 100755
index 0000000..a109ad0
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/btsnoop.cc
@@ -0,0 +1,282 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_snoop"
+
+#include <mutex>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "bt_types.h"
+#include "hci/include/btsnoop.h"
+#include "hci/include/btsnoop_mem.h"
+#include "hci_layer.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+#include "osi/include/time.h"
+#include "stack_config.h"
+
+// The number of of packets per btsnoop file before we rotate to the next
+// file. As of right now there are two snoop files that are rotated through.
+// The size can be dynamically configured by seting the relevant system
+// property
+#define DEFAULT_BTSNOOP_SIZE 0xffff
+
+#define BTSNOOP_ENABLE_PROPERTY "persist.bluetooth.btsnoopenable"
+#define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath"
+#define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log"
+#define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize"
+
+typedef enum {
+ kCommandPacket = 1,
+ kAclPacket = 2,
+ kScoPacket = 3,
+ kEventPacket = 4
+} packet_type_t;
+
+// Epoch in microseconds since 01/01/0000.
+static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+
+static int logfile_fd = INVALID_FD;
+static std::mutex btsnoop_mutex;
+
+static int32_t packets_per_file;
+static int32_t packet_counter;
+
+// TODO(zachoverflow): merge btsnoop and btsnoop_net together
+void btsnoop_net_open();
+void btsnoop_net_close();
+void btsnoop_net_write(const void* data, size_t length);
+
+static void delete_btsnoop_files();
+static bool is_btsnoop_enabled();
+static char* get_btsnoop_log_path(char* log_path);
+static char* get_btsnoop_last_log_path(char* last_log_path, char* log_path);
+static void open_next_snoop_file();
+static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
+ bool is_received, uint64_t timestamp_us);
+
+// Module lifecycle functions
+
+static future_t* start_up(void) {
+ std::lock_guard<std::mutex> lock(btsnoop_mutex);
+
+ if (!is_btsnoop_enabled()) {
+ delete_btsnoop_files();
+ } else {
+ open_next_snoop_file();
+ packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY,
+ DEFAULT_BTSNOOP_SIZE);
+ btsnoop_net_open();
+ }
+
+ return NULL;
+}
+
+static future_t* shut_down(void) {
+ std::lock_guard<std::mutex> lock(btsnoop_mutex);
+
+ if (!is_btsnoop_enabled()) {
+ delete_btsnoop_files();
+ }
+
+ if (logfile_fd != INVALID_FD) close(logfile_fd);
+ logfile_fd = INVALID_FD;
+
+ btsnoop_net_close();
+
+ return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t btsnoop_module = {
+ .name = BTSNOOP_MODULE,
+ .init = NULL,
+ .start_up = start_up,
+ .shut_down = shut_down,
+ .clean_up = NULL,
+ .dependencies = {STACK_CONFIG_MODULE, NULL}};
+
+// Interface functions
+static void capture(const BT_HDR* buffer, bool is_received) {
+ uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
+
+ std::lock_guard<std::mutex> lock(btsnoop_mutex);
+ uint64_t timestamp_us = time_gettimeofday_us();
+ btsnoop_mem_capture(buffer, timestamp_us);
+
+ if (logfile_fd == INVALID_FD) return;
+
+ switch (buffer->event & MSG_EVT_MASK) {
+ case MSG_HC_TO_STACK_HCI_EVT:
+ btsnoop_write_packet(kEventPacket, p, false, timestamp_us);
+ break;
+ case MSG_HC_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_HC_HCI_ACL:
+ btsnoop_write_packet(kAclPacket, p, is_received, timestamp_us);
+ break;
+ case MSG_HC_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_HC_HCI_SCO:
+ btsnoop_write_packet(kScoPacket, p, is_received, timestamp_us);
+ break;
+ case MSG_STACK_TO_HC_HCI_CMD:
+ btsnoop_write_packet(kCommandPacket, p, true, timestamp_us);
+ break;
+ }
+}
+
+static const btsnoop_t interface = {capture};
+
+const btsnoop_t* btsnoop_get_interface() {
+ return &interface;
+}
+
+// Internal functions
+static void delete_btsnoop_files() {
+ LOG_VERBOSE(LOG_TAG, "Deleting snoop log if it exists");
+ char log_path[PROPERTY_VALUE_MAX];
+ char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
+ get_btsnoop_log_path(log_path);
+ get_btsnoop_last_log_path(last_log_path, log_path);
+ remove(log_path);
+ remove(last_log_path);
+}
+
+static bool is_btsnoop_enabled() {
+ char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(BTSNOOP_ENABLE_PROPERTY, btsnoop_enabled, "false");
+ return strncmp(btsnoop_enabled, "true", 4) == 0;
+}
+
+static char* get_btsnoop_log_path(char* btsnoop_path) {
+ osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH);
+ return btsnoop_path;
+}
+
+static char* get_btsnoop_last_log_path(char* last_log_path,
+ char* btsnoop_path) {
+ snprintf(last_log_path, PROPERTY_VALUE_MAX + sizeof(".last"), "%s.last",
+ btsnoop_path);
+ return last_log_path;
+}
+
+static void open_next_snoop_file() {
+ packet_counter = 0;
+
+ if (logfile_fd != INVALID_FD) {
+ close(logfile_fd);
+ logfile_fd = INVALID_FD;
+ }
+
+ char log_path[PROPERTY_VALUE_MAX];
+ char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
+ get_btsnoop_log_path(log_path);
+ get_btsnoop_last_log_path(last_log_path, log_path);
+
+ if (!rename(log_path, last_log_path) && errno != ENOENT)
+ LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
+ log_path, last_log_path, strerror(errno));
+
+ mode_t prevmask = umask(0);
+ logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ umask(prevmask);
+ if (logfile_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
+ strerror(errno));
+ return;
+ }
+
+ write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+}
+
+typedef struct {
+ uint32_t length_original;
+ uint32_t length_captured;
+ uint32_t flags;
+ uint32_t dropped_packets;
+ uint64_t timestamp;
+ uint8_t type;
+} __attribute__((__packed__)) btsnoop_header_t;
+
+static uint64_t htonll(uint64_t ll) {
+ const uint32_t l = 1;
+ if (*(reinterpret_cast<const uint8_t*>(&l)) == 1)
+ return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 |
+ htonl(ll >> 32);
+
+ return ll;
+}
+
+static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
+ bool is_received, uint64_t timestamp_us) {
+ uint32_t length_he = 0;
+ uint32_t flags = 0;
+
+ switch (type) {
+ case kCommandPacket:
+ length_he = packet[2] + 4;
+ flags = 2;
+ break;
+ case kAclPacket:
+ length_he = (packet[3] << 8) + packet[2] + 5;
+ flags = is_received;
+ break;
+ case kScoPacket:
+ length_he = packet[2] + 4;
+ flags = is_received;
+ break;
+ case kEventPacket:
+ length_he = packet[1] + 3;
+ flags = 3;
+ break;
+ }
+
+ btsnoop_header_t header;
+ header.length_original = htonl(length_he);
+ header.length_captured = header.length_original;
+ header.flags = htonl(flags);
+ header.dropped_packets = 0;
+ header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA);
+ header.type = type;
+
+ btsnoop_net_write(&header, sizeof(btsnoop_header_t));
+ btsnoop_net_write(packet, length_he - 1);
+
+ if (logfile_fd != INVALID_FD) {
+ packet_counter++;
+ if (packet_counter > packets_per_file) {
+ open_next_snoop_file();
+ }
+
+ iovec iov[] = {{&header, sizeof(btsnoop_header_t)},
+ {reinterpret_cast<void*>(packet), length_he - 1}};
+ TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2));
+ }
+}
diff --git a/mtkbt/code/bt/hci/src/btsnoop_mem.cc b/mtkbt/code/bt/hci/src/btsnoop_mem.cc
new file mode 100755
index 0000000..ad135e0
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/btsnoop_mem.cc
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+
+#include "hci/include/btsnoop_mem.h"
+
+static btsnoop_data_cb data_callback = NULL;
+
+void btsnoop_mem_set_callback(btsnoop_data_cb cb) { data_callback = cb; }
+
+void btsnoop_mem_capture(const BT_HDR* packet, uint64_t timestamp_us) {
+ if (!data_callback) return;
+
+ CHECK(packet);
+
+ const uint8_t* data = &packet->data[packet->offset];
+ const uint16_t type = packet->event & BT_EVT_MASK;
+ size_t length = 0;
+
+ switch (type) {
+ case BT_EVT_TO_LM_HCI_CMD:
+ if (packet->len > 2) length = data[2] + 3;
+ break;
+
+ case BT_EVT_TO_BTU_HCI_EVT:
+ if (packet->len > 1) length = data[1] + 2;
+ break;
+
+ case BT_EVT_TO_LM_HCI_ACL:
+ case BT_EVT_TO_BTU_HCI_ACL:
+ if (packet->len > 3) length = (data[2] | (data[3] << 8)) + 4;
+ break;
+
+ case BT_EVT_TO_LM_HCI_SCO:
+ case BT_EVT_TO_BTU_HCI_SCO:
+ if (packet->len > 2) length = data[2] + 3;
+ break;
+ }
+
+ if (length) (*data_callback)(type, data, length, timestamp_us);
+}
diff --git a/mtkbt/code/bt/hci/src/btsnoop_net.cc b/mtkbt/code/bt/hci/src/btsnoop_net.cc
new file mode 100755
index 0000000..1d49692
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/btsnoop_net.cc
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_snoop_net"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+static void safe_close_(int* fd);
+static void* listen_fn_(void* context);
+
+static const char* LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
+static const int LOCALHOST_ = 0x7F000001;
+static const int LISTEN_PORT_ = 8872;
+
+static pthread_t listen_thread_;
+static bool listen_thread_valid_ = false;
+static std::mutex client_socket_mutex_;
+static int listen_socket_ = -1;
+static int client_socket_ = -1;
+
+void btsnoop_net_open() {
+#if (BT_NET_DEBUG != TRUE)
+ return; // Disable using network sockets for security reasons
+#endif
+
+ listen_thread_valid_ =
+ (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
+ if (!listen_thread_valid_)
+ LOG_ERROR(LOG_TAG, "%s pthread_create failed: %s", __func__,
+ strerror(errno));
+}
+
+void btsnoop_net_close() {
+#if (BT_NET_DEBUG != TRUE)
+ return; // Disable using network sockets for security reasons
+#endif
+
+ if (listen_thread_valid_) {
+ shutdown(listen_socket_, SHUT_RDWR);
+ pthread_join(listen_thread_, NULL);
+ safe_close_(&client_socket_);
+ listen_thread_valid_ = false;
+ }
+}
+
+void btsnoop_net_write(const void* data, size_t length) {
+#if (BT_NET_DEBUG != TRUE)
+ return; // Disable using network sockets for security reasons
+#endif
+
+ std::lock_guard<std::mutex> lock(client_socket_mutex_);
+ if (client_socket_ != -1) {
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(client_socket_, data, length, 0));
+
+ if (ret == -1 && errno == ECONNRESET) {
+ safe_close_(&client_socket_);
+ }
+ }
+}
+
+static void* listen_fn_(UNUSED_ATTR void* context) {
+ int enable = 1;
+
+ prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
+
+ listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_socket_ == -1) {
+ LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__,
+ strerror(errno));
+ goto cleanup;
+ }
+
+ if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable,
+ sizeof(enable)) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__,
+ strerror(errno));
+ goto cleanup;
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(LOCALHOST_);
+ addr.sin_port = htons(LISTEN_PORT_);
+ if (bind(listen_socket_, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to bind listen socket: %s", __func__,
+ strerror(errno));
+ goto cleanup;
+ }
+
+ if (listen(listen_socket_, 10) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to listen: %s", __func__, strerror(errno));
+ goto cleanup;
+ }
+
+ for (;;) {
+ int client_socket;
+ OSI_NO_INTR(client_socket = accept(listen_socket_, NULL, NULL));
+ if (client_socket == -1) {
+ if (errno == EINVAL || errno == EBADF) {
+ break;
+ }
+ LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__,
+ strerror(errno));
+ continue;
+ }
+
+ /* When a new client connects, we have to send the btsnoop file header. This
+ * allows a decoder to treat the session as a new, valid btsnoop file. */
+ std::lock_guard<std::mutex> lock(client_socket_mutex_);
+ safe_close_(&client_socket_);
+ client_socket_ = client_socket;
+
+ OSI_NO_INTR(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
+ }
+
+cleanup:
+ safe_close_(&listen_socket_);
+ return NULL;
+}
+
+static void safe_close_(int* fd) {
+ CHECK(fd != NULL);
+ if (*fd != -1) {
+ close(*fd);
+ *fd = -1;
+ }
+}
diff --git a/mtkbt/code/bt/hci/src/buffer_allocator.cc b/mtkbt/code/bt/hci/src/buffer_allocator.cc
new file mode 100755
index 0000000..d231abe
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/buffer_allocator.cc
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+
+#include "bt_common.h"
+#include "buffer_allocator.h"
+
+static void* buffer_alloc(size_t size) {
+ CHECK(size <= BT_DEFAULT_BUFFER_SIZE);
+ return osi_malloc(size);
+}
+
+static const allocator_t interface = {buffer_alloc, osi_free};
+
+const allocator_t* buffer_allocator_get_interface() { return &interface; }
diff --git a/mtkbt/code/bt/hci/src/hci_inject.cc b/mtkbt/code/bt/hci/src/hci_inject.cc
new file mode 100755
index 0000000..70194a5
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_inject.cc
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci_inject"
+
+#include "hci_inject.h"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "buffer_allocator.h"
+#include "hci_layer.h"
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket.h"
+#include "osi/include/thread.h"
+
+typedef enum {
+ HCI_PACKET_COMMAND = 1,
+ HCI_PACKET_ACL_DATA = 2,
+ HCI_PACKET_SCO_DATA = 3,
+ HCI_PACKET_EVENT = 4,
+} hci_packet_t;
+
+typedef struct {
+ socket_t* socket;
+ uint8_t buffer[65536 + 3]; // 2 bytes length prefix, 1 byte type prefix.
+ size_t buffer_size;
+} client_t;
+
+static bool hci_inject_open(const hci_t* hci_interface);
+static void hci_inject_close(void);
+static int hci_packet_to_event(hci_packet_t packet);
+static void accept_ready(socket_t* socket, void* context);
+static void read_ready(socket_t* socket, void* context);
+static void client_free(void* ptr);
+
+static const port_t LISTEN_PORT = 8873;
+
+static const hci_inject_t interface = {hci_inject_open, hci_inject_close};
+
+static const hci_t* hci;
+static const allocator_t* buffer_allocator;
+static socket_t* listen_socket;
+static thread_t* thread;
+static list_t* clients;
+
+static bool hci_inject_open(const hci_t* hci_interface) {
+#if (BT_NET_DEBUG != TRUE)
+ return true; // Disable using network sockets for security reasons
+#endif
+
+ CHECK(listen_socket == NULL);
+ CHECK(thread == NULL);
+ CHECK(clients == NULL);
+ CHECK(hci_interface != NULL);
+
+ hci = hci_interface;
+
+ thread = thread_new("hci_inject");
+ if (!thread) goto error;
+
+ clients = list_new(client_free);
+ if (!clients) goto error;
+
+ listen_socket = socket_new();
+ if (!listen_socket) goto error;
+
+ if (!socket_listen(listen_socket, LISTEN_PORT)) goto error;
+
+ socket_register(listen_socket, thread_get_reactor(thread), NULL, accept_ready,
+ NULL);
+ return true;
+
+error:;
+ interface.close();
+ return false;
+}
+
+static void hci_inject_close(void) {
+#if (BT_NET_DEBUG != TRUE)
+ return; // Disable using network sockets for security reasons
+#endif
+
+ socket_free(listen_socket);
+ list_free(clients);
+ thread_free(thread);
+
+ listen_socket = NULL;
+ thread = NULL;
+ clients = NULL;
+}
+
+static int hci_packet_to_event(hci_packet_t packet) {
+ switch (packet) {
+ case HCI_PACKET_COMMAND:
+ return MSG_STACK_TO_HC_HCI_CMD;
+ case HCI_PACKET_ACL_DATA:
+ return MSG_STACK_TO_HC_HCI_ACL;
+ case HCI_PACKET_SCO_DATA:
+ return MSG_STACK_TO_HC_HCI_SCO;
+ default:
+ LOG_ERROR(LOG_TAG, "%s unsupported packet type: %d", __func__, packet);
+ return -1;
+ }
+}
+
+static void accept_ready(socket_t* socket, UNUSED_ATTR void* context) {
+ CHECK(socket != NULL);
+ CHECK(socket == listen_socket);
+
+ socket = socket_accept(socket);
+ if (!socket) return;
+
+ client_t* client = (client_t*)osi_calloc(sizeof(client_t));
+
+ client->socket = socket;
+
+ if (!list_append(clients, client)) {
+ LOG_ERROR(LOG_TAG, "%s unable to add client to list.", __func__);
+ client_free(client);
+ return;
+ }
+
+ socket_register(socket, thread_get_reactor(thread), client, read_ready, NULL);
+}
+
+static void read_ready(UNUSED_ATTR socket_t* socket, void* context) {
+ CHECK(socket != NULL);
+ CHECK(context != NULL);
+
+ client_t* client = (client_t*)context;
+
+ ssize_t ret =
+ socket_read(client->socket, client->buffer + client->buffer_size,
+ sizeof(client->buffer) - client->buffer_size);
+ if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
+ list_remove(clients, client);
+ return;
+ }
+ client->buffer_size += ret;
+
+ while (client->buffer_size > 3) {
+ uint8_t* buffer = client->buffer;
+ hci_packet_t packet_type = (hci_packet_t)buffer[0];
+ size_t packet_len = (buffer[2] << 8) | buffer[1];
+ size_t frame_len = 3 + packet_len;
+
+ if (client->buffer_size < frame_len) break;
+
+ // TODO(sharvil): validate incoming HCI messages.
+ // TODO(sharvil): once we have an HCI parser, we can eliminate
+ // the 2-byte size field since it will be contained in the packet.
+
+ BT_HDR* buf = (BT_HDR*)buffer_allocator->alloc(BT_HDR_SIZE + packet_len);
+ if (buf) {
+ buf->event = hci_packet_to_event(packet_type);
+ buf->offset = 0;
+ buf->layer_specific = 0;
+ buf->len = packet_len;
+ memcpy(buf->data, buffer + 3, packet_len);
+ hci->transmit_downward(buf->event, buf);
+ } else {
+ LOG_ERROR(LOG_TAG, "%s dropping injected packet of length %zu", __func__,
+ packet_len);
+ }
+
+ size_t remainder = client->buffer_size - frame_len;
+ memmove(buffer, buffer + frame_len, remainder);
+ client->buffer_size -= frame_len;
+ }
+}
+
+static void client_free(void* ptr) {
+ if (!ptr) return;
+
+ client_t* client = (client_t*)ptr;
+ socket_free(client->socket);
+ osi_free(client);
+}
+
+const hci_inject_t* hci_inject_get_interface() {
+ buffer_allocator = buffer_allocator_get_interface();
+ return &interface;
+}
diff --git a/mtkbt/code/bt/hci/src/hci_layer.cc b/mtkbt/code/bt/hci/src/hci_layer.cc
new file mode 100755
index 0000000..7eef64a
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_layer.cc
@@ -0,0 +1,750 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci"
+
+#include "hci_layer.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+#include <base/sequenced_task_runner.h>
+#include <base/threading/thread.h>
+
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <mutex>
+
+#include "btcore/include/module.h"
+#include "btsnoop.h"
+#include "buffer_allocator.h"
+#include "hci_inject.h"
+#include "hci_internals.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+#include "osi/include/reactor.h"
+#include "packet_fragmenter.h"
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+#include "mediatek/include/fw_logger_filter.h"
+#include "mediatek/include/twrite.h"
+using vendor::mediatek::bluetooth::stack::BTSnoop;
+using vendor::mediatek::bluetooth::stack::FWLogFilter;
+#endif
+
+#define BT_HCI_TIMEOUT_TAG_NUM 1010000
+
+extern void hci_initialize();
+extern void hci_transmit(BT_HDR* packet);
+extern void hci_close();
+extern int hci_open_firmware_log_file();
+extern void hci_close_firmware_log_file(int fd);
+extern void hci_log_firmware_debug_packet(int fd, BT_HDR* packet);
+
+static int hci_firmware_log_fd = INVALID_FD;
+
+typedef struct {
+ uint16_t opcode;
+ future_t* complete_future;
+ command_complete_cb complete_callback;
+ command_status_cb status_callback;
+ void* context;
+ BT_HDR* command;
+ std::chrono::time_point<std::chrono::steady_clock> timestamp;
+} waiting_command_t;
+
+// Using a define here, because it can be stringified for the property lookup
+#define DEFAULT_STARTUP_TIMEOUT_MS 8000
+#define STRING_VALUE_OF(x) #x
+
+// RT priority for HCI thread
+static const int BT_HCI_RT_PRIORITY = 1;
+
+// Abort if there is no response to an HCI command.
+static const uint32_t COMMAND_PENDING_TIMEOUT_MS = 2000;
+static const uint32_t COMMAND_TIMEOUT_RESTART_US = 500000;
+
+// Our interface
+static bool interface_created;
+static hci_t interface;
+
+// Modules we import and callbacks we export
+static const allocator_t* buffer_allocator;
+static const btsnoop_t* btsnoop;
+static const packet_fragmenter_t* packet_fragmenter;
+
+static future_t* startup_future;
+static thread_t* thread; // We own this
+static std::mutex message_loop_mutex;
+static base::MessageLoop* message_loop_ = nullptr;
+static base::RunLoop* run_loop_ = nullptr;
+
+static alarm_t* startup_timer;
+
+// Outbound-related
+static int command_credits = 1;
+static std::mutex command_credits_mutex;
+static std::queue<base::Closure> command_queue;
+
+// Inbound-related
+static alarm_t* command_response_timer;
+static list_t* commands_pending_response;
+static std::recursive_mutex commands_pending_response_mutex;
+
+// The hand-off point for data going to a higher layer, set by the higher layer
+static fixed_queue_t* upwards_data_queue;
+
+static bool filter_incoming_event(BT_HDR* packet);
+static waiting_command_t* get_waiting_command(command_opcode_t opcode);
+static int get_num_waiting_commands();
+
+static void event_finish_startup(void* context);
+static void startup_timer_expired(void* context);
+
+static void enqueue_command(waiting_command_t* wait_entry);
+static void event_command_ready(waiting_command_t* wait_entry);
+static void enqueue_packet(void* packet);
+static void event_packet_ready(void* packet);
+static void command_timed_out(void* context);
+
+static void update_command_response_timer(void);
+
+static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished);
+static void dispatch_reassembled(BT_HDR* packet);
+static void fragmenter_transmit_finished(BT_HDR* packet,
+ bool all_fragments_sent);
+
+static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = {
+ transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished};
+
+void initialization_complete() {
+ std::lock_guard<std::mutex> lock(message_loop_mutex);
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&event_finish_startup, nullptr));
+}
+
+void hci_event_received(BT_HDR* packet) {
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ BTSnoop::GetInstance()->Capture(packet, true);
+ if (FWLogFilter::GetInstance()->Intercepted(packet)) {
+ return;
+ }
+#else
+ btsnoop->capture(packet, true);
+#endif
+ if (!filter_incoming_event(packet)) {
+ data_dispatcher_dispatch(interface.event_dispatcher, packet->data[0],
+ packet);
+ }
+}
+
+void acl_event_received(BT_HDR* packet) {
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ BTSnoop::GetInstance()->Capture(packet, true);
+#else
+ btsnoop->capture(packet, true);
+#endif
+ packet_fragmenter->reassemble_and_dispatch(packet);
+}
+
+void sco_data_received(BT_HDR* packet) {
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ BTSnoop::GetInstance()->Capture(packet, true);
+#else
+ btsnoop->capture(packet, true);
+#endif
+ packet_fragmenter->reassemble_and_dispatch(packet);
+}
+
+// Module lifecycle functions
+
+static future_t* hci_module_shut_down();
+
+void message_loop_run(UNUSED_ATTR void* context) {
+ {
+ std::lock_guard<std::mutex> lock(message_loop_mutex);
+ message_loop_ = new base::MessageLoop();
+ run_loop_ = new base::RunLoop();
+ }
+
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ base::Bind(&hci_initialize));
+ run_loop_->Run();
+
+ {
+ std::lock_guard<std::mutex> lock(message_loop_mutex);
+ delete message_loop_;
+ message_loop_ = nullptr;
+ delete run_loop_;
+ run_loop_ = nullptr;
+ }
+}
+
+static future_t* hci_module_start_up(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ // The host is only allowed to send at most one command initially,
+ // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
+ // This value can change when you get a command complete or command status
+ // event.
+ command_credits = 1;
+
+ // For now, always use the default timeout on non-Android builds.
+ period_ms_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+
+ // Grab the override startup timeout ms, if present.
+ char timeout_prop[PROPERTY_VALUE_MAX];
+ if (!osi_property_get("bluetooth.enable_timeout_ms", timeout_prop,
+ STRING_VALUE_OF(DEFAULT_STARTUP_TIMEOUT_MS)) ||
+ (startup_timeout_ms = atoi(timeout_prop)) < 100)
+ startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
+
+ startup_timer = alarm_new("hci.startup_timer");
+ if (!startup_timer) {
+ LOG_ERROR(LOG_TAG, "%s unable to create startup timer.", __func__);
+ goto error;
+ }
+
+ command_response_timer = alarm_new("hci.command_response_timer");
+ if (!command_response_timer) {
+ LOG_ERROR(LOG_TAG, "%s unable to create command response timer.", __func__);
+ goto error;
+ }
+
+ thread = thread_new("hci_thread");
+ if (!thread) {
+ LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
+ goto error;
+ }
+ if (!thread_set_rt_priority(thread, BT_HCI_RT_PRIORITY)) {
+ LOG_ERROR(LOG_TAG, "%s unable to make thread RT.", __func__);
+ }
+
+ commands_pending_response = list_new(NULL);
+ if (!commands_pending_response) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to create list for commands pending response.",
+ __func__);
+ goto error;
+ }
+
+ // Make sure we run in a bounded amount of time
+ future_t* local_startup_future;
+ local_startup_future = future_new();
+ startup_future = local_startup_future;
+ alarm_set(startup_timer, startup_timeout_ms, startup_timer_expired, NULL);
+
+ packet_fragmenter->init(&packet_fragmenter_callbacks);
+
+ thread_post(thread, message_loop_run, NULL);
+
+ LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
+ return local_startup_future;
+
+error:
+ hci_module_shut_down(); // returns NULL so no need to wait for it
+ return future_new_immediate(FUTURE_FAIL);
+}
+
+static future_t* hci_module_shut_down() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ // Free the timers
+ {
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ alarm_free(command_response_timer);
+ command_response_timer = NULL;
+ alarm_free(startup_timer);
+ startup_timer = NULL;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(message_loop_mutex);
+ message_loop_->task_runner()->PostTask(FROM_HERE, run_loop_->QuitClosure());
+ }
+
+ // Stop the thread to prevent Send() calls.
+ if (thread) {
+ thread_stop(thread);
+ thread_join(thread);
+ }
+
+ // Close HCI to prevent callbacks.
+ hci_close();
+
+ {
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ list_free(commands_pending_response);
+ commands_pending_response = NULL;
+ }
+
+ packet_fragmenter->cleanup();
+
+ thread_free(thread);
+ thread = NULL;
+
+ return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t hci_module = {
+ .name = HCI_MODULE,
+ .init = NULL,
+ .start_up = hci_module_start_up,
+ .shut_down = hci_module_shut_down,
+ .clean_up = NULL,
+ .dependencies = {BTSNOOP_MODULE, NULL}};
+
+// Interface functions
+
+static void set_data_queue(fixed_queue_t* queue) { upwards_data_queue = queue; }
+
+static void transmit_command(BT_HDR* command,
+ command_complete_cb complete_callback,
+ command_status_cb status_callback, void* context) {
+ waiting_command_t* wait_entry = reinterpret_cast<waiting_command_t*>(
+ osi_calloc(sizeof(waiting_command_t)));
+
+ uint8_t* stream = command->data + command->offset;
+ STREAM_TO_UINT16(wait_entry->opcode, stream);
+ wait_entry->complete_callback = complete_callback;
+ wait_entry->status_callback = status_callback;
+ wait_entry->command = command;
+ wait_entry->context = context;
+
+ // Store the command message type in the event field
+ // in case the upper layer didn't already
+ command->event = MSG_STACK_TO_HC_HCI_CMD;
+
+ enqueue_command(wait_entry);
+}
+
+static future_t* transmit_command_futured(BT_HDR* command) {
+ waiting_command_t* wait_entry = reinterpret_cast<waiting_command_t*>(
+ osi_calloc(sizeof(waiting_command_t)));
+ future_t* future = future_new();
+
+ uint8_t* stream = command->data + command->offset;
+ STREAM_TO_UINT16(wait_entry->opcode, stream);
+ wait_entry->complete_future = future;
+ wait_entry->command = command;
+
+ // Store the command message type in the event field
+ // in case the upper layer didn't already
+ command->event = MSG_STACK_TO_HC_HCI_CMD;
+
+ enqueue_command(wait_entry);
+ return future;
+}
+
+static void transmit_downward(data_dispatcher_type_t type, void* data) {
+ if (type == MSG_STACK_TO_HC_HCI_CMD) {
+ // TODO(zachoverflow): eliminate this call
+ transmit_command((BT_HDR*)data, NULL, NULL, NULL);
+ LOG_WARN(LOG_TAG,
+ "%s legacy transmit of command. Use transmit_command instead.",
+ __func__);
+ } else {
+ enqueue_packet(data);
+ }
+}
+
+// Start up functions
+
+static void event_finish_startup(UNUSED_ATTR void* context) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ alarm_cancel(startup_timer);
+ future_ready(startup_future, FUTURE_SUCCESS);
+ startup_future = NULL;
+}
+
+static void startup_timer_expired(UNUSED_ATTR void* context) {
+ LOG_ERROR(LOG_TAG, "%s", __func__);
+
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ future_ready(startup_future, FUTURE_FAIL);
+ startup_future = NULL;
+}
+
+// Command/packet transmitting functions
+static void enqueue_command(waiting_command_t* wait_entry) {
+ base::Closure callback = base::Bind(&event_command_ready, wait_entry);
+
+ std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
+ if (command_credits > 0) {
+ std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
+ if (message_loop_ == nullptr) {
+ // HCI Layer was shut down
+ buffer_allocator->free(wait_entry->command);
+ osi_free(wait_entry);
+ return;
+ }
+ message_loop_->task_runner()->PostTask(FROM_HERE, std::move(callback));
+ command_credits--;
+ } else {
+ command_queue.push(std::move(callback));
+ }
+}
+
+static void event_command_ready(waiting_command_t* wait_entry) {
+ /// Move it to the list of commands awaiting response
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ wait_entry->timestamp = std::chrono::steady_clock::now();
+ list_append(commands_pending_response, wait_entry);
+
+ // Send it off
+ packet_fragmenter->fragment_and_dispatch(wait_entry->command);
+
+ update_command_response_timer();
+}
+
+static void enqueue_packet(void* packet) {
+ std::lock_guard<std::mutex> lock(message_loop_mutex);
+ if (message_loop_ == nullptr) {
+ // HCI Layer was shut down
+ buffer_allocator->free(packet);
+ return;
+ }
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&event_packet_ready, packet));
+}
+
+static void event_packet_ready(void* pkt) {
+ // The queue may be the command queue or the packet queue, we don't care
+ BT_HDR* packet = (BT_HDR*)pkt;
+ packet_fragmenter->fragment_and_dispatch(packet);
+}
+
+// Callback for the fragmenter to send a fragment
+static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) {
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ BTSnoop::GetInstance()->Capture(packet, false);
+#else
+ btsnoop->capture(packet, false);
+#endif
+ hci_transmit(packet);
+
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ if (event != MSG_STACK_TO_HC_HCI_CMD && send_transmit_finished)
+ buffer_allocator->free(packet);
+}
+
+static void fragmenter_transmit_finished(BT_HDR* packet,
+ bool all_fragments_sent) {
+ if (all_fragments_sent) {
+ buffer_allocator->free(packet);
+ } else {
+ // This is kind of a weird case, since we're dispatching a partially sent
+ // packet up to a higher layer.
+ // TODO(zachoverflow): rework upper layer so this isn't necessary.
+ data_dispatcher_dispatch(interface.event_dispatcher,
+ packet->event & MSG_EVT_MASK, packet);
+ }
+}
+
+// Print debugging information and quit. Don't dereference original_wait_entry.
+static void command_timed_out(void* original_wait_entry) {
+ std::unique_lock<std::recursive_mutex> lock(commands_pending_response_mutex);
+
+ LOG_ERROR(LOG_TAG, "%s: %d commands pending response", __func__,
+ get_num_waiting_commands());
+
+ for (const list_node_t* node = list_begin(commands_pending_response);
+ node != list_end(commands_pending_response); node = list_next(node)) {
+ waiting_command_t* wait_entry =
+ reinterpret_cast<waiting_command_t*>(list_node(node));
+
+ int wait_time_ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - wait_entry->timestamp)
+ .count();
+ LOG_ERROR(LOG_TAG, "%s: Waited %d ms for a response to opcode: 0x%x %s",
+ __func__, wait_time_ms, wait_entry->opcode,
+ (wait_entry == original_wait_entry) ? "*matches timer*" : "");
+
+ // Dump the length field and the first byte of the payload, if present.
+ uint8_t* command = wait_entry->command->data + wait_entry->command->offset;
+ if (wait_entry->command->len > 3) {
+ LOG_ERROR(LOG_TAG, "%s: Size %d Hex %02x %02x %02x %02x", __func__,
+ wait_entry->command->len, command[0], command[1], command[2],
+ command[3]);
+ } else {
+ LOG_ERROR(LOG_TAG, "%s: Size %d Hex %02x %02x %02x", __func__,
+ wait_entry->command->len, command[0], command[1], command[2]);
+ }
+
+ LOG_EVENT_INT(BT_HCI_TIMEOUT_TAG_NUM, wait_entry->opcode);
+ }
+ lock.unlock();
+ /** M: Bug fix for race condition for pending command timer @{ */
+ if (list_is_empty(commands_pending_response)) return;
+ /** @} */
+
+ LOG_ERROR(LOG_TAG, "%s: requesting a firmware dump.", __func__);
+
+ /* Allocate a buffer to hold the HCI command. */
+ BT_HDR* bt_hdr =
+ static_cast<BT_HDR*>(osi_malloc(sizeof(BT_HDR) + HCIC_PREAMBLE_SIZE));
+
+ bt_hdr->len = HCIC_PREAMBLE_SIZE;
+ bt_hdr->event = MSG_STACK_TO_HC_HCI_CMD;
+ bt_hdr->offset = 0;
+
+ uint8_t* hci_packet = reinterpret_cast<uint8_t*>(bt_hdr + 1);
+
+ UINT16_TO_STREAM(hci_packet,
+ HCI_GRP_VENDOR_SPECIFIC | HCI_CONTROLLER_DEBUG_INFO_OCF);
+ UINT8_TO_STREAM(hci_packet, 0); // No parameters
+
+ hci_firmware_log_fd = hci_open_firmware_log_file();
+
+ transmit_fragment(bt_hdr, true);
+
+ osi_free(bt_hdr);
+
+ LOG_ERROR(LOG_TAG, "%s restarting the Bluetooth process.", __func__);
+ usleep(COMMAND_TIMEOUT_RESTART_US);
+ hci_close_firmware_log_file(hci_firmware_log_fd);
+
+ // We shouldn't try to recover the stack from this command timeout.
+ // If it's caused by a software bug, fix it. If it's a hardware bug, fix it.
+ abort();
+}
+
+// Event/packet receiving functions
+void process_command_credits(int credits) {
+ std::lock_guard<std::mutex> command_credits_lock(command_credits_mutex);
+ std::lock_guard<std::mutex> message_loop_lock(message_loop_mutex);
+
+ if (message_loop_ == nullptr) {
+ // HCI Layer was shut down
+ return;
+ }
+
+ // Subtract commands in flight.
+ command_credits = credits - get_num_waiting_commands();
+
+ while (command_credits > 0 && command_queue.size() > 0) {
+ message_loop_->task_runner()->PostTask(FROM_HERE,
+ std::move(command_queue.front()));
+ command_queue.pop();
+ command_credits--;
+ }
+}
+
+// Returns true if the event was intercepted and should not proceed to
+// higher layers. Also inspects an incoming event for interesting
+// information, like how many commands are now able to be sent.
+static bool filter_incoming_event(BT_HDR* packet) {
+ waiting_command_t* wait_entry = NULL;
+ uint8_t* stream = packet->data;
+ uint8_t event_code;
+ int credits = 0;
+ command_opcode_t opcode;
+
+ STREAM_TO_UINT8(event_code, stream);
+ STREAM_SKIP_UINT8(stream); // Skip the parameter total length field
+
+ if (event_code == HCI_COMMAND_COMPLETE_EVT) {
+ STREAM_TO_UINT8(credits, stream);
+ STREAM_TO_UINT16(opcode, stream);
+
+ wait_entry = get_waiting_command(opcode);
+
+ process_command_credits(credits);
+
+ if (!wait_entry) {
+ if (opcode != HCI_COMMAND_NONE) {
+ LOG_WARN(LOG_TAG,
+ "%s command complete event with no matching command (opcode: "
+ "0x%04x).",
+ __func__, opcode);
+ }
+ } else {
+ update_command_response_timer();
+ if (wait_entry->complete_callback) {
+ wait_entry->complete_callback(packet, wait_entry->context);
+ } else if (wait_entry->complete_future) {
+ future_ready(wait_entry->complete_future, packet);
+ }
+ }
+
+ goto intercepted;
+ } else if (event_code == HCI_COMMAND_STATUS_EVT) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, stream);
+ STREAM_TO_UINT8(credits, stream);
+ STREAM_TO_UINT16(opcode, stream);
+
+ // If a command generates a command status event, it won't be getting a
+ // command complete event
+ wait_entry = get_waiting_command(opcode);
+
+ process_command_credits(credits);
+
+ if (!wait_entry) {
+ LOG_WARN(
+ LOG_TAG,
+ "%s command status event with no matching command. opcode: 0x%04x",
+ __func__, opcode);
+ } else {
+ update_command_response_timer();
+ if (wait_entry->status_callback)
+ wait_entry->status_callback(status, wait_entry->command,
+ wait_entry->context);
+ }
+
+ goto intercepted;
+ } else if (event_code == HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT) {
+ if (hci_firmware_log_fd == INVALID_FD)
+ hci_firmware_log_fd = hci_open_firmware_log_file();
+
+ if (hci_firmware_log_fd != INVALID_FD)
+ hci_log_firmware_debug_packet(hci_firmware_log_fd, packet);
+
+ buffer_allocator->free(packet);
+ return true;
+ }
+
+ return false;
+
+intercepted:
+ if (wait_entry) {
+ // If it has a callback, it's responsible for freeing the packet
+ if (event_code == HCI_COMMAND_STATUS_EVT ||
+ (!wait_entry->complete_callback && !wait_entry->complete_future))
+ buffer_allocator->free(packet);
+
+ // If it has a callback, it's responsible for freeing the command
+ if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback)
+ buffer_allocator->free(wait_entry->command);
+
+ osi_free(wait_entry);
+ } else {
+ buffer_allocator->free(packet);
+ }
+
+ return true;
+}
+
+// Callback for the fragmenter to dispatch up a completely reassembled packet
+static void dispatch_reassembled(BT_HDR* packet) {
+ // Events should already have been dispatched before this point
+ CHECK((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT);
+ CHECK(upwards_data_queue != NULL);
+
+ fixed_queue_enqueue(upwards_data_queue, packet);
+}
+
+// Misc internal functions
+
+static waiting_command_t* get_waiting_command(command_opcode_t opcode) {
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+
+ for (const list_node_t* node = list_begin(commands_pending_response);
+ node != list_end(commands_pending_response); node = list_next(node)) {
+ waiting_command_t* wait_entry =
+ reinterpret_cast<waiting_command_t*>(list_node(node));
+
+ if (!wait_entry || wait_entry->opcode != opcode) continue;
+
+ list_remove(commands_pending_response, wait_entry);
+
+ return wait_entry;
+ }
+
+ return NULL;
+}
+
+static int get_num_waiting_commands() {
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+ return list_length(commands_pending_response);
+}
+
+static void update_command_response_timer(void) {
+ std::lock_guard<std::recursive_mutex> lock(commands_pending_response_mutex);
+
+ if (command_response_timer == NULL) return;
+ if (list_is_empty(commands_pending_response)) {
+ alarm_cancel(command_response_timer);
+ } else {
+ alarm_set(command_response_timer, COMMAND_PENDING_TIMEOUT_MS,
+ command_timed_out, list_front(commands_pending_response));
+ }
+}
+
+static void init_layer_interface() {
+ if (!interface_created) {
+ // It's probably ok for this to live forever. It's small and
+ // there's only one instance of the hci interface.
+ interface.event_dispatcher = data_dispatcher_new("hci_layer");
+ if (!interface.event_dispatcher) {
+ LOG_ERROR(LOG_TAG, "%s could not create upward dispatcher.", __func__);
+ return;
+ }
+
+ interface.set_data_queue = set_data_queue;
+ interface.transmit_command = transmit_command;
+ interface.transmit_command_futured = transmit_command_futured;
+ interface.transmit_downward = transmit_downward;
+ interface_created = true;
+ }
+}
+
+void hci_layer_cleanup_interface() {
+ if (interface_created) {
+ data_dispatcher_free(interface.event_dispatcher);
+ interface.event_dispatcher = NULL;
+
+ interface.set_data_queue = NULL;
+ interface.transmit_command = NULL;
+ interface.transmit_command_futured = NULL;
+ interface.transmit_downward = NULL;
+ interface_created = false;
+ }
+}
+
+const hci_t* hci_layer_get_interface() {
+ buffer_allocator = buffer_allocator_get_interface();
+ btsnoop = btsnoop_get_interface();
+ packet_fragmenter = packet_fragmenter_get_interface();
+
+ init_layer_interface();
+
+ return &interface;
+}
+
+const hci_t* hci_layer_get_test_interface(
+ const allocator_t* buffer_allocator_interface,
+ const btsnoop_t* btsnoop_interface,
+ const packet_fragmenter_t* packet_fragmenter_interface) {
+ buffer_allocator = buffer_allocator_interface;
+ btsnoop = btsnoop_interface;
+ packet_fragmenter = packet_fragmenter_interface;
+
+ init_layer_interface();
+ return &interface;
+}
diff --git a/mtkbt/code/bt/hci/src/hci_layer_android.cc b/mtkbt/code/bt/hci/src/hci_layer_android.cc
new file mode 100755
index 0000000..dff6bfa
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_layer_android.cc
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci"
+
+#include "hci_layer.h"
+
+#include <base/logging.h>
+#include "buffer_allocator.h"
+#include "osi/include/log.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
+#include <android/hardware/bluetooth/1.0/types.h>
+#include <hwbinder/ProcessState.h>
+
+#define LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log"
+#define LAST_LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log.last"
+
+using android::hardware::bluetooth::V1_0::IBluetoothHci;
+using android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using android::hardware::bluetooth::V1_0::HciPacket;
+using android::hardware::bluetooth::V1_0::Status;
+using android::hardware::ProcessState;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+
+extern void initialization_complete();
+extern void hci_event_received(BT_HDR* packet);
+extern void acl_event_received(BT_HDR* packet);
+extern void sco_data_received(BT_HDR* packet);
+
+android::sp<IBluetoothHci> btHci;
+
+class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
+ public:
+ BluetoothHciCallbacks() {
+ buffer_allocator = buffer_allocator_get_interface();
+ }
+
+ BT_HDR* WrapPacketAndCopy(uint16_t event, const hidl_vec<uint8_t>& data) {
+ size_t packet_size = data.size() + BT_HDR_SIZE;
+ BT_HDR* packet =
+ reinterpret_cast<BT_HDR*>(buffer_allocator->alloc(packet_size));
+ packet->offset = 0;
+ packet->len = data.size();
+ packet->layer_specific = 0;
+ packet->event = event;
+ // TODO(eisenbach): Avoid copy here; if BT_HDR->data can be ensured to
+ // be the only way the data is accessed, a pointer could be passed here...
+ memcpy(packet->data, data.data(), data.size());
+ return packet;
+ }
+
+ Return<void> initializationComplete(Status status) {
+ CHECK(status == Status::SUCCESS);
+ initialization_complete();
+ return Void();
+ }
+
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event);
+ hci_event_received(packet);
+ return Void();
+ }
+
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, data);
+ acl_event_received(packet);
+ return Void();
+ }
+
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, data);
+ sco_data_received(packet);
+ return Void();
+ }
+
+ const allocator_t* buffer_allocator;
+};
+
+void hci_initialize() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ btHci = IBluetoothHci::getService();
+ // If android.hardware.bluetooth* is not found, Bluetooth can not continue.
+ CHECK(btHci != nullptr);
+ LOG_INFO(LOG_TAG, "%s: IBluetoothHci::getService() returned %p (%s)",
+ __func__, btHci.get(), (btHci->isRemote() ? "remote" : "local"));
+
+ // Block allows allocation of a variable that might be bypassed by goto.
+ {
+ android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
+ btHci->initialize(callbacks);
+ }
+}
+
+void hci_close() {
+ btHci->close();
+ btHci = nullptr;
+}
+
+void hci_transmit(BT_HDR* packet) {
+ HciPacket data;
+ data.setToExternal(packet->data + packet->offset, packet->len);
+
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ switch (event & MSG_EVT_MASK) {
+ case MSG_STACK_TO_HC_HCI_CMD:
+ btHci->sendHciCommand(data);
+ break;
+ case MSG_STACK_TO_HC_HCI_ACL:
+ btHci->sendAclData(data);
+ break;
+ case MSG_STACK_TO_HC_HCI_SCO:
+ btHci->sendScoData(data);
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "Unknown packet type (%d)", event);
+ break;
+ }
+}
+
+int hci_open_firmware_log_file() {
+ if (rename(LOG_PATH, LAST_LOG_PATH) == -1 && errno != ENOENT) {
+ LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
+ LOG_PATH, LAST_LOG_PATH, strerror(errno));
+ }
+
+ mode_t prevmask = umask(0);
+ int logfile_fd = open(LOG_PATH, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ umask(prevmask);
+ if (logfile_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, LOG_PATH,
+ strerror(errno));
+ }
+
+ return logfile_fd;
+}
+
+void hci_close_firmware_log_file(int fd) {
+ if (fd != INVALID_FD) close(fd);
+}
+
+void hci_log_firmware_debug_packet(int fd, BT_HDR* packet) {
+ TEMP_FAILURE_RETRY(write(fd, packet->data, packet->len));
+}
diff --git a/mtkbt/code/bt/hci/src/hci_layer_linux.cc b/mtkbt/code/bt/hci/src/hci_layer_linux.cc
new file mode 100755
index 0000000..51d8429
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_layer_linux.cc
@@ -0,0 +1,398 @@
+/**********************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **********************************************************************/
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/threading/thread.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "buffer_allocator.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+#include "osi/include/compat.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+using base::Thread;
+
+#define BTPROTO_HCI 1
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+#define RFKILL_TYPE_BLUETOOTH 2
+#define RFKILL_OP_CHANGE_ALL 3
+
+#define MGMT_OP_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_COMMAND_COMP 0x0001
+#define MGMT_EV_SIZE_MAX 1024
+#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
+
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+ unsigned short hci_channel;
+};
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft, hard;
+} __attribute__((packed));
+
+struct mgmt_pkt {
+ uint16_t opcode;
+ uint16_t index;
+ uint16_t len;
+ uint8_t data[MGMT_EV_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_event_read_index {
+ uint16_t cc_opcode;
+ uint8_t status;
+ uint16_t num_intf;
+ uint16_t index[0];
+} __attribute__((packed));
+
+enum HciPacketType {
+ HCI_PACKET_TYPE_UNKNOWN = 0,
+ HCI_PACKET_TYPE_COMMAND = 1,
+ HCI_PACKET_TYPE_ACL_DATA = 2,
+ HCI_PACKET_TYPE_SCO_DATA = 3,
+ HCI_PACKET_TYPE_EVENT = 4
+};
+
+extern void initialization_complete();
+extern void hci_event_received(BT_HDR* packet);
+extern void acl_event_received(BT_HDR* packet);
+extern void sco_data_received(BT_HDR* packet);
+
+static int bt_vendor_fd = -1;
+static int hci_interface;
+static int rfkill_en;
+static int wait_hcidev(void);
+static int rfkill(int block);
+
+int reader_thread_ctrl_fd = -1;
+Thread* reader_thread = NULL;
+
+void monitor_socket(int ctrl_fd, int fd) {
+ const allocator_t* buffer_allocator = buffer_allocator_get_interface();
+ const size_t buf_size = 2000;
+ uint8_t buf[buf_size];
+ ssize_t len = read(fd, buf, buf_size);
+
+ while (len > 0) {
+ if (len == buf_size)
+ LOG(FATAL) << "This packet filled buffer, if it have continuation we "
+ "don't know how to merge it, increase buffer size!";
+
+ uint8_t type = buf[0];
+
+ size_t packet_size = buf_size + BT_HDR_SIZE;
+ BT_HDR* packet =
+ reinterpret_cast<BT_HDR*>(buffer_allocator->alloc(packet_size));
+ packet->offset = 0;
+ packet->layer_specific = 0;
+ packet->len = len - 1;
+ memcpy(packet->data, buf + 1, len - 1);
+
+ switch (type) {
+ case HCI_PACKET_TYPE_COMMAND:
+ packet->event = MSG_HC_TO_STACK_HCI_EVT;
+ hci_event_received(packet);
+ break;
+ case HCI_PACKET_TYPE_ACL_DATA:
+ packet->event = MSG_HC_TO_STACK_HCI_ACL;
+ acl_event_received(packet);
+ break;
+ case HCI_PACKET_TYPE_SCO_DATA:
+ packet->event = MSG_HC_TO_STACK_HCI_SCO;
+ sco_data_received(packet);
+ break;
+ case HCI_PACKET_TYPE_EVENT:
+ packet->event = MSG_HC_TO_STACK_HCI_EVT;
+ hci_event_received(packet);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected event type: " << +type;
+ break;
+ }
+
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(ctrl_fd, &fds);
+ FD_SET(fd, &fds);
+ int res = select(std::max(fd, ctrl_fd) + 1, &fds, NULL, NULL, NULL);
+ if (res <= 0) LOG(INFO) << "Nothing more to read";
+
+ if (FD_ISSET(ctrl_fd, &fds)) {
+ LOG(INFO) << "exitting";
+ return;
+ }
+
+ len = read(fd, buf, buf_size);
+ }
+}
+
+/* TODO: should thread the device waiting and return immedialty */
+void hci_initialize() {
+ LOG(INFO) << __func__;
+
+ char prop_value[PROPERTY_VALUE_MAX];
+ osi_property_get("bluetooth.interface", prop_value, "0");
+
+ errno = 0;
+ if (memcmp(prop_value, "hci", 3))
+ hci_interface = strtol(prop_value, NULL, 10);
+ else
+ hci_interface = strtol(prop_value + 3, NULL, 10);
+ if (errno) hci_interface = 0;
+
+ LOG(INFO) << "Using interface hci" << +hci_interface;
+
+ osi_property_get("bluetooth.rfkill", prop_value, "1");
+
+ rfkill_en = atoi(prop_value);
+ if (rfkill_en) {
+ rfkill(0);
+ }
+
+ int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ CHECK(fd >= 0) << "socket create error" << strerror(errno);
+
+ bt_vendor_fd = fd;
+
+ if (wait_hcidev()) {
+ LOG(FATAL) << "HCI interface hci" << +hci_interface << " not found";
+ }
+
+ struct sockaddr_hci addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = hci_interface;
+ addr.hci_channel = HCI_CHANNEL_USER;
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ LOG(FATAL) << "socket bind error " << strerror(errno);
+ }
+
+ int sv[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+ LOG(FATAL) << "socketpair failed: " << strerror(errno);
+ }
+
+ reader_thread_ctrl_fd = sv[0];
+ reader_thread = new Thread("hci_sock_reader");
+ reader_thread->Start();
+ reader_thread->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&monitor_socket, sv[1], bt_vendor_fd));
+
+ LOG(INFO) << "HCI device ready";
+ initialization_complete();
+}
+
+void hci_close() {
+ LOG(INFO) << __func__;
+
+ if (bt_vendor_fd != -1) {
+ close(bt_vendor_fd);
+ bt_vendor_fd = -1;
+ }
+
+ if (reader_thread_ctrl_fd != -1) {
+ uint8_t msg[] = {1};
+ send(reader_thread_ctrl_fd, msg, sizeof(msg), 0);
+ reader_thread_ctrl_fd = -1;
+ }
+
+ if (reader_thread != NULL) {
+ reader_thread->Stop();
+ delete reader_thread;
+ reader_thread = NULL;
+ }
+
+ rfkill(1);
+}
+
+void hci_transmit(BT_HDR* packet) {
+ uint8_t type;
+
+ CHECK(bt_vendor_fd != -1);
+
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ switch (event & MSG_EVT_MASK) {
+ case MSG_STACK_TO_HC_HCI_CMD:
+ type = 1;
+ break;
+ case MSG_STACK_TO_HC_HCI_ACL:
+ type = 2;
+ break;
+ case MSG_STACK_TO_HC_HCI_SCO:
+ type = 3;
+ break;
+ default:
+ LOG(FATAL) << "Unknown packet type " << event;
+ break;
+ }
+
+ uint8_t* addr = packet->data + packet->offset - 1;
+ uint8_t store = *addr;
+ *addr = type;
+ size_t ret = write(bt_vendor_fd, addr, packet->len + 1);
+
+ *(addr) = store;
+
+ if (ret != packet->len + 1) LOG(ERROR) << "Should have send whole packet";
+
+ if (ret == -1) LOG(FATAL) << strerror(errno);
+}
+
+static int wait_hcidev(void) {
+ struct sockaddr_hci addr;
+ struct pollfd fds[1];
+ struct mgmt_pkt ev;
+ int fd;
+ int ret = 0;
+
+ LOG(INFO) << __func__;
+
+ fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ LOG(ERROR) << "Bluetooth socket error: %s" << strerror(errno);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ LOG(ERROR) << "HCI Channel Control: " << strerror(errno);
+ close(fd);
+ return -1;
+ }
+
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+
+ /* Read Controller Index List Command */
+ ev.opcode = MGMT_OP_INDEX_LIST;
+ ev.index = HCI_DEV_NONE;
+ ev.len = 0;
+
+ ssize_t wrote;
+ OSI_NO_INTR(wrote = write(fd, &ev, 6));
+ if (wrote != 6) {
+ LOG(ERROR) << "Unable to write mgmt command: " << strerror(errno);
+ ret = -1;
+ goto end;
+ }
+
+ while (1) {
+ int n;
+ OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
+ if (n == -1) {
+ LOG(ERROR) << "Poll error: " << strerror(errno);
+ ret = -1;
+ break;
+ } else if (n == 0) {
+ LOG(ERROR) << "Timeout, no HCI device detected";
+ ret = -1;
+ break;
+ }
+
+ if (fds[0].revents & POLLIN) {
+ OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
+ if (n < 0) {
+ LOG(ERROR) << "Error reading control channel: " << strerror(errno);
+ ret = -1;
+ break;
+ }
+
+ if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+ goto end;
+ } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
+ struct mgmt_event_read_index* cc;
+ int i;
+
+ cc = (struct mgmt_event_read_index*)ev.data;
+
+ if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
+
+ for (i = 0; i < cc->num_intf; i++) {
+ if (cc->index[i] == hci_interface) goto end;
+ }
+ }
+ }
+ }
+
+end:
+ close(fd);
+ return ret;
+}
+
+static int rfkill(int block) {
+ struct rfkill_event event;
+ int fd;
+
+ LOG(INFO) << __func__;
+
+ fd = open("/dev/rfkill", O_WRONLY);
+ if (fd < 0) {
+ LOG(ERROR) << "Unable to open /dev/rfkill";
+ return -1;
+ }
+
+ memset(&event, 0, sizeof(struct rfkill_event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = RFKILL_TYPE_BLUETOOTH;
+ event.hard = block;
+ event.soft = block;
+
+ ssize_t len;
+ OSI_NO_INTR(len = write(fd, &event, sizeof(event)));
+ if (len < 0) {
+ LOG(ERROR) << "Failed to change rfkill state";
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int hci_open_firmware_log_file() { return INVALID_FD; }
+
+void hci_close_firmware_log_file(int fd) {}
+
+void hci_log_firmware_debug_packet(int fd, BT_HDR* packet) {}
diff --git a/mtkbt/code/bt/hci/src/hci_packet_factory.cc b/mtkbt/code/bt/hci/src/hci_packet_factory.cc
new file mode 100755
index 0000000..c3c4a60
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_packet_factory.cc
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+
+#include "bt_types.h"
+#include "buffer_allocator.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+#include "hci_packet_factory.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "osi/include/allocator.h"
+
+static const allocator_t* buffer_allocator;
+
+static BT_HDR* make_packet(size_t data_size);
+static BT_HDR* make_command_no_params(uint16_t opcode);
+static BT_HDR* make_command(uint16_t opcode, size_t parameter_size,
+ uint8_t** stream_out);
+
+// Interface functions
+
+static BT_HDR* make_reset(void) { return make_command_no_params(HCI_RESET); }
+
+static BT_HDR* make_read_buffer_size(void) {
+ return make_command_no_params(HCI_READ_BUFFER_SIZE);
+}
+
+static BT_HDR* make_host_buffer_size(uint16_t acl_size, uint8_t sco_size,
+ uint16_t acl_count, uint16_t sco_count) {
+ uint8_t* stream;
+ const uint8_t parameter_size = 2 + 1 + 2 + 2; // from each of the parameters
+ BT_HDR* packet = make_command(HCI_HOST_BUFFER_SIZE, parameter_size, &stream);
+
+ UINT16_TO_STREAM(stream, acl_size);
+ UINT8_TO_STREAM(stream, sco_size);
+ UINT16_TO_STREAM(stream, acl_count);
+ UINT16_TO_STREAM(stream, sco_count);
+ return packet;
+}
+
+static BT_HDR* make_read_local_version_info(void) {
+ return make_command_no_params(HCI_READ_LOCAL_VERSION_INFO);
+}
+
+static BT_HDR* make_read_bd_addr(void) {
+ return make_command_no_params(HCI_READ_BD_ADDR);
+}
+
+static BT_HDR* make_read_local_supported_commands(void) {
+ return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CMDS);
+}
+
+static BT_HDR* make_read_local_extended_features(uint8_t page_number) {
+ uint8_t* stream;
+ const uint8_t parameter_size = 1;
+ BT_HDR* packet =
+ make_command(HCI_READ_LOCAL_EXT_FEATURES, parameter_size, &stream);
+
+ UINT8_TO_STREAM(stream, page_number);
+ return packet;
+}
+
+static BT_HDR* make_write_simple_pairing_mode(uint8_t mode) {
+ uint8_t* stream;
+ const uint8_t parameter_size = 1;
+ BT_HDR* packet =
+ make_command(HCI_WRITE_SIMPLE_PAIRING_MODE, parameter_size, &stream);
+
+ UINT8_TO_STREAM(stream, mode);
+ return packet;
+}
+
+static BT_HDR* make_write_secure_connections_host_support(uint8_t mode) {
+ uint8_t* stream;
+ const uint8_t parameter_size = 1;
+ BT_HDR* packet =
+ make_command(HCI_WRITE_SECURE_CONNS_SUPPORT, parameter_size, &stream);
+
+ UINT8_TO_STREAM(stream, mode);
+ return packet;
+}
+
+static BT_HDR* make_set_event_mask(const bt_event_mask_t* event_mask) {
+ uint8_t* stream;
+ uint8_t parameter_size = sizeof(bt_event_mask_t);
+ BT_HDR* packet = make_command(HCI_SET_EVENT_MASK, parameter_size, &stream);
+
+ ARRAY8_TO_STREAM(stream, event_mask->as_array);
+ return packet;
+}
+
+static BT_HDR* make_ble_write_host_support(uint8_t supported_host,
+ uint8_t simultaneous_host) {
+ uint8_t* stream;
+ const uint8_t parameter_size = 1 + 1;
+ BT_HDR* packet =
+ make_command(HCI_WRITE_LE_HOST_SUPPORT, parameter_size, &stream);
+
+ UINT8_TO_STREAM(stream, supported_host);
+ UINT8_TO_STREAM(stream, simultaneous_host);
+ return packet;
+}
+
+static BT_HDR* make_ble_read_white_list_size(void) {
+ return make_command_no_params(HCI_BLE_READ_WHITE_LIST_SIZE);
+}
+
+static BT_HDR* make_ble_read_buffer_size(void) {
+ return make_command_no_params(HCI_BLE_READ_BUFFER_SIZE);
+}
+
+static BT_HDR* make_ble_read_supported_states(void) {
+ return make_command_no_params(HCI_BLE_READ_SUPPORTED_STATES);
+}
+
+static BT_HDR* make_ble_read_local_supported_features(void) {
+ return make_command_no_params(HCI_BLE_READ_LOCAL_SPT_FEAT);
+}
+
+static BT_HDR* make_ble_read_resolving_list_size(void) {
+ return make_command_no_params(HCI_BLE_READ_RESOLVING_LIST_SIZE);
+}
+
+static BT_HDR* make_ble_read_suggested_default_data_length(void) {
+ return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
+}
+
+static BT_HDR* make_ble_read_maximum_advertising_data_length(void) {
+ return make_command_no_params(HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH);
+}
+
+static BT_HDR* make_ble_read_number_of_supported_advertising_sets(void) {
+ return make_command_no_params(
+ HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS);
+}
+
+static BT_HDR* make_read_local_supported_codecs(void) {
+ return make_command_no_params(HCI_READ_LOCAL_SUPPORTED_CODECS);
+}
+
+static BT_HDR* make_ble_set_event_mask(const bt_event_mask_t* event_mask) {
+ uint8_t* stream;
+ uint8_t parameter_size = sizeof(bt_event_mask_t);
+ BT_HDR* packet =
+ make_command(HCI_BLE_SET_EVENT_MASK, parameter_size, &stream);
+
+ ARRAY8_TO_STREAM(stream, event_mask->as_array);
+ return packet;
+}
+
+// Internal functions
+
+static BT_HDR* make_command_no_params(uint16_t opcode) {
+ return make_command(opcode, 0, NULL);
+}
+
+static BT_HDR* make_command(uint16_t opcode, size_t parameter_size,
+ uint8_t** stream_out) {
+ BT_HDR* packet = make_packet(HCI_COMMAND_PREAMBLE_SIZE + parameter_size);
+
+ uint8_t* stream = packet->data;
+ UINT16_TO_STREAM(stream, opcode);
+ UINT8_TO_STREAM(stream, parameter_size);
+
+ if (stream_out != NULL) *stream_out = stream;
+
+ return packet;
+}
+
+static BT_HDR* make_packet(size_t data_size) {
+ BT_HDR* ret = (BT_HDR*)buffer_allocator->alloc(sizeof(BT_HDR) + data_size);
+ CHECK(ret);
+ ret->event = 0;
+ ret->offset = 0;
+ ret->layer_specific = 0;
+ ret->len = data_size;
+ return ret;
+}
+
+static const hci_packet_factory_t interface = {
+ make_reset,
+ make_read_buffer_size,
+ make_host_buffer_size,
+ make_read_local_version_info,
+ make_read_bd_addr,
+ make_read_local_supported_commands,
+ make_read_local_extended_features,
+ make_write_simple_pairing_mode,
+ make_write_secure_connections_host_support,
+ make_set_event_mask,
+ make_ble_write_host_support,
+ make_ble_read_white_list_size,
+ make_ble_read_buffer_size,
+ make_ble_read_supported_states,
+ make_ble_read_local_supported_features,
+ make_ble_read_resolving_list_size,
+ make_ble_read_suggested_default_data_length,
+ make_ble_read_maximum_advertising_data_length,
+ make_ble_read_number_of_supported_advertising_sets,
+ make_ble_set_event_mask,
+ make_read_local_supported_codecs};
+
+const hci_packet_factory_t* hci_packet_factory_get_interface() {
+ buffer_allocator = buffer_allocator_get_interface();
+ return &interface;
+}
diff --git a/mtkbt/code/bt/hci/src/hci_packet_parser.cc b/mtkbt/code/bt/hci/src/hci_packet_parser.cc
new file mode 100755
index 0000000..faf3939
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/hci_packet_parser.cc
@@ -0,0 +1,278 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci"
+
+#include "hci_packet_parser.h"
+
+#include <base/logging.h>
+
+#include "buffer_allocator.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "osi/include/log.h"
+
+static const command_opcode_t NO_OPCODE_CHECKING = 0;
+
+static const allocator_t* buffer_allocator;
+
+static uint8_t* read_command_complete_header(BT_HDR* response,
+ command_opcode_t expected_opcode,
+ size_t minimum_bytes_after);
+
+static void parse_generic_command_complete(BT_HDR* response) {
+ read_command_complete_header(response, NO_OPCODE_CHECKING,
+ 0 /* bytes after */);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_buffer_size_response(BT_HDR* response,
+ uint16_t* data_size_ptr,
+ uint16_t* acl_buffer_count_ptr) {
+ uint8_t* stream = read_command_complete_header(response, HCI_READ_BUFFER_SIZE,
+ 5 /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_UINT16(*data_size_ptr, stream);
+ STREAM_SKIP_UINT8(stream); // skip the sco packet length
+ STREAM_TO_UINT16(*acl_buffer_count_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_local_version_info_response(BT_HDR* response,
+ bt_version_t* bt_version) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_READ_LOCAL_VERSION_INFO, 8 /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_UINT8(bt_version->hci_version, stream);
+ STREAM_TO_UINT16(bt_version->hci_revision, stream);
+ STREAM_TO_UINT8(bt_version->lmp_version, stream);
+ STREAM_TO_UINT16(bt_version->manufacturer, stream);
+ STREAM_TO_UINT16(bt_version->lmp_subversion, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_local_supported_codecs_response(
+ BT_HDR* response, uint8_t* number_of_local_supported_codecs,
+ uint8_t* local_supported_codecs) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_READ_LOCAL_SUPPORTED_CODECS, 0 /* bytes after */);
+ if (stream) {
+ STREAM_TO_UINT8(*number_of_local_supported_codecs, stream);
+ for (uint8_t i = 0; i < *number_of_local_supported_codecs; i++) {
+ STREAM_TO_UINT8(*local_supported_codecs, stream);
+ local_supported_codecs++;
+ }
+ }
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_bd_addr_response(BT_HDR* response,
+ bt_bdaddr_t* address_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_READ_BD_ADDR, sizeof(bt_bdaddr_t) /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_BDADDR(address_ptr->address, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_local_supported_commands_response(
+ BT_HDR* response, uint8_t* supported_commands_ptr,
+ size_t supported_commands_length) {
+ uint8_t* stream =
+ read_command_complete_header(response, HCI_READ_LOCAL_SUPPORTED_CMDS,
+ supported_commands_length /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_ARRAY(supported_commands_ptr, stream,
+ (int)supported_commands_length);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_read_local_extended_features_response(
+ BT_HDR* response, uint8_t* page_number_ptr, uint8_t* max_page_number_ptr,
+ bt_device_features_t* feature_pages, size_t feature_pages_count) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_READ_LOCAL_EXT_FEATURES,
+ 2 + sizeof(bt_device_features_t) /* bytes after */);
+ CHECK(stream != NULL);
+
+ STREAM_TO_UINT8(*page_number_ptr, stream);
+ STREAM_TO_UINT8(*max_page_number_ptr, stream);
+
+ CHECK(*page_number_ptr < feature_pages_count);
+ STREAM_TO_ARRAY(feature_pages[*page_number_ptr].as_array, stream,
+ (int)sizeof(bt_device_features_t));
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_white_list_size_response(
+ BT_HDR* response, uint8_t* white_list_size_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_BLE_READ_WHITE_LIST_SIZE, 1 /* byte after */);
+ CHECK(stream != NULL);
+ STREAM_TO_UINT8(*white_list_size_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_buffer_size_response(BT_HDR* response,
+ uint16_t* data_size_ptr,
+ uint8_t* acl_buffer_count_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_BLE_READ_BUFFER_SIZE, 3 /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_UINT16(*data_size_ptr, stream);
+ STREAM_TO_UINT8(*acl_buffer_count_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_supported_states_response(
+ BT_HDR* response, uint8_t* supported_states, size_t supported_states_size) {
+ uint8_t* stream =
+ read_command_complete_header(response, HCI_BLE_READ_SUPPORTED_STATES,
+ supported_states_size /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_ARRAY(supported_states, stream, (int)supported_states_size);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_local_supported_features_response(
+ BT_HDR* response, bt_device_features_t* supported_features) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_BLE_READ_LOCAL_SPT_FEAT,
+ sizeof(bt_device_features_t) /* bytes after */);
+ CHECK(stream != NULL);
+ STREAM_TO_ARRAY(supported_features->as_array, stream,
+ (int)sizeof(bt_device_features_t));
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_resolving_list_size_response(
+ BT_HDR* response, uint8_t* resolving_list_size_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_BLE_READ_RESOLVING_LIST_SIZE, 1 /* bytes after */);
+ STREAM_TO_UINT8(*resolving_list_size_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_suggested_default_data_length_response(
+ BT_HDR* response, uint16_t* ble_default_packet_length_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */);
+ STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream);
+}
+
+static void parse_ble_read_maximum_advertising_data_length(
+ BT_HDR* response, uint16_t* ble_maximum_advertising_data_length_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH,
+ 2 /* bytes after */);
+ STREAM_TO_UINT16(*ble_maximum_advertising_data_length_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+static void parse_ble_read_number_of_supported_advertising_sets(
+ BT_HDR* response, uint8_t* ble_number_of_supported_advertising_sets_ptr) {
+ uint8_t* stream = read_command_complete_header(
+ response, HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS,
+ 1 /* bytes after */);
+ STREAM_TO_UINT8(*ble_number_of_supported_advertising_sets_ptr, stream);
+
+ buffer_allocator->free(response);
+}
+
+// Internal functions
+
+static uint8_t* read_command_complete_header(BT_HDR* response,
+ command_opcode_t expected_opcode,
+ size_t minimum_bytes_after) {
+ uint8_t* stream = response->data + response->offset;
+
+ // Read the event header
+ uint8_t event_code;
+ uint8_t parameter_length;
+ STREAM_TO_UINT8(event_code, stream);
+ STREAM_TO_UINT8(parameter_length, stream);
+
+ const size_t parameter_bytes_we_read_here = 4;
+
+ // Check the event header values against what we expect
+ CHECK(event_code == HCI_COMMAND_COMPLETE_EVT);
+ CHECK(parameter_length >=
+ (parameter_bytes_we_read_here + minimum_bytes_after));
+
+ // Read the command complete header
+ command_opcode_t opcode;
+ uint8_t status;
+ STREAM_SKIP_UINT8(stream); // skip the number of hci command packets field
+ STREAM_TO_UINT16(opcode, stream);
+
+ // Check the command complete header values against what we expect
+ if (expected_opcode != NO_OPCODE_CHECKING) {
+ CHECK(opcode == expected_opcode);
+ }
+
+ // Assume the next field is the status field
+ STREAM_TO_UINT8(status, stream);
+
+ if (status != HCI_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: return status - 0x%x", __func__, status);
+ return NULL;
+ }
+
+ return stream;
+}
+
+static const hci_packet_parser_t interface = {
+ parse_generic_command_complete,
+ parse_read_buffer_size_response,
+ parse_read_local_version_info_response,
+ parse_read_bd_addr_response,
+ parse_read_local_supported_commands_response,
+ parse_read_local_extended_features_response,
+ parse_ble_read_white_list_size_response,
+ parse_ble_read_buffer_size_response,
+ parse_ble_read_supported_states_response,
+ parse_ble_read_local_supported_features_response,
+ parse_ble_read_resolving_list_size_response,
+ parse_ble_read_suggested_default_data_length_response,
+ parse_ble_read_maximum_advertising_data_length,
+ parse_ble_read_number_of_supported_advertising_sets,
+ parse_read_local_supported_codecs_response};
+
+const hci_packet_parser_t* hci_packet_parser_get_interface() {
+ buffer_allocator = buffer_allocator_get_interface();
+ return &interface;
+}
+
+const hci_packet_parser_t* hci_packet_parser_get_test_interface(
+ allocator_t* buffer_allocator_interface) {
+ buffer_allocator = buffer_allocator_interface;
+ return &interface;
+}
diff --git a/mtkbt/code/bt/hci/src/packet_fragmenter.cc b/mtkbt/code/bt/hci/src/packet_fragmenter.cc
new file mode 100755
index 0000000..7ac4850
--- a/dev/null
+++ b/mtkbt/code/bt/hci/src/packet_fragmenter.cc
@@ -0,0 +1,256 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci_packet_fragmenter"
+
+#include "packet_fragmenter.h"
+
+#include <base/logging.h>
+#include <string.h>
+#include <unordered_map>
+
+#include "bt_target.h"
+#include "buffer_allocator.h"
+#include "device/include/controller.h"
+#include "hci_internals.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define APPLY_CONTINUATION_FLAG(handle) (((handle)&0xCFFF) | 0x1000)
+#define APPLY_START_FLAG(handle) (((handle)&0xCFFF) | 0x2000)
+#define SUB_EVENT(event) ((event)&MSG_SUB_EVT_MASK)
+#define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
+
+#define HANDLE_MASK 0x0FFF
+#define START_PACKET_BOUNDARY 2
+#define CONTINUATION_PACKET_BOUNDARY 1
+#define L2CAP_HEADER_SIZE 4
+
+// Our interface and callbacks
+
+static const allocator_t* buffer_allocator;
+static const controller_t* controller;
+static const packet_fragmenter_callbacks_t* callbacks;
+
+static std::unordered_map<uint16_t /* handle */, BT_HDR*> partial_packets;
+
+static void init(const packet_fragmenter_callbacks_t* result_callbacks) {
+ callbacks = result_callbacks;
+}
+
+static void cleanup() { partial_packets.clear(); }
+
+static void fragment_and_dispatch(BT_HDR* packet) {
+ CHECK(packet != NULL);
+
+ uint16_t event = packet->event & MSG_EVT_MASK;
+ uint8_t* stream = packet->data + packet->offset;
+
+ // We only fragment ACL packets
+ if (event != MSG_STACK_TO_HC_HCI_ACL) {
+ callbacks->fragmented(packet, true);
+ return;
+ }
+
+ uint16_t max_data_size =
+ SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID
+ ? controller->get_acl_data_size_classic()
+ : controller->get_acl_data_size_ble();
+
+ uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE;
+ uint16_t remaining_length = packet->len;
+
+ uint16_t continuation_handle;
+ STREAM_TO_UINT16(continuation_handle, stream);
+ continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle);
+
+ while (remaining_length > max_packet_size) {
+ // Make sure we use the right ACL packet size
+ stream = packet->data + packet->offset;
+ STREAM_SKIP_UINT16(stream);
+ UINT16_TO_STREAM(stream, max_data_size);
+
+ packet->len = max_packet_size;
+ callbacks->fragmented(packet, false);
+
+ packet->offset += max_data_size;
+ remaining_length -= max_data_size;
+ packet->len = remaining_length;
+
+ // Write the ACL header for the next fragment
+ stream = packet->data + packet->offset;
+ UINT16_TO_STREAM(stream, continuation_handle);
+ UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE);
+
+ // Apparently L2CAP can set layer_specific to a max number of segments to
+ // transmit
+ if (packet->layer_specific) {
+ packet->layer_specific--;
+
+ if (packet->layer_specific == 0) {
+ packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
+ callbacks->transmit_finished(packet, false);
+ return;
+ }
+ }
+ }
+
+ callbacks->fragmented(packet, true);
+}
+
+static bool check_uint16_overflow(uint16_t a, uint16_t b) {
+ return (UINT16_MAX - a) < b;
+}
+
+static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR* packet) {
+ if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
+ uint8_t* stream = packet->data;
+ uint16_t handle;
+ uint16_t l2cap_length;
+ uint16_t acl_length;
+
+ STREAM_TO_UINT16(handle, stream);
+ STREAM_TO_UINT16(acl_length, stream);
+ STREAM_TO_UINT16(l2cap_length, stream);
+
+ CHECK(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
+
+ uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle);
+ handle = handle & HANDLE_MASK;
+
+ if (boundary_flag == START_PACKET_BOUNDARY) {
+ auto map_iter = partial_packets.find(handle);
+ if (map_iter != partial_packets.end()) {
+ LOG_WARN(LOG_TAG,
+ "%s found unfinished packet for handle with start packet. "
+ "Dropping old.",
+ __func__);
+
+ BT_HDR* hdl = map_iter->second;
+ partial_packets.erase(map_iter);
+ buffer_allocator->free(hdl);
+ }
+
+ if (acl_length < L2CAP_HEADER_SIZE) {
+ LOG_WARN(LOG_TAG, "%s L2CAP packet too small (%d < %d). Dropping it.",
+ __func__, packet->len, L2CAP_HEADER_SIZE);
+ buffer_allocator->free(packet);
+ return;
+ }
+
+ uint16_t full_length =
+ l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
+
+ // Check for buffer overflow and that the full packet size + BT_HDR size
+ // is less than the max buffer size
+ if (check_uint16_overflow(l2cap_length,
+ (L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE)) ||
+ ((full_length + sizeof(BT_HDR)) > BT_DEFAULT_BUFFER_SIZE)) {
+ LOG_ERROR(LOG_TAG, "%s Dropping L2CAP packet with invalid length (%d).",
+ __func__, l2cap_length);
+ buffer_allocator->free(packet);
+ return;
+ }
+
+ if (full_length <= packet->len) {
+ if (full_length < packet->len)
+ LOG_WARN(LOG_TAG,
+ "%s found l2cap full length %d less than the hci length %d.",
+ __func__, l2cap_length, packet->len);
+
+ callbacks->reassembled(packet);
+ return;
+ }
+
+ BT_HDR* partial_packet =
+ (BT_HDR*)buffer_allocator->alloc(full_length + sizeof(BT_HDR));
+ partial_packet->event = packet->event;
+ partial_packet->len = full_length;
+ partial_packet->offset = packet->len;
+
+ memcpy(partial_packet->data, packet->data, packet->len);
+
+ // Update the ACL data size to indicate the full expected length
+ stream = partial_packet->data;
+ STREAM_SKIP_UINT16(stream); // skip the handle
+ UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE);
+
+ partial_packets[handle] = partial_packet;
+
+ // Free the old packet buffer, since we don't need it anymore
+ buffer_allocator->free(packet);
+ } else {
+ auto map_iter = partial_packets.find(handle);
+ if (map_iter == partial_packets.end()) {
+ LOG_WARN(LOG_TAG,
+ "%s got continuation for unknown packet. Dropping it.",
+ __func__);
+ buffer_allocator->free(packet);
+ return;
+ }
+ BT_HDR* partial_packet = map_iter->second;
+
+ packet->offset = HCI_ACL_PREAMBLE_SIZE;
+ uint16_t projected_offset =
+ partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
+ if (projected_offset >
+ partial_packet->len) { // len stores the expected length
+ LOG_WARN(LOG_TAG,
+ "%s got packet which would exceed expected length of %d. "
+ "Truncating.",
+ __func__, partial_packet->len);
+ packet->len = partial_packet->len - partial_packet->offset;
+ projected_offset = partial_packet->len;
+ }
+
+ memcpy(partial_packet->data + partial_packet->offset,
+ packet->data + packet->offset, packet->len - packet->offset);
+
+ // Free the old packet buffer, since we don't need it anymore
+ buffer_allocator->free(packet);
+ partial_packet->offset = projected_offset;
+
+ if (partial_packet->offset == partial_packet->len) {
+ partial_packets.erase(handle);
+ partial_packet->offset = 0;
+ callbacks->reassembled(partial_packet);
+ }
+ }
+ } else {
+ callbacks->reassembled(packet);
+ }
+}
+
+static const packet_fragmenter_t interface = {init, cleanup,
+
+ fragment_and_dispatch,
+ reassemble_and_dispatch};
+
+const packet_fragmenter_t* packet_fragmenter_get_interface() {
+ controller = controller_get_interface();
+ buffer_allocator = buffer_allocator_get_interface();
+ return &interface;
+}
+
+const packet_fragmenter_t* packet_fragmenter_get_test_interface(
+ const controller_t* controller_interface,
+ const allocator_t* buffer_allocator_interface) {
+ controller = controller_interface;
+ buffer_allocator = buffer_allocator_interface;
+ return &interface;
+}
diff --git a/mtkbt/code/bt/hci/test/packet_fragmenter_test.cc b/mtkbt/code/bt/hci/test/packet_fragmenter_test.cc
new file mode 100755
index 0000000..29c130d
--- a/dev/null
+++ b/mtkbt/code/bt/hci/test/packet_fragmenter_test.cc
@@ -0,0 +1,396 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include <stdint.h>
+
+#include "device/include/controller.h"
+#include "hci_internals.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+#include "packet_fragmenter.h"
+#include "test_stubs.h"
+
+DECLARE_TEST_MODES(init, set_data_sizes, no_fragmentation, fragmentation,
+ ble_no_fragmentation, ble_fragmentation,
+ non_acl_passthrough_fragmentation, no_reassembly, reassembly,
+ non_acl_passthrough_reassembly);
+
+#define LOCAL_BLE_CONTROLLER_ID 1
+
+static const char* sample_data =
+ "At this point they came in sight of thirty forty windmills that there are "
+ "on plain, and "
+ "as soon as Don Quixote saw them he said to his squire, \"Fortune is "
+ "arranging matters "
+ "for us better than we could have shaped our desires ourselves, for look "
+ "there, friend "
+ "Sancho Panza, where thirty or more monstrous giants present themselves, "
+ "all of whom I "
+ "mean to engage in battle and slay, and with whose spoils we shall begin "
+ "to make our "
+ "fortunes; for this is righteous warfare, and it is God's good service to "
+ "sweep so evil "
+ "a breed from off the face of the earth.\"";
+
+static const char* small_sample_data = "\"What giants?\" said Sancho Panza.";
+static const uint16_t test_handle_start = (0x1992 & 0xCFFF) | 0x2000;
+static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000;
+static int packet_index;
+static unsigned int data_size_sum;
+
+static const packet_fragmenter_t* fragmenter;
+
+static BT_HDR* manufacture_packet_for_fragmentation(uint16_t event,
+ const char* data) {
+ uint16_t data_length = strlen(data);
+ uint16_t size = data_length;
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ size += 4; // 2 for the handle, 2 for the length;
+ }
+
+ BT_HDR* packet = (BT_HDR*)osi_malloc(size + sizeof(BT_HDR));
+ packet->len = size;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+ uint8_t* packet_data = packet->data;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ UINT16_TO_STREAM(packet_data, test_handle_start);
+ UINT16_TO_STREAM(packet_data, data_length);
+ }
+
+ memcpy(packet_data, data, data_length);
+ return packet;
+}
+
+static void expect_packet_fragmented(uint16_t event, int max_acl_data_size,
+ BT_HDR* packet, const char* expected_data,
+ bool send_complete) {
+ uint8_t* data = packet->data + packet->offset;
+ int expected_data_offset;
+ int length_to_check;
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL) {
+ uint16_t handle;
+ uint16_t length;
+ STREAM_TO_UINT16(handle, data);
+ STREAM_TO_UINT16(length, data);
+
+ if (packet_index == 0)
+ EXPECT_EQ(test_handle_start, handle);
+ else
+ EXPECT_EQ(test_handle_continuation, handle);
+
+ int length_remaining = strlen(expected_data) - data_size_sum;
+ int packet_data_length = packet->len - HCI_ACL_PREAMBLE_SIZE;
+ EXPECT_EQ(packet_data_length, length);
+
+ if (length_remaining > max_acl_data_size)
+ EXPECT_EQ(max_acl_data_size, packet_data_length);
+
+ length_to_check = packet_data_length;
+ expected_data_offset = packet_index * max_acl_data_size;
+ packet_index++;
+ } else {
+ length_to_check = strlen(expected_data);
+ expected_data_offset = 0;
+ }
+
+ for (int i = 0; i < length_to_check; i++) {
+ EXPECT_EQ(expected_data[expected_data_offset + i], data[i]);
+ data_size_sum++;
+ }
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL)
+ EXPECT_TRUE(send_complete == (data_size_sum == strlen(expected_data)));
+
+ if (send_complete) osi_free(packet);
+}
+
+static void manufacture_packet_and_then_reassemble(uint16_t event,
+ uint16_t acl_size,
+ const char* data) {
+ uint16_t data_length = strlen(data);
+
+ if (event == MSG_HC_TO_STACK_HCI_ACL) {
+ uint16_t total_length = data_length + 2; // 2 for l2cap length;
+ uint16_t length_sent = 0;
+ uint16_t l2cap_length = data_length - 2; // l2cap length field, 2 for the
+ // pretend channel id borrowed
+ // from the data
+
+ do {
+ int length_to_send = (length_sent + (acl_size - 4) < total_length)
+ ? (acl_size - 4)
+ : (total_length - length_sent);
+ BT_HDR* packet = (BT_HDR*)osi_malloc(length_to_send + 4 + sizeof(BT_HDR));
+ packet->len = length_to_send + 4;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+
+ uint8_t* packet_data = packet->data;
+ if (length_sent == 0) { // first packet
+ UINT16_TO_STREAM(packet_data, test_handle_start);
+ UINT16_TO_STREAM(packet_data, length_to_send);
+ UINT16_TO_STREAM(packet_data, l2cap_length);
+ memcpy(packet_data, data, length_to_send - 2);
+ } else {
+ UINT16_TO_STREAM(packet_data, test_handle_continuation);
+ UINT16_TO_STREAM(packet_data, length_to_send);
+ memcpy(packet_data, data + length_sent - 2, length_to_send);
+ }
+
+ length_sent += length_to_send;
+ fragmenter->reassemble_and_dispatch(packet);
+ } while (length_sent < total_length);
+ } else {
+ BT_HDR* packet = (BT_HDR*)osi_malloc(data_length + sizeof(BT_HDR));
+ packet->len = data_length;
+ packet->offset = 0;
+ packet->event = event;
+ packet->layer_specific = 0;
+ memcpy(packet->data, data, data_length);
+
+ fragmenter->reassemble_and_dispatch(packet);
+ }
+}
+
+static void expect_packet_reassembled(uint16_t event, BT_HDR* packet,
+ const char* expected_data) {
+ uint16_t expected_data_length = strlen(expected_data);
+ uint8_t* data = packet->data + packet->offset;
+
+ if (event == MSG_HC_TO_STACK_HCI_ACL) {
+ uint16_t handle;
+ uint16_t length;
+ uint16_t l2cap_length;
+ STREAM_TO_UINT16(handle, data);
+ STREAM_TO_UINT16(length, data);
+ STREAM_TO_UINT16(l2cap_length, data);
+
+ EXPECT_EQ(test_handle_start, handle);
+ EXPECT_EQ(expected_data_length + 2, length);
+ EXPECT_EQ(expected_data_length - 2,
+ l2cap_length); // -2 for the pretend channel id
+ }
+
+ for (int i = 0; i < expected_data_length; i++) {
+ EXPECT_EQ(expected_data[i], data[i]);
+ data_size_sum++;
+ }
+
+ osi_free(packet);
+}
+
+STUB_FUNCTION(void, fragmented_callback, (BT_HDR * packet, bool send_complete))
+DURING(no_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet,
+ small_sample_data, send_complete);
+ return;
+}
+
+DURING(fragmentation) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data,
+ send_complete);
+ return;
+}
+
+DURING(ble_no_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet,
+ small_sample_data, send_complete);
+ return;
+}
+
+DURING(ble_fragmentation) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data,
+ send_complete);
+ return;
+}
+
+DURING(non_acl_passthrough_fragmentation) AT_CALL(0) {
+ expect_packet_fragmented(MSG_STACK_TO_HC_HCI_CMD, 10, packet, sample_data,
+ send_complete);
+ return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, reassembled_callback, (BT_HDR * packet))
+DURING(no_reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, small_sample_data);
+ return;
+}
+
+DURING(reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, sample_data);
+ return;
+}
+
+DURING(non_acl_passthrough_reassembly) AT_CALL(0) {
+ expect_packet_reassembled(MSG_HC_TO_STACK_HCI_EVT, packet, sample_data);
+ return;
+}
+
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(void, transmit_finished_callback,
+ (UNUSED_ATTR BT_HDR * packet,
+ UNUSED_ATTR bool sent_all_fragments))
+UNEXPECTED_CALL;
+}
+
+STUB_FUNCTION(uint16_t, get_acl_data_size_classic, (void))
+DURING(no_fragmentation, non_acl_passthrough_fragmentation, no_reassembly)
+return 42;
+DURING(fragmentation) return 10;
+DURING(no_reassembly) return 1337;
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+STUB_FUNCTION(uint16_t, get_acl_data_size_ble, (void))
+DURING(ble_no_fragmentation) return 42;
+DURING(ble_fragmentation) return 10;
+
+UNEXPECTED_CALL;
+return 0;
+}
+
+static void reset_for(TEST_MODES_T next) {
+ RESET_CALL_COUNT(fragmented_callback);
+ RESET_CALL_COUNT(reassembled_callback);
+ RESET_CALL_COUNT(transmit_finished_callback);
+ RESET_CALL_COUNT(get_acl_data_size_classic);
+ RESET_CALL_COUNT(get_acl_data_size_ble);
+ CURRENT_TEST_MODE = next;
+}
+
+class PacketFragmenterTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() {
+ AllocationTestHarness::SetUp();
+ fragmenter =
+ packet_fragmenter_get_test_interface(&controller, &allocator_malloc);
+
+ packet_index = 0;
+ data_size_sum = 0;
+
+ callbacks.fragmented = fragmented_callback;
+ callbacks.reassembled = reassembled_callback;
+ callbacks.transmit_finished = transmit_finished_callback;
+ controller.get_acl_data_size_classic = get_acl_data_size_classic;
+ controller.get_acl_data_size_ble = get_acl_data_size_ble;
+
+ reset_for(init);
+ fragmenter->init(&callbacks);
+ }
+
+ virtual void TearDown() {
+ fragmenter->cleanup();
+ AllocationTestHarness::TearDown();
+ }
+
+ controller_t controller;
+ packet_fragmenter_callbacks_t callbacks;
+};
+
+TEST_F(PacketFragmenterTest, test_no_fragment_necessary) {
+ reset_for(no_fragmentation);
+ BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+ small_sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_fragment_necessary) {
+ reset_for(fragmentation);
+ BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+ sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_no_fragment_necessary) {
+ reset_for(ble_no_fragmentation);
+ BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+ small_sample_data);
+ packet->event |= LOCAL_BLE_CONTROLLER_ID;
+ fragmenter->fragment_and_dispatch(packet);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_ble_fragment_necessary) {
+ reset_for(ble_fragmentation);
+ BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL,
+ sample_data);
+ packet->event |= LOCAL_BLE_CONTROLLER_ID;
+ fragmenter->fragment_and_dispatch(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_fragmentation) {
+ reset_for(non_acl_passthrough_fragmentation);
+ BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_CMD,
+ sample_data);
+ fragmenter->fragment_and_dispatch(packet);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(fragmented_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_no_reassembly_necessary) {
+ reset_for(no_reassembly);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 1337,
+ small_sample_data);
+
+ EXPECT_EQ(strlen(small_sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_reassembly_necessary) {
+ reset_for(reassembly);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 42,
+ sample_data);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
+
+TEST_F(PacketFragmenterTest, test_non_acl_passthrough_reasseembly) {
+ reset_for(non_acl_passthrough_reassembly);
+ manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_EVT, 42,
+ sample_data);
+
+ EXPECT_EQ(strlen(sample_data), data_size_sum);
+ EXPECT_CALL_COUNT(reassembled_callback, 1);
+}
diff --git a/mtkbt/code/bt/include/bt_common.h b/mtkbt/code/bt/include/bt_common.h
new file mode 100755
index 0000000..9680792
--- a/dev/null
+++ b/mtkbt/code/bt/include/bt_common.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
diff --git a/mtkbt/code/bt/include/bt_target.h b/mtkbt/code/bt/include/bt_target.h
new file mode 100755
index 0000000..4c5acf2
--- a/dev/null
+++ b/mtkbt/code/bt/include/bt_target.h
@@ -0,0 +1,1517 @@
+/******************************************************************************
+ *
+ * Copyright (c) 2014 The Android Open Source Project
+ * Copyright (C) 1999-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BT_TARGET_H
+#define BT_TARGET_H
+
+#ifndef BUILDCFG
+#define BUILDCFG
+#endif
+
+#if !defined(HAS_BDROID_BUILDCFG) && !defined(HAS_NO_BDROID_BUILDCFG)
+#error \
+ "An Android.mk file did not include bdroid_CFLAGS and possibly not bdroid_C_INCLUDES"
+#endif
+
+#ifdef HAS_BDROID_BUILDCFG
+#include "bdroid_buildcfg.h"
+#endif
+
+#ifdef HAS_MDROID_BUILDCFG
+#include "mdroid_buildcfg.h"
+#endif
+
+#include "bt_types.h" /* This must be defined AFTER buildcfg.h */
+
+//------------------Added from bdroid_buildcfg.h---------------------
+#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
+#define L2CAP_EXTFEA_SUPPORTED_MASK \
+ (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE | L2CAP_EXTFEA_NO_CRC | \
+ L2CAP_EXTFEA_FIXED_CHNLS)
+#endif
+
+#ifndef BTUI_OPS_FORMATS
+#define BTUI_OPS_FORMATS (BTA_OP_VCARD21_MASK | BTA_OP_ANY_MASK)
+#endif
+
+#ifndef BTA_RFC_MTU_SIZE
+#define BTA_RFC_MTU_SIZE \
+ (L2CAP_MTU_SIZE - L2CAP_MIN_OFFSET - RFCOMM_DATA_OVERHEAD)
+#endif
+
+#ifndef BTA_INCLUDED
+#define BTA_INCLUDED TRUE
+#endif
+
+#ifndef BTA_PAN_INCLUDED
+#define BTA_PAN_INCLUDED TRUE
+#endif
+
+#ifndef BTA_HD_INCLUDED
+#define BTA_HD_INCLUDED TRUE
+#endif
+
+#ifndef BTA_HH_INCLUDED
+#define BTA_HH_INCLUDED TRUE
+#endif
+
+#ifndef BTA_HH_ROLE
+#define BTA_HH_ROLE BTA_MASTER_ROLE_PREF
+#endif
+
+#ifndef BTA_HH_LE_INCLUDED
+#define BTA_HH_LE_INCLUDED TRUE
+#endif
+
+#ifndef BTA_AR_INCLUDED
+#define BTA_AR_INCLUDED TRUE
+#endif
+
+#ifndef BTA_AV_SINK_INCLUDED
+#define BTA_AV_SINK_INCLUDED FALSE
+#endif
+
+#ifndef BTA_DISABLE_DELAY
+#define BTA_DISABLE_DELAY 200 /* in milliseconds */
+#endif
+
+#ifndef SBC_FOR_EMBEDDED_LINUX
+#define SBC_FOR_EMBEDDED_LINUX TRUE
+#endif
+
+#ifndef AVDT_VERSION
+#define AVDT_VERSION 0x0102
+#endif
+
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 512
+#endif
+
+#ifndef BTA_AVRCP_FF_RW_SUPPORT
+#define BTA_AVRCP_FF_RW_SUPPORT TRUE
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+#define BTA_AG_SCO_PKT_TYPES \
+ (BTM_SCO_LINK_ONLY_MASK | ESCO_PKT_TYPES_MASK_EV3 | \
+ ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ ESCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif
+
+#ifndef BTA_AV_RET_TOUT
+#define BTA_AV_RET_TOUT 15
+#endif
+
+/** M: Bug fix for IOT device a2dp signal response too slowly @{ */
+#ifndef BTA_AV_SIG_TOUT
+#define BTA_AV_SIG_TOUT 7
+#endif
+/** @} */
+
+/* TRUE to use SCMS-T content protection */
+#ifndef BTA_AV_CO_CP_SCMS_T
+#define BTA_AV_CO_CP_SCMS_T FALSE
+#endif
+
+/* This feature is used to enable interleaved scan */
+#ifndef BTA_HOST_INTERLEAVE_SEARCH
+#define BTA_HOST_INTERLEAVE_SEARCH FALSE
+#endif
+
+#ifndef BTA_DM_SDP_DB_SIZE
+#define BTA_DM_SDP_DB_SIZE 8000
+#endif
+
+#ifndef HL_INCLUDED
+#define HL_INCLUDED TRUE
+#endif
+
+#ifndef AG_VOICE_SETTINGS
+#define AG_VOICE_SETTINGS HCI_DEFAULT_VOICE_SETTINGS
+#endif
+
+#ifndef BTIF_DM_OOB_TEST
+#define BTIF_DM_OOB_TEST TRUE
+#endif
+
+// How long to wait before activating sniff mode after entering the
+// idle state for FTS, OPS connections
+#ifndef BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS
+#define BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS 7000
+#endif
+
+//------------------End added from bdroid_buildcfg.h---------------------
+
+/******************************************************************************
+ *
+ * Buffer sizes
+ *
+ *****************************************************************************/
+
+#ifndef BT_DEFAULT_BUFFER_SIZE
+#define BT_DEFAULT_BUFFER_SIZE (4096 + 16)
+#endif
+
+#ifndef BT_SMALL_BUFFER_SIZE
+#define BT_SMALL_BUFFER_SIZE 660
+#endif
+
+/* Receives HCI events from the lower-layer. */
+#ifndef HCI_CMD_BUF_SIZE
+#define HCI_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+/* Sends SDP data packets. */
+#ifndef SDP_DATA_BUF_SIZE
+#define SDP_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends RFCOMM command packets. */
+#ifndef RFCOMM_CMD_BUF_SIZE
+#define RFCOMM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+/* Sends RFCOMM data packets. */
+#ifndef RFCOMM_DATA_BUF_SIZE
+#define RFCOMM_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends L2CAP packets to the peer and HCI messages to the controller. */
+#ifndef L2CAP_CMD_BUF_SIZE
+#define L2CAP_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_USER_TX_BUF_SIZE
+#define L2CAP_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_USER_RX_BUF_SIZE
+#define L2CAP_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Sends L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_TX_BUF_SIZE
+#define L2CAP_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Receives L2CAP segmented packets in ERTM mode */
+#ifndef L2CAP_FCR_RX_BUF_SIZE
+#define L2CAP_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef L2CAP_FCR_ERTM_BUF_SIZE
+#define L2CAP_FCR_ERTM_BUF_SIZE (10240 + 24)
+#endif
+
+/* Number of ACL buffers to assign to LE */
+/*
+ * TODO: Do we need this?
+ * It was used when the HCI buffers were shared with BR/EDR.
+ */
+#ifndef L2C_DEF_NUM_BLE_BUF_SHARED
+#define L2C_DEF_NUM_BLE_BUF_SHARED 1
+#endif
+
+/* Used by BTM when it sends HCI commands to the controller. */
+#ifndef BTM_CMD_BUF_SIZE
+#define BTM_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef OBX_LRG_DATA_BUF_SIZE
+#define OBX_LRG_DATA_BUF_SIZE (8080 + 26)
+#endif
+
+/* Used to send data to L2CAP. */
+#ifndef GAP_DATA_BUF_SIZE
+#define GAP_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* BNEP data and protocol messages. */
+#ifndef BNEP_BUF_SIZE
+#define BNEP_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* AVDTP buffer size for protocol messages */
+#ifndef AVDT_CMD_BUF_SIZE
+#define AVDT_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef PAN_BUF_SIZE
+#define PAN_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Maximum number of buffers to allocate for PAN */
+#ifndef PAN_BUF_MAX
+#define PAN_BUF_MAX 100
+#endif
+
+/* AVCTP buffer size for protocol messages */
+#ifndef AVCT_CMD_BUF_SIZE
+#define AVCT_CMD_BUF_SIZE 288
+#endif
+
+/* AVRCP buffer size for protocol messages */
+#ifndef AVRC_CMD_BUF_SIZE
+#define AVRC_CMD_BUF_SIZE 288
+#endif
+
+/* AVRCP Metadata buffer size for protocol messages */
+#ifndef AVRC_META_CMD_BUF_SIZE
+#define AVRC_META_CMD_BUF_SIZE BT_SMALL_BUFFER_SIZE
+#endif
+
+#ifndef BTA_HL_LRG_DATA_BUF_SIZE
+#define BTA_HL_LRG_DATA_BUF_SIZE (10240 + 24)
+#endif
+
+/* GATT Server Database buffer size */
+#ifndef GATT_DB_BUF_SIZE
+#define GATT_DB_BUF_SIZE 128
+#endif
+
+/* GATT Data sending buffer size */
+#ifndef GATT_DATA_BUF_SIZE
+#define GATT_DATA_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/******************************************************************************
+ *
+ * BTM
+ *
+ *****************************************************************************/
+
+/* Cancel Inquiry on incoming SSP */
+#ifndef BTM_NO_SSP_ON_INQUIRY
+#define BTM_NO_SSP_ON_INQUIRY FALSE
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_INCLUDED
+#define BTM_SCO_INCLUDED TRUE /* TRUE includes SCO code */
+#endif
+
+/* Includes SCO if TRUE */
+#ifndef BTM_SCO_HCI_INCLUDED
+#define BTM_SCO_HCI_INCLUDED FALSE /* TRUE includes SCO over HCI code */
+#endif
+
+/* This is used to work around a controller bug that doesn't like Disconnect
+ * issued while there is a role switch in progress
+*/
+#ifndef BTM_DISC_DURING_RS
+#define BTM_DISC_DURING_RS TRUE
+#endif
+
+/**************************
+ * Initial SCO TX credit
+ ************************/
+/* max TX SCO data packet size */
+#ifndef BTM_SCO_DATA_SIZE_MAX
+#define BTM_SCO_DATA_SIZE_MAX 240
+#endif
+
+/* The size in bytes of the BTM inquiry database. */
+#ifndef BTM_INQ_DB_SIZE
+#define BTM_INQ_DB_SIZE 40
+#endif
+
+/* The default scan mode */
+#ifndef BTM_DEFAULT_SCAN_TYPE
+#define BTM_DEFAULT_SCAN_TYPE BTM_SCAN_TYPE_INTERLACED
+#endif
+
+/* Should connections to unknown devices be allowed when not discoverable? */
+#ifndef BTM_ALLOW_CONN_IF_NONDISCOVER
+#define BTM_ALLOW_CONN_IF_NONDISCOVER TRUE
+#endif
+
+/* Sets the Page_Scan_Window: the length of time that the device is performing
+ * a page scan. */
+#ifndef BTM_DEFAULT_CONN_WINDOW
+#define BTM_DEFAULT_CONN_WINDOW 0x0012
+#endif
+
+/* Sets the Page_Scan_Activity: the interval between the start of two
+ * consecutive page scans. */
+#ifndef BTM_DEFAULT_CONN_INTERVAL
+#define BTM_DEFAULT_CONN_INTERVAL 0x0800
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan window. */
+#ifndef BTM_DEFAULT_DISC_WINDOW
+#define BTM_DEFAULT_DISC_WINDOW 0x0012
+#endif
+
+/* When automatic inquiry scan is enabled, this sets the inquiry scan interval.
+ */
+#ifndef BTM_DEFAULT_DISC_INTERVAL
+#define BTM_DEFAULT_DISC_INTERVAL 0x0800
+#endif
+
+/* Default class of device
+* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS}
+*
+* SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object
+* Transfer,Bit22 -Telephony)
+* MAJOR_CLASS:0x02 - PHONE
+* MINOR_CLASS:0x0C - SMART_PHONE
+*
+*/
+#ifndef BTA_DM_COD
+#define BTA_DM_COD \
+ { 0x5A, 0x02, 0x0C }
+#endif
+
+/* The number of SCO links. */
+#ifndef BTM_MAX_SCO_LINKS
+#define BTM_MAX_SCO_LINKS 3
+#endif
+
+/* The preferred type of SCO links (2-eSCO, 0-SCO). */
+#ifndef BTM_DEFAULT_SCO_MODE
+#define BTM_DEFAULT_SCO_MODE 2
+#endif
+
+/* The number of security records for peer devices. */
+#ifndef BTM_SEC_MAX_DEVICE_RECORDS
+#define BTM_SEC_MAX_DEVICE_RECORDS 100
+#endif
+
+/* The number of security records for services. */
+#ifndef BTM_SEC_MAX_SERVICE_RECORDS
+#define BTM_SEC_MAX_SERVICE_RECORDS 32
+#endif
+
+/* If True, force a retrieval of remote device name for each bond in case it's
+ * changed */
+#ifndef BTM_SEC_FORCE_RNR_FOR_DBOND
+#define BTM_SEC_FORCE_RNR_FOR_DBOND FALSE
+#endif
+
+/* Maximum device name length used in btm database. */
+#ifndef BTM_MAX_REM_BD_NAME_LEN
+#define BTM_MAX_REM_BD_NAME_LEN 248
+#endif
+
+/* Maximum local device name length stored btm database */
+#ifndef BTM_MAX_LOC_BD_NAME_LEN
+#define BTM_MAX_LOC_BD_NAME_LEN 248
+#endif
+
+/* Fixed Default String. When this is defined as null string, the device's
+ * product model name is used as the default local name.
+ */
+#ifndef BTM_DEF_LOCAL_NAME
+#define BTM_DEF_LOCAL_NAME ""
+#endif
+
+/* Maximum service name stored with security authorization (0 if not needed) */
+#ifndef BTM_SEC_SERVICE_NAME_LEN
+#define BTM_SEC_SERVICE_NAME_LEN BT_MAX_SERVICE_NAME_LEN
+#endif
+
+/* Maximum length of the service name. */
+#ifndef BT_MAX_SERVICE_NAME_LEN
+#define BT_MAX_SERVICE_NAME_LEN 21
+#endif
+
+/* The maximum number of clients that can register with the power manager. */
+#ifndef BTM_MAX_PM_RECORDS
+#define BTM_MAX_PM_RECORDS 2
+#endif
+
+/* This is set to show debug trace messages for the power manager. */
+#ifndef BTM_PM_DEBUG
+#define BTM_PM_DEBUG FALSE
+#endif
+
+/* This is set to TRUE if link is to be unparked due to BTM_CreateSCO API. */
+#ifndef BTM_SCO_WAKE_PARKED_LINK
+#define BTM_SCO_WAKE_PARKED_LINK TRUE
+#endif
+
+/* If the user does not respond to security process requests within this many
+ * seconds,
+ * a negative response would be sent automatically.
+ * 30 is LMP response timeout value */
+#ifndef BTM_SEC_TIMEOUT_VALUE
+#define BTM_SEC_TIMEOUT_VALUE 35
+#endif
+
+/* Maximum number of callbacks that can be registered using
+ * BTM_RegisterForVSEvents */
+#ifndef BTM_MAX_VSE_CALLBACKS
+#define BTM_MAX_VSE_CALLBACKS 3
+#endif
+
+/******************************************
+ * Lisbon Features
+ ******************************************/
+/* This is set to TRUE if the FEC is required for EIR packet. */
+#ifndef BTM_EIR_DEFAULT_FEC_REQUIRED
+#define BTM_EIR_DEFAULT_FEC_REQUIRED TRUE
+#endif
+
+/* The IO capability of the local device (for Simple Pairing) */
+#ifndef BTM_LOCAL_IO_CAPS
+#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO
+#endif
+
+#ifndef BTM_LOCAL_IO_CAPS_BLE
+#define BTM_LOCAL_IO_CAPS_BLE BTM_IO_CAP_KBDISP
+#endif
+
+/* The default MITM Protection Requirement (for Simple Pairing)
+ * Possible values are BTM_AUTH_SP_YES or BTM_AUTH_SP_NO */
+#ifndef BTM_DEFAULT_AUTH_REQ
+#define BTM_DEFAULT_AUTH_REQ BTM_AUTH_SP_NO
+#endif
+
+/* The default MITM Protection Requirement for dedicated bonding using Simple
+ * Pairing
+ * Possible values are BTM_AUTH_AP_YES or BTM_AUTH_AP_NO */
+#ifndef BTM_DEFAULT_DD_AUTH_REQ
+#define BTM_DEFAULT_DD_AUTH_REQ BTM_AUTH_AP_YES
+#endif
+
+/* TRUE to include Sniff Subrating */
+#ifndef BTM_SSR_INCLUDED
+#define BTM_SSR_INCLUDED TRUE
+#endif
+
+/*************************
+ * End of Lisbon Features
+ *************************/
+
+/* 4.1/4.2 secure connections feature */
+#ifndef SC_MODE_INCLUDED
+#define SC_MODE_INCLUDED TRUE
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef BTM_BLE_CONFORMANCE_TESTING
+#define BTM_BLE_CONFORMANCE_TESTING FALSE
+#endif
+
+/******************************************************************************
+ *
+ * L2CAP
+ *
+ *****************************************************************************/
+
+/* The maximum number of simultaneous links that L2CAP can support. */
+#ifndef MAX_ACL_CONNECTIONS
+#define MAX_L2CAP_LINKS 7
+#else
+#define MAX_L2CAP_LINKS MAX_ACL_CONNECTIONS
+#endif
+
+/* The maximum number of simultaneous channels that L2CAP can support. */
+#ifndef MAX_L2CAP_CHANNELS
+#define MAX_L2CAP_CHANNELS 16
+#endif
+
+/* The maximum number of simultaneous applications that can register with L2CAP.
+ */
+#ifndef MAX_L2CAP_CLIENTS
+#define MAX_L2CAP_CLIENTS 15
+#endif
+
+/* The number of seconds of link inactivity before a link is disconnected. */
+#ifndef L2CAP_LINK_INACTIVITY_TOUT
+#define L2CAP_LINK_INACTIVITY_TOUT 4
+#endif
+
+/* The number of seconds of link inactivity after bonding before a link is
+ * disconnected. */
+#ifndef L2CAP_BONDING_TIMEOUT
+#define L2CAP_BONDING_TIMEOUT 3
+#endif
+
+/* The time from the HCI connection complete to disconnect if no channel is
+ * established. */
+#ifndef L2CAP_LINK_STARTUP_TOUT
+#define L2CAP_LINK_STARTUP_TOUT 60
+#endif
+
+/* The L2CAP MTU; must be in accord with the HCI ACL buffer size. */
+#ifndef L2CAP_MTU_SIZE
+#define L2CAP_MTU_SIZE 1691
+#endif
+
+/*
+ * The L2CAP MPS over Bluetooth; must be in accord with the FCR tx buffer size
+ * and ACL down buffer size.
+ */
+#ifndef L2CAP_MPS_OVER_BR_EDR
+#define L2CAP_MPS_OVER_BR_EDR 1010
+#endif
+
+/* If host flow control enabled, this is the number of buffers the controller
+ * can have unacknowledged. */
+#ifndef L2CAP_HOST_FC_ACL_BUFS
+#define L2CAP_HOST_FC_ACL_BUFS 20
+#endif
+
+/* This is set to enable L2CAP to take the ACL link out of park mode when ACL
+ * data is to be sent. */
+#ifndef L2CAP_WAKE_PARKED_LINK
+#define L2CAP_WAKE_PARKED_LINK TRUE
+#endif
+
+/* Whether link wants to be the master or the slave. */
+#ifndef L2CAP_DESIRED_LINK_ROLE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#endif
+
+/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
+#ifndef L2CAP_NON_FLUSHABLE_PB_INCLUDED
+#define L2CAP_NON_FLUSHABLE_PB_INCLUDED TRUE
+#endif
+
+/* Minimum number of ACL credit for high priority link */
+#ifndef L2CAP_HIGH_PRI_MIN_XMIT_QUOTA
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA 5
+#endif
+
+/* used for monitoring HCI ACL credit management */
+#ifndef L2CAP_HCI_FLOW_CONTROL_DEBUG
+#define L2CAP_HCI_FLOW_CONTROL_DEBUG TRUE
+#endif
+
+/* Unicast Connectionless Data */
+#ifndef L2CAP_UCD_INCLUDED
+#define L2CAP_UCD_INCLUDED FALSE
+#endif
+
+/* Unicast Connectionless Data MTU */
+#ifndef L2CAP_UCD_MTU
+#define L2CAP_UCD_MTU L2CAP_MTU_SIZE
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_IDLE_TIMEOUT
+#define L2CAP_UCD_IDLE_TIMEOUT 2
+#endif
+
+/* Unicast Connectionless Data Idle Timeout */
+#ifndef L2CAP_UCD_CH_PRIORITY
+#define L2CAP_UCD_CH_PRIORITY L2CAP_CHNL_PRIORITY_MEDIUM
+#endif
+
+/* Used for features using fixed channels; set to zero if no fixed channels
+ * supported (BLE, etc.) */
+/* Excluding L2CAP signaling channel and UCD */
+#ifndef L2CAP_NUM_FIXED_CHNLS
+#define L2CAP_NUM_FIXED_CHNLS 32
+#endif
+
+/* First fixed channel supported */
+#ifndef L2CAP_FIRST_FIXED_CHNL
+#define L2CAP_FIRST_FIXED_CHNL 4
+#endif
+
+#ifndef L2CAP_LAST_FIXED_CHNL
+#define L2CAP_LAST_FIXED_CHNL \
+ (L2CAP_FIRST_FIXED_CHNL + L2CAP_NUM_FIXED_CHNLS - 1)
+#endif
+
+/* Round Robin service channels in link */
+#ifndef L2CAP_ROUND_ROBIN_CHANNEL_SERVICE
+#define L2CAP_ROUND_ROBIN_CHANNEL_SERVICE TRUE
+#endif
+
+/* used for monitoring eL2CAP data flow */
+#ifndef L2CAP_ERTM_STATS
+#define L2CAP_ERTM_STATS FALSE
+#endif
+
+/* Used for conformance testing ONLY: When TRUE lets scriptwrapper overwrite
+ * info response */
+#ifndef L2CAP_CONFORMANCE_TESTING
+#define L2CAP_CONFORMANCE_TESTING FALSE
+#endif
+
+/*
+ * Max bytes per connection to buffer locally before dropping the
+ * connection if local client does not receive it - default is 1MB
+ */
+#ifndef L2CAP_MAX_RX_BUFFER
+#define L2CAP_MAX_RX_BUFFER 0x100000
+#endif
+
+/******************************************************************************
+ *
+ * BLE
+ *
+ *****************************************************************************/
+
+#ifndef LOCAL_BLE_CONTROLLER_ID
+#define LOCAL_BLE_CONTROLLER_ID (1)
+#endif
+
+/*
+ * Toggles support for general LE privacy features such as remote address
+ * resolution, local address rotation etc.
+ */
+#ifndef BLE_PRIVACY_SPT
+#define BLE_PRIVACY_SPT TRUE
+#endif
+
+/*
+ * Enables or disables support for local privacy (ex. address rotation)
+ */
+#ifndef BLE_LOCAL_PRIVACY_ENABLED
+#define BLE_LOCAL_PRIVACY_ENABLED TRUE
+#endif
+
+/*
+ * Toggles support for vendor specific extensions such as RPA offloading,
+ * feature discovery, multi-adv etc.
+ */
+#ifndef BLE_VND_INCLUDED
+#define BLE_VND_INCLUDED FALSE
+#endif
+
+#ifndef BTM_BLE_ADV_TX_POWER
+#define BTM_BLE_ADV_TX_POWER \
+ { -21, -15, -7, 1, 9 }
+#endif
+
+/* The maximum number of simultaneous applications that can register with LE
+ * L2CAP. */
+#ifndef BLE_MAX_L2CAP_CLIENTS
+#define BLE_MAX_L2CAP_CLIENTS 15
+#endif
+
+/******************************************************************************
+ *
+ * ATT/GATT Protocol/Profile Settings
+ *
+ *****************************************************************************/
+#ifndef BLE_LLT_INCLUDED
+#define BLE_LLT_INCLUDED TRUE
+#endif
+
+#ifndef ATT_INCLUDED
+#define ATT_INCLUDED TRUE
+#endif
+
+#ifndef ATT_DEBUG
+#define ATT_DEBUG TRUE
+#endif
+
+#ifndef BLE_DELAY_REQUEST_ENC
+/* This flag is to work around IPHONE problem, We need to wait for iPhone ready
+ before send encryption request to iPhone */
+#define BLE_DELAY_REQUEST_ENC FALSE
+#endif
+
+#ifndef GAP_TRANSPORT_SUPPORTED
+#define GAP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
+#endif
+
+#ifndef GATTP_TRANSPORT_SUPPORTED
+#define GATTP_TRANSPORT_SUPPORTED GATT_TRANSPORT_LE_BR_EDR
+#endif
+
+#ifndef GATT_MAX_SR_PROFILES
+#define GATT_MAX_SR_PROFILES 32 /* max is 32 */
+#endif
+
+#ifndef GATT_MAX_APPS
+#define GATT_MAX_APPS 32 /* note: 2 apps used internally GATT and GAP */
+#endif
+
+#ifndef GATT_MAX_PHY_CHANNEL
+#define GATT_MAX_PHY_CHANNEL 7
+#endif
+
+/* Used for conformance testing ONLY */
+#ifndef GATT_CONFORMANCE_TESTING
+#define GATT_CONFORMANCE_TESTING FALSE
+#endif
+
+/* number of background connection device allowence, ideally to be the same as
+ * WL size
+*/
+#ifndef GATT_MAX_BG_CONN_DEV
+#define GATT_MAX_BG_CONN_DEV 32
+#endif
+
+/******************************************************************************
+ *
+ * SMP
+ *
+ *****************************************************************************/
+#ifndef SMP_DEBUG
+#define SMP_DEBUG FALSE
+#endif
+
+#ifndef SMP_DEFAULT_AUTH_REQ
+#define SMP_DEFAULT_AUTH_REQ SMP_AUTH_NB_ENC_ONLY
+#endif
+
+#ifndef SMP_MAX_ENC_KEY_SIZE
+#define SMP_MAX_ENC_KEY_SIZE 16
+#endif
+
+/* minimum link timeout after SMP pairing is done, leave room for key exchange
+ and racing condition for the following service connection.
+ Prefer greater than 0 second, and no less than default inactivity link idle
+ timer(L2CAP_LINK_INACTIVITY_TOUT) in l2cap) */
+#ifndef SMP_LINK_TOUT_MIN
+#if (L2CAP_LINK_INACTIVITY_TOUT > 0)
+#define SMP_LINK_TOUT_MIN L2CAP_LINK_INACTIVITY_TOUT
+#else
+#define SMP_LINK_TOUT_MIN 2
+#endif
+#endif
+/******************************************************************************
+ *
+ * SDP
+ *
+ *****************************************************************************/
+
+/* This is set to enable SDP server functionality. */
+#ifndef SDP_SERVER_ENABLED
+#define SDP_SERVER_ENABLED TRUE
+#endif
+
+/* The maximum number of SDP records the server can support. */
+#ifndef SDP_MAX_RECORDS
+#define SDP_MAX_RECORDS 30
+#endif
+
+/* The maximum number of attributes in each record. */
+#ifndef SDP_MAX_REC_ATTR
+#define SDP_MAX_REC_ATTR 25
+#endif
+
+#ifndef SDP_MAX_PAD_LEN
+#define SDP_MAX_PAD_LEN 600
+#endif
+
+/* The maximum length, in bytes, of an attribute. */
+#ifndef SDP_MAX_ATTR_LEN
+#define SDP_MAX_ATTR_LEN 400
+#endif
+
+/* The maximum number of attribute filters supported by SDP databases. */
+#ifndef SDP_MAX_ATTR_FILTERS
+#define SDP_MAX_ATTR_FILTERS 15
+#endif
+
+/* The maximum number of UUID filters supported by SDP databases. */
+#ifndef SDP_MAX_UUID_FILTERS
+#define SDP_MAX_UUID_FILTERS 3
+#endif
+
+/* The maximum number of record handles retrieved in a search. */
+#ifndef SDP_MAX_DISC_SERVER_RECS
+#define SDP_MAX_DISC_SERVER_RECS 21
+#endif
+
+/* The size of a scratchpad buffer, in bytes, for storing the response to an
+ * attribute request. */
+#ifndef SDP_MAX_LIST_BYTE_COUNT
+#define SDP_MAX_LIST_BYTE_COUNT 4096
+#endif
+
+/* The maximum number of parameters in an SDP protocol element. */
+#ifndef SDP_MAX_PROTOCOL_PARAMS
+#define SDP_MAX_PROTOCOL_PARAMS 2
+#endif
+
+/* The maximum number of simultaneous client and server connections. */
+#ifndef SDP_MAX_CONNECTIONS
+#define SDP_MAX_CONNECTIONS 4
+#endif
+
+/* The MTU size for the L2CAP configuration. */
+#ifndef SDP_MTU_SIZE
+#define SDP_MTU_SIZE 672
+#endif
+
+/* The flush timeout for the L2CAP configuration. */
+#ifndef SDP_FLUSH_TO
+#define SDP_FLUSH_TO 0xFFFF
+#endif
+
+/* The name for security authorization. */
+#ifndef SDP_SERVICE_NAME
+#define SDP_SERVICE_NAME "Service Discovery"
+#endif
+
+/* The security level for BTM. */
+#ifndef SDP_SECURITY_LEVEL
+#define SDP_SECURITY_LEVEL BTM_SEC_NONE
+#endif
+
+/******************************************************************************
+ *
+ * RFCOMM
+ *
+ *****************************************************************************/
+
+/* The maximum number of ports supported. */
+#ifndef MAX_RFC_PORTS
+#define MAX_RFC_PORTS 30
+#endif
+
+/* The maximum simultaneous links to different devices. */
+#ifndef MAX_ACL_CONNECTIONS
+#define MAX_BD_CONNECTIONS 7
+#else
+#define MAX_BD_CONNECTIONS MAX_ACL_CONNECTIONS
+#endif
+
+/* The port receive queue low watermark level, in bytes. */
+#ifndef PORT_RX_LOW_WM
+#define PORT_RX_LOW_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_LOW_WM)
+#endif
+
+/* The port receive queue high watermark level, in bytes. */
+#ifndef PORT_RX_HIGH_WM
+#define PORT_RX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_HIGH_WM)
+#endif
+
+/* The port receive queue critical watermark level, in bytes. */
+#ifndef PORT_RX_CRITICAL_WM
+#define PORT_RX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_RX_BUF_CRITICAL_WM)
+#endif
+
+/* The port receive queue low watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_LOW_WM
+#define PORT_RX_BUF_LOW_WM 4
+#endif
+
+/* The port receive queue high watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_HIGH_WM
+#define PORT_RX_BUF_HIGH_WM 10
+#endif
+
+/* The port receive queue critical watermark level, in number of buffers. */
+#ifndef PORT_RX_BUF_CRITICAL_WM
+#define PORT_RX_BUF_CRITICAL_WM 15
+#endif
+
+/* The port transmit queue high watermark level, in bytes. */
+#ifndef PORT_TX_HIGH_WM
+#define PORT_TX_HIGH_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_HIGH_WM)
+#endif
+
+/* The port transmit queue critical watermark level, in bytes. */
+#ifndef PORT_TX_CRITICAL_WM
+#define PORT_TX_CRITICAL_WM (BTA_RFC_MTU_SIZE * PORT_TX_BUF_CRITICAL_WM)
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_HIGH_WM
+#define PORT_TX_BUF_HIGH_WM 10
+#endif
+
+/* The port transmit queue high watermark level, in number of buffers. */
+#ifndef PORT_TX_BUF_CRITICAL_WM
+#define PORT_TX_BUF_CRITICAL_WM 15
+#endif
+
+/* The RFCOMM multiplexer preferred flow control mechanism. */
+#ifndef PORT_FC_DEFAULT
+#define PORT_FC_DEFAULT PORT_FC_CREDIT
+#endif
+
+/* The maximum number of credits receiver sends to peer when using credit-based
+ * flow control. */
+#ifndef PORT_CREDIT_RX_MAX
+#define PORT_CREDIT_RX_MAX 16
+#endif
+
+/* The credit low watermark level. */
+#ifndef PORT_CREDIT_RX_LOW
+#define PORT_CREDIT_RX_LOW 8
+#endif
+
+/******************************************************************************
+ *
+ * OBEX
+ *
+ *****************************************************************************/
+
+/*
+ * Buffer size to reassemble the SDU.
+ * It will allow buffers to be used that are larger than the L2CAP_MAX_MTU.
+ */
+#ifndef OBX_USER_RX_BUF_SIZE
+#define OBX_USER_RX_BUF_SIZE OBX_LRG_DATA_BUF_SIZE
+#endif
+
+/*
+ * Buffer size to hold the SDU.
+ * It will allow buffers to be used that are larger than the L2CAP_MAX_MTU.
+ */
+#ifndef OBX_USER_TX_BUF_SIZE
+#define OBX_USER_TX_BUF_SIZE OBX_LRG_DATA_BUF_SIZE
+#endif
+
+/* Buffer size used to hold MPS segments during SDU reassembly. */
+#ifndef OBX_FCR_RX_BUF_SIZE
+#define OBX_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in L2CA_SetFCROptions plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+ */
+#ifndef OBX_FCR_TX_BUF_SIZE
+#define OBX_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Size of the transmission window when using enhanced retransmission mode.
+ * Not used in basic and streaming modes. Range: 1 - 63
+ */
+#ifndef OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR
+#define OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR 20
+#endif
+
+/*
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ * 0 - infinite retransmissions
+ * 1 - single transmission
+ */
+#ifndef OBX_FCR_OPT_MAX_TX_B4_DISCNT
+#define OBX_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/*
+ * Retransmission Timeout
+ * Range: Minimum 2000 (2 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_RETX_TOUT
+#define OBX_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/*
+ * Monitor Timeout
+ * Range: Minimum 12000 (12 secs) on BR/EDR when supporting PBF.
+ */
+#ifndef OBX_FCR_OPT_MONITOR_TOUT
+#define OBX_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/*
+ * Maximum PDU payload size.
+ * Suggestion: The maximum amount of data that will fit into a 3-DH5 packet.
+ * Range: 2 octets
+ */
+#ifndef OBX_FCR_OPT_MAX_PDU_SIZE
+#define OBX_FCR_OPT_MAX_PDU_SIZE L2CAP_MPS_OVER_BR_EDR
+#endif
+
+/******************************************************************************
+ *
+ * BNEP
+ *
+ *****************************************************************************/
+
+#ifndef BNEP_INCLUDED
+#define BNEP_INCLUDED TRUE
+#endif
+
+/* BNEP status API call is used mainly to get the L2CAP handle */
+#ifndef BNEP_SUPPORTS_STATUS_API
+#define BNEP_SUPPORTS_STATUS_API TRUE
+#endif
+
+/*
+ * When BNEP connection changes roles after the connection is established
+ * we will do an authentication check again on the new role
+*/
+#ifndef BNEP_DO_AUTH_FOR_ROLE_SWITCH
+#define BNEP_DO_AUTH_FOR_ROLE_SWITCH TRUE
+#endif
+
+/* Maximum number of protocol filters supported. */
+#ifndef BNEP_MAX_PROT_FILTERS
+#define BNEP_MAX_PROT_FILTERS 5
+#endif
+
+/* Maximum number of multicast filters supported. */
+#ifndef BNEP_MAX_MULTI_FILTERS
+#define BNEP_MAX_MULTI_FILTERS 5
+#endif
+
+/* Minimum MTU size. */
+#ifndef BNEP_MIN_MTU_SIZE
+#define BNEP_MIN_MTU_SIZE L2CAP_MTU_SIZE
+#endif
+
+/* Preferred MTU size. */
+#ifndef BNEP_MTU_SIZE
+#define BNEP_MTU_SIZE BNEP_MIN_MTU_SIZE
+#endif
+
+/* Maximum number of buffers allowed in transmit data queue. */
+#ifndef BNEP_MAX_XMITQ_DEPTH
+#define BNEP_MAX_XMITQ_DEPTH 20
+#endif
+
+/* Maximum number BNEP of connections supported. */
+#ifndef BNEP_MAX_CONNECTIONS
+#define BNEP_MAX_CONNECTIONS 7
+#endif
+
+/******************************************************************************
+ *
+ * AVDTP
+ *
+ *****************************************************************************/
+
+#ifndef AVDT_INCLUDED
+#define AVDT_INCLUDED TRUE
+#endif
+
+/* Include reporting capability in AVDTP */
+#ifndef AVDT_REPORTING
+#define AVDT_REPORTING TRUE
+#endif
+
+/* Number of simultaneous links to different peer devices. */
+#ifndef AVDT_NUM_LINKS
+#define AVDT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous stream endpoints. */
+#ifndef AVDT_NUM_SEPS
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#define AVDT_NUM_SEPS (6 + MTK_A2DP_SINK_AAC_SEP)
+#else
+#define AVDT_NUM_SEPS 6
+#endif
+#endif
+
+/* Number of transport channels setup by AVDT for all media streams */
+#ifndef AVDT_NUM_TC_TBL
+#define AVDT_NUM_TC_TBL 6
+#endif
+
+/* Maximum size in bytes of the content protection information element. */
+#ifndef AVDT_PROTECT_SIZE
+#define AVDT_PROTECT_SIZE 90
+#endif
+
+/******************************************************************************
+ *
+ * PAN
+ *
+ *****************************************************************************/
+
+#ifndef PAN_INCLUDED
+#define PAN_INCLUDED TRUE
+#endif
+
+#ifndef PAN_NAP_DISABLED
+#define PAN_NAP_DISABLED FALSE
+#endif
+
+#ifndef PANU_DISABLED
+#define PANU_DISABLED FALSE
+#endif
+
+/* This will enable the PANU role */
+#ifndef PAN_SUPPORTS_ROLE_PANU
+#define PAN_SUPPORTS_ROLE_PANU TRUE
+#endif
+
+/* This will enable the GN role */
+#ifndef PAN_SUPPORTS_ROLE_GN
+#define PAN_SUPPORTS_ROLE_GN TRUE
+#endif
+
+/* This will enable the NAP role */
+#ifndef PAN_SUPPORTS_ROLE_NAP
+#define PAN_SUPPORTS_ROLE_NAP TRUE
+#endif
+
+/* This is just for debugging purposes */
+#ifndef PAN_SUPPORTS_DEBUG_DUMP
+#define PAN_SUPPORTS_DEBUG_DUMP TRUE
+#endif
+
+/* Maximum number of PAN connections allowed */
+#ifndef MAX_PAN_CONNS
+#define MAX_PAN_CONNS 7
+#endif
+
+/* Default service name for NAP role */
+#ifndef PAN_NAP_DEFAULT_SERVICE_NAME
+#define PAN_NAP_DEFAULT_SERVICE_NAME "Network Access Point Service"
+#endif
+
+/* Default service name for GN role */
+#ifndef PAN_GN_DEFAULT_SERVICE_NAME
+#define PAN_GN_DEFAULT_SERVICE_NAME "Group Network Service"
+#endif
+
+/* Default service name for PANU role */
+#ifndef PAN_PANU_DEFAULT_SERVICE_NAME
+#define PAN_PANU_DEFAULT_SERVICE_NAME "PAN User Service"
+#endif
+
+/* Default description for NAP role service */
+#ifndef PAN_NAP_DEFAULT_DESCRIPTION
+#define PAN_NAP_DEFAULT_DESCRIPTION "NAP"
+#endif
+
+/* Default description for GN role service */
+#ifndef PAN_GN_DEFAULT_DESCRIPTION
+#define PAN_GN_DEFAULT_DESCRIPTION "GN"
+#endif
+
+/* Default description for PANU role service */
+#ifndef PAN_PANU_DEFAULT_DESCRIPTION
+#define PAN_PANU_DEFAULT_DESCRIPTION "PANU"
+#endif
+
+/* Default Security level for PANU role. */
+#ifndef PAN_PANU_SECURITY_LEVEL
+#define PAN_PANU_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for GN role. */
+#ifndef PAN_GN_SECURITY_LEVEL
+#define PAN_GN_SECURITY_LEVEL 0
+#endif
+
+/* Default Security level for NAP role. */
+#ifndef PAN_NAP_SECURITY_LEVEL
+#define PAN_NAP_SECURITY_LEVEL 0
+#endif
+
+/******************************************************************************
+ *
+ * GAP
+ *
+ *****************************************************************************/
+
+#ifndef GAP_INCLUDED
+#define GAP_INCLUDED TRUE
+#endif
+
+/* This is set to enable use of GAP L2CAP connections. */
+#ifndef GAP_CONN_INCLUDED
+#define GAP_CONN_INCLUDED TRUE
+#endif
+
+/* The maximum number of simultaneous GAP L2CAP connections. */
+#ifndef GAP_MAX_CONNECTIONS
+#define GAP_MAX_CONNECTIONS 30
+#endif
+
+/* keep the raw data received from SDP server in database. */
+#ifndef SDP_RAW_DATA_INCLUDED
+#define SDP_RAW_DATA_INCLUDED TRUE
+#endif
+
+/* Inquiry duration in 1.28 second units. */
+#ifndef SDP_DEBUG
+#define SDP_DEBUG TRUE
+#endif
+
+/******************************************************************************
+ *
+ * HID
+ *
+ *****************************************************************************/
+
+/* HID Device Role Included */
+#ifndef HID_DEV_INCLUDED
+#define HID_DEV_INCLUDED TRUE
+#endif
+
+#ifndef HID_DEV_SUBCLASS
+#define HID_DEV_SUBCLASS COD_MINOR_POINTING
+#endif
+
+#ifndef HID_CONTROL_BUF_SIZE
+#define HID_CONTROL_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef HID_INTERRUPT_BUF_SIZE
+#define HID_INTERRUPT_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+#ifndef HID_DEV_MTU_SIZE
+#define HID_DEV_MTU_SIZE 64
+#endif
+
+#ifndef HID_DEV_FLUSH_TO
+#define HID_DEV_FLUSH_TO 0xffff
+#endif
+
+/*************************************************************************
+ * Definitions for Both HID-Host & Device
+*/
+#ifndef HID_MAX_SVC_NAME_LEN
+#define HID_MAX_SVC_NAME_LEN 32
+#endif
+
+#ifndef HID_MAX_SVC_DESCR_LEN
+#define HID_MAX_SVC_DESCR_LEN 32
+#endif
+
+#ifndef HID_MAX_PROV_NAME_LEN
+#define HID_MAX_PROV_NAME_LEN 32
+#endif
+
+/*************************************************************************
+ * Definitions for HID-Host
+*/
+#ifndef HID_HOST_INCLUDED
+#define HID_HOST_INCLUDED TRUE
+#endif
+
+#ifndef HID_HOST_MAX_DEVICES
+#define HID_HOST_MAX_DEVICES 7
+#endif
+
+#ifndef HID_HOST_MTU
+#define HID_HOST_MTU 640
+#endif
+
+#ifndef HID_HOST_FLUSH_TO
+#define HID_HOST_FLUSH_TO 0xffff
+#endif
+
+#ifndef HID_HOST_MAX_CONN_RETRY
+#define HID_HOST_MAX_CONN_RETRY (1)
+#endif
+
+#ifndef HID_HOST_REPAGE_WIN
+#define HID_HOST_REPAGE_WIN (2)
+#endif
+
+/*************************************************************************
+ * A2DP Definitions
+ */
+#ifndef A2D_INCLUDED
+#define A2D_INCLUDED TRUE
+#endif
+
+/******************************************************************************
+ *
+ * AVCTP
+ *
+ *****************************************************************************/
+
+/* Number of simultaneous ACL links to different peer devices. */
+#ifndef AVCT_NUM_LINKS
+#define AVCT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous AVCTP connections. */
+#ifndef AVCT_NUM_CONN
+#define AVCT_NUM_CONN 3
+#endif
+
+/******************************************************************************
+ *
+ * AVRCP
+ *
+ *****************************************************************************/
+
+#ifndef AVRC_METADATA_INCLUDED
+#define AVRC_METADATA_INCLUDED TRUE
+#endif
+
+#ifndef AVRC_ADV_CTRL_INCLUDED
+#define AVRC_ADV_CTRL_INCLUDED TRUE
+#endif
+
+#ifndef DUMP_PCM_DATA
+#define DUMP_PCM_DATA FALSE
+#endif
+
+/******************************************************************************
+ *
+ * MCAP
+ *
+ *****************************************************************************/
+#ifndef MCA_INCLUDED
+#define MCA_INCLUDED FALSE
+#endif
+
+/* The MTU size for the L2CAP configuration on control channel. 48 is the
+ * minimal */
+#ifndef MCA_CTRL_MTU
+#define MCA_CTRL_MTU 60
+#endif
+
+/* The maximum number of registered MCAP instances. */
+#ifndef MCA_NUM_REGS
+#define MCA_NUM_REGS 12
+#endif
+
+/* The maximum number of control channels (to difference devices) per registered
+ * MCAP instances. */
+#ifndef MCA_NUM_LINKS
+#define MCA_NUM_LINKS 3
+#endif
+
+/* The maximum number of MDEP (including HDP echo) per registered MCAP
+ * instances. */
+#ifndef MCA_NUM_DEPS
+#define MCA_NUM_DEPS 13
+#endif
+
+/* The maximum number of MDL link per control channel. */
+#ifndef MCA_NUM_MDLS
+#define MCA_NUM_MDLS 4
+#endif
+
+/* Buffer size to reassemble the SDU. */
+#ifndef MCA_USER_RX_BUF_SIZE
+#define MCA_USER_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* Buffer size to hold the SDU. */
+#ifndef MCA_USER_TX_BUF_SIZE
+#define MCA_USER_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Buffer size used to hold MPS segments during SDU reassembly
+ */
+#ifndef MCA_FCR_RX_BUF_SIZE
+#define MCA_FCR_RX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/*
+ * Default buffer size used to hold MPS segments used in (re)transmissions.
+ * The size of each buffer must be able to hold the maximum MPS segment size
+ * passed in tL2CAP_FCR_OPTIONS plus BT_HDR (8) + HCI preamble (4) +
+ * L2CAP_MIN_OFFSET (11 - as of BT 2.1 + EDR Spec).
+ */
+#ifndef MCA_FCR_TX_BUF_SIZE
+#define MCA_FCR_TX_BUF_SIZE BT_DEFAULT_BUFFER_SIZE
+#endif
+
+/* MCAP control channel FCR Option:
+Size of the transmission window when using enhanced retransmission mode.
+1 is defined by HDP specification for control channel.
+*/
+#ifndef MCA_FCR_OPT_TX_WINDOW_SIZE
+#define MCA_FCR_OPT_TX_WINDOW_SIZE 1
+#endif
+
+/* MCAP control channel FCR Option:
+Number of transmission attempts for a single I-Frame before taking
+Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+Streaming modes.
+Range: 0, 1-0xFF
+0 - infinite retransmissions
+1 - single transmission
+*/
+#ifndef MCA_FCR_OPT_MAX_TX_B4_DISCNT
+#define MCA_FCR_OPT_MAX_TX_B4_DISCNT 20
+#endif
+
+/* MCAP control channel FCR Option: Retransmission Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced retransmission
+mode.
+Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#ifndef MCA_FCR_OPT_RETX_TOUT
+#define MCA_FCR_OPT_RETX_TOUT 2000
+#endif
+
+/* MCAP control channel FCR Option: Monitor Timeout
+The AVRCP specification set a value in the range of 300 - 2000 ms
+Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced retransmission
+mode.
+Range: Minimum 12000 (12 secs) when supporting PBF.
+*/
+#ifndef MCA_FCR_OPT_MONITOR_TOUT
+#define MCA_FCR_OPT_MONITOR_TOUT 12000
+#endif
+
+/* MCAP control channel FCR Option: Maximum PDU payload size.
+The maximum number of payload octets that the local device can receive in a
+single PDU.
+*/
+#ifndef MCA_FCR_OPT_MPS_SIZE
+#define MCA_FCR_OPT_MPS_SIZE 1000
+#endif
+
+/******************************************************************************
+ *
+ * BTA
+ *
+ *****************************************************************************/
+/* BTA EIR canned UUID list (default is dynamic) */
+#ifndef BTA_EIR_CANNED_UUID_LIST
+#define BTA_EIR_CANNED_UUID_LIST FALSE
+#endif
+
+/* Number of supported customer UUID in EIR */
+#ifndef BTA_EIR_SERVER_NUM_CUSTOM_UUID
+#define BTA_EIR_SERVER_NUM_CUSTOM_UUID 8
+#endif
+
+/* CHLD override */
+#ifndef BTA_AG_CHLD_VAL_ECC
+#define BTA_AG_CHLD_VAL_ECC "(0,1,1x,2,2x,3)"
+#endif
+
+#ifndef BTA_AG_CHLD_VAL
+#define BTA_AG_CHLD_VAL "(0,1,2,3)"
+#endif
+
+/* Set the CIND to match HFP 1.5 */
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO \
+ "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-1)),(\"signal\",(0-" \
+ "5)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))"
+#endif
+
+#ifndef BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY
+#define BTA_DM_AVOID_A2DP_ROLESWITCH_ON_INQUIRY TRUE
+#endif
+
+/******************************************************************************
+ *
+ * Tracing: Include trace header file here.
+ *
+ *****************************************************************************/
+
+/* Enable/disable BTSnoop memory logging */
+#ifndef BTSNOOP_MEM
+#define BTSNOOP_MEM TRUE
+#endif
+
+#include "bt_trace.h"
+
+#endif /* BT_TARGET_H */
diff --git a/mtkbt/code/bt/include/bt_trace.h b/mtkbt/code/bt/include/bt_trace.h
new file mode 100755
index 0000000..e89299a
--- a/dev/null
+++ b/mtkbt/code/bt/include/bt_trace.h
@@ -0,0 +1,776 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const char BTE_LOGMSG_MODULE[] = "bte_logmsg_module";
+
+/* BTE tracing IDs for debug purposes */
+/* LayerIDs for stack */
+#define BTTRC_ID_STK_GKI 1
+#define BTTRC_ID_STK_BTU 2
+#define BTTRC_ID_STK_HCI 3
+#define BTTRC_ID_STK_L2CAP 4
+#define BTTRC_ID_STK_RFCM_MX 5
+#define BTTRC_ID_STK_RFCM_PRT 6
+#define BTTRC_ID_STK_OBEX_C 7
+#define BTTRC_ID_STK_OBEX_S 8
+#define BTTRC_ID_STK_AVCT 9
+#define BTTRC_ID_STK_AVDT 10
+#define BTTRC_ID_STK_AVRC 11
+#define BTTRC_ID_STK_BIC 12
+#define BTTRC_ID_STK_BIS 13
+#define BTTRC_ID_STK_BNEP 14
+#define BTTRC_ID_STK_BPP 15
+#define BTTRC_ID_STK_BTM_ACL 16
+#define BTTRC_ID_STK_BTM_PM 17
+#define BTTRC_ID_STK_BTM_DEV_CTRL 18
+#define BTTRC_ID_STK_BTM_SVC_DSC 19
+#define BTTRC_ID_STK_BTM_INQ 20
+#define BTTRC_ID_STK_BTM_SCO 21
+#define BTTRC_ID_STK_BTM_SEC 22
+#define BTTRC_ID_STK_HID 24
+#define BTTRC_ID_STK_HSP2 25
+#define BTTRC_ID_STK_CTP 26
+#define BTTRC_ID_STK_FTC 27
+#define BTTRC_ID_STK_FTS 28
+#define BTTRC_ID_STK_GAP 29
+#define BTTRC_ID_STK_HCRP 31
+#define BTTRC_ID_STK_ICP 32
+#define BTTRC_ID_STK_OPC 33
+#define BTTRC_ID_STK_OPS 34
+#define BTTRC_ID_STK_PAN 35
+#define BTTRC_ID_STK_SAP 36
+#define BTTRC_ID_STK_SDP 37
+#define BTTRC_ID_STK_SLIP 38
+#define BTTRC_ID_STK_SPP 39
+#define BTTRC_ID_STK_TCS 40
+#define BTTRC_ID_STK_VDP 41
+#define BTTRC_ID_STK_MCAP 42
+#define BTTRC_ID_STK_GATT 43
+#define BTTRC_ID_STK_SMP 44
+#define BTTRC_ID_STK_NFC 45
+#define BTTRC_ID_STK_NCI 46
+#define BTTRC_ID_STK_IDEP 47
+#define BTTRC_ID_STK_NDEP 48
+#define BTTRC_ID_STK_LLCP 49
+#define BTTRC_ID_STK_RW 50
+#define BTTRC_ID_STK_CE 51
+#define BTTRC_ID_STK_SNEP 52
+#define BTTRC_ID_STK_NDEF 53
+#define BTTRC_ID_STK_HIDD 54
+
+/* LayerIDs for BTA */
+#define BTTRC_ID_BTA_ACC 55 /* Advanced Camera Client */
+#define BTTRC_ID_BTA_AG 56 /* audio gateway */
+#define BTTRC_ID_BTA_AV 57 /* Advanced audio */
+#define BTTRC_ID_BTA_BIC 58 /* Basic Imaging Client */
+#define BTTRC_ID_BTA_BIS 59 /* Basic Imaging Server */
+#define BTTRC_ID_BTA_BP 60 /* Basic Printing Client */
+#define BTTRC_ID_BTA_CG 61
+#define BTTRC_ID_BTA_CT 62 /* cordless telephony terminal */
+#define BTTRC_ID_BTA_DG 63 /* data gateway */
+#define BTTRC_ID_BTA_DM 64 /* device manager */
+#define BTTRC_ID_BTA_DM_SRCH 65 /* device manager search */
+#define BTTRC_ID_BTA_DM_SEC 66 /* device manager security */
+#define BTTRC_ID_BTA_FM 67
+#define BTTRC_ID_BTA_FTC 68 /* file transfer client */
+#define BTTRC_ID_BTA_FTS 69 /* file transfer server */
+#define BTTRC_ID_BTA_HIDH 70
+#define BTTRC_ID_BTA_HIDD 71
+#define BTTRC_ID_BTA_JV 72
+#define BTTRC_ID_BTA_OPC 73 /* object push client */
+#define BTTRC_ID_BTA_OPS 74 /* object push server */
+#define BTTRC_ID_BTA_PAN 75 /* Personal Area Networking */
+#define BTTRC_ID_BTA_PR 76 /* Printer client */
+#define BTTRC_ID_BTA_SC 77 /* SIM Card Access server */
+#define BTTRC_ID_BTA_SS 78 /* synchronization server */
+#define BTTRC_ID_BTA_SYS 79 /* system manager */
+#define BTTRC_ID_AVDT_SCB 80 /* avdt scb */
+#define BTTRC_ID_AVDT_CCB 81 /* avdt ccb */
+
+/* LayerIDs added for BTL-A. Probably should modify bte_logmsg.cc in future. */
+#define BTTRC_ID_STK_RFCOMM 82
+#define BTTRC_ID_STK_RFCOMM_DATA 83
+#define BTTRC_ID_STK_OBEX 84
+#define BTTRC_ID_STK_A2DP 85
+#define BTTRC_ID_STK_BIP 86
+
+/* LayerIDs for BT APP */
+#define BTTRC_ID_BTAPP 87
+/* this is a temporary solution to allow dynamic enable/disable of
+ * BT_PROTOCOL_TRACE */
+#define BTTRC_ID_BT_PROTOCOL 88
+#define BTTRC_ID_MAX_ID BTTRC_ID_BT_PROTOCOL
+#define BTTRC_ID_ALL_LAYERS 0xFF /* all trace layers */
+
+/******************************************************************************
+ *
+ * Trace Levels
+ *
+ * The following values may be used for different levels:
+ * BT_TRACE_LEVEL_NONE 0 * No trace messages to be generated
+ * BT_TRACE_LEVEL_ERROR 1 * Error condition trace messages
+ * BT_TRACE_LEVEL_WARNING 2 * Warning condition trace messages
+ * BT_TRACE_LEVEL_API 3 * API traces
+ * BT_TRACE_LEVEL_EVENT 4 * Debug messages for events
+ * BT_TRACE_LEVEL_DEBUG 5 * Debug messages (general)
+ *****************************************************************************/
+
+/* Core Stack default trace levels */
+#ifndef HCI_INITIAL_TRACE_LEVEL
+#define HCI_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BTM_INITIAL_TRACE_LEVEL
+#define BTM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef L2CAP_INITIAL_TRACE_LEVEL
+#define L2CAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef RFCOMM_INITIAL_TRACE_LEVEL
+#define RFCOMM_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SDP_INITIAL_TRACE_LEVEL
+#define SDP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GAP_INITIAL_TRACE_LEVEL
+#define GAP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BNEP_INITIAL_TRACE_LEVEL
+#define BNEP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef PAN_INITIAL_TRACE_LEVEL
+#define PAN_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef A2DP_INITIAL_TRACE_LEVEL
+#define A2DP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVDT_INITIAL_TRACE_LEVEL
+#define AVDT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVCT_INITIAL_TRACE_LEVEL
+#define AVCT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef AVRC_INITIAL_TRACE_LEVEL
+#define AVRC_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef MCA_INITIAL_TRACE_LEVEL
+#define MCA_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef HID_INITIAL_TRACE_LEVEL
+#define HID_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef APPL_INITIAL_TRACE_LEVEL
+#define APPL_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef GATT_INITIAL_TRACE_LEVEL
+#define GATT_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef SMP_INITIAL_TRACE_LEVEL
+#define SMP_INITIAL_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#define BT_TRACE(l, t, ...) \
+ LogMsg((TRACE_CTRL_GENERAL | (l) | TRACE_ORG_STACK | (t)), ##__VA_ARGS__)
+
+/* Define tracing for the HCI unit */
+#define HCI_TRACE_ERROR(...) \
+ { \
+ if (btu_trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define HCI_TRACE_WARNING(...) \
+ { \
+ if (btu_trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define HCI_TRACE_EVENT(...) \
+ { \
+ if (btu_trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define HCI_TRACE_DEBUG(...) \
+ { \
+ if (btu_trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_HCI, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for BTM */
+#define BTM_TRACE_ERROR(...) \
+ { \
+ if (btm_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define BTM_TRACE_WARNING(...) \
+ { \
+ if (btm_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define BTM_TRACE_API(...) \
+ { \
+ if (btm_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define BTM_TRACE_EVENT(...) \
+ { \
+ if (btm_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define BTM_TRACE_DEBUG(...) \
+ { \
+ if (btm_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_BTM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the L2CAP unit */
+#define L2CAP_TRACE_ERROR(...) \
+ { \
+ if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define L2CAP_TRACE_WARNING(...) \
+ { \
+ if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define L2CAP_TRACE_API(...) \
+ { \
+ if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define L2CAP_TRACE_EVENT(...) \
+ { \
+ if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define L2CAP_TRACE_DEBUG(...) \
+ { \
+ if (l2cb.l2cap_trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_L2CAP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the SDP unit */
+#define SDP_TRACE_ERROR(...) \
+ { \
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define SDP_TRACE_WARNING(...) \
+ { \
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define SDP_TRACE_API(...) \
+ { \
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define SDP_TRACE_EVENT(...) \
+ { \
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define SDP_TRACE_DEBUG(...) \
+ { \
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_SDP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the RFCOMM unit */
+#define RFCOMM_TRACE_ERROR(...) \
+ { \
+ if (rfc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define RFCOMM_TRACE_WARNING(...) \
+ { \
+ if (rfc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define RFCOMM_TRACE_API(...) \
+ { \
+ if (rfc_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define RFCOMM_TRACE_EVENT(...) \
+ { \
+ if (rfc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define RFCOMM_TRACE_DEBUG(...) \
+ { \
+ if (rfc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_RFCOMM, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Generic Access Profile traces */
+#define GAP_TRACE_ERROR(...) \
+ { \
+ if (gap_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define GAP_TRACE_EVENT(...) \
+ { \
+ if (gap_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define GAP_TRACE_API(...) \
+ { \
+ if (gap_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define GAP_TRACE_WARNING(...) \
+ { \
+ if (gap_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_GAP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+
+/* define traces for HID Host */
+#define HIDH_TRACE_ERROR(...) \
+ { \
+ if (hh_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define HIDH_TRACE_WARNING(...) \
+ { \
+ if (hh_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define HIDH_TRACE_API(...) \
+ { \
+ if (hh_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define HIDH_TRACE_EVENT(...) \
+ { \
+ if (hh_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define HIDH_TRACE_DEBUG(...) \
+ { \
+ if (hh_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* define traces for HID Device */
+#define HIDD_TRACE_ERROR(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_WARNING(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_API(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_EVENT(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_DEBUG(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define HIDD_TRACE_VERBOSE(...) \
+ { \
+ if (hd_cb.trace_level >= BT_TRACE_LEVEL_VERBOSE) \
+ BT_TRACE(TRACE_LAYER_HID, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* define traces for BNEP */
+#define BNEP_TRACE_ERROR(...) \
+ { \
+ if (bnep_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define BNEP_TRACE_WARNING(...) \
+ { \
+ if (bnep_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define BNEP_TRACE_API(...) \
+ { \
+ if (bnep_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define BNEP_TRACE_EVENT(...) \
+ { \
+ if (bnep_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define BNEP_TRACE_DEBUG(...) \
+ { \
+ if (bnep_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_BNEP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* define traces for PAN */
+#define PAN_TRACE_ERROR(...) \
+ { \
+ if (pan_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define PAN_TRACE_WARNING(...) \
+ { \
+ if (pan_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define PAN_TRACE_API(...) \
+ { \
+ if (pan_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define PAN_TRACE_EVENT(...) \
+ { \
+ if (pan_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define PAN_TRACE_DEBUG(...) \
+ { \
+ if (pan_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_PAN, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the A2DP profile */
+#define A2DP_TRACE_ERROR(...) \
+ { \
+ if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define A2DP_TRACE_WARNING(...) \
+ { \
+ if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define A2DP_TRACE_EVENT(...) \
+ { \
+ if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define A2DP_TRACE_DEBUG(...) \
+ { \
+ if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define A2DP_TRACE_API(...) \
+ { \
+ if (a2dp_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_A2DP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+
+/* AVDTP */
+#define AVDT_TRACE_ERROR(...) \
+ { \
+ if (avdt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define AVDT_TRACE_WARNING(...) \
+ { \
+ if (avdt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define AVDT_TRACE_EVENT(...) \
+ { \
+ if (avdt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define AVDT_TRACE_DEBUG(...) \
+ { \
+ if (avdt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define AVDT_TRACE_API(...) \
+ { \
+ if (avdt_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the AVCTP protocol */
+#define AVCT_TRACE_ERROR(...) \
+ { \
+ if (avct_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define AVCT_TRACE_WARNING(...) \
+ { \
+ if (avct_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define AVCT_TRACE_EVENT(...) \
+ { \
+ if (avct_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define AVCT_TRACE_DEBUG(...) \
+ { \
+ if (avct_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define AVCT_TRACE_API(...) \
+ { \
+ if (avct_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the AVRCP profile */
+#define AVRC_TRACE_ERROR(...) \
+ { \
+ if (avrc_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define AVRC_TRACE_WARNING(...) \
+ { \
+ if (avrc_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define AVRC_TRACE_EVENT(...) \
+ { \
+ if (avrc_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define AVRC_TRACE_DEBUG(...) \
+ { \
+ if (avrc_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define AVRC_TRACE_API(...) \
+ { \
+ if (avrc_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_AVP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+
+/* MCAP */
+#define MCA_TRACE_ERROR(...) \
+ { \
+ if (mca_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define MCA_TRACE_WARNING(...) \
+ { \
+ if (mca_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define MCA_TRACE_EVENT(...) \
+ { \
+ if (mca_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define MCA_TRACE_DEBUG(...) \
+ { \
+ if (mca_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+#define MCA_TRACE_API(...) \
+ { \
+ if (mca_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_MCA, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the ATT/GATT unit */
+#define GATT_TRACE_ERROR(...) \
+ { \
+ if (gatt_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define GATT_TRACE_WARNING(...) \
+ { \
+ if (gatt_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define GATT_TRACE_API(...) \
+ { \
+ if (gatt_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define GATT_TRACE_EVENT(...) \
+ { \
+ if (gatt_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define GATT_TRACE_DEBUG(...) \
+ { \
+ if (gatt_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_ATT, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+/* Define tracing for the SMP unit */
+#define SMP_TRACE_ERROR(...) \
+ { \
+ if (smp_cb.trace_level >= BT_TRACE_LEVEL_ERROR) \
+ BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_ERROR, ##__VA_ARGS__); \
+ }
+#define SMP_TRACE_WARNING(...) \
+ { \
+ if (smp_cb.trace_level >= BT_TRACE_LEVEL_WARNING) \
+ BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_WARNING, ##__VA_ARGS__); \
+ }
+#define SMP_TRACE_API(...) \
+ { \
+ if (smp_cb.trace_level >= BT_TRACE_LEVEL_API) \
+ BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_API, ##__VA_ARGS__); \
+ }
+#define SMP_TRACE_EVENT(...) \
+ { \
+ if (smp_cb.trace_level >= BT_TRACE_LEVEL_EVENT) \
+ BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_EVENT, ##__VA_ARGS__); \
+ }
+#define SMP_TRACE_DEBUG(...) \
+ { \
+ if (smp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ BT_TRACE(TRACE_LAYER_SMP, TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
+ }
+
+extern uint8_t btif_trace_level;
+
+/* define traces for application */
+#define BTIF_TRACE_ERROR(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_ERROR) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_ERROR, \
+ ##__VA_ARGS__); \
+ }
+#define BTIF_TRACE_WARNING(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_WARNING) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_WARNING, \
+ ##__VA_ARGS__); \
+ }
+#define BTIF_TRACE_API(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_API) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_API, \
+ ##__VA_ARGS__); \
+ }
+#define BTIF_TRACE_EVENT(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_EVENT) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_EVENT, \
+ ##__VA_ARGS__); \
+ }
+#define BTIF_TRACE_DEBUG(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_DEBUG, \
+ ##__VA_ARGS__); \
+ }
+#define BTIF_TRACE_VERBOSE(...) \
+ { \
+ if (btif_trace_level >= BT_TRACE_LEVEL_VERBOSE) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_DEBUG, \
+ ##__VA_ARGS__); \
+ }
+
+/* define traces for application */
+#define APPL_TRACE_ERROR(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_ERROR) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_ERROR, \
+ ##__VA_ARGS__); \
+ }
+#define APPL_TRACE_WARNING(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_WARNING) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_WARNING, \
+ ##__VA_ARGS__); \
+ }
+#define APPL_TRACE_API(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_API) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_API, \
+ ##__VA_ARGS__); \
+ }
+#define APPL_TRACE_EVENT(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_EVENT) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_EVENT, \
+ ##__VA_ARGS__); \
+ }
+#define APPL_TRACE_DEBUG(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_DEBUG) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_DEBUG, \
+ ##__VA_ARGS__); \
+ }
+#define APPL_TRACE_VERBOSE(...) \
+ { \
+ if (appl_trace_level >= BT_TRACE_LEVEL_VERBOSE) \
+ LogMsg(TRACE_CTRL_GENERAL | TRACE_LAYER_NONE | TRACE_ORG_APPL | \
+ TRACE_TYPE_DEBUG, \
+ ##__VA_ARGS__); \
+ }
+
+typedef uint8_t tBTTRC_LAYER_ID;
+typedef uint8_t(tBTTRC_SET_TRACE_LEVEL)(uint8_t);
+
+typedef struct {
+ const tBTTRC_LAYER_ID layer_id_start;
+ const tBTTRC_LAYER_ID layer_id_end;
+ tBTTRC_SET_TRACE_LEVEL* p_f;
+ const char* trc_name;
+ uint8_t trace_level;
+} tBTTRC_FUNC_MAP;
+
+/* External declaration for appl_trace_level here to avoid to add the
+ * declaration in all the files using APPL_TRACExxx macros */
+extern uint8_t appl_trace_level;
+
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/mtkbt/code/bt/include/bte.h b/mtkbt/code/bt/include/bte.h
new file mode 100755
index 0000000..90c9590
--- a/dev/null
+++ b/mtkbt/code/bt/include/bte.h
@@ -0,0 +1,131 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains constants and definitions for the bte project
+ *
+ ******************************************************************************/
+#ifndef BTE_H
+#define BTE_H
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include "bt_target.h"
+
+/* By default on shutdown, the baud rate is reset to 115kbits. This should NOT
+ * be needed for platforms that kill the BTE driver and remove/reset BT chip.
+ */
+#ifndef BTE_RESET_BAUD_ON_BT_DISABLE
+#define BTE_RESET_BAUD_ON_BT_DISABLE TRUE
+#endif
+
+/* Target Modes (based on jumper settings on hardware [see user manual])
+ * BTE BBY
+ * J3 J4 SW3-3 SW3-2 SW3-1
+ * --------------------------------------------
+ * BTE_MODE_SERIAL_APP, OUT OUT OFF OFF OFF
+ * BTE_MODE_APPL, IN OUT OFF OFF ON
+ * BTE_MODE_RESERVED, OUT IN OFF ON OFF
+ * BTE_MODE_SAMPLE_APPS, IN IN OFF ON ON
+ * BTE_MODE_DONGLE, not yet supported ON OFF OFF
+ * BTE_MODE_APPL_PROTOCOL_TRACE, * this is a fake mode *
+ * BTE_MODE_INVALID
+ */
+enum {
+ BTE_MODE_SERIAL_APP, /* Sample serial port application */
+ BTE_MODE_APPL, /* Target used with Tester through RPC */
+ BTE_MODE_RESERVED, /* Reserved */
+ BTE_MODE_SAMPLE_APPS, /* Sample applications (ICP/HSP) */
+ BTE_MODE_DONGLE, /* Dongle mode */
+ BTE_MODE_APPL_PROTOCOL_TRACE, /* Allow protocol tracing without rpc */
+ BTE_MODE_INVALID
+};
+
+extern volatile uint8_t
+ bte_target_mode; /* indicates the mode that the board is running in */
+
+/* Startup options */
+extern uint32_t bte_startup_options; /* Switch and jumper settings at startup */
+void bte_get_startup_options(
+ uint32_t*
+ p_options); /* Platform specific function for getting startup options */
+
+#define BTE_OPTIONS_TARGET_MODE_MASK \
+ 0x00000007 /* bits 2-0 indicate target mode (QuickConnect: jp3 & jp4, BBY: \
+ SW3-1 & SW3-2)*/
+
+/****************************************************************************
+ * Definitions to define which type of application gets built
+ ****************************************************************************/
+#define BUILD_HCITOOL FALSE
+#define BUILD_L2PING FALSE
+
+#define LINUX_FM_DRIVER_INCLUDED FALSE
+
+/* hcisu userial operations. should probably go into bt_types to avoid
+ * collisions! */
+#define BT_EVT_TO_HCISU_USERIAL_OP (0x0080 | BT_EVT_HCISU)
+/* operation for above hcisu event */
+#define BT_HCISU_USERIAL_OPEN \
+ (0) /* open serial port calling USERIAL_Open() \
+ */
+#define BT_HCISU_USERIAL_CLOSE (1) /* close userial port */
+/* options associated with close op */
+#define BT_HCISU_USERIAL_CL_NO_DIS_BT \
+ 0 /* do not touch bt_wake and power gpio */
+#define BT_HCISU_USERIAL_CL_DIS_BT \
+ 1 /* put power and bt_wake into defined off state to preserve \
+ power */
+/* status codes for callback */
+#define BTE_HCISU_USERIAL_FAIL 0
+#define BTE_HCISU_USERIAL_OK 1
+typedef void(tUSERIAL_MSG_CBACK)(int status);
+typedef struct tHCISU_USERIAL_MSG_tag {
+ BT_HDR hdr;
+ tUSERIAL_MSG_CBACK* p_cback;
+ uint8_t port; /* port number */
+ uint8_t op;
+ uint8_t option; /* option for operation. depends on operation */
+} tHCISU_USERIAL_MSG;
+
+extern void bte_hcisu_userial_oper(tUSERIAL_MSG_CBACK* p_cback, uint8_t port,
+ uint8_t op, uint8_t option);
+
+/* Pointer to function for sending HCI commands and data to the HCI tranport */
+extern int (*p_bte_hci_send)(uint16_t port, BT_HDR* p_msg);
+
+// Initialize control block memory for each stack component.
+extern void BTE_InitStack(void);
+
+/* Protocol trace mask */
+extern uint32_t bte_proto_trace_mask;
+
+typedef struct tBAUD_REG_tag {
+ uint8_t DHBR;
+ uint8_t DLBR;
+ uint8_t ExplicitBaudRate0;
+ uint8_t ExplicitBaudRate1;
+ uint8_t ExplicitBaudRate2;
+ uint8_t ExplicitBaudRate3;
+} tBAUD_REG;
+
+extern const tBAUD_REG baud_rate_regs[];
+
+#endif /* BTE_H */
diff --git a/mtkbt/code/bt/include/bte_appl.h b/mtkbt/code/bt/include/bte_appl.h
new file mode 100755
index 0000000..b2aaa02
--- a/dev/null
+++ b/mtkbt/code/bt/include/bte_appl.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for the bte application task
+ *
+ ******************************************************************************/
+
+#pragma once
+
+typedef struct {
+ uint8_t ble_auth_req;
+ uint8_t ble_io_cap;
+ uint8_t ble_init_key;
+ uint8_t ble_resp_key;
+ uint8_t ble_max_key_size;
+} tBTE_APPL_CFG;
+
+extern tBTE_APPL_CFG bte_appl_cfg;
diff --git a/mtkbt/code/bt/include/stack_config.h b/mtkbt/code/bt/include/stack_config.h
new file mode 100755
index 0000000..156f5be
--- a/dev/null
+++ b/mtkbt/code/bt/include/stack_config.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "module.h"
+#include "osi/include/config.h"
+
+static const char STACK_CONFIG_MODULE[] = "stack_config_module";
+
+typedef struct {
+ bool (*get_trace_config_enabled)(void);
+ bool (*get_pts_secure_only_mode)(void);
+ bool (*get_pts_conn_updates_disabled)(void);
+ bool (*get_pts_crosskey_sdp_disable)(void);
+ const char* (*get_pts_smp_options)(void);
+ int (*get_pts_smp_failure_case)(void);
+ config_t* (*get_all)(void);
+} stack_config_t;
+
+const stack_config_t* stack_config_get_interface(void);
diff --git a/mtkbt/code/bt/main/Android.bp b/mtkbt/code/bt/main/Android.bp
new file mode 100755
index 0000000..b8e0bd6
--- a/dev/null
+++ b/mtkbt/code/bt/main/Android.bp
@@ -0,0 +1,89 @@
+// Bluetooth main HW module / shared library for target
+// ========================================================
+cc_library_shared {
+ name: "bluetooth.default",
+ defaults: ["fluoride_defaults"],
+ relative_install_path: "hw",
+ srcs: [
+ // platform specific
+ "bte_conf.cc",
+ "bte_init.cc",
+ "bte_init_cpp_logging.cc",
+ "bte_logmsg.cc",
+ "bte_main.cc",
+ "stack_config.cc",
+ ],
+ include_dirs: [
+ "hardware/mtk/bluetooth/mtkbt/code/bt",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/bta/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/bta/sys",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/bta/dm",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/btcore/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/l2cap",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/a2dp",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/btm",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/stack/avdt",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/udrv/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/btif/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/btif/co",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/hci/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/vnd/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/embdrv/sbc/encoder/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/embdrv/sbc/decoder/include",
+ "hardware/mtk/bluetooth/mtkbt/code/bt/utils/include",
+ ],
+ logtags: ["../EventLogTags.logtags"],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libaudioclient",
+ "libcutils",
+ "libdl",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libutils",
+ "libtinyxml2",
+ "libz",
+ ],
+ static_libs: [
+ "libbt-sbc-decoder",
+ "libbt-sbc-encoder",
+ "libFraunhoferAAC",
+ "libudrv-uipc",
+ ],
+ whole_static_libs: [
+ "libbt-bta",
+ "libbtdevice",
+ "libbtif",
+ "libbt-hci",
+ "libbt-protos",
+ "libbt-stack",
+ "libbt-utils",
+ "libbtcore",
+ "libosi",
+ "libbt-mtk_cust",
+ ],
+ // Shared library link options.
+ // References to global symbols and functions should bind to the library
+ // itself. This is to avoid issues with some of the unit/system tests
+ // that might link statically with some of the code in the library, and
+ // also dlopen(3) the shared library.
+ ldflags: ["-Wl,-Bsymbolic,-Bsymbolic-functions"],
+ required: [
+ "bt_did.conf",
+ "bt_stack.conf",
+ "libbt-hci",
+ "libldacBT_enc",
+ "libldacBT_abr",
+ // TODO(Peng): To check if conditional MTK_STACK_CONFIG_LOG is supported
+ "mtk_bt_stack.conf",
+ "mtk_bt_fw.conf",
+ ],
+ cflags: [
+ "-DBUILDCFG",
+ ],
+}
diff --git a/mtkbt/code/bt/main/BUILD.gn b/mtkbt/code/bt/main/BUILD.gn
new file mode 100755
index 0000000..957068c
--- a/dev/null
+++ b/mtkbt/code/bt/main/BUILD.gn
@@ -0,0 +1,86 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+shared_library("bluetooth.default") {
+ # HAL layer
+ sources = [
+ "//btif/src/bluetooth.cc",
+ ]
+
+ # platform specific
+ sources += [
+ "bte_conf.cc",
+ "bte_init.cc",
+ "bte_init_cpp_logging.cc",
+ "bte_logmsg.cc",
+ "bte_main.cc",
+ "stack_config.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//bta/include",
+ "//bta/sys",
+ "//bta/dm",
+ "//btcore/include",
+ "//include",
+ "//stack/include",
+ "//stack/l2cap",
+ "//stack/a2dp",
+ "//stack/btm",
+ "//stack/avdt",
+ "//hci",
+ "//hci/include",
+ "//udrv/include",
+ "//btif/include",
+ "//btif/co",
+ "//hci/includ",
+ "//vnd/include",
+ "//brcm/include",
+ "//embdrv/sbc/encoder/include",
+ "//embdrv/sbc/decoder/include",
+ "//utils/include",
+ "//test/suite",
+ ]
+
+ deps = [
+ "//bta",
+ "//btcore",
+ "//btif",
+ "//device",
+ "//embdrv/sbc",
+ "//hci",
+ "//osi",
+ "//stack",
+ "//third_party/libchrome:base",
+ "//third_party/tinyxml2",
+ "//udrv",
+ "//utils",
+ ]
+
+ cflags_c = [
+ "-Lobj/osi",
+ "-losi",
+ ]
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+}
diff --git a/mtkbt/code/bt/main/bte_conf.cc b/mtkbt/code/bt/main/bte_conf.cc
new file mode 100755
index 0000000..f765eb6
--- a/dev/null
+++ b/mtkbt/code/bt/main/bte_conf.cc
@@ -0,0 +1,99 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bte_conf"
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bta_api.h"
+#include "btif_common.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+
+// Parses the specified Device ID configuration file and registers the
+// Device ID records with SDP.
+void bte_load_did_conf(const char* p_path) {
+ CHECK(p_path != NULL);
+
+ config_t* config = config_new(p_path);
+ if (!config) {
+ LOG_ERROR(LOG_TAG, "%s unable to load DID config '%s'.", __func__, p_path);
+ return;
+ }
+
+ for (int i = 1; i <= BTA_DI_NUM_MAX; ++i) {
+ char section_name[16] = {0};
+ snprintf(section_name, sizeof(section_name), "DID%d", i);
+
+ if (!config_has_section(config, section_name)) {
+ LOG_DEBUG(LOG_TAG, "%s no section named %s.", __func__, section_name);
+ break;
+ }
+
+ tBTA_DI_RECORD record;
+ record.vendor =
+ config_get_int(config, section_name, "vendorId", LMP_COMPID_BROADCOM);
+ record.vendor_id_source = config_get_int(
+ config, section_name, "vendorIdSource", DI_VENDOR_ID_SOURCE_BTSIG);
+ record.product = config_get_int(config, section_name, "productId", 0);
+ record.version = config_get_int(config, section_name, "version", 0);
+ record.primary_record =
+ config_get_bool(config, section_name, "primaryRecord", false);
+ strlcpy(record.client_executable_url,
+ config_get_string(config, section_name, "clientExecutableURL", ""),
+ sizeof(record.client_executable_url));
+ strlcpy(record.service_description,
+ config_get_string(config, section_name, "serviceDescription", ""),
+ sizeof(record.service_description));
+ strlcpy(record.documentation_url,
+ config_get_string(config, section_name, "documentationURL", ""),
+ sizeof(record.documentation_url));
+
+ if (record.vendor_id_source != DI_VENDOR_ID_SOURCE_BTSIG &&
+ record.vendor_id_source != DI_VENDOR_ID_SOURCE_USBIF) {
+ LOG_ERROR(LOG_TAG,
+ "%s invalid vendor id source %d; ignoring DID record %d.",
+ __func__, record.vendor_id_source, i);
+ continue;
+ }
+
+ LOG_DEBUG(LOG_TAG, "Device ID record %d : %s", i,
+ (record.primary_record ? "primary" : "not primary"));
+ LOG_DEBUG(LOG_TAG, " vendorId = %04x", record.vendor);
+ LOG_DEBUG(LOG_TAG, " vendorIdSource = %04x", record.vendor_id_source);
+ LOG_DEBUG(LOG_TAG, " product = %04x", record.product);
+ LOG_DEBUG(LOG_TAG, " version = %04x", record.version);
+ LOG_DEBUG(LOG_TAG, " clientExecutableURL = %s",
+ record.client_executable_url);
+ LOG_DEBUG(LOG_TAG, " serviceDescription = %s",
+ record.service_description);
+ LOG_DEBUG(LOG_TAG, " documentationURL = %s", record.documentation_url);
+
+ uint32_t record_handle;
+ tBTA_STATUS status = BTA_DmSetLocalDiRecord(&record, &record_handle);
+ if (status != BTA_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s unable to set device ID record %d: error %d.",
+ __func__, i, status);
+ }
+ }
+
+ config_free(config);
+}
diff --git a/mtkbt/code/bt/main/bte_init.cc b/mtkbt/code/bt/main/bte_init.cc
new file mode 100755
index 0000000..2aa8a97
--- a/dev/null
+++ b/mtkbt/code/bt/main/bte_init.cc
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the routines that initialize the stack components.
+ * It must be called before the BTU task is started.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+
+#ifndef BTA_INCLUDED
+#define BTA_INCLUDED FALSE
+#endif
+
+#include "bte.h"
+
+/* Include initialization functions definitions */
+#include "port_api.h"
+
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_api.h"
+#endif
+
+#include "gap_api.h"
+
+#if (PAN_INCLUDED == TRUE)
+#include "pan_api.h"
+#endif
+
+#include "avrc_api.h"
+
+#if (A2D_INCLUDED == TRUE)
+#include "a2dp_api.h"
+#endif
+
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#endif
+
+#include "gatt_api.h"
+#include "smp_api.h"
+
+/*****************************************************************************
+ * F U N C T I O N S *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Function BTE_InitStack
+ *
+ * Description Initialize control block memory for each component.
+ *
+ * Note: The core stack components must be called
+ * before creating the BTU Task. The rest of the
+ * components can be initialized at a later time if desired
+ * as long as the component's init function is called
+ * before accessing any of its functions.
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void BTE_InitStack(void) {
+ /* Initialize the optional stack components */
+ RFCOMM_Init();
+
+/**************************
+ * BNEP and its profiles **
+ **************************/
+#if (BNEP_INCLUDED == TRUE)
+ BNEP_Init();
+
+#if (PAN_INCLUDED == TRUE)
+ PAN_Init();
+#endif /* PAN */
+#endif /* BNEP Included */
+
+/**************************
+ * AVDT and its profiles **
+ **************************/
+#if (A2D_INCLUDED == TRUE)
+ A2DP_Init();
+#endif /* AADP */
+
+ AVRC_Init();
+
+ /***********
+ * Others **
+ ***********/
+ GAP_Init();
+
+#if (HID_HOST_INCLUDED == TRUE)
+ HID_HostInit();
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+ MCA_Init();
+#endif
+}
diff --git a/mtkbt/code/bt/main/bte_init_cpp_logging.cc b/mtkbt/code/bt/main/bte_init_cpp_logging.cc
new file mode 100755
index 0000000..f29500d
--- a/dev/null
+++ b/mtkbt/code/bt/main/bte_init_cpp_logging.cc
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <base/command_line.h>
+#include "main_int.h"
+
+void init_cpp_logging(config_t* config) {
+ // Command line and log level might be also configured in service/main.cpp
+ // when running the bluetoothtbd daemon. If it's already configured, skip
+ // configuring.
+ if (base::CommandLine::InitializedForCurrentProcess()) return;
+
+ const char* loggingV =
+ config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingV", NULL);
+ const char* loggingVModule =
+ config_get_string(config, CONFIG_DEFAULT_SECTION, "LoggingVModule", NULL);
+
+ int argc = 1;
+ const char* argv[] = {"bt_stack", NULL, NULL};
+
+ if (loggingV != NULL) {
+ argv[argc] = loggingV;
+ argc++;
+ }
+
+ if (loggingVModule != NULL) {
+ argv[argc] = loggingVModule;
+ argc++;
+ }
+
+ // Init command line object with logging switches
+ base::CommandLine::Init(argc, argv);
+
+ logging::LoggingSettings log_settings;
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ }
+
+ // Android already logs thread_id, proc_id, timestamp, so disable those.
+ logging::SetLogItems(false, false, false, false);
+}
diff --git a/mtkbt/code/bt/main/bte_logmsg.cc b/mtkbt/code/bt/main/bte_logmsg.cc
new file mode 100755
index 0000000..42c2db8
--- a/dev/null
+++ b/mtkbt/code/bt/main/bte_logmsg.cc
@@ -0,0 +1,235 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_bte"
+
+#include <base/logging.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrc_api.h"
+#include "bt_common.h"
+#include "bta_api.h"
+#include "bte.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "gap_api.h"
+#include "l2c_api.h"
+#include "main_int.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "port_api.h"
+#include "sdp_api.h"
+#include "stack_config.h"
+
+#if (AVDT_INCLUDED == TRUE)
+#include "avdt_api.h"
+#endif
+#if (A2D_INCLUDED == TRUE)
+#include "a2dp_api.h"
+#endif
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_api.h"
+#endif
+#if (PAN_INCLUDED == TRUE)
+#include "pan_api.h"
+#endif
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_api.h"
+#endif
+#if (HID_DEV_INCLUDED == TRUE)
+#include "hidd_api.h"
+#endif
+
+#include "gatt_api.h"
+#include "smp_api.h"
+
+#ifndef DEFAULT_CONF_TRACE_LEVEL
+#define DEFAULT_CONF_TRACE_LEVEL BT_TRACE_LEVEL_WARNING
+#endif
+
+#ifndef BTE_LOG_BUF_SIZE
+#define BTE_LOG_BUF_SIZE 1024
+#endif
+
+#define BTE_LOG_MAX_SIZE (BTE_LOG_BUF_SIZE - 12)
+
+#define MSG_BUFFER_OFFSET 0
+
+/* LayerIDs for BTA, currently everything maps onto appl_trace_level */
+static const char* const bt_layer_tags[] = {
+ "bt_btif", "bt_usb", "bt_serial", "bt_socket", "bt_rs232", "bt_lc",
+ "bt_lm", "bt_hci", "bt_l2cap", "bt_rfcomm", "bt_sdp", "bt_tcs",
+ "bt_obex", "bt_btm", "bt_gap", "UNUSED", "UNUSED", "bt_icp",
+ "bt_hsp2", "bt_spp", "bt_ctp", "bt_bpp", "bt_hcrp", "bt_ftp",
+ "bt_opp", "bt_btu", "bt_gki", /* OBSOLETED */
+ "bt_bnep", "bt_pan", "bt_hfp", "bt_hid", "bt_bip", "bt_avp",
+ "bt_a2d", "bt_sap", "bt_amp", "bt_mca", "bt_att", "bt_smp",
+ "bt_nfc", "bt_nci", "bt_idep", "bt_ndep", "bt_llcp", "bt_rw",
+ "bt_ce", "bt_snep", "bt_ndef", "bt_nfa",
+};
+static uint8_t BTAPP_SetTraceLevel(uint8_t new_level);
+static uint8_t BTIF_SetTraceLevel(uint8_t new_level);
+static uint8_t BTU_SetTraceLevel(uint8_t new_level);
+
+/* make sure list is order by increasing layer id!!! */
+static tBTTRC_FUNC_MAP bttrc_set_level_map[] = {
+ {BTTRC_ID_STK_BTU, BTTRC_ID_STK_HCI, BTU_SetTraceLevel, "TRC_HCI",
+ DEFAULT_CONF_TRACE_LEVEL},
+ {BTTRC_ID_STK_L2CAP, BTTRC_ID_STK_L2CAP, L2CA_SetTraceLevel, "TRC_L2CAP",
+ DEFAULT_CONF_TRACE_LEVEL},
+ {BTTRC_ID_STK_RFCOMM, BTTRC_ID_STK_RFCOMM_DATA, PORT_SetTraceLevel,
+ "TRC_RFCOMM", DEFAULT_CONF_TRACE_LEVEL},
+#if (AVDT_INCLUDED == TRUE)
+ {BTTRC_ID_STK_AVDT, BTTRC_ID_STK_AVDT, AVDT_SetTraceLevel, "TRC_AVDT",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+ {BTTRC_ID_STK_AVRC, BTTRC_ID_STK_AVRC, AVRC_SetTraceLevel, "TRC_AVRC",
+ DEFAULT_CONF_TRACE_LEVEL},
+#if (AVDT_INCLUDED == TRUE)
+//{BTTRC_ID_AVDT_SCB, BTTRC_ID_AVDT_CCB, NULL, "TRC_AVDT_SCB",
+// DEFAULT_CONF_TRACE_LEVEL},
+#endif
+#if (A2D_INCLUDED == TRUE)
+ {BTTRC_ID_STK_A2DP, BTTRC_ID_STK_A2DP, A2DP_SetTraceLevel, "TRC_A2D",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+#if (BNEP_INCLUDED == TRUE)
+ {BTTRC_ID_STK_BNEP, BTTRC_ID_STK_BNEP, BNEP_SetTraceLevel, "TRC_BNEP",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+ {BTTRC_ID_STK_BTM_ACL, BTTRC_ID_STK_BTM_SEC, BTM_SetTraceLevel, "TRC_BTM",
+ DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_HOST_INCLUDED == TRUE)
+ {BTTRC_ID_STK_HID, BTTRC_ID_STK_HID, HID_HostSetTraceLevel, "TRC_HID_HOST",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+ {BTTRC_ID_STK_GAP, BTTRC_ID_STK_GAP, GAP_SetTraceLevel, "TRC_GAP",
+ DEFAULT_CONF_TRACE_LEVEL},
+#if (PAN_INCLUDED == TRUE)
+ {BTTRC_ID_STK_PAN, BTTRC_ID_STK_PAN, PAN_SetTraceLevel, "TRC_PAN",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+ {BTTRC_ID_STK_SDP, BTTRC_ID_STK_SDP, SDP_SetTraceLevel, "TRC_SDP",
+ DEFAULT_CONF_TRACE_LEVEL},
+ {BTTRC_ID_STK_GATT, BTTRC_ID_STK_GATT, GATT_SetTraceLevel, "TRC_GATT",
+ DEFAULT_CONF_TRACE_LEVEL},
+ {BTTRC_ID_STK_SMP, BTTRC_ID_STK_SMP, SMP_SetTraceLevel, "TRC_SMP",
+ DEFAULT_CONF_TRACE_LEVEL},
+#if (HID_DEV_INCLUDED == TRUE)
+ {BTTRC_ID_STK_HIDD, BTTRC_ID_STK_HIDD, HID_DevSetTraceLevel, "TRC_HID_DEV",
+ DEFAULT_CONF_TRACE_LEVEL},
+#endif
+
+ /* LayerIDs for BTA, currently everything maps onto appl_trace_level.
+ */
+ {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTAPP_SetTraceLevel, "TRC_BTAPP",
+ DEFAULT_CONF_TRACE_LEVEL},
+ {BTTRC_ID_BTA_ACC, BTTRC_ID_BTAPP, BTIF_SetTraceLevel, "TRC_BTIF",
+ DEFAULT_CONF_TRACE_LEVEL},
+
+ {0, 0, NULL, NULL, DEFAULT_CONF_TRACE_LEVEL}};
+
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
+ static char buffer[BTE_LOG_BUF_SIZE];
+ int trace_layer = TRACE_GET_LAYER(trace_set_mask);
+ if (trace_layer >= TRACE_LAYER_MAX_NUM) trace_layer = 0;
+
+ va_list ap;
+ va_start(ap, fmt_str);
+ vsnprintf(&buffer[MSG_BUFFER_OFFSET], BTE_LOG_MAX_SIZE, fmt_str, ap);
+ va_end(ap);
+
+ switch (TRACE_GET_TYPE(trace_set_mask)) {
+ case TRACE_TYPE_ERROR:
+ LOG_ERROR(bt_layer_tags[trace_layer], "%s", buffer);
+ break;
+ case TRACE_TYPE_WARNING:
+ LOG_WARN(bt_layer_tags[trace_layer], "%s", buffer);
+ break;
+ case TRACE_TYPE_API:
+ case TRACE_TYPE_EVENT:
+ LOG_INFO(bt_layer_tags[trace_layer], "%s", buffer);
+ break;
+ case TRACE_TYPE_DEBUG:
+ LOG_DEBUG(bt_layer_tags[trace_layer], "%s", buffer);
+ break;
+ default:
+ /* we should never get this */
+ LOG_ERROR(bt_layer_tags[trace_layer], "!BAD TRACE TYPE! %s", buffer);
+ CHECK(TRACE_GET_TYPE(trace_set_mask) == TRACE_TYPE_ERROR);
+ break;
+ }
+}
+
+/* this function should go into BTAPP_DM for example */
+static uint8_t BTAPP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) appl_trace_level = new_level;
+
+ return appl_trace_level;
+}
+
+static uint8_t BTIF_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) btif_trace_level = new_level;
+
+ return btif_trace_level;
+}
+
+static uint8_t BTU_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) btu_trace_level = new_level;
+
+ return btu_trace_level;
+}
+
+static void load_levels_from_config(const config_t* config) {
+ CHECK(config != NULL);
+
+ for (tBTTRC_FUNC_MAP* functions = &bttrc_set_level_map[0];
+ functions->trc_name; ++functions) {
+ int value =
+ config_get_int(config, CONFIG_DEFAULT_SECTION, functions->trc_name, -1);
+ if (value != -1) functions->trace_level = value;
+
+ if (functions->p_f) functions->p_f(functions->trace_level);
+ }
+}
+
+static future_t* init(void) {
+ const stack_config_t* stack_config = stack_config_get_interface();
+ if (!stack_config->get_trace_config_enabled()) {
+ LOG_INFO(LOG_TAG, "using compile default trace settings");
+ return NULL;
+ }
+
+ init_cpp_logging(stack_config->get_all());
+
+ load_levels_from_config(stack_config->get_all());
+ return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t bte_logmsg_module = {
+ .name = BTE_LOGMSG_MODULE,
+ .init = init,
+ .start_up = NULL,
+ .shut_down = NULL,
+ .clean_up = NULL,
+ .dependencies = {STACK_CONFIG_MODULE, NULL}};
diff --git a/mtkbt/code/bt/main/bte_main.cc b/mtkbt/code/bt/main/bte_main.cc
new file mode 100755
index 0000000..e745106
--- a/dev/null
+++ b/mtkbt/code/bt/main/bte_main.cc
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bte_main.cc
+ *
+ * Description: Contains BTE core stack initialization and shutdown code
+ *
+ ******************************************************************************/
+jjjjjjjjjjjjjjjjjjjjjj
+#define LOG_TAG "bt_main"
+
+#include <base/logging.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+
+#include "bt_common.h"
+#include "bt_hci_bdroid.h"
+#include "bt_utils.h"
+#include "bta_api.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btsnoop.h"
+#include "btu.h"
+#include "device/include/interop.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "stack_config.h"
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+#include "mediatek/include/twrite.h"
+#endif
+
+/*******************************************************************************
+ * Constants & Macros
+ ******************************************************************************/
+
+/* Run-time configuration file for BLE*/
+#ifndef BTE_BLE_STACK_CONF_FILE
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+#define BTE_BLE_STACK_CONF_FILE "ble_stack.conf"
+#else // !defined(OS_GENERIC)
+#define BTE_BLE_STACK_CONF_FILE "/etc/bluetooth/ble_stack.conf"
+#endif // defined(OS_GENERIC)
+#endif // BT_BLE_STACK_CONF_FILE
+
+/******************************************************************************
+ * Variables
+ *****************************************************************************/
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static const hci_t* hci;
+
+/*******************************************************************************
+ * Static functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Externs
+ ******************************************************************************/
+fixed_queue_t* btu_hci_msg_queue;
+
+/******************************************************************************
+ *
+ * Function bte_main_boot_entry
+ *
+ * Description BTE MAIN API - Entry point for BTE chip/stack initialization
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_boot_entry(void) {
+ module_init(get_module(INTEROP_MODULE));
+
+ hci = hci_layer_get_interface();
+ if (!hci) {
+ LOG_ERROR(LOG_TAG, "%s could not get hci layer interface.", __func__);
+ return;
+ }
+
+ btu_hci_msg_queue = fixed_queue_new(SIZE_MAX);
+ if (btu_hci_msg_queue == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate hci message queue.", __func__);
+ return;
+ }
+
+ data_dispatcher_register_default(hci->event_dispatcher, btu_hci_msg_queue);
+ hci->set_data_queue(btu_hci_msg_queue);
+
+ module_init(get_module(STACK_CONFIG_MODULE));
+
+}
+
+/******************************************************************************
+ *
+ * Function bte_main_cleanup
+ *
+ * Description BTE MAIN API - Cleanup code for BTE chip/stack
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_cleanup() {
+ data_dispatcher_register_default(hci_layer_get_interface()->event_dispatcher,
+ NULL);
+ hci->set_data_queue(NULL);
+ fixed_queue_free(btu_hci_msg_queue, NULL);
+
+ btu_hci_msg_queue = NULL;
+
+ module_clean_up(get_module(STACK_CONFIG_MODULE));
+
+ module_clean_up(get_module(INTEROP_MODULE));
+}
+
+/******************************************************************************
+ *
+ * Function bte_main_enable
+ *
+ * Description BTE MAIN API - Creates all the BTE tasks. Should be called
+ * part of the Bluetooth stack enable sequence
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_enable() {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ module_start_up(get_module(MTK_BTSNOOP_MODULE));
+#else
+ module_start_up(get_module(BTSNOOP_MODULE));
+#endif
+ module_start_up(get_module(HCI_MODULE));
+
+ BTU_StartUp();
+}
+
+/******************************************************************************
+ *
+ * Function bte_main_disable
+ *
+ * Description BTE MAIN API - Destroys all the BTE tasks. Should be called
+ * part of the Bluetooth stack disable sequence
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_disable(void) {
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ module_shut_down(get_module(HCI_MODULE));
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ module_shut_down(get_module(MTK_BTSNOOP_MODULE));
+#else
+ module_shut_down(get_module(BTSNOOP_MODULE));
+#endif
+
+ BTU_ShutDown();
+}
+
+/******************************************************************************
+ *
+ * Function bte_main_postload_cfg
+ *
+ * Description BTE MAIN API - Stack postload configuration
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_postload_cfg(void) {
+ // TODO(eisenbach): [HIDL] DEPRECATE?
+}
+
+/******************************************************************************
+ *
+ * Function bte_main_hci_send
+ *
+ * Description BTE MAIN API - This function is called by the upper stack to
+ * send an HCI message. The function displays a protocol trace
+ * message (if enabled), and then calls the 'transmit' function
+ * associated with the currently selected HCI transport
+ *
+ * Returns None
+ *
+ *****************************************************************************/
+void bte_main_hci_send(BT_HDR* p_msg, uint16_t event) {
+ uint16_t sub_event = event & BT_SUB_EVT_MASK; /* local controller ID */
+
+ p_msg->event = event;
+
+ if ((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) ||
+ (sub_event == LOCAL_BLE_CONTROLLER_ID)) {
+ hci->transmit_downward(event, p_msg);
+ } else {
+ APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
+ osi_free(p_msg);
+ }
+}
diff --git a/mtkbt/code/bt/main/main_int.h b/mtkbt/code/bt/main/main_int.h
new file mode 100755
index 0000000..3ca01c9
--- a/dev/null
+++ b/mtkbt/code/bt/main/main_int.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef MAIN_INT_H
+#define MAIN_INT_H
+
+#include "osi/include/config.h"
+
+/* Initiates the logging for C++ */
+void init_cpp_logging(config_t* config);
+
+#endif // MAIN_INT_H
diff --git a/mtkbt/code/bt/main/stack_config.cc b/mtkbt/code/bt/main/stack_config.cc
new file mode 100755
index 0000000..9caee3e
--- a/dev/null
+++ b/mtkbt/code/bt/main/stack_config.cc
@@ -0,0 +1,125 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_stack_config"
+
+#include "stack_config.h"
+
+#include <base/logging.h>
+
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+#include "mediatek/include/mtk_stack_config.h"
+using vendor::mediatek::bluetooth::stack::StackConfig;
+#endif
+
+const char* TRACE_CONFIG_ENABLED_KEY = "TraceConf";
+const char* PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
+const char* PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates";
+const char* PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
+const char* PTS_SMP_PAIRING_OPTIONS_KEY = "PTS_SmpOptions";
+const char* PTS_SMP_FAILURE_CASE_KEY = "PTS_SmpFailureCase";
+
+static config_t* config;
+
+// Module lifecycle functions
+
+static future_t* init() {
+// TODO(armansito): Find a better way than searching by a hardcoded path.
+#if defined(OS_GENERIC)
+ const char* path = "bt_stack.conf";
+#else // !defined(OS_GENERIC)
+ const char* path = "/etc/bluetooth/bt_stack.conf";
+#endif // defined(OS_GENERIC)
+ CHECK(path != NULL);
+
+ LOG_INFO(LOG_TAG, "%s attempt to load stack conf from %s", __func__, path);
+
+ config = config_new(path);
+ if (!config) {
+ LOG_INFO(LOG_TAG, "%s file >%s< not found", __func__, path);
+ config = config_new_empty();
+ }
+
+#if defined(MTK_STACK_CONFIG_LOG) && (MTK_STACK_CONFIG_LOG == TRUE)
+ if (StackConfig::GetInstance()->IsNeedOverWriteConfig()) {
+ config = StackConfig::GetInstance()->OverwriteConfig(config);
+ }
+#endif
+
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* clean_up() {
+ config_free(config);
+ config = NULL;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+EXPORT_SYMBOL extern const module_t stack_config_module = {
+ .name = STACK_CONFIG_MODULE,
+ .init = init,
+ .start_up = NULL,
+ .shut_down = NULL,
+ .clean_up = clean_up,
+ .dependencies = {NULL}};
+
+// Interface functions
+static bool get_trace_config_enabled(void) {
+ return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+ TRACE_CONFIG_ENABLED_KEY, false);
+}
+
+static bool get_pts_secure_only_mode(void) {
+ return config_get_bool(config, CONFIG_DEFAULT_SECTION, PTS_SECURE_ONLY_MODE,
+ false);
+}
+
+static bool get_pts_conn_updates_disabled(void) {
+ return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+ PTS_LE_CONN_UPDATED_DISABLED, false);
+}
+
+static bool get_pts_crosskey_sdp_disable(void) {
+ return config_get_bool(config, CONFIG_DEFAULT_SECTION,
+ PTS_DISABLE_SDP_LE_PAIR, false);
+}
+
+static const char* get_pts_smp_options(void) {
+ return config_get_string(config, CONFIG_DEFAULT_SECTION,
+ PTS_SMP_PAIRING_OPTIONS_KEY, NULL);
+}
+
+static int get_pts_smp_failure_case(void) {
+ return config_get_int(config, CONFIG_DEFAULT_SECTION,
+ PTS_SMP_FAILURE_CASE_KEY, 0);
+}
+
+static config_t* get_all(void) { return config; }
+
+const stack_config_t interface = {get_trace_config_enabled,
+ get_pts_secure_only_mode,
+ get_pts_conn_updates_disabled,
+ get_pts_crosskey_sdp_disable,
+ get_pts_smp_options,
+ get_pts_smp_failure_case,
+ get_all};
+
+const stack_config_t* stack_config_get_interface(void) { return &interface; }
diff --git a/mtkbt/code/bt/mediatek/Android.bp b/mtkbt/code/bt/mediatek/Android.bp
new file mode 100755
index 0000000..3db06d3
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/Android.bp
@@ -0,0 +1,26 @@
+// mediatek static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-mtk_cust",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: ["include"],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+
+ srcs: [
+ "config/log_mode.cc",
+ "config/log_time.cc",
+ "config/mtk_stack_config.cc",
+ "gatt/gatts_mtk.cc",
+ "hci/fw_logger_filter.cc",
+ "hci/fw_logger_switch.cc",
+ "hci/hci_inbound_data_monitor.cc",
+ "hci/twrite.cc",
+ "interop/interop_mtk.cc",
+ ],
+}
diff --git a/mtkbt/code/bt/mediatek/Android.mk b/mtkbt/code/bt/mediatek/Android.mk
new file mode 100755
index 0000000..5053e7d
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mtkbt/code/bt/mediatek/BUILD.gn b/mtkbt/code/bt/mediatek/BUILD.gn
new file mode 100755
index 0000000..1a50639
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/BUILD.gn
@@ -0,0 +1,21 @@
+static_library("libbt-mtk_cust") {
+ sources = [
+ "config/log_mode.cc",
+ "config/log_time.cc",
+ "config/mtk_stack_config.cc",
+ "hci/fw_logger_filter.cc",
+ "hci/fw_logger_switch.cc",
+ "hci/hci_inbound_data_monitor.cc",
+ "hci/twrite.cc",
+ "interop/interop_mtk.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//include",
+ "//btcore/include",
+ "//hci/include",
+ "//stack/include",
+ ]
+}
diff --git a/mtkbt/code/bt/mediatek/conf/Android.mk b/mtkbt/code/bt/mediatek/conf/Android.mk
new file mode 100755
index 0000000..1511860
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/conf/Android.mk
@@ -0,0 +1,23 @@
+# Cannot convert to Android.bp as resource copying has not
+# yet implemented for soong as of 12/16/2016
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth stack conf file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := mtk_bt_stack.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+# Bluetooth controller conf file
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := mtk_bt_fw.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/bluetooth
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT) \ No newline at end of file
diff --git a/mtkbt/code/bt/mediatek/conf/mtk_bt_fw.conf b/mtkbt/code/bt/mediatek/conf/mtk_bt_fw.conf
new file mode 100755
index 0000000..0c65fe9
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/conf/mtk_bt_fw.conf
@@ -0,0 +1,84 @@
+#
+# Control FW Log
+#
+
+[MtkBtFwLogOff]
+# FCBE switch
+# Ex. Disable FWlog to set C1 = 01 BE FC 01 00 / Enable FWlog to set C1 = 01 BE FC 01 05
+C1 = 01 BE FC 01 00
+# FC5F filter
+C2 = 01 5F FC 2A 50 01 09 00 00 00
+# FC5F group filter bitmap
+# SYS
+C201 = 00 00 00 00
+# TIM
+C202 = 00 00 00 00
+# PKV
+C203 = 00 00 00 00
+# LC
+C204 = 00 00 00 00
+# LL
+C205 = 00 00 00 00
+# ANT
+C206 = 00 00 00 00
+# LMP
+C207 = 00 00 00 00
+# CO
+C208 = 00 00 00 00
+# VOICE
+C209 = 00 00 00 00
+
+
+[MtkBtFwLogSqc]
+
+# FCBE switch - Disable
+# Ex. Disable FWlog to set C1 = 01 BE FC 01 00 / Enable FWlog to set C1 = 01 BE FC 01 05
+C1 = 01 BE FC 01 05
+# FC5F filter
+C2 = 01 5F FC 2A 50 01 09 00 00 00
+# FC5F group filter bitmap
+# SYS
+C201 = 00 00 00 88
+# TIM
+C202 = 00 00 00 00
+# PKV
+C203 = 00 00 00 00
+# LC
+C204 = 00 00 00 00
+# LL
+C205 = 00 00 00 00
+# ANT
+C206 = 00 00 00 00
+# LMP
+C207 = 00 00 00 00
+# CO
+C208 = 00 00 00 00
+# VOICE
+C209 = 00 00 00 00
+
+[MtkBtFwLogDebug]
+
+# FCBE switch - Enable
+# Ex. Disable FWlog to set C1 = 01 BE FC 01 00 / Enable FWlog to set C1 = 01 BE FC 01 05
+C1 = 01 BE FC 01 05
+# FC5F filter
+C2 = 01 5F FC 2A 50 01 09 00 00 00
+# FC5F group filter bitmap
+# SYS
+C201 = 00 00 00 CC
+# TIM
+C202 = 00 00 00 00
+# PKV
+C203 = 00 00 00 00
+# LC
+C204 = 1F F0 00 00
+# LL
+C205 = 07 27 06 00
+# ANT
+C206 = 00 00 00 00
+# LMP
+C207 = 03 00 03 00
+# CO
+C208 = 03 08 00 00
+# VOICE
+C209 = 00 00 00 00 \ No newline at end of file
diff --git a/mtkbt/code/bt/mediatek/conf/mtk_bt_stack.conf b/mtkbt/code/bt/mediatek/conf/mtk_bt_stack.conf
new file mode 100755
index 0000000..958648f
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/conf/mtk_bt_stack.conf
@@ -0,0 +1,33 @@
+# Enable trace level reconfiguration function
+# Must be present before any TRC_ trace level settings
+TraceConf=true
+
+# Trace level configuration
+# BT_TRACE_LEVEL_NONE 0 ( No trace messages to be generated )
+# BT_TRACE_LEVEL_ERROR 1 ( Error condition trace messages )
+# BT_TRACE_LEVEL_WARNING 2 ( Warning condition trace messages )
+# BT_TRACE_LEVEL_API 3 ( API traces )
+# BT_TRACE_LEVEL_EVENT 4 ( Debug messages for events )
+# BT_TRACE_LEVEL_DEBUG 5 ( Full debug messages )
+# BT_TRACE_LEVEL_VERBOSE 6 ( Verbose messages ) - Currently supported for TRC_BTAPP only.
+TRC_BTM=6
+TRC_HCI=6
+TRC_L2CAP=6
+TRC_RFCOMM=6
+TRC_OBEX=6
+TRC_AVCT=6
+TRC_AVDT=6
+TRC_AVRC=6
+TRC_AVDT_SCB=6
+TRC_AVDT_CCB=6
+TRC_A2D=6
+TRC_SDP=6
+TRC_GATT=6
+TRC_SMP=6
+TRC_BTAPP=6
+TRC_BTIF=6
+TRC_GAP=6
+TRC_BNEP=6
+TRC_PAN=6
+TRC_HID_HOST=6
+TRC_HID_DEV=6
diff --git a/mtkbt/code/bt/mediatek/config/log_mode.cc b/mtkbt/code/bt/mediatek/config/log_mode.cc
new file mode 100755
index 0000000..a499f55
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/config/log_mode.cc
@@ -0,0 +1,195 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_logmode"
+
+#include "log_mode.h"
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/memory/singleton.h>
+
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class LevelChecker {
+ public:
+ explicit LevelChecker(const std::string& key)
+ : kEngBuild_("eng"), kUserDebugBuild_("userdebug"), key_(key) {}
+ virtual ~LevelChecker() {}
+
+ virtual TraceLevel Check() = 0;
+
+ protected:
+ bool IsPropertySet() {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ if (osi_property_get(key_.c_str(), value, "")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ TraceLevel ParseSysPropertyTestMode() {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(key_.c_str(), value, "");
+ std::string test_mode = std::string(value);
+ std::transform(test_mode.begin(), test_mode.end(), test_mode.begin(),
+ ::tolower);
+ TraceLevel level = TraceLevel::kDefault;
+ if (std::string("debug") == test_mode) {
+ level = TraceLevel::kDebug;
+ } else if (std::string("sqc") == test_mode) {
+ level = TraceLevel::kSqc;
+ }
+ return level;
+ }
+
+ std::string GetBuildType() const {
+ const std::string kBuildTypeKey("ro.build.type");
+ char value[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(kBuildTypeKey.c_str(), value, "");
+ return std::string(value);
+ }
+
+ const std::string kEngBuild_;
+ const std::string kUserDebugBuild_;
+
+ private:
+ const std::string key_;
+};
+
+class StackLevelChecker : public LevelChecker {
+ public:
+ StackLevelChecker()
+ : LevelChecker(std::string("persist.bluetooth.hostloglevel")) {}
+ virtual ~StackLevelChecker() {}
+
+ TraceLevel Check() override {
+ if (IsPropertySet()) {
+ return ParseSysPropertyTestMode();
+ } else {
+ // LOG_INFO(LOG_TAG, "%s apply default setting by build", __func__);
+ // return GetTraceLevelByBuild();
+ return TraceLevel::kDefault;
+ }
+ }
+};
+
+class ControllerLevelChecker : public LevelChecker {
+ public:
+ ControllerLevelChecker()
+ : LevelChecker(std::string("persist.bluetooth.fwloglevel")) {}
+ virtual ~ControllerLevelChecker() {}
+
+ TraceLevel Check() override {
+ if (IsPropertySet()) {
+ return ParseSysPropertyTestMode();
+ } else {
+ // LOG_INFO(LOG_TAG, "%s apply default setting by build", __func__);
+ // return GetTraceLevelByBuild();
+ // To align with Android N, do not turn on if without setting
+ return TraceLevel::kDefault;
+ }
+ }
+#if 0
+ private:
+ TraceLevel GetTraceLevelByBuild() const {
+ return (LevelChecker::kEngBuild_ == GetBuildType()) ||
+ (LevelChecker::kUserDebugBuild_ == GetBuildType())
+ ? TraceLevel::kSqc
+ : TraceLevel::kDefault;
+ }
+#endif
+};
+
+class LogLevelImpl {
+ public:
+ LogLevelImpl()
+ : trace_level_names_{std::string("Default"), std::string("SQC"),
+ std::string("Debug"), std::string("Unknown")} {}
+ ~LogLevelImpl() = default;
+
+ TraceLevel QueryTraceLevel(TraceType type) {
+ std::unique_ptr<LevelChecker> checker;
+ TraceLevel level = kDefault;
+ switch (type) {
+ case kStack: {
+ checker = std::unique_ptr<LevelChecker>(new StackLevelChecker());
+ level = checker->Check();
+ break;
+ }
+ case kController: {
+ checker = std::unique_ptr<LevelChecker>(new ControllerLevelChecker());
+ level = checker->Check();
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("%s: unknown trace type: %d", __func__, type);
+ }
+ return level;
+ }
+
+ std::string GetTraceLevelName(TraceLevel level) const {
+ return trace_level_names_[level];
+ }
+
+ private:
+ std::vector<std::string> trace_level_names_;
+};
+
+LogLevel::LogLevel() : logmode_impl_(new LogLevelImpl()) {}
+
+LogLevel* LogLevel::GetInstance() { return base::Singleton<LogLevel>::get(); }
+
+TraceLevel LogLevel::QueryTraceLevel(TraceType type) {
+ return logmode_impl_->QueryTraceLevel(type);
+}
+
+std::string LogLevel::GetTraceLevelName(TraceLevel level) const {
+ return logmode_impl_->GetTraceLevelName(level);
+}
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/config/log_time.cc b/mtkbt/code/bt/mediatek/config/log_time.cc
new file mode 100755
index 0000000..568aa70
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/config/log_time.cc
@@ -0,0 +1,99 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_logtime"
+
+#include "log_time.h"
+
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <string>
+
+#include <base/memory/singleton.h>
+
+#include "osi/include/time.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class LogTimeImpl {
+ public:
+ LogTimeImpl() : kBTSnoopEpochDelta_(0x00dcddb30f2f8000ULL) {}
+ ~LogTimeImpl() = default;
+
+ uint64_t GetEpochTime() const {
+ return HToLL(time_gettimeofday_us() + kBTSnoopEpochDelta_);
+ }
+
+ std::string GetLogTimeTag() const {
+ // TODO(Peng): To implement with C++ template function
+ char curtime[64] = {0};
+ struct tm* tmp = NULL;
+ time_t lt;
+ /* get current time */
+ lt = time(NULL);
+ tmp = localtime(&lt);
+ strftime(curtime, sizeof(curtime), "%Y_%m%d_%H%M%S", tmp);
+ return std::string(curtime);
+ }
+
+ private:
+ uint64_t HToLL(uint64_t ll) const {
+ const uint32_t l = 1;
+ if (*(reinterpret_cast<const uint8_t*>(&l)) == 1)
+ return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 |
+ htonl(ll >> 32);
+ return ll;
+ }
+
+ const uint64_t kBTSnoopEpochDelta_;
+};
+
+LogTime::LogTime() : logtime_impl_(new LogTimeImpl()) {}
+
+LogTime* LogTime::GetInstance() { return base::Singleton<LogTime>::get(); }
+
+uint64_t LogTime::GetEpochTime() const { return logtime_impl_->GetEpochTime(); }
+
+std::string LogTime::GetLogTimeTag() const {
+ return logtime_impl_->GetLogTimeTag();
+}
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/config/mtk_stack_config.cc b/mtkbt/code/bt/mediatek/config/mtk_stack_config.cc
new file mode 100755
index 0000000..cdbde2b
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/config/mtk_stack_config.cc
@@ -0,0 +1,490 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_mtk_stack_config"
+
+#include "mtk_stack_config.h"
+
+#include <stdint.h>
+#include <unistd.h> // access()
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/memory/singleton.h>
+
+#include "hci_internals.h"
+#include "log_mode.h"
+#include "mtk_util.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+static const std::string kPath("/etc/bluetooth/");
+static const std::string kStackConf("mtk_bt_stack.conf");
+static const std::string kControllerConf("mtk_bt_fw.conf");
+
+class StackConfigParser {
+ public:
+ StackConfigParser() : kMtkBtStackConf_(kPath + kStackConf) {
+ stack_trace_["TRC_BTM"] = 0;
+ stack_trace_["TRC_HCI"] = 0;
+ stack_trace_["TRC_L2CAP"] = 0;
+ stack_trace_["TRC_RFCOMM"] = 0;
+ stack_trace_["TRC_OBEX"] = 0;
+ stack_trace_["TRC_AVCT"] = 0;
+ stack_trace_["TRC_AVDT"] = 0;
+ stack_trace_["TRC_AVRC"] = 0;
+ stack_trace_["TRC_AVDT_SCB"] = 0;
+ stack_trace_["TRC_AVDT_CCB"] = 0;
+ stack_trace_["TRC_A2D"] = 0;
+ stack_trace_["TRC_SDP"] = 0;
+ stack_trace_["TRC_GATT"] = 0;
+ stack_trace_["TRC_SMP"] = 0;
+ stack_trace_["TRC_BTAPP"] = 0;
+ stack_trace_["TRC_BTIF"] = 0;
+ stack_trace_["TRC_GAP"] = 0;
+ stack_trace_["TRC_BNEP"] = 0;
+ stack_trace_["TRC_PAN"] = 0;
+ stack_trace_["TRC_HID_HOST"] = 0;
+ stack_trace_["TRC_HID_DEV"] = 0;
+ }
+
+ config_t* OverwriteConfig(config_t* config) {
+ CHECK(config != NULL);
+ config_t* mtk_config = config_new(kMtkBtStackConf_.c_str());
+ if (!mtk_config) {
+ LOG_ERROR(LOG_TAG, "%s file %s not found!", __func__,
+ kMtkBtStackConf_.c_str());
+ } else {
+ for (auto& it : stack_trace_) {
+ if (config_has_key(config, CONFIG_DEFAULT_SECTION, it.first.c_str()) &&
+ config_has_key(mtk_config, CONFIG_DEFAULT_SECTION,
+ it.first.c_str())) {
+ it.second = config_get_int(mtk_config, CONFIG_DEFAULT_SECTION,
+ it.first.c_str(), it.second);
+ config_set_int(config, CONFIG_DEFAULT_SECTION, it.first.c_str(),
+ it.second);
+ LOG_INFO(LOG_TAG, "%s Overwrite: %s = %d", __func__, it.first.c_str(),
+ it.second);
+ }
+ }
+ }
+ return config;
+ }
+
+ private:
+ const std::string kMtkBtStackConf_;
+ std::map<std::string, int> stack_trace_;
+};
+
+class ControllerLogModeParser {
+ public:
+ explicit ControllerLogModeParser(TraceLevel level) : trace_level_(level) {}
+ virtual ~ControllerLogModeParser() {}
+
+ virtual std::vector<uint8_t> GetEnableCommandPacket() const = 0;
+ virtual std::vector<uint8_t> GetFilterommandPacket() const = 0;
+
+ protected:
+ TraceLevel GetTraceLevel() const { return trace_level_; }
+
+ private:
+ TraceLevel trace_level_;
+};
+
+class ControllerLogModeDefaultParser : public ControllerLogModeParser {
+ public:
+ explicit ControllerLogModeDefaultParser(TraceLevel level)
+ : ControllerLogModeParser(level) {
+ InitEnableCmdPackets();
+ InitFilterCmdPackets();
+ }
+ virtual ~ControllerLogModeDefaultParser() {}
+
+ std::vector<uint8_t> GetEnableCommandPacket() const override {
+ return enable_cmd_packets_[GetTraceLevel()];
+ }
+
+ std::vector<uint8_t> GetFilterommandPacket() const override {
+ return filter_cmd_packets_[GetTraceLevel()];
+ }
+
+ private:
+ void InitEnableCmdPackets() {
+ // kDefault
+ enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x00});
+ // kSqc
+ enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x05});
+ // kDebug
+ enable_cmd_packets_.push_back(std::vector<uint8_t>{0xBE, 0xFC, 0x01, 0x05});
+ }
+
+ void InitFilterCmdPackets() {
+ // kDefault
+ filter_cmd_packets_.push_back(std::vector<uint8_t>{
+ // C2 FC5F filter
+ 0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00,
+ // C201 SYS
+ 0x00, 0x00, 0x00, 0x00,
+ // C202 TIM
+ 0x00, 0x00, 0x00, 0x00,
+ // C203 PKV
+ 0x00, 0x00, 0x00, 0x00,
+ // C204 LC
+ 0x00, 0x00, 0x00, 0x00,
+ // C205 LL
+ 0x00, 0x00, 0x00, 0x00,
+ // C206 ANT
+ 0x00, 0x00, 0x00, 0x00,
+ // C207 LMP
+ 0x00, 0x00, 0x00, 0x00,
+ // C208 CO
+ 0x00, 0x00, 0x00, 0x00,
+ // C209 VOICE
+ 0x00, 0x00, 0x00, 0x00});
+ // kSqc
+ filter_cmd_packets_.push_back(std::vector<uint8_t>{
+ // C2 FC5F filter
+ 0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00,
+ // C201 SYS
+ 0x00, 0x00, 0x00, 0x88,
+ // C202 TIM
+ 0x00, 0x00, 0x00, 0x00,
+ // C203 PKV
+ 0x00, 0x00, 0x00, 0x00,
+ // C204 LC
+ 0x00, 0x00, 0x00, 0x00,
+ // C205 LL
+ 0x00, 0x00, 0x00, 0x00,
+ // C206 ANT
+ 0x00, 0x00, 0x00, 0x00,
+ // C207 LMP
+ 0x00, 0x00, 0x00, 0x00,
+ // C208 CO
+ 0x00, 0x00, 0x00, 0x00,
+ // C209 VOICE
+ 0x00, 0x00, 0x00, 0x00});
+
+ // kDebug
+ filter_cmd_packets_.push_back(std::vector<uint8_t>{
+ // C2 FC5F filter
+ 0x5F, 0xFC, 0x2A, 0x50, 0x01, 0x09, 0x00, 0x00, 0x00,
+ // C201 SYS
+ 0x00, 0x00, 0x00, 0xCC,
+ // C202 TIM
+ 0x00, 0x00, 0x00, 0x00,
+ // C203 PKV
+ 0x00, 0x00, 0x00, 0x00,
+ // C204 LC
+ 0x1F, 0xF0, 0x00, 0x00,
+ // C205 LL
+ 0x07, 0x27, 0x06, 0x00,
+ // C206 ANT
+ 0x00, 0x00, 0x00, 0x00,
+ // C207 LMP
+ 0x03, 0x00, 0x03, 0x00,
+ // C208 CO
+ 0x03, 0x08, 0x00, 0x00,
+ // C209 VOICE
+ 0x00, 0x00, 0x00, 0x00});
+ }
+
+ std::vector<std::vector<uint8_t> > enable_cmd_packets_;
+ std::vector<std::vector<uint8_t> > filter_cmd_packets_;
+};
+
+class ControllerLogModeConfParser : public ControllerLogModeParser {
+ public:
+ explicit ControllerLogModeConfParser(TraceLevel level)
+ : ControllerLogModeParser(level), kSerialTypeLen_(1) {
+ InitSections();
+ InitConfig();
+ }
+ virtual ~ControllerLogModeConfParser() {
+ if (config_) {
+ config_free(config_);
+ }
+ }
+
+ std::vector<uint8_t> GetEnableCommandPacket() const override {
+ return LoadEnableCommandData(GetTraceLevel());
+ }
+
+ std::vector<uint8_t> GetFilterommandPacket() const override {
+ return LoadFilterCommandData(GetTraceLevel());
+ }
+
+ private:
+ void InitSections() {
+ sections_[kDefault] = std::string("MtkBtFwLogOff");
+ sections_[kSqc] = std::string("MtkBtFwLogSqc");
+ sections_[kDebug] = std::string("MtkBtFwLogDebug");
+ }
+
+ void InitConfig() {
+ config_ = config_new(std::string(kPath + kControllerConf).c_str());
+ CHECK(config_ != NULL);
+ }
+
+ std::vector<uint8_t> LoadEnableCommandData(TraceLevel level) const {
+ const std::string kEnableCmdKey("C1");
+ std::string cmd_temp(config_get_string(config_, sections_.at(level).c_str(),
+ kEnableCmdKey.c_str(), NULL));
+ std::vector<uint8_t> cmd_data = ConvertCmdStringToData(cmd_temp);
+ std::vector<uint8_t> enable_cmd;
+ // Skip to add serial type bit
+ std::copy(cmd_data.begin() + kSerialTypeLen_, cmd_data.end(),
+ std::back_inserter(enable_cmd));
+ return enable_cmd;
+ }
+
+ std::vector<uint8_t> LoadFilterCommandData(TraceLevel level) const {
+ const std::string kFilterCmdKey("C2");
+ constexpr int kC2NumOfRows(10);
+ std::string cmd_temp(config_get_string(config_, sections_.at(level).c_str(),
+ kFilterCmdKey.c_str(), NULL));
+ for (int i(1); i < kC2NumOfRows; i++) {
+ std::stringstream ss;
+ ss << kFilterCmdKey << std::setfill('0') << std::setw(2) << i;
+ std::string cmdx(config_get_string(config_, sections_.at(level).c_str(),
+ ss.str().c_str(), NULL));
+ cmd_temp += std::string(" ") + cmdx;
+ }
+ std::vector<uint8_t> cmd_data = ConvertCmdStringToData(cmd_temp);
+ std::vector<uint8_t> filter_cmd;
+ // Skip to add serial type bit
+ std::copy(cmd_data.begin() + kSerialTypeLen_, cmd_data.end(),
+ std::back_inserter(filter_cmd));
+ return filter_cmd;
+ }
+
+ static uint8_t StringToUInt8(const std::string& str) {
+ return static_cast<uint8_t>(std::stoi(str, nullptr, 16));
+ }
+
+ std::vector<uint8_t> ConvertCmdStringToData(const std::string& cmd) const {
+ std::istringstream iss(cmd);
+ std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
+ std::istream_iterator<std::string>{}};
+ std::vector<uint8_t> data(tokens.size(), 0);
+ std::transform(tokens.begin(), tokens.end(), data.begin(), StringToUInt8);
+ return data;
+ }
+
+ const int kSerialTypeLen_;
+
+ config_t* config_;
+ std::map<TraceLevel, std::string> sections_;
+};
+
+class ControllerLogModeFactory : public Singleton<ControllerLogModeFactory> {
+ public:
+ std::shared_ptr<ControllerLogModeParser> Create(TraceLevel level);
+
+ private:
+ friend class Singleton<ControllerLogModeFactory>;
+};
+
+std::shared_ptr<ControllerLogModeParser> ControllerLogModeFactory::Create(
+ TraceLevel level) {
+ if (access(std::string(kPath + kControllerConf).c_str(), F_OK)) {
+ return std::shared_ptr<ControllerLogModeParser>(
+ new ControllerLogModeDefaultParser(level));
+ } else {
+ return std::shared_ptr<ControllerLogModeParser>(
+ new ControllerLogModeConfParser(level));
+ }
+}
+
+class BTStackLogConfig : public Singleton<BTStackLogConfig> {
+ public:
+ bool IsNeedOverWriteConfig() const {
+ TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack);
+ return (kDebug == level) || (kSqc == level);
+ }
+
+ bool IsBTSnoopEnabled() const {
+ if (isPropertySet(kBTSnoopEnableProperty_.c_str())) {
+ return IsBTSnoopFeatureEnabled(kBTSnoopEnableProperty_.c_str());
+ } else {
+ TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack);
+ return (kDebug == level) || (kSqc == level);
+ }
+ }
+
+ bool IsBTSnoopSaveLastEnabled() const {
+ if (isPropertySet(kBTSnoopShouldSaveLastProperty_.c_str())) {
+ return IsBTSnoopFeatureEnabled(kBTSnoopShouldSaveLastProperty_.c_str());
+ } else {
+ TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kStack);
+ return (kDebug == level) || (kSqc == level);
+ }
+ }
+
+ bool IsInboundDataMonitorEnabled() const {
+ if (isPropertySet(kBTForceTurnOffInboundDataMonitorProperty_.c_str())) {
+ return !IsBTSnoopFeatureEnabled(
+ kBTForceTurnOffInboundDataMonitorProperty_.c_str());
+ } else {
+ return IsBTSnoopEnabled();
+ }
+ }
+
+ private:
+ BTStackLogConfig()
+ : kBTSnoopEnableProperty_("persist.bluetooth.btsnoopenable"),
+ kBTSnoopShouldSaveLastProperty_("persist.bluetooth.btsnoopsavelast"),
+ kBTForceTurnOffInboundDataMonitorProperty_("persist.bluetooth.offmonitor") {}
+
+ bool isPropertySet(const std::string& key) const {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ if (osi_property_get(key.c_str(), value, "")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool IsBTSnoopFeatureEnabled(const char* key) const {
+ char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(key, btsnoop_enabled, "false");
+ return std::string(btsnoop_enabled) == std::string("true");
+ }
+
+ friend class Singleton<BTStackLogConfig>;
+
+ const std::string kBTSnoopEnableProperty_;
+ const std::string kBTSnoopShouldSaveLastProperty_;
+ const std::string kBTForceTurnOffInboundDataMonitorProperty_;
+};
+
+class StackConfigImpl {
+ public:
+ StackConfigImpl() = default;
+ ~StackConfigImpl() = default;
+
+ bool IsNeedOverWriteConfig() const {
+ return BTStackLogConfig::GetInstance()->IsNeedOverWriteConfig();
+ }
+
+ config_t* OverwriteConfig(config_t* config) {
+ std::unique_ptr<StackConfigParser> config_parse(new StackConfigParser);
+ return config_parse->OverwriteConfig(config);
+ }
+
+ const std::shared_ptr<ControllerLogModeParser> LoadFWLogModeParser(
+ TraceLevel level) {
+ return ControllerLogModeFactory::GetInstance()->Create(level);
+ }
+
+ std::vector<uint8_t> GetFWLogEnableCommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser) {
+ return parser->GetEnableCommandPacket();
+ }
+
+ std::vector<uint8_t> GetFWLogFilterommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser) {
+ return parser->GetFilterommandPacket();
+ }
+
+ bool IsBTSnoopEnabled() const {
+ return BTStackLogConfig::GetInstance()->IsBTSnoopEnabled();
+ }
+
+ bool IsBTSnoopSaveLastEnabled() const {
+ return BTStackLogConfig::GetInstance()->IsBTSnoopSaveLastEnabled();
+ }
+
+ bool IsInboundDataMonitorEnabled() const {
+ return BTStackLogConfig::GetInstance()->IsInboundDataMonitorEnabled();
+ }
+};
+
+StackConfig::StackConfig() : config_impl_(new StackConfigImpl()) {}
+
+StackConfig* StackConfig::GetInstance() {
+ return base::Singleton<StackConfig>::get();
+}
+
+bool StackConfig::IsNeedOverWriteConfig() const {
+ return config_impl_->IsNeedOverWriteConfig();
+}
+
+config_t* StackConfig::OverwriteConfig(config_t* config) {
+ return config_impl_->OverwriteConfig(config);
+}
+
+const std::shared_ptr<ControllerLogModeParser> StackConfig::LoadFWLogModeParser(
+ TraceLevel level) {
+ return config_impl_->LoadFWLogModeParser(level);
+}
+
+std::vector<uint8_t> StackConfig::GetFWLogEnableCommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser) {
+ return config_impl_->GetFWLogEnableCommandPacket(parser);
+}
+
+std::vector<uint8_t> StackConfig::GetFWLogFilterommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser) {
+ return config_impl_->GetFWLogFilterommandPacket(parser);
+}
+
+bool StackConfig::IsBTSnoopEnabled() const {
+ return config_impl_->IsBTSnoopEnabled();
+}
+
+bool StackConfig::IsBTSnoopSaveLastEnabled() const {
+ return config_impl_->IsBTSnoopSaveLastEnabled();
+}
+
+bool StackConfig::IsInboundDataMonitorEnabled() const {
+ return config_impl_->IsInboundDataMonitorEnabled();
+}
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/gatt/gatts_mtk.cc b/mtkbt/code/bt/mediatek/gatt/gatts_mtk.cc
new file mode 100755
index 0000000..6dcc5c9
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/gatt/gatts_mtk.cc
@@ -0,0 +1,110 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#include "gatts_mtk.h"
+#include "btcore/include/bdaddr.h"
+#include "btif/include/btif_config.h"
+#include "osi/include/osi.h"
+#include "stack/btm/btm_ble_int.h"
+#include "stack/gatt/gatt_int.h"
+
+/*****************************************************************************
+ * Local type definitions
+ ****************************************************************************/
+#define BTIF_STORAGE_PATH_SERVICE_CHANGE "SrvChgInd"
+
+/*****************************************************************************
+ * Static variables
+ ****************************************************************************/
+static uint16_t clt_cfg_hdl;
+
+/*****************************************************************************
+ * Externally called functions
+ ****************************************************************************/
+void gatts_srv_chg_set_cccd_handle(uint16_t handle) { clt_cfg_hdl = handle; }
+
+bool gatts_srv_chg_ind_get(BD_ADDR bda) {
+ bdstr_t bdstr;
+ sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2],
+ bda[3], bda[4], bda[5]);
+
+ int clt_cfg = 0;
+ if (!btif_config_get_int(bdstr, BTIF_STORAGE_PATH_SERVICE_CHANGE, &clt_cfg) ||
+ !clt_cfg)
+ return false;
+ return true;
+}
+
+void gatts_srv_chg_ind_set(BD_ADDR bda, bool ind) {
+ bdstr_t bdstr;
+ sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2],
+ bda[3], bda[4], bda[5]);
+
+ btif_config_set_int(bdstr, BTIF_STORAGE_PATH_SERVICE_CHANGE, ind ? 1 : 0);
+}
+
+tGATT_STATUS gatts_srv_chg_proc_write_req(BD_ADDR bda,
+ tGATT_WRITE_REQ* p_data) {
+ if (p_data == NULL) return GATT_ERROR;
+
+ if (p_data->handle != clt_cfg_hdl) return GATT_INVALID_HANDLE;
+
+ if (p_data->len == sizeof(tGATT_CLT_CHAR_CONFIG)) {
+ tGATT_CLT_CHAR_CONFIG ind_value = 0x00;
+ uint8_t* p = p_data->value;
+ STREAM_TO_UINT16(ind_value, p);
+ GATT_TRACE_EVENT("%s, Srv Chg Ind? %d", __func__,
+ ind_value & GATT_CLT_CONFIG_INDICATION);
+ if (ind_value & GATT_CLT_CONFIG_INDICATION) {
+ tGATTS_SRV_CHG srv_chg_clt;
+ memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
+ srv_chg_clt.srv_changed = false;
+ if (gatt_is_bda_in_the_srv_chg_clt_list(bda) != NULL ||
+ gatt_add_srv_chg_clt(&srv_chg_clt) != NULL) {
+ if (btm_sec_is_a_bonded_dev(bda)) {
+ gatts_srv_chg_ind_set(bda, true);
+ }
+ }
+ return GATT_SUCCESS;
+ } else {
+ gatt_delete_dev_from_srv_chg_clt_list(bda);
+ if (btm_sec_is_a_bonded_dev(bda)) {
+ gatts_srv_chg_ind_set(bda, false);
+ }
+ return GATT_SUCCESS;
+ }
+ }
+ return GATT_INVALID_PDU;
+}
diff --git a/mtkbt/code/bt/mediatek/hci/fw_logger_filter.cc b/mtkbt/code/bt/mediatek/hci/fw_logger_filter.cc
new file mode 100755
index 0000000..916d80e
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/hci/fw_logger_filter.cc
@@ -0,0 +1,105 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_fw_logger_filter"
+
+#include "fw_logger_filter.h"
+
+#include <base/logging.h>
+#include <base/memory/singleton.h>
+
+#include "bt_types.h"
+#include "osi/include/allocator.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class FWLogFilterImpl {
+ public:
+ FWLogFilterImpl() {}
+ ~FWLogFilterImpl() = default;
+
+ bool IsFWLogEvent(const BT_HDR* packet) const {
+ CHECK(packet != NULL);
+ const uint8_t* stream = packet->data;
+ return IsFWLogData(stream);
+ }
+
+ bool Intercepted(BT_HDR* packet) const {
+ CHECK(packet != NULL);
+ const uint8_t* stream = packet->data;
+ if (IsFWLogData(stream)) {
+ osi_free(packet);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ bool IsFWLogData(const uint8_t* data) const {
+ const uint8_t FW_EVENT_CODE = 0xFF;
+ const uint8_t FW_SUB_EVENT_CODE = 0x50;
+ uint8_t event_code = 0;
+ uint8_t subevent_code = 0;
+ STREAM_TO_UINT8(event_code, data);
+ STREAM_SKIP_UINT8(data); // Skip the parameter total length field
+ STREAM_TO_UINT8(subevent_code, data);
+ // LOG_INFO(LOG_TAG, "%s: event_code: 0x%x, subevent_code: 0x%x",
+ // __func__, event_code, subevent_code);
+ return (event_code == FW_EVENT_CODE && subevent_code == FW_SUB_EVENT_CODE);
+ }
+};
+
+FWLogFilter::FWLogFilter() : filter_impl_(new FWLogFilterImpl()) {}
+
+FWLogFilter* FWLogFilter::GetInstance() {
+ return base::Singleton<FWLogFilter>::get();
+}
+
+bool FWLogFilter::IsFWLogEvent(const BT_HDR* packet) const {
+ return filter_impl_->IsFWLogEvent(packet);
+}
+
+bool FWLogFilter::Intercepted(BT_HDR* packet) const {
+ return filter_impl_->Intercepted(packet);
+}
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/hci/fw_logger_switch.cc b/mtkbt/code/bt/mediatek/hci/fw_logger_switch.cc
new file mode 100755
index 0000000..599a06a
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/hci/fw_logger_switch.cc
@@ -0,0 +1,218 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_fw_logger_switch"
+
+#include "fw_logger_switch.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <utils/misc.h>
+#include <atomic>
+#include <mutex>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/memory/singleton.h>
+
+#include "bt_types.h"
+#include "buffer_allocator.h"
+#include "hci_internals.h"
+#include "hci_layer.h"
+#include "hci_packet_parser.h"
+#include "log_mode.h"
+#include "module.h"
+#include "mtk_stack_config.h"
+#include "mtk_util.h"
+#include "osi/include/allocator.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class FWLogSwitchImpl : public Singleton<FWLogSwitchImpl> {
+ public:
+ FWLogSwitchImpl()
+ : hci_(hci_layer_get_interface()),
+ buffer_allocator_(buffer_allocator_get_interface()),
+ is_started_{false},
+ last_trace_mode_{kUnknown} {}
+
+ BT_HDR* MakePacket(uint16_t data_size);
+ BT_HDR* MakeCommand(const uint8_t* cmd, uint16_t cmd_len);
+ BT_HDR* MakeEnableCommand(const std::vector<uint8_t>& enable_cmd);
+ BT_HDR* MakeFilterCommand(const std::vector<uint8_t>& filter_cmd);
+
+ bool is_need_dispatch_vsc(TraceLevel current) const {
+ return is_started_ && (kUnknown != current) &&
+ (current != last_trace_mode_);
+ }
+
+ bool is_start_poll() const { return is_started_; }
+
+ TraceLevel last_trace_mode() const { return last_trace_mode_; }
+
+ bool IsNeedToSendFilterCmd(TraceLevel current) const {
+ return kSqc == current || kDebug == current;
+ }
+
+ bool Start() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ if (is_start_poll()) {
+ std::lock_guard<std::mutex> lock(switch_mutex_);
+ LOG_INFO(LOG_TAG, "%s: already started, do trace mode reset.", __func__);
+ std::atomic_exchange(&last_trace_mode_, kUnknown);
+ } else {
+ ::android::add_sysprop_change_callback(FWLogConfigUpdate, 0);
+ std::atomic_exchange(&is_started_, true);
+ }
+ // FW log configuration may be set before BT on
+ // Check and update FWLog configuration for start up
+ FWLogConfigUpdate();
+ return is_started_;
+ }
+
+ bool Stop() {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ {
+ std::lock_guard<std::mutex> lock(switch_mutex_);
+ std::atomic_exchange(&is_started_, false);
+ std::atomic_exchange(&last_trace_mode_, kUnknown);
+ }
+ return !is_started_;
+ }
+
+ void Transmit(BT_HDR* command) {
+ CHECK(hci_ != NULL);
+ BT_HDR* response = static_cast<BT_HDR*>(
+ future_await(hci_->transmit_command_futured(command)));
+ hci_packet_parser_get_interface()->parse_generic_command_complete(response);
+ }
+
+ static void FWLogConfigUpdate(void);
+
+ private:
+ // workaround for add_sysprop_change_callback without context in
+ friend class Singleton<FWLogSwitchImpl>;
+
+ const hci_t* hci_;
+ const allocator_t* buffer_allocator_;
+ std::atomic_bool is_started_;
+ std::atomic<TraceLevel> last_trace_mode_;
+ std::mutex switch_mutex_;
+};
+
+BT_HDR* FWLogSwitchImpl::MakePacket(uint16_t data_size) {
+ BT_HDR* ret = (BT_HDR*)buffer_allocator_->alloc(sizeof(BT_HDR) + data_size);
+ CHECK(ret != NULL);
+ ret->event = 0;
+ ret->offset = 0;
+ ret->layer_specific = 0;
+ ret->len = data_size;
+ return ret;
+}
+
+BT_HDR* FWLogSwitchImpl::MakeCommand(const uint8_t* cmd, uint16_t cmd_len) {
+ BT_HDR* packet = MakePacket(cmd_len);
+ uint8_t* stream = packet->data;
+ const uint8_t* p_cmd = cmd;
+ ARRAY_TO_STREAM(stream, p_cmd, (int)cmd_len);
+ return packet;
+}
+
+BT_HDR* FWLogSwitchImpl::MakeEnableCommand(
+ const std::vector<uint8_t>& enable_cmd) {
+ CHECK(!enable_cmd.empty());
+ const uint8_t* p_cmd_buf = enable_cmd.data();
+ LOG_INFO(LOG_TAG, "%s firmware command: %s", __func__,
+ DataArrayToString<uint8_t>(p_cmd_buf, enable_cmd.size()).c_str());
+ return MakeCommand(p_cmd_buf, static_cast<uint16_t>(enable_cmd.size()));
+}
+
+BT_HDR* FWLogSwitchImpl::MakeFilterCommand(
+ const std::vector<uint8_t>& filter_cmd) {
+ CHECK(!filter_cmd.empty());
+ const uint8_t* p_cmd_buf = filter_cmd.data();
+ LOG_INFO(LOG_TAG, "%s firmware command: %s", __func__,
+ DataArrayToString<uint8_t>(p_cmd_buf, filter_cmd.size()).c_str());
+ return MakeCommand(p_cmd_buf, static_cast<uint16_t>(filter_cmd.size()));
+}
+
+void FWLogSwitchImpl::FWLogConfigUpdate() {
+ FWLogSwitchImpl* fwlog_switch = FWLogSwitchImpl::GetInstance();
+ TraceLevel level = LogLevel::GetInstance()->QueryTraceLevel(kController);
+ std::lock_guard<std::mutex> lock(fwlog_switch->switch_mutex_);
+ if (fwlog_switch->is_need_dispatch_vsc(level)) {
+ LOG_INFO(LOG_TAG, "%s: update log mode from %s to %s.", __func__,
+ LogLevel::GetInstance()
+ ->GetTraceLevelName(fwlog_switch->last_trace_mode())
+ .c_str(),
+ LogLevel::GetInstance()->GetTraceLevelName(level).c_str());
+ std::atomic_exchange(&fwlog_switch->last_trace_mode_, level);
+ const std::shared_ptr<ControllerLogModeParser> parser =
+ StackConfig::GetInstance()->LoadFWLogModeParser(level);
+ fwlog_switch->Transmit(fwlog_switch->MakeEnableCommand(
+ StackConfig::GetInstance()->GetFWLogEnableCommandPacket(parser)));
+ if (fwlog_switch->IsNeedToSendFilterCmd(level)) {
+ fwlog_switch->Transmit(fwlog_switch->MakeFilterCommand(
+ StackConfig::GetInstance()->GetFWLogFilterommandPacket(parser)));
+ }
+ }
+}
+
+FWLogSwitch::FWLogSwitch() {}
+
+FWLogSwitch* FWLogSwitch::GetInstance() {
+ return base::Singleton<FWLogSwitch>::get();
+}
+
+bool FWLogSwitch::StartUp() { return FWLogSwitchImpl::GetInstance()->Start(); }
+
+bool FWLogSwitch::IsStarted() const {
+ return FWLogSwitchImpl::GetInstance()->is_start_poll();
+}
+
+bool FWLogSwitch::Shutdown() { return FWLogSwitchImpl::GetInstance()->Stop(); }
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/hci/hci_inbound_data_monitor.cc b/mtkbt/code/bt/mediatek/hci/hci_inbound_data_monitor.cc
new file mode 100755
index 0000000..6316906
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/hci/hci_inbound_data_monitor.cc
@@ -0,0 +1,417 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_hci_inbound_data_monitor"
+
+#include "hci_inbound_data_monitor.h"
+
+#include <string.h>
+#include <atomic>
+#include <mutex>
+#include <vector>
+
+#include <base/logging.h>
+
+#include "fw_logger_filter.h"
+#include "osi/include/alarm.h"
+#include "osi/include/log.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+/*****************************************************************************
+ * Notice module begin
+ *****************************************************************************/
+
+class InboundData {
+ public:
+ InboundData(uint32_t times_per_sec, float data_per_sec, const char* msg,
+ bool is_alert = false)
+ : inbound_times_per_sec_(times_per_sec),
+ inbound_data_per_sec_(data_per_sec),
+ data_filter_msg_(msg),
+ is_alert_if_needed_(is_alert) {}
+ uint32_t inbound_times_per_sec() const { return inbound_times_per_sec_; }
+
+ float inbound_data_per_sec() const { return inbound_data_per_sec_; }
+
+ const char* data_filter_msg() const { return data_filter_msg_; }
+
+ bool is_alert_if_needed() const { return is_alert_if_needed_; }
+
+ private:
+ uint32_t inbound_times_per_sec_;
+ float inbound_data_per_sec_;
+ const char* data_filter_msg_;
+ bool is_alert_if_needed_;
+};
+
+using InboundDataLevelCallback = std::function<void(const InboundData&)>;
+
+// If chain of responsibility with performance concern, to replace with BST
+class DataLevel {
+ public:
+ explicit DataLevel(std::unique_ptr<DataLevel> successor)
+ : successor_(std::move(successor)) {}
+ virtual ~DataLevel() {}
+
+ virtual void Handle(const InboundData& inbound_data) = 0;
+
+ protected:
+ std::unique_ptr<DataLevel> successor_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DataLevel);
+};
+
+class UltraHighDataLevel : public DataLevel {
+ public:
+ UltraHighDataLevel() : DataLevel(nullptr) {}
+ virtual ~UltraHighDataLevel() {}
+
+ void Handle(const InboundData& inbound_data) override {
+ if (inbound_data.is_alert_if_needed()) {
+// LOG_ALWAYS_FATAL(
+// "%s: %s: oh boy, to the moon: times %u/s, amount %.2f KB/s.",
+// __func__, inbound_data.data_filter_msg(),
+// inbound_data.inbound_times_per_sec(),
+// inbound_data.inbound_data_per_sec());
+ LOG_ERROR(LOG_TAG,
+ "%s: %s: oh boy, to the moon: times %u/s, amount %.2f KB/s.",
+ __func__, inbound_data.data_filter_msg(),
+ inbound_data.inbound_times_per_sec(),
+ inbound_data.inbound_data_per_sec());
+ } else {
+ LOG_INFO(LOG_TAG,
+ "%s: %s: oh boy, to the moon: times %u/s, amount %.2f KB/s.",
+ __func__, inbound_data.data_filter_msg(),
+ inbound_data.inbound_times_per_sec(),
+ inbound_data.inbound_data_per_sec());
+ }
+ }
+};
+
+class HighDataLevel : public DataLevel {
+ public:
+ HighDataLevel()
+ : DataLevel(std::unique_ptr<DataLevel>(new UltraHighDataLevel())) {}
+ virtual ~HighDataLevel() {}
+
+ void Handle(const InboundData& inbound_data) override {
+ if ((inbound_data.inbound_times_per_sec() <= HIGH_TIMES) &&
+ (inbound_data.inbound_data_per_sec() <= HIGH_DATA_PER_SEC)) {
+ if (inbound_data.is_alert_if_needed()) {
+ LOG_WARN(LOG_TAG, "%s: %s: loading smells: times %u/s, amount %.2f KB/s.",
+ __func__, inbound_data.data_filter_msg(),
+ inbound_data.inbound_times_per_sec(),
+ inbound_data.inbound_data_per_sec());
+ } else {
+ LOG_INFO(LOG_TAG, "%s: %s: loading smells: times %u/s, amount %.2f KB/s.",
+ __func__, inbound_data.data_filter_msg(),
+ inbound_data.inbound_times_per_sec(),
+ inbound_data.inbound_data_per_sec());
+ }
+ } else {
+ successor_->Handle(inbound_data);
+ }
+ }
+};
+
+class MediumDataLevel : public DataLevel {
+ public:
+ MediumDataLevel()
+ : DataLevel(std::unique_ptr<DataLevel>(new HighDataLevel())) {}
+ virtual ~MediumDataLevel() {}
+
+ void Handle(const InboundData& inbound_data) override {
+ if ((inbound_data.inbound_times_per_sec() <= MEDIUM_TIMES) &&
+ (inbound_data.inbound_data_per_sec() <= MEDIUM_DATA_PER_SEC)) {
+ if (inbound_data.is_alert_if_needed()) {
+ LOG_INFO(LOG_TAG, "%s: %s: times %u/s, amount %.2f KB/s.", __func__,
+ inbound_data.data_filter_msg(),
+ inbound_data.inbound_times_per_sec(),
+ inbound_data.inbound_data_per_sec());
+ }
+ } else {
+ successor_->Handle(inbound_data);
+ }
+ }
+};
+
+class LowDataLevel : public DataLevel {
+ public:
+ LowDataLevel()
+ : DataLevel(std::unique_ptr<DataLevel>(new MediumDataLevel())) {}
+ virtual ~LowDataLevel() {}
+
+ void Handle(const InboundData& inbound_data) override {
+ if ((inbound_data.inbound_times_per_sec() <= LOW_TIMES) &&
+ (inbound_data.inbound_data_per_sec() <= LOW_DATA_PER_SEC)) {
+ {} // low level do nothing
+ } else {
+ successor_->Handle(inbound_data);
+ }
+ }
+};
+
+class Observer {
+ public:
+ Observer(InboundDataLevel data_level, const std::string& name,
+ bool is_registered = false)
+ : data_level_(data_level),
+ name_(name),
+ is_registered_(is_registered),
+ inbound_times_per_sec_(0),
+ inbound_data_per_sec_(0.0f) {}
+ virtual ~Observer() {}
+
+ virtual void Update(const BT_HDR* buffer) = 0;
+ virtual void Notify(InboundDataLevelCallback cb) = 0;
+
+ InboundDataLevel data_level() const { return data_level_; }
+
+ std::string name() const { return name_; }
+
+ bool is_registered() const { return is_registered_; }
+
+ void set_is_registered(bool is_registered) { is_registered_ = is_registered; }
+
+ uint32_t inbound_times_per_sec() const { return inbound_times_per_sec_; }
+
+ float inbound_data_per_sec() const { return inbound_data_per_sec_; }
+
+ protected:
+ void Notify(InboundDataLevelCallback cb, bool is_alert_if_needed) {
+ InboundData notice_data = {inbound_times_per_sec_,
+ (float)inbound_data_per_sec_ / 1024,
+ name_.c_str(), is_alert_if_needed};
+ cb(notice_data);
+ Reset();
+ }
+
+ void UpdateData(const uint8_t* data, uint16_t inbound_data_len) {
+ std::lock_guard<std::mutex> lock(data_mutex_);
+ inbound_times_per_sec_++;
+ inbound_data_per_sec_ += (uint32_t)inbound_data_len;
+ }
+
+ private:
+ void Reset() {
+ std::lock_guard<std::mutex> lock(data_mutex_);
+ inbound_times_per_sec_ = 0;
+ inbound_data_per_sec_ = 0.0f;
+ }
+
+ InboundDataLevel data_level_;
+ const std::string name_;
+ bool is_registered_;
+ uint32_t inbound_times_per_sec_;
+ float inbound_data_per_sec_;
+ std::mutex data_mutex_;
+};
+
+class ObserverWhole : public Observer {
+ public:
+ ObserverWhole()
+ : Observer(kInboundDataLevelUnknown, std::string("all inbound data"),
+ true) {}
+ virtual ~ObserverWhole() {}
+
+ void Update(const BT_HDR* buffer) override {
+ CHECK(buffer != NULL);
+ Observer::UpdateData(buffer->data, buffer->len);
+ }
+
+ void Notify(InboundDataLevelCallback cb) override {
+ return Observer::Notify(cb, false);
+ }
+};
+
+class ObserverFWLog : public Observer {
+ public:
+ ObserverFWLog()
+ : Observer(kInboundDataLevelUnknown, std::string("FW log data")) {}
+ virtual ~ObserverFWLog() {}
+
+ void Update(const BT_HDR* buffer) override {
+ CHECK(buffer != NULL);
+ if (FWLogFilter::GetInstance()->IsFWLogEvent(buffer)) {
+ Observer::UpdateData(buffer->data, buffer->len);
+ }
+ }
+
+ void Notify(InboundDataLevelCallback cb) override {
+ return Observer::Notify(cb, true);
+ }
+};
+
+class ObserverUTTest : public Observer {
+ public:
+ ObserverUTTest()
+ : Observer(kInboundDataLevelUnknown, std::string("GTest data")) {}
+ virtual ~ObserverUTTest() {}
+
+ void Update(const BT_HDR* buffer) override {
+ CHECK(buffer != NULL);
+ if (IsGTestData(buffer->data)) {
+ Observer::UpdateData(buffer->data, buffer->len);
+ }
+ }
+
+ void Notify(InboundDataLevelCallback cb) override {
+ return Observer::Notify(cb, false);
+ }
+
+ private:
+ bool IsGTestData(const uint8_t* data) {
+ // "Life is like a box of chocolate"
+ return (data[0] == 0x4C && data[1] == 0x69 && data[2] == 0x66);
+ }
+};
+
+class InboundDataMonitorImpl {
+ public:
+ explicit InboundDataMonitorImpl(const std::string& name)
+ : is_monitor_timer_started_{false},
+ data_monitor_timer_(
+ alarm_new((name + std::string("_timer")).c_str())),
+ data_level_checker_(new LowDataLevel()) {
+ ConstructObservers();
+ }
+
+ ~InboundDataMonitorImpl() {
+ if (data_monitor_timer_) {
+ alarm_free(data_monitor_timer_);
+ data_monitor_timer_ = NULL;
+ }
+ }
+
+ void InboundDataFilterUpdate(InboundDataFilter filter_type, bool is_on) {
+ observer_list_.at(filter_type)->set_is_registered(is_on);
+ }
+
+ void InboundDataUpdate(const BT_HDR* buffer) {
+ // alarm timer with wakeup lock, with low power suspend concern
+ // re-factor to change to event driven from periodic timer
+ RefreshMonitorTimer();
+ for (auto& observer : observer_list_) {
+ observer->Update(buffer);
+ }
+ }
+
+ void InboundDataNotify() {
+ for (auto& observer : observer_list_) {
+ observer->Notify([this](const InboundData& inbound_data) {
+ this->data_level_checker_->Handle(inbound_data);
+ });
+ }
+ }
+
+ InboundDataLevel GetDataLevel(InboundDataFilter filter_type) const {
+ return observer_list_.at(filter_type)->data_level();
+ }
+
+ private:
+ void ConstructObservers() {
+ // Need to align with declaration sequence as InboundDataFilter
+ observer_list_.emplace_back(new ObserverWhole());
+ observer_list_.emplace_back(new ObserverUTTest());
+ observer_list_.emplace_back(new ObserverFWLog());
+ }
+
+ void RefreshMonitorTimer() {
+ if (!is_monitor_timer_started_) {
+ alarm_set(data_monitor_timer_, DATA_MONITOR_TIMEOUT_MS,
+ [](void* context) {
+ CHECK(NULL != context);
+ // LOG_INFO(LOG_TAG, "%s", __func__);
+ InboundDataMonitorImpl* monitor =
+ static_cast<InboundDataMonitorImpl*>(context);
+ monitor->InboundDataNotify();
+ std::atomic_exchange(
+ &monitor->is_monitor_timer_started_, false);
+ },
+ this);
+ std::atomic_exchange(&is_monitor_timer_started_, true);
+ }
+ }
+
+ std::atomic_bool is_monitor_timer_started_;
+ alarm_t* data_monitor_timer_;
+ std::vector<std::unique_ptr<Observer> > observer_list_;
+ std::unique_ptr<DataLevel> data_level_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(InboundDataMonitorImpl);
+};
+
+/*****************************************************************************
+ * Monitor module begin
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Monitor API begin
+ *****************************************************************************/
+InboundDataMonitor::InboundDataMonitor(const std::string& name)
+ : inbound_data_mointor_impl_(new InboundDataMonitorImpl(name)) {}
+
+InboundDataMonitor::~InboundDataMonitor() {
+ inbound_data_mointor_impl_.reset(nullptr);
+}
+
+void InboundDataMonitor::InboundDataFilterUpdate(InboundDataFilter filter_type,
+ bool is_on) {
+ CHECK(inbound_data_mointor_impl_ != nullptr);
+ inbound_data_mointor_impl_->InboundDataFilterUpdate(filter_type, is_on);
+}
+void InboundDataMonitor::InboundDataUpdate(const BT_HDR* buffer) {
+ CHECK(inbound_data_mointor_impl_ != nullptr);
+ inbound_data_mointor_impl_->InboundDataUpdate(buffer);
+}
+
+InboundDataLevel InboundDataMonitor::GetDataLevel(
+ InboundDataFilter filter_type) const {
+ CHECK(inbound_data_mointor_impl_ != nullptr);
+ return inbound_data_mointor_impl_->GetDataLevel(filter_type);
+}
+
+/*****************************************************************************
+ * Monitor API end
+ *****************************************************************************/
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/hci/twrite.cc b/mtkbt/code/bt/mediatek/hci/twrite.cc
new file mode 100755
index 0000000..49b9971
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/hci/twrite.cc
@@ -0,0 +1,483 @@
+
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#define LOG_TAG "bt_snoop_twrite"
+
+#include "twrite.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/memory/singleton.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <base/sequenced_task_runner.h>
+#include <chrono>
+
+#include "bt_hci_bdroid.h"
+#include "btsnoop_mem.h"
+#include "hci_inbound_data_monitor.h"
+#include "log_time.h"
+#include "module.h"
+#include "mtk_stack_config.h"
+#include "mtk_util.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+#include "osi/include/thread.h"
+#include "stack_config.h"
+
+// To disable by default
+#define DBG_LOG_ENABLE FALSE
+
+#if DBG_LOG_ENABLE == TRUE
+#define DBG_LOG(tag, fmt, args...) LOG_DEBUG(LOG_TAG, fmt, ##args)
+#else
+#define DBG_LOG(tag, fmt, args...) ((void)0)
+#endif
+
+void btsnoop_net_open();
+void btsnoop_net_close();
+void btsnoop_net_write(const void* data, size_t length);
+
+// Module life cycle functions
+static future_t* start_up(void) {
+ vendor::mediatek::bluetooth::stack::BTSnoop::GetInstance()->StartUp();
+ return NULL;
+}
+
+static future_t* shut_down(void) {
+ vendor::mediatek::bluetooth::stack::BTSnoop::GetInstance()->Stop();
+ return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t mtk_btsnoop_module = {
+ .name = MTK_BTSNOOP_MODULE,
+ .init = NULL,
+ .start_up = start_up,
+ .shut_down = shut_down,
+ .clean_up = NULL,
+ .dependencies = {STACK_CONFIG_MODULE, NULL}};
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+const std::string kBTSnoopPathProperty("persist.bluetooth.btsnooppath");
+const std::string kBTSnoopDefaultPathProperty(
+ "/data/misc/bluetooth/logs/btsnoop_hci.log");
+
+class BTSnoopImpl {
+ public:
+ enum PacketType {
+ kCommandPacket = 1,
+ kAclPacket = 2,
+ kScoPacket = 3,
+ kEventPacket = 4
+ };
+
+ struct __attribute__((__packed__)) btsnoop_header_t {
+ uint32_t length_original;
+ uint32_t length_captured;
+ uint32_t flags;
+ uint32_t dropped_packets;
+ uint64_t timestamp;
+ uint8_t type;
+ };
+
+ BTSnoopImpl()
+ : kBTSnoopFileHeader_("btsnoop\0\0\0\0\1\0\0\x3\xea", 16),
+ message_loop_(nullptr),
+ run_loop_(nullptr),
+ thread_(NULL),
+ logfile_fd_(INVALID_FD),
+ is_logging_(false),
+ inbound_data_monitor_(nullptr) {}
+ ~BTSnoopImpl() = default;
+
+ void StartUp();
+ void Capture(const BT_HDR* buffer, bool is_received);
+ void Stop();
+
+ private:
+ std::string GetBTSnoopLogPath() {
+ char log_path[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get(kBTSnoopPathProperty.c_str(), log_path,
+ kBTSnoopDefaultPathProperty.c_str());
+ return std::string(log_path);
+ }
+
+ void BackupLogFile(const std::string& log_path) {
+ // Save the old log if configured to do so
+ if (StackConfig::GetInstance()->IsBTSnoopSaveLastEnabled()) {
+ std::string last_log_path =
+ log_path + std::string("_") + LogTime::GetInstance()->GetLogTimeTag();
+ if (rename(log_path.c_str(), last_log_path.c_str()) && errno != ENOENT)
+ LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
+ log_path.c_str(), last_log_path.c_str(), strerror(errno));
+ }
+ }
+
+ bool CreateLogFile(const std::string& log_path) {
+ mode_t prevmask = umask(0);
+ logfile_fd_ = open(log_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ if (logfile_fd_ == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__,
+ log_path.c_str(), strerror(errno));
+ umask(prevmask);
+ return false;
+ }
+ umask(prevmask);
+ return true;
+ }
+
+ std::string InitCustLogPath(const std::string& log_path);
+ // TODO(Peng): Sorry to apply software workaround, to remove it
+ bool MakeDir(const std::string &dir, uint8_t retry_times);
+ void RemoveAllLogs(const std::string& log_path);
+ void WritePacket(PacketType type, uint8_t* packet, bool is_received,
+ uint64_t timestamp_us);
+
+ static void BTSnoopInitialize(BTSnoopImpl* impl);
+ static void RunMessageLoop(void* context);
+ static void WriteData(int fd, btsnoop_header_t header,
+ std::vector<uint8_t> packets);
+
+ const std::string kBTSnoopFileHeader_;
+
+ std::mutex btsnoop_mutex_;
+ std::mutex message_loop_mutex_;
+ base::MessageLoop* message_loop_;
+ base::RunLoop* run_loop_;
+ thread_t* thread_;
+ int logfile_fd_;
+ bool is_logging_;
+ std::unique_ptr<InboundDataMonitor> inbound_data_monitor_;
+};
+
+void BTSnoopImpl::StartUp() {
+ if (is_logging_) {
+ return;
+ }
+ thread_ = thread_new("mbtsnoop_thread");
+ if (!thread_) {
+ LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
+ } else {
+ if (!thread_set_priority(thread_, 0)) {
+ LOG_ERROR(LOG_TAG, "%s unable to make thread priority.", __func__);
+ }
+ thread_post(thread_, BTSnoopImpl::RunMessageLoop, this);
+ }
+
+ // For low power concern, don't default turn on inbound data monitor
+ if (StackConfig::GetInstance()->IsInboundDataMonitorEnabled()) {
+ inbound_data_monitor_.reset(
+ new InboundDataMonitor(std::string(MTK_BTSNOOP_MODULE)));
+ if (inbound_data_monitor_ != nullptr) {
+ inbound_data_monitor_->InboundDataFilterUpdate(kInboundDataVSEFWLog, true);
+ }
+ }
+}
+
+void BTSnoopImpl::Stop() {
+ if (!is_logging_) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(btsnoop_mutex_);
+ if (logfile_fd_ != INVALID_FD) close(logfile_fd_);
+ logfile_fd_ = INVALID_FD;
+ btsnoop_net_close();
+
+ {
+ std::lock_guard<std::mutex> lock(message_loop_mutex_);
+ // Error handling for messge_loop_ is still NULL during thread creation
+ // but stop event is coming too soon
+ if (message_loop_ != nullptr) {
+ message_loop_->task_runner()->PostTask(
+ FROM_HERE, run_loop_->QuitClosure());
+ }
+ }
+
+ // Stop the thread to prevent Send() calls.
+ if (thread_) {
+ thread_stop(thread_);
+ thread_join(thread_);
+ thread_free(thread_);
+ thread_ = NULL;
+ }
+
+ if (inbound_data_monitor_ != nullptr) {
+ inbound_data_monitor_.reset();
+ }
+}
+
+void BTSnoopImpl::Capture(const BT_HDR* buffer, bool is_received) {
+ uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
+
+ std::lock_guard<std::mutex> lock(btsnoop_mutex_);
+ uint64_t timestamp_us = LogTime::GetInstance()->GetEpochTime();
+ btsnoop_mem_capture(buffer, timestamp_us);
+
+ if ((inbound_data_monitor_ != nullptr) && is_received) {
+ inbound_data_monitor_->InboundDataUpdate(buffer);
+ }
+
+ if (logfile_fd_ == INVALID_FD) return;
+
+ switch (buffer->event & MSG_EVT_MASK) {
+ case MSG_HC_TO_STACK_HCI_EVT:
+ WritePacket(kEventPacket, p, false, timestamp_us);
+ break;
+ case MSG_HC_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_HC_HCI_ACL:
+ WritePacket(kAclPacket, p, is_received, timestamp_us);
+ break;
+ case MSG_HC_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_HC_HCI_SCO:
+ WritePacket(kScoPacket, p, is_received, timestamp_us);
+ break;
+ case MSG_STACK_TO_HC_HCI_CMD:
+ WritePacket(kCommandPacket, p, true, timestamp_us);
+ break;
+ }
+}
+
+void BTSnoopImpl::BTSnoopInitialize(BTSnoopImpl* impl) {
+ std::lock_guard<std::mutex> lock(impl->btsnoop_mutex_);
+ bool should_log = StackConfig::GetInstance()->IsBTSnoopEnabled();
+ std::string log_path = impl->GetBTSnoopLogPath();
+ std::string log_dir = impl->InitCustLogPath(log_path);
+ if (!should_log) {
+ if (!log_dir.empty()) {
+ LOG_INFO(LOG_TAG, "%s: Try to delete snoop log under %s ",
+ __func__, log_dir.c_str());
+ impl->RemoveAllLogs(log_dir);
+ }
+ } else {
+ impl->BackupLogFile(log_path);
+ impl->is_logging_ = impl->CreateLogFile(log_path);
+ if (impl->is_logging_) {
+ LOG_INFO(LOG_TAG, "%s: begin to logging %s.", __func__, log_path.c_str());
+ write(impl->logfile_fd_, impl->kBTSnoopFileHeader_.c_str(),
+ impl->kBTSnoopFileHeader_.size());
+ btsnoop_net_open();
+ }
+ }
+}
+
+void BTSnoopImpl::RunMessageLoop(void* context) {
+ BTSnoopImpl* impl = static_cast<BTSnoopImpl*>(context);
+ {
+ std::lock_guard<std::mutex> lock(impl->message_loop_mutex_);
+ impl->message_loop_ = new base::MessageLoop();
+ impl->run_loop_ = new base::RunLoop();
+ }
+
+ impl->message_loop_->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BTSnoopImpl::BTSnoopInitialize, impl));
+ impl->run_loop_->Run();
+
+ {
+ std::lock_guard<std::mutex> lock(impl->message_loop_mutex_);
+ delete impl->message_loop_;
+ impl->message_loop_ = nullptr;
+ delete impl->run_loop_;
+ impl->run_loop_ = nullptr;
+ }
+}
+
+std::string BTSnoopImpl::InitCustLogPath(const std::string& log_path) {
+ CHECK(!log_path.empty());
+ CHECK(std::string::npos != log_path.find_last_of('/'));
+
+ std::string log_dir = log_path.substr(0, log_path.find_last_of('/') + 1);
+ if (access(log_dir.c_str(), F_OK) != 0) {
+ size_t pre(0), pos(0);
+ std::string dir;
+ const uint8_t MAKE_DIR_RETRY_TIMES(7);
+ while (std::string::npos != (pos = log_dir.find('/', pre))) {
+ dir = log_path.substr(0, pos++);
+ pre = pos;
+ if (dir.empty()) continue; // leading with '/'
+ if (!MakeDir(dir, MAKE_DIR_RETRY_TIMES)) {
+ return std::string("");
+ }
+ }
+ }
+ return log_dir;
+}
+
+bool BTSnoopImpl::MakeDir(const std::string &dir, uint8_t retry_times) {
+ bool is_done(false);
+ uint8_t retry(retry_times);
+ while (retry > 0) {
+ if (mkdir(dir.c_str(), 0770) && (errno != EEXIST)) {
+ LOG_ERROR(LOG_TAG, "%s mkdir for %s, error! %s",
+ __func__, dir.c_str(), strerror(errno));
+ } else {
+ is_done = true;
+ break;
+ }
+ retry--;
+ sleep(1);
+ }
+ return is_done;
+}
+
+void BTSnoopImpl::RemoveAllLogs(const std::string& log_dir) {
+ CHECK(!log_dir.empty());
+ CHECK(log_dir[log_dir.size() - 1] == '/');
+
+ DIR* p_dir = opendir(log_dir.c_str());
+ if (p_dir != NULL) {
+ struct dirent* p_file;
+ while ((p_file = readdir(p_dir)) != NULL) {
+ if (strcmp(p_file->d_name, "..") == 0 ||
+ strcmp(p_file->d_name, ".") == 0) {
+ continue;
+ }
+ std::string file_path(log_dir);
+ file_path += std::string(p_file->d_name);
+ if (remove(file_path.c_str())) {
+ LOG_WARN(LOG_TAG, "%s remove fw log file failed. file:%s. errno: %s",
+ __func__, file_path.c_str(), strerror(errno));
+ break;
+ }
+ }
+ closedir(p_dir);
+ }
+}
+
+void BTSnoopImpl::WritePacket(PacketType type, uint8_t* packet,
+ bool is_received, uint64_t timestamp_us) {
+ uint32_t length_he = 0;
+ uint32_t flags = 0;
+
+ switch (type) {
+ case kCommandPacket:
+ length_he = packet[2] + 4;
+ flags = 2;
+ break;
+ case kAclPacket:
+ length_he = (packet[3] << 8) + packet[2] + 5;
+ flags = is_received;
+ break;
+ case kScoPacket:
+ length_he = packet[2] + 4;
+ flags = is_received;
+ break;
+ case kEventPacket:
+ length_he = packet[1] + 3;
+ flags = 3;
+ break;
+ }
+
+ btsnoop_header_t header;
+ header.length_original = htonl(length_he);
+ header.length_captured = header.length_original;
+ header.flags = htonl(flags);
+ header.dropped_packets = 0;
+ header.timestamp = timestamp_us;
+ header.type = type;
+
+ DBG_LOG(LOG_TAG, "%s len_ori: %x, len_captured: %x, flags: %x, type: %x",
+ __func__, header.length_original, header.length_captured,
+ header.flags, header.type);
+ DBG_LOG(LOG_TAG, "%s data: %s", __func__,
+ DataArrayToString<uint8_t>(packet, (length_he - 1)).c_str());
+ std::vector<uint8_t> packets(packet, (packet + (length_he - 1)));
+ base::Closure callback = base::Bind(&BTSnoopImpl::WriteData, logfile_fd_,
+ std::move(header), std::move(packets));
+ std::lock_guard<std::mutex> lock(message_loop_mutex_);
+ if (message_loop_ != nullptr) {
+ message_loop_->task_runner()->PostTask(FROM_HERE, std::move(callback));
+ }
+}
+
+void BTSnoopImpl::WriteData(int fd, btsnoop_header_t header,
+ std::vector<uint8_t> packets) {
+ uint8_t* packet = packets.data();
+ btsnoop_net_write(&header, sizeof(header));
+ btsnoop_net_write(packet, packets.size());
+ DBG_LOG(LOG_TAG, "%s len_ori: %x, len_captured: %x, flags: %x, type: %x",
+ __func__, header.length_original, header.length_captured,
+ header.flags, header.type);
+ DBG_LOG(LOG_TAG, "%s data: %s", __func__,
+ DataArrayToString<uint8_t>(packet, packets.size()).c_str());
+ if (fd != INVALID_FD) {
+ iovec iov[] = {{&header, sizeof(header)}, {packet, packets.size()}};
+ ssize_t ret = TEMP_FAILURE_RETRY(writev(fd, iov, sizeof(iov) / sizeof(iov[0])));
+ if (-1 == ret) {
+ LOG_ERROR(LOG_TAG, "%s error write due to: %s", __func__, strerror(errno));
+ }
+ }
+}
+
+BTSnoop::BTSnoop() : btsnoop_impl_(new BTSnoopImpl()) {}
+
+BTSnoop* BTSnoop::GetInstance() { return base::Singleton<BTSnoop>::get(); }
+
+void BTSnoop::StartUp() { btsnoop_impl_->StartUp(); }
+
+void BTSnoop::Capture(const BT_HDR* buffer, bool is_received) {
+ btsnoop_impl_->Capture(buffer, is_received);
+}
+
+void BTSnoop::Stop() { btsnoop_impl_->Stop(); }
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/fw_logger_filter.h b/mtkbt/code/bt/mediatek/include/fw_logger_filter.h
new file mode 100755
index 0000000..ba62165
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/fw_logger_filter.h
@@ -0,0 +1,73 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include "bt_types.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class FWLogFilterImpl;
+
+class FWLogFilter {
+ public:
+ static FWLogFilter* GetInstance();
+ bool IsFWLogEvent(const BT_HDR* packet) const;
+ bool Intercepted(BT_HDR* packet) const;
+
+ private:
+ FWLogFilter();
+ friend struct base::DefaultSingletonTraits<FWLogFilter>;
+ std::unique_ptr<FWLogFilterImpl> filter_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(FWLogFilter);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/fw_logger_switch.h b/mtkbt/code/bt/mediatek/include/fw_logger_switch.h
new file mode 100755
index 0000000..ec59e7b
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/fw_logger_switch.h
@@ -0,0 +1,67 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <base/macros.h>
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class FWLogSwitch {
+ public:
+ static FWLogSwitch* GetInstance();
+ bool StartUp(void);
+ bool IsStarted() const;
+ bool Shutdown(void);
+
+ private:
+ FWLogSwitch();
+ friend struct base::DefaultSingletonTraits<FWLogSwitch>;
+
+ DISALLOW_COPY_AND_ASSIGN(FWLogSwitch);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/gatts_mtk.h b/mtkbt/code/bt/mediatek/include/gatts_mtk.h
new file mode 100755
index 0000000..3cb67bc
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/gatts_mtk.h
@@ -0,0 +1,99 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include "bta/include/bta_gatt_api.h"
+
+
+/*******************************************************************************
+ *
+ * Function gatts_srv_chg_set_handle
+ *
+ * Description Set the allocated attribute handle of the Client
+ * Characteristic Configuration Descriptor
+ * of the Service Changed Characteristic.
+ *
+ * Parameter attribute handle of the Client Characteristic Configuration
+ * Descriptor
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void gatts_srv_chg_set_cccd_handle(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function gatts_srv_chg_ind_get
+ *
+ * Description Get stored indication configuration from NVRAM
+ *
+ * Parameter bda - BT address of the remote device
+ *
+ * Returns true - remote device has configure to be indicated, otherwise false
+ *
+ ******************************************************************************/
+extern bool gatts_srv_chg_ind_get(BD_ADDR bda);
+
+/*******************************************************************************
+ *
+ * Function gatts_srv_chg_ind_set
+ *
+ * Description Stores the indication configuration to NVRAM
+ *
+ * Parameter bda - BT address of the remote device
+ * ind - whether Characteristic value is configured to indicated or not
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+
+extern void gatts_srv_chg_ind_set(BD_ADDR bda, bool ind);
+
+
+/*******************************************************************************
+ *
+ * Function gatts_srv_chg_proc_write_req
+ *
+ * Description Write Request process of Service Changed Characteristic
+ *
+ * Parameter bda - BT address of the remote device
+ * p_data - write request data
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS gatts_srv_chg_proc_write_req(BD_ADDR bda,
+ tGATT_WRITE_REQ* p_data);
diff --git a/mtkbt/code/bt/mediatek/include/hci_inbound_data_monitor.h b/mtkbt/code/bt/mediatek/include/hci_inbound_data_monitor.h
new file mode 100755
index 0000000..1f62f8c
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/hci_inbound_data_monitor.h
@@ -0,0 +1,96 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+#include "bt_types.h"
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+enum InboundDataLevel {
+ kInboundDataLevelLow,
+ kInboundDataLevelMedium,
+ kInboundDataLevelHigh,
+ kInboundDataLevelUltraHigh,
+ kInboundDataLevelUnknown
+};
+
+static constexpr uint64_t DATA_MONITOR_TIMEOUT_MS = 1000;
+// Criteria
+static uint32_t LOW_TIMES = 100;
+static float LOW_DATA_PER_SEC = 20.00f;
+static uint32_t MEDIUM_TIMES = 300;
+static float MEDIUM_DATA_PER_SEC = 40.00f;
+static uint32_t HIGH_TIMES = 600;
+static float HIGH_DATA_PER_SEC = 80.00f;
+
+// Filter
+enum InboundDataFilter {
+ kInboundDataFilterNone,
+ kInboundDataUTTest, // For UTTest debug propose only
+ kInboundDataVSEFWLog,
+ kInboundDataFilterUnknown
+};
+
+class InboundDataMonitorImpl;
+
+class InboundDataMonitor {
+ public:
+ explicit InboundDataMonitor(const std::string& monitor_name);
+ ~InboundDataMonitor();
+
+ void InboundDataFilterUpdate(InboundDataFilter filter_type, bool is_on);
+ void InboundDataUpdate(const BT_HDR* buffer);
+ InboundDataLevel GetDataLevel(InboundDataFilter filter_type) const;
+
+ private:
+ std::unique_ptr<InboundDataMonitorImpl> inbound_data_mointor_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(InboundDataMonitor);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/interop_mtk.h b/mtkbt/code/bt/mediatek/include/interop_mtk.h
new file mode 100755
index 0000000..a4d8c44
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/interop_mtk.h
@@ -0,0 +1,85 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+/******************************************************************************
+ *
+ * This file contains functions for the MTK defined interop function
+ *
+ ******************************************************************************/
+
+#include "bt_types.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "device/include/interop.h"
+
+/******************************************************************************
+*
+**
+** Function interop_mtk_match_addr
+**
+** Description Looks up the interop_addr_database for the specified BD address.
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+extern bool interop_mtk_match_addr(const interop_feature_t feature, const bt_bdaddr_t* addr);
+
+
+/*******************************************************************************
+**
+** Function interop_mtk_match_name
+**
+** Description Looks up the interop_name_database for the specified BD address.
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+extern bool interop_mtk_match_name(const interop_feature_t feature, const bt_bdaddr_t* addr);
+
+
+/*******************************************************************************
+**
+** Function interop_mtk_match_addr_name
+**
+** Description Looks up the interop_addr_database and interop_name_database for the
+** specified BD address.
+**
+** Returns TRUE if matched, else FALSE
+**
+*******************************************************************************/
+extern bool interop_mtk_match_addr_name(const interop_feature_t feature, const bt_bdaddr_t* addr);
+#endif
diff --git a/mtkbt/code/bt/mediatek/include/log_mode.h b/mtkbt/code/bt/mediatek/include/log_mode.h
new file mode 100755
index 0000000..fb452a9
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/log_mode.h
@@ -0,0 +1,75 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+enum TraceLevel { kDefault, kSqc, kDebug, kUnknown };
+
+enum TraceType { kStack, kController };
+
+class LogLevelImpl;
+
+class LogLevel {
+ public:
+ static LogLevel* GetInstance();
+ TraceLevel QueryTraceLevel(TraceType type);
+ std::string GetTraceLevelName(TraceLevel level) const;
+
+ private:
+ LogLevel();
+ friend struct base::DefaultSingletonTraits<LogLevel>;
+ std::unique_ptr<LogLevelImpl> logmode_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogLevel);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/log_time.h b/mtkbt/code/bt/mediatek/include/log_time.h
new file mode 100755
index 0000000..434ed2f
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/log_time.h
@@ -0,0 +1,72 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <stdint.h>
+#include <memory>
+
+#include <base/macros.h>
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class LogTimeImpl;
+
+class LogTime {
+ public:
+ static LogTime* GetInstance();
+ uint64_t GetEpochTime() const;
+ std::string GetLogTimeTag() const;
+
+ private:
+ LogTime();
+ friend struct base::DefaultSingletonTraits<LogTime>;
+ std::unique_ptr<LogTimeImpl> logtime_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogTime);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/mdroid_buildcfg.h b/mtkbt/code/bt/mediatek/include/mdroid_buildcfg.h
new file mode 100755
index 0000000..7be7f7d
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/mdroid_buildcfg.h
@@ -0,0 +1,164 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ *
+ * MediaTek Inc. (C) 2017. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#pragma once
+
+#if __STDC_VERSION__ < 199901L
+# ifndef FALSE
+# define FALSE 0
+# endif
+# ifndef TRUE
+# define TRUE (!FALSE)
+# endif
+#else
+# include <stdbool.h>
+# ifndef FALSE
+# define FALSE false
+# endif
+# ifndef TRUE
+# define TRUE true
+# endif
+#endif
+
+/******************************************************************************
+ **
+ ** for FW multiple links 7br + 16ble
+ **
+ ******************************************************************************/
+#ifndef MAX_ACL_CONNECTIONS
+#define MAX_ACL_CONNECTIONS 39
+#endif
+
+#ifndef GATT_MAX_PHY_CHANNEL
+#define GATT_MAX_PHY_CHANNEL MAX_ACL_CONNECTIONS
+#endif
+
+#ifndef BTA_GATTC_KNOWN_SR_MAX
+#define BTA_GATTC_KNOWN_SR_MAX GATT_MAX_PHY_CHANNEL
+#endif
+
+#ifndef BTA_GATTC_CL_MAX
+#define BTA_GATTC_CL_MAX 64
+#endif
+
+#ifndef GATT_MAX_SR_PROFILES
+#define GATT_MAX_SR_PROFILES 64
+#endif
+
+#ifndef GATT_MAX_APPS
+#define GATT_MAX_APPS 64
+#endif
+
+#ifndef GATT_CL_MAX_LCB
+#define GATT_CL_MAX_LCB 64
+#endif
+
+#ifndef BTM_BLE_MAX_BG_CONN_DEV_NUM
+#define BTM_BLE_MAX_BG_CONN_DEV_NUM 64
+#endif
+
+#ifndef GATT_MAX_BG_CONN_DEV
+#define GATT_MAX_BG_CONN_DEV BTM_BLE_MAX_BG_CONN_DEV_NUM
+#endif
+
+#ifndef MAX_L2CAP_CLIENTS
+#define MAX_L2CAP_CLIENTS 20 /** M: reconfig from 15 to 20 */
+#endif
+
+// For HDP PTS case.
+// In 64bit project. It occur SDP DB full error by smaller size.
+#ifndef BTA_HL_DISC_SIZE
+#define BTA_HL_DISC_SIZE 3200
+#endif
+
+/* MTK_BLUEDROID_PATCH Begin -- for a2dp sink */
+#ifndef MTK_A2DP_SINK_SUPPORT
+#define MTK_A2DP_SINK_SUPPORT TRUE
+#endif
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+#define BTA_AV_SINK_INCLUDED TRUE
+#endif
+/* MTK_BLUEDROID_PATCH End */
+
+/******************************************************************************
+ **
+ ** For Feature or common bugfix
+ **
+ ******************************************************************************/
+#ifndef BTM_BLE_SCAN_SLOW_INT_1
+#define BTM_BLE_SCAN_SLOW_INT_1 96
+#endif
+
+#ifndef BTM_BLE_CONN_INT_MIN_DEF
+#define BTM_BLE_CONN_INT_MIN_DEF 8
+#endif
+
+#ifndef BTM_BLE_CONN_INT_MAX_DEF
+#define BTM_BLE_CONN_INT_MAX_DEF 8
+#endif
+
+#ifndef BTM_BLE_CONN_INT_MIN_LIMIT
+#define BTM_BLE_CONN_INT_MIN_LIMIT 8
+#endif
+
+#ifndef BTM_BLE_CONN_TIMEOUT_DEF
+#define BTM_BLE_CONN_TIMEOUT_DEF 300
+#endif
+
+#ifndef MTK_COMMON
+#define MTK_COMMON TRUE
+#endif
+
+#ifndef BLE_VND_INCLUDED
+#define BLE_VND_INCLUDED TRUE
+#endif
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#define HANDLE_KEY_MISSING TRUE
+#endif
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#define PIN_KEY_MISSING_HANDLE_UNPAIR TRUE
+#endif
+#ifndef MTK_A2DP_SNK_AAC_CODEC
+#define MTK_A2DP_SNK_AAC_CODEC TRUE
+#endif
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#define MTK_A2DP_SINK_AAC_SEP (1)
+#else
+#define MTK_A2DP_SINK_AAC_SEP (0)
+#endif
diff --git a/mtkbt/code/bt/mediatek/include/mtk_bt_av.h b/mtkbt/code/bt/mediatek/include/mtk_bt_av.h
new file mode 100755
index 0000000..ae26617
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/mtk_bt_av.h
@@ -0,0 +1,63 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+
+
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#ifndef __MTK_BT_AV_H__
+#define __MTK_BT_AV_H__
+
+#include <hardware/bt_av.h>
+
+#define BTAV_A2DP_CODEC_INDEX_SINK_AAC BTAV_A2DP_CODEC_INDEX_MAX
+
+#endif /* __MTK_BT_AV_H__ */
+
diff --git a/mtkbt/code/bt/mediatek/include/mtk_stack_config.h b/mtkbt/code/bt/mediatek/include/mtk_stack_config.h
new file mode 100755
index 0000000..f1d607f
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/mtk_stack_config.h
@@ -0,0 +1,84 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include "log_mode.h"
+#include "osi/include/config.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class StackConfigImpl;
+class ControllerLogModeParser;
+
+class StackConfig {
+ public:
+ static StackConfig* GetInstance();
+ bool IsNeedOverWriteConfig() const;
+ config_t* OverwriteConfig(config_t* config);
+ const std::shared_ptr<ControllerLogModeParser> LoadFWLogModeParser(
+ TraceLevel level);
+ std::vector<uint8_t> GetFWLogEnableCommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser);
+ std::vector<uint8_t> GetFWLogFilterommandPacket(
+ const std::shared_ptr<ControllerLogModeParser>& parser);
+ bool IsBTSnoopEnabled() const;
+ bool IsBTSnoopSaveLastEnabled() const;
+ bool IsInboundDataMonitorEnabled() const;
+
+ private:
+ StackConfig();
+ friend struct base::DefaultSingletonTraits<StackConfig>;
+ std::unique_ptr<StackConfigImpl> config_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackConfig);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/mtk_util.h b/mtkbt/code/bt/mediatek/include/mtk_util.h
new file mode 100755
index 0000000..5069a72
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/mtk_util.h
@@ -0,0 +1,92 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <iomanip>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <string>
+
+#include <base/macros.h>
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+template <typename T>
+std::string DataArrayToString(const T* arr, size_t array_len) {
+ std::stringstream ss;
+ int temp(0);
+ for (size_t i(0); i < array_len; i++) {
+ temp = static_cast<int>(arr[i]);
+ ss << " " << std::uppercase << std::setfill('0') << std::hex << std::setw(2)
+ << temp;
+ }
+ return ss.str();
+}
+
+template <typename T>
+class Singleton {
+ public:
+ static T* GetInstance() {
+ std::call_once(GetOnceFlag(), [] { instance_.reset(new T()); });
+ return instance_.get();
+ }
+
+ protected:
+ explicit Singleton<T>() = default;
+ ~Singleton<T>() = default;
+
+ private:
+ static std::once_flag& GetOnceFlag() {
+ static std::once_flag oncecall_;
+ return oncecall_;
+ }
+
+ static std::unique_ptr<T> instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(Singleton);
+};
+
+template <typename T>
+std::unique_ptr<T> Singleton<T>::instance_ = nullptr;
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/include/twrite.h b/mtkbt/code/bt/mediatek/include/twrite.h
new file mode 100755
index 0000000..ec519f5
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/include/twrite.h
@@ -0,0 +1,76 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include "bt_types.h"
+
+static constexpr char MTK_BTSNOOP_MODULE[] = "mtk_btsnoop_module";
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+} // namespace base
+
+namespace vendor {
+namespace mediatek {
+namespace bluetooth {
+namespace stack {
+
+class BTSnoopImpl;
+
+class BTSnoop {
+ public:
+ static BTSnoop* GetInstance();
+ void StartUp();
+ void Capture(const BT_HDR* buffer, bool is_received);
+ void Stop();
+
+ private:
+ BTSnoop();
+ friend struct base::DefaultSingletonTraits<BTSnoop>;
+ std::unique_ptr<BTSnoopImpl> btsnoop_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(BTSnoop);
+};
+
+} // namespace stack
+} // namespace bluetooth
+} // namespace mediatek
+} // namespace vendor
diff --git a/mtkbt/code/bt/mediatek/interop/interop_mtk.cc b/mtkbt/code/bt/mediatek/interop/interop_mtk.cc
new file mode 100755
index 0000000..11faff8
--- a/dev/null
+++ b/mtkbt/code/bt/mediatek/interop/interop_mtk.cc
@@ -0,0 +1,107 @@
+/* Copyright Statement:
+ * *
+ * * This software/firmware and related documentation ("MediaTek Software") are
+ * * protected under relevant copyright laws. The information contained herein
+ * * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * * any reproduction, modification, use or disclosure of MediaTek Software,
+ * * and information contained herein, in whole or in part, shall be strictly prohibited.
+ * *
+ * * MediaTek Inc. (C) 2016. All rights reserved.
+ * *
+ * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ * *
+ * * The following software/firmware and/or related documentation ("MediaTek Software")
+ * * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * * applicable license agreements with MediaTek Inc.
+ * */
+
+
+/******************************************************************************
+ *
+ * This file contains functions for the MTK defined interop function
+ *
+ ******************************************************************************/
+#define LOG_TAG "bt_device_interop_mtk"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include "bt_types.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+
+#include "bdaddr.h"
+#include "osi/include/log.h"
+#include "btif/include/btif_config.h"
+#include "btm_api.h"
+#include "interop_mtk.h"
+
+bt_status_t btmtk_get_ble_device_name(const bt_bdaddr_t *remote_bd_addr, BD_NAME bd_name)
+{
+ bdstr_t bdstr;
+ int length = BD_NAME_LEN;
+ bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+ int ret = btif_config_get_str(bdstr, "Name", (char*)bd_name, &length);
+ return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+bool interop_mtk_match_addr(const interop_feature_t feature, const bt_bdaddr_t* addr)
+{
+ return interop_match_addr(feature, addr);
+}
+
+bool interop_mtk_match_name(const interop_feature_t feature, const bt_bdaddr_t* addr)
+{
+ char *dev_name_str;
+ BD_NAME remote_name = {0};
+ BD_ADDR bd_addr;
+
+ bdcpy(bd_addr, addr->address);
+ dev_name_str = BTM_SecReadDevName(bd_addr);
+
+ //need to load ble device name from config
+ if (dev_name_str == NULL || dev_name_str[0] == '\0')
+ {
+ dev_name_str = (char *)remote_name;
+ btmtk_get_ble_device_name(addr, remote_name);
+ }
+
+ if (dev_name_str != NULL && dev_name_str[0] != '\0')
+ {
+ if(true == interop_match_name(feature, (const char *)dev_name_str))
+ {
+ char bdstr[20] = {0};
+ APPL_TRACE_DEBUG("%s device %s(%s) is a match for interop workaround %d.", __func__,
+ dev_name_str, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), feature);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool interop_mtk_match_addr_name(const interop_feature_t feature, const bt_bdaddr_t* addr)
+{
+ if(interop_mtk_match_addr(feature, addr))
+ return true;
+
+ return interop_mtk_match_name(feature, addr);
+}
+#endif
diff --git a/mtkbt/code/bt/osi/Android.bp b/mtkbt/code/bt/osi/Android.bp
new file mode 100755
index 0000000..ee91a43
--- a/dev/null
+++ b/mtkbt/code/bt/osi/Android.bp
@@ -0,0 +1,159 @@
+cc_defaults {
+ name: "fluoride_osi_defaults",
+ defaults: ["fluoride_defaults"],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/osi/src/protos",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ]
+}
+
+// Static libraries required by other modules
+// ========================================================
+cc_test_library {
+ name: "libosi-AllocationTestHarness",
+ defaults: ["fluoride_osi_defaults"],
+ srcs: [
+ "test/AllocationTestHarness.cc",
+ ],
+ host_supported: true,
+ shared: {
+ enabled: false
+ }
+}
+
+cc_test_library {
+ name: "libosi-AlarmTestHarness",
+ defaults: ["fluoride_osi_defaults"],
+ srcs: [
+ "test/AlarmTestHarness.cc",
+ ],
+ host_supported: true,
+ shared: {
+ enabled: false
+ }
+}
+
+// Bluetooth Protobuf static library for target and host
+// ========================================================
+cc_library_static {
+ name: "libbt-protos",
+ defaults: ["fluoride_defaults"],
+ srcs: ["src/protos/bluetooth.proto"],
+ proto: {
+ export_proto_headers: true,
+ },
+ host_supported: true
+}
+
+
+// libosi static library for target
+// ========================================================
+cc_library_static {
+ name: "libosi",
+ defaults: ["fluoride_osi_defaults"],
+ // TODO(mcchou): Remove socket_utils sources after platform specific
+ // dependencies are abstracted.
+ srcs: [
+ "src/alarm.cc",
+ "src/allocation_tracker.cc",
+ "src/allocator.cc",
+ "src/array.cc",
+ "src/buffer.cc",
+ "src/compat.cc",
+ "src/config.cc",
+ "src/data_dispatcher.cc",
+ "src/fixed_queue.cc",
+ "src/future.cc",
+ "src/hash_map_utils.cc",
+ "src/list.cc",
+ "src/metrics.cc",
+ "src/mutex.cc",
+ "src/osi.cc",
+ "src/properties.cc",
+ "src/reactor.cc",
+ "src/ringbuffer.cc",
+ "src/semaphore.cc",
+ "src/socket.cc",
+ "src/socket_utils/socket_local_client.cc",
+ "src/socket_utils/socket_local_server.cc",
+ "src/thread.cc",
+ "src/time.cc",
+ "src/wakelock.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: ["libbt-protos"],
+ host_supported: true,
+ // TODO(armansito): Setting _GNU_SOURCE isn't very platform-independent but
+ // should be compatible for a Linux host OS. We should figure out what to do for
+ // a non-Linux host OS.
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ linux: {
+ cflags: [
+ "-D_GNU_SOURCE",
+ "-DOS_GENERIC",
+ ],
+ },
+ },
+}
+
+// libosi unit tests for target and host
+// ========================================================
+cc_test {
+ name: "net_test_osi",
+ defaults: ["fluoride_osi_defaults"],
+ host_supported: true,
+ srcs: [
+ "test/AlarmTestHarness.cc",
+ "test/AllocationTestHarness.cc",
+ "test/alarm_test.cc",
+ "test/allocation_tracker_test.cc",
+ "test/allocator_test.cc",
+ "test/array_test.cc",
+ "test/config_test.cc",
+ "test/data_dispatcher_test.cc",
+ "test/fixed_queue_test.cc",
+ "test/future_test.cc",
+ "test/hash_map_utils_test.cc",
+ "test/leaky_bonded_queue_test.cc",
+ "test/list_test.cc",
+ "test/metrics_test.cc",
+ "test/properties_test.cc",
+ "test/rand_test.cc",
+ "test/reactor_test.cc",
+ "test/ringbuffer_test.cc",
+ "test/semaphore_test.cc",
+ "test/thread_test.cc",
+ "test/time_test.cc",
+ "test/wakelock_test.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libcutils",
+ ],
+ static_libs: [
+ "libbt-protos",
+ "libgmock",
+ "libosi",
+ ],
+ target: {
+ linux: {
+ cflags: ["-DOS_GENERIC"],
+ host_ldlibs: [
+ "-lrt",
+ "-lpthread",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ }
+ },
+}
diff --git a/mtkbt/code/bt/osi/BUILD.gn b/mtkbt/code/bt/osi/BUILD.gn
new file mode 100755
index 0000000..92a8a2a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/BUILD.gn
@@ -0,0 +1,99 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("osi") {
+ sources = [
+ "src/alarm.cc",
+ "src/allocation_tracker.cc",
+ "src/allocator.cc",
+ "src/array.cc",
+ "src/buffer.cc",
+ "src/compat.cc",
+ "src/config.cc",
+ "src/data_dispatcher.cc",
+ "src/fixed_queue.cc",
+ "src/future.cc",
+ "src/hash_map_utils.cc",
+ "src/list.cc",
+ "src/metrics_linux.cc",
+ "src/mutex.cc",
+ "src/osi.cc",
+ "src/properties.cc",
+ "src/reactor.cc",
+ "src/ringbuffer.cc",
+ "src/semaphore.cc",
+ "src/socket.cc",
+
+ # TODO(mcchou): Remove these sources after platform specific
+ # dependencies are abstracted.
+ "src/socket_utils/socket_local_client.cc",
+ "src/socket_utils/socket_local_server.cc",
+ "src/thread.cc",
+ "src/time.cc",
+ "src/wakelock.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//utils/include",
+ "//stack/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_osi") {
+ testonly = true
+ sources = [
+ "test/AlarmTestHarness.cc",
+ "test/AllocationTestHarness.cc",
+ "test/alarm_test.cc",
+ "test/allocation_tracker_test.cc",
+ "test/allocator_test.cc",
+ "test/array_test.cc",
+ "test/config_test.cc",
+ "test/data_dispatcher_test.cc",
+ "test/future_test.cc",
+ "test/hash_map_utils_test.cc",
+ "test/leaky_bonded_queue_test.cc",
+ "test/list_test.cc",
+ "test/properties_test.cc",
+ "test/rand_test.cc",
+ "test/reactor_test.cc",
+ "test/ringbuffer_test.cc",
+ "test/thread_test.cc",
+ "test/time_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//osi/test",
+ ]
+
+ deps = [
+ "//osi",
+ "//third_party/googletest:gtest_main",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ ]
+}
diff --git a/mtkbt/code/bt/osi/include/alarm.h b/mtkbt/code/bt/osi/include/alarm.h
new file mode 100755
index 0000000..a59f12d
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/alarm.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "osi/include/time.h"
+
+typedef struct alarm_t alarm_t;
+typedef struct fixed_queue_t fixed_queue_t;
+typedef struct thread_t thread_t;
+
+// Prototype for the alarm callback function.
+typedef void (*alarm_callback_t)(void* data);
+
+// Creates a new one-time off alarm object with user-assigned
+// |name|. |name| may not be NULL, and a copy of the string will
+// be stored internally. The value of |name| has no semantic
+// meaning. It is recommended that the name is unique (for
+// better debuggability), but that is not enforced. The returned
+// object must be freed by calling |alarm_free|. Returns NULL on
+// failure.
+alarm_t* alarm_new(const char* name);
+
+// Creates a new periodic alarm object with user-assigned |name|.
+// |name| may not be NULL, and a copy of the string will be
+// stored internally. The value of |name| has no semantic
+// meaning. It is recommended that the name is unique (for better
+// debuggability), but that is not enforced. The returned object
+// must be freed by calling |alarm_free|. Returns NULL on
+// failure.
+alarm_t* alarm_new_periodic(const char* name);
+
+// Frees an |alarm| object created by |alarm_new| or
+// |alarm_new_periodic|. |alarm| may be NULL. If the alarm is
+// pending, it will be cancelled first. It is not safe to call
+// |alarm_free| from inside the callback of |alarm|.
+void alarm_free(alarm_t* alarm);
+
+// Sets an |alarm| to execute a callback in the future. The |cb|
+// callback is called after the given |interval_ms|, where
+// |interval_ms| is the number of milliseconds relative to the
+// current time. If |alarm| was created with
+// |alarm_new_periodic|, the alarm is scheduled to fire
+// periodically every |interval_ms|, otherwise it is a one time
+// only alarm. A periodic alarm repeats every |interval_ms| until
+// it is cancelled or freed. When the alarm fires, the |cb|
+// callback is called with the context argument |data|:
+//
+// void cb(void *data) {...}
+//
+// The |data| argument may be NULL, but the |cb| callback may not
+// be NULL. All |cb| callbacks scheduled through this call are
+// called within a single (internally created) thread. That
+// thread is not same as the caller’s thread. If two (or more)
+// alarms are set back-to-back with the same |interval_ms|, the
+// callbacks will be called in the order the alarms are set.
+void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+ void* data);
+
+// Sets an |alarm| to execute a callback in the future on a
+// specific |queue|. This function is same as |alarm_set| except
+// that the |cb| callback is scheduled for execution in the
+// context of the thread responsible for processing |queue|.
+// Also, the callback execution ordering guarantee exists only
+// among alarms that are scheduled on the same queue. |queue|
+// may not be NULL.
+void alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms,
+ alarm_callback_t cb, void* data, fixed_queue_t* queue);
+
+// This function cancels the |alarm| if it was previously set.
+// When this call returns, the caller has a guarantee that the
+// callback is not in progress and will not be called if it
+// hasn't already been called. This function is idempotent.
+// |alarm| may not be NULL.
+void alarm_cancel(alarm_t* alarm);
+
+// Tests whether the |alarm| is scheduled.
+// Return true if the |alarm| is scheduled or NULL, otherwise false.
+bool alarm_is_scheduled(const alarm_t* alarm);
+
+// Registers |queue| for processing alarm callbacks on |thread|.
+// |queue| may not be NULL. |thread| may not be NULL.
+void alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread);
+
+// Unregisters |queue| for processing alarm callbacks on whichever thread
+// it is registered with. All alarms currently set for execution on |queue|
+// will be canceled. |queue| may not be NULL. This function is idempotent.
+void alarm_unregister_processing_queue(fixed_queue_t* queue);
+
+// Figure out how much time until next expiration.
+// Returns 0 if not armed. |alarm| may not be NULL.
+// TODO: Remove this function once PM timers can be re-factored
+period_ms_t alarm_get_remaining_ms(const alarm_t* alarm);
+
+// Cleanup the alarm internal state.
+// This function should be called by the OSI module cleanup during
+// graceful shutdown.
+void alarm_cleanup(void);
+
+// Dump alarm-related statistics and debug info to the |fd| file descriptor.
+// The information is in user-readable text format. The |fd| must be valid.
+void alarm_debug_dump(int fd);
diff --git a/mtkbt/code/bt/osi/include/allocation_tracker.h b/mtkbt/code/bt/osi/include/allocation_tracker.h
new file mode 100755
index 0000000..1e3fa07
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/allocation_tracker.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct allocation_tracker_t allocation_tracker_t;
+typedef uint8_t allocator_id_t;
+
+// Initialize the allocation tracker. If you do not call this function,
+// the allocation tracker functions do nothing but are still safe to call.
+void allocation_tracker_init(void);
+
+// Reset the allocation tracker. Don't call this in the normal course of
+// operations. Useful mostly for testing.
+void allocation_tracker_reset(void);
+
+// Expects that there are no allocations at the time of this call. Dumps
+// information about unfreed allocations to the log. Returns the amount of
+// unallocated memory.
+size_t allocation_tracker_expect_no_allocations(void);
+
+// Notify the tracker of a new allocation belonging to |allocator_id|.
+// If |ptr| is NULL, this function does nothing. |requested_size| is the
+// size of the allocation without any canaries. The caller must allocate
+// enough memory for canaries; the total allocation size can be determined
+// by calling |allocation_tracker_resize_for_canary|. Returns |ptr| offset
+// to the the beginning of the uncanaried region.
+void* allocation_tracker_notify_alloc(allocator_id_t allocator_id, void* ptr,
+ size_t requested_size);
+
+// Notify the tracker of an allocation that is being freed. |ptr| must be a
+// pointer returned by a call to |allocation_tracker_notify_alloc| with the
+// same |allocator_id|. If |ptr| is NULL, this function does nothing. Returns
+// |ptr| offset to the real beginning of the allocation including any canary
+// space.
+void* allocation_tracker_notify_free(allocator_id_t allocator_id, void* ptr);
+
+// Get the full size for an allocation, taking into account the size of
+// canaries.
+size_t allocation_tracker_resize_for_canary(size_t size);
diff --git a/mtkbt/code/bt/osi/include/allocator.h b/mtkbt/code/bt/osi/include/allocator.h
new file mode 100755
index 0000000..ef03f9a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/allocator.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef void* (*alloc_fn)(size_t size);
+typedef void (*free_fn)(void* ptr);
+
+typedef struct {
+ alloc_fn alloc;
+ free_fn free;
+} allocator_t;
+
+// allocator_t abstractions for the osi_*alloc and osi_free functions
+extern const allocator_t allocator_malloc;
+extern const allocator_t allocator_calloc;
+
+char* osi_strdup(const char* str);
+char* osi_strndup(const char* str, size_t len);
+
+void* osi_malloc(size_t size);
+void* osi_calloc(size_t size);
+void osi_free(void* ptr);
+
+// Free a buffer that was previously allocated with function |osi_malloc|
+// or |osi_calloc| and reset the pointer to that buffer to NULL.
+// |p_ptr| is a pointer to the buffer pointer to be reset.
+// |p_ptr| cannot be NULL.
+void osi_free_and_reset(void** p_ptr);
+
+// Dump allocation-related statistics and debug info to the |fd| file
+// descriptor.
+// The information is in user-readable text format. The |fd| must be valid.
+void osi_allocator_debug_dump(int fd);
diff --git a/mtkbt/code/bt/osi/include/array.h b/mtkbt/code/bt/osi/include/array.h
new file mode 100755
index 0000000..bdae2fa
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/array.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct array_t array_t;
+
+// Returns a new array object that stores elements of size |element_size|. The
+// returned object must be freed with |array_free|. |element_size| must be
+// greater than 0. Returns NULL on failure.
+array_t* array_new(size_t element_size);
+
+// Frees an array that was allocated with |array_new|. |array| may be NULL.
+void array_free(array_t* array);
+
+// Returns a pointer to the first stored element in |array|. |array| must not be
+// NULL.
+void* array_ptr(const array_t* array);
+
+// Returns a pointer to the |index|th element of |array|. |index| must be less
+// than the array's length. |array| must not be NULL.
+void* array_at(const array_t* array, size_t index);
+
+// Returns the number of elements stored in |array|. |array| must not be NULL.
+size_t array_length(const array_t* array);
+
+// Inserts an element to the end of |array| by value. For example, a caller
+// may simply call array_append_value(array, 5) instead of storing 5 into a
+// variable and then inserting by pointer. Although |value| is a uint32_t,
+// only the lowest |element_size| bytes will be stored. |array| must not be
+// NULL. Returns true if the element could be inserted into the array, false
+// on error.
+bool array_append_value(array_t* array, uint32_t value);
+
+// Inserts an element to the end of |array|. The value pointed to by |data| must
+// be at least |element_size| bytes long and will be copied into the array.
+// Neither |array| nor |data| may be NULL. Returns true if the element could be
+// inserted into the array, false on error.
+bool array_append_ptr(array_t* array, void* data);
diff --git a/mtkbt/code/bt/osi/include/buffer.h b/mtkbt/code/bt/osi/include/buffer.h
new file mode 100755
index 0000000..b81c9e9
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/buffer.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef struct buffer_t buffer_t;
+
+// Returns a new buffer of |size| bytes. Returns NULL if a buffer could not be
+// allocated. |size| must be non-zero. The caller must release this buffer with
+// |buffer_free|.
+buffer_t* buffer_new(size_t size);
+
+// Creates a new reference to the buffer |buf|. A reference is indistinguishable
+// from the original: writes to the original will be reflected in the reference
+// and vice versa. In other words, this function creates an alias to |buf|. The
+// caller must release the returned buffer with |buffer_free|. Note that
+// releasing the returned buffer does not release |buf|. |buf| must not be NULL.
+buffer_t* buffer_new_ref(const buffer_t* buf);
+
+// Creates a new reference to the last |slice_size| bytes of |buf|. See
+// |buffer_new_ref| for a description of references. |slice_size| must be
+// greater than 0 and may be at most |buffer_length|
+// (0 < slice_size <= buffer_length). |buf| must not be NULL.
+buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size);
+
+// Frees a buffer object. |buf| may be NULL.
+void buffer_free(buffer_t* buf);
+
+// Returns a pointer to a writeable memory region for |buf|. All references
+// and slices that share overlapping bytes will also be written to when
+// writing to the returned pointer. The caller may safely write up to
+// |buffer_length| consecutive bytes starting at the address returned by
+// this function. |buf| must not be NULL.
+void* buffer_ptr(const buffer_t* buf);
+
+// Returns the length of the writeable memory region referred to by |buf|.
+// |buf| must not be NULL.
+size_t buffer_length(const buffer_t* buf);
diff --git a/mtkbt/code/bt/osi/include/compat.h b/mtkbt/code/bt/osi/include/compat.h
new file mode 100755
index 0000000..95fe037
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/compat.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <features.h>
+#include <sys/types.h>
+
+#if __GLIBC__
+
+#include <unistd.h>
+
+/* Get thread identification. */
+pid_t gettid(void);
+
+/* Copy src to string dst of size siz. */
+size_t strlcpy(char* dst, const char* src, size_t siz);
+
+/* Appends src to string dst of size siz. */
+size_t strlcat(char* dst, const char* src, size_t siz);
+
+#endif
diff --git a/mtkbt/code/bt/osi/include/config.h b/mtkbt/code/bt/osi/include/config.h
new file mode 100755
index 0000000..0ca4b3a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/config.h
@@ -0,0 +1,150 @@
+#pragma once
+
+// This module implements a configuration parser. Clients can query the
+// contents of a configuration file through the interface provided here.
+// The current implementation is read-only; mutations are only kept in
+// memory. This parser supports the INI file format.
+
+// Implementation notes:
+// - Key/value pairs that are not within a section are assumed to be under
+// the |CONFIG_DEFAULT_SECTION| section.
+// - Multiple sections with the same name will be merged as if they were in
+// a single section.
+// - Empty sections with no key/value pairs will be treated as if they do
+// not exist. In other words, |config_has_section| will return false for
+// empty sections.
+// - Duplicate keys in a section will overwrite previous values.
+// - All strings are case sensitive.
+
+#include <stdbool.h>
+
+// The default section name to use if a key/value pair is not defined within
+// a section.
+#define CONFIG_DEFAULT_SECTION "Global"
+
+typedef struct config_t config_t;
+typedef struct config_section_node_t config_section_node_t;
+
+// Creates a new config object with no entries (i.e. not backed by a file).
+// This function returns a config object or NULL on error. Clients must call
+// |config_free| on the returned handle when it is no longer required.
+config_t* config_new_empty(void);
+
+// Loads the specified file and returns a handle to the config file. If there
+// was a problem loading the file or allocating memory, this function returns
+// NULL. Clients must call |config_free| on the returned handle when it is no
+// longer required. |filename| must not be NULL and must point to a readable
+// file on the filesystem.
+config_t* config_new(const char* filename);
+
+// Clones |src|, including all of it's sections, keys, and values.
+// Returns a new config which is a copy and separated from the original;
+// changes to the new config are not reflected in any way in the original.
+//
+// |src| must not be NULL
+// This function will not return NULL.
+// Clients must call config_free on the returned object.
+config_t* config_new_clone(const config_t* src);
+
+// Frees resources associated with the config file. No further operations may
+// be performed on the |config| object after calling this function. |config|
+// may be NULL.
+void config_free(config_t* config);
+
+// Returns true if the config file contains a section named |section|. If
+// the section has no key/value pairs in it, this function will return false.
+// |config| and |section| must not be NULL.
+bool config_has_section(const config_t* config, const char* section);
+
+// Returns true if the config file has a key named |key| under |section|.
+// Returns false otherwise. |config|, |section|, and |key| must not be NULL.
+bool config_has_key(const config_t* config, const char* section,
+ const char* key);
+
+// Returns the integral value for a given |key| in |section|. If |section|
+// or |key| do not exist, or the value cannot be fully converted to an integer,
+// this function returns |def_value|. |config|, |section|, and |key| must not
+// be NULL.
+int config_get_int(const config_t* config, const char* section, const char* key,
+ int def_value);
+
+// Returns the boolean value for a given |key| in |section|. If |section|
+// or |key| do not exist, or the value cannot be converted to a boolean, this
+// function returns |def_value|. |config|, |section|, and |key| must not be
+// NULL.
+bool config_get_bool(const config_t* config, const char* section,
+ const char* key, bool def_value);
+
+// Returns the string value for a given |key| in |section|. If |section| or
+// |key| do not exist, this function returns |def_value|. The returned string
+// is owned by the config module and must not be freed. |config|, |section|,
+// and |key| must not be NULL. |def_value| may be NULL.
+const char* config_get_string(const config_t* config, const char* section,
+ const char* key, const char* def_value);
+
+// Sets an integral value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, and |key|
+// must not be NULL.
+void config_set_int(config_t* config, const char* section, const char* key,
+ int value);
+
+// Sets a boolean value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, and |key|
+// must not be NULL.
+void config_set_bool(config_t* config, const char* section, const char* key,
+ bool value);
+
+// Sets a string value for the |key| in |section|. If |key| or |section| do
+// not already exist, this function creates them. |config|, |section|, |key|,
+// and
+// |value| must not be NULL.
+void config_set_string(config_t* config, const char* section, const char* key,
+ const char* value);
+
+// Removes |section| from the |config| (and, as a result, all keys in the
+// section).
+// Returns true if |section| was found and removed from |config|, false
+// otherwise.
+// Neither |config| nor |section| may be NULL.
+bool config_remove_section(config_t* config, const char* section);
+
+// Removes one specific |key| residing in |section| of the |config|. Returns
+// true
+// if the section and key were found and the key was removed, false otherwise.
+// None of |config|, |section|, or |key| may be NULL.
+bool config_remove_key(config_t* config, const char* section, const char* key);
+
+// Returns an iterator to the first section in the config file. If there are no
+// sections, the iterator will equal the return value of |config_section_end|.
+// The returned pointer must be treated as an opaque handle and must not be
+// freed.
+// The iterator is invalidated on any config mutating operation. |config| may
+// not be NULL.
+const config_section_node_t* config_section_begin(const config_t* config);
+
+// Returns an iterator to one past the last section in the config file. It does
+// not represent a valid section, but can be used to determine if all sections
+// have been iterated over. The returned pointer must be treated as an opaque
+// handle and must not be freed and must not be iterated on (must not call
+// |config_section_next| on it). |config| may not be NULL.
+const config_section_node_t* config_section_end(const config_t* config);
+
+// Moves |iter| to the next section. If there are no more sections, |iter| will
+// equal the value of |config_section_end|. |iter| may not be NULL and must be
+// a pointer returned by either |config_section_begin| or |config_section_next|.
+const config_section_node_t* config_section_next(
+ const config_section_node_t* iter);
+
+// Returns the name of the section referred to by |iter|. The returned pointer
+// is owned by the config module and must not be freed by the caller. The
+// pointer will remain valid until |config_free| is called. |iter| may not be
+// NULL and must not equal the value returned by |config_section_end|.
+const char* config_section_name(const config_section_node_t* iter);
+
+// Saves |config| to a file given by |filename|. Note that this could be a
+// destructive operation: if |filename| already exists, it will be overwritten.
+// The config module does not preserve comments or formatting so if a config
+// file was opened with |config_new| and subsequently overwritten with
+// |config_save|, all comments and special formatting in the original file will
+// be lost. Neither |config| nor |filename| may be NULL.
+bool config_save(const config_t* config, const char* filename);
diff --git a/mtkbt/code/bt/osi/include/data_dispatcher.h b/mtkbt/code/bt/osi/include/data_dispatcher.h
new file mode 100755
index 0000000..7c231f8
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/data_dispatcher.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/fixed_queue.h"
+
+#define DISPATCHER_NAME_MAX 16
+
+typedef struct data_dispatcher_t data_dispatcher_t;
+typedef uintptr_t data_dispatcher_type_t;
+
+// Creates a new data dispatcher object, with the given name.
+// The returned object must be freed by calling |data_dispatcher_free|.
+// Returns NULL on failure. |name| may not be NULL.
+data_dispatcher_t* data_dispatcher_new(const char* name);
+
+// Frees a data dispatcher object created by |data_dispatcher_new|.
+// |data_dispatcher| may be NULL.
+void data_dispatcher_free(data_dispatcher_t* dispatcher);
+
+// Registers |type| and |queue| with the data dispatcher so that data
+// sent under |type| ends up in |queue|. If |type| is already registered,
+// it is replaced. If |queue| is NULL, the existing registration is
+// removed, if it exists. |dispatcher| may not be NULL.
+void data_dispatcher_register(data_dispatcher_t* dispatcher,
+ data_dispatcher_type_t type,
+ fixed_queue_t* queue);
+
+// Registers a default queue to send data to when there is not a specific
+// type/queue relationship registered. If a default queue is already registered,
+// it is replaced. If |queue| is NULL, the existing registration is
+// removed, if it exists. |dispatcher| may not be NULL.
+void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
+ fixed_queue_t* queue);
+
+// Dispatches |data| to the queue registered for |type|. If no such registration
+// exists, it is dispatched to the default queue if it exists.
+// Neither |dispatcher| nor |data| may be NULL.
+// Returns true if data dispatch was successful.
+bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
+ data_dispatcher_type_t type, void* data);
diff --git a/mtkbt/code/bt/osi/include/fixed_queue.h b/mtkbt/code/bt/osi/include/fixed_queue.h
new file mode 100755
index 0000000..6b98f7e
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/fixed_queue.h
@@ -0,0 +1,133 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "osi/include/list.h"
+
+struct fixed_queue_t;
+typedef struct fixed_queue_t fixed_queue_t;
+typedef struct reactor_t reactor_t;
+
+typedef void (*fixed_queue_free_cb)(void* data);
+typedef void (*fixed_queue_cb)(fixed_queue_t* queue, void* context);
+
+// Creates a new fixed queue with the given |capacity|. If more elements than
+// |capacity| are added to the queue, the caller is blocked until space is
+// made available in the queue. Returns NULL on failure. The caller must free
+// the returned queue with |fixed_queue_free|.
+fixed_queue_t* fixed_queue_new(size_t capacity);
+
+// Frees a queue and (optionally) the enqueued elements.
+// |queue| is the queue to free. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
+// Freeing a queue that is currently in use (i.e. has waiters
+// blocked on it) results in undefined behaviour.
+void fixed_queue_free(fixed_queue_t* queue, fixed_queue_free_cb free_cb);
+
+// Flushes a queue and (optionally) frees the enqueued elements.
+// |queue| is the queue to flush. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
+void fixed_queue_flush(fixed_queue_t* queue, fixed_queue_free_cb free_cb);
+
+// Returns a value indicating whether the given |queue| is empty. If |queue|
+// is NULL, the return value is true.
+bool fixed_queue_is_empty(fixed_queue_t* queue);
+
+// Returns the length of the |queue|. If |queue| is NULL, the return value
+// is 0.
+size_t fixed_queue_length(fixed_queue_t* queue);
+
+// Returns the maximum number of elements this queue may hold. |queue| may
+// not be NULL.
+size_t fixed_queue_capacity(fixed_queue_t* queue);
+
+// Enqueues the given |data| into the |queue|. The caller will be blocked
+// if no more space is available in the queue. Neither |queue| nor |data|
+// may be NULL.
+void fixed_queue_enqueue(fixed_queue_t* queue, void* data);
+
+// Dequeues the next element from |queue|. If the queue is currently empty,
+// this function will block the caller until an item is enqueued. This
+// function will never return NULL. |queue| may not be NULL.
+void* fixed_queue_dequeue(fixed_queue_t* queue);
+
+// Tries to enqueue |data| into the |queue|. This function will never block
+// the caller. If the queue capacity would be exceeded by adding one more
+// element, this function returns false immediately. Otherwise, this function
+// returns true. Neither |queue| nor |data| may be NULL.
+bool fixed_queue_try_enqueue(fixed_queue_t* queue, void* data);
+
+// Tries to dequeue an element from |queue|. This function will never block
+// the caller. If the queue is empty or NULL, this function returns NULL
+// immediately. Otherwise, the next element in the queue is returned.
+void* fixed_queue_try_dequeue(fixed_queue_t* queue);
+
+// Returns the first element from |queue|, if present, without dequeuing it.
+// This function will never block the caller. Returns NULL if there are no
+// elements in the queue or |queue| is NULL.
+void* fixed_queue_try_peek_first(fixed_queue_t* queue);
+
+// Returns the last element from |queue|, if present, without dequeuing it.
+// This function will never block the caller. Returns NULL if there are no
+// elements in the queue or |queue| is NULL.
+void* fixed_queue_try_peek_last(fixed_queue_t* queue);
+
+// Tries to remove a |data| element from the middle of the |queue|. This
+// function will never block the caller. If the queue is empty or NULL, this
+// function returns NULL immediately. |data| may not be NULL. If the |data|
+// element is found in the queue, a pointer to the removed data is returned,
+// otherwise NULL.
+void* fixed_queue_try_remove_from_queue(fixed_queue_t* queue, void* data);
+
+// Returns the iterateable list with all entries in the |queue|. This function
+// will never block the caller. |queue| may not be NULL.
+//
+// NOTE: The return result of this function is not thread safe: the list could
+// be modified by another thread, and the result would be unpredictable.
+// TODO: The usage of this function should be refactored, and the function
+// itself should be removed.
+list_t* fixed_queue_get_list(fixed_queue_t* queue);
+
+// This function returns a valid file descriptor. Callers may perform one
+// operation on the fd: select(2). If |select| indicates that the file
+// descriptor is readable, the caller may call |fixed_queue_enqueue| without
+// blocking. The caller must not close the returned file descriptor. |queue|
+// may not be NULL.
+int fixed_queue_get_enqueue_fd(const fixed_queue_t* queue);
+
+// This function returns a valid file descriptor. Callers may perform one
+// operation on the fd: select(2). If |select| indicates that the file
+// descriptor is readable, the caller may call |fixed_queue_dequeue| without
+// blocking. The caller must not close the returned file descriptor. |queue|
+// may not be NULL.
+int fixed_queue_get_dequeue_fd(const fixed_queue_t* queue);
+
+// Registers |queue| with |reactor| for dequeue operations. When there is an
+// element in the queue, ready_cb will be called. The |context| parameter is
+// passed, untouched, to the callback routine. Neither |queue|, nor |reactor|,
+// nor |read_cb| may be NULL. |context| may be NULL.
+void fixed_queue_register_dequeue(fixed_queue_t* queue, reactor_t* reactor,
+ fixed_queue_cb ready_cb, void* context);
+
+// Unregisters the dequeue ready callback for |queue| from whichever reactor
+// it is registered with, if any. This function is idempotent.
+void fixed_queue_unregister_dequeue(fixed_queue_t* queue);
diff --git a/mtkbt/code/bt/osi/include/future.h b/mtkbt/code/bt/osi/include/future.h
new file mode 100755
index 0000000..3ed1a21
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/future.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+typedef struct future_t future_t;
+
+#define FUTURE_SUCCESS ((void*)1)
+#define FUTURE_FAIL ((void*)0)
+
+// Constructs a new future_t object. Returns NULL on failure.
+future_t* future_new(void);
+
+// Constructs a new future_t object with an immediate |value|. No waiting will
+// occur in the call to |future_await| because the value is already present.
+// Returns NULL on failure.
+future_t* future_new_immediate(void* value);
+
+// Signals that the |future| is ready, passing |value| back to the context
+// waiting for the result. Must only be called once for every future.
+// |future| may not be NULL.
+void future_ready(future_t* future, void* value);
+
+// Waits for the |future| to be ready. Returns the value set in |future_ready|.
+// Frees the future before return. |future| may not be NULL.
+void* future_await(future_t* async_result);
diff --git a/mtkbt/code/bt/osi/include/hash_map_utils.h b/mtkbt/code/bt/osi/include/hash_map_utils.h
new file mode 100755
index 0000000..1ea3996
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/hash_map_utils.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+// Creates a hash map based on the |params| string containing key and value
+// pairs. Pairs are expected in the form "key=value" separated by the ';'
+// character. Both ';' and '=' characters are invalid in keys or values.
+// |params| cannot be NULL, is not modified and is owned by the caller.
+// Examples:
+// "key0=value10;key1=value1;" -> map: [key0]="value0" [key1]="value1"
+// "key0=;key1=value1;" -> map: [key0]="" [key1]="value1"
+// "=value0;key1=value1;" -> map: [key1]="value1"
+// A new hash map or NULL is returned and is owned by the caller.
+std::unordered_map<std::string, std::string>
+hash_map_utils_new_from_string_params(const char* params);
+
+// Dumps the contents of the hash_map to the log for debugging purposes.
+// If |map| is not NULL, all entries of |map| will be dumped, otherwise nothing
+// will be dumped. Note that this function does not take the ownership of |map|.
+void hash_map_utils_dump_string_keys_string_values(
+ std::unordered_map<std::string, std::string>& map);
diff --git a/mtkbt/code/bt/osi/include/leaky_bonded_queue.h b/mtkbt/code/bt/osi/include/leaky_bonded_queue.h
new file mode 100755
index 0000000..8259cdc
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/leaky_bonded_queue.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <queue>
+
+namespace system_bt_osi {
+
+/*
+ * LeakyBondedQueue<T>
+ *
+ * - LeakyLondedQueue<T> is a fixed size queue that leaks oldest item when
+ * reaching its capacity. This is useful in creating memory bonded data
+ * structure where freshness is more important than full coverage.
+ * - The queue is protected by a simple mutex and is thread-safe, although
+ * improvements could be made to lock enqueue and dequeue separately, it
+ * is not implemented at this moment due to lack of demand
+ * - The queue uses unique_ptr to automatically free its content when it is
+ * destructed. It is the user's responsibility to implement T's destructor
+ * correctly.
+ *
+ */
+template <class T>
+class LeakyBondedQueue {
+ public:
+ LeakyBondedQueue(size_t capacity);
+ /* Default destructor
+ *
+ * Call Clear() and free the queue structure itself
+ */
+ ~LeakyBondedQueue();
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, pop
+ * the oldest item
+ */
+ void Enqueue(T* new_item);
+ /*
+ * Add item NEW_ITEM to the underlining queue. If the queue is full, dequeue
+ * the oldest item and returns it to the caller. Return nullptr otherwise.
+ */
+ T* EnqueueWithPop(T* new_item);
+ /*
+ * Dequeues the oldest item from the queue. Return nullptr if queue is empty
+ */
+ T* Dequeue();
+ /*
+ * Returns the length of queue
+ */
+ size_t Length();
+ /*
+ * Returns the defined capacity of the queue
+ */
+ size_t Capacity();
+ /*
+ * Returns whether the queue is empty
+ */
+ bool Empty();
+ /*
+ * Pops all items from the queue
+ */
+ void Clear();
+
+ private:
+ // Put item in unique_ptr so that they get freed automatically when poped or
+ // when queue_ is freed
+ std::queue<std::unique_ptr<T>> queue_;
+ std::mutex lock_;
+ size_t capacity_;
+};
+
+/*
+* Definitions must be in the header for template classes
+*/
+
+template <class T>
+LeakyBondedQueue<T>::LeakyBondedQueue(size_t capacity) {
+ capacity_ = capacity;
+}
+
+template <class T>
+LeakyBondedQueue<T>::~LeakyBondedQueue() {}
+
+template <class T>
+void LeakyBondedQueue<T>::Enqueue(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ if ((queue_.size() + 1) > capacity_) {
+ queue_.pop();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::EnqueueWithPop(T* new_item) {
+ std::lock_guard<std::mutex> lock(lock_);
+ T* old_item = nullptr;
+ if ((queue_.size() + 1) > capacity_) {
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ old_item = item.release();
+ }
+ std::unique_ptr<T> item_ptr(new_item);
+ queue_.push(std::move(item_ptr));
+ return old_item;
+}
+
+template <class T>
+T* LeakyBondedQueue<T>::Dequeue() {
+ std::lock_guard<std::mutex> lock(lock_);
+ std::unique_ptr<T> item = std::move(queue_.front());
+ queue_.pop();
+ return item.release();
+}
+
+template <class T>
+void LeakyBondedQueue<T>::Clear() {
+ std::lock_guard<std::mutex> lock(lock_);
+ while (!queue_.empty()) {
+ // unique_ptr does not need to be freed
+ queue_.pop();
+ }
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Length() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.size();
+}
+
+template <class T>
+size_t LeakyBondedQueue<T>::Capacity() {
+ return capacity_;
+}
+
+template <class T>
+bool LeakyBondedQueue<T>::Empty() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return queue_.empty();
+}
+
+} // namespace system_bt_osi
diff --git a/mtkbt/code/bt/osi/include/list.h b/mtkbt/code/bt/osi/include/list.h
new file mode 100755
index 0000000..50c3e2c
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/list.h
@@ -0,0 +1,139 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct list_node_t;
+typedef struct list_node_t list_node_t;
+
+struct list_t;
+typedef struct list_t list_t;
+
+typedef void (*list_free_cb)(void* data);
+
+// Iterator callback prototype used for |list_foreach|.
+// |data| represents the list item currently being iterated, |context| is a
+// user defined value passed into |list_foreach|.
+// Callback must return true to continue iterating or false to stop iterating.
+typedef bool (*list_iter_cb)(void* data, void* context);
+
+// Returns a new, empty list. Returns NULL if not enough memory could be
+// allocated for the list structure. The returned list must be freed with
+// |list_free|. The |callback| specifies a function to be called whenever a
+// list element is removed from the list. It can be used to release resources
+// held by the list element, e.g. memory or file descriptor. |callback| may
+// be NULL if no cleanup is necessary on element removal.
+list_t* list_new(list_free_cb callback);
+
+// Frees the list. This function accepts NULL as an argument, in which case it
+// behaves like a no-op.
+void list_free(list_t* list);
+
+// Returns true if |list| is empty (has no elements), false otherwise.
+// |list| may not be NULL.
+bool list_is_empty(const list_t* list);
+
+// Returns true if the list contains |data|, false otherwise.
+// |list| may not be NULL.
+bool list_contains(const list_t* list, const void* data);
+
+// Returns the length of the |list|. |list| may not be NULL.
+size_t list_length(const list_t* list);
+
+// Returns the first element in the list without removing it. |list| may not
+// be NULL or empty.
+void* list_front(const list_t* list);
+
+// Returns the last element in the list without removing it. |list| may not
+// be NULL or empty.
+void* list_back(const list_t* list);
+
+// Returns the last node in the list without removing it. |list| may not
+// be NULL or empty.
+list_node_t* list_back_node(const list_t* list);
+
+// Inserts |data| after |prev_node| in |list|. |data|, |list|, and |prev_node|
+// may not be NULL. This function does not make a copy of |data| so the pointer
+// must remain valid at least until the element is removed from the list or the
+// list is freed. Returns true if |data| could be inserted, false otherwise
+// (e.g. out of memory).
+bool list_insert_after(list_t* list, list_node_t* prev_node, void* data);
+
+// Inserts |data| at the beginning of |list|. Neither |data| nor |list| may be
+// NULL.
+// This function does not make a copy of |data| so the pointer must remain valid
+// at least until the element is removed from the list or the list is freed.
+// Returns true if |data| could be inserted, false otherwise (e.g. out of
+// memory).
+bool list_prepend(list_t* list, void* data);
+
+// Inserts |data| at the end of |list|. Neither |data| nor |list| may be NULL.
+// This function does not make a copy of |data| so the pointer must remain valid
+// at least until the element is removed from the list or the list is freed.
+// Returns true if |data| could be inserted, false otherwise (e.g. out of
+// memory).
+bool list_append(list_t* list, void* data);
+
+// Removes |data| from the list. Neither |list| nor |data| may be NULL. If
+// |data|
+// is inserted multiple times in the list, this function will only remove the
+// first instance. If a free function was specified in |list_new|, it will be
+// called back with |data|. This function returns true if |data| was found in
+// the list and removed, false otherwise.
+bool list_remove(list_t* list, void* data);
+
+// Removes all elements in the list. Calling this function will return the list
+// to the
+// same state it was in after |list_new|. |list| may not be NULL.
+void list_clear(list_t* list);
+
+// Iterates through the |list| and calls |callback| for each data element.
+// Iteration continues until |callback| returns false. The function returns the
+// pointer to last processed element, or NULL if the list is empty, or all calls
+// to |callback| returned true. |context| is passed to |callback| on each
+// iteration.
+// If the list is empty, |callback| will never be called. It is safe to mutate
+// the list inside the callback. If an element is added before the node being
+// visited, there will be no callback for the newly-inserted node. Neither
+// |list| nor |callback| may be NULL.
+list_node_t* list_foreach(const list_t* list, list_iter_cb callback,
+ void* context);
+
+// Returns an iterator to the first element in |list|. |list| may not be NULL.
+// The returned iterator is valid as long as it does not equal the value
+// returned by |list_end|.
+list_node_t* list_begin(const list_t* list);
+
+// Returns an iterator that points past the end of the list. In other words,
+// this function returns the value of an invalid iterator for the given list.
+// When an iterator has the same value as what's returned by this function, you
+// may no longer call |list_next| with the iterator. |list| may not be NULL.
+list_node_t* list_end(const list_t* list);
+
+// Given a valid iterator |node|, this function returns the next value for the
+// iterator. If the returned value equals the value returned by |list_end|, the
+// iterator has reached the end of the list and may no longer be used for any
+// purpose.
+list_node_t* list_next(const list_node_t* node);
+
+// Returns the value stored at the location pointed to by the iterator |node|.
+// |node| must not equal the value returned by |list_end|.
+void* list_node(const list_node_t* node);
diff --git a/mtkbt/code/bt/osi/include/log.h b/mtkbt/code/bt/osi/include/log.h
new file mode 100755
index 0000000..d42ea62
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/log.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+/*
+ * TODO(armansito): Work-around until we figure out a way to generate logs in a
+ * platform-independent manner.
+ */
+#if defined(OS_GENERIC)
+
+/* syslog didn't work well here since we would be redefining LOG_DEBUG. */
+#include <stdio.h>
+
+#define LOGWRAPPER(tag, fmt, args...) \
+ fprintf(stderr, "%s: " fmt "\n", tag, ##args)
+
+#define LOG_VERBOSE(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_ERROR(...) LOGWRAPPER(__VA_ARGS__)
+
+#define LOG_EVENT_INT(...)
+
+#else /* !defined(OS_GENERIC) */
+
+#include <log/log.h>
+
+/**
+ * These log statements are effectively executing only ALOG(_________, tag, fmt,
+ * ## args ).
+ * fprintf is only to cause compilation error when LOG_TAG is not provided,
+ * which breaks build on Linux (for OS_GENERIC).
+ */
+
+#if LOG_NDEBUG
+#define LOG_VERBOSE(tag, fmt, args...) \
+ do { \
+ (true) ? ((int)0) : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+#else // LOG_NDEBUG
+#define LOG_VERBOSE(tag, fmt, args...) \
+ do { \
+ (true) ? ALOG(LOG_VERBOSE, tag, fmt, ##args) \
+ : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+#endif // !LOG_NDEBUG
+
+#define LOG_DEBUG(tag, fmt, args...) \
+ do { \
+ (true) ? ALOG(LOG_DEBUG, tag, fmt, ##args) \
+ : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+#define LOG_INFO(tag, fmt, args...) \
+ do { \
+ (true) ? ALOG(LOG_INFO, tag, fmt, ##args) \
+ : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+#define LOG_WARN(tag, fmt, args...) \
+ do { \
+ (true) ? ALOG(LOG_WARN, tag, fmt, ##args) \
+ : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+#define LOG_ERROR(tag, fmt, args...) \
+ do { \
+ (true) ? ALOG(LOG_ERROR, tag, fmt, ##args) \
+ : fprintf(stderr, "%s" fmt, tag, ##args); \
+ } while (0)
+
+#endif /* defined(OS_GENERIC) */
diff --git a/mtkbt/code/bt/osi/include/metrics.h b/mtkbt/code/bt/osi/include/metrics.h
new file mode 100755
index 0000000..dcd1a20
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/metrics.h
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+namespace system_bt_osi {
+
+// Typedefs to hide protobuf definition to the rest of stack
+
+typedef enum {
+ DEVICE_TYPE_UNKNOWN,
+ DEVICE_TYPE_BREDR,
+ DEVICE_TYPE_LE,
+ DEVICE_TYPE_DUMO,
+} device_type_t;
+
+typedef enum {
+ WAKE_EVENT_UNKNOWN,
+ WAKE_EVENT_ACQUIRED,
+ WAKE_EVENT_RELEASED,
+} wake_event_type_t;
+
+typedef enum {
+ SCAN_TYPE_UNKNOWN,
+ SCAN_TECH_TYPE_LE,
+ SCAN_TECH_TYPE_BREDR,
+ SCAN_TECH_TYPE_BOTH,
+} scan_tech_t;
+
+typedef enum {
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ CONNECTION_TECHNOLOGY_TYPE_LE,
+ CONNECTION_TECHNOLOGY_TYPE_BREDR,
+} connection_tech_t;
+
+typedef enum {
+ DISCONNECT_REASON_UNKNOWN,
+ DISCONNECT_REASON_METRICS_DUMP,
+ DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+} disconnect_reason_t;
+
+/* Values of A2DP metrics that we care about
+ *
+ * audio_duration_ms : sum of audio duration (in milliseconds).
+ * device_class: device class of the paired device.
+ * media_timer_min_ms : minimum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_max_ms: maximum scheduled time (in milliseconds)
+ * of the media timer.
+ * media_timer_avg_ms: average scheduled time (in milliseconds)
+ * of the media timer.
+ * buffer_overruns_max_count: TODO - not clear what this is.
+ * buffer_overruns_total : number of times the media buffer with
+ * audio data has overrun
+ * buffer_underruns_average: TODO - not clear what this is.
+ * buffer_underruns_count: number of times there was no enough
+ * audio data to add to the media buffer.
+ * NOTE: Negative values are invalid
+*/
+class A2dpSessionMetrics {
+ public:
+ A2dpSessionMetrics() {}
+
+ /*
+ * Update the metrics value in the current metrics object using the metrics
+ * objects supplied
+ */
+ void Update(const A2dpSessionMetrics& metrics);
+
+ /*
+ * Compare whether two metrics objects are equal
+ */
+ bool operator==(const A2dpSessionMetrics& rhs) const;
+
+ /*
+ * Initialize all values to -1 which is invalid in order to make a distinction
+ * between 0 and invalid values
+ */
+ int64_t audio_duration_ms = -1;
+ int32_t media_timer_min_ms = -1;
+ int32_t media_timer_max_ms = -1;
+ int32_t media_timer_avg_ms = -1;
+ int64_t total_scheduling_count = -1;
+ int32_t buffer_overruns_max_count = -1;
+ int32_t buffer_overruns_total = -1;
+ float buffer_underruns_average = -1;
+ int32_t buffer_underruns_count = -1;
+};
+
+class BluetoothMetricsLogger {
+ public:
+ static BluetoothMetricsLogger* GetInstance() {
+ static BluetoothMetricsLogger* instance = new BluetoothMetricsLogger();
+ return instance;
+ }
+
+ /*
+ * Record a pairing event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * device_class: class of remote device
+ * device_type: type of remote device
+ * disconnect_reason: HCI reason for pairing disconnection.
+ * See: stack/include/hcidefs.h
+ */
+ void LogPairEvent(uint32_t disconnect_reason, uint64_t timestamp_ms,
+ uint32_t device_class, device_type_t device_type);
+
+ /*
+ * Record a wake event
+ *
+ * Parameters:
+ * timestamp_ms: Unix epoch time in milliseconds
+ * type: whether it was acquired or released
+ * requestor: if provided is the service requesting the wake lock
+ * name: the name of the wake lock held
+ */
+ void LogWakeEvent(wake_event_type_t type, const std::string& requestor,
+ const std::string& name, uint64_t timestamp_ms);
+
+ /*
+ * Record a scan event
+ *
+ * Parameters
+ * timestamp_ms : Unix epoch time in milliseconds
+ * start : true if this is the beginning of the scan
+ * initiator: a unique ID identifying the app starting the scan
+ * type: whether the scan reports BR/EDR, LE, or both.
+ * results: number of results to be reported.
+ */
+ void LogScanEvent(bool start, const std::string& initator, scan_tech_t type,
+ uint32_t results, uint64_t timestamp_ms);
+
+ /*
+ * Start logging a Bluetooth session
+ *
+ * A Bluetooth session is defined a a connection between this device and
+ * another remote device which may include multiple profiles and protocols
+ *
+ * Only one Bluetooth session can exist at one time. Calling this method twice
+ * without LogBluetoothSessionEnd will result in logging a premature end of
+ * current Bluetooth session
+ *
+ * Parameters:
+ * connection_tech_type : type of connection technology
+ * timestamp_ms : the timestamp for session start, 0 means now
+ *
+ */
+ void LogBluetoothSessionStart(connection_tech_t connection_tech_type,
+ uint64_t timestamp_ms);
+
+ /*
+ * Stop logging a Bluetooth session and pushes it to the log queue
+ *
+ * If no Bluetooth session exist, this method exits immediately
+ *
+ * Parameters:
+ * disconnect_reason : A string representation of disconnect reason
+ * timestamp_ms : the timestamp of session end, 0 means now
+ *
+ */
+ void LogBluetoothSessionEnd(disconnect_reason_t disconnect_reason,
+ uint64_t timestamp_ms);
+
+ /*
+ * Log information about remote device in a current Bluetooth session
+ *
+ * If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * device_class : device_class defined in btm_api_types.h
+ * device_type : type of remote device
+ */
+ void LogBluetoothSessionDeviceInfo(uint32_t device_class,
+ device_type_t device_type);
+
+ /*
+ * Log A2DP Audio Session Information
+ *
+ * - Repeated calls to this method will override previous metrics if in the
+ * same Bluetooth connection
+ * - If a Bluetooth session does not exist, create one with default parameter
+ * and timestamp now
+ *
+ * Parameters:
+ * a2dp_session_metrics - pointer to struct holding a2dp stats
+ *
+ */
+ void LogA2dpSession(const A2dpSessionMetrics& a2dp_session_metrics);
+
+ /*
+ * Writes the metrics, in base64 protobuf format, into the descriptor FD
+ * If CLEAR is true, metrics events are cleared afterwards.
+ */
+ void WriteBase64(int fd, bool clear);
+ void WriteBase64String(std::string* serialized, bool clear);
+ void WriteString(std::string* serialized, bool clear);
+
+ /*
+ * Reset the metrics logger by cleaning up its staging queues and existing
+ * protobuf objects.
+ */
+ void Reset();
+
+ /*
+ * Maximum number of log entries for each session or event
+ */
+ static const size_t kMaxNumBluetoothSession = 50;
+ static const size_t kMaxNumPairEvent = 50;
+ static const size_t kMaxNumWakeEvent = 1000;
+ static const size_t kMaxNumScanEvent = 50;
+
+ private:
+ BluetoothMetricsLogger();
+
+ /*
+ * When a Bluetooth session is on and the user initiates a metrics dump, we
+ * need to be able to upload whatever we have first. This method breaks the
+ * ongoing Bluetooth session into two sessions with the previous one labeled
+ * as "METRICS_DUMP" for the disconnect reason.
+ */
+ void CutoffSession();
+
+ /*
+ * Build the internal metrics object using information gathered
+ */
+ void Build();
+
+ /*
+ * Reset objects related to current Bluetooth session
+ */
+ void ResetSession();
+
+ /*
+ * Reset the underlining BluetoothLog object
+ */
+ void ResetLog();
+
+ /*
+ * PIMPL style implementation to hide internal dependencies
+ */
+ struct impl;
+ std::unique_ptr<impl> const pimpl_;
+};
+}
diff --git a/mtkbt/code/bt/osi/include/mutex.h b/mtkbt/code/bt/osi/include/mutex.h
new file mode 100755
index 0000000..bf00983
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/mutex.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+// Lock the global mutex
+void mutex_global_lock(void);
+
+// Unlock the global mutex
+void mutex_global_unlock(void);
diff --git a/mtkbt/code/bt/osi/include/osi.h b/mtkbt/code/bt/osi/include/osi.h
new file mode 100755
index 0000000..3359cbf
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/osi.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define UNUSED_ATTR __attribute__((unused))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define INVALID_FD (-1)
+
+#define CONCAT(a, b) a##b
+
+// Use during compile time to check conditional values
+// NOTE: The the failures will present as a generic error
+// "error: initialization makes pointer from integer without a cast"
+// but the file and line number will present the condition that
+// failed.
+#define DUMMY_COUNTER(c) CONCAT(__osi_dummy_, c)
+#define DUMMY_PTR DUMMY_COUNTER(__COUNTER__)
+
+// base/macros.h defines a COMPILE_ASSERT macro to the C++11 keyword
+// "static_assert" (it undef's COMPILE_ASSERT before redefining it).
+// C++ code that includes base and osi/include/osi.h can thus easily default to
+// the definition from libbase but we should check here to avoid compile errors.
+#ifndef COMPILE_ASSERT
+#define COMPILE_ASSERT(COND) \
+ typedef int failed_compile_assert[(COND) ? 1 : -1] __attribute__((unused))
+#endif // COMPILE_ASSERT
+
+// Macros for safe integer to pointer conversion. In the C language, data is
+// commonly cast to opaque pointer containers and back for generic parameter
+// passing in callbacks. These macros should be used sparingly in new code
+// (never in C++ code). Whenever integers need to be passed as a pointer, use
+// these macros.
+#define PTR_TO_UINT(p) ((unsigned int)((uintptr_t)(p)))
+#define UINT_TO_PTR(u) ((void*)((uintptr_t)(u)))
+
+#define PTR_TO_INT(p) ((int)((intptr_t)(p)))
+#define INT_TO_PTR(i) ((void*)((intptr_t)(i)))
+
+// Obtain a random number between 0 and INT_MAX inclusive.
+// Taken from a system random source such as /dev/random.
+// No guarantees of distribution are made.
+// Effort is made for this to come from a real random source.
+int osi_rand(void);
+
+// Re-run |fn| system call until the system call doesn't cause EINTR.
+#define OSI_NO_INTR(fn) \
+ do { \
+ } while ((fn) == -1 && errno == EINTR)
diff --git a/mtkbt/code/bt/osi/include/properties.h b/mtkbt/code/bt/osi/include/properties.h
new file mode 100755
index 0000000..ececef5
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/properties.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <cstdint>
+#if defined(OS_GENERIC)
+#define PROPERTY_VALUE_MAX 92
+#else
+#include <cutils/properties.h>
+#endif // defined(OS_GENERIC)
+
+// Get value associated with key |key| into |value|.
+// Returns the length of the value which will never be greater than
+// PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+// (the length does not include the terminating zero).
+// If the property read fails or returns an empty value, the |default_value|
+// is used (if nonnull). If the |default_value| is null, zero is returned.
+int osi_property_get(const char* key, char* value, const char* default_value);
+
+// Write value of property associated with key |key| to |value|.
+// Returns 0 on success, < 0 on failure
+int osi_property_set(const char* key, const char* value);
+
+// Adapter function for property_get_int32 in
+// libcutils/include/cutils/properties.h
+//
+// returns the value of |key| truncated and coerced into an
+// int32_t. If the property is not set, then the |default_value| is used.
+int32_t osi_property_get_int32(const char* key, int32_t default_value);
diff --git a/mtkbt/code/bt/osi/include/reactor.h b/mtkbt/code/bt/osi/include/reactor.h
new file mode 100755
index 0000000..c868a01
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/reactor.h
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "osi/include/osi.h"
+
+// This module implements the Reactor pattern.
+// See http://en.wikipedia.org/wiki/Reactor_pattern for details.
+
+typedef struct reactor_t reactor_t;
+typedef struct reactor_object_t reactor_object_t;
+
+// Enumerates the reasons a reactor has stopped.
+typedef enum {
+ REACTOR_STATUS_STOP, // |reactor_stop| was called.
+ REACTOR_STATUS_ERROR, // there was an error during the operation.
+ REACTOR_STATUS_DONE, // the reactor completed its work (for the _run_once*
+ // variants).
+} reactor_status_t;
+
+// Creates a new reactor object. Returns NULL on failure. The returned object
+// must be freed by calling |reactor_free|.
+reactor_t* reactor_new(void);
+
+// Frees a reactor object created with |reactor_new|. |reactor| may be NULL.
+void reactor_free(reactor_t* reactor);
+
+// Starts the reactor. This function blocks the caller until |reactor_stop| is
+// called from another thread or in a callback. |reactor| may not be NULL.
+reactor_status_t reactor_start(reactor_t* reactor);
+
+// Runs one iteration of the reactor. This function blocks until at least one
+// registered object becomes ready. |reactor| may not be NULL.
+reactor_status_t reactor_run_once(reactor_t* reactor);
+
+// Immediately unblocks the reactor. This function is safe to call from any
+// thread.
+// |reactor| may not be NULL.
+void reactor_stop(reactor_t* reactor);
+
+// Registers a file descriptor with the reactor. The file descriptor, |fd|, must
+// be valid when this function is called and its ownership is not transferred
+// to the reactor. The |context| variable is a user-defined opaque handle that
+// is passed back to the |read_ready| and |write_ready| functions. It is not
+// copied or even dereferenced by the reactor so it may contain any value
+// including NULL. The |read_ready| and |write_ready| arguments are optional and
+// may be NULL. This function returns an opaque object that represents the file
+// descriptor's registration with the reactor. When the caller is no longer
+// interested in events on the |fd|, it must free the returned object by calling
+// |reactor_unregister|.
+reactor_object_t* reactor_register(reactor_t* reactor, int fd, void* context,
+ void (*read_ready)(void* context),
+ void (*write_ready)(void* context));
+
+// Changes the subscription mode for the file descriptor represented by
+// |object|. If the caller has already registered a file descriptor with a
+// reactor, has a valid |object|, and decides to change the |read_ready| and/or
+// |write_ready| callback routines, they can call this routine. Returns true if
+// the subscription was changed, false otherwise.
+// |object| may not be NULL, |read_ready| and |write_ready| may be NULL.
+bool reactor_change_registration(reactor_object_t* object,
+ void (*read_ready)(void* context),
+ void (*write_ready)(void* context));
+
+// Unregisters a previously registered file descriptor with its reactor. |obj|
+// may not be NULL. |obj| is invalid after calling this function so the caller
+// must drop all references to it.
+void reactor_unregister(reactor_object_t* obj);
diff --git a/mtkbt/code/bt/osi/include/ringbuffer.h b/mtkbt/code/bt/osi/include/ringbuffer.h
new file mode 100755
index 0000000..6a3c3fa
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/ringbuffer.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+typedef struct ringbuffer_t ringbuffer_t;
+
+// NOTE:
+// None of the functions below are thread safe when it comes to accessing the
+// *rb pointer. It is *NOT* possible to insert and pop/delete at the same time.
+// Callers must protect the *rb pointer separately.
+
+// Create a ringbuffer with the specified size
+// Returns NULL if memory allocation failed. Resulting pointer must be freed
+// using |ringbuffer_free|.
+ringbuffer_t* ringbuffer_init(const size_t size);
+
+// Frees the ringbuffer structure and buffer
+// Save to call with NULL.
+void ringbuffer_free(ringbuffer_t* rb);
+
+// Returns remaining buffer size
+size_t ringbuffer_available(const ringbuffer_t* rb);
+
+// Returns size of data in buffer
+size_t ringbuffer_size(const ringbuffer_t* rb);
+
+// Attempts to insert up to |length| bytes of data at |p| into the buffer
+// Return actual number of bytes added. Can be less than |length| if buffer
+// is full.
+size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length);
+
+// Peek |length| number of bytes from the ringbuffer, starting at |offset|,
+// into the buffer |p|. Return the actual number of bytes peeked. Can be less
+// than |length| if there is less than |length| data available. |offset| must
+// be non-negative.
+size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p,
+ size_t length);
+
+// Does the same as |ringbuffer_peek|, but also advances the ring buffer head
+size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length);
+
+// Deletes |length| bytes from the ringbuffer starting from the head
+// Return actual number of bytes deleted.
+size_t ringbuffer_delete(ringbuffer_t* rb, size_t length);
diff --git a/mtkbt/code/bt/osi/include/semaphore.h b/mtkbt/code/bt/osi/include/semaphore.h
new file mode 100755
index 0000000..9c8f6fb
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/semaphore.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+struct semaphore_t;
+typedef struct semaphore_t semaphore_t;
+
+// Creates a new semaphore with an initial value of |value|.
+// Returns NULL on failure. The returned object must be released
+// with |semaphore_free|.
+semaphore_t* semaphore_new(unsigned int value);
+
+// Frees a semaphore allocated with |semaphore_new|. |semaphore| may
+// be NULL.
+void semaphore_free(semaphore_t* semaphore);
+
+// Decrements the value of |semaphore|. If it is 0, this call blocks until
+// it becomes non-zero. |semaphore| may not be NULL.
+void semaphore_wait(semaphore_t* semaphore);
+
+// Tries to decrement the value of |semaphore|. Returns true if the value was
+// decremented, false if the value was 0. This function never blocks.
+// |semaphore| may not be NULL.
+bool semaphore_try_wait(semaphore_t* semaphore);
+
+// Increments the value of |semaphore|. |semaphore| may not be NULL.
+void semaphore_post(semaphore_t* semaphore);
+
+// Returns a file descriptor representing this semaphore. The caller may
+// only perform one operation on the file descriptor: select(2). If |select|
+// indicates the fd is readable, the caller may call |semaphore_wait|
+// without blocking. If select indicates the fd is writable, the caller may
+// call |semaphore_post| without blocking. Note that there may be a race
+// condition between calling |select| and |semaphore_wait| or |semaphore_post|
+// which results in blocking behaviour.
+//
+// The caller must not close the returned file descriptor. |semaphore| may not
+// be NULL.
+int semaphore_get_fd(const semaphore_t* semaphore);
diff --git a/mtkbt/code/bt/osi/include/socket.h b/mtkbt/code/bt/osi/include/socket.h
new file mode 100755
index 0000000..5cd8938
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/socket.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef struct reactor_t reactor_t;
+typedef struct socket_t socket_t;
+typedef uint16_t port_t;
+
+typedef void (*socket_cb)(socket_t* socket, void* context);
+
+// Returns a new socket object. The socket is in an idle, disconnected state
+// when it is returned by this function. The returned object must be freed by
+// calling |socket_free|. Returns NULL on failure.
+socket_t* socket_new(void);
+
+// Returns a new socket object backed by |fd|. The socket object is in whichever
+// state |fd| is in when it was passed to this function. The returned object
+// must be freed by calling |socket_free|. Returns NULL on failure. If this
+// function is successful, ownership of |fd| is transferred and the caller must
+// not close it.
+socket_t* socket_new_from_fd(int fd);
+
+// Frees a socket object created by |socket_new| or |socket_accept|. |socket|
+// may be NULL. If the socket was connected, it will be disconnected.
+void socket_free(socket_t* socket);
+
+// Puts |socket| in listening mode for incoming TCP connections on the specified
+// |port| and the loopback IPv4 address. Returns true on success, false on
+// failure (e.g. |port| is bound by another socket). |socket| may not be NULL.
+bool socket_listen(const socket_t* socket, port_t port);
+
+// Blocks on a listening socket, |socket|, until a client connects to it.
+// Returns a connected socket on success, NULL on failure. The returned object
+// must be freed by calling |socket_free|. |socket| may not be NULL.
+socket_t* socket_accept(const socket_t* socket);
+
+// Reads up to |count| bytes from |socket| into |buf|. This function will not
+// block. This function returns a positive integer representing the number
+// of bytes copied into |buf| on success, 0 if the socket has disconnected,
+// and -1 on error. This function may return a value less than |count| if not
+// enough data is currently available. If this function returns -1, errno will
+// also be set (see recv(2) for possible errno values). However, if the reading
+// system call was interrupted with errno of EINTR, the read operation is
+// restarted internally without propagating EINTR back to the caller. If there
+// were no bytes available to be read, this function returns -1 and sets errno
+// to EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
+ssize_t socket_read(const socket_t* socket, void* buf, size_t count);
+
+// Writes up to |count| bytes from |buf| into |socket|. This function will not
+// block. Returns a positive integer representing the number of bytes written
+// to |socket| on success, 0 if the socket has disconnected, and -1 on error.
+// This function may return a value less than |count| if writing more bytes
+// would result in blocking. If this function returns -1, errno will also be
+// set (see send(2) for possible errno values). However, if the writing system
+// call was interrupted with errno of EINTR, the write operation is restarted
+// internally without propagating EINTR back to the caller. If no bytes could
+// be written without blocking, this function will return -1 and set errno to
+// EWOULDBLOCK. Neither |socket| nor |buf| may be NULL.
+ssize_t socket_write(const socket_t* socket, const void* buf, size_t count);
+
+// This function performs the same write operation as |socket_write| and also
+// sends the file descriptor |fd| over the socket to a remote process. Ownership
+// of |fd| transfers to this function and the descriptor must not be used any
+// longer. If |fd| is INVALID_FD, this function behaves the same as
+// |socket_write|.
+ssize_t socket_write_and_transfer_fd(const socket_t* socket, const void* buf,
+ size_t count, int fd);
+
+// Returns the number of bytes that can be read from |socket| without blocking.
+// On error, this function returns -1. |socket| may not be NULL.
+//
+// Note: this function should not be part of the socket interface. It is only
+// provided as a stop-gap until we can refactor away code that depends on
+// a priori knowledge of the byte count. Do not use this function unless
+// you need it while refactoring legacy bluedroid code.
+ssize_t socket_bytes_available(const socket_t* socket);
+
+// Registers |socket| with the |reactor|. When the socket becomes readable,
+// |read_cb| will be called. When the socket becomes writeable, |write_cb| will
+// be called. The |context| parameter is passed, untouched, to each of the
+// callback routines. Neither |socket| nor |reactor| may be NULL. |read_cb|,
+// |write_cb|, and |context| may be NULL.
+void socket_register(socket_t* socket, reactor_t* reactor, void* context,
+ socket_cb read_cb, socket_cb write_cb);
+
+// Unregisters |socket| from whichever reactor it is registered with, if any.
+// This function is idempotent.
+void socket_unregister(socket_t* socket);
diff --git a/mtkbt/code/bt/osi/include/socket_utils/socket_local.h b/mtkbt/code/bt/osi/include/socket_utils/socket_local.h
new file mode 100755
index 0000000..fd3b00c
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/socket_utils/socket_local.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ *
+ * @return 0 on success or -1 on failure
+ */
+int osi_socket_make_sockaddr_un(const char* name, int namespaceId,
+ struct sockaddr_un* p_addr, socklen_t* alen);
diff --git a/mtkbt/code/bt/osi/include/socket_utils/sockets.h b/mtkbt/code/bt/osi/include/socket_utils/sockets.h
new file mode 100755
index 0000000..fc7514f
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/socket_utils/sockets.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR "/dev/socket"
+
+/*
+ * osi_android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int osi_android_get_control_socket(const char* name) {
+ char key[64];
+ snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
+
+ const char* val = getenv(key);
+ if (!val) {
+ return -1;
+ }
+
+ errno = 0;
+ int fd = strtol(val, NULL, 10);
+ if (errno) {
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int osi_socket_local_server(const char* name, int namespaceId, int type);
+extern int osi_socket_local_server_bind(int s, const char* name,
+ int namespaceId);
+extern int osi_socket_local_client_connect(int fd, const char* name,
+ int namespaceId, int type);
+extern int osi_socket_local_client(const char* name, int namespaceId, int type);
diff --git a/mtkbt/code/bt/osi/include/thread.h b/mtkbt/code/bt/osi/include/thread.h
new file mode 100755
index 0000000..c8da381
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/thread.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define THREAD_NAME_MAX 16
+
+typedef struct reactor_t reactor_t;
+typedef struct thread_t thread_t;
+
+typedef void (*thread_fn)(void* context);
+
+// Creates and starts a new thread with the given name. Only THREAD_NAME_MAX
+// bytes from |name| will be assigned to the newly-created thread. Returns a
+// thread object if the thread was successfully started, NULL otherwise. The
+// returned thread object must be freed with |thread_free|. |name| may not
+// be NULL.
+thread_t* thread_new(const char* name);
+
+// Similar to |thread_new| but creates with a given queue |size|.
+thread_t* thread_new_sized(const char* name, size_t size);
+
+// Frees the given |thread|. If the thread is still running, it is stopped
+// and the calling thread will block until |thread| terminates. |thread|
+// may be NULL.
+void thread_free(thread_t* thread);
+
+// Waits for |thread_stop|. Upon returning, the only other operations a caller
+// may perform on |thread| are |thread_free| and |thread_join|. |thread_join|
+// is idempotent and may be called from any thread. |thread| may not be NULL.
+void thread_join(thread_t* thread);
+
+// Call |func| with the argument |context| on |thread|. This function typically
+// does not block unless there are an excessive number of functions posted to
+// |thread| that have not been dispatched yet. Neither |thread| nor |func| may
+// be NULL. |context| may be NULL.
+// Return true on success, otherwise false.
+bool thread_post(thread_t* thread, thread_fn func, void* context);
+
+// Requests |thread| to stop. Only |thread_free| and |thread_name| may be called
+// after calling |thread_stop|. This function is guaranteed to not block.
+// |thread| may not be NULL.
+void thread_stop(thread_t* thread);
+
+// Attempts to sets the |priority| of a given |thread|.
+// The |thread| has to be running for this call to succeed.
+// Returns true on success.
+bool thread_set_priority(thread_t* thread, int priority);
+
+// Attempts to set |thread| to the real-time SCHED_FIFO |priority|.
+// The |thread| has to be running for this call to succeed.
+// Priority values are valid in the range sched_get_priority_max(SCHED_FIFO)
+// to sched_get_priority_min(SCHED_FIFO). Larger values are higher priority.
+// Returns true on success.
+bool thread_set_rt_priority(thread_t* thread, int priority);
+
+// Returns true if the current thread is the same as the one represented by
+// |thread|.
+// |thread| may not be NULL.
+bool thread_is_self(const thread_t* thread);
+
+// Returns the reactor for the given |thread|. |thread| may not be NULL.
+reactor_t* thread_get_reactor(const thread_t* thread);
+
+// Returns the name of the given |thread|. |thread| may not be NULL.
+const char* thread_name(const thread_t* thread);
diff --git a/mtkbt/code/bt/osi/include/time.h b/mtkbt/code/bt/osi/include/time.h
new file mode 100755
index 0000000..0988c20
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/time.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+
+typedef uint64_t period_ms_t;
+
+// Get the OS boot time in milliseconds.
+//
+// NOTE: The return value will rollover every 49.7 days,
+// hence it cannot be used for absolute time comparison.
+// Relative time comparison using 32-bits integers such
+// as (t2_u32 - t1_u32 < delta_u32) should work as expected as long
+// as there is no multiple rollover between t2_u32 and t1_u32.
+//
+// TODO: This function's return type should be modified to |period_ms_t|.
+// Be careful: some of the code that is using it assumes the return type
+// is uint32_t.
+uint32_t time_get_os_boottime_ms(void);
+
+// Get the OS boot time in microseconds.
+uint64_t time_get_os_boottime_us(void);
+
+// Get the current wall clock time in microseconds.
+uint64_t time_gettimeofday_us(void);
diff --git a/mtkbt/code/bt/osi/include/wakelock.h b/mtkbt/code/bt/osi/include/wakelock.h
new file mode 100755
index 0000000..502f9fb
--- a/dev/null
+++ b/mtkbt/code/bt/osi/include/wakelock.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <stdbool.h>
+
+// Set the Bluetooth OS callouts to |callouts|.
+// This function should be called when native kernel wakelocks are not used
+// directly. If this function is not called, or |callouts| is NULL, then native
+// kernel wakelocks will be used.
+void wakelock_set_os_callouts(bt_os_callouts_t* callouts);
+
+// Acquire the Bluetooth wakelock.
+// The function is thread safe.
+// Return true on success, otherwise false.
+bool wakelock_acquire(void);
+
+// Release the Bluetooth wakelock.
+// The function is thread safe.
+// Return true on success, otherwise false.
+bool wakelock_release(void);
+
+// Cleanup the wakelock internal state.
+// This function should be called by the OSI module cleanup during
+// graceful shutdown.
+void wakelock_cleanup(void);
+
+// This function should not need to be called normally.
+// /sys/power/wake_{|un}lock are used by default.
+// This is not guaranteed to have any effect after an alarm has been
+// set with alarm_set.
+// If |lock_path| or |unlock_path| are NULL, that path is not changed.
+void wakelock_set_paths(const char* lock_path, const char* unlock_path);
+
+// Dump wakelock-related debug info to the |fd| file descriptor.
+// The caller is responsible for closing the |fd|.
+void wakelock_debug_dump(int fd);
diff --git a/mtkbt/code/bt/osi/src/alarm.cc b/mtkbt/code/bt/osi/src/alarm.cc
new file mode 100755
index 0000000..81740d3
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/alarm.cc
@@ -0,0 +1,733 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "include/bt_target.h"
+
+#define LOG_TAG "bt_osi_alarm"
+
+#include "osi/include/alarm.h"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+
+#include <hardware/bluetooth.h>
+
+#include <mutex>
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+#include "osi/include/wakelock.h"
+
+// Callback and timer threads should run at RT priority in order to ensure they
+// meet audio deadlines. Use this priority for all audio/timer related thread.
+static const int THREAD_RT_PRIORITY = 1;
+
+typedef struct {
+ size_t count;
+ period_ms_t total_ms;
+ period_ms_t max_ms;
+} stat_t;
+
+// Alarm-related information and statistics
+typedef struct {
+ const char* name;
+ size_t scheduled_count;
+ size_t canceled_count;
+ size_t rescheduled_count;
+ size_t total_updates;
+ period_ms_t last_update_ms;
+ stat_t callback_execution;
+ stat_t overdue_scheduling;
+ stat_t premature_scheduling;
+} alarm_stats_t;
+
+struct alarm_t {
+ // The mutex is held while the callback for this alarm is being executed.
+ // It allows us to release the coarse-grained monitor lock while a
+ // potentially long-running callback is executing. |alarm_cancel| uses this
+ // mutex to provide a guarantee to its caller that the callback will not be
+ // in progress when it returns.
+ std::recursive_mutex* callback_mutex;
+ period_ms_t creation_time;
+ period_ms_t period;
+ period_ms_t deadline;
+ period_ms_t prev_deadline; // Previous deadline - used for accounting of
+ // periodic timers
+ bool is_periodic;
+ fixed_queue_t* queue; // The processing queue to add this alarm to
+ alarm_callback_t callback;
+ void* data;
+ alarm_stats_t stats;
+};
+
+// If the next wakeup time is less than this threshold, we should acquire
+// a wakelock instead of setting a wake alarm so we're not bouncing in
+// and out of suspend frequently. This value is externally visible to allow
+// unit tests to run faster. It should not be modified by production code.
+int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
+static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
+
+#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
+#else
+static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
+#endif
+
+// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
+// functions execute serially and not concurrently. As a result, this mutex
+// also protects the |alarms| list.
+static std::mutex alarms_mutex;
+static list_t* alarms;
+static timer_t timer;
+static timer_t wakeup_timer;
+static bool timer_set;
+
+// All alarm callbacks are dispatched from |dispatcher_thread|
+static thread_t* dispatcher_thread;
+static bool dispatcher_thread_active;
+static semaphore_t* alarm_expired;
+
+// Default alarm callback thread and queue
+static thread_t* default_callback_thread;
+static fixed_queue_t* default_callback_queue;
+
+static alarm_t* alarm_new_internal(const char* name, bool is_periodic);
+static bool lazy_initialize(void);
+static period_ms_t now(void);
+static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+ alarm_callback_t cb, void* data,
+ fixed_queue_t* queue);
+static void alarm_cancel_internal(alarm_t* alarm);
+static void remove_pending_alarm(alarm_t* alarm);
+static void schedule_next_instance(alarm_t* alarm);
+static void reschedule_root_alarm(void);
+static void alarm_queue_ready(fixed_queue_t* queue, void* context);
+static void timer_callback(void* data);
+static void callback_dispatch(void* context);
+static bool timer_create_internal(const clockid_t clock_id, timer_t* timer);
+static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
+ period_ms_t deadline_ms,
+ period_ms_t execution_delta_ms);
+
+static void update_stat(stat_t* stat, period_ms_t delta) {
+ if (stat->max_ms < delta) stat->max_ms = delta;
+ stat->total_ms += delta;
+ stat->count++;
+}
+
+alarm_t* alarm_new(const char* name) { return alarm_new_internal(name, false); }
+
+alarm_t* alarm_new_periodic(const char* name) {
+ return alarm_new_internal(name, true);
+}
+
+static alarm_t* alarm_new_internal(const char* name, bool is_periodic) {
+ // Make sure we have a list we can insert alarms into.
+ if (!alarms && !lazy_initialize()) {
+ CHECK(false); // if initialization failed, we should not continue
+ return NULL;
+ }
+
+ alarm_t* ret = static_cast<alarm_t*>(osi_calloc(sizeof(alarm_t)));
+
+ ret->callback_mutex = new std::recursive_mutex;
+ ret->is_periodic = is_periodic;
+ ret->stats.name = osi_strdup(name);
+ // NOTE: The stats were reset by osi_calloc() above
+
+ return ret;
+}
+
+void alarm_free(alarm_t* alarm) {
+ if (!alarm) return;
+
+ alarm_cancel(alarm);
+ delete alarm->callback_mutex;
+ osi_free((void*)alarm->stats.name);
+ osi_free(alarm);
+}
+
+period_ms_t alarm_get_remaining_ms(const alarm_t* alarm) {
+ CHECK(alarm != NULL);
+ period_ms_t remaining_ms = 0;
+ period_ms_t just_now = now();
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+ if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now;
+
+ return remaining_ms;
+}
+
+void alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb,
+ void* data) {
+ alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue);
+}
+
+void alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms,
+ alarm_callback_t cb, void* data, fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+ alarm_set_internal(alarm, interval_ms, cb, data, queue);
+}
+
+// Runs in exclusion with alarm_cancel and timer_callback.
+static void alarm_set_internal(alarm_t* alarm, period_ms_t period,
+ alarm_callback_t cb, void* data,
+ fixed_queue_t* queue) {
+ CHECK(alarms != NULL);
+ CHECK(alarm != NULL);
+ CHECK(cb != NULL);
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+
+ alarm->creation_time = now();
+ alarm->period = period;
+ alarm->queue = queue;
+ alarm->callback = cb;
+ alarm->data = data;
+
+ schedule_next_instance(alarm);
+ alarm->stats.scheduled_count++;
+}
+
+void alarm_cancel(alarm_t* alarm) {
+ CHECK(alarms != NULL);
+ if (!alarm) return;
+
+ {
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+ alarm_cancel_internal(alarm);
+ }
+
+ // If the callback for |alarm| is in progress, wait here until it completes.
+ std::lock_guard<std::recursive_mutex> lock(*alarm->callback_mutex);
+}
+
+// Internal implementation of canceling an alarm.
+// The caller must hold the |alarms_mutex|
+static void alarm_cancel_internal(alarm_t* alarm) {
+ bool needs_reschedule =
+ (!list_is_empty(alarms) && list_front(alarms) == alarm);
+
+ remove_pending_alarm(alarm);
+
+ alarm->deadline = 0;
+ alarm->prev_deadline = 0;
+ alarm->callback = NULL;
+ alarm->data = NULL;
+ alarm->stats.canceled_count++;
+ alarm->queue = NULL;
+
+ if (needs_reschedule) reschedule_root_alarm();
+}
+
+bool alarm_is_scheduled(const alarm_t* alarm) {
+ if ((alarms == NULL) || (alarm == NULL)) return false;
+ return (alarm->callback != NULL);
+}
+
+void alarm_cleanup(void) {
+ // If lazy_initialize never ran there is nothing else to do
+ if (!alarms) return;
+
+ dispatcher_thread_active = false;
+ semaphore_post(alarm_expired);
+ thread_free(dispatcher_thread);
+ dispatcher_thread = NULL;
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+
+ fixed_queue_free(default_callback_queue, NULL);
+ default_callback_queue = NULL;
+ thread_free(default_callback_thread);
+ default_callback_thread = NULL;
+
+ timer_delete(wakeup_timer);
+ timer_delete(timer);
+ semaphore_free(alarm_expired);
+ alarm_expired = NULL;
+
+ list_free(alarms);
+ alarms = NULL;
+}
+
+static bool lazy_initialize(void) {
+ CHECK(alarms == NULL);
+
+ // timer_t doesn't have an invalid value so we must track whether
+ // the |timer| variable is valid ourselves.
+ bool timer_initialized = false;
+ bool wakeup_timer_initialized = false;
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+
+ alarms = list_new(NULL);
+ if (!alarms) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
+ goto error;
+ }
+
+ if (!timer_create_internal(CLOCK_ID, &timer)) goto error;
+ timer_initialized = true;
+
+ if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error;
+ wakeup_timer_initialized = true;
+
+ alarm_expired = semaphore_new(0);
+ if (!alarm_expired) {
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
+ goto error;
+ }
+
+ default_callback_thread =
+ thread_new_sized("alarm_default_callbacks", SIZE_MAX);
+ if (default_callback_thread == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.",
+ __func__);
+ goto error;
+ }
+ thread_set_rt_priority(default_callback_thread, THREAD_RT_PRIORITY);
+ default_callback_queue = fixed_queue_new(SIZE_MAX);
+ if (default_callback_queue == NULL) {
+ LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.",
+ __func__);
+ goto error;
+ }
+ alarm_register_processing_queue(default_callback_queue,
+ default_callback_thread);
+
+ dispatcher_thread_active = true;
+ dispatcher_thread = thread_new("alarm_dispatcher");
+ if (!dispatcher_thread) {
+ LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
+ goto error;
+ }
+ thread_set_rt_priority(dispatcher_thread, THREAD_RT_PRIORITY);
+ thread_post(dispatcher_thread, callback_dispatch, NULL);
+ return true;
+
+error:
+ fixed_queue_free(default_callback_queue, NULL);
+ default_callback_queue = NULL;
+ thread_free(default_callback_thread);
+ default_callback_thread = NULL;
+
+ thread_free(dispatcher_thread);
+ dispatcher_thread = NULL;
+
+ dispatcher_thread_active = false;
+
+ semaphore_free(alarm_expired);
+ alarm_expired = NULL;
+
+ if (wakeup_timer_initialized) timer_delete(wakeup_timer);
+
+ if (timer_initialized) timer_delete(timer);
+
+ list_free(alarms);
+ alarms = NULL;
+
+ return false;
+}
+
+static period_ms_t now(void) {
+ CHECK(alarms != NULL);
+
+ struct timespec ts;
+ if (clock_gettime(CLOCK_ID, &ts) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__,
+ strerror(errno));
+ return 0;
+ }
+
+ return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
+}
+
+// Remove alarm from internal alarm list and the processing queue
+// The caller must hold the |alarms_mutex|
+static void remove_pending_alarm(alarm_t* alarm) {
+ list_remove(alarms, alarm);
+ while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) {
+ // Remove all repeated alarm instances from the queue.
+ // NOTE: We are defensive here - we shouldn't have repeated alarm instances
+ }
+}
+
+// Must be called with |alarms_mutex| held
+static void schedule_next_instance(alarm_t* alarm) {
+ // If the alarm is currently set and it's at the start of the list,
+ // we'll need to re-schedule since we've adjusted the earliest deadline.
+ bool needs_reschedule =
+ (!list_is_empty(alarms) && list_front(alarms) == alarm);
+ if (alarm->callback) remove_pending_alarm(alarm);
+
+ // Calculate the next deadline for this alarm
+ period_ms_t just_now = now();
+ period_ms_t ms_into_period = 0;
+ if ((alarm->is_periodic) && (alarm->period != 0))
+ ms_into_period = ((just_now - alarm->creation_time) % alarm->period);
+ alarm->deadline = just_now + (alarm->period - ms_into_period);
+
+ // Add it into the timer list sorted by deadline (earliest deadline first).
+ if (list_is_empty(alarms) ||
+ ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) {
+ list_prepend(alarms, alarm);
+ } else {
+ for (list_node_t* node = list_begin(alarms); node != list_end(alarms);
+ node = list_next(node)) {
+ list_node_t* next = list_next(node);
+ if (next == list_end(alarms) ||
+ ((alarm_t*)list_node(next))->deadline > alarm->deadline) {
+ list_insert_after(alarms, node, alarm);
+ break;
+ }
+ }
+ }
+
+ // If the new alarm has the earliest deadline, we need to re-evaluate our
+ // schedule.
+ if (needs_reschedule ||
+ (!list_is_empty(alarms) && list_front(alarms) == alarm)) {
+ reschedule_root_alarm();
+ }
+}
+
+// NOTE: must be called with |alarms_mutex| held
+static void reschedule_root_alarm(void) {
+ CHECK(alarms != NULL);
+
+ const bool timer_was_set = timer_set;
+ alarm_t* next;
+ int64_t next_expiration;
+
+ // If used in a zeroed state, disarms the timer.
+ struct itimerspec timer_time;
+ memset(&timer_time, 0, sizeof(timer_time));
+
+ if (list_is_empty(alarms)) goto done;
+
+ next = static_cast<alarm_t*>(list_front(alarms));
+ next_expiration = next->deadline - now();
+ if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
+ if (!timer_set) {
+ if (!wakelock_acquire()) {
+ LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__);
+ goto done;
+ }
+ }
+
+ timer_time.it_value.tv_sec = (next->deadline / 1000);
+ timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+
+ // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec
+ // for timers with *_ALARM clock IDs. Although the man page states that the
+ // timer would be canceled, the current behavior (as of Linux kernel 3.17)
+ // is that the callback is issued immediately. The only way to cancel an
+ // *_ALARM timer is to delete the timer. But unfortunately, deleting and
+ // re-creating a timer is rather expensive; every timer_create(2) spawns a
+ // new thread. So we simply set the timer to fire at the largest possible
+ // time.
+ //
+ // If we've reached this code path, we're going to grab a wake lock and
+ // wait for the next timer to fire. In that case, there's no reason to
+ // have a pending wakeup timer so we simply cancel it.
+ struct itimerspec end_of_time;
+ memset(&end_of_time, 0, sizeof(end_of_time));
+ end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2));
+ timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
+ } else {
+ // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
+ // in kernels before 3.17 unless you have the following patch:
+ // https://lkml.org/lkml/2014/7/7/576
+ struct itimerspec wakeup_time;
+ memset(&wakeup_time, 0, sizeof(wakeup_time));
+
+ wakeup_time.it_value.tv_sec = (next->deadline / 1000);
+ wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
+ if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__,
+ strerror(errno));
+ }
+
+done:
+ timer_set =
+ timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
+ if (timer_was_set && !timer_set) {
+ wakelock_release();
+ }
+
+ if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
+
+ // If next expiration was in the past (e.g. short timer that got context
+ // switched) then the timer might have diarmed itself. Detect this case and
+ // work around it by manually signalling the |alarm_expired| semaphore.
+ //
+ // It is possible that the timer was actually super short (a few
+ // milliseconds) and the timer expired normally before we called
+ // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that
+ // alarm. Nothing bad should happen in that case though since the callback
+ // dispatch function checks to make sure the timer at the head of the list
+ // actually expired.
+ if (timer_set) {
+ struct itimerspec time_to_expire;
+ timer_gettime(timer, &time_to_expire);
+ if (time_to_expire.it_value.tv_sec == 0 &&
+ time_to_expire.it_value.tv_nsec == 0) {
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s alarm expiration too close for posix timers, switching to guns",
+ __func__);
+ semaphore_post(alarm_expired);
+ }
+ }
+}
+
+void alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread) {
+ CHECK(queue != NULL);
+ CHECK(thread != NULL);
+
+ fixed_queue_register_dequeue(queue, thread_get_reactor(thread),
+ alarm_queue_ready, NULL);
+}
+
+void alarm_unregister_processing_queue(fixed_queue_t* queue) {
+ CHECK(alarms != NULL);
+ CHECK(queue != NULL);
+
+ fixed_queue_unregister_dequeue(queue);
+
+ // Cancel all alarms that are using this queue
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+ for (list_node_t* node = list_begin(alarms); node != list_end(alarms);) {
+ alarm_t* alarm = (alarm_t*)list_node(node);
+ node = list_next(node);
+ // TODO: Each module is responsible for tearing down its alarms; currently,
+ // this is not the case. In the future, this check should be replaced by
+ // an assert.
+ if (alarm->queue == queue) alarm_cancel_internal(alarm);
+ }
+}
+
+static void alarm_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+ CHECK(queue != NULL);
+
+ std::unique_lock<std::mutex> lock(alarms_mutex);
+ alarm_t* alarm = (alarm_t*)fixed_queue_try_dequeue(queue);
+ if (alarm == NULL) {
+ return; // The alarm was probably canceled
+ }
+
+ //
+ // If the alarm is not periodic, we've fully serviced it now, and can reset
+ // some of its internal state. This is useful to distinguish between expired
+ // alarms and active ones.
+ //
+ alarm_callback_t callback = alarm->callback;
+ void* data = alarm->data;
+ period_ms_t deadline = alarm->deadline;
+ if (alarm->is_periodic) {
+ // The periodic alarm has been rescheduled and alarm->deadline has been
+ // updated, hence we need to use the previous deadline.
+ deadline = alarm->prev_deadline;
+ } else {
+ alarm->deadline = 0;
+ alarm->callback = NULL;
+ alarm->data = NULL;
+ alarm->queue = NULL;
+ }
+
+ std::lock_guard<std::recursive_mutex> cb_lock(*alarm->callback_mutex);
+ lock.unlock();
+
+ period_ms_t t0 = now();
+ callback(data);
+ period_ms_t t1 = now();
+
+ // Update the statistics
+ CHECK(t1 >= t0);
+ period_ms_t delta = t1 - t0;
+ update_scheduling_stats(&alarm->stats, t0, deadline, delta);
+}
+
+// Callback function for wake alarms and our posix timer
+static void timer_callback(UNUSED_ATTR void* ptr) {
+ semaphore_post(alarm_expired);
+}
+
+// Function running on |dispatcher_thread| that performs the following:
+// (1) Receives a signal using |alarm_exired| that the alarm has expired
+// (2) Dispatches the alarm callback for processing by the corresponding
+// thread for that alarm.
+static void callback_dispatch(UNUSED_ATTR void* context) {
+ while (true) {
+ semaphore_wait(alarm_expired);
+ if (!dispatcher_thread_active) break;
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+ alarm_t* alarm;
+
+ // Take into account that the alarm may get cancelled before we get to it.
+ // We're done here if there are no alarms or the alarm at the front is in
+ // the future. Exit right away since there's nothing left to do.
+ if (list_is_empty(alarms) ||
+ (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) {
+ reschedule_root_alarm();
+ continue;
+ }
+
+ list_remove(alarms, alarm);
+
+ if (alarm->is_periodic) {
+ alarm->prev_deadline = alarm->deadline;
+ schedule_next_instance(alarm);
+ alarm->stats.rescheduled_count++;
+ }
+ reschedule_root_alarm();
+
+ // Enqueue the alarm for processing
+ fixed_queue_enqueue(alarm->queue, alarm);
+ }
+
+ LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
+}
+
+static bool timer_create_internal(const clockid_t clock_id, timer_t* timer) {
+ CHECK(timer != NULL);
+
+ struct sigevent sigevent;
+ // create timer with RT priority thread
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);
+ struct sched_param param;
+ param.sched_priority = THREAD_RT_PRIORITY;
+ pthread_attr_setschedparam(&thread_attr, &param);
+
+ memset(&sigevent, 0, sizeof(sigevent));
+ sigevent.sigev_notify = SIGEV_THREAD;
+ sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
+ sigevent.sigev_notify_attributes = &thread_attr;
+ if (timer_create(clock_id, &sigevent, timer) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__,
+ clock_id, strerror(errno));
+ if (clock_id == CLOCK_BOOTTIME_ALARM) {
+ LOG_ERROR(LOG_TAG,
+ "The kernel might not have support for "
+ "timer_create(CLOCK_BOOTTIME_ALARM): "
+ "https://lwn.net/Articles/429925/");
+ LOG_ERROR(LOG_TAG,
+ "See following patches: "
+ "https://git.kernel.org/cgit/linux/kernel/git/torvalds/"
+ "linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms,
+ period_ms_t deadline_ms,
+ period_ms_t execution_delta_ms) {
+ stats->total_updates++;
+ stats->last_update_ms = now_ms;
+
+ update_stat(&stats->callback_execution, execution_delta_ms);
+
+ if (deadline_ms < now_ms) {
+ // Overdue scheduling
+ period_ms_t delta_ms = now_ms - deadline_ms;
+ update_stat(&stats->overdue_scheduling, delta_ms);
+ } else if (deadline_ms > now_ms) {
+ // Premature scheduling
+ period_ms_t delta_ms = deadline_ms - now_ms;
+ update_stat(&stats->premature_scheduling, delta_ms);
+ }
+}
+
+static void dump_stat(int fd, stat_t* stat, const char* description) {
+ period_ms_t average_time_ms = 0;
+ if (stat->count != 0) average_time_ms = stat->total_ms / stat->count;
+
+ dprintf(fd, "%-51s: %llu / %llu / %llu\n", description,
+ (unsigned long long)stat->total_ms, (unsigned long long)stat->max_ms,
+ (unsigned long long)average_time_ms);
+}
+
+void alarm_debug_dump(int fd) {
+ dprintf(fd, "\nBluetooth Alarms Statistics:\n");
+
+ std::lock_guard<std::mutex> lock(alarms_mutex);
+
+ if (alarms == NULL) {
+ dprintf(fd, " None\n");
+ return;
+ }
+
+ period_ms_t just_now = now();
+
+ dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms));
+
+ // Dump info for each alarm
+ for (list_node_t* node = list_begin(alarms); node != list_end(alarms);
+ node = list_next(node)) {
+ alarm_t* alarm = (alarm_t*)list_node(node);
+ alarm_stats_t* stats = &alarm->stats;
+
+ dprintf(fd, " Alarm : %s (%s)\n", stats->name,
+ (alarm->is_periodic) ? "PERIODIC" : "SINGLE");
+
+ dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n",
+ " Action counts (sched/resched/exec/cancel)",
+ stats->scheduled_count, stats->rescheduled_count,
+ stats->callback_execution.count, stats->canceled_count);
+
+ dprintf(fd, "%-51s: %zu / %zu\n",
+ " Deviation counts (overdue/premature)",
+ stats->overdue_scheduling.count, stats->premature_scheduling.count);
+
+ dprintf(fd, "%-51s: %llu / %llu / %lld\n",
+ " Time in ms (since creation/interval/remaining)",
+ (unsigned long long)(just_now - alarm->creation_time),
+ (unsigned long long)alarm->period,
+ (long long)(alarm->deadline - just_now));
+
+ dump_stat(fd, &stats->callback_execution,
+ " Callback execution time in ms (total/max/avg)");
+
+ dump_stat(fd, &stats->overdue_scheduling,
+ " Overdue scheduling time in ms (total/max/avg)");
+
+ dump_stat(fd, &stats->premature_scheduling,
+ " Premature scheduling time in ms (total/max/avg)");
+
+ dprintf(fd, "\n");
+ }
+}
diff --git a/mtkbt/code/bt/osi/src/allocation_tracker.cc b/mtkbt/code/bt/osi/src/allocation_tracker.cc
new file mode 100755
index 0000000..2dee1dc
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/allocation_tracker.cc
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_allocation_tracker"
+
+#include "osi/include/allocation_tracker.h"
+
+#include <base/logging.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mutex>
+#include <unordered_map>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+typedef struct {
+ uint8_t allocator_id;
+ void* ptr;
+ size_t size;
+ bool freed;
+} allocation_t;
+
+static const size_t canary_size = 8;
+static char canary[canary_size];
+static std::unordered_map<void*, allocation_t*> allocations;
+static std::mutex tracker_lock;
+static bool enabled = false;
+
+// Memory allocation statistics
+static size_t alloc_counter = 0;
+static size_t free_counter = 0;
+static size_t alloc_total_size = 0;
+static size_t free_total_size = 0;
+
+void allocation_tracker_init(void) {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+ if (enabled) return;
+
+ // randomize the canary contents
+ for (size_t i = 0; i < canary_size; i++) canary[i] = (char)osi_rand();
+
+ LOG_DEBUG(LOG_TAG, "canary initialized");
+
+ enabled = true;
+}
+
+// Test function only. Do not call in the normal course of operations.
+void allocation_tracker_uninit(void) {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+ if (!enabled) return;
+
+ allocations.clear();
+ enabled = false;
+}
+
+void allocation_tracker_reset(void) {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+ if (!enabled) return;
+
+ allocations.clear();
+}
+
+size_t allocation_tracker_expect_no_allocations(void) {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+ if (!enabled) return 0;
+
+ size_t unfreed_memory_size = 0;
+
+ for (const auto& entry : allocations) {
+ allocation_t* allocation = entry.second;
+ if (!allocation->freed) {
+ unfreed_memory_size +=
+ allocation->size; // Report back the unfreed byte count
+ LOG_ERROR(LOG_TAG,
+ "%s found unfreed allocation. address: 0x%zx size: %zd bytes",
+ __func__, (uintptr_t)allocation->ptr, allocation->size);
+ }
+ }
+
+ return unfreed_memory_size;
+}
+
+void* allocation_tracker_notify_alloc(uint8_t allocator_id, void* ptr,
+ size_t requested_size) {
+ char* return_ptr;
+ {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+ if (!enabled || !ptr) return ptr;
+
+ // Keep statistics
+ alloc_counter++;
+ alloc_total_size += allocation_tracker_resize_for_canary(requested_size);
+
+ return_ptr = ((char*)ptr) + canary_size;
+
+ auto map_entry = allocations.find(return_ptr);
+ allocation_t* allocation;
+ if (map_entry != allocations.end()) {
+ allocation = map_entry->second;
+ CHECK(allocation->freed); // Must have been freed before
+ } else {
+ allocation = (allocation_t*)calloc(1, sizeof(allocation_t));
+ allocations[return_ptr] = allocation;
+ }
+
+ allocation->allocator_id = allocator_id;
+ allocation->freed = false;
+ allocation->size = requested_size;
+ allocation->ptr = return_ptr;
+ }
+
+ // Add the canary on both sides
+ memcpy(return_ptr - canary_size, canary, canary_size);
+ memcpy(return_ptr + requested_size, canary, canary_size);
+
+ return return_ptr;
+}
+
+void* allocation_tracker_notify_free(UNUSED_ATTR uint8_t allocator_id,
+ void* ptr) {
+ std::unique_lock<std::mutex> lock(tracker_lock);
+
+ if (!enabled || !ptr) return ptr;
+
+ auto map_entry = allocations.find(ptr);
+ CHECK(map_entry != allocations.end());
+ allocation_t* allocation = map_entry->second;
+ CHECK(allocation); // Must have been tracked before
+ CHECK(!allocation->freed); // Must not be a double free
+ CHECK(allocation->allocator_id ==
+ allocator_id); // Must be from the same allocator
+
+ // Keep statistics
+ free_counter++;
+ free_total_size += allocation_tracker_resize_for_canary(allocation->size);
+
+ allocation->freed = true;
+
+ UNUSED_ATTR const char* beginning_canary = ((char*)ptr) - canary_size;
+ UNUSED_ATTR const char* end_canary = ((char*)ptr) + allocation->size;
+
+ for (size_t i = 0; i < canary_size; i++) {
+ CHECK(beginning_canary[i] == canary[i]);
+ CHECK(end_canary[i] == canary[i]);
+ }
+
+ // Free the hash map entry to avoid unlimited memory usage growth.
+ // Double-free of memory is detected with "assert(allocation)" above
+ // as the allocation entry will not be present.
+ allocations.erase(ptr);
+ free(allocation);
+
+ return ((char*)ptr) - canary_size;
+}
+
+size_t allocation_tracker_resize_for_canary(size_t size) {
+ return (!enabled) ? size : size + (2 * canary_size);
+}
+
+void osi_allocator_debug_dump(int fd) {
+ dprintf(fd, "\nBluetooth Memory Allocation Statistics:\n");
+
+ std::unique_lock<std::mutex> lock(tracker_lock);
+
+ dprintf(fd, " Total allocated/free/used counts : %zu / %zu / %zu\n",
+ alloc_counter, free_counter, alloc_counter - free_counter);
+ dprintf(fd, " Total allocated/free/used octets : %zu / %zu / %zu\n",
+ alloc_total_size, free_total_size,
+ alloc_total_size - free_total_size);
+}
diff --git a/mtkbt/code/bt/osi/src/allocator.cc b/mtkbt/code/bt/osi/src/allocator.cc
new file mode 100755
index 0000000..4e4f9a7
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/allocator.cc
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "osi/include/allocation_tracker.h"
+#include "osi/include/allocator.h"
+
+static const allocator_id_t alloc_allocator_id = 42;
+
+char* osi_strdup(const char* str) {
+ size_t size = strlen(str) + 1; // + 1 for the null terminator
+ size_t real_size = allocation_tracker_resize_for_canary(size);
+ void* ptr = malloc(real_size);
+ CHECK(ptr);
+
+ char* new_string = static_cast<char*>(
+ allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size));
+ if (!new_string) return NULL;
+
+ memcpy(new_string, str, size);
+ return new_string;
+}
+
+char* osi_strndup(const char* str, size_t len) {
+ size_t size = strlen(str);
+ if (len < size) size = len;
+
+ size_t real_size = allocation_tracker_resize_for_canary(size + 1);
+ void* ptr = malloc(real_size);
+ CHECK(ptr);
+
+ char* new_string = static_cast<char*>(
+ allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size + 1));
+ if (!new_string) return NULL;
+
+ memcpy(new_string, str, size);
+ new_string[size] = '\0';
+ return new_string;
+}
+
+void* osi_malloc(size_t size) {
+ size_t real_size = allocation_tracker_resize_for_canary(size);
+ void* ptr = malloc(real_size);
+ CHECK(ptr);
+ return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size);
+}
+
+void* osi_calloc(size_t size) {
+ size_t real_size = allocation_tracker_resize_for_canary(size);
+ void* ptr = calloc(1, real_size);
+ CHECK(ptr);
+ return allocation_tracker_notify_alloc(alloc_allocator_id, ptr, size);
+}
+
+void osi_free(void* ptr) {
+ free(allocation_tracker_notify_free(alloc_allocator_id, ptr));
+}
+
+void osi_free_and_reset(void** p_ptr) {
+ CHECK(p_ptr != NULL);
+ osi_free(*p_ptr);
+ *p_ptr = NULL;
+}
+
+const allocator_t allocator_calloc = {osi_calloc, osi_free};
+
+const allocator_t allocator_malloc = {osi_malloc, osi_free};
diff --git a/mtkbt/code/bt/osi/src/array.cc b/mtkbt/code/bt/osi/src/array.cc
new file mode 100755
index 0000000..913b711
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/array.cc
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_array"
+
+#include "osi/include/array.h"
+
+#include <base/logging.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+struct array_t {
+ size_t element_size;
+ size_t length;
+ size_t capacity;
+ uint8_t* data;
+ uint8_t internal_storage[];
+};
+
+static bool grow(array_t* array);
+
+static const size_t INTERNAL_ELEMENTS = 16;
+
+array_t* array_new(size_t element_size) {
+ CHECK(element_size > 0);
+
+ array_t* array = static_cast<array_t*>(
+ osi_calloc(sizeof(array_t) + element_size * INTERNAL_ELEMENTS));
+
+ array->element_size = element_size;
+ array->capacity = INTERNAL_ELEMENTS;
+ array->data = array->internal_storage;
+ return array;
+}
+
+void array_free(array_t* array) {
+ if (!array) return;
+
+ if (array->data != array->internal_storage) free(array->data);
+
+ osi_free(array);
+}
+
+void* array_ptr(const array_t* array) { return array_at(array, 0); }
+
+void* array_at(const array_t* array, size_t index) {
+ CHECK(array != NULL);
+ CHECK(index < array->length);
+ return array->data + (index * array->element_size);
+}
+
+size_t array_length(const array_t* array) {
+ CHECK(array != NULL);
+ return array->length;
+}
+
+bool array_append_value(array_t* array, uint32_t value) {
+ return array_append_ptr(array, &value);
+}
+
+bool array_append_ptr(array_t* array, void* data) {
+ CHECK(array != NULL);
+ CHECK(data != NULL);
+
+ if (array->length == array->capacity && !grow(array)) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to grow array past current capacity of %zu elements "
+ "of size %zu.",
+ __func__, array->capacity, array->element_size);
+ return false;
+ }
+
+ ++array->length;
+ memcpy(array_at(array, array->length - 1), data, array->element_size);
+ return true;
+}
+
+static bool grow(array_t* array) {
+ const size_t new_capacity = array->capacity + (array->capacity / 2);
+ const bool is_moving = (array->data == array->internal_storage);
+
+ void* new_data = realloc(is_moving ? NULL : array->data,
+ new_capacity * array->element_size);
+ if (!new_data) return false;
+
+ if (is_moving)
+ memcpy(new_data, array->internal_storage,
+ array->length * array->element_size);
+
+ array->data = static_cast<uint8_t*>(new_data);
+ array->capacity = new_capacity;
+ return true;
+}
diff --git a/mtkbt/code/bt/osi/src/buffer.cc b/mtkbt/code/bt/osi/src/buffer.cc
new file mode 100755
index 0000000..abfacdb
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/buffer.cc
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_buffer"
+
+#include "osi/include/buffer.h"
+
+#include <base/logging.h>
+#include <stdint.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+struct buffer_t {
+ buffer_t* root;
+ size_t refcount;
+ size_t length;
+ uint8_t data[];
+};
+
+buffer_t* buffer_new(size_t size) {
+ CHECK(size > 0);
+
+ buffer_t* buffer =
+ static_cast<buffer_t*>(osi_calloc(sizeof(buffer_t) + size));
+
+ buffer->root = buffer;
+ buffer->refcount = 1;
+ buffer->length = size;
+
+ return buffer;
+}
+
+buffer_t* buffer_new_ref(const buffer_t* buf) {
+ CHECK(buf != NULL);
+ return buffer_new_slice(buf, buf->length);
+}
+
+buffer_t* buffer_new_slice(const buffer_t* buf, size_t slice_size) {
+ CHECK(buf != NULL);
+ CHECK(slice_size > 0);
+ CHECK(slice_size <= buf->length);
+
+ buffer_t* ret = static_cast<buffer_t*>(osi_calloc(sizeof(buffer_t)));
+
+ ret->root = buf->root;
+ ret->refcount = SIZE_MAX;
+ ret->length = slice_size;
+
+ ++buf->root->refcount;
+
+ return ret;
+}
+
+void buffer_free(buffer_t* buffer) {
+ if (!buffer) return;
+
+ if (buffer->root != buffer) {
+ // We're a leaf node. Delete the root node if we're the last referent.
+ if (--buffer->root->refcount == 0) osi_free(buffer->root);
+ osi_free(buffer);
+ } else if (--buffer->refcount == 0) {
+ // We're a root node. Roots are only deleted when their refcount goes to 0.
+ osi_free(buffer);
+ }
+}
+
+void* buffer_ptr(const buffer_t* buf) {
+ CHECK(buf != NULL);
+ return buf->root->data + buf->root->length - buf->length;
+}
+
+size_t buffer_length(const buffer_t* buf) {
+ CHECK(buf != NULL);
+ return buf->length;
+}
diff --git a/mtkbt/code/bt/osi/src/compat.cc b/mtkbt/code/bt/osi/src/compat.cc
new file mode 100755
index 0000000..069964c
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/compat.cc
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ * Copyright 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: compat.cc
+ *
+ * Description: Compatibility functions for non-bionic C libraries
+ *
+ *
+ ******************************************************************************/
+
+#include <features.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/compat.h"
+#include "osi/include/osi.h"
+
+#if __GLIBC__
+pid_t gettid(void) { return syscall(SYS_gettid); }
+#endif
+
+/* These functions from bionic
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if __GLIBC__
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(char* dst, const char* src, size_t siz) {
+ char* d = dst;
+ const char* s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0') break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0) *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return (s - src - 1); /* count does not include NUL */
+}
+#endif
+
+#if __GLIBC__
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t strlcat(char* dst, const char* src, size_t siz) {
+ char* d = dst;
+ const char* s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0') d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0) return (dlen + strlen(s));
+
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+
+ s++;
+ }
+
+ *d = '\0';
+
+ return (dlen + (s - src)); /* count does not include NUL */
+}
+#endif
diff --git a/mtkbt/code/bt/osi/src/config.cc b/mtkbt/code/bt/osi/src/config.cc
new file mode 100755
index 0000000..1019721
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/config.cc
@@ -0,0 +1,517 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_config"
+
+#include "osi/include/config.h"
+
+#include <base/logging.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+typedef struct {
+ char* key;
+ char* value;
+} entry_t;
+
+typedef struct {
+ char* name;
+ list_t* entries;
+} section_t;
+
+struct config_t {
+ list_t* sections;
+};
+
+// Empty definition; this type is aliased to list_node_t.
+struct config_section_iter_t {};
+
+static bool config_parse(FILE* fp, config_t* config);
+
+static section_t* section_new(const char* name);
+static void section_free(void* ptr);
+static section_t* section_find(const config_t* config, const char* section);
+
+static entry_t* entry_new(const char* key, const char* value);
+static void entry_free(void* ptr);
+static entry_t* entry_find(const config_t* config, const char* section,
+ const char* key);
+
+config_t* config_new_empty(void) {
+ config_t* config = static_cast<config_t*>(osi_calloc(sizeof(config_t)));
+
+ config->sections = list_new(section_free);
+ if (!config->sections) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate list for sections.", __func__);
+ goto error;
+ }
+
+ return config;
+
+error:;
+ config_free(config);
+ return NULL;
+}
+
+config_t* config_new(const char* filename) {
+ CHECK(filename != NULL);
+
+ config_t* config = config_new_empty();
+ if (!config) return NULL;
+
+ FILE* fp = fopen(filename, "rt");
+ if (!fp) {
+ LOG_ERROR(LOG_TAG, "%s unable to open file '%s': %s", __func__, filename,
+ strerror(errno));
+ config_free(config);
+ return NULL;
+ }
+
+ if (!config_parse(fp, config)) {
+ config_free(config);
+ config = NULL;
+ }
+
+ fclose(fp);
+ return config;
+}
+
+config_t* config_new_clone(const config_t* src) {
+ CHECK(src != NULL);
+
+ config_t* ret = config_new_empty();
+
+ CHECK(ret != NULL);
+
+ for (const list_node_t* node = list_begin(src->sections);
+ node != list_end(src->sections); node = list_next(node)) {
+ section_t* sec = static_cast<section_t*>(list_node(node));
+
+ for (const list_node_t* node_entry = list_begin(sec->entries);
+ node_entry != list_end(sec->entries);
+ node_entry = list_next(node_entry)) {
+ entry_t* entry = static_cast<entry_t*>(list_node(node_entry));
+
+ config_set_string(ret, sec->name, entry->key, entry->value);
+ }
+ }
+
+ return ret;
+}
+
+void config_free(config_t* config) {
+ if (!config) return;
+
+ list_free(config->sections);
+ osi_free(config);
+}
+
+bool config_has_section(const config_t* config, const char* section) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+
+ return (section_find(config, section) != NULL);
+}
+
+bool config_has_key(const config_t* config, const char* section,
+ const char* key) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ return (entry_find(config, section, key) != NULL);
+}
+
+int config_get_int(const config_t* config, const char* section, const char* key,
+ int def_value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ entry_t* entry = entry_find(config, section, key);
+ if (!entry) return def_value;
+
+ char* endptr;
+ int ret = strtol(entry->value, &endptr, 0);
+ return (*endptr == '\0') ? ret : def_value;
+}
+
+bool config_get_bool(const config_t* config, const char* section,
+ const char* key, bool def_value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ entry_t* entry = entry_find(config, section, key);
+ if (!entry) return def_value;
+
+ if (!strcmp(entry->value, "true")) return true;
+ if (!strcmp(entry->value, "false")) return false;
+
+ return def_value;
+}
+
+const char* config_get_string(const config_t* config, const char* section,
+ const char* key, const char* def_value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ entry_t* entry = entry_find(config, section, key);
+ if (!entry) return def_value;
+
+ return entry->value;
+}
+
+void config_set_int(config_t* config, const char* section, const char* key,
+ int value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ char value_str[32] = {0};
+ snprintf(value_str, sizeof(value_str), "%d", value);
+ config_set_string(config, section, key, value_str);
+}
+
+void config_set_bool(config_t* config, const char* section, const char* key,
+ bool value) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ config_set_string(config, section, key, value ? "true" : "false");
+}
+
+void config_set_string(config_t* config, const char* section, const char* key,
+ const char* value) {
+ section_t* sec = section_find(config, section);
+ if (!sec) {
+ sec = section_new(section);
+ list_append(config->sections, sec);
+ }
+
+ for (const list_node_t* node = list_begin(sec->entries);
+ node != list_end(sec->entries); node = list_next(node)) {
+ entry_t* entry = static_cast<entry_t*>(list_node(node));
+ if (!strcmp(entry->key, key)) {
+ osi_free(entry->value);
+ entry->value = osi_strdup(value);
+ return;
+ }
+ }
+
+ entry_t* entry = entry_new(key, value);
+ list_append(sec->entries, entry);
+}
+
+bool config_remove_section(config_t* config, const char* section) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+
+ section_t* sec = section_find(config, section);
+ if (!sec) return false;
+
+ return list_remove(config->sections, sec);
+}
+
+bool config_remove_key(config_t* config, const char* section, const char* key) {
+ CHECK(config != NULL);
+ CHECK(section != NULL);
+ CHECK(key != NULL);
+
+ section_t* sec = section_find(config, section);
+ entry_t* entry = entry_find(config, section, key);
+ if (!sec || !entry) return false;
+
+ return list_remove(sec->entries, entry);
+}
+
+const config_section_node_t* config_section_begin(const config_t* config) {
+ CHECK(config != NULL);
+ return (const config_section_node_t*)list_begin(config->sections);
+}
+
+const config_section_node_t* config_section_end(const config_t* config) {
+ CHECK(config != NULL);
+ return (const config_section_node_t*)list_end(config->sections);
+}
+
+const config_section_node_t* config_section_next(
+ const config_section_node_t* node) {
+ CHECK(node != NULL);
+ return (const config_section_node_t*)list_next((const list_node_t*)node);
+}
+
+const char* config_section_name(const config_section_node_t* node) {
+ CHECK(node != NULL);
+ const list_node_t* lnode = (const list_node_t*)node;
+ const section_t* section = (const section_t*)list_node(lnode);
+ return section->name;
+}
+
+bool config_save(const config_t* config, const char* filename) {
+ CHECK(config != NULL);
+ CHECK(filename != NULL);
+ CHECK(*filename != '\0');
+
+ // Steps to ensure content of config file gets to disk:
+ //
+ // 1) Open and write to temp file (e.g. bt_config.conf.new).
+ // 2) Sync the temp file to disk with fsync().
+ // 3) Rename temp file to actual config file (e.g. bt_config.conf).
+ // This ensures atomic update.
+ // 4) Sync directory that has the conf file with fsync().
+ // This ensures directory entries are up-to-date.
+ int dir_fd = -1;
+ FILE* fp = NULL;
+
+ // Build temp config file based on config file (e.g. bt_config.conf.new).
+ static const char* temp_file_ext = ".new";
+ const int filename_len = strlen(filename);
+ const int temp_filename_len = filename_len + strlen(temp_file_ext) + 1;
+ char* temp_filename = static_cast<char*>(osi_calloc(temp_filename_len));
+ snprintf(temp_filename, temp_filename_len, "%s%s", filename, temp_file_ext);
+
+ // Extract directory from file path (e.g. /data/misc/bluedroid).
+ char* temp_dirname = osi_strdup(filename);
+ const char* directoryname = dirname(temp_dirname);
+ if (!directoryname) {
+ LOG_ERROR(LOG_TAG, "%s error extracting directory from '%s': %s", __func__,
+ filename, strerror(errno));
+ goto error;
+ }
+
+ dir_fd = open(directoryname, O_RDONLY);
+ if (dir_fd < 0) {
+ LOG_ERROR(LOG_TAG, "%s unable to open dir '%s': %s", __func__,
+ directoryname, strerror(errno));
+ goto error;
+ }
+
+ fp = fopen(temp_filename, "wt");
+ if (!fp) {
+ LOG_ERROR(LOG_TAG, "%s unable to write file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ goto error;
+ }
+
+ for (const list_node_t* node = list_begin(config->sections);
+ node != list_end(config->sections); node = list_next(node)) {
+ const section_t* section = (const section_t*)list_node(node);
+ if (fprintf(fp, "[%s]\n", section->name) < 0) {
+ LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ goto error;
+ }
+
+ for (const list_node_t* enode = list_begin(section->entries);
+ enode != list_end(section->entries); enode = list_next(enode)) {
+ const entry_t* entry = (const entry_t*)list_node(enode);
+ if (fprintf(fp, "%s = %s\n", entry->key, entry->value) < 0) {
+ LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ goto error;
+ }
+ }
+
+ // Only add a separating newline if there are more sections.
+ if (list_next(node) != list_end(config->sections)) {
+ if (fputc('\n', fp) == EOF) {
+ LOG_ERROR(LOG_TAG, "%s unable to write to file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ goto error;
+ }
+ }
+ }
+
+ // Sync written temp file out to disk. fsync() is blocking until data makes it
+ // to disk.
+ if (fsync(fileno(fp)) < 0) {
+ LOG_WARN(LOG_TAG, "%s unable to fsync file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ }
+
+ if (fclose(fp) == EOF) {
+ LOG_ERROR(LOG_TAG, "%s unable to close file '%s': %s", __func__,
+ temp_filename, strerror(errno));
+ goto error;
+ }
+ fp = NULL;
+
+ // Change the file's permissions to Read/Write by User and Group
+ if (chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to change file permissions '%s': %s",
+ __func__, filename, strerror(errno));
+ goto error;
+ }
+
+ // Rename written temp file to the actual config file.
+ if (rename(temp_filename, filename) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to commit file '%s': %s", __func__, filename,
+ strerror(errno));
+ goto error;
+ }
+
+ // This should ensure the directory is updated as well.
+ if (fsync(dir_fd) < 0) {
+ LOG_WARN(LOG_TAG, "%s unable to fsync dir '%s': %s", __func__,
+ directoryname, strerror(errno));
+ }
+
+ if (close(dir_fd) < 0) {
+ LOG_ERROR(LOG_TAG, "%s unable to close dir '%s': %s", __func__,
+ directoryname, strerror(errno));
+ goto error;
+ }
+
+ osi_free(temp_filename);
+ osi_free(temp_dirname);
+ return true;
+
+error:
+ // This indicates there is a write issue. Unlink as partial data is not
+ // acceptable.
+ unlink(temp_filename);
+ if (fp) fclose(fp);
+ if (dir_fd != -1) close(dir_fd);
+ osi_free(temp_filename);
+ osi_free(temp_dirname);
+ return false;
+}
+
+static char* trim(char* str) {
+ while (isspace(*str)) ++str;
+
+ if (!*str) return str;
+
+ char* end_str = str + strlen(str) - 1;
+ while (end_str > str && isspace(*end_str)) --end_str;
+
+ end_str[1] = '\0';
+ return str;
+}
+
+static bool config_parse(FILE* fp, config_t* config) {
+ CHECK(fp != NULL);
+ CHECK(config != NULL);
+
+ int line_num = 0;
+ char line[1024];
+ char section[1024];
+ strcpy(section, CONFIG_DEFAULT_SECTION);
+
+ while (fgets(line, sizeof(line), fp)) {
+ char* line_ptr = trim(line);
+ ++line_num;
+
+ // Skip blank and comment lines.
+ if (*line_ptr == '\0' || *line_ptr == '#') continue;
+
+ if (*line_ptr == '[') {
+ size_t len = strlen(line_ptr);
+ if (line_ptr[len - 1] != ']') {
+ LOG_DEBUG(LOG_TAG, "%s unterminated section name on line %d.", __func__,
+ line_num);
+ return false;
+ }
+ strncpy(section, line_ptr + 1, len - 2);
+ section[len - 2] = '\0';
+ } else {
+ char* split = strchr(line_ptr, '=');
+ if (!split) {
+ LOG_DEBUG(LOG_TAG, "%s no key/value separator found on line %d.",
+ __func__, line_num);
+ return false;
+ }
+
+ *split = '\0';
+ config_set_string(config, section, trim(line_ptr), trim(split + 1));
+ }
+ }
+ return true;
+}
+
+static section_t* section_new(const char* name) {
+ section_t* section = static_cast<section_t*>(osi_calloc(sizeof(section_t)));
+
+ section->name = osi_strdup(name);
+ section->entries = list_new(entry_free);
+ return section;
+}
+
+static void section_free(void* ptr) {
+ if (!ptr) return;
+
+ section_t* section = static_cast<section_t*>(ptr);
+ osi_free(section->name);
+ list_free(section->entries);
+ osi_free(section);
+}
+
+static section_t* section_find(const config_t* config, const char* section) {
+ for (const list_node_t* node = list_begin(config->sections);
+ node != list_end(config->sections); node = list_next(node)) {
+ section_t* sec = static_cast<section_t*>(list_node(node));
+ if (!strcmp(sec->name, section)) return sec;
+ }
+
+ return NULL;
+}
+
+static entry_t* entry_new(const char* key, const char* value) {
+ entry_t* entry = static_cast<entry_t*>(osi_calloc(sizeof(entry_t)));
+
+ entry->key = osi_strdup(key);
+ entry->value = osi_strdup(value);
+ return entry;
+}
+
+static void entry_free(void* ptr) {
+ if (!ptr) return;
+
+ entry_t* entry = static_cast<entry_t*>(ptr);
+ osi_free(entry->key);
+ osi_free(entry->value);
+ osi_free(entry);
+}
+
+static entry_t* entry_find(const config_t* config, const char* section,
+ const char* key) {
+ section_t* sec = section_find(config, section);
+ if (!sec) return NULL;
+
+ for (const list_node_t* node = list_begin(sec->entries);
+ node != list_end(sec->entries); node = list_next(node)) {
+ entry_t* entry = static_cast<entry_t*>(list_node(node));
+ if (!strcmp(entry->key, key)) return entry;
+ }
+
+ return NULL;
+}
diff --git a/mtkbt/code/bt/osi/src/data_dispatcher.cc b/mtkbt/code/bt/osi/src/data_dispatcher.cc
new file mode 100755
index 0000000..385f395
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/data_dispatcher.cc
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_data_dispatcher"
+
+#include "osi/include/data_dispatcher.h"
+
+#include <base/logging.h>
+#include <unordered_map>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define DEFAULT_TABLE_BUCKETS 10
+
+typedef std::unordered_map<data_dispatcher_type_t, fixed_queue_t*>
+ DispatchTableMap;
+
+struct data_dispatcher_t {
+ char* name;
+ DispatchTableMap* dispatch_table;
+ fixed_queue_t* default_queue; // We don't own this queue
+};
+
+data_dispatcher_t* data_dispatcher_new(const char* name) {
+ CHECK(name != NULL);
+
+ data_dispatcher_t* ret =
+ (data_dispatcher_t*)osi_calloc(sizeof(data_dispatcher_t));
+
+ ret->dispatch_table = new DispatchTableMap();
+
+ ret->name = osi_strdup(name);
+ if (!ret->name) {
+ LOG_ERROR(LOG_TAG, "%s unable to duplicate provided name.", __func__);
+ goto error;
+ }
+
+ return ret;
+
+error:;
+ data_dispatcher_free(ret);
+ return NULL;
+}
+
+void data_dispatcher_free(data_dispatcher_t* dispatcher) {
+ if (!dispatcher) return;
+
+ delete dispatcher->dispatch_table;
+ osi_free(dispatcher->name);
+ osi_free(dispatcher);
+}
+
+void data_dispatcher_register(data_dispatcher_t* dispatcher,
+ data_dispatcher_type_t type,
+ fixed_queue_t* queue) {
+ CHECK(dispatcher != NULL);
+
+ if (queue)
+ (*dispatcher->dispatch_table)[type] = queue;
+ else
+ dispatcher->dispatch_table->erase(type);
+}
+
+void data_dispatcher_register_default(data_dispatcher_t* dispatcher,
+ fixed_queue_t* queue) {
+ CHECK(dispatcher != NULL);
+
+ dispatcher->default_queue = queue;
+}
+
+bool data_dispatcher_dispatch(data_dispatcher_t* dispatcher,
+ data_dispatcher_type_t type, void* data) {
+ CHECK(dispatcher != NULL);
+ CHECK(data != NULL);
+
+ fixed_queue_t* queue;
+ auto iter = dispatcher->dispatch_table->find(type);
+ if (iter == dispatcher->dispatch_table->end())
+ queue = dispatcher->default_queue;
+ else
+ queue = iter->second;
+
+ if (queue)
+ fixed_queue_enqueue(queue, data);
+ else
+ LOG_WARN(LOG_TAG,
+ "%s has no handler for type (%zd) in data dispatcher named: %s",
+ __func__, type, dispatcher->name);
+
+ return queue != NULL;
+}
diff --git a/mtkbt/code/bt/osi/src/fixed_queue.cc b/mtkbt/code/bt/osi/src/fixed_queue.cc
new file mode 100755
index 0000000..c384050
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/fixed_queue.cc
@@ -0,0 +1,262 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <string.h>
+
+#include <mutex>
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+
+typedef struct fixed_queue_t {
+ list_t* list;
+ semaphore_t* enqueue_sem;
+ semaphore_t* dequeue_sem;
+ std::mutex* mutex;
+ size_t capacity;
+
+ reactor_object_t* dequeue_object;
+ fixed_queue_cb dequeue_ready;
+ void* dequeue_context;
+} fixed_queue_t;
+
+static void internal_dequeue_ready(void* context);
+
+fixed_queue_t* fixed_queue_new(size_t capacity) {
+ fixed_queue_t* ret =
+ static_cast<fixed_queue_t*>(osi_calloc(sizeof(fixed_queue_t)));
+
+ ret->mutex = new std::mutex;
+ ret->capacity = capacity;
+
+ ret->list = list_new(NULL);
+ if (!ret->list) goto error;
+
+ ret->enqueue_sem = semaphore_new(capacity);
+ if (!ret->enqueue_sem) goto error;
+
+ ret->dequeue_sem = semaphore_new(0);
+ if (!ret->dequeue_sem) goto error;
+
+ return ret;
+
+error:
+ fixed_queue_free(ret, NULL);
+ return NULL;
+}
+
+void fixed_queue_free(fixed_queue_t* queue, fixed_queue_free_cb free_cb) {
+ if (!queue) return;
+
+ fixed_queue_unregister_dequeue(queue);
+
+ if (free_cb)
+ for (const list_node_t* node = list_begin(queue->list);
+ node != list_end(queue->list); node = list_next(node))
+ free_cb(list_node(node));
+
+ list_free(queue->list);
+ semaphore_free(queue->enqueue_sem);
+ semaphore_free(queue->dequeue_sem);
+ delete queue->mutex;
+ osi_free(queue);
+}
+
+void fixed_queue_flush(fixed_queue_t* queue, fixed_queue_free_cb free_cb) {
+ if (!queue) return;
+
+ while (!fixed_queue_is_empty(queue)) {
+ void* data = fixed_queue_try_dequeue(queue);
+ if (free_cb != NULL) {
+ free_cb(data);
+ }
+ }
+}
+
+bool fixed_queue_is_empty(fixed_queue_t* queue) {
+ if (queue == NULL) return true;
+
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ return list_is_empty(queue->list);
+}
+
+size_t fixed_queue_length(fixed_queue_t* queue) {
+ if (queue == NULL) return 0;
+
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ return list_length(queue->list);
+}
+
+size_t fixed_queue_capacity(fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+
+ return queue->capacity;
+}
+
+void fixed_queue_enqueue(fixed_queue_t* queue, void* data) {
+ CHECK(queue != NULL);
+ CHECK(data != NULL);
+
+ semaphore_wait(queue->enqueue_sem);
+
+ {
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ list_append(queue->list, data);
+ }
+
+ semaphore_post(queue->dequeue_sem);
+}
+
+void* fixed_queue_dequeue(fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+
+ semaphore_wait(queue->dequeue_sem);
+
+ void* ret = NULL;
+ {
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ ret = list_front(queue->list);
+ list_remove(queue->list, ret);
+ }
+
+ semaphore_post(queue->enqueue_sem);
+
+ return ret;
+}
+
+bool fixed_queue_try_enqueue(fixed_queue_t* queue, void* data) {
+ CHECK(queue != NULL);
+ CHECK(data != NULL);
+
+ if (!semaphore_try_wait(queue->enqueue_sem)) return false;
+
+ {
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ list_append(queue->list, data);
+ }
+
+ semaphore_post(queue->dequeue_sem);
+ return true;
+}
+
+void* fixed_queue_try_dequeue(fixed_queue_t* queue) {
+ if (queue == NULL) return NULL;
+
+ if (!semaphore_try_wait(queue->dequeue_sem)) return NULL;
+
+ void* ret = NULL;
+ {
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ ret = list_front(queue->list);
+ list_remove(queue->list, ret);
+ }
+
+ semaphore_post(queue->enqueue_sem);
+
+ return ret;
+}
+
+void* fixed_queue_try_peek_first(fixed_queue_t* queue) {
+ if (queue == NULL) return NULL;
+
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ return list_is_empty(queue->list) ? NULL : list_front(queue->list);
+}
+
+void* fixed_queue_try_peek_last(fixed_queue_t* queue) {
+ if (queue == NULL) return NULL;
+
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ return list_is_empty(queue->list) ? NULL : list_back(queue->list);
+}
+
+void* fixed_queue_try_remove_from_queue(fixed_queue_t* queue, void* data) {
+ if (queue == NULL) return NULL;
+
+ bool removed = false;
+ {
+ std::lock_guard<std::mutex> lock(*queue->mutex);
+ if (list_contains(queue->list, data) &&
+ semaphore_try_wait(queue->dequeue_sem)) {
+ removed = list_remove(queue->list, data);
+ CHECK(removed);
+ }
+ }
+
+ if (removed) {
+ semaphore_post(queue->enqueue_sem);
+ return data;
+ }
+ return NULL;
+}
+
+list_t* fixed_queue_get_list(fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+
+ // NOTE: Using the list in this way is not thread-safe.
+ // Using this list in any context where threads can call other functions
+ // to the queue can break our assumptions and the queue in general.
+ return queue->list;
+}
+
+int fixed_queue_get_dequeue_fd(const fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+ return semaphore_get_fd(queue->dequeue_sem);
+}
+
+int fixed_queue_get_enqueue_fd(const fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+ return semaphore_get_fd(queue->enqueue_sem);
+}
+
+void fixed_queue_register_dequeue(fixed_queue_t* queue, reactor_t* reactor,
+ fixed_queue_cb ready_cb, void* context) {
+ CHECK(queue != NULL);
+ CHECK(reactor != NULL);
+ CHECK(ready_cb != NULL);
+
+ // Make sure we're not already registered
+ fixed_queue_unregister_dequeue(queue);
+
+ queue->dequeue_ready = ready_cb;
+ queue->dequeue_context = context;
+ queue->dequeue_object =
+ reactor_register(reactor, fixed_queue_get_dequeue_fd(queue), queue,
+ internal_dequeue_ready, NULL);
+}
+
+void fixed_queue_unregister_dequeue(fixed_queue_t* queue) {
+ CHECK(queue != NULL);
+
+ if (queue->dequeue_object) {
+ reactor_unregister(queue->dequeue_object);
+ queue->dequeue_object = NULL;
+ }
+}
+
+static void internal_dequeue_ready(void* context) {
+ CHECK(context != NULL);
+
+ fixed_queue_t* queue = static_cast<fixed_queue_t*>(context);
+ queue->dequeue_ready(queue, queue->dequeue_context);
+}
diff --git a/mtkbt/code/bt/osi/src/future.cc b/mtkbt/code/bt/osi/src/future.cc
new file mode 100755
index 0000000..cbfd91a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/future.cc
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_future"
+
+#include "osi/include/future.h"
+
+#include <base/logging.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+
+struct future_t {
+ bool ready_can_be_called;
+ semaphore_t* semaphore; // NULL semaphore means immediate future
+ void* result;
+};
+
+static void future_free(future_t* future);
+
+future_t* future_new(void) {
+ future_t* ret = static_cast<future_t*>(osi_calloc(sizeof(future_t)));
+
+ ret->semaphore = semaphore_new(0);
+ if (!ret->semaphore) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate memory for the semaphore.",
+ __func__);
+ goto error;
+ }
+
+ ret->ready_can_be_called = true;
+ return ret;
+error:;
+ future_free(ret);
+ return NULL;
+}
+
+future_t* future_new_immediate(void* value) {
+ future_t* ret = static_cast<future_t*>(osi_calloc(sizeof(future_t)));
+
+ ret->result = value;
+ ret->ready_can_be_called = false;
+ return ret;
+}
+
+void future_ready(future_t* future, void* value) {
+ CHECK(future != NULL);
+ CHECK(future->ready_can_be_called);
+
+ future->ready_can_be_called = false;
+ future->result = value;
+ semaphore_post(future->semaphore);
+}
+
+void* future_await(future_t* future) {
+ CHECK(future != NULL);
+
+ // If the future is immediate, it will not have a semaphore
+ if (future->semaphore) semaphore_wait(future->semaphore);
+
+ void* result = future->result;
+ future_free(future);
+ return result;
+}
+
+static void future_free(future_t* future) {
+ if (!future) return;
+
+ semaphore_free(future->semaphore);
+ osi_free(future);
+}
diff --git a/mtkbt/code/bt/osi/src/hash_map_utils.cc b/mtkbt/code/bt/osi/src/hash_map_utils.cc
new file mode 100755
index 0000000..c934cfb
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/hash_map_utils.cc
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "hash_map_utils"
+
+#include "osi/include/hash_map_utils.h"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+std::unordered_map<std::string, std::string>
+hash_map_utils_new_from_string_params(const char* params) {
+ CHECK(params != NULL);
+
+ std::unordered_map<std::string, std::string> map;
+
+ char* str = osi_strdup(params);
+ if (!str) return map;
+
+ LOG_VERBOSE(LOG_TAG, "%s: source string: '%s'", __func__, str);
+
+ // Parse |str| and add extracted key-and-value pair(s) in |map|.
+ int items = 0;
+ char* tmpstr;
+ char* kvpair = strtok_r(str, ";", &tmpstr);
+ while (kvpair && *kvpair) {
+ char* eq = strchr(kvpair, '=');
+
+ if (eq == kvpair) goto next_pair;
+
+ char* key;
+ char* value;
+ if (eq) {
+ key = osi_strndup(kvpair, eq - kvpair);
+
+ // The increment of |eq| moves |eq| to the beginning of the value.
+ ++eq;
+ value = (*eq != '\0') ? osi_strdup(eq) : osi_strdup("");
+ } else {
+ key = osi_strdup(kvpair);
+ value = osi_strdup("");
+ }
+
+ map[key] = value;
+
+ osi_free(key);
+ osi_free(value);
+
+ items++;
+ next_pair:
+ kvpair = strtok_r(NULL, ";", &tmpstr);
+ }
+
+ if (!items) LOG_VERBOSE(LOG_TAG, "%s: no items found in string\n", __func__);
+
+ osi_free(str);
+ return map;
+}
+
+void hash_map_utils_dump_string_keys_string_values(
+ std::unordered_map<std::string, std::string>& map) {
+ for (const auto& ptr : map) {
+ LOG_INFO(LOG_TAG, "key: '%s' value: '%s'\n", ptr.first.c_str(),
+ ptr.second.c_str());
+ }
+}
diff --git a/mtkbt/code/bt/osi/src/list.cc b/mtkbt/code/bt/osi/src/list.cc
new file mode 100755
index 0000000..44ebe09
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/list.cc
@@ -0,0 +1,215 @@
+#include <base/logging.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+
+struct list_node_t {
+ struct list_node_t* next;
+ void* data;
+};
+
+typedef struct list_t {
+ list_node_t* head;
+ list_node_t* tail;
+ size_t length;
+ list_free_cb free_cb;
+ const allocator_t* allocator;
+} list_t;
+
+static list_node_t* list_free_node_(list_t* list, list_node_t* node);
+
+// Hidden constructor, only to be used by the hash map for the allocation
+// tracker.
+// Behaves the same as |list_new|, except you get to specify the allocator.
+list_t* list_new_internal(list_free_cb callback,
+ const allocator_t* zeroed_allocator) {
+ list_t* list = (list_t*)zeroed_allocator->alloc(sizeof(list_t));
+ if (!list) return NULL;
+
+ list->free_cb = callback;
+ list->allocator = zeroed_allocator;
+ return list;
+}
+
+list_t* list_new(list_free_cb callback) {
+ return list_new_internal(callback, &allocator_calloc);
+}
+
+void list_free(list_t* list) {
+ if (!list) return;
+
+ list_clear(list);
+ list->allocator->free(list);
+}
+
+bool list_is_empty(const list_t* list) {
+ CHECK(list != NULL);
+ return (list->length == 0);
+}
+
+bool list_contains(const list_t* list, const void* data) {
+ CHECK(list != NULL);
+ CHECK(data != NULL);
+
+ for (const list_node_t* node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ if (list_node(node) == data) return true;
+ }
+
+ return false;
+}
+
+size_t list_length(const list_t* list) {
+ CHECK(list != NULL);
+ return list->length;
+}
+
+void* list_front(const list_t* list) {
+ CHECK(list != NULL);
+ CHECK(!list_is_empty(list));
+
+ return list->head->data;
+}
+
+void* list_back(const list_t* list) {
+ CHECK(list != NULL);
+ CHECK(!list_is_empty(list));
+
+ return list->tail->data;
+}
+
+list_node_t* list_back_node(const list_t* list) {
+ CHECK(list != NULL);
+ CHECK(!list_is_empty(list));
+
+ return list->tail;
+}
+
+bool list_insert_after(list_t* list, list_node_t* prev_node, void* data) {
+ CHECK(list != NULL);
+ CHECK(prev_node != NULL);
+ CHECK(data != NULL);
+
+ list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+ if (!node) return false;
+
+ node->next = prev_node->next;
+ node->data = data;
+ prev_node->next = node;
+ if (list->tail == prev_node) list->tail = node;
+ ++list->length;
+ return true;
+}
+
+bool list_prepend(list_t* list, void* data) {
+ CHECK(list != NULL);
+ CHECK(data != NULL);
+
+ list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+ if (!node) return false;
+ node->next = list->head;
+ node->data = data;
+ list->head = node;
+ if (list->tail == NULL) list->tail = list->head;
+ ++list->length;
+ return true;
+}
+
+bool list_append(list_t* list, void* data) {
+ CHECK(list != NULL);
+ CHECK(data != NULL);
+
+ list_node_t* node = (list_node_t*)list->allocator->alloc(sizeof(list_node_t));
+ if (!node) return false;
+ node->next = NULL;
+ node->data = data;
+ if (list->tail == NULL) {
+ list->head = node;
+ list->tail = node;
+ } else {
+ list->tail->next = node;
+ list->tail = node;
+ }
+ ++list->length;
+ return true;
+}
+
+bool list_remove(list_t* list, void* data) {
+ CHECK(list != NULL);
+ CHECK(data != NULL);
+
+ if (list_is_empty(list)) return false;
+
+ if (list->head->data == data) {
+ list_node_t* next = list_free_node_(list, list->head);
+ if (list->tail == list->head) list->tail = next;
+ list->head = next;
+ return true;
+ }
+
+ for (list_node_t *prev = list->head, *node = list->head->next; node;
+ prev = node, node = node->next)
+ if (node->data == data) {
+ prev->next = list_free_node_(list, node);
+ if (list->tail == node) list->tail = prev;
+ return true;
+ }
+
+ return false;
+}
+
+void list_clear(list_t* list) {
+ CHECK(list != NULL);
+ for (list_node_t* node = list->head; node;)
+ node = list_free_node_(list, node);
+ list->head = NULL;
+ list->tail = NULL;
+ list->length = 0;
+}
+
+list_node_t* list_foreach(const list_t* list, list_iter_cb callback,
+ void* context) {
+ CHECK(list != NULL);
+ CHECK(callback != NULL);
+
+ for (list_node_t* node = list->head; node;) {
+ list_node_t* next = node->next;
+ if (!callback(node->data, context)) return node;
+ node = next;
+ }
+ return NULL;
+}
+
+list_node_t* list_begin(const list_t* list) {
+ CHECK(list != NULL);
+ return list->head;
+}
+
+list_node_t* list_end(UNUSED_ATTR const list_t* list) {
+ CHECK(list != NULL);
+ return NULL;
+}
+
+list_node_t* list_next(const list_node_t* node) {
+ CHECK(node != NULL);
+ return node->next;
+}
+
+void* list_node(const list_node_t* node) {
+ CHECK(node != NULL);
+ return node->data;
+}
+
+static list_node_t* list_free_node_(list_t* list, list_node_t* node) {
+ CHECK(list != NULL);
+ CHECK(node != NULL);
+
+ list_node_t* next = node->next;
+
+ if (list->free_cb) list->free_cb(node->data);
+ list->allocator->free(node);
+ --list->length;
+
+ return next;
+}
diff --git a/mtkbt/code/bt/osi/src/metrics.cc b/mtkbt/code/bt/osi/src/metrics.cc
new file mode 100755
index 0000000..f31bf4e
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/metrics.cc
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "bt_osi_metrics"
+
+#include <unistd.h>
+#include <algorithm>
+#include <cerrno>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <mutex>
+
+#include <base/base64.h>
+#include <base/logging.h>
+
+#include "osi/include/leaky_bonded_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+#include "stack/include/btm_api_types.h"
+
+#include "src/protos/bluetooth.pb.h"
+
+#include "osi/include/metrics.h"
+
+namespace system_bt_osi {
+
+using clearcut::connectivity::A2DPSession;
+using clearcut::connectivity::BluetoothLog;
+using clearcut::connectivity::BluetoothSession;
+using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
+using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
+using clearcut::connectivity::DeviceInfo;
+using clearcut::connectivity::DeviceInfo_DeviceType;
+using clearcut::connectivity::PairEvent;
+using clearcut::connectivity::ScanEvent;
+using clearcut::connectivity::ScanEvent_ScanTechnologyType;
+using clearcut::connectivity::ScanEvent_ScanEventType;
+using clearcut::connectivity::WakeEvent;
+using clearcut::connectivity::WakeEvent_WakeEventType;
+
+/*
+ * Get current OS boot time in millisecond
+ */
+static int64_t time_get_os_boottime_ms(void) {
+ return time_get_os_boottime_us() / 1000;
+}
+
+static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
+ if (metrics.audio_duration_ms >= 0) {
+ audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
+ audio_duration_ms += metrics.audio_duration_ms;
+ }
+ if (metrics.media_timer_min_ms >= 0) {
+ if (media_timer_min_ms < 0) {
+ media_timer_min_ms = metrics.media_timer_min_ms;
+ } else {
+ media_timer_min_ms =
+ std::min(media_timer_min_ms, metrics.media_timer_min_ms);
+ }
+ }
+ if (metrics.media_timer_max_ms >= 0) {
+ media_timer_max_ms =
+ std::max(media_timer_max_ms, metrics.media_timer_max_ms);
+ }
+ if (metrics.media_timer_avg_ms >= 0 && metrics.total_scheduling_count >= 0) {
+ if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
+ media_timer_avg_ms = metrics.media_timer_avg_ms;
+ total_scheduling_count = metrics.total_scheduling_count;
+ } else {
+ media_timer_avg_ms = combine_averages(
+ media_timer_avg_ms, total_scheduling_count,
+ metrics.media_timer_avg_ms, metrics.total_scheduling_count);
+ total_scheduling_count += metrics.total_scheduling_count;
+ }
+ }
+ if (metrics.buffer_overruns_max_count >= 0) {
+ buffer_overruns_max_count =
+ std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
+ }
+ if (metrics.buffer_overruns_total >= 0) {
+ buffer_overruns_total =
+ std::max(static_cast<int32_t>(0), buffer_overruns_total);
+ buffer_overruns_total += metrics.buffer_overruns_total;
+ }
+ if (metrics.buffer_underruns_average >= 0 &&
+ metrics.buffer_underruns_count >= 0) {
+ if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
+ buffer_underruns_average = metrics.buffer_underruns_average;
+ buffer_underruns_count = metrics.buffer_underruns_count;
+ } else {
+ buffer_underruns_average = combine_averages(
+ buffer_underruns_average, buffer_underruns_count,
+ metrics.buffer_underruns_average, metrics.buffer_underruns_count);
+ buffer_underruns_count += metrics.buffer_underruns_count;
+ }
+ }
+}
+
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ return audio_duration_ms == rhs.audio_duration_ms &&
+ media_timer_min_ms == rhs.media_timer_min_ms &&
+ media_timer_max_ms == rhs.media_timer_max_ms &&
+ media_timer_avg_ms == rhs.media_timer_avg_ms &&
+ total_scheduling_count == rhs.total_scheduling_count &&
+ buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
+ buffer_overruns_total == rhs.buffer_overruns_total &&
+ buffer_underruns_average == rhs.buffer_underruns_average &&
+ buffer_underruns_count == rhs.buffer_underruns_count;
+}
+
+static DeviceInfo_DeviceType get_device_type(device_type_t type) {
+ switch (type) {
+ case DEVICE_TYPE_BREDR:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR;
+ case DEVICE_TYPE_LE:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_LE;
+ case DEVICE_TYPE_DUMO:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_DUMO;
+ case DEVICE_TYPE_UNKNOWN:
+ default:
+ return DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_UNKNOWN;
+ }
+}
+
+static BluetoothSession_ConnectionTechnologyType get_connection_tech_type(
+ connection_tech_t type) {
+ switch (type) {
+ case CONNECTION_TECHNOLOGY_TYPE_LE:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE;
+ case CONNECTION_TECHNOLOGY_TYPE_BREDR:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR;
+ case CONNECTION_TECHNOLOGY_TYPE_UNKNOWN:
+ default:
+ return BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN;
+ }
+}
+
+static ScanEvent_ScanTechnologyType get_scan_tech_type(scan_tech_t type) {
+ switch (type) {
+ case SCAN_TECH_TYPE_LE:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_LE;
+ case SCAN_TECH_TYPE_BREDR:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR;
+ case SCAN_TECH_TYPE_BOTH:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BOTH;
+ case SCAN_TYPE_UNKNOWN:
+ default:
+ return ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TYPE_UNKNOWN;
+ }
+}
+
+static WakeEvent_WakeEventType get_wake_event_type(wake_event_type_t type) {
+ switch (type) {
+ case WAKE_EVENT_ACQUIRED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED;
+ case WAKE_EVENT_RELEASED:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED;
+ case WAKE_EVENT_UNKNOWN:
+ default:
+ return WakeEvent_WakeEventType::WakeEvent_WakeEventType_UNKNOWN;
+ }
+}
+
+static BluetoothSession_DisconnectReasonType get_disconnect_reason_type(
+ disconnect_reason_t type) {
+ switch (type) {
+ case DISCONNECT_REASON_METRICS_DUMP:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP;
+ case DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS;
+ case DISCONNECT_REASON_UNKNOWN:
+ default:
+ return BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN;
+ }
+}
+
+struct BluetoothMetricsLogger::impl {
+ impl(size_t max_bluetooth_session, size_t max_pair_event,
+ size_t max_wake_event, size_t max_scan_event)
+ : bt_session_queue_(
+ new LeakyBondedQueue<BluetoothSession>(max_bluetooth_session)),
+ pair_event_queue_(new LeakyBondedQueue<PairEvent>(max_pair_event)),
+ wake_event_queue_(new LeakyBondedQueue<WakeEvent>(max_wake_event)),
+ scan_event_queue_(new LeakyBondedQueue<ScanEvent>(max_scan_event)) {
+ bluetooth_log_ = BluetoothLog::default_instance().New();
+ bluetooth_session_ = nullptr;
+ bluetooth_session_start_time_ms_ = 0;
+ a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+
+ /* Bluetooth log lock protected */
+ BluetoothLog* bluetooth_log_;
+ std::recursive_mutex bluetooth_log_lock_;
+ /* End Bluetooth log lock protected */
+ /* Bluetooth session lock protected */
+ BluetoothSession* bluetooth_session_;
+ uint64_t bluetooth_session_start_time_ms_;
+ A2dpSessionMetrics a2dp_session_metrics_;
+ std::recursive_mutex bluetooth_session_lock_;
+ /* End bluetooth session lock protected */
+ std::unique_ptr<LeakyBondedQueue<BluetoothSession>> bt_session_queue_;
+ std::unique_ptr<LeakyBondedQueue<PairEvent>> pair_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<WakeEvent>> wake_event_queue_;
+ std::unique_ptr<LeakyBondedQueue<ScanEvent>> scan_event_queue_;
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger()
+ : pimpl_(new impl(kMaxNumBluetoothSession, kMaxNumPairEvent,
+ kMaxNumWakeEvent, kMaxNumScanEvent)) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {
+ PairEvent* event = new PairEvent();
+ DeviceInfo* info = event->mutable_device_paired_with();
+ info->set_device_class(device_class);
+ info->set_device_type(get_device_type(device_type));
+ event->set_disconnect_reason(disconnect_reason);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->pair_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_pair_event(
+ pimpl_->bluetooth_log_->num_pair_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(get_wake_event_type(type));
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->wake_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_wake_event(
+ pimpl_->bluetooth_log_->num_wake_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ if (start) {
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_START);
+ } else {
+ event->set_scan_event_type(ScanEvent::SCAN_EVENT_STOP);
+ }
+ event->set_initiator(initator);
+ event->set_scan_technology_type(get_scan_tech_type(type));
+ event->set_number_results(results);
+ event->set_event_time_millis(timestamp_ms);
+ pimpl_->scan_event_queue_->Enqueue(event);
+ {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_scan_event(
+ pimpl_->bluetooth_log_->num_scan_event() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ LogBluetoothSessionEnd(DISCONNECT_REASON_NEXT_START_WITHOUT_END_PREVIOUS,
+ 0);
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = time_get_os_boottime_ms();
+ }
+ pimpl_->bluetooth_session_start_time_ms_ = timestamp_ms;
+ pimpl_->bluetooth_session_ = new BluetoothSession();
+ pimpl_->bluetooth_session_->set_connection_technology_type(
+ get_connection_tech_type(connection_tech_type));
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ return;
+ }
+ if (timestamp_ms == 0) {
+ timestamp_ms = time_get_os_boottime_ms();
+ }
+ int64_t session_duration_sec =
+ (timestamp_ms - pimpl_->bluetooth_session_start_time_ms_) / 1000;
+ pimpl_->bluetooth_session_->set_session_duration_sec(session_duration_sec);
+ pimpl_->bluetooth_session_->set_disconnect_reason_type(
+ get_disconnect_reason_type(disconnect_reason));
+ pimpl_->bt_session_queue_->Enqueue(pimpl_->bluetooth_session_);
+ pimpl_->bluetooth_session_ = nullptr;
+ {
+ std::lock_guard<std::recursive_mutex> log_lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->set_num_bluetooth_session(
+ pimpl_->bluetooth_log_->num_bluetooth_session() + 1);
+ }
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ }
+ DeviceInfo* info = pimpl_->bluetooth_session_->mutable_device_connected_to();
+ info->set_device_class(device_class);
+ info->set_device_type(DeviceInfo::DEVICE_TYPE_BREDR);
+}
+
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ == nullptr) {
+ // When no bluetooth session exist, create one on system's behalf
+ // Set connection type: for A2DP it is always BR/EDR
+ LogBluetoothSessionStart(CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ LogBluetoothSessionDeviceInfo(BTM_COD_MAJOR_AUDIO, DEVICE_TYPE_BREDR);
+ }
+ // Accumulate metrics
+ pimpl_->a2dp_session_metrics_.Update(a2dp_session_metrics);
+ // Get or allocate new A2DP session object
+ A2DPSession* a2dp_session =
+ pimpl_->bluetooth_session_->mutable_a2dp_session();
+ a2dp_session->set_audio_duration_millis(
+ pimpl_->a2dp_session_metrics_.audio_duration_ms);
+ a2dp_session->set_media_timer_min_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_min_ms);
+ a2dp_session->set_media_timer_max_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_max_ms);
+ a2dp_session->set_media_timer_avg_millis(
+ pimpl_->a2dp_session_metrics_.media_timer_avg_ms);
+ a2dp_session->set_buffer_overruns_max_count(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_max_count);
+ a2dp_session->set_buffer_overruns_total(
+ pimpl_->a2dp_session_metrics_.buffer_overruns_total);
+ a2dp_session->set_buffer_underruns_average(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_average);
+ a2dp_session->set_buffer_underruns_count(
+ pimpl_->a2dp_session_metrics_.buffer_underruns_count);
+}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ LOG_DEBUG(LOG_TAG, "%s building metrics", __func__);
+ Build();
+ LOG_DEBUG(LOG_TAG, "%s serializing metrics", __func__);
+ if (!pimpl_->bluetooth_log_->SerializeToString(serialized)) {
+ LOG_ERROR(LOG_TAG, "%s: error serializing metrics", __func__);
+ return;
+ }
+ if (clear) {
+ pimpl_->bluetooth_log_->Clear();
+ }
+}
+
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
+ bool clear) {
+ this->WriteString(serialized, clear);
+ base::Base64Encode(*serialized, serialized);
+}
+
+void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
+ std::string protoBase64;
+ this->WriteBase64String(&protoBase64, clear);
+ ssize_t ret;
+ OSI_NO_INTR(ret = write(fd, protoBase64.c_str(), protoBase64.size()));
+ if (ret == -1) {
+ LOG_ERROR(LOG_TAG, "%s: error writing to dumpsys fd: %s (%d)", __func__,
+ strerror(errno), errno);
+ }
+}
+
+void BluetoothMetricsLogger::CutoffSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ BluetoothSession* new_bt_session =
+ new BluetoothSession(*pimpl_->bluetooth_session_);
+ new_bt_session->clear_a2dp_session();
+ new_bt_session->clear_rfcomm_session();
+ LogBluetoothSessionEnd(DISCONNECT_REASON_METRICS_DUMP, 0);
+ pimpl_->bluetooth_session_ = new_bt_session;
+ pimpl_->bluetooth_session_start_time_ms_ = time_get_os_boottime_ms();
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+ }
+}
+
+void BluetoothMetricsLogger::Build() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ CutoffSession();
+ BluetoothLog* bluetooth_log = pimpl_->bluetooth_log_;
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->session_size()) <=
+ pimpl_->bt_session_queue_->Capacity()) {
+ bluetooth_log->mutable_session()->AddAllocated(
+ pimpl_->bt_session_queue_->Dequeue());
+ }
+ while (!pimpl_->pair_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->pair_event_size()) <=
+ pimpl_->pair_event_queue_->Capacity()) {
+ bluetooth_log->mutable_pair_event()->AddAllocated(
+ pimpl_->pair_event_queue_->Dequeue());
+ }
+ while (!pimpl_->scan_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->scan_event_size()) <=
+ pimpl_->scan_event_queue_->Capacity()) {
+ bluetooth_log->mutable_scan_event()->AddAllocated(
+ pimpl_->scan_event_queue_->Dequeue());
+ }
+ while (!pimpl_->wake_event_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
+ }
+ while (!pimpl_->bt_session_queue_->Empty() &&
+ static_cast<size_t>(bluetooth_log->wake_event_size()) <=
+ pimpl_->wake_event_queue_->Capacity()) {
+ bluetooth_log->mutable_wake_event()->AddAllocated(
+ pimpl_->wake_event_queue_->Dequeue());
+ }
+}
+
+void BluetoothMetricsLogger::ResetSession() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_session_lock_);
+ if (pimpl_->bluetooth_session_ != nullptr) {
+ delete pimpl_->bluetooth_session_;
+ pimpl_->bluetooth_session_ = nullptr;
+ }
+ pimpl_->bluetooth_session_start_time_ms_ = 0;
+ pimpl_->a2dp_session_metrics_ = A2dpSessionMetrics();
+}
+
+void BluetoothMetricsLogger::ResetLog() {
+ std::lock_guard<std::recursive_mutex> lock(pimpl_->bluetooth_log_lock_);
+ pimpl_->bluetooth_log_->Clear();
+}
+
+void BluetoothMetricsLogger::Reset() {
+ ResetSession();
+ ResetLog();
+ pimpl_->bt_session_queue_->Clear();
+ pimpl_->pair_event_queue_->Clear();
+ pimpl_->wake_event_queue_->Clear();
+ pimpl_->scan_event_queue_->Clear();
+}
+
+} // namespace system_bt_osi
diff --git a/mtkbt/code/bt/osi/src/metrics_linux.cc b/mtkbt/code/bt/osi/src/metrics_linux.cc
new file mode 100755
index 0000000..3169131
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/metrics_linux.cc
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#define LOG_TAG "bt_osi_metrics"
+
+#include <unistd.h>
+#include <algorithm>
+#include <cerrno>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <mutex>
+
+#include <base/base64.h>
+#include <base/logging.h>
+
+#include "osi/include/leaky_bonded_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "osi/include/metrics.h"
+
+namespace system_bt_osi {
+
+// Maximum number of log entries for each repeated field
+#define MAX_NUM_BLUETOOTH_SESSION 50
+#define MAX_NUM_PAIR_EVENT 50
+#define MAX_NUM_WAKE_EVENT 50
+#define MAX_NUM_SCAN_EVENT 50
+
+static float combine_averages(float avg_a, int64_t ct_a, float avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+static int32_t combine_averages(int32_t avg_a, int64_t ct_a, int32_t avg_b,
+ int64_t ct_b) {
+ if (ct_a > 0 && ct_b > 0) {
+ return (avg_a * ct_a + avg_b * ct_b) / (ct_a + ct_b);
+ } else if (ct_b > 0) {
+ return avg_b;
+ } else {
+ return avg_a;
+ }
+}
+
+void A2dpSessionMetrics::Update(const A2dpSessionMetrics& metrics) {
+ if (metrics.audio_duration_ms > 0) {
+ audio_duration_ms = std::max(static_cast<int64_t>(0), audio_duration_ms);
+ audio_duration_ms += metrics.audio_duration_ms;
+ }
+ if (metrics.media_timer_min_ms > 0) {
+ if (media_timer_min_ms < 0) {
+ media_timer_min_ms = metrics.media_timer_min_ms;
+ } else {
+ media_timer_min_ms =
+ std::min(media_timer_min_ms, metrics.media_timer_min_ms);
+ }
+ }
+ if (metrics.media_timer_max_ms > 0) {
+ media_timer_max_ms =
+ std::max(media_timer_max_ms, metrics.media_timer_max_ms);
+ }
+ if (metrics.media_timer_avg_ms > 0 && metrics.total_scheduling_count > 0) {
+ if (media_timer_avg_ms < 0 || total_scheduling_count < 0) {
+ media_timer_avg_ms = metrics.media_timer_avg_ms;
+ total_scheduling_count = metrics.total_scheduling_count;
+ } else {
+ media_timer_avg_ms = combine_averages(
+ media_timer_avg_ms, total_scheduling_count,
+ metrics.media_timer_avg_ms, metrics.total_scheduling_count);
+ total_scheduling_count += metrics.total_scheduling_count;
+ }
+ }
+ if (metrics.buffer_overruns_max_count > 0) {
+ buffer_overruns_max_count =
+ std::max(buffer_overruns_max_count, metrics.buffer_overruns_max_count);
+ }
+ if (metrics.buffer_overruns_total > 0) {
+ buffer_overruns_total =
+ std::max(static_cast<int32_t>(0), buffer_overruns_total);
+ buffer_overruns_total += metrics.buffer_overruns_total;
+ }
+ if (metrics.buffer_underruns_average > 0 &&
+ metrics.buffer_underruns_count > 0) {
+ if (buffer_underruns_average < 0 || buffer_underruns_count < 0) {
+ buffer_underruns_average = metrics.buffer_underruns_average;
+ buffer_underruns_count = metrics.buffer_underruns_count;
+ } else {
+ buffer_underruns_average = combine_averages(
+ metrics.buffer_underruns_average, metrics.buffer_underruns_count,
+ buffer_underruns_average, buffer_underruns_count);
+ buffer_underruns_count += metrics.buffer_underruns_count;
+ }
+ }
+}
+
+bool A2dpSessionMetrics::operator==(const A2dpSessionMetrics& rhs) const {
+ return audio_duration_ms == rhs.audio_duration_ms &&
+ media_timer_min_ms == rhs.media_timer_min_ms &&
+ media_timer_max_ms == rhs.media_timer_max_ms &&
+ media_timer_avg_ms == rhs.media_timer_avg_ms &&
+ total_scheduling_count == rhs.total_scheduling_count &&
+ buffer_overruns_max_count == rhs.buffer_overruns_max_count &&
+ buffer_overruns_total == rhs.buffer_overruns_total &&
+ buffer_underruns_average == rhs.buffer_underruns_average &&
+ buffer_underruns_count == rhs.buffer_underruns_count;
+}
+
+struct BluetoothMetricsLogger::impl {
+ // TODO(siyuanh): Implement for linux
+};
+
+BluetoothMetricsLogger::BluetoothMetricsLogger() : pimpl_(new impl) {}
+
+void BluetoothMetricsLogger::LogPairEvent(uint32_t disconnect_reason,
+ uint64_t timestamp_ms,
+ uint32_t device_class,
+ device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogWakeEvent(wake_event_type_t type,
+ const std::string& requestor,
+ const std::string& name,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogScanEvent(bool start,
+ const std::string& initator,
+ scan_tech_t type, uint32_t results,
+ uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionStart(
+ connection_tech_t connection_tech_type, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionEnd(
+ disconnect_reason_t disconnect_reason, uint64_t timestamp_ms) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogBluetoothSessionDeviceInfo(
+ uint32_t device_class, device_type_t device_type) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::LogA2dpSession(
+ const A2dpSessionMetrics& a2dp_session_metrics) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteString(std::string* serialized, bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteBase64String(std::string* serialized,
+ bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::WriteBase64(int fd, bool clear) {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::CutoffSession() {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::Build() {
+ // TODO(siyuanh): Implement for linux
+}
+
+void BluetoothMetricsLogger::Reset() {
+ // TODO(siyuanh): Implement for linux
+}
+
+} // namespace system_bt_osi
diff --git a/mtkbt/code/bt/osi/src/mutex.cc b/mtkbt/code/bt/osi/src/mutex.cc
new file mode 100755
index 0000000..fbbef40
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/mutex.cc
@@ -0,0 +1,29 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_mutex"
+
+#include <mutex>
+
+#include "osi/include/mutex.h"
+
+static std::recursive_mutex global_mutex;
+
+void mutex_global_lock(void) { global_mutex.lock(); }
+
+void mutex_global_unlock(void) { global_mutex.unlock(); }
diff --git a/mtkbt/code/bt/osi/src/osi.cc b/mtkbt/code/bt/osi/src/osi.cc
new file mode 100755
index 0000000..0109a95
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/osi.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_rand"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define RANDOM_PATH "/dev/urandom"
+
+int osi_rand(void) {
+ int rand;
+ int rand_fd = open(RANDOM_PATH, O_RDONLY);
+
+ if (rand_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s can't open rand fd %s: %s ", __func__, RANDOM_PATH,
+ strerror(errno));
+ CHECK(rand_fd != INVALID_FD);
+ }
+
+ ssize_t read_bytes = read(rand_fd, &rand, sizeof(rand));
+ close(rand_fd);
+
+ CHECK(read_bytes == sizeof(rand));
+
+ if (rand < 0) rand = -rand;
+
+ return rand;
+}
diff --git a/mtkbt/code/bt/osi/src/properties.cc b/mtkbt/code/bt/osi/src/properties.cc
new file mode 100755
index 0000000..7392953
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/properties.cc
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "osi/include/properties.h"
+
+int osi_property_get(const char* key, char* value, const char* default_value) {
+#if defined(OS_GENERIC)
+ /* For linux right now just return default value, if present */
+ int len = 0;
+ if (!default_value) return len;
+
+ len = strlen(default_value);
+ if (len >= PROPERTY_VALUE_MAX) len = PROPERTY_VALUE_MAX - 1;
+
+ memcpy(value, default_value, len);
+ value[len] = '\0';
+ return len;
+#else
+ return property_get(key, value, default_value);
+#endif // defined(OS_GENERIC)
+}
+
+int osi_property_set(const char* key, const char* value) {
+#if defined(OS_GENERIC)
+ return -1;
+#else
+ return property_set(key, value);
+#endif // defined(OS_GENERIC)
+}
+
+int32_t osi_property_get_int32(const char* key, int32_t default_value) {
+#if defined(OS_GENERIC)
+ return default_value;
+#else
+ return property_get_int32(key, default_value);
+#endif // defined(OS_GENERIC)
+}
diff --git a/mtkbt/code/bt/osi/src/protos/bluetooth.proto b/mtkbt/code/bt/osi/src/protos/bluetooth.proto
new file mode 100755
index 0000000..f6f1d0b
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/protos/bluetooth.proto
@@ -0,0 +1,224 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+// Author: pkanwar@google.com (Pankaj Kanwar)
+// Protos for uploading bluetooth metrics.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package clearcut.connectivity;
+
+option java_package = "com.google.wireless.android.play.playlog.connectivity";
+// option (datapol.file_vetting_status) = "latest";
+
+// import "storage/datapol/annotations/proto/semantic_annotations.proto";
+
+message BluetoothLog {
+ // Session information that gets logged for every BT connection.
+ repeated BluetoothSession session = 1;
+
+ // Session information that gets logged for every Pair event.
+ repeated PairEvent pair_event = 2;
+
+ // Information for Wake locks.
+ repeated WakeEvent wake_event = 3;
+
+ // Scan event information.
+ repeated ScanEvent scan_event = 4;
+
+ // Number of bonded devices.
+ optional int32 num_bonded_devices = 5;
+
+ // Number of BluetoothSession including discarded ones beyond capacity
+ optional int64 num_bluetooth_session = 6;
+
+ // Number of PairEvent including discarded ones beyond capacity
+ optional int64 num_pair_event = 7;
+
+ // Number of WakeEvent including discarded ones beyond capacity
+ optional int64 num_wake_event = 8;
+
+ // Number of ScanEvent including discarded ones beyond capacity
+ optional int64 num_scan_event = 9;
+}
+
+// The information about the device.
+message DeviceInfo {
+ // Device type.
+ enum DeviceType {
+ // Type is unknown.
+ DEVICE_TYPE_UNKNOWN = 0;
+
+ DEVICE_TYPE_BREDR = 1;
+
+ DEVICE_TYPE_LE = 2;
+
+ DEVICE_TYPE_DUMO = 3;
+ }
+
+ // Device class
+ // https://cs.corp.google.com/#android/system/bt/stack/include/btm_api.h&q=major_computer.
+ optional int32 device_class = 1;
+
+ // Device type.
+ optional DeviceType device_type = 2;
+}
+
+// Information that gets logged for every Bluetooth connection.
+message BluetoothSession {
+ // Type of technology used in the connection.
+ enum ConnectionTechnologyType {
+ CONNECTION_TECHNOLOGY_TYPE_UNKNOWN = 0;
+
+ CONNECTION_TECHNOLOGY_TYPE_LE = 1;
+
+ CONNECTION_TECHNOLOGY_TYPE_BREDR = 2;
+ }
+
+ enum DisconnectReasonType {
+ UNKNOWN = 0;
+
+ // A metrics dump takes a snapshot of current Bluetooth session and thus
+ // is not a real disconnect, but a discontinuation in metrics logging.
+ // This enum indicates this situation.
+ METRICS_DUMP = 1;
+
+ NEXT_START_WITHOUT_END_PREVIOUS = 2;
+ }
+
+ // Duration of the session.
+ optional int64 session_duration_sec = 2;
+
+ // Technology type.
+ optional ConnectionTechnologyType connection_technology_type = 3;
+
+ // Reason for disconnecting.
+ optional string disconnect_reason = 4 [deprecated = true];
+
+ // The information about the device which it is connected to.
+ optional DeviceInfo device_connected_to = 5;
+
+ // The information about the RFComm session.
+ optional RFCommSession rfcomm_session = 6;
+
+ // The information about the A2DP audio session.
+ optional A2DPSession a2dp_session = 7;
+
+ // Numeric reason for disconnecting as defined in metrics.h
+ optional DisconnectReasonType disconnect_reason_type = 8;
+}
+
+message RFCommSession {
+ // bytes transmitted.
+ optional int32 rx_bytes = 1;
+
+ // bytes transmitted.
+ optional int32 tx_bytes = 2;
+}
+
+// Session information that gets logged for A2DP session.
+message A2DPSession {
+ // Media timer in milliseconds.
+ optional int32 media_timer_min_millis = 1;
+
+ // Media timer in milliseconds.
+ optional int32 media_timer_max_millis = 2;
+
+ // Media timer in milliseconds.
+ optional int32 media_timer_avg_millis = 3;
+
+ // Buffer overruns count.
+ optional int32 buffer_overruns_max_count = 4;
+
+ // Buffer overruns total.
+ optional int32 buffer_overruns_total = 5;
+
+ // Buffer underruns average.
+ optional float buffer_underruns_average = 6;
+
+ // Buffer underruns count.
+ optional int32 buffer_underruns_count = 7;
+
+ // Total audio time in this A2DP session
+ optional int64 audio_duration_millis = 8;
+}
+
+message PairEvent {
+ // The reason for disconnecting
+ // https://cs.corp.google.com/#android/system/bt/stack/include/hcidefs.h&q=failed_establish.
+ optional int32 disconnect_reason = 1;
+
+ // Pair event time
+ optional int64 event_time_millis =
+ 2; // [(datapol.semantic_type) = ST_TIMESTAMP];
+
+ // The information about the device which it is paired to.
+ optional DeviceInfo device_paired_with = 3;
+}
+
+message WakeEvent {
+ // Information about the wake event type.
+ enum WakeEventType {
+ // Type is unknown.
+ UNKNOWN = 0;
+
+ // WakeLock was acquired.
+ ACQUIRED = 1;
+
+ // WakeLock was released.
+ RELEASED = 2;
+ }
+
+ // Information about the wake event type.
+ optional WakeEventType wake_event_type = 1;
+
+ // Initiator of the scan. Only the first three names will be stored.
+ // e.g. com.google.gms.
+ optional string requestor = 2;
+
+ // Name of the wakelock (e.g. bluedroid_timer).
+ optional string name = 3;
+
+ // Time of the event.
+ optional int64 event_time_millis =
+ 4; // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
+
+message ScanEvent {
+ // Scan type.
+ enum ScanTechnologyType {
+ // Scan Type is unknown.
+ SCAN_TYPE_UNKNOWN = 0;
+
+ SCAN_TECH_TYPE_LE = 1;
+
+ SCAN_TECH_TYPE_BREDR = 2;
+
+ SCAN_TECH_TYPE_BOTH = 3;
+ }
+
+ // Scan event type.
+ enum ScanEventType {
+ // Scan started.
+ SCAN_EVENT_START = 0;
+
+ // Scan stopped.
+ SCAN_EVENT_STOP = 1;
+ }
+
+ // Scan event type.
+ optional ScanEventType scan_event_type = 1;
+
+ // Initiator of the scan. Only the first three names will be stored.
+ // e.g. com.google.gms.
+ optional string initiator = 2;
+
+ // Technology used for scanning.
+ optional ScanTechnologyType scan_technology_type = 3;
+
+ // Number of results returned.
+ optional int32 number_results = 4;
+
+ // Time of the event.
+ optional int64 event_time_millis =
+ 5; // [(datapol.semantic_type) = ST_TIMESTAMP];
+}
diff --git a/mtkbt/code/bt/osi/src/reactor.cc b/mtkbt/code/bt/osi/src/reactor.cc
new file mode 100755
index 0000000..7f88df9
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/reactor.cc
@@ -0,0 +1,297 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_reactor"
+
+#include "osi/include/reactor.h"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include <mutex>
+
+#include "osi/include/allocator.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+
+#if !defined(EFD_SEMAPHORE)
+#define EFD_SEMAPHORE (1 << 0)
+#endif
+
+struct reactor_t {
+ int epoll_fd;
+ int event_fd;
+ std::mutex* list_mutex;
+ list_t* invalidation_list; // reactor objects that have been unregistered.
+ pthread_t run_thread; // the pthread on which reactor_run is executing.
+ bool is_running; // indicates whether |run_thread| is valid.
+ bool object_removed;
+};
+
+struct reactor_object_t {
+ int fd; // the file descriptor to monitor for events.
+ void* context; // a context that's passed back to the *_ready functions.
+ reactor_t* reactor; // the reactor instance this object is registered with.
+ std::mutex* mutex; // protects the lifetime of this object and all variables.
+
+ void (*read_ready)(void* context); // function to call when the file
+ // descriptor becomes readable.
+ void (*write_ready)(void* context); // function to call when the file
+ // descriptor becomes writeable.
+};
+
+static reactor_status_t run_reactor(reactor_t* reactor, int iterations);
+
+static const size_t MAX_EVENTS = 64;
+static const eventfd_t EVENT_REACTOR_STOP = 1;
+
+reactor_t* reactor_new(void) {
+ reactor_t* ret = (reactor_t*)osi_calloc(sizeof(reactor_t));
+
+ ret->epoll_fd = INVALID_FD;
+ ret->event_fd = INVALID_FD;
+
+ ret->epoll_fd = epoll_create(MAX_EVENTS);
+ if (ret->epoll_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to create epoll instance: %s", __func__,
+ strerror(errno));
+ goto error;
+ }
+
+ ret->event_fd = eventfd(0, 0);
+ if (ret->event_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to create eventfd: %s", __func__,
+ strerror(errno));
+ goto error;
+ }
+
+ ret->list_mutex = new std::mutex;
+ ret->invalidation_list = list_new(NULL);
+ if (!ret->invalidation_list) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate object invalidation list.",
+ __func__);
+ goto error;
+ }
+
+ struct epoll_event event;
+ memset(&event, 0, sizeof(event));
+ event.events = EPOLLIN;
+ event.data.ptr = NULL;
+ if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to register eventfd with epoll set: %s",
+ __func__, strerror(errno));
+ goto error;
+ }
+
+ return ret;
+
+error:;
+ reactor_free(ret);
+ return NULL;
+}
+
+void reactor_free(reactor_t* reactor) {
+ if (!reactor) return;
+
+ list_free(reactor->invalidation_list);
+ close(reactor->event_fd);
+ close(reactor->epoll_fd);
+ osi_free(reactor);
+}
+
+reactor_status_t reactor_start(reactor_t* reactor) {
+ CHECK(reactor != NULL);
+ return run_reactor(reactor, 0);
+}
+
+reactor_status_t reactor_run_once(reactor_t* reactor) {
+ CHECK(reactor != NULL);
+ return run_reactor(reactor, 1);
+}
+
+void reactor_stop(reactor_t* reactor) {
+ CHECK(reactor != NULL);
+
+ eventfd_write(reactor->event_fd, EVENT_REACTOR_STOP);
+}
+
+reactor_object_t* reactor_register(reactor_t* reactor, int fd, void* context,
+ void (*read_ready)(void* context),
+ void (*write_ready)(void* context)) {
+ CHECK(reactor != NULL);
+ CHECK(fd != INVALID_FD);
+
+ reactor_object_t* object =
+ (reactor_object_t*)osi_calloc(sizeof(reactor_object_t));
+
+ object->reactor = reactor;
+ object->fd = fd;
+ object->context = context;
+ object->read_ready = read_ready;
+ object->write_ready = write_ready;
+ object->mutex = new std::mutex;
+
+ struct epoll_event event;
+ memset(&event, 0, sizeof(event));
+ if (read_ready) event.events |= (EPOLLIN | EPOLLRDHUP);
+ if (write_ready) event.events |= EPOLLOUT;
+ event.data.ptr = object;
+
+ if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to register fd %d to epoll set: %s", __func__,
+ fd, strerror(errno));
+ delete object->mutex;
+ osi_free(object);
+ return NULL;
+ }
+
+ return object;
+}
+
+bool reactor_change_registration(reactor_object_t* object,
+ void (*read_ready)(void* context),
+ void (*write_ready)(void* context)) {
+ CHECK(object != NULL);
+
+ struct epoll_event event;
+ memset(&event, 0, sizeof(event));
+ if (read_ready) event.events |= (EPOLLIN | EPOLLRDHUP);
+ if (write_ready) event.events |= EPOLLOUT;
+ event.data.ptr = object;
+
+ if (epoll_ctl(object->reactor->epoll_fd, EPOLL_CTL_MOD, object->fd, &event) ==
+ -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to modify interest set for fd %d: %s",
+ __func__, object->fd, strerror(errno));
+ return false;
+ }
+
+ std::lock_guard<std::mutex> lock(*object->mutex);
+ object->read_ready = read_ready;
+ object->write_ready = write_ready;
+
+ return true;
+}
+
+void reactor_unregister(reactor_object_t* obj) {
+ CHECK(obj != NULL);
+
+ reactor_t* reactor = obj->reactor;
+
+ if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to unregister fd %d from epoll set: %s",
+ __func__, obj->fd, strerror(errno));
+
+ if (reactor->is_running &&
+ pthread_equal(pthread_self(), reactor->run_thread)) {
+ reactor->object_removed = true;
+ return;
+ }
+
+ {
+ std::unique_lock<std::mutex> lock(*reactor->list_mutex);
+ list_append(reactor->invalidation_list, obj);
+ }
+
+ // Taking the object lock here makes sure a callback for |obj| isn't
+ // currently executing. The reactor thread must then either be before
+ // the callbacks or after. If after, we know that the object won't be
+ // referenced because it has been taken out of the epoll set. If before,
+ // it won't be referenced because the reactor thread will check the
+ // invalidation_list and find it in there. So by taking this lock, we
+ // are waiting until the reactor thread drops all references to |obj|.
+ // One the wait completes, we can unlock and destroy |obj| safely.
+ obj->mutex->lock();
+ obj->mutex->unlock();
+ delete obj->mutex;
+ osi_free(obj);
+}
+
+// Runs the reactor loop for a maximum of |iterations|.
+// 0 |iterations| means loop forever.
+// |reactor| may not be NULL.
+static reactor_status_t run_reactor(reactor_t* reactor, int iterations) {
+ CHECK(reactor != NULL);
+
+ reactor->run_thread = pthread_self();
+ reactor->is_running = true;
+
+ struct epoll_event events[MAX_EVENTS];
+ for (int i = 0; iterations == 0 || i < iterations; ++i) {
+ {
+ std::lock_guard<std::mutex> lock(*reactor->list_mutex);
+ list_clear(reactor->invalidation_list);
+ }
+
+ int ret;
+ OSI_NO_INTR(ret = epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1));
+ if (ret == -1) {
+ LOG_ERROR(LOG_TAG, "%s error in epoll_wait: %s", __func__,
+ strerror(errno));
+ reactor->is_running = false;
+ return REACTOR_STATUS_ERROR;
+ }
+
+ for (int j = 0; j < ret; ++j) {
+ // The event file descriptor is the only one that registers with
+ // a NULL data pointer. We use the NULL to identify it and break
+ // out of the reactor loop.
+ if (events[j].data.ptr == NULL) {
+ eventfd_t value;
+ eventfd_read(reactor->event_fd, &value);
+ reactor->is_running = false;
+ return REACTOR_STATUS_STOP;
+ }
+
+ reactor_object_t* object = (reactor_object_t*)events[j].data.ptr;
+
+ std::unique_lock<std::mutex> lock(*reactor->list_mutex);
+ if (list_contains(reactor->invalidation_list, object)) {
+ continue;
+ }
+
+ // Downgrade the list lock to an object lock.
+ {
+ std::lock_guard<std::mutex> obj_lock(*object->mutex);
+ lock.unlock();
+
+ reactor->object_removed = false;
+ if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) &&
+ object->read_ready)
+ object->read_ready(object->context);
+ if (!reactor->object_removed && events[j].events & EPOLLOUT &&
+ object->write_ready)
+ object->write_ready(object->context);
+ }
+
+ if (reactor->object_removed) {
+ delete object->mutex;
+ osi_free(object);
+ }
+ }
+ }
+
+ reactor->is_running = false;
+ return REACTOR_STATUS_DONE;
+}
diff --git a/mtkbt/code/bt/osi/src/ringbuffer.cc b/mtkbt/code/bt/osi/src/ringbuffer.cc
new file mode 100755
index 0000000..5c7874d
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/ringbuffer.cc
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <stdlib.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/ringbuffer.h"
+
+struct ringbuffer_t {
+ size_t total;
+ size_t available;
+ uint8_t* base;
+ uint8_t* head;
+ uint8_t* tail;
+};
+
+ringbuffer_t* ringbuffer_init(const size_t size) {
+ ringbuffer_t* p =
+ static_cast<ringbuffer_t*>(osi_calloc(sizeof(ringbuffer_t)));
+
+ p->base = static_cast<uint8_t*>(osi_calloc(size));
+ p->head = p->tail = p->base;
+ p->total = p->available = size;
+
+ return p;
+}
+
+void ringbuffer_free(ringbuffer_t* rb) {
+ if (rb != NULL) osi_free(rb->base);
+ osi_free(rb);
+}
+
+size_t ringbuffer_available(const ringbuffer_t* rb) {
+ CHECK(rb);
+ return rb->available;
+}
+
+size_t ringbuffer_size(const ringbuffer_t* rb) {
+ CHECK(rb);
+ return rb->total - rb->available;
+}
+
+size_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length) {
+ CHECK(rb);
+ CHECK(p);
+
+ if (length > ringbuffer_available(rb)) length = ringbuffer_available(rb);
+
+ for (size_t i = 0; i != length; ++i) {
+ *rb->tail++ = *p++;
+ if (rb->tail >= (rb->base + rb->total)) rb->tail = rb->base;
+ }
+
+ rb->available -= length;
+ return length;
+}
+
+size_t ringbuffer_delete(ringbuffer_t* rb, size_t length) {
+ CHECK(rb);
+
+ if (length > ringbuffer_size(rb)) length = ringbuffer_size(rb);
+
+ rb->head += length;
+ if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
+
+ rb->available += length;
+ return length;
+}
+
+size_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p,
+ size_t length) {
+ CHECK(rb);
+ CHECK(p);
+ CHECK(offset >= 0);
+ CHECK((size_t)offset <= ringbuffer_size(rb));
+
+ uint8_t* b = ((rb->head - rb->base + offset) % rb->total) + rb->base;
+ const size_t bytes_to_copy = (offset + length > ringbuffer_size(rb))
+ ? ringbuffer_size(rb) - offset
+ : length;
+
+ for (size_t copied = 0; copied < bytes_to_copy; ++copied) {
+ *p++ = *b++;
+ if (b >= (rb->base + rb->total)) b = rb->base;
+ }
+
+ return bytes_to_copy;
+}
+
+size_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length) {
+ CHECK(rb);
+ CHECK(p);
+
+ const size_t copied = ringbuffer_peek(rb, 0, p, length);
+ rb->head += copied;
+ if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
+
+ rb->available += copied;
+ return copied;
+}
diff --git a/mtkbt/code/bt/osi/src/semaphore.cc b/mtkbt/code/bt/osi/src/semaphore.cc
new file mode 100755
index 0000000..097f32e
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/semaphore.cc
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_semaphore"
+
+#include "osi/include/semaphore.h"
+
+#include <base/logging.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#if !defined(EFD_SEMAPHORE)
+#define EFD_SEMAPHORE (1 << 0)
+#endif
+
+struct semaphore_t {
+ int fd;
+};
+
+semaphore_t* semaphore_new(unsigned int value) {
+ semaphore_t* ret = static_cast<semaphore_t*>(osi_malloc(sizeof(semaphore_t)));
+ ret->fd = eventfd(value, EFD_SEMAPHORE);
+ if (ret->fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate semaphore: %s", __func__,
+ strerror(errno));
+ osi_free(ret);
+ ret = NULL;
+ }
+ return ret;
+}
+
+void semaphore_free(semaphore_t* semaphore) {
+ if (!semaphore) return;
+
+ if (semaphore->fd != INVALID_FD) close(semaphore->fd);
+ osi_free(semaphore);
+}
+
+void semaphore_wait(semaphore_t* semaphore) {
+ CHECK(semaphore != NULL);
+ CHECK(semaphore->fd != INVALID_FD);
+
+ eventfd_t value;
+ if (eventfd_read(semaphore->fd, &value) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to wait on semaphore: %s", __func__,
+ strerror(errno));
+}
+
+bool semaphore_try_wait(semaphore_t* semaphore) {
+ CHECK(semaphore != NULL);
+ CHECK(semaphore->fd != INVALID_FD);
+
+ int flags = fcntl(semaphore->fd, F_GETFL);
+ if (flags == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to get flags for semaphore fd: %s", __func__,
+ strerror(errno));
+ return false;
+ }
+ if (fcntl(semaphore->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to set O_NONBLOCK for semaphore fd: %s",
+ __func__, strerror(errno));
+ return false;
+ }
+
+ bool rc = true;
+ eventfd_t value;
+ if (eventfd_read(semaphore->fd, &value) == -1) rc = false;
+
+ if (fcntl(semaphore->fd, F_SETFL, flags) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to restore flags for semaphore fd: %s",
+ __func__, strerror(errno));
+ return rc;
+}
+
+void semaphore_post(semaphore_t* semaphore) {
+ CHECK(semaphore != NULL);
+ CHECK(semaphore->fd != INVALID_FD);
+
+ if (eventfd_write(semaphore->fd, 1ULL) == -1)
+ LOG_ERROR(LOG_TAG, "%s unable to post to semaphore: %s", __func__,
+ strerror(errno));
+}
+
+int semaphore_get_fd(const semaphore_t* semaphore) {
+ CHECK(semaphore != NULL);
+ CHECK(semaphore->fd != INVALID_FD);
+ return semaphore->fd;
+}
diff --git a/mtkbt/code/bt/osi/src/socket.cc b/mtkbt/code/bt/osi/src/socket.cc
new file mode 100755
index 0000000..201f976
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/socket.cc
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_socket"
+
+#include "osi/include/socket.h"
+
+#include <asm/ioctls.h>
+#include <base/logging.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+
+// The IPv4 loopback address: 127.0.0.1
+static const in_addr_t LOCALHOST_ = 0x7f000001;
+
+struct socket_t {
+ int fd;
+ reactor_object_t* reactor_object;
+ socket_cb read_ready;
+ socket_cb write_ready;
+ void* context; // Not owned, do not free.
+};
+
+static void internal_read_ready(void* context);
+static void internal_write_ready(void* context);
+
+socket_t* socket_new(void) {
+ socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+ int enable = 1;
+
+ ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (ret->fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to create socket: %s", __func__,
+ strerror(errno));
+ goto error;
+ }
+
+ if (setsockopt(ret->fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) ==
+ -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to set SO_REUSEADDR: %s", __func__,
+ strerror(errno));
+ goto error;
+ }
+
+ return ret;
+
+error:;
+ if (ret) close(ret->fd);
+ osi_free(ret);
+ return NULL;
+}
+
+socket_t* socket_new_from_fd(int fd) {
+ CHECK(fd != INVALID_FD);
+
+ socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+
+ ret->fd = fd;
+ return ret;
+}
+
+void socket_free(socket_t* socket) {
+ if (!socket) return;
+
+ socket_unregister(socket);
+ close(socket->fd);
+ osi_free(socket);
+}
+
+bool socket_listen(const socket_t* socket, port_t port) {
+ CHECK(socket != NULL);
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(LOCALHOST_);
+ addr.sin_port = htons(port);
+ if (bind(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to bind socket to port %u: %s", __func__,
+ port, strerror(errno));
+ return false;
+ }
+
+ if (listen(socket->fd, 10) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to listen on port %u: %s", __func__, port,
+ strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+socket_t* socket_accept(const socket_t* socket) {
+ CHECK(socket != NULL);
+
+ int fd;
+ OSI_NO_INTR(fd = accept(socket->fd, NULL, NULL));
+ if (fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s unable to accept socket: %s", __func__,
+ strerror(errno));
+ return NULL;
+ }
+
+ socket_t* ret = (socket_t*)osi_calloc(sizeof(socket_t));
+
+ ret->fd = fd;
+ return ret;
+}
+
+ssize_t socket_read(const socket_t* socket, void* buf, size_t count) {
+ CHECK(socket != NULL);
+ CHECK(buf != NULL);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = recv(socket->fd, buf, count, MSG_DONTWAIT));
+
+ return ret;
+}
+
+ssize_t socket_write(const socket_t* socket, const void* buf, size_t count) {
+ CHECK(socket != NULL);
+ CHECK(buf != NULL);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = send(socket->fd, buf, count, MSG_DONTWAIT));
+
+ return ret;
+}
+
+ssize_t socket_write_and_transfer_fd(const socket_t* socket, const void* buf,
+ size_t count, int fd) {
+ CHECK(socket != NULL);
+ CHECK(buf != NULL);
+
+ if (fd == INVALID_FD) return socket_write(socket, buf, count);
+
+ struct msghdr msg;
+ struct iovec iov;
+ char control_buf[CMSG_SPACE(sizeof(int))];
+
+ iov.iov_base = (void*)buf;
+ iov.iov_len = count;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control_buf;
+ msg.msg_controllen = sizeof(control_buf);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ struct cmsghdr* header = CMSG_FIRSTHDR(&msg);
+ header->cmsg_level = SOL_SOCKET;
+ header->cmsg_type = SCM_RIGHTS;
+ header->cmsg_len = CMSG_LEN(sizeof(int));
+ *(int*)CMSG_DATA(header) = fd;
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = sendmsg(socket->fd, &msg, MSG_DONTWAIT));
+
+ close(fd);
+ return ret;
+}
+
+ssize_t socket_bytes_available(const socket_t* socket) {
+ CHECK(socket != NULL);
+
+ int size = 0;
+ if (ioctl(socket->fd, FIONREAD, &size) == -1) return -1;
+ return size;
+}
+
+void socket_register(socket_t* socket, reactor_t* reactor, void* context,
+ socket_cb read_cb, socket_cb write_cb) {
+ CHECK(socket != NULL);
+
+ // Make sure the socket isn't currently registered.
+ socket_unregister(socket);
+
+ socket->read_ready = read_cb;
+ socket->write_ready = write_cb;
+ socket->context = context;
+
+ void (*read_fn)(void*) = (read_cb != NULL) ? internal_read_ready : NULL;
+ void (*write_fn)(void*) = (write_cb != NULL) ? internal_write_ready : NULL;
+
+ socket->reactor_object =
+ reactor_register(reactor, socket->fd, socket, read_fn, write_fn);
+}
+
+void socket_unregister(socket_t* socket) {
+ CHECK(socket != NULL);
+
+ if (socket->reactor_object) reactor_unregister(socket->reactor_object);
+ socket->reactor_object = NULL;
+}
+
+static void internal_read_ready(void* context) {
+ CHECK(context != NULL);
+
+ socket_t* socket = static_cast<socket_t*>(context);
+ socket->read_ready(socket, socket->context);
+}
+
+static void internal_write_ready(void* context) {
+ CHECK(context != NULL);
+
+ socket_t* socket = static_cast<socket_t*>(context);
+ socket->write_ready(socket, socket->context);
+}
diff --git a/mtkbt/code/bt/osi/src/socket_utils/README b/mtkbt/code/bt/osi/src/socket_utils/README
new file mode 100755
index 0000000..9ed210a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/socket_utils/README
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+The sources in this folder re -
+ implement some of the sources in libcutils / sockets to provide a short -
+ term solution eliminating libcutils dependency from system /
+ bt.Once a long -
+ term platform - independent abstraction is presented,
+ these sources and the corresponding headers should be removed.
+
+ Note that only a part of the source files are pulled from libcutils /
+ sockets,
+ and"osi_" prefix is added to all functions
+ .The developers who want to pull sockets sources other than the
+ existing ones must put the sources in this folder and refactor
+ the functions as well.
+
+ The current sources include :
+
+ [Headers] -
+ osi / include / socket_utils / sockets.h -
+ osi / include / socket_utils / socket_local.h[Source files] -
+ osi / src / socket_utils / socket_local_client.cc -
+ osi / src / socket_utils /
+ socket_local_server
+ .cc
+
+ Please update the above list if adding more sources.
diff --git a/mtkbt/code/bt/osi/src/socket_utils/socket_local_client.cc b/mtkbt/code/bt/osi/src/socket_utils/socket_local_client.cc
new file mode 100755
index 0000000..7338407
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/socket_utils/socket_local_client.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/socket_local.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int osi_socket_make_sockaddr_un(const char* name, int namespaceId,
+ struct sockaddr_un* p_addr, socklen_t* alen) {
+ memset(p_addr, 0, sizeof(*p_addr));
+ size_t namelen;
+
+ switch (namespaceId) {
+ case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#if defined(__linux__)
+ namelen = strlen(name);
+
+ // Test with length +1 for the *initial* '\0'.
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
+
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
+
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
+#else
+ /* this OS doesn't have the Linux abstract namespace */
+
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+#endif
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_RESERVED:
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen >
+ sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, name);
+ break;
+ default:
+ // invalid namespace id
+ return -1;
+ }
+
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int osi_socket_local_client_connect(int fd, const char* name, int namespaceId,
+ int type UNUSED_ATTR) {
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int err;
+
+ err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ goto error;
+ }
+
+ OSI_NO_INTR(err = connect(fd, (struct sockaddr*)&addr, alen));
+ if (err < 0) {
+ goto error;
+ }
+
+ return fd;
+
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int osi_socket_local_client(const char* name, int namespaceId, int type) {
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if (s < 0) return -1;
+
+ if (0 > osi_socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
diff --git a/mtkbt/code/bt/osi/src/socket_utils/socket_local_server.cc b/mtkbt/code/bt/osi/src/socket_utils/socket_local_server.cc
new file mode 100755
index 0000000..9bfdf54
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/socket_utils/socket_local_server.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <netinet/in.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "osi/include/socket_utils/socket_local.h"
+#include "osi/include/socket_utils/sockets.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int osi_socket_local_server_bind(int s, const char* name, int namespaceId) {
+ struct sockaddr_un addr;
+ socklen_t alen;
+ int n;
+ int err;
+
+ err = osi_socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ return -1;
+ }
+
+/* basically: if this is a filesystem path, unlink first */
+#if !defined(__linux__)
+ if (1) {
+#else
+ if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED ||
+ namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+ /*ignore ENOENT*/
+ unlink(addr.sun_path);
+ }
+
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ if (bind(s, (struct sockaddr*)&addr, alen) < 0) {
+ return -1;
+ }
+
+ return s;
+}
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem
+ * namespace
+ *
+ * Returns fd on success, -1 on fail
+ */
+int osi_socket_local_server(const char* name, int namespaceId, int type) {
+ int err;
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if (s < 0) return -1;
+
+ err = osi_socket_local_server_bind(s, name, namespaceId);
+
+ if (err < 0) {
+ close(s);
+ return -1;
+ }
+
+ if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
+ int ret;
+
+ ret = listen(s, LISTEN_BACKLOG);
+
+ if (ret < 0) {
+ close(s);
+ return -1;
+ }
+ }
+
+ return s;
+}
diff --git a/mtkbt/code/bt/osi/src/thread.cc b/mtkbt/code/bt/osi/src/thread.cc
new file mode 100755
index 0000000..61b44f2
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/thread.cc
@@ -0,0 +1,253 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_thread"
+
+#include "osi/include/thread.h"
+
+#include <atomic>
+
+#include <base/logging.h>
+#include <errno.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+
+struct thread_t {
+ std::atomic_bool is_joined{false};
+ pthread_t pthread;
+ pid_t tid;
+ char name[THREAD_NAME_MAX + 1];
+ reactor_t* reactor;
+ fixed_queue_t* work_queue;
+};
+
+struct start_arg {
+ thread_t* thread;
+ semaphore_t* start_sem;
+ int error;
+};
+
+typedef struct {
+ thread_fn func;
+ void* context;
+} work_item_t;
+
+static void* run_thread(void* start_arg);
+static void work_queue_read_cb(void* context);
+
+static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 128;
+
+thread_t* thread_new_sized(const char* name, size_t work_queue_capacity) {
+ CHECK(name != NULL);
+ CHECK(work_queue_capacity != 0);
+
+ thread_t* ret = static_cast<thread_t*>(osi_calloc(sizeof(thread_t)));
+
+ ret->reactor = reactor_new();
+ if (!ret->reactor) goto error;
+
+ ret->work_queue = fixed_queue_new(work_queue_capacity);
+ if (!ret->work_queue) goto error;
+
+ // Start is on the stack, but we use a semaphore, so it's safe
+ struct start_arg start;
+ start.start_sem = semaphore_new(0);
+ if (!start.start_sem) goto error;
+
+ strncpy(ret->name, name, THREAD_NAME_MAX);
+ start.thread = ret;
+ start.error = 0;
+ pthread_create(&ret->pthread, NULL, run_thread, &start);
+ semaphore_wait(start.start_sem);
+ semaphore_free(start.start_sem);
+
+ if (start.error) goto error;
+
+ return ret;
+
+error:;
+ if (ret) {
+ fixed_queue_free(ret->work_queue, osi_free);
+ reactor_free(ret->reactor);
+ }
+ osi_free(ret);
+ return NULL;
+}
+
+thread_t* thread_new(const char* name) {
+ return thread_new_sized(name, DEFAULT_WORK_QUEUE_CAPACITY);
+}
+
+void thread_free(thread_t* thread) {
+ if (!thread) return;
+
+ thread_stop(thread);
+ thread_join(thread);
+
+ fixed_queue_free(thread->work_queue, osi_free);
+ reactor_free(thread->reactor);
+ osi_free(thread);
+}
+
+void thread_join(thread_t* thread) {
+ CHECK(thread != NULL);
+
+ if (!std::atomic_exchange(&thread->is_joined, true))
+ pthread_join(thread->pthread, NULL);
+}
+
+bool thread_post(thread_t* thread, thread_fn func, void* context) {
+ CHECK(thread != NULL);
+ CHECK(func != NULL);
+
+ // TODO(sharvil): if the current thread == |thread| and we've run out
+ // of queue space, we should abort this operation, otherwise we'll
+ // deadlock.
+
+ // Queue item is freed either when the queue itself is destroyed
+ // or when the item is removed from the queue for dispatch.
+ work_item_t* item = (work_item_t*)osi_malloc(sizeof(work_item_t));
+ item->func = func;
+ item->context = context;
+ fixed_queue_enqueue(thread->work_queue, item);
+ return true;
+}
+
+void thread_stop(thread_t* thread) {
+ CHECK(thread != NULL);
+ reactor_stop(thread->reactor);
+}
+
+bool thread_set_priority(thread_t* thread, int priority) {
+ if (!thread) return false;
+
+ const int rc = setpriority(PRIO_PROCESS, thread->tid, priority);
+ if (rc < 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to set thread priority %d for tid %d, error %d",
+ __func__, priority, thread->tid, rc);
+ return false;
+ }
+
+ return true;
+}
+
+bool thread_set_rt_priority(thread_t* thread, int priority) {
+ if (!thread) return false;
+
+ struct sched_param rt_params;
+ rt_params.sched_priority = priority;
+
+ const int rc = sched_setscheduler(thread->tid, SCHED_FIFO, &rt_params);
+ if (rc != 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to set SCHED_FIFO priority %d for tid %d, error %s",
+ __func__, priority, thread->tid, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool thread_is_self(const thread_t* thread) {
+ CHECK(thread != NULL);
+ return !!pthread_equal(pthread_self(), thread->pthread);
+}
+
+reactor_t* thread_get_reactor(const thread_t* thread) {
+ CHECK(thread != NULL);
+ return thread->reactor;
+}
+
+const char* thread_name(const thread_t* thread) {
+ CHECK(thread != NULL);
+ return thread->name;
+}
+
+static void* run_thread(void* start_arg) {
+ CHECK(start_arg != NULL);
+
+ struct start_arg* start = static_cast<struct start_arg*>(start_arg);
+ thread_t* thread = start->thread;
+
+ CHECK(thread != NULL);
+
+ if (prctl(PR_SET_NAME, (unsigned long)thread->name) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to set thread name: %s", __func__,
+ strerror(errno));
+ start->error = errno;
+ semaphore_post(start->start_sem);
+ return NULL;
+ }
+ thread->tid = gettid();
+
+ LOG_INFO(LOG_TAG, "%s: thread id %d, thread name %s started", __func__,
+ thread->tid, thread->name);
+
+ semaphore_post(start->start_sem);
+
+ int fd = fixed_queue_get_dequeue_fd(thread->work_queue);
+ void* context = thread->work_queue;
+
+ reactor_object_t* work_queue_object =
+ reactor_register(thread->reactor, fd, context, work_queue_read_cb, NULL);
+ reactor_start(thread->reactor);
+ reactor_unregister(work_queue_object);
+
+ // Make sure we dispatch all queued work items before exiting the thread.
+ // This allows a caller to safely tear down by enqueuing a teardown
+ // work item and then joining the thread.
+ size_t count = 0;
+ work_item_t* item =
+ static_cast<work_item_t*>(fixed_queue_try_dequeue(thread->work_queue));
+ while (item && count <= fixed_queue_capacity(thread->work_queue)) {
+ item->func(item->context);
+ osi_free(item);
+ item =
+ static_cast<work_item_t*>(fixed_queue_try_dequeue(thread->work_queue));
+ ++count;
+ }
+
+ if (count > fixed_queue_capacity(thread->work_queue))
+ LOG_DEBUG(LOG_TAG, "%s growing event queue on shutdown.", __func__);
+
+ LOG_WARN(LOG_TAG, "%s: thread id %d, thread name %s exited", __func__,
+ thread->tid, thread->name);
+ return NULL;
+}
+
+static void work_queue_read_cb(void* context) {
+ CHECK(context != NULL);
+
+ fixed_queue_t* queue = (fixed_queue_t*)context;
+ work_item_t* item = static_cast<work_item_t*>(fixed_queue_dequeue(queue));
+ item->func(item->context);
+ osi_free(item);
+}
diff --git a/mtkbt/code/bt/osi/src/time.cc b/mtkbt/code/bt/osi/src/time.cc
new file mode 100755
index 0000000..0b7f3a1
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/time.cc
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_time"
+
+#include <sys/time.h>
+#include <time.h>
+
+#include "osi/include/time.h"
+
+uint32_t time_get_os_boottime_ms(void) {
+ return (uint32_t)(time_get_os_boottime_us() / 1000);
+}
+
+uint64_t time_get_os_boottime_us(void) {
+ struct timespec ts_now;
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
+
+ return ((uint64_t)ts_now.tv_sec * 1000000L) +
+ ((uint64_t)ts_now.tv_nsec / 1000);
+}
+
+uint64_t time_gettimeofday_us(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return static_cast<uint64_t>(tv.tv_sec) * 1000000ULL +
+ static_cast<uint64_t>(tv.tv_usec);
+}
diff --git a/mtkbt/code/bt/osi/src/wakelock.cc b/mtkbt/code/bt/osi/src/wakelock.cc
new file mode 100755
index 0000000..565735f
--- a/dev/null
+++ b/mtkbt/code/bt/osi/src/wakelock.cc
@@ -0,0 +1,373 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_osi_wakelock"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <hardware/bluetooth.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <string>
+
+#include "base/logging.h"
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+#include "osi/include/metrics.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "osi/include/wakelock.h"
+
+using system_bt_osi::BluetoothMetricsLogger;
+
+static bt_os_callouts_t* wakelock_os_callouts = NULL;
+static bool is_native = true;
+
+static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
+static const char* WAKE_LOCK_ID = "bluetooth_timer";
+static const std::string DEFAULT_WAKE_LOCK_PATH = "/sys/power/wake_lock";
+static const std::string DEFAULT_WAKE_UNLOCK_PATH = "/sys/power/wake_unlock";
+static std::string wake_lock_path;
+static std::string wake_unlock_path;
+static ssize_t locked_id_len = -1;
+static pthread_once_t initialized = PTHREAD_ONCE_INIT;
+static int wake_lock_fd = INVALID_FD;
+static int wake_unlock_fd = INVALID_FD;
+
+// Wakelock statistics for the "bluetooth_timer"
+typedef struct {
+ bool is_acquired;
+ size_t acquired_count;
+ size_t released_count;
+ size_t acquired_errors;
+ size_t released_errors;
+ period_ms_t min_acquired_interval_ms;
+ period_ms_t max_acquired_interval_ms;
+ period_ms_t last_acquired_interval_ms;
+ period_ms_t total_acquired_interval_ms;
+ period_ms_t last_acquired_timestamp_ms;
+ period_ms_t last_released_timestamp_ms;
+ period_ms_t last_reset_timestamp_ms;
+ int last_acquired_error;
+ int last_released_error;
+} wakelock_stats_t;
+
+static wakelock_stats_t wakelock_stats;
+
+// This mutex ensures that the functions that update and dump the statistics
+// are executed serially.
+static std::mutex stats_mutex;
+
+static bt_status_t wakelock_acquire_callout(void);
+static bt_status_t wakelock_acquire_native(void);
+static bt_status_t wakelock_release_callout(void);
+static bt_status_t wakelock_release_native(void);
+static void wakelock_initialize(void);
+static void wakelock_initialize_native(void);
+static void reset_wakelock_stats(void);
+static void update_wakelock_acquired_stats(bt_status_t acquired_status);
+static void update_wakelock_released_stats(bt_status_t released_status);
+
+void wakelock_set_os_callouts(bt_os_callouts_t* callouts) {
+ wakelock_os_callouts = callouts;
+ is_native = (wakelock_os_callouts == NULL);
+ LOG_INFO(LOG_TAG, "%s set to %s", __func__,
+ (is_native) ? "native" : "non-native");
+}
+
+bool wakelock_acquire(void) {
+ pthread_once(&initialized, wakelock_initialize);
+
+ bt_status_t status = BT_STATUS_FAIL;
+
+ if (is_native)
+ status = wakelock_acquire_native();
+ else
+ status = wakelock_acquire_callout();
+
+ update_wakelock_acquired_stats(status);
+
+ if (status != BT_STATUS_SUCCESS)
+ LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock: %d", __func__, status);
+
+ return (status == BT_STATUS_SUCCESS);
+}
+
+static bt_status_t wakelock_acquire_callout(void) {
+ return static_cast<bt_status_t>(
+ wakelock_os_callouts->acquire_wake_lock(WAKE_LOCK_ID));
+}
+
+static bt_status_t wakelock_acquire_native(void) {
+ if (wake_lock_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s lock not acquired, invalid fd", __func__);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ if (wake_unlock_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s not acquiring lock: can't release lock", __func__);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ long lock_name_len = strlen(WAKE_LOCK_ID);
+ locked_id_len = write(wake_lock_fd, WAKE_LOCK_ID, lock_name_len);
+ if (locked_id_len == -1) {
+ LOG_ERROR(LOG_TAG, "%s wake lock not acquired: %s", __func__,
+ strerror(errno));
+ return BT_STATUS_FAIL;
+ } else if (locked_id_len < lock_name_len) {
+ // TODO (jamuraa): this is weird. maybe we should release and retry.
+ LOG_WARN(LOG_TAG, "%s wake lock truncated to %zd chars", __func__,
+ locked_id_len);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+bool wakelock_release(void) {
+ pthread_once(&initialized, wakelock_initialize);
+
+ bt_status_t status = BT_STATUS_FAIL;
+
+ if (is_native)
+ status = wakelock_release_native();
+ else
+ status = wakelock_release_callout();
+
+ update_wakelock_released_stats(status);
+
+ return (status == BT_STATUS_SUCCESS);
+}
+
+static bt_status_t wakelock_release_callout(void) {
+ return static_cast<bt_status_t>(
+ wakelock_os_callouts->release_wake_lock(WAKE_LOCK_ID));
+}
+
+static bt_status_t wakelock_release_native(void) {
+ if (wake_unlock_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s lock not released, invalid fd", __func__);
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ ssize_t wrote_name_len = write(wake_unlock_fd, WAKE_LOCK_ID, locked_id_len);
+ if (wrote_name_len == -1) {
+ LOG_ERROR(LOG_TAG, "%s can't release wake lock: %s", __func__,
+ strerror(errno));
+ } else if (wrote_name_len < locked_id_len) {
+ LOG_ERROR(LOG_TAG, "%s lock release only wrote %zd, assuming released",
+ __func__, wrote_name_len);
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+static void wakelock_initialize(void) {
+ reset_wakelock_stats();
+
+ if (is_native) wakelock_initialize_native();
+}
+
+static void wakelock_initialize_native(void) {
+ LOG_DEBUG(LOG_TAG, "%s opening wake locks", __func__);
+
+ if (wake_lock_path.empty()) wake_lock_path = DEFAULT_WAKE_LOCK_PATH;
+
+ wake_lock_fd = open(wake_lock_path.c_str(), O_RDWR | O_CLOEXEC);
+ if (wake_lock_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s can't open wake lock %s: %s", __func__,
+ wake_lock_path.c_str(), strerror(errno));
+ CHECK(wake_lock_fd != INVALID_FD);
+ }
+
+ if (wake_unlock_path.empty()) wake_unlock_path = DEFAULT_WAKE_UNLOCK_PATH;
+
+ wake_unlock_fd = open(wake_unlock_path.c_str(), O_RDWR | O_CLOEXEC);
+ if (wake_unlock_fd == INVALID_FD) {
+ LOG_ERROR(LOG_TAG, "%s can't open wake unlock %s: %s", __func__,
+ wake_unlock_path.c_str(), strerror(errno));
+ CHECK(wake_unlock_fd != INVALID_FD);
+ }
+}
+
+void wakelock_cleanup(void) {
+ wake_lock_path.clear();
+ wake_unlock_path.clear();
+ initialized = PTHREAD_ONCE_INIT;
+}
+
+void wakelock_set_paths(const char* lock_path, const char* unlock_path) {
+ if (lock_path) wake_lock_path = lock_path;
+
+ if (unlock_path) wake_unlock_path = unlock_path;
+}
+
+static period_ms_t now(void) {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_ID, &ts) == -1) {
+ LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__,
+ strerror(errno));
+ return 0;
+ }
+
+ return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
+}
+
+// Reset the Bluetooth wakelock statistics.
+// This function is thread-safe.
+static void reset_wakelock_stats(void) {
+ std::lock_guard<std::mutex> lock(stats_mutex);
+
+ wakelock_stats.is_acquired = false;
+ wakelock_stats.acquired_count = 0;
+ wakelock_stats.released_count = 0;
+ wakelock_stats.acquired_errors = 0;
+ wakelock_stats.released_errors = 0;
+ wakelock_stats.min_acquired_interval_ms = 0;
+ wakelock_stats.max_acquired_interval_ms = 0;
+ wakelock_stats.last_acquired_interval_ms = 0;
+ wakelock_stats.total_acquired_interval_ms = 0;
+ wakelock_stats.last_acquired_timestamp_ms = 0;
+ wakelock_stats.last_released_timestamp_ms = 0;
+ wakelock_stats.last_reset_timestamp_ms = now();
+}
+
+//
+// Update the Bluetooth acquire wakelock statistics.
+//
+// This function should be called every time when the wakelock is acquired.
+// |acquired_status| is the status code that was return when the wakelock was
+// acquired.
+// This function is thread-safe.
+//
+static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
+ const period_ms_t now_ms = now();
+
+ std::lock_guard<std::mutex> lock(stats_mutex);
+
+ if (acquired_status != BT_STATUS_SUCCESS) {
+ wakelock_stats.acquired_errors++;
+ wakelock_stats.last_acquired_error = acquired_status;
+ }
+
+ if (wakelock_stats.is_acquired) {
+ return;
+ }
+
+ wakelock_stats.is_acquired = true;
+ wakelock_stats.acquired_count++;
+ wakelock_stats.last_acquired_timestamp_ms = now_ms;
+
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ system_bt_osi::WAKE_EVENT_ACQUIRED, "", "", now_ms);
+}
+
+//
+// Update the Bluetooth release wakelock statistics.
+//
+// This function should be called every time when the wakelock is released.
+// |released_status| is the status code that was return when the wakelock was
+// released.
+// This function is thread-safe.
+//
+static void update_wakelock_released_stats(bt_status_t released_status) {
+ const period_ms_t now_ms = now();
+
+ std::lock_guard<std::mutex> lock(stats_mutex);
+
+ if (released_status != BT_STATUS_SUCCESS) {
+ wakelock_stats.released_errors++;
+ wakelock_stats.last_released_error = released_status;
+ }
+
+ if (!wakelock_stats.is_acquired) {
+ return;
+ }
+
+ wakelock_stats.is_acquired = false;
+ wakelock_stats.released_count++;
+ wakelock_stats.last_released_timestamp_ms = now_ms;
+
+ // Compute the acquired interval and update the statistics
+ period_ms_t delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
+ if (delta_ms < wakelock_stats.min_acquired_interval_ms ||
+ wakelock_stats.released_count == 1) {
+ wakelock_stats.min_acquired_interval_ms = delta_ms;
+ }
+ if (delta_ms > wakelock_stats.max_acquired_interval_ms) {
+ wakelock_stats.max_acquired_interval_ms = delta_ms;
+ }
+ wakelock_stats.last_acquired_interval_ms = delta_ms;
+ wakelock_stats.total_acquired_interval_ms += delta_ms;
+
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ system_bt_osi::WAKE_EVENT_RELEASED, "", "", now_ms);
+}
+
+void wakelock_debug_dump(int fd) {
+ const period_ms_t now_ms = now();
+
+ std::lock_guard<std::mutex> lock(stats_mutex);
+
+ // Compute the last acquired interval if the wakelock is still acquired
+ period_ms_t delta_ms = 0;
+ period_ms_t last_interval = wakelock_stats.last_acquired_interval_ms;
+ period_ms_t min_interval = wakelock_stats.min_acquired_interval_ms;
+ period_ms_t max_interval = wakelock_stats.max_acquired_interval_ms;
+ period_ms_t ave_interval = 0;
+
+ if (wakelock_stats.is_acquired) {
+ delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms;
+ if (delta_ms > max_interval) max_interval = delta_ms;
+ if (delta_ms < min_interval) min_interval = delta_ms;
+ last_interval = delta_ms;
+ }
+ period_ms_t total_interval =
+ wakelock_stats.total_acquired_interval_ms + delta_ms;
+
+ if (wakelock_stats.acquired_count > 0)
+ ave_interval = total_interval / wakelock_stats.acquired_count;
+
+ dprintf(fd, "\nBluetooth Wakelock Statistics:\n");
+ dprintf(fd, " Is acquired : %s\n",
+ wakelock_stats.is_acquired ? "true" : "false");
+ dprintf(fd, " Acquired/released count : %zu / %zu\n",
+ wakelock_stats.acquired_count, wakelock_stats.released_count);
+ dprintf(fd, " Acquired/released error count : %zu / %zu\n",
+ wakelock_stats.acquired_errors, wakelock_stats.released_errors);
+ dprintf(fd, " Last acquire/release error code: %d / %d\n",
+ wakelock_stats.last_acquired_error,
+ wakelock_stats.last_released_error);
+ dprintf(fd, " Last acquired time (ms) : %llu\n",
+ (unsigned long long)last_interval);
+ dprintf(fd, " Acquired time min/max/avg (ms) : %llu / %llu / %llu\n",
+ (unsigned long long)min_interval, (unsigned long long)max_interval,
+ (unsigned long long)ave_interval);
+ dprintf(fd, " Total acquired time (ms) : %llu\n",
+ (unsigned long long)total_interval);
+ dprintf(
+ fd, " Total run time (ms) : %llu\n",
+ (unsigned long long)(now_ms - wakelock_stats.last_reset_timestamp_ms));
+}
diff --git a/mtkbt/code/bt/osi/test/AlarmTestHarness.cc b/mtkbt/code/bt/osi/test/AlarmTestHarness.cc
new file mode 100755
index 0000000..ee6aaa3
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/AlarmTestHarness.cc
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "AlarmTestHarness.h"
+
+#include <hardware/bluetooth.h>
+
+#include "osi/include/alarm.h"
+#include "osi/include/wakelock.h"
+
+static bool is_wake_lock_acquired = false;
+
+static int acquire_wake_lock_cb(const char* lock_name) {
+ is_wake_lock_acquired = true;
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock_cb(const char* lock_name) {
+ is_wake_lock_acquired = false;
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t bt_wakelock_callouts = {
+ sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb};
+
+void AlarmTestHarness::SetUp() {
+ AllocationTestHarness::SetUp();
+
+ TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 500;
+
+ wakelock_set_os_callouts(&bt_wakelock_callouts);
+}
+
+void AlarmTestHarness::TearDown() {
+ alarm_cleanup();
+ wakelock_cleanup();
+ wakelock_set_os_callouts(NULL);
+
+ AllocationTestHarness::TearDown();
+}
+
+bool AlarmTestHarness::WakeLockHeld() { return is_wake_lock_acquired; }
diff --git a/mtkbt/code/bt/osi/test/AlarmTestHarness.h b/mtkbt/code/bt/osi/test/AlarmTestHarness.h
new file mode 100755
index 0000000..39dd218
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/AlarmTestHarness.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "AllocationTestHarness.h"
+
+extern int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS;
+
+class AlarmTestHarness : public AllocationTestHarness {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+ public:
+ // Returns true if a wake lock is held.
+ bool WakeLockHeld();
+};
diff --git a/mtkbt/code/bt/osi/test/AllocationTestHarness.cc b/mtkbt/code/bt/osi/test/AllocationTestHarness.cc
new file mode 100755
index 0000000..8df097f
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/AllocationTestHarness.cc
@@ -0,0 +1,33 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "osi/test/AllocationTestHarness.h"
+
+#include "osi/include/allocation_tracker.h"
+
+void AllocationTestHarness::SetUp() {
+ allocation_tracker_init();
+ allocation_tracker_reset();
+}
+
+void AllocationTestHarness::TearDown() {
+ EXPECT_EQ(0U, allocation_tracker_expect_no_allocations())
+ << "not all memory freed";
+}
diff --git a/mtkbt/code/bt/osi/test/AllocationTestHarness.h b/mtkbt/code/bt/osi/test/AllocationTestHarness.h
new file mode 100755
index 0000000..cbf29d8
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/AllocationTestHarness.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+class AllocationTestHarness : public ::testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+};
diff --git a/mtkbt/code/bt/osi/test/alarm_test.cc b/mtkbt/code/bt/osi/test/alarm_test.cc
new file mode 100755
index 0000000..dd4bbc1
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/alarm_test.cc
@@ -0,0 +1,453 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "AlarmTestHarness.h"
+
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+static semaphore_t* semaphore;
+static int cb_counter;
+static int cb_misordered_counter;
+
+static const uint64_t EPSILON_MS = 50;
+
+static void msleep(uint64_t ms) { usleep(ms * 1000); }
+
+class AlarmTest : public AlarmTestHarness {
+ protected:
+ virtual void SetUp() {
+ AlarmTestHarness::SetUp();
+ cb_counter = 0;
+ cb_misordered_counter = 0;
+
+ semaphore = semaphore_new(0);
+ }
+
+ virtual void TearDown() {
+ semaphore_free(semaphore);
+ AlarmTestHarness::TearDown();
+ }
+};
+
+static void cb(UNUSED_ATTR void* data) {
+ ++cb_counter;
+ semaphore_post(semaphore);
+}
+
+static void ordered_cb(void* data) {
+ int i = PTR_TO_INT(data);
+ if (i != cb_counter) cb_misordered_counter++;
+ ++cb_counter;
+ semaphore_post(semaphore);
+}
+
+TEST_F(AlarmTest, test_new_free_simple) {
+ alarm_t* alarm = alarm_new("alarm_test.test_new_free_simple");
+ ASSERT_TRUE(alarm != NULL);
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_free_null) { alarm_free(NULL); }
+
+TEST_F(AlarmTest, test_simple_cancel) {
+ alarm_t* alarm = alarm_new("alarm_test.test_simple_cancel");
+ alarm_cancel(alarm);
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_cancel) {
+ alarm_t* alarm = alarm_new("alarm_test.test_cancel");
+ alarm_set(alarm, 10, cb, NULL);
+ alarm_cancel(alarm);
+
+ msleep(10 + EPSILON_MS);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_FALSE(WakeLockHeld());
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_cancel_idempotent) {
+ alarm_t* alarm = alarm_new("alarm_test.test_cancel_idempotent");
+ alarm_set(alarm, 10, cb, NULL);
+ alarm_cancel(alarm);
+ alarm_cancel(alarm);
+ alarm_cancel(alarm);
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short) {
+ alarm_t* alarm = alarm_new("alarm_test.test_set_short");
+
+ alarm_set(alarm, 10, cb, NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_TRUE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short_periodic) {
+ alarm_t* alarm = alarm_new_periodic("alarm_test.test_set_short_periodic");
+
+ alarm_set(alarm, 10, cb, NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_TRUE(WakeLockHeld());
+
+ for (int i = 1; i <= 10; i++) {
+ semaphore_wait(semaphore);
+
+ EXPECT_GE(cb_counter, i);
+ EXPECT_TRUE(WakeLockHeld());
+ }
+ alarm_cancel(alarm);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_zero_periodic) {
+ alarm_t* alarm = alarm_new_periodic("alarm_test.test_set_zero_periodic");
+
+ alarm_set(alarm, 0, cb, NULL);
+
+ EXPECT_TRUE(WakeLockHeld());
+
+ for (int i = 1; i <= 10; i++) {
+ semaphore_wait(semaphore);
+
+ EXPECT_GE(cb_counter, i);
+ EXPECT_TRUE(WakeLockHeld());
+ }
+ alarm_cancel(alarm);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_long) {
+ alarm_t* alarm = alarm_new("alarm_test.test_set_long");
+ alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_FALSE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm);
+}
+
+TEST_F(AlarmTest, test_set_short_short) {
+ alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_short_short_0"),
+ alarm_new("alarm_test.test_set_short_short_1")};
+
+ alarm_set(alarm[0], 10, cb, NULL);
+ alarm_set(alarm[1], 20, cb, NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_TRUE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_TRUE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 2);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm[0]);
+ alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_set_short_long) {
+ alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_short_long_0"),
+ alarm_new("alarm_test.test_set_short_long_1")};
+
+ alarm_set(alarm[0], 10, cb, NULL);
+ alarm_set(alarm[1], 10 + TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb,
+ NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_TRUE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_FALSE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 2);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm[0]);
+ alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_set_long_long) {
+ alarm_t* alarm[2] = {alarm_new("alarm_test.test_set_long_long_0"),
+ alarm_new("alarm_test.test_set_long_long_1")};
+
+ alarm_set(alarm[0], TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+ alarm_set(alarm[1], 2 * (TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS), cb,
+ NULL);
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_FALSE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_FALSE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_EQ(cb_counter, 2);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm[0]);
+ alarm_free(alarm[1]);
+}
+
+TEST_F(AlarmTest, test_is_scheduled) {
+ alarm_t* alarm = alarm_new("alarm_test.test_is_scheduled");
+
+ EXPECT_FALSE(alarm_is_scheduled((alarm_t*)NULL));
+ EXPECT_FALSE(alarm_is_scheduled(alarm));
+ alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL);
+ EXPECT_TRUE(alarm_is_scheduled(alarm));
+
+ EXPECT_EQ(cb_counter, 0);
+ EXPECT_FALSE(WakeLockHeld());
+
+ semaphore_wait(semaphore);
+
+ EXPECT_FALSE(alarm_is_scheduled(alarm));
+ EXPECT_EQ(cb_counter, 1);
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_free(alarm);
+}
+
+// Test whether the callbacks are invoked in the expected order
+TEST_F(AlarmTest, test_callback_ordering) {
+ alarm_t* alarms[100];
+
+ for (int i = 0; i < 100; i++) {
+ const std::string alarm_name =
+ "alarm_test.test_callback_ordering[" + std::to_string(i) + "]";
+ alarms[i] = alarm_new(alarm_name.c_str());
+ }
+
+ for (int i = 0; i < 100; i++) {
+ alarm_set(alarms[i], 100, ordered_cb, INT_TO_PTR(i));
+ }
+
+ for (int i = 1; i <= 100; i++) {
+ semaphore_wait(semaphore);
+ EXPECT_GE(cb_counter, i);
+ }
+ EXPECT_EQ(cb_counter, 100);
+ EXPECT_EQ(cb_misordered_counter, 0);
+
+ for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
+
+ EXPECT_FALSE(WakeLockHeld());
+}
+
+// Test whether the callbacks are involed in the expected order on a
+// separate queue.
+TEST_F(AlarmTest, test_callback_ordering_on_queue) {
+ alarm_t* alarms[100];
+ fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+ thread_t* thread =
+ thread_new("timers.test_callback_ordering_on_queue.thread");
+
+ alarm_register_processing_queue(queue, thread);
+
+ for (int i = 0; i < 100; i++) {
+ const std::string alarm_name =
+ "alarm_test.test_callback_ordering_on_queue[" + std::to_string(i) + "]";
+ alarms[i] = alarm_new(alarm_name.c_str());
+ }
+
+ for (int i = 0; i < 100; i++) {
+ alarm_set_on_queue(alarms[i], 100, ordered_cb, INT_TO_PTR(i), queue);
+ }
+
+ for (int i = 1; i <= 100; i++) {
+ semaphore_wait(semaphore);
+ EXPECT_GE(cb_counter, i);
+ }
+ EXPECT_EQ(cb_counter, 100);
+ EXPECT_EQ(cb_misordered_counter, 0);
+
+ for (int i = 0; i < 100; i++) alarm_free(alarms[i]);
+
+ EXPECT_FALSE(WakeLockHeld());
+
+ alarm_unregister_processing_queue(queue);
+ fixed_queue_free(queue, NULL);
+ thread_free(thread);
+}
+
+// Test whether unregistering a processing queue cancels all timers using
+// that queue.
+TEST_F(AlarmTest, test_unregister_processing_queue) {
+ alarm_t* alarms[100];
+ fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+ thread_t* thread =
+ thread_new("timers.test_unregister_processing_queue.thread");
+
+ alarm_register_processing_queue(queue, thread);
+
+ for (int i = 0; i < 100; i++) {
+ const std::string alarm_name =
+ "alarm_test.test_unregister_processing_queue[" + std::to_string(i) +
+ "]";
+ alarms[i] = alarm_new(alarm_name.c_str());
+ }
+
+ // Schedule half of the timers to expire soon, and the rest far in the future
+ for (int i = 0; i < 50; i++) {
+ alarm_set_on_queue(alarms[i], 100, ordered_cb, INT_TO_PTR(i), queue);
+ }
+ for (int i = 50; i < 100; i++) {
+ alarm_set_on_queue(alarms[i], 1000 * 1000, ordered_cb, INT_TO_PTR(i),
+ queue);
+ }
+
+ // Wait until half of the timers have expired
+ for (int i = 1; i <= 50; i++) {
+ semaphore_wait(semaphore);
+ EXPECT_GE(cb_counter, i);
+ }
+ EXPECT_EQ(cb_counter, 50);
+ EXPECT_EQ(cb_misordered_counter, 0);
+
+ // Test that only the expired timers are not scheduled
+ for (int i = 0; i < 50; i++) {
+ EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+ }
+ for (int i = 50; i < 100; i++) {
+ EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+ }
+
+ alarm_unregister_processing_queue(queue);
+
+ // Test that none of the timers are scheduled
+ for (int i = 0; i < 100; i++) {
+ EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+ }
+
+ for (int i = 0; i < 100; i++) {
+ alarm_free(alarms[i]);
+ }
+
+ EXPECT_FALSE(WakeLockHeld());
+
+ fixed_queue_free(queue, NULL);
+ thread_free(thread);
+}
+
+// Test whether unregistering a processing queue cancels all periodic timers
+// using that queue.
+TEST_F(AlarmTest, test_periodic_unregister_processing_queue) {
+ alarm_t* alarms[5];
+ fixed_queue_t* queue = fixed_queue_new(SIZE_MAX);
+ thread_t* thread =
+ thread_new("timers.test_periodic_unregister_processing_queue.thread");
+
+ alarm_register_processing_queue(queue, thread);
+
+ for (int i = 0; i < 5; i++) {
+ const std::string alarm_name =
+ "alarm_test.test_periodic_unregister_processing_queue[" +
+ std::to_string(i) + "]";
+ alarms[i] = alarm_new_periodic(alarm_name.c_str());
+ }
+
+ // Schedule each of the timers with different period
+ for (int i = 0; i < 5; i++) {
+ alarm_set_on_queue(alarms[i], 20 + i, cb, INT_TO_PTR(i), queue);
+ }
+ EXPECT_TRUE(WakeLockHeld());
+
+ for (int i = 1; i <= 20; i++) {
+ semaphore_wait(semaphore);
+
+ EXPECT_GE(cb_counter, i);
+ EXPECT_TRUE(WakeLockHeld());
+ }
+
+ // Test that all timers are still scheduled
+ for (int i = 0; i < 5; i++) {
+ EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+ }
+
+ alarm_unregister_processing_queue(queue);
+
+ int saved_cb_counter = cb_counter;
+
+ // Test that none of the timers are scheduled
+ for (int i = 0; i < 5; i++) {
+ EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+ }
+
+ // Sleep for 500ms and test again that the cb_counter hasn't been modified
+ usleep(500 * 1000);
+ EXPECT_TRUE(cb_counter == saved_cb_counter);
+
+ for (int i = 0; i < 5; i++) {
+ alarm_free(alarms[i]);
+ }
+
+ EXPECT_FALSE(WakeLockHeld());
+
+ fixed_queue_free(queue, NULL);
+ thread_free(thread);
+}
+
+// Try to catch any race conditions between the timer callback and |alarm_free|.
+TEST_F(AlarmTest, test_callback_free_race) {
+ for (int i = 0; i < 1000; ++i) {
+ const std::string alarm_name =
+ "alarm_test.test_callback_free_race[" + std::to_string(i) + "]";
+ alarm_t* alarm = alarm_new(alarm_name.c_str());
+ alarm_set(alarm, 0, cb, NULL);
+ alarm_free(alarm);
+ }
+ alarm_cleanup();
+}
diff --git a/mtkbt/code/bt/osi/test/allocation_tracker_test.cc b/mtkbt/code/bt/osi/test/allocation_tracker_test.cc
new file mode 100755
index 0000000..cf979cb
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/allocation_tracker_test.cc
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "osi/include/allocation_tracker.h"
+
+void allocation_tracker_uninit(void);
+
+static const allocator_id_t allocator_id = 5;
+
+TEST(AllocationTrackerTest, test_uninit_no_bad_effects) {
+ void* dummy_allocation = malloc(4);
+
+ // Ensure uninitialized state (previous tests may have called init)
+ allocation_tracker_uninit();
+
+ EXPECT_EQ(4U, allocation_tracker_resize_for_canary(4));
+ allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4);
+ EXPECT_EQ(0U, allocation_tracker_expect_no_allocations()); // should not have
+ // registered an
+ // allocation
+ allocation_tracker_notify_free(allocator_id, dummy_allocation);
+ EXPECT_EQ(0U, allocation_tracker_expect_no_allocations());
+
+ free(dummy_allocation);
+}
+
+TEST(AllocationTrackerTest, test_canaries_on) {
+ allocation_tracker_uninit();
+ allocation_tracker_init();
+
+ size_t with_canary_size = allocation_tracker_resize_for_canary(4);
+ EXPECT_TRUE(with_canary_size > 4);
+
+ void* dummy_allocation = malloc(with_canary_size);
+ void* useable_ptr =
+ allocation_tracker_notify_alloc(allocator_id, dummy_allocation, 4);
+ EXPECT_TRUE(useable_ptr > dummy_allocation);
+ EXPECT_EQ(4U, allocation_tracker_expect_no_allocations()); // should have
+ // registered the
+ // allocation
+ void* freeable_ptr =
+ allocation_tracker_notify_free(allocator_id, useable_ptr);
+ EXPECT_EQ(dummy_allocation, freeable_ptr);
+ EXPECT_EQ(0U, allocation_tracker_expect_no_allocations());
+
+ free(dummy_allocation);
+}
diff --git a/mtkbt/code/bt/osi/test/allocator_test.cc b/mtkbt/code/bt/osi/test/allocator_test.cc
new file mode 100755
index 0000000..9dc6302
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/allocator_test.cc
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ *
+ ******************************************************************************/
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/allocator.h"
+
+class AllocatorTest : public AllocationTestHarness {};
+
+TEST_F(AllocatorTest, test_osi_strndup) {
+ char str[] = "IloveBluetooth";
+ size_t len = strlen(str);
+ char* copy_str = NULL;
+
+ // len == 0
+ copy_str = osi_strndup(str, 0);
+ EXPECT_EQ(0, strcmp(copy_str, ""));
+ osi_free(copy_str);
+
+ // len == strlen(str)
+ copy_str = osi_strndup(str, len);
+ EXPECT_EQ(0, strcmp(str, copy_str));
+ osi_free(copy_str);
+
+ // len < strlen(str)
+ copy_str = osi_strndup(str, len - 5);
+ EXPECT_EQ(0, strcmp("IloveBlue", copy_str));
+ osi_free(copy_str);
+
+ // len > strlen(str)
+ copy_str = osi_strndup(str, len + 5);
+ EXPECT_EQ(0, strcmp(str, copy_str));
+ osi_free(copy_str);
+}
diff --git a/mtkbt/code/bt/osi/test/array_test.cc b/mtkbt/code/bt/osi/test/array_test.cc
new file mode 100755
index 0000000..2addadc
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/array_test.cc
@@ -0,0 +1,67 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/array.h"
+
+class ArrayTest : public AllocationTestHarness {};
+
+TEST_F(ArrayTest, test_new_free_simple) {
+ array_t* array = array_new(4);
+ ASSERT_TRUE(array != NULL);
+ array_free(array);
+}
+
+TEST_F(ArrayTest, test_free_null) { array_free(NULL); }
+
+TEST_F(ArrayTest, test_invalid_ptr) {
+ array_t* array = array_new(4);
+ EXPECT_DEATH(array_ptr(array), "");
+ array_free(array);
+}
+
+TEST_F(ArrayTest, test_invalid_at) {
+ array_t* array = array_new(4);
+ EXPECT_DEATH(array_at(array, 1), "");
+ array_free(array);
+}
+
+TEST_F(ArrayTest, test_append_value) {
+ array_t* array = array_new(sizeof(int));
+ for (int i = 0; i < 100; ++i) {
+ array_append_value(array, i * i);
+ }
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(*(int*)array_at(array, i), i * i);
+ }
+ array_free(array);
+}
+
+TEST_F(ArrayTest, test_append_ptr) {
+ int items[100];
+ array_t* array = array_new(sizeof(int));
+ for (int i = 0; i < 100; ++i) {
+ items[i] = i * i;
+ array_append_ptr(array, &items[i]);
+ }
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(*(int*)array_at(array, i), i * i);
+ }
+ array_free(array);
+}
+
+TEST_F(ArrayTest, test_large_element) {
+ char strings[][128] = {
+ "string 1", "string 2", "string 3", "string 4",
+ "string 5", "string 6", "string 7", "string 8",
+ };
+
+ array_t* array = array_new(128);
+ for (int i = 0; i < 100; ++i) {
+ array_append_ptr(array, strings[i % 8]);
+ }
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_TRUE(!memcmp(array_at(array, i), strings[i % 8], 128));
+ }
+ array_free(array);
+}
diff --git a/mtkbt/code/bt/osi/test/config_test.cc b/mtkbt/code/bt/osi/test/config_test.cc
new file mode 100755
index 0000000..6712222
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/config_test.cc
@@ -0,0 +1,202 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/config.h"
+
+static const char CONFIG_FILE[] = "/data/local/tmp/config_test.conf";
+static const char CONFIG_FILE_CONTENT[] =
+ " \n\
+first_key=value \n\
+ \n\
+# Device ID (DID) configuration \n\
+[DID] \n\
+ \n\
+# Record Number: 1, 2 or 3 - maximum of 3 records \n\
+recordNumber = 1 \n\
+ \n\
+# Primary Record - true or false (default) \n\
+# There can be only one primary record \n\
+primaryRecord = true \n\
+ \n\
+# Vendor ID '0xFFFF' indicates no Device ID Service Record is present in the device \n\
+# 0x000F = Broadcom Corporation (default) \n\
+#vendorId = 0x000F \n\
+ \n\
+# Vendor ID Source \n\
+# 0x0001 = Bluetooth SIG assigned Device ID Vendor ID value (default) \n\
+# 0x0002 = USB Implementer's Forum assigned Device ID Vendor ID value \n\
+#vendorIdSource = 0x0001 \n\
+ \n\
+# Product ID & Product Version \n\
+# Per spec DID v1.3 0xJJMN for version is interpreted as JJ.M.N \n\
+# JJ: major version number, M: minor version number, N: sub-minor version number \n\
+# For example: 1200, v14.3.6 \n\
+productId = 0x1200 \n\
+version = 0x1111 \n\
+ \n\
+# Optional attributes \n\
+#clientExecutableURL = \n\
+#serviceDescription = \n\
+#documentationURL = \n\
+ \n\
+# Additional optional DID records. Bluedroid supports up to 3 records. \n\
+[DID] \n\
+[DID] \n\
+version = 0x1436 \n\
+";
+
+class ConfigTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() {
+ AllocationTestHarness::SetUp();
+ FILE* fp = fopen(CONFIG_FILE, "wt");
+ fwrite(CONFIG_FILE_CONTENT, 1, sizeof(CONFIG_FILE_CONTENT), fp);
+ fclose(fp);
+ }
+};
+
+TEST_F(ConfigTest, config_new_empty) {
+ config_t* config = config_new_empty();
+ EXPECT_TRUE(config != NULL);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_new_no_file) {
+ config_t* config = config_new("/meow");
+ EXPECT_TRUE(config == NULL);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_new) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config != NULL);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_free_null) { config_free(NULL); }
+
+TEST_F(ConfigTest, config_new_clone) {
+ config_t* config = config_new(CONFIG_FILE);
+ config_t* clone = config_new_clone(config);
+
+ config_set_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "not_value");
+
+ EXPECT_STRNE(
+ config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "one"),
+ config_get_string(clone, CONFIG_DEFAULT_SECTION, "first_key", "one"));
+
+ config_free(config);
+ config_free(clone);
+}
+
+TEST_F(ConfigTest, config_has_section) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config_has_section(config, "DID"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_has_key_in_default_section) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config_has_key(config, CONFIG_DEFAULT_SECTION, "first_key"));
+ EXPECT_STREQ(
+ config_get_string(config, CONFIG_DEFAULT_SECTION, "first_key", "meow"),
+ "value");
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_has_keys) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config_has_key(config, "DID", "recordNumber"));
+ EXPECT_TRUE(config_has_key(config, "DID", "primaryRecord"));
+ EXPECT_TRUE(config_has_key(config, "DID", "productId"));
+ EXPECT_TRUE(config_has_key(config, "DID", "version"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_no_bad_keys) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_FALSE(config_has_key(config, "DID_BAD", "primaryRecord"));
+ EXPECT_FALSE(config_has_key(config, "DID", "primaryRecord_BAD"));
+ EXPECT_FALSE(config_has_key(config, CONFIG_DEFAULT_SECTION, "primaryRecord"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_get_int_version) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_EQ(config_get_int(config, "DID", "version", 0), 0x1436);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_get_int_default) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_EQ(config_get_int(config, "DID", "primaryRecord", 123), 123);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_section) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config_remove_section(config, "DID"));
+ EXPECT_FALSE(config_has_section(config, "DID"));
+ EXPECT_FALSE(config_has_key(config, "DID", "productId"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_section_missing) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_FALSE(config_remove_section(config, "not a section"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_key) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
+ EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
+ EXPECT_FALSE(config_has_key(config, "DID", "productId"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_remove_key_missing) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 0x1200);
+ EXPECT_TRUE(config_remove_key(config, "DID", "productId"));
+ EXPECT_EQ(config_get_int(config, "DID", "productId", 999), 999);
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_begin) {
+ config_t* config = config_new(CONFIG_FILE);
+ const config_section_node_t* section = config_section_begin(config);
+ EXPECT_TRUE(section != NULL);
+ const char* section_name = config_section_name(section);
+ EXPECT_TRUE(section != NULL);
+ EXPECT_TRUE(!strcmp(section_name, CONFIG_DEFAULT_SECTION));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_next) {
+ config_t* config = config_new(CONFIG_FILE);
+ const config_section_node_t* section = config_section_begin(config);
+ EXPECT_TRUE(section != NULL);
+ section = config_section_next(section);
+ EXPECT_TRUE(section != NULL);
+ const char* section_name = config_section_name(section);
+ EXPECT_TRUE(section != NULL);
+ EXPECT_TRUE(!strcmp(section_name, "DID"));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_section_end) {
+ config_t* config = config_new(CONFIG_FILE);
+ const config_section_node_t* section = config_section_begin(config);
+ section = config_section_next(section);
+ section = config_section_next(section);
+ EXPECT_EQ(section, config_section_end(config));
+ config_free(config);
+}
+
+TEST_F(ConfigTest, config_save_basic) {
+ config_t* config = config_new(CONFIG_FILE);
+ EXPECT_TRUE(config_save(config, CONFIG_FILE));
+ config_free(config);
+}
diff --git a/mtkbt/code/bt/osi/test/data_dispatcher_test.cc b/mtkbt/code/bt/osi/test/data_dispatcher_test.cc
new file mode 100755
index 0000000..cc7d78d
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/data_dispatcher_test.cc
@@ -0,0 +1,258 @@
+#include <gtest/gtest.h>
+
+#include <climits>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/data_dispatcher.h"
+
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+
+#define DUMMY_TYPE_0 34
+#define DUMMY_TYPE_1 42
+#define TYPE_EDGE_CASE_ZERO 0
+#define TYPE_EDGE_CASE_MAX INT_MAX
+
+#define DUMMY_QUEUE_SIZE 10
+
+class DataDispatcherTest : public AllocationTestHarness {};
+
+static char dummy_data_0[42] = "please test your code";
+static char dummy_data_1[42] = "testing is good for your sanity";
+
+TEST_F(DataDispatcherTest, test_new_free_simple) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+ ASSERT_TRUE(dispatcher != NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_nowhere) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+ EXPECT_FALSE(
+ data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_single) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ // Send data to the queue
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_multiple) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register two queues
+ fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+ // Send data to one of them
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+
+ fixed_queue_free(dummy_queue0, NULL);
+ fixed_queue_free(dummy_queue1, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_default) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register two queues, a default and a typed one
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ fixed_queue_t* default_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+ data_dispatcher_register_default(dispatcher, default_queue);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(default_queue));
+
+ // Send data to nowhere
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
+
+ // Did we get it?
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_FALSE(fixed_queue_is_empty(default_queue));
+ EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(default_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(default_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ fixed_queue_free(default_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_multiple_to_single) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ // Send data to the queue
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_1));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_multiple_to_multiple) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register two queues
+ fixed_queue_t* dummy_queue0 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ fixed_queue_t* dummy_queue1 = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue0);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_1, dummy_queue1);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+ // Send data to both of them
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_1, dummy_data_1));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue0));
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue1));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue0));
+ EXPECT_STREQ(dummy_data_1, (char*)fixed_queue_try_dequeue(dummy_queue1));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue1));
+
+ fixed_queue_free(dummy_queue0, NULL);
+ fixed_queue_free(dummy_queue1, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_single_reregistered) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue, then reregister
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ fixed_queue_t* dummy_queue_reregistered = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue_reregistered);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
+
+ // Send data to the queue
+ EXPECT_TRUE(data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+
+ // Did we get it?
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue_reregistered));
+ EXPECT_STREQ(dummy_data_0,
+ (char*)fixed_queue_try_dequeue(dummy_queue_reregistered));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue_reregistered));
+
+ fixed_queue_free(dummy_queue, NULL);
+ fixed_queue_free(dummy_queue_reregistered, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_reregistered_null) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, dummy_queue);
+ data_dispatcher_register(dispatcher, DUMMY_TYPE_0, NULL);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ EXPECT_FALSE(
+ data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_single_to_default_reregistered_null) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register_default(dispatcher, dummy_queue);
+ data_dispatcher_register_default(dispatcher, NULL);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ EXPECT_FALSE(
+ data_dispatcher_dispatch(dispatcher, DUMMY_TYPE_0, dummy_data_0));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_edge_zero) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_queue);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ // Send data to the queue
+ EXPECT_TRUE(
+ data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_ZERO, dummy_data_0));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
+
+TEST_F(DataDispatcherTest, test_dispatch_edge_max) {
+ data_dispatcher_t* dispatcher = data_dispatcher_new("test_dispatcher");
+
+ // Register a queue
+ fixed_queue_t* dummy_queue = fixed_queue_new(DUMMY_QUEUE_SIZE);
+ data_dispatcher_register(dispatcher, TYPE_EDGE_CASE_MAX, dummy_queue);
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ // Send data to the queue
+ EXPECT_TRUE(
+ data_dispatcher_dispatch(dispatcher, TYPE_EDGE_CASE_MAX, dummy_data_0));
+
+ // Did we get it?
+ EXPECT_FALSE(fixed_queue_is_empty(dummy_queue));
+ EXPECT_STREQ(dummy_data_0, (char*)fixed_queue_try_dequeue(dummy_queue));
+ EXPECT_TRUE(fixed_queue_is_empty(dummy_queue));
+
+ fixed_queue_free(dummy_queue, NULL);
+ data_dispatcher_free(dispatcher);
+}
diff --git a/mtkbt/code/bt/osi/test/fixed_queue_test.cc b/mtkbt/code/bt/osi/test/fixed_queue_test.cc
new file mode 100755
index 0000000..56917ef
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/fixed_queue_test.cc
@@ -0,0 +1,350 @@
+#include <gtest/gtest.h>
+
+#include <climits>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/allocator.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+static const size_t TEST_QUEUE_SIZE = 10;
+static const char* DUMMY_DATA_STRING = "Dummy data string";
+static const char* DUMMY_DATA_STRING1 = "Dummy data string1";
+static const char* DUMMY_DATA_STRING2 = "Dummy data string2";
+static const char* DUMMY_DATA_STRING3 = "Dummy data string3";
+static future_t* received_message_future = NULL;
+
+static int test_queue_entry_free_counter = 0;
+
+// Test whether a file descriptor |fd| is readable.
+// Return true if the file descriptor is readable, otherwise false.
+static bool is_fd_readable(int fd) {
+ fd_set rfds;
+ struct timeval tv;
+
+ FD_ZERO(&rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_SET(fd, &rfds);
+ // Only the enqueue_fd should be readable
+ int result = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
+ EXPECT_TRUE(result >= 0);
+
+ return FD_ISSET(fd, &rfds);
+}
+
+// Function for performing dequeue operations from the queue when is ready
+static void fixed_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+ void* msg = fixed_queue_try_dequeue(queue);
+ EXPECT_TRUE(msg != NULL);
+ future_ready(received_message_future, msg);
+}
+
+static void test_queue_entry_free_cb(void* data) {
+ // Don't free the data, because we are testing only whether the callback
+ // is called.
+ test_queue_entry_free_counter++;
+}
+
+class FixedQueueTest : public AllocationTestHarness {};
+
+TEST_F(FixedQueueTest, test_fixed_queue_new_free) {
+ fixed_queue_t* queue;
+
+ // Test a corner case: queue of size 0
+ queue = fixed_queue_new(0);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_free(queue, NULL);
+
+ // Test a corner case: queue of size 1
+ queue = fixed_queue_new(1);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_free(queue, NULL);
+
+ // Test a corner case: queue of maximum size
+ queue = fixed_queue_new((size_t)-1);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_free(queue, NULL);
+
+ // Test a queue of some size
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_free(queue, NULL);
+
+ // Test free-ing a NULL queue
+ fixed_queue_free(NULL, NULL);
+ fixed_queue_free(NULL, osi_free);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_flush) {
+ fixed_queue_t* queue;
+
+ // Test a corner case: queue of size 0 and no callback to free entries
+ queue = fixed_queue_new(0);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_flush(queue, NULL);
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+ fixed_queue_free(queue, osi_free);
+
+ // Test a corner case: queue of size 0 and a callback to free entries
+ queue = fixed_queue_new(0);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_flush(queue, osi_free);
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+ fixed_queue_free(queue, osi_free);
+
+ // Test a queue of some size and no callback to free entries
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+ EXPECT_FALSE(fixed_queue_is_empty(queue));
+ fixed_queue_flush(queue, NULL);
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+ fixed_queue_free(queue, osi_free);
+
+ // Test a queue of some size and a callback to free entries
+ test_queue_entry_free_counter = 0;
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ EXPECT_TRUE(queue != NULL);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+ EXPECT_FALSE(fixed_queue_is_empty(queue));
+ fixed_queue_flush(queue, test_queue_entry_free_cb);
+ EXPECT_TRUE(test_queue_entry_free_counter == 3);
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+ fixed_queue_free(queue, osi_free);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_is_empty) {
+ fixed_queue_t* queue;
+
+ // Test a NULL queue
+ EXPECT_TRUE(fixed_queue_is_empty(NULL));
+
+ // Test an empty queue
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+
+ // Test a non-empty queue
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
+ EXPECT_FALSE(fixed_queue_is_empty(queue));
+
+ // Test an empty dequeued queue
+ ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+ EXPECT_TRUE(fixed_queue_is_empty(queue));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_length) {
+ fixed_queue_t* queue;
+
+ // Test a NULL queue
+ EXPECT_EQ((size_t)0, fixed_queue_length(NULL));
+
+ // Test an empty queue
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+ // Test a non-empty queue
+ fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING);
+ EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+
+ // Test an empty dequeued queue
+ ASSERT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+ EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_capacity) {
+ fixed_queue_t* queue;
+
+ // Test a corner case: queue of size 0
+ queue = fixed_queue_new(0);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_EQ((size_t)0, fixed_queue_capacity(queue));
+ fixed_queue_free(queue, NULL);
+
+ // Test a corner case: queue of size 1
+ queue = fixed_queue_new(1);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_EQ((size_t)1, fixed_queue_capacity(queue));
+ fixed_queue_free(queue, NULL);
+
+ // Test a corner case: queue of maximum size
+ queue = fixed_queue_new((size_t)-1);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_EQ((size_t)-1, fixed_queue_capacity(queue));
+ fixed_queue_free(queue, NULL);
+
+ // Test a queue of some size
+ queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+ EXPECT_EQ(TEST_QUEUE_SIZE, fixed_queue_capacity(queue));
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_enqueue_dequeue) {
+ fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+
+ // Test blocking enqueue and blocking dequeue
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+ EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_dequeue(queue));
+ EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+ // Test non-blocking enqueue and non-blocking dequeue
+ EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+ EXPECT_EQ((size_t)1, fixed_queue_length(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+ EXPECT_EQ((size_t)0, fixed_queue_length(queue));
+
+ // Test non-blocking enqueue beyond queue capacity
+ for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+ EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+ }
+ // The next enqueue operation is beyond the queue capacity, so it should fail
+ EXPECT_FALSE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+
+ // Test non-blocking dequeue from a queue that is full to max capacity
+ for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+ EXPECT_EQ(DUMMY_DATA_STRING, fixed_queue_try_dequeue(queue));
+ }
+
+ // Test non-blocking dequeue from an empty queue
+ EXPECT_EQ(NULL, fixed_queue_try_dequeue(queue));
+
+ // Test non-blocking dequeue from a NULL queue
+ EXPECT_EQ(NULL, fixed_queue_try_dequeue(NULL));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_try_peek_first_last) {
+ fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+
+ // Test peek first/last from a NULL queue
+ EXPECT_EQ(NULL, fixed_queue_try_peek_first(NULL));
+ EXPECT_EQ(NULL, fixed_queue_try_peek_last(NULL));
+
+ // Test peek first/last from an empty queue
+ EXPECT_EQ(NULL, fixed_queue_try_peek_first(queue));
+ EXPECT_EQ(NULL, fixed_queue_try_peek_last(queue));
+
+ // Test peek first/last from a queue with one element
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+ EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_last(queue));
+
+ // Test peek first/last from a queue with two elements
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+ EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_peek_last(queue));
+
+ // Test peek first/last from a queue with three elements
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+ EXPECT_EQ(DUMMY_DATA_STRING1, fixed_queue_try_peek_first(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING3, fixed_queue_try_peek_last(queue));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_try_remove_from_queue) {
+ fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+
+ // Test removing from a NULL queue
+ EXPECT_EQ(NULL,
+ fixed_queue_try_remove_from_queue(NULL, (void*)DUMMY_DATA_STRING));
+
+ // Test removing from an empty queue
+ EXPECT_EQ(NULL,
+ fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
+
+ // Test removing a queued string from a queue
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING1);
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING2);
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING3);
+ EXPECT_EQ((size_t)3, fixed_queue_length(queue));
+ EXPECT_EQ(DUMMY_DATA_STRING2, fixed_queue_try_remove_from_queue(
+ queue, (void*)DUMMY_DATA_STRING2));
+ EXPECT_EQ((size_t)2, fixed_queue_length(queue));
+ // Removing again should fail
+ EXPECT_EQ(NULL, fixed_queue_try_remove_from_queue(queue,
+ (void*)DUMMY_DATA_STRING2));
+
+ // Test removing a non-queued string from a queue
+ EXPECT_EQ(NULL,
+ fixed_queue_try_remove_from_queue(queue, (void*)DUMMY_DATA_STRING));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_get_enqueue_dequeue_fd) {
+ fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+
+ // Test validity of enqueue and dequeue file descriptors
+ int enqueue_fd = fixed_queue_get_enqueue_fd(queue);
+ int dequeue_fd = fixed_queue_get_dequeue_fd(queue);
+ EXPECT_TRUE(enqueue_fd >= 0);
+ EXPECT_TRUE(dequeue_fd >= 0);
+ EXPECT_TRUE(enqueue_fd < FD_SETSIZE);
+ EXPECT_TRUE(dequeue_fd < FD_SETSIZE);
+
+ // Test the file descriptors of an empty queue
+ // Only the enqueue_fd should be readable
+ EXPECT_TRUE(is_fd_readable(enqueue_fd));
+ EXPECT_FALSE(is_fd_readable(dequeue_fd));
+
+ // Test the file descriptors of a non-empty queue
+ // Both the enqueue_fd and dequeue_fd should be readable
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+ EXPECT_TRUE(is_fd_readable(enqueue_fd));
+ EXPECT_TRUE(is_fd_readable(dequeue_fd));
+ fixed_queue_dequeue(queue);
+
+ // Test the file descriptors of a full queue
+ // Only the dequeue_fd should be readable
+ for (size_t i = 0; i < TEST_QUEUE_SIZE; i++) {
+ EXPECT_TRUE(fixed_queue_try_enqueue(queue, (void*)DUMMY_DATA_STRING));
+ }
+ EXPECT_FALSE(is_fd_readable(enqueue_fd));
+ EXPECT_TRUE(is_fd_readable(dequeue_fd));
+
+ fixed_queue_free(queue, NULL);
+}
+
+TEST_F(FixedQueueTest, test_fixed_queue_register_dequeue) {
+ fixed_queue_t* queue = fixed_queue_new(TEST_QUEUE_SIZE);
+ ASSERT_TRUE(queue != NULL);
+
+ received_message_future = future_new();
+ ASSERT_TRUE(received_message_future != NULL);
+
+ thread_t* worker_thread = thread_new("test_fixed_queue_worker_thread");
+ ASSERT_TRUE(worker_thread != NULL);
+
+ fixed_queue_register_dequeue(queue, thread_get_reactor(worker_thread),
+ fixed_queue_ready, NULL);
+
+ // Add a message to the queue, and expect to receive it
+ fixed_queue_enqueue(queue, (void*)DUMMY_DATA_STRING);
+ const char* msg = (const char*)future_await(received_message_future);
+ EXPECT_EQ(DUMMY_DATA_STRING, msg);
+
+ fixed_queue_unregister_dequeue(queue);
+ thread_free(worker_thread);
+ fixed_queue_free(queue, NULL);
+}
diff --git a/mtkbt/code/bt/osi/test/future_test.cc b/mtkbt/code/bt/osi/test/future_test.cc
new file mode 100755
index 0000000..fe5e7fd
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/future_test.cc
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/future.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+static const char* pass_back_data0 = "fancy a sandwich? it's a fancy sandwich";
+static const char* pass_back_data1 =
+ "what kind of ice cream truck plays the worst christmas song of all time?";
+
+class FutureTest : public AllocationTestHarness {};
+
+static void post_to_future(void* context) {
+ future_ready((future_t*)context, (void*)pass_back_data0);
+}
+
+TEST_F(FutureTest, test_future_non_immediate) {
+ future_t* future = future_new();
+ ASSERT_TRUE(future != NULL);
+
+ thread_t* worker_thread = thread_new("worker thread");
+ thread_post(worker_thread, post_to_future, future);
+
+ EXPECT_EQ(pass_back_data0, future_await(future));
+
+ thread_free(worker_thread);
+}
+
+TEST_F(FutureTest, test_future_immediate) {
+ future_t* future = future_new_immediate((void*)pass_back_data1);
+ ASSERT_TRUE(future != NULL);
+ EXPECT_EQ(pass_back_data1, future_await(future));
+}
diff --git a/mtkbt/code/bt/osi/test/hash_map_utils_test.cc b/mtkbt/code/bt/osi/test/hash_map_utils_test.cc
new file mode 100755
index 0000000..0e483e5
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/hash_map_utils_test.cc
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/hash_map_utils.h"
+
+#include "osi/include/allocator.h"
+
+class HashMapUtilsTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() { AllocationTestHarness::SetUp(); }
+ virtual void TearDown() {
+ map.clear();
+ AllocationTestHarness::TearDown();
+ }
+
+ std::unordered_map<std::string, std::string> map;
+};
+
+TEST_F(HashMapUtilsTest, test_empty_string_params) {
+ char params[] = "";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_semicolons) {
+ char params[] = ";;;";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_equal_sign_in_value) {
+ char params[] = "keyOfSomething=value=OfSomething";
+ char key[] = "keyOfSomething";
+ char value[] = "value=OfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(value, map[key]);
+ map.clear();
+}
+
+TEST_F(HashMapUtilsTest, test_two_pairs_with_same_key) {
+ char params[] = "key=valu0;key=value1";
+ char key[] = "key";
+ char value1[] = "value1";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(value1, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_without_semicolon) {
+ char params[] = "keyOfSomething=valueOfSomething";
+ char key[] = "keyOfSomething";
+ char value[] = "valueOfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_key_value_pair_with_semicolon) {
+ char params[] = "keyOfSomething=valueOfSomething;";
+ char key[] = "keyOfSomething";
+ char value[] = "valueOfSomething";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_value) {
+ char params[] = "keyOfSomething=;";
+ char key[] = "keyOfSomething";
+ char value[] = "";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(1u, map.size());
+ EXPECT_EQ(value, map[key]);
+}
+
+TEST_F(HashMapUtilsTest, test_one_pair_with_empty_key) {
+ char params[] = "=valueOfSomething;";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_TRUE(map.empty());
+}
+
+TEST_F(HashMapUtilsTest, test_two_key_value_pairs) {
+ char params[] = "key0=value0;key1=value1;";
+ char key0[] = "key0";
+ char value0[] = "value0";
+ char key1[] = "key1";
+ char value1[] = "value1";
+ map = hash_map_utils_new_from_string_params(params);
+ EXPECT_EQ(2u, map.size());
+ EXPECT_EQ(value0, map[key0]);
+ EXPECT_EQ(value1, map[key1]);
+}
diff --git a/mtkbt/code/bt/osi/test/leaky_bonded_queue_test.cc b/mtkbt/code/bt/osi/test/leaky_bonded_queue_test.cc
new file mode 100755
index 0000000..c538101
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/leaky_bonded_queue_test.cc
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "osi/include/leaky_bonded_queue.h"
+
+namespace testing {
+
+using system_bt_osi::LeakyBondedQueue;
+
+#define ITEM_EQ(a, b) \
+ do { \
+ EXPECT_EQ(a, b); \
+ EXPECT_EQ(a->index, b->index); \
+ } while (0)
+
+class Item {
+ public:
+ Item(int i) { index = i; }
+ virtual ~Item() {}
+ int index;
+};
+
+class MockItem : public Item {
+ public:
+ MockItem(int i) : Item(i) {}
+ ~MockItem() { Destruct(); }
+ MOCK_METHOD0(Destruct, void());
+};
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(3);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(3));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(3));
+ MockItem* item2_2 = queue->Dequeue();
+ MockItem* item3_3 = queue->Dequeue();
+ MockItem* item4_4 = queue->Dequeue();
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_THAT(item4_4, NotNull());
+ ITEM_EQ(item4_4, item4);
+ LOG(INFO) << "All done release items";
+ EXPECT_CALL(*item2_2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_CALL(*item3_3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_CALL(*item4_4, Destruct()).Times(1);
+ delete item4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueueDequeue2) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestEnqueuePop) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item2_2 = queue->EnqueueWithPop(item4);
+ EXPECT_THAT(item2_2, NotNull());
+ ITEM_EQ(item2_2, item2);
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ delete item2_2;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item3_3 = queue->EnqueueWithPop(item1);
+ EXPECT_THAT(item3_3, NotNull());
+ ITEM_EQ(item3_3, item3);
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ delete item3_3;
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ MockItem* item4_4_4 = queue->Dequeue();
+ MockItem* item1_1_1 = queue->Dequeue();
+ ITEM_EQ(item4_4_4, item4);
+ ITEM_EQ(item1_1_1, item1);
+ EXPECT_CALL(*item1_1_1, Destruct()).Times(1);
+ delete item1_1_1;
+ EXPECT_CALL(*item4_4_4, Destruct()).Times(1);
+ delete item4_4_4;
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueClear) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ queue->Clear();
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestQueueFree) {
+ MockItem* item1 = new MockItem(1);
+ MockItem* item2 = new MockItem(2);
+ MockItem* item3 = new MockItem(3);
+ MockItem* item4 = new MockItem(4);
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ EXPECT_EQ(queue->Capacity(), static_cast<size_t>(2));
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ MockItem* item1_1 = queue->Dequeue();
+ ITEM_EQ(item1, item1_1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(0));
+ queue->Enqueue(item2);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(1));
+ queue->Enqueue(item3);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item2, Destruct()).Times(1);
+ queue->Enqueue(item4);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item3, Destruct()).Times(1);
+ queue->Enqueue(item1);
+ EXPECT_EQ(queue->Length(), static_cast<size_t>(2));
+ EXPECT_CALL(*item1, Destruct()).Times(1);
+ EXPECT_CALL(*item4, Destruct()).Times(1);
+ delete queue;
+}
+
+TEST(LeakyBondedQueueTest, TestPushNull) {
+ MockItem* item1 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ MockItem* item1_1 = queue->Dequeue();
+ EXPECT_THAT(item1_1, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullOverflowQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(1);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ MockItem* item2_2 = queue->Dequeue();
+ EXPECT_THAT(item2_2, IsNull());
+}
+
+TEST(LeakyBondedQueueTest, TestPushNullDeleteQueue) {
+ MockItem* item1 = nullptr;
+ MockItem* item2 = nullptr;
+ LeakyBondedQueue<MockItem>* queue = new LeakyBondedQueue<MockItem>(2);
+ queue->Enqueue(item1);
+ queue->Enqueue(item2);
+ delete queue;
+}
+}
diff --git a/mtkbt/code/bt/osi/test/list_test.cc b/mtkbt/code/bt/osi/test/list_test.cc
new file mode 100755
index 0000000..d5a438f
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/list_test.cc
@@ -0,0 +1,211 @@
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/list.h"
+#include "osi/include/osi.h"
+
+class ListTest : public AllocationTestHarness {};
+
+TEST_F(ListTest, test_new_free_simple) {
+ list_t* list = list_new(NULL);
+ ASSERT_TRUE(list != NULL);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_free_null) {
+ // In this test we just verify that list_free is callable with NULL.
+ list_free(NULL);
+}
+
+TEST_F(ListTest, test_empty_list_is_empty) {
+ list_t* list = list_new(NULL);
+ EXPECT_TRUE(list_is_empty(list));
+ list_free(list);
+}
+
+TEST_F(ListTest, test_empty_list_has_no_length) {
+ list_t* list = list_new(NULL);
+ EXPECT_EQ(list_length(list), 0U);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_simple_list_prepend) {
+ list_t* list = list_new(NULL);
+ EXPECT_TRUE(list_prepend(list, &list));
+ EXPECT_FALSE(list_is_empty(list));
+ EXPECT_EQ(list_length(list), 1U);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_simple_list_append) {
+ list_t* list = list_new(NULL);
+ EXPECT_TRUE(list_append(list, &list));
+ EXPECT_FALSE(list_is_empty(list));
+ EXPECT_EQ(list_length(list), 1U);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_remove_found) {
+ list_t* list = list_new(NULL);
+ list_append(list, &list);
+ EXPECT_TRUE(list_remove(list, &list));
+ EXPECT_TRUE(list_is_empty(list));
+ EXPECT_EQ(list_length(list), 0U);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_remove_not_found) {
+ int x;
+ list_t* list = list_new(NULL);
+ list_append(list, &list);
+ EXPECT_FALSE(list_remove(list, &x));
+ EXPECT_FALSE(list_is_empty(list));
+ EXPECT_EQ(list_length(list), 1U);
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_front) {
+ int x[] = {1, 2, 3, 4, 5};
+ list_t* list = list_new(NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+ EXPECT_EQ(list_front(list), &x[0]);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_back) {
+ int x[] = {1, 2, 3, 4, 5};
+ list_t* list = list_new(NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+ EXPECT_EQ(list_back(list), &x[ARRAY_SIZE(x) - 1]);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_clear) {
+ int x[] = {1, 2, 3, 4, 5};
+ list_t* list = list_new(NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+ list_clear(list);
+ EXPECT_TRUE(list_is_empty(list));
+ EXPECT_EQ(list_length(list), 0U);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_append_multiple) {
+ int x[] = {1, 2, 3, 4, 5};
+ list_t* list = list_new(NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+
+ int i = 0;
+ for (const list_node_t *node = list_begin(list); node != list_end(list);
+ node = list_next(node), ++i)
+ EXPECT_EQ(list_node(node), &x[i]);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_prepend_multiple) {
+ int x[] = {1, 2, 3, 4, 5};
+ list_t* list = list_new(NULL);
+
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_prepend(list, &x[i]);
+
+ int i = ARRAY_SIZE(x) - 1;
+ for (const list_node_t *node = list_begin(list); node != list_end(list);
+ node = list_next(node), --i)
+ EXPECT_EQ(list_node(node), &x[i]);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_begin_empty_list) {
+ list_t* list = list_new(NULL);
+ EXPECT_EQ(list_begin(list), list_end(list));
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_next) {
+ list_t* list = list_new(NULL);
+ list_append(list, &list);
+ EXPECT_NE(list_begin(list), list_end(list));
+ EXPECT_EQ(list_next(list_begin(list)), list_end(list));
+ list_free(list);
+}
+
+static bool list_callback_sum(void* data, void* context) {
+ CHECK(data);
+ CHECK(context);
+ int* sum = (int*)context;
+ int* value = (int*)data;
+ *sum += *value;
+ return true;
+}
+
+static bool list_callback_find_int(void* data, void* context) {
+ CHECK(data);
+ CHECK(context);
+ return (*(int*)data != *(int*)context);
+}
+
+TEST_F(ListTest, test_list_foreach_full) {
+ list_t* list = list_new(NULL);
+
+ // Fill in test data
+ int x[] = {1, 2, 3, 4, 5};
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+ EXPECT_EQ(list_length(list), (size_t)5);
+
+ // Test complete iteration
+ int sum = 0;
+ list_node_t* rc = list_foreach(list, list_callback_sum, &sum);
+ EXPECT_EQ(sum, 15);
+ EXPECT_TRUE(rc == NULL);
+
+ list_free(list);
+}
+
+TEST_F(ListTest, test_list_foreach_partial) {
+ list_t* list = list_new(NULL);
+
+ // Fill in test data
+ int x[] = {1, 2, 3, 4, 5};
+ for (size_t i = 0; i < ARRAY_SIZE(x); ++i) list_append(list, &x[i]);
+ EXPECT_EQ(list_length(list), (size_t)5);
+
+ // Test partial iteration
+ int find = 4;
+ list_node_t* rc = list_foreach(list, list_callback_find_int, &find);
+ EXPECT_TRUE(rc != NULL);
+ int* rc_val = (int*)list_node(rc);
+ EXPECT_TRUE(*rc_val == 4);
+
+ find = 1;
+ rc = list_foreach(list, list_callback_find_int, &find);
+ EXPECT_TRUE(rc != NULL);
+ rc_val = (int*)list_node(rc);
+ EXPECT_TRUE(*rc_val == 1);
+
+ find = 5;
+ rc = list_foreach(list, list_callback_find_int, &find);
+ EXPECT_TRUE(rc != NULL);
+ rc_val = (int*)list_node(rc);
+ EXPECT_TRUE(*rc_val == 5);
+
+ find = 0;
+ rc = list_foreach(list, list_callback_find_int, &find);
+ EXPECT_TRUE(rc == NULL);
+
+ list_free(list);
+}
diff --git a/mtkbt/code/bt/osi/test/metrics_test.cc b/mtkbt/code/bt/osi/test/metrics_test.cc
new file mode 100755
index 0000000..a8de2fc
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/metrics_test.cc
@@ -0,0 +1,802 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+
+#include "osi/include/metrics.h"
+#include "osi/include/time.h"
+#include "src/protos/bluetooth.pb.h"
+
+#define BTM_COD_MAJOR_AUDIO_TEST 0x04
+
+namespace testing {
+
+using clearcut::connectivity::A2DPSession;
+using clearcut::connectivity::BluetoothLog;
+using clearcut::connectivity::BluetoothSession;
+using clearcut::connectivity::BluetoothSession_ConnectionTechnologyType;
+using clearcut::connectivity::BluetoothSession_DisconnectReasonType;
+using clearcut::connectivity::DeviceInfo;
+using clearcut::connectivity::DeviceInfo_DeviceType;
+using clearcut::connectivity::PairEvent;
+using clearcut::connectivity::RFCommSession;
+using clearcut::connectivity::ScanEvent;
+using clearcut::connectivity::ScanEvent_ScanTechnologyType;
+using clearcut::connectivity::ScanEvent_ScanEventType;
+using clearcut::connectivity::WakeEvent;
+using clearcut::connectivity::WakeEvent_WakeEventType;
+using system_bt_osi::BluetoothMetricsLogger;
+using system_bt_osi::A2dpSessionMetrics;
+
+namespace {
+const size_t kMaxEventGenerationLimit = 5000;
+}
+
+/*
+ * Get current OS boot time in ms
+ */
+static int64_t time_get_os_boottime_ms(void) {
+ return time_get_os_boottime_us() / 1000;
+}
+
+static void sleep_ms(int64_t t) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(t));
+}
+
+DeviceInfo* MakeDeviceInfo(int32_t device_class,
+ DeviceInfo_DeviceType device_type) {
+ DeviceInfo* info = new DeviceInfo();
+ info->set_device_class(device_class);
+ info->set_device_type(device_type);
+ return info;
+}
+
+PairEvent* MakePairEvent(int32_t disconnect_reason, int64_t timestamp_ms,
+ DeviceInfo* device_info) {
+ PairEvent* event = new PairEvent();
+ event->set_disconnect_reason(disconnect_reason);
+ event->set_event_time_millis(timestamp_ms);
+ if (device_info) event->set_allocated_device_paired_with(device_info);
+ return event;
+}
+
+WakeEvent* MakeWakeEvent(WakeEvent_WakeEventType event_type,
+ const std::string& requestor, const std::string& name,
+ int64_t timestamp_ms) {
+ WakeEvent* event = new WakeEvent();
+ event->set_wake_event_type(event_type);
+ event->set_requestor(requestor);
+ event->set_name(name);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+ScanEvent* MakeScanEvent(ScanEvent_ScanEventType event_type,
+ const std::string& initiator,
+ ScanEvent_ScanTechnologyType tech_type,
+ int32_t num_results, int64_t timestamp_ms) {
+ ScanEvent* event = new ScanEvent();
+ event->set_scan_event_type(event_type);
+ event->set_initiator(initiator);
+ event->set_scan_technology_type(tech_type);
+ event->set_number_results(num_results);
+ event->set_event_time_millis(timestamp_ms);
+ return event;
+}
+
+A2DPSession* MakeA2DPSession(const A2dpSessionMetrics& metrics) {
+ A2DPSession* session = new A2DPSession();
+ session->set_media_timer_min_millis(metrics.media_timer_min_ms);
+ session->set_media_timer_max_millis(metrics.media_timer_max_ms);
+ session->set_media_timer_avg_millis(metrics.media_timer_avg_ms);
+ session->set_buffer_overruns_max_count(metrics.buffer_overruns_max_count);
+ session->set_buffer_overruns_total(metrics.buffer_overruns_total);
+ session->set_buffer_underruns_average(metrics.buffer_underruns_average);
+ session->set_buffer_underruns_count(metrics.buffer_underruns_count);
+ session->set_audio_duration_millis(metrics.audio_duration_ms);
+ return session;
+}
+
+BluetoothSession* MakeBluetoothSession(
+ int64_t session_duration_sec,
+ BluetoothSession_ConnectionTechnologyType conn_type,
+ BluetoothSession_DisconnectReasonType disconnect_reason,
+ DeviceInfo* device_info, RFCommSession* rfcomm_session,
+ A2DPSession* a2dp_session) {
+ BluetoothSession* session = new BluetoothSession();
+ if (a2dp_session) session->set_allocated_a2dp_session(a2dp_session);
+ if (rfcomm_session) session->set_allocated_rfcomm_session(rfcomm_session);
+ if (device_info) session->set_allocated_device_connected_to(device_info);
+ session->set_session_duration_sec(session_duration_sec);
+ session->set_connection_technology_type(conn_type);
+ session->set_disconnect_reason_type(disconnect_reason);
+ return session;
+}
+
+BluetoothLog* MakeBluetoothLog(std::vector<BluetoothSession*> bt_sessions,
+ std::vector<PairEvent*> pair_events,
+ std::vector<WakeEvent*> wake_events,
+ std::vector<ScanEvent*> scan_events) {
+ BluetoothLog* bt_log = new BluetoothLog();
+ for (BluetoothSession* session : bt_sessions) {
+ bt_log->mutable_session()->AddAllocated(session);
+ }
+ bt_sessions.clear();
+ for (PairEvent* event : pair_events) {
+ bt_log->mutable_pair_event()->AddAllocated(event);
+ }
+ pair_events.clear();
+ for (WakeEvent* event : wake_events) {
+ bt_log->mutable_wake_event()->AddAllocated(event);
+ }
+ wake_events.clear();
+ for (ScanEvent* event : scan_events) {
+ bt_log->mutable_scan_event()->AddAllocated(event);
+ }
+ scan_events.clear();
+ return bt_log;
+}
+
+void GenerateWakeEvents(size_t start, size_t end,
+ std::vector<WakeEvent*>* wake_events) {
+ for (size_t i = start; i < end; ++i) {
+ wake_events->push_back(MakeWakeEvent(
+ i % 2 == 0 ? WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED
+ : WakeEvent_WakeEventType::WakeEvent_WakeEventType_RELEASED,
+ "TEST_REQ", "TEST_NAME", i));
+ }
+}
+
+#define COMPARE_A2DP_METRICS(a, b) \
+ do { \
+ EXPECT_EQ(a.audio_duration_ms, b.audio_duration_ms); \
+ EXPECT_EQ(a.media_timer_min_ms, b.media_timer_min_ms); \
+ EXPECT_EQ(a.media_timer_max_ms, b.media_timer_max_ms); \
+ EXPECT_EQ(a.media_timer_avg_ms, b.media_timer_avg_ms); \
+ EXPECT_EQ(a.total_scheduling_count, b.total_scheduling_count); \
+ EXPECT_EQ(a.buffer_overruns_max_count, b.buffer_overruns_max_count); \
+ EXPECT_EQ(a.buffer_overruns_total, b.buffer_overruns_total); \
+ EXPECT_THAT(a.buffer_underruns_average, \
+ FloatNear(b.buffer_underruns_average, 0.01)); \
+ a.buffer_underruns_average = b.buffer_underruns_average; \
+ EXPECT_EQ(a.buffer_underruns_count, b.buffer_underruns_count); \
+ } while (0)
+
+/*
+ * metrics_sum = metrics1 + metrics2
+ */
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNormal) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestUpdateNew) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestNullUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 25;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 25;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 100;
+ metrics_sum.total_scheduling_count = 50;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 130;
+ metrics_sum.buffer_underruns_count = 2400;
+ metrics2.Update(metrics1);
+ COMPARE_A2DP_METRICS(metrics2, metrics_sum);
+ EXPECT_TRUE(metrics2 == metrics_sum);
+ EXPECT_EQ(metrics2, metrics_sum);
+}
+
+TEST(BluetoothA2DPSessionMetricsTest, TestPartialUpdate) {
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics_sum.media_timer_max_ms = 100;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics_sum.media_timer_avg_ms = 50;
+ metrics_sum.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics_sum.buffer_overruns_max_count = 70;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 80;
+ metrics_sum.buffer_underruns_count = 1200;
+ metrics1.Update(metrics2);
+ COMPARE_A2DP_METRICS(metrics1, metrics_sum);
+ EXPECT_TRUE(metrics1 == metrics_sum);
+ EXPECT_EQ(metrics1, metrics_sum);
+}
+
+class BluetoothMetricsLoggerTest : public Test {
+ protected:
+ // Use to hold test protos
+ std::vector<PairEvent*> pair_events_;
+ std::vector<WakeEvent*> wake_events_;
+ std::vector<ScanEvent*> scan_events_;
+ std::vector<BluetoothSession*> bt_sessions_;
+ int64_t num_pair_event_ = 0;
+ int64_t num_wake_event_ = 0;
+ int64_t num_scan_event_ = 0;
+ int64_t num_bt_session_ = 0;
+ BluetoothLog* bt_log_;
+ std::string bt_log_str_;
+ std::string bt_log_ascii_str_;
+
+ void UpdateLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ bt_log_->mutable_session()->AddAllocated(session);
+ }
+ if (num_bt_session_ > 0) {
+ bt_log_->set_num_bluetooth_session(num_bt_session_);
+ } else if (bt_sessions_.size() > 0) {
+ bt_log_->set_num_bluetooth_session(bt_sessions_.size());
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ bt_log_->mutable_pair_event()->AddAllocated(event);
+ }
+ if (num_pair_event_ > 0) {
+ bt_log_->set_num_pair_event(num_pair_event_);
+ } else if (pair_events_.size() > 0) {
+ bt_log_->set_num_pair_event(pair_events_.size());
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ bt_log_->mutable_wake_event()->AddAllocated(event);
+ }
+ if (num_wake_event_ > 0) {
+ bt_log_->set_num_wake_event(num_wake_event_);
+ } else if (wake_events_.size() > 0) {
+ bt_log_->set_num_wake_event(wake_events_.size());
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ bt_log_->mutable_scan_event()->AddAllocated(event);
+ }
+ if (num_scan_event_ > 0) {
+ bt_log_->set_num_scan_event(num_scan_event_);
+ } else if (scan_events_.size() > 0) {
+ bt_log_->set_num_scan_event(scan_events_.size());
+ }
+ scan_events_.clear();
+ bt_log_->SerializeToString(&bt_log_str_);
+ }
+
+ void ClearLog() {
+ for (BluetoothSession* session : bt_sessions_) {
+ session->Clear();
+ delete session;
+ }
+ bt_sessions_.clear();
+ for (PairEvent* event : pair_events_) {
+ event->Clear();
+ delete event;
+ }
+ pair_events_.clear();
+ for (WakeEvent* event : wake_events_) {
+ event->Clear();
+ delete event;
+ }
+ wake_events_.clear();
+ for (ScanEvent* event : scan_events_) {
+ event->Clear();
+ delete event;
+ }
+ scan_events_.clear();
+ bt_log_->Clear();
+ }
+
+ void SetUp() {
+ bt_log_ = new BluetoothLog();
+ // Clear existing metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ }
+ void TearDown() {
+ // Clear remaining metrics entries, if any
+ BluetoothMetricsLogger::GetInstance()->Reset();
+ ClearLog();
+ delete bt_log_;
+ }
+
+ public:
+};
+
+TEST_F(BluetoothMetricsLoggerTest, PairEventTest) {
+ pair_events_.push_back(MakePairEvent(
+ 35, 12345,
+ MakeDeviceInfo(
+ 42, DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR)));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogPairEvent(
+ 35, 12345, 42, system_bt_osi::DEVICE_TYPE_BREDR);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventTest) {
+ wake_events_.push_back(
+ MakeWakeEvent(WakeEvent_WakeEventType::WakeEvent_WakeEventType_ACQUIRED,
+ "TEST_REQ", "TEST_NAME", 12345));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ system_bt_osi::WAKE_EVENT_ACQUIRED, "TEST_REQ", "TEST_NAME", 12345);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, WakeEventOverrunTest) {
+ GenerateWakeEvents(
+ kMaxEventGenerationLimit - BluetoothMetricsLogger::kMaxNumWakeEvent,
+ kMaxEventGenerationLimit, &wake_events_);
+ num_wake_event_ = kMaxEventGenerationLimit;
+ UpdateLog();
+ for (size_t i = 0; i < kMaxEventGenerationLimit; ++i) {
+ BluetoothMetricsLogger::GetInstance()->LogWakeEvent(
+ i % 2 == 0 ? system_bt_osi::WAKE_EVENT_ACQUIRED
+ : system_bt_osi::WAKE_EVENT_RELEASED,
+ "TEST_REQ", "TEST_NAME", i);
+ }
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, ScanEventTest) {
+ scan_events_.push_back(MakeScanEvent(
+ ScanEvent_ScanEventType::ScanEvent_ScanEventType_SCAN_EVENT_STOP,
+ "TEST_INITIATOR", ScanEvent_ScanTechnologyType::
+ ScanEvent_ScanTechnologyType_SCAN_TECH_TYPE_BREDR,
+ 42, 123456));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogScanEvent(
+ false, "TEST_INITIATOR", system_bt_osi::SCAN_TECH_TYPE_BREDR, 42, 123456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionDumpBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, time_get_os_boottime_ms());
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+TEST_F(BluetoothMetricsLoggerTest, BluetoothSessionStartBeforeEndTest) {
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_UNKNOWN,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_NEXT_START_WITHOUT_END_PREVIOUS,
+ nullptr, nullptr, nullptr));
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 2,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_LE,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ nullptr, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_UNKNOWN, 0);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_LE, 0);
+ sleep_ms(2000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. LogA2dpSession
+ * 6. LogBluetoothSessionEnd
+ * 7. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 10,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 123456);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 133456);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionTwoUpdatesSeparatedbyDumpTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogBluetoothSessionEnd
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionTwoUpdatesSeparatedbyDumpTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics1);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ session = MakeA2DPSession(metrics2);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case 1: A2DPSessionOnlyTest
+ *
+ * 1. Create Instance
+ * 4. LogA2dpSession
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 8. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionOnlyTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+
+/*
+ * Test Case: A2DPSessionDumpBeforeTwoUpdatesTest
+ *
+ * 1. Create Instance
+ * 2. LogBluetoothSessionStart
+ * 3. LogBluetoothSessionDeviceInfo
+ * 5. WriteString
+ * 6. LogA2dpSession
+ * 7. LogA2dpSession
+ * 8. LogBluetoothSessionEnd
+ * 9. WriteString
+ *
+ */
+TEST_F(BluetoothMetricsLoggerTest, A2DPSessionDumpBeforeTwoUpdatesTest) {
+ /* Same metrics from BluetoothA2DPSessionMetricsTest.TestUpdateNormal */
+ A2dpSessionMetrics metrics1;
+ A2dpSessionMetrics metrics2;
+ A2dpSessionMetrics metrics_sum;
+ metrics1.audio_duration_ms = 10;
+ metrics2.audio_duration_ms = 25;
+ metrics_sum.audio_duration_ms = 35;
+ metrics1.media_timer_min_ms = 10;
+ metrics2.media_timer_min_ms = 25;
+ metrics_sum.media_timer_min_ms = 10;
+ metrics1.media_timer_max_ms = 100;
+ metrics2.media_timer_max_ms = 200;
+ metrics_sum.media_timer_max_ms = 200;
+ metrics1.media_timer_avg_ms = 50;
+ metrics1.total_scheduling_count = 50;
+ metrics2.media_timer_avg_ms = 100;
+ metrics2.total_scheduling_count = 50;
+ metrics_sum.media_timer_avg_ms = 75;
+ metrics_sum.total_scheduling_count = 100;
+ metrics1.buffer_overruns_max_count = 70;
+ metrics2.buffer_overruns_max_count = 80;
+ metrics_sum.buffer_overruns_max_count = 80;
+ metrics1.buffer_underruns_average = 80;
+ metrics1.buffer_underruns_count = 1200;
+ metrics2.buffer_underruns_average = 130;
+ metrics2.buffer_underruns_count = 2400;
+ metrics_sum.buffer_underruns_average = 113.33333333;
+ metrics_sum.buffer_underruns_count = 3600;
+ DeviceInfo* info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_METRICS_DUMP,
+ info, nullptr, nullptr));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionStart(
+ system_bt_osi::CONNECTION_TECHNOLOGY_TYPE_BREDR, 0);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST, system_bt_osi::DEVICE_TYPE_BREDR);
+ sleep_ms(1000);
+ std::string msg_str;
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+ ClearLog();
+ info = MakeDeviceInfo(
+ BTM_COD_MAJOR_AUDIO_TEST,
+ DeviceInfo_DeviceType::DeviceInfo_DeviceType_DEVICE_TYPE_BREDR);
+ A2DPSession* session = MakeA2DPSession(metrics_sum);
+ bt_sessions_.push_back(MakeBluetoothSession(
+ 1,
+ BluetoothSession_ConnectionTechnologyType::
+ BluetoothSession_ConnectionTechnologyType_CONNECTION_TECHNOLOGY_TYPE_BREDR,
+ BluetoothSession_DisconnectReasonType::
+ BluetoothSession_DisconnectReasonType_UNKNOWN,
+ info, nullptr, session));
+ UpdateLog();
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics1);
+ BluetoothMetricsLogger::GetInstance()->LogA2dpSession(metrics2);
+ sleep_ms(1000);
+ BluetoothMetricsLogger::GetInstance()->LogBluetoothSessionEnd(
+ system_bt_osi::DISCONNECT_REASON_UNKNOWN, 0);
+ msg_str.clear();
+ BluetoothMetricsLogger::GetInstance()->WriteString(&msg_str, true);
+ EXPECT_THAT(msg_str, StrEq(bt_log_str_));
+}
+}
diff --git a/mtkbt/code/bt/osi/test/properties_test.cc b/mtkbt/code/bt/osi/test/properties_test.cc
new file mode 100755
index 0000000..f8c503a
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/properties_test.cc
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/properties.h"
+
+class PropertiesTest : public AllocationTestHarness {};
+
+TEST_F(PropertiesTest, test_default_value) {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get("very.useful.test", value, "very_useful_value");
+ ASSERT_STREQ(value, "very_useful_value");
+}
+
+TEST_F(PropertiesTest, test_successfull_set_and_get_value) {
+ char value[PROPERTY_VALUE_MAX] = "nothing_interesting";
+ int ret = osi_property_set("very.useful.set.test", value);
+ ASSERT_EQ(0, ret);
+
+ char received[PROPERTY_VALUE_MAX];
+ osi_property_get("very.useful.set.test", received, NULL);
+ ASSERT_STREQ(received, "nothing_interesting");
+}
+
+TEST_F(PropertiesTest, test_default_value_int32) {
+ int32_t value = 42;
+ int32_t rvalue = osi_property_get_int32("very.useful.test", value);
+ ASSERT_EQ(rvalue, value);
+}
+
+TEST_F(PropertiesTest, test_successfull_set_and_get_value_int32) {
+ char value[PROPERTY_VALUE_MAX] = "42";
+ int ret = osi_property_set("very.useful.set.test", value);
+ ASSERT_EQ(0, ret);
+
+ int32_t received = osi_property_get_int32("very.useful.set.test", 84);
+ ASSERT_EQ(received, 42);
+}
diff --git a/mtkbt/code/bt/osi/test/rand_test.cc b/mtkbt/code/bt/osi/test/rand_test.cc
new file mode 100755
index 0000000..720617b
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/rand_test.cc
@@ -0,0 +1,17 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/osi.h"
+
+class RandTest : public AllocationTestHarness {};
+
+TEST_F(RandTest, test_rand) {
+ // We can't guarantee any distribution
+ // We'd like it to not crash though.
+ for (int i = 0; i < 10; i++) {
+ int x;
+ x = osi_rand();
+ EXPECT_TRUE(x >= 0);
+ }
+}
diff --git a/mtkbt/code/bt/osi/test/reactor_test.cc b/mtkbt/code/bt/osi/test/reactor_test.cc
new file mode 100755
index 0000000..0164227
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/reactor_test.cc
@@ -0,0 +1,113 @@
+#include <gtest/gtest.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/reactor.h"
+
+class ReactorTest : public AllocationTestHarness {};
+
+static pthread_t thread;
+static volatile bool thread_running;
+
+static void* reactor_thread(void* ptr) {
+ reactor_t* reactor = (reactor_t*)ptr;
+
+ thread_running = true;
+ reactor_start(reactor);
+ thread_running = false;
+
+ return NULL;
+}
+
+static void spawn_reactor_thread(reactor_t* reactor) {
+ int ret = pthread_create(&thread, NULL, reactor_thread, reactor);
+ EXPECT_EQ(ret, 0);
+}
+
+static void join_reactor_thread() { pthread_join(thread, NULL); }
+
+TEST_F(ReactorTest, reactor_new) {
+ reactor_t* reactor = reactor_new();
+ EXPECT_TRUE(reactor != NULL);
+ reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_free_null) { reactor_free(NULL); }
+
+TEST_F(ReactorTest, reactor_stop_start) {
+ reactor_t* reactor = reactor_new();
+ reactor_stop(reactor);
+ reactor_start(reactor);
+ reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_repeated_stop_start) {
+ reactor_t* reactor = reactor_new();
+ for (int i = 0; i < 10; ++i) {
+ reactor_stop(reactor);
+ reactor_start(reactor);
+ }
+ reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_start_wait_stop) {
+ reactor_t* reactor = reactor_new();
+
+ spawn_reactor_thread(reactor);
+ usleep(50 * 1000);
+ EXPECT_TRUE(thread_running);
+
+ reactor_stop(reactor);
+ join_reactor_thread();
+ EXPECT_FALSE(thread_running);
+
+ reactor_free(reactor);
+}
+
+typedef struct {
+ reactor_t* reactor;
+ reactor_object_t* object;
+} unregister_arg_t;
+
+static void unregister_cb(void* context) {
+ unregister_arg_t* arg = (unregister_arg_t*)context;
+ reactor_unregister(arg->object);
+ reactor_stop(arg->reactor);
+}
+
+TEST_F(ReactorTest, reactor_unregister_from_callback) {
+ reactor_t* reactor = reactor_new();
+
+ int fd = eventfd(0, 0);
+ unregister_arg_t arg;
+ arg.reactor = reactor;
+ arg.object = reactor_register(reactor, fd, &arg, unregister_cb, NULL);
+ spawn_reactor_thread(reactor);
+ eventfd_write(fd, 1);
+
+ join_reactor_thread();
+
+ close(fd);
+ reactor_free(reactor);
+}
+
+TEST_F(ReactorTest, reactor_unregister_from_separate_thread) {
+ reactor_t* reactor = reactor_new();
+
+ int fd = eventfd(0, 0);
+
+ reactor_object_t* object = reactor_register(reactor, fd, NULL, NULL, NULL);
+ spawn_reactor_thread(reactor);
+ usleep(50 * 1000);
+ reactor_unregister(object);
+
+ reactor_stop(reactor);
+ join_reactor_thread();
+
+ close(fd);
+ reactor_free(reactor);
+}
diff --git a/mtkbt/code/bt/osi/test/ringbuffer_test.cc b/mtkbt/code/bt/osi/test/ringbuffer_test.cc
new file mode 100755
index 0000000..3475973
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/ringbuffer_test.cc
@@ -0,0 +1,139 @@
+#include <gtest/gtest.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/ringbuffer.h"
+
+TEST(RingbufferTest, test_new_simple) {
+ ringbuffer_t* rb = ringbuffer_init(4096);
+ ASSERT_TRUE(rb != NULL);
+ EXPECT_EQ((size_t)4096, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+ ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_basic) {
+ ringbuffer_t* rb = ringbuffer_init(16);
+
+ uint8_t buffer[10] = {0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0A};
+ ringbuffer_insert(rb, buffer, 10);
+ EXPECT_EQ((size_t)10, ringbuffer_size(rb));
+ EXPECT_EQ((size_t)6, ringbuffer_available(rb));
+
+ uint8_t peek[10] = {0};
+ size_t peeked = ringbuffer_peek(rb, 0, peek, 10);
+ EXPECT_EQ((size_t)10, ringbuffer_size(rb)); // Ensure size doesn't change
+ EXPECT_EQ((size_t)6, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)10, peeked);
+ ASSERT_TRUE(0 == memcmp(buffer, peek, peeked));
+
+ ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_insert_full) {
+ ringbuffer_t* rb = ringbuffer_init(5);
+
+ uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+ uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+ uint8_t peek[5] = {0};
+
+ size_t added = ringbuffer_insert(rb, aa, 7);
+ EXPECT_EQ((size_t)5, added);
+ EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+ added = ringbuffer_insert(rb, bb, 5);
+ EXPECT_EQ((size_t)0, added);
+ EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+ size_t peeked = ringbuffer_peek(rb, 0, peek, 5);
+ EXPECT_EQ((size_t)5, peeked);
+ EXPECT_EQ((size_t)0, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+ ASSERT_TRUE(0 == memcmp(aa, peek, peeked));
+
+ ringbuffer_free(rb);
+}
+
+TEST(RingbufferTest, test_multi_insert_delete) {
+ ringbuffer_t* rb = ringbuffer_init(16);
+ EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+
+ // Insert some bytes
+
+ uint8_t aa[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+ size_t added = ringbuffer_insert(rb, aa, sizeof(aa));
+ EXPECT_EQ((size_t)8, added);
+ EXPECT_EQ((size_t)8, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)8, ringbuffer_size(rb));
+
+ uint8_t bb[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+ ringbuffer_insert(rb, bb, sizeof(bb));
+ EXPECT_EQ((size_t)3, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)13, ringbuffer_size(rb));
+
+ uint8_t content[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB};
+ uint8_t peek[16] = {0};
+ size_t peeked = ringbuffer_peek(rb, 0, peek, 16);
+ EXPECT_EQ((size_t)13, peeked);
+ ASSERT_TRUE(0 == memcmp(content, peek, peeked));
+
+ // Delete some bytes
+
+ ringbuffer_delete(rb, sizeof(aa));
+ EXPECT_EQ((size_t)11, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)5, ringbuffer_size(rb));
+
+ // Add some more to wrap buffer
+
+ uint8_t cc[] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
+ ringbuffer_insert(rb, cc, sizeof(cc));
+ EXPECT_EQ((size_t)2, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)14, ringbuffer_size(rb));
+
+ uint8_t content2[] = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xCC, 0xCC};
+ peeked = ringbuffer_peek(rb, 0, peek, 7);
+ EXPECT_EQ((size_t)7, peeked);
+ ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+ // Pop buffer
+
+ memset(peek, 0, 16);
+ size_t popped = ringbuffer_pop(rb, peek, 7);
+ EXPECT_EQ((size_t)7, popped);
+ EXPECT_EQ((size_t)9, ringbuffer_available(rb));
+ ASSERT_TRUE(0 == memcmp(content2, peek, peeked));
+
+ // Add more again to check head motion
+
+ uint8_t dd[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD};
+ added = ringbuffer_insert(rb, dd, sizeof(dd));
+ EXPECT_EQ((size_t)8, added);
+ EXPECT_EQ((size_t)1, ringbuffer_available(rb));
+
+ // Delete everything
+
+ ringbuffer_delete(rb, 16);
+ EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+
+ // Add small token
+
+ uint8_t ae[] = {0xAE, 0xAE, 0xAE};
+ added = ringbuffer_insert(rb, ae, sizeof(ae));
+ EXPECT_EQ((size_t)13, ringbuffer_available(rb));
+
+ // Get everything
+
+ popped = ringbuffer_pop(rb, peek, 16);
+ EXPECT_EQ(added, popped);
+ EXPECT_EQ((size_t)16, ringbuffer_available(rb));
+ EXPECT_EQ((size_t)0, ringbuffer_size(rb));
+ ASSERT_TRUE(0 == memcmp(ae, peek, popped));
+
+ ringbuffer_free(rb);
+}
diff --git a/mtkbt/code/bt/osi/test/semaphore_test.cc b/mtkbt/code/bt/osi/test/semaphore_test.cc
new file mode 100755
index 0000000..44aee8d
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/semaphore_test.cc
@@ -0,0 +1,86 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include <base/logging.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/semaphore.h"
+#include "osi/include/thread.h"
+
+struct SemaphoreTestSequenceHelper {
+ semaphore_t* semaphore;
+ int counter;
+};
+
+namespace {
+void sleep_then_increment_counter(void* context) {
+ SemaphoreTestSequenceHelper* helper =
+ reinterpret_cast<SemaphoreTestSequenceHelper*>(context);
+ CHECK(helper);
+ CHECK(helper->semaphore);
+ sleep(1);
+ ++helper->counter;
+ semaphore_post(helper->semaphore);
+}
+} // namespace
+
+class SemaphoreTest : public AllocationTestHarness {};
+
+TEST_F(SemaphoreTest, test_new_simple) {
+ semaphore_t* semaphore = semaphore_new(0);
+ ASSERT_TRUE(semaphore != NULL);
+ semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_new_with_value) {
+ semaphore_t* semaphore = semaphore_new(3);
+ ASSERT_TRUE(semaphore != NULL);
+
+ EXPECT_TRUE(semaphore_try_wait(semaphore));
+ EXPECT_TRUE(semaphore_try_wait(semaphore));
+ EXPECT_TRUE(semaphore_try_wait(semaphore));
+ EXPECT_FALSE(semaphore_try_wait(semaphore));
+
+ semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_try_wait) {
+ semaphore_t* semaphore = semaphore_new(0);
+ ASSERT_TRUE(semaphore != NULL);
+
+ EXPECT_FALSE(semaphore_try_wait(semaphore));
+ semaphore_post(semaphore);
+ EXPECT_TRUE(semaphore_try_wait(semaphore));
+ EXPECT_FALSE(semaphore_try_wait(semaphore));
+
+ semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_wait_after_post) {
+ semaphore_t* semaphore = semaphore_new(0);
+ ASSERT_TRUE(semaphore != NULL);
+ semaphore_post(semaphore);
+ semaphore_wait(semaphore);
+ semaphore_free(semaphore);
+}
+
+TEST_F(SemaphoreTest, test_ensure_wait) {
+ semaphore_t* semaphore = semaphore_new(0);
+ ASSERT_TRUE(semaphore != NULL);
+ thread_t* thread = thread_new("semaphore_test_thread");
+ ASSERT_TRUE(thread != NULL);
+
+ EXPECT_FALSE(semaphore_try_wait(semaphore));
+ SemaphoreTestSequenceHelper sequence_helper = {semaphore, 0};
+ thread_post(thread, sleep_then_increment_counter, &sequence_helper);
+ semaphore_wait(semaphore);
+ EXPECT_EQ(sequence_helper.counter, 1)
+ << "semaphore_wait() did not wait for counter to increment";
+
+ semaphore_free(semaphore);
+ thread_free(thread);
+}
diff --git a/mtkbt/code/bt/osi/test/test_stubs.h b/mtkbt/code/bt/osi/test/test_stubs.h
new file mode 100755
index 0000000..cbaa967
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/test_stubs.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+// Helper macros for stubbing out functions and modules for testing.
+
+// Stub out a function, with call counting and mode awareness
+#define STUB_FUNCTION(ret, name, params) \
+ UNUSED_ATTR static int name##_callcount; \
+ static ret name params { \
+ UNUSED_ATTR int _local_callcount = name##_callcount; \
+ name##_callcount++;
+
+// Expect a certain number of calls to the specified stub function
+#define EXPECT_CALL_COUNT(name, count) \
+ EXPECT_EQ((count), (name##_callcount)) \
+ << "expected " #name " to be called " #count " times"
+
+// Reset the call count for the specificed stub function
+#define RESET_CALL_COUNT(name) ((name##_callcount) = 0)
+
+// Use this in a stub function to catch unexpected calls.
+// Prints out a nice message including the call count, the
+// stub function name, and the mode index (sadly no mode name)
+#define UNEXPECTED_CALL \
+ EXPECT_TRUE(false) << "unexpected call " << _local_callcount << " to " \
+ << __func__ << " during mode " << (int)_current_mode
+
+#define MODE_IS(mode) (_current_mode == (mode))
+
+// Macro selection helpers
+#define OVERLOAD_CAT(A, B) A##B
+#define OVERLOAD_SELECT(NAME, NUM) OVERLOAD_CAT(NAME##_, NUM)
+#define OVERLOAD_GET_COUNT(_1, _2, _3, _4, _5, _6, COUNT, ...) COUNT
+#define OVERLOAD_VA_SIZE(...) OVERLOAD_GET_COUNT(__VA_ARGS__, 6, 5, 4, 3, 2, 1)
+#define OVERLOAD_OF(NAME, ...) \
+ OVERLOAD_SELECT(NAME, OVERLOAD_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
+
+// Use this to branch stub function execution to a specific mode or modes.
+// Treat it like an if statement. For example:
+//
+// DURING(dinner) EXPECT_EQ(bread_pudding, food);
+// DURING(midday_snack, midnight_snack) EXPECT_EQ(chocolate, food);
+#define DURING(...) OVERLOAD_OF(DURING, __VA_ARGS__)
+
+#define DURING_1(mode0) if (MODE_IS(mode0))
+#define DURING_2(mode0, mode1) if (MODE_IS(mode0) || MODE_IS(mode1))
+#define DURING_3(mode0, mode1, mode2) \
+ if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2))
+#define DURING_4(mode0, mode1, mode2, mode3) \
+ if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3))
+#define DURING_5(mode0, mode1, mode2, mode3, mode4) \
+ if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3) || \
+ MODE_IS(mode4))
+#define DURING_6(mode0, mode1, mode2, mode3, mode4, mode5) \
+ if (MODE_IS(mode0) || MODE_IS(mode1) || MODE_IS(mode2) || MODE_IS(mode3) || \
+ MODE_IS(mode4) || MODE_IS(mode5))
+
+// Use this to branch stub function exeuction to a specific call
+// count index (zero based). Treat it like an if statement.
+// Usually most helpful following a DURING clause. For example:
+//
+// DURING (breakfast) AT_CALL(0) EXPECT_EQ(bacon, food);
+//
+// or
+//
+// DURING (three_course_meal) {
+// AT_CALL(0) EXPECT_EQ(shrimp_cocktail, food);
+// AT_CALL(1) EXPECT_EQ(bacon_wrapped_bacon, food);
+// AT_CALL(1) EXPECT_EQ(chocolate_covered_fake_blueberries, food);
+// }
+#define AT_CALL(index) if (_local_callcount == (index))
+
+// Declare all the available test modes for the DURING clauses
+// For example:
+//
+// DECLARE_TEST_MODES(breakfast, lunch, dinner);
+#define DECLARE_TEST_MODES(...) \
+ typedef enum { __VA_ARGS__ } _test_modes_t; \
+ static _test_modes_t _current_mode;
+
+// Get the current test mode
+#define CURRENT_TEST_MODE _current_mode
+
+#define TEST_MODES_T _test_modes_t
diff --git a/mtkbt/code/bt/osi/test/thread_test.cc b/mtkbt/code/bt/osi/test/thread_test.cc
new file mode 100755
index 0000000..debf250
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/thread_test.cc
@@ -0,0 +1,57 @@
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include <sys/select.h>
+
+#include "osi/include/osi.h"
+#include "osi/include/reactor.h"
+#include "osi/include/thread.h"
+
+class ThreadTest : public AllocationTestHarness {};
+
+TEST_F(ThreadTest, test_new_simple) {
+ thread_t* thread = thread_new("test_thread");
+ ASSERT_TRUE(thread != NULL);
+ thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_free_simple) {
+ thread_t* thread = thread_new("test_thread");
+ thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_name) {
+ thread_t* thread = thread_new("test_name");
+ ASSERT_STREQ(thread_name(thread), "test_name");
+ thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_long_name) {
+ thread_t* thread = thread_new("0123456789abcdef");
+ ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+ thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_very_long_name) {
+ thread_t* thread = thread_new("0123456789abcdefg");
+ ASSERT_STREQ("0123456789abcdef", thread_name(thread));
+ thread_free(thread);
+}
+
+static void thread_is_self_fn(void* context) {
+ thread_t* thread = (thread_t*)context;
+ EXPECT_TRUE(thread_is_self(thread));
+}
+
+TEST_F(ThreadTest, test_thread_is_self) {
+ thread_t* thread = thread_new("test_thread");
+ thread_post(thread, thread_is_self_fn, thread);
+ thread_free(thread);
+}
+
+TEST_F(ThreadTest, test_thread_is_not_self) {
+ thread_t* thread = thread_new("test_thread");
+ EXPECT_FALSE(thread_is_self(thread));
+ thread_free(thread);
+}
diff --git a/mtkbt/code/bt/osi/test/time_test.cc b/mtkbt/code/bt/osi/test/time_test.cc
new file mode 100755
index 0000000..6b35c17
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/time_test.cc
@@ -0,0 +1,154 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include "AllocationTestHarness.h"
+
+#include "osi/include/time.h"
+
+// Generous upper bound: 10 seconds
+static const uint32_t TEST_TIME_DELTA_UPPER_BOUND_MS = 10 * 1000;
+
+class TimeTest : public AllocationTestHarness {};
+
+//
+// Test that the return value of time_get_os_boottime_ms() is not zero.
+//
+// NOTE: For now this test is disabled, because the return value
+// of time_get_os_boottime_ms() is 32-bits integer that could wrap-around
+// in 49.7 days. It should be re-enabled if/after the wrap-around issue
+// is resolved (e.g., if the return value is 64-bits integer).
+//
+#if 0
+TEST_F(TimeTest, test_time_get_os_boottime_ms_not_zero) {
+ uint32_t t1 = time_get_os_boottime_ms();
+ ASSERT_TRUE(t1 > 0);
+}
+#endif
+
+//
+// Test that the return value of time_get_os_boottime_us() is not zero.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_not_zero) {
+ uint64_t t1 = time_get_os_boottime_us();
+ ASSERT_TRUE(t1 > 0);
+}
+
+//
+// Test that the return value of time_get_os_boottime_ms()
+// is monotonically increasing within reasonable boundries.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_upper_bound) {
+ uint32_t t1 = time_get_os_boottime_ms();
+ uint32_t t2 = time_get_os_boottime_ms();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of time_get_os_boottime_us()
+// is monotonically increasing within reasonable boundries.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_increases_upper_bound) {
+ uint64_t t1 = time_get_os_boottime_us();
+ uint64_t t2 = time_get_os_boottime_us();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of time_get_os_boottime_ms()
+// is increasing.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_ms_increases_lower_bound) {
+ static const uint32_t TEST_TIME_SLEEP_MS = 100;
+ struct timespec delay;
+
+ delay.tv_sec = TEST_TIME_SLEEP_MS / 1000;
+ delay.tv_nsec = 1000 * 1000 * (TEST_TIME_SLEEP_MS % 1000);
+
+ // Take two timestamps with sleep in-between
+ uint32_t t1 = time_get_os_boottime_ms();
+ int err = nanosleep(&delay, &delay);
+ uint32_t t2 = time_get_os_boottime_ms();
+
+ ASSERT_TRUE(err == 0);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_MS);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS);
+}
+
+//
+// Test that the return value of time_get_os_boottime_us()
+// is increasing.
+//
+TEST_F(TimeTest, test_time_get_os_boottime_us_increases_lower_bound) {
+ static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
+ struct timespec delay;
+
+ delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
+ delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
+
+ // Take two timestamps with sleep in-between
+ uint64_t t1 = time_get_os_boottime_us();
+ int err = nanosleep(&delay, &delay);
+ uint64_t t2 = time_get_os_boottime_us();
+
+ ASSERT_TRUE(err == 0);
+ ASSERT_TRUE(t2 > t1);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of time_gettimeofday_us() is not zero.
+//
+TEST_F(TimeTest, test_time_gettimeofday_us_not_zero) {
+ uint64_t t1 = time_gettimeofday_us();
+ ASSERT_TRUE(t1 > 0);
+}
+
+//
+// Test that the return value of time_gettimeofday_us()
+// is monotonically increasing within reasonable boundaries.
+//
+TEST_F(TimeTest, test_time_gettimeofday_us_increases_upper_bound) {
+ uint64_t t1 = time_gettimeofday_us();
+ uint64_t t2 = time_gettimeofday_us();
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
+
+//
+// Test that the return value of time_gettimeofday_us()
+// is increasing.
+//
+TEST_F(TimeTest, test_time_gettimeofday_us_increases_lower_bound) {
+ static const uint64_t TEST_TIME_SLEEP_US = 100 * 1000;
+ struct timespec delay;
+
+ delay.tv_sec = TEST_TIME_SLEEP_US / (1000 * 1000);
+ delay.tv_nsec = 1000 * (TEST_TIME_SLEEP_US % (1000 * 1000));
+
+ // Take two timestamps with sleep in-between
+ uint64_t t1 = time_gettimeofday_us();
+ int err = nanosleep(&delay, &delay);
+ uint64_t t2 = time_gettimeofday_us();
+
+ ASSERT_TRUE(err == 0);
+ ASSERT_TRUE(t2 > t1);
+ ASSERT_TRUE((t2 - t1) >= TEST_TIME_SLEEP_US);
+ ASSERT_TRUE((t2 - t1) < TEST_TIME_DELTA_UPPER_BOUND_MS * 1000);
+}
diff --git a/mtkbt/code/bt/osi/test/wakelock_test.cc b/mtkbt/code/bt/osi/test/wakelock_test.cc
new file mode 100755
index 0000000..d1ff0a2
--- a/dev/null
+++ b/mtkbt/code/bt/osi/test/wakelock_test.cc
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+
+#include <base/logging.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "osi/include/wakelock.h"
+
+#include "AllocationTestHarness.h"
+
+static bool is_wake_lock_acquired = false;
+
+static int acquire_wake_lock_cb(const char* lock_name) {
+ is_wake_lock_acquired = true;
+ return BT_STATUS_SUCCESS;
+}
+
+static int release_wake_lock_cb(const char* lock_name) {
+ is_wake_lock_acquired = false;
+ return BT_STATUS_SUCCESS;
+}
+
+static bt_os_callouts_t bt_wakelock_callouts = {
+ sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb};
+
+class WakelockTest : public AllocationTestHarness {
+ protected:
+ virtual void SetUp() {
+ AllocationTestHarness::SetUp();
+
+// TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
+#if defined(OS_GENERIC)
+ tmp_dir_ = "/tmp/btwlXXXXXX";
+#else
+ tmp_dir_ = "/data/local/tmp/btwlXXXXXX";
+#endif // !defined(OS_GENERIC)
+
+ char* buffer = const_cast<char*>(tmp_dir_.c_str());
+ char* dtemp = mkdtemp(buffer);
+ if (!dtemp) {
+ perror("Can't make wake lock test directory: ");
+ CHECK(false);
+ }
+
+ lock_path_ = tmp_dir_ + "/wake_lock";
+ unlock_path_ = tmp_dir_ + "/wake_unlock";
+
+ creat(lock_path_.c_str(), S_IRWXU);
+ creat(unlock_path_.c_str(), S_IRWXU);
+ }
+
+ virtual void TearDown() {
+ is_wake_lock_acquired = false;
+ wakelock_cleanup();
+ wakelock_set_os_callouts(NULL);
+
+ // Clean up the temp wake lock directory
+ unlink(lock_path_.c_str());
+ unlink(unlock_path_.c_str());
+ rmdir(tmp_dir_.c_str());
+
+ AllocationTestHarness::TearDown();
+ }
+
+ //
+ // Test whether the file-based wakelock is acquired.
+ //
+ bool IsFileWakeLockAcquired() {
+ bool acquired = false;
+
+ int lock_fd = open(lock_path_.c_str(), O_RDONLY);
+ CHECK(lock_fd >= 0);
+
+ int unlock_fd = open(unlock_path_.c_str(), O_RDONLY);
+ CHECK(unlock_fd >= 0);
+
+ struct stat lock_stat, unlock_stat;
+ fstat(lock_fd, &lock_stat);
+ fstat(unlock_fd, &unlock_stat);
+
+ CHECK(lock_stat.st_size >= unlock_stat.st_size);
+
+ void* lock_file =
+ mmap(nullptr, lock_stat.st_size, PROT_READ, MAP_PRIVATE, lock_fd, 0);
+
+ void* unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ,
+ MAP_PRIVATE, unlock_fd, 0);
+
+ if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) {
+ acquired = lock_stat.st_size > unlock_stat.st_size;
+ } else {
+ // these files should always either be with a lock that has more,
+ // or equal.
+ CHECK(false);
+ }
+
+ munmap(lock_file, lock_stat.st_size);
+ munmap(unlock_file, unlock_stat.st_size);
+ close(lock_fd);
+ close(unlock_fd);
+
+ return acquired;
+ }
+
+ std::string tmp_dir_;
+ std::string lock_path_;
+ std::string unlock_path_;
+};
+
+TEST_F(WakelockTest, test_set_os_callouts) {
+ wakelock_set_os_callouts(&bt_wakelock_callouts);
+
+ // Initially, the wakelock is not acquired
+ ASSERT_FALSE(is_wake_lock_acquired);
+
+ for (size_t i = 0; i < 1000; i++) {
+ wakelock_acquire();
+ ASSERT_TRUE(is_wake_lock_acquired);
+ wakelock_release();
+ ASSERT_FALSE(is_wake_lock_acquired);
+ }
+}
+
+TEST_F(WakelockTest, test_set_paths) {
+ wakelock_set_os_callouts(NULL); // Make sure we use native wakelocks
+ wakelock_set_paths(lock_path_.c_str(), unlock_path_.c_str());
+
+ // Initially, the wakelock is not acquired
+ ASSERT_FALSE(IsFileWakeLockAcquired());
+
+ for (size_t i = 0; i < 1000; i++) {
+ wakelock_acquire();
+ ASSERT_TRUE(IsFileWakeLockAcquired());
+ wakelock_release();
+ ASSERT_FALSE(IsFileWakeLockAcquired());
+ }
+}
diff --git a/mtkbt/code/bt/service/Android.bp b/mtkbt/code/bt/service/Android.bp
new file mode 100755
index 0000000..1f15abb
--- a/dev/null
+++ b/mtkbt/code/bt/service/Android.bp
@@ -0,0 +1,243 @@
+cc_defaults {
+ name: "fluoride_service_defaults",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "common"
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt"
+ ],
+ srcs: [
+ "common/bluetooth/adapter_state.cc",
+ "common/bluetooth/advertise_data.cc",
+ "common/bluetooth/advertise_settings.cc",
+ "common/bluetooth/descriptor.cc",
+ "common/bluetooth/characteristic.cc",
+ "common/bluetooth/scan_filter.cc",
+ "common/bluetooth/scan_result.cc",
+ "common/bluetooth/scan_settings.cc",
+ "common/bluetooth/service.cc",
+ "common/bluetooth/util/address_helper.cc",
+ "common/bluetooth/util/atomic_string.cc",
+ "common/bluetooth/uuid.cc",
+ ]
+}
+
+// Source variables
+// ========================================================
+btserviceCommonBinderSrc = [
+ "common/android/bluetooth/IBluetooth.aidl",
+ "common/android/bluetooth/IBluetoothCallback.aidl",
+ "common/android/bluetooth/IBluetoothGattClient.aidl",
+ "common/android/bluetooth/IBluetoothGattClientCallback.aidl",
+ "common/android/bluetooth/IBluetoothGattServer.aidl",
+ "common/android/bluetooth/IBluetoothGattServerCallback.aidl",
+ "common/android/bluetooth/IBluetoothLeAdvertiser.aidl",
+ "common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl",
+ "common/android/bluetooth/IBluetoothLeScanner.aidl",
+ "common/android/bluetooth/IBluetoothLeScannerCallback.aidl",
+ "common/android/bluetooth/IBluetoothLowEnergy.aidl",
+ "common/android/bluetooth/IBluetoothLowEnergyCallback.aidl",
+ "common/android/bluetooth/advertise_data.cc",
+ "common/android/bluetooth/advertise_settings.cc",
+ "common/android/bluetooth/bluetooth_gatt_characteristic.cc",
+ "common/android/bluetooth/bluetooth_gatt_descriptor.cc",
+ "common/android/bluetooth/bluetooth_gatt_included_service.cc",
+ "common/android/bluetooth/bluetooth_gatt_service.cc",
+ "common/android/bluetooth/scan_filter.cc",
+ "common/android/bluetooth/scan_result.cc",
+ "common/android/bluetooth/scan_settings.cc",
+ "common/android/bluetooth/uuid.cc",
+]
+
+btserviceCommonAidlInclude = [
+ "system/bt/service/common",
+ "frameworks/native/aidl/binder",
+]
+
+btserviceDaemonSrc = [
+ "adapter.cc",
+ "daemon.cc",
+ "gatt_client.cc",
+ "gatt_server.cc",
+ "gatt_server_old.cc",
+ "hal/bluetooth_gatt_interface.cc",
+ "hal/bluetooth_interface.cc",
+ "ipc/ipc_handler.cc",
+ "ipc/ipc_manager.cc",
+ "logging_helpers.cc",
+ "low_energy_advertiser.cc",
+ "low_energy_scanner.cc",
+ "low_energy_client.cc",
+ "settings.cc",
+]
+
+btserviceLinuxSrc = [
+ "ipc/ipc_handler_linux.cc",
+ "ipc/linux_ipc_host.cc",
+]
+
+btserviceBinderDaemonImplSrc = [
+ "ipc/binder/bluetooth_binder_server.cc",
+ "ipc/binder/bluetooth_gatt_client_binder_server.cc",
+ "ipc/binder/bluetooth_gatt_server_binder_server.cc",
+ "ipc/binder/bluetooth_le_advertiser_binder_server.cc",
+ "ipc/binder/bluetooth_le_scanner_binder_server.cc",
+ "ipc/binder/bluetooth_low_energy_binder_server.cc",
+ "ipc/binder/interface_with_instances_base.cc",
+ "ipc/binder/ipc_handler_binder.cc",
+]
+
+btserviceBinderDaemonSrc = btserviceCommonBinderSrc + btserviceBinderDaemonImplSrc
+
+// Main unit test sources. These get built for host and target.
+// ========================================================
+btserviceBaseTestSrc = [
+ "hal/fake_bluetooth_gatt_interface.cc",
+ "hal/fake_bluetooth_interface.cc",
+ "test/adapter_unittest.cc",
+ "test/advertise_data_unittest.cc",
+ "test/fake_hal_util.cc",
+ "test/gatt_client_unittest.cc",
+ "test/gatt_server_unittest.cc",
+ "test/low_energy_advertiser_unittest.cc",
+ "test/low_energy_client_unittest.cc",
+ "test/low_energy_scanner_unittest.cc",
+ "test/settings_unittest.cc",
+ "test/util_unittest.cc",
+ "test/uuid_unittest.cc",
+]
+
+// Native system service for target
+// ========================================================
+cc_binary {
+ name: "bluetoothtbd",
+ defaults: ["fluoride_service_defaults"],
+ srcs: btserviceBinderDaemonSrc
+ + btserviceLinuxSrc
+ + btserviceDaemonSrc
+ + ["main.cc"],
+ aidl: {
+ include_dirs: btserviceCommonAidlInclude
+ },
+ required: ["bluetooth.default"],
+ static_libs: ["libbtcore"],
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "liblog",
+ "libutils",
+ ],
+ init_rc: ["bluetoothtbd.rc"],
+}
+
+// Native system service unit tests for target and host
+
+// ========================================================
+cc_test {
+ name: "bluetoothtbd_test",
+ defaults: ["fluoride_service_defaults"],
+ srcs: btserviceBaseTestSrc
+ + btserviceDaemonSrc + [
+ "test/main.cc"
+ ],
+ aidl: {
+ include_dirs: btserviceCommonAidlInclude,
+ },
+ static_libs: [
+ "libgmock",
+ "liblog",
+ ],
+ host_supported: true,
+ target: {
+ // This includes Binder related tests that can only be run
+ // on target.
+ android: {
+ srcs: btserviceBinderDaemonSrc + [
+ "test/parcelable_unittest.cc",
+ "test/ParcelableTest.aidl",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ },
+ host: {
+ srcs: [
+ "test/stub_ipc_handler_binder.cc",
+ ],
+ },
+ darwin: {
+ srcs: [
+ "test/stub_ipc_handler_linux.cc",
+ ],
+ },
+ linux: {
+ srcs: btserviceLinuxSrc + [
+ // TODO(bcf): Fix this test.
+ //"test/ipc_linux_unittest.cc",
+ ],
+ host_ldlibs: ["-lrt"],
+ },
+ },
+}
+
+// Client library for interacting with Bluetooth daemon
+// This is a static library for target.
+// ========================================================
+cc_library_static {
+ name: "libbluetooth-client",
+ defaults: ["fluoride_service_defaults"],
+ srcs: btserviceCommonBinderSrc,
+ aidl: {
+ export_aidl_headers: true,
+ include_dirs: btserviceCommonAidlInclude
+ },
+ export_include_dirs: ["common"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+// Native system service CLI for target
+// ========================================================
+cc_binary {
+ name: "bluetooth-cli",
+ defaults: ["fluoride_defaults"],
+ srcs: ["client/main.cc"],
+ static_libs: ["libbluetooth-client"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+// Heart Rate GATT service example for target
+// ========================================================
+cc_binary {
+ name: "bt-example-hr-server",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: ["example/heart_rate"],
+ srcs: [
+ "example/heart_rate/heart_rate_server.cc",
+ "example/heart_rate/server_main.cc",
+ ],
+ static_libs: ["libbluetooth-client"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+cc_library_static {
+ name: "libbluetoothtbd_hal",
+ defaults: ["fluoride_defaults"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs = [
+ "hal/bluetooth_gatt_interface.cc",
+ "hal/bluetooth_interface.cc",
+ "logging_helpers.cc",
+ ]
+}
diff --git a/mtkbt/code/bt/service/BUILD.gn b/mtkbt/code/bt/service/BUILD.gn
new file mode 100755
index 0000000..e156c72
--- a/dev/null
+++ b/mtkbt/code/bt/service/BUILD.gn
@@ -0,0 +1,100 @@
+#
+# Copyright (C) 2015 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+source_set("service") {
+ sources = [
+ "adapter.cc",
+ "common/bluetooth/adapter_state.cc",
+ "common/bluetooth/advertise_data.cc",
+ "common/bluetooth/advertise_settings.cc",
+ "common/bluetooth/characteristic.cc",
+ "common/bluetooth/descriptor.cc",
+ "common/bluetooth/scan_filter.cc",
+ "common/bluetooth/scan_result.cc",
+ "common/bluetooth/scan_settings.cc",
+ "common/bluetooth/service.cc",
+ "common/bluetooth/util/address_helper.cc",
+ "common/bluetooth/util/atomic_string.cc",
+ "common/bluetooth/uuid.cc",
+ "daemon.cc",
+ "gatt_client.cc",
+ "gatt_server.cc",
+ "gatt_server_old.cc",
+ "hal/bluetooth_gatt_interface.cc",
+ "hal/bluetooth_interface.cc",
+ "hal/fake_bluetooth_gatt_interface.cc",
+ "hal/fake_bluetooth_interface.cc",
+ "ipc/ipc_handler.cc",
+ "ipc/ipc_handler_linux.cc",
+ "ipc/ipc_manager.cc",
+ "ipc/linux_ipc_host.cc",
+ "logging_helpers.cc",
+ "low_energy_advertiser.cc",
+ "low_energy_scanner.cc",
+ "low_energy_client.cc",
+ "settings.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//service/common",
+ "//third_party/modp_b64/modp64",
+ "//third_party/libhardware/include",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base"
+ ]
+}
+
+executable("bluetoothtbd") {
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ ":service",
+ "//btcore",
+ "//third_party/libchrome:base",
+ "//third_party/modp_b64",
+ ]
+
+ include_dirs = [ "//" ]
+
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lrt",
+ ]
+}
+
+executable("service_unittests") {
+ testonly = true
+ sources = [
+ "test/fake_hal_util.cc",
+ "test/settings_unittest.cc",
+ "test/uuid_unittest.cc",
+ ]
+
+ include_dirs = [ "//" ]
+
+ deps = [
+ ":service",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ "//third_party/modp_b64",
+ ]
+}
diff --git a/mtkbt/code/bt/service/adapter.cc b/mtkbt/code/bt/service/adapter.cc
new file mode 100755
index 0000000..42f8d79
--- a/dev/null
+++ b/mtkbt/code/bt/service/adapter.cc
@@ -0,0 +1,417 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/adapter.h"
+
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/common/bluetooth/util/atomic_string.h"
+#include "service/gatt_client.h"
+#include "service/gatt_server.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+#include "service/low_energy_advertiser.h"
+#include "service/low_energy_client.h"
+#include "service/low_energy_scanner.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// static
+const char Adapter::kDefaultAddress[] = "00:00:00:00:00:00";
+// static
+const char Adapter::kDefaultName[] = "not-initialized";
+
+// TODO(armansito): The following constants come straight from
+// packages/apps/Bluetooth/src/c/a/b/btservice/AdapterService.java. It would be
+// nice to know if there were a way to obtain these values from the stack
+// instead of hardcoding them here.
+
+// The minimum number of advertising instances required for multi-advertisement
+// support.
+const int kMinAdvInstancesForMultiAdv = 5;
+
+// Used when determining if offloaded scan filtering is supported.
+const int kMinOffloadedFilters = 10;
+
+// Used when determining if offloaded scan batching is supported.
+const int kMinOffloadedScanStorageBytes = 1024;
+
+void Adapter::Observer::OnAdapterStateChanged(Adapter* adapter,
+ AdapterState prev_state,
+ AdapterState new_state) {
+ // Default implementation does nothing
+}
+
+void Adapter::Observer::OnDeviceConnectionStateChanged(
+ Adapter* adapter, const std::string& device_address, bool connected) {
+ // Default implementation does nothing
+}
+
+// The real Adapter implementation used in production.
+class AdapterImpl : public Adapter, public hal::BluetoothInterface::Observer {
+ public:
+ AdapterImpl()
+ : state_(ADAPTER_STATE_OFF),
+ address_(kDefaultAddress),
+ name_(kDefaultName) {
+ memset(&local_le_features_, 0, sizeof(local_le_features_));
+ hal::BluetoothInterface::Get()->AddObserver(this);
+ ble_client_factory_.reset(new LowEnergyClientFactory(*this));
+ ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
+ ble_scanner_factory_.reset(new LowEnergyScannerFactory(*this));
+ gatt_client_factory_.reset(new GattClientFactory());
+ gatt_server_factory_.reset(new GattServerFactory());
+ hal::BluetoothInterface::Get()->GetHALInterface()->get_adapter_properties();
+ }
+
+ ~AdapterImpl() override {
+ hal::BluetoothInterface::Get()->RemoveObserver(this);
+ }
+
+ void AddObserver(Adapter::Observer* observer) override {
+ lock_guard<mutex> lock(observers_lock_);
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Adapter::Observer* observer) override {
+ lock_guard<mutex> lock(observers_lock_);
+ observers_.RemoveObserver(observer);
+ }
+
+ AdapterState GetState() const override { return state_.load(); }
+
+ bool IsEnabled() const override { return state_.load() == ADAPTER_STATE_ON; }
+
+ bool Enable(bool start_restricted) override {
+ AdapterState current_state = GetState();
+ if (current_state != ADAPTER_STATE_OFF) {
+ LOG(INFO) << "Adapter not disabled - state: "
+ << AdapterStateToString(current_state);
+ return false;
+ }
+
+ // Set the state before calling enable() as there might be a race between
+ // here and the AdapterStateChangedCallback.
+ state_ = ADAPTER_STATE_TURNING_ON;
+ NotifyAdapterStateChanged(current_state, state_);
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable(
+ start_restricted);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to enable Bluetooth - status: "
+ << BtStatusText((const bt_status_t)status);
+ state_ = ADAPTER_STATE_OFF;
+ NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_ON, state_);
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Disable() override {
+ if (!IsEnabled()) {
+ LOG(INFO) << "Adapter is not enabled";
+ return false;
+ }
+
+ AdapterState current_state = GetState();
+
+ // Set the state before calling enable() as there might be a race between
+ // here and the AdapterStateChangedCallback.
+ state_ = ADAPTER_STATE_TURNING_OFF;
+ NotifyAdapterStateChanged(current_state, state_);
+
+ int status = hal::BluetoothInterface::Get()->GetHALInterface()->disable();
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to disable Bluetooth - status: "
+ << BtStatusText((const bt_status_t)status);
+ state_ = current_state;
+ NotifyAdapterStateChanged(ADAPTER_STATE_TURNING_OFF, state_);
+ return false;
+ }
+
+ return true;
+ }
+
+ std::string GetName() const override { return name_.Get(); }
+
+ bool SetName(const std::string& name) override {
+ bt_bdname_t hal_name;
+ size_t max_name_len = sizeof(hal_name.name);
+
+ // Include the \0 byte in size measurement.
+ if (name.length() >= max_name_len) {
+ LOG(ERROR) << "Given name \"" << name << "\" is larger than maximum"
+ << " allowed size: " << max_name_len;
+ return false;
+ }
+
+ strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
+ name.length() + 1);
+
+ VLOG(1) << "Setting adapter name: " << name;
+
+ if (!SetAdapterProperty(BT_PROPERTY_BDNAME, &hal_name, sizeof(hal_name))) {
+ LOG(ERROR) << "Failed to set adapter name: " << name;
+ return false;
+ }
+
+ return true;
+ }
+
+ std::string GetAddress() const override { return address_.Get(); }
+
+ bool IsMultiAdvertisementSupported() override {
+ lock_guard<mutex> lock(local_le_features_lock_);
+ return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
+ }
+
+ bool IsDeviceConnected(const std::string& device_address) override {
+ lock_guard<mutex> lock(connected_devices_lock_);
+ return connected_devices_.find(device_address) != connected_devices_.end();
+ }
+
+ int GetTotalNumberOfTrackableAdvertisements() override {
+ lock_guard<mutex> lock(local_le_features_lock_);
+ return local_le_features_.total_trackable_advertisers;
+ }
+
+ bool IsOffloadedFilteringSupported() override {
+ lock_guard<mutex> lock(local_le_features_lock_);
+ return local_le_features_.max_adv_filter_supported >= kMinOffloadedFilters;
+ }
+
+ bool IsOffloadedScanBatchingSupported() override {
+ lock_guard<mutex> lock(local_le_features_lock_);
+ return local_le_features_.scan_result_storage_size >=
+ kMinOffloadedScanStorageBytes;
+ }
+
+ LowEnergyClientFactory* GetLowEnergyClientFactory() const override {
+ return ble_client_factory_.get();
+ }
+
+ LowEnergyAdvertiserFactory* GetLeAdvertiserFactory() const override {
+ return ble_advertiser_factory_.get();
+ }
+
+ LowEnergyScannerFactory* GetLeScannerFactory() const override {
+ return ble_scanner_factory_.get();
+ }
+
+ GattClientFactory* GetGattClientFactory() const override {
+ return gatt_client_factory_.get();
+ }
+
+ GattServerFactory* GetGattServerFactory() const override {
+ return gatt_server_factory_.get();
+ }
+
+ // hal::BluetoothInterface::Observer overrides.
+ void AdapterStateChangedCallback(bt_state_t state) override {
+ LOG(INFO) << "Adapter state changed: " << BtStateText(state);
+
+ AdapterState prev_state = GetState();
+
+ switch (state) {
+ case BT_STATE_OFF:
+ state_ = ADAPTER_STATE_OFF;
+ break;
+
+ case BT_STATE_ON:
+ state_ = ADAPTER_STATE_ON;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ NotifyAdapterStateChanged(prev_state, GetState());
+ }
+
+ void AdapterPropertiesCallback(bt_status_t status, int num_properties,
+ bt_property_t* properties) override {
+ LOG(INFO) << "Adapter properties changed";
+
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "status: " << BtStatusText(status);
+ return;
+ }
+
+ for (int i = 0; i < num_properties; i++) {
+ bt_property_t* property = properties + i;
+ switch (property->type) {
+ case BT_PROPERTY_BDADDR: {
+ std::string address =
+ BtAddrString(reinterpret_cast<bt_bdaddr_t*>(property->val));
+ LOG(INFO) << "Adapter address changed: " << address;
+ address_.Set(address);
+ break;
+ }
+ case BT_PROPERTY_BDNAME: {
+ bt_bdname_t* hal_name = reinterpret_cast<bt_bdname_t*>(property->val);
+ std::string name = reinterpret_cast<char*>(hal_name->name);
+ LOG(INFO) << "Adapter name changed: " << name;
+ name_.Set(name);
+ break;
+ }
+ case BT_PROPERTY_LOCAL_LE_FEATURES: {
+ lock_guard<mutex> lock(local_le_features_lock_);
+ if (property->len != sizeof(bt_local_le_features_t)) {
+ LOG(WARNING) << "Malformed value received for property: "
+ << "BT_PROPERTY_LOCAL_LE_FEATURES";
+ break;
+ }
+ bt_local_le_features_t* features =
+ reinterpret_cast<bt_local_le_features_t*>(property->val);
+ memcpy(&local_le_features_, features, sizeof(*features));
+ LOG(INFO) << "Supported LE features updated";
+ break;
+ }
+ default:
+ VLOG(1) << "Unhandled adapter property: "
+ << BtPropertyText(property->type);
+ break;
+ }
+
+ // TODO(armansito): notify others of the updated properties
+ }
+ }
+
+ void SSPRequestCallback(bt_bdaddr_t*, bt_bdname_t*, uint32_t,
+ bt_ssp_variant_t, uint32_t pass_key) override {
+ LOG(INFO) << "Passkey is: " << pass_key;
+ }
+
+ void AclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state) override {
+ std::string device_address = BtAddrString(&remote_bdaddr);
+ bool connected = (state == BT_ACL_STATE_CONNECTED);
+ LOG(INFO) << "ACL state changed: " << device_address
+ << " - connected: " << (connected ? "true" : "false");
+
+ // If this is reported with an error status, I suppose the best thing we can
+ // do is to log it and ignore the event.
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "status: " << BtStatusText(status);
+ return;
+ }
+
+ // Introduce a scope to manage |connected_devices_lock_| with RAII.
+ {
+ lock_guard<mutex> lock(connected_devices_lock_);
+ if (connected)
+ connected_devices_.insert(device_address);
+ else
+ connected_devices_.erase(device_address);
+ }
+
+ lock_guard<mutex> lock(observers_lock_);
+ FOR_EACH_OBSERVER(
+ Adapter::Observer, observers_,
+ OnDeviceConnectionStateChanged(this, device_address, connected));
+ }
+
+ // Sends a request to set the given HAL adapter property type and value.
+ bool SetAdapterProperty(bt_property_type_t type, void* value, int length) {
+ CHECK(length > 0);
+ CHECK(value);
+
+ bt_property_t property;
+ property.len = length;
+ property.val = value;
+ property.type = type;
+
+ int status =
+ hal::BluetoothInterface::Get()->GetHALInterface()->set_adapter_property(
+ &property);
+ if (status != BT_STATUS_SUCCESS) {
+ VLOG(1) << "Failed to set property";
+ return false;
+ }
+
+ return true;
+ }
+
+ // Helper for invoking the AdapterStateChanged observer method.
+ void NotifyAdapterStateChanged(AdapterState prev_state,
+ AdapterState new_state) {
+ if (prev_state == new_state) return;
+
+ lock_guard<mutex> lock(observers_lock_);
+ FOR_EACH_OBSERVER(Adapter::Observer, observers_,
+ OnAdapterStateChanged(this, prev_state, new_state));
+ }
+
+ private:
+ // The current adapter state.
+ std::atomic<AdapterState> state_;
+
+ // The Bluetooth device address of the local adapter in string from
+ // (i.e.. XX:XX:XX:XX:XX:XX)
+ util::AtomicString address_;
+
+ // The current local adapter name.
+ util::AtomicString name_;
+
+ // The current set of supported LE features as obtained from the stack. The
+ // values here are all initially set to 0 and updated when the corresponding
+ // adapter property has been received from the stack.
+ std::mutex local_le_features_lock_;
+ bt_local_le_features_t local_le_features_;
+
+ // List of observers that are interested in notifications from us.
+ std::mutex observers_lock_;
+ base::ObserverList<Adapter::Observer> observers_;
+
+ // List of devices addresses that are currently connected.
+ std::mutex connected_devices_lock_;
+ std::unordered_set<std::string> connected_devices_;
+
+ // Factory used to create per-app LowEnergyClient instances.
+ std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
+
+ // Factory used to create per-app LeAdvertiser instances.
+ std::unique_ptr<LowEnergyAdvertiserFactory> ble_advertiser_factory_;
+
+ // Factory used to create per-app LeScanner instances.
+ std::unique_ptr<LowEnergyScannerFactory> ble_scanner_factory_;
+
+ // Factory used to create per-app GattClient instances.
+ std::unique_ptr<GattClientFactory> gatt_client_factory_;
+
+ // Factory used to create per-app GattServer instances.
+ std::unique_ptr<GattServerFactory> gatt_server_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(AdapterImpl);
+};
+
+// static
+std::unique_ptr<Adapter> Adapter::Create() {
+ return std::unique_ptr<Adapter>(new AdapterImpl());
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/adapter.h b/mtkbt/code/bt/service/adapter.h
new file mode 100755
index 0000000..37275db
--- a/dev/null
+++ b/mtkbt/code/bt/service/adapter.h
@@ -0,0 +1,154 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include "service/common/bluetooth/adapter_state.h"
+
+namespace bluetooth {
+
+class GattClientFactory;
+class GattServerFactory;
+class LowEnergyAdvertiserFactory;
+class LowEnergyScannerFactory;
+class LowEnergyClientFactory;
+
+// Represents the local Bluetooth adapter.
+class Adapter {
+ public:
+ // The default values returned before the Adapter is fully initialized and
+ // powered. The complete values for these fields are obtained following a
+ // successful call to "Enable".
+ static const char kDefaultAddress[];
+ static const char kDefaultName[];
+
+ // Observer interface allows other classes to receive notifications from us.
+ // All of the methods in this interface are declared as optional to allow
+ // different layers to process only those events that they are interested in.
+ //
+ // All methods take in an |adapter| argument which points to the Adapter
+ // object that the Observer instance was added to.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ // Called when there is a change in the state of the local Bluetooth
+ // |adapter| from |prev_state| to |new_state|.
+ virtual void OnAdapterStateChanged(Adapter* adapter,
+ AdapterState prev_state,
+ AdapterState new_state);
+
+ // Called when there is a change in the connection state between the local
+ // |adapter| and a remote device with address |device_address|. If the ACL
+ // state changes from disconnected to connected, then |connected| will be
+ // true and vice versa.
+ virtual void OnDeviceConnectionStateChanged(
+ Adapter* adapter, const std::string& device_address, bool connected);
+ };
+
+ // Returns an Adapter implementation to be used in production. Don't use these
+ // in tests; use MockAdapter instead.
+ static std::unique_ptr<Adapter> Create();
+
+ virtual ~Adapter() = default;
+
+ // Add or remove an observer.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Returns the current Adapter state.
+ virtual AdapterState GetState() const = 0;
+
+ // Returns true, if the adapter radio is current powered.
+ virtual bool IsEnabled() const = 0;
+
+ // Enables Bluetooth. This method will send a request to the Bluetooth adapter
+ // to power up its radio. Returns true, if the request was successfully sent
+ // to the controller, otherwise returns false. A successful call to this
+ // method only means that the enable request has been sent to the Bluetooth
+ // controller and does not imply that the operation itself succeeded.
+ // The |start_restricted| flag enables the adapter in restricted mode. In
+ // restricted mode, bonds that are created are marked as restricted in the
+ // config file. These devices are deleted upon leaving restricted mode.
+ virtual bool Enable(bool start_restricted) = 0;
+
+ // Powers off the Bluetooth radio. Returns true, if the disable request was
+ // successfully sent to the Bluetooth controller.
+ virtual bool Disable() = 0;
+
+ // Returns the name currently assigned to the local adapter.
+ virtual std::string GetName() const = 0;
+
+ // Sets the name assigned to the local Bluetooth adapter. This is the name
+ // that the local controller will present to remote devices.
+ virtual bool SetName(const std::string& name) = 0;
+
+ // Returns the local adapter addess in string form (XX:XX:XX:XX:XX:XX).
+ virtual std::string GetAddress() const = 0;
+
+ // Returns true if the local adapter supports the Low-Energy
+ // multi-advertisement feature.
+ virtual bool IsMultiAdvertisementSupported() = 0;
+
+ // Returns true if the remote device with address |device_address| is
+ // currently connected. This is not a const method as it modifies the state of
+ // the associated internal mutex.
+ virtual bool IsDeviceConnected(const std::string& device_address) = 0;
+
+ // Returns the total number of trackable advertisements as supported by the
+ // underlying hardware.
+ virtual int GetTotalNumberOfTrackableAdvertisements() = 0;
+
+ // Returns true if hardware-backed scan filtering is supported.
+ virtual bool IsOffloadedFilteringSupported() = 0;
+
+ // Returns true if hardware-backed batch scanning is supported.
+ virtual bool IsOffloadedScanBatchingSupported() = 0;
+
+ // Returns a pointer to the LowEnergyClientFactory. This can be used to
+ // register per-application LowEnergyClient instances to perform BLE GAP
+ // operations.
+ virtual LowEnergyClientFactory* GetLowEnergyClientFactory() const = 0;
+
+ // Returns a pointer to the LowEnergyScannerFactory. This can be used to
+ // register per-application LowEnergyScanner instances to perform scanning.
+ virtual LowEnergyScannerFactory* GetLeScannerFactory() const = 0;
+
+ // Returns a pointer to the LowEnergyAdvertiserFactory. This can be used to
+ // register per-application LowEnergyAdvertiser instances to perform
+ // advertising.
+ virtual LowEnergyAdvertiserFactory* GetLeAdvertiserFactory() const = 0;
+
+ // Returns a pointer to the GattClientFactory. This can be used to register
+ // per-application GATT server instances.
+ virtual GattClientFactory* GetGattClientFactory() const = 0;
+
+ // Returns a pointer to the GattServerFactory. This can be used to register
+ // per-application GATT server instances.
+ virtual GattServerFactory* GetGattServerFactory() const = 0;
+
+ protected:
+ Adapter() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Adapter);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/bluetooth_instance.h b/mtkbt/code/bt/service/bluetooth_instance.h
new file mode 100755
index 0000000..868f425
--- a/dev/null
+++ b/mtkbt/code/bt/service/bluetooth_instance.h
@@ -0,0 +1,75 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <functional>
+#include <memory>
+
+#include <base/macros.h>
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/uuid.h"
+
+namespace bluetooth {
+
+// A BluetoothInstance represents an application's handle to an instance
+// that is registered with the underlying Bluetooth stack using a UUID and has a
+// stack-assigned integer "instance_id" ID associated with it.
+class BluetoothInstance {
+ public:
+ virtual ~BluetoothInstance() = default;
+
+ // Returns the app-specific unique ID used while registering this instance.
+ virtual const UUID& GetAppIdentifier() const = 0;
+
+ // Returns the HAL "interface ID" assigned to this instance by the stack.
+ virtual int GetInstanceId() const = 0;
+
+ protected:
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ BluetoothInstance() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInstance);
+};
+
+// A BluetoothInstanceFactory provides a common interface for factory
+// classes that handle asynchronously registering a per-application instance of
+// a BluetoothInstance with the underlying stack.
+class BluetoothInstanceFactory {
+ public:
+ BluetoothInstanceFactory() = default;
+ virtual ~BluetoothInstanceFactory() = default;
+
+ // Callback invoked as a result of a call to RegisterInstance.
+ using RegisterCallback =
+ std::function<void(BLEStatus status, const UUID& app_uuid,
+ std::unique_ptr<BluetoothInstance> instance)>;
+
+ // Registers an instance for the given unique identifier |app_uuid|.
+ // On success, this asynchronously invokes |callback| with a unique pointer
+ // to a BluetoothInstance whose ownership can be taken by the caller. In
+ // the case of an error, the pointer will contain nullptr.
+ virtual bool RegisterInstance(const UUID& app_uuid,
+ const RegisterCallback& callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInstanceFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/bluetoothtbd.rc b/mtkbt/code/bt/service/bluetoothtbd.rc
new file mode 100755
index 0000000..f613711
--- a/dev/null
+++ b/mtkbt/code/bt/service/bluetoothtbd.rc
@@ -0,0 +1,4 @@
+service bluetoothtbd /system/bin/bluetoothtbd
+ class main
+ user bluetooth
+ group wakelock net_bt_admin bluetooth net_admin
diff --git a/mtkbt/code/bt/service/client/main.cc b/mtkbt/code/bt/service/client/main.cc
new file mode 100755
index 0000000..be6b15e
--- a/dev/null
+++ b/mtkbt/code/bt/service/client/main.cc
@@ -0,0 +1,1110 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <iostream>
+#include <string>
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <android/bluetooth/BnBluetoothCallback.h>
+#include <android/bluetooth/BnBluetoothGattClientCallback.h>
+#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
+#include <android/bluetooth/BnBluetoothLeScannerCallback.h>
+#include <android/bluetooth/BnBluetoothLowEnergyCallback.h>
+#include <android/bluetooth/IBluetooth.h>
+#include <android/bluetooth/IBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <android/bluetooth/IBluetoothLeScanner.h>
+#include <android/bluetooth/IBluetoothLowEnergy.h>
+#include <bluetooth/adapter_state.h>
+#include <bluetooth/low_energy_constants.h>
+#include <bluetooth/scan_filter.h>
+#include <bluetooth/scan_settings.h>
+#include <bluetooth/uuid.h>
+
+using namespace std;
+
+using android::sp;
+using android::String8;
+using android::String16;
+using android::binder::Status;
+using android::OK;
+using android::getService;
+
+using android::bluetooth::IBluetooth;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeScanner;
+using android::bluetooth::IBluetoothLowEnergy;
+
+namespace {
+
+#define COLOR_OFF "\x1B[0m"
+#define COLOR_RED "\x1B[0;91m"
+#define COLOR_GREEN "\x1B[0;92m"
+#define COLOR_YELLOW "\x1B[0;93m"
+#define COLOR_BLUE "\x1B[0;94m"
+#define COLOR_MAGENTA "\x1B[0;95m"
+#define COLOR_BOLDGRAY "\x1B[1;30m"
+#define COLOR_BOLDWHITE "\x1B[1;37m"
+#define COLOR_BOLDYELLOW "\x1B[1;93m"
+#define CLEAR_LINE "\x1B[2K"
+
+#define CHECK_ARGS_COUNT(args, op, num, msg) \
+ if (!((args).size() op num)) { \
+ PrintError(msg); \
+ return; \
+ }
+#define CHECK_NO_ARGS(args) \
+ CHECK_ARGS_COUNT(args, ==, 0, "Expected no arguments")
+
+// TODO(armansito): Clean up this code. Right now everything is in this
+// monolithic file. We should organize this into different classes for command
+// handling, console output/printing, callback handling, etc.
+// (See http://b/23387611)
+
+// Used to synchronize the printing of the command-line prompt and incoming
+// Binder callbacks.
+std::atomic_bool showing_prompt(false);
+
+// The registered IBluetoothLowEnergy client handle. If |ble_registering| is
+// true then an operation to register the client is in progress.
+std::atomic_bool ble_registering(false);
+std::atomic_int ble_client_id(0);
+
+// The registered IBluetoothLeAdvertiser handle. If |ble_advertiser_registering|
+// is true then an operation to register the advertiser is in progress.
+const int invalid_advertiser_id = -1;
+std::atomic_bool ble_advertiser_registering(false);
+std::atomic_int ble_advertiser_id(invalid_advertiser_id);
+
+// The registered IBluetoothLeScanner handle. If |ble_scanner_registering| is
+// true then an operation to register the scanner is in progress.
+std::atomic_bool ble_scanner_registering(false);
+std::atomic_int ble_scanner_id(0);
+
+// The registered IBluetoothGattClient client handle. If |gatt_registering| is
+// true then an operation to register the client is in progress.
+std::atomic_bool gatt_registering(false);
+std::atomic_int gatt_client_id(0);
+
+// True if we should dump the scan record bytes for incoming scan results.
+std::atomic_bool dump_scan_record(false);
+
+// True if the remote process has died and we should exit.
+std::atomic_bool should_exit(false);
+
+std::string kServiceName = "bluetooth-service";
+
+void PrintPrompt() { cout << COLOR_BLUE "[FCLI] " COLOR_OFF << flush; }
+
+void PrintError(const string& message) {
+ cout << COLOR_RED << message << COLOR_OFF << endl;
+}
+
+void PrintOpStatus(const std::string& op, bool status) {
+ cout << COLOR_BOLDWHITE << op << " status: " COLOR_OFF
+ << (status ? (COLOR_GREEN "success") : (COLOR_RED "failure"))
+ << COLOR_OFF << endl;
+}
+
+inline void BeginAsyncOut() {
+ if (showing_prompt.load()) cout << CLEAR_LINE << "\r";
+}
+
+inline void EndAsyncOut() {
+ std::flush(cout);
+ if (showing_prompt.load())
+ PrintPrompt();
+ else
+ cout << endl;
+}
+
+class CLIBluetoothCallback : public android::bluetooth::BnBluetoothCallback {
+ public:
+ CLIBluetoothCallback() = default;
+ ~CLIBluetoothCallback() override = default;
+
+ // IBluetoothCallback overrides:
+ Status OnBluetoothStateChange(int32_t prev_state,
+ int32_t new_state) override {
+ BeginAsyncOut();
+ cout << COLOR_BOLDWHITE "Adapter state changed: " COLOR_OFF << COLOR_MAGENTA
+ << AdapterStateToString(bluetooth::AdapterState(prev_state))
+ << COLOR_OFF << COLOR_BOLDWHITE " -> " COLOR_OFF << COLOR_BOLDYELLOW
+ << AdapterStateToString(bluetooth::AdapterState(new_state))
+ << COLOR_OFF;
+ EndAsyncOut();
+
+ return Status::ok();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothCallback);
+};
+
+class CLIBluetoothLowEnergyCallback
+ : public android::bluetooth::BnBluetoothLowEnergyCallback {
+ public:
+ CLIBluetoothLowEnergyCallback() = default;
+ ~CLIBluetoothLowEnergyCallback() override = default;
+
+ // IBluetoothLowEnergyCallback overrides:
+ Status OnClientRegistered(int status, int client_id) override {
+ BeginAsyncOut();
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ PrintError("Failed to register BLE client");
+ } else {
+ ble_client_id = client_id;
+ cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
+ << COLOR_GREEN << client_id << COLOR_OFF;
+ }
+ EndAsyncOut();
+
+ ble_registering = false;
+ return Status::ok();
+ }
+
+ Status OnConnectionState(int status, int client_id, const String16& address,
+ bool connected) override {
+ BeginAsyncOut();
+ cout << COLOR_BOLDWHITE "Connection state: " << COLOR_BOLDYELLOW "["
+ << address << " connected: " << (connected ? "true" : "false") << " ] "
+ << COLOR_BOLDWHITE "- status: " << status
+ << COLOR_BOLDWHITE " - client_id: " << client_id << COLOR_OFF;
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ Status OnMtuChanged(int status, const String16& address, int mtu) override {
+ BeginAsyncOut();
+ cout << COLOR_BOLDWHITE "MTU changed: " << COLOR_BOLDYELLOW "[" << address
+ << " ] " << COLOR_BOLDWHITE " - status: " << status
+ << COLOR_BOLDWHITE " - mtu: " << mtu << COLOR_OFF;
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLowEnergyCallback);
+};
+
+class CLIBluetoothLeAdvertiserCallback
+ : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
+ public:
+ CLIBluetoothLeAdvertiserCallback() = default;
+ ~CLIBluetoothLeAdvertiserCallback() override = default;
+
+ // IBluetoothLowEnergyCallback overrides:
+ Status OnAdvertiserRegistered(int status, int advertiser_id) override {
+ BeginAsyncOut();
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ PrintError("Failed to register BLE advertiser");
+ } else {
+ ble_advertiser_id = advertiser_id;
+ cout << COLOR_BOLDWHITE "Registered BLE advertiser with ID: " COLOR_OFF
+ << COLOR_GREEN << advertiser_id << COLOR_OFF;
+ }
+ EndAsyncOut();
+
+ ble_advertiser_registering = false;
+ return Status::ok();
+ }
+
+ Status OnMultiAdvertiseCallback(
+ int status, bool is_start,
+ const android::bluetooth::AdvertiseSettings& /* settings */) {
+ BeginAsyncOut();
+ std::string op = is_start ? "start" : "stop";
+
+ PrintOpStatus("Advertising " + op, status == bluetooth::BLE_STATUS_SUCCESS);
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
+};
+
+class CLIBluetoothLeScannerCallback
+ : public android::bluetooth::BnBluetoothLeScannerCallback {
+ public:
+ CLIBluetoothLeScannerCallback() = default;
+ ~CLIBluetoothLeScannerCallback() override = default;
+
+ // IBluetoothLowEnergyCallback overrides:
+ Status OnScannerRegistered(int status, int scanner_id) override {
+ BeginAsyncOut();
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ PrintError("Failed to register BLE client");
+ } else {
+ ble_scanner_id = scanner_id;
+ cout << COLOR_BOLDWHITE "Registered BLE client with ID: " COLOR_OFF
+ << COLOR_GREEN << scanner_id << COLOR_OFF;
+ }
+ EndAsyncOut();
+
+ ble_scanner_registering = false;
+ return Status::ok();
+ }
+
+ Status OnScanResult(
+ const android::bluetooth::ScanResult& scan_result) override {
+ BeginAsyncOut();
+ cout << COLOR_BOLDWHITE "Scan result: " << COLOR_BOLDYELLOW "["
+ << scan_result.device_address() << "] "
+ << COLOR_BOLDWHITE "- RSSI: " << scan_result.rssi() << COLOR_OFF;
+
+ if (dump_scan_record) {
+ cout << " - Record: "
+ << base::HexEncode(scan_result.scan_record().data(),
+ scan_result.scan_record().size());
+ }
+ EndAsyncOut();
+ return Status::ok();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeScannerCallback);
+};
+
+class CLIGattClientCallback
+ : public android::bluetooth::BnBluetoothGattClientCallback {
+ public:
+ CLIGattClientCallback() = default;
+ ~CLIGattClientCallback() override = default;
+
+ // IBluetoothGattClientCallback overrides:
+ Status OnClientRegistered(int status, int client_id) override {
+ BeginAsyncOut();
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ PrintError("Failed to register GATT client");
+ } else {
+ gatt_client_id = client_id;
+ cout << COLOR_BOLDWHITE "Registered GATT client with ID: " COLOR_OFF
+ << COLOR_GREEN << client_id << COLOR_OFF;
+ }
+ EndAsyncOut();
+
+ gatt_registering = false;
+ return Status::ok();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CLIGattClientCallback);
+};
+
+void PrintCommandStatus(bool status) { PrintOpStatus("Command", status); }
+
+void PrintFieldAndValue(const string& field, const string& value) {
+ cout << COLOR_BOLDWHITE << field << ": " << COLOR_BOLDYELLOW << value
+ << COLOR_OFF << endl;
+}
+
+void PrintFieldAndBoolValue(const string& field, bool value) {
+ PrintFieldAndValue(field, (value ? "true" : "false"));
+}
+
+void HandleDisable(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ bool status;
+ bt_iface->Disable(&status);
+ PrintCommandStatus(status);
+}
+
+void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
+ bool is_restricted_mode = false;
+
+ for (auto iter : args) {
+ const std::string& arg = iter;
+ if (arg == "-h") {
+ static const char kUsage[] =
+ "Usage: start-adv [flags]\n"
+ "\n"
+ "Flags:\n"
+ "\t--restricted|-r\tStart in restricted mode\n";
+ cout << kUsage << endl;
+ return;
+ } else if (arg == "--restricted" || arg == "-r") {
+ is_restricted_mode = true;
+ }
+ }
+
+ bool status;
+ bt_iface->Enable(is_restricted_mode, &status);
+ PrintCommandStatus(status);
+}
+
+void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ int32_t st;
+ bt_iface->GetState(&st);
+ bluetooth::AdapterState state = static_cast<bluetooth::AdapterState>(st);
+ PrintFieldAndValue("Adapter state", bluetooth::AdapterStateToString(state));
+}
+
+void HandleIsEnabled(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ bool enabled;
+ bt_iface->IsEnabled(&enabled);
+ PrintFieldAndBoolValue("Adapter enabled", enabled);
+}
+
+void HandleGetLocalAddress(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ String16 address;
+ bt_iface->GetAddress(&address);
+ PrintFieldAndValue("Adapter address", std::string(String8(address).string()));
+}
+
+void HandleSetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_ARGS_COUNT(args, >=, 1, "No name was given");
+
+ std::string name;
+ for (const auto& arg : args) name += arg + " ";
+
+ base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
+
+ bool status;
+ bt_iface->SetName(String16(String8(name.c_str())), &status);
+ PrintCommandStatus(status);
+}
+
+void HandleGetLocalName(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+ String16 name;
+ bt_iface->GetName(&name);
+ PrintFieldAndValue("Adapter name", std::string(String8(name).string()));
+}
+
+void HandleAdapterInfo(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ cout << COLOR_BOLDWHITE "Adapter Properties: " COLOR_OFF << endl;
+
+ String16 address;
+ bt_iface->GetAddress(&address);
+ PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
+
+ int adapter_state;
+ bt_iface->GetState(&adapter_state);
+ PrintFieldAndValue("\tState",
+ bluetooth::AdapterStateToString(
+ static_cast<bluetooth::AdapterState>(adapter_state)));
+
+ String16 name;
+ bt_iface->GetName(&name);
+ PrintFieldAndValue("\tName", std::string(String8(name).string()));
+
+ bool multi_adv;
+ bt_iface->IsMultiAdvertisementSupported(&multi_adv);
+ PrintFieldAndBoolValue("\tMulti-Adv. supported", multi_adv);
+}
+
+void HandleSupportsMultiAdv(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ bool multi_adv;
+ bt_iface->IsMultiAdvertisementSupported(&multi_adv);
+ PrintFieldAndBoolValue("Multi-advertisement support", multi_adv);
+}
+
+void HandleRegisterBLEAdvertiser(IBluetooth* bt_iface,
+ const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (ble_advertiser_registering.load()) {
+ PrintError("In progress");
+ return;
+ }
+
+ if (ble_advertiser_id.load() != invalid_advertiser_id) {
+ PrintError("Already registered");
+ return;
+ }
+
+ sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+ bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+ if (!ble_advertiser_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Le Advertiser interface");
+ return;
+ }
+
+ bool status;
+ ble_advertiser_iface->RegisterAdvertiser(
+ new CLIBluetoothLeAdvertiserCallback(), &status);
+ ble_advertiser_registering = status;
+ PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLEAdvertiser(IBluetooth* bt_iface,
+ const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (ble_advertiser_id.load() == invalid_advertiser_id) {
+ PrintError("Not registered");
+ return;
+ }
+
+ sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+ bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+ if (!ble_advertiser_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ ble_advertiser_iface->UnregisterAdvertiser(ble_advertiser_id.load());
+ ble_advertiser_id = invalid_advertiser_id;
+ PrintCommandStatus(true);
+}
+
+void HandleRegisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (ble_registering.load()) {
+ PrintError("In progress");
+ return;
+ }
+
+ if (ble_client_id.load()) {
+ PrintError("Already registered");
+ return;
+ }
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ bool status;
+ ble_iface->RegisterClient(new CLIBluetoothLowEnergyCallback(), &status);
+ ble_registering = status;
+ PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLE(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (!ble_client_id.load()) {
+ PrintError("Not registered");
+ return;
+ }
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ ble_iface->UnregisterClient(ble_client_id.load());
+ ble_client_id = 0;
+ PrintCommandStatus(true);
+}
+
+void HandleUnregisterAllBLE(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ ble_iface->UnregisterAll();
+ PrintCommandStatus(true);
+}
+
+void HandleRegisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (gatt_registering.load()) {
+ PrintError("In progress");
+ return;
+ }
+
+ if (gatt_client_id.load()) {
+ PrintError("Already registered");
+ return;
+ }
+
+ sp<IBluetoothGattClient> gatt_iface;
+ bt_iface->GetGattClientInterface(&gatt_iface);
+ if (!gatt_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
+ return;
+ }
+
+ bool status;
+ gatt_iface->RegisterClient(new CLIGattClientCallback(), &status);
+ gatt_registering = status;
+ PrintCommandStatus(status);
+}
+
+void HandleUnregisterGATT(IBluetooth* bt_iface, const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (!gatt_client_id.load()) {
+ PrintError("Not registered");
+ return;
+ }
+
+ sp<IBluetoothGattClient> gatt_iface;
+ bt_iface->GetGattClientInterface(&gatt_iface);
+ if (!gatt_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth GATT Client interface");
+ return;
+ }
+
+ gatt_iface->UnregisterClient(gatt_client_id.load());
+ gatt_client_id = 0;
+ PrintCommandStatus(true);
+}
+
+void HandleStartAdv(IBluetooth* bt_iface, const vector<string>& args) {
+ bool include_name = false;
+ bool include_tx_power = false;
+ bool connectable = false;
+ bool set_manufacturer_data = false;
+ bool set_uuid = false;
+ bluetooth::UUID uuid;
+
+ for (auto iter = args.begin(); iter != args.end(); ++iter) {
+ const std::string& arg = *iter;
+ if (arg == "-n")
+ include_name = true;
+ else if (arg == "-t")
+ include_tx_power = true;
+ else if (arg == "-c")
+ connectable = true;
+ else if (arg == "-m")
+ set_manufacturer_data = true;
+ else if (arg == "-u") {
+ // This flag has a single argument.
+ ++iter;
+ if (iter == args.end()) {
+ PrintError("Expected a UUID after -u");
+ return;
+ }
+
+ std::string uuid_str = *iter;
+ uuid = bluetooth::UUID(uuid_str);
+ if (!uuid.is_valid()) {
+ PrintError("Invalid UUID: " + uuid_str);
+ return;
+ }
+
+ set_uuid = true;
+ } else if (arg == "-h") {
+ static const char kUsage[] =
+ "Usage: start-adv [flags]\n"
+ "\n"
+ "Flags:\n"
+ "\t-n\tInclude device name\n"
+ "\t-t\tInclude TX power\n"
+ "\t-c\tSend connectable adv. packets (default is non-connectable)\n"
+ "\t-m\tInclude random manufacturer data\n"
+ "\t-h\tShow this help message\n";
+ cout << kUsage << endl;
+ return;
+ } else {
+ PrintError("Unrecognized option: " + arg);
+ return;
+ }
+ }
+
+ if (ble_advertiser_id.load() == invalid_advertiser_id) {
+ PrintError("BLE advertiser not registered");
+ return;
+ }
+
+ sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+ bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+ if (!ble_advertiser_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Le Advertiser interface");
+ return;
+ }
+
+ std::vector<uint8_t> data;
+ if (set_manufacturer_data) {
+ data = {{0x07, bluetooth::kEIRTypeManufacturerSpecificData, 0xe0, 0x00, 'T',
+ 'e', 's', 't'}};
+ }
+
+ if (set_uuid) {
+ // Determine the type and length bytes.
+ int uuid_size = uuid.GetShortestRepresentationSize();
+ uint8_t type;
+ if (uuid_size == bluetooth::UUID::kNumBytes128)
+ type = bluetooth::kEIRTypeComplete128BitUUIDs;
+ else if (uuid_size == bluetooth::UUID::kNumBytes32)
+ type = bluetooth::kEIRTypeComplete32BitUUIDs;
+ else if (uuid_size == bluetooth::UUID::kNumBytes16)
+ type = bluetooth::kEIRTypeComplete16BitUUIDs;
+ else
+ NOTREACHED() << "Unexpected size: " << uuid_size;
+
+ data.push_back(uuid_size + 1);
+ data.push_back(type);
+
+ auto uuid_bytes = uuid.GetFullLittleEndian();
+ int index = (uuid_size == 16) ? 0 : 12;
+ data.insert(data.end(), uuid_bytes.data() + index,
+ uuid_bytes.data() + index + uuid_size);
+ }
+
+ base::TimeDelta timeout;
+
+ bluetooth::AdvertiseSettings settings(
+ bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
+ bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
+
+ if (include_tx_power) {
+ data.push_back(0x02);
+ data.push_back(bluetooth::kEIRTypeTxPower);
+ data.push_back(0x00);
+ }
+
+ bluetooth::AdvertiseData adv_data(data);
+
+ if (include_name) {
+ String16 name_param;
+ bt_iface->GetName(&name_param);
+ std::string name(String8(name_param).string());
+ data.push_back(name.length() + 1);
+ data.push_back(bluetooth::kEIRTypeCompleteLocalName);
+ data.insert(data.begin(), name.c_str(), name.c_str() + name.length());
+ }
+
+ bluetooth::AdvertiseData scan_rsp;
+
+ bool status;
+ ble_advertiser_iface->StartMultiAdvertising(
+ ble_advertiser_id.load(), adv_data, scan_rsp, settings, &status);
+ PrintCommandStatus(status);
+}
+
+void HandleStopAdv(IBluetooth* bt_iface, const vector<string>& args) {
+ if (ble_advertiser_id.load() == invalid_advertiser_id) {
+ PrintError("BLE advertiser not registered");
+ return;
+ }
+
+ sp<IBluetoothLeAdvertiser> ble_advertiser_iface;
+ bt_iface->GetLeAdvertiserInterface(&ble_advertiser_iface);
+ if (!ble_advertiser_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ bool status;
+ ble_advertiser_iface->StopMultiAdvertising(ble_advertiser_id.load(), &status);
+ PrintCommandStatus(status);
+}
+
+void HandleConnect(IBluetooth* bt_iface, const vector<string>& args) {
+ string address;
+
+ if (args.size() != 1) {
+ PrintError("Expected MAC address as only argument");
+ return;
+ }
+
+ address = args[0];
+
+ if (!ble_client_id.load()) {
+ PrintError("BLE not registered");
+ return;
+ }
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ bool status;
+ ble_iface->Connect(ble_client_id.load(),
+ String16(address.c_str(), address.length()),
+ false /* is_direct */, &status);
+
+ PrintCommandStatus(status);
+}
+
+void HandleDisconnect(IBluetooth* bt_iface, const vector<string>& args) {
+ string address;
+
+ if (args.size() != 1) {
+ PrintError("Expected MAC address as only argument");
+ return;
+ }
+
+ address = args[0];
+
+ if (!ble_client_id.load()) {
+ PrintError("BLE not registered");
+ return;
+ }
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ bool status;
+ ble_iface->Disconnect(ble_client_id.load(),
+ String16(address.c_str(), address.length()), &status);
+ PrintCommandStatus(status);
+}
+
+void HandleSetMtu(IBluetooth* bt_iface, const vector<string>& args) {
+ string address;
+ int mtu;
+
+ if (args.size() != 2) {
+ PrintError("Usage: set-mtu [address] [mtu]");
+ return;
+ }
+
+ address = args[0];
+ mtu = std::stoi(args[1]);
+
+ if (mtu < 23) {
+ PrintError("MTU must be 23 or larger");
+ return;
+ }
+
+ if (!ble_client_id.load()) {
+ PrintError("BLE not registered");
+ return;
+ }
+
+ sp<IBluetoothLowEnergy> ble_iface;
+ bt_iface->GetLowEnergyInterface(&ble_iface);
+ if (!ble_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth Low Energy interface");
+ return;
+ }
+
+ bool status;
+ ble_iface->SetMtu(ble_client_id.load(),
+ String16(address.c_str(), address.length()), mtu, &status);
+ PrintCommandStatus(status);
+}
+
+void HandleRegisterBLEScanner(IBluetooth* bt_iface,
+ const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (ble_scanner_registering.load()) {
+ PrintError("In progress");
+ return;
+ }
+
+ if (ble_scanner_id.load()) {
+ PrintError("Already registered");
+ return;
+ }
+
+ sp<IBluetoothLeScanner> ble_scanner_iface;
+ bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+ if (!ble_scanner_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth LE Scanner interface");
+ return;
+ }
+
+ bool status;
+ ble_scanner_iface->RegisterScanner(new CLIBluetoothLeScannerCallback(),
+ &status);
+ ble_scanner_registering = status;
+ PrintCommandStatus(status);
+}
+
+void HandleUnregisterBLEScanner(IBluetooth* bt_iface,
+ const vector<string>& args) {
+ CHECK_NO_ARGS(args);
+
+ if (!ble_scanner_id.load()) {
+ PrintError("Not registered");
+ return;
+ }
+
+ sp<IBluetoothLeScanner> ble_scanner_iface;
+ bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+ if (!ble_scanner_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+ return;
+ }
+
+ ble_scanner_iface->UnregisterScanner(ble_scanner_id.load());
+ ble_scanner_id = 0;
+ PrintCommandStatus(true);
+}
+
+void HandleStartLeScan(IBluetooth* bt_iface, const vector<string>& args) {
+ if (!ble_client_id.load()) {
+ PrintError("BLE not registered");
+ return;
+ }
+
+ for (const auto& arg : args) {
+ if (arg == "-d") {
+ dump_scan_record = true;
+ } else if (arg == "-h") {
+ static const char kUsage[] =
+ "Usage: start-le-scan [flags]\n"
+ "\n"
+ "Flags:\n"
+ "\t-d\tDump scan record\n"
+ "\t-h\tShow this help message\n";
+ cout << kUsage << endl;
+ return;
+ }
+ }
+
+ sp<IBluetoothLeScanner> ble_scanner_iface;
+ bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+ if (!ble_scanner_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+ return;
+ }
+
+ bluetooth::ScanSettings settings;
+ std::vector<android::bluetooth::ScanFilter> filters;
+
+ bool status;
+ ble_scanner_iface->StartScan(ble_scanner_id.load(), settings, filters,
+ &status);
+ PrintCommandStatus(status);
+}
+
+void HandleStopLeScan(IBluetooth* bt_iface, const vector<string>& args) {
+ if (!ble_client_id.load()) {
+ PrintError("BLE not registered");
+ return;
+ }
+
+ sp<IBluetoothLeScanner> ble_scanner_iface;
+ bt_iface->GetLeScannerInterface(&ble_scanner_iface);
+ if (!ble_scanner_iface.get()) {
+ PrintError("Failed to obtain handle to Bluetooth LE scanner interface");
+ return;
+ }
+
+ bool status;
+ ble_scanner_iface->StopScan(ble_scanner_id.load(), &status);
+ PrintCommandStatus(status);
+}
+
+void HandleHelp(IBluetooth* bt_iface, const vector<string>& args);
+
+struct {
+ string command;
+ void (*func)(IBluetooth*, const vector<string>& args);
+ string help;
+} kCommandMap[] = {
+ {"help", HandleHelp, "\t\t\tDisplay this message"},
+ {"disable", HandleDisable, "\t\t\tDisable Bluetooth"},
+ {"enable", HandleEnable, "\t\t\tEnable Bluetooth (-h for options)"},
+ {"get-state", HandleGetState, "\t\tGet the current adapter state"},
+ {"is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled"},
+ {"get-local-address", HandleGetLocalAddress,
+ "\tGet the local adapter address"},
+ {"set-local-name", HandleSetLocalName, "\t\tSet the local adapter name"},
+ {"get-local-name", HandleGetLocalName, "\t\tGet the local adapter name"},
+ {"adapter-info", HandleAdapterInfo, "\t\tPrint adapter properties"},
+ {"supports-multi-adv", HandleSupportsMultiAdv,
+ "\tWhether multi-advertisement is currently supported"},
+ {"register-le-advertiser", HandleRegisterBLEAdvertiser,
+ "\t\tRegister with the Bluetooth Low Energy Advertiser interface"},
+ {"unregister-le-advertiser", HandleUnregisterBLEAdvertiser,
+ "\t\tUnregister from the Bluetooth LE Advertiser interface"},
+ {"register-ble", HandleRegisterBLE,
+ "\t\tRegister with the Bluetooth Low Energy interface"},
+ {"unregister-ble", HandleUnregisterBLE,
+ "\t\tUnregister from the Bluetooth Low Energy interface"},
+ {"unregister-all-ble", HandleUnregisterAllBLE,
+ "\tUnregister all clients from the Bluetooth Low Energy interface"},
+ {"register-gatt", HandleRegisterGATT,
+ "\t\tRegister with the Bluetooth GATT Client interface"},
+ {"unregister-gatt", HandleUnregisterGATT,
+ "\t\tUnregister from the Bluetooth GATT Client interface"},
+ {"connect-le", HandleConnect, "\t\tConnect to LE device (-h for options)"},
+ {"disconnect-le", HandleDisconnect,
+ "\t\tDisconnect LE device (-h for options)"},
+ {"set-mtu", HandleSetMtu, "\t\tSet MTU (-h for options)"},
+ {"start-adv", HandleStartAdv, "\t\tStart advertising (-h for options)"},
+ {"stop-adv", HandleStopAdv, "\t\tStop advertising"},
+ {"register-le-scanner", HandleRegisterBLEScanner,
+ "\t\tRegister with the Bluetooth Low Energy scanner interface"},
+ {"unregister-le-scanner", HandleUnregisterBLEScanner,
+ "\t\tUnregister from the Bluetooth LE scanner interface"},
+ {"start-le-scan", HandleStartLeScan,
+ "\t\tStart LE device scan (-h for options)"},
+ {"stop-le-scan", HandleStopLeScan, "\t\tStop LE device scan"},
+ {},
+};
+
+void HandleHelp(IBluetooth* /* bt_iface */, const vector<string>& /* args */) {
+ cout << endl;
+ for (int i = 0; kCommandMap[i].func; i++)
+ cout << "\t" << kCommandMap[i].command << kCommandMap[i].help << endl;
+ cout << endl;
+}
+
+const char kExecuteLong[] = "exec";
+const char kExecuteShort[] = "e";
+
+bool ExecuteCommand(const sp<IBluetooth>& bt_iface, std::string& command) {
+ vector<string> args = base::SplitString(command, " ", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL);
+
+ if (args.empty()) return true;
+
+ // The first argument is the command while the remaining are what we pass to
+ // the handler functions.
+ command = args[0];
+ args.erase(args.begin());
+
+ for (int i = 0; kCommandMap[i].func; i++) {
+ if (command == kCommandMap[i].command) {
+ kCommandMap[i].func(bt_iface.get(), args);
+ return true;
+ }
+ }
+
+ cout << "Unrecognized command: " << command << endl;
+ return false;
+}
+
+} // namespace
+
+class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ BluetoothDeathRecipient() = default;
+ ~BluetoothDeathRecipient() override = default;
+
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& /* who */) override {
+ BeginAsyncOut();
+ cout << COLOR_BOLDWHITE "The Bluetooth daemon has died" COLOR_OFF << endl;
+ cout << "\nPress 'ENTER' to exit.";
+ EndAsyncOut();
+
+ android::IPCThreadState::self()->stopProcess();
+ should_exit = true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeathRecipient);
+};
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ logging::LoggingSettings log_settings;
+
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ return EXIT_FAILURE;
+ }
+
+ sp<IBluetooth> bt_iface;
+ status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
+ if (status != OK) {
+ LOG(ERROR) << "Failed to get service binder: '" << kServiceName
+ << "' status=" << status;
+ return EXIT_FAILURE;
+ }
+
+ sp<BluetoothDeathRecipient> dr(new BluetoothDeathRecipient());
+ if (android::IInterface::asBinder(bt_iface.get())->linkToDeath(dr) !=
+ android::NO_ERROR) {
+ LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the Binder process thread pool. We have to set this up,
+ // otherwise, incoming callbacks from IBluetoothCallback will block the main
+ // thread (in other words, we have to do this as we are a "Binder server").
+ android::ProcessState::self()->startThreadPool();
+
+ // Register Adapter state-change callback
+ sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
+ bt_iface->RegisterCallback(callback);
+
+ cout << COLOR_BOLDWHITE << "Fluoride Command-Line Interface\n"
+ << COLOR_OFF << endl
+ << "Type \"help\" to see possible commands.\n"
+ << endl;
+
+ string command;
+
+ // Add commands from the command line, if they exist.
+ auto command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(kExecuteLong)) {
+ command += command_line->GetSwitchValueASCII(kExecuteLong);
+ }
+
+ if (command_line->HasSwitch(kExecuteShort)) {
+ if (!command.empty()) command += " ; ";
+ command += command_line->GetSwitchValueASCII(kExecuteShort);
+ }
+
+ while (true) {
+ vector<string> commands = base::SplitString(
+ command, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ for (string command : commands) {
+ if (!ExecuteCommand(bt_iface, command)) break;
+ }
+
+ commands.clear();
+
+ PrintPrompt();
+
+ showing_prompt = true;
+ auto& istream = getline(cin, command);
+ showing_prompt = false;
+
+ if (istream.eof() || should_exit.load()) {
+ cout << "\nExiting" << endl;
+ return EXIT_SUCCESS;
+ }
+
+ if (!istream.good()) {
+ LOG(ERROR) << "An error occured while reading input";
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/mtkbt/code/bt/service/common/README b/mtkbt/code/bt/service/common/README
new file mode 100755
index 0000000..de9e914
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/README
@@ -0,0 +1,18 @@
+This directory contains all the "common" sources between the bluetooth daemon
+and our client library. All source files here are under the "bluetooth"
+subdirectory, which is the exported root path for the client static library.
+Only common files should go here. All headers that go into common/bluetooth must
+only include other headers from common/bluetooth and must use "bluetooth" as the
+root path, e.g.:
+
+#include <bluetooth/uuid.h>
+
+This is so that client applications that link against the client library have
+one common include path exported to them, and our headers can find eachother
+within that.
+
+It is however OK to include from the package root when including common headers
+from source files as these are pre-compiled. For example,
+common/bluetooth/adapter_state.cpp should do:
+
+#include "service/common/bluetooth/adapter_state.h"
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseData.aidl b/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseData.aidl
new file mode 100755
index 0000000..3005670
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable AdvertiseData cpp_header "android/bluetooth/advertise_data.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseSettings.aidl b/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseSettings.aidl
new file mode 100755
index 0000000..f479e5a
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/AdvertiseSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable AdvertiseSettings cpp_header "android/bluetooth/advertise_settings.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
new file mode 100755
index 0000000..5f3f729
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattCharacteristic.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattCharacteristic cpp_header "android/bluetooth/bluetooth_gatt_characteristic.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
new file mode 100755
index 0000000..51af33e
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattDescriptor cpp_header "android/bluetooth/bluetooth_gatt_descriptor.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
new file mode 100755
index 0000000..0ee3f63
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattIncludedService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattIncludedService cpp_header "android/bluetooth/bluetooth_gatt_included_service.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattService.aidl b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattService.aidl
new file mode 100755
index 0000000..92bdfe0
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/BluetoothGattService.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothGattService cpp_header "android/bluetooth/bluetooth_gatt_service.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetooth.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetooth.aidl
new file mode 100755
index 0000000..1e96952
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetooth.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothLowEnergy;
+import android.bluetooth.IBluetoothLeAdvertiser;
+import android.bluetooth.IBluetoothLeScanner;
+import android.bluetooth.IBluetoothGattClient;
+import android.bluetooth.IBluetoothGattServer;
+
+import android.bluetooth.UUID;
+
+interface IBluetooth {
+ boolean IsEnabled();
+ int GetState();
+ boolean Enable(boolean startRestricted);
+ boolean EnableNoAutoConnect();
+ boolean Disable();
+
+ String GetAddress();
+ UUID[] GetUUIDs();
+ boolean SetName(String name);
+ String GetName();
+
+ void RegisterCallback(IBluetoothCallback callback);
+ void UnregisterCallback(IBluetoothCallback callback);
+
+ boolean IsMultiAdvertisementSupported();
+
+ IBluetoothLowEnergy GetLowEnergyInterface();
+ IBluetoothLeAdvertiser GetLeAdvertiserInterface();
+ IBluetoothLeScanner GetLeScannerInterface();
+ IBluetoothGattClient GetGattClientInterface();
+ IBluetoothGattServer GetGattServerInterface();
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothCallback.aidl
new file mode 100755
index 0000000..24ac89b
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothCallback {
+ void OnBluetoothStateChange(int prev_state, int new_state);
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl
new file mode 100755
index 0000000..ccd05b0
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClient.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothGattClientCallback;
+
+interface IBluetoothGattClient {
+
+ boolean RegisterClient(in IBluetoothGattClientCallback callback);
+ void UnregisterClient(int client_id);
+ void UnregisterAll();
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
new file mode 100755
index 0000000..94dec9d
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattClientCallback.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+oneway interface IBluetoothGattClientCallback {
+ void OnClientRegistered(int status, int client_id);
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl
new file mode 100755
index 0000000..50d0a82
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServer.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.IBluetoothGattServerCallback;
+import android.bluetooth.UUID;
+
+interface IBluetoothGattServer {
+
+ boolean RegisterServer(in IBluetoothGattServerCallback callback);
+ void UnregisterServer(int server_id);
+ void UnregisterAll();
+
+ boolean AddService(int server_id, in BluetoothGattService service);
+
+ boolean SendResponse(
+ int server_id,
+ String device_address,
+ int request_id,
+ int status, int offset,
+ in byte[] value);
+
+ boolean SendNotification(
+ int server_id,
+ String device_address,
+ int handle,
+ boolean confirm,
+ in byte[] value);
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
new file mode 100755
index 0000000..06340d0
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothGattServerCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothGattService;
+
+oneway interface IBluetoothGattServerCallback {
+ void OnServerRegistered(int status, int server_id);
+
+ void OnServiceAdded(int status, in BluetoothGattService service);
+
+ void OnCharacteristicReadRequest(String device_address,
+ int request_id, int offset, boolean is_long, int handle);
+
+ void OnDescriptorReadRequest(String device_address,
+ int request_id, int offset, boolean is_long, int handle);
+
+ void OnCharacteristicWriteRequest(String device_address,
+ int request_id, int offset, boolean is_prepare_write, boolean need_response,
+ in byte[] value, int handle);
+
+ void OnDescriptorWriteRequest(String device_address,
+ int request_id, int offset, boolean is_prepare_write, boolean need_response,
+ in byte[] value, int handle);
+
+ void OnExecuteWriteRequest(String device_address,
+ int request_id, boolean is_execute);
+
+ void OnNotificationSent(String device_address,
+ int status);
+
+ void OnConnectionStateChanged(String device_address, boolean connected);
+ }
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
new file mode 100755
index 0000000..5435af3
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiser.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLeAdvertiserCallback;
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+
+interface IBluetoothLeAdvertiser {
+ boolean RegisterAdvertiser(in IBluetoothLeAdvertiserCallback callback);
+ void UnregisterAdvertiser(int advertiser_id);
+ void UnregisterAll();
+
+ boolean StartMultiAdvertising(
+ int advertiser_id,
+ in AdvertiseData advertise_data,
+ in AdvertiseData scan_response,
+ in AdvertiseSettings settings);
+ boolean StopMultiAdvertising(int advertiser_id);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
new file mode 100755
index 0000000..d51657e
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeAdvertiserCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.AdvertiseSettings;
+
+oneway interface IBluetoothLeAdvertiserCallback {
+ void OnAdvertiserRegistered(int status, int advertiser_id);
+ void OnMultiAdvertiseCallback(int status, boolean is_start, in AdvertiseSettings settings);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl
new file mode 100755
index 0000000..2f9506d
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScanner.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLeScannerCallback;
+import android.bluetooth.ScanFilter;
+import android.bluetooth.ScanSettings;
+
+interface IBluetoothLeScanner {
+ boolean RegisterScanner(in IBluetoothLeScannerCallback callback);
+ void UnregisterScanner(int scanner_id);
+ void UnregisterAll();
+
+ boolean StartScan(int client_id,
+ in ScanSettings settings,
+ in ScanFilter[] filters);
+ boolean StopScan(int client_id);
+}
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
new file mode 100755
index 0000000..4ee6be3
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLeScannerCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.ScanResult;
+
+oneway interface IBluetoothLeScannerCallback {
+ void OnScannerRegistered(int status, int client_id);
+ void OnScanResult(in ScanResult scan_result);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
new file mode 100755
index 0000000..4d49430
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergy.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetoothLowEnergyCallback;
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+
+interface IBluetoothLowEnergy {
+ boolean RegisterClient(in IBluetoothLowEnergyCallback callback);
+ void UnregisterClient(int client_if);
+ void UnregisterAll();
+
+ boolean Connect(int client_id, String address, boolean is_direct);
+ boolean Disconnect(int client_id, String address);
+
+ boolean SetMtu(int client_id, String address, int mtu);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
new file mode 100755
index 0000000..858506a
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/IBluetoothLowEnergyCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.ScanResult;
+import android.bluetooth.AdvertiseSettings;
+
+oneway interface IBluetoothLowEnergyCallback {
+ void OnClientRegistered(int status, int client_id);
+ void OnConnectionState(int status, int client_id, String address, boolean connected);
+ void OnMtuChanged(int status, String address, int mtu);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/ScanFilter.aidl b/mtkbt/code/bt/service/common/android/bluetooth/ScanFilter.aidl
new file mode 100755
index 0000000..2787a99
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/ScanFilter.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanFilter cpp_header "android/bluetooth/scan_filter.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/ScanResult.aidl b/mtkbt/code/bt/service/common/android/bluetooth/ScanResult.aidl
new file mode 100755
index 0000000..7ba2df5
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/ScanResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanResult cpp_header "android/bluetooth/scan_result.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/ScanSettings.aidl b/mtkbt/code/bt/service/common/android/bluetooth/ScanSettings.aidl
new file mode 100755
index 0000000..3b11b24
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/ScanSettings.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable ScanSettings cpp_header "android/bluetooth/scan_settings.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/UUID.aidl b/mtkbt/code/bt/service/common/android/bluetooth/UUID.aidl
new file mode 100755
index 0000000..54f993f
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/UUID.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable UUID cpp_header "android/bluetooth/uuid.h";
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.cc b/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.cc
new file mode 100755
index 0000000..07eb50a
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.cc
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/advertise_data.h"
+
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t AdvertiseData::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeByteVector(data_);
+ return status;
+}
+
+status_t AdvertiseData::readFromParcel(const Parcel* parcel) {
+ status_t status = parcel->readByteVector(&data_);
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.h b/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.h
new file mode 100755
index 0000000..cde0eac
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/advertise_data.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/advertise_data.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class AdvertiseData : public Parcelable, public ::bluetooth::AdvertiseData {
+ public:
+ // NOLINT, implicit converter
+ AdvertiseData(const ::bluetooth::AdvertiseData& advertise_data) // NOLINT
+ : ::bluetooth::AdvertiseData(advertise_data){};
+ AdvertiseData() = default;
+ ~AdvertiseData() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.cc b/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.cc
new file mode 100755
index 0000000..b8fb1d1
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.cc
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "android/bluetooth/advertise_settings.h"
+
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t AdvertiseSettings::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(mode_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(tx_power_level_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(connectable_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(timeout_.InMilliseconds());
+ return status;
+}
+
+status_t AdvertiseSettings::readFromParcel(const Parcel* parcel) {
+ int32_t value;
+ status_t status = parcel->readInt32(&value);
+ if (status != OK) return status;
+
+ mode_ = static_cast<AdvertiseSettings::Mode>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+
+ tx_power_level_ = static_cast<AdvertiseSettings::TxPowerLevel>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+
+ connectable_ = static_cast<bool>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+
+ timeout_ = ::base::TimeDelta::FromMilliseconds(value);
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.h b/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.h
new file mode 100755
index 0000000..afca233
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/advertise_settings.h
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/advertise_settings.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class AdvertiseSettings : public Parcelable,
+ public ::bluetooth::AdvertiseSettings {
+ public:
+ // NOLINT, implicit converter
+ AdvertiseSettings(
+ const ::bluetooth::AdvertiseSettings& advertise_settings) // NOLINT
+ : ::bluetooth::AdvertiseSettings(advertise_settings){};
+ AdvertiseSettings() = default;
+ ~AdvertiseSettings() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
new file mode 100755
index 0000000..cf1fb2f
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.cc
@@ -0,0 +1,84 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattCharacteristic::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(handle_);
+ if (status != OK) return status;
+
+ status = parcel->writeParcelable((UUID)uuid_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(properties_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(permissions_);
+ if (status != OK) return status;
+
+ std::vector<BluetoothGattDescriptor> descriptors;
+ for (const auto& desc : descriptors_) {
+ descriptors.push_back(desc);
+ }
+
+ status = parcel->writeParcelableVector(descriptors);
+ return status;
+}
+
+status_t BluetoothGattCharacteristic::readFromParcel(const Parcel* parcel) {
+ int32_t tmp;
+ status_t status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ handle_ = tmp;
+
+ UUID uuid;
+ status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ uuid_ = uuid;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ properties_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ permissions_ = tmp;
+
+ std::vector<BluetoothGattDescriptor> descriptors;
+ status = parcel->readParcelableVector(&descriptors);
+ if (status != OK) return status;
+
+ for (const auto& desc : descriptors) {
+ descriptors_.push_back(desc);
+ }
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
new file mode 100755
index 0000000..9884d99
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_characteristic.h
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/characteristic.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattCharacteristic : public Parcelable,
+ public ::bluetooth::Characteristic {
+ public:
+ BluetoothGattCharacteristic() = default;
+ BluetoothGattCharacteristic(
+ const ::bluetooth::Characteristic& characteristic) // NOLINT(implicit)
+ : ::bluetooth::Characteristic(characteristic){};
+ ~BluetoothGattCharacteristic() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
new file mode 100755
index 0000000..7749404
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.cc
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattDescriptor::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeParcelable((UUID)uuid_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(handle_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(permissions_);
+ return status;
+}
+
+status_t BluetoothGattDescriptor::readFromParcel(const Parcel* parcel) {
+ UUID uuid;
+ status_t status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ uuid_ = (bluetooth::UUID)uuid;
+
+ int32_t tmp;
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ handle_ = tmp;
+
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ permissions_ = tmp;
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
new file mode 100755
index 0000000..955c645
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_descriptor.h
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/descriptor.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattDescriptor : public Parcelable,
+ public ::bluetooth::Descriptor {
+ public:
+ BluetoothGattDescriptor() = default;
+ BluetoothGattDescriptor(
+ const ::bluetooth::Descriptor& characteristic) // NOLINT(implicit)
+ : ::bluetooth::Descriptor(characteristic){};
+ ~BluetoothGattDescriptor() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
new file mode 100755
index 0000000..02dc546
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.cc
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattIncludedService::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeParcelable((UUID)uuid_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(handle_);
+ if (status != OK) return status;
+
+ status = parcel->writeBool(primary_);
+ return status;
+}
+
+status_t BluetoothGattIncludedService::readFromParcel(const Parcel* parcel) {
+ UUID uuid;
+ status_t status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ uuid_ = uuid;
+
+ int32_t tmp;
+ status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ handle_ = tmp;
+
+ status = parcel->readBool(&primary_);
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h
new file mode 100755
index 0000000..3a00a19
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_included_service.h
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/service.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+using ::bluetooth::UUID;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattIncludedService : public Parcelable {
+ public:
+ BluetoothGattIncludedService() = default;
+ BluetoothGattIncludedService(
+ const ::bluetooth::Service& service) // NOLINT(implicit)
+ : handle_(service.handle()),
+ uuid_(service.uuid()),
+ primary_(service.primary()){};
+ ~BluetoothGattIncludedService() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ uint16_t handle() const { return handle_; }
+ bool primary() const { return primary_; }
+ UUID uuid() const { return uuid_; }
+
+ protected:
+ uint16_t handle_;
+ UUID uuid_;
+ bool primary_;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc
new file mode 100755
index 0000000..f4915cb
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.cc
@@ -0,0 +1,86 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::OK;
+using android::String8;
+using android::String16;
+
+namespace android {
+namespace bluetooth {
+
+status_t BluetoothGattService::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(handle_);
+ if (status != OK) return status;
+
+ status = parcel->writeBool(primary_);
+ if (status != OK) return status;
+
+ status = parcel->writeParcelable((UUID)uuid_);
+ if (status != OK) return status;
+
+ std::vector<BluetoothGattCharacteristic> characteristics;
+ for (const auto& chrc : characteristics_) characteristics.push_back(chrc);
+
+ status = parcel->writeParcelableVector(characteristics);
+
+ std::vector<BluetoothGattIncludedService> includedServices;
+ for (const auto& service : included_services_)
+ includedServices.push_back(service);
+
+ status = parcel->writeParcelableVector(includedServices);
+
+ return status;
+}
+
+status_t BluetoothGattService::readFromParcel(const Parcel* parcel) {
+ int32_t tmp;
+ status_t status = parcel->readInt32(&tmp);
+ if (status != OK) return status;
+ handle_ = tmp;
+
+ status = parcel->readBool(&primary_);
+ if (status != OK) return status;
+
+ UUID uuid;
+ status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ uuid_ = uuid;
+
+ std::vector<BluetoothGattCharacteristic> characteristics;
+ status = parcel->readParcelableVector(&characteristics);
+ if (status != OK) return status;
+
+ for (const auto& chrc : characteristics) characteristics_.push_back(chrc);
+
+ std::vector<BluetoothGattIncludedService> includedServices;
+ status = parcel->readParcelableVector(&includedServices);
+ if (status != OK) return status;
+
+ for (const auto& srvc : includedServices)
+ included_services_.push_back(BluetoothGattService(srvc));
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.h b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.h
new file mode 100755
index 0000000..932d4fb
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/bluetooth_gatt_service.h
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "android/bluetooth/bluetooth_gatt_included_service.h"
+#include "bluetooth/service.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class BluetoothGattService : public Parcelable, public ::bluetooth::Service {
+ public:
+ BluetoothGattService() = default;
+ BluetoothGattService(const ::bluetooth::Service& service)
+ : ::bluetooth::Service(service){}; // NOLINT(implicit)
+ BluetoothGattService(
+ const BluetoothGattIncludedService& includedService) // NOLINT(implicit)
+ : ::bluetooth::Service(includedService.handle(),
+ includedService.primary(), includedService.uuid(),
+ {}, {}){};
+ ~BluetoothGattService() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.cc b/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.cc
new file mode 100755
index 0000000..bf9eaf2
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.cc
@@ -0,0 +1,93 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/scan_filter.h"
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String8;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanFilter::writeToParcel(Parcel* parcel) const {
+ status_t status =
+ parcel->writeString16(String16(String8(device_name_.c_str())));
+ if (status != OK) return status;
+
+ status = parcel->writeString16(String16(String8(device_address_.c_str())));
+ if (status != OK) return status;
+
+ // TODO(jpawlowski) make type casting nicer
+ // uuid won't really keep ownership, it's just for type casting
+ std::unique_ptr<UUID> uuid;
+ UUID tmp;
+
+ if (service_uuid_) {
+ tmp = *service_uuid_;
+ uuid.reset(&tmp);
+ } else {
+ uuid.reset(nullptr);
+ }
+ status = parcel->writeNullableParcelable(uuid);
+ uuid.release();
+ if (status != OK) return status;
+
+ if (service_uuid_mask_) {
+ tmp = *service_uuid_mask_;
+ uuid.reset(&tmp);
+ } else {
+ uuid.reset(nullptr);
+ }
+ status = parcel->writeNullableParcelable(uuid);
+ uuid.release();
+
+ return status;
+}
+
+status_t ScanFilter::readFromParcel(const Parcel* parcel) {
+ String16 name;
+ status_t status = parcel->readString16(&name);
+ if (status != OK) return status;
+ device_name_ = std::string(String8(name).string());
+
+ String16 addr;
+ status = parcel->readString16(&addr);
+ if (status != OK) return status;
+ device_address_ = std::string(String8(addr).string());
+
+ std::unique_ptr<UUID> uuid;
+ status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ service_uuid_ = std::move(uuid);
+
+ status = parcel->readParcelable(&uuid);
+ if (status != OK) return status;
+ service_uuid_mask_ = std::move(uuid);
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.h b/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.h
new file mode 100755
index 0000000..c14f392
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_filter.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/scan_filter.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanFilter : public Parcelable, public ::bluetooth::ScanFilter {
+ public:
+ ScanFilter() = default;
+ // NOLINT, implicit converter
+ ScanFilter(const ::bluetooth::ScanFilter& scan_filter) // NOLINT
+ : ::bluetooth::ScanFilter(scan_filter){};
+ ~ScanFilter() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_result.cc b/mtkbt/code/bt/service/common/android/bluetooth/scan_result.cc
new file mode 100755
index 0000000..17378df
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_result.cc
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/scan_result.h"
+
+#include <base/logging.h>
+#include <binder/Parcel.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String8;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanResult::writeToParcel(Parcel* parcel) const {
+ status_t status =
+ parcel->writeString16(String16(String8(device_address_.c_str())));
+ if (status != OK) return status;
+
+ status = parcel->writeByteVector(scan_record_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(rssi_);
+ return status;
+}
+
+status_t ScanResult::readFromParcel(const Parcel* parcel) {
+ String16 addr;
+ status_t status = parcel->readString16(&addr);
+ if (status != OK) return status;
+ device_address_ = std::string(String8(addr).string());
+
+ status = parcel->readByteVector(&scan_record_);
+ if (status != OK) return status;
+
+ status = parcel->readInt32(&rssi_);
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_result.h b/mtkbt/code/bt/service/common/android/bluetooth/scan_result.h
new file mode 100755
index 0000000..732ef0c
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_result.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/scan_result.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanResult : public Parcelable, public ::bluetooth::ScanResult {
+ public:
+ ScanResult() = default;
+ // NOLINT, implicit converter
+ ScanResult(const ::bluetooth::ScanResult& scan_result) // NOLINT
+ : ::bluetooth::ScanResult(scan_result){};
+ ~ScanResult() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.cc b/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.cc
new file mode 100755
index 0000000..0920cca
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.cc
@@ -0,0 +1,80 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/scan_settings.h"
+
+#include <binder/Parcel.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t ScanSettings::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(mode_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(callback_type_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(result_type_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt64(report_delay_ms_.InMilliseconds());
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(match_mode_);
+ if (status != OK) return status;
+
+ status = parcel->writeInt32(match_count_per_filter_);
+ return status;
+}
+
+status_t ScanSettings::readFromParcel(const Parcel* parcel) {
+ int value;
+ status_t status = parcel->readInt32(&value);
+ if (status != OK) return status;
+ mode_ = static_cast<ScanSettings::Mode>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+ callback_type_ = static_cast<ScanSettings::CallbackType>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+ result_type_ = static_cast<ScanSettings::ResultType>(value);
+
+ int64_t value64;
+ status = parcel->readInt64(&value64);
+ report_delay_ms_ = ::base::TimeDelta::FromMilliseconds(value64);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+ match_mode_ = static_cast<ScanSettings::MatchMode>(value);
+
+ status = parcel->readInt32(&value);
+ if (status != OK) return status;
+ match_count_per_filter_ = static_cast<ScanSettings::MatchCount>(value);
+
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.h b/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.h
new file mode 100755
index 0000000..14b8bd5
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/scan_settings.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/scan_settings.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class ScanSettings : public Parcelable, public ::bluetooth::ScanSettings {
+ public:
+ ScanSettings() = default;
+ // NOLINT, implicit converter
+ ScanSettings(const ::bluetooth::ScanSettings& scan_settings) // NOLINT
+ : ::bluetooth::ScanSettings(scan_settings){};
+ ~ScanSettings() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/uuid.cc b/mtkbt/code/bt/service/common/android/bluetooth/uuid.cc
new file mode 100755
index 0000000..6d03bb6
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/uuid.cc
@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/android/bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+
+using android::Parcelable;
+using android::Parcel;
+using android::String16;
+using android::status_t;
+using android::OK;
+
+namespace android {
+namespace bluetooth {
+
+status_t UUID::writeToParcel(Parcel* parcel) const {
+ // The scheme used by android.os.ParcelUuid is to wrote the most significant
+ // bits first as one 64-bit integer, followed by the least significant bits in
+ // a second 64-bit integer. This is the same as writing the raw-bytes in
+ // sequence, but we don't want to assume any host-endianness here. So follow
+ // the same scheme and use the same Parcel APIs.
+ UUID::UUID128Bit bytes = GetFullBigEndian();
+
+ uint64_t most_sig_bits =
+ ((((uint64_t)bytes[0]) << 56) | (((uint64_t)bytes[1]) << 48) |
+ (((uint64_t)bytes[2]) << 40) | (((uint64_t)bytes[3]) << 32) |
+ (((uint64_t)bytes[4]) << 24) | (((uint64_t)bytes[5]) << 16) |
+ (((uint64_t)bytes[6]) << 8) | bytes[7]);
+
+ uint64_t least_sig_bits =
+ ((((uint64_t)bytes[8]) << 56) | (((uint64_t)bytes[9]) << 48) |
+ (((uint64_t)bytes[10]) << 40) | (((uint64_t)bytes[11]) << 32) |
+ (((uint64_t)bytes[12]) << 24) | (((uint64_t)bytes[13]) << 16) |
+ (((uint64_t)bytes[14]) << 8) | bytes[15]);
+
+ status_t status = parcel->writeUint64(most_sig_bits);
+ if (status != OK) return status;
+
+ status = parcel->writeUint64(least_sig_bits);
+ return status;
+}
+
+status_t UUID::readFromParcel(const Parcel* parcel) {
+ UUID::UUID128Bit bytes;
+
+ uint64_t most_sig_bits, least_sig_bits;
+ status_t status = parcel->readUint64(&most_sig_bits);
+ if (status != OK) return status;
+
+ status = parcel->readUint64(&least_sig_bits);
+ if (status != OK) return status;
+
+ bytes[0] = (most_sig_bits >> 56) & 0xFF;
+ bytes[1] = (most_sig_bits >> 48) & 0xFF;
+ bytes[2] = (most_sig_bits >> 40) & 0xFF;
+ bytes[3] = (most_sig_bits >> 32) & 0xFF;
+ bytes[4] = (most_sig_bits >> 24) & 0xFF;
+ bytes[5] = (most_sig_bits >> 16) & 0xFF;
+ bytes[6] = (most_sig_bits >> 8) & 0xFF;
+ bytes[7] = most_sig_bits & 0xFF;
+
+ bytes[8] = (least_sig_bits >> 56) & 0xFF;
+ bytes[9] = (least_sig_bits >> 48) & 0xFF;
+ bytes[10] = (least_sig_bits >> 40) & 0xFF;
+ bytes[11] = (least_sig_bits >> 32) & 0xFF;
+ bytes[12] = (least_sig_bits >> 24) & 0xFF;
+ bytes[13] = (least_sig_bits >> 16) & 0xFF;
+ bytes[14] = (least_sig_bits >> 8) & 0xFF;
+ bytes[15] = least_sig_bits & 0xFF;
+
+ id_ = bytes;
+ is_valid_ = true;
+ return status;
+}
+
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/android/bluetooth/uuid.h b/mtkbt/code/bt/service/common/android/bluetooth/uuid.h
new file mode 100755
index 0000000..c0a09e0
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/android/bluetooth/uuid.h
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include "bluetooth/uuid.h"
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+
+namespace android {
+namespace bluetooth {
+
+class UUID : public Parcelable, public ::bluetooth::UUID {
+ public:
+ UUID() = default;
+ // NOLINT, implicit converter
+ UUID(const ::bluetooth::UUID& uuid) : ::bluetooth::UUID(uuid){}; // NOLINT
+ ~UUID() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t writeToParcel(Parcel* parcel) const override;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ status_t readFromParcel(const Parcel* parcel) override;
+};
+} // namespace bluetooth
+} // namespace android
diff --git a/mtkbt/code/bt/service/common/bluetooth/adapter_state.cc b/mtkbt/code/bt/service/common/bluetooth/adapter_state.cc
new file mode 100755
index 0000000..9ca5998
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/adapter_state.cc
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/adapter_state.h"
+
+namespace bluetooth {
+
+std::string AdapterStateToString(AdapterState state) {
+ switch (state) {
+ case ADAPTER_STATE_DISCONNECTED:
+ return "ADAPTER_STATE_DISCONNECTED";
+ case ADAPTER_STATE_CONNECTING:
+ return "ADAPTER_STATE_CONNECTING";
+ case ADAPTER_STATE_CONNECTED:
+ return "ADAPTER_STATE_CONNECTED";
+ case ADAPTER_STATE_DISCONNECTING:
+ return "ADAPTER_STATE_DISCONNECTING";
+ case ADAPTER_STATE_OFF:
+ return "ADAPTER_STATE_OFF";
+ case ADAPTER_STATE_TURNING_ON:
+ return "ADAPTER_STATE_TURNING_ON";
+ case ADAPTER_STATE_ON:
+ return "ADAPTER_STATE_ON";
+ case ADAPTER_STATE_TURNING_OFF:
+ return "ADAPTER_STATE_TURNING_OFF";
+ default:
+ return "unknown state";
+ }
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/adapter_state.h b/mtkbt/code/bt/service/common/bluetooth/adapter_state.h
new file mode 100755
index 0000000..1b2fbe4
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/adapter_state.h
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+
+// Possible Adapter states. The values for each enumration have been copied
+// from frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java.
+// These values need to match their android.bluetooth.BluetoothAdapter
+// counterparts for this to be compatible with the framework, hence we
+// redeclare them here.
+enum AdapterState {
+ ADAPTER_STATE_DISCONNECTED = 0,
+ ADAPTER_STATE_CONNECTING = 1,
+ ADAPTER_STATE_CONNECTED = 2,
+ ADAPTER_STATE_DISCONNECTING = 3,
+ ADAPTER_STATE_OFF = 10,
+ ADAPTER_STATE_TURNING_ON = 11,
+ ADAPTER_STATE_ON = 12,
+ ADAPTER_STATE_TURNING_OFF = 13,
+ ADAPTER_STATE_INVALID = 0xFFFF
+};
+
+// Returns a string for the given Adapter state |state|.
+std::string AdapterStateToString(AdapterState state);
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/advertise_data.cc b/mtkbt/code/bt/service/common/bluetooth/advertise_data.cc
new file mode 100755
index 0000000..93bffa8
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/advertise_data.cc
@@ -0,0 +1,83 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/advertise_data.h"
+
+#include <base/logging.h>
+
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+namespace bluetooth {
+
+AdvertiseData::AdvertiseData(const std::vector<uint8_t>& data) : data_(data) {}
+
+AdvertiseData::AdvertiseData() {}
+
+AdvertiseData::AdvertiseData(const AdvertiseData& other) : data_(other.data_) {}
+
+bool AdvertiseData::IsValid() const {
+ size_t len = data_.size();
+
+ // Consider empty data as valid.
+ if (!len) return true;
+
+ for (size_t i = 0, field_len = 0; i < len; i += (field_len + 1)) {
+ field_len = data_[i];
+
+ // If the length of the current field would exceed the total data length,
+ // then the data is badly formatted.
+ if (i + field_len >= len) {
+ VLOG(1) << "Advertising data badly formatted";
+ return false;
+ }
+
+ // A field length of 0 would be invalid as it should at least contain the
+ // EIR field type.
+ if (field_len < 1) return false;
+
+ uint8_t type = data_[i + 1];
+
+ // Clients are not allowed to set the following EIR fields as these are
+ // managed by stack.
+ switch (type) {
+ case HCI_EIR_FLAGS_TYPE:
+ case HCI_EIR_OOB_BD_ADDR_TYPE:
+ case HCI_EIR_OOB_COD_TYPE:
+ case HCI_EIR_OOB_SSP_HASH_C_TYPE:
+ case HCI_EIR_OOB_SSP_RAND_R_TYPE:
+ VLOG(1) << "Cannot set EIR field type: " << type;
+ return false;
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool AdvertiseData::operator==(const AdvertiseData& rhs) const {
+ return data_ == rhs.data_;
+}
+
+AdvertiseData& AdvertiseData::operator=(const AdvertiseData& other) {
+ if (this == &other) return *this;
+
+ data_ = other.data_;
+ return *this;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/advertise_data.h b/mtkbt/code/bt/service/common/bluetooth/advertise_data.h
new file mode 100755
index 0000000..0eb2bc1
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/advertise_data.h
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+#include <base/macros.h>
+
+namespace bluetooth {
+
+// Represents a data packet for Bluetooth Low Energy advertisements. This is the
+// native equivalent of the Android framework class defined in
+// frameworks/base/core/j/android/bluetooth/le/AdvertiseData.java
+class AdvertiseData {
+ public:
+ // Constructs an AdvertiseData with the given parameters. |data| can only
+ // contain the "Service UUIDs", "Service Data", "Manufacturer Data",
+ // "Tx Power" and "Device name" fields as specified in the Core Specification
+ // Supplement. |data| must be properly formatted according to the supplement
+ // and contains the data as it will be sent over the wire.
+ //
+ // Tx Power field value will be filled with proper value.
+ explicit AdvertiseData(const std::vector<uint8_t>& data);
+
+ // Default constructor initializes all fields to be empty/false.
+ AdvertiseData();
+ AdvertiseData(const AdvertiseData& other);
+ virtual ~AdvertiseData() = default;
+
+ // Returns true if the advertising data is formatted correctly according to
+ // the TLV format.
+ bool IsValid() const;
+
+ // data() returns the current advertising data contained by this instance. The
+ // data is in the TLV format as specified in the Bluetooth Core Specification.
+ const std::vector<uint8_t>& data() const { return data_; }
+
+ // Comparison operator.
+ bool operator==(const AdvertiseData& rhs) const;
+
+ // Assignment operator
+ AdvertiseData& operator=(const AdvertiseData& other);
+
+ protected:
+ std::vector<uint8_t> data_;
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/advertise_settings.cc b/mtkbt/code/bt/service/common/bluetooth/advertise_settings.cc
new file mode 100755
index 0000000..ca3428c
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/advertise_settings.cc
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/advertise_settings.h"
+
+namespace bluetooth {
+
+AdvertiseSettings::AdvertiseSettings(Mode mode, base::TimeDelta timeout,
+ TxPowerLevel tx_power_level,
+ bool connectable)
+ : mode_(mode),
+ timeout_(timeout),
+ tx_power_level_(tx_power_level),
+ connectable_(connectable) {}
+
+// Default values are taken from the AdvertiseSettings.java
+AdvertiseSettings::AdvertiseSettings()
+ : mode_(MODE_LOW_POWER),
+ tx_power_level_(TX_POWER_LEVEL_MEDIUM),
+ connectable_(true) {}
+
+bool AdvertiseSettings::operator==(const AdvertiseSettings& rhs) const {
+ if (mode_ != rhs.mode_) return false;
+
+ if (timeout_ != rhs.timeout_) return false;
+
+ if (tx_power_level_ != rhs.tx_power_level_) return false;
+
+ if (connectable_ != rhs.connectable_) return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/advertise_settings.h b/mtkbt/code/bt/service/common/bluetooth/advertise_settings.h
new file mode 100755
index 0000000..6a533dd
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/advertise_settings.h
@@ -0,0 +1,96 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+#include <base/time/time.h>
+
+namespace bluetooth {
+
+// AdvertiseSettings provides a way to adjust advertising preferences for each
+// Bluetooth LE advertisement instance. This is the native equivalent of the
+// Android framework class defined in
+// frameworks/base/core/java/android/bluetooth/le/AdvertiseSettings.java
+class AdvertiseSettings {
+ public:
+ // Advertising mode describes power consumption mode used for advertising.
+ enum Mode {
+ // Perform Bluetooth LE advertising in low power mode. This is the default
+ // and preferred advertising mode as it consumes the least power.
+ MODE_LOW_POWER = 0x00,
+
+ // Perform Bluetooth LE advertising in balanced power mode. This is balanced
+ // between advertising frequency and power consumption.
+ MODE_BALANCED = 0x01,
+
+ // Perform Bluetooth LE advertising in low latency, high power mode. This
+ // has the highest power consumption and should not be used for continuous
+ // background advertising.
+ MODE_LOW_LATENCY = 0x02,
+ };
+
+ // Levels that can be set for advertising transmission power.
+ enum TxPowerLevel {
+ // Advertise using the lowest transmission (TX) power level. Low
+ // transmission power can be used to restrict the visibility range of
+ // advertising packets.
+ TX_POWER_LEVEL_ULTRA_LOW = 0x00,
+
+ // Advertise using low TX power level.
+ TX_POWER_LEVEL_LOW = 0x01,
+
+ // Advertise using medium TX power level.
+ TX_POWER_LEVEL_MEDIUM = 0x02,
+
+ // Advertise using high TX power level. This corresponds to largest
+ // visibility range of the advertising packet.
+ TX_POWER_LEVEL_HIGH = 0x03,
+ };
+
+ AdvertiseSettings(Mode mode, base::TimeDelta timeout,
+ TxPowerLevel tx_power_level, bool connectable);
+
+ // The default constructor sets all fields to defaults:
+ // mode: MODE_LOW_POWER
+ // TX power level: TX_POWER_LEVEL_MEDIUM
+ // connectable: true
+ AdvertiseSettings();
+ virtual ~AdvertiseSettings() = default;
+
+ // Returns the advertise mode.
+ Mode mode() const { return mode_; }
+
+ // Returns the advertising time limit in milliseconds.
+ const base::TimeDelta& timeout() const { return timeout_; }
+
+ // Returns the TX power level for advertising.
+ TxPowerLevel tx_power_level() const { return tx_power_level_; }
+
+ // Returns whether the advertisement will indicate connectable.
+ bool connectable() const { return connectable_; }
+
+ // Comparison operator.
+ bool operator==(const AdvertiseSettings& rhs) const;
+
+ protected:
+ Mode mode_;
+ base::TimeDelta timeout_;
+ TxPowerLevel tx_power_level_;
+ bool connectable_;
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/characteristic.cc b/mtkbt/code/bt/service/common/bluetooth/characteristic.cc
new file mode 100755
index 0000000..492a63a
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/characteristic.cc
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <bluetooth/characteristic.h>
+
+namespace bluetooth {
+Characteristic::Characteristic(const Characteristic& other) {
+ handle_ = other.handle_;
+ uuid_ = other.uuid_;
+ properties_ = other.properties_;
+ permissions_ = other.permissions_;
+ descriptors_ = other.descriptors_;
+}
+
+Characteristic& Characteristic::operator=(const Characteristic& other) {
+ if (*this == other) return *this;
+
+ handle_ = other.handle_;
+ uuid_ = other.uuid_;
+ properties_ = other.properties_;
+ permissions_ = other.permissions_;
+ descriptors_ = other.descriptors_;
+
+ return *this;
+}
+
+bool Characteristic::Equals(const Characteristic& other) const {
+ return handle_ == other.handle_ && uuid_ == other.uuid_ &&
+ properties_ == other.properties_ &&
+ permissions_ == other.permissions_ &&
+ descriptors_ == other.descriptors_;
+}
+
+bool Characteristic::operator==(const Characteristic& rhs) const {
+ return Equals(rhs);
+}
+
+bool Characteristic::operator!=(const Characteristic& rhs) const {
+ return !Equals(rhs);
+}
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/characteristic.h b/mtkbt/code/bt/service/common/bluetooth/characteristic.h
new file mode 100755
index 0000000..ba7328a
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/characteristic.h
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <bluetooth/descriptor.h>
+#include <bluetooth/uuid.h>
+
+#include <vector>
+
+namespace bluetooth {
+class Characteristic {
+ public:
+ Characteristic() = default;
+ Characteristic(const Characteristic& other);
+ Characteristic(uint16_t handle, const UUID& uuid, uint8_t properties,
+ uint16_t permissions,
+ const std::vector<Descriptor>& descriptors)
+ : handle_(handle),
+ uuid_(uuid),
+ properties_(properties),
+ permissions_(permissions),
+ descriptors_(descriptors){};
+ Characteristic& operator=(const Characteristic& other);
+ virtual ~Characteristic() = default;
+
+ // Comparison function and operator.
+ bool Equals(const Characteristic& other) const;
+ bool operator==(const Characteristic& rhs) const;
+ bool operator!=(const Characteristic& rhs) const;
+
+ uint16_t handle() const { return handle_; }
+ const UUID& uuid() const { return uuid_; }
+ uint8_t properties() const { return properties_; }
+ uint16_t permissions() const { return permissions_; }
+ const std::vector<Descriptor>& descriptors() const { return descriptors_; }
+ std::vector<Descriptor>& descriptors() { return descriptors_; }
+
+ protected:
+ uint16_t handle_;
+ UUID uuid_;
+ uint8_t properties_;
+ uint16_t permissions_;
+ std::vector<Descriptor> descriptors_;
+};
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/descriptor.cc b/mtkbt/code/bt/service/common/bluetooth/descriptor.cc
new file mode 100755
index 0000000..7e37596
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/descriptor.cc
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <bluetooth/descriptor.h>
+
+namespace bluetooth {
+Descriptor::Descriptor(const Descriptor& other) {
+ handle_ = other.handle_;
+ uuid_ = other.uuid_;
+ permissions_ = other.permissions_;
+}
+
+Descriptor& Descriptor::operator=(const Descriptor& other) {
+ if (*this == other) return *this;
+
+ handle_ = other.handle_;
+ uuid_ = other.uuid_;
+ permissions_ = other.permissions_;
+
+ return *this;
+}
+
+bool Descriptor::Equals(const Descriptor& other) const {
+ return handle_ == other.handle_ && uuid_ == other.uuid_ &&
+ permissions_ == other.permissions_;
+}
+
+bool Descriptor::operator==(const Descriptor& rhs) const { return Equals(rhs); }
+
+bool Descriptor::operator!=(const Descriptor& rhs) const {
+ return !Equals(rhs);
+}
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/descriptor.h b/mtkbt/code/bt/service/common/bluetooth/descriptor.h
new file mode 100755
index 0000000..35fe53e
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/descriptor.h
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <bluetooth/uuid.h>
+
+namespace bluetooth {
+class Descriptor {
+ public:
+ Descriptor() = default;
+ Descriptor(const Descriptor& other);
+ Descriptor& operator=(const Descriptor& other);
+ Descriptor(uint16_t handle, const UUID& uuid, uint16_t permissions)
+ : handle_(handle), uuid_(uuid), permissions_(permissions){};
+ virtual ~Descriptor() = default;
+
+ // Comparison function and operator.
+ bool Equals(const Descriptor& other) const;
+ bool operator==(const Descriptor& rhs) const;
+ bool operator!=(const Descriptor& rhs) const;
+
+ uint16_t handle() const { return handle_; }
+ uint16_t permissions() const { return permissions_; }
+ const UUID& uuid() const { return uuid_; }
+
+ protected:
+ uint16_t handle_;
+ UUID uuid_;
+ uint16_t permissions_;
+};
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/low_energy_constants.h b/mtkbt/code/bt/service/common/bluetooth/low_energy_constants.h
new file mode 100755
index 0000000..348fa60
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/low_energy_constants.h
@@ -0,0 +1,125 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <stdint.h>
+
+namespace bluetooth {
+
+// Defined here are various status codes that can be returned from the stack for
+// BLE operations.
+enum BLEStatus {
+ BLE_STATUS_SUCCESS = 0,
+ BLE_STATUS_ADV_ERROR_DATA_TOO_LARGE = 1,
+ BLE_STATUS_ADV_ERROR_TOO_MANY_ADVERTISERS = 2,
+ BLE_STATUS_ADV_ERROR_ALREADY_STARTED = 3,
+ BLE_STATUS_ADV_ERROR_FEATURE_UNSUPPORTED = 5,
+ BLE_STATUS_FAILURE = 0x101,
+};
+
+enum GATTError {
+ GATT_ERROR_NONE = 0,
+ GATT_ERROR_INVALID_HANDLE = 0x01,
+ GATT_ERROR_READ_NOT_PERMITTED = 0x02,
+ GATT_ERROR_WRITE_NOT_PERMITTED = 0x03,
+ GATT_ERROR_INVALID_PDU = 0x04,
+ GATT_ERROR_INSUFFICIENT_AUTHEN = 0x05,
+ GATT_ERROR_REQUEST_NOT_SUPPORTED = 0x06,
+ GATT_ERROR_INVALID_OFFSET = 0x07,
+ GATT_ERROR_INSUFFICIENT_AUTHOR = 0x08,
+ GATT_ERROR_PREP_QUEUE_FULL = 0x09,
+ GATT_ERROR_ATTRIBUTE_NOT_FOUND = 0x0a,
+ GATT_ERROR_ATTRIBUTE_NOT_LONG = 0x0b,
+ GATT_ERROR_INSUFFICIENT_KEY_SIZE = 0x0c,
+ GATT_ERROR_INVALID_ATTRIBUTE_LENGTH = 0x0d,
+ GATT_ERROR_UNLIKELY = 0x0e,
+ GATT_ERROR_INSUFFICIENT_ENCR = 0x0f,
+ GATT_ERROR_UNSUPPORTED_GRP_TYPE = 0x10,
+ GATT_ERROR_INSUFFICIENT_RESOURCES = 0x11,
+ GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED = 0xFD,
+ GATT_ERROR_PROCEDURE_IN_PROGRESS = 0xFE,
+ GATT_ERROR_OUT_OF_RANGE = 0xFF
+};
+
+enum Transport { TRANSPORT_AUTO = 0, TRANSPORT_BREDR = 1, TRANSPORT_LE = 2 };
+
+// Android attribute permission values
+const uint16_t kAttributePermissionNone = 0x0;
+const uint16_t kAttributePermissionRead = 0x1;
+const uint16_t kAttributePermissionReadEncrypted = 0x2;
+const uint16_t kAttributePermissionReadEncryptedMITM = 0x4;
+const uint16_t kAttributePermissionWrite = 0x10;
+const uint16_t kAttributePermissionWriteEncrypted = 0x20;
+const uint16_t kAttributePermissionWriteEncryptedMITM = 0x40;
+const uint16_t kAttributePermissionWriteSigned = 0x80;
+const uint16_t kAttributePermissionWriteSignedMITM = 0x100;
+
+// GATT characteristic properties bit-field values (not including the
+// characteristic extended properties).
+const uint8_t kCharacteristicPropertyNone = 0x0;
+const uint8_t kCharacteristicPropertyBroadcast = 0x1;
+const uint8_t kCharacteristicPropertyRead = 0x2;
+const uint8_t kCharacteristicPropertyWriteNoResponse = 0x4;
+const uint8_t kCharacteristicPropertyWrite = 0x8;
+const uint8_t kCharacteristicPropertyNotify = 0x10;
+const uint8_t kCharacteristicPropertyIndicate = 0x20;
+const uint8_t kCharacteristicPropertySignedWrite = 0x40;
+const uint8_t kCharacteristicPropertyExtendedProps = 0x80;
+
+// Advertising interval for different modes.
+const int kAdvertisingIntervalHighMs = 1000;
+const int kAdvertisingIntervalMediumMs = 250;
+const int kAdvertisingIntervalLowMs = 100;
+
+// Add some randomness to the advertising min/max interval so the controller can
+// do some optimization.
+// TODO(armansito): I took this directly from packages/apps/Bluetooth but based
+// on code review comments this constant and the accompanying logic doesn't make
+// sense. Let's remove this constant and figure out how to properly calculate
+// the Max. Adv. Interval. (See http://b/24344075).
+const int kAdvertisingIntervalDeltaUnit = 10;
+
+// Legacy Advertising types (ADV_IND, ADV_SCAN_IND, etc.) that are exposed to
+// applications.
+const uint16_t kAdvertisingEventTypeLegacyConnectable = 0x0013;
+const uint16_t kAdvertisingEventTypeLegacyScannable = 0x0012;
+const uint16_t kAdvertisingEventTypeLegacyNonConnectable = 0x0010;
+
+// Advertising channels. These should be kept the same as those defined in the
+// stack.
+const int kAdvertisingChannel37 = (1 << 0);
+const int kAdvertisingChannel38 = (1 << 1);
+const int kAdvertisingChannel39 = (1 << 2);
+const int kAdvertisingChannelAll =
+ (kAdvertisingChannel37 | kAdvertisingChannel38 | kAdvertisingChannel39);
+
+// Various Extended Inquiry Response fields types that are used for advertising
+// data fields as defined in the Core Specification Supplement.
+const uint8_t kEIRTypeFlags = 0x01;
+const uint8_t kEIRTypeIncomplete16BitUUIDs = 0x02;
+const uint8_t kEIRTypeComplete16BitUUIDs = 0x03;
+const uint8_t kEIRTypeIncomplete32BitUUIDs = 0x04;
+const uint8_t kEIRTypeComplete32BitUUIDs = 0x05;
+const uint8_t kEIRTypeIncomplete128BitUUIDs = 0x06;
+const uint8_t kEIRTypeComplete128BitUUIDs = 0x07;
+const uint8_t kEIRTypeShortenedLocalName = 0x08;
+const uint8_t kEIRTypeCompleteLocalName = 0x09;
+const uint8_t kEIRTypeTxPower = 0x0A;
+const uint8_t kEIRTypeServiceData = 0x16;
+const uint8_t kEIRTypeManufacturerSpecificData = 0xFF;
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_filter.cc b/mtkbt/code/bt/service/common/bluetooth/scan_filter.cc
new file mode 100755
index 0000000..c0b7375
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_filter.cc
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/scan_filter.h"
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+namespace bluetooth {
+
+ScanFilter::ScanFilter(const ScanFilter& other) {
+ device_name_ = other.device_name_;
+ device_address_ = other.device_address_;
+
+ if (other.service_uuid_) service_uuid_.reset(new UUID(*other.service_uuid_));
+
+ if (other.service_uuid_mask_)
+ service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+}
+
+ScanFilter& ScanFilter::operator=(const ScanFilter& other) {
+ device_name_ = other.device_name_;
+ device_address_ = other.device_address_;
+
+ if (other.service_uuid_)
+ service_uuid_.reset(new UUID(*other.service_uuid_));
+ else
+ service_uuid_ = nullptr;
+
+ if (other.service_uuid_mask_)
+ service_uuid_mask_.reset(new UUID(*other.service_uuid_mask_));
+ else
+ service_uuid_mask_ = nullptr;
+
+ return *this;
+}
+
+bool ScanFilter::SetDeviceAddress(const std::string& device_address) {
+ if (!util::IsAddressValid(device_address)) return false;
+
+ device_address_ = device_address;
+ return true;
+}
+
+void ScanFilter::SetServiceUuid(const UUID& service_uuid) {
+ service_uuid_.reset(new UUID(service_uuid));
+ service_uuid_mask_.reset();
+}
+
+void ScanFilter::SetServiceUuidWithMask(const UUID& service_uuid,
+ const UUID& mask) {
+ service_uuid_.reset(new UUID(service_uuid));
+ service_uuid_mask_.reset(new UUID(mask));
+}
+
+bool ScanFilter::operator==(const ScanFilter& rhs) const {
+ if (device_name_ != rhs.device_name_) return false;
+
+ if (device_address_ != rhs.device_address_) return false;
+
+ // Both must be either NULL or non-NULL. If only one of them is NULL, then
+ // return false.
+ if (!!service_uuid_ != !!rhs.service_uuid_) return false;
+
+ if (service_uuid_ && rhs.service_uuid_ &&
+ *service_uuid_ != *rhs.service_uuid_)
+ return false;
+
+ // Both must be either NULL or non-NULL. If only one of them is NULL, then
+ // return false.
+ if (!!service_uuid_mask_ != !!rhs.service_uuid_mask_) return false;
+
+ if (service_uuid_mask_ && rhs.service_uuid_mask_ &&
+ *service_uuid_mask_ != *rhs.service_uuid_mask_)
+ return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_filter.h b/mtkbt/code/bt/service/common/bluetooth/scan_filter.h
new file mode 100755
index 0000000..d4c87dd
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_filter.h
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <bluetooth/uuid.h>
+
+namespace bluetooth {
+
+// Used for filtering scan results by allowing clients to restrict scan results
+// to only those that are of interest to them.
+class ScanFilter {
+ public:
+ ScanFilter() = default;
+ virtual ~ScanFilter() = default;
+
+ // Copy constructor and assignment operator.
+ ScanFilter(const ScanFilter& other);
+ ScanFilter& operator=(const ScanFilter& other);
+
+ // The device name used while filtering scan results.
+ const std::string& device_name() const { return device_name_; }
+ void set_device_name(const std::string& name) { device_name_ = name; }
+
+ // The device address used while filtering scan results. Address should be in
+ // the XX:XX:XX:XX:XX:XX where X is a hexadecimal digit.
+ const std::string& device_address() const { return device_address_; }
+
+ // Sets the device address used for filtering. Returns false if
+ // |device_address| is in an illegal format.
+ bool SetDeviceAddress(const std::string& device_address);
+
+ // The service UUID and its mask used while filtering scan results. See
+ // SetServiceUuidWithMask for what this mask does. The raw pointer returned
+ // from these getters belongs to the ScanFilter object. nullptr will be
+ // returned if these fields have not been set on this filter.
+ UUID* service_uuid() const { return service_uuid_.get(); }
+ UUID* service_uuid_mask() const { return service_uuid_mask_.get(); }
+
+ // Sets the service UUID for this filter.
+ void SetServiceUuid(const UUID& service_uuid);
+
+ // Sets the service UUID for this filter with a 128-bit mask. The mask allows
+ // the caller to partially filter scanned service UUIDs. For any of the
+ // 128-bits of a UUID, set the corresponding bit in the mask to 1 to match the
+ // advertised value, and 0 to ignore that bit.
+ void SetServiceUuidWithMask(const UUID& service_uuid, const UUID& mask);
+
+ // Comparison operator.
+ bool operator==(const ScanFilter& rhs) const;
+
+ protected:
+ std::string device_name_;
+ std::string device_address_;
+
+ std::unique_ptr<UUID> service_uuid_;
+ std::unique_ptr<UUID> service_uuid_mask_;
+
+ // TODO(armansito): Add service and manufacturer data filter fields.
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_result.cc b/mtkbt/code/bt/service/common/bluetooth/scan_result.cc
new file mode 100755
index 0000000..099cac7
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_result.cc
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/scan_result.h"
+
+#include <base/logging.h>
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+namespace bluetooth {
+
+ScanResult::ScanResult(const std::string& device_address,
+ const std::vector<uint8_t>& scan_record, int rssi)
+ : device_address_(device_address), scan_record_(scan_record), rssi_(rssi) {
+ CHECK(util::IsAddressValid(device_address)) << "Invalid BD_ADDR given: "
+ << device_address;
+}
+
+bool ScanResult::operator==(const ScanResult& rhs) const {
+ if (device_address_ != rhs.device_address_) return false;
+
+ if (scan_record_ != rhs.scan_record_) return false;
+
+ if (rssi_ != rhs.rssi_) return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_result.h b/mtkbt/code/bt/service/common/bluetooth/scan_result.h
new file mode 100755
index 0000000..150ad4e
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_result.h
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace bluetooth {
+
+// ScanResult represents a single Bluetooth LE device scan result. It
+// encapsulates information about discovered LE devices.
+class ScanResult {
+ public:
+ ScanResult(const std::string& device_address,
+ const std::vector<uint8_t>& scan_record, int rssi);
+ ScanResult() = default;
+ virtual ~ScanResult() = default;
+
+ // Returns the remote BD_ADDR associated with this scan result.
+ const std::string& device_address() const { return device_address_; }
+
+ // Returns the scan record (advertising +scan-response data) associated with
+ // this scan result.
+ const std::vector<uint8_t>& scan_record() const { return scan_record_; }
+
+ // Returns the RSSI associated with this scan result.
+ int rssi() const { return rssi_; }
+
+ // Comparison operator.
+ bool operator==(const ScanResult& rhs) const;
+
+ protected:
+ std::string device_address_;
+ std::vector<uint8_t> scan_record_;
+ int rssi_;
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_settings.cc b/mtkbt/code/bt/service/common/bluetooth/scan_settings.cc
new file mode 100755
index 0000000..a405a28
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_settings.cc
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/scan_settings.h"
+
+namespace bluetooth {
+
+ScanSettings::ScanSettings()
+ : mode_(MODE_LOW_POWER),
+ callback_type_(CALLBACK_TYPE_ALL_MATCHES),
+ result_type_(RESULT_TYPE_FULL),
+ match_count_per_filter_(MATCH_COUNT_MAX_ADVERTISEMENTS) {}
+
+ScanSettings::ScanSettings(Mode mode, CallbackTypeBitField callback_type,
+ ResultType result_type,
+ base::TimeDelta report_delay_ms,
+ MatchMode match_mode,
+ MatchCount match_count_per_filter)
+ : mode_(mode),
+ callback_type_(callback_type),
+ result_type_(result_type),
+ report_delay_ms_(report_delay_ms),
+ match_mode_(match_mode),
+ match_count_per_filter_(match_count_per_filter) {}
+
+bool ScanSettings::operator==(const ScanSettings& rhs) const {
+ if (mode_ != rhs.mode_) return false;
+
+ if (callback_type_ != rhs.callback_type_) return false;
+
+ if (result_type_ != rhs.result_type_) return false;
+
+ if (report_delay_ms_ != rhs.report_delay_ms_) return false;
+
+ if (match_mode_ != rhs.match_mode_) return false;
+
+ if (match_count_per_filter_ != rhs.match_count_per_filter_) return false;
+
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/scan_settings.h b/mtkbt/code/bt/service/common/bluetooth/scan_settings.h
new file mode 100755
index 0000000..da907b5
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/scan_settings.h
@@ -0,0 +1,161 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/time/time.h>
+
+namespace bluetooth {
+
+// ScanSettings encapsulates Bluetooth LE device scan parameters. This is the
+// native equivalent of the Android framework class defined in
+// frameworks/base/core/java/android/bluetooth/le/ScanSettings.java.
+class ScanSettings {
+ public:
+ // A scan mode describes the power consumption involved in LE scans.
+ enum Mode {
+ // A special Bluetooth LE scan mode. Applications using this scan mode will
+ // passively listen for other scan results without starting BLE scans
+ // themselves.
+ MODE_OPPORTUNISTIC = -1,
+
+ // Perform Bluetooth LE scan in low power mode. This is the default scan
+ // mode as it consumes the least power.
+ MODE_LOW_POWER = 0,
+
+ // Perform Bluetooth LE scan in balanced power mode. Scan results are
+ // returned at a rate that provides a good trade-off between scan frequency
+ // and power consumption.
+ MODE_BALANCED = 1,
+
+ // Scan using the highest duty cycle. It's recommended to only use this mode
+ // when the application is running in the foreground.
+ MODE_LOW_LATENCY = 2,
+ };
+
+ // A callback type describes how scan results will be reported to applications
+ // in asynchronous callbacks.
+ enum CallbackType {
+ // Trigger a callback for every Bluetooth advertisement found that matches
+ // the filter criteria. If no filter is active, all advertisement packets
+ // are reported.
+ CALLBACK_TYPE_ALL_MATCHES = 1,
+
+ // A result callback is only triggered for the first advertisement packet
+ // received that matches the filter criteria. This requires that the
+ // hardware support the offloaded filtering feature.
+ CALLBACK_TYPE_FIRST_MATCH = 2,
+
+ // Receive a callback when advertisements are no longer received from a
+ // device that has been previously reported by a first match callback. This
+ // requires that the hardware support the offloaded filtering feature.
+ CALLBACK_TYPE_MATCH_LOST = 4,
+ };
+ using CallbackTypeBitField = int;
+
+ // Determines how many advertisements to match per filter.
+ enum MatchCount {
+ // Match one advertisement per filter.
+ MATCH_COUNT_ONE_ADVERTISEMENT = 1,
+
+ // Match few advertisements per filter depending on the current capability
+ // and availability of hardware resources.
+ MATCH_COUNT_FEW_ADVERTISEMENTS = 2,
+
+ // Match as many advertisements per filter as the underlying hardware can
+ // allow, depending on the current capability and availability of hardware
+ // resources.
+ MATCH_COUNT_MAX_ADVERTISEMENTS = 3,
+ };
+
+ // Hardware filter match mode.
+ enum MatchMode {
+ // In aggressive mode the hardware will determine a match sooner even with
+ // feeble signal strength and a low number of sightings in a duration.
+ MATCH_MODE_AGGRESSIVE = 1,
+
+ // In sticky mode a higher threshold of signal strength and sightings is
+ // required before a scan result is reported by the hardware.
+ MATCH_MODE_STICKY = 2,
+ };
+
+ // Scan result type describes the contents of each scan result.
+ enum ResultType {
+ // Request full scan results which contain the device name, RSSI,
+ // advertising data, scan response data, and the scan timestamp.
+ RESULT_TYPE_FULL = 0,
+
+ // Request abbreviated scan results which contain the device name, RSSI, and
+ // scan timestamp.
+ // Note: It is possible for an application to get more scan results than it
+ // asked for, if there are multiple apps using this type.
+ RESULT_TYPE_ABBREVIATED = 1,
+ };
+
+ // The default constructor sets all fields to defaults:
+ // mode: MODE_LOW_POWER
+ // callback_type: CALLBACK_TYPE_ALL_MATCHES
+ // result_type: RESULT_TYPE_FULL
+ // report_delay_ms: 0
+ // match_mode: MATCH_MODE_AGGRESSIVE
+ // match_count_per_filter: MATCH_COUNT_MAX_ADVERTISEMENTS
+ ScanSettings();
+ ScanSettings(Mode mode, CallbackTypeBitField callback_type,
+ ResultType result_type, base::TimeDelta report_delay_ms,
+ MatchMode match_mode, MatchCount match_count_per_filter);
+ virtual ~ScanSettings() = default;
+
+ // Returns the scan mode.
+ Mode mode() const { return mode_; }
+ void set_mode(Mode mode) { mode_ = mode; }
+
+ // Returns the callback type.
+ CallbackTypeBitField callback_type() const { return callback_type_; }
+ void set_callback_type(CallbackTypeBitField type) { callback_type_ = type; }
+
+ // Returns the scan result type.
+ ResultType result_type() const { return result_type_; }
+ void set_result_type(ResultType type) { result_type_ = type; }
+
+ // Returns the report delay value in milliseconds.
+ const base::TimeDelta& report_delay() const { return report_delay_ms_; }
+ void set_report_delay(const base::TimeDelta& delay) {
+ report_delay_ms_ = delay;
+ }
+
+ // Returns the hardware filter match mode.
+ MatchMode match_mode() const { return match_mode_; }
+ void set_match_mode(MatchMode mode) { match_mode_ = mode; }
+
+ // Returns the count of advertisements to match per filter.
+ MatchCount match_count_per_filter() const { return match_count_per_filter_; }
+ void set_match_count_per_filter(MatchCount count) {
+ match_count_per_filter_ = count;
+ }
+
+ // Comparison operator.
+ bool operator==(const ScanSettings& rhs) const;
+
+ protected:
+ Mode mode_;
+ CallbackTypeBitField callback_type_;
+ ResultType result_type_;
+ base::TimeDelta report_delay_ms_;
+ MatchMode match_mode_;
+ MatchCount match_count_per_filter_;
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/service.cc b/mtkbt/code/bt/service/common/bluetooth/service.cc
new file mode 100755
index 0000000..6a8a0c3
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/service.cc
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <bluetooth/service.h>
+
+namespace bluetooth {
+Service::Service(const Service& other) {
+ handle_ = other.handle_;
+ primary_ = other.primary_;
+ uuid_ = other.uuid_;
+ characteristics_ = other.characteristics_;
+ included_services_ = other.included_services_;
+}
+
+Service& Service::operator=(const Service& other) {
+ if (*this == other) return *this;
+
+ handle_ = other.handle_;
+ primary_ = other.primary_;
+ uuid_ = other.uuid_;
+ characteristics_ = other.characteristics_;
+ included_services_ = other.included_services_;
+ return *this;
+}
+
+bool Service::Equals(const Service& other) const {
+ return handle_ == other.handle_ && primary_ == other.primary_ &&
+ uuid_ == other.uuid_ && characteristics_ == other.characteristics_ &&
+ included_services_ == other.included_services_;
+}
+
+bool Service::operator==(const Service& rhs) const { return Equals(rhs); }
+
+bool Service::operator!=(const Service& rhs) const { return !Equals(rhs); }
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/service.h b/mtkbt/code/bt/service/common/bluetooth/service.h
new file mode 100755
index 0000000..b3ce0ea
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/service.h
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <bluetooth/characteristic.h>
+#include <bluetooth/uuid.h>
+
+#include <vector>
+
+namespace bluetooth {
+class Service {
+ public:
+ Service() = default;
+ Service(const Service& other);
+ Service(uint16_t handle, bool primary, const UUID& uuid,
+ const std::vector<Characteristic>& characteristics,
+ const std::vector<Service>& included_services)
+ : handle_(handle),
+ primary_(primary),
+ uuid_(uuid),
+ characteristics_(characteristics),
+ included_services_(included_services){};
+ Service& operator=(const Service& other);
+ virtual ~Service() = default;
+
+ // Comparison function and operator.
+ bool Equals(const Service& other) const;
+ bool operator==(const Service& rhs) const;
+ bool operator!=(const Service& rhs) const;
+
+ uint16_t handle() const { return handle_; }
+ bool primary() const { return primary_; }
+ const UUID& uuid() const { return uuid_; }
+ const std::vector<Characteristic>& characteristics() const {
+ return characteristics_;
+ }
+ std::vector<Characteristic>& characteristics() { return characteristics_; }
+ const std::vector<Service>& included_services() const {
+ return included_services_;
+ }
+
+ protected:
+ uint16_t handle_;
+ bool primary_;
+ UUID uuid_;
+ std::vector<Characteristic> characteristics_;
+ std::vector<Service> included_services_;
+};
+}
diff --git a/mtkbt/code/bt/service/common/bluetooth/util/address_helper.cc b/mtkbt/code/bt/service/common/bluetooth/util/address_helper.cc
new file mode 100755
index 0000000..17aecce
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/util/address_helper.cc
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+#include <cstdlib>
+
+#include <base/logging.h>
+#include <base/strings/string_split.h>
+
+namespace util {
+
+bool IsAddressValid(const std::string& address) {
+ bt_bdaddr_t addr;
+ return BdAddrFromString(address, &addr);
+}
+
+bool BdAddrFromString(const std::string& address, bt_bdaddr_t* out_addr) {
+ CHECK(out_addr);
+
+ if (address.length() != 17) return false;
+
+ std::vector<std::string> byte_tokens = base::SplitString(
+ address, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ if (byte_tokens.size() != 6) return false;
+
+ for (int i = 0; i < 6; i++) {
+ const auto& token = byte_tokens[i];
+
+ if (token.length() != 2) return false;
+
+ char* temp = nullptr;
+ out_addr->address[i] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') return false;
+ }
+
+ return true;
+}
+
+} // namespace util
diff --git a/mtkbt/code/bt/service/common/bluetooth/util/address_helper.h b/mtkbt/code/bt/service/common/bluetooth/util/address_helper.h
new file mode 100755
index 0000000..d71d907
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/util/address_helper.h
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <string>
+
+namespace util {
+
+// Checks if the given string representing a Bluetooth device address (BD_ADDR)
+// is correctly formatted. The correct formatting is of the form
+//
+// XX:XX:XX:XX:XX:XX
+//
+// where X is an alpha-numeric character.
+bool IsAddressValid(const std::string& address);
+
+// Populates a bt_bdaddr_t from a given string. Returns false if the data is
+// invalid.
+bool BdAddrFromString(const std::string& address, bt_bdaddr_t* out_addr);
+
+} // namespace util
diff --git a/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.cc b/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.cc
new file mode 100755
index 0000000..fd71a5b
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.cc
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/util/atomic_string.h"
+
+namespace util {
+
+AtomicString::AtomicString(const std::string& str) : str_(str) {}
+
+std::string AtomicString::Get() const {
+ std::mutex* mutex = const_cast<std::mutex*>(&lock_);
+ std::lock_guard<std::mutex> lock(*mutex);
+ return str_;
+}
+
+void AtomicString::Set(const std::string& str) {
+ std::lock_guard<std::mutex> lock(lock_);
+ str_ = str;
+}
+
+} // namespace util
diff --git a/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.h b/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.h
new file mode 100755
index 0000000..e1c2526
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/util/atomic_string.h
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <mutex>
+#include <string>
+
+#include <base/macros.h>
+
+namespace util {
+
+// A simple atomic container class for std::string.
+class AtomicString final {
+ public:
+ explicit AtomicString(const std::string& str);
+ ~AtomicString() = default;
+
+ std::string Get() const;
+ void Set(const std::string& str);
+
+ private:
+ std::mutex lock_;
+ std::string str_;
+
+ DISALLOW_COPY_AND_ASSIGN(AtomicString);
+};
+
+} // namespace util
diff --git a/mtkbt/code/bt/service/common/bluetooth/uuid.cc b/mtkbt/code/bt/service/common/bluetooth/uuid.cc
new file mode 100755
index 0000000..b7ae9e5
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/uuid.cc
@@ -0,0 +1,160 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/common/bluetooth/uuid.h"
+
+#include <algorithm>
+#include <array>
+#include <stack>
+#include <string>
+
+#include <base/rand_util.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+
+namespace bluetooth {
+
+namespace {
+
+const UUID::UUID128Bit kSigBaseUUID = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5f, 0x9b, 0x34, 0xfb}};
+
+} // namespace
+
+// static
+UUID UUID::GetRandom() {
+ UUID128Bit bytes;
+ base::RandBytes(bytes.data(), bytes.size());
+ return UUID(bytes);
+}
+
+// static
+UUID UUID::GetNil() {
+ UUID128Bit bytes;
+ bytes.fill(0);
+ return UUID(bytes);
+}
+
+// static
+UUID UUID::GetMax() {
+ UUID128Bit bytes;
+ bytes.fill(1);
+ return UUID(bytes);
+}
+
+void UUID::InitializeDefault() {
+ // Initialize to Bluetooth SIG base UUID.
+ id_ = kSigBaseUUID;
+ is_valid_ = true;
+}
+
+UUID::UUID() { InitializeDefault(); }
+
+UUID::UUID(std::string uuid) {
+ InitializeDefault();
+ is_valid_ = false;
+
+ if (uuid.empty()) return;
+
+ if (uuid.size() < 11 && uuid.find("0x") == 0) uuid = uuid.substr(2);
+
+ if (uuid.size() != 4 && uuid.size() != 8 && uuid.size() != 36) return;
+
+ if (uuid.size() == 36) {
+ if (uuid[8] != '-') return;
+ if (uuid[13] != '-') return;
+ if (uuid[18] != '-') return;
+ if (uuid[23] != '-') return;
+
+ std::vector<std::string> tokens = base::SplitString(
+ uuid, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ if (tokens.size() != 5) return;
+
+ uuid = base::JoinString(tokens, "");
+ }
+
+ const int start_index = uuid.size() == 4 ? 2 : 0;
+ const size_t copy_size = std::min(id_.size(), uuid.size() / 2);
+ for (size_t i = 0; i < copy_size; ++i) {
+ std::string octet_text(uuid, i * 2, 2);
+ char* temp = nullptr;
+ id_[start_index + i] = strtol(octet_text.c_str(), &temp, 16);
+ if (*temp != '\0') return;
+ }
+
+ is_valid_ = true;
+}
+
+UUID::UUID(const bt_uuid_t& uuid) {
+ std::reverse_copy(uuid.uu, uuid.uu + sizeof(uuid.uu), id_.begin());
+ is_valid_ = true;
+}
+
+UUID::UUID(const UUID16Bit& uuid) {
+ InitializeDefault();
+ std::copy(uuid.begin(), uuid.end(), id_.begin() + kNumBytes16);
+}
+
+UUID::UUID(const UUID32Bit& uuid) {
+ InitializeDefault();
+ std::copy(uuid.begin(), uuid.end(), id_.begin());
+}
+
+UUID::UUID(const UUID128Bit& uuid) : id_(uuid), is_valid_(true) {}
+
+UUID::UUID128Bit UUID::GetFullBigEndian() const { return id_; }
+
+UUID::UUID128Bit UUID::GetFullLittleEndian() const {
+ UUID::UUID128Bit ret;
+ std::reverse_copy(id_.begin(), id_.end(), ret.begin());
+ return ret;
+}
+
+bt_uuid_t UUID::GetBlueDroid() const {
+ bt_uuid_t ret;
+ std::reverse_copy(id_.begin(), id_.end(), ret.uu);
+ return ret;
+}
+
+std::string UUID::ToString() const {
+ return base::StringPrintf(
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ id_[0], id_[1], id_[2], id_[3], id_[4], id_[5], id_[6], id_[7], id_[8],
+ id_[9], id_[10], id_[11], id_[12], id_[13], id_[14], id_[15]);
+}
+
+size_t UUID::GetShortestRepresentationSize() const {
+ if (memcmp(id_.data() + 4, kSigBaseUUID.data() + 4, id_.size() - 4) != 0)
+ return kNumBytes128;
+
+ if (id_[0] == 0 && id_[1] == 0) return kNumBytes16;
+
+ return kNumBytes32;
+}
+
+bool UUID::operator<(const UUID& rhs) const {
+ return std::lexicographical_compare(id_.begin(), id_.end(), rhs.id_.begin(),
+ rhs.id_.end());
+}
+
+bool UUID::operator==(const UUID& rhs) const {
+ return std::equal(id_.begin(), id_.end(), rhs.id_.begin());
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/common/bluetooth/uuid.h b/mtkbt/code/bt/service/common/bluetooth/uuid.h
new file mode 100755
index 0000000..034654c
--- a/dev/null
+++ b/mtkbt/code/bt/service/common/bluetooth/uuid.h
@@ -0,0 +1,109 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <array>
+#include <string>
+
+// TODO: Find places that break include what you use and remove this.
+#include <base/logging.h>
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+
+class UUID {
+ public:
+ static constexpr size_t kNumBytes128 = 16;
+ static constexpr size_t kNumBytes32 = 4;
+ static constexpr size_t kNumBytes16 = 2;
+
+ typedef std::array<uint8_t, kNumBytes16> UUID16Bit;
+ typedef std::array<uint8_t, kNumBytes32> UUID32Bit;
+ typedef std::array<uint8_t, kNumBytes128> UUID128Bit;
+
+ // Creates and returns a random 128-bit UUID.
+ static UUID GetRandom();
+
+ // Creates and returns a UUID in which all 128 bits are equal to 0.
+ static UUID GetNil();
+
+ // Creates and returns a UUID in which all 128 bits are equal to 1.
+ static UUID GetMax();
+
+ // Construct a Bluetooth 'base' UUID.
+ UUID();
+ virtual ~UUID() = default;
+
+ // BlueDroid constructor.
+ explicit UUID(const bt_uuid_t& uuid);
+
+ // String constructor. Only hex ASCII accepted.
+ explicit UUID(std::string uuid);
+
+ // std::array variants constructors.
+ explicit UUID(const UUID16Bit& uuid);
+ explicit UUID(const UUID32Bit& uuid);
+ explicit UUID(const UUID128Bit& uuid);
+
+ // Provide the full network-byte-ordered blob.
+ UUID128Bit GetFullBigEndian() const;
+
+ // Provide blob in Little endian (BlueDroid expects this).
+ UUID128Bit GetFullLittleEndian() const;
+
+ // Helper for bluedroid LE type.
+ bt_uuid_t GetBlueDroid() const;
+
+ // Returns a string representation for the UUID.
+ std::string ToString() const;
+
+ // Returns whether or not this UUID was initialized correctly.
+ bool is_valid() const { return is_valid_; }
+
+ // Returns the shortest possible representation of this UUID in bytes.
+ size_t GetShortestRepresentationSize() const;
+
+ bool operator<(const UUID& rhs) const;
+ bool operator==(const UUID& rhs) const;
+ inline bool operator!=(const UUID& rhs) const { return !(*this == rhs); }
+
+ protected:
+ void InitializeDefault();
+
+ // Network-byte-ordered ID.
+ UUID128Bit id_;
+
+ // True if this UUID was initialized with a correct representation.
+ bool is_valid_;
+};
+
+} // namespace bluetooth
+
+// Custom std::hash specialization so that bluetooth::UUID can be used as a key
+// in std::unordered_map.
+namespace std {
+
+template <>
+struct hash<bluetooth::UUID> {
+ std::size_t operator()(const bluetooth::UUID& key) const {
+ const auto& uuid_bytes = key.GetFullBigEndian();
+ std::hash<std::string> hash_fn;
+ return hash_fn(std::string((char*)uuid_bytes.data(), uuid_bytes.size()));
+ }
+};
+
+} // namespace std
diff --git a/mtkbt/code/bt/service/daemon.cc b/mtkbt/code/bt/service/daemon.cc
new file mode 100755
index 0000000..bc022d2
--- a/dev/null
+++ b/mtkbt/code/bt/service/daemon.cc
@@ -0,0 +1,173 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/daemon.h"
+
+#include <memory>
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+#include "service/hal/bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+
+namespace bluetooth {
+
+namespace {
+
+// The global Daemon instance.
+Daemon* g_daemon = nullptr;
+
+class DaemonImpl : public Daemon {
+ public:
+ DaemonImpl() : initialized_(false) {}
+
+ ~DaemonImpl() override {
+ if (!initialized_) return;
+
+ CleanUpBluetoothStack();
+ }
+
+ void StartMainLoop() override { message_loop_->Run(); }
+
+ Settings* GetSettings() const override { return settings_.get(); }
+
+ base::MessageLoop* GetMessageLoop() const override {
+ return message_loop_.get();
+ }
+
+ private:
+ bool StartUpBluetoothInterfaces() {
+ if (!hal::BluetoothInterface::Initialize()) goto failed;
+
+ if (!hal::BluetoothGattInterface::Initialize()) goto failed;
+
+ return true;
+
+ failed:
+ ShutDownBluetoothInterfaces();
+ return false;
+ }
+
+ void ShutDownBluetoothInterfaces() {
+ if (hal::BluetoothGattInterface::IsInitialized())
+ hal::BluetoothGattInterface::CleanUp();
+ if (hal::BluetoothInterface::IsInitialized())
+ hal::BluetoothInterface::CleanUp();
+ }
+
+ void CleanUpBluetoothStack() {
+ // The Adapter object needs to be cleaned up before the HAL interfaces.
+ ipc_manager_.reset();
+ adapter_.reset();
+ ShutDownBluetoothInterfaces();
+ }
+
+ bool SetUpIPC() {
+ // If an IPC socket path was given, initialize IPC with it. Otherwise
+ // initialize Binder IPC.
+ if (settings_->UseSocketIPC()) {
+ if (!ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, nullptr)) {
+ LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager";
+ return false;
+ }
+ } else if (!ipc_manager_->Start(ipc::IPCManager::TYPE_BINDER, nullptr)) {
+ LOG(ERROR) << "Failed to set up Binder IPCManager";
+ return false;
+ }
+
+ return true;
+ }
+
+ bool Init() override {
+ CHECK(!initialized_);
+ message_loop_.reset(new base::MessageLoop());
+
+ settings_.reset(new Settings());
+ if (!settings_->Init()) {
+ LOG(ERROR) << "Failed to set up Settings";
+ return false;
+ }
+
+ if (!StartUpBluetoothInterfaces()) {
+ LOG(ERROR) << "Failed to set up HAL Bluetooth interfaces";
+ return false;
+ }
+
+ adapter_ = Adapter::Create();
+ ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+
+ if (!SetUpIPC()) {
+ CleanUpBluetoothStack();
+ return false;
+ }
+
+ initialized_ = true;
+ LOG(INFO) << "Daemon initialized";
+
+ return true;
+ }
+
+ bool initialized_;
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<Settings> settings_;
+ std::unique_ptr<Adapter> adapter_;
+ std::unique_ptr<ipc::IPCManager> ipc_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DaemonImpl);
+};
+
+} // namespace
+
+// static
+bool Daemon::Initialize() {
+ CHECK(!g_daemon);
+
+ g_daemon = new DaemonImpl();
+ if (g_daemon->Init()) return true;
+
+ LOG(ERROR) << "Failed to initialize the Daemon object";
+
+ delete g_daemon;
+ g_daemon = nullptr;
+
+ return false;
+}
+
+// static
+void Daemon::ShutDown() {
+ CHECK(g_daemon);
+ delete g_daemon;
+ g_daemon = nullptr;
+}
+
+// static
+void Daemon::InitializeForTesting(Daemon* test_daemon) {
+ CHECK(test_daemon);
+ CHECK(!g_daemon);
+
+ g_daemon = test_daemon;
+}
+
+// static
+Daemon* Daemon::Get() {
+ CHECK(g_daemon);
+ return g_daemon;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/daemon.h b/mtkbt/code/bt/service/daemon.h
new file mode 100755
index 0000000..0afefa9
--- a/dev/null
+++ b/mtkbt/code/bt/service/daemon.h
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+#include <base/message_loop/message_loop.h>
+
+namespace ipc {
+class IPCManager;
+} // namespace ipc
+
+namespace bluetooth {
+
+class CoreStack;
+class Settings;
+
+// The Daemon class is a singleton that represents the root of the ownership
+// hierarchy. The single instance sets up and owns the main event loop, the IPC
+// handlers, global Settings, and the core Bluetooth stack.
+class Daemon {
+ public:
+ // Initializes the daemon. This must be called to at the start of the
+ // application to set up the global daemon instance and everything it manages.
+ // Returns false in case of a failure.
+ static bool Initialize();
+
+ // Cleans up all the resources associated with the global Daemon object.
+ static void ShutDown();
+
+ // Assigns the global Daemon instance for testing. Should only be called from
+ // test code.
+ static void InitializeForTesting(Daemon* test_daemon);
+
+ // Returns the singleton Daemon instance. All classes can interact with the
+ // Daemon, obtain its resources etc using this getter.
+ static Daemon* Get();
+
+ // The global Settings object. All classes have direct access to this through
+ // the Daemon object.
+ virtual Settings* GetSettings() const = 0;
+
+ // The main event loop. This should be used for any events and delayed tasks
+ // that should be executed on the daemon's main thread.
+ virtual base::MessageLoop* GetMessageLoop() const = 0;
+
+ // Starts the daemon's main loop.
+ virtual void StartMainLoop() = 0;
+
+ protected:
+ Daemon() = default;
+ virtual ~Daemon() = default;
+
+ private:
+ // Internal instance helper called by Initialize().
+ virtual bool Init() = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/doc/IBluetooth.txt b/mtkbt/code/bt/service/doc/IBluetooth.txt
new file mode 100755
index 0000000..54695e6
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetooth.txt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC API for talking with the Bluetooth service and perform high-level
+ * operations on the adapter.
+ */
+interface IBluetooth {
+ /**
+ * Returns true if the Bluetooth adapter is powered and ready to use. This
+ * is equivalent to "getState() == ADAPTER_STATE_ON".
+ */
+ boolean isEnabled();
+
+ /**
+ * Returns the current Bluetooth adapter state. The return value can be one of
+ * the following:
+ *
+ * - ADAPTER_STATE_OFF = 10
+ * - ADAPTER_STATE_TURNING_ON = 11
+ * - ADAPTER_STATE_ON = 12
+ * - ADAPTER_STATE_TURNING_OFF = 13
+ */
+ int getState();
+
+ /**
+ * Turns on the Bluetooth radio. This function initiates the procedure to
+ * bring the adapter state from ADAPTER_STATE_OFF to ADAPTER_STATE_ON. Returns
+ * false, if the state is not ADAPTER_STATE_OFF or if there is an error while
+ * initiating the operation. On success, the adapter state will be
+ * asynchronously updated to ADAPTER_STATE_TURNING_ON and eventually to
+ * ADAPTER_STATE_ON. Callers can monitor the status of this call by observing
+ * the IBluetoothCallback.onBluetoothStateChange callback.
+ */
+ boolean enable();
+
+ /**
+ * Turns off the Bluetooth radio. This function initiates the procedure to
+ * bring the adapter state from ADAPTER_STATE_ON to ADAPTER_STATE_OFF. Returns
+ * false, if the state is not ADAPTER_STATE_ON or if there is an error while
+ * initiating the operation. On success, the adapter state will be
+ * asynchronously updated to ADAPTER_STATE_TURNING_OFF and eventually to
+ * ADAPTER_STATE_OFF. Callers can monitor the status of this call by observing
+ * the IBluetoothCallback.onBluetoothStateChange callback.
+ */
+ boolean disable();
+
+ /**
+ * Returns the identity Bluetooth Device Address (BD_ADDR) assigned to the
+ * underlying Bluetooth controller. Returns a string of the form
+ * "XX:XX:XX:XX:XX:XX", where each "X" is a hexadecimal digit. Returns
+ * "00:00:00:00:00:00" if the address is not known, which is usually the case
+ * before the adapter is enabled for the first time.
+ */
+ String getAddress();
+
+ /**
+ * Sets the name assigned to the Bluetooth adapter. This is the name that will
+ * be seen by remote devices during discovery. Returns false if the operation
+ * fails.
+ */
+ boolean setName(in String name);
+
+ /**
+ * Returns the current name assigned to the Bluetooth adapter. This is the
+ * name that is seen by remote devices during discovery. If the controller has
+ * not been initialized yet (before the first time it gets enabled), this will
+ * return "not-initialized".
+ */
+ String getName();
+
+ /**
+ * Registers a callback receiver which can be used to listen to state updates
+ * from the adapter. The Bluetooth daemon will automatically register this if
+ * the owning process dies.
+ */
+ void registerCallback(in IBluetoothCallback callback);
+
+ /**
+ * Unregisters a previously registered callback.
+ */
+ void unregisterCallback(in IBluetoothCallback callback);
+
+ /**
+ * Returns true, if the multi-advertisement feature is supported. Returns
+ * false, if this device can only advertise a single instance.
+ */
+ boolean isMultiAdvertisementSupported();
+
+ /**
+ * Returns a binder that can be used to interact with Low-Energy features.
+ */
+ IBluetoothLowEnergy getLowEnergyInterface();
+
+ /**
+ * Returns a binder that can be used to interact with GATT client-role
+ * features.
+ */
+ IBluetoothGattClient getGattClientInterface();
+
+ /**
+ * Returns a binder that can be used to interact with GATT server-role
+ * features.
+ */
+ IBluetoothGattServer getGattServerInterface();
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothCallback.txt b/mtkbt/code/bt/service/doc/IBluetoothCallback.txt
new file mode 100755
index 0000000..612ecca
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothCallback.txt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC callback interface for receiving notifications about the
+ * high-level Bluetooth adapter state.
+ */
+interface IBluetoothCallback {
+ /**
+ * Called when the adapter state changes from |prev_state| to |new_state|.
+ */
+ void onBluetoothStateChange(in int prev_state, in int new_state);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothGattClient.txt b/mtkbt/code/bt/service/doc/IBluetoothGattClient.txt
new file mode 100755
index 0000000..8e55005
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothGattClient.txt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for interacting with Bluetooth GATT client-role
+ * features.
+ * TODO(armansito): Not yet supported.
+ */
+interface IBluetoothGattClient {
+ /**
+ * Registers a client application with this interface. This creates a unique
+ * GATT client instance for the application. Returns true on success; false
+ * otherwise. If successful, the caller will be assigned a "client_id" which
+ * will be reported asynchronously via
+ * IBluetoothGattClientCallback.onRegistered. This ID is required to make
+ * calls to the functions defined below.
+ */
+ boolean registerClient(in IBluetoothGattClientCallback callback);
+
+ /**
+ * Unregisters a previously registered client with interface ID |client_id|.
+ */
+ void unregisterClient(in int client_id);
+
+ /**
+ * Unregisters all previously registered clients.
+ */
+ void unregisterAll();
+
+ /**
+ * Refreshes the local client-side attribute cache that mirrors the attribute
+ * database of remote device with address |device_address|. Returns false in
+ * case of an error. |client_id| is the identifier obtained via
+ * registerClient.
+ */
+ boolean refreshDevice(in int client_id, in String device_address);
+
+ /**
+ * Returns the GATT services, characteristics, and descriptors on the remote
+ * device with address |device_address| asynchronously via the corresponding
+ * IBluetoothGattClientCallback callbacks. Based on the current connection and
+ * bonding state, either GATT service discovery will be initiated or the
+ * results will be returned from the attribute cache. Returns false in case of
+ * an error. |client_id| is the identifier obtained via registerClient.
+ */
+ boolean discoverServices(in int client_id, in String device_address);
+
+ /**
+ * Initiate a read request for the remote characteristic with identifier
+ * |characteristic_id|. The result will be asynchronously reported in
+ * IBluetoothGattClientCallback.onCharacteristicRead. Returns false if the
+ * request cannot be started, e.g. if a read is already pending on this remote
+ * device. If the read request fails due to characteristic permissions,
+ * this function will try to raise the connection security level based on the
+ * characteristic's permission requirements. If that operation fails, then the
+ * |status| parameter of the onCharacteristicRead callback will contain the
+ * appropriate ATT protocol error code. |client_id| is obtained via
+ * registerClient.
+ */
+ boolean readCharacteristic(in int client_id,
+ in GattIdentifier characteristic_id);
+
+ /**
+ * Initiate a write request for the remote characteristic with identifier
+ * |characteristic_id| with the value |value|. The |write_type| parameter
+ * indicates which of the following GATT write procedure should be used:
+ *
+ * - WRITE_TYPE_DEFAULT (0x02): Regular Write Procedure
+ * - WRITE_TYPE_NO_RESPONSE (0x01): Write Without Response procedure
+ * - WRITE_TYPE_SIGNED (0x04): Signed Write Without Response procedure.
+ *
+ * The result will be asynchronously reported in
+ * IBluetoothGattClientCallback.onCharacteristicWrite. Returns false if the
+ * request cannot be started. If the write request fails due to attribute
+ * permissions, this function will try to raise the connection security level
+ * based on the characteristic's permission requirements. If that operation
+ * fails, then the |status| parameter of the onCharacteristicWrite callback
+ * will contain the appropriate ATT protocol error code. |client_id| is
+ * obtained via registerClient.
+ */
+ boolean writeCharacteristic(in int client_id,
+ in GattIdentifier characteristic_id,
+ in int write_type,
+ in byte[] value);
+
+ /**
+ * Initiate a read request for the remote descriptor with identifier
+ * |descriptor_id|. The result will be asynchronously reported in
+ * IBluetoothGattClientCallback.onDescriptorRead. Returns false if the
+ * request cannot be started, e.g. if a read is already pending on this remote
+ * device. If the read request fails due to descriptor permissions,
+ * this function will try to raise the connection security level based on the
+ * descriptor's permission requirements. If that operation fails, then the
+ * |status| parameter of the onDescriptorRead callback will contain the
+ * appropriate ATT protocol error code. |client_id| is obtained via
+ * registerClient.
+ */
+ boolean readDescriptor(in int client_id,
+ in GattIdentifier descriptor_id);
+
+ /**
+ * Initiate a write request for the remote descriptor with identifier
+ * |descriptor_id| with the value |value|. The |write_type| parameter
+ * indicates which of the following GATT write procedure should be used:
+ *
+ * - WRITE_TYPE_DEFAULT (0x02): Regular write procedure
+ * - WRITE_TYPE_NO_RESPONSE (0x01): Write without response procedure
+ * - WRITE_TYPE_SIGNED (0x04): Authenticated-signed write procedure
+ *
+ * The result will be asynchronously reported in
+ * IBluetoothGattClientCallback.onDescriptorWrite. Returns false if the
+ * request cannot be started. If the write request fails due to attribute
+ * permissions, this function will try to raise the connection security level
+ * based on the descriptor's permission requirements. If that operation fails,
+ * then the |status| parameter of the onDescriptorWrite callback will contain
+ * the appropriate ATT protocol error code. |client_id| is obtained via
+ * registerClient.
+ */
+ boolean writeDescriptor(in int client_id,
+ in GattIdentifier descriptor_id,
+ in int write_type,
+ in byte[] value);
+
+ /**
+ * Enables handle-value notifications from the remote characteristic with ID
+ * |characteristic_id|. If successful, notifications will be signaled via
+ * IBluetoothGattClientCallback.onNotify. Returns false if the request cannot
+ * be initiated. |client_id| is obtained via registerClient.
+ */
+ boolean registerForNotifications(in int client_id,
+ in GattIdentifier characteristic_id);
+
+ /**
+ * Disables handle-value notifications from the remote characteristic with ID
+ * |characteristic_id|. Returns false if the request cannot be initiated, e.g.
+ * if notifications from this characteristic have not been enabled.
+ * |client_id| is obtained via registerClient.
+ */
+ boolean unregisterForNotifications(in int client_id,
+ in GattIdentifier characteristic_id);
+
+ /**
+ * Initiates a reliable write procedure for the remote device with address
+ * |device_address|. Once a reliable write transaction has been initiated, all
+ * calls to writeCharacteristic are sent to the remote device for verification
+ * and queued up for atomic execution. The application can verify each write
+ * payload using the IBluetoothGattClientCallback.onCharacteristicWrite
+ * callback and abort reliable write in case of a mismatch. The queued writes
+ * will be processed atomically by the remote device after calling
+ * endReliableWrite. Returns false if the procedure cannot be started, e.g. if
+ * it has already been started earlier. |client_id| is obtained via
+ * registerClient.
+ */
+ boolean beginReliableWrite(in int client_id, in String device_address);
+
+ /**
+ * Ends a previously started reliable write procedure for the remote device
+ * with address |device_address|. If |execute| is true, then a request will be
+ * sent to execute the queued writes, else a request will be sent to abort the
+ * queued writes. Returns false in case of a failure, e.g. if a reliable write
+ * procedure was not started. IBluetoothGattClientCallback.onExecuteWrite will
+ * be used to asynchronously report the result of the execute write request.
+ * |client_id| is obtained via registerClient.
+ */
+ boolean endReliableWrite(in int client_id, in String device_address,
+ in boolean execute);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothGattClientCallback.txt b/mtkbt/code/bt/service/doc/IBluetoothGattClientCallback.txt
new file mode 100755
index 0000000..d3ec6ed
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothGattClientCallback.txt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth GATT
+ * client-role operations.
+ * TODO(armansito): Not yet supported.
+ */
+oneway interface IBluetoothGattClientCallback {
+ /**
+ * Called as a result of IBluetoothGattClient.registerClient.
+ * |status| will contain BLE_STATUS_SUCCESS (0) if the client was successfully
+ * registered. |client_id| is the owning application's unique GATT client
+ * handle and can be used to perform further operations on the
+ * IBluetoothGattClient interface.
+ */
+ void onClientRegistered(in int status, in int client_id);
+
+ /**
+ * Called for each GATT service that was discovered on the remote device. The
+ * device that this service belongs to can be obtained from the |service_id|
+ * structure. |is_primary| is true if this refers to a primary service,
+ * otherwise this refers to a secondary service.
+ */
+ void onGetService(in boolean is_primary, in GattIdentifier service_id);
+
+ /**
+ * Called for each include definition that was discovered on the remote
+ * device.
+ */
+ void onGetIncludedService(in GattIdentifier included_service_id);
+
+ /**
+ * Called for each characteristic that was discovered on the remote device.
+ * The service that this characteristic belongs to can be obtained from the
+ * |characteristic_id| structure. |properties| contains the bitmask of GATT
+ * characteristic properties as defined in the Bluetooth Core Specification.
+ */
+ void onGetCharacteristic(in GattIdentifier characteristic_id,
+ in int properties);
+
+ /**
+ * Called for each descriptor that was discovered on the remote device. The
+ * service and characteristic that this descriptor belongs to can be obtained
+ * from the |descriptor_id| structure.
+ */
+ void onGetDescriptor(in GattIdentifier descriptor_id);
+
+ /**
+ * Called to mark the end of GATT service discovery on the remote device with
+ * address |device_address|. |status| will contain BLE_STATUS_SUCCESS (0) if
+ * the operation was successful.
+ */
+ void onSearchComplete(in String device_address, in int status);
+
+ /**
+ * Called as a result of IBluetoothGattClient.readCharacteristic. |status|
+ * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+ * code in case of an error. |characteristic_id| refers to the characteristic
+ * this operation was performed on. On success, |value| will contain the
+ * characteristic value that was read from the remote device. This argument
+ * can be ignored in case of failure.
+ */
+ void onCharacteristicRead(in int status, in GattIdentifier characteristic_id,
+ in byte[] value);
+
+ /**
+ * Called as a result of IBluetoothGattClient.writeCharacteristic. |status|
+ * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+ * code in case of an error. |characteristic_id| refers to the characteristic
+ * this operation was performed on.
+ */
+ void onCharacteristicWrite(in int status,
+ in GattIdentifier characteristic_id);
+
+ /**
+ * Called as a result of IBluetoothGattClient.endReliableWrite.
+ * |device_address| refers to the remote device that the endReliableWrite
+ * method was called on. |status| will contain BLE_STATUS_SUCCESS (0) on
+ * success and an ATT error code in case of an error.
+ */
+ void onExecuteWrite(in String device_address, in int status);
+
+ /**
+ * Called as a result of IBluetoothGattClient.readDescriptor. |status|
+ * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+ * code in case of an error. |descriptor_id| refers to the descriptor this
+ * operation was performed on. On success, |value| will contain the
+ * descriptor value that was read from the remote device. This argument
+ * can be ignored in case of failure.
+ */
+ void onDescriptorRead(in int status, in GattIdentifier descriptor_id,
+ in byte[] value);
+
+ /**
+ * Called as a result of IBluetoothGattClient.writeDescriptor. |status|
+ * will contain BLE_STATUS_SUCCESS (0) on success and an ATT protocol error
+ * code in case of an error. |descriptor_id| refers to the descriptor this
+ * operation was performed on.
+ */
+ void onDescriptorWrite(in int status, in GattIdentifier descriptor_id);
+
+ /**
+ * Called when there is an incoming ATT Handle-Value notification or
+ * indication for the characteristic with identifier |characteristic_id|.
+ */
+ void onNotify(in GattIdentifier characteristic_id, in byte[] value);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothGattServer.txt b/mtkbt/code/bt/service/doc/IBluetoothGattServer.txt
new file mode 100755
index 0000000..0efecab
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothGattServer.txt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for interacting with Bluetooth GATT server-role
+ * features.
+ */
+interface IBluetoothGattServer {
+ /**
+ * Registers a client application with this interface. This creates a unique
+ * GATT server instance for the application that will contain the GATT
+ * services belonging to the calling application. A special interface ID will
+ * be returned in a callback to the application that can be used to perform
+ * GATT server operations. Returns false in case of an error.
+ */
+ boolean registerServer(in IBluetoothGattServerCallback callback);
+
+ /**
+ * Unregisters a previously registered server with interface ID |server_if|.
+ */
+ void unregisterServer(in int server_if);
+
+ /**
+ * Unregisters all previously registered servers.
+ */
+ void unregisterAll();
+
+ /**
+ * Adds new GATT service. This will execute synchronously, and result in
+ * IBluetoothGattServerCallback.onServiceAdded.
+ *
+ * Returns true on success, false otherwise.
+ */
+ boolean AddService(int server_id, in BluetoothGattService service);
+
+ /**
+ * Sends a response to a currently pending read or write request. The request
+ * will be propagated to the application via IBluetoothGattServerCallback with
+ * a unique |request_id| which must be passed to this method along with the
+ * |device_address| of the device that the request originated from.
+ *
+ * The |status| field should contain the result of the operation. In the case
+ * of success, the application should pass in "0". Otherwise this should
+ * contain an ATT protocol error code.
+ */
+ boolean sendResponse(in int server_if, in String device_address,
+ in int request_id, in int status,
+ in int offset, in byte[] value);
+
+ /**
+ * Sends a handle-value notification or indication to the device with the
+ * given address for the characteristic with the given handle. |confirm|
+ * should be set to true, if a handle-value indication should be sent, which
+ * will remain pending until the remote device sends a handle-value
+ * confirmation. Returns false if a call to this method is pending. Otherwise
+ * reports the result asynchronously in
+ * IBluetoothGattServerCallback.onNotificationSent.
+ */
+ boolean sendNotification(in int server_if, in String device_address,
+ in int handle,
+ in boolean confirm, in byte[] value);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothGattServerCallback.txt b/mtkbt/code/bt/service/doc/IBluetoothGattServerCallback.txt
new file mode 100755
index 0000000..3744ff1
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothGattServerCallback.txt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth GATT
+ * server-role operations.
+ */
+oneway interface IBluetoothGattServerCallback {
+ /**
+ * Called to report the result of a call to
+ * IBluetoothGattServer.registerServer. |status| will be 0 (or
+ * BLE_STATUS_SUCCESS) if the server was successfully registered. |server_if|
+ * is the owning application's unique GATT server handle and can be used to
+ * perform further operations on the IBluetoothGattServer interface.
+ */
+ void onServerRegistered(in int status, in int server_if);
+
+ /**
+ * Called to report the result of a call to IBluetoothGattServer.AddService.
+ * A |status| of 0 denotes success, which means that the GATT service has
+ * been published and is discoverable. In this case handles of added service,
+ * it's characteristics and descriptors are filled.
+ */
+ void onServiceAdded(in int status, in BluetoothGattServer service_id);
+
+ /**
+ * Called when there is an incoming read request from the remote device with
+ * address |device_address| for the characteristic with handle |handle|.
+ * |offset| is the index of the characteristic value that
+ * the remote device wants to read from. If |is_long| is true, then this
+ * request is part of a Long Read procedure. An implementation should handle
+ * this request by calling IBluetoothGattServer.sendResponse with the given
+ * |request_id| and the appropriate characteristic value.
+ *
+ * If |offset| is invalid then sendResponse should be called with
+ * GATT_ERROR_INVALID_OFFSET. If |is_long| is true but this characteristic is
+ * not a long attribute (i.e. its value would fit within the current ATT MTU),
+ * then GATT_ERROR_ATTRIBUTE_NOT_LONG should be returned.
+ */
+ void onCharacteristicReadRequest(in String device_address, in int request_id,
+ in int offset, in boolean is_long,
+ in int handle);
+
+ /**
+ * Called when there is an incoming read request from the remote device with
+ * address |device_address| for the descriptor with handle |handle|.
+ * |offset| is the index of the descriptor value that
+ * the remote device wants to read from. If |is_long| is true, then this
+ * request is part of a Long Read procedure. An implementation should handle
+ * this request by calling IBluetoothGattServer.sendResponse with the given
+ * |request_id| and the appropriate descriptor value.
+ *
+ * If |offset| is invalid then sendResponse should be called with
+ * GATT_ERROR_INVALID_OFFSET. If |is_long| is true but this descriptor is
+ * not a long attribute (i.e. its value would fit within the current ATT MTU),
+ * then GATT_ERROR_ATTRIBUTE_NOT_LONG should be returned.
+ */
+ void onDescriptorReadRequest(in String device_address, in int request_id,
+ in int offset, in boolean is_long,
+ in int handle);
+
+ /**
+ * Called when there is an incoming write request from the remote device with
+ * address |device_address| for the characteristic with handle |handle|
+ * with the value |value|. An implementation should handle
+ * this request by calling IBluetoothGattServer.sendResponse with the given
+ * |request_id|. |offset| is the index of the characteristic value that the
+ * remote device wants to write to, so the value should be written starting at
+ * |offset|. If |need_response| is false, then this is a "Write Without
+ * Response" procedure and sendResponse should not be called. If
+ * |is_prepare_write| is true, then the implementation should not commit this
+ * write until a call to onExecuteWriteRequest is received.
+ *
+ * If |offset| is invalid, then sendResponse should be called with
+ * GATT_ERROR_INVALID_OFFSET.
+ */
+ void onCharacteristicWriteRequest(in String device_address, in int request_id,
+ in int offset, in boolean is_prepare_write,
+ in boolean need_response, in byte[] value,
+ in int handle);
+
+ /**
+ * Called when there is an incoming write request from the remote device with
+ * address |device_address| for the descriptor with handle |handle|
+ * with the value |value|. An implementation should handle
+ * this request by calling IBluetoothGattServer.sendResponse with the given
+ * |request_id|. |offset| is the index of the descriptor value that the
+ * remote device wants to write to, so the value should be written starting at
+ * |offset|. If |need_response| is false, then this is a "Write Without
+ * Response" procedure and sendResponse should not be called. If
+ * |is_prepare_write| is true, then the implementation should not commit this
+ * write until a call to onExecuteWriteRequest is received.
+ *
+ * If |offset| is invalid, then sendResponse should be called with
+ * GATT_ERROR_INVALID_OFFSET.
+ */
+ void onDescriptorWriteRequest(in String device_address, in int request_id,
+ in int offset, in boolean is_prepare_write,
+ in boolean need_response, in byte[] value,
+ in int handle);
+
+ /**
+ * Called when there is an incoming execute-write request to commit or abort
+ * previously prepared writes. If |is_execute| is true, then the
+ * implementation should commit all previously prepared writes. Otherwise all
+ * prepared writes should dropped (aborted). The application should report the
+ * result of the execute write by calling IBluetoothGattServer.sendResponse
+ * with the given |request_id|.
+ */
+ void onExecuteWriteRequest(in String device_address, in int request_id,
+ in boolean is_execute);
+
+ /**
+ * Reports the result of a previous call to
+ * IBluetoothGattServer.sendNotification. If an indication was sent, this will
+ * be called when the remote device sends a confirmation packet. Otherwise
+ * this will be called as soon as the notification packet is successfully sent
+ * out over the radio.
+ */
+ void onNotificationSent(in String device_address, in int status);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothLowEnergy.txt b/mtkbt/code/bt/service/doc/IBluetoothLowEnergy.txt
new file mode 100755
index 0000000..b7218cb
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothLowEnergy.txt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC API for interacting with Bluetooth Low-Energy features.
+ */
+interface IBluetoothLowEnergy {
+ /**
+ * Registers a client application that can manage its own Low Energy
+ * instance. A special client interface ID will be returned in a callback to
+ * the application that can be used to perform Low Energy operations. Returns
+ * false in case of an error.
+ */
+ boolean registerClient(in IBluetoothLowEnergyCallback callback);
+
+ /**
+ * Unregisters a previously registered client with "client interface ID"
+ * |client_if|.
+ */
+ void unregisterClient(in int client_if);
+
+ /**
+ * Unregisters all previously registered clients.
+ */
+ void unregisterAll();
+
+ /* Initiates a BLE connection do device with address |address|. If
+ * |is_direct| is set, use direct connect procedure. Return true on success,
+ * false otherwise.
+ */
+ boolean Connect(in int client_id, in const char* address,
+ in boolean is_direct);
+
+ /* Disconnect from previously connected BLE device with address |address|.
+ * Returns true on success, false otherwise.
+ */
+ boolean Disconnect(in int client_id, in const char* address);
+
+ /**
+ * Sends request to set MTU to |mtu| for the device with address |address|.
+ * OnMtuChanged callback will be triggered as a result of this call. Returns
+ * true when the command was sent, false otherwise.
+ */
+ boolean setMtu(in int client_id, in char* address, int mtu);
+
+ /**
+ * Initiates a BLE device scan for the scan client with ID |client_id|, using
+ * the parameters defined in |settings|. Scan results that are reported to the
+ * application with the associated IBluetoothLowEnergyCallback event will be
+ * filtered using a combination of hardware and software filtering based on
+ * |filters|. Return true on success, false otherwise.
+ */
+ boolean startScan(in int client_id, in ScanSettings settings,
+ in ScanFilter[] filters);
+
+ /**
+ * Stops a previously initiated scan session for the client with ID
+ * |client_id|. Return true on success, false otherwise.
+ */
+ boolean stopScan(in int client_id);
+
+ /**
+ * Starts a multi-advertising instance using |advertising_data| and
+ * |scan_response_data|, both of which can be empty. Each of these parameters
+ * must contain the raw advertising packet. Returns false if there were any
+ * synchronous failures, e.g. if the advertising or scan response data are
+ * incorrectly formatted. Otherwise, the result of the operation will be
+ * asynchronously reported in
+ * IBluetoothLowEnergyCallback.onMultiAdvertiseCallback. See the headers in
+ * common/bluetooth/binder for documentation on the AdvertiseData and
+ * AdvertiseSettings data types.
+ */
+ boolean startMultiAdvertising(in int client_if,
+ in AdvertiseData advertise_data,
+ in AdvertiseData scan_response_data,
+ in AdvertiseSettings settings);
+
+ /**
+ * Stops the previously started multi-advertising instance for the given
+ * client. Returns false in case of an error, e.g. this client has not started
+ * an instance.
+ */
+ boolean stopMultiAdvertising(in int client_if);
+}
diff --git a/mtkbt/code/bt/service/doc/IBluetoothLowEnergyCallback.txt b/mtkbt/code/bt/service/doc/IBluetoothLowEnergyCallback.txt
new file mode 100755
index 0000000..1ced0aa
--- a/dev/null
+++ b/mtkbt/code/bt/service/doc/IBluetoothLowEnergyCallback.txt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Binder IPC interface for receiving callbacks related to Bluetooth Low Energy
+ * operations.
+ */
+oneway interface IBluetoothLowEnergyCallback {
+ /**
+ * Called to report the result of a call to
+ * IBluetoothLowEnergy.registerClient. |status| will be BLE_STATUS_SUCCESS (0)
+ * if the client was successfully registered. |client_if| is the owning
+ * application's unique Low Energy client handle and can be used
+ * to perform further operations on the IBluetoothLowEnergy interface.
+ */
+ void onClientRegistered(in int status, in int client_if);
+
+ /* Called asynchronously to notify the delegate of connection state change.
+ */
+ void OnConnectionState(in int status, in int client_id, in const char* address,
+ in bool connected);
+
+ /* Called to report current MTU value. Can be a result of calling
+ * IBluetoothLowEnergy.setMtu or remote device trying to change MTU.
+ */
+ void OnMtuChanged(in int status, in const char* address, in int mtu);
+
+ /**
+ * Called to report BLE device scan results once a scan session is started for
+ * this client using IBluetoothLowEnergy.startScan. |scan_result| contains all
+ * the data related to the discovered BLE device.
+ */
+ void onScanResult(in ScanResult scan_result);
+
+ /**
+ * Called to report the result of a call to
+ * IBluetoothLowEnergy.startMultiAdvertising or stopMultiAdvertising.
+ */
+ void onMultiAdvertiseCallback(in int status, in boolean is_start,
+ in AdvertiseSettings settings);
+}
diff --git a/mtkbt/code/bt/service/example/heart_rate/constants.h b/mtkbt/code/bt/service/example/heart_rate/constants.h
new file mode 100755
index 0000000..6159997
--- a/dev/null
+++ b/mtkbt/code/bt/service/example/heart_rate/constants.h
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <bluetooth/uuid.h>
+
+// This header defines constants specific to the GATT Heart Rate Service.
+
+namespace heart_rate {
+
+// HR Measurement characteristic value flags
+const uint8_t kHRValueFormat8Bit = (0 << 0);
+const uint8_t kHRValueFormat16Bit = (1 << 0);
+const uint16_t kHRSensorContactDetected = (3 << 1);
+const uint8_t kHREnergyExpendedPresent = (1 << 3);
+
+const bluetooth::UUID kCCCDescriptorUUID("2902");
+const bluetooth::UUID kHRServiceUUID("180D");
+const bluetooth::UUID kHRMeasurementUUID("2A37");
+const bluetooth::UUID kBodySensorLocationUUID("2A38");
+const bluetooth::UUID kHRControlPointUUID("2A39");
+
+const uint8_t kHRBodyLocationOther = 0;
+const uint8_t kHRBodyLocationChest = 1;
+const uint8_t kHRBodyLocationWrist = 2;
+const uint8_t kHRBodyLocationFinger = 3;
+const uint8_t kHRBodyLocationHand = 4;
+const uint8_t kHRBodyLocationEarLobe = 5;
+const uint8_t kHRBodyLocationFoot = 6;
+
+} // namespace heart_rate
diff --git a/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.cc b/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.cc
new file mode 100755
index 0000000..a7bfe52
--- a/dev/null
+++ b/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.cc
@@ -0,0 +1,493 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/rand_util.h>
+
+#include <android/bluetooth/BnBluetoothLeAdvertiserCallback.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <bluetooth/low_energy_constants.h>
+
+#include "constants.h"
+#include "heart_rate_server.h"
+
+using android::binder::Status;
+using android::String8;
+using android::String16;
+
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::BluetoothGattService;
+
+namespace heart_rate {
+
+class CLIBluetoothLeAdvertiserCallback
+ : public android::bluetooth::BnBluetoothLeAdvertiserCallback {
+ public:
+ explicit CLIBluetoothLeAdvertiserCallback(
+ android::sp<android::bluetooth::IBluetooth> bt)
+ : bt_(bt) {}
+
+ // IBluetoothLeAdvertiserCallback overrides:
+ Status OnAdvertiserRegistered(int status, int advertiser_id) {
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ LOG(ERROR)
+ << "Failed to register BLE advertiser, will not start advertising";
+ return Status::ok();
+ }
+
+ LOG(INFO) << "Registered BLE advertiser with ID: " << advertiser_id;
+
+ String16 name_param;
+ bt_->GetName(&name_param);
+ std::string name(String8(name_param).string());
+
+ /* Advertising data: 16-bit Service UUID: Heart Rate Service, Tx power*/
+ std::vector<uint8_t> data{0x03, bluetooth::kEIRTypeComplete16BitUUIDs,
+ 0x0D, 0x18,
+ 0x02, bluetooth::kEIRTypeTxPower,
+ 0x00};
+ data.push_back(name.length() + 1);
+ data.push_back(bluetooth::kEIRTypeCompleteLocalName);
+ data.insert(data.end(), name.c_str(), name.c_str() + name.length());
+
+ base::TimeDelta timeout;
+
+ bluetooth::AdvertiseSettings settings(
+ bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
+ bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, true);
+
+ bluetooth::AdvertiseData adv_data(data);
+ bluetooth::AdvertiseData scan_rsp;
+
+ android::sp<IBluetoothLeAdvertiser> ble;
+ bt_->GetLeAdvertiserInterface(&ble);
+ bool start_status;
+ ble->StartMultiAdvertising(advertiser_id, adv_data, scan_rsp, settings,
+ &start_status);
+ return Status::ok();
+ }
+
+ Status OnMultiAdvertiseCallback(
+ int status, bool is_start,
+ const android::bluetooth::AdvertiseSettings& /* settings */) {
+ LOG(INFO) << "Advertising" << (is_start ? " started" : " stopped");
+ return Status::ok();
+ };
+
+ private:
+ android::sp<android::bluetooth::IBluetooth> bt_;
+ DISALLOW_COPY_AND_ASSIGN(CLIBluetoothLeAdvertiserCallback);
+};
+
+HeartRateServer::HeartRateServer(
+ android::sp<android::bluetooth::IBluetooth> bluetooth,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ bool advertise)
+ : simulation_started_(false),
+ bluetooth_(bluetooth),
+ server_if_(-1),
+ hr_notification_count_(0),
+ energy_expended_(0),
+ advertise_(advertise),
+ main_task_runner_(main_task_runner),
+ weak_ptr_factory_(this) {
+ CHECK(bluetooth_.get());
+}
+
+HeartRateServer::~HeartRateServer() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!gatt_.get() || server_if_ == -1) return;
+
+ if (!android::IInterface::asBinder(gatt_.get())->isBinderAlive()) return;
+
+ // Manually unregister ourselves from the daemon. It's good practice to do
+ // this, even though the daemon will automatically unregister us if this
+ // process exits.
+ gatt_->UnregisterServer(server_if_);
+}
+
+bool HeartRateServer::Run(const RunCallback& callback) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (pending_run_cb_) {
+ LOG(ERROR) << "Already started";
+ return false;
+ }
+
+ // Grab the IBluetoothGattServer binder from the Bluetooth daemon.
+ bluetooth_->GetGattServerInterface(&gatt_);
+ if (!gatt_.get()) {
+ LOG(ERROR) << "Failed to obtain handle to IBluetoothGattServer interface";
+ return false;
+ }
+
+ // Register this instance as a GATT server. If this call succeeds, we will
+ // asynchronously receive a server ID via the OnServerRegistered callback.
+ bool status;
+ gatt_->RegisterServer(this, &status);
+ if (!status) {
+ LOG(ERROR) << "Failed to register with the server interface";
+ return false;
+ }
+
+ pending_run_cb_ = callback;
+
+ return true;
+}
+
+void HeartRateServer::ScheduleNextMeasurement() {
+ main_task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&HeartRateServer::SendHeartRateMeasurement,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(1));
+}
+
+void HeartRateServer::SendHeartRateMeasurement() {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ // Send a notification or indication to all enabled devices.
+ bool found = false;
+ for (const auto& iter : device_ccc_map_) {
+ uint8_t ccc_val = iter.second;
+
+ if (!ccc_val) continue;
+
+ found = true;
+
+ // Don't send a notification if one is already pending for this device.
+ if (pending_notification_map_[iter.first]) continue;
+
+ std::vector<uint8_t> value;
+ BuildHeartRateMeasurementValue(&value);
+
+ bool status;
+ gatt_->SendNotification(server_if_, String16(String8(iter.first.c_str())),
+ hr_measurement_handle_, false, value, &status);
+ if (status) pending_notification_map_[iter.first] = true;
+ }
+
+ // Still enabled!
+ if (found) {
+ ScheduleNextMeasurement();
+ return;
+ }
+
+ // All clients disabled notifications.
+ simulation_started_ = false;
+
+ // TODO(armansito): We should keep track of closed connections here so that we
+ // don't send notifications to uninterested clients.
+}
+
+void HeartRateServer::BuildHeartRateMeasurementValue(
+ std::vector<uint8_t>* out_value) {
+ CHECK(out_value); // Assert that |out_value| is not nullptr.
+
+ // Default flags field. Here is what we put in there:
+ // Bit 0: 0 - 8-bit Heart Rate value
+ // Bits 1 & 2: 11 - Sensor contact feature supported and contact detected.
+ uint8_t flags = kHRValueFormat8Bit | kHRSensorContactDetected;
+
+ // Our demo's heart rate. Pick a value between 90 and 130.
+ uint8_t heart_rate = base::RandInt(90, 130);
+
+ // On every tenth beat we include the Energy Expended value.
+ bool include_ee = false;
+ if (!(hr_notification_count_ % 10)) {
+ include_ee = true;
+ flags |= kHREnergyExpendedPresent;
+ }
+
+ hr_notification_count_++;
+ energy_expended_ = std::min(UINT16_MAX, (int)energy_expended_ + 1);
+
+ // Add all the value bytes.
+ out_value->push_back(flags);
+ out_value->push_back(heart_rate);
+ if (include_ee) {
+ out_value->push_back(energy_expended_);
+ out_value->push_back(energy_expended_ >> 8);
+ }
+}
+
+Status HeartRateServer::OnServerRegistered(int status, int server_if) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to register GATT server";
+ pending_run_cb_(false);
+ return Status::ok();
+ }
+
+ // Registration succeeded. Store our ID, as we need it for GATT server
+ // operations.
+ server_if_ = server_if;
+
+ LOG(INFO) << "Heart Rate server registered - server_if: " << server_if_;
+
+ bluetooth::Service hrService(
+ 0, true, kHRServiceUUID,
+ {{0,
+ kHRMeasurementUUID,
+ bluetooth::kCharacteristicPropertyNotify,
+ 0,
+ {{0, kCCCDescriptorUUID, (bluetooth::kAttributePermissionRead |
+ bluetooth::kAttributePermissionWrite)}}},
+ {0,
+ kBodySensorLocationUUID,
+ bluetooth::kCharacteristicPropertyRead,
+ bluetooth::kAttributePermissionRead,
+ {}},
+ {0,
+ kHRControlPointUUID,
+ bluetooth::kCharacteristicPropertyWrite,
+ bluetooth::kAttributePermissionWrite,
+ {}}},
+ {});
+
+ bool op_status = true;
+
+ Status stat = gatt_->AddService(server_if_, (BluetoothGattService)hrService,
+ &op_status);
+ if (!stat.isOk()) {
+ LOG(ERROR) << "Failed to add service, status is: " /*<< stat*/;
+ pending_run_cb_(false);
+ return Status::ok();
+ }
+
+ if (!op_status) {
+ LOG(ERROR) << "Failed to add service";
+ pending_run_cb_(false);
+ return Status::ok();
+ }
+
+ LOG(INFO) << "Initiated AddService request";
+ return Status::ok();
+}
+
+Status HeartRateServer::OnServiceAdded(
+ int status, const android::bluetooth::BluetoothGattService& service) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to add Heart Rate service";
+ pending_run_cb_(false);
+ return Status::ok();
+ }
+
+ hr_service_handle_ = service.handle();
+ hr_measurement_handle_ = service.characteristics()[0].handle();
+ hr_measurement_cccd_handle_ =
+ service.characteristics()[0].descriptors()[0].handle();
+ body_sensor_loc_handle_ = service.characteristics()[1].handle();
+ hr_control_point_handle_ = service.characteristics()[2].handle();
+
+ LOG(INFO) << "Heart Rate service added";
+ pending_run_cb_(true);
+
+ if (advertise_) {
+ android::sp<IBluetoothLeAdvertiser> ble;
+ bluetooth_->GetLeAdvertiserInterface(&ble);
+ bool status;
+ ble->RegisterAdvertiser(new CLIBluetoothLeAdvertiserCallback(bluetooth_),
+ &status);
+ }
+
+ return Status::ok();
+}
+
+Status HeartRateServer::OnCharacteristicReadRequest(
+ const String16& device_address, int request_id, int offset,
+ bool /* is_long */, int handle) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ // This is where we handle an incoming characteristic read. Only the body
+ // sensor location characteristic is readable.
+ CHECK(handle == body_sensor_loc_handle_);
+
+ std::vector<uint8_t> value;
+ bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
+ if (offset > 1)
+ error = bluetooth::GATT_ERROR_INVALID_OFFSET;
+ else if (offset == 0)
+ value.push_back(kHRBodyLocationFoot);
+
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
+ value, &status);
+ return Status::ok();
+}
+
+Status HeartRateServer::OnDescriptorReadRequest(const String16& device_address,
+ int request_id, int offset,
+ bool /* is_long */,
+ int handle) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ // This is where we handle an incoming characteristic descriptor read. There
+ // is only one descriptor.
+ if (handle != hr_measurement_cccd_handle_) {
+ std::vector<uint8_t> value;
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_ATTRIBUTE_NOT_FOUND, offset,
+ value, &status);
+ return Status::ok();
+ }
+
+ // 16-bit value encoded as little-endian.
+ const uint8_t value_bytes[] = {
+ device_ccc_map_[std::string(String8(device_address).string())], 0x00};
+
+ std::vector<uint8_t> value;
+ bluetooth::GATTError error = bluetooth::GATT_ERROR_NONE;
+ if (offset > 2)
+ error = bluetooth::GATT_ERROR_INVALID_OFFSET;
+ else
+ value.insert(value.begin(), value_bytes + offset, value_bytes + 2 - offset);
+
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id, error, offset,
+ value, &status);
+ return Status::ok();
+}
+
+Status HeartRateServer::OnCharacteristicWriteRequest(
+ const String16& device_address, int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, int handle) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ std::vector<uint8_t> dummy;
+
+ // This is where we handle an incoming characteristic write. The Heart Rate
+ // service doesn't really support prepared writes, so we just reject them to
+ // keep things simple.
+ if (is_prepare_write) {
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
+ dummy, &status);
+ return Status::ok();
+ }
+
+ // Heart Rate Control point is the only writable characteristic.
+ CHECK(handle == hr_control_point_handle_);
+
+ // Writes to the Heart Rate Control Point characteristic must contain a single
+ // byte with the value 0x01.
+ if (value.size() != 1 || value[0] != 0x01) {
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_OUT_OF_RANGE, offset, dummy,
+ &status);
+ return Status::ok();
+ }
+
+ LOG(INFO) << "Heart Rate Control Point written; Enery Expended reset!";
+ energy_expended_ = 0;
+
+ if (!need_response) return Status::ok();
+
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
+ return Status::ok();
+}
+
+Status HeartRateServer::OnDescriptorWriteRequest(
+ const String16& device_address, int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, int handle) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ std::vector<uint8_t> dummy;
+
+ // This is where we handle an incoming characteristic write. The Heart Rate
+ // service doesn't really support prepared writes, so we just reject them to
+ // keep things simple.
+ if (is_prepare_write) {
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, offset,
+ dummy, &status);
+ return Status::ok();
+ }
+
+ // CCC is the only descriptor we have.
+ CHECK(handle == hr_measurement_cccd_handle_);
+
+ // CCC must contain 2 bytes for a 16-bit value in little-endian. The only
+ // allowed values here are 0x0000 and 0x0001.
+ if (value.size() != 2 || value[1] != 0x00 || value[0] > 0x01) {
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_CCCD_IMPROPERLY_CONFIGURED,
+ offset, dummy, &status);
+ return Status::ok();
+ }
+
+ device_ccc_map_[std::string(String8(device_address).string())] = value[0];
+
+ LOG(INFO) << "Heart Rate Measurement CCC written - device: " << device_address
+ << " value: " << (int)value[0];
+
+ // Start the simulation.
+ if (!simulation_started_ && value[0]) {
+ simulation_started_ = true;
+ ScheduleNextMeasurement();
+ }
+
+ if (!need_response) return Status::ok();
+
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_NONE, offset, dummy, &status);
+ return Status::ok();
+}
+
+Status HeartRateServer::OnExecuteWriteRequest(const String16& device_address,
+ int request_id,
+ bool /* is_execute */) {
+ // We don't support Prepared Writes so, simply return Not Supported error.
+ std::vector<uint8_t> dummy;
+ bool status;
+ gatt_->SendResponse(server_if_, device_address, request_id,
+ bluetooth::GATT_ERROR_REQUEST_NOT_SUPPORTED, 0, dummy,
+ &status);
+
+ return Status::ok();
+}
+
+Status HeartRateServer::OnNotificationSent(const String16& device_address,
+ int status) {
+ LOG(INFO) << "Notification was sent - device: " << device_address
+ << " status: " << status;
+ std::lock_guard<std::mutex> lock(mutex_);
+ pending_notification_map_[std::string(String8(device_address).string())] =
+ false;
+
+ return Status::ok();
+}
+
+Status HeartRateServer::OnConnectionStateChanged(const String16& device_address,
+ bool connected) {
+ LOG(INFO) << "Connection state changed - device: " << device_address
+ << " connected: " << (connected ? "true" : "false");
+ return Status::ok();
+}
+} // namespace heart_rate
diff --git a/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.h b/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.h
new file mode 100755
index 0000000..5f64d85
--- a/dev/null
+++ b/mtkbt/code/bt/service/example/heart_rate/heart_rate_server.h
@@ -0,0 +1,144 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/weak_ptr.h>
+#include <base/single_thread_task_runner.h>
+
+#include <android/bluetooth/BnBluetoothGattServerCallback.h>
+#include <android/bluetooth/IBluetooth.h>
+
+using android::binder::Status;
+using android::String16;
+
+namespace heart_rate {
+
+// Implements an example GATT Heart Rate service. This class emulates the
+// behavior of a heart rate service by sending fake heart-rate pulses.
+class HeartRateServer
+ : public android::bluetooth::BnBluetoothGattServerCallback {
+ public:
+ HeartRateServer(android::sp<android::bluetooth::IBluetooth> bluetooth,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ bool advertise);
+ ~HeartRateServer() override;
+
+ // Set up the server and register the GATT services with the stack. This
+ // initiates a set of asynchronous procedures. Invokes |callback|
+ // asynchronously with the result of the operation.
+ using RunCallback = std::function<void(bool success)>;
+ bool Run(const RunCallback& callback);
+
+ private:
+ // Helpers for posting heart rate measurement notifications.
+ void ScheduleNextMeasurement();
+ void SendHeartRateMeasurement();
+ void BuildHeartRateMeasurementValue(std::vector<uint8_t>* out_value);
+
+ // ipc::binder::IBluetoothGattServerCallback override:
+ Status OnServerRegistered(int status, int server_id) override;
+ Status OnServiceAdded(
+ int status,
+ const android::bluetooth::BluetoothGattService& service) override;
+ Status OnCharacteristicReadRequest(const String16& device_address,
+ int request_id, int offset, bool is_long,
+ int handle) override;
+ Status OnDescriptorReadRequest(const String16& device_address, int request_id,
+ int offset, bool is_long, int handle) override;
+ Status OnCharacteristicWriteRequest(const String16& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ int handle) override;
+ Status OnDescriptorWriteRequest(const String16& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ int handle) override;
+ Status OnExecuteWriteRequest(const String16& device_address, int request_id,
+ bool is_execute) override;
+ Status OnNotificationSent(const String16& device_address,
+ int status) override;
+ Status OnConnectionStateChanged(const String16& device_address,
+ bool connected) override;
+
+ // Single mutex to protect all variables below.
+ std::mutex mutex_;
+
+ // This stores whether or not at least one remote device has written to the
+ // CCC descriptor.
+ bool simulation_started_;
+
+ // The IBluetooth and IBluetoothGattServer binders that we use to communicate
+ // with the Bluetooth daemon's GATT server features.
+ android::sp<android::bluetooth::IBluetooth> bluetooth_;
+ android::sp<android::bluetooth::IBluetoothGattServer> gatt_;
+
+ // ID assigned to us by the daemon to operate on our dedicated GATT server
+ // instance.
+ int server_if_;
+
+ // Callback passed to Run(). We use this to tell main that all attributes have
+ // been registered with the daemon.
+ RunCallback pending_run_cb_;
+
+ // Stores whether or not an outgoing notification is still pending. We use
+ // this to throttle notifications so that we don't accidentally congest the
+ // connection.
+ std::unordered_map<std::string, bool> pending_notification_map_;
+
+ // The current HR notification count.
+ int hr_notification_count_;
+
+ // The Energy Expended value we use in our notifications.
+ uint16_t energy_expended_;
+
+ // Handles that refer to Heart Rate Service GATT objects.
+ // These returned to us from the Bluetooth daemon as we populate the database.
+ uint16_t hr_service_handle_;
+ uint16_t hr_measurement_handle_;
+ uint16_t hr_measurement_cccd_handle_;
+ uint16_t body_sensor_loc_handle_;
+ uint16_t hr_control_point_handle_;
+
+ // The daemon itself doesn't maintain a Client Characteristic Configuration
+ // mapping, so we do it ourselves here.
+ std::unordered_map<std::string, uint8_t> device_ccc_map_;
+
+ // Wether we should also start advertising
+ bool advertise_;
+
+ // libchrome task runner that we use to post heart rate measurement
+ // notifications on the main thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+ // We use this to pass weak_ptr's to base::Bind, which won't execute if the
+ // HeartRateServer object gets deleted. This is a convenience utility from
+ // libchrome and we use it here since base::TaskRunner uses base::Callback.
+ // Note: This should remain the last member so that it'll be destroyed and
+ // invalidate its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<HeartRateServer> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeartRateServer);
+};
+
+} // namespace heart_rate
diff --git a/mtkbt/code/bt/service/example/heart_rate/server_main.cc b/mtkbt/code/bt/service/example/heart_rate/server_main.cc
new file mode 100755
index 0000000..76e7741
--- a/dev/null
+++ b/mtkbt/code/bt/service/example/heart_rate/server_main.cc
@@ -0,0 +1,160 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/command_line.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <android/bluetooth/IBluetooth.h>
+
+#include "heart_rate_server.h"
+
+using android::sp;
+using android::OK;
+using android::bluetooth::IBluetooth;
+
+using android::getService;
+
+namespace {
+
+std::string kServiceName = "bluetooth-service";
+
+void QuitMessageLoop() {
+ // I don't know why both of these calls are necessary but the message loop
+ // doesn't stop unless I call both. Bug in base::MessageLoop?
+ base::RunLoop().Quit();
+ base::MessageLoop::current()->QuitNow();
+}
+
+// Handles the case where the Bluetooth process dies.
+class BluetoothDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ explicit BluetoothDeathRecipient(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ : main_task_runner_(main_task_runner) {}
+
+ ~BluetoothDeathRecipient() override = default;
+
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& /* who */) override {
+ LOG(ERROR) << "The Bluetooth daemon has died. Aborting.";
+
+ // binderDied executes on a dedicated thread. We need to stop the main loop
+ // on the main thread so we post a message to it here. The main loop only
+ // runs on the main thread.
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(&QuitMessageLoop));
+
+ android::IPCThreadState::self()->stopProcess();
+ }
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+};
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ logging::LoggingSettings log_settings;
+
+ // Initialize global logging based on command-line parameters (this is a
+ // libchrome pattern).
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ return EXIT_FAILURE;
+ }
+
+ // Set up a message loop so that we can schedule timed Heart Rate
+ // notifications.
+ base::MessageLoop main_loop;
+
+ LOG(INFO) << "Starting GATT Heart Rate Service sample";
+
+ sp<IBluetooth> bluetooth;
+ status_t status = getService(String16(kServiceName.c_str()), &bluetooth);
+ if (status != OK) {
+ LOG(ERROR) << "Failed to get service binder: '" << kServiceName
+ << "' status=" << status;
+ return EXIT_FAILURE;
+ }
+
+ // Bluetooth needs to be enabled for our demo to work.
+ bool enabled;
+ bluetooth->IsEnabled(&enabled);
+ if (!enabled) {
+ LOG(ERROR) << "Bluetooth is not enabled.";
+ return EXIT_FAILURE;
+ }
+
+ // Register for death notifications on the IBluetooth binder. This let's us
+ // handle the case where the Bluetooth daemon process (bluetoothtbd) dies
+ // outside of our control.
+ sp<BluetoothDeathRecipient> dr(
+ new BluetoothDeathRecipient(main_loop.task_runner()));
+ if (android::IInterface::asBinder(bluetooth.get())->linkToDeath(dr) !=
+ android::NO_ERROR) {
+ LOG(ERROR) << "Failed to register DeathRecipient for IBluetooth";
+ return EXIT_FAILURE;
+ }
+
+ // Initialize the Binder process thread pool. We have to set this up,
+ // otherwise, incoming callbacks from the Bluetooth daemon would block the
+ // main thread (in other words, we have to do this as we are a "Binder
+ // server").
+ android::ProcessState::self()->startThreadPool();
+
+ // heart_rate::HeartRateServer notifies success or failure asynchronously
+ // using a closure, so we set up a lambda for that here.
+ auto callback = [&](bool success) {
+ if (success) {
+ LOG(INFO) << "Heart Rate service started successfully";
+ return;
+ }
+
+ LOG(ERROR) << "Starting Heart Rate server failed asynchronously";
+ main_loop.QuitWhenIdle();
+ };
+
+ bool advertise =
+ base::CommandLine::ForCurrentProcess()->HasSwitch("advertise");
+
+ // Create the Heart Rate server.
+ std::unique_ptr<heart_rate::HeartRateServer> hr(
+ new heart_rate::HeartRateServer(bluetooth, main_loop.task_runner(),
+ advertise));
+ if (!hr->Run(callback)) {
+ LOG(ERROR) << "Failed to start Heart Rate server";
+ return EXIT_FAILURE;
+ }
+
+ // Run the main loop on the main process thread. Binder callbacks will be
+ // received in dedicated threads set up by the ProcessState::startThreadPool
+ // call above but we use this main loop for sending out heart rate
+ // notifications.
+ main_loop.Run();
+
+ LOG(INFO) << "Exiting";
+ return EXIT_SUCCESS;
+}
diff --git a/mtkbt/code/bt/service/gatt_client.cc b/mtkbt/code/bt/service/gatt_client.cc
new file mode 100755
index 0000000..0567dd7
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_client.cc
@@ -0,0 +1,102 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/gatt_client.h"
+
+#include <base/logging.h>
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// GattClient implementation
+// ========================================================
+
+GattClient::GattClient(const UUID& uuid, int client_id)
+ : app_identifier_(uuid), client_id_(client_id) {}
+
+GattClient::~GattClient() {
+ // Automatically unregister the client.
+ VLOG(1) << "GattClient unregistering client: " << client_id_;
+
+ hal::BluetoothGattInterface::Get()
+ ->GetClientHALInterface()
+ ->unregister_client(client_id_);
+}
+
+const UUID& GattClient::GetAppIdentifier() const { return app_identifier_; }
+
+int GattClient::GetInstanceId() const { return client_id_; }
+
+// GattClientFactory implementation
+// ========================================================
+
+GattClientFactory::GattClientFactory() {
+ hal::BluetoothGattInterface::Get()->AddClientObserver(this);
+}
+
+GattClientFactory::~GattClientFactory() {
+ hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+}
+
+bool GattClientFactory::RegisterInstance(const UUID& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ if (pending_calls_.find(uuid) != pending_calls_.end()) {
+ LOG(ERROR) << "GATT client with given UUID already registered - "
+ << "UUID: " << uuid.ToString();
+ return false;
+ }
+
+ const btgatt_client_interface_t* hal_iface =
+ hal::BluetoothGattInterface::Get()->GetClientHALInterface();
+ bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+ if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS) return false;
+
+ pending_calls_[uuid] = callback;
+
+ return true;
+}
+
+void GattClientFactory::RegisterClientCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int status, int client_id,
+ const bt_uuid_t& app_uuid) {
+ UUID uuid(app_uuid);
+
+ auto iter = pending_calls_.find(uuid);
+ if (iter == pending_calls_.end()) {
+ VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+ return;
+ }
+
+ bool success = (status == BT_STATUS_SUCCESS);
+ BLEStatus result = success ? BLE_STATUS_SUCCESS : BLE_STATUS_FAILURE;
+
+ // No need to construct a client if the call wasn't successful.
+ std::unique_ptr<GattClient> client;
+ if (success) client.reset(new GattClient(uuid, client_id));
+
+ // Notify the result via the result callback.
+ iter->second(result, uuid, std::move(client));
+
+ pending_calls_.erase(iter);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/gatt_client.h b/mtkbt/code/bt/service/gatt_client.h
new file mode 100755
index 0000000..fd83ffe
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_client.h
@@ -0,0 +1,83 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+// A GattClient instance represents an application's handle to perform GATT
+// client-role operations. Instances cannot be created directly and should be
+// obtained through the factory.
+class GattClient : public BluetoothInstance {
+ public:
+ ~GattClient() override;
+
+ // BluetoothClientInstace overrides:
+ const UUID& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ private:
+ friend class GattClientFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ GattClient(const UUID& uuid, int client_id);
+
+ // See getters above for documentation.
+ UUID app_identifier_;
+ int client_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(GattClient);
+};
+
+// GattClientFactory is used to register and obtain a per-application GattClient
+// instance. Users should call RegisterClient to obtain their own unique
+// GattClient instance that has been registered with the Bluetooth stack.
+class GattClientFactory : public BluetoothInstanceFactory,
+ private hal::BluetoothGattInterface::ClientObserver {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ GattClientFactory();
+ ~GattClientFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const UUID& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ // hal::BluetoothGattInterface::ClientObserver override:
+ void RegisterClientCallback(hal::BluetoothGattInterface* gatt_iface,
+ int status, int client_id,
+ const bt_uuid_t& app_uuid) override;
+
+ // Map of pending calls to register.
+ std::mutex pending_calls_lock_;
+ std::unordered_map<UUID, RegisterCallback> pending_calls_;
+
+ DISALLOW_COPY_AND_ASSIGN(GattClientFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/gatt_server.cc b/mtkbt/code/bt/service/gatt_server.cc
new file mode 100755
index 0000000..e4a6ec5
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_server.cc
@@ -0,0 +1,635 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/gatt_server.h"
+
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+bool operator==(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) {
+ return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
+}
+
+bool operator!=(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace
+
+// GattServer implementation
+// ========================================================
+
+GattServer::GattServer(const UUID& uuid, int server_id)
+ : app_identifier_(uuid), server_id_(server_id), delegate_(nullptr) {}
+
+GattServer::~GattServer() {
+ // Automatically unregister the server.
+ VLOG(1) << "GattServer unregistering: " << server_id_;
+
+ // Unregister as observer so we no longer receive any callbacks.
+ hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
+
+ // Unregister this server, stop all services, and ignore the result.
+ // TODO(armansito): stop and remove all services here? unregister_server
+ // should really take care of that.
+ hal::BluetoothGattInterface::Get()
+ ->GetServerHALInterface()
+ ->unregister_server(server_id_);
+}
+
+void GattServer::SetDelegate(Delegate* delegate) {
+ lock_guard<mutex> lock(mutex_);
+ delegate_ = delegate;
+}
+
+const UUID& GattServer::GetAppIdentifier() const { return app_identifier_; }
+
+int GattServer::GetInstanceId() const { return server_id_; }
+
+bool GattServer::AddService(const bluetooth::Service& service,
+ const ResultCallback& callback) {
+ VLOG(1) << __func__ << " server_id: " << server_id_;
+ lock_guard<mutex> lock(mutex_);
+
+ if (!callback) {
+ LOG(ERROR) << "|callback| cannot be NULL";
+ return false;
+ }
+
+ std::vector<btgatt_db_element_t> svc;
+
+ svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
+ : BTGATT_DB_SECONDARY_SERVICE),
+ .uuid = service.uuid().GetBlueDroid()});
+
+ for (const auto& characteristic : service.characteristics()) {
+ svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = characteristic.uuid().GetBlueDroid(),
+ .properties = characteristic.properties(),
+ .permissions = characteristic.permissions()});
+ for (const auto& descriptor : characteristic.descriptors())
+ svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
+ .uuid = descriptor.uuid().GetBlueDroid(),
+ .permissions = descriptor.permissions()});
+ }
+
+ for (const auto& incl_svc : service.included_services())
+ svc.push_back({.type = BTGATT_DB_INCLUDED_SERVICE,
+ .attribute_handle = incl_svc.handle()});
+
+ pending_end_decl_cb_ = callback;
+
+ bt_status_t status =
+ hal::BluetoothGattInterface::Get()->GetServerHALInterface()->add_service(
+ server_id_, svc);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initiate call to populate GATT service";
+ CleanUpPendingData();
+ return false;
+ }
+
+ return true;
+}
+
+bool GattServer::SendResponse(const std::string& device_address, int request_id,
+ GATTError error, int offset,
+ const std::vector<uint8_t>& value) {
+ VLOG(1) << __func__ << " - server_id: " << server_id_
+ << " device_address: " << device_address
+ << " request_id: " << request_id << " error: " << error
+ << " offset: " << offset;
+ lock_guard<mutex> lock(mutex_);
+
+ bt_bdaddr_t addr;
+ if (!util::BdAddrFromString(device_address, &addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ if (value.size() + offset > BTGATT_MAX_ATTR_LEN) {
+ LOG(ERROR) << "Value is too large";
+ return false;
+ }
+
+ // Find the correct connection ID for |device_address| and |request_id|.
+ auto iter = conn_addr_map_.find(device_address);
+ if (iter == conn_addr_map_.end()) {
+ LOG(ERROR) << "No known connections for device address: " << device_address;
+ return false;
+ }
+
+ std::shared_ptr<Connection> connection;
+ for (const auto& tmp : iter->second) {
+ if (tmp->request_id_to_handle.find(request_id) ==
+ tmp->request_id_to_handle.end())
+ continue;
+
+ connection = tmp;
+ }
+
+ if (!connection) {
+ LOG(ERROR) << "Pending request with ID " << request_id
+ << " not found for device with BD_ADDR: " << device_address;
+ return false;
+ }
+
+ btgatt_response_t response;
+ memset(&response, 0, sizeof(response));
+
+ // We keep -1 as the handle for "Execute Write Request". In that case,
+ // there is no need to populate the response data. Just send zeros back.
+ int handle = connection->request_id_to_handle[request_id];
+ response.handle = handle;
+ response.attr_value.handle = handle;
+ if (handle != -1) {
+ memcpy(response.attr_value.value, value.data(), value.size());
+ response.attr_value.offset = offset;
+ response.attr_value.len = value.size();
+ }
+
+ bt_status_t result =
+ hal::BluetoothGattInterface::Get()
+ ->GetServerHALInterface()
+ ->send_response(connection->conn_id, request_id, error, &response);
+ if (result != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initiate call to send GATT response";
+ return false;
+ }
+
+ connection->request_id_to_handle.erase(request_id);
+
+ return true;
+}
+
+bool GattServer::SendNotification(const std::string& device_address,
+ const uint16_t handle, bool confirm,
+ const std::vector<uint8_t>& value,
+ const GattCallback& callback) {
+ VLOG(1) << " - server_id: " << server_id_
+ << " device_address: " << device_address << " confirm: " << confirm;
+ lock_guard<mutex> lock(mutex_);
+
+ bt_bdaddr_t addr;
+ if (!util::BdAddrFromString(device_address, &addr)) {
+ LOG(ERROR) << "Invalid device address given: " << device_address;
+ return false;
+ }
+
+ // Get the connection IDs for which we will send this notification.
+ auto conn_iter = conn_addr_map_.find(device_address);
+ if (conn_iter == conn_addr_map_.end()) {
+ LOG(ERROR) << "No known connections for device with address: "
+ << device_address;
+ return false;
+ }
+
+ std::shared_ptr<PendingIndication> pending_ind(
+ new PendingIndication(callback));
+
+ // Send the notification/indication on all matching connections.
+ int send_count = 0;
+ for (const auto& conn : conn_iter->second) {
+ // Make sure that one isn't already pending for this connection.
+ if (pending_indications_.find(conn->conn_id) !=
+ pending_indications_.end()) {
+ VLOG(1) << "A" << (confirm ? "n indication" : " notification")
+ << " is already pending for connection: " << conn->conn_id;
+ continue;
+ }
+
+ // The HAL API takes char* rather const char* for |value|, so we have to
+ // cast away the const.
+ // TODO(armansito): Make HAL accept const char*.
+ bt_status_t status = hal::BluetoothGattInterface::Get()
+ ->GetServerHALInterface()
+ ->send_indication(server_id_, handle,
+ conn->conn_id, confirm, value);
+
+ // Increment the send count if this was successful. We don't immediately
+ // fail if the HAL returned an error. It's better to report success as long
+ // as we sent out at least one notification to this device as
+ // multi-transport GATT connections from the same BD_ADDR will be rare
+ // enough already.
+ if (status != BT_STATUS_SUCCESS) continue;
+
+ send_count++;
+ pending_indications_[conn->conn_id] = pending_ind;
+ }
+
+ if (send_count == 0) {
+ LOG(ERROR) << "Failed to send notifications/indications to device: "
+ << device_address;
+ return false;
+ }
+
+ return true;
+}
+
+void GattServer::ConnectionCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int server_id,
+ int connected, const bt_bdaddr_t& bda) {
+ lock_guard<mutex> lock(mutex_);
+
+ if (server_id != server_id_) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " conn_id: " << conn_id << " connected: " << connected
+ << " BD_ADDR: " << device_address;
+
+ if (!connected) {
+ // Erase the entry if we were connected to it.
+ VLOG(1) << "No longer connected: " << device_address;
+ conn_id_map_.erase(conn_id);
+ auto iter = conn_addr_map_.find(device_address);
+ if (iter == conn_addr_map_.end()) return;
+
+ // Remove the appropriate connection objects in the address.
+ for (auto conn_iter = iter->second.begin(); conn_iter != iter->second.end();
+ ++conn_iter) {
+ if ((*conn_iter)->conn_id != conn_id) continue;
+
+ iter->second.erase(conn_iter);
+ break;
+ }
+
+ if (delegate_)
+ delegate_->OnConnectionStateChanged(this, device_address, false);
+
+ return;
+ }
+
+ if (conn_id_map_.find(conn_id) != conn_id_map_.end()) {
+ LOG(WARNING) << "Connection entry already exists; "
+ << "ignoring ConnectionCallback";
+ return;
+ }
+
+ LOG(INFO) << "Added connection entry for conn_id: " << conn_id
+ << " device address: " << device_address;
+ std::shared_ptr<Connection> connection(new Connection(conn_id, bda));
+ conn_id_map_[conn_id] = connection;
+ conn_addr_map_[device_address].push_back(connection);
+
+ if (delegate_)
+ delegate_->OnConnectionStateChanged(this, device_address, true);
+}
+
+void GattServer::ServiceAddedCallback(hal::BluetoothGattInterface* gatt_iface,
+ int status, int server_id,
+ std::vector<btgatt_db_element_t> svc) {
+ lock_guard<mutex> lock(mutex_);
+
+ if (server_id != server_id_) return;
+
+ VLOG(1) << __func__ << " - status: " << status << " server_id: " << server_id
+ << " first handle: " << svc[0].attribute_handle
+ << " service UUID: " << UUID(svc[0].uuid).ToString()
+ << " count: " << svc.size();
+
+ Service service(svc[0].attribute_handle, true, UUID(svc[0].uuid), {}, {});
+
+ for (size_t i = 1; i < svc.size(); i++) {
+ const btgatt_db_element_t& curr = svc[i];
+ VLOG(1) << " - processing item no: " << i
+ << " handle: " << curr.attribute_handle;
+ if (curr.type == BTGATT_DB_CHARACTERISTIC) {
+ service.characteristics().push_back({curr.attribute_handle,
+ UUID(curr.uuid),
+ curr.properties,
+ curr.permissions,
+ {}});
+ } else if (curr.type == BTGATT_DB_DESCRIPTOR) {
+ service.characteristics().back().descriptors().push_back(
+ {curr.attribute_handle, UUID(curr.uuid), curr.permissions});
+ } else if (svc[i].type == BTGATT_DB_INCLUDED_SERVICE) {
+ }
+ }
+
+ pending_end_decl_cb_((bluetooth::BLEStatus)status, service);
+
+ CleanUpPendingData();
+}
+
+void GattServer::ServiceStoppedCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* server_id */, int /* service_handle */) {
+ // TODO(armansito): Support stopping a service.
+}
+
+void GattServer::RequestReadCharacteristicCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attribute_handle, int offset, bool is_long) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address
+ << " attribute_handle: " << attribute_handle << " offset: " << offset
+ << " is_long: " << is_long;
+
+ conn->request_id_to_handle[trans_id] = attribute_handle;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnCharacteristicReadRequest(this, device_address, trans_id, offset,
+ is_long, attribute_handle);
+}
+void GattServer::RequestReadDescriptorCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attribute_handle, int offset, bool is_long) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address
+ << " attribute_handle: " << attribute_handle << " offset: " << offset
+ << " is_long: " << is_long;
+
+ conn->request_id_to_handle[trans_id] = attribute_handle;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnDescriptorReadRequest(this, device_address, trans_id, offset,
+ is_long, attribute_handle);
+}
+
+void GattServer::RequestWriteCharacteristicCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool need_rsp,
+ bool is_prep, std::vector<uint8_t> value) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address << " attr_handle: " << attr_handle
+ << " offset: " << offset << " length: " << value.size()
+ << " need_rsp: " << need_rsp << " is_prep: " << is_prep;
+
+ // Store the request ID only if this is not a write-without-response. If
+ // another request occurs after this with the same request ID, then we'll
+ // simply process it normally, though that shouldn't ever happen.
+ if (need_rsp) conn->request_id_to_handle[trans_id] = attr_handle;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnCharacteristicWriteRequest(this, device_address, trans_id,
+ offset, is_prep, need_rsp,
+ std::move(value), attr_handle);
+}
+
+void GattServer::RequestWriteDescriptorCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool need_rsp,
+ bool is_prep, std::vector<uint8_t> value) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address << " attr_handle: " << attr_handle
+ << " offset: " << offset << " length: " << value.size()
+ << " need_rsp: " << need_rsp << " is_prep: " << is_prep;
+
+ // Store the request ID only if this is not a write-without-response. If
+ // another request occurs after this with the same request ID, then we'll
+ // simply process it normally, though that shouldn't ever happen.
+ if (need_rsp) conn->request_id_to_handle[trans_id] = attr_handle;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnDescriptorWriteRequest(this, device_address, trans_id, offset,
+ is_prep, need_rsp, std::move(value),
+ attr_handle);
+}
+
+void GattServer::RequestExecWriteCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write) {
+ lock_guard<mutex> lock(mutex_);
+
+ // Check to see if we know about this connection. Otherwise ignore the
+ // request.
+ auto conn = GetConnection(conn_id, bda, trans_id);
+ if (!conn) return;
+
+ std::string device_address = BtAddrString(&bda);
+
+ VLOG(1) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " BD_ADDR: " << device_address << " exec_write: " << exec_write;
+
+ // Just store a dummy invalid handle as this request doesn't apply to a
+ // specific handle.
+ conn->request_id_to_handle[trans_id] = -1;
+
+ // If there is no delegate then there is nobody to handle request. The request
+ // will eventually timeout and we should get a connection update that
+ // terminates the connection.
+ if (!delegate_) {
+ // TODO(armansito): Require a delegate at server registration so that this
+ // is never possible.
+ LOG(WARNING) << "No delegate was assigned to GattServer. Incoming request "
+ << "will time out.";
+ return;
+ }
+
+ delegate_->OnExecuteWriteRequest(this, device_address, trans_id, exec_write);
+}
+
+void GattServer::IndicationSentCallback(
+ hal::BluetoothGattInterface* /* gatt_iface */, int conn_id, int status) {
+ VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status;
+ lock_guard<mutex> lock(mutex_);
+
+ const auto& pending_ind_iter = pending_indications_.find(conn_id);
+ if (pending_ind_iter == pending_indications_.end()) {
+ VLOG(1) << "Unknown connection: " << conn_id;
+ return;
+ }
+
+ std::shared_ptr<PendingIndication> pending_ind = pending_ind_iter->second;
+ pending_indications_.erase(pending_ind_iter);
+
+ if (status == BT_STATUS_SUCCESS) pending_ind->has_success = true;
+
+ // Invoke it if this was the last reference to the confirmation callback.
+ if (pending_ind.unique() && pending_ind->callback) {
+ pending_ind->callback(pending_ind->has_success
+ ? GATT_ERROR_NONE
+ : static_cast<GATTError>(status));
+ }
+}
+
+void GattServer::CleanUpPendingData() {
+ pending_end_decl_cb_ = ResultCallback();
+}
+
+std::shared_ptr<GattServer::Connection> GattServer::GetConnection(
+ int conn_id, const bt_bdaddr_t& bda, int request_id) {
+ auto iter = conn_id_map_.find(conn_id);
+ if (iter == conn_id_map_.end()) {
+ VLOG(1) << "Connection doesn't belong to this server";
+ return nullptr;
+ }
+
+ auto conn = iter->second;
+ if (conn->bdaddr != bda) {
+ LOG(WARNING) << "BD_ADDR: " << BtAddrString(&bda) << " doesn't match "
+ << "connection ID: " << conn_id;
+ return nullptr;
+ }
+
+ if (conn->request_id_to_handle.find(request_id) !=
+ conn->request_id_to_handle.end()) {
+ VLOG(1) << "Request with ID: " << request_id << " already exists for "
+ << " connection: " << conn_id;
+ return nullptr;
+ }
+
+ return conn;
+}
+
+// GattServerFactory implementation
+// ========================================================
+
+GattServerFactory::GattServerFactory() {
+ hal::BluetoothGattInterface::Get()->AddServerObserver(this);
+}
+
+GattServerFactory::~GattServerFactory() {
+ hal::BluetoothGattInterface::Get()->RemoveServerObserver(this);
+}
+
+bool GattServerFactory::RegisterInstance(const UUID& uuid,
+ const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ if (pending_calls_.find(uuid) != pending_calls_.end()) {
+ LOG(ERROR) << "GATT-server client with given UUID already being registered "
+ << " - UUID: " << uuid.ToString();
+ return false;
+ }
+
+ const btgatt_server_interface_t* hal_iface =
+ hal::BluetoothGattInterface::Get()->GetServerHALInterface();
+ bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+ if (hal_iface->register_server(&app_uuid) != BT_STATUS_SUCCESS) return false;
+
+ pending_calls_[uuid] = callback;
+
+ return true;
+}
+
+void GattServerFactory::RegisterServerCallback(
+ hal::BluetoothGattInterface* gatt_iface, int status, int server_id,
+ const bt_uuid_t& app_uuid) {
+ UUID uuid(app_uuid);
+
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ auto iter = pending_calls_.find(uuid);
+ if (iter == pending_calls_.end()) {
+ VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+ return;
+ }
+
+ // No need to construct a server if the call wasn't successful.
+ std::unique_ptr<GattServer> server;
+ BLEStatus result = BLE_STATUS_FAILURE;
+ if (status == BT_STATUS_SUCCESS) {
+ server.reset(new GattServer(uuid, server_id));
+
+ gatt_iface->AddServerObserver(server.get());
+
+ result = BLE_STATUS_SUCCESS;
+ }
+
+ // Notify the result via the result callback.
+ iter->second(result, uuid, std::move(server));
+
+ pending_calls_.erase(iter);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/gatt_server.h b/mtkbt/code/bt/service/gatt_server.h
new file mode 100755
index 0000000..84ee165
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_server.h
@@ -0,0 +1,296 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <deque>
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/service.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+// A GattServer instance represents an application's handle to perform GATT
+// server-role operations. Instances cannot be created directly and should be
+// obtained through the factory.
+class GattServer : public BluetoothInstance,
+ private hal::BluetoothGattInterface::ServerObserver {
+ public:
+ // Delegate interface is used to handle incoming requests and confirmations
+ // for a GATT service.
+ class Delegate {
+ public:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ // Called when there is an incoming read request for the characteristic with
+ // ID |characteristic_id| from a remote device with address
+ // |device_address|. |request_id| can be used to respond to this request by
+ // calling SendResponse below.
+ virtual void OnCharacteristicReadRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_long, uint16_t handle) = 0;
+
+ // Called when there is an incoming read request for the descriptor with
+ // ID |descriptor_id| from a remote device with address |device_address|.
+ // |request_id| can be used to respond to this request by
+ // calling SendResponse below.
+ virtual void OnDescriptorReadRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_long, uint16_t handle) = 0;
+
+ // Called when there is an incoming write request for the characteristic
+ // with ID |characteristic_id| from a remote device with address
+ // |device_address|. |request_id| can be used to respond to this request by
+ // calling SendResponse, if the |need_response| parameter is true. Otherwise
+ // this is a "Write Without Reponse" procedure and SendResponse will fail.
+ // If |is_prepare_write| is true, then the write should not be committed
+ // immediately as this is a "Prepared Write Request". Instead, the Delegate
+ // should hold on to the value and either discard it or complete the write
+ // when it receives the OnExecuteWriteRequest event.
+ virtual void OnCharacteristicWriteRequest(
+ GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, uint16_t handle) = 0;
+
+ // Called when there is an incoming write request for the descriptor
+ // with ID |descriptor_id| from a remote device with address
+ // |device_address|. |request_id| can be used to respond to this request by
+ // calling SendResponse, if the |need_response| parameter is true. Otherwise
+ // this is a "Write Without Response" procedure and SendResponse will fail.
+ // If |is_prepare_write| is true, then the write should not be committed
+ // immediately as this is a "Prepared Write Request". Instead, the Delegate
+ // should hold on to the value and either discard it or complete the write
+ // when it receives the OnExecuteWriteRequest event.
+ virtual void OnDescriptorWriteRequest(
+ GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, uint16_t handle) = 0;
+
+ // Called when there is an incoming "Execute Write Request". If |is_execute|
+ // is true, then the Delegate should commit all previously prepared writes.
+ // Otherwise, all prepared writes should be aborted. The Delegate should
+ // call "SendResponse" to complete the procedure.
+ virtual void OnExecuteWriteRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, bool is_execute) = 0;
+
+ virtual void OnConnectionStateChanged(GattServer* gatt_server,
+ const std::string& device_addres,
+ bool connected) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ // The desctructor automatically unregisters this instance from the stack.
+ ~GattServer() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // GattServer instance.
+ void SetDelegate(Delegate* delegate);
+
+ // BluetoothClientInstace overrides:
+ const UUID& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ // Callback type used to report the status of an asynchronous GATT server
+ // operation.
+ using ResultCallback =
+ std::function<void(BLEStatus status, const Service& id)>;
+ using GattCallback = std::function<void(GATTError error)>;
+
+ // Add service declaration. This method immediately
+ // returns false if a service hasn't been started. Otherwise, |callback| will
+ // be called asynchronously with the result of the operation.
+ //
+ // TODO(armansito): It is unclear to me what it means for this function to
+ // fail. What is the state that we're in? Is the service declaration over so
+ // we can add other services to this server instance? Do we need to clean up
+ // all the entries or does the upper-layer need to remove the service? Or are
+ // we in a stuck-state where the service declaration hasn't ended?
+ bool AddService(const bluetooth::Service&, const ResultCallback& callback);
+
+ // Sends a response for a pending notification. |request_id| and
+ // |device_address| should match those that were received through one of the
+ // Delegate callbacks. |value| and |offset| are used for read requests and
+ // prepare write requests and should match the value of the attribute. Returns
+ // false if the pending request could not be resolved using the given
+ // parameters or if the call to the underlying stack fails.
+ bool SendResponse(const std::string& device_address, int request_id,
+ GATTError error, int offset,
+ const std::vector<uint8_t>& value);
+
+ // Sends an ATT Handle-Value Notification to the device with BD_ADDR
+ // |device_address| for the characteristic with handle |handle| and
+ // value |value|. If |confirm| is true, then an ATT Handle-Value Indication
+ // will be sent instead, which requires the remote to confirm receipt. Returns
+ // false if there was an immediate error in initiating the notification
+ // procedure. Otherwise, returns true and reports the asynchronous result of
+ // the operation in |callback|.
+ //
+ // If |confirm| is true, then |callback| will be run when the remote device
+ // sends a ATT Handle-Value Confirmation packet. Otherwise, it will be run as
+ // soon as the notification has been sent out.
+ bool SendNotification(const std::string& device_address,
+ const uint16_t handle, bool confirm,
+ const std::vector<uint8_t>& value,
+ const GattCallback& callback);
+
+ private:
+ friend class GattServerFactory;
+
+ // Used for the internal remote connection tracking. Keeps track of the
+ // request ID and the device address for the connection. If |request_id| is -1
+ // then no ATT read/write request is currently pending.
+ struct Connection {
+ Connection(int conn_id, const bt_bdaddr_t& bdaddr)
+ : conn_id(conn_id), bdaddr(bdaddr) {}
+ Connection() : conn_id(-1) { memset(&bdaddr, 0, sizeof(bdaddr)); }
+
+ int conn_id;
+ std::unordered_map<int, int> request_id_to_handle;
+ bt_bdaddr_t bdaddr;
+ };
+
+ // Used to keep track of a pending Handle-Value indication.
+ struct PendingIndication {
+ explicit PendingIndication(const GattCallback& callback)
+ : has_success(false), callback(callback) {}
+
+ bool has_success;
+ GattCallback callback;
+ };
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ GattServer(const UUID& uuid, int server_id);
+
+ // hal::BluetoothGattInterface::ServerObserver overrides:
+ void ConnectionCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
+ int server_id, int connected,
+ const bt_bdaddr_t& bda) override;
+ void ServiceAddedCallback(hal::BluetoothGattInterface* gatt_iface, int status,
+ int server_if,
+ std::vector<btgatt_db_element_t>) override;
+ void ServiceStoppedCallback(hal::BluetoothGattInterface* gatt_iface,
+ int status, int server_id,
+ int service_handle) override;
+ void RequestReadCharacteristicCallback(
+ hal::BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attribute_handle, int offset,
+ bool is_long) override;
+ void RequestReadDescriptorCallback(hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attribute_handle, int offset,
+ bool is_long) override;
+ void RequestWriteCharacteristicCallback(
+ hal::BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool need_rsp,
+ bool is_prep, std::vector<uint8_t> value) override;
+ void RequestWriteDescriptorCallback(hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle,
+ int offset, bool need_rsp, bool is_prep,
+ std::vector<uint8_t> value) override;
+ void RequestExecWriteCallback(hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int exec_write) override;
+ void IndicationSentCallback(hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int status) override;
+
+ // Helper function that notifies and clears the pending callback.
+ void CleanUpPendingData();
+
+ // Handles the next attribute entry in the pending service declaration.
+ void HandleNextEntry(hal::BluetoothGattInterface* gatt_iface);
+
+ // Helper method that returns a pointer to an internal Connection instance
+ // that matches the given parameters.
+ std::shared_ptr<Connection> GetConnection(int conn_id, const bt_bdaddr_t& bda,
+ int request_id);
+
+ // See getters for documentation.
+ UUID app_identifier_;
+ int server_id_;
+
+ // Mutex that synchronizes access to the entries below.
+ std::mutex mutex_;
+ ResultCallback pending_end_decl_cb_;
+
+ // GATT connection mappings from stack-provided "conn_id" IDs and remote
+ // device addresses to Connection structures. The conn_id map is one-to-one
+ // while the conn_addr map is one to many, as a remote device may support
+ // multiple transports (BR/EDR & LE) and use the same device address for both.
+ std::unordered_map<int, std::shared_ptr<Connection>> conn_id_map_;
+ std::unordered_map<std::string, std::vector<std::shared_ptr<Connection>>>
+ conn_addr_map_;
+
+ // Connections for which a Handle-Value indication is pending. Since there can
+ // be multiple indications to the same device (in the case of a dual-mode
+ // device with simulatenous BR/EDR & LE GATT connections), we also keep track
+ // of whether there has been at least one successful confirmation.
+ std::unordered_map<int, std::shared_ptr<PendingIndication>>
+ pending_indications_;
+
+ // Raw handle to the Delegate, which must outlive this GattServer instance.
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(GattServer);
+};
+
+// GattServerFactory is used to register and obtain a per-application GattServer
+// instance. Users should call RegisterClient to obtain their own unique
+// GattServer instance that has been registered with the Bluetooth stack.
+class GattServerFactory : public BluetoothInstanceFactory,
+ private hal::BluetoothGattInterface::ServerObserver {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ GattServerFactory();
+ ~GattServerFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const UUID& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ // hal::BluetoothGattInterface::ServerObserver override:
+ void RegisterServerCallback(hal::BluetoothGattInterface* gatt_iface,
+ int status, int server_id,
+ const bt_uuid_t& app_uuid) override;
+
+ // Map of pending calls to register.
+ std::mutex pending_calls_lock_;
+ std::unordered_map<UUID, RegisterCallback> pending_calls_;
+
+ DISALLOW_COPY_AND_ASSIGN(GattServerFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/gatt_server_old.cc b/mtkbt/code/bt/service/gatt_server_old.cc
new file mode 100755
index 0000000..d32ac8f
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_server_old.cc
@@ -0,0 +1,729 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "bt_gatts"
+
+#include "gatt_server_old.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <algorithm>
+#include <array>
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+namespace {
+
+const size_t kMaxGattAttributeSize = 512;
+std::vector<btgatt_db_element_t> pending_svc_decl;
+std::unordered_set<int> blob_index;
+
+// TODO(icoolidge): Support multiple instances
+// TODO(armansito): Remove this variable. No point of having this if
+// each bluetooth::gatt::Server instance already keeps a pointer to the
+// ServerInternals that is associated with it (which is much cleaner). It looks
+// like this variable exists because the btif callbacks don't allow the
+// upper-layer to pass user data to them. We could:
+//
+// 1. Fix the btif callbacks so that some sort of continuation can be
+// attached to a callback. This might be a long shot since the callback
+// interface doesn't allow more than one caller to register its own callbacks
+// (which might be what we want though, since this would make the API more
+// flexible).
+//
+// 2. Allow creation of Server objects using a factory method that returns
+// the result asynchronously in a base::Callback. The RegisterServerCallback
+// provides an |app_uuid|, which can be used to store callback structures in
+// a map and lazily instantiate the Server and invoke the correct callback.
+// This is a general pattern that we should use throughout the daemon, since
+// all operations can timeout or fail and this is best reported in an
+// asynchronous base::Callback.
+//
+static bluetooth::gatt::ServerInternals* g_internal = nullptr;
+
+enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
+
+} // namespace
+
+void DoNothing(uint8_t p) {}
+
+namespace bluetooth {
+namespace gatt {
+
+struct Characteristic {
+ UUID uuid;
+ int blob_section;
+ std::vector<uint8_t> blob;
+
+ // Support synchronized blob updates by latching under mutex.
+ std::vector<uint8_t> next_blob;
+ bool next_blob_pending;
+ bool notify;
+};
+
+struct ServerInternals {
+ ServerInternals();
+ ~ServerInternals();
+ int Initialize();
+ bt_status_t AddCharacteristic(const UUID& uuid, uint8_t properties,
+ uint16_t permissions);
+
+ // This maps API attribute UUIDs to BlueDroid handles.
+ std::map<UUID, int> uuid_to_attribute;
+
+ // The attribute cache, indexed by BlueDroid handles.
+ std::unordered_map<int, Characteristic> characteristics;
+
+ // Associate a control attribute with its value attribute.
+ std::unordered_map<int, int> controlled_blobs;
+
+ ScanResults scan_results;
+
+ UUID last_write;
+ const btgatt_interface_t* gatt;
+ int server_if;
+ int client_if;
+ int service_handle;
+ std::set<int> connections;
+
+ std::mutex lock;
+ std::condition_variable api_synchronize;
+ int pipefd[kPipeNumEnds];
+};
+
+} // namespace gatt
+} // namespace bluetooth
+
+namespace {
+
+/** Callback invoked in response to register_server */
+void RegisterServerCallback(int status, int server_if, bt_uuid_t* app_uuid) {
+ LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
+ server_if, app_uuid);
+
+ g_internal->server_if = server_if;
+ pending_svc_decl.push_back(
+ {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = *app_uuid});
+}
+
+void ServiceAddedCallback(int status, int server_if,
+ std::vector<btgatt_db_element_t> service) {
+ LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d",
+ __func__, status, server_if, service.size(),
+ service[0].attribute_handle);
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->server_if = server_if;
+
+ g_internal->service_handle = service[0].attribute_handle;
+
+ uint16_t prev_char_handle = 0;
+ uint16_t prev_char_properties = 0;
+ for (size_t i = 1; i < service.size(); i++) {
+ const btgatt_db_element_t& el = service[i];
+ if (el.type == BTGATT_DB_DESCRIPTOR) {
+ LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle);
+ } else if (el.type == BTGATT_DB_CHARACTERISTIC) {
+ bluetooth::UUID id(el.uuid);
+ uint16_t char_handle = el.attribute_handle;
+
+ LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle);
+
+ g_internal->uuid_to_attribute[id] = char_handle;
+ g_internal->characteristics[char_handle].uuid = id;
+ g_internal->characteristics[char_handle].blob_section = 0;
+
+ // If the added characteristic is blob
+ if (blob_index.find(i) != blob_index.end()) {
+ // Finally, associate the control attribute with the value attribute.
+ // Also, initialize the control attribute to a readable zero.
+ const uint16_t control_attribute = char_handle;
+ const uint16_t blob_attribute = prev_char_handle;
+ g_internal->controlled_blobs[control_attribute] = blob_attribute;
+ g_internal->characteristics[blob_attribute].notify =
+ prev_char_properties & bluetooth::gatt::kPropertyNotify;
+
+ bluetooth::gatt::Characteristic& ctrl =
+ g_internal->characteristics[control_attribute];
+ ctrl.next_blob.clear();
+ ctrl.next_blob.push_back(0);
+ ctrl.next_blob_pending = true;
+ ctrl.blob_section = 0;
+ ctrl.notify = false;
+ }
+ prev_char_handle = char_handle;
+ prev_char_properties = el.properties;
+ }
+ }
+
+ pending_svc_decl.clear();
+ blob_index.clear();
+
+ // The UUID provided here is unimportant, and is only used to satisfy
+ // BlueDroid.
+ // It must be different than any other registered UUID.
+ bt_uuid_t client_id = service[0].uuid;
+ ++client_id.uu[15];
+
+ bt_status_t btstat = g_internal->gatt->client->register_client(&client_id);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
+ }
+}
+
+void RequestReadCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+ int attr_handle, int attribute_offset_octets,
+ bool is_long) {
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+
+ bluetooth::gatt::Characteristic& ch =
+ g_internal->characteristics[attr_handle];
+
+ // Latch next_blob to blob on a 'fresh' read.
+ if (ch.next_blob_pending && attribute_offset_octets == 0 &&
+ ch.blob_section == 0) {
+ std::swap(ch.blob, ch.next_blob);
+ ch.next_blob_pending = false;
+ }
+
+ const size_t blob_offset_octets =
+ std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
+ const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
+ const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
+
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG,
+ "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
+ "blob_section:%u (is_long:%u)",
+ __func__, conn_id, addr.c_str(), attr_handle,
+ attribute_offset_octets, ch.blob_section, is_long);
+
+ btgatt_response_t response;
+ response.attr_value.len = 0;
+
+ if (attribute_offset_octets < static_cast<int>(attribute_size)) {
+ std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
+ ch.blob.begin() + blob_offset_octets + attribute_size,
+ response.attr_value.value);
+ response.attr_value.len = attribute_size - attribute_offset_octets;
+ }
+
+ response.attr_value.handle = attr_handle;
+ response.attr_value.offset = attribute_offset_octets;
+ response.attr_value.auth_req = 0;
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestWriteCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+ int attr_handle, int attribute_offset, bool need_rsp,
+ bool is_prep, std::vector<uint8_t> value) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG,
+ "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
+ "length:%zu "
+ "need_resp:%u is_prep:%u",
+ __func__, conn_id, addr.c_str(), trans_id, attr_handle,
+ attribute_offset, value.size(), need_rsp, is_prep);
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+
+ bluetooth::gatt::Characteristic& ch =
+ g_internal->characteristics[attr_handle];
+
+ ch.blob.resize(attribute_offset + value.size());
+
+ std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset);
+
+ auto target_blob = g_internal->controlled_blobs.find(attr_handle);
+ // If this is a control attribute, adjust offset of the target blob.
+ if (target_blob != g_internal->controlled_blobs.end() &&
+ ch.blob.size() == 1u) {
+ g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
+ LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
+ target_blob->second, ch.blob[0]);
+ } else if (!is_prep) {
+ // This is a single frame characteristic write.
+ // Notify upwards because we're done now.
+ const bluetooth::UUID::UUID128Bit& attr_uuid = ch.uuid.GetFullBigEndian();
+ ssize_t status;
+ OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd],
+ attr_uuid.data(), attr_uuid.size()));
+ if (-1 == status)
+ LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
+ } else {
+ // This is a multi-frame characteristic write.
+ // Wait for an 'RequestExecWriteCallback' to notify completion.
+ g_internal->last_write = ch.uuid;
+ }
+
+ // Respond only if needed.
+ if (!need_rsp) return;
+
+ btgatt_response_t response;
+ response.attr_value.handle = attr_handle;
+ response.attr_value.offset = attribute_offset;
+ response.attr_value.len = value.size();
+ response.attr_value.auth_req = 0;
+ // Provide written data back to sender for the response.
+ // Remote stacks use this to validate the success of the write.
+ std::copy(value.begin(), value.end(), response.attr_value.value);
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+ int exec_write) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
+ conn_id, addr.c_str(), trans_id, exec_write);
+
+ // This 'response' data is unused for ExecWriteResponses.
+ // It is only used to pass BlueDroid argument validation.
+ btgatt_response_t response = {};
+ g_internal->gatt->server->send_response(conn_id, trans_id, 0, &response);
+
+ if (!exec_write) return;
+
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ // Communicate the attribute UUID as notification of a write update.
+ const bluetooth::UUID::UUID128Bit uuid =
+ g_internal->last_write.GetFullBigEndian();
+ ssize_t status;
+ OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(),
+ uuid.size()));
+ if (-1 == status)
+ LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
+}
+
+void ConnectionCallback(int conn_id, int server_if, int connected,
+ bt_bdaddr_t* bda) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
+ __func__, conn_id, server_if, connected, addr.c_str());
+ if (connected == 1) {
+ g_internal->connections.insert(conn_id);
+ } else if (connected == 0) {
+ g_internal->connections.erase(conn_id);
+ }
+}
+
+void EnableAdvertisingCallback(uint8_t status) {
+ LOG_INFO(LOG_TAG, "%s: status:%d", __func__, status);
+ // This terminates a Start call.
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->api_synchronize.notify_one();
+}
+
+void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
+ LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
+ client_if, app_uuid->uu[0]);
+ g_internal->client_if = client_if;
+
+ // Setup our advertisement. This has no callback.
+ g_internal->gatt->advertiser->SetData(0 /* std_inst */, false,
+ {/*TODO: put inverval 2,2 here*/},
+ base::Bind(&DoNothing));
+
+ g_internal->gatt->advertiser->Enable(
+ 0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback),
+ 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::Bind(&DoNothing));
+}
+
+void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
+ LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
+ status, server_if, srvc_handle);
+ // This terminates a Stop call.
+ // TODO(icoolidge): make this symmetric with start
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->api_synchronize.notify_one();
+}
+
+void ScanResultCallback(uint16_t ble_evt_type, uint8_t addr_type,
+ bt_bdaddr_t* bda, uint8_t ble_primary_phy,
+ uint8_t ble_secondary_phy, uint8_t ble_advertising_sid,
+ int8_t ble_tx_power, int8_t rssi,
+ uint16_t ble_periodic_adv_int,
+ std::vector<uint8_t> adv_data) {
+ std::string addr(BtAddrString(bda));
+ std::lock_guard<std::mutex> lock(g_internal->lock);
+ g_internal->scan_results[addr] = rssi;
+}
+
+void ClientConnectCallback(int conn_id, int status, int client_if,
+ bt_bdaddr_t* bda) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
+ conn_id, status, client_if, addr.c_str());
+}
+
+void ClientDisconnectCallback(int conn_id, int status, int client_if,
+ bt_bdaddr_t* bda) {
+ std::string addr(BtAddrString(bda));
+ LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
+ conn_id, status, client_if, addr.c_str());
+}
+
+void IndicationSentCallback(UNUSED_ATTR int conn_id, UNUSED_ATTR int status) {
+ // TODO(icoolidge): what to do
+}
+
+void ResponseConfirmationCallback(UNUSED_ATTR int status,
+ UNUSED_ATTR int handle) {
+ // TODO(icoolidge): what to do
+}
+
+const btgatt_server_callbacks_t gatt_server_callbacks = {
+ RegisterServerCallback,
+ ConnectionCallback,
+ ServiceAddedCallback,
+ ServiceStoppedCallback,
+ nullptr, /* service_deleted_cb */
+ RequestReadCallback,
+ RequestReadCallback,
+ RequestWriteCallback,
+ RequestWriteCallback,
+ RequestExecWriteCallback,
+ ResponseConfirmationCallback,
+ IndicationSentCallback,
+ nullptr, /* congestion_cb*/
+ nullptr, /* mtu_changed_cb */
+ nullptr, /* phy_update_cb */
+ nullptr, /* conn_update_cb */
+};
+
+// TODO(eisenbach): Refactor GATT interface to not require servers
+// to refer to the client interface.
+const btgatt_client_callbacks_t gatt_client_callbacks = {
+ RegisterClientCallback,
+ ClientConnectCallback,
+ ClientDisconnectCallback,
+ nullptr, /* search_complete_cb; */
+ nullptr, /* register_for_notification_cb; */
+ nullptr, /* notify_cb; */
+ nullptr, /* read_characteristic_cb; */
+ nullptr, /* write_characteristic_cb; */
+ nullptr, /* read_descriptor_cb; */
+ nullptr, /* write_descriptor_cb; */
+ nullptr, /* execute_write_cb; */
+ nullptr, /* read_remote_rssi_cb; */
+ nullptr, /* configure_mtu_cb; */
+ nullptr, /* congestion_cb; */
+ nullptr, /* get_gatt_db_cb; */
+ nullptr, /* services_removed_cb */
+ nullptr, /* services_added_cb */
+ nullptr, /* phy_update_cb */
+ nullptr, /* conn_update_cb */
+};
+
+const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
+ ScanResultCallback,
+ nullptr, /* batchscan_reports_cb; */
+ nullptr, /* batchscan_threshold_cb; */
+ nullptr, /* track_adv_event_cb; */
+};
+
+const btgatt_callbacks_t gatt_callbacks = {
+ /** Set to sizeof(btgatt_callbacks_t) */
+ sizeof(btgatt_callbacks_t),
+
+ /** GATT Client callbacks */
+ &gatt_client_callbacks,
+
+ /** GATT Server callbacks */
+ &gatt_server_callbacks,
+
+ /** GATT Server callbacks */
+ &gatt_scanner_callbacks,
+};
+
+} // namespace
+
+namespace bluetooth {
+namespace gatt {
+
+int ServerInternals::Initialize() {
+ // Get the interface to the GATT profile.
+ const bt_interface_t* bt_iface =
+ hal::BluetoothInterface::Get()->GetHALInterface();
+ gatt = reinterpret_cast<const btgatt_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
+ if (!gatt) {
+ LOG_ERROR(LOG_TAG, "Error getting GATT interface");
+ return -1;
+ }
+
+ bt_status_t btstat = gatt->init(&gatt_callbacks);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
+ return -1;
+ }
+
+ int status = pipe(pipefd);
+ if (status == -1) {
+ LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+bt_status_t ServerInternals::AddCharacteristic(const UUID& uuid,
+ uint8_t properties,
+ uint16_t permissions) {
+ bt_uuid_t c_uuid = uuid.GetBlueDroid();
+
+ pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = c_uuid,
+ .properties = properties,
+ .permissions = permissions});
+ return BT_STATUS_SUCCESS;
+}
+
+ServerInternals::ServerInternals()
+ : gatt(nullptr),
+ server_if(0),
+ client_if(0),
+ service_handle(0),
+ pipefd{INVALID_FD, INVALID_FD} {}
+
+ServerInternals::~ServerInternals() {
+ if (pipefd[0] != INVALID_FD) close(pipefd[0]);
+ if (pipefd[1] != INVALID_FD) close(pipefd[1]);
+
+ gatt->server->delete_service(server_if, service_handle);
+ gatt->server->unregister_server(server_if);
+ gatt->client->unregister_client(client_if);
+}
+
+Server::Server() : internal_(nullptr) {}
+
+Server::~Server() {}
+
+bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
+ internal_.reset(new ServerInternals);
+ if (!internal_) {
+ LOG_ERROR(LOG_TAG, "Error creating internals");
+ return false;
+ }
+ g_internal = internal_.get();
+
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ int status = internal_->Initialize();
+ if (status) {
+ LOG_ERROR(LOG_TAG, "Error initializing internals");
+ return false;
+ }
+
+ bt_uuid_t uuid = service_id.GetBlueDroid();
+
+ bt_status_t btstat = internal_->gatt->server->register_server(&uuid);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to register server");
+ return false;
+ }
+
+ internal_->api_synchronize.wait(lock);
+ // TODO(icoolidge): Better error handling.
+ if (internal_->server_if == 0) {
+ LOG_ERROR(LOG_TAG, "Initialization of server failed");
+ return false;
+ }
+
+ *gatt_pipe = internal_->pipefd[kPipeReadEnd];
+ LOG_INFO(LOG_TAG, "Server Initialize succeeded");
+ return true;
+}
+
+bool Server::SetAdvertisement(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name) {
+ // std::vector<uint8_t> id_data;
+ // const auto& mutable_manufacturer_data = manufacturer_data;
+ // const auto& mutable_service_data = service_data;
+
+ // for (const UUID &id : ids) {
+ // const auto le_id = id.GetFullLittleEndian();
+ // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+ // }
+
+ std::lock_guard<std::mutex> lock(internal_->lock);
+
+ // Setup our advertisement. This has no callback.
+ internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */
+ {}, base::Bind(&DoNothing));
+ // transmit_name, /* name */
+ // 2, 2, interval
+ // mutable_manufacturer_data,
+ // mutable_service_data,
+ // id_data);
+ return true;
+}
+
+bool Server::SetScanResponse(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name) {
+ // std::vector<uint8_t> id_data;
+ // const auto& mutable_manufacturer_data = manufacturer_data;
+ // const auto& mutable_service_data = service_data;
+
+ // for (const UUID &id : ids) {
+ // const auto le_id = id.GetFullLittleEndian();
+ // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
+ // }
+
+ std::lock_guard<std::mutex> lock(internal_->lock);
+
+ // Setup our advertisement. This has no callback.
+ internal_->gatt->advertiser->SetData(0, true, /* scan response */
+ {}, base::Bind(&DoNothing));
+ // transmit_name, /* name */
+ // false, /* no txpower */
+ // 2, 2, interval
+ // 0, /* appearance */
+ // mutable_manufacturer_data,
+ // mutable_service_data,
+ // id_data);
+ return true;
+}
+
+bool Server::AddCharacteristic(const UUID& id, int properties,
+ int permissions) {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ bt_status_t btstat =
+ internal_->AddCharacteristic(id, properties, permissions);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
+ internal_->api_synchronize.wait(lock);
+ const int handle = internal_->uuid_to_attribute[id];
+ internal_->characteristics[handle].notify = properties & kPropertyNotify;
+ return true;
+}
+
+bool Server::AddBlob(const UUID& id, const UUID& control_id, int properties,
+ int permissions) {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+
+ // First, add the primary attribute (characteristic value)
+ bt_status_t btstat =
+ internal_->AddCharacteristic(id, properties, permissions);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to set scan response data");
+ return false;
+ }
+
+ // Next, add the secondary attribute (blob control).
+ // Control attributes have fixed permissions/properties.
+ // Remember position at which blob was added.
+ blob_index.insert(pending_svc_decl.size());
+ btstat =
+ internal_->AddCharacteristic(control_id, kPropertyRead | kPropertyWrite,
+ kPermissionRead | kPermissionWrite);
+
+ return true;
+}
+
+bool Server::Start() {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ bt_status_t btstat = internal_->gatt->server->add_service(
+ internal_->server_if, pending_svc_decl);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
+ internal_->api_synchronize.wait(lock);
+ return true;
+}
+
+bool Server::Stop() {
+ std::unique_lock<std::mutex> lock(internal_->lock);
+ bt_status_t btstat = internal_->gatt->server->stop_service(
+ internal_->server_if, internal_->service_handle);
+ if (btstat != BT_STATUS_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
+ internal_->service_handle);
+ return false;
+ }
+ internal_->api_synchronize.wait(lock);
+ return true;
+}
+
+bool Server::ScanEnable() {
+ internal_->gatt->scanner->Scan(true);
+ return true;
+}
+
+bool Server::ScanDisable() {
+ internal_->gatt->scanner->Scan(false);
+ return true;
+}
+
+bool Server::GetScanResults(ScanResults* results) {
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ *results = internal_->scan_results;
+ return true;
+}
+
+bool Server::SetCharacteristicValue(const UUID& id,
+ const std::vector<uint8_t>& value) {
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ const int attribute_id = internal_->uuid_to_attribute[id];
+ Characteristic& ch = internal_->characteristics[attribute_id];
+ ch.next_blob = value;
+ ch.next_blob_pending = true;
+
+ if (!ch.notify) return true;
+
+ for (auto connection : internal_->connections) {
+ internal_->gatt->server->send_indication(internal_->server_if, attribute_id,
+ connection, true, {0});
+ }
+ return true;
+}
+
+bool Server::GetCharacteristicValue(const UUID& id,
+ std::vector<uint8_t>* value) {
+ std::lock_guard<std::mutex> lock(internal_->lock);
+ const int attribute_id = internal_->uuid_to_attribute[id];
+ *value = internal_->characteristics[attribute_id].blob;
+ return true;
+}
+
+} // namespace gatt
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/gatt_server_old.h b/mtkbt/code/bt/service/gatt_server_old.h
new file mode 100755
index 0000000..a16bdfc
--- a/dev/null
+++ b/mtkbt/code/bt/service/gatt_server_old.h
@@ -0,0 +1,126 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#pragma once
+
+#include <array>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_gatt.h"
+#include "service/common/bluetooth/uuid.h"
+
+namespace bluetooth {
+namespace gatt {
+
+// Attribute permission values
+const int kPermissionRead = 0x1;
+const int kPermissionReadEncrypted = 0x2;
+const int kPermissionReadEncryptedMitm = 0x4;
+const int kPermissionWrite = 0x10;
+const int kPermissionWriteEnecrypted = 0x20;
+const int KPermissionWriteEncryptedMitm = 0x40;
+const int kPermissionWriteSigned = 0x80;
+const int kPermissionWriteSignedMitm = 0x100;
+
+// GATT characteristic properties bit-field values
+const int kPropertyBroadcast = 0x1;
+const int kPropertyRead = 0x2;
+const int kPropertyWriteNoResponse = 0x4;
+const int kPropertyWrite = 0x8;
+const int kPropertyNotify = 0x10;
+const int kPropertyIndicate = 0x20;
+const int kPropertySignedWrite = 0x40;
+const int kPropertyExtendedProps = 0x80;
+
+// A mapping from string bluetooth addresses to RSSI measurements.
+typedef std::unordered_map<std::string, int> ScanResults;
+
+// TODO(armansito): This should be a private internal class though I don't see
+// why we even need this class. Instead it should probably be merged into
+// Server.
+struct ServerInternals;
+
+// Server is threadsafe and internally locked.
+// Asynchronous IO is identified via a gatt_pipe FD,
+// and synchronously read with 'GetCharacteristicValue'
+//
+// ****DEPRECATED****
+//
+// TODO(armansito): This class has been deprecated and is being replaced by
+// bluetooth::GattServer. We will remove this entirely once the new code is
+// ready.
+class Server {
+ public:
+ Server();
+ ~Server();
+
+ // Register GATT interface, initialize internal state,
+ // and open a pipe for characteristic write notification.
+ bool Initialize(const UUID& service_id, int* gatt_pipe);
+
+ // Control the content of service advertisement.
+ bool SetAdvertisement(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name);
+
+ // Control the content of service scan response.
+ bool SetScanResponse(const std::vector<UUID>& ids,
+ const std::vector<uint8_t>& service_data,
+ const std::vector<uint8_t>& manufacturer_data,
+ bool transmit_name);
+
+ // Add an ordinary characteristic for reading and/or writing.
+ bool AddCharacteristic(const UUID& id, int properties, int permissions);
+
+ // Add a special 'blob' characteristic with a corresponding control
+ // attribute to manipulate which part of the blob the attribute represents.
+ bool AddBlob(const UUID& id, const UUID& control_id, int properties,
+ int permissions);
+
+ // Put a new value into a characeteristic.
+ // It will be read from a client starting at the next 0-offset read.
+ bool SetCharacteristicValue(const UUID& id,
+ const std::vector<uint8_t>& value);
+
+ // Get the current value of a characteristic.
+ bool GetCharacteristicValue(const UUID& id, std::vector<uint8_t>* value);
+
+ // Start this service. Activate advertisements, allow connections.
+ // Characteristics should all be created before this.
+ bool Start();
+
+ // Cease advertisements and disallow connections.
+ bool Stop();
+
+ // Enable LE scan. Scan results will be cached internally.
+ bool ScanEnable();
+
+ // Disable LE scan.
+ bool ScanDisable();
+
+ // Copy out the cached scan results.
+ bool GetScanResults(ScanResults* results);
+
+ private:
+ // Internal data.
+ std::unique_ptr<ServerInternals> internal_;
+};
+
+} // namespace gatt
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.cc b/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.cc
new file mode 100755
index 0000000..936a053
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.cc
@@ -0,0 +1,821 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/hal/bluetooth_gatt_interface.h"
+
+#include <mutex>
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+#include "service/logging_helpers.h"
+
+using std::lock_guard;
+using std::unique_lock;
+using std::shared_lock;
+using std::mutex;
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothGattInterface instance.
+BluetoothGattInterface* g_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+// TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_mutex_impl g_instance_lock;
+
+// Helper for obtaining the observer lists. This is forward declared here
+// and defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothGattInterface::ScannerObserver>*
+GetScannerObservers();
+base::ObserverList<BluetoothGattInterface::ClientObserver>*
+GetClientObservers();
+base::ObserverList<BluetoothGattInterface::ServerObserver>*
+GetServerObservers();
+
+#define FOR_EACH_SCANNER_OBSERVER(func) \
+ FOR_EACH_OBSERVER(BluetoothGattInterface::ScannerObserver, \
+ *GetScannerObservers(), func)
+
+#define FOR_EACH_CLIENT_OBSERVER(func) \
+ FOR_EACH_OBSERVER(BluetoothGattInterface::ClientObserver, \
+ *GetClientObservers(), func)
+
+#define FOR_EACH_SERVER_OBSERVER(func) \
+ FOR_EACH_OBSERVER(BluetoothGattInterface::ServerObserver, \
+ *GetServerObservers(), func)
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(app_uuid);
+
+ FOR_EACH_CLIENT_OBSERVER(
+ RegisterClientCallback(g_interface, status, client_if, *app_uuid));
+}
+
+void ScanResultCallback(
+ uint16_t ble_evt_type, uint8_t addr_type, bt_bdaddr_t* bda,
+ uint8_t ble_primary_phy, uint8_t ble_secondary_phy,
+ uint8_t ble_advertising_sid, int8_t ble_tx_power, int8_t rssi,
+ uint16_t ble_periodic_adv_int,
+ std::vector<uint8_t> adv_data) { // NOLINT(pass-by-value)
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ VLOG(2) << __func__ << " - BD_ADDR: " << BtAddrString(bda)
+ << " RSSI: " << rssi;
+ FOR_EACH_SCANNER_OBSERVER(
+ ScanResultCallback(g_interface, *bda, rssi, adv_data));
+}
+
+void ConnectCallback(int conn_id, int status, int client_if, bt_bdaddr_t* bda) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ VLOG(2) << __func__ << " - status: " << status << " client_if: " << client_if
+ << " - BD_ADDR: " << BtAddrString(bda) << " - conn_id: " << conn_id;
+
+ FOR_EACH_CLIENT_OBSERVER(
+ ConnectCallback(g_interface, conn_id, status, client_if, *bda));
+}
+
+void DisconnectCallback(int conn_id, int status, int client_if,
+ bt_bdaddr_t* bda) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " - status: " << status
+ << " client_if: " << client_if << " - BD_ADDR: " << BtAddrString(bda);
+ FOR_EACH_CLIENT_OBSERVER(
+ DisconnectCallback(g_interface, conn_id, status, client_if, *bda));
+}
+
+void SearchCompleteCallback(int conn_id, int status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " - status: " << status;
+ FOR_EACH_CLIENT_OBSERVER(
+ SearchCompleteCallback(g_interface, conn_id, status));
+}
+
+void RegisterForNotificationCallback(int conn_id, int registered, int status,
+ uint16_t handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ LOG(INFO) << __func__ << " - conn_id: " << conn_id << " - status: " << status
+ << " - registered: " << registered << " - handle: " << handle;
+ FOR_EACH_CLIENT_OBSERVER(RegisterForNotificationCallback(
+ g_interface, conn_id, status, registered, handle));
+}
+
+void NotifyCallback(int conn_id, btgatt_notify_params_t* p_data) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id
+ << " - address: " << BtAddrString(&p_data->bda)
+ << " - handle: " << p_data->handle << " - len: " << p_data->len
+ << " - is_notify: " << p_data->is_notify;
+
+ FOR_EACH_CLIENT_OBSERVER(NotifyCallback(g_interface, conn_id, p_data));
+}
+
+void WriteCharacteristicCallback(int conn_id, int status, uint16_t handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " - status: " << status;
+
+ FOR_EACH_CLIENT_OBSERVER(
+ WriteCharacteristicCallback(g_interface, conn_id, status, handle));
+}
+
+void WriteDescriptorCallback(int conn_id, int status, uint16_t handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " - status: " << status;
+
+ FOR_EACH_CLIENT_OBSERVER(
+ WriteDescriptorCallback(g_interface, conn_id, status, handle));
+}
+
+void MtuChangedCallback(int conn_id, int status, int mtu) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " status: " << status
+ << " mtu: " << mtu;
+
+ FOR_EACH_CLIENT_OBSERVER(
+ MtuChangedCallback(g_interface, conn_id, status, mtu));
+}
+
+void GetGattDbCallback(int conn_id, btgatt_db_element_t* db, int size) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " size: " << size;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_CLIENT_OBSERVER(GetGattDbCallback(g_interface, conn_id, db, size));
+}
+
+void ServicesRemovedCallback(int conn_id, uint16_t start_handle,
+ uint16_t end_handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id
+ << " start_handle: " << start_handle << " end_handle: " << end_handle;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_CLIENT_OBSERVER(
+ ServicesRemovedCallback(g_interface, conn_id, start_handle, end_handle));
+}
+
+void ServicesAddedCallback(int conn_id, btgatt_db_element_t* added,
+ int added_count) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id
+ << " added_count: " << added_count;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_CLIENT_OBSERVER(
+ ServicesAddedCallback(g_interface, conn_id, added, added_count));
+}
+
+void RegisterServerCallback(int status, int server_if, bt_uuid_t* app_uuid) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(app_uuid);
+
+ FOR_EACH_SERVER_OBSERVER(
+ RegisterServerCallback(g_interface, status, server_if, *app_uuid));
+}
+
+void ConnectionCallback(int conn_id, int server_if, int connected,
+ bt_bdaddr_t* bda) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id
+ << " server_if: " << server_if << " connected: " << connected;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(
+ ConnectionCallback(g_interface, conn_id, server_if, connected, *bda));
+}
+
+void ServiceAddedCallback(
+ int status, int server_if,
+ std::vector<btgatt_db_element_t> service) { // NOLINT(pass-by-value)
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+ << " count: " << service.size();
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(service.size());
+
+ FOR_EACH_SERVER_OBSERVER(
+ ServiceAddedCallback(g_interface, status, server_if, service));
+}
+
+void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+ << " handle: " << srvc_handle;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_SERVER_OBSERVER(
+ ServiceStoppedCallback(g_interface, status, server_if, srvc_handle));
+}
+
+void ServiceDeletedCallback(int status, int server_if, int srvc_handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " server_if: " << server_if
+ << " handle: " << srvc_handle;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_SERVER_OBSERVER(
+ ServiceDeletedCallback(g_interface, status, server_if, srvc_handle));
+}
+
+void RequestReadCharacteristicCallback(int conn_id, int trans_id,
+ bt_bdaddr_t* bda, int attr_handle,
+ int offset, bool is_long) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " is_long: " << is_long;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestReadCharacteristicCallback(
+ g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
+}
+
+void RequestReadDescriptorCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+ int attr_handle, int offset, bool is_long) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " is_long: " << is_long;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestReadDescriptorCallback(
+ g_interface, conn_id, trans_id, *bda, attr_handle, offset, is_long));
+}
+
+void RequestWriteCharacteristicCallback(int conn_id, int trans_id,
+ bt_bdaddr_t* bda, int attr_handle,
+ int offset, bool need_rsp, bool is_prep,
+ std::vector<uint8_t> value) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " length: " << value.size() << " need_rsp: " << need_rsp
+ << " is_prep: " << is_prep;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestWriteCharacteristicCallback(
+ g_interface, conn_id, trans_id, *bda, attr_handle, offset, need_rsp,
+ is_prep, value));
+}
+
+void RequestWriteDescriptorCallback(
+ int conn_id, int trans_id, bt_bdaddr_t* bda, int attr_handle, int offset,
+ bool need_rsp, bool is_prep,
+ std::vector<uint8_t> value) { // NOLINT(pass-by-value)
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " attr_handle: " << attr_handle << " offset: " << offset
+ << " length: " << value.size() << " need_rsp: " << need_rsp
+ << " is_prep: " << is_prep;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestWriteDescriptorCallback(
+ g_interface, conn_id, trans_id, *bda, attr_handle, offset, need_rsp,
+ is_prep, value));
+}
+
+void RequestExecWriteCallback(int conn_id, int trans_id, bt_bdaddr_t* bda,
+ int exec_write) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " trans_id: " << trans_id
+ << " exec_write: " << exec_write;
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(bda);
+
+ FOR_EACH_SERVER_OBSERVER(RequestExecWriteCallback(
+ g_interface, conn_id, trans_id, *bda, exec_write));
+}
+
+void ResponseConfirmationCallback(int status, int handle) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - status: " << status << " handle: " << handle;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_SERVER_OBSERVER(
+ ResponseConfirmationCallback(g_interface, status, handle));
+}
+
+void IndicationSentCallback(int conn_id, int status) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " status: " << status;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_SERVER_OBSERVER(
+ IndicationSentCallback(g_interface, conn_id, status));
+}
+
+void MtuChangedCallback(int conn_id, int mtu) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VLOG(2) << __func__ << " - conn_id: " << conn_id << " mtu: " << mtu;
+ VERIFY_INTERFACE_OR_RETURN();
+
+ FOR_EACH_SERVER_OBSERVER(MtuChangedCallback(g_interface, conn_id, mtu));
+}
+
+// The HAL Bluetooth GATT client interface callbacks. These signal a mixture of
+// GATT client-role and GAP events.
+
+const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
+ ScanResultCallback,
+ nullptr, // batchscan_reports_cb
+ nullptr, // batchscan_threshold_cb
+ nullptr, // track_adv_event_cb
+};
+
+const btgatt_client_callbacks_t gatt_client_callbacks = {
+ RegisterClientCallback,
+ ConnectCallback,
+ DisconnectCallback,
+ SearchCompleteCallback,
+ RegisterForNotificationCallback,
+ NotifyCallback,
+ nullptr, // read_characteristic_cb
+ WriteCharacteristicCallback,
+ nullptr, // read_descriptor_cb
+ WriteDescriptorCallback,
+ nullptr, // execute_write_cb
+ nullptr, // read_remote_rssi_cb
+ MtuChangedCallback,
+ nullptr, // congestion_cb
+ GetGattDbCallback,
+ ServicesRemovedCallback,
+ ServicesAddedCallback,
+ nullptr,
+ nullptr,
+};
+
+const btgatt_server_callbacks_t gatt_server_callbacks = {
+ RegisterServerCallback,
+ ConnectionCallback,
+ ServiceAddedCallback,
+ ServiceStoppedCallback,
+ ServiceDeletedCallback,
+ RequestReadCharacteristicCallback,
+ RequestReadDescriptorCallback,
+ RequestWriteCharacteristicCallback,
+ RequestWriteDescriptorCallback,
+ RequestExecWriteCallback,
+ ResponseConfirmationCallback,
+ IndicationSentCallback,
+ nullptr, // congestion_cb
+ MtuChangedCallback,
+ nullptr,
+ nullptr,
+};
+
+const btgatt_callbacks_t gatt_callbacks = {
+ sizeof(btgatt_callbacks_t), &gatt_client_callbacks, &gatt_server_callbacks,
+ &gatt_scanner_callbacks,
+};
+
+} // namespace
+
+// BluetoothGattInterface implementation for production.
+class BluetoothGattInterfaceImpl : public BluetoothGattInterface {
+ public:
+ BluetoothGattInterfaceImpl() : hal_iface_(nullptr) {}
+
+ ~BluetoothGattInterfaceImpl() override {
+ if (hal_iface_) hal_iface_->cleanup();
+ }
+
+ void AddScannerObserver(ScannerObserver* observer) override {
+ scanner_observers_.AddObserver(observer);
+ }
+
+ void RemoveScannerObserver(ScannerObserver* observer) override {
+ scanner_observers_.RemoveObserver(observer);
+ }
+
+ void AddClientObserver(ClientObserver* observer) override {
+ client_observers_.AddObserver(observer);
+ }
+
+ void RemoveClientObserver(ClientObserver* observer) override {
+ client_observers_.RemoveObserver(observer);
+ }
+
+ void AddServerObserver(ServerObserver* observer) override {
+ server_observers_.AddObserver(observer);
+ }
+
+ void RemoveServerObserver(ServerObserver* observer) override {
+ server_observers_.RemoveObserver(observer);
+ }
+
+ BleAdvertiserInterface* GetAdvertiserHALInterface() const override {
+ return hal_iface_->advertiser;
+ }
+
+ BleScannerInterface* GetScannerHALInterface() const override {
+ return hal_iface_->scanner;
+ }
+
+ const btgatt_client_interface_t* GetClientHALInterface() const override {
+ return hal_iface_->client;
+ }
+
+ const btgatt_server_interface_t* GetServerHALInterface() const override {
+ return hal_iface_->server;
+ }
+
+ // Initialize the interface.
+ bool Initialize() {
+ const bt_interface_t* bt_iface =
+ BluetoothInterface::Get()->GetHALInterface();
+ CHECK(bt_iface);
+
+ const btgatt_interface_t* gatt_iface =
+ reinterpret_cast<const btgatt_interface_t*>(
+ bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
+ if (!gatt_iface) {
+ LOG(ERROR) << "Failed to obtain HAL GATT interface handle";
+ return false;
+ }
+
+ bt_status_t status = gatt_iface->init(&gatt_callbacks);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize HAL GATT interface";
+ return false;
+ }
+
+ hal_iface_ = gatt_iface;
+
+ return true;
+ }
+
+ base::ObserverList<ScannerObserver>* scanner_observers() {
+ return &scanner_observers_;
+ }
+
+ base::ObserverList<ClientObserver>* client_observers() {
+ return &client_observers_;
+ }
+
+ base::ObserverList<ServerObserver>* server_observers() {
+ return &server_observers_;
+ }
+
+ private:
+ // List of observers that are interested in notifications from us.
+ // We're not using a base::ObserverListThreadSafe, which it posts observer
+ // events automatically on the origin threads, as we want to avoid that
+ // overhead and simply forward the events to the upper layer.
+ base::ObserverList<ScannerObserver> scanner_observers_;
+ base::ObserverList<ClientObserver> client_observers_;
+ base::ObserverList<ServerObserver> server_observers_;
+
+ // The HAL handle obtained from the shared library. We hold a weak reference
+ // to this since the actual data resides in the shared Bluetooth library.
+ const btgatt_interface_t* hal_iface_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterfaceImpl);
+};
+
+namespace {
+
+base::ObserverList<BluetoothGattInterface::ScannerObserver>*
+GetScannerObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothGattInterfaceImpl*>(g_interface)
+ ->scanner_observers();
+}
+
+base::ObserverList<BluetoothGattInterface::ClientObserver>*
+GetClientObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothGattInterfaceImpl*>(g_interface)
+ ->client_observers();
+}
+
+base::ObserverList<BluetoothGattInterface::ServerObserver>*
+GetServerObservers() {
+ CHECK(g_interface);
+ return static_cast<BluetoothGattInterfaceImpl*>(g_interface)
+ ->server_observers();
+}
+
+} // namespace
+
+// Default observer implementations. These are provided so that the methods
+// themselves are optional.
+
+void BluetoothGattInterface::ScannerObserver::ScanResultCallback(
+ BluetoothGattInterface* /* gatt_iface */, const bt_bdaddr_t& /* bda */,
+ int /* rssi */,
+ std::vector<uint8_t> /* adv_data */) { // NOLINT(pass-by-value)
+ // Do Nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::RegisterClientCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* client_if */, const bt_uuid_t& /* app_uuid */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ConnectCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */, int /* client_if */, const bt_bdaddr_t& /* bda */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::DisconnectCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */, int /* client_if */, const bt_bdaddr_t& /* bda */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::SearchCompleteCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::RegisterForNotificationCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */, int /* registered */, uint16_t /* handle */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::NotifyCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ btgatt_notify_params_t* /* p_data */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::WriteCharacteristicCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */, uint16_t /* handle */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::WriteDescriptorCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */, uint16_t /* handle */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ClientObserver::MtuChangedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* statis*/, int /* mtu */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::GetGattDbCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ btgatt_db_element_t* /* gatt_db */, int /* size */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ServicesRemovedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ uint16_t /* start_handle */, uint16_t /* end_handle */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ClientObserver::ServicesAddedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ btgatt_db_element_t* /* added */, int /* added_count */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RegisterServerCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* server_if */, const bt_uuid_t& /* app_uuid */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ConnectionCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* server_if */, int /* connected */, const bt_bdaddr_t& /* bda */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceAddedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* server_if */,
+ std::vector<btgatt_db_element_t> /* service */) { // NOLINT(pass-by-value)
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceStoppedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* server_if */, int /* srvc_handle */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ServiceDeletedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* server_if */, int /* srvc_handle */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestReadCharacteristicCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* trans_id */, const bt_bdaddr_t& /* bda */, int /* attr_handle */,
+ int /* offset */, bool /* is_long */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestReadDescriptorCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* trans_id */, const bt_bdaddr_t& /* bda */, int /* attr_handle */,
+ int /* offset */, bool /* is_long */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestWriteCharacteristicCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* trans_id */, const bt_bdaddr_t& /* bda */, int /* attr_handle */,
+ int /* offset */, bool /* need_rsp */, bool /* is_prep */,
+ std::vector<uint8_t> /* value */) { // NOLINT(pass-by-value)
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestWriteDescriptorCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* trans_id */, const bt_bdaddr_t& /* bda */, int /* attr_handle */,
+ int /* offset */, bool /* need_rsp */, bool /* is_prep */,
+ std::vector<uint8_t> /* value */) { // NOLINT(pass-by-value)
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::RequestExecWriteCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* trans_id */, const bt_bdaddr_t& /* bda */, int /* exec_write */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::ResponseConfirmationCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* status */,
+ int /* handle */) {
+ // Do nothing
+}
+
+void BluetoothGattInterface::ServerObserver::IndicationSentCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* status */) {
+ // Do nothing.
+}
+
+void BluetoothGattInterface::ServerObserver::MtuChangedCallback(
+ BluetoothGattInterface* /* gatt_iface */, int /* conn_id */,
+ int /* mtu */) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothGattInterface::Initialize() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_interface);
+
+ std::unique_ptr<BluetoothGattInterfaceImpl> impl(
+ new BluetoothGattInterfaceImpl());
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothGattInterface";
+ return false;
+ }
+
+ g_interface = impl.release();
+
+ return true;
+}
+
+// static
+void BluetoothGattInterface::CleanUp() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+
+ delete g_interface;
+ g_interface = nullptr;
+}
+
+// static
+bool BluetoothGattInterface::IsInitialized() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+
+ return g_interface != nullptr;
+}
+
+// static
+BluetoothGattInterface* BluetoothGattInterface::Get() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_interface);
+ return g_interface;
+}
+
+// static
+void BluetoothGattInterface::InitializeForTesting(
+ BluetoothGattInterface* test_instance) {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_interface);
+
+ g_interface = test_instance;
+}
+
+bt_status_t BluetoothGattInterface::StartScan(int client_id) {
+ lock_guard<mutex> lock(scan_clients_lock_);
+
+ // Scan already initiated for this client.
+ if (scan_client_set_.find(client_id) != scan_client_set_.end()) {
+ // Assume starting scan multiple times is not error, but warn user.
+ LOG(WARNING) << "Scan already initiated for client";
+ return BT_STATUS_SUCCESS;
+ }
+
+ // If this is the first scan client, then make a call into the stack. We
+ // only do this when the reference count changes to or from 0.
+ if (scan_client_set_.empty()) {
+ GetScannerHALInterface()->Scan(true);
+ }
+
+ scan_client_set_.insert(client_id);
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t BluetoothGattInterface::StopScan(int client_id) {
+ lock_guard<mutex> lock(scan_clients_lock_);
+
+ // Scan not initiated for this client.
+ auto iter = scan_client_set_.find(client_id);
+ if (iter == scan_client_set_.end()) {
+ // Assume stopping scan multiple times is not error, but warn user.
+ LOG(WARNING) << "Scan already stopped or not initiated for client";
+ return BT_STATUS_SUCCESS;
+ }
+
+ if (scan_client_set_.size() == 1) {
+ GetScannerHALInterface()->Scan(false);
+ }
+
+ scan_client_set_.erase(iter);
+ return BT_STATUS_SUCCESS;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.h b/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.h
new file mode 100755
index 0000000..9627dc1
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/bluetooth_gatt_interface.h
@@ -0,0 +1,262 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+
+#include <base/macros.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+
+namespace bluetooth {
+namespace hal {
+
+// This class represents the standard BT-GATT interface. This class combines
+// GATT profile server and client role operations with general GAP profile
+// operations of various roles (central, scanner, peripheral, advertiser),
+// wrapping around the underlying bt_gatt_interface_t structure. A single
+// instance of this class exists per application and it allows multiple classes
+// to interface with the global HAL interface by multiplexing callbacks among
+// registered clients.
+//
+// This is declared as an abstract interface so that a fake implementation can
+// be injected for testing the upper layer.
+class BluetoothGattInterface {
+ public:
+ // The HAL interface doesn't allow registering "user data" that carries
+ // context beyond the callback parameters, forcing implementations to deal
+ // with global variables. The *Observer interface is to redirect these events
+ // to interested parties in an object-oriented manner.
+
+ // The standard LE scanner callback interface.
+ class ScannerObserver {
+ public:
+ virtual ~ScannerObserver() = default;
+
+ // All of the events below correspond to callbacks defined in
+ // "btgatt_scanner_callbacks_t" in the HAL API definitions.
+
+ virtual void ScanResultCallback(
+ BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi,
+ std::vector<uint8_t> adv_data); // NOLINT(pass-by-value)
+ };
+
+ // The standard BT-GATT client callback interface.
+ class ClientObserver {
+ public:
+ virtual ~ClientObserver() = default;
+
+ // All of the events below correspond to callbacks defined in
+ // "bt_gatt_client_callbacks_t" in the HAL API definitions.
+
+ virtual void RegisterClientCallback(BluetoothGattInterface* gatt_iface,
+ int status, int client_if,
+ const bt_uuid_t& app_uuid);
+
+ virtual void ConnectCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status, int client_if,
+ const bt_bdaddr_t& bda);
+
+ virtual void DisconnectCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status, int client_if,
+ const bt_bdaddr_t& bda);
+
+ virtual void SearchCompleteCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status);
+
+ virtual void RegisterForNotificationCallback(
+ BluetoothGattInterface* gatt_iface, int conn_id, int status,
+ int registered, uint16_t handle);
+
+ virtual void NotifyCallback(BluetoothGattInterface* gatt_iface, int conn_id,
+ btgatt_notify_params_t* p_data);
+
+ virtual void WriteCharacteristicCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status,
+ uint16_t handle);
+
+ virtual void WriteDescriptorCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status,
+ uint16_t handle);
+
+ virtual void MtuChangedCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status, int mtu);
+
+ virtual void GetGattDbCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, btgatt_db_element_t* gatt_db,
+ int size);
+
+ virtual void ServicesRemovedCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, uint16_t start_handle,
+ uint16_t end_handle);
+
+ virtual void ServicesAddedCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, btgatt_db_element_t* added,
+ int added_count);
+ };
+
+ // The standard BT-GATT server callback interface.
+ class ServerObserver {
+ public:
+ virtual ~ServerObserver() = default;
+
+ virtual void RegisterServerCallback(BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ const bt_uuid_t& app_uuid);
+
+ virtual void ConnectionCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int server_if, int connected,
+ const bt_bdaddr_t& bda);
+
+ virtual void ServiceAddedCallback(
+ BluetoothGattInterface* gatt_iface, int status, int server_if,
+ std::vector<btgatt_db_element_t> service); // NOLINT(pass-by-value)
+
+ virtual void ServiceStoppedCallback(BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ int srvc_handle);
+
+ virtual void ServiceDeletedCallback(BluetoothGattInterface* gatt_iface,
+ int status, int server_if,
+ int srvc_handle);
+
+ virtual void RequestReadCharacteristicCallback(
+ BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool is_long);
+
+ virtual void RequestReadDescriptorCallback(
+ BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool is_long);
+
+ virtual void RequestWriteCharacteristicCallback(
+ BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool need_rsp,
+ bool is_prep,
+ std::vector<uint8_t> value); // NOLINT(pass-by-value)
+
+ virtual void RequestWriteDescriptorCallback(
+ BluetoothGattInterface* gatt_iface, int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int attr_handle, int offset, bool need_rsp,
+ bool is_prep,
+ std::vector<uint8_t> value); // NOLINT(pass-by-alue)
+
+ virtual void RequestExecWriteCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int exec_write);
+
+ virtual void ResponseConfirmationCallback(
+ BluetoothGattInterface* gatt_iface, int status, int handle);
+
+ virtual void IndicationSentCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int status);
+
+ virtual void MtuChangedCallback(BluetoothGattInterface* gatt_iface,
+ int conn_id, int mtu);
+ };
+
+ // Initialize and clean up the BluetoothInterface singleton. Returns false if
+ // the underlying HAL interface failed to initialize, and true on success.
+ static bool Initialize();
+
+ // Shuts down and cleans up the interface. CleanUp must be called on the same
+ // thread that called Initialize.
+ static void CleanUp();
+
+ // Returns true if the interface was initialized and a global singleton has
+ // been created.
+ static bool IsInitialized();
+
+ // Initialize for testing. Use this to inject a test version of
+ // BluetoothGattInterface. To be used from unit tests only.
+ static void InitializeForTesting(BluetoothGattInterface* test_instance);
+
+ // Returns the BluetoothGattInterface singleton. If the interface has
+ // not been initialized, returns nullptr. This method is thread-safe, in that
+ // it will block if the internal lock is being held by another thread. Don't
+ // call this re-entrantly from an observer event as this may cause a deadlock.
+ static BluetoothGattInterface* Get();
+
+ // Add or remove an observer that is interested in LE scanner interface
+ // notifications from us. Thread-safety is guaranteed by ObserverList.
+ virtual void AddScannerObserver(ScannerObserver* observer) = 0;
+ virtual void RemoveScannerObserver(ScannerObserver* observer) = 0;
+
+ // Add or remove an observer that is interested in GATT client interface
+ // notifications from us. Thread-safety is guaranteed by ObserverList.
+ virtual void AddClientObserver(ClientObserver* observer) = 0;
+ virtual void RemoveClientObserver(ClientObserver* observer) = 0;
+
+ // Add or remove an observer that is interested in GATT server interface
+ // notifications from us. Thread-safety is guaranteed by ObserverList.
+ virtual void AddServerObserver(ServerObserver* observer) = 0;
+ virtual void RemoveServerObserver(ServerObserver* observer) = 0;
+
+ // The HAL module pointer that represents the standard BT LE advertiser
+ // interface. This is implemented in and provided by the shared Bluetooth
+ // library, so this isn't owned by us.
+ //
+ // Upper layers can make ble_advertiser_interface_t API calls through this
+ // structure.
+ virtual BleAdvertiserInterface* GetAdvertiserHALInterface() const = 0;
+
+ // The HAL module pointer that represents the standard BT LE scanner
+ // interface. This is implemented in and provided by the shared Bluetooth
+ // library, so this isn't owned by us.
+ //
+ // Upper layers can make ble_scanner_interface_t API calls through this
+ // structure.
+ virtual BleScannerInterface* GetScannerHALInterface() const = 0;
+
+ // The HAL module pointer that represents the standard BT-GATT client
+ // interface. This is implemented in and provided by the shared Bluetooth
+ // library, so this isn't owned by us.
+ //
+ // Upper layers can make btgatt_client_interface_t API calls through this
+ // structure.
+ virtual const btgatt_client_interface_t* GetClientHALInterface() const = 0;
+
+ // The HAL module pointer that represents the standard BT-GATT server
+ // interface. This is implemented in and provided by the shared Bluetooth
+ // library, so this isn't owned by us.
+ //
+ // Upper layers can make btgatt_server_interface_t API calls through this
+ // structure.
+ virtual const btgatt_server_interface_t* GetServerHALInterface() const = 0;
+
+ // Initiates a regular BLE device scan. This is called internally from each
+ // LowEnergyClient. This function synchronizes the scan requests and maintains
+ // an internal reference count for each scan client that is interested.
+ bt_status_t StartScan(int client_id);
+ bt_status_t StopScan(int client_id);
+
+ protected:
+ BluetoothGattInterface() = default;
+ virtual ~BluetoothGattInterface() = default;
+
+ private:
+ // Used to keep a reference count for the different BLE scan clients.
+ std::mutex scan_clients_lock_;
+ std::unordered_set<int> scan_client_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothGattInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/bluetooth_interface.cc b/mtkbt/code/bt/service/hal/bluetooth_interface.cc
new file mode 100755
index 0000000..cf55afd
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/bluetooth_interface.cc
@@ -0,0 +1,406 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/hal/bluetooth_interface.h"
+
+#include <mutex>
+#include <shared_mutex>
+
+#include <base/logging.h>
+#include <base/observer_list.h>
+
+#include "service/logging_helpers.h"
+
+#include "btcore/include/hal_util.h"
+
+using std::lock_guard;
+using std::unique_lock;
+using std::shared_lock;
+using std::mutex;
+#if defined(OS_GENERIC) && defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION < 3500)
+using shared_mutex_impl = std::shared_mutex;
+#else
+using shared_mutex_impl = std::shared_timed_mutex;
+#endif
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+// The global BluetoothInterface instance.
+BluetoothInterface* g_bluetooth_interface = nullptr;
+
+// Mutex used by callbacks to access |g_interface|. If we initialize or clean it
+// use unique_lock. If only accessing |g_interface| use shared lock.
+// TODO(jpawlowski): this should be just shared_mutex, as we currently don't use
+// timed methods. Change to shared_mutex when we upgrade to C++14
+shared_mutex_impl g_instance_lock;
+
+// Helper for obtaining the observer list. This is forward declared here and
+// defined below since it depends on BluetoothInterfaceImpl.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers();
+
+#define FOR_EACH_BLUETOOTH_OBSERVER(func) \
+ FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
+
+#define VERIFY_INTERFACE_OR_RETURN() \
+ do { \
+ if (!g_bluetooth_interface) { \
+ LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+ return; \
+ } \
+ } while (0)
+
+void AdapterStateChangedCallback(bt_state_t state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << "Adapter state changed: " << BtStateText(state);
+ FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
+}
+
+void AdapterPropertiesCallback(bt_status_t status, int num_properties,
+ bt_property_t* properties) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
+ << ", num_properties: " << num_properties;
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ AdapterPropertiesCallback(status, num_properties, properties));
+}
+
+void RemoteDevicePropertiesCallback(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ int num_properties,
+ bt_property_t* properties) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << " Remote device properties changed - status: "
+ << BtStatusText(status)
+ << " - BD_ADDR: " << BtAddrString(remote_bd_addr)
+ << ", num_properties: " << num_properties;
+ FOR_EACH_BLUETOOTH_OBSERVER(RemoteDevicePropertiesCallback(
+ status, remote_bd_addr, num_properties, properties));
+}
+
+void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(1) << "Discovery state changed - state: " << BtDiscoveryStateText(state);
+ FOR_EACH_BLUETOOTH_OBSERVER(DiscoveryStateChangedCallback(state));
+}
+
+void PinRequestCallback(bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name,
+ uint32_t cod, bool min_16_digit) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(2) << __func__ << " - remote_bd_addr: " << remote_bd_addr
+ << " - bd_name: " << bd_name << " - cod: " << cod
+ << " - min_16_digit: " << min_16_digit;
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ PinRequestCallback(remote_bd_addr, bd_name, cod, min_16_digit));
+}
+
+void SSPRequestCallback(bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant,
+ uint32_t pass_key) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(2) << __func__ << " - remote_bd_addr: " << remote_bd_addr
+ << " - bd_name: " << bd_name << " - cod: " << cod
+ << " - pairing_variant: " << pairing_variant;
+ FOR_EACH_BLUETOOTH_OBSERVER(SSPRequestCallback(remote_bd_addr, bd_name, cod,
+ pairing_variant, pass_key));
+}
+
+void BondStateChangedCallback(bt_status_t status, bt_bdaddr_t* remote_bd_addr,
+ bt_bond_state_t state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ VLOG(2) << __func__ << " - remote_bd_addr: " << BtAddrString(remote_bd_addr)
+ << " - status: " << status << " - state: " << state;
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ BondStateChangedCallback(status, remote_bd_addr, state));
+}
+
+void AclStateChangedCallback(bt_status_t status, bt_bdaddr_t* remote_bd_addr,
+ bt_acl_state_t state) {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ VERIFY_INTERFACE_OR_RETURN();
+ CHECK(remote_bd_addr);
+ VLOG(1) << "Remote device ACL state changed - status: "
+ << BtStatusText(status)
+ << " - BD_ADDR: " << BtAddrString(remote_bd_addr) << " - state: "
+ << ((state == BT_ACL_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED");
+ FOR_EACH_BLUETOOTH_OBSERVER(
+ AclStateChangedCallback(status, *remote_bd_addr, state));
+}
+
+void ThreadEventCallback(bt_cb_thread_evt evt) {
+ VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
+
+ // TODO(armansito): This callback is completely useless to us but btif borks
+ // out if this is not set. Consider making this optional.
+}
+
+bool SetWakeAlarmCallout(uint64_t /* delay_millis */, bool /* should_wake */,
+ alarm_cb /* cb */, void* /* data */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ return false;
+}
+
+int AcquireWakeLockCallout(const char* /* lock_name */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ // Lie here and return success so that enabling and disabling the controller
+ // works before this is properly implemented.
+ return BT_STATUS_SUCCESS;
+}
+
+int ReleaseWakeLockCallout(const char* /* lock_name */) {
+ // TODO(armansito): According to sharvil@, this interface doesn't even need to
+ // exist and can be done entirely from within osi by interfacing directly with
+ // the kernel. Remove these stubs once that's fixed. (See http://b/23390297)
+ // Lie here and return success so that enabling and disabling the controller
+ // works before this is properly implemented.
+ return BT_STATUS_SUCCESS;
+}
+
+// The HAL Bluetooth DM callbacks.
+bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ AdapterStateChangedCallback,
+ AdapterPropertiesCallback,
+ RemoteDevicePropertiesCallback,
+ nullptr, /* device_found_cb */
+ DiscoveryStateChangedCallback,
+ PinRequestCallback,
+ SSPRequestCallback,
+ BondStateChangedCallback,
+ AclStateChangedCallback,
+ ThreadEventCallback,
+ nullptr, /* dut_mode_recv_cb */
+ nullptr, /* le_test_mode_cb */
+ nullptr /* energy_info_cb */
+};
+
+bt_os_callouts_t bt_os_callouts = {sizeof(bt_os_callouts_t),
+ SetWakeAlarmCallout, AcquireWakeLockCallout,
+ ReleaseWakeLockCallout};
+
+} // namespace
+
+// BluetoothInterface implementation for production.
+class BluetoothInterfaceImpl : public BluetoothInterface {
+ public:
+ BluetoothInterfaceImpl() : hal_iface_(nullptr), hal_adapter_(nullptr) {}
+
+ ~BluetoothInterfaceImpl() override {
+ if (hal_iface_) hal_iface_->cleanup();
+ }
+
+ // BluetoothInterface overrides.
+ void AddObserver(Observer* observer) override {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(Observer* observer) override {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ observers_.RemoveObserver(observer);
+ }
+
+ const bt_interface_t* GetHALInterface() const override { return hal_iface_; }
+
+ bt_callbacks_t* GetHALCallbacks() const override { return &bt_callbacks; }
+
+ const bluetooth_device_t* GetHALAdapter() const override {
+ return hal_adapter_;
+ }
+
+ // Initialize the interface. This loads the shared Bluetooth library and sets
+ // up the callbacks.
+ bool Initialize() {
+ // Load the Bluetooth shared library module.
+ const hw_module_t* module;
+ int status = hal_util_load_bt_library(&module);
+ if (status) {
+ LOG(ERROR) << "Failed to load Bluetooth library: " << status;
+ return false;
+ }
+
+ // Open the Bluetooth adapter.
+ hw_device_t* device;
+ status = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
+ if (status) {
+ LOG(ERROR) << "Failed to open the Bluetooth module";
+ return false;
+ }
+
+ hal_adapter_ = reinterpret_cast<bluetooth_device_t*>(device);
+ hal_iface_ = hal_adapter_->get_bluetooth_interface();
+
+ // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
+ // callbacks.
+ status = hal_iface_->init(&bt_callbacks);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initialize Bluetooth stack";
+ return false;
+ }
+
+ status = hal_iface_->set_os_callouts(&bt_os_callouts);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to set up Bluetooth OS callouts";
+ return false;
+ }
+
+ return true;
+ }
+
+ base::ObserverList<Observer>* observers() { return &observers_; }
+
+ private:
+ // List of observers that are interested in notifications from us. We're not
+ // using a base::ObserverListThreadSafe, which it posts observer events
+ // automatically on the origin threads, as we want to avoid that overhead and
+ // simply forward the events to the upper layer.
+ base::ObserverList<Observer> observers_;
+
+ // The HAL handle obtained from the shared library. We hold a weak reference
+ // to this since the actual data resides in the shared Bluetooth library.
+ const bt_interface_t* hal_iface_;
+
+ // The HAL handle that represents the underlying Bluetooth adapter. We hold a
+ // weak reference to this since the actual data resides in the shared
+ // Bluetooth library.
+ const bluetooth_device_t* hal_adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInterfaceImpl);
+};
+
+namespace {
+
+// Helper for obtaining the observer list from the global instance. This
+// function is NOT thread safe.
+base::ObserverList<BluetoothInterface::Observer>* GetObservers() {
+ CHECK(g_bluetooth_interface);
+ return static_cast<BluetoothInterfaceImpl*>(g_bluetooth_interface)
+ ->observers();
+}
+
+} // namespace
+
+// Default observer implementations. These are provided so that the methods
+// themselves are optional.
+void BluetoothInterface::Observer::AdapterStateChangedCallback(
+ bt_state_t /* state*/) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::AdapterPropertiesCallback(
+ bt_status_t /* status */, int /* num_properties */,
+ bt_property_t* /* properties */) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::RemoteDevicePropertiesCallback(
+ bt_status_t /* status */, bt_bdaddr_t* /* remote_bd_addr */,
+ int /* num_properties */, bt_property_t* /* properties */) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
+ bt_discovery_state_t /* state */) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::PinRequestCallback(
+ bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
+ bool min_16_digit) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::SSPRequestCallback(
+ bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name, uint32_t cod,
+ bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::BondStateChangedCallback(
+ bt_status_t status, bt_bdaddr_t* remote_bd_addr, bt_bond_state_t state) {
+ // Do nothing.
+}
+
+void BluetoothInterface::Observer::AclStateChangedCallback(
+ bt_status_t /* status */, const bt_bdaddr_t& /* remote_bdaddr */,
+ bt_acl_state_t /* state */) {
+ // Do nothing.
+}
+
+// static
+bool BluetoothInterface::Initialize() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(!g_bluetooth_interface);
+
+ std::unique_ptr<BluetoothInterfaceImpl> impl(new BluetoothInterfaceImpl());
+ if (!impl->Initialize()) {
+ LOG(ERROR) << "Failed to initialize BluetoothInterface";
+ return false;
+ }
+
+ g_bluetooth_interface = impl.release();
+
+ return true;
+}
+
+// static
+void BluetoothInterface::CleanUp() {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_bluetooth_interface);
+
+ delete g_bluetooth_interface;
+ g_bluetooth_interface = nullptr;
+}
+
+// static
+bool BluetoothInterface::IsInitialized() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+
+ return g_bluetooth_interface != nullptr;
+}
+
+// static
+BluetoothInterface* BluetoothInterface::Get() {
+ shared_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(g_bluetooth_interface);
+ return g_bluetooth_interface;
+}
+
+// static
+void BluetoothInterface::InitializeForTesting(
+ BluetoothInterface* test_instance) {
+ unique_lock<shared_mutex_impl> lock(g_instance_lock);
+ CHECK(test_instance);
+ CHECK(!g_bluetooth_interface);
+
+ g_bluetooth_interface = test_instance;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/bluetooth_interface.h b/mtkbt/code/bt/service/hal/bluetooth_interface.h
new file mode 100755
index 0000000..92d94ba
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/bluetooth_interface.h
@@ -0,0 +1,128 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+#include <hardware/bluetooth.h>
+
+namespace bluetooth {
+namespace hal {
+
+// This class represents the HAL Bluetooth adapter interface, wrapping around
+// the underlying bt_interface_t structure, its methods, and callbacks. A single
+// instance of this class exists per application and it allows multiple classes
+// to interface with the global HAL interface by multiplexing callbacks among
+// registered clients.
+//
+// This is declared as an abstract interface so that a fake implementation can
+// be injected for testing the upper layer.
+//
+// TODO: (expose callback types directly but via redirection) methods for
+// initialize, clean up, and set for testing.
+class BluetoothInterface {
+ public:
+ // The standard Bluetooth adapter management callback interface. The HAL
+ // interface doesn't allow registering "user data" that carries context beyond
+ // the callback parameters, forcing implementations to deal with global
+ // variables. The Observer interface is to redirect these events to interested
+ // parties in an object-oriented manner.
+ //
+ // TODO(armansito): We should fix this in the HAL.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ // All of the events below correspond to callbacks defined in
+ // "bt_callbacks_t" in the HAL API definitions.
+
+ virtual void AdapterStateChangedCallback(bt_state_t state);
+ virtual void AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* properties);
+ virtual void RemoteDevicePropertiesCallback(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ int num_properties,
+ bt_property_t* properties);
+ virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
+ virtual void PinRequestCallback(bt_bdaddr_t* remote_bd_addr,
+ bt_bdname_t* bd_name, uint32_t cod,
+ bool min_16_digit);
+ virtual void SSPRequestCallback(bt_bdaddr_t* remote_bd_addr,
+ bt_bdname_t* bd_name, uint32_t cod,
+ bt_ssp_variant_t pairing_variant,
+ uint32_t pass_key);
+ virtual void BondStateChangedCallback(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ bt_bond_state_t state);
+ virtual void AclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state);
+
+ // TODO(armansito): Complete the list of callbacks.
+ };
+
+ // Initialize and clean up the BluetoothInterface singleton. Returns false if
+ // the underlying HAL interface failed to initialize, and true on success.
+ static bool Initialize();
+
+ // Shuts down and cleans up the interface. CleanUp must be called on the same
+ // thread that called Initialize.
+ static void CleanUp();
+
+ // Returns true if the interface was initialized and a global singleton has
+ // been created.
+ static bool IsInitialized();
+
+ // Initialize for testing. Use this to inject a test version of
+ // BlueoothInterface. To be used from unit tests only.
+ static void InitializeForTesting(BluetoothInterface* test_instance);
+
+ // Returns the BluetoothInterface singleton. If the interface has not been
+ // initialized, returns nullptr.
+ static BluetoothInterface* Get();
+
+ // Add or remove an observer that is interested in notifications from us.
+ virtual void AddObserver(Observer* observer) = 0;
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // The HAL module pointer that represents the standard Bluetooth adapter
+ // management interface. This is implemented in and provided by the shared
+ // Bluetooth library, so this isn't owned by us.
+ //
+ // Upper layers can make bt_interface_t API calls through this structure.
+ // However, DO NOT call the "init" function as this is called and managed by
+ // us. The behavior is undefined if "init" is called directly by upper layers.
+ virtual const bt_interface_t* GetHALInterface() const = 0;
+
+ // Returns the HAL callbacks that have been initialized previously.
+ virtual bt_callbacks_t* GetHALCallbacks() const = 0;
+
+ // The HAL module pointer that represents the underlying Bluetooth adapter.
+ // This is implemented in and provided by the shared Bluetooth library, so
+ // this isn't owned by us.
+ virtual const bluetooth_device_t* GetHALAdapter() const = 0;
+
+ protected:
+ BluetoothInterface() = default;
+ virtual ~BluetoothInterface() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BluetoothInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.cc b/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.cc
new file mode 100755
index 0000000..1250e85
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.cc
@@ -0,0 +1,325 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+// The global test handler instances. We have to have globals since the HAL
+// interface methods all have to be global and their signatures don't allow us
+// to pass in user_data.
+std::shared_ptr<BleAdvertiserInterface> g_advertiser_handler;
+std::shared_ptr<BleScannerInterface> g_scanner_handler;
+std::shared_ptr<FakeBluetoothGattInterface::TestClientHandler> g_client_handler;
+std::shared_ptr<FakeBluetoothGattInterface::TestServerHandler> g_server_handler;
+
+bt_status_t FakeRegisterClient(bt_uuid_t* app_uuid) {
+ if (g_client_handler) return g_client_handler->RegisterClient(app_uuid);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeUnregisterClient(int client_if) {
+ if (g_client_handler) return g_client_handler->UnregisterClient(client_if);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeConnect(int client_if, const bt_bdaddr_t* bd_addr,
+ bool is_direct, int transport, int phy) {
+ if (g_client_handler)
+ return g_client_handler->Connect(client_if, bd_addr, is_direct, transport);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDisconnect(int client_if, const bt_bdaddr_t* bd_addr,
+ int conn_id) {
+ if (g_client_handler)
+ return g_client_handler->Disconnect(client_if, bd_addr, conn_id);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeRegisterServer(bt_uuid_t* app_uuid) {
+ if (g_server_handler) return g_server_handler->RegisterServer(app_uuid);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeUnregisterServer(int server_if) {
+ if (g_server_handler) return g_server_handler->UnregisterServer(server_if);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeAddService(int server_if,
+ std::vector<btgatt_db_element_t> service) {
+ if (g_server_handler)
+ return g_server_handler->AddService(server_if, std::move(service));
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeDeleteService(int server_if, int srvc_handle) {
+ if (g_server_handler)
+ return g_server_handler->DeleteService(server_if, srvc_handle);
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeSendIndication(int server_if, int attribute_handle, int conn_id,
+ int confirm, std::vector<uint8_t> value) {
+ if (g_server_handler)
+ return g_server_handler->SendIndication(server_if, attribute_handle,
+ conn_id, confirm, std::move(value));
+
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t FakeSendResponse(int conn_id, int trans_id, int status,
+ btgatt_response_t* response) {
+ if (g_server_handler)
+ return g_server_handler->SendResponse(conn_id, trans_id, status, response);
+
+ return BT_STATUS_FAIL;
+}
+
+btgatt_client_interface_t fake_btgattc_iface = {
+ FakeRegisterClient,
+ FakeUnregisterClient,
+ FakeConnect,
+ FakeDisconnect,
+ nullptr, // refresh
+ nullptr, // search_service
+ nullptr, // discover_service_by_uuid
+ nullptr, // read_characteristic
+ nullptr, // read_using_characteristic_uuid
+ nullptr, // write_characteristic
+ nullptr, // read_descriptor
+ nullptr, // write_descriptor
+ nullptr, // execute_write
+ nullptr, // register_for_notification
+ nullptr, // deregister_for_notification
+ nullptr, // read_remote_rssi
+ nullptr, // get_device_type
+ nullptr, // configure_mtu
+ nullptr, // conn_parameter_update
+ nullptr, // set_phy
+ nullptr, // read_phy
+ nullptr, // test_command
+ nullptr, // get_gatt_db
+};
+
+btgatt_server_interface_t fake_btgatts_iface = {
+ FakeRegisterServer,
+ FakeUnregisterServer,
+ nullptr, // connect
+ nullptr, // disconnect
+ FakeAddService,
+ nullptr, // stop_service
+ FakeDeleteService,
+ FakeSendIndication,
+ FakeSendResponse,
+ nullptr, // set_phy
+ nullptr, // read_phy
+};
+
+} // namespace
+
+FakeBluetoothGattInterface::FakeBluetoothGattInterface(
+ std::shared_ptr<BleAdvertiserInterface> advertiser_handler,
+ std::shared_ptr<BleScannerInterface> scanner_handler,
+ std::shared_ptr<TestClientHandler> client_handler,
+ std::shared_ptr<TestServerHandler> server_handler)
+ : client_handler_(client_handler) {
+ CHECK(!g_advertiser_handler);
+ CHECK(!g_scanner_handler);
+ CHECK(!g_client_handler);
+ CHECK(!g_server_handler);
+
+ // We allow passing NULL. In this case all calls we fail by default.
+ if (advertiser_handler) g_advertiser_handler = advertiser_handler;
+
+ if (scanner_handler) g_scanner_handler = scanner_handler;
+
+ if (client_handler) g_client_handler = client_handler;
+
+ if (server_handler) g_server_handler = server_handler;
+}
+
+FakeBluetoothGattInterface::~FakeBluetoothGattInterface() {
+ if (g_advertiser_handler) g_advertiser_handler = nullptr;
+
+ if (g_scanner_handler) g_scanner_handler = nullptr;
+
+ if (g_client_handler) g_client_handler = nullptr;
+
+ if (g_server_handler) g_server_handler = nullptr;
+}
+
+// The methods below can be used to notify observers with certain events and
+// given parameters.
+void FakeBluetoothGattInterface::NotifyScanResultCallback(
+ const bt_bdaddr_t& bda, int rssi, std::vector<uint8_t> adv_data) {
+ FOR_EACH_OBSERVER(ScannerObserver, scanner_observers_,
+ ScanResultCallback(this, bda, rssi, adv_data));
+}
+
+void FakeBluetoothGattInterface::NotifyRegisterClientCallback(
+ int status, int client_if, const bt_uuid_t& app_uuid) {
+ FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+ RegisterClientCallback(this, status, client_if, app_uuid));
+}
+
+void FakeBluetoothGattInterface::NotifyConnectCallback(int conn_id, int status,
+ int client_if,
+ const bt_bdaddr_t& bda) {
+ FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+ ConnectCallback(this, conn_id, status, client_if, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyDisconnectCallback(
+ int conn_id, int status, int client_if, const bt_bdaddr_t& bda) {
+ FOR_EACH_OBSERVER(ClientObserver, client_observers_,
+ DisconnectCallback(this, conn_id, status, client_if, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyRegisterServerCallback(
+ int status, int server_if, const bt_uuid_t& app_uuid) {
+ FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+ RegisterServerCallback(this, status, server_if, app_uuid));
+}
+
+void FakeBluetoothGattInterface::NotifyServerConnectionCallback(
+ int conn_id, int server_if, int connected, const bt_bdaddr_t& bda) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ ConnectionCallback(this, conn_id, server_if, connected, bda));
+}
+
+void FakeBluetoothGattInterface::NotifyServiceAddedCallback(
+ int status, int server_if, std::vector<btgatt_db_element_t> service) {
+ FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+ ServiceAddedCallback(this, status, server_if, service));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestReadCharacteristicCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+ int offset, bool is_long) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestReadCharacteristicCallback(this, conn_id, trans_id, bda,
+ attr_handle, offset, is_long));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestReadDescriptorCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+ int offset, bool is_long) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestReadDescriptorCallback(this, conn_id, trans_id, bda, attr_handle,
+ offset, is_long));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestWriteCharacteristicCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+ int offset, bool need_rsp, bool is_prep, std::vector<uint8_t> value) {
+ FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+ RequestWriteCharacteristicCallback(
+ this, conn_id, trans_id, bda, attr_handle, offset,
+ need_rsp, is_prep, value));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestWriteDescriptorCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int attr_handle,
+ int offset, bool need_rsp, bool is_prep, std::vector<uint8_t> value) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestWriteDescriptorCallback(this, conn_id, trans_id, bda, attr_handle,
+ offset, need_rsp, is_prep, value));
+}
+
+void FakeBluetoothGattInterface::NotifyRequestExecWriteCallback(
+ int conn_id, int trans_id, const bt_bdaddr_t& bda, int exec_write) {
+ FOR_EACH_OBSERVER(
+ ServerObserver, server_observers_,
+ RequestExecWriteCallback(this, conn_id, trans_id, bda, exec_write));
+}
+
+void FakeBluetoothGattInterface::NotifyIndicationSentCallback(int conn_id,
+ int status) {
+ FOR_EACH_OBSERVER(ServerObserver, server_observers_,
+ IndicationSentCallback(this, conn_id, status));
+}
+
+void FakeBluetoothGattInterface::AddScannerObserver(ScannerObserver* observer) {
+ CHECK(observer);
+ scanner_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveScannerObserver(
+ ScannerObserver* observer) {
+ CHECK(observer);
+ scanner_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothGattInterface::AddClientObserver(ClientObserver* observer) {
+ CHECK(observer);
+ client_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveClientObserver(
+ ClientObserver* observer) {
+ CHECK(observer);
+ client_observers_.RemoveObserver(observer);
+}
+
+void FakeBluetoothGattInterface::AddServerObserver(ServerObserver* observer) {
+ CHECK(observer);
+ server_observers_.AddObserver(observer);
+}
+
+void FakeBluetoothGattInterface::RemoveServerObserver(
+ ServerObserver* observer) {
+ CHECK(observer);
+ server_observers_.RemoveObserver(observer);
+}
+
+BleAdvertiserInterface* FakeBluetoothGattInterface::GetAdvertiserHALInterface()
+ const {
+ return g_advertiser_handler.get();
+}
+
+BleScannerInterface* FakeBluetoothGattInterface::GetScannerHALInterface()
+ const {
+ return g_scanner_handler.get();
+}
+
+const btgatt_client_interface_t*
+FakeBluetoothGattInterface::GetClientHALInterface() const {
+ return &fake_btgattc_iface;
+}
+
+const btgatt_server_interface_t*
+FakeBluetoothGattInterface::GetServerHALInterface() const {
+ return &fake_btgatts_iface;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.h b/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.h
new file mode 100755
index 0000000..c96f7f0
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/fake_bluetooth_gatt_interface.h
@@ -0,0 +1,150 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothGattInterface : public BluetoothGattInterface {
+ public:
+ // Handles HAL Bluetooth GATT client API calls for testing. Test code can
+ // provide a fake or mock implementation of this and all calls will be routed
+ // to it.
+ class TestClientHandler {
+ public:
+ virtual ~TestClientHandler() = default;
+
+ virtual bt_status_t RegisterClient(bt_uuid_t* app_uuid) = 0;
+ virtual bt_status_t UnregisterClient(int client_if) = 0;
+
+ virtual bt_status_t Connect(int client_if, const bt_bdaddr_t* bd_addr,
+ bool is_direct, int transport) = 0;
+ virtual bt_status_t Disconnect(int client_if, const bt_bdaddr_t* bd_addr,
+ int conn_id) = 0;
+ };
+
+ // Handles HAL Bluetooth GATT server API calls for testing. Test code can
+ // provide a fake or mock implementation of this and all calls will be routed
+ // to it.
+ class TestServerHandler {
+ public:
+ virtual ~TestServerHandler() = default;
+
+ virtual bt_status_t RegisterServer(bt_uuid_t* app_uuid) = 0;
+ virtual bt_status_t UnregisterServer(int server_if) = 0;
+ virtual bt_status_t AddService(
+ int server_if, std::vector<btgatt_db_element_t> service) = 0;
+ virtual bt_status_t DeleteService(int server_if, int srvc_handle) = 0;
+ virtual bt_status_t SendIndication(int server_if, int attribute_handle,
+ int conn_id, int confirm,
+ std::vector<uint8_t> value) = 0;
+ virtual bt_status_t SendResponse(int conn_id, int trans_id, int status,
+ btgatt_response_t* response) = 0;
+ };
+
+ // Constructs the fake with the given handlers. Implementations can
+ // provide their own handlers or simply pass "nullptr" for the default
+ // behavior in which BT_STATUS_FAIL will be returned from all calls.
+ FakeBluetoothGattInterface(
+ std::shared_ptr<BleAdvertiserInterface> advertiser_handler,
+ std::shared_ptr<BleScannerInterface> scanner_handler,
+ std::shared_ptr<TestClientHandler> client_handler,
+ std::shared_ptr<TestServerHandler> server_handler);
+ ~FakeBluetoothGattInterface();
+
+ // The methods below can be used to notify observers with certain events and
+ // given parameters.
+
+ void NotifyRegisterScannerCallback(int status, int client_if,
+ const bt_uuid_t& app_uuid);
+ void NotifyScanResultCallback(const bt_bdaddr_t& bda, int rssi,
+ std::vector<uint8_t> adv_data);
+
+ // Client callbacks:
+ void NotifyRegisterClientCallback(int status, int client_if,
+ const bt_uuid_t& app_uuid);
+ void NotifyConnectCallback(int conn_id, int status, int client_if,
+ const bt_bdaddr_t& bda);
+ void NotifyDisconnectCallback(int conn_id, int status, int client_if,
+ const bt_bdaddr_t& bda);
+
+ // Server callbacks:
+ void NotifyRegisterServerCallback(int status, int server_if,
+ const bt_uuid_t& app_uuid);
+ void NotifyServerConnectionCallback(int conn_id, int server_if, int connected,
+ const bt_bdaddr_t& bda);
+ void NotifyServiceAddedCallback(int status, int server_if,
+ std::vector<btgatt_db_element_t> srvc);
+ void NotifyCharacteristicAddedCallback(int status, int server_if,
+ const bt_uuid_t& uuid, int srvc_handle,
+ int char_handle);
+ void NotifyDescriptorAddedCallback(int status, int server_if,
+ const bt_uuid_t& uuid, int srvc_handle,
+ int desc_handle);
+ void NotifyServiceStartedCallback(int status, int server_if, int srvc_handle);
+ void NotifyRequestReadCharacteristicCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset,
+ bool is_long);
+ void NotifyRequestReadDescriptorCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset,
+ bool is_long);
+ void NotifyRequestWriteCharacteristicCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset,
+ bool need_rsp, bool is_prep,
+ std::vector<uint8_t> value);
+ void NotifyRequestWriteDescriptorCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda,
+ int attr_handle, int offset,
+ bool need_rsp, bool is_prep,
+ std::vector<uint8_t> value);
+ void NotifyRequestExecWriteCallback(int conn_id, int trans_id,
+ const bt_bdaddr_t& bda, int exec_write);
+ void NotifyIndicationSentCallback(int conn_id, int status);
+
+ // BluetoothGattInterface overrides:
+ void AddScannerObserver(ScannerObserver* observer) override;
+ void RemoveScannerObserver(ScannerObserver* observer) override;
+ void AddClientObserver(ClientObserver* observer) override;
+ void RemoveClientObserver(ClientObserver* observer) override;
+ void AddServerObserver(ServerObserver* observer) override;
+ void RemoveServerObserver(ServerObserver* observer) override;
+ BleAdvertiserInterface* GetAdvertiserHALInterface() const override;
+ BleScannerInterface* GetScannerHALInterface() const override;
+ const btgatt_client_interface_t* GetClientHALInterface() const override;
+ const btgatt_server_interface_t* GetServerHALInterface() const override;
+
+ private:
+ base::ObserverList<ScannerObserver> scanner_observers_;
+ base::ObserverList<ClientObserver> client_observers_;
+ base::ObserverList<ServerObserver> server_observers_;
+ std::shared_ptr<BleScannerInterface> scanner_handler_;
+ std::shared_ptr<TestClientHandler> client_handler_;
+ std::shared_ptr<TestServerHandler> server_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothGattInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/fake_bluetooth_interface.cc b/mtkbt/code/bt/service/hal/fake_bluetooth_interface.cc
new file mode 100755
index 0000000..95f1f98
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/fake_bluetooth_interface.cc
@@ -0,0 +1,164 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+
+FakeBluetoothInterface::Manager g_hal_manager;
+
+int FakeHALEnable(bool start_restricted) {
+ return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALDisable() {
+ return g_hal_manager.disable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
+}
+
+int FakeHALGetAdapterProperties() { return BT_STATUS_SUCCESS; }
+
+int FakeHALSetAdapterProperty(const bt_property_t* /* property */) {
+ LOG(INFO) << __func__;
+ return (g_hal_manager.set_property_succeed ? BT_STATUS_SUCCESS
+ : BT_STATUS_FAIL);
+}
+
+bt_interface_t fake_bt_iface = {
+ sizeof(bt_interface_t),
+ nullptr, /* init */
+ FakeHALEnable,
+ FakeHALDisable,
+ nullptr, /* cleanup */
+ FakeHALGetAdapterProperties,
+ nullptr, /* get_adapter_property */
+ FakeHALSetAdapterProperty,
+ nullptr, /* get_remote_device_properties */
+ nullptr, /* get_remote_device_property */
+ nullptr, /* set_remote_device_property */
+ nullptr, /* get_remote_service_record */
+ nullptr, /* get_remote_services */
+ nullptr, /* start_discovery */
+ nullptr, /* cancel_discovery */
+ nullptr, /* create_bond */
+ nullptr, /* create_bond_out_of_band */
+ nullptr, /* remove_bond */
+ nullptr, /* cancel_bond */
+ nullptr, /* get_connection_state */
+ nullptr, /* pin_reply */
+ nullptr, /* ssp_reply */
+ nullptr, /* get_profile_interface */
+ nullptr, /* dut_mode_configure */
+ nullptr, /* dut_more_send */
+ nullptr, /* le_test_mode */
+ nullptr, /* set_os_callouts */
+ nullptr, /* read_energy_info */
+ nullptr, /* dump */
+ nullptr, /* config clear */
+ nullptr, /* interop_database_clear */
+ nullptr /* interop_database_add */
+};
+
+} // namespace
+
+// static
+FakeBluetoothInterface::Manager* FakeBluetoothInterface::GetManager() {
+ return &g_hal_manager;
+}
+
+FakeBluetoothInterface::Manager::Manager()
+ : enable_succeed(false),
+ disable_succeed(false),
+ set_property_succeed(false) {}
+
+void FakeBluetoothInterface::NotifyAdapterStateChanged(bt_state_t state) {
+ FOR_EACH_OBSERVER(Observer, observers_, AdapterStateChangedCallback(state));
+}
+
+void FakeBluetoothInterface::NotifyAdapterPropertiesChanged(
+ int num_properties, bt_property_t* properties) {
+ FOR_EACH_OBSERVER(
+ Observer, observers_,
+ AdapterPropertiesCallback(BT_STATUS_SUCCESS, num_properties, properties));
+}
+
+void FakeBluetoothInterface::NotifyAdapterNamePropertyChanged(
+ const std::string& name) {
+ bt_bdname_t hal_name;
+ strncpy(reinterpret_cast<char*>(hal_name.name), name.c_str(),
+ std::min(sizeof(hal_name) - 1, name.length()));
+ reinterpret_cast<char*>(hal_name.name)[name.length()] = '\0';
+
+ bt_property_t property;
+ property.len = sizeof(hal_name);
+ property.val = &hal_name;
+ property.type = BT_PROPERTY_BDNAME;
+
+ NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAdapterAddressPropertyChanged(
+ const bt_bdaddr_t* address) {
+ bt_property_t property;
+ property.len = sizeof(bt_bdaddr_t);
+ property.val = (void*)address;
+ property.type = BT_PROPERTY_BDADDR;
+
+ NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAdapterLocalLeFeaturesPropertyChanged(
+ const bt_local_le_features_t* features) {
+ bt_property_t property;
+ property.len = sizeof(*features);
+ property.val = (void*)features;
+ property.type = BT_PROPERTY_LOCAL_LE_FEATURES;
+
+ NotifyAdapterPropertiesChanged(1, &property);
+}
+
+void FakeBluetoothInterface::NotifyAclStateChangedCallback(
+ bt_status_t status, const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state) {
+ FOR_EACH_OBSERVER(Observer, observers_,
+ AclStateChangedCallback(status, remote_bdaddr, state));
+}
+
+void FakeBluetoothInterface::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void FakeBluetoothInterface::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+const bt_interface_t* FakeBluetoothInterface::GetHALInterface() const {
+ return &fake_bt_iface;
+}
+
+bt_callbacks_t* FakeBluetoothInterface::GetHALCallbacks() const {
+ return nullptr;
+}
+
+const bluetooth_device_t* FakeBluetoothInterface::GetHALAdapter() const {
+ // TODO(armansito): Do something meaningful here to simulate test behavior.
+ return nullptr;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/hal/fake_bluetooth_interface.h b/mtkbt/code/bt/service/hal/fake_bluetooth_interface.h
new file mode 100755
index 0000000..1b2e246
--- a/dev/null
+++ b/mtkbt/code/bt/service/hal/fake_bluetooth_interface.h
@@ -0,0 +1,75 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <base/observer_list.h>
+
+#include "service/hal/bluetooth_interface.h"
+
+namespace bluetooth {
+namespace hal {
+
+class FakeBluetoothInterface : public BluetoothInterface {
+ public:
+ // A Fake HAL Bluetooth interface. This is kept as a global singleton as the
+ // Bluetooth HAL doesn't support anything otherwise.
+ //
+ // TODO(armansito): Use an abstract "TestHandler" interface instead.
+ struct Manager {
+ Manager();
+ ~Manager() = default;
+
+ // Values that should be returned from bt_interface_t methods.
+ bool enable_succeed;
+ bool disable_succeed;
+ bool set_property_succeed;
+ };
+
+ // Returns the global Manager.
+ static Manager* GetManager();
+
+ FakeBluetoothInterface() = default;
+ ~FakeBluetoothInterface() override = default;
+
+ // Notifies the observers that the adapter state changed to |state|.
+ void NotifyAdapterStateChanged(bt_state_t state);
+
+ // Triggers an adapter property change event.
+ void NotifyAdapterPropertiesChanged(int num_properties,
+ bt_property_t* properties);
+ void NotifyAdapterNamePropertyChanged(const std::string& name);
+ void NotifyAdapterAddressPropertyChanged(const bt_bdaddr_t* address);
+ void NotifyAdapterLocalLeFeaturesPropertyChanged(
+ const bt_local_le_features_t* features);
+ void NotifyAclStateChangedCallback(bt_status_t status,
+ const bt_bdaddr_t& remote_bdaddr,
+ bt_acl_state_t state);
+
+ // hal::BluetoothInterface overrides:
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ const bt_interface_t* GetHALInterface() const override;
+ bt_callbacks_t* GetHALCallbacks() const override;
+ const bluetooth_device_t* GetHALAdapter() const override;
+
+ private:
+ base::ObserverList<Observer> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothInterface);
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.cc
new file mode 100755
index 0000000..ea2d2c2
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.cc
@@ -0,0 +1,253 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
+#include "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
+#include "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
+#include "service/ipc/binder/bluetooth_le_scanner_binder_server.h"
+#include "service/ipc/binder/bluetooth_low_energy_binder_server.h"
+
+#include "service/hal/bluetooth_interface.h"
+
+using android::sp;
+using android::String8;
+using android::String16;
+
+using android::bluetooth::IBluetoothCallback;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothGattServer;
+
+namespace ipc {
+namespace binder {
+
+BluetoothBinderServer::BluetoothBinderServer(bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+ adapter_->AddObserver(this);
+}
+
+BluetoothBinderServer::~BluetoothBinderServer() {
+ adapter_->RemoveObserver(this);
+}
+
+// binder::BnBluetooth overrides:
+Status BluetoothBinderServer::IsEnabled(bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->IsEnabled();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetState(int32_t* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->GetState();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::Enable(bool start_restricted,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->Enable(start_restricted);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::EnableNoAutoConnect(bool* _aidl_return) {
+ VLOG(2) << __func__;
+ // TODO(armansito): Implement.
+ *_aidl_return = false;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::Disable(bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->Disable();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetAddress(::android::String16* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = String16(String8(adapter_->GetAddress().c_str()));
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetUUIDs(
+ ::std::vector<::android::bluetooth::UUID>* _aidl_return) {
+ VLOG(2) << __func__;
+ // TODO(armansito): Implement.
+ *_aidl_return = std::vector<android::bluetooth::UUID>();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::SetName(const ::android::String16& name,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->SetName(std::string(String8(name).string()));
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetName(::android::String16* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = String16(String8(adapter_->GetName().c_str()));
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::RegisterCallback(
+ const ::android::sp<IBluetoothCallback>& callback) {
+ VLOG(2) << __func__;
+ if (!callback.get()) {
+ LOG(ERROR) << "RegisterCallback called with NULL binder. Ignoring.";
+ return Status::ok();
+ }
+ callbacks_.Register(callback);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::UnregisterCallback(
+ const ::android::sp<IBluetoothCallback>& callback) {
+ VLOG(2) << __func__;
+ if (!callback.get()) {
+ LOG(ERROR) << "UnregisterCallback called with NULL binder. Ignoring.";
+ return Status::ok();
+ }
+ callbacks_.Unregister(callback);
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::IsMultiAdvertisementSupported(
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ *_aidl_return = adapter_->IsMultiAdvertisementSupported();
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLowEnergyInterface(
+ ::android::sp<IBluetoothLowEnergy>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothLowEnergy interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!low_energy_interface_.get())
+ low_energy_interface_ = new BluetoothLowEnergyBinderServer(adapter_);
+
+ *_aidl_return = low_energy_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLeAdvertiserInterface(
+ ::android::sp<IBluetoothLeAdvertiser>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR)
+ << "Cannot obtain IBluetoothLeAdvertiser interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!le_advertiser_interface_.get())
+ le_advertiser_interface_ = new BluetoothLeAdvertiserBinderServer(adapter_);
+
+ *_aidl_return = le_advertiser_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetLeScannerInterface(
+ ::android::sp<IBluetoothLeScanner>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothLeScanner interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!le_scanner_interface_.get())
+ le_scanner_interface_ = new BluetoothLeScannerBinderServer(adapter_);
+
+ *_aidl_return = le_scanner_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetGattClientInterface(
+ ::android::sp<IBluetoothGattClient>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothGattClient interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!gatt_client_interface_.get())
+ gatt_client_interface_ = new BluetoothGattClientBinderServer(adapter_);
+
+ *_aidl_return = gatt_client_interface_;
+ return Status::ok();
+}
+
+Status BluetoothBinderServer::GetGattServerInterface(
+ ::android::sp<IBluetoothGattServer>* _aidl_return) {
+ VLOG(2) << __func__;
+
+ if (!adapter_->IsEnabled()) {
+ LOG(ERROR) << "Cannot obtain IBluetoothGattServer interface while disabled";
+ *_aidl_return = NULL;
+ return Status::ok();
+ }
+
+ if (!gatt_server_interface_.get())
+ gatt_server_interface_ = new BluetoothGattServerBinderServer(adapter_);
+
+ *_aidl_return = gatt_server_interface_;
+ return Status::ok();
+}
+
+android::status_t BluetoothBinderServer::dump(
+ int fd, const android::Vector<android::String16>& args) {
+ VLOG(2) << __func__ << " called with fd " << fd;
+ if (args.size() > 0) {
+ // TODO (jamuraa): Parse arguments and switch on --proto, --proto_text
+ for (const auto& x : args) {
+ VLOG(2) << __func__ << "argument: " << x.string();
+ }
+ }
+ // TODO (jamuraa): enumerate profiles and dump profile information
+ const bt_interface_t* iface =
+ bluetooth::hal::BluetoothInterface::Get()->GetHALInterface();
+ iface->dump(fd, NULL);
+ return android::NO_ERROR;
+}
+
+void BluetoothBinderServer::OnAdapterStateChanged(
+ bluetooth::Adapter* adapter, bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) {
+ CHECK_EQ(adapter, adapter_);
+ VLOG(2) << "Received adapter state update - prev: " << prev_state
+ << " new: " << new_state;
+ callbacks_.ForEach([prev_state, new_state](IBluetoothCallback* callback) {
+ callback->OnBluetoothStateChange(prev_state, new_state);
+ });
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.h
new file mode 100755
index 0000000..55a3300
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_binder_server.h
@@ -0,0 +1,124 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <android/bluetooth/BnBluetooth.h>
+#include <android/bluetooth/IBluetoothCallback.h>
+#include <android/bluetooth/IBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothGattServer.h>
+#include <android/bluetooth/IBluetoothLeAdvertiser.h>
+#include <android/bluetooth/IBluetoothLeScanner.h>
+#include <android/bluetooth/IBluetoothLowEnergy.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/ipc/binder/remote_callback_list.h"
+
+using android::String16;
+using android::binder::Status;
+
+using android::bluetooth::BnBluetooth;
+using android::bluetooth::IBluetoothCallback;
+using android::bluetooth::IBluetoothGattClient;
+using android::bluetooth::IBluetoothGattServer;
+using android::bluetooth::IBluetoothLowEnergy;
+using android::bluetooth::IBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeScanner;
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetooth Binder interface.
+class BluetoothBinderServer : public BnBluetooth,
+ public bluetooth::Adapter::Observer {
+ public:
+ explicit BluetoothBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothBinderServer() override;
+
+ // IBluetooth overrides:
+ Status IsEnabled(bool* _aidl_return) override;
+ Status GetState(int32_t* _aidl_return) override;
+ Status Enable(bool start_restricted, bool* _aidl_return) override;
+ Status EnableNoAutoConnect(bool* _aidl_return) override;
+ Status Disable(bool* _aidl_return) override;
+
+ Status GetAddress(::android::String16* _aidl_return) override;
+ Status GetUUIDs(
+ ::std::vector<::android::bluetooth::UUID>* _aidl_return) override;
+ Status SetName(const ::android::String16& name, bool* _aidl_return) override;
+ Status GetName(::android::String16* _aidl_return) override;
+
+ Status RegisterCallback(
+ const ::android::sp<IBluetoothCallback>& callback) override;
+ Status UnregisterCallback(
+ const ::android::sp<IBluetoothCallback>& callback) override;
+ Status IsMultiAdvertisementSupported(bool* _aidl_return) override;
+ Status GetLowEnergyInterface(
+ ::android::sp<IBluetoothLowEnergy>* _aidl_return) override;
+ Status GetLeAdvertiserInterface(
+ ::android::sp<IBluetoothLeAdvertiser>* _aidl_return) override;
+ Status GetLeScannerInterface(
+ ::android::sp<IBluetoothLeScanner>* _aidl_return) override;
+ Status GetGattClientInterface(
+ ::android::sp<IBluetoothGattClient>* _aidl_return) override;
+ Status GetGattServerInterface(
+ ::android::sp<IBluetoothGattServer>* _aidl_return) override;
+
+ android::status_t dump(
+ int fd, const android::Vector<android::String16>& args) override;
+
+ // bluetooth::Adapter::Observer overrides:
+ void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) override;
+
+ private:
+ bluetooth::Adapter* adapter_; // weak
+ RemoteCallbackList<IBluetoothCallback> callbacks_;
+
+ // The IBluetoothLowEnergy interface handle. This is lazily initialized on the
+ // first call to GetLowEnergyInterface().
+ android::sp<IBluetoothLowEnergy> low_energy_interface_;
+
+ // The IBluetoothLeAdvertiser interface handle. This is lazily initialized on
+ // the first call to GetLeAdvertiserInterface().
+ android::sp<IBluetoothLeAdvertiser> le_advertiser_interface_;
+
+ // The IBluetoothLeScanner interface handle. This is lazily initialized on the
+ // first call to GetLeScannerInterface().
+ android::sp<IBluetoothLeScanner> le_scanner_interface_;
+
+ // The IBluetoothGattClient interface handle. This is lazily initialized on
+ // the first call to GetGattClientInterface().
+ android::sp<IBluetoothGattClient> gatt_client_interface_;
+
+ // The IBluetoothGattServer interface handle. This is lazily initialized on
+ // the first call to GetGattServerInterface().
+ android::sp<IBluetoothGattServer> gatt_server_interface_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
new file mode 100755
index 0000000..77a5f75
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.cc
@@ -0,0 +1,89 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_gatt_client_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::bluetooth::IBluetoothGattClientCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothGattClientBinderServer::BluetoothGattClientBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+Status BluetoothGattClientBinderServer::RegisterClient(
+ const android::sp<IBluetoothGattClientCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+
+ bluetooth::GattClientFactory* gatt_client_factory =
+ adapter_->GetGattClientFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, gatt_client_factory);
+ return Status::ok();
+}
+
+Status BluetoothGattClientBinderServer::UnregisterClient(int client_id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(client_id);
+ return Status::ok();
+}
+
+Status BluetoothGattClientBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+android::sp<IBluetoothGattClientCallback>
+BluetoothGattClientBinderServer::GetGattClientCallback(int client_id) {
+ auto cb = GetCallback(client_id);
+ return android::sp<IBluetoothGattClientCallback>(
+ static_cast<IBluetoothGattClientCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::GattClient>
+BluetoothGattClientBinderServer::GetGattClient(int client_id) {
+ return std::static_pointer_cast<bluetooth::GattClient>(
+ GetInstance(client_id));
+}
+
+void BluetoothGattClientBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " client ID: " << instance->GetInstanceId()
+ << " status: " << status;
+
+ android::sp<IBluetoothGattClientCallback> cb(
+ static_cast<IBluetoothGattClientCallback*>(callback.get()));
+ cb->OnClientRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h
new file mode 100755
index 0000000..390b0ad
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_client_binder_server.h
@@ -0,0 +1,75 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+
+#include <android/bluetooth/BnBluetoothGattClient.h>
+#include <android/bluetooth/IBluetoothGattClientCallback.h>
+
+#include "service/gatt_client.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+using android::bluetooth::BnBluetoothGattClient;
+using android::bluetooth::IBluetoothGattClientCallback;
+
+using ::android::binder::Status;
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothGattClient interface.
+class BluetoothGattClientBinderServer : public BnBluetoothGattClient,
+ public InterfaceWithInstancesBase {
+ public:
+ explicit BluetoothGattClientBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothGattClientBinderServer() override = default;
+
+ // IBluetoothGattClient overrides:
+ Status RegisterClient(
+ const android::sp<IBluetoothGattClientCallback>& callback,
+ bool* _aidl_return) override;
+ Status UnregisterClient(int client_id) override;
+ Status UnregisterAll() override;
+
+ private:
+ // Returns a pointer to the IBluetoothGattClientCallback instance
+ // associated with |client_id|. Returns NULL if such a callback cannot be
+ // found.
+ android::sp<IBluetoothGattClientCallback> GetGattClientCallback(
+ int client_id);
+
+ // Returns a pointer to the GattClient instance associated with |client_id|.
+ // Returns NULL if such a client cannot be found.
+ std::shared_ptr<bluetooth::GattClient> GetGattClient(int client_id);
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothGattClientBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
new file mode 100755
index 0000000..f0f0717
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.cc
@@ -0,0 +1,309 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_gatt_server_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using ::android::String8;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::android::bluetooth::IBluetoothGattServerCallback;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothGattServerBinderServer::BluetoothGattServerBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+Status BluetoothGattServerBinderServer::RegisterServer(
+ const ::android::sp<IBluetoothGattServerCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ bluetooth::GattServerFactory* gatt_server_factory =
+ adapter_->GetGattServerFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, gatt_server_factory);
+ return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::UnregisterServer(int server_id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(server_id);
+ return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::AddService(
+ int server_id, const android::bluetooth::BluetoothGattService& service,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_server = GetGattServer(server_id);
+ if (!gatt_server) {
+ LOG(ERROR) << "Unknown server_id: " << server_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ // Create a weak pointer and pass that to the callback to prevent a potential
+ // use after free.
+ android::wp<BluetoothGattServerBinderServer> weak_ptr_to_this(this);
+ auto callback = [=](bluetooth::BLEStatus status,
+ const bluetooth::Service& service) {
+ auto sp_to_this = weak_ptr_to_this.promote();
+ if (!sp_to_this.get()) {
+ VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(server_id);
+ if (!gatt_cb.get()) {
+ VLOG(2) << "The callback was deleted";
+ return;
+ }
+
+ gatt_cb->OnServiceAdded(status, service);
+ };
+
+ if (!gatt_server->AddService(service, callback)) {
+ LOG(ERROR) << "Failed to add service";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::SendResponse(
+ int server_id, const String16& device_address, int request_id, int status,
+ int offset, const std::vector<uint8_t>& value, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_server = GetGattServer(server_id);
+ if (!gatt_server) {
+ LOG(ERROR) << "Unknown server_id: " << server_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = gatt_server->SendResponse(
+ std::string(String8(device_address).string()), request_id,
+ static_cast<bluetooth::GATTError>(status), offset, value);
+
+ return Status::ok();
+}
+
+Status BluetoothGattServerBinderServer::SendNotification(
+ int server_id, const String16& device_address, int handle, bool confirm,
+ const std::vector<uint8_t>& value, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_server = GetGattServer(server_id);
+ if (!gatt_server) {
+ LOG(ERROR) << "Unknown server_id: " << server_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ // Create a weak pointer and pass that to the callback to prevent a potential
+ // use after free.
+ android::wp<BluetoothGattServerBinderServer> weak_ptr_to_this(this);
+ auto callback = [=](bluetooth::GATTError error) {
+ auto sp_to_this = weak_ptr_to_this.promote();
+ if (!sp_to_this.get()) {
+ VLOG(2) << "BluetoothLowEnergyBinderServer was deleted";
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(server_id);
+ if (!gatt_cb.get()) {
+ VLOG(2) << "The callback was deleted";
+ return;
+ }
+
+ gatt_cb->OnNotificationSent(device_address, error);
+ };
+
+ if (!gatt_server->SendNotification(
+ std::string(String8(device_address).string()), handle, confirm, value,
+ callback)) {
+ LOG(ERROR) << "Failed to send notification";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+void BluetoothGattServerBinderServer::OnCharacteristicReadRequest(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_long, uint16_t handle) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnCharacteristicReadRequest(
+ String16(device_address.c_str(), device_address.length()), request_id,
+ offset, is_long, handle);
+}
+
+void BluetoothGattServerBinderServer::OnDescriptorReadRequest(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_long, uint16_t handle) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnDescriptorReadRequest(
+ String16(device_address.c_str(), device_address.length()), request_id,
+ offset, is_long, handle);
+}
+
+android::sp<IBluetoothGattServerCallback>
+BluetoothGattServerBinderServer::GetGattServerCallback(int server_id) {
+ auto cb = GetCallback(server_id);
+ return android::sp<IBluetoothGattServerCallback>(
+ static_cast<IBluetoothGattServerCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::GattServer>
+BluetoothGattServerBinderServer::GetGattServer(int server_id) {
+ return std::static_pointer_cast<bluetooth::GattServer>(
+ GetInstance(server_id));
+}
+
+void BluetoothGattServerBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " instance ID: " << instance->GetInstanceId()
+ << " status: " << status;
+ bluetooth::GattServer* gatt_server =
+ static_cast<bluetooth::GattServer*>(instance);
+ gatt_server->SetDelegate(this);
+
+ android::sp<IBluetoothGattServerCallback> cb(
+ static_cast<IBluetoothGattServerCallback*>(callback.get()));
+ cb->OnServerRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+void BluetoothGattServerBinderServer::OnCharacteristicWriteRequest(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, uint16_t handle) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnCharacteristicWriteRequest(
+ String16(device_address.c_str(), device_address.length()), request_id,
+ offset, is_prepare_write, need_response, value, handle);
+}
+
+void BluetoothGattServerBinderServer::OnDescriptorWriteRequest(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ int request_id, int offset, bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value, uint16_t handle) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnDescriptorWriteRequest(
+ String16(device_address.c_str(), device_address.length()), request_id,
+ offset, is_prepare_write, need_response, value, handle);
+}
+
+void BluetoothGattServerBinderServer::OnExecuteWriteRequest(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ int request_id, bool is_execute) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnExecuteWriteRequest(
+ String16(device_address.c_str(), device_address.length()), request_id,
+ is_execute);
+}
+
+void BluetoothGattServerBinderServer::OnConnectionStateChanged(
+ bluetooth::GattServer* gatt_server, const std::string& device_address,
+ bool connected) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto gatt_cb = GetGattServerCallback(gatt_server->GetInstanceId());
+ if (!gatt_cb.get()) {
+ LOG(WARNING) << "Callback for this GattServer was deleted.";
+ return;
+ }
+
+ gatt_cb->OnConnectionStateChanged(
+ String16(device_address.c_str(), device_address.length()), connected);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h
new file mode 100755
index 0000000..8a6dc02
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_gatt_server_binder_server.h
@@ -0,0 +1,117 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+
+#include <android/bluetooth/BnBluetoothGattServer.h>
+#include <android/bluetooth/IBluetoothGattServerCallback.h>
+
+#include "service/gatt_server.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+using android::bluetooth::BnBluetoothGattServer;
+using android::bluetooth::IBluetoothGattServerCallback;
+
+using ::android::binder::Status;
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothGattServer interface.
+class BluetoothGattServerBinderServer : public BnBluetoothGattServer,
+ public InterfaceWithInstancesBase,
+ public bluetooth::GattServer::Delegate {
+ public:
+ explicit BluetoothGattServerBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothGattServerBinderServer() override = default;
+
+ // IBluetoothGattServer overrides:
+ Status RegisterServer(
+ const ::android::sp<::android::bluetooth::IBluetoothGattServerCallback>&
+ callback,
+ bool* _aidl_return) override;
+ Status UnregisterServer(int32_t server_id) override;
+ Status UnregisterAll() override;
+ Status AddService(int32_t server_id,
+ const ::android::bluetooth::BluetoothGattService& service,
+ bool* _aidl_return) override;
+ Status SendResponse(int32_t server_id,
+ const ::android::String16& device_address,
+ int32_t request_id, int32_t status, int32_t offset,
+ const ::std::vector<uint8_t>& value,
+ bool* _aidl_return) override;
+ Status SendNotification(int32_t server_id,
+ const ::android::String16& device_address, int handle,
+ bool confirm, const ::std::vector<uint8_t>& value,
+ bool* _aidl_return) override;
+
+ // bluetooth::GattServer::Delegate overrides:
+ void OnCharacteristicReadRequest(bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_long,
+ uint16_t handle) override;
+ void OnDescriptorReadRequest(bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_long,
+ uint16_t handle) override;
+ void OnCharacteristicWriteRequest(bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ uint16_t handle) override;
+ void OnDescriptorWriteRequest(bluetooth::GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ uint16_t handle) override;
+ void OnExecuteWriteRequest(bluetooth::GattServer* gatt_server,
+ const std::string& device_address, int request_id,
+ bool is_execute) override;
+ void OnConnectionStateChanged(bluetooth::GattServer* gatt_server,
+ const std::string& device_addres,
+ bool connected) override;
+
+ private:
+ // Returns a pointer to the IBluetoothGattServerCallback instance
+ // associated with |server_id|. Returns NULL if such a callback cannot be
+ // found.
+ android::sp<IBluetoothGattServerCallback> GetGattServerCallback(
+ int server_id);
+
+ // Returns a pointer to the GattServer instance associated with |server_id|.
+ // Returns NULL if such an instance cannot be found.
+ std::shared_ptr<bluetooth::GattServer> GetGattServer(int server_id);
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothGattServerBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
new file mode 100755
index 0000000..170e94c
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.cc
@@ -0,0 +1,184 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_le_advertiser_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothLeAdvertiserBinderServer::BluetoothLeAdvertiserBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+BluetoothLeAdvertiserBinderServer::~BluetoothLeAdvertiserBinderServer() {}
+
+Status BluetoothLeAdvertiserBinderServer::RegisterAdvertiser(
+ const android::sp<IBluetoothLeAdvertiserCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ bluetooth::LowEnergyAdvertiserFactory* adv_factory =
+ adapter_->GetLeAdvertiserFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, adv_factory);
+ return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::UnregisterAdvertiser(
+ int advertiser_id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(advertiser_id);
+ return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::StartMultiAdvertising(
+ int advertiser_id, const android::bluetooth::AdvertiseData& advertise_data,
+ const android::bluetooth::AdvertiseData& scan_response,
+ const android::bluetooth::AdvertiseSettings& settings, bool* _aidl_return) {
+ VLOG(2) << __func__ << " advertiser_id: " << advertiser_id;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto advertiser = GetLEAdvertiser(advertiser_id);
+ if (!advertiser) {
+ LOG(ERROR) << "Unknown advertiser_id: " << advertiser_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ // Create a weak pointer and pass that to the callback to prevent a potential
+ // use after free.
+ android::wp<BluetoothLeAdvertiserBinderServer> weak_ptr_to_this(this);
+ auto settings_copy = settings;
+ auto callback = [=](bluetooth::BLEStatus status) {
+ auto sp_to_this = weak_ptr_to_this.promote();
+ if (!sp_to_this.get()) {
+ VLOG(2) << "BluetoothLeAdvertiserBinderServer was deleted";
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto cb = GetLECallback(advertiser_id);
+ if (!cb.get()) {
+ VLOG(1) << "Advertiser was removed before callback: " << advertiser_id;
+ return;
+ }
+
+ cb->OnMultiAdvertiseCallback(status, true /* is_start */, settings_copy);
+ };
+
+ if (!advertiser->StartAdvertising(settings, advertise_data, scan_response,
+ callback)) {
+ LOG(ERROR) << "Failed to initiate call to start advertising";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+Status BluetoothLeAdvertiserBinderServer::StopMultiAdvertising(
+ int advertiser_id, bool* _aidl_return) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto advertiser = GetLEAdvertiser(advertiser_id);
+ if (!advertiser) {
+ LOG(ERROR) << "Unknown advertiser_id: " << advertiser_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ // Create a weak pointer and pass that to the callback to prevent a potential
+ // use after free.
+ android::wp<BluetoothLeAdvertiserBinderServer> weak_ptr_to_this(this);
+ auto settings_copy = advertiser->advertise_settings();
+ auto callback = [=](bluetooth::BLEStatus status) {
+ auto sp_to_this = weak_ptr_to_this.promote();
+ if (!sp_to_this.get()) {
+ VLOG(2) << "BluetoothLeAdvertiserBinderServer was deleted";
+ return;
+ }
+
+ auto cb = GetLECallback(advertiser_id);
+ if (!cb.get()) {
+ VLOG(2) << "Advertiser was unregistered - advertiser_id: "
+ << advertiser_id;
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ cb->OnMultiAdvertiseCallback(status, false /* is_start */, settings_copy);
+ };
+
+ if (!advertiser->StopAdvertising(callback)) {
+ LOG(ERROR) << "Failed to initiate call to start advertising";
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = true;
+ return Status::ok();
+}
+
+android::sp<IBluetoothLeAdvertiserCallback>
+BluetoothLeAdvertiserBinderServer::GetLECallback(int advertiser_id) {
+ auto cb = GetCallback(advertiser_id);
+ return android::sp<IBluetoothLeAdvertiserCallback>(
+ static_cast<IBluetoothLeAdvertiserCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyAdvertiser>
+BluetoothLeAdvertiserBinderServer::GetLEAdvertiser(int advertiser_id) {
+ return std::static_pointer_cast<bluetooth::LowEnergyAdvertiser>(
+ GetInstance(advertiser_id));
+}
+
+void BluetoothLeAdvertiserBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " status: " << status;
+
+ android::sp<IBluetoothLeAdvertiserCallback> cb(
+ static_cast<IBluetoothLeAdvertiserCallback*>(callback.get()));
+ cb->OnAdvertiserRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
new file mode 100755
index 0000000..fc00db5
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_advertiser_binder_server.h
@@ -0,0 +1,85 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLeAdvertiserCallback.h>
+#include "android/bluetooth/BnBluetoothLeAdvertiser.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_advertiser.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLeAdvertiser;
+using android::bluetooth::IBluetoothLeAdvertiserCallback;
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLeAdvertiserBinderServer : public BnBluetoothLeAdvertiser,
+ public InterfaceWithInstancesBase {
+ public:
+ explicit BluetoothLeAdvertiserBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothLeAdvertiserBinderServer() override;
+
+ // IBluetoothLowEnergy overrides:
+ Status RegisterAdvertiser(
+ const android::sp<IBluetoothLeAdvertiserCallback>& callback,
+ bool* _aidl_return) override;
+ Status UnregisterAdvertiser(int advertiser_id) override;
+ Status UnregisterAll() override;
+ Status StartMultiAdvertising(
+ int advertiser_id,
+ const android::bluetooth::AdvertiseData& advertise_data,
+ const android::bluetooth::AdvertiseData& scan_response,
+ const android::bluetooth::AdvertiseSettings& settings,
+ bool* _aidl_return) override;
+ Status StopMultiAdvertising(int advertiser_id, bool* _aidl_return) override;
+
+ private:
+ // Returns a pointer to the IBluetoothLeAdvertiserCallback instance associated
+ // with |advertiser_id|. Returns NULL if such a callback cannot be found.
+ android::sp<IBluetoothLeAdvertiserCallback> GetLECallback(int advertiser_id);
+
+ // Returns a pointer to the LowEnergyAdvertiser instance associated with
+ // |advertiser_id|. Returns NULL if such a advertiser cannot be found.
+ std::shared_ptr<bluetooth::LowEnergyAdvertiser> GetLEAdvertiser(
+ int advertiser_id);
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothLeAdvertiserBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
new file mode 100755
index 0000000..0c20a46
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.cc
@@ -0,0 +1,148 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_le_scanner_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothLeScannerBinderServer::BluetoothLeScannerBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+BluetoothLeScannerBinderServer::~BluetoothLeScannerBinderServer() {}
+
+Status BluetoothLeScannerBinderServer::RegisterScanner(
+ const android::sp<IBluetoothLeScannerCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ bluetooth::LowEnergyScannerFactory* ble_factory =
+ adapter_->GetLeScannerFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, ble_factory);
+ return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::UnregisterScanner(int scanner_id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(scanner_id);
+ return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::StartScan(
+ int scanner_id, const android::bluetooth::ScanSettings& settings,
+ const std::vector<android::bluetooth::ScanFilter>& filters,
+ bool* _aidl_return) {
+ VLOG(2) << __func__ << " scanner_id: " << scanner_id;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto scanner = GetLEScanner(scanner_id);
+ if (!scanner) {
+ LOG(ERROR) << "Unknown scanner_id: " << scanner_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ std::vector<bluetooth::ScanFilter> flt;
+ for (const auto& filter : filters) {
+ flt.push_back(filter);
+ }
+
+ *_aidl_return = scanner->StartScan(settings, flt);
+ return Status::ok();
+}
+
+Status BluetoothLeScannerBinderServer::StopScan(int scanner_id,
+ bool* _aidl_return) {
+ VLOG(2) << __func__ << " scanner_id: " << scanner_id;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto scanner = GetLEScanner(scanner_id);
+ if (!scanner) {
+ LOG(ERROR) << "Unknown scanner_id: " << scanner_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = scanner->StopScan();
+ return Status::ok();
+}
+
+void BluetoothLeScannerBinderServer::OnScanResult(
+ bluetooth::LowEnergyScanner* scanner, const bluetooth::ScanResult& result) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ int scanner_id = scanner->GetInstanceId();
+ auto cb = GetLECallback(scanner->GetInstanceId());
+ if (!cb.get()) {
+ VLOG(2) << "Scanner was unregistered - scanner_id: " << scanner_id;
+ return;
+ }
+
+ cb->OnScanResult(result);
+}
+
+android::sp<IBluetoothLeScannerCallback>
+BluetoothLeScannerBinderServer::GetLECallback(int scanner_id) {
+ auto cb = GetCallback(scanner_id);
+ return android::sp<IBluetoothLeScannerCallback>(
+ static_cast<IBluetoothLeScannerCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyScanner>
+BluetoothLeScannerBinderServer::GetLEScanner(int scanner_id) {
+ return std::static_pointer_cast<bluetooth::LowEnergyScanner>(
+ GetInstance(scanner_id));
+}
+
+void BluetoothLeScannerBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " status: " << status;
+ bluetooth::LowEnergyScanner* le_scanner =
+ static_cast<bluetooth::LowEnergyScanner*>(instance);
+ le_scanner->SetDelegate(this);
+
+ android::sp<IBluetoothLeScannerCallback> cb(
+ static_cast<IBluetoothLeScannerCallback*>(callback.get()));
+ cb->OnScannerRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h
new file mode 100755
index 0000000..ef9a900
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_le_scanner_binder_server.h
@@ -0,0 +1,87 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLeScannerCallback.h>
+#include "android/bluetooth/BnBluetoothLeScanner.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_scanner.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLeScanner;
+using android::bluetooth::IBluetoothLeScannerCallback;
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLeScannerBinderServer
+ : public BnBluetoothLeScanner,
+ public InterfaceWithInstancesBase,
+ public bluetooth::LowEnergyScanner::Delegate {
+ public:
+ explicit BluetoothLeScannerBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothLeScannerBinderServer() override;
+
+ // IBluetoothLowEnergy overrides:
+ Status RegisterScanner(
+ const android::sp<IBluetoothLeScannerCallback>& callback,
+ bool* _aidl_return) override;
+ Status UnregisterScanner(int scanner_id) override;
+ Status UnregisterAll() override;
+ Status StartScan(int scanner_id,
+ const android::bluetooth::ScanSettings& settings,
+ const std::vector<android::bluetooth::ScanFilter>& filters,
+ bool* _aidl_return) override;
+ Status StopScan(int scanner_id, bool* _aidl_return) override;
+
+ void OnScanResult(bluetooth::LowEnergyScanner* scanner,
+ const bluetooth::ScanResult& result) override;
+
+ private:
+ // Returns a pointer to the IBluetoothLowEnergyCallback instance associated
+ // with |scanner_id|. Returns NULL if such a callback cannot be found.
+ android::sp<IBluetoothLeScannerCallback> GetLECallback(int scanner_id);
+
+ // Returns a pointer to the LowEnergyScanner instance associated with
+ // |scanner_id|. Returns NULL if such a scanner cannot be found.
+ std::shared_ptr<bluetooth::LowEnergyScanner> GetLEScanner(int scanner_id);
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothLeScannerBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc b/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc
new file mode 100755
index 0000000..9b8a863
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.cc
@@ -0,0 +1,181 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/bluetooth_low_energy_binder_server.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+
+using android::String8;
+using android::String16;
+using android::binder::Status;
+
+namespace ipc {
+namespace binder {
+
+namespace {
+const int kInvalidInstanceId = -1;
+} // namespace
+
+BluetoothLowEnergyBinderServer::BluetoothLowEnergyBinderServer(
+ bluetooth::Adapter* adapter)
+ : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+BluetoothLowEnergyBinderServer::~BluetoothLowEnergyBinderServer() {}
+
+Status BluetoothLowEnergyBinderServer::RegisterClient(
+ const android::sp<IBluetoothLowEnergyCallback>& callback,
+ bool* _aidl_return) {
+ VLOG(2) << __func__;
+ bluetooth::LowEnergyClientFactory* ble_factory =
+ adapter_->GetLowEnergyClientFactory();
+
+ *_aidl_return = RegisterInstanceBase(callback, ble_factory);
+ return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::UnregisterClient(int client_id) {
+ VLOG(2) << __func__;
+ UnregisterInstanceBase(client_id);
+ return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::UnregisterAll() {
+ VLOG(2) << __func__;
+ UnregisterAllBase();
+ return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::Connect(int client_id,
+ const String16& address,
+ bool is_direct,
+ bool* _aidl_return) {
+ VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address
+ << " is_direct: " << is_direct;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto client = GetLEClient(client_id);
+ if (!client) {
+ LOG(ERROR) << "Unknown client_id: " << client_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return =
+ client->Connect(std::string(String8(address).string()), is_direct);
+ return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::Disconnect(int client_id,
+ const String16& address,
+ bool* _aidl_return) {
+ VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto client = GetLEClient(client_id);
+ if (!client) {
+ LOG(ERROR) << "Unknown client_id: " << client_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = client->Disconnect(std::string(String8(address).string()));
+ return Status::ok();
+}
+
+Status BluetoothLowEnergyBinderServer::SetMtu(int client_id,
+ const String16& address, int mtu,
+ bool* _aidl_return) {
+ VLOG(2) << __func__ << " client_id: " << client_id << " address: " << address
+ << " mtu: " << mtu;
+ std::lock_guard<std::mutex> lock(*maps_lock());
+
+ auto client = GetLEClient(client_id);
+ if (!client) {
+ LOG(ERROR) << "Unknown client_id: " << client_id;
+ *_aidl_return = false;
+ return Status::ok();
+ }
+
+ *_aidl_return = client->SetMtu(std::string(String8(address).string()), mtu);
+ return Status::ok();
+}
+
+void BluetoothLowEnergyBinderServer::OnConnectionState(
+ bluetooth::LowEnergyClient* client, int status, const char* address,
+ bool connected) {
+ VLOG(2) << __func__ << " address: " << address << " connected: " << connected;
+
+ int client_id = client->GetInstanceId();
+ auto cb = GetLECallback(client->GetInstanceId());
+ if (!cb.get()) {
+ VLOG(2) << "Client was unregistered - client_id: " << client_id;
+ return;
+ }
+
+ cb->OnConnectionState(status, client_id,
+ String16(address, std::strlen(address)), connected);
+}
+
+void BluetoothLowEnergyBinderServer::OnMtuChanged(
+ bluetooth::LowEnergyClient* client, int status, const char* address,
+ int mtu) {
+ VLOG(2) << __func__ << " address: " << address << " status: " << status
+ << " mtu: " << mtu;
+
+ int client_id = client->GetInstanceId();
+ auto cb = GetLECallback(client_id);
+ if (!cb.get()) {
+ VLOG(2) << "Client was unregistered - client_id: " << client_id;
+ return;
+ }
+
+ cb->OnMtuChanged(status, String16(address, std::strlen(address)), mtu);
+}
+
+android::sp<IBluetoothLowEnergyCallback>
+BluetoothLowEnergyBinderServer::GetLECallback(int client_id) {
+ auto cb = GetCallback(client_id);
+ return android::sp<IBluetoothLowEnergyCallback>(
+ static_cast<IBluetoothLowEnergyCallback*>(cb.get()));
+}
+
+std::shared_ptr<bluetooth::LowEnergyClient>
+BluetoothLowEnergyBinderServer::GetLEClient(int client_id) {
+ return std::static_pointer_cast<bluetooth::LowEnergyClient>(
+ GetInstance(client_id));
+}
+
+void BluetoothLowEnergyBinderServer::OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) {
+ VLOG(1) << __func__ << " status: " << status;
+ bluetooth::LowEnergyClient* le_client =
+ static_cast<bluetooth::LowEnergyClient*>(instance);
+ le_client->SetDelegate(this);
+
+ android::sp<IBluetoothLowEnergyCallback> cb(
+ static_cast<IBluetoothLowEnergyCallback*>(callback.get()));
+ cb->OnClientRegistered(status, (status == bluetooth::BLE_STATUS_SUCCESS)
+ ? instance->GetInstanceId()
+ : kInvalidInstanceId);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h b/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h
new file mode 100755
index 0000000..d393c7d
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/bluetooth_low_energy_binder_server.h
@@ -0,0 +1,91 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+
+#include <android/bluetooth/IBluetoothLowEnergyCallback.h>
+#include "android/bluetooth/BnBluetoothLowEnergy.h"
+
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/ipc/binder/interface_with_instances_base.h"
+#include "service/low_energy_client.h"
+
+using android::binder::Status;
+using android::String16;
+
+using android::bluetooth::BnBluetoothLowEnergy;
+using android::bluetooth::IBluetoothLowEnergyCallback;
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+namespace binder {
+
+// Implements the server side of the IBluetoothLowEnergy interface.
+class BluetoothLowEnergyBinderServer
+ : public BnBluetoothLowEnergy,
+ public InterfaceWithInstancesBase,
+ public bluetooth::LowEnergyClient::Delegate {
+ public:
+ explicit BluetoothLowEnergyBinderServer(bluetooth::Adapter* adapter);
+ ~BluetoothLowEnergyBinderServer() override;
+
+ // IBluetoothLowEnergy overrides:
+ Status RegisterClient(
+ const android::sp<IBluetoothLowEnergyCallback>& callback,
+ bool* _aidl_return) override;
+ Status UnregisterClient(int client_id) override;
+ Status UnregisterAll() override;
+ Status Connect(int client_id, const String16& address, bool is_direct,
+ bool* _aidl_return) override;
+ Status Disconnect(int client_id, const String16& address,
+ bool* _aidl_return) override;
+ Status SetMtu(int client_id, const String16& address, int mtu,
+ bool* _aidl_return) override;
+
+ // bluetooth::LowEnergyClient::Delegate overrides:
+ void OnConnectionState(bluetooth::LowEnergyClient* client, int status,
+ const char* address, bool connected) override;
+ void OnMtuChanged(bluetooth::LowEnergyClient* client, int status,
+ const char* address, int mtu) override;
+
+ private:
+ // Returns a pointer to the IBluetoothLowEnergyCallback instance associated
+ // with |client_id|. Returns NULL if such a callback cannot be found.
+ android::sp<IBluetoothLowEnergyCallback> GetLECallback(int client_id);
+
+ // Returns a pointer to the LowEnergyClient instance associated with
+ // |client_id|. Returns NULL if such a client cannot be found.
+ std::shared_ptr<bluetooth::LowEnergyClient> GetLEClient(int client_id);
+
+ // InterfaceWithInstancesBase override:
+ void OnRegisterInstanceImpl(bluetooth::BLEStatus status,
+ android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) override;
+
+ bluetooth::Adapter* adapter_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyBinderServer);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.cc b/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.cc
new file mode 100755
index 0000000..18b1eae
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.cc
@@ -0,0 +1,152 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/interface_with_instances_base.h"
+
+#include <base/logging.h>
+
+namespace ipc {
+namespace binder {
+
+bool InterfaceWithInstancesBase::RegisterInstanceBase(
+ const android::sp<IInterface>& callback,
+ bluetooth::BluetoothInstanceFactory* factory) {
+ VLOG(2) << __func__;
+ CHECK(factory);
+
+ if (!callback.get()) {
+ LOG(ERROR) << "Cannot register a NULL callback";
+ return false;
+ }
+
+ // Store the callback in the pending list. It will get removed later when the
+ // stack notifies us asynchronously.
+ bluetooth::UUID app_uuid = bluetooth::UUID::GetRandom();
+ if (!pending_callbacks_.Register(app_uuid, callback)) {
+ LOG(ERROR) << "Failed to store |callback| to map";
+ return false;
+ }
+
+ // Create a weak pointer and pass that to the callback to prevent an invalid
+ // access later. Since this object is managed using Android's StrongPointer
+ // (sp) we are using a wp here rather than std::weak_ptr.
+ android::wp<InterfaceWithInstancesBase> weak_ptr_to_this(this);
+
+ bluetooth::BluetoothInstanceFactory::RegisterCallback cb = [weak_ptr_to_this](
+ bluetooth::BLEStatus status, const bluetooth::UUID& in_uuid,
+ std::unique_ptr<bluetooth::BluetoothInstance> instance) {
+ // If the weak pointer was invalidated then there is nothing we can do.
+ android::sp<InterfaceWithInstancesBase> strong_ptr_to_this =
+ weak_ptr_to_this.promote();
+ if (!strong_ptr_to_this.get()) {
+ VLOG(2) << "InterfaceWithInstancesBase was deleted while instance was"
+ << " being registered";
+ return;
+ }
+
+ strong_ptr_to_this->OnRegisterInstance(status, in_uuid,
+ std::move(instance));
+ };
+
+ if (factory->RegisterInstance(app_uuid, cb)) return true;
+
+ LOG(ERROR) << "Failed to register instance";
+ pending_callbacks_.Remove(app_uuid);
+
+ return false;
+}
+
+void InterfaceWithInstancesBase::UnregisterInstanceBase(int instance_id) {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(maps_lock_);
+
+ id_to_cb_.Remove(instance_id);
+ id_to_instance_.erase(instance_id);
+}
+
+void InterfaceWithInstancesBase::UnregisterAllBase() {
+ VLOG(2) << __func__;
+ std::lock_guard<std::mutex> lock(maps_lock_);
+
+ id_to_cb_.Clear();
+ id_to_instance_.clear();
+}
+
+android::sp<IInterface> InterfaceWithInstancesBase::GetCallback(
+ int instance_id) {
+ return id_to_cb_.Get(instance_id);
+}
+
+std::shared_ptr<bluetooth::BluetoothInstance>
+InterfaceWithInstancesBase::GetInstance(int instance_id) {
+ auto iter = id_to_instance_.find(instance_id);
+ if (iter == id_to_instance_.end())
+ return std::shared_ptr<bluetooth::BluetoothInstance>();
+ return iter->second;
+}
+
+void InterfaceWithInstancesBase::OnRegisterInstance(
+ bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+ std::unique_ptr<bluetooth::BluetoothInstance> instance) {
+ VLOG(2) << __func__ << " - status: " << status;
+
+ // Simply remove the callback from |pending_callbacks_| as it no longer
+ // belongs in there.
+ sp<IInterface> callback = pending_callbacks_.Remove(uuid);
+
+ // |callback| might be NULL if it was removed from the pending list, e.g. the
+ // remote process that owns the callback died.
+ if (!callback.get()) {
+ VLOG(1) << "Callback was removed before the call to \"RegisterInstance\" "
+ << "returned; unregistering instance";
+ return;
+ }
+
+ if (status != bluetooth::BLE_STATUS_SUCCESS) {
+ // The call wasn't successful. Notify the implementation and return.
+ LOG(ERROR) << "Failed to register instance: " << status;
+ OnRegisterInstanceImpl(status, callback, nullptr);
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(maps_lock_);
+ int instance_id = instance->GetInstanceId();
+ if (!id_to_cb_.Register(instance_id, callback, this)) {
+ LOG(ERROR) << "Failed to store callback";
+ OnRegisterInstanceImpl(bluetooth::BLE_STATUS_FAILURE, callback, nullptr);
+ return;
+ }
+
+ VLOG(1) << "Registered BluetoothInstance - ID: " << instance_id;
+
+ auto shared_instance =
+ std::shared_ptr<bluetooth::BluetoothInstance>(instance.release());
+ id_to_instance_[instance_id] = shared_instance;
+
+ OnRegisterInstanceImpl(status, callback, shared_instance.get());
+}
+
+void InterfaceWithInstancesBase::OnRemoteCallbackRemoved(const int& key) {
+ VLOG(2) << __func__ << " instance_id: " << key;
+ std::lock_guard<std::mutex> lock(maps_lock_);
+
+ // No need to remove from the callback map as the entry should be already
+ // removed when this callback gets called.
+ id_to_instance_.erase(key);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.h b/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.h
new file mode 100755
index 0000000..f0aa762
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/interface_with_instances_base.h
@@ -0,0 +1,105 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/ipc/binder/remote_callback_map.h"
+
+namespace ipc {
+namespace binder {
+
+// InterfaceWithInstancesBase provides a common base class for Binder interface
+// servers that involve instance callback Binders registered with an integer
+// instance ID over an asynchronous lower-level stack API. This class abstracts
+// away the common procedures of managing pending callbacks, listening to death
+// notifications, and maintaining multiple internal maps in one common base
+// class.
+// TODO: add code example here.
+class InterfaceWithInstancesBase
+ : public RemoteCallbackMap<int, android::IInterface>::Delegate,
+ virtual public android::RefBase {
+ public:
+ InterfaceWithInstancesBase() = default;
+ ~InterfaceWithInstancesBase() override = default;
+
+ protected:
+ // The initial entry point for registering a instance. Invoke this from the
+ // registration API to add a instance/UUID pair to the pending list and set up
+ // the generic asynchronous callback handler and initiate the process with the
+ // given |factory| instance. Returns false, if there were any errors that
+ // could be synchronously reported.
+ bool RegisterInstanceBase(const android::sp<IInterface>& callback,
+ bluetooth::BluetoothInstanceFactory* factory);
+
+ // Unregister the instance with the given ID, if it was registered before.
+ void UnregisterInstanceBase(int instance_id);
+
+ // Unregisters all registered instances.
+ void UnregisterAllBase();
+
+ // Returns a handle to the lock used to synchronize access to the internal
+ // data structures. Subclasses should acquire this before accessing the maps.
+ std::mutex* maps_lock() { return &maps_lock_; }
+
+ // Returns the callback interface binder that is assigned to the given
+ // instance ID |instance_id|. The returned pointer will contain NULL if an
+ // entry for the given ID cannot be found.
+ android::sp<IInterface> GetCallback(int instance_id);
+
+ // Returns the instance instance that is assigned to the given instance ID
+ // |instance_id|. The returned pointer will contain NULL if an entry for the
+ // given ID cannot be found.
+ std::shared_ptr<bluetooth::BluetoothInstance> GetInstance(int instance_id);
+
+ private:
+ // Base implementation of the register callback.
+ void OnRegisterInstance(
+ bluetooth::BLEStatus status, const bluetooth::UUID& uuid,
+ std::unique_ptr<bluetooth::BluetoothInstance> instance);
+
+ // Called when the callback registration has completed. |instance| is owned by
+ // the base class and should not be deleted by the implementation. If the
+ // operation failed, nullptr will be passed for |instance|.
+ virtual void OnRegisterInstanceImpl(
+ bluetooth::BLEStatus status, android::sp<IInterface> callback,
+ bluetooth::BluetoothInstance* instance) = 0;
+
+ // RemoteCallbackMap<int, IBluetoothLowEnergyCallback>::Delegate override:
+ void OnRemoteCallbackRemoved(const int& key) override;
+
+ // Instances that are pending registration. Once their registration is
+ // complete, the entry will be removed from this map.
+ RemoteCallbackMap<bluetooth::UUID, android::IInterface> pending_callbacks_;
+
+ // We keep two maps here: one from instance_id IDs to callback Binders and one
+ // from instance_id IDs to the BluetoothInstance structures themselves.
+ std::mutex maps_lock_; // Needed for |id_to_instance_|.
+ RemoteCallbackMap<int, IInterface> id_to_cb_;
+ std::unordered_map<int, std::shared_ptr<bluetooth::BluetoothInstance>>
+ id_to_instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(InterfaceWithInstancesBase);
+};
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.cc b/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.cc
new file mode 100755
index 0000000..5b92120
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.cc
@@ -0,0 +1,79 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/ipc_handler_binder.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "service/ipc/binder/bluetooth_binder_server.h"
+
+using android::defaultServiceManager;
+using android::sp;
+using android::status_t;
+using android::String8;
+using android::String16;
+
+namespace ipc {
+
+std::string kServiceName = "bluetooth-service";
+
+IPCHandlerBinder::IPCHandlerBinder(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate) {}
+
+IPCHandlerBinder::~IPCHandlerBinder() {}
+
+bool IPCHandlerBinder::Run() {
+ CHECK(adapter());
+
+ // Register the IBluetooth service with the Android ServiceManager.
+ android::sp<binder::BluetoothBinderServer> bt_server =
+ new binder::BluetoothBinderServer(adapter());
+ status_t status = defaultServiceManager()->addService(
+ String16(String8(kServiceName.c_str())), bt_server);
+ if (status != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to register Bluetooth service with ServiceManager";
+ return false;
+ }
+
+ // Notify the delegate. We do this in the message loop to avoid reentrancy.
+ if (delegate()) {
+ base::MessageLoop::current()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&IPCHandlerBinder::NotifyStarted, this));
+ }
+
+ android::ProcessState::self()->startThreadPool();
+
+ return true;
+}
+
+void IPCHandlerBinder::Stop() {
+ // TODO(armansito): There are several methods in android::IPCThreadState that
+ // are related to shutting down the threadpool, however I haven't been able to
+ // make them shut things down cleanly. Figure out the right way to stop the
+ // Binder IPC here.
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+ if (delegate()) delegate()->OnIPCHandlerStarted(IPCManager::TYPE_BINDER);
+}
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.h b/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.h
new file mode 100755
index 0000000..060548b
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/ipc_handler_binder.h
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace ipc {
+
+// Implements a Binder based IPCHandler.
+class IPCHandlerBinder : public IPCHandler {
+ public:
+ IPCHandlerBinder(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+ ~IPCHandlerBinder() override;
+
+ // IPCHandler overrides:
+ bool Run() override;
+ void Stop() override;
+
+ private:
+ IPCHandlerBinder() = default;
+
+ // Notify the delegate that IPC has started.
+ void NotifyStarted();
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandlerBinder);
+};
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/remote_callback_list.h b/mtkbt/code/bt/service/ipc/binder/remote_callback_list.h
new file mode 100755
index 0000000..e62b7ef
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/remote_callback_list.h
@@ -0,0 +1,205 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace ipc {
+namespace binder {
+
+// Takes care of the grunt work of maintaining a list of remote interfaces,
+// typically for the use of performing registered callbacks from a remote
+// service. This is a native equivalent of the the android.os.RemoteCallbackList
+// Java class. The type "T" must inherit from android::IInterface.
+//
+// TODO(armansito): We need to unit test this class. Right now it's defined as a
+// simple template interface over the native libbinder types directly and we
+// can't compile libbinder for host unless the Binder kernel module is enabled
+// on the system. Figure out whether to:
+// 1) write the Binder test-code in a new target-only executable;
+// 2) conditionally compile into the host-native test suite if the Binder
+// module is built;
+// 3) provide a test-only static library that re-defines the libbinder
+// classes as mocks.
+// (See http://b/23386387)
+//
+// TODO(armansito): We should make this class non-final and the template
+// interface abstract, so that code that depends on this can be unit tested
+// against a mock version of this class.
+//
+// TODO(armansito): Consider submitting this class to frameworks/native/binder.
+template <typename T>
+class RemoteCallbackList final {
+ public:
+ RemoteCallbackList() = default;
+ ~RemoteCallbackList();
+
+ // Register and unregister a callback interface. Registering will
+ // automatically start tracking for death notifications in case the remote
+ // process hosting the Binder dies. In such a case, the Binder is
+ // automatically removed from the list.
+ bool Register(const android::sp<T>& callback);
+ bool Unregister(const android::sp<T>& callback);
+
+ // Calls the given function on each of the contained callbacks. The internal
+ // mutex is locked for the duration of the iteration.
+ void ForEach(const std::function<void(T*)>& callback);
+
+ private:
+ class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ CallbackDeathRecipient(const android::sp<T>& callback,
+ RemoteCallbackList* owner);
+
+ android::sp<T> get_callback() const { return callback_; }
+
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& who) override;
+
+ private:
+ android::sp<T> callback_;
+ RemoteCallbackList<T>* owner_; // weak
+ };
+
+ // Typedef for internal map container. This keeps track of a given Binder and
+ // a death receiver associated with it.
+ using CallbackMap = std::unordered_map<android::IBinder*,
+ android::sp<CallbackDeathRecipient>>;
+
+ bool UnregisterInternal(typename CallbackMap::iterator iter);
+
+ std::mutex map_lock_;
+ CallbackMap callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteCallbackList);
+};
+
+// Template Implementation details below
+// ========================================================
+
+using android::IBinder;
+using android::IInterface;
+using android::sp;
+using android::wp;
+
+template <typename T>
+RemoteCallbackList<T>::~RemoteCallbackList() {
+ std::lock_guard<std::mutex> lock(map_lock_);
+ for (auto iter = callbacks_.begin(); iter != callbacks_.end(); ++iter)
+ UnregisterInternal(iter);
+}
+
+template <typename T>
+bool RemoteCallbackList<T>::Register(const sp<T>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+
+ sp<IBinder> binder = IInterface::asBinder(callback.get());
+ if (callbacks_.find(binder.get()) != callbacks_.end()) {
+ VLOG(1) << "Callback list already contains given callback";
+ return false;
+ }
+
+ sp<CallbackDeathRecipient> dr(new CallbackDeathRecipient(callback, this));
+
+ if (binder->linkToDeath(dr) != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to link death recipient to binder";
+ return false;
+ }
+
+ callbacks_[binder.get()] = dr;
+
+ VLOG(2) << "Callback successfully registered with list";
+
+ return true;
+}
+
+template <typename T>
+bool RemoteCallbackList<T>::Unregister(const sp<T>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+
+ sp<IBinder> binder = IInterface::asBinder(callback.get());
+ auto iter = callbacks_.find(binder.get());
+ if (iter == callbacks_.end()) {
+ VLOG(2) << "Given callback not registered with this list";
+ return false;
+ }
+
+ return UnregisterInternal(iter);
+}
+
+template <typename T>
+void RemoteCallbackList<T>::ForEach(const std::function<void(T*)>& callback) {
+ std::lock_guard<std::mutex> lock(map_lock_);
+ for (const auto& iter : callbacks_)
+ callback(iter.second->get_callback().get());
+}
+
+template <typename T>
+bool RemoteCallbackList<T>::UnregisterInternal(
+ typename CallbackMap::iterator iter) {
+ sp<CallbackDeathRecipient> dr = iter->second;
+ callbacks_.erase(iter);
+
+ if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
+ android::NO_ERROR) {
+ LOG(ERROR) << "Failed to unlink death recipient from binder";
+
+ // We removed the entry from |map_| but unlinkToDeath failed. There isn't
+ // really much we can do here other than deleting the binder and returning
+ // an error.
+ return false;
+ }
+
+ VLOG(2) << "Callback successfully removed from list";
+
+ return true;
+}
+
+template <typename T>
+RemoteCallbackList<T>::CallbackDeathRecipient::CallbackDeathRecipient(
+ const sp<T>& callback, RemoteCallbackList<T>* owner)
+ : callback_(callback), owner_(owner) {
+ CHECK(callback_.get());
+ CHECK(owner_);
+}
+
+template <typename T>
+void RemoteCallbackList<T>::CallbackDeathRecipient::binderDied(
+ const wp<IBinder>& who) {
+ VLOG(1) << "Received binderDied";
+
+ sp<IBinder> binder = IInterface::asBinder(callback_.get());
+ CHECK(who.unsafe_get() == binder.get());
+
+ // Remove the callback but no need to call unlinkToDeath.
+ std::lock_guard<std::mutex> lock(owner_->map_lock_);
+ auto iter = owner_->callbacks_.find(binder.get());
+ CHECK(iter != owner_->callbacks_.end());
+ owner_->callbacks_.erase(iter);
+
+ VLOG(1) << "Callback from dead process unregistered";
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/binder/remote_callback_map.h b/mtkbt/code/bt/service/ipc/binder/remote_callback_map.h
new file mode 100755
index 0000000..b3422ac
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/binder/remote_callback_map.h
@@ -0,0 +1,246 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include <base/logging.h>
+#include <base/macros.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+namespace ipc {
+namespace binder {
+
+// A map of remote interfaces where the value type "V" must inherit from
+// android::IInterface. This is just like RemoteCallbackList except it provides
+// a key-value mapping.
+//
+// TODO(armansito): We should make this class non-final and the template
+// interface abstract, so that code that depends on this can be unit tested
+// against a mock version of this class.
+template <typename K, typename V>
+class RemoteCallbackMap final {
+ public:
+ RemoteCallbackMap() = default;
+ ~RemoteCallbackMap();
+
+ // The Delegate interface is used to notify when a registered callback is
+ // removed from the map as a result of the death of the remote process that
+ // owns the registered callback.
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // Called when a remote callback associated with the key |key| has been
+ // removed. This won't get called if the callback was removed as a result of
+ // a call to RemoteCallbackMap::Unregister.
+ virtual void OnRemoteCallbackRemoved(const K& key) = 0;
+ };
+
+ // Register a callback interface and associate it with the given key.
+ // Registering will automatically start tracking for death notifications in
+ // case the remote process hosting the Binder dies. In such a case, the Binder
+ // is automatically removed from the map.
+ //
+ // An optional |delegate| can be passed which will be assocated with the given
+ // key/value pair. |delegate| must outlive this map.
+ bool Register(const K& key, const android::sp<V>& callback,
+ Delegate* delegate = nullptr);
+
+ // Unregisters a previously registered callback with the given key. Returns
+ // false if |key| doesn't exist.
+ bool Unregister(const K& key);
+
+ // Returns the callback associated with the given key. Returns NULL if |key|
+ // doesn't exist.
+ android::sp<V> Get(const K& key);
+
+ // Removes the callback associated with the given key from the map and returns
+ // the value. Returns NULL if the key doesn't exists.
+ android::sp<V> Remove(const K& key);
+
+ // Clear the contents of the map.
+ void Clear();
+
+ private:
+ class CallbackDeathRecipient : public android::IBinder::DeathRecipient {
+ public:
+ CallbackDeathRecipient(const K& key, const android::sp<V>& callback,
+ RemoteCallbackMap<K, V>* owner, Delegate* delegate);
+
+ android::sp<V> get_callback() const { return callback_; }
+
+ // android::IBinder::DeathRecipient override:
+ void binderDied(const android::wp<android::IBinder>& who) override;
+
+ private:
+ K key_;
+ android::sp<V> callback_;
+ RemoteCallbackMap<K, V>* owner_; // weak
+ Delegate* delegate_; // weak
+ };
+
+ // Typedef for internal map container.
+ using CallbackMap =
+ std::unordered_map<K, android::sp<CallbackDeathRecipient>>;
+
+ bool UnregisterInternal(typename CallbackMap::iterator iter);
+
+ std::mutex map_lock_;
+ CallbackMap map_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteCallbackMap);
+};
+
+// Template Implementation details below
+// ========================================================
+
+using android::IBinder;
+using android::IInterface;
+using android::sp;
+using android::wp;
+using std::lock_guard;
+using std::mutex;
+
+template <typename K, typename V>
+RemoteCallbackMap<K, V>::~RemoteCallbackMap() {
+ Clear();
+}
+
+template <typename K, typename V>
+bool RemoteCallbackMap<K, V>::Register(const K& key, const sp<V>& callback,
+ Delegate* delegate) {
+ lock_guard<mutex> lock(map_lock_);
+
+ if (map_.find(key) != map_.end()) {
+ VLOG(1) << "Callback map already contains key";
+ return false;
+ }
+
+ sp<CallbackDeathRecipient> dr(
+ new CallbackDeathRecipient(key, callback, this, delegate));
+ sp<IBinder> binder = IInterface::asBinder(callback.get());
+ if (binder->linkToDeath(dr) != android::NO_ERROR) {
+ LOG(ERROR) << "Failed to link death recipient to binder";
+ return false;
+ }
+
+ map_[key] = dr;
+
+ VLOG(2) << "Callback successfully registered with map";
+
+ return true;
+}
+
+template <typename K, typename V>
+bool RemoteCallbackMap<K, V>::Unregister(const K& key) {
+ lock_guard<mutex> lock(map_lock_);
+
+ auto iter = map_.find(key);
+ if (iter == map_.end()) {
+ VLOG(1) << "Callback with given key not found";
+ return false;
+ }
+
+ return UnregisterInternal(iter);
+}
+
+template <typename K, typename V>
+sp<V> RemoteCallbackMap<K, V>::Get(const K& key) {
+ lock_guard<mutex> lock(map_lock_);
+
+ auto iter = map_.find(key);
+ if (iter == map_.end()) return nullptr;
+
+ return iter->second->get_callback();
+}
+
+template <typename K, typename V>
+sp<V> RemoteCallbackMap<K, V>::Remove(const K& key) {
+ lock_guard<mutex> lock(map_lock_);
+
+ auto iter = map_.find(key);
+ if (iter == map_.end()) return nullptr;
+
+ sp<V> val = iter->second->get_callback();
+ UnregisterInternal(iter);
+
+ return val;
+}
+template <typename K, typename V>
+void RemoteCallbackMap<K, V>::Clear() {
+ lock_guard<mutex> lock(map_lock_);
+
+ for (auto iter = map_.begin(); iter != map_.end();)
+ UnregisterInternal(iter++);
+}
+
+template <typename K, typename V>
+bool RemoteCallbackMap<K, V>::UnregisterInternal(
+ typename CallbackMap::iterator iter) {
+ sp<CallbackDeathRecipient> dr = iter->second;
+ map_.erase(iter);
+
+ if (IInterface::asBinder(dr->get_callback().get())->unlinkToDeath(dr) !=
+ android::NO_ERROR) {
+ LOG(ERROR) << "Failed to unlink death recipient from binder";
+
+ // We removed the entry from |map_| but unlinkToDeath failed. There isn't
+ // really much we can do here other than deleting the binder and returning
+ // an error.
+ return false;
+ }
+
+ VLOG(2) << "Callback successfully removed from map";
+
+ return true;
+}
+
+template <typename K, typename V>
+RemoteCallbackMap<K, V>::CallbackDeathRecipient::CallbackDeathRecipient(
+ const K& key, const sp<V>& callback, RemoteCallbackMap<K, V>* owner,
+ Delegate* delegate)
+ : key_(key), callback_(callback), owner_(owner), delegate_(delegate) {
+ CHECK(callback_.get());
+}
+
+template <typename K, typename V>
+void RemoteCallbackMap<K, V>::CallbackDeathRecipient::binderDied(
+ const wp<IBinder>& who) {
+ VLOG(1) << "Received binderDied";
+
+ sp<IBinder> binder = IInterface::asBinder(callback_.get());
+ CHECK(who.unsafe_get() == binder.get());
+
+ // Remove the callback but no need to call unlinkToDeath.
+ {
+ lock_guard<mutex> lock(owner_->map_lock_);
+ auto iter = owner_->map_.find(key_);
+ CHECK(iter != owner_->map_.end());
+ owner_->map_.erase(iter);
+ }
+
+ VLOG(1) << "Callback from dead process unregistered; notifying delegate";
+
+ // Notify delegate.
+ if (delegate_) delegate_->OnRemoteCallbackRemoved(key_);
+}
+
+} // namespace binder
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_handler.cc b/mtkbt/code/bt/service/ipc/ipc_handler.cc
new file mode 100755
index 0000000..66d9c03
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_handler.cc
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/ipc_handler.h"
+
+#include <base/logging.h>
+
+namespace ipc {
+
+IPCHandler::IPCHandler(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : adapter_(adapter), delegate_(delegate) {
+ CHECK(adapter_);
+}
+
+IPCHandler::~IPCHandler() {}
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_handler.h b/mtkbt/code/bt/service/ipc/ipc_handler.h
new file mode 100755
index 0000000..b1029ca
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_handler.h
@@ -0,0 +1,62 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+
+#include "service/ipc/ipc_manager.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+// IPCHandler is an interface that classes implementing different IPC mechanisms
+// must conform to.
+class IPCHandler : public base::RefCountedThreadSafe<IPCHandler> {
+ public:
+ IPCHandler(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+ virtual ~IPCHandler();
+
+ // Initializes and runs the IPC mechanism. Returns true on success, false
+ // otherwise.
+ virtual bool Run() = 0;
+
+ // Stops the IPC mechanism.
+ virtual void Stop() = 0;
+
+ protected:
+ // Getters for private members to allow subclasses to access them in read-only
+ // fashion.
+ bluetooth::Adapter* adapter() const { return adapter_; }
+ IPCManager::Delegate* delegate() const { return delegate_; }
+
+ private:
+ IPCHandler() = default;
+
+ // Weak reference to the global Adapter instance.
+ bluetooth::Adapter* adapter_;
+
+ // The delegate that is interested in notifications from us.
+ IPCManager::Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandler);
+};
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_handler_linux.cc b/mtkbt/code/bt/service/ipc/ipc_handler_linux.cc
new file mode 100755
index 0000000..bcd21aa
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_handler_linux.cc
@@ -0,0 +1,207 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/ipc_handler_linux.h"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/bind.h>
+
+#include "osi/include/socket_utils/sockets.h"
+#include "service/daemon.h"
+#include "service/ipc/linux_ipc_host.h"
+#include "service/settings.h"
+
+namespace ipc {
+
+IPCHandlerLinux::IPCHandlerLinux(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate),
+ running_(false),
+ thread_("IPCHandlerLinux"),
+ keep_running_(true) {}
+
+IPCHandlerLinux::~IPCHandlerLinux() {
+ // This will only be set if the Settings::create_ipc_socket_path() was
+ // originally provided.
+ if (!socket_path_.empty()) unlink(socket_path_.value().c_str());
+}
+
+bool IPCHandlerLinux::Run() {
+ CHECK(!running_);
+
+ const std::string& android_suffix =
+ bluetooth::Daemon::Get()->GetSettings()->android_ipc_socket_suffix();
+ const base::FilePath& path =
+ bluetooth::Daemon::Get()->GetSettings()->create_ipc_socket_path();
+
+ // Both flags cannot be set at the same time.
+ CHECK(android_suffix.empty() || path.empty());
+ if (android_suffix.empty() && path.empty()) {
+ LOG(ERROR) << "No domain socket path provided";
+ return false;
+ }
+
+ CHECK(base::MessageLoop::current()); // An origin event loop is required.
+ origin_task_runner_ = base::MessageLoop::current()->task_runner();
+
+ if (!android_suffix.empty()) {
+ int server_fd = osi_android_get_control_socket(android_suffix.c_str());
+ if (server_fd == -1) {
+ LOG(ERROR) << "Unable to get Android socket from: " << android_suffix;
+ return false;
+ }
+ LOG(INFO) << "Binding to Android server socket:" << android_suffix;
+ socket_.reset(server_fd);
+ } else {
+ LOG(INFO) << "Creating a Unix domain socket:" << path.value();
+
+ // TODO(armansito): This is opens the door to potentially unlinking files in
+ // the current directory that we're not supposed to. For now we will have an
+ // assumption that the daemon runs in a sandbox but we should generally do
+ // this properly.
+ unlink(path.value().c_str());
+
+ base::ScopedFD server_socket(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+ if (!server_socket.is_valid()) {
+ LOG(ERROR) << "Failed to open domain socket for IPC";
+ return false;
+ }
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, path.value().c_str(),
+ sizeof(address.sun_path) - 1);
+ if (bind(server_socket.get(), (struct sockaddr*)&address, sizeof(address)) <
+ 0) {
+ LOG(ERROR) << "Failed to bind IPC socket to address: " << strerror(errno);
+ return false;
+ }
+
+ socket_.swap(server_socket);
+ socket_path_ = path;
+ }
+
+ CHECK(socket_.is_valid());
+
+ running_ = true; // Set this here before launching the thread.
+
+ // Start an IO thread and post the listening task.
+ base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+ if (!thread_.StartWithOptions(options)) {
+ LOG(ERROR) << "Failed to start IPCHandlerLinux thread";
+ running_ = false;
+ return false;
+ }
+
+ thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&IPCHandlerLinux::StartListeningOnThread, this));
+
+ return true;
+}
+
+void IPCHandlerLinux::Stop() {
+ keep_running_ = false;
+
+ // At this moment the listening thread might be blocking on the accept
+ // syscall. Shutdown and close the server socket before joining the thread to
+ // interrupt accept so that the main thread doesn't keep blocking.
+ shutdown(socket_.get(), SHUT_RDWR);
+ socket_.reset();
+
+ // Join and clean up the thread.
+ thread_.Stop();
+
+ // Thread exited. Notify the delegate. Post this on the event loop so that the
+ // callback isn't reentrant.
+ NotifyStoppedOnOriginThread();
+}
+
+void IPCHandlerLinux::StartListeningOnThread() {
+ CHECK(socket_.is_valid());
+ CHECK(adapter());
+ CHECK(running_);
+
+ LOG(INFO) << "Listening to incoming connections";
+
+ int status = listen(socket_.get(), SOMAXCONN);
+ if (status < 0) {
+ LOG(ERROR) << "Failed to listen on domain socket: " << strerror(errno);
+ origin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&IPCHandlerLinux::ShutDownOnOriginThread, this));
+ return;
+ }
+
+ NotifyStartedOnOriginThread();
+
+ // TODO(armansito): The code below can cause the daemon to run indefinitely if
+ // the thread is joined while it's in the middle of the EventLoop() call. The
+ // EventLoop() won't exit until a client terminates the connection, however
+ // this can be fixed by using the |thread_|'s MessageLoopForIO instead (since
+ // it gets stopped along with the thread).
+ // TODO(icoolidge): accept simultaneous clients
+ while (keep_running_.load()) {
+ int client_socket = accept4(socket_.get(), nullptr, nullptr, SOCK_NONBLOCK);
+ if (client_socket < 0) {
+ LOG(ERROR) << "Failed to accept client connection: " << strerror(errno);
+ continue;
+ }
+
+ LOG(INFO) << "Established client connection: fd=" << client_socket;
+
+ LinuxIPCHost ipc_host(client_socket, adapter());
+
+ // TODO(armansito): Use |thread_|'s MessageLoopForIO instead of using a
+ // custom event loop to poll from the socket.
+ ipc_host.EventLoop();
+ }
+}
+
+void IPCHandlerLinux::ShutDownOnOriginThread() {
+ LOG(INFO) << "Shutting down IPCHandlerLinux thread";
+ thread_.Stop();
+ running_ = false;
+
+ NotifyStoppedOnCurrentThread();
+}
+
+void IPCHandlerLinux::NotifyStartedOnOriginThread() {
+ if (!delegate()) return;
+
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerLinux::NotifyStartedOnCurrentThread, this));
+}
+
+void IPCHandlerLinux::NotifyStartedOnCurrentThread() {
+ if (delegate()) delegate()->OnIPCHandlerStarted(IPCManager::TYPE_LINUX);
+}
+
+void IPCHandlerLinux::NotifyStoppedOnOriginThread() {
+ if (!delegate()) return;
+
+ origin_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&IPCHandlerLinux::NotifyStoppedOnCurrentThread, this));
+}
+
+void IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
+ if (delegate()) delegate()->OnIPCHandlerStopped(IPCManager::TYPE_LINUX);
+}
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_handler_linux.h b/mtkbt/code/bt/service/ipc/ipc_handler_linux.h
new file mode 100755
index 0000000..b00eb27
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_handler_linux.h
@@ -0,0 +1,89 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <atomic>
+
+#include <base/files/file_path.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/threading/thread.h>
+
+#include "service/ipc/ipc_handler.h"
+#include "service/ipc/ipc_manager.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+} // namespace base
+
+namespace ipc {
+
+// Implements a Linux sequential packet domain-socket based IPCHandler
+class IPCHandlerLinux : public IPCHandler {
+ public:
+ IPCHandlerLinux(bluetooth::Adapter* adapter, IPCManager::Delegate* delegate);
+ ~IPCHandlerLinux() override;
+
+ // IPCHandler overrides:
+ bool Run() override;
+ void Stop() override;
+
+ private:
+ IPCHandlerLinux() = default;
+
+ // Starts listening for incoming connections. Posted on |thread_| by Run().
+ void StartListeningOnThread();
+
+ // Stops the IPC thread. This helper is needed since base::Thread requires
+ // threads to be stopped on the thread that started them.
+ void ShutDownOnOriginThread();
+
+ // Notifies the delegate that we started or stoppedlistening for incoming
+ // connections.
+ void NotifyStartedOnOriginThread();
+ void NotifyStartedOnCurrentThread();
+ void NotifyStoppedOnOriginThread();
+ void NotifyStoppedOnCurrentThread();
+
+// True, if the IPC mechanism is running.
+#if defined(__APPLE__)
+ bool running_ ATTRIBUTE_UNUSED;
+#else
+ bool running_;
+#endif
+
+ // The server socket on which we listen to incoming connections.
+ base::ScopedFD socket_;
+
+ // The file path to |socket_|. This is only set if we create and manage the
+ // life time of the socket.
+ base::FilePath socket_path_;
+
+ // We use a dedicated thread for listening to incoming connections and
+ // polling from the socket to avoid blocking the main thread.
+ base::Thread thread_;
+
+ // Whether or not the listening thread should continue to run.
+ std::atomic<bool> keep_running_;
+
+ // The origin thread's task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCHandlerLinux);
+};
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_manager.cc b/mtkbt/code/bt/service/ipc/ipc_manager.cc
new file mode 100755
index 0000000..74c53bc
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_manager.cc
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/ipc_manager.h"
+
+#if !defined(OS_GENERIC)
+#include "service/ipc/binder/ipc_handler_binder.h"
+#endif // !defined(OS_GENERIC)
+#include "service/ipc/ipc_handler_linux.h"
+
+namespace ipc {
+
+IPCManager::IPCManager(bluetooth::Adapter* adapter) : adapter_(adapter) {
+ CHECK(adapter_);
+}
+
+IPCManager::~IPCManager() {
+ // Don't rely on the handlers getting destroyed since another thread might be
+ // holding a reference to them. Instead, explicitly stop them here.
+ if (BinderStarted()) binder_handler_->Stop();
+ if (LinuxStarted()) linux_handler_->Stop();
+}
+
+bool IPCManager::Start(Type type, Delegate* delegate) {
+ switch (type) {
+ case TYPE_LINUX:
+ if (LinuxStarted()) {
+ LOG(ERROR) << "IPCManagerLinux already started.";
+ return false;
+ }
+
+ linux_handler_ = new IPCHandlerLinux(adapter_, delegate);
+ if (!linux_handler_->Run()) {
+ linux_handler_ = nullptr;
+ return false;
+ }
+ return true;
+#if !defined(OS_GENERIC)
+ case TYPE_BINDER:
+ if (BinderStarted()) {
+ LOG(ERROR) << "IPCManagerBinder already started.";
+ return false;
+ }
+
+ binder_handler_ = new IPCHandlerBinder(adapter_, delegate);
+ if (!binder_handler_->Run()) {
+ binder_handler_ = nullptr;
+ return false;
+ }
+ return true;
+#endif // !defined(OS_GENERIC)
+ default:
+ LOG(ERROR) << "Unsupported IPC type given: " << type;
+ }
+
+ return false;
+}
+
+bool IPCManager::BinderStarted() const { return binder_handler_.get(); }
+
+bool IPCManager::LinuxStarted() const { return linux_handler_.get(); }
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/ipc_manager.h b/mtkbt/code/bt/service/ipc/ipc_manager.h
new file mode 100755
index 0000000..c0ade0e
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/ipc_manager.h
@@ -0,0 +1,100 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <memory>
+
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+class IPCHandler;
+
+// IPCManager is a class for initializing and running supported IPC mechanisms.
+// It manages the life-time of different IPC flavors that are available on the
+// system. There are two flavors: a Linux sequential packet domain socket based
+// system and one based on the Binder-based android.bluetooth framework.
+class IPCManager {
+ public:
+ // Possible IPC types.
+ enum Type {
+ TYPE_LINUX, // IPC based on a Linux sequential packet domain socket
+ TYPE_BINDER // IPC based on the Binder
+ };
+
+ // Interface for observing events from an IPC mechanism. These methods will be
+ // called on the thread that started the particular IPC type.
+ class Delegate {
+ public:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ // Called when an IPC mechanism has successfully started and is ready for
+ // client connections.
+ virtual void OnIPCHandlerStarted(Type type) = 0;
+
+ // Called when an IPC mechanism has stopped. This may happen due to an error
+ // in initialization or due to a regular shut down routine.
+ virtual void OnIPCHandlerStopped(Type type) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ explicit IPCManager(bluetooth::Adapter* adapter);
+ ~IPCManager();
+
+ // Initialize the underlying IPC handler based on |type|, if that type has not
+ // yet been initialized and returns true on success. Returns false if that
+ // type has already been initialized or an error occurs.
+ //
+ // If TYPE_LINUX is given, the file path to use for the domain socket will be
+ // obtained from the global Settings object. Hence, the Settings object must
+ // have been initialized before calling this method.
+ //
+ // |delegate| must out-live the IPCManager and the underlying handler. Users
+ // can guarantee proper clean up by deallocating |delegate| when or after
+ // Delegate::OnIPCHandlerStopped is called. It is safe to destroy |delegate|
+ // after destroying the IPCManager instance, as the destructor will join and
+ // clean up all underlying threads.
+ bool Start(Type type, Delegate* delegate);
+
+ // Returns true if an IPC type has been initialized.
+ bool BinderStarted() const;
+ bool LinuxStarted() const;
+
+ private:
+ IPCManager() = default;
+
+ // Pointers to the different IPC handler classes. These are initialized and
+ // owned by us.
+ scoped_refptr<IPCHandler> binder_handler_;
+ scoped_refptr<IPCHandler> linux_handler_;
+
+ // The Bluetooth adapter instance. This is owned by Daemon so we keep a raw
+ // pointer to it.
+ bluetooth::Adapter* adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCManager);
+};
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/linux_ipc_host.cc b/mtkbt/code/bt/service/ipc/linux_ipc_host.cc
new file mode 100755
index 0000000..7b328cf
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/linux_ipc_host.cc
@@ -0,0 +1,338 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "bt_bluetooth_host"
+
+#include "service/ipc/linux_ipc_host.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include <base/base64.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "service/adapter.h"
+
+using bluetooth::Adapter;
+using bluetooth::UUID;
+
+using namespace bluetooth::gatt;
+
+namespace {
+
+// IPC API is according to:
+// https://docs.google.com/document/d/1eRnku-jAyVU1wGJsLT2CzWi0-8bs2g49s1b3FR_GApM
+const char kSetAdapterNameCommand[] = "set-device-name";
+const char kCreateServiceCommand[] = "create-service";
+const char kDestroyServiceCommand[] = "destroy-service";
+const char kAddCharacteristicCommand[] = "add-characteristic";
+const char kSetCharacteristicValueCommand[] = "set-characteristic-value";
+const char kSetAdvertisementCommand[] = "set-advertisement";
+const char kSetScanResponseCommand[] = "set-scan-response";
+const char kStartServiceCommand[] = "start-service";
+const char kStopServiceCommand[] = "stop-service";
+const char kWriteCharacteristicCommand[] = "write-characteristic";
+
+// Useful values for indexing LinuxIPCHost::pfds_
+// Not super general considering that we should be able to support
+// many GATT FDs owned by one LinuxIPCHost.
+enum {
+ kFdIpc = 0,
+ kFdGatt = 1,
+ kPossibleFds = 2,
+};
+
+bool TokenBool(const std::string& text) { return text == "true"; }
+
+} // namespace
+
+namespace ipc {
+
+LinuxIPCHost::LinuxIPCHost(int sockfd, Adapter* adapter)
+ : adapter_(adapter), pfds_(1, {sockfd, POLLIN, 0}) {}
+
+LinuxIPCHost::~LinuxIPCHost() { close(pfds_[0].fd); }
+
+bool LinuxIPCHost::EventLoop() {
+ while (true) {
+ int status =
+ TEMP_FAILURE_RETRY(ppoll(pfds_.data(), pfds_.size(), nullptr, nullptr));
+ if (status < 1) {
+ LOG_ERROR(LOG_TAG, "ppoll error");
+ return false;
+ }
+
+ if (pfds_[kFdIpc].revents && !OnMessage()) {
+ return false;
+ }
+
+ if (pfds_.size() == kPossibleFds && pfds_[kFdGatt].revents &&
+ !OnGattWrite()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool LinuxIPCHost::OnSetAdapterName(const std::string& name) {
+ std::string decoded_data;
+ base::Base64Decode(name, &decoded_data);
+ return adapter_->SetName(decoded_data);
+}
+
+bool LinuxIPCHost::OnCreateService(const std::string& service_uuid) {
+ gatt_servers_[service_uuid] = std::unique_ptr<Server>(new Server);
+
+ int gattfd;
+ bool status =
+ gatt_servers_[service_uuid]->Initialize(UUID(service_uuid), &gattfd);
+ if (!status) {
+ LOG_ERROR(LOG_TAG, "Failed to initialize bluetooth");
+ return false;
+ }
+ pfds_.resize(kPossibleFds);
+ pfds_[kFdGatt] = {gattfd, POLLIN, 0};
+ return true;
+}
+
+bool LinuxIPCHost::OnDestroyService(const std::string& service_uuid) {
+ gatt_servers_.erase(service_uuid);
+ close(pfds_[1].fd);
+ pfds_.resize(1);
+ return true;
+}
+
+bool LinuxIPCHost::OnAddCharacteristic(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& control_uuid,
+ const std::string& options) {
+ std::vector<std::string> option_tokens = base::SplitString(
+ options, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ int properties_mask = 0;
+ int permissions_mask = 0;
+
+ if (std::find(option_tokens.begin(), option_tokens.end(), "notify") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionRead;
+ properties_mask |= kPropertyRead;
+ properties_mask |= kPropertyNotify;
+ }
+ if (std::find(option_tokens.begin(), option_tokens.end(), "read") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionRead;
+ properties_mask |= kPropertyRead;
+ }
+ if (std::find(option_tokens.begin(), option_tokens.end(), "write") !=
+ option_tokens.end()) {
+ permissions_mask |= kPermissionWrite;
+ properties_mask |= kPropertyWrite;
+ }
+
+ if (control_uuid.empty()) {
+ gatt_servers_[service_uuid]->AddCharacteristic(
+ UUID(characteristic_uuid), properties_mask, permissions_mask);
+ } else {
+ gatt_servers_[service_uuid]->AddBlob(UUID(characteristic_uuid),
+ UUID(control_uuid), properties_mask,
+ permissions_mask);
+ }
+ return true;
+}
+
+bool LinuxIPCHost::OnSetCharacteristicValue(
+ const std::string& service_uuid, const std::string& characteristic_uuid,
+ const std::string& value) {
+ std::string decoded_data;
+ base::Base64Decode(value, &decoded_data);
+ std::vector<uint8_t> blob_data(decoded_data.begin(), decoded_data.end());
+ gatt_servers_[service_uuid]->SetCharacteristicValue(UUID(characteristic_uuid),
+ blob_data);
+ return true;
+}
+
+bool LinuxIPCHost::OnSetAdvertisement(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name) {
+ LOG_INFO(LOG_TAG, "%s: service:%s uuids:%s data:%s", __func__,
+ service_uuid.c_str(), advertise_uuids.c_str(),
+ advertise_data.c_str());
+
+ std::vector<std::string> advertise_uuid_tokens = base::SplitString(
+ advertise_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ // string -> vector<UUID>
+ std::vector<UUID> ids;
+ for (const auto& uuid_token : advertise_uuid_tokens)
+ ids.emplace_back(uuid_token);
+
+ std::string decoded_data;
+ base::Base64Decode(advertise_data, &decoded_data);
+ std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+ decoded_data.end());
+
+ base::Base64Decode(manufacturer_data, &decoded_data);
+ std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+ decoded_data.end());
+
+ gatt_servers_[service_uuid]->SetAdvertisement(ids, decoded_advertise_data,
+ decoded_manufacturer_data,
+ TokenBool(transmit_name));
+ return true;
+}
+
+bool LinuxIPCHost::OnSetScanResponse(const std::string& service_uuid,
+ const std::string& scan_response_uuids,
+ const std::string& scan_response_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name) {
+ std::vector<std::string> scan_response_uuid_tokens = base::SplitString(
+ scan_response_uuids, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+ // string -> vector<UUID>
+ std::vector<UUID> ids;
+ for (const auto& uuid_token : scan_response_uuid_tokens)
+ ids.emplace_back(uuid_token);
+
+ std::string decoded_data;
+ base::Base64Decode(scan_response_data, &decoded_data);
+ std::vector<uint8_t> decoded_advertise_data(decoded_data.begin(),
+ decoded_data.end());
+
+ base::Base64Decode(manufacturer_data, &decoded_data);
+ std::vector<uint8_t> decoded_manufacturer_data(decoded_data.begin(),
+ decoded_data.end());
+
+ gatt_servers_[service_uuid]->SetScanResponse(ids, decoded_advertise_data,
+ decoded_manufacturer_data,
+ TokenBool(transmit_name));
+ return true;
+}
+
+bool LinuxIPCHost::OnStartService(const std::string& service_uuid) {
+ return gatt_servers_[service_uuid]->Start();
+}
+
+bool LinuxIPCHost::OnStopService(const std::string& service_uuid) {
+ return gatt_servers_[service_uuid]->Stop();
+}
+
+bool LinuxIPCHost::OnMessage() {
+ std::string ipc_msg;
+ ssize_t size;
+
+ OSI_NO_INTR(size =
+ recv(pfds_[kFdIpc].fd, &ipc_msg[0], 0, MSG_PEEK | MSG_TRUNC));
+ if (-1 == size) {
+ LOG_ERROR(LOG_TAG, "Error reading datagram size: %s", strerror(errno));
+ return false;
+ } else if (0 == size) {
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+ return false;
+ }
+
+ ipc_msg.resize(size);
+ OSI_NO_INTR(size = read(pfds_[kFdIpc].fd, &ipc_msg[0], ipc_msg.size()));
+ if (-1 == size) {
+ LOG_ERROR(LOG_TAG, "Error reading IPC: %s", strerror(errno));
+ return false;
+ } else if (0 == size) {
+ LOG_INFO(LOG_TAG, "%s:%d: Connection closed", __func__, __LINE__);
+ return false;
+ }
+
+ std::vector<std::string> tokens = base::SplitString(
+ ipc_msg, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ switch (tokens.size()) {
+ case 2:
+ if (tokens[0] == kSetAdapterNameCommand)
+ return OnSetAdapterName(tokens[1]);
+ if (tokens[0] == kCreateServiceCommand) return OnCreateService(tokens[1]);
+ if (tokens[0] == kDestroyServiceCommand)
+ return OnDestroyService(tokens[1]);
+ if (tokens[0] == kStartServiceCommand) return OnStartService(tokens[1]);
+ if (tokens[0] == kStopServiceCommand) return OnStopService(tokens[1]);
+ break;
+ case 4:
+ if (tokens[0] == kSetCharacteristicValueCommand)
+ return OnSetCharacteristicValue(tokens[1], tokens[2], tokens[3]);
+ break;
+ case 5:
+ if (tokens[0] == kAddCharacteristicCommand)
+ return OnAddCharacteristic(tokens[1], tokens[2], tokens[3], tokens[4]);
+ break;
+ case 6:
+ if (tokens[0] == kSetAdvertisementCommand)
+ return OnSetAdvertisement(tokens[1], tokens[2], tokens[3], tokens[4],
+ tokens[5]);
+ if (tokens[0] == kSetScanResponseCommand)
+ return OnSetScanResponse(tokens[1], tokens[2], tokens[3], tokens[4],
+ tokens[5]);
+ break;
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "Malformed IPC message: %s", ipc_msg.c_str());
+ return false;
+}
+
+bool LinuxIPCHost::OnGattWrite() {
+ UUID::UUID128Bit id;
+ ssize_t r;
+
+ OSI_NO_INTR(r = read(pfds_[kFdGatt].fd, id.data(), id.size()));
+ if (r != id.size()) {
+ LOG_ERROR(LOG_TAG, "Error reading GATT attribute ID");
+ return false;
+ }
+
+ std::vector<uint8_t> value;
+ // TODO(icoolidge): Generalize this for multiple clients.
+ auto server = gatt_servers_.begin();
+ server->second->GetCharacteristicValue(UUID(id), &value);
+ const std::string value_string(value.begin(), value.end());
+ std::string encoded_value;
+ base::Base64Encode(value_string, &encoded_value);
+
+ std::string transmit(kWriteCharacteristicCommand);
+ transmit += "|" + server->first;
+ transmit += "|" + base::HexEncode(id.data(), id.size());
+ transmit += "|" + encoded_value;
+
+ OSI_NO_INTR(r = write(pfds_[kFdIpc].fd, transmit.data(), transmit.size()));
+ if (-1 == r) {
+ LOG_ERROR(LOG_TAG, "Error replying to IPC: %s", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/ipc/linux_ipc_host.h b/mtkbt/code/bt/service/ipc/linux_ipc_host.h
new file mode 100755
index 0000000..a51a966
--- a/dev/null
+++ b/mtkbt/code/bt/service/ipc/linux_ipc_host.h
@@ -0,0 +1,107 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#pragma once
+
+#include <poll.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "service/common/bluetooth/uuid.h"
+#include "service/gatt_server_old.h"
+
+namespace bluetooth {
+class Adapter;
+} // namespace bluetooth
+
+namespace ipc {
+
+// This implements a single threaded event loop which dispatches
+// reads from a set of FDs (pfds_) to a set of handlers.
+// Reads from the GATT pipe read end will result in a write to
+// to the IPC socket, and vise versa.
+class LinuxIPCHost {
+ public:
+ // LinuxIPCHost owns the passed sockfd.
+ LinuxIPCHost(int sockfd, bluetooth::Adapter* adapter);
+ ~LinuxIPCHost();
+
+ // Synchronously handle all events on input FDs.
+ bool EventLoop();
+
+ private:
+ // Handler for IPC message receives.
+ // Decodes protocol and dispatches to another handler.
+ bool OnMessage();
+
+ // Handler for GATT characteristic writes.
+ // Encodes to protocol and transmits IPC.
+ bool OnGattWrite();
+
+ // Applies adapter name changes to stack.
+ bool OnSetAdapterName(const std::string& name);
+
+ // Handles service creation.
+ bool OnCreateService(const std::string& service_uuid);
+
+ // Handles service destruction.
+ bool OnDestroyService(const std::string& service_uuid);
+
+ // Creates a characteristic for a service.
+ bool OnAddCharacteristic(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& control_uuid,
+ const std::string& options);
+
+ // Sets the value of a characetistic.
+ bool OnSetCharacteristicValue(const std::string& service_uuid,
+ const std::string& characteristic_uuid,
+ const std::string& value);
+
+ // Applies settings to service advertisement.
+ bool OnSetAdvertisement(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name);
+
+ // Applies settings to scan response.
+ bool OnSetScanResponse(const std::string& service_uuid,
+ const std::string& advertise_uuids,
+ const std::string& advertise_data,
+ const std::string& manufacturer_data,
+ const std::string& transmit_name);
+
+ // Starts service (advertisement and connections)
+ bool OnStartService(const std::string& service_uuid);
+
+ // Stops service.
+ bool OnStopService(const std::string& service_uuid);
+
+ // weak reference.
+ bluetooth::Adapter* adapter_;
+
+ // File descripters that we will block against.
+ std::vector<struct pollfd> pfds_;
+
+ // Container for multiple GATT servers. Currently only one is supported.
+ // TODO(icoolidge): support many to one for real.
+ std::unordered_map<std::string, std::unique_ptr<bluetooth::gatt::Server>>
+ gatt_servers_;
+};
+
+} // namespace ipc
diff --git a/mtkbt/code/bt/service/logging_helpers.cc b/mtkbt/code/bt/service/logging_helpers.cc
new file mode 100755
index 0000000..34e70e4
--- a/dev/null
+++ b/mtkbt/code/bt/service/logging_helpers.cc
@@ -0,0 +1,149 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include "logging_helpers.h"
+
+#include <string.h>
+
+#include <string>
+
+#define CASE_RETURN_TEXT(code) \
+ case code: \
+ return #code
+
+const char* BtAvConnectionStateText(const btav_connection_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTED);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTING);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_CONNECTED);
+ CASE_RETURN_TEXT(BTAV_CONNECTION_STATE_DISCONNECTING);
+ default:
+ return "Invalid AV connection state";
+ }
+}
+
+const char* BtAvAudioStateText(const btav_audio_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_REMOTE_SUSPEND);
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STOPPED);
+ CASE_RETURN_TEXT(BTAV_AUDIO_STATE_STARTED);
+ default:
+ return "Invalid audio state";
+ }
+}
+
+const char* BtTransportText(const btgatt_transport_t t) {
+ switch (t) {
+ CASE_RETURN_TEXT(GATT_TRANSPORT_AUTO);
+ CASE_RETURN_TEXT(GATT_TRANSPORT_BREDR);
+ CASE_RETURN_TEXT(GATT_TRANSPORT_LE);
+ default:
+ return "unknown transport";
+ }
+}
+
+const char* BtStateText(const bt_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BT_STATE_OFF);
+ CASE_RETURN_TEXT(BT_STATE_ON);
+ default:
+ return "unknown state code";
+ }
+}
+
+const char* BtDiscoveryStateText(const bt_discovery_state_t state) {
+ switch (state) {
+ CASE_RETURN_TEXT(BT_DISCOVERY_STOPPED);
+ CASE_RETURN_TEXT(BT_DISCOVERY_STARTED);
+ default:
+ return "unknown discovery state code";
+ }
+}
+
+const char* BtScanModeText(const bt_scan_mode_t mode) {
+ switch (mode) {
+ CASE_RETURN_TEXT(BT_SCAN_MODE_NONE);
+ CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE);
+ CASE_RETURN_TEXT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ default:
+ return "unknown scan mode";
+ }
+}
+
+const char* BtStatusText(const bt_status_t status) {
+ switch (status) {
+ CASE_RETURN_TEXT(BT_STATUS_SUCCESS);
+ CASE_RETURN_TEXT(BT_STATUS_FAIL);
+ CASE_RETURN_TEXT(BT_STATUS_NOT_READY);
+ CASE_RETURN_TEXT(BT_STATUS_NOMEM);
+ CASE_RETURN_TEXT(BT_STATUS_DONE);
+ CASE_RETURN_TEXT(BT_STATUS_BUSY);
+ CASE_RETURN_TEXT(BT_STATUS_UNSUPPORTED);
+ CASE_RETURN_TEXT(BT_STATUS_PARM_INVALID);
+ CASE_RETURN_TEXT(BT_STATUS_UNHANDLED);
+ CASE_RETURN_TEXT(BT_STATUS_AUTH_FAILURE);
+ CASE_RETURN_TEXT(BT_STATUS_RMT_DEV_DOWN);
+ CASE_RETURN_TEXT(BT_STATUS_AUTH_REJECTED);
+ default:
+ return "unknown status code";
+ }
+}
+
+const char* BtPropertyText(const bt_property_type_t prop) {
+ switch (prop) {
+ CASE_RETURN_TEXT(BT_PROPERTY_BDNAME);
+ CASE_RETURN_TEXT(BT_PROPERTY_BDADDR);
+ CASE_RETURN_TEXT(BT_PROPERTY_UUIDS);
+ CASE_RETURN_TEXT(BT_PROPERTY_CLASS_OF_DEVICE);
+ CASE_RETURN_TEXT(BT_PROPERTY_TYPE_OF_DEVICE);
+ CASE_RETURN_TEXT(BT_PROPERTY_SERVICE_RECORD);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_SCAN_MODE);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+ CASE_RETURN_TEXT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_FRIENDLY_NAME);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_RSSI);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_VERSION_INFO);
+ CASE_RETURN_TEXT(BT_PROPERTY_LOCAL_LE_FEATURES);
+ CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
+ default:
+ return "Invalid property";
+ }
+}
+
+const char* BtEventText(const bt_cb_thread_evt evt) {
+ switch (evt) {
+ CASE_RETURN_TEXT(ASSOCIATE_JVM);
+ CASE_RETURN_TEXT(DISASSOCIATE_JVM);
+ default:
+ return "unknown state code";
+ }
+}
+
+const char* BtAclText(const bt_acl_state_t code) {
+ switch (code) {
+ CASE_RETURN_TEXT(BT_ACL_STATE_CONNECTED);
+ CASE_RETURN_TEXT(BT_ACL_STATE_DISCONNECTED);
+ default:
+ return "unknown ACL code";
+ }
+}
+
+std::string BtAddrString(const bt_bdaddr_t* addr) {
+ char buffer[20];
+ snprintf(buffer, sizeof(buffer), "%02X:%02X:%02X:%02X:%02X:%02X",
+ addr->address[0], addr->address[1], addr->address[2],
+ addr->address[3], addr->address[4], addr->address[5]);
+ return std::string(buffer);
+}
diff --git a/mtkbt/code/bt/service/logging_helpers.h b/mtkbt/code/bt/service/logging_helpers.h
new file mode 100755
index 0000000..4462f3e
--- a/dev/null
+++ b/mtkbt/code/bt/service/logging_helpers.h
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#pragma once
+
+#include <string.h>
+
+#include <string>
+
+#include "hardware/bluetooth.h"
+#include "hardware/bt_av.h"
+#include "hardware/bt_gatt_types.h"
+
+const char* BtAvConnectionStateText(const btav_connection_state_t state);
+
+const char* BtAvAudioStateText(const btav_audio_state_t state);
+
+const char* BtTransportText(const btgatt_transport_t t);
+
+const char* BtStateText(const bt_state_t state);
+
+const char* BtDiscoveryStateText(const bt_discovery_state_t);
+
+const char* BtScanModeText(const bt_scan_mode_t mode);
+
+const char* BtStatusText(const bt_status_t status);
+
+const char* BtPropertyText(const bt_property_type_t prop);
+
+const char* BtEventText(const bt_cb_thread_evt evt);
+
+const char* BtAclText(const bt_acl_state_t state);
+
+// TODO(icoolidge): Address object.
+std::string BtAddrString(const bt_bdaddr_t* addr);
diff --git a/mtkbt/code/bt/service/low_energy_advertiser.cc b/mtkbt/code/bt/service/low_energy_advertiser.cc
new file mode 100755
index 0000000..f25d4f9
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_advertiser.cc
@@ -0,0 +1,349 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/low_energy_advertiser.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+BLEStatus GetBLEStatus(int status) {
+ if (status == BT_STATUS_FAIL) return BLE_STATUS_FAILURE;
+
+ return static_cast<BLEStatus>(status);
+}
+
+// The Bluetooth Core Specification defines time interval (e.g. Page Scan
+// Interval, Advertising Interval, etc) units as 0.625 milliseconds (or 1
+// Baseband slot). The HAL advertising functions expect the interval in this
+// unit. This function maps an AdvertiseSettings::Mode value to the
+// corresponding time unit.
+int GetAdvertisingIntervalUnit(AdvertiseSettings::Mode mode) {
+ int ms;
+
+ switch (mode) {
+ case AdvertiseSettings::MODE_BALANCED:
+ ms = kAdvertisingIntervalMediumMs;
+ break;
+ case AdvertiseSettings::MODE_LOW_LATENCY:
+ ms = kAdvertisingIntervalLowMs;
+ break;
+ case AdvertiseSettings::MODE_LOW_POWER:
+ // Fall through
+ default:
+ ms = kAdvertisingIntervalHighMs;
+ break;
+ }
+
+ // Convert milliseconds to Bluetooth units.
+ return (ms * 1000) / 625;
+}
+
+int8_t GetAdvertisingTxPower(AdvertiseSettings::TxPowerLevel tx_power) {
+ int8_t power;
+
+ switch (tx_power) {
+ case AdvertiseSettings::TX_POWER_LEVEL_ULTRA_LOW:
+ power = -21;
+ break;
+ case AdvertiseSettings::TX_POWER_LEVEL_LOW:
+ power = -15;
+ break;
+ case AdvertiseSettings::TX_POWER_LEVEL_MEDIUM:
+ power = -7;
+ break;
+ case AdvertiseSettings::TX_POWER_LEVEL_HIGH:
+ // Fall through
+ default:
+ power = 1;
+ break;
+ }
+
+ return power;
+}
+
+void GetAdvertiseParams(const AdvertiseSettings& settings, bool has_scan_rsp,
+ AdvertiseParameters* out_params) {
+ CHECK(out_params);
+
+ out_params->min_interval = GetAdvertisingIntervalUnit(settings.mode());
+ out_params->max_interval =
+ out_params->min_interval + kAdvertisingIntervalDeltaUnit;
+
+ if (settings.connectable())
+ out_params->advertising_event_properties =
+ kAdvertisingEventTypeLegacyConnectable;
+ else if (has_scan_rsp)
+ out_params->advertising_event_properties =
+ kAdvertisingEventTypeLegacyScannable;
+ else
+ out_params->advertising_event_properties =
+ kAdvertisingEventTypeLegacyNonConnectable;
+
+ out_params->channel_map = kAdvertisingChannelAll;
+ out_params->tx_power = GetAdvertisingTxPower(settings.tx_power_level());
+
+ // TODO: expose those new setting through AdvertiseSettings
+ out_params->primary_advertising_phy = 0x01;
+ out_params->secondary_advertising_phy = 0x01;
+ out_params->scan_request_notification_enable = 0;
+}
+
+void DoNothing(uint8_t status) {}
+
+} // namespace
+
+// LowEnergyAdvertiser implementation
+// ========================================================
+
+LowEnergyAdvertiser::LowEnergyAdvertiser(const UUID& uuid, int advertiser_id)
+ : app_identifier_(uuid),
+ advertiser_id_(advertiser_id),
+ adv_started_(false),
+ adv_start_callback_(nullptr),
+ adv_stop_callback_(nullptr) {}
+
+LowEnergyAdvertiser::~LowEnergyAdvertiser() {
+ // Automatically unregister the advertiser.
+ VLOG(1) << "LowEnergyAdvertiser unregistering advertiser: " << advertiser_id_;
+
+ // Stop advertising and ignore the result.
+ hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface()->Enable(
+ advertiser_id_, false, base::Bind(&DoNothing), 0, 0,
+ base::Bind(&DoNothing));
+ hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface()->Unregister(
+ advertiser_id_);
+}
+
+bool LowEnergyAdvertiser::StartAdvertising(const AdvertiseSettings& settings,
+ const AdvertiseData& advertise_data,
+ const AdvertiseData& scan_response,
+ const StatusCallback& callback) {
+ VLOG(2) << __func__;
+ lock_guard<mutex> lock(adv_fields_lock_);
+
+ if (IsAdvertisingStarted()) {
+ LOG(WARNING) << "Already advertising";
+ return false;
+ }
+
+ if (IsStartingAdvertising()) {
+ LOG(WARNING) << "StartAdvertising already pending";
+ return false;
+ }
+
+ if (!advertise_data.IsValid()) {
+ LOG(ERROR) << "Invalid advertising data";
+ return false;
+ }
+
+ if (!scan_response.IsValid()) {
+ LOG(ERROR) << "Invalid scan response data";
+ return false;
+ }
+
+ advertise_settings_ = settings;
+
+ AdvertiseParameters params;
+ GetAdvertiseParams(settings, !scan_response.data().empty(), &params);
+
+ hal::BluetoothGattInterface::Get()
+ ->GetAdvertiserHALInterface()
+ ->StartAdvertising(
+ advertiser_id_,
+ base::Bind(&LowEnergyAdvertiser::EnableCallback,
+ base::Unretained(this), true, advertiser_id_),
+ params, advertise_data.data(), scan_response.data(),
+ settings.timeout().InSeconds(),
+ base::Bind(&LowEnergyAdvertiser::EnableCallback,
+ base::Unretained(this), false, advertiser_id_));
+ ;
+
+ adv_start_callback_.reset(new StatusCallback(callback));
+ return true;
+}
+
+bool LowEnergyAdvertiser::StopAdvertising(const StatusCallback& callback) {
+ VLOG(2) << __func__;
+ lock_guard<mutex> lock(adv_fields_lock_);
+
+ if (!IsAdvertisingStarted()) {
+ LOG(ERROR) << "Not advertising";
+ return false;
+ }
+
+ if (IsStoppingAdvertising()) {
+ LOG(ERROR) << "StopAdvertising already pending";
+ return false;
+ }
+
+ hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface()->Enable(
+ advertiser_id_, false,
+ base::Bind(&LowEnergyAdvertiser::EnableCallback, base::Unretained(this),
+ false, advertiser_id_),
+ 0, 0, base::Bind(&LowEnergyAdvertiser::EnableCallback,
+ base::Unretained(this), false, advertiser_id_));
+
+ // OK to set this at the end since we're still holding |adv_fields_lock_|.
+ adv_stop_callback_.reset(new StatusCallback(callback));
+
+ return true;
+}
+
+bool LowEnergyAdvertiser::IsAdvertisingStarted() const {
+ return adv_started_.load();
+}
+
+bool LowEnergyAdvertiser::IsStartingAdvertising() const {
+ return !IsAdvertisingStarted() && adv_start_callback_;
+}
+
+bool LowEnergyAdvertiser::IsStoppingAdvertising() const {
+ return IsAdvertisingStarted() && adv_stop_callback_;
+}
+
+const UUID& LowEnergyAdvertiser::GetAppIdentifier() const {
+ return app_identifier_;
+}
+
+int LowEnergyAdvertiser::GetInstanceId() const { return advertiser_id_; }
+
+void LowEnergyAdvertiser::EnableCallback(bool enable, uint8_t advertiser_id,
+ uint8_t status) {
+ if (advertiser_id != advertiser_id_) return;
+
+ lock_guard<mutex> lock(adv_fields_lock_);
+
+ VLOG(1) << __func__ << "advertiser_id: " << advertiser_id
+ << " status: " << status << " enable: " << enable;
+
+ if (enable) {
+ CHECK(adv_start_callback_);
+ CHECK(!adv_stop_callback_);
+
+ // Terminate operation in case of error.
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to enable multi-advertising";
+ InvokeAndClearStartCallback(GetBLEStatus(status));
+ return;
+ }
+
+ // All pending tasks are complete. Report success.
+ adv_started_ = true;
+ InvokeAndClearStartCallback(BLE_STATUS_SUCCESS);
+
+ } else {
+ CHECK(!adv_start_callback_);
+ CHECK(adv_stop_callback_);
+
+ if (status == BT_STATUS_SUCCESS) {
+ VLOG(1) << "Multi-advertising stopped for advertiser_id: "
+ << advertiser_id;
+ adv_started_ = false;
+ } else {
+ LOG(ERROR) << "Failed to stop multi-advertising";
+ }
+
+ InvokeAndClearStopCallback(GetBLEStatus(status));
+ }
+}
+
+void LowEnergyAdvertiser::InvokeAndClearStartCallback(BLEStatus status) {
+ // We allow NULL callbacks.
+ if (*adv_start_callback_) (*adv_start_callback_)(status);
+
+ adv_start_callback_ = nullptr;
+}
+
+void LowEnergyAdvertiser::InvokeAndClearStopCallback(BLEStatus status) {
+ // We allow NULL callbacks.
+ if (*adv_stop_callback_) (*adv_stop_callback_)(status);
+
+ adv_stop_callback_ = nullptr;
+}
+
+// LowEnergyAdvertiserFactory implementation
+// ========================================================
+
+LowEnergyAdvertiserFactory::LowEnergyAdvertiserFactory() {}
+
+LowEnergyAdvertiserFactory::~LowEnergyAdvertiserFactory() {}
+
+bool LowEnergyAdvertiserFactory::RegisterInstance(
+ const UUID& app_uuid, const RegisterCallback& callback) {
+ VLOG(1) << __func__;
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ if (pending_calls_.find(app_uuid) != pending_calls_.end()) {
+ LOG(ERROR) << "Low-Energy advertiser with given UUID already registered - "
+ << "UUID: " << app_uuid.ToString();
+ return false;
+ }
+
+ BleAdvertiserInterface* hal_iface =
+ hal::BluetoothGattInterface::Get()->GetAdvertiserHALInterface();
+
+ VLOG(1) << __func__ << " calling register!";
+ hal_iface->RegisterAdvertiser(
+ base::Bind(&LowEnergyAdvertiserFactory::RegisterAdvertiserCallback,
+ base::Unretained(this), callback, app_uuid));
+ VLOG(1) << __func__ << " call finished!";
+
+ pending_calls_.insert(app_uuid);
+
+ return true;
+}
+
+void LowEnergyAdvertiserFactory::RegisterAdvertiserCallback(
+ const RegisterCallback& callback, const UUID& app_uuid,
+ uint8_t advertiser_id, uint8_t status) {
+ VLOG(1) << __func__;
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ auto iter = pending_calls_.find(app_uuid);
+ if (iter == pending_calls_.end()) {
+ VLOG(1) << "Ignoring callback for unknown app_id: " << app_uuid.ToString();
+ return;
+ }
+
+ // No need to construct a advertiser if the call wasn't successful.
+ std::unique_ptr<LowEnergyAdvertiser> advertiser;
+ BLEStatus result = BLE_STATUS_FAILURE;
+ if (status == BT_STATUS_SUCCESS) {
+ advertiser.reset(new LowEnergyAdvertiser(app_uuid, advertiser_id));
+
+ result = BLE_STATUS_SUCCESS;
+ }
+
+ // Notify the result via the result callback.
+ callback(result, app_uuid, std::move(advertiser));
+
+ pending_calls_.erase(iter);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/low_energy_advertiser.h b/mtkbt/code/bt/service/low_energy_advertiser.h
new file mode 100755
index 0000000..a014ae1
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_advertiser.h
@@ -0,0 +1,145 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/advertise_data.h"
+#include "service/common/bluetooth/advertise_settings.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+class Adapter;
+
+// A LowEnergyAdvertiser represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyAdvertiser : public BluetoothInstance {
+ public:
+ // The destructor automatically unregisters this client instance from the
+ // stack.
+ ~LowEnergyAdvertiser() override;
+
+ // Callback type used to return the result of asynchronous operations below.
+ using StatusCallback = std::function<void(BLEStatus)>;
+
+ // Starts advertising based on the given advertising and scan response
+ // data and the provided |settings|. Reports the result of the operation in
+ // |callback|. Return true on success, false otherwise. Please see logs for
+ // details in case of error.
+ bool StartAdvertising(const AdvertiseSettings& settings,
+ const AdvertiseData& advertise_data,
+ const AdvertiseData& scan_response,
+ const StatusCallback& callback);
+
+ // Stops advertising if it was already started. Reports the result of the
+ // operation in |callback|.
+ bool StopAdvertising(const StatusCallback& callback);
+
+ // Returns true if advertising has been started.
+ bool IsAdvertisingStarted() const;
+
+ // Returns the state of pending advertising operations.
+ bool IsStartingAdvertising() const;
+ bool IsStoppingAdvertising() const;
+
+ // Returns the current advertising settings.
+ const AdvertiseSettings& advertise_settings() const {
+ return advertise_settings_;
+ }
+
+ // BluetoothClientInstace overrides:
+ const UUID& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ private:
+ friend class LowEnergyAdvertiserFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ LowEnergyAdvertiser(const UUID& uuid, int advertiser_id);
+
+ // BluetoothGattInterface::AdvertiserObserver overrides:
+ void SetDataCallback(uint8_t advertiser_id, uint8_t status);
+ void SetParamsCallback(uint8_t advertiser_id, uint8_t status);
+ void EnableCallback(bool enable, uint8_t advertiser_id, uint8_t status);
+
+ // Calls and clears the pending callbacks.
+ void InvokeAndClearStartCallback(BLEStatus status);
+ void InvokeAndClearStopCallback(BLEStatus status);
+
+ // See getters above for documentation.
+ UUID app_identifier_;
+ int advertiser_id_;
+
+ // Protects advertising-related members below.
+ std::mutex adv_fields_lock_;
+
+ // Latest advertising settings.
+ AdvertiseSettings advertise_settings_;
+
+ std::atomic_bool adv_started_;
+ std::unique_ptr<StatusCallback> adv_start_callback_;
+ std::unique_ptr<StatusCallback> adv_stop_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiser);
+};
+
+// LowEnergyAdvertiserFactory is used to register and obtain a per-application
+// LowEnergyAdvertiser instance. Users should call RegisterInstance to obtain
+// their
+// own unique LowEnergyAdvertiser instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyAdvertiserFactory : public BluetoothInstanceFactory {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ explicit LowEnergyAdvertiserFactory();
+ ~LowEnergyAdvertiserFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const UUID& app_uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ friend class LowEnergyAdvertiser;
+
+ // BluetoothGattInterface::AdvertiserObserver overrides:
+ void RegisterAdvertiserCallback(const RegisterCallback& callback,
+ const UUID& app_uuid, uint8_t advertiser_id,
+ uint8_t status);
+
+ // Map of pending calls to register.
+ std::mutex pending_calls_lock_;
+ std::unordered_set<UUID> pending_calls_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/low_energy_client.cc b/mtkbt/code/bt/service/low_energy_client.cc
new file mode 100755
index 0000000..1e2d7f3
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_client.cc
@@ -0,0 +1,261 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/low_energy_client.h"
+
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+// LowEnergyClient implementation
+// ========================================================
+
+LowEnergyClient::LowEnergyClient(Adapter& adapter, const UUID& uuid,
+ int client_id)
+ : adapter_(adapter),
+ app_identifier_(uuid),
+ client_id_(client_id),
+ delegate_(nullptr) {}
+
+LowEnergyClient::~LowEnergyClient() {
+ // Automatically unregister the client.
+ VLOG(1) << "LowEnergyClient unregistering client: " << client_id_;
+
+ // Unregister as observer so we no longer receive any callbacks.
+ hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+
+ hal::BluetoothGattInterface::Get()
+ ->GetClientHALInterface()
+ ->unregister_client(client_id_);
+}
+
+bool LowEnergyClient::Connect(const std::string& address, bool is_direct) {
+ VLOG(2) << __func__ << "Address: " << address << " is_direct: " << is_direct;
+
+ bt_bdaddr_t bda;
+ util::BdAddrFromString(address, &bda);
+
+ bt_status_t status =
+ hal::BluetoothGattInterface::Get()->GetClientHALInterface()->connect(
+ client_id_, &bda, is_direct, BT_TRANSPORT_LE, PHY_LE_1M_MASK);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "HAL call to connect failed";
+ return false;
+ }
+
+ return true;
+}
+
+bool LowEnergyClient::Disconnect(const std::string& address) {
+ VLOG(2) << __func__ << "Address: " << address;
+
+ bt_bdaddr_t bda;
+ util::BdAddrFromString(address, &bda);
+
+ std::map<const bt_bdaddr_t, int>::iterator conn_id;
+ {
+ lock_guard<mutex> lock(connection_fields_lock_);
+ conn_id = connection_ids_.find(bda);
+ if (conn_id == connection_ids_.end()) {
+ LOG(WARNING) << "Can't disconnect, no existing connection to " << address;
+ return false;
+ }
+ }
+
+ bt_status_t status =
+ hal::BluetoothGattInterface::Get()->GetClientHALInterface()->disconnect(
+ client_id_, &bda, conn_id->second);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "HAL call to disconnect failed";
+ return false;
+ }
+
+ return true;
+}
+
+bool LowEnergyClient::SetMtu(const std::string& address, int mtu) {
+ VLOG(2) << __func__ << "Address: " << address << " MTU: " << mtu;
+
+ bt_bdaddr_t bda;
+ util::BdAddrFromString(address, &bda);
+
+ std::map<const bt_bdaddr_t, int>::iterator conn_id;
+ {
+ lock_guard<mutex> lock(connection_fields_lock_);
+ conn_id = connection_ids_.find(bda);
+ if (conn_id == connection_ids_.end()) {
+ LOG(WARNING) << "Can't set MTU, no existing connection to " << address;
+ return false;
+ }
+ }
+
+ bt_status_t status = hal::BluetoothGattInterface::Get()
+ ->GetClientHALInterface()
+ ->configure_mtu(conn_id->second, mtu);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "HAL call to set MTU failed";
+ return false;
+ }
+
+ return true;
+}
+
+void LowEnergyClient::SetDelegate(Delegate* delegate) {
+ lock_guard<mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+const UUID& LowEnergyClient::GetAppIdentifier() const {
+ return app_identifier_;
+}
+
+int LowEnergyClient::GetInstanceId() const { return client_id_; }
+
+void LowEnergyClient::ConnectCallback(hal::BluetoothGattInterface* gatt_iface,
+ int conn_id, int status, int client_id,
+ const bt_bdaddr_t& bda) {
+ if (client_id != client_id_) return;
+
+ VLOG(1) << __func__ << "client_id: " << client_id << " status: " << status;
+
+ {
+ lock_guard<mutex> lock(connection_fields_lock_);
+ auto success = connection_ids_.emplace(bda, conn_id);
+ if (!success.second) {
+ LOG(ERROR) << __func__ << " Insertion into connection_ids_ failed!";
+ }
+ }
+
+ if (delegate_)
+ delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
+ true);
+}
+
+void LowEnergyClient::DisconnectCallback(
+ hal::BluetoothGattInterface* gatt_iface, int conn_id, int status,
+ int client_id, const bt_bdaddr_t& bda) {
+ if (client_id != client_id_) return;
+
+ VLOG(1) << __func__ << " client_id: " << client_id << " status: " << status;
+ {
+ lock_guard<mutex> lock(connection_fields_lock_);
+ if (!connection_ids_.erase(bda)) {
+ LOG(ERROR) << __func__ << " Erasing from connection_ids_ failed!";
+ }
+ }
+
+ if (delegate_)
+ delegate_->OnConnectionState(this, status, BtAddrString(&bda).c_str(),
+ false);
+}
+
+void LowEnergyClient::MtuChangedCallback(
+ hal::BluetoothGattInterface* gatt_iface, int conn_id, int status, int mtu) {
+ VLOG(1) << __func__ << " conn_id: " << conn_id << " status: " << status
+ << " mtu: " << mtu;
+
+ const bt_bdaddr_t* bda = nullptr;
+ {
+ lock_guard<mutex> lock(connection_fields_lock_);
+ for (auto& connection : connection_ids_) {
+ if (connection.second == conn_id) {
+ bda = &connection.first;
+ break;
+ }
+ }
+ }
+
+ if (!bda) return;
+
+ const char* addr = BtAddrString(bda).c_str();
+ if (delegate_) delegate_->OnMtuChanged(this, status, addr, mtu);
+}
+
+// LowEnergyClientFactory implementation
+// ========================================================
+
+LowEnergyClientFactory::LowEnergyClientFactory(Adapter& adapter)
+ : adapter_(adapter) {
+ hal::BluetoothGattInterface::Get()->AddClientObserver(this);
+}
+
+LowEnergyClientFactory::~LowEnergyClientFactory() {
+ hal::BluetoothGattInterface::Get()->RemoveClientObserver(this);
+}
+
+bool LowEnergyClientFactory::RegisterInstance(
+ const UUID& uuid, const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ if (pending_calls_.find(uuid) != pending_calls_.end()) {
+ LOG(ERROR) << "Low-Energy client with given UUID already registered - "
+ << "UUID: " << uuid.ToString();
+ return false;
+ }
+
+ const btgatt_client_interface_t* hal_iface =
+ hal::BluetoothGattInterface::Get()->GetClientHALInterface();
+ bt_uuid_t app_uuid = uuid.GetBlueDroid();
+
+ if (hal_iface->register_client(&app_uuid) != BT_STATUS_SUCCESS) return false;
+
+ pending_calls_[uuid] = callback;
+
+ return true;
+}
+
+void LowEnergyClientFactory::RegisterClientCallback(
+ hal::BluetoothGattInterface* gatt_iface, int status, int client_id,
+ const bt_uuid_t& app_uuid) {
+ UUID uuid(app_uuid);
+
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ auto iter = pending_calls_.find(uuid);
+ if (iter == pending_calls_.end()) {
+ VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+ return;
+ }
+
+ // No need to construct a client if the call wasn't successful.
+ std::unique_ptr<LowEnergyClient> client;
+ BLEStatus result = BLE_STATUS_FAILURE;
+ if (status == BT_STATUS_SUCCESS) {
+ client.reset(new LowEnergyClient(adapter_, uuid, client_id));
+
+ gatt_iface->AddClientObserver(client.get());
+
+ result = BLE_STATUS_SUCCESS;
+ }
+
+ // Notify the result via the result callback.
+ iter->second(result, uuid, std::move(client));
+
+ pending_calls_.erase(iter);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/low_energy_client.h b/mtkbt/code/bt/service/low_energy_client.h
new file mode 100755
index 0000000..d9b1d37
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_client.h
@@ -0,0 +1,175 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+struct ConnComparator {
+ bool operator()(const bt_bdaddr_t& a, const bt_bdaddr_t& b) const {
+ return memcmp(&a, &b, sizeof(bt_bdaddr_t)) < 0;
+ }
+};
+
+class Adapter;
+
+// A LowEnergyClient represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyClient : private hal::BluetoothGattInterface::ClientObserver,
+ public BluetoothInstance {
+ public:
+ // The Delegate interface is used to notify asynchronous events related to BLE
+ // GAP operations.
+ class Delegate {
+ public:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ // Called asynchronously to notify the delegate of connection state change
+ virtual void OnConnectionState(LowEnergyClient* client, int status,
+ const char* address, bool connected) = 0;
+
+ // Called asynchronously to notify the delegate of mtu change
+ virtual void OnMtuChanged(LowEnergyClient* client, int status,
+ const char* address, int mtu) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ // The destructor automatically unregisters this client instance from the
+ // stack.
+ ~LowEnergyClient() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // LowEnergyClient instance.
+ void SetDelegate(Delegate* delegate);
+
+ // Callback type used to return the result of asynchronous operations below.
+ using StatusCallback = std::function<void(BLEStatus)>;
+
+ // Initiates a BLE connection do device with address |address|. If
+ // |is_direct| is set, use direct connect procedure. Return true on success
+ //, false otherwise.
+ bool Connect(const std::string& address, bool is_direct);
+
+ // Disconnect from previously connected BLE device with address |address|.
+ // Return true on success, false otherwise.
+ bool Disconnect(const std::string& address);
+
+ // Sends request to set MTU to |mtu| for device with address |address|.
+ // Return true on success, false otherwise.
+ bool SetMtu(const std::string& address, int mtu);
+
+ // BluetoothClientInstace overrides:
+ const UUID& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ private:
+ friend class LowEnergyClientFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ LowEnergyClient(Adapter& adapter, const UUID& uuid, int client_id);
+
+ // BluetoothGattInterface::ClientObserver overrides:
+ void ConnectCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
+ int status, int client_id,
+ const bt_bdaddr_t& bda) override;
+ void DisconnectCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
+ int status, int client_id,
+ const bt_bdaddr_t& bda) override;
+ void MtuChangedCallback(hal::BluetoothGattInterface* gatt_iface, int conn_id,
+ int status, int mtu) override;
+
+ // Calls and clears the pending callbacks.
+ void InvokeAndClearStartCallback(BLEStatus status);
+ void InvokeAndClearStopCallback(BLEStatus status);
+
+ // Raw pointer to the Bluetooth Adapter.
+ Adapter& adapter_;
+
+ // See getters above for documentation.
+ UUID app_identifier_;
+ int client_id_;
+
+ // Raw handle to the Delegate, which must outlive this LowEnergyClient
+ // instance.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_;
+
+ // Protects device connection related members below.
+ std::mutex connection_fields_lock_;
+
+ // Maps bluetooth address to connection id
+ // TODO(jpawlowski): change type to bimap
+ std::map<const bt_bdaddr_t, int, ConnComparator> connection_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyClient);
+};
+
+// LowEnergyClientFactory is used to register and obtain a per-application
+// LowEnergyClient instance. Users should call RegisterInstance to obtain their
+// own unique LowEnergyClient instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyClientFactory
+ : private hal::BluetoothGattInterface::ClientObserver,
+ public BluetoothInstanceFactory {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ explicit LowEnergyClientFactory(Adapter& adapter);
+ ~LowEnergyClientFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const UUID& uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ friend class LowEnergyClient;
+
+ // BluetoothGattInterface::ClientObserver overrides:
+ void RegisterClientCallback(hal::BluetoothGattInterface* gatt_iface,
+ int status, int client_id,
+ const bt_uuid_t& app_uuid) override;
+
+ // Map of pending calls to register.
+ std::mutex pending_calls_lock_;
+ std::map<UUID, RegisterCallback> pending_calls_;
+
+ // Raw pointer to the Adapter that owns this factory.
+ Adapter& adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyClientFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/low_energy_scanner.cc b/mtkbt/code/bt/service/low_energy_scanner.cc
new file mode 100755
index 0000000..5220414
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_scanner.cc
@@ -0,0 +1,227 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/low_energy_scanner.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/logging_helpers.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+using std::lock_guard;
+using std::mutex;
+
+namespace bluetooth {
+
+namespace {
+
+// 31 + 31 for advertising data and scan response. This is the maximum length
+// TODO(armansito): Fix the HAL to return a concatenated blob that contains the
+// true length of each field and also provide a length parameter so that we
+// can support advertising length extensions in the future.
+const size_t kScanRecordLength = 62;
+
+// Returns the length of the given scan record array. We have to calculate this
+// based on the maximum possible data length and the TLV data. See TODO above
+// |kScanRecordLength|.
+size_t GetScanRecordLength(std::vector<uint8_t> bytes) {
+ for (size_t i = 0, field_len = 0; i < kScanRecordLength;
+ i += (field_len + 1)) {
+ field_len = bytes[i];
+
+ // Assert here that the data returned from the stack is correctly formatted
+ // in TLV form and that the length of the current field won't exceed the
+ // total data length.
+ CHECK(i + field_len < kScanRecordLength);
+
+ // If the field length is zero and we haven't reached the maximum length,
+ // then we have found the length, as the stack will pad the data with zeros
+ // accordingly.
+ if (field_len == 0) return i;
+ }
+
+ // We have reached the end.
+ return kScanRecordLength;
+}
+
+} // namespace
+
+// LowEnergyScanner implementation
+// ========================================================
+
+LowEnergyScanner::LowEnergyScanner(Adapter& adapter, const UUID& uuid,
+ int scanner_id)
+ : adapter_(adapter),
+ app_identifier_(uuid),
+ scanner_id_(scanner_id),
+ scan_started_(false),
+ delegate_(nullptr) {}
+
+LowEnergyScanner::~LowEnergyScanner() {
+ // Automatically unregister the scanner.
+ VLOG(1) << "LowEnergyScanner unregistering scanner: " << scanner_id_;
+
+ // Unregister as observer so we no longer receive any callbacks.
+ hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this);
+
+ hal::BluetoothGattInterface::Get()->GetScannerHALInterface()->Unregister(
+ scanner_id_);
+
+ // Stop any scans started by this client.
+ if (scan_started_.load()) StopScan();
+}
+
+void LowEnergyScanner::SetDelegate(Delegate* delegate) {
+ lock_guard<mutex> lock(delegate_mutex_);
+ delegate_ = delegate;
+}
+
+bool LowEnergyScanner::StartScan(const ScanSettings& settings,
+ const std::vector<ScanFilter>& filters) {
+ VLOG(2) << __func__;
+
+ // Cannot start a scan if the adapter is not enabled.
+ if (!adapter_.IsEnabled()) {
+ LOG(ERROR) << "Cannot scan while Bluetooth is disabled";
+ return false;
+ }
+
+ // TODO(jpawlowski): Push settings and filtering logic below the HAL.
+ bt_status_t status =
+ hal::BluetoothGattInterface::Get()->StartScan(scanner_id_);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to initiate scanning for client: " << scanner_id_;
+ return false;
+ }
+
+ scan_started_ = true;
+ return true;
+}
+
+bool LowEnergyScanner::StopScan() {
+ VLOG(2) << __func__;
+
+ // TODO(armansito): We don't support batch scanning yet so call
+ // StopRegularScanForClient directly. In the future we will need to
+ // conditionally call a batch scan API here.
+ bt_status_t status =
+ hal::BluetoothGattInterface::Get()->StopScan(scanner_id_);
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << "Failed to stop scan for client: " << scanner_id_;
+ return false;
+ }
+
+ scan_started_ = false;
+ return true;
+}
+
+const UUID& LowEnergyScanner::GetAppIdentifier() const {
+ return app_identifier_;
+}
+
+int LowEnergyScanner::GetInstanceId() const { return scanner_id_; }
+
+void LowEnergyScanner::ScanResultCallback(
+ hal::BluetoothGattInterface* gatt_iface, const bt_bdaddr_t& bda, int rssi,
+ std::vector<uint8_t> adv_data) {
+ // Ignore scan results if this client didn't start a scan.
+ if (!scan_started_.load()) return;
+
+ lock_guard<mutex> lock(delegate_mutex_);
+ if (!delegate_) return;
+
+ // TODO(armansito): Apply software filters here.
+
+ size_t record_len = GetScanRecordLength(adv_data);
+ std::vector<uint8_t> scan_record(adv_data.begin(),
+ adv_data.begin() + record_len);
+
+ ScanResult result(BtAddrString(&bda), scan_record, rssi);
+
+ delegate_->OnScanResult(this, result);
+}
+
+// LowEnergyScannerFactory implementation
+// ========================================================
+
+LowEnergyScannerFactory::LowEnergyScannerFactory(Adapter& adapter)
+ : adapter_(adapter) {
+ hal::BluetoothGattInterface::Get()->AddScannerObserver(this);
+}
+
+LowEnergyScannerFactory::~LowEnergyScannerFactory() {
+ hal::BluetoothGattInterface::Get()->RemoveScannerObserver(this);
+}
+
+bool LowEnergyScannerFactory::RegisterInstance(
+ const UUID& uuid, const RegisterCallback& callback) {
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ if (pending_calls_.find(uuid) != pending_calls_.end()) {
+ LOG(ERROR) << "Low-Energy scanner with given UUID already registered - "
+ << "UUID: " << uuid.ToString();
+ return false;
+ }
+
+ BleScannerInterface* hal_iface =
+ hal::BluetoothGattInterface::Get()->GetScannerHALInterface();
+
+ hal_iface->RegisterScanner(
+ base::Bind(&LowEnergyScannerFactory::RegisterScannerCallback,
+ base::Unretained(this), callback, uuid));
+
+ pending_calls_.insert(uuid);
+
+ return true;
+}
+
+void LowEnergyScannerFactory::RegisterScannerCallback(
+ const RegisterCallback& callback, const UUID& app_uuid, uint8_t scanner_id,
+ uint8_t status) {
+ UUID uuid(app_uuid);
+
+ VLOG(1) << __func__ << " - UUID: " << uuid.ToString();
+ lock_guard<mutex> lock(pending_calls_lock_);
+
+ auto iter = pending_calls_.find(uuid);
+ if (iter == pending_calls_.end()) {
+ VLOG(1) << "Ignoring callback for unknown app_id: " << uuid.ToString();
+ return;
+ }
+
+ // No need to construct a scanner if the call wasn't successful.
+ std::unique_ptr<LowEnergyScanner> scanner;
+ BLEStatus result = BLE_STATUS_FAILURE;
+ if (status == BT_STATUS_SUCCESS) {
+ scanner.reset(new LowEnergyScanner(adapter_, uuid, scanner_id));
+
+ hal::BluetoothGattInterface::Get()->AddScannerObserver(scanner.get());
+
+ result = BLE_STATUS_SUCCESS;
+ }
+
+ // Notify the result via the result callback.
+ callback(result, app_uuid, std::move(scanner));
+
+ pending_calls_.erase(iter);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/low_energy_scanner.h b/mtkbt/code/bt/service/low_energy_scanner.h
new file mode 100755
index 0000000..e7f6584
--- a/dev/null
+++ b/mtkbt/code/bt/service/low_energy_scanner.h
@@ -0,0 +1,161 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <base/macros.h>
+
+#include "service/bluetooth_instance.h"
+#include "service/common/bluetooth/advertise_data.h"
+#include "service/common/bluetooth/advertise_settings.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+#include "service/common/bluetooth/scan_filter.h"
+#include "service/common/bluetooth/scan_result.h"
+#include "service/common/bluetooth/scan_settings.h"
+#include "service/common/bluetooth/uuid.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bluetooth {
+
+class Adapter;
+
+// A LowEnergyScanner represents an application's handle to perform various
+// Bluetooth Low Energy GAP operations. Instances cannot be created directly and
+// should be obtained through the factory.
+class LowEnergyScanner : private hal::BluetoothGattInterface::ScannerObserver,
+ public BluetoothInstance {
+ public:
+ // The Delegate interface is used to notify asynchronous events related to LE
+ // scan.
+ class Delegate {
+ public:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ // Called asynchronously to notify the delegate of nearby BLE advertisers
+ // found during a device scan.
+ virtual void OnScanResult(LowEnergyScanner* client,
+ const ScanResult& scan_result) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ // The destructor automatically unregisters this client instance from the
+ // stack.
+ ~LowEnergyScanner() override;
+
+ // Assigns a delegate to this instance. |delegate| must out-live this
+ // LowEnergyClient instance.
+ void SetDelegate(Delegate* delegate);
+
+ // Initiates a BLE device scan for this client using the given |settings| and
+ // |filters|. See the documentation for ScanSettings and ScanFilter for how
+ // these parameters can be configured. Return true on success, false
+ // otherwise. Please see logs for details in case of error.
+ bool StartScan(const ScanSettings& settings,
+ const std::vector<ScanFilter>& filters);
+
+ // Stops an ongoing BLE device scan for this client.
+ bool StopScan();
+
+ // Returns the current scan settings.
+ const ScanSettings& scan_settings() const { return scan_settings_; }
+
+ // BluetoothInstace overrides:
+ const UUID& GetAppIdentifier() const override;
+ int GetInstanceId() const override;
+
+ void ScanResultCallback(hal::BluetoothGattInterface* gatt_iface,
+ const bt_bdaddr_t& bda, int rssi,
+ std::vector<uint8_t> adv_data) override;
+
+ private:
+ friend class LowEnergyScannerFactory;
+
+ // Constructor shouldn't be called directly as instances are meant to be
+ // obtained from the factory.
+ LowEnergyScanner(Adapter& adapter, const UUID& uuid, int scanner_id);
+
+ // Calls and clears the pending callbacks.
+ void InvokeAndClearStartCallback(BLEStatus status);
+ void InvokeAndClearStopCallback(BLEStatus status);
+
+ // Raw pointer to the Bluetooth Adapter.
+ Adapter& adapter_;
+
+ // See getters above for documentation.
+ UUID app_identifier_;
+ int scanner_id_;
+
+ // Protects device scan related members below.
+ std::mutex scan_fields_lock_;
+
+ // Current scan settings.
+ ScanSettings scan_settings_;
+
+ // If true, then this client have a BLE device scan in progress.
+ std::atomic_bool scan_started_;
+
+ // Raw handle to the Delegate, which must outlive this LowEnergyScanner
+ // instance.
+ std::mutex delegate_mutex_;
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyScanner);
+};
+
+// LowEnergyScannerFactory is used to register and obtain a per-application
+// LowEnergyScanner instance. Users should call RegisterInstance to obtain their
+// own unique LowEnergyScanner instance that has been registered with the
+// Bluetooth stack.
+class LowEnergyScannerFactory
+ : private hal::BluetoothGattInterface::ScannerObserver,
+ public BluetoothInstanceFactory {
+ public:
+ // Don't construct/destruct directly except in tests. Instead, obtain a handle
+ // from an Adapter instance.
+ explicit LowEnergyScannerFactory(Adapter& adapter);
+ ~LowEnergyScannerFactory() override;
+
+ // BluetoothInstanceFactory override:
+ bool RegisterInstance(const UUID& app_uuid,
+ const RegisterCallback& callback) override;
+
+ private:
+ friend class LowEnergyScanner;
+
+ // BluetoothGattInterface::ScannerObserver overrides:
+ void RegisterScannerCallback(const RegisterCallback& callback,
+ const UUID& app_uuid, uint8_t scanner_id,
+ uint8_t status);
+
+ // Map of pending calls to register.
+ std::mutex pending_calls_lock_;
+ std::unordered_set<UUID> pending_calls_;
+
+ // Raw pointer to the Adapter that owns this factory.
+ Adapter& adapter_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerFactory);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/main.cc b/mtkbt/code/bt/service/main.cc
new file mode 100755
index 0000000..df66497
--- a/dev/null
+++ b/mtkbt/code/bt/service/main.cc
@@ -0,0 +1,81 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+#include <base/logging.h>
+
+#include "osi/include/properties.h"
+#include "service/daemon.h"
+#include "service/switches.h"
+
+namespace {
+
+// TODO(armansito): None of these should be hardcoded here. Instead, pass these
+// via commandline.
+const char kDisableProperty[] = "persist.bluetooth.disable";
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+
+ logging::LoggingSettings log_settings;
+ if (!logging::InitLogging(log_settings)) {
+ LOG(ERROR) << "Failed to set up logging";
+ return EXIT_FAILURE;
+ }
+
+ // TODO(armansito): Initialize base/logging. By default it will dump to stdout
+ // but we might want to change that based on a command-line switch. Figure out
+ // how to route the logging to Android's syslog. Once that's done, we won't
+ // need to use osi/include/log.h anymore.
+
+ // TODO(armansito): Register exit-time clean-up handlers for the IPC sockets.
+ // Register signal handlers.
+ auto command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(bluetooth::switches::kHelpLong) ||
+ command_line->HasSwitch(bluetooth::switches::kHelpShort)) {
+ LOG(INFO) << bluetooth::switches::kHelpMessage;
+ return EXIT_SUCCESS;
+ }
+
+#if !defined(OS_GENERIC)
+ // TODO(armansito): Remove Chromecast specific property out of here. This
+ // should just be obtained from global config.
+ char disable_value[PROPERTY_VALUE_MAX];
+ int status = property_get(kDisableProperty, disable_value, nullptr);
+ if (status && !strcmp(disable_value, "1")) {
+ LOG(INFO) << "service disabled";
+ return EXIT_SUCCESS;
+ }
+#endif // !defined(OS_GENERIC)
+
+ if (!bluetooth::Daemon::Initialize()) {
+ LOG(ERROR) << "Failed to initialize Daemon";
+ return EXIT_FAILURE;
+ }
+
+ // Start the main event loop.
+ bluetooth::Daemon::Get()->StartMainLoop();
+
+ // The main message loop has exited; clean up the Daemon.
+ bluetooth::Daemon::Get()->ShutDown();
+
+ return EXIT_SUCCESS;
+}
diff --git a/mtkbt/code/bt/service/settings.cc b/mtkbt/code/bt/service/settings.cc
new file mode 100755
index 0000000..d4728d7
--- a/dev/null
+++ b/mtkbt/code/bt/service/settings.cc
@@ -0,0 +1,82 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/settings.h"
+
+#include <base/base_switches.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+
+#include "service/switches.h"
+
+namespace bluetooth {
+
+Settings::Settings() : initialized_(false) {}
+
+Settings::~Settings() {}
+
+bool Settings::Init() {
+ CHECK(!initialized_);
+ auto command_line = base::CommandLine::ForCurrentProcess();
+ const auto& switches = command_line->GetSwitches();
+
+ for (const auto& iter : switches) {
+ if (iter.first == switches::kCreateIPCSocketPath) {
+ // kCreateIPCSocketPath: An optional argument that initializes an IPC
+ // socket path for IPC.
+ base::FilePath path(iter.second);
+ if (path.empty() || path.EndsWithSeparator()) {
+ LOG(ERROR) << "Invalid IPC create socket path";
+ return false;
+ }
+
+ create_ipc_socket_path_ = path;
+ } else if (iter.first == switches::kAndroidIPCSocketSuffix) {
+ // kAndroidIPCSocketSuffix: An optional argument used to express
+ // a socket that Android init created for us. We bind to this.
+ const std::string& suffix = iter.second;
+ if (suffix.empty()) {
+ LOG(ERROR) << "Invalid Android socket suffix";
+ return false;
+ }
+
+ android_ipc_socket_suffix_ = suffix;
+ }
+ // Check for libbase logging switches. These get processed by
+ // logging::InitLogging directly.
+ else if (iter.first != ::switches::kV) {
+ LOG(ERROR) << "Unexpected command-line switches found: " << iter.first;
+ return false;
+ }
+ }
+
+ // Two IPC methods/paths were provided.
+ if (!android_ipc_socket_suffix_.empty() && !create_ipc_socket_path_.empty()) {
+ LOG(ERROR) << "Too many IPC methods provided";
+ return false;
+ }
+
+ // The daemon has no arguments
+ if (command_line->GetArgs().size()) {
+ LOG(ERROR) << "Unexpected command-line arguments found";
+ return false;
+ }
+
+ initialized_ = true;
+ return true;
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/settings.h b/mtkbt/code/bt/service/settings.h
new file mode 100755
index 0000000..d68bda1
--- a/dev/null
+++ b/mtkbt/code/bt/service/settings.h
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+
+namespace bluetooth {
+
+// The Settings class stores global runtime configurations, such as IPC domain
+// namespace, configuration file locations, and other system properties and
+// flags.
+class Settings {
+ public:
+ // Constant for the "--help" command-line switches.
+ static const char kHelp[];
+
+ Settings();
+ ~Settings();
+
+ // TODO(armansito): Write an instance method for storing things into a file.
+
+ // Initializes the Settings object. This reads the command-line options for
+ // the current process (which must have been initialized using
+ // base::CommandLine) and sets up the initial global settings. Returns false
+ // if there is an error, e.g. if the parameters/switches are malformed.
+ bool Init();
+
+ // If Android init created a server socket for the daemon,
+ // we can retrieve it through this suffix.
+ const std::string& android_ipc_socket_suffix() const {
+ return android_ipc_socket_suffix_;
+ }
+
+ // Path to create a Unix domain socket server for Bluetooth IPC.
+ const base::FilePath& create_ipc_socket_path() const {
+ return create_ipc_socket_path_;
+ }
+
+ // Returns true if domain-socket based IPC should be used. If false, then
+ // Binder IPC must be used.
+ inline bool UseSocketIPC() const {
+ return !android_ipc_socket_suffix().empty() ||
+ !create_ipc_socket_path().empty();
+ }
+
+ private:
+ bool initialized_;
+ std::string android_ipc_socket_suffix_;
+ base::FilePath create_ipc_socket_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(Settings);
+};
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/switches.h b/mtkbt/code/bt/service/switches.h
new file mode 100755
index 0000000..af23398
--- a/dev/null
+++ b/mtkbt/code/bt/service/switches.h
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace switches {
+
+// List of command-line switches used by the daemon.
+const char kHelpLong[] = "help";
+const char kHelpShort[] = "h";
+const char kAndroidIPCSocketSuffix[] = "android-ipc-socket-suffix";
+const char kCreateIPCSocketPath[] = "create-ipc-socket";
+
+const char kHelpMessage[] =
+ "\nBluetooth System Service\n"
+ "\n"
+ "Usage:\n"
+ "\t--help,-h\t\t\tShow this help message\n"
+ "\t--android-ipc-socket-suffix\tSuffix of socket created by Android init. "
+ "Mutually exclusive with --create-ipc-socket.\n"
+ "\t--create-ipc-socket\t\tSocket path created for Unix domain socket based "
+ "IPC. Mutually exclusive with --android-ipc-socket-suffix.\n"
+ "\t--v\t\t\t\tLog verbosity level (e.g. -v=1)\n";
+
+} // namespace switches
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/ParcelableTest.aidl b/mtkbt/code/bt/service/test/ParcelableTest.aidl
new file mode 100755
index 0000000..b69aadf
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/ParcelableTest.aidl
@@ -0,0 +1,30 @@
+package test;
+
+/* This file is just a test to make sure all parcelables
+ * are correct. It will be removed once they're used in
+ * real AIDL files.
+ */
+
+import android.bluetooth.AdvertiseData;
+import android.bluetooth.AdvertiseSettings;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattIncludedService;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.ScanFilter;
+import android.bluetooth.ScanResult;
+import android.bluetooth.ScanSettings;
+import android.bluetooth.UUID;
+
+interface ParcelableTest {
+ void OnAdvertiseData(in AdvertiseData advertise_data);
+ void OnAdvertiseSettings(in AdvertiseSettings advertise_settings);
+ void OnScanFilter(in ScanFilter scan_filter);
+ void OnScanResult(in ScanResult scan_result);
+ void OnScanSettings(in ScanSettings scan_settings);
+ void OnUUID(in UUID uuid);
+ void OnDescripor(in BluetoothGattDescriptor descriptor);
+ void OnCharacteristic(in BluetoothGattCharacteristic characteristic);
+ void OnIncludedService(in BluetoothGattIncludedService service);
+ void OnService(in BluetoothGattService service);
+}
diff --git a/mtkbt/code/bt/service/test/adapter_unittest.cc b/mtkbt/code/bt/service/test/adapter_unittest.cc
new file mode 100755
index 0000000..f7ee109
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/adapter_unittest.cc
@@ -0,0 +1,284 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/hal/fake_bluetooth_interface.h"
+
+namespace bluetooth {
+namespace {
+
+class AdapterTest : public ::testing::Test {
+ public:
+ AdapterTest() = default;
+ ~AdapterTest() override = default;
+
+ void SetUp() override {
+ fake_hal_manager_ = hal::FakeBluetoothInterface::GetManager();
+ fake_hal_iface_ = new hal::FakeBluetoothInterface();
+ hal::BluetoothInterface::InitializeForTesting(fake_hal_iface_);
+
+ // Initialize GATT interface with default handlers.
+ hal::BluetoothGattInterface::InitializeForTesting(
+ new hal::FakeBluetoothGattInterface(nullptr, nullptr, nullptr,
+ nullptr));
+
+ adapter_ = Adapter::Create();
+ }
+
+ void TearDown() override {
+ adapter_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ hal::BluetoothInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothInterface* fake_hal_iface_;
+ hal::FakeBluetoothInterface::Manager* fake_hal_manager_;
+ std::unique_ptr<Adapter> adapter_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AdapterTest);
+};
+
+class TestObserver final : public bluetooth::Adapter::Observer {
+ public:
+ explicit TestObserver(bluetooth::Adapter* adapter)
+ : adapter_(adapter),
+ prev_state_(bluetooth::ADAPTER_STATE_INVALID),
+ cur_state_(bluetooth::ADAPTER_STATE_INVALID),
+ last_device_connected_state_(false) {
+ CHECK(adapter_);
+ adapter_->AddObserver(this);
+ }
+
+ ~TestObserver() override { adapter_->RemoveObserver(this); }
+
+ bluetooth::AdapterState prev_state() const { return prev_state_; }
+ bluetooth::AdapterState cur_state() const { return cur_state_; }
+
+ std::string last_connection_state_address() const {
+ return last_connection_state_address_;
+ }
+
+ bool last_device_connected_state() const {
+ return last_device_connected_state_;
+ }
+
+ // bluetooth::Adapter::Observer override:
+ void OnAdapterStateChanged(bluetooth::Adapter* adapter,
+ bluetooth::AdapterState prev_state,
+ bluetooth::AdapterState new_state) override {
+ ASSERT_EQ(adapter_, adapter);
+ prev_state_ = prev_state;
+ cur_state_ = new_state;
+ }
+
+ void OnDeviceConnectionStateChanged(Adapter* adapter,
+ const std::string& device_address,
+ bool connected) override {
+ ASSERT_EQ(adapter_, adapter);
+ last_connection_state_address_ = device_address;
+ last_device_connected_state_ = connected;
+ }
+
+ private:
+ bluetooth::Adapter* adapter_;
+ bluetooth::AdapterState prev_state_, cur_state_;
+ std::string last_connection_state_address_;
+ bool last_device_connected_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
+TEST_F(AdapterTest, IsEnabled) {
+ EXPECT_FALSE(adapter_->IsEnabled());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_TRUE(adapter_->IsEnabled());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+ EXPECT_FALSE(adapter_->IsEnabled());
+}
+
+TEST_F(AdapterTest, Enable) {
+ TestObserver observer(adapter_.get());
+
+ EXPECT_FALSE(adapter_->IsEnabled());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Enable fails at HAL level
+ EXPECT_FALSE(adapter_->Enable(false));
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Enable success
+ fake_hal_manager_->enable_succeed = true;
+ EXPECT_TRUE(adapter_->Enable(false));
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.cur_state());
+
+ // Enable fails because not disabled
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, adapter_->GetState());
+ EXPECT_FALSE(adapter_->Enable(false));
+
+ // Adapter state updates properly
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Enable fails because already enabled
+ EXPECT_FALSE(adapter_->Enable(false));
+}
+
+TEST_F(AdapterTest, Disable) {
+ TestObserver observer(adapter_.get());
+
+ fake_hal_manager_->disable_succeed = true;
+ EXPECT_FALSE(adapter_->IsEnabled());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Disable fails because already disabled
+ EXPECT_FALSE(adapter_->Disable());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
+
+ // Disable success
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ EXPECT_TRUE(adapter_->Disable());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.cur_state());
+
+ // Disable fails because not enabled
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, adapter_->GetState());
+ EXPECT_FALSE(adapter_->Disable());
+
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, adapter_->GetState());
+
+ // Should have received a state update.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Disable fails at HAL level
+ fake_hal_manager_->disable_succeed = false;
+ EXPECT_FALSE(adapter_->Disable());
+
+ // Should have received a state update. In this case we will receive two
+ // updates: one going from OFF to TURNING_OFF, and one going from TURNING_OFF
+ // back to ON since we failed to initiate the disable operation.
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_OFF, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
+
+ // Update state to OFF. Should receive a state update.
+ fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_OFF);
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.prev_state());
+ EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.cur_state());
+}
+
+TEST_F(AdapterTest, GetName) {
+ EXPECT_EQ(bluetooth::Adapter::kDefaultName, adapter_->GetName());
+
+ const char kTestAdapterName[] = "Test Adapter Name";
+
+ fake_hal_iface_->NotifyAdapterNamePropertyChanged(kTestAdapterName);
+ EXPECT_EQ(kTestAdapterName, adapter_->GetName());
+}
+
+TEST_F(AdapterTest, SetName) {
+ bt_bdname_t hal_name;
+
+ // Name too large.
+ EXPECT_FALSE(adapter_->SetName(std::string(sizeof(hal_name.name), 'a')));
+
+ // Valid length.
+ EXPECT_FALSE(adapter_->SetName("Test Name"));
+ fake_hal_manager_->set_property_succeed = true;
+ EXPECT_TRUE(adapter_->SetName("Test Name"));
+}
+
+TEST_F(AdapterTest, GetAddress) {
+ EXPECT_EQ(bluetooth::Adapter::kDefaultAddress, adapter_->GetAddress());
+
+ const bt_bdaddr_t kTestAdapterInput = {{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}};
+ const char kTestAdapterAddressOutput[] = "12:34:56:78:9A:BC";
+
+ fake_hal_iface_->NotifyAdapterAddressPropertyChanged(&kTestAdapterInput);
+ EXPECT_EQ(kTestAdapterAddressOutput, adapter_->GetAddress());
+}
+
+TEST_F(AdapterTest, IsMultiAdvertisementSupported) {
+ EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
+
+ bt_local_le_features_t features;
+ memset(&features, 0, sizeof(features));
+
+ features.max_adv_instance = 10; // Some high number.
+ fake_hal_iface_->NotifyAdapterLocalLeFeaturesPropertyChanged(&features);
+ EXPECT_TRUE(adapter_->IsMultiAdvertisementSupported());
+
+ features.max_adv_instance = 0; // Low number.
+ fake_hal_iface_->NotifyAdapterLocalLeFeaturesPropertyChanged(&features);
+ EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
+}
+
+TEST_F(AdapterTest, IsDeviceConnected) {
+ const char kDeviceAddr[] = "12:34:56:78:9A:BC";
+ TestObserver observer(adapter_.get());
+
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+
+ bt_bdaddr_t hal_addr;
+ ASSERT_TRUE(util::BdAddrFromString(kDeviceAddr, &hal_addr));
+
+ // status != BT_STATUS_SUCCESS should be ignored
+ fake_hal_iface_->NotifyAclStateChangedCallback(BT_STATUS_FAIL, hal_addr,
+ BT_ACL_STATE_CONNECTED);
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_TRUE(observer.last_connection_state_address().empty());
+ EXPECT_FALSE(observer.last_device_connected_state());
+
+ // Connected
+ fake_hal_iface_->NotifyAclStateChangedCallback(BT_STATUS_SUCCESS, hal_addr,
+ BT_ACL_STATE_CONNECTED);
+ EXPECT_TRUE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+ EXPECT_TRUE(observer.last_device_connected_state());
+
+ // Disconnected
+ fake_hal_iface_->NotifyAclStateChangedCallback(BT_STATUS_SUCCESS, hal_addr,
+ BT_ACL_STATE_DISCONNECTED);
+ EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+ EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+ EXPECT_FALSE(observer.last_device_connected_state());
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/advertise_data_unittest.cc b/mtkbt/code/bt/service/test/advertise_data_unittest.cc
new file mode 100755
index 0000000..bd0787e
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/advertise_data_unittest.cc
@@ -0,0 +1,112 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <gtest/gtest.h>
+
+#include "service/common/bluetooth/advertise_data.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+
+namespace bluetooth {
+
+TEST(AdvertiseDataTest, EmptyData) {
+ const std::vector<uint8_t> data0;
+ AdvertiseData adv0(data0);
+ EXPECT_TRUE(adv0.IsValid());
+
+ // Single empty field not allowed.
+ const std::vector<uint8_t> data1{0x00};
+ AdvertiseData adv1(data1);
+ EXPECT_FALSE(adv1.IsValid());
+}
+
+TEST(AdvertiseDataTest, BadTLV) {
+ // Single field, field empty.
+ const std::vector<uint8_t> data0{0x01};
+ AdvertiseData adv0(data0);
+ EXPECT_FALSE(adv0.IsValid());
+
+ // Single field, first field length too long.
+ const std::vector<uint8_t> data1{0x05, 0x02, 0x00, 0x00, 0x00};
+ AdvertiseData adv1(data1);
+ EXPECT_FALSE(adv1.IsValid());
+
+ // Two fields, second field length too long.
+ const std::vector<uint8_t> data2{0x02, 0x02, 0x00, 0x02, 0x00};
+ AdvertiseData adv2(data2);
+ EXPECT_FALSE(adv2.IsValid());
+
+ // Two fields, second field empty.
+ const std::vector<uint8_t> data3{0x02, 0x02, 0x00, 0x01};
+ AdvertiseData adv3(data3);
+ EXPECT_FALSE(adv3.IsValid());
+}
+
+TEST(AdvertiseDataTest, GoodTLV) {
+ // Singe field.
+ const std::vector<uint8_t> data0{0x03, 0x02, 0x01, 0x02};
+ AdvertiseData adv0(data0);
+ EXPECT_TRUE(adv0.IsValid());
+
+ // Twi fields.
+ const std::vector<uint8_t> data1{0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01};
+ AdvertiseData adv1(data1);
+ EXPECT_TRUE(adv0.IsValid());
+}
+
+TEST(AdvertiseDataTest, DisallowedFields) {
+ // Singe field.
+ const std::vector<uint8_t> data0{0x02, HCI_EIR_FLAGS_TYPE, 0x00};
+ AdvertiseData adv0(data0);
+ EXPECT_FALSE(adv0.IsValid());
+
+ // Two fields, first invalid.
+ const std::vector<uint8_t> data1{
+ 0x02, HCI_EIR_FLAGS_TYPE, 0x00, 0x03, 0x02, 0x01, 0x02};
+ AdvertiseData adv1(data1);
+ EXPECT_FALSE(adv1.IsValid());
+
+ // Two fields, second invalid.
+ const std::vector<uint8_t> data2{
+ 0x03, 0x02, 0x01, 0x02, 0x02, HCI_EIR_FLAGS_TYPE, 0x00};
+ AdvertiseData adv2(data2);
+ EXPECT_FALSE(adv2.IsValid());
+
+ // Check all blacklisted fields
+ uint8_t blacklist[] = {HCI_EIR_FLAGS_TYPE, HCI_EIR_OOB_BD_ADDR_TYPE,
+ HCI_EIR_OOB_COD_TYPE, HCI_EIR_OOB_SSP_HASH_C_TYPE,
+ HCI_EIR_OOB_SSP_RAND_R_TYPE};
+ for (size_t i = 0; i < sizeof(blacklist); i++) {
+ const std::vector<uint8_t> data{0x02, blacklist[i], 0x00};
+ AdvertiseData adv(data);
+ EXPECT_FALSE(adv.IsValid());
+ }
+}
+
+TEST(AdvertiseDataTest, EqualsData) {
+ const std::vector<uint8_t> data0{0x02, 0x02, 0x00};
+ const std::vector<uint8_t> data1{0x02, 0x03, 0x00};
+
+ AdvertiseData adv0(data0);
+ AdvertiseData adv1(data1);
+
+ EXPECT_FALSE(adv0 == adv1);
+
+ AdvertiseData adv2(data1);
+ EXPECT_TRUE(adv1 == adv2);
+}
+
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/fake_hal_util.cc b/mtkbt/code/bt/service/test/fake_hal_util.cc
new file mode 100755
index 0000000..0fdc19b
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/fake_hal_util.cc
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "btcore/include/hal_util.h"
+
+// TODO(armansito): This provides a fake implementation of the function defined
+// in btcore/include/hal_util.h. We have to provide this to prevent having to
+// pull in libbtcore and transitively libhardware as dependencies for the unit
+// tests. Instead of doing it this way, however, we should instead provide a C++
+// class abstraction for this (and all other btif interfaces) that we can mock
+// for testing.
+int hal_util_load_bt_library(const struct hw_module_t** module) { return -1; }
diff --git a/mtkbt/code/bt/service/test/gatt_client_unittest.cc b/mtkbt/code/bt/service/test/gatt_client_unittest.cc
new file mode 100755
index 0000000..7527e8b
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/gatt_client_unittest.cc
@@ -0,0 +1,163 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/gatt_client.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+ : public hal::FakeBluetoothGattInterface::TestClientHandler {
+ public:
+ MockGattHandler() = default;
+ ~MockGattHandler() override = default;
+
+ MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
+ MOCK_METHOD1(UnregisterClient, bt_status_t(int));
+ MOCK_METHOD1(Scan, bt_status_t(bool));
+ MOCK_METHOD4(Connect, bt_status_t(int, const bt_bdaddr_t*, bool, int));
+ MOCK_METHOD3(Disconnect, bt_status_t(int, const bt_bdaddr_t*, int));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class GattClientTest : public ::testing::Test {
+ public:
+ GattClientTest() = default;
+ ~GattClientTest() override = default;
+
+ void SetUp() override {
+ // Only set |mock_handler_| if a previous test case hasn't set it.
+ if (!mock_handler_) mock_handler_.reset(new MockGattHandler());
+
+ fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+ nullptr, nullptr,
+ std::static_pointer_cast<
+ hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_),
+ nullptr);
+ hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+
+ factory_.reset(new GattClientFactory());
+ }
+
+ void TearDown() override {
+ factory_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+ std::shared_ptr<MockGattHandler> mock_handler_;
+ std::unique_ptr<GattClientFactory> factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GattClientTest);
+};
+
+TEST_F(GattClientTest, RegisterInstance) {
+ EXPECT_CALL(*mock_handler_, RegisterClient(_))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // These will be asynchronously populated with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ UUID cb_uuid;
+ std::unique_ptr<GattClient> client;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const UUID& uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ status = in_status;
+ cb_uuid = uuid;
+ client = std::unique_ptr<GattClient>(
+ static_cast<GattClient*>(in_client.release()));
+ callback_count++;
+ };
+
+ UUID uuid0 = UUID::GetRandom();
+
+ // HAL returns failure.
+ EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // HAL returns success.
+ EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // Calling twice with the same UUID should fail with no additional call into
+ // the stack.
+ EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Call with a different UUID while one is pending.
+ UUID uuid1 = UUID::GetRandom();
+ EXPECT_CALL(*mock_handler_, RegisterClient(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
+
+ // Trigger callback with an unknown UUID. This should get ignored.
+ UUID uuid2 = UUID::GetRandom();
+ bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+ EXPECT_EQ(0, callback_count);
+
+ // |uuid0| succeeds.
+ int client_id0 = 2; // Pick something that's not 0.
+ hal_uuid = uuid0.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS,
+ client_id0, hal_uuid);
+
+ EXPECT_EQ(1, callback_count);
+ ASSERT_TRUE(client.get() != nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(client_id0, client->GetInstanceId());
+ EXPECT_EQ(uuid0, client->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ // The client should unregister itself when deleted.
+ EXPECT_CALL(*mock_handler_, UnregisterClient(client_id0))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ client.reset();
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // |uuid1| fails.
+ int client_id1 = 3;
+ hal_uuid = uuid1.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_id1,
+ hal_uuid);
+
+ EXPECT_EQ(2, callback_count);
+ ASSERT_TRUE(client.get() == nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_FAILURE, status);
+ EXPECT_EQ(uuid1, cb_uuid);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/gatt_server_unittest.cc b/mtkbt/code/bt/service/test/gatt_server_unittest.cc
new file mode 100755
index 0000000..ee88b99
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/gatt_server_unittest.cc
@@ -0,0 +1,730 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/common/bluetooth/util/address_helper.h"
+#include "service/gatt_server.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+ : public hal::FakeBluetoothGattInterface::TestServerHandler {
+ public:
+ MockGattHandler() = default;
+ ~MockGattHandler() override = default;
+
+ MOCK_METHOD1(RegisterServer, bt_status_t(bt_uuid_t*));
+ MOCK_METHOD1(UnregisterServer, bt_status_t(int));
+ MOCK_METHOD2(AddService, bt_status_t(int, std::vector<btgatt_db_element_t>));
+ MOCK_METHOD5(AddCharacteristic, bt_status_t(int, int, bt_uuid_t*, int, int));
+ MOCK_METHOD4(AddDescriptor, bt_status_t(int, int, bt_uuid_t*, int));
+ MOCK_METHOD3(StartService, bt_status_t(int, int, int));
+ MOCK_METHOD2(DeleteService, bt_status_t(int, int));
+ MOCK_METHOD5(SendIndication,
+ bt_status_t(int, int, int, int, std::vector<uint8_t>));
+ MOCK_METHOD4(SendResponse, bt_status_t(int, int, int, btgatt_response_t*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class TestDelegate : public GattServer::Delegate {
+ public:
+ TestDelegate() = default;
+ ~TestDelegate() override = default;
+
+ struct RequestData {
+ RequestData()
+ : id(-1),
+ offset(-1),
+ is_long(false),
+ is_prep(false),
+ need_rsp(false),
+ is_exec(false),
+ count(0),
+ connected(false) {}
+ ~RequestData() = default;
+
+ std::string device_address;
+ int id;
+ int offset;
+ bool is_long;
+ bool is_prep;
+ bool need_rsp;
+ bool is_exec;
+ uint16_t handle;
+ int count;
+ std::vector<uint8_t> write_value;
+ bool connected;
+ };
+
+ void OnCharacteristicReadRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_long,
+ uint16_t handle) override {
+ ASSERT_TRUE(gatt_server);
+ char_read_req_.device_address = device_address;
+ char_read_req_.id = request_id;
+ char_read_req_.offset = offset;
+ char_read_req_.is_long = is_long;
+ char_read_req_.handle = handle;
+ char_read_req_.count++;
+ }
+
+ void OnDescriptorReadRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset, bool is_long,
+ uint16_t handle) override {
+ ASSERT_TRUE(gatt_server);
+ desc_read_req_.device_address = device_address;
+ desc_read_req_.id = request_id;
+ desc_read_req_.offset = offset;
+ desc_read_req_.is_long = is_long;
+ desc_read_req_.handle = handle;
+ desc_read_req_.count++;
+ }
+
+ void OnCharacteristicWriteRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ uint16_t handle) override {
+ ASSERT_TRUE(gatt_server);
+ char_write_req_.device_address = device_address;
+ char_write_req_.id = request_id;
+ char_write_req_.offset = offset;
+ char_write_req_.is_prep = is_prepare_write;
+ char_write_req_.need_rsp = need_response;
+ char_write_req_.handle = handle;
+ char_write_req_.count++;
+ char_write_req_.write_value = value;
+ }
+
+ void OnDescriptorWriteRequest(GattServer* gatt_server,
+ const std::string& device_address,
+ int request_id, int offset,
+ bool is_prepare_write, bool need_response,
+ const std::vector<uint8_t>& value,
+ uint16_t handle) override {
+ ASSERT_TRUE(gatt_server);
+ desc_write_req_.device_address = device_address;
+ desc_write_req_.id = request_id;
+ desc_write_req_.offset = offset;
+ desc_write_req_.is_prep = is_prepare_write;
+ desc_write_req_.need_rsp = need_response;
+ desc_write_req_.handle = handle;
+ desc_write_req_.count++;
+ desc_write_req_.write_value = value;
+ }
+
+ void OnExecuteWriteRequest(GattServer* gatt_server,
+ const std::string& device_address, int request_id,
+ bool is_execute) override {
+ ASSERT_TRUE(gatt_server);
+ exec_req_.device_address = device_address;
+ exec_req_.id = request_id;
+ exec_req_.is_exec = is_execute;
+ exec_req_.count++;
+ }
+
+ void OnConnectionStateChanged(GattServer* gatt_server,
+ const std::string& device_address,
+ bool connected) override {
+ ASSERT_TRUE(gatt_server);
+ conn_state_changed_.device_address = device_address;
+ conn_state_changed_.connected = connected;
+ conn_state_changed_.count++;
+ }
+
+ const RequestData& char_read_req() const { return char_read_req_; }
+ const RequestData& desc_read_req() const { return desc_read_req_; }
+ const RequestData& char_write_req() const { return char_write_req_; }
+ const RequestData& desc_write_req() const { return desc_write_req_; }
+ const RequestData& conn_state_changed() const { return conn_state_changed_; }
+
+ private:
+ RequestData char_read_req_;
+ RequestData desc_read_req_;
+ RequestData char_write_req_;
+ RequestData desc_write_req_;
+ RequestData exec_req_;
+ RequestData conn_state_changed_;
+};
+
+class GattServerTest : public ::testing::Test {
+ public:
+ GattServerTest() = default;
+ ~GattServerTest() override = default;
+
+ void SetUp() override {
+ mock_handler_.reset(new MockGattHandler());
+ fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+ nullptr, nullptr, nullptr,
+ std::static_pointer_cast<
+ hal::FakeBluetoothGattInterface::TestServerHandler>(mock_handler_));
+
+ hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+ factory_.reset(new GattServerFactory());
+ }
+
+ void TearDown() override {
+ factory_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+ std::shared_ptr<MockGattHandler> mock_handler_;
+ std::unique_ptr<GattServerFactory> factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GattServerTest);
+};
+
+const int kDefaultServerId = 4;
+
+class GattServerPostRegisterTest : public GattServerTest {
+ public:
+ GattServerPostRegisterTest() = default;
+ ~GattServerPostRegisterTest() override = default;
+
+ void SetUp() override {
+ GattServerTest::SetUp();
+ UUID uuid = UUID::GetRandom();
+ auto callback = [&](BLEStatus status, const UUID& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_client.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ gatt_server_ = std::unique_ptr<GattServer>(
+ static_cast<GattServer*>(in_client.release()));
+ };
+
+ EXPECT_CALL(*mock_handler_, RegisterServer(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ factory_->RegisterInstance(uuid, callback);
+
+ bt_uuid_t hal_uuid = uuid.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterServerCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, hal_uuid);
+ }
+
+ void TearDown() override {
+ EXPECT_CALL(*mock_handler_, UnregisterServer(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ gatt_server_ = nullptr;
+ GattServerTest::TearDown();
+ }
+
+ void SetUpTestService() {
+ EXPECT_CALL(*mock_handler_, AddService(_, _))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ UUID uuid0 = UUID::GetRandom();
+ UUID uuid1 = UUID::GetRandom();
+ UUID uuid2 = UUID::GetRandom();
+
+ bool register_success = false;
+
+ Service service(0, true, uuid0, {}, {});
+
+ ASSERT_TRUE(gatt_server_->AddService(
+ service, [&](BLEStatus status, const Service& added_service) {
+ ASSERT_EQ(BLE_STATUS_SUCCESS, status);
+ ASSERT_TRUE(UUID(added_service.uuid()) == UUID(service.uuid()));
+ ASSERT_TRUE(added_service.handle() == 0x0001);
+ register_success = true;
+ }));
+
+ srvc_handle_ = 0x0001;
+ char_handle_ = 0x0002;
+ desc_handle_ = 0x0004;
+
+ std::vector<btgatt_db_element_t> service_with_handles = {
+ {.type = BTGATT_DB_PRIMARY_SERVICE,
+ .uuid = uuid0.GetBlueDroid(),
+ .attribute_handle = srvc_handle_},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = uuid1.GetBlueDroid(),
+ .attribute_handle = char_handle_},
+ {.type = BTGATT_DB_DESCRIPTOR,
+ .uuid = uuid2.GetBlueDroid(),
+ .attribute_handle = desc_handle_},
+ };
+
+ fake_hal_gatt_iface_->NotifyServiceAddedCallback(
+ BT_STATUS_SUCCESS, kDefaultServerId, service_with_handles);
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ ASSERT_TRUE(register_success);
+ }
+
+ protected:
+ std::unique_ptr<GattServer> gatt_server_;
+
+ uint16_t srvc_handle_;
+ uint16_t char_handle_;
+ uint16_t desc_handle_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GattServerPostRegisterTest);
+};
+
+TEST_F(GattServerTest, RegisterServer) {
+ EXPECT_CALL(*mock_handler_, RegisterServer(_))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // These will be asynchronously populate with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ UUID cb_uuid;
+ std::unique_ptr<GattServer> server;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const UUID& uuid,
+ std::unique_ptr<BluetoothInstance> in_server) {
+ status = in_status;
+ cb_uuid = uuid;
+ server = std::unique_ptr<GattServer>(
+ static_cast<GattServer*>(in_server.release()));
+ callback_count++;
+ };
+
+ UUID uuid0 = UUID::GetRandom();
+
+ // HAL returns failure.
+ EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // HAL returns success.
+ EXPECT_TRUE(factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // Calling twice with the same UUID should fail with no additional calls into
+ // the stack.
+ EXPECT_FALSE(factory_->RegisterInstance(uuid0, callback));
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Call with a different UUID while one is pending.
+ UUID uuid1 = UUID::GetRandom();
+ EXPECT_CALL(*mock_handler_, RegisterServer(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_TRUE(factory_->RegisterInstance(uuid1, callback));
+
+ // Trigger callback with an unknown UUID. This should get ignored.
+ UUID uuid2 = UUID::GetRandom();
+ bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterServerCallback(0, 0, hal_uuid);
+ EXPECT_EQ(0, callback_count);
+
+ // |uuid0| succeeds.
+ int server_if0 = 2; // Pick something that's not 0.
+ hal_uuid = uuid0.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterServerCallback(BT_STATUS_SUCCESS,
+ server_if0, hal_uuid);
+
+ EXPECT_EQ(1, callback_count);
+ ASSERT_TRUE(server.get() != nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(server_if0, server->GetInstanceId());
+ EXPECT_EQ(uuid0, server->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ // The server should unregister itself when deleted.
+ EXPECT_CALL(*mock_handler_, UnregisterServer(server_if0))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ server.reset();
+
+ testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // |uuid1| fails.
+ int server_if1 = 3;
+ hal_uuid = uuid1.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterServerCallback(BT_STATUS_FAIL, server_if1,
+ hal_uuid);
+
+ EXPECT_EQ(2, callback_count);
+ ASSERT_TRUE(server.get() == nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_FAILURE, status);
+ EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(GattServerPostRegisterTest, RequestRead) {
+ SetUpTestService();
+
+ TestDelegate test_delegate;
+ gatt_server_->SetDelegate(&test_delegate);
+
+ const std::vector<uint8_t> kTestValue = {0x01, 0x02, 0x03};
+ const std::vector<uint8_t> kTestValueTooLarge(BTGATT_MAX_ATTR_LEN + 1, 0);
+ const std::string kTestAddress0 = "01:23:45:67:89:AB";
+ const std::string kTestAddress1 = "CD:EF:01:23:45:67";
+ const int kReqId0 = 0;
+ const int kReqId1 = 1;
+ const int kConnId0 = 1;
+
+ // No pending request.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ bt_bdaddr_t hal_addr0, hal_addr1;
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1));
+
+ // Send a connection callback. The GattServer should store the connection
+ // information and be able to process the incoming read requests for this
+ // connection.
+ fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+ kConnId0, kDefaultServerId, true, hal_addr0);
+
+ // Unknown connection ID shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+ kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, false);
+ EXPECT_EQ(0, test_delegate.char_read_req().count);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+ // Unknown device address shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr1, char_handle_, 0, false);
+ EXPECT_EQ(0, test_delegate.char_read_req().count);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+ // Characteristic and descriptor handles should trigger correct callbacks.
+ fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.char_read_req().device_address);
+ EXPECT_EQ(kReqId0, test_delegate.char_read_req().id);
+ EXPECT_EQ(0, test_delegate.char_read_req().offset);
+ EXPECT_FALSE(test_delegate.char_read_req().is_long);
+ EXPECT_TRUE(char_handle_ == test_delegate.char_read_req().handle);
+ EXPECT_EQ(0, test_delegate.desc_read_req().count);
+
+ fake_hal_gatt_iface_->NotifyRequestReadDescriptorCallback(
+ kConnId0, kReqId1, hal_addr0, desc_handle_, 2, true);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(1, test_delegate.desc_read_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.desc_read_req().device_address);
+ EXPECT_EQ(kReqId1, test_delegate.desc_read_req().id);
+ EXPECT_EQ(2, test_delegate.desc_read_req().offset);
+ EXPECT_TRUE(test_delegate.desc_read_req().is_long);
+ EXPECT_TRUE(desc_handle_ == test_delegate.desc_read_req().handle);
+
+ // Callback with a pending request ID will be ignored.
+ fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0, false);
+ fake_hal_gatt_iface_->NotifyRequestReadCharacteristicCallback(
+ kConnId0, kReqId1, hal_addr0, char_handle_, 0, false);
+ EXPECT_EQ(1, test_delegate.char_read_req().count);
+ EXPECT_EQ(1, test_delegate.desc_read_req().count);
+
+ // Send response for wrong device address.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress1, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Send response for a value that's too large.
+ EXPECT_FALSE(gatt_server_->SendResponse(
+ kTestAddress0, kReqId0, GATT_ERROR_NONE, 0, kTestValueTooLarge));
+
+ EXPECT_CALL(*mock_handler_,
+ SendResponse(kConnId0, kReqId0, BT_STATUS_SUCCESS, _))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Stack call fails.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Successful send response for characteristic.
+ EXPECT_TRUE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Characteristic request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ EXPECT_CALL(*mock_handler_,
+ SendResponse(kConnId0, kReqId1, BT_STATUS_SUCCESS, _))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Successful send response for descriptor.
+ EXPECT_TRUE(gatt_server_->SendResponse(kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Descriptor request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ gatt_server_->SetDelegate(nullptr);
+}
+
+TEST_F(GattServerPostRegisterTest, RequestWrite) {
+ SetUpTestService();
+
+ TestDelegate test_delegate;
+ gatt_server_->SetDelegate(&test_delegate);
+
+ const std::vector<uint8_t> kTestValue = {0x01, 0x02, 0x03};
+ const std::string kTestAddress0 = "01:23:45:67:89:AB";
+ const std::string kTestAddress1 = "CD:EF:01:23:45:67";
+ const int kReqId0 = 0;
+ const int kReqId1 = 1;
+ const int kConnId0 = 1;
+
+ // No pending request.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ bt_bdaddr_t hal_addr0, hal_addr1;
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress1, &hal_addr1));
+
+ // Send a connection callback. The GattServer should store the connection
+ // information and be able to process the incoming read requests for this
+ // connection.
+ fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+ kConnId0, kDefaultServerId, true, hal_addr0);
+
+ // Unknown connection ID shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0 + 1, kReqId0, hal_addr0, char_handle_, 0, true, false,
+ kTestValue);
+ EXPECT_EQ(0, test_delegate.char_write_req().count);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ // Unknown device address shouldn't trigger anything.
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr1, char_handle_, 0, true, false, kTestValue);
+ EXPECT_EQ(0, test_delegate.char_write_req().count);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ // Characteristic and descriptor handles should trigger correct callbacks.
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0, true, false, kTestValue);
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.char_write_req().device_address);
+ EXPECT_EQ(kReqId0, test_delegate.char_write_req().id);
+ EXPECT_EQ(0, test_delegate.char_write_req().offset);
+ EXPECT_EQ(true, test_delegate.char_write_req().need_rsp);
+ EXPECT_EQ(false, test_delegate.char_write_req().is_exec);
+ EXPECT_EQ(kTestValue, test_delegate.char_write_req().write_value);
+ EXPECT_TRUE(char_handle_ == test_delegate.char_write_req().handle);
+ EXPECT_EQ(0, test_delegate.desc_write_req().count);
+
+ fake_hal_gatt_iface_->NotifyRequestWriteDescriptorCallback(
+ kConnId0, kReqId1, hal_addr0, desc_handle_, 2, true, false, kTestValue);
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(1, test_delegate.desc_write_req().count);
+ EXPECT_EQ(kTestAddress0, test_delegate.desc_write_req().device_address);
+ EXPECT_EQ(kReqId1, test_delegate.desc_write_req().id);
+ EXPECT_EQ(2, test_delegate.desc_write_req().offset);
+ EXPECT_EQ(true, test_delegate.desc_write_req().need_rsp);
+ EXPECT_EQ(false, test_delegate.desc_write_req().is_exec);
+ EXPECT_EQ(kTestValue, test_delegate.desc_write_req().write_value);
+ EXPECT_TRUE(desc_handle_ == test_delegate.desc_write_req().handle);
+
+ // Callback with a pending request ID will be ignored.
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0, true, false, kTestValue);
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0, kReqId1, hal_addr0, char_handle_, 0, true, false, kTestValue);
+ EXPECT_EQ(1, test_delegate.char_write_req().count);
+ EXPECT_EQ(1, test_delegate.desc_write_req().count);
+
+ // Send response for wrong device address.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress1, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ EXPECT_CALL(*mock_handler_,
+ SendResponse(kConnId0, kReqId0, BT_STATUS_SUCCESS, _))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Stack call fails.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Successful send response for characteristic.
+ EXPECT_TRUE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Characteristic request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ EXPECT_CALL(*mock_handler_,
+ SendResponse(kConnId0, kReqId1, BT_STATUS_SUCCESS, _))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // Successful send response for descriptor.
+ EXPECT_TRUE(gatt_server_->SendResponse(kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // Descriptor request ID no longer pending.
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId1,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ // SendResponse should fail for a "Write Without Response".
+ fake_hal_gatt_iface_->NotifyRequestWriteCharacteristicCallback(
+ kConnId0, kReqId0, hal_addr0, char_handle_, 0, false, false, kTestValue);
+ EXPECT_EQ(false, test_delegate.char_write_req().need_rsp);
+ EXPECT_FALSE(gatt_server_->SendResponse(kTestAddress0, kReqId0,
+ GATT_ERROR_NONE, 0, kTestValue));
+
+ gatt_server_->SetDelegate(nullptr);
+}
+
+TEST_F(GattServerPostRegisterTest, SendNotification) {
+ SetUpTestService();
+
+ const std::string kTestAddress0 = "01:23:45:67:89:AB";
+ const std::string kTestAddress1 = "cd:ef:01:23:45:67";
+ const std::string kInvalidAddress = "thingamajig blabbidyboop";
+ const int kConnId0 = 0;
+ const int kConnId1 = 1;
+ std::vector<uint8_t> value;
+ bt_bdaddr_t hal_addr0;
+ ASSERT_TRUE(util::BdAddrFromString(kTestAddress0, &hal_addr0));
+
+ // Set up two connections with the same address.
+ fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+ kConnId0, kDefaultServerId, true, hal_addr0);
+ fake_hal_gatt_iface_->NotifyServerConnectionCallback(
+ kConnId1, kDefaultServerId, true, hal_addr0);
+
+ // Set up a test callback.
+ GATTError gatt_error;
+ int callback_count = 0;
+ auto callback = [&](GATTError in_error) {
+ gatt_error = in_error;
+ callback_count++;
+ };
+
+ // Bad device address.
+ EXPECT_FALSE(gatt_server_->SendNotification(kInvalidAddress, char_handle_,
+ false, value, callback));
+
+ // Bad connection.
+ EXPECT_FALSE(gatt_server_->SendNotification(kTestAddress1, char_handle_,
+ false, value, callback));
+
+ // We should get a HAL call for each connection for this address. The calls
+ // fail.
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId0, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_FAIL));
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId1, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_FAIL));
+ EXPECT_FALSE(gatt_server_->SendNotification(kTestAddress0, char_handle_,
+ false, value, callback));
+
+ // One of the calls succeeds.
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId0, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId1, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_FAIL));
+ EXPECT_TRUE(gatt_server_->SendNotification(kTestAddress0, char_handle_, false,
+ value, callback));
+
+ // One of the connections is already pending so there should be only one call.
+ // This one we send with confirm=true.
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId1, 1, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_TRUE(gatt_server_->SendNotification(kTestAddress0, char_handle_, true,
+ value, callback));
+
+ // Calls are already pending.
+ EXPECT_FALSE(gatt_server_->SendNotification(kTestAddress0, char_handle_, true,
+ value, callback));
+
+ // Trigger one confirmation callback. We should get calls for two callbacks
+ // since we have two separate calls pending.
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId0,
+ BT_STATUS_SUCCESS);
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId1,
+ BT_STATUS_SUCCESS);
+ EXPECT_EQ(2, callback_count);
+ EXPECT_EQ(GATT_ERROR_NONE, gatt_error);
+
+ callback_count = 0;
+
+ // Restart. Both calls succeed now.
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId0, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_CALL(*mock_handler_, SendIndication(kDefaultServerId, char_handle_,
+ kConnId1, 0, value))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_TRUE(gatt_server_->SendNotification(kTestAddress0, char_handle_, false,
+ value, callback));
+
+ // Trigger one confirmation callback. The callback we passed should still be
+ // pending. The first callback is for the wrong connection ID.
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId0 + 50,
+ BT_STATUS_FAIL);
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId0,
+ BT_STATUS_SUCCESS);
+ EXPECT_EQ(0, callback_count);
+
+ // This should be ignored since |kConnId0| was already processed.
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId0,
+ BT_STATUS_SUCCESS);
+ EXPECT_EQ(0, callback_count);
+
+ // Run the callback with failure. Since the previous callback reported
+ // success, we should report success.
+ fake_hal_gatt_iface_->NotifyIndicationSentCallback(kConnId1,
+ BT_STATUS_SUCCESS);
+ EXPECT_EQ(1, callback_count);
+ EXPECT_EQ(GATT_ERROR_NONE, gatt_error);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/ipc_linux_unittest.cc b/mtkbt/code/bt/service/test/ipc_linux_unittest.cc
new file mode 100755
index 0000000..39cc741
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/ipc_linux_unittest.cc
@@ -0,0 +1,205 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <memory>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/files/scoped_file.h>
+#include <base/macros.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/hal/fake_bluetooth_interface.h"
+#include "service/ipc/ipc_manager.h"
+#include "service/settings.h"
+#include "service/test/mock_daemon.h"
+
+namespace {
+
+using testing::Return;
+
+const char kTestSocketPath[] = "test_socket_path";
+
+class IPCLinuxTest : public ::testing::Test {
+ public:
+ IPCLinuxTest() = default;
+ ~IPCLinuxTest() override = default;
+
+ void SetUp() override {
+ SetUpCommandLine();
+ ASSERT_TRUE(settings_.Init());
+
+ auto mock_daemon = new bluetooth::testing::MockDaemon();
+
+ ON_CALL(*mock_daemon, GetSettings()).WillByDefault(Return(&settings_));
+ ON_CALL(*mock_daemon, GetMessageLoop())
+ .WillByDefault(Return(&message_loop_));
+
+ bluetooth::Daemon::InitializeForTesting(mock_daemon);
+ bluetooth::hal::BluetoothInterface::InitializeForTesting(
+ new bluetooth::hal::FakeBluetoothInterface());
+ bluetooth::hal::BluetoothGattInterface::InitializeForTesting(
+ new bluetooth::hal::FakeBluetoothGattInterface(nullptr, nullptr,
+ nullptr, nullptr));
+
+ adapter_ = bluetooth::Adapter::Create();
+ ipc_manager_.reset(new ipc::IPCManager(adapter_.get()));
+ }
+
+ void TearDown() override {
+ client_fd_.reset();
+ ipc_manager_.reset();
+ adapter_.reset();
+ bluetooth::hal::BluetoothGattInterface::CleanUp();
+ bluetooth::hal::BluetoothInterface::CleanUp();
+ bluetooth::Daemon::ShutDown();
+ base::CommandLine::Reset();
+ }
+
+ virtual void SetUpCommandLine() {
+ std::string ipc_socket_arg =
+ base::StringPrintf("--create-ipc-socket=%s", kTestSocketPath);
+ const base::CommandLine::CharType* argv[] = {
+ "program", ipc_socket_arg.c_str(),
+ };
+ base::CommandLine::Init(arraysize(argv), argv);
+ }
+
+ void ConnectToTestSocket() {
+ client_fd_.reset(socket(PF_UNIX, SOCK_SEQPACKET, 0));
+ ASSERT_TRUE(client_fd_.is_valid());
+
+ struct sockaddr_un address;
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, kTestSocketPath, sizeof(address.sun_path) - 1);
+
+ int status =
+ connect(client_fd_.get(), (struct sockaddr*)&address, sizeof(address));
+ EXPECT_EQ(0, status);
+ }
+
+ protected:
+ base::AtExitManager exit_manager_;
+ base::MessageLoop message_loop_;
+ bluetooth::Settings settings_;
+
+ std::unique_ptr<bluetooth::Adapter> adapter_;
+ std::unique_ptr<ipc::IPCManager> ipc_manager_;
+ base::ScopedFD client_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCLinuxTest);
+};
+
+class IPCLinuxTestDisabled : public IPCLinuxTest {
+ public:
+ IPCLinuxTestDisabled() = default;
+ ~IPCLinuxTestDisabled() override = default;
+
+ void SetUpCommandLine() override {
+ // Set up with no --ipc-socket-path
+ const base::CommandLine::CharType* argv[] = {"program"};
+ base::CommandLine::Init(arraysize(argv), argv);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IPCLinuxTestDisabled);
+};
+
+class TestDelegate : public ipc::IPCManager::Delegate,
+ public base::SupportsWeakPtr<TestDelegate> {
+ public:
+ TestDelegate() : started_count_(0), stopped_count_(0) {}
+
+ void OnIPCHandlerStarted(ipc::IPCManager::Type type) override {
+ ASSERT_EQ(ipc::IPCManager::TYPE_LINUX, type);
+ started_count_++;
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ void OnIPCHandlerStopped(ipc::IPCManager::Type type) override {
+ ASSERT_EQ(ipc::IPCManager::TYPE_LINUX, type);
+ stopped_count_++;
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+
+ int started_count() const { return started_count_; }
+ int stopped_count() const { return stopped_count_; }
+
+ private:
+ int started_count_;
+ int stopped_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+TEST_F(IPCLinuxTestDisabled, StartWithNoSocketPath) {
+ TestDelegate delegate;
+ EXPECT_FALSE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+ EXPECT_FALSE(ipc_manager_->LinuxStarted());
+ EXPECT_EQ(0, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+}
+
+TEST_F(IPCLinuxTest, BasicStartAndExit) {
+ TestDelegate delegate;
+ EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+ EXPECT_TRUE(ipc_manager_->LinuxStarted());
+
+ // Run the message loop. We will stop the loop when we receive a delegate
+ // event.
+ message_loop_.Run();
+
+ // We should have received the started event.
+ EXPECT_EQ(1, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+
+ // At this point the thread is blocking on accept and listening for incoming
+ // connections. TearDown should gracefully clean up the thread and the test
+ // should succeed without hanging.
+ ipc_manager_.reset();
+ message_loop_.Run();
+ EXPECT_EQ(1, delegate.stopped_count());
+}
+
+TEST_F(IPCLinuxTest, BasicStartAndConnect) {
+ TestDelegate delegate;
+ EXPECT_TRUE(ipc_manager_->Start(ipc::IPCManager::TYPE_LINUX, &delegate));
+ EXPECT_TRUE(ipc_manager_->LinuxStarted());
+
+ // Run the message loop. We will stop the loop when we receive a delegate
+ // event.
+ message_loop_.Run();
+
+ // We should have received the started event.
+ EXPECT_EQ(1, delegate.started_count());
+ EXPECT_EQ(0, delegate.stopped_count());
+
+ // IPC successfully started. Now attempt to connect to the socket.
+ ConnectToTestSocket();
+
+ // TODO(armansito): Test that the IPC event loop shuts down cleanly while a
+ // client is connected. Currently this will fail and the fix is to use
+ // MessageLoopForIO rather than a custom event loop.
+}
+
+} // namespace
diff --git a/mtkbt/code/bt/service/test/low_energy_advertiser_unittest.cc b/mtkbt/code/bt/service/test/low_energy_advertiser_unittest.cc
new file mode 100755
index 0000000..03188d7
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/low_energy_advertiser_unittest.cc
@@ -0,0 +1,639 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_advertiser.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Exactly;
+using ::testing::Invoke;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::Matcher;
+using status_cb = base::Callback<void(uint8_t)>;
+using reg_cb =
+ base::Callback<void(uint8_t /* advertiser_id */, uint8_t /* status */)>;
+
+namespace bluetooth {
+namespace {
+
+class MockAdvertiserHandler : public BleAdvertiserInterface {
+ public:
+ MockAdvertiserHandler() {}
+ ~MockAdvertiserHandler() override = default;
+
+ MOCK_METHOD1(RegisterAdvertiser, void(IdStatusCallback));
+ MOCK_METHOD1(Unregister, void(uint8_t));
+ MOCK_METHOD2(GetOwnAddress, void(uint8_t, GetAddressCallback));
+ MOCK_METHOD3(SetParameters,
+ void(uint8_t, AdvertiseParameters, ParametersCallback));
+ MOCK_METHOD4(SetData, void(int, bool, std::vector<uint8_t>, StatusCallback));
+ MOCK_METHOD6(Enable, void(uint8_t, bool, StatusCallback, uint16_t, uint8_t,
+ StatusCallback));
+ MOCK_METHOD7(StartAdvertising,
+ void(uint8_t advertiser_id, StatusCallback cb,
+ AdvertiseParameters, std::vector<uint8_t>,
+ std::vector<uint8_t>, int, StatusCallback));
+ MOCK_METHOD9(StartAdvertisingSet,
+ void(IdTxPowerStatusCallback cb, AdvertiseParameters params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data,
+ PeriodicAdvertisingParameters periodic_params,
+ std::vector<uint8_t> periodic_data, uint16_t duration,
+ uint8_t maxExtAdvEvents, IdStatusCallback timeout_cb));
+ MOCK_METHOD3(SetPeriodicAdvertisingParameters,
+ void(int, PeriodicAdvertisingParameters, StatusCallback));
+ MOCK_METHOD3(SetPeriodicAdvertisingData,
+ void(int, std::vector<uint8_t>, StatusCallback));
+ MOCK_METHOD3(SetPeriodicAdvertisingEnable, void(int, bool, StatusCallback));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAdvertiserHandler);
+};
+
+class LowEnergyAdvertiserTest : public ::testing::Test {
+ public:
+ LowEnergyAdvertiserTest() = default;
+ ~LowEnergyAdvertiserTest() override = default;
+
+ void SetUp() override {
+ // Only set |mock_handler_| if a test hasn't set it.
+ if (!mock_handler_) mock_handler_.reset(new MockAdvertiserHandler());
+ hal::BluetoothGattInterface::InitializeForTesting(
+ new hal::FakeBluetoothGattInterface(
+ std::static_pointer_cast<BleAdvertiserInterface>(mock_handler_),
+ nullptr, nullptr, nullptr));
+ ble_advertiser_factory_.reset(new LowEnergyAdvertiserFactory());
+ }
+
+ void TearDown() override {
+ ble_advertiser_factory_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ }
+
+ protected:
+ std::shared_ptr<MockAdvertiserHandler> mock_handler_;
+ std::unique_ptr<LowEnergyAdvertiserFactory> ble_advertiser_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserTest);
+};
+
+// Used for tests that operate on a pre-registered advertiser.
+class LowEnergyAdvertiserPostRegisterTest : public LowEnergyAdvertiserTest {
+ public:
+ LowEnergyAdvertiserPostRegisterTest() : next_client_id_(0) {}
+ ~LowEnergyAdvertiserPostRegisterTest() override = default;
+
+ void SetUp() override {
+ LowEnergyAdvertiserTest::SetUp();
+ auto callback = [&](std::unique_ptr<LowEnergyAdvertiser> advertiser) {
+ le_advertiser_ = std::move(advertiser);
+ };
+ RegisterTestAdvertiser(callback);
+ }
+
+ void TearDown() override {
+ EXPECT_CALL(*mock_handler_, Enable(_, false, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_handler_, Unregister(_)).Times(1);
+ le_advertiser_.reset();
+ LowEnergyAdvertiserTest::TearDown();
+ }
+
+ void RegisterTestAdvertiser(
+ const std::function<void(std::unique_ptr<LowEnergyAdvertiser> advertiser)>
+ callback) {
+ UUID uuid = UUID::GetRandom();
+ auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_client.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ callback(std::unique_ptr<LowEnergyAdvertiser>(
+ static_cast<LowEnergyAdvertiser*>(in_client.release())));
+ };
+
+ reg_cb reg_adv_cb;
+ EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_adv_cb));
+
+ ble_advertiser_factory_->RegisterInstance(uuid, api_callback);
+
+ reg_adv_cb.Run(next_client_id_++, BT_STATUS_SUCCESS);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+ }
+
+ void StartAdvertising() {
+ ASSERT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ ASSERT_FALSE(le_advertiser_->IsStartingAdvertising());
+ ASSERT_FALSE(le_advertiser_->IsStoppingAdvertising());
+
+ status_cb start_advertising_cb;
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ status_cb set_data_cb;
+
+ AdvertiseSettings settings;
+ AdvertiseData adv, scan_rsp;
+ ASSERT_TRUE(le_advertiser_->StartAdvertising(
+ settings, adv, scan_rsp, LowEnergyAdvertiser::StatusCallback()));
+ ASSERT_TRUE(le_advertiser_->IsStartingAdvertising());
+
+ start_advertising_cb.Run(BT_STATUS_SUCCESS);
+
+ ASSERT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ ASSERT_FALSE(le_advertiser_->IsStartingAdvertising());
+ ASSERT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ }
+
+ void AdvertiseDataTestHelper(AdvertiseData data,
+ std::function<void(BLEStatus)> callback,
+ status_cb* set_data_cb) {
+ AdvertiseSettings settings;
+
+ LOG_ASSERT(set_data_cb) << "set_data_cb must be set";
+
+ EXPECT_TRUE(le_advertiser_->StartAdvertising(settings, data,
+ AdvertiseData(), callback));
+
+ set_data_cb->Run(BT_STATUS_SUCCESS);
+
+ status_cb disable_cb;
+ EXPECT_CALL(*mock_handler_, Enable(_, false, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<2>(&disable_cb));
+
+ EXPECT_TRUE(
+ le_advertiser_->StopAdvertising(LowEnergyAdvertiser::StatusCallback()));
+ disable_cb.Run(BT_STATUS_SUCCESS);
+ }
+
+ protected:
+ std::unique_ptr<LowEnergyAdvertiser> le_advertiser_;
+
+ private:
+ int next_client_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyAdvertiserPostRegisterTest);
+};
+
+TEST_F(LowEnergyAdvertiserTest, RegisterInstance) {
+ // These will be asynchronously populated with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ UUID cb_uuid;
+ std::unique_ptr<LowEnergyAdvertiser> advertiser;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const UUID& uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ status = in_status;
+ cb_uuid = uuid;
+ advertiser = std::unique_ptr<LowEnergyAdvertiser>(
+ static_cast<LowEnergyAdvertiser*>(in_client.release()));
+ callback_count++;
+ };
+
+ UUID uuid0 = UUID::GetRandom();
+
+ reg_cb reg_adv1_cb;
+ EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_adv1_cb));
+
+ // Success.
+ EXPECT_TRUE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // Calling twice with the same UUID should fail with no additional call into
+ // the stack.
+ EXPECT_FALSE(ble_advertiser_factory_->RegisterInstance(uuid0, callback));
+
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Call with a different UUID while one is pending.
+ UUID uuid1 = UUID::GetRandom();
+ reg_cb reg_adv2_cb;
+ EXPECT_CALL(*mock_handler_, RegisterAdvertiser(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_adv2_cb));
+ EXPECT_TRUE(ble_advertiser_factory_->RegisterInstance(uuid1, callback));
+
+ // |uuid0| succeeds.
+ int client_if0 = 2; // Pick something that's not 0.
+ reg_adv1_cb.Run(client_if0, BT_STATUS_SUCCESS);
+
+ EXPECT_EQ(1, callback_count);
+ ASSERT_TRUE(advertiser.get() !=
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(client_if0, advertiser->GetInstanceId());
+ EXPECT_EQ(uuid0, advertiser->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ // The advertiser should unregister itself when deleted.
+ EXPECT_CALL(*mock_handler_, Enable(client_if0, false, _, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_handler_, Unregister(client_if0)).Times(1);
+ advertiser.reset();
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // |uuid1| fails.
+ uint8_t client_if1 = 10;
+ reg_adv2_cb.Run(client_if1, BT_STATUS_FAIL);
+
+ EXPECT_EQ(2, callback_count);
+ ASSERT_TRUE(advertiser.get() ==
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_FAILURE, status);
+ EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, StartAdvertisingBasic) {
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+
+ // Use default advertising settings and data.
+ AdvertiseSettings settings;
+ AdvertiseData adv_data, scan_rsp;
+ int callback_count = 0;
+ BLEStatus last_status = BLE_STATUS_FAILURE;
+ auto callback = [&](BLEStatus status) {
+ last_status = status;
+ callback_count++;
+ };
+
+ status_cb start_advertising_cb;
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(SaveArg<1>(&start_advertising_cb));
+
+ // Stack call returns success.
+ EXPECT_TRUE(
+ le_advertiser_->StartAdvertising(settings, adv_data, scan_rsp, callback));
+
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(0, callback_count);
+
+ // Already starting.
+ EXPECT_FALSE(
+ le_advertiser_->StartAdvertising(settings, adv_data, scan_rsp, callback));
+
+ // Notify failure.
+ start_advertising_cb.Run(BT_STATUS_FAIL);
+
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(1, callback_count);
+ EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+
+ // Try again.
+ EXPECT_TRUE(
+ le_advertiser_->StartAdvertising(settings, adv_data, scan_rsp, callback));
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_TRUE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(1, callback_count);
+
+ start_advertising_cb.Run(BT_STATUS_SUCCESS);
+
+ EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(2, callback_count);
+ EXPECT_EQ(BLE_STATUS_SUCCESS, last_status);
+
+ // Already started.
+ EXPECT_FALSE(
+ le_advertiser_->StartAdvertising(settings, adv_data, scan_rsp, callback));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, StopAdvertisingBasic) {
+ AdvertiseSettings settings;
+
+ // Not enabled.
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(
+ le_advertiser_->StopAdvertising(LowEnergyAdvertiser::StatusCallback()));
+
+ // Start advertising for testing.
+ StartAdvertising();
+
+ int callback_count = 0;
+ BLEStatus last_status = BLE_STATUS_FAILURE;
+ auto callback = [&](BLEStatus status) {
+ last_status = status;
+ callback_count++;
+ };
+
+ status_cb enable_cb;
+ EXPECT_CALL(*mock_handler_, Enable(_, false, _, _, _, _))
+ .Times(2)
+ .WillRepeatedly(SaveArg<2>(&enable_cb));
+
+ // Stack returns success.
+ EXPECT_TRUE(le_advertiser_->StopAdvertising(callback));
+ EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(0, callback_count);
+
+ // Already disabling.
+ EXPECT_FALSE(le_advertiser_->StopAdvertising(callback));
+ EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(0, callback_count);
+
+ // Notify failure.
+ enable_cb.Run(BT_STATUS_FAIL);
+ EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(1, callback_count);
+ EXPECT_EQ(BLE_STATUS_FAILURE, last_status);
+
+ // Try again.
+ EXPECT_TRUE(le_advertiser_->StopAdvertising(callback));
+ EXPECT_TRUE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_TRUE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(1, callback_count);
+
+ // Notify success.
+ enable_cb.Run(BT_STATUS_SUCCESS);
+ EXPECT_FALSE(le_advertiser_->IsAdvertisingStarted());
+ EXPECT_FALSE(le_advertiser_->IsStartingAdvertising());
+ EXPECT_FALSE(le_advertiser_->IsStoppingAdvertising());
+ EXPECT_EQ(2, callback_count);
+ EXPECT_EQ(BLE_STATUS_SUCCESS, last_status);
+
+ // Already stopped.
+ EXPECT_FALSE(le_advertiser_->StopAdvertising(callback));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, InvalidAdvertiseData) {
+ const std::vector<uint8_t> data0{0x02, HCI_EIR_FLAGS_TYPE, 0x00};
+ const std::vector<uint8_t> data1{0x04, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE,
+ 0x01, 0x02, 0x00};
+ AdvertiseData invalid_adv(data0);
+ AdvertiseData valid_adv(data1);
+
+ AdvertiseSettings settings;
+
+ EXPECT_FALSE(le_advertiser_->StartAdvertising(
+ settings, valid_adv, invalid_adv, LowEnergyAdvertiser::StatusCallback()));
+ EXPECT_FALSE(le_advertiser_->StartAdvertising(
+ settings, invalid_adv, valid_adv, LowEnergyAdvertiser::StatusCallback()));
+
+ // Manufacturer data not correctly formatted according to spec. We let the
+ // stack handle this case.
+ const std::vector<uint8_t> data2{0x01, HCI_EIR_MANUFACTURER_SPECIFIC_TYPE};
+ AdvertiseData invalid_mfc(data2);
+
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _)).Times(1);
+ EXPECT_TRUE(le_advertiser_->StartAdvertising(
+ settings, invalid_mfc, valid_adv, LowEnergyAdvertiser::StatusCallback()));
+}
+
+TEST_F(LowEnergyAdvertiserPostRegisterTest, AdvertiseDataParsing) {
+ const std::vector<uint8_t> kUUID16BitData{
+ 0x03, HCI_EIR_COMPLETE_16BITS_UUID_TYPE, 0xDE, 0xAD,
+ };
+
+ const std::vector<uint8_t> kUUID32BitData{
+ 0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02};
+
+ const std::vector<uint8_t> kUUID128BitData{
+ 0x11, HCI_EIR_COMPLETE_128BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x03, 0x04,
+ 0x05, 0x06,
+ 0x07, 0x08,
+ 0x09, 0x0A,
+ 0x0B, 0x0C,
+ 0x0D, 0x0E};
+
+ const std::vector<uint8_t> kMultiUUIDData{
+ 0x11, HCI_EIR_COMPLETE_128BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x03, 0x04,
+ 0x05, 0x06,
+ 0x07, 0x08,
+ 0x09, 0x0A,
+ 0x0B, 0x0C,
+ 0x0D, 0x0E,
+ 0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0xBE, 0xEF};
+
+ const std::vector<uint8_t> kServiceData16Bit{
+ 0x05, HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE, 0xDE, 0xAD, 0xBE, 0xEF};
+
+ const std::vector<uint8_t> kServiceData32Bit{
+ 0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE, 0xDE, 0xAD, 0x01, 0x02, 0xBE,
+ 0xEF};
+
+ const std::vector<uint8_t> kServiceData128Bit{
+ 0x13, HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x03, 0x04,
+ 0x05, 0x06,
+ 0x07, 0x08,
+ 0x09, 0x0A,
+ 0x0B, 0x0C,
+ 0x0D, 0x0E,
+ 0xBE, 0xEF};
+
+ const std::vector<uint8_t> kMultiServiceData{
+ 0x13, HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x03, 0x04,
+ 0x05, 0x06,
+ 0xBE, 0xEF,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x03, 0x04,
+ 0x05, 0x06,
+ 0x05, HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0xBE, 0xEF};
+
+ const std::vector<uint8_t> kServiceUUIDMatch{
+ 0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0xBE, 0xEF};
+
+ const std::vector<uint8_t> kServiceUUIDMismatch{
+ 0x05, HCI_EIR_COMPLETE_32BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x01,
+ 0x07, HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE,
+ 0xDE, 0xAD,
+ 0x01, 0x02,
+ 0xBE, 0xEF};
+
+ AdvertiseData uuid_16bit_adv(kUUID16BitData);
+ AdvertiseData uuid_32bit_adv(kUUID32BitData);
+ AdvertiseData uuid_128bit_adv(kUUID128BitData);
+ AdvertiseData multi_uuid_adv(kMultiUUIDData);
+
+ AdvertiseData service_16bit_adv(kServiceData16Bit);
+ AdvertiseData service_32bit_adv(kServiceData32Bit);
+ AdvertiseData service_128bit_adv(kServiceData128Bit);
+ AdvertiseData multi_service_adv(kMultiServiceData);
+
+ AdvertiseData service_uuid_match(kServiceUUIDMatch);
+ AdvertiseData service_uuid_mismatch(kServiceUUIDMismatch);
+
+ AdvertiseSettings settings;
+
+ int callback_count = 0;
+ BLEStatus last_status = BLE_STATUS_FAILURE;
+ auto callback = [&](BLEStatus status) {
+ last_status = status;
+ callback_count++;
+ };
+
+ status_cb start_advertising_cb;
+ // Multiple UUID test
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(multi_uuid_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(1, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Multiple Service Data test
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(multi_service_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(2, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // 16bit uuid test, should succeed with correctly parsed uuid in little-endian
+ // 128-bit format.
+ const std::vector<uint8_t> uuid_16bit_canonical{
+ 0xFB, 0x34, 0x9b, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0xDE, 0xAD, 0x00, 0x00};
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(uuid_16bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(3, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // 32bit uuid test, should succeed with correctly parsed uuid
+ const std::vector<uint8_t> uuid_32bit_canonical{
+ 0xFB, 0x34, 0x9b, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0xDE, 0xAD, 0x01, 0x02};
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(uuid_32bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(4, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // 128bit uuid test, should succeed with correctly parsed uuid
+ const std::vector<uint8_t> uuid_128bit{0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E};
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(uuid_128bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(5, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ const std::vector<uint8_t> service_data{0xBE, 0xEF};
+
+ // Service data with 16bit uuid included, should succeed with
+ // uuid and service data parsed out
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(service_16bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(6, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Service data with 32bit uuid included, should succeed with
+ // uuid and service data parsed out
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(service_32bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(7, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Service data with 128bit uuid included, should succeed with
+ // uuid and service data parsed out
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(service_128bit_adv, callback, &start_advertising_cb);
+ EXPECT_EQ(8, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Service data and UUID where the UUID for both match, should succeed.
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(service_uuid_match, callback, &start_advertising_cb);
+ EXPECT_EQ(9, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Service data and UUID where the UUID for dont match, should fail
+ EXPECT_CALL(*mock_handler_, StartAdvertising(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&start_advertising_cb));
+ AdvertiseDataTestHelper(service_uuid_match, callback, &start_advertising_cb);
+ EXPECT_EQ(10, callback_count);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
+ " bitwise equal to " + ::testing::PrintToString(x)) {
+ static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
+ return std::memcmp(&arg, &x, sizeof(x)) == 0;
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/low_energy_client_unittest.cc b/mtkbt/code/bt/service/test/low_energy_client_unittest.cc
new file mode 100755
index 0000000..99eb934
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/low_energy_client_unittest.cc
@@ -0,0 +1,304 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_client.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::Pointee;
+using ::testing::DoAll;
+using ::testing::Invoke;
+
+namespace bluetooth {
+namespace {
+
+class MockGattHandler
+ : public hal::FakeBluetoothGattInterface::TestClientHandler {
+ public:
+ MockGattHandler(){};
+ ~MockGattHandler() override = default;
+
+ MOCK_METHOD1(RegisterClient, bt_status_t(bt_uuid_t*));
+ MOCK_METHOD1(UnregisterClient, bt_status_t(int));
+ MOCK_METHOD4(Connect, bt_status_t(int, const bt_bdaddr_t*, bool, int));
+ MOCK_METHOD3(Disconnect, bt_status_t(int, const bt_bdaddr_t*, int));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGattHandler);
+};
+
+class TestDelegate : public LowEnergyClient::Delegate {
+ public:
+ TestDelegate() : connection_state_count_(0), last_mtu_(0) {}
+
+ ~TestDelegate() override = default;
+
+ int connection_state_count() const { return connection_state_count_; }
+
+ void OnConnectionState(LowEnergyClient* client, int status,
+ const char* address, bool connected) {
+ ASSERT_TRUE(client);
+ connection_state_count_++;
+ }
+
+ void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
+ int mtu) {
+ ASSERT_TRUE(client);
+ last_mtu_ = mtu;
+ }
+
+ private:
+ int connection_state_count_;
+
+ int last_mtu_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+class LowEnergyClientTest : public ::testing::Test {
+ public:
+ LowEnergyClientTest() = default;
+ ~LowEnergyClientTest() override = default;
+
+ void SetUp() override {
+ // Only set |mock_handler_| if a test hasn't set it.
+ if (!mock_handler_) mock_handler_.reset(new MockGattHandler());
+ fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+ nullptr, nullptr,
+ std::static_pointer_cast<
+ hal::FakeBluetoothGattInterface::TestClientHandler>(mock_handler_),
+ nullptr);
+ hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+ ble_factory_.reset(new LowEnergyClientFactory(mock_adapter_));
+ }
+
+ void TearDown() override {
+ ble_factory_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+ testing::MockAdapter mock_adapter_;
+ std::shared_ptr<MockGattHandler> mock_handler_;
+ std::unique_ptr<LowEnergyClientFactory> ble_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyClientTest);
+};
+
+// Used for tests that operate on a pre-registered client.
+class LowEnergyClientPostRegisterTest : public LowEnergyClientTest {
+ public:
+ LowEnergyClientPostRegisterTest() : next_client_id_(0) {}
+ ~LowEnergyClientPostRegisterTest() override = default;
+
+ void SetUp() override {
+ LowEnergyClientTest::SetUp();
+ auto callback = [&](std::unique_ptr<LowEnergyClient> client) {
+ le_client_ = std::move(client);
+ };
+ RegisterTestClient(callback);
+ }
+
+ void TearDown() override {
+ EXPECT_CALL(*mock_handler_, UnregisterClient(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ le_client_.reset();
+ LowEnergyClientTest::TearDown();
+ }
+
+ void RegisterTestClient(
+ const std::function<void(std::unique_ptr<LowEnergyClient> client)>
+ callback) {
+ UUID uuid = UUID::GetRandom();
+ auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_client.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ callback(std::unique_ptr<LowEnergyClient>(
+ static_cast<LowEnergyClient*>(in_client.release())));
+ };
+
+ EXPECT_CALL(*mock_handler_, RegisterClient(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ ble_factory_->RegisterInstance(uuid, api_callback);
+
+ bt_uuid_t hal_uuid = uuid.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, next_client_id_++,
+ hal_uuid);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+ }
+
+ protected:
+ std::unique_ptr<LowEnergyClient> le_client_;
+
+ private:
+ int next_client_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyClientPostRegisterTest);
+};
+
+TEST_F(LowEnergyClientTest, RegisterInstance) {
+ EXPECT_CALL(*mock_handler_, RegisterClient(_))
+ .Times(2)
+ .WillOnce(Return(BT_STATUS_FAIL))
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+
+ // These will be asynchronously populated with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ UUID cb_uuid;
+ std::unique_ptr<LowEnergyClient> client;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const UUID& uuid,
+ std::unique_ptr<BluetoothInstance> in_client) {
+ status = in_status;
+ cb_uuid = uuid;
+ client = std::unique_ptr<LowEnergyClient>(
+ static_cast<LowEnergyClient*>(in_client.release()));
+ callback_count++;
+ };
+
+ UUID uuid0 = UUID::GetRandom();
+
+ // HAL returns failure.
+ EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // HAL returns success.
+ EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // Calling twice with the same UUID should fail with no additional call into
+ // the stack.
+ EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Call with a different UUID while one is pending.
+ UUID uuid1 = UUID::GetRandom();
+ EXPECT_CALL(*mock_handler_, RegisterClient(_))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
+
+ // Trigger callback with an unknown UUID. This should get ignored.
+ UUID uuid2 = UUID::GetRandom();
+ bt_uuid_t hal_uuid = uuid2.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(0, 0, hal_uuid);
+ EXPECT_EQ(0, callback_count);
+
+ // |uuid0| succeeds.
+ int client_if0 = 2; // Pick something that's not 0.
+ hal_uuid = uuid0.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_SUCCESS,
+ client_if0, hal_uuid);
+
+ EXPECT_EQ(1, callback_count);
+ ASSERT_TRUE(client.get() != nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(client_if0, client->GetInstanceId());
+ EXPECT_EQ(uuid0, client->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ // The client should unregister itself when deleted.
+ EXPECT_CALL(*mock_handler_, UnregisterClient(client_if0))
+ .Times(1)
+ .WillOnce(Return(BT_STATUS_SUCCESS));
+ client.reset();
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // |uuid1| fails.
+ int client_if1 = 3;
+ hal_uuid = uuid1.GetBlueDroid();
+ fake_hal_gatt_iface_->NotifyRegisterClientCallback(BT_STATUS_FAIL, client_if1,
+ hal_uuid);
+
+ EXPECT_EQ(2, callback_count);
+ ASSERT_TRUE(client.get() == nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_FAILURE, status);
+ EXPECT_EQ(uuid1, cb_uuid);
+}
+
+MATCHER_P(BitEq, x, std::string(negation ? "isn't" : "is") +
+ " bitwise equal to " + ::testing::PrintToString(x)) {
+ static_assert(sizeof(x) == sizeof(arg), "Size mismatch");
+ return std::memcmp(&arg, &x, sizeof(x)) == 0;
+}
+
+TEST_F(LowEnergyClientPostRegisterTest, Connect) {
+ const bt_bdaddr_t kTestAddress = {{0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C}};
+ const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
+ const bool kTestDirect = false;
+ const int connId = 12;
+
+ TestDelegate delegate;
+ le_client_->SetDelegate(&delegate);
+
+ // TODO(jpawlowski): NotifyConnectCallback should be called after returning
+ // success, fix it when it becomes important.
+ // These should succeed and result in a HAL call
+ EXPECT_CALL(*mock_handler_,
+ Connect(le_client_->GetInstanceId(), Pointee(BitEq(kTestAddress)),
+ kTestDirect, BT_TRANSPORT_LE))
+ .Times(1)
+ .WillOnce(DoAll(Invoke([&](int client_id, const bt_bdaddr_t* bd_addr,
+ bool is_direct, int transport) {
+ fake_hal_gatt_iface_->NotifyConnectCallback(
+ connId, BT_STATUS_SUCCESS, client_id, *bd_addr);
+ }),
+ Return(BT_STATUS_SUCCESS)));
+
+ EXPECT_TRUE(le_client_->Connect(kTestAddressStr, kTestDirect));
+ EXPECT_EQ(1, delegate.connection_state_count());
+
+ // TODO(jpawlowski): same as above
+ // These should succeed and result in a HAL call
+ EXPECT_CALL(*mock_handler_, Disconnect(le_client_->GetInstanceId(),
+ Pointee(BitEq(kTestAddress)), connId))
+ .Times(1)
+ .WillOnce(DoAll(
+ Invoke([&](int client_id, const bt_bdaddr_t* bd_addr, int connId) {
+ fake_hal_gatt_iface_->NotifyDisconnectCallback(
+ connId, BT_STATUS_SUCCESS, client_id, *bd_addr);
+ }),
+ Return(BT_STATUS_SUCCESS)));
+
+ EXPECT_TRUE(le_client_->Disconnect(kTestAddressStr));
+ EXPECT_EQ(2, delegate.connection_state_count());
+
+ le_client_->SetDelegate(nullptr);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/low_energy_scanner_unittest.cc b/mtkbt/code/bt/service/test/low_energy_scanner_unittest.cc
new file mode 100755
index 0000000..dc20ecf
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/low_energy_scanner_unittest.cc
@@ -0,0 +1,354 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "service/adapter.h"
+#include "service/hal/fake_bluetooth_gatt_interface.h"
+#include "service/low_energy_scanner.h"
+#include "stack/include/bt_types.h"
+#include "stack/include/hcidefs.h"
+#include "test/mock_adapter.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::Pointee;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::SaveArg;
+
+namespace bluetooth {
+namespace {
+
+class MockScannerHandler : public BleScannerInterface {
+ public:
+ MockScannerHandler() {}
+ ~MockScannerHandler() override = default;
+
+ MOCK_METHOD1(RegisterScanner, void(BleScannerInterface::RegisterCallback));
+ MOCK_METHOD1(Unregister, void(int));
+ MOCK_METHOD1(Scan, void(bool));
+
+ MOCK_METHOD5(ScanFilterParamSetupImpl,
+ void(uint8_t client_if, uint8_t action, uint8_t filt_index,
+ btgatt_filt_param_setup_t* filt_param,
+ FilterParamSetupCallback cb));
+ MOCK_METHOD2(ScanFilterClear, void(int filt_index, FilterConfigCallback cb));
+ MOCK_METHOD2(ScanFilterEnable, void(bool enable, EnableCallback cb));
+ MOCK_METHOD3(SetScanParameters,
+ void(int scan_interval, int scan_window, Callback cb));
+
+ MOCK_METHOD5(BatchscanConfigStorage,
+ void(int client_if, int batch_scan_full_max,
+ int batch_scan_trunc_max, int batch_scan_notify_threshold,
+ Callback cb));
+
+ MOCK_METHOD6(BatchscanEnable,
+ void(int scan_mode, int scan_interval, int scan_window,
+ int addr_type, int discard_rule, Callback cb));
+
+ MOCK_METHOD1(BatchscanDisable, void(Callback cb));
+
+ MOCK_METHOD2(BatchscanReadReports, void(int client_if, int scan_mode));
+
+ MOCK_METHOD7(StartSync, void(uint8_t, bt_bdaddr_t, uint16_t, uint16_t,
+ StartSyncCb, SyncReportCb, SyncLostCb));
+ MOCK_METHOD1(StopSync, void(uint16_t));
+
+ void ScanFilterAddRemove(int action, int filt_type, int filt_index,
+ int company_id, int company_id_mask,
+ const bt_uuid_t* p_uuid,
+ const bt_uuid_t* p_uuid_mask,
+ const bt_bdaddr_t* bd_addr, char addr_type,
+ std::vector<uint8_t> data,
+ std::vector<uint8_t> p_mask,
+ FilterConfigCallback cb){};
+
+ void ScanFilterParamSetup(
+ uint8_t client_if, uint8_t action, uint8_t filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
+ FilterParamSetupCallback cb) {
+ ScanFilterParamSetupImpl(client_if, action, filt_index, filt_param.get(),
+ std::move(cb));
+ }
+};
+
+class TestDelegate : public LowEnergyScanner::Delegate {
+ public:
+ TestDelegate() : scan_result_count_(0) {}
+
+ ~TestDelegate() override = default;
+
+ int scan_result_count() const { return scan_result_count_; }
+ const ScanResult& last_scan_result() const { return last_scan_result_; }
+
+ void OnScanResult(LowEnergyScanner* scanner, const ScanResult& scan_result) {
+ ASSERT_TRUE(scanner);
+ scan_result_count_++;
+ last_scan_result_ = scan_result;
+ }
+
+ private:
+ int scan_result_count_;
+ ScanResult last_scan_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+class LowEnergyScannerTest : public ::testing::Test {
+ public:
+ LowEnergyScannerTest() = default;
+ ~LowEnergyScannerTest() override = default;
+
+ void SetUp() override {
+ // Only set |mock_handler_| if a test hasn't set it.
+ if (!mock_handler_) mock_handler_.reset(new MockScannerHandler());
+ fake_hal_gatt_iface_ = new hal::FakeBluetoothGattInterface(
+ nullptr, std::static_pointer_cast<BleScannerInterface>(mock_handler_),
+ nullptr, nullptr);
+ hal::BluetoothGattInterface::InitializeForTesting(fake_hal_gatt_iface_);
+ ble_factory_.reset(new LowEnergyScannerFactory(mock_adapter_));
+ }
+
+ void TearDown() override {
+ ble_factory_.reset();
+ hal::BluetoothGattInterface::CleanUp();
+ }
+
+ protected:
+ hal::FakeBluetoothGattInterface* fake_hal_gatt_iface_;
+ testing::MockAdapter mock_adapter_;
+ std::shared_ptr<MockScannerHandler> mock_handler_;
+ std::unique_ptr<LowEnergyScannerFactory> ble_factory_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerTest);
+};
+
+// Used for tests that operate on a pre-registered scanner.
+class LowEnergyScannerPostRegisterTest : public LowEnergyScannerTest {
+ public:
+ LowEnergyScannerPostRegisterTest() : next_scanner_id_(0) {}
+ ~LowEnergyScannerPostRegisterTest() override = default;
+
+ void SetUp() override {
+ LowEnergyScannerTest::SetUp();
+ auto callback = [&](std::unique_ptr<LowEnergyScanner> scanner) {
+ le_scanner_ = std::move(scanner);
+ };
+ RegisterTestScanner(callback);
+ }
+
+ void TearDown() override {
+ EXPECT_CALL(*mock_handler_, Unregister(_)).Times(1).WillOnce(Return());
+ le_scanner_.reset();
+ LowEnergyScannerTest::TearDown();
+ }
+
+ void RegisterTestScanner(
+ const std::function<void(std::unique_ptr<LowEnergyScanner> scanner)>
+ callback) {
+ UUID uuid = UUID::GetRandom();
+ auto api_callback = [&](BLEStatus status, const UUID& in_uuid,
+ std::unique_ptr<BluetoothInstance> in_scanner) {
+ CHECK(in_uuid == uuid);
+ CHECK(in_scanner.get());
+ CHECK(status == BLE_STATUS_SUCCESS);
+
+ callback(std::unique_ptr<LowEnergyScanner>(
+ static_cast<LowEnergyScanner*>(in_scanner.release())));
+ };
+
+ BleScannerInterface::RegisterCallback reg_scanner_cb;
+ EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_scanner_cb));
+
+ ble_factory_->RegisterInstance(uuid, api_callback);
+
+ reg_scanner_cb.Run(next_scanner_id_++, BT_STATUS_SUCCESS);
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+ }
+
+ protected:
+ std::unique_ptr<LowEnergyScanner> le_scanner_;
+
+ private:
+ int next_scanner_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(LowEnergyScannerPostRegisterTest);
+};
+
+TEST_F(LowEnergyScannerTest, RegisterInstance) {
+ BleScannerInterface::RegisterCallback reg_scanner_cb1;
+ EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_scanner_cb1));
+
+ // These will be asynchronously populated with a result when the callback
+ // executes.
+ BLEStatus status = BLE_STATUS_SUCCESS;
+ UUID cb_uuid;
+ std::unique_ptr<LowEnergyScanner> scanner;
+ int callback_count = 0;
+
+ auto callback = [&](BLEStatus in_status, const UUID& uuid,
+ std::unique_ptr<BluetoothInstance> in_scanner) {
+ status = in_status;
+ cb_uuid = uuid;
+ scanner = std::unique_ptr<LowEnergyScanner>(
+ static_cast<LowEnergyScanner*>(in_scanner.release()));
+ callback_count++;
+ };
+
+ UUID uuid0 = UUID::GetRandom();
+
+ // HAL returns success.
+ EXPECT_TRUE(ble_factory_->RegisterInstance(uuid0, callback));
+ EXPECT_EQ(0, callback_count);
+
+ // Calling twice with the same UUID should fail with no additional call into
+ // the stack.
+ EXPECT_FALSE(ble_factory_->RegisterInstance(uuid0, callback));
+
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // Call with a different UUID while one is pending.
+ UUID uuid1 = UUID::GetRandom();
+ BleScannerInterface::RegisterCallback reg_scanner_cb2;
+ EXPECT_CALL(*mock_handler_, RegisterScanner(_))
+ .Times(1)
+ .WillOnce(SaveArg<0>(&reg_scanner_cb2));
+ EXPECT_TRUE(ble_factory_->RegisterInstance(uuid1, callback));
+
+ // |uuid0| succeeds.
+ int scanner_if0 = 2; // Pick something that's not 0.
+ reg_scanner_cb1.Run(scanner_if0, BT_STATUS_SUCCESS);
+
+ EXPECT_EQ(1, callback_count);
+ ASSERT_TRUE(scanner.get() !=
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_SUCCESS, status);
+ EXPECT_EQ(scanner_if0, scanner->GetInstanceId());
+ EXPECT_EQ(uuid0, scanner->GetAppIdentifier());
+ EXPECT_EQ(uuid0, cb_uuid);
+
+ // The scanner should unregister itself when deleted.
+ EXPECT_CALL(*mock_handler_, Unregister(scanner_if0))
+ .Times(1)
+ .WillOnce(Return());
+ scanner.reset();
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+
+ // |uuid1| fails.
+ int scanner_if1 = 3;
+ reg_scanner_cb2.Run(scanner_if1, BT_STATUS_FAIL);
+
+ EXPECT_EQ(2, callback_count);
+ ASSERT_TRUE(scanner.get() ==
+ nullptr); // Assert to terminate in case of error
+ EXPECT_EQ(BLE_STATUS_FAILURE, status);
+ EXPECT_EQ(uuid1, cb_uuid);
+}
+
+TEST_F(LowEnergyScannerPostRegisterTest, ScanSettings) {
+ EXPECT_CALL(mock_adapter_, IsEnabled())
+ .WillOnce(Return(false))
+ .WillRepeatedly(Return(true));
+
+ ScanSettings settings;
+ std::vector<ScanFilter> filters;
+
+ // Adapter is not enabled.
+ EXPECT_FALSE(le_scanner_->StartScan(settings, filters));
+
+ // TODO(jpawlowski): add tests checking settings and filter parsing when
+ // implemented
+
+ // These should succeed and result in a HAL call
+ EXPECT_CALL(*mock_handler_, Scan(true)).Times(1).WillOnce(Return());
+ EXPECT_TRUE(le_scanner_->StartScan(settings, filters));
+
+ // These should succeed and result in a HAL call
+ EXPECT_CALL(*mock_handler_, Scan(false)).Times(1).WillOnce(Return());
+ EXPECT_TRUE(le_scanner_->StopScan());
+
+ ::testing::Mock::VerifyAndClearExpectations(mock_handler_.get());
+}
+
+TEST_F(LowEnergyScannerPostRegisterTest, ScanRecord) {
+ TestDelegate delegate;
+ le_scanner_->SetDelegate(&delegate);
+
+ EXPECT_EQ(0, delegate.scan_result_count());
+
+ std::vector<uint8_t> kTestRecord0({0x02, 0x01, 0x00, 0x00});
+ std::vector<uint8_t> kTestRecord1({0x00});
+ std::vector<uint8_t> kTestRecord2(
+ {0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00});
+ const bt_bdaddr_t kTestAddress = {{0x01, 0x02, 0x03, 0x0A, 0x0B, 0x0C}};
+ const char kTestAddressStr[] = "01:02:03:0A:0B:0C";
+ const int kTestRssi = 64;
+
+ // Scan wasn't started. Result should be ignored.
+ fake_hal_gatt_iface_->NotifyScanResultCallback(kTestAddress, kTestRssi,
+ kTestRecord0);
+ EXPECT_EQ(0, delegate.scan_result_count());
+
+ // Start a scan session for |le_scanner_|.
+ EXPECT_CALL(mock_adapter_, IsEnabled()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*mock_handler_, Scan(_))
+ .Times(2)
+ .WillOnce(Return())
+ .WillOnce(Return());
+ ScanSettings settings;
+ std::vector<ScanFilter> filters;
+ ASSERT_TRUE(le_scanner_->StartScan(settings, filters));
+
+ fake_hal_gatt_iface_->NotifyScanResultCallback(kTestAddress, kTestRssi,
+ kTestRecord0);
+ EXPECT_EQ(1, delegate.scan_result_count());
+ EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+ EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+ EXPECT_EQ(3U, delegate.last_scan_result().scan_record().size());
+
+ fake_hal_gatt_iface_->NotifyScanResultCallback(kTestAddress, kTestRssi,
+ kTestRecord1);
+ EXPECT_EQ(2, delegate.scan_result_count());
+ EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+ EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+ EXPECT_TRUE(delegate.last_scan_result().scan_record().empty());
+
+ fake_hal_gatt_iface_->NotifyScanResultCallback(kTestAddress, kTestRssi,
+ kTestRecord2);
+ EXPECT_EQ(3, delegate.scan_result_count());
+ EXPECT_EQ(kTestAddressStr, delegate.last_scan_result().device_address());
+ EXPECT_EQ(kTestRssi, delegate.last_scan_result().rssi());
+ EXPECT_EQ(62U, delegate.last_scan_result().scan_record().size());
+
+ le_scanner_->SetDelegate(nullptr);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/main.cc b/mtkbt/code/bt/service/test/main.cc
new file mode 100755
index 0000000..55e0d07
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/main.cc
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+
+#include <gtest/gtest.h>
+
+GTEST_API_ int main(int argc, char** argv) {
+ base::AtExitManager exit_manager;
+ base::CommandLine::Init(argc, argv);
+ logging::LoggingSettings log_settings;
+ logging::InitLogging(log_settings);
+
+ LOG(INFO) << "Running Bluetooth daemon unit tests.";
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/mtkbt/code/bt/service/test/mock_adapter.h b/mtkbt/code/bt/service/test/mock_adapter.h
new file mode 100755
index 0000000..1a762fb
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/mock_adapter.h
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "service/daemon.h"
+
+namespace bluetooth {
+namespace testing {
+
+class MockAdapter : public Adapter {
+ public:
+ MockAdapter() = default;
+ ~MockAdapter() override = default;
+
+ MOCK_METHOD1(AddObserver, void(Observer*));
+ MOCK_METHOD1(RemoveObserver, void(Observer*));
+ MOCK_CONST_METHOD0(GetState, AdapterState());
+ MOCK_CONST_METHOD0(IsEnabled, bool());
+ MOCK_METHOD1(Enable, bool(bool));
+ MOCK_METHOD0(Disable, bool());
+ MOCK_CONST_METHOD0(GetName, std::string());
+ MOCK_METHOD1(SetName, bool(const std::string&));
+ MOCK_CONST_METHOD0(GetAddress, std::string());
+ MOCK_METHOD0(IsMultiAdvertisementSupported, bool());
+ MOCK_METHOD1(IsDeviceConnected, bool(const std::string&));
+ MOCK_METHOD0(GetTotalNumberOfTrackableAdvertisements, int());
+ MOCK_METHOD0(IsOffloadedFilteringSupported, bool());
+ MOCK_METHOD0(IsOffloadedScanBatchingSupported, bool());
+ MOCK_CONST_METHOD0(GetLowEnergyClientFactory, LowEnergyClientFactory*());
+ MOCK_CONST_METHOD0(GetLeAdvertiserFactory, LowEnergyAdvertiserFactory*());
+ MOCK_CONST_METHOD0(GetLeScannerFactory, LowEnergyScannerFactory*());
+ MOCK_CONST_METHOD0(GetGattClientFactory, GattClientFactory*());
+ MOCK_CONST_METHOD0(GetGattServerFactory, GattServerFactory*());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAdapter);
+};
+
+} // namespace testing
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/mock_daemon.h b/mtkbt/code/bt/service/test/mock_daemon.h
new file mode 100755
index 0000000..a5dd974
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/mock_daemon.h
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "service/daemon.h"
+
+namespace bluetooth {
+namespace testing {
+
+class MockDaemon : public Daemon {
+ public:
+ MockDaemon() = default;
+ ~MockDaemon() override = default;
+
+ MOCK_CONST_METHOD0(GetSettings, Settings*());
+ MOCK_CONST_METHOD0(GetMessageLoop, base::MessageLoop*());
+ MOCK_METHOD0(StartMainLoop, void());
+ MOCK_METHOD0(Init, bool());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockDaemon);
+};
+
+} // namespace testing
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/parcelable_unittest.cc b/mtkbt/code/bt/service/test/parcelable_unittest.cc
new file mode 100755
index 0000000..dcfb8fb
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/parcelable_unittest.cc
@@ -0,0 +1,211 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <gtest/gtest.h>
+
+#include "service/common/android/bluetooth/advertise_data.h"
+#include "service/common/android/bluetooth/advertise_settings.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_characteristic.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_descriptor.h"
+#include "service/common/android/bluetooth/bluetooth_gatt_service.h"
+#include "service/common/android/bluetooth/scan_filter.h"
+#include "service/common/android/bluetooth/scan_result.h"
+#include "service/common/android/bluetooth/scan_settings.h"
+#include "service/common/android/bluetooth/uuid.h"
+#include "service/common/bluetooth/low_energy_constants.h"
+
+using android::Parcel;
+
+using bluetooth::AdvertiseData;
+using bluetooth::AdvertiseSettings;
+using bluetooth::Characteristic;
+using bluetooth::Descriptor;
+using bluetooth::ScanFilter;
+using bluetooth::ScanResult;
+using bluetooth::ScanSettings;
+using bluetooth::Service;
+using bluetooth::UUID;
+
+namespace bluetooth {
+namespace {
+
+template <class IN, class OUT>
+bool TestData(IN& in) {
+ Parcel parcel;
+
+ parcel.writeParcelable((OUT)in);
+ parcel.setDataPosition(0);
+ OUT out;
+ parcel.readParcelable(&out);
+ // in case of error this display nice log message
+ EXPECT_EQ(out, in);
+ return in == out;
+}
+
+TEST(ParcelableTest, NonEmptyAdvertiseData) {
+ std::vector<uint8_t> data{0x02, 0x02, 0x00};
+ AdvertiseData adv0(data);
+ bool result =
+ TestData<AdvertiseData, android::bluetooth::AdvertiseData>(adv0);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, DefaultAdvertiseSettings) {
+ AdvertiseSettings settings;
+ bool result =
+ TestData<AdvertiseSettings, android::bluetooth::AdvertiseSettings>(
+ settings);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, NonEmptyAdvertiseSettings) {
+ AdvertiseSettings settings(
+ AdvertiseSettings::MODE_BALANCED, base::TimeDelta::FromMilliseconds(150),
+ AdvertiseSettings::TX_POWER_LEVEL_HIGH, false /* connectable */);
+
+ bool result =
+ TestData<AdvertiseSettings, android::bluetooth::AdvertiseSettings>(
+ settings);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, UUID) {
+ // Try a whole bunch of UUIDs.
+ for (int i = 0; i < 10; i++) {
+ UUID uuid = UUID::GetRandom();
+ TestData<UUID, android::bluetooth::UUID>(uuid);
+ }
+}
+
+TEST(ParcelableTest, ScanSettings) {
+ ScanSettings settings0;
+ ScanSettings settings1(
+ ScanSettings::MODE_BALANCED, ScanSettings::CALLBACK_TYPE_FIRST_MATCH,
+ ScanSettings::RESULT_TYPE_ABBREVIATED,
+ base::TimeDelta::FromMilliseconds(150), ScanSettings::MATCH_MODE_STICKY,
+ ScanSettings::MATCH_COUNT_FEW_ADVERTISEMENTS);
+
+ bool result =
+ TestData<ScanSettings, android::bluetooth::ScanSettings>(settings0);
+ EXPECT_TRUE(result);
+
+ result = TestData<ScanSettings, android::bluetooth::ScanSettings>(settings0);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, ScanFilter) {
+ ScanFilter filter;
+
+ filter.set_device_name("Test Device Name");
+ ASSERT_TRUE(filter.SetDeviceAddress("01:02:04:AB:CD:EF"));
+
+ bool result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+ EXPECT_TRUE(result);
+
+ UUID uuid = UUID::GetRandom();
+ filter.SetServiceUuid(uuid);
+
+ result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+ EXPECT_TRUE(result);
+
+ UUID mask = UUID::GetRandom();
+ filter.SetServiceUuidWithMask(uuid, mask);
+ result = TestData<ScanFilter, android::bluetooth::ScanFilter>(filter);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, ScanResult) {
+ const char kTestAddress[] = "01:02:03:AB:CD:EF";
+
+ const std::vector<uint8_t> kEmptyBytes;
+ const std::vector<uint8_t> kTestBytes{0x01, 0x02, 0x03};
+
+ const int kTestRssi = 127;
+
+ ScanResult result0(kTestAddress, kEmptyBytes, kTestRssi);
+ ScanResult result1(kTestAddress, kTestBytes, kTestRssi);
+
+ bool result = TestData<ScanResult, android::bluetooth::ScanResult>(result0);
+ EXPECT_TRUE(result);
+
+ result = TestData<ScanResult, android::bluetooth::ScanResult>(result1);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattDescriptor) {
+ Descriptor s = Descriptor(0x0000, UUID::GetRandom(),
+ bluetooth::kAttributePermissionRead);
+ Descriptor s2 = Descriptor(0xFFFE, UUID::GetRandom(),
+ bluetooth::kAttributePermissionWrite);
+ Descriptor s3 = Descriptor(0x003D, UUID::GetRandom(),
+ bluetooth::kAttributePermissionReadEncryptedMITM |
+ bluetooth::kAttributePermissionRead);
+
+ bool result =
+ TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s);
+ EXPECT_TRUE(result);
+
+ result =
+ TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s2);
+ EXPECT_TRUE(result);
+
+ result =
+ TestData<Descriptor, android::bluetooth::BluetoothGattDescriptor>(s3);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattCharacteristic) {
+ Characteristic c = Characteristic(0x0004, UUID::GetRandom(), 0, 0,
+ {Descriptor(0x0005, UUID::GetRandom(), 0),
+ Descriptor(0x0007, UUID::GetRandom(), 0),
+ Descriptor(0x00A1, UUID::GetRandom(), 0)});
+
+ bool result =
+ TestData<Characteristic, android::bluetooth::BluetoothGattCharacteristic>(
+ c);
+ EXPECT_TRUE(result);
+}
+
+TEST(ParcelableTest, GattService) {
+ Service s =
+ Service(0x0001, true, UUID("CAFE"),
+ {Characteristic(0x0004, UUID::GetRandom(),
+ bluetooth::kCharacteristicPropertyNotify,
+ bluetooth::kAttributePermissionRead,
+ {Descriptor(0x0005, UUID::GetRandom(), 0),
+ Descriptor(0x0007, UUID::GetRandom(), 0),
+ Descriptor(0x0009, UUID::GetRandom(), 0)}),
+ Characteristic(0x000D, UUID::GetRandom(),
+ bluetooth::kCharacteristicPropertyWrite,
+ bluetooth::kAttributePermissionWrite,
+ {Descriptor(0x0010, UUID::GetRandom(), 0),
+ Descriptor(0x0012, UUID::GetRandom(), 0)}),
+ Characteristic(0x0015, UUID::GetRandom(), 0, 0, {})},
+ {});
+
+ Parcel parcel;
+
+ parcel.writeParcelable((android::bluetooth::BluetoothGattService)s);
+ parcel.setDataPosition(0);
+ android::bluetooth::BluetoothGattService out;
+ parcel.readParcelable(&out);
+
+ bool result = TestData<Service, android::bluetooth::BluetoothGattService>(s);
+ EXPECT_TRUE(result);
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/mtkbt/code/bt/service/test/settings_unittest.cc b/mtkbt/code/bt/service/test/settings_unittest.cc
new file mode 100755
index 0000000..62b6db5
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/settings_unittest.cc
@@ -0,0 +1,100 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/macros.h>
+#include <gtest/gtest.h>
+
+#include "service/settings.h"
+#include "service/switches.h"
+
+using bluetooth::Settings;
+using namespace bluetooth::switches;
+
+namespace {
+
+class SettingsTest : public ::testing::Test {
+ public:
+ SettingsTest() = default;
+
+ void SetUp() override { base::CommandLine::Reset(); }
+
+ void TearDown() override { base::CommandLine::Reset(); }
+
+ protected:
+ base::AtExitManager exit_manager_;
+ Settings settings_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SettingsTest);
+};
+
+TEST_F(SettingsTest, EmptyCommandLine) {
+ const base::CommandLine::CharType* argv[] = {"program"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches1) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar", "--foobarbaz"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedSwitches2) {
+ const base::CommandLine::CharType* argv[] = {"program", "--foobarbaz"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments1) {
+ const base::CommandLine::CharType* argv[] = {"program", "foobarbaz"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, UnexpectedArguments2) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar", "foobarbaz"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, TooManyIpcOptions) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--create-ipc-socket=foobar",
+ "--android-ipc-socket-suffix=foobar"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_FALSE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsCreateIpc) {
+ const base::CommandLine::CharType* argv[] = {"program",
+ "--create-ipc-socket=foobar"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_TRUE(settings_.Init());
+}
+
+TEST_F(SettingsTest, GoodArgumentsAndroidIpc) {
+ const base::CommandLine::CharType* argv[] = {
+ "program", "--android-ipc-socket-suffix=foobar"};
+ EXPECT_TRUE(base::CommandLine::Init(arraysize(argv), argv));
+ EXPECT_TRUE(settings_.Init());
+}
+
+} // namespace
diff --git a/mtkbt/code/bt/service/test/stub_ipc_handler_binder.cc b/mtkbt/code/bt/service/test/stub_ipc_handler_binder.cc
new file mode 100755
index 0000000..8ce064b
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/stub_ipc_handler_binder.cc
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/binder/ipc_handler_binder.h"
+
+// TODO(armansito): This is a crappy workaround to link IPCHandlerBinder into
+// host-native unit tests. We should instead figure out a way to build Binder
+// unit tests for host.
+
+namespace ipc {
+
+IPCHandlerBinder::IPCHandlerBinder(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate) {
+ // Stub
+}
+
+IPCHandlerBinder::~IPCHandlerBinder() {
+ // Stub
+}
+
+bool IPCHandlerBinder::Run() {
+ // Stub
+ return false;
+}
+
+void IPCHandlerBinder::Stop() {
+ // Stub
+}
+
+void IPCHandlerBinder::NotifyStarted() {
+ // Stub
+}
+
+} // namespace
diff --git a/mtkbt/code/bt/service/test/stub_ipc_handler_linux.cc b/mtkbt/code/bt/service/test/stub_ipc_handler_linux.cc
new file mode 100755
index 0000000..011b965
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/stub_ipc_handler_linux.cc
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "service/ipc/ipc_handler_linux.h"
+
+// TODO(keybuk): This is a crappy workaround to link IPCHandlerLinux into
+// host-native unit tests. IPCManager shouldn't explicitly reference these
+// classes.
+
+namespace ipc {
+
+IPCHandlerLinux::IPCHandlerLinux(bluetooth::Adapter* adapter,
+ IPCManager::Delegate* delegate)
+ : IPCHandler(adapter, delegate),
+ running_(false),
+ thread_("IPCHandlerLinux"),
+ keep_running_(true) {
+ // Stub
+}
+
+IPCHandlerLinux::~IPCHandlerLinux() {
+ // Stub
+}
+
+bool IPCHandlerLinux::Run() {
+ // Stub
+ return false;
+}
+
+void IPCHandlerLinux::Stop() {
+ // Stub
+}
+
+void IPCHandlerLinux::StartListeningOnThread() {
+ // Stub
+}
+
+void IPCHandlerLinux::ShutDownOnOriginThread() {
+ // Stub
+}
+
+void IPCHandlerLinux::NotifyStartedOnOriginThread() {
+ // Stub
+}
+
+void IPCHandlerLinux::NotifyStartedOnCurrentThread() {
+ // Stub
+}
+
+void IPCHandlerLinux::NotifyStoppedOnOriginThread() {
+ // Stub
+}
+
+void IPCHandlerLinux::NotifyStoppedOnCurrentThread() {
+ // Stub
+}
+
+} // namespace
diff --git a/mtkbt/code/bt/service/test/util_unittest.cc b/mtkbt/code/bt/service/test/util_unittest.cc
new file mode 100755
index 0000000..83e7fb7
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/util_unittest.cc
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <gtest/gtest.h>
+
+#include "service/common/bluetooth/util/address_helper.h"
+
+namespace util {
+
+TEST(UtilTest, IsAddressValid) {
+ EXPECT_FALSE(IsAddressValid(""));
+ EXPECT_FALSE(IsAddressValid("000000000000"));
+ EXPECT_FALSE(IsAddressValid("00:00:00:00:0000"));
+ EXPECT_FALSE(IsAddressValid("00:00:00:00:00:0"));
+ EXPECT_FALSE(IsAddressValid("00:00:00:00:00:0;"));
+ EXPECT_TRUE(IsAddressValid("00:00:00:00:00:00"));
+ EXPECT_FALSE(IsAddressValid("aB:cD:eF:Gh:iJ:Kl"));
+}
+
+TEST(UtilTest, BdAddrFromString) {
+ bt_bdaddr_t addr;
+ memset(&addr, 0, sizeof(addr));
+
+ EXPECT_TRUE(BdAddrFromString("00:00:00:00:00:00", &addr));
+ const bt_bdaddr_t result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
+
+ EXPECT_TRUE(BdAddrFromString("ab:01:4C:d5:21:9f", &addr));
+ const bt_bdaddr_t result1 = {{0xab, 0x01, 0x4c, 0xd5, 0x21, 0x9f}};
+ EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
+}
+
+} // namespace util
diff --git a/mtkbt/code/bt/service/test/uuid_unittest.cc b/mtkbt/code/bt/service/test/uuid_unittest.cc
new file mode 100755
index 0000000..3a8103a
--- a/dev/null
+++ b/mtkbt/code/bt/service/test/uuid_unittest.cc
@@ -0,0 +1,160 @@
+//
+// Copyright (C) 2015 Google, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <stdint.h>
+#include <algorithm>
+#include <array>
+
+#include <gtest/gtest.h>
+
+#include "service/common/bluetooth/uuid.h"
+
+using namespace bluetooth;
+
+namespace {
+
+const std::array<uint8_t, UUID::kNumBytes128> kBtSigBaseUUID = {{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5f, 0x9b, 0x34, 0xfb,
+}};
+
+} // namespace
+
+// Verify that an uninitialized UUID is equal
+// To the BT SIG Base UUID.
+TEST(UUIDTest, DefaultUUID) {
+ UUID uuid;
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == kBtSigBaseUUID);
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16Bit) {
+ auto my_uuid_16 = kBtSigBaseUUID;
+ my_uuid_16[2] = 0xde;
+ my_uuid_16[3] = 0xad;
+ UUID uuid(UUID::UUID16Bit({{0xde, 0xad}}));
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+ ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 16-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init16BitString) {
+ auto my_uuid_16 = kBtSigBaseUUID;
+ my_uuid_16[2] = 0xde;
+ my_uuid_16[3] = 0xad;
+ UUID uuid("dead");
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+ ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+
+ uuid = UUID("0xdead");
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_16);
+ ASSERT_TRUE(UUID::kNumBytes16 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 32-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init32Bit) {
+ auto my_uuid_32 = kBtSigBaseUUID;
+ my_uuid_32[0] = 0xde;
+ my_uuid_32[1] = 0xad;
+ my_uuid_32[2] = 0xbe;
+ my_uuid_32[3] = 0xef;
+ UUID uuid(UUID::UUID32Bit({{0xde, 0xad, 0xbe, 0xef}}));
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+ ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify correct reading of a 32-bit UUID initialized from string.
+TEST(UUIDTest, Init32BitString) {
+ auto my_uuid_32 = kBtSigBaseUUID;
+ my_uuid_32[0] = 0xde;
+ my_uuid_32[1] = 0xad;
+ my_uuid_32[2] = 0xbe;
+ my_uuid_32[3] = 0xef;
+ UUID uuid("deadbeef");
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_32);
+ ASSERT_TRUE(UUID::kNumBytes32 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128Bit) {
+ auto my_uuid_128 = kBtSigBaseUUID;
+ for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+ my_uuid_128[i] = i;
+ }
+
+ UUID uuid(my_uuid_128);
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullBigEndian() == my_uuid_128);
+ ASSERT_TRUE(UUID::kNumBytes128 == uuid.GetShortestRepresentationSize());
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it as LE.
+TEST(UUIDTest, Init128BitLittleEndian) {
+ auto my_uuid_128 = kBtSigBaseUUID;
+ for (int i = 0; i < static_cast<int>(my_uuid_128.size()); ++i) {
+ my_uuid_128[i] = i;
+ }
+
+ UUID uuid(my_uuid_128);
+ std::reverse(my_uuid_128.begin(), my_uuid_128.end());
+ ASSERT_TRUE(uuid.is_valid());
+ ASSERT_TRUE(uuid.GetFullLittleEndian() == my_uuid_128);
+}
+
+// Verify that we initialize a 128-bit UUID in a
+// way consistent with how we read it.
+TEST(UUIDTest, Init128BitString) {
+ UUID::UUID128Bit my_uuid{
+ {7, 1, 6, 8, 14, 255, 16, 2, 3, 4, 5, 6, 7, 8, 9, 10}};
+ std::string my_uuid_string("07010608-0eff-1002-0304-05060708090a");
+
+ UUID uuid0(my_uuid);
+ UUID uuid1(my_uuid_string);
+
+ ASSERT_TRUE(uuid0.is_valid());
+ ASSERT_TRUE(uuid1.is_valid());
+ ASSERT_TRUE(uuid0 == uuid1);
+ ASSERT_TRUE(UUID::kNumBytes128 == uuid0.GetShortestRepresentationSize());
+}
+
+TEST(UUIDTest, InitInvalid) {
+ UUID uuid0("000102030405060708090A0B0C0D0E0F");
+ ASSERT_FALSE(uuid0.is_valid());
+
+ UUID uuid1("1*90");
+ ASSERT_FALSE(uuid1.is_valid());
+
+ UUID uuid2("109g");
+ ASSERT_FALSE(uuid1.is_valid());
+}
+
+TEST(UUIDTest, ToString) {
+ const UUID::UUID16Bit data{{0x18, 0x0d}};
+ UUID uuid(data);
+ std::string uuid_string = uuid.ToString();
+ EXPECT_EQ("0000180d-0000-1000-8000-00805f9b34fb", uuid_string);
+}
diff --git a/mtkbt/code/bt/stack/Android.bp b/mtkbt/code/bt/stack/Android.bp
new file mode 100755
index 0000000..61b7598
--- a/dev/null
+++ b/mtkbt/code/bt/stack/Android.bp
@@ -0,0 +1,291 @@
+// Bluetooth stack static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-stack",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "avct",
+ "btm",
+ "avrc",
+ "l2cap",
+ "avdt",
+ "gatt",
+ "gap",
+ "pan",
+ "bnep",
+ "hid",
+ "sdp",
+ "smp",
+ "srvc",
+ ],
+ include_dirs: [
+ "external/aac/libAACenc/include",
+ "external/aac/libSYS/include",
+ "external/libldac/inc",
+ "external/libldac/abr/inc",
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/vnd/include",
+ "vendor/mediatek/limit_open/system/bt/vnd/ble",
+ "vendor/mediatek/limit_open/system/bt/btif/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/udrv/include",
+ "vendor/mediatek/limit_open/system/bt/bta/include",
+ "vendor/mediatek/limit_open/system/bt/bta/sys",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ ],
+ srcs: [
+ "a2dp/a2dp_aac.cc",
+ "a2dp/a2dp_aac_encoder.cc",
+ "a2dp/a2dp_api.cc",
+ "a2dp/a2dp_codec_config.cc",
+ "a2dp/a2dp_sbc.cc",
+ "a2dp/a2dp_sbc_encoder.cc",
+ "a2dp/a2dp_sbc_up_sample.cc",
+ "a2dp/a2dp_vendor.cc",
+ "a2dp/a2dp_vendor_aptx.cc",
+ "a2dp/a2dp_vendor_aptx_hd.cc",
+ "a2dp/a2dp_vendor_aptx_encoder.cc",
+ "a2dp/a2dp_vendor_aptx_hd_encoder.cc",
+ "a2dp/a2dp_vendor_ldac.cc",
+ "a2dp/a2dp_vendor_ldac_abr.cc",
+ "a2dp/a2dp_vendor_ldac_encoder.cc",
+ "avct/avct_api.cc",
+ "avct/avct_bcb_act.cc",
+ "avct/avct_ccb.cc",
+ "avct/avct_l2c.cc",
+ "avct/avct_l2c_br.cc",
+ "avct/avct_lcb.cc",
+ "avct/avct_lcb_act.cc",
+ "avdt/avdt_ad.cc",
+ "avdt/avdt_api.cc",
+ "avdt/avdt_ccb.cc",
+ "avdt/avdt_ccb_act.cc",
+ "avdt/avdt_l2c.cc",
+ "avdt/avdt_msg.cc",
+ "avdt/avdt_scb.cc",
+ "avdt/avdt_scb_act.cc",
+ "avrc/avrc_api.cc",
+ "avrc/avrc_bld_ct.cc",
+ "avrc/avrc_bld_tg.cc",
+ "avrc/avrc_opt.cc",
+ "avrc/avrc_pars_ct.cc",
+ "avrc/avrc_pars_tg.cc",
+ "avrc/avrc_sdp.cc",
+ "avrc/avrc_utils.cc",
+ "bnep/bnep_api.cc",
+ "bnep/bnep_main.cc",
+ "bnep/bnep_utils.cc",
+ "btm/ble_advertiser_hci_interface.cc",
+ "btm/btm_acl.cc",
+ "btm/btm_ble.cc",
+ "btm/btm_ble_addr.cc",
+ "btm/btm_ble_adv_filter.cc",
+ "btm/btm_ble_batchscan.cc",
+ "btm/btm_ble_bgconn.cc",
+ "btm/btm_ble_cont_energy.cc",
+ "btm/btm_ble_gap.cc",
+ "btm/btm_ble_multi_adv.cc",
+ "btm/btm_ble_privacy.cc",
+ "btm/btm_dev.cc",
+ "btm/btm_devctl.cc",
+ "btm/btm_inq.cc",
+ "btm/btm_main.cc",
+ "btm/btm_pm.cc",
+ "btm/btm_sco.cc",
+ "btm/btm_sec.cc",
+ "btu/btu_hcif.cc",
+ "btu/btu_init.cc",
+ "btu/btu_task.cc",
+ "gap/gap_api.cc",
+ "gap/gap_ble.cc",
+ "gap/gap_conn.cc",
+ "gap/gap_utils.cc",
+ "gatt/att_protocol.cc",
+ "gatt/gatt_api.cc",
+ "gatt/gatt_attr.cc",
+ "gatt/gatt_auth.cc",
+ "gatt/gatt_cl.cc",
+ "gatt/gatt_db.cc",
+ "gatt/gatt_main.cc",
+ "gatt/gatt_sr.cc",
+ "gatt/gatt_utils.cc",
+ "hcic/hciblecmds.cc",
+ "hcic/hcicmds.cc",
+ "hid/hidh_api.cc",
+ "hid/hidh_conn.cc",
+ "hid/hidd_api.cc",
+ "hid/hidd_conn.cc",
+ "l2cap/l2c_api.cc",
+ "l2cap/l2c_ble.cc",
+ "l2cap/l2c_csm.cc",
+ "l2cap/l2c_fcr.cc",
+ "l2cap/l2c_link.cc",
+ "l2cap/l2c_main.cc",
+ "l2cap/l2c_ucd.cc",
+ "l2cap/l2c_utils.cc",
+ "l2cap/l2cap_client.cc",
+ "mcap/mca_api.cc",
+ "mcap/mca_cact.cc",
+ "mcap/mca_csm.cc",
+ "mcap/mca_dact.cc",
+ "mcap/mca_dsm.cc",
+ "mcap/mca_l2c.cc",
+ "mcap/mca_main.cc",
+ "pan/pan_api.cc",
+ "pan/pan_main.cc",
+ "pan/pan_utils.cc",
+ "rfcomm/port_api.cc",
+ "rfcomm/port_rfc.cc",
+ "rfcomm/port_utils.cc",
+ "rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_mx_fsm.cc",
+ "rfcomm/rfc_port_fsm.cc",
+ "rfcomm/rfc_port_if.cc",
+ "rfcomm/rfc_ts_frames.cc",
+ "rfcomm/rfc_utils.cc",
+ "sdp/sdp_api.cc",
+ "sdp/sdp_db.cc",
+ "sdp/sdp_discovery.cc",
+ "sdp/sdp_main.cc",
+ "sdp/sdp_server.cc",
+ "sdp/sdp_utils.cc",
+ "smp/aes.cc",
+ "smp/p_256_curvepara.cc",
+ "smp/p_256_ecc_pp.cc",
+ "smp/p_256_multprecision.cc",
+ "smp/smp_act.cc",
+ "smp/smp_api.cc",
+ "smp/smp_br_main.cc",
+ "smp/smp_cmac.cc",
+ "smp/smp_keys.cc",
+ "smp/smp_l2c.cc",
+ "smp/smp_main.cc",
+ "smp/smp_utils.cc",
+ "srvc/srvc_battery.cc",
+ "srvc/srvc_dis.cc",
+ "srvc/srvc_eng.cc",
+ ],
+ static_libs: [
+ "libbt-hci",
+ "libFraunhoferAAC",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ required: [
+ "libldacBT_enc",
+ "libldacBT_abr",
+ ]
+}
+
+// Bluetooth stack unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_stack",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ ],
+ srcs: ["test/stack_a2dp_test.cc"],
+ shared_libs: [
+ "liblog",
+ ],
+ static_libs: [
+ "libbt-stack",
+ "libbt-sbc-encoder",
+ "libFraunhoferAAC",
+ "libosi",
+ ],
+}
+
+// Bluetooth stack smp unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_stack_smp",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "btm",
+ "l2cap",
+ "smp",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ ],
+ srcs: [
+ "smp/smp_keys.cc",
+ "smp/aes.cc",
+ "smp/smp_api.cc",
+ "smp/smp_main.cc",
+ "smp/smp_utils.cc",
+ "test/stack_smp_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ "libosi",
+ ],
+}
+
+
+// Bluetooth stack multi-advertising unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_stack_multi_adv",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ "btm",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ ],
+ srcs: [
+ "btm/btm_ble_multi_adv.cc",
+ "test/ble_advertiser_test.cc",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ ],
+}
+
+// Bluetooth stack advertise data parsing unit tests for target
+// =============================================================
+cc_test {
+ name: "net_test_stack_ad_parser",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ srcs: [
+ "test/ad_parser_unittest.cc",
+ ],
+ static_libs: [
+ "liblog",
+ "libgmock",
+ ],
+}
diff --git a/mtkbt/code/bt/stack/BUILD.gn b/mtkbt/code/bt/stack/BUILD.gn
new file mode 100755
index 0000000..87535d4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/BUILD.gn
@@ -0,0 +1,266 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("stack") {
+ sources = [
+ "a2dp/a2dp_aac.cc",
+ "a2dp/a2dp_aac_encoder.cc",
+ "a2dp/a2dp_api.cc",
+ "a2dp/a2dp_codec_config.cc",
+ "a2dp/a2dp_sbc.cc",
+ "a2dp/a2dp_sbc_encoder.cc",
+ "a2dp/a2dp_sbc_up_sample.cc",
+ "a2dp/a2dp_vendor.cc",
+ "a2dp/a2dp_vendor_aptx.cc",
+ "a2dp/a2dp_vendor_aptx_encoder.cc",
+ "a2dp/a2dp_vendor_aptx_hd.cc",
+ "a2dp/a2dp_vendor_aptx_hd_encoder.cc",
+ "a2dp/a2dp_vendor_ldac.cc",
+ "a2dp/a2dp_vendor_ldac_abr.cc",
+ "a2dp/a2dp_vendor_ldac_encoder.cc",
+ "avct/avct_api.cc",
+ "avct/avct_bcb_act.cc",
+ "avct/avct_ccb.cc",
+ "avct/avct_l2c.cc",
+ "avct/avct_l2c_br.cc",
+ "avct/avct_lcb.cc",
+ "avct/avct_lcb_act.cc",
+ "avdt/avdt_ad.cc",
+ "avdt/avdt_api.cc",
+ "avdt/avdt_ccb.cc",
+ "avdt/avdt_ccb_act.cc",
+ "avdt/avdt_l2c.cc",
+ "avdt/avdt_msg.cc",
+ "avdt/avdt_scb.cc",
+ "avdt/avdt_scb_act.cc",
+ "avrc/avrc_api.cc",
+ "avrc/avrc_bld_ct.cc",
+ "avrc/avrc_bld_tg.cc",
+ "avrc/avrc_opt.cc",
+ "avrc/avrc_pars_ct.cc",
+ "avrc/avrc_pars_tg.cc",
+ "avrc/avrc_sdp.cc",
+ "avrc/avrc_utils.cc",
+ "bnep/bnep_api.cc",
+ "bnep/bnep_main.cc",
+ "bnep/bnep_utils.cc",
+ "btm/ble_advertiser_hci_interface.cc",
+ "btm/btm_acl.cc",
+ "btm/btm_ble.cc",
+ "btm/btm_ble_addr.cc",
+ "btm/btm_ble_adv_filter.cc",
+ "btm/btm_ble_batchscan.cc",
+ "btm/btm_ble_bgconn.cc",
+ "btm/btm_ble_cont_energy.cc",
+ "btm/btm_ble_gap.cc",
+ "btm/btm_ble_multi_adv.cc",
+ "btm/btm_ble_privacy.cc",
+ "btm/btm_dev.cc",
+ "btm/btm_devctl.cc",
+ "btm/btm_inq.cc",
+ "btm/btm_main.cc",
+ "btm/btm_pm.cc",
+ "btm/btm_sco.cc",
+ "btm/btm_sec.cc",
+ "btu/btu_hcif.cc",
+ "btu/btu_init.cc",
+ "btu/btu_task.cc",
+ "gap/gap_api.cc",
+ "gap/gap_ble.cc",
+ "gap/gap_conn.cc",
+ "gap/gap_utils.cc",
+ "gatt/att_protocol.cc",
+ "gatt/gatt_api.cc",
+ "gatt/gatt_attr.cc",
+ "gatt/gatt_auth.cc",
+ "gatt/gatt_cl.cc",
+ "gatt/gatt_db.cc",
+ "gatt/gatt_main.cc",
+ "gatt/gatt_sr.cc",
+ "gatt/gatt_utils.cc",
+ "hcic/hciblecmds.cc",
+ "hcic/hcicmds.cc",
+ "hid/hidh_api.cc",
+ "hid/hidh_conn.cc",
+ "hid/hidd_api.cc",
+ "hid/hidd_conn.cc",
+ "l2cap/l2c_api.cc",
+ "l2cap/l2c_ble.cc",
+ "l2cap/l2c_csm.cc",
+ "l2cap/l2c_fcr.cc",
+ "l2cap/l2c_link.cc",
+ "l2cap/l2c_main.cc",
+ "l2cap/l2c_ucd.cc",
+ "l2cap/l2c_utils.cc",
+ "l2cap/l2cap_client.cc",
+ "mcap/mca_api.cc",
+ "mcap/mca_cact.cc",
+ "mcap/mca_csm.cc",
+ "mcap/mca_dact.cc",
+ "mcap/mca_dsm.cc",
+ "mcap/mca_l2c.cc",
+ "mcap/mca_main.cc",
+ "pan/pan_api.cc",
+ "pan/pan_main.cc",
+ "pan/pan_utils.cc",
+ "rfcomm/port_api.cc",
+ "rfcomm/port_rfc.cc",
+ "rfcomm/port_utils.cc",
+ "rfcomm/rfc_l2cap_if.cc",
+ "rfcomm/rfc_mx_fsm.cc",
+ "rfcomm/rfc_port_fsm.cc",
+ "rfcomm/rfc_port_if.cc",
+ "rfcomm/rfc_ts_frames.cc",
+ "rfcomm/rfc_utils.cc",
+ "sdp/sdp_api.cc",
+ "sdp/sdp_db.cc",
+ "sdp/sdp_discovery.cc",
+ "sdp/sdp_main.cc",
+ "sdp/sdp_server.cc",
+ "sdp/sdp_utils.cc",
+ "smp/aes.cc",
+ "smp/p_256_curvepara.cc",
+ "smp/p_256_ecc_pp.cc",
+ "smp/p_256_multprecision.cc",
+ "smp/smp_act.cc",
+ "smp/smp_api.cc",
+ "smp/smp_br_main.cc",
+ "smp/smp_cmac.cc",
+ "smp/smp_keys.cc",
+ "smp/smp_l2c.cc",
+ "smp/smp_main.cc",
+ "smp/smp_utils.cc",
+ "srvc/srvc_battery.cc",
+ "srvc/srvc_dis.cc",
+ "srvc/srvc_eng.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "avct",
+ "btm",
+ "avrc",
+ "l2cap",
+ "avdt",
+ "gatt",
+ "gap",
+ "pan",
+ "bnep",
+ "hid",
+ "sdp",
+ "smp",
+ "srvc",
+ "//btcore/include",
+ "//vnd/include",
+ "//vnd/ble",
+ "//btif/include",
+ "//hci/include",
+ "//include",
+ "//udrv/include",
+ "//rpc/include",
+ "//hcis",
+ "//ctrlr/include",
+ "//bta/include",
+ "//bta/sys",
+ "//utils/include",
+ "//",
+ ]
+
+ deps = [
+ "//third_party/libchrome:base",
+ "//third_party/libldac:libldacBT_enc",
+ "//third_party/libldac:libldacBT_abr",
+ "//third_party/aac:libFraunhoferAAC",
+ ]
+}
+
+executable("stack_unittests") {
+ testonly = true
+ sources = [
+ "test/stack_a2dp_test.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//bta/include",
+ "//bta/sys",
+ "//btcore/include",
+ "//embdrv/sbc/encoder/include",
+ "//hci/include",
+ "//include",
+ "//stack/a2dp",
+ "//stack/btm",
+ "//stack/include",
+ "//third_party/tinyxml2",
+ "//udrv/include",
+ "//utils/include",
+ "//vnd/include"
+ ]
+
+ libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+
+ deps = [
+ ":stack",
+ "//osi",
+ "//btcore",
+ "//device",
+ "//embdrv/sbc",
+ "//hci",
+ "//main:bluetooth.default",
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
+executable("net_test_stack_multi_adv") {
+ testonly = true
+ sources = [
+ "btm/btm_ble_multi_adv.cc",
+ "test/ble_advertiser_test.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//btcore/include",
+ "//hci/include",
+ "//include",
+ "//stack/btm",
+ ]
+
+libs = [
+ "-ldl",
+ "-lpthread",
+ "-lresolv",
+ "-lrt",
+ "-lz",
+ "-latomic",
+ ]
+
+ deps = [
+ "//third_party/googletest:gmock_main",
+ "//third_party/libchrome:base",
+ ]
+}
+
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_aac.cc b/mtkbt/code/bt/stack/a2dp/a2dp_aac.cc
new file mode 100755
index 0000000..4af0649
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_aac.cc
@@ -0,0 +1,1464 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse the AAC Codec Information
+ * Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_aac"
+
+#include "bt_target.h"
+
+#include "a2dp_aac.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_aac_encoder.h"
+#include "bt_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define A2DP_AAC_DEFAULT_BITRATE 320000 // 320 kbps
+#define A2DP_AAC_MIN_BITRATE 64000 // 64 kbps
+
+// data type for the AAC Codec Information Element */
+// NOTE: bits_per_sample is needed only for AAC encoder initialization.
+typedef struct {
+ uint8_t objectType; /* Object Type */
+ uint16_t sampleRate; /* Sampling Frequency */
+ uint8_t channelMode; /* STEREO/MONO */
+ uint8_t variableBitRateSupport; /* Variable Bit Rate Support*/
+ uint32_t bitRate; /* Bit rate */
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_AAC_CIE;
+
+/* AAC Source codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_caps = {
+ // objectType
+ A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+ // sampleRate
+ // TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
+ A2DP_AAC_SAMPLING_FREQ_44100,
+ // channelMode
+ A2DP_AAC_CHANNEL_MODE_STEREO,
+ // variableBitRateSupport
+ A2DP_AAC_VARIABLE_BIT_RATE_DISABLED,
+ // bitRate
+ A2DP_AAC_DEFAULT_BITRATE,
+ // bits_per_sample
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
+/* Default AAC codec configuration */
+static const tA2DP_AAC_CIE a2dp_aac_default_config = {
+ A2DP_AAC_OBJECT_TYPE_MPEG2_LC, // objectType
+ A2DP_AAC_SAMPLING_FREQ_44100, // sampleRate
+ A2DP_AAC_CHANNEL_MODE_STEREO, // channelMode
+ A2DP_AAC_VARIABLE_BIT_RATE_DISABLED, // variableBitRateSupport
+ A2DP_AAC_DEFAULT_BITRATE, // bitRate
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 // bits_per_sample
+};
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+/* AAC Sink codec capabilities */
+static const tA2DP_AAC_CIE a2dp_aac_sink_caps = {
+ // objectType
+ A2DP_AAC_OBJECT_TYPE_MPEG2_LC,
+ // sampleRate
+ // TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
+ A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000,
+ // channelMode
+ A2DP_AAC_CHANNEL_MODE_STEREO | A2DP_AAC_CHANNEL_MODE_MONO,
+ // variableBitRateSupport
+ A2DP_AAC_VARIABLE_BIT_RATE_DISABLED,
+ // bitRate
+ A2DP_AAC_DEFAULT_BITRATE,
+ // bits_per_sample
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16};
+
+ /* Default AAC codec configuration */
+static const tA2DP_AAC_CIE a2dp_aac_default_sink_config = {
+ A2DP_AAC_OBJECT_TYPE_MPEG2_LC, // objectType
+ A2DP_AAC_SAMPLING_FREQ_44100 | A2DP_AAC_SAMPLING_FREQ_48000, // sampleRate
+ A2DP_AAC_CHANNEL_MODE_STEREO | A2DP_AAC_CHANNEL_MODE_MONO, // channelMode
+ A2DP_AAC_VARIABLE_BIT_RATE_DISABLED, // variableBitRateSupport
+ A2DP_AAC_DEFAULT_BITRATE, // bitRate
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 // bits_per_sample
+};
+#endif
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_aac = {
+ a2dp_aac_encoder_init,
+ a2dp_aac_encoder_cleanup,
+ a2dp_aac_feeding_reset,
+ a2dp_aac_feeding_flush,
+ a2dp_aac_get_encoder_interval_ms,
+ a2dp_aac_send_frames,
+ nullptr // set_transmit_queue_length
+};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
+ const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_peer_codec_info);
+
+// Builds the AAC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the AAC Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoAac(uint8_t media_type,
+ const tA2DP_AAC_CIE* p_ie,
+ uint8_t* p_result) {
+ if (p_ie == NULL || p_result == NULL) {
+ return A2DP_INVALID_PARAMS;
+ }
+
+ *p_result++ = A2DP_AAC_CODEC_LEN;
+ *p_result++ = (media_type << 4);
+ *p_result++ = A2DP_MEDIA_CT_AAC;
+
+ // Object Type
+ if (p_ie->objectType == 0) return A2DP_INVALID_PARAMS;
+ *p_result++ = p_ie->objectType;
+
+ // Sampling Frequency
+ if (p_ie->sampleRate == 0) return A2DP_INVALID_PARAMS;
+ *p_result++ = (uint8_t)(p_ie->sampleRate & A2DP_AAC_SAMPLING_FREQ_MASK0);
+ *p_result = (uint8_t)((p_ie->sampleRate & A2DP_AAC_SAMPLING_FREQ_MASK1) >> 8);
+
+ // Channel Mode
+ if (p_ie->channelMode == 0) return A2DP_INVALID_PARAMS;
+ *p_result++ |= (p_ie->channelMode & A2DP_AAC_CHANNEL_MODE_MASK);
+
+ // Variable Bit Rate Support
+ *p_result = (p_ie->variableBitRateSupport & A2DP_AAC_VARIABLE_BIT_RATE_MASK);
+
+ // Bit Rate
+ *p_result++ |= (uint8_t)((p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK0) >> 16);
+ *p_result++ = (uint8_t)((p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK1) >> 8);
+ *p_result++ = (uint8_t)(p_ie->bitRate & A2DP_AAC_BIT_RATE_MASK2);
+
+ return A2DP_SUCCESS;
+}
+
+// Parses the AAC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence is
+// codec capabilities, otherwise is codec configuration.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoAac(tA2DP_AAC_CIE* p_ie,
+ const uint8_t* p_codec_info,
+ bool is_capability) {
+ uint8_t losc;
+ uint8_t media_type;
+ tA2DP_CODEC_TYPE codec_type;
+
+ if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+ // Check the codec capability length
+ losc = *p_codec_info++;
+ if (losc != A2DP_AAC_CODEC_LEN) return A2DP_WRONG_CODEC;
+
+ media_type = (*p_codec_info++) >> 4;
+ codec_type = *p_codec_info++;
+ /* Check the Media Type and Media Codec Type */
+ if (media_type != AVDT_MEDIA_TYPE_AUDIO || codec_type != A2DP_MEDIA_CT_AAC) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ p_ie->objectType = *p_codec_info++;
+ p_ie->sampleRate = (*p_codec_info & A2DP_AAC_SAMPLING_FREQ_MASK0) |
+ (*(p_codec_info + 1) << 8 & A2DP_AAC_SAMPLING_FREQ_MASK1);
+ p_codec_info++;
+ p_ie->channelMode = *p_codec_info & A2DP_AAC_CHANNEL_MODE_MASK;
+ p_codec_info++;
+
+ p_ie->variableBitRateSupport =
+ *p_codec_info & A2DP_AAC_VARIABLE_BIT_RATE_MASK;
+
+ p_ie->bitRate = ((*p_codec_info) << 16 & A2DP_AAC_BIT_RATE_MASK0) |
+ (*(p_codec_info + 1) << 8 & A2DP_AAC_BIT_RATE_MASK1) |
+ (*(p_codec_info + 2) & A2DP_AAC_BIT_RATE_MASK2);
+ p_codec_info += 3;
+
+ if (is_capability) return A2DP_SUCCESS;
+
+ if (A2DP_BitsSet(p_ie->objectType) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_OBJ_TYPE;
+ if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_IsSourceCodecValidAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+#else
+ return false;
+#endif
+}
+
+bool A2DP_IsPeerSourceCodecValidAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+#else
+ return false;
+#endif
+}
+
+bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecSupportedAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ return (A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+ true) == A2DP_SUCCESS);
+#else
+ return false;
+#endif
+}
+
+bool A2DP_IsPeerSourceCodecSupportedAac(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ return (A2DP_CodecInfoMatchesCapabilityAac(&a2dp_aac_sink_caps, p_codec_info,
+ true) == A2DP_SUCCESS);
+#else
+ return false;
+#endif
+}
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+void A2DP_InitDefaultCodecAac(uint8_t* p_codec_info) {
+ if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_default_sink_config,
+ p_codec_info) != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_BuildInfoAac failed", __func__);
+ }
+}
+#endif
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(UNUSED_ATTR const uint8_t* p_src_cap,
+ UNUSED_ATTR uint8_t* p_pref_cfg) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ tA2DP_AAC_CIE src_cap;
+ tA2DP_AAC_CIE pref_cap;
+
+ /* initialize it to default AAC configuration */
+ A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_default_sink_config,
+ p_pref_cfg);
+
+ /* now try to build a preferred one */
+ /* parse configuration */
+ tA2DP_STATUS status = A2DP_ParseInfoAac(&src_cap, p_src_cap, true);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse src cap ret = %d", __func__, status);
+ return A2DP_FAIL;
+ }
+
+ if (src_cap.objectType & A2DP_AAC_OBJECT_TYPE_MPEG2_LC) {
+ pref_cap.objectType = A2DP_AAC_OBJECT_TYPE_MPEG2_LC;
+ }
+ else {
+ LOG_ERROR(LOG_TAG, "%s, src_cap.object_type:%d", __func__, src_cap.objectType);
+ }
+
+ if (src_cap.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ pref_cap.sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+ }
+ else if (src_cap.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ pref_cap.sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+ }
+ else {
+ LOG_ERROR(LOG_TAG, "%s, src_cap.samp_freq:%d", __func__, src_cap.sampleRate);
+ }
+
+ if (src_cap.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ pref_cap.channelMode = A2DP_AAC_CHANNEL_MODE_STEREO;
+ }
+ else if (src_cap.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ pref_cap.channelMode = A2DP_AAC_CHANNEL_MODE_MONO;
+ }
+ else {
+ LOG_ERROR(LOG_TAG, "%s, src_cap.channels:%d", __func__, src_cap.channelMode);
+ }
+
+ if ((src_cap.variableBitRateSupport & A2DP_AAC_VARIABLE_BIT_RATE_MASK) == 0) {
+ LOG_ERROR(LOG_TAG, "%s, RMT SRC don't support VBR:%d", __func__, src_cap.variableBitRateSupport);
+ }
+ pref_cap.bitRate= src_cap.bitRate;
+ A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &pref_cap, p_pref_cfg);
+ return A2DP_SUCCESS;
+#else
+ return A2DP_NS_CODEC_TYPE;
+#endif
+}
+
+// Checks whether A2DP AAC codec configuration matches with a device's codec
+// capabilities. |p_cap| is the AAC codec configuration. |p_codec_info| is
+// the device's codec capabilities.
+// If |is_capability| is true, the byte sequence is codec capabilities,
+// otherwise is codec configuration.
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAac(
+ const tA2DP_AAC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability) {
+ tA2DP_STATUS status;
+ tA2DP_AAC_CIE cfg_cie;
+
+ /* parse configuration */
+ status = A2DP_ParseInfoAac(&cfg_cie, p_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ LOG_DEBUG(LOG_TAG, "%s: Object Type peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.objectType, p_cap->objectType);
+ LOG_DEBUG(LOG_TAG, "%s: Sample Rate peer: %u, capability %u", __func__,
+ cfg_cie.sampleRate, p_cap->sampleRate);
+ LOG_DEBUG(LOG_TAG, "%s: Channel Mode peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.channelMode, p_cap->channelMode);
+ LOG_DEBUG(
+ LOG_TAG, "%s: Variable Bit Rate Support peer: 0x%x, capability 0x%x",
+ __func__, cfg_cie.variableBitRateSupport, p_cap->variableBitRateSupport);
+ LOG_DEBUG(LOG_TAG, "%s: Bit Rate peer: %u, capability %u", __func__,
+ cfg_cie.bitRate, p_cap->bitRate);
+
+ /* Object Type */
+ if ((cfg_cie.objectType & p_cap->objectType) == 0) return A2DP_BAD_OBJ_TYPE;
+
+ /* Sample Rate */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_BAD_SAMP_FREQ;
+
+ /* Channel Mode */
+ if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_UsesRtpHeaderAac(UNUSED_ATTR bool content_protection_enabled,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return true;
+}
+
+const char* A2DP_CodecNameAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+ return "AAC";
+}
+
+bool A2DP_CodecTypeEqualsAac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_AAC_CIE aac_cie_a;
+ tA2DP_AAC_CIE aac_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAac(&aac_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAac(&aac_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_AAC_CIE aac_cie_a;
+ tA2DP_AAC_CIE aac_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAac(&aac_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAac(&aac_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return (aac_cie_a.objectType == aac_cie_b.objectType) &&
+ (aac_cie_a.sampleRate == aac_cie_b.sampleRate) &&
+ (aac_cie_a.channelMode == aac_cie_b.channelMode) &&
+ (aac_cie_a.variableBitRateSupport ==
+ aac_cie_b.variableBitRateSupport) &&
+ (aac_cie_a.bitRate == aac_cie_b.bitRate);
+}
+
+int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.sampleRate) {
+ case A2DP_AAC_SAMPLING_FREQ_8000:
+ return 8000;
+ case A2DP_AAC_SAMPLING_FREQ_11025:
+ return 11025;
+ case A2DP_AAC_SAMPLING_FREQ_12000:
+ return 12000;
+ case A2DP_AAC_SAMPLING_FREQ_16000:
+ return 16000;
+ case A2DP_AAC_SAMPLING_FREQ_22050:
+ return 22050;
+ case A2DP_AAC_SAMPLING_FREQ_24000:
+ return 24000;
+ case A2DP_AAC_SAMPLING_FREQ_32000:
+ return 32000;
+ case A2DP_AAC_SAMPLING_FREQ_44100:
+ return 44100;
+ case A2DP_AAC_SAMPLING_FREQ_48000:
+ return 48000;
+ case A2DP_AAC_SAMPLING_FREQ_64000:
+ return 64000;
+ case A2DP_AAC_SAMPLING_FREQ_88200:
+ return 88200;
+ case A2DP_AAC_SAMPLING_FREQ_96000:
+ return 96000;
+ }
+
+ return -1;
+}
+
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // NOTE: Hard-coded value - currently the AAC encoder library
+ // is compiled with 16 bits per sample
+ return 16;
+}
+
+int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.channelMode) {
+ case A2DP_AAC_CHANNEL_MODE_MONO:
+ return 1;
+ case A2DP_AAC_CHANNEL_MODE_STEREO:
+ return 2;
+ }
+
+ return -1;
+}
+
+int A2DP_GetSinkTrackChannelTypeAac(UNUSED_ATTR const uint8_t* p_codec_info) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+
+ tA2DP_AAC_CIE aac_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.channelMode) {
+ case A2DP_AAC_CHANNEL_MODE_MONO:
+ return 1;
+ case A2DP_AAC_CHANNEL_MODE_STEREO:
+ return 3;
+ default:
+ break;
+ }
+ return -1;
+#else
+ return -1;
+#endif
+}
+
+int A2DP_GetSinkFramesCountToProcessAac(
+ UNUSED_ATTR uint64_t time_interval_ms,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return -1;
+}
+
+int A2DP_GetObjectTypeCodeAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.objectType) {
+ case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+ return aac_cie.objectType;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetChannelModeCodeAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.channelMode) {
+ case A2DP_AAC_CHANNEL_MODE_MONO:
+ case A2DP_AAC_CHANNEL_MODE_STEREO:
+ return aac_cie.channelMode;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetVariableBitRateSupportAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aac_cie.variableBitRateSupport) {
+ case A2DP_AAC_VARIABLE_BIT_RATE_ENABLED:
+ case A2DP_AAC_VARIABLE_BIT_RATE_DISABLED:
+ return aac_cie.variableBitRateSupport;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetBitRateAac(const uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return aac_cie.bitRate;
+}
+
+int A2DP_ComputeMaxBitRateAac(const uint8_t* p_codec_info, uint16_t mtu) {
+ tA2DP_AAC_CIE aac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ int sampling_freq = A2DP_GetTrackSampleRateAac(p_codec_info);
+ if (sampling_freq == -1) return -1;
+
+ int pcm_channel_samples_per_frame = 0;
+ switch (aac_cie.objectType) {
+ case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+ pcm_channel_samples_per_frame = 1024;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+ // TODO: The MPEG documentation doesn't specify the value.
+ break;
+ default:
+ break;
+ }
+ if (pcm_channel_samples_per_frame == 0) return -1;
+
+ // See Section 3.2.1 Estimating Average Frame Size from
+ // the aacEncoder.pdf document included with the AAC source code.
+ return (8 * mtu * sampling_freq) / pcm_channel_samples_per_frame;
+}
+
+bool A2DP_GetPacketTimestampAac(const uint8_t* p_codec_info,
+ const uint8_t* p_data, uint32_t* p_timestamp) {
+ // TODO: Is this function really codec-specific?
+ *p_timestamp = *(const uint32_t*)p_data;
+ return true;
+}
+
+bool A2DP_BuildCodecHeaderAac(UNUSED_ATTR const uint8_t* p_codec_info,
+ UNUSED_ATTR BT_HDR* p_buf,
+ UNUSED_ATTR uint16_t frames_per_packet) {
+ return true;
+}
+
+void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info) {
+ tA2DP_STATUS a2dp_status;
+ tA2DP_AAC_CIE aac_cie;
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+ a2dp_status = A2DP_ParseInfoAac(&aac_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAac fail:%d", __func__, a2dp_status);
+ return;
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tobjectType: 0x%x", aac_cie.objectType);
+ if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG2_LC) {
+ LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-2 AAC LC)");
+ }
+ if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LC) {
+ LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC LC)");
+ }
+ if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_LTP) {
+ LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC LTP)");
+ }
+ if (aac_cie.objectType & A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE) {
+ LOG_DEBUG(LOG_TAG, "\tobjectType: (MPEG-4 AAC Scalable)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aac_cie.sampleRate);
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_8000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (8000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_11025) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (11025)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_12000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (12000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_16000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (16000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_22050) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (22050)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_24000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (24000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_32000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (32000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_64000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (64000)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (88200)");
+ }
+ if (aac_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (96000)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", aac_cie.channelMode);
+ if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_MONO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+ }
+ if (aac_cie.channelMode == A2DP_AAC_CHANNEL_MODE_STEREO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tvariableBitRateSupport: %s",
+ (aac_cie.variableBitRateSupport != 0) ? "true" : "false");
+
+ LOG_DEBUG(LOG_TAG, "\tbitRate: %u", aac_cie.bitRate);
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsSourceCodecValidAac(p_codec_info)) return NULL;
+
+ return &a2dp_encoder_interface_aac;
+}
+
+bool A2DP_AdjustCodecAac(uint8_t* p_codec_info) {
+ tA2DP_AAC_CIE cfg_cie;
+
+ // Nothing to do: just verify the codec info is valid
+ if (A2DP_ParseInfoAac(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+ return false;
+
+ return true;
+}
+
+btav_a2dp_codec_index_t A2DP_SourceCodecIndexAac(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SOURCE_AAC;
+}
+
+const char* A2DP_CodecIndexStrAac(void) { return "AAC"; }
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+const char* A2DP_CodecIndexStrAacSink(void) { return "AAC SINK"; }
+#endif
+bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Content protection info - support SCMS-T */
+ uint8_t* p = p_cfg->protect_info;
+ *p++ = AVDT_CP_LOSC;
+ UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+ p_cfg->num_protect = 1;
+#endif
+
+ return true;
+}
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aac_sink_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+ return true;
+}
+#endif
+
+UNUSED_ATTR static void build_codec_config(const tA2DP_AAC_CIE& config_cie,
+ btav_a2dp_codec_config_t* result) {
+ if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ if (config_cie.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+
+ result->bits_per_sample = config_cie.bits_per_sample;
+
+ if (config_cie.channelMode & A2DP_AAC_CHANNEL_MODE_MONO)
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (config_cie.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigAac::A2dpCodecConfigAac(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, "AAC", codec_priority) {
+ // Compute the local capability
+ if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ }
+ if (a2dp_aac_caps.sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ }
+ codec_local_capability_.bits_per_sample = a2dp_aac_caps.bits_per_sample;
+ if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (a2dp_aac_caps.channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigAac::~A2dpCodecConfigAac() {}
+
+bool A2dpCodecConfigAac::init() {
+ if (!isValid()) return false;
+
+ // Load the encoder
+ if (!A2DP_LoadEncoderAac()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecConfigAac::useRtpHeaderMarkerBit() const { return true; }
+
+//
+// Selects the best sample rate from |sampleRate|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint16_t sampleRate,
+ tA2DP_AAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ return true;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ return true;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |sampleRate| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint16_t sampleRate,
+ tA2DP_AAC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ p_result->sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best bits per sample from |bits_per_sample|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_AAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ return true;
+ }
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+ }
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+ const btav_a2dp_codec_config_t* p_codec_audio_config,
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_AAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best channel mode from |channelMode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t channelMode,
+ tA2DP_AAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ p_result->channelMode = A2DP_AAC_CHANNEL_MODE_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ p_result->channelMode = A2DP_AAC_CHANNEL_MODE_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |channelMode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t channelMode,
+ tA2DP_AAC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ p_result->channelMode = A2DP_AAC_CHANNEL_MODE_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ p_result->channelMode = A2DP_AAC_CHANNEL_MODE_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+bool A2dpCodecConfigAac::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ tA2DP_AAC_CIE sink_info_cie;
+ tA2DP_AAC_CIE result_config_cie;
+ uint8_t channelMode;
+ uint16_t sampleRate;
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+
+ // Save the internal state
+ btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+ btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+ btav_a2dp_codec_config_t saved_codec_selectable_capability =
+ codec_selectable_capability_;
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+ memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+ sizeof(ota_codec_peer_config_));
+
+ tA2DP_STATUS status =
+ A2DP_ParseInfoAac(&sink_info_cie, p_peer_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+ __func__, status);
+ goto fail;
+ }
+
+ //
+ // Build the preferred configuration
+ //
+ memset(&result_config_cie, 0, sizeof(result_config_cie));
+
+ // NOTE: Always assign the Object Type and Variable Bit Rate Support.
+ result_config_cie.objectType = a2dp_aac_caps.objectType;
+ result_config_cie.variableBitRateSupport =
+ a2dp_aac_caps.variableBitRateSupport;
+
+ // Set the bit rate as follows:
+ // 1. If the Sink device reports a bogus bit rate
+ // (bitRate < A2DP_AAC_MIN_BITRATE), then use the bit rate from our
+ // configuration. Examples of observed bogus bit rates are zero
+ // and 24576.
+ // 2. If the Sink device reports valid bit rate
+ // (bitRate >= A2DP_AAC_MIN_BITRATE), then use the smaller
+ // of the Sink device's bit rate and the bit rate from our configuration.
+ // In either case, the actual streaming bit rate will also consider the MTU.
+ if (sink_info_cie.bitRate < A2DP_AAC_MIN_BITRATE) {
+ // Bogus bit rate
+ result_config_cie.bitRate = a2dp_aac_caps.bitRate;
+ } else {
+ result_config_cie.bitRate =
+ std::min(a2dp_aac_caps.bitRate, sink_info_cie.bitRate);
+ }
+
+ //
+ // Select the sample frequency
+ //
+ sampleRate = a2dp_aac_caps.sampleRate & sink_info_cie.sampleRate;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ switch (codec_user_config_.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_44100;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_48000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_88200;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ result_config_cie.sampleRate = A2DP_AAC_SAMPLING_FREQ_96000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ break;
+ }
+
+ // Select the sample frequency if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ }
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ }
+
+ if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+ // Compute the common capability
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_44100)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_48000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_88200)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ if (sampleRate & A2DP_AAC_SAMPLING_FREQ_96000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+
+ // No user preference - try the codec audio config
+ if (select_audio_sample_rate(&codec_audio_config_, sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_sample_rate(
+ a2dp_aac_default_config.sampleRate & sink_info_cie.sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_sample_rate(sampleRate, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match sample frequency: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aac_caps.sampleRate, sink_info_cie.sampleRate);
+ goto fail;
+ }
+
+ //
+ // Select the bits per sample
+ //
+ // NOTE: this information is NOT included in the AAC A2DP codec description
+ // that is sent OTA.
+ bits_per_sample = a2dp_aac_caps.bits_per_sample;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ switch (codec_user_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ result_config_cie.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ break;
+ }
+
+ // Select the bits per sample if there is no user preference
+ do {
+ // Compute the selectable capability
+ codec_selectable_capability_.bits_per_sample =
+ a2dp_aac_caps.bits_per_sample;
+
+ if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+ break;
+
+ // Compute the common capability
+ codec_capability_.bits_per_sample = bits_per_sample;
+
+ // No user preference - the the codec audio config
+ if (select_audio_bits_per_sample(&codec_audio_config_,
+ a2dp_aac_caps.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_bits_per_sample(a2dp_aac_default_config.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_bits_per_sample(a2dp_aac_caps.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match bits per sample: default = 0x%x "
+ "user preference = 0x%x",
+ __func__, a2dp_aac_default_config.bits_per_sample,
+ codec_user_config_.bits_per_sample);
+ goto fail;
+ }
+
+ //
+ // Select the channel mode
+ //
+ channelMode = a2dp_aac_caps.channelMode & sink_info_cie.channelMode;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ switch (codec_user_config_.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ result_config_cie.channelMode = A2DP_AAC_CHANNEL_MODE_MONO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ result_config_cie.channelMode = A2DP_AAC_CHANNEL_MODE_STEREO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ break;
+ }
+
+ // Select the channel mode if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+ // Compute the common capability
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_MONO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (channelMode & A2DP_AAC_CHANNEL_MODE_STEREO) {
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ // No user preference - try the codec audio config
+ if (select_audio_channel_mode(&codec_audio_config_, channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_channel_mode(
+ a2dp_aac_default_config.channelMode & sink_info_cie.channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_channel_mode(channelMode, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match channel mode: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aac_caps.channelMode, sink_info_cie.channelMode);
+ goto fail;
+ }
+
+ if (A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ p_result_codec_config) != A2DP_SUCCESS) {
+ goto fail;
+ }
+
+ //
+ // Copy the codec-specific fields if they are not zero
+ //
+ if (codec_user_config_.codec_specific_1 != 0)
+ codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+ if (codec_user_config_.codec_specific_2 != 0)
+ codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+ if (codec_user_config_.codec_specific_3 != 0)
+ codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+ if (codec_user_config_.codec_specific_4 != 0)
+ codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
+
+ // Create a local copy of the peer codec capability, and the
+ // result codec config.
+ if (is_capability) {
+ status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_capability_);
+ } else {
+ status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_config_);
+ }
+ CHECK(status == A2DP_SUCCESS);
+ status = A2DP_BuildInfoAac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ ota_codec_config_);
+ CHECK(status == A2DP_SUCCESS);
+ return true;
+
+fail:
+ // Restore the internal state
+ codec_config_ = saved_codec_config;
+ codec_capability_ = saved_codec_capability;
+ codec_selectable_capability_ = saved_codec_selectable_capability;
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+ memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+ sizeof(ota_codec_peer_config_));
+ return false;
+}
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+A2dpCodecConfigAacSink::A2dpCodecConfigAacSink(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_AAC, "AAC(Sink)",
+ codec_priority) {}
+
+A2dpCodecConfigAacSink::~A2dpCodecConfigAacSink() {}
+
+bool A2dpCodecConfigAacSink::init() {
+ if (!isValid()) return false;
+
+ return true;
+}
+bool A2dpCodecConfigAacSink::useRtpHeaderMarkerBit() const {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigAacSink::setCodecConfig(
+ UNUSED_ATTR const uint8_t* p_peer_codec_info,
+ UNUSED_ATTR bool is_capability,
+ UNUSED_ATTR uint8_t* p_result_codec_config) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigAacSink::updateEncoderUserConfig(
+ UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+ UNUSED_ATTR bool* p_config_updated) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+period_ms_t A2dpCodecConfigAacSink::encoderIntervalMs() const {
+ // TODO: This method applies only to Source codecs
+ return 0;
+}
+#endif
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_aac_encoder.cc b/mtkbt/code/bt/stack/a2dp/a2dp_aac_encoder.cc
new file mode 100755
index 0000000..9c69588
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_aac_encoder.cc
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_aac_encoder"
+
+#include "a2dp_aac_encoder.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <aacenc_lib.h>
+#include <base/logging.h>
+
+#include "a2dp_aac.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Encoder for AAC Source Codec
+//
+
+// A2DP AAC encoder interval in milliseconds
+#define A2DP_AAC_ENCODER_INTERVAL_MS 20
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_AAC_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#else
+#define A2DP_AAC_OFFSET AVDT_MEDIA_OFFSET
+#endif
+
+typedef struct {
+ uint32_t sample_rate;
+ uint8_t channel_mode;
+ uint8_t bits_per_sample;
+ uint32_t frame_length; // Samples per channel in a frame
+ uint8_t input_channels_n; // Number of channels
+ int max_encoded_buffer_bytes; // Max encoded bytes per frame
+} tA2DP_AAC_ENCODER_PARAMS;
+
+typedef struct {
+ uint32_t counter;
+ uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
+ uint64_t last_frame_us;
+} tA2DP_AAC_FEEDING_STATE;
+
+typedef struct {
+ uint64_t session_start_us;
+
+ size_t media_read_total_expected_packets;
+ size_t media_read_total_expected_reads_count;
+ size_t media_read_total_expected_read_bytes;
+
+ size_t media_read_total_dropped_packets;
+ size_t media_read_total_actual_reads_count;
+ size_t media_read_total_actual_read_bytes;
+} a2dp_aac_encoder_stats_t;
+
+typedef struct {
+ a2dp_source_read_callback_t read_callback;
+ a2dp_source_enqueue_callback_t enqueue_callback;
+ uint16_t TxAaMtuSize;
+
+ bool use_SCMS_T;
+ bool is_peer_edr; // True if the peer device supports EDR
+ bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
+ uint16_t peer_mtu; // MTU of the A2DP peer
+ uint32_t timestamp; // Timestamp for the A2DP frames
+
+ HANDLE_AACENCODER aac_handle;
+ bool has_aac_handle; // True if aac_handle is valid
+
+ tA2DP_FEEDING_PARAMS feeding_params;
+ tA2DP_AAC_ENCODER_PARAMS aac_encoder_params;
+ tA2DP_AAC_FEEDING_STATE aac_feeding_state;
+
+ a2dp_aac_encoder_stats_t stats;
+} tA2DP_AAC_ENCODER_CB;
+
+static tA2DP_AAC_ENCODER_CB a2dp_aac_encoder_cb;
+
+static void a2dp_aac_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated);
+static void a2dp_aac_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us);
+static void a2dp_aac_encode_frames(uint8_t nb_frame);
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer);
+
+bool A2DP_LoadEncoderAac(void) {
+ // Nothing to do - the library is statically linked
+ return true;
+}
+
+void A2DP_UnloadEncoderAac(void) {
+ // Nothing to do - the library is statically linked
+ if (a2dp_aac_encoder_cb.has_aac_handle)
+ aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+ memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+}
+
+void a2dp_aac_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback) {
+ if (a2dp_aac_encoder_cb.has_aac_handle)
+ aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+ memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+
+ a2dp_aac_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+ a2dp_aac_encoder_cb.read_callback = read_callback;
+ a2dp_aac_encoder_cb.enqueue_callback = enqueue_callback;
+ a2dp_aac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_aac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aac_encoder_cb.timestamp = 0;
+
+ a2dp_aac_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ a2dp_aac_encoder_cb.use_SCMS_T = true;
+#endif
+
+ // NOTE: Ignore the restart_input / restart_output flags - this initization
+ // happens when the connection is (re)started.
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ a2dp_aac_encoder_update(a2dp_aac_encoder_cb.peer_mtu, a2dp_codec_config,
+ &restart_input, &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigAac::updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ a2dp_aac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_aac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aac_encoder_cb.timestamp = 0;
+
+ if (a2dp_aac_encoder_cb.peer_mtu == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid peer MTU",
+ __func__, name().c_str());
+ return false;
+ }
+
+ a2dp_aac_encoder_update(a2dp_aac_encoder_cb.peer_mtu, this, p_restart_input,
+ p_restart_output, p_config_updated);
+ return true;
+}
+
+// Update the A2DP AAC encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_aac_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated) {
+ tA2DP_AAC_ENCODER_PARAMS* p_encoder_params =
+ &a2dp_aac_encoder_cb.aac_encoder_params;
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+ AACENC_ERROR aac_error;
+ int aac_param_value, aac_sampling_freq, aac_peak_bit_rate;
+
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ if (!a2dp_aac_encoder_cb.has_aac_handle) {
+ AACENC_ERROR aac_error = aacEncOpen(&a2dp_aac_encoder_cb.aac_handle, 0,
+ 2 /* max 2 channels: stereo */);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot open AAC encoder handle: AAC error 0x%x",
+ __func__, aac_error);
+ return; // TODO: Return an error?
+ }
+ a2dp_aac_encoder_cb.has_aac_handle = true;
+ }
+
+ if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid codec config",
+ __func__, a2dp_codec_config->name().c_str());
+ return;
+ }
+ const uint8_t* p_codec_info = codec_info;
+
+ // The feeding parameters
+ tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aac_encoder_cb.feeding_params;
+ p_feeding_params->sample_rate = A2DP_GetTrackSampleRateAac(p_codec_info);
+ p_feeding_params->bits_per_sample =
+ a2dp_codec_config->getAudioBitsPerSample();
+ p_feeding_params->channel_count = A2DP_GetTrackChannelCountAac(p_codec_info);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+ __func__, p_feeding_params->sample_rate,
+ p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+ // The codec parameters
+ p_encoder_params->sample_rate =
+ a2dp_aac_encoder_cb.feeding_params.sample_rate;
+ p_encoder_params->channel_mode = A2DP_GetChannelModeCodeAac(p_codec_info);
+
+ uint16_t mtu_size = BT_DEFAULT_BUFFER_SIZE - A2DP_AAC_OFFSET - sizeof(BT_HDR);
+ if (mtu_size < peer_mtu) {
+ a2dp_aac_encoder_cb.TxAaMtuSize = mtu_size;
+ } else {
+ a2dp_aac_encoder_cb.TxAaMtuSize = peer_mtu;
+ }
+
+ LOG_DEBUG(LOG_TAG, "%s: MTU=%d, peer_mtu=%d", __func__,
+ a2dp_aac_encoder_cb.TxAaMtuSize, peer_mtu);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate: %d channel_mode: %d ", __func__,
+ p_encoder_params->sample_rate, p_encoder_params->channel_mode);
+
+ // Set the encoder's parameters: Audio Object Type - MANDATORY
+ // A2DP_AAC_OBJECT_TYPE_MPEG2_LC -> AOT_AAC_LC
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_LC -> AOT_AAC_LC
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_LTP -> AOT_AAC_LTP
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE -> AOT_AAC_SCAL
+ aac_param_value = AOT_AAC_LC;
+ int object_type = A2DP_GetObjectTypeCodeAac(p_codec_info);
+ switch (object_type) {
+ case A2DP_AAC_OBJECT_TYPE_MPEG2_LC:
+ aac_param_value = AOT_AAC_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LC:
+ aac_param_value = AOT_AAC_LC;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_LTP:
+ aac_param_value = AOT_AAC_LTP;
+ break;
+ case A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE:
+ aac_param_value = AOT_AAC_SCAL;
+ break;
+ default:
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_AOT: "
+ "invalid object type %d",
+ __func__, object_type);
+ return; // TODO: Return an error?
+ }
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle, AACENC_AOT,
+ aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_AOT to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: audioMuxVersion
+ aac_param_value = 2; // audioMuxVersion = "2"
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_AUDIOMUXVER, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_AUDIOMUXVER to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Signaling mode of the extension AOT
+ aac_param_value = 1; // Signaling mode of the extension AOT = 1
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_SIGNALING_MODE, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_SIGNALING_MODE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Sample Rate - MANDATORY
+ aac_param_value = A2DP_GetTrackSampleRateAac(p_codec_info);
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_SAMPLERATE, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_SAMPLERATE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+ aac_sampling_freq = aac_param_value; // Save for extra usage below
+
+ // Set the encoder's parameters: Bit Rate - MANDATORY
+ aac_param_value = A2DP_GetBitRateAac(p_codec_info);
+ // Calculate the bit rate from MTU and sampling frequency
+ aac_peak_bit_rate =
+ A2DP_ComputeMaxBitRateAac(p_codec_info, a2dp_aac_encoder_cb.TxAaMtuSize);
+ aac_param_value = std::min(aac_param_value, aac_peak_bit_rate);
+ LOG_DEBUG(LOG_TAG, "%s: MTU = %d Sampling Frequency = %d Bit Rate = %d",
+ __func__, a2dp_aac_encoder_cb.TxAaMtuSize, aac_sampling_freq,
+ aac_param_value);
+ if (aac_param_value == -1) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_BITRATE: "
+ "invalid codec bit rate",
+ __func__);
+ return; // TODO: Return an error?
+ }
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_BITRATE, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_BITRATE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: PEAK Bit Rate
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_PEAK_BITRATE, aac_peak_bit_rate);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_PEAK_BITRATE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_peak_bit_rate, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Channel Mode - MANDATORY
+ if (A2DP_GetTrackChannelCountAac(p_codec_info) == 1) {
+ aac_param_value = MODE_1; // Mono
+ } else {
+ aac_param_value = MODE_2; // Stereo
+ }
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_CHANNELMODE, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_CHANNELMODE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Transport Type
+ aac_param_value = TT_MP4_LATM_MCP1; // muxConfigPresent = 1
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_TRANSMUX, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_TRANSMUX to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Header Period
+ aac_param_value = 1;
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_HEADER_PERIOD, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_HEADER_PERIOD to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Set the encoder's parameters: Variable Bit Rate Support
+ aac_param_value = A2DP_GetVariableBitRateSupportAac(p_codec_info);
+ if (aac_param_value == -1) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_BITRATEMODE: "
+ "invalid codec bit rate mode",
+ __func__);
+ return; // TODO: Return an error?
+ }
+ aac_error = aacEncoder_SetParam(a2dp_aac_encoder_cb.aac_handle,
+ AACENC_BITRATEMODE, aac_param_value);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot set AAC parameter AACENC_BITRATEMODE to %d: "
+ "AAC error 0x%x",
+ __func__, aac_param_value, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Mark the end of setting the encoder's parameters
+ aac_error =
+ aacEncEncode(a2dp_aac_encoder_cb.aac_handle, NULL, NULL, NULL, NULL);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot complete setting the AAC parameters: AAC error 0x%x",
+ __func__, aac_error);
+ return; // TODO: Return an error?
+ }
+
+ // Retrieve the encoder info so we can save the frame length
+ AACENC_InfoStruct aac_info;
+ aac_error = aacEncInfo(a2dp_aac_encoder_cb.aac_handle, &aac_info);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot retrieve the AAC encoder info: AAC error 0x%x",
+ __func__, aac_error);
+ return; // TODO: Return an error?
+ }
+ p_encoder_params->frame_length = aac_info.frameLength;
+ p_encoder_params->input_channels_n = aac_info.inputChannels;
+ p_encoder_params->max_encoded_buffer_bytes = aac_info.maxOutBufBytes;
+ LOG_DEBUG(LOG_TAG,
+ "%s: AAC frame_length = %u input_channels_n = %u "
+ "max_encoded_buffer_bytes = %d",
+ __func__, p_encoder_params->frame_length,
+ p_encoder_params->input_channels_n,
+ p_encoder_params->max_encoded_buffer_bytes);
+}
+
+void a2dp_aac_encoder_cleanup(void) {
+ if (a2dp_aac_encoder_cb.has_aac_handle)
+ aacEncClose(&a2dp_aac_encoder_cb.aac_handle);
+ memset(&a2dp_aac_encoder_cb, 0, sizeof(a2dp_aac_encoder_cb));
+}
+
+void a2dp_aac_feeding_reset(void) {
+ /* By default, just clear the entire state */
+ memset(&a2dp_aac_encoder_cb.aac_feeding_state, 0,
+ sizeof(a2dp_aac_encoder_cb.aac_feeding_state));
+
+ a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick =
+ (a2dp_aac_encoder_cb.feeding_params.sample_rate *
+ a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8 *
+ a2dp_aac_encoder_cb.feeding_params.channel_count *
+ A2DP_AAC_ENCODER_INTERVAL_MS) /
+ 1000;
+
+ LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", __func__,
+ a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick);
+}
+
+void a2dp_aac_feeding_flush(void) {
+ a2dp_aac_encoder_cb.aac_feeding_state.counter = 0;
+}
+
+period_ms_t a2dp_aac_get_encoder_interval_ms(void) {
+ return A2DP_AAC_ENCODER_INTERVAL_MS;
+}
+
+void a2dp_aac_send_frames(uint64_t timestamp_us) {
+ uint8_t nb_frame = 0;
+ uint8_t nb_iterations = 0;
+
+ a2dp_aac_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+ LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations",
+ __func__, nb_frame, nb_iterations);
+ if (nb_frame == 0) return;
+
+ for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+ // Transcode frame and enqueue
+ a2dp_aac_encode_frames(nb_frame);
+ }
+}
+
+// Obtains the number of frames to send and number of iterations
+// to be used. |num_of_iterations| and |num_of_frames| parameters
+// are used as output param for returning the respective values.
+static void a2dp_aac_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us) {
+ uint32_t result = 0;
+ uint8_t nof = 0;
+ uint8_t noi = 1;
+
+ uint32_t pcm_bytes_per_frame =
+ a2dp_aac_encoder_cb.aac_encoder_params.frame_length *
+ a2dp_aac_encoder_cb.feeding_params.channel_count *
+ a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;
+ LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
+ pcm_bytes_per_frame);
+
+ uint32_t us_this_tick = A2DP_AAC_ENCODER_INTERVAL_MS * 1000;
+ uint64_t now_us = timestamp_us;
+ if (a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us != 0)
+ us_this_tick =
+ (now_us - a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us);
+ a2dp_aac_encoder_cb.aac_feeding_state.last_frame_us = now_us;
+
+ a2dp_aac_encoder_cb.aac_feeding_state.counter +=
+ a2dp_aac_encoder_cb.aac_feeding_state.bytes_per_tick * us_this_tick /
+ (A2DP_AAC_ENCODER_INTERVAL_MS * 1000);
+
+ result = a2dp_aac_encoder_cb.aac_feeding_state.counter / pcm_bytes_per_frame;
+ a2dp_aac_encoder_cb.aac_feeding_state.counter -= result * pcm_bytes_per_frame;
+ nof = result;
+
+ LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+ __func__, nof, noi);
+
+ *num_of_frames = nof;
+ *num_of_iterations = noi;
+}
+
+static void a2dp_aac_encode_frames(uint8_t nb_frame) {
+ tA2DP_AAC_ENCODER_PARAMS* p_encoder_params =
+ &a2dp_aac_encoder_cb.aac_encoder_params;
+ tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aac_encoder_cb.feeding_params;
+ uint8_t remain_nb_frame = nb_frame;
+ uint8_t read_buffer[BT_DEFAULT_BUFFER_SIZE];
+ int pcm_bytes_per_frame = p_encoder_params->frame_length *
+ p_feeding_params->channel_count *
+ p_feeding_params->bits_per_sample / 8;
+ CHECK(pcm_bytes_per_frame <= static_cast<int>(sizeof(read_buffer)));
+
+ // Setup the input buffer
+ AACENC_BufDesc in_buf_desc;
+ void* in_buf_vector[1] = {nullptr};
+ int in_buf_identifiers[1] = {IN_AUDIO_DATA};
+ int in_buf_sizes[1] = {pcm_bytes_per_frame};
+ int in_buf_element_sizes[1] = {p_feeding_params->bits_per_sample / 8};
+ in_buf_desc.numBufs = 1;
+ in_buf_desc.bufs = in_buf_vector;
+ in_buf_desc.bufferIdentifiers = in_buf_identifiers;
+ in_buf_desc.bufSizes = in_buf_sizes;
+ in_buf_desc.bufElSizes = in_buf_element_sizes;
+
+ // Setup the output buffer (partially)
+ AACENC_BufDesc out_buf_desc;
+ void* out_buf_vector[1] = {nullptr};
+ int out_buf_identifiers[1] = {OUT_BITSTREAM_DATA};
+ int out_buf_sizes[1] = {p_encoder_params->max_encoded_buffer_bytes};
+ // NOTE: out_buf_element_sizes below is probably unused by the encoder
+ int out_buf_element_sizes[1] = {p_feeding_params->bits_per_sample / 8};
+ out_buf_desc.numBufs = 1;
+ out_buf_desc.bufs = out_buf_vector;
+ out_buf_desc.bufferIdentifiers = out_buf_identifiers;
+ out_buf_desc.bufSizes = out_buf_sizes;
+ out_buf_desc.bufElSizes = out_buf_element_sizes;
+ CHECK(p_encoder_params->max_encoded_buffer_bytes <=
+ static_cast<int>(BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR)));
+
+ AACENC_InArgs aac_in_args;
+ aac_in_args.numInSamples =
+ p_encoder_params->frame_length * p_feeding_params->channel_count;
+ aac_in_args.numAncBytes = 0;
+
+ AACENC_OutArgs aac_out_args = {
+ .numOutBytes = 0, .numInSamples = 0, .numAncBytes = 0};
+
+ uint32_t count;
+ int written = 0;
+
+ while (nb_frame) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ p_buf->offset = A2DP_AAC_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+ a2dp_aac_encoder_cb.stats.media_read_total_expected_packets++;
+
+ count = 0;
+ do {
+ //
+ // Read the PCM data and encode it
+ //
+ if (a2dp_aac_read_feeding(read_buffer)) {
+ uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+ if (!a2dp_aac_encoder_cb.has_aac_handle) {
+ LOG_ERROR(LOG_TAG, "%s: invalid AAC handle", __func__);
+ a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ return;
+ }
+ in_buf_vector[0] = read_buffer;
+ out_buf_vector[0] = packet + count;
+ AACENC_ERROR aac_error =
+ aacEncEncode(a2dp_aac_encoder_cb.aac_handle, &in_buf_desc,
+ &out_buf_desc, &aac_in_args, &aac_out_args);
+ if (aac_error != AACENC_OK) {
+ LOG_ERROR(LOG_TAG, "%s: AAC encoding error: 0x%x", __func__,
+ aac_error);
+ a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ return;
+ }
+ written = aac_out_args.numOutBytes;
+ count += written;
+ p_buf->len += written;
+ nb_frame--;
+ p_buf->layer_specific++; // added a frame to the buffer
+ } else {
+ LOG_WARN(LOG_TAG, "%s: underflow %d", __func__, nb_frame);
+ a2dp_aac_encoder_cb.aac_feeding_state.counter +=
+ nb_frame * p_encoder_params->frame_length *
+ p_feeding_params->channel_count *
+ p_feeding_params->bits_per_sample / 8;
+
+ // no more pcm to read
+ nb_frame = 0;
+ }
+ } while ((written == 0) && nb_frame);
+
+ // NOTE: We don't check whether the packet will fit in the MTU,
+ // because AAC doesn't give us control over the encoded frame size.
+ // If the packet is larger than the MTU, it will be fragmented before
+ // transmission.
+ if (p_buf->len) {
+ /*
+ * Timestamp of the media packet header represent the TS of the
+ * first frame, i.e the timestamp before including this frame.
+ */
+ *((uint32_t*)(p_buf + 1)) = a2dp_aac_encoder_cb.timestamp;
+
+ a2dp_aac_encoder_cb.timestamp +=
+ p_buf->layer_specific * p_encoder_params->frame_length;
+
+ uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+ remain_nb_frame = nb_frame;
+ if (!a2dp_aac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+ } else {
+ a2dp_aac_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ }
+ }
+}
+
+static bool a2dp_aac_read_feeding(uint8_t* read_buffer) {
+ uint32_t read_size = a2dp_aac_encoder_cb.aac_encoder_params.frame_length *
+ a2dp_aac_encoder_cb.feeding_params.channel_count *
+ a2dp_aac_encoder_cb.feeding_params.bits_per_sample / 8;
+
+ a2dp_aac_encoder_cb.stats.media_read_total_expected_reads_count++;
+ a2dp_aac_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;
+
+ /* Read Data from UIPC channel */
+ uint32_t nb_byte_read =
+ a2dp_aac_encoder_cb.read_callback(read_buffer, read_size);
+ a2dp_aac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+
+ if (nb_byte_read < read_size) {
+ if (nb_byte_read == 0) return false;
+
+ /* Fill the unfilled part of the read buffer with silence (0) */
+ memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+ nb_byte_read = read_size;
+ }
+ a2dp_aac_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+ return true;
+}
+
+period_ms_t A2dpCodecConfigAac::encoderIntervalMs() const {
+ return a2dp_aac_get_encoder_interval_ms();
+}
+
+void A2dpCodecConfigAac::debug_codec_dump(int fd) {
+ a2dp_aac_encoder_stats_t* stats = &a2dp_aac_encoder_cb.stats;
+
+ A2dpCodecConfig::debug_codec_dump(fd);
+
+ dprintf(fd,
+ " Packet counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_packets,
+ stats->media_read_total_dropped_packets);
+
+ dprintf(fd,
+ " PCM read counts (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_reads_count,
+ stats->media_read_total_actual_reads_count);
+
+ dprintf(fd,
+ " PCM read bytes (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_read_bytes,
+ stats->media_read_total_actual_read_bytes);
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_api.cc b/mtkbt/code/bt/stack/a2dp/a2dp_api.cc
new file mode 100755
index 0000000..cf2c214
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_api.cc
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Common API for the Advanced Audio Distribution Profile (A2DP)
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_api"
+
+#include "a2dp_api.h"
+
+#include <string.h>
+
+#include "a2dp_int.h"
+#include "avdt_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "sdpdefs.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+tA2DP_CB a2dp_cb;
+
+/******************************************************************************
+ *
+ * Function a2dp_sdp_cback
+ *
+ * Description This is the SDP callback function used by A2DP_FindService.
+ * This function will be executed by SDP when the service
+ * search is completed. If the search is successful, it
+ * finds the first record in the database that matches the
+ * UUID of the search. Then retrieves various parameters
+ * from the record. When it is finished it calls the
+ * application callback function.
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+static void a2dp_sdp_cback(uint16_t status) {
+ tSDP_DISC_REC* p_rec = NULL;
+ tSDP_DISC_ATTR* p_attr;
+ bool found = false;
+ tA2DP_Service a2dp_svc;
+ tSDP_PROTOCOL_ELEM elem;
+
+ LOG_VERBOSE(LOG_TAG, "%s: status: %d", __func__, status);
+
+ if (status == SDP_SUCCESS) {
+ /* loop through all records we found */
+ do {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(
+ a2dp_cb.find.p_db, a2dp_cb.find.service_uuid, p_rec)) == NULL) {
+ break;
+ }
+ memset(&a2dp_svc, 0, sizeof(tA2DP_Service));
+
+ /* get service name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) !=
+ NULL) {
+ a2dp_svc.p_service_name = (char*)p_attr->attr_value.v.array;
+ a2dp_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get provider name */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_PROVIDER_NAME)) !=
+ NULL) {
+ a2dp_svc.p_provider_name = (char*)p_attr->attr_value.v.array;
+ a2dp_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ }
+
+ /* get supported features */
+ if ((p_attr = SDP_FindAttributeInRec(
+ p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) {
+ a2dp_svc.features = p_attr->attr_value.v.u16;
+ }
+
+ /* get AVDTP version */
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) {
+ a2dp_svc.avdt_version = elem.params[0];
+ LOG_VERBOSE(LOG_TAG, "avdt_version: 0x%x", a2dp_svc.avdt_version);
+ }
+
+ /* we've got everything, we're done */
+ found = true;
+ break;
+
+ } while (true);
+ }
+
+ a2dp_cb.find.service_uuid = 0;
+ osi_free_and_reset((void**)&a2dp_cb.find.p_db);
+ /* return info from sdp record in app callback function */
+ if (a2dp_cb.find.p_cback != NULL) {
+ (*a2dp_cb.find.p_cback)(found, &a2dp_svc);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_set_avdt_sdp_ver
+ *
+ * Description This function allows the script wrapper to change the
+ * avdt version of a2dp.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver) {
+ a2dp_cb.avdt_sdp_ver = avdt_sdp_ver;
+}
+
+/******************************************************************************
+ *
+ * Function A2DP_AddRecord
+ *
+ * Description This function is called by a server application to add
+ * SRC or SNK information to an SDP record. Prior to
+ * calling this function the application must call
+ * SDP_CreateRecord() to create an SDP record.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates SRC or SNK.
+ *
+ * p_service_name: Pointer to a null-terminated character
+ * string containing the service name.
+ *
+ * p_provider_name: Pointer to a null-terminated character
+ * string containing the provider name.
+ *
+ * features: Profile supported features.
+ *
+ * sdp_handle: SDP handle returned by SDP_CreateRecord().
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns A2DP_SUCCESS if function execution succeeded,
+ * A2DP_INVALID_PARAMS if bad parameters are given.
+ * A2DP_FAIL if function execution failed.
+ *
+ *****************************************************************************/
+tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name,
+ char* p_provider_name, uint16_t features,
+ uint32_t sdp_handle) {
+ uint16_t browse_list[1];
+ bool result = true;
+ uint8_t temp[8];
+ uint8_t* p;
+ tSDP_PROTOCOL_ELEM proto_list[A2DP_NUM_PROTO_ELEMS];
+
+ LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid);
+
+ if ((sdp_handle == 0) || (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&
+ service_uuid != UUID_SERVCLASS_AUDIO_SINK))
+ return A2DP_INVALID_PARAMS;
+
+ /* add service class id list */
+ result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid);
+
+ memset((void*)proto_list, 0,
+ A2DP_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
+
+ /* add protocol descriptor list */
+ proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_list[0].num_params = 1;
+ proto_list[0].params[0] = AVDT_PSM;
+ proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP;
+ proto_list[1].num_params = 1;
+ proto_list[1].params[0] = a2dp_cb.avdt_sdp_ver;
+
+ result &= SDP_AddProtocolList(sdp_handle, A2DP_NUM_PROTO_ELEMS, proto_list);
+
+ /* add profile descriptor list */
+ result &= SDP_AddProfileDescriptorList(
+ sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2DP_VERSION);
+
+ /* add supported feature */
+ if (features != 0) {
+ p = temp;
+ UINT16_TO_BE_STREAM(p, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+ }
+
+ /* add provider name */
+ if (p_provider_name != NULL) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+ browse_list);
+
+ return (result ? A2DP_SUCCESS : A2DP_FAIL);
+}
+
+/******************************************************************************
+ *
+ * Function A2DP_FindService
+ *
+ * Description This function is called by a client application to
+ * perform service discovery and retrieve SRC or SNK SDP
+ * record information from a server. Information is
+ * returned for the first service record found on the
+ * server that matches the service UUID. The callback
+ * function will be executed when service discovery is
+ * complete. There can only be one outstanding call to
+ * A2DP_FindService() at a time; the application must wait
+ * for the callback before it makes another call to
+ * the function.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates SRC or SNK.
+ *
+ * bd_addr: BD address of the peer device.
+ *
+ * p_db: Pointer to the information to initialize
+ * the discovery database.
+ *
+ * p_cback: Pointer to the A2DP_FindService()
+ * callback function.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns A2DP_SUCCESS if function execution succeeded,
+ * A2DP_INVALID_PARAMS if bad parameters are given.
+ * A2DP_BUSY if discovery is already in progress.
+ * A2DP_FAIL if function execution failed.
+ *
+ *****************************************************************************/
+tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+ tA2DP_SDP_DB_PARAMS* p_db,
+ tA2DP_FIND_CBACK* p_cback) {
+ tSDP_UUID uuid_list;
+ bool result = true;
+ uint16_t a2dp_attr_list[] = {
+ ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2DP_NUM_ATTR, if changed */
+ ATTR_ID_BT_PROFILE_DESC_LIST, ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_SERVICE_NAME, ATTR_ID_PROTOCOL_DESC_LIST,
+ ATTR_ID_PROVIDER_NAME};
+
+ LOG_VERBOSE(LOG_TAG, "%s: uuid: 0x%x", __func__, service_uuid);
+ if ((service_uuid != UUID_SERVCLASS_AUDIO_SOURCE &&
+ service_uuid != UUID_SERVCLASS_AUDIO_SINK) ||
+ p_db == NULL || p_cback == NULL)
+ return A2DP_INVALID_PARAMS;
+
+ if (a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE ||
+ a2dp_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK)
+ return A2DP_BUSY;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
+ p_db->p_attrs = a2dp_attr_list;
+ p_db->num_attr = A2DP_NUM_ATTR;
+ }
+
+ if (a2dp_cb.find.p_db == NULL)
+ a2dp_cb.find.p_db = (tSDP_DISCOVERY_DB*)osi_malloc(p_db->db_len);
+
+ result = SDP_InitDiscoveryDb(a2dp_cb.find.p_db, p_db->db_len, 1, &uuid_list,
+ p_db->num_attr, p_db->p_attrs);
+
+ if (result == true) {
+ /* store service_uuid */
+ a2dp_cb.find.service_uuid = service_uuid;
+ a2dp_cb.find.p_cback = p_cback;
+
+ /* perform service search */
+ result = SDP_ServiceSearchAttributeRequest(bd_addr, a2dp_cb.find.p_db,
+ a2dp_sdp_cback);
+ if (false == result) {
+ a2dp_cb.find.service_uuid = 0;
+ }
+ }
+
+ return (result ? A2DP_SUCCESS : A2DP_FAIL);
+}
+
+/******************************************************************************
+ *
+ * Function A2DP_SetTraceLevel
+ *
+ * Description Sets the trace level for A2D. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the A2DP tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+uint8_t A2DP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) a2dp_cb.trace_level = new_level;
+
+ return (a2dp_cb.trace_level);
+}
+
+/******************************************************************************
+ * Function A2DP_BitsSet
+ *
+ * Description Check the given num for the number of bits set
+ * Returns A2DP_SET_ONE_BIT, if one and only one bit is set
+ * A2DP_SET_ZERO_BIT, if all bits clear
+ * A2DP_SET_MULTL_BIT, if multiple bits are set
+ *****************************************************************************/
+uint8_t A2DP_BitsSet(uint64_t num) {
+ if (num == 0) return A2DP_SET_ZERO_BIT;
+ if ((num & (num - 1)) == 0) return A2DP_SET_ONE_BIT;
+ return A2DP_SET_MULTL_BIT;
+}
+
+/*******************************************************************************
+ *
+ * Function A2DP_Init
+ *
+ * Description This function is called to initialize the control block
+ * for this layer. It must be called before accessing any
+ * other API functions for this layer. It is typically called
+ * once during the start up of the stack.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void A2DP_Init(void) {
+ memset(&a2dp_cb, 0, sizeof(tA2DP_CB));
+
+ a2dp_cb.avdt_sdp_ver = AVDT_VERSION;
+
+#if defined(A2DP_INITIAL_TRACE_LEVEL)
+ a2dp_cb.trace_level = A2DP_INITIAL_TRACE_LEVEL;
+#else
+ a2dp_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/** M: Bug fix for When doing A2DP close, cancel SDP if it has been started to avoid NE@{ */
+/******************************************************************************
+** Function A2D_Get_Disc_DB
+**
+** Description get discovery database of a2dp
+** Returns point of discovery database
+******************************************************************************/
+tSDP_DISCOVERY_DB * A2D_Get_Disc_DB(void)
+{
+ return a2dp_cb.find.p_db;
+}
+/** @} */
+
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_codec_config.cc b/mtkbt/code/bt/stack/a2dp/a2dp_codec_config.cc
new file mode 100755
index 0000000..766afe1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_codec_config.cc
@@ -0,0 +1,1316 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A2DP Codecs Configuration
+ */
+
+#define LOG_TAG "a2dp_codec"
+
+#include "a2dp_codec_api.h"
+
+#include <base/logging.h>
+#include <inttypes.h>
+
+#include "a2dp_aac.h"
+#include "a2dp_sbc.h"
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx.h"
+#include "a2dp_vendor_aptx_hd.h"
+#include "a2dp_vendor_ldac.h"
+#include "osi/include/log.h"
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#include "mtk_bt_av.h"
+#endif
+/* The Media Type offset within the codec info byte array */
+#define A2DP_MEDIA_TYPE_OFFSET 1
+
+// Initializes the codec config.
+// |codec_config| is the codec config to initialize.
+// |codec_index| and |codec_priority| are the codec type and priority to use
+// for the initialization.
+static void init_btav_a2dp_codec_config(
+ btav_a2dp_codec_config_t* codec_config, btav_a2dp_codec_index_t codec_index,
+ btav_a2dp_codec_priority_t codec_priority) {
+ memset(codec_config, 0, sizeof(btav_a2dp_codec_config_t));
+ codec_config->codec_type = codec_index;
+ codec_config->codec_priority = codec_priority;
+}
+
+A2dpCodecConfig::A2dpCodecConfig(btav_a2dp_codec_index_t codec_index,
+ const std::string& name,
+ btav_a2dp_codec_priority_t codec_priority)
+ : codec_index_(codec_index),
+ name_(name),
+ default_codec_priority_(codec_priority) {
+ setCodecPriority(codec_priority);
+
+ init_btav_a2dp_codec_config(&codec_config_, codec_index_, codecPriority());
+ init_btav_a2dp_codec_config(&codec_capability_, codec_index_,
+ codecPriority());
+ init_btav_a2dp_codec_config(&codec_local_capability_, codec_index_,
+ codecPriority());
+ init_btav_a2dp_codec_config(&codec_selectable_capability_, codec_index_,
+ codecPriority());
+ init_btav_a2dp_codec_config(&codec_user_config_, codec_index_,
+ BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
+ init_btav_a2dp_codec_config(&codec_audio_config_, codec_index_,
+ BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
+
+ memset(ota_codec_config_, 0, sizeof(ota_codec_config_));
+ memset(ota_codec_peer_capability_, 0, sizeof(ota_codec_peer_capability_));
+ memset(ota_codec_peer_config_, 0, sizeof(ota_codec_peer_config_));
+}
+
+A2dpCodecConfig::~A2dpCodecConfig() {}
+
+void A2dpCodecConfig::setCodecPriority(
+ btav_a2dp_codec_priority_t codec_priority) {
+ if (codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) {
+ // Compute the default codec priority
+ setDefaultCodecPriority();
+ } else {
+ codec_priority_ = codec_priority;
+ }
+}
+
+void A2dpCodecConfig::setDefaultCodecPriority() {
+ if (default_codec_priority_ != BTAV_A2DP_CODEC_PRIORITY_DEFAULT) {
+ codec_priority_ = default_codec_priority_;
+ } else {
+ // Compute the default codec priority
+ uint32_t priority = 1000 * (codec_index_ + 1) + 1;
+ codec_priority_ = static_cast<btav_a2dp_codec_priority_t>(priority);
+ }
+}
+
+A2dpCodecConfig* A2dpCodecConfig::createCodec(
+ btav_a2dp_codec_index_t codec_index,
+ btav_a2dp_codec_priority_t codec_priority) {
+ LOG_DEBUG(LOG_TAG, "%s: codec %s", __func__, A2DP_CodecIndexStr(codec_index));
+
+ A2dpCodecConfig* codec_config = nullptr;
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ codec_config = new A2dpCodecConfigSbc(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ codec_config = new A2dpCodecConfigSbcSink(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ codec_config = new A2dpCodecConfigAac(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ codec_config = new A2dpCodecConfigAptx(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ codec_config = new A2dpCodecConfigAptxHd(codec_priority);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ codec_config = new A2dpCodecConfigLdac(codec_priority);
+ break;
+ // Add a switch statement for each vendor-specific codec
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ break;
+ }
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (BTAV_A2DP_CODEC_INDEX_SINK_AAC == codec_index)
+ codec_config = new A2dpCodecConfigAacSink(codec_priority);
+#endif
+ if (codec_config != nullptr) {
+ if (!codec_config->init()) {
+ delete codec_config;
+ codec_config = nullptr;
+ }
+ }
+
+ return codec_config;
+}
+
+bool A2dpCodecConfig::isValid() const { return true; }
+
+bool A2dpCodecConfig::copyOutOtaCodecConfig(uint8_t* p_codec_info) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ // TODO: We should use a mechanism to verify codec config,
+ // not codec capability.
+ if (!A2DP_IsSourceCodecValid(ota_codec_config_)) {
+ return false;
+ }
+ memcpy(p_codec_info, ota_codec_config_, sizeof(ota_codec_config_));
+ return true;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecConfig() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ // TODO: We should check whether the codec config is valid
+ return codec_config_;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecCapability() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ // TODO: We should check whether the codec capability is valid
+ return codec_capability_;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecLocalCapability() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ // TODO: We should check whether the codec capability is valid
+ return codec_local_capability_;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecSelectableCapability() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ // TODO: We should check whether the codec capability is valid
+ return codec_selectable_capability_;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecUserConfig() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ return codec_user_config_;
+}
+
+btav_a2dp_codec_config_t A2dpCodecConfig::getCodecAudioConfig() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ return codec_audio_config_;
+}
+
+uint8_t A2dpCodecConfig::getAudioBitsPerSample() {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ switch (codec_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return 16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return 24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return 32;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return 0;
+}
+
+bool A2dpCodecConfig::isCodecConfigEmpty(
+ const btav_a2dp_codec_config_t& codec_config) {
+ return (
+ (codec_config.codec_priority == BTAV_A2DP_CODEC_PRIORITY_DEFAULT) &&
+ (codec_config.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) &&
+ (codec_config.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) &&
+ (codec_config.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) &&
+ (codec_config.codec_specific_1 == 0) &&
+ (codec_config.codec_specific_2 == 0) &&
+ (codec_config.codec_specific_3 == 0) &&
+ (codec_config.codec_specific_4 == 0));
+}
+
+bool A2dpCodecConfig::setCodecUserConfig(
+ const btav_a2dp_codec_config_t& codec_user_config,
+ const btav_a2dp_codec_config_t& codec_audio_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ // Save copies of the current codec config, and the OTA codec config, so they
+ // can be compared for changes.
+ btav_a2dp_codec_config_t saved_codec_config = getCodecConfig();
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ codec_user_config_ = codec_user_config;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ codec_audio_config_ = codec_audio_config;
+ bool success =
+ setCodecConfig(p_peer_codec_info, is_capability, p_result_codec_config);
+ if (!success) {
+ // Restore the local copy of the user and audio config
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ return false;
+ }
+
+ //
+ // The input (audio data) should be restarted if the audio format has changed
+ //
+ btav_a2dp_codec_config_t new_codec_config = getCodecConfig();
+ if ((saved_codec_config.sample_rate != new_codec_config.sample_rate) ||
+ (saved_codec_config.bits_per_sample !=
+ new_codec_config.bits_per_sample) ||
+ (saved_codec_config.channel_mode != new_codec_config.channel_mode)) {
+ *p_restart_input = true;
+ }
+
+ //
+ // The output (the connection) should be restarted if OTA codec config
+ // has changed.
+ //
+ if (!A2DP_CodecEquals(saved_ota_codec_config, p_result_codec_config)) {
+ *p_restart_output = true;
+ }
+
+ bool encoder_restart_input = *p_restart_input;
+ bool encoder_restart_output = *p_restart_output;
+ bool encoder_config_updated = *p_config_updated;
+ if (updateEncoderUserConfig(p_peer_params, &encoder_restart_input,
+ &encoder_restart_output,
+ &encoder_config_updated)) {
+ if (encoder_restart_input) *p_restart_input = true;
+ if (encoder_restart_output) *p_restart_output = true;
+ if (encoder_config_updated) *p_config_updated = true;
+ }
+ if (*p_restart_input || *p_restart_output) *p_config_updated = true;
+
+ return true;
+}
+
+bool A2dpCodecConfig::codecConfigIsValid(
+ const btav_a2dp_codec_config_t& codec_config) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ return (codec_config.codec_type < (BTAV_A2DP_CODEC_INDEX_MAX + 1)) &&
+#else
+ return (codec_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) &&
+#endif
+ (codec_config.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) &&
+ (codec_config.bits_per_sample !=
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) &&
+ (codec_config.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE);
+}
+
+std::string A2dpCodecConfig::codecConfig2Str(
+ const btav_a2dp_codec_config_t& codec_config) {
+ std::string result;
+
+ if (!codecConfigIsValid(codec_config)) return "Invalid";
+
+ result.append("Rate=");
+ result.append(codecSampleRate2Str(codec_config.sample_rate));
+ result.append(" Bits=");
+ result.append(codecBitsPerSample2Str(codec_config.bits_per_sample));
+ result.append(" Mode=");
+ result.append(codecChannelMode2Str(codec_config.channel_mode));
+
+ return result;
+}
+
+std::string A2dpCodecConfig::codecSampleRate2Str(
+ btav_a2dp_codec_sample_rate_t codec_sample_rate) {
+ std::string result;
+
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_44100) {
+ if (!result.empty()) result += "|";
+ result += "44100";
+ }
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_48000) {
+ if (!result.empty()) result += "|";
+ result += "48000";
+ }
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_88200) {
+ if (!result.empty()) result += "|";
+ result += "88200";
+ }
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_96000) {
+ if (!result.empty()) result += "|";
+ result += "96000";
+ }
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_176400) {
+ if (!result.empty()) result += "|";
+ result += "176400";
+ }
+ if (codec_sample_rate & BTAV_A2DP_CODEC_SAMPLE_RATE_192000) {
+ if (!result.empty()) result += "|";
+ result += "192000";
+ }
+ if (result.empty()) {
+ std::stringstream ss;
+ ss << "UnknownSampleRate(0x" << std::hex << codec_sample_rate << ")";
+ ss >> result;
+ }
+
+ return result;
+}
+
+std::string A2dpCodecConfig::codecBitsPerSample2Str(
+ btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample) {
+ std::string result;
+
+ if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ if (!result.empty()) result += "|";
+ result += "16";
+ }
+ if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ if (!result.empty()) result += "|";
+ result += "24";
+ }
+ if (codec_bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ if (!result.empty()) result += "|";
+ result += "32";
+ }
+ if (result.empty()) {
+ std::stringstream ss;
+ ss << "UnknownBitsPerSample(0x" << std::hex << codec_bits_per_sample << ")";
+ ss >> result;
+ }
+
+ return result;
+}
+
+std::string A2dpCodecConfig::codecChannelMode2Str(
+ btav_a2dp_codec_channel_mode_t codec_channel_mode) {
+ std::string result;
+
+ if (codec_channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_MONO) {
+ if (!result.empty()) result += "|";
+ result += "MONO";
+ }
+ if (codec_channel_mode & BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO) {
+ if (!result.empty()) result += "|";
+ result += "STEREO";
+ }
+ if (result.empty()) {
+ std::stringstream ss;
+ ss << "UnknownChannelMode(0x" << std::hex << codec_channel_mode << ")";
+ ss >> result;
+ }
+
+ return result;
+}
+
+void A2dpCodecConfig::debug_codec_dump(int fd) {
+ std::string result;
+ dprintf(fd, "\nA2DP %s State:\n", name().c_str());
+ dprintf(fd, " Priority: %d\n", codecPriority());
+ dprintf(fd, " Encoder interval (ms): %" PRIu64 "\n", encoderIntervalMs());
+
+ result = codecConfig2Str(getCodecConfig());
+ dprintf(fd, " Config: %s\n", result.c_str());
+
+ result = codecConfig2Str(getCodecSelectableCapability());
+ dprintf(fd, " Selectable: %s\n", result.c_str());
+
+ result = codecConfig2Str(getCodecLocalCapability());
+ dprintf(fd, " Local capability: %s\n", result.c_str());
+}
+
+//
+// Compares two codecs |lhs| and |rhs| based on their priority.
+// Returns true if |lhs| has higher priority (larger priority value).
+// If |lhs| and |rhs| have same priority, the unique codec index is used
+// as a tie-breaker: larger codec index value means higher priority.
+//
+static bool compare_codec_priority(const A2dpCodecConfig* lhs,
+ const A2dpCodecConfig* rhs) {
+ if (lhs->codecPriority() > rhs->codecPriority()) return true;
+ if (lhs->codecPriority() < rhs->codecPriority()) return false;
+ return (lhs->codecIndex() > rhs->codecIndex());
+}
+
+A2dpCodecs::A2dpCodecs(
+ const std::vector<btav_a2dp_codec_config_t>& codec_priorities)
+ : current_codec_config_(nullptr) {
+ for (auto config : codec_priorities) {
+ codec_priorities_.insert(
+ std::make_pair(config.codec_type, config.codec_priority));
+ }
+}
+
+A2dpCodecs::~A2dpCodecs() {
+ std::unique_lock<std::recursive_mutex> lock(codec_mutex_);
+ for (const auto& iter : indexed_codecs_) {
+ delete iter.second;
+ }
+ for (const auto& iter : disabled_codecs_) {
+ delete iter.second;
+ }
+ lock.unlock();
+}
+
+bool A2dpCodecs::init() {
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ btav_a2dp_codec_index_t codec_index =
+ static_cast<btav_a2dp_codec_index_t>(i);
+
+ // Select the codec priority if explicitly configured
+ btav_a2dp_codec_priority_t codec_priority =
+ BTAV_A2DP_CODEC_PRIORITY_DEFAULT;
+ auto cp_iter = codec_priorities_.find(codec_index);
+ if (cp_iter != codec_priorities_.end()) {
+ codec_priority = cp_iter->second;
+ }
+
+ A2dpCodecConfig* codec_config =
+ A2dpCodecConfig::createCodec(codec_index, codec_priority);
+ if (codec_config == nullptr) continue;
+
+ if (codec_priority != BTAV_A2DP_CODEC_PRIORITY_DEFAULT) {
+ LOG_INFO(LOG_TAG, "%s: updated %s codec priority to %d", __func__,
+ codec_config->name().c_str(), codec_priority);
+ }
+
+ // Test if the codec is disabled
+ if (codec_config->codecPriority() == BTAV_A2DP_CODEC_PRIORITY_DISABLED) {
+ disabled_codecs_.insert(std::make_pair(codec_index, codec_config));
+ continue;
+ }
+
+ indexed_codecs_.insert(std::make_pair(codec_index, codec_config));
+
+ if (codec_index < BTAV_A2DP_CODEC_INDEX_SOURCE_MAX) {
+ ordered_source_codecs_.push_back(codec_config);
+ ordered_source_codecs_.sort(compare_codec_priority);
+ } else {
+ ordered_sink_codecs_.push_back(codec_config);
+ ordered_sink_codecs_.sort(compare_codec_priority);
+ }
+ }
+
+ if (ordered_source_codecs_.empty()) {
+ LOG_ERROR(LOG_TAG, "%s: no Source codecs were initialized", __func__);
+ } else {
+ for (auto iter : ordered_source_codecs_) {
+ LOG_INFO(LOG_TAG, "%s: initialized Source codec %s", __func__,
+ iter->name().c_str());
+ }
+ }
+ if (ordered_sink_codecs_.empty()) {
+ LOG_ERROR(LOG_TAG, "%s: no Sink codecs were initialized", __func__);
+ } else {
+ for (auto iter : ordered_sink_codecs_) {
+ LOG_INFO(LOG_TAG, "%s: initialized Sink codec %s", __func__,
+ iter->name().c_str());
+ }
+ }
+
+ return (!ordered_source_codecs_.empty() && !ordered_sink_codecs_.empty());
+}
+
+A2dpCodecConfig* A2dpCodecs::findSourceCodecConfig(
+ const uint8_t* p_codec_info) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ btav_a2dp_codec_index_t codec_index = A2DP_SourceCodecIndex(p_codec_info);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (codec_index == (BTAV_A2DP_CODEC_INDEX_MAX + 1)) return nullptr;
+#else
+ if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) return nullptr;
+#endif
+ auto iter = indexed_codecs_.find(codec_index);
+ if (iter == indexed_codecs_.end()) return nullptr;
+ return iter->second;
+}
+
+bool A2dpCodecs::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config,
+ bool select_current_codec) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ A2dpCodecConfig* a2dp_codec_config = findSourceCodecConfig(p_peer_codec_info);
+ if (a2dp_codec_config == nullptr) return false;
+ if (!a2dp_codec_config->setCodecConfig(p_peer_codec_info, is_capability,
+ p_result_codec_config)) {
+ return false;
+ }
+ if (select_current_codec) {
+ current_codec_config_ = a2dp_codec_config;
+ }
+ return true;
+}
+
+bool A2dpCodecs::setCodecUserConfig(
+ const btav_a2dp_codec_config_t& codec_user_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_sink_capabilities, uint8_t* p_result_codec_config,
+ bool* p_restart_input, bool* p_restart_output, bool* p_config_updated) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ btav_a2dp_codec_config_t codec_audio_config;
+ A2dpCodecConfig* a2dp_codec_config = nullptr;
+ A2dpCodecConfig* last_codec_config = current_codec_config_;
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s: Configuring: codec_type=%d codec_priority=%d "
+ "sample_rate=0x%x bits_per_sample=0x%x "
+ "channel_mode=0x%x codec_specific_1=%" PRIi64
+ " "
+ "codec_specific_2=%" PRIi64
+ " "
+ "codec_specific_3=%" PRIi64
+ " "
+ "codec_specific_4=%" PRIi64,
+ __func__, codec_user_config.codec_type, codec_user_config.codec_priority,
+ codec_user_config.sample_rate, codec_user_config.bits_per_sample,
+ codec_user_config.channel_mode, codec_user_config.codec_specific_1,
+ codec_user_config.codec_specific_2, codec_user_config.codec_specific_3,
+ codec_user_config.codec_specific_4);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (codec_user_config.codec_type < (BTAV_A2DP_CODEC_INDEX_MAX + 1)) {
+#else
+ if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) {
+#endif
+ auto iter = indexed_codecs_.find(codec_user_config.codec_type);
+ if (iter == indexed_codecs_.end()) goto fail;
+ a2dp_codec_config = iter->second;
+ } else {
+ // Update the default codec
+ a2dp_codec_config = current_codec_config_;
+ }
+ if (a2dp_codec_config == nullptr) goto fail;
+
+ // Reuse the existing codec audio config
+ codec_audio_config = a2dp_codec_config->getCodecAudioConfig();
+ if (!a2dp_codec_config->setCodecUserConfig(
+ codec_user_config, codec_audio_config, p_peer_params,
+ p_peer_sink_capabilities, true, p_result_codec_config,
+ p_restart_input, p_restart_output, p_config_updated)) {
+ goto fail;
+ }
+
+ // Update the codec priorities, and eventually restart the connection
+ // if a new codec needs to be selected.
+ do {
+ // Update the codec priority
+ btav_a2dp_codec_priority_t old_priority =
+ a2dp_codec_config->codecPriority();
+ btav_a2dp_codec_priority_t new_priority = codec_user_config.codec_priority;
+ a2dp_codec_config->setCodecPriority(new_priority);
+ // Get the actual (recomputed) priority
+ new_priority = a2dp_codec_config->codecPriority();
+
+ // Check if there was no previous codec
+ if (last_codec_config == nullptr) {
+ current_codec_config_ = a2dp_codec_config;
+ *p_restart_output = true;
+ break;
+ }
+
+ // Check if the priority of the current codec was updated
+ if (a2dp_codec_config == last_codec_config) {
+ if (old_priority == new_priority) break; // No change in priority
+
+ *p_config_updated = true;
+ if (new_priority < old_priority) {
+ // The priority has become lower - restart the connection to
+ // select a new codec.
+ *p_restart_output = true;
+ }
+ break;
+ }
+
+ if (new_priority <= old_priority) {
+ // No change in priority, or the priority has become lower.
+ // This wasn't the current codec, so we shouldn't select a new codec.
+ if (*p_restart_input || *p_restart_output ||
+ (old_priority != new_priority)) {
+ *p_config_updated = true;
+ }
+ *p_restart_input = false;
+ *p_restart_output = false;
+ break;
+ }
+
+ *p_config_updated = true;
+ if (new_priority >= last_codec_config->codecPriority()) {
+ // The new priority is higher than the current codec. Restart the
+ // connection to select a new codec.
+ current_codec_config_ = a2dp_codec_config;
+ last_codec_config->setDefaultCodecPriority();
+ *p_restart_output = true;
+ }
+ } while (false);
+ ordered_source_codecs_.sort(compare_codec_priority);
+
+ if (*p_restart_input || *p_restart_output) *p_config_updated = true;
+
+ LOG_DEBUG(LOG_TAG,
+ "%s: Configured: restart_input = %d restart_output = %d "
+ "config_updated = %d",
+ __func__, *p_restart_input, *p_restart_output, *p_config_updated);
+
+ return true;
+
+fail:
+ current_codec_config_ = last_codec_config;
+ return false;
+}
+
+bool A2dpCodecs::setCodecAudioConfig(
+ const btav_a2dp_codec_config_t& codec_audio_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_sink_capabilities, uint8_t* p_result_codec_config,
+ bool* p_restart_output, bool* p_config_updated) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ btav_a2dp_codec_config_t codec_user_config;
+ A2dpCodecConfig* a2dp_codec_config = current_codec_config_;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ if (a2dp_codec_config == nullptr) return false;
+
+ // Reuse the existing codec user config
+ codec_user_config = a2dp_codec_config->getCodecUserConfig();
+ bool restart_input = false; // Flag ignored - input was just restarted
+ if (!a2dp_codec_config->setCodecUserConfig(
+ codec_user_config, codec_audio_config, p_peer_params,
+ p_peer_sink_capabilities, true, p_result_codec_config, &restart_input,
+ p_restart_output, p_config_updated)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecs::setCodecOtaConfig(
+ const uint8_t* p_ota_codec_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ uint8_t* p_result_codec_config, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ btav_a2dp_codec_index_t codec_type;
+ btav_a2dp_codec_config_t codec_user_config;
+ btav_a2dp_codec_config_t codec_audio_config;
+ A2dpCodecConfig* a2dp_codec_config = nullptr;
+ A2dpCodecConfig* last_codec_config = current_codec_config_;
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ // Check whether the current codec config is explicitly configured by
+ // user configuration. If yes, then the OTA codec configuration is ignored.
+ if (current_codec_config_ != nullptr) {
+ codec_user_config = current_codec_config_->getCodecUserConfig();
+ if (!A2dpCodecConfig::isCodecConfigEmpty(codec_user_config)) {
+ LOG_WARN(LOG_TAG,
+ "%s: ignoring peer OTA configuration for codec %s: "
+ "existing user configuration for current codec %s",
+ __func__, A2DP_CodecName(p_ota_codec_config),
+ current_codec_config_->name().c_str());
+ goto fail;
+ }
+ }
+
+ // Check whether the codec config for the same codec is explicitly configured
+ // by user configuration. If yes, then the OTA codec configuration is
+ // ignored.
+ codec_type = A2DP_SourceCodecIndex(p_ota_codec_config);
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (codec_type == (BTAV_A2DP_CODEC_INDEX_MAX + 1)) {
+#else
+ if (codec_type == BTAV_A2DP_CODEC_INDEX_MAX) {
+#endif
+ LOG_WARN(LOG_TAG,
+ "%s: ignoring peer OTA codec configuration: "
+ "invalid codec",
+ __func__);
+ goto fail; // Invalid codec
+ } else {
+ auto iter = indexed_codecs_.find(codec_type);
+ if (iter == indexed_codecs_.end()) {
+ LOG_WARN(LOG_TAG,
+ "%s: cannot find codec configuration for peer OTA codec %s",
+ __func__, A2DP_CodecName(p_ota_codec_config));
+ goto fail;
+ }
+ a2dp_codec_config = iter->second;
+ }
+ if (a2dp_codec_config == nullptr) goto fail;
+ codec_user_config = a2dp_codec_config->getCodecUserConfig();
+ if (!A2dpCodecConfig::isCodecConfigEmpty(codec_user_config)) {
+ LOG_WARN(LOG_TAG,
+ "%s: ignoring peer OTA configuration for codec %s: "
+ "existing user configuration for same codec",
+ __func__, A2DP_CodecName(p_ota_codec_config));
+ goto fail;
+ }
+ current_codec_config_ = a2dp_codec_config;
+
+ // Reuse the existing codec user config and codec audio config
+ codec_audio_config = a2dp_codec_config->getCodecAudioConfig();
+ if (!a2dp_codec_config->setCodecUserConfig(
+ codec_user_config, codec_audio_config, p_peer_params,
+ p_ota_codec_config, false, p_result_codec_config, p_restart_input,
+ p_restart_output, p_config_updated)) {
+ LOG_WARN(LOG_TAG,
+ "%s: cannot set codec configuration for peer OTA codec %s",
+ __func__, A2DP_CodecName(p_ota_codec_config));
+ goto fail;
+ }
+ CHECK(current_codec_config_ != nullptr);
+
+ if (*p_restart_input || *p_restart_output) *p_config_updated = true;
+
+ return true;
+
+fail:
+ current_codec_config_ = last_codec_config;
+ return false;
+}
+
+bool A2dpCodecs::getCodecConfigAndCapabilities(
+ btav_a2dp_codec_config_t* p_codec_config,
+ std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
+ std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+
+ if (current_codec_config_ != nullptr) {
+ *p_codec_config = current_codec_config_->getCodecConfig();
+ } else {
+ btav_a2dp_codec_config_t codec_config;
+ memset(&codec_config, 0, sizeof(codec_config));
+ *p_codec_config = codec_config;
+ }
+
+ std::vector<btav_a2dp_codec_config_t> codecs_capabilities;
+ for (auto codec : orderedSourceCodecs()) {
+ codecs_capabilities.push_back(codec->getCodecLocalCapability());
+ }
+ *p_codecs_local_capabilities = codecs_capabilities;
+
+ codecs_capabilities.clear();
+ for (auto codec : orderedSourceCodecs()) {
+ btav_a2dp_codec_config_t codec_capability =
+ codec->getCodecSelectableCapability();
+ // Don't add entries that cannot be used
+ if ((codec_capability.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||
+ (codec_capability.bits_per_sample ==
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||
+ (codec_capability.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {
+ continue;
+ }
+ codecs_capabilities.push_back(codec_capability);
+ }
+ *p_codecs_selectable_capabilities = codecs_capabilities;
+
+ return true;
+}
+
+void A2dpCodecs::debug_codec_dump(int fd) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ dprintf(fd, "\nA2DP Codecs State:\n");
+
+ // Print the current codec name
+ if (current_codec_config_ != nullptr) {
+ dprintf(fd, " Current Codec: %s\n", current_codec_config_->name().c_str());
+ } else {
+ dprintf(fd, " Current Codec: None\n");
+ }
+
+ // Print the codec-specific state
+ for (auto codec_config : ordered_source_codecs_) {
+ codec_config->debug_codec_dump(fd);
+ }
+}
+
+tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info) {
+ return (tA2DP_CODEC_TYPE)(p_codec_info[AVDT_CODEC_TYPE_INDEX]);
+}
+
+bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsSourceCodecValidSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsSourceCodecValidAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorSourceCodecValid(p_codec_info);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsSinkCodecValidSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsSinkCodecValidAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorSinkCodecValid(p_codec_info);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsPeerSourceCodecValidSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsPeerSourceCodecValidAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorPeerSourceCodecValid(p_codec_info);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsPeerSinkCodecValidSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsPeerSinkCodecValidAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorPeerSinkCodecValid(p_codec_info);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsSinkCodecSupportedSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsSinkCodecSupportedAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorSinkCodecSupported(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
+
+bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_IsPeerSourceCodecSupportedSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_IsPeerSourceCodecSupportedAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_IsVendorPeerSourceCodecSupported(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
+
+void A2DP_InitDefaultCodec(uint8_t* p_codec_info) {
+ A2DP_InitDefaultCodecSbc(p_codec_info);
+}
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+void A2DP_InitAacDefaultCodec(uint8_t* p_codec_info) {
+ A2DP_InitDefaultCodecAac(p_codec_info);
+}
+#endif
+tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_src_cap);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_BuildSrc2SinkConfigSbc(p_src_cap, p_pref_cfg);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_BuildSrc2SinkConfigAac(p_src_cap, p_pref_cfg);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorBuildSrc2SinkConfig(p_src_cap, p_pref_cfg);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return A2DP_NS_CODEC_TYPE;
+}
+
+bool A2DP_UsesRtpHeader(bool content_protection_enabled,
+ const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ if (codec_type != A2DP_MEDIA_CT_NON_A2DP) return true;
+
+ return A2DP_VendorUsesRtpHeader(content_protection_enabled, p_codec_info);
+}
+
+uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info) {
+ uint8_t media_type = (p_codec_info[A2DP_MEDIA_TYPE_OFFSET] >> 4) & 0x0f;
+ return media_type;
+}
+
+const char* A2DP_CodecName(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_CodecNameSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_CodecNameAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorCodecName(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return "UNKNOWN CODEC";
+}
+
+bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ if (codec_type_a != codec_type_b) return false;
+
+ switch (codec_type_a) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_CodecTypeEqualsSbc(p_codec_info_a, p_codec_info_b);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_CodecTypeEqualsAac(p_codec_info_a, p_codec_info_b);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorCodecTypeEquals(p_codec_info_a, p_codec_info_b);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+ return false;
+}
+
+bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ if (codec_type_a != codec_type_b) return false;
+
+ switch (codec_type_a) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_CodecEqualsSbc(p_codec_info_a, p_codec_info_b);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_CodecEqualsAac(p_codec_info_a, p_codec_info_b);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorCodecEquals(p_codec_info_a, p_codec_info_b);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type_a);
+ return false;
+}
+
+int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetTrackSampleRateSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetTrackSampleRateAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetTrackSampleRate(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
+int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetTrackBitsPerSampleAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetTrackBitsPerSample(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
+int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetTrackChannelCountSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetTrackChannelCountAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetTrackChannelCount(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
+int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetSinkTrackChannelTypeSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetSinkTrackChannelTypeAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetSinkTrackChannelType(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
+int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetSinkFramesCountToProcessSbc(time_interval_ms,
+ p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetSinkFramesCountToProcessAac(time_interval_ms,
+ p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetSinkFramesCountToProcess(time_interval_ms,
+ p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return -1;
+}
+
+bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
+ uint32_t* p_timestamp) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetPacketTimestampSbc(p_codec_info, p_data, p_timestamp);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetPacketTimestampAac(p_codec_info, p_data, p_timestamp);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetPacketTimestamp(p_codec_info, p_data, p_timestamp);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
+
+bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_BuildCodecHeaderSbc(p_codec_info, p_buf, frames_per_packet);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_BuildCodecHeaderAac(p_codec_info, p_buf, frames_per_packet);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorBuildCodecHeader(p_codec_info, p_buf,
+ frames_per_packet);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
+ const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_GetEncoderInterfaceSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_GetEncoderInterfaceAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorGetEncoderInterface(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return NULL;
+}
+
+bool A2DP_AdjustCodec(uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_AdjustCodecSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_AdjustCodecAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorAdjustCodec(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return false;
+}
+
+btav_a2dp_codec_index_t A2DP_SourceCodecIndex(const uint8_t* p_codec_info) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(p_codec_info);
+
+ LOG_VERBOSE(LOG_TAG, "%s: codec_type = 0x%x", __func__, codec_type);
+
+ switch (codec_type) {
+ case A2DP_MEDIA_CT_SBC:
+ return A2DP_SourceCodecIndexSbc(p_codec_info);
+ case A2DP_MEDIA_CT_AAC:
+ return A2DP_SourceCodecIndexAac(p_codec_info);
+ case A2DP_MEDIA_CT_NON_A2DP:
+ return A2DP_VendorSourceCodecIndex(p_codec_info);
+ default:
+ break;
+ }
+
+ LOG_ERROR(LOG_TAG, "%s: unsupported codec type 0x%x", __func__, codec_type);
+ return BTAV_A2DP_CODEC_INDEX_MAX;
+}
+
+const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index) {
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ return A2DP_CodecIndexStrSbc();
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ return A2DP_CodecIndexStrSbcSink();
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ return A2DP_CodecIndexStrAac();
+ default:
+ break;
+ }
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (BTAV_A2DP_CODEC_INDEX_SINK_AAC == codec_index)
+ return A2DP_CodecIndexStrAacSink();
+#endif
+ if (codec_index < BTAV_A2DP_CODEC_INDEX_MAX)
+ return A2DP_VendorCodecIndexStr(codec_index);
+
+ return "UNKNOWN CODEC INDEX";
+}
+
+bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg) {
+ LOG_VERBOSE(LOG_TAG, "%s: codec %s", __func__,
+ A2DP_CodecIndexStr(codec_index));
+
+ /* Default: no content protection info */
+ p_cfg->num_protect = 0;
+ p_cfg->protect_info[0] = 0;
+
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ return A2DP_InitCodecConfigSbc(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ return A2DP_InitCodecConfigSbcSink(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ return A2DP_InitCodecConfigAac(p_cfg);
+ default:
+ break;
+ }
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (BTAV_A2DP_CODEC_INDEX_SINK_AAC == codec_index)
+ return A2DP_InitCodecConfigAacSink(p_cfg);
+#endif
+
+ if (codec_index < BTAV_A2DP_CODEC_INDEX_MAX)
+ return A2DP_VendorInitCodecConfig(codec_index, p_cfg);
+
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_int.h b/mtkbt/code/bt/stack/a2dp/a2dp_int.h
new file mode 100755
index 0000000..6fb4543
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_int.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * 2DP internal header file
+ *
+ ******************************************************************************/
+#ifndef A2DP_INT_H
+#define A2DP_INT_H
+
+#include "a2dp_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+#define A2DP_VERSION 0x0102
+
+/* Number of attributes in A2DP SDP record. */
+#define A2DP_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define A2DP_NUM_PROTO_ELEMS 2
+
+/*****************************************************************************
+ * Type definitions
+ ****************************************************************************/
+
+/* Control block used by A2DP_FindService(). */
+typedef struct {
+ tA2DP_FIND_CBACK* p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */
+ uint16_t service_uuid; /* service UUID of search */
+} tA2DP_FIND_CB;
+
+typedef struct {
+ tA2DP_FIND_CB find; /* find service control block */
+ uint8_t trace_level;
+ uint16_t avdt_sdp_ver; /* AVDTP version */
+} tA2DP_CB;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+extern tA2DP_CB a2dp_cb;
+
+/* Used only for conformance testing */
+extern void a2dp_set_avdt_sdp_ver(uint16_t avdt_sdp_ver);
+
+#endif /* A2DP_INT_H */
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_sbc.cc b/mtkbt/code/bt/stack/a2dp/a2dp_sbc.cc
new file mode 100755
index 0000000..45ff08c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_sbc.cc
@@ -0,0 +1,1670 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse SBC Codec Information Element
+ * and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_sbc"
+
+#include "bt_target.h"
+
+#include "a2dp_sbc.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_sbc_encoder.h"
+#include "bt_utils.h"
+#include "embdrv/sbc/encoder/include/sbc_encoder.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#define A2DP_SBC_MAX_BITPOOL 53
+
+/* data type for the SBC Codec Information Element */
+typedef struct {
+ uint8_t samp_freq; /* Sampling frequency */
+ uint8_t ch_mode; /* Channel mode */
+ uint8_t block_len; /* Block length */
+ uint8_t num_subbands; /* Number of subbands */
+ uint8_t alloc_method; /* Allocation method */
+ uint8_t min_bitpool; /* Minimum bitpool */
+ uint8_t max_bitpool; /* Maximum bitpool */
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_SBC_CIE;
+
+/* SBC SRC codec capabilities */
+static const tA2DP_SBC_CIE a2dp_sbc_caps = {
+ A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+ /** M: Bug Fix for PTS case @{ */
+ // In PTS & A2DP spec, SBC MUST support MONO and other one channel mode
+ // and the MUST support all block length range.
+ // Original code:
+ // A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */
+ // A2DP_SBC_IE_BLOCKS_16, /* block_len */
+ (A2DP_SBC_IE_CH_MD_MONO |A2DP_SBC_IE_CH_MD_JOINT), /* ch_mode */
+ (A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
+ A2DP_SBC_IE_BLOCKS_4), /* block_len */
+ /** @} */
+ A2DP_SBC_IE_SUBBAND_8, /* num_subbands */
+ A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */
+ A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */
+ A2DP_SBC_MAX_BITPOOL, /* max_bitpool */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
+};
+
+/* SBC SINK codec capabilities */
+static const tA2DP_SBC_CIE a2dp_sbc_sink_caps = {
+ (A2DP_SBC_IE_SAMP_FREQ_48 | A2DP_SBC_IE_SAMP_FREQ_44), /* samp_freq */
+ (A2DP_SBC_IE_CH_MD_MONO | A2DP_SBC_IE_CH_MD_STEREO |
+ A2DP_SBC_IE_CH_MD_JOINT | A2DP_SBC_IE_CH_MD_DUAL), /* ch_mode */
+ (A2DP_SBC_IE_BLOCKS_16 | A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 |
+ A2DP_SBC_IE_BLOCKS_4), /* block_len */
+ (A2DP_SBC_IE_SUBBAND_4 | A2DP_SBC_IE_SUBBAND_8), /* num_subbands */
+ (A2DP_SBC_IE_ALLOC_MD_L | A2DP_SBC_IE_ALLOC_MD_S), /* alloc_method */
+ A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */
+ A2DP_SBC_MAX_BITPOOL, /* max_bitpool */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
+};
+
+/* Default SBC codec configuration */
+const tA2DP_SBC_CIE a2dp_sbc_default_config = {
+ A2DP_SBC_IE_SAMP_FREQ_44, /* samp_freq */
+ A2DP_SBC_IE_CH_MD_JOINT, /* ch_mode */
+ A2DP_SBC_IE_BLOCKS_16, /* block_len */
+ A2DP_SBC_IE_SUBBAND_8, /* num_subbands */
+ A2DP_SBC_IE_ALLOC_MD_L, /* alloc_method */
+ A2DP_SBC_IE_MIN_BITPOOL, /* min_bitpool */
+ A2DP_SBC_MAX_BITPOOL, /* max_bitpool */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_sbc = {
+ a2dp_sbc_encoder_init,
+ a2dp_sbc_encoder_cleanup,
+ a2dp_sbc_feeding_reset,
+ a2dp_sbc_feeding_flush,
+ a2dp_sbc_get_encoder_interval_ms,
+ a2dp_sbc_send_frames,
+ nullptr // set_transmit_queue_length
+};
+
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
+ const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability);
+static void A2DP_ParseMplHeaderSbc(uint8_t* p_src, bool* p_frag, bool* p_start,
+ bool* p_last, uint8_t* p_num);
+
+// Builds the SBC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the SBC Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoSbc(uint8_t media_type,
+ const tA2DP_SBC_CIE* p_ie,
+ uint8_t* p_result) {
+ if (p_ie == NULL || p_result == NULL ||
+ (p_ie->samp_freq & ~A2DP_SBC_IE_SAMP_FREQ_MSK) ||
+ (p_ie->ch_mode & ~A2DP_SBC_IE_CH_MD_MSK) ||
+ (p_ie->block_len & ~A2DP_SBC_IE_BLOCKS_MSK) ||
+ (p_ie->num_subbands & ~A2DP_SBC_IE_SUBBAND_MSK) ||
+ (p_ie->alloc_method & ~A2DP_SBC_IE_ALLOC_MD_MSK) ||
+ (p_ie->min_bitpool > p_ie->max_bitpool) ||
+ (p_ie->min_bitpool < A2DP_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->min_bitpool > A2DP_SBC_IE_MAX_BITPOOL) ||
+ (p_ie->max_bitpool < A2DP_SBC_IE_MIN_BITPOOL) ||
+ (p_ie->max_bitpool > A2DP_SBC_IE_MAX_BITPOOL)) {
+ /* if any unused bit is set */
+ return A2DP_INVALID_PARAMS;
+ }
+
+ *p_result++ = A2DP_SBC_INFO_LEN;
+ *p_result++ = (media_type << 4);
+ *p_result++ = A2DP_MEDIA_CT_SBC;
+
+ /* Media Codec Specific Information Element */
+ *p_result++ = p_ie->samp_freq | p_ie->ch_mode;
+
+ *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_method;
+
+ *p_result++ = p_ie->min_bitpool;
+ *p_result = p_ie->max_bitpool;
+
+ return A2DP_SUCCESS;
+}
+
+// Parses the SBC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence contains
+// codec capability.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoSbc(tA2DP_SBC_CIE* p_ie,
+ const uint8_t* p_codec_info,
+ bool is_capability) {
+ uint8_t losc;
+ uint8_t media_type;
+ tA2DP_CODEC_TYPE codec_type;
+
+ if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+ // Check the codec capability length
+ losc = *p_codec_info++;
+ if (losc != A2DP_SBC_INFO_LEN) return A2DP_WRONG_CODEC;
+
+ media_type = (*p_codec_info++) >> 4;
+ codec_type = *p_codec_info++;
+ /* Check the Media Type and Media Codec Type */
+ if (media_type != AVDT_MEDIA_TYPE_AUDIO || codec_type != A2DP_MEDIA_CT_SBC) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ p_ie->samp_freq = *p_codec_info & A2DP_SBC_IE_SAMP_FREQ_MSK;
+ p_ie->ch_mode = *p_codec_info & A2DP_SBC_IE_CH_MD_MSK;
+ p_codec_info++;
+ p_ie->block_len = *p_codec_info & A2DP_SBC_IE_BLOCKS_MSK;
+ p_ie->num_subbands = *p_codec_info & A2DP_SBC_IE_SUBBAND_MSK;
+ p_ie->alloc_method = *p_codec_info & A2DP_SBC_IE_ALLOC_MD_MSK;
+ p_codec_info++;
+ p_ie->min_bitpool = *p_codec_info++;
+ p_ie->max_bitpool = *p_codec_info++;
+ if (p_ie->min_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
+ p_ie->min_bitpool > A2DP_SBC_IE_MAX_BITPOOL) {
+ return A2DP_BAD_MIN_BITPOOL;
+ }
+
+ if (p_ie->max_bitpool < A2DP_SBC_IE_MIN_BITPOOL ||
+ p_ie->max_bitpool > A2DP_SBC_IE_MAX_BITPOOL ||
+ p_ie->max_bitpool < p_ie->min_bitpool) {
+ return A2DP_BAD_MAX_BITPOOL;
+ }
+
+ if (is_capability) return A2DP_SUCCESS;
+
+ if (A2DP_BitsSet(p_ie->samp_freq) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->ch_mode) != A2DP_SET_ONE_BIT) return A2DP_BAD_CH_MODE;
+ if (A2DP_BitsSet(p_ie->block_len) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_BLOCK_LEN;
+ if (A2DP_BitsSet(p_ie->num_subbands) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SUBBANDS;
+ if (A2DP_BitsSet(p_ie->alloc_method) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_ALLOC_METHOD;
+
+ return A2DP_SUCCESS;
+}
+
+// Build the SBC Media Payload Header.
+// |p_dst| points to the location where the header should be written to.
+// If |frag| is true, the media payload frame is fragmented.
+// |start| is true for the first packet of a fragmented frame.
+// |last| is true for the last packet of a fragmented frame.
+// If |frag| is false, |num| is the number of number of frames in the packet,
+// otherwise is the number of remaining fragments (including this one).
+static void A2DP_BuildMediaPayloadHeaderSbc(uint8_t* p_dst, bool frag,
+ bool start, bool last,
+ uint8_t num) {
+ if (p_dst == NULL) return;
+
+ *p_dst = 0;
+ if (frag) *p_dst |= A2DP_SBC_HDR_F_MSK;
+ if (start) *p_dst |= A2DP_SBC_HDR_S_MSK;
+ if (last) *p_dst |= A2DP_SBC_HDR_L_MSK;
+ *p_dst |= (A2DP_SBC_HDR_NUM_MSK & num);
+}
+
+/******************************************************************************
+ *
+ * Function A2DP_ParseMplHeaderSbc
+ *
+ * Description This function is called by an application to parse
+ * the SBC Media Payload header.
+ * Input Parameters:
+ * p_src: the byte sequence to parse..
+ *
+ * Output Parameters:
+ * frag: 1, if fragmented. 0, otherwise.
+ *
+ * start: 1, if the starting packet of a fragmented frame.
+ *
+ * last: 1, if the last packet of a fragmented frame.
+ *
+ * num: If frag is 1, this is the number of remaining
+ * fragments
+ * (including this fragment) of this frame.
+ * If frag is 0, this is the number of frames in
+ * this packet.
+ *
+ * Returns void.
+ *****************************************************************************/
+UNUSED_ATTR static void A2DP_ParseMplHeaderSbc(uint8_t* p_src, bool* p_frag,
+ bool* p_start, bool* p_last,
+ uint8_t* p_num) {
+ if (p_src && p_frag && p_start && p_last && p_num) {
+ *p_frag = (*p_src & A2DP_SBC_HDR_F_MSK) ? true : false;
+ *p_start = (*p_src & A2DP_SBC_HDR_S_MSK) ? true : false;
+ *p_last = (*p_src & A2DP_SBC_HDR_L_MSK) ? true : false;
+ *p_num = (*p_src & A2DP_SBC_HDR_NUM_MSK);
+ }
+}
+
+const char* A2DP_CodecNameSbc(UNUSED_ATTR const uint8_t* p_codec_info) {
+ return "SBC";
+}
+
+bool A2DP_IsSourceCodecValidSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecValidSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSourceCodecValidSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSinkCodecValidSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsSinkCodecSupportedSbc(const uint8_t* p_codec_info) {
+ return (A2DP_CodecInfoMatchesCapabilitySbc(&a2dp_sbc_sink_caps, p_codec_info,
+ false) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsPeerSourceCodecSupportedSbc(const uint8_t* p_codec_info) {
+ return (A2DP_CodecInfoMatchesCapabilitySbc(&a2dp_sbc_sink_caps, p_codec_info,
+ true) == A2DP_SUCCESS);
+}
+
+void A2DP_InitDefaultCodecSbc(uint8_t* p_codec_info) {
+ if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_default_config,
+ p_codec_info) != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_BuildInfoSbc failed", __func__);
+ }
+}
+
+// Checks whether A2DP SBC codec configuration matches with a device's codec
+// capabilities. |p_cap| is the SBC codec configuration. |p_codec_info| is
+// the device's codec capabilities. |is_capability| is true if
+// |p_codec_info| contains A2DP codec capability.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilitySbc(
+ const tA2DP_SBC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability) {
+ tA2DP_STATUS status;
+ tA2DP_SBC_CIE cfg_cie;
+
+ /* parse configuration */
+ status = A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ LOG_DEBUG(LOG_TAG, "%s: FREQ peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.samp_freq, p_cap->samp_freq);
+ LOG_DEBUG(LOG_TAG, "%s: CH_MODE peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.ch_mode, p_cap->ch_mode);
+ LOG_DEBUG(LOG_TAG, "%s: BLOCK_LEN peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.block_len, p_cap->block_len);
+ LOG_DEBUG(LOG_TAG, "%s: SUB_BAND peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.num_subbands, p_cap->num_subbands);
+ LOG_DEBUG(LOG_TAG, "%s: ALLOC_METHOD peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.alloc_method, p_cap->alloc_method);
+ LOG_DEBUG(LOG_TAG, "%s: MIN_BitPool peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.min_bitpool, p_cap->min_bitpool);
+ LOG_DEBUG(LOG_TAG, "%s: MAX_BitPool peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.max_bitpool, p_cap->max_bitpool);
+
+ /* sampling frequency */
+ if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) return A2DP_NS_SAMP_FREQ;
+
+ /* channel mode */
+ if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) return A2DP_NS_CH_MODE;
+
+ /* block length */
+ if ((cfg_cie.block_len & p_cap->block_len) == 0) return A2DP_BAD_BLOCK_LEN;
+
+ /* subbands */
+ if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0)
+ return A2DP_NS_SUBBANDS;
+
+ /* allocation method */
+ if ((cfg_cie.alloc_method & p_cap->alloc_method) == 0)
+ return A2DP_NS_ALLOC_METHOD;
+
+ /* min bitpool */
+ if (cfg_cie.min_bitpool > p_cap->max_bitpool) return A2DP_NS_MIN_BITPOOL;
+
+ /* max bitpool */
+ if (cfg_cie.max_bitpool < p_cap->min_bitpool) return A2DP_NS_MAX_BITPOOL;
+
+ return A2DP_SUCCESS;
+}
+
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg) {
+ tA2DP_SBC_CIE src_cap;
+ tA2DP_SBC_CIE pref_cap;
+
+ /* initialize it to default SBC configuration */
+ A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_default_config,
+ p_pref_cfg);
+
+ /* now try to build a preferred one */
+ /* parse configuration */
+ tA2DP_STATUS status = A2DP_ParseInfoSbc(&src_cap, p_src_cap, true);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse src cap ret = %d", __func__, status);
+ return A2DP_FAIL;
+ }
+
+ if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
+ pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+ else if (src_cap.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44)
+ pref_cap.samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+
+ if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_JOINT)
+ pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
+ else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_STEREO)
+ pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
+ else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_DUAL)
+ pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
+ else if (src_cap.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
+ pref_cap.ch_mode = A2DP_SBC_IE_CH_MD_MONO;
+
+ if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_16)
+ pref_cap.block_len = A2DP_SBC_IE_BLOCKS_16;
+ else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_12)
+ pref_cap.block_len = A2DP_SBC_IE_BLOCKS_12;
+ else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_8)
+ pref_cap.block_len = A2DP_SBC_IE_BLOCKS_8;
+ else if (src_cap.block_len & A2DP_SBC_IE_BLOCKS_4)
+ pref_cap.block_len = A2DP_SBC_IE_BLOCKS_4;
+
+ if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_8)
+ pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_8;
+ else if (src_cap.num_subbands & A2DP_SBC_IE_SUBBAND_4)
+ pref_cap.num_subbands = A2DP_SBC_IE_SUBBAND_4;
+
+ if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_L)
+ pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_L;
+ else if (src_cap.alloc_method & A2DP_SBC_IE_ALLOC_MD_S)
+ pref_cap.alloc_method = A2DP_SBC_IE_ALLOC_MD_S;
+
+ pref_cap.min_bitpool = src_cap.min_bitpool;
+ pref_cap.max_bitpool = src_cap.max_bitpool;
+
+ A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &pref_cap, p_pref_cfg);
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_CodecTypeEqualsSbc(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_SBC_CIE sbc_cie_a;
+ tA2DP_SBC_CIE sbc_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoSbc(&sbc_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ return (codec_type_a == codec_type_b) && (codec_type_a == A2DP_MEDIA_CT_SBC);
+}
+
+bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_SBC_CIE sbc_cie_a;
+ tA2DP_SBC_CIE sbc_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoSbc(&sbc_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoSbc(&sbc_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ if ((codec_type_a != codec_type_b) || (codec_type_a != A2DP_MEDIA_CT_SBC))
+ return false;
+
+ return (sbc_cie_a.samp_freq == sbc_cie_b.samp_freq) &&
+ (sbc_cie_a.ch_mode == sbc_cie_b.ch_mode) &&
+ (sbc_cie_a.block_len == sbc_cie_b.block_len) &&
+ (sbc_cie_a.num_subbands == sbc_cie_b.num_subbands) &&
+ (sbc_cie_a.alloc_method == sbc_cie_b.alloc_method) &&
+ (sbc_cie_a.min_bitpool == sbc_cie_b.min_bitpool) &&
+ (sbc_cie_a.max_bitpool == sbc_cie_b.max_bitpool);
+}
+
+int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.samp_freq) {
+ case A2DP_SBC_IE_SAMP_FREQ_16:
+ return 16000;
+ case A2DP_SBC_IE_SAMP_FREQ_32:
+ return 32000;
+ case A2DP_SBC_IE_SAMP_FREQ_44:
+ return 44100;
+ case A2DP_SBC_IE_SAMP_FREQ_48:
+ return 48000;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return 16; // For SBC we always use 16 bits per audio sample
+}
+
+int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.ch_mode) {
+ case A2DP_SBC_IE_CH_MD_MONO:
+ return 1;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ return 2;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetNumberOfSubbandsSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.num_subbands) {
+ case A2DP_SBC_IE_SUBBAND_4:
+ return 4;
+ case A2DP_SBC_IE_SUBBAND_8:
+ return 8;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetNumberOfBlocksSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.block_len) {
+ case A2DP_SBC_IE_BLOCKS_4:
+ return 4;
+ case A2DP_SBC_IE_BLOCKS_8:
+ return 8;
+ case A2DP_SBC_IE_BLOCKS_12:
+ return 12;
+ case A2DP_SBC_IE_BLOCKS_16:
+ return 16;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetAllocationMethodCodeSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.alloc_method) {
+ case A2DP_SBC_IE_ALLOC_MD_S:
+ return SBC_SNR;
+ case A2DP_SBC_IE_ALLOC_MD_L:
+ return SBC_LOUDNESS;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetChannelModeCodeSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.ch_mode) {
+ case A2DP_SBC_IE_CH_MD_MONO:
+ return SBC_MONO;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ return SBC_DUAL;
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ return SBC_STEREO;
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ return SBC_JOINT_STEREO;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetSamplingFrequencyCodeSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.samp_freq) {
+ case A2DP_SBC_IE_SAMP_FREQ_16:
+ return SBC_sf16000;
+ case A2DP_SBC_IE_SAMP_FREQ_32:
+ return SBC_sf32000;
+ case A2DP_SBC_IE_SAMP_FREQ_44:
+ return SBC_sf44100;
+ case A2DP_SBC_IE_SAMP_FREQ_48:
+ return SBC_sf48000;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetMinBitpoolSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return sbc_cie.min_bitpool;
+}
+
+int A2DP_GetMaxBitpoolSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return sbc_cie.max_bitpool;
+}
+
+int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (sbc_cie.ch_mode) {
+ case A2DP_SBC_IE_CH_MD_MONO:
+ return 1;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ return 3;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE sbc_cie;
+ uint32_t freq_multiple;
+ uint32_t num_blocks;
+ uint32_t num_subbands;
+ int frames_to_process;
+
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ // Check the sample frequency
+ switch (sbc_cie.samp_freq) {
+ case A2DP_SBC_IE_SAMP_FREQ_16:
+ LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (16000)", __func__,
+ sbc_cie.samp_freq);
+ freq_multiple = 16 * time_interval_ms;
+ break;
+ case A2DP_SBC_IE_SAMP_FREQ_32:
+ LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (32000)", __func__,
+ sbc_cie.samp_freq);
+ freq_multiple = 32 * time_interval_ms;
+ break;
+ case A2DP_SBC_IE_SAMP_FREQ_44:
+ LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (44100)", __func__,
+ sbc_cie.samp_freq);
+ freq_multiple = (441 * time_interval_ms) / 10;
+ break;
+ case A2DP_SBC_IE_SAMP_FREQ_48:
+ LOG_VERBOSE(LOG_TAG, "%s: samp_freq:%d (48000)", __func__,
+ sbc_cie.samp_freq);
+ freq_multiple = 48 * time_interval_ms;
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "%s: unknown frequency: %d", __func__,
+ sbc_cie.samp_freq);
+ return -1;
+ }
+
+ // Check the channel mode
+ switch (sbc_cie.ch_mode) {
+ case A2DP_SBC_IE_CH_MD_MONO:
+ LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (Mono)", __func__, sbc_cie.ch_mode);
+ break;
+ case A2DP_SBC_IE_CH_MD_DUAL:
+ LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (DUAL)", __func__, sbc_cie.ch_mode);
+ break;
+ case A2DP_SBC_IE_CH_MD_STEREO:
+ LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (STEREO)", __func__,
+ sbc_cie.ch_mode);
+ break;
+ case A2DP_SBC_IE_CH_MD_JOINT:
+ LOG_VERBOSE(LOG_TAG, "%s: ch_mode:%d (JOINT)", __func__, sbc_cie.ch_mode);
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "%s: unknown channel mode: %d", __func__,
+ sbc_cie.ch_mode);
+ return -1;
+ }
+
+ // Check the block length
+ switch (sbc_cie.block_len) {
+ case A2DP_SBC_IE_BLOCKS_4:
+ LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (4)", __func__, sbc_cie.block_len);
+ num_blocks = 4;
+ break;
+ case A2DP_SBC_IE_BLOCKS_8:
+ LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (8)", __func__, sbc_cie.block_len);
+ num_blocks = 8;
+ break;
+ case A2DP_SBC_IE_BLOCKS_12:
+ LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (12)", __func__,
+ sbc_cie.block_len);
+ num_blocks = 12;
+ break;
+ case A2DP_SBC_IE_BLOCKS_16:
+ LOG_VERBOSE(LOG_TAG, "%s: block_len:%d (16)", __func__,
+ sbc_cie.block_len);
+ num_blocks = 16;
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "%s: unknown block length: %d", __func__,
+ sbc_cie.block_len);
+ return -1;
+ }
+
+ // Check the number of sub-bands
+ switch (sbc_cie.num_subbands) {
+ case A2DP_SBC_IE_SUBBAND_4:
+ LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (4)", __func__,
+ sbc_cie.num_subbands);
+ num_subbands = 4;
+ break;
+ case A2DP_SBC_IE_SUBBAND_8:
+ LOG_VERBOSE(LOG_TAG, "%s: num_subbands:%d (8)", __func__,
+ sbc_cie.num_subbands);
+ num_subbands = 8;
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "%s: unknown number of subbands: %d", __func__,
+ sbc_cie.num_subbands);
+ return -1;
+ }
+
+ // Check the allocation method
+ switch (sbc_cie.alloc_method) {
+ case A2DP_SBC_IE_ALLOC_MD_S:
+ LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (SNR)", __func__,
+ sbc_cie.alloc_method);
+ break;
+ case A2DP_SBC_IE_ALLOC_MD_L:
+ LOG_VERBOSE(LOG_TAG, "%s: alloc_method:%d (Loudness)", __func__,
+ sbc_cie.alloc_method);
+ break;
+ default:
+ LOG_ERROR(LOG_TAG, "%s: unknown allocation method: %d", __func__,
+ sbc_cie.alloc_method);
+ return -1;
+ }
+
+ LOG_VERBOSE(LOG_TAG, "%s: Bit pool Min:%d Max:%d", __func__,
+ sbc_cie.min_bitpool, sbc_cie.max_bitpool);
+
+ frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
+
+ return frames_to_process;
+}
+
+bool A2DP_GetPacketTimestampSbc(UNUSED_ATTR const uint8_t* p_codec_info,
+ const uint8_t* p_data, uint32_t* p_timestamp) {
+ *p_timestamp = *(const uint32_t*)p_data;
+ return true;
+}
+
+bool A2DP_BuildCodecHeaderSbc(UNUSED_ATTR const uint8_t* p_codec_info,
+ BT_HDR* p_buf, uint16_t frames_per_packet) {
+ uint8_t* p;
+
+ p_buf->offset -= A2DP_SBC_MPL_HDR_LEN;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ p_buf->len += A2DP_SBC_MPL_HDR_LEN;
+ A2DP_BuildMediaPayloadHeaderSbc(p, false, false, false,
+ (uint8_t)frames_per_packet);
+
+ return true;
+}
+
+void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info) {
+ tA2DP_STATUS a2dp_status;
+ tA2DP_SBC_CIE sbc_cie;
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+ a2dp_status = A2DP_ParseInfoSbc(&sbc_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoSbc fail:%d", __func__, a2dp_status);
+ return;
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", sbc_cie.samp_freq);
+ if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_16) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (16000)");
+ }
+ if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_32) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (32000)");
+ }
+ if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+ }
+ if (sbc_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", sbc_cie.ch_mode);
+ if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+ }
+ if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Dual)");
+ }
+ if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+ }
+ if (sbc_cie.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Joint)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tblock_len: 0x%x", sbc_cie.block_len);
+ if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_4) {
+ LOG_DEBUG(LOG_TAG, "\tblock_len: (4)");
+ }
+ if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_8) {
+ LOG_DEBUG(LOG_TAG, "\tblock_len: (8)");
+ }
+ if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_12) {
+ LOG_DEBUG(LOG_TAG, "\tblock_len: (12)");
+ }
+ if (sbc_cie.block_len & A2DP_SBC_IE_BLOCKS_16) {
+ LOG_DEBUG(LOG_TAG, "\tblock_len: (16)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tnum_subbands: 0x%x", sbc_cie.num_subbands);
+ if (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_4) {
+ LOG_DEBUG(LOG_TAG, "\tnum_subbands: (4)");
+ }
+ if (sbc_cie.num_subbands & A2DP_SBC_IE_SUBBAND_8) {
+ LOG_DEBUG(LOG_TAG, "\tnum_subbands: (8)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\talloc_method: 0x%x)", sbc_cie.alloc_method);
+ if (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_S) {
+ LOG_DEBUG(LOG_TAG, "\talloc_method: (SNR)");
+ }
+ if (sbc_cie.alloc_method & A2DP_SBC_IE_ALLOC_MD_L) {
+ LOG_DEBUG(LOG_TAG, "\talloc_method: (Loundess)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tBit pool Min:%d Max:%d", sbc_cie.min_bitpool,
+ sbc_cie.max_bitpool);
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsSourceCodecValidSbc(p_codec_info)) return NULL;
+
+ return &a2dp_encoder_interface_sbc;
+}
+
+bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info) {
+ tA2DP_SBC_CIE cfg_cie;
+
+ if (A2DP_ParseInfoSbc(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+ return false;
+
+ // Updated the max bitpool
+ if (cfg_cie.max_bitpool > A2DP_SBC_MAX_BITPOOL) {
+ LOG_WARN(LOG_TAG, "%s: Updated the SBC codec max bitpool from %d to %d",
+ __func__, cfg_cie.max_bitpool, A2DP_SBC_MAX_BITPOOL);
+ cfg_cie.max_bitpool = A2DP_SBC_MAX_BITPOOL;
+ }
+
+ return (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &cfg_cie, p_codec_info) ==
+ A2DP_SUCCESS);
+}
+
+btav_a2dp_codec_index_t A2DP_SourceCodecIndexSbc(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SOURCE_SBC;
+}
+
+const char* A2DP_CodecIndexStrSbc(void) { return "SBC"; }
+
+const char* A2DP_CodecIndexStrSbcSink(void) { return "SBC SINK"; }
+
+bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Content protection info - support SCMS-T */
+ uint8_t* p = p_cfg->protect_info;
+ *p++ = AVDT_CP_LOSC;
+ UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+ p_cfg->num_protect = 1;
+#endif
+
+ return true;
+}
+
+bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &a2dp_sbc_sink_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+ return true;
+}
+
+UNUSED_ATTR static void build_codec_config(const tA2DP_SBC_CIE& config_cie,
+ btav_a2dp_codec_config_t* result) {
+ if (config_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (config_cie.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+ result->bits_per_sample = config_cie.bits_per_sample;
+
+ if (config_cie.ch_mode & A2DP_SBC_IE_CH_MD_MONO)
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+
+ if (config_cie.ch_mode & (A2DP_SBC_IE_CH_MD_STEREO | A2DP_SBC_IE_CH_MD_JOINT |
+ A2DP_SBC_IE_CH_MD_DUAL)) {
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigSbc::A2dpCodecConfigSbc(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, "SBC", codec_priority) {
+ // Compute the local capability
+ if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (a2dp_sbc_caps.samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ codec_local_capability_.bits_per_sample = a2dp_sbc_caps.bits_per_sample;
+ if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (a2dp_sbc_caps.ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigSbc::~A2dpCodecConfigSbc() {}
+
+bool A2dpCodecConfigSbc::init() {
+ if (!isValid()) return false;
+
+ // Load the encoder
+ if (!A2DP_LoadEncoderSbc()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecConfigSbc::useRtpHeaderMarkerBit() const { return false; }
+
+//
+// Selects the best sample rate from |samp_freq|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint8_t samp_freq, tA2DP_SBC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ p_result->samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ p_result->samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |samp_freq| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t samp_freq,
+ tA2DP_SBC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ p_result->samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ p_result->samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+//
+// Selects the best bits per sample.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+ btav_a2dp_codec_config_t* p_codec_config) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+ const btav_a2dp_codec_config_t* p_codec_audio_config,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best channel mode from |ch_mode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t ch_mode, tA2DP_SBC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |ch_mode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t ch_mode,
+ tA2DP_SBC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ p_result->ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+bool A2dpCodecConfigSbc::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ tA2DP_SBC_CIE sink_info_cie;
+ tA2DP_SBC_CIE result_config_cie;
+ uint8_t samp_freq;
+ uint8_t ch_mode;
+ uint8_t block_len;
+ uint8_t num_subbands;
+ uint8_t alloc_method;
+
+ // Save the internal state
+ btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+ btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+ btav_a2dp_codec_config_t saved_codec_selectable_capability =
+ codec_selectable_capability_;
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+ memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+ sizeof(ota_codec_peer_config_));
+
+ tA2DP_STATUS status =
+ A2DP_ParseInfoSbc(&sink_info_cie, p_peer_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+ __func__, status);
+ goto fail;
+ }
+ // Try using the prefered peer codec config (if valid), instead of the peer
+ // capability.
+ if (is_capability && A2DP_IsPeerSinkCodecValidSbc(ota_codec_peer_config_)) {
+ status = A2DP_ParseInfoSbc(&sink_info_cie, ota_codec_peer_config_, false);
+ if (status != A2DP_SUCCESS) {
+ // Use the peer codec capability
+ status =
+ A2DP_ParseInfoSbc(&sink_info_cie, p_peer_codec_info, is_capability);
+ CHECK(status == A2DP_SUCCESS);
+ }
+ }
+
+ //
+ // Build the preferred configuration
+ //
+ memset(&result_config_cie, 0, sizeof(result_config_cie));
+
+ //
+ // Select the sample frequency
+ //
+ samp_freq = a2dp_sbc_caps.samp_freq & sink_info_cie.samp_freq;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ switch (codec_user_config_.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ result_config_cie.samp_freq = A2DP_SBC_IE_SAMP_FREQ_44;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ result_config_cie.samp_freq = A2DP_SBC_IE_SAMP_FREQ_48;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ break;
+ }
+
+ // Select the sample frequency if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+
+ if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+ // Compute the common capability
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_44)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (samp_freq & A2DP_SBC_IE_SAMP_FREQ_48)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+ // No user preference - try the codec audio config
+ if (select_audio_sample_rate(&codec_audio_config_, samp_freq,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_sample_rate(
+ a2dp_sbc_default_config.samp_freq & sink_info_cie.samp_freq,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_sample_rate(samp_freq, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match sample frequency: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_sbc_caps.samp_freq, sink_info_cie.samp_freq);
+ goto fail;
+ }
+
+ //
+ // Select the bits per sample
+ //
+ // NOTE: this information is NOT included in the SBC A2DP codec description
+ // that is sent OTA.
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ switch (codec_user_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ break;
+ }
+
+ // Select the bits per sample if there is no user preference
+ do {
+ // Compute the selectable capability
+ codec_selectable_capability_.bits_per_sample =
+ a2dp_sbc_caps.bits_per_sample;
+
+ if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+ break;
+
+ // Compute the common capability
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+
+ // No user preference - try the codec audio config
+ if (select_audio_bits_per_sample(&codec_audio_config_, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ // TODO: no-op - temporary kept here for consistency
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match bits per sample: user preference = 0x%x",
+ __func__, codec_user_config_.bits_per_sample);
+ goto fail;
+ }
+
+ //
+ // Select the channel mode
+ //
+ ch_mode = a2dp_sbc_caps.ch_mode & sink_info_cie.ch_mode;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ switch (codec_user_config_.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ result_config_cie.ch_mode = A2DP_SBC_IE_CH_MD_MONO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ result_config_cie.ch_mode = A2DP_SBC_IE_CH_MD_JOINT;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ break;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ result_config_cie.ch_mode = A2DP_SBC_IE_CH_MD_STEREO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ break;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ result_config_cie.ch_mode = A2DP_SBC_IE_CH_MD_DUAL;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ break;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ break;
+ }
+
+ // Select the channel mode if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (ch_mode & A2DP_SBC_IE_CH_MD_MONO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_JOINT) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_STEREO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (ch_mode & A2DP_SBC_IE_CH_MD_DUAL) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+ // Compute the common capability
+ if (ch_mode & A2DP_SBC_IE_CH_MD_MONO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (ch_mode & (A2DP_SBC_IE_CH_MD_JOINT | A2DP_SBC_IE_CH_MD_STEREO |
+ A2DP_SBC_IE_CH_MD_DUAL)) {
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ // No user preference - use the codec audio config
+ if (select_audio_channel_mode(&codec_audio_config_, ch_mode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_channel_mode(
+ a2dp_sbc_default_config.ch_mode & sink_info_cie.ch_mode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_channel_mode(ch_mode, &result_config_cie, &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match channel mode: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_sbc_caps.ch_mode, sink_info_cie.ch_mode);
+ goto fail;
+ }
+
+ //
+ // Select the block length
+ //
+ block_len = a2dp_sbc_caps.block_len & sink_info_cie.block_len;
+ if (block_len & A2DP_SBC_IE_BLOCKS_16) {
+ result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_16;
+ } else if (block_len & A2DP_SBC_IE_BLOCKS_12) {
+ result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_12;
+ } else if (block_len & A2DP_SBC_IE_BLOCKS_8) {
+ result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_8;
+ } else if (block_len & A2DP_SBC_IE_BLOCKS_4) {
+ result_config_cie.block_len = A2DP_SBC_IE_BLOCKS_4;
+ } else {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match block length: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_sbc_caps.block_len, sink_info_cie.block_len);
+ goto fail;
+ }
+
+ //
+ // Select the number of sub-bands
+ //
+ num_subbands = a2dp_sbc_caps.num_subbands & sink_info_cie.num_subbands;
+ if (num_subbands & A2DP_SBC_IE_SUBBAND_8) {
+ result_config_cie.num_subbands = A2DP_SBC_IE_SUBBAND_8;
+ } else if (num_subbands & A2DP_SBC_IE_SUBBAND_4) {
+ result_config_cie.num_subbands = A2DP_SBC_IE_SUBBAND_4;
+ } else {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match number of sub-bands: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_sbc_caps.num_subbands, sink_info_cie.num_subbands);
+ goto fail;
+ }
+
+ //
+ // Select the allocation method
+ //
+ alloc_method = a2dp_sbc_caps.alloc_method & sink_info_cie.alloc_method;
+ if (alloc_method & A2DP_SBC_IE_ALLOC_MD_L) {
+ result_config_cie.alloc_method = A2DP_SBC_IE_ALLOC_MD_L;
+ } else if (alloc_method & A2DP_SBC_IE_ALLOC_MD_S) {
+ result_config_cie.alloc_method = A2DP_SBC_IE_ALLOC_MD_S;
+ } else {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match allocation method: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_sbc_caps.alloc_method, sink_info_cie.alloc_method);
+ goto fail;
+ }
+
+ //
+ // Select the min/max bitpool
+ //
+ result_config_cie.min_bitpool = a2dp_sbc_caps.min_bitpool;
+ if (result_config_cie.min_bitpool < sink_info_cie.min_bitpool)
+ result_config_cie.min_bitpool = sink_info_cie.min_bitpool;
+ result_config_cie.max_bitpool = a2dp_sbc_caps.max_bitpool;
+ if (result_config_cie.max_bitpool > sink_info_cie.max_bitpool)
+ result_config_cie.max_bitpool = sink_info_cie.max_bitpool;
+ if (result_config_cie.min_bitpool > result_config_cie.max_bitpool) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match min/max bitpool: "
+ "source caps min/max = 0x%x/0x%x sink info min/max = 0x%x/0x%x",
+ __func__, a2dp_sbc_caps.min_bitpool, a2dp_sbc_caps.max_bitpool,
+ sink_info_cie.min_bitpool, sink_info_cie.max_bitpool);
+ goto fail;
+ }
+
+ if (A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ p_result_codec_config) != A2DP_SUCCESS) {
+ goto fail;
+ }
+
+ //
+ // Copy the codec-specific fields if they are not zero
+ //
+ if (codec_user_config_.codec_specific_1 != 0)
+ codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+ if (codec_user_config_.codec_specific_2 != 0)
+ codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+ if (codec_user_config_.codec_specific_3 != 0)
+ codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+ if (codec_user_config_.codec_specific_4 != 0)
+ codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
+
+ // Create a local copy of the peer codec capability/config, and the
+ // result codec config.
+ if (is_capability) {
+ memcpy(ota_codec_peer_capability_, p_peer_codec_info,
+ sizeof(ota_codec_peer_capability_));
+ } else {
+ memcpy(ota_codec_peer_config_, p_peer_codec_info,
+ sizeof(ota_codec_peer_config_));
+ }
+ status = A2DP_BuildInfoSbc(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ ota_codec_config_);
+ CHECK(status == A2DP_SUCCESS);
+ return true;
+
+fail:
+ // Restore the internal state
+ codec_config_ = saved_codec_config;
+ codec_capability_ = saved_codec_capability;
+ codec_selectable_capability_ = saved_codec_selectable_capability;
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+ memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+ sizeof(ota_codec_peer_config_));
+ return false;
+}
+
+A2dpCodecConfigSbcSink::A2dpCodecConfigSbcSink(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_SBC, "SBC(Sink)",
+ codec_priority) {}
+
+A2dpCodecConfigSbcSink::~A2dpCodecConfigSbcSink() {}
+
+bool A2dpCodecConfigSbcSink::init() {
+ if (!isValid()) return false;
+
+ return true;
+}
+
+bool A2dpCodecConfigSbcSink::useRtpHeaderMarkerBit() const {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigSbcSink::setCodecConfig(
+ UNUSED_ATTR const uint8_t* p_peer_codec_info,
+ UNUSED_ATTR bool is_capability,
+ UNUSED_ATTR uint8_t* p_result_codec_config) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+bool A2dpCodecConfigSbcSink::updateEncoderUserConfig(
+ UNUSED_ATTR const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ UNUSED_ATTR bool* p_restart_input, UNUSED_ATTR bool* p_restart_output,
+ UNUSED_ATTR bool* p_config_updated) {
+ // TODO: This method applies only to Source codecs
+ return false;
+}
+
+period_ms_t A2dpCodecConfigSbcSink::encoderIntervalMs() const {
+ // TODO: This method applies only to Source codecs
+ return 0;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_sbc_encoder.cc b/mtkbt/code/bt/stack/a2dp/a2dp_sbc_encoder.cc
new file mode 100755
index 0000000..939a68a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_sbc_encoder.cc
@@ -0,0 +1,921 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_sbc_encoder"
+
+#include "a2dp_sbc_encoder.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "a2dp_sbc.h"
+#include "a2dp_sbc_up_sample.h"
+#include "bt_common.h"
+#include "embdrv/sbc/encoder/include/sbc_encoder.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/* Buffer pool */
+#define A2DP_SBC_BUFFER_SIZE BT_DEFAULT_BUFFER_SIZE
+
+// A2DP SBC encoder interval in milliseconds.
+#define A2DP_SBC_ENCODER_INTERVAL_MS 20
+
+/* High quality quality setting @ 44.1 khz */
+#define A2DP_SBC_DEFAULT_BITRATE 328
+
+#define A2DP_SBC_NON_EDR_MAX_RATE 229
+
+/*
+ * 2DH5 payload size of:
+ * 679 bytes - (4 bytes L2CAP Header + 12 bytes AVDTP Header)
+ */
+#define MAX_2MBPS_AVDTP_MTU 663
+#define A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK 3
+
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1 119
+#define A2DP_SBC_MAX_HQ_FRAME_SIZE_48 115
+
+/* Define the bitrate step when trying to match bitpool value */
+#define A2DP_SBC_BITRATE_STEP 5
+
+/* Readability constants */
+#define A2DP_SBC_FRAME_HEADER_SIZE_BYTES 4 // A2DP Spec v1.3, 12.4, Table 12.12
+#define A2DP_SBC_SCALE_FACTOR_BITS 4 // A2DP Spec v1.3, 12.4, Table 12.13
+
+/* offset */
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+/* A2DP header will contain a CP header of size 1 */
+#define A2DP_HDR_SIZE 2
+#define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN + 1)
+#else
+#define A2DP_HDR_SIZE 1
+#define A2DP_SBC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_SBC_MPL_HDR_LEN)
+#endif
+
+typedef struct {
+ uint32_t aa_frame_counter;
+ int32_t aa_feed_counter;
+ int32_t aa_feed_residue;
+ uint32_t counter;
+ uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
+ uint64_t last_frame_us;
+} tA2DP_SBC_FEEDING_STATE;
+
+typedef struct {
+ uint64_t session_start_us;
+
+ size_t media_read_total_expected_packets;
+ size_t media_read_total_expected_reads_count;
+ size_t media_read_total_expected_read_bytes;
+
+ size_t media_read_total_dropped_packets;
+ size_t media_read_total_actual_reads_count;
+ size_t media_read_total_actual_read_bytes;
+
+ size_t media_read_total_expected_frames;
+ size_t media_read_total_dropped_frames;
+} a2dp_sbc_encoder_stats_t;
+
+typedef struct {
+ a2dp_source_read_callback_t read_callback;
+ a2dp_source_enqueue_callback_t enqueue_callback;
+ uint16_t TxAaMtuSize;
+ uint8_t tx_sbc_frames;
+ bool is_peer_edr; /* True if the peer device supports EDR */
+ bool peer_supports_3mbps; /* True if the peer device supports 3Mbps EDR */
+ uint16_t peer_mtu; /* MTU of the A2DP peer */
+ uint32_t timestamp; /* Timestamp for the A2DP frames */
+ SBC_ENC_PARAMS sbc_encoder_params;
+ tA2DP_FEEDING_PARAMS feeding_params;
+ tA2DP_SBC_FEEDING_STATE feeding_state;
+ int16_t pcmBuffer[SBC_MAX_PCM_BUFFER_SIZE];
+
+ a2dp_sbc_encoder_stats_t stats;
+} tA2DP_SBC_ENCODER_CB;
+
+static tA2DP_SBC_ENCODER_CB a2dp_sbc_encoder_cb;
+
+static void a2dp_sbc_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated);
+static bool a2dp_sbc_read_feeding(void);
+static void a2dp_sbc_encode_frames(uint8_t nb_frame);
+static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us);
+static uint8_t calculate_max_frames_per_packet(void);
+static uint16_t a2dp_sbc_source_rate(void);
+static uint32_t a2dp_sbc_frame_length(void);
+
+bool A2DP_LoadEncoderSbc(void) {
+ // Nothing to do - the library is statically linked
+ return true;
+}
+
+void A2DP_UnloadEncoderSbc(void) {
+ // Nothing to do - the library is statically linked
+}
+
+void a2dp_sbc_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback) {
+ memset(&a2dp_sbc_encoder_cb, 0, sizeof(a2dp_sbc_encoder_cb));
+
+ a2dp_sbc_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+ a2dp_sbc_encoder_cb.read_callback = read_callback;
+ a2dp_sbc_encoder_cb.enqueue_callback = enqueue_callback;
+ a2dp_sbc_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_sbc_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_sbc_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_sbc_encoder_cb.timestamp = 0;
+
+ // NOTE: Ignore the restart_input / restart_output flags - this initization
+ // happens when the connection is (re)started.
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ a2dp_sbc_encoder_update(a2dp_sbc_encoder_cb.peer_mtu, a2dp_codec_config,
+ &restart_input, &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigSbc::updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ a2dp_sbc_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_sbc_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_sbc_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_sbc_encoder_cb.timestamp = 0;
+
+ if (a2dp_sbc_encoder_cb.peer_mtu == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid peer MTU",
+ __func__, name().c_str());
+ return false;
+ }
+
+ a2dp_sbc_encoder_update(a2dp_sbc_encoder_cb.peer_mtu, this, p_restart_input,
+ p_restart_output, p_config_updated);
+ return true;
+}
+
+// Update the A2DP SBC encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_sbc_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated) {
+ SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+ uint16_t s16SamplingFreq;
+ int16_t s16BitPool = 0;
+ int16_t s16BitRate;
+ int16_t s16FrameLen;
+ uint8_t protect = 0;
+ int min_bitpool;
+ int max_bitpool;
+
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+ if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid codec config",
+ __func__, a2dp_codec_config->name().c_str());
+ return;
+ }
+ const uint8_t* p_codec_info = codec_info;
+ min_bitpool = A2DP_GetMinBitpoolSbc(p_codec_info);
+ max_bitpool = A2DP_GetMaxBitpoolSbc(p_codec_info);
+
+ // The feeding parameters
+ tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_sbc_encoder_cb.feeding_params;
+ p_feeding_params->sample_rate = A2DP_GetTrackSampleRateSbc(p_codec_info);
+ p_feeding_params->bits_per_sample =
+ A2DP_GetTrackBitsPerSampleSbc(p_codec_info);
+ p_feeding_params->channel_count = A2DP_GetTrackChannelCountSbc(p_codec_info);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+ __func__, p_feeding_params->sample_rate,
+ p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+ // The codec parameters
+ p_encoder_params->s16ChannelMode = A2DP_GetChannelModeCodeSbc(p_codec_info);
+ p_encoder_params->s16NumOfSubBands =
+ A2DP_GetNumberOfSubbandsSbc(p_codec_info);
+ p_encoder_params->s16NumOfBlocks = A2DP_GetNumberOfBlocksSbc(p_codec_info);
+ p_encoder_params->s16AllocationMethod =
+ A2DP_GetAllocationMethodCodeSbc(p_codec_info);
+ p_encoder_params->s16SamplingFreq =
+ A2DP_GetSamplingFrequencyCodeSbc(p_codec_info);
+ p_encoder_params->s16NumOfChannels =
+ A2DP_GetTrackChannelCountSbc(p_codec_info);
+
+ // Reset invalid parameters
+ if (!p_encoder_params->s16NumOfSubBands) {
+ LOG_WARN(LOG_TAG, "%s: SubBands are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_SUBBANDS);
+ p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
+ }
+ if (!p_encoder_params->s16NumOfBlocks) {
+ LOG_WARN(LOG_TAG, "%s: Blocks are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_BLOCKS);
+ p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
+ }
+ if (!p_encoder_params->s16NumOfChannels) {
+ LOG_WARN(LOG_TAG, "%s: Channels are set to 0, resetting to max (%d)",
+ __func__, SBC_MAX_NUM_OF_CHANNELS);
+ p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
+ }
+
+ uint16_t mtu_size = A2DP_SBC_BUFFER_SIZE - A2DP_SBC_OFFSET - sizeof(BT_HDR);
+ if (mtu_size < peer_mtu) {
+ a2dp_sbc_encoder_cb.TxAaMtuSize = mtu_size;
+ } else {
+ a2dp_sbc_encoder_cb.TxAaMtuSize = peer_mtu;
+ }
+
+ if (p_encoder_params->s16SamplingFreq == SBC_sf16000)
+ s16SamplingFreq = 16000;
+ else if (p_encoder_params->s16SamplingFreq == SBC_sf32000)
+ s16SamplingFreq = 32000;
+ else if (p_encoder_params->s16SamplingFreq == SBC_sf44100)
+ s16SamplingFreq = 44100;
+ else
+ s16SamplingFreq = 48000;
+
+ // Set the initial target bit rate
+ p_encoder_params->u16BitRate = a2dp_sbc_source_rate();
+
+ LOG_DEBUG(LOG_TAG, "%s: MTU=%d, peer_mtu=%d min_bitpool=%d max_bitpool=%d",
+ __func__, a2dp_sbc_encoder_cb.TxAaMtuSize, peer_mtu, min_bitpool,
+ max_bitpool);
+ LOG_DEBUG(LOG_TAG,
+ "%s: ChannelMode=%d, NumOfSubBands=%d, NumOfBlocks=%d, "
+ "AllocationMethod=%d, BitRate=%d, SamplingFreq=%d BitPool=%d",
+ __func__, p_encoder_params->s16ChannelMode,
+ p_encoder_params->s16NumOfSubBands,
+ p_encoder_params->s16NumOfBlocks,
+ p_encoder_params->s16AllocationMethod, p_encoder_params->u16BitRate,
+ s16SamplingFreq, p_encoder_params->s16BitPool);
+
+ do {
+ if ((p_encoder_params->s16ChannelMode == SBC_JOINT_STEREO) ||
+ (p_encoder_params->s16ChannelMode == SBC_STEREO)) {
+ s16BitPool = (int16_t)((p_encoder_params->u16BitRate *
+ p_encoder_params->s16NumOfSubBands * 1000 /
+ s16SamplingFreq) -
+ ((32 + (4 * p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfChannels) +
+ ((p_encoder_params->s16ChannelMode - 2) *
+ p_encoder_params->s16NumOfSubBands)) /
+ p_encoder_params->s16NumOfBlocks));
+
+ s16FrameLen = 4 +
+ (4 * p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfChannels) /
+ 8 +
+ (((p_encoder_params->s16ChannelMode - 2) *
+ p_encoder_params->s16NumOfSubBands) +
+ (p_encoder_params->s16NumOfBlocks * s16BitPool)) /
+ 8;
+
+ s16BitRate = (8 * s16FrameLen * s16SamplingFreq) /
+ (p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfBlocks * 1000);
+
+ if (s16BitRate > p_encoder_params->u16BitRate) s16BitPool--;
+
+ if (p_encoder_params->s16NumOfSubBands == 8)
+ s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
+ else
+ s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
+ } else {
+ s16BitPool =
+ (int16_t)(((p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->u16BitRate * 1000) /
+ (s16SamplingFreq * p_encoder_params->s16NumOfChannels)) -
+ (((32 / p_encoder_params->s16NumOfChannels) +
+ (4 * p_encoder_params->s16NumOfSubBands)) /
+ p_encoder_params->s16NumOfBlocks));
+
+ p_encoder_params->s16BitPool =
+ (s16BitPool > (16 * p_encoder_params->s16NumOfSubBands))
+ ? (16 * p_encoder_params->s16NumOfSubBands)
+ : s16BitPool;
+ }
+
+ if (s16BitPool < 0) s16BitPool = 0;
+
+ LOG_DEBUG(LOG_TAG, "%s: bitpool candidate: %d (%d kbps)", __func__,
+ s16BitPool, p_encoder_params->u16BitRate);
+
+ if (s16BitPool > max_bitpool) {
+ LOG_DEBUG(LOG_TAG, "%s: computed bitpool too large (%d)", __func__,
+ s16BitPool);
+ /* Decrease bitrate */
+ p_encoder_params->u16BitRate -= A2DP_SBC_BITRATE_STEP;
+ /* Record that we have decreased the bitrate */
+ protect |= 1;
+ } else if (s16BitPool < min_bitpool) {
+ LOG_WARN(LOG_TAG, "%s: computed bitpool too small (%d)", __func__,
+ s16BitPool);
+
+ /* Increase bitrate */
+ uint16_t previous_u16BitRate = p_encoder_params->u16BitRate;
+ p_encoder_params->u16BitRate += A2DP_SBC_BITRATE_STEP;
+ /* Record that we have increased the bitrate */
+ protect |= 2;
+ /* Check over-flow */
+ if (p_encoder_params->u16BitRate < previous_u16BitRate) protect |= 3;
+ } else {
+ break;
+ }
+ /* In case we have already increased and decreased the bitrate, just stop */
+ if (protect == 3) {
+ LOG_ERROR(LOG_TAG, "%s: could not find bitpool in range", __func__);
+ break;
+ }
+ } while (true);
+
+ /* Finally update the bitpool in the encoder structure */
+ p_encoder_params->s16BitPool = s16BitPool;
+
+ LOG_DEBUG(LOG_TAG, "%s: final bit rate %d, final bit pool %d", __func__,
+ p_encoder_params->u16BitRate, p_encoder_params->s16BitPool);
+
+ /* Reset entirely the SBC encoder */
+ SBC_Encoder_Init(&a2dp_sbc_encoder_cb.sbc_encoder_params);
+ a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+}
+
+void a2dp_sbc_encoder_cleanup(void) {
+ memset(&a2dp_sbc_encoder_cb, 0, sizeof(a2dp_sbc_encoder_cb));
+}
+
+void a2dp_sbc_feeding_reset(void) {
+ /* By default, just clear the entire state */
+ memset(&a2dp_sbc_encoder_cb.feeding_state, 0,
+ sizeof(a2dp_sbc_encoder_cb.feeding_state));
+
+ a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick =
+ (a2dp_sbc_encoder_cb.feeding_params.sample_rate *
+ a2dp_sbc_encoder_cb.feeding_params.bits_per_sample / 8 *
+ a2dp_sbc_encoder_cb.feeding_params.channel_count *
+ A2DP_SBC_ENCODER_INTERVAL_MS) /
+ 1000;
+
+ LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", __func__,
+ a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick);
+}
+
+void a2dp_sbc_feeding_flush(void) {
+ a2dp_sbc_encoder_cb.feeding_state.counter = 0;
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue = 0;
+}
+
+period_ms_t a2dp_sbc_get_encoder_interval_ms(void) {
+ return A2DP_SBC_ENCODER_INTERVAL_MS;
+}
+
+void a2dp_sbc_send_frames(uint64_t timestamp_us) {
+ uint8_t nb_frame = 0;
+ uint8_t nb_iterations = 0;
+
+ a2dp_sbc_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+ LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations",
+ __func__, nb_frame, nb_iterations);
+ if (nb_frame == 0) return;
+
+ for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+ // Transcode frame and enqueue
+ a2dp_sbc_encode_frames(nb_frame);
+ }
+}
+
+// Obtains the number of frames to send and number of iterations
+// to be used. |num_of_iterations| and |num_of_frames| parameters
+// are used as output param for returning the respective values.
+static void a2dp_sbc_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us) {
+ uint8_t nof = 0;
+ uint8_t noi = 1;
+
+ uint32_t projected_nof = 0;
+ uint32_t pcm_bytes_per_frame =
+ a2dp_sbc_encoder_cb.sbc_encoder_params.s16NumOfSubBands *
+ a2dp_sbc_encoder_cb.sbc_encoder_params.s16NumOfBlocks *
+ a2dp_sbc_encoder_cb.feeding_params.channel_count *
+ a2dp_sbc_encoder_cb.feeding_params.bits_per_sample / 8;
+ LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
+ pcm_bytes_per_frame);
+
+ uint32_t us_this_tick = A2DP_SBC_ENCODER_INTERVAL_MS * 1000;
+ uint64_t now_us = timestamp_us;
+ if (a2dp_sbc_encoder_cb.feeding_state.last_frame_us != 0)
+ us_this_tick = (now_us - a2dp_sbc_encoder_cb.feeding_state.last_frame_us);
+ a2dp_sbc_encoder_cb.feeding_state.last_frame_us = now_us;
+
+ a2dp_sbc_encoder_cb.feeding_state.counter +=
+ a2dp_sbc_encoder_cb.feeding_state.bytes_per_tick * us_this_tick /
+ (A2DP_SBC_ENCODER_INTERVAL_MS * 1000);
+
+ /* Calculate the number of frames pending for this media tick */
+ projected_nof =
+ a2dp_sbc_encoder_cb.feeding_state.counter / pcm_bytes_per_frame;
+ // Update the stats
+ a2dp_sbc_encoder_cb.stats.media_read_total_expected_frames += projected_nof;
+
+ if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) {
+ LOG_WARN(LOG_TAG, "%s: limiting frames to be sent from %d to %d", __func__,
+ projected_nof, MAX_PCM_FRAME_NUM_PER_TICK);
+
+ // Update the stats
+ size_t delta = projected_nof - MAX_PCM_FRAME_NUM_PER_TICK;
+ a2dp_sbc_encoder_cb.stats.media_read_total_dropped_frames += delta;
+
+ projected_nof = MAX_PCM_FRAME_NUM_PER_TICK;
+ }
+
+ LOG_VERBOSE(LOG_TAG, "%s: frames for available PCM data %u", __func__,
+ projected_nof);
+
+ if (a2dp_sbc_encoder_cb.is_peer_edr) {
+ if (!a2dp_sbc_encoder_cb.tx_sbc_frames) {
+ LOG_ERROR(LOG_TAG, "%s: tx_sbc_frames not updated, update from here",
+ __func__);
+ a2dp_sbc_encoder_cb.tx_sbc_frames = calculate_max_frames_per_packet();
+ }
+
+ nof = a2dp_sbc_encoder_cb.tx_sbc_frames;
+ if (!nof) {
+ LOG_ERROR(LOG_TAG,
+ "%s: number of frames not updated, set calculated values",
+ __func__);
+ nof = projected_nof;
+ noi = 1;
+ } else {
+ if (nof < projected_nof) {
+ noi = projected_nof / nof; // number of iterations would vary
+ if (noi > A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK) {
+ LOG_ERROR(LOG_TAG, "%s: Audio Congestion (iterations:%d > max (%d))",
+ __func__, noi, A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK);
+ noi = A2DP_SBC_MAX_PCM_ITER_NUM_PER_TICK;
+ a2dp_sbc_encoder_cb.feeding_state.counter =
+ noi * nof * pcm_bytes_per_frame;
+ }
+ projected_nof = nof;
+ } else {
+ noi = 1; // number of iterations is 1
+ LOG_VERBOSE(LOG_TAG, "%s: reducing frames for available PCM data",
+ __func__);
+ nof = projected_nof;
+ }
+ }
+ } else {
+ // For BR cases nof will be same as the value retrieved at projected_nof
+ LOG_VERBOSE(LOG_TAG, "%s: headset BR, number of frames %u", __func__, nof);
+ if (projected_nof > MAX_PCM_FRAME_NUM_PER_TICK) {
+ LOG_ERROR(LOG_TAG, "%s: Audio Congestion (frames: %d > max (%d))",
+ __func__, projected_nof, MAX_PCM_FRAME_NUM_PER_TICK);
+
+ // Update the stats
+ size_t delta = projected_nof - MAX_PCM_FRAME_NUM_PER_TICK;
+ a2dp_sbc_encoder_cb.stats.media_read_total_dropped_frames += delta;
+
+ projected_nof = MAX_PCM_FRAME_NUM_PER_TICK;
+ a2dp_sbc_encoder_cb.feeding_state.counter =
+ noi * projected_nof * pcm_bytes_per_frame;
+ }
+ nof = projected_nof;
+ }
+ a2dp_sbc_encoder_cb.feeding_state.counter -= noi * nof * pcm_bytes_per_frame;
+ LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+ __func__, nof, noi);
+
+ *num_of_frames = nof;
+ *num_of_iterations = noi;
+}
+
+static void a2dp_sbc_encode_frames(uint8_t nb_frame) {
+ SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+ uint8_t remain_nb_frame = nb_frame;
+ uint16_t blocm_x_subband =
+ p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
+
+ uint8_t last_frame_len = 0;
+ while (nb_frame) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(A2DP_SBC_BUFFER_SIZE);
+ p_buf->offset = A2DP_SBC_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+ a2dp_sbc_encoder_cb.stats.media_read_total_expected_packets++;
+
+ do {
+ /* Fill allocated buffer with 0 */
+ memset(a2dp_sbc_encoder_cb.pcmBuffer, 0,
+ blocm_x_subband * p_encoder_params->s16NumOfChannels);
+
+ //
+ // Read the PCM data and encode it. If necessary, upsample the data.
+ //
+ if (a2dp_sbc_read_feeding()) {
+ uint8_t* output = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+ int16_t* input = a2dp_sbc_encoder_cb.pcmBuffer;
+ uint16_t output_len = SBC_Encode(p_encoder_params, input, output);
+ last_frame_len = output_len;
+
+ /* Update SBC frame length */
+ p_buf->len += output_len;
+ nb_frame--;
+ p_buf->layer_specific++;
+ } else {
+ LOG_WARN(LOG_TAG, "%s: underflow %d, %d", __func__, nb_frame,
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
+ a2dp_sbc_encoder_cb.feeding_state.counter +=
+ nb_frame * p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfBlocks *
+ a2dp_sbc_encoder_cb.feeding_params.channel_count *
+ a2dp_sbc_encoder_cb.feeding_params.bits_per_sample / 8;
+ /* no more pcm to read */
+ nb_frame = 0;
+ }
+ } while (
+ ((p_buf->len + last_frame_len) < a2dp_sbc_encoder_cb.TxAaMtuSize) &&
+ (p_buf->layer_specific < 0x0F) && nb_frame);
+
+ if (p_buf->len) {
+ /*
+ * Timestamp of the media packet header represent the TS of the
+ * first SBC frame, i.e the timestamp before including this frame.
+ */
+ *((uint32_t*)(p_buf + 1)) = a2dp_sbc_encoder_cb.timestamp;
+
+ a2dp_sbc_encoder_cb.timestamp += p_buf->layer_specific * blocm_x_subband;
+
+ uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+ remain_nb_frame = nb_frame;
+ if (!a2dp_sbc_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+ } else {
+ a2dp_sbc_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ }
+ }
+}
+
+static bool a2dp_sbc_read_feeding(void) {
+ SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+ uint16_t blocm_x_subband =
+ p_encoder_params->s16NumOfSubBands * p_encoder_params->s16NumOfBlocks;
+ uint32_t read_size;
+ uint32_t sbc_sampling = 48000;
+ uint32_t src_samples;
+ uint16_t bytes_needed = blocm_x_subband * p_encoder_params->s16NumOfChannels *
+ a2dp_sbc_encoder_cb.feeding_params.bits_per_sample /
+ 8;
+ static uint16_t up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS *
+ SBC_MAX_NUM_OF_CHANNELS *
+ SBC_MAX_NUM_OF_SUBBANDS * 2];
+ static uint16_t read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS *
+ SBC_MAX_NUM_OF_CHANNELS *
+ SBC_MAX_NUM_OF_SUBBANDS];
+ uint32_t src_size_used;
+ uint32_t dst_size_used;
+ bool fract_needed;
+ int32_t fract_max;
+ int32_t fract_threshold;
+ uint32_t nb_byte_read;
+
+ /* Get the SBC sampling rate */
+ switch (p_encoder_params->s16SamplingFreq) {
+ case SBC_sf48000:
+ sbc_sampling = 48000;
+ break;
+ case SBC_sf44100:
+ sbc_sampling = 44100;
+ break;
+ case SBC_sf32000:
+ sbc_sampling = 32000;
+ break;
+ case SBC_sf16000:
+ sbc_sampling = 16000;
+ break;
+ }
+
+ a2dp_sbc_encoder_cb.stats.media_read_total_expected_reads_count++;
+ if (sbc_sampling == a2dp_sbc_encoder_cb.feeding_params.sample_rate) {
+ read_size =
+ bytes_needed - a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue;
+ a2dp_sbc_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;
+ nb_byte_read = a2dp_sbc_encoder_cb.read_callback(
+ ((uint8_t*)a2dp_sbc_encoder_cb.pcmBuffer) +
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+ read_size);
+ a2dp_sbc_encoder_cb.stats.media_read_total_actual_read_bytes +=
+ nb_byte_read;
+
+ if (nb_byte_read != read_size) {
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += nb_byte_read;
+ return false;
+ }
+ a2dp_sbc_encoder_cb.stats.media_read_total_actual_reads_count++;
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue = 0;
+ return true;
+ }
+
+ /*
+ * Some Feeding PCM frequencies require to split the number of sample
+ * to read.
+ * E.g 128 / 6 = 21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0
+ */
+ fract_needed = false; /* Default */
+ switch (a2dp_sbc_encoder_cb.feeding_params.sample_rate) {
+ case 32000:
+ case 8000:
+ fract_needed = true;
+ fract_max = 2; /* 0, 1 and 2 */
+ fract_threshold = 0; /* Add one for the first */
+ break;
+ case 16000:
+ fract_needed = true;
+ fract_max = 2; /* 0, 1 and 2 */
+ fract_threshold = 1; /* Add one for the first two frames*/
+ break;
+ }
+
+ /* Compute number of sample to read from source */
+ src_samples = blocm_x_subband;
+ src_samples *= a2dp_sbc_encoder_cb.feeding_params.sample_rate;
+ src_samples /= sbc_sampling;
+
+ /* The previous division may have a remainder not null */
+ if (fract_needed) {
+ if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter <= fract_threshold) {
+ src_samples++; /* for every read before threshold add one sample */
+ }
+
+ /* do nothing if counter >= threshold */
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter++; /* one more read */
+ if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter > fract_max) {
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_counter = 0;
+ }
+ }
+
+ /* Compute number of bytes to read from source */
+ read_size = src_samples;
+ read_size *= a2dp_sbc_encoder_cb.feeding_params.channel_count;
+ read_size *= (a2dp_sbc_encoder_cb.feeding_params.bits_per_sample / 8);
+ a2dp_sbc_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;
+
+ /* Read Data from UIPC channel */
+ nb_byte_read =
+ a2dp_sbc_encoder_cb.read_callback((uint8_t*)read_buffer, read_size);
+ a2dp_sbc_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+
+ if (nb_byte_read < read_size) {
+ if (nb_byte_read == 0) return false;
+
+ /* Fill the unfilled part of the read buffer with silence (0) */
+ memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+ nb_byte_read = read_size;
+ }
+ a2dp_sbc_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+ /* Initialize PCM up-sampling engine */
+ a2dp_sbc_init_up_sample(a2dp_sbc_encoder_cb.feeding_params.sample_rate,
+ sbc_sampling,
+ a2dp_sbc_encoder_cb.feeding_params.bits_per_sample,
+ a2dp_sbc_encoder_cb.feeding_params.channel_count);
+
+ /*
+ * Re-sample the read buffer.
+ * The output PCM buffer will be stereo, 16 bit per sample.
+ */
+ dst_size_used = a2dp_sbc_up_sample(
+ (uint8_t*)read_buffer,
+ (uint8_t*)up_sampled_buffer +
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+ nb_byte_read, sizeof(up_sampled_buffer) -
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue,
+ &src_size_used);
+
+ /* update the residue */
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue += dst_size_used;
+
+ /* only copy the pcm sample when we have up-sampled enough PCM */
+ if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue < bytes_needed)
+ return false;
+
+ /* Copy the output pcm samples in SBC encoding buffer */
+ memcpy((uint8_t*)a2dp_sbc_encoder_cb.pcmBuffer, (uint8_t*)up_sampled_buffer,
+ bytes_needed);
+ /* update the residue */
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue -= bytes_needed;
+
+ if (a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue != 0) {
+ memcpy((uint8_t*)up_sampled_buffer,
+ (uint8_t*)up_sampled_buffer + bytes_needed,
+ a2dp_sbc_encoder_cb.feeding_state.aa_feed_residue);
+ }
+ return true;
+}
+
+static uint8_t calculate_max_frames_per_packet(void) {
+ uint16_t effective_mtu_size = a2dp_sbc_encoder_cb.TxAaMtuSize;
+ SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+ uint16_t result = 0;
+ uint32_t frame_len;
+
+ LOG_VERBOSE(LOG_TAG, "%s: original AVDTP MTU size: %d", __func__,
+ a2dp_sbc_encoder_cb.TxAaMtuSize);
+
+ // Restrict the MTU - even though some Sink devices are advertising large
+ // MTU, they are not able to handle the packets and are stuttering.
+ if (effective_mtu_size > MAX_2MBPS_AVDTP_MTU) {
+ LOG_WARN(LOG_TAG, "%s: Restricting AVDTP MTU size to %d", __func__,
+ MAX_2MBPS_AVDTP_MTU);
+ effective_mtu_size = MAX_2MBPS_AVDTP_MTU;
+ a2dp_sbc_encoder_cb.TxAaMtuSize = effective_mtu_size;
+ }
+
+ if (!p_encoder_params->s16NumOfSubBands) {
+ LOG_ERROR(LOG_TAG, "%s: SubBands are set to 0, resetting to %d", __func__,
+ SBC_MAX_NUM_OF_SUBBANDS);
+ p_encoder_params->s16NumOfSubBands = SBC_MAX_NUM_OF_SUBBANDS;
+ }
+ if (!p_encoder_params->s16NumOfBlocks) {
+ LOG_ERROR(LOG_TAG, "%s: Blocks are set to 0, resetting to %d", __func__,
+ SBC_MAX_NUM_OF_BLOCKS);
+ p_encoder_params->s16NumOfBlocks = SBC_MAX_NUM_OF_BLOCKS;
+ }
+ if (!p_encoder_params->s16NumOfChannels) {
+ LOG_ERROR(LOG_TAG, "%s: Channels are set to 0, resetting to %d", __func__,
+ SBC_MAX_NUM_OF_CHANNELS);
+ p_encoder_params->s16NumOfChannels = SBC_MAX_NUM_OF_CHANNELS;
+ }
+
+ frame_len = a2dp_sbc_frame_length();
+
+ LOG_VERBOSE(LOG_TAG, "%s: Effective Tx MTU to be considered: %d", __func__,
+ effective_mtu_size);
+
+ switch (p_encoder_params->s16SamplingFreq) {
+ case SBC_sf44100:
+ if (frame_len == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Calculating frame length, resetting it to default %d",
+ __func__, A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1);
+ frame_len = A2DP_SBC_MAX_HQ_FRAME_SIZE_44_1;
+ }
+ result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len;
+ LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", __func__,
+ result);
+ break;
+
+ case SBC_sf48000:
+ if (frame_len == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Calculating frame length, resetting it to default %d",
+ __func__, A2DP_SBC_MAX_HQ_FRAME_SIZE_48);
+ frame_len = A2DP_SBC_MAX_HQ_FRAME_SIZE_48;
+ }
+ result = (effective_mtu_size - A2DP_HDR_SIZE) / frame_len;
+ LOG_VERBOSE(LOG_TAG, "%s: Max number of SBC frames: %d", __func__,
+ result);
+ break;
+
+ default:
+ LOG_ERROR(LOG_TAG, "%s: Max number of SBC frames: %d", __func__, result);
+ break;
+ }
+ return result;
+}
+
+static uint16_t a2dp_sbc_source_rate(void) {
+ uint16_t rate = A2DP_SBC_DEFAULT_BITRATE;
+
+ /* restrict bitrate if a2dp link is non-edr */
+ if (!a2dp_sbc_encoder_cb.is_peer_edr) {
+ rate = A2DP_SBC_NON_EDR_MAX_RATE;
+ LOG_VERBOSE(LOG_TAG, "%s: non-edr a2dp sink detected, restrict rate to %d",
+ __func__, rate);
+ }
+
+ return rate;
+}
+
+static uint32_t a2dp_sbc_frame_length(void) {
+ SBC_ENC_PARAMS* p_encoder_params = &a2dp_sbc_encoder_cb.sbc_encoder_params;
+ uint32_t frame_len = 0;
+
+ LOG_VERBOSE(LOG_TAG,
+ "%s: channel mode: %d, sub-band: %d, number of block: %d, "
+ "bitpool: %d, sampling frequency: %d, num channels: %d",
+ __func__, p_encoder_params->s16ChannelMode,
+ p_encoder_params->s16NumOfSubBands,
+ p_encoder_params->s16NumOfBlocks, p_encoder_params->s16BitPool,
+ p_encoder_params->s16SamplingFreq,
+ p_encoder_params->s16NumOfChannels);
+
+ switch (p_encoder_params->s16ChannelMode) {
+ case SBC_MONO:
+ /* FALLTHROUGH */
+ case SBC_DUAL:
+ frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+ ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+ p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfChannels) /
+ CHAR_BIT) +
+ ((uint32_t)(p_encoder_params->s16NumOfBlocks *
+ p_encoder_params->s16NumOfChannels *
+ p_encoder_params->s16BitPool) /
+ CHAR_BIT);
+ break;
+ case SBC_STEREO:
+ frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+ ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+ p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfChannels) /
+ CHAR_BIT) +
+ ((uint32_t)(p_encoder_params->s16NumOfBlocks *
+ p_encoder_params->s16BitPool) /
+ CHAR_BIT);
+ break;
+ case SBC_JOINT_STEREO:
+ frame_len = A2DP_SBC_FRAME_HEADER_SIZE_BYTES +
+ ((uint32_t)(A2DP_SBC_SCALE_FACTOR_BITS *
+ p_encoder_params->s16NumOfSubBands *
+ p_encoder_params->s16NumOfChannels) /
+ CHAR_BIT) +
+ ((uint32_t)(p_encoder_params->s16NumOfSubBands +
+ (p_encoder_params->s16NumOfBlocks *
+ p_encoder_params->s16BitPool)) /
+ CHAR_BIT);
+ break;
+ default:
+ LOG_VERBOSE(LOG_TAG, "%s: Invalid channel number: %d", __func__,
+ p_encoder_params->s16ChannelMode);
+ break;
+ }
+ LOG_VERBOSE(LOG_TAG, "%s: calculated frame length: %d", __func__, frame_len);
+ return frame_len;
+}
+
+period_ms_t A2dpCodecConfigSbc::encoderIntervalMs() const {
+ return a2dp_sbc_get_encoder_interval_ms();
+}
+
+void A2dpCodecConfigSbc::debug_codec_dump(int fd) {
+ a2dp_sbc_encoder_stats_t* stats = &a2dp_sbc_encoder_cb.stats;
+
+ A2dpCodecConfig::debug_codec_dump(fd);
+
+ dprintf(fd,
+ " Packet counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_packets,
+ stats->media_read_total_dropped_packets);
+
+ dprintf(fd,
+ " PCM read counts (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_reads_count,
+ stats->media_read_total_actual_reads_count);
+
+ dprintf(fd,
+ " PCM read bytes (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_read_bytes,
+ stats->media_read_total_actual_read_bytes);
+
+ dprintf(fd,
+ " Frames counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_frames,
+ stats->media_read_total_dropped_frames);
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_sbc_up_sample.cc b/mtkbt/code/bt/stack/a2dp/a2dp_sbc_up_sample.cc
new file mode 100755
index 0000000..da15fe9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_sbc_up_sample.cc
@@ -0,0 +1,370 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains utility functions for dealing with SBC data frames
+ * and codec capabilities.
+ *
+ ******************************************************************************/
+
+#include "a2dp_sbc_up_sample.h"
+
+typedef int(tA2DP_SBC_ACT)(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+typedef struct {
+ int32_t cur_pos; /* current position */
+ uint32_t src_sps; /* samples per second (source audio data) */
+ uint32_t dst_sps; /* samples per second (converted audio data) */
+ tA2DP_SBC_ACT* p_act; /* the action function to do the conversion */
+ uint8_t bits; /* number of bits per pcm sample */
+ uint8_t n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
+ int16_t worker1;
+ int16_t worker2;
+ uint8_t div;
+} tA2DP_SBC_UPS_CB;
+
+tA2DP_SBC_UPS_CB a2dp_sbc_ups_cb;
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_init_up_sample
+ *
+ * Description initialize the up sample
+ *
+ * src_sps: samples per second (source audio data)
+ * dst_sps: samples per second (converted audio data)
+ * bits: number of bits per pcm sample
+ * n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void a2dp_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits,
+ uint8_t n_channels) {
+ a2dp_sbc_ups_cb.cur_pos = -1;
+ a2dp_sbc_ups_cb.src_sps = src_sps;
+ a2dp_sbc_ups_cb.dst_sps = dst_sps;
+ a2dp_sbc_ups_cb.bits = bits;
+ a2dp_sbc_ups_cb.n_channels = n_channels;
+
+ if (n_channels == 1) {
+ /* mono */
+ if (bits == 8) {
+ a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8m;
+ a2dp_sbc_ups_cb.div = 1;
+ } else {
+ a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16m;
+ a2dp_sbc_ups_cb.div = 2;
+ }
+ } else {
+ /* stereo */
+ if (bits == 8) {
+ a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_8s;
+ a2dp_sbc_ups_cb.div = 2;
+ } else {
+ a2dp_sbc_ups_cb.p_act = a2dp_sbc_up_sample_16s;
+ a2dp_sbc_ups_cb.div = 4;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (number of bytes)
+ * dst_samples: The size of p_dst (number of bytes)
+ *
+ * Note: An AE reported an issue with this function.
+ * When called with a2dp_sbc_up_sample(src, uint8_array_dst..)
+ * the byte before uint8_array_dst may get overwritten.
+ * Using uint16_array_dst avoids the problem.
+ * This issue is related to endian-ness and is hard to resolve
+ * in a generic manner.
+ * **************** Please use uint16 array as dst.
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret) {
+ uint32_t src;
+ uint32_t dst;
+
+ if (a2dp_sbc_ups_cb.p_act) {
+ src = src_samples / a2dp_sbc_ups_cb.div;
+ dst = dst_samples / a2dp_sbc_ups_cb.div;
+ return (*a2dp_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret);
+ } else {
+ *p_ret = 0;
+ return 0;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_16s (16bits-stereo)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 4
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 4 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_16s(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret) {
+ int16_t* p_src_tmp = (int16_t*)p_src;
+ int16_t* p_dst_tmp = (int16_t*)p_dst;
+ int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
+ int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
+ uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+ uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+ while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+ *p_dst_tmp++ = *p_worker1;
+ *p_dst_tmp++ = *p_worker2;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ }
+
+ a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+ while (src_samples-- && dst_samples) {
+ *p_worker1 = *p_src_tmp++;
+ *p_worker2 = *p_src_tmp++;
+
+ do {
+ *p_dst_tmp++ = *p_worker1;
+ *p_dst_tmp++ = *p_worker2;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+ a2dp_sbc_ups_cb.cur_pos += dst_sps;
+ }
+
+ if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+ *p_ret = ((char*)p_src_tmp - (char*)p_src);
+ return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_16m (16bits-mono)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 2
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 2 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_16m(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret) {
+ int16_t* p_src_tmp = (int16_t*)p_src;
+ int16_t* p_dst_tmp = (int16_t*)p_dst;
+ int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
+ uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+ uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+ while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+ *p_dst_tmp++ = *p_worker;
+ *p_dst_tmp++ = *p_worker;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ dst_samples--;
+ }
+
+ a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+ while (src_samples-- && dst_samples) {
+ *p_worker = *p_src_tmp++;
+
+ do {
+ *p_dst_tmp++ = *p_worker;
+ *p_dst_tmp++ = *p_worker;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ dst_samples--;
+
+ } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+ a2dp_sbc_ups_cb.cur_pos += dst_sps;
+ }
+
+ if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+ *p_ret = ((char*)p_src_tmp - (char*)p_src);
+ return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_8s (8bits-stereo)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 2
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 2 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_8s(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret) {
+ uint8_t* p_src_tmp = (uint8_t*)p_src;
+ int16_t* p_dst_tmp = (int16_t*)p_dst;
+ int16_t* p_worker1 = &a2dp_sbc_ups_cb.worker1;
+ int16_t* p_worker2 = &a2dp_sbc_ups_cb.worker2;
+ uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+ uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+ while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+ *p_dst_tmp++ = *p_worker1;
+ *p_dst_tmp++ = *p_worker2;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ dst_samples--;
+ }
+
+ a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+ while (src_samples-- && dst_samples) {
+ *p_worker1 = *(uint8_t*)p_src_tmp++;
+ *p_worker1 -= 0x80;
+ *p_worker1 <<= 8;
+ *p_worker2 = *(uint8_t*)p_src_tmp++;
+ *p_worker2 -= 0x80;
+ *p_worker2 <<= 8;
+
+ do {
+ *p_dst_tmp++ = *p_worker1;
+ *p_dst_tmp++ = *p_worker2;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples--;
+ dst_samples--;
+ } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+ a2dp_sbc_ups_cb.cur_pos += dst_sps;
+ }
+
+ if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+ *p_ret = ((char*)p_src_tmp - (char*)p_src);
+ return ((char*)p_dst_tmp - (char*)p_dst);
+}
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_8m (8bits-mono)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (number of bytes)
+ * dst_samples: The size of p_dst (number of bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_8m(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret) {
+ uint8_t* p_src_tmp = (uint8_t*)p_src;
+ int16_t* p_dst_tmp = (int16_t*)p_dst;
+ int16_t* p_worker = &a2dp_sbc_ups_cb.worker1;
+ uint32_t src_sps = a2dp_sbc_ups_cb.src_sps;
+ uint32_t dst_sps = a2dp_sbc_ups_cb.dst_sps;
+
+ while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples) {
+ *p_dst_tmp++ = *p_worker;
+ *p_dst_tmp++ = *p_worker;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples -= 4;
+ }
+
+ a2dp_sbc_ups_cb.cur_pos = dst_sps;
+
+ while (src_samples-- && dst_samples) {
+ *p_worker = *(uint8_t*)p_src_tmp++;
+ *p_worker -= 0x80;
+ *p_worker <<= 8;
+
+ do {
+ *p_dst_tmp++ = *p_worker;
+ *p_dst_tmp++ = *p_worker;
+
+ a2dp_sbc_ups_cb.cur_pos -= src_sps;
+ dst_samples -= 4;
+
+ } while (a2dp_sbc_ups_cb.cur_pos > 0 && dst_samples);
+
+ a2dp_sbc_ups_cb.cur_pos += dst_sps;
+ }
+
+ if (a2dp_sbc_ups_cb.cur_pos == (int32_t)dst_sps) a2dp_sbc_ups_cb.cur_pos = 0;
+
+ *p_ret = ((char*)p_src_tmp - (char*)p_src);
+ return ((char*)p_dst_tmp - (char*)p_dst);
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor.cc
new file mode 100755
index 0000000..e1d88b1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor.cc
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Vendor Specific A2DP Codecs Support
+ */
+
+#define LOG_TAG "a2dp_vendor"
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx.h"
+#include "a2dp_vendor_aptx_hd.h"
+#include "a2dp_vendor_ldac.h"
+#include "bt_target.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_IsVendorSourceCodecValidAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_IsVendorSourceCodecValidAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsVendorSourceCodecValidLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
+
+bool A2DP_IsVendorSinkCodecValid(UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return false;
+}
+
+bool A2DP_IsVendorPeerSourceCodecValid(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return false;
+}
+
+bool A2DP_IsVendorPeerSinkCodecValid(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_IsVendorPeerSinkCodecValidAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_IsVendorPeerSinkCodecValidAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_IsVendorPeerSinkCodecValidLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
+
+bool A2DP_IsVendorSinkCodecSupported(UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return false;
+}
+
+bool A2DP_IsVendorPeerSourceCodecSupported(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id> and peer codec capabilities
+ // NOTE: Should be done only for local Sink codecs.
+
+ return false;
+}
+
+tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(
+ UNUSED_ATTR const uint8_t* p_src_cap, UNUSED_ATTR uint8_t* p_pref_cfg) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return A2DP_NS_CODEC_TYPE;
+}
+
+uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info) {
+ const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX];
+
+ uint32_t vendor_id = (p[0] & 0x000000ff) | ((p[1] << 8) & 0x0000ff00) |
+ ((p[2] << 16) & 0x00ff0000) |
+ ((p[3] << 24) & 0xff000000);
+
+ return vendor_id;
+}
+
+uint16_t A2DP_VendorCodecGetCodecId(const uint8_t* p_codec_info) {
+ const uint8_t* p = &p_codec_info[A2DP_VENDOR_CODEC_CODEC_ID_START_IDX];
+
+ uint16_t codec_id = (p[0] & 0x00ff) | ((p[1] << 8) & 0xff00);
+
+ return codec_id;
+}
+
+bool A2DP_VendorUsesRtpHeader(bool content_protection_enabled,
+ const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorUsesRtpHeaderAptx(content_protection_enabled,
+ p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorUsesRtpHeaderAptxHd(content_protection_enabled,
+ p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorUsesRtpHeaderLdac(content_protection_enabled,
+ p_codec_info);
+ }
+
+ // Add checks based on <content_protection_enabled, vendor_id, codec_id>
+
+ return true;
+}
+
+const char* A2DP_VendorCodecName(UNUSED_ATTR const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecNameAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecNameAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorCodecNameLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return "UNKNOWN VENDOR CODEC";
+}
+
+bool A2DP_VendorCodecTypeEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ if ((codec_type_a != codec_type_b) ||
+ (codec_type_a != A2DP_MEDIA_CT_NON_A2DP)) {
+ return false;
+ }
+
+ uint32_t vendor_id_a = A2DP_VendorCodecGetVendorId(p_codec_info_a);
+ uint16_t codec_id_a = A2DP_VendorCodecGetCodecId(p_codec_info_a);
+ uint32_t vendor_id_b = A2DP_VendorCodecGetVendorId(p_codec_info_b);
+ uint16_t codec_id_b = A2DP_VendorCodecGetCodecId(p_codec_info_b);
+
+ if (vendor_id_a != vendor_id_b || codec_id_a != codec_id_b) return false;
+
+ // Check for aptX
+ if (vendor_id_a == A2DP_APTX_VENDOR_ID &&
+ codec_id_a == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecTypeEqualsAptx(p_codec_info_a, p_codec_info_b);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id_a == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id_a == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecTypeEqualsAptxHd(p_codec_info_a, p_codec_info_b);
+ }
+
+ // Check for LDAC
+ if (vendor_id_a == A2DP_LDAC_VENDOR_ID && codec_id_a == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorCodecTypeEqualsLdac(p_codec_info_a, p_codec_info_b);
+ }
+
+ // OPTIONAL: Add extra vendor-specific checks based on the
+ // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
+
+ return true;
+}
+
+bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_CODEC_TYPE codec_type_a = A2DP_GetCodecType(p_codec_info_a);
+ tA2DP_CODEC_TYPE codec_type_b = A2DP_GetCodecType(p_codec_info_b);
+
+ if ((codec_type_a != codec_type_b) ||
+ (codec_type_a != A2DP_MEDIA_CT_NON_A2DP)) {
+ return false;
+ }
+
+ uint32_t vendor_id_a = A2DP_VendorCodecGetVendorId(p_codec_info_a);
+ uint16_t codec_id_a = A2DP_VendorCodecGetCodecId(p_codec_info_a);
+ uint32_t vendor_id_b = A2DP_VendorCodecGetVendorId(p_codec_info_b);
+ uint16_t codec_id_b = A2DP_VendorCodecGetCodecId(p_codec_info_b);
+
+ if ((vendor_id_a != vendor_id_b) || (codec_id_a != codec_id_b)) return false;
+
+ // Check for aptX
+ if (vendor_id_a == A2DP_APTX_VENDOR_ID &&
+ codec_id_a == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecEqualsAptx(p_codec_info_a, p_codec_info_b);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id_a == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id_a == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorCodecEqualsAptxHd(p_codec_info_a, p_codec_info_b);
+ }
+
+ // Check for LDAC
+ if (vendor_id_a == A2DP_LDAC_VENDOR_ID && codec_id_a == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorCodecEqualsLdac(p_codec_info_a, p_codec_info_b);
+ }
+
+ // Add extra vendor-specific checks based on the
+ // vendor-specific data stored in "p_codec_info_a" and "p_codec_info_b".
+
+ return false;
+}
+
+int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackSampleRateAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackSampleRateAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetTrackSampleRateLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return -1;
+}
+
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return -1;
+}
+
+int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackChannelCountAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetTrackChannelCountAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetTrackChannelCountLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return -1;
+}
+
+int A2DP_VendorGetSinkTrackChannelType(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return -1;
+}
+
+int A2DP_VendorGetSinkFramesCountToProcess(
+ UNUSED_ATTR uint64_t time_interval_ms,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ // uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ // uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Add checks based on <vendor_id, codec_id>
+ // NOTE: Should be done only for local Sink codecs.
+
+ return -1;
+}
+
+bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetPacketTimestampAptx(p_codec_info, p_data, p_timestamp);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetPacketTimestampAptxHd(p_codec_info, p_data,
+ p_timestamp);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetPacketTimestampLdac(p_codec_info, p_data, p_timestamp);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
+
+bool A2DP_VendorBuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorBuildCodecHeaderAptx(p_codec_info, p_buf,
+ frames_per_packet);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorBuildCodecHeaderAptxHd(p_codec_info, p_buf,
+ frames_per_packet);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorBuildCodecHeaderLdac(p_codec_info, p_buf,
+ frames_per_packet);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
+ const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetEncoderInterfaceAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorGetEncoderInterfaceAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorGetEncoderInterfaceLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return NULL;
+}
+
+bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorAdjustCodecAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorAdjustCodecAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorAdjustCodecLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return false;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndex(
+ const uint8_t* p_codec_info) {
+ uint32_t vendor_id = A2DP_VendorCodecGetVendorId(p_codec_info);
+ uint16_t codec_id = A2DP_VendorCodecGetCodecId(p_codec_info);
+
+ // Check for aptX
+ if (vendor_id == A2DP_APTX_VENDOR_ID &&
+ codec_id == A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorSourceCodecIndexAptx(p_codec_info);
+ }
+
+ // Check for aptX-HD
+ if (vendor_id == A2DP_APTX_HD_VENDOR_ID &&
+ codec_id == A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_VendorSourceCodecIndexAptxHd(p_codec_info);
+ }
+
+ // Check for LDAC
+ if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
+ return A2DP_VendorSourceCodecIndexLdac(p_codec_info);
+ }
+
+ // Add checks based on <vendor_id, codec_id>
+
+ return BTAV_A2DP_CODEC_INDEX_MAX;
+}
+
+const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index) {
+ // Add checks based on codec_index
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ break; // These are not vendor-specific codecs
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ return A2DP_VendorCodecIndexStrAptx();
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ return A2DP_VendorCodecIndexStrAptxHd();
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ return A2DP_VendorCodecIndexStrLdac();
+ // Add a switch statement for each vendor-specific codec
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ break;
+ }
+
+ return "UNKNOWN CODEC INDEX";
+}
+
+bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg) {
+ // Add checks based on codec_index
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ break; // These are not vendor-specific codecs
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ return A2DP_VendorInitCodecConfigAptx(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ return A2DP_VendorInitCodecConfigAptxHd(p_cfg);
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ return A2DP_VendorInitCodecConfigLdac(p_cfg);
+ // Add a switch statement for each vendor-specific codec
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ break;
+ }
+
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx.cc
new file mode 100755
index 0000000..10e15bc
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx.cc
@@ -0,0 +1,889 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse the aptX Codec Information
+ * Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_vendor_aptx"
+
+#include "bt_target.h"
+
+#include "a2dp_vendor_aptx.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx_encoder.h"
+#include "bt_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+// data type for the aptX Codec Information Element */
+typedef struct {
+ uint32_t vendorId;
+ uint16_t codecId; /* Codec ID for aptX */
+ uint8_t sampleRate; /* Sampling Frequency */
+ uint8_t channelMode; /* STEREO/DUAL/MONO */
+ uint8_t future1;
+ uint8_t future2;
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_APTX_CIE;
+
+/* aptX Source codec capabilities */
+static const tA2DP_APTX_CIE a2dp_aptx_caps = {
+ A2DP_APTX_VENDOR_ID, /* vendorId */
+ A2DP_APTX_CODEC_ID_BLUETOOTH, /* codecId */
+ (A2DP_APTX_SAMPLERATE_44100 | A2DP_APTX_SAMPLERATE_48000), /* sampleRate */
+ A2DP_APTX_CHANNELS_STEREO, /* channelMode */
+ A2DP_APTX_FUTURE_1, /* future1 */
+ A2DP_APTX_FUTURE_2, /* future2 */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
+};
+
+/* Default aptX codec configuration */
+static const tA2DP_APTX_CIE a2dp_aptx_default_config = {
+ A2DP_APTX_VENDOR_ID, /* vendorId */
+ A2DP_APTX_CODEC_ID_BLUETOOTH, /* codecId */
+ A2DP_APTX_SAMPLERATE_44100, /* sampleRate */
+ A2DP_APTX_CHANNELS_STEREO, /* channelMode */
+ A2DP_APTX_FUTURE_1, /* future1 */
+ A2DP_APTX_FUTURE_2, /* future2 */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 /* bits_per_sample */
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_aptx = {
+ a2dp_vendor_aptx_encoder_init,
+ a2dp_vendor_aptx_encoder_cleanup,
+ a2dp_vendor_aptx_feeding_reset,
+ a2dp_vendor_aptx_feeding_flush,
+ a2dp_vendor_aptx_get_encoder_interval_ms,
+ a2dp_vendor_aptx_send_frames,
+ nullptr // set_transmit_queue_length
+};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAptx(
+ const tA2DP_APTX_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_peer_codec_info);
+
+// Builds the aptX Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the aptX Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoAptx(uint8_t media_type,
+ const tA2DP_APTX_CIE* p_ie,
+ uint8_t* p_result) {
+ if (p_ie == NULL || p_result == NULL) {
+ return A2DP_INVALID_PARAMS;
+ }
+
+ *p_result++ = A2DP_APTX_CODEC_LEN;
+ *p_result++ = (media_type << 4);
+ *p_result++ = A2DP_MEDIA_CT_NON_A2DP;
+ *p_result++ = (uint8_t)(p_ie->vendorId & 0x000000FF);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x0000FF00) >> 8);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x00FF0000) >> 16);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0xFF000000) >> 24);
+ *p_result++ = (uint8_t)(p_ie->codecId & 0x00FF);
+ *p_result++ = (uint8_t)((p_ie->codecId & 0xFF00) >> 8);
+ *p_result++ = p_ie->sampleRate | p_ie->channelMode;
+
+ return A2DP_SUCCESS;
+}
+
+// Parses the aptX Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence is
+// codec capabilities, otherwise is codec configuration.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoAptx(tA2DP_APTX_CIE* p_ie,
+ const uint8_t* p_codec_info,
+ bool is_capability) {
+ uint8_t losc;
+ uint8_t media_type;
+ tA2DP_CODEC_TYPE codec_type;
+
+ if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+ // Check the codec capability length
+ losc = *p_codec_info++;
+ if (losc != A2DP_APTX_CODEC_LEN) return A2DP_WRONG_CODEC;
+
+ media_type = (*p_codec_info++) >> 4;
+ codec_type = *p_codec_info++;
+ /* Check the Media Type and Media Codec Type */
+ if (media_type != AVDT_MEDIA_TYPE_AUDIO ||
+ codec_type != A2DP_MEDIA_CT_NON_A2DP) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ // Check the Vendor ID and Codec ID */
+ p_ie->vendorId = (*p_codec_info & 0x000000FF) |
+ (*(p_codec_info + 1) << 8 & 0x0000FF00) |
+ (*(p_codec_info + 2) << 16 & 0x00FF0000) |
+ (*(p_codec_info + 3) << 24 & 0xFF000000);
+ p_codec_info += 4;
+ p_ie->codecId =
+ (*p_codec_info & 0x00FF) | (*(p_codec_info + 1) << 8 & 0xFF00);
+ p_codec_info += 2;
+ if (p_ie->vendorId != A2DP_APTX_VENDOR_ID ||
+ p_ie->codecId != A2DP_APTX_CODEC_ID_BLUETOOTH) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ p_ie->channelMode = *p_codec_info & 0x0F;
+ p_ie->sampleRate = *p_codec_info & 0xF0;
+ p_codec_info++;
+
+ if (is_capability) return A2DP_SUCCESS;
+
+ if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_IsVendorSourceCodecValidAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSinkCodecValidAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+// Checks whether A2DP aptX codec configuration matches with a device's codec
+// capabilities. |p_cap| is the aptX codec configuration. |p_codec_info| is
+// the device's codec capabilities.
+// If |is_capability| is true, the byte sequence is codec capabilities,
+// otherwise is codec configuration.
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAptx(
+ const tA2DP_APTX_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability) {
+ tA2DP_STATUS status;
+ tA2DP_APTX_CIE cfg_cie;
+
+ /* parse configuration */
+ status = A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ LOG_DEBUG(LOG_TAG, "%s: FREQ peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.sampleRate, p_cap->sampleRate);
+ LOG_DEBUG(LOG_TAG, "%s: CH_MODE peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.channelMode, p_cap->channelMode);
+
+ /* sampling frequency */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_NS_SAMP_FREQ;
+
+ /* channel mode */
+ if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_VendorUsesRtpHeaderAptx(UNUSED_ATTR bool content_protection_enabled,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ return true;
+#else
+ // no RTP header for aptX classic and no Copy Protection byte
+ return false;
+#endif
+}
+
+const char* A2DP_VendorCodecNameAptx(UNUSED_ATTR const uint8_t* p_codec_info) {
+ return "aptX";
+}
+
+bool A2DP_VendorCodecTypeEqualsAptx(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_APTX_CIE aptx_cie_a;
+ tA2DP_APTX_CIE aptx_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptx(&aptx_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAptx(&aptx_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2DP_VendorCodecEqualsAptx(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_APTX_CIE aptx_cie_a;
+ tA2DP_APTX_CIE aptx_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptx(&aptx_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAptx(&aptx_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return (aptx_cie_a.sampleRate == aptx_cie_b.sampleRate) &&
+ (aptx_cie_a.channelMode == aptx_cie_b.channelMode);
+}
+
+int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE aptx_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ if (aptx_cie.sampleRate == A2DP_APTX_SAMPLERATE_44100) return 44100;
+ if (aptx_cie.sampleRate == A2DP_APTX_SAMPLERATE_48000) return 48000;
+
+ return -1;
+}
+
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE aptx_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return 16; // For aptX we always use 16 bits per audio sample
+}
+
+int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE aptx_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aptx_cie.channelMode) {
+ case A2DP_APTX_CHANNELS_MONO:
+ return 1;
+ case A2DP_APTX_CHANNELS_STEREO:
+ return 2;
+ }
+
+ return -1;
+}
+
+bool A2DP_VendorGetPacketTimestampAptx(UNUSED_ATTR const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp) {
+ // TODO: Is this function really codec-specific?
+ *p_timestamp = *(const uint32_t*)p_data;
+ return true;
+}
+
+bool A2DP_VendorBuildCodecHeaderAptx(UNUSED_ATTR const uint8_t* p_codec_info,
+ UNUSED_ATTR BT_HDR* p_buf,
+ UNUSED_ATTR uint16_t frames_per_packet) {
+ // Nothing to do
+ return true;
+}
+
+void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info) {
+ tA2DP_STATUS a2dp_status;
+ tA2DP_APTX_CIE aptx_cie;
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+ a2dp_status = A2DP_ParseInfoAptx(&aptx_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptx fail:%d", __func__, a2dp_status);
+ return;
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aptx_cie.sampleRate);
+ if (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+ }
+ if (aptx_cie.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", aptx_cie.channelMode);
+ if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_MONO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+ }
+ if (aptx_cie.channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+ }
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsVendorSourceCodecValidAptx(p_codec_info)) return NULL;
+
+ return &a2dp_encoder_interface_aptx;
+}
+
+bool A2DP_VendorAdjustCodecAptx(uint8_t* p_codec_info) {
+ tA2DP_APTX_CIE cfg_cie;
+
+ // Nothing to do: just verify the codec info is valid
+ if (A2DP_ParseInfoAptx(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+ return false;
+
+ return true;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptx(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SOURCE_APTX;
+}
+
+const char* A2DP_VendorCodecIndexStrAptx(void) { return "aptX"; }
+
+bool A2DP_VendorInitCodecConfigAptx(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Content protection info - support SCMS-T */
+ uint8_t* p = p_cfg->protect_info;
+ *p++ = AVDT_CP_LOSC;
+ UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+ p_cfg->num_protect = 1;
+#endif
+
+ return true;
+}
+
+A2dpCodecConfigAptx::A2dpCodecConfigAptx(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, "aptX",
+ codec_priority) {
+ // Compute the local capability
+ if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (a2dp_aptx_caps.sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ codec_local_capability_.bits_per_sample = a2dp_aptx_caps.bits_per_sample;
+ if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_MONO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (a2dp_aptx_caps.channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigAptx::~A2dpCodecConfigAptx() {}
+
+bool A2dpCodecConfigAptx::init() {
+ if (!isValid()) return false;
+
+ // Load the encoder
+ if (!A2DP_VendorLoadEncoderAptx()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecConfigAptx::useRtpHeaderMarkerBit() const { return false; }
+
+//
+// Selects the best sample rate from |sampleRate|.
+// The result is stored in |p_result| and p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint8_t sampleRate,
+ tA2DP_APTX_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ p_result->sampleRate = A2DP_APTX_SAMPLERATE_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ p_result->sampleRate = A2DP_APTX_SAMPLERATE_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |sampleRate| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t sampleRate,
+ tA2DP_APTX_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ p_result->sampleRate = A2DP_APTX_SAMPLERATE_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ p_result->sampleRate = A2DP_APTX_SAMPLERATE_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best bits per sample.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+ btav_a2dp_codec_config_t* p_codec_config) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+ const btav_a2dp_codec_config_t* p_codec_audio_config,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best channel mode from |channelMode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t channelMode,
+ tA2DP_APTX_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ p_result->channelMode = A2DP_APTX_CHANNELS_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+ p_result->channelMode = A2DP_APTX_CHANNELS_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |channelMode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t channelMode,
+ tA2DP_APTX_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+ p_result->channelMode = A2DP_APTX_CHANNELS_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ p_result->channelMode = A2DP_APTX_CHANNELS_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+bool A2dpCodecConfigAptx::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ tA2DP_APTX_CIE sink_info_cie;
+ tA2DP_APTX_CIE result_config_cie;
+ uint8_t sampleRate;
+ uint8_t channelMode;
+
+ // Save the internal state
+ btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+ btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+ btav_a2dp_codec_config_t saved_codec_selectable_capability =
+ codec_selectable_capability_;
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+ memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+ sizeof(ota_codec_peer_config_));
+
+ tA2DP_STATUS status =
+ A2DP_ParseInfoAptx(&sink_info_cie, p_peer_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+ __func__, status);
+ goto fail;
+ }
+
+ //
+ // Build the preferred configuration
+ //
+ memset(&result_config_cie, 0, sizeof(result_config_cie));
+ result_config_cie.vendorId = a2dp_aptx_caps.vendorId;
+ result_config_cie.codecId = a2dp_aptx_caps.codecId;
+
+ //
+ // Select the sample frequency
+ //
+ sampleRate = a2dp_aptx_caps.sampleRate & sink_info_cie.sampleRate;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ switch (codec_user_config_.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ result_config_cie.sampleRate = A2DP_APTX_SAMPLERATE_44100;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ result_config_cie.sampleRate = A2DP_APTX_SAMPLERATE_48000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ break;
+ }
+
+ // Select the sample frequency if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (sampleRate & A2DP_APTX_SAMPLERATE_44100) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (sampleRate & A2DP_APTX_SAMPLERATE_48000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+
+ if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+ // Compute the common capability
+ if (sampleRate & A2DP_APTX_SAMPLERATE_44100)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (sampleRate & A2DP_APTX_SAMPLERATE_48000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+ // No user preference - try the codec audio config
+ if (select_audio_sample_rate(&codec_audio_config_, sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_sample_rate(
+ a2dp_aptx_default_config.sampleRate & sink_info_cie.sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_sample_rate(sampleRate, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match sample frequency: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aptx_caps.sampleRate, sink_info_cie.sampleRate);
+ goto fail;
+ }
+
+ //
+ // Select the bits per sample
+ //
+ // NOTE: this information is NOT included in the aptX A2DP codec
+ // description that is sent OTA.
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ switch (codec_user_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ break;
+ }
+
+ // Select the bits per sample if there is no user preference
+ do {
+ // Compute the selectable capability
+ codec_selectable_capability_.bits_per_sample =
+ a2dp_aptx_caps.bits_per_sample;
+
+ if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+ break;
+
+ // Compute the common capability
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+
+ // No user preference - try the codec audio config
+ if (select_audio_bits_per_sample(&codec_audio_config_, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ // NOTE: no-op - kept here for consistency
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match bits per sample: user preference = 0x%x",
+ __func__, codec_user_config_.bits_per_sample);
+ goto fail;
+ }
+
+ //
+ // Select the channel mode
+ //
+ channelMode = a2dp_aptx_caps.channelMode & sink_info_cie.channelMode;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ switch (codec_user_config_.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+ result_config_cie.channelMode = A2DP_APTX_CHANNELS_MONO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ result_config_cie.channelMode = A2DP_APTX_CHANNELS_STEREO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ break;
+ }
+
+ // Select the channel mode if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (channelMode & A2DP_APTX_CHANNELS_MONO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (channelMode & A2DP_APTX_CHANNELS_STEREO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+ // Compute the common capability
+ if (channelMode & A2DP_APTX_CHANNELS_MONO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (channelMode & A2DP_APTX_CHANNELS_STEREO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+
+ // No user preference - try the codec audio config
+ if (select_audio_channel_mode(&codec_audio_config_, channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_channel_mode(
+ a2dp_aptx_default_config.channelMode & sink_info_cie.channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_channel_mode(channelMode, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match channel mode: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aptx_caps.channelMode, sink_info_cie.channelMode);
+ goto fail;
+ }
+
+ //
+ // Set the rest of the fields as bit-wise AND operation
+ //
+ result_config_cie.future1 = a2dp_aptx_caps.future1 & sink_info_cie.future1;
+ result_config_cie.future2 = a2dp_aptx_caps.future2 & sink_info_cie.future2;
+
+ if (A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ p_result_codec_config) != A2DP_SUCCESS) {
+ goto fail;
+ }
+
+ //
+ // Copy the codec-specific fields if they are not zero
+ //
+ if (codec_user_config_.codec_specific_1 != 0)
+ codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+ if (codec_user_config_.codec_specific_2 != 0)
+ codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+ if (codec_user_config_.codec_specific_3 != 0)
+ codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+ if (codec_user_config_.codec_specific_4 != 0)
+ codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
+
+ // Create a local copy of the peer codec capability/config, and the
+ // result codec config.
+ if (is_capability) {
+ status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_capability_);
+ } else {
+ status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_config_);
+ }
+ CHECK(status == A2DP_SUCCESS);
+ status = A2DP_BuildInfoAptx(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ ota_codec_config_);
+ CHECK(status == A2DP_SUCCESS);
+
+ return true;
+
+fail:
+ // Restore the internal state
+ codec_config_ = saved_codec_config;
+ codec_capability_ = saved_codec_capability;
+ codec_selectable_capability_ = saved_codec_selectable_capability;
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+ memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+ sizeof(ota_codec_peer_config_));
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_encoder.cc
new file mode 100755
index 0000000..4c8554d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_vendor_aptx_encoder"
+
+#include "a2dp_vendor_aptx_encoder.h"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Encoder for aptX Source Codec
+//
+
+//
+// The aptX encoder shared library, and the functions to use
+//
+static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
+static void* aptx_encoder_lib_handle = NULL;
+
+static const char* APTX_ENCODER_INIT_NAME = "aptxbtenc_init";
+typedef int (*tAPTX_ENCODER_INIT)(void* state, short endian);
+
+static const char* APTX_ENCODER_ENCODE_STEREO_NAME = "aptxbtenc_encodestereo";
+typedef int (*tAPTX_ENCODER_ENCODE_STEREO)(void* state, void* pcmL, void* pcmR,
+ void* buffer);
+
+static const char* APTX_ENCODER_SIZEOF_PARAMS_NAME = "SizeofAptxbtenc";
+typedef int (*tAPTX_ENCODER_SIZEOF_PARAMS)(void);
+
+static tAPTX_ENCODER_INIT aptx_encoder_init_func;
+static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func;
+static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func;
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#else
+// no RTP header for aptX classic
+#define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE)
+#endif
+
+#define A2DP_APTX_MAX_PCM_BYTES_PER_READ 1024
+
+typedef struct {
+ uint64_t sleep_time_ns;
+ uint32_t pcm_reads;
+ uint32_t pcm_bytes_per_read;
+ uint32_t aptx_bytes;
+ uint32_t frame_size_counter;
+} tAPTX_FRAMING_PARAMS;
+
+typedef struct {
+ uint64_t session_start_us;
+
+ size_t media_read_total_expected_packets;
+ size_t media_read_total_expected_reads_count;
+ size_t media_read_total_expected_read_bytes;
+
+ size_t media_read_total_dropped_packets;
+ size_t media_read_total_actual_reads_count;
+ size_t media_read_total_actual_read_bytes;
+} a2dp_aptx_encoder_stats_t;
+
+typedef struct {
+ a2dp_source_read_callback_t read_callback;
+ a2dp_source_enqueue_callback_t enqueue_callback;
+
+ bool use_SCMS_T;
+ bool is_peer_edr; // True if the peer device supports EDR
+ bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
+ uint16_t peer_mtu; // MTU of the A2DP peer
+ uint32_t timestamp; // Timestamp for the A2DP frames
+
+ tA2DP_FEEDING_PARAMS feeding_params;
+ tAPTX_FRAMING_PARAMS framing_params;
+ void* aptx_encoder_state;
+ a2dp_aptx_encoder_stats_t stats;
+} tA2DP_APTX_ENCODER_CB;
+
+static tA2DP_APTX_ENCODER_CB a2dp_aptx_encoder_cb;
+
+static void a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated);
+static void aptx_init_framing_params(tAPTX_FRAMING_PARAMS* framing_params);
+static void aptx_update_framing_params(tAPTX_FRAMING_PARAMS* framing_params);
+static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params,
+ size_t* data_out_index, uint16_t* data16_in,
+ uint8_t* data_out);
+
+bool A2DP_VendorLoadEncoderAptx(void) {
+ if (aptx_encoder_lib_handle != NULL) return true; // Already loaded
+
+ // Open the encoder library
+ aptx_encoder_lib_handle = dlopen(APTX_ENCODER_LIB_NAME, RTLD_NOW);
+ if (aptx_encoder_lib_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: cannot open aptX encoder library %s: %s", __func__,
+ APTX_ENCODER_LIB_NAME, dlerror());
+ return false;
+ }
+
+ aptx_encoder_init_func = (tAPTX_ENCODER_INIT)dlsym(aptx_encoder_lib_handle,
+ APTX_ENCODER_INIT_NAME);
+ if (aptx_encoder_init_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_ENCODER_INIT_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptx();
+ return false;
+ }
+
+ aptx_encoder_encode_stereo_func = (tAPTX_ENCODER_ENCODE_STEREO)dlsym(
+ aptx_encoder_lib_handle, APTX_ENCODER_ENCODE_STEREO_NAME);
+ if (aptx_encoder_encode_stereo_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_ENCODER_ENCODE_STEREO_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptx();
+ return false;
+ }
+
+ aptx_encoder_sizeof_params_func = (tAPTX_ENCODER_SIZEOF_PARAMS)dlsym(
+ aptx_encoder_lib_handle, APTX_ENCODER_SIZEOF_PARAMS_NAME);
+ if (aptx_encoder_sizeof_params_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_ENCODER_SIZEOF_PARAMS_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptx();
+ return false;
+ }
+
+ return true;
+}
+
+void A2DP_VendorUnloadEncoderAptx(void) {
+ aptx_encoder_init_func = NULL;
+ aptx_encoder_encode_stereo_func = NULL;
+ aptx_encoder_sizeof_params_func = NULL;
+
+ if (aptx_encoder_lib_handle != NULL) {
+ dlclose(aptx_encoder_lib_handle);
+ aptx_encoder_lib_handle = NULL;
+ }
+}
+
+void a2dp_vendor_aptx_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback) {
+ memset(&a2dp_aptx_encoder_cb, 0, sizeof(a2dp_aptx_encoder_cb));
+
+ a2dp_aptx_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+ a2dp_aptx_encoder_cb.read_callback = read_callback;
+ a2dp_aptx_encoder_cb.enqueue_callback = enqueue_callback;
+ a2dp_aptx_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aptx_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_aptx_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aptx_encoder_cb.timestamp = 0;
+
+ /* aptX encoder config */
+ a2dp_aptx_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ a2dp_aptx_encoder_cb.use_SCMS_T = true;
+#endif
+
+ a2dp_aptx_encoder_cb.aptx_encoder_state =
+ osi_malloc(aptx_encoder_sizeof_params_func());
+ if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) {
+ aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
+ } else {
+ LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__);
+ // TODO: Return an error?
+ }
+
+ // NOTE: Ignore the restart_input / restart_output flags - this initization
+ // happens when the connection is (re)started.
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ a2dp_vendor_aptx_encoder_update(a2dp_aptx_encoder_cb.peer_mtu,
+ a2dp_codec_config, &restart_input,
+ &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigAptx::updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ a2dp_aptx_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aptx_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_aptx_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aptx_encoder_cb.timestamp = 0;
+
+ if (a2dp_aptx_encoder_cb.peer_mtu == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid peer MTU",
+ __func__, name().c_str());
+ return false;
+ }
+
+ a2dp_vendor_aptx_encoder_update(a2dp_aptx_encoder_cb.peer_mtu, this,
+ p_restart_input, p_restart_output,
+ p_config_updated);
+ return true;
+}
+
+// Update the A2DP aptX encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_vendor_aptx_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated) {
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+ if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid codec config",
+ __func__, a2dp_codec_config->name().c_str());
+ return;
+ }
+ const uint8_t* p_codec_info = codec_info;
+
+ // The feeding parameters
+ tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_aptx_encoder_cb.feeding_params;
+ p_feeding_params->sample_rate =
+ A2DP_VendorGetTrackSampleRateAptx(p_codec_info);
+ p_feeding_params->bits_per_sample =
+ A2DP_VendorGetTrackBitsPerSampleAptx(p_codec_info);
+ p_feeding_params->channel_count =
+ A2DP_VendorGetTrackChannelCountAptx(p_codec_info);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+ __func__, p_feeding_params->sample_rate,
+ p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+ aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
+}
+
+void a2dp_vendor_aptx_encoder_cleanup(void) {
+ osi_free(a2dp_aptx_encoder_cb.aptx_encoder_state);
+ memset(&a2dp_aptx_encoder_cb, 0, sizeof(a2dp_aptx_encoder_cb));
+}
+
+//
+// Initialize the framing parameters, and set those that don't change
+// while streaming (e.g., 'sleep_time_ns').
+//
+static void aptx_init_framing_params(tAPTX_FRAMING_PARAMS* framing_params) {
+ framing_params->sleep_time_ns = 0;
+ framing_params->pcm_reads = 0;
+ framing_params->pcm_bytes_per_read = 0;
+ framing_params->aptx_bytes = 0;
+ framing_params->frame_size_counter = 0;
+
+ if (a2dp_aptx_encoder_cb.feeding_params.sample_rate == 48000) {
+ if (a2dp_aptx_encoder_cb.use_SCMS_T) {
+ framing_params->sleep_time_ns = 13000000;
+ } else {
+ framing_params->sleep_time_ns = 14000000;
+ }
+ } else {
+ // Assume the sample rate is 44100
+ if (a2dp_aptx_encoder_cb.use_SCMS_T) {
+ framing_params->sleep_time_ns = 14000000;
+ } else {
+ framing_params->sleep_time_ns = 15000000;
+ }
+ }
+
+ LOG_DEBUG(LOG_TAG, "%s: sleep_time_ns = %" PRIu64, __func__,
+ framing_params->sleep_time_ns);
+}
+
+//
+// Set frame size and transmission interval needed to stream the required
+// sample rate using 2-DH5 packets for aptX and 2-DH3 packets for aptX-LL.
+// With SCMS-T enabled we need to reserve room for extra headers added later.
+// Packets are always sent at equals time intervals but to achieve the
+// required sample rate, the frame size needs to change on occasion.
+//
+// Also need to specify how many of the required PCM samples are read at a
+// time:
+// aptx_bytes = pcm_reads * pcm_bytes_per_read / 4
+// and
+// number of aptX samples produced = pcm_bytes_per_read / 16
+//
+static void aptx_update_framing_params(tAPTX_FRAMING_PARAMS* framing_params) {
+ if (a2dp_aptx_encoder_cb.feeding_params.sample_rate == 48000) {
+ if (a2dp_aptx_encoder_cb.use_SCMS_T) {
+ framing_params->aptx_bytes = 624;
+ framing_params->pcm_bytes_per_read = 208;
+ framing_params->pcm_reads = 12;
+ } else {
+ framing_params->aptx_bytes = 672;
+ framing_params->pcm_bytes_per_read = 224;
+ framing_params->pcm_reads = 12;
+ }
+ } else {
+ // Assume the sample rate is 44100
+ if (a2dp_aptx_encoder_cb.use_SCMS_T) {
+ if (++framing_params->frame_size_counter < 20) {
+ framing_params->aptx_bytes = 616;
+ framing_params->pcm_bytes_per_read = 224;
+ framing_params->pcm_reads = 11;
+ } else {
+ framing_params->aptx_bytes = 644;
+ framing_params->pcm_bytes_per_read = 368;
+ framing_params->pcm_reads = 7;
+ framing_params->frame_size_counter = 0;
+ }
+ } else {
+ if (++framing_params->frame_size_counter < 8) {
+ framing_params->aptx_bytes = 660;
+ framing_params->pcm_bytes_per_read = 240;
+ framing_params->pcm_reads = 11;
+ } else {
+ framing_params->aptx_bytes = 672;
+ framing_params->pcm_bytes_per_read = 224;
+ framing_params->pcm_reads = 12;
+ framing_params->frame_size_counter = 0;
+ }
+ }
+ }
+
+ LOG_VERBOSE(LOG_TAG,
+ "%s: sleep_time_ns = %" PRIu64
+ " aptx_bytes = %u "
+ "pcm_bytes_per_read = %u pcm_reads = %u frame_size_counter = %u",
+ __func__, framing_params->sleep_time_ns,
+ framing_params->aptx_bytes, framing_params->pcm_bytes_per_read,
+ framing_params->pcm_reads, framing_params->frame_size_counter);
+}
+
+void a2dp_vendor_aptx_feeding_reset(void) {
+ aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
+}
+
+void a2dp_vendor_aptx_feeding_flush(void) {
+ aptx_init_framing_params(&a2dp_aptx_encoder_cb.framing_params);
+}
+
+period_ms_t a2dp_vendor_aptx_get_encoder_interval_ms(void) {
+ return a2dp_aptx_encoder_cb.framing_params.sleep_time_ns / (1000 * 1000);
+}
+
+void a2dp_vendor_aptx_send_frames(uint64_t timestamp_us) {
+ tAPTX_FRAMING_PARAMS* framing_params = &a2dp_aptx_encoder_cb.framing_params;
+
+ // Prepare the packet to send
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ p_buf->offset = A2DP_APTX_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ uint8_t* encoded_ptr = (uint8_t*)(p_buf + 1);
+ encoded_ptr += p_buf->offset;
+
+ aptx_update_framing_params(framing_params);
+
+ //
+ // Read the PCM data and encode it
+ //
+ LOG_VERBOSE(LOG_TAG, "%s: %u PCM reads of size %u", __func__,
+ framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
+ size_t encoded_ptr_index = 0;
+ size_t pcm_bytes_encoded = 0;
+ a2dp_aptx_encoder_cb.stats.media_read_total_expected_packets++;
+ a2dp_aptx_encoder_cb.stats.media_read_total_expected_reads_count +=
+ framing_params->pcm_reads;
+ a2dp_aptx_encoder_cb.stats.media_read_total_expected_read_bytes +=
+ framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
+ for (size_t reads = 0; reads < framing_params->pcm_reads; reads++) {
+ uint16_t read_buffer16[A2DP_APTX_MAX_PCM_BYTES_PER_READ / sizeof(uint16_t)];
+ size_t pcm_bytes_read = a2dp_aptx_encoder_cb.read_callback(
+ (uint8_t*)read_buffer16, framing_params->pcm_bytes_per_read);
+ a2dp_aptx_encoder_cb.stats.media_read_total_actual_read_bytes +=
+ pcm_bytes_read;
+ if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
+ LOG_WARN(LOG_TAG,
+ "%s: underflow at PCM reading iteration %zu: read %zu "
+ "instead of %d",
+ __func__, reads, pcm_bytes_read,
+ framing_params->pcm_bytes_per_read);
+ break;
+ }
+ a2dp_aptx_encoder_cb.stats.media_read_total_actual_reads_count++;
+ pcm_bytes_encoded += aptx_encode_16bit(framing_params, &encoded_ptr_index,
+ read_buffer16, encoded_ptr);
+ }
+
+ // Compute the number of encoded bytes
+ const int COMPRESSION_RATIO = 4;
+ size_t encoded_bytes = pcm_bytes_encoded / COMPRESSION_RATIO;
+ p_buf->len += encoded_bytes;
+ LOG_VERBOSE(LOG_TAG, "%s: encoded %zu PCM bytes to %zu", __func__,
+ pcm_bytes_encoded, encoded_bytes);
+
+ // Update the RTP timestamp
+ *((uint32_t*)(p_buf + 1)) = a2dp_aptx_encoder_cb.timestamp;
+ const uint8_t BYTES_PER_FRAME = 2;
+ uint32_t rtp_timestamp =
+ (pcm_bytes_encoded / a2dp_aptx_encoder_cb.feeding_params.channel_count) /
+ BYTES_PER_FRAME;
+ a2dp_aptx_encoder_cb.timestamp += rtp_timestamp;
+
+ if (p_buf->len > 0) {
+ a2dp_aptx_encoder_cb.enqueue_callback(p_buf, 1);
+ } else {
+ a2dp_aptx_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ }
+}
+
+static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params,
+ size_t* data_out_index, uint16_t* data16_in,
+ uint8_t* data_out) {
+ size_t pcm_bytes_encoded = 0;
+ size_t frame = 0;
+
+ for (size_t aptx_samples = 0;
+ aptx_samples < framing_params->pcm_bytes_per_read / 16; aptx_samples++) {
+ uint32_t pcmL[4];
+ uint32_t pcmR[4];
+ uint16_t encoded_sample[2];
+
+ for (size_t i = 0, j = frame; i < 4; i++, j++) {
+ pcmL[i] = (uint16_t) * (data16_in + (2 * j));
+ pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1));
+ }
+
+ aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state,
+ &pcmL, &pcmR, &encoded_sample);
+
+ data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff);
+ data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff);
+ data_out[*data_out_index + 2] = (uint8_t)((encoded_sample[1] >> 8) & 0xff);
+ data_out[*data_out_index + 3] = (uint8_t)((encoded_sample[1] >> 0) & 0xff);
+
+ frame += 4;
+ pcm_bytes_encoded += 16;
+ *data_out_index += 4;
+ }
+
+ return pcm_bytes_encoded;
+}
+
+period_ms_t A2dpCodecConfigAptx::encoderIntervalMs() const {
+ return a2dp_vendor_aptx_get_encoder_interval_ms();
+}
+
+void A2dpCodecConfigAptx::debug_codec_dump(int fd) {
+ a2dp_aptx_encoder_stats_t* stats = &a2dp_aptx_encoder_cb.stats;
+
+ A2dpCodecConfig::debug_codec_dump(fd);
+
+ dprintf(fd,
+ " Packet counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_packets,
+ stats->media_read_total_dropped_packets);
+
+ dprintf(fd,
+ " PCM read counts (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_reads_count,
+ stats->media_read_total_actual_reads_count);
+
+ dprintf(fd,
+ " PCM read bytes (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_read_bytes,
+ stats->media_read_total_actual_read_bytes);
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd.cc
new file mode 100755
index 0000000..919aef1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd.cc
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse the aptX-HD Codec Information
+ * Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_vendor_aptx_hd"
+
+#include "bt_target.h"
+
+#include "a2dp_vendor_aptx_hd.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx_hd_encoder.h"
+#include "bt_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+// data type for the aptX-HD Codec Information Element */
+typedef struct {
+ uint32_t vendorId;
+ uint16_t codecId; /* Codec ID for aptX-HD */
+ uint8_t sampleRate; /* Sampling Frequency */
+ uint8_t channelMode; /* STEREO/DUAL/MONO */
+ uint8_t acl_sprint_reserved0;
+ uint8_t acl_sprint_reserved1;
+ uint8_t acl_sprint_reserved2;
+ uint8_t acl_sprint_reserved3;
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_APTX_HD_CIE;
+
+/* aptX-HD Source codec capabilities */
+static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_caps = {
+ A2DP_APTX_HD_VENDOR_ID, /* vendorId */
+ A2DP_APTX_HD_CODEC_ID_BLUETOOTH, /* codecId */
+ (A2DP_APTX_HD_SAMPLERATE_44100 |
+ A2DP_APTX_HD_SAMPLERATE_48000), /* sampleRate */
+ A2DP_APTX_HD_CHANNELS_STEREO, /* channelMode */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED0, /* acl_sprint_reserved0 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED1, /* acl_sprint_reserved1 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED2, /* acl_sprint_reserved2 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED3, /* acl_sprint_reserved3 */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 /* bits_per_sample */
+};
+
+/* Default aptX-HD codec configuration */
+static const tA2DP_APTX_HD_CIE a2dp_aptx_hd_default_config = {
+ A2DP_APTX_HD_VENDOR_ID, /* vendorId */
+ A2DP_APTX_HD_CODEC_ID_BLUETOOTH, /* codecId */
+ A2DP_APTX_HD_SAMPLERATE_44100, /* sampleRate */
+ A2DP_APTX_HD_CHANNELS_STEREO, /* channelMode */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED0, /* acl_sprint_reserved0 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED1, /* acl_sprint_reserved1 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED2, /* acl_sprint_reserved2 */
+ A2DP_APTX_HD_ACL_SPRINT_RESERVED3, /* acl_sprint_reserved3 */
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 /* bits_per_sample */
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_aptx_hd = {
+ a2dp_vendor_aptx_hd_encoder_init,
+ a2dp_vendor_aptx_hd_encoder_cleanup,
+ a2dp_vendor_aptx_hd_feeding_reset,
+ a2dp_vendor_aptx_hd_feeding_flush,
+ a2dp_vendor_aptx_hd_get_encoder_interval_ms,
+ a2dp_vendor_aptx_hd_send_frames,
+ nullptr // set_transmit_queue_length
+};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAptxHd(
+ const tA2DP_APTX_HD_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_peer_codec_info);
+
+// Builds the aptX-HD Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the aptX-HD Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoAptxHd(uint8_t media_type,
+ const tA2DP_APTX_HD_CIE* p_ie,
+ uint8_t* p_result) {
+ if (p_ie == NULL || p_result == NULL) {
+ return A2DP_INVALID_PARAMS;
+ }
+
+ *p_result++ = A2DP_APTX_HD_CODEC_LEN;
+ *p_result++ = (media_type << 4);
+ *p_result++ = A2DP_MEDIA_CT_NON_A2DP;
+ *p_result++ = (uint8_t)(p_ie->vendorId & 0x000000FF);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x0000FF00) >> 8);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x00FF0000) >> 16);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0xFF000000) >> 24);
+ *p_result++ = (uint8_t)(p_ie->codecId & 0x00FF);
+ *p_result++ = (uint8_t)((p_ie->codecId & 0xFF00) >> 8);
+ *p_result++ = p_ie->sampleRate | p_ie->channelMode;
+ *p_result++ = p_ie->acl_sprint_reserved0;
+ *p_result++ = p_ie->acl_sprint_reserved1;
+ *p_result++ = p_ie->acl_sprint_reserved2;
+ *p_result++ = p_ie->acl_sprint_reserved3;
+
+ return A2DP_SUCCESS;
+}
+
+// Parses the aptX-HD Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence is
+// codec capabilities, otherwise is codec configuration.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoAptxHd(tA2DP_APTX_HD_CIE* p_ie,
+ const uint8_t* p_codec_info,
+ bool is_capability) {
+ uint8_t losc;
+ uint8_t media_type;
+ tA2DP_CODEC_TYPE codec_type;
+
+ if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+ // Check the codec capability length
+ losc = *p_codec_info++;
+ if (losc != A2DP_APTX_HD_CODEC_LEN) return A2DP_WRONG_CODEC;
+
+ media_type = (*p_codec_info++) >> 4;
+ codec_type = *p_codec_info++;
+ /* Check the Media Type and Media Codec Type */
+ if (media_type != AVDT_MEDIA_TYPE_AUDIO ||
+ codec_type != A2DP_MEDIA_CT_NON_A2DP) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ // Check the Vendor ID and Codec ID */
+ p_ie->vendorId = (*p_codec_info & 0x000000FF) |
+ (*(p_codec_info + 1) << 8 & 0x0000FF00) |
+ (*(p_codec_info + 2) << 16 & 0x00FF0000) |
+ (*(p_codec_info + 3) << 24 & 0xFF000000);
+ p_codec_info += 4;
+ p_ie->codecId =
+ (*p_codec_info & 0x00FF) | (*(p_codec_info + 1) << 8 & 0xFF00);
+ p_codec_info += 2;
+ if (p_ie->vendorId != A2DP_APTX_HD_VENDOR_ID ||
+ p_ie->codecId != A2DP_APTX_HD_CODEC_ID_BLUETOOTH) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ p_ie->channelMode = *p_codec_info & 0x0F;
+ p_ie->sampleRate = *p_codec_info & 0xF0;
+ p_codec_info++;
+
+ p_ie->acl_sprint_reserved0 = *(p_codec_info++);
+ p_ie->acl_sprint_reserved1 = *(p_codec_info++);
+ p_ie->acl_sprint_reserved2 = *(p_codec_info++);
+ p_ie->acl_sprint_reserved3 = *(p_codec_info++);
+
+ if (is_capability) return A2DP_SUCCESS;
+
+ if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_IsVendorSourceCodecValidAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, false) ==
+ A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSinkCodecValidAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, false) ==
+ A2DP_SUCCESS) ||
+ (A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+// Checks whether A2DP aptX-HD codec configuration matches with a device's
+// codec capabilities. |p_cap| is the aptX-HD codec configuration.
+// |p_codec_info| is the device's codec capabilities.
+// If |is_capability| is true, the byte sequence is codec capabilities,
+// otherwise is codec configuration.
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityAptxHd(
+ const tA2DP_APTX_HD_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability) {
+ tA2DP_STATUS status;
+ tA2DP_APTX_HD_CIE cfg_cie;
+
+ /* parse configuration */
+ status = A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ LOG_DEBUG(LOG_TAG, "%s: FREQ peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.sampleRate, p_cap->sampleRate);
+ LOG_DEBUG(LOG_TAG, "%s: CH_MODE peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.channelMode, p_cap->channelMode);
+
+ /* sampling frequency */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_NS_SAMP_FREQ;
+
+ /* channel mode */
+ if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_VendorUsesRtpHeaderAptxHd(UNUSED_ATTR bool content_protection_enabled,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return true;
+}
+
+const char* A2DP_VendorCodecNameAptxHd(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return "aptX-HD";
+}
+
+bool A2DP_VendorCodecTypeEqualsAptxHd(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie_a;
+ tA2DP_APTX_HD_CIE aptx_hd_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAptxHd(&aptx_hd_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2DP_VendorCodecEqualsAptxHd(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie_a;
+ tA2DP_APTX_HD_CIE aptx_hd_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoAptxHd(&aptx_hd_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return (aptx_hd_cie_a.sampleRate == aptx_hd_cie_b.sampleRate) &&
+ (aptx_hd_cie_a.channelMode == aptx_hd_cie_b.channelMode);
+}
+
+int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ if (aptx_hd_cie.sampleRate == A2DP_APTX_HD_SAMPLERATE_44100) return 44100;
+ if (aptx_hd_cie.sampleRate == A2DP_APTX_HD_SAMPLERATE_48000) return 48000;
+
+ return -1;
+}
+
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ return 24; // For aptX-HD we always use 24 bits per audio sample
+}
+
+int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (aptx_hd_cie.channelMode) {
+ case A2DP_APTX_HD_CHANNELS_MONO:
+ return 1;
+ case A2DP_APTX_HD_CHANNELS_STEREO:
+ return 2;
+ }
+
+ return -1;
+}
+
+bool A2DP_VendorGetPacketTimestampAptxHd(
+ UNUSED_ATTR const uint8_t* p_codec_info, const uint8_t* p_data,
+ uint32_t* p_timestamp) {
+ // TODO: Is this function really codec-specific?
+ *p_timestamp = *(const uint32_t*)p_data;
+ return true;
+}
+
+bool A2DP_VendorBuildCodecHeaderAptxHd(UNUSED_ATTR const uint8_t* p_codec_info,
+ UNUSED_ATTR BT_HDR* p_buf,
+ UNUSED_ATTR uint16_t frames_per_packet) {
+ // Nothing to do
+ return true;
+}
+
+void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info) {
+ tA2DP_STATUS a2dp_status;
+ tA2DP_APTX_HD_CIE aptx_hd_cie;
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+ a2dp_status = A2DP_ParseInfoAptxHd(&aptx_hd_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoAptxHd fail:%d", __func__,
+ a2dp_status);
+ return;
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", aptx_hd_cie.sampleRate);
+ if (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+ }
+ if (aptx_hd_cie.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", aptx_hd_cie.channelMode);
+ if (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+ }
+ if (aptx_hd_cie.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+ }
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptxHd(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsVendorSourceCodecValidAptxHd(p_codec_info)) return NULL;
+
+ return &a2dp_encoder_interface_aptx_hd;
+}
+
+bool A2DP_VendorAdjustCodecAptxHd(uint8_t* p_codec_info) {
+ tA2DP_APTX_HD_CIE cfg_cie;
+
+ // Nothing to do: just verify the codec info is valid
+ if (A2DP_ParseInfoAptxHd(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+ return false;
+
+ return true;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptxHd(
+ const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD;
+}
+
+const char* A2DP_VendorCodecIndexStrAptxHd(void) { return "aptX-HD"; }
+
+bool A2DP_VendorInitCodecConfigAptxHd(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &a2dp_aptx_hd_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Content protection info - support SCMS-T */
+ uint8_t* p = p_cfg->protect_info;
+ *p++ = AVDT_CP_LOSC;
+ UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+ p_cfg->num_protect = 1;
+#endif
+
+ return true;
+}
+
+A2dpCodecConfigAptxHd::A2dpCodecConfigAptxHd(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD, "aptX-HD",
+ codec_priority) {
+ // Compute the local capability
+ if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (a2dp_aptx_hd_caps.sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ codec_local_capability_.bits_per_sample = a2dp_aptx_hd_caps.bits_per_sample;
+ if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (a2dp_aptx_hd_caps.channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigAptxHd::~A2dpCodecConfigAptxHd() {}
+
+bool A2dpCodecConfigAptxHd::init() {
+ if (!isValid()) return false;
+
+ // Load the encoder
+ if (!A2DP_VendorLoadEncoderAptxHd()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecConfigAptxHd::useRtpHeaderMarkerBit() const { return false; }
+
+//
+// Selects the best sample rate from |sampleRate|.
+// The result is stored in |p_result| and p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint8_t sampleRate,
+ tA2DP_APTX_HD_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ p_result->sampleRate = A2DP_APTX_HD_SAMPLERATE_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ p_result->sampleRate = A2DP_APTX_HD_SAMPLERATE_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |sampleRate| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t sampleRate,
+ tA2DP_APTX_HD_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ p_result->sampleRate = A2DP_APTX_HD_SAMPLERATE_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ p_result->sampleRate = A2DP_APTX_HD_SAMPLERATE_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best bits per sample.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+ btav_a2dp_codec_config_t* p_codec_config) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// The result is stored in |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+ const btav_a2dp_codec_config_t* p_codec_audio_config,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best channel mode from |channelMode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t channelMode,
+ tA2DP_APTX_HD_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ p_result->channelMode = A2DP_APTX_HD_CHANNELS_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ p_result->channelMode = A2DP_APTX_HD_CHANNELS_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |channelMode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t channelMode,
+ tA2DP_APTX_HD_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ p_result->channelMode = A2DP_APTX_HD_CHANNELS_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ p_result->channelMode = A2DP_APTX_HD_CHANNELS_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+bool A2dpCodecConfigAptxHd::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ tA2DP_APTX_HD_CIE sink_info_cie;
+ tA2DP_APTX_HD_CIE result_config_cie;
+ uint8_t sampleRate;
+ uint8_t channelMode;
+
+ // Save the internal state
+ btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+ btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+ btav_a2dp_codec_config_t saved_codec_selectable_capability =
+ codec_selectable_capability_;
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+ memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+ sizeof(ota_codec_peer_config_));
+
+ tA2DP_STATUS status =
+ A2DP_ParseInfoAptxHd(&sink_info_cie, p_peer_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+ __func__, status);
+ goto fail;
+ }
+
+ //
+ // Build the preferred configuration
+ //
+ memset(&result_config_cie, 0, sizeof(result_config_cie));
+ result_config_cie.vendorId = a2dp_aptx_hd_caps.vendorId;
+ result_config_cie.codecId = a2dp_aptx_hd_caps.codecId;
+
+ //
+ // Select the sample frequency
+ //
+ sampleRate = a2dp_aptx_hd_caps.sampleRate & sink_info_cie.sampleRate;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ switch (codec_user_config_.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ result_config_cie.sampleRate = A2DP_APTX_HD_SAMPLERATE_44100;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ result_config_cie.sampleRate = A2DP_APTX_HD_SAMPLERATE_48000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ break;
+ }
+
+ // Select the sample frequency if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+
+ if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+ // Compute the common capability
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_44100)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (sampleRate & A2DP_APTX_HD_SAMPLERATE_48000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+
+ // No user preference - try the codec audio config
+ if (select_audio_sample_rate(&codec_audio_config_, sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_sample_rate(
+ a2dp_aptx_hd_default_config.sampleRate & sink_info_cie.sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_sample_rate(sampleRate, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match sample frequency: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aptx_hd_caps.sampleRate, sink_info_cie.sampleRate);
+ goto fail;
+ }
+
+ //
+ // Select the bits per sample
+ //
+ // NOTE: this information is NOT included in the aptX-HD A2DP codec
+ // description that is sent OTA.
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ switch (codec_user_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ break;
+ }
+
+ // Select the bits per sample if there is no user preference
+ do {
+ // Compute the selectable capability
+ codec_selectable_capability_.bits_per_sample =
+ a2dp_aptx_hd_caps.bits_per_sample;
+
+ if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+ break;
+
+ // Compute the common capability
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+
+ // No user preference - try the codec audio config
+ if (select_audio_bits_per_sample(&codec_audio_config_, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ // NOTE: no-op - kept here for consistency
+ if (select_best_bits_per_sample(&codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match bits per sample: user preference = 0x%x",
+ __func__, codec_user_config_.bits_per_sample);
+ goto fail;
+ }
+
+ //
+ // Select the channel mode
+ //
+ channelMode = a2dp_aptx_hd_caps.channelMode & sink_info_cie.channelMode;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ switch (codec_user_config_.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ result_config_cie.channelMode = A2DP_APTX_HD_CHANNELS_MONO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ result_config_cie.channelMode = A2DP_APTX_HD_CHANNELS_STEREO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ break;
+ }
+
+ // Select the channel mode if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (channelMode & A2DP_APTX_HD_CHANNELS_MONO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+ // Compute the common capability
+ if (channelMode & A2DP_APTX_HD_CHANNELS_MONO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (channelMode & A2DP_APTX_HD_CHANNELS_STEREO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+
+ // No user preference - try the codec audio config
+ if (select_audio_channel_mode(&codec_audio_config_, channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_channel_mode(
+ a2dp_aptx_hd_default_config.channelMode & sink_info_cie.channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_channel_mode(channelMode, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match channel mode: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_aptx_hd_caps.channelMode,
+ sink_info_cie.channelMode);
+ goto fail;
+ }
+
+ //
+ // Set the rest of the fields as bit-wise AND operation
+ //
+ result_config_cie.acl_sprint_reserved0 =
+ a2dp_aptx_hd_caps.acl_sprint_reserved0 &
+ sink_info_cie.acl_sprint_reserved0;
+ result_config_cie.acl_sprint_reserved1 =
+ a2dp_aptx_hd_caps.acl_sprint_reserved1 &
+ sink_info_cie.acl_sprint_reserved1;
+ result_config_cie.acl_sprint_reserved2 =
+ a2dp_aptx_hd_caps.acl_sprint_reserved2 &
+ sink_info_cie.acl_sprint_reserved2;
+ result_config_cie.acl_sprint_reserved3 =
+ a2dp_aptx_hd_caps.acl_sprint_reserved3 &
+ sink_info_cie.acl_sprint_reserved3;
+
+ if (A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ p_result_codec_config) != A2DP_SUCCESS) {
+ goto fail;
+ }
+
+ //
+ // Copy the codec-specific fields if they are not zero
+ //
+ if (codec_user_config_.codec_specific_1 != 0)
+ codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+ if (codec_user_config_.codec_specific_2 != 0)
+ codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+ if (codec_user_config_.codec_specific_3 != 0)
+ codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+ if (codec_user_config_.codec_specific_4 != 0)
+ codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
+
+ // Create a local copy of the peer codec capability/config, and the
+ // result codec config.
+ if (is_capability) {
+ status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_capability_);
+ } else {
+ status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_config_);
+ }
+ CHECK(status == A2DP_SUCCESS);
+ status = A2DP_BuildInfoAptxHd(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ ota_codec_config_);
+ CHECK(status == A2DP_SUCCESS);
+ return true;
+
+fail:
+ // Restore the internal state
+ codec_config_ = saved_codec_config;
+ codec_capability_ = saved_codec_capability;
+ codec_selectable_capability_ = saved_codec_selectable_capability;
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+ memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+ sizeof(ota_codec_peer_config_));
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
new file mode 100755
index 0000000..d35d872
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_vendor_aptx_hd_encoder"
+
+#include "a2dp_vendor_aptx_hd_encoder.h"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_aptx_hd.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Encoder for aptX-HD Source Codec
+//
+
+//
+// The aptX-HD encoder shared library, and the functions to use
+//
+static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
+static void* aptx_hd_encoder_lib_handle = NULL;
+
+static const char* APTX_HD_ENCODER_INIT_NAME = "aptxhdbtenc_init";
+typedef int (*tAPTX_HD_ENCODER_INIT)(void* state, short endian);
+
+static const char* APTX_HD_ENCODER_ENCODE_STEREO_NAME =
+ "aptxhdbtenc_encodestereo";
+typedef int (*tAPTX_HD_ENCODER_ENCODE_STEREO)(void* state, void* pcmL,
+ void* pcmR, void* buffer);
+
+static const char* APTX_HD_ENCODER_SIZEOF_PARAMS_NAME = "SizeofAptxhdbtenc";
+typedef int (*tAPTX_HD_ENCODER_SIZEOF_PARAMS)(void);
+
+static tAPTX_HD_ENCODER_INIT aptx_hd_encoder_init_func;
+static tAPTX_HD_ENCODER_ENCODE_STEREO aptx_hd_encoder_encode_stereo_func;
+static tAPTX_HD_ENCODER_SIZEOF_PARAMS aptx_hd_encoder_sizeof_params_func;
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1)
+#else
+#define A2DP_APTX_HD_OFFSET AVDT_MEDIA_OFFSET
+#endif
+
+#define A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ 1024
+
+typedef struct {
+ uint64_t sleep_time_ns;
+ uint32_t pcm_reads;
+ uint32_t pcm_bytes_per_read;
+ uint32_t aptx_hd_bytes;
+ uint32_t frame_size_counter;
+} tAPTX_HD_FRAMING_PARAMS;
+
+typedef struct {
+ uint64_t session_start_us;
+
+ size_t media_read_total_expected_packets;
+ size_t media_read_total_expected_reads_count;
+ size_t media_read_total_expected_read_bytes;
+
+ size_t media_read_total_dropped_packets;
+ size_t media_read_total_actual_reads_count;
+ size_t media_read_total_actual_read_bytes;
+} a2dp_aptx_hd_encoder_stats_t;
+
+typedef struct {
+ a2dp_source_read_callback_t read_callback;
+ a2dp_source_enqueue_callback_t enqueue_callback;
+
+ bool use_SCMS_T;
+ bool is_peer_edr; // True if the peer device supports EDR
+ bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
+ uint16_t peer_mtu; // // MTU of the A2DP peer
+ uint32_t timestamp; // Timestamp for the A2DP frames
+
+ tA2DP_FEEDING_PARAMS feeding_params;
+ tAPTX_HD_FRAMING_PARAMS framing_params;
+ void* aptx_hd_encoder_state;
+ a2dp_aptx_hd_encoder_stats_t stats;
+} tA2DP_APTX_HD_ENCODER_CB;
+
+static tA2DP_APTX_HD_ENCODER_CB a2dp_aptx_hd_encoder_cb;
+
+static void a2dp_vendor_aptx_hd_encoder_update(
+ uint16_t peer_mtu, A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input, bool* p_restart_output, bool* p_config_updated);
+static void aptx_hd_init_framing_params(
+ tAPTX_HD_FRAMING_PARAMS* framing_params);
+static void aptx_hd_update_framing_params(
+ tAPTX_HD_FRAMING_PARAMS* framing_params);
+static size_t aptx_hd_encode_24bit(tAPTX_HD_FRAMING_PARAMS* framing_params,
+ size_t* data_out_index, uint32_t* data32_in,
+ uint8_t* data_out);
+
+bool A2DP_VendorLoadEncoderAptxHd(void) {
+ if (aptx_hd_encoder_lib_handle != NULL) return true; // Already loaded
+
+ // Open the encoder library
+ aptx_hd_encoder_lib_handle = dlopen(APTX_HD_ENCODER_LIB_NAME, RTLD_NOW);
+ if (aptx_hd_encoder_lib_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: cannot open aptX-HD encoder library %s: %s",
+ __func__, APTX_HD_ENCODER_LIB_NAME, dlerror());
+ return false;
+ }
+
+ aptx_hd_encoder_init_func = (tAPTX_HD_ENCODER_INIT)dlsym(
+ aptx_hd_encoder_lib_handle, APTX_HD_ENCODER_INIT_NAME);
+ if (aptx_hd_encoder_init_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_HD_ENCODER_INIT_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptxHd();
+ return false;
+ }
+
+ aptx_hd_encoder_encode_stereo_func = (tAPTX_HD_ENCODER_ENCODE_STEREO)dlsym(
+ aptx_hd_encoder_lib_handle, APTX_HD_ENCODER_ENCODE_STEREO_NAME);
+ if (aptx_hd_encoder_encode_stereo_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_HD_ENCODER_ENCODE_STEREO_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptxHd();
+ return false;
+ }
+
+ aptx_hd_encoder_sizeof_params_func = (tAPTX_HD_ENCODER_SIZEOF_PARAMS)dlsym(
+ aptx_hd_encoder_lib_handle, APTX_HD_ENCODER_SIZEOF_PARAMS_NAME);
+ if (aptx_hd_encoder_sizeof_params_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, APTX_HD_ENCODER_SIZEOF_PARAMS_NAME, dlerror());
+ A2DP_VendorUnloadEncoderAptxHd();
+ return false;
+ }
+
+ return true;
+}
+
+void A2DP_VendorUnloadEncoderAptxHd(void) {
+ aptx_hd_encoder_init_func = NULL;
+ aptx_hd_encoder_encode_stereo_func = NULL;
+ aptx_hd_encoder_sizeof_params_func = NULL;
+
+ if (aptx_hd_encoder_lib_handle != NULL) {
+ dlclose(aptx_hd_encoder_lib_handle);
+ aptx_hd_encoder_lib_handle = NULL;
+ }
+}
+
+void a2dp_vendor_aptx_hd_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback) {
+ memset(&a2dp_aptx_hd_encoder_cb, 0, sizeof(a2dp_aptx_hd_encoder_cb));
+
+ a2dp_aptx_hd_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+ a2dp_aptx_hd_encoder_cb.read_callback = read_callback;
+ a2dp_aptx_hd_encoder_cb.enqueue_callback = enqueue_callback;
+ a2dp_aptx_hd_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aptx_hd_encoder_cb.peer_supports_3mbps =
+ p_peer_params->peer_supports_3mbps;
+ a2dp_aptx_hd_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aptx_hd_encoder_cb.timestamp = 0;
+
+ /* aptX-HD encoder config */
+ a2dp_aptx_hd_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ a2dp_aptx_hd_encoder_cb.use_SCMS_T = true;
+#endif
+
+ a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state =
+ osi_malloc(aptx_hd_encoder_sizeof_params_func());
+ if (a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state != NULL) {
+ aptx_hd_encoder_init_func(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
+ } else {
+ LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX-HD encoder state", __func__);
+ // TODO: Return an error?
+ }
+
+ // NOTE: Ignore the restart_input / restart_output flags - this initization
+ // happens when the connection is (re)started.
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ a2dp_vendor_aptx_hd_encoder_update(a2dp_aptx_hd_encoder_cb.peer_mtu,
+ a2dp_codec_config, &restart_input,
+ &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigAptxHd::updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ a2dp_aptx_hd_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_aptx_hd_encoder_cb.peer_supports_3mbps =
+ p_peer_params->peer_supports_3mbps;
+ a2dp_aptx_hd_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_aptx_hd_encoder_cb.timestamp = 0;
+
+ if (a2dp_aptx_hd_encoder_cb.peer_mtu == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid peer MTU",
+ __func__, name().c_str());
+ return false;
+ }
+
+ a2dp_vendor_aptx_hd_encoder_update(a2dp_aptx_hd_encoder_cb.peer_mtu, this,
+ p_restart_input, p_restart_output,
+ p_config_updated);
+ return true;
+}
+
+// Update the A2DP aptX-HD encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_vendor_aptx_hd_encoder_update(
+ uint16_t peer_mtu, A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input, bool* p_restart_output, bool* p_config_updated) {
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+ if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid codec config",
+ __func__, a2dp_codec_config->name().c_str());
+ return;
+ }
+ const uint8_t* p_codec_info = codec_info;
+
+ // The feeding parameters
+ tA2DP_FEEDING_PARAMS* p_feeding_params =
+ &a2dp_aptx_hd_encoder_cb.feeding_params;
+ p_feeding_params->sample_rate =
+ A2DP_VendorGetTrackSampleRateAptxHd(p_codec_info);
+ p_feeding_params->bits_per_sample =
+ A2DP_VendorGetTrackBitsPerSampleAptxHd(p_codec_info);
+ p_feeding_params->channel_count =
+ A2DP_VendorGetTrackChannelCountAptxHd(p_codec_info);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+ __func__, p_feeding_params->sample_rate,
+ p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+ aptx_hd_init_framing_params(&a2dp_aptx_hd_encoder_cb.framing_params);
+}
+
+void a2dp_vendor_aptx_hd_encoder_cleanup(void) {
+ osi_free(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state);
+ memset(&a2dp_aptx_hd_encoder_cb, 0, sizeof(a2dp_aptx_hd_encoder_cb));
+}
+
+//
+// Initialize the framing parameters, and set those that don't change
+// while streaming (e.g., 'sleep_time_ns').
+//
+static void aptx_hd_init_framing_params(
+ tAPTX_HD_FRAMING_PARAMS* framing_params) {
+ framing_params->sleep_time_ns = 0;
+ framing_params->pcm_reads = 0;
+ framing_params->pcm_bytes_per_read = 0;
+ framing_params->aptx_hd_bytes = 0;
+ framing_params->frame_size_counter = 0;
+
+ framing_params->sleep_time_ns = 9000000;
+
+ LOG_DEBUG(LOG_TAG, "%s: sleep_time_ns = %" PRIu64, __func__,
+ framing_params->sleep_time_ns);
+}
+
+//
+// Set frame size and transmission interval needed to stream the required
+// sample rate using 2-DH5 packets for aptX and 2-DH3 packets for aptX-LL.
+// With SCMS-T enabled we need to reserve room for extra headers added later.
+// Packets are always sent at equals time intervals but to achieve the
+// required sample rate, the frame size needs to change on occasion.
+//
+// Also need to specify how many of the required PCM samples are read at a
+// time:
+// aptx_bytes = pcm_reads * pcm_bytes_per_read / 4
+// and
+// number of aptX samples produced = pcm_bytes_per_read / 16
+//
+static void aptx_hd_update_framing_params(
+ tAPTX_HD_FRAMING_PARAMS* framing_params) {
+ if (a2dp_aptx_hd_encoder_cb.feeding_params.sample_rate == 48000) {
+ framing_params->aptx_hd_bytes = 648;
+ framing_params->pcm_bytes_per_read = 24;
+ framing_params->pcm_reads = 108;
+ } else {
+ // Assume the sample rate is 44100
+
+ //
+ // Total of 80 iterations:
+ // - Iteration 80: packet size 648, with 108 reads of 24 PCM bytes
+ // - Iterations 20, 40, 60: packet size 612, with 102 reads of 24 PCM bytes
+ // - All other iterations: packet size 594, with 99 reads of 24 PCM bytes
+ //
+ if (framing_params->frame_size_counter + 1 == 80) {
+ framing_params->aptx_hd_bytes = 648;
+ framing_params->pcm_bytes_per_read = 24;
+ framing_params->pcm_reads = 108;
+ } else if (((framing_params->frame_size_counter + 1) % 20) == 0) {
+ framing_params->aptx_hd_bytes = 612;
+ framing_params->pcm_bytes_per_read = 24;
+ framing_params->pcm_reads = 102;
+ } else {
+ framing_params->aptx_hd_bytes = 594;
+ framing_params->pcm_bytes_per_read = 24;
+ framing_params->pcm_reads = 99;
+ }
+ framing_params->frame_size_counter++;
+ if (framing_params->frame_size_counter == 80)
+ framing_params->frame_size_counter = 0;
+ }
+
+ LOG_VERBOSE(LOG_TAG,
+ "%s: sleep_time_ns = %" PRIu64
+ " aptx_hd_bytes = %u "
+ "pcm_bytes_per_read = %u pcm_reads = %u frame_size_counter = %u",
+ __func__, framing_params->sleep_time_ns,
+ framing_params->aptx_hd_bytes, framing_params->pcm_bytes_per_read,
+ framing_params->pcm_reads, framing_params->frame_size_counter);
+}
+
+void a2dp_vendor_aptx_hd_feeding_reset(void) {
+ aptx_hd_init_framing_params(&a2dp_aptx_hd_encoder_cb.framing_params);
+}
+
+void a2dp_vendor_aptx_hd_feeding_flush(void) {
+ aptx_hd_init_framing_params(&a2dp_aptx_hd_encoder_cb.framing_params);
+}
+
+period_ms_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void) {
+ return a2dp_aptx_hd_encoder_cb.framing_params.sleep_time_ns / (1000 * 1000);
+}
+
+void a2dp_vendor_aptx_hd_send_frames(uint64_t timestamp_us) {
+ tAPTX_HD_FRAMING_PARAMS* framing_params =
+ &a2dp_aptx_hd_encoder_cb.framing_params;
+
+ // Prepare the packet to send
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ p_buf->offset = A2DP_APTX_HD_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+
+ uint8_t* encoded_ptr = (uint8_t*)(p_buf + 1);
+ encoded_ptr += p_buf->offset;
+
+ aptx_hd_update_framing_params(framing_params);
+
+ //
+ // Read the PCM data and encode it
+ //
+ LOG_VERBOSE(LOG_TAG, "%s: %u PCM reads of size %u", __func__,
+ framing_params->pcm_reads, framing_params->pcm_bytes_per_read);
+ size_t encoded_ptr_index = 0;
+ size_t pcm_bytes_encoded = 0;
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_packets++;
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_reads_count +=
+ framing_params->pcm_reads;
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_expected_read_bytes +=
+ framing_params->pcm_reads * framing_params->pcm_bytes_per_read;
+ for (size_t reads = 0; reads < framing_params->pcm_reads; reads++) {
+ uint32_t
+ read_buffer32[A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ / sizeof(uint32_t)];
+ size_t pcm_bytes_read = a2dp_aptx_hd_encoder_cb.read_callback(
+ (uint8_t*)read_buffer32, framing_params->pcm_bytes_per_read);
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_read_bytes +=
+ pcm_bytes_read;
+ if (pcm_bytes_read < framing_params->pcm_bytes_per_read) {
+ LOG_WARN(LOG_TAG,
+ "%s: underflow at PCM reading iteration %zu: read %zu "
+ "instead of %d",
+ __func__, reads, pcm_bytes_read,
+ framing_params->pcm_bytes_per_read);
+ break;
+ }
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_actual_reads_count++;
+ pcm_bytes_encoded += aptx_hd_encode_24bit(
+ framing_params, &encoded_ptr_index, read_buffer32, encoded_ptr);
+ }
+
+ // Compute the number of encoded bytes
+ const int COMPRESSION_RATIO = 4;
+ size_t encoded_bytes = pcm_bytes_encoded / COMPRESSION_RATIO;
+ p_buf->len += encoded_bytes;
+ LOG_VERBOSE(LOG_TAG, "%s: encoded %zu PCM bytes to %zu", __func__,
+ pcm_bytes_encoded, encoded_bytes);
+
+ // Update the RTP timestamp
+ *((uint32_t*)(p_buf + 1)) = a2dp_aptx_hd_encoder_cb.timestamp;
+ const uint8_t BYTES_PER_FRAME = 3;
+ uint32_t rtp_timestamp =
+ (pcm_bytes_encoded /
+ a2dp_aptx_hd_encoder_cb.feeding_params.channel_count) /
+ BYTES_PER_FRAME;
+ a2dp_aptx_hd_encoder_cb.timestamp += rtp_timestamp;
+
+ if (p_buf->len > 0) {
+ a2dp_aptx_hd_encoder_cb.enqueue_callback(p_buf, 1);
+ } else {
+ a2dp_aptx_hd_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ }
+}
+
+static size_t aptx_hd_encode_24bit(tAPTX_HD_FRAMING_PARAMS* framing_params,
+ size_t* data_out_index, uint32_t* data32_in,
+ uint8_t* data_out) {
+ size_t pcm_bytes_encoded = 0;
+ const uint8_t* p = (const uint8_t*)(data32_in);
+
+ for (size_t aptx_hd_samples = 0;
+ aptx_hd_samples < framing_params->pcm_bytes_per_read / 24;
+ aptx_hd_samples++) {
+ uint32_t pcmL[4];
+ uint32_t pcmR[4];
+ uint32_t encoded_sample[2];
+
+ // Expand from AUDIO_FORMAT_PCM_24_BIT_PACKED data (3 bytes per sample)
+ // into AUDIO_FORMAT_PCM_8_24_BIT (4 bytes per sample).
+ for (size_t i = 0; i < 4; i++) {
+ pcmL[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16));
+ p += 3;
+ pcmR[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16));
+ p += 3;
+ }
+
+ aptx_hd_encoder_encode_stereo_func(
+ a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, &pcmL, &pcmR,
+ &encoded_sample);
+
+ uint8_t* encoded_ptr = (uint8_t*)&encoded_sample[0];
+ data_out[*data_out_index + 0] = *(encoded_ptr + 2);
+ data_out[*data_out_index + 1] = *(encoded_ptr + 1);
+ data_out[*data_out_index + 2] = *(encoded_ptr + 0);
+ data_out[*data_out_index + 3] = *(encoded_ptr + 6);
+ data_out[*data_out_index + 4] = *(encoded_ptr + 5);
+ data_out[*data_out_index + 5] = *(encoded_ptr + 4);
+
+ pcm_bytes_encoded += 24;
+ *data_out_index += 6;
+ }
+
+ return pcm_bytes_encoded;
+}
+
+period_ms_t A2dpCodecConfigAptxHd::encoderIntervalMs() const {
+ return a2dp_vendor_aptx_hd_get_encoder_interval_ms();
+}
+
+void A2dpCodecConfigAptxHd::debug_codec_dump(int fd) {
+ a2dp_aptx_hd_encoder_stats_t* stats = &a2dp_aptx_hd_encoder_cb.stats;
+
+ A2dpCodecConfig::debug_codec_dump(fd);
+
+ dprintf(fd,
+ " Packet counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_packets,
+ stats->media_read_total_dropped_packets);
+
+ dprintf(fd,
+ " PCM read counts (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_reads_count,
+ stats->media_read_total_actual_reads_count);
+
+ dprintf(fd,
+ " PCM read bytes (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_read_bytes,
+ stats->media_read_total_actual_read_bytes);
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac.cc
new file mode 100755
index 0000000..e822a2f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac.cc
@@ -0,0 +1,1184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/******************************************************************************
+ *
+ * Utility functions to help build and parse the LDAC Codec Information
+ * Element and Media Payload.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "a2dp_vendor_ldac"
+
+#include "bt_target.h"
+
+#include "a2dp_vendor_ldac.h"
+
+#include <string.h>
+
+#include <base/logging.h>
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac_encoder.h"
+#include "bt_utils.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+// data type for the LDAC Codec Information Element */
+// NOTE: bits_per_sample is needed only for LDAC encoder initialization.
+typedef struct {
+ uint32_t vendorId;
+ uint16_t codecId; /* Codec ID for LDAC */
+ uint8_t sampleRate; /* Sampling Frequency */
+ uint8_t channelMode; /* STEREO/DUAL/MONO */
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+} tA2DP_LDAC_CIE;
+
+/* LDAC Source codec capabilities */
+static const tA2DP_LDAC_CIE a2dp_ldac_caps = {
+ A2DP_LDAC_VENDOR_ID, // vendorId
+ A2DP_LDAC_CODEC_ID, // codecId
+ // sampleRate
+ (A2DP_LDAC_SAMPLING_FREQ_44100 | A2DP_LDAC_SAMPLING_FREQ_48000 |
+ A2DP_LDAC_SAMPLING_FREQ_88200 | A2DP_LDAC_SAMPLING_FREQ_96000),
+ // channelMode
+ (A2DP_LDAC_CHANNEL_MODE_DUAL | A2DP_LDAC_CHANNEL_MODE_STEREO),
+ // bits_per_sample
+ (BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16 | BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24 |
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32)};
+
+/* Default LDAC codec configuration */
+static const tA2DP_LDAC_CIE a2dp_ldac_default_config = {
+ A2DP_LDAC_VENDOR_ID, // vendorId
+ A2DP_LDAC_CODEC_ID, // codecId
+ A2DP_LDAC_SAMPLING_FREQ_96000, // sampleRate
+ A2DP_LDAC_CHANNEL_MODE_STEREO, // channelMode
+ BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32 // bits_per_sample
+};
+
+static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_ldac = {
+ a2dp_vendor_ldac_encoder_init,
+ a2dp_vendor_ldac_encoder_cleanup,
+ a2dp_vendor_ldac_feeding_reset,
+ a2dp_vendor_ldac_feeding_flush,
+ a2dp_vendor_ldac_get_encoder_interval_ms,
+ a2dp_vendor_ldac_send_frames,
+ a2dp_vendor_ldac_set_transmit_queue_length};
+
+UNUSED_ATTR static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(
+ const tA2DP_LDAC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_peer_codec_info);
+
+// Builds the LDAC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
+// |p_ie| is a pointer to the LDAC Codec Information Element information.
+// The result is stored in |p_result|. Returns A2DP_SUCCESS on success,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_BuildInfoLdac(uint8_t media_type,
+ const tA2DP_LDAC_CIE* p_ie,
+ uint8_t* p_result) {
+ if (p_ie == NULL || p_result == NULL) {
+ return A2DP_INVALID_PARAMS;
+ }
+
+ *p_result++ = A2DP_LDAC_CODEC_LEN;
+ *p_result++ = (media_type << 4);
+ *p_result++ = A2DP_MEDIA_CT_NON_A2DP;
+
+ // Vendor ID and Codec ID
+ *p_result++ = (uint8_t)(p_ie->vendorId & 0x000000FF);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x0000FF00) >> 8);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0x00FF0000) >> 16);
+ *p_result++ = (uint8_t)((p_ie->vendorId & 0xFF000000) >> 24);
+ *p_result++ = (uint8_t)(p_ie->codecId & 0x00FF);
+ *p_result++ = (uint8_t)((p_ie->codecId & 0xFF00) >> 8);
+
+ // Sampling Frequency
+ *p_result = (uint8_t)(p_ie->sampleRate & A2DP_LDAC_SAMPLING_FREQ_MASK);
+ if (*p_result == 0) return A2DP_INVALID_PARAMS;
+ p_result++;
+
+ // Channel Mode
+ *p_result = (uint8_t)(p_ie->channelMode & A2DP_LDAC_CHANNEL_MODE_MASK);
+ if (*p_result == 0) return A2DP_INVALID_PARAMS;
+
+ return A2DP_SUCCESS;
+}
+
+// Parses the LDAC Media Codec Capabilities byte sequence beginning from the
+// LOSC octet. The result is stored in |p_ie|. The byte sequence to parse is
+// |p_codec_info|. If |is_capability| is true, the byte sequence is
+// codec capabilities, otherwise is codec configuration.
+// Returns A2DP_SUCCESS on success, otherwise the corresponding A2DP error
+// status code.
+static tA2DP_STATUS A2DP_ParseInfoLdac(tA2DP_LDAC_CIE* p_ie,
+ const uint8_t* p_codec_info,
+ bool is_capability) {
+ uint8_t losc;
+ uint8_t media_type;
+ tA2DP_CODEC_TYPE codec_type;
+
+ if (p_ie == NULL || p_codec_info == NULL) return A2DP_INVALID_PARAMS;
+
+ // Check the codec capability length
+ losc = *p_codec_info++;
+ if (losc != A2DP_LDAC_CODEC_LEN) return A2DP_WRONG_CODEC;
+
+ media_type = (*p_codec_info++) >> 4;
+ codec_type = *p_codec_info++;
+ /* Check the Media Type and Media Codec Type */
+ if (media_type != AVDT_MEDIA_TYPE_AUDIO ||
+ codec_type != A2DP_MEDIA_CT_NON_A2DP) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ // Check the Vendor ID and Codec ID */
+ p_ie->vendorId = (*p_codec_info & 0x000000FF) |
+ (*(p_codec_info + 1) << 8 & 0x0000FF00) |
+ (*(p_codec_info + 2) << 16 & 0x00FF0000) |
+ (*(p_codec_info + 3) << 24 & 0xFF000000);
+ p_codec_info += 4;
+ p_ie->codecId =
+ (*p_codec_info & 0x00FF) | (*(p_codec_info + 1) << 8 & 0xFF00);
+ p_codec_info += 2;
+ if (p_ie->vendorId != A2DP_LDAC_VENDOR_ID ||
+ p_ie->codecId != A2DP_LDAC_CODEC_ID) {
+ return A2DP_WRONG_CODEC;
+ }
+
+ p_ie->sampleRate = *p_codec_info++ & A2DP_LDAC_SAMPLING_FREQ_MASK;
+ p_ie->channelMode = *p_codec_info++ & A2DP_LDAC_CHANNEL_MODE_MASK;
+
+ if (is_capability) return A2DP_SUCCESS;
+
+ if (A2DP_BitsSet(p_ie->sampleRate) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_SAMP_FREQ;
+ if (A2DP_BitsSet(p_ie->channelMode) != A2DP_SET_ONE_BIT)
+ return A2DP_BAD_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+// Build the LDAC Media Payload Header.
+// |p_dst| points to the location where the header should be written to.
+// If |frag| is true, the media payload frame is fragmented.
+// |start| is true for the first packet of a fragmented frame.
+// |last| is true for the last packet of a fragmented frame.
+// If |frag| is false, |num| is the number of number of frames in the packet,
+// otherwise is the number of remaining fragments (including this one).
+static void A2DP_BuildMediaPayloadHeaderLdac(uint8_t* p_dst, bool frag,
+ bool start, bool last,
+ uint8_t num) {
+ if (p_dst == NULL) return;
+
+ *p_dst = 0;
+ if (frag) *p_dst |= A2DP_LDAC_HDR_F_MSK;
+ if (start) *p_dst |= A2DP_LDAC_HDR_S_MSK;
+ if (last) *p_dst |= A2DP_LDAC_HDR_L_MSK;
+ *p_dst |= (A2DP_LDAC_HDR_NUM_MSK & num);
+}
+
+bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE cfg_cie;
+
+ /* Use a liberal check when parsing the codec info */
+ return (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, false) == A2DP_SUCCESS) ||
+ (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
+}
+
+// Checks whether A2DP LDAC codec configuration matches with a device's codec
+// capabilities. |p_cap| is the LDAC codec configuration. |p_codec_info| is
+// the device's codec capabilities.
+// If |is_capability| is true, the byte sequence is codec capabilities,
+// otherwise is codec configuration.
+// |p_codec_info| contains the codec capabilities for a peer device that
+// is acting as an A2DP source.
+// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
+// otherwise the corresponding A2DP error status code.
+static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(
+ const tA2DP_LDAC_CIE* p_cap, const uint8_t* p_codec_info,
+ bool is_capability) {
+ tA2DP_STATUS status;
+ tA2DP_LDAC_CIE cfg_cie;
+
+ /* parse configuration */
+ status = A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: parsing failed %d", __func__, status);
+ return status;
+ }
+
+ /* verify that each parameter is in range */
+
+ LOG_DEBUG(LOG_TAG, "%s: FREQ peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.sampleRate, p_cap->sampleRate);
+ LOG_DEBUG(LOG_TAG, "%s: CH_MODE peer: 0x%x, capability 0x%x", __func__,
+ cfg_cie.channelMode, p_cap->channelMode);
+
+ /* sampling frequency */
+ if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) return A2DP_NS_SAMP_FREQ;
+
+ /* channel mode */
+ if ((cfg_cie.channelMode & p_cap->channelMode) == 0) return A2DP_NS_CH_MODE;
+
+ return A2DP_SUCCESS;
+}
+
+bool A2DP_VendorUsesRtpHeaderLdac(UNUSED_ATTR bool content_protection_enabled,
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ // TODO: Is this correct? The RTP header is always included?
+ return true;
+}
+
+const char* A2DP_VendorCodecNameLdac(UNUSED_ATTR const uint8_t* p_codec_info) {
+ return "LDAC";
+}
+
+bool A2DP_VendorCodecTypeEqualsLdac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_LDAC_CIE ldac_cie_a;
+ tA2DP_LDAC_CIE ldac_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoLdac(&ldac_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoLdac(&ldac_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2DP_VendorCodecEqualsLdac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b) {
+ tA2DP_LDAC_CIE ldac_cie_a;
+ tA2DP_LDAC_CIE ldac_cie_b;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status =
+ A2DP_ParseInfoLdac(&ldac_cie_a, p_codec_info_a, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+ a2dp_status = A2DP_ParseInfoLdac(&ldac_cie_b, p_codec_info_b, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return false;
+ }
+
+ return (ldac_cie_a.sampleRate == ldac_cie_b.sampleRate) &&
+ (ldac_cie_a.channelMode == ldac_cie_b.channelMode);
+}
+
+int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (ldac_cie.sampleRate) {
+ case A2DP_LDAC_SAMPLING_FREQ_44100:
+ return 44100;
+ case A2DP_LDAC_SAMPLING_FREQ_48000:
+ return 48000;
+ case A2DP_LDAC_SAMPLING_FREQ_88200:
+ return 88200;
+ case A2DP_LDAC_SAMPLING_FREQ_96000:
+ return 96000;
+ case A2DP_LDAC_SAMPLING_FREQ_176400:
+ return 176400;
+ case A2DP_LDAC_SAMPLING_FREQ_192000:
+ return 192000;
+ }
+
+ return -1;
+}
+
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (a2dp_ldac_caps.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ return 16;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ return 24;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ return 32;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return -1;
+}
+
+int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (ldac_cie.channelMode) {
+ case A2DP_LDAC_CHANNEL_MODE_MONO:
+ return 1;
+ case A2DP_LDAC_CHANNEL_MODE_DUAL:
+ return 2;
+ case A2DP_LDAC_CHANNEL_MODE_STEREO:
+ return 2;
+ }
+
+ return -1;
+}
+
+int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE ldac_cie;
+
+ // Check whether the codec info contains valid data
+ tA2DP_STATUS a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, false);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: cannot decode codec information: %d", __func__,
+ a2dp_status);
+ return -1;
+ }
+
+ switch (ldac_cie.channelMode) {
+ case A2DP_LDAC_CHANNEL_MODE_MONO:
+ case A2DP_LDAC_CHANNEL_MODE_DUAL:
+ case A2DP_LDAC_CHANNEL_MODE_STEREO:
+ return ldac_cie.channelMode;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+bool A2DP_VendorGetPacketTimestampLdac(UNUSED_ATTR const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp) {
+ // TODO: Is this function really codec-specific?
+ *p_timestamp = *(const uint32_t*)p_data;
+ return true;
+}
+
+bool A2DP_VendorBuildCodecHeaderLdac(UNUSED_ATTR const uint8_t* p_codec_info,
+ BT_HDR* p_buf,
+ uint16_t frames_per_packet) {
+ uint8_t* p;
+
+ p_buf->offset -= A2DP_LDAC_MPL_HDR_LEN;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ p_buf->len += A2DP_LDAC_MPL_HDR_LEN;
+ A2DP_BuildMediaPayloadHeaderLdac(p, false, false, false,
+ (uint8_t)frames_per_packet);
+
+ return true;
+}
+
+void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info) {
+ tA2DP_STATUS a2dp_status;
+ tA2DP_LDAC_CIE ldac_cie;
+
+ LOG_DEBUG(LOG_TAG, "%s", __func__);
+
+ a2dp_status = A2DP_ParseInfoLdac(&ldac_cie, p_codec_info, true);
+ if (a2dp_status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: A2DP_ParseInfoLdac fail:%d", __func__, a2dp_status);
+ return;
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: 0x%x", ldac_cie.sampleRate);
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (44100)");
+ }
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (48000)");
+ }
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (88200)");
+ }
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (96000)");
+ }
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (176400)");
+ }
+ if (ldac_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ LOG_DEBUG(LOG_TAG, "\tsamp_freq: (192000)");
+ }
+
+ LOG_DEBUG(LOG_TAG, "\tch_mode: 0x%x", ldac_cie.channelMode);
+ if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Mono)");
+ }
+ if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Dual)");
+ }
+ if (ldac_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ LOG_DEBUG(LOG_TAG, "\tch_mode: (Stereo)");
+ }
+}
+
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
+ const uint8_t* p_codec_info) {
+ if (!A2DP_IsVendorSourceCodecValidLdac(p_codec_info)) return NULL;
+
+ return &a2dp_encoder_interface_ldac;
+}
+
+bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) {
+ tA2DP_LDAC_CIE cfg_cie;
+
+ // Nothing to do: just verify the codec info is valid
+ if (A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) != A2DP_SUCCESS)
+ return false;
+
+ return true;
+}
+
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
+ UNUSED_ATTR const uint8_t* p_codec_info) {
+ return BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC;
+}
+
+const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
+
+bool A2DP_VendorInitCodecConfigLdac(tAVDT_CFG* p_cfg) {
+ if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_caps,
+ p_cfg->codec_info) != A2DP_SUCCESS) {
+ return false;
+ }
+
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ /* Content protection info - support SCMS-T */
+ uint8_t* p = p_cfg->protect_info;
+ *p++ = AVDT_CP_LOSC;
+ UINT16_TO_STREAM(p, AVDT_CP_SCMS_T_ID);
+ p_cfg->num_protect = 1;
+#endif
+
+ return true;
+}
+
+UNUSED_ATTR static void build_codec_config(const tA2DP_LDAC_CIE& config_cie,
+ btav_a2dp_codec_config_t* result) {
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ if (config_cie.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000)
+ result->sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+
+ result->bits_per_sample = config_cie.bits_per_sample;
+
+ if (config_cie.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO)
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (config_cie.channelMode &
+ (A2DP_LDAC_CHANNEL_MODE_DUAL | A2DP_LDAC_CHANNEL_MODE_STEREO)) {
+ result->channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigLdac::A2dpCodecConfigLdac(
+ btav_a2dp_codec_priority_t codec_priority)
+ : A2dpCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, "LDAC",
+ codec_priority) {
+ // Compute the local capability
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ }
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ }
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ }
+ if (a2dp_ldac_caps.sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ codec_local_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+ }
+ codec_local_capability_.bits_per_sample = a2dp_ldac_caps.bits_per_sample;
+ if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (a2dp_ldac_caps.channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ codec_local_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+}
+
+A2dpCodecConfigLdac::~A2dpCodecConfigLdac() {}
+
+bool A2dpCodecConfigLdac::init() {
+ if (!isValid()) return false;
+
+ // Load the encoder
+ if (!A2DP_VendorLoadEncoderLdac()) {
+ LOG_ERROR(LOG_TAG, "%s: cannot load the encoder", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+bool A2dpCodecConfigLdac::useRtpHeaderMarkerBit() const { return false; }
+
+//
+// Selects the best sample rate from |sampleRate|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_sample_rate(uint8_t sampleRate,
+ tA2DP_LDAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_192000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+ return true;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_176400;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ return true;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_96000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ return true;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_88200;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ return true;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio sample rate from |p_codec_audio_config|.
+// |sampleRate| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_sample_rate(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t sampleRate,
+ tA2DP_LDAC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_44100;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_48000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_88200;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_96000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_176400;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ p_result->sampleRate = A2DP_LDAC_SAMPLING_FREQ_192000;
+ p_codec_config->sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best bits per sample from |bits_per_sample|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_bits_per_sample(
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_LDAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ return true;
+ }
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+ }
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio bits per sample from |p_codec_audio_config|.
+// |bits_per_sample| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_bits_per_sample(
+ const btav_a2dp_codec_config_t* p_codec_audio_config,
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample, tA2DP_LDAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ p_codec_config->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ p_result->bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ break;
+ }
+ return false;
+}
+
+//
+// Selects the best channel mode from |channelMode|.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_best_channel_mode(uint8_t channelMode,
+ tA2DP_LDAC_CIE* p_result,
+ btav_a2dp_codec_config_t* p_codec_config) {
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_DUAL;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ return false;
+}
+
+//
+// Selects the audio channel mode from |p_codec_audio_config|.
+// |channelMode| contains the capability.
+// The result is stored in |p_result| and |p_codec_config|.
+// Returns true if a selection was made, otherwise false.
+//
+static bool select_audio_channel_mode(
+ const btav_a2dp_codec_config_t* p_codec_audio_config, uint8_t channelMode,
+ tA2DP_LDAC_CIE* p_result, btav_a2dp_codec_config_t* p_codec_config) {
+ switch (p_codec_audio_config->channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_MONO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_STEREO;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ p_result->channelMode = A2DP_LDAC_CHANNEL_MODE_DUAL;
+ p_codec_config->channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ return true;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ break;
+ }
+
+ return false;
+}
+
+bool A2dpCodecConfigLdac::setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) {
+ std::lock_guard<std::recursive_mutex> lock(codec_mutex_);
+ tA2DP_LDAC_CIE sink_info_cie;
+ tA2DP_LDAC_CIE result_config_cie;
+ uint8_t channelMode;
+ uint8_t sampleRate;
+ btav_a2dp_codec_bits_per_sample_t bits_per_sample;
+
+ // Save the internal state
+ btav_a2dp_codec_config_t saved_codec_config = codec_config_;
+ btav_a2dp_codec_config_t saved_codec_capability = codec_capability_;
+ btav_a2dp_codec_config_t saved_codec_selectable_capability =
+ codec_selectable_capability_;
+ btav_a2dp_codec_config_t saved_codec_user_config = codec_user_config_;
+ btav_a2dp_codec_config_t saved_codec_audio_config = codec_audio_config_;
+ uint8_t saved_ota_codec_config[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_capability[AVDT_CODEC_SIZE];
+ uint8_t saved_ota_codec_peer_config[AVDT_CODEC_SIZE];
+ memcpy(saved_ota_codec_config, ota_codec_config_, sizeof(ota_codec_config_));
+ memcpy(saved_ota_codec_peer_capability, ota_codec_peer_capability_,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(saved_ota_codec_peer_config, ota_codec_peer_config_,
+ sizeof(ota_codec_peer_config_));
+
+ tA2DP_STATUS status =
+ A2DP_ParseInfoLdac(&sink_info_cie, p_peer_codec_info, is_capability);
+ if (status != A2DP_SUCCESS) {
+ LOG_ERROR(LOG_TAG, "%s: can't parse peer's Sink capabilities: error = %d",
+ __func__, status);
+ goto fail;
+ }
+
+ //
+ // Build the preferred configuration
+ //
+ memset(&result_config_cie, 0, sizeof(result_config_cie));
+ result_config_cie.vendorId = a2dp_ldac_caps.vendorId;
+ result_config_cie.codecId = a2dp_ldac_caps.codecId;
+
+ //
+ // Select the sample frequency
+ //
+ sampleRate = a2dp_ldac_caps.sampleRate & sink_info_cie.sampleRate;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ switch (codec_user_config_.sample_rate) {
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_44100:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_44100;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_48000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_48000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_88200:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_88200;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_96000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_96000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_176400:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_176400;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ break;
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_192000:
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ result_config_cie.sampleRate = A2DP_LDAC_SAMPLING_FREQ_192000;
+ codec_capability_.sample_rate = codec_user_config_.sample_rate;
+ codec_config_.sample_rate = codec_user_config_.sample_rate;
+ }
+ case BTAV_A2DP_CODEC_SAMPLE_RATE_NONE:
+ codec_capability_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ codec_config_.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE;
+ break;
+ }
+
+ // Select the sample frequency if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ }
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000) {
+ codec_selectable_capability_.sample_rate |=
+ BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+ }
+
+ if (codec_config_.sample_rate != BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) break;
+
+ // Compute the common capability
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_44100)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_44100;
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_48000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_48000;
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_88200)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_88200;
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_96000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_96000;
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_176400)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_176400;
+ if (sampleRate & A2DP_LDAC_SAMPLING_FREQ_192000)
+ codec_capability_.sample_rate |= BTAV_A2DP_CODEC_SAMPLE_RATE_192000;
+
+ // No user preference - try the codec audio config
+ if (select_audio_sample_rate(&codec_audio_config_, sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_sample_rate(
+ a2dp_ldac_default_config.sampleRate & sink_info_cie.sampleRate,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_sample_rate(sampleRate, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match sample frequency: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_ldac_caps.sampleRate, sink_info_cie.sampleRate);
+ goto fail;
+ }
+
+ //
+ // Select the bits per sample
+ //
+ // NOTE: this information is NOT included in the LDAC A2DP codec description
+ // that is sent OTA.
+ bits_per_sample = a2dp_ldac_caps.bits_per_sample;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ switch (codec_user_config_.bits_per_sample) {
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_16) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_24) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32:
+ if (bits_per_sample & BTAV_A2DP_CODEC_BITS_PER_SAMPLE_32) {
+ result_config_cie.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_capability_.bits_per_sample = codec_user_config_.bits_per_sample;
+ codec_config_.bits_per_sample = codec_user_config_.bits_per_sample;
+ }
+ break;
+ case BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE:
+ result_config_cie.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_capability_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ codec_config_.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE;
+ break;
+ }
+
+ // Select the bits per sample if there is no user preference
+ do {
+ // Compute the selectable capability
+ codec_selectable_capability_.bits_per_sample =
+ a2dp_ldac_caps.bits_per_sample;
+
+ if (codec_config_.bits_per_sample != BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE)
+ break;
+
+ // Compute the common capability
+ codec_capability_.bits_per_sample = bits_per_sample;
+
+ // No user preference - the the codec audio config
+ if (select_audio_bits_per_sample(&codec_audio_config_,
+ a2dp_ldac_caps.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_bits_per_sample(a2dp_ldac_default_config.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_bits_per_sample(a2dp_ldac_caps.bits_per_sample,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.bits_per_sample == BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match bits per sample: default = 0x%x "
+ "user preference = 0x%x",
+ __func__, a2dp_ldac_default_config.bits_per_sample,
+ codec_user_config_.bits_per_sample);
+ goto fail;
+ }
+
+ //
+ // Select the channel mode
+ //
+ channelMode = a2dp_ldac_caps.channelMode & sink_info_cie.channelMode;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ switch (codec_user_config_.channel_mode) {
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_MONO:
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ result_config_cie.channelMode = A2DP_LDAC_CHANNEL_MODE_MONO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO:
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ result_config_cie.channelMode = A2DP_LDAC_CHANNEL_MODE_STEREO;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ break;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ result_config_cie.channelMode = A2DP_LDAC_CHANNEL_MODE_DUAL;
+ codec_capability_.channel_mode = codec_user_config_.channel_mode;
+ codec_config_.channel_mode = codec_user_config_.channel_mode;
+ break;
+ }
+ break;
+ case BTAV_A2DP_CODEC_CHANNEL_MODE_NONE:
+ codec_capability_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ codec_config_.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE;
+ break;
+ }
+
+ // Select the channel mode if there is no user preference
+ do {
+ // Compute the selectable capability
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_STEREO) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_DUAL) {
+ codec_selectable_capability_.channel_mode |=
+ BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ if (codec_config_.channel_mode != BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) break;
+
+ // Compute the common capability
+ if (channelMode & A2DP_LDAC_CHANNEL_MODE_MONO)
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_MONO;
+ if (channelMode &
+ (A2DP_LDAC_CHANNEL_MODE_STEREO | A2DP_LDAC_CHANNEL_MODE_DUAL)) {
+ codec_capability_.channel_mode |= BTAV_A2DP_CODEC_CHANNEL_MODE_STEREO;
+ }
+
+ // No user preference - try the codec audio config
+ if (select_audio_channel_mode(&codec_audio_config_, channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - try the default config
+ if (select_best_channel_mode(
+ a2dp_ldac_default_config.channelMode & sink_info_cie.channelMode,
+ &result_config_cie, &codec_config_)) {
+ break;
+ }
+
+ // No user preference - use the best match
+ if (select_best_channel_mode(channelMode, &result_config_cie,
+ &codec_config_)) {
+ break;
+ }
+ } while (false);
+ if (codec_config_.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot match channel mode: source caps = 0x%x "
+ "sink info = 0x%x",
+ __func__, a2dp_ldac_caps.channelMode, sink_info_cie.channelMode);
+ goto fail;
+ }
+
+ if (A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ p_result_codec_config) != A2DP_SUCCESS) {
+ goto fail;
+ }
+
+ //
+ // Copy the codec-specific fields if they are not zero
+ //
+ if (codec_user_config_.codec_specific_1 != 0)
+ codec_config_.codec_specific_1 = codec_user_config_.codec_specific_1;
+ if (codec_user_config_.codec_specific_2 != 0)
+ codec_config_.codec_specific_2 = codec_user_config_.codec_specific_2;
+ if (codec_user_config_.codec_specific_3 != 0)
+ codec_config_.codec_specific_3 = codec_user_config_.codec_specific_3;
+ if (codec_user_config_.codec_specific_4 != 0)
+ codec_config_.codec_specific_4 = codec_user_config_.codec_specific_4;
+
+ // Create a local copy of the peer codec capability, and the
+ // result codec config.
+ if (is_capability) {
+ status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_capability_);
+ } else {
+ status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &sink_info_cie,
+ ota_codec_peer_config_);
+ }
+ CHECK(status == A2DP_SUCCESS);
+ status = A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &result_config_cie,
+ ota_codec_config_);
+ CHECK(status == A2DP_SUCCESS);
+ return true;
+
+fail:
+ // Restore the internal state
+ codec_config_ = saved_codec_config;
+ codec_capability_ = saved_codec_capability;
+ codec_selectable_capability_ = saved_codec_selectable_capability;
+ codec_user_config_ = saved_codec_user_config;
+ codec_audio_config_ = saved_codec_audio_config;
+ memcpy(ota_codec_config_, saved_ota_codec_config, sizeof(ota_codec_config_));
+ memcpy(ota_codec_peer_capability_, saved_ota_codec_peer_capability,
+ sizeof(ota_codec_peer_capability_));
+ memcpy(ota_codec_peer_config_, saved_ota_codec_peer_config,
+ sizeof(ota_codec_peer_config_));
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_abr.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_abr.cc
new file mode 100755
index 0000000..784da88
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_abr.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_vendor_ldac_abr"
+
+#include "a2dp_vendor_ldac_abr.h"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "osi/include/log.h"
+
+//
+// LDAC ABR(Adaptive Bit Rate) Source Code
+//
+
+//
+// The LDAC ABR shared library, and the functions to use
+//
+static const char* LDAC_ABR_LIB_NAME = "libldacBT_abr.so";
+static void* ldac_abr_lib_handle = NULL;
+
+static const char* LDAC_ABR_GET_HANDLE_NAME = "ldac_ABR_get_handle";
+typedef HANDLE_LDAC_ABR (*tLDAC_ABR_GET_HANDLE)(void);
+
+static const char* LDAC_ABR_FREE_HANDLE_NAME = "ldac_ABR_free_handle";
+typedef void (*tLDAC_ABR_FREE_HANDLE)(HANDLE_LDAC_ABR hLdacAbr);
+
+static const char* LDAC_ABR_INIT_NAME = "ldac_ABR_Init";
+typedef int (*tLDAC_ABR_INIT)(HANDLE_LDAC_ABR hLdacAbr,
+ unsigned int interval_ms);
+
+static const char* LDAC_ABR_SET_THRESHOLDS_NAME = "ldac_ABR_set_thresholds";
+typedef int (*tLDAC_ABR_SET_THRESHOLDS)(HANDLE_LDAC_ABR hLdacAbr,
+ unsigned int th_critical,
+ unsigned int th_dangerous_trend,
+ unsigned int th_safety_4hqsq);
+
+static const char* LDAC_ABR_PROC_NAME = "ldac_ABR_Proc";
+typedef int (*tLDAC_ABR_PROC)(HANDLE_LDAC_BT hLdacParam,
+ HANDLE_LDAC_ABR hLdacAbr, unsigned int txq_length,
+ unsigned int flag_enable);
+
+static tLDAC_ABR_GET_HANDLE ldac_abr_get_handle_func;
+static tLDAC_ABR_FREE_HANDLE ldac_abr_free_handle_func;
+static tLDAC_ABR_INIT ldac_abr_init_func;
+static tLDAC_ABR_SET_THRESHOLDS ldac_abr_set_thresholds_func;
+static tLDAC_ABR_PROC ldac_abr_proc_func;
+
+bool A2DP_VendorLoadLdacAbr(void) {
+ if (ldac_abr_lib_handle != NULL) return true; // Already loaded
+
+ // Open the LDAC ABR library
+ ldac_abr_lib_handle = dlopen(LDAC_ABR_LIB_NAME, RTLD_NOW);
+ if (ldac_abr_lib_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: cannot open LDAC ABR library %s: %s", __func__,
+ LDAC_ABR_LIB_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ // Load all functions
+ ldac_abr_get_handle_func = (tLDAC_ABR_GET_HANDLE)dlsym(
+ ldac_abr_lib_handle, LDAC_ABR_GET_HANDLE_NAME);
+ if (ldac_abr_get_handle_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the LDAC ABR library: %s",
+ __func__, LDAC_ABR_GET_HANDLE_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ ldac_abr_free_handle_func = (tLDAC_ABR_FREE_HANDLE)dlsym(
+ ldac_abr_lib_handle, LDAC_ABR_FREE_HANDLE_NAME);
+ if (ldac_abr_free_handle_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the LDAC ABR library: %s",
+ __func__, LDAC_ABR_FREE_HANDLE_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ ldac_abr_init_func =
+ (tLDAC_ABR_INIT)dlsym(ldac_abr_lib_handle, LDAC_ABR_INIT_NAME);
+ if (ldac_abr_init_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the LDAC ABR library: %s",
+ __func__, LDAC_ABR_INIT_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ ldac_abr_set_thresholds_func = (tLDAC_ABR_SET_THRESHOLDS)dlsym(
+ ldac_abr_lib_handle, LDAC_ABR_SET_THRESHOLDS_NAME);
+ if (ldac_abr_set_thresholds_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the LDAC ABR library: %s",
+ __func__, LDAC_ABR_SET_THRESHOLDS_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ ldac_abr_proc_func =
+ (tLDAC_ABR_PROC)dlsym(ldac_abr_lib_handle, LDAC_ABR_PROC_NAME);
+ if (ldac_abr_proc_func == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the LDAC ABR library: %s",
+ __func__, LDAC_ABR_PROC_NAME, dlerror());
+ A2DP_VendorUnloadLdacAbr();
+ return false;
+ }
+
+ return true;
+}
+
+void A2DP_VendorUnloadLdacAbr(void) {
+ ldac_abr_get_handle_func = NULL;
+ ldac_abr_free_handle_func = NULL;
+ ldac_abr_init_func = NULL;
+ ldac_abr_set_thresholds_func = NULL;
+ ldac_abr_proc_func = NULL;
+
+ if (ldac_abr_lib_handle != NULL) {
+ dlclose(ldac_abr_lib_handle);
+ ldac_abr_lib_handle = NULL;
+ }
+}
+
+HANDLE_LDAC_ABR a2dp_ldac_abr_get_handle(void) {
+ return ldac_abr_get_handle_func();
+}
+
+void a2dp_ldac_abr_free_handle(HANDLE_LDAC_ABR hLdacAbr) {
+ return ldac_abr_free_handle_func(hLdacAbr);
+}
+
+int a2dp_ldac_abr_init(HANDLE_LDAC_ABR hLdacAbr, unsigned int interval_ms) {
+ return ldac_abr_init_func(hLdacAbr, interval_ms);
+}
+
+int a2dp_ldac_abr_set_thresholds(HANDLE_LDAC_ABR hLdacAbr,
+ unsigned int th_critical,
+ unsigned int th_dangerous_trend,
+ unsigned int th_4hqsq) {
+ return ldac_abr_set_thresholds_func(hLdacAbr, th_critical, th_dangerous_trend,
+ th_4hqsq);
+}
+
+int a2dp_ldac_abr_proc(HANDLE_LDAC_BT hLdacParam, HANDLE_LDAC_ABR hLdacAbr,
+ size_t transmit_queue_length, unsigned int flag_enable) {
+ return ldac_abr_proc_func(hLdacParam, hLdacAbr, transmit_queue_length,
+ flag_enable);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_encoder.cc b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_encoder.cc
new file mode 100755
index 0000000..68deea8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/a2dp/a2dp_vendor_ldac_encoder.cc
@@ -0,0 +1,789 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "a2dp_vendor_ldac_encoder"
+
+#include "a2dp_vendor_ldac_encoder.h"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ldacBT.h>
+
+#include "a2dp_vendor.h"
+#include "a2dp_vendor_ldac.h"
+#include "a2dp_vendor_ldac_abr.h"
+#include "bt_common.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+//
+// Encoder for LDAC Source Codec
+//
+
+//
+// The LDAC encoder shared library, and the functions to use
+//
+static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
+static void* ldac_encoder_lib_handle = NULL;
+
+static const char* LDAC_GET_HANDLE_NAME = "ldacBT_get_handle";
+typedef HANDLE_LDAC_BT (*tLDAC_GET_HANDLE)(void);
+
+static const char* LDAC_FREE_HANDLE_NAME = "ldacBT_free_handle";
+typedef void (*tLDAC_FREE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_CLOSE_HANDLE_NAME = "ldacBT_close_handle";
+typedef void (*tLDAC_CLOSE_HANDLE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_VERSION_NAME = "ldacBT_get_version";
+typedef int (*tLDAC_GET_VERSION)(void);
+
+static const char* LDAC_GET_BITRATE_NAME = "ldacBT_get_bitrate";
+typedef int (*tLDAC_GET_BITRATE)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_SAMPLING_FREQ_NAME = "ldacBT_get_sampling_freq";
+typedef int (*tLDAC_GET_SAMPLING_FREQ)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_INIT_HANDLE_ENCODE_NAME = "ldacBT_init_handle_encode";
+typedef int (*tLDAC_INIT_HANDLE_ENCODE)(HANDLE_LDAC_BT hLdacParam, int mtu,
+ int eqmid, int channel_mode,
+ LDACBT_SMPL_FMT_T fmt,
+ int sampling_freq);
+
+static const char* LDAC_ENCODE_NAME = "ldacBT_encode";
+typedef int (*tLDAC_ENCODE)(HANDLE_LDAC_BT hLdacParam, void* p_pcm,
+ int* p_pcm_encoded_byte, unsigned char* p_stream,
+ int* pframe_length_wrote, int* pframe_num);
+
+static const char* LDAC_SET_EQMID_NAME = "ldacBT_set_eqmid";
+typedef int (*tLDAC_SET_EQMID)(HANDLE_LDAC_BT hLdacParam, int eqmid);
+
+static const char* LDAC_ALTER_EQMID_PRIORITY_NAME =
+ "ldacBT_alter_eqmid_priority";
+typedef int (*tLDAC_ALTER_EQMID_PRIORITY)(HANDLE_LDAC_BT hLdacParam,
+ int priority);
+
+static const char* LDAC_GET_EQMID_NAME = "ldacBT_get_eqmid";
+typedef int (*tLDAC_GET_EQMID)(HANDLE_LDAC_BT hLdacParam);
+
+static const char* LDAC_GET_ERROR_CODE_NAME = "ldacBT_get_error_code";
+typedef int (*tLDAC_GET_ERROR_CODE)(HANDLE_LDAC_BT hLdacParam);
+
+static tLDAC_GET_HANDLE ldac_get_handle_func;
+static tLDAC_FREE_HANDLE ldac_free_handle_func;
+static tLDAC_CLOSE_HANDLE ldac_close_handle_func;
+static tLDAC_GET_VERSION ldac_get_version_func;
+static tLDAC_GET_BITRATE ldac_get_bitrate_func;
+static tLDAC_GET_SAMPLING_FREQ ldac_get_sampling_freq_func;
+static tLDAC_INIT_HANDLE_ENCODE ldac_init_handle_encode_func;
+static tLDAC_ENCODE ldac_encode_func;
+static tLDAC_SET_EQMID ldac_set_eqmid_func;
+static tLDAC_ALTER_EQMID_PRIORITY ldac_alter_eqmid_priority_func;
+static tLDAC_GET_EQMID ldac_get_eqmid_func;
+static tLDAC_GET_ERROR_CODE ldac_get_error_code_func;
+
+// A2DP LDAC encoder interval in milliseconds
+#define A2DP_LDAC_ENCODER_INTERVAL_MS 20
+#define A2DP_LDAC_MEDIA_BYTES_PER_FRAME 128
+
+// offset
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN + 1)
+#else
+#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN)
+#endif
+
+typedef struct {
+ uint32_t sample_rate;
+ uint8_t channel_mode;
+ uint8_t bits_per_sample;
+ int quality_mode_index;
+ int pcm_wlength;
+ LDACBT_SMPL_FMT_T pcm_fmt;
+} tA2DP_LDAC_ENCODER_PARAMS;
+
+typedef struct {
+ uint32_t counter;
+ uint32_t bytes_per_tick; /* pcm bytes read each media task tick */
+ uint64_t last_frame_us;
+} tA2DP_LDAC_FEEDING_STATE;
+
+typedef struct {
+ uint64_t session_start_us;
+
+ size_t media_read_total_expected_packets;
+ size_t media_read_total_expected_reads_count;
+ size_t media_read_total_expected_read_bytes;
+
+ size_t media_read_total_dropped_packets;
+ size_t media_read_total_actual_reads_count;
+ size_t media_read_total_actual_read_bytes;
+} a2dp_ldac_encoder_stats_t;
+
+typedef struct {
+ a2dp_source_read_callback_t read_callback;
+ a2dp_source_enqueue_callback_t enqueue_callback;
+ uint16_t TxAaMtuSize;
+ size_t TxQueueLength;
+
+ bool use_SCMS_T;
+ bool is_peer_edr; // True if the peer device supports EDR
+ bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
+ uint16_t peer_mtu; // MTU of the A2DP peer
+ uint32_t timestamp; // Timestamp for the A2DP frames
+
+ HANDLE_LDAC_BT ldac_handle;
+ bool has_ldac_handle; // True if ldac_handle is valid
+
+ HANDLE_LDAC_ABR ldac_abr_handle;
+ bool has_ldac_abr_handle;
+ int last_ldac_abr_eqmid;
+ size_t ldac_abr_adjustments;
+
+ tA2DP_FEEDING_PARAMS feeding_params;
+ tA2DP_LDAC_ENCODER_PARAMS ldac_encoder_params;
+ tA2DP_LDAC_FEEDING_STATE ldac_feeding_state;
+
+ a2dp_ldac_encoder_stats_t stats;
+} tA2DP_LDAC_ENCODER_CB;
+
+static bool ldac_abr_loaded = false;
+
+static tA2DP_LDAC_ENCODER_CB a2dp_ldac_encoder_cb;
+
+static void a2dp_vendor_ldac_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated);
+static void a2dp_ldac_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us);
+static void a2dp_ldac_encode_frames(uint8_t nb_frame);
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer);
+static std::string quality_mode_index_to_name(int quality_mode_index);
+
+static void* load_func(const char* func_name) {
+ void* func_ptr = dlsym(ldac_encoder_lib_handle, func_name);
+ if (func_ptr == NULL) {
+ LOG_ERROR(LOG_TAG,
+ "%s: cannot find function '%s' in the encoder library: %s",
+ __func__, func_name, dlerror());
+ A2DP_VendorUnloadEncoderLdac();
+ return NULL;
+ }
+ return func_ptr;
+}
+
+bool A2DP_VendorLoadEncoderLdac(void) {
+ if (ldac_encoder_lib_handle != NULL) return true; // Already loaded
+
+ // Initialize the control block
+ memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb));
+
+ // Open the encoder library
+ ldac_encoder_lib_handle = dlopen(LDAC_ENCODER_LIB_NAME, RTLD_NOW);
+ if (ldac_encoder_lib_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: cannot open LDAC encoder library %s: %s", __func__,
+ LDAC_ENCODER_LIB_NAME, dlerror());
+ return false;
+ }
+
+ // Load all functions
+ ldac_get_handle_func = (tLDAC_GET_HANDLE)load_func(LDAC_GET_HANDLE_NAME);
+ if (ldac_get_handle_func == NULL) return false;
+ ldac_free_handle_func = (tLDAC_FREE_HANDLE)load_func(LDAC_FREE_HANDLE_NAME);
+ if (ldac_free_handle_func == NULL) return false;
+ ldac_close_handle_func =
+ (tLDAC_CLOSE_HANDLE)load_func(LDAC_CLOSE_HANDLE_NAME);
+ if (ldac_close_handle_func == NULL) return false;
+ ldac_get_version_func = (tLDAC_GET_VERSION)load_func(LDAC_GET_VERSION_NAME);
+ if (ldac_get_version_func == NULL) return false;
+ ldac_get_bitrate_func = (tLDAC_GET_BITRATE)load_func(LDAC_GET_BITRATE_NAME);
+ if (ldac_get_bitrate_func == NULL) return false;
+ ldac_get_sampling_freq_func =
+ (tLDAC_GET_SAMPLING_FREQ)load_func(LDAC_GET_SAMPLING_FREQ_NAME);
+ if (ldac_get_sampling_freq_func == NULL) return false;
+ ldac_init_handle_encode_func =
+ (tLDAC_INIT_HANDLE_ENCODE)load_func(LDAC_INIT_HANDLE_ENCODE_NAME);
+ if (ldac_init_handle_encode_func == NULL) return false;
+ ldac_encode_func = (tLDAC_ENCODE)load_func(LDAC_ENCODE_NAME);
+ if (ldac_encode_func == NULL) return false;
+ ldac_set_eqmid_func = (tLDAC_SET_EQMID)load_func(LDAC_SET_EQMID_NAME);
+ if (ldac_set_eqmid_func == NULL) return false;
+ ldac_alter_eqmid_priority_func =
+ (tLDAC_ALTER_EQMID_PRIORITY)load_func(LDAC_ALTER_EQMID_PRIORITY_NAME);
+ if (ldac_alter_eqmid_priority_func == NULL) return false;
+ ldac_get_eqmid_func = (tLDAC_GET_EQMID)load_func(LDAC_GET_EQMID_NAME);
+ if (ldac_get_eqmid_func == NULL) return false;
+ ldac_get_error_code_func =
+ (tLDAC_GET_ERROR_CODE)load_func(LDAC_GET_ERROR_CODE_NAME);
+ if (ldac_get_error_code_func == NULL) return false;
+
+ if (!A2DP_VendorLoadLdacAbr()) {
+ LOG_WARN(LOG_TAG, "%s: cannot load the LDAC ABR library", __func__);
+ ldac_abr_loaded = false;
+ } else {
+ ldac_abr_loaded = true;
+ }
+ return true;
+}
+
+void A2DP_VendorUnloadEncoderLdac(void) {
+ // Cleanup any LDAC-related state
+ if (a2dp_ldac_encoder_cb.has_ldac_handle && ldac_free_handle_func != NULL)
+ ldac_free_handle_func(a2dp_ldac_encoder_cb.ldac_handle);
+ memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb));
+
+ ldac_get_handle_func = NULL;
+ ldac_free_handle_func = NULL;
+ ldac_close_handle_func = NULL;
+ ldac_get_version_func = NULL;
+ ldac_get_bitrate_func = NULL;
+ ldac_get_sampling_freq_func = NULL;
+ ldac_init_handle_encode_func = NULL;
+ ldac_encode_func = NULL;
+ ldac_set_eqmid_func = NULL;
+ ldac_alter_eqmid_priority_func = NULL;
+ ldac_get_eqmid_func = NULL;
+ ldac_get_error_code_func = NULL;
+
+ if (ldac_encoder_lib_handle != NULL) {
+ dlclose(ldac_encoder_lib_handle);
+ ldac_encoder_lib_handle = NULL;
+ }
+}
+
+void a2dp_vendor_ldac_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback) {
+ if (a2dp_ldac_encoder_cb.has_ldac_handle)
+ ldac_free_handle_func(a2dp_ldac_encoder_cb.ldac_handle);
+ if (a2dp_ldac_encoder_cb.has_ldac_abr_handle)
+ a2dp_ldac_abr_free_handle(a2dp_ldac_encoder_cb.ldac_abr_handle);
+ memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb));
+
+ a2dp_ldac_encoder_cb.stats.session_start_us = time_get_os_boottime_us();
+
+ a2dp_ldac_encoder_cb.read_callback = read_callback;
+ a2dp_ldac_encoder_cb.enqueue_callback = enqueue_callback;
+ a2dp_ldac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_ldac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_ldac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_ldac_encoder_cb.timestamp = 0;
+ a2dp_ldac_encoder_cb.ldac_abr_handle = NULL;
+ a2dp_ldac_encoder_cb.has_ldac_abr_handle = false;
+ a2dp_ldac_encoder_cb.last_ldac_abr_eqmid = -1;
+ a2dp_ldac_encoder_cb.ldac_abr_adjustments = 0;
+
+ a2dp_ldac_encoder_cb.use_SCMS_T = false; // TODO: should be a parameter
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ a2dp_ldac_encoder_cb.use_SCMS_T = true;
+#endif
+
+ // NOTE: Ignore the restart_input / restart_output flags - this initization
+ // happens when the connection is (re)started.
+ bool restart_input = false;
+ bool restart_output = false;
+ bool config_updated = false;
+ a2dp_vendor_ldac_encoder_update(a2dp_ldac_encoder_cb.peer_mtu,
+ a2dp_codec_config, &restart_input,
+ &restart_output, &config_updated);
+}
+
+bool A2dpCodecConfigLdac::updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated) {
+ a2dp_ldac_encoder_cb.is_peer_edr = p_peer_params->is_peer_edr;
+ a2dp_ldac_encoder_cb.peer_supports_3mbps = p_peer_params->peer_supports_3mbps;
+ a2dp_ldac_encoder_cb.peer_mtu = p_peer_params->peer_mtu;
+ a2dp_ldac_encoder_cb.timestamp = 0;
+
+ if (a2dp_ldac_encoder_cb.peer_mtu == 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid peer MTU",
+ __func__, name().c_str());
+ return false;
+ }
+
+ a2dp_vendor_ldac_encoder_update(a2dp_ldac_encoder_cb.peer_mtu, this,
+ p_restart_input, p_restart_output,
+ p_config_updated);
+ return true;
+}
+
+// Update the A2DP LDAC encoder.
+// |peer_mtu| is the peer MTU.
+// |a2dp_codec_config| is the A2DP codec to use for the update.
+static void a2dp_vendor_ldac_encoder_update(uint16_t peer_mtu,
+ A2dpCodecConfig* a2dp_codec_config,
+ bool* p_restart_input,
+ bool* p_restart_output,
+ bool* p_config_updated) {
+ tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
+ &a2dp_ldac_encoder_cb.ldac_encoder_params;
+ uint8_t codec_info[AVDT_CODEC_SIZE];
+
+ *p_restart_input = false;
+ *p_restart_output = false;
+ *p_config_updated = false;
+
+ if (!a2dp_ldac_encoder_cb.has_ldac_handle) {
+ a2dp_ldac_encoder_cb.ldac_handle = ldac_get_handle_func();
+ if (a2dp_ldac_encoder_cb.ldac_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: Cannot get LDAC encoder handle", __func__);
+ return; // TODO: Return an error?
+ }
+ a2dp_ldac_encoder_cb.has_ldac_handle = true;
+ }
+
+ if (!a2dp_codec_config->copyOutOtaCodecConfig(codec_info)) {
+ LOG_ERROR(LOG_TAG,
+ "%s: Cannot update the codec encoder for %s: "
+ "invalid codec config",
+ __func__, a2dp_codec_config->name().c_str());
+ return;
+ }
+ const uint8_t* p_codec_info = codec_info;
+ btav_a2dp_codec_config_t codec_config = a2dp_codec_config->getCodecConfig();
+
+ // The feeding parameters
+ tA2DP_FEEDING_PARAMS* p_feeding_params = &a2dp_ldac_encoder_cb.feeding_params;
+ p_feeding_params->sample_rate =
+ A2DP_VendorGetTrackSampleRateLdac(p_codec_info);
+ p_feeding_params->bits_per_sample =
+ a2dp_codec_config->getAudioBitsPerSample();
+ p_feeding_params->channel_count =
+ A2DP_VendorGetTrackChannelCountLdac(p_codec_info);
+ LOG_DEBUG(LOG_TAG, "%s: sample_rate=%u bits_per_sample=%u channel_count=%u",
+ __func__, p_feeding_params->sample_rate,
+ p_feeding_params->bits_per_sample, p_feeding_params->channel_count);
+
+ // The codec parameters
+ p_encoder_params->sample_rate =
+ a2dp_ldac_encoder_cb.feeding_params.sample_rate;
+ p_encoder_params->channel_mode =
+ A2DP_VendorGetChannelModeCodeLdac(p_codec_info);
+
+ uint16_t mtu_size =
+ BT_DEFAULT_BUFFER_SIZE - A2DP_LDAC_OFFSET - sizeof(BT_HDR);
+ if (mtu_size < peer_mtu) {
+ a2dp_ldac_encoder_cb.TxAaMtuSize = mtu_size;
+ } else {
+ a2dp_ldac_encoder_cb.TxAaMtuSize = peer_mtu;
+ }
+
+ // Set the quality mode index
+ int old_quality_mode_index = p_encoder_params->quality_mode_index;
+ if (codec_config.codec_specific_1 != 0) {
+ p_encoder_params->quality_mode_index = codec_config.codec_specific_1 % 10;
+ LOG_DEBUG(LOG_TAG, "%s: setting quality mode to %s", __func__,
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index)
+ .c_str());
+ } else {
+ p_encoder_params->quality_mode_index = A2DP_LDAC_QUALITY_ABR;
+ LOG_DEBUG(LOG_TAG, "%s: setting quality mode to default %s", __func__,
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index)
+ .c_str());
+ }
+
+ int ldac_eqmid = LDAC_ABR_MODE_EQMID;
+ if (p_encoder_params->quality_mode_index == A2DP_LDAC_QUALITY_ABR) {
+ if (!ldac_abr_loaded) {
+ p_encoder_params->quality_mode_index = A2DP_LDAC_QUALITY_MID;
+ LOG_WARN(
+ LOG_TAG,
+ "%s: LDAC ABR library is not loaded, resetting quality mode to %s",
+ __func__,
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index)
+ .c_str());
+ } else {
+ LOG_DEBUG(LOG_TAG, "%s: changing mode from %s to %s", __func__,
+ quality_mode_index_to_name(old_quality_mode_index).c_str(),
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index)
+ .c_str());
+ if (a2dp_ldac_encoder_cb.ldac_abr_handle != NULL) {
+ LOG_DEBUG(LOG_TAG, "%s: already in LDAC ABR mode, do nothing.",
+ __func__);
+ } else {
+ LOG_DEBUG(LOG_TAG, "%s: get and init LDAC ABR handle.", __func__);
+ a2dp_ldac_encoder_cb.ldac_abr_handle = a2dp_ldac_abr_get_handle();
+ if (a2dp_ldac_encoder_cb.ldac_abr_handle != NULL) {
+ a2dp_ldac_encoder_cb.has_ldac_abr_handle = true;
+ a2dp_ldac_encoder_cb.last_ldac_abr_eqmid = -1;
+ a2dp_ldac_encoder_cb.ldac_abr_adjustments = 0;
+ a2dp_ldac_abr_init(a2dp_ldac_encoder_cb.ldac_abr_handle,
+ A2DP_LDAC_ENCODER_INTERVAL_MS);
+ } else {
+ p_encoder_params->quality_mode_index = A2DP_LDAC_QUALITY_MID;
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s: get LDAC ABR handle failed, resetting quality mode to %s.",
+ __func__,
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index)
+ .c_str());
+ }
+ }
+ }
+ } else {
+ ldac_eqmid = p_encoder_params->quality_mode_index;
+ LOG_DEBUG(LOG_TAG, "%s: in %s mode, free LDAC ABR handle.", __func__,
+ quality_mode_index_to_name(ldac_eqmid).c_str());
+ if (a2dp_ldac_encoder_cb.has_ldac_abr_handle) {
+ a2dp_ldac_abr_free_handle(a2dp_ldac_encoder_cb.ldac_abr_handle);
+ a2dp_ldac_encoder_cb.ldac_abr_handle = NULL;
+ a2dp_ldac_encoder_cb.has_ldac_abr_handle = false;
+ a2dp_ldac_encoder_cb.last_ldac_abr_eqmid = -1;
+ a2dp_ldac_encoder_cb.ldac_abr_adjustments = 0;
+ }
+ }
+
+ if (p_encoder_params->quality_mode_index != old_quality_mode_index)
+ *p_config_updated = true;
+
+ p_encoder_params->pcm_wlength =
+ a2dp_ldac_encoder_cb.feeding_params.bits_per_sample >> 3;
+ // Set the Audio format from pcm_wlength
+ p_encoder_params->pcm_fmt = LDACBT_SMPL_FMT_S16;
+ if (p_encoder_params->pcm_wlength == 2)
+ p_encoder_params->pcm_fmt = LDACBT_SMPL_FMT_S16;
+ else if (p_encoder_params->pcm_wlength == 3)
+ p_encoder_params->pcm_fmt = LDACBT_SMPL_FMT_S24;
+ else if (p_encoder_params->pcm_wlength == 4)
+ p_encoder_params->pcm_fmt = LDACBT_SMPL_FMT_S32;
+
+ LOG_DEBUG(LOG_TAG, "%s: MTU=%d, peer_mtu=%d", __func__,
+ a2dp_ldac_encoder_cb.TxAaMtuSize, peer_mtu);
+ LOG_DEBUG(LOG_TAG,
+ "%s: sample_rate: %d channel_mode: %d "
+ "quality_mode_index: %d pcm_wlength: %d pcm_fmt: %d",
+ __func__, p_encoder_params->sample_rate,
+ p_encoder_params->channel_mode,
+ p_encoder_params->quality_mode_index, p_encoder_params->pcm_wlength,
+ p_encoder_params->pcm_fmt);
+
+ // Initialize the encoder.
+ // NOTE: MTU in the initialization must include the AVDT media header size.
+ int result = ldac_init_handle_encode_func(
+ a2dp_ldac_encoder_cb.ldac_handle,
+ a2dp_ldac_encoder_cb.TxAaMtuSize + AVDT_MEDIA_HDR_SIZE, ldac_eqmid,
+ p_encoder_params->channel_mode, p_encoder_params->pcm_fmt,
+ p_encoder_params->sample_rate);
+ if (result != 0) {
+ LOG_ERROR(LOG_TAG, "%s: error initializing the LDAC encoder: %d", __func__,
+ result);
+ }
+}
+
+void a2dp_vendor_ldac_encoder_cleanup(void) {
+ if (a2dp_ldac_encoder_cb.has_ldac_abr_handle)
+ a2dp_ldac_abr_free_handle(a2dp_ldac_encoder_cb.ldac_abr_handle);
+ if (a2dp_ldac_encoder_cb.has_ldac_handle)
+ ldac_free_handle_func(a2dp_ldac_encoder_cb.ldac_handle);
+ memset(&a2dp_ldac_encoder_cb, 0, sizeof(a2dp_ldac_encoder_cb));
+}
+
+void a2dp_vendor_ldac_feeding_reset(void) {
+ /* By default, just clear the entire state */
+ memset(&a2dp_ldac_encoder_cb.ldac_feeding_state, 0,
+ sizeof(a2dp_ldac_encoder_cb.ldac_feeding_state));
+
+ a2dp_ldac_encoder_cb.ldac_feeding_state.bytes_per_tick =
+ (a2dp_ldac_encoder_cb.feeding_params.sample_rate *
+ a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8 *
+ a2dp_ldac_encoder_cb.feeding_params.channel_count *
+ A2DP_LDAC_ENCODER_INTERVAL_MS) /
+ 1000;
+
+ LOG_DEBUG(LOG_TAG, "%s: PCM bytes per tick %u", __func__,
+ a2dp_ldac_encoder_cb.ldac_feeding_state.bytes_per_tick);
+}
+
+void a2dp_vendor_ldac_feeding_flush(void) {
+ a2dp_ldac_encoder_cb.ldac_feeding_state.counter = 0;
+}
+
+period_ms_t a2dp_vendor_ldac_get_encoder_interval_ms(void) {
+ return A2DP_LDAC_ENCODER_INTERVAL_MS;
+}
+
+void a2dp_vendor_ldac_send_frames(uint64_t timestamp_us) {
+ uint8_t nb_frame = 0;
+ uint8_t nb_iterations = 0;
+
+ a2dp_ldac_get_num_frame_iteration(&nb_iterations, &nb_frame, timestamp_us);
+ LOG_VERBOSE(LOG_TAG, "%s: Sending %d frames per iteration, %d iterations",
+ __func__, nb_frame, nb_iterations);
+ if (nb_frame == 0) return;
+
+ for (uint8_t counter = 0; counter < nb_iterations; counter++) {
+ if (a2dp_ldac_encoder_cb.has_ldac_abr_handle) {
+ int flag_enable = 1;
+ int prev_eqmid = a2dp_ldac_encoder_cb.last_ldac_abr_eqmid;
+ a2dp_ldac_encoder_cb.last_ldac_abr_eqmid =
+ a2dp_ldac_abr_proc(a2dp_ldac_encoder_cb.ldac_handle,
+ a2dp_ldac_encoder_cb.ldac_abr_handle,
+ a2dp_ldac_encoder_cb.TxQueueLength, flag_enable);
+ if (prev_eqmid != a2dp_ldac_encoder_cb.last_ldac_abr_eqmid)
+ a2dp_ldac_encoder_cb.ldac_abr_adjustments++;
+ }
+ // Transcode frame and enqueue
+ a2dp_ldac_encode_frames(nb_frame);
+ }
+}
+
+// Obtains the number of frames to send and number of iterations
+// to be used. |num_of_iterations| and |num_of_frames| parameters
+// are used as output param for returning the respective values.
+static void a2dp_ldac_get_num_frame_iteration(uint8_t* num_of_iterations,
+ uint8_t* num_of_frames,
+ uint64_t timestamp_us) {
+ uint32_t result = 0;
+ uint8_t nof = 0;
+ uint8_t noi = 1;
+
+ uint32_t pcm_bytes_per_frame =
+ A2DP_LDAC_MEDIA_BYTES_PER_FRAME *
+ a2dp_ldac_encoder_cb.feeding_params.channel_count *
+ a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8;
+ LOG_VERBOSE(LOG_TAG, "%s: pcm_bytes_per_frame %u", __func__,
+ pcm_bytes_per_frame);
+
+ uint32_t us_this_tick = A2DP_LDAC_ENCODER_INTERVAL_MS * 1000;
+ uint64_t now_us = timestamp_us;
+ if (a2dp_ldac_encoder_cb.ldac_feeding_state.last_frame_us != 0)
+ us_this_tick =
+ (now_us - a2dp_ldac_encoder_cb.ldac_feeding_state.last_frame_us);
+ a2dp_ldac_encoder_cb.ldac_feeding_state.last_frame_us = now_us;
+
+ a2dp_ldac_encoder_cb.ldac_feeding_state.counter +=
+ a2dp_ldac_encoder_cb.ldac_feeding_state.bytes_per_tick * us_this_tick /
+ (A2DP_LDAC_ENCODER_INTERVAL_MS * 1000);
+
+ result =
+ a2dp_ldac_encoder_cb.ldac_feeding_state.counter / pcm_bytes_per_frame;
+ a2dp_ldac_encoder_cb.ldac_feeding_state.counter -=
+ result * pcm_bytes_per_frame;
+ nof = result;
+
+ LOG_VERBOSE(LOG_TAG, "%s: effective num of frames %u, iterations %u",
+ __func__, nof, noi);
+
+ *num_of_frames = nof;
+ *num_of_iterations = noi;
+}
+
+static void a2dp_ldac_encode_frames(uint8_t nb_frame) {
+ tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
+ &a2dp_ldac_encoder_cb.ldac_encoder_params;
+ uint8_t remain_nb_frame = nb_frame;
+ uint16_t ldac_frame_size;
+ uint8_t read_buffer[LDACBT_MAX_LSU * 4 /* byte/sample */ * 2 /* ch */];
+
+ switch (p_encoder_params->sample_rate) {
+ case 176400:
+ case 192000:
+ ldac_frame_size = 512; // sample/ch
+ break;
+ case 88200:
+ case 96000:
+ ldac_frame_size = 256; // sample/ch
+ break;
+ case 44100:
+ case 48000:
+ default:
+ ldac_frame_size = 128; // sample/ch
+ break;
+ }
+
+ uint32_t count;
+ int32_t encode_count = 0;
+ int32_t out_frames = 0;
+ int written = 0;
+
+ while (nb_frame) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ p_buf->offset = A2DP_LDAC_OFFSET;
+ p_buf->len = 0;
+ p_buf->layer_specific = 0;
+ a2dp_ldac_encoder_cb.stats.media_read_total_expected_packets++;
+
+ count = 0;
+ do {
+ //
+ // Read the PCM data and encode it
+ //
+ if (a2dp_ldac_read_feeding(read_buffer)) {
+ uint8_t* packet = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len;
+ if (a2dp_ldac_encoder_cb.ldac_handle == NULL) {
+ LOG_ERROR(LOG_TAG, "%s: invalid LDAC handle", __func__);
+ a2dp_ldac_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ return;
+ }
+ int result = ldac_encode_func(
+ a2dp_ldac_encoder_cb.ldac_handle, read_buffer, (int*)&encode_count,
+ packet + count, (int*)&written, (int*)&out_frames);
+ if (result != 0) {
+ int err_code =
+ ldac_get_error_code_func(a2dp_ldac_encoder_cb.ldac_handle);
+ LOG_ERROR(LOG_TAG,
+ "%s: LDAC encoding error: %d api_error = %d "
+ "handle_error = %d block_error = %d",
+ __func__, result, LDACBT_API_ERR(err_code),
+ LDACBT_HANDLE_ERR(err_code), LDACBT_BLOCK_ERR(err_code));
+ a2dp_ldac_encoder_cb.stats.media_read_total_dropped_packets++;
+ osi_free(p_buf);
+ return;
+ }
+ count += written;
+ p_buf->len += written;
+ nb_frame--;
+ p_buf->layer_specific += out_frames; // added a frame to the buffer
+ } else {
+ LOG_WARN(LOG_TAG, "%s: underflow %d", __func__, nb_frame);
+ a2dp_ldac_encoder_cb.ldac_feeding_state.counter +=
+ nb_frame * LDACBT_ENC_LSU *
+ a2dp_ldac_encoder_cb.feeding_params.channel_count *
+ a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8;
+
+ // no more pcm to read
+ nb_frame = 0;
+ }
+ } while ((written == 0) && nb_frame);
+
+ if (p_buf->len) {
+ /*
+ * Timestamp of the media packet header represent the TS of the
+ * first frame, i.e the timestamp before including this frame.
+ */
+ *((uint32_t*)(p_buf + 1)) = a2dp_ldac_encoder_cb.timestamp;
+
+ a2dp_ldac_encoder_cb.timestamp += p_buf->layer_specific * ldac_frame_size;
+
+ uint8_t done_nb_frame = remain_nb_frame - nb_frame;
+ remain_nb_frame = nb_frame;
+ if (!a2dp_ldac_encoder_cb.enqueue_callback(p_buf, done_nb_frame)) return;
+ } else {
+ // NOTE: Unlike the execution path for other codecs, it is normal for
+ // LDAC to NOT write encoded data to the last buffer if there wasn't
+ // enough data to write to. That data is accumulated internally by
+ // the codec and included in the next iteration. Therefore, here we
+ // don't increment the "media_read_total_dropped_packets" counter.
+ osi_free(p_buf);
+ }
+ }
+}
+
+static bool a2dp_ldac_read_feeding(uint8_t* read_buffer) {
+ uint32_t read_size = LDACBT_ENC_LSU *
+ a2dp_ldac_encoder_cb.feeding_params.channel_count *
+ a2dp_ldac_encoder_cb.feeding_params.bits_per_sample / 8;
+
+ a2dp_ldac_encoder_cb.stats.media_read_total_expected_reads_count++;
+ a2dp_ldac_encoder_cb.stats.media_read_total_expected_read_bytes += read_size;
+
+ /* Read Data from UIPC channel */
+ uint32_t nb_byte_read =
+ a2dp_ldac_encoder_cb.read_callback(read_buffer, read_size);
+ a2dp_ldac_encoder_cb.stats.media_read_total_actual_read_bytes += nb_byte_read;
+
+ if (nb_byte_read < read_size) {
+ if (nb_byte_read == 0) return false;
+
+ /* Fill the unfilled part of the read buffer with silence (0) */
+ memset(((uint8_t*)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
+ nb_byte_read = read_size;
+ }
+ a2dp_ldac_encoder_cb.stats.media_read_total_actual_reads_count++;
+
+ return true;
+}
+
+static std::string quality_mode_index_to_name(int quality_mode_index) {
+ switch (quality_mode_index) {
+ case A2DP_LDAC_QUALITY_HIGH:
+ return "HIGH";
+ case A2DP_LDAC_QUALITY_MID:
+ return "MID";
+ case A2DP_LDAC_QUALITY_LOW:
+ return "LOW";
+ case A2DP_LDAC_QUALITY_ABR:
+ return "ABR";
+ default:
+ return "Unknown";
+ }
+}
+
+void a2dp_vendor_ldac_set_transmit_queue_length(size_t transmit_queue_length) {
+ a2dp_ldac_encoder_cb.TxQueueLength = transmit_queue_length;
+}
+
+period_ms_t A2dpCodecConfigLdac::encoderIntervalMs() const {
+ return a2dp_vendor_ldac_get_encoder_interval_ms();
+}
+
+void A2dpCodecConfigLdac::debug_codec_dump(int fd) {
+ a2dp_ldac_encoder_stats_t* stats = &a2dp_ldac_encoder_cb.stats;
+ tA2DP_LDAC_ENCODER_PARAMS* p_encoder_params =
+ &a2dp_ldac_encoder_cb.ldac_encoder_params;
+
+ A2dpCodecConfig::debug_codec_dump(fd);
+
+ dprintf(fd,
+ " Packet counts (expected/dropped) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_packets,
+ stats->media_read_total_dropped_packets);
+
+ dprintf(fd,
+ " PCM read counts (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_reads_count,
+ stats->media_read_total_actual_reads_count);
+
+ dprintf(fd,
+ " PCM read bytes (expected/actual) : %zu / "
+ "%zu\n",
+ stats->media_read_total_expected_read_bytes,
+ stats->media_read_total_actual_read_bytes);
+
+ dprintf(
+ fd, " LDAC quality mode : %s\n",
+ quality_mode_index_to_name(p_encoder_params->quality_mode_index).c_str());
+
+ dprintf(fd,
+ " LDAC transmission bitrate (Kbps) : %d\n",
+ ldac_get_bitrate_func(a2dp_ldac_encoder_cb.ldac_handle));
+
+ dprintf(fd,
+ " LDAC saved transmit queue length : %zu\n",
+ a2dp_ldac_encoder_cb.TxQueueLength);
+ if (a2dp_ldac_encoder_cb.has_ldac_abr_handle) {
+ dprintf(fd,
+ " LDAC adaptive bit rate encode quality mode index : %d\n",
+ a2dp_ldac_encoder_cb.last_ldac_abr_eqmid);
+ dprintf(fd,
+ " LDAC adaptive bit rate adjustments : %zu\n",
+ a2dp_ldac_encoder_cb.ldac_abr_adjustments);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_api.cc b/mtkbt/code/bt/stack/avct/avct_api.cc
new file mode 100755
index 0000000..2a9a485
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_api.cc
@@ -0,0 +1,430 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains API of the audio/video control transport protocol.
+ *
+ ******************************************************************************/
+
+#include "avct_api.h"
+#include <string.h>
+#include "avct_int.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* Control block for AVCT */
+tAVCT_CB avct_cb;
+
+/*******************************************************************************
+ *
+ * Function AVCT_Register
+ *
+ * Description This is the system level registration function for the
+ * AVCTP protocol. This function initializes AVCTP and
+ * prepares the protocol stack for its use. This function
+ * must be called once by the system or platform using AVCTP
+ * before the other functions of the API an be used.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void AVCT_Register(uint16_t mtu, UNUSED_ATTR uint16_t mtu_br,
+ uint8_t sec_mask) {
+ AVCT_TRACE_API("AVCT_Register");
+
+ /* register PSM with L2CAP */
+ L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_appl);
+
+ /* set security level */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0,
+ 0);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0,
+ 0);
+
+ /* initialize AVCTP data structures */
+ memset(&avct_cb, 0, sizeof(tAVCT_CB));
+
+ /* Include the browsing channel which uses eFCR */
+ L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_br_appl);
+
+ /* AVCTP browsing channel uses the same security service as AVCTP control
+ * channel */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM,
+ 0, 0);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_BR_PSM,
+ 0, 0);
+
+ if (mtu_br < AVCT_MIN_BROWSE_MTU) mtu_br = AVCT_MIN_BROWSE_MTU;
+ avct_cb.mtu_br = mtu_br;
+
+#if defined(AVCT_INITIAL_TRACE_LEVEL)
+ avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
+#else
+ avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+
+ if (mtu < AVCT_MIN_CONTROL_MTU) mtu = AVCT_MIN_CONTROL_MTU;
+ /* store mtu */
+ avct_cb.mtu = mtu;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_Deregister
+ *
+ * Description This function is called to deregister use AVCTP protocol.
+ * It is called when AVCTP is no longer being used by any
+ * application in the system. Before this function can be
+ * called, all connections must be removed with
+ * AVCT_RemoveConn().
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void AVCT_Deregister(void) {
+ AVCT_TRACE_API("AVCT_Deregister");
+
+ /* deregister PSM with L2CAP */
+ L2CA_Deregister(AVCT_PSM);
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_CreateConn
+ *
+ * Description Create an AVCTP connection. There are two types of
+ * connections, initiator and acceptor, as determined by
+ * the p_cc->role parameter. When this function is called to
+ * create an initiator connection, an AVCTP connection to
+ * the peer device is initiated if one does not already exist.
+ * If an acceptor connection is created, the connection waits
+ * passively for an incoming AVCTP connection from a peer
+ * device.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc, BD_ADDR peer_addr) {
+ uint16_t result = AVCT_SUCCESS;
+ tAVCT_CCB* p_ccb;
+ tAVCT_LCB* p_lcb;
+
+ AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
+
+ /* Allocate ccb; if no ccbs, return failure */
+ p_ccb = avct_ccb_alloc(p_cc);
+ if (p_ccb == NULL) {
+ result = AVCT_NO_RESOURCES;
+ } else {
+ /* get handle */
+ *p_handle = avct_ccb_to_idx(p_ccb);
+
+ /* if initiator connection */
+ if (p_cc->role == AVCT_INT) {
+ /* find link; if none allocate a new one */
+ p_lcb = avct_lcb_by_bd(peer_addr);
+ if (p_lcb == NULL) {
+ p_lcb = avct_lcb_alloc(peer_addr);
+ if (p_lcb == NULL) {
+ /* no link resources; free ccb as well */
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_NO_RESOURCES;
+ }
+ }
+ /* check if PID already in use */
+ else if (avct_lcb_has_pid(p_lcb, p_cc->pid)) {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ result = AVCT_PID_IN_USE;
+ }
+
+ if (result == AVCT_SUCCESS) {
+ /* bind lcb to ccb */
+ p_ccb->p_lcb = p_lcb;
+ AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
+ avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT*)&p_ccb);
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_RemoveConn
+ *
+ * Description Remove an AVCTP connection. This function is called when
+ * the application is no longer using a connection. If this
+ * is the last connection to a peer the L2CAP channel for AVCTP
+ * will be closed.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVCT_RemoveConn(uint8_t handle) {
+ uint16_t result = AVCT_SUCCESS;
+ tAVCT_CCB* p_ccb;
+
+ AVCT_TRACE_API("AVCT_RemoveConn");
+
+ /* map handle to ccb */
+ p_ccb = avct_ccb_by_idx(handle);
+ if (p_ccb == NULL) {
+ result = AVCT_BAD_HANDLE;
+ }
+ /* if connection not bound to lcb, dealloc */
+ else if (p_ccb->p_lcb == NULL) {
+ avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ }
+ /* send unbind event to lcb */
+ else {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT,
+ (tAVCT_LCB_EVT*)&p_ccb);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_CreateBrowse
+ *
+ * Description Create an AVCTP Browse channel. There are two types of
+ * connections, initiator and acceptor, as determined by
+ * the role parameter. When this function is called to
+ * create an initiator connection, the Browse channel to
+ * the peer device is initiated if one does not already exist.
+ * If an acceptor connection is created, the connection waits
+ * passively for an incoming AVCTP connection from a peer
+ * device.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role) {
+ uint16_t result = AVCT_SUCCESS;
+ tAVCT_CCB* p_ccb;
+ tAVCT_BCB* p_bcb;
+ int index;
+
+ AVCT_TRACE_API("AVCT_CreateBrowse: %d", role);
+
+ /* map handle to ccb */
+ p_ccb = avct_ccb_by_idx(handle);
+ if (p_ccb == NULL) {
+ return AVCT_BAD_HANDLE;
+ } else {
+ /* mark this CCB as supporting browsing channel */
+ if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0) {
+ p_ccb->allocated |= AVCT_ALOC_BCB;
+ }
+ }
+
+ /* if initiator connection */
+ if (role == AVCT_INT) {
+ /* the link control block must exist before this function is called as INT.
+ */
+ if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0)) {
+ result = AVCT_NOT_OPEN;
+ } else {
+ /* find link; if none allocate a new one */
+ index = p_ccb->p_lcb->allocated;
+ if (index > AVCT_NUM_LINKS) {
+ result = AVCT_BAD_HANDLE;
+ } else {
+ p_bcb = &avct_cb.bcb[index - 1];
+ p_bcb->allocated = index;
+ }
+ }
+
+ if (result == AVCT_SUCCESS) {
+ /* bind bcb to ccb */
+ p_ccb->p_bcb = p_bcb;
+ memcpy(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr, BD_ADDR_LEN);
+ AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT*)&p_ccb);
+ }
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_RemoveBrowse
+ *
+ * Description Remove an AVCTP Browse channel. This function is called
+ * when the application is no longer using a connection. If
+ * this is the last connection to a peer the L2CAP channel for
+ * AVCTP will be closed.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVCT_RemoveBrowse(uint8_t handle) {
+ uint16_t result = AVCT_SUCCESS;
+ tAVCT_CCB* p_ccb;
+
+ AVCT_TRACE_API("AVCT_RemoveBrowse");
+
+ /* map handle to ccb */
+ p_ccb = avct_ccb_by_idx(handle);
+ if (p_ccb == NULL) {
+ result = AVCT_BAD_HANDLE;
+ } else if (p_ccb->p_bcb != NULL)
+ /* send unbind event to bcb */
+ {
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT,
+ (tAVCT_LCB_EVT*)&p_ccb);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_GetBrowseMtu
+ *
+ * Description Get the peer_mtu for the AVCTP Browse channel of the given
+ * connection.
+ *
+ * Returns the peer browsing channel MTU.
+ *
+ ******************************************************************************/
+uint16_t AVCT_GetBrowseMtu(uint8_t handle) {
+ uint16_t peer_mtu = AVCT_MIN_BROWSE_MTU;
+
+ tAVCT_CCB* p_ccb = avct_ccb_by_idx(handle);
+
+ if (p_ccb != NULL && p_ccb->p_bcb != NULL) {
+ peer_mtu = p_ccb->p_bcb->peer_mtu;
+ }
+
+ return peer_mtu;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_GetPeerMtu
+ *
+ * Description Get the peer_mtu for the AVCTP channel of the given
+ * connection.
+ *
+ * Returns the peer MTU size.
+ *
+ ******************************************************************************/
+uint16_t AVCT_GetPeerMtu(uint8_t handle) {
+ uint16_t peer_mtu = L2CAP_DEFAULT_MTU;
+ tAVCT_CCB* p_ccb;
+
+ /* map handle to ccb */
+ p_ccb = avct_ccb_by_idx(handle);
+ if (p_ccb != NULL) {
+ if (p_ccb->p_lcb) {
+ peer_mtu = p_ccb->p_lcb->peer_mtu;
+ }
+ }
+
+ return peer_mtu;
+}
+
+/*******************************************************************************
+ *
+ * Function AVCT_MsgReq
+ *
+ * Description Send an AVCTP message to a peer device. In calling
+ * AVCT_MsgReq(), the application should keep track of the
+ * congestion state of AVCTP as communicated with events
+ * AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
+ * application calls AVCT_MsgReq() when AVCTP is congested
+ * the message may be discarded. The application may make its
+ * first call to AVCT_MsgReq() after it receives an
+ * AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control
+ * channel or AVCT_BROWSE_CONN_CFM_EVT or
+ * AVCT_BROWSE_CONN_IND_EVT on browsing channel.
+ *
+ * p_msg->layer_specific must be set to
+ * AVCT_DATA_CTRL for control channel traffic;
+ * AVCT_DATA_BROWSE for for browse channel traffic.
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr, BT_HDR* p_msg) {
+ uint16_t result = AVCT_SUCCESS;
+ tAVCT_CCB* p_ccb;
+ tAVCT_UL_MSG ul_msg;
+
+ AVCT_TRACE_API("%s", __func__);
+
+ /* verify p_msg parameter */
+ if (p_msg == NULL) {
+ return AVCT_NO_RESOURCES;
+ }
+ AVCT_TRACE_API("%s len: %d layer_specific: %d", __func__, p_msg->len,
+ p_msg->layer_specific);
+
+ /* map handle to ccb */
+ p_ccb = avct_ccb_by_idx(handle);
+ if (p_ccb == NULL) {
+ result = AVCT_BAD_HANDLE;
+ osi_free(p_msg);
+ }
+ /* verify channel is bound to link */
+ else if (p_ccb->p_lcb == NULL) {
+ result = AVCT_NOT_OPEN;
+ osi_free(p_msg);
+ }
+
+ if (result == AVCT_SUCCESS) {
+ ul_msg.p_buf = p_msg;
+ ul_msg.p_ccb = p_ccb;
+ ul_msg.label = label;
+ ul_msg.cr = cr;
+
+ /* send msg event to bcb */
+ if (p_msg->layer_specific == AVCT_DATA_BROWSE) {
+ if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0) {
+ /* BCB channel is not open and not allocated */
+ result = AVCT_BAD_HANDLE;
+ osi_free(p_msg);
+ } else {
+ p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT,
+ (tAVCT_LCB_EVT*)&ul_msg);
+ }
+ }
+ /* send msg event to lcb */
+ else {
+ avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT,
+ (tAVCT_LCB_EVT*)&ul_msg);
+ }
+ }
+ return result;
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_bcb_act.cc b/mtkbt/code/bt/stack/avct/avct_bcb_act.cc
new file mode 100755
index 0000000..abf58fc
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_bcb_act.cc
@@ -0,0 +1,679 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+*
+* Name: avct_bcb_act.cc
+*
+* Description: This module contains action functions of the browsing control
+* state machine.
+*
+ *****************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/* action function list */
+const tAVCT_BCB_ACTION avct_bcb_action[] = {
+ avct_bcb_chnl_open, /* AVCT_LCB_CHNL_OPEN */
+ avct_bcb_chnl_disc, /* AVCT_LCB_CHNL_DISC */
+ avct_bcb_send_msg, /* AVCT_LCB_SEND_MSG */
+ avct_bcb_open_ind, /* AVCT_LCB_OPEN_IND */
+ avct_bcb_open_fail, /* AVCT_LCB_OPEN_FAIL */
+ avct_bcb_close_ind, /* AVCT_LCB_CLOSE_IND */
+ avct_bcb_close_cfm, /* AVCT_LCB_CLOSE_CFM */
+ avct_bcb_msg_ind, /* AVCT_LCB_MSG_IND */
+ avct_bcb_cong_ind, /* AVCT_LCB_CONG_IND */
+ avct_bcb_bind_conn, /* AVCT_LCB_BIND_CONN */
+ avct_bcb_bind_fail, /* AVCT_LCB_BIND_FAIL */
+ avct_bcb_unbind_disc, /* AVCT_LCB_UNBIND_DISC */
+ avct_bcb_chk_disc, /* AVCT_LCB_CHK_DISC */
+ avct_bcb_discard_msg, /* AVCT_LCB_DISCARD_MSG */
+ avct_bcb_dealloc, /* AVCT_LCB_DEALLOC */
+ avct_bcb_free_msg_ind /* AVCT_LCB_FREE_MSG_IND */
+};
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_msg_asmbl
+ *
+ * Description Reassemble incoming message.
+ *
+ *
+ * Returns Pointer to reassembled message; NULL if no message
+ * available.
+ *
+ ******************************************************************************/
+static BT_HDR* avct_bcb_msg_asmbl(UNUSED_ATTR tAVCT_BCB* p_bcb, BT_HDR* p_buf) {
+ uint8_t* p;
+ uint8_t pkt_type;
+
+ /* parse the message header */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ pkt_type = AVCT_PKT_TYPE(p);
+
+ /* must be single packet - can not fragment */
+ if (pkt_type != AVCT_PKT_TYPE_SINGLE) {
+ osi_free_and_reset((void**)&p_buf);
+ AVCT_TRACE_WARNING("Pkt type=%d - fragmentation not allowed. drop it",
+ pkt_type);
+ }
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_chnl_open
+ *
+ * Description Open L2CAP channel to peer
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ uint16_t result = AVCT_RESULT_FAIL;
+ tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
+ tL2CAP_ERTM_INFO ertm_info;
+
+ BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP_BROWSE, 0);
+
+ /* Set the FCR options: Browsing channel mandates ERTM */
+ ertm_info.preferred_mode = avct_l2c_br_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+
+ /* call l2cap connect req */
+ p_bcb->ch_state = AVCT_CH_CONN;
+ p_bcb->ch_lcid =
+ L2CA_ErtmConnectReq(AVCT_BR_PSM, p_lcb->peer_addr, &ertm_info);
+ if (p_bcb->ch_lcid == 0) {
+ /* if connect req failed, send ourselves close event */
+ avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_unbind_disc
+ *
+ * Description call callback with disconnect event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_unbind_disc(UNUSED_ATTR tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ p_data->p_ccb->p_bcb = NULL;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_BROWSE_DISCONN_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_open_ind
+ *
+ * Description Handle an LL_OPEN event.
+ * For the allocated ccb already bound to the bcb, send a
+ * connect event. For the unbound ccb with a new PID, bind that
+ * ccb to the bcb with the same bd_addr and send a connect
+ * event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ tAVCT_CCB* p_ccb_bind = NULL;
+ bool bind = false;
+ tAVCT_UL_MSG ul_msg;
+
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ /* if ccb allocated and */
+ if (p_ccb->allocated) {
+ /* if bound to this bcb send connect confirm event */
+ if (p_ccb->p_bcb == p_bcb) {
+ bind = true;
+ p_ccb_bind = p_ccb;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
+ 0, p_ccb->p_lcb->peer_addr);
+ }
+ /* if unbound acceptor and lcb allocated and bd_addr are the same for bcb
+ and lcb */
+ else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+ (p_ccb->p_lcb != NULL) &&
+ (!memcmp(p_bcb->peer_addr, p_ccb->p_lcb->peer_addr,
+ BD_ADDR_LEN))) {
+ /* bind bcb to ccb and send connect ind event */
+ bind = true;
+ p_ccb_bind = p_ccb;
+ p_ccb->p_bcb = p_bcb;
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT,
+ 0, p_ccb->p_lcb->peer_addr);
+ }
+ }
+ }
+
+ /* if no ccbs bound to this lcb, disconnect */
+ if (bind == false) {
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ return;
+ }
+
+ if (!p_bcb->p_tx_msg || !p_ccb_bind) {
+ return;
+ }
+
+ ul_msg.p_buf = p_bcb->p_tx_msg;
+ ul_msg.p_ccb = p_ccb_bind;
+ ul_msg.label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF);
+ ul_msg.cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8);
+ p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE;
+ p_bcb->p_tx_msg = NULL;
+
+ /* send msg event to bcb */
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT*)&ul_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_open_fail
+ *
+ * Description L2CAP channel open attempt failed. Mark the ccbs
+ * as NULL bcb.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_open_fail(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
+ p_ccb->p_bcb = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_close_ind
+ *
+ * Description L2CAP channel closed by peer. Deallocate any initiator
+ * ccbs on this lcb and send disconnect ind event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_close_ind(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
+
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
+ if (p_ccb->cc.role == AVCT_INT) {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
+ AVCT_BROWSE_DISCONN_CFM_EVT, 0,
+ p_lcb->peer_addr);
+ } else {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
+ AVCT_BROWSE_DISCONN_IND_EVT, 0, NULL);
+ }
+ p_ccb->p_bcb = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_close_cfm
+ *
+ * Description L2CAP channel closed by us. Deallocate any initiator
+ * ccbs on this lcb and send disconnect ind or cfm event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ uint8_t event = 0;
+ /* Whether BCB initiated channel close */
+ bool ch_close = p_bcb->ch_close;
+ tAVCT_CTRL_CBACK* p_cback;
+
+ p_bcb->ch_close = false;
+ p_bcb->allocated = 0;
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
+ /* if this ccb initiated close send disconnect cfm otherwise ind */
+ if (ch_close) {
+ event = AVCT_BROWSE_DISCONN_CFM_EVT;
+ } else {
+ event = AVCT_BROWSE_DISCONN_IND_EVT;
+ }
+
+ p_cback = p_ccb->cc.p_ctrl_cback;
+ p_ccb->p_bcb = NULL;
+ if (p_ccb->p_lcb == NULL) avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
+ (*p_cback)(avct_ccb_to_idx(p_ccb), event, p_data->result,
+ p_bcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_bind_conn
+ *
+ * Description Bind ccb to lcb and send connect cfm event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_bind_conn(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
+ p_data->p_ccb->p_bcb = p_bcb;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_BROWSE_CONN_CFM_EVT, 0,
+ p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_chk_disc
+ *
+ * Description A ccb wants to close; if it is the last ccb on this lcb,
+ * close channel. Otherwise just deallocate and call
+ * callback.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_chk_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ p_bcb->ch_close = avct_bcb_get_last_ccb_index(p_bcb, p_data->p_ccb);
+ if (p_bcb->ch_close) {
+ avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ return;
+ }
+
+ avct_bcb_unbind_disc(p_bcb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_chnl_disc
+ *
+ * Description Disconnect L2CAP channel.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_chnl_disc(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ L2CA_DisconnectReq(p_bcb->ch_lcid);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_bind_fail
+ *
+ * Description Deallocate ccb and call callback with connect event
+ * with failure result.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_bind_fail(UNUSED_ATTR tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ p_data->p_ccb->p_bcb = NULL;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_BROWSE_CONN_CFM_EVT, AVCT_RESULT_FAIL,
+ NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_cong_ind
+ *
+ * Description Handle congestion indication from L2CAP.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ uint8_t event;
+ tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
+
+ /* set event */
+ event =
+ (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT;
+
+ /* send event to all ccbs on this lcb */
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0,
+ p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_discard_msg
+ *
+ * Description Discard a message sent in from the API.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ osi_free_and_reset((void**)&p_bcb->p_tx_msg);
+
+ /* if control channel is up, save the message and open the browsing channel */
+ if (p_data->ul_msg.p_ccb->p_lcb == NULL) {
+ osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
+ return;
+ }
+ p_bcb->p_tx_msg = p_data->ul_msg.p_buf;
+
+ if (p_bcb->p_tx_msg) {
+ p_bcb->p_tx_msg->layer_specific =
+ (p_data->ul_msg.cr << 8) + p_data->ul_msg.label;
+
+ /* the channel is closed, opening or closing - open it again */
+ AVCT_TRACE_DEBUG("ch_state: %d, allocated:%d->%d", p_bcb->ch_state,
+ p_bcb->allocated, p_data->ul_msg.p_ccb->p_lcb->allocated);
+ p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated;
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT,
+ (tAVCT_LCB_EVT*)p_data->ul_msg.p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_send_msg
+ *
+ * Description Build and send an AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ uint16_t curr_msg_len;
+ uint8_t pkt_type = AVCT_PKT_TYPE_SINGLE;
+ uint8_t hdr_len;
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+
+ /* initialize packet type and other stuff */
+ if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) {
+ AVCT_TRACE_ERROR("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__,
+ curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE);
+ osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
+ return;
+ }
+
+ /* set header len */
+ hdr_len = avct_lcb_pkt_type_len[pkt_type];
+ p_buf = p_data->ul_msg.p_buf;
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+
+ p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+ /* send message to L2CAP */
+ L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_free_msg_ind
+ *
+ * Description Discard an incoming AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_free_msg_ind(UNUSED_ATTR tAVCT_BCB* p_bcb,
+ tAVCT_LCB_EVT* p_data) {
+ if (p_data) osi_free_and_reset((void**)&p_data->p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_msg_ind
+ *
+ * Description Handle an incoming AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
+ uint8_t* p;
+ uint8_t label, type, cr_ipid;
+ uint16_t pid;
+ tAVCT_CCB* p_ccb;
+ tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
+
+ if ((p_data == NULL) || (p_data->p_buf == NULL)) {
+ AVCT_TRACE_WARNING("%s p_data is NULL, returning!", __func__);
+ return;
+ }
+
+ /* this p_buf is to be reported through p_msg_cback. The layer_specific
+ * needs to be set properly to indicate that it is received through
+ * browsing channel */
+ p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
+
+ /* reassemble message; if no message available (we received a fragment) return
+ */
+ p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf);
+ if (p_data->p_buf == NULL) {
+ return;
+ }
+
+ p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse header byte */
+ AVCT_PARSE_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID) {
+ AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+ return;
+ }
+
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ p_ccb = avct_lcb_has_pid(p_lcb, pid);
+ if (p_ccb) {
+ /* PID found; send msg up, adjust bt hdr and call msg callback */
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid,
+ p_data->p_buf);
+ return;
+ }
+
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ p_buf->layer_specific = AVCT_DATA_BROWSE;
+ L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_dealloc
+ *
+ * Description Deallocate a browse control block.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avct_bcb_dealloc(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+
+ AVCT_TRACE_DEBUG("%s %d", __func__, p_bcb->allocated);
+
+ for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
+ /* if ccb allocated and */
+ if ((p_ccb->allocated) && (p_ccb->p_bcb == p_bcb)) {
+ p_ccb->p_bcb = NULL;
+ AVCT_TRACE_DEBUG("%s used by ccb: %d", __func__, idx);
+ break;
+ }
+ }
+
+ /* the browsing channel is down. Check if we have pending messages */
+ osi_free_and_reset((void**)&p_bcb->p_tx_msg);
+ memset(p_bcb, 0, sizeof(tAVCT_BCB));
+}
+
+/*******************************************************************************
+ *
+ * Function avct_close_bcb
+ *
+ * Description this function is called right before LCB disconnects.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_close_bcb(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_BCB* p_bcb = avct_bcb_by_lcb(p_lcb);
+ if (p_bcb->allocated) {
+ avct_bcb_event(p_bcb, AVCT_LCB_UL_UNBIND_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_by_bcb
+ *
+ * Description This lookup function finds the lcb for a bcb.
+ *
+ * Returns pointer to the lcb.
+ *
+ ******************************************************************************/
+tAVCT_LCB* avct_lcb_by_bcb(tAVCT_BCB* p_bcb) {
+ return &avct_cb.lcb[p_bcb->allocated - 1];
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_by_lcb
+ *
+ * Description This lookup function finds the bcb for a lcb.
+ *
+ * Returns pointer to the lcb.
+ *
+ ******************************************************************************/
+tAVCT_BCB* avct_bcb_by_lcb(tAVCT_LCB* p_lcb) {
+ return &avct_cb.bcb[p_lcb->allocated - 1];
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_get_last_ccb_index
+ *
+ * Description See if given ccb is only one on the bcb.
+ *
+ *
+ * Returns 0, if ccb is last, (ccb index + 1) otherwise.
+ *
+ ******************************************************************************/
+uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB* p_bcb, tAVCT_CCB* p_ccb_last) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ uint8_t idx = 0;
+
+ for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
+ if (p_ccb != p_ccb_last) return 0;
+ idx = (uint8_t)(i + 1);
+ }
+ }
+ return idx;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_by_lcid
+ *
+ * Description Find the BCB associated with the L2CAP LCID
+ *
+ *
+ * Returns pointer to the lcb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVCT_BCB* avct_bcb_by_lcid(uint16_t lcid) {
+ tAVCT_BCB* p_bcb = &avct_cb.bcb[0];
+ int idx;
+
+ for (idx = 0; idx < AVCT_NUM_LINKS; idx++, p_bcb++) {
+ if (p_bcb->allocated && (p_bcb->ch_lcid == lcid)) {
+ return p_bcb;
+ }
+ }
+
+ /* out of lcbs */
+ AVCT_TRACE_WARNING("No bcb for lcid %x", lcid);
+ return NULL;
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_ccb.cc b/mtkbt/code/bt/stack/avct/avct_ccb.cc
new file mode 100755
index 0000000..2cdd85b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_ccb.cc
@@ -0,0 +1,137 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains functions which operate on the AVCTP connection
+ * control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_target.h"
+#include "bt_types.h"
+
+/*******************************************************************************
+ *
+ * Function avct_ccb_alloc
+ *
+ * Description Allocate a connection control block; copy parameters to ccb.
+ *
+ *
+ * Returns pointer to the ccb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tAVCT_CCB* avct_ccb_alloc(tAVCT_CC* p_cc) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (!p_ccb->allocated) {
+ p_ccb->allocated = AVCT_ALOC_LCB;
+ memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
+ AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_CONN) {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_ccb_dealloc
+ *
+ * Description Deallocate a connection control block and call application
+ * callback.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avct_ccb_dealloc(tAVCT_CCB* p_ccb, uint8_t event, uint16_t result,
+ BD_ADDR bd_addr) {
+ tAVCT_CTRL_CBACK* p_cback = p_ccb->cc.p_ctrl_cback;
+
+ AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
+
+ if (p_ccb->p_bcb == NULL) {
+ memset(p_ccb, 0, sizeof(tAVCT_CCB));
+ } else {
+ /* control channel is down, but the browsing channel is still connected 0
+ * disconnect it now */
+ avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT,
+ (tAVCT_LCB_EVT*)&p_ccb);
+ p_ccb->p_lcb = NULL;
+ }
+
+ if (event != AVCT_NO_EVT) {
+ (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_ccb_to_idx
+ *
+ * Description Given a pointer to an ccb, return its index.
+ *
+ *
+ * Returns Index of ccb.
+ *
+ ******************************************************************************/
+uint8_t avct_ccb_to_idx(tAVCT_CCB* p_ccb) {
+ /* use array arithmetic to determine index */
+ return (uint8_t)(p_ccb - avct_cb.ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_ccb_by_idx
+ *
+ * Description Return ccb pointer based on ccb index (or handle).
+ *
+ *
+ * Returns pointer to the ccb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVCT_CCB* avct_ccb_by_idx(uint8_t idx) {
+ tAVCT_CCB* p_ccb;
+
+ /* verify index */
+ if (idx < AVCT_NUM_CONN) {
+ p_ccb = &avct_cb.ccb[idx];
+
+ /* verify ccb is allocated */
+ if (!p_ccb->allocated) {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("ccb %d not allocated", idx);
+ }
+ } else {
+ p_ccb = NULL;
+ AVCT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_defs.h b/mtkbt/code/bt/stack/avct/avct_defs.h
new file mode 100755
index 0000000..73d4fcf
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_defs.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This contains constants definitions and other information from the AVCTP
+ * specification. This file is intended for use internal to AVCT only.
+ *
+ ******************************************************************************/
+#ifndef AVCT_DEFS_H
+#define AVCT_DEFS_H
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* packet type */
+#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
+#define AVCT_PKT_TYPE_START 1 /* start packet */
+#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
+#define AVCT_PKT_TYPE_END 3 /* end packet */
+
+/* header lengths for different packet types */
+#define AVCT_HDR_LEN_SINGLE 3
+#define AVCT_HDR_LEN_START 4
+#define AVCT_HDR_LEN_CONT 1
+#define AVCT_HDR_LEN_END 1
+
+/* invalid cr+ipid value */
+#define AVCT_CR_IPID_INVALID 1
+
+/*****************************************************************************
+ * message parsing and building macros
+ ****************************************************************************/
+
+#define AVCT_BUILD_HDR(p, label, type, cr_ipid) \
+ *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
+
+#define AVCT_PARSE_HDR(p, label, type, cr_ipid) \
+ do { \
+ (label) = *(p) >> 4; \
+ (type) = (*(p) >> 2) & 3; \
+ (cr_ipid) = *(p)++ & 3; \
+ } while (0)
+
+#define AVCT_PKT_TYPE(p) ((*(p) >> 2) & 3)
+
+#endif /* AVCT_DEFS_H */
diff --git a/mtkbt/code/bt/stack/avct/avct_int.h b/mtkbt/code/bt/stack/avct/avct_int.h
new file mode 100755
index 0000000..9674cbc
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_int.h
@@ -0,0 +1,223 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains interfaces which are internal to AVCTP.
+ *
+ ******************************************************************************/
+#ifndef AVCT_INT_H
+#define AVCT_INT_H
+
+#include "avct_api.h"
+#include "avct_defs.h"
+#include "bt_common.h"
+#include "l2c_api.h"
+#include "osi/include/fixed_queue.h"
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* lcb state machine events */
+enum {
+ AVCT_LCB_UL_BIND_EVT,
+ AVCT_LCB_UL_UNBIND_EVT,
+ AVCT_LCB_UL_MSG_EVT,
+ AVCT_LCB_INT_CLOSE_EVT,
+ AVCT_LCB_LL_OPEN_EVT,
+ AVCT_LCB_LL_CLOSE_EVT,
+ AVCT_LCB_LL_MSG_EVT,
+ AVCT_LCB_LL_CONG_EVT
+};
+
+/* "states" used for L2CAP channel */
+#define AVCT_CH_IDLE 0 /* No connection */
+#define AVCT_CH_CONN 1 /* Waiting for connection confirm */
+#define AVCT_CH_CFG 2 /* Waiting for configuration complete */
+#define AVCT_CH_OPEN 3 /* Channel opened */
+
+/* "no event" indicator used by ccb dealloc */
+#define AVCT_NO_EVT 0xFF
+
+/*****************************************************************************
+ * data types
+ ****************************************************************************/
+/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
+typedef struct {
+ uint16_t peer_mtu; /* peer l2c mtu */
+ uint16_t ch_result; /* L2CAP connection result value */
+ uint16_t ch_lcid; /* L2CAP channel LCID */
+ uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
+ uint8_t state; /* The state machine state */
+ uint8_t ch_state; /* L2CAP channel state */
+ uint8_t ch_flags; /* L2CAP configuration flags */
+} tAVCT_SCB;
+
+/* link control block type */
+typedef struct {
+ uint16_t peer_mtu; /* peer l2c mtu */
+ uint16_t ch_result; /* L2CAP connection result value */
+ uint16_t ch_lcid; /* L2CAP channel LCID */
+ uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
+ uint8_t state; /* The state machine state */
+ uint8_t ch_state; /* L2CAP channel state */
+ uint8_t ch_flags; /* L2CAP configuration flags */
+ BT_HDR* p_rx_msg; /* Message being reassembled */
+ uint16_t conflict_lcid; /* L2CAP channel LCID */
+ BD_ADDR peer_addr; /* BD address of peer */
+ fixed_queue_t* tx_q; /* Transmit data buffer queue */
+ bool cong; /* true, if congested */
+} tAVCT_LCB;
+
+/* browse control block type */
+typedef struct {
+ uint16_t peer_mtu; /* peer l2c mtu */
+ uint16_t ch_result; /* L2CAP connection result value */
+ uint16_t ch_lcid; /* L2CAP channel LCID */
+ uint8_t allocated; /* 0, not allocated. index+1, otherwise. */
+ uint8_t state; /* The state machine state */
+ uint8_t ch_state; /* L2CAP channel state */
+ uint8_t ch_flags; /* L2CAP configuration flags */
+ BT_HDR* p_tx_msg; /* Message to be sent - in case the browsing channel is not
+ open when MsgReg is called */
+ uint8_t ch_close; /* CCB index+1, if CCB initiated channel close */
+ BD_ADDR peer_addr; /* BD address of peer */
+} tAVCT_BCB;
+
+#define AVCT_ALOC_LCB 0x01
+#define AVCT_ALOC_BCB 0x02
+/* connection control block */
+typedef struct {
+ tAVCT_CC cc; /* parameters from connection creation */
+ tAVCT_LCB* p_lcb; /* Associated LCB */
+ tAVCT_BCB* p_bcb; /* associated BCB */
+ bool ch_close; /* Whether CCB initiated channel close */
+ uint8_t allocated; /* Whether LCB/BCB is allocated */
+} tAVCT_CCB;
+
+/* data type associated with UL_MSG_EVT */
+typedef struct {
+ BT_HDR* p_buf;
+ tAVCT_CCB* p_ccb;
+ uint8_t label;
+ uint8_t cr;
+} tAVCT_UL_MSG;
+
+/* union associated with lcb state machine events */
+typedef union {
+ tAVCT_UL_MSG ul_msg;
+ BT_HDR* p_buf;
+ tAVCT_CCB* p_ccb;
+ uint16_t result;
+ bool cong;
+ uint8_t err_code;
+} tAVCT_LCB_EVT;
+
+/* Control block for AVCT */
+typedef struct {
+ tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */
+ tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */
+ tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */
+ uint16_t mtu; /* our L2CAP MTU */
+ uint16_t mtu_br; /* our L2CAP MTU for the Browsing channel */
+ uint8_t trace_level; /* trace level */
+} tAVCT_CB;
+
+/*****************************************************************************
+ * function declarations
+ ****************************************************************************/
+
+/* LCB function declarations */
+extern void avct_lcb_event(tAVCT_LCB* p_lcb, uint8_t event,
+ tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_event(tAVCT_BCB* p_bcb, uint8_t event,
+ tAVCT_LCB_EVT* p_data);
+extern void avct_close_bcb(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern tAVCT_LCB* avct_lcb_by_bcb(tAVCT_BCB* p_bcb);
+extern tAVCT_BCB* avct_bcb_by_lcb(tAVCT_LCB* p_lcb);
+extern uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB* p_bcb,
+ tAVCT_CCB* p_ccb_last);
+extern tAVCT_BCB* avct_bcb_by_lcid(uint16_t lcid);
+extern tAVCT_LCB* avct_lcb_by_bd(BD_ADDR bd_addr);
+extern tAVCT_LCB* avct_lcb_alloc(BD_ADDR bd_addr);
+extern void avct_lcb_dealloc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern tAVCT_LCB* avct_lcb_by_lcid(uint16_t lcid);
+extern tAVCT_CCB* avct_lcb_has_pid(tAVCT_LCB* p_lcb, uint16_t pid);
+extern bool avct_lcb_last_ccb(tAVCT_LCB* p_lcb, tAVCT_CCB* p_ccb_last);
+
+/* LCB action functions */
+extern void avct_lcb_chnl_open(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_unbind_disc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_open_fail(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_close_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_close_cfm(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_bind_conn(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_chk_disc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_chnl_disc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_bind_fail(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_cong_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_discard_msg(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_send_msg(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+extern void avct_lcb_free_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data);
+
+/* BCB action functions */
+typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_unbind_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_open_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_close_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_bind_conn(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_chk_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_chnl_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_bind_fail(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+extern void avct_bcb_free_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+
+extern void avct_bcb_dealloc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data);
+
+extern const tAVCT_BCB_ACTION avct_bcb_action[];
+extern const uint8_t avct_lcb_pkt_type_len[];
+extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
+
+/* CCB function declarations */
+extern tAVCT_CCB* avct_ccb_alloc(tAVCT_CC* p_cc);
+extern void avct_ccb_dealloc(tAVCT_CCB* p_ccb, uint8_t event, uint16_t result,
+ BD_ADDR bd_addr);
+extern uint8_t avct_ccb_to_idx(tAVCT_CCB* p_ccb);
+extern tAVCT_CCB* avct_ccb_by_idx(uint8_t idx);
+
+/*****************************************************************************
+ * global data
+ ****************************************************************************/
+
+/* Main control block */
+extern tAVCT_CB avct_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avct_l2c_appl;
+extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
+
+#endif /* AVCT_INT_H */
diff --git a/mtkbt/code/bt/stack/avct/avct_l2c.cc b/mtkbt/code/bt/stack/avct/avct_l2c.cc
new file mode 100755
index 0000000..2ed077b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_l2c.cc
@@ -0,0 +1,412 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This AVCTP module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE (1 << 0)
+#define AVCT_L2C_CFG_CFM_DONE (1 << 1)
+
+/* callback function declarations */
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id);
+void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_appl = {
+ avct_l2c_connect_ind_cback,
+ avct_l2c_connect_cfm_cback,
+ NULL,
+ avct_l2c_config_ind_cback,
+ avct_l2c_config_cfm_cback,
+ avct_l2c_disconnect_ind_cback,
+ avct_l2c_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_data_ind_cback,
+ avct_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_is_passive
+ *
+ * Description check is the CCB associated with the given LCB was created
+ * as passive
+ *
+ * Returns true, if the given LCB is created as AVCT_PASSIVE
+ *
+ ******************************************************************************/
+static bool avct_l2c_is_passive(tAVCT_LCB* p_lcb) {
+ bool is_passive = false;
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
+ AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
+ if (p_ccb->cc.control & AVCT_PASSIVE) {
+ is_passive = true;
+ break;
+ }
+ }
+ }
+ return is_passive;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_connect_ind_cback
+ *
+ * Description This is the L2CAP connect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ UNUSED_ATTR uint16_t psm, uint8_t id) {
+ tAVCT_LCB* p_lcb;
+ uint16_t result = L2CAP_CONN_OK;
+ tL2CAP_CFG_INFO cfg;
+
+ /* do we already have a channel for this peer? */
+ p_lcb = avct_lcb_by_bd(bd_addr);
+ if (p_lcb == NULL) {
+ /* no, allocate lcb */
+ p_lcb = avct_lcb_alloc(bd_addr);
+ if (p_lcb == NULL) {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ }
+ /* else we already have a channel for this peer */
+ else {
+ if (!avct_l2c_is_passive(p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
+ /* this LCB included CT role - reject */
+ result = L2CAP_CONN_NO_RESOURCES;
+ } else {
+ /* TG role only - accept the connection from CT. move the channel ID to
+ * the conflict list */
+ p_lcb->conflict_lcid = p_lcb->ch_lcid;
+ AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x",
+ p_lcb->conflict_lcid);
+ }
+ }
+
+ if (p_lcb) {
+ AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
+ lcid, result, p_lcb->ch_state);
+ }
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK) {
+ /* store LCID */
+ p_lcb->ch_lcid = lcid;
+
+ /* transition to configuration state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+ }
+
+ if (p_lcb) AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_connect_cfm_cback
+ *
+ * Description This is the L2CAP connect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVCT_LCB* p_lcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ AVCT_TRACE_DEBUG(
+ "avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, "
+ "conflict_lcid:0x%x",
+ lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CONN) {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK) {
+ /* set channel state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = avct_cb.mtu;
+ L2CA_ConfigReq(lcid, &cfg);
+ AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
+ }
+ /* else failure */
+ else {
+ AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x",
+ p_lcb->conflict_lcid);
+ if (p_lcb->conflict_lcid == lcid)
+ p_lcb->conflict_lcid = 0;
+ else
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+ }
+ } else if (p_lcb->conflict_lcid == lcid) {
+ /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
+ AVCT_TRACE_DEBUG(
+ "avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x",
+ p_lcb->ch_state, p_lcb->conflict_lcid);
+ if (result == L2CAP_CONN_OK) {
+ /* just in case the peer also accepts our connection - Send L2CAP
+ * disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ p_lcb->conflict_lcid = 0;
+ }
+ AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_config_cfm_cback
+ *
+ * Description This is the L2CAP config confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVCT_LCB* p_lcb;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
+ lcid, p_lcb->ch_state, p_cfg->result);
+ /* if in correct state */
+ if (p_lcb->ch_state == AVCT_CH_CFG) {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /* else failure */
+ else {
+ AVCT_TRACE_DEBUG(
+ "ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ",
+ p_lcb->ch_state);
+ /* store result value */
+ p_lcb->ch_result = p_cfg->result;
+
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_config_ind_cback
+ *
+ * Description This is the L2CAP config indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVCT_LCB* p_lcb;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid,
+ p_lcb->ch_state);
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present) {
+ p_lcb->peer_mtu = p_cfg->mtu;
+ } else {
+ p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_disconnect_ind_cback
+ *
+ * Description This is the L2CAP disconnect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
+ tAVCT_LCB* p_lcb;
+ uint16_t result = AVCT_RESULT_FAIL;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid,
+ p_lcb->ch_state);
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+ AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_disconnect_cfm_cback
+ *
+ * Description This is the L2CAP disconnect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVCT_LCB* p_lcb;
+ uint16_t res;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ AVCT_TRACE_DEBUG(
+ "avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", lcid,
+ p_lcb->ch_state, result);
+ /* result value may be previously stored */
+ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+ p_lcb->ch_result = 0;
+
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&res);
+ AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_congestion_ind_cback
+ *
+ * Description This is the L2CAP congestion indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
+ tAVCT_LCB* p_lcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT*)&is_congested);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_data_ind_cback
+ *
+ * Description This is the L2CAP data indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
+ tAVCT_LCB* p_lcb;
+
+ AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
+ /* look up lcb for this channel */
+ p_lcb = avct_lcb_by_lcid(lcid);
+ if (p_lcb != NULL) {
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT*)&p_buf);
+ } else /* prevent buffer leak */
+ {
+ AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
+ osi_free(p_buf);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_l2c_br.cc b/mtkbt/code/bt/stack/avct/avct_l2c_br.cc
new file mode 100755
index 0000000..4538650
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_l2c_br.cc
@@ -0,0 +1,417 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Name: avct_l2c_br.cc
+ *
+ * Description: This AVCTP module interfaces to L2CAP
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define AVCT_L2C_CFG_IND_DONE (1 << 0)
+#define AVCT_L2C_CFG_CFM_DONE (1 << 1)
+
+/* AVCTP Browsing channel FCR Option:
+ * Size of the transmission window when using enhanced retransmission mode. Not
+ * used in basic and streaming modes. Range: 1 - 63
+ */
+#define AVCT_BR_FCR_OPT_TX_WINDOW_SIZE 10
+
+/* AVCTP Browsing channel FCR Option:
+ * Number of transmission attempts for a single I-Frame before taking
+ * Down the connection. Used In ERTM mode only. Value is Ignored in basic and
+ * Streaming modes.
+ * Range: 0, 1-0xFF
+ * 0 - infinite retransmissions
+ * 1 - single transmission
+ */
+#define AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT 20
+
+/* AVCTP Browsing channel FCR Option: Retransmission Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost I-Frames. Only used in Enhanced
+ * retransmission mode.
+ * Range: Minimum 2000 (2 secs) when supporting PBF.
+ */
+#define AVCT_BR_FCR_OPT_RETX_TOUT 2000
+
+/* AVCTP Browsing channel FCR Option: Monitor Timeout
+ * The AVRCP specification set a value in the range of 300 - 2000 ms
+ * Timeout (in msecs) to detect Lost S-Frames. Only used in Enhanced
+ * retransmission mode.
+ * Range: Minimum 12000 (12 secs) when supporting PBF.
+ */
+#define AVCT_BR_FCR_OPT_MONITOR_TOUT 12000
+
+/* callback function declarations */
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id);
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avct_l2c_br_appl = {
+ avct_l2c_br_connect_ind_cback,
+ avct_l2c_br_connect_cfm_cback,
+ NULL,
+ avct_l2c_br_config_ind_cback,
+ avct_l2c_br_config_cfm_cback,
+ avct_l2c_br_disconnect_ind_cback,
+ avct_l2c_br_disconnect_cfm_cback,
+ NULL,
+ avct_l2c_br_data_ind_cback,
+ avct_l2c_br_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/* Browsing channel eL2CAP default options */
+const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for Browsing channel */
+ AVCT_BR_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ AVCT_BR_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
+ disconnecting */
+ AVCT_BR_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ AVCT_BR_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ L2CAP_DEFAULT_ERM_MPS /* MPS segment size */
+};
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_connect_ind_cback
+ *
+ * Description This is the L2CAP connect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ UNUSED_ATTR uint16_t psm, uint8_t id) {
+ tAVCT_LCB* p_lcb;
+ uint16_t result = L2CAP_CONN_NO_RESOURCES;
+ tL2CAP_CFG_INFO cfg;
+ tAVCT_BCB* p_bcb;
+ tL2CAP_ERTM_INFO ertm_info;
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+
+ p_lcb = avct_lcb_by_bd(bd_addr);
+ if (p_lcb != NULL) {
+ /* control channel exists */
+ p_bcb = avct_bcb_by_lcb(p_lcb);
+ memcpy(p_bcb->peer_addr, bd_addr, BD_ADDR_LEN);
+
+ if (p_bcb->allocated == 0) {
+ /* browsing channel does not exist yet and the browsing channel is
+ * registered
+ * - accept connection */
+ p_bcb->allocated = p_lcb->allocated; /* copy the index from lcb */
+
+ result = L2CAP_CONN_OK;
+ cfg.mtu = avct_cb.mtu_br;
+
+ cfg.fcr_present = true;
+ cfg.fcr = avct_l2c_br_fcr_opts_def;
+ }
+ }
+ /* else no control channel yet, reject */
+
+ /* Set the FCR options: Browsing channel mandates ERTM */
+ ertm_info.preferred_mode = cfg.fcr.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+ ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
+
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, 0, &ertm_info);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK) {
+ /* store LCID */
+ p_bcb->ch_lcid = lcid;
+
+ /* transition to configuration state */
+ p_bcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_connect_cfm_cback
+ *
+ * Description This is the L2CAP connect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_connect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVCT_BCB* p_lcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CONN)) return;
+
+ if (result != L2CAP_CONN_OK) {
+ /* failure */
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+ return;
+ }
+
+ /* result is successful */
+ /* set channel state */
+ p_lcb->ch_state = AVCT_CH_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = true;
+ cfg.mtu = avct_cb.mtu_br;
+
+ cfg.fcr_present = true;
+ cfg.fcr = avct_l2c_br_fcr_opts_def;
+
+ L2CA_ConfigReq(lcid, &cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_config_cfm_cback
+ *
+ * Description This is the L2CAP config confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVCT_BCB* p_lcb;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if ((p_lcb == NULL) || (p_lcb->ch_state != AVCT_CH_CFG)) return;
+
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+ /* else failure */
+ else {
+ /* store result value */
+ p_lcb->ch_result = p_cfg->result;
+
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_config_ind_cback
+ *
+ * Description This is the L2CAP config indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVCT_BCB* p_lcb;
+ uint16_t max_mtu = BT_DEFAULT_BUFFER_SIZE - L2CAP_MIN_OFFSET - BT_HDR_SIZE;
+
+ /* Don't include QoS nor flush timeout in the response since we
+ currently always accept these values. Note: fcr_present is left
+ untouched since l2cap negotiates this internally
+ */
+ p_cfg->flush_to_present = false;
+ p_cfg->qos_present = false;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if (p_lcb == NULL) return;
+
+ /* store the mtu in tbl */
+ p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
+ if (p_cfg->mtu_present) {
+ p_lcb->peer_mtu = p_cfg->mtu;
+ }
+
+ if (p_lcb->peer_mtu > max_mtu) {
+ p_lcb->peer_mtu = p_cfg->mtu = max_mtu;
+
+ /* Must tell the peer what the adjusted value is */
+ p_cfg->mtu_present = true;
+ } else /* Don't include in the response */
+ p_cfg->mtu_present = false;
+
+ AVCT_TRACE_DEBUG("%s peer_mtu:%d use:%d", __func__, p_lcb->peer_mtu, max_mtu);
+
+ if (p_lcb->peer_mtu >= AVCT_MIN_BROWSE_MTU)
+ p_cfg->result = L2CAP_CFG_OK;
+ else {
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ p_cfg->mtu_present = true;
+ p_cfg->mtu = AVCT_MIN_BROWSE_MTU;
+ }
+
+ /* send L2CAP configure response */
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ if (p_cfg->result != L2CAP_CFG_OK) {
+ return;
+ }
+
+ /* if first config ind */
+ if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
+ /* update flags */
+ p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
+ p_lcb->ch_state = AVCT_CH_OPEN;
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_disconnect_ind_cback
+ *
+ * Description This is the L2CAP disconnect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
+ tAVCT_BCB* p_lcb;
+ uint16_t result = AVCT_RESULT_FAIL;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if (p_lcb == NULL) return;
+
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_disconnect_cfm_cback
+ *
+ * Description This is the L2CAP disconnect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVCT_BCB* p_lcb;
+ uint16_t res;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if (p_lcb == NULL) return;
+
+ /* result value may be previously stored */
+ res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
+ p_lcb->ch_result = 0;
+
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&res);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_congestion_ind_cback
+ *
+ * Description This is the L2CAP congestion indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_congestion_ind_cback(uint16_t lcid, bool is_congested) {
+ tAVCT_BCB* p_lcb;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if (p_lcb == NULL) return;
+
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT*)&is_congested);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_l2c_br_data_ind_cback
+ *
+ * Description This is the L2CAP data indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avct_l2c_br_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
+ tAVCT_BCB* p_lcb;
+ tAVCT_LCB_EVT evt_data;
+
+ /* look up lcb for this channel */
+ p_lcb = avct_bcb_by_lcid(lcid);
+ if (p_lcb == NULL) {
+ /* prevent buffer leak */
+ osi_free(p_buf);
+ return;
+ }
+
+ evt_data.p_buf = p_buf;
+ avct_bcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, &evt_data);
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_lcb.cc b/mtkbt/code/bt/stack/avct/avct_lcb.cc
new file mode 100755
index 0000000..f13dc73
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_lcb.cc
@@ -0,0 +1,394 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the link control state machine and functions which
+ * operate on the link control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * state machine constants and types
+ ****************************************************************************/
+
+/* verbose state strings for trace */
+const char* const avct_lcb_st_str[] = {"LCB_IDLE_ST", "LCB_OPENING_ST",
+ "LCB_OPEN_ST", "LCB_CLOSING_ST"};
+
+/* verbose event strings for trace */
+const char* const avct_lcb_evt_str[] = {
+ "UL_BIND_EVT", "UL_UNBIND_EVT", "UL_MSG_EVT", "INT_CLOSE_EVT",
+ "LL_OPEN_EVT", "LL_CLOSE_EVT", "LL_MSG_EVT", "LL_CONG_EVT"};
+
+/* lcb state machine states */
+enum {
+ AVCT_LCB_IDLE_ST,
+ AVCT_LCB_OPENING_ST,
+ AVCT_LCB_OPEN_ST,
+ AVCT_LCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVCT_LCB_CHNL_OPEN,
+ AVCT_LCB_CHNL_DISC,
+ AVCT_LCB_SEND_MSG,
+ AVCT_LCB_OPEN_IND,
+ AVCT_LCB_OPEN_FAIL,
+ AVCT_LCB_CLOSE_IND,
+ AVCT_LCB_CLOSE_CFM,
+ AVCT_LCB_MSG_IND,
+ AVCT_LCB_CONG_IND,
+ AVCT_LCB_BIND_CONN,
+ AVCT_LCB_BIND_FAIL,
+ AVCT_LCB_UNBIND_DISC,
+ AVCT_LCB_CHK_DISC,
+ AVCT_LCB_DISCARD_MSG,
+ AVCT_LCB_DEALLOC,
+ AVCT_LCB_FREE_MSG_IND,
+ AVCT_LCB_NUM_ACTIONS
+};
+
+#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB* p_ccb, tAVCT_LCB_EVT* p_data);
+
+/* action function list */
+const tAVCT_LCB_ACTION avct_lcb_action[] = {
+ avct_lcb_chnl_open, avct_lcb_chnl_disc, avct_lcb_send_msg,
+ avct_lcb_open_ind, avct_lcb_open_fail, avct_lcb_close_ind,
+ avct_lcb_close_cfm, avct_lcb_msg_ind, avct_lcb_cong_ind,
+ avct_lcb_bind_conn, avct_lcb_bind_fail, avct_lcb_unbind_disc,
+ avct_lcb_chk_disc, avct_lcb_discard_msg, avct_lcb_dealloc,
+ avct_lcb_free_msg_ind};
+
+/* state table information */
+#define AVCT_LCB_ACTIONS 2 /* number of actions */
+#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
+#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* UL_BIND */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+ /* UL_UNBIND */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+ /* UL_MSG */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+ /* INT_CLOSE */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+ /* LL_OPEN */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* LL_CLOSE */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+ /* LL_MSG */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
+ /* LL_CONG */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}};
+
+/* state table for opening state */
+const uint8_t avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* UL_BIND */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+ /* UL_UNBIND */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE,
+ AVCT_LCB_OPENING_ST},
+ /* UL_MSG */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+ /* INT_CLOSE */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* LL_OPEN */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* LL_CLOSE */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+ /* LL_MSG */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
+ /* LL_CONG */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* UL_BIND */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* UL_UNBIND */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* UL_MSG */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* INT_CLOSE */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* LL_OPEN */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* LL_CLOSE */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+ /* LL_MSG */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
+ /* LL_CONG */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
+ /* Event Action 1 Action 2 Next state */
+ /* UL_BIND */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* UL_UNBIND */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* UL_MSG */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* INT_CLOSE */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* LL_OPEN */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* LL_CLOSE */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
+ /* LL_MSG */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
+ /* LL_CONG */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
+
+/* state table */
+const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
+ avct_lcb_st_idle, avct_lcb_st_opening, avct_lcb_st_open,
+ avct_lcb_st_closing};
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_event
+ *
+ * Description State machine event handling function for lcb
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_event(tAVCT_LCB* p_lcb, uint8_t event, tAVCT_LCB_EVT* p_data) {
+ tAVCT_LCB_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated,
+ avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_lcb->state];
+
+ /* set next state */
+ p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != AVCT_LCB_IGNORE) {
+ (*avct_lcb_action[action])(p_lcb, p_data);
+ } else {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_bcb_event
+ *
+ * Description State machine event handling function for lcb
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_bcb_event(tAVCT_BCB* p_bcb, uint8_t event, tAVCT_LCB_EVT* p_data) {
+ tAVCT_LCB_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+ AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated,
+ avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
+
+ /* look up the state table for the current state */
+ state_table = avct_lcb_st_tbl[p_bcb->state];
+
+ /* set next state */
+ p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
+
+ /* execute action functions */
+ for (i = 0; i < AVCT_LCB_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != AVCT_LCB_IGNORE) {
+ (*avct_bcb_action[action])(p_bcb, p_data);
+ } else {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_by_bd
+ *
+ * Description This lookup function finds the lcb for a BD address.
+ *
+ *
+ * Returns pointer to the lcb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVCT_LCB* avct_lcb_by_bd(BD_ADDR bd_addr) {
+ tAVCT_LCB* p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
+ /* if allocated lcb has matching lcb */
+ if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN))) {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS) {
+ /* if no lcb found */
+ p_lcb = NULL;
+
+ AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_alloc
+ *
+ * Description Allocate a link control block.
+ *
+ *
+ * Returns pointer to the lcb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tAVCT_LCB* avct_lcb_alloc(BD_ADDR bd_addr) {
+ tAVCT_LCB* p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
+ if (!p_lcb->allocated) {
+ p_lcb->allocated = (uint8_t)(i + 1);
+ memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
+ AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
+ p_lcb->tx_q = fixed_queue_new(SIZE_MAX);
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS) {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING("Out of lcbs");
+ }
+ return p_lcb;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_dealloc
+ *
+ * Description Deallocate a link control block.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avct_lcb_dealloc(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ AVCT_TRACE_DEBUG("%s allocated: %d", __func__, p_lcb->allocated);
+
+ // Check if the LCB is still referenced
+
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ for (size_t i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && p_ccb->p_lcb == p_lcb) {
+ AVCT_TRACE_DEBUG("%s LCB in use; lcb index: %d", __func__, i);
+ return;
+ }
+ }
+
+ // If not, de-allocate now...
+
+ AVCT_TRACE_DEBUG("%s Freeing LCB", __func__);
+ osi_free(p_lcb->p_rx_msg);
+ fixed_queue_free(p_lcb->tx_q, NULL);
+ memset(p_lcb, 0, sizeof(tAVCT_LCB));
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_by_lcid
+ *
+ * Description Find the LCB associated with the L2CAP LCID
+ *
+ *
+ * Returns pointer to the lcb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVCT_LCB* avct_lcb_by_lcid(uint16_t lcid) {
+ tAVCT_LCB* p_lcb = &avct_cb.lcb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
+ if (p_lcb->allocated &&
+ ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid))) {
+ break;
+ }
+ }
+
+ if (i == AVCT_NUM_LINKS) {
+ /* out of lcbs */
+ p_lcb = NULL;
+ AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
+ }
+
+ return p_lcb;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_has_pid
+ *
+ * Description See if any ccbs on this lcb have a particular pid.
+ *
+ *
+ * Returns Pointer to CCB if PID found, NULL otherwise.
+ *
+ ******************************************************************************/
+tAVCT_CCB* avct_lcb_has_pid(tAVCT_LCB* p_lcb, uint16_t pid) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid)) {
+ return p_ccb;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_last_ccb
+ *
+ * Description See if given ccb is only one on the lcb.
+ *
+ *
+ * Returns true if ccb is last, false otherwise.
+ *
+ ******************************************************************************/
+bool avct_lcb_last_ccb(tAVCT_LCB* p_lcb, tAVCT_CCB* p_ccb_last) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ AVCT_TRACE_WARNING("avct_lcb_last_ccb");
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ AVCT_TRACE_WARNING("%x: aloc:%d, lcb:0x%x/0x%x, ccb:0x%x/0x%x", i,
+ p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb,
+ p_ccb_last);
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/mtkbt/code/bt/stack/avct/avct_lcb_act.cc b/mtkbt/code/bt/stack/avct/avct_lcb_act.cc
new file mode 100755
index 0000000..9731780
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avct/avct_lcb_act.cc
@@ -0,0 +1,634 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains action functions of the link control state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avct_api.h"
+#include "avct_int.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "osi/include/osi.h"
+
+/* packet header length lookup table */
+const uint8_t avct_lcb_pkt_type_len[] = {AVCT_HDR_LEN_SINGLE,
+ AVCT_HDR_LEN_START, AVCT_HDR_LEN_CONT,
+ AVCT_HDR_LEN_END};
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_msg_asmbl
+ *
+ * Description Reassemble incoming message.
+ *
+ *
+ * Returns Pointer to reassembled message; NULL if no message
+ * available.
+ *
+ ******************************************************************************/
+static BT_HDR* avct_lcb_msg_asmbl(tAVCT_LCB* p_lcb, BT_HDR* p_buf) {
+ uint8_t* p;
+ uint8_t pkt_type;
+ BT_HDR* p_ret;
+
+ /* parse the message header */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ pkt_type = AVCT_PKT_TYPE(p);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avct_lcb_pkt_type_len[pkt_type]) {
+ osi_free(p_buf);
+ AVCT_TRACE_WARNING("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVCT_PKT_TYPE_SINGLE) {
+ /* if reassembly in progress drop message and process new single */
+ if (p_lcb->p_rx_msg != NULL)
+ AVCT_TRACE_WARNING("Got single during reassembly");
+
+ osi_free_and_reset((void**)&p_lcb->p_rx_msg);
+
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVCT_PKT_TYPE_START) {
+ /* if reassembly in progress drop message and process new start */
+ if (p_lcb->p_rx_msg != NULL)
+ AVCT_TRACE_WARNING("Got start during reassembly");
+
+ osi_free(p_lcb->p_rx_msg);
+
+ /*
+ * Allocate bigger buffer for reassembly. As lower layers are
+ * not aware of possible packet size after reassembly, they
+ * would have allocated smaller buffer.
+ */
+ p_lcb->p_rx_msg = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ memcpy(p_lcb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
+
+ /* Free original buffer */
+ osi_free(p_buf);
+
+ /* update p to point to new buffer */
+ p = (uint8_t*)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_lcb->p_rx_msg->len -= 1;
+
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else {
+ /* if no reassembly in progress drop message */
+ if (p_lcb->p_rx_msg == NULL) {
+ osi_free(p_buf);
+ AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ } else {
+ /* get size of buffer holding assembled message */
+ /*
+ * NOTE: The buffer is allocated above at the beginning of the
+ * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+ */
+ uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVCT_HDR_LEN_CONT;
+ p_buf->len -= AVCT_HDR_LEN_CONT;
+
+ /* verify length */
+ if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) {
+ /* won't fit; free everything */
+ AVCT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
+ osi_free_and_reset((void**)&p_lcb->p_rx_msg);
+ osi_free(p_buf);
+ p_ret = NULL;
+ } else {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((uint8_t*)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVCT_PKT_TYPE_END) {
+ p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = p_lcb->p_rx_msg;
+ p_lcb->p_rx_msg = NULL;
+ } else {
+ p_lcb->p_rx_msg->offset += p_buf->len;
+ p_lcb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ osi_free(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_chnl_open
+ *
+ * Description Open L2CAP channel to peer
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_chnl_open(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ uint16_t result = AVCT_RESULT_FAIL;
+
+ BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
+ /* call l2cap connect req */
+ p_lcb->ch_state = AVCT_CH_CONN;
+ p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr);
+ if (p_lcb->ch_lcid == 0) {
+ /* if connect req failed, send ourselves close event */
+ avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT*)&result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_unbind_disc
+ *
+ * Description Deallocate ccb and call callback with disconnect event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_unbind_disc(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_open_ind
+ *
+ * Description Handle an LL_OPEN event. For each allocated ccb already
+ * bound to this lcb, send a connect event. For each
+ * unbound ccb with a new PID, bind that ccb to this lcb and
+ * send a connect event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_open_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+ bool bind = false;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ /* if ccb allocated and */
+ if (p_ccb->allocated) {
+ /* if bound to this lcb send connect confirm event */
+ if (p_ccb->p_lcb == p_lcb) {
+ bind = true;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, 0,
+ p_lcb->peer_addr);
+ }
+ /* if unbound acceptor and lcb doesn't already have a ccb for this PID */
+ else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
+ (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL)) {
+ /* bind ccb to lcb and send connect ind event */
+ bind = true;
+ p_ccb->p_lcb = p_lcb;
+ L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
+ p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, 0,
+ p_lcb->peer_addr);
+ }
+ }
+ }
+
+ /* if no ccbs bound to this lcb, disconnect */
+ if (bind == false) {
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_open_fail
+ *
+ * Description L2CAP channel open attempt failed. Deallocate any ccbs
+ * on this lcb and send connect confirm event with failure.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_open_fail(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
+ avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT, p_data->result,
+ p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_close_ind
+ *
+ * Description L2CAP channel closed by peer. Deallocate any initiator
+ * ccbs on this lcb and send disconnect ind event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_close_ind(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
+ if (p_ccb->cc.role == AVCT_INT) {
+ avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT, 0, p_lcb->peer_addr);
+ } else {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
+ AVCT_DISCONNECT_IND_EVT, 0, p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_close_cfm
+ *
+ * Description L2CAP channel closed by us. Deallocate any initiator
+ * ccbs on this lcb and send disconnect ind or cfm event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_close_cfm(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+ uint8_t event;
+
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
+ /* if this ccb initiated close send disconnect cfm otherwise ind */
+ if (p_ccb->ch_close) {
+ p_ccb->ch_close = false;
+ event = AVCT_DISCONNECT_CFM_EVT;
+ } else {
+ event = AVCT_DISCONNECT_IND_EVT;
+ }
+
+ if (p_ccb->cc.role == AVCT_INT) {
+ avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
+ } else {
+ p_ccb->p_lcb = NULL;
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, p_data->result,
+ p_lcb->peer_addr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_bind_conn
+ *
+ * Description Bind ccb to lcb and send connect cfm event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_bind_conn(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ p_data->p_ccb->p_lcb = p_lcb;
+ (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
+ AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_chk_disc
+ *
+ * Description A ccb wants to close; if it is the last ccb on this lcb,
+ * close channel. Otherwise just deallocate and call
+ * callback.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_chk_disc(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ AVCT_TRACE_WARNING("%s", __func__);
+
+ avct_close_bcb(p_lcb, p_data);
+ if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb)) {
+ AVCT_TRACE_WARNING("%s: closing", __func__);
+ p_data->p_ccb->ch_close = true;
+ avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
+ } else {
+ AVCT_TRACE_WARNING("%s: dealloc ccb", __func__);
+ avct_lcb_unbind_disc(p_lcb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_chnl_disc
+ *
+ * Description Disconnect L2CAP channel.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_chnl_disc(tAVCT_LCB* p_lcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
+ L2CA_DisconnectReq(p_lcb->ch_lcid);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_bind_fail
+ *
+ * Description Deallocate ccb and call callback with connect event
+ * with failure result.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_bind_fail(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_cong_ind
+ *
+ * Description Handle congestion indication from L2CAP.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_cong_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
+ int i;
+ uint8_t event;
+ BT_HDR* p_buf;
+
+ /* set event */
+ event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
+ p_lcb->cong = p_data->cong;
+ if (p_lcb->cong == false && !fixed_queue_is_empty(p_lcb->tx_q)) {
+ while (!p_lcb->cong &&
+ (p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_lcb->tx_q)) != NULL) {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
+ p_lcb->cong = true;
+ }
+ }
+ }
+
+ /* send event to all ccbs on this lcb */
+ for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
+ if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
+ (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0,
+ p_lcb->peer_addr);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_discard_msg
+ *
+ * Description Discard a message sent in from the API.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_discard_msg(UNUSED_ATTR tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ AVCT_TRACE_WARNING("%s Dropping message", __func__);
+ osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_send_msg
+ *
+ * Description Build and send an AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_send_msg(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ uint16_t curr_msg_len;
+ uint8_t pkt_type;
+ uint8_t hdr_len;
+ uint8_t* p;
+ uint8_t nosp = 0; /* number of subsequent packets */
+ uint16_t temp;
+ uint16_t buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
+
+ /* store msg len */
+ curr_msg_len = p_data->ul_msg.p_buf->len;
+
+ /* initialize packet type and other stuff */
+ if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) {
+ pkt_type = AVCT_PKT_TYPE_SINGLE;
+ } else {
+ pkt_type = AVCT_PKT_TYPE_START;
+ temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
+ nosp = temp / (p_lcb->peer_mtu - 1) + 1;
+ if ((temp % (p_lcb->peer_mtu - 1)) != 0) nosp++;
+ }
+
+ /* while we haven't sent all packets */
+ while (curr_msg_len != 0) {
+ BT_HDR* p_buf;
+
+ /* set header len */
+ hdr_len = avct_lcb_pkt_type_len[pkt_type];
+
+ /* if remaining msg must be fragmented */
+ if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len)) {
+ /* get a new buffer for fragment we are sending */
+ p_buf = (BT_HDR*)osi_malloc(buf_size);
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_lcb->peer_mtu - hdr_len;
+
+ memcpy(
+ (uint8_t*)(p_buf + 1) + p_buf->offset,
+ (uint8_t*)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset,
+ p_buf->len);
+
+ p_data->ul_msg.p_buf->offset += p_buf->len;
+ p_data->ul_msg.p_buf->len -= p_buf->len;
+ } else {
+ p_buf = p_data->ul_msg.p_buf;
+ }
+
+ curr_msg_len -= p_buf->len;
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
+ if (pkt_type == AVCT_PKT_TYPE_START) {
+ UINT8_TO_STREAM(p, nosp);
+ }
+ if ((pkt_type == AVCT_PKT_TYPE_START) ||
+ (pkt_type == AVCT_PKT_TYPE_SINGLE)) {
+ UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
+ }
+
+ if (p_lcb->cong == true) {
+ fixed_queue_enqueue(p_lcb->tx_q, p_buf);
+ }
+
+ /* send message to L2CAP */
+ else {
+ if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
+ p_lcb->cong = true;
+ }
+ }
+
+ /* update pkt type for next packet */
+ if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END)) {
+ pkt_type = AVCT_PKT_TYPE_CONT;
+ } else {
+ pkt_type = AVCT_PKT_TYPE_END;
+ }
+ }
+ AVCT_TRACE_DEBUG("%s tx_q_count:%d", __func__,
+ fixed_queue_length(p_lcb->tx_q));
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_free_msg_ind
+ *
+ * Description Discard an incoming AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_free_msg_ind(UNUSED_ATTR tAVCT_LCB* p_lcb,
+ tAVCT_LCB_EVT* p_data) {
+ if (p_data == NULL) return;
+
+ osi_free_and_reset((void**)&p_data->p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avct_lcb_msg_ind
+ *
+ * Description Handle an incoming AVCTP message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avct_lcb_msg_ind(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
+ uint8_t* p;
+ uint8_t label, type, cr_ipid;
+ uint16_t pid;
+ tAVCT_CCB* p_ccb;
+
+ /* this p_buf is to be reported through p_msg_cback. The layer_specific
+ * needs to be set properly to indicate that it is received through
+ * control channel */
+ p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
+
+ /* reassemble message; if no message available (we received a fragment) return
+ */
+ p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf);
+ if (p_data->p_buf == NULL) {
+ return;
+ }
+
+ p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset;
+
+ /* parse header byte */
+ AVCT_PARSE_HDR(p, label, type, cr_ipid);
+
+ /* check for invalid cr_ipid */
+ if (cr_ipid == AVCT_CR_IPID_INVALID) {
+ AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+ return;
+ }
+
+ /* parse and lookup PID */
+ BE_STREAM_TO_UINT16(pid, p);
+ p_ccb = avct_lcb_has_pid(p_lcb, pid);
+ if (p_ccb) {
+ /* PID found; send msg up, adjust bt hdr and call msg callback */
+ p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
+ p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
+ (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid,
+ p_data->p_buf);
+ return;
+ }
+
+ /* PID not found; drop message */
+ AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
+ osi_free_and_reset((void**)&p_data->p_buf);
+
+ /* if command send reject */
+ if (cr_ipid == AVCT_CMD) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVCT_CMD_BUF_SIZE);
+ p_buf->len = AVCT_HDR_LEN_SINGLE;
+ p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
+ UINT16_TO_BE_STREAM(p, pid);
+ L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_ad.cc b/mtkbt/code/bt/stack/avdt/avdt_ad.cc
new file mode 100755
index 0000000..3012def
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_ad.cc
@@ -0,0 +1,573 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the AVDTP adaption layer.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_type_to_tcid
+ *
+ * Description Derives the TCID from the channel type and SCB.
+ *
+ *
+ * Returns TCID value.
+ *
+ ******************************************************************************/
+uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB* p_scb) {
+ uint8_t scb_idx;
+
+ if (type == AVDT_CHAN_SIG) {
+ return 0;
+ } else {
+ scb_idx = avdt_scb_to_hdl(p_scb) - 1;
+ /*
+ AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx *
+ (AVDT_CHAN_NUM_TYPES - 1)) + type));
+ */
+ return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tcid_to_type
+ *
+ * Description Derives the channel type from the TCID.
+ *
+ *
+ * Returns Channel type value.
+ *
+ ******************************************************************************/
+static uint8_t avdt_ad_tcid_to_type(uint8_t tcid) {
+ uint8_t type;
+
+ if (tcid == 0) {
+ type = AVDT_CHAN_SIG;
+ } else {
+ /* tcid translates to type based on number of channels, as follows:
+ ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
+ ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
+ ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
+ */
+ type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
+ }
+ AVDT_TRACE_DEBUG("tcid: %d, type: %d", tcid, type);
+ return type;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_init
+ *
+ * Description Initialize adaption layer.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_init(void) {
+ int i;
+ tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+ memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
+
+ /* make sure the peer_mtu is a valid value */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_tbl_by_st
+ *
+ * Description Find adaption layer transport channel table entry matching
+ * the given state.
+ *
+ *
+ * Returns Pointer to matching entry. For control channel it returns
+ * the matching entry. For media or other it returns the
+ * first matching entry (there could be more than one).
+ *
+ ******************************************************************************/
+tAVDT_TC_TBL* avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB* p_ccb,
+ uint8_t state) {
+ int i;
+ tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+ uint8_t ccb_idx;
+
+ if (p_ccb == NULL) {
+ /* resending security req */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
+ /* must be AVDT_CHAN_SIG - tcid always zero */
+ if ((p_tbl->tcid == 0) && (p_tbl->state == state)) {
+ break;
+ }
+ }
+ } else {
+ ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
+ if (type == AVDT_CHAN_SIG) {
+ /* if control channel, tcid always zero */
+ if ((p_tbl->tcid == 0) && (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state)) {
+ break;
+ }
+ } else {
+ /* if other channel, tcid is always > zero */
+ if ((p_tbl->tcid > 0) && (p_tbl->ccb_idx == ccb_idx) &&
+ (p_tbl->state == state)) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* if nothing found return null */
+ if (i == AVDT_NUM_TC_TBL) {
+ p_tbl = NULL;
+ }
+
+ return p_tbl;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_tbl_by_lcid
+ *
+ * Description Find adaption layer transport channel table entry by LCID.
+ *
+ *
+ * Returns Pointer to entry.
+ *
+ ******************************************************************************/
+tAVDT_TC_TBL* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) {
+ uint8_t idx;
+
+ idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < AVDT_NUM_TC_TBL) {
+ return &avdt_cb.ad.tc_tbl[idx];
+ } else {
+ return NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_tbl_by_type
+ *
+ * Description This function retrieves the transport channel table entry
+ * for a particular channel.
+ *
+ *
+ * Returns Pointer to transport channel table entry.
+ *
+ ******************************************************************************/
+tAVDT_TC_TBL* avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB* p_ccb,
+ tAVDT_SCB* p_scb) {
+ uint8_t tcid;
+ int i;
+ tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+ uint8_t ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
+ if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx)) {
+ break;
+ }
+ }
+
+ CHECK(i != AVDT_NUM_TC_TBL);
+
+ return p_tbl;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_tbl_alloc
+ *
+ * Description Allocate an entry in the traffic channel table.
+ *
+ *
+ * Returns Pointer to entry.
+ *
+ ******************************************************************************/
+tAVDT_TC_TBL* avdt_ad_tc_tbl_alloc(tAVDT_CCB* p_ccb) {
+ int i;
+ tAVDT_TC_TBL* p_tbl = avdt_cb.ad.tc_tbl;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
+ if (p_tbl->state == AVDT_AD_ST_UNUSED) {
+ break;
+ }
+ }
+
+ /* sanity check */
+ CHECK(i != AVDT_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags = 0;
+ p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
+ p_tbl->state = AVDT_AD_ST_IDLE;
+ return p_tbl;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_tbl_to_idx
+ *
+ * Description Convert a transport channel table entry to an index.
+ *
+ *
+ * Returns Index value.
+ *
+ ******************************************************************************/
+uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL* p_tbl) {
+ AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d", (p_tbl - avdt_cb.ad.tc_tbl));
+ /* use array arithmetic to determine index */
+ return (uint8_t)(p_tbl - avdt_cb.ad.tc_tbl);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_close_ind
+ *
+ * Description This function is called by the L2CAP interface when the
+ * L2CAP channel is closed. It looks up the CCB or SCB for
+ * the channel and sends it a close event. The reason
+ * parameter is the same value passed by the L2CAP
+ * callback function.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_tc_close_ind(tAVDT_TC_TBL* p_tbl, UNUSED_ATTR uint16_t reason) {
+ tAVDT_CCB* p_ccb;
+ tAVDT_SCB* p_scb;
+ tAVDT_SCB_TC_CLOSE close;
+
+ close.old_tc_state = p_tbl->state;
+ /* clear avdt_ad_tc_tbl entry */
+ p_tbl->state = AVDT_AD_ST_UNUSED;
+ p_tbl->cfg_flags = 0;
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+ AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d", p_tbl->tcid,
+ close.old_tc_state);
+ /* if signaling channel, notify ccb that channel open */
+ if (p_tbl->tcid == 0) {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
+ }
+ /* if media or other channel, notify scb that channel close */
+ else {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb =
+ avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL) {
+ close.tcid = p_tbl->tcid;
+ close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT*)&close);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_open_ind
+ *
+ * Description This function is called by the L2CAP interface when
+ * the L2CAP channel is opened. It looks up the CCB or SCB
+ * for the channel and sends it an open event.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_tc_open_ind(tAVDT_TC_TBL* p_tbl) {
+ tAVDT_CCB* p_ccb;
+ tAVDT_SCB* p_scb;
+ tAVDT_OPEN open;
+ tAVDT_EVT_HDR evt;
+
+ p_tbl->state = AVDT_AD_ST_OPEN;
+
+ /* if signaling channel, notify ccb that channel open */
+ if (p_tbl->tcid == 0) {
+ /* set the signal channel to use high priority within the ACL link */
+ L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid,
+ L2CAP_CHNL_PRIORITY_HIGH);
+
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ /* use err_param to indicate the role of connection.
+ * AVDT_ACP, if ACP */
+ evt.err_param = AVDT_INT;
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) {
+ evt.err_param = AVDT_ACP;
+ }
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT*)&evt);
+ }
+ /* if media or other channel, notify scb that channel open */
+ else {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb =
+ avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+
+ /* put lcid in event data */
+ if (p_scb != NULL) {
+ open.peer_mtu = p_tbl->peer_mtu;
+ open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
+ open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
+ avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT*)&open);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_cong_ind
+ *
+ * Description This function is called by the L2CAP interface layer when
+ * L2CAP calls the congestion callback. It looks up the CCB
+ * or SCB for the channel and sends it a congestion event.
+ * The is_congested parameter is the same value passed by
+ * the L2CAP callback function.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_tc_cong_ind(tAVDT_TC_TBL* p_tbl, bool is_congested) {
+ tAVDT_CCB* p_ccb;
+ tAVDT_SCB* p_scb;
+
+ /* if signaling channel, notify ccb of congestion */
+ if (p_tbl->tcid == 0) {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT*)&is_congested);
+ }
+ /* if media or other channel, notify scb that channel open */
+ else {
+ /* look up scb in stream routing table by ccb, tcid */
+ p_scb =
+ avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT,
+ (tAVDT_SCB_EVT*)&is_congested);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_tc_data_ind
+ *
+ * Description This function is called by the L2CAP interface layer when
+ * incoming data is received from L2CAP. It looks up the CCB
+ * or SCB for the channel and routes the data accordingly.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_tc_data_ind(tAVDT_TC_TBL* p_tbl, BT_HDR* p_buf) {
+ tAVDT_CCB* p_ccb;
+ tAVDT_SCB* p_scb;
+
+ /* store type (media, recovery, reporting) */
+ p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
+
+ /* if signaling channel, handle control message */
+ if (p_tbl->tcid == 0) {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ avdt_msg_ind(p_ccb, p_buf);
+ }
+ /* if media or other channel, send event to scb */
+ else {
+ p_scb =
+ avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf);
+ } else {
+ osi_free(p_buf);
+ AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_write_req
+ *
+ * Description This function is called by a CCB or SCB to send data to a
+ * transport channel. It looks up the LCID of the channel
+ * based on the type, CCB, and SCB (if present). Then it
+ * passes the data to L2CA_DataWrite().
+ *
+ *
+ * Returns AVDT_AD_SUCCESS, if data accepted
+ * AVDT_AD_CONGESTED, if data accepted and the channel is
+ * congested
+ * AVDT_AD_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+ BT_HDR* p_buf) {
+ uint8_t tcid;
+
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid,
+ p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_open_req
+ *
+ * Description This function is called by a CCB or SCB to open a transport
+ * channel. This function allocates and initializes a
+ * transport channel table entry. The channel can be opened
+ * in two roles: as an initiator or acceptor. When opened
+ * as an initiator the function will start an L2CAP connection.
+ * When opened as an acceptor the function simply configures
+ * the table entry to listen for an incoming channel.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_open_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+ uint8_t role) {
+ tAVDT_TC_TBL* p_tbl;
+ uint16_t lcid;
+
+ p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+ if (p_tbl == NULL) {
+ AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
+ return;
+ }
+
+ p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
+ AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d", type, role,
+ p_tbl->tcid);
+
+ if (type == AVDT_CHAN_SIG) {
+ /* if signaling, get mtu from registration control block */
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ } else {
+ /* otherwise get mtu from scb */
+ p_tbl->my_mtu = p_scb->cs.mtu;
+ p_tbl->my_flush_to = p_scb->cs.flush_to;
+
+ /* also set scb_hdl in rt_tbl */
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl =
+ avdt_scb_to_hdl(p_scb);
+ AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
+ avdt_scb_to_hdl(p_scb));
+ }
+
+ /* if we're acceptor, we're done; just sit back and listen */
+ if (role == AVDT_ACP) {
+ p_tbl->state = AVDT_AD_ST_ACP;
+ }
+ /* else we're inititator, start the L2CAP connection */
+ else {
+ p_tbl->state = AVDT_AD_ST_CONN;
+
+ /* call l2cap connect req */
+ lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr);
+ if (lcid != 0) {
+ /* if connect req ok, store tcid in lcid table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
+ avdt_ad_tc_tbl_to_idx(p_tbl);
+ AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d",
+ (lcid - L2CAP_BASE_APPL_CID),
+ avdt_ad_tc_tbl_to_idx(p_tbl));
+
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+ AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x",
+ avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid);
+ } else {
+ /* if connect req failed, call avdt_ad_tc_close_ind() */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ad_close_req
+ *
+ * Description This function is called by a CCB or SCB to close a
+ * transport channel. The function looks up the LCID for the
+ * channel and calls L2CA_DisconnectReq().
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ad_close_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb) {
+ uint8_t tcid;
+ tAVDT_TC_TBL* p_tbl;
+
+ p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
+ AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d", p_tbl->state);
+
+ switch (p_tbl->state) {
+ case AVDT_AD_ST_UNUSED:
+ /* probably for reporting */
+ break;
+ case AVDT_AD_ST_ACP:
+ /* if we're listening on this channel, send ourselves a close ind */
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ break;
+ default:
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(type, p_scb);
+
+ /* call l2cap disconnect req */
+ L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_api.cc b/mtkbt/code/bt/stack/avdt/avdt_api.cc
new file mode 100755
index 0000000..3a12afa
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_api.cc
@@ -0,0 +1,1161 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains API of the audio/video distribution transport
+ * protocol.
+ *
+ ******************************************************************************/
+
+#include "avdt_api.h"
+#include <string.h>
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "l2c_api.h"
+
+/* Control block for AVDT */
+tAVDT_CB avdt_cb;
+
+void avdt_ccb_idle_ccb_timer_timeout(void* data) {
+ tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+ uint8_t avdt_event = AVDT_CCB_IDLE_TOUT_EVT;
+ uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+ avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT*)&err_code);
+}
+
+void avdt_ccb_ret_ccb_timer_timeout(void* data) {
+ tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+ uint8_t avdt_event = AVDT_CCB_RET_TOUT_EVT;
+ uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+ avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT*)&err_code);
+}
+
+void avdt_ccb_rsp_ccb_timer_timeout(void* data) {
+ tAVDT_CCB* p_ccb = (tAVDT_CCB*)data;
+ uint8_t avdt_event = AVDT_CCB_RSP_TOUT_EVT;
+ uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+ avdt_ccb_event(p_ccb, avdt_event, (tAVDT_CCB_EVT*)&err_code);
+}
+
+void avdt_scb_transport_channel_timer_timeout(void* data) {
+ tAVDT_SCB* p_scb = (tAVDT_SCB*)data;
+ uint8_t avdt_event = AVDT_SCB_TC_TOUT_EVT;
+
+ avdt_scb_event(p_scb, avdt_event, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_Register
+ *
+ * Description This is the system level registration function for the
+ * AVDTP protocol. This function initializes AVDTP and
+ * prepares the protocol stack for its use. This function
+ * must be called once by the system or platform using AVDTP
+ * before the other functions of the API an be used.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void AVDT_Register(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback) {
+ /* register PSM with L2CAP */
+ L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl);
+
+ /* set security level */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG);
+
+ /* do not use security on the media channel */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA);
+
+#if (AVDT_REPORTING == TRUE)
+ /* do not use security on the reporting channel */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE,
+ AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT);
+#endif
+
+ /* initialize AVDTP data structures */
+ avdt_scb_init();
+ avdt_ccb_init();
+ avdt_ad_init();
+
+ /* copy registration struct */
+ memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG));
+ avdt_cb.p_conn_cback = p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_Deregister
+ *
+ * Description This function is called to deregister use AVDTP protocol.
+ * It is called when AVDTP is no longer being used by any
+ * application in the system. Before this function can be
+ * called, all streams must be removed with
+ * AVDT_RemoveStream().
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void AVDT_Deregister(void) {
+ /* deregister PSM with L2CAP */
+ L2CA_Deregister(AVDT_PSM);
+}
+
+void AVDT_AbortReq(uint8_t handle) {
+ AVDT_TRACE_ERROR("%s", __func__);
+
+ tAVDT_SCB* p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL);
+ } else {
+ AVDT_TRACE_ERROR("%s Improper SCB, can not abort the stream", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_CreateStream
+ *
+ * Description Create a stream endpoint. After a stream endpoint is
+ * created an application can initiate a connection between
+ * this endpoint and an endpoint on a peer device. In
+ * addition, a peer device can discover, get the capabilities,
+ * and connect to this endpoint.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs) {
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB* p_scb;
+
+ /* Verify parameters; if invalid, return failure */
+ if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) ||
+ (p_cs->p_ctrl_cback == NULL)) {
+ result = AVDT_BAD_PARAMS;
+ }
+ /* Allocate scb; if no scbs, return failure */
+ else {
+ p_scb = avdt_scb_alloc(p_cs);
+ if (p_scb == NULL) {
+ result = AVDT_NO_RESOURCES;
+ } else {
+ *p_handle = avdt_scb_to_hdl(p_scb);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_RemoveStream
+ *
+ * Description Remove a stream endpoint. This function is called when
+ * the application is no longer using a stream endpoint.
+ * If this function is called when the endpoint is connected
+ * the connection is closed and then the stream endpoint
+ * is removed.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_RemoveStream(uint8_t handle) {
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB* p_scb;
+
+ /* look up scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else {
+ /* send remove event to scb */
+ avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_DiscoverReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and discovers
+ * the stream endpoints on the peer device. (Please note
+ * that AVDTP discovery is unrelated to SDP discovery).
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+ * is sent to the application via its callback function.
+ * The application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again to the same device until
+ * discovery is complete.
+ *
+ * The memory addressed by sep_info is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the discovery procedure. This memory must remain
+ * accessible until the application receives the
+ * AVDT_DISCOVER_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO* p_sep_info,
+ uint8_t max_seps, tAVDT_CTRL_CBACK* p_cback) {
+ tAVDT_CCB* p_ccb;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ /* find channel control block for this bd addr; if none, allocate one */
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ p_ccb = avdt_ccb_alloc(bd_addr);
+ if (p_ccb == NULL) {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+
+ if (result == AVDT_SUCCESS) {
+ /* make sure no discovery or get capabilities req already in progress */
+ if (p_ccb->proc_busy) {
+ result = AVDT_BUSY;
+ }
+ /* send event to ccb */
+ else {
+ evt.discover.p_sep_info = p_sep_info;
+ evt.discover.num_seps = max_seps;
+ evt.discover.p_cback = p_cback;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_get_cap_req
+ *
+ * Description internal function to serve both AVDT_GetCapReq and
+ * AVDT_GetAllCapReq
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+static uint16_t avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP* p_evt) {
+ tAVDT_CCB* p_ccb = NULL;
+ uint16_t result = AVDT_SUCCESS;
+
+ /* verify SEID */
+ if ((p_evt->single.seid < AVDT_SEID_MIN) ||
+ (p_evt->single.seid > AVDT_SEID_MAX)) {
+ AVDT_TRACE_ERROR("seid: %d", p_evt->single.seid);
+ result = AVDT_BAD_PARAMS;
+ }
+ /* find channel control block for this bd addr; if none, allocate one */
+ else {
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ p_ccb = avdt_ccb_alloc(bd_addr);
+ if (p_ccb == NULL) {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+ }
+
+ if (result == AVDT_SUCCESS) {
+ /* make sure no discovery or get capabilities req already in progress */
+ if (p_ccb->proc_busy) {
+ result = AVDT_BUSY;
+ }
+ /* send event to ccb */
+ else {
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT*)p_evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetCapReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and gets the
+ * capabilities of a stream endpoint on the peer device.
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+ * sent to the application via its callback function. The
+ * application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again until the procedure is complete.
+ *
+ * The memory pointed to by p_cfg is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the get capabilities procedure. This memory must
+ * remain accessible until the application receives
+ * the AVDT_GETCAP_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
+ tAVDT_CTRL_CBACK* p_cback) {
+ tAVDT_CCB_API_GETCAP getcap;
+
+ getcap.single.seid = seid;
+ getcap.single.sig_id = AVDT_SIG_GETCAP;
+ getcap.p_cfg = p_cfg;
+ getcap.p_cback = p_cback;
+ return avdt_get_cap_req(bd_addr, &getcap);
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetAllCapReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and gets the
+ * capabilities of a stream endpoint on the peer device.
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+ * sent to the application via its callback function. The
+ * application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again until the procedure is complete.
+ *
+ * The memory pointed to by p_cfg is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the get capabilities procedure. This memory must
+ * remain accessible until the application receives
+ * the AVDT_GETCAP_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_GetAllCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
+ tAVDT_CTRL_CBACK* p_cback) {
+ tAVDT_CCB_API_GETCAP getcap;
+
+ getcap.single.seid = seid;
+ getcap.single.sig_id = AVDT_SIG_GET_ALLCAP;
+ getcap.p_cfg = p_cfg;
+ getcap.p_cback = p_cback;
+ return avdt_get_cap_req(bd_addr, &getcap);
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_DelayReport
+ *
+ * Description This functions sends a Delay Report to the peer device
+ * that is associated with a particular SEID.
+ * This function is called by SNK device.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else
+ /* send event to scb */
+ {
+ evt.apidelay.hdr.seid = seid;
+ evt.apidelay.delay = delay;
+ avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_OpenReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and connects
+ * to a stream endpoint on a peer device. When the connection
+ * is completed, an AVDT_OPEN_CFM_EVT is sent to the
+ * application via the control callback function for this
+ * handle.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid,
+ tAVDT_CFG* p_cfg) {
+ tAVDT_CCB* p_ccb = NULL;
+ tAVDT_SCB* p_scb = NULL;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ /* verify SEID */
+ if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) {
+ result = AVDT_BAD_PARAMS;
+ }
+ /* map handle to scb */
+ else {
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* find channel control block for this bd addr; if none, allocate one */
+ else {
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ p_ccb = avdt_ccb_alloc(bd_addr);
+ if (p_ccb == NULL) {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ }
+ }
+ }
+
+ /* send event to scb */
+ if (result == AVDT_SUCCESS) {
+ evt.msg.config_cmd.hdr.seid = seid;
+ evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+ evt.msg.config_cmd.int_seid = handle;
+ evt.msg.config_cmd.p_cfg = p_cfg;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_ConfigRsp
+ *
+ * Description Respond to a configure request from the peer device. This
+ * function must be called if the application receives an
+ * AVDT_CONFIG_IND_EVT through its control callback.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+ uint8_t category) {
+ tAVDT_SCB* p_scb;
+ tAVDT_SCB_EVT evt;
+ uint16_t result = AVDT_SUCCESS;
+ uint8_t event_code;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* handle special case when this function is called but peer has not send
+ ** a configuration cmd; ignore and return error result
+ */
+ else if (!p_scb->in_use) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else {
+ evt.msg.hdr.err_code = error_code;
+ evt.msg.hdr.err_param = category;
+ evt.msg.hdr.label = label;
+ if (error_code == 0) {
+ event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT;
+ } else {
+ event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT;
+ }
+ avdt_scb_event(p_scb, event_code, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_StartReq
+ *
+ * Description Start one or more stream endpoints. This initiates the
+ * transfer of media packets for the streams. All stream
+ * endpoints must previously be opened. When the streams
+ * are started, an AVDT_START_CFM_EVT is sent to the
+ * application via the control callback function for each
+ * stream.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles) {
+ tAVDT_SCB* p_scb = NULL;
+ tAVDT_CCB_EVT evt;
+ uint16_t result = AVDT_SUCCESS;
+ int i;
+
+ if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) {
+ result = AVDT_BAD_PARAMS;
+ } else {
+ /* verify handles */
+ for (i = 0; i < num_handles; i++) {
+ p_scb = avdt_scb_by_hdl(p_handles[i]);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ }
+ }
+
+ if (result == AVDT_SUCCESS) {
+ if (p_scb->p_ccb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else {
+ /* send event to ccb */
+ memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+ evt.msg.multi.num_seps = num_handles;
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_SuspendReq
+ *
+ * Description Suspend one or more stream endpoints. This suspends the
+ * transfer of media packets for the streams. All stream
+ * endpoints must previously be open and started. When the
+ * streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+ * the application via the control callback function for
+ * each stream.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles) {
+ tAVDT_SCB* p_scb = NULL;
+ tAVDT_CCB_EVT evt;
+ uint16_t result = AVDT_SUCCESS;
+ int i;
+
+ if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) {
+ result = AVDT_BAD_PARAMS;
+ } else {
+ /* verify handles */
+ for (i = 0; i < num_handles; i++) {
+ p_scb = avdt_scb_by_hdl(p_handles[i]);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ break;
+ }
+ }
+ }
+
+ if (result == AVDT_SUCCESS) {
+ if (p_scb->p_ccb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else {
+ /* send event to ccb */
+ memcpy(evt.msg.multi.seid_list, p_handles, num_handles);
+ evt.msg.multi.num_seps = num_handles;
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt);
+ }
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_CloseReq
+ *
+ * Description Close a stream endpoint. This stops the transfer of media
+ * packets and closes the transport channel associated with
+ * this stream endpoint. When the stream is closed, an
+ * AVDT_CLOSE_CFM_EVT is sent to the application via the
+ * control callback function for this handle.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_CloseReq(uint8_t handle) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_SUCCESS;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else
+ /* send event to scb */
+ {
+ avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_ReconfigReq
+ *
+ * Description Reconfigure a stream endpoint. This allows the application
+ * to change the codec or content protection capabilities of
+ * a stream endpoint after it has been opened. This function
+ * can only be called if the stream is opened but not started
+ * or if the stream has been suspended. When the procedure
+ * is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+ * application via the control callback function for this
+ * handle.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else {
+ /* force psc_mask to zero */
+ p_cfg->psc_mask = 0;
+
+ evt.msg.reconfig_cmd.p_cfg = p_cfg;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_ReconfigRsp
+ *
+ * Description Respond to a reconfigure request from the peer device.
+ * This function must be called if the application receives
+ * an AVDT_RECONFIG_IND_EVT through its control callback.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+ uint8_t category) {
+ tAVDT_SCB* p_scb;
+ tAVDT_SCB_EVT evt;
+ uint16_t result = AVDT_SUCCESS;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else {
+ evt.msg.hdr.err_code = error_code;
+ evt.msg.hdr.err_param = category;
+ evt.msg.hdr.label = label;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_SecurityReq
+ *
+ * Description Send a security request to the peer device. When the
+ * security procedure is completed, an AVDT_SECURITY_CFM_EVT
+ * is sent to the application via the control callback function
+ * for this handle. (Please note that AVDTP security
+ * procedures are unrelated to Bluetooth link level security.)
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else {
+ evt.msg.security_rsp.p_data = p_data;
+ evt.msg.security_rsp.len = len;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_SecurityRsp
+ *
+ * Description Respond to a security request from the peer device.
+ * This function must be called if the application receives
+ * an AVDT_SECURITY_IND_EVT through its control callback.
+ * (Please note that AVDTP security procedures are unrelated
+ * to Bluetooth link level security.)
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label, uint8_t error_code,
+ uint8_t* p_data, uint16_t len) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_SCB_EVT evt;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ }
+ /* send event to scb */
+ else {
+ evt.msg.security_rsp.hdr.err_code = error_code;
+ evt.msg.security_rsp.hdr.label = label;
+ evt.msg.security_rsp.p_data = p_data;
+ evt.msg.security_rsp.len = len;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_WriteReqOpt
+ *
+ * Description Send a media packet to the peer device. The stream must
+ * be started before this function is called. Also, this
+ * function can only be called if the stream is a SRC.
+ *
+ * When AVDTP has sent the media packet and is ready for the
+ * next packet, an AVDT_WRITE_CFM_EVT is sent to the
+ * application via the control callback. The application must
+ * wait for the AVDT_WRITE_CFM_EVT before it makes the next
+ * call to AVDT_WriteReq(). If the applications calls
+ * AVDT_WriteReq() before it receives the event the packet
+ * will not be sent. The application may make its first call
+ * to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+ * or AVDT_START_IND_EVT.
+ *
+ * The application passes the packet using the BT_HDR
+ * structure.
+ * This structure is described in section 2.1. The offset
+ * field must be equal to or greater than AVDT_MEDIA_OFFSET
+ * (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used).
+ * This allows enough space in the buffer for the L2CAP and
+ * AVDTP headers.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ * The opt parameter allows passing specific options like:
+ * - NO_RTP : do not add the RTP header to buffer
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
+ uint8_t m_pt, tAVDT_DATA_OPT_MASK opt) {
+ tAVDT_SCB* p_scb;
+ tAVDT_SCB_EVT evt;
+ uint16_t result = AVDT_SUCCESS;
+
+ /* map handle to scb */
+ p_scb = avdt_scb_by_hdl(handle);
+ if (p_scb == NULL) {
+ result = AVDT_BAD_HANDLE;
+ } else {
+ evt.apiwrite.p_buf = p_pkt;
+ evt.apiwrite.time_stamp = time_stamp;
+ evt.apiwrite.m_pt = m_pt;
+ evt.apiwrite.opt = opt;
+ avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_WriteReq
+ *
+ * Description Send a media packet to the peer device. The stream must
+ * be started before this function is called. Also, this
+ * function can only be called if the stream is a SRC.
+ *
+ * When AVDTP has sent the media packet and is ready for the
+ * next packet, an AVDT_WRITE_CFM_EVT is sent to the
+ * application via the control callback. The application must
+ * wait for the AVDT_WRITE_CFM_EVT before it makes the next
+ * call to AVDT_WriteReq(). If the applications calls
+ * AVDT_WriteReq() before it receives the event the packet
+ * will not be sent. The application may make its first call
+ * to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+ * or AVDT_START_IND_EVT.
+ *
+ * The application passes the packet using the BT_HDR
+ * structure.
+ * This structure is described in section 2.1. The offset
+ * field must be equal to or greater than AVDT_MEDIA_OFFSET.
+ * This allows enough space in the buffer for the L2CAP and
+ * AVDTP headers.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_WriteReq(uint8_t handle, BT_HDR* p_pkt, uint32_t time_stamp,
+ uint8_t m_pt) {
+ return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE);
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_ConnectReq
+ *
+ * Description This function initiates an AVDTP signaling connection
+ * to the peer device. When the connection is completed, an
+ * AVDT_CONNECT_IND_EVT is sent to the application via its
+ * control callback function. If the connection attempt fails
+ * an AVDT_DISCONNECT_IND_EVT is sent. The security mask
+ * parameter overrides the outgoing security mask set in
+ * AVDT_Register().
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask,
+ tAVDT_CTRL_CBACK* p_cback) {
+ tAVDT_CCB* p_ccb = NULL;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ /* find channel control block for this bd addr; if none, allocate one */
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ p_ccb = avdt_ccb_alloc(bd_addr);
+ if (p_ccb == NULL) {
+ /* could not allocate channel control block */
+ result = AVDT_NO_RESOURCES;
+ }
+ } else if (p_ccb->ll_opened == false) {
+ AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening");
+
+ /* ccb was already allocated for the incoming signalling. */
+ result = AVDT_BUSY;
+ }
+
+ if (result == AVDT_SUCCESS) {
+ /* send event to ccb */
+ evt.connect.p_cback = p_cback;
+ evt.connect.sec_mask = sec_mask;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_DisconnectReq
+ *
+ * Description This function disconnect an AVDTP signaling connection
+ * to the peer device. When disconnected an
+ * AVDT_DISCONNECT_IND_EVT is sent to the application via its
+ * control callback function.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+uint16_t AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK* p_cback) {
+ tAVDT_CCB* p_ccb = NULL;
+ uint16_t result = AVDT_SUCCESS;
+ tAVDT_CCB_EVT evt;
+
+ /* find channel control block for this bd addr; if none, error */
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if (result == AVDT_SUCCESS) {
+ /* send event to ccb */
+ evt.disconnect.p_cback = p_cback;
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetL2CapChannel
+ *
+ * Description Get the L2CAP CID used by the handle.
+ *
+ * Returns CID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+uint16_t AVDT_GetL2CapChannel(uint8_t handle) {
+ tAVDT_SCB* p_scb;
+ tAVDT_CCB* p_ccb;
+ uint8_t tcid;
+ uint16_t lcid = 0;
+
+ /* map handle to scb */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) &&
+ ((p_ccb = p_scb->p_ccb) != NULL)) {
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ }
+
+ return (lcid);
+}
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetSignalChannel
+ *
+ * Description Get the L2CAP CID used by the signal channel of the given
+ * handle.
+ *
+ * Returns CID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+uint16_t AVDT_GetSignalChannel(uint8_t handle, BD_ADDR bd_addr) {
+ tAVDT_SCB* p_scb;
+ tAVDT_CCB* p_ccb;
+ uint8_t tcid = 0; /* tcid is always 0 for signal channel */
+ uint16_t lcid = 0;
+
+ /* map handle to scb */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) &&
+ ((p_ccb = p_scb->p_ccb) != NULL)) {
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ } else {
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb != NULL) {
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ }
+ }
+
+ return (lcid);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function AVDT_SendReport
+ *
+ * Description
+ *
+ *
+ *
+ * Returns
+ *
+ ******************************************************************************/
+uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA* p_data) {
+ tAVDT_SCB* p_scb;
+ uint16_t result = AVDT_BAD_PARAMS;
+ tAVDT_TC_TBL* p_tbl;
+ uint8_t *p, *plen, *pm1, *p_end;
+ uint32_t ssrc;
+ uint16_t len;
+
+ /* map handle to scb && verify parameters */
+ if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) && (p_scb->p_ccb != NULL) &&
+ (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) ||
+ ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) ||
+ (type == AVDT_RTCP_PT_SDES))) {
+ result = AVDT_NO_RESOURCES;
+
+ /* build SR - assume fit in one packet */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+ if (p_tbl->state == AVDT_AD_ST_OPEN) {
+ BT_HDR* p_pkt = (BT_HDR*)osi_malloc(p_tbl->peer_mtu + sizeof(BT_HDR));
+
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ pm1 = p;
+ *p++ = AVDT_MEDIA_OCTET1 | 1;
+ *p++ = type;
+ /* save the location for length */
+ plen = p;
+ p += 2;
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+ UINT32_TO_BE_STREAM(p, ssrc);
+
+ switch (type) {
+ case AVDT_RTCP_PT_SR: /* Sender Report */
+ *pm1 = AVDT_MEDIA_OCTET1;
+ UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec);
+ UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac);
+ UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time);
+ UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count);
+ UINT32_TO_BE_STREAM(p, p_data->sr.octet_count);
+ break;
+
+ case AVDT_RTCP_PT_RR: /* Receiver Report */
+ *p++ = p_data->rr.frag_lost;
+ AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost);
+ p_data->rr.packet_lost &= 0xFFFFFF;
+ AVDT_TRACE_API("packet_lost: %d", p_data->rr.packet_lost);
+ UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost);
+ UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd);
+ UINT32_TO_BE_STREAM(p, p_data->rr.jitter);
+ UINT32_TO_BE_STREAM(p, p_data->rr.lsr);
+ UINT32_TO_BE_STREAM(p, p_data->rr.dlsr);
+ break;
+
+ case AVDT_RTCP_PT_SDES: /* Source Description */
+ *p++ = AVDT_RTCP_SDES_CNAME;
+ len = strlen((char*)p_data->cname);
+ if (len > AVDT_MAX_CNAME_SIZE) len = AVDT_MAX_CNAME_SIZE;
+ *p++ = (uint8_t)len;
+ strlcpy((char*)p, (char*)p_data->cname, len + 1);
+ p += len;
+ break;
+ }
+ p_end = p;
+ len = p - pm1 - 1;
+ UINT16_TO_BE_STREAM(plen, len);
+
+ /* set the actual payload length */
+ p_pkt->len = p_end - p;
+ /* send the packet */
+ if (L2CAP_DW_FAILED !=
+ avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt))
+ result = AVDT_SUCCESS;
+ }
+ }
+
+ return result;
+}
+#endif
+
+/******************************************************************************
+ *
+ * Function AVDT_SetTraceLevel
+ *
+ * Description Sets the trace level for AVDT. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the AVDT tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+uint8_t AVDT_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) avdt_cb.trace_level = new_level;
+
+ return (avdt_cb.trace_level);
+}
+
+/** M: Bug fix for not disconnect signal channel @{ */
+/*******************************************************************************
+**
+** Function AVDT_ULCloseReq
+**
+** Description This function to trigger ccb checks for active streams on this CCB
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+uint16_t AVDT_ULCloseReq(BD_ADDR bd_addr)
+{
+ tAVDT_CCB *p_ccb = NULL;
+ uint16_t result = AVDT_SUCCESS;
+
+ /* find channel control block for this bd addr; if none, error */
+ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL)
+ {
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if (result == AVDT_SUCCESS)
+ {
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
+ }
+ return result;
+}
+/** @} */
diff --git a/mtkbt/code/bt/stack/avdt/avdt_ccb.cc b/mtkbt/code/bt/stack/avdt/avdt_ccb.cc
new file mode 100755
index 0000000..c1f1469
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_ccb.cc
@@ -0,0 +1,522 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the channel control block state machine and
+ * functions which operate on the channel control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * state machine constants and types
+ ****************************************************************************/
+#if (AVDT_DEBUG == TRUE)
+
+/* verbose state strings for trace */
+const char* const avdt_ccb_st_str[] = {"CCB_IDLE_ST", "CCB_OPENING_ST",
+ "CCB_OPEN_ST", "CCB_CLOSING_ST"};
+
+/* verbose event strings for trace */
+const char* const avdt_ccb_evt_str[] = {
+ "API_DISCOVER_REQ_EVT", "API_GETCAP_REQ_EVT",
+ "API_START_REQ_EVT", "API_SUSPEND_REQ_EVT",
+ "API_DISCOVER_RSP_EVT", "API_GETCAP_RSP_EVT",
+ "API_START_RSP_EVT", "API_SUSPEND_RSP_EVT",
+ "API_CONNECT_REQ_EVT", "API_DISCONNECT_REQ_EVT",
+ "MSG_DISCOVER_CMD_EVT", "MSG_GETCAP_CMD_EVT",
+ "MSG_START_CMD_EVT", "MSG_SUSPEND_CMD_EVT",
+ "MSG_DISCOVER_RSP_EVT", "MSG_GETCAP_RSP_EVT",
+ "MSG_START_RSP_EVT", "MSG_SUSPEND_RSP_EVT",
+ "RCVRSP_EVT", "SENDMSG_EVT",
+ "RET_TOUT_EVT", "RSP_TOUT_EVT",
+ "IDLE_TOUT_EVT", "UL_OPEN_EVT",
+ "UL_CLOSE_EVT", "LL_OPEN_EVT",
+ "LL_CLOSE_EVT", "LL_CONG_EVT"};
+
+#endif
+
+/* action function list */
+const tAVDT_CCB_ACTION avdt_ccb_action[] = {
+ avdt_ccb_chan_open, avdt_ccb_chan_close,
+ avdt_ccb_chk_close, avdt_ccb_hdl_discover_cmd,
+ avdt_ccb_hdl_discover_rsp, avdt_ccb_hdl_getcap_cmd,
+ avdt_ccb_hdl_getcap_rsp, avdt_ccb_hdl_start_cmd,
+ avdt_ccb_hdl_start_rsp, avdt_ccb_hdl_suspend_cmd,
+ avdt_ccb_hdl_suspend_rsp, avdt_ccb_snd_discover_cmd,
+ avdt_ccb_snd_discover_rsp, avdt_ccb_snd_getcap_cmd,
+ avdt_ccb_snd_getcap_rsp, avdt_ccb_snd_start_cmd,
+ avdt_ccb_snd_start_rsp, avdt_ccb_snd_suspend_cmd,
+ avdt_ccb_snd_suspend_rsp, avdt_ccb_clear_cmds,
+ avdt_ccb_cmd_fail, avdt_ccb_free_cmd,
+ avdt_ccb_cong_state, avdt_ccb_ret_cmd,
+ avdt_ccb_snd_cmd, avdt_ccb_snd_msg,
+ avdt_ccb_set_reconn, avdt_ccb_clr_reconn,
+ avdt_ccb_chk_reconn, avdt_ccb_chk_timer,
+ avdt_ccb_set_conn, avdt_ccb_set_disconn,
+ avdt_ccb_do_disconn, avdt_ccb_ll_closed,
+ avdt_ccb_ll_opened, avdt_ccb_dealloc};
+
+/* state table information */
+#define AVDT_CCB_ACTIONS 2 /* number of actions */
+#define AVDT_CCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_CCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_DISCOVER_REQ_EVT */
+ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+ /* API_GETCAP_REQ_EVT */
+ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+ /* API_START_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_SUSPEND_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_DISCOVER_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_GETCAP_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_START_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_SUSPEND_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* API_CONNECT_REQ_EVT */
+ {AVDT_CCB_SET_CONN, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST},
+ /* API_DISCONNECT_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_DISCOVER_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_GETCAP_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_DISCOVER_RSP_EVT */
+ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_GETCAP_RSP_EVT */
+ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* RCVRSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* SENDMSG_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* RET_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* RSP_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* IDLE_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* UL_OPEN_EVT */
+ {AVDT_CCB_CHAN_OPEN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* UL_CLOSE_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* LL_OPEN_EVT */
+ {AVDT_CCB_LL_OPENED, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* LL_CLOSE_EVT */
+ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* LL_CONG_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}};
+
+/* state table for opening state */
+const uint8_t avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_DISCOVER_REQ_EVT */
+ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_GETCAP_REQ_EVT */
+ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_START_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_SUSPEND_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_DISCOVER_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_GETCAP_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_START_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_SUSPEND_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_CONNECT_REQ_EVT */
+ {AVDT_CCB_SET_CONN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* API_DISCONNECT_REQ_EVT */
+ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+ /* MSG_DISCOVER_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_GETCAP_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_DISCOVER_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_GETCAP_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* RCVRSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* SENDMSG_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* RET_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* RSP_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* IDLE_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* UL_OPEN_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST},
+ /* UL_CLOSE_EVT */
+ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+ /* LL_OPEN_EVT */
+ {AVDT_CCB_SND_CMD, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+ /* LL_CLOSE_EVT */
+ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* LL_CONG_EVT */
+ {AVDT_CCB_CONG_STATE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_DISCOVER_REQ_EVT */
+ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_GETCAP_REQ_EVT */
+ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_START_REQ_EVT */
+ {AVDT_CCB_SND_START_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_SUSPEND_REQ_EVT */
+ {AVDT_CCB_SND_SUSPEND_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_DISCOVER_RSP_EVT */
+ {AVDT_CCB_SND_DISCOVER_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_GETCAP_RSP_EVT */
+ {AVDT_CCB_SND_GETCAP_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_START_RSP_EVT */
+ {AVDT_CCB_SND_START_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_SUSPEND_RSP_EVT */
+ {AVDT_CCB_SND_SUSPEND_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* API_CONNECT_REQ_EVT */
+ {AVDT_CCB_SET_CONN, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST},
+ /* API_DISCONNECT_REQ_EVT */
+ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST},
+ /* MSG_DISCOVER_CMD_EVT */
+ {AVDT_CCB_HDL_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* MSG_GETCAP_CMD_EVT */
+ {AVDT_CCB_HDL_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_CCB_HDL_START_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_CCB_HDL_SUSPEND_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* MSG_DISCOVER_RSP_EVT */
+ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_OPEN_ST},
+ /* MSG_GETCAP_RSP_EVT */
+ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_OPEN_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* RCVRSP_EVT */
+ {AVDT_CCB_FREE_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* SENDMSG_EVT */
+ {AVDT_CCB_SND_MSG, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* RET_TOUT_EVT */
+ {AVDT_CCB_RET_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* RSP_TOUT_EVT */
+ {AVDT_CCB_CMD_FAIL, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST},
+ /* IDLE_TOUT_EVT */
+ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST},
+ /* UL_OPEN_EVT */
+ {AVDT_CCB_CHK_TIMER, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* UL_CLOSE_EVT */
+ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* LL_OPEN_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST},
+ /* LL_CLOSE_EVT */
+ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* LL_CONG_EVT */
+ {AVDT_CCB_CONG_STATE, AVDT_CCB_SND_MSG, AVDT_CCB_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_DISCOVER_REQ_EVT */
+ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CLOSING_ST},
+ /* API_GETCAP_REQ_EVT */
+ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CLOSING_ST},
+ /* API_START_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_SUSPEND_REQ_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_DISCOVER_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_GETCAP_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_START_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_SUSPEND_RSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* API_CONNECT_REQ_EVT */
+ {AVDT_CCB_SET_RECONN, AVDT_CCB_SET_CONN, AVDT_CCB_CLOSING_ST},
+ /* API_DISCONNECT_REQ_EVT */
+ {AVDT_CCB_CLR_RECONN, AVDT_CCB_SET_DISCONN, AVDT_CCB_CLOSING_ST},
+ /* MSG_DISCOVER_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_GETCAP_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_DISCOVER_RSP_EVT */
+ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_GETCAP_RSP_EVT */
+ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* RCVRSP_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* SENDMSG_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* RET_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* RSP_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* IDLE_TOUT_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* UL_OPEN_EVT */
+ {AVDT_CCB_SET_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* UL_CLOSE_EVT */
+ {AVDT_CCB_CLR_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* LL_OPEN_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST},
+ /* LL_CLOSE_EVT */
+ {AVDT_CCB_CHK_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST},
+ /* LL_CONG_EVT */
+ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS];
+
+/* state table */
+const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = {
+ avdt_ccb_st_idle, avdt_ccb_st_opening, avdt_ccb_st_open,
+ avdt_ccb_st_closing};
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_init
+ *
+ * Description Initialize channel control block module.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ccb_init(void) {
+ memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS);
+ avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION*)avdt_ccb_action;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_event
+ *
+ * Description State machine event handling function for ccb
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_ccb_event(tAVDT_CCB* p_ccb, uint8_t event, tAVDT_CCB_EVT* p_data) {
+ tAVDT_CCB_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+#if (AVDT_DEBUG == TRUE)
+ AVDT_TRACE_EVENT("%s: CCB ccb=%d event=%s state=%s", __func__,
+ avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event],
+ avdt_ccb_st_str[p_ccb->state]);
+#endif
+
+ /* look up the state table for the current state */
+ state_table = avdt_ccb_st_tbl[p_ccb->state];
+
+ /* set next state */
+ if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE]) {
+ p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE];
+ }
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_CCB_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != AVDT_CCB_IGNORE) {
+ (*avdt_cb.p_ccb_act[action])(p_ccb, p_data);
+ } else {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_by_bd
+ *
+ * Description This lookup function finds the ccb for a BD address.
+ *
+ *
+ * Returns pointer to the ccb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVDT_CCB* avdt_ccb_by_bd(BD_ADDR bd_addr) {
+ tAVDT_CCB* p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) {
+ /* if allocated ccb has matching ccb */
+ if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN))) {
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS) {
+ /* if no ccb found */
+ p_ccb = NULL;
+
+ AVDT_TRACE_DEBUG("No ccb for addr %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_alloc
+ *
+ * Description Allocate a channel control block.
+ *
+ *
+ * Returns pointer to the ccb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tAVDT_CCB* avdt_ccb_alloc(BD_ADDR bd_addr) {
+ tAVDT_CCB* p_ccb = &avdt_cb.ccb[0];
+ int i;
+
+ for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) {
+ if (!p_ccb->allocated) {
+ p_ccb->allocated = true;
+ memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN);
+ p_ccb->cmd_q = fixed_queue_new(SIZE_MAX);
+ p_ccb->rsp_q = fixed_queue_new(SIZE_MAX);
+ p_ccb->idle_ccb_timer = alarm_new("avdt_ccb.idle_ccb_timer");
+ p_ccb->ret_ccb_timer = alarm_new("avdt_ccb.ret_ccb_timer");
+ p_ccb->rsp_ccb_timer = alarm_new("avdt_ccb.rsp_ccb_timer");
+ AVDT_TRACE_DEBUG("avdt_ccb_alloc %d", i);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_LINKS) {
+ /* out of ccbs */
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING("Out of ccbs");
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_dealloc
+ *
+ * Description Deallocate a stream control block.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_dealloc(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d", avdt_ccb_to_idx(p_ccb));
+ alarm_free(p_ccb->idle_ccb_timer);
+ alarm_free(p_ccb->ret_ccb_timer);
+ alarm_free(p_ccb->rsp_ccb_timer);
+ fixed_queue_free(p_ccb->cmd_q, NULL);
+ fixed_queue_free(p_ccb->rsp_q, NULL);
+ memset(p_ccb, 0, sizeof(tAVDT_CCB));
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_to_idx
+ *
+ * Description Given a pointer to an ccb, return its index.
+ *
+ *
+ * Returns Index of ccb.
+ *
+ ******************************************************************************/
+uint8_t avdt_ccb_to_idx(tAVDT_CCB* p_ccb) {
+ /* use array arithmetic to determine index */
+ return (uint8_t)(p_ccb - avdt_cb.ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_by_idx
+ *
+ * Description Return ccb pointer based on ccb index.
+ *
+ *
+ * Returns pointer to the ccb, or NULL if none found.
+ *
+ ******************************************************************************/
+tAVDT_CCB* avdt_ccb_by_idx(uint8_t idx) {
+ tAVDT_CCB* p_ccb;
+
+ /* verify index */
+ if (idx < AVDT_NUM_LINKS) {
+ p_ccb = &avdt_cb.ccb[idx];
+ } else {
+ p_ccb = NULL;
+ AVDT_TRACE_WARNING("No ccb for idx %d", idx);
+ }
+ return p_ccb;
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_ccb_act.cc b/mtkbt/code/bt/stack/avdt/avdt_ccb_act.cc
new file mode 100755
index 0000000..943855f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_ccb_act.cc
@@ -0,0 +1,1032 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the action functions associated with the channel
+ * control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_clear_ccb
+ *
+ * Description This function clears out certain buffers, queues, and
+ * other data elements of a ccb.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_ccb_clear_ccb(tAVDT_CCB* p_ccb) {
+ BT_HDR* p_buf;
+
+ /* clear certain ccb variables */
+ p_ccb->cong = false;
+ p_ccb->ret_count = 0;
+
+ /* free message being fragmented */
+ osi_free_and_reset((void**)&p_ccb->p_curr_msg);
+
+ /* free message being reassembled */
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+
+ /* clear out response queue */
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL)
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_chan_open
+ *
+ * Description This function calls avdt_ad_open_req() to
+ * initiate a signaling channel connection.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_chan_open(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG);
+ avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_chan_close
+ *
+ * Description This function calls avdt_ad_close_req() to close a
+ * signaling channel connection.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_chan_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ /* close the transport channel used by this CCB */
+ avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_chk_close
+ *
+ * Description This function checks for active streams on this CCB.
+ * If there are none, it starts an idle timer.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_chk_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ int i;
+ tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+
+ /* see if there are any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) {
+ break;
+ }
+ }
+
+ /* if no active scbs start idle timer */
+ if (i == AVDT_NUM_SEPS) {
+ alarm_cancel(p_ccb->ret_ccb_timer);
+ alarm_cancel(p_ccb->rsp_ccb_timer);
+ period_ms_t interval_ms = avdt_cb.rcb.idle_tout * 1000;
+ alarm_set_on_queue(p_ccb->idle_ccb_timer, interval_ms,
+ avdt_ccb_idle_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_discover_cmd
+ *
+ * Description This function is called when a discover command is
+ * received from the peer. It gathers up the stream
+ * information for all allocated streams and initiates
+ * sending of a discover response.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS];
+ tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+ int i;
+
+ p_data->msg.discover_rsp.p_sep_info = sep_info;
+ p_data->msg.discover_rsp.num_seps = 0;
+
+ /* for all allocated scbs */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+ if (p_scb->allocated) {
+ /* copy sep info */
+ sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use;
+ sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1;
+ sep_info[p_data->msg.discover_rsp.num_seps].media_type =
+ p_scb->cs.media_type;
+ sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep;
+
+ p_data->msg.discover_rsp.num_seps++;
+ }
+ }
+
+ /* send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_discover_rsp
+ *
+ * Description This function is called when a discover response or
+ * reject is received from the peer. It calls the application
+ * callback function with the results.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /* we're done with procedure */
+ p_ccb->proc_busy = false;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT,
+ (tAVDT_CTRL*)(&p_data->msg.discover_rsp));
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_getcap_cmd
+ *
+ * Description This function is called when a get capabilities command
+ * is received from the peer. It retrieves the stream
+ * configuration for the requested stream and initiates
+ * sending of a get capabilities response.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_SCB* p_scb;
+
+ /* look up scb for seid sent to us */
+ p_scb = avdt_scb_by_hdl(p_data->msg.single.seid);
+
+ p_data->msg.svccap.p_cfg = &p_scb->cs.cfg;
+
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_getcap_rsp
+ *
+ * Description This function is called with a get capabilities response
+ * or reject is received from the peer. It calls the
+ * application callback function with the results.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /* we're done with procedure */
+ p_ccb->proc_busy = false;
+
+ /* call app callback with results */
+ (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT,
+ (tAVDT_CTRL*)(&p_data->msg.svccap));
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_start_cmd
+ *
+ * Description This function is called when a start command is received
+ * from the peer. It verifies that all requested streams
+ * are in the proper state. If so, it initiates sending of
+ * a start response. Otherwise it sends a start reject.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t err_code = 0;
+
+ /* verify all streams in the right state */
+ uint8_t seid =
+ avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code);
+ if (seid == 0 && err_code == 0) {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data);
+ } else {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_start_rsp
+ *
+ * Description This function is called when a start response or reject
+ * is received from the peer. Using the SEIDs stored in the
+ * current command message, it sends a start response or start
+ * reject event to each SCB associated with the command.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t event;
+ int i;
+ uint8_t* p;
+ tAVDT_SCB* p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_START_RSP_EVT
+ : AVDT_SCB_MSG_START_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (uint8_t*)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++) {
+ p_scb = avdt_scb_by_hdl(p[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT*)&p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_suspend_cmd
+ *
+ * Description This function is called when a suspend command is received
+ * from the peer. It verifies that all requested streams are
+ * in the proper state. If so, it initiates sending of a
+ * suspend response. Otherwise it sends a suspend reject.
+
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t seid;
+ uint8_t err_code = 0;
+
+ /* verify all streams in the right state */
+ if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND,
+ p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &err_code)) == 0 &&
+ err_code == 0) {
+ /* we're ok, send response */
+ avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data);
+ } else {
+ /* not ok, send reject */
+ p_data->msg.hdr.err_code = err_code;
+ p_data->msg.hdr.err_param = seid;
+ avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_hdl_suspend_rsp
+ *
+ * Description This function is called when a suspend response or reject
+ * is received from the peer. Using the SEIDs stored in the
+ * current command message, it sends a suspend response or
+ * suspend reject event to each SCB associated with the
+ * command.
+ *
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t event;
+ int i;
+ uint8_t* p;
+ tAVDT_SCB* p_scb;
+
+ /* determine rsp or rej event */
+ event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_SUSPEND_RSP_EVT
+ : AVDT_SCB_MSG_SUSPEND_REJ_EVT;
+
+ /* get to where seid's are stashed in current cmd */
+ p = (uint8_t*)(p_ccb->p_curr_cmd + 1);
+
+ /* little trick here; length of current command equals number of streams */
+ for (i = 0; i < p_ccb->p_curr_cmd->len; i++) {
+ p_scb = avdt_scb_by_hdl(p[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT*)&p_data->msg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_discover_cmd
+ *
+ * Description This function is called to send a discover command to the
+ * peer. It copies variables needed for the procedure from
+ * the event to the CCB. It marks the CCB as busy and then
+ * sends a discover command.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->discover.p_sep_info;
+ p_ccb->proc_cback = p_data->discover.p_cback;
+ p_ccb->proc_param = p_data->discover.num_seps;
+
+ /* we're busy */
+ p_ccb->proc_busy = true;
+
+ /* build and queue discover req */
+ avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_discover_rsp
+ *
+ * Description This function is called to send a discover response to
+ * the peer. It takes the stream information passed in the
+ * event and sends a discover response.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_getcap_cmd
+ *
+ * Description This function is called to send a get capabilities command
+ * to the peer. It copies variables needed for the procedure
+ * from the event to the CCB. It marks the CCB as busy and
+ * then sends a get capabilities command.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t sig_id = AVDT_SIG_GETCAP;
+
+ /* store info in ccb struct */
+ p_ccb->p_proc_data = p_data->getcap.p_cfg;
+ p_ccb->proc_cback = p_data->getcap.p_cback;
+
+ /* we're busy */
+ p_ccb->proc_busy = true;
+
+ /* build and queue discover req */
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG*)&p_data->getcap.single);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_getcap_rsp
+ *
+ * Description This function is called to send a get capabilities response
+ * to the peer. It takes the stream information passed in the
+ * event and sends a get capabilities response.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t sig_id = AVDT_SIG_GETCAP;
+
+ if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP)
+ sig_id = AVDT_SIG_GET_ALLCAP;
+
+ /* send response */
+ avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_start_cmd
+ *
+ * Description This function is called to send a start command to the
+ * peer. It verifies that all requested streams are in the
+ * proper state. If so, it sends a start command. Otherwise
+ * send ourselves back a start reject.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ int i;
+ tAVDT_SCB* p_scb;
+ tAVDT_MSG avdt_msg;
+ uint8_t seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ avdt_msg.hdr.err_param =
+ avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code);
+ if (avdt_msg.hdr.err_param == 0) {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg);
+ } else {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++) {
+ p_scb = avdt_scb_by_hdl(seid_list[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT,
+ (tAVDT_SCB_EVT*)&avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_start_rsp
+ *
+ * Description This function is called to send a start response to the
+ * peer. It takes the stream information passed in the event
+ * and sends a start response. Then it sends a start event
+ * to the SCB for each stream.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_SCB* p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++) {
+ p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_suspend_cmd
+ *
+ * Description This function is called to send a suspend command to the
+ * peer. It verifies that all requested streams are in the
+ * proper state. If so, it sends a suspend command.
+ * Otherwise it calls the callback function for each requested
+ * stream and sends a suspend confirmation with failure.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ int i;
+ tAVDT_SCB* p_scb;
+ tAVDT_MSG avdt_msg;
+ uint8_t seid_list[AVDT_NUM_SEPS];
+
+ /* make copy of our seid list */
+ memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps);
+
+ /* verify all streams in the right state */
+ avdt_msg.hdr.err_param =
+ avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list,
+ p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code);
+ if (avdt_msg.hdr.err_param == 0) {
+ /* set peer seid list in messsage */
+ avdt_scb_peer_seid_list(&p_data->msg.multi);
+
+ /* send command */
+ avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg);
+ } else {
+ /* failed; send ourselves a reject for each stream */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++) {
+ p_scb = avdt_scb_by_hdl(seid_list[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT,
+ (tAVDT_SCB_EVT*)&avdt_msg.hdr);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_suspend_rsp
+ *
+ * Description This function is called to send a suspend response to the
+ * peer. It takes the stream information passed in the event
+ * and sends a suspend response. Then it sends a suspend event
+ * to the SCB for each stream.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_SCB* p_scb;
+ int i;
+
+ /* send response message */
+ avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg);
+
+ /* send start event to each scb */
+ for (i = 0; i < p_data->msg.multi.num_seps; i++) {
+ p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_clear_cmds
+ *
+ * Description This function is called when the signaling channel is
+ * closed to clean up any pending commands. For each pending
+ * command in the command queue, it frees the command and
+ * calls the application callback function indicating failure.
+ * Certain CCB variables are also initialized.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ int i;
+ tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+ uint8_t err_code = AVDT_ERR_CONNECT;
+
+ /* clear the ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out command queue; this is a little tricky here; we need
+ ** to handle the case where there is a command on deck in p_curr_cmd,
+ ** plus we need to clear out the queue
+ */
+ do {
+ /* we know p_curr_cmd = NULL after this */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code);
+
+ /* set up next message */
+ p_ccb->p_curr_cmd = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q);
+
+ } while (p_ccb->p_curr_cmd != NULL);
+
+ /* send a CC_CLOSE_EVT any active scbs associated with this ccb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+ if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) {
+ avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_cmd_fail
+ *
+ * Description This function is called when there is a response timeout.
+ * The currently pending command is freed and we fake a
+ * reject message back to ourselves.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_MSG msg;
+ uint8_t evt;
+ tAVDT_SCB* p_scb;
+
+ if (p_ccb->p_curr_cmd != NULL) {
+ /* set up data */
+ msg.hdr.err_code = p_data->err_code;
+ msg.hdr.err_param = 0;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* pretend that we received a rej message */
+ evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1];
+
+ if (evt & AVDT_CCB_MKR) {
+ avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR),
+ (tAVDT_CCB_EVT*)&msg);
+ } else {
+ /* we get the scb out of the current cmd */
+ p_scb = avdt_scb_by_hdl(*((uint8_t*)(p_ccb->p_curr_cmd + 1)));
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT*)&msg);
+ }
+ }
+
+ osi_free_and_reset((void**)&p_ccb->p_curr_cmd);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_free_cmd
+ *
+ * Description This function is called when a response is received for a
+ * currently pending command. The command is freed.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ osi_free_and_reset((void**)&p_ccb->p_curr_cmd);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_cong_state
+ *
+ * Description This function is called to set the congestion state for
+ * the CCB.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ p_ccb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_ret_cmd
+ *
+ * Description This function is called to retransmit the currently
+ * pending command. The retransmission count is incremented.
+ * If the count reaches the maximum number of retransmissions,
+ * the event is treated as a response timeout.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ uint8_t err_code = AVDT_ERR_TIMEOUT;
+
+ p_ccb->ret_count++;
+ if (p_ccb->ret_count == AVDT_RET_MAX) {
+ /* command failed */
+ p_ccb->ret_count = 0;
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code);
+
+ /* go to next queued command */
+ avdt_ccb_snd_cmd(p_ccb, p_data);
+ } else {
+ /* if command pending and we're not congested and not sending a fragment */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) &&
+ (p_ccb->p_curr_cmd != NULL)) {
+ /* make copy of message in p_curr_cmd and send it */
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+ memcpy(p_msg, p_ccb->p_curr_cmd,
+ (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset +
+ p_ccb->p_curr_cmd->len));
+ avdt_msg_send(p_ccb, p_msg);
+ }
+
+ /* restart ret timer */
+ alarm_cancel(p_ccb->idle_ccb_timer);
+ alarm_cancel(p_ccb->rsp_ccb_timer);
+ period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+ alarm_set_on_queue(p_ccb->ret_ccb_timer, interval_ms,
+ avdt_ccb_ret_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_cmd
+ *
+ * Description This function is called the send the next command,
+ * if any, in the command queue.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ BT_HDR* p_msg;
+
+ /* do we have commands to send? send next command; make sure we're clear;
+ ** not congested, not sending fragment, not waiting for response
+ */
+ if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) &&
+ (p_ccb->p_curr_cmd == NULL)) {
+ p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q);
+ if (p_msg != NULL) {
+ /* make a copy of buffer in p_curr_cmd */
+ p_ccb->p_curr_cmd = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+ memcpy(p_ccb->p_curr_cmd, p_msg,
+ (sizeof(BT_HDR) + p_msg->offset + p_msg->len));
+ avdt_msg_send(p_ccb, p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_snd_msg
+ *
+ * Description
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ BT_HDR* p_msg;
+
+ /* if not congested */
+ if (!p_ccb->cong) {
+ /* are we sending a fragmented message? continue sending fragment */
+ if (p_ccb->p_curr_msg != NULL) {
+ avdt_msg_send(p_ccb, NULL);
+ }
+ /* do we have responses to send? send them */
+ else if (!fixed_queue_is_empty(p_ccb->rsp_q)) {
+ while ((p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) {
+ if (avdt_msg_send(p_ccb, p_msg) == true) {
+ /* break out if congested */
+ break;
+ }
+ }
+ }
+
+ /* do we have commands to send? send next command */
+ avdt_ccb_snd_cmd(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_set_reconn
+ *
+ * Description This function is called to enable a reconnect attempt when
+ * a channel transitions from closing to idle state. It sets
+ * the reconn variable to true.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ p_ccb->reconn = true;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_clr_reconn
+ *
+ * Description This function is called to clear the reconn variable.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ p_ccb->reconn = false;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_chk_reconn
+ *
+ * Description This function is called to check if a reconnect attempt
+ * is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT
+ * to the CCB. If disabled, the CCB is deallocated.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ uint8_t err_code = AVDT_ERR_CONNECT;
+
+ if (p_ccb->reconn) {
+ p_ccb->reconn = false;
+
+ /* clear out ccb */
+ avdt_ccb_clear_ccb(p_ccb);
+
+ /* clear out current command, if any */
+ avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code);
+
+ /* reopen the signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+ } else {
+ avdt_ccb_ll_closed(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_chk_timer
+ *
+ * Description This function stops the CCB timer if the idle timer is
+ * running.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ alarm_cancel(p_ccb->idle_ccb_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_set_conn
+ *
+ * Description Set CCB variables associated with AVDT_ConnectReq().
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /* save callback */
+ p_ccb->p_conn_cback = p_data->connect.p_cback;
+
+ /* set security level */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP,
+ p_data->connect.sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT,
+ AVDT_CHAN_SIG);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_set_disconn
+ *
+ * Description Set CCB variables associated with AVDT_DisconnectReq().
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ /*
+ AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x",
+ p_ccb->p_conn_cback, p_data->disconnect.p_cback);
+ */
+ /* save callback */
+ if (p_data->disconnect.p_cback)
+ p_ccb->p_conn_cback = p_data->disconnect.p_cback;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_do_disconn
+ *
+ * Description Do action associated with AVDT_DisconnectReq().
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* close channel */
+ avdt_ccb_chan_close(p_ccb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_ll_closed
+ *
+ * Description Clear commands from and deallocate CCB.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) {
+ tAVDT_CTRL_CBACK* p_cback;
+ BD_ADDR bd_addr;
+ tAVDT_CTRL avdt_ctrl;
+
+ /* clear any pending commands */
+ avdt_ccb_clear_cmds(p_ccb, NULL);
+
+ /* save callback pointer, bd addr */
+ p_cback = p_ccb->p_conn_cback;
+ if (!p_cback) p_cback = avdt_cb.p_conn_cback;
+ memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* dealloc ccb */
+ avdt_ccb_dealloc(p_ccb, NULL);
+
+ /* call callback */
+ if (p_cback) {
+ avdt_ctrl.hdr.err_code = 0;
+ (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_ccb_ll_opened
+ *
+ * Description Call callback on open.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+
+ p_ccb->ll_opened = true;
+
+ if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdt_cb.p_conn_cback;
+
+ /* call callback */
+ if (p_ccb->p_conn_cback) {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param;
+ (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT,
+ &avdt_ctrl);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_defs.h b/mtkbt/code/bt/stack/avdt/avdt_defs.h
new file mode 100755
index 0000000..02e9241
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_defs.h
@@ -0,0 +1,242 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This contains constants definitions and other information from the AVDTP
+ * specification. This file is intended for use internal to AVDT only.
+ *
+ ******************************************************************************/
+#ifndef AVDT_DEFS_H
+#define AVDT_DEFS_H
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* signalling packet type */
+#define AVDT_PKT_TYPE_SINGLE 0 /* single packet */
+#define AVDT_PKT_TYPE_START 1 /* start packet */
+#define AVDT_PKT_TYPE_CONT 2 /* continue packet */
+#define AVDT_PKT_TYPE_END 3 /* end packet */
+
+/* signalling message type */
+#define AVDT_MSG_TYPE_CMD 0 /* command */
+#define AVDT_MSG_TYPE_GRJ 1 /* general reject */
+#define AVDT_MSG_TYPE_RSP 2 /* response accept */
+#define AVDT_MSG_TYPE_REJ 3 /* response reject */
+
+/* signalling messages */
+#define AVDT_SIG_DISCOVER 1 /* discover */
+#define AVDT_SIG_GETCAP 2 /* get capabilities */
+#define AVDT_SIG_SETCONFIG 3 /* set configuration */
+#define AVDT_SIG_GETCONFIG 4 /* get configuration */
+#define AVDT_SIG_RECONFIG 5 /* reconfigure */
+#define AVDT_SIG_OPEN 6 /* open */
+#define AVDT_SIG_START 7 /* start */
+#define AVDT_SIG_CLOSE 8 /* close */
+#define AVDT_SIG_SUSPEND 9 /* suspend */
+#define AVDT_SIG_ABORT 10 /* abort */
+#define AVDT_SIG_SECURITY 11 /* security control */
+#define AVDT_SIG_GET_ALLCAP 12 /* get all capabilities */
+#define AVDT_SIG_DELAY_RPT 13 /* delay report */
+
+/* maximum signal value */
+#define AVDT_SIG_MAX AVDT_SIG_DELAY_RPT
+
+/* used for general reject */
+#define AVDT_SIG_NONE 0
+
+/* some maximum and minimum sizes of signalling messages */
+#define AVDT_DISCOVER_REQ_MIN 1
+#define AVDT_DISCOVER_REQ_MAX 124
+
+/* service category information element field values */
+#define AVDT_CAT_TRANS 1 /* Media Transport */
+#define AVDT_CAT_REPORT 2 /* Reporting */
+#define AVDT_CAT_RECOV 3 /* Recovery */
+#define AVDT_CAT_PROTECT 4 /* Content Protection */
+#define AVDT_CAT_HDRCMP 5 /* Header Compression */
+#define AVDT_CAT_MUX 6 /* Multiplexing */
+#define AVDT_CAT_CODEC 7 /* Media Codec */
+#define AVDT_CAT_DELAY_RPT 8 /* Delay Reporting */
+#define AVDT_CAT_MAX_CUR AVDT_CAT_DELAY_RPT
+
+/* min/max lengths of service category information elements */
+#define AVDT_LEN_TRANS_MIN 0
+#define AVDT_LEN_REPORT_MIN 0
+#define AVDT_LEN_RECOV_MIN 3
+#define AVDT_LEN_PROTECT_MIN 2
+#define AVDT_LEN_HDRCMP_MIN 1
+#define AVDT_LEN_MUX_MIN 3
+#define AVDT_LEN_CODEC_MIN 2
+#define AVDT_LEN_DELAY_RPT_MIN 0
+
+#define AVDT_LEN_TRANS_MAX 0
+#define AVDT_LEN_REPORT_MAX 0
+#define AVDT_LEN_RECOV_MAX 3
+#define AVDT_LEN_PROTECT_MAX 255
+#define AVDT_LEN_HDRCMP_MAX 1
+#define AVDT_LEN_MUX_MAX 7
+#define AVDT_LEN_CODEC_MAX 255
+#define AVDT_LEN_DELAY_RPT_MAX 0
+
+/* minimum possible size of configuration or capabilities data */
+#define AVDT_LEN_CFG_MIN 2
+
+/* minimum and maximum lengths for different message types */
+#define AVDT_LEN_SINGLE 1
+#define AVDT_LEN_SETCONFIG_MIN 2
+#define AVDT_LEN_RECONFIG_MIN 1
+#define AVDT_LEN_MULTI_MIN 1
+#define AVDT_LEN_SECURITY_MIN 1
+#define AVDT_LEN_DELAY_RPT 3
+
+/* header lengths for different packet types */
+#define AVDT_LEN_TYPE_SINGLE 2 /* single packet */
+#define AVDT_LEN_TYPE_START 3 /* start packet */
+#define AVDT_LEN_TYPE_CONT 1 /* continue packet */
+#define AVDT_LEN_TYPE_END 1 /* end packet */
+
+/* length of general reject message */
+#define AVDT_LEN_GEN_REJ 2
+
+/* recovery service capabilities information elements */
+/* min value for maximum recovery window */
+#define AVDT_RECOV_MRWS_MIN 0x01
+/* max value for maximum recovery window */
+#define AVDT_RECOV_MRWS_MAX 0x18
+/* min value for maximum number of media packets */
+#define AVDT_RECOV_MNMP_MIN 0x01
+/* max value for maximum number of media packets */
+#define AVDT_RECOV_MNMP_MAX 0x18
+
+/* SEID value range */
+#define AVDT_SEID_MIN 0x01
+#define AVDT_SEID_MAX 0x3E
+
+/* first byte of media packet header */
+#define AVDT_MEDIA_OCTET1 0x80
+
+/* for adaptation layer header */
+/* coding of length field */
+#define AVDT_ALH_LCODE_MASK 0x03
+/* No length field present. Take length from l2cap */
+#define AVDT_ALH_LCODE_NONE 0x00
+/* 16bit length field */
+#define AVDT_ALH_LCODE_16BIT 0x01
+/* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */
+#define AVDT_ALH_LCODE_9BITM0 0x02
+/* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */
+#define AVDT_ALH_LCODE_9BITM1 0x03
+
+/* set this for continuation packet */
+#define AVDT_ALH_FRAG_MASK 0x04
+
+/*****************************************************************************
+ * message parsing and building macros
+ ****************************************************************************/
+
+#define AVDT_MSG_PRS_HDR(p, lbl, pkt, msg) \
+ do { \
+ (lbl) = (*(p) >> 4) & 0x0F; \
+ (pkt) = (*(p) >> 2) & 0x03; \
+ (msg) = *(p)++ & 0x03; \
+ } while (0)
+
+#define AVDT_MSG_PRS_DISC(p, seid, in_use, type, tsep) \
+ do { \
+ (seid) = *(p) >> 2; \
+ (in_use) = (*(p)++ >> 1) & 0x01; \
+ (type) = (*(p) >> 4) & 0x0F; \
+ (tsep) = (*(p)++ >> 3) & 0x01; \
+ } while (0)
+
+#define AVDT_MSG_PRS_SIG(p, sig) \
+ do { \
+ (sig) = (*(p)++) & 0x3F; \
+ } while (0)
+
+#define AVDT_MSG_PRS_SEID(p, seid) \
+ do { \
+ (seid) = ((*(p)++) >> 2) & 0x3F; \
+ } while (0)
+
+#define AVDT_MSG_PRS_PKT_TYPE(p, pkt) \
+ do { \
+ (pkt) = (*(p) >> 2) & 0x03; \
+ } while (0)
+
+#define AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc) \
+ do { \
+ (o_v) = (*(p) >> 6) & 0x02; \
+ (o_p) = (*(p) >> 5) & 0x01; \
+ (o_x) = (*(p) >> 4) & 0x01; \
+ (o_cc) = (*(p)++) & 0x0F; \
+ } while (0)
+
+#define AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc) \
+ do { \
+ (o_v) = (*(p) >> 6) & 0x02; \
+ (o_p) = (*(p) >> 5) & 0x01; \
+ (o_cc) = (*(p)++) & 0x1F; \
+ } while (0)
+
+#define AVDT_MSG_PRS_M_PT(p, m_pt, marker) \
+ do { \
+ (marker) = (*(p) >> 7) & 0x01; \
+ (m_pt) = (*(p)++) & 0x7F; \
+ } while (0)
+
+#define AVDT_MSG_BLD_HDR(p, lbl, pkt, msg) \
+ do { \
+ *(p)++ = (uint8_t)((lbl) << 4) | ((pkt) << 2) | (msg); \
+ } while (0)
+
+#define AVDT_MSG_BLD_DISC(p, seid, in_use, type, tsep) \
+ do { \
+ *(p)++ = (uint8_t)(((seid) << 2) | ((in_use) << 1)); \
+ *(p)++ = (uint8_t)(((type) << 4) | ((tsep) << 3)); \
+ } while (0)
+
+#define AVDT_MSG_BLD_SIG(p, sig) \
+ do { \
+ *(p)++ = (uint8_t)(sig); \
+ } while (0)
+
+#define AVDT_MSG_BLD_SEID(p, seid) \
+ do { \
+ *(p)++ = (uint8_t)((seid) << 2); \
+ } while (0)
+
+#define AVDT_MSG_BLD_ERR(p, err) \
+ do { \
+ *(p)++ = (uint8_t)(err); \
+ } while (0)
+
+#define AVDT_MSG_BLD_PARAM(p, param) \
+ do { \
+ *(p)++ = (uint8_t)(param); \
+ } while (0)
+
+#define AVDT_MSG_BLD_NOSP(p, nosp) \
+ do { \
+ *(p)++ = (uint8_t)(nosp); \
+ } while (0)
+
+#endif /* AVDT_DEFS_H */
diff --git a/mtkbt/code/bt/stack/avdt/avdt_int.h b/mtkbt/code/bt/stack/avdt/avdt_int.h
new file mode 100755
index 0000000..8d45418
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_int.h
@@ -0,0 +1,715 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains interfaces which are internal to AVDTP.
+ *
+ ******************************************************************************/
+#ifndef AVDT_INT_H
+#define AVDT_INT_H
+
+#include "avdt_api.h"
+#include "avdt_defs.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+
+#ifndef AVDT_DEBUG
+#define AVDT_DEBUG FALSE
+#endif
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* channel types */
+enum {
+ AVDT_CHAN_SIG, /* signaling channel */
+ AVDT_CHAN_MEDIA, /* media channel */
+#if (AVDT_REPORTING == TRUE)
+ AVDT_CHAN_REPORT, /* reporting channel */
+#endif
+ AVDT_CHAN_NUM_TYPES
+};
+
+/* protocol service capabilities of this AVDTP implementation */
+#if (AVDT_REPORTING == TRUE)
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT)
+#else /* AVDT_REPORTING */
+#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT)
+#define AVDT_LEG_PSC (AVDT_PSC_TRANS)
+#endif /* AVDT_REPORTING */
+
+/* initiator/acceptor signaling roles */
+#define AVDT_CLOSE_ACP 0
+#define AVDT_CLOSE_INT 1
+#define AVDT_OPEN_ACP 2
+#define AVDT_OPEN_INT 3
+
+/* states for avdt_scb_verify */
+#define AVDT_VERIFY_OPEN 0
+#define AVDT_VERIFY_STREAMING 1
+#define AVDT_VERIFY_SUSPEND 2
+#define AVDT_VERIFY_START 3
+
+/* to distinguish CCB events from SCB events */
+#define AVDT_CCB_MKR 0x80
+
+/* offset where AVDTP signaling message content starts;
+ * use the size of a start header since it's the largest possible
+ * layout of signaling message in a buffer is:
+ *
+ * | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... |
+ *
+ * Note that we "hide" the scb handles at the top of the message buffer.
+*/
+#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START)
+
+/* scb transport channel connect timeout value (in milliseconds) */
+#define AVDT_SCB_TC_CONN_TIMEOUT_MS (10 * 1000)
+
+/* scb transport channel disconnect timeout value (in milliseconds) */
+#define AVDT_SCB_TC_DISC_TIMEOUT_MS (10 * 1000)
+
+/* maximum number of command retransmissions */
+#ifndef AVDT_RET_MAX
+#define AVDT_RET_MAX 1
+#endif
+
+/* ccb state machine states */
+enum {
+ AVDT_CCB_IDLE_ST,
+ AVDT_CCB_OPENING_ST,
+ AVDT_CCB_OPEN_ST,
+ AVDT_CCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_CCB_CHAN_OPEN,
+ AVDT_CCB_CHAN_CLOSE,
+ AVDT_CCB_CHK_CLOSE,
+ AVDT_CCB_HDL_DISCOVER_CMD,
+ AVDT_CCB_HDL_DISCOVER_RSP,
+ AVDT_CCB_HDL_GETCAP_CMD,
+ AVDT_CCB_HDL_GETCAP_RSP,
+ AVDT_CCB_HDL_START_CMD,
+ AVDT_CCB_HDL_START_RSP,
+ AVDT_CCB_HDL_SUSPEND_CMD,
+ AVDT_CCB_HDL_SUSPEND_RSP,
+ AVDT_CCB_SND_DISCOVER_CMD,
+ AVDT_CCB_SND_DISCOVER_RSP,
+ AVDT_CCB_SND_GETCAP_CMD,
+ AVDT_CCB_SND_GETCAP_RSP,
+ AVDT_CCB_SND_START_CMD,
+ AVDT_CCB_SND_START_RSP,
+ AVDT_CCB_SND_SUSPEND_CMD,
+ AVDT_CCB_SND_SUSPEND_RSP,
+ AVDT_CCB_CLEAR_CMDS,
+ AVDT_CCB_CMD_FAIL,
+ AVDT_CCB_FREE_CMD,
+ AVDT_CCB_CONG_STATE,
+ AVDT_CCB_RET_CMD,
+ AVDT_CCB_SND_CMD,
+ AVDT_CCB_SND_MSG,
+ AVDT_CCB_SET_RECONN,
+ AVDT_CCB_CLR_RECONN,
+ AVDT_CCB_CHK_RECONN,
+ AVDT_CCB_CHK_TIMER,
+ AVDT_CCB_SET_CONN,
+ AVDT_CCB_SET_DISCONN,
+ AVDT_CCB_DO_DISCONN,
+ AVDT_CCB_LL_CLOSED,
+ AVDT_CCB_LL_OPENED,
+ AVDT_CCB_DEALLOC,
+ AVDT_CCB_NUM_ACTIONS
+};
+
+#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS
+
+/* ccb state machine events */
+enum {
+ AVDT_CCB_API_DISCOVER_REQ_EVT,
+ AVDT_CCB_API_GETCAP_REQ_EVT,
+ AVDT_CCB_API_START_REQ_EVT,
+ AVDT_CCB_API_SUSPEND_REQ_EVT,
+ AVDT_CCB_API_DISCOVER_RSP_EVT,
+ AVDT_CCB_API_GETCAP_RSP_EVT,
+ AVDT_CCB_API_START_RSP_EVT,
+ AVDT_CCB_API_SUSPEND_RSP_EVT,
+ AVDT_CCB_API_CONNECT_REQ_EVT,
+ AVDT_CCB_API_DISCONNECT_REQ_EVT,
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT,
+ AVDT_CCB_MSG_GETCAP_CMD_EVT,
+ AVDT_CCB_MSG_START_CMD_EVT,
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT,
+ AVDT_CCB_MSG_GETCAP_RSP_EVT,
+ AVDT_CCB_MSG_START_RSP_EVT,
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_CCB_RCVRSP_EVT,
+ AVDT_CCB_SENDMSG_EVT,
+ AVDT_CCB_RET_TOUT_EVT,
+ AVDT_CCB_RSP_TOUT_EVT,
+ AVDT_CCB_IDLE_TOUT_EVT,
+ AVDT_CCB_UL_OPEN_EVT,
+ AVDT_CCB_UL_CLOSE_EVT,
+ AVDT_CCB_LL_OPEN_EVT,
+ AVDT_CCB_LL_CLOSE_EVT,
+ AVDT_CCB_LL_CONG_EVT
+};
+
+/* scb state machine states; these state values are private to this module so
+ * the scb state cannot be read or set by actions functions
+*/
+enum {
+ AVDT_SCB_IDLE_ST,
+ AVDT_SCB_CONF_ST,
+ AVDT_SCB_OPENING_ST,
+ AVDT_SCB_OPEN_ST,
+ AVDT_SCB_STREAM_ST,
+ AVDT_SCB_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum {
+ AVDT_SCB_HDL_ABORT_CMD,
+ AVDT_SCB_HDL_ABORT_RSP,
+ AVDT_SCB_HDL_CLOSE_CMD,
+ AVDT_SCB_HDL_CLOSE_RSP,
+ AVDT_SCB_HDL_GETCONFIG_CMD,
+ AVDT_SCB_HDL_GETCONFIG_RSP,
+ AVDT_SCB_HDL_OPEN_CMD,
+ AVDT_SCB_HDL_OPEN_REJ,
+ AVDT_SCB_HDL_OPEN_RSP,
+ AVDT_SCB_HDL_PKT,
+ AVDT_SCB_DROP_PKT,
+ AVDT_SCB_HDL_RECONFIG_CMD,
+ AVDT_SCB_HDL_RECONFIG_RSP,
+ AVDT_SCB_HDL_SECURITY_CMD,
+ AVDT_SCB_HDL_SECURITY_RSP,
+ AVDT_SCB_HDL_SETCONFIG_CMD,
+ AVDT_SCB_HDL_SETCONFIG_REJ,
+ AVDT_SCB_HDL_SETCONFIG_RSP,
+ AVDT_SCB_HDL_START_CMD,
+ AVDT_SCB_HDL_START_RSP,
+ AVDT_SCB_HDL_SUSPEND_CMD,
+ AVDT_SCB_HDL_SUSPEND_RSP,
+ AVDT_SCB_HDL_TC_CLOSE,
+#if (AVDT_REPORTING == TRUE)
+ AVDT_SCB_HDL_TC_CLOSE_STO,
+#endif
+ AVDT_SCB_HDL_TC_OPEN,
+#if (AVDT_REPORTING == TRUE)
+ AVDT_SCB_HDL_TC_OPEN_STO,
+#endif
+ AVDT_SCB_SND_DELAY_RPT_REQ,
+ AVDT_SCB_HDL_DELAY_RPT_CMD,
+ AVDT_SCB_HDL_DELAY_RPT_RSP,
+ AVDT_SCB_HDL_WRITE_REQ,
+ AVDT_SCB_SND_ABORT_REQ,
+ AVDT_SCB_SND_ABORT_RSP,
+ AVDT_SCB_SND_CLOSE_REQ,
+ AVDT_SCB_SND_STREAM_CLOSE,
+ AVDT_SCB_SND_CLOSE_RSP,
+ AVDT_SCB_SND_GETCONFIG_REQ,
+ AVDT_SCB_SND_GETCONFIG_RSP,
+ AVDT_SCB_SND_OPEN_REQ,
+ AVDT_SCB_SND_OPEN_RSP,
+ AVDT_SCB_SND_RECONFIG_REQ,
+ AVDT_SCB_SND_RECONFIG_RSP,
+ AVDT_SCB_SND_SECURITY_REQ,
+ AVDT_SCB_SND_SECURITY_RSP,
+ AVDT_SCB_SND_SETCONFIG_REQ,
+ AVDT_SCB_SND_SETCONFIG_REJ,
+ AVDT_SCB_SND_SETCONFIG_RSP,
+ AVDT_SCB_SND_TC_CLOSE,
+ AVDT_SCB_CB_ERR,
+ AVDT_SCB_CONG_STATE,
+ AVDT_SCB_REJ_STATE,
+ AVDT_SCB_REJ_IN_USE,
+ AVDT_SCB_REJ_NOT_IN_USE,
+ AVDT_SCB_SET_REMOVE,
+ AVDT_SCB_FREE_PKT,
+ AVDT_SCB_CLR_PKT,
+ AVDT_SCB_CHK_SND_PKT,
+ AVDT_SCB_TC_TIMER,
+ AVDT_SCB_CLR_VARS,
+ AVDT_SCB_DEALLOC,
+ AVDT_SCB_NUM_ACTIONS
+};
+
+#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS
+
+/* scb state machine events */
+enum {
+ AVDT_SCB_API_REMOVE_EVT,
+ AVDT_SCB_API_WRITE_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_REQ_EVT,
+ AVDT_SCB_API_DELAY_RPT_REQ_EVT,
+ AVDT_SCB_API_SETCONFIG_REQ_EVT,
+ AVDT_SCB_API_OPEN_REQ_EVT,
+ AVDT_SCB_API_CLOSE_REQ_EVT,
+ AVDT_SCB_API_RECONFIG_REQ_EVT,
+ AVDT_SCB_API_SECURITY_REQ_EVT,
+ AVDT_SCB_API_ABORT_REQ_EVT,
+ AVDT_SCB_API_GETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_RSP_EVT,
+ AVDT_SCB_API_SETCONFIG_REJ_EVT,
+ AVDT_SCB_API_OPEN_RSP_EVT,
+ AVDT_SCB_API_CLOSE_RSP_EVT,
+ AVDT_SCB_API_RECONFIG_RSP_EVT,
+ AVDT_SCB_API_SECURITY_RSP_EVT,
+ AVDT_SCB_API_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT,
+ AVDT_SCB_MSG_OPEN_CMD_EVT,
+ AVDT_SCB_MSG_START_CMD_EVT,
+ AVDT_SCB_MSG_SUSPEND_CMD_EVT,
+ AVDT_SCB_MSG_CLOSE_CMD_EVT,
+ AVDT_SCB_MSG_ABORT_CMD_EVT,
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT,
+ AVDT_SCB_MSG_SECURITY_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT,
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT,
+ AVDT_SCB_MSG_OPEN_RSP_EVT,
+ AVDT_SCB_MSG_START_RSP_EVT,
+ AVDT_SCB_MSG_SUSPEND_RSP_EVT,
+ AVDT_SCB_MSG_CLOSE_RSP_EVT,
+ AVDT_SCB_MSG_ABORT_RSP_EVT,
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT,
+ AVDT_SCB_MSG_SECURITY_RSP_EVT,
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT,
+ AVDT_SCB_MSG_OPEN_REJ_EVT,
+ AVDT_SCB_MSG_START_REJ_EVT,
+ AVDT_SCB_MSG_SUSPEND_REJ_EVT,
+ AVDT_SCB_TC_TOUT_EVT,
+ AVDT_SCB_TC_OPEN_EVT,
+ AVDT_SCB_TC_CLOSE_EVT,
+ AVDT_SCB_TC_CONG_EVT,
+ AVDT_SCB_TC_DATA_EVT,
+ AVDT_SCB_CC_CLOSE_EVT
+};
+
+/* adaption layer number of stream routing table entries */
+#if (AVDT_REPORTING == TRUE)
+/* 2 channels(1 media, 1 report) for each SEP and one for signalling */
+#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS << 1) + 1)
+#else
+#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1)
+#endif
+
+/* adaption layer number of transport channel table entries - moved to target.h
+#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */
+
+/* "states" used in transport channel table */
+#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */
+#define AVDT_AD_ST_IDLE 1 /* No connection */
+#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */
+#define AVDT_AD_ST_INT 3 /* Initiating a connection */
+#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */
+#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */
+#define AVDT_AD_ST_OPEN 6 /* Channel opened */
+#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */
+#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */
+
+/* Configuration flags. tAVDT_TC_TBL.cfg_flags */
+#define AVDT_L2C_CFG_IND_DONE (1 << 0)
+#define AVDT_L2C_CFG_CFM_DONE (1 << 1)
+#define AVDT_L2C_CFG_CONN_INT (1 << 2)
+#define AVDT_L2C_CFG_CONN_ACP (1 << 3)
+
+/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */
+#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */
+#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */
+#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */
+
+/*****************************************************************************
+ * data types
+ ****************************************************************************/
+
+/* msg union of all message parameter types */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_EVT_HDR single;
+ tAVDT_SETCONFIG config_cmd;
+ tAVDT_CONFIG reconfig_cmd;
+ tAVDT_MULTI multi;
+ tAVDT_SECURITY security_cmd;
+ tAVDT_DISCOVER discover_rsp;
+ tAVDT_CONFIG svccap;
+ tAVDT_SECURITY security_rsp;
+ tAVDT_DELAY_RPT delay_rpt_cmd;
+} tAVDT_MSG;
+
+/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK* p_cback;
+ tAVDT_SEP_INFO* p_sep_info;
+ uint8_t num_seps;
+} tAVDT_CCB_API_DISCOVER;
+
+/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */
+typedef struct {
+ tAVDT_EVT_HDR single;
+ tAVDT_CTRL_CBACK* p_cback;
+ tAVDT_CFG* p_cfg;
+} tAVDT_CCB_API_GETCAP;
+
+/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */
+typedef struct {
+ tAVDT_CTRL_CBACK* p_cback;
+ uint8_t sec_mask;
+} tAVDT_CCB_API_CONNECT;
+
+/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */
+typedef struct { tAVDT_CTRL_CBACK* p_cback; } tAVDT_CCB_API_DISCONNECT;
+
+/* union associated with ccb state machine events */
+typedef union {
+ tAVDT_CCB_API_DISCOVER discover;
+ tAVDT_CCB_API_GETCAP getcap;
+ tAVDT_CCB_API_CONNECT connect;
+ tAVDT_CCB_API_DISCONNECT disconnect;
+ tAVDT_MSG msg;
+ bool llcong;
+ uint8_t err_code;
+} tAVDT_CCB_EVT;
+
+/* channel control block type */
+typedef struct {
+ BD_ADDR peer_addr; /* BD address of peer */
+ /*
+ * NOTE: idle_ccb_timer, ret_ccb_timer and rsp_ccb_timer are mutually
+ * exclusive - no more than one timer should be running at the same time.
+ */
+ alarm_t* idle_ccb_timer; /* Idle CCB timer entry */
+ alarm_t* ret_ccb_timer; /* Ret CCB timer entry */
+ alarm_t* rsp_ccb_timer; /* Rsp CCB timer entry */
+ fixed_queue_t* cmd_q; /* Queue for outgoing command messages */
+ fixed_queue_t* rsp_q; /* Queue for outgoing response and reject messages */
+ tAVDT_CTRL_CBACK* proc_cback; /* Procedure callback function */
+ tAVDT_CTRL_CBACK*
+ p_conn_cback; /* Connection/disconnection callback function */
+ void* p_proc_data; /* Pointer to data storage for procedure */
+ BT_HDR* p_curr_cmd; /* Current command being sent awaiting response */
+ BT_HDR* p_curr_msg; /* Current message being sent */
+ BT_HDR* p_rx_msg; /* Current message being received */
+ bool allocated; /* Whether ccb is allocated */
+ uint8_t state; /* The CCB state machine state */
+ bool ll_opened; /* true if LL is opened */
+ bool proc_busy; /* true when a discover or get capabilities procedure in
+ progress */
+ uint8_t proc_param; /* Procedure parameter; either SEID for get capabilities
+ or number of SEPS for discover */
+ bool cong; /* Whether signaling channel is congested */
+ uint8_t label; /* Message header "label" (sequence number) */
+ bool reconn; /* If true, reinitiate connection after transitioning from
+ CLOSING to IDLE state */
+ uint8_t ret_count; /* Command retransmission count */
+} tAVDT_CCB;
+
+/* type for action functions */
+typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+
+/* type for AVDT_SCB_API_WRITE_REQ_EVT */
+typedef struct {
+ BT_HDR* p_buf;
+ uint32_t time_stamp;
+ uint8_t m_pt;
+ tAVDT_DATA_OPT_MASK opt;
+} tAVDT_SCB_APIWRITE;
+
+/* type for AVDT_SCB_TC_CLOSE_EVT */
+typedef struct {
+ uint8_t old_tc_state; /* channel state before closed */
+ uint8_t tcid; /* TCID */
+ uint8_t type; /* channel type */
+} tAVDT_SCB_TC_CLOSE;
+
+/* type for scb event data */
+typedef union {
+ tAVDT_MSG msg;
+ tAVDT_SCB_APIWRITE apiwrite;
+ tAVDT_DELAY_RPT apidelay;
+ tAVDT_OPEN open;
+ tAVDT_SCB_TC_CLOSE close;
+ bool llcong;
+ BT_HDR* p_pkt;
+} tAVDT_SCB_EVT;
+
+/* stream control block type */
+typedef struct {
+ tAVDT_CS cs; /* stream creation struct */
+ tAVDT_CFG curr_cfg; /* current configuration */
+ tAVDT_CFG req_cfg; /* requested configuration */
+ alarm_t* transport_channel_timer; /* transport channel connect timer */
+ BT_HDR* p_pkt; /* packet waiting to be sent */
+ tAVDT_CCB* p_ccb; /* ccb associated with this scb */
+ uint16_t media_seq; /* media packet sequence number */
+ bool allocated; /* whether scb is allocated or unused */
+ bool in_use; /* whether stream being used by peer */
+ uint8_t role; /* initiator/acceptor role in current procedure */
+ bool remove; /* whether CB is marked for removal */
+ uint8_t state; /* state machine state */
+ uint8_t peer_seid; /* SEID of peer stream */
+ uint8_t curr_evt; /* current event; set only by state machine */
+ bool cong; /* Whether media transport channel is congested */
+ uint8_t close_code; /* Error code received in close response */
+} tAVDT_SCB;
+
+/* type for action functions */
+typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+
+/* adaption layer type for transport channel table */
+typedef struct {
+ uint16_t peer_mtu; /* L2CAP mtu of the peer device */
+ uint16_t my_mtu; /* Our MTU for this channel */
+ uint16_t my_flush_to; /* Our flush timeout for this channel */
+ uint16_t lcid;
+ uint8_t tcid; /* transport channel id */
+ uint8_t ccb_idx; /* channel control block associated with this tc */
+ uint8_t state; /* transport channel state */
+ uint8_t cfg_flags; /* L2CAP configuration flags */
+ uint8_t id;
+} tAVDT_TC_TBL;
+
+/* adaption layer type for stream routing table */
+typedef struct {
+ uint16_t lcid; /* L2CAP LCID of the associated transport channel */
+ uint8_t scb_hdl; /* stream control block associated with this tc */
+} tAVDT_RT_TBL;
+
+/* adaption layer control block */
+typedef struct {
+ tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL];
+ tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL];
+ uint8_t lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
+} tAVDT_AD;
+
+/* Control block for AVDT */
+typedef struct {
+ tAVDT_REG rcb; /* registration control block */
+ tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */
+ tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */
+ tAVDT_AD ad; /* adaption layer control block */
+ tAVDTC_CTRL_CBACK* p_conf_cback; /* conformance callback function */
+ tAVDT_CCB_ACTION* p_ccb_act; /* pointer to CCB action functions */
+ tAVDT_SCB_ACTION* p_scb_act; /* pointer to SCB action functions */
+ tAVDT_CTRL_CBACK* p_conn_cback; /* connection callback function */
+ uint8_t trace_level; /* trace level */
+} tAVDT_CB;
+
+/*****************************************************************************
+ * function declarations
+ ****************************************************************************/
+
+/* CCB function declarations */
+extern void avdt_ccb_init(void);
+extern void avdt_ccb_event(tAVDT_CCB* p_ccb, uint8_t event,
+ tAVDT_CCB_EVT* p_data);
+extern tAVDT_CCB* avdt_ccb_by_bd(BD_ADDR bd_addr);
+extern tAVDT_CCB* avdt_ccb_alloc(BD_ADDR bd_addr);
+extern void avdt_ccb_dealloc(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern uint8_t avdt_ccb_to_idx(tAVDT_CCB* p_ccb);
+extern tAVDT_CCB* avdt_ccb_by_idx(uint8_t idx);
+
+/* CCB action functions */
+extern void avdt_ccb_chan_open(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chan_close(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_close(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+extern void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data);
+
+/* SCB function prototypes */
+extern void avdt_scb_event(tAVDT_SCB* p_scb, uint8_t event,
+ tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_init(void);
+extern tAVDT_SCB* avdt_scb_alloc(tAVDT_CS* p_cs);
+extern void avdt_scb_dealloc(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern uint8_t avdt_scb_to_hdl(tAVDT_SCB* p_scb);
+extern tAVDT_SCB* avdt_scb_by_hdl(uint8_t hdl);
+extern uint8_t avdt_scb_verify(tAVDT_CCB* p_ccb, uint8_t state, uint8_t* p_seid,
+ uint16_t num_seid, uint8_t* p_err_code);
+extern void avdt_scb_peer_seid_list(tAVDT_MULTI* p_multi);
+extern uint32_t avdt_scb_gen_ssrc(tAVDT_SCB* p_scb);
+
+/* SCB action functions */
+extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_close_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_drop_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_security_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_start_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_start_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_open(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_hdl_write_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_abort_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_abort_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_close_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_stream_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_getconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_open_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_reconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_security_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_snd_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_cb_err(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_cong_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_in_use(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_rej_not_in_use(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_set_remove(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_free_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_chk_snd_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_clr_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_transport_channel_timer(tAVDT_SCB* p_scb,
+ tAVDT_SCB_EVT* p_data);
+extern void avdt_scb_clr_vars(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data);
+
+/* msg function declarations */
+extern bool avdt_msg_send(tAVDT_CCB* p_ccb, BT_HDR* p_msg);
+extern void avdt_msg_send_cmd(tAVDT_CCB* p_ccb, void* p_scb, uint8_t sig_id,
+ tAVDT_MSG* p_params);
+extern void avdt_msg_send_rsp(tAVDT_CCB* p_ccb, uint8_t sig_id,
+ tAVDT_MSG* p_params);
+extern void avdt_msg_send_rej(tAVDT_CCB* p_ccb, uint8_t sig_id,
+ tAVDT_MSG* p_params);
+extern void avdt_msg_send_grej(tAVDT_CCB* p_ccb, uint8_t sig_id,
+ tAVDT_MSG* p_params);
+extern void avdt_msg_ind(tAVDT_CCB* p_ccb, BT_HDR* p_buf);
+
+/* adaption layer function declarations */
+extern void avdt_ad_init(void);
+extern uint8_t avdt_ad_type_to_tcid(uint8_t type, tAVDT_SCB* p_scb);
+extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_st(uint8_t type, tAVDT_CCB* p_ccb,
+ uint8_t state);
+extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_lcid(uint16_t lcid);
+extern tAVDT_TC_TBL* avdt_ad_tc_tbl_alloc(tAVDT_CCB* p_ccb);
+extern uint8_t avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL* p_tbl);
+extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL* p_tbl, uint16_t reason);
+extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL* p_tbl);
+extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL* p_tbl, bool is_congested);
+extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL* p_tbl, BT_HDR* p_buf);
+extern tAVDT_TC_TBL* avdt_ad_tc_tbl_by_type(uint8_t type, tAVDT_CCB* p_ccb,
+ tAVDT_SCB* p_scb);
+extern uint8_t avdt_ad_write_req(uint8_t type, tAVDT_CCB* p_ccb,
+ tAVDT_SCB* p_scb, BT_HDR* p_buf);
+extern void avdt_ad_open_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb,
+ uint8_t role);
+extern void avdt_ad_close_req(uint8_t type, tAVDT_CCB* p_ccb, tAVDT_SCB* p_scb);
+
+extern void avdt_ccb_idle_ccb_timer_timeout(void* data);
+extern void avdt_ccb_ret_ccb_timer_timeout(void* data);
+extern void avdt_ccb_rsp_ccb_timer_timeout(void* data);
+extern void avdt_scb_transport_channel_timer_timeout(void* data);
+
+/*****************************************************************************
+ * macros
+ ****************************************************************************/
+
+/* we store the scb and the label in the layer_specific field of the
+ * current cmd
+*/
+#define AVDT_BLD_LAYERSPEC(ls, msg, label) ls = (((label) << 4) | (msg))
+
+#define AVDT_LAYERSPEC_LABEL(ls) ((uint8_t)((ls) >> 4))
+
+#define AVDT_LAYERSPEC_MSG(ls) ((uint8_t)((ls)&0x000F))
+
+/*****************************************************************************
+ * global data
+ ****************************************************************************/
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+extern tAVDT_CB avdt_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO avdt_l2c_appl;
+
+/* reject message event lookup table */
+extern const uint8_t avdt_msg_rej_2_evt[];
+
+#endif /* AVDT_INT_H */
diff --git a/mtkbt/code/bt/stack/avdt/avdt_l2c.cc b/mtkbt/code/bt/stack/avdt/avdt_l2c.cc
new file mode 100755
index 0000000..35502f8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_l2c.cc
@@ -0,0 +1,517 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This AVDTP adaption layer module interfaces to L2CAP
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "device/include/interop.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+/* callback function declarations */
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id);
+void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+void avdt_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+void avdt_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+void avdt_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
+void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO avdt_l2c_appl = {
+ avdt_l2c_connect_ind_cback,
+ avdt_l2c_connect_cfm_cback,
+ NULL,
+ avdt_l2c_config_ind_cback,
+ avdt_l2c_config_cfm_cback,
+ avdt_l2c_disconnect_ind_cback,
+ avdt_l2c_disconnect_cfm_cback,
+ NULL,
+ avdt_l2c_data_ind_cback,
+ avdt_l2c_congestion_ind_cback,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+ *
+ * Function avdt_sec_check_complete_term
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void avdt_sec_check_complete_term(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport,
+ UNUSED_ATTR void* p_ref_data,
+ uint8_t res) {
+ tAVDT_CCB* p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL* p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d", res);
+ if (!bd_addr) {
+ AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
+ return;
+ }
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
+ if (p_tbl == NULL) return;
+
+ if (res == BTM_SUCCESS) {
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp(bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK,
+ L2CAP_CONN_OK);
+
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] =
+ avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = true;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ } else {
+ L2CA_ConnectRsp(bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK,
+ L2CAP_CONN_OK);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_sec_check_complete_orig
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void avdt_sec_check_complete_orig(BD_ADDR bd_addr,
+ tBT_TRANSPORT trasnport,
+ UNUSED_ATTR void* p_ref_data,
+ uint8_t res) {
+ tAVDT_CCB* p_ccb = NULL;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_TC_TBL* p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d", res);
+ if (bd_addr) p_ccb = avdt_ccb_by_bd(bd_addr);
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
+ if (p_tbl == NULL) return;
+
+ if (res == BTM_SUCCESS) {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = true;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ } else {
+ L2CA_DisconnectReq(p_tbl->lcid);
+ avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+/*******************************************************************************
+ *
+ * Function avdt_l2c_connect_ind_cback
+ *
+ * Description This is the L2CAP connect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ UNUSED_ATTR uint16_t psm, uint8_t id) {
+ tAVDT_CCB* p_ccb;
+ tAVDT_TC_TBL* p_tbl = NULL;
+ uint16_t result;
+ tL2CAP_CFG_INFO cfg;
+ tBTM_STATUS rc;
+
+ /* do we already have a control channel for this peer? */
+ p_ccb = avdt_ccb_by_bd(bd_addr);
+ if (p_ccb == NULL) {
+ /* no, allocate ccb */
+ p_ccb = avdt_ccb_alloc(bd_addr);
+ if (p_ccb == NULL) {
+ /* no ccb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ } else {
+ /* allocate and set up entry; first channel is always signaling */
+ p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
+ p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
+ p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ p_tbl->tcid = AVDT_CHAN_SIG;
+ p_tbl->lcid = lcid;
+ p_tbl->id = id;
+ p_tbl->state = AVDT_AD_ST_SEC_ACP;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
+
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ (const bt_bdaddr_t*)&bd_addr)) {
+ // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+ tACL_CONN* p_acl_cb = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ btm_set_packet_types(
+ p_acl_cb,
+ (btm_cb.btm_acl_pkt_types_supported | HCI_PKT_TYPES_MASK_NO_3_DH1 |
+ HCI_PKT_TYPES_MASK_NO_3_DH3 | HCI_PKT_TYPES_MASK_NO_3_DH5));
+ }
+
+ /* Check the security */
+ rc = btm_sec_mx_access_request(bd_addr, AVDT_PSM, false,
+ BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_term, NULL);
+ if (rc == BTM_CMD_STARTED) {
+ L2CA_ConnectRsp(p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING,
+ L2CAP_CONN_OK);
+ }
+ return;
+ }
+ }
+ /* deal with simultaneous control channel connect case */
+ else {
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN);
+ if (p_tbl != NULL) {
+ /* reject their connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+ /* this must be a traffic channel; are we accepting a traffic channel
+ ** for this ccb?
+ */
+ else {
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP);
+ if (p_tbl != NULL) {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#if (AVDT_REPORTING == TRUE)
+ /* this must be a reporting channel; are we accepting a reporting channel
+ ** for this ccb?
+ */
+ else {
+ p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP);
+ if (p_tbl != NULL) {
+ /* yes; proceed with connection */
+ result = L2CAP_CONN_OK;
+ }
+#endif
+ /* else we're not listening for traffic channel; reject */
+ else {
+ result = L2CAP_CONN_NO_PSM;
+ }
+ }
+ }
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK) {
+ /* store idx in LCID table, store LCID in routing table */
+ avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] =
+ avdt_ad_tc_tbl_to_idx(p_tbl);
+ avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
+
+ /* transition to configuration state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = true;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_connect_cfm_cback
+ *
+ * Description This is the L2CAP connect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVDT_TC_TBL* p_tbl;
+ tL2CAP_CFG_INFO cfg;
+ tAVDT_CCB* p_ccb;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d", lcid,
+ result);
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CONN) {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK) {
+ if (p_tbl->tcid != AVDT_CHAN_SIG) {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_CFG;
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = p_tbl->my_mtu;
+ cfg.flush_to_present = true;
+ cfg.flush_to = p_tbl->my_flush_to;
+ L2CA_ConfigReq(lcid, &cfg);
+ } else {
+ p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
+ if (p_ccb == NULL) {
+ result = L2CAP_CONN_NO_RESOURCES;
+ } else {
+ /* set channel state */
+ p_tbl->state = AVDT_AD_ST_SEC_INT;
+ p_tbl->lcid = lcid;
+ p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
+
+ if (interop_match_addr(INTEROP_2MBPS_LINK_ONLY,
+ (const bt_bdaddr_t*)&p_ccb->peer_addr)) {
+ // Disable 3DH packets for AVDT ACL to improve sensitivity on HS
+ tACL_CONN* p_acl_cb =
+ btm_bda_to_acl(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
+ btm_set_packet_types(
+ p_acl_cb,
+ (btm_cb.btm_acl_pkt_types_supported |
+ HCI_PKT_TYPES_MASK_NO_3_DH1 | HCI_PKT_TYPES_MASK_NO_3_DH3 |
+ HCI_PKT_TYPES_MASK_NO_3_DH5));
+ }
+
+ /* Check the security */
+ btm_sec_mx_access_request(p_ccb->peer_addr, AVDT_PSM, true,
+ BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG,
+ &avdt_sec_check_complete_orig, NULL);
+ }
+ }
+ }
+
+ /* failure; notify adaption that channel closed */
+ if (result != L2CAP_CONN_OK) {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_config_cfm_cback
+ *
+ * Description This is the L2CAP config confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVDT_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ p_tbl->lcid = lcid;
+
+ /* if in correct state */
+ if (p_tbl->state == AVDT_AD_ST_CFG) {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CONN_OK) {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ /* else failure */
+ else {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_config_ind_cback
+ *
+ * Description This is the L2CAP config indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tAVDT_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present) {
+ p_tbl->peer_mtu = p_cfg->mtu;
+ } else {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x", p_tbl->peer_mtu, lcid);
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0) {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE) {
+ avdt_ad_tc_open_ind(p_tbl);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_disconnect_ind_cback
+ *
+ * Description This is the L2CAP disconnect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
+ tAVDT_TC_TBL* p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
+ lcid, ack_needed);
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ avdt_ad_tc_close_ind(p_tbl, 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_disconnect_cfm_cback
+ *
+ * Description This is the L2CAP disconnect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tAVDT_TC_TBL* p_tbl;
+
+ AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d", lcid,
+ result);
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ avdt_ad_tc_close_ind(p_tbl, result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_congestion_ind_cback
+ *
+ * Description This is the L2CAP congestion indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
+ tAVDT_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ avdt_ad_tc_cong_ind(p_tbl, is_congested);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_l2c_data_ind_cback
+ *
+ * Description This is the L2CAP data indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void avdt_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
+ tAVDT_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = avdt_ad_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ avdt_ad_tc_data_ind(p_tbl, p_buf);
+ } else /* prevent buffer leak */
+ osi_free(p_buf);
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_msg.cc b/mtkbt/code/bt/stack/avdt/avdt_msg.cc
new file mode 100755
index 0000000..2595ab8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_msg.cc
@@ -0,0 +1,1665 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains functions for parsing and building AVDTP signaling
+ * messages. It also contains functions called by the SCB or CCB state
+ * machines for sending command, response, and reject messages. It also
+ * contains a function that processes incoming messages and dispatches them
+ * to the appropriate SCB or CCB.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* mask of all psc values */
+#define AVDT_MSG_PSC_MASK \
+ (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT | AVDT_PSC_RECOV | \
+ AVDT_PSC_HDRCMP | AVDT_PSC_MUX)
+#define AVDT_PSC_PROTECT (1 << 4) /* Content Protection */
+#define AVDT_PSC_CODEC (1 << 7) /* codec */
+
+/*****************************************************************************
+ * type definitions
+ ****************************************************************************/
+
+/* type for message building functions */
+typedef void (*tAVDT_MSG_BLD)(uint8_t** p, tAVDT_MSG* p_msg);
+
+/* type for message parsing functions */
+typedef uint8_t (*tAVDT_MSG_PRS)(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len);
+
+/*****************************************************************************
+ * local function declarations
+ ****************************************************************************/
+
+static void avdt_msg_bld_none(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_single(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_setconfig_cmd(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_reconfig_cmd(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_multi(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_security_cmd(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_discover_rsp(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_svccap(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_security_rsp(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_all_svccap(uint8_t** p, tAVDT_MSG* p_msg);
+static void avdt_msg_bld_delay_rpt(uint8_t** p, tAVDT_MSG* p_msg);
+
+static uint8_t avdt_msg_prs_none(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len);
+static uint8_t avdt_msg_prs_single(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len);
+static uint8_t avdt_msg_prs_setconfig_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_reconfig_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_multi(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len);
+static uint8_t avdt_msg_prs_security_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_discover_rsp(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_svccap(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len);
+static uint8_t avdt_msg_prs_all_svccap(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+static uint8_t avdt_msg_prs_delay_rpt(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len);
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* table of information element minimum lengths used for parsing */
+const uint8_t avdt_msg_ie_len_min[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MIN, /* media transport */
+ AVDT_LEN_REPORT_MIN, /* reporting */
+ AVDT_LEN_RECOV_MIN, /* recovery */
+ AVDT_LEN_PROTECT_MIN, /* content protection */
+ AVDT_LEN_HDRCMP_MIN, /* header compression */
+ AVDT_LEN_MUX_MIN, /* multiplexing */
+ AVDT_LEN_CODEC_MIN, /* codec */
+ AVDT_LEN_DELAY_RPT_MIN /* delay report */
+};
+
+/* table of information element minimum lengths used for parsing */
+const uint8_t avdt_msg_ie_len_max[] = {
+ 0, /* unused */
+ AVDT_LEN_TRANS_MAX, /* media transport */
+ AVDT_LEN_REPORT_MAX, /* reporting */
+ AVDT_LEN_RECOV_MAX, /* recovery */
+ AVDT_LEN_PROTECT_MAX, /* content protection */
+ AVDT_LEN_HDRCMP_MAX, /* header compression */
+ AVDT_LEN_MUX_MAX, /* multiplexing */
+ AVDT_LEN_CODEC_MAX, /* codec */
+ AVDT_LEN_DELAY_RPT_MAX /* delay report */
+};
+
+/* table of error codes used when decoding information elements */
+const uint8_t avdt_msg_ie_err[] = {
+ 0, /* unused */
+ AVDT_ERR_MEDIA_TRANS, /* media transport */
+ AVDT_ERR_LENGTH, /* reporting */
+ AVDT_ERR_RECOV_FMT, /* recovery */
+ AVDT_ERR_CP_FMT, /* content protection */
+ AVDT_ERR_ROHC_FMT, /* header compression */
+ AVDT_ERR_MUX_FMT, /* multiplexing */
+ AVDT_ERR_SERVICE, /* codec */
+ AVDT_ERR_SERVICE /* delay report ?? */
+};
+
+/* table of packet type minimum lengths */
+static const uint8_t avdt_msg_pkt_type_len[] = {
+ AVDT_LEN_TYPE_SINGLE, AVDT_LEN_TYPE_START, AVDT_LEN_TYPE_CONT,
+ AVDT_LEN_TYPE_END};
+
+/* function table for building command messages */
+const tAVDT_MSG_BLD avdt_msg_bld_cmd[] = {
+ avdt_msg_bld_none, /* discover */
+ avdt_msg_bld_single, /* get capabilities */
+ avdt_msg_bld_setconfig_cmd, /* set configuration */
+ avdt_msg_bld_single, /* get configuration */
+ avdt_msg_bld_reconfig_cmd, /* reconfigure */
+ avdt_msg_bld_single, /* open */
+ avdt_msg_bld_multi, /* start */
+ avdt_msg_bld_single, /* close */
+ avdt_msg_bld_multi, /* suspend */
+ avdt_msg_bld_single, /* abort */
+ avdt_msg_bld_security_cmd, /* security control */
+ avdt_msg_bld_single, /* get all capabilities */
+ avdt_msg_bld_delay_rpt /* delay report */
+};
+
+/* function table for building response messages */
+const tAVDT_MSG_BLD avdt_msg_bld_rsp[] = {
+ avdt_msg_bld_discover_rsp, /* discover */
+ avdt_msg_bld_svccap, /* get capabilities */
+ avdt_msg_bld_none, /* set configuration */
+ avdt_msg_bld_all_svccap, /* get configuration */
+ avdt_msg_bld_none, /* reconfigure */
+ avdt_msg_bld_none, /* open */
+ avdt_msg_bld_none, /* start */
+ avdt_msg_bld_none, /* close */
+ avdt_msg_bld_none, /* suspend */
+ avdt_msg_bld_none, /* abort */
+ avdt_msg_bld_security_rsp, /* security control */
+ avdt_msg_bld_all_svccap, /* get all capabilities */
+ avdt_msg_bld_none /* delay report */
+};
+
+/* function table for parsing command messages */
+const tAVDT_MSG_PRS avdt_msg_prs_cmd[] = {
+ avdt_msg_prs_none, /* discover */
+ avdt_msg_prs_single, /* get capabilities */
+ avdt_msg_prs_setconfig_cmd, /* set configuration */
+ avdt_msg_prs_single, /* get configuration */
+ avdt_msg_prs_reconfig_cmd, /* reconfigure */
+ avdt_msg_prs_single, /* open */
+ avdt_msg_prs_multi, /* start */
+ avdt_msg_prs_single, /* close */
+ avdt_msg_prs_multi, /* suspend */
+ avdt_msg_prs_single, /* abort */
+ avdt_msg_prs_security_cmd, /* security control */
+ avdt_msg_prs_single, /* get all capabilities */
+ avdt_msg_prs_delay_rpt /* delay report */
+};
+
+/* function table for parsing response messages */
+const tAVDT_MSG_PRS avdt_msg_prs_rsp[] = {
+ avdt_msg_prs_discover_rsp, /* discover */
+ avdt_msg_prs_svccap, /* get capabilities */
+ avdt_msg_prs_none, /* set configuration */
+ avdt_msg_prs_all_svccap, /* get configuration */
+ avdt_msg_prs_none, /* reconfigure */
+ avdt_msg_prs_none, /* open */
+ avdt_msg_prs_none, /* start */
+ avdt_msg_prs_none, /* close */
+ avdt_msg_prs_none, /* suspend */
+ avdt_msg_prs_none, /* abort */
+ avdt_msg_prs_security_rsp, /* security control */
+ avdt_msg_prs_all_svccap, /* get all capabilities */
+ avdt_msg_prs_none /* delay report */
+};
+
+/* command message-to-event lookup table */
+const uint8_t avdt_msg_cmd_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_CMD_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_CMD_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_CMD_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_CMD_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_CMD_EVT, /* open */
+ AVDT_CCB_MSG_START_CMD_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_CMD_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_CMD_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_CMD_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_CMD_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_CMD_EVT /* delay report */
+};
+
+/* response message-to-event lookup table */
+const uint8_t avdt_msg_rsp_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_RSP_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_RSP_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ AVDT_SCB_MSG_DELAY_RPT_RSP_EVT /* delay report */
+};
+
+/* reject message-to-event lookup table */
+const uint8_t avdt_msg_rej_2_evt[] = {
+ AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */
+ AVDT_SCB_MSG_SETCONFIG_REJ_EVT, /* set configuration */
+ AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */
+ AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */
+ AVDT_SCB_MSG_OPEN_REJ_EVT, /* open */
+ AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */
+ AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */
+ AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */
+ AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */
+ AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */
+ AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */
+ 0 /* delay report */
+};
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_cfg
+ *
+ * Description This function builds the configuration parameters contained
+ * in a command or response message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_cfg(uint8_t** p, tAVDT_CFG* p_cfg) {
+ uint8_t len;
+
+ /* for now, just build media transport, codec, and content protection, and
+ * multiplexing */
+
+ /* media transport */
+ if (p_cfg->psc_mask & AVDT_PSC_TRANS) {
+ *(*p)++ = AVDT_CAT_TRANS;
+ *(*p)++ = 0; /* length */
+ }
+
+#if (AVDT_REPORTING == TRUE)
+ /* reporting transport */
+ if (p_cfg->psc_mask & AVDT_PSC_REPORT) {
+ *(*p)++ = AVDT_CAT_REPORT;
+ *(*p)++ = 0; /* length */
+ }
+#endif
+
+ /* codec */
+ if (p_cfg->num_codec != 0) {
+ *(*p)++ = AVDT_CAT_CODEC;
+ len = p_cfg->codec_info[0] + 1;
+ if (len > AVDT_CODEC_SIZE) len = AVDT_CODEC_SIZE;
+
+ memcpy(*p, p_cfg->codec_info, len);
+ *p += len;
+ }
+
+ /* content protection */
+ if (p_cfg->num_protect != 0) {
+ *(*p)++ = AVDT_CAT_PROTECT;
+ len = p_cfg->protect_info[0] + 1;
+ if (len > AVDT_PROTECT_SIZE) len = AVDT_PROTECT_SIZE;
+
+ memcpy(*p, p_cfg->protect_info, len);
+ *p += len;
+ }
+
+ /* delay report */
+ if (p_cfg->psc_mask & AVDT_PSC_DELAY_RPT) {
+ *(*p)++ = AVDT_CAT_DELAY_RPT;
+ *(*p)++ = 0; /* length */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_none
+ *
+ * Description This message building function builds an empty message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_none(UNUSED_ATTR uint8_t** p,
+ UNUSED_ATTR tAVDT_MSG* p_msg) {
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_single
+ *
+ * Description This message building function builds a message containing
+ * a single SEID.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_single(uint8_t** p, tAVDT_MSG* p_msg) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->single.seid);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_setconfig_cmd
+ *
+ * Description This message building function builds a set configuration
+ * command message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_setconfig_cmd(uint8_t** p, tAVDT_MSG* p_msg) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.hdr.seid);
+ AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.int_seid);
+ avdt_msg_bld_cfg(p, p_msg->config_cmd.p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_reconfig_cmd
+ *
+ * Description This message building function builds a reconfiguration
+ * command message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_reconfig_cmd(uint8_t** p, tAVDT_MSG* p_msg) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->reconfig_cmd.hdr.seid);
+
+ /* force psc mask zero to build only codec and security */
+ p_msg->reconfig_cmd.p_cfg->psc_mask = 0;
+ avdt_msg_bld_cfg(p, p_msg->reconfig_cmd.p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_multi
+ *
+ * Description This message building function builds a message containing
+ * multiple SEID's.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_multi(uint8_t** p, tAVDT_MSG* p_msg) {
+ int i;
+
+ for (i = 0; i < p_msg->multi.num_seps; i++) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->multi.seid_list[i]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_security_cmd
+ *
+ * Description This message building function builds a security
+ * command message.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_security_cmd(uint8_t** p, tAVDT_MSG* p_msg) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->security_cmd.hdr.seid);
+ memcpy(*p, p_msg->security_cmd.p_data, p_msg->security_cmd.len);
+ *p += p_msg->security_cmd.len;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_delay_rpt
+ *
+ * Description This message building function builds a delay report
+ * command message.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_delay_rpt(uint8_t** p, tAVDT_MSG* p_msg) {
+ AVDT_MSG_BLD_SEID(*p, p_msg->delay_rpt_cmd.hdr.seid);
+ UINT16_TO_BE_STREAM(*p, p_msg->delay_rpt_cmd.delay);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_discover_rsp
+ *
+ * Description This message building function builds a discover
+ * response message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_discover_rsp(uint8_t** p, tAVDT_MSG* p_msg) {
+ int i;
+
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++) {
+ /* build discover rsp info */
+ AVDT_MSG_BLD_DISC(*p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_svccap
+ *
+ * Description This message building function builds a message containing
+ * service capabilities parameters.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_svccap(uint8_t** p, tAVDT_MSG* p_msg) {
+ tAVDT_CFG cfg;
+
+ /* make sure the delay report category is not reported */
+ memcpy(&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG));
+ cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT;
+ avdt_msg_bld_cfg(p, &cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_all_svccap
+ *
+ * Description This message building function builds a message containing
+ * service capabilities parameters.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_all_svccap(uint8_t** p, tAVDT_MSG* p_msg) {
+ avdt_msg_bld_cfg(p, p_msg->svccap.p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_bld_security_rsp
+ *
+ * Description This message building function builds a security
+ * response message.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void avdt_msg_bld_security_rsp(uint8_t** p, tAVDT_MSG* p_msg) {
+ memcpy(*p, p_msg->security_rsp.p_data, p_msg->security_rsp.len);
+ *p += p_msg->security_rsp.len;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_cfg
+ *
+ * Description This message parsing function parses the configuration
+ * parameters field of a message.
+ *
+ *
+ * Returns Error code or zero if no error, and element that failed
+ * in p_elem.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_cfg(tAVDT_CFG* p_cfg, uint8_t* p, uint16_t len,
+ uint8_t* p_elem, uint8_t sig_id) {
+ uint8_t* p_end;
+ uint8_t elem = 0;
+ uint8_t elem_len;
+ uint8_t tmp;
+ uint8_t err = 0;
+ uint8_t protect_offset = 0;
+
+ if (!p_cfg) {
+ AVDT_TRACE_ERROR("not expecting this cfg");
+ return AVDT_ERR_BAD_STATE;
+ }
+
+ p_cfg->psc_mask = 0;
+ p_cfg->num_codec = 0;
+ p_cfg->num_protect = 0;
+
+ /* while there is still data to parse */
+ p_end = p + len;
+ while ((p < p_end) && (err == 0)) {
+ /* verify overall length */
+ if ((p_end - p) < AVDT_LEN_CFG_MIN) {
+ err = AVDT_ERR_PAYLOAD;
+ break;
+ }
+
+ /* get and verify info elem id, length */
+ elem = *p++;
+ elem_len = *p++;
+
+ if ((elem == 0) || (elem > AVDT_CAT_MAX_CUR)) {
+ /* this may not be really bad.
+ * It may be a service category that is too new for us.
+ * allow these to be parsed without reporting an error.
+ * If this is a "capability" (as in GetCapRsp & GetConfigRsp), this is
+ * filtered out.
+ * If this is a Configuration (as in SetConfigCmd & ReconfigCmd),
+ * this will be marked as an error in the caller of this function */
+ if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG)) {
+ /* Cannot accept unknown category. */
+ err = AVDT_ERR_CATEGORY;
+ break;
+ } else /* GETCAP or GET_ALLCAP */
+ {
+ /* Skip unknown categories. */
+ p += elem_len;
+ AVDT_TRACE_DEBUG("skipping unknown service category=%d len: %d", elem,
+ elem_len);
+ continue;
+ }
+ }
+
+ if ((elem_len > avdt_msg_ie_len_max[elem]) ||
+ (elem_len < avdt_msg_ie_len_min[elem])) {
+ err = avdt_msg_ie_err[elem];
+ break;
+ }
+
+ /* add element to psc mask, but mask out codec or protect */
+ p_cfg->psc_mask |= (1 << elem);
+ AVDT_TRACE_DEBUG("elem=%d elem_len: %d psc_mask=0x%x", elem, elem_len,
+ p_cfg->psc_mask);
+
+ /* parse individual information elements with additional parameters */
+ switch (elem) {
+ case AVDT_CAT_RECOV:
+ p_cfg->recov_type = *p++;
+ p_cfg->recov_mrws = *p++;
+ p_cfg->recov_mnmp = *p++;
+ if (p_cfg->recov_type != AVDT_RECOV_RFC2733) {
+ err = AVDT_ERR_RECOV_TYPE;
+ } else if ((p_cfg->recov_mrws < AVDT_RECOV_MRWS_MIN) ||
+ (p_cfg->recov_mrws > AVDT_RECOV_MRWS_MAX) ||
+ (p_cfg->recov_mnmp < AVDT_RECOV_MNMP_MIN) ||
+ (p_cfg->recov_mnmp > AVDT_RECOV_MNMP_MAX)) {
+ err = AVDT_ERR_RECOV_FMT;
+ }
+ break;
+
+ case AVDT_CAT_PROTECT:
+ p_cfg->psc_mask &= ~AVDT_PSC_PROTECT;
+ if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE) {
+ p_cfg->num_protect++;
+ p_cfg->protect_info[protect_offset] = elem_len;
+ protect_offset++;
+ memcpy(&p_cfg->protect_info[protect_offset], p, elem_len);
+ protect_offset += elem_len;
+ }
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_HDRCMP:
+ p_cfg->hdrcmp_mask = *p++;
+ break;
+
+ case AVDT_CAT_CODEC:
+ p_cfg->psc_mask &= ~AVDT_PSC_CODEC;
+ tmp = elem_len;
+ if (elem_len >= AVDT_CODEC_SIZE) {
+ tmp = AVDT_CODEC_SIZE - 1;
+ }
+ p_cfg->num_codec++;
+ p_cfg->codec_info[0] = elem_len;
+ memcpy(&p_cfg->codec_info[1], p, tmp);
+ p += elem_len;
+ break;
+
+ case AVDT_CAT_DELAY_RPT:
+ break;
+
+ default:
+ p += elem_len;
+ break;
+ } /* switch */
+ } /* while ! err, !end*/
+ *p_elem = elem;
+ AVDT_TRACE_DEBUG("err=0x%x, elem:0x%x psc_mask=0x%x", err, elem,
+ p_cfg->psc_mask);
+
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_none
+ *
+ * Description This message parsing function parses a message with no
+ * parameters.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_none(UNUSED_ATTR tAVDT_MSG* p_msg,
+ UNUSED_ATTR uint8_t* p,
+ UNUSED_ATTR uint16_t len) {
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_single
+ *
+ * Description This message parsing function parses a message with a
+ * single SEID.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_single(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len) {
+ uint8_t err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_SINGLE) {
+ err = AVDT_ERR_LENGTH;
+ } else {
+ AVDT_MSG_PRS_SEID(p, p_msg->single.seid);
+
+ if (avdt_scb_by_hdl(p_msg->single.seid) == NULL) {
+ err = AVDT_ERR_SEID;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_setconfig_cmd
+ *
+ * Description This message parsing function parses a set configuration
+ * command message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_setconfig_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ uint8_t err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SETCONFIG_MIN) {
+ err = AVDT_ERR_LENGTH;
+ } else {
+ /* get seids */
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->config_cmd.hdr.seid) == NULL) {
+ err = AVDT_ERR_SEID;
+ }
+
+ AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.int_seid);
+ if ((p_msg->config_cmd.int_seid < AVDT_SEID_MIN) ||
+ (p_msg->config_cmd.int_seid > AVDT_SEID_MAX)) {
+ err = AVDT_ERR_SEID;
+ }
+ }
+
+ if (!err) {
+ /* parse configuration parameters */
+ len -= 2;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len,
+ &p_msg->hdr.err_param, AVDT_SIG_SETCONFIG);
+
+ if (!err) {
+ /* verify protocol service capabilities are supported */
+ if (((p_msg->config_cmd.p_cfg->psc_mask & (~AVDT_PSC)) != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0)) {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_reconfig_cmd
+ *
+ * Description This message parsing function parses a reconfiguration
+ * command message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_reconfig_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ uint8_t err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_RECONFIG_MIN) {
+ err = AVDT_ERR_LENGTH;
+ } else {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->reconfig_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->reconfig_cmd.hdr.seid) == NULL) {
+ err = AVDT_ERR_SEID;
+ } else {
+ /* parse config parameters */
+ len--;
+ err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len,
+ &p_msg->hdr.err_param, AVDT_SIG_RECONFIG);
+
+ /* verify no protocol service capabilities in parameters */
+ if (!err) {
+ AVDT_TRACE_DEBUG("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x",
+ p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK);
+ if ((p_msg->config_cmd.p_cfg->psc_mask != 0) ||
+ (p_msg->config_cmd.p_cfg->num_codec == 0 &&
+ p_msg->config_cmd.p_cfg->num_protect == 0)) {
+ err = AVDT_ERR_INVALID_CAP;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_multi
+ *
+ * Description This message parsing function parses a message containing
+ * multiple SEID's.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_multi(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len) {
+ int i;
+ uint8_t err = 0;
+
+ p_msg->hdr.err_param = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_MULTI_MIN || (len > AVDT_NUM_SEPS)) {
+ err = AVDT_ERR_LENGTH;
+ } else {
+ /* get and verify all seps */
+ for (i = 0; i < len; i++) {
+ AVDT_MSG_PRS_SEID(p, p_msg->multi.seid_list[i]);
+ if (avdt_scb_by_hdl(p_msg->multi.seid_list[i]) == NULL) {
+ err = AVDT_ERR_SEID;
+ p_msg->hdr.err_param = p_msg->multi.seid_list[i];
+ break;
+ }
+ }
+ p_msg->multi.num_seps = (uint8_t)i;
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_security_cmd
+ *
+ * Description This message parsing function parses a security
+ * command message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_security_cmd(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ uint8_t err = 0;
+
+ /* verify len */
+ if (len < AVDT_LEN_SECURITY_MIN) {
+ err = AVDT_ERR_LENGTH;
+ } else {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->security_cmd.hdr.seid);
+ if (avdt_scb_by_hdl(p_msg->security_cmd.hdr.seid) == NULL) {
+ err = AVDT_ERR_SEID;
+ } else {
+ p_msg->security_cmd.p_data = p;
+ p_msg->security_cmd.len = len - 1;
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_discover_rsp
+ *
+ * Description This message parsing function parses a discover
+ * response message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_discover_rsp(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ int i;
+ uint8_t err = 0;
+
+ /* determine number of seps; seps in msg is len/2, but set to minimum
+ ** of seps app has supplied memory for and seps in msg
+ */
+ if (p_msg->discover_rsp.num_seps > (len / 2)) {
+ p_msg->discover_rsp.num_seps = (len / 2);
+ }
+
+ /* parse out sep info */
+ for (i = 0; i < p_msg->discover_rsp.num_seps; i++) {
+ /* parse discover rsp info */
+ AVDT_MSG_PRS_DISC(p, p_msg->discover_rsp.p_sep_info[i].seid,
+ p_msg->discover_rsp.p_sep_info[i].in_use,
+ p_msg->discover_rsp.p_sep_info[i].media_type,
+ p_msg->discover_rsp.p_sep_info[i].tsep);
+
+ /* verify that seid is valid */
+ if ((p_msg->discover_rsp.p_sep_info[i].seid < AVDT_SEID_MIN) ||
+ (p_msg->discover_rsp.p_sep_info[i].seid > AVDT_SEID_MAX)) {
+ err = AVDT_ERR_SEID;
+ break;
+ }
+ }
+
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_svccap
+ *
+ * Description This message parsing function parses a message containing
+ * service capabilities parameters.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_svccap(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len) {
+ /* parse parameters */
+ uint8_t err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len,
+ &p_msg->hdr.err_param, AVDT_SIG_GETCAP);
+ if (p_msg->svccap.p_cfg) {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_LEG_PSC;
+ }
+
+ return (err);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_all_svccap
+ *
+ * Description This message parsing function parses a message containing
+ * service capabilities parameters.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_all_svccap(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ uint8_t err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len,
+ &p_msg->hdr.err_param, AVDT_SIG_GET_ALLCAP);
+ if (p_msg->svccap.p_cfg) {
+ p_msg->svccap.p_cfg->psc_mask &= AVDT_MSG_PSC_MASK;
+ }
+ return (err);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_security_rsp
+ *
+ * Description This message parsing function parsing a security
+ * response message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ p_msg->security_rsp.p_data = p;
+ p_msg->security_rsp.len = len;
+
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_rej
+ *
+ * Description
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_rej(tAVDT_MSG* p_msg, uint8_t* p, uint8_t sig) {
+ if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) {
+ p_msg->hdr.err_param = *p++;
+ p_msg->hdr.err_code = *p;
+ } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) {
+ AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+ p_msg->hdr.err_code = *p;
+ } else {
+ p_msg->hdr.err_code = *p;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_prs_delay_rpt
+ *
+ * Description This message parsing function parses a security
+ * command message.
+ *
+ *
+ * Returns Error code or zero if no error.
+ *
+ ******************************************************************************/
+static uint8_t avdt_msg_prs_delay_rpt(tAVDT_MSG* p_msg, uint8_t* p,
+ uint16_t len) {
+ uint8_t err = 0;
+
+ /* verify len */
+ if (len != AVDT_LEN_DELAY_RPT) {
+ AVDT_TRACE_WARNING("avdt_msg_prs_delay_rpt expected len: %u got: %u",
+ AVDT_LEN_DELAY_RPT, len);
+ err = AVDT_ERR_LENGTH;
+ } else {
+ /* get seid */
+ AVDT_MSG_PRS_SEID(p, p_msg->delay_rpt_cmd.hdr.seid);
+
+ if (avdt_scb_by_hdl(p_msg->delay_rpt_cmd.hdr.seid) == NULL) {
+ err = AVDT_ERR_SEID;
+ } else {
+ BE_STREAM_TO_UINT16(p_msg->delay_rpt_cmd.delay, p);
+ AVDT_TRACE_DEBUG("avdt_msg_prs_delay_rpt delay: %u",
+ p_msg->delay_rpt_cmd.delay);
+ }
+ }
+ return err;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_send
+ *
+ * Description Send, and if necessary fragment the next message.
+ *
+ *
+ * Returns Congested state; true if CCB congested, false if not.
+ *
+ ******************************************************************************/
+bool avdt_msg_send(tAVDT_CCB* p_ccb, BT_HDR* p_msg) {
+ uint16_t curr_msg_len;
+ uint8_t pkt_type;
+ uint8_t hdr_len;
+ tAVDT_TC_TBL* p_tbl;
+ BT_HDR* p_buf;
+ uint8_t* p;
+ uint8_t label;
+ uint8_t msg;
+ uint8_t sig;
+ uint8_t nosp = 0; /* number of subsequent packets */
+
+ /* look up transport channel table entry to get peer mtu */
+ p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_SIG, p_ccb, NULL);
+
+ /* set the current message if there is a message passed in */
+ if (p_msg != NULL) {
+ p_ccb->p_curr_msg = p_msg;
+ }
+
+ /* store copy of curr_msg->len */
+ curr_msg_len = p_ccb->p_curr_msg->len;
+
+ /* while not congested and we haven't sent it all */
+ while ((!p_ccb->cong) && (p_ccb->p_curr_msg != NULL)) {
+ /* check what kind of message we've got here; we are using the offset
+ ** to indicate that a message is being fragmented
+ */
+
+ /* if message isn't being fragmented and it fits in mtu */
+ if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len <= p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE)) {
+ pkt_type = AVDT_PKT_TYPE_SINGLE;
+ hdr_len = AVDT_LEN_TYPE_SINGLE;
+ p_buf = p_ccb->p_curr_msg;
+ }
+ /* if message isn't being fragmented and it doesn't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len >
+ p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE)) {
+ pkt_type = AVDT_PKT_TYPE_START;
+ hdr_len = AVDT_LEN_TYPE_START;
+ nosp = (p_ccb->p_curr_msg->len + AVDT_LEN_TYPE_START - p_tbl->peer_mtu) /
+ (p_tbl->peer_mtu - 1) +
+ 2;
+
+ /* get a new buffer for fragment we are sending */
+ p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset,
+ (uint8_t*)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset,
+ p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes don't fit in mtu */
+ else if ((p_ccb->p_curr_msg->offset > AVDT_MSG_OFFSET) &&
+ (p_ccb->p_curr_msg->len >
+ (p_tbl->peer_mtu - AVDT_LEN_TYPE_CONT))) {
+ pkt_type = AVDT_PKT_TYPE_CONT;
+ hdr_len = AVDT_LEN_TYPE_CONT;
+
+ /* get a new buffer for fragment we are sending */
+ p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* copy portion of data from current message to new buffer */
+ p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
+ p_buf->len = p_tbl->peer_mtu - hdr_len;
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset,
+ (uint8_t*)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset,
+ p_buf->len);
+ }
+ /* if message is being fragmented and remaining bytes do fit in mtu */
+ else {
+ pkt_type = AVDT_PKT_TYPE_END;
+ hdr_len = AVDT_LEN_TYPE_END;
+ p_buf = p_ccb->p_curr_msg;
+ }
+
+ /* label, sig id, msg type are in hdr of p_curr_msg */
+ label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific);
+ msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific);
+ sig = (uint8_t)p_ccb->p_curr_msg->event;
+ AVDT_TRACE_DEBUG("avdt_msg_send label:%d, msg:%d, sig:%d", label, msg, sig);
+
+ /* keep track of how much of msg we've sent */
+ curr_msg_len -= p_buf->len;
+ if (curr_msg_len == 0) {
+ /* entire message sent; mark as finished */
+ p_ccb->p_curr_msg = NULL;
+
+ /* start timer here for commands */
+ if (msg == AVDT_MSG_TYPE_CMD) {
+ /* if retransmit timeout set to zero, sig doesn't use retransmit */
+ if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) ||
+ (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0)) {
+ alarm_cancel(p_ccb->idle_ccb_timer);
+ alarm_cancel(p_ccb->ret_ccb_timer);
+ period_ms_t interval_ms = avdt_cb.rcb.sig_tout * 1000;
+ alarm_set_on_queue(p_ccb->rsp_ccb_timer, interval_ms,
+ avdt_ccb_rsp_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ } else if (sig != AVDT_SIG_DELAY_RPT) {
+ alarm_cancel(p_ccb->idle_ccb_timer);
+ alarm_cancel(p_ccb->rsp_ccb_timer);
+ period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000;
+ alarm_set_on_queue(p_ccb->ret_ccb_timer, interval_ms,
+ avdt_ccb_ret_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ }
+ } else {
+ /* message being fragmented and not completely sent */
+ p_ccb->p_curr_msg->len -= p_buf->len;
+ p_ccb->p_curr_msg->offset += p_buf->len;
+ }
+
+ /* set up to build header */
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* build header */
+ AVDT_MSG_BLD_HDR(p, label, pkt_type, msg);
+ if (pkt_type == AVDT_PKT_TYPE_START) {
+ AVDT_MSG_BLD_NOSP(p, nosp);
+ }
+ if ((pkt_type == AVDT_PKT_TYPE_START) ||
+ (pkt_type == AVDT_PKT_TYPE_SINGLE)) {
+ AVDT_MSG_BLD_SIG(p, sig);
+ }
+
+ /* send msg buffer down */
+ avdt_ad_write_req(AVDT_CHAN_SIG, p_ccb, NULL, p_buf);
+ }
+ return (p_ccb->cong);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_asmbl
+ *
+ * Description Reassemble incoming message.
+ *
+ *
+ * Returns Pointer to reassembled message; NULL if no message
+ * available.
+ *
+ ******************************************************************************/
+BT_HDR* avdt_msg_asmbl(tAVDT_CCB* p_ccb, BT_HDR* p_buf) {
+ uint8_t* p;
+ uint8_t pkt_type;
+ BT_HDR* p_ret;
+
+ /* parse the message header */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ AVDT_MSG_PRS_PKT_TYPE(p, pkt_type);
+
+ /* quick sanity check on length */
+ if (p_buf->len < avdt_msg_pkt_type_len[pkt_type]) {
+ osi_free(p_buf);
+ AVDT_TRACE_WARNING("Bad length during reassembly");
+ p_ret = NULL;
+ }
+ /* single packet */
+ else if (pkt_type == AVDT_PKT_TYPE_SINGLE) {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ AVDT_TRACE_WARNING("Got single during reassembly");
+
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+
+ p_ret = p_buf;
+ }
+ /* start packet */
+ else if (pkt_type == AVDT_PKT_TYPE_START) {
+ /* if reassembly in progress drop message and process new single */
+ if (p_ccb->p_rx_msg != NULL)
+ AVDT_TRACE_WARNING("Got start during reassembly");
+
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+
+ /*
+ * Allocate bigger buffer for reassembly. As lower layers are
+ * not aware of possible packet size after reassembly, they
+ * would have allocated smaller buffer.
+ */
+ p_ccb->p_rx_msg = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ memcpy(p_ccb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len);
+
+ /* Free original buffer */
+ osi_free(p_buf);
+
+ /* update p to point to new buffer */
+ p = (uint8_t*)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset;
+
+ /* copy first header byte over nosp */
+ *(p + 1) = *p;
+
+ /* set offset to point to where to copy next */
+ p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len;
+
+ /* adjust length for packet header */
+ p_ccb->p_rx_msg->len -= 1;
+
+ p_ret = NULL;
+ }
+ /* continue or end */
+ else {
+ /* if no reassembly in progress drop message */
+ if (p_ccb->p_rx_msg == NULL) {
+ osi_free(p_buf);
+ AVDT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
+ p_ret = NULL;
+ } else {
+ /* get size of buffer holding assembled message */
+ /*
+ * NOTE: The buffer is allocated above at the beginning of the
+ * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+ */
+ uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+
+ /* adjust offset and len of fragment for header byte */
+ p_buf->offset += AVDT_LEN_TYPE_CONT;
+ p_buf->len -= AVDT_LEN_TYPE_CONT;
+
+ /* verify length */
+ if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) {
+ /* won't fit; free everything */
+ AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+ osi_free(p_buf);
+ p_ret = NULL;
+ } else {
+ /* copy contents of p_buf to p_rx_msg */
+ memcpy((uint8_t*)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset,
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ if (pkt_type == AVDT_PKT_TYPE_END) {
+ p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = p_ccb->p_rx_msg;
+ p_ccb->p_rx_msg = NULL;
+ } else {
+ p_ccb->p_rx_msg->offset += p_buf->len;
+ p_ccb->p_rx_msg->len += p_buf->len;
+ p_ret = NULL;
+ }
+ osi_free(p_buf);
+ }
+ }
+ }
+ return p_ret;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_send_cmd
+ *
+ * Description This function is called to send a command message. The
+ * sig_id parameter indicates the message type, p_params
+ * points to the message parameters, if any. It gets a buffer
+ * from the AVDTP command pool, executes the message building
+ * function for this message type. It then queues the message
+ * in the command queue for this CCB.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_msg_send_cmd(tAVDT_CCB* p_ccb, void* p_scb, uint8_t sig_id,
+ tAVDT_MSG* p_params) {
+ uint8_t* p;
+ uint8_t* p_start;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* set up buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_cmd[sig_id - 1])(&p, p_params);
+
+ /* set len */
+ p_buf->len = (uint16_t)(p - p_start);
+
+ /* now store scb hdls, if any, in buf */
+ if (p_scb != NULL) {
+ p = (uint8_t*)(p_buf + 1);
+
+ /* for start and suspend, p_scb points to array of handles */
+ if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND)) {
+ memcpy(p, (uint8_t*)p_scb, p_buf->len);
+ }
+ /* for all others, p_scb points to scb as usual */
+ else {
+ *p = avdt_scb_to_hdl((tAVDT_SCB*)p_scb);
+ }
+ }
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_CMD, p_ccb->label);
+
+ /* increment label */
+ p_ccb->label = (p_ccb->label + 1) % 16;
+
+ /* queue message and trigger ccb to send it */
+ fixed_queue_enqueue(p_ccb->cmd_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_send_rsp
+ *
+ * Description This function is called to send a response message. The
+ * sig_id parameter indicates the message type, p_params
+ * points to the message parameters, if any. It gets a buffer
+ * from the AVDTP command pool, executes the message building
+ * function for this message type. It then queues the message
+ * in the response queue for this CCB.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_msg_send_rsp(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+ uint8_t* p;
+ uint8_t* p_start;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* set up buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* execute parameter building function to build message */
+ (*avdt_msg_bld_rsp[sig_id - 1])(&p, p_params);
+
+ /* set length */
+ p_buf->len = (uint16_t)(p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP,
+ p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_send_rej
+ *
+ * Description This function is called to send a reject message. The
+ * sig_id parameter indicates the message type. It gets
+ * a buffer from the AVDTP command pool and builds the
+ * message based on the message type and the error code.
+ * It then queues the message in the response queue for
+ * this CCB.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_msg_send_rej(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+ uint8_t* p;
+ uint8_t* p_start;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* set up buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* if sig id included, build into message */
+ if (sig_id != AVDT_SIG_NONE) {
+ /* if this sig has a parameter, add the parameter */
+ if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG)) {
+ AVDT_MSG_BLD_PARAM(p, p_params->hdr.err_param);
+ } else if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND)) {
+ AVDT_MSG_BLD_SEID(p, p_params->hdr.err_param);
+ }
+
+ /* add the error code */
+ AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code);
+ }
+ AVDT_TRACE_DEBUG("avdt_msg_send_rej");
+
+ /* calculate length */
+ p_buf->len = (uint16_t)(p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ,
+ p_params->hdr.label);
+
+ /* queue message and trigger ccb to send it */
+ fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_send_grej
+ *
+ * Description This function is called to send a general reject message.
+ * The sig_id parameter indicates the message type. It gets
+ * a buffer from the AVDTP command pool and builds the
+ * message based on the message type and the error code.
+ * It then queues the message in the response queue for
+ * this CCB.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_msg_send_grej(tAVDT_CCB* p_ccb, uint8_t sig_id, tAVDT_MSG* p_params) {
+ uint8_t* p;
+ uint8_t* p_start;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE);
+
+ /* set up buf pointer and offset */
+ p_buf->offset = AVDT_MSG_OFFSET;
+ p_start = p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* calculate length */
+ p_buf->len = (uint16_t)(p - p_start);
+
+ /* stash sig, label, and message type in buf */
+ p_buf->event = sig_id;
+ AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_GRJ,
+ p_params->hdr.label);
+ AVDT_TRACE_DEBUG(__func__);
+
+ /* queue message and trigger ccb to send it */
+ fixed_queue_enqueue(p_ccb->rsp_q, p_buf);
+ avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_msg_ind
+ *
+ * Description This function is called by the adaption layer when an
+ * incoming message is received on the signaling channel.
+ * It parses the message and sends an event to the appropriate
+ * SCB or CCB for the message.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_msg_ind(tAVDT_CCB* p_ccb, BT_HDR* p_buf) {
+ tAVDT_SCB* p_scb;
+ uint8_t* p;
+ bool ok = true;
+ bool handle_rsp = false;
+ bool gen_rej = false;
+ uint8_t label;
+ uint8_t pkt_type;
+ uint8_t msg_type;
+ uint8_t sig = 0;
+ tAVDT_MSG msg;
+ tAVDT_CFG cfg;
+ uint8_t err;
+ uint8_t evt = 0;
+ uint8_t scb_hdl;
+
+ /* reassemble message; if no message available (we received a fragment) return
+ */
+ p_buf = avdt_msg_asmbl(p_ccb, p_buf);
+ if (p_buf == NULL) {
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* parse the message header */
+ AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type);
+
+ AVDT_TRACE_DEBUG("msg_type=%d, sig=%d", msg_type, sig);
+ /* set up label and ccb_idx in message hdr */
+ msg.hdr.label = label;
+ msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb);
+
+ /* verify msg type */
+ if (msg_type == AVDT_MSG_TYPE_GRJ) {
+ AVDT_TRACE_WARNING("Dropping msg msg_type=%d", msg_type);
+ ok = false;
+ }
+ /* check for general reject */
+ else if ((msg_type == AVDT_MSG_TYPE_REJ) &&
+ (p_buf->len == AVDT_LEN_GEN_REJ)) {
+ gen_rej = true;
+ if (p_ccb->p_curr_cmd != NULL) {
+ msg.hdr.sig_id = sig = (uint8_t)p_ccb->p_curr_cmd->event;
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ msg.hdr.err_code = AVDT_ERR_NSC;
+ msg.hdr.err_param = 0;
+ }
+ } else /* not a general reject */
+ {
+ /* get and verify signal */
+ AVDT_MSG_PRS_SIG(p, sig);
+ msg.hdr.sig_id = sig;
+ if ((sig == 0) || (sig > AVDT_SIG_MAX)) {
+ AVDT_TRACE_WARNING("Dropping msg sig=%d msg_type:%d", sig, msg_type);
+ ok = false;
+
+ /* send a general reject */
+ if (msg_type == AVDT_MSG_TYPE_CMD) {
+ avdt_msg_send_grej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ if (ok && !gen_rej) {
+ /* skip over header (msg length already verified during reassembly) */
+ p_buf->len -= AVDT_LEN_TYPE_SINGLE;
+
+ /* set up to parse message */
+ if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER)) {
+ /* parse discover rsp message to struct supplied by app */
+ msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO*)p_ccb->p_proc_data;
+ msg.discover_rsp.num_seps = p_ccb->proc_param;
+ } else if ((msg_type == AVDT_MSG_TYPE_RSP) &&
+ ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP))) {
+ /* parse discover rsp message to struct supplied by app */
+ msg.svccap.p_cfg = (tAVDT_CFG*)p_ccb->p_proc_data;
+ } else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG)) {
+ /* parse get config rsp message to struct allocated locally */
+ msg.svccap.p_cfg = &cfg;
+ } else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG)) {
+ /* parse config cmd message to struct allocated locally */
+ msg.config_cmd.p_cfg = &cfg;
+ } else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG)) {
+ /* parse reconfig cmd message to struct allocated locally */
+ msg.reconfig_cmd.p_cfg = &cfg;
+ }
+
+ /* parse message; while we're at it map message sig to event */
+ if (msg_type == AVDT_MSG_TYPE_CMD) {
+ msg.hdr.err_code = err =
+ (*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_cmd_2_evt[sig - 1];
+ } else if (msg_type == AVDT_MSG_TYPE_RSP) {
+ msg.hdr.err_code = err =
+ (*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len);
+ evt = avdt_msg_rsp_2_evt[sig - 1];
+ } else /* msg_type == AVDT_MSG_TYPE_REJ */
+ {
+ err = avdt_msg_prs_rej(&msg, p, sig);
+ evt = avdt_msg_rej_2_evt[sig - 1];
+ }
+
+ /* if parsing failed */
+ if (err != 0) {
+ AVDT_TRACE_WARNING("Parsing failed sig=%d err=0x%x", sig, err);
+
+ /* if its a rsp or rej, drop it; if its a cmd, send a rej;
+ ** note special case for abort; never send abort reject
+ */
+ ok = false;
+ if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT)) {
+ avdt_msg_send_rej(p_ccb, sig, &msg);
+ }
+ }
+ }
+
+ /* if its a rsp or rej, check sent cmd to see if we're waiting for
+ ** the rsp or rej. If we didn't send a cmd for it, drop it. If
+ ** it does match a cmd, stop timer for the cmd.
+ */
+ if (ok) {
+ if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ)) {
+ if ((p_ccb->p_curr_cmd != NULL) && (p_ccb->p_curr_cmd->event == sig) &&
+ (AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label)) {
+ /* stop timer */
+ alarm_cancel(p_ccb->idle_ccb_timer);
+ alarm_cancel(p_ccb->ret_ccb_timer);
+ alarm_cancel(p_ccb->rsp_ccb_timer);
+
+ /* clear retransmission count */
+ p_ccb->ret_count = 0;
+
+ /* later in this function handle ccb event */
+ handle_rsp = true;
+ } else {
+ ok = false;
+ AVDT_TRACE_WARNING("Cmd not found for rsp sig=%d label=%d", sig, label);
+ }
+ }
+ }
+
+ if (ok) {
+ /* if it's a ccb event send to ccb */
+ if (evt & AVDT_CCB_MKR) {
+ avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR),
+ (tAVDT_CCB_EVT*)&msg);
+ }
+ /* if it's a scb event */
+ else {
+ /* Scb events always have a single seid. For cmd, get seid from
+ ** message. For rej and rsp, get seid from p_curr_cmd.
+ */
+ if (msg_type == AVDT_MSG_TYPE_CMD) {
+ scb_hdl = msg.single.seid;
+ } else {
+ scb_hdl = *((uint8_t*)(p_ccb->p_curr_cmd + 1));
+ }
+
+ /* Map seid to the scb and send it the event. For cmd, seid has
+ ** already been verified by parsing function.
+ */
+ if (evt) {
+ p_scb = avdt_scb_by_hdl(scb_hdl);
+ if (p_scb != NULL) {
+ avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT*)&msg);
+ }
+ }
+ }
+ }
+
+ /* free message buffer */
+ osi_free(p_buf);
+
+ /* if its a rsp or rej, send event to ccb to free associated
+ ** cmd msg buffer and handle cmd queue
+ */
+ if (handle_rsp) {
+ avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL);
+ }
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_scb.cc b/mtkbt/code/bt/stack/avdt/avdt_scb.cc
new file mode 100755
index 0000000..777cc73
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_scb.cc
@@ -0,0 +1,993 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the stream control block and functions which
+ * operate on the stream control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * state machine constants and types
+ ****************************************************************************/
+#if (AVDT_DEBUG == TRUE)
+
+/* verbose state strings for trace */
+const char* const avdt_scb_st_str[] = {"SCB_IDLE_ST", "SCB_CONF_ST",
+ "SCB_OPENING_ST", "SCB_OPEN_ST",
+ "SCB_STREAM_ST", "SCB_CLOSING_ST"};
+
+/* verbose event strings for trace */
+const char* const avdt_scb_evt_str[] = {
+ "API_REMOVE_EVT", "API_WRITE_REQ_EVT", "API_GETCONFIG_REQ_EVT",
+ "API_DELAY_RPT_REQ", "API_SETCONFIG_REQ_EVT", "API_OPEN_REQ_EVT",
+ "API_CLOSE_REQ_EVT", "API_RECONFIG_REQ_EVT", "API_SECURITY_REQ_EVT",
+ "API_ABORT_REQ_EVT", "API_GETCONFIG_RSP_EVT", "API_SETCONFIG_RSP_EVT",
+ "API_SETCONFIG_REJ_EVT", "API_OPEN_RSP_EVT", "API_CLOSE_RSP_EVT",
+ "API_RECONFIG_RSP_EVT", "API_SECURITY_RSP_EVT", "API_ABORT_RSP_EVT",
+ "MSG_SETCONFIG_CMD_EVT", "MSG_GETCONFIG_CMD_EVT", "MSG_OPEN_CMD_EVT",
+ "MSG_START_CMD_EVT", "MSG_SUSPEND_CMD_EVT", "MSG_CLOSE_CMD_EVT",
+ "MSG_ABORT_CMD_EVT", "MSG_RECONFIG_CMD_EVT", "MSG_SECURITY_CMD_EVT",
+ "MSG_DELAY_RPT_CMD_EVT", "MSG_DELAY_RPT_RSP_EVT", "MSG_SETCONFIG_RSP_EVT",
+ "MSG_GETCONFIG_RSP_EVT", "MSG_OPEN_RSP_EVT", "MSG_START_RSP_EVT",
+ "MSG_SUSPEND_RSP_EVT", "MSG_CLOSE_RSP_EVT", "MSG_ABORT_RSP_EVT",
+ "MSG_RECONFIG_RSP_EVT", "MSG_SECURITY_RSP_EVT", "MSG_SETCONFIG_REJ_EVT",
+ "MSG_OPEN_REJ_EVT", "MSG_START_REJ_EVT", "MSG_SUSPEND_REJ_EVT",
+ "TC_TOUT_EVT", "TC_OPEN_EVT", "TC_CLOSE_EVT",
+ "TC_CONG_EVT", "TC_DATA_EVT", "CC_CLOSE_EVT"};
+
+#endif
+
+/* action function list */
+const tAVDT_SCB_ACTION avdt_scb_action[] = {avdt_scb_hdl_abort_cmd,
+ avdt_scb_hdl_abort_rsp,
+ avdt_scb_hdl_close_cmd,
+ avdt_scb_hdl_close_rsp,
+ avdt_scb_hdl_getconfig_cmd,
+ avdt_scb_hdl_getconfig_rsp,
+ avdt_scb_hdl_open_cmd,
+ avdt_scb_hdl_open_rej,
+ avdt_scb_hdl_open_rsp,
+ avdt_scb_hdl_pkt,
+ avdt_scb_drop_pkt,
+ avdt_scb_hdl_reconfig_cmd,
+ avdt_scb_hdl_reconfig_rsp,
+ avdt_scb_hdl_security_cmd,
+ avdt_scb_hdl_security_rsp,
+ avdt_scb_hdl_setconfig_cmd,
+ avdt_scb_hdl_setconfig_rej,
+ avdt_scb_hdl_setconfig_rsp,
+ avdt_scb_hdl_start_cmd,
+ avdt_scb_hdl_start_rsp,
+ avdt_scb_hdl_suspend_cmd,
+ avdt_scb_hdl_suspend_rsp,
+ avdt_scb_hdl_tc_close,
+#if (AVDT_REPORTING == TRUE)
+ avdt_scb_hdl_tc_close_sto,
+#endif
+ avdt_scb_hdl_tc_open,
+#if (AVDT_REPORTING == TRUE)
+ avdt_scb_hdl_tc_open_sto,
+#endif
+ avdt_scb_snd_delay_rpt_req,
+ avdt_scb_hdl_delay_rpt_cmd,
+ avdt_scb_hdl_delay_rpt_rsp,
+ avdt_scb_hdl_write_req,
+ avdt_scb_snd_abort_req,
+ avdt_scb_snd_abort_rsp,
+ avdt_scb_snd_close_req,
+ avdt_scb_snd_stream_close,
+ avdt_scb_snd_close_rsp,
+ avdt_scb_snd_getconfig_req,
+ avdt_scb_snd_getconfig_rsp,
+ avdt_scb_snd_open_req,
+ avdt_scb_snd_open_rsp,
+ avdt_scb_snd_reconfig_req,
+ avdt_scb_snd_reconfig_rsp,
+ avdt_scb_snd_security_req,
+ avdt_scb_snd_security_rsp,
+ avdt_scb_snd_setconfig_req,
+ avdt_scb_snd_setconfig_rej,
+ avdt_scb_snd_setconfig_rsp,
+ avdt_scb_snd_tc_close,
+ avdt_scb_cb_err,
+ avdt_scb_cong_state,
+ avdt_scb_rej_state,
+ avdt_scb_rej_in_use,
+ avdt_scb_rej_not_in_use,
+ avdt_scb_set_remove,
+ avdt_scb_free_pkt,
+ avdt_scb_clr_pkt,
+ avdt_scb_chk_snd_pkt,
+ avdt_scb_transport_channel_timer,
+ avdt_scb_clr_vars,
+ avdt_scb_dealloc};
+
+/* state table information */
+#define AVDT_SCB_ACTIONS 2 /* number of actions */
+#define AVDT_SCB_NEXT_STATE 2 /* position of next state */
+#define AVDT_SCB_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for idle state */
+const uint8_t avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_DEALLOC, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_SND_SETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_SETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_NOT_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_HDL_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_CONG_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_CLR_VARS, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}};
+
+/* state table for configured state */
+const uint8_t avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CONF_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_SND_OPEN_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_SND_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_HDL_OPEN_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_HDL_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_HDL_OPEN_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* TC_CONG_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}};
+
+/* state table for opening state */
+const uint8_t avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_HDL_TC_OPEN, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_CONG_EVT */
+ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}};
+
+/* state table for open state */
+const uint8_t avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_SND_RECONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_SND_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_HDL_START_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_RECONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#if (AVDT_REPORTING == TRUE)
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#else
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+#endif
+ /* TC_CONG_EVT */
+ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}};
+
+/* state table for streaming state */
+const uint8_t avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_HDL_WRITE_REQ, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_CLR_PKT, AVDT_SCB_CLOSING_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_HDL_SUSPEND_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_STREAM_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_CONG_EVT */
+ {AVDT_SCB_CONG_STATE, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_HDL_PKT, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}};
+
+/* state table for closing state */
+const uint8_t avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = {
+ /* Event */
+ /* Action 1 Action 2 Next state */
+ /* API_REMOVE_EVT */
+ {AVDT_SCB_SET_REMOVE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_WRITE_REQ_EVT */
+ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_GETCONFIG_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_DELAY_RPT_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_SETCONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_OPEN_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_CLOSE_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_SECURITY_REQ_EVT */
+ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_ABORT_REQ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_CLOSE_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_SECURITY_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* API_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_GETCONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_OPEN_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_START_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SUSPEND_CMD_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_CLOSE_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_ABORT_CMD_EVT */
+ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_RECONFIG_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SECURITY_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_DELAY_RPT_CMD_EVT */
+ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_DELAY_RPT_RSP_EVT */
+ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_GETCONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_OPEN_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_START_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SUSPEND_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_CLOSE_RSP_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_CLOSE_RSP, AVDT_SCB_CLOSING_ST},
+ /* MSG_ABORT_RSP_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST},
+ /* MSG_RECONFIG_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SECURITY_RSP_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SETCONFIG_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_OPEN_REJ_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_START_REJ_EVT */
+ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* MSG_SUSPEND_REJ_EVT */
+ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* TC_TOUT_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* TC_OPEN_EVT */
+ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* TC_CLOSE_EVT */
+ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST},
+ /* TC_CONG_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* TC_DATA_EVT */
+ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST},
+ /* CC_CLOSE_EVT */
+ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS];
+
+/* state table */
+const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = {
+ avdt_scb_st_idle, avdt_scb_st_conf, avdt_scb_st_opening,
+ avdt_scb_st_open, avdt_scb_st_stream, avdt_scb_st_closing};
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_event
+ *
+ * Description State machine event handling function for scb
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_event(tAVDT_SCB* p_scb, uint8_t event, tAVDT_SCB_EVT* p_data) {
+ tAVDT_SCB_ST_TBL state_table;
+ uint8_t action;
+ int i;
+
+#if (AVDT_DEBUG == TRUE)
+ AVDT_TRACE_EVENT("%s: SCB hdl=%d event=%d/%s state=%s", __func__,
+ avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event],
+ avdt_scb_st_str[p_scb->state]);
+#endif
+ /* set current event */
+ p_scb->curr_evt = event;
+
+ /* look up the state table for the current state */
+ state_table = avdt_scb_st_tbl[p_scb->state];
+
+ /* set next state */
+ if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE]) {
+ p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE];
+ }
+
+ /* execute action functions */
+ for (i = 0; i < AVDT_SCB_ACTIONS; i++) {
+ action = state_table[event][i];
+ if (action != AVDT_SCB_IGNORE) {
+ (*avdt_cb.p_scb_act[action])(p_scb, p_data);
+ } else {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_init
+ *
+ * Description Initialize stream control block module.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_init(void) {
+ memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS);
+ avdt_cb.p_scb_act = (tAVDT_SCB_ACTION*)avdt_scb_action;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_alloc
+ *
+ * Description Allocate a stream control block.
+ *
+ *
+ * Returns pointer to the scb, or NULL if none could be allocated.
+ *
+ ******************************************************************************/
+tAVDT_SCB* avdt_scb_alloc(tAVDT_CS* p_cs) {
+ tAVDT_SCB* p_scb = &avdt_cb.scb[0];
+ int i;
+
+ /* find available scb */
+ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) {
+ if (!p_scb->allocated) {
+ memset(p_scb, 0, sizeof(tAVDT_SCB));
+ p_scb->allocated = true;
+ p_scb->p_ccb = NULL;
+
+ memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS));
+ p_scb->transport_channel_timer =
+ alarm_new("avdt_scb.transport_channel_timer");
+ AVDT_TRACE_DEBUG("%s: hdl=%d, psc_mask:0x%x", __func__, i + 1,
+ p_cs->cfg.psc_mask);
+ break;
+ }
+ }
+
+ if (i == AVDT_NUM_SEPS) {
+ /* out of ccbs */
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("Out of scbs");
+ }
+
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_dealloc
+ *
+ * Description Deallocate a stream control block.
+ *
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void avdt_scb_dealloc(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ AVDT_TRACE_DEBUG("%s: hdl=%d", __func__, avdt_scb_to_hdl(p_scb));
+ alarm_free(p_scb->transport_channel_timer);
+ memset(p_scb, 0, sizeof(tAVDT_SCB));
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_to_hdl
+ *
+ * Description Given a pointer to an scb, return its handle (or seid).
+ *
+ *
+ * Returns Index of scb.
+ *
+ ******************************************************************************/
+uint8_t avdt_scb_to_hdl(tAVDT_SCB* p_scb) {
+ return (uint8_t)(p_scb - avdt_cb.scb + 1);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_by_hdl
+ *
+ * Description Given an scb handle (or seid), return a pointer to the scb.
+ *
+ *
+ * Returns Pointer to scb or NULL if index is out of range or scb
+ * is not allocated.
+ *
+ ******************************************************************************/
+tAVDT_SCB* avdt_scb_by_hdl(uint8_t hdl) {
+ tAVDT_SCB* p_scb;
+
+ /* verify index */
+ if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS)) {
+ p_scb = &avdt_cb.scb[hdl - 1];
+
+ /* verify scb is allocated */
+ if (!p_scb->allocated) {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("scb hdl %d not allocated", hdl);
+ }
+ } else {
+ p_scb = NULL;
+ AVDT_TRACE_WARNING("scb hdl %d out of range", hdl);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_verify
+ *
+ * Description Verify the condition of a list of scbs.
+ *
+ *
+ * Returns SEID that failed, or 0 if success.
+ *
+ ******************************************************************************/
+uint8_t avdt_scb_verify(tAVDT_CCB* p_ccb, uint8_t state, uint8_t* p_seid,
+ uint16_t num_seid, uint8_t* p_err_code) {
+ int i;
+ tAVDT_SCB* p_scb;
+ uint8_t nsc_mask;
+ uint8_t ret = 0;
+
+ AVDT_TRACE_DEBUG("avdt_scb_verify state %d", state);
+ /* set nonsupported command mask */
+ /* translate public state into private state */
+ nsc_mask = 0;
+ if (state == AVDT_VERIFY_SUSPEND) nsc_mask = AVDT_NSC_SUSPEND;
+
+ /* verify every scb */
+ for (i = 0, *p_err_code = 0;
+ (i < num_seid) && (*p_err_code == 0) && (i < AVDT_NUM_SEPS); i++) {
+ p_scb = avdt_scb_by_hdl(p_seid[i]);
+ if (p_scb == NULL)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ else if (p_scb->p_ccb != p_ccb)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ else if (p_scb->cs.nsc_mask & nsc_mask)
+ *p_err_code = AVDT_ERR_NSC;
+
+ switch (state) {
+ case AVDT_VERIFY_OPEN:
+ case AVDT_VERIFY_START:
+ if (p_scb->state != AVDT_SCB_OPEN_ST &&
+ p_scb->state != AVDT_SCB_STREAM_ST)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+
+ case AVDT_VERIFY_SUSPEND:
+ case AVDT_VERIFY_STREAMING:
+ if (p_scb->state != AVDT_SCB_STREAM_ST)
+ *p_err_code = AVDT_ERR_BAD_STATE;
+ break;
+ }
+ }
+
+ if ((i != num_seid) && (i < AVDT_NUM_SEPS)) {
+ ret = p_seid[i];
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_peer_seid_list
+ *
+ * Description Given a list of SCB handles, return a list of peer SEIDs
+ * for the handles, copied in place into the struct passed in.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_peer_seid_list(tAVDT_MULTI* p_multi) {
+ int i;
+ tAVDT_SCB* p_scb;
+
+ for (i = 0; i < p_multi->num_seps; i++) {
+ p_scb = avdt_scb_by_hdl(p_multi->seid_list[i]);
+ if (p_scb != NULL) {
+ p_multi->seid_list[i] = p_scb->peer_seid;
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/avdt/avdt_scb_act.cc b/mtkbt/code/bt/stack/avdt/avdt_scb_act.cc
new file mode 100755
index 0000000..8832d44
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avdt/avdt_scb_act.cc
@@ -0,0 +1,1454 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains the action functions associated with the stream
+ * control block state machine.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "a2dp_codec_api.h"
+#include "avdt_api.h"
+#include "avdt_int.h"
+#include "avdtc_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/* This table is used to lookup the callback event that matches a particular
+ * state machine API request event. Note that state machine API request
+ * events are at the beginning of the event list starting at zero, thus
+ * allowing for this table.
+*/
+const uint8_t avdt_scb_cback_evt[] = {
+ 0, /* API_REMOVE_EVT (no event) */
+ AVDT_WRITE_CFM_EVT, /* API_WRITE_REQ_EVT */
+ 0, /* API_GETCONFIG_REQ_EVT (no event) */
+ 0, /* API_DELAY_RPT_REQ_EVT (no event) */
+ AVDT_OPEN_CFM_EVT, /* API_SETCONFIG_REQ_EVT */
+ AVDT_OPEN_CFM_EVT, /* API_OPEN_REQ_EVT */
+ AVDT_CLOSE_CFM_EVT, /* API_CLOSE_REQ_EVT */
+ AVDT_RECONFIG_CFM_EVT, /* API_RECONFIG_REQ_EVT */
+ AVDT_SECURITY_CFM_EVT, /* API_SECURITY_REQ_EVT */
+ 0 /* API_ABORT_REQ_EVT (no event) */
+};
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_gen_ssrc
+ *
+ * Description This function generates a SSRC number unique to the stream.
+ *
+ * Returns SSRC value.
+ *
+ ******************************************************************************/
+uint32_t avdt_scb_gen_ssrc(tAVDT_SCB* p_scb) {
+ /* combine the value of the media type and codec type of the SCB */
+ return (
+ (uint32_t)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2]));
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_abort_cmd
+ *
+ * Description This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT
+ * to initiate sending of an abort response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_abort_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_abort_rsp
+ *
+ * Description This function is an empty function; it serves as a
+ * placeholder for a conformance API action function.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_abort_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_close_cmd
+ *
+ * Description This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT
+ * to initiate sending of a close response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_close_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_scb->role = AVDT_CLOSE_ACP;
+ avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_close_rsp
+ *
+ * Description This function sets the close_code variable to the error
+ * code returned in the close response.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_scb->close_code = p_data->msg.hdr.err_code;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_getconfig_cmd
+ *
+ * Description This function retrieves the configuration parameters of
+ * the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT
+ * to initiate sending of a get configuration response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_getconfig_rsp
+ *
+ * Description This function is an empty function; it serves as a
+ * placeholder for a conformance API action function.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_getconfig_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_open_cmd
+ *
+ * Description This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT
+ * to initiate sending of an open response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_open_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_open_rej
+ *
+ * Description This function calls the application callback function
+ * indicating the open request has failed. It initializes
+ * certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT
+ * to the CCB.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_open_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* do exactly same as setconfig reject */
+ avdt_scb_hdl_setconfig_rej(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_open_rsp
+ *
+ * Description This function calls avdt_ad_open_req() to initiate
+ * connection of the transport channel for this stream.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_open_rsp(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ /* initiate opening of trans channels for this SEID */
+ p_scb->role = AVDT_OPEN_INT;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT);
+
+ /* start tc connect timer */
+ alarm_set_on_queue(
+ p_scb->transport_channel_timer, AVDT_SCB_TC_CONN_TIMEOUT_MS,
+ avdt_scb_transport_channel_timer_timeout, p_scb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_pkt_no_frag
+ *
+ * Description
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ uint8_t *p, *p_start;
+ uint8_t o_v, o_p, o_x, o_cc;
+ uint8_t m_pt;
+ uint8_t marker;
+ uint16_t seq;
+ uint32_t time_stamp;
+ uint16_t offset;
+ uint16_t ex_len;
+ uint8_t pad_len = 0;
+
+ p = p_start = (uint8_t*)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+
+ /* parse media packet header */
+ AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc);
+ AVDT_MSG_PRS_M_PT(p, m_pt, marker);
+ BE_STREAM_TO_UINT16(seq, p);
+ BE_STREAM_TO_UINT32(time_stamp, p);
+ p += 4;
+
+ /* skip over any csrc's in packet */
+ p += o_cc * 4;
+
+ /* check for and skip over extension header */
+ if (o_x) {
+ p += 2;
+ BE_STREAM_TO_UINT16(ex_len, p);
+ p += ex_len * 4;
+ }
+
+ /* save our new offset */
+ offset = (uint16_t)(p - p_start);
+
+ /* adjust length for any padding at end of packet */
+ if (o_p) {
+ /* padding length in last byte of packet */
+ pad_len = *(p_start + p_data->p_pkt->len);
+ }
+
+ /* do sanity check */
+ if ((offset > p_data->p_pkt->len) ||
+ ((pad_len + offset) > p_data->p_pkt->len)) {
+ AVDT_TRACE_WARNING("Got bad media packet");
+ osi_free_and_reset((void**)&p_data->p_pkt);
+ }
+ /* adjust offset and length and send it up */
+ else {
+ p_data->p_pkt->len -= (offset + pad_len);
+ p_data->p_pkt->offset += offset;
+
+ if (p_scb->cs.p_sink_data_cback != NULL) {
+ /* report sequence number */
+ p_data->p_pkt->layer_specific = seq;
+ (*p_scb->cs.p_sink_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt,
+ time_stamp,
+ (uint8_t)(m_pt | (marker << 7)));
+ } else {
+ osi_free_and_reset((void**)&p_data->p_pkt);
+ }
+ }
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_report
+ *
+ * Description
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+uint8_t* avdt_scb_hdl_report(tAVDT_SCB* p_scb, uint8_t* p, uint16_t len) {
+ uint16_t result = AVDT_SUCCESS;
+ uint8_t* p_start = p;
+ uint32_t ssrc;
+ uint8_t o_v, o_p, o_cc;
+ AVDT_REPORT_TYPE pt;
+ tAVDT_REPORT_DATA report, *p_rpt;
+
+ AVDT_TRACE_DEBUG("%s", __func__);
+ if (p_scb->cs.p_report_cback) {
+ p_rpt = &report;
+ /* parse report packet header */
+ AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc);
+ pt = *p++;
+ p += 2;
+ BE_STREAM_TO_UINT32(ssrc, p);
+
+ switch (pt) {
+ case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */
+ BE_STREAM_TO_UINT32(report.sr.ntp_sec, p);
+ BE_STREAM_TO_UINT32(report.sr.ntp_frac, p);
+ BE_STREAM_TO_UINT32(report.sr.rtp_time, p);
+ BE_STREAM_TO_UINT32(report.sr.pkt_count, p);
+ BE_STREAM_TO_UINT32(report.sr.octet_count, p);
+ break;
+
+ case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */
+ report.rr.frag_lost = *p;
+ BE_STREAM_TO_UINT32(report.rr.packet_lost, p);
+ report.rr.packet_lost &= 0xFFFFFF;
+ BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p);
+ BE_STREAM_TO_UINT32(report.rr.jitter, p);
+ BE_STREAM_TO_UINT32(report.rr.lsr, p);
+ BE_STREAM_TO_UINT32(report.rr.dlsr, p);
+ break;
+
+ case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */
+ if (*p == AVDT_RTCP_SDES_CNAME) {
+ p_rpt = (tAVDT_REPORT_DATA*)(p + 2);
+ } else {
+ AVDT_TRACE_WARNING(" - SDES SSRC=0x%08x sc=%d %d len=%d %s", ssrc,
+ o_cc, *p, *(p + 1), p + 2);
+ result = AVDT_BUSY;
+ }
+ break;
+
+ default:
+ AVDT_TRACE_ERROR("Bad Report pkt - packet type: %d", pt);
+ result = AVDT_BAD_PARAMS;
+ }
+
+ if (result == AVDT_SUCCESS)
+ (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt);
+ }
+ p_start += len;
+ return p_start;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_pkt
+ *
+ * Description
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+#if (AVDT_REPORTING == TRUE)
+ if (p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT) {
+ uint8_t* p = (uint8_t*)(p_data->p_pkt + 1) + p_data->p_pkt->offset;
+ avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len);
+ osi_free_and_reset((void**)&p_data->p_pkt);
+ } else
+#endif
+ avdt_scb_hdl_pkt_no_frag(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_drop_pkt
+ *
+ * Description Drop an incoming media packet. This function is called if
+ * a media packet is received in any state besides streaming.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_drop_pkt(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ AVDT_TRACE_ERROR("%s dropped incoming media packet", __func__);
+ osi_free_and_reset((void**)&p_data->p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_reconfig_cmd
+ *
+ * Description This function calls the application callback function
+ * with a reconfiguration indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG) {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ p_data->msg.hdr.err_param = 0;
+ avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data);
+ } else {
+ /* store requested configuration */
+ memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
+ AVDT_RECONFIG_IND_EVT,
+ (tAVDT_CTRL*)&p_data->msg.reconfig_cmd);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_reconfig_rsp
+ *
+ * Description This function calls the application callback function
+ * with a reconfiguration confirm.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ if (p_data->msg.hdr.err_code == 0) {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0) {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info,
+ AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0) {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info,
+ AVDT_PROTECT_SIZE);
+ }
+ }
+
+ p_data->msg.svccap.p_cfg = &p_scb->curr_cfg;
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_RECONFIG_CFM_EVT,
+ (tAVDT_CTRL*)&p_data->msg.svccap);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_security_cmd
+ *
+ * Description This function calls the application callback with a
+ * security indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_security_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* if command not supported */
+ if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY) {
+ /* send reject */
+ p_data->msg.hdr.err_code = AVDT_ERR_NSC;
+ avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data);
+ } else {
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
+ AVDT_SECURITY_IND_EVT,
+ (tAVDT_CTRL*)&p_data->msg.security_cmd);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_security_rsp
+ *
+ * Description This function calls the application callback with a
+ * security confirm.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_SECURITY_CFM_EVT,
+ (tAVDT_CTRL*)&p_data->msg.security_cmd);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_setconfig_cmd
+ *
+ * Description This function marks the SCB as in use and copies the
+ * configuration and peer SEID to the SCB. It then calls
+ * the application callback with a configuration indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ tAVDT_CFG* p_cfg;
+
+ if (!p_scb->in_use) {
+ p_cfg = p_data->msg.config_cmd.p_cfg;
+ if (A2DP_GetCodecType(p_scb->cs.cfg.codec_info) ==
+ A2DP_GetCodecType(p_cfg->codec_info)) {
+ /* set sep as in use */
+ p_scb->in_use = true;
+
+ /* copy info to scb */
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.int_seid;
+ memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG));
+ /* call app callback */
+ /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/
+ (*p_scb->cs.p_ctrl_cback)(
+ avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_CONFIG_IND_EVT, (tAVDT_CTRL*)&p_data->msg.config_cmd);
+ } else {
+ p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+ }
+ } else {
+ avdt_scb_rej_in_use(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_setconfig_rej
+ *
+ * Description This function marks the SCB as not in use and calls the
+ * application callback with an open confirm indicating
+ * failure.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ AVDT_CCB_UL_CLOSE_EVT, NULL);
+
+ /* call application callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_OPEN_CFM_EVT,
+ (tAVDT_CTRL*)&p_data->msg.hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_setconfig_rsp
+ *
+ * Description This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT
+ * to initiate sending of an open command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_EVT_HDR single;
+
+ if (p_scb->p_ccb != NULL) {
+ /* save configuration */
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ /* initiate open */
+ single.seid = p_scb->peer_seid;
+ avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT*)&single);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_start_cmd
+ *
+ * Description This function calls the application callback with a
+ * start indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_start_cmd(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_IND_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_start_rsp
+ *
+ * Description This function calls the application callback with a
+ * start confirm.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_start_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_START_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_suspend_cmd
+ *
+ * Description This function calls the application callback with a suspend
+ * indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_suspend_cmd(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_IND_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_suspend_rsp
+ *
+ * Description This function calls the application callback with a suspend
+ * confirm.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_suspend_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(
+ avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_SUSPEND_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_tc_close
+ *
+ * Description This function is called when the transport channel is
+ * closed. It marks the SCB as not in use and
+ * initializes certain SCB parameters. It then sends
+ * an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB
+ * initiated the close. It then checks to see if the SCB
+ * is to be removed. If it is it deallocates the SCB.
+ * Finally, it calls the application callback with a close
+ * indication.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_tc_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ uint8_t hdl = avdt_scb_to_hdl(p_scb);
+ tAVDT_CTRL_CBACK* p_ctrl_cback = p_scb->cs.p_ctrl_cback;
+ tAVDT_CTRL avdt_ctrl;
+ uint8_t event;
+ tAVDT_CCB* p_ccb = p_scb->p_ccb;
+ BD_ADDR remote_addr;
+
+ memcpy(remote_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+
+ /* set up hdr */
+ avdt_ctrl.hdr.err_code = p_scb->close_code;
+
+ /* clear sep variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ p_scb->media_seq = 0;
+ p_scb->cong = false;
+
+ /* free pkt we're holding, if any */
+ osi_free_and_reset((void**)&p_scb->p_pkt);
+
+ alarm_cancel(p_scb->transport_channel_timer);
+
+ if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT)) {
+ /* tell ccb we're done with signaling channel */
+ avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL);
+ }
+ event =
+ (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT;
+ p_scb->role = AVDT_CLOSE_ACP;
+
+ if (p_scb->remove) {
+ avdt_scb_dealloc(p_scb, NULL);
+ }
+
+ /* call app callback */
+ (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_delay_rpt_req
+ *
+ * Description This function calls the application callback with a delay
+ * report.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_delay_rpt_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT,
+ (tAVDT_MSG*)&p_data->apidelay);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_delay_rpt_cmd
+ *
+ * Description This function calls the application callback with a delay
+ * report.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(
+ avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+
+ if (p_scb->p_ccb)
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg);
+ else
+ avdt_scb_rej_not_in_use(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_delay_rpt_rsp
+ *
+ * Description This function calls the application callback with a delay
+ * report.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ (*p_scb->cs.p_ctrl_cback)(
+ avdt_scb_to_hdl(p_scb), p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_DELAY_REPORT_CFM_EVT, (tAVDT_CTRL*)&p_data->msg.hdr);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_tc_close_sto
+ *
+ * Description This function is called when a channel is closed in OPEN
+ * state. Check the channel type and process accordingly.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_tc_close_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+ /* AVDT_CHAN_SIG does not visit this action */
+ if (p_data && p_data->close.type != AVDT_CHAN_MEDIA) {
+ /* it's reporting or recovery channel,
+ * the channel close in open state means the peer does not support it */
+ if (p_data->close.old_tc_state == AVDT_AD_ST_OPEN) {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 0;
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_DISCONN_EVT, &avdt_ctrl);
+ }
+ } else {
+ /* must be in OPEN state. need to go back to idle */
+ avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL);
+ avdt_scb_hdl_tc_close(p_scb, p_data);
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_tc_open
+ *
+ * Description This function is called when the transport channel is
+ * opened while in the opening state. It calls the
+ * application callback with an open indication or open
+ * confirm depending on who initiated the open procedure.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_tc_open(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ uint8_t event;
+#if (AVDT_REPORTING == TRUE)
+ uint8_t role;
+#endif
+
+ alarm_cancel(p_scb->transport_channel_timer);
+
+ event =
+ (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT;
+ p_data->open.hdr.err_code = 0;
+
+ AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x",
+ p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask,
+ p_scb->curr_cfg.psc_mask);
+#if (AVDT_REPORTING == TRUE)
+ if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) {
+ /* open the reporting channel, if both devices support it */
+ role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP;
+ avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role);
+ }
+#endif
+
+ /* call app callback */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ event, (tAVDT_CTRL*)&p_data->open);
+}
+
+#if (AVDT_REPORTING == TRUE)
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_tc_open_sto
+ *
+ * Description This function is called when the transport channel is
+ * opened while in the opening state. It calls the
+ * application callback with an open indication or open
+ * confirm depending on who initiated the open procedure.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_tc_open_sto(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+ /* open reporting channel here, when it is implemented */
+
+ /* call app callback */
+ if (p_data->open.hdr.err_code == AVDT_CHAN_REPORT) {
+ avdt_ctrl.hdr.err_code = 0;
+ avdt_ctrl.hdr.err_param = 1;
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb),
+ p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL,
+ AVDT_REPORT_CONN_EVT, &avdt_ctrl);
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_hdl_write_req
+ *
+ * Description This function frees the media packet currently stored in
+ * the SCB, if any. Then it builds a new media packet from
+ * with the passed in buffer and stores it in the SCB.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_hdl_write_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ uint8_t* p;
+ uint32_t ssrc;
+ bool add_rtp_header = !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP);
+
+ /* free packet we're holding, if any; to be replaced with new */
+ if (p_scb->p_pkt != NULL) {
+ /* this shouldn't be happening */
+ AVDT_TRACE_WARNING("Dropped media packet; congested");
+ }
+ osi_free_and_reset((void**)&p_scb->p_pkt);
+
+ /* Recompute only if the RTP header wasn't disabled by the API */
+ if (add_rtp_header) {
+ bool is_content_protection = (p_scb->curr_cfg.num_protect > 0);
+ add_rtp_header =
+ A2DP_UsesRtpHeader(is_content_protection, p_scb->curr_cfg.codec_info);
+ }
+
+ /* Build a media packet, and add an RTP header if required. */
+ if (add_rtp_header) {
+ ssrc = avdt_scb_gen_ssrc(p_scb);
+
+ p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE;
+ p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE;
+ p_scb->media_seq++;
+ p = (uint8_t*)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset;
+
+ UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1);
+ UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt);
+ UINT16_TO_BE_STREAM(p, p_scb->media_seq);
+ UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp);
+ UINT32_TO_BE_STREAM(p, ssrc);
+ }
+
+ /* store it */
+ p_scb->p_pkt = p_data->apiwrite.p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_abort_req
+ *
+ * Description This function sends an abort command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_abort_req(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_EVT_HDR hdr;
+
+ if (p_scb->p_ccb != NULL) {
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG*)&hdr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_abort_rsp
+ *
+ * Description This function sends an abort response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_abort_rsp(UNUSED_ATTR tAVDT_SCB* p_scb,
+ tAVDT_SCB_EVT* p_data) {
+ avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT,
+ &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_close_req
+ *
+ * Description This function sends a close command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_close_req(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_EVT_HDR hdr;
+
+ p_scb->role = AVDT_CLOSE_INT;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG*)&hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_stream_close
+ *
+ * Description This function sends a close command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_stream_close(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ osi_free_and_reset((void**)&p_scb->p_pkt);
+ avdt_scb_snd_close_req(p_scb, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_close_rsp
+ *
+ * Description This function sends a close response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_close_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_getconfig_req
+ *
+ * Description This function sends a get configuration command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_getconfig_req(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_EVT_HDR hdr;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG*)&hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_getconfig_rsp
+ *
+ * Description This function sends a get configuration response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_getconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_open_req
+ *
+ * Description This function sends an open command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_open_req(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_EVT_HDR hdr;
+
+ hdr.seid = p_scb->peer_seid;
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG*)&hdr);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_open_rsp
+ *
+ * Description This function sends an open response message. It also
+ * calls avdt_ad_open_req() to accept a transport channel
+ * connection.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_open_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ /* notify adaption that we're waiting for transport channel open */
+ p_scb->role = AVDT_OPEN_ACP;
+ avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP);
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg);
+
+ alarm_set_on_queue(
+ p_scb->transport_channel_timer, AVDT_SCB_TC_CONN_TIMEOUT_MS,
+ avdt_scb_transport_channel_timer_timeout, p_scb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_reconfig_req
+ *
+ * Description This function stores the configuration parameters in the
+ * SCB and sends a reconfiguration command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_reconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_reconfig_rsp
+ *
+ * Description This function stores the configuration parameters in the
+ * SCB and sends a reconfiguration response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_reconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ if (p_data->msg.hdr.err_code == 0) {
+ /* store new configuration */
+ if (p_scb->req_cfg.num_codec > 0) {
+ p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec;
+ memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info,
+ AVDT_CODEC_SIZE);
+ }
+ if (p_scb->req_cfg.num_protect > 0) {
+ p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect;
+ memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info,
+ AVDT_PROTECT_SIZE);
+ }
+
+ /* send response */
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ } else {
+ /* send reject */
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_security_req
+ *
+ * Description This function sends a security command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_security_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_data->msg.hdr.seid = p_scb->peer_seid;
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_security_rsp
+ *
+ * Description This function sends a security response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_security_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ if (p_data->msg.hdr.err_code == 0) {
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ } else {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_setconfig_rej
+ *
+ * Description This function marks the SCB as not in use and sends a
+ * set configuration reject message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_setconfig_rej(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ if (p_scb->p_ccb != NULL) {
+ avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* clear scb variables */
+ avdt_scb_clr_vars(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_setconfig_req
+ *
+ * Description This function marks the SCB as in use and copies the
+ * configuration parameters to the SCB. Then the function
+ * sends a set configuration command message and initiates
+ * opening of the signaling channel.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_setconfig_req(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ tAVDT_CFG *p_req, *p_cfg;
+
+ /* copy API parameters to scb, set scb as in use */
+ p_scb->in_use = true;
+ p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx);
+ p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid;
+ p_req = p_data->msg.config_cmd.p_cfg;
+ p_cfg = &p_scb->cs.cfg;
+ memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg);
+
+ /* tell ccb to open channel */
+ avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_setconfig_rsp
+ *
+ * Description This function copies the requested configuration into the
+ * current configuration and sends a set configuration
+ * response message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_setconfig_rsp(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ if (p_scb->p_ccb != NULL) {
+ memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG));
+
+ avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_snd_tc_close
+ *
+ * Description This function calls avdt_ad_close_req() to close the
+ * transport channel for this SCB.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_snd_tc_close(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+#if (AVDT_REPORTING == TRUE)
+ if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT)
+ avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb);
+#endif
+ avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_cb_err
+ *
+ * Description This function calls the application callback function
+ * indicating an error.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_cb_err(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ /* call callback, using lookup table to get callback event */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
+ avdt_scb_cback_evt[p_scb->curr_evt], &avdt_ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_cong_state
+ *
+ * Description This function sets the congestion state of the SCB media
+ * transport channel.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_cong_state(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_scb->cong = p_data->llcong;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_rej_state
+ *
+ * Description This function sends a reject message to the peer indicating
+ * incorrect state for the received command message.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_rej_state(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_rej_in_use
+ *
+ * Description This function sends a reject message to the peer indicating
+ * the stream is in use.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_rej_in_use(UNUSED_ATTR tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ p_data->msg.hdr.err_code = AVDT_ERR_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_rej_not_in_use
+ *
+ * Description This function sends a reject message to the peer indicating
+ * the stream is in use.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_rej_not_in_use(UNUSED_ATTR tAVDT_SCB* p_scb,
+ tAVDT_SCB_EVT* p_data) {
+ p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE;
+ p_data->msg.hdr.err_param = 0;
+ avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx),
+ p_data->msg.hdr.sig_id, &p_data->msg);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_set_remove
+ *
+ * Description This function marks an SCB to be removed.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_set_remove(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ p_scb->remove = true;
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_free_pkt
+ *
+ * Description This function frees the media packet passed in.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_free_pkt(tAVDT_SCB* p_scb, tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+
+ osi_free_and_reset((void**)&p_data->apiwrite.p_buf);
+
+ AVDT_TRACE_WARNING("Dropped media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_clr_pkt
+ *
+ * Description This function frees the media packet stored in the SCB.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_clr_pkt(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+ tAVDT_CCB* p_ccb;
+ uint8_t tcid;
+ uint16_t lcid;
+
+ /* set error code and parameter */
+ avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE;
+ avdt_ctrl.hdr.err_param = 0;
+ /* flush the media data queued at L2CAP */
+ p_ccb = p_scb->p_ccb;
+ if (p_ccb != NULL) {
+ /* get tcid from type, scb */
+ tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb);
+
+ lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid;
+ L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_ALL);
+ }
+
+ if (p_scb->p_pkt != NULL) {
+ osi_free_and_reset((void**)&p_scb->p_pkt);
+
+ AVDT_TRACE_DEBUG("Dropped stored media packet");
+
+ /* we need to call callback to keep data flow going */
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT,
+ &avdt_ctrl);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_chk_snd_pkt
+ *
+ * Description This function checks if the SCB is congested, and if not
+ * congested it sends a stored media packet, if any. After it
+ * sends the packet it calls the application callback function
+ * with a write confirm.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_chk_snd_pkt(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ tAVDT_CTRL avdt_ctrl;
+ BT_HDR* p_pkt;
+
+ avdt_ctrl.hdr.err_code = 0;
+
+ if (!p_scb->cong) {
+ if (p_scb->p_pkt != NULL) {
+ p_pkt = p_scb->p_pkt;
+ p_scb->p_pkt = NULL;
+ avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt);
+
+ (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL,
+ AVDT_WRITE_CFM_EVT, &avdt_ctrl);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_transport_channel_timer
+ *
+ * Description This function is called to start a timer when the peer
+ * initiates closing of the stream. The timer verifies that
+ * the peer disconnects the transport channel.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_transport_channel_timer(tAVDT_SCB* p_scb,
+ UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ alarm_set_on_queue(
+ p_scb->transport_channel_timer, AVDT_SCB_TC_DISC_TIMEOUT_MS,
+ avdt_scb_transport_channel_timer_timeout, p_scb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function avdt_scb_clr_vars
+ *
+ * Description This function initializes certain SCB variables.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void avdt_scb_clr_vars(tAVDT_SCB* p_scb, UNUSED_ATTR tAVDT_SCB_EVT* p_data) {
+ p_scb->in_use = false;
+ p_scb->p_ccb = NULL;
+ p_scb->peer_seid = 0;
+}
diff --git a/mtkbt/code/bt/stack/avrc/avrc_api.cc b/mtkbt/code/bt/stack/avrc/avrc_api.cc
new file mode 100755
index 0000000..2fba78c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_api.cc
@@ -0,0 +1,1368 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Interface to AVRCP mandatory commands
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+#include "btu.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+extern fixed_queue_t* btu_general_alarm_queue;
+
+#define AVRC_MAX_RCV_CTRL_EVT AVCT_BROWSE_UNCONG_IND_EVT
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+static const uint8_t avrc_ctrl_event_map[] = {
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_CFM_EVT */
+ AVRC_OPEN_IND_EVT, /* AVCT_CONNECT_IND_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_CFM_EVT */
+ AVRC_CLOSE_IND_EVT, /* AVCT_DISCONNECT_IND_EVT */
+ AVRC_CONG_IND_EVT, /* AVCT_CONG_IND_EVT */
+ AVRC_UNCONG_IND_EVT, /* AVCT_UNCONG_IND_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_CFM_EVT */
+ AVRC_BROWSE_OPEN_IND_EVT, /* AVCT_BROWSE_CONN_IND_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_CFM_EVT */
+ AVRC_BROWSE_CLOSE_IND_EVT, /* AVCT_BROWSE_DISCONN_IND_EVT */
+ AVRC_BROWSE_CONG_IND_EVT, /* AVCT_BROWSE_CONG_IND_EVT */
+ AVRC_BROWSE_UNCONG_IND_EVT /* AVCT_BROWSE_UNCONG_IND_EVT */
+};
+
+/* use this unused opcode to indication no need to call the callback function */
+#define AVRC_OP_DROP 0xFE
+/* use this unused opcode to indication no need to call the callback function &
+ * free buffer */
+#define AVRC_OP_DROP_N_FREE 0xFD
+
+#define AVRC_OP_UNIT_INFO_RSP_LEN 8
+#define AVRC_OP_SUB_UNIT_INFO_RSP_LEN 8
+#define AVRC_OP_REJ_MSG_LEN 11
+
+/* Flags definitions for AVRC_MsgReq */
+#define AVRC_MSG_MASK_IS_VENDOR_CMD 0x01
+#define AVRC_MSG_MASK_IS_CONTINUATION_RSP 0x02
+
+/******************************************************************************
+ *
+ * Function avrc_ctrl_cback
+ *
+ * Description This is the callback function used by AVCTP to report
+ * received link events.
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+static void avrc_ctrl_cback(uint8_t handle, uint8_t event, uint16_t result,
+ BD_ADDR peer_addr) {
+ uint8_t avrc_event;
+
+ if (event <= AVRC_MAX_RCV_CTRL_EVT && avrc_cb.ccb[handle].p_ctrl_cback) {
+ avrc_event = avrc_ctrl_event_map[event];
+ if (event == AVCT_CONNECT_CFM_EVT) {
+ if (result != 0) /* failed */
+ avrc_event = AVRC_CLOSE_IND_EVT;
+ }
+ (*avrc_cb.ccb[handle].p_ctrl_cback)(handle, avrc_event, result, peer_addr);
+ }
+
+ if ((event == AVCT_DISCONNECT_CFM_EVT) ||
+ (event == AVCT_DISCONNECT_IND_EVT)) {
+ avrc_flush_cmd_q(handle);
+ alarm_free(avrc_cb.ccb_int[handle].tle);
+ avrc_cb.ccb_int[handle].tle = NULL;
+ }
+}
+
+/******************************************************************************
+ *
+ * Function avrc_flush_cmd_q
+ *
+ * Description Flush command queue for the specified avrc handle
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+void avrc_flush_cmd_q(uint8_t handle) {
+ AVRC_TRACE_DEBUG("AVRC: Flushing command queue for handle=0x%02x", handle);
+ avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+
+ alarm_cancel(avrc_cb.ccb_int[handle].tle);
+ fixed_queue_free(avrc_cb.ccb_int[handle].cmd_q, osi_free);
+ avrc_cb.ccb_int[handle].cmd_q = NULL;
+}
+
+/******************************************************************************
+ *
+ * Function avrc_process_timeout
+ *
+ * Description Handle avrc command timeout
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+void avrc_process_timeout(void* data) {
+ tAVRC_PARAM* param = (tAVRC_PARAM*)data;
+
+ AVRC_TRACE_DEBUG("AVRC: command timeout (handle=0x%02x, label=0x%02x)",
+ param->handle, param->label);
+
+ /* Notify app */
+ if (avrc_cb.ccb[param->handle].p_ctrl_cback) {
+ (*avrc_cb.ccb[param->handle].p_ctrl_cback)(
+ param->handle, AVRC_CMD_TIMEOUT_EVT, param->label, NULL);
+ }
+
+ /* If vendor command timed-out, then send next command in the queue */
+ if (param->msg_mask & AVRC_MSG_MASK_IS_VENDOR_CMD) {
+ avrc_send_next_vendor_cmd(param->handle);
+ }
+ osi_free(param);
+}
+
+/******************************************************************************
+ *
+ * Function avrc_send_next_vendor_cmd
+ *
+ * Description Dequeue and send next vendor command for given handle
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+void avrc_send_next_vendor_cmd(uint8_t handle) {
+ BT_HDR* p_next_cmd;
+ uint8_t next_label;
+
+ while ((p_next_cmd = (BT_HDR*)fixed_queue_try_dequeue(
+ avrc_cb.ccb_int[handle].cmd_q)) != NULL) {
+ p_next_cmd->event &= 0xFF; /* opcode */
+ next_label = (p_next_cmd->layer_specific) >> 8; /* extract label */
+ p_next_cmd->layer_specific &= 0xFF; /* AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+
+ AVRC_TRACE_DEBUG(
+ "AVRC: Dequeuing command 0x%08x (handle=0x%02x, label=0x%02x)",
+ p_next_cmd, handle, next_label);
+
+ /* Send the message */
+ if ((AVCT_MsgReq(handle, next_label, AVCT_CMD, p_next_cmd)) ==
+ AVCT_SUCCESS) {
+ /* Start command timer to wait for response */
+ avrc_start_cmd_timer(handle, next_label, AVRC_MSG_MASK_IS_VENDOR_CMD);
+ return;
+ }
+ }
+
+ if (p_next_cmd == NULL) {
+ /* cmd queue empty */
+ avrc_cb.ccb_int[handle].flags &= ~AVRC_CB_FLAGS_RSP_PENDING;
+ }
+}
+
+/******************************************************************************
+ *
+ * Function avrc_start_cmd_timer
+ *
+ * Description Start timer for waiting for responses
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask) {
+ tAVRC_PARAM* param =
+ static_cast<tAVRC_PARAM*>(osi_malloc(sizeof(tAVRC_PARAM)));
+ param->handle = handle;
+ param->label = label;
+ param->msg_mask = msg_mask;
+
+ AVRC_TRACE_DEBUG("AVRC: starting timer (handle=0x%02x, label=0x%02x)", handle,
+ label);
+
+ alarm_set_on_queue(avrc_cb.ccb_int[handle].tle, AVRC_CMD_TOUT_MS,
+ avrc_process_timeout, param, btu_general_alarm_queue);
+}
+
+/******************************************************************************
+ *
+ * Function avrc_get_data_ptr
+ *
+ * Description Gets a pointer to the data payload in the packet.
+ *
+ * Returns A pointer to the data payload.
+ *
+ *****************************************************************************/
+static uint8_t* avrc_get_data_ptr(BT_HDR* p_pkt) {
+ return (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+}
+
+/******************************************************************************
+ *
+ * Function avrc_copy_packet
+ *
+ * Description Copies an AVRC packet to a new buffer. In the new buffer,
+ * the payload offset is at least AVCT_MSG_OFFSET octets.
+ *
+ * Returns The buffer with the copied data.
+ *
+ *****************************************************************************/
+static BT_HDR* avrc_copy_packet(BT_HDR* p_pkt, int rsp_pkt_len) {
+ const int offset = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+ const int pkt_len = MAX(rsp_pkt_len, p_pkt->len);
+ BT_HDR* p_pkt_copy = (BT_HDR*)osi_malloc(BT_HDR_SIZE + offset + pkt_len);
+
+ /* Copy the packet header, set the new offset, and copy the payload */
+ memcpy(p_pkt_copy, p_pkt, BT_HDR_SIZE);
+ p_pkt_copy->offset = offset;
+ uint8_t* p_data = avrc_get_data_ptr(p_pkt);
+ uint8_t* p_data_copy = avrc_get_data_ptr(p_pkt_copy);
+ memcpy(p_data_copy, p_data, p_pkt->len);
+
+ return p_pkt_copy;
+}
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/******************************************************************************
+ *
+ * Function avrc_prep_end_frag
+ *
+ * Description This function prepares an end response fragment
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+static void avrc_prep_end_frag(uint8_t handle) {
+ tAVRC_FRAG_CB* p_fcb;
+ BT_HDR* p_pkt_new;
+ uint8_t *p_data, *p_orig_data;
+ uint8_t rsp_type;
+
+ AVRC_TRACE_DEBUG("%s", __func__);
+ p_fcb = &avrc_cb.fcb[handle];
+
+ /* The response type of the end fragment should be the same as the the PDU of
+ *"End Fragment
+ ** Response" Errata:
+ *https://www.bluetooth.org/errata/errata_view.cfm?errata_id=4383
+ */
+ p_orig_data = ((uint8_t*)(p_fcb->p_fmsg + 1) + p_fcb->p_fmsg->offset);
+ rsp_type = ((*p_orig_data) & AVRC_CTYPE_MASK);
+
+ p_pkt_new = p_fcb->p_fmsg;
+ p_pkt_new->len -=
+ (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+ p_pkt_new->offset +=
+ (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE);
+ p_data = (uint8_t*)(p_pkt_new + 1) + p_pkt_new->offset;
+ *p_data++ = rsp_type;
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ *p_data++ = p_fcb->frag_pdu;
+ *p_data++ = AVRC_PKT_END;
+
+ /* 4=pdu, pkt_type & len */
+ UINT16_TO_BE_STREAM(
+ p_data, (p_pkt_new->len - AVRC_VENDOR_HDR_SIZE - AVRC_MIN_META_HDR_SIZE));
+}
+
+/******************************************************************************
+ *
+ * Function avrc_send_continue_frag
+ *
+ * Description This function sends a continue response fragment
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+static uint16_t avrc_send_continue_frag(uint8_t handle, uint8_t label) {
+ tAVRC_FRAG_CB* p_fcb;
+ BT_HDR *p_pkt_old, *p_pkt;
+ uint8_t *p_old, *p_data;
+ uint8_t cr = AVCT_RSP;
+
+ p_fcb = &avrc_cb.fcb[handle];
+ p_pkt = p_fcb->p_fmsg;
+
+ AVRC_TRACE_DEBUG("%s handle = %u label = %u len = %d", __func__, handle,
+ label, p_pkt->len);
+ if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
+ int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+ p_pkt_old = p_fcb->p_fmsg;
+ p_pkt = (BT_HDR*)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
+ p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
+ p_pkt->offset = AVCT_MSG_OFFSET;
+ p_pkt->layer_specific = p_pkt_old->layer_specific;
+ p_pkt->event = p_pkt_old->event;
+ p_old = (uint8_t*)(p_pkt_old + 1) + p_pkt_old->offset;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ memcpy(p_data, p_old, AVRC_MAX_CTRL_DATA_LEN);
+ /* use AVRC continue packet type */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+ p_data++; /* pdu */
+ *p_data++ = AVRC_PKT_CONTINUE;
+ /* 4=pdu, pkt_type & len */
+ UINT16_TO_BE_STREAM(p_data,
+ (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE - 4));
+
+ /* prepare the left over for as an end fragment */
+ avrc_prep_end_frag(handle);
+ } else {
+ /* end fragment. clean the control block */
+ p_fcb->frag_enabled = false;
+ p_fcb->p_fmsg = NULL;
+ }
+ return AVCT_MsgReq(handle, label, cr, p_pkt);
+}
+
+/******************************************************************************
+ *
+ * Function avrc_proc_vendor_command
+ *
+ * Description This function processes received vendor command.
+ *
+ * Returns if not NULL, the response to send right away.
+ *
+ *****************************************************************************/
+static BT_HDR* avrc_proc_vendor_command(uint8_t handle, uint8_t label,
+ BT_HDR* p_pkt,
+ tAVRC_MSG_VENDOR* p_msg) {
+ BT_HDR* p_rsp = NULL;
+ uint8_t* p_data;
+ uint8_t* p_begin;
+ uint8_t pkt_type;
+ bool abort_frag = false;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ tAVRC_FRAG_CB* p_fcb;
+
+ p_begin = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_begin + AVRC_VENDOR_HDR_SIZE;
+ pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+
+ if (pkt_type != AVRC_PKT_SINGLE) {
+ /* reject - commands can only be in single packets at AVRCP level */
+ AVRC_TRACE_ERROR("commands must be in single packet pdu:0x%x", *p_data);
+ /* use the current GKI buffer to send the reject */
+ status = AVRC_STS_BAD_CMD;
+ }
+ /* check if there are fragments waiting to be sent */
+ else if (avrc_cb.fcb[handle].frag_enabled) {
+ p_fcb = &avrc_cb.fcb[handle];
+ if (p_msg->company_id == AVRC_CO_METADATA) {
+ switch (*p_data) {
+ case AVRC_PDU_ABORT_CONTINUATION_RSP:
+ /* aborted by CT - send accept response */
+ abort_frag = true;
+ p_begin = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ *p_begin = (AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK);
+ if (*(p_data + 4) != p_fcb->frag_pdu) {
+ *p_begin = (AVRC_RSP_REJ & AVRC_CTYPE_MASK);
+ *(p_data + 4) = AVRC_STS_BAD_PARAM;
+ } else {
+ p_data = (p_begin + AVRC_VENDOR_HDR_SIZE + 2);
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = (p_data - p_begin);
+ }
+ AVCT_MsgReq(handle, label, AVCT_RSP, p_pkt);
+ p_msg->hdr.opcode =
+ AVRC_OP_DROP; /* used the p_pkt to send response */
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP:
+ if (*(p_data + 4) == p_fcb->frag_pdu) {
+ avrc_send_continue_frag(handle, label);
+ p_msg->hdr.opcode = AVRC_OP_DROP_N_FREE;
+ } else {
+ /* the pdu id does not match - reject the command using the current
+ * GKI buffer */
+ AVRC_TRACE_ERROR(
+ "%s continue pdu: 0x%x does not match the current pdu: 0x%x",
+ __func__, *(p_data + 4), p_fcb->frag_pdu);
+ status = AVRC_STS_BAD_PARAM;
+ abort_frag = true;
+ }
+ break;
+
+ default:
+ /* implicit abort */
+ abort_frag = true;
+ }
+ } else {
+ abort_frag = true;
+ /* implicit abort */
+ }
+
+ if (abort_frag) {
+ osi_free_and_reset((void**)&p_fcb->p_fmsg);
+ p_fcb->frag_enabled = false;
+ }
+ }
+
+ if (status != AVRC_STS_NO_ERROR) {
+ /* use the current GKI buffer to build/send the reject message */
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = AVRC_RSP_REJ;
+ p_data += AVRC_VENDOR_HDR_SIZE; /* pdu */
+ *p_data++ = 0; /* pkt_type */
+ UINT16_TO_BE_STREAM(p_data, 1); /* len */
+ *p_data++ = status; /* error code */
+ p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
+ p_rsp = p_pkt;
+ }
+
+ return p_rsp;
+}
+
+/******************************************************************************
+ *
+ * Function avrc_proc_far_msg
+ *
+ * Description This function processes metadata fragmenation
+ * and reassembly
+ *
+ * Returns 0, to report the message with msg_cback .
+ *
+ *****************************************************************************/
+static uint8_t avrc_proc_far_msg(uint8_t handle, uint8_t label, uint8_t cr,
+ BT_HDR** pp_pkt, tAVRC_MSG_VENDOR* p_msg) {
+ BT_HDR* p_pkt = *pp_pkt;
+ uint8_t* p_data;
+ uint8_t drop_code = 0;
+ bool buf_overflow = false;
+ BT_HDR* p_rsp = NULL;
+ BT_HDR* p_cmd = NULL;
+ bool req_continue = false;
+ BT_HDR* p_pkt_new = NULL;
+ uint8_t pkt_type;
+ tAVRC_RASM_CB* p_rcb;
+ tAVRC_NEXT_CMD avrc_cmd;
+ tAVRC_STS status;
+
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+
+ /* Skip over vendor header (ctype, subunit*, opcode, CO_ID) */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+
+ pkt_type = *(p_data + 1) & AVRC_PKT_TYPE_MASK;
+ AVRC_TRACE_DEBUG("pkt_type %d", pkt_type);
+ p_rcb = &avrc_cb.rcb[handle];
+
+ /* check if the message needs to be re-assembled */
+ if (pkt_type == AVRC_PKT_SINGLE || pkt_type == AVRC_PKT_START) {
+ /* previous fragments need to be dropped, when received another new message
+ */
+ p_rcb->rasm_offset = 0;
+ osi_free_and_reset((void**)&p_rcb->p_rmsg);
+ }
+
+ if (pkt_type != AVRC_PKT_SINGLE && cr == AVCT_RSP) {
+ /* not a single response packet - need to re-assemble metadata messages */
+ if (pkt_type == AVRC_PKT_START) {
+ /* Allocate buffer for re-assembly */
+ p_rcb->rasm_pdu = *p_data;
+ p_rcb->p_rmsg = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ /* Copy START packet to buffer for re-assembling fragments */
+ memcpy(p_rcb->p_rmsg, p_pkt, sizeof(BT_HDR)); /* Copy bt hdr */
+
+ /* Copy metadata message */
+ memcpy((uint8_t*)(p_rcb->p_rmsg + 1),
+ (uint8_t*)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+
+ /* offset of start of metadata response in reassembly buffer */
+ p_rcb->p_rmsg->offset = p_rcb->rasm_offset = 0;
+
+ /*
+ * Free original START packet, replace with pointer to
+ * reassembly buffer.
+ */
+ osi_free(p_pkt);
+ *pp_pkt = p_rcb->p_rmsg;
+
+ /*
+ * Set offset to point to where to copy next - use the same
+ * reassembly logic as AVCT.
+ */
+ p_rcb->p_rmsg->offset += p_rcb->p_rmsg->len;
+ req_continue = true;
+ } else if (p_rcb->p_rmsg == NULL) {
+ /* Received a CONTINUE/END, but no corresponding START
+ (or previous fragmented response was dropped) */
+ AVRC_TRACE_DEBUG(
+ "Received a CONTINUE/END without no corresponding START \
+ (or previous fragmented response was dropped)");
+ drop_code = 5;
+ osi_free(p_pkt);
+ *pp_pkt = NULL;
+ } else {
+ /* get size of buffer holding assembled message */
+ /*
+ * NOTE: The buffer is allocated above at the beginning of the
+ * reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
+ */
+ uint16_t buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
+ /* adjust offset and len of fragment for header byte */
+ p_pkt->offset += (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+ p_pkt->len -= (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE);
+ /* verify length */
+ if ((p_rcb->p_rmsg->offset + p_pkt->len) > buf_len) {
+ AVRC_TRACE_WARNING(
+ "Fragmented message too big! - report the partial message");
+ p_pkt->len = buf_len - p_rcb->p_rmsg->offset;
+ pkt_type = AVRC_PKT_END;
+ buf_overflow = true;
+ }
+
+ /* copy contents of p_pkt to p_rx_msg */
+ memcpy((uint8_t*)(p_rcb->p_rmsg + 1) + p_rcb->p_rmsg->offset,
+ (uint8_t*)(p_pkt + 1) + p_pkt->offset, p_pkt->len);
+
+ if (pkt_type == AVRC_PKT_END) {
+ p_rcb->p_rmsg->offset = p_rcb->rasm_offset;
+ p_rcb->p_rmsg->len += p_pkt->len;
+ p_pkt_new = p_rcb->p_rmsg;
+ p_rcb->rasm_offset = 0;
+ p_rcb->p_rmsg = NULL;
+ p_msg->p_vendor_data = (uint8_t*)(p_pkt_new + 1) + p_pkt_new->offset;
+ p_msg->hdr.ctype = p_msg->p_vendor_data[0] & AVRC_CTYPE_MASK;
+ /* 6 = ctype, subunit*, opcode & CO_ID */
+ p_msg->p_vendor_data += AVRC_VENDOR_HDR_SIZE;
+ p_msg->vendor_len = p_pkt_new->len - AVRC_VENDOR_HDR_SIZE;
+ p_data = p_msg->p_vendor_data + 1; /* skip pdu */
+ *p_data++ = AVRC_PKT_SINGLE;
+ UINT16_TO_BE_STREAM(p_data,
+ (p_msg->vendor_len - AVRC_MIN_META_HDR_SIZE));
+ AVRC_TRACE_DEBUG("end frag:%d, total len:%d, offset:%d", p_pkt->len,
+ p_pkt_new->len, p_pkt_new->offset);
+ } else {
+ p_rcb->p_rmsg->offset += p_pkt->len;
+ p_rcb->p_rmsg->len += p_pkt->len;
+ p_pkt_new = NULL;
+ req_continue = true;
+ }
+ osi_free(p_pkt);
+ *pp_pkt = p_pkt_new;
+ }
+ }
+
+ if (cr == AVCT_CMD) {
+ p_rsp = avrc_proc_vendor_command(handle, label, *pp_pkt, p_msg);
+ if (p_rsp) {
+ AVCT_MsgReq(handle, label, AVCT_RSP, p_rsp);
+ drop_code = 3;
+ } else if (p_msg->hdr.opcode == AVRC_OP_DROP) {
+ drop_code = 1;
+ } else if (p_msg->hdr.opcode == AVRC_OP_DROP_N_FREE)
+ drop_code = 4;
+
+ } else if (cr == AVCT_RSP) {
+ if (req_continue == true) {
+ avrc_cmd.pdu = AVRC_PDU_REQUEST_CONTINUATION_RSP;
+ drop_code = 2;
+ } else if (buf_overflow == true) {
+ /* Incoming message too big to fit in BT_DEFAULT_BUFFER_SIZE. Send abort
+ * to peer */
+ avrc_cmd.pdu = AVRC_PDU_ABORT_CONTINUATION_RSP;
+ drop_code = 4;
+ } else {
+ return drop_code;
+ }
+ avrc_cmd.status = AVRC_STS_NO_ERROR;
+ avrc_cmd.target_pdu = p_rcb->rasm_pdu;
+ status = AVRC_BldCommand((tAVRC_COMMAND*)&avrc_cmd, &p_cmd);
+ if (status == AVRC_STS_NO_ERROR) {
+ AVRC_MsgReq(handle, (uint8_t)(label), AVRC_CMD_CTRL, p_cmd);
+ }
+ }
+
+ return drop_code;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+
+/******************************************************************************
+ *
+ * Function avrc_msg_cback
+ *
+ * Description This is the callback function used by AVCTP to report
+ * received AV control messages.
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+static void avrc_msg_cback(uint8_t handle, uint8_t label, uint8_t cr,
+ BT_HDR* p_pkt) {
+ uint8_t opcode;
+ tAVRC_MSG msg;
+ uint8_t* p_data;
+ uint8_t* p_begin;
+ bool drop = false;
+ bool do_free = true;
+ BT_HDR* p_rsp = NULL;
+ uint8_t* p_rsp_data;
+ int xx;
+ bool reject = false;
+ const char* p_drop_msg = "dropped";
+ tAVRC_MSG_VENDOR* p_msg = &msg.vendor;
+
+ if (cr == AVCT_CMD && (p_pkt->layer_specific & AVCT_DATA_CTRL &&
+ AVRC_PACKET_LEN < sizeof(p_pkt->len))) {
+ /* Ignore the invalid AV/C command frame */
+ p_drop_msg = "dropped - too long AV/C cmd frame size";
+ osi_free(p_pkt);
+ return;
+ }
+
+ if (cr == AVCT_REJ) {
+ /* The peer thinks that this PID is no longer open - remove this handle */
+ /* */
+ osi_free(p_pkt);
+ AVCT_RemoveConn(handle);
+ return;
+ } else if (cr == AVCT_RSP) {
+ /* Received response. Stop command timeout timer */
+ AVRC_TRACE_DEBUG("AVRC: stopping timer (handle=0x%02x)", handle);
+ alarm_cancel(avrc_cb.ccb_int[handle].tle);
+ }
+
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ memset(&msg, 0, sizeof(tAVRC_MSG));
+
+ if (p_pkt->layer_specific == AVCT_DATA_BROWSE) {
+ opcode = AVRC_OP_BROWSE;
+ msg.browse.hdr.ctype = cr;
+ msg.browse.p_browse_data = p_data;
+ msg.browse.browse_len = p_pkt->len;
+ msg.browse.p_browse_pkt = p_pkt;
+ } else {
+ msg.hdr.ctype = p_data[0] & AVRC_CTYPE_MASK;
+ AVRC_TRACE_DEBUG("%s handle:%d, ctype:%d, offset:%d, len: %d", __func__,
+ handle, msg.hdr.ctype, p_pkt->offset, p_pkt->len);
+ msg.hdr.subunit_type =
+ (p_data[1] & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.hdr.subunit_id = p_data[1] & AVRC_SUBID_MASK;
+ opcode = p_data[2];
+ }
+
+ if (((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) && (cr == AVCT_CMD)) ||
+ ((avrc_cb.ccb[handle].control & AVRC_CT_CONTROL) && (cr == AVCT_RSP))) {
+ switch (opcode) {
+ case AVRC_OP_UNIT_INFO:
+ if (cr == AVCT_CMD) {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set subunit_type &
+ subunit_id,
+ set AVRC_OP_UNIT_INFO */
+ /* 3 bytes: ctype, subunit*, opcode */
+ p_rsp_data += AVRC_AVC_HDR_SIZE;
+ *p_rsp_data++ = 7;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ AVRC_CO_ID_TO_BE_STREAM(p_rsp_data, avrc_cb.ccb[handle].company_id);
+ p_rsp->len =
+ (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+ p_drop_msg = "auto respond";
+ } else {
+ /* parse response */
+ p_data += 4; /* 3 bytes: ctype, subunit*, opcode + octet 3 (is 7)*/
+ msg.unit.unit_type =
+ (*p_data & AVRC_SUBTYPE_MASK) >> AVRC_SUBTYPE_SHIFT;
+ msg.unit.unit = *p_data & AVRC_SUBID_MASK;
+ p_data++;
+ AVRC_BE_STREAM_TO_CO_ID(msg.unit.company_id, p_data);
+ }
+ break;
+
+ case AVRC_OP_SUB_INFO:
+ if (cr == AVCT_CMD) {
+ /* send the response to the peer */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_SUB_UNIT_INFO_RSP_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_IMPL_STBL;
+ /* check & set the offset. set response code, set (subunit_type &
+ subunit_id),
+ set AVRC_OP_SUB_INFO, set (page & extention code) */
+ p_rsp_data += 4;
+ /* Panel subunit & id=0 */
+ *p_rsp_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ memset(p_rsp_data, AVRC_CMD_OPRND_PAD, AVRC_SUBRSP_OPRND_BYTES);
+ p_rsp_data += AVRC_SUBRSP_OPRND_BYTES;
+ p_rsp->len =
+ (uint16_t)(p_rsp_data - (uint8_t*)(p_rsp + 1) - p_rsp->offset);
+ cr = AVCT_RSP;
+ p_drop_msg = "auto responded";
+ } else {
+ /* parse response */
+ p_data += AVRC_AVC_HDR_SIZE; /* 3 bytes: ctype, subunit*, opcode */
+ msg.sub.page =
+ (*p_data++ >> AVRC_SUB_PAGE_SHIFT) & AVRC_SUB_PAGE_MASK;
+ xx = 0;
+ while (*p_data != AVRC_CMD_OPRND_PAD && xx < AVRC_SUB_TYPE_LEN) {
+ msg.sub.subunit_type[xx] = *p_data++ >> AVRC_SUBTYPE_SHIFT;
+ if (msg.sub.subunit_type[xx] == AVRC_SUB_PANEL)
+ msg.sub.panel = true;
+ xx++;
+ }
+ }
+ break;
+
+ case AVRC_OP_VENDOR: {
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_begin = p_data;
+ if (p_pkt->len <
+ AVRC_VENDOR_HDR_SIZE) /* 6 = ctype, subunit*, opcode & CO_ID */
+ {
+ if (cr == AVCT_CMD)
+ reject = true;
+ else
+ drop = true;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
+ opcode */
+ AVRC_BE_STREAM_TO_CO_ID(p_msg->company_id, p_data);
+ p_msg->p_vendor_data = p_data;
+ p_msg->vendor_len = p_pkt->len - (p_data - p_begin);
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ uint8_t drop_code = 0;
+ if (p_msg->company_id == AVRC_CO_METADATA) {
+ /* Validate length for metadata message */
+ if (p_pkt->len < (AVRC_VENDOR_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)) {
+ if (cr == AVCT_CMD)
+ reject = true;
+ else
+ drop = true;
+ break;
+ }
+
+ /* Check+handle fragmented messages */
+ drop_code = avrc_proc_far_msg(handle, label, cr, &p_pkt, p_msg);
+ if (drop_code > 0) drop = true;
+ }
+ if (drop_code > 0) {
+ if (drop_code != 4) do_free = false;
+ switch (drop_code) {
+ case 1:
+ p_drop_msg = "sent_frag";
+ break;
+ case 2:
+ p_drop_msg = "req_cont";
+ break;
+ case 3:
+ p_drop_msg = "sent_frag3";
+ break;
+ case 4:
+ p_drop_msg = "sent_frag_free";
+ break;
+ default:
+ p_drop_msg = "sent_fragd";
+ }
+ }
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
+ /* If vendor response received, and did not ask for continuation */
+ /* then check queue for addition commands to send */
+ if ((cr == AVCT_RSP) && (drop_code != 2)) {
+ avrc_send_next_vendor_cmd(handle);
+ }
+ } break;
+
+ case AVRC_OP_PASS_THRU:
+ if (p_pkt->len < 5) /* 3 bytes: ctype, subunit*, opcode & op_id & len */
+ {
+ if (cr == AVCT_CMD)
+ reject = true;
+ else
+ drop = true;
+ break;
+ }
+ p_data += AVRC_AVC_HDR_SIZE; /* skip the first 3 bytes: ctype, subunit*,
+ opcode */
+ msg.pass.op_id = (AVRC_PASS_OP_ID_MASK & *p_data);
+ if (AVRC_PASS_STATE_MASK & *p_data)
+ msg.pass.state = true;
+ else
+ msg.pass.state = false;
+ p_data++;
+ msg.pass.pass_len = *p_data++;
+ if (msg.pass.pass_len != p_pkt->len - 5)
+ msg.pass.pass_len = p_pkt->len - 5;
+ if (msg.pass.pass_len)
+ msg.pass.p_pass_data = p_data;
+ else
+ msg.pass.p_pass_data = NULL;
+ break;
+
+ case AVRC_OP_BROWSE:
+ /* If browse response received, then check queue for addition commands
+ * to send */
+ if (cr == AVCT_RSP) {
+ avrc_send_next_vendor_cmd(handle);
+ }
+ break;
+
+ default:
+ if ((avrc_cb.ccb[handle].control & AVRC_CT_TARGET) &&
+ (cr == AVCT_CMD)) {
+ /* reject unsupported opcode */
+ reject = true;
+ }
+ drop = true;
+ break;
+ }
+ } else /* drop the event */
+ {
+ if (opcode != AVRC_OP_BROWSE) drop = true;
+ }
+
+ if (reject) {
+ /* reject unsupported opcode */
+ p_rsp = avrc_copy_packet(p_pkt, AVRC_OP_REJ_MSG_LEN);
+ p_rsp_data = avrc_get_data_ptr(p_rsp);
+ *p_rsp_data = AVRC_RSP_REJ;
+ p_drop_msg = "rejected";
+ cr = AVCT_RSP;
+ drop = true;
+ }
+
+ if (p_rsp) {
+ /* set to send response right away */
+ AVCT_MsgReq(handle, label, cr, p_rsp);
+ drop = true;
+ }
+
+ if (drop == false) {
+ msg.hdr.opcode = opcode;
+ (*avrc_cb.ccb[handle].p_msg_cback)(handle, label, opcode, &msg);
+ } else {
+ AVRC_TRACE_WARNING("%s %s msg handle:%d, control:%d, cr:%d, opcode:x%x",
+ __func__, p_drop_msg, handle,
+ avrc_cb.ccb[handle].control, cr, opcode);
+ }
+
+ if (opcode == AVRC_OP_BROWSE && msg.browse.p_browse_pkt == NULL) {
+ do_free = false;
+ }
+
+ if (do_free) osi_free(p_pkt);
+}
+
+static void AVRC_build_empty_packet(BT_HDR* p_pkt) {
+ uint8_t* p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+ *p_start = AVRC_RSP_ACCEPT & AVRC_CTYPE_MASK;
+ p_start += AVRC_VENDOR_HDR_SIZE;
+ UINT8_TO_BE_STREAM(p_start, 0);
+ UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
+ UINT16_TO_BE_STREAM(p_start, 0);
+ p_pkt->len = AVRC_VENDOR_HDR_SIZE + 4;
+}
+
+static void AVRC_build_error_packet(BT_HDR* p_pkt) {
+ uint8_t* p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+ *p_start = AVRC_RSP_REJ & AVRC_CTYPE_MASK;
+ p_start += AVRC_VENDOR_HDR_SIZE;
+ UINT8_TO_BE_STREAM(p_start, 0);
+ UINT8_TO_BE_STREAM(p_start, AVRC_PKT_SINGLE);
+ UINT16_TO_BE_STREAM(p_start, 1);
+ UINT8_TO_BE_STREAM(p_start, AVRC_STS_BAD_PARAM);
+ p_pkt->len = AVRC_VENDOR_HDR_SIZE + 5;
+}
+
+static uint16_t AVRC_HandleContinueRsp(uint8_t handle, uint8_t label,
+ BT_HDR* p_pkt) {
+ AVRC_TRACE_DEBUG("%s()", __func__);
+
+ uint8_t* p_data =
+ ((uint8_t*)(p_pkt + 1) + p_pkt->offset + AVRC_VENDOR_HDR_SIZE);
+ tAVRC_FRAG_CB* p_fcb = &avrc_cb.fcb[handle];
+
+ uint8_t pdu, pkt_type, target_pdu;
+ uint16_t len;
+
+ BE_STREAM_TO_UINT8(pdu, p_data);
+ BE_STREAM_TO_UINT8(pkt_type, p_data);
+ BE_STREAM_TO_UINT16(len, p_data);
+ BE_STREAM_TO_UINT8(target_pdu, p_data);
+
+ if (pdu == AVRC_PDU_REQUEST_CONTINUATION_RSP &&
+ target_pdu == p_fcb->frag_pdu) {
+ return avrc_send_continue_frag(handle, label);
+ }
+
+ if (pdu == AVRC_PDU_ABORT_CONTINUATION_RSP && target_pdu == p_fcb->frag_pdu) {
+ AVRC_build_empty_packet(p_pkt);
+ } else {
+ AVRC_TRACE_ERROR("%s() error: target_pdu: 0x%02x, frag_pdu: 0x%02x",
+ __func__, *(p_data + 4), p_fcb->frag_pdu);
+ AVRC_build_error_packet(p_pkt);
+ }
+
+ p_fcb->frag_enabled = false;
+ osi_free_and_reset((void**)&p_fcb->p_fmsg);
+
+ return AVCT_MsgReq(handle, label, AVCT_RSP, p_pkt);
+}
+
+/******************************************************************************
+ *
+ * Function avrc_pass_msg
+ *
+ * Description Compose a PASS THROUGH command according to p_msg
+ *
+ * Input Parameters:
+ * p_msg: Pointer to PASS THROUGH message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns pointer to a valid GKI buffer if successful.
+ * NULL if p_msg is NULL.
+ *
+ *****************************************************************************/
+static BT_HDR* avrc_pass_msg(tAVRC_MSG_PASS* p_msg) {
+ CHECK(p_msg != NULL);
+ CHECK(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->pass_len));
+
+ BT_HDR* p_cmd = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+ uint8_t* p_data = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT); /* Panel subunit & id=0 */
+ *p_data++ = AVRC_OP_PASS_THRU;
+ *p_data = (AVRC_PASS_OP_ID_MASK & p_msg->op_id);
+ if (p_msg->state) *p_data |= AVRC_PASS_STATE_MASK;
+ p_data++;
+
+ if (p_msg->op_id == AVRC_ID_VENDOR) {
+ *p_data++ = p_msg->pass_len;
+ if (p_msg->pass_len && p_msg->p_pass_data) {
+ memcpy(p_data, p_msg->p_pass_data, p_msg->pass_len);
+ p_data += p_msg->pass_len;
+ }
+ } else {
+ /* set msg len to 0 for other op_id */
+ *p_data++ = 0;
+ }
+ p_cmd->len = (uint16_t)(p_data - (uint8_t*)(p_cmd + 1) - p_cmd->offset);
+
+ return p_cmd;
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_Open
+ *
+ * Description This function is called to open a connection to AVCTP.
+ * The connection can be either an initiator or acceptor, as
+ * determined by the p_ccb->stream parameter.
+ * The connection can be a target, a controller or for both
+ * role, as determined by the p_ccb->control parameter.
+ * By definition, a target connection is an acceptor connection
+ * that waits for an incoming AVCTP connection from the peer.
+ * The connection remains available to the application until
+ * the application closes it by calling AVRC_Close(). The
+ * application does not need to reopen the connection after an
+ * AVRC_CLOSE_IND_EVT is received.
+ *
+ * Input Parameters:
+ * p_ccb->company_id: Company Identifier.
+ *
+ * p_ccb->p_ctrl_cback: Pointer to control callback
+ * function.
+ *
+ * p_ccb->p_msg_cback: Pointer to message callback
+ * function.
+ *
+ * p_ccb->conn: AVCTP connection role. This is set to
+ * AVCTP_INT for initiator connections and AVCTP_ACP
+ * for acceptor connections.
+ *
+ * p_ccb->control: Control role. This is set to
+ * AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+ * for control connections or
+ * (AVRC_CT_TARGET|AVRC_CT_CONTROL)
+ * for connections that support both roles.
+ *
+ * peer_addr: BD address of peer device. This value is
+ * only used for initiator connections; for acceptor
+ * connections it can be set to NULL.
+ *
+ * Output Parameters:
+ * p_handle: Pointer to handle. This parameter is only
+ * valid if AVRC_SUCCESS is returned.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if there are not enough resources to open
+ * the connection.
+ *
+ *****************************************************************************/
+uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
+ BD_ADDR_PTR peer_addr) {
+ uint16_t status;
+ tAVCT_CC cc;
+
+ cc.p_ctrl_cback = avrc_ctrl_cback; /* Control callback */
+ cc.p_msg_cback = avrc_msg_cback; /* Message callback */
+ cc.pid = UUID_SERVCLASS_AV_REMOTE_CONTROL; /* Profile ID */
+ cc.role = p_ccb->conn; /* Initiator/acceptor role */
+ cc.control = p_ccb->control; /* Control role (Control/Target) */
+
+ status = AVCT_CreateConn(p_handle, &cc, peer_addr);
+ if (status == AVCT_SUCCESS) {
+ memcpy(&avrc_cb.ccb[*p_handle], p_ccb, sizeof(tAVRC_CONN_CB));
+ memset(&avrc_cb.ccb_int[*p_handle], 0, sizeof(tAVRC_CONN_INT_CB));
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ memset(&avrc_cb.fcb[*p_handle], 0, sizeof(tAVRC_FRAG_CB));
+ memset(&avrc_cb.rcb[*p_handle], 0, sizeof(tAVRC_RASM_CB));
+#endif
+ avrc_cb.ccb_int[*p_handle].tle = alarm_new("avrcp.commandTimer");
+ avrc_cb.ccb_int[*p_handle].cmd_q = fixed_queue_new(SIZE_MAX);
+ }
+ AVRC_TRACE_DEBUG("%s role: %d, control:%d status:%d, handle:%d", __func__,
+ cc.role, cc.control, status, *p_handle);
+
+ return status;
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_Close
+ *
+ * Description Close a connection opened with AVRC_Open().
+ * This function is called when the
+ * application is no longer using a connection.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_Close(uint8_t handle) {
+ AVRC_TRACE_DEBUG("%s handle:%d", __func__, handle);
+ return AVCT_RemoveConn(handle);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_OpenBrowse
+ *
+ * Description This function is called to open a browsing connection to
+ * AVCTP. The connection can be either an initiator or
+ * acceptor, as determined by the p_conn_role.
+ * The handle is returned by a previous call to AVRC_Open.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if there are not enough resources to open
+ * the connection.
+ *
+ *****************************************************************************/
+uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role) {
+ return AVCT_CreateBrowse(handle, conn_role);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_CloseBrowse
+ *
+ * Description Close a connection opened with AVRC_OpenBrowse().
+ * This function is called when the
+ * application is no longer using a connection.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_CloseBrowse(uint8_t handle) { return AVCT_RemoveBrowse(handle); }
+
+/******************************************************************************
+ *
+ * Function AVRC_MsgReq
+ *
+ * Description This function is used to send the AVRCP byte stream in p_pkt
+ * down to AVCTP.
+ *
+ * It is expected that p_pkt->offset is at least
+ * AVCT_MSG_OFFSET
+ * p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+ * p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or
+ * AVRC_OP_BROWSE
+ * The above BT_HDR settings are set by the AVRC_Bld*
+ * functions.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
+ BT_HDR* p_pkt) {
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ uint8_t* p_data;
+ uint8_t cr = AVCT_CMD;
+ bool chk_frag = true;
+ uint8_t* p_start = NULL;
+ tAVRC_FRAG_CB* p_fcb;
+ uint16_t len;
+ uint16_t status;
+ uint8_t msg_mask = 0;
+ uint16_t peer_mtu;
+
+ if (!p_pkt) return AVRC_BAD_PARAM;
+
+ AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d", __func__,
+ handle, label, ctype, p_pkt->len);
+
+ if (ctype >= AVRC_RSP_NOT_IMPL) cr = AVCT_RSP;
+
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ if (*p_data == AVRC_PDU_REQUEST_CONTINUATION_RSP ||
+ *p_data == AVRC_PDU_ABORT_CONTINUATION_RSP) {
+ return AVRC_HandleContinueRsp(handle, label, p_pkt);
+ }
+
+ if (p_pkt->event == AVRC_OP_VENDOR) {
+ /* add AVRCP Vendor Dependent headers */
+ p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+ p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
+ p_pkt->len += AVRC_VENDOR_HDR_SIZE;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = (ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+
+ /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
+ if (cr == AVCT_CMD) {
+ msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
+
+ if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP) ||
+ (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP)) {
+ msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+ }
+ }
+ } else if (p_pkt->event == AVRC_OP_PASS_THRU) {
+ /* add AVRCP Pass Through headers */
+ p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+ p_pkt->offset -= AVRC_PASS_THRU_SIZE;
+ p_pkt->len += AVRC_PASS_THRU_SIZE;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = (ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_PASS_THRU; /* opcode */
+ *p_data++ = AVRC_ID_VENDOR; /* operation id */
+ *p_data++ = 5; /* operation data len */
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ } else {
+ chk_frag = false;
+ peer_mtu = AVCT_GetBrowseMtu(handle);
+ if (p_pkt->len > (peer_mtu - AVCT_HDR_LEN_SINGLE)) {
+ AVRC_TRACE_ERROR(
+ "%s bigger than peer mtu (p_pkt->len(%d) > peer_mtu(%d-%d))",
+ __func__, p_pkt->len, peer_mtu, AVCT_HDR_LEN_SINGLE);
+ osi_free(p_pkt);
+ return AVRC_MSG_TOO_BIG;
+ }
+ }
+
+ /* abandon previous fragments */
+ p_fcb = &avrc_cb.fcb[handle];
+
+ if (p_fcb == NULL) {
+ AVRC_TRACE_ERROR("%s p_fcb is NULL", __func__);
+ osi_free(p_pkt);
+ return AVRC_NOT_OPEN;
+ }
+
+ if (p_fcb->frag_enabled) p_fcb->frag_enabled = false;
+
+ osi_free_and_reset((void**)&p_fcb->p_fmsg);
+
+ /* AVRCP spec has not defined any control channel commands that needs
+ * fragmentation at this level
+ * check for fragmentation only on the response */
+ if ((cr == AVCT_RSP) && (chk_frag == true)) {
+ if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) {
+ int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset);
+ BT_HDR* p_pkt_new =
+ (BT_HDR*)osi_malloc(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE);
+ if (p_start != NULL) {
+ p_fcb->frag_enabled = true;
+ p_fcb->p_fmsg = p_pkt;
+ p_fcb->frag_pdu = *p_start;
+ p_pkt = p_pkt_new;
+ p_pkt_new = p_fcb->p_fmsg;
+ p_pkt->len = AVRC_MAX_CTRL_DATA_LEN;
+ p_pkt->offset = p_pkt_new->offset;
+ p_pkt->layer_specific = p_pkt_new->layer_specific;
+ p_pkt->event = p_pkt_new->event;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_start -= AVRC_VENDOR_HDR_SIZE;
+ memcpy(p_data, p_start, AVRC_MAX_CTRL_DATA_LEN);
+ /* use AVRC start packet type */
+ p_data += AVRC_VENDOR_HDR_SIZE;
+ p_data++; /* pdu */
+ *p_data++ = AVRC_PKT_START;
+
+ /* 4 pdu, pkt_type & len */
+ len = (AVRC_MAX_CTRL_DATA_LEN - AVRC_VENDOR_HDR_SIZE -
+ AVRC_MIN_META_HDR_SIZE);
+ UINT16_TO_BE_STREAM(p_data, len);
+
+ /* prepare the left over for as an end fragment */
+ avrc_prep_end_frag(handle);
+ AVRC_TRACE_DEBUG("%s p_pkt len:%d/%d, next len:%d", __func__,
+ p_pkt->len, len, p_fcb->p_fmsg->len);
+ } else {
+ /* TODO: Is this "else" block valid? Remove it? */
+ AVRC_TRACE_ERROR("%s no buffers for fragmentation", __func__);
+ osi_free(p_pkt);
+ return AVRC_NO_RESOURCES;
+ }
+ }
+ } else if ((p_pkt->event == AVRC_OP_VENDOR) && (cr == AVCT_CMD) &&
+ (avrc_cb.ccb_int[handle].flags & AVRC_CB_FLAGS_RSP_PENDING) &&
+ !(msg_mask & AVRC_MSG_MASK_IS_CONTINUATION_RSP)) {
+ /* If we are sending a vendor specific command, and a response is pending,
+ * then enqueue the command until the response has been received.
+ * This is to interop with TGs that abort sending responses whenever a new
+ * command
+ * is received (exception is continuation request command
+ * must sent that to get additional response frags) */
+ AVRC_TRACE_DEBUG(
+ "AVRC: Enqueuing command 0x%08x (handle=0x%02x, label=0x%02x)", p_pkt,
+ handle, label);
+
+ /* label in BT_HDR (will need this later when the command is dequeued) */
+ p_pkt->layer_specific = (label << 8) | (p_pkt->layer_specific & 0xFF);
+
+ /* Enqueue the command */
+ fixed_queue_enqueue(avrc_cb.ccb_int[handle].cmd_q, p_pkt);
+ return AVRC_SUCCESS;
+ }
+
+ /* Send the message */
+ status = AVCT_MsgReq(handle, label, cr, p_pkt);
+ if ((status == AVCT_SUCCESS) && (cr == AVCT_CMD)) {
+ /* If a command was successfully sent, indicate that a response is pending
+ */
+ avrc_cb.ccb_int[handle].flags |= AVRC_CB_FLAGS_RSP_PENDING;
+
+ /* Start command timer to wait for response */
+ avrc_start_cmd_timer(handle, label, msg_mask);
+ }
+
+ return status;
+#else
+ return AVRC_NO_RESOURCES;
+#endif
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_PassCmd
+ *
+ * Description Send a PASS THROUGH command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * p_msg: Pointer to PASS THROUGH message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label, tAVRC_MSG_PASS* p_msg) {
+ BT_HDR* p_buf;
+ uint16_t status = AVRC_NO_RESOURCES;
+ if (!p_msg) return AVRC_BAD_PARAM;
+
+ p_msg->hdr.ctype = AVRC_CMD_CTRL;
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf) {
+ status = AVCT_MsgReq(handle, label, AVCT_CMD, p_buf);
+ if (status == AVCT_SUCCESS) {
+ /* Start command timer to wait for response */
+ avrc_start_cmd_timer(handle, label, 0);
+ }
+ }
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_PassRsp
+ *
+ * Description Send a PASS THROUGH response to the peer device. This
+ * function can only be called for target role connections.
+ * This function must be called when a PASS THROUGH command
+ * message is received from the peer through the
+ * tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label. Must be the same value as
+ * passed with the command message in the callback
+ * function.
+ *
+ * p_msg: Pointer to PASS THROUGH message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label, tAVRC_MSG_PASS* p_msg) {
+ BT_HDR* p_buf;
+ if (!p_msg) return AVRC_BAD_PARAM;
+
+ p_buf = avrc_pass_msg(p_msg);
+ if (p_buf) return AVCT_MsgReq(handle, label, AVCT_RSP, p_buf);
+ return AVRC_NO_RESOURCES;
+}
diff --git a/mtkbt/code/bt/stack/avrc/avrc_bld_ct.cc b/mtkbt/code/bt/stack/avrc/avrc_bld_ct.cc
new file mode 100755
index 0000000..2cb1246
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_bld_ct.cc
@@ -0,0 +1,664 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function avrc_bld_next_cmd
+ *
+ * Description This function builds the Request Continue or Abort command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_next_cmd(tAVRC_NEXT_CMD* p_cmd, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+
+ AVRC_TRACE_API("avrc_bld_next_cmd");
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth 1 - pdu_id (1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->target_pdu);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+ * the following commands are introduced in AVRCP 1.4
+ ****************************************************************************/
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_abs_volume_cmd
+ *
+ * Description This function builds the Set Absolute Volume command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_abs_volume_cmd(tAVRC_SET_VOLUME_CMD* p_cmd,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+
+ AVRC_TRACE_API("avrc_bld_set_abs_volume_cmd");
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed lenth 1 - volume (1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_cmd->volume));
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_register_notifn
+ *
+ * Description This function builds the register notification.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_register_notifn(BT_HDR* p_pkt, uint8_t event_id,
+ uint32_t event_param) {
+ uint8_t *p_data, *p_start;
+
+ AVRC_TRACE_API("avrc_bld_register_notifn");
+ /* get the existing length, if any, and also the num attributes */
+ // Set the notify value
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 5 -*/
+ UINT16_TO_BE_STREAM(p_data, 5);
+ UINT8_TO_BE_STREAM(p_data, event_id);
+ UINT32_TO_BE_STREAM(p_data, event_param);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_capability_cmd
+ *
+ * Description This function builds the get capability command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_cmd(BT_HDR* p_pkt, uint8_t cap_id) {
+ AVRC_TRACE_API("avrc_bld_get_capability_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, cap_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_list_player_app_attr_cmd
+ *
+ * Description This function builds the list player app attrib command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_attr_cmd(BT_HDR* p_pkt) {
+ AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_list_player_app_values_cmd
+ *
+ * Description This function builds the list player app values command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_list_player_app_values_cmd(BT_HDR* p_pkt,
+ uint8_t attrib_id) {
+ AVRC_TRACE_API("avrc_bld_list_player_app_values_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 1 -*/
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, attrib_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_current_player_app_values_cmd
+ *
+ * Description This function builds the get current player app setting
+ * values command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_current_player_app_values_cmd(
+ BT_HDR* p_pkt, uint8_t num_attrib_id, uint8_t* attrib_ids) {
+ AVRC_TRACE_API("avrc_bld_get_current_player_app_values_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ uint8_t param_len =
+ num_attrib_id + 1; // 1 additional to hold num attributes feild
+ /* add length -*/
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, num_attrib_id);
+ for (int count = 0; count < num_attrib_id; count++) {
+ UINT8_TO_BE_STREAM(p_data, attrib_ids[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_current_player_app_values_cmd
+ *
+ * Description This function builds the set current player app setting
+ * values command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_current_player_app_values_cmd(
+ BT_HDR* p_pkt, uint8_t num_attrib_id, tAVRC_APP_SETTING* p_val) {
+ AVRC_TRACE_API("avrc_bld_set_current_player_app_values_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* we have to store attrib- value pair
+ * 1 additional to store num elements
+ */
+ uint8_t param_len = (2 * num_attrib_id) + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, num_attrib_id);
+ for (int count = 0; count < num_attrib_id; count++) {
+ UINT8_TO_BE_STREAM(p_data, p_val[count].attr_id);
+ UINT8_TO_BE_STREAM(p_data, p_val[count].attr_val);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_player_app_setting_attr_text_cmd
+ *
+ * Description This function builds the get player app setting attribute
+ * text command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_attr_text_cmd(
+ BT_HDR* p_pkt, tAVRC_GET_APP_ATTR_TXT_CMD* p_cmd) {
+ AVRC_TRACE_API("%s", __func__);
+
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+
+ uint8_t param_len = p_cmd->num_attr + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->num_attr);
+ for (int count = 0; count < p_cmd->num_attr; count++) {
+ UINT8_TO_BE_STREAM(p_data, p_cmd->attrs[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_player_app_setting_value_text_cmd
+ *
+ * Description This function builds the get player app setting value
+ * text command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_player_app_setting_value_text_cmd(
+ BT_HDR* p_pkt, tAVRC_GET_APP_VAL_TXT_CMD* p_cmd) {
+ AVRC_TRACE_API("%s", __func__);
+
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+
+ uint8_t param_len = p_cmd->num_val + 1;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ UINT8_TO_BE_STREAM(p_data, p_cmd->num_val);
+ for (int count = 0; count < p_cmd->num_val; count++) {
+ UINT8_TO_BE_STREAM(p_data, p_cmd->vals[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_element_attr_cmd
+ *
+ * Description This function builds the get element attribute command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_element_attr_cmd(BT_HDR* p_pkt,
+ uint8_t num_attrib,
+ uint32_t* attrib_ids) {
+ AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* we have to store attrib- value pair
+ * 1 additional to store num elements
+ */
+ uint8_t param_len = (4 * num_attrib) + 9;
+ /* add length */
+ UINT16_TO_BE_STREAM(p_data, param_len);
+ /* 8 bytes of identifier as 0 (playing)*/
+ UINT32_TO_BE_STREAM(p_data, 0);
+ UINT32_TO_BE_STREAM(p_data, 0);
+ UINT8_TO_BE_STREAM(p_data, num_attrib);
+ for (int count = 0; count < num_attrib; count++) {
+ UINT32_TO_BE_STREAM(p_data, attrib_ids[count]);
+ }
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_play_item_cmd
+ *
+ * Description This function builds the play item cmd
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_cmd(BT_HDR* p_pkt, uint8_t scope,
+ uint8_t* uid, uint16_t uid_counter) {
+ AVRC_TRACE_API("avrc_bld_get_element_attr_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 11 */
+ UINT16_TO_BE_STREAM(p_data, 0xb);
+ /* Add scope */
+ UINT8_TO_BE_STREAM(p_data, scope);
+ /* Add UID */
+ ARRAY_TO_BE_STREAM(p_data, uid, AVRC_UID_SIZE);
+ /* Add UID Counter */
+ UINT16_TO_BE_STREAM(p_data, uid_counter);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_play_status_cmd
+ *
+ * Description This function builds the get play status command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_cmd(BT_HDR* p_pkt) {
+ AVRC_TRACE_API("avrc_bld_list_player_app_attr_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+ /* add fixed length 0 -*/
+ UINT16_TO_BE_STREAM(p_data, 0);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_folder_items_cmd
+ *
+ * Description This function builds the get folder items cmd.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_cmd(BT_HDR* p_pkt,
+ const tAVRC_GET_ITEMS_CMD* cmd) {
+ AVRC_TRACE_API(
+ "avrc_bld_get_folder_items_cmd scope %d, start_item %d, end_item %d",
+ cmd->scope, cmd->start_item, cmd->end_item);
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t* p_data = p_start + 1; /* pdu */
+
+ /* To get the list of all media players we simply need to use the predefined
+ * PDU mentioned in above spec. */
+ /* scope (1) + st item (4) + end item (4) + attr (1) */
+ UINT16_TO_BE_STREAM(p_data, 10);
+ UINT8_TO_BE_STREAM(p_data, cmd->scope); /* scope (1bytes) */
+ UINT32_TO_BE_STREAM(p_data, cmd->start_item); /* start item (4bytes) */
+ UINT32_TO_BE_STREAM(p_data, cmd->end_item); /* end item (4bytes) */
+ UINT8_TO_BE_STREAM(p_data, 0); /* attribute count = 0 (1bytes) */
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_change_folder_cmd
+ *
+ * Description This function builds the change folder command
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_change_folder_cmd(BT_HDR* p_pkt,
+ const tAVRC_CHG_PATH_CMD* cmd) {
+ AVRC_TRACE_API("avrc_bld_change_folder_cmd");
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t* p_data = p_start + 1; /* pdu */
+
+ /* To change folder we need to provide the following:
+ * UID Counter (2) + Direction (1) + UID (8) = 11bytes
+ */
+ UINT16_TO_BE_STREAM(p_data, 11);
+ UINT16_TO_BE_STREAM(p_data, cmd->uid_counter);
+ UINT8_TO_BE_STREAM(p_data, cmd->direction);
+ ARRAY_TO_BE_STREAM(p_data, cmd->folder_uid, AVRC_UID_SIZE);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_browsed_player_cmd
+ *
+ * Description This function builds the set browsed player cmd.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_cmd(
+ BT_HDR* p_pkt, const tAVRC_SET_BR_PLAYER_CMD* cmd) {
+ AVRC_TRACE_API("%s", __func__);
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* This is where the PDU specific for AVRC starts
+ * AVRCP Spec 1.4 section 22.19 */
+ uint8_t* p_data = p_start + 1; /* pdu */
+
+ /* To change browsed player the following is the total length:
+ * Player ID (2)
+ */
+ UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+ UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_addressed_player_cmd
+ *
+ * Description This function builds the set addressed player cmd.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_addressed_player_cmd(
+ BT_HDR* p_pkt, const tAVRC_SET_ADDR_PLAYER_CMD* cmd) {
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+
+ /* To change addressed player the following is the total length:
+ * Player ID (2)
+ */
+ UINT16_TO_BE_STREAM(p_data, 2); /* fixed length */
+ UINT16_TO_BE_STREAM(p_data, cmd->player_id);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_init_cmd_buffer
+ *
+ * Description This function initializes the command buffer based on PDU
+ *
+ * Returns NULL, if no GKI buffer or failure to build the message.
+ * Otherwise, the GKI buffer that contains the initialized
+ * message.
+ *
+ ******************************************************************************/
+static BT_HDR* avrc_bld_init_cmd_buffer(tAVRC_COMMAND* p_cmd) {
+ uint16_t chnl = AVCT_DATA_CTRL;
+ uint8_t opcode = avrc_opcode_from_pdu(p_cmd->pdu);
+ AVRC_TRACE_API("avrc_bld_init_cmd_buffer: pdu=%x, opcode=%x", p_cmd->pdu,
+ opcode);
+
+ uint16_t offset = 0;
+ switch (opcode) {
+ case AVRC_OP_BROWSE:
+ chnl = AVCT_DATA_BROWSE;
+ offset = AVCT_BROWSE_OFFSET;
+ break;
+
+ case AVRC_OP_PASS_THRU:
+ offset = AVRC_MSG_PASS_THRU_OFFSET;
+ break;
+
+ case AVRC_OP_VENDOR:
+ offset = AVRC_MSG_VENDOR_OFFSET;
+ break;
+ }
+
+ /* allocate and initialize the buffer */
+ BT_HDR* p_pkt = (BT_HDR*)osi_malloc(AVRC_META_CMD_BUF_SIZE);
+ uint8_t *p_data, *p_start;
+
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = opcode;
+ p_pkt->offset = offset;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_start = p_data;
+
+ /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+ if (opcode != AVRC_OP_PASS_THRU) *p_data++ = p_cmd->pdu;
+
+ switch (opcode) {
+ case AVRC_OP_VENDOR:
+ /* reserved 0, packet_type 0 */
+ UINT8_TO_BE_STREAM(p_data, 0);
+ /* continue to the next "case to add length */
+ /* add fixed lenth - 0 */
+ UINT16_TO_BE_STREAM(p_data, 0);
+ break;
+ }
+
+ p_pkt->len = (p_data - p_start);
+ p_cmd->cmd.opcode = opcode;
+
+ return p_pkt;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_BldCommand
+ *
+ * Description This function builds the given AVRCP command to the given
+ * GKI buffer
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) {
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ bool alloc = false;
+ AVRC_TRACE_API("AVRC_BldCommand: pdu=%x status=%x", p_cmd->cmd.pdu,
+ p_cmd->cmd.status);
+ if (!p_cmd || !pp_pkt) {
+ AVRC_TRACE_API(
+ "AVRC_BldCommand. Invalid parameters passed. p_cmd=%p, pp_pkt=%p",
+ p_cmd, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL) {
+ *pp_pkt = avrc_bld_init_cmd_buffer(p_cmd);
+ if (*pp_pkt == NULL) {
+ AVRC_TRACE_API("AVRC_BldCommand: Failed to initialize command buffer");
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ alloc = true;
+ }
+ status = AVRC_STS_NO_ERROR;
+ BT_HDR* p_pkt = *pp_pkt;
+
+ switch (p_cmd->pdu) {
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ status = avrc_bld_next_cmd(&p_cmd->continu, p_pkt);
+ break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ status = avrc_bld_next_cmd(&p_cmd->abort, p_pkt);
+ break;
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ status = avrc_bld_set_abs_volume_cmd(&p_cmd->volume, p_pkt);
+ break;
+#endif
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ status = avrc_bld_register_notifn(p_pkt, p_cmd->reg_notif.event_id,
+ p_cmd->reg_notif.param);
+#endif
+ break;
+ case AVRC_PDU_GET_CAPABILITIES:
+ status =
+ avrc_bld_get_capability_cmd(p_pkt, p_cmd->get_caps.capability_id);
+ break;
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ status = avrc_bld_list_player_app_attr_cmd(p_pkt);
+ break;
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ status = avrc_bld_list_player_app_values_cmd(
+ p_pkt, p_cmd->list_app_values.attr_id);
+ break;
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ status = avrc_bld_get_current_player_app_values_cmd(
+ p_pkt, p_cmd->get_cur_app_val.num_attr, p_cmd->get_cur_app_val.attrs);
+ break;
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ status = avrc_bld_set_current_player_app_values_cmd(
+ p_pkt, p_cmd->set_app_val.num_val, p_cmd->set_app_val.p_vals);
+ break;
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ avrc_bld_get_player_app_setting_attr_text_cmd(p_pkt,
+ &p_cmd->get_app_attr_txt);
+ break;
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ avrc_bld_get_player_app_setting_value_text_cmd(p_pkt,
+ &p_cmd->get_app_val_txt);
+ break;
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ status = avrc_bld_get_element_attr_cmd(
+ p_pkt, p_cmd->get_elem_attrs.num_attr, p_cmd->get_elem_attrs.attrs);
+ break;
+ case AVRC_PDU_PLAY_ITEM:
+ status = avrc_bld_play_item_cmd(p_pkt, p_cmd->play_item.scope,
+ p_cmd->play_item.uid,
+ p_cmd->play_item.uid_counter);
+ break;
+ case AVRC_PDU_GET_PLAY_STATUS:
+ status = avrc_bld_get_play_status_cmd(p_pkt);
+ break;
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ status = avrc_bld_get_folder_items_cmd(p_pkt, &(p_cmd->get_items));
+ break;
+ case AVRC_PDU_CHANGE_PATH:
+ status = avrc_bld_change_folder_cmd(p_pkt, &(p_cmd->chg_path));
+ break;
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ status = avrc_bld_set_browsed_player_cmd(p_pkt, &(p_cmd->br_player));
+ break;
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ status = avrc_bld_set_addressed_player_cmd(p_pkt, &(p_cmd->addr_player));
+ break;
+ }
+
+ if (alloc && (status != AVRC_STS_NO_ERROR)) {
+ osi_free(p_pkt);
+ *pp_pkt = NULL;
+ }
+ AVRC_TRACE_API("AVRC_BldCommand: returning %d", status);
+ return status;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/mtkbt/code/bt/stack/avrc/avrc_bld_tg.cc b/mtkbt/code/bt/stack/avrc/avrc_bld_tg.cc
new file mode 100755
index 0000000..f96a5d3
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_bld_tg.cc
@@ -0,0 +1,1523 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+#define AVRC_ITEM_PLAYER_IS_VALID(_p_player) \
+ ((_p_player)->name.p_str && \
+ ((_p_player)->major_type & AVRC_MJ_TYPE_INVALID) == 0 && \
+ ((_p_player)->sub_type & AVRC_SUB_TYPE_INVALID) == 0 && \
+ (((_p_player)->play_status <= AVRC_PLAYSTATE_REV_SEEK) || \
+ ((_p_player)->play_status == AVRC_PLAYSTATE_ERROR)))
+
+/* 17 = item_type(1) + item len(2) + min item (14) */
+#define AVRC_MIN_LEN_GET_FOLDER_ITEMS_RSP 17
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_capability_rsp
+ *
+ * Description This function builds the Get Capability response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_capability_rsp(tAVRC_GET_CAPS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len, *p_count;
+ uint16_t len = 0;
+ uint8_t xx;
+ uint32_t* p_company_id;
+ uint8_t* p_event_id;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) {
+ AVRC_TRACE_ERROR("%s bad parameter. p_rsp: %x", __func__, p_rsp);
+ status = AVRC_STS_BAD_PARAM;
+ return status;
+ }
+
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->capability_id);
+ p_count = p_data;
+
+ if (len == 0) {
+ *p_count = p_rsp->count;
+ p_data++;
+ len = 2; /* move past the capability_id and count */
+ } else {
+ p_data = p_start + p_pkt->len;
+ *p_count += p_rsp->count;
+ }
+
+ if (p_rsp->capability_id == AVRC_CAP_COMPANY_ID) {
+ p_company_id = p_rsp->param.company_id;
+ for (xx = 0; xx < p_rsp->count; xx++) {
+ UINT24_TO_BE_STREAM(p_data, p_company_id[xx]);
+ }
+ len += p_rsp->count * 3;
+ } else {
+ p_event_id = p_rsp->param.event_id;
+ *p_count = 0;
+ for (xx = 0; xx < p_rsp->count; xx++) {
+ if (AVRC_IS_VALID_EVENT_ID(p_event_id[xx])) {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_event_id[xx]);
+ }
+ }
+ len += (*p_count);
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ status = AVRC_STS_NO_ERROR;
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_list_app_settings_attr_rsp
+ *
+ * Description This function builds the List Application Settings Attribute
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_attr_rsp(
+ tAVRC_LIST_APP_ATTR_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len, *p_num;
+ uint16_t len = 0;
+ uint8_t xx;
+
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data;
+ if (len == 0) {
+ /* first time initialize the attribute count */
+ *p_num = 0;
+ p_data++;
+ } else {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++) {
+ if (AVRC_IsValidPlayerAttr(p_rsp->attrs[xx])) {
+ (*p_num)++;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->attrs[xx]);
+ }
+ }
+
+ len = *p_num + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_list_app_settings_values_rsp
+ *
+ * Description This function builds the List Application Setting Values
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_list_app_settings_values_rsp(
+ tAVRC_LIST_APP_VALUES_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len, *p_num;
+ uint8_t xx;
+ uint16_t len;
+
+ AVRC_TRACE_API("%s", __func__);
+
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ /* get the existing length, if any, and also the num attributes */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data;
+ /* first time initialize the attribute count */
+ if (len == 0) {
+ *p_num = p_rsp->num_val;
+ p_data++;
+ } else {
+ p_data = p_start + p_pkt->len;
+ *p_num += p_rsp->num_val;
+ }
+
+ for (xx = 0; xx < p_rsp->num_val; xx++) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->vals[xx]);
+ }
+
+ len = *p_num + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_cur_app_setting_value_rsp
+ *
+ * Description This function builds the Get Current Application Setting
+ * Value response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_cur_app_setting_value_rsp(
+ tAVRC_GET_CUR_APP_VALUE_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len, *p_count;
+ uint16_t len;
+ uint8_t xx;
+
+ if (!p_rsp->p_vals) {
+ AVRC_TRACE_ERROR("%s NULL parameter", __func__);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+ if (len == 0) {
+ /* first time initialize the attribute count */
+ *p_count = 0;
+ p_data++;
+ } else {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx = 0; xx < p_rsp->num_val; xx++) {
+ if (avrc_is_valid_player_attrib_value(p_rsp->p_vals[xx].attr_id,
+ p_rsp->p_vals[xx].attr_val)) {
+ (*p_count)++;
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_vals[xx].attr_val);
+ }
+ }
+ len = ((*p_count) << 1) + 1;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_app_setting_value_rsp
+ *
+ * Description This function builds the Set Application Setting Value
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_app_setting_value_rsp(
+ UNUSED_ATTR tAVRC_RSP* p_rsp, UNUSED_ATTR BT_HDR* p_pkt) {
+ /* nothing to be added. */
+ AVRC_TRACE_API("%s", __func__);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_app_setting_text_rsp
+ *
+ * Description This function builds the Get Application Settings Attribute
+ * Text or Get Application Settings Value Text response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_app_setting_text_rsp(
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len, *p_count;
+ uint16_t len, len_left;
+ uint8_t xx;
+ tAVRC_STS sts = AVRC_STS_NO_ERROR;
+ uint8_t num_added = 0;
+
+ if (!p_rsp->p_attrs) {
+ AVRC_TRACE_ERROR("%s NULL parameter", __func__);
+ return AVRC_STS_BAD_PARAM;
+ }
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+
+ /*
+ * NOTE: The buffer is allocated within avrc_bld_init_rsp_buffer(), and is
+ * always of size BT_DEFAULT_BUFFER_SIZE.
+ */
+ len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset - p_pkt->len;
+
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_count = p_data;
+
+ if (len == 0) {
+ *p_count = 0;
+ p_data++;
+ } else {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (xx = 0; xx < p_rsp->num_attr; xx++) {
+ if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) {
+ AVRC_TRACE_ERROR("%s out of room (str_len:%d, left:%d)", __func__, xx,
+ p_rsp->p_attrs[xx].str_len, len_left);
+ p_rsp->num_attr = num_added;
+ sts = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ if (!p_rsp->p_attrs[xx].str_len || !p_rsp->p_attrs[xx].p_str) {
+ AVRC_TRACE_ERROR("%s NULL attr text[%d]", __func__, xx);
+ continue;
+ }
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].charset_id);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->p_attrs[xx].p_str,
+ p_rsp->p_attrs[xx].str_len);
+ (*p_count)++;
+ num_added++;
+ }
+ len = p_data - p_count;
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return sts;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_app_setting_attr_text_rsp
+ *
+ * Description This function builds the Get Application Setting Attribute
+ * Text response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_attr_text_rsp(
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp, BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_app_setting_value_text_rsp
+ *
+ * Description This function builds the Get Application Setting Value Text
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_app_setting_value_text_rsp(
+ tAVRC_GET_APP_ATTR_TXT_RSP* p_rsp, BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ return avrc_bld_app_setting_text_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_inform_charset_rsp
+ *
+ * Description This function builds the Inform Displayable Character Set
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_inform_charset_rsp(UNUSED_ATTR tAVRC_RSP* p_rsp,
+ UNUSED_ATTR BT_HDR* p_pkt) {
+ /* nothing to be added. */
+ AVRC_TRACE_API("%s", __func__);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_inform_battery_status_rsp
+ *
+ * Description This function builds the Inform Battery Status
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_inform_battery_status_rsp(
+ UNUSED_ATTR tAVRC_RSP* p_rsp, UNUSED_ATTR BT_HDR* p_pkt) {
+ /* nothing to be added. */
+ AVRC_TRACE_API("%s", __func__);
+ return AVRC_STS_NO_ERROR;
+}
+
+static void avrc_build_attribute_entries(int num_attrs,
+ tAVRC_ATTR_ENTRY* p_attrs,
+ int remaining_buffer_capacity,
+ uint8_t** pp_data,
+ uint8_t* p_attribute_count) {
+ AVRC_TRACE_DEBUG("%s num_attrs: %d, remaining_buffer_capacity: %d", __func__,
+ num_attrs, remaining_buffer_capacity);
+ uint8_t* p_data = *pp_data;
+ /* Fill in the Attribute ID, Character Set, Length and Values */
+ for (int index = 0; index < num_attrs; index++) {
+ AVRC_TRACE_DEBUG("%s attr id[%d]: %d", __func__, index,
+ p_attrs[index].attr_id);
+ CHECK(AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attrs[index].attr_id));
+ if (!p_attrs[index].name.p_str) {
+ p_attrs[index].name.str_len = 0;
+ }
+ /* 8 is the size of attr_id, char set and str_len */
+ remaining_buffer_capacity -= 8;
+ if (remaining_buffer_capacity < 0) {
+ AVRC_TRACE_WARNING(
+ "%s not enough buffer space for attr_id[%d]: %d,"
+ " skipping %d attributes",
+ __func__, index, p_attrs[index].attr_id, num_attrs - index);
+ break;
+ }
+ if (remaining_buffer_capacity < p_attrs[index].name.str_len) {
+ AVRC_TRACE_WARNING(
+ "%s not enough buffer space for attr_id[%d]: %d,"
+ " truncating attribute",
+ __func__, index, p_attrs[index].attr_id);
+ p_attrs[index].name.str_len = remaining_buffer_capacity;
+ remaining_buffer_capacity = 0;
+ }
+ remaining_buffer_capacity -= p_attrs[index].name.str_len;
+ UINT32_TO_BE_STREAM(p_data, p_attrs[index].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_attrs[index].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_attrs[index].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_attrs[index].name.p_str,
+ p_attrs[index].name.str_len);
+ (*p_attribute_count)++;
+ }
+ *pp_data = p_data;
+ AVRC_TRACE_DEBUG("%s filled attributes, remaining_buffer_capacity: %d",
+ __func__, num_attrs, remaining_buffer_capacity);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_elem_attrs_rsp
+ *
+ * Description This function builds the Get Element Attributes
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_elem_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ if (!p_rsp->p_attrs) {
+ AVRC_TRACE_ERROR("%s NULL p_attrs", __func__);
+ return AVRC_STS_BAD_PARAM;
+ }
+ /* Figure out how much we have left in current buffer */
+ int remaining_buffer_capacity =
+ BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset;
+ if (remaining_buffer_capacity < 5) {
+ AVRC_TRACE_ERROR("%s not enough buffer for packet header",
+ remaining_buffer_capacity);
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ /* Get to the beginning of PDU */
+ uint8_t* p_pdu_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* Skip PDU ID and Reserved byte to get pointer to Parameter Length */
+ uint8_t *p_data, *p_parameter_len;
+ p_data = p_parameter_len = p_pdu_start + 2;
+ /* Parse parameter length */
+ uint16_t parameter_len;
+ BE_STREAM_TO_UINT16(parameter_len, p_data);
+ /* Get pointer to Attribute Count */
+ uint8_t* p_attribute_count = p_data;
+ /* Initialize field values when Parameter Length is 0 */
+ if (parameter_len == 0) {
+ *p_attribute_count = 0;
+ p_data++;
+ } else {
+ // TODO: Why do we need this case?
+ p_data = p_pdu_start + p_pkt->len;
+ }
+ remaining_buffer_capacity -= p_data - p_pdu_start;
+ ;
+ if (remaining_buffer_capacity < 0) {
+ AVRC_TRACE_ERROR("%s not enough buffer capacity for response");
+ return AVRC_STS_BAD_PARAM;
+ }
+ /* Fill in the Attribute ID, Character Set, Length and Values */
+ avrc_build_attribute_entries(p_rsp->num_attrs, p_rsp->p_attrs,
+ remaining_buffer_capacity, &p_data,
+ p_attribute_count);
+ parameter_len = p_data - p_attribute_count;
+ UINT16_TO_BE_STREAM(p_parameter_len, parameter_len);
+ p_pkt->len = (p_data - p_pdu_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_play_status_rsp
+ *
+ * Description This function builds the Get Play Status
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_play_status_rsp(tAVRC_GET_PLAY_STATUS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+
+ AVRC_TRACE_API("%s", __func__);
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 2;
+
+ /* add fixed lenth - song len(4) + song position(4) + status(1) */
+ UINT16_TO_BE_STREAM(p_data, 9);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->song_len);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->song_pos);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->play_status);
+ p_pkt->len = (p_data - p_start);
+
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_notify_rsp
+ *
+ * Description This function builds the Notification response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_notify_rsp(tAVRC_REG_NOTIF_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+ uint8_t* p_len;
+ uint16_t len = 0;
+ uint8_t xx;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ AVRC_TRACE_API("%s event_id %d", __func__, p_rsp->event_id);
+
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 2; /* pdu + rsvd */
+ p_data += 2;
+
+ UINT8_TO_BE_STREAM(p_data, p_rsp->event_id);
+ switch (p_rsp->event_id) {
+ case AVRC_EVT_PLAY_STATUS_CHANGE: /* 0x01 */
+ /* p_rsp->param.play_status >= AVRC_PLAYSTATE_STOPPED is always true */
+ if ((p_rsp->param.play_status <= AVRC_PLAYSTATE_REV_SEEK) ||
+ (p_rsp->param.play_status == AVRC_PLAYSTATE_ERROR)) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.play_status);
+ len = 2;
+ } else {
+ AVRC_TRACE_ERROR("%s bad play state", __func__);
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE: /* 0x02 */
+ ARRAY_TO_BE_STREAM(p_data, p_rsp->param.track, AVRC_UID_SIZE);
+ len = (uint8_t)(AVRC_UID_SIZE + 1);
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END: /* 0x03 */
+ case AVRC_EVT_TRACK_REACHED_START: /* 0x04 */
+ case AVRC_EVT_NOW_PLAYING_CHANGE: /* 0x09 */
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE: /* 0x0a */
+ len = 1;
+ break;
+
+ case AVRC_EVT_PLAY_POS_CHANGED: /* 0x05 */
+ UINT32_TO_BE_STREAM(p_data, p_rsp->param.play_pos);
+ len = 5;
+ break;
+
+ case AVRC_EVT_BATTERY_STATUS_CHANGE: /* 0x06 */
+ if (AVRC_IS_VALID_BATTERY_STATUS(p_rsp->param.battery_status)) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.battery_status);
+ len = 2;
+ } else {
+ AVRC_TRACE_ERROR("%s bad battery status", __func__);
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE: /* 0x07 */
+ if (AVRC_IS_VALID_SYSTEM_STATUS(p_rsp->param.system_status)) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.system_status);
+ len = 2;
+ } else {
+ AVRC_TRACE_ERROR("%s bad system status", __func__);
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE: /* 0x08 */
+ if (p_rsp->param.player_setting.num_attr > AVRC_MAX_APP_SETTINGS)
+ p_rsp->param.player_setting.num_attr = AVRC_MAX_APP_SETTINGS;
+
+ if (p_rsp->param.player_setting.num_attr > 0) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.num_attr);
+ len = 2;
+ for (xx = 0; xx < p_rsp->param.player_setting.num_attr; xx++) {
+ if (avrc_is_valid_player_attrib_value(
+ p_rsp->param.player_setting.attr_id[xx],
+ p_rsp->param.player_setting.attr_value[xx])) {
+ UINT8_TO_BE_STREAM(p_data, p_rsp->param.player_setting.attr_id[xx]);
+ UINT8_TO_BE_STREAM(p_data,
+ p_rsp->param.player_setting.attr_value[xx]);
+ } else {
+ AVRC_TRACE_ERROR("%s bad player app seeting attribute or value",
+ __func__);
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ len += 2;
+ }
+ } else
+ status = AVRC_STS_BAD_PARAM;
+ break;
+
+ case AVRC_EVT_VOLUME_CHANGE: /* 0x0d */
+ len = 2;
+ UINT8_TO_BE_STREAM(p_data, (AVRC_MAX_VOLUME & p_rsp->param.volume));
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE: /* 0x0b */
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.player_id);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.addr_player.uid_counter);
+ len = 5;
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE: /* 0x0c */
+ UINT16_TO_BE_STREAM(p_data, p_rsp->param.uid_counter); /* uid counter */
+ len = 3;
+ break;
+
+ default:
+ status = AVRC_STS_BAD_PARAM;
+ AVRC_TRACE_ERROR("%s unknown event_id", __func__);
+ }
+
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_next_rsp
+ *
+ * Description This function builds the Request Continue or Abort
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_next_rsp(tAVRC_NEXT_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data = (p_start + 2); /* Skip the pdu and reserved bits */
+
+ UINT16_TO_BE_STREAM(p_data, 0x0001); /* only one attribute to be sent */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->target_pdu);
+
+ AVRC_TRACE_API("%s: target_pdu: 0x%02x", __func__, p_rsp->target_pdu);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+ *
+ * Function avrc_bld_set_absolute_volume_rsp
+ *
+ * Description This function builds the set absolute volume response
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is build successfully
+ *
+ *****************************************************************************/
+static tAVRC_STS avrc_bld_set_absolute_volume_rsp(uint8_t abs_vol,
+ BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* To calculate length */
+ uint8_t* p_data = p_start + 2;
+ /* add fixed lenth status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, abs_vol);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_group_navigation_rsp
+ *
+ * Description This function builds the Group Navigation
+ * response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+tAVRC_STS avrc_bld_group_navigation_rsp(uint16_t navi_id, BT_HDR* p_pkt) {
+ if (!AVRC_IS_VALID_GROUP(navi_id)) {
+ AVRC_TRACE_ERROR("%s bad navigation op id: %d", __func__, navi_id);
+ return AVRC_STS_BAD_PARAM;
+ }
+ AVRC_TRACE_API("%s", __func__);
+ uint8_t* p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ UINT16_TO_BE_STREAM(p_data, navi_id);
+ p_pkt->len = 2;
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_rejected_rsp
+ *
+ * Description This function builds the General Response response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_rejected_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ uint8_t* p_data;
+ uint8_t opcode = p_rsp->opcode;
+
+ AVRC_TRACE_API("%s: status=%d, pdu:x%x, opcode=%x", __func__, p_rsp->status,
+ p_rsp->pdu, opcode);
+
+ if (opcode == AVRC_OP_BROWSE) {
+ p_data = p_start + 1;
+ if ((AVRC_PDU_INVALID == *p_start) ||
+ (avrc_opcode_from_pdu(*p_start) != AVRC_OP_BROWSE)) {
+ /* if invalid or the given opcode is not recognized as a browsing command
+ * opcode, */
+ /* use general reject command */
+ *p_start = AVRC_PDU_GENERAL_REJECT;
+ }
+ } else {
+ p_data = p_start + 2;
+ }
+ AVRC_TRACE_DEBUG("%s pdu:x%x, Opcode:%x", __func__, *p_start, opcode);
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = p_data - p_start;
+ return AVRC_STS_NO_ERROR;
+}
+
+/*****************************************************************************
+ * the following commands are introduced in AVRCP 1.4
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_ctrl_status_rsp
+ *
+ * Description This function builds the responses with a uint8_t parameter.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_ctrl_status_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t* p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ AVRC_TRACE_DEBUG("pdu:x%x", *p_start);
+
+ /* To calculate length */
+ uint8_t* p_data = p_start + 2; /* pdu + rsvd */
+
+ /* add fixed lenth - status(1) */
+ UINT16_TO_BE_STREAM(p_data, 1);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_addr_player_rsp
+ *
+ * Description This function builds the Set Addresses Player response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_addr_player_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_set_browsed_player_rsp
+ *
+ * Description This function builds the Set Browsed Player response.
+ *
+ * This message goes through the Browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_set_browsed_player_rsp(tAVRC_SET_BR_PLAYER_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+ uint8_t* p_len;
+ uint16_t len;
+ tAVRC_NAME* p_folders = p_rsp->p_folders;
+ uint16_t len_left;
+ uint8_t* p_folder_depth;
+ uint16_t mtu;
+
+ /* make sure the given buffer can accomodate this response */
+ len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+ p_data = (uint8_t*)(p_pkt + 1);
+ BE_STREAM_TO_UINT16(mtu, p_data);
+ if (len_left > mtu) {
+ len_left = mtu;
+ }
+ len_left = len_left - p_pkt->offset - p_pkt->len;
+ AVRC_TRACE_DEBUG("len_left:%d, mtu:%d ", len_left, mtu);
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* the existing len */
+ BE_STREAM_TO_UINT16(len, p_data);
+ /* find the position to add the folder depth.
+ * 9 is sizeof (status + uid_counter + num_items + charset_id) */
+ p_folder_depth = p_data + 9;
+ if (len == 0) {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->charset_id);
+ *p_folder_depth = 0;
+ p_data++;
+ len = 10;
+ /* assuming that we would never use a buffer that is too small for headers
+ */
+ len_left -= 12;
+ } else {
+ p_data = p_start + p_pkt->len;
+ }
+
+ for (uint8_t xx = 0;
+ (xx < p_rsp->folder_depth) && (len_left > (p_folders[xx].str_len + 2));
+ xx++) {
+ (*p_folder_depth)++;
+ UINT16_TO_BE_STREAM(p_data, p_folders[xx].str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_folders[xx].p_str, p_folders[xx].str_len);
+ len += (p_folders[xx].str_len + 2);
+ }
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_folder_items_rsp
+ *
+ * Description This function builds the Get Folder Items response.
+ * The error code is returned in *p_status.
+ * AVRC_STS_INTERNAL_ERR means no buffers.
+ * Try again later or with smaller item_count
+ *
+ * This message goes through the Browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * AVRC_STS_INTERNAL_ERR, if the given buffer does not have
+ * enough room
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_folder_items_rsp(tAVRC_GET_ITEMS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+ uint8_t *p_len, xx;
+ uint16_t len;
+ uint16_t item_len;
+ uint8_t *p_item_len, yy;
+ tAVRC_ITEM_PLAYER* p_player;
+ tAVRC_ITEM_FOLDER* p_folder;
+ tAVRC_ITEM_MEDIA* p_media;
+ tAVRC_ATTR_ENTRY* p_attr;
+ tAVRC_ITEM* p_item_list = p_rsp->p_item_list;
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint16_t len_left;
+ uint8_t *p_num, *p;
+ uint8_t *p_item_start, *p_attr_count;
+ uint16_t item_count;
+ uint16_t mtu;
+ bool multi_items_add_fail = false;
+ AVRC_TRACE_API("%s", __func__);
+
+ /* make sure the given buffer can accomodate this response */
+ len_left = BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE;
+ p = (uint8_t*)(p_pkt + 1);
+ BE_STREAM_TO_UINT16(mtu, p);
+ if (len_left > mtu) len_left = mtu;
+ len_left = len_left - p_pkt->offset - p_pkt->len;
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* the existing len */
+ BE_STREAM_TO_UINT16(len, p_data);
+ p_num = p_data + 3;
+ if (len == 0) {
+ /* first time initialize the attribute count */
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ item_count = 0;
+ p_data += 2;
+ len = 5;
+ len_left -= 5;
+ } else {
+ p_data = p_start + p_pkt->len;
+ p = p_num;
+ BE_STREAM_TO_UINT16(item_count, p);
+ }
+ AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d", len, len_left, item_count);
+
+ /* min len required = item_type(1) + item len(2) + min item (14) = 17 */
+ for (xx = 0;
+ xx < p_rsp->item_count && len_left > AVRC_MIN_LEN_GET_FOLDER_ITEMS_RSP &&
+ multi_items_add_fail == false;
+ xx++) {
+ p_item_start = p_data;
+ UINT8_TO_BE_STREAM(p_data, p_item_list[xx].item_type);
+ /* variable item lenth - save the location to add length */
+ p_item_len = p_data;
+ p_data += 2;
+ item_len = 0;
+ len_left -= 3; /* item_type(1) + item len(2) */
+ switch (p_item_list[xx].item_type) {
+ case AVRC_ITEM_PLAYER:
+ /* min len required: 2 + 1 + 4 + 1 + 16 + 2 + 2 = 30 + str_len */
+ p_player = &p_item_list[xx].u.player;
+ item_len = AVRC_FEATURE_MASK_SIZE + p_player->name.str_len + 12;
+
+ if ((len_left <= item_len) ||
+ AVRC_ITEM_PLAYER_IS_VALID(p_player) == false) {
+ p_data = p_item_start;
+ } else {
+ UINT16_TO_BE_STREAM(p_data, p_player->player_id);
+ UINT8_TO_BE_STREAM(p_data, p_player->major_type);
+ UINT32_TO_BE_STREAM(p_data, p_player->sub_type);
+ UINT8_TO_BE_STREAM(p_data, p_player->play_status);
+ ARRAY_TO_BE_STREAM(p_data, p_player->features,
+ AVRC_FEATURE_MASK_SIZE);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_player->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_player->name.p_str,
+ p_player->name.str_len);
+ }
+ break;
+
+ case AVRC_ITEM_FOLDER:
+ /* min len required: 8 + 1 + 1 + 2 + 2 = 14 + str_len */
+ p_folder = &p_item_list[xx].u.folder;
+ item_len = AVRC_UID_SIZE + p_folder->name.str_len + 6;
+
+ if ((len_left > item_len) && p_folder->name.p_str &&
+ p_folder->type <= AVRC_FOLDER_TYPE_YEARS) {
+ ARRAY_TO_BE_STREAM(p_data, p_folder->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_folder->type);
+ UINT8_TO_BE_STREAM(p_data, p_folder->playable);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_folder->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_folder->name.p_str,
+ p_folder->name.str_len);
+ } else {
+ p_data = p_item_start;
+ }
+ break;
+
+ case AVRC_ITEM_MEDIA:
+ /* min len required: 8 + 1 + 2 + 2 + 1 = 14 + str_len */
+ p_media = &p_item_list[xx].u.media;
+ item_len = AVRC_UID_SIZE + p_media->name.str_len + 6;
+
+ if ((len_left >= item_len) && p_media->name.p_str &&
+ p_media->type <= AVRC_MEDIA_TYPE_VIDEO) {
+ ARRAY_TO_BE_STREAM(p_data, p_media->uid, AVRC_UID_SIZE);
+ UINT8_TO_BE_STREAM(p_data, p_media->type);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_media->name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_media->name.p_str,
+ p_media->name.str_len);
+ p_attr_count = p_data++;
+ *p_attr_count = 0;
+ len_left -= item_len;
+ if (p_media->attr_count > 0) {
+ p_attr = p_media->p_attr_list;
+ for (yy = 0; yy < p_media->attr_count; yy++) {
+ if (p_attr[yy].name.p_str &&
+ AVRC_IS_VALID_MEDIA_ATTRIBUTE(p_attr[yy].attr_id) &&
+ (len_left >= (p_attr[yy].name.str_len + 8))) {
+ (*p_attr_count)++;
+ UINT32_TO_BE_STREAM(p_data, p_attr[yy].attr_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.charset_id);
+ UINT16_TO_BE_STREAM(p_data, p_attr[yy].name.str_len);
+ ARRAY_TO_BE_STREAM(p_data, p_attr[yy].name.p_str,
+ p_attr[yy].name.str_len);
+ item_len += (p_attr[yy].name.str_len + 8);
+ len_left -= (p_attr[yy].name.str_len + 8);
+ } else if ((len_left < (p_attr[yy].name.str_len + 8)) &&
+ item_count > 0) {
+ p_data = p_item_start;
+ multi_items_add_fail = TRUE;
+ break;
+ }
+ }
+ }
+ } else {
+ if (len_left < item_len && item_count > 0)
+ multi_items_add_fail = TRUE;
+ p_data = p_item_start;
+ }
+ break;
+ } /* switch item_type */
+
+ if (p_item_start != p_data) {
+ /* successfully added the item */
+ item_count++;
+ /* fill in variable item lenth */
+ UINT16_TO_BE_STREAM(p_item_len, item_len);
+ } else {
+ if (multi_items_add_fail == false) {
+ /* some item is not added properly - set an error status */
+ if (len_left < item_len)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ status = AVRC_STS_BAD_PARAM;
+ }
+ }
+ if (multi_items_add_fail == false) {
+ len += item_len;
+ len += 3; /* the item_type(1) and item_len(2) */
+ }
+ AVRC_TRACE_DEBUG("len:%d, len_left:%d, num:%d, item_len:%d", len, len_left,
+ item_count, item_len);
+ } /* for item_count */
+
+ UINT16_TO_BE_STREAM(p_num, item_count);
+ UINT16_TO_BE_STREAM(p_len, len);
+ p_pkt->len = (p_data - p_start);
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_change_path_rsp
+ *
+ * Description This function builds the Change Path response.
+ *
+ * This message goes through the Browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_change_path_rsp(tAVRC_CHG_PATH_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start;
+
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_start + 1; /* pdu */
+ /* add fixed length - status(1) + num_items(4) */
+ UINT16_TO_BE_STREAM(p_data, 5);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_attrs_rsp
+ *
+ * Description This function builds the GetItemAttributes response,
+ *
+ * The Get Item Attributes message goes through the
+ * Browsing channel (already specified in the |p_pkt|)
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * AVRC_STS_INTERNAL_ERR, if the given buffer does not have
+ * enough room
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_item_attrs_rsp(tAVRC_GET_ATTRS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ if (!p_rsp->p_attrs) {
+ AVRC_TRACE_ERROR("%s NULL p_attrs", __func__);
+ return AVRC_STS_BAD_PARAM;
+ }
+ /* Figure out how much we have left in current buffer */
+ int remaining_buffer_capacity =
+ BT_DEFAULT_BUFFER_SIZE - BT_HDR_SIZE - p_pkt->offset;
+ /* Get to the beginning of data section in buffer */
+ uint8_t* p_data = (uint8_t*)(p_pkt + 1);
+ /* Get the MTU size that is filled in earlier */
+ uint16_t mtu;
+ BE_STREAM_TO_UINT16(mtu, p_data);
+ if (remaining_buffer_capacity > mtu) {
+ remaining_buffer_capacity = mtu;
+ }
+ AVRC_TRACE_DEBUG("%s: remaining_buffer_capacity:%d, mtu:%d", __func__,
+ remaining_buffer_capacity, mtu);
+ if (remaining_buffer_capacity < 5) {
+ AVRC_TRACE_ERROR("%s: not enough space for packet header, remaining:%d < 5",
+ __func__, remaining_buffer_capacity);
+ return AVRC_STS_INTERNAL_ERR;
+ }
+ /* Get to the beginning of PDU */
+ uint8_t* p_pdu_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ /* Skip PDU ID to get pointer to Parameter length */
+ uint8_t* p_parameter_len;
+ p_data = p_parameter_len = p_pdu_start + 1;
+ /* Parse existing parameter length */
+ uint16_t parameter_len;
+ BE_STREAM_TO_UINT16(parameter_len, p_data);
+ /* Skip one byte to Number of Attributes */
+ uint8_t* p_status = p_data++;
+ uint8_t* p_attribute_count = p_data++;
+ if (parameter_len == 0) {
+ /* First time, initialize the status byte */
+ *p_status = p_rsp->status;
+ if (p_rsp->status != AVRC_STS_NO_ERROR) {
+ // TODO(siyuanh): This is a hack
+ parameter_len = 1;
+ UINT16_TO_BE_STREAM(p_parameter_len, parameter_len);
+ p_pkt->len = p_status - p_pdu_start;
+ return AVRC_STS_NO_ERROR;
+ }
+ *p_attribute_count = 0;
+ } else {
+ // TODO(siyuanh): Why do wee need this case?
+ p_data = p_pdu_start + p_pkt->len;
+ }
+ remaining_buffer_capacity -= p_data - p_pdu_start;
+ /* Fill in the Attribute ID, Character Set, Length and Values */
+ avrc_build_attribute_entries(p_rsp->num_attrs, p_rsp->p_attrs,
+ remaining_buffer_capacity, &p_data,
+ p_attribute_count);
+ parameter_len = p_data - p_status;
+ UINT16_TO_BE_STREAM(p_parameter_len, parameter_len);
+ p_pkt->len = p_data - p_pdu_start;
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_get_num_of_item_rsp
+ *
+ * Description This function builds the Get Total Number of Items response.
+ *
+ * This message goes through the Browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * AVRC_STS_INTERNAL_ERR, if the given buffer does not have
+ * enough room
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_get_num_of_item_rsp(tAVRC_GET_NUM_OF_ITEMS_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len;
+
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ if (p_rsp->status == AVRC_STS_NO_ERROR) {
+ /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+ UINT16_TO_BE_STREAM(p_data, 7);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+ } else {
+ /* add fixed lenth - status(1) */
+ UINT16_TO_BE_STREAM(p_data, 7);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ p_pkt->len = (p_data - p_start);
+ return p_rsp->status;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_search_rsp
+ *
+ * Description This function builds the Search response.
+ *
+ * This message goes through the Browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_search_rsp(tAVRC_SEARCH_RSP* p_rsp, BT_HDR* p_pkt) {
+ uint8_t *p_data, *p_start, *p_len;
+
+ AVRC_TRACE_API("%s", __func__);
+ /* get the existing length, if any, and also the num attributes */
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_data = p_len = p_start + 1; /* pdu */
+
+ /* add fixed lenth - status(1) + uid_counter(2) + num_items(4) */
+ UINT16_TO_BE_STREAM(p_data, 7);
+ UINT8_TO_BE_STREAM(p_data, p_rsp->status);
+ UINT16_TO_BE_STREAM(p_data, p_rsp->uid_counter);
+ UINT32_TO_BE_STREAM(p_data, p_rsp->num_items);
+ p_pkt->len = (p_data - p_start);
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_play_item_rsp
+ *
+ * Description This function builds the Play Item response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_play_item_rsp(tAVRC_RSP* p_rsp, BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_add_to_now_playing_rsp
+ *
+ * Description This function builds the Add to Now Playing response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_bld_add_to_now_playing_rsp(tAVRC_RSP* p_rsp,
+ BT_HDR* p_pkt) {
+ AVRC_TRACE_API("%s", __func__);
+ return avrc_bld_ctrl_status_rsp(p_rsp, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_bld_init_rsp_buffer
+ *
+ * Description This function initializes the response buffer based on PDU
+ *
+ * Returns NULL, if no buffer or failure to build the message.
+ * Otherwise, the buffer that contains the initialized message.
+ *
+ ******************************************************************************/
+static BT_HDR* avrc_bld_init_rsp_buffer(tAVRC_RESPONSE* p_rsp) {
+ uint16_t offset = 0;
+ uint16_t chnl = AVCT_DATA_CTRL;
+ uint8_t opcode = avrc_opcode_from_pdu(p_rsp->pdu);
+
+ AVRC_TRACE_API("%s: pdu=%x, opcode=%x/%x", __func__, p_rsp->pdu, opcode,
+ p_rsp->rsp.opcode);
+ if (opcode != p_rsp->rsp.opcode && p_rsp->rsp.status != AVRC_STS_NO_ERROR &&
+ avrc_is_valid_opcode(p_rsp->rsp.opcode)) {
+ opcode = p_rsp->rsp.opcode;
+ AVRC_TRACE_API("%s opcode=%x", __func__, opcode);
+ }
+
+ switch (opcode) {
+ case AVRC_OP_BROWSE:
+ chnl = AVCT_DATA_BROWSE;
+ offset = AVCT_BROWSE_OFFSET;
+ break;
+
+ case AVRC_OP_PASS_THRU:
+ offset = AVRC_MSG_PASS_THRU_OFFSET;
+ break;
+
+ case AVRC_OP_VENDOR:
+ offset = AVRC_MSG_VENDOR_OFFSET;
+ break;
+ }
+
+ /* allocate and initialize the buffer */
+ BT_HDR* p_pkt = (BT_HDR*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
+ uint8_t *p_data, *p_start;
+
+ p_pkt->layer_specific = chnl;
+ p_pkt->event = opcode;
+ p_pkt->offset = offset;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ p_start = p_data;
+
+ /* pass thru - group navigation - has a two byte op_id, so dont do it here */
+ if (opcode != AVRC_OP_PASS_THRU) *p_data++ = p_rsp->pdu;
+
+ switch (opcode) {
+ case AVRC_OP_VENDOR:
+ /* reserved 0, packet_type 0 */
+ UINT8_TO_BE_STREAM(p_data, 0);
+ /* continue to the next "case to add length */
+
+ case AVRC_OP_BROWSE:
+ /* add fixed lenth - 0 */
+ UINT16_TO_BE_STREAM(p_data, 0);
+ break;
+ }
+
+ p_pkt->len = (p_data - p_start);
+ p_rsp->rsp.opcode = opcode;
+
+ return p_pkt;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_BldResponse
+ *
+ * Description This function builds the given AVRCP response to the given
+ * buffer
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp,
+ BT_HDR** pp_pkt) {
+ tAVRC_STS status = AVRC_STS_BAD_PARAM;
+ BT_HDR* p_pkt;
+ bool alloc = false;
+ uint8_t* p;
+ uint16_t peer_mtu;
+
+ if (!p_rsp || !pp_pkt) {
+ AVRC_TRACE_API("%s Invalid parameters passed. p_rsp=%p, pp_pkt=%p",
+ __func__, p_rsp, pp_pkt);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ if (*pp_pkt == NULL) {
+ *pp_pkt = avrc_bld_init_rsp_buffer(p_rsp);
+ if (*pp_pkt == NULL) {
+ AVRC_TRACE_API("%s Failed to initialize response buffer", __func__);
+ return AVRC_STS_INTERNAL_ERR;
+ }
+
+ if ((*pp_pkt)->layer_specific == AVCT_DATA_BROWSE) {
+ p = (uint8_t*)((*pp_pkt) + 1);
+ peer_mtu = AVCT_GetBrowseMtu(handle) - AVCT_HDR_LEN_SINGLE;
+ UINT16_TO_BE_STREAM(p, peer_mtu);
+ }
+
+ alloc = true;
+ }
+ status = AVRC_STS_NO_ERROR;
+ p_pkt = *pp_pkt;
+
+ AVRC_TRACE_API("%s pdu=%x status=%x", __func__, p_rsp->rsp.pdu,
+ p_rsp->rsp.status);
+ if (p_rsp->rsp.status != AVRC_STS_NO_ERROR) {
+ return (avrc_bld_rejected_rsp(&p_rsp->rsp, p_pkt));
+ }
+
+ switch (p_rsp->pdu) {
+ case AVRC_PDU_NEXT_GROUP:
+ case AVRC_PDU_PREV_GROUP:
+ status = avrc_bld_group_navigation_rsp(p_rsp->pdu, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ status = avrc_bld_get_capability_rsp(&p_rsp->get_caps, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ status =
+ avrc_bld_list_app_settings_attr_rsp(&p_rsp->list_app_attr, p_pkt);
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ status =
+ avrc_bld_list_app_settings_values_rsp(&p_rsp->list_app_values, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE:
+ status = avrc_bld_get_cur_app_setting_value_rsp(&p_rsp->get_cur_app_val,
+ p_pkt);
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ status = avrc_bld_set_app_setting_value_rsp(&p_rsp->set_app_val, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT:
+ status = avrc_bld_get_app_setting_attr_text_rsp(&p_rsp->get_app_attr_txt,
+ p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT:
+ status = avrc_bld_get_app_setting_value_text_rsp(&p_rsp->get_app_val_txt,
+ p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET:
+ status = avrc_bld_inform_charset_rsp(&p_rsp->inform_charset, p_pkt);
+ break;
+
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT:
+ status = avrc_bld_inform_battery_status_rsp(&p_rsp->inform_battery_status,
+ p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR:
+ status = avrc_bld_get_elem_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ status = avrc_bld_get_play_status_rsp(&p_rsp->get_play_status, p_pkt);
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ status = avrc_bld_notify_rsp(&p_rsp->reg_notif, p_pkt);
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP:
+ status = avrc_bld_next_rsp(&p_rsp->continu, p_pkt);
+ break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP:
+ status = avrc_bld_next_rsp(&p_rsp->abort, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ status = avrc_bld_set_addr_player_rsp(&p_rsp->addr_player, p_pkt);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM:
+ status = avrc_bld_play_item_rsp(&p_rsp->play_item, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME:
+ status = avrc_bld_set_absolute_volume_rsp(p_rsp->volume.volume, p_pkt);
+ break;
+
+ case AVRC_PDU_ADD_TO_NOW_PLAYING:
+ status = avrc_bld_add_to_now_playing_rsp(&p_rsp->add_to_play, p_pkt);
+ break;
+
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ status = avrc_bld_set_browsed_player_rsp(&p_rsp->br_player, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ status = avrc_bld_get_folder_items_rsp(&p_rsp->get_items, p_pkt);
+ break;
+
+ case AVRC_PDU_CHANGE_PATH:
+ status = avrc_bld_change_path_rsp(&p_rsp->chg_path, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ status = avrc_bld_get_item_attrs_rsp(&p_rsp->get_attrs, p_pkt);
+ break;
+
+ case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+ status = avrc_bld_get_num_of_item_rsp(&p_rsp->get_num_of_items, p_pkt);
+ break;
+
+ case AVRC_PDU_SEARCH:
+ status = avrc_bld_search_rsp(&p_rsp->search, p_pkt);
+ break;
+ }
+
+ if (alloc && (status != AVRC_STS_NO_ERROR)) {
+ osi_free(p_pkt);
+ *pp_pkt = NULL;
+ }
+ AVRC_TRACE_API("%s returning %d", __func__, status);
+ return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == true)*/
diff --git a/mtkbt/code/bt/stack/avrc/avrc_int.h b/mtkbt/code/bt/stack/avrc/avrc_int.h
new file mode 100755
index 0000000..d6c79c8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_int.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * VRCP internal header file.
+ *
+ ******************************************************************************/
+
+#ifndef AVRC_INT_H
+#define AVRC_INT_H
+
+#include "avct_defs.h"
+#include "avrc_api.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+
+/* DEBUG FLAGS
+ *
+ * #define META_DEBUG_ENABLED
+ */
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Number of attributes in AVRC SDP record. */
+#define AVRC_NUM_ATTR 6
+
+/* Number of protocol elements in protocol element list. */
+#define AVRC_NUM_PROTO_ELEMS 2
+
+#ifndef AVRC_MIN_CMD_LEN
+#define AVRC_MIN_CMD_LEN 20
+#endif
+
+#define AVRC_UNIT_OPRND_BYTES 5
+#define AVRC_SUB_OPRND_BYTES 4
+#define AVRC_SUBRSP_OPRND_BYTES 3
+#define AVRC_SUB_PAGE_MASK 7
+#define AVRC_SUB_PAGE_SHIFT 4
+#define AVRC_SUB_EXT_CODE 7
+#define AVRC_PASS_OP_ID_MASK 0x7F
+#define AVRC_PASS_STATE_MASK 0x80
+#define AVRC_CMD_OPRND_PAD 0xFF
+
+#define AVRC_CTYPE_MASK 0x0F
+#define AVRC_SUBTYPE_MASK 0xF8
+#define AVRC_SUBTYPE_SHIFT 3
+#define AVRC_SUBID_MASK 0x07
+#define AVRC_SUBID_IGNORE 0x07
+
+#define AVRC_SINGLE_PARAM_SIZE 1
+#define AVRC_METADATA_PKT_TYPE_MASK 0x03
+#define AVRC_PASS_THOUGH_MSG_MASK \
+ 0x80 /* MSB of msg_type indicates the PAS THROUGH msg */
+#define AVRC_VENDOR_UNIQUE_MASK 0x70 /* vendor unique id */
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) \
+ { \
+ *(p)++ = (uint8_t)((u32) >> 16); \
+ *(p)++ = (uint8_t)((u32) >> 8); \
+ *(p)++ = (uint8_t)(u32); \
+ }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + \
+ (((uint32_t)(*(p))) << 16)); \
+ (p) += 3; \
+ }
+
+#define AVRC_AVC_HDR_SIZE 3 /* ctype, subunit*, opcode */
+
+#define AVRC_MIN_META_HDR_SIZE 4 /* pdu id(1), packet type(1), param len(2) */
+#define AVRC_MIN_BROWSE_HDR_SIZE 3 /* pdu id(1), param len(2) */
+
+#define AVRC_VENDOR_HDR_SIZE 6 /* ctype, subunit*, opcode, CO_ID */
+#define AVRC_MSG_VENDOR_OFFSET 23
+#define AVRC_MIN_VENDOR_SIZE \
+ (AVRC_MSG_VENDOR_OFFSET + BT_HDR_SIZE + AVRC_MIN_META_HDR_SIZE)
+
+#define AVRC_PASS_THRU_SIZE 8
+#define AVRC_MSG_PASS_THRU_OFFSET 25
+#define AVRC_MIN_PASS_THRU_SIZE (AVRC_MSG_PASS_THRU_OFFSET + BT_HDR_SIZE + 4)
+
+#define AVRC_MIN_BROWSE_SIZE \
+ (AVCT_BROWSE_OFFSET + BT_HDR_SIZE + AVRC_MIN_BROWSE_HDR_SIZE)
+
+#define AVRC_CTRL_PKT_LEN(pf, pk) \
+ { (pf) = (uint8_t*)((pk) + 1) + (pk)->offset + 2; }
+
+#define AVRC_MAX_CTRL_DATA_LEN (AVRC_PACKET_LEN)
+
+/* Timeout for waiting for avrc command responses (in milliseconds) */
+#ifndef AVRC_CMD_TOUT_MS
+#define AVRC_CMD_TOUT_MS (2 * 1000)
+#endif
+
+/* Flags for avrc_cb.ccb_int[].flags */
+#define AVRC_CB_FLAGS_RSP_PENDING 0x01 /* Waiting for AVRC response */
+
+/*****************************************************************************
+ * Type definitions
+ ****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+/* type for Metadata fragmentation control block */
+typedef struct {
+ BT_HDR* p_fmsg; /* the fragmented message */
+ uint8_t frag_pdu; /* the PDU ID for fragmentation */
+ bool frag_enabled; /* fragmentation flag */
+} tAVRC_FRAG_CB;
+
+/* type for Metadata re-assembly control block */
+typedef struct {
+ BT_HDR* p_rmsg; /* the received message */
+ uint16_t rasm_offset; /* re-assembly flag, the offset of the start fragment */
+ uint8_t rasm_pdu; /* the PDU ID for re-assembly */
+} tAVRC_RASM_CB;
+#endif
+
+/* AVRC internal connection control block */
+typedef struct {
+ fixed_queue_t*
+ cmd_q; /* Command queue for serializing vendor specific commands */
+ uint8_t flags; /* See AVRC_CB_FLAGS_* definitions */
+ alarm_t* tle; /* Command timeout timer */
+} tAVRC_CONN_INT_CB;
+
+typedef struct {
+ tAVRC_CONN_CB
+ ccb[AVCT_NUM_CONN]; /* Connection control block from AVRC_Open API */
+ tAVRC_CONN_INT_CB
+ ccb_int[AVCT_NUM_CONN]; /* Internal connection control block */
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ tAVRC_FRAG_CB fcb[AVCT_NUM_CONN];
+ tAVRC_RASM_CB rcb[AVCT_NUM_CONN];
+#endif
+ tAVRC_FIND_CBACK* p_cback; /* pointer to application callback */
+ tSDP_DISCOVERY_DB* p_db; /* pointer to discovery database */
+ uint16_t service_uuid; /* service UUID to search */
+ uint8_t trace_level;
+} tAVRC_CB;
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+extern tAVRC_CB avrc_cb;
+
+extern bool avrc_is_valid_pdu_id(uint8_t pdu_id);
+extern bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value);
+extern BT_HDR* avrc_alloc_ctrl_pkt(uint8_t pdu);
+extern tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS* p_msg,
+ uint16_t* p_vendor_unique_id);
+extern uint8_t avrc_opcode_from_pdu(uint8_t pdu);
+extern bool avrc_is_valid_opcode(uint8_t opcode);
+extern void avrc_flush_cmd_q(uint8_t handle);
+void avrc_start_cmd_timer(uint8_t handle, uint8_t label, uint8_t msg_mask);
+void avrc_send_next_vendor_cmd(uint8_t handle);
+
+#endif /* AVRC_INT_H */
diff --git a/mtkbt/code/bt/stack/avrc/avrc_opt.cc b/mtkbt/code/bt/stack/avrc/avrc_opt.cc
new file mode 100755
index 0000000..1c0acb8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_opt.cc
@@ -0,0 +1,226 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Interface to AVRCP optional commands
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+
+/******************************************************************************
+ *
+ * Function avrc_vendor_msg
+ *
+ * Description Compose a VENDOR DEPENDENT command according to p_msg
+ *
+ * Input Parameters:
+ * p_msg: Pointer to VENDOR DEPENDENT message structure.
+ *
+ * Output Parameters:
+* None.
+ *
+ * Returns pointer to a valid GKI buffer if successful.
+ * NULL if p_msg is NULL.
+ *
+ *****************************************************************************/
+static BT_HDR* avrc_vendor_msg(tAVRC_MSG_VENDOR* p_msg) {
+ BT_HDR* p_cmd;
+ uint8_t* p_data;
+
+ CHECK(p_msg != NULL);
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+ CHECK(AVRC_META_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
+ p_cmd = (BT_HDR*)osi_malloc(AVRC_META_CMD_BUF_SIZE);
+#else
+ CHECK(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN + p_msg->vendor_len));
+ p_cmd = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
+#endif
+
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK);
+ *p_data++ =
+ (p_msg->hdr.subunit_type << AVRC_SUBTYPE_SHIFT) | p_msg->hdr.subunit_id;
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, p_msg->company_id);
+ if (p_msg->vendor_len && p_msg->p_vendor_data)
+ memcpy(p_data, p_msg->p_vendor_data, p_msg->vendor_len);
+ p_cmd->len = (uint16_t)(p_data + p_msg->vendor_len - (uint8_t*)(p_cmd + 1) -
+ p_cmd->offset);
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+ return p_cmd;
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_UnitCmd
+ *
+ * Description Send a UNIT INFO command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_UnitCmd(uint8_t handle, uint8_t label) {
+ BT_HDR* p_cmd = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
+ uint8_t* p_data;
+
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_UNIT_INFO;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_UNIT_OPRND_BYTES);
+ p_cmd->len =
+ p_data + AVRC_UNIT_OPRND_BYTES - (uint8_t*)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+ return AVCT_MsgReq(handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_SubCmd
+ *
+ * Description Send a SUBUNIT INFO command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * page: Specifies which part of the subunit type table
+ * is requested. For AVRCP it is typically zero.
+ * Value range is 0-7.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_SubCmd(uint8_t handle, uint8_t label, uint8_t page) {
+ BT_HDR* p_cmd = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
+ uint8_t* p_data;
+
+ p_cmd->offset = AVCT_MSG_OFFSET;
+ p_data = (uint8_t*)(p_cmd + 1) + p_cmd->offset;
+ *p_data++ = AVRC_CMD_STATUS;
+ /* unit & id ignore */
+ *p_data++ = (AVRC_SUB_UNIT << AVRC_SUBTYPE_SHIFT) | AVRC_SUBID_IGNORE;
+ *p_data++ = AVRC_OP_SUB_INFO;
+ *p_data++ =
+ ((page & AVRC_SUB_PAGE_MASK) << AVRC_SUB_PAGE_SHIFT) | AVRC_SUB_EXT_CODE;
+ memset(p_data, AVRC_CMD_OPRND_PAD, AVRC_SUB_OPRND_BYTES);
+ p_cmd->len =
+ p_data + AVRC_SUB_OPRND_BYTES - (uint8_t*)(p_cmd + 1) - p_cmd->offset;
+ p_cmd->layer_specific = AVCT_DATA_CTRL;
+
+ return AVCT_MsgReq(handle, label, AVCT_CMD, p_cmd);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_VendorCmd
+ *
+ * Description Send a VENDOR DEPENDENT command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * p_msg: Pointer to VENDOR DEPENDENT message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_VendorCmd(uint8_t handle, uint8_t label,
+ tAVRC_MSG_VENDOR* p_msg) {
+ BT_HDR* p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq(handle, label, AVCT_CMD, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_VendorRsp
+ *
+ * Description Send a VENDOR DEPENDENT response to the peer device. This
+ * function can only be called for target role connections.
+ * This function must be called when a VENDOR DEPENDENT
+ * command message is received from the peer through the
+ * tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label. Must be the same value as
+ * passed with the command message in the callback
+ * function.
+ *
+ * p_msg: Pointer to VENDOR DEPENDENT message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+uint16_t AVRC_VendorRsp(uint8_t handle, uint8_t label,
+ tAVRC_MSG_VENDOR* p_msg) {
+ BT_HDR* p_buf = avrc_vendor_msg(p_msg);
+ if (p_buf)
+ return AVCT_MsgReq(handle, label, AVCT_RSP, p_buf);
+ else
+ return AVCT_NO_RESOURCES;
+}
diff --git a/mtkbt/code/bt/stack/avrc/avrc_pars_ct.cc b/mtkbt/code/bt/stack/avrc/avrc_pars_ct.cc
new file mode 100755
index 0000000..144c778
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_pars_ct.cc
@@ -0,0 +1,688 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function avrc_pars_vendor_rsp
+ *
+ * Description This function parses the vendor specific commands defined by
+ * Bluetooth SIG
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg,
+ tAVRC_RESPONSE* p_result) {
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint8_t* p;
+ uint16_t len;
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ uint8_t eventid = 0;
+#endif
+
+ /* Check the vendor data */
+ if (p_msg->vendor_len == 0) return AVRC_STS_NO_ERROR;
+ if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR;
+
+ p = p_msg->p_vendor_data;
+ BE_STREAM_TO_UINT8(p_result->pdu, p);
+ p++; /* skip the reserved/packe_type byte */
+ BE_STREAM_TO_UINT16(len, p);
+ AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d/0x%x", __func__,
+ p_msg->hdr.ctype, p_result->pdu, len, len);
+ if (p_msg->hdr.ctype == AVRC_RSP_REJ) {
+ p_result->rsp.status = *p;
+ return p_result->rsp.status;
+ }
+
+ switch (p_result->pdu) {
+/* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+/* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT8(p_result->volume.volume, p);
+ }
+ break;
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+#if (AVRC_ADV_CTRL_INCLUDED == TRUE)
+ BE_STREAM_TO_UINT8(eventid, p);
+ if (AVRC_EVT_VOLUME_CHANGE == eventid &&
+ (AVRC_RSP_CHANGED == p_msg->hdr.ctype ||
+ AVRC_RSP_INTERIM == p_msg->hdr.ctype ||
+ AVRC_RSP_REJ == p_msg->hdr.ctype ||
+ AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) {
+ p_result->reg_notif.status = p_msg->hdr.ctype;
+ p_result->reg_notif.event_id = eventid;
+ BE_STREAM_TO_UINT8(p_result->reg_notif.param.volume, p);
+ }
+ AVRC_TRACE_DEBUG("%s PDU reg notif response:event %x, volume %x",
+ __func__, eventid, p_result->reg_notif.param.volume);
+#endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */
+ break;
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+
+ return status;
+}
+
+void avrc_parse_notification_rsp(uint8_t* p_stream,
+ tAVRC_REG_NOTIF_RSP* p_rsp) {
+ BE_STREAM_TO_UINT8(p_rsp->event_id, p_stream);
+ switch (p_rsp->event_id) {
+ case AVRC_EVT_PLAY_STATUS_CHANGE:
+ BE_STREAM_TO_UINT8(p_rsp->param.play_status, p_stream);
+ break;
+
+ case AVRC_EVT_TRACK_CHANGE:
+ BE_STREAM_TO_ARRAY(p_stream, p_rsp->param.track, 8);
+ break;
+
+ case AVRC_EVT_APP_SETTING_CHANGE:
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.num_attr, p_stream);
+ for (int index = 0; index < p_rsp->param.player_setting.num_attr;
+ index++) {
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_id[index],
+ p_stream);
+ BE_STREAM_TO_UINT8(p_rsp->param.player_setting.attr_value[index],
+ p_stream);
+ }
+ break;
+
+ case AVRC_EVT_NOW_PLAYING_CHANGE:
+ break;
+
+ case AVRC_EVT_AVAL_PLAYERS_CHANGE:
+ break;
+
+ case AVRC_EVT_ADDR_PLAYER_CHANGE:
+ break;
+
+ case AVRC_EVT_UIDS_CHANGE:
+ break;
+
+ case AVRC_EVT_TRACK_REACHED_END:
+ case AVRC_EVT_TRACK_REACHED_START:
+ case AVRC_EVT_PLAY_POS_CHANGED:
+ case AVRC_EVT_BATTERY_STATUS_CHANGE:
+ case AVRC_EVT_SYSTEM_STATUS_CHANGE:
+ default:
+ break;
+ }
+}
+
+static tAVRC_STS avrc_pars_browse_rsp(tAVRC_MSG_BROWSE* p_msg,
+ tAVRC_RESPONSE* p_rsp) {
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint8_t pdu;
+
+ if (p_msg->browse_len == 0) {
+ AVRC_TRACE_ERROR("%s length ", p_msg->browse_len);
+ return AVRC_STS_BAD_PARAM;
+ }
+
+ uint8_t* p = p_msg->p_browse_data;
+
+ /* read the pdu */
+ BE_STREAM_TO_UINT8(pdu, p);
+ uint16_t pkt_len;
+ /* read the entire packet len */
+ BE_STREAM_TO_UINT16(pkt_len, p);
+
+ AVRC_TRACE_DEBUG("%s pdu %d", __func__, pdu);
+
+ /* used to track how much we have read, if we cannot read anymore but the
+ * packet says so then we have a malformed packet. Also vice versa. */
+ uint16_t pkt_len_read = 0;
+
+ switch (pdu) {
+ case AVRC_PDU_GET_FOLDER_ITEMS: {
+ tAVRC_GET_ITEMS_RSP* get_item_rsp = &(p_rsp->get_items);
+ /* Copy back the PDU */
+ get_item_rsp->pdu = pdu;
+ /* read the status */
+ BE_STREAM_TO_UINT8(get_item_rsp->status, p);
+ /* read the UID counter */
+ BE_STREAM_TO_UINT16(get_item_rsp->uid_counter, p);
+ /* read the number of items */
+ BE_STREAM_TO_UINT16(get_item_rsp->item_count, p);
+ pkt_len_read += 5;
+
+ AVRC_TRACE_DEBUG(
+ "%s pdu %d status %d pkt_len %d uid counter %d item count %d",
+ __func__, get_item_rsp->pdu, get_item_rsp->status, pkt_len,
+ get_item_rsp->uid_counter, get_item_rsp->item_count);
+
+ if (get_item_rsp->status != AVRC_STS_NO_ERROR) {
+ AVRC_TRACE_WARNING("%s returning error %d", __func__,
+ get_item_rsp->status);
+ return get_item_rsp->status;
+ }
+
+ /* get each of the items */
+ get_item_rsp->p_item_list = (tAVRC_ITEM*)osi_malloc(
+ get_item_rsp->item_count * (sizeof(tAVRC_ITEM)));
+ tAVRC_ITEM* curr_item = get_item_rsp->p_item_list;
+ for (int i = 0; i < get_item_rsp->item_count; i++) {
+ BE_STREAM_TO_UINT8(curr_item->item_type, p);
+ pkt_len_read += 1;
+ AVRC_TRACE_DEBUG("%s item type %d", __func__, curr_item->item_type);
+ switch (curr_item->item_type) {
+ case AVRC_ITEM_PLAYER: {
+ /* Handle player */
+ tAVRC_ITEM_PLAYER* player = &(curr_item->u.player);
+ uint8_t player_len;
+ BE_STREAM_TO_UINT16(player_len, p);
+ BE_STREAM_TO_UINT16(player->player_id, p);
+ BE_STREAM_TO_UINT8(player->major_type, p);
+ BE_STREAM_TO_UINT32(player->sub_type, p);
+ BE_STREAM_TO_UINT8(player->play_status, p);
+ BE_STREAM_TO_ARRAY(p, player->features, AVRC_FEATURE_MASK_SIZE);
+ pkt_len_read += (10 + AVRC_FEATURE_MASK_SIZE);
+
+ /* read str */
+ BE_STREAM_TO_UINT16(player->name.charset_id, p);
+ BE_STREAM_TO_UINT16(player->name.str_len, p);
+ player->name.p_str = (uint8_t*)osi_malloc(
+ (player->name.str_len + 1) * sizeof(uint8_t));
+ BE_STREAM_TO_ARRAY(p, player->name.p_str, player->name.str_len);
+ pkt_len_read += (4 + player->name.str_len);
+ AVRC_TRACE_DEBUG(
+ "%s type %d id %d mtype %d stype %d ps %d cs %d name len %d",
+ __func__, curr_item->item_type, player->player_id,
+ player->major_type, player->sub_type, player->play_status,
+ player->name.charset_id, player->name.str_len);
+ } break;
+
+ case AVRC_ITEM_FOLDER: {
+ tAVRC_ITEM_FOLDER* folder = &(curr_item->u.folder);
+ uint16_t folder_len;
+ BE_STREAM_TO_UINT16(folder_len, p);
+
+ BE_STREAM_TO_ARRAY(p, folder->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8(folder->type, p);
+ BE_STREAM_TO_UINT8(folder->playable, p);
+ pkt_len_read += (4 + AVRC_UID_SIZE);
+
+ /* read str, encoding to be handled by upper layers */
+ BE_STREAM_TO_UINT16(folder->name.charset_id, p);
+ BE_STREAM_TO_UINT16(folder->name.str_len, p);
+ folder->name.p_str = (uint8_t*)osi_malloc(
+ (folder->name.str_len + 1) * sizeof(uint8_t));
+ BE_STREAM_TO_ARRAY(p, folder->name.p_str, folder->name.str_len);
+ pkt_len_read += (4 + folder->name.str_len);
+ AVRC_TRACE_DEBUG("%s type %d playable %d cs %d name len %d",
+ __func__, folder->type, folder->playable,
+ folder->name.charset_id, folder->name.str_len);
+ } break;
+
+ case AVRC_ITEM_MEDIA: {
+ tAVRC_ITEM_MEDIA* media = &(curr_item->u.media);
+ uint8_t media_len;
+ BE_STREAM_TO_UINT16(media_len, p);
+ BE_STREAM_TO_ARRAY(p, media->uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT8(media->type, p);
+ pkt_len_read += (3 + AVRC_UID_SIZE);
+
+ /* read str, encoding to be handled by upper layers */
+ BE_STREAM_TO_UINT16(media->name.charset_id, p);
+ BE_STREAM_TO_UINT16(media->name.str_len, p);
+ media->name.p_str =
+ (uint8_t*)osi_malloc((media->name.str_len) * sizeof(uint8_t));
+ BE_STREAM_TO_ARRAY(p, media->name.p_str, media->name.str_len);
+
+ BE_STREAM_TO_UINT8(media->attr_count, p);
+ AVRC_TRACE_DEBUG("%s media type %d charset id %d len %d attr ct %d",
+ __func__, media->type, media->name.charset_id,
+ media->name.str_len, media->attr_count);
+ pkt_len_read += (5 + media->name.str_len);
+
+ media->p_attr_list = (tAVRC_ATTR_ENTRY*)osi_malloc(
+ media->attr_count * sizeof(tAVRC_ATTR_ENTRY));
+ for (int jk = 0; jk < media->attr_count; jk++) {
+ tAVRC_ATTR_ENTRY* attr_entry = &(media->p_attr_list[jk]);
+ BE_STREAM_TO_UINT32(attr_entry->attr_id, p);
+
+ /* Parse the name now */
+ BE_STREAM_TO_UINT16(attr_entry->name.charset_id, p);
+ BE_STREAM_TO_UINT16(attr_entry->name.str_len, p);
+ attr_entry->name.p_str = (uint8_t*)osi_malloc(
+ attr_entry->name.str_len * sizeof(uint8_t));
+ BE_STREAM_TO_ARRAY(p, attr_entry->name.p_str,
+ attr_entry->name.str_len);
+ pkt_len_read += (8 + attr_entry->name.str_len);
+ AVRC_TRACE_DEBUG("%s media attr id %d cs %d name len %d",
+ __func__, attr_entry->attr_id,
+ attr_entry->name.charset_id,
+ attr_entry->name.str_len);
+ }
+ } break;
+
+ default:
+ AVRC_TRACE_ERROR("%s item type not handled %d", __func__,
+ curr_item->item_type);
+ return AVRC_STS_INTERNAL_ERR;
+ }
+
+ /* we check if we have overrun */
+ if (pkt_len_read > pkt_len) {
+ AVRC_TRACE_ERROR("%s overflow in read pkt_len %d pkt_len_read %d",
+ __func__, pkt_len, pkt_len_read);
+ return AVRC_STS_BAD_CMD;
+ }
+ AVRC_TRACE_DEBUG("%s pkt_len %d pkt_len_read %d", __func__, pkt_len,
+ pkt_len_read);
+
+ /* advance to populate the next item */
+ curr_item++;
+ }
+ break;
+ }
+
+ case AVRC_PDU_CHANGE_PATH: {
+ tAVRC_CHG_PATH_RSP* change_path_rsp = &(p_rsp->chg_path);
+ /* Copyback the PDU */
+ change_path_rsp->pdu = pdu;
+ /* Read the status */
+ BE_STREAM_TO_UINT8(change_path_rsp->status, p);
+ /* Read the number of items in folder */
+ BE_STREAM_TO_UINT32(change_path_rsp->num_items, p);
+ pkt_len_read += 5;
+
+ AVRC_TRACE_DEBUG("%s pdu %d status %d item count %d", __func__,
+ change_path_rsp->pdu, change_path_rsp->status,
+ change_path_rsp->num_items);
+ break;
+ }
+
+ case AVRC_PDU_SET_BROWSED_PLAYER: {
+ tAVRC_SET_BR_PLAYER_RSP* set_br_pl_rsp = &(p_rsp->br_player);
+ /* Copyback the PDU */
+ set_br_pl_rsp->pdu = pdu;
+
+ /* Read the status */
+ BE_STREAM_TO_UINT8(set_br_pl_rsp->status, p);
+
+ if (set_br_pl_rsp->status != AVRC_STS_NO_ERROR) {
+ AVRC_TRACE_ERROR(
+ "%s Stopping further parsing because player not browsable sts %d",
+ __func__, set_br_pl_rsp->status);
+ break;
+ }
+ BE_STREAM_TO_UINT16(set_br_pl_rsp->uid_counter, p);
+ BE_STREAM_TO_UINT32(set_br_pl_rsp->num_items, p);
+ BE_STREAM_TO_UINT16(set_br_pl_rsp->charset_id, p);
+ BE_STREAM_TO_UINT8(set_br_pl_rsp->folder_depth, p);
+ AVRC_TRACE_DEBUG(
+ "%s AVRC_PDU_SET_BROWSED_PLAYER status %d items %d cs %d depth %d",
+ __func__, set_br_pl_rsp->status, set_br_pl_rsp->num_items,
+ set_br_pl_rsp->charset_id, set_br_pl_rsp->folder_depth);
+ pkt_len_read += 10;
+
+ set_br_pl_rsp->p_folders = (tAVRC_NAME*)osi_malloc(
+ set_br_pl_rsp->num_items * sizeof(tAVRC_NAME));
+
+ /* Read each of the folder in the depth */
+ for (uint32_t i = 0; i < set_br_pl_rsp->folder_depth; i++) {
+ tAVRC_NAME* folder_name = &(set_br_pl_rsp->p_folders[i]);
+ BE_STREAM_TO_UINT16(folder_name->str_len, p);
+ AVRC_TRACE_DEBUG("%s AVRC_PDU_SET_BROWSED_PLAYER item: %d len: %d",
+ __func__, i, folder_name->str_len);
+ folder_name->p_str =
+ (uint8_t*)osi_malloc((folder_name->str_len + 1) * sizeof(uint8_t));
+ BE_STREAM_TO_ARRAY(p, folder_name->p_str, folder_name->str_len);
+ pkt_len_read += (2 + folder_name->str_len);
+ }
+ break;
+ }
+
+ default:
+ AVRC_TRACE_ERROR("%s pdu %d not handled", __func__, pdu);
+ }
+
+ if (pkt_len != pkt_len_read) {
+ AVRC_TRACE_ERROR("%s finished pkt_len %d pkt_len_read %d", __func__,
+ pkt_len, pkt_len_read);
+ return AVRC_STS_BAD_CMD;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_ctrl_pars_vendor_rsp
+ *
+ * Description This function parses the vendor specific commands defined by
+ * Bluetooth SIG
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg,
+ tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t* buf_len) {
+ uint8_t* p = p_msg->p_vendor_data;
+ BE_STREAM_TO_UINT8(p_result->pdu, p);
+ p++; /* skip the reserved/packe_type byte */
+
+ uint16_t len;
+ BE_STREAM_TO_UINT16(len, p);
+ AVRC_TRACE_DEBUG("%s ctype:0x%x pdu:0x%x, len:%d", __func__, p_msg->hdr.ctype,
+ p_result->pdu, len);
+ /* Todo: Issue in handling reject, check */
+ if (p_msg->hdr.ctype == AVRC_RSP_REJ) {
+ p_result->rsp.status = *p;
+ return p_result->rsp.status;
+ }
+
+ /* TODO: Break the big switch into functions. */
+ switch (p_result->pdu) {
+ /* case AVRC_PDU_REQUEST_CONTINUATION_RSP: 0x40 */
+ /* case AVRC_PDU_ABORT_CONTINUATION_RSP: 0x41 */
+
+ case AVRC_PDU_REGISTER_NOTIFICATION:
+ avrc_parse_notification_rsp(p, &p_result->reg_notif);
+ break;
+
+ case AVRC_PDU_GET_CAPABILITIES:
+ if (len == 0) {
+ p_result->get_caps.count = 0;
+ p_result->get_caps.capability_id = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->get_caps.capability_id, p);
+ BE_STREAM_TO_UINT8(p_result->get_caps.count, p);
+ AVRC_TRACE_DEBUG("%s cap id = %d, cap_count = %d ", __func__,
+ p_result->get_caps.capability_id,
+ p_result->get_caps.count);
+ if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID) {
+ for (int xx = 0; ((xx < p_result->get_caps.count) &&
+ (xx < AVRC_CAP_MAX_NUM_COMP_ID));
+ xx++) {
+ BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[xx], p);
+ }
+ } else if (p_result->get_caps.capability_id ==
+ AVRC_CAP_EVENTS_SUPPORTED) {
+ for (int xx = 0; ((xx < p_result->get_caps.count) &&
+ (xx < AVRC_CAP_MAX_NUM_EVT_ID));
+ xx++) {
+ BE_STREAM_TO_UINT8(p_result->get_caps.param.event_id[xx], p);
+ }
+ }
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR:
+ if (len == 0) {
+ p_result->list_app_attr.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->list_app_attr.num_attr, p);
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__,
+ p_result->list_app_attr.num_attr);
+ for (int xx = 0; xx < p_result->list_app_attr.num_attr; xx++) {
+ BE_STREAM_TO_UINT8(p_result->list_app_attr.attrs[xx], p);
+ }
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES:
+ if (len == 0) {
+ p_result->list_app_values.num_val = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->list_app_values.num_val, p);
+ AVRC_TRACE_DEBUG("%s value count = %d ", __func__,
+ p_result->list_app_values.num_val);
+ for (int xx = 0; xx < p_result->list_app_values.num_val; xx++) {
+ BE_STREAM_TO_UINT8(p_result->list_app_values.vals[xx], p);
+ }
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: {
+ if (len == 0) {
+ p_result->get_cur_app_val.num_val = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_val, p);
+ tAVRC_APP_SETTING* app_sett = (tAVRC_APP_SETTING*)osi_malloc(
+ p_result->get_cur_app_val.num_val * sizeof(tAVRC_APP_SETTING));
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__,
+ p_result->get_cur_app_val.num_val);
+ for (int xx = 0; xx < p_result->get_cur_app_val.num_val; xx++) {
+ BE_STREAM_TO_UINT8(app_sett[xx].attr_id, p);
+ BE_STREAM_TO_UINT8(app_sett[xx].attr_val, p);
+ }
+ p_result->get_cur_app_val.p_vals = app_sett;
+ } break;
+
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: {
+ tAVRC_APP_SETTING_TEXT* p_setting_text;
+ uint8_t num_attrs;
+
+ if (len == 0) {
+ p_result->get_app_attr_txt.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_attrs, p);
+ AVRC_TRACE_DEBUG("%s attr count = %d ", __func__,
+ p_result->get_app_attr_txt.num_attr);
+ p_result->get_app_attr_txt.num_attr = num_attrs;
+ p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_malloc(
+ num_attrs * sizeof(tAVRC_APP_SETTING_TEXT));
+ for (int xx = 0; xx < num_attrs; xx++) {
+ BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].attr_id, p);
+ BE_STREAM_TO_UINT16(p_result->get_app_attr_txt.p_attrs[xx].charset_id,
+ p);
+ BE_STREAM_TO_UINT8(p_result->get_app_attr_txt.p_attrs[xx].str_len, p);
+ if (p_result->get_app_attr_txt.p_attrs[xx].str_len != 0) {
+ uint8_t* p_str = (uint8_t*)osi_malloc(
+ p_result->get_app_attr_txt.p_attrs[xx].str_len);
+ BE_STREAM_TO_ARRAY(p, p_str,
+ p_result->get_app_attr_txt.p_attrs[xx].str_len);
+ p_result->get_app_attr_txt.p_attrs[xx].p_str = p_str;
+ } else {
+ p_result->get_app_attr_txt.p_attrs[xx].p_str = NULL;
+ }
+ }
+ } break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: {
+ tAVRC_APP_SETTING_TEXT* p_setting_text;
+ uint8_t num_vals;
+
+ if (len == 0) {
+ p_result->get_app_val_txt.num_attr = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_vals, p);
+ p_result->get_app_val_txt.num_attr = num_vals;
+ AVRC_TRACE_DEBUG("%s value count = %d ", __func__,
+ p_result->get_app_val_txt.num_attr);
+
+ p_setting_text = (tAVRC_APP_SETTING_TEXT*)osi_malloc(
+ num_vals * sizeof(tAVRC_APP_SETTING_TEXT));
+ for (int i = 0; i < num_vals; i++) {
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].attr_id, p);
+ BE_STREAM_TO_UINT16(p_result->get_app_val_txt.p_attrs[i].charset_id, p);
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.p_attrs[i].str_len, p);
+ if (p_result->get_app_val_txt.p_attrs[i].str_len != 0) {
+ uint8_t* p_str = (uint8_t*)osi_malloc(
+ p_result->get_app_val_txt.p_attrs[i].str_len);
+ BE_STREAM_TO_ARRAY(p, p_str,
+ p_result->get_app_val_txt.p_attrs[i].str_len);
+ p_result->get_app_val_txt.p_attrs[i].p_str = p_str;
+ } else {
+ p_result->get_app_val_txt.p_attrs[i].p_str = NULL;
+ }
+ }
+ } break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE:
+ /* nothing comes as part of this rsp */
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR: {
+ uint8_t num_attrs;
+
+ if (len <= 0) {
+ p_result->get_attrs.num_attrs = 0;
+ break;
+ }
+ BE_STREAM_TO_UINT8(num_attrs, p);
+ p_result->get_attrs.num_attrs = num_attrs;
+ if (num_attrs) {
+ tAVRC_ATTR_ENTRY* p_attrs =
+ (tAVRC_ATTR_ENTRY*)osi_malloc(num_attrs * sizeof(tAVRC_ATTR_ENTRY));
+ for (int i = 0; i < num_attrs; i++) {
+ BE_STREAM_TO_UINT32(p_attrs[i].attr_id, p);
+ BE_STREAM_TO_UINT16(p_attrs[i].name.charset_id, p);
+ BE_STREAM_TO_UINT16(p_attrs[i].name.str_len, p);
+ if (p_attrs[i].name.str_len > 0) {
+ p_attrs[i].name.p_str =
+ (uint8_t*)osi_malloc(p_attrs[i].name.str_len);
+ BE_STREAM_TO_ARRAY(p, p_attrs[i].name.p_str,
+ p_attrs[i].name.str_len);
+ }
+ }
+ p_result->get_attrs.p_attrs = p_attrs;
+ }
+ } break;
+
+ case AVRC_PDU_GET_PLAY_STATUS:
+ if (len == 0) {
+ break;
+ }
+ BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
+ BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER:
+ if (len != 1) {
+ AVRC_TRACE_ERROR("%s pdu: %d len %d", __func__, p_result->pdu, len);
+ return AVRC_STS_BAD_CMD;
+ }
+ BE_STREAM_TO_UINT8(p_result->rsp.status, p);
+ break;
+
+ default:
+ return AVRC_STS_BAD_CMD;
+ }
+ return AVRC_STS_NO_ERROR;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_Ctrl_ParsResponse
+ *
+ * Description This function is a parse response for AVRCP Controller.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t* buf_len) {
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ if (p_msg && p_result) {
+ switch (p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status =
+ avrc_ctrl_pars_vendor_rsp(&p_msg->vendor, p_result, p_buf, buf_len);
+ break;
+
+ case AVRC_OP_BROWSE: /* 0xff Browse commands */
+ status = avrc_pars_browse_rsp(&p_msg->browse, p_result);
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->rsp.opcode = p_msg->hdr.opcode;
+ p_result->rsp.status = status;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_ParsResponse
+ *
+ * Description This function is a superset of AVRC_ParsMetadata to parse
+ * the response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ UNUSED_ATTR uint8_t* p_buf,
+ UNUSED_ATTR uint16_t buf_len) {
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ uint16_t id;
+
+ if (p_msg && p_result) {
+ switch (p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_pars_vendor_rsp(&p_msg->vendor, p_result);
+ break;
+
+ case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
+ status = avrc_pars_pass_thru(&p_msg->pass, &id);
+ if (status == AVRC_STS_NO_ERROR) {
+ p_result->pdu = (uint8_t)id;
+ }
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->rsp.opcode = p_msg->hdr.opcode;
+ p_result->rsp.status = status;
+ }
+ return status;
+}
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/mtkbt/code/bt/stack/avrc/avrc_pars_tg.cc b/mtkbt/code/bt/stack/avrc/avrc_pars_tg.cc
new file mode 100755
index 0000000..cc5ec1d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_pars_tg.cc
@@ -0,0 +1,549 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_defs.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/*******************************************************************************
+ *
+ * Function avrc_ctrl_pars_vendor_cmd
+ *
+ * Description This function parses the vendor specific commands defined by
+ * Bluetooth SIG for AVRCP Conroller.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_ctrl_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
+ tAVRC_COMMAND* p_result) {
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+
+ uint8_t* p = p_msg->p_vendor_data;
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
+ if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
+ AVRC_TRACE_DEBUG("%s detects wrong AV/C type!", __func__);
+ status = AVRC_STS_BAD_CMD;
+ }
+
+ p++; /* skip the reserved byte */
+ uint16_t len;
+ BE_STREAM_TO_UINT16(len, p);
+ if ((len + 4) != (p_msg->vendor_len)) {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+
+ if (status != AVRC_STS_NO_ERROR) return status;
+
+ switch (p_result->pdu) {
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: {
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT8(p_result->volume.volume, p);
+ p_result->volume.volume = AVRC_MAX_VOLUME & p_result->volume.volume;
+ }
+ break;
+ }
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
+ BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
+ break;
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_pars_vendor_cmd
+ *
+ * Description This function parses the vendor specific commands defined by
+ * Bluetooth SIG
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
+ tAVRC_COMMAND* p_result, uint8_t* p_buf,
+ uint16_t buf_len) {
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint8_t* p;
+ uint16_t len;
+ uint8_t xx, yy;
+ uint8_t* p_u8;
+ uint16_t* p_u16;
+ uint32_t u32, u32_2, *p_u32;
+ tAVRC_APP_SETTING* p_app_set;
+ uint16_t size_needed;
+
+ /* Check the vendor data */
+ if (p_msg->vendor_len == 0) return AVRC_STS_NO_ERROR;
+ if (p_msg->p_vendor_data == NULL) return AVRC_STS_INTERNAL_ERR;
+
+ p = p_msg->p_vendor_data;
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG("%s pdu:0x%x", __func__, p_result->pdu);
+ if (!AVRC_IsValidAvcType(p_result->pdu, p_msg->hdr.ctype)) {
+ AVRC_TRACE_DEBUG("%s detects wrong AV/C type(0x%x)!", __func__,
+ p_msg->hdr.ctype);
+ status = AVRC_STS_BAD_CMD;
+ }
+
+ p++; /* skip the reserved byte */
+ BE_STREAM_TO_UINT16(len, p);
+ if ((len + 4) != (p_msg->vendor_len)) {
+ AVRC_TRACE_ERROR("%s incorrect length :%d, %d", __func__, len,
+ p_msg->vendor_len);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+
+ if (status != AVRC_STS_NO_ERROR) return status;
+
+ switch (p_result->pdu) {
+ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
+ p_result->get_caps.capability_id = *p++;
+ if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
+ status = AVRC_STS_BAD_PARAM;
+ else if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
+ /* no additional parameters */
+ if (len != 0) status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+ p_result->list_app_values.attr_id = *p++;
+ if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
+ status = AVRC_STS_BAD_PARAM;
+ else if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+ BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_attr, p);
+ if (len != (p_result->get_cur_app_val.num_attr + 1)) {
+ status = AVRC_STS_INTERNAL_ERR;
+ break;
+ }
+ p_u8 = p_result->get_cur_app_val.attrs;
+ for (xx = 0, yy = 0; xx < p_result->get_cur_app_val.num_attr; xx++) {
+ /* only report the valid player app attributes */
+ if (AVRC_IsValidPlayerAttr(*p)) p_u8[yy++] = *p;
+ p++;
+ }
+ p_result->get_cur_app_val.num_attr = yy;
+ if (yy == 0) {
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+ BE_STREAM_TO_UINT8(p_result->set_app_val.num_val, p);
+ size_needed = sizeof(tAVRC_APP_SETTING);
+ if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
+ p_result->set_app_val.p_vals = (tAVRC_APP_SETTING*)p_buf;
+ p_app_set = p_result->set_app_val.p_vals;
+ for (xx = 0;
+ ((xx < p_result->set_app_val.num_val) && (buf_len > size_needed));
+ xx++) {
+ p_app_set[xx].attr_id = *p++;
+ p_app_set[xx].attr_val = *p++;
+ if (!avrc_is_valid_player_attrib_value(p_app_set[xx].attr_id,
+ p_app_set[xx].attr_val))
+ status = AVRC_STS_BAD_PARAM;
+ }
+ if (xx != p_result->set_app_val.num_val) {
+ AVRC_TRACE_ERROR(
+ "%s AVRC_PDU_SET_PLAYER_APP_VALUE not enough room:%d orig "
+ "num_val:%d",
+ __func__, xx, p_result->set_app_val.num_val);
+ p_result->set_app_val.num_val = xx;
+ }
+ } else {
+ AVRC_TRACE_ERROR(
+ "%s AVRC_PDU_SET_PLAYER_APP_VALUE NULL decode buffer or bad len",
+ __func__);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
+ if (len < 3)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.attr_id, p);
+ if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
+ status = AVRC_STS_BAD_PARAM;
+ else {
+ BE_STREAM_TO_UINT8(p_result->get_app_val_txt.num_val, p);
+ if ((len - 2 /* attr_id & num_val */) !=
+ p_result->get_app_val_txt.num_val)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ p_u8 = p_result->get_app_val_txt.vals;
+ for (xx = 0; xx < p_result->get_app_val_txt.num_val; xx++) {
+ p_u8[xx] = *p++;
+ if (!avrc_is_valid_player_attrib_value(
+ p_result->get_app_val_txt.attr_id, p_u8[xx])) {
+ status = AVRC_STS_BAD_PARAM;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
+ if (len < 3)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT8(p_result->inform_charset.num_id, p);
+ if ((len - 1 /* num_id */) != p_result->inform_charset.num_id * 2)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ p_u16 = p_result->inform_charset.charsets;
+ if (p_result->inform_charset.num_id > AVRC_MAX_CHARSET_SIZE)
+ p_result->inform_charset.num_id = AVRC_MAX_CHARSET_SIZE;
+ for (xx = 0; xx < p_result->inform_charset.num_id; xx++) {
+ BE_STREAM_TO_UINT16(p_u16[xx], p);
+ }
+ }
+ }
+ break;
+
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ p_result->inform_battery_status.battery_status = *p++;
+ if (!AVRC_IS_VALID_BATTERY_STATUS(
+ p_result->inform_battery_status.battery_status))
+ status = AVRC_STS_BAD_PARAM;
+ }
+ break;
+
+ case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
+ if (len < 9) /* UID/8 and num_attr/1 */
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT32(u32, p);
+ BE_STREAM_TO_UINT32(u32_2, p);
+ if (u32 == 0 && u32_2 == 0) {
+ BE_STREAM_TO_UINT8(p_result->get_elem_attrs.num_attr, p);
+ if ((len - 9 /* UID/8 and num_attr/1 */) !=
+ (p_result->get_elem_attrs.num_attr * 4))
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ p_u32 = p_result->get_elem_attrs.attrs;
+ if (p_result->get_elem_attrs.num_attr > AVRC_MAX_ELEM_ATTR_SIZE)
+ p_result->get_elem_attrs.num_attr = AVRC_MAX_ELEM_ATTR_SIZE;
+ for (xx = 0; xx < p_result->get_elem_attrs.num_attr; xx++) {
+ BE_STREAM_TO_UINT32(p_u32[xx], p);
+ }
+ }
+ } else
+ status = AVRC_STS_NOT_FOUND;
+ }
+ break;
+
+ case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
+ /* no additional parameters */
+ if (len != 0) status = AVRC_STS_INTERNAL_ERR;
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ if (len != 5)
+ status = AVRC_STS_INTERNAL_ERR;
+ else {
+ BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
+ BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
+ }
+ break;
+
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ if (len != 1)
+ status = AVRC_STS_INTERNAL_ERR;
+ else
+ p_result->volume.volume = *p++;
+ break;
+
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ if (len != 1) {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
+ break;
+
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ if (len != 1) {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
+ break;
+
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ if (len != 2) {
+ AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",
+ len);
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p);
+ break;
+
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ if (len != (AVRC_UID_SIZE + 3)) status = AVRC_STS_INTERNAL_ERR;
+ BE_STREAM_TO_UINT8(p_result->play_item.scope, p);
+ if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING) {
+ status = AVRC_STS_BAD_SCOPE;
+ }
+ BE_STREAM_TO_ARRAY(p, p_result->play_item.uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT16(p_result->play_item.uid_counter, p);
+ break;
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_Ctrl_ParsCommand
+ *
+ * Description This function is used to parse cmds received for CTRL
+ * Currently it is for SetAbsVolume and Volume Change
+ * Notification..
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+
+ if (p_msg && p_result) {
+ switch (p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_ctrl_pars_vendor_cmd(&p_msg->vendor, p_result);
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->cmd.opcode = p_msg->hdr.opcode;
+ p_result->cmd.status = status;
+ }
+ AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_pars_browsing_cmd
+ *
+ * Description This function parses the commands that go through the
+ * browsing channel
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP+1
+ *
+ ******************************************************************************/
+static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
+ tAVRC_COMMAND* p_result, uint8_t* p_buf,
+ uint16_t buf_len) {
+ tAVRC_STS status = AVRC_STS_NO_ERROR;
+ uint8_t* p = p_msg->p_browse_data;
+ int count;
+
+ p_result->pdu = *p++;
+ AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
+ /* skip over len */
+ p += 2;
+
+ switch (p_result->pdu) {
+ case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ // For current implementation all players are browsable.
+ BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ STREAM_TO_UINT8(p_result->get_items.scope, p);
+ // To be modified later here (Scope) when all browsing commands are
+ // supported
+ if (p_result->get_items.scope > AVRC_SCOPE_NOW_PLAYING) {
+ status = AVRC_STS_BAD_SCOPE;
+ }
+ BE_STREAM_TO_UINT32(p_result->get_items.start_item, p);
+ BE_STREAM_TO_UINT32(p_result->get_items.end_item, p);
+ if (p_result->get_items.start_item > p_result->get_items.end_item) {
+ status = AVRC_STS_BAD_RANGE;
+ }
+ STREAM_TO_UINT8(p_result->get_items.attr_count, p);
+ p_result->get_items.p_attr_list = NULL;
+ if (p_result->get_items.attr_count && p_buf &&
+ (p_result->get_items.attr_count != AVRC_FOLDER_ITEM_COUNT_NONE)) {
+ p_result->get_items.p_attr_list = (uint32_t*)p_buf;
+ count = p_result->get_items.attr_count;
+ if (buf_len < (count << 2))
+ p_result->get_items.attr_count = count = (buf_len >> 2);
+ for (int idx = 0; idx < count; idx++) {
+ BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
+ }
+ }
+ break;
+
+ case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
+ BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
+ if (p_result->chg_path.direction != AVRC_DIR_UP &&
+ p_result->chg_path.direction != AVRC_DIR_DOWN) {
+ status = AVRC_STS_BAD_DIR;
+ }
+ BE_STREAM_TO_ARRAY(p, p_result->chg_path.folder_uid, AVRC_UID_SIZE);
+ break;
+
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
+ if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
+ status = AVRC_STS_BAD_SCOPE;
+ break;
+ }
+ BE_STREAM_TO_ARRAY(p, p_result->get_attrs.uid, AVRC_UID_SIZE);
+ BE_STREAM_TO_UINT16(p_result->get_attrs.uid_counter, p);
+ BE_STREAM_TO_UINT8(p_result->get_attrs.attr_count, p);
+ p_result->get_attrs.p_attr_list = NULL;
+ if (p_result->get_attrs.attr_count && p_buf) {
+ p_result->get_attrs.p_attr_list = (uint32_t*)p_buf;
+ count = p_result->get_attrs.attr_count;
+ if (buf_len < (count << 2))
+ p_result->get_attrs.attr_count = count = (buf_len >> 2);
+ for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
+ idx++) {
+ BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
+ if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
+ p_result->get_attrs.p_attr_list[count])) {
+ count++;
+ }
+ }
+
+ if (p_result->get_attrs.attr_count != count && count == 0)
+ status = AVRC_STS_BAD_PARAM;
+ else
+ p_result->get_attrs.attr_count = count;
+ }
+ break;
+
+ case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
+ BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
+ if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
+ status = AVRC_STS_BAD_SCOPE;
+ }
+ break;
+
+ case AVRC_PDU_SEARCH: /* 0x80 */
+ BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
+ BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
+ p_result->search.string.p_str = p_buf;
+ if (p_buf) {
+ if (buf_len > p_result->search.string.str_len)
+ buf_len = p_result->search.string.str_len;
+ BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
+ } else {
+ status = AVRC_STS_INTERNAL_ERR;
+ }
+ break;
+
+ default:
+ status = AVRC_STS_BAD_CMD;
+ break;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_ParsCommand
+ *
+ * Description This function is a superset of AVRC_ParsMetadata to parse
+ * the command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
+ uint8_t* p_buf, uint16_t buf_len) {
+ tAVRC_STS status = AVRC_STS_INTERNAL_ERR;
+ uint16_t id;
+
+ if (p_msg && p_result) {
+ switch (p_msg->hdr.opcode) {
+ case AVRC_OP_VENDOR: /* 0x00 Vendor-dependent commands */
+ status = avrc_pars_vendor_cmd(&p_msg->vendor, p_result, p_buf, buf_len);
+ break;
+
+ case AVRC_OP_PASS_THRU: /* 0x7C panel subunit opcode */
+ status = avrc_pars_pass_thru(&p_msg->pass, &id);
+ if (status == AVRC_STS_NO_ERROR) {
+ p_result->pdu = (uint8_t)id;
+ }
+ break;
+
+ case AVRC_OP_BROWSE:
+ status =
+ avrc_pars_browsing_cmd(&p_msg->browse, p_result, p_buf, buf_len);
+ break;
+
+ default:
+ AVRC_TRACE_ERROR("%s unknown opcode:0x%x", __func__, p_msg->hdr.opcode);
+ break;
+ }
+ p_result->cmd.opcode = p_msg->hdr.opcode;
+ p_result->cmd.status = status;
+ }
+ AVRC_TRACE_DEBUG("%s return status:0x%x", __func__, status);
+ return status;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == true) */
diff --git a/mtkbt/code/bt/stack/avrc/avrc_sdp.cc b/mtkbt/code/bt/stack/avrc/avrc_sdp.cc
new file mode 100755
index 0000000..b9600c1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_sdp.cc
@@ -0,0 +1,341 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * AVRCP SDP related functions
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+
+/*****************************************************************************
+ * Global data
+ ****************************************************************************/
+tAVRC_CB avrc_cb;
+
+/******************************************************************************
+ *
+ * Function avrc_sdp_cback
+ *
+ * Description This is the SDP callback function used by A2DP_FindService.
+ * This function will be executed by SDP when the service
+ * search is completed. If the search is successful, it
+ * finds the first record in the database that matches the
+ * UUID of the search. Then retrieves various parameters
+ * from the record. When it is finished it calls the
+ * application callback function.
+ *
+ * Returns Nothing.
+ *
+ *****************************************************************************/
+static void avrc_sdp_cback(uint16_t status) {
+ AVRC_TRACE_API("%s status: %d", __func__, status);
+
+ /* reset service_uuid, so can start another find service */
+ avrc_cb.service_uuid = 0;
+
+ /* return info from sdp record in app callback function */
+ (*avrc_cb.p_cback)(status);
+
+ return;
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_FindService
+ *
+ * Description This function is called by the application to perform
+ * service discovery and retrieve AVRCP SDP record information
+ * from a peer device. Information is returned for the first
+ * service record found on the server that matches the service
+ * UUID. The callback function will be executed when service
+ * discovery is complete. There can only be one outstanding
+ * call to AVRC_FindService() at a time; the application must
+ * wait for the callback before it makes another call to the
+ * function. The application is responsible for allocating
+ * memory for the discovery database. It is recommended that
+ * the size of the discovery database be at least 300 bytes.
+ * The application can deallocate the memory after the
+ * callback function has executed.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates
+ * TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ * r CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ *
+ * bd_addr: BD address of the peer device.
+ *
+ * p_db: SDP discovery database parameters.
+ *
+ * p_cback: Pointer to the callback function.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_PARAMS if discovery database parameters are
+ * invalid.
+ * AVRC_NO_RESOURCES if there are not enough resources to
+ * perform the service search.
+ *
+ *****************************************************************************/
+uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+ tAVRC_SDP_DB_PARAMS* p_db,
+ tAVRC_FIND_CBACK* p_cback) {
+ tSDP_UUID uuid_list;
+ bool result = true;
+ uint16_t a2dp_attr_list[] = {
+ ATTR_ID_SERVICE_CLASS_ID_LIST, /* update AVRC_NUM_ATTR, if changed */
+ ATTR_ID_PROTOCOL_DESC_LIST, ATTR_ID_BT_PROFILE_DESC_LIST,
+ ATTR_ID_SERVICE_NAME, ATTR_ID_SUPPORTED_FEATURES,
+ ATTR_ID_PROVIDER_NAME};
+
+ AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
+ if ((service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET &&
+ service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL) ||
+ p_db == NULL || p_db->p_db == NULL || p_cback == NULL)
+ return AVRC_BAD_PARAM;
+
+ /* check if it is busy */
+ if (avrc_cb.service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET ||
+ avrc_cb.service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ return AVRC_NO_RESOURCES;
+
+ /* set up discovery database */
+ uuid_list.len = LEN_UUID_16;
+ uuid_list.uu.uuid16 = service_uuid;
+
+ if (p_db->p_attrs == NULL || p_db->num_attr == 0) {
+ p_db->p_attrs = a2dp_attr_list;
+ p_db->num_attr = AVRC_NUM_ATTR;
+ }
+
+ result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list,
+ p_db->num_attr, p_db->p_attrs);
+
+ if (result == true) {
+ /* store service_uuid and discovery db pointer */
+ avrc_cb.p_db = p_db->p_db;
+ avrc_cb.service_uuid = service_uuid;
+ avrc_cb.p_cback = p_cback;
+
+ /* perform service search */
+ result =
+ SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, avrc_sdp_cback);
+ }
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_AddRecord
+ *
+ * Description This function is called to build an AVRCP SDP record.
+ * Prior to calling this function the application must
+ * call SDP_CreateRecord() to create an SDP record.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates
+ * TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ * or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ *
+ * p_service_name: Pointer to a null-terminated character
+ * string containing the service name.
+ * If service name is not used set this to NULL.
+ *
+ * p_provider_name: Pointer to a null-terminated character
+ * string containing the provider name.
+ * If provider name is not used set this to NULL.
+ *
+ * categories: Supported categories.
+ *
+ * sdp_handle: SDP handle returned by SDP_CreateRecord().
+ *
+ * browse_supported: browse support info.
+ *
+ * profile_version: profile version of avrcp record.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if not enough resources to build the SDP
+ * record.
+ *
+ *****************************************************************************/
+uint16_t AVRC_AddRecord(uint16_t service_uuid, const char* p_service_name,
+ const char* p_provider_name, uint16_t categories,
+ uint32_t sdp_handle, bool browse_supported,
+ uint16_t profile_version) {
+ uint16_t browse_list[1];
+ bool result = true;
+ uint8_t temp[8];
+ uint8_t* p;
+ uint16_t count = 1;
+ uint8_t index = 0;
+ uint16_t class_list[2];
+
+ AVRC_TRACE_API("%s uuid: %x", __func__, service_uuid);
+
+ if (service_uuid != UUID_SERVCLASS_AV_REM_CTRL_TARGET &&
+ service_uuid != UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ return AVRC_BAD_PARAM;
+
+ /* add service class id list */
+ class_list[0] = service_uuid;
+ if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) &&
+ (profile_version > AVRC_REV_1_3)) {
+ class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL;
+ count = 2;
+ }
+ result &= SDP_AddServiceClassIdList(sdp_handle, count, class_list);
+
+ /* add protocol descriptor list */
+ tSDP_PROTOCOL_ELEM avrc_proto_desc_list[AVRC_NUM_PROTO_ELEMS];
+ avrc_proto_desc_list[0].num_params = 1;
+ avrc_proto_desc_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ avrc_proto_desc_list[0].params[0] = AVCT_PSM;
+ avrc_proto_desc_list[0].params[1] = 0;
+ for (index = 1; index < AVRC_NUM_PROTO_ELEMS; index++) {
+ avrc_proto_desc_list[index].num_params = 1;
+ avrc_proto_desc_list[index].protocol_uuid = UUID_PROTOCOL_AVCTP;
+ avrc_proto_desc_list[index].params[0] = AVCT_REV_1_4;
+ avrc_proto_desc_list[index].params[1] = 0;
+ }
+ result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS,
+ (tSDP_PROTOCOL_ELEM*)avrc_proto_desc_list);
+
+ /* additional protocal descriptor, required only for version > 1.3 */
+ if ((profile_version > AVRC_REV_1_3) && (browse_supported)) {
+ tSDP_PROTO_LIST_ELEM avrc_add_proto_desc_list;
+ avrc_add_proto_desc_list.num_elems = 2;
+ avrc_add_proto_desc_list.list_elem[0].num_params = 1;
+ avrc_add_proto_desc_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ avrc_add_proto_desc_list.list_elem[0].params[0] = AVCT_BR_PSM;
+ avrc_add_proto_desc_list.list_elem[0].params[1] = 0;
+ avrc_add_proto_desc_list.list_elem[1].num_params = 1;
+ avrc_add_proto_desc_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_AVCTP;
+ avrc_add_proto_desc_list.list_elem[1].params[0] = AVCT_REV_1_4;
+ avrc_add_proto_desc_list.list_elem[1].params[1] = 0;
+
+ result &= SDP_AddAdditionProtoLists(
+ sdp_handle, 1, (tSDP_PROTO_LIST_ELEM*)&avrc_add_proto_desc_list);
+ }
+ /* add profile descriptor list */
+ result &= SDP_AddProfileDescriptorList(
+ sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version);
+
+ /* add supported categories */
+ p = temp;
+ UINT16_TO_BE_STREAM(p, categories);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES,
+ UINT_DESC_TYPE, (uint32_t)2, (uint8_t*)temp);
+
+ /* add provider name */
+ if (p_provider_name != NULL) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_provider_name) + 1), (uint8_t*)p_provider_name);
+ }
+
+ /* add service name */
+ if (p_service_name != NULL) {
+ result &= SDP_AddAttribute(
+ sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
+ }
+
+ /* add browse group list */
+ browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+ browse_list);
+
+ return (result ? AVRC_SUCCESS : AVRC_FAIL);
+}
+
+/******************************************************************************
+ *
+ * Function AVRC_SetTraceLevel
+ *
+ * Description Sets the trace level for AVRC. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the AVRC tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+uint8_t AVRC_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) avrc_cb.trace_level = new_level;
+
+ return (avrc_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_Init
+ *
+ * Description This function is called at stack startup to allocate the
+ * control block (if using dynamic memory), and initializes the
+ * control block and tracing level.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void AVRC_Init(void) {
+ memset(&avrc_cb, 0, sizeof(tAVRC_CB));
+
+#if defined(AVRC_INITIAL_TRACE_LEVEL)
+ avrc_cb.trace_level = AVRC_INITIAL_TRACE_LEVEL;
+#else
+ avrc_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/** M: Bug fix for update avrcp version @{ */
+/*******************************************************************************
+ *
+ * Function Update_AVRC_Version
+ *
+ * Description update AVRCP version to match remote device AVRC version.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool AVRC_Update_Version(uint32_t sdp_handle, uint16_t profile_version) {
+ /* update profile descriptor list */
+ bool result = SDP_AddProfileDescriptorList(
+ sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, profile_version);
+ AVRC_TRACE_API("%s Update_AVRC_Version result : %x", __func__, result);
+ return result;
+}
+/** @} */
diff --git a/mtkbt/code/bt/stack/avrc/avrc_utils.cc b/mtkbt/code/bt/stack/avrc/avrc_utils.cc
new file mode 100755
index 0000000..6504ac4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/avrc/avrc_utils.cc
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "avrc_api.h"
+#include "avrc_int.h"
+#include "bt_common.h"
+
+#if (AVRC_METADATA_INCLUDED == TRUE)
+
+/**************************************************************************
+ *
+ * Function AVRC_IsValidAvcType
+ *
+ * Description Check if correct AVC type is specified
+ *
+ * Returns returns true if it is valid
+ *
+ *
+ ******************************************************************************/
+bool AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type) {
+ bool result = false;
+
+ if (avc_type < AVRC_RSP_NOT_IMPL) /* command msg */
+ {
+ switch (pdu_id) {
+ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */
+ case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
+ case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+ case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
+ case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+ case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
+ case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
+ case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
+ if (avc_type == AVRC_CMD_STATUS) result = true;
+ break;
+
+ case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+ case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
+ case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
+ case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
+ case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
+ if (avc_type == AVRC_CMD_CTRL) result = true;
+ break;
+
+ case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+ result = true;
+ break;
+
+ case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
+ case AVRC_PDU_SET_ADDRESSED_PLAYER: /* 0x60 */
+ case AVRC_PDU_PLAY_ITEM: /* 0x74 */
+ case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
+ if (avc_type == AVRC_CMD_CTRL) result = true;
+ break;
+
+ case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
+ if (avc_type == AVRC_CMD_NOTIF) result = true;
+ break;
+ }
+ } else /* response msg */
+ {
+ if (avc_type >= AVRC_RSP_NOT_IMPL && avc_type <= AVRC_RSP_INTERIM)
+ result = true;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_is_valid_player_attrib_value
+ *
+ * Description Check if the given attrib value is valid for its attribute
+ *
+ * Returns returns true if it is valid
+ *
+ ******************************************************************************/
+bool avrc_is_valid_player_attrib_value(uint8_t attrib, uint8_t value) {
+ bool result = false;
+
+ switch (attrib) {
+ case AVRC_PLAYER_SETTING_EQUALIZER:
+ if ((value > 0) && (value <= AVRC_PLAYER_VAL_ON)) result = true;
+ break;
+
+ case AVRC_PLAYER_SETTING_REPEAT:
+ if ((value > 0) && (value <= AVRC_PLAYER_VAL_GROUP_REPEAT)) result = true;
+ break;
+
+ case AVRC_PLAYER_SETTING_SHUFFLE:
+ case AVRC_PLAYER_SETTING_SCAN:
+ if ((value > 0) && (value <= AVRC_PLAYER_VAL_GROUP_SHUFFLE))
+ result = true;
+ break;
+ }
+
+ if (attrib >= AVRC_PLAYER_SETTING_LOW_MENU_EXT) result = true;
+
+ if (!result) {
+ AVRC_TRACE_ERROR(" %s found not matching attrib(x%x)-value(x%x) pair!",
+ __func__, attrib, value);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function AVRC_IsValidPlayerAttr
+ *
+ * Description Check if the given attrib value is a valid one
+ *
+ * Returns returns true if it is valid
+ *
+ ******************************************************************************/
+bool AVRC_IsValidPlayerAttr(uint8_t attr) {
+ bool result = false;
+
+ if ((attr >= AVRC_PLAYER_SETTING_EQUALIZER &&
+ attr <= AVRC_PLAYER_SETTING_SCAN) ||
+ (attr >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) {
+ result = true;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_pars_pass_thru
+ *
+ * Description This function parses the pass thru commands defined by
+ * Bluetooth SIG
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+tAVRC_STS avrc_pars_pass_thru(tAVRC_MSG_PASS* p_msg,
+ uint16_t* p_vendor_unique_id) {
+ uint8_t* p_data;
+ uint32_t co_id;
+ uint16_t id;
+ tAVRC_STS status = AVRC_STS_BAD_CMD;
+
+ if (p_msg->op_id == AVRC_ID_VENDOR &&
+ p_msg->pass_len == AVRC_PASS_THRU_GROUP_LEN) {
+ p_data = p_msg->p_pass_data;
+ AVRC_BE_STREAM_TO_CO_ID(co_id, p_data);
+ if (co_id == AVRC_CO_METADATA) {
+ BE_STREAM_TO_UINT16(id, p_data);
+ if (AVRC_IS_VALID_GROUP(id)) {
+ *p_vendor_unique_id = id;
+ status = AVRC_STS_NO_ERROR;
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_opcode_from_pdu
+ *
+ * Description This function returns the opcode of the given pdu
+ *
+ * Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+ *
+ ******************************************************************************/
+uint8_t avrc_opcode_from_pdu(uint8_t pdu) {
+ uint8_t opcode = 0;
+
+ switch (pdu) {
+ case AVRC_PDU_SET_BROWSED_PLAYER:
+ case AVRC_PDU_GET_FOLDER_ITEMS:
+ case AVRC_PDU_CHANGE_PATH:
+ case AVRC_PDU_GET_ITEM_ATTRIBUTES:
+ case AVRC_PDU_SEARCH:
+ case AVRC_PDU_GENERAL_REJECT:
+ case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS:
+ opcode = AVRC_OP_BROWSE;
+ break;
+
+ case AVRC_PDU_NEXT_GROUP:
+ case AVRC_PDU_PREV_GROUP: /* pass thru */
+ opcode = AVRC_OP_PASS_THRU;
+ break;
+
+ default: /* vendor */
+ opcode = AVRC_OP_VENDOR;
+ break;
+ }
+
+ return opcode;
+}
+
+/*******************************************************************************
+ *
+ * Function avrc_is_valid_opcode
+ *
+ * Description This function returns the opcode of the given pdu
+ *
+ * Returns AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or AVRC_OP_BROWSE
+ *
+ ******************************************************************************/
+bool avrc_is_valid_opcode(uint8_t opcode) {
+ bool is_valid = false;
+ switch (opcode) {
+ case AVRC_OP_BROWSE:
+ case AVRC_OP_PASS_THRU:
+ case AVRC_OP_VENDOR:
+ is_valid = true;
+ break;
+ }
+ return is_valid;
+}
+
+#endif /* (AVRC_METADATA_INCLUDED == TRUE) */
diff --git a/mtkbt/code/bt/stack/bnep/bnep_api.cc b/mtkbt/code/bt/stack/bnep/bnep_api.cc
new file mode 100755
index 0000000..557e7f4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/bnep/bnep_api.cc
@@ -0,0 +1,693 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the BNEP API code
+ *
+ ******************************************************************************/
+
+#include "bnep_api.h"
+#include <string.h>
+#include "bnep_int.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function BNEP_Init
+ *
+ * Description This function initializes the BNEP unit. It should be called
+ * before accessing any other APIs to initialize the control
+ * block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BNEP_Init(void) {
+ memset(&bnep_cb, 0, sizeof(tBNEP_CB));
+
+#if defined(BNEP_INITIAL_TRACE_LEVEL)
+ bnep_cb.trace_level = BNEP_INITIAL_TRACE_LEVEL;
+#else
+ bnep_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_Register
+ *
+ * Description This function is called by the upper layer to register
+ * its callbacks with BNEP
+ *
+ * Parameters: p_reg_info - contains all callback function pointers
+ *
+ *
+ * Returns BNEP_SUCCESS if registered successfully
+ * BNEP_FAILURE if connection state callback is missing
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_Register(tBNEP_REGISTER* p_reg_info) {
+ /* There should be connection state call back registered */
+ if ((!p_reg_info) || (!(p_reg_info->p_conn_state_cb)))
+ return BNEP_SECURITY_FAIL;
+
+ bnep_cb.p_conn_ind_cb = p_reg_info->p_conn_ind_cb;
+ bnep_cb.p_conn_state_cb = p_reg_info->p_conn_state_cb;
+ bnep_cb.p_data_ind_cb = p_reg_info->p_data_ind_cb;
+ bnep_cb.p_data_buf_cb = p_reg_info->p_data_buf_cb;
+ bnep_cb.p_filter_ind_cb = p_reg_info->p_filter_ind_cb;
+ bnep_cb.p_mfilter_ind_cb = p_reg_info->p_mfilter_ind_cb;
+ bnep_cb.p_tx_data_flow_cb = p_reg_info->p_tx_data_flow_cb;
+
+ if (bnep_register_with_l2cap()) return BNEP_SECURITY_FAIL;
+
+ bnep_cb.profile_registered = true;
+ return BNEP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_Deregister
+ *
+ * Description This function is called by the upper layer to de-register
+ * its callbacks.
+ *
+ * Parameters: void
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BNEP_Deregister(void) {
+ /* Clear all the call backs registered */
+ bnep_cb.p_conn_ind_cb = NULL;
+ bnep_cb.p_conn_state_cb = NULL;
+ bnep_cb.p_data_ind_cb = NULL;
+ bnep_cb.p_data_buf_cb = NULL;
+ bnep_cb.p_filter_ind_cb = NULL;
+ bnep_cb.p_mfilter_ind_cb = NULL;
+
+ bnep_cb.profile_registered = false;
+ L2CA_Deregister(BT_PSM_BNEP);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_Connect
+ *
+ * Description This function creates a BNEP connection to a remote
+ * device.
+ *
+ * Parameters: p_rem_addr - BD_ADDR of the peer
+ * src_uuid - source uuid for the connection
+ * dst_uuid - destination uuid for the connection
+ * p_handle - pointer to return the handle for the
+ * connection
+ *
+ * Returns BNEP_SUCCESS if connection started
+ * BNEP_NO_RESOURCES if no resources
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_Connect(BD_ADDR p_rem_bda, tBT_UUID* src_uuid,
+ tBT_UUID* dst_uuid, uint16_t* p_handle) {
+ uint16_t cid;
+ tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(p_rem_bda);
+
+ BNEP_TRACE_API("BNEP_Connect() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_rem_bda[0], p_rem_bda[1], p_rem_bda[2], p_rem_bda[3],
+ p_rem_bda[4], p_rem_bda[5]);
+
+ if (!bnep_cb.profile_registered) return BNEP_WRONG_STATE;
+
+ /* Both source and destination UUID lengths should be same */
+ if (src_uuid->len != dst_uuid->len) return BNEP_CONN_FAILED_UUID_SIZE;
+
+ if (!p_bcb) {
+ p_bcb = bnepu_allocate_bcb(p_rem_bda);
+ if (p_bcb == NULL) return (BNEP_NO_RESOURCES);
+ } else if (p_bcb->con_state != BNEP_STATE_CONNECTED)
+ return BNEP_WRONG_STATE;
+ else {
+ /* Backup current UUID values to restore if role change fails */
+ memcpy((uint8_t*)&(p_bcb->prv_src_uuid), (uint8_t*)&(p_bcb->src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->prv_dst_uuid), (uint8_t*)&(p_bcb->dst_uuid),
+ sizeof(tBT_UUID));
+ }
+
+ /* We are the originator of this connection */
+ p_bcb->con_flags |= BNEP_FLAGS_IS_ORIG;
+
+ memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)src_uuid, sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)dst_uuid, sizeof(tBT_UUID));
+
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
+ /* Transition to the next appropriate state, waiting for connection confirm.
+ */
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ BNEP_TRACE_API("BNEP initiating security procedures for src uuid 0x%x",
+ p_bcb->src_uuid.uu.uuid16);
+
+#if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == TRUE)
+ btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
+ BTM_SEC_PROTO_BNEP, bnep_get_uuid32(src_uuid),
+ &bnep_sec_check_complete, p_bcb);
+#else
+ bnep_sec_check_complete(p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+#endif
+
+ } else {
+ /* Transition to the next appropriate state, waiting for connection confirm.
+ */
+ p_bcb->con_state = BNEP_STATE_CONN_START;
+
+ cid = L2CA_ConnectReq(BT_PSM_BNEP, p_bcb->rem_bda);
+ if (cid != 0) {
+ p_bcb->l2cap_cid = cid;
+
+ } else {
+ BNEP_TRACE_ERROR("BNEP - Originate failed");
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED, false);
+ bnepu_release_bcb(p_bcb);
+ return BNEP_CONN_FAILED;
+ }
+
+ /* Start timer waiting for connect */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+ }
+
+ *p_handle = p_bcb->handle;
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_ConnectResp
+ *
+ * Description This function is called in responce to connection indication
+ *
+ *
+ * Parameters: handle - handle given in the connection indication
+ * resp - responce for the connection indication
+ *
+ * Returns BNEP_SUCCESS if connection started
+ * BNEP_WRONG_HANDLE if the connection is not found
+ * BNEP_WRONG_STATE if the responce is not expected
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_ConnectResp(uint16_t handle, tBNEP_RESULT resp) {
+ tBNEP_CONN* p_bcb;
+ uint16_t resp_code = BNEP_SETUP_CONN_OK;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP ||
+ (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)))
+ return (BNEP_WRONG_STATE);
+
+ BNEP_TRACE_API("BNEP_ConnectResp() for handle %d, responce %d", handle,
+ resp);
+
+ /* Form appropriate responce based on profile responce */
+ if (resp == BNEP_CONN_FAILED_SRC_UUID)
+ resp_code = BNEP_SETUP_INVALID_SRC_UUID;
+ else if (resp == BNEP_CONN_FAILED_DST_UUID)
+ resp_code = BNEP_SETUP_INVALID_DEST_UUID;
+ else if (resp == BNEP_CONN_FAILED_UUID_SIZE)
+ resp_code = BNEP_SETUP_INVALID_UUID_SIZE;
+ else if (resp == BNEP_SUCCESS)
+ resp_code = BNEP_SETUP_CONN_OK;
+ else
+ resp_code = BNEP_SETUP_CONN_NOT_ALLOWED;
+
+ bnep_send_conn_responce(p_bcb, resp_code);
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ if (resp == BNEP_SUCCESS)
+ bnep_connected(p_bcb);
+ else if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
+ /* Restore the original parameters */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
+ sizeof(tBT_UUID));
+ }
+
+ /* Process remaining part of the setup message (extension headers) */
+ if (p_bcb->p_pending_data) {
+ uint8_t extension_present = true, *p, ext_type;
+ uint16_t rem_len;
+
+ rem_len = p_bcb->p_pending_data->len;
+ p = (uint8_t*)(p_bcb->p_pending_data + 1) + p_bcb->p_pending_data->offset;
+ while (extension_present && p && rem_len) {
+ ext_type = *p++;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type) break;
+
+ p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
+ }
+
+ osi_free_and_reset((void**)&p_bcb->p_pending_data);
+ }
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_Disconnect
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - handle of the connection
+ *
+ * Returns BNEP_SUCCESS if connection is disconnected
+ * BNEP_WRONG_HANDLE if no connection is not found
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_Disconnect(uint16_t handle) {
+ tBNEP_CONN* p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ if (p_bcb->con_state == BNEP_STATE_IDLE) return (BNEP_WRONG_HANDLE);
+
+ BNEP_TRACE_API("BNEP_Disconnect() for handle %d", handle);
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ bnepu_release_bcb(p_bcb);
+
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_WriteBuf
+ *
+ * Description This function sends data in a GKI buffer on BNEP connection
+ *
+ * Parameters: handle - handle of the connection to write
+ * p_dest_addr - BD_ADDR/Ethernet addr of the destination
+ * p_buf - pointer to address of buffer with data
+ * protocol - protocol type of the packet
+ * p_src_addr - (optional) BD_ADDR/ethernet address of the
+ * source
+ * (should be NULL if it is local BD Addr)
+ * fw_ext_present - forwarded extensions present
+ *
+ * Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+ * BNEP_MTU_EXCEDED - If the data length is greater than
+ * the MTU
+ * BNEP_IGNORE_CMD - If the packet is filtered out
+ * BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+ * BNEP_SUCCESS - If written successfully
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, uint8_t* p_dest_addr, BT_HDR* p_buf,
+ uint16_t protocol, uint8_t* p_src_addr,
+ bool fw_ext_present) {
+ tBNEP_CONN* p_bcb;
+ uint8_t* p_data;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) {
+ osi_free(p_buf);
+ return (BNEP_WRONG_HANDLE);
+ }
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+ /* Check MTU size */
+ if (p_buf->len > BNEP_MTU_SIZE) {
+ BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", p_buf->len,
+ BNEP_MTU_SIZE);
+ osi_free(p_buf);
+ return (BNEP_MTU_EXCEDED);
+ }
+
+ /* Check if the packet should be filtered out */
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
+ p_data) != BNEP_SUCCESS) {
+ /*
+ ** If packet is filtered and ext headers are present
+ ** drop the data and forward the ext headers
+ */
+ if (fw_ext_present) {
+ uint8_t ext, length;
+ uint16_t org_len, new_len;
+ /* parse the extension headers and findout the new packet len */
+ org_len = p_buf->len;
+ new_len = 0;
+ do {
+ ext = *p_data++;
+ length = *p_data++;
+ p_data += length;
+
+ new_len += (length + 2);
+
+ if (new_len > org_len) {
+ osi_free(p_buf);
+ return BNEP_IGNORE_CMD;
+ }
+
+ } while (ext & 0x80);
+
+ if (protocol != BNEP_802_1_P_PROTOCOL)
+ protocol = 0;
+ else {
+ new_len += 4;
+ p_data[2] = 0;
+ p_data[3] = 0;
+ }
+ p_buf->len = new_len;
+ } else {
+ osi_free(p_buf);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+
+ /* Check transmit queue */
+ if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH) {
+ osi_free(p_buf);
+ return (BNEP_Q_SIZE_EXCEEDED);
+ }
+
+ /* Build the BNEP header */
+ bnepu_build_bnep_hdr(p_bcb, p_buf, protocol, p_src_addr, p_dest_addr,
+ fw_ext_present);
+
+ /* Send the data or queue it up */
+ bnepu_check_send_packet(p_bcb, p_buf);
+
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_Write
+ *
+ * Description This function sends data over a BNEP connection
+ *
+ * Parameters: handle - handle of the connection to write
+ * p_dest_addr - BD_ADDR/Ethernet addr of the destination
+ * p_data - pointer to data start
+ * protocol - protocol type of the packet
+ * p_src_addr - (optional) BD_ADDR/ethernet address of the
+ * source
+ * (should be NULL if it is local BD Addr)
+ * fw_ext_present - forwarded extensions present
+ *
+ * Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+ * BNEP_MTU_EXCEDED - If the data length is greater than
+ * the MTU
+ * BNEP_IGNORE_CMD - If the packet is filtered out
+ * BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+ * BNEP_NO_RESOURCES - If not able to allocate a buffer
+ * BNEP_SUCCESS - If written successfully
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_Write(uint16_t handle, uint8_t* p_dest_addr, uint8_t* p_data,
+ uint16_t len, uint16_t protocol, uint8_t* p_src_addr,
+ bool fw_ext_present) {
+ tBNEP_CONN* p_bcb;
+ uint8_t* p;
+
+ /* Check MTU size. Consider the possibility of having extension headers */
+ if (len > BNEP_MTU_SIZE) {
+ BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", len,
+ BNEP_MTU_SIZE);
+ return (BNEP_MTU_EXCEDED);
+ }
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check if the packet should be filtered out */
+ if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
+ p_data) != BNEP_SUCCESS) {
+ /*
+ ** If packet is filtered and ext headers are present
+ ** drop the data and forward the ext headers
+ */
+ if (fw_ext_present) {
+ uint8_t ext, length;
+ uint16_t org_len, new_len;
+ /* parse the extension headers and findout the new packet len */
+ org_len = len;
+ new_len = 0;
+ p = p_data;
+ do {
+ ext = *p_data++;
+ length = *p_data++;
+ p_data += length;
+
+ new_len += (length + 2);
+
+ if (new_len > org_len) return BNEP_IGNORE_CMD;
+
+ } while (ext & 0x80);
+
+ if (protocol != BNEP_802_1_P_PROTOCOL)
+ protocol = 0;
+ else {
+ new_len += 4;
+ p_data[2] = 0;
+ p_data[3] = 0;
+ }
+ len = new_len;
+ p_data = p;
+ } else
+ return BNEP_IGNORE_CMD;
+ }
+
+ /* Check transmit queue */
+ if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH)
+ return (BNEP_Q_SIZE_EXCEEDED);
+
+ /* Get a buffer to copy the data into */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+
+ p_buf->len = len;
+ p_buf->offset = BNEP_MINIMUM_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + BNEP_MINIMUM_OFFSET;
+
+ memcpy(p, p_data, len);
+
+ /* Build the BNEP header */
+ bnepu_build_bnep_hdr(p_bcb, p_buf, protocol, p_src_addr, p_dest_addr,
+ fw_ext_present);
+
+ /* Send the data or queue it up */
+ bnepu_check_send_packet(p_bcb, p_buf);
+
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetProtocolFilters
+ *
+ * Description This function sets the protocol filters on peer device
+ *
+ * Parameters: handle - Handle for the connection
+ * num_filters - total number of filter ranges
+ * p_start_array - Array of beginings of all protocol ranges
+ * p_end_array - Array of ends of all protocol ranges
+ *
+ * Returns BNEP_WRONG_HANDLE - if the connection handle is
+ * not valid
+ * BNEP_SET_FILTER_FAIL - if the connection is in wrong
+ * state
+ * BNEP_TOO_MANY_FILTERS - if too many filters
+ * BNEP_SUCCESS - if request sent successfully
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_SetProtocolFilters(uint16_t handle, uint16_t num_filters,
+ uint16_t* p_start_array,
+ uint16_t* p_end_array) {
+ uint16_t xx;
+ tBNEP_CONN* p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check the connection state */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return (BNEP_WRONG_STATE);
+
+ /* Validate the parameters */
+ if (num_filters && (!p_start_array || !p_end_array))
+ return (BNEP_SET_FILTER_FAIL);
+
+ if (num_filters > BNEP_MAX_PROT_FILTERS) return (BNEP_TOO_MANY_FILTERS);
+
+ /* Fill the filter values in connnection block */
+ for (xx = 0; xx < num_filters; xx++) {
+ p_bcb->sent_prot_filter_start[xx] = *p_start_array++;
+ p_bcb->sent_prot_filter_end[xx] = *p_end_array++;
+ }
+
+ p_bcb->sent_num_filters = num_filters;
+
+ bnepu_send_peer_our_filters(p_bcb);
+
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetMulticastFilters
+ *
+ * Description This function sets the filters for multicast addresses for
+ * BNEP.
+ *
+ * Parameters: handle - Handle for the connection
+ * num_filters - total number of filter ranges
+ * p_start_array - Pointer to sequence of beginings of all
+ * multicast address ranges
+ * p_end_array - Pointer to sequence of ends of all
+ * multicast address ranges
+ *
+ * Returns BNEP_WRONG_HANDLE - if the connection handle is
+ * not valid
+ * BNEP_SET_FILTER_FAIL - if the connection is in wrong
+ * state
+ * BNEP_TOO_MANY_FILTERS - if too many filters
+ * BNEP_SUCCESS - if request sent successfully
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle, uint16_t num_filters,
+ uint8_t* p_start_array,
+ uint8_t* p_end_array) {
+ uint16_t xx;
+ tBNEP_CONN* p_bcb;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ /* Check the connection state */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return (BNEP_WRONG_STATE);
+
+ /* Validate the parameters */
+ if (num_filters && (!p_start_array || !p_end_array))
+ return (BNEP_SET_FILTER_FAIL);
+
+ if (num_filters > BNEP_MAX_MULTI_FILTERS) return (BNEP_TOO_MANY_FILTERS);
+
+ /* Fill the multicast filter values in connnection block */
+ for (xx = 0; xx < num_filters; xx++) {
+ memcpy(p_bcb->sent_mcast_filter_start[xx], p_start_array, BD_ADDR_LEN);
+ memcpy(p_bcb->sent_mcast_filter_end[xx], p_end_array, BD_ADDR_LEN);
+
+ p_start_array += BD_ADDR_LEN;
+ p_end_array += BD_ADDR_LEN;
+ }
+
+ p_bcb->sent_mcast_filters = num_filters;
+
+ bnepu_send_peer_our_multi_filters(p_bcb);
+
+ return (BNEP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetTraceLevel
+ *
+ * Description This function sets the trace level for BNEP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t BNEP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) bnep_cb.trace_level = new_level;
+
+ return (bnep_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function BNEP_GetStatus
+ *
+ * Description This function gets the status information for BNEP
+ * connection
+ *
+ * Returns BNEP_SUCCESS - if the status is available
+ * BNEP_NO_RESOURCES - if no structure is passed for
+ * output
+ * BNEP_WRONG_HANDLE - if the handle is invalid
+ * BNEP_WRONG_STATE - if not in connected state
+ *
+ ******************************************************************************/
+tBNEP_RESULT BNEP_GetStatus(uint16_t handle, tBNEP_STATUS* p_status) {
+#if (BNEP_SUPPORTS_STATUS_API == TRUE)
+ tBNEP_CONN* p_bcb;
+
+ if (!p_status) return BNEP_NO_RESOURCES;
+
+ if ((!handle) || (handle > BNEP_MAX_CONNECTIONS)) return (BNEP_WRONG_HANDLE);
+
+ p_bcb = &(bnep_cb.bcb[handle - 1]);
+
+ memset(p_status, 0, sizeof(tBNEP_STATUS));
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ return BNEP_WRONG_STATE;
+
+ /* Read the status parameters from the connection control block */
+ p_status->con_status = BNEP_STATUS_CONNECTED;
+ p_status->l2cap_cid = p_bcb->l2cap_cid;
+ p_status->rem_mtu_size = p_bcb->rem_mtu_size;
+ p_status->xmit_q_depth = fixed_queue_length(p_bcb->xmit_q);
+ p_status->sent_num_filters = p_bcb->sent_num_filters;
+ p_status->sent_mcast_filters = p_bcb->sent_mcast_filters;
+ p_status->rcvd_num_filters = p_bcb->rcvd_num_filters;
+ p_status->rcvd_mcast_filters = p_bcb->rcvd_mcast_filters;
+
+ memcpy(p_status->rem_bda, p_bcb->rem_bda, BD_ADDR_LEN);
+ memcpy(&(p_status->src_uuid), &(p_bcb->src_uuid), sizeof(tBT_UUID));
+ memcpy(&(p_status->dst_uuid), &(p_bcb->dst_uuid), sizeof(tBT_UUID));
+
+ return BNEP_SUCCESS;
+#else
+ return (BNEP_IGNORE_CMD);
+#endif
+}
diff --git a/mtkbt/code/bt/stack/bnep/bnep_int.h b/mtkbt/code/bt/stack/bnep/bnep_int.h
new file mode 100755
index 0000000..9703963
--- a/dev/null
+++ b/mtkbt/code/bt/stack/bnep/bnep_int.h
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used BNEP definitions
+ *
+ ******************************************************************************/
+
+#ifndef BNEP_INT_H
+#define BNEP_INT_H
+
+#include "bnep_api.h"
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+
+/* BNEP frame types
+*/
+#define BNEP_FRAME_GENERAL_ETHERNET 0x00
+#define BNEP_FRAME_CONTROL 0x01
+#define BNEP_FRAME_COMPRESSED_ETHERNET 0x02
+#define BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY 0x03
+#define BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY 0x04
+
+/* BNEP filter control message types
+*/
+#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD 0x00
+#define BNEP_SETUP_CONNECTION_REQUEST_MSG 0x01
+#define BNEP_SETUP_CONNECTION_RESPONSE_MSG 0x02
+#define BNEP_FILTER_NET_TYPE_SET_MSG 0x03
+#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG 0x04
+#define BNEP_FILTER_MULTI_ADDR_SET_MSG 0x05
+#define BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG 0x06
+
+/* BNEP header extension types
+*/
+#define BNEP_EXTENSION_FILTER_CONTROL 0x00
+
+/* BNEP Setup Connection response codes
+*/
+#define BNEP_SETUP_CONN_OK 0x0000
+#define BNEP_SETUP_INVALID_DEST_UUID 0x0001
+#define BNEP_SETUP_INVALID_SRC_UUID 0x0002
+#define BNEP_SETUP_INVALID_UUID_SIZE 0x0003
+#define BNEP_SETUP_CONN_NOT_ALLOWED 0x0004
+
+/* BNEP filter control response codes
+*/
+#define BNEP_FILTER_CRL_OK 0x0000
+#define BNEP_FILTER_CRL_UNSUPPORTED 0x0001
+#define BNEP_FILTER_CRL_BAD_RANGE 0x0002
+#define BNEP_FILTER_CRL_MAX_REACHED 0x0003
+#define BNEP_FILTER_CRL_SECURITY_ERR 0x0004
+
+/* 802.1p protocol packet will have actual protocol field in side the payload */
+#define BNEP_802_1_P_PROTOCOL 0x8100
+
+/* Timeout definitions. */
+/* Connection related timeout */
+#define BNEP_CONN_TIMEOUT_MS (20 * 1000)
+/* host response timeout */
+#define BNEP_HOST_TIMEOUT_MS (200 * 1000)
+#define BNEP_FILTER_SET_TIMEOUT_MS (10 * 1000)
+
+/* Define the Out-Flow default values. */
+#define BNEP_OFLOW_QOS_FLAG 0
+#define BNEP_OFLOW_SERV_TYPE 0
+#define BNEP_OFLOW_TOKEN_RATE 0
+#define BNEP_OFLOW_TOKEN_BUCKET_SIZE 0
+#define BNEP_OFLOW_PEAK_BANDWIDTH 0
+#define BNEP_OFLOW_LATENCY 0
+#define BNEP_OFLOW_DELAY_VARIATION 0
+
+/* Define the In-Flow default values. */
+#define BNEP_IFLOW_QOS_FLAG 0
+#define BNEP_IFLOW_SERV_TYPE 0
+#define BNEP_IFLOW_TOKEN_RATE 0
+#define BNEP_IFLOW_TOKEN_BUCKET_SIZE 0
+#define BNEP_IFLOW_PEAK_BANDWIDTH 0
+#define BNEP_IFLOW_LATENCY 0
+#define BNEP_IFLOW_DELAY_VARIATION 0
+
+#define BNEP_FLUSH_TO 0xFFFF
+
+#define BNEP_MAX_RETRANSMITS 3
+
+/* Define the BNEP Connection Control Block
+*/
+typedef struct {
+#define BNEP_STATE_IDLE 0
+#define BNEP_STATE_CONN_START 1
+#define BNEP_STATE_CFG_SETUP 2
+#define BNEP_STATE_CONN_SETUP 3
+#define BNEP_STATE_SEC_CHECKING 4
+#define BNEP_STATE_SETUP_RCVD 5
+#define BNEP_STATE_CONNECTED 6
+ uint8_t con_state;
+
+#define BNEP_FLAGS_IS_ORIG 0x01
+#define BNEP_FLAGS_HIS_CFG_DONE 0x02
+#define BNEP_FLAGS_MY_CFG_DONE 0x04
+#define BNEP_FLAGS_L2CAP_CONGESTED 0x08
+#define BNEP_FLAGS_FILTER_RESP_PEND 0x10
+#define BNEP_FLAGS_MULTI_RESP_PEND 0x20
+#define BNEP_FLAGS_SETUP_RCVD 0x40
+#define BNEP_FLAGS_CONN_COMPLETED 0x80
+ uint8_t con_flags;
+ BT_HDR* p_pending_data;
+
+ uint16_t l2cap_cid;
+ BD_ADDR rem_bda;
+ uint16_t rem_mtu_size;
+ alarm_t* conn_timer;
+ fixed_queue_t* xmit_q;
+
+ uint16_t sent_num_filters;
+ uint16_t sent_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+ uint16_t sent_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+ uint16_t sent_mcast_filters;
+ BD_ADDR sent_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+ BD_ADDR sent_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+ uint16_t rcvd_num_filters;
+ uint16_t rcvd_prot_filter_start[BNEP_MAX_PROT_FILTERS];
+ uint16_t rcvd_prot_filter_end[BNEP_MAX_PROT_FILTERS];
+
+ uint16_t rcvd_mcast_filters;
+ BD_ADDR rcvd_mcast_filter_start[BNEP_MAX_MULTI_FILTERS];
+ BD_ADDR rcvd_mcast_filter_end[BNEP_MAX_MULTI_FILTERS];
+
+ uint16_t bad_pkts_rcvd;
+ uint8_t re_transmits;
+ uint16_t handle;
+ tBT_UUID prv_src_uuid;
+ tBT_UUID prv_dst_uuid;
+ tBT_UUID src_uuid;
+ tBT_UUID dst_uuid;
+
+} tBNEP_CONN;
+
+/* The main BNEP control block
+*/
+typedef struct {
+ tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */
+ tBNEP_CONN bcb[BNEP_MAX_CONNECTIONS];
+
+ tBNEP_CONNECT_IND_CB* p_conn_ind_cb;
+ tBNEP_CONN_STATE_CB* p_conn_state_cb;
+ tBNEP_DATA_IND_CB* p_data_ind_cb;
+ tBNEP_DATA_BUF_CB* p_data_buf_cb;
+ tBNEP_FILTER_IND_CB* p_filter_ind_cb;
+ tBNEP_MFILTER_IND_CB* p_mfilter_ind_cb;
+ tBNEP_TX_DATA_FLOW_CB* p_tx_data_flow_cb;
+
+ tL2CAP_APPL_INFO reg_info;
+
+ bool profile_registered; /* true when we got our BD addr */
+ uint8_t trace_level;
+
+} tBNEP_CB;
+
+/* Global BNEP data
+*/
+extern tBNEP_CB bnep_cb;
+
+/* Functions provided by bnep_main.cc
+*/
+extern tBNEP_RESULT bnep_register_with_l2cap(void);
+extern void bnep_disconnect(tBNEP_CONN* p_bcb, uint16_t reason);
+extern tBNEP_CONN* bnep_conn_originate(uint8_t* p_bd_addr);
+extern void bnep_conn_timer_timeout(void* data);
+extern void bnep_connected(tBNEP_CONN* p_bcb);
+
+/* Functions provided by bnep_utils.cc
+*/
+extern tBNEP_CONN* bnepu_find_bcb_by_cid(uint16_t cid);
+extern tBNEP_CONN* bnepu_find_bcb_by_bd_addr(uint8_t* p_bda);
+extern tBNEP_CONN* bnepu_allocate_bcb(BD_ADDR p_rem_bda);
+extern void bnepu_release_bcb(tBNEP_CONN* p_bcb);
+extern void bnepu_send_peer_our_filters(tBNEP_CONN* p_bcb);
+extern void bnepu_send_peer_our_multi_filters(tBNEP_CONN* p_bcb);
+extern bool bnepu_does_dest_support_prot(tBNEP_CONN* p_bcb, uint16_t protocol);
+extern void bnepu_build_bnep_hdr(tBNEP_CONN* p_bcb, BT_HDR* p_buf,
+ uint16_t protocol, uint8_t* p_src_addr,
+ uint8_t* p_dest_addr, bool ext_bit);
+extern void test_bnepu_build_bnep_hdr(tBNEP_CONN* p_bcb, BT_HDR* p_buf,
+ uint16_t protocol, uint8_t* p_src_addr,
+ uint8_t* p_dest_addr, uint8_t type);
+
+extern tBNEP_CONN* bnepu_get_route_to_dest(uint8_t* p_bda);
+extern void bnepu_check_send_packet(tBNEP_CONN* p_bcb, BT_HDR* p_buf);
+extern void bnep_send_command_not_understood(tBNEP_CONN* p_bcb,
+ uint8_t cmd_code);
+extern void bnepu_process_peer_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters,
+ uint16_t len);
+extern void bnepu_process_peer_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data);
+extern void bnepu_process_multicast_filter_rsp(tBNEP_CONN* p_bcb,
+ uint8_t* p_data);
+extern void bnep_send_conn_req(tBNEP_CONN* p_bcb);
+extern void bnep_send_conn_responce(tBNEP_CONN* p_bcb, uint16_t resp_code);
+extern void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup,
+ uint8_t len);
+extern void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb,
+ uint8_t* p_setup);
+extern uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p,
+ uint16_t* len, bool is_ext);
+extern void bnep_sec_check_complete(BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+ void* p_ref_data, uint8_t result);
+extern tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb,
+ BD_ADDR p_dest_addr,
+ uint16_t protocol,
+ bool fw_ext_present,
+ uint8_t* p_data);
+extern uint32_t bnep_get_uuid32(tBT_UUID* src_uuid);
+
+#endif
diff --git a/mtkbt/code/bt/stack/bnep/bnep_main.cc b/mtkbt/code/bt/stack/bnep/bnep_main.cc
new file mode 100755
index 0000000..b0fad6a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/bnep/bnep_main.cc
@@ -0,0 +1,734 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main BNEP functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bt_target.h"
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btm_api.h"
+#include "btu.h"
+
+#include "bnep_api.h"
+#include "bnep_int.h"
+#include "bt_utils.h"
+
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* G L O B A L B N E P D A T A */
+/******************************************************************************/
+tBNEP_CB bnep_cb;
+
+const uint16_t bnep_frame_hdr_sizes[] = {14, 1, 2, 8, 8};
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void bnep_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
+ uint8_t l2cap_id);
+static void bnep_connect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void bnep_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void bnep_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void bnep_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
+static void bnep_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
+static void bnep_congestion_ind(uint16_t lcid, bool is_congested);
+
+/*******************************************************************************
+ *
+ * Function bnep_register_with_l2cap
+ *
+ * Description This function registers BNEP PSM with L2CAP
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBNEP_RESULT bnep_register_with_l2cap(void) {
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ memset(&bnep_cb.l2cap_my_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ bnep_cb.l2cap_my_cfg.mtu_present = true;
+ bnep_cb.l2cap_my_cfg.mtu = BNEP_MTU_SIZE;
+ bnep_cb.l2cap_my_cfg.flush_to_present = true;
+ bnep_cb.l2cap_my_cfg.flush_to = BNEP_FLUSH_TO;
+
+ bnep_cb.reg_info.pL2CA_ConnectInd_Cb = bnep_connect_ind;
+ bnep_cb.reg_info.pL2CA_ConnectCfm_Cb = bnep_connect_cfm;
+ bnep_cb.reg_info.pL2CA_ConfigInd_Cb = bnep_config_ind;
+ bnep_cb.reg_info.pL2CA_ConfigCfm_Cb = bnep_config_cfm;
+ bnep_cb.reg_info.pL2CA_DisconnectInd_Cb = bnep_disconnect_ind;
+ bnep_cb.reg_info.pL2CA_DisconnectCfm_Cb = bnep_disconnect_cfm;
+ bnep_cb.reg_info.pL2CA_DataInd_Cb = bnep_data_ind;
+ bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register(BT_PSM_BNEP, &bnep_cb.reg_info)) {
+ BNEP_TRACE_ERROR("BNEP - Registration failed");
+ return BNEP_SECURITY_FAIL;
+ }
+
+ return BNEP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_connect_ind
+ *
+ * Description This function handles an inbound connection indication
+ * from L2CAP. This is the case where we are acting as a
+ * server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ UNUSED_ATTR uint16_t psm, uint8_t l2cap_id) {
+ tBNEP_CONN* p_bcb = bnepu_find_bcb_by_bd_addr(bd_addr);
+
+ /* If we are not acting as server, or already have a connection, or have */
+ /* no more resources to handle the connection, reject the connection. */
+ if (!(bnep_cb.profile_registered) || (p_bcb) ||
+ ((p_bcb = bnepu_allocate_bcb(bd_addr)) == NULL)) {
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+ /* Save the L2CAP Channel ID. */
+ p_bcb->l2cap_cid = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq(l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+ /* Start timer waiting for config setup */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+
+ BNEP_TRACE_EVENT("BNEP - Rcvd L2CAP conn ind, CID: 0x%x", p_bcb->l2cap_cid);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_connect_cfm
+ *
+ * Description This function handles the connect confirm events
+ * from L2CAP. This is the case when we are acting as a
+ * client and have sent a connect request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
+ tBNEP_CONN* p_bcb;
+
+ /* Find CCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) &&
+ (p_bcb->con_state == BNEP_STATE_CONN_START)) {
+ p_bcb->con_state = BNEP_STATE_CFG_SETUP;
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq(l2cap_cid, &bnep_cb.l2cap_my_cfg);
+
+ /* Start timer waiting for config results */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+
+ BNEP_TRACE_EVENT("BNEP - got conn cnf, sent cfg req, CID: 0x%x",
+ p_bcb->l2cap_cid);
+ } else {
+ BNEP_TRACE_WARNING("BNEP - Rcvd conn cnf with error: 0x%x CID 0x%x",
+ result, p_bcb->l2cap_cid);
+
+ /* Tell the upper layer, if he has a callback */
+ if (bnep_cb.p_conn_state_cb && p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED, false);
+ }
+
+ bnepu_release_bcb(p_bcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_config_ind
+ *
+ * Description This function processes the L2CAP configuration indication
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tBNEP_CONN* p_bcb;
+ uint16_t result, mtu = 0;
+
+ /* Find CCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ BNEP_TRACE_EVENT("BNEP - Rcvd cfg ind, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu < BNEP_MIN_MTU_SIZE)) {
+ mtu = p_cfg->mtu;
+ p_cfg->flush_to_present = false;
+ p_cfg->mtu_present = true;
+ p_cfg->mtu = BNEP_MIN_MTU_SIZE;
+ p_cfg->result = result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ } else {
+ if (p_cfg->mtu > BNEP_MTU_SIZE)
+ p_bcb->rem_mtu_size = BNEP_MTU_SIZE;
+ else
+ p_bcb->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = false;
+ p_cfg->mtu_present = false;
+ p_cfg->result = result = L2CAP_CFG_OK;
+ }
+
+ L2CA_ConfigRsp(l2cap_cid, p_cfg);
+
+ if (result != L2CAP_CFG_OK) {
+ BNEP_TRACE_EVENT("BNEP - Rcvd cfg ind with bad MTU %d, CID: 0x%x", mtu,
+ l2cap_cid);
+ return;
+ }
+
+ p_bcb->con_flags |= BNEP_FLAGS_HIS_CFG_DONE;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_MY_CFG_DONE) {
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ /* Start timer waiting for setup or response */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+
+ if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
+ btm_sec_mx_access_request(
+ p_bcb->rem_bda, BT_PSM_BNEP, true, BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(&(p_bcb->src_uuid)), &bnep_sec_check_complete, p_bcb);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_config_cfm
+ *
+ * Description This function processes the L2CAP configuration confirmation
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tBNEP_CONN* p_bcb;
+
+ BNEP_TRACE_EVENT("BNEP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid,
+ p_cfg->result);
+
+ /* Find CCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd L2CAP cfg ind, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ p_bcb->con_flags |= BNEP_FLAGS_MY_CFG_DONE;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_HIS_CFG_DONE) {
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+
+ /* Start timer waiting for setup or response */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_HOST_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb,
+ btu_general_alarm_queue);
+
+ if (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) {
+ btm_sec_mx_access_request(p_bcb->rem_bda, BT_PSM_BNEP, true,
+ BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(&(p_bcb->src_uuid)),
+ &bnep_sec_check_complete, p_bcb);
+ }
+ }
+ } else {
+ /* Tell the upper layer, if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb)) {
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED_CFG, false);
+ }
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ bnepu_release_bcb(p_bcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_disconnect_ind
+ *
+ * Description This function handles a disconnect event from L2CAP. If
+ * requested to, we ack the disconnect before dropping the CCB
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
+ tBNEP_CONN* p_bcb;
+
+ if (ack_needed) L2CA_DisconnectRsp(l2cap_cid);
+
+ /* Find CCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ BNEP_TRACE_EVENT("BNEP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_DISCONNECTED, false);
+ } else {
+ if ((bnep_cb.p_conn_state_cb) &&
+ ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) ||
+ (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)))
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED, false);
+ }
+
+ bnepu_release_bcb(p_bcb);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_disconnect_cfm
+ *
+ * Description This function gets the disconnect confirm event from L2CAP
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_disconnect_cfm(uint16_t l2cap_cid, uint16_t result) {
+ BNEP_TRACE_EVENT("BNEP - Rcvd L2CAP disc cfm, CID: 0x%x, Result 0x%x",
+ l2cap_cid, result);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_congestion_ind
+ *
+ * Description This is a callback function called by L2CAP when
+ * congestion status changes
+ *
+ ******************************************************************************/
+static void bnep_congestion_ind(uint16_t l2cap_cid, bool is_congested) {
+ tBNEP_CONN* p_bcb;
+
+ /* Find BCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd L2CAP cong, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (is_congested) {
+ p_bcb->con_flags |= BNEP_FLAGS_L2CAP_CONGESTED;
+ if (bnep_cb.p_tx_data_flow_cb) {
+ bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_OFF);
+ }
+ } else {
+ p_bcb->con_flags &= ~BNEP_FLAGS_L2CAP_CONGESTED;
+
+ if (bnep_cb.p_tx_data_flow_cb) {
+ bnep_cb.p_tx_data_flow_cb(p_bcb->handle, BNEP_TX_FLOW_ON);
+ }
+
+ /* While not congested, send as many buffers as we can */
+ while (!(p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED)) {
+ BT_HDR* p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_bcb->xmit_q);
+
+ if (!p_buf) break;
+
+ L2CA_DataWrite(l2cap_cid, p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ * if we are the originator of the connection, we are the SDP
+ * client, and the received message is queued for the client.
+ *
+ * If we are the destination of the connection, we are the SDP
+ * server, so the message is passed to the server processing
+ * function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void bnep_data_ind(uint16_t l2cap_cid, BT_HDR* p_buf) {
+ tBNEP_CONN* p_bcb;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint16_t rem_len = p_buf->len;
+ uint8_t type, ctrl_type, ext_type = 0;
+ bool extension_present, fw_ext_present;
+ uint16_t protocol = 0;
+ uint8_t *p_src_addr, *p_dst_addr;
+
+ /* Find CCB based on CID */
+ p_bcb = bnepu_find_bcb_by_cid(l2cap_cid);
+ if (p_bcb == NULL) {
+ BNEP_TRACE_WARNING("BNEP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* Get the type and extension bits */
+ type = *p++;
+ extension_present = type >> 7;
+ type &= 0x7f;
+ if ((rem_len <= bnep_frame_hdr_sizes[type]) || (rem_len > BNEP_MTU_SIZE)) {
+ BNEP_TRACE_EVENT("BNEP - rcvd frame, bad len: %d type: 0x%02x", p_buf->len,
+ type);
+ osi_free(p_buf);
+ return;
+ }
+
+ rem_len--;
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)) &&
+ (type != BNEP_FRAME_CONTROL)) {
+ BNEP_TRACE_WARNING(
+ "BNEP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+ p_bcb->con_state, l2cap_cid);
+
+ if (extension_present) {
+ /*
+ ** When there is no connection if a data packet is received
+ ** with unknown control extension headers then those should be processed
+ ** according to complain/ignore law
+ */
+ uint8_t ext, length;
+ uint16_t org_len, new_len;
+ /* parse the extension headers and process unknown control headers */
+ org_len = rem_len;
+ new_len = 0;
+ do {
+ ext = *p++;
+ length = *p++;
+ p += length;
+
+ if ((!(ext & 0x7F)) && (*p > BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG))
+ bnep_send_command_not_understood(p_bcb, *p);
+
+ new_len += (length + 2);
+
+ if (new_len > org_len) break;
+
+ } while (ext & 0x80);
+ }
+
+ osi_free(p_buf);
+ return;
+ }
+
+ if (type > BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY) {
+ BNEP_TRACE_EVENT("BNEP - rcvd frame, unknown type: 0x%02x", type);
+ osi_free(p_buf);
+ return;
+ }
+
+ BNEP_TRACE_DEBUG("BNEP - rcv frame, type: %d len: %d Ext: %d", type,
+ p_buf->len, extension_present);
+
+ /* Initialize addresses to 'not supplied' */
+ p_src_addr = p_dst_addr = NULL;
+
+ switch (type) {
+ case BNEP_FRAME_GENERAL_ETHERNET:
+ p_dst_addr = p;
+ p += BD_ADDR_LEN;
+ p_src_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16(protocol, p);
+ rem_len -= 14;
+ break;
+
+ case BNEP_FRAME_CONTROL:
+ ctrl_type = *p;
+ p = bnep_process_control_packet(p_bcb, p, &rem_len, false);
+
+ if (ctrl_type == BNEP_SETUP_CONNECTION_REQUEST_MSG &&
+ p_bcb->con_state != BNEP_STATE_CONNECTED && extension_present && p &&
+ rem_len) {
+ osi_free(p_bcb->p_pending_data);
+ p_bcb->p_pending_data = (BT_HDR*)osi_malloc(rem_len + sizeof(BT_HDR));
+ memcpy((uint8_t*)(p_bcb->p_pending_data + 1), p, rem_len);
+ p_bcb->p_pending_data->len = rem_len;
+ p_bcb->p_pending_data->offset = 0;
+ } else {
+ while (extension_present && p && rem_len) {
+ ext_type = *p++;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type) break;
+
+ p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
+ }
+ }
+ osi_free(p_buf);
+ return;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET:
+ BE_STREAM_TO_UINT16(protocol, p);
+ rem_len -= 2;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+ p_src_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16(protocol, p);
+ rem_len -= 8;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+ p_dst_addr = p;
+ p += BD_ADDR_LEN;
+ BE_STREAM_TO_UINT16(protocol, p);
+ rem_len -= 8;
+ break;
+ }
+
+ /* Process the header extension if there is one */
+ while (extension_present && p && rem_len) {
+ ext_type = *p;
+ extension_present = ext_type >> 7;
+ ext_type &= 0x7F;
+
+ /* if unknown extension present stop processing */
+ if (ext_type) {
+ BNEP_TRACE_EVENT("Data extension type 0x%x found", ext_type);
+ break;
+ }
+
+ p++;
+ rem_len--;
+ p = bnep_process_control_packet(p_bcb, p, &rem_len, true);
+ }
+
+ p_buf->offset += p_buf->len - rem_len;
+ p_buf->len = rem_len;
+
+ /* Always give the upper layer MAC addresses */
+ if (!p_src_addr) p_src_addr = (uint8_t*)p_bcb->rem_bda;
+
+ if (!p_dst_addr)
+ p_dst_addr = (uint8_t*)controller_get_interface()->get_address();
+
+ /* check whether there are any extensions to be forwarded */
+ if (ext_type)
+ fw_ext_present = true;
+ else
+ fw_ext_present = false;
+
+ if (bnep_cb.p_data_buf_cb) {
+ (*bnep_cb.p_data_buf_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol,
+ p_buf, fw_ext_present);
+ } else if (bnep_cb.p_data_ind_cb) {
+ (*bnep_cb.p_data_ind_cb)(p_bcb->handle, p_src_addr, p_dst_addr, protocol, p,
+ rem_len, fw_ext_present);
+ osi_free(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_conn_timer_timeout
+ *
+ * Description This function processes a timeout. If it is a startup
+ * timeout, we check for reading our BD address. If it
+ * is an L2CAP timeout, we send a disconnect req to L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_conn_timer_timeout(void* data) {
+ tBNEP_CONN* p_bcb = (tBNEP_CONN*)data;
+
+ BNEP_TRACE_EVENT(
+ "BNEP - CCB timeout in state: %d CID: 0x%x flags %x, re_transmit %d",
+ p_bcb->con_state, p_bcb->l2cap_cid, p_bcb->con_flags,
+ p_bcb->re_transmits);
+
+ if (p_bcb->con_state == BNEP_STATE_CONN_SETUP) {
+ BNEP_TRACE_EVENT("BNEP - CCB timeout in state: %d CID: 0x%x",
+ p_bcb->con_state, p_bcb->l2cap_cid);
+
+ if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) {
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
+ bnep_send_conn_req(p_bcb);
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb,
+ btu_general_alarm_queue);
+ } else {
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED, false);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+ } else if (p_bcb->con_state != BNEP_STATE_CONNECTED) {
+ BNEP_TRACE_EVENT("BNEP - CCB timeout in state: %d CID: 0x%x",
+ p_bcb->con_state, p_bcb->l2cap_cid);
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_CONN_FAILED, false);
+
+ bnepu_release_bcb(p_bcb);
+ } else if (p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND) {
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
+ bnepu_send_peer_our_filters(p_bcb);
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb,
+ btu_general_alarm_queue);
+ } else {
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_SET_FILTER_FAIL, false);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+ } else if (p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND) {
+ if (p_bcb->re_transmits++ != BNEP_MAX_RETRANSMITS) {
+ bnepu_send_peer_our_multi_filters(p_bcb);
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb,
+ btu_general_alarm_queue);
+ } else {
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_SET_FILTER_FAIL, false);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_connected
+ *
+ * Description This function is called when a connection is established
+ * (after config).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_connected(tBNEP_CONN* p_bcb) {
+ bool is_role_change;
+
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ is_role_change = true;
+ else
+ is_role_change = false;
+
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags |= BNEP_FLAGS_CONN_COMPLETED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+
+ /* Ensure timer is stopped */
+ alarm_cancel(p_bcb->conn_timer);
+ p_bcb->re_transmits = 0;
+
+ /* Tell the upper layer, if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, BNEP_SUCCESS,
+ is_role_change);
+}
diff --git a/mtkbt/code/bt/stack/bnep/bnep_utils.cc b/mtkbt/code/bt/stack/bnep/bnep_utils.cc
new file mode 100755
index 0000000..d2cb73f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/bnep/bnep_utils.cc
@@ -0,0 +1,1324 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains BNEP utility functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "bnep_int.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static uint8_t* bnepu_init_hdr(BT_HDR* p_buf, uint16_t hdr_len,
+ uint8_t pkt_type);
+
+void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb,
+ uint8_t* p_filters, uint16_t len);
+void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb,
+ uint16_t response_code);
+
+/*******************************************************************************
+ *
+ * Function bnepu_find_bcb_by_cid
+ *
+ * Description This function searches the bcb table for an entry with the
+ * passed CID.
+ *
+ * Returns the BCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+tBNEP_CONN* bnepu_find_bcb_by_cid(uint16_t cid) {
+ uint16_t xx;
+ tBNEP_CONN* p_bcb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) {
+ if ((p_bcb->con_state != BNEP_STATE_IDLE) && (p_bcb->l2cap_cid == cid))
+ return (p_bcb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_find_bcb_by_bd_addr
+ *
+ * Description This function searches the BCB table for an entry with the
+ * passed Bluetooth Address.
+ *
+ * Returns the BCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+tBNEP_CONN* bnepu_find_bcb_by_bd_addr(uint8_t* p_bda) {
+ uint16_t xx;
+ tBNEP_CONN* p_bcb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) {
+ if (p_bcb->con_state != BNEP_STATE_IDLE) {
+ if (!memcmp((uint8_t*)(p_bcb->rem_bda), p_bda, BD_ADDR_LEN))
+ return (p_bcb);
+ }
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_allocate_bcb
+ *
+ * Description This function allocates a new BCB.
+ *
+ * Returns BCB address, or NULL if none available.
+ *
+ ******************************************************************************/
+tBNEP_CONN* bnepu_allocate_bcb(BD_ADDR p_rem_bda) {
+ uint16_t xx;
+ tBNEP_CONN* p_bcb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_bcb = bnep_cb.bcb; xx < BNEP_MAX_CONNECTIONS; xx++, p_bcb++) {
+ if (p_bcb->con_state == BNEP_STATE_IDLE) {
+ alarm_free(p_bcb->conn_timer);
+ memset((uint8_t*)p_bcb, 0, sizeof(tBNEP_CONN));
+ p_bcb->conn_timer = alarm_new("bnep.conn_timer");
+
+ memcpy((uint8_t*)(p_bcb->rem_bda), (uint8_t*)p_rem_bda, BD_ADDR_LEN);
+ p_bcb->handle = xx + 1;
+ p_bcb->xmit_q = fixed_queue_new(SIZE_MAX);
+
+ return (p_bcb);
+ }
+ }
+
+ /* If here, no free BCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_release_bcb
+ *
+ * Description This function releases a BCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_release_bcb(tBNEP_CONN* p_bcb) {
+ /* Ensure timer is stopped */
+ alarm_free(p_bcb->conn_timer);
+ p_bcb->conn_timer = NULL;
+
+ /* Drop any response pointer we may be holding */
+ p_bcb->con_state = BNEP_STATE_IDLE;
+ //p_bcb->p_pending_data = NULL;
+ osi_free_and_reset((void**)&p_bcb->p_pending_data);
+ /* Free transmit queue */
+ while (!fixed_queue_is_empty(p_bcb->xmit_q)) {
+ osi_free(fixed_queue_try_dequeue(p_bcb->xmit_q));
+ }
+ fixed_queue_free(p_bcb->xmit_q, NULL);
+ p_bcb->xmit_q = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_send_conn_req
+ *
+ * Description This function sends a BNEP connection request to peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_send_conn_req(tBNEP_CONN* p_bcb) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t *p, *p_start;
+
+ BNEP_TRACE_DEBUG("%s: sending setup req with dst uuid %x", __func__,
+ p_bcb->dst_uuid.uu.uuid16);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_SETUP_CONNECTION_REQUEST_MSG);
+
+ UINT8_TO_BE_STREAM(p, p_bcb->dst_uuid.len);
+
+ if (p_bcb->dst_uuid.len == 2) {
+ UINT16_TO_BE_STREAM(p, p_bcb->dst_uuid.uu.uuid16);
+ UINT16_TO_BE_STREAM(p, p_bcb->src_uuid.uu.uuid16);
+ } else if (p_bcb->dst_uuid.len == 4) {
+ UINT32_TO_BE_STREAM(p, p_bcb->dst_uuid.uu.uuid32);
+ UINT32_TO_BE_STREAM(p, p_bcb->src_uuid.uu.uuid32);
+ } else if (p_bcb->dst_uuid.len == 16) {
+ memcpy(p, p_bcb->dst_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+ p += p_bcb->dst_uuid.len;
+ memcpy(p, p_bcb->src_uuid.uu.uuid128, p_bcb->dst_uuid.len);
+ p += p_bcb->dst_uuid.len;
+ } else {
+ BNEP_TRACE_ERROR("%s: uuid: %x, invalid length: %x", __func__,
+ p_bcb->dst_uuid.uu.uuid16, p_bcb->dst_uuid.len);
+ }
+
+ p_buf->len = (uint16_t)(p - p_start);
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_send_conn_responce
+ *
+ * Description This function sends a BNEP setup response to peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_send_conn_responce(tBNEP_CONN* p_bcb, uint16_t resp_code) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+
+ BNEP_TRACE_EVENT("BNEP - bnep_send_conn_responce for CID: 0x%x",
+ p_bcb->l2cap_cid);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_SETUP_CONNECTION_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM(p, resp_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_send_peer_our_filters
+ *
+ * Description This function sends our filters to a peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_send_peer_our_filters(tBNEP_CONN* p_bcb) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+ uint16_t xx;
+
+ BNEP_TRACE_DEBUG("BNEP sending peer our filters");
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_FILTER_NET_TYPE_SET_MSG);
+
+ UINT16_TO_BE_STREAM(p, (4 * p_bcb->sent_num_filters));
+ for (xx = 0; xx < p_bcb->sent_num_filters; xx++) {
+ UINT16_TO_BE_STREAM(p, p_bcb->sent_prot_filter_start[xx]);
+ UINT16_TO_BE_STREAM(p, p_bcb->sent_prot_filter_end[xx]);
+ }
+
+ p_buf->len = 4 + (4 * p_bcb->sent_num_filters);
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+
+ p_bcb->con_flags |= BNEP_FLAGS_FILTER_RESP_PEND;
+
+ /* Start timer waiting for setup response */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_send_peer_our_multi_filters
+ *
+ * Description This function sends our multicast filters to a peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_send_peer_our_multi_filters(tBNEP_CONN* p_bcb) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+ uint16_t xx;
+
+ BNEP_TRACE_DEBUG("BNEP sending peer our multicast filters");
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_FILTER_MULTI_ADDR_SET_MSG);
+
+ UINT16_TO_BE_STREAM(p, (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters));
+ for (xx = 0; xx < p_bcb->sent_mcast_filters; xx++) {
+ memcpy(p, p_bcb->sent_mcast_filter_start[xx], BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ memcpy(p, p_bcb->sent_mcast_filter_end[xx], BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ }
+
+ p_buf->len = 4 + (2 * BD_ADDR_LEN * p_bcb->sent_mcast_filters);
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+
+ p_bcb->con_flags |= BNEP_FLAGS_MULTI_RESP_PEND;
+
+ /* Start timer waiting for setup response */
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_FILTER_SET_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_send_peer_filter_rsp
+ *
+ * Description This function sends a filter response to a peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_send_peer_filter_rsp(tBNEP_CONN* p_bcb, uint16_t response_code) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+
+ BNEP_TRACE_DEBUG("BNEP sending filter response");
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_FILTER_NET_TYPE_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM(p, response_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_send_command_not_understood
+ *
+ * Description This function sends a BNEP command not understood message
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_send_command_not_understood(tBNEP_CONN* p_bcb, uint8_t cmd_code) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+
+ BNEP_TRACE_EVENT(
+ "BNEP - bnep_send_command_not_understood for CID: 0x%x, cmd 0x%x",
+ p_bcb->l2cap_cid, cmd_code);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD);
+
+ UINT8_TO_BE_STREAM(p, cmd_code);
+
+ p_buf->len = 3;
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_check_send_packet
+ *
+ * Description This function tries to send a packet to L2CAP.
+ * If L2CAP is flow controlled, it enqueues the
+ * packet to the transmit queue
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_check_send_packet(tBNEP_CONN* p_bcb, BT_HDR* p_buf) {
+ BNEP_TRACE_EVENT("BNEP - bnepu_check_send_packet for CID: 0x%x",
+ p_bcb->l2cap_cid);
+ if (p_bcb->con_flags & BNEP_FLAGS_L2CAP_CONGESTED) {
+ if (fixed_queue_length(p_bcb->xmit_q) >= BNEP_MAX_XMITQ_DEPTH) {
+ BNEP_TRACE_EVENT("BNEP - congested, dropping buf, CID: 0x%x",
+ p_bcb->l2cap_cid);
+
+ osi_free(p_buf);
+ } else {
+ fixed_queue_enqueue(p_bcb->xmit_q, p_buf);
+ }
+ } else {
+ L2CA_DataWrite(p_bcb->l2cap_cid, p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_build_bnep_hdr
+ *
+ * Description This function builds the BNEP header for a packet
+ * Extension headers are not sent yet, so there is no
+ * check for that.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_build_bnep_hdr(tBNEP_CONN* p_bcb, BT_HDR* p_buf, uint16_t protocol,
+ uint8_t* p_src_addr, uint8_t* p_dest_addr,
+ bool fw_ext_present) {
+ const controller_t* controller = controller_get_interface();
+ uint8_t ext_bit, *p = (uint8_t *)NULL;
+ uint8_t type = BNEP_FRAME_COMPRESSED_ETHERNET;
+
+ ext_bit = fw_ext_present ? 0x80 : 0x00;
+
+ if ((p_src_addr) &&
+ (memcmp(p_src_addr, &controller->get_address()->address, BD_ADDR_LEN)))
+ type = BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY;
+
+ if (memcmp(p_dest_addr, p_bcb->rem_bda, BD_ADDR_LEN))
+ type = (type == BNEP_FRAME_COMPRESSED_ETHERNET)
+ ? BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY
+ : BNEP_FRAME_GENERAL_ETHERNET;
+
+ if (!p_src_addr) p_src_addr = (uint8_t*)controller->get_address();
+
+ switch (type) {
+ case BNEP_FRAME_GENERAL_ETHERNET:
+ p = bnepu_init_hdr(p_buf, 15,
+ (uint8_t)(ext_bit | BNEP_FRAME_GENERAL_ETHERNET));
+
+ memcpy(p, p_dest_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+
+ memcpy(p, p_src_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET:
+ p = bnepu_init_hdr(p_buf, 3,
+ (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET));
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY:
+ p = bnepu_init_hdr(
+ p_buf, 9,
+ (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_SRC_ONLY));
+
+ memcpy(p, p_src_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+
+ case BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY:
+ p = bnepu_init_hdr(
+ p_buf, 9,
+ (uint8_t)(ext_bit | BNEP_FRAME_COMPRESSED_ETHERNET_DEST_ONLY));
+
+ memcpy(p, p_dest_addr, BD_ADDR_LEN);
+ p += BD_ADDR_LEN;
+ break;
+ }
+
+ UINT16_TO_BE_STREAM(p, protocol);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_init_hdr
+ *
+ * Description This function initializes the BNEP header
+ *
+ * Returns pointer to header in buffer
+ *
+ ******************************************************************************/
+static uint8_t* bnepu_init_hdr(BT_HDR* p_buf, uint16_t hdr_len,
+ uint8_t pkt_type) {
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* See if we need to make space in the buffer */
+ if (p_buf->offset < (hdr_len + L2CAP_MIN_OFFSET)) {
+ uint16_t xx, diff = BNEP_MINIMUM_OFFSET - p_buf->offset;
+ p = p + p_buf->len - 1;
+ for (xx = 0; xx < p_buf->len; xx++, p--) p[diff] = *p;
+
+ p_buf->offset = BNEP_MINIMUM_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ }
+
+ p_buf->len += hdr_len;
+ p_buf->offset -= hdr_len;
+ p -= hdr_len;
+
+ *p++ = pkt_type;
+
+ return (p);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_process_setup_conn_req
+ *
+ * Description This function processes a peer's setup connection request
+ * message. The destination UUID is verified and response sent
+ * Connection open indication will be given to PAN profile
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_process_setup_conn_req(tBNEP_CONN* p_bcb, uint8_t* p_setup,
+ uint8_t len) {
+ BNEP_TRACE_EVENT("BNEP - bnep_process_setup_conn_req for CID: 0x%x",
+ p_bcb->l2cap_cid);
+
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP &&
+ p_bcb->con_state != BNEP_STATE_SEC_CHECKING &&
+ p_bcb->con_state != BNEP_STATE_CONNECTED) {
+ BNEP_TRACE_ERROR("BNEP - setup request in bad state %d", p_bcb->con_state);
+ bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ return;
+ }
+
+ /* Check if we already initiated security check or if waiting for user
+ * responce */
+ if (p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD) {
+ BNEP_TRACE_EVENT(
+ "BNEP - Duplicate Setup message received while doing security check");
+ return;
+ }
+
+ /* Check if peer is the originator */
+ if (p_bcb->con_state != BNEP_STATE_CONNECTED &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) &&
+ (p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) {
+ BNEP_TRACE_ERROR("BNEP - setup request when we are originator",
+ p_bcb->con_state);
+ bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ return;
+ }
+
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED) {
+ memcpy((uint8_t*)&(p_bcb->prv_src_uuid), (uint8_t*)&(p_bcb->src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->prv_dst_uuid), (uint8_t*)&(p_bcb->dst_uuid),
+ sizeof(tBT_UUID));
+ }
+
+ p_bcb->dst_uuid.len = p_bcb->src_uuid.len = len;
+
+ if (p_bcb->dst_uuid.len == 2) {
+ /* because peer initiated connection keep src uuid as dst uuid */
+ BE_STREAM_TO_UINT16(p_bcb->src_uuid.uu.uuid16, p_setup);
+ BE_STREAM_TO_UINT16(p_bcb->dst_uuid.uu.uuid16, p_setup);
+
+ /* If nothing has changed don't bother the profile */
+ if (p_bcb->con_state == BNEP_STATE_CONNECTED &&
+ p_bcb->src_uuid.uu.uuid16 == p_bcb->prv_src_uuid.uu.uuid16 &&
+ p_bcb->dst_uuid.uu.uuid16 == p_bcb->prv_dst_uuid.uu.uuid16) {
+ bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_OK);
+ return;
+ }
+ } else if (p_bcb->dst_uuid.len == 4) {
+ BE_STREAM_TO_UINT32(p_bcb->src_uuid.uu.uuid32, p_setup);
+ BE_STREAM_TO_UINT32(p_bcb->dst_uuid.uu.uuid32, p_setup);
+ } else if (p_bcb->dst_uuid.len == 16) {
+ memcpy(p_bcb->src_uuid.uu.uuid128, p_setup, p_bcb->src_uuid.len);
+ p_setup += p_bcb->src_uuid.len;
+ memcpy(p_bcb->dst_uuid.uu.uuid128, p_setup, p_bcb->dst_uuid.len);
+ p_setup += p_bcb->dst_uuid.len;
+ } else {
+ BNEP_TRACE_ERROR("BNEP - Bad UID len %d in ConnReq", p_bcb->dst_uuid.len);
+ bnep_send_conn_responce(p_bcb, BNEP_SETUP_INVALID_UUID_SIZE);
+ return;
+ }
+
+ p_bcb->con_state = BNEP_STATE_SEC_CHECKING;
+ p_bcb->con_flags |= BNEP_FLAGS_SETUP_RCVD;
+
+ BNEP_TRACE_EVENT(
+ "BNEP initiating security check for incoming call for uuid 0x%x",
+ p_bcb->src_uuid.uu.uuid16);
+#if (BNEP_DO_AUTH_FOR_ROLE_SWITCH == FALSE)
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ bnep_sec_check_complete(p_bcb->rem_bda, p_bcb, BTM_SUCCESS);
+ else
+#endif
+ btm_sec_mx_access_request(
+ p_bcb->rem_bda, BT_PSM_BNEP, false, BTM_SEC_PROTO_BNEP,
+ bnep_get_uuid32(&(p_bcb->src_uuid)), &bnep_sec_check_complete, p_bcb);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_process_setup_conn_responce
+ *
+ * Description This function processes a peer's setup connection response
+ * message. The response code is verified and
+ * Connection open indication will be given to PAN profile
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_process_setup_conn_responce(tBNEP_CONN* p_bcb, uint8_t* p_setup) {
+ tBNEP_RESULT resp;
+ uint16_t resp_code;
+
+ BNEP_TRACE_DEBUG("BNEP received setup responce");
+ /* The state should be either SETUP or CONNECTED */
+ if (p_bcb->con_state != BNEP_STATE_CONN_SETUP) {
+ /* Should we disconnect ? */
+ BNEP_TRACE_ERROR("BNEP - setup response in bad state %d", p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_IS_ORIG)) {
+ BNEP_TRACE_ERROR("BNEP - setup response when we are not originator",
+ p_bcb->con_state);
+ return;
+ }
+
+ BE_STREAM_TO_UINT16(resp_code, p_setup);
+
+ switch (resp_code) {
+ case BNEP_SETUP_INVALID_SRC_UUID:
+ resp = BNEP_CONN_FAILED_SRC_UUID;
+ break;
+
+ case BNEP_SETUP_INVALID_DEST_UUID:
+ resp = BNEP_CONN_FAILED_DST_UUID;
+ break;
+
+ case BNEP_SETUP_INVALID_UUID_SIZE:
+ resp = BNEP_CONN_FAILED_UUID_SIZE;
+ break;
+
+ case BNEP_SETUP_CONN_NOT_ALLOWED:
+ default:
+ resp = BNEP_CONN_FAILED;
+ break;
+ }
+
+ /* Check the responce code */
+ if (resp_code != BNEP_SETUP_CONN_OK) {
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
+ BNEP_TRACE_EVENT("BNEP - role change response is %d", resp_code);
+
+ /* Restore the earlier BNEP status */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+ memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
+ sizeof(tBT_UUID));
+
+ /* Ensure timer is stopped */
+ alarm_cancel(p_bcb->conn_timer);
+ p_bcb->re_transmits = 0;
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, resp, true);
+
+ return;
+ } else {
+ BNEP_TRACE_ERROR("BNEP - setup response %d is not OK", resp_code);
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if ((p_bcb->con_flags & BNEP_FLAGS_IS_ORIG) && (bnep_cb.p_conn_state_cb))
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda, resp, false);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+ }
+
+ /* Received successful responce */
+ bnep_connected(p_bcb);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_process_control_packet
+ *
+ * Description This function processes a peer's setup connection request
+ * message. The destination UUID is verified and response sent
+ * Connection open indication will be given to PAN profile
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t* bnep_process_control_packet(tBNEP_CONN* p_bcb, uint8_t* p,
+ uint16_t* rem_len, bool is_ext) {
+ uint8_t control_type;
+ uint16_t len, ext_len = 0;
+
+ if (p == NULL || rem_len == NULL) {
+ if (rem_len !=NULL) *rem_len = 0;
+ BNEP_TRACE_DEBUG("%s: invalid packet: p = %p rem_len = %p", __func__, p,
+ rem_len);
+ return NULL;
+ }
+ uint16_t rem_len_orig = *rem_len;
+
+ if (is_ext) {
+ if (*rem_len < 1) goto bad_packet_length;
+ ext_len = *p++;
+ *rem_len = *rem_len - 1;
+ }
+
+ if (*rem_len < 1) goto bad_packet_length;
+ control_type = *p++;
+ *rem_len = *rem_len - 1;
+
+ BNEP_TRACE_EVENT(
+ "%s: BNEP processing control packet rem_len %d, is_ext %d, ctrl_type %d",
+ __func__, *rem_len, is_ext, control_type);
+
+ switch (control_type) {
+ case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+ if (*rem_len < 1) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD for pkt type: %d",
+ __func__, *p);
+ p++;
+ *rem_len = *rem_len - 1;
+ break;
+
+ case BNEP_SETUP_CONNECTION_REQUEST_MSG:
+ len = *p++;
+ if (*rem_len < ((2 * len) + 1)) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_SETUP_CONNECTION_REQUEST_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ if (!is_ext) bnep_process_setup_conn_req(p_bcb, p, (uint8_t)len);
+ p += (2 * len);
+ *rem_len = *rem_len - (2 * len) - 1;
+ break;
+
+ case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
+ if (*rem_len < 2) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_SETUP_CONNECTION_RESPONSE_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ if (!is_ext) bnep_process_setup_conn_responce(p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ case BNEP_FILTER_NET_TYPE_SET_MSG:
+ BE_STREAM_TO_UINT16(len, p);
+ if (*rem_len < (len + 2)) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_FILTER_NET_TYPE_SET_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ bnepu_process_peer_filter_set(p_bcb, p, len);
+ p += len;
+ *rem_len = *rem_len - len - 2;
+ break;
+
+ case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
+ if (*rem_len < 2) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_FILTER_NET_TYPE_RESPONSE_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ bnepu_process_peer_filter_rsp(p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ case BNEP_FILTER_MULTI_ADDR_SET_MSG:
+ BE_STREAM_TO_UINT16(len, p);
+ if (*rem_len < (len + 2)) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_FILTER_MULTI_ADDR_SET_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ bnepu_process_peer_multicast_filter_set(p_bcb, p, len);
+ p += len;
+ *rem_len = *rem_len - len - 2;
+ break;
+
+ case BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG:
+ if (*rem_len < 2) {
+ BNEP_TRACE_ERROR(
+ "%s: Received BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG with bad length",
+ __func__);
+ goto bad_packet_length;
+ }
+ bnepu_process_multicast_filter_rsp(p_bcb, p);
+ p += 2;
+ *rem_len = *rem_len - 2;
+ break;
+
+ default:
+ BNEP_TRACE_ERROR("%s: BNEP - bad ctl pkt type: %d", __func__,
+ control_type);
+ bnep_send_command_not_understood(p_bcb, control_type);
+ if (is_ext && (ext_len > 0)) {
+ if (*rem_len < (ext_len - 1)) {
+ goto bad_packet_length;
+ }
+ p += (ext_len - 1);
+ *rem_len -= (ext_len - 1);
+ }
+ break;
+ }
+ return p;
+
+bad_packet_length:
+ BNEP_TRACE_ERROR("%s: bad control packet length: original=%d remaining=%d",
+ __func__, rem_len_orig, *rem_len);
+ *rem_len = 0;
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_process_peer_filter_set
+ *
+ * Description This function processes a peer's filter control
+ * 'set' message. The filters are stored in the BCB,
+ * and an appropriate filter response message sent.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_process_peer_filter_set(tBNEP_CONN* p_bcb, uint8_t* p_filters,
+ uint16_t len) {
+ uint16_t num_filters = 0;
+ uint16_t xx, resp_code = BNEP_FILTER_CRL_OK;
+ uint16_t start, end;
+ uint8_t* p_temp_filters;
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) {
+ BNEP_TRACE_DEBUG(
+ "BNEP received filter set from peer when there is no connection");
+ return;
+ }
+
+ BNEP_TRACE_DEBUG("BNEP received filter set from peer");
+ /* Check for length not a multiple of 4 */
+ if (len & 3) {
+ BNEP_TRACE_EVENT("BNEP - bad filter len: %d", len);
+ bnepu_send_peer_filter_rsp(p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ if (len) num_filters = (uint16_t)(len >> 2);
+
+ /* Validate filter values */
+ if (num_filters <= BNEP_MAX_PROT_FILTERS) {
+ p_temp_filters = p_filters;
+ for (xx = 0; xx < num_filters; xx++) {
+ BE_STREAM_TO_UINT16(start, p_temp_filters);
+ BE_STREAM_TO_UINT16(end, p_temp_filters);
+
+ if (start > end) {
+ resp_code = BNEP_FILTER_CRL_BAD_RANGE;
+ break;
+ }
+ }
+ } else
+ resp_code = BNEP_FILTER_CRL_MAX_REACHED;
+
+ if (resp_code != BNEP_FILTER_CRL_OK) {
+ bnepu_send_peer_filter_rsp(p_bcb, resp_code);
+ return;
+ }
+
+ if (bnep_cb.p_filter_ind_cb)
+ (*bnep_cb.p_filter_ind_cb)(p_bcb->handle, true, 0, len, p_filters);
+
+ p_bcb->rcvd_num_filters = num_filters;
+ for (xx = 0; xx < num_filters; xx++) {
+ BE_STREAM_TO_UINT16(start, p_filters);
+ BE_STREAM_TO_UINT16(end, p_filters);
+
+ p_bcb->rcvd_prot_filter_start[xx] = start;
+ p_bcb->rcvd_prot_filter_end[xx] = end;
+ }
+
+ bnepu_send_peer_filter_rsp(p_bcb, resp_code);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_process_peer_filter_rsp
+ *
+ * Description This function processes a peer's filter control
+ * 'response' message.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_process_peer_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data) {
+ uint16_t resp_code;
+ tBNEP_RESULT result;
+
+ BNEP_TRACE_DEBUG("BNEP received filter responce");
+ /* The state should be CONNECTED */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) {
+ BNEP_TRACE_ERROR("BNEP - filter response in bad state %d",
+ p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_FILTER_RESP_PEND)) {
+ BNEP_TRACE_ERROR("BNEP - filter response when not expecting");
+ return;
+ }
+
+ /* Ensure timer is stopped */
+ alarm_cancel(p_bcb->conn_timer);
+ p_bcb->con_flags &= ~BNEP_FLAGS_FILTER_RESP_PEND;
+ p_bcb->re_transmits = 0;
+
+ BE_STREAM_TO_UINT16(resp_code, p_data);
+
+ result = BNEP_SUCCESS;
+ if (resp_code != BNEP_FILTER_CRL_OK) result = BNEP_SET_FILTER_FAIL;
+
+ if (bnep_cb.p_filter_ind_cb)
+ (*bnep_cb.p_filter_ind_cb)(p_bcb->handle, false, result, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_process_multicast_filter_rsp
+ *
+ * Description This function processes multicast filter control
+ * 'response' message.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_process_multicast_filter_rsp(tBNEP_CONN* p_bcb, uint8_t* p_data) {
+ uint16_t resp_code;
+ tBNEP_RESULT result;
+
+ BNEP_TRACE_DEBUG("BNEP received multicast filter responce");
+ /* The state should be CONNECTED */
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) {
+ BNEP_TRACE_ERROR("BNEP - multicast filter response in bad state %d",
+ p_bcb->con_state);
+ return;
+ }
+
+ /* Check if we are the originator */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_MULTI_RESP_PEND)) {
+ BNEP_TRACE_ERROR("BNEP - multicast filter response when not expecting");
+ return;
+ }
+
+ /* Ensure timer is stopped */
+ alarm_cancel(p_bcb->conn_timer);
+ p_bcb->con_flags &= ~BNEP_FLAGS_MULTI_RESP_PEND;
+ p_bcb->re_transmits = 0;
+
+ BE_STREAM_TO_UINT16(resp_code, p_data);
+
+ result = BNEP_SUCCESS;
+ if (resp_code != BNEP_FILTER_CRL_OK) result = BNEP_SET_FILTER_FAIL;
+
+ if (bnep_cb.p_mfilter_ind_cb)
+ (*bnep_cb.p_mfilter_ind_cb)(p_bcb->handle, false, result, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_process_peer_multicast_filter_set
+ *
+ * Description This function processes a peer's filter control
+ * 'set' message. The filters are stored in the BCB,
+ * and an appropriate filter response message sent.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_process_peer_multicast_filter_set(tBNEP_CONN* p_bcb,
+ uint8_t* p_filters, uint16_t len) {
+ uint16_t resp_code = BNEP_FILTER_CRL_OK;
+ uint16_t num_filters, xx;
+ uint8_t *p_temp_filters, null_bda[BD_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
+
+ if ((p_bcb->con_state != BNEP_STATE_CONNECTED) &&
+ (!(p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED))) {
+ BNEP_TRACE_DEBUG(
+ "BNEP received multicast filter set from peer when there is no "
+ "connection");
+ return;
+ }
+
+ if (len % 12) {
+ BNEP_TRACE_EVENT("BNEP - bad filter len: %d", len);
+ bnepu_send_peer_multicast_filter_rsp(p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ if (len > (BNEP_MAX_MULTI_FILTERS * 2 * BD_ADDR_LEN)) {
+ BNEP_TRACE_EVENT("BNEP - Too many filters");
+ bnepu_send_peer_multicast_filter_rsp(p_bcb, BNEP_FILTER_CRL_MAX_REACHED);
+ return;
+ }
+
+ num_filters = 0;
+ if (len) num_filters = (uint16_t)(len / 12);
+
+ /* Validate filter values */
+ if (num_filters <= BNEP_MAX_MULTI_FILTERS) {
+ p_temp_filters = p_filters;
+ for (xx = 0; xx < num_filters; xx++) {
+ if (memcmp(p_temp_filters, p_temp_filters + BD_ADDR_LEN, BD_ADDR_LEN) >
+ 0) {
+ bnepu_send_peer_multicast_filter_rsp(p_bcb, BNEP_FILTER_CRL_BAD_RANGE);
+ return;
+ }
+
+ p_temp_filters += (BD_ADDR_LEN * 2);
+ }
+ }
+
+ p_bcb->rcvd_mcast_filters = num_filters;
+ for (xx = 0; xx < num_filters; xx++) {
+ memcpy(p_bcb->rcvd_mcast_filter_start[xx], p_filters, BD_ADDR_LEN);
+ memcpy(p_bcb->rcvd_mcast_filter_end[xx], p_filters + BD_ADDR_LEN,
+ BD_ADDR_LEN);
+ p_filters += (BD_ADDR_LEN * 2);
+
+ /* Check if any of the ranges have all zeros as both starting and ending
+ * addresses */
+ if ((memcmp(null_bda, p_bcb->rcvd_mcast_filter_start[xx], BD_ADDR_LEN) ==
+ 0) &&
+ (memcmp(null_bda, p_bcb->rcvd_mcast_filter_end[xx], BD_ADDR_LEN) ==
+ 0)) {
+ p_bcb->rcvd_mcast_filters = 0xFFFF;
+ break;
+ }
+ }
+
+ BNEP_TRACE_EVENT("BNEP multicast filters %d", p_bcb->rcvd_mcast_filters);
+ bnepu_send_peer_multicast_filter_rsp(p_bcb, resp_code);
+
+ if (bnep_cb.p_mfilter_ind_cb)
+ (*bnep_cb.p_mfilter_ind_cb)(p_bcb->handle, true, 0, len, p_filters);
+}
+
+/*******************************************************************************
+ *
+ * Function bnepu_send_peer_multicast_filter_rsp
+ *
+ * Description This function sends a filter response to a peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnepu_send_peer_multicast_filter_rsp(tBNEP_CONN* p_bcb,
+ uint16_t response_code) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(BNEP_BUF_SIZE);
+ uint8_t* p;
+
+ BNEP_TRACE_DEBUG("BNEP sending multicast filter response %d", response_code);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Put in BNEP frame type - filter control */
+ UINT8_TO_BE_STREAM(p, BNEP_FRAME_CONTROL);
+
+ /* Put in filter message type - set filters */
+ UINT8_TO_BE_STREAM(p, BNEP_FILTER_MULTI_ADDR_RESPONSE_MSG);
+
+ UINT16_TO_BE_STREAM(p, response_code);
+
+ p_buf->len = 4;
+
+ bnepu_check_send_packet(p_bcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_sec_check_complete
+ *
+ * Description This function is registered with BTM and will be called
+ * after completing the security procedures
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bnep_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT trasnport,
+ void* p_ref_data, uint8_t result) {
+ tBNEP_CONN* p_bcb = (tBNEP_CONN*)p_ref_data;
+ uint16_t resp_code = BNEP_SETUP_CONN_OK;
+ bool is_role_change;
+
+ BNEP_TRACE_EVENT("BNEP security callback returned result %d", result);
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED)
+ is_role_change = true;
+ else
+ is_role_change = false;
+
+ /* check if the port is still waiting for security to complete */
+ if (p_bcb->con_state != BNEP_STATE_SEC_CHECKING) {
+ BNEP_TRACE_ERROR(
+ "BNEP Connection in wrong state %d when security is completed",
+ p_bcb->con_state);
+ return;
+ }
+
+ /* if it is outgoing call and result is FAILURE return security fail error */
+ if (!(p_bcb->con_flags & BNEP_FLAGS_SETUP_RCVD)) {
+ if (result != BTM_SUCCESS) {
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
+ /* Tell the user that role change is failed because of security */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_SECURITY_FAIL, is_role_change);
+
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
+ sizeof(tBT_UUID));
+ return;
+ }
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (bnep_cb.p_conn_state_cb)
+ (*bnep_cb.p_conn_state_cb)(p_bcb->handle, p_bcb->rem_bda,
+ BNEP_SECURITY_FAIL, is_role_change);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for connection confirm.
+ */
+ p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+
+ bnep_send_conn_req(p_bcb);
+ alarm_set_on_queue(p_bcb->conn_timer, BNEP_CONN_TIMEOUT_MS,
+ bnep_conn_timer_timeout, p_bcb, btu_general_alarm_queue);
+ return;
+ }
+
+ /* it is an incoming call respond appropriately */
+ if (result != BTM_SUCCESS) {
+ bnep_send_conn_responce(p_bcb, BNEP_SETUP_CONN_NOT_ALLOWED);
+ if (p_bcb->con_flags & BNEP_FLAGS_CONN_COMPLETED) {
+ /* Role change is failed because of security. Revert back to connected
+ * state */
+ p_bcb->con_state = BNEP_STATE_CONNECTED;
+ p_bcb->con_flags &= (~BNEP_FLAGS_SETUP_RCVD);
+ memcpy((uint8_t*)&(p_bcb->src_uuid), (uint8_t*)&(p_bcb->prv_src_uuid),
+ sizeof(tBT_UUID));
+ memcpy((uint8_t*)&(p_bcb->dst_uuid), (uint8_t*)&(p_bcb->prv_dst_uuid),
+ sizeof(tBT_UUID));
+ return;
+ }
+
+ L2CA_DisconnectReq(p_bcb->l2cap_cid);
+
+ bnepu_release_bcb(p_bcb);
+ return;
+ }
+
+ if (bnep_cb.p_conn_ind_cb) {
+ p_bcb->con_state = BNEP_STATE_CONN_SETUP;
+ (*bnep_cb.p_conn_ind_cb)(p_bcb->handle, p_bcb->rem_bda, &p_bcb->dst_uuid,
+ &p_bcb->src_uuid, is_role_change);
+ } else {
+ /* Profile didn't register connection indication call back */
+ bnep_send_conn_responce(p_bcb, resp_code);
+ bnep_connected(p_bcb);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_is_packet_allowed
+ *
+ * Description This function verifies whether the protocol passes through
+ * the protocol filters set by the peer
+ *
+ * Returns BNEP_SUCCESS - if the protocol is allowed
+ * BNEP_IGNORE_CMD - if the protocol is filtered out
+ *
+ ******************************************************************************/
+tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb, BD_ADDR p_dest_addr,
+ uint16_t protocol, bool fw_ext_present,
+ uint8_t* p_data) {
+ if (p_bcb->rcvd_num_filters) {
+ uint16_t i, proto;
+
+ /* Findout the actual protocol to check for the filtering */
+ proto = protocol;
+ if (proto == BNEP_802_1_P_PROTOCOL) {
+ if (fw_ext_present) {
+ uint8_t len, ext;
+ /* parse the extension headers and findout actual protocol */
+ do {
+ ext = *p_data++;
+ len = *p_data++;
+ p_data += len;
+
+ } while (ext & 0x80);
+ }
+ p_data += 2;
+ BE_STREAM_TO_UINT16(proto, p_data);
+ }
+
+ for (i = 0; i < p_bcb->rcvd_num_filters; i++) {
+ if ((p_bcb->rcvd_prot_filter_start[i] <= proto) &&
+ (proto <= p_bcb->rcvd_prot_filter_end[i]))
+ break;
+ }
+
+ if (i == p_bcb->rcvd_num_filters) {
+ BNEP_TRACE_DEBUG("Ignoring protocol 0x%x in BNEP data write", proto);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+
+ /* Ckeck for multicast address filtering */
+ if ((p_dest_addr[0] & 0x01) && p_bcb->rcvd_mcast_filters) {
+ uint16_t i;
+
+ /* Check if every multicast should be filtered */
+ if (p_bcb->rcvd_mcast_filters != 0xFFFF) {
+ /* Check if the address is mentioned in the filter range */
+ for (i = 0; i < p_bcb->rcvd_mcast_filters; i++) {
+ if ((memcmp(p_bcb->rcvd_mcast_filter_start[i], p_dest_addr,
+ BD_ADDR_LEN) <= 0) &&
+ (memcmp(p_bcb->rcvd_mcast_filter_end[i], p_dest_addr,
+ BD_ADDR_LEN) >= 0))
+ break;
+ }
+ }
+
+ /*
+ ** If every multicast should be filtered or the address is not in the filter
+ *range
+ ** drop the packet
+ */
+ if ((p_bcb->rcvd_mcast_filters == 0xFFFF) ||
+ (i == p_bcb->rcvd_mcast_filters)) {
+ BNEP_TRACE_DEBUG(
+ "Ignoring multicast address %x.%x.%x.%x.%x.%x in BNEP data write",
+ p_dest_addr[0], p_dest_addr[1], p_dest_addr[2], p_dest_addr[3],
+ p_dest_addr[4], p_dest_addr[5]);
+ return BNEP_IGNORE_CMD;
+ }
+ }
+
+ return BNEP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function bnep_get_uuid32
+ *
+ * Description This function returns the 32-bit equivalent of the UUID
+ *
+ * Returns uint32_t - 32-bit equivalent of the UUID
+ *
+ ******************************************************************************/
+uint32_t bnep_get_uuid32(tBT_UUID* src_uuid) {
+ uint32_t result;
+
+ if (src_uuid->len == 2)
+ return ((uint32_t)src_uuid->uu.uuid16);
+ else if (src_uuid->len == 4)
+ return (src_uuid->uu.uuid32 & 0x0000FFFF);
+ else {
+ result = src_uuid->uu.uuid128[2];
+ result = (result << 8) | (src_uuid->uu.uuid128[3]);
+ return result;
+ }
+}
diff --git a/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.cc b/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.cc
new file mode 100755
index 0000000..740ab50
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.cc
@@ -0,0 +1,715 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "ble_advertiser_hci_interface.h"
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <queue>
+#include <utility>
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btm_int_types.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
+#define BTM_BLE_MULTI_ADV_ENB_LEN 3
+#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
+#define BTM_BLE_AD_DATA_LEN 31
+#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3)
+
+#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1
+#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31
+
+using status_cb = BleAdvertiserHciInterface::status_cb;
+
+using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */,
+ uint16_t /* return_parameters_length*/)>;
+extern void btu_hcif_send_cmd_with_cb(
+ const tracked_objects::Location& posted_from, uint16_t opcode,
+ uint8_t* params, uint8_t params_len, hci_cmd_cb cb);
+
+namespace {
+BleAdvertiserHciInterface* instance = nullptr;
+
+void btm_ble_multi_adv_vsc_cmpl_cback(uint8_t expected_opcode,
+ status_cb command_complete,
+ uint8_t* param, uint16_t param_len) {
+ uint8_t status, subcode;
+
+ // All multi-adv commands respond with status and inst_id.
+ LOG_ASSERT(param_len == 2) << "Received bad response length to multi-adv VSC";
+
+ STREAM_TO_UINT8(status, param);
+ STREAM_TO_UINT8(subcode, param);
+
+ VLOG(1) << "subcode = " << +subcode << ", status: " << +status;
+
+ if (expected_opcode != subcode) {
+ LOG(ERROR) << "unexpected VSC cmpl, expect: " << +subcode
+ << " get: " << +expected_opcode;
+ return;
+ }
+
+ command_complete.Run(status);
+}
+
+void parameters_response_parser(BleAdvertiserHciInterface::parameters_cb cb,
+ uint8_t* ret_params, uint16_t ret_params_len) {
+ uint8_t status;
+ int8_t tx_power;
+
+ uint8_t* pp = ret_params;
+ STREAM_TO_UINT8(status, pp);
+ STREAM_TO_INT8(tx_power, pp);
+
+ cb.Run(status, tx_power);
+}
+
+void known_tx_pwr(BleAdvertiserHciInterface::parameters_cb cb, int8_t tx_power,
+ uint8_t status) {
+ cb.Run(status, tx_power);
+}
+
+class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
+ void SendAdvCmd(const tracked_objects::Location& posted_from,
+ uint8_t param_len, uint8_t* param_buf,
+ status_cb command_complete) {
+ btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV_OCF, param_buf,
+ param_len,
+ base::Bind(&btm_ble_multi_adv_vsc_cmpl_cback,
+ param_buf[0], command_complete));
+ }
+
+ void ReadInstanceCount(
+ base::Callback<void(uint8_t /* inst_cnt*/)> cb) override {
+ cb.Run(BTM_BleMaxMultiAdvInstanceCount());
+ }
+
+ void SetAdvertisingEventObserver(
+ AdvertisingEventObserver* observer) override {
+ this->advertising_event_observer = observer;
+ }
+
+ void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min,
+ uint32_t adv_int_max, uint8_t channel_map,
+ uint8_t own_address_type, BD_ADDR own_address,
+ uint8_t peer_address_type, BD_ADDR peer_address,
+ uint8_t filter_policy, int8_t tx_power,
+ uint8_t primary_phy, uint8_t secondary_max_skip,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ uint8_t scan_request_notify_enable,
+ parameters_cb command_complete) override {
+ VLOG(1) << __func__;
+ uint8_t param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN];
+ memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM);
+ UINT16_TO_STREAM(pp, adv_int_min);
+ UINT16_TO_STREAM(pp, adv_int_max);
+
+ if (properties == 0x0013) {
+ UINT8_TO_STREAM(pp, 0x00); // ADV_IND
+ } else if (properties == 0x0012) {
+ UINT8_TO_STREAM(pp, 0x02); // ADV_SCAN_IND
+ } else if (properties == 0x0010) {
+ UINT8_TO_STREAM(pp, 0x03); // ADV_NONCONN_IND
+ } else {
+ LOG(ERROR) << "Unsupported advertisement type selected:" << std::hex
+ << properties;
+ command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT, 0);
+ return;
+ }
+
+ UINT8_TO_STREAM(pp, own_address_type);
+ BDADDR_TO_STREAM(pp, own_address);
+ UINT8_TO_STREAM(pp, peer_address_type);
+ BDADDR_TO_STREAM(pp, peer_address);
+ UINT8_TO_STREAM(pp, channel_map);
+ UINT8_TO_STREAM(pp, filter_policy);
+ UINT8_TO_STREAM(pp, handle);
+ INT8_TO_STREAM(pp, tx_power);
+
+ SendAdvCmd(
+ FROM_HERE, BTM_BLE_MULTI_ADV_SET_PARAM_LEN, param,
+ base::Bind(&known_tx_pwr, std::move(command_complete), tx_power));
+ }
+
+ void SetAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference, uint8_t data_length,
+ uint8_t* data, status_cb command_complete) override {
+ VLOG(1) << __func__;
+ uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN];
+ memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_ADV_DATA);
+ UINT8_TO_STREAM(pp, data_length);
+ ARRAY_TO_STREAM(pp, data, data_length);
+ param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = handle;
+
+ SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param,
+ command_complete);
+ }
+
+ void SetScanResponseData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference,
+ uint8_t scan_response_data_length,
+ uint8_t* scan_response_data,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ uint8_t param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN];
+ memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA);
+ UINT8_TO_STREAM(pp, scan_response_data_length);
+ ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length);
+ param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1] = handle;
+
+ SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN, param,
+ command_complete);
+ }
+
+ void SetRandomAddress(uint8_t handle, uint8_t random_address[6],
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ uint8_t param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN];
+ memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
+ BDADDR_TO_STREAM(pp, random_address);
+ UINT8_TO_STREAM(pp, handle);
+
+ SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN, param,
+ command_complete);
+ }
+
+ void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
+ uint8_t max_extended_advertising_events,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ if (max_extended_advertising_events) {
+ command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
+ return;
+ }
+
+ uint8_t param[BTM_BLE_MULTI_ADV_ENB_LEN];
+ memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_ENB);
+ UINT8_TO_STREAM(pp, enable);
+ UINT8_TO_STREAM(pp, handle);
+
+ SendAdvCmd(FROM_HERE, (uint8_t)BTM_BLE_MULTI_ADV_ENB_LEN, param,
+ command_complete);
+ }
+
+ void SetPeriodicAdvertisingParameters(uint8_t, uint16_t, uint16_t, uint16_t,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << " VSC can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ void SetPeriodicAdvertisingData(uint8_t, uint8_t, uint8_t, uint8_t*,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << " VSC can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ void SetPeriodicAdvertisingEnable(uint8_t, uint8_t,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << " VSC can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ bool QuirkAdvertiserZeroHandle() override {
+ // Android BT HCI Requirements version 0.96 and below specify that handle 0
+ // is equal to standard HCI interface, and should be accessed using non-VSC
+ // commands.
+ LOG(INFO) << "QuirkAdvertiserZeroHandle in use";
+ return true;
+ }
+
+ void RemoveAdvertisingSet(uint8_t handle,
+ status_cb command_complete) override {
+ // VSC Advertising don't have remove method.
+ command_complete.Run(0);
+ }
+
+ public:
+ static void VendorSpecificEventCback(uint8_t length, uint8_t* p) {
+ VLOG(1) << __func__;
+
+ LOG_ASSERT(p);
+ uint8_t sub_event, adv_inst, change_reason;
+ uint16_t conn_handle;
+
+ STREAM_TO_UINT8(sub_event, p);
+ length--;
+
+ if (sub_event != HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG || length != 4) {
+ return;
+ }
+
+ STREAM_TO_UINT8(adv_inst, p);
+ STREAM_TO_UINT8(change_reason, p);
+ STREAM_TO_UINT16(conn_handle, p);
+
+ AdvertisingEventObserver* observer =
+ ((BleAdvertiserVscHciInterfaceImpl*)BleAdvertiserHciInterface::Get())
+ ->advertising_event_observer;
+ if (observer)
+ observer->OnAdvertisingSetTerminated(change_reason, adv_inst, conn_handle,
+ 0x00);
+ }
+
+ private:
+ AdvertisingEventObserver* advertising_event_observer = nullptr;
+};
+
+void adv_cmd_cmpl_cback(status_cb cb, uint8_t* return_parameters,
+ uint16_t return_parameters_length) {
+ uint8_t status = *return_parameters;
+ cb.Run(status);
+}
+
+class BleAdvertiserLegacyHciInterfaceImpl : public BleAdvertiserHciInterface {
+ void SendAdvCmd(const tracked_objects::Location& posted_from, uint16_t opcode,
+ uint8_t* param_buf, uint8_t param_buf_len,
+ status_cb command_complete) {
+ btu_hcif_send_cmd_with_cb(
+ posted_from, opcode, param_buf, param_buf_len,
+ base::Bind(&adv_cmd_cmpl_cback, command_complete));
+ }
+
+ void ReadInstanceCount(
+ base::Callback<void(uint8_t /* inst_cnt*/)> cb) override {
+ cb.Run(1);
+ }
+
+ void SetAdvertisingEventObserver(
+ AdvertisingEventObserver* observer) override {}
+
+ void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min,
+ uint32_t adv_int_max, uint8_t channel_map,
+ uint8_t own_address_type, BD_ADDR /* own_address */,
+ uint8_t peer_address_type, BD_ADDR peer_address,
+ uint8_t filter_policy, int8_t tx_power,
+ uint8_t primary_phy, uint8_t secondary_max_skip,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ uint8_t scan_request_notify_enable,
+ parameters_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS];
+
+ uint8_t* pp = param;
+ UINT16_TO_STREAM(pp, adv_int_min);
+ UINT16_TO_STREAM(pp, adv_int_max);
+
+ if (properties == 0x0013) {
+ UINT8_TO_STREAM(pp, 0x00); // ADV_IND
+ } else if (properties == 0x0012) {
+ UINT8_TO_STREAM(pp, 0x02); // ADV_SCAN_IND
+ } else if (properties == 0x0010) {
+ UINT8_TO_STREAM(pp, 0x03); // ADV_NONCONN_IND
+ } else {
+ LOG(ERROR) << "Unsupported advertisement type selected:" << std::hex
+ << properties;
+ command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT, 0);
+ return;
+ }
+
+ UINT8_TO_STREAM(pp, own_address_type);
+ UINT8_TO_STREAM(pp, peer_address_type);
+ BDADDR_TO_STREAM(pp, peer_address);
+ UINT8_TO_STREAM(pp, channel_map);
+ UINT8_TO_STREAM(pp, filter_policy);
+
+ SendAdvCmd(
+ FROM_HERE, HCI_BLE_WRITE_ADV_PARAMS, param,
+ HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS,
+ base::Bind(&known_tx_pwr, std::move(command_complete), (int8_t)0));
+ }
+
+ void SetAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference, uint8_t data_length,
+ uint8_t* data, status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1];
+
+ uint8_t* pp = param;
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);
+ UINT8_TO_STREAM(pp, data_length);
+ ARRAY_TO_STREAM(pp, data, data_length);
+
+ SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_ADV_DATA, param,
+ HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete);
+ }
+
+ void SetScanResponseData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference,
+ uint8_t scan_response_data_length,
+ uint8_t* scan_response_data,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ uint8_t param[HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1];
+
+ uint8_t* pp = param;
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);
+ UINT8_TO_STREAM(pp, scan_response_data_length);
+ ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length);
+
+ SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_SCAN_RSP_DATA, param,
+ HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1, command_complete);
+ }
+
+ void SetRandomAddress(uint8_t handle, uint8_t random_address[6],
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ uint8_t param[HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD];
+
+ uint8_t* pp = param;
+ BDADDR_TO_STREAM(pp, random_address);
+
+ SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_RANDOM_ADDR, param,
+ HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD, command_complete);
+ }
+
+ void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
+ uint8_t max_extended_advertising_events,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ if (max_extended_advertising_events) {
+ command_complete.Run(HCI_ERR_ILLEGAL_PARAMETER_FMT);
+ return;
+ }
+
+ uint8_t param[HCIC_PARAM_SIZE_WRITE_ADV_ENABLE];
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, enable);
+
+ SendAdvCmd(FROM_HERE, HCI_BLE_WRITE_ADV_ENABLE, param,
+ HCIC_PARAM_SIZE_WRITE_ADV_ENABLE, command_complete);
+ }
+
+ void SetPeriodicAdvertisingParameters(uint8_t, uint16_t, uint16_t, uint16_t,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << "Legacy can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ void SetPeriodicAdvertisingData(uint8_t, uint8_t, uint8_t, uint8_t*,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << "Legacy can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ void SetPeriodicAdvertisingEnable(uint8_t, uint8_t,
+ status_cb command_complete) override {
+ LOG(INFO) << __func__ << "Legacy can't do periodic advertising";
+ command_complete.Run(HCI_ERR_ILLEGAL_COMMAND);
+ }
+
+ void RemoveAdvertisingSet(uint8_t handle,
+ status_cb command_complete) override {
+ // Legacy Advertising don't have remove method.
+ command_complete.Run(0);
+ }
+};
+
+class BleAdvertiserHciExtendedImpl : public BleAdvertiserHciInterface {
+ void SendAdvCmd(const tracked_objects::Location& posted_from, uint16_t opcode,
+ uint8_t* param_buf, uint8_t param_buf_len,
+ status_cb command_complete) {
+ btu_hcif_send_cmd_with_cb(
+ posted_from, opcode, param_buf, param_buf_len,
+ base::Bind(&adv_cmd_cmpl_cback, command_complete));
+ }
+
+ void ReadInstanceCount(
+ base::Callback<void(uint8_t /* inst_cnt*/)> cb) override {
+ cb.Run(controller_get_interface()
+ ->get_ble_number_of_supported_advertising_sets());
+ }
+
+ void SetAdvertisingEventObserver(
+ AdvertisingEventObserver* observer) override {
+ this->advertising_event_observer = observer;
+ }
+
+ void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min,
+ uint32_t adv_int_max, uint8_t channel_map,
+ uint8_t own_address_type, BD_ADDR /* own_address */,
+ uint8_t peer_address_type, BD_ADDR peer_address,
+ uint8_t filter_policy, int8_t tx_power,
+ uint8_t primary_phy, uint8_t secondary_max_skip,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ uint8_t scan_request_notify_enable,
+ parameters_cb command_complete) override {
+ VLOG(1) << __func__;
+ const uint16_t HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN = 25;
+ uint8_t param[HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN];
+ memset(param, 0, HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, properties);
+ UINT24_TO_STREAM(pp, adv_int_min);
+ UINT24_TO_STREAM(pp, adv_int_max);
+ UINT8_TO_STREAM(pp, channel_map);
+ UINT8_TO_STREAM(pp, own_address_type);
+ UINT8_TO_STREAM(pp, peer_address_type);
+ BDADDR_TO_STREAM(pp, peer_address);
+ UINT8_TO_STREAM(pp, filter_policy);
+ INT8_TO_STREAM(pp, tx_power);
+ UINT8_TO_STREAM(pp, primary_phy);
+ UINT8_TO_STREAM(pp, secondary_max_skip);
+ UINT8_TO_STREAM(pp, secondary_phy);
+ UINT8_TO_STREAM(pp, advertising_sid);
+ UINT8_TO_STREAM(pp, scan_request_notify_enable);
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_PARAM, param,
+ HCI_LE_SET_EXT_ADVERTISING_PARAM_LEN,
+ base::Bind(parameters_response_parser, std::move(command_complete)));
+ }
+
+ void SetAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference, uint8_t data_length,
+ uint8_t* data, status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ const uint16_t cmd_length = 4 + data_length;
+ uint8_t param[cmd_length];
+ memset(param, 0, cmd_length);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, operation);
+ UINT8_TO_STREAM(pp, fragment_preference);
+ UINT8_TO_STREAM(pp, data_length);
+ ARRAY_TO_STREAM(pp, data, data_length);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_DATA, param, cmd_length,
+ command_complete);
+ }
+
+ void SetScanResponseData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference,
+ uint8_t scan_response_data_length,
+ uint8_t* scan_response_data,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ const uint16_t cmd_length = 4 + scan_response_data_length;
+ uint8_t param[cmd_length];
+ memset(param, 0, cmd_length);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, operation);
+ UINT8_TO_STREAM(pp, fragment_preference);
+ UINT8_TO_STREAM(pp, scan_response_data_length);
+ ARRAY_TO_STREAM(pp, scan_response_data, scan_response_data_length);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_SCAN_RESP, param,
+ cmd_length, command_complete);
+ }
+
+ void SetRandomAddress(uint8_t handle, uint8_t random_address[6],
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ const int LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN = 7;
+
+ uint8_t param[LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN];
+ memset(param, 0, LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ BDADDR_TO_STREAM(pp, random_address);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_RANDOM_ADDRESS, param,
+ LE_SET_ADVERTISING_SET_RANDOM_ADDRESS_LEN, command_complete);
+ }
+
+ void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
+ uint8_t max_extended_advertising_events,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ /* cmd_length = header_size + num_of_of_advertiser * size_per_advertiser */
+ const uint16_t cmd_length = 2 + 1 * 4;
+ uint8_t param[cmd_length];
+ memset(param, 0, cmd_length);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, enable);
+ UINT8_TO_STREAM(pp, 0x01); // just one set
+
+ UINT8_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, duration);
+ UINT8_TO_STREAM(pp, max_extended_advertising_events);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_EXT_ADVERTISING_ENABLE, param, cmd_length,
+ command_complete);
+ }
+
+ void SetPeriodicAdvertisingParameters(uint8_t handle,
+ uint16_t periodic_adv_int_min,
+ uint16_t periodic_adv_int_max,
+ uint16_t periodic_properties,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ const uint16_t HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN = 7;
+ uint8_t param[HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN];
+ memset(param, 0, HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, periodic_adv_int_min);
+ UINT16_TO_STREAM(pp, periodic_adv_int_max);
+ UINT16_TO_STREAM(pp, periodic_properties);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_PARAM, param,
+ HCI_LE_SET_PRIODIC_ADVERTISING_PARAM_LEN, command_complete);
+ }
+
+ void SetPeriodicAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t adv_data_length, uint8_t* adv_data,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ const uint16_t HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN =
+ 3 + adv_data_length;
+ uint8_t param[HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN];
+ memset(param, 0, HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN);
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, operation);
+ UINT8_TO_STREAM(pp, adv_data_length);
+ ARRAY_TO_STREAM(pp, adv_data, adv_data_length);
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_DATA, param,
+ HCI_LE_SET_PRIODIC_ADVERTISING_DATA_LEN, command_complete);
+ }
+
+ void SetPeriodicAdvertisingEnable(uint8_t enable, uint8_t handle,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+ const uint16_t HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN = 2;
+ uint8_t param[HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN];
+ memset(param, 0, HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN);
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, enable);
+ UINT8_TO_STREAM(pp, handle);
+ SendAdvCmd(FROM_HERE, HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE, param,
+ HCI_LE_ENABLE_PRIODIC_ADVERTISEMENT_LEN, command_complete);
+ }
+
+ void RemoveAdvertisingSet(uint8_t handle,
+ status_cb command_complete) override {
+ VLOG(1) << __func__;
+
+ const uint16_t cmd_length = 1;
+ uint8_t param[cmd_length];
+ memset(param, 0, cmd_length);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, handle);
+
+ SendAdvCmd(FROM_HERE, HCI_LE_REMOVE_ADVERTISING_SET, param, cmd_length,
+ command_complete);
+ }
+
+ public:
+ void OnAdvertisingSetTerminated(uint8_t length, uint8_t* p) {
+ VLOG(1) << __func__;
+ LOG_ASSERT(p);
+ uint8_t status, advertising_handle, num_completed_extended_adv_events;
+ uint16_t conn_handle;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(advertising_handle, p);
+ STREAM_TO_UINT16(conn_handle, p);
+ STREAM_TO_UINT8(num_completed_extended_adv_events, p);
+
+ conn_handle = conn_handle & 0x0FFF; // only 12 bits meaningful
+
+ AdvertisingEventObserver* observer = this->advertising_event_observer;
+ if (observer)
+ observer->OnAdvertisingSetTerminated(status, advertising_handle,
+ conn_handle,
+ num_completed_extended_adv_events);
+ }
+
+ private:
+ AdvertisingEventObserver* advertising_event_observer = nullptr;
+};
+
+} // namespace
+
+void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length) {
+ if (BleAdvertiserHciInterface::Get()) {
+ ((BleAdvertiserHciExtendedImpl*)BleAdvertiserHciInterface::Get())
+ ->OnAdvertisingSetTerminated(length, p);
+ }
+}
+
+void BleAdvertiserHciInterface::Initialize() {
+ VLOG(1) << __func__;
+ LOG_ASSERT(instance == nullptr) << "Was already initialized.";
+
+ if (controller_get_interface()->supports_ble_extended_advertising()) {
+ LOG(INFO) << "Extended advertising will be in use";
+ instance = new BleAdvertiserHciExtendedImpl();
+ } else if (BTM_BleMaxMultiAdvInstanceCount()) {
+ LOG(INFO) << "VSC advertising will be in use";
+ instance = new BleAdvertiserVscHciInterfaceImpl();
+ BTM_RegisterForVSEvents(
+ BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, true);
+ } else {
+ LOG(INFO) << "Legacy advertising will be in use";
+ instance = new BleAdvertiserLegacyHciInterfaceImpl();
+ }
+}
+
+BleAdvertiserHciInterface* BleAdvertiserHciInterface::Get() { return instance; }
+
+void BleAdvertiserHciInterface::CleanUp() {
+ VLOG(1) << __func__;
+
+ if (BTM_BleMaxMultiAdvInstanceCount()) {
+ BTM_RegisterForVSEvents(
+ BleAdvertiserVscHciInterfaceImpl::VendorSpecificEventCback, false);
+ }
+
+ delete instance;
+ instance = nullptr;
+}
diff --git a/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.h b/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.h
new file mode 100755
index 0000000..7797ce8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/ble_advertiser_hci_interface.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BLE_ADVERTISER_HCI_INTERFACE_H
+#define BLE_ADVERTISER_HCI_INTERFACE_H
+
+#include <base/bind.h>
+#include "stack/include/bt_types.h"
+
+/* This class is an abstraction of HCI commands used for managing
+ * advertisements. Please see VSC HCI SPEC at
+ * https://static.googleusercontent.com/media/source.android.com/en//devices/Android-6.0-Bluetooth-HCI-Reqs.pdf
+ * and Bluetooth 5.0 "Advertising Extension" feature for more details */
+class BleAdvertiserHciInterface {
+ public:
+ using status_cb = base::Callback<void(uint8_t /* status */)>;
+ using parameters_cb =
+ base::Callback<void(uint8_t /* status */, int8_t /* tx_power */)>;
+
+ static void Initialize();
+ static BleAdvertiserHciInterface* Get();
+ static void CleanUp();
+
+ virtual ~BleAdvertiserHciInterface() = default;
+
+ class AdvertisingEventObserver {
+ public:
+ virtual ~AdvertisingEventObserver() = default;
+ virtual void OnAdvertisingSetTerminated(
+ uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
+ uint8_t num_completed_extended_adv_events) = 0;
+ };
+
+ virtual void SetAdvertisingEventObserver(
+ AdvertisingEventObserver* observer) = 0;
+ virtual void ReadInstanceCount(
+ base::Callback<void(uint8_t /* inst_cnt*/)> cb) = 0;
+ virtual void SetParameters(uint8_t handle, uint16_t properties,
+ uint32_t adv_int_min, uint32_t adv_int_max,
+ uint8_t channel_map, uint8_t own_address_type,
+ BD_ADDR own_address, uint8_t peer_address_type,
+ BD_ADDR peer_address, uint8_t filter_policy,
+ int8_t tx_power, uint8_t primary_phy,
+ uint8_t secondary_max_skip, uint8_t secondary_phy,
+ uint8_t advertising_sid,
+ uint8_t scan_request_notify_enable,
+ parameters_cb command_complete) = 0;
+ virtual void SetAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference,
+ uint8_t data_length, uint8_t* data,
+ status_cb command_complete) = 0;
+ virtual void SetScanResponseData(uint8_t handle, uint8_t operation,
+ uint8_t fragment_preference,
+ uint8_t scan_response_data_length,
+ uint8_t* scan_response_data,
+ status_cb command_complete) = 0;
+ virtual void SetRandomAddress(uint8_t handle, BD_ADDR random_address,
+ status_cb command_complete) = 0;
+ virtual void Enable(uint8_t enable, uint8_t handle, uint16_t duration,
+ uint8_t max_extended_advertising_events,
+ status_cb command_complete) = 0;
+ virtual void SetPeriodicAdvertisingParameters(uint8_t handle,
+ uint16_t periodic_adv_int_min,
+ uint16_t periodic_adv_int_max,
+ uint16_t periodic_properties,
+ status_cb command_complete) = 0;
+ virtual void SetPeriodicAdvertisingData(uint8_t handle, uint8_t operation,
+ uint8_t adv_data_length,
+ uint8_t* adv_data,
+ status_cb command_complete) = 0;
+ virtual void SetPeriodicAdvertisingEnable(uint8_t enable, uint8_t handle,
+ status_cb command_complete) = 0;
+ virtual void RemoveAdvertisingSet(uint8_t handle,
+ status_cb command_complete) = 0;
+
+ // Some implementation don't behave well when handle value 0 is used.
+ virtual bool QuirkAdvertiserZeroHandle() { return 0; }
+};
+
+#endif // BLE_ADVERTISER_HCI_INTERFACE_H
diff --git a/mtkbt/code/bt/stack/btm/btm_acl.cc b/mtkbt/code/bt/stack/btm/btm_acl.cc
new file mode 100755
index 0000000..f525b9e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_acl.cc
@@ -0,0 +1,2424 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Name: btm_acl.cc
+ *
+ * Description: This file contains functions that handle ACL connections.
+ * This includes operations such as hold and sniff modes,
+ * supported packet types.
+ *
+ * This module contains both internal and external (API)
+ * functions. External (API) functions are distinguishable
+ * by their names beginning with uppercase BTM.
+ *
+ *
+ *****************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/osi.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+static void btm_read_remote_features(uint16_t handle);
+static void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number);
+static void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
+ uint8_t num_read_pages);
+
+/* 3 seconds timeout waiting for responses */
+#define BTM_DEV_REPLY_TIMEOUT_MS (3 * 1000)
+
+/*******************************************************************************
+ *
+ * Function btm_acl_init
+ *
+ * Description This function is called at BTM startup to initialize
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_init(void) {
+ BTM_TRACE_DEBUG("btm_acl_init");
+ /* Initialize nonzero defaults */
+ btm_cb.btm_def_link_super_tout = HCI_DEFAULT_INACT_TOUT;
+ btm_cb.acl_disc_reason = 0xff;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_bda_to_acl
+ *
+ * Description This function returns the FIRST acl_db entry for the passed
+ * BDA.
+ *
+ * Parameters bda : BD address of the remote device
+ * transport : Physical transport used for ACL connection
+ * (BR/EDR or LE)
+ *
+ * Returns Returns pointer to the ACL DB for the requested BDA if found.
+ * NULL if not found.
+ *
+ ******************************************************************************/
+tACL_CONN* btm_bda_to_acl(const BD_ADDR bda, tBT_TRANSPORT transport) {
+ tACL_CONN* p = &btm_cb.acl_db[0];
+ uint16_t xx;
+ if (bda) {
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+ if ((p->in_use) && (!memcmp(p->remote_addr, bda, BD_ADDR_LEN)) &&
+ p->transport == transport) {
+ BTM_TRACE_DEBUG("btm_bda_to_acl found");
+ return (p);
+ }
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return ((tACL_CONN*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_handle_to_acl_index
+ *
+ * Description This function returns the FIRST acl_db entry for the passed
+ * hci_handle.
+ *
+ * Returns index to the acl_db or MAX_L2CAP_LINKS.
+ *
+ ******************************************************************************/
+uint8_t btm_handle_to_acl_index(uint16_t hci_handle) {
+ tACL_CONN* p = &btm_cb.acl_db[0];
+ uint8_t xx;
+ BTM_TRACE_DEBUG("btm_handle_to_acl_index");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+ if ((p->in_use) && (p->hci_handle == hci_handle)) {
+ break;
+ }
+ }
+
+ /* If here, no BD Addr found */
+ return (xx);
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+/*******************************************************************************
+ *
+ * Function btm_ble_get_acl_remote_addr
+ *
+ * Description This function reads the active remote address used for the
+ * connection.
+ *
+ * Returns success return true, otherwise false.
+ *
+ ******************************************************************************/
+bool btm_ble_get_acl_remote_addr(tBTM_SEC_DEV_REC* p_dev_rec, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ bool st = true;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR(
+ "btm_ble_get_acl_remote_addr can not find device with matching "
+ "address");
+ return false;
+ }
+
+ switch (p_dev_rec->ble.active_addr_type) {
+ case BTM_BLE_ADDR_PSEUDO:
+ memcpy(conn_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ break;
+
+ case BTM_BLE_ADDR_RRA:
+ memcpy(conn_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+ *p_addr_type = BLE_ADDR_RANDOM;
+ break;
+
+ case BTM_BLE_ADDR_STATIC:
+ memcpy(conn_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ *p_addr_type = p_dev_rec->ble.static_addr_type;
+ break;
+
+ default:
+ BTM_TRACE_ERROR("Unknown active address: %d",
+ p_dev_rec->ble.active_addr_type);
+ st = false;
+ break;
+ }
+
+ return st;
+}
+#endif
+/*******************************************************************************
+ *
+ * Function btm_acl_created
+ *
+ * Description This function is called by L2CAP when an ACL connection
+ * is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_created(BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+ uint16_t hci_handle, uint8_t link_role,
+ tBT_TRANSPORT transport) {
+ tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+ tACL_CONN* p;
+ uint8_t xx;
+
+ BTM_TRACE_DEBUG("btm_acl_created hci_handle=%d link_role=%d transport=%d",
+ hci_handle, link_role, transport);
+ /* Ensure we don't have duplicates */
+ p = btm_bda_to_acl(bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+ p->transport = transport;
+ BTM_TRACE_DEBUG(
+ "Duplicate btm_acl_created: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ BTM_SetLinkPolicy(p->remote_addr, &btm_cb.btm_def_link_policy);
+ return;
+ }
+
+ /* Allocate acl_db entry */
+ for (xx = 0, p = &btm_cb.acl_db[0]; xx < MAX_L2CAP_LINKS; xx++, p++) {
+ if (!p->in_use) {
+ p->in_use = true;
+ p->hci_handle = hci_handle;
+ p->link_role = link_role;
+ p->link_up_issued = false;
+ memcpy(p->remote_addr, bda, BD_ADDR_LEN);
+
+ p->transport = transport;
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (transport == BT_TRANSPORT_LE)
+ btm_ble_refresh_local_resolvable_private_addr(
+ bda, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr);
+#else
+ p->conn_addr_type = BLE_ADDR_PUBLIC;
+ memcpy(p->conn_addr, &controller_get_interface()->get_address()->address,
+ BD_ADDR_LEN);
+
+#endif
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+
+ btm_pm_sm_alloc(xx);
+
+ if (dc) memcpy(p->remote_dc, dc, DEV_CLASS_LEN);
+
+ if (bdn) memcpy(p->remote_name, bdn, BTM_MAX_REM_BD_NAME_LEN);
+
+ /* if BR/EDR do something more */
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ btsnd_hcic_read_rmt_clk_offset(p->hci_handle);
+ btsnd_hcic_rmt_ver_req(p->hci_handle);
+ }
+ p_dev_rec = btm_find_dev_by_handle(hci_handle);
+
+ if (p_dev_rec) {
+ BTM_TRACE_DEBUG("device_type=0x%x", p_dev_rec->device_type);
+ }
+
+ if (p_dev_rec && !(transport == BT_TRANSPORT_LE)) {
+ /* If remote features already known, copy them and continue connection
+ * setup */
+ if ((p_dev_rec->num_read_pages) &&
+ (p_dev_rec->num_read_pages <= (HCI_EXT_FEATURES_PAGE_MAX + 1))) {
+ memcpy(p->peer_lmp_feature_pages, p_dev_rec->feature_pages,
+ (HCI_FEATURE_BYTES_PER_PAGE * p_dev_rec->num_read_pages));
+ p->num_read_pages = p_dev_rec->num_read_pages;
+
+ const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+ /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+ btm_sec_set_peer_sec_caps(p, p_dev_rec);
+
+ BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+ if (req_pend) {
+ /* Request for remaining Security Features (if any) */
+ l2cu_resubmit_pending_sec_req(p_dev_rec->bd_addr);
+ }
+ btm_establish_continue(p);
+ return;
+ }
+ }
+
+ /* If here, features are not known yet */
+ if (p_dev_rec && transport == BT_TRANSPORT_LE) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_get_acl_remote_addr(p_dev_rec, p->active_remote_addr,
+ &p->active_remote_addr_type);
+#endif
+
+ if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(
+ controller_get_interface()->get_features_ble()->as_array) ||
+ link_role == HCI_ROLE_MASTER) {
+ btsnd_hcic_ble_read_remote_feat(p->hci_handle);
+ } else {
+ btm_establish_continue(p);
+ }
+ } else {
+ btm_read_remote_features(p->hci_handle);
+ }
+
+ /* read page 1 - on rmt feature event for buffer reasons */
+ return;
+ }
+ }
+}
+/** M: fix truncated conn_handle to uint16_t type@{ */
+void btm_acl_update_conn_addr(uint16_t conn_handle, BD_ADDR address) {
+/** @} */
+ uint8_t idx = btm_handle_to_acl_index(conn_handle);
+ if (idx != MAX_L2CAP_LINKS) {
+ memcpy(btm_cb.acl_db[idx].conn_addr, address, BD_ADDR_LEN);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_report_role_change
+ *
+ * Description This function is called when the local device is deemed
+ * to be down. It notifies L2CAP of the failure.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_report_role_change(uint8_t hci_status, BD_ADDR bda) {
+ tBTM_ROLE_SWITCH_CMPL ref_data;
+ BTM_TRACE_DEBUG("btm_acl_report_role_change");
+ if (btm_cb.devcb.p_switch_role_cb &&
+ (bda && (0 == memcmp(btm_cb.devcb.switch_role_ref_data.remote_bd_addr,
+ bda, BD_ADDR_LEN)))) {
+ memcpy(&ref_data, &btm_cb.devcb.switch_role_ref_data,
+ sizeof(tBTM_ROLE_SWITCH_CMPL));
+ ref_data.hci_status = hci_status;
+ (*btm_cb.devcb.p_switch_role_cb)(&ref_data);
+ memset(&btm_cb.devcb.switch_role_ref_data, 0,
+ sizeof(tBTM_ROLE_SWITCH_CMPL));
+ btm_cb.devcb.p_switch_role_cb = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_removed
+ *
+ * Description This function is called by L2CAP when an ACL connection
+ * is removed. Since only L2CAP creates ACL links, we use
+ * the L2CAP link index as our index into the control blocks.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_removed(BD_ADDR bda, tBT_TRANSPORT transport) {
+ tACL_CONN* p;
+ tBTM_BL_EVENT_DATA evt_data;
+ tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+ BTM_TRACE_DEBUG("btm_acl_removed");
+ p = btm_bda_to_acl(bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ p->in_use = false;
+
+ /* if the disconnected channel has a pending role switch, clear it now */
+ btm_acl_report_role_change(HCI_ERR_NO_CONNECTION, bda);
+
+ /* Only notify if link up has had a chance to be issued */
+ if (p->link_up_issued) {
+ p->link_up_issued = false;
+
+ /* If anyone cares, tell him database changed */
+ if (btm_cb.p_bl_changed_cb) {
+ evt_data.event = BTM_BL_DISCN_EVT;
+ evt_data.discn.p_bda = bda;
+ evt_data.discn.handle = p->hci_handle;
+ evt_data.discn.transport = p->transport;
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+
+ btm_acl_update_busy_level(BTM_BLI_ACL_DOWN_EVT);
+ }
+
+ BTM_TRACE_DEBUG(
+ "acl hci_handle=%d transport=%d connectable_mode=0x%0x link_role=%d",
+ p->hci_handle, p->transport, btm_cb.ble_ctr_cb.inq_var.connectable_mode,
+ p->link_role);
+
+ p_dev_rec = btm_find_dev(bda);
+ if (p_dev_rec) {
+ BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x",
+ p_dev_rec->sec_flags);
+ if (p->transport == BT_TRANSPORT_LE) {
+ BTM_TRACE_DEBUG("LE link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ if ((p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) == 0) {
+ BTM_TRACE_DEBUG("Not Bonded");
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_LE_AUTHENTICATED);
+ } else {
+ BTM_TRACE_DEBUG("Bonded");
+ }
+ } else {
+ BTM_TRACE_DEBUG("Bletooth link down");
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+ BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED);
+ }
+ BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x",
+ p_dev_rec->sec_flags);
+ } else {
+ BTM_TRACE_ERROR("Device not found");
+ }
+
+ /* Clear the ACL connection data */
+ memset(p, 0, sizeof(tACL_CONN));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_device_down
+ *
+ * Description This function is called when the local device is deemed
+ * to be down. It notifies L2CAP of the failure.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_device_down(void) {
+ tACL_CONN* p = &btm_cb.acl_db[0];
+ uint16_t xx;
+ BTM_TRACE_DEBUG("btm_acl_device_down");
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+ if (p->in_use) {
+ BTM_TRACE_DEBUG("hci_handle=%d HCI_ERR_HW_FAILURE ", p->hci_handle);
+ l2c_link_hci_disc_comp(p->hci_handle, HCI_ERR_HW_FAILURE);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_update_busy_level
+ *
+ * Description This function is called to update the busy level of the
+ * system.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_update_busy_level(tBTM_BLI_EVENT event) {
+ bool old_inquiry_state = btm_cb.is_inquiry;
+ tBTM_BL_UPDATE_DATA evt;
+ evt.busy_level_flags = 0;
+ switch (event) {
+ case BTM_BLI_ACL_UP_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_ACL_UP_EVT");
+ break;
+ case BTM_BLI_ACL_DOWN_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_ACL_DOWN_EVT");
+ break;
+ case BTM_BLI_PAGE_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_PAGE_EVT");
+ btm_cb.is_paging = true;
+ evt.busy_level_flags = BTM_BL_PAGING_STARTED;
+ break;
+ case BTM_BLI_PAGE_DONE_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_PAGE_DONE_EVT");
+ btm_cb.is_paging = false;
+ evt.busy_level_flags = BTM_BL_PAGING_COMPLETE;
+ break;
+ case BTM_BLI_INQ_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_INQ_EVT");
+ btm_cb.is_inquiry = true;
+ evt.busy_level_flags = BTM_BL_INQUIRY_STARTED;
+ break;
+ case BTM_BLI_INQ_CANCEL_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_INQ_CANCEL_EVT");
+ btm_cb.is_inquiry = false;
+ evt.busy_level_flags = BTM_BL_INQUIRY_CANCELLED;
+ break;
+ case BTM_BLI_INQ_DONE_EVT:
+ BTM_TRACE_DEBUG("BTM_BLI_INQ_DONE_EVT");
+ btm_cb.is_inquiry = false;
+ evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
+ break;
+ }
+
+ uint8_t busy_level;
+ if (btm_cb.is_paging || btm_cb.is_inquiry)
+ busy_level = 10;
+ else
+ busy_level = BTM_GetNumAclLinks();
+
+ if ((busy_level != btm_cb.busy_level) ||
+ (old_inquiry_state != btm_cb.is_inquiry)) {
+ evt.event = BTM_BL_UPDATE_EVT;
+ evt.busy_level = busy_level;
+ btm_cb.busy_level = busy_level;
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK)) {
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA*)&evt);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetRole
+ *
+ * Description This function is called to get the role of the local device
+ * for the ACL connection with the specified remote device
+ *
+ * Returns BTM_SUCCESS if connection exists.
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetRole(BD_ADDR remote_bd_addr, uint8_t* p_role) {
+ tACL_CONN* p;
+ BTM_TRACE_DEBUG("BTM_GetRole");
+ p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p == NULL) {
+ *p_role = BTM_ROLE_UNDEFINED;
+ return (BTM_UNKNOWN_ADDR);
+ }
+
+ /* Get the current role */
+ *p_role = p->link_role;
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SwitchRole
+ *
+ * Description This function is called to switch role between master and
+ * slave. If role is already set it will do nothing. If the
+ * command was initiated, the callback function is called upon
+ * completion.
+ *
+ * Returns BTM_SUCCESS if already in specified role.
+ * BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if couldn't allocate memory to issue
+ * command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_MODE_UNSUPPORTED if local device does not support role
+ * switching
+ * BTM_BUSY if the previous command is not completed
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SwitchRole(BD_ADDR remote_bd_addr, uint8_t new_role,
+ tBTM_CMPL_CB* p_cb) {
+ tACL_CONN* p;
+ tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+#if (BTM_SCO_INCLUDED == TRUE)
+ bool is_sco_active;
+#endif
+ tBTM_STATUS status;
+ tBTM_PM_MODE pwr_mode;
+ tBTM_PM_PWR_MD settings;
+ BD_ADDR_PTR p_bda;
+ BTM_TRACE_API("BTM_SwitchRole BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ remote_bd_addr[0], remote_bd_addr[1], remote_bd_addr[2],
+ remote_bd_addr[3], remote_bd_addr[4], remote_bd_addr[5]);
+
+ /* Make sure the local device supports switching */
+ if (!controller_get_interface()->supports_master_slave_role_switch())
+ return (BTM_MODE_UNSUPPORTED);
+
+ if (btm_cb.devcb.p_switch_role_cb && p_cb) {
+ p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ BTM_TRACE_DEBUG(
+ "Role switch on other device is in progress 0x%02x%02x%02x%02x%02x%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+ return (BTM_BUSY);
+ }
+
+ p = btm_bda_to_acl(remote_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p == NULL) return (BTM_UNKNOWN_ADDR);
+
+ /* Finished if already in desired role */
+ if (p->link_role == new_role) return (BTM_SUCCESS);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ /* Check if there is any SCO Active on this BD Address */
+ is_sco_active = btm_is_sco_active_by_bdaddr(remote_bd_addr);
+
+ if (is_sco_active == true) return (BTM_NO_RESOURCES);
+#endif
+
+ /* Ignore role switch request if the previous request was not completed */
+ if (p->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
+ BTM_TRACE_DEBUG("BTM_SwitchRole busy: %d", p->switch_role_state);
+ return (BTM_BUSY);
+ }
+
+ status = BTM_ReadPowerMode(p->remote_addr, &pwr_mode);
+ if (status != BTM_SUCCESS) return (status);
+
+ /* Wake up the link if in sniff or park before attempting switch */
+ if (pwr_mode == BTM_PM_MD_PARK || pwr_mode == BTM_PM_MD_SNIFF) {
+ memset((void*)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+ status = BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p->remote_addr, &settings);
+ if (status != BTM_CMD_STARTED) return (BTM_WRONG_MODE);
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_MODE_CHANGE;
+ }
+ /* some devices do not support switch while encryption is on */
+ else {
+ p_dev_rec = btm_find_dev(remote_bd_addr);
+ if ((p_dev_rec != NULL) &&
+ ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) &&
+ !BTM_EPR_AVAILABLE(p)) {
+ /* bypass turning off encryption if change link key is already doing it */
+ if (p->encrypt_state != BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF) {
+ btsnd_hcic_set_conn_encrypt(p->hci_handle, false);
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ }
+
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ } else {
+ btsnd_hcic_switch_role(remote_bd_addr, new_role);
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+
+#if (BTM_DISC_DURING_RS == TRUE)
+ if (p_dev_rec) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+ }
+ }
+
+ /* Initialize return structure in case request fails */
+ if (p_cb) {
+ memcpy(btm_cb.devcb.switch_role_ref_data.remote_bd_addr, remote_bd_addr,
+ BD_ADDR_LEN);
+ btm_cb.devcb.switch_role_ref_data.role = new_role;
+ /* initialized to an error code */
+ btm_cb.devcb.switch_role_ref_data.hci_status = HCI_ERR_UNSUPPORTED_VALUE;
+ btm_cb.devcb.p_switch_role_cb = p_cb;
+ }
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_encrypt_change
+ *
+ * Description This function is when encryption of the connection is
+ * completed by the LM. Checks to see if a role switch or
+ * change of link key was active and initiates or continues
+ * process if needed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
+ uint8_t encr_enable) {
+ tACL_CONN* p;
+ uint8_t xx;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_BL_ROLE_CHG_DATA evt;
+
+ BTM_TRACE_DEBUG("btm_acl_encrypt_change handle=%d status=%d encr_enabl=%d",
+ handle, status, encr_enable);
+ xx = btm_handle_to_acl_index(handle);
+ /* don't assume that we can never get a bad hci_handle */
+ if (xx < MAX_L2CAP_LINKS)
+ p = &btm_cb.acl_db[xx];
+ else
+ return;
+
+ /* Process Role Switch if active */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) {
+ /* if encryption turn off failed we still will try to switch role */
+ if (encr_enable) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ } else {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_SWITCHING;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_TEMP_FUNC;
+ }
+
+ btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+#if (BTM_DISC_DURING_RS == TRUE)
+ p_dev_rec = btm_find_dev(p->remote_addr);
+ if (p_dev_rec != NULL) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+
+ }
+ /* Finished enabling Encryption after role switch */
+ else if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_ON) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ btm_acl_report_role_change(btm_cb.devcb.switch_role_ref_data.hci_status,
+ p->remote_addr);
+
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = btm_cb.devcb.switch_role_ref_data.role;
+ evt.p_bda = btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ evt.hci_status = btm_cb.devcb.switch_role_ref_data.hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA*)&evt);
+
+ BTM_TRACE_DEBUG(
+ "Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ evt.new_role, evt.hci_status, p->switch_role_state);
+ }
+
+#if (BTM_DISC_DURING_RS == TRUE)
+ /* If a disconnect is pending, issue it now that role switch has completed
+ */
+ p_dev_rec = btm_find_dev(p->remote_addr);
+ if (p_dev_rec != NULL) {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+ BTM_TRACE_WARNING(
+ "btm_acl_encrypt_change -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR(
+ "btm_acl_encrypt_change: tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+ PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+#endif
+ }
+}
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkPolicy
+ *
+ * Description Create and send HCI "Write Policy Set" command
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy(BD_ADDR remote_bda, uint16_t* settings) {
+ tACL_CONN* p;
+ uint8_t* localFeatures = BTM_ReadLocalFeatures();
+ BTM_TRACE_DEBUG("%s", __func__);
+ /* BTM_TRACE_API ("%s: requested settings: 0x%04x", __func__, *settings ); */
+
+ /* First, check if hold mode is supported */
+ if (*settings != HCI_DISABLE_ALL_LM_MODES) {
+ if ((*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+ (!HCI_SWITCH_SUPPORTED(localFeatures))) {
+ *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ BTM_TRACE_API("BTM_SetLinkPolicy switch not supported (settings: 0x%04x)",
+ *settings);
+ }
+ /** M: for devices in IOT list, disable role switch @{*/
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ else if ((*settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+ (HCI_SWITCH_SUPPORTED(localFeatures))) {
+ if (interop_mtk_match_addr_name(INTEROP_MTK_LINK_POLICY_DISABLE_ROLE_SWITCH,
+ ((const bt_bdaddr_t *)remote_bda))) {
+ *settings &= (~HCI_ENABLE_MASTER_SLAVE_SWITCH);
+ BTM_TRACE_API ("BTM_SetLinkPolicy switch is forbidden for IOT device (settings: 0x%04x)", *settings );
+ }
+ }
+#endif
+ /** @} */
+
+ if ((*settings & HCI_ENABLE_HOLD_MODE) &&
+ (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) {
+ *settings &= (~HCI_ENABLE_HOLD_MODE);
+ BTM_TRACE_API("BTM_SetLinkPolicy hold not supported (settings: 0x%04x)",
+ *settings);
+ }
+ if ((*settings & HCI_ENABLE_SNIFF_MODE) &&
+ (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) {
+ *settings &= (~HCI_ENABLE_SNIFF_MODE);
+ BTM_TRACE_API("BTM_SetLinkPolicy sniff not supported (settings: 0x%04x)",
+ *settings);
+ }
+ if ((*settings & HCI_ENABLE_PARK_MODE) &&
+ (!HCI_PARK_MODE_SUPPORTED(localFeatures))) {
+ *settings &= (~HCI_ENABLE_PARK_MODE);
+ BTM_TRACE_API("BTM_SetLinkPolicy park not supported (settings: 0x%04x)",
+ *settings);
+ }
+ }
+
+ p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p != NULL) {
+ btsnd_hcic_write_policy_set(p->hci_handle, *settings);
+ return BTM_CMD_STARTED;
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkPolicy
+ *
+ * Description Set the default value for HCI "Write Policy Set" command
+ * to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkPolicy(uint16_t settings) {
+ uint8_t* localFeatures = BTM_ReadLocalFeatures();
+
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkPolicy setting:0x%04x", settings);
+
+ if ((settings & HCI_ENABLE_MASTER_SLAVE_SWITCH) &&
+ (!HCI_SWITCH_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ BTM_TRACE_DEBUG(
+ "BTM_SetDefaultLinkPolicy switch not supported (settings: 0x%04x)",
+ settings);
+ }
+ if ((settings & HCI_ENABLE_HOLD_MODE) &&
+ (!HCI_HOLD_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_HOLD_MODE;
+ BTM_TRACE_DEBUG(
+ "BTM_SetDefaultLinkPolicy hold not supported (settings: 0x%04x)",
+ settings);
+ }
+ if ((settings & HCI_ENABLE_SNIFF_MODE) &&
+ (!HCI_SNIFF_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_SNIFF_MODE;
+ BTM_TRACE_DEBUG(
+ "BTM_SetDefaultLinkPolicy sniff not supported (settings: 0x%04x)",
+ settings);
+ }
+ if ((settings & HCI_ENABLE_PARK_MODE) &&
+ (!HCI_PARK_MODE_SUPPORTED(localFeatures))) {
+ settings &= ~HCI_ENABLE_PARK_MODE;
+ BTM_TRACE_DEBUG(
+ "BTM_SetDefaultLinkPolicy park not supported (settings: 0x%04x)",
+ settings);
+ }
+ BTM_TRACE_DEBUG("Set DefaultLinkPolicy:0x%04x", settings);
+
+ btm_cb.btm_def_link_policy = settings;
+
+ /* Set the default Link Policy of the controller */
+ btsnd_hcic_write_def_policy_set(settings);
+}
+
+void btm_use_preferred_conn_params(BD_ADDR bda) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
+
+ /* If there are any preferred connection parameters, set them now */
+ if ((p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+ (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX) &&
+ (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+ (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX) &&
+ (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX) &&
+ (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) &&
+ (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ ((p_lcb->min_interval < p_dev_rec->conn_params.min_conn_int &&
+ p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ||
+ (p_lcb->min_interval > p_dev_rec->conn_params.max_conn_int) ||
+ (p_lcb->latency > p_dev_rec->conn_params.slave_latency) ||
+ (p_lcb->timeout > p_dev_rec->conn_params.supervision_tout))) {
+ BTM_TRACE_DEBUG(
+ "%s: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d "
+ "supervision_tout=%d",
+ __func__, p_lcb->handle, p_dev_rec->conn_params.min_conn_int,
+ p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency,
+ p_dev_rec->conn_params.supervision_tout);
+
+ /** M: Schedule the connection update command, but not send hci command directy @{ */
+ L2CA_UpdateBleConnParams(bda, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int,
+ p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout);
+ /** @} */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_version_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the remote version info.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_version_complete(uint8_t* p) {
+ tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+ uint8_t status;
+ uint16_t handle;
+ int xx;
+ BTM_TRACE_DEBUG("btm_read_remote_version_complete");
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+
+ /* Look up the connection by handle and copy features */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_acl_cb++) {
+ if ((p_acl_cb->in_use) && (p_acl_cb->hci_handle == handle)) {
+ if (status == HCI_SUCCESS) {
+ STREAM_TO_UINT8(p_acl_cb->lmp_version, p);
+ STREAM_TO_UINT16(p_acl_cb->manufacturer, p);
+ STREAM_TO_UINT16(p_acl_cb->lmp_subversion, p);
+ }
+
+ if (p_acl_cb->transport == BT_TRANSPORT_LE) {
+ l2cble_notify_le_connection(p_acl_cb->remote_addr);
+ btm_use_preferred_conn_params(p_acl_cb->remote_addr);
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_remote_ext_features
+ *
+ * Description Local function called to process all extended features pages
+ * read from a remote device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_remote_ext_features(tACL_CONN* p_acl_cb,
+ uint8_t num_read_pages) {
+ uint16_t handle = p_acl_cb->hci_handle;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ uint8_t page_idx;
+
+ BTM_TRACE_DEBUG("btm_process_remote_ext_features");
+
+ /* Make sure we have the record to save remote features information */
+ if (p_dev_rec == NULL) {
+ /* Get a new device; might be doing dedicated bonding */
+ p_dev_rec = btm_find_or_alloc_dev(p_acl_cb->remote_addr);
+ }
+
+ p_acl_cb->num_read_pages = num_read_pages;
+ p_dev_rec->num_read_pages = num_read_pages;
+
+ /* Move the pages to placeholder */
+ for (page_idx = 0; page_idx < num_read_pages; page_idx++) {
+ if (page_idx > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("%s: page=%d unexpected", __func__, page_idx);
+ break;
+ }
+ memcpy(p_dev_rec->feature_pages[page_idx],
+ p_acl_cb->peer_lmp_feature_pages[page_idx],
+ HCI_FEATURE_BYTES_PER_PAGE);
+ }
+
+ const uint8_t req_pend = (p_dev_rec->sm4 & BTM_SM4_REQ_PEND);
+
+ /* Store the Peer Security Capabilites (in SM4 and rmt_sec_caps) */
+ btm_sec_set_peer_sec_caps(p_acl_cb, p_dev_rec);
+
+ BTM_TRACE_API("%s: pend:%d", __func__, req_pend);
+ if (req_pend) {
+ /* Request for remaining Security Features (if any) */
+ l2cu_resubmit_pending_sec_req(p_dev_rec->bd_addr);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_features
+ *
+ * Description Local function called to send a read remote supported
+ * features/remote extended features page[0].
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_features(uint16_t handle) {
+ uint8_t acl_idx;
+ tACL_CONN* p_acl_cb;
+
+ BTM_TRACE_DEBUG("btm_read_remote_features() handle: %d", handle);
+
+ acl_idx = btm_handle_to_acl_index(handle);
+ if (acl_idx >= MAX_L2CAP_LINKS) {
+ BTM_TRACE_ERROR("btm_read_remote_features handle=%d invalid", handle);
+ return;
+ }
+
+ p_acl_cb = &btm_cb.acl_db[acl_idx];
+ p_acl_cb->num_read_pages = 0;
+ memset(p_acl_cb->peer_lmp_feature_pages, 0,
+ sizeof(p_acl_cb->peer_lmp_feature_pages));
+
+ /* first send read remote supported features HCI command */
+ /* because we don't know whether the remote support extended feature command
+ */
+ btsnd_hcic_rmt_features_req(handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_ext_features
+ *
+ * Description Local function called to send a read remote extended
+ * features
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number) {
+ BTM_TRACE_DEBUG("btm_read_remote_ext_features() handle: %d page: %d", handle,
+ page_number);
+
+ btsnd_hcic_rmt_ext_features(handle, page_number);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_features_complete
+ *
+ * Description This function is called when the remote supported features
+ * complete event is received from the HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_features_complete(uint8_t* p) {
+ tACL_CONN* p_acl_cb;
+ uint8_t status;
+ uint16_t handle;
+ uint8_t acl_idx;
+
+ BTM_TRACE_DEBUG("btm_read_remote_features_complete");
+ STREAM_TO_UINT8(status, p);
+
+ if (status != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("btm_read_remote_features_complete failed (status 0x%02x)",
+ status);
+ return;
+ }
+
+ STREAM_TO_UINT16(handle, p);
+
+ acl_idx = btm_handle_to_acl_index(handle);
+ if (acl_idx >= MAX_L2CAP_LINKS) {
+ BTM_TRACE_ERROR("btm_read_remote_features_complete handle=%d invalid",
+ handle);
+ return;
+ }
+
+ p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+ /* Copy the received features page */
+ STREAM_TO_ARRAY(p_acl_cb->peer_lmp_feature_pages[0], p,
+ HCI_FEATURE_BYTES_PER_PAGE);
+
+ if ((HCI_LMP_EXTENDED_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[0])) &&
+ (controller_get_interface()
+ ->supports_reading_remote_extended_features())) {
+ /* if the remote controller has extended features and local controller
+ supports HCI_Read_Remote_Extended_Features command then start reading
+ these feature starting with extended features page 1 */
+ BTM_TRACE_DEBUG("Start reading remote extended features");
+ btm_read_remote_ext_features(handle, 1);
+ return;
+ }
+
+ /* Remote controller has no extended features. Process remote controller
+ supported features (features page 0). */
+ btm_process_remote_ext_features(p_acl_cb, 1);
+
+ /* Continue with HCI connection establishment */
+ btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_ext_features_complete
+ *
+ * Description This function is called when the remote extended features
+ * complete event is received from the HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features_complete(uint8_t* p) {
+ tACL_CONN* p_acl_cb;
+ uint8_t page_num, max_page;
+ uint16_t handle;
+ uint8_t acl_idx;
+
+ BTM_TRACE_DEBUG("btm_read_remote_ext_features_complete");
+
+ ++p;
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(page_num, p);
+ STREAM_TO_UINT8(max_page, p);
+
+ /* Validate parameters */
+ acl_idx = btm_handle_to_acl_index(handle);
+ if (acl_idx >= MAX_L2CAP_LINKS) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_complete handle=%d invalid",
+ handle);
+ return;
+ }
+
+ if (max_page > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_complete page=%d unknown",
+ max_page);
+ return;
+ }
+
+ p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+ /* Copy the received features page */
+ STREAM_TO_ARRAY(p_acl_cb->peer_lmp_feature_pages[page_num], p,
+ HCI_FEATURE_BYTES_PER_PAGE);
+
+ /* If there is the next remote features page and
+ * we have space to keep this page data - read this page */
+ if ((page_num < max_page) && (page_num < HCI_EXT_FEATURES_PAGE_MAX)) {
+ page_num++;
+ BTM_TRACE_DEBUG("BTM reads next remote extended features page (%d)",
+ page_num);
+ btm_read_remote_ext_features(handle, page_num);
+ return;
+ }
+
+ /* Reading of remote feature pages is complete */
+ BTM_TRACE_DEBUG("BTM reached last remote extended features page (%d)",
+ page_num);
+
+ /* Process the pages */
+ btm_process_remote_ext_features(p_acl_cb, (uint8_t)(page_num + 1));
+
+ /* Continue with HCI connection establishment */
+ btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_remote_ext_features_failed
+ *
+ * Description This function is called when the remote extended features
+ * complete event returns a failed status.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_remote_ext_features_failed(uint8_t status, uint16_t handle) {
+ tACL_CONN* p_acl_cb;
+ uint8_t acl_idx;
+
+ BTM_TRACE_WARNING(
+ "btm_read_remote_ext_features_failed (status 0x%02x) for handle %d",
+ status, handle);
+
+ acl_idx = btm_handle_to_acl_index(handle);
+ if (acl_idx >= MAX_L2CAP_LINKS) {
+ BTM_TRACE_ERROR("btm_read_remote_ext_features_failed handle=%d invalid",
+ handle);
+ return;
+ }
+
+ p_acl_cb = &btm_cb.acl_db[acl_idx];
+
+ /* Process supported features only */
+ btm_process_remote_ext_features(p_acl_cb, 1);
+
+ /* Continue HCI connection establishment */
+ btm_establish_continue(p_acl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_establish_continue
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the read local link policy
+ * request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_establish_continue(tACL_CONN* p_acl_cb) {
+ tBTM_BL_EVENT_DATA evt_data;
+ BTM_TRACE_DEBUG("btm_establish_continue");
+#if (BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+ if (p_acl_cb->transport == BT_TRANSPORT_BR_EDR) {
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types(p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy)
+ BTM_SetLinkPolicy(p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+ }
+#endif
+ p_acl_cb->link_up_issued = true;
+
+ /* If anyone cares, tell him database changed */
+ if (btm_cb.p_bl_changed_cb) {
+ evt_data.event = BTM_BL_CONN_EVT;
+ evt_data.conn.p_bda = p_acl_cb->remote_addr;
+ evt_data.conn.p_bdn = p_acl_cb->remote_name;
+ evt_data.conn.p_dc = p_acl_cb->remote_dc;
+ evt_data.conn.p_features = p_acl_cb->peer_lmp_feature_pages[0];
+ evt_data.conn.handle = p_acl_cb->hci_handle;
+ evt_data.conn.transport = p_acl_cb->transport;
+
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ }
+ btm_acl_update_busy_level(BTM_BLI_ACL_UP_EVT);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkSuperTout
+ *
+ * Description Set the default value for HCI "Write Link Supervision
+ * Timeout"
+ * command to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkSuperTout(uint16_t timeout) {
+ BTM_TRACE_DEBUG("BTM_SetDefaultLinkSuperTout");
+ btm_cb.btm_def_link_super_tout = timeout;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetLinkSuperTout
+ *
+ * Description Read the link supervision timeout value of the connection
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout(BD_ADDR remote_bda, uint16_t* p_timeout) {
+ tACL_CONN* p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+ BTM_TRACE_DEBUG("BTM_GetLinkSuperTout");
+ if (p != (tACL_CONN*)NULL) {
+ *p_timeout = p->link_super_tout;
+ return (BTM_SUCCESS);
+ }
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkSuperTout
+ *
+ * Description Create and send HCI "Write Link Supervision Timeout" command
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout(BD_ADDR remote_bda, uint16_t timeout) {
+ tACL_CONN* p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+
+ BTM_TRACE_DEBUG("BTM_SetLinkSuperTout");
+ if (p != (tACL_CONN*)NULL) {
+ p->link_super_tout = timeout;
+
+ /* Only send if current role is Master; 2.0 spec requires this */
+ if (p->link_role == BTM_ROLE_MASTER) {
+ btsnd_hcic_write_link_super_tout(LOCAL_BR_EDR_CONTROLLER_ID,
+ p->hci_handle, timeout);
+ return (BTM_CMD_STARTED);
+ } else
+ return (BTM_SUCCESS);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsAclConnectionUp
+ *
+ * Description This function is called to check if an ACL connection exists
+ * to a specific remote BD Address.
+ *
+ * Returns true if connection is up, else false.
+ *
+ ******************************************************************************/
+bool BTM_IsAclConnectionUp(BD_ADDR remote_bda, tBT_TRANSPORT transport) {
+ tACL_CONN* p;
+
+ BTM_TRACE_API("BTM_IsAclConnectionUp: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ return (true);
+ }
+
+ /* If here, no BD Addr found */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumAclLinks
+ *
+ * Description This function is called to count the number of
+ * ACL links that are active.
+ *
+ * Returns uint16_t Number of active ACL links
+ *
+ ******************************************************************************/
+uint16_t BTM_GetNumAclLinks(void) {
+ uint16_t num_acl = 0;
+
+ for (uint16_t i = 0; i < MAX_L2CAP_LINKS; ++i) {
+ if (btm_cb.acl_db[i].in_use) ++num_acl;
+ }
+
+ return num_acl;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_get_acl_disc_reason_code
+ *
+ * Description This function is called to get the disconnection reason code
+ * returned by the HCI at disconnection complete event.
+ *
+ * Returns true if connection is up, else false.
+ *
+ ******************************************************************************/
+uint16_t btm_get_acl_disc_reason_code(void) {
+ uint8_t res = btm_cb.acl_disc_reason;
+ BTM_TRACE_DEBUG("btm_get_acl_disc_reason_code");
+ return (res);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetHCIConnHandle
+ *
+ * Description This function is called to get the handle for an ACL
+ * connection to a specific remote BD Address.
+ *
+ * Returns the handle of the connection, or 0xFFFF if none.
+ *
+ ******************************************************************************/
+uint16_t BTM_GetHCIConnHandle(const BD_ADDR remote_bda,
+ tBT_TRANSPORT transport) {
+ tACL_CONN* p;
+ BTM_TRACE_DEBUG("BTM_GetHCIConnHandle");
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ return (p->hci_handle);
+ }
+
+ /* If here, no BD Addr found */
+ return (0xFFFF);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_clk_off_comp_evt
+ *
+ * Description This function is called when clock offset command completes.
+ *
+ * Input Parms hci_handle - connection handle associated with the change
+ * clock offset
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_clk_off_comp_evt(uint16_t hci_handle, uint16_t clock_offset) {
+ uint8_t xx;
+ BTM_TRACE_DEBUG("btm_process_clk_off_comp_evt");
+ /* Look up the connection by handle and set the current mode */
+ xx = btm_handle_to_acl_index(hci_handle);
+ if (xx < MAX_L2CAP_LINKS) btm_cb.acl_db[xx].clock_offset = clock_offset;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_role_changed
+ *
+ * Description This function is called whan a link's master/slave role
+ * change event or command status event (with error) is
+ * received. It updates the link control block, and calls the
+ * registered callback with status and role (if registered).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_acl_role_changed(uint8_t hci_status, BD_ADDR bd_addr,
+ uint8_t new_role) {
+ uint8_t* p_bda =
+ (bd_addr) ? bd_addr : btm_cb.devcb.switch_role_ref_data.remote_bd_addr;
+ tACL_CONN* p = btm_bda_to_acl(p_bda, BT_TRANSPORT_BR_EDR);
+ tBTM_ROLE_SWITCH_CMPL* p_data = &btm_cb.devcb.switch_role_ref_data;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_BL_ROLE_CHG_DATA evt;
+
+ BTM_TRACE_DEBUG("btm_acl_role_changed");
+ /* Ignore any stray events */
+ if (p == NULL) {
+ /* it could be a failure */
+ if (hci_status != HCI_SUCCESS)
+ btm_acl_report_role_change(hci_status, bd_addr);
+ return;
+ }
+
+ p_data->hci_status = hci_status;
+
+ if (hci_status == HCI_SUCCESS) {
+ p_data->role = new_role;
+ memcpy(p_data->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* Update cached value */
+ p->link_role = new_role;
+
+ /* Reload LSTO: link supervision timeout is reset in the LM after a role
+ * switch */
+ if (new_role == BTM_ROLE_MASTER) {
+ BTM_SetLinkSuperTout(p->remote_addr, p->link_super_tout);
+ }
+ } else {
+ /* so the BTM_BL_ROLE_CHG_EVT uses the old role */
+ new_role = p->link_role;
+ }
+
+ /* Check if any SCO req is pending for role change */
+ btm_sco_chk_pend_rolechange(p->hci_handle);
+
+ /* if switching state is switching we need to turn encryption on */
+ /* if idle, we did not change encryption */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_SWITCHING) {
+ btsnd_hcic_set_conn_encrypt(p->hci_handle, true);
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON;
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_ON;
+ return;
+ }
+
+ /* Set the switch_role_state to IDLE since the reply received from HCI */
+ /* regardless of its result either success or failed. */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_IN_PROGRESS) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IDLE;
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_IDLE;
+ }
+
+ /* if role switch complete is needed, report it now */
+ btm_acl_report_role_change(hci_status, bd_addr);
+
+ /* if role change event is registered, report it now */
+ if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_ROLE_CHG_MASK)) {
+ evt.event = BTM_BL_ROLE_CHG_EVT;
+ evt.new_role = new_role;
+ evt.p_bda = p_bda;
+ evt.hci_status = hci_status;
+ (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA*)&evt);
+ }
+
+ BTM_TRACE_DEBUG(
+ "Role Switch Event: new_role 0x%02x, HCI Status 0x%02x, rs_st:%d",
+ p_data->role, p_data->hci_status, p->switch_role_state);
+
+#if (BTM_DISC_DURING_RS == TRUE)
+ /* If a disconnect is pending, issue it now that role switch has completed */
+ p_dev_rec = btm_find_dev(p_bda);
+ if (p_dev_rec != NULL) {
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_DISC_PENDING) {
+ BTM_TRACE_WARNING(
+ "btm_acl_role_changed -> Issuing delayed HCI_Disconnect!!!");
+ btsnd_hcic_disconnect(p_dev_rec->hci_handle, HCI_ERR_PEER_USER);
+ }
+ BTM_TRACE_ERROR("tBTM_SEC_DEV:0x%x rs_disc_pending=%d",
+ PTR_TO_UINT(p_dev_rec), p_dev_rec->rs_disc_pending);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+ }
+
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_AllocateSCN
+ *
+ * Description Look through the Server Channel Numbers for a free one.
+ *
+ * Returns Allocated SCN number or 0 if none.
+ *
+ ******************************************************************************/
+
+uint8_t BTM_AllocateSCN(void) {
+ uint8_t x;
+ BTM_TRACE_DEBUG("BTM_AllocateSCN");
+
+ // stack reserves scn 1 for HFP, HSP we still do the correct way
+ for (x = 1; x < BTM_MAX_SCN; x++) {
+ if (!btm_cb.btm_scn[x]) {
+ btm_cb.btm_scn[x] = true;
+ return (x + 1);
+ }
+ }
+
+ return (0); /* No free ports */
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_TryAllocateSCN
+ *
+ * Description Try to allocate a fixed server channel
+ *
+ * Returns Returns true if server channel was available
+ *
+ ******************************************************************************/
+
+bool BTM_TryAllocateSCN(uint8_t scn) {
+ /* Make sure we don't exceed max port range.
+ * Stack reserves scn 1 for HFP, HSP we still do the correct way.
+ */
+ if ((scn >= BTM_MAX_SCN) || (scn == 1)) return false;
+
+ /* check if this port is available */
+ if (!btm_cb.btm_scn[scn - 1]) {
+ btm_cb.btm_scn[scn - 1] = true;
+ return true;
+ }
+
+ return (false); /* Port was busy */
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_FreeSCN
+ *
+ * Description Free the specified SCN.
+ *
+ * Returns true or false
+ *
+ ******************************************************************************/
+bool BTM_FreeSCN(uint8_t scn) {
+ BTM_TRACE_DEBUG("BTM_FreeSCN ");
+ if (scn <= BTM_MAX_SCN) {
+ btm_cb.btm_scn[scn - 1] = false;
+ return (true);
+ } else
+ return (false); /* Illegal SCN passed in */
+}
+
+/*******************************************************************************
+ *
+ * Function btm_set_packet_types
+ *
+ * Description This function sets the packet types used for a specific
+ * ACL connection. It is called internally by btm_acl_created
+ * or by an application/profile by BTM_SetPacketTypes.
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_set_packet_types(tACL_CONN* p, uint16_t pkt_types) {
+ uint16_t temp_pkt_types;
+ BTM_TRACE_DEBUG("btm_set_packet_types");
+ /* Save in the ACL control blocks, types that we support */
+ temp_pkt_types = (pkt_types & BTM_ACL_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* OR in any exception packet types if at least 2.0 version of spec */
+ temp_pkt_types |=
+ ((pkt_types & BTM_ACL_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_acl_pkt_types_supported & BTM_ACL_EXCEPTION_PKTS_MASK));
+
+ /* Exclude packet types not supported by the peer */
+ btm_acl_chk_peer_pkt_type_support(p, &temp_pkt_types);
+
+ BTM_TRACE_DEBUG("SetPacketType Mask -> 0x%04x", temp_pkt_types);
+
+ btsnd_hcic_change_conn_type(p->hci_handle, temp_pkt_types);
+ p->pkt_types_mask = temp_pkt_types;
+
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_get_max_packet_size
+ *
+ * Returns Returns maximum packet size that can be used for current
+ * connection, 0 if connection is not established
+ *
+ ******************************************************************************/
+uint16_t btm_get_max_packet_size(BD_ADDR addr) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ uint16_t pkt_types = 0;
+ uint16_t pkt_size = 0;
+ BTM_TRACE_DEBUG("btm_get_max_packet_size");
+ if (p != NULL) {
+ pkt_types = p->pkt_types_mask;
+ } else {
+ /* Special case for when info for the local device is requested */
+ if (memcmp(controller_get_interface()->get_address(), addr, BD_ADDR_LEN) ==
+ 0) {
+ pkt_types = btm_cb.btm_acl_pkt_types_supported;
+ }
+ }
+
+ if (pkt_types) {
+ if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH5))
+ pkt_size = HCI_EDR3_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH5))
+ pkt_size = HCI_EDR2_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH3))
+ pkt_size = HCI_EDR3_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH5)
+ pkt_size = HCI_DH5_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH3))
+ pkt_size = HCI_EDR2_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM5)
+ pkt_size = HCI_DM5_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH3)
+ pkt_size = HCI_DH3_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM3)
+ pkt_size = HCI_DM3_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_3_DH1))
+ pkt_size = HCI_EDR3_DH1_PACKET_SIZE;
+ else if (!(pkt_types & BTM_ACL_PKT_TYPES_MASK_NO_2_DH1))
+ pkt_size = HCI_EDR2_DH1_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DH1)
+ pkt_size = HCI_DH1_PACKET_SIZE;
+ else if (pkt_types & BTM_ACL_PKT_TYPES_MASK_DM1)
+ pkt_size = HCI_DM1_PACKET_SIZE;
+ }
+
+ return (pkt_size);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteVersion
+ *
+ * Returns If connected report peer device info
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion(BD_ADDR addr, uint8_t* lmp_version,
+ uint16_t* manufacturer,
+ uint16_t* lmp_sub_version) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG("BTM_ReadRemoteVersion");
+ if (p == NULL) return (BTM_UNKNOWN_ADDR);
+
+ if (lmp_version) *lmp_version = p->lmp_version;
+
+ if (manufacturer) *manufacturer = p->manufacturer;
+
+ if (lmp_sub_version) *lmp_sub_version = p->lmp_subversion;
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteFeatures
+ *
+ * Returns pointer to the remote supported features mask (8 bytes)
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteFeatures(BD_ADDR addr) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG("BTM_ReadRemoteFeatures");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ return (p->peer_lmp_feature_pages[0]);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteExtendedFeatures
+ *
+ * Returns pointer to the remote extended features mask (8 bytes)
+ * or NULL if bad page
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteExtendedFeatures(BD_ADDR addr, uint8_t page_number) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG("BTM_ReadRemoteExtendedFeatures");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ if (page_number > HCI_EXT_FEATURES_PAGE_MAX) {
+ BTM_TRACE_ERROR("Warning: BTM_ReadRemoteExtendedFeatures page %d unknown",
+ page_number);
+ return NULL;
+ }
+
+ return (p->peer_lmp_feature_pages[page_number]);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadNumberRemoteFeaturesPages
+ *
+ * Returns number of features pages read from the remote device.
+ *
+ ******************************************************************************/
+uint8_t BTM_ReadNumberRemoteFeaturesPages(BD_ADDR addr) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG("BTM_ReadNumberRemoteFeaturesPages");
+ if (p == NULL) {
+ return (0);
+ }
+
+ return (p->num_read_pages);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadAllRemoteFeatures
+ *
+ * Returns pointer to all features of the remote (24 bytes).
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadAllRemoteFeatures(BD_ADDR addr) {
+ tACL_CONN* p = btm_bda_to_acl(addr, BT_TRANSPORT_BR_EDR);
+ BTM_TRACE_DEBUG("BTM_ReadAllRemoteFeatures");
+ if (p == NULL) {
+ return (NULL);
+ }
+
+ return (p->peer_lmp_feature_pages[0]);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RegBusyLevelNotif
+ *
+ * Description This function is called to register a callback to receive
+ * busy level change events.
+ *
+ * Returns BTM_SUCCESS if successfully registered, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegBusyLevelNotif(tBTM_BL_CHANGE_CB* p_cb, uint8_t* p_level,
+ tBTM_BL_EVENT_MASK evt_mask) {
+ BTM_TRACE_DEBUG("BTM_RegBusyLevelNotif");
+ if (p_level) *p_level = btm_cb.busy_level;
+
+ btm_cb.bl_evt_mask = evt_mask;
+
+ if (!p_cb)
+ btm_cb.p_bl_changed_cb = NULL;
+ else if (btm_cb.p_bl_changed_cb)
+ return (BTM_BUSY);
+ else
+ btm_cb.p_bl_changed_cb = p_cb;
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetQoS
+ *
+ * Description This function is called to setup QoS
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetQoS(BD_ADDR bd, FLOW_SPEC* p_flow, tBTM_CMPL_CB* p_cb) {
+ tACL_CONN* p = &btm_cb.acl_db[0];
+
+ BTM_TRACE_API("BTM_SetQoS: BdAddr: %02x%02x%02x%02x%02x%02x", bd[0], bd[1],
+ bd[2], bd[3], bd[4], bd[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_qos_setup_cmpl_cb) return (BTM_BUSY);
+
+ p = btm_bda_to_acl(bd, BT_TRANSPORT_BR_EDR);
+ if (p != NULL) {
+ btm_cb.devcb.p_qos_setup_cmpl_cb = p_cb;
+ alarm_set_on_queue(btm_cb.devcb.qos_setup_timer, BTM_DEV_REPLY_TIMEOUT_MS,
+ btm_qos_setup_timeout, NULL, btu_general_alarm_queue);
+
+ btsnd_hcic_qos_setup(p->hci_handle, p_flow->qos_flags, p_flow->service_type,
+ p_flow->token_rate, p_flow->peak_bandwidth,
+ p_flow->latency, p_flow->delay_variation);
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_qos_setup_timeout
+ *
+ * Description Callback when QoS setup times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_qos_setup_timeout(UNUSED_ATTR void* data) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+ btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+ if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_qos_setup_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the qos setup request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_qos_setup_complete(uint8_t status, uint16_t handle,
+ FLOW_SPEC* p_flow) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_qos_setup_cmpl_cb;
+ tBTM_QOS_SETUP_CMPL qossu;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(btm_cb.devcb.qos_setup_timer);
+ btm_cb.devcb.p_qos_setup_cmpl_cb = NULL;
+
+ /* If there was a registered callback, call it */
+ if (p_cb) {
+ memset(&qossu, 0, sizeof(tBTM_QOS_SETUP_CMPL));
+ qossu.status = status;
+ qossu.handle = handle;
+ if (p_flow != NULL) {
+ qossu.flow.qos_flags = p_flow->qos_flags;
+ qossu.flow.service_type = p_flow->service_type;
+ qossu.flow.token_rate = p_flow->token_rate;
+ qossu.flow.peak_bandwidth = p_flow->peak_bandwidth;
+ qossu.flow.latency = p_flow->latency;
+ qossu.flow.delay_variation = p_flow->delay_variation;
+ }
+ BTM_TRACE_DEBUG("BTM: p_flow->delay_variation: 0x%02x",
+ qossu.flow.delay_variation);
+ (*p_cb)(&qossu);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRSSI
+ *
+ * Description This function is called to read the link policy settings.
+ * The address of link policy results are returned in the
+ * callback.
+ * (tBTM_RSSI_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI(const BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb) {
+ tACL_CONN* p;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+ BTM_TRACE_API("BTM_ReadRSSI: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_rssi_cmpl_cb) return (BTM_BUSY);
+
+ BTM_ReadDevInfo(remote_bda, &dev_type, &addr_type);
+ if (dev_type == BT_DEVICE_TYPE_BLE) transport = BT_TRANSPORT_LE;
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ btm_cb.devcb.p_rssi_cmpl_cb = p_cb;
+ alarm_set_on_queue(btm_cb.devcb.read_rssi_timer, BTM_DEV_REPLY_TIMEOUT_MS,
+ btm_read_rssi_timeout, NULL, btu_general_alarm_queue);
+
+ btsnd_hcic_read_rssi(p->hci_handle);
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLinkQuality
+ *
+ * Description This function is called to read the link qulaity.
+ * The value of the link quality is returned in the callback.
+ * (tBTM_LINK_QUALITY_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality(BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb) {
+ tACL_CONN* p;
+
+ BTM_TRACE_API("BTM_ReadLinkQuality: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_link_qual_cmpl_cb) return (BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p != (tACL_CONN*)NULL) {
+ btm_cb.devcb.p_link_qual_cmpl_cb = p_cb;
+ alarm_set_on_queue(btm_cb.devcb.read_link_quality_timer,
+ BTM_DEV_REPLY_TIMEOUT_MS, btm_read_link_quality_timeout,
+ NULL, btu_general_alarm_queue);
+
+ btsnd_hcic_get_link_quality(p->hci_handle);
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTxPower
+ *
+ * Description This function is called to read the current
+ * TX power of the connection. The tx power level results
+ * are returned in the callback.
+ * (tBTM_RSSI_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated or error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower(BD_ADDR remote_bda, tBT_TRANSPORT transport,
+ tBTM_CMPL_CB* p_cb) {
+ tACL_CONN* p;
+#define BTM_READ_RSSI_TYPE_CUR 0x00
+#define BTM_READ_RSSI_TYPE_MAX 0X01
+
+ BTM_TRACE_API("BTM_ReadTxPower: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+
+ /* If someone already waiting on the version, do not allow another */
+ if (btm_cb.devcb.p_tx_power_cmpl_cb) return (BTM_BUSY);
+
+ p = btm_bda_to_acl(remote_bda, transport);
+ if (p != (tACL_CONN*)NULL) {
+ btm_cb.devcb.p_tx_power_cmpl_cb = p_cb;
+ alarm_set_on_queue(btm_cb.devcb.read_tx_power_timer,
+ BTM_DEV_REPLY_TIMEOUT_MS, btm_read_tx_power_timeout,
+ NULL, btu_general_alarm_queue);
+
+ if (p->transport == BT_TRANSPORT_LE) {
+ memcpy(btm_cb.devcb.read_tx_pwr_addr, remote_bda, BD_ADDR_LEN);
+ btsnd_hcic_ble_read_adv_chnl_tx_power();
+ } else {
+ btsnd_hcic_read_tx_power(p->hci_handle, BTM_READ_RSSI_TYPE_CUR);
+ }
+
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If here, no BD Addr found */
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_tx_power_timeout
+ *
+ * Description Callback when reading the tx power times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_tx_power_timeout(UNUSED_ATTR void* data) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+ if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_tx_power_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the read tx power request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_tx_power_complete(uint8_t* p, bool is_ble) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_tx_power_cmpl_cb;
+ tBTM_TX_POWER_RESULTS results;
+ uint16_t handle;
+ tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+ uint16_t index;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(btm_cb.devcb.read_tx_power_timer);
+ btm_cb.devcb.p_tx_power_cmpl_cb = NULL;
+
+ /* If there was a registered callback, call it */
+ if (p_cb) {
+ STREAM_TO_UINT8(results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ if (!is_ble) {
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(results.tx_power, p);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+ memcpy(results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ } else {
+ STREAM_TO_UINT8(results.tx_power, p);
+ memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN);
+ }
+ BTM_TRACE_DEBUG("BTM TX power Complete: tx_power %d, hci status 0x%02x",
+ results.tx_power, results.hci_status);
+ } else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_rssi_timeout
+ *
+ * Description Callback when reading the RSSI times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_rssi_timeout(UNUSED_ATTR void* data) {
+ tBTM_RSSI_RESULTS results;
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+ results.status = BTM_DEVICE_TIMEOUT;
+ if (p_cb)
+ (*p_cb)(&results);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_rssi_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the read rssi request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_rssi_complete(uint8_t* p) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ tBTM_RSSI_RESULTS results;
+ uint16_t handle;
+ tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+ uint16_t index;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(btm_cb.devcb.read_rssi_timer);
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ /* If there was a registered callback, call it */
+ if (p_cb) {
+ STREAM_TO_UINT8(results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16(handle, p);
+
+ STREAM_TO_UINT8(results.rssi, p);
+ BTM_TRACE_DEBUG("BTM RSSI Complete: rssi %d, hci status 0x%02x",
+ results.rssi, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+ memcpy(results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ } else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_link_quality_timeout
+ *
+ * Description Callback when reading the link quality times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_link_quality_timeout(UNUSED_ATTR void* data) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+ btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+ if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_link_quality_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the read link quality.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_link_quality_complete(uint8_t* p) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_link_qual_cmpl_cb;
+ tBTM_LINK_QUALITY_RESULTS results;
+ uint16_t handle;
+ tACL_CONN* p_acl_cb = &btm_cb.acl_db[0];
+ uint16_t index;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(btm_cb.devcb.read_link_quality_timer);
+ btm_cb.devcb.p_link_qual_cmpl_cb = NULL;
+
+ /* If there was a registered callback, call it */
+ if (p_cb) {
+ STREAM_TO_UINT8(results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT16(handle, p);
+
+ STREAM_TO_UINT8(results.link_quality, p);
+ BTM_TRACE_DEBUG(
+ "BTM Link Quality Complete: Link Quality %d, hci status 0x%02x",
+ results.link_quality, results.hci_status);
+
+ /* Search through the list of active channels for the correct BD Addr */
+ for (index = 0; index < MAX_L2CAP_LINKS; index++, p_acl_cb++) {
+ if ((p_acl_cb->in_use) && (handle == p_acl_cb->hci_handle)) {
+ memcpy(results.rem_bda, p_acl_cb->remote_addr, BD_ADDR_LEN);
+ break;
+ }
+ }
+ } else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_remove_acl
+ *
+ * Description This function is called to disconnect an ACL connection
+ *
+ * Returns BTM_SUCCESS if successfully initiated, otherwise
+ * BTM_NO_RESOURCES.
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_remove_acl(BD_ADDR bd_addr, tBT_TRANSPORT transport) {
+ uint16_t hci_handle = BTM_GetHCIConnHandle(bd_addr, transport);
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ BTM_TRACE_DEBUG("btm_remove_acl");
+#if (BTM_DISC_DURING_RS == TRUE)
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ /* Role Switch is pending, postpone until completed */
+ if (p_dev_rec && (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING)) {
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ } else /* otherwise can disconnect right away */
+#endif
+ {
+ if (hci_handle != 0xFFFF && p_dev_rec &&
+ p_dev_rec->sec_state != BTM_SEC_STATE_DISCONNECTING) {
+ btsnd_hcic_disconnect(hci_handle, HCI_ERR_PEER_USER);
+ } else
+ status = BTM_UNKNOWN_ADDR;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetTraceLevel
+ *
+ * Description This function sets the trace level for BTM. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t BTM_SetTraceLevel(uint8_t new_level) {
+ BTM_TRACE_DEBUG("BTM_SetTraceLevel");
+ if (new_level != 0xFF) btm_cb.trace_level = new_level;
+
+ return (btm_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_cont_rswitch
+ *
+ * Description This function is called to continue processing an active
+ * role switch. It first disables encryption if enabled and
+ * EPR is not supported
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_cont_rswitch(tACL_CONN* p, tBTM_SEC_DEV_REC* p_dev_rec,
+ uint8_t hci_status) {
+ BTM_TRACE_DEBUG("btm_cont_rswitch");
+ /* Check to see if encryption needs to be turned off if pending
+ change of link key or role switch */
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ /* Must turn off Encryption first if necessary */
+ /* Some devices do not support switch or change of link key while encryption
+ * is on */
+ if (p_dev_rec != NULL &&
+ ((p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) != 0) &&
+ !BTM_EPR_AVAILABLE(p)) {
+ btsnd_hcic_set_conn_encrypt(p->hci_handle, false);
+ p->encrypt_state = BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF;
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE)
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF;
+ } else /* Encryption not used or EPR supported, continue with switch
+ and/or change of link key */
+ {
+ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_MODE_CHANGE) {
+ p->switch_role_state = BTM_ACL_SWKEY_STATE_IN_PROGRESS;
+#if (BTM_DISC_DURING_RS == TRUE)
+ if (p_dev_rec) p_dev_rec->rs_disc_pending = BTM_SEC_RS_PENDING;
+#endif
+ btsnd_hcic_switch_role(p->remote_addr, (uint8_t)!p->link_role);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_resubmit_page
+ *
+ * Description send pending page request
+ *
+ ******************************************************************************/
+void btm_acl_resubmit_page(void) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BT_HDR* p_buf;
+ uint8_t* pp;
+ BD_ADDR bda;
+ BTM_TRACE_DEBUG("btm_acl_resubmit_page");
+ /* If there were other page request schedule can start the next one */
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue);
+ if (p_buf != NULL) {
+ /* skip 3 (2 bytes opcode and 1 byte len) to get to the bd_addr
+ * for both create_conn and rmt_name */
+ pp = (uint8_t*)(p_buf + 1) + p_buf->offset + 3;
+
+ STREAM_TO_BDADDR(bda, pp);
+
+ p_dev_rec = btm_find_or_alloc_dev(bda);
+
+ memcpy(btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p_buf);
+ } else
+ btm_cb.paging = false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_reset_paging
+ *
+ * Description set paging to false and free the page queue - called at
+ * hci_reset
+ *
+ ******************************************************************************/
+void btm_acl_reset_paging(void) {
+ BT_HDR* p;
+ BTM_TRACE_DEBUG("btm_acl_reset_paging");
+ /* If we sent reset we are definitely not paging any more */
+ while ((p = (BT_HDR*)fixed_queue_try_dequeue(btm_cb.page_queue)) != NULL)
+ osi_free(p);
+
+ btm_cb.paging = false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_paging
+ *
+ * Description send a paging command or queue it in btm_cb
+ *
+ ******************************************************************************/
+void btm_acl_paging(BT_HDR* p, BD_ADDR bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_DEBUG("btm_acl_paging discing:%d, paging:%d BDA: %06x%06x",
+ btm_cb.discing, btm_cb.paging,
+ (bda[0] << 16) + (bda[1] << 8) + bda[2],
+ (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ if (btm_cb.discing) {
+ btm_cb.paging = true;
+ fixed_queue_enqueue(btm_cb.page_queue, p);
+ } else {
+ if (!BTM_ACL_IS_CONNECTED(bda)) {
+ BTM_TRACE_DEBUG(
+ "connecting_bda: %06x%06x",
+ (btm_cb.connecting_bda[0] << 16) + (btm_cb.connecting_bda[1] << 8) +
+ btm_cb.connecting_bda[2],
+ (btm_cb.connecting_bda[3] << 16) + (btm_cb.connecting_bda[4] << 8) +
+ btm_cb.connecting_bda[5]);
+ if (btm_cb.paging &&
+ memcmp(bda, btm_cb.connecting_bda, BD_ADDR_LEN) != 0) {
+ fixed_queue_enqueue(btm_cb.page_queue, p);
+ } else {
+ p_dev_rec = btm_find_or_alloc_dev(bda);
+ memcpy(btm_cb.connecting_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+
+ btm_cb.paging = true;
+ } else /* ACL is already up */
+ {
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_notif_conn_collision
+ *
+ * Description Send connection collision event to upper layer if registered
+ *
+ * Returns true if sent out to upper layer,
+ * false if no one needs the notification.
+ *
+ ******************************************************************************/
+bool btm_acl_notif_conn_collision(BD_ADDR bda) {
+ tBTM_BL_EVENT_DATA evt_data;
+
+ /* Report possible collision to the upper layer. */
+ if (btm_cb.p_bl_changed_cb) {
+ BTM_TRACE_DEBUG(
+ "btm_acl_notif_conn_collision: RemBdAddr: %02x%02x%02x%02x%02x%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ evt_data.event = BTM_BL_COLLISION_EVT;
+ evt_data.conn.p_bda = bda;
+ evt_data.conn.transport = BT_TRANSPORT_BR_EDR;
+ evt_data.conn.handle = BTM_INVALID_HCI_HANDLE;
+ (*btm_cb.p_bl_changed_cb)(&evt_data);
+ return true;
+ } else
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_acl_chk_peer_pkt_type_support
+ *
+ * Description Check if peer supports requested packets
+ *
+ ******************************************************************************/
+void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p, uint16_t* p_pkt_type) {
+ /* 3 and 5 slot packets? */
+ if (!HCI_3_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3);
+
+ if (!HCI_5_SLOT_PACKETS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ *p_pkt_type &= ~(BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* 2 and 3 MPS support? */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ /* Not supported. Add 'not_supported' mask for all 2MPS packet types */
+ *p_pkt_type |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ /* Not supported. Add 'not_supported' mask for all 3MPS packet types */
+ *p_pkt_type |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+
+ /* EDR 3 and 5 slot support? */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p->peer_lmp_feature_pages[0]) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(p->peer_lmp_feature_pages[0])) {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ /* Not supported. Add 'not_supported' mask for all 3-slot EDR packet types
+ */
+ *p_pkt_type |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p->peer_lmp_feature_pages[0]))
+ /* Not supported. Add 'not_supported' mask for all 5-slot EDR packet types
+ */
+ *p_pkt_type |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble.cc b/mtkbt/code/bt/stack/btm/btm_ble.cc
new file mode 100755
index 0000000..67ba4db
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble.cc
@@ -0,0 +1,2481 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for BLE device control utilities, and LE
+ * security functions.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include "bt_target.h"
+
+#include <base/bind.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gap_api.h"
+#include "gatt_api.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "smp_api.h"
+
+extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
+ uint16_t length, uint16_t tlen,
+ uint8_t* p_signature);
+
+/******************************************************************************/
+/* External Function to be called by other modules */
+/******************************************************************************/
+/********************************************************
+ *
+ * Function BTM_SecAddBleDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * for a LE device stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * bd_name - Name of the peer device. NULL if unknown.
+ * dev_type - Remote device's device type.
+ * addr_type - LE device address type.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleDevice(const BD_ADDR bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) {
+ BTM_TRACE_DEBUG("%s: dev_type=0x%x", __func__, dev_type);
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (!p_dev_rec) {
+ p_dev_rec = btm_sec_allocate_dev_rec();
+
+ memcpy(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ /** M: let DUMO device use same device name @{ */
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+ /** @} */
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
+ p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
+
+ /* update conn params, use default value for background connection params */
+ p_dev_rec->conn_params.min_conn_int = BTM_BLE_CONN_PARAM_UNDEF;
+ p_dev_rec->conn_params.max_conn_int = BTM_BLE_CONN_PARAM_UNDEF;
+ p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_PARAM_UNDEF;
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_PARAM_UNDEF;
+
+ BTM_TRACE_DEBUG("%s: Device added, handle=0x%x ", __func__,
+ p_dev_rec->ble_hci_handle);
+ }
+ /** M: let DUMO device use same device name @{ */
+ else {
+ if (dev_type != BT_DEVICE_DEVTYPE_DUAL)
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+ }
+ /** @} */
+
+ if (bd_name && bd_name[0]) {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ strlcpy((char*)p_dev_rec->sec_bd_name, (char*)bd_name,
+ BTM_MAX_REM_BD_NAME_LEN);
+ }
+ p_dev_rec->device_type |= dev_type;
+ p_dev_rec->ble.ble_addr_type = addr_type;
+
+ memcpy(p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN);
+ /* sync up with the Inq Data base*/
+ tBTM_INQ_INFO* p_info = BTM_InqDbRead(bd_addr);
+ if (p_info) {
+ p_info->results.ble_addr_type = p_dev_rec->ble.ble_addr_type;
+ p_info->results.device_type = p_dev_rec->device_type;
+ BTM_TRACE_DEBUG("InqDb device_type =0x%x addr_type=0x%x",
+ p_info->results.device_type, p_info->results.ble_addr_type);
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+*
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleKey(BD_ADDR bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
+ tBTM_LE_KEY_TYPE key_type) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BTM_TRACE_DEBUG("BTM_SecAddBleKey");
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (!p_dev_rec || !p_le_key ||
+ (key_type != BTM_LE_KEY_PENC && key_type != BTM_LE_KEY_PID &&
+ key_type != BTM_LE_KEY_PCSRK && key_type != BTM_LE_KEY_LENC &&
+ key_type != BTM_LE_KEY_LCSRK && key_type != BTM_LE_KEY_LID)) {
+ BTM_TRACE_WARNING(
+ "BTM_SecAddBleKey() Wrong Type, or No Device record \
+ for bdaddr: %08x%04x, Type: %d",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) +
+ bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], key_type);
+ return (false);
+ }
+
+ BTM_TRACE_DEBUG(
+ "BTM_SecAddLeKey() BDA: %08x%04x, Type: 0x%02x",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], key_type);
+
+ btm_sec_save_le_key(bd_addr, key_type, p_le_key, false);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (key_type == BTM_LE_KEY_PID || key_type == BTM_LE_KEY_LID)
+ btm_ble_resolving_list_load_dev(p_dev_rec);
+#endif
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLoadLocalKeys
+ *
+ * Description Local local identity key, encryption root or sign counter.
+ *
+ * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ * BTM_BLE_KEY_TYPE_ER
+ * or BTM_BLE_KEY_TYPE_COUNTER.
+ * p_key: pointer to the key.
+ *
+ * Returns non2.
+ *
+ ******************************************************************************/
+void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {
+ tBTM_DEVCB* p_devcb = &btm_cb.devcb;
+ BTM_TRACE_DEBUG("%s", __func__);
+ if (p_key != NULL) {
+ switch (key_type) {
+ case BTM_BLE_KEY_TYPE_ID:
+ memcpy(&p_devcb->id_keys, &p_key->id_keys,
+ sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ memcpy(p_devcb->ble_encryption_key_value, p_key->er,
+ sizeof(BT_OCTET16));
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknow local key type: %d", key_type);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceEncRoot
+ *
+ * Description This function is called to read the local device encryption
+ * root.
+ *
+ * Returns void
+ * the local device ER is copied into ble_encr_key_value
+ *
+ ******************************************************************************/
+void BTM_GetDeviceEncRoot(BT_OCTET16 ble_encr_key_value) {
+ BTM_TRACE_DEBUG("%s", __func__);
+ memcpy(ble_encr_key_value, btm_cb.devcb.ble_encryption_key_value,
+ BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceIDRoot
+ *
+ * Description This function is called to read the local device identity
+ * root.
+ *
+ * Returns void
+ * the local device IR is copied into irk
+ *
+ ******************************************************************************/
+void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {
+ BTM_TRACE_DEBUG("BTM_GetDeviceIDRoot ");
+
+ memcpy(irk, btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceDHK
+ *
+ * Description This function is called to read the local device DHK.
+ *
+ * Returns void
+ * the local device DHK is copied into dhk
+ *
+ ******************************************************************************/
+void BTM_GetDeviceDHK(BT_OCTET16 dhk) {
+ BTM_TRACE_DEBUG("BTM_GetDeviceDHK");
+ memcpy(dhk, btm_cb.devcb.id_keys.dhk, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectionAddr
+ *
+ * Description This function is called to get the local device address
+ * information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_ReadConnectionAddr(BD_ADDR remote_bda, BD_ADDR local_conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ tACL_CONN* p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
+
+ if (p_acl == NULL) {
+ BTM_TRACE_ERROR("No connection exist!");
+ return;
+ }
+ memcpy(local_conn_addr, p_acl->conn_addr, BD_ADDR_LEN);
+ *p_addr_type = p_acl->conn_addr_type;
+
+ BTM_TRACE_DEBUG("BTM_ReadConnectionAddr address type: %d addr: 0x%02x",
+ p_acl->conn_addr_type, p_acl->conn_addr[0]);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsBleConnection
+ *
+ * Description This function is called to check if the connection handle
+ * for an LE link
+ *
+ * Returns true if connection is LE link, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_IsBleConnection(uint16_t conn_handle) {
+ uint8_t xx;
+ tACL_CONN* p;
+
+ BTM_TRACE_API("BTM_IsBleConnection: conn_handle: %d", conn_handle);
+
+ xx = btm_handle_to_acl_index(conn_handle);
+ if (xx >= MAX_L2CAP_LINKS) return false;
+
+ p = &btm_cb.acl_db[xx];
+
+ return (p->transport == BT_TRANSPORT_LE);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteConnectionAddr
+ *
+ * Description This function is read the remote device address currently used
+ *
+ * Parameters pseudo_addr: pseudo random address available
+ * conn_addr:connection address used
+ * p_addr_type : BD Address type, Public or Random of the address
+ * used
+ *
+ * Returns bool, true if connection to remote device exists, else false
+ *
+ ******************************************************************************/
+bool BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ bool st = true;
+#if (BLE_PRIVACY_SPT == TRUE)
+ tACL_CONN* p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
+
+ if (p == NULL) {
+ BTM_TRACE_ERROR(
+ "BTM_ReadRemoteConnectionAddr can not find connection"
+ " with matching address");
+ return false;
+ }
+
+ memcpy(conn_addr, p->active_remote_addr, BD_ADDR_LEN);
+ *p_addr_type = p->active_remote_addr_type;
+#else
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(pseudo_addr);
+
+ memcpy(conn_addr, pseudo_addr, BD_ADDR_LEN);
+ if (p_dev_rec != NULL) {
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ }
+#endif
+ return st;
+}
+/*******************************************************************************
+ *
+ * Function BTM_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation BTM_SUCCESS if success.
+ * Otherwise, BTM_REPEATED_ATTEMPTS if too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_SecurityGrant(BD_ADDR bd_addr, uint8_t res) {
+ tSMP_STATUS res_smp =
+ (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
+ BTM_TRACE_DEBUG("BTM_SecurityGrant");
+ SMP_SecurityGrant(bd_addr, res_smp);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BlePasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which passkey was
+ * requested
+ * res - result of the operation BTM_SUCCESS if success
+ * key_len - length in bytes of the Passkey
+ * p_passkey - pointer to array with the passkey
+ * trusted_mask - bitwise OR of trusted services (array of
+ * uint32_t)
+ *
+ ******************************************************************************/
+void BTM_BlePasskeyReply(BD_ADDR bd_addr, uint8_t res, uint32_t passkey) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ tSMP_STATUS res_smp =
+ (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("Passkey reply to Unknown device");
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ BTM_TRACE_DEBUG("BTM_BlePasskeyReply");
+ SMP_PasskeyReply(bd_addr, res_smp, passkey);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+void BTM_BleConfirmReply(BD_ADDR bd_addr, uint8_t res) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ tSMP_STATUS res_smp =
+ (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("Passkey reply to Unknown device");
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ BTM_TRACE_DEBUG("%s", __func__);
+ SMP_ConfirmReply(bd_addr, res_smp);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - oob data, depending on transport and
+ * capabilities.
+ * Might be "Simple Pairing Randomizer", or
+ * "Security Manager TK Value".
+ *
+ ******************************************************************************/
+void BTM_BleOobDataReply(BD_ADDR bd_addr, uint8_t res, uint8_t len,
+ uint8_t* p_data) {
+ tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ BTM_TRACE_DEBUG("%s:", __func__);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s: Unknown device", __func__);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+ SMP_OobDataReply(bd_addr, res_smp, len, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ * data is available
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * p_c - pointer to Confirmation.
+ * p_r - pointer to Randomizer
+ *
+ ******************************************************************************/
+void BTM_BleSecureConnectionOobDataReply(BD_ADDR bd_addr, uint8_t* p_c,
+ uint8_t* p_r) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ BTM_TRACE_DEBUG("%s:", __func__);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s: Unknown device", __func__);
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+ tSMP_SC_OOB_DATA oob;
+ memset(&oob, 0, sizeof(tSMP_SC_OOB_DATA));
+
+ oob.peer_oob_data.present = true;
+ memcpy(&oob.peer_oob_data.randomizer, p_r, BT_OCTET16_LEN);
+ memcpy(&oob.peer_oob_data.commitment, p_c, BT_OCTET16_LEN);
+ oob.peer_oob_data.addr_rcvd_from.type = p_dev_rec->ble.ble_addr_type;
+ memcpy(&oob.peer_oob_data.addr_rcvd_from.bda, bd_addr, sizeof(BD_ADDR));
+
+ SMP_SecureConnectionOobDataReply((uint8_t*)&oob);
+}
+
+/******************************************************************************
+ *
+ * Function BTM_BleSetConnScanParams
+ *
+ * Description Set scan parameter used in BLE connection request
+ *
+ * Parameters: scan_interval: scan interval
+ * scan_window: scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+ bool new_param = false;
+
+ if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN,
+ BTM_BLE_SCAN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN,
+ BTM_BLE_SCAN_WIN_MAX)) {
+ if (p_ble_cb->scan_int != scan_interval) {
+ p_ble_cb->scan_int = scan_interval;
+ new_param = true;
+ }
+
+ if (p_ble_cb->scan_win != scan_window) {
+ p_ble_cb->scan_win = scan_window;
+ new_param = true;
+ }
+
+ if (new_param && p_ble_cb->conn_state == BLE_BG_CONN) {
+ btm_ble_suspend_bg_conn();
+ }
+ } else {
+ BTM_TRACE_ERROR("Illegal Connection Scan Parameters");
+ }
+}
+
+/********************************************************
+ *
+ * Function BTM_BleSetPrefConnParams
+ *
+ * Description Set a peripheral's preferred connection parameters
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * scan_interval: scan interval
+ * scan_window: scan window
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleSetPrefConnParams(BD_ADDR bd_addr, uint16_t min_conn_int,
+ uint16_t max_conn_int, uint16_t slave_latency,
+ uint16_t supervision_tout) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ BTM_TRACE_API(
+ "BTM_BleSetPrefConnParams min: %u max: %u latency: %u \
+ tout: %u",
+ min_conn_int, max_conn_int, slave_latency, supervision_tout);
+
+ if (BTM_BLE_ISVALID_PARAM(min_conn_int, BTM_BLE_CONN_INT_MIN,
+ BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(max_conn_int, BTM_BLE_CONN_INT_MIN,
+ BTM_BLE_CONN_INT_MAX) &&
+ BTM_BLE_ISVALID_PARAM(supervision_tout, BTM_BLE_CONN_SUP_TOUT_MIN,
+ BTM_BLE_CONN_SUP_TOUT_MAX) &&
+ (slave_latency <= BTM_BLE_CONN_LATENCY_MAX ||
+ slave_latency == BTM_BLE_CONN_PARAM_UNDEF)) {
+ if (p_dev_rec) {
+ /* expect conn int and stout and slave latency to be updated all together
+ */
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF ||
+ max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) {
+ if (min_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.min_conn_int = min_conn_int;
+ else
+ p_dev_rec->conn_params.min_conn_int = max_conn_int;
+
+ if (max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.max_conn_int = max_conn_int;
+ else
+ p_dev_rec->conn_params.max_conn_int = min_conn_int;
+
+ if (slave_latency != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.slave_latency = slave_latency;
+ else
+ p_dev_rec->conn_params.slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+
+ if (supervision_tout != BTM_BLE_CONN_PARAM_UNDEF)
+ p_dev_rec->conn_params.supervision_tout = supervision_tout;
+ else
+ p_dev_rec->conn_params.supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
+ }
+
+ } else {
+ BTM_TRACE_ERROR("Unknown Device, setting rejected");
+ }
+ } else {
+ BTM_TRACE_ERROR("Illegal Connection Parameters");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDevInfo
+ *
+ * Description This function is called to read the device/address type
+ * of BD address.
+ *
+ * Parameter remote_bda: remote device address
+ * p_dev_type: output parameter to read the device type.
+ * p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+void BTM_ReadDevInfo(const BD_ADDR remote_bda, tBT_DEVICE_TYPE* p_dev_type,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(remote_bda);
+ tBTM_INQ_INFO* p_inq_info = BTM_InqDbRead(remote_bda);
+
+ *p_addr_type = BLE_ADDR_PUBLIC;
+
+ if (!p_dev_rec) {
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ /* Check with the BT manager if details about remote device are known */
+ if (p_inq_info != NULL) {
+ *p_dev_type = p_inq_info->results.device_type;
+ *p_addr_type = p_inq_info->results.ble_addr_type;
+ } else {
+ /* unknown device, assume BR/EDR */
+ BTM_TRACE_DEBUG("btm_find_dev_type - unknown device, BR/EDR assumed");
+ }
+ } else /* there is a security device record exisitng */
+ {
+ /* new inquiry result, overwrite device type in security device record */
+ if (p_inq_info) {
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+ }
+ if (memcmp(p_dev_rec->bd_addr, remote_bda, BD_ADDR_LEN) == 0 &&
+ memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) {
+ *p_dev_type = p_dev_rec->device_type;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ } else if (memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) ==
+ 0) {
+ *p_dev_type = BT_DEVICE_TYPE_BLE;
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ } else /* matching static adddress only */
+ {
+ *p_dev_type = BT_DEVICE_TYPE_BREDR;
+ *p_addr_type = BLE_ADDR_PUBLIC;
+ }
+ }
+
+ BTM_TRACE_DEBUG("btm_find_dev_type - device_type = %d addr_type = %d",
+ *p_dev_type, *p_addr_type);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectedTransportAddress
+ *
+ * Description This function is called to read the paired device/address
+ * type of other device paired corresponding to the BD_address
+ *
+ * Parameter remote_bda: remote device address, carry out the transport
+ * address
+ * transport: active transport
+ *
+ * Return true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+bool BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda,
+ tBT_TRANSPORT transport) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(remote_bda);
+
+ /* if no device can be located, return */
+ if (p_dev_rec == NULL) return false;
+
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ if (btm_bda_to_acl(p_dev_rec->bd_addr, transport) != NULL) {
+ memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ return true;
+ } else if (p_dev_rec->device_type & BT_DEVICE_TYPE_BREDR) {
+ memcpy(remote_bda, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ } else
+ memset(remote_bda, 0, BD_ADDR_LEN);
+ return false;
+ }
+
+ if (transport == BT_TRANSPORT_LE) {
+ memcpy(remote_bda, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ if (btm_bda_to_acl(p_dev_rec->ble.pseudo_addr, transport) != NULL)
+ return true;
+ else
+ return false;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReceiverTest
+ *
+ * Description This function is called to start the LE Receiver test
+ *
+ * Parameter rx_freq - Frequency Range
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ btsnd_hcic_ble_receiver_test(rx_freq);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTransmitterTest
+ *
+ * Description This function is called to start the LE Transmitter test
+ *
+ * Parameter tx_freq - Frequency Range
+ * test_data_len - Length in bytes of payload data in each
+ * packet
+ * packet_payload - Pattern to use in the payload
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
+ uint8_t packet_payload,
+ tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+ btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTestEnd
+ *
+ * Description This function is called to stop the in-progress TX or RX
+ * test
+ *
+ * Parameter p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
+
+ btsnd_hcic_ble_test_end();
+}
+
+/*******************************************************************************
+ * Internal Functions
+ ******************************************************************************/
+void btm_ble_test_command_complete(uint8_t* p) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_le_test_cmd_cmpl_cb;
+
+ btm_cb.devcb.p_le_test_cmd_cmpl_cb = NULL;
+
+ if (p_cb) {
+ (*p_cb)(p);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_UseLeLink
+ *
+ * Description This function is to select the underlying physical link to
+ * use.
+ *
+ * Returns true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+bool BTM_UseLeLink(BD_ADDR bd_addr) {
+ tACL_CONN* p;
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+ bool use_le = false;
+
+ p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p != NULL) {
+ return use_le;
+ } else {
+ p = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+ if (p != NULL) {
+ use_le = true;
+ } else {
+ BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+ use_le = (dev_type == BT_DEVICE_TYPE_BLE);
+ }
+ }
+ return use_le;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetBleDataLength
+ *
+ * Description This function is to set maximum BLE transmission packet size
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, uint16_t tx_pdu_length) {
+ tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+
+ if (p_acl == NULL) {
+ BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",
+ __func__);
+ return BTM_WRONG_MODE;
+ }
+
+ BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __func__, tx_pdu_length);
+
+ if (!controller_get_interface()->supports_ble_packet_extension()) {
+ BTM_TRACE_ERROR("%s failed, request not supported", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (!HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl->peer_le_features)) {
+ BTM_TRACE_ERROR("%s failed, peer does not support request", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX)
+ tx_pdu_length = BTM_BLE_DATA_SIZE_MAX;
+ else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
+ tx_pdu_length = BTM_BLE_DATA_SIZE_MIN;
+
+ /* always set the TxTime to be max, as controller does not care for now */
+ btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
+ BTM_BLE_DATA_TX_TIME_MAX);
+
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_determine_security_act
+ *
+ * Description This function checks the security of current LE link
+ * and returns the appropriate action that needs to be
+ * taken to achieve the required security.
+ *
+ * Parameter is_originator - True if outgoing connection
+ * bdaddr: remote device address
+ * security_required: Security required for the service.
+ *
+ * Returns The appropriate security action required.
+ *
+ ******************************************************************************/
+tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator,
+ BD_ADDR bdaddr,
+ uint16_t security_required) {
+ tBTM_LE_AUTH_REQ auth_req = 0x00;
+
+ if (is_originator) {
+ if ((security_required & BTM_SEC_OUT_FLAGS) == 0 &&
+ (security_required & BTM_SEC_OUT_MITM) == 0) {
+ BTM_TRACE_DEBUG("%s No security required for outgoing connection",
+ __func__);
+ return BTM_SEC_OK;
+ }
+
+ if (security_required & BTM_SEC_OUT_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM;
+ } else {
+ if ((security_required & BTM_SEC_IN_FLAGS) == 0 &&
+ (security_required & BTM_SEC_IN_MITM) == 0) {
+ BTM_TRACE_DEBUG("%s No security required for incoming connection",
+ __func__);
+ return BTM_SEC_OK;
+ }
+
+ if (security_required & BTM_SEC_IN_MITM) auth_req |= BTM_LE_AUTH_REQ_MITM;
+ }
+
+ tBTM_BLE_SEC_REQ_ACT ble_sec_act;
+ btm_ble_link_sec_check(bdaddr, auth_req, &ble_sec_act);
+
+ BTM_TRACE_DEBUG("%s ble_sec_act %d", __func__, ble_sec_act);
+
+ if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD) return BTM_SEC_ENC_PENDING;
+
+ if (ble_sec_act == BTM_BLE_SEC_REQ_ACT_NONE) return BTM_SEC_OK;
+
+ uint8_t sec_flag = 0;
+ BTM_GetSecurityFlagsByTransport(bdaddr, &sec_flag, BT_TRANSPORT_LE);
+
+ bool is_link_encrypted = false;
+ bool is_key_mitm = false;
+ if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED | BTM_SEC_FLAG_LKEY_KNOWN)) {
+ if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) is_link_encrypted = true;
+
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) is_key_mitm = true;
+ }
+
+ if (auth_req & BTM_LE_AUTH_REQ_MITM) {
+ if (!is_key_mitm) {
+ return BTM_SEC_ENCRYPT_MITM;
+ } else {
+ if (is_link_encrypted)
+ return BTM_SEC_OK;
+ else
+ return BTM_SEC_ENCRYPT;
+ }
+ } else {
+ if (is_link_encrypted)
+ return BTM_SEC_OK;
+ else
+ return BTM_SEC_ENCRYPT_NO_MITM;
+ }
+
+ return BTM_SEC_OK;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_sec_check
+ *
+ * Description This function is to check and set the security required for
+ * LE link for LE COC.
+ *
+ * Parameter bdaddr: remote device address.
+ * psm : PSM of the LE COC sevice.
+ * is_originator: true if outgoing connection.
+ * p_callback : Pointer to the callback function.
+ * p_ref_data : Pointer to be returned along with the callback.
+ *
+ * Returns true if link already meets the required security; otherwise
+ * false.
+ *
+ ******************************************************************************/
+bool btm_ble_start_sec_check(BD_ADDR bd_addr, uint16_t psm, bool is_originator,
+ tBTM_SEC_CALLBACK* p_callback, void* p_ref_data) {
+ /* Find the service record for the PSM */
+ tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm);
+
+ /* If there is no application registered with this PSM do not allow connection
+ */
+ if (!p_serv_rec) {
+ BTM_TRACE_WARNING("%s PSM: %d no application registerd", __func__, psm);
+ (*p_callback)(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
+ return false;
+ }
+
+ tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(
+ is_originator, bd_addr, p_serv_rec->security_flags);
+
+ tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
+ bool status = false;
+
+ switch (sec_act) {
+ case BTM_SEC_OK:
+ BTM_TRACE_DEBUG("%s Security met", __func__);
+ p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
+ status = true;
+ break;
+
+ case BTM_SEC_ENCRYPT:
+ BTM_TRACE_DEBUG("%s Encryption needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT;
+ break;
+
+ case BTM_SEC_ENCRYPT_MITM:
+ BTM_TRACE_DEBUG("%s Pairing with MITM needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+ break;
+
+ case BTM_SEC_ENCRYPT_NO_MITM:
+ BTM_TRACE_DEBUG("%s Pairing with No MITM needs to be done", __func__);
+ ble_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+ break;
+
+ case BTM_SEC_ENC_PENDING:
+ BTM_TRACE_DEBUG("%s Ecryption pending", __func__);
+ break;
+ }
+
+ if (ble_sec_act == BTM_BLE_SEC_NONE) return status;
+
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ p_lcb->sec_act = sec_act;
+ BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data,
+ ble_sec_act);
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_rand_enc_complete
+ *
+ * Description This function is the callback functions for HCI_Rand command
+ * and HCI_Encrypt command is completed.
+ * This message is received from the HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_rand_enc_complete(uint8_t* p, uint16_t op_code,
+ tBTM_RAND_ENC_CB* p_enc_cplt_cback) {
+ tBTM_RAND_ENC params;
+ uint8_t* p_dest = params.param_buf;
+
+ BTM_TRACE_DEBUG("btm_ble_rand_enc_complete");
+
+ memset(&params, 0, sizeof(tBTM_RAND_ENC));
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_enc_cplt_cback && p) {
+ /* Pass paramters to the callback function */
+ STREAM_TO_UINT8(params.status, p); /* command status */
+
+ if (params.status == HCI_SUCCESS) {
+ params.opcode = op_code;
+
+ if (op_code == HCI_BLE_RAND)
+ params.param_len = BT_OCTET8_LEN;
+ else
+ params.param_len = BT_OCTET16_LEN;
+
+ /* Fetch return info from HCI event message */
+ memcpy(p_dest, p, params.param_len);
+ }
+ if (p_enc_cplt_cback) /* Call the Encryption complete callback function */
+ (*p_enc_cplt_cback)(&params);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_get_enc_key_type
+ *
+ * Description This function is to increment local sign counter
+ * Returns None
+ *
+ ******************************************************************************/
+void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, bool is_local) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_DEBUG("btm_ble_increment_sign_ctr is_local=%d", is_local);
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ if (is_local)
+ p_dev_rec->ble.keys.local_counter++;
+ else
+ p_dev_rec->ble.keys.counter++;
+ BTM_TRACE_DEBUG("is_local=%d local sign counter=%d peer sign counter=%d",
+ is_local, p_dev_rec->ble.keys.local_counter,
+ p_dev_rec->ble.keys.counter);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_get_enc_key_type
+ *
+ * Description This function is to get the BLE key type that has been
+ * exchanged betweem the local device and the peer device.
+ *
+ * Returns p_key_type: output parameter to carry the key type value.
+ *
+ ******************************************************************************/
+bool btm_ble_get_enc_key_type(BD_ADDR bd_addr, uint8_t* p_key_types) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_DEBUG("btm_ble_get_enc_key_type");
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ *p_key_types = p_dev_rec->ble.key_type;
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_get_local_div
+ *
+ * Description This function is called to read the local DIV
+ *
+ * Returns TURE - if a valid DIV is availavle
+ ******************************************************************************/
+bool btm_get_local_div(BD_ADDR bd_addr, uint16_t* p_div) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ bool status = false;
+ BTM_TRACE_DEBUG("btm_get_local_div");
+
+ BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", bd_addr[0],
+ bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ *p_div = 0;
+ p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec && p_dev_rec->ble.keys.div) {
+ status = true;
+ *p_div = p_dev_rec->ble.keys.div;
+ }
+ BTM_TRACE_DEBUG("btm_get_local_div status=%d (1-OK) DIV=0x%x", status,
+ *p_div);
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_save_le_key
+ *
+ * Description This function is called by the SMP to update
+ * an BLE key. SMP is internal, whereas all the keys shall
+ * be sent to the application. The function is also called
+ * when application passes ble key stored in NVRAM to the
+ * btm_sec.
+ * pass_to_application parameter is false in this case.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type,
+ tBTM_LE_KEY_VALUE* p_keys, bool pass_to_application) {
+ tBTM_SEC_DEV_REC* p_rec;
+ tBTM_LE_EVT_DATA cb_data;
+ uint8_t i;
+
+ BTM_TRACE_DEBUG("btm_sec_save_le_key key_type=0x%x pass_to_application=%d",
+ key_type, pass_to_application);
+ /* Store the updated key in the device database */
+
+ BTM_TRACE_DEBUG("bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", bd_addr[0],
+ bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ if ((p_rec = btm_find_dev(bd_addr)) != NULL &&
+ (p_keys || key_type == BTM_LE_KEY_LID)) {
+ btm_ble_init_pseudo_addr(p_rec, bd_addr);
+
+ switch (key_type) {
+ case BTM_LE_KEY_PENC:
+ memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
+ memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
+ p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
+ p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
+ p_rec->ble.keys.key_size = p_keys->penc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_PENC;
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ if (p_keys->penc_key.sec_level == SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+ BTM_TRACE_DEBUG(
+ "BTM_LE_KEY_PENC key_type=0x%x sec_flags=0x%x sec_leve=0x%x",
+ p_rec->ble.key_type, p_rec->sec_flags, p_rec->ble.keys.sec_level);
+ break;
+
+ case BTM_LE_KEY_PID:
+ for (i = 0; i < BT_OCTET16_LEN; i++) {
+ p_rec->ble.keys.irk[i] = p_keys->pid_key.irk[i];
+ }
+
+ // memcpy( p_rec->ble.keys.irk, p_keys->pid_key, BT_OCTET16_LEN); todo
+ // will crash the system
+ memcpy(p_rec->ble.static_addr, p_keys->pid_key.static_addr,
+ BD_ADDR_LEN);
+ p_rec->ble.static_addr_type = p_keys->pid_key.addr_type;
+ p_rec->ble.key_type |= BTM_LE_KEY_PID;
+ BTM_TRACE_DEBUG("BTM_LE_KEY_PID key_type=0x%x save peer IRK",
+ p_rec->ble.key_type);
+ /* update device record address as static address */
+ memcpy(p_rec->bd_addr, p_keys->pid_key.static_addr, BD_ADDR_LEN);
+ /* combine DUMO device security record if needed */
+ btm_consolidate_dev(p_rec);
+ break;
+
+ case BTM_LE_KEY_PCSRK:
+ memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
+ p_rec->ble.keys.counter = p_keys->pcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
+ if (p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED)
+ p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
+ else
+ p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
+
+ BTM_TRACE_DEBUG(
+ "BTM_LE_KEY_PCSRK key_type=0x%x sec_flags=0x%x sec_level=0x%x "
+ "peer_counter=%d",
+ p_rec->ble.key_type, p_rec->sec_flags,
+ p_rec->ble.keys.srk_sec_level, p_rec->ble.keys.counter);
+ break;
+
+ case BTM_LE_KEY_LENC:
+ memcpy(p_rec->ble.keys.lltk, p_keys->lenc_key.ltk, BT_OCTET16_LEN);
+ p_rec->ble.keys.div = p_keys->lenc_key.div; /* update DIV */
+ p_rec->ble.keys.sec_level = p_keys->lenc_key.sec_level;
+ p_rec->ble.keys.key_size = p_keys->lenc_key.key_size;
+ p_rec->ble.key_type |= BTM_LE_KEY_LENC;
+
+ BTM_TRACE_DEBUG(
+ "BTM_LE_KEY_LENC key_type=0x%x DIV=0x%x key_size=0x%x "
+ "sec_level=0x%x",
+ p_rec->ble.key_type, p_rec->ble.keys.div, p_rec->ble.keys.key_size,
+ p_rec->ble.keys.sec_level);
+ break;
+
+ case BTM_LE_KEY_LCSRK: /* local CSRK has been delivered */
+ memcpy(p_rec->ble.keys.lcsrk, p_keys->lcsrk_key.csrk, BT_OCTET16_LEN);
+ p_rec->ble.keys.div = p_keys->lcsrk_key.div; /* update DIV */
+ p_rec->ble.keys.local_csrk_sec_level = p_keys->lcsrk_key.sec_level;
+ p_rec->ble.keys.local_counter = p_keys->lcsrk_key.counter;
+ p_rec->ble.key_type |= BTM_LE_KEY_LCSRK;
+ BTM_TRACE_DEBUG(
+ "BTM_LE_KEY_LCSRK key_type=0x%x DIV=0x%x scrk_sec_level=0x%x "
+ "local_counter=%d",
+ p_rec->ble.key_type, p_rec->ble.keys.div,
+ p_rec->ble.keys.local_csrk_sec_level,
+ p_rec->ble.keys.local_counter);
+ break;
+
+ case BTM_LE_KEY_LID:
+ p_rec->ble.key_type |= BTM_LE_KEY_LID;
+ break;
+ default:
+ BTM_TRACE_WARNING("btm_sec_save_le_key (Bad key_type 0x%02x)",
+ key_type);
+ return;
+ }
+
+ BTM_TRACE_DEBUG(
+ "BLE key type 0x%02x updated for BDA: %08x%04x (btm_sec_save_le_key)",
+ key_type, (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) +
+ bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+
+ /* Notify the application that one of the BLE keys has been updated
+ If link key is in progress, it will get sent later.*/
+ if (pass_to_application && btm_cb.api.p_le_callback) {
+ cb_data.key.p_key_value = p_keys;
+ cb_data.key.key_type = key_type;
+
+ (*btm_cb.api.p_le_callback)(BTM_LE_KEY_EVT, bd_addr, &cb_data);
+ }
+ return;
+ }
+
+ BTM_TRACE_WARNING(
+ "BLE key type 0x%02x called for Unknown BDA or type: %08x%04x !! "
+ "(btm_sec_save_le_key)",
+ key_type,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+
+ if (p_rec) {
+ BTM_TRACE_DEBUG("sec_flags=0x%x", p_rec->sec_flags);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_sec_key_size
+ *
+ * Description update the current lin kencryption key size
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_update_sec_key_size(BD_ADDR bd_addr, uint8_t enc_key_size) {
+ tBTM_SEC_DEV_REC* p_rec;
+
+ BTM_TRACE_DEBUG("btm_ble_update_sec_key_size enc_key_size = %d",
+ enc_key_size);
+
+ p_rec = btm_find_dev(bd_addr);
+ if (p_rec != NULL) {
+ p_rec->enc_key_size = enc_key_size;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_sec_key_size
+ *
+ * Description update the current lin kencryption key size
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t btm_ble_read_sec_key_size(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_rec;
+
+ p_rec = btm_find_dev(bd_addr);
+ if (p_rec != NULL) {
+ return p_rec->enc_key_size;
+ } else
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_link_sec_check
+ *
+ * Description Check BLE link security level match.
+ *
+ * Returns true: check is OK and the *p_sec_req_act contain the action
+ *
+ ******************************************************************************/
+void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req,
+ tBTM_BLE_SEC_REQ_ACT* p_sec_req_act) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ uint8_t req_sec_level = BTM_LE_SEC_NONE, cur_sec_level = BTM_LE_SEC_NONE;
+
+ BTM_TRACE_DEBUG("btm_ble_link_sec_check auth_req =0x%x", auth_req);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("btm_ble_link_sec_check received for unknown device");
+ return;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ /* race condition: discard the security request while master is encrypting
+ * the link */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_DISCARD;
+ } else {
+ req_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ if (auth_req & BTM_LE_AUTH_REQ_MITM) {
+ req_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ }
+
+ BTM_TRACE_DEBUG("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* currently encrpted */
+ if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) {
+ if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED)
+ cur_sec_level = BTM_LE_SEC_AUTHENTICATED;
+ else
+ cur_sec_level = BTM_LE_SEC_UNAUTHENTICATE;
+ } else /* unencrypted link */
+ {
+ /* if bonded, get the key security level */
+ if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC)
+ cur_sec_level = p_dev_rec->ble.keys.sec_level;
+ else
+ cur_sec_level = BTM_LE_SEC_NONE;
+ }
+
+ if (cur_sec_level >= req_sec_level) {
+ /* To avoid re-encryption on an encrypted link for an equal condition
+ * encryption */
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_ENCRYPT;
+ } else {
+ /* start the pariring process to upgrade the keys*/
+ *p_sec_req_act = BTM_BLE_SEC_REQ_ACT_PAIR;
+ }
+ }
+
+ BTM_TRACE_DEBUG("cur_sec_level=%d req_sec_level=%d sec_req_act=%d",
+ cur_sec_level, req_sec_level, *p_sec_req_act);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_encryption
+ *
+ * Description This function is called to ensure that LE connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Returns void
+ * the local device ER is copied into er
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_set_encryption(BD_ADDR bd_addr, tBTM_BLE_SEC_ACT sec_act,
+ uint8_t link_role) {
+ tBTM_STATUS cmd = BTM_NO_RESOURCES;
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
+ tBTM_BLE_SEC_REQ_ACT sec_req_act;
+ tBTM_LE_AUTH_REQ auth_req;
+
+ if (p_rec == NULL) {
+ BTM_TRACE_WARNING(
+ "btm_ble_set_encryption (NULL device record!! sec_act=0x%x", sec_act);
+ return (BTM_WRONG_MODE);
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_set_encryption sec_act=0x%x role_master=%d", sec_act,
+ p_rec->role_master);
+
+ if (sec_act == BTM_BLE_SEC_ENCRYPT_MITM) {
+ p_rec->security_required |= BTM_SEC_IN_MITM;
+ }
+
+ switch (sec_act) {
+ case BTM_BLE_SEC_ENCRYPT:
+ if (link_role == BTM_ROLE_MASTER) {
+ /* start link layer encryption using the security info stored */
+ cmd = btm_ble_start_encrypt(bd_addr, false, NULL);
+ break;
+ }
+ /* if salve role then fall through to call SMP_Pair below which will send a
+ sec_request to request the master to encrypt the link */
+ case BTM_BLE_SEC_ENCRYPT_NO_MITM:
+ case BTM_BLE_SEC_ENCRYPT_MITM:
+ auth_req = (sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM)
+ ? SMP_AUTH_GEN_BOND
+ : (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT);
+ btm_ble_link_sec_check(bd_addr, auth_req, &sec_req_act);
+ if (sec_req_act == BTM_BLE_SEC_REQ_ACT_NONE ||
+ sec_req_act == BTM_BLE_SEC_REQ_ACT_DISCARD) {
+ BTM_TRACE_DEBUG("%s, no action needed. Ignore", __func__);
+ cmd = BTM_SUCCESS;
+ break;
+ }
+ if (link_role == BTM_ROLE_MASTER) {
+ if (sec_req_act == BTM_BLE_SEC_REQ_ACT_ENCRYPT) {
+ cmd = btm_ble_start_encrypt(bd_addr, false, NULL);
+ break;
+ }
+ }
+
+ if (SMP_Pair(bd_addr) == SMP_STARTED) {
+ cmd = BTM_CMD_STARTED;
+ p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ }
+ break;
+
+ default:
+ cmd = BTM_WRONG_MODE;
+ break;
+ }
+ return cmd;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_ltk_request
+ *
+ * Description This function is called when encryption request is received
+ * on a slave device.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8], uint16_t ediv) {
+ tBTM_CB* p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ BT_OCTET8 dummy_stk = {0};
+
+ BTM_TRACE_DEBUG("btm_ble_ltk_request");
+
+ p_cb->ediv = ediv;
+
+ memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+
+ if (p_dev_rec != NULL) {
+ if (!smp_proc_ltk_request(p_dev_rec->bd_addr))
+ btm_ble_ltk_request_reply(p_dev_rec->bd_addr, false, dummy_stk);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_encrypt
+ *
+ * Description This function is called to start LE encryption.
+ *
+ *
+ * Returns BTM_SUCCESS if encryption was started successfully
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, bool use_stk, BT_OCTET16 stk) {
+ tBTM_CB* p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
+ BT_OCTET8 dummy_rand = {0};
+
+ BTM_TRACE_DEBUG("btm_ble_start_encrypt");
+
+ if (!p_rec) {
+ BTM_TRACE_ERROR("Link is not active, can not encrypt!");
+ return BTM_WRONG_MODE;
+ }
+
+ if (p_rec->sec_state == BTM_SEC_STATE_ENCRYPTING) {
+ BTM_TRACE_WARNING("Link Encryption is active, Busy!");
+ return BTM_BUSY;
+ }
+
+ p_cb->enc_handle = p_rec->ble_hci_handle;
+
+ if (use_stk) {
+ btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, dummy_rand, 0, stk);
+ } else if (p_rec->ble.key_type & BTM_LE_KEY_PENC) {
+ btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
+ p_rec->ble.keys.ediv, p_rec->ble.keys.pltk);
+ } else {
+ BTM_TRACE_ERROR("No key available to encrypt the link");
+ return BTM_NO_RESOURCES;
+ }
+
+ if (p_rec->sec_state == BTM_SEC_STATE_IDLE)
+ p_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_link_encrypted
+ *
+ * Description This function is called when LE link encrption status is
+ * changed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_link_encrypted(BD_ADDR bd_addr, uint8_t encr_enable) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ bool enc_cback;
+
+ if (!p_dev_rec) {
+ BTM_TRACE_WARNING(
+ "btm_ble_link_encrypted (No Device Found!) encr_enable=%d",
+ encr_enable);
+ return;
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_link_encrypted encr_enable=%d", encr_enable);
+
+ enc_cback = (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING);
+
+ smp_link_encrypted(bd_addr, encr_enable);
+
+ BTM_TRACE_DEBUG(" p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ if (encr_enable && p_dev_rec->enc_key_size == 0)
+ p_dev_rec->enc_key_size = p_dev_rec->ble.keys.key_size;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ if (p_dev_rec->p_callback && enc_cback) {
+ if (encr_enable)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, true);
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(HANDLE_KEY_MISSING) && (HANDLE_KEY_MISSING == TRUE)
+ else if (p_dev_rec->role_master && (p_dev_rec->sec_status == HCI_ERR_KEY_MISSING))
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_KEY_MISSING, TRUE);
+ else if (p_dev_rec->role_master)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, TRUE);
+#else
+ else if (p_dev_rec->role_master)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, TRUE);
+#endif
+#endif
+ }
+ /* to notify GATT to send data if any request is pending */
+ gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_ltk_request_reply
+ *
+ * Description This function is called to send a LTK request reply on a
+ * slave
+ * device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_ltk_request_reply(BD_ADDR bda, bool use_stk, BT_OCTET16 stk) {
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bda);
+ tBTM_CB* p_cb = &btm_cb;
+
+ if (p_rec == NULL) {
+ BTM_TRACE_ERROR("btm_ble_ltk_request_reply received for unknown device");
+ return;
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_ltk_request_reply");
+ p_cb->enc_handle = p_rec->ble_hci_handle;
+ p_cb->key_size = p_rec->ble.keys.key_size;
+
+ BTM_TRACE_ERROR("key size = %d", p_rec->ble.keys.key_size);
+ if (use_stk) {
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, stk);
+ } else /* calculate LTK using peer device */
+ {
+ if (p_rec->ble.key_type & BTM_LE_KEY_LENC)
+ btsnd_hcic_ble_ltk_req_reply(btm_cb.enc_handle, p_rec->ble.keys.lltk);
+ else
+ btsnd_hcic_ble_ltk_req_neg_reply(btm_cb.enc_handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_io_capabilities_req
+ *
+ * Description This function is called to handle SMP get IO capability
+ * request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t btm_ble_io_capabilities_req(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBTM_LE_IO_REQ* p_data) {
+ uint8_t callback_rc = BTM_SUCCESS;
+ BTM_TRACE_DEBUG("btm_ble_io_capabilities_req");
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_le_callback)(
+ BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)p_data);
+ }
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != p_data->oob_data)) {
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ if (btm_cb.devcb.keep_rfu_in_auth_req) {
+ BTM_TRACE_DEBUG("btm_ble_io_capabilities_req keep_rfu_in_auth_req = %u",
+ btm_cb.devcb.keep_rfu_in_auth_req);
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK_KEEP_RFU;
+ btm_cb.devcb.keep_rfu_in_auth_req = false;
+ } else { /* default */
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+ }
+#else
+ p_data->auth_req &= BTM_LE_AUTH_REQ_MASK;
+#endif
+
+ BTM_TRACE_DEBUG(
+ "btm_ble_io_capabilities_req 1: p_dev_rec->security_required = %d "
+ "auth_req:%d",
+ p_dev_rec->security_required, p_data->auth_req);
+ BTM_TRACE_DEBUG(
+ "btm_ble_io_capabilities_req 2: i_keys=0x%x r_keys=0x%x (bit 0-LTK "
+ "1-IRK 2-CSRK)",
+ p_data->init_keys, p_data->resp_keys);
+
+ /* if authentication requires MITM protection, put on the mask */
+ if (p_dev_rec->security_required & BTM_SEC_IN_MITM)
+ p_data->auth_req |= BTM_LE_AUTH_REQ_MITM;
+
+ if (!(p_data->auth_req & SMP_AUTH_BOND)) {
+ BTM_TRACE_DEBUG("Non bonding: No keys should be exchanged");
+ p_data->init_keys = 0;
+ p_data->resp_keys = 0;
+ }
+
+ BTM_TRACE_DEBUG("btm_ble_io_capabilities_req 3: auth_req:%d",
+ p_data->auth_req);
+ BTM_TRACE_DEBUG("btm_ble_io_capabilities_req 4: i_keys=0x%x r_keys=0x%x",
+ p_data->init_keys, p_data->resp_keys);
+
+ BTM_TRACE_DEBUG(
+ "btm_ble_io_capabilities_req 5: p_data->io_cap = %d auth_req:%d",
+ p_data->io_cap, p_data->auth_req);
+
+ /* remove MITM protection requirement if IO cap does not allow it */
+ if ((p_data->io_cap == BTM_IO_CAP_NONE) && p_data->oob_data == SMP_OOB_NONE)
+ p_data->auth_req &= ~BTM_LE_AUTH_REQ_MITM;
+
+ if (!(p_data->auth_req & SMP_SC_SUPPORT_BIT)) {
+ /* if Secure Connections are not supported then remove LK derivation,
+ ** and keypress notifications.
+ */
+ BTM_TRACE_DEBUG(
+ "%s-SC not supported -> No LK derivation, no keypress notifications",
+ __func__);
+ p_data->auth_req &= ~SMP_KP_SUPPORT_BIT;
+ p_data->init_keys &= ~SMP_SEC_KEY_TYPE_LK;
+ p_data->resp_keys &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ BTM_TRACE_DEBUG(
+ "btm_ble_io_capabilities_req 6: IO_CAP:%d oob_data:%d auth_req:0x%02x",
+ p_data->io_cap, p_data->oob_data, p_data->auth_req);
+ }
+ return callback_rc;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_br_keys_req
+ *
+ * Description This function is called to handle SMP request for keys sent
+ * over BR/EDR.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t btm_ble_br_keys_req(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBTM_LE_IO_REQ* p_data) {
+ uint8_t callback_rc = BTM_SUCCESS;
+ BTM_TRACE_DEBUG("%s", __func__);
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_le_callback)(
+ BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)p_data);
+ }
+
+ return callback_rc;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_connected
+ *
+ * Description This function is when a LE connection to the peer device is
+ * establsihed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_connected(uint8_t* bda, uint16_t handle, uint8_t enc_mode,
+ uint8_t role, tBLE_ADDR_TYPE addr_type,
+ UNUSED_ATTR bool addr_matched) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT("btm_ble_connected");
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "Security Manager: btm_ble_connected : handle:%d enc_mode:%d bda:%x "
+ "RName:%s",
+ handle, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5],
+ p_dev_rec->sec_bd_name);
+
+ BTM_TRACE_DEBUG("btm_ble_connected sec_flags=0x%x", p_dev_rec->sec_flags);
+ } else {
+ BTM_TRACE_EVENT(
+ "Security Manager: btm_ble_connected: handle:%d enc_mode:%d "
+ "bda:%x ",
+ handle, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ }
+
+ if (!p_dev_rec) {
+ /* There is no device record for new connection. Allocate one */
+ p_dev_rec = btm_sec_alloc_dev(bda);
+ if (p_dev_rec == NULL) return;
+ } else /* Update the timestamp for this device */
+ {
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ }
+
+ /* update device information */
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BLE;
+ p_dev_rec->ble_hci_handle = handle;
+ p_dev_rec->ble.ble_addr_type = addr_type;
+ /* update pseudo address */
+ memcpy(p_dev_rec->ble.pseudo_addr, bda, BD_ADDR_LEN);
+
+ p_dev_rec->role_master = false;
+ if (role == HCI_ROLE_MASTER) p_dev_rec->role_master = true;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (!addr_matched) p_dev_rec->ble.active_addr_type = BTM_BLE_ADDR_PSEUDO;
+
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_RANDOM && !addr_matched)
+ memcpy(p_dev_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+#endif
+
+ p_cb->inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+
+ return;
+}
+
+/*****************************************************************************
+ * Function btm_ble_conn_complete
+ *
+ * Description LE connection complete.
+ *
+ *****************************************************************************/
+void btm_ble_conn_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len,
+ bool enhanced) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ uint8_t peer_addr_type;
+#endif
+ BD_ADDR local_rpa, peer_rpa;
+ uint8_t role, status, bda_type;
+ uint16_t handle;
+ BD_ADDR bda;
+ uint16_t conn_interval, conn_latency, conn_timeout;
+ bool match = false;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(role, p);
+ STREAM_TO_UINT8(bda_type, p);
+ STREAM_TO_BDADDR(bda, p);
+
+ if (status == 0) {
+ if (enhanced) {
+ STREAM_TO_BDADDR(local_rpa, p);
+ STREAM_TO_BDADDR(peer_rpa, p);
+ }
+
+ STREAM_TO_UINT16(conn_interval, p);
+ STREAM_TO_UINT16(conn_latency, p);
+ STREAM_TO_UINT16(conn_timeout, p);
+ handle = HCID_GET_HANDLE(handle);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ peer_addr_type = bda_type;
+ match = btm_identity_addr_to_random_pseudo(bda, &bda_type, true);
+
+ /* possiblly receive connection complete with resolvable random while
+ the device has been paired */
+ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) {
+ tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda);
+ if (match_rec) {
+ LOG_INFO(LOG_TAG, "%s matched and resolved random address", __func__);
+ match = true;
+ match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+ if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
+ /* assign the original address to be the current report address */
+ memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ } else {
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ }
+ } else {
+ LOG_INFO(LOG_TAG, "%s unable to match and resolve random address",
+ __func__);
+ }
+ }
+#endif
+
+ btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type,
+ match);
+
+ l2cble_conn_comp(handle, role, bda, bda_type, conn_interval, conn_latency,
+ conn_timeout);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (enhanced) {
+ btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
+
+ if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
+ btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa,
+ BLE_ADDR_RANDOM);
+ }
+#endif
+ } else {
+ role = HCI_ROLE_UNKNOWN;
+ if (status != HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+#endif
+ } else {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+ }
+ }
+
+ btm_ble_update_mode_operation(role, bda, status);
+}
+
+/*****************************************************************************
+ * Function btm_ble_create_ll_conn_complete
+ *
+ * Description LE connection complete.
+ *
+ *****************************************************************************/
+void btm_ble_create_ll_conn_complete(uint8_t status) {
+ if (status != HCI_SUCCESS) {
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
+ }
+}
+/*****************************************************************************
+ * Function btm_proc_smp_cback
+ *
+ * Description This function is the SMP callback handler.
+ *
+ *****************************************************************************/
+uint8_t btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr,
+ tSMP_EVT_DATA* p_data) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ uint8_t res = 0;
+
+ BTM_TRACE_DEBUG("btm_proc_smp_cback event = %d", event);
+
+ if (p_dev_rec != NULL) {
+ switch (event) {
+ case SMP_IO_CAP_REQ_EVT:
+ btm_ble_io_capabilities_req(p_dev_rec,
+ (tBTM_LE_IO_REQ*)&p_data->io_req);
+ break;
+
+ case SMP_BR_KEYS_REQ_EVT:
+ btm_ble_br_keys_req(p_dev_rec, (tBTM_LE_IO_REQ*)&p_data->io_req);
+ break;
+
+ case SMP_PASSKEY_REQ_EVT:
+ case SMP_PASSKEY_NOTIF_EVT:
+ case SMP_OOB_REQ_EVT:
+ case SMP_NC_REQ_EVT:
+ case SMP_SC_OOB_REQ_EVT:
+ /* fall through */
+ p_dev_rec->sec_flags |= BTM_SEC_LE_AUTHENTICATED;
+
+ case SMP_SEC_REQUEST_EVT:
+ if (event == SMP_SEC_REQUEST_EVT &&
+ btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+ BTM_TRACE_DEBUG("%s: Ignoring SMP Security request", __func__);
+ break;
+ }
+ memcpy(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+ /* fall through */
+
+ case SMP_COMPLT_EVT:
+ if (btm_cb.api.p_le_callback) {
+ /* the callback function implementation may change the IO
+ * capability... */
+ BTM_TRACE_DEBUG("btm_cb.api.p_le_callback=0x%x",
+ btm_cb.api.p_le_callback);
+ (*btm_cb.api.p_le_callback)(event, bd_addr,
+ (tBTM_LE_EVT_DATA*)p_data);
+ }
+
+ if (event == SMP_COMPLT_EVT) {
+ BTM_TRACE_DEBUG(
+ "evt=SMP_COMPLT_EVT before update sec_level=0x%x sec_flags=0x%x",
+ p_data->cmplt.sec_level, p_dev_rec->sec_flags);
+
+ res = (p_data->cmplt.reason == SMP_SUCCESS) ? BTM_SUCCESS
+ : BTM_ERR_PROCESSING;
+
+ BTM_TRACE_DEBUG(
+ "after update result=%d sec_level=0x%x sec_flags=0x%x", res,
+ p_data->cmplt.sec_level, p_dev_rec->sec_flags);
+
+ if (p_data->cmplt.is_pair_cancel &&
+ btm_cb.api.p_bond_cancel_cmpl_callback) {
+ BTM_TRACE_DEBUG("Pairing Cancel completed");
+ (*btm_cb.api.p_bond_cancel_cmpl_callback)(BTM_SUCCESS);
+ }
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ if (res != BTM_SUCCESS) {
+ if (!btm_cb.devcb.no_disc_if_pair_fail &&
+ p_data->cmplt.reason != SMP_CONN_TOUT) {
+ BTM_TRACE_DEBUG("Pairing failed - prepare to remove ACL");
+ /** M: Bug fix for HOGP reconnect pending bug @{ */
+ p_dev_rec->sec_flags &= ~BTM_SEC_LE_AUTHENTICATED;
+ /** @} */
+ l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ } else {
+ BTM_TRACE_DEBUG("Pairing failed - Not Removing ACL");
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ }
+#else
+ if (res != BTM_SUCCESS && p_data->cmplt.reason != SMP_CONN_TOUT) {
+ BTM_TRACE_DEBUG("Pairing failed - prepare to remove ACL");
+ /** M: Bug fix for HOGP reconnect pending bug @{ */
+ p_dev_rec->sec_flags &= ~BTM_SEC_LE_AUTHENTICATED;
+ /** @} */
+ l2cu_start_post_bond_timer(p_dev_rec->ble_hci_handle);
+ }
+#endif
+
+ BTM_TRACE_DEBUG(
+ "btm_cb pairing_state=%x pairing_flags=%x pin_code_len=%x",
+ btm_cb.pairing_state, btm_cb.pairing_flags, btm_cb.pin_code_len);
+ BTM_TRACE_DEBUG("btm_cb.pairing_bda %02x:%02x:%02x:%02x:%02x:%02x",
+ btm_cb.pairing_bda[0], btm_cb.pairing_bda[1],
+ btm_cb.pairing_bda[2], btm_cb.pairing_bda[3],
+ btm_cb.pairing_bda[4], btm_cb.pairing_bda[5]);
+
+ /* Reset btm state only if the callback address matches pairing
+ * address*/
+ if (memcmp(bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) {
+ memset(btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.pairing_state = BTM_PAIR_STATE_IDLE;
+ btm_cb.pairing_flags = 0;
+ }
+
+ if (res == BTM_SUCCESS) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* add all bonded device into resolving list if IRK is available*/
+ btm_ble_resolving_list_load_dev(p_dev_rec);
+#endif
+ }
+
+ btm_sec_dev_rec_cback_event(p_dev_rec, res, true);
+ }
+ break;
+
+ default:
+ BTM_TRACE_DEBUG("unknown event = %d", event);
+ break;
+ }
+ } else {
+ BTM_TRACE_ERROR("btm_proc_smp_cback received for unknown device");
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleDataSignature
+ *
+ * Description This function is called to sign the data using AES128 CMAC
+ * algorith.
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_text: singing data
+ * len: length of the data to be signed.
+ * signature: output parameter where data signature is going to
+ * be stored.
+ *
+ * Returns true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleDataSignature(BD_ADDR bd_addr, uint8_t* p_text, uint16_t len,
+ BLE_SIGNATURE signature) {
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ bool ret = false;
+ if (p_rec == NULL) {
+ BTM_TRACE_ERROR("%s-data signing can not be done from unknown device",
+ __func__);
+ } else {
+ uint8_t* p_mac = (uint8_t*)signature;
+ uint8_t* pp;
+ uint8_t* p_buf = (uint8_t*)osi_malloc(len + 4);
+
+ BTM_TRACE_DEBUG("%s-Start to generate Local CSRK", __func__);
+ pp = p_buf;
+ /* prepare plain text */
+ if (p_text) {
+ memcpy(p_buf, p_text, len);
+ pp = (p_buf + len);
+ }
+
+ UINT32_TO_STREAM(pp, p_rec->ble.keys.local_counter);
+ UINT32_TO_STREAM(p_mac, p_rec->ble.keys.local_counter);
+
+ ret = aes_cipher_msg_auth_code(p_rec->ble.keys.lcsrk, p_buf,
+ (uint16_t)(len + 4), BTM_CMAC_TLEN_SIZE,
+ p_mac);
+ if (ret == true) {
+ btm_ble_increment_sign_ctr(bd_addr, true);
+ }
+
+ BTM_TRACE_DEBUG("%s p_mac = %d", __func__, p_mac);
+ BTM_TRACE_DEBUG(
+ "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
+ "0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ BTM_TRACE_DEBUG(
+ "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
+ "0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+ osi_free(p_buf);
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleVerifySignature
+ *
+ * Description This function is called to verify the data signature
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_orig: original data before signature.
+ * len: length of the signing data
+ * counter: counter used when doing data signing
+ * p_comp: signature to be compared against.
+
+ * Returns true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleVerifySignature(BD_ADDR bd_addr, uint8_t* p_orig, uint16_t len,
+ uint32_t counter, uint8_t* p_comp) {
+ bool verified = false;
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
+ uint8_t p_mac[BTM_CMAC_TLEN_SIZE];
+
+ if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) {
+ BTM_TRACE_ERROR("can not verify signature for unknown device");
+ } else if (counter < p_rec->ble.keys.counter) {
+ BTM_TRACE_ERROR("signature received with out dated sign counter");
+ } else if (p_orig == NULL) {
+ BTM_TRACE_ERROR("No signature to verify");
+ } else {
+ BTM_TRACE_DEBUG("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
+ p_rec->ble.keys.counter);
+
+ if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len,
+ BTM_CMAC_TLEN_SIZE, p_mac)) {
+ if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
+ btm_ble_increment_sign_ctr(bd_addr, false);
+ verified = true;
+ }
+ }
+ }
+ return verified;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetLeSecurityState
+ *
+ * Description This function is called to get security mode 1 flags and
+ * encryption key size for LE peer.
+ *
+ * Returns bool true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+bool BTM_GetLeSecurityState(BD_ADDR bd_addr, uint8_t* p_le_dev_sec_flags,
+ uint8_t* p_le_key_size) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ uint16_t dev_rec_sec_flags;
+
+ *p_le_dev_sec_flags = 0;
+ *p_le_key_size = 0;
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s fails", __func__);
+ return (false);
+ }
+
+ if (p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE) {
+ BTM_TRACE_ERROR("%s-this is not LE device", __func__);
+ return (false);
+ }
+
+ dev_rec_sec_flags = p_dev_rec->sec_flags;
+
+ if (dev_rec_sec_flags & BTM_SEC_LE_ENCRYPTED) {
+ /* link is encrypted with LTK or STK */
+ *p_le_key_size = p_dev_rec->enc_key_size;
+ *p_le_dev_sec_flags |= BTM_SEC_LE_LINK_ENCRYPTED;
+
+ *p_le_dev_sec_flags |=
+ (dev_rec_sec_flags & BTM_SEC_LE_AUTHENTICATED)
+ ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */
+ : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */
+ } else if (p_dev_rec->ble.key_type & BTM_LE_KEY_PENC) {
+ /* link is unencrypted, still LTK is available */
+ *p_le_key_size = p_dev_rec->ble.keys.key_size;
+
+ *p_le_dev_sec_flags |=
+ (dev_rec_sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+ ? BTM_SEC_LE_LINK_PAIRED_WITH_MITM /* set auth LTK flag */
+ : BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM; /* set unauth LTK flag */
+ }
+
+ BTM_TRACE_DEBUG("%s - le_dev_sec_flags: 0x%02x, le_key_size: %d", __func__,
+ *p_le_dev_sec_flags, *p_le_key_size);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecurityProcedureIsRunning
+ *
+ * Description This function indicates if LE security procedure is
+ * currently running with the peer.
+ *
+ * Returns bool true if security procedure is running, false
+ * otherwise.
+ *
+ ******************************************************************************/
+bool BTM_BleSecurityProcedureIsRunning(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("%s device with BDA: %08x%04x is not found", __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) +
+ (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return false;
+ }
+
+ return (p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetSupportedKeySize
+ *
+ * Description This function gets the maximum encryption key size in bytes
+ * the local device can suport.
+ * record.
+ *
+ * Returns the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+extern uint8_t BTM_BleGetSupportedKeySize(BD_ADDR bd_addr) {
+#if (L2CAP_LE_COC_INCLUDED == TRUE)
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ tBTM_LE_IO_REQ dev_io_cfg;
+ uint8_t callback_rc;
+
+ if (!p_dev_rec) {
+ BTM_TRACE_ERROR("%s device with BDA: %08x%04x is not found", __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) +
+ (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return 0;
+ }
+
+ if (btm_cb.api.p_le_callback == NULL) {
+ BTM_TRACE_ERROR("%s can't access supported key size", __func__);
+ return 0;
+ }
+
+ callback_rc = (*btm_cb.api.p_le_callback)(
+ BTM_LE_IO_REQ_EVT, p_dev_rec->bd_addr, (tBTM_LE_EVT_DATA*)&dev_io_cfg);
+
+ if (callback_rc != BTM_SUCCESS) {
+ BTM_TRACE_ERROR("%s can't access supported key size", __func__);
+ return 0;
+ }
+
+ BTM_TRACE_DEBUG("%s device supports key size = %d", __func__,
+ dev_io_cfg.max_key_size);
+ return (dev_io_cfg.max_key_size);
+#else
+ return 0;
+#endif
+}
+
+/*******************************************************************************
+ * Utility functions for LE device IR/ER generation
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_notify_new_key
+ *
+ * Description This function is to notify application new keys have been
+ * generated.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_notify_new_key(uint8_t key_type) {
+ tBTM_BLE_LOCAL_KEYS* p_locak_keys = NULL;
+
+ BTM_TRACE_DEBUG("btm_notify_new_key key_type=%d", key_type);
+
+ if (btm_cb.api.p_le_key_callback) {
+ switch (key_type) {
+ case BTM_BLE_KEY_TYPE_ID:
+ BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ID");
+ p_locak_keys = (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.id_keys;
+ break;
+
+ case BTM_BLE_KEY_TYPE_ER:
+ BTM_TRACE_DEBUG("BTM_BLE_KEY_TYPE_ER");
+ p_locak_keys =
+ (tBTM_BLE_LOCAL_KEYS*)&btm_cb.devcb.ble_encryption_key_value;
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknown key type: %d", key_type);
+ break;
+ }
+ if (p_locak_keys != NULL)
+ (*btm_cb.api.p_le_key_callback)(key_type, p_locak_keys);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_process_irk
+ *
+ * Description This function is called when IRK is generated, store it in
+ * local control block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_process_irk(tSMP_ENC* p) {
+ BTM_TRACE_DEBUG("btm_ble_process_irk");
+ if (p && p->opcode == HCI_BLE_ENCRYPT) {
+ memcpy(btm_cb.devcb.id_keys.irk, p->param_buf, BT_OCTET16_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ID);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* if privacy is enabled, new RPA should be calculated */
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
+ }
+#endif
+ } else {
+ BTM_TRACE_ERROR("Generating IRK exception.");
+ }
+
+ /* proceed generate ER */
+ btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand1) {
+ memcpy(&btm_cb.devcb.ble_encryption_key_value[0], rand1, BT_OCTET8_LEN);
+
+ btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand2) {
+ memcpy(&btm_cb.devcb.ble_encryption_key_value[8], rand2, BT_OCTET8_LEN);
+ btm_notify_new_key(BTM_BLE_KEY_TYPE_ER);
+ }));
+
+ }));
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_process_dhk
+ *
+ * Description This function is called when DHK is calculated, store it in
+ * local control block, and proceed to generate ER, a 128-bits
+ * random number.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_process_dhk(tSMP_ENC* p) {
+ uint8_t btm_ble_irk_pt = 0x01;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG("btm_ble_process_dhk");
+
+ if (p && p->opcode == HCI_BLE_ENCRYPT) {
+ memcpy(btm_cb.devcb.id_keys.dhk, p->param_buf, BT_OCTET16_LEN);
+ BTM_TRACE_DEBUG("BLE DHK generated.");
+
+ /* IRK = D1(IR, 1) */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_irk_pt,
+ 1, &output)) {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ } else {
+ btm_ble_process_irk(&output);
+ }
+ } else {
+ /* reset all identity root related key */
+ memset(&btm_cb.devcb.id_keys, 0, sizeof(tBTM_BLE_LOCAL_ID_KEYS));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_reset_id
+ *
+ * Description This function is called to reset LE device identity.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_reset_id(void) {
+ BTM_TRACE_DEBUG("btm_ble_reset_id");
+
+ /* Regenerate Identity Root*/
+ btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
+ BTM_TRACE_DEBUG("btm_ble_process_ir1");
+ memcpy(btm_cb.devcb.id_keys.ir, rand, BT_OCTET8_LEN);
+
+ btsnd_hcic_ble_rand(base::Bind([](BT_OCTET8 rand) {
+ uint8_t btm_ble_dhk_pt = 0x03;
+ tSMP_ENC output;
+
+ BTM_TRACE_DEBUG("btm_ble_process_ir2");
+
+ /* remembering in control block */
+ memcpy(&btm_cb.devcb.id_keys.ir[8], rand, BT_OCTET8_LEN);
+ /* generate DHK= Eir({0x03, 0x00, 0x00 ...}) */
+
+ SMP_Encrypt(btm_cb.devcb.id_keys.ir, BT_OCTET16_LEN, &btm_ble_dhk_pt, 1,
+ &output);
+ btm_ble_process_dhk(&output);
+
+ BTM_TRACE_DEBUG("BLE IR generated.");
+ }));
+ }));
+}
+
+/* This function set a random address to local controller. It also temporarily
+ * disable scans and adv before sending the command to the controller. */
+void btm_ble_set_random_address(BD_ADDR random_bda) {
+ tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+ bool adv_mode = btm_cb.ble_ctr_cb.inq_var.adv_mode;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ if (btm_ble_get_conn_st() == BLE_DIR_CONN) {
+ BTM_TRACE_ERROR("%s: Cannot set random address. Direct conn ongoing",
+ __func__);
+ return;
+ }
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE)
+ btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_DISABLE);
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) btm_ble_stop_scan();
+ btm_ble_suspend_bg_conn();
+
+ memcpy(p_cb->private_addr, random_bda, BD_ADDR_LEN);
+ btsnd_hcic_ble_set_random_addr(p_cb->private_addr);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE)
+ btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_ENABLE);
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) btm_ble_start_scan();
+ btm_ble_resume_bg_conn();
+}
+
+#if BTM_BLE_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+ *
+ * Function btm_ble_set_no_disc_if_pair_fail
+ *
+ * Description This function indicates whether no disconnect of the ACL
+ * should be used if pairing failed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_set_no_disc_if_pair_fail(bool disable_disc) {
+ BTM_TRACE_DEBUG("btm_ble_set_disc_enable_if_pair_fail disable_disc=%d",
+ disable_disc);
+ btm_cb.devcb.no_disc_if_pair_fail = disable_disc;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_test_mac_value
+ *
+ * Description This function set test MAC value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_set_test_mac_value(bool enable, uint8_t* p_test_mac_val) {
+ BTM_TRACE_DEBUG("btm_ble_set_test_mac_value enable=%d", enable);
+ btm_cb.devcb.enable_test_mac_val = enable;
+ memcpy(btm_cb.devcb.test_mac, p_test_mac_val, BT_OCTET8_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_test_local_sign_cntr_value
+ *
+ * Description This function set test local sign counter value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_set_test_local_sign_cntr_value(bool enable,
+ uint32_t test_local_sign_cntr) {
+ BTM_TRACE_DEBUG(
+ "btm_ble_set_test_local_sign_cntr_value enable=%d local_sign_cntr=%d",
+ enable, test_local_sign_cntr);
+ btm_cb.devcb.enable_test_local_sign_cntr = enable;
+ btm_cb.devcb.test_local_sign_cntr = test_local_sign_cntr;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_keep_rfu_in_auth_req
+ *
+ * Description This function indicates if RFU bits have to be kept as is
+ * (by default they have to be set to 0 by the sender).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_set_keep_rfu_in_auth_req(bool keep_rfu) {
+ BTM_TRACE_DEBUG("btm_ble_set_keep_rfu_in_auth_req keep_rfus=%d", keep_rfu);
+ btm_cb.devcb.keep_rfu_in_auth_req = keep_rfu;
+}
+
+#endif /* BTM_BLE_CONFORMANCE_TESTING */
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_addr.cc b/mtkbt/code/bt/stack/btm/btm_ble_addr.cc
new file mode 100755
index 0000000..4025df2
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_addr.cc
@@ -0,0 +1,522 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for BLE address management.
+ *
+ ******************************************************************************/
+
+#include <base/bind.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gap_api.h"
+#include "hcimsgs.h"
+
+#include "btm_ble_int.h"
+#include "smp_api.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function btm_gen_resolve_paddr_cmpl
+ *
+ * Description This is callback functioin when resolvable private address
+ * generation is complete.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_gen_resolve_paddr_cmpl(tSMP_ENC* p) {
+ tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BTM_TRACE_EVENT("btm_gen_resolve_paddr_cmpl");
+
+ if (p) {
+ /* set hash to be LSB of rpAddress */
+ p_cb->private_addr[5] = p->param_buf[0];
+ p_cb->private_addr[4] = p->param_buf[1];
+ p_cb->private_addr[3] = p->param_buf[2];
+ /* set it to controller */
+ btm_ble_set_random_address(p_cb->private_addr);
+
+ p_cb->own_addr_type = BLE_ADDR_RANDOM;
+
+ /* start a periodical timer to refresh random addr */
+ period_ms_t interval_ms = BTM_BLE_PRIVATE_ADDR_INT_MS;
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ interval_ms = btm_cb.ble_ctr_cb.rpa_tout * 1000;
+#endif
+ alarm_set_on_queue(p_cb->refresh_raddr_timer, interval_ms,
+ btm_ble_refresh_raddr_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ } else {
+ /* random address set failure */
+ BTM_TRACE_DEBUG("set random address failed");
+ }
+}
+/*******************************************************************************
+ *
+ * Function btm_gen_resolve_paddr_low
+ *
+ * Description This function is called when random address has generate the
+ * random number base for low 3 byte bd address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_gen_resolve_paddr_low(BT_OCTET8 rand) {
+ tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tSMP_ENC output;
+
+ BTM_TRACE_EVENT("btm_gen_resolve_paddr_low");
+ rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ rand[2] |= BLE_RESOLVE_ADDR_MSB;
+
+ p_cb->private_addr[2] = rand[0];
+ p_cb->private_addr[1] = rand[1];
+ p_cb->private_addr[0] = rand[2];
+
+ /* encrypt with ur IRK */
+ if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, rand, 3,
+ &output)) {
+ btm_gen_resolve_paddr_cmpl(NULL);
+ } else {
+ btm_gen_resolve_paddr_cmpl(&output);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btm_gen_resolvable_private_addr
+ *
+ * Description This function generate a resolvable private address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb) {
+ BTM_TRACE_EVENT("%s", __func__);
+ /* generate 3B rand as BD LSB, SRK with it, get BD MSB */
+ btsnd_hcic_ble_rand(std::move(cb));
+}
+/*******************************************************************************
+ *
+ * Function btm_gen_non_resolve_paddr_cmpl
+ *
+ * Description This is the callback function when non-resolvable private
+ * function is generated and write to controller.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_gen_non_resolve_paddr_cmpl(BT_OCTET8 rand) {
+ tBTM_LE_RANDOM_CB* p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_ADDR_CBACK* p_cback = p_cb->p_generate_cback;
+ void* p_data = p_cb->p;
+ uint8_t* pp;
+ BD_ADDR static_random;
+
+ BTM_TRACE_EVENT("btm_gen_non_resolve_paddr_cmpl");
+
+ p_cb->p_generate_cback = NULL;
+ pp = rand;
+ STREAM_TO_BDADDR(static_random, pp);
+ /* mask off the 2 MSB */
+ static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK;
+
+ /* report complete */
+ if (p_cback) (*p_cback)(static_random, p_data);
+}
+/*******************************************************************************
+ *
+ * Function btm_gen_non_resolvable_private_addr
+ *
+ * Description This function generate a non-resolvable private address.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_gen_non_resolvable_private_addr(tBTM_BLE_ADDR_CBACK* p_cback,
+ void* p) {
+ tBTM_LE_RANDOM_CB* p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+
+ BTM_TRACE_EVENT("btm_gen_non_resolvable_private_addr");
+
+ if (p_mgnt_cb->p_generate_cback != NULL) return;
+
+ p_mgnt_cb->p_generate_cback = p_cback;
+ p_mgnt_cb->p = p;
+ btsnd_hcic_ble_rand(base::Bind(&btm_gen_non_resolve_paddr_cmpl));
+}
+
+/*******************************************************************************
+ * Utility functions for Random address resolving
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_ble_proc_resolve_x
+ *
+ * Description This function compares the X with random address 3 MSO bytes
+ * to find a match.
+ *
+ * Returns true on match, false otherwise
+ *
+ ******************************************************************************/
+static bool btm_ble_proc_resolve_x(const tSMP_ENC& encrypt_output,
+ const bt_bdaddr_t& random_bda) {
+ BTM_TRACE_EVENT("btm_ble_proc_resolve_x");
+
+ /* compare the hash with 3 LSB of bd address */
+ uint8_t comp[3];
+ comp[0] = random_bda.address[5];
+ comp[1] = random_bda.address[4];
+ comp[2] = random_bda.address[3];
+
+ if (!memcmp(encrypt_output.param_buf, comp, 3)) {
+ BTM_TRACE_EVENT("match is found");
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_init_pseudo_addr
+ *
+ * Description This function is used to initialize pseudo address.
+ * If pseudo address is not available, use dummy address
+ *
+ * Returns true is updated; false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec,
+ BD_ADDR new_pseudo_addr) {
+ BD_ADDR dummy_bda = {0};
+
+ if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0) {
+ memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN);
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_addr_resolvable
+ *
+ * Description This function checks if a RPA is resolvable by the device
+ * key.
+ *
+ * Returns true is resolvable; false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC* p_dev_rec) {
+ bool rt = false;
+
+ if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) return rt;
+
+ uint8_t rand[3];
+ tSMP_ENC output;
+ if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
+ BTM_TRACE_DEBUG("%s try to resolve", __func__);
+ /* use the 3 MSB of bd address as prand */
+ rand[0] = rpa[2];
+ rand[1] = rpa[1];
+ rand[2] = rpa[0];
+
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
+
+ rand[0] = rpa[5];
+ rand[1] = rpa[4];
+ rand[2] = rpa[3];
+
+ if (!memcmp(output.param_buf, &rand[0], 3)) {
+ btm_ble_init_pseudo_addr(p_dev_rec, rpa);
+ rt = true;
+ }
+ }
+ return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_match_random_bda
+ *
+ * Description This function match the random address to the appointed
+ * device record, starting from calculating IRK. If the record
+ * index exceeds the maximum record number, matching failed and
+ * send a callback.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+static bool btm_ble_match_random_bda(void* data, void* context) {
+ bt_bdaddr_t random_bda;
+ bdcpy(random_bda.address, (uint8_t *)context);
+
+ /* use the 3 MSB of bd address as prand */
+
+ uint8_t rand[3];
+ rand[0] = random_bda.address[2];
+ rand[1] = random_bda.address[1];
+ rand[2] = random_bda.address[0];
+
+ BTM_TRACE_EVENT("%s next iteration", __func__);
+
+ tSMP_ENC output;
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+
+ BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
+ p_dev_rec->device_type);
+
+ if (!(p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) ||
+ !(p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
+ return true;
+
+ /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+ SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN, &rand[0], 3, &output);
+ // if it was match, finish iteration, otherwise continue
+ return !btm_ble_proc_resolve_x(output, random_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolve_random_addr
+ *
+ * Description This function is called to resolve a random address.
+ *
+ * Returns pointer to the security record of the device whom a random
+ * address is matched to.
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(BD_ADDR random_bda) {
+ BTM_TRACE_EVENT("%s", __func__);
+
+ /* start to resolve random address */
+ /* check for next security record */
+
+ list_node_t* n =
+ list_foreach(btm_cb.sec_dev_rec, btm_ble_match_random_bda, random_bda);
+ tBTM_SEC_DEV_REC* p_dev_rec = nullptr;
+ if (n != nullptr) p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
+
+ BTM_TRACE_EVENT("%s: %sresolved", __func__,
+ (p_dev_rec == nullptr ? "not " : ""));
+ return p_dev_rec;
+}
+
+/*******************************************************************************
+ * address mapping between pseudo address and real connection address
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_find_dev_by_identity_addr
+ *
+ * Description find the security record whose LE static address is matching
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_find_dev_by_identity_addr(BD_ADDR bd_addr,
+ uint8_t addr_type) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ list_node_t* end = list_end(btm_cb.sec_dev_rec);
+ for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end;
+ node = list_next(node)) {
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+ if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) == 0) {
+ if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
+ (addr_type & (~BLE_ADDR_TYPE_ID_BIT)))
+ BTM_TRACE_WARNING(
+ "%s find pseudo->random match with diff addr type: %d vs %d",
+ __func__, p_dev_rec->ble.static_addr_type, addr_type);
+
+ /* found the match */
+ return p_dev_rec;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_identity_addr_to_random_pseudo
+ *
+ * Description This function map a static BD address to a pseudo random
+ * address in security database.
+ *
+ ******************************************************************************/
+bool btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, uint8_t* p_addr_type,
+ bool refresh) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ btm_find_dev_by_identity_addr(bd_addr, *p_addr_type);
+
+ BTM_TRACE_EVENT("%s", __func__);
+ /* evt reported on static address, map static address to random pseudo */
+ if (p_dev_rec != NULL) {
+ /* if RPA offloading is supported, or 4.2 controller, do RPA refresh */
+ if (refresh &&
+ controller_get_interface()->get_ble_resolving_list_max_size() != 0)
+ btm_ble_read_resolving_list_entry(p_dev_rec);
+
+ /* assign the original address to be the current report address */
+ if (!btm_ble_init_pseudo_addr(p_dev_rec, bd_addr))
+ memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+
+ *p_addr_type = p_dev_rec->ble.ble_addr_type;
+ return true;
+ }
+#endif
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_random_pseudo_to_identity_addr
+ *
+ * Description This function map a random pseudo address to a public
+ * address. random_pseudo is input and output parameter
+ *
+ ******************************************************************************/
+bool btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo,
+ uint8_t* p_static_addr_type) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(random_pseudo);
+
+ if (p_dev_rec != NULL) {
+ if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
+ *p_static_addr_type = p_dev_rec->ble.static_addr_type;
+ memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ if (controller_get_interface()->supports_ble_privacy())
+ *p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_refresh_peer_resolvable_private_addr
+ *
+ * Description This function refresh the currently used resolvable remote
+ * private address into security database and set active
+ * connection address.
+ *
+ ******************************************************************************/
+void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda,
+ BD_ADDR rpa,
+ uint8_t rra_type) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ uint8_t rra_dummy = false;
+ BD_ADDR dummy_bda = {0};
+
+ if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0) rra_dummy = true;
+
+ /* update security record here, in adv event or connection complete process */
+ tBTM_SEC_DEV_REC* p_sec_rec = btm_find_dev(pseudo_bda);
+ if (p_sec_rec != NULL) {
+ memcpy(p_sec_rec->ble.cur_rand_addr, rpa, BD_ADDR_LEN);
+
+ /* unknown, if dummy address, set to static */
+ if (rra_type == BTM_BLE_ADDR_PSEUDO)
+ p_sec_rec->ble.active_addr_type =
+ rra_dummy ? BTM_BLE_ADDR_STATIC : BTM_BLE_ADDR_RRA;
+ else
+ p_sec_rec->ble.active_addr_type = rra_type;
+ } else {
+ BTM_TRACE_ERROR("No matching known device in record");
+ return;
+ }
+
+ BTM_TRACE_DEBUG("%s: active_addr_type: %d ", __func__,
+ p_sec_rec->ble.active_addr_type);
+
+ /* connection refresh remote address */
+ tACL_CONN* p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
+ if (p_acl == NULL)
+ p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+
+ if (p_acl != NULL) {
+ if (rra_type == BTM_BLE_ADDR_PSEUDO) {
+ /* use static address, resolvable_private_addr is empty */
+ if (rra_dummy) {
+ p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type;
+ memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr,
+ BD_ADDR_LEN);
+ } else {
+ p_acl->active_remote_addr_type = BLE_ADDR_RANDOM;
+ memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+ }
+ } else {
+ p_acl->active_remote_addr_type = rra_type;
+ memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
+ }
+
+ BTM_TRACE_DEBUG("p_acl->active_remote_addr_type: %d ",
+ p_acl->active_remote_addr_type);
+ BTM_TRACE_DEBUG("%s conn_addr: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ p_acl->active_remote_addr[0], p_acl->active_remote_addr[1],
+ p_acl->active_remote_addr[2], p_acl->active_remote_addr[3],
+ p_acl->active_remote_addr[4], p_acl->active_remote_addr[5]);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_refresh_local_resolvable_private_addr
+ *
+ * Description This function refresh the currently used resolvable private
+ * address for the active link to the remote device
+ *
+ ******************************************************************************/
+void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr,
+ BD_ADDR local_rpa) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ tACL_CONN* p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
+ BD_ADDR dummy_bda = {0};
+
+ if (p != NULL) {
+ if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ p->conn_addr_type = BLE_ADDR_RANDOM;
+ if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN))
+ memcpy(p->conn_addr, local_rpa, BD_ADDR_LEN);
+ else
+ memcpy(p->conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr,
+ BD_ADDR_LEN);
+ } else {
+ p->conn_addr_type = BLE_ADDR_PUBLIC;
+ memcpy(p->conn_addr, &controller_get_interface()->get_address()->address,
+ BD_ADDR_LEN);
+ }
+ }
+#endif
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_adv_filter.cc b/mtkbt/code/bt/stack/btm/btm_ble_adv_filter.cc
new file mode 100755
index 0000000..5f264d0
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_adv_filter.cc
@@ -0,0 +1,849 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include <base/bind.h>
+#include <string.h>
+#include <algorithm>
+#include <vector>
+
+#include "bt_target.h"
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3
+#define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13
+#define BTM_BLE_ADV_FILT_TRACK_NUM 2
+
+#define BTM_BLE_PF_SELECT_NONE 0
+
+/* BLE meta vsc header: 1 bytes of sub_code, 1 byte of PCF action */
+#define BTM_BLE_META_HDR_LENGTH 3
+#define BTM_BLE_PF_FEAT_SEL_LEN 18
+#define BTM_BLE_PCF_ENABLE_LEN 2
+
+#define BTM_BLE_META_ADDR_LEN 7
+#define BTM_BLE_META_UUID_LEN 40
+
+#define BTM_BLE_PF_BIT_TO_MASK(x) (uint16_t)(1 << (x))
+
+tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb;
+tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+static const BD_ADDR na_bda = {0};
+
+static uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+ uint8_t cond_type,
+ tBLE_BD_ADDR* p_bd_addr,
+ uint8_t num_available);
+
+#define BTM_BLE_SET_SCAN_PF_OPCODE(x, y) (((x) << 4) | (y))
+#define BTM_BLE_GET_SCAN_PF_SUBCODE(x) ((x) >> 4)
+#define BTM_BLE_GET_SCAN_PF_ACTION(x) ((x)&0x0f)
+#define BTM_BLE_INVALID_COUNTER 0xff
+
+/* length of each multi adv sub command */
+#define BTM_BLE_ADV_FILTER_ENB_LEN 3
+
+/* length of each batch scan command */
+#define BTM_BLE_ADV_FILTER_CLEAR_LEN 3
+#define BTM_BLE_ADV_FILTER_LEN 2
+
+#define BTM_BLE_ADV_FILT_CB_EVT_MASK 0xF0
+#define BTM_BLE_ADV_FILT_SUBCODE_MASK 0x0F
+
+/*******************************************************************************
+ *
+ * Function btm_ble_obtain_vsc_details
+ *
+ * Description This function obtains the VSC details
+ *
+ * Parameters
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_obtain_vsc_details() {
+ tBTM_STATUS st = BTM_SUCCESS;
+
+#if (BLE_VND_INCLUDED == TRUE)
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+ if (cmn_ble_vsc_cb.filter_support && 0 == cmn_ble_vsc_cb.max_filter) {
+ st = BTM_MODE_UNSUPPORTED;
+ return st;
+ }
+#else
+ cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER;
+#endif
+ return st;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_condtype_to_ocf
+ *
+ * Description Convert cond_type to OCF
+ *
+ * Returns Returns ocf value
+ *
+ ******************************************************************************/
+uint8_t btm_ble_condtype_to_ocf(uint8_t cond_type) {
+ uint8_t ocf = 0;
+
+ switch (cond_type) {
+ case BTM_BLE_PF_ADDR_FILTER:
+ ocf = BTM_BLE_META_PF_ADDR;
+ break;
+ case BTM_BLE_PF_SRVC_UUID:
+ ocf = BTM_BLE_META_PF_UUID;
+ break;
+ case BTM_BLE_PF_SRVC_SOL_UUID:
+ ocf = BTM_BLE_META_PF_SOL_UUID;
+ break;
+ case BTM_BLE_PF_LOCAL_NAME:
+ ocf = BTM_BLE_META_PF_LOCAL_NAME;
+ break;
+ case BTM_BLE_PF_MANU_DATA:
+ ocf = BTM_BLE_META_PF_MANU_DATA;
+ break;
+ case BTM_BLE_PF_SRVC_DATA_PATTERN:
+ ocf = BTM_BLE_META_PF_SRVC_DATA;
+ break;
+ case BTM_BLE_PF_TYPE_ALL:
+ ocf = BTM_BLE_META_PF_ALL;
+ break;
+ default:
+ ocf = BTM_BLE_PF_TYPE_MAX;
+ break;
+ }
+ return ocf;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_ocf_to_condtype
+ *
+ * Description Convert OCF to cond type
+ *
+ * Returns Returns condtype value
+ *
+ ******************************************************************************/
+uint8_t btm_ble_ocf_to_condtype(uint8_t ocf) {
+ uint8_t cond_type = 0;
+
+ switch (ocf) {
+ case BTM_BLE_META_PF_FEAT_SEL:
+ cond_type = BTM_BLE_META_PF_FEAT_SEL;
+ break;
+ case BTM_BLE_META_PF_ADDR:
+ cond_type = BTM_BLE_PF_ADDR_FILTER;
+ break;
+ case BTM_BLE_META_PF_UUID:
+ cond_type = BTM_BLE_PF_SRVC_UUID;
+ break;
+ case BTM_BLE_META_PF_SOL_UUID:
+ cond_type = BTM_BLE_PF_SRVC_SOL_UUID;
+ break;
+ case BTM_BLE_META_PF_LOCAL_NAME:
+ cond_type = BTM_BLE_PF_LOCAL_NAME;
+ break;
+ case BTM_BLE_META_PF_MANU_DATA:
+ cond_type = BTM_BLE_PF_MANU_DATA;
+ break;
+ case BTM_BLE_META_PF_SRVC_DATA:
+ cond_type = BTM_BLE_PF_SRVC_DATA_PATTERN;
+ break;
+ case BTM_BLE_META_PF_ALL:
+ cond_type = BTM_BLE_PF_TYPE_ALL;
+ break;
+ default:
+ cond_type = BTM_BLE_PF_TYPE_MAX;
+ break;
+ }
+ return cond_type;
+}
+
+void btm_flt_update_cb(uint8_t expected_ocf, tBTM_BLE_PF_CFG_CBACK cb,
+ uint8_t* p, uint16_t evt_len) {
+ if (evt_len != 4) {
+ BTM_TRACE_ERROR("%s: bad length: %d", __func__, evt_len);
+ return;
+ }
+
+ uint8_t status, op_subcode, action, num_avail;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(op_subcode, p);
+ STREAM_TO_UINT8(action, p);
+ STREAM_TO_UINT8(num_avail, p);
+
+ if (expected_ocf != op_subcode) {
+ BTM_TRACE_ERROR("%s: Incorrect opcode: 0x%02x, expected: 0x%02x", __func__,
+ expected_ocf, op_subcode);
+ return;
+ }
+
+ if (op_subcode == BTM_BLE_META_PF_FEAT_SEL) {
+ cb.Run(num_avail, action, status);
+ return;
+ }
+
+ uint8_t cond_type = btm_ble_ocf_to_condtype(expected_ocf);
+ BTM_TRACE_DEBUG("%s: Recd: %d, %d, %d, %d, %d", __func__, op_subcode,
+ expected_ocf, action, status, num_avail);
+ if (HCI_SUCCESS == status) {
+ if (memcmp(&btm_ble_adv_filt_cb.cur_filter_target.bda, &na_bda,
+ BD_ADDR_LEN) == 0)
+ btm_ble_cs_update_pf_counter(action, cond_type, NULL, num_avail);
+ else
+ btm_ble_cs_update_pf_counter(
+ action, cond_type, &btm_ble_adv_filt_cb.cur_filter_target, num_avail);
+ }
+
+ /* send ADV PF operation complete */
+ btm_ble_adv_filt_cb.op_type = 0;
+
+ cb.Run(num_avail, action, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_find_addr_filter_counter
+ *
+ * Description find the per bd address ADV payload filter counter by
+ * BD_ADDR.
+ *
+ * Returns pointer to the counter if found; NULL otherwise.
+ *
+ ******************************************************************************/
+tBTM_BLE_PF_COUNT* btm_ble_find_addr_filter_counter(tBLE_BD_ADDR* p_le_bda) {
+ uint8_t i;
+ tBTM_BLE_PF_COUNT* p_addr_filter =
+ &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+ if (p_le_bda == NULL) return &btm_ble_adv_filt_cb.p_addr_filter_count[0];
+
+ for (i = 0; i < cmn_ble_vsc_cb.max_filter; i++, p_addr_filter++) {
+ if (p_addr_filter->in_use &&
+ memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) {
+ return p_addr_filter;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_alloc_addr_filter_counter
+ *
+ * Description allocate the per device adv payload filter counter.
+ *
+ * Returns pointer to the counter if allocation succeed; NULL
+ * otherwise.
+ *
+ ******************************************************************************/
+tBTM_BLE_PF_COUNT* btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr) {
+ uint8_t i;
+ tBTM_BLE_PF_COUNT* p_addr_filter =
+ &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+
+ for (i = 0; i < cmn_ble_vsc_cb.max_filter; i++, p_addr_filter++) {
+ if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) {
+ memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_addr_filter->in_use = true;
+ return p_addr_filter;
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_dealloc_addr_filter_counter
+ *
+ * Description de-allocate the per device adv payload filter counter.
+ *
+ * Returns true if deallocation succeed; false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR* p_bd_addr,
+ uint8_t filter_type) {
+ uint8_t i;
+ tBTM_BLE_PF_COUNT* p_addr_filter =
+ &btm_ble_adv_filt_cb.p_addr_filter_count[1];
+ bool found = false;
+
+ if (BTM_BLE_PF_TYPE_ALL == filter_type && NULL == p_bd_addr)
+ memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0,
+ sizeof(tBTM_BLE_PF_COUNT));
+
+ for (i = 0; i < cmn_ble_vsc_cb.max_filter; i++, p_addr_filter++) {
+ if ((p_addr_filter->in_use) &&
+ (NULL == p_bd_addr ||
+ (NULL != p_bd_addr &&
+ memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) {
+ found = true;
+ memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT));
+
+ if (NULL != p_bd_addr) break;
+ }
+ }
+ return found;
+}
+
+/**
+ * This function update(add,delete or clear) the adv local name filtering
+ * condition.
+ */
+void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> name, tBTM_BLE_PF_CFG_CBACK cb) {
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+
+ uint8_t len_max = len + BTM_BLE_PF_STR_LEN_MAX;
+ uint8_t param[len_max];
+ memset(param, 0, len_max);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME);
+ UINT8_TO_STREAM(p, action);
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (action != BTM_BLE_SCAN_COND_CLEAR) {
+ int size = std::min(name.size(), (size_t)BTM_BLE_PF_STR_LEN_MAX);
+ ARRAY_TO_STREAM(p, name.data(), size);
+ len += size;
+ }
+
+ /* send local name filter */
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_LOCAL_NAME, cb));
+
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/**
+ * this function update(add/remove) service data change filter.
+ */
+void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index) {
+ uint8_t num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1;
+
+ btm_ble_cs_update_pf_counter(action, BTM_BLE_PF_SRVC_DATA, nullptr,
+ num_avail);
+}
+
+/**
+ * This function update(add,delete or clear) the adv manufacturer data filtering
+ * condition.
+ */
+void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index, uint16_t company_id,
+ uint16_t company_id_mask, std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ int len_max = len + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX;
+
+ uint8_t param[len_max];
+ memset(param, 0, len_max);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA);
+ UINT8_TO_STREAM(p, action);
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (action != BTM_BLE_SCAN_COND_CLEAR) {
+ uint8_t size = std::min(data.size(), (size_t)(BTM_BLE_PF_STR_LEN_MAX - 2));
+
+ UINT16_TO_STREAM(p, company_id);
+ if (size > 0 && data_mask.size() != 0) {
+ ARRAY_TO_STREAM(p, data.data(), size);
+ len += size + 2;
+ } else
+ len += 2;
+
+ if (company_id_mask != 0) {
+ UINT16_TO_STREAM(p, company_id_mask);
+ } else {
+ UINT16_TO_STREAM(p, (uint16_t)0xFFFF);
+ }
+ len += 2;
+
+ if (size > 0 && data_mask.size() != 0) {
+ ARRAY_TO_STREAM(p, data_mask.data(), size);
+ len += (size);
+ }
+
+ BTM_TRACE_DEBUG("Manuf data length: %d", len);
+ }
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_MANU_DATA, cb));
+
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/**
+ * This function update(add,delete or clear) the service data filtering
+ * condition.
+ **/
+void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ int len_max = len + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX;
+
+ uint8_t param[len_max];
+ memset(param, 0, len_max);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA);
+ UINT8_TO_STREAM(p, action);
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (action != BTM_BLE_SCAN_COND_CLEAR) {
+ uint8_t size = std::min(data.size(), (size_t)(BTM_BLE_PF_STR_LEN_MAX - 2));
+
+ if (size > 0) {
+ ARRAY_TO_STREAM(p, data.data(), size);
+ len += size;
+ ARRAY_TO_STREAM(p, data_mask.data(), size);
+ len += size;
+ }
+ }
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_SRVC_DATA, cb));
+
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_cs_update_pf_counter
+ *
+ * Description this function is to update the adv data payload filter
+ * counter
+ *
+ * Returns current number of the counter; BTM_BLE_INVALID_COUNTER if
+ * counter update failed.
+ *
+ ******************************************************************************/
+uint8_t btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action,
+ uint8_t cond_type, tBLE_BD_ADDR* p_bd_addr,
+ uint8_t num_available) {
+ tBTM_BLE_PF_COUNT* p_addr_filter = NULL;
+ uint8_t* p_counter = NULL;
+
+ btm_ble_obtain_vsc_details();
+
+ if (cond_type > BTM_BLE_PF_TYPE_ALL) {
+ BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type);
+ return BTM_BLE_INVALID_COUNTER;
+ }
+
+ /* for these three types of filter, always generic */
+ if (BTM_BLE_PF_ADDR_FILTER == cond_type ||
+ BTM_BLE_PF_MANU_DATA == cond_type || BTM_BLE_PF_LOCAL_NAME == cond_type ||
+ BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type)
+ p_bd_addr = NULL;
+
+ if ((p_addr_filter = btm_ble_find_addr_filter_counter(p_bd_addr)) == NULL &&
+ BTM_BLE_SCAN_COND_ADD == action) {
+ p_addr_filter = btm_ble_alloc_addr_filter_counter(p_bd_addr->bda);
+ }
+
+ if (NULL != p_addr_filter) {
+ /* all filter just cleared */
+ if ((BTM_BLE_PF_TYPE_ALL == cond_type &&
+ BTM_BLE_SCAN_COND_CLEAR == action) ||
+ /* or bd address filter been deleted */
+ (BTM_BLE_PF_ADDR_FILTER == cond_type &&
+ (BTM_BLE_SCAN_COND_DELETE == action ||
+ BTM_BLE_SCAN_COND_CLEAR == action))) {
+ btm_ble_dealloc_addr_filter_counter(p_bd_addr, cond_type);
+ }
+ /* if not feature selection, update new addition/reduction of the filter
+ counter */
+ else if (cond_type != BTM_BLE_PF_TYPE_ALL) {
+ p_counter = p_addr_filter->pf_counter;
+ if (num_available > 0) p_counter[cond_type] += 1;
+
+ BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d",
+ p_counter[cond_type], cmn_ble_vsc_cb.max_filter,
+ num_available);
+ return p_counter[cond_type];
+ }
+ } else {
+ BTM_TRACE_ERROR("no matching filter counter found");
+ }
+ /* no matching filter located and updated */
+ return BTM_BLE_INVALID_COUNTER;
+}
+
+/**
+ * This function updates the address filter of adv.
+ */
+void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index, tBLE_BD_ADDR addr,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ const uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN;
+
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR);
+ UINT8_TO_STREAM(p, action);
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (action != BTM_BLE_SCAN_COND_CLEAR) {
+ BDADDR_TO_STREAM(p, addr.bda);
+ UINT8_TO_STREAM(p, addr.type);
+ }
+
+ /* send address filter */
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_ADDR, cb));
+
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/**
+ * This function updates(adds, deletes or clears) the service UUID filter.
+ */
+void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_TYPE filter_type, tBT_UUID uuid,
+ tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+ tBTM_BLE_PF_COND_MASK* p_uuid_mask,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ uint8_t evt_type;
+
+ if (BTM_BLE_PF_SRVC_UUID == filter_type) {
+ evt_type = BTM_BLE_META_PF_UUID;
+ } else {
+ evt_type = BTM_BLE_META_PF_SOL_UUID;
+ }
+
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH;
+ uint8_t max_len = len + BTM_BLE_META_UUID_LEN;
+ uint8_t param[max_len];
+ memset(param, 0, max_len);
+ uint8_t* p = param;
+
+ UINT8_TO_STREAM(p, evt_type);
+ UINT8_TO_STREAM(p, action);
+ UINT8_TO_STREAM(p, filt_index);
+
+ if (action != BTM_BLE_SCAN_COND_CLEAR) {
+ if (uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, uuid.uu.uuid16);
+ len += LEN_UUID_16;
+ } else if (uuid.len == LEN_UUID_32) {
+ UINT32_TO_STREAM(p, uuid.uu.uuid32);
+ len += LEN_UUID_32;
+ } else if (uuid.len == LEN_UUID_128) {
+ ARRAY_TO_STREAM(p, uuid.uu.uuid128, LEN_UUID_128);
+ len += LEN_UUID_128;
+ } else {
+ BTM_TRACE_ERROR("illegal UUID length: %d", uuid.len);
+ cb.Run(0, BTM_BLE_PF_CONFIG, 1 /*BTA_FAILURE*/);
+ return;
+ }
+
+ if (p_uuid_mask) {
+ if (uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, p_uuid_mask->uuid16_mask);
+ len += LEN_UUID_16;
+ } else if (uuid.len == LEN_UUID_32) {
+ UINT32_TO_STREAM(p, p_uuid_mask->uuid32_mask);
+ len += LEN_UUID_32;
+ } else if (uuid.len == LEN_UUID_128) {
+ ARRAY_TO_STREAM(p, p_uuid_mask->uuid128_mask, LEN_UUID_128);
+ len += LEN_UUID_128;
+ }
+ } else {
+ memset(p, 0xff, uuid.len);
+ len += uuid.len;
+ }
+ }
+
+ /* send UUID filter update */
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, evt_type, cb));
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/**
+ * all adv payload filter by de-selecting all the adv pf feature bits
+ */
+void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ /* clear the general filter entry */
+ {
+ tBTM_BLE_PF_CFG_CBACK fDoNothing;
+
+ /* clear manufactuer data filter */
+ BTM_LE_PF_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, 0, 0, {}, {},
+ fDoNothing);
+
+ /* clear local name filter */
+ BTM_LE_PF_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, fDoNothing);
+
+ /* update the counter for service data */
+ BTM_LE_PF_srvc_data(BTM_BLE_SCAN_COND_CLEAR, filt_index);
+
+ /* clear UUID filter */
+ BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+ BTM_BLE_PF_SRVC_UUID, {}, 0, nullptr, fDoNothing);
+
+ BTM_LE_PF_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index,
+ BTM_BLE_PF_SRVC_SOL_UUID, {}, 0, nullptr, fDoNothing);
+
+ /* clear service data filter */
+ BTM_LE_PF_srvc_data_pattern(BTM_BLE_SCAN_COND_CLEAR, filt_index, {}, {},
+ fDoNothing);
+ }
+
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN;
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* p = param;
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+ UINT8_TO_STREAM(p, filt_index);
+ /* set PCF selection */
+ UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE);
+ /* set logic condition as OR as default */
+ UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR);
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
+
+ memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleAdvFilterParamSetup
+ *
+ * Description This function is called to setup the adv data payload filter
+ * condition.
+ *
+ * Parameters action - Type of action to be performed
+ * filt_index - Filter index
+ * p_filt_params - Filter parameters
+ * cb - Callback
+ *
+ ******************************************************************************/
+void BTM_BleAdvFilterParamSetup(
+ int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+ tBTM_BLE_PF_PARAM_CB cb) {
+ tBTM_BLE_PF_COUNT* p_bda_filter = NULL;
+ uint8_t len = BTM_BLE_ADV_FILT_META_HDR_LENGTH +
+ BTM_BLE_ADV_FILT_FEAT_SELN_LEN + BTM_BLE_ADV_FILT_TRACK_NUM;
+ uint8_t param[len], *p;
+
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ return;
+ }
+
+ p = param;
+ memset(param, 0, len);
+ BTM_TRACE_EVENT("%s", __func__);
+
+ if (BTM_BLE_SCAN_COND_ADD == action) {
+ p_bda_filter = btm_ble_find_addr_filter_counter(nullptr);
+ if (NULL == p_bda_filter) {
+ BTM_TRACE_ERROR("BD Address not found!");
+ cb.Run(0, BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ return;
+ }
+
+ BTM_TRACE_DEBUG("%s : Feat mask:%d", __func__, p_filt_params->feat_seln);
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD);
+
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ /* set PCF selection */
+ UINT16_TO_STREAM(p, p_filt_params->feat_seln);
+ /* set logic type */
+ UINT16_TO_STREAM(p, p_filt_params->list_logic_type);
+ /* set logic condition */
+ UINT8_TO_STREAM(p, p_filt_params->filt_logic_type);
+ /* set RSSI high threshold */
+ UINT8_TO_STREAM(p, p_filt_params->rssi_high_thres);
+ /* set delivery mode */
+ UINT8_TO_STREAM(p, p_filt_params->dely_mode);
+
+ if (0x01 == p_filt_params->dely_mode) {
+ /* set onfound timeout */
+ UINT16_TO_STREAM(p, p_filt_params->found_timeout);
+ /* set onfound timeout count*/
+ UINT8_TO_STREAM(p, p_filt_params->found_timeout_cnt);
+ /* set RSSI low threshold */
+ UINT8_TO_STREAM(p, p_filt_params->rssi_low_thres);
+ /* set onlost timeout */
+ UINT16_TO_STREAM(p, p_filt_params->lost_timeout);
+ /* set num_of_track_entries for firmware greater than L-release version */
+ if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION)
+ UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries);
+ }
+
+ if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION)
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN;
+ else
+ len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN +
+ BTM_BLE_ADV_FILT_TRACK_NUM;
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
+ } else if (BTM_BLE_SCAN_COND_DELETE == action) {
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_DELETE);
+ /* Filter index */
+ UINT8_TO_STREAM(p, filt_index);
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH),
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
+ } else if (BTM_BLE_SCAN_COND_CLEAR == action) {
+ /* Deallocate all filters here */
+ btm_ble_dealloc_addr_filter_counter(NULL, BTM_BLE_PF_TYPE_ALL);
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL);
+ UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
+
+ btu_hcif_send_cmd_with_cb(
+ FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH - 1),
+ base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
+ }
+}
+
+void enable_cmpl_cback(tBTM_BLE_PF_STATUS_CBACK p_stat_cback, uint8_t* p,
+ uint16_t evt_len) {
+ uint8_t status, op_subcode, action;
+
+ if (evt_len != 3) {
+ BTM_TRACE_ERROR("%s: APCF callback length = %d", __func__, evt_len);
+ return;
+ }
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(op_subcode, p);
+ STREAM_TO_UINT8(action, p);
+
+ if (op_subcode != BTM_BLE_META_PF_ENABLE) {
+ BTM_TRACE_ERROR("%s :bad subcode: 0x%02x", __func__, op_subcode);
+ return;
+ }
+
+ p_stat_cback.Run(action, status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableDisableFilterFeature
+ *
+ * Description This function is called to enable / disable the APCF feature
+ *
+ * Parameters enable: enable or disable the filter condition
+ * p_stat_cback - Status callback pointer
+ *
+ ******************************************************************************/
+void BTM_BleEnableDisableFilterFeature(uint8_t enable,
+ tBTM_BLE_PF_STATUS_CBACK p_stat_cback) {
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) {
+ if (p_stat_cback) p_stat_cback.Run(BTM_BLE_PF_ENABLE, 1 /* BTA_FAILURE */);
+ return;
+ }
+
+ uint8_t param[20];
+ memset(param, 0, 20);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE);
+ UINT8_TO_STREAM(p, enable);
+
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ BTM_BLE_PCF_ENABLE_LEN,
+ base::Bind(&enable_cmpl_cback, p_stat_cback));
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_adv_filter_init
+ *
+ * Description This function initializes the adv filter control block
+ *
+ * Parameters
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+void btm_ble_adv_filter_init(void) {
+ memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_ADV_FILTER_CB));
+ if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) return;
+
+ if (cmn_ble_vsc_cb.max_filter > 0) {
+ btm_ble_adv_filt_cb.p_addr_filter_count = (tBTM_BLE_PF_COUNT*)osi_malloc(
+ sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_adv_filter_cleanup
+ *
+ * Description This function de-initializes the adv filter control block
+ *
+ * Parameters
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+void btm_ble_adv_filter_cleanup(void) {
+ osi_free_and_reset((void**)&btm_ble_adv_filt_cb.p_addr_filter_count);
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_batchscan.cc b/mtkbt/code/bt/stack/btm/btm_ble_batchscan.cc
new file mode 100755
index 0000000..21900e9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_batchscan.cc
@@ -0,0 +1,552 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <base/bind.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+#include "bt_target.h"
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+
+using base::Bind;
+using base::Callback;
+using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */,
+ uint16_t /* return_parameters_length*/)>;
+
+tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
+tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb;
+
+/* length of each batch scan command */
+#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4
+#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN 12
+#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN 2
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN 2
+
+namespace {
+
+bool can_do_batch_scan() {
+ if (!controller_get_interface()->supports_ble()) return false;
+
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ if (cmn_ble_vsc_cb.tot_scan_results_strg == 0) return false;
+
+ return true;
+}
+
+/* VSE callback for batch scan, filter, and tracking events */
+void btm_ble_batchscan_filter_track_adv_vse_cback(uint8_t len, uint8_t* p) {
+ tBTM_BLE_TRACK_ADV_DATA adv_data;
+
+ uint8_t sub_event = 0;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+ STREAM_TO_UINT8(sub_event, p);
+
+ BTM_TRACE_EVENT(
+ "btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x",
+ sub_event);
+ if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event &&
+ NULL != ble_batchscan_cb.p_thres_cback) {
+ ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value);
+ return;
+ }
+
+ if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event &&
+ NULL != ble_advtrack_cb.p_track_cback) {
+ if (len < 10) return;
+
+ memset(&adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA));
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+ adv_data.client_if = (uint8_t)ble_advtrack_cb.ref_value;
+ if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
+ STREAM_TO_UINT8(adv_data.filt_index, p);
+ STREAM_TO_UINT8(adv_data.advertiser_state, p);
+ STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
+ STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+ STREAM_TO_UINT8(adv_data.addr_type, p);
+
+ /* Extract the adv info details */
+ if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
+ STREAM_TO_UINT8(adv_data.tx_power, p);
+ STREAM_TO_UINT8(adv_data.rssi_value, p);
+ STREAM_TO_UINT16(adv_data.time_stamp, p);
+
+ STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
+ if (adv_data.adv_pkt_len > 0) {
+ adv_data.p_adv_pkt_data =
+ static_cast<uint8_t*>(osi_malloc(adv_data.adv_pkt_len));
+ memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
+ }
+
+ STREAM_TO_UINT8(adv_data.scan_rsp_len, p);
+ if (adv_data.scan_rsp_len > 0) {
+ adv_data.p_scan_rsp_data =
+ static_cast<uint8_t*>(osi_malloc(adv_data.scan_rsp_len));
+ memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
+ }
+ }
+ } else {
+ /* Based on L-release version */
+ STREAM_TO_UINT8(adv_data.filt_index, p);
+ STREAM_TO_UINT8(adv_data.addr_type, p);
+ STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
+ STREAM_TO_UINT8(adv_data.advertiser_state, p);
+ }
+
+ BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d",
+ adv_data.filt_index, adv_data.addr_type,
+ adv_data.advertiser_state);
+
+ // Make sure the device is known
+ BTM_SecAddBleDevice(adv_data.bd_addr.address, NULL, BT_DEVICE_TYPE_BLE,
+ adv_data.addr_type);
+
+ ble_advtrack_cb.p_track_cback(&adv_data);
+ return;
+ }
+}
+
+void feat_enable_cb(uint8_t* p, uint16_t len) {
+ if (len < 2) {
+ BTM_TRACE_ERROR("%s: wrong length", __func__);
+ return;
+ }
+
+ uint8_t status, subcode;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE;
+ if (subcode != expected_opcode) {
+ BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__,
+ expected_opcode, subcode);
+ return;
+ }
+
+ if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_ENABLE_CALLED)
+ BTM_TRACE_ERROR("%s: state should be ENABLE_CALLED", __func__);
+
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE;
+}
+
+void storage_config_cb(Callback<void(uint8_t /* status */)> cb, uint8_t* p,
+ uint16_t len) {
+ if (len < 2) {
+ BTM_TRACE_ERROR("%s: wrong length", __func__);
+ return;
+ }
+
+ uint8_t status, subcode;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM;
+ if (subcode != expected_opcode) {
+ BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__,
+ expected_opcode, subcode);
+ return;
+ }
+
+ cb.Run(status);
+}
+
+void param_enable_cb(Callback<void(uint8_t /* status */)> cb, uint8_t* p,
+ uint16_t len) {
+ if (len < 2) {
+ BTM_TRACE_ERROR("%s: wrong length", __func__);
+ return;
+ }
+
+ uint8_t status, subcode;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS;
+ if (subcode != expected_opcode) {
+ BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode,
+ subcode);
+ return;
+ }
+
+ cb.Run(status);
+}
+
+void disable_cb(base::Callback<void(uint8_t /* status */)> cb, uint8_t* p,
+ uint16_t len) {
+ if (len < 2) {
+ BTM_TRACE_ERROR("%s: wrong length", __func__);
+ return;
+ }
+
+ uint8_t status, subcode;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_SET_PARAMS;
+ if (subcode != expected_opcode) {
+ BTM_TRACE_ERROR("%s: bad subcode: 0x%02x 0x%02x", __func__, expected_opcode,
+ subcode);
+ return;
+ }
+
+ if (ble_batchscan_cb.cur_state != BTM_BLE_SCAN_DISABLE_CALLED) {
+ BTM_TRACE_ERROR("%s: state should be DISABLE_CALLED", __func__);
+ }
+
+ if (BTM_SUCCESS == status) {
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
+ } else {
+ BTM_TRACE_ERROR("%s: Invalid state after disabled", __func__);
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
+ }
+
+ cb.Run(status);
+}
+
+/**
+ * This function reads the reports from controller. |scan_mode| is the mode for
+ * which the reports are to be read
+ */
+void btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ hci_cmd_cb cb) {
+ uint8_t len = BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN;
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
+ UINT8_TO_STREAM(pp, scan_mode);
+
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+}
+
+/* read reports. data is accumulated in |data_all|, number of records is
+ * accumulated in |num_records_all| */
+void read_reports_cb(std::vector<uint8_t> data_all, uint8_t num_records_all,
+ tBTM_BLE_SCAN_REP_CBACK cb, uint8_t* p, uint16_t len) {
+ if (len < 2) {
+ BTM_TRACE_ERROR("%s: wrong length", __func__);
+ return;
+ }
+
+ uint8_t status, subcode;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT8(subcode, p);
+
+ uint8_t expected_opcode = BTM_BLE_BATCH_SCAN_READ_RESULTS;
+ if (subcode != expected_opcode) {
+ BTM_TRACE_ERROR("%s: bad subcode, expected: %d got: %d", __func__,
+ expected_opcode, subcode);
+ return;
+ }
+
+ uint8_t report_format, num_records;
+ STREAM_TO_UINT8(report_format, p);
+ STREAM_TO_UINT8(num_records, p);
+
+ BTM_TRACE_DEBUG("%s: status=%d,len=%d,rec=%d", __func__, status, len - 4,
+ num_records);
+
+ if (num_records == 0) {
+ cb.Run(status, report_format, num_records_all, data_all);
+ return;
+ }
+
+ if (len > 4) {
+ data_all.insert(data_all.end(), p, p + len - 4);
+ num_records_all += num_records;
+
+ /* More records could be in the buffer and needs to be pulled out */
+ btm_ble_read_batchscan_reports(
+ report_format, base::Bind(&read_reports_cb, std::move(data_all),
+ num_records_all, std::move(cb)));
+ }
+}
+
+/**
+ * This function writes the storage configuration in controller
+ *
+ * Parameters batch_scan_full_max - Max storage space (in %) allocated to
+ * full scanning
+ * batch_scan_trunc_max - Max storage space (in %) allocated to
+ * truncated scanning
+ * batch_scan_notify_threshold - Set up notification level
+ * based on total space
+ *
+ **/
+void btm_ble_set_storage_config(uint8_t batch_scan_full_max,
+ uint8_t batch_scan_trunc_max,
+ uint8_t batch_scan_notify_threshold,
+ hci_cmd_cb cb) {
+ uint8_t len = BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN;
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* pp = param;
+ UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
+ UINT8_TO_STREAM(pp, batch_scan_full_max);
+ UINT8_TO_STREAM(pp, batch_scan_trunc_max);
+ UINT8_TO_STREAM(pp, batch_scan_notify_threshold);
+
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+}
+
+/* This function writes the batch scan params in controller */
+void btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ uint32_t scan_interval, uint32_t scan_window,
+ tBLE_ADDR_TYPE addr_type,
+ tBTM_BLE_DISCARD_RULE discard_rule,
+ hci_cmd_cb cb) {
+ // Override param and decide addr_type based on own addr type
+ // TODO: Remove upper layer parameter?
+ addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type;
+
+ uint8_t len = BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN;
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_SET_PARAMS);
+ UINT8_TO_STREAM(p, scan_mode);
+ UINT32_TO_STREAM(p, scan_window);
+ UINT32_TO_STREAM(p, scan_interval);
+ UINT8_TO_STREAM(p, addr_type);
+ UINT8_TO_STREAM(p, discard_rule);
+
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+}
+
+/* This function enables the customer specific feature in controller */
+void btm_ble_enable_batchscan(hci_cmd_cb cb) {
+ uint8_t len = BTM_BLE_BATCH_SCAN_ENB_DISB_LEN;
+ uint8_t param[len];
+ memset(param, 0, len);
+
+ uint8_t* p = param;
+ UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
+ UINT8_TO_STREAM(p, 0x01 /* enable */);
+
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+}
+
+} // namespace
+
+/*******************************************************************************
+ *
+ * Description This function is called to write storage config params.
+ *
+ * Parameters: batch_scan_full_max - Max storage space (in %) allocated to
+ * full style
+ * batch_scan_trunc_max - Max storage space (in %) allocated to
+ * trunc style
+ * batch_scan_notify_threshold - Setup notification level based
+ * on total space
+ * cb - Setup callback pointer
+ * p_thres_cback - Threshold callback pointer
+ * ref_value - Reference value
+ *
+ ******************************************************************************/
+void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max,
+ uint8_t batch_scan_trunc_max,
+ uint8_t batch_scan_notify_threshold,
+ Callback<void(uint8_t /* status */)> cb,
+ tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback,
+ tBTM_BLE_REF_VALUE ref_value) {
+ if (!can_do_batch_scan()) {
+ cb.Run(BTM_ERR_PROCESSING);
+ return;
+ }
+
+ BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d", __func__,
+ ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max,
+ batch_scan_trunc_max, batch_scan_notify_threshold);
+
+ ble_batchscan_cb.p_thres_cback = p_thres_cback;
+ ble_batchscan_cb.ref_value = ref_value;
+
+ if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
+ batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
+ batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) {
+ BTM_TRACE_ERROR("Illegal set storage config params");
+ cb.Run(BTM_ILLEGAL_VALUE);
+ return;
+ }
+
+ if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
+ btm_ble_enable_batchscan(Bind(&feat_enable_cb));
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+ }
+
+ btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
+ batch_scan_notify_threshold,
+ Bind(&storage_config_cb, cb));
+ return;
+}
+
+/* This function is called to configure and enable batch scanning */
+void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ uint32_t scan_interval, uint32_t scan_window,
+ tBLE_ADDR_TYPE addr_type,
+ tBTM_BLE_DISCARD_RULE discard_rule,
+ Callback<void(uint8_t /* status */)> cb) {
+ BTM_TRACE_EVENT("%s: %d, %d, %d, %d, %d, %d", __func__, scan_mode,
+ scan_interval, scan_window, addr_type, discard_rule);
+
+ if (!can_do_batch_scan()) {
+ cb.Run(BTM_ERR_PROCESSING);
+ return;
+ }
+
+ BTM_TRACE_DEBUG("%s: %d, %x, %x, %d, %d", __func__, scan_mode, scan_interval,
+ scan_window, discard_rule, ble_batchscan_cb.cur_state);
+
+ /* Only 16 bits will be used for scan interval and scan window as per
+ * agreement with Google */
+ /* So the standard LE range would suffice for scan interval and scan window */
+ if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN,
+ BTM_BLE_SCAN_INT_MAX) ||
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN,
+ BTM_BLE_SCAN_WIN_MAX)) &&
+ (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
+ BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode ||
+ BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode) &&
+ (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
+ BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) {
+ } else {
+ BTM_TRACE_ERROR("%s: Illegal enable scan params", __func__);
+ cb.Run(BTM_ILLEGAL_VALUE);
+ return;
+ }
+
+ if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
+ BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
+ btm_ble_enable_batchscan(Bind(&feat_enable_cb));
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
+ }
+
+ ble_batchscan_cb.scan_mode = scan_mode;
+ ble_batchscan_cb.scan_interval = scan_interval;
+ ble_batchscan_cb.scan_window = scan_window;
+ ble_batchscan_cb.addr_type = addr_type;
+ ble_batchscan_cb.discard_rule = discard_rule;
+ /* This command starts batch scanning, if enabled */
+ btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
+ discard_rule, Bind(&param_enable_cb, cb));
+}
+
+/* This function is called to disable batch scanning */
+void BTM_BleDisableBatchScan(base::Callback<void(uint8_t /* status */)> cb) {
+ BTM_TRACE_EVENT(" BTM_BleDisableBatchScan");
+
+ if (!can_do_batch_scan()) {
+ cb.Run(BTM_ERR_PROCESSING);
+ return;
+ }
+
+ btm_ble_set_batchscan_param(
+ BTM_BLE_BATCH_SCAN_MODE_DISABLE, ble_batchscan_cb.scan_interval,
+ ble_batchscan_cb.scan_window, ble_batchscan_cb.addr_type,
+ ble_batchscan_cb.discard_rule, Bind(&disable_cb, cb));
+ ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
+}
+
+/* This function is called to start reading batch scan reports */
+void BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ tBTM_BLE_SCAN_REP_CBACK cb) {
+ uint8_t read_scan_mode = 0;
+
+ BTM_TRACE_EVENT("%s; %d", __func__, scan_mode);
+
+ if (!can_do_batch_scan()) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+ cb.Run(BTM_ERR_PROCESSING, 0, 0, {});
+ return;
+ }
+
+ /* Check if the requested scan mode has already been setup by the user */
+ read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
+ if (0 == read_scan_mode)
+ read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
+
+ /* Check only for modes, as scan reports can be called after disabling batch
+ * scan */
+ if (read_scan_mode < 0 || (scan_mode != BTM_BLE_BATCH_SCAN_MODE_PASS &&
+ scan_mode != BTM_BLE_BATCH_SCAN_MODE_ACTI)) {
+ BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode,
+ scan_mode, ble_batchscan_cb.cur_state);
+ cb.Run(BTM_ILLEGAL_VALUE, 0, 0, {});
+ return;
+ }
+
+ btm_ble_read_batchscan_reports(
+ scan_mode, base::Bind(&read_reports_cb, std::vector<uint8_t>(), 0, cb));
+ return;
+}
+
+/* This function is called to setup the callback for tracking */
+void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback,
+ tBTM_BLE_REF_VALUE ref_value) {
+ BTM_TRACE_EVENT("%s:", __func__);
+
+ if (!can_do_batch_scan()) {
+ BTM_TRACE_ERROR("Controller does not support batch scan");
+
+ tBTM_BLE_TRACK_ADV_DATA track_adv_data;
+ memset(&track_adv_data, 0, sizeof(tBTM_BLE_TRACK_ADV_DATA));
+ track_adv_data.advertiser_info_present =
+ NO_ADV_INFO_PRESENT; /* Indicates failure */
+ track_adv_data.client_if = (uint8_t)ref_value;
+ p_track_cback(&track_adv_data);
+ return;
+ }
+
+ ble_advtrack_cb.p_track_cback = p_track_cback;
+ ble_advtrack_cb.ref_value = ref_value;
+ return;
+}
+
+/**
+ * This function initialize the batch scan control block.
+ **/
+void btm_ble_batchscan_init(void) {
+ BTM_TRACE_EVENT(" btm_ble_batchscan_init");
+ memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+ memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+ BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, true);
+}
+
+/**
+ * This function cleans the batch scan control block.
+ **/
+void btm_ble_batchscan_cleanup(void) {
+ BTM_TRACE_EVENT("%s", __func__);
+
+ memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
+ memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_bgconn.cc b/mtkbt/code/bt/stack/btm/btm_ble_bgconn.cc
new file mode 100755
index 0000000..c3d8dbb
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_bgconn.cc
@@ -0,0 +1,652 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for BLE whitelist operation.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <string.h>
+#include <unordered_map>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/allocator.h"
+#include "osi/include/osi.h"
+
+#ifndef BTM_BLE_SCAN_PARAM_TOUT
+#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
+#endif
+
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
+static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state);
+
+// Unfortunately (for now?) we have to maintain a copy of the device whitelist
+// on the host to determine if a device is pending to be connected or not. This
+// controls whether the host should keep trying to scan for whitelisted
+// peripherals or not.
+// TODO: Move all of this to controller/le/background_list or similar?
+typedef struct background_connection_t {
+ bt_bdaddr_t address;
+ uint8_t addr_type;
+
+ bool in_controller_wl;
+ uint8_t addr_type_in_wl;
+
+ bool pending_removal;
+} background_connection_t;
+
+struct BgConnHash {
+ bool operator()(const bt_bdaddr_t& x) const {
+ const uint8_t* a = x.address;
+ return a[0] ^ (a[1] << 8) ^ (a[2] << 16) ^ (a[3] << 24) ^ a[4] ^
+ (a[5] << 8);
+ }
+};
+
+struct BgConnKeyEqual {
+ bool operator()(const bt_bdaddr_t& x, const bt_bdaddr_t& y) const {
+ return bdaddr_equals(&x, &y);
+ }
+};
+
+static std::unordered_map<bt_bdaddr_t, background_connection_t, BgConnHash,
+ BgConnKeyEqual>
+ background_connections;
+
+static void background_connection_add(uint8_t addr_type, bt_bdaddr_t* address) {
+ CHECK(address);
+
+ auto map_iter = background_connections.find(*address);
+ if (map_iter == background_connections.end()) {
+ background_connections[*address] =
+ background_connection_t{*address, addr_type, false, 0, false};
+ } else {
+ background_connection_t* connection = &map_iter->second;
+ connection->addr_type = addr_type;
+ connection->pending_removal = false;
+ }
+}
+
+static void background_connection_remove(bt_bdaddr_t* address) {
+ auto map_iter = background_connections.find(*address);
+ if (map_iter != background_connections.end()) {
+ if (map_iter->second.in_controller_wl) {
+ map_iter->second.pending_removal = true;
+ } else {
+ background_connections.erase(map_iter);
+ }
+ }
+}
+
+static void background_connections_clear() { background_connections.clear(); }
+
+static bool background_connections_pending() {
+ for (auto& map_el : background_connections) {
+ background_connection_t* connection = &map_el.second;
+ if (connection->pending_removal) continue;
+ const bool connected =
+ BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
+ if (!connected) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int background_connections_count() {
+ int count = 0;
+ for (auto& map_el : background_connections) {
+ if (!map_el.second.pending_removal) ++count;
+ }
+ return count;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_update_scanner_filter_policy
+ *
+ * Description This function updates the filter policy of scanner
+ ******************************************************************************/
+void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy) {
+ tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
+
+ uint32_t scan_interval =
+ !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+ uint32_t scan_window =
+ !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+ BTM_TRACE_EVENT("%s", __func__);
+
+ p_inq->sfp = scan_policy;
+ p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE
+ ? BTM_BLE_SCAN_MODE_ACTI
+ : p_inq->scan_type;
+
+ btm_send_hci_set_scan_params(
+ p_inq->scan_type, (uint16_t)scan_interval, (uint16_t)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, scan_policy);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_bgconn_cancel_if_disconnected
+ *
+ * Description If a device has been disconnected, it must be re-added to
+ * the white list. If needed, this function cancels a pending
+ * initiate command in order to trigger restart of the initiate
+ * command which in turn updates the white list.
+ *
+ * Parameters bd_addr: updated device
+ *
+ ******************************************************************************/
+void btm_ble_bgconn_cancel_if_disconnected(BD_ADDR bd_addr) {
+ if (btm_cb.ble_ctr_cb.conn_state != BLE_BG_CONN) return;
+
+ bt_bdaddr_t addr = *(bt_bdaddr_t*)bd_addr;
+
+ auto map_it = background_connections.find(addr);
+ if (map_it != background_connections.end()) {
+ background_connection_t* connection = &map_it->second;
+ if (!connection->in_controller_wl && !connection->pending_removal &&
+ !BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
+ btm_ble_start_auto_conn(false);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_add_dev_to_controller
+ *
+ * Description This function load the device into controller white list
+ ******************************************************************************/
+bool btm_add_dev_to_controller(bool to_add, BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ bool started = false;
+ BD_ADDR dummy_bda = {0};
+
+ if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
+ if (to_add) {
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
+ !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ background_connection_add(p_dev_rec->ble.ble_addr_type,
+ (bt_bdaddr_t*)bd_addr);
+ started = true;
+ p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+ } else if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) !=
+ 0 &&
+ memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) !=
+ 0) {
+ background_connection_add(p_dev_rec->ble.static_addr_type,
+ (bt_bdaddr_t*)p_dev_rec->ble.static_addr);
+ started = true;
+ p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
+ }
+ } else {
+ if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC ||
+ !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
+ background_connection_remove((bt_bdaddr_t*)bd_addr);
+ started = true;
+ }
+
+ if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 &&
+ memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) {
+ background_connection_remove((bt_bdaddr_t*)p_dev_rec->ble.static_addr);
+ started = true;
+ }
+
+ p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
+ }
+ } else {
+ /* not a known device, i.e. attempt to connect to device never seen before
+ */
+ uint8_t addr_type =
+ BTM_IS_PUBLIC_BDA(bd_addr) ? BLE_ADDR_PUBLIC : BLE_ADDR_RANDOM;
+ started = true;
+ if (to_add)
+ background_connection_add(addr_type, (bt_bdaddr_t*)bd_addr);
+ else
+ background_connection_remove((bt_bdaddr_t*)bd_addr);
+ }
+
+ return started;
+}
+/*******************************************************************************
+ *
+ * Function btm_execute_wl_dev_operation
+ *
+ * Description execute the pending whitelist device operation (loading or
+ * removing)
+ ******************************************************************************/
+bool btm_execute_wl_dev_operation(void) {
+ // handle removals first to avoid filling up controller's white list
+ for (auto map_it = background_connections.begin();
+ map_it != background_connections.end();) {
+ background_connection_t* connection = &map_it->second;
+ if (connection->pending_removal) {
+ btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
+ connection->address.address);
+ map_it = background_connections.erase(map_it);
+ } else
+ ++map_it;
+ }
+ for (auto& map_el : background_connections) {
+ background_connection_t* connection = &map_el.second;
+ const bool connected =
+ BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
+ if (!connection->in_controller_wl && !connected) {
+ btsnd_hcic_ble_add_white_list(connection->addr_type,
+ connection->address.address);
+ connection->in_controller_wl = true;
+ connection->addr_type_in_wl = connection->addr_type;
+ } else if (connection->in_controller_wl && connected) {
+ /* Bluetooth Core 4.2 as well as ESR08 disallows more than one
+ connection between two LE addresses. Not all controllers handle this
+ correctly, therefore we must make sure connected devices are not in
+ the white list when bg connection attempt is active. */
+ btsnd_hcic_ble_remove_from_white_list(connection->addr_type_in_wl,
+ connection->address.address);
+ connection->in_controller_wl = false;
+ }
+ }
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_update_dev_to_white_list
+ *
+ * Description This function adds or removes a device into/from
+ * the white list.
+ *
+ ******************************************************************************/
+bool btm_update_dev_to_white_list(bool to_add, BD_ADDR bd_addr) {
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+
+ if (to_add &&
+ background_connections_count() ==
+ controller_get_interface()->get_ble_white_list_size()) {
+ BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
+ return false;
+ }
+
+ btm_suspend_wl_activity(p_cb->wl_state);
+ btm_add_dev_to_controller(to_add, bd_addr);
+ btm_resume_wl_activity(p_cb->wl_state);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_white_list
+ *
+ * Description This function clears the white list.
+ *
+ ******************************************************************************/
+void btm_ble_clear_white_list(void) {
+ BTM_TRACE_EVENT("btm_ble_clear_white_list");
+ btsnd_hcic_ble_clear_white_list();
+ background_connections_clear();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_white_list_complete
+ *
+ * Description Indicates white list cleared.
+ *
+ ******************************************************************************/
+void btm_ble_clear_white_list_complete(uint8_t* p_data,
+ UNUSED_ATTR uint16_t evt_len) {
+ uint8_t status;
+
+ STREAM_TO_UINT8(status, p_data);
+ BTM_TRACE_EVENT("%s status=%d", __func__, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_white_list_init
+ *
+ * Description Initialize white list size
+ *
+ ******************************************************************************/
+void btm_ble_white_list_init(uint8_t white_list_size) {
+ BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_add_2_white_list_complete
+ *
+ * Description White list element added
+ *
+ ******************************************************************************/
+void btm_ble_add_2_white_list_complete(uint8_t status) {
+ BTM_TRACE_EVENT("%s status=%d", __func__, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_remove_from_white_list_complete
+ *
+ * Description White list element removal complete
+ *
+ ******************************************************************************/
+void btm_ble_remove_from_white_list_complete(uint8_t* p,
+ UNUSED_ATTR uint16_t evt_len) {
+ BTM_TRACE_EVENT("%s status=%d", __func__, *p);
+}
+
+void btm_send_hci_create_connection(
+ uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
+ uint8_t addr_type_peer, BD_ADDR bda_peer, uint8_t addr_type_own,
+ uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
+ uint8_t initiating_phys) {
+ if (controller_get_interface()->supports_ble_extended_advertising()) {
+ EXT_CONN_PHY_CFG phy_cfg[3]; // maximum three phys
+
+ int phy_cnt =
+ std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys)
+ .count();
+
+ LOG_ASSERT(phy_cnt < 3) << "More than three phys provided";
+ // TODO(jpawlowski): tune parameters for different transports
+ for (int i = 0; i < phy_cnt; i++) {
+ phy_cfg[i].scan_int = scan_int;
+ phy_cfg[i].scan_win = scan_win;
+ phy_cfg[i].conn_int_min = conn_int_min;
+ phy_cfg[i].conn_int_max = conn_int_max;
+ phy_cfg[i].conn_latency = conn_latency;
+ phy_cfg[i].sup_timeout = conn_timeout;
+ phy_cfg[i].min_ce_len = min_ce_len;
+ phy_cfg[i].max_ce_len = max_ce_len;
+ }
+
+ addr_type_peer &= ~BLE_ADDR_TYPE_ID_BIT;
+ btsnd_hcic_ble_ext_create_conn(init_filter_policy, addr_type_own,
+ addr_type_peer, bda_peer, initiating_phys,
+ phy_cfg);
+ } else {
+ btsnd_hcic_ble_create_ll_conn(scan_int, scan_win, init_filter_policy,
+ addr_type_peer, bda_peer, addr_type_own,
+ conn_int_min, conn_int_max, conn_latency,
+ conn_timeout, min_ce_len, max_ce_len);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_auto_conn
+ *
+ * Description This function is to start/stop auto connection procedure.
+ *
+ * Parameters start: true to start; false to stop.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool btm_ble_start_auto_conn(bool start) {
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+ BD_ADDR dummy_bda = {0};
+ bool exec = true;
+ uint16_t scan_int;
+ uint16_t scan_win;
+ uint8_t own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
+ uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
+
+ uint8_t phy = PHY_LE_1M;
+ if (controller_get_interface()->supports_ble_2m_phy()) phy |= PHY_LE_2M;
+ if (controller_get_interface()->supports_ble_coded_phy()) phy |= PHY_LE_CODED;
+
+ BTM_TRACE_EVENT("%s start=%d", __func__, start);
+
+ if (start) {
+ if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() &&
+ btm_ble_topology_check(BTM_BLE_STATE_INIT) && l2cu_can_allocate_lcb()) {
+ p_cb->wl_state |= BTM_BLE_WL_INIT;
+
+ btm_execute_wl_dev_operation();
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
+#endif
+ scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_INT_1
+ : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_SLOW_WIN_1
+ : p_cb->scan_win;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
+ controller_get_interface()->supports_ble_privacy()) {
+ own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+ }
+#endif
+
+ btm_send_hci_create_connection(
+ scan_int, /* uint16_t scan_int */
+ scan_win, /* uint16_t scan_win */
+ 0x01, /* uint8_t white_list */
+ peer_addr_type, /* uint8_t addr_type_peer */
+ dummy_bda, /* BD_ADDR bda_peer */
+ own_addr_type, /* uint8_t addr_type_own */
+ BTM_BLE_CONN_INT_MIN_DEF, /* uint16_t conn_int_min */
+ BTM_BLE_CONN_INT_MAX_DEF, /* uint16_t conn_int_max */
+ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency */
+ BTM_BLE_CONN_TIMEOUT_DEF, /* uint16_t conn_timeout */
+ 0, /* uint16_t min_len */
+ 0, /* uint16_t max_len */
+ phy);
+ btm_ble_set_conn_st(BLE_BG_CONN);
+ } else {
+ exec = false;
+ }
+ } else {
+ if (p_cb->conn_state == BLE_BG_CONN) {
+ btsnd_hcic_ble_create_conn_cancel();
+ btm_ble_set_conn_st(BLE_CONN_CANCEL);
+ p_cb->wl_state &= ~BTM_BLE_WL_INIT;
+ } else {
+ BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop",
+ p_cb->conn_state);
+ exec = false;
+ }
+ }
+ return exec;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_suspend_bg_conn
+ *
+ * Description This function is to suspend an active background connection
+ * procedure.
+ *
+ * Parameters none.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+bool btm_ble_suspend_bg_conn(void) {
+ BTM_TRACE_EVENT("%s", __func__);
+
+ if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO)
+ return btm_ble_start_auto_conn(false);
+
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function btm_suspend_wl_activity
+ *
+ * Description This function is to suspend white list related activity
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state) {
+ if (wl_state & BTM_BLE_WL_INIT) {
+ btm_ble_start_auto_conn(false);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btm_resume_wl_activity
+ *
+ * Description This function is to resume white list related activity
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) {
+ btm_ble_resume_bg_conn();
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_resume_bg_conn
+ *
+ * Description This function is to resume a background auto connection
+ * procedure.
+ *
+ * Parameters none.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+bool btm_ble_resume_bg_conn(void) {
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+ if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) {
+ return btm_ble_start_auto_conn(true);
+ }
+
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_get_conn_st
+ *
+ * Description This function get BLE connection state
+ *
+ * Returns connection state
+ *
+ ******************************************************************************/
+tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) {
+ return btm_cb.ble_ctr_cb.conn_state;
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_set_conn_st
+ *
+ * Description This function set BLE connection state
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) {
+ btm_cb.ble_ctr_cb.conn_state = new_st;
+
+ if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN)
+ btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
+ else
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_enqueue_direct_conn_req
+ *
+ * Description This function enqueue the direct connection request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void btm_ble_enqueue_direct_conn_req(void* p_param) {
+ tBTM_BLE_CONN_REQ* p =
+ (tBTM_BLE_CONN_REQ*)osi_malloc(sizeof(tBTM_BLE_CONN_REQ));
+
+ p->p_param = p_param;
+
+ fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p);
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_dequeue_direct_conn_req
+ *
+ * Description This function dequeues the direct connection request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda) {
+ if (fixed_queue_is_empty(btm_cb.ble_ctr_cb.conn_pending_q)) return;
+
+ list_t* list = fixed_queue_get_list(btm_cb.ble_ctr_cb.conn_pending_q);
+ for (const list_node_t* node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ tBTM_BLE_CONN_REQ* p_req = (tBTM_BLE_CONN_REQ*)list_node(node);
+ tL2C_LCB* p_lcb = (tL2C_LCB*)p_req->p_param;
+ if ((p_lcb == NULL) || (!p_lcb->in_use)) {
+ continue;
+ }
+ // If BD address matches
+ if (!memcmp(rem_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN)) {
+ fixed_queue_try_remove_from_queue(btm_cb.ble_ctr_cb.conn_pending_q,
+ p_req);
+ l2cu_release_lcb((tL2C_LCB*)p_req->p_param);
+ osi_free((void*)p_req);
+ break;
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function btm_send_pending_direct_conn
+ *
+ * Description This function send the pending direct connection request in
+ * queue
+ *
+ * Returns true if started, false otherwise
+ *
+ ******************************************************************************/
+bool btm_send_pending_direct_conn(void) {
+ tBTM_BLE_CONN_REQ* p_req;
+ bool rt = false;
+
+ p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_try_dequeue(
+ btm_cb.ble_ctr_cb.conn_pending_q);
+ if (p_req != NULL) {
+ tL2C_LCB* p_lcb = (tL2C_LCB*)(p_req->p_param);
+ /* Ignore entries that might have been released while queued. */
+ if (p_lcb->in_use) rt = l2cble_init_direct_conn(p_lcb);
+ osi_free(p_req);
+ }
+
+ return rt;
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_cont_energy.cc b/mtkbt/code/bt/stack/btm/btm_ble_cont_energy.cc
new file mode 100755
index 0000000..61c5327
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_cont_energy.cc
@@ -0,0 +1,99 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+tBTM_BLE_ENERGY_INFO_CB ble_energy_info_cb;
+
+/*******************************************************************************
+ *
+ * Function btm_ble_cont_energy_cmpl_cback
+ *
+ * Description Controller VSC complete callback
+ *
+ * Parameters
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_cont_energy_cmpl_cback(tBTM_VSC_CMPL* p_params) {
+ uint8_t* p = p_params->p_param_buf;
+ uint16_t len = p_params->param_len;
+ uint8_t status = 0;
+ uint32_t total_tx_time = 0, total_rx_time = 0, total_idle_time = 0,
+ total_energy_used = 0;
+
+ if (len < 17) {
+ BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback");
+ return;
+ }
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT32(total_tx_time, p);
+ STREAM_TO_UINT32(total_rx_time, p);
+ STREAM_TO_UINT32(total_idle_time, p);
+ STREAM_TO_UINT32(total_energy_used, p);
+
+ BTM_TRACE_DEBUG(
+ "energy_info status=%d,tx_t=%ld, rx_t=%ld, ener_used=%ld, idle_t=%ld",
+ status, total_tx_time, total_rx_time, total_energy_used, total_idle_time);
+
+ if (NULL != ble_energy_info_cb.p_ener_cback)
+ ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time,
+ total_idle_time, total_energy_used, status);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetEnergyInfo
+ *
+ * Description This function obtains the energy info
+ *
+ * Parameters p_ener_cback - Callback pointer
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback) {
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
+
+ BTM_TRACE_EVENT("BTM_BleGetEnergyInfo");
+
+ if (0 == cmn_ble_vsc_cb.energy_support) {
+ BTM_TRACE_ERROR("Controller does not support get energy info");
+ return BTM_ERR_PROCESSING;
+ }
+
+ ble_energy_info_cb.p_ener_cback = p_ener_cback;
+ BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
+ btm_ble_cont_energy_cmpl_cback);
+ return BTM_CMD_STARTED;
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_gap.cc b/mtkbt/code/bt/stack/btm/btm_ble_gap.cc
new file mode 100755
index 0000000..a031523
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_gap.cc
@@ -0,0 +1,2805 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for BLE GAP.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_ble"
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/strings/string_number_conversions.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <list>
+#include <vector>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gap_api.h"
+#include "hcimsgs.h"
+#include "osi/include/osi.h"
+
+#include "advertise_data_parser.h"
+#include "btm_ble_int.h"
+#include "gatt_int.h"
+#include "gattdefs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+
+#define BTM_BLE_NAME_SHORT 0x01
+#define BTM_BLE_NAME_CMPL 0x02
+
+#define BTM_BLE_FILTER_TARGET_UNKNOWN 0xff
+#define BTM_BLE_POLICY_UNKNOWN 0xff
+
+#define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS (30 * 1000)
+#define MIN_ADV_LENGTH 2
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+namespace {
+
+class AdvertisingCache {
+ public:
+ /* Set the data to |data| for device |addr_type, addr| */
+ const std::vector<uint8_t>& Set(uint8_t addr_type, BD_ADDR addr,
+ std::vector<uint8_t> data) {
+ auto it = Find(addr_type, addr);
+ if (it != items.end()) {
+ it->data = std::move(data);
+ return it->data;
+ }
+
+ if (items.size() > cache_max) {
+ items.pop_back();
+ }
+
+ items.emplace_front(addr_type, addr, std::move(data));
+ return items.front().data;
+ }
+
+ /* Append |data| for device |addr_type, addr| */
+ const std::vector<uint8_t>& Append(uint8_t addr_type, BD_ADDR addr,
+ std::vector<uint8_t> data) {
+ auto it = Find(addr_type, addr);
+ if (it != items.end()) {
+ it->data.insert(it->data.end(), data.begin(), data.end());
+ return it->data;
+ }
+
+ if (items.size() > cache_max) {
+ items.pop_back();
+ }
+
+ items.emplace_front(addr_type, addr, std::move(data));
+ return items.front().data;
+ }
+
+ /* Clear data for device |addr_type, addr| */
+ void Clear(uint8_t addr_type, BD_ADDR addr) {
+ auto it = Find(addr_type, addr);
+ if (it != items.end()) {
+ items.erase(it);
+ }
+ }
+
+ private:
+ struct Item {
+ uint8_t addr_type;
+ BD_ADDR addr;
+ std::vector<uint8_t> data;
+
+ Item(uint8_t addr_type, BD_ADDR addr, std::vector<uint8_t> data)
+ : addr_type(addr_type), data(data) {
+ memcpy(this->addr, addr, BD_ADDR_LEN);
+ }
+ };
+
+ std::list<Item>::iterator Find(uint8_t addr_type, BD_ADDR addr) {
+ for (auto it = items.begin(); it != items.end(); it++) {
+ if (it->addr_type == addr_type &&
+ memcmp(it->addr, addr, BD_ADDR_LEN) == 0) {
+ return it;
+ }
+ }
+ return items.end();
+ }
+
+ /* we keep maximum 7 devices in the cache */
+ const size_t cache_max = 7;
+ std::list<Item> items;
+};
+
+/* Devices in this cache are waiting for eiter scan response, or chained packets
+ * on secondary channel */
+AdvertisingCache cache;
+
+} // namespace
+
+#if (BLE_VND_INCLUDED == TRUE)
+static tBTM_BLE_CTRL_FEATURES_CBACK* p_ctrl_le_feature_rd_cmpl_cback = NULL;
+#endif
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+static void btm_ble_update_adv_flag(uint8_t flag);
+static void btm_ble_process_adv_pkt_cont(
+ uint16_t evt_type, uint8_t addr_type, BD_ADDR bda, uint8_t primary_phy,
+ uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power,
+ int8_t rssi, uint16_t periodic_adv_int, uint8_t data_len, uint8_t* data);
+static uint8_t btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB* p_cb,
+ BD_ADDR_PTR p_peer_addr_ptr,
+ tBLE_ADDR_TYPE* p_peer_addr_type,
+ tBLE_ADDR_TYPE* p_own_addr_type);
+static void btm_ble_stop_observe(void);
+static void btm_ble_fast_adv_timer_timeout(void* data);
+static void btm_ble_start_slow_adv(void);
+static void btm_ble_inquiry_timer_gap_limited_discovery_timeout(void* data);
+static void btm_ble_inquiry_timer_timeout(void* data);
+static void btm_ble_observer_timer_timeout(void* data);
+
+#define BTM_BLE_INQ_RESULT 0x01
+#define BTM_BLE_OBS_RESULT 0x02
+
+bool ble_evt_type_is_connectable(uint16_t evt_type) {
+ return evt_type & (1 << BLE_EVT_CONNECTABLE_BIT);
+}
+
+bool ble_evt_type_is_scannable(uint16_t evt_type) {
+ return evt_type & (1 << BLE_EVT_SCANNABLE_BIT);
+}
+
+bool ble_evt_type_is_directed(uint16_t evt_type) {
+ return evt_type & (1 << BLE_EVT_DIRECTED_BIT);
+}
+
+bool ble_evt_type_is_scan_resp(uint16_t evt_type) {
+ return evt_type & (1 << BLE_EVT_SCAN_RESPONSE_BIT);
+}
+
+bool ble_evt_type_is_legacy(uint16_t evt_type) {
+ return evt_type & (1 << BLE_EVT_LEGACY_BIT);
+}
+
+uint8_t ble_evt_type_data_status(uint16_t evt_type) {
+ return (evt_type >> 5) & 3;
+}
+
+/* LE states combo bit to check */
+const uint8_t btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] =
+ {{
+ /* single state support */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_OFF}, /* conn_adv */
+ {HCI_SUPP_LE_STATES_INIT_MASK, HCI_SUPP_LE_STATES_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_INIT_MASK,
+ HCI_SUPP_LE_STATES_INIT_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_SLAVE_OFF}, /* slave */
+ {0, 0}, /* todo: lo du dir adv, not covered ? */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF}, /* hi duty dir adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASK,
+ HCI_SUPP_LE_STATESSCAN_ADV_OFF} /* scanable adv */
+ },
+ {
+ /* conn_adv =0 */
+ {0, 0}, /* conn_adv */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* init: 32 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* master: 35 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/
+ {0, 0}, /* lo du dir adv */
+ {0, 0}, /* hi duty dir adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ {
+ /* init */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* conn_adv: 32 */
+ {0, 0}, /* init */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* slave 41 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF}, /* lo du dir adv 34 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* hi duty dir adv 33 */
+ {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF} /* scanable adv */
+
+ },
+ {
+ /* master */
+ {HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF}, /* conn_adv: 35 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* init 28 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_OFF}, /* master 28 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF}, /* slave: 32 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* lo duty cycle adv
+ 37 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* hi duty cycle adv
+ 36 */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* non connectable adv
+ */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF} /* scanable adv */
+
+ },
+ {
+ /* slave */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* init 41 */
+ {HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF}, /* master 41 */
+ {HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF}, /* slave: 38,*/
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* lo duty cycle adv 40
+ */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* hi duty cycle adv 39
+ */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF} /* scanable adv */
+
+ },
+ {
+ /* lo duty cycle adv */
+ {0, 0}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF}, /* init 34 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF}, /* master 37 */
+ {HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 40 */
+ {0, 0}, /* lo duty cycle adv 40 */
+ {0, 0}, /* hi duty cycle adv 39 */
+ {0, 0}, /* non connectable adv */
+ {0, 0}, /* TODO: passive scan, not covered? */
+ {0, 0}, /* TODO: active scan, not covered? */
+ {0, 0} /* scanable adv */
+ },
+ {
+ /* hi duty cycle adv */
+ {0, 0}, /* conn_adv: 38,*/
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF}, /* init 33 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF}, /* master 36 */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF}, /* slave: 39*/
+ {0, 0}, /* lo duty cycle adv 40 */
+ {0, 0}, /* hi duty cycle adv 39 */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ {
+ /* non connectable adv */
+ {0, 0}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {0, 0}, /* hi duty cycle adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ },
+ {
+ /* passive scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF}, /* hi duty cycle
+ adv */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF}, /* non connectable
+ adv */
+ {0, 0}, /* passive scan */
+ {0, 0}, /* active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF} /* scanable adv */
+ },
+ {
+ /* active scan */
+ {HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF}, /* hi duty
+ cycle adv
+ */
+ {HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF}, /* non
+ connectable
+ adv */
+ {0, 0}, /* TODO: passive scan */
+ {0, 0}, /* TODO: active scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF} /* scanable adv */
+ },
+ {
+ /* scanable adv */
+ {0, 0}, /* conn_adv: */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF}, /* init */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF}, /* master */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF}, /* slave: */
+ {0, 0}, /* lo duty cycle adv */
+ {0, 0}, /* hi duty cycle adv */
+ {0, 0}, /* non connectable adv */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF}, /* passive scan */
+ {HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK,
+ HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF}, /* active scan */
+ {0, 0} /* scanable adv */
+ }
+
+};
+/* check LE combo state supported */
+#define BTM_LE_STATES_SUPPORTED(x, y, z) ((x)[(z)] & (y))
+
+/*******************************************************************************
+ *
+ * Function BTM_BleUpdateAdvFilterPolicy
+ *
+ * Description This function update the filter policy of advertiser.
+ *
+ * Parameter adv_policy: advertising filter policy
+ *
+ * Return void
+ ******************************************************************************/
+void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ BD_ADDR p_addr_ptr = {0};
+ uint8_t adv_mode = p_cb->adv_mode;
+
+ BTM_TRACE_EVENT("BTM_BleUpdateAdvFilterPolicy");
+
+ if (!controller_get_interface()->supports_ble()) return;
+
+ if (p_cb->afp != adv_policy) {
+ p_cb->afp = adv_policy;
+
+ /* if adv active, stop and restart */
+ btm_ble_stop_adv();
+
+ if (p_cb->connectable_mode & BTM_BLE_CONNECTABLE)
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(
+ p_cb, p_addr_ptr, &init_addr_type, &p_cb->adv_addr_type);
+
+ btsnd_hcic_ble_write_adv_params(
+ (uint16_t)(p_cb->adv_interval_min ? p_cb->adv_interval_min
+ : BTM_BLE_GAP_ADV_SLOW_INT),
+ (uint16_t)(p_cb->adv_interval_max ? p_cb->adv_interval_max
+ : BTM_BLE_GAP_ADV_SLOW_INT),
+ p_cb->evt_type, p_cb->adv_addr_type, init_addr_type, p_addr_ptr,
+ p_cb->adv_chnl_map, p_cb->afp);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) btm_ble_start_adv();
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleObserve
+ *
+ * Description This procedure keep the device listening for advertising
+ * events from a broadcast device.
+ *
+ * Parameters start: start or stop observe.
+ * white_list: use white list in observer mode or not.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb) {
+ tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_WRONG_MODE;
+
+ uint32_t scan_interval =
+ !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
+ uint32_t scan_window =
+ !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
+
+ BTM_TRACE_EVENT("%s : scan_type:%d, %d, %d", __func__,
+ btm_cb.btm_inq_vars.scan_type, p_inq->scan_interval,
+ p_inq->scan_window);
+
+ if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE;
+
+ if (start) {
+ /* shared inquiry database, do not allow observe if any inquiry is active */
+ if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ BTM_TRACE_ERROR("%s Observe Already Active", __func__);
+ return status;
+ }
+
+ btm_cb.ble_ctr_cb.p_obs_results_cb = p_results_cb;
+ btm_cb.ble_ctr_cb.p_obs_cmpl_cb = p_cmpl_cb;
+ status = BTM_CMD_STARTED;
+
+ /* scan is not started */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ /* allow config of scan type */
+ p_inq->scan_type = (p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE)
+ ? BTM_BLE_SCAN_MODE_ACTI
+ : p_inq->scan_type;
+/* assume observe always not using white list */
+#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == true)
+ /* enable resolving list */
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+
+ btm_send_hci_set_scan_params(
+ p_inq->scan_type, (uint16_t)scan_interval, (uint16_t)scan_window,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, BTM_BLE_DEFAULT_SFP);
+
+ p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+ status = btm_ble_start_scan();
+ }
+
+ if (status == BTM_CMD_STARTED) {
+ btm_cb.ble_ctr_cb.scan_activity |= BTM_LE_OBSERVE_ACTIVE;
+ if (duration != 0) {
+ /* start observer timer */
+ period_ms_t duration_ms = duration * 1000;
+ alarm_set_on_queue(btm_cb.ble_ctr_cb.observer_timer, duration_ms,
+ btm_ble_observer_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+ }
+ } else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ status = BTM_CMD_STARTED;
+ btm_ble_stop_observe();
+ } else {
+ BTM_TRACE_ERROR("%s Observe not active", __func__);
+ }
+
+ return status;
+}
+
+#if (BLE_VND_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function btm_vsc_brcm_features_complete
+ *
+ * Description Command Complete callback for HCI_BLE_VENDOR_CAP_OCF
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_vendor_capability_vsc_cmpl_cback(
+ tBTM_VSC_CMPL* p_vcs_cplt_params) {
+ uint8_t status = 0xFF;
+ uint8_t* p;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ /* Check status of command complete event */
+ if ((p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF) &&
+ (p_vcs_cplt_params->param_len > 0)) {
+ p = p_vcs_cplt_params->p_param_buf;
+ STREAM_TO_UINT8(status, p);
+ }
+
+ if (status == HCI_SUCCESS) {
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.filter_support, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.max_filter, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.energy_support, p);
+
+ if (p_vcs_cplt_params->param_len >
+ BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.version_supported, p);
+ } else {
+ btm_cb.cmn_ble_vsc_cb.version_supported =
+ BTM_VSC_CHIP_CAPABILITY_L_VERSION;
+ }
+
+ if (btm_cb.cmn_ble_vsc_cb.version_supported >=
+ BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
+ STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
+ /** M: bug fix, STREAM_TO_UINT16 change to STREAM_TO_UINT8 @{*/
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
+ STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
+ /** @} */
+ }
+ btm_cb.cmn_ble_vsc_cb.values_read = true;
+ }
+
+ BTM_TRACE_DEBUG(
+ "%s: stat=%d, irk=%d, ADV ins:%d, rpa=%d, ener=%d, ext_scan=%d", __func__,
+ status, btm_cb.cmn_ble_vsc_cb.max_irk_list_sz,
+ btm_cb.cmn_ble_vsc_cb.adv_inst_max, btm_cb.cmn_ble_vsc_cb.rpa_offloading,
+ btm_cb.cmn_ble_vsc_cb.energy_support,
+ btm_cb.cmn_ble_vsc_cb.extended_scan_support);
+
+ btm_ble_adv_init();
+
+ if (btm_cb.cmn_ble_vsc_cb.max_filter > 0) btm_ble_adv_filter_init();
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* VS capability included and non-4.2 device */
+ if (btm_cb.cmn_ble_vsc_cb.max_irk_list_sz > 0 &&
+ controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ btm_ble_resolving_list_init(btm_cb.cmn_ble_vsc_cb.max_irk_list_sz);
+#endif /* (BLE_PRIVACY_SPT == TRUE) */
+
+ if (btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg > 0) btm_ble_batchscan_init();
+
+ if (p_ctrl_le_feature_rd_cmpl_cback != NULL)
+ p_ctrl_le_feature_rd_cmpl_cback(status);
+}
+#endif /* (BLE_VND_INCLUDED == TRUE) */
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetVendorCapabilities
+ *
+ * Description This function reads local LE features
+ *
+ * Parameters p_cmn_vsc_cb : Locala LE capability structure
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb) {
+ BTM_TRACE_DEBUG("BTM_BleGetVendorCapabilities");
+
+ if (NULL != p_cmn_vsc_cb) {
+ *p_cmn_vsc_cb = btm_cb.cmn_ble_vsc_cb;
+ }
+}
+
+/******************************************************************************
+ *
+ * Function BTM_BleReadControllerFeatures
+ *
+ * Description Reads BLE specific controller features
+ *
+ * Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when
+ * features are read
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BLE_VND_INCLUDED == TRUE)
+extern void BTM_BleReadControllerFeatures(
+ tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {
+ if (true == btm_cb.cmn_ble_vsc_cb.values_read) return;
+
+ BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures");
+
+ p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback;
+ BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP_OCF, 0, NULL,
+ btm_ble_vendor_capability_vsc_cmpl_cback);
+}
+#else
+extern void BTM_BleReadControllerFeatures(
+ UNUSED_ATTR tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback) {}
+#endif
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableMixedPrivacyMode
+ *
+ * Description This function is called to enabled Mixed mode if privacy 1.2
+ * is applicable in controller.
+ *
+ * Parameters mixed_on: mixed mode to be used or not.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleEnableMixedPrivacyMode(bool mixed_on) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_cb.ble_ctr_cb.mixed_mode = mixed_on;
+
+/* TODO: send VSC to enabled mixed mode */
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfigPrivacy
+ *
+ * Description This function is called to enable or disable the privacy in
+ * LE channel of the local device.
+ *
+ * Parameters privacy_mode: privacy mode on or off.
+ *
+ * Returns bool privacy mode set success; otherwise failed.
+ *
+ ******************************************************************************/
+bool BTM_BleConfigPrivacy(bool privacy_mode) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_EVENT("%s", __func__);
+
+ /* if LE is not supported, return error */
+ if (!controller_get_interface()->supports_ble()) return false;
+
+ uint8_t addr_resolution = 0;
+ if (!privacy_mode) /* if privacy disabled, always use public address */
+ {
+ p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_PUBLIC;
+ p_cb->privacy_mode = BTM_PRIVACY_NONE;
+ } else /* privacy is turned on*/
+ {
+ /* always set host random address, used when privacy 1.1 or priavcy 1.2 is
+ * disabled */
+ p_cb->addr_mgnt_cb.own_addr_type = BLE_ADDR_RANDOM;
+ btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
+
+ /* 4.2 controller only allow privacy 1.2 or mixed mode, resolvable private
+ * address in controller */
+ if (controller_get_interface()->supports_ble_privacy()) {
+ addr_resolution = 1;
+ /* check vendor specific capability */
+ p_cb->privacy_mode =
+ btm_cb.ble_ctr_cb.mixed_mode ? BTM_PRIVACY_MIXED : BTM_PRIVACY_1_2;
+ } else /* 4.1/4.0 controller */
+ p_cb->privacy_mode = BTM_PRIVACY_1_1;
+ }
+
+ GAP_BleAttrDBUpdate(GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
+ (tGAP_BLE_ATTR_VALUE*)&addr_resolution);
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleMaxMultiAdvInstanceCount
+ *
+ * Description Returns max number of multi adv instances supported by
+ * controller
+ *
+ * Returns Max multi adv instance count
+ *
+ ******************************************************************************/
+extern uint8_t BTM_BleMaxMultiAdvInstanceCount(void) {
+ return btm_cb.cmn_ble_vsc_cb.adv_inst_max < BTM_BLE_MULTI_ADV_MAX
+ ? btm_cb.cmn_ble_vsc_cb.adv_inst_max
+ : BTM_BLE_MULTI_ADV_MAX;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLocalPrivacyEnabled
+ *
+ * Description Checks if local device supports private address
+ *
+ * Returns Return true if local privacy is enabled else false
+ *
+ ******************************************************************************/
+bool BTM_BleLocalPrivacyEnabled(void) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ return (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE);
+#else
+ return false;
+#endif
+}
+
+/**
+ * Set BLE connectable mode to auto connect
+ */
+void BTM_BleStartAutoConn() {
+ BTM_TRACE_EVENT("%s", __func__);
+ if (!controller_get_interface()->supports_ble()) return;
+
+ if (btm_cb.ble_ctr_cb.bg_conn_type != BTM_BLE_CONN_AUTO) {
+ btm_ble_start_auto_conn(true);
+ btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_AUTO;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleClearBgConnDev
+ *
+ * Description This function is called to clear the whitelist,
+ * end any pending whitelist connections,
+* and reset the local bg device list.
+ *
+ * Parameters void
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleClearBgConnDev(void) {
+ btm_ble_start_auto_conn(false);
+ btm_ble_clear_white_list();
+ gatt_reset_bgdev_list();
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleUpdateBgConnDev
+ *
+ * Description This function is called to add or remove a device into/from
+ * background connection procedure. The background connection
+* procedure is decided by the background connection type, it
+*can be
+* auto connection, or selective connection.
+ *
+ * Parameters add_remove: true to add; false to remove.
+ * remote_bda: device address to add/remove.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool BTM_BleUpdateBgConnDev(bool add_remove, BD_ADDR remote_bda) {
+ BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove);
+ return btm_update_dev_to_white_list(add_remove, remote_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetConnectableMode
+ *
+ * Description This function is called to set BLE connectable mode for a
+ * peripheral device.
+ *
+ * Parameters conn_mode: directed connectable mode, or non-directed. It
+ * can be BTM_BLE_CONNECT_EVT,
+ * BTM_BLE_CONNECT_DIR_EVT or
+ * BTM_BLE_CONNECT_LO_DUTY_DIR_EVT
+ *
+ * Returns BTM_ILLEGAL_VALUE if controller does not support BLE.
+ * BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ BTM_TRACE_EVENT("%s connectable_mode = %d ", __func__, connectable_mode);
+ if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE;
+
+ p_cb->directed_conn = connectable_mode;
+ return btm_ble_set_connectability(p_cb->connectable_mode);
+}
+
+#if (BLE_PRIVACY_SPT == TRUE)
+static bool is_resolving_list_bit_set(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+
+ if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) != 0)
+ return false;
+
+ return true;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function btm_set_conn_mode_adv_init_addr
+ *
+ * Description set initator address type and local address type based on
+ * adv mode.
+ *
+ *
+ ******************************************************************************/
+static uint8_t btm_set_conn_mode_adv_init_addr(
+ tBTM_BLE_INQ_CB* p_cb, BD_ADDR_PTR p_peer_addr_ptr,
+ tBLE_ADDR_TYPE* p_peer_addr_type, tBLE_ADDR_TYPE* p_own_addr_type) {
+ uint8_t evt_type;
+#if (BLE_PRIVACY_SPT == TRUE)
+ tBTM_SEC_DEV_REC* p_dev_rec;
+#endif
+
+ evt_type =
+ (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE)
+ ? ((p_cb->scan_rsp) ? BTM_BLE_DISCOVER_EVT : BTM_BLE_NON_CONNECT_EVT)
+ : BTM_BLE_CONNECT_EVT;
+
+ if (evt_type == BTM_BLE_CONNECT_EVT) {
+ evt_type = p_cb->directed_conn;
+
+ if (p_cb->directed_conn == BTM_BLE_CONNECT_DIR_EVT ||
+ p_cb->directed_conn == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* for privacy 1.2, convert peer address as static, own address set as ID
+ * addr */
+ if (btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 ||
+ btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) {
+ /* only do so for bonded device */
+ if ((p_dev_rec = btm_find_or_alloc_dev(p_cb->direct_bda.bda)) != NULL &&
+ p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
+ btm_ble_enable_resolving_list(BTM_BLE_RL_ADV);
+ memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+ *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+ return evt_type;
+ }
+ /* otherwise fall though as normal directed adv */
+ else {
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+ }
+ }
+#endif
+ /* direct adv mode does not have privacy, if privacy is not enabled */
+ *p_peer_addr_type = p_cb->direct_bda.type;
+ memcpy(p_peer_addr_ptr, p_cb->direct_bda.bda, BD_ADDR_LEN);
+ return evt_type;
+ }
+ }
+
+/* undirect adv mode or non-connectable mode*/
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* when privacy 1.2 privacy only mode is used, or mixed mode */
+ if ((btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_1_2 &&
+ p_cb->afp != AP_SCAN_CONN_ALL) ||
+ btm_cb.ble_ctr_cb.privacy_mode == BTM_PRIVACY_MIXED) {
+ list_node_t* n =
+ list_foreach(btm_cb.sec_dev_rec, is_resolving_list_bit_set, NULL);
+ if (n) {
+ /* if enhanced privacy is required, set Identity address and matching IRK
+ * peer */
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
+ memcpy(p_peer_addr_ptr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
+ *p_peer_addr_type = p_dev_rec->ble.static_addr_type;
+
+ *p_own_addr_type = BLE_ADDR_RANDOM_ID;
+ } else {
+ /* resolving list is empty, not enabled */
+ *p_own_addr_type = BLE_ADDR_RANDOM;
+ }
+ }
+ /* privacy 1.1, or privacy 1.2, general discoverable/connectable mode, disable
+ privacy in */
+ /* controller fall back to host based privacy */
+ else if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
+ *p_own_addr_type = BLE_ADDR_RANDOM;
+ }
+#endif
+
+ /* if no privacy,do not set any peer address,*/
+ /* local address type go by global privacy setting */
+ return evt_type;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetAdvParams
+ *
+ * Description This function is called to set advertising parameters.
+ *
+ * Parameters adv_int_min: minimum advertising interval
+ * adv_int_max: maximum advertising interval
+ * p_dir_bda: connectable direct initiator's LE device address
+ * chnl_map: advertising channel map.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min, uint16_t adv_int_max,
+ tBLE_BD_ADDR* p_dir_bda,
+ tBTM_BLE_ADV_CHNL_MAP chnl_map) {
+ tBTM_LE_RANDOM_CB* p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
+ uint8_t adv_mode = p_cb->adv_mode;
+
+ BTM_TRACE_EVENT("BTM_BleSetAdvParams");
+
+ if (!controller_get_interface()->supports_ble()) return BTM_ILLEGAL_VALUE;
+
+ if (!BTM_BLE_ISVALID_PARAM(adv_int_min, BTM_BLE_ADV_INT_MIN,
+ BTM_BLE_ADV_INT_MAX) ||
+ !BTM_BLE_ISVALID_PARAM(adv_int_max, BTM_BLE_ADV_INT_MIN,
+ BTM_BLE_ADV_INT_MAX)) {
+ return BTM_ILLEGAL_VALUE;
+ }
+
+ p_cb->adv_interval_min = adv_int_min;
+ p_cb->adv_interval_max = adv_int_max;
+ p_cb->adv_chnl_map = chnl_map;
+
+ if (p_dir_bda) {
+ memcpy(&p_cb->direct_bda, p_dir_bda, sizeof(tBLE_BD_ADDR));
+ }
+
+ BTM_TRACE_EVENT("update params for an active adv");
+
+ btm_ble_stop_adv();
+
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(
+ p_cb, p_addr_ptr, &init_addr_type, &own_addr_type);
+
+ /* update adv params */
+ btsnd_hcic_ble_write_adv_params(
+ p_cb->adv_interval_min, p_cb->adv_interval_max, p_cb->evt_type,
+ own_addr_type, init_addr_type, p_addr_ptr, p_cb->adv_chnl_map, p_cb->afp);
+
+ if (adv_mode == BTM_BLE_ADV_ENABLE) btm_ble_start_adv();
+
+ return status;
+}
+
+/**
+ * This function is called to set scan parameters. |cb| is called with operation
+ * status
+ **/
+void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window,
+ tBLE_SCAN_MODE scan_mode,
+ base::Callback<void(uint8_t)> cb) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ uint32_t max_scan_interval;
+ uint32_t max_scan_window;
+
+ BTM_TRACE_EVENT("%s", __func__);
+ if (!controller_get_interface()->supports_ble()) return;
+
+ /* If not supporting extended scan support, use the older range for checking
+ */
+ if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
+ max_scan_interval = BTM_BLE_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_SCAN_WIN_MAX;
+ } else {
+ /* If supporting extended scan support, use the new extended range for
+ * checking */
+ max_scan_interval = BTM_BLE_EXT_SCAN_INT_MAX;
+ max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX;
+ }
+
+ if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN,
+ max_scan_interval) &&
+ BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN,
+ max_scan_window) &&
+ (scan_mode == BTM_BLE_SCAN_MODE_ACTI ||
+ scan_mode == BTM_BLE_SCAN_MODE_PASS)) {
+ p_cb->scan_type = scan_mode;
+ p_cb->scan_interval = scan_interval;
+ p_cb->scan_window = scan_window;
+
+ cb.Run(BTM_SUCCESS);
+ } else {
+ cb.Run(BTM_ILLEGAL_VALUE);
+
+ BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d",
+ scan_interval, scan_window);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleWriteScanRsp
+ *
+ * Description This function is called to write LE scan response.
+ *
+ * Parameters: p_scan_rsp: scan response information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleWriteScanRsp(uint8_t* data, uint8_t length,
+ tBTM_BLE_ADV_DATA_CMPL_CBACK* p_adv_data_cback) {
+ BTM_TRACE_EVENT("%s: length: %d", __func__, length);
+ if (!controller_get_interface()->supports_ble()) {
+ p_adv_data_cback(BTM_ILLEGAL_VALUE);
+ return;
+ }
+
+ btsnd_hcic_ble_set_scan_rsp_data(length, data);
+
+ if (length != 0)
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = true;
+ else
+ btm_cb.ble_ctr_cb.inq_var.scan_rsp = false;
+
+ p_adv_data_cback(BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadDiscoverability
+ *
+ * Description This function is called to read the current LE
+ * discoverability mode of the device.
+ *
+ * Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or
+ * BTM_BLE_GENRAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadDiscoverability() {
+ BTM_TRACE_API("%s", __func__);
+
+ return (btm_cb.ble_ctr_cb.inq_var.discoverable_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadConnectability
+ *
+ * Description This function is called to read the current LE
+ * connectability mode of the device.
+ *
+ * Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadConnectability() {
+ BTM_TRACE_API("%s", __func__);
+
+ return (btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_select_adv_interval
+ *
+ * Description select adv interval based on device mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_select_adv_interval(tBTM_BLE_INQ_CB* p_cb, uint8_t evt_type,
+ uint16_t* p_adv_int_min,
+ uint16_t* p_adv_int_max) {
+ if (p_cb->adv_interval_min && p_cb->adv_interval_max) {
+ *p_adv_int_min = p_cb->adv_interval_min;
+ *p_adv_int_max = p_cb->adv_interval_max;
+ } else {
+ switch (evt_type) {
+ case BTM_BLE_CONNECT_EVT:
+ case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_1;
+ break;
+
+ case BTM_BLE_NON_CONNECT_EVT:
+ case BTM_BLE_DISCOVER_EVT:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_FAST_INT_2;
+ break;
+
+ /* connectable directed event */
+ case BTM_BLE_CONNECT_DIR_EVT:
+ *p_adv_int_min = BTM_BLE_GAP_ADV_DIR_MIN_INT;
+ *p_adv_int_max = BTM_BLE_GAP_ADV_DIR_MAX_INT;
+ break;
+
+ default:
+ *p_adv_int_min = *p_adv_int_max = BTM_BLE_GAP_ADV_SLOW_INT;
+ break;
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_dmt_flag_bits
+ *
+ * Description Obtain updated adv flag value based on connect and
+ * discoverability mode. Also, setup DMT support value in the
+ * flag based on whether the controller supports both LE and
+ * BR/EDR.
+ *
+ * Parameters: flag_value (Input / Output) - flag value
+ * connect_mode (Input) - Connect mode value
+ * disc_mode (Input) - discoverability mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value,
+ const uint16_t connect_mode,
+ const uint16_t disc_mode) {
+ /* BR/EDR non-discoverable , non-connectable */
+ if ((disc_mode & BTM_DISCOVERABLE_MASK) == 0 &&
+ (connect_mode & BTM_CONNECTABLE_MASK) == 0)
+ *adv_flag_value |= BTM_BLE_BREDR_NOT_SPT;
+ else
+ *adv_flag_value &= ~BTM_BLE_BREDR_NOT_SPT;
+
+ /* if local controller support, mark both controller and host support in flag
+ */
+ if (controller_get_interface()->supports_simultaneous_le_bredr())
+ *adv_flag_value |= (BTM_BLE_DMT_CONTROLLER_SPT | BTM_BLE_DMT_HOST_SPT);
+ else
+ *adv_flag_value &= ~(BTM_BLE_DMT_CONTROLLER_SPT | BTM_BLE_DMT_HOST_SPT);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_adv_flag
+ *
+ * Description Set adv flag in adv data.
+ *
+ * Parameters: connect_mode (Input)- Connect mode value
+ * disc_mode (Input) - discoverability mode
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode) {
+ uint8_t flag = 0, old_flag = 0;
+ tBTM_BLE_LOCAL_ADV_DATA* p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+
+ if (p_adv_data->p_flags != NULL) flag = old_flag = *(p_adv_data->p_flags);
+
+ btm_ble_update_dmt_flag_bits(&flag, connect_mode, disc_mode);
+
+ LOG_DEBUG(LOG_TAG, "disc_mode %04x", disc_mode);
+ /* update discoverable flag */
+ if (disc_mode & BTM_BLE_LIMITED_DISCOVERABLE) {
+ flag &= ~BTM_BLE_GEN_DISC_FLAG;
+ flag |= BTM_BLE_LIMIT_DISC_FLAG;
+ } else if (disc_mode & BTM_BLE_GENERAL_DISCOVERABLE) {
+ flag |= BTM_BLE_GEN_DISC_FLAG;
+ flag &= ~BTM_BLE_LIMIT_DISC_FLAG;
+ } else /* remove all discoverable flags */
+ {
+ flag &= ~(BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_GEN_DISC_FLAG);
+ }
+
+ if (flag != old_flag) {
+ btm_ble_update_adv_flag(flag);
+ }
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_set_discoverability
+ *
+ * Description This function is called to set BLE discoverable mode.
+ *
+ * Parameters: combined_mode: discoverability mode.
+ *
+ * Returns BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode) {
+ tBTM_LE_RANDOM_CB* p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ uint16_t mode = (combined_mode & BTM_BLE_DISCOVERABLE_MASK);
+ uint8_t new_mode = BTM_BLE_ADV_ENABLE;
+ uint8_t evt_type;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC,
+ own_addr_type = p_addr_cb->own_addr_type;
+ uint16_t adv_int_min, adv_int_max;
+
+ BTM_TRACE_EVENT("%s mode=0x%0x combined_mode=0x%x", __func__, mode,
+ combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_DISCOVERABLE) return (BTM_ILLEGAL_VALUE);
+
+ p_cb->discoverable_mode = mode;
+
+ evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &init_addr_type,
+ &own_addr_type);
+
+ if (p_cb->connectable_mode == BTM_BLE_NON_CONNECTABLE &&
+ mode == BTM_BLE_NON_DISCOVERABLE)
+ new_mode = BTM_BLE_ADV_DISABLE;
+
+ btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+ alarm_cancel(p_cb->fast_adv_timer);
+
+ /* update adv params if start advertising */
+ BTM_TRACE_EVENT("evt_type=0x%x p-cb->evt_type=0x%x ", evt_type,
+ p_cb->evt_type);
+
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode, combined_mode);
+
+ if (evt_type != p_cb->evt_type || p_cb->adv_addr_type != own_addr_type ||
+ !p_cb->fast_adv_on) {
+ btm_ble_stop_adv();
+
+ /* update adv params */
+ btsnd_hcic_ble_write_adv_params(adv_int_min, adv_int_max, evt_type,
+ own_addr_type, init_addr_type, p_addr_ptr,
+ p_cb->adv_chnl_map, p_cb->afp);
+ p_cb->evt_type = evt_type;
+ p_cb->adv_addr_type = own_addr_type;
+ }
+ }
+
+ if (status == BTM_SUCCESS && p_cb->adv_mode != new_mode) {
+ if (new_mode == BTM_BLE_ADV_ENABLE)
+ status = btm_ble_start_adv();
+ else
+ status = btm_ble_stop_adv();
+ }
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ p_cb->fast_adv_on = true;
+ /* start initial GAP mode adv timer */
+ alarm_set_on_queue(p_cb->fast_adv_timer, BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS,
+ btm_ble_fast_adv_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ } else {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+ }
+
+ /* set up stop advertising timer */
+ if (status == BTM_SUCCESS && mode == BTM_BLE_LIMITED_DISCOVERABLE) {
+ BTM_TRACE_EVENT("start timer for limited disc mode duration=%d ms",
+ BTM_BLE_GAP_LIM_TIMEOUT_MS);
+ /* start Tgap(lim_timeout) */
+ alarm_set_on_queue(p_cb->inquiry_timer, BTM_BLE_GAP_LIM_TIMEOUT_MS,
+ btm_ble_inquiry_timer_gap_limited_discovery_timeout,
+ NULL, btu_general_alarm_queue);
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_connectability
+ *
+ * Description This function is called to set BLE connectability mode.
+ *
+ * Parameters: combined_mode: connectability mode.
+ *
+ * Returns BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode) {
+ tBTM_LE_RANDOM_CB* p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+ uint16_t mode = (combined_mode & BTM_BLE_CONNECTABLE_MASK);
+ uint8_t new_mode = BTM_BLE_ADV_ENABLE;
+ uint8_t evt_type;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE peer_addr_type = BLE_ADDR_PUBLIC,
+ own_addr_type = p_addr_cb->own_addr_type;
+ uint16_t adv_int_min, adv_int_max;
+
+ BTM_TRACE_EVENT("%s mode=0x%0x combined_mode=0x%x", __func__, mode,
+ combined_mode);
+
+ /*** Check mode parameter ***/
+ if (mode > BTM_BLE_MAX_CONNECTABLE) return (BTM_ILLEGAL_VALUE);
+
+ p_cb->connectable_mode = mode;
+
+ evt_type = btm_set_conn_mode_adv_init_addr(p_cb, p_addr_ptr, &peer_addr_type,
+ &own_addr_type);
+
+ if (mode == BTM_BLE_NON_CONNECTABLE &&
+ p_cb->discoverable_mode == BTM_BLE_NON_DISCOVERABLE)
+ new_mode = BTM_BLE_ADV_DISABLE;
+
+ btm_ble_select_adv_interval(p_cb, evt_type, &adv_int_min, &adv_int_max);
+
+ alarm_cancel(p_cb->fast_adv_timer);
+ /* update adv params if needed */
+ if (new_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_set_adv_flag(combined_mode, btm_cb.btm_inq_vars.discoverable_mode);
+ if (p_cb->evt_type != evt_type ||
+ p_cb->adv_addr_type != p_addr_cb->own_addr_type || !p_cb->fast_adv_on) {
+ btm_ble_stop_adv();
+
+ btsnd_hcic_ble_write_adv_params(adv_int_min, adv_int_max, evt_type,
+ own_addr_type, peer_addr_type, p_addr_ptr,
+ p_cb->adv_chnl_map, p_cb->afp);
+ p_cb->evt_type = evt_type;
+ p_cb->adv_addr_type = own_addr_type;
+ }
+ }
+
+ /* update advertising mode */
+ if (status == BTM_SUCCESS && new_mode != p_cb->adv_mode) {
+ if (new_mode == BTM_BLE_ADV_ENABLE)
+ status = btm_ble_start_adv();
+ else
+ status = btm_ble_stop_adv();
+ }
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ p_cb->fast_adv_on = true;
+ /* start initial GAP mode adv timer */
+ alarm_set_on_queue(p_cb->fast_adv_timer, BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS,
+ btm_ble_fast_adv_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ } else {
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+ }
+ return status;
+}
+
+void btm_send_hci_scan_enable(uint8_t enable, uint8_t filter_duplicates) {
+ if (controller_get_interface()->supports_ble_extended_advertising()) {
+ btsnd_hcic_ble_set_extended_scan_enable(enable, filter_duplicates, 0x0000,
+ 0x0000);
+ } else {
+ btsnd_hcic_ble_set_scan_enable(enable, filter_duplicates);
+ }
+}
+
+void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int,
+ uint16_t scan_win, uint8_t addr_type_own,
+ uint8_t scan_filter_policy) {
+ if (controller_get_interface()->supports_ble_extended_advertising()) {
+ scanning_phy_cfg phy_cfg;
+ phy_cfg.scan_type = scan_type;
+ phy_cfg.scan_int = scan_int;
+ phy_cfg.scan_win = scan_win;
+
+ btsnd_hcic_ble_set_extended_scan_params(addr_type_own, scan_filter_policy,
+ 1, &phy_cfg);
+ } else {
+ btsnd_hcic_ble_set_scan_params(scan_type, scan_int, scan_win, addr_type_own,
+ scan_filter_policy);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_inquiry
+ *
+ * Description This function is called to start BLE inquiry procedure.
+ * If the duration is zero, the periodic inquiry mode is
+ * cancelled.
+ *
+ * Parameters: mode - GENERAL or LIMITED inquiry
+ * p_inq_params - pointer to the BLE inquiry parameter.
+ * p_results_cb - callback returning pointer to results
+ * (tBTM_INQ_RESULTS)
+ * p_cmpl_cb - callback indicating the end of an inquiry
+ *
+ *
+ *
+ * Returns BTM_CMD_STARTED if successfully started
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_BUSY - if an inquiry is already active
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_start_inquiry(uint8_t mode, uint8_t duration) {
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_DEBUG("btm_ble_start_inquiry: mode = %02x inq_active = 0x%02x",
+ mode, btm_cb.btm_inq_vars.inq_active);
+
+ /* if selective connection is active, or inquiry is already active, reject it
+ */
+ if (BTM_BLE_IS_INQ_ACTIVE(p_ble_cb->scan_activity)) {
+ BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry");
+ return (BTM_BUSY);
+ }
+
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ /** M: record correct scan type @{ */
+ p_ble_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_ACTI;
+ /** @} */
+ btm_send_hci_set_scan_params(
+ BTM_BLE_SCAN_MODE_ACTI, BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, SP_ADV_ALL);
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* enable IRK list */
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
+#endif
+ p_ble_cb->inq_var.scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
+ status = btm_ble_start_scan();
+ } else if ((p_ble_cb->inq_var.scan_interval !=
+ BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+ (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
+ BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params",
+ __func__);
+ btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ btm_send_hci_set_scan_params(
+ BTM_BLE_SCAN_MODE_ACTI, BTM_BLE_LOW_LATENCY_SCAN_INT,
+ BTM_BLE_LOW_LATENCY_SCAN_WIN,
+ btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, SP_ADV_ALL);
+ btm_send_hci_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
+ }
+
+ if (status == BTM_CMD_STARTED) {
+ p_inq->inq_active |= mode;
+ p_ble_cb->scan_activity |= mode;
+
+ BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x",
+ p_inq->inq_active);
+
+ if (duration != 0) {
+ /* start inquiry timer */
+ period_ms_t duration_ms = duration * 1000;
+ alarm_set_on_queue(p_ble_cb->inq_var.inquiry_timer, duration_ms,
+ btm_ble_inquiry_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_remote_name_cmpl
+ *
+ * Description This function is called when BLE remote name is received.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_read_remote_name_cmpl(bool status, BD_ADDR bda, uint16_t length,
+ char* p_name) {
+ uint8_t hci_status = HCI_SUCCESS;
+ BD_NAME bd_name;
+
+ memset(bd_name, 0, (BD_NAME_LEN + 1));
+ if (length > BD_NAME_LEN) {
+ length = BD_NAME_LEN;
+ }
+ memcpy((uint8_t*)bd_name, p_name, length);
+
+ if ((!status) || (length == 0)) {
+ hci_status = HCI_ERR_HOST_TIMEOUT;
+ }
+
+ btm_process_remote_name(bda, bd_name, length + 1, hci_status);
+ btm_sec_rmt_name_request_complete(bda, (uint8_t*)p_name, hci_status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_remote_name
+ *
+ * Description This function read remote LE device name using GATT read
+ * procedure.
+ *
+ * Parameters: None.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ if (!controller_get_interface()->supports_ble()) return BTM_ERR_PROCESSING;
+
+ tINQ_DB_ENT* p_i = btm_inq_db_find(remote_bda);
+ if (p_i && !ble_evt_type_is_connectable(p_i->inq_info.results.ble_evt_type)) {
+ BTM_TRACE_DEBUG("name request to non-connectable device failed.");
+ return BTM_ERR_PROCESSING;
+ }
+
+ /* read remote device name using GATT procedure */
+ if (p_inq->remname_active) return BTM_BUSY;
+
+ if (!GAP_BleReadPeerDevName(remote_bda, btm_ble_read_remote_name_cmpl))
+ return BTM_BUSY;
+
+ p_inq->p_remname_cmpl_cb = p_cb;
+ p_inq->remname_active = true;
+
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+ alarm_set_on_queue(p_inq->remote_name_timer, BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS,
+ btm_inq_remote_name_timer_timeout, NULL,
+ btu_general_alarm_queue);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_cancel_remote_name
+ *
+ * Description This function cancel read remote LE device name.
+ *
+ * Parameters: None.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool btm_ble_cancel_remote_name(BD_ADDR remote_bda) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ bool status;
+
+ status = GAP_BleCancelReadPeerDevName(remote_bda);
+
+ p_inq->remname_active = false;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+ alarm_cancel(p_inq->remote_name_timer);
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_adv_flag
+ *
+ * Description This function update the limited discoverable flag in the
+ * adv data.
+ *
+ * Parameters: None.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_update_adv_flag(uint8_t flag) {
+ tBTM_BLE_LOCAL_ADV_DATA* p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
+ uint8_t* p;
+
+ BTM_TRACE_DEBUG("btm_ble_update_adv_flag new=0x%x", flag);
+
+ if (p_adv_data->p_flags != NULL) {
+ BTM_TRACE_DEBUG("btm_ble_update_adv_flag old=0x%x", *p_adv_data->p_flags);
+ *p_adv_data->p_flags = flag;
+ } else /* no FLAGS in ADV data*/
+ {
+ p = (p_adv_data->p_pad == NULL) ? p_adv_data->ad_data : p_adv_data->p_pad;
+ /* need 3 bytes space to stuff in the flags, if not */
+ /* erase all written data, just for flags */
+ if ((BTM_BLE_AD_DATA_LEN - (p - p_adv_data->ad_data)) < 3) {
+ p = p_adv_data->p_pad = p_adv_data->ad_data;
+ memset(p_adv_data->ad_data, 0, BTM_BLE_AD_DATA_LEN);
+ }
+
+ *p++ = 2;
+ *p++ = BTM_BLE_AD_TYPE_FLAG;
+ p_adv_data->p_flags = p;
+ *p++ = flag;
+ p_adv_data->p_pad = p;
+ }
+
+ btsnd_hcic_ble_set_adv_data(
+ (uint8_t)(p_adv_data->p_pad - p_adv_data->ad_data), p_adv_data->ad_data);
+ p_adv_data->data_mask |= BTM_BLE_AD_BIT_FLAGS;
+}
+
+/**
+ * Check ADV flag to make sure device is discoverable and match the search
+ * condition
+ */
+uint8_t btm_ble_is_discoverable(BD_ADDR bda,
+ std::vector<uint8_t> const& adv_data) {
+ uint8_t flag = 0, rt = 0;
+ uint8_t data_len;
+ tBTM_INQ_PARMS* p_cond = &btm_cb.btm_inq_vars.inqparms;
+
+ /* for observer, always "discoverable */
+ if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity))
+ rt |= BTM_BLE_OBS_RESULT;
+
+ /* does not match filter condition */
+ if (p_cond->filter_cond_type == BTM_FILTER_COND_BD_ADDR &&
+ memcmp(bda, p_cond->filter_cond.bdaddr_cond, BD_ADDR_LEN) != 0) {
+ BTM_TRACE_DEBUG("BD ADDR does not meet filter condition");
+ return rt;
+ }
+
+ if (!adv_data.empty()) {
+ const uint8_t* p_flag = AdvertiseDataParser::GetFieldByType(
+ adv_data, BTM_BLE_AD_TYPE_FLAG, &data_len);
+ if (p_flag != NULL) {
+ flag = *p_flag;
+
+ if ((btm_cb.btm_inq_vars.inq_active & BTM_BLE_GENERAL_INQUIRY) &&
+ (flag & (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_GEN_DISC_FLAG)) != 0) {
+ BTM_TRACE_DEBUG("Find Generable Discoverable device");
+ rt |= BTM_BLE_INQ_RESULT;
+ }
+
+ else if (btm_cb.btm_inq_vars.inq_active & BTM_BLE_LIMITED_INQUIRY &&
+ (flag & BTM_BLE_LIMIT_DISC_FLAG) != 0) {
+ BTM_TRACE_DEBUG("Find limited discoverable device");
+ rt |= BTM_BLE_INQ_RESULT;
+ }
+ }
+ }
+ return rt;
+}
+
+static void btm_ble_appearance_to_cod(uint16_t appearance, uint8_t* dev_class) {
+ dev_class[0] = 0;
+
+ switch (appearance) {
+ case BTM_BLE_APPEARANCE_GENERIC_PHONE:
+ dev_class[1] = BTM_COD_MAJOR_PHONE;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_COMPUTER:
+ dev_class[1] = BTM_COD_MAJOR_COMPUTER;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_REMOTE:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_REMOTE_CONTROL;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_THERMOMETER:
+ case BTM_BLE_APPEARANCE_THERMOMETER_EAR:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_THERMOMETER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_HEART_RATE:
+ case BTM_BLE_APPEARANCE_HEART_RATE_BELT:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_HEART_PULSE_MONITOR;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE:
+ case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM:
+ case BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_BLOOD_MONITOR;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER:
+ case BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP:
+ case BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_PULSE_OXIMETER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_GLUCOSE:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_GLUCOSE_METER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WEIGHT:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_WEIGHING_SCALE;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WALKING:
+ case BTM_BLE_APPEARANCE_WALKING_IN_SHOE:
+ case BTM_BLE_APPEARANCE_WALKING_ON_SHOE:
+ case BTM_BLE_APPEARANCE_WALKING_ON_HIP:
+ dev_class[1] = BTM_COD_MAJOR_HEALTH;
+ dev_class[2] = BTM_COD_MINOR_STEP_COUNTER;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_WATCH:
+ case BTM_BLE_APPEARANCE_SPORTS_WATCH:
+ dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+ dev_class[2] = BTM_COD_MINOR_WRIST_WATCH;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES:
+ dev_class[1] = BTM_COD_MAJOR_WEARABLE;
+ dev_class[2] = BTM_COD_MINOR_GLASSES;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_DISPLAY:
+ dev_class[1] = BTM_COD_MAJOR_IMAGING;
+ dev_class[2] = BTM_COD_MINOR_DISPLAY;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER:
+ dev_class[1] = BTM_COD_MAJOR_AUDIO;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER:
+ case BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER:
+ case BTM_BLE_APPEARANCE_GENERIC_HID:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ break;
+ case BTM_BLE_APPEARANCE_HID_KEYBOARD:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_KEYBOARD;
+ break;
+ case BTM_BLE_APPEARANCE_HID_MOUSE:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_POINTING;
+ break;
+ case BTM_BLE_APPEARANCE_HID_JOYSTICK:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_JOYSTICK;
+ break;
+ case BTM_BLE_APPEARANCE_HID_GAMEPAD:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_GAMEPAD;
+ break;
+ case BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_DIGITIZING_TABLET;
+ break;
+ case BTM_BLE_APPEARANCE_HID_CARD_READER:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_CARD_READER;
+ break;
+ case BTM_BLE_APPEARANCE_HID_DIGITAL_PEN:
+ dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ dev_class[2] = BTM_COD_MINOR_DIGITAL_PAN;
+ break;
+ case BTM_BLE_APPEARANCE_UKNOWN:
+ case BTM_BLE_APPEARANCE_GENERIC_CLOCK:
+ case BTM_BLE_APPEARANCE_GENERIC_TAG:
+ case BTM_BLE_APPEARANCE_GENERIC_KEYRING:
+ case BTM_BLE_APPEARANCE_GENERIC_CYCLING:
+ case BTM_BLE_APPEARANCE_CYCLING_COMPUTER:
+ case BTM_BLE_APPEARANCE_CYCLING_SPEED:
+ case BTM_BLE_APPEARANCE_CYCLING_CADENCE:
+ case BTM_BLE_APPEARANCE_CYCLING_POWER:
+ case BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE:
+ case BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD:
+ case BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV:
+ default:
+ dev_class[1] = BTM_COD_MAJOR_UNCLASSIFIED;
+ dev_class[2] = BTM_COD_MINOR_UNCLASSIFIED;
+ };
+}
+
+/**
+ * Update adv packet information into inquiry result.
+ */
+void btm_ble_update_inq_result(tINQ_DB_ENT* p_i, uint8_t addr_type, BD_ADDR bda,
+ uint16_t evt_type, uint8_t primary_phy,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ int8_t tx_power, int8_t rssi,
+ uint16_t periodic_adv_int,
+ std::vector<uint8_t> const& data) {
+ tBTM_INQ_RESULTS* p_cur = &p_i->inq_info.results;
+ uint8_t len;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ /* Save the info */
+ p_cur->inq_result_type = BTM_INQ_RESULT_BLE;
+ p_cur->ble_addr_type = addr_type;
+ p_cur->rssi = rssi;
+ p_cur->ble_primary_phy = primary_phy;
+ p_cur->ble_secondary_phy = secondary_phy;
+ p_cur->ble_advertising_sid = advertising_sid;
+ p_cur->ble_tx_power = tx_power;
+ p_cur->ble_periodic_adv_int = periodic_adv_int;
+
+ if (btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI &&
+ ble_evt_type_is_scannable(evt_type) &&
+ !ble_evt_type_is_scan_resp(evt_type)) {
+ p_i->scan_rsp = false;
+ } else
+ p_i->scan_rsp = true;
+
+ if (p_i->inq_count != p_inq->inq_counter)
+ p_cur->device_type = BT_DEVICE_TYPE_BLE;
+ else
+ p_cur->device_type |= BT_DEVICE_TYPE_BLE;
+
+ if (evt_type != BTM_BLE_SCAN_RSP_EVT) p_cur->ble_evt_type = evt_type;
+
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+ if (!data.empty()) {
+ const uint8_t* p_flag =
+ AdvertiseDataParser::GetFieldByType(data, BTM_BLE_AD_TYPE_FLAG, &len);
+ if (p_flag != NULL) p_cur->flag = *p_flag;
+ }
+
+ if (!data.empty()) {
+ /* Check to see the BLE device has the Appearance UUID in the advertising
+ * data. If it does
+ * then try to convert the appearance value to a class of device value
+ * Bluedroid can use.
+ * Otherwise fall back to trying to infer if it is a HID device based on the
+ * service class.
+ */
+ const uint8_t* p_uuid16 = AdvertiseDataParser::GetFieldByType(
+ data, BTM_BLE_AD_TYPE_APPEARANCE, &len);
+ if (p_uuid16 && len == 2) {
+ btm_ble_appearance_to_cod((uint16_t)p_uuid16[0] | (p_uuid16[1] << 8),
+ p_cur->dev_class);
+ } else {
+ p_uuid16 = AdvertiseDataParser::GetFieldByType(
+ data, BTM_BLE_AD_TYPE_16SRV_CMPL, &len);
+ if (p_uuid16 != NULL) {
+ uint8_t i;
+ for (i = 0; i + 2 <= len; i = i + 2) {
+ /* if this BLE device support HID over LE, set HID Major in class of
+ * device */
+ if ((p_uuid16[i] | (p_uuid16[i + 1] << 8)) == UUID_SERVCLASS_LE_HID) {
+ p_cur->dev_class[0] = 0;
+ p_cur->dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
+ p_cur->dev_class[2] = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* if BR/EDR not supported is not set, assume is a DUMO device */
+ if ((p_cur->flag & BTM_BLE_BREDR_NOT_SPT) == 0 &&
+ !ble_evt_type_is_directed(evt_type)) {
+ if (p_cur->ble_addr_type != BLE_ADDR_RANDOM) {
+ BTM_TRACE_DEBUG("BR/EDR NOT support bit not set, treat as DUMO");
+ p_cur->device_type |= BT_DEVICE_TYPE_DUMO;
+ } else {
+ BTM_TRACE_DEBUG("Random address, treating device as LE only");
+ }
+ } else {
+ BTM_TRACE_DEBUG("BR/EDR NOT SUPPORT bit set, LE only device");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_clear_all_pending_le_entry
+ *
+ * Description This function is called to clear all LE pending entry in
+ * inquiry database.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_clear_all_pending_le_entry(void) {
+ uint16_t xx;
+ tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ /* mark all pending LE entry as unused if an LE only device has scan
+ * response outstanding */
+ if ((p_ent->in_use) &&
+ (p_ent->inq_info.results.device_type == BT_DEVICE_TYPE_BLE) &&
+ !p_ent->scan_rsp)
+ p_ent->in_use = false;
+ }
+}
+
+void btm_ble_process_adv_addr(BD_ADDR bda, uint8_t addr_type) {
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* map address to security record */
+ bool match = btm_identity_addr_to_random_pseudo(bda, &addr_type, false);
+
+ BTM_TRACE_DEBUG("%s: bda= %0x:%0x:%0x:%0x:%0x:%0x", __func__, bda[0], bda[1],
+ bda[2], bda[3], bda[4], bda[5]);
+ /* always do RRA resolution on host */
+ if (!match && BTM_BLE_IS_RESOLVE_BDA(bda)) {
+ tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda);
+ if (match_rec) {
+ match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
+ memcpy(match_rec->ble.cur_rand_addr, bda, BD_ADDR_LEN);
+
+ if (btm_ble_init_pseudo_addr(match_rec, bda)) {
+ memcpy(bda, match_rec->bd_addr, BD_ADDR_LEN);
+ } else {
+ // Assign the original address to be the current report address
+ memcpy(bda, match_rec->ble.pseudo_addr, BD_ADDR_LEN);
+ }
+ }
+ }
+#endif
+}
+
+/**
+ * This function is called when extended advertising report event is received .
+ * It updates the inquiry database. If the inquiry database is full, the oldest
+ * entry is discarded.
+ */
+void btm_ble_process_ext_adv_pkt(uint8_t data_len, uint8_t* data) {
+ BD_ADDR bda, direct_address;
+ uint8_t* p = data;
+ uint8_t addr_type, num_reports, pkt_data_len, primary_phy, secondary_phy,
+ advertising_sid;
+ int8_t rssi, tx_power;
+ uint16_t event_type, periodic_adv_int, direct_address_type;
+
+ /* Only process the results if the inquiry is still active */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) return;
+
+ /* Extract the number of reports in this event. */
+ STREAM_TO_UINT8(num_reports, p);
+
+ while (num_reports--) {
+ if (p > data + data_len) {
+ // TODO(jpawlowski): we should crash the stack here
+ BTM_TRACE_ERROR(
+ "Malformed LE Extended Advertising Report Event from controller - "
+ "can't loop the data");
+ return;
+ }
+
+ /* Extract inquiry results */
+ STREAM_TO_UINT16(event_type, p);
+ STREAM_TO_UINT8(addr_type, p);
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_UINT8(primary_phy, p);
+ STREAM_TO_UINT8(secondary_phy, p);
+ STREAM_TO_UINT8(advertising_sid, p);
+ STREAM_TO_INT8(tx_power, p);
+ STREAM_TO_INT8(rssi, p);
+ STREAM_TO_UINT16(periodic_adv_int, p);
+ STREAM_TO_UINT8(direct_address_type, p);
+ STREAM_TO_BDADDR(direct_address, p);
+ STREAM_TO_UINT8(pkt_data_len, p);
+
+ uint8_t* pkt_data = p;
+ p += pkt_data_len; /* Advance to the the next packet*/
+
+ if (rssi >= 21 && rssi <= 126) {
+ BTM_TRACE_ERROR("%s: bad rssi value in advertising report: ", __func__,
+ pkt_data_len, rssi);
+ }
+
+ btm_ble_process_adv_addr(bda, addr_type);
+ btm_ble_process_adv_pkt_cont(event_type, addr_type, bda, primary_phy,
+ secondary_phy, advertising_sid, tx_power, rssi,
+ periodic_adv_int, pkt_data_len, pkt_data);
+ }
+}
+
+/**
+ * This function is called when advertising report event is received. It updates
+ * the inquiry database. If the inquiry database is full, the oldest entry is
+ * discarded.
+ */
+void btm_ble_process_adv_pkt(uint8_t data_len, uint8_t* data) {
+ BD_ADDR bda;
+ uint8_t* p = data;
+ uint8_t legacy_evt_type, addr_type, num_reports, pkt_data_len;
+ int8_t rssi;
+
+ /* Only process the results if the inquiry is still active */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) return;
+
+ /* Extract the number of reports in this event. */
+ STREAM_TO_UINT8(num_reports, p);
+
+ while (num_reports--) {
+ if (p > data + data_len) {
+ // TODO(jpawlowski): we should crash the stack here
+ BTM_TRACE_ERROR("Malformed LE Advertising Report Event from controller");
+ return;
+ }
+
+ /* Extract inquiry results */
+ STREAM_TO_UINT8(legacy_evt_type, p);
+ STREAM_TO_UINT8(addr_type, p);
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_UINT8(pkt_data_len, p);
+
+ uint8_t* pkt_data = p;
+ p += pkt_data_len; /* Advance to the the rssi byte */
+
+ STREAM_TO_INT8(rssi, p);
+
+ if (rssi >= 21 && rssi <= 126) {
+ BTM_TRACE_ERROR("%s: bad rssi value in advertising report: ", __func__,
+ pkt_data_len, rssi);
+ }
+
+ btm_ble_process_adv_addr(bda, addr_type);
+
+ uint16_t event_type;
+ if (legacy_evt_type == 0x00) { // ADV_IND;
+ event_type = 0x0013;
+ } else if (legacy_evt_type == 0x01) { // ADV_DIRECT_IND;
+ event_type = 0x0015;
+ } else if (legacy_evt_type == 0x02) { // ADV_SCAN_IND;
+ event_type = 0x0012;
+ } else if (legacy_evt_type == 0x03) { // ADV_NONCONN_IND;
+ event_type = 0x0010;
+ } else if (legacy_evt_type == 0x04) { // SCAN_RSP;
+ // We can't distinguish between "SCAN_RSP to an ADV_IND", and "SCAN_RSP to
+ // an ADV_SCAN_IND", so always return "SCAN_RSP to an ADV_IND"
+ event_type = 0x001B;
+ } else {
+ BTM_TRACE_ERROR(
+ "Malformed LE Advertising Report Event - unsupported "
+ "legacy_event_type 0x%02x",
+ legacy_evt_type);
+ return;
+ }
+
+ btm_ble_process_adv_pkt_cont(
+ event_type, addr_type, bda, PHY_LE_1M, PHY_LE_NO_PACKET, NO_ADI_PRESENT,
+ TX_POWER_NOT_PRESENT, rssi, 0x00 /* no periodic adv */, pkt_data_len,
+ pkt_data);
+ }
+}
+
+/**
+ * This function is called after random address resolution is done, and proceed
+ * to process adv packet.
+ */
+static void btm_ble_process_adv_pkt_cont(
+ uint16_t evt_type, uint8_t addr_type, BD_ADDR bda, uint8_t primary_phy,
+ uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power,
+ int8_t rssi, uint16_t periodic_adv_int, uint8_t data_len, uint8_t* data) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ bool update = true;
+
+ std::vector<uint8_t> tmp;
+ if (data_len != 0) tmp.insert(tmp.begin(), data, data + data_len);
+
+ bool is_scannable = ble_evt_type_is_scannable(evt_type);
+ bool is_scan_resp = ble_evt_type_is_scan_resp(evt_type);
+
+ // We might have send scan request to this device before, but didn't get the
+ // response. In such case make sure data is put at start, not appended to
+ // already existing data.
+ bool is_start =
+ ble_evt_type_is_legacy(evt_type) && is_scannable && !is_scan_resp;
+ std::vector<uint8_t> const& adv_data =
+ is_start ? cache.Set(addr_type, bda, std::move(tmp))
+ : cache.Append(addr_type, bda, std::move(tmp));
+
+ bool data_complete = (ble_evt_type_data_status(evt_type) != 0x01);
+
+ if (!data_complete) {
+ // If we didn't receive whole adv data yet, don't report the device.
+ DVLOG(1) << "Data not complete yet, waiting for more "
+ << base::HexEncode(bda, BD_ADDR_LEN);
+ return;
+ }
+
+ bool is_active_scan =
+ btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI;
+ if (is_active_scan && is_scannable && !is_scan_resp) {
+ // If we didn't receive scan response yet, don't report the device.
+ DVLOG(1) << " Waiting for scan response "
+ << base::HexEncode(bda, BD_ADDR_LEN);
+ return;
+ }
+
+ if (!AdvertiseDataParser::IsValid(adv_data)) {
+ DVLOG(1) << __func__ << "Dropping bad advertisement packet: "
+ << base::HexEncode(adv_data.data(), adv_data.size());
+ return;
+ }
+
+ tINQ_DB_ENT* p_i = btm_inq_db_find(bda);
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda)) {
+ /* never been report as an LE device */
+ if (p_i && (!(p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) ||
+ /* scan repsonse to be updated */
+ (!p_i->scan_rsp))) {
+ update = true;
+ } else if (BTM_BLE_IS_OBS_ACTIVE(btm_cb.ble_ctr_cb.scan_activity)) {
+ update = false;
+ } else {
+ /* if yes, skip it */
+ return; /* assumption: one result per event */
+ }
+ }
+ /* If existing entry, use that, else get a new one (possibly reusing the
+ * oldest) */
+ if (p_i == NULL) {
+ p_i = btm_inq_db_new(bda);
+ if (p_i != NULL) {
+ p_inq->inq_cmpl_info.num_resp++;
+ } else
+ return;
+ } else if (p_i->inq_count !=
+ p_inq->inq_counter) /* first time seen in this inquiry */
+ {
+ p_inq->inq_cmpl_info.num_resp++;
+ }
+
+ /* update the LE device information in inquiry database */
+ btm_ble_update_inq_result(p_i, addr_type, bda, evt_type, primary_phy,
+ secondary_phy, advertising_sid, tx_power, rssi,
+ periodic_adv_int, adv_data);
+
+ uint8_t result = btm_ble_is_discoverable(bda, adv_data);
+ if (result == 0) {
+ cache.Clear(addr_type, bda);
+ LOG_WARN(LOG_TAG,
+ "%s device no longer discoverable, discarding advertising packet",
+ __func__);
+ return;
+ }
+
+ if (!update) result &= ~BTM_BLE_INQ_RESULT;
+ /* If the number of responses found and limited, issue a cancel inquiry */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps) {
+ /* new device */
+ if (p_i == NULL ||
+ /* assume a DUMO device, BR/EDR inquiry is always active */
+ (p_i &&
+ (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) ==
+ BT_DEVICE_TYPE_BLE &&
+ p_i->scan_rsp)) {
+ BTM_TRACE_WARNING(
+ "INQ RES: Extra Response Received...cancelling inquiry..");
+
+ /* if is non-periodic inquiry active, cancel now */
+ if ((p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK) != 0 &&
+ (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) == 0)
+ btsnd_hcic_inq_cancel();
+
+ btm_ble_stop_inquiry();
+
+ btm_acl_update_busy_level(BTM_BLI_INQ_DONE_EVT);
+ }
+ }
+
+ tBTM_INQ_RESULTS_CB* p_inq_results_cb = p_inq->p_inq_results_cb;
+ if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
+ (p_inq_results_cb)((tBTM_INQ_RESULTS*)&p_i->inq_info.results,
+ const_cast<uint8_t*>(adv_data.data()), adv_data.size());
+ }
+
+ tBTM_INQ_RESULTS_CB* p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
+ if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
+ (p_obs_results_cb)((tBTM_INQ_RESULTS*)&p_i->inq_info.results,
+ const_cast<uint8_t*>(adv_data.data()), adv_data.size());
+ }
+
+ cache.Clear(addr_type, bda);
+}
+
+void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* data) {
+ uint8_t status, tx_phy, rx_phy;
+ uint16_t handle;
+
+ LOG_ASSERT(len == 5);
+ uint8_t* p = data;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ handle = handle & 0x0FFF;
+ STREAM_TO_UINT8(tx_phy, p);
+ STREAM_TO_UINT8(rx_phy, p);
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ if (!p_dev_rec) {
+ BTM_TRACE_WARNING("%s: No Device Found!", __func__);
+ return;
+ }
+
+ tGATT_TCB* p_tcb =
+ gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+ if (p_tcb == NULL) return;
+
+ gatt_notify_phy_updated(p_tcb, tx_phy, rx_phy, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_scan
+ *
+ * Description Start the BLE scan.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_start_scan(void) {
+ tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
+ /* start scan, disable duplicate filtering */
+ btm_send_hci_scan_enable(BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter);
+
+ if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI)
+ btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
+ else
+ btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_stop_scan
+ *
+ * Description Stop the BLE scan.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_stop_scan(void) {
+ BTM_TRACE_EVENT("btm_ble_stop_scan ");
+
+ if (btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI)
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
+ else
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
+
+ /* Clear the inquiry callback if set */
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+
+ /* stop discovery now */
+ btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+
+ btm_update_scanner_filter_policy(SP_ADV_ALL);
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_stop_inquiry
+ *
+ * Description Stop the BLE Inquiry.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_stop_inquiry(void) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ alarm_cancel(p_ble_cb->inq_var.inquiry_timer);
+
+ p_ble_cb->scan_activity &= ~BTM_BLE_INQUIRY_MASK;
+
+ /* If no more scan activity, stop LE scan now */
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity))
+ btm_ble_stop_scan();
+ else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
+ (p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
+ BTM_TRACE_DEBUG("%s: setting default params for ongoing observe", __func__);
+ btm_ble_stop_scan();
+ btm_ble_start_scan();
+ }
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status, p_inq->inq_cmpl_info.num_resp);
+
+ btm_process_inq_complete(
+ HCI_SUCCESS, (uint8_t)(p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK));
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_stop_observe
+ *
+ * Description Stop the BLE Observe.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_stop_observe(void) {
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+ tBTM_CMPL_CB* p_obs_cb = p_ble_cb->p_obs_cmpl_cb;
+
+ alarm_cancel(p_ble_cb->observer_timer);
+
+ p_ble_cb->scan_activity &= ~BTM_LE_OBSERVE_ACTIVE;
+
+ p_ble_cb->p_obs_results_cb = NULL;
+ p_ble_cb->p_obs_cmpl_cb = NULL;
+
+ if (!BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) btm_ble_stop_scan();
+
+ if (p_obs_cb)
+ (p_obs_cb)((tBTM_INQUIRY_CMPL*)&btm_cb.btm_inq_vars.inq_cmpl_info);
+}
+/*******************************************************************************
+ *
+ * Function btm_ble_adv_states_operation
+ *
+ * Description Set or clear adv states in topology mask
+ *
+ * Returns operation status. true if sucessful, false otherwise.
+ *
+ ******************************************************************************/
+typedef bool(BTM_TOPOLOGY_FUNC_PTR)(tBTM_BLE_STATE_MASK);
+static bool btm_ble_adv_states_operation(BTM_TOPOLOGY_FUNC_PTR* p_handler,
+ uint8_t adv_evt) {
+ bool rt = false;
+
+ switch (adv_evt) {
+ case BTM_BLE_CONNECT_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_CONN_ADV_BIT);
+ break;
+
+ case BTM_BLE_NON_CONNECT_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_NON_CONN_ADV_BIT);
+ break;
+ case BTM_BLE_CONNECT_DIR_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT);
+ break;
+
+ case BTM_BLE_DISCOVER_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_SCAN_ADV_BIT);
+ break;
+
+ case BTM_BLE_CONNECT_LO_DUTY_DIR_EVT:
+ rt = (*p_handler)(BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT);
+ break;
+
+ default:
+ BTM_TRACE_ERROR("unknown adv event : %d", adv_evt);
+ break;
+ }
+
+ return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_adv
+ *
+ * Description start the BLE advertising.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_start_adv(void) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (!btm_ble_adv_states_operation(btm_ble_topology_check, p_cb->evt_type))
+ return BTM_WRONG_MODE;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* To relax resolving list, always have resolving list enabled, unless
+ * directed adv */
+ if (p_cb->evt_type != BTM_BLE_CONNECT_LO_DUTY_DIR_EVT &&
+ p_cb->evt_type != BTM_BLE_CONNECT_DIR_EVT)
+ /* enable resolving list is desired */
+ btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_ADV);
+#endif
+
+ btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_ENABLE);
+ p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
+ btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type);
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_stop_adv
+ *
+ * Description Stop the BLE advertising.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_stop_adv(void) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ btsnd_hcic_ble_set_adv_enable(BTM_BLE_ADV_DISABLE);
+
+ p_cb->fast_adv_on = false;
+ p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
+
+ /* clear all adv states */
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
+ }
+ return BTM_SUCCESS;
+}
+
+static void btm_ble_fast_adv_timer_timeout(UNUSED_ATTR void* data) {
+ /* fast adv is completed, fall back to slow adv interval */
+ btm_ble_start_slow_adv();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_start_slow_adv
+ *
+ * Description Restart adv with slow adv interval
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_ble_start_slow_adv(void) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
+ tBTM_LE_RANDOM_CB* p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+ BD_ADDR p_addr_ptr = {0};
+ tBLE_ADDR_TYPE init_addr_type = BLE_ADDR_PUBLIC;
+ tBLE_ADDR_TYPE own_addr_type = p_addr_cb->own_addr_type;
+
+ btm_ble_stop_adv();
+
+ p_cb->evt_type = btm_set_conn_mode_adv_init_addr(
+ p_cb, p_addr_ptr, &init_addr_type, &own_addr_type);
+
+ /* slow adv mode never goes into directed adv */
+ btsnd_hcic_ble_write_adv_params(BTM_BLE_GAP_ADV_SLOW_INT,
+ BTM_BLE_GAP_ADV_SLOW_INT, p_cb->evt_type,
+ own_addr_type, init_addr_type, p_addr_ptr,
+ p_cb->adv_chnl_map, p_cb->afp);
+
+ btm_ble_start_adv();
+ }
+}
+
+static void btm_ble_inquiry_timer_gap_limited_discovery_timeout(
+ UNUSED_ATTR void* data) {
+ /* lim_timeout expired, limited discovery should exit now */
+ btm_cb.btm_inq_vars.discoverable_mode &= ~BTM_BLE_LIMITED_DISCOVERABLE;
+ btm_ble_set_adv_flag(btm_cb.btm_inq_vars.connectable_mode,
+ btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+static void btm_ble_inquiry_timer_timeout(UNUSED_ATTR void* data) {
+ btm_ble_stop_inquiry();
+}
+
+static void btm_ble_observer_timer_timeout(UNUSED_ATTR void* data) {
+ btm_ble_stop_observe();
+}
+
+void btm_ble_refresh_raddr_timer_timeout(UNUSED_ATTR void* data) {
+ if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type == BLE_ADDR_RANDOM) {
+ /* refresh the random addr */
+ btm_gen_resolvable_private_addr(base::Bind(&btm_gen_resolve_paddr_low));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_remote_features_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the read LE remote feature
+ * supported complete event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_read_remote_features_complete(uint8_t* p) {
+ BTM_TRACE_EVENT("%s", __func__);
+
+ uint16_t handle;
+ uint8_t status;
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ handle = handle & 0x0FFF; // only 12 bits meaningful
+
+ if (status != HCI_SUCCESS) {
+ BTM_TRACE_ERROR("%s: failed for handle: 0x%04d, status 0x%02x", __func__,
+ handle, status);
+ if (status != HCI_ERR_UNSUPPORTED_REM_FEATURE) return;
+ }
+
+ int idx = btm_handle_to_acl_index(handle);
+ if (idx == MAX_L2CAP_LINKS) {
+ BTM_TRACE_ERROR("%s: can't find acl for handle: 0x%04d", __func__, handle);
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ STREAM_TO_ARRAY(btm_cb.acl_db[idx].peer_le_features, p, BD_FEATURES_LEN);
+ }
+
+ btsnd_hcic_rmt_ver_req(handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_write_adv_enable_complete
+ *
+ * Description This function process the write adv enable command complete.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_write_adv_enable_complete(uint8_t* p) {
+ tBTM_BLE_INQ_CB* p_cb = &btm_cb.ble_ctr_cb.inq_var;
+
+ /* if write adv enable/disbale not succeed */
+ if (*p != HCI_SUCCESS) {
+ /* toggle back the adv mode */
+ p_cb->adv_mode = !p_cb->adv_mode;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_dir_adv_tout
+ *
+ * Description when directed adv time out
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_dir_adv_tout(void) {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_set_topology_mask
+ *
+ * Description set BLE topology mask
+ *
+ * Returns true is request is allowed, false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {
+ request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+ btm_cb.ble_ctr_cb.cur_states |= (request_state_mask & BTM_BLE_STATE_ALL_MASK);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_topology_mask
+ *
+ * Description Clear BLE topology bit mask
+ *
+ * Returns true is request is allowed, false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state_mask) {
+ request_state_mask &= BTM_BLE_STATE_ALL_MASK;
+ btm_cb.ble_ctr_cb.cur_states &= ~request_state_mask;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_link_topology_mask
+ *
+ * Description This function update the link topology mask
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_update_link_topology_mask(uint8_t link_role, bool increase) {
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_CONN_MASK);
+
+ if (increase)
+ btm_cb.ble_ctr_cb.link_count[link_role]++;
+ else if (btm_cb.ble_ctr_cb.link_count[link_role] > 0)
+ btm_cb.ble_ctr_cb.link_count[link_role]--;
+
+ if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_MASTER])
+ btm_ble_set_topology_mask(BTM_BLE_STATE_MASTER_BIT);
+
+ if (btm_cb.ble_ctr_cb.link_count[HCI_ROLE_SLAVE])
+ btm_ble_set_topology_mask(BTM_BLE_STATE_SLAVE_BIT);
+
+ if (link_role == HCI_ROLE_SLAVE && increase) {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+ /* clear all adv states */
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_mode_operation
+ *
+ * Description This function update the GAP role operation when a link
+ * status is updated.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bd_addr,
+ uint8_t status) {
+ if (status == HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT) {
+ btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ /* make device fall back into undirected adv mode by default */
+ btm_cb.ble_ctr_cb.inq_var.directed_conn = BTM_BLE_CONNECT_EVT;
+ /* clear all adv states */
+ btm_ble_clear_topology_mask(BTM_BLE_STATE_ALL_ADV_MASK);
+ }
+
+ if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) {
+ btm_ble_set_connectability(btm_cb.btm_inq_vars.connectable_mode |
+ btm_cb.ble_ctr_cb.inq_var.connectable_mode);
+ }
+
+ /* in case of disconnected, we must cancel bgconn and restart
+ in order to add back device to white list in order to reconnect */
+ btm_ble_bgconn_cancel_if_disconnected(bd_addr);
+
+ /* when no connection is attempted, and controller is not rejecting last
+ request
+ due to resource limitation, start next direct connection or background
+ connection
+ now in order */
+ if (btm_ble_get_conn_st() == BLE_CONN_IDLE &&
+ status != HCI_ERR_HOST_REJECT_RESOURCES &&
+ status != HCI_ERR_MAX_NUM_OF_CONNECTIONS &&
+ !btm_send_pending_direct_conn()) {
+ btm_ble_resume_bg_conn();
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_init
+ *
+ * Description Initialize the control block variable values.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_init(void) {
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ alarm_free(p_cb->observer_timer);
+ alarm_free(p_cb->inq_var.fast_adv_timer);
+ memset(p_cb, 0, sizeof(tBTM_BLE_CB));
+ memset(&(btm_cb.cmn_ble_vsc_cb), 0, sizeof(tBTM_BLE_VSC_CB));
+ btm_cb.cmn_ble_vsc_cb.values_read = false;
+
+ p_cb->observer_timer = alarm_new("btm_ble.observer_timer");
+ p_cb->cur_states = 0;
+ p_cb->conn_pending_q = fixed_queue_new(SIZE_MAX);
+
+ p_cb->inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
+ p_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ p_cb->inq_var.adv_chnl_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
+ p_cb->inq_var.afp = BTM_BLE_DEFAULT_AFP;
+ p_cb->inq_var.sfp = BTM_BLE_DEFAULT_SFP;
+ p_cb->inq_var.connectable_mode = BTM_BLE_NON_CONNECTABLE;
+ p_cb->inq_var.discoverable_mode = BTM_BLE_NON_DISCOVERABLE;
+ p_cb->inq_var.fast_adv_timer = alarm_new("btm_ble_inq.fast_adv_timer");
+ p_cb->inq_var.inquiry_timer = alarm_new("btm_ble_inq.inquiry_timer");
+
+ /* for background connection, reset connection params to be undefined */
+ p_cb->scan_int = p_cb->scan_win = BTM_BLE_SCAN_PARAM_UNDEF;
+
+ p_cb->inq_var.evt_type = BTM_BLE_NON_CONNECT_EVT;
+
+ p_cb->addr_mgnt_cb.refresh_raddr_timer =
+ alarm_new("btm_ble_addr.refresh_raddr_timer");
+
+#if (BLE_VND_INCLUDED == FALSE)
+ btm_ble_adv_filter_init();
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_topology_check
+ *
+ * Description check to see requested state is supported. One state check
+ * at a time is supported
+ *
+ * Returns true is request is allowed, false otherwise.
+ *
+ ******************************************************************************/
+bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request_state_mask) {
+ bool rt = false;
+
+ uint8_t state_offset = 0;
+ uint16_t cur_states = btm_cb.ble_ctr_cb.cur_states;
+ uint8_t mask, offset;
+ uint8_t request_state = 0;
+
+ /* check only one bit is set and within valid range */
+ if (request_state_mask == BTM_BLE_STATE_INVALID ||
+ request_state_mask > BTM_BLE_STATE_SCAN_ADV_BIT ||
+ (request_state_mask & (request_state_mask - 1)) != 0) {
+ BTM_TRACE_ERROR("illegal state requested: %d", request_state_mask);
+ return rt;
+ }
+
+ while (request_state_mask) {
+ request_state_mask >>= 1;
+ request_state++;
+ }
+
+ /* check if the requested state is supported or not */
+ mask = btm_le_state_combo_tbl[0][request_state - 1][0];
+ offset = btm_le_state_combo_tbl[0][request_state - 1][1];
+
+ const uint8_t* ble_supported_states =
+ controller_get_interface()->get_ble_supported_states();
+
+ if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) {
+ BTM_TRACE_ERROR("state requested not supported: %d", request_state);
+ return rt;
+ }
+
+ rt = true;
+ /* make sure currently active states are all supported in conjunction with the
+ requested
+ state. If the bit in table is not set, the combination is not supported */
+ while (cur_states != 0) {
+ if (cur_states & 0x01) {
+ mask = btm_le_state_combo_tbl[request_state][state_offset][0];
+ offset = btm_le_state_combo_tbl[request_state][state_offset][1];
+
+ if (mask != 0 && offset != 0) {
+ if (!BTM_LE_STATES_SUPPORTED(ble_supported_states, mask, offset)) {
+ rt = false;
+ break;
+ }
+ }
+ }
+ cur_states >>= 1;
+ state_offset++;
+ }
+ return rt;
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_int.h b/mtkbt/code/bt/stack/btm/btm_ble_int.h
new file mode 100755
index 0000000..f7da237
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_int.h
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main Bluetooth Manager (BTM) internal
+ * definitions.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_INT_H
+#define BTM_BLE_INT_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_ble_api.h"
+#include "btm_ble_int_types.h"
+#include "btm_int.h"
+#include "btm_int_types.h"
+#include "hcidefs.h"
+#include "smp_api.h"
+
+extern bool ble_evt_type_is_connectable(uint16_t evt_type);
+extern void btm_ble_refresh_raddr_timer_timeout(void* data);
+extern void btm_ble_process_adv_pkt(uint8_t len, uint8_t* p);
+extern void btm_ble_process_phy_update_pkt(uint8_t len, uint8_t* p);
+extern void btm_ble_process_ext_adv_pkt(uint8_t len, uint8_t* p);
+extern void btm_ble_proc_scan_rsp_rpt(uint8_t* p);
+extern tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda,
+ tBTM_CMPL_CB* p_cb);
+extern bool btm_ble_cancel_remote_name(BD_ADDR remote_bda);
+
+extern tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode);
+extern tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode);
+extern void btm_send_hci_scan_enable(uint8_t enable, uint8_t filter_duplicates);
+extern void btm_send_hci_set_scan_params(uint8_t scan_type, uint16_t scan_int,
+ uint16_t scan_win,
+ uint8_t addr_type_own,
+ uint8_t scan_filter_policy);
+extern tBTM_STATUS btm_ble_start_inquiry(uint8_t mode, uint8_t duration);
+extern void btm_ble_stop_scan(void);
+extern void btm_clear_all_pending_le_entry(void);
+
+extern void btm_ble_stop_scan();
+extern void btm_ble_stop_inquiry(void);
+extern void btm_ble_init(void);
+extern void btm_ble_connected(uint8_t* bda, uint16_t handle, uint8_t enc_mode,
+ uint8_t role, tBLE_ADDR_TYPE addr_type,
+ bool addr_matched);
+extern void btm_ble_read_remote_features_complete(uint8_t* p);
+extern void btm_ble_write_adv_enable_complete(uint8_t* p);
+extern void btm_ble_conn_complete(uint8_t* p, uint16_t evt_len, bool enhanced);
+extern void btm_read_ble_local_supported_states_complete(uint8_t* p,
+ uint16_t evt_len);
+extern tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
+extern void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
+extern tBTM_STATUS btm_ble_start_adv(void);
+extern tBTM_STATUS btm_ble_stop_adv(void);
+extern void btm_le_on_advertising_set_terminated(uint8_t* p, uint16_t length);
+extern tBTM_STATUS btm_ble_start_scan(void);
+extern void btm_ble_create_ll_conn_complete(uint8_t status);
+
+/* LE security function from btm_sec.cc */
+extern void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req,
+ tBTM_BLE_SEC_REQ_ACT* p_sec_req_act);
+extern void btm_ble_ltk_request_reply(BD_ADDR bda, bool use_stk,
+ BT_OCTET16 stk);
+extern uint8_t btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr,
+ tSMP_EVT_DATA* p_data);
+extern tBTM_STATUS btm_ble_set_encryption(BD_ADDR bd_addr,
+ tBTM_BLE_SEC_ACT sec_act,
+ uint8_t link_role);
+extern void btm_ble_ltk_request(uint16_t handle, uint8_t rand[8],
+ uint16_t ediv);
+extern tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, bool use_stk,
+ BT_OCTET16 stk);
+extern void btm_ble_link_encrypted(BD_ADDR bd_addr, uint8_t encr_enable);
+
+/* LE device management functions */
+extern void btm_ble_reset_id(void);
+
+/* security related functions */
+extern void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, bool is_local);
+extern bool btm_get_local_div(BD_ADDR bd_addr, uint16_t* p_div);
+extern bool btm_ble_get_enc_key_type(BD_ADDR bd_addr, uint8_t* p_key_types);
+
+extern void btm_ble_test_command_complete(uint8_t* p);
+extern void btm_ble_rand_enc_complete(uint8_t* p, uint16_t op_code,
+ tBTM_RAND_ENC_CB* p_enc_cplt_cback);
+
+extern void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type,
+ tBTM_LE_KEY_VALUE* p_keys,
+ bool pass_to_application);
+extern void btm_ble_update_sec_key_size(BD_ADDR bd_addr, uint8_t enc_key_size);
+extern uint8_t btm_ble_read_sec_key_size(BD_ADDR bd_addr);
+
+/* white list function */
+extern bool btm_update_dev_to_white_list(bool to_add, BD_ADDR bd_addr);
+extern void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
+extern void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
+extern void btm_ble_clear_white_list(void);
+extern void btm_read_white_list_size_complete(uint8_t* p, uint16_t evt_len);
+extern void btm_ble_add_2_white_list_complete(uint8_t status);
+extern void btm_ble_remove_from_white_list_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_clear_white_list_complete(uint8_t* p, uint16_t evt_len);
+extern void btm_ble_white_list_init(uint8_t white_list_size);
+
+/* background connection function */
+extern bool btm_ble_suspend_bg_conn(void);
+extern bool btm_ble_resume_bg_conn(void);
+extern void btm_send_hci_create_connection(
+ uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
+ uint8_t addr_type_peer, BD_ADDR bda_peer, uint8_t addr_type_own,
+ uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
+ uint8_t phy);
+extern bool btm_ble_start_auto_conn(bool start);
+extern bool btm_ble_start_select_conn(bool start);
+extern bool btm_ble_renew_bg_conn_params(bool add, BD_ADDR bd_addr);
+extern void btm_write_dir_conn_wl(BD_ADDR target_addr);
+extern void btm_ble_update_mode_operation(uint8_t link_role, BD_ADDR bda,
+ uint8_t status);
+extern bool btm_execute_wl_dev_operation(void);
+extern void btm_ble_update_link_topology_mask(uint8_t role, bool increase);
+extern void btm_ble_bgconn_cancel_if_disconnected(BD_ADDR bd_addr);
+
+/* direct connection utility */
+extern bool btm_send_pending_direct_conn(void);
+extern void btm_ble_enqueue_direct_conn_req(void* p_param);
+extern void btm_ble_dequeue_direct_conn_req(BD_ADDR rem_bda);
+
+/* BLE address management */
+extern void btm_gen_resolvable_private_addr(base::Callback<void(BT_OCTET8)> cb);
+extern void btm_gen_non_resolvable_private_addr(tBTM_BLE_ADDR_CBACK* p_cback,
+ void* p);
+extern tBTM_SEC_DEV_REC* btm_ble_resolve_random_addr(BD_ADDR random_bda);
+extern void btm_gen_resolve_paddr_low(BT_OCTET8 rand);
+
+/* privacy function */
+#if (BLE_PRIVACY_SPT == TRUE)
+/* BLE address mapping with CS feature */
+extern bool btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr,
+ uint8_t* p_addr_type,
+ bool refresh);
+extern bool btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo,
+ uint8_t* p_static_addr_type);
+extern void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda,
+ BD_ADDR rra,
+ uint8_t rra_type);
+extern void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr,
+ BD_ADDR local_rpa);
+extern void btm_ble_read_resolving_list_entry_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_remove_resolving_list_entry_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_add_resolving_list_entry_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len);
+extern void btm_read_ble_resolving_list_size_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_enable_resolving_list(uint8_t);
+extern bool btm_ble_disable_resolving_list(uint8_t rl_mask, bool to_resume);
+extern void btm_ble_enable_resolving_list_for_platform(uint8_t rl_mask);
+extern void btm_ble_resolving_list_init(uint8_t max_irk_list_sz);
+extern void btm_ble_resolving_list_cleanup(void);
+#endif
+
+extern void btm_ble_adv_init(void);
+extern void* btm_ble_multi_adv_get_ref(uint8_t inst_id);
+extern void btm_ble_multi_adv_cleanup(void);
+extern void btm_ble_batchscan_init(void);
+extern void btm_ble_batchscan_cleanup(void);
+extern void btm_ble_adv_filter_init(void);
+extern void btm_ble_adv_filter_cleanup(void);
+extern bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
+extern bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
+extern bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
+extern void btm_ble_set_random_address(BD_ADDR random_bda);
+
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+extern void btm_ble_set_no_disc_if_pair_fail(bool disble_disc);
+extern void btm_ble_set_test_mac_value(bool enable, uint8_t* p_test_mac_val);
+extern void btm_ble_set_test_local_sign_cntr_value(
+ bool enable, uint32_t test_local_sign_cntr);
+extern void btm_ble_set_keep_rfu_in_auth_req(bool keep_rfu);
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_int_types.h b/mtkbt/code/bt/stack/btm/btm_ble_int_types.h
new file mode 100755
index 0000000..68bd54a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_int_types.h
@@ -0,0 +1,330 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_INT_TYPES_H
+#define BTM_BLE_INT_TYPES_H
+
+#include "osi/include/alarm.h"
+
+/* scanning enable status */
+#define BTM_BLE_SCAN_ENABLE 0x01
+#define BTM_BLE_SCAN_DISABLE 0x00
+
+/* advertising enable status */
+#define BTM_BLE_ADV_ENABLE 0x01
+#define BTM_BLE_ADV_DISABLE 0x00
+
+/* use the high 4 bits unused by inquiry mode */
+#define BTM_BLE_SELECT_SCAN 0x20
+#define BTM_BLE_NAME_REQUEST 0x40
+#define BTM_BLE_OBSERVE 0x80
+
+#define BTM_BLE_MAX_WL_ENTRY 1
+#define BTM_BLE_AD_DATA_LEN 31
+
+#define BTM_BLE_ENC_MASK 0x03
+
+#define BTM_BLE_DUPLICATE_ENABLE 1
+#define BTM_BLE_DUPLICATE_DISABLE 0
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+/* Interval(scan_int) = 80 ms(0x0080 * 0.625 ms) */
+#define BTM_BLE_GAP_DISC_SCAN_INT 128
+#else
+/* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_DISC_SCAN_INT 18
+#endif
+/* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
+#define BTM_BLE_GAP_DISC_SCAN_WIN 18
+/* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_INT 512
+/* Tgap(lim_timeout) = 180s max */
+#define BTM_BLE_GAP_LIM_TIMEOUT_MS (180 * 1000)
+/* Interval(scan_int) = 5s= 8000 * 0.625 ms */
+#define BTM_BLE_LOW_LATENCY_SCAN_INT 8000
+/* scan_window = 5s= 8000 * 0.625 ms */
+#define BTM_BLE_LOW_LATENCY_SCAN_WIN 8000
+
+/* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms = 48 *0.625 */
+#define BTM_BLE_GAP_ADV_FAST_INT_1 48
+/* TGAP(adv_fast_interval2) = 100(used) ~ 150 ms = 160 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_FAST_INT_2 160
+/* Tgap(adv_slow_interval) = 1.28 s= 512 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_SLOW_INT 2048
+/* Tgap(dir_conn_adv_int_max) = 500 ms = 800 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MAX_INT 800
+/* Tgap(dir_conn_adv_int_min) = 250 ms = 400 * 0.625 ms */
+#define BTM_BLE_GAP_ADV_DIR_MIN_INT 400
+
+#define BTM_BLE_GAP_FAST_ADV_TIMEOUT_MS (30 * 1000)
+
+#define BTM_BLE_SEC_REQ_ACT_NONE 0
+/* encrypt the link using current key or key refresh */
+#define BTM_BLE_SEC_REQ_ACT_ENCRYPT 1
+#define BTM_BLE_SEC_REQ_ACT_PAIR 2
+/* discard the sec request while encryption is started but not completed */
+#define BTM_BLE_SEC_REQ_ACT_DISCARD 3
+typedef uint8_t tBTM_BLE_SEC_REQ_ACT;
+
+#define BLE_STATIC_PRIVATE_MSB_MASK 0x3f
+/* most significant bit, bit7, bit6 is 01 to be resolvable random */
+#define BLE_RESOLVE_ADDR_MSB 0x40
+/* bit 6, and bit7 */
+#define BLE_RESOLVE_ADDR_MASK 0xc0
+#define BTM_BLE_IS_RESOLVE_BDA(x) \
+ (((x)[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
+
+#define BLE_PUBLIC_ADDR_MSB_MASK 0xC0
+/* most significant bit, bit7, bit6 is 10 to be public address*/
+#define BLE_PUBLIC_ADDR_MSB 0x80
+#define BTM_IS_PUBLIC_BDA(x) \
+ (((x)[0] & BLE_PUBLIC_ADDR_MSB_MASK) == BLE_PUBLIC_ADDR_MSB)
+
+/* LE scan activity bit mask, continue with LE inquiry bits */
+/* observe is in progress */
+#define BTM_LE_OBSERVE_ACTIVE 0x80
+
+/* BLE scan activity mask checking */
+#define BTM_BLE_IS_SCAN_ACTIVE(x) ((x)&BTM_BLE_SCAN_ACTIVE_MASK)
+#define BTM_BLE_IS_INQ_ACTIVE(x) ((x)&BTM_BLE_INQUIRY_MASK)
+#define BTM_BLE_IS_OBS_ACTIVE(x) ((x)&BTM_LE_OBSERVE_ACTIVE)
+
+/* BLE ADDR type ID bit */
+#define BLE_ADDR_TYPE_ID_BIT 0x02
+
+#define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55
+#define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95
+
+typedef struct {
+ uint16_t data_mask;
+ uint8_t* p_flags;
+ uint8_t ad_data[BTM_BLE_AD_DATA_LEN];
+ uint8_t* p_pad;
+} tBTM_BLE_LOCAL_ADV_DATA;
+
+typedef struct {
+ /* Used for determining if a response has already been received for the
+ * current inquiry operation. (We do not want to flood the caller with
+ * multiple responses from the same device. */
+ uint32_t inq_count;
+ bool scan_rsp;
+ tBLE_BD_ADDR le_bda;
+} tINQ_LE_BDADDR;
+
+#define BTM_BLE_ISVALID_PARAM(x, min, max) \
+ (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
+
+/* 15 minutes minimum for random address refreshing */
+#define BTM_BLE_PRIVATE_ADDR_INT_MS (15 * 60 * 1000)
+
+typedef struct {
+ uint16_t discoverable_mode;
+ uint16_t connectable_mode;
+ uint32_t scan_window;
+ uint32_t scan_interval;
+ uint8_t scan_type; /* current scan type: active or passive */
+ uint8_t scan_duplicate_filter; /* duplicate filter enabled for scan */
+ uint16_t adv_interval_min;
+ uint16_t adv_interval_max;
+ tBTM_BLE_AFP afp; /* advertising filter policy */
+ tBTM_BLE_SFP sfp; /* scanning filter policy */
+
+ tBLE_ADDR_TYPE adv_addr_type;
+ uint8_t evt_type;
+ uint8_t adv_mode;
+ tBLE_BD_ADDR direct_bda;
+ tBTM_BLE_EVT directed_conn;
+ bool fast_adv_on;
+ alarm_t* fast_adv_timer;
+
+ /* inquiry BD addr database */
+ uint8_t num_bd_entries;
+ uint8_t max_bd_entries;
+ tBTM_BLE_LOCAL_ADV_DATA adv_data;
+ tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
+
+ alarm_t* inquiry_timer;
+ bool scan_rsp;
+ uint8_t state; /* Current state that the inquiry process is in */
+ int8_t tx_power;
+} tBTM_BLE_INQ_CB;
+
+/* random address resolving complete callback */
+typedef void(tBTM_BLE_RESOLVE_CBACK)(void* match_rec, void* p);
+
+typedef void(tBTM_BLE_ADDR_CBACK)(BD_ADDR_PTR static_random, void* p);
+
+/* random address management control block */
+typedef struct {
+ tBLE_ADDR_TYPE own_addr_type; /* local device LE address type */
+ BD_ADDR private_addr;
+ BD_ADDR random_bda;
+ tBTM_BLE_ADDR_CBACK* p_generate_cback;
+ void* p;
+ alarm_t* refresh_raddr_timer;
+} tBTM_LE_RANDOM_CB;
+
+typedef struct {
+ uint16_t min_conn_int;
+ uint16_t max_conn_int;
+ uint16_t slave_latency;
+ uint16_t supervision_tout;
+
+} tBTM_LE_CONN_PRAMS;
+
+typedef struct {
+ BD_ADDR bd_addr;
+ uint8_t attr;
+ bool is_connected;
+ bool in_use;
+} tBTM_LE_BG_CONN_DEV;
+
+/* white list using state as a bit mask */
+#define BTM_BLE_WL_IDLE 0
+#define BTM_BLE_WL_INIT 1
+typedef uint8_t tBTM_BLE_WL_STATE;
+
+/* resolving list using state as a bit mask */
+#define BTM_BLE_RL_IDLE 0
+#define BTM_BLE_RL_INIT 1
+#define BTM_BLE_RL_SCAN 2
+#define BTM_BLE_RL_ADV 4
+typedef uint8_t tBTM_BLE_RL_STATE;
+
+/* BLE connection state */
+#define BLE_CONN_IDLE 0
+#define BLE_DIR_CONN 1
+#define BLE_BG_CONN 2
+#define BLE_CONN_CANCEL 3
+typedef uint8_t tBTM_BLE_CONN_ST;
+
+typedef struct { void* p_param; } tBTM_BLE_CONN_REQ;
+
+/* LE state request */
+#define BTM_BLE_STATE_INVALID 0
+#define BTM_BLE_STATE_CONN_ADV 1
+#define BTM_BLE_STATE_INIT 2
+#define BTM_BLE_STATE_MASTER 3
+#define BTM_BLE_STATE_SLAVE 4
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV 5
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV 6
+#define BTM_BLE_STATE_NON_CONN_ADV 7
+#define BTM_BLE_STATE_PASSIVE_SCAN 8
+#define BTM_BLE_STATE_ACTIVE_SCAN 9
+#define BTM_BLE_STATE_SCAN_ADV 10
+#define BTM_BLE_STATE_MAX 11
+typedef uint8_t tBTM_BLE_STATE;
+
+#define BTM_BLE_STATE_CONN_ADV_BIT 0x0001
+#define BTM_BLE_STATE_INIT_BIT 0x0002
+#define BTM_BLE_STATE_MASTER_BIT 0x0004
+#define BTM_BLE_STATE_SLAVE_BIT 0x0008
+#define BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT 0x0010
+#define BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT 0x0020
+#define BTM_BLE_STATE_NON_CONN_ADV_BIT 0x0040
+#define BTM_BLE_STATE_PASSIVE_SCAN_BIT 0x0080
+#define BTM_BLE_STATE_ACTIVE_SCAN_BIT 0x0100
+#define BTM_BLE_STATE_SCAN_ADV_BIT 0x0200
+typedef uint16_t tBTM_BLE_STATE_MASK;
+
+#define BTM_BLE_STATE_ALL_MASK 0x03ff
+#define BTM_BLE_STATE_ALL_ADV_MASK \
+ (BTM_BLE_STATE_CONN_ADV_BIT | BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT | \
+ BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT | BTM_BLE_STATE_SCAN_ADV_BIT)
+#define BTM_BLE_STATE_ALL_SCAN_MASK \
+ (BTM_BLE_STATE_PASSIVE_SCAN_BIT | BTM_BLE_STATE_ACTIVE_SCAN_BIT)
+#define BTM_BLE_STATE_ALL_CONN_MASK \
+ (BTM_BLE_STATE_MASTER_BIT | BTM_BLE_STATE_SLAVE_BIT)
+
+#ifndef BTM_LE_RESOLVING_LIST_MAX
+#define BTM_LE_RESOLVING_LIST_MAX 0x20
+#endif
+
+typedef struct {
+ BD_ADDR* resolve_q_random_pseudo;
+ uint8_t* resolve_q_action;
+ uint8_t q_next;
+ uint8_t q_pending;
+} tBTM_BLE_RESOLVE_Q;
+
+typedef struct {
+ bool in_use;
+ bool to_add;
+ BD_ADDR bd_addr;
+ uint8_t attr;
+} tBTM_BLE_WL_OP;
+
+/* BLE privacy mode */
+#define BTM_PRIVACY_NONE 0 /* BLE no privacy */
+#define BTM_PRIVACY_1_1 1 /* BLE privacy 1.1, do not support privacy 1.0 */
+#define BTM_PRIVACY_1_2 2 /* BLE privacy 1.2 */
+#define BTM_PRIVACY_MIXED \
+ 3 /* BLE privacy mixed mode, broadcom propietary mode */
+typedef uint8_t tBTM_PRIVACY_MODE;
+
+/* data length change event callback */
+typedef void(tBTM_DATA_LENGTH_CHANGE_CBACK)(uint16_t max_tx_length,
+ uint16_t max_rx_length);
+
+/* Define BLE Device Management control structure
+*/
+typedef struct {
+ uint8_t scan_activity; /* LE scan activity mask */
+
+ /*****************************************************
+ ** BLE Inquiry
+ *****************************************************/
+ tBTM_BLE_INQ_CB inq_var;
+
+ /* observer callback and timer */
+ tBTM_INQ_RESULTS_CB* p_obs_results_cb;
+ tBTM_CMPL_CB* p_obs_cmpl_cb;
+ alarm_t* observer_timer;
+
+ /* background connection procedure cb value */
+ tBTM_BLE_CONN_TYPE bg_conn_type;
+ uint32_t scan_int;
+ uint32_t scan_win;
+
+ /* white list information */
+ tBTM_BLE_WL_STATE wl_state;
+
+ fixed_queue_t* conn_pending_q;
+ tBTM_BLE_CONN_ST conn_state;
+
+ /* random address management control block */
+ tBTM_LE_RANDOM_CB addr_mgnt_cb;
+
+ bool enabled;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ bool mixed_mode; /* privacy 1.2 mixed mode is on or not */
+ tBTM_PRIVACY_MODE privacy_mode; /* privacy mode */
+ uint8_t resolving_list_avail_size; /* resolving list available size */
+ tBTM_BLE_RESOLVE_Q resolving_list_pend_q; /* Resolving list queue */
+ tBTM_BLE_RL_STATE suspended_rl_state; /* Suspended resolving list state */
+ uint8_t* irk_list_mask; /* IRK list availability mask, up to max entry bits */
+ tBTM_BLE_RL_STATE rl_state; /* Resolving list state */
+#endif
+
+ /* current BLE link state */
+ tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
+ uint8_t link_count[2]; /* total link count master and slave*/
+} tBTM_BLE_CB;
+
+#endif // BTM_BLE_INT_TYPES_H
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_multi_adv.cc b/mtkbt/code/bt/stack/btm/btm_ble_multi_adv.cc
new file mode 100755
index 0000000..ba31c81
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_multi_adv.cc
@@ -0,0 +1,884 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <string.h>
+#include <queue>
+#include <vector>
+
+#include "bt_target.h"
+#include "device/include/controller.h"
+#include "osi/include/alarm.h"
+
+#include "ble_advertiser.h"
+#include "ble_advertiser_hci_interface.h"
+#include "btm_int_types.h"
+
+using base::Bind;
+using RegisterCb =
+ base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>;
+using IdTxPowerStatusCb = base::Callback<void(
+ uint8_t /* inst_id */, int8_t /* tx_power */, uint8_t /* status */)>;
+extern void btm_gen_resolvable_private_addr(
+ base::Callback<void(uint8_t[8])> cb);
+extern fixed_queue_t* btu_general_alarm_queue;
+
+constexpr int ADV_DATA_LEN_MAX = 251;
+
+namespace {
+
+bool is_connectable(uint16_t advertising_event_properties) {
+ return advertising_event_properties & 0x01;
+}
+
+struct AdvertisingInstance {
+ uint8_t inst_id;
+ bool in_use;
+ uint8_t advertising_event_properties;
+ alarm_t* adv_raddr_timer;
+ int8_t tx_power;
+ uint16_t duration;
+ uint8_t maxExtAdvEvents;
+ alarm_t* timeout_timer;
+ uint8_t own_address_type;
+ BD_ADDR own_address;
+ MultiAdvCb timeout_cb;
+ bool address_update_required;
+
+ /* When true, advertising set is enabled, or last scheduled call to "LE Set
+ * Extended Advertising Set Enable" is to enable this advertising set. Any
+ * command scheduled when in this state will execute when the set is enabled,
+ * unless enabling fails.
+ *
+ * When false, advertising set is disabled, or last scheduled call to "LE Set
+ * Extended Advertising Set Enable" is to disable this advertising set. Any
+ * command scheduled when in this state will execute when the set is disabled.
+ */
+ bool enable_status;
+
+ bool IsEnabled() { return enable_status; }
+
+ bool IsConnectable() { return is_connectable(advertising_event_properties); }
+
+ AdvertisingInstance(int inst_id)
+ : inst_id(inst_id),
+ in_use(false),
+ advertising_event_properties(0),
+ tx_power(0),
+ duration(0),
+ timeout_timer(nullptr),
+ own_address_type(0),
+ own_address{0},
+ address_update_required(false),
+ enable_status(false) {
+ adv_raddr_timer = alarm_new_periodic("btm_ble.adv_raddr_timer");
+ }
+
+ ~AdvertisingInstance() {
+ alarm_free(adv_raddr_timer);
+ if (timeout_timer) alarm_free(timeout_timer);
+ }
+};
+
+void btm_ble_adv_raddr_timer_timeout(void* data);
+
+void DoNothing(uint8_t) {}
+void DoNothing2(uint8_t, uint8_t) {}
+
+struct closure_data {
+ base::Closure user_task;
+ tracked_objects::Location posted_from;
+};
+
+static void alarm_closure_cb(void* p) {
+ closure_data* data = (closure_data*)p;
+ VLOG(1) << "executing timer scheduled at %s" << data->posted_from.ToString();
+ data->user_task.Run();
+ delete data;
+}
+
+// Periodic alarms are not supported, because we clean up data in callback
+void alarm_set_closure_on_queue(const tracked_objects::Location& posted_from,
+ alarm_t* alarm, period_ms_t interval_ms,
+ base::Closure user_task, fixed_queue_t* queue) {
+ closure_data* data = new closure_data;
+ data->posted_from = posted_from;
+ data->user_task = std::move(user_task);
+ VLOG(1) << "scheduling timer %s" << data->posted_from.ToString();
+ alarm_set_on_queue(alarm, interval_ms, alarm_closure_cb, data, queue);
+}
+
+class BleAdvertisingManagerImpl;
+
+/* a temporary type for holding all the data needed in callbacks below*/
+struct CreatorParams {
+ uint8_t inst_id;
+ BleAdvertisingManagerImpl* self;
+ IdTxPowerStatusCb cb;
+ tBTM_BLE_ADV_PARAMS params;
+ std::vector<uint8_t> advertise_data;
+ std::vector<uint8_t> scan_response_data;
+ tBLE_PERIODIC_ADV_PARAMS periodic_params;
+ std::vector<uint8_t> periodic_data;
+ uint16_t duration;
+ uint8_t maxExtAdvEvents;
+ RegisterCb timeout_cb;
+};
+
+using c_type = std::unique_ptr<CreatorParams>;
+
+class BleAdvertisingManagerImpl
+ : public BleAdvertisingManager,
+ public BleAdvertiserHciInterface::AdvertisingEventObserver {
+ public:
+ BleAdvertisingManagerImpl(BleAdvertiserHciInterface* interface) {
+ this->hci_interface = interface;
+ hci_interface->ReadInstanceCount(
+ base::Bind(&BleAdvertisingManagerImpl::ReadInstanceCountCb,
+ base::Unretained(this)));
+ }
+
+ ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
+
+ void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) override {
+ bt_bdaddr_t addr;
+ memcpy(addr.address, adv_inst[inst_id].own_address, BD_ADDR_LEN);
+ cb.Run(adv_inst[inst_id].own_address_type, addr);
+ }
+
+ void ReadInstanceCountCb(uint8_t instance_count) {
+ this->inst_count = instance_count;
+ adv_inst.reserve(inst_count);
+ /* Initialize adv instance indices and IDs. */
+ for (uint8_t i = 0; i < inst_count; i++) {
+ adv_inst.emplace_back(i);
+ }
+ }
+
+ void OnRpaGenerationComplete(base::Callback<void(bt_bdaddr_t)> cb,
+ uint8_t rand[8]) {
+ VLOG(1) << __func__;
+
+ bt_bdaddr_t bda;
+
+ rand[2] &= (~BLE_RESOLVE_ADDR_MASK);
+ rand[2] |= BLE_RESOLVE_ADDR_MSB;
+
+ bda.address[2] = rand[0];
+ bda.address[1] = rand[1];
+ bda.address[0] = rand[2];
+
+ BT_OCTET16 irk;
+ BTM_GetDeviceIDRoot(irk);
+ tSMP_ENC output;
+
+ if (!SMP_Encrypt(irk, BT_OCTET16_LEN, rand, 3, &output))
+ LOG_ASSERT(false) << "SMP_Encrypt failed";
+
+ /* set hash to be LSB of rpAddress */
+ bda.address[5] = output.param_buf[0];
+ bda.address[4] = output.param_buf[1];
+ bda.address[3] = output.param_buf[2];
+
+ cb.Run(bda);
+ }
+
+ void GenerateRpa(base::Callback<void(bt_bdaddr_t)> cb) {
+ btm_gen_resolvable_private_addr(
+ Bind(&BleAdvertisingManagerImpl::OnRpaGenerationComplete,
+ base::Unretained(this), std::move(cb)));
+ }
+
+ void ConfigureRpa(AdvertisingInstance* p_inst, MultiAdvCb configuredCb) {
+ /* Connectable advertising set must be disabled when updating RPA */
+ bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
+
+ // If there is any form of timeout on the set, schedule address update when
+ // the set stops, because there is no good way to compute new timeout value.
+ // Maximum duration value is around 10 minutes, so this is safe.
+ if (restart && (p_inst->duration || p_inst->maxExtAdvEvents)) {
+ p_inst->address_update_required = true;
+ configuredCb.Run(0x01);
+ return;
+ }
+
+ GenerateRpa(Bind(
+ [](AdvertisingInstance* p_inst, MultiAdvCb configuredCb,
+ bt_bdaddr_t bda) {
+ /* Connectable advertising set must be disabled when updating RPA */
+ bool restart = p_inst->IsEnabled() && p_inst->IsConnectable();
+
+ auto hci_interface =
+ ((BleAdvertisingManagerImpl*)BleAdvertisingManager::Get())
+ ->GetHciInterface();
+
+ if (restart) {
+ p_inst->enable_status = false;
+ hci_interface->Enable(false, p_inst->inst_id, 0x00, 0x00,
+ Bind(DoNothing));
+ }
+
+ /* set it to controller */
+ hci_interface->SetRandomAddress(
+ p_inst->inst_id, p_inst->own_address,
+ Bind(
+ [](AdvertisingInstance* p_inst, bt_bdaddr_t bda,
+ MultiAdvCb configuredCb, uint8_t status) {
+ memcpy(p_inst->own_address, &bda, BD_ADDR_LEN);
+ configuredCb.Run(0x00);
+ },
+ p_inst, bda, configuredCb));
+
+ if (restart) {
+ p_inst->enable_status = true;
+ hci_interface->Enable(true, p_inst->inst_id, 0x00, 0x00,
+ Bind(DoNothing));
+ }
+ },
+ p_inst, std::move(configuredCb)));
+ }
+
+ void RegisterAdvertiser(
+ base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)> cb)
+ override {
+ AdvertisingInstance* p_inst = &adv_inst[0];
+ for (uint8_t i = 0; i < inst_count; i++, p_inst++) {
+ if (p_inst->in_use) continue;
+
+ p_inst->in_use = true;
+
+ // set up periodic timer to update address.
+ if (BTM_BleLocalPrivacyEnabled()) {
+ p_inst->own_address_type = BLE_ADDR_RANDOM;
+ GenerateRpa(Bind(
+ [](AdvertisingInstance* p_inst,
+ base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>
+ cb,
+ bt_bdaddr_t bda) {
+ memcpy(p_inst->own_address, &bda, BD_ADDR_LEN);
+
+ alarm_set_on_queue(p_inst->adv_raddr_timer,
+ BTM_BLE_PRIVATE_ADDR_INT_MS,
+ btm_ble_adv_raddr_timer_timeout, p_inst,
+ btu_general_alarm_queue);
+ cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS);
+ },
+ p_inst, cb));
+ } else {
+ p_inst->own_address_type = BLE_ADDR_PUBLIC;
+ memcpy(p_inst->own_address,
+ controller_get_interface()->get_address()->address, BD_ADDR_LEN);
+
+ cb.Run(p_inst->inst_id, BTM_BLE_MULTI_ADV_SUCCESS);
+ }
+ return;
+ }
+
+ LOG(INFO) << "no free advertiser instance";
+ cb.Run(0xFF, ADVERTISE_FAILED_TOO_MANY_ADVERTISERS);
+ }
+
+ void StartAdvertising(uint8_t advertiser_id, MultiAdvCb cb,
+ tBTM_BLE_ADV_PARAMS* params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data, int duration,
+ MultiAdvCb timeout_cb) override {
+ /* a temporary type for holding all the data needed in callbacks below*/
+ struct CreatorParams {
+ uint8_t inst_id;
+ BleAdvertisingManagerImpl* self;
+ MultiAdvCb cb;
+ tBTM_BLE_ADV_PARAMS params;
+ std::vector<uint8_t> advertise_data;
+ std::vector<uint8_t> scan_response_data;
+ int duration;
+ MultiAdvCb timeout_cb;
+ };
+
+ std::unique_ptr<CreatorParams> c;
+ c.reset(new CreatorParams());
+
+ c->self = this;
+ c->cb = std::move(cb);
+ c->params = *params;
+ c->advertise_data = std::move(advertise_data);
+ c->scan_response_data = std::move(scan_response_data);
+ c->duration = duration;
+ c->timeout_cb = std::move(timeout_cb);
+ c->inst_id = advertiser_id;
+
+ using c_type = std::unique_ptr<CreatorParams>;
+
+ // this code is intentionally left formatted this way to highlight the
+ // asynchronous flow
+ // clang-format off
+ c->self->SetParameters(c->inst_id, &c->params, Bind(
+ [](c_type c, uint8_t status, int8_t tx_power) {
+ if (status != 0) {
+ LOG(ERROR) << "setting parameters failed, status: " << +status;
+ c->cb.Run(status);
+ return;
+ }
+
+ c->self->adv_inst[c->inst_id].tx_power = tx_power;
+
+ BD_ADDR *rpa = &c->self->adv_inst[c->inst_id].own_address;
+ c->self->GetHciInterface()->SetRandomAddress(c->inst_id, *rpa, Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ LOG(ERROR) << "setting random address failed, status: " << +status;
+ c->cb.Run(status);
+ return;
+ }
+
+ c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ LOG(ERROR) << "setting advertise data failed, status: " << +status;
+ c->cb.Run(status);
+ return;
+ }
+
+ c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ LOG(ERROR) << "setting scan response data failed, status: " << +status;
+ c->cb.Run(status);
+ return;
+ }
+
+ c->self->Enable(c->inst_id, true, c->cb, c->duration, 0, std::move(c->timeout_cb));
+
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ // clang-format on
+ }
+
+ void StartAdvertisingSet(IdTxPowerStatusCb cb, tBTM_BLE_ADV_PARAMS* params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data,
+ tBLE_PERIODIC_ADV_PARAMS* periodic_params,
+ std::vector<uint8_t> periodic_data,
+ uint16_t duration, uint8_t maxExtAdvEvents,
+ RegisterCb timeout_cb) override {
+ std::unique_ptr<CreatorParams> c;
+ c.reset(new CreatorParams());
+
+ c->self = this;
+ c->cb = std::move(cb);
+ c->params = *params;
+ c->advertise_data = std::move(advertise_data);
+ c->scan_response_data = std::move(scan_response_data);
+ c->periodic_params = *periodic_params;
+ c->periodic_data = std::move(periodic_data);
+ c->duration = duration;
+ c->maxExtAdvEvents = maxExtAdvEvents;
+ c->timeout_cb = std::move(timeout_cb);
+
+
+ // this code is intentionally left formatted this way to highlight the
+ // asynchronous flow
+ // clang-format off
+ c->self->RegisterAdvertiser(Bind(
+ [](c_type c, uint8_t advertiser_id, uint8_t status) {
+ if (status != 0) {
+ LOG(ERROR) << "registering advertiser failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->inst_id = advertiser_id;
+
+ c->self->SetParameters(c->inst_id, &c->params, Bind(
+ [](c_type c, uint8_t status, int8_t tx_power) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting parameters failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->adv_inst[c->inst_id].tx_power = tx_power;
+
+ BD_ADDR *rpa = &c->self->adv_inst[c->inst_id].own_address;
+ c->self->GetHciInterface()->SetRandomAddress(c->inst_id, *rpa, Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting random address failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->SetData(c->inst_id, false, std::move(c->advertise_data), Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting advertise data failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->SetData(c->inst_id, true, std::move(c->scan_response_data), Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting scan response data failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ if (c->periodic_params.enable) {
+ c->self->StartAdvertisingSetPeriodicPart(std::move(c));
+ } else {
+ c->self->StartAdvertisingSetFinish(std::move(c));
+ }
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ // clang-format on
+ }
+
+ void StartAdvertisingSetPeriodicPart(c_type c) {
+ // this code is intentionally left formatted this way to highlight the
+ // asynchronous flow
+ // clang-format off
+ c->self->SetPeriodicAdvertisingParameters(c->inst_id, &c->periodic_params, Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->SetPeriodicAdvertisingData(c->inst_id, std::move(c->periodic_data), Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "setting periodic parameters failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->SetPeriodicAdvertisingEnable(c->inst_id, true, Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "enabling periodic advertising failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+
+ c->self->StartAdvertisingSetFinish(std::move(c));
+
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ }, base::Passed(&c)));
+ // clang-format on
+ }
+
+ void StartAdvertisingSetFinish(c_type c) {
+ uint8_t inst_id = c->inst_id;
+ uint16_t duration = c->duration;
+ uint8_t maxExtAdvEvents = c->maxExtAdvEvents;
+ RegisterCb timeout_cb = std::move(c->timeout_cb);
+ BleAdvertisingManagerImpl* self = c->self;
+ MultiAdvCb enable_cb = Bind(
+ [](c_type c, uint8_t status) {
+ if (status != 0) {
+ c->self->Unregister(c->inst_id);
+ LOG(ERROR) << "enabling advertiser failed, status: " << +status;
+ c->cb.Run(0, 0, status);
+ return;
+ }
+ int8_t tx_power = c->self->adv_inst[c->inst_id].tx_power;
+ c->cb.Run(c->inst_id, tx_power, status);
+ },
+ base::Passed(&c));
+
+ self->Enable(inst_id, true, std::move(enable_cb), duration, maxExtAdvEvents,
+ Bind(std::move(timeout_cb), inst_id));
+ }
+
+ void EnableWithTimerCb(uint8_t inst_id, MultiAdvCb enable_cb, int duration,
+ MultiAdvCb timeout_cb, uint8_t status) {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+ AdvertisingInstance* p_inst = &adv_inst[inst_id];
+
+ // Run the regular enable callback
+ enable_cb.Run(status);
+
+ p_inst->timeout_timer = alarm_new("btm_ble.adv_timeout");
+
+ base::Closure cb = Bind(&BleAdvertisingManagerImpl::Enable,
+ base::Unretained(this), inst_id, 0 /* disable */,
+ std::move(timeout_cb), 0, 0, base::Bind(DoNothing));
+
+ // schedule disable when the timeout passes
+ alarm_set_closure_on_queue(FROM_HERE, p_inst->timeout_timer, duration * 10,
+ std::move(cb), btu_general_alarm_queue);
+ }
+
+ void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb, uint16_t duration,
+ uint8_t maxExtAdvEvents, MultiAdvCb timeout_cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+ if (inst_id >= inst_count) {
+ LOG(ERROR) << "bad instance id " << +inst_id;
+ return;
+ }
+
+ AdvertisingInstance* p_inst = &adv_inst[inst_id];
+ VLOG(1) << __func__ << " enable: " << enable << ", duration: " << +duration;
+ if (!p_inst->in_use) {
+ LOG(ERROR) << "Invalid or no active instance";
+ cb.Run(BTM_BLE_MULTI_ADV_FAILURE);
+ return;
+ }
+
+ if (enable && (duration || maxExtAdvEvents)) {
+ p_inst->timeout_cb = std::move(timeout_cb);
+ }
+
+ p_inst->duration = duration;
+ p_inst->maxExtAdvEvents = maxExtAdvEvents;
+
+ if (enable && p_inst->address_update_required) {
+ p_inst->address_update_required = false;
+ ConfigureRpa(p_inst, base::Bind(&BleAdvertisingManagerImpl::EnableFinish,
+ base::Unretained(this), p_inst, enable,
+ std::move(cb)));
+ return;
+ }
+
+ EnableFinish(p_inst, enable, std::move(cb), 0);
+ }
+
+ void EnableFinish(AdvertisingInstance* p_inst, bool enable, MultiAdvCb cb,
+ uint8_t status) {
+ if (enable && p_inst->duration) {
+ p_inst->enable_status = enable;
+ // TODO(jpawlowski): HCI implementation that can't do duration should
+ // emulate it, not EnableWithTimerCb.
+ GetHciInterface()->Enable(
+ enable, p_inst->inst_id, p_inst->duration, p_inst->maxExtAdvEvents,
+ Bind(&BleAdvertisingManagerImpl::EnableWithTimerCb,
+ base::Unretained(this), p_inst->inst_id, std::move(cb),
+ p_inst->duration, p_inst->timeout_cb));
+
+ } else {
+ if (p_inst->timeout_timer) {
+ alarm_cancel(p_inst->timeout_timer);
+ alarm_free(p_inst->timeout_timer);
+ p_inst->timeout_timer = nullptr;
+ }
+
+ p_inst->enable_status = enable;
+ GetHciInterface()->Enable(enable, p_inst->inst_id, p_inst->duration,
+ p_inst->maxExtAdvEvents, std::move(cb));
+ }
+ }
+
+ void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params,
+ ParametersCb cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+ if (inst_id >= inst_count) {
+ LOG(ERROR) << "bad instance id " << +inst_id;
+ return;
+ }
+
+ AdvertisingInstance* p_inst = &adv_inst[inst_id];
+ if (!p_inst->in_use) {
+ LOG(ERROR) << "adv instance not in use" << +inst_id;
+ cb.Run(BTM_BLE_MULTI_ADV_FAILURE, 0);
+ return;
+ }
+
+ // TODO: disable only if was enabled, currently no use scenario needs that,
+ // we always set parameters before enabling
+ // GetHciInterface()->Enable(false, inst_id, Bind(DoNothing));
+ p_inst->advertising_event_properties =
+ p_params->advertising_event_properties;
+ p_inst->tx_power = p_params->tx_power;
+ BD_ADDR peer_address = {0, 0, 0, 0, 0, 0};
+
+ GetHciInterface()->SetParameters(
+ p_inst->inst_id, p_params->advertising_event_properties,
+ p_params->adv_int_min, p_params->adv_int_max, p_params->channel_map,
+ p_inst->own_address_type, p_inst->own_address, 0x00, peer_address,
+ p_params->adv_filter_policy, p_inst->tx_power,
+ p_params->primary_advertising_phy, 0x01,
+ p_params->secondary_advertising_phy, 0x01 /* TODO: proper SID */,
+ p_params->scan_request_notification_enable, cb);
+
+ // TODO: re-enable only if it was enabled, properly call
+ // SetParamsCallback
+ // currently no use scenario needs that
+ // GetHciInterface()->Enable(true, inst_id, BTM_BleUpdateAdvInstParamCb);
+ }
+
+ void SetData(uint8_t inst_id, bool is_scan_rsp, std::vector<uint8_t> data,
+ MultiAdvCb cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+ if (inst_id >= inst_count) {
+ LOG(ERROR) << "bad instance id " << +inst_id;
+ return;
+ }
+
+ AdvertisingInstance* p_inst = &adv_inst[inst_id];
+ VLOG(1) << "is_scan_rsp = " << is_scan_rsp;
+
+ if (!is_scan_rsp && is_connectable(p_inst->advertising_event_properties)) {
+ uint8_t flags_val = BTM_GENERAL_DISCOVERABLE;
+
+ if (p_inst->duration) flags_val = BTM_LIMITED_DISCOVERABLE;
+
+ std::vector<uint8_t> flags;
+ flags.push_back(2); // length
+ flags.push_back(HCI_EIR_FLAGS_TYPE);
+ flags.push_back(flags_val);
+
+ data.insert(data.begin(), flags.begin(), flags.end());
+ }
+
+ // Find and fill TX Power with the correct value
+ if (data.size()) {
+ size_t i = 0;
+ while (i < data.size()) {
+ uint8_t type = data[i + 1];
+ if (type == HCI_EIR_TX_POWER_LEVEL_TYPE) {
+ data[i + 2] = adv_inst[inst_id].tx_power;
+ }
+ i += data[i] + 1;
+ }
+ }
+
+ VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
+ DivideAndSendData(
+ inst_id, data, cb,
+ base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender,
+ base::Unretained(this), is_scan_rsp));
+ }
+
+ void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id,
+ uint8_t operation, uint8_t length, uint8_t* data,
+ MultiAdvCb cb) {
+ if (is_scan_rsp)
+ GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length,
+ data, cb);
+ else
+ GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length,
+ data, cb);
+ }
+
+ using DataSender = base::Callback<void(
+ uint8_t /*inst_id*/, uint8_t /* operation */, uint8_t /* length */,
+ uint8_t* /* data */, MultiAdvCb /* done */)>;
+
+ void DivideAndSendData(int inst_id, std::vector<uint8_t> data,
+ MultiAdvCb done_cb, DataSender sender) {
+ DivideAndSendDataRecursively(true, inst_id, std::move(data), 0,
+ std::move(done_cb), std::move(sender), 0);
+ }
+
+ static void DivideAndSendDataRecursively(bool isFirst, int inst_id,
+ std::vector<uint8_t> data,
+ int offset, MultiAdvCb done_cb,
+ DataSender sender, uint8_t status) {
+ constexpr uint8_t INTERMEDIATE =
+ 0x00; // Intermediate fragment of fragmented data
+ constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data
+ constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data
+ constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data
+
+ int dataSize = (int)data.size();
+ if (status != 0 || (!isFirst && offset == dataSize)) {
+ /* if we got error writing data, or reached the end of data */
+ done_cb.Run(status);
+ return;
+ }
+
+ bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX;
+ uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE
+ : moreThanOnePacket ? INTERMEDIATE : LAST;
+ int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset;
+ int newOffset = offset + length;
+
+ sender.Run(
+ inst_id, operation, length, data.data() + offset,
+ Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false,
+ inst_id, std::move(data), newOffset, std::move(done_cb), sender));
+ }
+
+ void SetPeriodicAdvertisingParameters(uint8_t inst_id,
+ tBLE_PERIODIC_ADV_PARAMS* params,
+ MultiAdvCb cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+
+ GetHciInterface()->SetPeriodicAdvertisingParameters(
+ inst_id, params->min_interval, params->max_interval,
+ params->periodic_advertising_properties, cb);
+ }
+
+ void SetPeriodicAdvertisingData(uint8_t inst_id, std::vector<uint8_t> data,
+ MultiAdvCb cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+
+ VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
+
+ DivideAndSendData(
+ inst_id, data, cb,
+ base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData,
+ base::Unretained(GetHciInterface())));
+ }
+
+ void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable,
+ MultiAdvCb cb) override {
+ VLOG(1) << __func__ << " inst_id: " << +inst_id << ", enable: " << +enable;
+
+ GetHciInterface()->SetPeriodicAdvertisingEnable(enable, inst_id, cb);
+ }
+
+ void Unregister(uint8_t inst_id) override {
+ AdvertisingInstance* p_inst = &adv_inst[inst_id];
+
+ VLOG(1) << __func__ << " inst_id: " << +inst_id;
+ if (inst_id >= inst_count) {
+ LOG(ERROR) << "bad instance id " << +inst_id;
+ return;
+ }
+
+ if (adv_inst[inst_id].IsEnabled()) {
+ p_inst->enable_status = false;
+ GetHciInterface()->Enable(false, inst_id, 0x00, 0x00, Bind(DoNothing));
+ }
+
+ alarm_cancel(p_inst->adv_raddr_timer);
+ p_inst->in_use = false;
+ GetHciInterface()->RemoveAdvertisingSet(inst_id, Bind(DoNothing));
+ p_inst->address_update_required = false;
+ }
+
+ void OnAdvertisingSetTerminated(
+ uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
+ uint8_t num_completed_extended_adv_events) override {
+ AdvertisingInstance* p_inst = &adv_inst[advertising_handle];
+ VLOG(1) << __func__ << "status: 0x" << std::hex << +status
+ << ", advertising_handle: 0x" << std::hex << +advertising_handle
+ << ", connection_handle: 0x" << std::hex << +connection_handle;
+
+ if (status == 0x43 || status == 0x3C) {
+ // either duration elapsed, or maxExtAdvEvents reached
+ p_inst->enable_status = false;
+
+ if (p_inst->timeout_cb.is_null()) {
+ LOG(INFO) << __func__ << "No timeout callback";
+ return;
+ }
+
+ p_inst->timeout_cb.Run(status);
+ return;
+ }
+
+ if (BTM_BleLocalPrivacyEnabled() &&
+ advertising_handle <= BTM_BLE_MULTI_ADV_MAX) {
+ btm_acl_update_conn_addr(connection_handle, p_inst->own_address);
+ }
+
+ VLOG(1) << "reneabling advertising";
+
+ if (p_inst->in_use == true) {
+ // TODO(jpawlowski): we don't really allow to do directed advertising
+ // right now. This should probably be removed, check with Andre.
+ if ((p_inst->advertising_event_properties & 0x0C) ==
+ 0 /* directed advertising bits not set */) {
+ GetHciInterface()->Enable(true, advertising_handle, 0x00, 0x00,
+ Bind(DoNothing));
+ } else {
+ /* mark directed adv as disabled if adv has been stopped */
+ p_inst->in_use = false;
+ }
+ }
+ }
+
+ private:
+ BleAdvertiserHciInterface* GetHciInterface() { return hci_interface; }
+
+ BleAdvertiserHciInterface* hci_interface = nullptr;
+ std::vector<AdvertisingInstance> adv_inst;
+ uint8_t inst_count;
+};
+
+BleAdvertisingManager* instance;
+
+void btm_ble_adv_raddr_timer_timeout(void* data) {
+ ((BleAdvertisingManagerImpl*)BleAdvertisingManager::Get())
+ ->ConfigureRpa((AdvertisingInstance*)data, base::Bind(DoNothing));
+}
+} // namespace
+
+void BleAdvertisingManager::Initialize(BleAdvertiserHciInterface* interface) {
+ instance = new BleAdvertisingManagerImpl(interface);
+}
+
+BleAdvertisingManager* BleAdvertisingManager::Get() {
+ CHECK(instance);
+ return instance;
+};
+
+void BleAdvertisingManager::CleanUp() {
+ delete instance;
+ instance = nullptr;
+};
+
+/**
+ * This function initialize the advertising manager.
+ **/
+void btm_ble_adv_init() {
+ BleAdvertiserHciInterface::Initialize();
+ BleAdvertisingManager::Initialize(BleAdvertiserHciInterface::Get());
+ BleAdvertiserHciInterface::Get()->SetAdvertisingEventObserver(
+ (BleAdvertisingManagerImpl*)BleAdvertisingManager::Get());
+
+ if (BleAdvertiserHciInterface::Get()->QuirkAdvertiserZeroHandle()) {
+ // If handle 0 can't be used, register advertiser for it, but never use it.
+ BleAdvertisingManager::Get()->RegisterAdvertiser(Bind(DoNothing2));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_multi_adv_cleanup
+ *
+ * Description This function cleans up multi adv control block.
+ *
+ * Parameters
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_multi_adv_cleanup(void) {
+ BleAdvertisingManager::CleanUp();
+ BleAdvertiserHciInterface::CleanUp();
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_ble_privacy.cc b/mtkbt/code/bt/stack/btm/btm_ble_privacy.cc
new file mode 100755
index 0000000..5d35226
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_ble_privacy.cc
@@ -0,0 +1,943 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for BLE controller based privacy.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_target.h"
+
+#if (BLE_PRIVACY_SPT == TRUE)
+#include "bt_types.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "vendor_hcidefs.h"
+
+/* RPA offload VSC specifics */
+#define BTM_BLE_META_IRK_ENABLE 0x01
+#define BTM_BLE_META_ADD_IRK_ENTRY 0x02
+#define BTM_BLE_META_REMOVE_IRK_ENTRY 0x03
+#define BTM_BLE_META_CLEAR_IRK_LIST 0x04
+#define BTM_BLE_META_READ_IRK_ENTRY 0x05
+#define BTM_BLE_META_CS_RESOLVE_ADDR 0x00000001
+#define BTM_BLE_IRK_ENABLE_LEN 2
+
+#define BTM_BLE_META_ADD_IRK_LEN 24
+#define BTM_BLE_META_REMOVE_IRK_LEN 8
+#define BTM_BLE_META_CLEAR_IRK_LEN 1
+#define BTM_BLE_META_READ_IRK_LEN 2
+#define BTM_BLE_META_ADD_WL_ATTR_LEN 9
+
+/*******************************************************************************
+ * Functions implemented controller based privacy using Resolving List
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_ble_enq_resolving_list_pending
+ *
+ * Description add target address into resolving pending operation queue
+ *
+ * Parameters target_bda: target device address
+ * add_entry: true for add entry, false for remove entry
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_enq_resolving_list_pending(BD_ADDR pseudo_bda, uint8_t op_code) {
+ tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], pseudo_bda, BD_ADDR_LEN);
+ p_q->resolve_q_action[p_q->q_next] = op_code;
+ p_q->q_next++;
+ p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_brcm_find_resolving_pending_entry
+ *
+ * Description check to see if the action is in pending list
+ *
+ * Parameters true: action pending;
+ * false: new action
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool btm_ble_brcm_find_resolving_pending_entry(BD_ADDR pseudo_addr,
+ uint8_t action) {
+ tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ for (uint8_t i = p_q->q_pending; i != p_q->q_next;) {
+ if (memcmp(p_q->resolve_q_random_pseudo[i], pseudo_addr, BD_ADDR_LEN) ==
+ 0 &&
+ action == p_q->resolve_q_action[i])
+ return true;
+
+ i++;
+ i %= controller_get_interface()->get_ble_resolving_list_max_size();
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_deq_resolving_pending
+ *
+ * Description dequeue target address from resolving pending operation
+ * queue
+ *
+ * Parameters pseudo_addr: pseudo_addr device address
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool btm_ble_deq_resolving_pending(BD_ADDR pseudo_addr) {
+ tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ if (p_q->q_next != p_q->q_pending) {
+ memcpy(pseudo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending],
+ BD_ADDR_LEN);
+ memset(p_q->resolve_q_random_pseudo[p_q->q_pending], 0, BD_ADDR_LEN);
+ p_q->q_pending++;
+ p_q->q_pending %=
+ controller_get_interface()->get_ble_resolving_list_max_size();
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_irk_index
+ *
+ * Description clear IRK list index mask for availability
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_ble_clear_irk_index(uint8_t index) {
+ uint8_t byte;
+ uint8_t bit;
+
+ if (index < controller_get_interface()->get_ble_resolving_list_max_size()) {
+ byte = index / 8;
+ bit = index % 8;
+ btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_find_irk_index
+ *
+ * Description find the first available IRK list index
+ *
+ * Returns index from 0 ~ max (127 default)
+ *
+ ******************************************************************************/
+uint8_t btm_ble_find_irk_index(void) {
+ uint8_t i = 0;
+ uint8_t byte;
+ uint8_t bit;
+
+ while (i < controller_get_interface()->get_ble_resolving_list_max_size()) {
+ byte = i / 8;
+ bit = i % 8;
+
+ if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0) {
+ btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit);
+ return i;
+ }
+ i++;
+ }
+
+ BTM_TRACE_ERROR("%s failed, list full", __func__);
+ return i;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_update_resolving_list
+ *
+ * Description update resolving list entry in host maintained record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, bool add) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(pseudo_bda);
+ if (p_dev_rec == NULL) return;
+
+ if (add) {
+ p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT;
+ if (!controller_get_interface()->supports_ble_privacy())
+ p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index();
+ } else {
+ p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+ if (!controller_get_interface()->supports_ble_privacy()) {
+ /* clear IRK list index mask */
+ btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index);
+ p_dev_rec->ble.resolving_list_index = 0;
+ }
+ }
+}
+
+bool clear_resolving_list_bit(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_resolving_list_complete
+ *
+ * Description This function is called when command complete for
+ * clear resolving list
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len) {
+ uint8_t status = 0;
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status=%d", __func__, status);
+
+ if (status == HCI_SUCCESS) {
+ if (evt_len >= 3) {
+ /* VSC complete has one extra byte for op code and list size, skip it here
+ */
+ p++;
+
+ /* updated the available list size, and current list size */
+ uint8_t irk_list_sz_max = 0;
+ STREAM_TO_UINT8(irk_list_sz_max, p);
+
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ btm_ble_resolving_list_init(irk_list_sz_max);
+
+ uint8_t irk_mask_size = (irk_list_sz_max % 8) ? (irk_list_sz_max / 8 + 1)
+ : (irk_list_sz_max / 8);
+ memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size);
+ }
+
+ btm_cb.ble_ctr_cb.resolving_list_avail_size =
+ controller_get_interface()->get_ble_resolving_list_max_size();
+
+ BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d", __func__,
+ btm_cb.ble_ctr_cb.resolving_list_avail_size);
+
+ list_foreach(btm_cb.sec_dev_rec, clear_resolving_list_bit, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_add_resolving_list_entry_complete
+ *
+ * Description This function is called when command complete for
+ * add resolving list entry
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) {
+ uint8_t status;
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ BD_ADDR pseudo_bda;
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_DEBUG("no pending resolving list operation");
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* privacy 1.2 command complete does not have these extra byte */
+ if (evt_len > 2) {
+ /* VSC complete has one extra byte for op code, skip it here */
+ p++;
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+
+ /** M: Bug fix for BTM_RESOLVING_LIST_BIT be cleared unexpectedly @{ */
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(pseudo_bda);
+ if (p_dev_rec != NULL &&
+ !(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT))
+ btm_ble_update_resolving_list(pseudo_bda, TRUE);
+ /** @} */
+ } else
+ btm_cb.ble_ctr_cb.resolving_list_avail_size--;
+ } else if (status ==
+ HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */
+ {
+ btm_cb.ble_ctr_cb.resolving_list_avail_size = 0;
+ BTM_TRACE_DEBUG("%s Resolving list Full ", __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_remove_resolving_list_entry_complete
+ *
+ * Description This function is called when command complete for
+ * remove resolving list entry
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_remove_resolving_list_entry_complete(uint8_t* p,
+ uint16_t evt_len) {
+ BD_ADDR pseudo_bda;
+ uint8_t status;
+
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_ERROR("%s no pending resolving list operation", __func__);
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* proprietary: spec does not have these extra bytes */
+ if (evt_len > 2) {
+ p++; /* skip opcode */
+ STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
+
+ /** M: Bug fix for BTM_RESOLVING_LIST_BIT be set unexpectedly @{ */
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(pseudo_bda);
+ if (p_dev_rec != NULL &&
+ (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT))
+ btm_ble_update_resolving_list(pseudo_bda, FALSE);
+ /** @} */
+ } else
+ btm_cb.ble_ctr_cb.resolving_list_avail_size++;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_resolving_list_entry_complete
+ *
+ * Description This function is called when command complete for
+ * remove resolving list entry
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_read_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len) {
+ uint8_t status, rra_type = BTM_BLE_ADDR_PSEUDO;
+ BD_ADDR rra, pseudo_bda;
+
+ STREAM_TO_UINT8(status, p);
+
+ BTM_TRACE_DEBUG("%s status = %d", __func__, status);
+
+ if (!btm_ble_deq_resolving_pending(pseudo_bda)) {
+ BTM_TRACE_ERROR("no pending resolving list operation");
+ return;
+ }
+
+ if (status == HCI_SUCCESS) {
+ /* proprietary spec has extra bytes */
+ if (evt_len > 8) {
+ /* skip subcode, index, IRK value, address type, identity addr type */
+ p += (2 + 16 + 1 + 6);
+ STREAM_TO_BDADDR(rra, p);
+
+ BTM_TRACE_ERROR("%s peer_addr: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ rra[0], rra[1], rra[2], rra[3], rra[4], rra[5]);
+ } else {
+ STREAM_TO_BDADDR(rra, p);
+ }
+ btm_ble_refresh_peer_resolvable_private_addr(pseudo_bda, rra, rra_type);
+ }
+}
+/*******************************************************************************
+ VSC that implement controller based privacy
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_vsc_op_cmpl
+ *
+ * Description IRK operation VSC complete handler
+ *
+ * Parameters
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_resolving_list_vsc_op_cmpl(tBTM_VSC_CMPL* p_params) {
+ uint8_t *p = p_params->p_param_buf, op_subcode;
+ uint16_t evt_len = p_params->param_len;
+
+ op_subcode = *(p + 1);
+
+ BTM_TRACE_DEBUG("%s op_subcode = %d", __func__, op_subcode);
+
+ if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST) {
+ btm_ble_clear_resolving_list_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY) {
+ btm_ble_add_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY) {
+ btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY) {
+ btm_ble_read_resolving_list_entry_complete(p, evt_len);
+ } else if (op_subcode == BTM_BLE_META_IRK_ENABLE) {
+ /* RPA offloading enable/disabled */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_remove_resolving_list_entry
+ *
+ * Description This function to remove an IRK entry from the list
+ *
+ * Parameters ble_addr_type: address type
+ * ble_addr: LE adddress
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) {
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ return BTM_WRONG_MODE;
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr);
+ } else {
+ uint8_t param[20] = {0};
+ uint8_t* p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+ BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_REMOVE_IRK_LEN, param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+ BTM_BLE_META_REMOVE_IRK_ENTRY);
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_clear_resolving_list
+ *
+ * Description This function clears the resolving list
+ *
+ * Parameters None.
+ *
+ ******************************************************************************/
+void btm_ble_clear_resolving_list(void) {
+ if (controller_get_interface()->supports_ble_privacy()) {
+ btsnd_hcic_ble_clear_resolving_list();
+ } else {
+ uint8_t param[20] = {0};
+ uint8_t* p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST);
+ BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_CLEAR_IRK_LEN, param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_read_resolving_list_entry
+ *
+ * Description This function read an IRK entry by index
+ *
+ * Parameters entry index.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC* p_dev_rec) {
+ if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT))
+ return BTM_WRONG_MODE;
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr);
+ } else {
+ uint8_t param[20] = {0};
+ uint8_t* p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.resolving_list_index);
+
+ BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_META_READ_IRK_LEN,
+ param, btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+ BTM_BLE_META_READ_IRK_ENTRY);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_suspend_resolving_list_activity
+ *
+ * Description This function suspends all resolving list activity,
+ * including scanning, initiating, and advertising, if
+ * resolving list is being enabled.
+ *
+ * Parameters
+ *
+ * Returns true if suspended; false otherwise
+ *
+ ******************************************************************************/
+bool btm_ble_suspend_resolving_list_activity(void) {
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ /* if resolving list is not enabled, do not need to terminate any activity */
+ /* if asking for stop all activity */
+ /* if already suspended */
+ if (p_ble_cb->suspended_rl_state != BTM_BLE_RL_IDLE) return true;
+
+ /* direct connection active, wait until it completed */
+ if (btm_ble_get_conn_st() == BLE_DIR_CONN) {
+ BTM_TRACE_ERROR("resolving list can not be edited, EnQ now");
+ return false;
+ }
+
+ p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+
+ if (p_ble_cb->inq_var.adv_mode == BTM_BLE_ADV_ENABLE) {
+ btm_ble_stop_adv();
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_ADV;
+ }
+
+ if (BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) {
+ btm_ble_stop_scan();
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_SCAN;
+ }
+
+ if (btm_ble_suspend_bg_conn())
+ p_ble_cb->suspended_rl_state |= BTM_BLE_RL_INIT;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resume_resolving_list_activity
+ *
+ * Description This function resumes the resolving list activity, including
+ * scanning, initiating, and advertising, if any of these
+ * activities has been suspended earlier.
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_ble_resume_resolving_list_activity(void) {
+ tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_ADV) btm_ble_start_adv();
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_SCAN) btm_ble_start_scan();
+
+ if (p_ble_cb->suspended_rl_state & BTM_BLE_RL_INIT) btm_ble_resume_bg_conn();
+
+ p_ble_cb->suspended_rl_state = BTM_BLE_RL_IDLE;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_vendor_enable_irk_feature
+ *
+ * Description This function is called to enable or disable the RRA
+ * offloading feature.
+ *
+ * Parameters enable: enable or disable the RRA offloading feature
+ *
+ ******************************************************************************/
+void btm_ble_vendor_enable_irk_feature(bool enable) {
+ uint8_t param[20], *p;
+
+ p = param;
+ memset(param, 0, 20);
+
+ /* select feature based on control block settings */
+ UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE);
+ UINT8_TO_STREAM(p, enable ? 0x01 : 0x00);
+
+ BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN,
+ param, btm_ble_resolving_list_vsc_op_cmpl);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_exe_disable_resolving_list
+ *
+ * Description execute resolving list disable
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+bool btm_ble_exe_disable_resolving_list(void) {
+ if (!btm_ble_suspend_resolving_list_activity()) return false;
+
+ if (!controller_get_interface()->supports_ble_privacy())
+ btm_ble_vendor_enable_irk_feature(false);
+ else
+ btsnd_hcic_ble_set_addr_resolution_enable(false);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_exe_enable_resolving_list
+ *
+ * Description enable LE resolve address list
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_ble_exe_enable_resolving_list(void) {
+ if (!btm_ble_suspend_resolving_list_activity()) return;
+
+ if (!controller_get_interface()->supports_ble_privacy())
+ btm_ble_vendor_enable_irk_feature(true);
+ else
+ btsnd_hcic_ble_set_addr_resolution_enable(true);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_disable_resolving_list
+ *
+ * Description Disable LE Address resolution
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+bool btm_ble_disable_resolving_list(uint8_t rl_mask, bool to_resume) {
+ uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ return false;
+
+ btm_cb.ble_ctr_cb.rl_state &= ~rl_mask;
+
+ if (rl_state != BTM_BLE_RL_IDLE &&
+ btm_cb.ble_ctr_cb.rl_state == BTM_BLE_RL_IDLE) {
+ if (btm_ble_exe_disable_resolving_list()) {
+ if (to_resume) btm_ble_resume_resolving_list_activity();
+
+ return true;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_load_dev
+ *
+ * Description This function adds a device which is using RPA into the
+ * white list.
+ *
+ * Parameters pointer to device security record
+ *
+ * Returns true if device added, otherwise falase.
+ *
+ ******************************************************************************/
+bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
+ bool rt = false;
+ uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state;
+ bool add = false;
+
+ BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
+ btm_cb.ble_ctr_cb.privacy_mode);
+
+ /* if controller does not support RPA offloading or privacy 1.2, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ return false;
+
+ BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
+ btm_cb.ble_ctr_cb.privacy_mode);
+
+ /** M: fix judgement condition of adding device to resloving list @{ */
+ if (p_dev_rec == NULL)
+ return false;
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ if ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 ||
+ (p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0)
+ add = true;
+ }
+ else {
+ if ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0)
+ add = true;
+ }
+ /** @} */
+
+ /* only add RPA enabled device into resolving list */
+ if (add) {
+ if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ btm_ble_brcm_find_resolving_pending_entry(
+ p_dev_rec->bd_addr, BTM_BLE_META_ADD_IRK_ENTRY) == false) {
+ if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0) {
+ if (rl_mask) {
+ if (!btm_ble_disable_resolving_list(rl_mask, false)) return false;
+ }
+
+ btm_ble_update_resolving_list(p_dev_rec->bd_addr, true);
+ /** M: need a static address, if not exchanged by SMP, use pseudo instead @{ */
+ if (bdaddr_is_empty((const bt_bdaddr_t *)p_dev_rec->ble.static_addr)) {
+ bdcpy(p_dev_rec->ble.static_addr, p_dev_rec->ble.pseudo_addr);
+ p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
+ }
+ /** @} */
+ if (controller_get_interface()->supports_ble_privacy()) {
+ uint8_t* peer_irk = p_dev_rec->ble.keys.irk;
+ uint8_t* local_irk = btm_cb.devcb.id_keys.irk;
+
+ BTM_TRACE_DEBUG("%s:adding device to controller resolving list",
+ __func__);
+ // use identical IRK for now
+ btsnd_hcic_ble_add_device_resolving_list(
+ p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr,
+ peer_irk, local_irk);
+
+ if (controller_get_interface()->supports_ble_privacy()) {
+ BTM_TRACE_DEBUG("%s: adding device privacy mode", __func__);
+ btsnd_hcic_ble_set_privacy_mode(p_dev_rec->ble.static_addr_type,
+ p_dev_rec->ble.static_addr, 0x01);
+ }
+ } else {
+ uint8_t param[40] = {0};
+ uint8_t* p = param;
+
+ UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
+ ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
+ UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
+ BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
+
+ BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+ BTM_BLE_META_ADD_IRK_LEN, param,
+ btm_ble_resolving_list_vsc_op_cmpl);
+ }
+
+ rt = true;
+ btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+ BTM_BLE_META_ADD_IRK_ENTRY);
+
+ /* if resolving list has been turned on, re-enable it */
+ if (rl_mask)
+ btm_ble_enable_resolving_list(rl_mask);
+ else
+ btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+ }
+ } else {
+ BTM_TRACE_ERROR("Device already in Resolving list");
+ rt = true;
+ }
+ } else {
+ BTM_TRACE_DEBUG("Device not a RPA enabled device");
+ }
+ return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_remove_dev
+ *
+ * Description This function removes the device from resolving list
+ *
+ * Parameters
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
+ uint8_t rl_mask = btm_cb.ble_ctr_cb.rl_state;
+
+ BTM_TRACE_EVENT("%s", __func__);
+ if (rl_mask) {
+ if (!btm_ble_disable_resolving_list(rl_mask, false)) return;
+ }
+
+ if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ btm_ble_brcm_find_resolving_pending_entry(
+ p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY) == false) {
+ btm_ble_update_resolving_list(p_dev_rec->bd_addr, false);
+ btm_ble_remove_resolving_list_entry(p_dev_rec);
+ } else {
+ BTM_TRACE_DEBUG("Device not in resolving list");
+ }
+
+ /* if resolving list has been turned on, re-enable it */
+ if (rl_mask) btm_ble_enable_resolving_list(rl_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_enable_resolving_list
+ *
+ * Description enable LE resolve address list
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_ble_enable_resolving_list(uint8_t rl_mask) {
+ uint8_t rl_state = btm_cb.ble_ctr_cb.rl_state;
+
+ btm_cb.ble_ctr_cb.rl_state |= rl_mask;
+ if (rl_state == BTM_BLE_RL_IDLE &&
+ btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE &&
+ controller_get_interface()->get_ble_resolving_list_max_size() != 0) {
+ btm_ble_exe_enable_resolving_list();
+ btm_ble_resume_resolving_list_activity();
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_empty
+ *
+ * Description check to see if resoving list is empty or not
+ *
+ * Returns true: empty; false non-empty
+ *
+ ******************************************************************************/
+bool btm_ble_resolving_list_empty(void) {
+ return (controller_get_interface()->get_ble_resolving_list_max_size() ==
+ btm_cb.ble_ctr_cb.resolving_list_avail_size);
+}
+
+bool is_on_resolving_list(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev = static_cast<tBTM_SEC_DEV_REC*>(data);
+ if ((p_dev->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
+ (p_dev->ble.in_controller_list & BTM_WHITE_LIST_BIT))
+ return false;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_enable_resolving_list_for_platform
+ *
+ * Description enable/disable resolving list feature depending on if any
+ * resolving list is empty and whitelist is involoved in the
+ * operation.
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_ble_enable_resolving_list_for_platform(uint8_t rl_mask) {
+ /* if controller does not support, skip */
+ if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+ return;
+
+ if (btm_cb.ble_ctr_cb.wl_state == BTM_BLE_WL_IDLE) {
+ if (controller_get_interface()->get_ble_resolving_list_max_size() >
+ btm_cb.ble_ctr_cb.resolving_list_avail_size)
+ btm_ble_enable_resolving_list(rl_mask);
+ else
+ btm_ble_disable_resolving_list(rl_mask, true);
+ return;
+ }
+
+ list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_on_resolving_list, NULL);
+ if (n)
+ btm_ble_enable_resolving_list(rl_mask);
+ else
+ btm_ble_disable_resolving_list(rl_mask, true);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_init
+ *
+ * Description Initialize resolving list in host stack
+ *
+ * Parameters Max resolving list size
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_resolving_list_init(uint8_t max_irk_list_sz) {
+ tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+ uint8_t irk_mask_size =
+ (max_irk_list_sz % 8) ? (max_irk_list_sz / 8 + 1) : (max_irk_list_sz / 8);
+
+ if (max_irk_list_sz > 0) {
+ p_q->resolve_q_random_pseudo =
+ (BD_ADDR*)osi_malloc(sizeof(BD_ADDR) * max_irk_list_sz);
+ p_q->resolve_q_action = (uint8_t*)osi_malloc(max_irk_list_sz);
+
+ /* RPA offloading feature */
+ if (btm_cb.ble_ctr_cb.irk_list_mask == NULL)
+ btm_cb.ble_ctr_cb.irk_list_mask = (uint8_t*)osi_malloc(irk_mask_size);
+
+ BTM_TRACE_DEBUG("%s max_irk_list_sz = %d", __func__, max_irk_list_sz);
+ }
+
+ controller_get_interface()->set_ble_resolving_list_max_size(max_irk_list_sz);
+ btm_ble_clear_resolving_list();
+ btm_cb.ble_ctr_cb.resolving_list_avail_size = max_irk_list_sz;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_resolving_list_cleanup
+ *
+ * Description Cleanup resolving list dynamic memory
+ *
+ * Parameters
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_ble_resolving_list_cleanup(void) {
+ tBTM_BLE_RESOLVE_Q* p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+
+ osi_free_and_reset((void**)&p_q->resolve_q_random_pseudo);
+ osi_free_and_reset((void**)&p_q->resolve_q_action);
+
+ controller_get_interface()->set_ble_resolving_list_max_size(0);
+
+ osi_free_and_reset((void**)&btm_cb.ble_ctr_cb.irk_list_mask);
+}
+#endif
diff --git a/mtkbt/code/bt/stack/btm/btm_dev.cc b/mtkbt/code/bt/stack/btm/btm_dev.cc
new file mode 100755
index 0000000..f8f5b58
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_dev.cc
@@ -0,0 +1,574 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the Bluetooth Device Manager
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * dev_class - Device Class
+ * bd_name - Name of the peer device. NULL if unknown.
+ * features - Remote device's features (up to 3 pages).
+ * NULL if not known
+ * trusted_mask - Bitwise OR of services that do not
+ * require authorization.
+ * (array of uint32_t)
+ * link_key - Connection link key. NULL if unknown.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
+ uint8_t* features, uint32_t trusted_mask[],
+ LINK_KEY link_key, uint8_t key_type, tBTM_IO_CAP io_cap,
+ uint8_t pin_length) {
+ BTM_TRACE_API("%s: link key type:%x", __func__, key_type);
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (!p_dev_rec) {
+ p_dev_rec = btm_sec_allocate_dev_rec();
+
+ memcpy(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ /* use default value for background connection params */
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+ } else {
+ /* "Bump" timestamp for existing record */
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+
+ /* TODO(eisenbach):
+ * Small refactor, but leaving original logic for now.
+ * On the surface, this does not make any sense at all. Why change the
+ * bond state for an existing device here? This logic should be verified
+ * as part of a larger refactor.
+ */
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+ }
+
+ if (dev_class) memcpy(p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);
+
+ memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
+
+ if (bd_name && bd_name[0]) {
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ strlcpy((char*)p_dev_rec->sec_bd_name, (char*)bd_name,
+ BTM_MAX_REM_BD_NAME_LEN);
+ }
+
+ p_dev_rec->num_read_pages = 0;
+ if (features) {
+ bool found = false;
+ memcpy(p_dev_rec->feature_pages, features,
+ sizeof(p_dev_rec->feature_pages));
+ for (int i = HCI_EXT_FEATURES_PAGE_MAX; !found && i >= 0; i--) {
+ for (int j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++) {
+ if (p_dev_rec->feature_pages[i][j] != 0) {
+ found = true;
+ p_dev_rec->num_read_pages = i + 1;
+ break;
+ }
+ }
+ }
+ } else {
+ memset(p_dev_rec->feature_pages, 0, sizeof(p_dev_rec->feature_pages));
+ }
+
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+ if (link_key) {
+ BTM_TRACE_EVENT("%s: BDA: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+ memcpy(p_dev_rec->link_key, link_key, LINK_KEY_LEN);
+ p_dev_rec->link_key_type = key_type;
+ p_dev_rec->pin_code_length = pin_length;
+
+ if (pin_length >= 16 || key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ // Set the flag if the link key was made by using either a 16 digit
+ // pin or MITM.
+ p_dev_rec->sec_flags |=
+ BTM_SEC_16_DIGIT_PIN_AUTHED | BTM_SEC_LINK_KEY_AUTHED;
+ }
+ }
+
+#if (BTIF_MIXED_MODE_INCLUDED == TRUE)
+ if (key_type < BTM_MAX_PRE_SM4_LKEY_TYPE)
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ else
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+#endif
+
+ p_dev_rec->rmt_io_caps = io_cap;
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecDeleteDevice
+ *
+ * Description Free resources associated with the device.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ *
+ * Returns true if removed OK, false if not found or ACL link is active
+ *
+ ******************************************************************************/
+bool BTM_SecDeleteDevice(BD_ADDR bd_addr) {
+ if (BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE) ||
+ BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_BR_EDR)) {
+ BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active",
+ __func__);
+ return false;
+ }
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ btm_sec_free_dev(p_dev_rec);
+ /* Tell controller to get rid of the link key, if it has one stored */
+ BTM_DeleteStoredLinkKey(bd_addr, NULL);
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClearSecurityFlags
+ *
+ * Description Reset the security flags (mark as not-paired) for a given
+ * remove device.
+ *
+ ******************************************************************************/
+extern void BTM_SecClearSecurityFlags(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) return;
+
+ p_dev_rec->sec_flags = 0;
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->sm4 = BTM_SM4_UNKNOWN;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecReadDevName
+ *
+ * Description Looks for the device name in the security database for the
+ * specified BD address.
+ *
+ * Returns Pointer to the name or NULL
+ *
+ ******************************************************************************/
+char* BTM_SecReadDevName(BD_ADDR bd_addr) {
+ char* p_name = NULL;
+ tBTM_SEC_DEV_REC* p_srec;
+
+ p_srec = btm_find_dev(bd_addr);
+ if (p_srec != NULL) p_name = (char*)p_srec->sec_bd_name;
+
+ return (p_name);
+}
+
+bool is_bd_addr_equal(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ BD_ADDR* bd_addr = static_cast<BD_ADDR*>(context);
+
+ if (!memcmp(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN)) return false;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_alloc_dev
+ *
+ * Description Look for the record in the device database for the record
+ * with specified address
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_sec_alloc_dev(BD_ADDR bd_addr) {
+ tBTM_INQ_INFO* p_inq_info;
+ BTM_TRACE_EVENT("btm_sec_alloc_dev");
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_sec_allocate_dev_rec();
+
+ /* Check with the BT manager if details about remote device are known */
+ /* outgoing connection */
+ p_inq_info = BTM_InqDbRead(bd_addr);
+ if (p_inq_info != NULL) {
+ memcpy(p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN);
+
+ p_dev_rec->device_type = p_inq_info->results.device_type;
+ p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
+ } else if (!memcmp(bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+ /* update conn params, use default value for background connection params */
+ memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
+
+ memcpy(p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_LE);
+ p_dev_rec->hci_handle = BTM_GetHCIConnHandle(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ return (p_dev_rec);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_free_dev
+ *
+ * Description Mark device record as not used
+ *
+ ******************************************************************************/
+void btm_sec_free_dev(tBTM_SEC_DEV_REC* p_dev_rec) {
+ /* Clear out any saved BLE keys */
+ btm_sec_clear_ble_keys(p_dev_rec);
+ list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_dev_support_switch
+ *
+ * Description This function is called by the L2CAP to check if remote
+ * device supports role switch
+ *
+ * Parameters: bd_addr - Address of the peer device
+ *
+ * Returns true if device is known and role switch is supported
+ *
+ ******************************************************************************/
+bool btm_dev_support_switch(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ uint8_t xx;
+ bool feature_empty = true;
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ /* Role switch is not allowed if a SCO is up */
+ if (btm_is_sco_active_by_bdaddr(bd_addr)) return (false);
+#endif
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec &&
+ controller_get_interface()->supports_master_slave_role_switch()) {
+ if (HCI_SWITCH_SUPPORTED(p_dev_rec->feature_pages[0])) {
+ BTM_TRACE_DEBUG("btm_dev_support_switch return true (feature found)");
+ return (true);
+ }
+
+ /* If the feature field is all zero, we never received them */
+ for (xx = 0; xx < BD_FEATURES_LEN; xx++) {
+ if (p_dev_rec->feature_pages[0][xx] != 0x00) {
+ feature_empty = false; /* at least one is != 0 */
+ break;
+ }
+ }
+
+ /* If we don't know peer's capabilities, assume it supports Role-switch */
+ if (feature_empty) {
+ BTM_TRACE_DEBUG("btm_dev_support_switch return true (feature empty)");
+ return (true);
+ }
+ }
+
+ BTM_TRACE_DEBUG("btm_dev_support_switch return false");
+ return (false);
+}
+
+bool is_handle_equal(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ uint16_t* handle = static_cast<uint16_t*>(context);
+
+ if (p_dev_rec->hci_handle == *handle || p_dev_rec->ble_hci_handle == *handle)
+ return false;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_find_dev_by_handle
+ *
+ * Description Look for the record in the device database for the record
+ * with specified handle
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle) {
+ list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_handle_equal, &handle);
+ if (n) return static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
+
+ return NULL;
+}
+
+bool is_address_equal(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ BD_ADDR* bd_addr = static_cast<BD_ADDR*>(context);
+
+ if (!memcmp(p_dev_rec->bd_addr, *bd_addr, BD_ADDR_LEN)) return false;
+ // If a LE random address is looking for device record
+ if (!memcmp(p_dev_rec->ble.pseudo_addr, *bd_addr, BD_ADDR_LEN)) return false;
+
+ if (btm_ble_addr_resolvable(*bd_addr, p_dev_rec)) return false;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_find_dev
+ *
+ * Description Look for the record in the device database for the record
+ * with specified BD address
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_find_dev(const BD_ADDR bd_addr) {
+ if (!bd_addr) return NULL;
+
+ list_node_t* n =
+ list_foreach(btm_cb.sec_dev_rec, is_address_equal, (void*)bd_addr);
+ if (n) return static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_consolidate_dev
+5**
+ * Description combine security records if identified as same peer
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec) {
+ tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ list_node_t* end = list_end(btm_cb.sec_dev_rec);
+ for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end;
+ node = list_next(node)) {
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+
+ if (p_target_rec == p_dev_rec) continue;
+
+ if (!memcmp(p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN)) {
+ memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC));
+ p_target_rec->ble = temp_rec.ble;
+ p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle;
+ p_target_rec->enc_key_size = temp_rec.enc_key_size;
+ p_target_rec->conn_params = temp_rec.conn_params;
+ p_target_rec->device_type |= temp_rec.device_type;
+ p_target_rec->sec_flags |= temp_rec.sec_flags;
+
+ p_target_rec->new_encryption_key_is_p256 =
+ temp_rec.new_encryption_key_is_p256;
+ p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br;
+ p_target_rec->bond_type = temp_rec.bond_type;
+
+ /* remove the combined record */
+ list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ break;
+ }
+
+ /* an RPA device entry is a duplicate of the target record */
+ if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec)) {
+ if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr,
+ BD_ADDR_LEN) == 0) {
+ p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type;
+ p_target_rec->device_type |= p_dev_rec->device_type;
+
+ /* remove the combined record */
+ list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ }
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_find_or_alloc_dev
+ *
+ * Description Look for the record in the device database for the record
+ * with specified BD address
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BTM_TRACE_EVENT("btm_find_or_alloc_dev");
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_sec_alloc_dev(bd_addr);
+ }
+ return (p_dev_rec);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_find_oldest_dev_rec
+ *
+ * Description Locates the oldest device in use. It first looks for
+ * the oldest non-paired device. If all devices are paired it
+ * returns the oldest paired device.
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+static tBTM_SEC_DEV_REC* btm_find_oldest_dev_rec(void) {
+ tBTM_SEC_DEV_REC* p_oldest = NULL;
+ uint32_t ts_oldest = 0xFFFFFFFF;
+ tBTM_SEC_DEV_REC* p_oldest_paired = NULL;
+ uint32_t ts_oldest_paired = 0xFFFFFFFF;
+
+ list_node_t* end = list_end(btm_cb.sec_dev_rec);
+ for (list_node_t* node = list_begin(btm_cb.sec_dev_rec); node != end;
+ node = list_next(node)) {
+ tBTM_SEC_DEV_REC* p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+
+ if ((p_dev_rec->sec_flags &
+ (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) == 0) {
+ // Device is not paired
+ if (p_dev_rec->timestamp < ts_oldest) {
+ p_oldest = p_dev_rec;
+ ts_oldest = p_dev_rec->timestamp;
+ }
+ } else {
+ // Paired device
+ if (p_dev_rec->timestamp < ts_oldest_paired) {
+ p_oldest_paired = p_dev_rec;
+ ts_oldest_paired = p_dev_rec->timestamp;
+ }
+ }
+ }
+
+ // If we did not find any non-paired devices, use the oldest paired one...
+ if (ts_oldest == 0xFFFFFFFF) p_oldest = p_oldest_paired;
+
+ return p_oldest;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_allocate_dev_rec
+ *
+ * Description Attempts to allocate a new device record. If we have
+ * exceeded the maximum number of allowable records to
+ * allocate, the oldest record will be deleted to make room
+ * for the new record.
+ *
+ * Returns Pointer to the newly allocated record
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void) {
+ tBTM_SEC_DEV_REC* p_dev_rec = NULL;
+
+ if (list_length(btm_cb.sec_dev_rec) > BTM_SEC_MAX_DEVICE_RECORDS) {
+ p_dev_rec = btm_find_oldest_dev_rec();
+ list_remove(btm_cb.sec_dev_rec, p_dev_rec);
+ }
+
+ p_dev_rec =
+ static_cast<tBTM_SEC_DEV_REC*>(osi_calloc(sizeof(tBTM_SEC_DEV_REC)));
+ list_append(btm_cb.sec_dev_rec, p_dev_rec);
+
+ // Initialize defaults
+ p_dev_rec->sec_flags = BTM_SEC_IN_USE;
+ p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ p_dev_rec->rmt_io_caps = BTM_IO_CAP_UNKNOWN;
+
+ return p_dev_rec;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_get_bond_type_dev
+ *
+ * Description Get the bond type for a device in the device database
+ * with specified BD address
+ *
+ * Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN
+ *
+ ******************************************************************************/
+tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec == NULL) return BOND_TYPE_UNKNOWN;
+
+ return p_dev_rec->bond_type;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_set_bond_type_dev
+ *
+ * Description Set the bond type for a device in the device database
+ * with specified BD address
+ *
+ * Returns true on success, otherwise false
+ *
+ ******************************************************************************/
+bool btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (p_dev_rec == NULL) return false;
+
+ p_dev_rec->bond_type = bond_type;
+ return true;
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_devctl.cc b/mtkbt/code/bt/stack/btm/btm_devctl.cc
new file mode 100755
index 0000000..15b17f3
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_devctl.cc
@@ -0,0 +1,842 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions that handle BTM interface functions for the
+ * Bluetooth device including Rest, HCI buffer size and others
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btcore/include/module.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+
+#include "gatt_int.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+extern thread_t* bt_workqueue_thread;
+
+/******************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/******************************************************************************/
+
+#ifndef BTM_DEV_RESET_TIMEOUT
+#define BTM_DEV_RESET_TIMEOUT 4
+#endif
+
+// TODO: Reevaluate this value in the context of timers with ms granularity
+#define BTM_DEV_NAME_REPLY_TIMEOUT_MS \
+ (2 * 1000) /* 2 seconds for name reply \
+ */
+
+#define BTM_INFO_TIMEOUT 5 /* 5 seconds for info response */
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+
+static void btm_decode_ext_features_page(uint8_t page_number,
+ const BD_FEATURES p_features);
+
+/*******************************************************************************
+ *
+ * Function btm_dev_init
+ *
+ * Description This function is on the BTM startup
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_dev_init(void) {
+ /* Initialize nonzero defaults */
+ memset(btm_cb.cfg.bd_name, 0, sizeof(tBTM_LOC_BD_NAME));
+
+ btm_cb.devcb.read_local_name_timer = alarm_new("btm.read_local_name_timer");
+ btm_cb.devcb.read_rssi_timer = alarm_new("btm.read_rssi_timer");
+ btm_cb.devcb.read_link_quality_timer =
+ alarm_new("btm.read_link_quality_timer");
+ btm_cb.devcb.read_inq_tx_power_timer =
+ alarm_new("btm.read_inq_tx_power_timer");
+ btm_cb.devcb.qos_setup_timer = alarm_new("btm.qos_setup_timer");
+ btm_cb.devcb.read_tx_power_timer = alarm_new("btm.read_tx_power_timer");
+
+ btm_cb.btm_acl_pkt_types_supported =
+ BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1 +
+ BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3 +
+ BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5;
+
+ btm_cb.btm_sco_pkt_types_supported =
+ ESCO_PKT_TYPES_MASK_HV1 + ESCO_PKT_TYPES_MASK_HV2 +
+ ESCO_PKT_TYPES_MASK_HV3 + ESCO_PKT_TYPES_MASK_EV3 +
+ ESCO_PKT_TYPES_MASK_EV4 + ESCO_PKT_TYPES_MASK_EV5;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_db_reset
+ *
+ * Description This function is called by BTM_DeviceReset and clears out
+ * any pending callbacks for inquiries, discoveries, other
+ * pending functions that may be in progress.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_db_reset(void) {
+ tBTM_CMPL_CB* p_cb;
+ tBTM_STATUS status = BTM_DEV_RESET;
+
+ btm_inq_db_reset();
+
+ if (btm_cb.devcb.p_rln_cmpl_cb) {
+ p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb) (*p_cb)((void*)NULL);
+ }
+
+ if (btm_cb.devcb.p_rssi_cmpl_cb) {
+ p_cb = btm_cb.devcb.p_rssi_cmpl_cb;
+ btm_cb.devcb.p_rssi_cmpl_cb = NULL;
+
+ if (p_cb) (*p_cb)((tBTM_RSSI_RESULTS*)&status);
+ }
+}
+
+bool set_sec_state_idle(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ return true;
+}
+
+static void reset_complete(void* result) {
+ CHECK(result == FUTURE_SUCCESS);
+ const controller_t* controller = controller_get_interface();
+
+ /* Tell L2CAP that all connections are gone */
+ l2cu_device_reset();
+
+ /* Clear current security state */
+ list_foreach(btm_cb.sec_dev_rec, set_sec_state_idle, NULL);
+
+ /* After the reset controller should restore all parameters to defaults. */
+ btm_cb.btm_inq_vars.inq_counter = 1;
+ btm_cb.btm_inq_vars.inq_scan_window = HCI_DEF_INQUIRYSCAN_WINDOW;
+ btm_cb.btm_inq_vars.inq_scan_period = HCI_DEF_INQUIRYSCAN_INTERVAL;
+ btm_cb.btm_inq_vars.inq_scan_type = HCI_DEF_SCAN_TYPE;
+
+ btm_cb.btm_inq_vars.page_scan_window = HCI_DEF_PAGESCAN_WINDOW;
+ btm_cb.btm_inq_vars.page_scan_period = HCI_DEF_PAGESCAN_INTERVAL;
+ btm_cb.btm_inq_vars.page_scan_type = HCI_DEF_SCAN_TYPE;
+
+ btm_cb.ble_ctr_cb.conn_state = BLE_CONN_IDLE;
+ btm_cb.ble_ctr_cb.bg_conn_type = BTM_BLE_CONN_NONE;
+ gatt_reset_bgdev_list();
+
+ btm_pm_reset();
+
+ l2c_link_processs_num_bufs(controller->get_acl_buffer_count_classic());
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ /* Set up the BLE privacy settings */
+ if (controller->supports_ble() && controller->supports_ble_privacy() &&
+ controller->get_ble_resolving_list_max_size() > 0) {
+ btm_ble_resolving_list_init(controller->get_ble_resolving_list_max_size());
+ /* set the default random private address timeout */
+ btsnd_hcic_ble_set_rand_priv_addr_timeout(BTM_BLE_PRIVATE_ADDR_INT_MS /
+ 1000);
+ }
+#endif
+
+ if (controller->supports_ble()) {
+ btm_ble_white_list_init(controller->get_ble_white_list_size());
+ l2c_link_processs_ble_num_bufs(controller->get_acl_buffer_count_ble());
+ }
+
+ BTM_SetPinType(btm_cb.cfg.pin_type, btm_cb.cfg.pin_code,
+ btm_cb.cfg.pin_code_len);
+
+ for (int i = 0; i <= controller->get_last_features_classic_index(); i++) {
+ btm_decode_ext_features_page(i,
+ controller->get_features_classic(i)->as_array);
+ }
+
+ btm_report_device_status(BTM_DEV_STATUS_UP);
+}
+
+// TODO(zachoverflow): remove this function
+void BTM_DeviceReset(UNUSED_ATTR tBTM_CMPL_CB* p_cb) {
+ /* Flush all ACL connections */
+ btm_acl_device_down();
+
+ /* Clear the callback, so application would not hang on reset */
+ btm_db_reset();
+
+ module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
+ bt_workqueue_thread, reset_complete);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsDeviceUp
+ *
+ * Description This function is called to check if the device is up.
+ *
+ * Returns true if device is up, else false
+ *
+ ******************************************************************************/
+bool BTM_IsDeviceUp(void) { return controller_get_interface()->get_is_ready(); }
+
+/*******************************************************************************
+ *
+ * Function btm_read_local_name_timeout
+ *
+ * Description Callback when reading the local name times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_local_name_timeout(UNUSED_ATTR void* data) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+ if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_decode_ext_features_page
+ *
+ * Description This function is decodes a features page.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_decode_ext_features_page(uint8_t page_number,
+ const uint8_t* p_features) {
+ BTM_TRACE_DEBUG("btm_decode_ext_features_page page: %d", page_number);
+ switch (page_number) {
+ /* Extended (Legacy) Page 0 */
+ case 0:
+
+ /* Create ACL supported packet types mask */
+ btm_cb.btm_acl_pkt_types_supported =
+ (BTM_ACL_PKT_TYPES_MASK_DH1 + BTM_ACL_PKT_TYPES_MASK_DM1);
+
+ if (HCI_3_SLOT_PACKETS_SUPPORTED(p_features))
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_DH3 + BTM_ACL_PKT_TYPES_MASK_DM3);
+
+ if (HCI_5_SLOT_PACKETS_SUPPORTED(p_features))
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_DH5 + BTM_ACL_PKT_TYPES_MASK_DM5);
+
+ /* Add in EDR related ACL types */
+ if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
+ }
+
+ if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) {
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 + BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+
+ /* Check to see if 3 and 5 slot packets are available */
+ if (HCI_EDR_ACL_2MPS_SUPPORTED(p_features) ||
+ HCI_EDR_ACL_3MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_features))
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);
+
+ if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_features))
+ btm_cb.btm_acl_pkt_types_supported |=
+ (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 +
+ BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
+ }
+
+ BTM_TRACE_DEBUG("Local supported ACL packet types: 0x%04x",
+ btm_cb.btm_acl_pkt_types_supported);
+
+ /* Create (e)SCO supported packet types mask */
+ btm_cb.btm_sco_pkt_types_supported = 0;
+#if (BTM_SCO_INCLUDED == TRUE)
+ btm_cb.sco_cb.esco_supported = false;
+#endif
+ if (HCI_SCO_LINK_SUPPORTED(p_features)) {
+ btm_cb.btm_sco_pkt_types_supported = ESCO_PKT_TYPES_MASK_HV1;
+
+ if (HCI_HV2_PACKETS_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_HV2;
+
+ if (HCI_HV3_PACKETS_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_HV3;
+ }
+
+ if (HCI_ESCO_EV3_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV3;
+
+ if (HCI_ESCO_EV4_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV4;
+
+ if (HCI_ESCO_EV5_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_EV5;
+ if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK) {
+ btm_cb.sco_cb.esco_supported = true;
+
+ /* Add in EDR related eSCO types */
+ if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_NO_2_EV5;
+ } else {
+ btm_cb.btm_sco_pkt_types_supported |=
+ (ESCO_PKT_TYPES_MASK_NO_2_EV3 + ESCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+
+ if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_features)) {
+ if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
+ btm_cb.btm_sco_pkt_types_supported |= ESCO_PKT_TYPES_MASK_NO_3_EV5;
+ } else {
+ btm_cb.btm_sco_pkt_types_supported |=
+ (ESCO_PKT_TYPES_MASK_NO_3_EV3 + ESCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+
+ BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x",
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Create Default Policy Settings */
+ if (HCI_SWITCH_SUPPORTED(p_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;
+
+ if (HCI_HOLD_MODE_SUPPORTED(p_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE;
+
+ if (HCI_SNIFF_MODE_SUPPORTED(p_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE;
+
+ if (HCI_PARK_MODE_SUPPORTED(p_features))
+ btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE;
+ else
+ btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE;
+
+ btm_sec_dev_reset();
+
+ if (HCI_LMP_INQ_RSSI_SUPPORTED(p_features)) {
+ if (HCI_EXT_INQ_RSP_SUPPORTED(p_features))
+ BTM_SetInquiryMode(BTM_INQ_RESULT_EXTENDED);
+ else
+ BTM_SetInquiryMode(BTM_INQ_RESULT_WITH_RSSI);
+ }
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if (HCI_NON_FLUSHABLE_PB_SUPPORTED(p_features))
+ l2cu_set_non_flushable_pbf(true);
+ else
+ l2cu_set_non_flushable_pbf(false);
+#endif
+ BTM_SetPageScanType(BTM_DEFAULT_SCAN_TYPE);
+ BTM_SetInquiryScanType(BTM_DEFAULT_SCAN_TYPE);
+
+ break;
+
+ default:
+ BTM_TRACE_WARNING("%s: feature page %d ignored", __func__, page_number);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLocalDeviceName
+ *
+ * Description This function is called to set the local device name.
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName(char* p_name) {
+ uint8_t* p;
+
+ if (!p_name || !p_name[0] || (strlen((char*)p_name) > BD_NAME_LEN))
+ return (BTM_ILLEGAL_VALUE);
+
+ if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET);
+ /* Save the device name if local storage is enabled */
+ p = (uint8_t*)btm_cb.cfg.bd_name;
+ if (p != (uint8_t*)p_name)
+ strlcpy(btm_cb.cfg.bd_name, p_name, BTM_MAX_LOC_BD_NAME_LEN);
+
+ btsnd_hcic_change_name(p);
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceName
+ *
+ * Description This function is called to read the local device name.
+ *
+ * Returns status of the operation
+ * If success, BTM_SUCCESS is returned and p_name points stored
+ * local device name
+ * If BTM doesn't store local device name, BTM_NO_RESOURCES is
+ * is returned and p_name is set to NULL
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceName(char** p_name) {
+ *p_name = btm_cb.cfg.bd_name;
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceNameFromController
+ *
+ * Description Get local device name from controller. Do not use cached
+ * name (used to get chip-id prior to btm reset complete).
+ *
+ * Returns BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceNameFromController(
+ tBTM_CMPL_CB* p_rln_cmpl_cback) {
+ /* Check if rln already in progress */
+ if (btm_cb.devcb.p_rln_cmpl_cb) return (BTM_NO_RESOURCES);
+
+ /* Save callback */
+ btm_cb.devcb.p_rln_cmpl_cb = p_rln_cmpl_cback;
+
+ btsnd_hcic_read_name();
+ alarm_set_on_queue(btm_cb.devcb.read_local_name_timer,
+ BTM_DEV_NAME_REPLY_TIMEOUT_MS, btm_read_local_name_timeout,
+ NULL, btu_general_alarm_queue);
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_local_name_complete
+ *
+ * Description This function is called when local name read complete.
+ * message is received from the HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_local_name_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_rln_cmpl_cb;
+ uint8_t status;
+
+ alarm_cancel(btm_cb.devcb.read_local_name_timer);
+
+ /* If there was a callback address for read local name, call it */
+ btm_cb.devcb.p_rln_cmpl_cb = NULL;
+
+ if (p_cb) {
+ STREAM_TO_UINT8(status, p);
+
+ if (status == HCI_SUCCESS)
+ (*p_cb)(p);
+ else
+ (*p_cb)(NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDeviceClass
+ *
+ * Description This function is called to set the local device class
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class) {
+ if (!memcmp(btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN))
+ return (BTM_SUCCESS);
+
+ memcpy(btm_cb.devcb.dev_class, dev_class, DEV_CLASS_LEN);
+
+ if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET);
+
+ btsnd_hcic_write_dev_class(dev_class);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceClass
+ *
+ * Description This function is called to read the local device class
+ *
+ * Returns pointer to the device class
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadDeviceClass(void) {
+ return ((uint8_t*)btm_cb.devcb.dev_class);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalFeatures
+ *
+ * Description This function is called to read the local features
+ *
+ * Returns pointer to the local features string
+ *
+ ******************************************************************************/
+// TODO(zachoverflow): get rid of this function
+uint8_t* BTM_ReadLocalFeatures(void) {
+ // Discarding const modifier for now, until this function dies
+ return (uint8_t*)controller_get_interface()
+ ->get_features_classic(0)
+ ->as_array;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForDeviceStatusNotif
+ *
+ * Description This function is called to register for device status
+ * change notifications.
+ *
+ * If one registration is already there calling function should
+ * save the pointer to the function that is return and
+ * call it when processing of the event is complete
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_DEV_STATUS_CB* BTM_RegisterForDeviceStatusNotif(tBTM_DEV_STATUS_CB* p_cb) {
+ tBTM_DEV_STATUS_CB* p_prev = btm_cb.devcb.p_dev_status_cb;
+
+ btm_cb.devcb.p_dev_status_cb = p_cb;
+ return (p_prev);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_VendorSpecificCommand
+ *
+ * Description Send a vendor specific HCI command to the controller.
+ *
+ * Notes
+ * Opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC.
+ *
+ ******************************************************************************/
+void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len,
+ uint8_t* p_param_buf, tBTM_VSC_CMPL_CB* p_cb) {
+ /* Allocate a buffer to hold HCI command plus the callback function */
+ void* p_buf = osi_malloc(sizeof(BT_HDR) + sizeof(tBTM_CMPL_CB*) + param_len +
+ HCIC_PREAMBLE_SIZE);
+
+ BTM_TRACE_EVENT("BTM: %s: Opcode: 0x%04X, ParamLen: %i.", __func__, opcode,
+ param_len);
+
+ /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */
+ btsnd_hcic_vendor_spec_cmd(p_buf, opcode, param_len, p_param_buf,
+ (void*)p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_vsc_complete
+ *
+ * Description This function is called when local HCI Vendor Specific
+ * Command complete message is received from the HCI.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_vsc_complete(uint8_t* p, uint16_t opcode, uint16_t evt_len,
+ tBTM_CMPL_CB* p_vsc_cplt_cback) {
+ tBTM_VSC_CMPL vcs_cplt_params;
+
+ /* If there was a callback address for vcs complete, call it */
+ if (p_vsc_cplt_cback) {
+ /* Pass paramters to the callback function */
+ vcs_cplt_params.opcode = opcode; /* Number of bytes in return info */
+ vcs_cplt_params.param_len = evt_len; /* Number of bytes in return info */
+ vcs_cplt_params.p_param_buf = p;
+ (*p_vsc_cplt_cback)(
+ &vcs_cplt_params); /* Call the VSC complete callback function */
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForVSEvents
+ *
+ * Description This function is called to register/deregister for vendor
+ * specific HCI events.
+ *
+ * If is_register=true, then the function will be registered;
+ * otherwise, the the function will be deregistered.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_BUSY if maximum number of callbacks have already been
+ * registered.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register) {
+ tBTM_STATUS retval = BTM_SUCCESS;
+ uint8_t i, free_idx = BTM_MAX_VSE_CALLBACKS;
+
+ /* See if callback is already registered */
+ for (i = 0; i < BTM_MAX_VSE_CALLBACKS; i++) {
+ if (btm_cb.devcb.p_vend_spec_cb[i] == NULL) {
+ /* Found a free slot. Store index */
+ free_idx = i;
+ } else if (btm_cb.devcb.p_vend_spec_cb[i] == p_cb) {
+ /* Found callback in lookup table. If deregistering, clear the entry. */
+ if (is_register == false) {
+ btm_cb.devcb.p_vend_spec_cb[i] = NULL;
+ BTM_TRACE_EVENT("BTM Deregister For VSEvents is successfully");
+ }
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* Didn't find callback. Add callback to free slot if registering */
+ if (is_register) {
+ if (free_idx < BTM_MAX_VSE_CALLBACKS) {
+ btm_cb.devcb.p_vend_spec_cb[free_idx] = p_cb;
+ BTM_TRACE_EVENT("BTM Register For VSEvents is successfully");
+ } else {
+ /* No free entries available */
+ BTM_TRACE_ERROR("BTM_RegisterForVSEvents: too many callbacks registered");
+
+ retval = BTM_NO_RESOURCES;
+ }
+ }
+
+ return (retval);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_vendor_specific_evt
+ *
+ * Description Process event HCI_VENDOR_SPECIFIC_EVT
+ *
+ * Note: Some controllers do not send command complete, so
+ * the callback and busy flag are cleared here also.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_vendor_specific_evt(uint8_t* p, uint8_t evt_len) {
+ uint8_t i;
+
+ BTM_TRACE_DEBUG("BTM Event: Vendor Specific event from controller");
+
+ for (i = 0; i < BTM_MAX_VSE_CALLBACKS; i++) {
+ if (btm_cb.devcb.p_vend_spec_cb[i])
+ (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_WritePageTimeout
+ *
+ * Description Send HCI Write Page Timeout.
+ *
+ ******************************************************************************/
+void BTM_WritePageTimeout(uint16_t timeout) {
+ BTM_TRACE_EVENT("BTM: BTM_WritePageTimeout: Timeout: %d.", timeout);
+
+ /* Send the HCI command */
+ btsnd_hcic_write_page_tout(timeout);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteVoiceSettings
+ *
+ * Description Send HCI Write Voice Settings command.
+ * See hcidefs.h for settings bitmask values.
+ *
+ ******************************************************************************/
+void BTM_WriteVoiceSettings(uint16_t settings) {
+ BTM_TRACE_EVENT("BTM: BTM_WriteVoiceSettings: Settings: 0x%04x.", settings);
+
+ /* Send the HCI command */
+ btsnd_hcic_write_voice_settings((uint16_t)(settings & 0x03ff));
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_EnableTestMode
+ *
+ * Description Send HCI the enable device under test command.
+ *
+ * Note: Controller can only be taken out of this mode by
+ * resetting the controller.
+ *
+ * Returns
+ * BTM_SUCCESS Command sent.
+ * BTM_NO_RESOURCES If out of resources to send the command.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_EnableTestMode(void) {
+ uint8_t cond;
+
+ BTM_TRACE_EVENT("BTM: BTM_EnableTestMode");
+
+ /* set auto accept connection as this is needed during test mode */
+ /* Allocate a buffer to hold HCI command */
+ cond = HCI_DO_AUTO_ACCEPT_CONNECT;
+ btsnd_hcic_set_event_filter(HCI_FILTER_CONNECTION_SETUP,
+ HCI_FILTER_COND_NEW_DEVICE, &cond, sizeof(cond));
+
+ /* put device to connectable mode */
+ if (BTM_SetConnectability(BTM_CONNECTABLE, BTM_DEFAULT_CONN_WINDOW,
+ BTM_DEFAULT_CONN_INTERVAL) != BTM_SUCCESS) {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* put device to discoverable mode */
+ if (BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE, BTM_DEFAULT_DISC_WINDOW,
+ BTM_DEFAULT_DISC_INTERVAL) != BTM_SUCCESS) {
+ return BTM_NO_RESOURCES;
+ }
+
+ /* mask off all of event from controller */
+ hci_layer_get_interface()->transmit_command(
+ hci_packet_factory_get_interface()->make_set_event_mask(
+ (const bt_event_mask_t*)("\x00\x00\x00\x00\x00\x00\x00\x00")),
+ NULL, NULL, NULL);
+
+ /* Send the HCI command */
+ btsnd_hcic_enable_test_mode();
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_DeleteStoredLinkKey
+ *
+ * Description This function is called to delete link key for the specified
+ * device addresses from the NVRAM storage attached to the
+ * Bluetooth controller.
+ *
+ * Parameters: bd_addr - Addresses of the devices
+ * p_cb - Call back function to be called to return
+ * the results
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB* p_cb) {
+ BD_ADDR local_bd_addr;
+ bool delete_all_flag = false;
+
+ /* Check if the previous command is completed */
+ if (btm_cb.devcb.p_stored_link_key_cmpl_cb) return (BTM_BUSY);
+
+ if (!bd_addr) {
+ /* This is to delete all link keys */
+ delete_all_flag = true;
+
+ /* We don't care the BD address. Just pass a non zero pointer */
+ bd_addr = local_bd_addr;
+ }
+
+ BTM_TRACE_EVENT("BTM: BTM_DeleteStoredLinkKey: delete_all_flag: %s",
+ delete_all_flag ? "true" : "false");
+
+ /* Send the HCI command */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = p_cb;
+ btsnd_hcic_delete_stored_key(bd_addr, delete_all_flag);
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_delete_stored_link_key_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the delete stored link key
+ * command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_delete_stored_link_key_complete(uint8_t* p) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb;
+ tBTM_DELETE_STORED_LINK_KEY_COMPLETE result;
+
+ /* If there was a callback registered for read stored link key, call it */
+ btm_cb.devcb.p_stored_link_key_cmpl_cb = NULL;
+
+ if (p_cb) {
+ /* Set the call back event to indicate command complete */
+ result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS;
+
+ /* Extract the result fields from the HCI event */
+ STREAM_TO_UINT8(result.status, p);
+ STREAM_TO_UINT16(result.num_keys, p);
+
+ /* Call the call back and pass the result */
+ (*p_cb)(&result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_report_device_status
+ *
+ * Description This function is called when there is a change in the device
+ * status. This function will report the new device status to
+ * the application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_report_device_status(tBTM_DEV_STATUS status) {
+ tBTM_DEV_STATUS_CB* p_cb = btm_cb.devcb.p_dev_status_cb;
+
+ /* Call the call back to pass the device status to application */
+ if (p_cb) (*p_cb)(status);
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_inq.cc b/mtkbt/code/bt/stack/btm/btm_inq.cc
new file mode 100755
index 0000000..7f9cb40
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_inq.cc
@@ -0,0 +1,2687 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions that handle inquiries. These include
+ * setting discoverable mode, controlling the mode of the Baseband, and
+ * maintaining a small database of inquiry responses, with API for people
+ * to browse it.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "device/include/controller.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "advertise_data_parser.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+/* 3 second timeout waiting for responses */
+#define BTM_INQ_REPLY_TIMEOUT_MS (3 * 1000)
+
+/* TRUE to enable DEBUG traces for btm_inq */
+#ifndef BTM_INQ_DEBUG
+#define BTM_INQ_DEBUG FALSE
+#endif
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/******************************************************************************/
+static const LAP general_inq_lap = {0x9e, 0x8b, 0x33};
+static const LAP limited_inq_lap = {0x9e, 0x8b, 0x00};
+
+const uint16_t BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] = {
+ UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+ /* UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */
+ /* UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */
+ UUID_SERVCLASS_SERIAL_PORT, UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+ UUID_SERVCLASS_DIALUP_NETWORKING, UUID_SERVCLASS_IRMC_SYNC,
+ UUID_SERVCLASS_OBEX_OBJECT_PUSH, UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ UUID_SERVCLASS_IRMC_SYNC_COMMAND, UUID_SERVCLASS_HEADSET,
+ UUID_SERVCLASS_CORDLESS_TELEPHONY, UUID_SERVCLASS_AUDIO_SOURCE,
+ UUID_SERVCLASS_AUDIO_SINK, UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+ /* UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */
+ UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ /* UUID_SERVCLASS_VIDEO_CONFERENCING, */
+ UUID_SERVCLASS_INTERCOM, UUID_SERVCLASS_FAX,
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ /* UUID_SERVCLASS_WAP, */
+ /* UUID_SERVCLASS_WAP_CLIENT, */
+ UUID_SERVCLASS_PANU, UUID_SERVCLASS_NAP, UUID_SERVCLASS_GN,
+ UUID_SERVCLASS_DIRECT_PRINTING,
+ /* UUID_SERVCLASS_REFERENCE_PRINTING, */
+ UUID_SERVCLASS_IMAGING, UUID_SERVCLASS_IMAGING_RESPONDER,
+ UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE, UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+ UUID_SERVCLASS_HF_HANDSFREE, UUID_SERVCLASS_AG_HANDSFREE,
+ UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+ /* UUID_SERVCLASS_REFLECTED_UI, */
+ UUID_SERVCLASS_BASIC_PRINTING, UUID_SERVCLASS_PRINTING_STATUS,
+ UUID_SERVCLASS_HUMAN_INTERFACE, UUID_SERVCLASS_CABLE_REPLACEMENT,
+ UUID_SERVCLASS_HCRP_PRINT, UUID_SERVCLASS_HCRP_SCAN,
+ /* UUID_SERVCLASS_COMMON_ISDN_ACCESS, */
+ /* UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */
+ /* UUID_SERVCLASS_UDI_MT, */
+ /* UUID_SERVCLASS_UDI_TA, */
+ /* UUID_SERVCLASS_VCP, */
+ UUID_SERVCLASS_SAP, UUID_SERVCLASS_PBAP_PCE, UUID_SERVCLASS_PBAP_PSE,
+ UUID_SERVCLASS_PHONE_ACCESS, UUID_SERVCLASS_HEADSET_HS,
+ UUID_SERVCLASS_PNP_INFORMATION,
+ /* UUID_SERVCLASS_GENERIC_NETWORKING, */
+ /* UUID_SERVCLASS_GENERIC_FILETRANSFER, */
+ /* UUID_SERVCLASS_GENERIC_AUDIO, */
+ /* UUID_SERVCLASS_GENERIC_TELEPHONY, */
+ /* UUID_SERVCLASS_UPNP_SERVICE, */
+ /* UUID_SERVCLASS_UPNP_IP_SERVICE, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */
+ /* UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */
+ UUID_SERVCLASS_VIDEO_SOURCE, UUID_SERVCLASS_VIDEO_SINK,
+ /* UUID_SERVCLASS_VIDEO_DISTRIBUTION */
+ UUID_SERVCLASS_MESSAGE_ACCESS, UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+ UUID_SERVCLASS_HDP_SOURCE, UUID_SERVCLASS_HDP_SINK};
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void btm_initiate_inquiry(tBTM_INQUIRY_VAR_ST* p_inq);
+static tBTM_STATUS btm_set_inq_event_filter(uint8_t filter_cond_type,
+ tBTM_INQ_FILT_COND* p_filt_cond);
+static void btm_clr_inq_result_flt(void);
+
+static uint8_t btm_convert_uuid_to_eir_service(uint16_t uuid16);
+static void btm_set_eir_uuid(uint8_t* p_eir, tBTM_INQ_RESULTS* p_results);
+static const uint8_t* btm_eir_get_uuid_list(uint8_t* p_eir, size_t eir_len,
+ uint8_t uuid_size,
+ uint8_t* p_num_uuid,
+ uint8_t* p_uuid_list_type);
+static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid,
+ uint8_t uuid_size);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDiscoverability
+ *
+ * Description This function is called to set the device into or out of
+ * discoverable mode. Discoverable mode means inquiry
+ * scans are enabled. If a value of '0' is entered for window
+ * or interval, the default values are used.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_BUSY if a setting of the filter is already in progress
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
+ uint16_t interval) {
+ uint8_t scan_mode = 0;
+ uint16_t service_class;
+ uint8_t* p_cod;
+ uint8_t major, minor;
+ DEV_CLASS cod;
+ LAP temp_lap[2];
+ bool is_limited;
+ bool cod_limited;
+
+ BTM_TRACE_API("BTM_SetDiscoverability");
+ if (controller_get_interface()->supports_ble()) {
+ if (btm_ble_set_discoverability((uint16_t)(inq_mode)) == BTM_SUCCESS) {
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |=
+ (inq_mode & BTM_BLE_DISCOVERABLE_MASK);
+ }
+ }
+ inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
+
+ /*** Check mode parameter ***/
+ if (inq_mode > BTM_MAX_DISCOVERABLE) return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET);
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window) window = BTM_DEFAULT_DISC_WINDOW;
+
+ if (!interval) interval = BTM_DEFAULT_DISC_INTERVAL;
+
+ BTM_TRACE_API(
+ "BTM_SetDiscoverability: mode %d [NonDisc-0, Lim-1, Gen-2], window "
+ "0x%04x, interval 0x%04x",
+ inq_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (inq_mode != BTM_NON_DISCOVERABLE) {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_INQUIRYSCAN_WINDOW ||
+ window > HCI_MAX_INQUIRYSCAN_WINDOW ||
+ interval < HCI_MIN_INQUIRYSCAN_INTERVAL ||
+ interval > HCI_MAX_INQUIRYSCAN_INTERVAL || window > interval) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+ }
+
+ /* Set the IAC if needed */
+ if (inq_mode != BTM_NON_DISCOVERABLE) {
+ if (inq_mode & BTM_LIMITED_DISCOVERABLE) {
+ /* Use the GIAC and LIAC codes for limited discoverable mode */
+ memcpy(temp_lap[0], limited_inq_lap, LAP_LEN);
+ memcpy(temp_lap[1], general_inq_lap, LAP_LEN);
+
+ btsnd_hcic_write_cur_iac_lap(2, (LAP * const)temp_lap);
+ } else {
+ btsnd_hcic_write_cur_iac_lap(1, (LAP * const) & general_inq_lap);
+ }
+
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+ }
+
+ /* Send down the inquiry scan window and period if changed */
+ if ((window != btm_cb.btm_inq_vars.inq_scan_window) ||
+ (interval != btm_cb.btm_inq_vars.inq_scan_period)) {
+ btsnd_hcic_write_inqscan_cfg(interval, window);
+ btm_cb.btm_inq_vars.inq_scan_window = window;
+ btm_cb.btm_inq_vars.inq_scan_period = interval;
+ }
+
+ if (btm_cb.btm_inq_vars.connectable_mode & BTM_CONNECTABLE_MASK)
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+
+ btsnd_hcic_write_scan_enable(scan_mode);
+ btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_DISCOVERABLE_MASK);
+ btm_cb.btm_inq_vars.discoverable_mode |= inq_mode;
+
+ /* Change the service class bit if mode has changed */
+ p_cod = BTM_ReadDeviceClass();
+ BTM_COD_SERVICE_CLASS(service_class, p_cod);
+ is_limited = (inq_mode & BTM_LIMITED_DISCOVERABLE) ? true : false;
+ cod_limited = (service_class & BTM_COD_SERVICE_LMTD_DISCOVER) ? true : false;
+ if (is_limited ^ cod_limited) {
+ BTM_COD_MINOR_CLASS(minor, p_cod);
+ BTM_COD_MAJOR_CLASS(major, p_cod);
+ if (is_limited)
+ service_class |= BTM_COD_SERVICE_LMTD_DISCOVER;
+ else
+ service_class &= ~BTM_COD_SERVICE_LMTD_DISCOVER;
+
+ FIELDS_TO_COD(cod, minor, major, service_class);
+ (void)BTM_SetDeviceClass(cod);
+ }
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryScanType
+ *
+ * Description This function is called to set the iquiry scan-type to
+ * standard or interlaced.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type) {
+ BTM_TRACE_API("BTM_SetInquiryScanType");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD &&
+ scan_type != BTM_SCAN_TYPE_INTERLACED)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!controller_get_interface()->supports_interlaced_inquiry_scan())
+ return (BTM_MODE_UNSUPPORTED);
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.inq_scan_type) {
+ if (BTM_IsDeviceUp()) {
+ btsnd_hcic_write_inqscan_type((uint8_t)scan_type);
+ btm_cb.btm_inq_vars.inq_scan_type = scan_type;
+ } else
+ return (BTM_WRONG_MODE);
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPageScanType
+ *
+ * Description This function is called to set the page scan-type to
+ * standard or interlaced.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type) {
+ BTM_TRACE_API("BTM_SetPageScanType");
+ if (scan_type != BTM_SCAN_TYPE_STANDARD &&
+ scan_type != BTM_SCAN_TYPE_INTERLACED)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* whatever app wants if device is not 1.2 scan type should be STANDARD */
+ if (!controller_get_interface()->supports_interlaced_inquiry_scan())
+ return (BTM_MODE_UNSUPPORTED);
+
+ /* Check for scan type if configuration has been changed */
+ if (scan_type != btm_cb.btm_inq_vars.page_scan_type) {
+ if (BTM_IsDeviceUp()) {
+ btsnd_hcic_write_pagescan_type((uint8_t)scan_type);
+ btm_cb.btm_inq_vars.page_scan_type = scan_type;
+ } else
+ return (BTM_WRONG_MODE);
+ }
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryMode
+ *
+ * Description This function is called to set standard or with RSSI
+ * mode of the inquiry for local device.
+ *
+ * Output Params: mode - standard, with RSSI, extended
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) {
+ const controller_t* controller = controller_get_interface();
+ BTM_TRACE_API("BTM_SetInquiryMode");
+ if (mode == BTM_INQ_RESULT_STANDARD) {
+ /* mandatory mode */
+ } else if (mode == BTM_INQ_RESULT_WITH_RSSI) {
+ if (!controller->supports_rssi_with_inquiry_results())
+ return (BTM_MODE_UNSUPPORTED);
+ } else if (mode == BTM_INQ_RESULT_EXTENDED) {
+ if (!controller->supports_extended_inquiry_response())
+ return (BTM_MODE_UNSUPPORTED);
+ } else
+ return (BTM_ILLEGAL_VALUE);
+
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ btsnd_hcic_write_inquiry_mode(mode);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDiscoverability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ *
+ * Output Params: p_window - current inquiry scan duration
+ * p_interval - current inquiry scan interval
+ *
+ * Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ * BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
+ BTM_TRACE_API("BTM_ReadDiscoverability");
+ if (p_window) *p_window = btm_cb.btm_inq_vars.inq_scan_window;
+
+ if (p_interval) *p_interval = btm_cb.btm_inq_vars.inq_scan_period;
+
+ return (btm_cb.btm_inq_vars.discoverable_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPeriodicInquiryMode
+ *
+ * Description This function is called to set the device periodic inquiry
+ * mode. If the duration is zero, the periodic inquiry mode is
+ * cancelled.
+ *
+ * Note: We currently do not allow concurrent inquiry and
+ * periodic inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * max_delay - maximum amount of time between successive
+ * inquiries
+ * min_delay - minimum amount of time between successive
+ * inquiries
+ * p_results_cb - callback returning pointer to results
+ * (tBTM_INQ_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully started
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_BUSY - if an inquiry is already active
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS* p_inqparms,
+ uint16_t max_delay, uint16_t min_delay,
+ tBTM_INQ_RESULTS_CB* p_results_cb) {
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API(
+ "BTM_SetPeriodicInquiryMode: mode: %d, dur: %d, rsps: %d, flt: %d, min: "
+ "%d, max: %d",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type, min_delay, max_delay);
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active) return (BTM_BUSY);
+
+ /* If illegal parameters return false */
+ if (p_inqparms->mode != BTM_GENERAL_INQUIRY &&
+ p_inqparms->mode != BTM_LIMITED_INQUIRY)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Verify the parameters for this command */
+ if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN ||
+ p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH ||
+ min_delay <= p_inqparms->duration ||
+ min_delay < BTM_PER_INQ_MIN_MIN_PERIOD ||
+ min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || max_delay <= min_delay ||
+ max_delay < BTM_PER_INQ_MIN_MAX_PERIOD)
+ /* max_delay > BTM_PER_INQ_MAX_MAX_PERIOD)*/
+ /* BTM_PER_INQ_MAX_MAX_PERIOD set to 1's in all bits. Condition resulting in
+ false always*/
+ {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Save the inquiry parameters to be used upon the completion of
+ * setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+ p_inq->per_min_delay = min_delay;
+ p_inq->per_max_delay = max_delay;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->p_inq_results_cb = p_results_cb;
+
+ p_inq->inq_active = (uint8_t)(
+ (p_inqparms->mode == BTM_LIMITED_INQUIRY)
+ ? (BTM_LIMITED_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE)
+ : (BTM_GENERAL_INQUIRY_ACTIVE | BTM_PERIODIC_INQUIRY_ACTIVE));
+
+ /* If a filter is specified, then save it for later and clear the current
+ filter.
+ The setting of the filter is done upon completion of clearing of the
+ previous
+ filter.
+ */
+ if (p_inqparms->filter_cond_type != BTM_CLR_INQUIRY_FILTER) {
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ } else /* The filter is not being used so simply clear it; the inquiry can
+ start after this operation */
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+
+ /* Before beginning the inquiry the current filter must be cleared, so
+ * initiate the command */
+ status = btm_set_inq_event_filter(p_inqparms->filter_cond_type,
+ &p_inqparms->filter_cond);
+ if (status != BTM_CMD_STARTED) {
+ /* If set filter command is not succesful reset the state */
+ p_inq->p_inq_results_cb = NULL;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelPeriodicInquiry
+ *
+ * Description This function cancels a periodic inquiry
+ *
+ * Returns
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelPeriodicInquiry(void) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tBTM_STATUS status = BTM_SUCCESS;
+ BTM_TRACE_API("BTM_CancelPeriodicInquiry called");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ /* Only cancel if one is active */
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ btm_cb.btm_inq_vars.inq_active = BTM_INQUIRY_INACTIVE;
+ btm_cb.btm_inq_vars.p_inq_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
+
+ btsnd_hcic_exit_per_inq();
+
+ /* If the event filter is in progress, mark it so that the processing of the
+ return
+ event will be ignored */
+ if (p_inq->inqfilt_active) p_inq->pending_filt_complete_event++;
+
+ p_inq->inqfilt_active = false;
+ p_inq->inq_counter++;
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetConnectability
+ *
+ * Description This function is called to set the device into or out of
+ * connectable mode. Discoverable mode means page scans are
+ * enabled.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
+ uint16_t interval) {
+ uint8_t scan_mode = 0;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API("BTM_SetConnectability");
+
+ if (controller_get_interface()->supports_ble()) {
+ if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) {
+ return BTM_NO_RESOURCES;
+ }
+ p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
+ }
+ page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
+
+ /*** Check mode parameter ***/
+ if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE)
+ return (BTM_ILLEGAL_VALUE);
+
+ /* Make sure the controller is active */
+ if (!controller_get_interface()->get_is_ready()) return (BTM_DEV_RESET);
+
+ /* If the window and/or interval is '0', set to default values */
+ if (!window) window = BTM_DEFAULT_CONN_WINDOW;
+
+ if (!interval) interval = BTM_DEFAULT_CONN_INTERVAL;
+
+ BTM_TRACE_API(
+ "BTM_SetConnectability: mode %d [NonConn-0, Conn-1], window 0x%04x, "
+ "interval 0x%04x",
+ page_mode, window, interval);
+
+ /*** Check for valid window and interval parameters ***/
+ /*** Only check window and duration if mode is connectable ***/
+ if (page_mode == BTM_CONNECTABLE) {
+ /* window must be less than or equal to interval */
+ if (window < HCI_MIN_PAGESCAN_WINDOW || window > HCI_MAX_PAGESCAN_WINDOW ||
+ interval < HCI_MIN_PAGESCAN_INTERVAL ||
+ interval > HCI_MAX_PAGESCAN_INTERVAL || window > interval) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ scan_mode |= HCI_PAGE_SCAN_ENABLED;
+ }
+
+ if ((window != p_inq->page_scan_window) ||
+ (interval != p_inq->page_scan_period)) {
+ p_inq->page_scan_window = window;
+ p_inq->page_scan_period = interval;
+ btsnd_hcic_write_pagescan_cfg(interval, window);
+ }
+
+ /* Keep the inquiry scan as previouosly set */
+ if (p_inq->discoverable_mode & BTM_DISCOVERABLE_MASK)
+ scan_mode |= HCI_INQUIRY_SCAN_ENABLED;
+
+ btsnd_hcic_write_scan_enable(scan_mode);
+ p_inq->connectable_mode &= (~BTM_CONNECTABLE_MASK);
+ p_inq->connectable_mode |= page_mode;
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ * Output Params p_window - current page scan duration
+ * p_interval - current time between page scans
+ *
+ * Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadConnectability(uint16_t* p_window, uint16_t* p_interval) {
+ BTM_TRACE_API("BTM_ReadConnectability");
+ if (p_window) *p_window = btm_cb.btm_inq_vars.page_scan_window;
+
+ if (p_interval) *p_interval = btm_cb.btm_inq_vars.page_scan_period;
+
+ return (btm_cb.btm_inq_vars.connectable_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsInquiryActive
+ *
+ * Description This function returns a bit mask of the current inquiry
+ * state
+ *
+ * Returns BTM_INQUIRY_INACTIVE if inactive (0)
+ * BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ * BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ * BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+uint16_t BTM_IsInquiryActive(void) {
+ BTM_TRACE_API("BTM_IsInquiryActive");
+
+ return (btm_cb.btm_inq_vars.inq_active);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelInquiry
+ *
+ * Description This function cancels an inquiry if active
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelInquiry(void) {
+ tBTM_STATUS status = BTM_SUCCESS;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ uint8_t active_mode = p_inq->inq_active;
+#endif
+ BTM_TRACE_API("BTM_CancelInquiry called");
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ /* Only cancel if not in periodic mode, otherwise the caller should call
+ * BTM_CancelPeriodicMode */
+ if ((p_inq->inq_active & BTM_INQUIRY_ACTIVE_MASK) != 0 &&
+ (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE))) {
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->p_inq_results_cb =
+ (tBTM_INQ_RESULTS_CB*)NULL; /* Do not notify caller anymore */
+ p_inq->p_inq_cmpl_cb =
+ (tBTM_CMPL_CB*)NULL; /* Do not notify caller anymore */
+
+ /* If the event filter is in progress, mark it so that the processing of the
+ return
+ event will be ignored */
+ if (p_inq->inqfilt_active) {
+ p_inq->inqfilt_active = false;
+ p_inq->pending_filt_complete_event++;
+ }
+ /* Initiate the cancel inquiry */
+ else {
+ if (((p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK) != 0)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ && (active_mode & BTM_BR_INQUIRY_MASK)
+#endif
+ ) {
+ btsnd_hcic_inq_cancel();
+ }
+ if (((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ && (active_mode & BTM_BLE_INQ_ACTIVE_MASK)
+#endif
+ )
+ btm_ble_stop_inquiry();
+ }
+
+ /* Do not send the BUSY_LEVEL event yet. Wait for the cancel_complete event
+ * and then send the BUSY_LEVEL event
+ * btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);
+ */
+
+ p_inq->inq_counter++;
+ btm_clr_inq_result_flt();
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_StartInquiry
+ *
+ * Description This function is called to start an inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry, BR/LE bit mask
+ * seperately
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * p_results_cb - Pointer to the callback routine which gets
+ * called upon receipt of an inquiry result. If
+ * this field is NULL, the application is not
+ * notified.
+ *
+ * p_cmpl_cb - Pointer to the callback routine which gets
+ * called upon completion. If this field is
+ * NULL, the application is not notified when
+ * completed.
+ * Returns tBTM_STATUS
+ * BTM_CMD_STARTED if successfully initiated
+ * BTM_BUSY if already in progress
+ * BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb) {
+ tBTM_STATUS status = BTM_CMD_STARTED;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
+ p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
+ p_inqparms->filter_cond_type);
+
+ /* Only one active inquiry is allowed in this implementation.
+ Also do not allow an inquiry if the inquiry filter is being updated */
+ if (p_inq->inq_active || p_inq->inqfilt_active) {
+ /*check if LE observe is already running*/
+ if (p_inq->scan_type == INQ_LE_OBSERVE &&
+ p_inq->p_inq_ble_results_cb != NULL) {
+ BTM_TRACE_API("BTM_StartInquiry: LE observe in progress");
+ p_inq->scan_type = INQ_GENERAL;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
+ btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
+ } else {
+ return (BTM_BUSY);
+ BTM_TRACE_API("BTM_StartInquiry: return BUSY");
+ }
+ } else
+ p_inq->scan_type = INQ_GENERAL;
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_GENERAL_INQUIRY &&
+ (p_inqparms->mode & BTM_BR_INQUIRY_MASK) != BTM_LIMITED_INQUIRY &&
+ (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_GENERAL_INQUIRY &&
+ (p_inqparms->mode & BTM_BLE_INQUIRY_MASK) != BTM_BLE_LIMITED_INQUIRY)
+ return (BTM_ILLEGAL_VALUE);
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_FINISH) return BTM_ILLEGAL_VALUE;
+#endif
+
+ /* Save the inquiry parameters to be used upon the completion of
+ * setting/clearing the inquiry filter */
+ p_inq->inqparms = *p_inqparms;
+
+ /* Initialize the inquiry variables */
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->p_inq_cmpl_cb = p_cmpl_cb;
+ p_inq->p_inq_results_cb = p_results_cb;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->inq_active = p_inqparms->mode;
+
+ BTM_TRACE_DEBUG("BTM_StartInquiry: p_inq->inq_active = 0x%02x",
+ p_inq->inq_active);
+
+/* interleave scan minimal conditions */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+
+ /* check if both modes are present */
+ if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK) &&
+ (p_inqparms->mode & BTM_BR_INQUIRY_MASK)) {
+ BTM_TRACE_API("BTM:Interleave Inquiry Mode Set");
+ p_inqparms->duration = p_inqparms->intl_duration[p_inq->next_state];
+ p_inq->inqparms.duration = p_inqparms->duration;
+ } else {
+ BTM_TRACE_API("BTM:Single Mode: No interleaving, Mode:0x%02x",
+ p_inqparms->mode);
+ p_inq->next_state = BTM_NO_INTERLEAVING;
+ }
+#endif
+
+ /* start LE inquiry here if requested */
+ if ((p_inqparms->mode & BTM_BLE_INQUIRY_MASK)
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ &&
+ (p_inq->next_state == BTM_BLE_ONE || p_inq->next_state == BTM_BLE_TWO ||
+ p_inq->next_state == BTM_NO_INTERLEAVING)
+#endif
+ )
+
+ {
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ p_inq->inq_active = (p_inqparms->mode & BTM_BLE_INQUIRY_MASK);
+ BTM_TRACE_API("BTM:Starting LE Scan with duration %d and activeMode:0x%02x",
+ p_inqparms->duration,
+ (p_inqparms->mode & BTM_BLE_INQUIRY_MASK));
+#endif
+ if (!controller_get_interface()->supports_ble()) {
+ p_inq->inqparms.mode &= ~BTM_BLE_INQUIRY_MASK;
+ status = BTM_ILLEGAL_VALUE;
+ }
+ /* BLE for now does not support filter condition for inquiry */
+ else {
+ status = btm_ble_start_inquiry(
+ (uint8_t)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK),
+ p_inqparms->duration);
+ if (status != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("Err Starting LE Inquiry.");
+ p_inq->inqparms.mode &= ~BTM_BLE_INQUIRY_MASK;
+ }
+ }
+#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+ p_inqparms->mode &= ~BTM_BLE_INQUIRY_MASK;
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_NO_INTERLEAVING) {
+ p_inq->next_state = BTM_FINISH;
+ } else {
+ BTM_TRACE_API(
+ "BTM:Interleaving: started LE scan, Advancing to next state: %d",
+ p_inq->next_state + 1);
+ p_inq->next_state += 1;
+ }
+ /* reset next_state if status <> BTM_Started */
+ if (status != BTM_CMD_STARTED) p_inq->next_state = BTM_BR_ONE;
+
+ /* if interleave scan..return here */
+ return status;
+#endif
+
+ BTM_TRACE_DEBUG("BTM_StartInquiry: mode = %02x", p_inqparms->mode);
+ }
+
+ /* we're done with this routine if BR/EDR inquiry is not desired. */
+ if ((p_inqparms->mode & BTM_BR_INQUIRY_MASK) == BTM_INQUIRY_NONE)
+ return status;
+
+/* BR/EDR inquiry portion */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if ((p_inq->next_state == BTM_BR_ONE || p_inq->next_state == BTM_BR_TWO ||
+ p_inq->next_state == BTM_NO_INTERLEAVING)) {
+ p_inq->inq_active = (p_inqparms->mode & BTM_BR_INQUIRY_MASK);
+#endif
+ /* If a filter is specified, then save it for later and clear the current
+ filter.
+ The setting of the filter is done upon completion of clearing of the
+ previous
+ filter.
+ */
+ switch (p_inqparms->filter_cond_type) {
+ case BTM_CLR_INQUIRY_FILTER:
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ break;
+
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ case BTM_FILTER_COND_BD_ADDR:
+ /* The filter is not being used so simply clear it;
+ the inquiry can start after this operation */
+ p_inq->state = BTM_INQ_CLR_FILT_STATE;
+ p_inqparms->filter_cond_type = BTM_CLR_INQUIRY_FILTER;
+ /* =============>>>> adding LE filtering here ????? */
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ /* Before beginning the inquiry the current filter must be cleared, so
+ * initiate the command */
+ status = btm_set_inq_event_filter(p_inqparms->filter_cond_type,
+ &p_inqparms->filter_cond);
+ if (status != BTM_CMD_STARTED) p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->next_state == BTM_NO_INTERLEAVING)
+ p_inq->next_state = BTM_FINISH;
+ else {
+ BTM_TRACE_API(
+ "BTM:Interleaving: Started BTM inq, Advancing to next state: %d",
+ p_inq->next_state + 1);
+ p_inq->next_state += 1;
+ }
+ }
+ if (status != BTM_CMD_STARTED) {
+ /* Some error beginning the scan process.
+ Reset the next_state parameter.. Do we need to reset the inq_active also?
+ */
+ BTM_TRACE_API("BTM:Interleaving: Error in Starting inquiry, status: 0x%02x",
+ status);
+ p_inq->next_state = BTM_BR_ONE;
+ }
+#endif
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteDeviceName
+ *
+ * Description This function initiates a remote device HCI command to the
+ * controller and calls the callback when the process has
+ * completed.
+ *
+ * Input Params: remote_bda - device address of name to retrieve
+ * p_cb - callback function called when
+ * BTM_CMD_STARTED is returned.
+ * A pointer to tBTM_REMOTE_DEV_NAME is
+ * passed to the callback.
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_BUSY if already in progress
+ * BTM_UNKNOWN_ADDR if device address is bad
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteDeviceName(BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb,
+ tBT_TRANSPORT transport) {
+ BTM_TRACE_API("%s: bd addr [%02x%02x%02x%02x%02x%02x]", __func__,
+ remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+ /* Use LE transport when LE is the only available option */
+ if (transport == BT_TRANSPORT_LE) {
+ return btm_ble_read_remote_name(remote_bda, p_cb);
+ }
+ /* Use classic transport for BR/EDR and Dual Mode devices */
+ return btm_initiate_rem_name(remote_bda, BTM_RMT_NAME_EXT,
+ BTM_EXT_RMT_NAME_TIMEOUT_MS, p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelRemoteDeviceName
+ *
+ * Description This function initiates the cancel request for the specified
+ * remote device.
+ *
+ * Input Params: None
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if there is not an active remote name
+ * request.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelRemoteDeviceName(void) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ BTM_TRACE_API("BTM_CancelRemoteDeviceName()");
+
+ /* Make sure there is not already one in progress */
+ if (p_inq->remname_active) {
+ if (BTM_UseLeLink(p_inq->remname_bda)) {
+ if (btm_ble_cancel_remote_name(p_inq->remname_bda))
+ return (BTM_CMD_STARTED);
+ else
+ return (BTM_UNKNOWN_ADDR);
+ } else
+ btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda);
+ return (BTM_CMD_STARTED);
+ } else
+ return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbRead
+ *
+ * Description This function looks through the inquiry database for a match
+ * based on Bluetooth Device Address. This is the application's
+ * interface to get the inquiry details of a specific BD
+ * address.
+ *
+ * Returns pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbRead(const BD_ADDR p_bda) {
+ BTM_TRACE_API("BTM_InqDbRead: bd addr [%02x%02x%02x%02x%02x%02x]", p_bda[0],
+ p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ tINQ_DB_ENT* p_ent = btm_inq_db_find(p_bda);
+ if (!p_ent) return NULL;
+
+ return &p_ent->inq_info;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbFirst
+ *
+ * Description This function looks through the inquiry database for the
+ * first used entry, and returns that. This is used in
+ * conjunction with
+ * BTM_InqDbNext by applications as a way to walk through the
+ * inquiry database.
+ *
+ * Returns pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbFirst(void) {
+ uint16_t xx;
+ tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (p_ent->in_use) return (&p_ent->inq_info);
+ }
+
+ /* If here, no used entry found */
+ return ((tBTM_INQ_INFO*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbNext
+ *
+ * Description This function looks through the inquiry database for the
+ * next used entry, and returns that. If the input parameter
+ * is NULL, the first entry is returned.
+ *
+ * Returns pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur) {
+ tINQ_DB_ENT* p_ent;
+ uint16_t inx;
+
+ if (p_cur) {
+ p_ent = (tINQ_DB_ENT*)((uint8_t*)p_cur - offsetof(tINQ_DB_ENT, inq_info));
+ inx = (uint16_t)((p_ent - btm_cb.btm_inq_vars.inq_db) + 1);
+
+ for (p_ent = &btm_cb.btm_inq_vars.inq_db[inx]; inx < BTM_INQ_DB_SIZE;
+ inx++, p_ent++) {
+ if (p_ent->in_use) return (&p_ent->inq_info);
+ }
+
+ /* If here, more entries found */
+ return ((tBTM_INQ_INFO*)NULL);
+ } else
+ return (BTM_InqDbFirst());
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ClearInqDb
+ *
+ * Description This function is called to clear out a device or all devices
+ * from the inquiry database.
+ *
+ * Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+ * (NULL clears all entries)
+ *
+ * Returns BTM_BUSY if an inquiry, get remote name, or event filter
+ * is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ClearInqDb(BD_ADDR p_bda) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ /* If an inquiry or remote name is in progress return busy */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE || p_inq->inqfilt_active)
+ return (BTM_BUSY);
+
+ btm_clr_inq_db(p_bda);
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadInquiryRspTxPower
+ *
+ * Description This command will read the inquiry Transmit Power level used
+ * to transmit the FHS and EIR data packets. This can be used
+ * directly in the Tx Power Level EIR data type.
+ *
+ * Returns BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb) {
+ if (btm_cb.devcb.p_inq_tx_power_cmpl_cb) return (BTM_BUSY);
+
+ btm_cb.devcb.p_inq_tx_power_cmpl_cb = p_cb;
+ alarm_set_on_queue(btm_cb.devcb.read_inq_tx_power_timer,
+ BTM_INQ_REPLY_TIMEOUT_MS, btm_read_inq_tx_power_timeout,
+ NULL, btu_general_alarm_queue);
+
+ btsnd_hcic_read_inq_tx_power();
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * **
+ * BTM Internal Inquiry Functions **
+ * **
+ *******************************************************************************
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_inq_db_reset
+ *
+ * Description This function is called at at reset to clear the inquiry
+ * database & pending callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_inq_db_reset(void) {
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ uint8_t num_responses;
+ uint8_t temp_inq_active;
+ tBTM_STATUS status;
+
+ /* If an inquiry or periodic inquiry is active, reset the mode to inactive */
+ if (p_inq->inq_active != BTM_INQUIRY_INACTIVE) {
+ temp_inq_active = p_inq->inq_active; /* Save so state can change BEFORE
+ callback is called */
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+
+ /* If not a periodic inquiry, the complete callback must be called to notify
+ * caller */
+ if (temp_inq_active == BTM_LIMITED_INQUIRY_ACTIVE ||
+ temp_inq_active == BTM_GENERAL_INQUIRY_ACTIVE) {
+ if (p_inq->p_inq_cmpl_cb) {
+ num_responses = 0;
+ (*p_inq->p_inq_cmpl_cb)(&num_responses);
+ }
+ }
+ }
+
+ /* Cancel a remote name request if active, and notify the caller (if waiting)
+ */
+ if (p_inq->remname_active) {
+ alarm_cancel(p_inq->remote_name_timer);
+ p_inq->remname_active = false;
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ if (p_inq->p_remname_cmpl_cb) {
+ rem_name.status = BTM_DEV_RESET;
+
+ (*p_inq->p_remname_cmpl_cb)(&rem_name);
+ p_inq->p_remname_cmpl_cb = NULL;
+ }
+ }
+
+ /* Cancel an inquiry filter request if active, and notify the caller (if
+ * waiting) */
+ if (p_inq->inqfilt_active) {
+ p_inq->inqfilt_active = false;
+
+ if (p_inq->p_inqfilter_cmpl_cb) {
+ status = BTM_DEV_RESET;
+ (*p_inq->p_inqfilter_cmpl_cb)(&status);
+ }
+ }
+
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+ p_inq->pending_filt_complete_event = 0;
+ p_inq->p_inq_results_cb = NULL;
+ btm_clr_inq_db(NULL); /* Clear out all the entries in the database */
+ btm_clr_inq_result_flt();
+
+ p_inq->discoverable_mode = BTM_NON_DISCOVERABLE;
+ p_inq->connectable_mode = BTM_NON_CONNECTABLE;
+ p_inq->page_scan_type = BTM_SCAN_TYPE_STANDARD;
+ p_inq->inq_scan_type = BTM_SCAN_TYPE_STANDARD;
+
+ p_inq->discoverable_mode |= BTM_BLE_NON_DISCOVERABLE;
+ p_inq->connectable_mode |= BTM_BLE_NON_CONNECTABLE;
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_db_init
+ *
+ * Description This function is called at startup to initialize the inquiry
+ * database.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_inq_db_init(void) {
+ alarm_free(btm_cb.btm_inq_vars.remote_name_timer);
+ btm_cb.btm_inq_vars.remote_name_timer =
+ alarm_new("btm_inq.remote_name_timer");
+ btm_cb.btm_inq_vars.no_inc_ssp = BTM_NO_SSP_ON_INQUIRY;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_stop_on_ssp
+ *
+ * Description This function is called on incoming SSP
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_inq_stop_on_ssp(void) {
+ uint8_t normal_active =
+ (BTM_GENERAL_INQUIRY_ACTIVE | BTM_LIMITED_INQUIRY_ACTIVE);
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_inq_stop_on_ssp: no_inc_ssp=%d inq_active:0x%x state:%d "
+ "inqfilt_active:%d",
+ btm_cb.btm_inq_vars.no_inc_ssp, btm_cb.btm_inq_vars.inq_active,
+ btm_cb.btm_inq_vars.state, btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ if (btm_cb.btm_inq_vars.no_inc_ssp) {
+ if (btm_cb.btm_inq_vars.state == BTM_INQ_ACTIVE_STATE) {
+ if (btm_cb.btm_inq_vars.inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ BTM_CancelPeriodicInquiry();
+ } else if (btm_cb.btm_inq_vars.inq_active & normal_active) {
+ /* can not call BTM_CancelInquiry() here. We need to report inquiry
+ * complete evt */
+ btsnd_hcic_inq_cancel();
+ }
+ }
+ /* do not allow inquiry to start */
+ btm_cb.btm_inq_vars.inq_active |= BTM_SSP_INQUIRY_ACTIVE;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_clear_ssp
+ *
+ * Description This function is called when pairing_state becomes idle
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_inq_clear_ssp(void) {
+ btm_cb.btm_inq_vars.inq_active &= ~BTM_SSP_INQUIRY_ACTIVE;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_clr_inq_db
+ *
+ * Description This function is called to clear out a device or all devices
+ * from the inquiry database.
+ *
+ * Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+ * (NULL clears all entries)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_clr_inq_db(BD_ADDR p_bda) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tINQ_DB_ENT* p_ent = p_inq->inq_db;
+ uint16_t xx;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_clr_inq_db: inq_active:0x%x state:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state);
+#endif
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (p_ent->in_use) {
+ /* If this is the specified BD_ADDR or clearing all devices */
+ if (p_bda == NULL || (!memcmp(p_ent->inq_info.results.remote_bd_addr,
+ p_bda, BD_ADDR_LEN))) {
+ p_ent->in_use = false;
+ }
+ }
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("inq_active:0x%x state:%d", btm_cb.btm_inq_vars.inq_active,
+ btm_cb.btm_inq_vars.state);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_clr_inq_result_flt
+ *
+ * Description This function looks through the bdaddr database for a match
+ * based on Bluetooth Device Address
+ *
+ * Returns true if found, else false (new entry)
+ *
+ ******************************************************************************/
+static void btm_clr_inq_result_flt(void) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ osi_free_and_reset((void**)&p_inq->p_bd_db);
+ p_inq->num_bd_entries = 0;
+ p_inq->max_bd_entries = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_find_bdaddr
+ *
+ * Description This function looks through the bdaddr database for a match
+ * based on Bluetooth Device Address
+ *
+ * Returns true if found, else false (new entry)
+ *
+ ******************************************************************************/
+bool btm_inq_find_bdaddr(BD_ADDR p_bda) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tINQ_BDADDR* p_db = &p_inq->p_bd_db[0];
+ uint16_t xx;
+
+ /* Don't bother searching, database doesn't exist or periodic mode */
+ if ((p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) || !p_db)
+ return (false);
+
+ for (xx = 0; xx < p_inq->num_bd_entries; xx++, p_db++) {
+ if (!memcmp(p_db->bd_addr, p_bda, BD_ADDR_LEN) &&
+ p_db->inq_count == p_inq->inq_counter)
+ return (true);
+ }
+
+ if (xx < p_inq->max_bd_entries) {
+ p_db->inq_count = p_inq->inq_counter;
+ memcpy(p_db->bd_addr, p_bda, BD_ADDR_LEN);
+ p_inq->num_bd_entries++;
+ }
+
+ /* If here, New Entry */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_db_find
+ *
+ * Description This function looks through the inquiry database for a match
+ * based on Bluetooth Device Address
+ *
+ * Returns pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tINQ_DB_ENT* btm_inq_db_find(const BD_ADDR p_bda) {
+ uint16_t xx;
+ tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if ((p_ent->in_use) &&
+ (!memcmp(p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN)))
+ return (p_ent);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_db_new
+ *
+ * Description This function looks through the inquiry database for an
+ * unused entry. If no entry is free, it allocates the oldest
+ * entry.
+ *
+ * Returns pointer to entry
+ *
+ ******************************************************************************/
+tINQ_DB_ENT* btm_inq_db_new(BD_ADDR p_bda) {
+ uint16_t xx;
+ tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT* p_old = btm_cb.btm_inq_vars.inq_db;
+ uint32_t ot = 0xFFFFFFFF;
+
+ for (xx = 0; xx < BTM_INQ_DB_SIZE; xx++, p_ent++) {
+ if (!p_ent->in_use) {
+ memset(p_ent, 0, sizeof(tINQ_DB_ENT));
+ memcpy(p_ent->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_ent->in_use = true;
+
+ return (p_ent);
+ }
+
+ if (p_ent->time_of_resp < ot) {
+ p_old = p_ent;
+ ot = p_ent->time_of_resp;
+ }
+ }
+
+ /* If here, no free entry found. Return the oldest. */
+
+ memset(p_old, 0, sizeof(tINQ_DB_ENT));
+ memcpy(p_old->inq_info.results.remote_bd_addr, p_bda, BD_ADDR_LEN);
+ p_old->in_use = true;
+
+ return (p_old);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_set_inq_event_filter
+ *
+ * Description This function is called to set the inquiry event filter.
+ * It is called by either internally, or by the external API
+ * function (BTM_SetInqEventFilter). It is used internally as
+ * part of the inquiry processing.
+ *
+ * Input Params:
+ * filter_cond_type - this is the type of inquiry filter to
+ * apply:
+ * BTM_FILTER_COND_DEVICE_CLASS,
+ * BTM_FILTER_COND_BD_ADDR, or
+ * BTM_CLR_INQUIRY_FILTER
+ *
+ * p_filt_cond - this is either a BD_ADDR or DEV_CLASS
+ * depending on the filter_cond_type
+ * (See section 4.7.3 of Core Spec 1.0b).
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ *
+ ******************************************************************************/
+static tBTM_STATUS btm_set_inq_event_filter(uint8_t filter_cond_type,
+ tBTM_INQ_FILT_COND* p_filt_cond) {
+ uint8_t condition_length = DEV_CLASS_LEN * 2;
+ uint8_t condition_buf[DEV_CLASS_LEN * 2];
+ uint8_t* p_cond = condition_buf; /* points to the condition to pass to HCI */
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_set_inq_event_filter: filter type %d [Clear-0, COD-1, BDADDR-2]",
+ filter_cond_type);
+ BTM_TRACE_DEBUG(
+ " condition [%02x%02x%02x %02x%02x%02x]",
+ p_filt_cond->bdaddr_cond[0], p_filt_cond->bdaddr_cond[1],
+ p_filt_cond->bdaddr_cond[2], p_filt_cond->bdaddr_cond[3],
+ p_filt_cond->bdaddr_cond[4], p_filt_cond->bdaddr_cond[5]);
+#endif
+
+ /* Load the correct filter condition to pass to the lower layer */
+ switch (filter_cond_type) {
+ case BTM_FILTER_COND_DEVICE_CLASS:
+ /* copy the device class and device class fields into contiguous memory to
+ * send to HCI */
+ memcpy(condition_buf, p_filt_cond->cod_cond.dev_class, DEV_CLASS_LEN);
+ memcpy(&condition_buf[DEV_CLASS_LEN],
+ p_filt_cond->cod_cond.dev_class_mask, DEV_CLASS_LEN);
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_FILTER_COND_BD_ADDR:
+ p_cond = p_filt_cond->bdaddr_cond;
+
+ /* condition length should already be set as the default */
+ break;
+
+ case BTM_CLR_INQUIRY_FILTER:
+ condition_length = 0;
+ break;
+
+ default:
+ return (BTM_ILLEGAL_VALUE); /* Bad parameter was passed in */
+ }
+
+ btm_cb.btm_inq_vars.inqfilt_active = true;
+
+ /* Filter the inquiry results for the specified condition type and value */
+ btsnd_hcic_set_event_filter(HCI_FILTER_INQUIRY_RESULT, filter_cond_type,
+ p_cond, condition_length);
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_event_filter_complete
+ *
+ * Description This function is called when a set event filter has
+ * completed.
+ * Note: This routine currently only handles inquiry filters.
+ * Connection filters are ignored for now.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_event_filter_complete(uint8_t* p) {
+ uint8_t hci_status;
+ tBTM_STATUS status;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB* p_cb = p_inq->p_inqfilter_cmpl_cb;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_event_filter_complete: inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
+ btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* If the filter complete event is from an old or cancelled request, ignore it
+ */
+ if (p_inq->pending_filt_complete_event) {
+ p_inq->pending_filt_complete_event--;
+ return;
+ }
+
+ /* Only process the inquiry filter; Ignore the connection filter until it
+ is used by the upper layers */
+ if (p_inq->inqfilt_active == true) {
+ /* Extract the returned status from the buffer */
+ STREAM_TO_UINT8(hci_status, p);
+ if (hci_status != HCI_SUCCESS) {
+ /* If standalone operation, return the error status; if embedded in the
+ * inquiry, continue the inquiry */
+ BTM_TRACE_WARNING(
+ "BTM Warning: Set Event Filter Failed (HCI returned 0x%x)",
+ hci_status);
+ status = BTM_ERR_PROCESSING;
+ } else
+ status = BTM_SUCCESS;
+
+ /* If the set filter was initiated externally (via BTM_SetInqEventFilter),
+ call the
+ callback function to notify the initiator that it has completed */
+ if (p_inq->state == BTM_INQ_INACTIVE_STATE) {
+ p_inq->inqfilt_active = false;
+ if (p_cb) (*p_cb)(&status);
+ } else /* An inquiry is active (the set filter command was internally
+ generated),
+ process the next state of the process (Set a new filter or start
+ the inquiry). */
+ {
+ if (status != BTM_SUCCESS) {
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete(
+ BTM_ERR_PROCESSING,
+ (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+
+ /* btm_process_inq_complete() does not restore the following settings on
+ * periodic inquiry */
+ p_inq->inqfilt_active = false;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ return;
+ }
+
+ /* Check to see if a new filter needs to be set up */
+ if (p_inq->state == BTM_INQ_CLR_FILT_STATE) {
+ status = btm_set_inq_event_filter(p_inq->inqparms.filter_cond_type,
+ &p_inq->inqparms.filter_cond);
+ if (status == BTM_CMD_STARTED) {
+ p_inq->state = BTM_INQ_SET_FILT_STATE;
+ } else /* Error setting the filter: Call the initiator's callback
+ function to indicate a failure */
+ {
+ p_inq->inqfilt_active = false;
+
+ /* Process the inquiry complete (Error Status) */
+ btm_process_inq_complete(
+ BTM_ERR_PROCESSING,
+ (uint8_t)(p_inq->inqparms.mode & BTM_BR_INQUIRY_MASK));
+ }
+ } else /* Initiate the Inquiry or Periodic Inquiry */
+ {
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->inqfilt_active = false;
+ btm_initiate_inquiry(p_inq);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_initiate_inquiry
+ *
+ * Description This function is called to start an inquiry or periodic
+ * inquiry upon completion of the setting and/or clearing of
+ * the inquiry filter.
+ *
+ * Inputs: p_inq (btm_cb.btm_inq_vars) - pointer to saved inquiry
+ * information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals
+ * (If '0', the inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter
+ * (based on filter_cond_type)
+ *
+ * Returns If an error occurs the initiator's callback is called with
+ * the error status.
+ *
+ ******************************************************************************/
+static void btm_initiate_inquiry(tBTM_INQUIRY_VAR_ST* p_inq) {
+ const LAP* lap;
+ tBTM_INQ_PARMS* p_inqparms = &p_inq->inqparms;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_initiate_inquiry: inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
+ btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ btm_acl_update_busy_level(BTM_BLI_INQ_EVT);
+
+ if (p_inq->inq_active & BTM_SSP_INQUIRY_ACTIVE) {
+ btm_process_inq_complete(BTM_NO_RESOURCES,
+ (uint8_t)(p_inqparms->mode & BTM_BR_INQUIRY_MASK));
+ return;
+ }
+
+ /* Make sure the number of responses doesn't overflow the database
+ * configuration */
+ p_inqparms->max_resps = (uint8_t)((p_inqparms->max_resps <= BTM_INQ_DB_SIZE)
+ ? p_inqparms->max_resps
+ : BTM_INQ_DB_SIZE);
+
+ lap = (p_inq->inq_active & BTM_LIMITED_INQUIRY_ACTIVE) ? &limited_inq_lap
+ : &general_inq_lap;
+
+ if (p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) {
+ btsnd_hcic_per_inq_mode(p_inq->per_max_delay, p_inq->per_min_delay, *lap,
+ p_inqparms->duration, p_inqparms->max_resps);
+ } else {
+ btm_clr_inq_result_flt();
+
+ /* Allocate memory to hold bd_addrs responding */
+ p_inq->p_bd_db = (tINQ_BDADDR*)osi_calloc(BT_DEFAULT_BUFFER_SIZE);
+ p_inq->max_bd_entries =
+ (uint16_t)(BT_DEFAULT_BUFFER_SIZE / sizeof(tINQ_BDADDR));
+
+ btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_inq_results
+ *
+ * Description This function is called when inquiry results are received
+ * from the device. It updates the inquiry database. If the
+ * inquiry database is full, the oldest entry is discarded.
+ *
+ * Parameters inq_res_mode - BTM_INQ_RESULT_STANDARD
+ * BTM_INQ_RESULT_WITH_RSSI
+ * BTM_INQ_RESULT_EXTENDED
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_inq_results(uint8_t* p, uint8_t inq_res_mode) {
+ uint8_t num_resp, xx;
+ BD_ADDR bda;
+ tINQ_DB_ENT* p_i;
+ tBTM_INQ_RESULTS* p_cur = NULL;
+ bool is_new = true;
+ bool update = false;
+ int8_t i_rssi;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tBTM_INQ_RESULTS_CB* p_inq_results_cb = p_inq->p_inq_results_cb;
+ uint8_t page_scan_rep_mode = 0;
+ uint8_t page_scan_per_mode = 0;
+ uint8_t page_scan_mode = 0;
+ uint8_t rssi = 0;
+ DEV_CLASS dc;
+ uint16_t clock_offset;
+ uint8_t* p_eir_data = NULL;
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_process_inq_results inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
+ btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ /* Only process the results if the BR inquiry is still active */
+ if (!(p_inq->inq_active & BTM_BR_INQ_ACTIVE_MASK)) return;
+
+ STREAM_TO_UINT8(num_resp, p);
+
+ if (inq_res_mode == BTM_INQ_RESULT_EXTENDED && (num_resp > 1)) {
+ BTM_TRACE_ERROR("btm_process_inq_results() extended results (%d) > 1",
+ num_resp);
+ return;
+ }
+
+ for (xx = 0; xx < num_resp; xx++) {
+ update = false;
+ /* Extract inquiry results */
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_UINT8(page_scan_rep_mode, p);
+ STREAM_TO_UINT8(page_scan_per_mode, p);
+
+ if (inq_res_mode == BTM_INQ_RESULT_STANDARD) {
+ STREAM_TO_UINT8(page_scan_mode, p);
+ }
+
+ STREAM_TO_DEVCLASS(dc, p);
+ STREAM_TO_UINT16(clock_offset, p);
+ if (inq_res_mode != BTM_INQ_RESULT_STANDARD) {
+ STREAM_TO_UINT8(rssi, p);
+ }
+
+ p_i = btm_inq_db_find(bda);
+
+ /* Only process the num_resp is smaller than max_resps.
+ If results are queued to BTU task while canceling inquiry,
+ or when more than one result is in this response, > max_resp
+ responses could be processed which can confuse some apps
+ */
+ if (p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp >= p_inq->inqparms.max_resps
+ /* new device response */
+ &&
+ (p_i == NULL ||
+ /* exisiting device with BR/EDR info */
+ (p_i &&
+ (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0))) {
+ /* BTM_TRACE_WARNING("INQ RES: Extra Response Received...ignoring"); */
+ return;
+ }
+
+ /* Check if this address has already been processed for this inquiry */
+ if (btm_inq_find_bdaddr(bda)) {
+ /* BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/
+ /* By default suppose no update needed */
+ i_rssi = (int8_t)rssi;
+
+ /* If this new RSSI is higher than the last one */
+ if (p_inq->inqparms.report_dup && (rssi != 0) && p_i &&
+ (i_rssi > p_i->inq_info.results.rssi ||
+ p_i->inq_info.results.rssi == 0
+ /* BR/EDR inquiry information update */
+ ||
+ (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0)) {
+ p_cur = &p_i->inq_info.results;
+ BTM_TRACE_DEBUG("update RSSI new:%d, old:%d", i_rssi, p_cur->rssi);
+ p_cur->rssi = i_rssi;
+ update = true;
+ }
+ /* If we received a second Extended Inq Event for an already */
+ /* discovered device, this is because for the first one EIR was not
+ received */
+ else if ((inq_res_mode == BTM_INQ_RESULT_EXTENDED) && (p_i)) {
+ p_cur = &p_i->inq_info.results;
+ update = true;
+ }
+ /* If no update needed continue with next response (if any) */
+ else
+ continue;
+ }
+
+ /* If existing entry, use that, else get a new one (possibly reusing the
+ * oldest) */
+ if (p_i == NULL) {
+ p_i = btm_inq_db_new(bda);
+ is_new = true;
+ }
+
+ /* If an entry for the device already exists, overwrite it ONLY if it is
+ from
+ a previous inquiry. (Ignore it if it is a duplicate response from the
+ same
+ inquiry.
+ */
+ else if (p_i->inq_count == p_inq->inq_counter &&
+ (p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BREDR))
+ is_new = false;
+
+ /* keep updating RSSI to have latest value */
+ if (inq_res_mode != BTM_INQ_RESULT_STANDARD)
+ p_i->inq_info.results.rssi = (int8_t)rssi;
+ else
+ p_i->inq_info.results.rssi = BTM_INQ_RES_IGNORE_RSSI;
+
+ if (is_new == true) {
+ /* Save the info */
+ p_cur = &p_i->inq_info.results;
+ p_cur->page_scan_rep_mode = page_scan_rep_mode;
+ p_cur->page_scan_per_mode = page_scan_per_mode;
+ p_cur->page_scan_mode = page_scan_mode;
+ p_cur->dev_class[0] = dc[0];
+ p_cur->dev_class[1] = dc[1];
+ p_cur->dev_class[2] = dc[2];
+ p_cur->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ p_i->time_of_resp = time_get_os_boottime_ms();
+
+ if (p_i->inq_count != p_inq->inq_counter)
+ p_inq->inq_cmpl_info.num_resp++; /* A new response was found */
+
+ p_cur->inq_result_type = BTM_INQ_RESULT_BR;
+ if (p_i->inq_count != p_inq->inq_counter) {
+ p_cur->device_type = BT_DEVICE_TYPE_BREDR;
+ p_i->scan_rsp = false;
+ } else
+ p_cur->device_type |= BT_DEVICE_TYPE_BREDR;
+ p_i->inq_count = p_inq->inq_counter; /* Mark entry for current inquiry */
+
+ /* If the number of responses found and not unlimited, issue a cancel
+ * inquiry */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
+ p_inq->inqparms.max_resps &&
+ p_inq->inq_cmpl_info.num_resp == p_inq->inqparms.max_resps &&
+ /* BLE scanning is active and received adv */
+ ((((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0) &&
+ p_cur->device_type == BT_DEVICE_TYPE_DUMO && p_i->scan_rsp) ||
+ (p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) == 0)) {
+ /* BTM_TRACE_DEBUG("BTMINQ: Found devices, cancelling
+ * inquiry..."); */
+ btsnd_hcic_inq_cancel();
+
+ if ((p_inq->inqparms.mode & BTM_BLE_INQUIRY_MASK) != 0)
+ btm_ble_stop_inquiry();
+ btm_acl_update_busy_level(BTM_BLI_INQ_DONE_EVT);
+ }
+ /* Initialize flag to false. This flag is set/used by application */
+ p_i->inq_info.appl_knows_rem_name = false;
+ }
+
+ if (is_new || update) {
+ if (inq_res_mode == BTM_INQ_RESULT_EXTENDED) {
+ memset(p_cur->eir_uuid, 0,
+ BTM_EIR_SERVICE_ARRAY_SIZE * (BTM_EIR_ARRAY_BITS / 8));
+ /* set bit map of UUID list from received EIR */
+ btm_set_eir_uuid(p, p_cur);
+ p_eir_data = p;
+ } else
+ p_eir_data = NULL;
+
+ /* If a callback is registered, call it with the results */
+ if (p_inq_results_cb)
+ (p_inq_results_cb)((tBTM_INQ_RESULTS*)p_cur, p_eir_data, 62);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sort_inq_result
+ *
+ * Description This function is called when inquiry complete is received
+ * from the device to sort inquiry results based on rssi.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sort_inq_result(void) {
+ uint8_t xx, yy, num_resp;
+ tINQ_DB_ENT* p_ent = btm_cb.btm_inq_vars.inq_db;
+ tINQ_DB_ENT* p_next = btm_cb.btm_inq_vars.inq_db + 1;
+ int size;
+ tINQ_DB_ENT* p_tmp = (tINQ_DB_ENT*)osi_malloc(sizeof(tINQ_DB_ENT));
+
+ num_resp = (btm_cb.btm_inq_vars.inq_cmpl_info.num_resp < BTM_INQ_DB_SIZE)
+ ? btm_cb.btm_inq_vars.inq_cmpl_info.num_resp
+ : BTM_INQ_DB_SIZE;
+
+ size = sizeof(tINQ_DB_ENT);
+ for (xx = 0; xx < num_resp - 1; xx++, p_ent++) {
+ for (yy = xx + 1, p_next = p_ent + 1; yy < num_resp; yy++, p_next++) {
+ if (p_ent->inq_info.results.rssi < p_next->inq_info.results.rssi) {
+ memcpy(p_tmp, p_next, size);
+ memcpy(p_next, p_ent, size);
+ memcpy(p_ent, p_tmp, size);
+ }
+ }
+ }
+
+ osi_free(p_tmp);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_inq_complete
+ *
+ * Description This function is called when inquiry complete is received
+ * from the device. Call the callback if not in periodic
+ * inquiry mode AND it is not NULL
+ * (The caller wants the event).
+ *
+ * The callback pass back the status and the number of
+ * responses
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_inq_complete(uint8_t status, uint8_t mode) {
+ tBTM_CMPL_CB* p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ /* inquiry inactive case happens when inquiry is cancelled.
+ Make mode 0 for no further inquiries from the current inquiry process
+ */
+ if (status != HCI_SUCCESS || p_inq->next_state == BTM_FINISH ||
+ !p_inq->inq_active) {
+ /* re-initialize for next inquiry request */
+ p_inq->next_state = BTM_BR_ONE;
+ /* make the mode 0 here */
+ p_inq->inqparms.mode &= ~(p_inq->inqparms.mode);
+ }
+#endif
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == FALSE)
+ p_inq->inqparms.mode &= ~(mode);
+#endif
+
+ if (p_inq->scan_type == INQ_LE_OBSERVE && !p_inq->inq_active) {
+ /*end of LE observe*/
+ p_inq->p_inq_ble_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
+ p_inq->p_inq_ble_cmpl_cb = (tBTM_CMPL_CB*)NULL;
+ p_inq->scan_type = INQ_NONE;
+ }
+
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_process_inq_complete inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
+ btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+ btm_acl_update_busy_level(BTM_BLI_INQ_DONE_EVT);
+ /* Ignore any stray or late complete messages if the inquiry is not active */
+ if (p_inq->inq_active) {
+ p_inq->inq_cmpl_info.status = (tBTM_STATUS)(
+ (status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING);
+
+ /* Notify caller that the inquiry has completed; (periodic inquiries do not
+ * send completion events */
+ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) &&
+ p_inq->inqparms.mode == 0) {
+ btm_clear_all_pending_le_entry();
+ p_inq->state = BTM_INQ_INACTIVE_STATE;
+
+ /* Increment so the start of a next inquiry has a new count */
+ p_inq->inq_counter++;
+
+ btm_clr_inq_result_flt();
+
+ if ((p_inq->inq_cmpl_info.status == BTM_SUCCESS) &&
+ controller_get_interface()->supports_rssi_with_inquiry_results()) {
+ btm_sort_inq_result();
+ }
+
+ /* Clear the results callback if set */
+ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB*)NULL;
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB*)NULL;
+
+ /* If we have a callback registered for inquiry complete, call it */
+ BTM_TRACE_DEBUG("BTM Inq Compl Callback: status 0x%02x, num results %d",
+ p_inq->inq_cmpl_info.status,
+ p_inq->inq_cmpl_info.num_resp);
+
+ if (p_inq_cb) (p_inq_cb)((tBTM_INQUIRY_CMPL*)&p_inq->inq_cmpl_info);
+ }
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ if (p_inq->inqparms.mode != 0 &&
+ !(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE)) {
+ /* make inquiry inactive for next iteration */
+ p_inq->inq_active = BTM_INQUIRY_INACTIVE;
+ /* call the inquiry again */
+ BTM_StartInquiry(&p_inq->inqparms, p_inq->p_inq_results_cb,
+ p_inq->p_inq_cmpl_cb);
+ }
+#endif
+ }
+ if (p_inq->inqparms.mode == 0 &&
+ p_inq->scan_type == INQ_GENERAL) // this inquiry is complete
+ {
+ p_inq->scan_type = INQ_NONE;
+ /* check if the LE observe is pending */
+ if (p_inq->p_inq_ble_results_cb != NULL) {
+ BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan");
+ BTM_BleObserve(1, 0, p_inq->p_inq_ble_results_cb,
+ p_inq->p_inq_ble_cmpl_cb);
+ }
+ }
+#if (BTM_INQ_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("inq_active:0x%x state:%d inqfilt_active:%d",
+ btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
+ btm_cb.btm_inq_vars.inqfilt_active);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_cancel_complete
+ *
+ * Description This function is called when inquiry cancel complete is
+ * received from the device. This function will also call the
+ * btm_process_inq_complete. This function is needed to
+ * differentiate a cancel_cmpl_evt from the inq_cmpl_evt.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_cancel_complete(uint8_t status, uint8_t mode) {
+ btm_acl_update_busy_level(BTM_BLI_INQ_CANCEL_EVT);
+ btm_process_inq_complete(status, mode);
+}
+/*******************************************************************************
+ *
+ * Function btm_initiate_rem_name
+ *
+ * Description This function looks initiates a remote name request. It is
+ * called either by GAP or by the API call
+ * BTM_ReadRemoteDeviceName.
+ *
+ * Input Params: p_cb - callback function called when
+ * BTM_CMD_STARTED is returned.
+ * A pointer to tBTM_REMOTE_DEV_NAME is
+ * passed to the callback.
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was sent to HCI.
+ * BTM_BUSY if already in progress
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_initiate_rem_name(BD_ADDR remote_bda, uint8_t origin,
+ period_ms_t timeout_ms, tBTM_CMPL_CB* p_cb) {
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+
+ /*** Make sure the device is ready ***/
+ if (!BTM_IsDeviceUp()) return (BTM_WRONG_MODE);
+
+ if (origin == BTM_RMT_NAME_SEC) {
+ btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ return BTM_CMD_STARTED;
+ }
+ /* Make sure there are no two remote name requests from external API in
+ progress */
+ else if (origin == BTM_RMT_NAME_EXT) {
+ if (p_inq->remname_active) {
+ return (BTM_BUSY);
+ } else {
+ /* If there is no remote name request running,call the callback function
+ * and start timer */
+ p_inq->p_remname_cmpl_cb = p_cb;
+ memcpy(p_inq->remname_bda, remote_bda, BD_ADDR_LEN);
+
+ alarm_set_on_queue(p_inq->remote_name_timer, timeout_ms,
+ btm_inq_remote_name_timer_timeout, NULL,
+ btu_general_alarm_queue);
+
+ /* If the database entry exists for the device, use its clock offset */
+ tINQ_DB_ENT* p_i = btm_inq_db_find(remote_bda);
+ if (p_i) {
+ tBTM_INQ_INFO* p_cur = &p_i->inq_info;
+ btsnd_hcic_rmt_name_req(
+ remote_bda, p_cur->results.page_scan_rep_mode,
+ p_cur->results.page_scan_mode,
+ (uint16_t)(p_cur->results.clock_offset | BTM_CLOCK_OFFSET_VALID));
+ } else {
+ /* Otherwise use defaults and mark the clock offset as invalid */
+ btsnd_hcic_rmt_name_req(remote_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ }
+
+ p_inq->remname_active = true;
+ return BTM_CMD_STARTED;
+ }
+ } else {
+ return BTM_ILLEGAL_VALUE;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_remote_name
+ *
+ * Description This function is called when a remote name is received from
+ * the device. If remote names are cached, it updates the
+ * inquiry database.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_process_remote_name(BD_ADDR bda, BD_NAME bdn, uint16_t evt_len,
+ uint8_t hci_status) {
+ tBTM_REMOTE_DEV_NAME rem_name;
+ tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ tBTM_CMPL_CB* p_cb = p_inq->p_remname_cmpl_cb;
+ uint8_t* p_n1;
+
+ uint16_t temp_evt_len;
+
+ if (bda != NULL) {
+ BTM_TRACE_EVENT("BDA %02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2],
+ bda[3], bda[4], bda[5]);
+ }
+
+ BTM_TRACE_EVENT("Inquire BDA %02x:%02x:%02x:%02x:%02x:%02x",
+ p_inq->remname_bda[0], p_inq->remname_bda[1],
+ p_inq->remname_bda[2], p_inq->remname_bda[3],
+ p_inq->remname_bda[4], p_inq->remname_bda[5]);
+
+ /* If the inquire BDA and remote DBA are the same, then stop the timer and set
+ * the active to false */
+ if ((p_inq->remname_active == true) &&
+ (((bda != NULL) && (memcmp(bda, p_inq->remname_bda, BD_ADDR_LEN) == 0)) ||
+ bda == NULL))
+
+ {
+ if (BTM_UseLeLink(p_inq->remname_bda)) {
+ if (hci_status == HCI_ERR_UNSPECIFIED)
+ btm_ble_cancel_remote_name(p_inq->remname_bda);
+ }
+ alarm_cancel(p_inq->remote_name_timer);
+ p_inq->remname_active = false;
+ /* Clean up and return the status if the command was not successful */
+ /* Note: If part of the inquiry, the name is not stored, and the */
+ /* inquiry complete callback is called. */
+
+ if (hci_status == HCI_SUCCESS) {
+ /* Copy the name from the data stream into the return structure */
+ /* Note that even if it is not being returned, it is used as a */
+ /* temporary buffer. */
+ p_n1 = (uint8_t*)rem_name.remote_bd_name;
+ rem_name.length = (evt_len < BD_NAME_LEN) ? evt_len : BD_NAME_LEN;
+ rem_name.remote_bd_name[rem_name.length] = 0;
+ rem_name.status = BTM_SUCCESS;
+ temp_evt_len = rem_name.length;
+
+ while (temp_evt_len > 0) {
+ *p_n1++ = *bdn++;
+ temp_evt_len--;
+ }
+ rem_name.remote_bd_name[rem_name.length] = 0;
+ }
+
+ /* If processing a stand alone remote name then report the error in the
+ callback */
+ else {
+ rem_name.status = BTM_BAD_VALUE_RET;
+ rem_name.length = 0;
+ rem_name.remote_bd_name[0] = 0;
+ }
+ /* Reset the remote BAD to zero and call callback if possible */
+ memset(p_inq->remname_bda, 0, BD_ADDR_LEN);
+
+ p_inq->p_remname_cmpl_cb = NULL;
+ if (p_cb) (p_cb)((tBTM_REMOTE_DEV_NAME*)&rem_name);
+ }
+}
+
+void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void* data) {
+ btm_inq_rmt_name_failed();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_inq_rmt_name_failed
+ *
+ * Description This function is if timeout expires while getting remote
+ * name. This is done for devices that incorrectly do not
+ * report operation failure
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_inq_rmt_name_failed(void) {
+ BTM_TRACE_ERROR("btm_inq_rmt_name_failed() remname_active=%d",
+ btm_cb.btm_inq_vars.remname_active);
+
+ if (btm_cb.btm_inq_vars.remname_active)
+ btm_process_remote_name(btm_cb.btm_inq_vars.remname_bda, NULL, 0,
+ HCI_ERR_UNSPECIFIED);
+ else
+ btm_process_remote_name(NULL, NULL, 0, HCI_ERR_UNSPECIFIED);
+
+ btm_sec_rmt_name_request_complete(NULL, NULL, HCI_ERR_UNSPECIFIED);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_inq_tx_power_timeout
+ *
+ * Description Callback when reading the inquiry tx power times out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_inq_tx_power_timeout(UNUSED_ATTR void* data) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
+ btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;
+ if (p_cb) (*p_cb)((void*)NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_inq_tx_power_complete
+ *
+ * Description read inquiry tx power level complete callback function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_inq_tx_power_complete(uint8_t* p) {
+ tBTM_CMPL_CB* p_cb = btm_cb.devcb.p_inq_tx_power_cmpl_cb;
+ tBTM_INQ_TXPWR_RESULTS results;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+ alarm_cancel(btm_cb.devcb.read_inq_tx_power_timer);
+ btm_cb.devcb.p_inq_tx_power_cmpl_cb = NULL;
+
+ /* If there was a registered callback, call it */
+ if (p_cb) {
+ STREAM_TO_UINT8(results.hci_status, p);
+
+ if (results.hci_status == HCI_SUCCESS) {
+ results.status = BTM_SUCCESS;
+
+ STREAM_TO_UINT8(results.tx_power, p);
+ BTM_TRACE_EVENT(
+ "BTM INQ TX POWER Complete: tx_power %d, hci status 0x%02x",
+ results.tx_power, results.hci_status);
+ } else
+ results.status = BTM_ERR_PROCESSING;
+
+ (*p_cb)(&results);
+ }
+}
+/*******************************************************************************
+ *
+ * Function BTM_WriteEIR
+ *
+ * Description This function is called to write EIR data to controller.
+ *
+ * Parameters p_buff - allocated HCI command buffer including extended
+ * inquriry response
+ *
+ * Returns BTM_SUCCESS - if successful
+ * BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff) {
+ if (controller_get_interface()->supports_extended_inquiry_response()) {
+ BTM_TRACE_API("Write Extended Inquiry Response to controller");
+ btsnd_hcic_write_ext_inquiry_response(p_buff, BTM_EIR_DEFAULT_FEC_REQUIRED);
+ return BTM_SUCCESS;
+ } else {
+ osi_free(p_buff);
+ return BTM_MODE_UNSUPPORTED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_convert_uuid_to_eir_service
+ *
+ * Description This function is called to get the bit position of UUID.
+ *
+ * Parameters uuid16 - UUID 16-bit
+ *
+ * Returns BTM EIR service ID if found
+ * BTM_EIR_MAX_SERVICES - if not found
+ *
+ ******************************************************************************/
+static uint8_t btm_convert_uuid_to_eir_service(uint16_t uuid16) {
+ uint8_t xx;
+
+ for (xx = 0; xx < BTM_EIR_MAX_SERVICES; xx++) {
+ if (uuid16 == BTM_EIR_UUID_LKUP_TBL[xx]) {
+ return xx;
+ }
+ }
+ return BTM_EIR_MAX_SERVICES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_HasEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters p_eir_uuid - bit map of UUID list
+ * uuid16 - UUID 16-bit
+ *
+ * Returns true - if found
+ * false - if not found
+ *
+ ******************************************************************************/
+bool BTM_HasEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+ uint8_t service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if (service_id < BTM_EIR_MAX_SERVICES)
+ return (BTM_EIR_HAS_SERVICE(p_eir_uuid, service_id));
+ else
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_HasInquiryEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID
+ * list.
+ *
+ * Parameters p_results - inquiry results
+ * uuid16 - UUID 16-bit
+ *
+ * Returns BTM_EIR_FOUND - if found
+ * BTM_EIR_NOT_FOUND - if not found and it is complete list
+ * BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results,
+ uint16_t uuid16) {
+ if (BTM_HasEirService(p_results->eir_uuid, uuid16)) {
+ return BTM_EIR_FOUND;
+ } else if (p_results->eir_complete_list) {
+ return BTM_EIR_NOT_FOUND;
+ } else
+ return BTM_EIR_UNKNOWN;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_AddEirService
+ *
+ * Description This function is called to add a service in bit map of UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+ uint8_t service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if (service_id < BTM_EIR_MAX_SERVICES)
+ BTM_EIR_SET_SERVICE(p_eir_uuid, service_id);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveEirService
+ *
+ * Description This function is called to remove a service in bit map of
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+ uint8_t service_id;
+
+ service_id = btm_convert_uuid_to_eir_service(uuid16);
+ if (service_id < BTM_EIR_MAX_SERVICES)
+ BTM_EIR_CLR_SERVICE(p_eir_uuid, service_id);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirSupportedServices
+ *
+ * Description This function is called to get UUID list from bit map of
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * p - reference of current pointer of EIR
+ * max_num_uuid16 - max number of UUID can be written in EIR
+ * num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
+ uint8_t max_num_uuid16,
+ uint8_t* p_num_uuid16) {
+ uint8_t service_index;
+
+ *p_num_uuid16 = 0;
+
+ for (service_index = 0; service_index < BTM_EIR_MAX_SERVICES;
+ service_index++) {
+ if (BTM_EIR_HAS_SERVICE(p_eir_uuid, service_index)) {
+ if (*p_num_uuid16 < max_num_uuid16) {
+ UINT16_TO_STREAM(*p, BTM_EIR_UUID_LKUP_TBL[service_index]);
+ (*p_num_uuid16)++;
+ }
+ /* if max number of UUIDs are stored and found one more */
+ else {
+ return BTM_EIR_MORE_16BITS_UUID_TYPE;
+ }
+ }
+ }
+ return BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirUuidList
+ *
+ * Description This function parses EIR and returns UUID list.
+ *
+ * Parameters p_eir - EIR
+ * eir_len - EIR len
+ * uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+ * p_num_uuid - return number of UUID in found list
+ * p_uuid_list - return UUID list
+ * max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns 0 - if not found
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ * BTM_EIR_MORE_16BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ * BTM_EIR_MORE_32BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ * BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len, uint8_t uuid_size,
+ uint8_t* p_num_uuid, uint8_t* p_uuid_list,
+ uint8_t max_num_uuid) {
+ const uint8_t* p_uuid_data;
+ uint8_t type;
+ uint8_t yy, xx;
+ uint16_t* p_uuid16 = (uint16_t*)p_uuid_list;
+ uint32_t* p_uuid32 = (uint32_t*)p_uuid_list;
+ char buff[LEN_UUID_128 * 2 + 1];
+
+ p_uuid_data =
+ btm_eir_get_uuid_list(p_eir, eir_len, uuid_size, p_num_uuid, &type);
+ if (p_uuid_data == NULL) {
+ return 0x00;
+ }
+
+ if (*p_num_uuid > max_num_uuid) {
+ BTM_TRACE_WARNING("%s: number of uuid in EIR = %d, size of uuid list = %d",
+ __func__, *p_num_uuid, max_num_uuid);
+ *p_num_uuid = max_num_uuid;
+ }
+
+ BTM_TRACE_DEBUG("%s: type = %02X, number of uuid = %d", __func__, type,
+ *p_num_uuid);
+
+ if (uuid_size == LEN_UUID_16) {
+ for (yy = 0; yy < *p_num_uuid; yy++) {
+ STREAM_TO_UINT16(*(p_uuid16 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG(" 0x%04X", *(p_uuid16 + yy));
+ }
+ } else if (uuid_size == LEN_UUID_32) {
+ for (yy = 0; yy < *p_num_uuid; yy++) {
+ STREAM_TO_UINT32(*(p_uuid32 + yy), p_uuid_data);
+ BTM_TRACE_DEBUG(" 0x%08X", *(p_uuid32 + yy));
+ }
+ } else if (uuid_size == LEN_UUID_128) {
+ for (yy = 0; yy < *p_num_uuid; yy++) {
+ STREAM_TO_ARRAY16(p_uuid_list + yy * LEN_UUID_128, p_uuid_data);
+ for (xx = 0; xx < LEN_UUID_128; xx++)
+ snprintf(buff + xx * 2, sizeof(buff) - xx * 2, "%02X",
+ *(p_uuid_list + yy * LEN_UUID_128 + xx));
+ BTM_TRACE_DEBUG(" 0x%s", buff);
+ }
+ }
+
+ return type;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_eir_get_uuid_list
+ *
+ * Description This function searches UUID list in EIR.
+ *
+ * Parameters p_eir - address of EIR
+ * eir_len - EIR length
+ * uuid_size - size of UUID to find
+ * p_num_uuid - number of UUIDs found
+ * p_uuid_list_type - EIR data type
+ *
+ * Returns NULL - if UUID list with uuid_size is not found
+ * beginning of UUID list in EIR - otherwise
+ *
+ ******************************************************************************/
+static const uint8_t* btm_eir_get_uuid_list(uint8_t* p_eir, size_t eir_len,
+ uint8_t uuid_size,
+ uint8_t* p_num_uuid,
+ uint8_t* p_uuid_list_type) {
+ const uint8_t* p_uuid_data;
+ uint8_t complete_type, more_type;
+ uint8_t uuid_len;
+
+ switch (uuid_size) {
+ case LEN_UUID_16:
+ complete_type = BTM_EIR_COMPLETE_16BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_32:
+ complete_type = BTM_EIR_COMPLETE_32BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_32BITS_UUID_TYPE;
+ break;
+ case LEN_UUID_128:
+ complete_type = BTM_EIR_COMPLETE_128BITS_UUID_TYPE;
+ more_type = BTM_EIR_MORE_128BITS_UUID_TYPE;
+ break;
+ default:
+ *p_num_uuid = 0;
+ return NULL;
+ break;
+ }
+
+ p_uuid_data = AdvertiseDataParser::GetFieldByType(p_eir, eir_len,
+ complete_type, &uuid_len);
+ if (p_uuid_data == NULL) {
+ p_uuid_data = AdvertiseDataParser::GetFieldByType(p_eir, eir_len, more_type,
+ &uuid_len);
+ *p_uuid_list_type = more_type;
+ } else {
+ *p_uuid_list_type = complete_type;
+ }
+
+ *p_num_uuid = uuid_len / uuid_size;
+ return p_uuid_data;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_convert_uuid_to_uuid16
+ *
+ * Description This function converts UUID to UUID 16-bit.
+ *
+ * Parameters p_uuid - address of UUID
+ * uuid_size - size of UUID
+ *
+ * Returns 0 - if UUID cannot be converted to UUID 16-bit
+ * UUID 16-bit - otherwise
+ *
+ ******************************************************************************/
+static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid,
+ uint8_t uuid_size) {
+ static const uint8_t base_uuid[LEN_UUID_128] = {
+ 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint16_t uuid16 = 0;
+ uint32_t uuid32;
+ bool is_base_uuid;
+ uint8_t xx;
+
+ switch (uuid_size) {
+ case LEN_UUID_16:
+ STREAM_TO_UINT16(uuid16, p_uuid);
+ break;
+ case LEN_UUID_32:
+ STREAM_TO_UINT32(uuid32, p_uuid);
+ if (uuid32 < 0x10000) uuid16 = (uint16_t)uuid32;
+ break;
+ case LEN_UUID_128:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ is_base_uuid = true;
+ for (xx = 0; xx < LEN_UUID_128 - 4; xx++) {
+ if (p_uuid[xx] != base_uuid[xx]) {
+ is_base_uuid = false;
+ break;
+ }
+ }
+ if (is_base_uuid) {
+ if ((p_uuid[LEN_UUID_128 - 1] == 0) &&
+ (p_uuid[LEN_UUID_128 - 2] == 0)) {
+ p_uuid += (LEN_UUID_128 - 4);
+ STREAM_TO_UINT16(uuid16, p_uuid);
+ }
+ }
+ break;
+ default:
+ BTM_TRACE_WARNING("btm_convert_uuid_to_uuid16 invalid uuid size");
+ break;
+ }
+
+ return (uuid16);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_set_eir_uuid
+ *
+ * Description This function is called to store received UUID into inquiry
+ * result.
+ *
+ * Parameters p_eir - pointer of EIR significant part
+ * p_results - pointer of inquiry result
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void btm_set_eir_uuid(uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) {
+ const uint8_t* p_uuid_data;
+ uint8_t num_uuid;
+ uint16_t uuid16;
+ uint8_t yy;
+ uint8_t type = BTM_EIR_MORE_16BITS_UUID_TYPE;
+
+ p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
+ LEN_UUID_16, &num_uuid, &type);
+
+ if (type == BTM_EIR_COMPLETE_16BITS_UUID_TYPE) {
+ p_results->eir_complete_list = true;
+ } else {
+ p_results->eir_complete_list = false;
+ }
+
+ BTM_TRACE_API("btm_set_eir_uuid eir_complete_list=0x%02X",
+ p_results->eir_complete_list);
+
+ if (p_uuid_data) {
+ for (yy = 0; yy < num_uuid; yy++) {
+ STREAM_TO_UINT16(uuid16, p_uuid_data);
+ BTM_AddEirService(p_results->eir_uuid, uuid16);
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
+ LEN_UUID_32, &num_uuid, &type);
+ if (p_uuid_data) {
+ for (yy = 0; yy < num_uuid; yy++) {
+ uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_32);
+ p_uuid_data += LEN_UUID_32;
+ if (uuid16) BTM_AddEirService(p_results->eir_uuid, uuid16);
+ }
+ }
+
+ p_uuid_data = btm_eir_get_uuid_list(p_eir, HCI_EXT_INQ_RESPONSE_LEN,
+ LEN_UUID_128, &num_uuid, &type);
+ if (p_uuid_data) {
+ for (yy = 0; yy < num_uuid; yy++) {
+ uuid16 = btm_convert_uuid_to_uuid16(p_uuid_data, LEN_UUID_128);
+ p_uuid_data += LEN_UUID_128;
+ if (uuid16) BTM_AddEirService(p_results->eir_uuid, uuid16);
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_int.h b/mtkbt/code/bt/stack/btm/btm_int.h
new file mode 100755
index 0000000..00aa7f7
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_int.h
@@ -0,0 +1,281 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main Bluetooth Manager (BTM) internal
+ * definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_INT_H
+#define BTM_INT_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "hcidefs.h"
+
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+#include "rfcdefs.h"
+
+#include "btm_api.h"
+#include "device/include/esco_parameters.h"
+
+#include "btm_ble_int.h"
+#include "btm_int_types.h"
+#include "smp_api.h"
+
+extern tBTM_CB btm_cb;
+
+/* Internal functions provided by btm_main.cc
+ *******************************************
+*/
+extern void btm_init(void);
+/** M: Fix fdleak bug @{ */
+extern void btm_free(void);
+/** @} */
+
+/* Internal functions provided by btm_inq.cc
+ ******************************************
+*/
+extern tBTM_STATUS btm_initiate_rem_name(BD_ADDR remote_bda, uint8_t origin,
+ period_ms_t timeout_ms,
+ tBTM_CMPL_CB* p_cb);
+
+extern void btm_process_remote_name(BD_ADDR bda, BD_NAME name, uint16_t evt_len,
+ uint8_t hci_status);
+extern void btm_inq_rmt_name_failed(void);
+extern void btm_inq_remote_name_timer_timeout(void* data);
+
+/* Inquiry related functions */
+extern void btm_clr_inq_db(BD_ADDR p_bda);
+extern void btm_inq_db_init(void);
+extern void btm_process_inq_results(uint8_t* p, uint8_t inq_res_mode);
+extern void btm_process_inq_complete(uint8_t status, uint8_t mode);
+extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_event_filter_complete(uint8_t* p);
+extern void btm_inq_stop_on_ssp(void);
+extern void btm_inq_clear_ssp(void);
+extern tINQ_DB_ENT* btm_inq_db_find(const BD_ADDR p_bda);
+extern bool btm_inq_find_bdaddr(BD_ADDR p_bda);
+
+extern bool btm_lookup_eir(BD_ADDR_PTR p_rem_addr);
+
+/* Internal functions provided by btm_acl.cc
+ *******************************************
+*/
+extern void btm_acl_init(void);
+extern void btm_acl_created(BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
+ uint16_t hci_handle, uint8_t link_role,
+ tBT_TRANSPORT transport);
+extern void btm_acl_removed(BD_ADDR bda, tBT_TRANSPORT transport);
+extern void btm_acl_device_down(void);
+extern void btm_acl_update_busy_level(tBTM_BLI_EVENT event);
+
+extern void btm_cont_rswitch(tACL_CONN* p, tBTM_SEC_DEV_REC* p_dev_rec,
+ uint8_t hci_status);
+
+extern uint8_t btm_handle_to_acl_index(uint16_t hci_handle);
+extern void btm_read_link_policy_complete(uint8_t* p);
+
+extern void btm_read_rssi_timeout(void* data);
+extern void btm_read_rssi_complete(uint8_t* p);
+
+extern void btm_read_tx_power_timeout(void* data);
+extern void btm_read_tx_power_complete(uint8_t* p, bool is_ble);
+
+extern void btm_read_link_quality_timeout(void* data);
+extern void btm_read_link_quality_complete(uint8_t* p);
+
+extern tBTM_STATUS btm_set_packet_types(tACL_CONN* p, uint16_t pkt_types);
+extern void btm_process_clk_off_comp_evt(uint16_t hci_handle,
+ uint16_t clock_offset);
+extern void btm_acl_role_changed(uint8_t hci_status, BD_ADDR bd_addr,
+ uint8_t new_role);
+extern void btm_acl_encrypt_change(uint16_t handle, uint8_t status,
+ uint8_t encr_enable);
+extern uint16_t btm_get_acl_disc_reason_code(void);
+extern tBTM_STATUS btm_remove_acl(BD_ADDR bd_addr, tBT_TRANSPORT transport);
+extern void btm_read_remote_features_complete(uint8_t* p);
+extern void btm_read_remote_ext_features_complete(uint8_t* p);
+extern void btm_read_remote_ext_features_failed(uint8_t status,
+ uint16_t handle);
+extern void btm_read_remote_version_complete(uint8_t* p);
+extern void btm_establish_continue(tACL_CONN* p_acl_cb);
+
+extern void btm_acl_chk_peer_pkt_type_support(tACL_CONN* p,
+ uint16_t* p_pkt_type);
+/* Read maximum data packet that can be sent over current connection */
+extern uint16_t btm_get_max_packet_size(BD_ADDR addr);
+extern tACL_CONN* btm_bda_to_acl(const BD_ADDR bda, tBT_TRANSPORT transport);
+extern bool btm_acl_notif_conn_collision(BD_ADDR bda);
+/** M: fix truncated conn_handle to uint16_t type@{ */
+extern void btm_acl_update_conn_addr(uint16_t conn_handle, BD_ADDR address);
+/** @} */
+
+extern void btm_pm_reset(void);
+extern void btm_pm_sm_alloc(uint8_t ind);
+extern void btm_pm_proc_cmd_status(uint8_t status);
+extern void btm_pm_proc_mode_change(uint8_t hci_status, uint16_t hci_handle,
+ uint8_t mode, uint16_t interval);
+extern void btm_pm_proc_ssr_evt(uint8_t* p, uint16_t evt_len);
+extern tBTM_STATUS btm_read_power_mode_state(BD_ADDR remote_bda,
+ tBTM_PM_STATE* pmState);
+#if (BTM_SCO_INCLUDED == TRUE)
+extern void btm_sco_chk_pend_unpark(uint8_t hci_status, uint16_t hci_handle);
+#else
+#define btm_sco_chk_pend_unpark(hci_status, hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+
+extern void btm_qos_setup_timeout(void* data);
+extern void btm_qos_setup_complete(uint8_t status, uint16_t handle,
+ FLOW_SPEC* p_flow);
+
+/* Internal functions provided by btm_sco.cc
+ *******************************************
+*/
+extern void btm_sco_init(void);
+extern void btm_sco_connected(uint8_t hci_status, BD_ADDR bda,
+ uint16_t hci_handle, tBTM_ESCO_DATA* p_esco_data);
+extern void btm_esco_proc_conn_chg(uint8_t status, uint16_t handle,
+ uint8_t tx_interval, uint8_t retrans_window,
+ uint16_t rx_pkt_len, uint16_t tx_pkt_len);
+extern void btm_sco_conn_req(BD_ADDR bda, DEV_CLASS dev_class,
+ uint8_t link_type);
+extern void btm_sco_removed(uint16_t hci_handle, uint8_t reason);
+extern void btm_sco_acl_removed(BD_ADDR bda);
+extern void btm_route_sco_data(BT_HDR* p_msg);
+extern bool btm_is_sco_active(uint16_t handle);
+extern void btm_remove_sco_links(BD_ADDR bda);
+extern bool btm_is_sco_active_by_bdaddr(BD_ADDR remote_bda);
+
+extern void btm_read_def_esco_mode(enh_esco_params_t* p_parms);
+extern uint16_t btm_find_scb_by_handle(uint16_t handle);
+extern void btm_sco_flush_sco_data(uint16_t sco_inx);
+
+/* Internal functions provided by btm_devctl.cc
+ *********************************************
+*/
+extern void btm_dev_init(void);
+extern void btm_read_local_name_timeout(void* data);
+extern void btm_read_local_name_complete(uint8_t* p, uint16_t evt_len);
+
+extern void btm_ble_add_2_white_list_complete(uint8_t status);
+extern void btm_ble_remove_from_white_list_complete(uint8_t* p,
+ uint16_t evt_len);
+extern void btm_ble_clear_white_list_complete(uint8_t* p, uint16_t evt_len);
+extern bool btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC* p_dev_rec);
+extern tBTM_STATUS btm_ble_read_resolving_list_entry(
+ tBTM_SEC_DEV_REC* p_dev_rec);
+extern bool btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC* p_dev_rec);
+extern void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC* p_dev_rec);
+
+/* Vendor Specific Command complete evt handler */
+extern void btm_vsc_complete(uint8_t* p, uint16_t cc_opcode, uint16_t evt_len,
+ tBTM_CMPL_CB* p_vsc_cplt_cback);
+extern void btm_inq_db_reset(void);
+extern void btm_vendor_specific_evt(uint8_t* p, uint8_t evt_len);
+extern void btm_delete_stored_link_key_complete(uint8_t* p);
+extern void btm_report_device_status(tBTM_DEV_STATUS status);
+
+/* Internal functions provided by btm_dev.cc
+ *********************************************
+*/
+extern bool btm_dev_support_switch(BD_ADDR bd_addr);
+
+extern tBTM_SEC_DEV_REC* btm_sec_allocate_dev_rec(void);
+extern tBTM_SEC_DEV_REC* btm_sec_alloc_dev(BD_ADDR bd_addr);
+extern void btm_sec_free_dev(tBTM_SEC_DEV_REC* p_dev_rec);
+extern tBTM_SEC_DEV_REC* btm_find_dev(const BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC* btm_find_or_alloc_dev(BD_ADDR bd_addr);
+extern tBTM_SEC_DEV_REC* btm_find_dev_by_handle(uint16_t handle);
+extern tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr);
+extern bool btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type);
+
+/* Internal functions provided by btm_sec.cc
+ *********************************************
+*/
+extern bool btm_dev_support_switch(BD_ADDR bd_addr);
+extern tBTM_STATUS btm_sec_l2cap_access_req(BD_ADDR bd_addr, uint16_t psm,
+ uint16_t handle,
+ CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data);
+extern tBTM_STATUS btm_sec_mx_access_request(
+ BD_ADDR bd_addr, uint16_t psm, bool is_originator, uint32_t mx_proto_id,
+ uint32_t mx_chan_id, tBTM_SEC_CALLBACK* p_callback, void* p_ref_data);
+extern void btm_sec_conn_req(uint8_t* bda, uint8_t* dc);
+extern void btm_create_conn_cancel_complete(uint8_t* p);
+
+extern void btm_read_inq_tx_power_timeout(void* data);
+extern void btm_read_inq_tx_power_complete(uint8_t* p);
+
+extern void btm_sec_init(uint8_t sec_mode);
+extern void btm_sec_dev_reset(void);
+extern void btm_sec_abort_access_req(BD_ADDR bd_addr);
+extern void btm_sec_auth_complete(uint16_t handle, uint8_t status);
+extern void btm_sec_encrypt_change(uint16_t handle, uint8_t status,
+ uint8_t encr_enable);
+extern void btm_sec_connected(uint8_t* bda, uint16_t handle, uint8_t status,
+ uint8_t enc_mode);
+extern tBTM_STATUS btm_sec_disconnect(uint16_t handle, uint8_t reason);
+extern void btm_sec_disconnected(uint16_t handle, uint8_t reason);
+extern void btm_sec_rmt_name_request_complete(uint8_t* bd_addr,
+ uint8_t* bd_name, uint8_t status);
+extern void btm_sec_rmt_host_support_feat_evt(uint8_t* p);
+extern void btm_io_capabilities_req(uint8_t* p);
+extern void btm_io_capabilities_rsp(uint8_t* p);
+extern void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p);
+extern void btm_keypress_notif_evt(uint8_t* p);
+extern void btm_simple_pair_complete(uint8_t* p);
+extern void btm_sec_link_key_notification(uint8_t* p_bda, uint8_t* p_link_key,
+ uint8_t key_type);
+extern void btm_sec_link_key_request(uint8_t* p_bda);
+extern void btm_sec_pin_code_request(uint8_t* p_bda);
+extern void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset);
+extern void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec,
+ uint8_t res, bool is_le_trasnport);
+extern void btm_sec_set_peer_sec_caps(tACL_CONN* p_acl_cb,
+ tBTM_SEC_DEV_REC* p_dev_rec);
+
+extern void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec);
+extern bool btm_sec_is_a_bonded_dev(BD_ADDR bda);
+extern void btm_consolidate_dev(tBTM_SEC_DEV_REC* p_target_rec);
+extern bool btm_sec_is_le_capable_dev(BD_ADDR bda);
+extern bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec,
+ BD_ADDR new_pseudo_addr);
+extern tBTM_SEC_SERV_REC* btm_sec_find_first_serv(CONNECTION_TYPE conn_type,
+ uint16_t psm);
+extern bool btm_ble_start_sec_check(BD_ADDR bd_addr, uint16_t psm,
+ bool is_originator,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data);
+
+extern tINQ_DB_ENT* btm_inq_db_new(BD_ADDR p_bda);
+
+extern void btm_rem_oob_req(uint8_t* p);
+extern void btm_read_local_oob_complete(uint8_t* p);
+
+extern void btm_acl_resubmit_page(void);
+extern void btm_acl_reset_paging(void);
+extern void btm_acl_paging(BT_HDR* p, BD_ADDR dest);
+extern uint8_t btm_sec_clr_service_by_psm(uint16_t psm);
+extern void btm_sec_clr_temp_auth_service(BD_ADDR bda);
+
+#endif
diff --git a/mtkbt/code/bt/stack/btm/btm_int_types.h b/mtkbt/code/bt/stack/btm/btm_int_types.h
new file mode 100755
index 0000000..bb083e2
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_int_types.h
@@ -0,0 +1,885 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef BTM_INT_TYPES_H
+#define BTM_INT_TYPES_H
+
+#include "btm_api_types.h"
+#include "btm_ble_api_types.h"
+#include "btm_ble_int_types.h"
+#include "hcidefs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/list.h"
+#include "rfcdefs.h"
+
+typedef char tBTM_LOC_BD_NAME[BTM_MAX_LOC_BD_NAME_LEN + 1];
+
+#define BTM_ACL_IS_CONNECTED(bda) \
+ (btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR) != NULL)
+
+/* Definitions for Server Channel Number (SCN) management
+*/
+#define BTM_MAX_SCN PORT_MAX_RFC_PORTS
+
+/* Define masks for supported and exception 2.0 ACL packet types
+*/
+#define BTM_ACL_SUPPORTED_PKTS_MASK \
+ (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 | HCI_PKT_TYPES_MASK_DM3 | \
+ HCI_PKT_TYPES_MASK_DH3 | HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5)
+
+#define BTM_ACL_EXCEPTION_PKTS_MASK \
+ (HCI_PKT_TYPES_MASK_NO_2_DH1 | HCI_PKT_TYPES_MASK_NO_3_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH3 | HCI_PKT_TYPES_MASK_NO_3_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH5 | HCI_PKT_TYPES_MASK_NO_3_DH5)
+
+#define BTM_EPR_AVAILABLE(p) \
+ ((HCI_ATOMIC_ENCRYPT_SUPPORTED((p)->peer_lmp_feature_pages[0]) && \
+ HCI_ATOMIC_ENCRYPT_SUPPORTED( \
+ controller_get_interface()->get_features_classic(0)->as_array)) \
+ ? true \
+ : false)
+
+#define BTM_IS_BRCM_CONTROLLER() \
+ (controller_get_interface()->get_bt_version()->manufacturer == \
+ LMP_COMPID_BROADCOM)
+
+/** M: define MTK controller @{ */
+#define BTM_IS_MTK_CONTROLLER() \
+ (controller_get_interface()->get_bt_version()->manufacturer == \
+ LMP_COMPID_MEDIATEK)
+/** @} */
+
+/* Define the ACL Management control structure
+*/
+typedef struct {
+ uint16_t hci_handle;
+ uint16_t pkt_types_mask;
+ uint16_t clock_offset;
+ BD_ADDR remote_addr;
+ DEV_CLASS remote_dc;
+ BD_NAME remote_name;
+
+ uint16_t manufacturer;
+ uint16_t lmp_subversion;
+ uint16_t link_super_tout;
+ BD_FEATURES
+ peer_lmp_feature_pages[HCI_EXT_FEATURES_PAGE_MAX + 1]; /* Peer LMP Extended
+ features mask table
+ for the device */
+ uint8_t num_read_pages;
+ uint8_t lmp_version;
+
+ bool in_use;
+ uint8_t link_role;
+ bool link_up_issued; /* True if busy_level link up has been issued */
+
+#define BTM_ACL_SWKEY_STATE_IDLE 0
+#define BTM_ACL_SWKEY_STATE_MODE_CHANGE 1
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF 2
+#define BTM_ACL_SWKEY_STATE_SWITCHING 3
+#define BTM_ACL_SWKEY_STATE_ENCRYPTION_ON 4
+#define BTM_ACL_SWKEY_STATE_IN_PROGRESS 5
+ uint8_t switch_role_state;
+
+#define BTM_ACL_ENCRYPT_STATE_IDLE 0
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_OFF 1 /* encryption turning off */
+#define BTM_ACL_ENCRYPT_STATE_TEMP_FUNC \
+ 2 /* temporarily off for change link key or role switch */
+#define BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON 3 /* encryption turning on */
+ uint8_t encrypt_state; /* overall BTM encryption state */
+
+ tBT_TRANSPORT transport;
+ BD_ADDR conn_addr; /* local device address used for this connection */
+ uint8_t conn_addr_type; /* local device address type for this connection */
+ BD_ADDR active_remote_addr; /* remote address used on this connection */
+ uint8_t active_remote_addr_type; /* local device address type for this
+ connection */
+ BD_FEATURES peer_le_features; /* Peer LE Used features mask for the device */
+
+} tACL_CONN;
+
+/* Define the Device Management control structure
+*/
+typedef struct {
+ tBTM_DEV_STATUS_CB* p_dev_status_cb; /* Device status change callback */
+ tBTM_VS_EVT_CB* p_vend_spec_cb
+ [BTM_MAX_VSE_CALLBACKS]; /* Register for vendor specific events */
+
+ tBTM_CMPL_CB*
+ p_stored_link_key_cmpl_cb; /* Read/Write/Delete stored link key */
+
+ alarm_t* read_local_name_timer; /* Read local name timer */
+ tBTM_CMPL_CB* p_rln_cmpl_cb; /* Callback function to be called when */
+ /* read local name function complete */
+ alarm_t* read_rssi_timer; /* Read RSSI timer */
+ tBTM_CMPL_CB* p_rssi_cmpl_cb; /* Callback function to be called when */
+ /* read RSSI function completes */
+ alarm_t* read_link_quality_timer;
+ tBTM_CMPL_CB* p_link_qual_cmpl_cb; /* Callback function to be called when */
+ /* read link quality function completes */
+
+ alarm_t* read_inq_tx_power_timer;
+ tBTM_CMPL_CB*
+ p_inq_tx_power_cmpl_cb; /* Callback function to be called when */
+ /* read inq tx power function completes */
+
+ alarm_t* qos_setup_timer; /* QoS setup timer */
+ tBTM_CMPL_CB* p_qos_setup_cmpl_cb; /* Callback function to be called when */
+ /* qos setup function completes */
+
+ tBTM_ROLE_SWITCH_CMPL switch_role_ref_data;
+ tBTM_CMPL_CB* p_switch_role_cb; /* Callback function to be called when */
+ /* requested switch role is completed */
+
+ alarm_t* read_tx_power_timer; /* Read tx power timer */
+ tBTM_CMPL_CB* p_tx_power_cmpl_cb; /* Callback function to be called */
+
+ DEV_CLASS dev_class; /* Local device class */
+
+ tBTM_CMPL_CB*
+ p_le_test_cmd_cmpl_cb; /* Callback function to be called when
+ LE test mode command has been sent successfully */
+
+ BD_ADDR read_tx_pwr_addr; /* read TX power target address */
+
+#define BTM_LE_SUPPORT_STATE_SIZE 8
+ uint8_t le_supported_states[BTM_LE_SUPPORT_STATE_SIZE];
+
+ tBTM_BLE_LOCAL_ID_KEYS id_keys; /* local BLE ID keys */
+ BT_OCTET16 ble_encryption_key_value; /* BLE encryption key */
+
+#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
+ bool no_disc_if_pair_fail;
+ bool enable_test_mac_val;
+ BT_OCTET8 test_mac;
+ bool enable_test_local_sign_cntr;
+ uint32_t test_local_sign_cntr;
+#endif
+
+ tBTM_IO_CAP loc_io_caps; /* IO capability of the local device */
+ tBTM_AUTH_REQ loc_auth_req; /* the auth_req flag */
+ bool secure_connections_only; /* Rejects service level 0 connections if */
+ /* itself or peer device doesn't support */
+ /* secure connections */
+} tBTM_DEVCB;
+
+/* Define the structures and constants used for inquiry
+*/
+
+/* Definitions of limits for inquiries */
+#define BTM_PER_INQ_MIN_MAX_PERIOD HCI_PER_INQ_MIN_MAX_PERIOD
+#define BTM_PER_INQ_MAX_MAX_PERIOD HCI_PER_INQ_MAX_MAX_PERIOD
+#define BTM_PER_INQ_MIN_MIN_PERIOD HCI_PER_INQ_MIN_MIN_PERIOD
+#define BTM_PER_INQ_MAX_MIN_PERIOD HCI_PER_INQ_MAX_MIN_PERIOD
+#define BTM_MAX_INQUIRY_LENGTH HCI_MAX_INQUIRY_LENGTH
+#define BTM_MIN_INQUIRY_LEN 0x01
+
+#define BTM_MIN_INQ_TX_POWER (-70)
+#define BTM_MAX_INQ_TX_POWER 20
+
+typedef struct {
+ uint32_t inq_count; /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ BD_ADDR bd_addr;
+} tINQ_BDADDR;
+
+typedef struct {
+ uint32_t time_of_resp;
+ uint32_t
+ inq_count; /* "timestamps" the entry with a particular inquiry count */
+ /* Used for determining if a response has already been */
+ /* received for the current inquiry operation. (We do not */
+ /* want to flood the caller with multiple responses from */
+ /* the same device. */
+ tBTM_INQ_INFO inq_info;
+ bool in_use;
+ bool scan_rsp;
+} tINQ_DB_ENT;
+
+enum { INQ_NONE, INQ_LE_OBSERVE, INQ_GENERAL };
+typedef uint8_t tBTM_INQ_TYPE;
+
+typedef struct {
+ tBTM_CMPL_CB* p_remname_cmpl_cb;
+
+#define BTM_EXT_RMT_NAME_TIMEOUT_MS (40 * 1000) /* 40 seconds */
+
+ alarm_t* remote_name_timer;
+
+ uint16_t discoverable_mode;
+ uint16_t connectable_mode;
+ uint16_t page_scan_window;
+ uint16_t page_scan_period;
+ uint16_t inq_scan_window;
+ uint16_t inq_scan_period;
+ uint16_t inq_scan_type;
+ uint16_t page_scan_type; /* current page scan type */
+ tBTM_INQ_TYPE scan_type;
+
+ BD_ADDR remname_bda; /* Name of bd addr for active remote name request */
+#define BTM_RMT_NAME_INACTIVE 0
+#define BTM_RMT_NAME_EXT 0x1 /* Initiated through API */
+#define BTM_RMT_NAME_SEC 0x2 /* Initiated internally by security manager */
+#define BTM_RMT_NAME_INQ 0x4 /* Remote name initiated internally by inquiry */
+ bool remname_active; /* State of a remote name request by external API */
+
+ tBTM_CMPL_CB* p_inq_cmpl_cb;
+ tBTM_INQ_RESULTS_CB* p_inq_results_cb;
+ tBTM_CMPL_CB*
+ p_inq_ble_cmpl_cb; /*completion callback exclusively for LE Observe*/
+ tBTM_INQ_RESULTS_CB*
+ p_inq_ble_results_cb; /*results callback exclusively for LE observe*/
+ tBTM_CMPL_CB* p_inqfilter_cmpl_cb; /* Called (if not NULL) after inquiry
+ filter completed */
+ uint32_t inq_counter; /* Counter incremented each time an inquiry completes */
+ /* Used for determining whether or not duplicate devices */
+ /* have responded to the same inquiry */
+ tINQ_BDADDR* p_bd_db; /* Pointer to memory that holds bdaddrs */
+ uint16_t num_bd_entries; /* Number of entries in database */
+ uint16_t max_bd_entries; /* Maximum number of entries that can be stored */
+ tINQ_DB_ENT inq_db[BTM_INQ_DB_SIZE];
+ tBTM_INQ_PARMS inqparms; /* Contains the parameters for the current inquiry */
+ tBTM_INQUIRY_CMPL
+ inq_cmpl_info; /* Status and number of responses from the last inquiry */
+
+ uint16_t per_min_delay; /* Current periodic minimum delay */
+ uint16_t per_max_delay; /* Current periodic maximum delay */
+ bool inqfilt_active;
+ uint8_t pending_filt_complete_event; /* to take care of
+ btm_event_filter_complete
+ corresponding to */
+ /* inquiry that has been cancelled*/
+ uint8_t inqfilt_type; /* Contains the inquiry filter type (BD ADDR, COD, or
+ Clear) */
+
+#define BTM_INQ_INACTIVE_STATE 0
+#define BTM_INQ_CLR_FILT_STATE \
+ 1 /* Currently clearing the inquiry filter preceeding the inquiry request */
+ /* (bypassed if filtering is not used) */
+#define BTM_INQ_SET_FILT_STATE \
+ 2 /* Sets the new filter (or turns off filtering) in this state */
+#define BTM_INQ_ACTIVE_STATE \
+ 3 /* Actual inquiry or periodic inquiry is in progress */
+#define BTM_INQ_REMNAME_STATE 4 /* Remote name requests are active */
+
+ uint8_t state; /* Current state that the inquiry process is in */
+ uint8_t inq_active; /* Bit Mask indicating type of inquiry is active */
+ bool no_inc_ssp; /* true, to stop inquiry on incoming SSP */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ btm_inq_state
+ next_state; /*interleaving state to determine next mode to be inquired*/
+#endif
+} tBTM_INQUIRY_VAR_ST;
+
+/* The MSB of the clock offset field indicates whether the offset is valid. */
+#define BTM_CLOCK_OFFSET_VALID 0x8000
+
+/* Define the structures needed by security management
+*/
+
+#define BTM_SEC_INVALID_HANDLE 0xFFFF
+
+typedef uint8_t* BTM_BD_NAME_PTR; /* Pointer to Device name */
+
+/* Security callback is called by this unit when security
+ * procedures are completed. Parameters are
+ * BD Address of remote
+ * Result of the operation
+*/
+typedef tBTM_SEC_CBACK tBTM_SEC_CALLBACK;
+
+typedef void(tBTM_SCO_IND_CBACK)(uint16_t sco_inx);
+
+/* MACROs to convert from SCO packet types mask to ESCO and back */
+#define BTM_SCO_PKT_TYPE_MASK \
+ (HCI_PKT_TYPES_MASK_HV1 | HCI_PKT_TYPES_MASK_HV2 | HCI_PKT_TYPES_MASK_HV3)
+
+/* Mask defining only the SCO types of an esco packet type */
+#define BTM_ESCO_PKT_TYPE_MASK \
+ (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 | ESCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_SCO_2_ESCO(scotype) \
+ ((uint16_t)(((scotype)&BTM_SCO_PKT_TYPE_MASK) >> 5))
+#define BTM_ESCO_2_SCO(escotype) \
+ ((uint16_t)(((escotype)&BTM_ESCO_PKT_TYPE_MASK) << 5))
+
+/* Define masks for supported and exception 2.0 SCO packet types
+*/
+#define BTM_SCO_SUPPORTED_PKTS_MASK \
+ (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 | \
+ ESCO_PKT_TYPES_MASK_HV3 | ESCO_PKT_TYPES_MASK_EV3 | \
+ ESCO_PKT_TYPES_MASK_EV4 | ESCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_EXCEPTION_PKTS_MASK \
+ (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
+
+#define BTM_SCO_ROUTE_UNKNOWN 0xff
+
+/* Define the structure that contains (e)SCO data */
+typedef struct {
+ tBTM_ESCO_CBACK* p_esco_cback; /* Callback for eSCO events */
+ enh_esco_params_t setup;
+ tBTM_ESCO_DATA data; /* Connection complete information */
+ uint8_t hci_status;
+} tBTM_ESCO_INFO;
+
+/* Define the structure used for SCO Management
+*/
+typedef struct {
+ tBTM_ESCO_INFO esco; /* Current settings */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ fixed_queue_t* xmit_data_q; /* SCO data transmitting queue */
+#endif
+ tBTM_SCO_CB* p_conn_cb; /* Callback for when connected */
+ tBTM_SCO_CB* p_disc_cb; /* Callback for when disconnect */
+ uint16_t state; /* The state of the SCO link */
+ uint16_t hci_handle; /* HCI Handle */
+ bool is_orig; /* true if the originator */
+ bool rem_bd_known; /* true if remote BD addr known */
+ /** M: Bug Fix for create sco collision @{ */
+ bool is_collision; /* true if collision happened */
+ /** @} */
+
+} tSCO_CONN;
+
+/* SCO Management control block */
+typedef struct {
+ tBTM_SCO_IND_CBACK* app_sco_ind_cb;
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ tBTM_SCO_DATA_CB* p_data_cb; /* Callback for SCO data over HCI */
+#endif
+ tSCO_CONN sco_db[BTM_MAX_SCO_LINKS];
+ enh_esco_params_t def_esco_parms;
+ uint16_t sco_disc_reason;
+ bool esco_supported; /* true if 1.2 cntlr AND supports eSCO links */
+ esco_data_path_t sco_route; /* HCI, PCM, or TEST */
+} tSCO_CB;
+
+#if (BTM_SCO_INCLUDED == TRUE)
+extern void btm_set_sco_ind_cback(tBTM_SCO_IND_CBACK* sco_ind_cb);
+extern void btm_accept_sco_link(uint16_t sco_inx, enh_esco_params_t* p_setup,
+ tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb);
+extern void btm_reject_sco_link(uint16_t sco_inx);
+extern void btm_sco_chk_pend_rolechange(uint16_t hci_handle);
+extern void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle);
+
+#else
+#define btm_accept_sco_link(sco_inx, p_setup, p_conn_cb, p_disc_cb)
+#define btm_reject_sco_link(sco_inx)
+#define btm_set_sco_ind_cback(sco_ind_cb)
+#define btm_sco_chk_pend_rolechange(hci_handle)
+#endif /* BTM_SCO_INCLUDED */
+
+/*
+ * Define structure for Security Service Record.
+ * A record exists for each service registered with the Security Manager
+*/
+#define BTM_SEC_OUT_FLAGS \
+ (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHORIZE)
+#define BTM_SEC_IN_FLAGS \
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)
+
+#define BTM_SEC_OUT_LEVEL4_FLAGS \
+ (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_MITM | \
+ BTM_SEC_MODE4_LEVEL4)
+
+#define BTM_SEC_IN_LEVEL4_FLAGS \
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_MITM | \
+ BTM_SEC_MODE4_LEVEL4)
+typedef struct {
+ uint32_t mx_proto_id; /* Service runs over this multiplexer protocol */
+ uint32_t orig_mx_chan_id; /* Channel on the multiplexer protocol */
+ uint32_t term_mx_chan_id; /* Channel on the multiplexer protocol */
+ uint16_t psm; /* L2CAP PSM value */
+ uint16_t security_flags; /* Bitmap of required security features */
+ uint8_t service_id; /* Passed in authorization callback */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ uint16_t
+ ucd_security_flags; /* Bitmap of required security features for UCD */
+#endif
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ uint8_t orig_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+ uint8_t term_service_name[BTM_SEC_SERVICE_NAME_LEN + 1];
+#endif
+} tBTM_SEC_SERV_REC;
+
+/* LE Security information of device in Slave Role */
+typedef struct {
+ BT_OCTET16 irk; /* peer diverified identity root */
+ BT_OCTET16 pltk; /* peer long term key */
+ BT_OCTET16 pcsrk; /* peer SRK peer device used to secured sign local data */
+
+ BT_OCTET16 lltk; /* local long term key */
+ BT_OCTET16 lcsrk; /* local SRK peer device used to secured sign local data */
+
+ BT_OCTET8 rand; /* random vector for LTK generation */
+ uint16_t ediv; /* LTK diversifier of this slave device */
+ uint16_t div; /* local DIV to generate local LTK=d1(ER,DIV,0) and
+ CSRK=d1(ER,DIV,1) */
+ uint8_t sec_level; /* local pairing security level */
+ uint8_t key_size; /* key size of the LTK delivered to peer device */
+ uint8_t srk_sec_level; /* security property of peer SRK for this device */
+ uint8_t local_csrk_sec_level; /* security property of local CSRK for this
+ device */
+
+ uint32_t counter; /* peer sign counter for verifying rcv signed cmd */
+ uint32_t local_counter; /* local sign counter for sending signed write cmd*/
+} tBTM_SEC_BLE_KEYS;
+
+typedef struct {
+ BD_ADDR pseudo_addr; /* LE pseudo address of the device if different from
+ device address */
+ tBLE_ADDR_TYPE ble_addr_type; /* LE device type: public or random address */
+ tBLE_ADDR_TYPE static_addr_type; /* static address type */
+ BD_ADDR static_addr; /* static address */
+
+#define BTM_WHITE_LIST_BIT 0x01
+#define BTM_RESOLVING_LIST_BIT 0x02
+ uint8_t in_controller_list; /* in controller resolving list or not */
+ uint8_t resolving_list_index;
+#if (BLE_PRIVACY_SPT == TRUE)
+ BD_ADDR cur_rand_addr; /* current random address */
+
+#define BTM_BLE_ADDR_PSEUDO 0 /* address index device record */
+#define BTM_BLE_ADDR_RRA 1 /* cur_rand_addr */
+#define BTM_BLE_ADDR_STATIC 2 /* static_addr */
+ uint8_t active_addr_type;
+#endif
+
+ tBTM_LE_KEY_TYPE key_type; /* bit mask of valid key types in record */
+ tBTM_SEC_BLE_KEYS keys; /* LE device security info in slave rode */
+} tBTM_SEC_BLE;
+
+/* Peering bond type */
+enum { BOND_TYPE_UNKNOWN, BOND_TYPE_PERSISTENT, BOND_TYPE_TEMPORARY };
+typedef uint8_t tBTM_BOND_TYPE;
+
+/*
+ * Define structure for Security Device Record.
+ * A record exists for each device authenticated with this device
+*/
+typedef struct {
+ tBTM_SEC_SERV_REC* p_cur_service;
+ tBTM_SEC_CALLBACK* p_callback;
+ void* p_ref_data;
+ uint32_t timestamp; /* Timestamp of the last connection */
+ uint32_t trusted_mask[BTM_SEC_SERVICE_ARRAY_SIZE]; /* Bitwise OR of trusted
+ services */
+ uint16_t hci_handle; /* Handle to connection when exists */
+ uint16_t clock_offset; /* Latest known clock offset */
+ BD_ADDR bd_addr; /* BD_ADDR of the device */
+ DEV_CLASS dev_class; /* DEV_CLASS of the device */
+ LINK_KEY link_key; /* Device link key */
+ uint8_t pin_code_length; /* Length of the pin_code used for paring */
+
+#define BTM_SEC_AUTHORIZED BTM_SEC_FLAG_AUTHORIZED /* 0x01 */
+#define BTM_SEC_AUTHENTICATED BTM_SEC_FLAG_AUTHENTICATED /* 0x02 */
+#define BTM_SEC_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED /* 0x04 */
+#define BTM_SEC_NAME_KNOWN 0x08
+#define BTM_SEC_LINK_KEY_KNOWN BTM_SEC_FLAG_LKEY_KNOWN /* 0x10 */
+#define BTM_SEC_LINK_KEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED /* 0x20 */
+#define BTM_SEC_ROLE_SWITCHED 0x40
+#define BTM_SEC_IN_USE 0x80
+/* LE link security flag */
+#define BTM_SEC_LE_AUTHENTICATED \
+ 0x0200 /* LE link is encrypted after pairing with MITM */
+#define BTM_SEC_LE_ENCRYPTED 0x0400 /* LE link is encrypted */
+#define BTM_SEC_LE_NAME_KNOWN 0x0800 /* not used */
+#define BTM_SEC_LE_LINK_KEY_KNOWN \
+ 0x1000 /* bonded with peer (peer LTK and/or SRK is saved) */
+#define BTM_SEC_LE_LINK_KEY_AUTHED 0x2000 /* pairing is done with MITM */
+#define BTM_SEC_16_DIGIT_PIN_AUTHED \
+ 0x4000 /* pairing is done with 16 digit pin */
+
+ uint16_t sec_flags; /* Current device security state */
+
+ tBTM_BD_NAME sec_bd_name; /* User friendly name of the device. (may be
+ truncated to save space in dev_rec table) */
+ BD_FEATURES feature_pages[HCI_EXT_FEATURES_PAGE_MAX +
+ 1]; /* Features supported by the device */
+ uint8_t num_read_pages;
+
+#define BTM_SEC_STATE_IDLE 0
+#define BTM_SEC_STATE_AUTHENTICATING 1
+#define BTM_SEC_STATE_ENCRYPTING 2
+#define BTM_SEC_STATE_GETTING_NAME 3
+#define BTM_SEC_STATE_AUTHORIZING 4
+#define BTM_SEC_STATE_SWITCHING_ROLE 5
+#define BTM_SEC_STATE_DISCONNECTING 6 /* disconnecting BR/EDR */
+#define BTM_SEC_STATE_DELAY_FOR_ENC \
+ 7 /* delay to check for encryption to work around */
+ /* controller problems */
+#define BTM_SEC_STATE_DISCONNECTING_BLE 8 /* disconnecting BLE */
+#define BTM_SEC_STATE_DISCONNECTING_BOTH 9 /* disconnecting BR/EDR and BLE */
+
+ uint8_t sec_state; /* Operating state */
+ bool is_originator; /* true if device is originating connection */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ bool is_ucd; /* true if device is sending or receiving UCD */
+ /* if incoming security failed, received UCD will be discarded */
+#endif
+ bool role_master; /* true if current mode is master */
+ uint16_t security_required; /* Security required for connection */
+ bool link_key_not_sent; /* link key notification has not been sent waiting for
+ name */
+ uint8_t link_key_type; /* Type of key used in pairing */
+ bool link_key_changed; /* Changed link key during current connection */
+
+#define BTM_MAX_PRE_SM4_LKEY_TYPE \
+ BTM_LKEY_TYPE_REMOTE_UNIT /* the link key type used by legacy pairing */
+
+#define BTM_SM4_UNKNOWN 0x00
+#define BTM_SM4_KNOWN 0x10
+#define BTM_SM4_TRUE 0x11
+#define BTM_SM4_REQ_PEND 0x08 /* set this bit when getting remote features */
+#define BTM_SM4_UPGRADE 0x04 /* set this bit when upgrading link key */
+#define BTM_SM4_RETRY \
+ 0x02 /* set this bit to retry on HCI_ERR_KEY_MISSING or \
+ HCI_ERR_LMP_ERR_TRANS_COLLISION */
+#define BTM_SM4_DD_ACP \
+ 0x20 /* set this bit to indicate peer initiated dedicated bonding */
+#define BTM_SM4_CONN_PEND \
+ 0x40 /* set this bit to indicate accepting acl conn; to be cleared on \
+ btm_acl_created */
+ uint8_t sm4; /* BTM_SM4_TRUE, if the peer supports SM4 */
+ tBTM_IO_CAP rmt_io_caps; /* IO capability of the peer device */
+ tBTM_AUTH_REQ rmt_auth_req; /* the auth_req flag as in the IO caps rsp evt */
+ bool remote_supports_secure_connections;
+ bool remote_features_needed; /* set to true if the local device is in */
+ /* "Secure Connections Only" mode and it receives */
+ /* HCI_IO_CAPABILITY_REQUEST_EVT from the peer before */
+ /* it knows peer's support for Secure Connections */
+
+ uint16_t ble_hci_handle; /* use in DUMO connection */
+ uint8_t enc_key_size; /* current link encryption key size */
+ tBT_DEVICE_TYPE device_type;
+ bool new_encryption_key_is_p256; /* Set to true when the newly generated LK
+ ** is generated from P-256.
+ ** Link encrypted with such LK can be used
+ ** for SM over BR/EDR.
+ */
+ bool no_smp_on_br; /* if set to true then SMP on BR/EDR doesn't */
+ /* work, i.e. link keys crosspairing */
+ /* SC BR/EDR->SC LE doesn't happen */
+ tBTM_BOND_TYPE bond_type; /* peering bond type */
+
+ tBTM_SEC_BLE ble;
+ tBTM_LE_CONN_PRAMS conn_params;
+
+#if (BTM_DISC_DURING_RS == TRUE)
+#define BTM_SEC_RS_NOT_PENDING 0 /* Role Switch not in progress */
+#define BTM_SEC_RS_PENDING 1 /* Role Switch in progress */
+#define BTM_SEC_DISC_PENDING 2 /* Disconnect is pending */
+ uint8_t rs_disc_pending;
+#endif
+#define BTM_SEC_NO_LAST_SERVICE_ID 0
+ uint8_t last_author_service_id; /* ID of last serviced authorized: Reset after
+ each l2cap connection */
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(HANDLE_KEY_MISSING) && (HANDLE_KEY_MISSING == TRUE)
+ uint8_t sec_status; /*status for pin_or_key_missing*/
+#endif
+#endif
+
+} tBTM_SEC_DEV_REC;
+
+#define BTM_SEC_IS_SM4(sm) ((bool)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_LEGACY(sm) ((bool)(BTM_SM4_KNOWN == ((sm)&BTM_SM4_TRUE)))
+#define BTM_SEC_IS_SM4_UNKNOWN(sm) \
+ ((bool)(BTM_SM4_UNKNOWN == ((sm)&BTM_SM4_TRUE)))
+
+#define BTM_SEC_LE_MASK \
+ (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | \
+ BTM_SEC_LE_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_AUTHED)
+
+/*
+ * Define device configuration structure
+*/
+typedef struct {
+ tBTM_LOC_BD_NAME bd_name; /* local Bluetooth device name */
+ bool pin_type; /* true if PIN type is fixed */
+ uint8_t pin_code_len; /* Bonding information */
+ PIN_CODE pin_code; /* PIN CODE if pin type is fixed */
+ bool connectable; /* If true page scan should be enabled */
+ uint8_t def_inq_scan_mode; /* ??? limited/general/none */
+} tBTM_CFG;
+
+enum {
+ BTM_PM_ST_ACTIVE = BTM_PM_STS_ACTIVE,
+ BTM_PM_ST_HOLD = BTM_PM_STS_HOLD,
+ BTM_PM_ST_SNIFF = BTM_PM_STS_SNIFF,
+ BTM_PM_ST_PARK = BTM_PM_STS_PARK,
+ BTM_PM_ST_PENDING = BTM_PM_STS_PENDING,
+ BTM_PM_ST_INVALID = 0xFF
+};
+typedef uint8_t tBTM_PM_STATE;
+
+enum {
+ BTM_PM_SET_MODE_EVT, /* Set power mode API is called. */
+ BTM_PM_UPDATE_EVT,
+ BTM_PM_RD_MODE_EVT /* Read power mode API is called. */
+};
+typedef uint8_t tBTM_PM_EVENT;
+
+typedef struct {
+ uint16_t event;
+ uint16_t len;
+ uint8_t link_ind;
+} tBTM_PM_MSG_DATA;
+
+typedef struct {
+ uint8_t hci_status;
+ uint8_t mode;
+ uint16_t interval;
+} tBTM_PM_MD_CHG_DATA;
+
+typedef struct {
+ uint8_t pm_id; /* the entity that calls SetPowerMode API */
+ tBTM_PM_PWR_MD* p_pmd;
+} tBTM_PM_SET_MD_DATA;
+
+typedef struct {
+ void* p_data;
+ uint8_t link_ind;
+} tBTM_PM_SM_DATA;
+
+typedef struct {
+ tBTM_PM_PWR_MD req_mode[BTM_MAX_PM_RECORDS + 1]; /* the desired mode and
+ parameters of the
+ connection*/
+ tBTM_PM_PWR_MD
+ set_mode; /* the mode and parameters sent down to the host controller. */
+ uint16_t interval; /* the interval from last mode change event. */
+#if (BTM_SSR_INCLUDED == TRUE)
+ uint16_t max_lat; /* stored SSR maximum latency */
+ uint16_t min_rmt_to; /* stored SSR minimum remote timeout */
+ uint16_t min_loc_to; /* stored SSR minimum local timeout */
+#endif
+ tBTM_PM_STATE state; /* contains the current mode of the connection */
+ bool chg_ind; /* a request change indication */
+} tBTM_PM_MCB;
+
+#define BTM_PM_REC_NOT_USED 0
+typedef struct {
+ tBTM_PM_STATUS_CBACK*
+ cback; /* to notify the registered party of mode change event */
+ uint8_t mask; /* registered request mask. 0, if this entry is not used */
+} tBTM_PM_RCB;
+
+enum {
+ BTM_BLI_ACL_UP_EVT,
+ BTM_BLI_ACL_DOWN_EVT,
+ BTM_BLI_PAGE_EVT,
+ BTM_BLI_PAGE_DONE_EVT,
+ BTM_BLI_INQ_EVT,
+ BTM_BLI_INQ_CANCEL_EVT,
+ BTM_BLI_INQ_DONE_EVT
+};
+typedef uint8_t tBTM_BLI_EVENT;
+
+/* Pairing State */
+enum {
+ BTM_PAIR_STATE_IDLE, /* Idle */
+ BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name (to check for SM4) */
+ BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req
+ (PIN is pre-fetched) */
+ BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */
+ BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric
+ confirmation */
+ BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */
+ BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB
+ data */
+ BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB
+ data */
+ BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */
+ BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication
+ cpmplete */
+ BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */
+};
+typedef uint8_t tBTM_PAIRING_STATE;
+
+#define BTM_PAIR_FLAGS_WE_STARTED_DD \
+ 0x01 /* We want to do dedicated bonding */
+#define BTM_PAIR_FLAGS_PEER_STARTED_DD \
+ 0x02 /* Peer initiated dedicated bonding */
+#define BTM_PAIR_FLAGS_DISC_WHEN_DONE 0x04 /* Disconnect when done */
+#define BTM_PAIR_FLAGS_PIN_REQD \
+ 0x08 /* set this bit when pin_callback is called */
+#define BTM_PAIR_FLAGS_PRE_FETCH_PIN \
+ 0x10 /* set this bit when pre-fetch pin */
+#define BTM_PAIR_FLAGS_REJECTED_CONNECT \
+ 0x20 /* set this bit when rejected incoming connection */
+#define BTM_PAIR_FLAGS_WE_CANCEL_DD \
+ 0x40 /* set this bit when cancelling a bonding procedure */
+#define BTM_PAIR_FLAGS_LE_ACTIVE \
+ 0x80 /* use this bit when SMP pairing is active */
+
+typedef struct {
+ bool is_mux;
+ BD_ADDR bd_addr;
+ uint16_t psm;
+ bool is_orig;
+ tBTM_SEC_CALLBACK* p_callback;
+ void* p_ref_data;
+ uint32_t mx_proto_id;
+ uint32_t mx_chan_id;
+ tBT_TRANSPORT transport;
+ tBTM_BLE_SEC_ACT sec_act;
+} tBTM_SEC_QUEUE_ENTRY;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+#define CONN_ORIENT_TERM 0x00 /* incoming connection oriented */
+#define CONN_ORIENT_ORIG 0x01 /* outgoing connection oriented */
+#define CONNLESS_TERM 0x02 /* incoming connectionless */
+#define CONNLESS_ORIG 0x03 /* outgoing connectionless */
+#define CONNECTION_TYPE_ORIG_MASK 0x01 /* mask for direction */
+#define CONNECTION_TYPE_CONNLESS_MASK \
+ 0x02 /* mask for connectionless or not \
+ */
+typedef uint8_t CONNECTION_TYPE;
+
+#else
+
+#define CONN_ORIENT_TERM false
+#define CONN_ORIENT_ORIG true
+typedef bool CONNECTION_TYPE;
+
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
+
+/* Define a structure to hold all the BTM data
+*/
+
+#define BTM_STATE_BUFFER_SIZE 5 /* size of state buffer */
+
+typedef struct {
+ tBTM_CFG cfg; /* Device configuration */
+
+ /****************************************************
+ ** ACL Management
+ ****************************************************/
+ tACL_CONN acl_db[MAX_L2CAP_LINKS];
+ uint8_t btm_scn[BTM_MAX_SCN]; /* current SCNs: true if SCN is in use */
+ uint16_t btm_def_link_policy;
+ uint16_t btm_def_link_super_tout;
+
+ tBTM_BL_EVENT_MASK bl_evt_mask;
+ tBTM_BL_CHANGE_CB* p_bl_changed_cb; /* Callback for when Busy Level changed */
+
+ /****************************************************
+ ** Power Management
+ ****************************************************/
+ tBTM_PM_MCB pm_mode_db[MAX_L2CAP_LINKS]; /* per ACL link */
+ tBTM_PM_RCB pm_reg_db[BTM_MAX_PM_RECORDS + 1]; /* per application/module */
+ uint8_t pm_pend_link; /* the index of acl_db, which has a pending PM cmd */
+ uint8_t pm_pend_id; /* the id pf the module, which has a pending PM cmd */
+
+ /*****************************************************
+ ** Device control
+ *****************************************************/
+ tBTM_DEVCB devcb;
+
+ /*****************************************************
+ ** BLE Device controllers
+ *****************************************************/
+ tBTM_BLE_CB ble_ctr_cb;
+
+ uint16_t enc_handle;
+ BT_OCTET8 enc_rand; /* received rand value from LTK request*/
+ uint16_t ediv; /* received ediv value from LTK request */
+ uint8_t key_size;
+ tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
+
+ /* Packet types supported by the local device */
+ uint16_t btm_acl_pkt_types_supported;
+ uint16_t btm_sco_pkt_types_supported;
+
+ /*****************************************************
+ ** Inquiry
+ *****************************************************/
+ tBTM_INQUIRY_VAR_ST btm_inq_vars;
+
+/*****************************************************
+** SCO Management
+*****************************************************/
+#if (BTM_SCO_INCLUDED == TRUE)
+ tSCO_CB sco_cb;
+#endif
+
+ /*****************************************************
+ ** Security Management
+ *****************************************************/
+ tBTM_APPL_INFO api;
+
+#define BTM_SEC_MAX_RMT_NAME_CALLBACKS 2
+ tBTM_RMT_NAME_CALLBACK* p_rmt_name_callback[BTM_SEC_MAX_RMT_NAME_CALLBACKS];
+
+ tBTM_SEC_DEV_REC* p_collided_dev_rec;
+ alarm_t* sec_collision_timer;
+ uint32_t collision_start_time;
+ uint32_t max_collision_delay;
+ uint32_t dev_rec_count; /* Counter used for device record timestamp */
+ uint8_t security_mode;
+ bool pairing_disabled;
+ bool connect_only_paired;
+ bool security_mode_changed; /* mode changed during bonding */
+ bool pin_type_changed; /* pin type changed during bonding */
+ bool sec_req_pending; /* true if a request is pending */
+
+ uint8_t pin_code_len; /* for legacy devices */
+ PIN_CODE pin_code; /* for legacy devices */
+ tBTM_PAIRING_STATE pairing_state; /* The current pairing state */
+ uint8_t pairing_flags; /* The current pairing flags */
+ BD_ADDR pairing_bda; /* The device currently pairing */
+ alarm_t* pairing_timer; /* Timer for pairing process */
+ uint16_t disc_handle; /* for legacy devices */
+ uint8_t disc_reason; /* for legacy devices */
+ tBTM_SEC_SERV_REC sec_serv_rec[BTM_SEC_MAX_SERVICE_RECORDS];
+ list_t* sec_dev_rec; /* list of tBTM_SEC_DEV_REC */
+ tBTM_SEC_SERV_REC* p_out_serv;
+ tBTM_MKEY_CALLBACK* mkey_cback;
+
+ BD_ADDR connecting_bda;
+ DEV_CLASS connecting_dc;
+
+ uint8_t acl_disc_reason;
+ uint8_t trace_level;
+ uint8_t busy_level; /* the current busy level */
+ bool is_paging; /* true, if paging is in progess */
+ bool is_inquiry; /* true, if inquiry is in progess */
+ fixed_queue_t* page_queue;
+ bool paging;
+ bool discing;
+ fixed_queue_t* sec_pending_q; /* pending sequrity requests in
+ tBTM_SEC_QUEUE_ENTRY format */
+
+ char state_temp_buffer[BTM_STATE_BUFFER_SIZE];
+} tBTM_CB;
+
+/* security action for L2CAP COC channels */
+#define BTM_SEC_OK 1
+#define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */
+#define BTM_SEC_ENCRYPT_NO_MITM 3 /* unauthenticated encryption or better */
+#define BTM_SEC_ENCRYPT_MITM 4 /* authenticated encryption */
+#define BTM_SEC_ENC_PENDING 5 /* wait for link encryption pending */
+
+typedef uint8_t tBTM_SEC_ACTION;
+
+#endif // BTM_INT_TYPES_H
diff --git a/mtkbt/code/bt/stack/btm/btm_main.cc b/mtkbt/code/bt/stack/btm/btm_main.cc
new file mode 100755
index 0000000..b4d3897
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_main.cc
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the definition of the btm control block.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_types.h"
+#include "btm_int.h"
+#include "stack_config.h"
+
+/* Global BTM control block structure
+*/
+tBTM_CB btm_cb;
+
+/*******************************************************************************
+ *
+ * Function btm_init
+ *
+ * Description This function is called at BTM startup to allocate the
+ * control block (if using dynamic memory), and initializes the
+ * tracing level. It then initializes the various components
+ * of btm.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_init(void) {
+ /* All fields are cleared; nonzero fields are reinitialized in appropriate
+ * function */
+ memset(&btm_cb, 0, sizeof(tBTM_CB));
+ btm_cb.page_queue = fixed_queue_new(SIZE_MAX);
+ btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+ btm_cb.sec_collision_timer = alarm_new("btm.sec_collision_timer");
+ btm_cb.pairing_timer = alarm_new("btm.pairing_timer");
+
+#if defined(BTM_INITIAL_TRACE_LEVEL)
+ btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
+#else
+ btm_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ /* Initialize BTM component structures */
+ btm_inq_db_init(); /* Inquiry Database and Structures */
+ btm_acl_init(); /* ACL Database and Structures */
+ /* Security Manager Database and Structures */
+ if (stack_config_get_interface()->get_pts_secure_only_mode())
+ btm_sec_init(BTM_SEC_MODE_SC);
+ else
+ btm_sec_init(BTM_SEC_MODE_SP);
+#if (BTM_SCO_INCLUDED == TRUE)
+ btm_sco_init(); /* SCO Database and Structures (If included) */
+#endif
+
+ btm_cb.sec_dev_rec = list_new(osi_free);
+
+ btm_dev_init(); /* Device Manager Structures & HCI_Reset */
+}
+
+/** M: Fix fdleak bug @{ */
+/*******************************************************************************
+**
+** Function btm_free
+**
+** Description This function is free control block (if using dynamic memory).
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void btm_free (void)
+{
+ fixed_queue_free(btm_cb.page_queue, NULL);
+ btm_cb.page_queue = NULL;
+
+ fixed_queue_free(btm_cb.sec_pending_q, NULL);
+ btm_cb.sec_pending_q = NULL;
+
+ if (btm_cb.sec_dev_rec != NULL)
+ list_free(btm_cb.sec_dev_rec);
+}
+/** @} */
diff --git a/mtkbt/code/bt/stack/btm/btm_pm.cc b/mtkbt/code/bt/stack/btm/btm_pm.cc
new file mode 100755
index 0000000..0df4667
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_pm.cc
@@ -0,0 +1,953 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains functions that manages ACL link modes.
+ * This includes operations such as active, hold,
+ * park and sniff modes.
+ *
+ * This module contains both internal and external (API)
+ * functions. External (API) functions are distinguishable
+ * by their names beginning with uppercase BTM.
+ *
+ *****************************************************************************/
+
+#define LOG_TAG "bt_btm_pm"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+/*****************************************************************************/
+/* to handle different modes */
+/*****************************************************************************/
+#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */
+#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */
+
+/* Usage: (ptr_features[ offset ] & mask )?true:false */
+/* offset to supported feature */
+const uint8_t btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1};
+/* mask to supported feature */
+const uint8_t btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
+
+#define BTM_PM_GET_MD1 1
+#define BTM_PM_GET_MD2 2
+#define BTM_PM_GET_COMP 3
+
+const uint8_t
+ btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES * BTM_PM_NUM_SET_MODES] = {
+ BTM_PM_GET_COMP, BTM_PM_GET_MD2, BTM_PM_GET_MD2,
+
+ BTM_PM_GET_MD1, BTM_PM_GET_COMP, BTM_PM_GET_MD1,
+
+ BTM_PM_GET_MD1, BTM_PM_GET_MD2, BTM_PM_GET_COMP};
+
+/* function prototype */
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda);
+static tBTM_STATUS btm_pm_snd_md_req(uint8_t pm_id, int link_ind,
+ tBTM_PM_PWR_MD* p_mode);
+static const char* mode_to_string(tBTM_PM_MODE mode);
+
+#if (BTM_PM_DEBUG == TRUE)
+const char* btm_pm_state_str[] = {"pm_active_state", "pm_hold_state",
+ "pm_sniff_state", "pm_park_state",
+ "pm_pend_state"};
+
+const char* btm_pm_event_str[] = {"pm_set_mode_event", "pm_hci_sts_event",
+ "pm_mod_chg_event", "pm_update_event"};
+
+const char* btm_pm_action_str[] = {"pm_set_mode_action", "pm_update_db_action",
+ "pm_mod_chg_action", "pm_hci_sts_action",
+ "pm_update_action"};
+#endif // BTM_PM_DEBUG
+
+/*****************************************************************************/
+/* P U B L I C F U N C T I O N S */
+/*****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_PmRegister
+ *
+ * Description register or deregister with power manager
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_NO_RESOURCES if no room to hold registration
+ * BTM_ILLEGAL_VALUE
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
+ tBTM_PM_STATUS_CBACK* p_cb) {
+ int xx;
+
+ /* de-register */
+ if (mask & BTM_PM_DEREG) {
+ if (*p_pm_id >= BTM_MAX_PM_RECORDS) return BTM_ILLEGAL_VALUE;
+ btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
+ return BTM_SUCCESS;
+ }
+
+ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
+ /* find an unused entry */
+ if (btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED) {
+ /* if register for notification, should provide callback routine */
+ if (mask & BTM_PM_REG_NOTIF) {
+ if (p_cb == NULL) return BTM_ILLEGAL_VALUE;
+ btm_cb.pm_reg_db[xx].cback = p_cb;
+ }
+ btm_cb.pm_reg_db[xx].mask = mask;
+ *p_pm_id = xx;
+ return BTM_SUCCESS;
+ }
+ }
+
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPowerMode
+ *
+ * Description store the mode in control block or
+ * alter ACL connection behavior.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, BD_ADDR remote_bda,
+ tBTM_PM_PWR_MD* p_mode) {
+ uint8_t* p_features;
+ int ind, acl_ind;
+ tBTM_PM_MCB* p_cb = NULL; /* per ACL link */
+ tBTM_PM_MODE mode;
+ int temp_pm_id;
+
+ if (pm_id >= BTM_MAX_PM_RECORDS) pm_id = BTM_PM_SET_ONLY_ID;
+
+ if (p_mode == NULL) return BTM_ILLEGAL_VALUE;
+
+ BTM_TRACE_API("BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
+ (remote_bda[2] << 24) + (remote_bda[3] << 16) +
+ (remote_bda[4] << 8) + remote_bda[5],
+ p_mode->mode);
+
+ /* take out the force bit */
+ mode = p_mode->mode & ~BTM_PM_MD_FORCE;
+
+ acl_ind = btm_pm_find_acl_ind(remote_bda);
+ if (acl_ind == MAX_L2CAP_LINKS) return (BTM_UNKNOWN_ADDR);
+
+ p_cb = &(btm_cb.pm_mode_db[acl_ind]);
+
+ if (mode != BTM_PM_MD_ACTIVE) {
+ /* check if the requested mode is supported */
+ ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
+ p_features = BTM_ReadLocalFeatures();
+ if (!(p_features[btm_pm_mode_off[ind]] & btm_pm_mode_msk[ind]))
+ return BTM_MODE_UNSUPPORTED;
+ }
+
+ if (mode == p_cb->state) /* the requested mode is current mode */
+ {
+ /* already in the requested mode and the current interval has less latency
+ * than the max */
+ if ((mode == BTM_PM_MD_ACTIVE) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) &&
+ (p_mode->min <= p_cb->interval)) ||
+ ((p_mode->mode & BTM_PM_MD_FORCE) == 0 &&
+ (p_mode->max >= p_cb->interval))) {
+ BTM_TRACE_DEBUG("BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d",
+ p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
+ return BTM_SUCCESS;
+ }
+ }
+
+ temp_pm_id = pm_id;
+ if (pm_id == BTM_PM_SET_ONLY_ID) temp_pm_id = BTM_MAX_PM_RECORDS;
+
+ /* update mode database */
+ if (((pm_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET)) ||
+ ((pm_id == BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_pend_link != MAX_L2CAP_LINKS))) {
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("BTM_SetPowerMode: Saving cmd acl_ind %d temp_pm_id %d",
+ acl_ind, temp_pm_id);
+#endif // BTM_PM_DEBUG
+ /* Make sure mask is set to BTM_PM_REG_SET */
+ btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
+ *(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD*)p_mode);
+ p_cb->chg_ind = true;
+ }
+
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm state:0x%x, pm_pend_link: %d", p_cb->state,
+ btm_cb.pm_pend_link);
+#endif // BTM_PM_DEBUG
+ /* if mode == hold or pending, return */
+ if ((p_cb->state == BTM_PM_STS_HOLD) || (p_cb->state == BTM_PM_STS_PENDING) ||
+ (btm_cb.pm_pend_link != MAX_L2CAP_LINKS)) /* command pending */
+ {
+ if (acl_ind != btm_cb.pm_pend_link) {
+ /* set the stored mask */
+ p_cb->state |= BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG("btm_pm state stored:%d", acl_ind);
+ }
+ return BTM_CMD_STORED;
+ }
+
+ return btm_pm_snd_md_req(pm_id, acl_ind, p_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadPowerMode
+ *
+ * Description This returns the current mode for a specific
+ * ACL connection.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ *
+ * Output Param p_mode - address where the current mode is copied into.
+ * BTM_ACL_MODE_NORMAL
+ * BTM_ACL_MODE_HOLD
+ * BTM_ACL_MODE_SNIFF
+ * BTM_ACL_MODE_PARK
+ * (valid only if return code is BTM_SUCCESS)
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadPowerMode(BD_ADDR remote_bda, tBTM_PM_MODE* p_mode) {
+ int acl_ind;
+
+ acl_ind = btm_pm_find_acl_ind(remote_bda);
+ if (acl_ind == MAX_L2CAP_LINKS) return (BTM_UNKNOWN_ADDR);
+
+ *p_mode = btm_cb.pm_mode_db[acl_ind].state;
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_power_mode_state
+ *
+ * Description This returns the current pm state for a specific
+ * ACL connection.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ *
+ * Output Param pmState - address where the current pm state is copied.
+ * BTM_PM_ST_ACTIVE
+ * BTM_PM_ST_HOLD
+ * BTM_PM_ST_SNIFF
+ * BTM_PM_ST_PARK
+ * BTM_PM_ST_PENDING
+ * (valid only if return code is BTM_SUCCESS)
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_read_power_mode_state(BD_ADDR remote_bda,
+ tBTM_PM_STATE* pmState) {
+ int acl_ind = btm_pm_find_acl_ind(remote_bda);
+
+ if (acl_ind == MAX_L2CAP_LINKS) return (BTM_UNKNOWN_ADDR);
+
+ *pmState = btm_cb.pm_mode_db[acl_ind].state;
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSsrParams
+ *
+ * Description This sends the given SSR parameters for the given ACL
+ * connection if it is in ACTIVE mode.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ * max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+ * min_rmt_to - minimum remote timeout
+ * min_loc_to - minimum local timeout
+ *
+ *
+ * Returns BTM_SUCCESS if the HCI command is issued successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ * BTM_CMD_STORED if the command is stored
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetSsrParams(BD_ADDR remote_bda, uint16_t max_lat,
+ uint16_t min_rmt_to, uint16_t min_loc_to) {
+#if (BTM_SSR_INCLUDED == TRUE)
+ int acl_ind;
+ tBTM_PM_MCB* p_cb;
+
+ acl_ind = btm_pm_find_acl_ind(remote_bda);
+ if (acl_ind == MAX_L2CAP_LINKS) return (BTM_UNKNOWN_ADDR);
+
+ if (BTM_PM_STS_ACTIVE == btm_cb.pm_mode_db[acl_ind].state ||
+ BTM_PM_STS_SNIFF == btm_cb.pm_mode_db[acl_ind].state) {
+ btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[acl_ind].hci_handle, max_lat,
+ min_rmt_to, min_loc_to);
+ return BTM_SUCCESS;
+ }
+ p_cb = &btm_cb.pm_mode_db[acl_ind];
+ p_cb->max_lat = max_lat;
+ p_cb->min_rmt_to = min_rmt_to;
+ p_cb->min_loc_to = min_loc_to;
+ return BTM_CMD_STORED;
+#else
+ return BTM_ILLEGAL_ACTION;
+#endif // BTM_SSR_INCLUDED
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_reset
+ *
+ * Description as a part of the BTM reset process.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_pm_reset(void) {
+ int xx;
+ tBTM_PM_STATUS_CBACK* cb = NULL;
+
+ /* clear the pending request for application */
+ if ((btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF)) {
+ cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
+ }
+
+ /* clear the register record */
+ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
+ btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
+ }
+
+ if (cb != NULL && btm_cb.pm_pend_link < MAX_L2CAP_LINKS)
+ (*cb)(btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, BTM_PM_STS_ERROR,
+ BTM_DEV_RESET, 0);
+
+ /* no command pending */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_sm_alloc
+ *
+ * Description This function initializes the control block of an ACL link.
+ * It is called when an ACL connection is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_pm_sm_alloc(uint8_t ind) {
+ tBTM_PM_MCB* p_db = &btm_cb.pm_mode_db[ind]; /* per ACL link */
+ memset(p_db, 0, sizeof(tBTM_PM_MCB));
+ p_db->state = BTM_PM_ST_ACTIVE;
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_sm_alloc ind:%d st:%d", ind, p_db->state);
+#endif // BTM_PM_DEBUG
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_find_acl_ind
+ *
+ * Description This function initializes the control block of an ACL link.
+ * It is called when an ACL connection is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static int btm_pm_find_acl_ind(BD_ADDR remote_bda) {
+ tACL_CONN* p = &btm_cb.acl_db[0];
+ uint8_t xx;
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p++) {
+ if ((p->in_use) && (!memcmp(p->remote_addr, remote_bda, BD_ADDR_LEN)) &&
+ p->transport == BT_TRANSPORT_BR_EDR) {
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_find_acl_ind ind:%d, st:%d", xx,
+ btm_cb.pm_mode_db[xx].state);
+#endif // BTM_PM_DEBUG
+ break;
+ }
+ }
+ return xx;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_compare_modes
+ * Description get the "more active" mode of the 2
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTM_PM_PWR_MD* btm_pm_compare_modes(tBTM_PM_PWR_MD* p_md1,
+ tBTM_PM_PWR_MD* p_md2,
+ tBTM_PM_PWR_MD* p_res) {
+ uint8_t res;
+
+ if (p_md1 == NULL) {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+
+ return p_md2;
+ }
+
+ if (p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE) {
+ return NULL;
+ }
+
+ /* check if force bit is involved */
+ if (p_md1->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_md1;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ if (p_md2->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_md2;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res;
+ }
+
+ res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
+ res = btm_pm_md_comp_matrix[res];
+ switch (res) {
+ case BTM_PM_GET_MD1:
+ *p_res = *p_md1;
+ return p_md1;
+
+ case BTM_PM_GET_MD2:
+ *p_res = *p_md2;
+ return p_md2;
+
+ case BTM_PM_GET_COMP:
+ p_res->mode = p_md1->mode;
+ /* min of the two */
+ p_res->max = (p_md1->max < p_md2->max) ? (p_md1->max) : (p_md2->max);
+ /* max of the two */
+ p_res->min = (p_md1->min > p_md2->min) ? (p_md1->min) : (p_md2->min);
+
+ /* the intersection is NULL */
+ if (p_res->max < p_res->min) return NULL;
+
+ if (p_res->mode == BTM_PM_MD_SNIFF) {
+ /* max of the two */
+ p_res->attempt = (p_md1->attempt > p_md2->attempt) ? (p_md1->attempt)
+ : (p_md2->attempt);
+ p_res->timeout = (p_md1->timeout > p_md2->timeout) ? (p_md1->timeout)
+ : (p_md2->timeout);
+ }
+ return p_res;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_get_set_mode
+ * Description get the resulting mode from the registered parties, then compare
+ * it with the requested mode, if the command is from an
+ * unregistered party.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTM_PM_MODE btm_pm_get_set_mode(uint8_t pm_id, tBTM_PM_MCB* p_cb,
+ tBTM_PM_PWR_MD* p_mode,
+ tBTM_PM_PWR_MD* p_res) {
+ int xx, loop_max;
+ tBTM_PM_PWR_MD* p_md = NULL;
+
+ if (p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE) {
+ *p_res = *p_mode;
+ p_res->mode &= ~BTM_PM_MD_FORCE;
+ return p_res->mode;
+ }
+
+ if (!p_mode)
+ loop_max = BTM_MAX_PM_RECORDS + 1;
+ else
+ loop_max = BTM_MAX_PM_RECORDS;
+
+ for (xx = 0; xx < loop_max; xx++) {
+ /* g through all the registered "set" parties */
+ if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET) {
+ if (p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE) {
+ /* if at least one registered (SET) party says ACTIVE, stay active */
+ return BTM_PM_MD_ACTIVE;
+ } else {
+ /* if registered parties give conflicting information, stay active */
+ if ((btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL)
+ return BTM_PM_MD_ACTIVE;
+ p_md = p_res;
+ }
+ }
+ }
+
+ /* if the resulting mode is NULL(nobody registers SET), use the requested mode
+ */
+ if (p_md == NULL) {
+ if (p_mode)
+ *p_res = *((tBTM_PM_PWR_MD*)p_mode);
+ else /* p_mode is NULL when btm_pm_snd_md_req is called from
+ btm_pm_proc_mode_change */
+ return BTM_PM_MD_ACTIVE;
+ } else {
+ /* if the command is from unregistered party,
+ compare the resulting mode from registered party*/
+ if ((pm_id == BTM_PM_SET_ONLY_ID) &&
+ ((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL))
+ return BTM_PM_MD_ACTIVE;
+ }
+
+ return p_res->mode;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_snd_md_req
+ * Description get the resulting mode and send the resuest to host controller
+ * Returns tBTM_STATUS
+ *, bool *p_chg_ind
+ ******************************************************************************/
+static tBTM_STATUS btm_pm_snd_md_req(uint8_t pm_id, int link_ind,
+ tBTM_PM_PWR_MD* p_mode) {
+ tBTM_PM_PWR_MD md_res;
+ tBTM_PM_MODE mode;
+ tBTM_PM_MCB* p_cb = &btm_cb.pm_mode_db[link_ind];
+ bool chg_ind = false;
+
+ mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
+ md_res.mode = mode;
+
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_snd_md_req link_ind:%d, mode: %d", link_ind, mode);
+#endif // BTM_PM_DEBUG
+
+ if (p_cb->state == mode) {
+ /* already in the resulting mode */
+ if ((mode == BTM_PM_MD_ACTIVE) ||
+ ((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)))
+ return BTM_CMD_STORED;
+ /* Otherwise, needs to wake, then sleep */
+ chg_ind = true;
+ }
+ p_cb->chg_ind = chg_ind;
+
+ /* cannot go directly from current mode to resulting mode. */
+ if (mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE)
+ p_cb->chg_ind = true; /* needs to wake, then sleep */
+
+ if (p_cb->chg_ind == true) /* needs to wake first */
+ md_res.mode = BTM_PM_MD_ACTIVE;
+#if (BTM_SSR_INCLUDED == TRUE)
+ else if (BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat) {
+ btsnd_hcic_sniff_sub_rate(btm_cb.acl_db[link_ind].hci_handle, p_cb->max_lat,
+ p_cb->min_rmt_to, p_cb->min_loc_to);
+ p_cb->max_lat = 0;
+ }
+#endif // BTM_SSR_INCLUDED
+ /* Default is failure */
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ /* send the appropriate HCI command */
+ btm_cb.pm_pend_id = pm_id;
+
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_ind: %d", p_cb->state,
+ link_ind);
+#endif // BTM_PM_DEBUG
+
+ BTM_TRACE_DEBUG("%s switching from %s to %s.", __func__,
+ mode_to_string(p_cb->state), mode_to_string(md_res.mode));
+ switch (md_res.mode) {
+ case BTM_PM_MD_ACTIVE:
+ switch (p_cb->state) {
+ case BTM_PM_MD_SNIFF:
+ btsnd_hcic_exit_sniff_mode(btm_cb.acl_db[link_ind].hci_handle);
+ btm_cb.pm_pend_link = link_ind;
+ break;
+ case BTM_PM_MD_PARK:
+ btsnd_hcic_exit_park_mode(btm_cb.acl_db[link_ind].hci_handle);
+ btm_cb.pm_pend_link = link_ind;
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+ break;
+
+ case BTM_PM_MD_HOLD:
+ btsnd_hcic_hold_mode(btm_cb.acl_db[link_ind].hci_handle, md_res.max,
+ md_res.min);
+ btm_cb.pm_pend_link = link_ind;
+ break;
+
+ case BTM_PM_MD_SNIFF:
+ btsnd_hcic_sniff_mode(btm_cb.acl_db[link_ind].hci_handle, md_res.max,
+ md_res.min, md_res.attempt, md_res.timeout);
+ btm_cb.pm_pend_link = link_ind;
+ break;
+
+ case BTM_PM_MD_PARK:
+ btsnd_hcic_park_mode(btm_cb.acl_db[link_ind].hci_handle, md_res.max,
+ md_res.min);
+ btm_cb.pm_pend_link = link_ind;
+ break;
+ default:
+ /* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
+ break;
+ }
+
+ if (btm_cb.pm_pend_link == MAX_L2CAP_LINKS) {
+/* the command was not sent */
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("pm_pend_link: %d", btm_cb.pm_pend_link);
+#endif // BTM_PM_DEBUG
+ return (BTM_NO_RESOURCES);
+ }
+
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_check_stored
+ *
+ * Description This function is called when an HCI command status event
+ * occurs to check if there's any PM command issued while
+ * waiting for HCI command status.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+static void btm_pm_check_stored(void) {
+ int xx;
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++) {
+ if (btm_cb.pm_mode_db[xx].state & BTM_PM_STORED_MASK) {
+ btm_cb.pm_mode_db[xx].state &= ~BTM_PM_STORED_MASK;
+ BTM_TRACE_DEBUG("btm_pm_check_stored :%d", xx);
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_proc_cmd_status
+ *
+ * Description This function is called when an HCI command status event
+ * occurs for power manager related commands.
+ *
+ * Input Parms status - status of the event (HCI_SUCCESS if no errors)
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void btm_pm_proc_cmd_status(uint8_t status) {
+ tBTM_PM_MCB* p_cb;
+ tBTM_PM_STATUS pm_status;
+
+ if (btm_cb.pm_pend_link >= MAX_L2CAP_LINKS) return;
+
+ p_cb = &btm_cb.pm_mode_db[btm_cb.pm_pend_link];
+
+ if (status == HCI_SUCCESS) {
+ p_cb->state = BTM_PM_ST_PENDING;
+ pm_status = BTM_PM_STS_PENDING;
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
+#endif // BTM_PM_DEBUG
+ } else /* the command was not successfull. Stay in the same state */
+ {
+ pm_status = BTM_PM_STS_ERROR;
+ }
+
+ /* notify the caller is appropriate */
+ if ((btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
+ (btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF)) {
+ (*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(
+ btm_cb.acl_db[btm_cb.pm_pend_link].remote_addr, pm_status, 0, status);
+ }
+
+/* no pending cmd now */
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG(
+ "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
+ p_cb->state, btm_cb.pm_pend_link, MAX_L2CAP_LINKS);
+#endif // BTM_PM_DEBUG
+ btm_cb.pm_pend_link = MAX_L2CAP_LINKS;
+
+ btm_pm_check_stored();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_process_mode_change
+ *
+ * Description This function is called when an HCI mode change event
+ * occurs.
+ *
+ * Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
+ * hci_handle - connection handle associated with the change
+ * mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or
+ * HCI_MODE_PARK
+ * interval - number of baseband slots (meaning depends on
+ * mode)
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void btm_pm_proc_mode_change(uint8_t hci_status, uint16_t hci_handle,
+ uint8_t mode, uint16_t interval) {
+ tACL_CONN* p;
+ tBTM_PM_MCB* p_cb = NULL;
+ int xx, yy, zz;
+ tBTM_PM_STATE old_state;
+ tL2C_LCB* p_lcb;
+
+ /* get the index to acl_db */
+ xx = btm_handle_to_acl_index(hci_handle);
+ if (xx >= MAX_L2CAP_LINKS) return;
+
+ p = &btm_cb.acl_db[xx];
+
+ /* update control block */
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+ old_state = p_cb->state;
+ p_cb->state = mode;
+ p_cb->interval = interval;
+
+ BTM_TRACE_DEBUG("%s switched from %s to %s.", __func__,
+ mode_to_string(old_state), mode_to_string(p_cb->state));
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb != NULL) {
+ if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF)) {
+ /* There might be any pending packets due to SNIFF or PENDING state */
+ /* Trigger L2C to start transmission of the pending packets. */
+ BTM_TRACE_DEBUG(
+ "btm mode change to active; check l2c_link for outgoing packets");
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+ }
+ }
+
+ /* notify registered parties */
+ for (yy = 0; yy <= BTM_MAX_PM_RECORDS; yy++) {
+ /* set req_mode HOLD mode->ACTIVE */
+ if ((mode == BTM_PM_MD_ACTIVE) &&
+ (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD))
+ p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
+ }
+
+ /* new request has been made. - post a message to BTU task */
+ if (old_state & BTM_PM_STORED_MASK) {
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_proc_mode_change: Sending stored req:%d", xx);
+#endif // BTM_PM_DEBUG
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, xx, NULL);
+ } else {
+ for (zz = 0; zz < MAX_L2CAP_LINKS; zz++) {
+ if (btm_cb.pm_mode_db[zz].chg_ind == true) {
+#if (BTM_PM_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm_pm_proc_mode_change: Sending PM req :%d", zz);
+#endif // BTM_PM_DEBUG
+ btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, zz, NULL);
+ break;
+ }
+ }
+ }
+
+ /* notify registered parties */
+ for (yy = 0; yy < BTM_MAX_PM_RECORDS; yy++) {
+ if (btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF) {
+ (*btm_cb.pm_reg_db[yy].cback)(p->remote_addr, mode, interval, hci_status);
+ }
+ }
+#if (BTM_SCO_INCLUDED == TRUE)
+ /*check if sco disconnect is waiting for the mode change */
+ btm_sco_disc_chk_pend_for_modechange(hci_handle);
+#endif
+
+ /* If mode change was because of an active role switch or change link key */
+ btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_proc_ssr_evt
+ *
+ * Description This function is called when an HCI sniff subrating event
+ * occurs.
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+void btm_pm_proc_ssr_evt(uint8_t* p, UNUSED_ATTR uint16_t evt_len) {
+ uint8_t status;
+ uint16_t handle;
+ uint16_t max_rx_lat;
+ int xx, yy;
+ tBTM_PM_MCB* p_cb;
+ tACL_CONN* p_acl = NULL;
+ uint16_t use_ssr = true;
+
+ STREAM_TO_UINT8(status, p);
+
+ STREAM_TO_UINT16(handle, p);
+ /* get the index to acl_db */
+ xx = btm_handle_to_acl_index(handle);
+ if (xx >= MAX_L2CAP_LINKS) return;
+
+ p += 2;
+ STREAM_TO_UINT16(max_rx_lat, p);
+ p_cb = &(btm_cb.pm_mode_db[xx]);
+
+ p_acl = &btm_cb.acl_db[xx];
+ if (p_cb->interval == max_rx_lat) {
+ /* using legacy sniff */
+ use_ssr = false;
+ }
+
+ /* notify registered parties */
+ for (yy = 0; yy < BTM_MAX_PM_RECORDS; yy++) {
+ if (btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF) {
+ if (p_acl) {
+ (*btm_cb.pm_reg_db[yy].cback)(p_acl->remote_addr, BTM_PM_STS_SSR,
+ use_ssr, status);
+ }
+ }
+ }
+}
+#endif // BTM_SSR_INCLUDED
+
+/*******************************************************************************
+ *
+ * Function btm_pm_device_in_active_or_sniff_mode
+ *
+ * Description This function is called to check if in active or sniff mode
+ *
+ * Returns true, if in active or sniff mode
+ *
+ ******************************************************************************/
+bool btm_pm_device_in_active_or_sniff_mode(void) {
+ /* The active state is the highest state-includes connected device and sniff
+ * mode*/
+
+ /* Covers active and sniff modes */
+ if (BTM_GetNumAclLinks() > 0) {
+ BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks());
+ return true;
+ }
+
+ /* Check BLE states */
+ if (btm_ble_get_conn_st() != BLE_CONN_IDLE) {
+ BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st());
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pm_device_in_scan_state
+ *
+ * Description This function is called to check if in paging, inquiry or
+ * connecting mode
+ *
+ * Returns true, if in paging, inquiry or connecting mode
+ *
+ ******************************************************************************/
+bool btm_pm_device_in_scan_state(void) {
+ /* Scan state-paging, inquiry, and trying to connect */
+
+ /* Check for paging */
+ if (btm_cb.is_paging || (!fixed_queue_is_empty(btm_cb.page_queue)) ||
+ BTM_BL_PAGING_STARTED == btm_cb.busy_level) {
+ BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
+ return true;
+ }
+
+ /* Check for inquiry */
+ if ((btm_cb.btm_inq_vars.inq_active &
+ (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0) {
+ BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_PM_ReadControllerState
+ *
+ * Description This function is called to obtain the controller state
+ *
+ * Returns Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and
+ * BTM_CONTRL_IDLE
+ *
+ ******************************************************************************/
+tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void) {
+ if (true == btm_pm_device_in_active_or_sniff_mode())
+ return BTM_CONTRL_ACTIVE;
+ else if (true == btm_pm_device_in_scan_state())
+ return BTM_CONTRL_SCAN;
+ else
+ return BTM_CONTRL_IDLE;
+}
+
+static const char* mode_to_string(tBTM_PM_MODE mode) {
+ switch (mode) {
+ case BTM_PM_MD_ACTIVE:
+ return "ACTIVE";
+ case BTM_PM_MD_SNIFF:
+ return "SNIFF";
+ case BTM_PM_MD_PARK:
+ return "PARK";
+ case BTM_PM_MD_HOLD:
+ return "HOLD";
+ default:
+ return "UNKNOWN";
+ }
+}
diff --git a/mtkbt/code/bt/stack/btm/btm_sco.cc b/mtkbt/code/bt/stack/btm/btm_sco.cc
new file mode 100755
index 0000000..2e71c56
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_sco.cc
@@ -0,0 +1,1869 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions that handle SCO connections. This includes
+ * operations such as connect, disconnect, change supported packet types.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "device/include/esco_parameters.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "osi/include/osi.h"
+
+#if (BTM_SCO_INCLUDED == TRUE)
+
+/******************************************************************************/
+/* L O C A L D A T A D E F I N I T I O N S */
+/******************************************************************************/
+
+#define SCO_ST_UNUSED 0
+#define SCO_ST_LISTENING 1
+#define SCO_ST_W4_CONN_RSP 2
+#define SCO_ST_CONNECTING 3
+#define SCO_ST_CONNECTED 4
+#define SCO_ST_DISCONNECTING 5
+#define SCO_ST_PEND_UNPARK 6
+#define SCO_ST_PEND_ROLECHANGE 7
+#define SCO_ST_PEND_MODECHANGE 8
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+
+static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function btm_sco_flush_sco_data
+ *
+ * Description This function is called to flush the SCO data for this
+ * channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS > 0)
+void btm_sco_flush_sco_data(uint16_t sco_inx) {
+ tSCO_CONN* p;
+ BT_HDR* p_buf;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS) {
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p->xmit_data_q)) != NULL)
+ osi_free(p_buf);
+ }
+}
+}
+#else
+void btm_sco_flush_sco_data(UNUSED_ATTR uint16_t sco_inx) {}
+#endif
+/*******************************************************************************
+ *
+ * Function btm_sco_init
+ *
+ * Description This function is called at BTM startup to initialize
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_init(void) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ for (int i = 0; i < BTM_MAX_SCO_LINKS; i++)
+ btm_cb.sco_cb.sco_db[i].xmit_data_q = fixed_queue_new(SIZE_MAX);
+#endif
+ /* Initialize nonzero defaults */
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+ btm_cb.sco_cb.def_esco_parms = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ btm_cb.sco_cb.def_esco_parms.max_latency_ms = 12;
+ btm_cb.sco_cb.sco_route = ESCO_DATA_PATH_PCM;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_esco_conn_rsp
+ *
+ * Description This function is called upon receipt of an (e)SCO connection
+ * request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+ * the request. Parameters used to negotiate eSCO links.
+ * If p_parms is NULL, then default values are used.
+ * If the link type of the incoming request is SCO, then only
+ * the tx_bw, max_latency, content format, and packet_types are
+ * valid. The hci_status parameter should be
+ * ([0x0] to accept, [0x0d..0x0f] to reject)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_esco_conn_rsp(uint16_t sco_inx, uint8_t hci_status, BD_ADDR bda,
+ enh_esco_params_t* p_parms) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p_sco = NULL;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS) p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Reject the connect request if refused by caller or wrong state */
+ if (hci_status != HCI_SUCCESS || p_sco == NULL) {
+ if (p_sco) {
+ p_sco->state = (p_sco->state == SCO_ST_W4_CONN_RSP) ? SCO_ST_LISTENING
+ : SCO_ST_UNUSED;
+ }
+ if (!btm_cb.sco_cb.esco_supported) {
+ btsnd_hcic_reject_conn(bda, hci_status);
+ } else {
+ btsnd_hcic_reject_esco_conn(bda, hci_status);
+ }
+
+ /** M: Bug Fix for create sco collision @{ */
+ if (p_sco != NULL)
+ p_sco->is_collision = false;
+ /** @} */
+ } else /* Connection is being accepted */
+ {
+ p_sco->state = SCO_ST_CONNECTING;
+ enh_esco_params_t* p_setup = &p_sco->esco.setup;
+ /* If parameters not specified use the default */
+ if (p_parms) {
+ *p_setup = *p_parms;
+ } else {
+ /* Use the last setup passed thru BTM_SetEscoMode (or defaults) */
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+ }
+
+ uint16_t temp_packet_types =
+ (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* Make sure at least one eSCO packet type is sent, else might confuse peer
+ */
+ /* Taking this out to confirm with BQB tests
+ ** Real application would like to include this though, as many devices
+ ** do not retry with SCO only if an eSCO connection fails.
+ if (!(temp_packet_types & BTM_ESCO_LINK_ONLY_MASK))
+ {
+ temp_packet_types |= BTM_SCO_PKT_TYPES_MASK_EV3;
+ }
+ */
+ /* If SCO request, remove eSCO packet types (conformance) */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO) {
+ temp_packet_types &= BTM_SCO_LINK_ONLY_MASK;
+ temp_packet_types |= BTM_SCO_EXCEPTION_PKTS_MASK;
+ } else {
+ /* OR in any exception packet types */
+ temp_packet_types |=
+ ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ }
+
+ /** M: Change feature For enhanced setup synchronous connection. @{ */
+ // MTK platform uses differenct command by codec type.
+ /* Use Enhanced Synchronous commands if supported */
+ if (p_setup && (p_setup->transmit_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC
+ && p_setup->receive_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC)) {
+ /*if (controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection()) {*/
+ /* Use the saved SCO routing */
+ /** @} */
+ p_setup->input_data_path = p_setup->output_data_path =
+ btm_cb.sco_cb.sco_route;
+
+ BTM_TRACE_DEBUG(
+ "%s: txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, "
+ "pkt 0x%04x, path %u",
+ __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_setup->max_latency_ms, p_setup->retransmission_effort,
+ p_setup->packet_types, p_setup->input_data_path);
+
+ btsnd_hcic_enhanced_accept_synchronous_connection(bda, p_setup);
+
+ } else {
+ /* Use legacy command if enhanced SCO setup is not supported */
+ uint16_t voice_content_format = btm_sco_voice_settings_to_legacy(p_setup);
+ btsnd_hcic_accept_esco_conn(
+ bda, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_setup->max_latency_ms, voice_content_format,
+ p_setup->retransmission_effort, p_setup->packet_types);
+ }
+ }
+#endif
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function btm_sco_check_send_pkts
+ *
+ * Description This function is called to check if it can send packets
+ * to the Host Controller.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_check_send_pkts(uint16_t sco_inx) {
+ tSCO_CB* p_cb = &btm_cb.sco_cb;
+ tSCO_CONN* p_ccb = &p_cb->sco_db[sco_inx];
+
+ /* If there is data to send, send it now */
+ BT_HDR* p_buf;
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_data_q)) !=
+ NULL) {
+#if (BTM_SCO_HCI_DEBUG == TRUE)
+ BTM_TRACE_DEBUG("btm: [%d] buf in xmit_data_q",
+ fixed_queue_length(p_ccb->xmit_data_q) + 1);
+#endif
+
+ HCI_SCO_DATA_TO_LOWER(p_buf);
+ }
+}
+#endif /* BTM_SCO_HCI_INCLUDED == TRUE */
+
+/*******************************************************************************
+ *
+ * Function btm_route_sco_data
+ *
+ * Description Route received SCO data.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_route_sco_data(BT_HDR* p_msg) {
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ uint16_t sco_inx, handle;
+ uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint8_t pkt_size = 0;
+ uint8_t pkt_status = 0;
+
+ /* Extract Packet_Status_Flag and handle */
+ STREAM_TO_UINT16(handle, p);
+ pkt_status = HCID_GET_EVENT(handle);
+ handle = HCID_GET_HANDLE(handle);
+
+ STREAM_TO_UINT8(pkt_size, p);
+
+ sco_inx = btm_find_scb_by_handle(handle);
+ if (sco_inx != BTM_MAX_SCO_LINKS) {
+ /* send data callback */
+ if (!btm_cb.sco_cb.p_data_cb)
+ /* if no data callback registered, just free the buffer */
+ osi_free(p_msg);
+ else {
+ (*btm_cb.sco_cb.p_data_cb)(sco_inx, p_msg,
+ (tBTM_SCO_DATA_FLAG)pkt_status);
+ }
+ } else /* no mapping handle SCO connection is active, free the buffer */
+ {
+ osi_free(p_msg);
+ }
+#else
+ osi_free(p_msg);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteScoData
+ *
+ * Description This function write SCO data to a specified instance. The
+ * data to be written p_buf needs to carry an offset of
+ * HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+ * exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is
+ * set to 60 and is configurable. Data longer than the maximum
+ * bytes will be truncated.
+ *
+ * Returns BTM_SUCCESS: data write is successful
+ * BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+ * BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO
+ * packet size.
+ * BTM_NO_RESOURCES: no resources.
+ * BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is
+ * not routed via HCI.
+ *
+ *
+ ******************************************************************************/
+#if (BTM_SCO_HCI_INCLUDED == TRUE && BTM_MAX_SCO_LINKS > 0)
+tBTM_STATUS BTM_WriteScoData(uint16_t sco_inx, BT_HDR* p_buf) {
+ tSCO_CONN* p_ccb = &btm_cb.sco_cb.sco_db[sco_inx];
+ uint8_t* p;
+ tBTM_STATUS status = BTM_SUCCESS;
+
+ if (sco_inx < BTM_MAX_SCO_LINKS && btm_cb.sco_cb.p_data_cb &&
+ p_ccb->state == SCO_ST_CONNECTED) {
+ /* Ensure we have enough space in the buffer for the SCO and HCI headers */
+ if (p_buf->offset < HCI_SCO_PREAMBLE_SIZE) {
+ BTM_TRACE_ERROR("BTM SCO - cannot send buffer, offset: %d",
+ p_buf->offset);
+ osi_free(p_buf);
+ status = BTM_ILLEGAL_VALUE;
+ } else /* write HCI header */
+ {
+ /* Step back 3 bytes to add the headers */
+ p_buf->offset -= HCI_SCO_PREAMBLE_SIZE;
+ /* Set the pointer to the beginning of the data */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ /* add HCI handle */
+ UINT16_TO_STREAM(p, p_ccb->hci_handle);
+ /* only sent the first BTM_SCO_DATA_SIZE_MAX bytes data if more than max,
+ and set warning status */
+ if (p_buf->len > BTM_SCO_DATA_SIZE_MAX) {
+ p_buf->len = BTM_SCO_DATA_SIZE_MAX;
+ status = BTM_SCO_BAD_LENGTH;
+ }
+
+ UINT8_TO_STREAM(p, (uint8_t)p_buf->len);
+ p_buf->len += HCI_SCO_PREAMBLE_SIZE;
+
+ fixed_queue_enqueue(p_ccb->xmit_data_q, p_buf);
+
+ btm_sco_check_send_pkts(sco_inx);
+ }
+ } else {
+ osi_free(p_buf);
+
+ BTM_TRACE_ERROR("%s:invalid sco index: %d at state [%d]", __func__, sco_inx,
+ btm_cb.sco_cb.sco_db[sco_inx].state);
+ status = BTM_UNKNOWN_ADDR;
+ }
+
+ return status;
+}
+#else
+tBTM_STATUS BTM_WriteScoData(UNUSED_ATTR uint16_t sco_inx,
+ UNUSED_ATTR BT_HDR* p_buf) {
+ return (BTM_NO_RESOURCES);
+}
+#endif
+
+#if (BTM_MAX_SCO_LINKS > 0)
+/*******************************************************************************
+ *
+ * Function btm_send_connect_request
+ *
+ * Description This function is called to respond to SCO connect
+ * indications
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTM_STATUS btm_send_connect_request(uint16_t acl_handle,
+ enh_esco_params_t* p_setup) {
+ tACL_CONN* p_acl;
+
+ /* Send connect request depending on version of spec */
+ if (!btm_cb.sco_cb.esco_supported) {
+ btsnd_hcic_add_SCO_conn(acl_handle, BTM_ESCO_2_SCO(p_setup->packet_types));
+ } else {
+ uint16_t temp_packet_types =
+ (p_setup->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types */
+ temp_packet_types |=
+ ((p_setup->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+
+ /* Finally, remove EDR eSCO if the remote device doesn't support it */
+ /* UPF25: Only SCO was brought up in this case */
+ btm_handle_to_acl_index(acl_handle);
+ uint8_t acl_index = btm_handle_to_acl_index(acl_handle);
+ if (acl_index < MAX_L2CAP_LINKS) {
+ p_acl = &btm_cb.acl_db[acl_index];
+ if (!HCI_EDR_ESCO_2MPS_SUPPORTED(p_acl->peer_lmp_feature_pages[0])) {
+ BTM_TRACE_WARNING("BTM Remote does not support 2-EDR eSCO");
+ temp_packet_types |=
+ (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5);
+ }
+ if (!HCI_EDR_ESCO_3MPS_SUPPORTED(p_acl->peer_lmp_feature_pages[0])) {
+ BTM_TRACE_WARNING("BTM Remote does not support 3-EDR eSCO");
+ temp_packet_types |=
+ (ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+
+ /* Check to see if BR/EDR Secure Connections is being used
+ ** If so, we cannot use SCO-only packet types (HFP 1.7)
+ */
+ if (BTM_BothEndsSupportSecureConnections(p_acl->remote_addr)) {
+ temp_packet_types &= ~(BTM_SCO_PKT_TYPE_MASK);
+ BTM_TRACE_DEBUG("%s: SCO Conn: pkt_types after removing SCO (0x%04x)",
+ __func__, temp_packet_types);
+
+ /* Return error if no packet types left */
+ if (temp_packet_types == 0) {
+ BTM_TRACE_ERROR("%s: SCO Conn (BR/EDR SC): No packet types available",
+ __func__);
+ return (BTM_WRONG_MODE);
+ }
+ } else {
+ BTM_TRACE_DEBUG(
+ "%s: SCO Conn(BR/EDR SC):local or peer does not support BR/EDR SC",
+ __func__);
+ }
+ }
+
+ /* Save the previous types in case command fails */
+ uint16_t saved_packet_types = p_setup->packet_types;
+ p_setup->packet_types = temp_packet_types;
+
+ /** M: Change feature For enhanced setup synchronous connection. @{ */
+ // MTK platform uses differenct command by codec type.
+ /* Use Enhanced Synchronous commands if supported */
+ if (p_setup && (p_setup->transmit_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC
+ && p_setup->receive_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC)/*FALSE*/) {
+ /*if (controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection()) {*/
+ /* Use the saved SCO routing */
+ /** @} */
+ p_setup->input_data_path = p_setup->output_data_path =
+ btm_cb.sco_cb.sco_route;
+
+ BTM_TRACE_DEBUG(
+ "%s: txbw 0x%x, rxbw 0x%x, "
+ "lat 0x%x, retrans 0x%02x, pkt 0x%04x, path %u",
+ __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_setup->max_latency_ms, p_setup->retransmission_effort,
+ p_setup->packet_types, p_setup->input_data_path);
+
+ btsnd_hcic_enhanced_set_up_synchronous_connection(acl_handle, p_setup);
+ p_setup->packet_types = saved_packet_types;
+ } else { /* Use older command */
+ uint16_t voice_content_format = btm_sco_voice_settings_to_legacy(p_setup);
+
+ BTM_TRACE_API(
+ "%s: txbw 0x%x, rxbw 0x%x, "
+ "lat 0x%x, voice 0x%x, retrans 0x%02x, pkt 0x%04x",
+ __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_setup->max_latency_ms, voice_content_format,
+ p_setup->retransmission_effort, p_setup->packet_types);
+
+ btsnd_hcic_setup_esco_conn(
+ acl_handle, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_setup->max_latency_ms, voice_content_format,
+ p_setup->retransmission_effort, p_setup->packet_types);
+ }
+ }
+
+ return (BTM_CMD_STARTED);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function btm_set_sco_ind_cback
+ *
+ * Description This function is called to register for TCS SCO connect
+ * indications.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_set_sco_ind_cback(tBTM_SCO_IND_CBACK* sco_ind_cb) {
+ btm_cb.sco_cb.app_sco_ind_cb = sco_ind_cb;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_accept_sco_link
+ *
+ * Description This function is called to respond to TCS SCO connect
+ * indications
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_accept_sco_link(uint16_t sco_inx, enh_esco_params_t* p_setup,
+ tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p_sco;
+
+ if (sco_inx >= BTM_MAX_SCO_LINKS) {
+ BTM_TRACE_ERROR("btm_accept_sco_link: Invalid sco_inx(%d)", sco_inx);
+ return;
+ }
+
+ /* Link role is ignored in for this message */
+ p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ p_sco->p_conn_cb = p_conn_cb;
+ p_sco->p_disc_cb = p_disc_cb;
+ p_sco->esco.data.link_type =
+ BTM_LINK_TYPE_ESCO; /* Accept with all supported types */
+
+ BTM_TRACE_DEBUG("TCS accept SCO: Packet Types 0x%04x", p_setup->packet_types);
+
+ btm_esco_conn_rsp(sco_inx, HCI_SUCCESS, p_sco->esco.data.bd_addr, p_setup);
+#else
+ btm_reject_sco_link(sco_inx);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_reject_sco_link
+ *
+ * Description This function is called to respond to SCO connect
+ * indications
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_reject_sco_link(uint16_t sco_inx) {
+ btm_esco_conn_rsp(sco_inx, HCI_ERR_HOST_REJECT_RESOURCES,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CreateSco
+ *
+ * Description This function is called to create an SCO connection. If the
+ * "is_orig" flag is true, the connection will be originated,
+ * otherwise BTM will wait for the other side to connect.
+ *
+ * NOTE: If BTM_IGNORE_SCO_PKT_TYPE is passed in the pkt_types
+ * parameter the default packet types is used.
+ *
+ * Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+ * BTM_BUSY if another SCO being set up to
+ * the same BD address
+ * BTM_NO_RESOURCES if the max SCO limit has been reached
+ * BTM_CMD_STARTED if the connection establishment is started.
+ * In this case, "*p_sco_inx" is filled in
+ * with the sco index used for the connection.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CreateSco(BD_ADDR remote_bda, bool is_orig, uint16_t pkt_types,
+ uint16_t* p_sco_inx, tBTM_SCO_CB* p_conn_cb,
+ tBTM_SCO_CB* p_disc_cb) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ enh_esco_params_t* p_setup;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+ uint16_t acl_handle = 0;
+ tACL_CONN* p_acl;
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ tBTM_PM_PWR_MD pm;
+ tBTM_PM_STATE state;
+#else
+ uint8_t mode;
+#endif // BTM_SCO_WAKE_PARKED_LINK
+
+ *p_sco_inx = BTM_INVALID_SCO_INDEX;
+
+ /* If originating, ensure that there is an ACL connection to the BD Address */
+
+ if (is_orig) {
+ if (!remote_bda) {
+ BTM_TRACE_ERROR("%s: remote_bda is null", __func__);
+ return BTM_ILLEGAL_VALUE;
+ }
+ acl_handle = BTM_GetHCIConnHandle(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (acl_handle == 0xFFFF) {
+ BTM_TRACE_ERROR(
+ "%s: cannot find ACL handle for remote device "
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, remote_bda[0], remote_bda[1], remote_bda[2], remote_bda[3],
+ remote_bda[4], remote_bda[5]);
+ return BTM_UNKNOWN_ADDR;
+ }
+ }
+
+ if (remote_bda) {
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) ||
+ (p->state == SCO_ST_PEND_UNPARK)) &&
+ (!memcmp(p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN))) {
+ return BTM_BUSY;
+ }
+ }
+ } else {
+ /* Support only 1 wildcard BD address at a time */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_LISTENING) && (!p->rem_bd_known)) return BTM_BUSY;
+ }
+ }
+
+ /* Try to find an unused control block, and kick off the SCO establishment */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS;
+ xx++, p++) {
+ if (p->state == SCO_ST_UNUSED) {
+ if (remote_bda) {
+ if (is_orig) {
+/* can not create SCO link if in park mode */
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) ==
+ BTM_SUCCESS)) {
+ if (state == BTM_PM_ST_SNIFF || state == BTM_PM_ST_PARK ||
+ state == BTM_PM_ST_PENDING) {
+ BTM_TRACE_DEBUG("%s In sniff, park or pend mode: %d", __func__,
+ state);
+ memset((void*)&pm, 0, sizeof(pm));
+ pm.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, remote_bda, &pm);
+ p->state = SCO_ST_PEND_UNPARK;
+ }
+ }
+#else // BTM_SCO_WAKE_PARKED_LINK
+ if ((BTM_ReadPowerMode(remote_bda, &mode) == BTM_SUCCESS) &&
+ (mode == BTM_PM_MD_PARK))
+ return (BTM_WRONG_MODE);
+#endif // BTM_SCO_WAKE_PARKED_LINK
+ }
+ memcpy(p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN);
+ p->rem_bd_known = true;
+ } else
+ p->rem_bd_known = false;
+
+ p_setup = &p->esco.setup;
+ *p_setup = btm_cb.sco_cb.def_esco_parms;
+
+ /* Determine the packet types */
+ p_setup->packet_types = pkt_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported;
+ /* OR in any exception packet types */
+ if (controller_get_interface()->get_bt_version()->hci_version >=
+ HCI_PROTO_VERSION_2_0) {
+ p_setup->packet_types |=
+ (pkt_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK);
+ }
+
+ p->p_conn_cb = p_conn_cb;
+ p->p_disc_cb = p_disc_cb;
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->is_orig = is_orig;
+
+ if (p->state != SCO_ST_PEND_UNPARK) {
+ if (is_orig) {
+ /* If role change is in progress, do not proceed with SCO setup
+ * Wait till role change is complete */
+ p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl && p_acl->switch_role_state != BTM_ACL_SWKEY_STATE_IDLE) {
+ BTM_TRACE_API("Role Change is in progress for ACL handle 0x%04x",
+ acl_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+ }
+ }
+ }
+
+ if (p->state != SCO_ST_PEND_UNPARK &&
+ p->state != SCO_ST_PEND_ROLECHANGE) {
+ if (is_orig) {
+ BTM_TRACE_API("%s:(e)SCO Link for ACL handle 0x%04x", __func__,
+ acl_handle);
+
+ if ((btm_send_connect_request(acl_handle, p_setup)) !=
+ BTM_CMD_STARTED)
+ return (BTM_NO_RESOURCES);
+
+ p->state = SCO_ST_CONNECTING;
+ } else
+ p->state = SCO_ST_LISTENING;
+ }
+
+ *p_sco_inx = xx;
+
+ return BTM_CMD_STARTED;
+ }
+ }
+
+#endif
+ /* If here, all SCO blocks in use */
+ return BTM_NO_RESOURCES;
+}
+
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+ *
+ * Function btm_sco_chk_pend_unpark
+ *
+ * Description This function is called by BTIF when there is a mode change
+ * event to see if there are SCO commands waiting for the
+ * unpark.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_chk_pend_unpark(uint8_t hci_status, uint16_t hci_handle) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ uint16_t xx;
+ uint16_t acl_handle;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_PEND_UNPARK) &&
+ ((acl_handle = BTM_GetHCIConnHandle(
+ p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+ {
+ BTM_TRACE_API(
+ "%s:(e)SCO Link for ACL "
+ "handle 0x%04x, hci_status 0x%02x",
+ __func__, acl_handle, hci_status);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) ==
+ BTM_CMD_STARTED)
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+#endif // BTM_MAX_SCO_LINKS
+}
+#endif // BTM_SCO_WAKE_PARKED_LINK
+
+/*******************************************************************************
+ *
+ * Function btm_sco_chk_pend_rolechange
+ *
+ * Description This function is called by BTIF when there is a role change
+ * event to see if there are SCO commands waiting for the role
+ * change.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_chk_pend_rolechange(uint16_t hci_handle) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ uint16_t xx;
+ uint16_t acl_handle;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_PEND_ROLECHANGE) &&
+ ((acl_handle = BTM_GetHCIConnHandle(
+ p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) == hci_handle))
+
+ {
+ BTM_TRACE_API(
+ "btm_sco_chk_pend_rolechange -> (e)SCO Link for ACL handle 0x%04x",
+ acl_handle);
+
+ if ((btm_send_connect_request(acl_handle, &p->esco.setup)) ==
+ BTM_CMD_STARTED)
+ p->state = SCO_ST_CONNECTING;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_disc_chk_pend_for_modechange
+ *
+ * Description This function is called by btm when there is a mode change
+ * event to see if there are SCO disconnect commands waiting
+ * for the mode change.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ BTM_TRACE_DEBUG("%s: hci_handle 0x%04x, p->state 0x%02x", __func__,
+ hci_handle, p->state);
+
+ for (uint16_t xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_PEND_MODECHANGE) &&
+ (BTM_GetHCIConnHandle(p->esco.data.bd_addr, BT_TRANSPORT_BR_EDR)) ==
+ hci_handle)
+
+ {
+ BTM_TRACE_DEBUG("%s: SCO Link handle 0x%04x", __func__, p->hci_handle);
+ BTM_RemoveSco(xx);
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_conn_req
+ *
+ * Description This function is called by BTIF when an SCO connection
+ * request is received from a remote.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_conn_req(BD_ADDR bda, DEV_CLASS dev_class, uint8_t link_type) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CB* p_sco = &btm_cb.sco_cb;
+ tSCO_CONN* p = &p_sco->sco_db[0];
+ uint16_t xx;
+ tBTM_ESCO_CONN_REQ_EVT_DATA evt_data;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ /*
+ * If the sco state is in the SCO_ST_CONNECTING state, we still need
+ * to return accept sco to avoid race conditon for sco creation
+ */
+ int rem_bd_matches =
+ p->rem_bd_known && !memcmp(p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+ /** M: Bug Fix for create sco collision @{ */
+ if ((p->state == SCO_ST_CONNECTING) && rem_bd_matches)
+ p->is_collision = true;
+ /** @} */
+ if (((p->state == SCO_ST_CONNECTING) && rem_bd_matches) ||
+ ((p->state == SCO_ST_LISTENING) &&
+ (rem_bd_matches || !p->rem_bd_known))) {
+ /* If this guy was a wildcard, he is not one any more */
+ p->rem_bd_known = true;
+ p->esco.data.link_type = link_type;
+ p->state = SCO_ST_W4_CONN_RSP;
+ memcpy(p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+
+ /* If no callback, auto-accept the connection if packet types match */
+ if (!p->esco.p_esco_cback) {
+ /* If requesting eSCO reject if default parameters are SCO only */
+ if ((link_type == BTM_LINK_TYPE_ESCO &&
+ !(p_sco->def_esco_parms.packet_types & BTM_ESCO_LINK_ONLY_MASK) &&
+ ((p_sco->def_esco_parms.packet_types &
+ BTM_SCO_EXCEPTION_PKTS_MASK) == BTM_SCO_EXCEPTION_PKTS_MASK))
+
+ /* Reject request if SCO is desired but no SCO packets delected */
+ ||
+ (link_type == BTM_LINK_TYPE_SCO &&
+ !(p_sco->def_esco_parms.packet_types & BTM_SCO_LINK_ONLY_MASK))) {
+ btm_esco_conn_rsp(xx, HCI_ERR_HOST_REJECT_RESOURCES, bda, NULL);
+ } else /* Accept the request */
+ {
+ btm_esco_conn_rsp(xx, HCI_SUCCESS, bda, NULL);
+ }
+ } else /* Notify upper layer of connect indication */
+ {
+ memcpy(evt_data.bd_addr, bda, BD_ADDR_LEN);
+ memcpy(evt_data.dev_class, dev_class, DEV_CLASS_LEN);
+ evt_data.link_type = link_type;
+ evt_data.sco_inx = xx;
+ p->esco.p_esco_cback(BTM_ESCO_CONN_REQ_EVT,
+ (tBTM_ESCO_EVT_DATA*)&evt_data);
+ }
+
+ return;
+ }
+ }
+
+ /* TCS usage */
+ if (btm_cb.sco_cb.app_sco_ind_cb) {
+ /* Now, try to find an unused control block */
+ for (xx = 0, p = &btm_cb.sco_cb.sco_db[0]; xx < BTM_MAX_SCO_LINKS;
+ xx++, p++) {
+ if (p->state == SCO_ST_UNUSED) {
+ p->is_orig = false;
+ p->state = SCO_ST_LISTENING;
+
+ p->esco.data.link_type = link_type;
+ memcpy(p->esco.data.bd_addr, bda, BD_ADDR_LEN);
+ p->rem_bd_known = true;
+ break;
+ }
+ }
+ if (xx < BTM_MAX_SCO_LINKS) {
+ btm_cb.sco_cb.app_sco_ind_cb(xx);
+ return;
+ }
+ }
+
+#endif
+ /* If here, no one wants the SCO connection. Reject it */
+ BTM_TRACE_WARNING(
+ "btm_sco_conn_req: No one wants this SCO connection; rejecting it");
+ btm_esco_conn_rsp(BTM_MAX_SCO_LINKS, HCI_ERR_HOST_REJECT_RESOURCES, bda,
+ NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_connected
+ *
+ * Description This function is called by BTIF when an (e)SCO connection
+ * is connected.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_connected(uint8_t hci_status, BD_ADDR bda, uint16_t hci_handle,
+ tBTM_ESCO_DATA* p_esco_data) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+ bool spt = false;
+ tBTM_CHG_ESCO_PARAMS parms;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = hci_status;
+
+#if (BTM_MAX_SCO_LINKS > 0)
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ /** M: Bug Fix for create sco collision @{ */
+ if (p->is_collision && (!bda) && hci_status != HCI_SUCCESS) {
+ p->is_collision = false;
+ return;
+ }
+ /** @} */
+ if (((p->state == SCO_ST_CONNECTING) || (p->state == SCO_ST_LISTENING) ||
+ (p->state == SCO_ST_W4_CONN_RSP)) &&
+ (p->rem_bd_known) &&
+ (!bda || !memcmp(p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
+ if (hci_status != HCI_SUCCESS) {
+ /* Report the error if originator, otherwise remain in Listen mode */
+ if (p->is_orig) {
+ /* If role switch is pending, we need try again after role switch is
+ * complete */
+ if (hci_status == HCI_ERR_ROLE_SWITCH_PENDING) {
+ BTM_TRACE_API("Role Change pending for HCI handle 0x%04x",
+ hci_handle);
+ p->state = SCO_ST_PEND_ROLECHANGE;
+ }
+ /* avoid calling disconnect callback because of sco creation race */
+ else if (hci_status != HCI_ERR_LMP_ERR_TRANS_COLLISION) {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ }
+ } else {
+ /* Notify the upper layer that incoming sco connection has failed. */
+ if (p->state == SCO_ST_CONNECTING) {
+ p->state = SCO_ST_UNUSED;
+ (*p->p_disc_cb)(xx);
+ } else
+ p->state = SCO_ST_LISTENING;
+ }
+ /** M: Bug Fix for create sco collision @{ */
+ p->is_collision = false;
+ /** @} */
+
+ return;
+ }
+
+ if (p->state == SCO_ST_LISTENING) spt = true;
+
+ p->state = SCO_ST_CONNECTED;
+ p->hci_handle = hci_handle;
+ /** M: Bug Fix for create sco collision @{ */
+ p->is_collision = false;
+ /** @} */
+
+ if (!btm_cb.sco_cb.esco_supported) {
+ p->esco.data.link_type = BTM_LINK_TYPE_SCO;
+ if (spt) {
+ parms.packet_types = p->esco.setup.packet_types;
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency_ms = p->esco.setup.max_latency_ms;
+ parms.retransmission_effort = p->esco.setup.retransmission_effort;
+
+ BTM_ChangeEScoLinkParms(xx, &parms);
+ }
+ } else {
+ if (p_esco_data) p->esco.data = *p_esco_data;
+ }
+
+ (*p->p_conn_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_find_scb_by_handle
+ *
+ * Description Look through all active SCO connection for a match based on
+ * the HCI handle.
+ *
+ * Returns index to matched SCO connection CB, or BTM_MAX_SCO_LINKS if
+ * no match.
+ *
+ ******************************************************************************/
+uint16_t btm_find_scb_by_handle(uint16_t handle) {
+ int xx;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state == SCO_ST_CONNECTED) && (p->hci_handle == handle)) {
+ return (xx);
+ }
+ }
+
+ /* If here, no match found */
+ return (xx);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveSco
+ *
+ * Description This function is called to remove a specific SCO connection.
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[sco_inx];
+ uint16_t tempstate;
+ tBTM_PM_STATE state = BTM_PM_ST_INVALID;
+
+ BTM_TRACE_DEBUG("%s", __func__);
+
+ /* Validity check */
+ if ((sco_inx >= BTM_MAX_SCO_LINKS) || (p->state == SCO_ST_UNUSED))
+ return (BTM_UNKNOWN_ADDR);
+
+ /* If no HCI handle, simply drop the connection and return */
+ if (p->hci_handle == BTM_INVALID_HCI_HANDLE ||
+ p->state == SCO_ST_PEND_UNPARK) {
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister the eSCO event callback */
+ return (BTM_SUCCESS);
+ }
+
+ if ((btm_read_power_mode_state(p->esco.data.bd_addr, &state) ==
+ BTM_SUCCESS) &&
+ state == BTM_PM_ST_PENDING) {
+ BTM_TRACE_DEBUG("%s: BTM_PM_ST_PENDING for ACL mapped with SCO Link 0x%04x",
+ __func__, p->hci_handle);
+ p->state = SCO_ST_PEND_MODECHANGE;
+ return (BTM_CMD_STARTED);
+ }
+
+ tempstate = p->state;
+ p->state = SCO_ST_DISCONNECTING;
+
+ btsnd_hcic_disconnect(p->hci_handle, HCI_ERR_PEER_USER);
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_NO_RESOURCES);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_remove_sco_links
+ *
+ * Description This function is called to remove all sco links for an ACL
+ * link.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_remove_sco_links(BD_ADDR bda) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->rem_bd_known && (!memcmp(p->esco.data.bd_addr, bda, BD_ADDR_LEN))) {
+ BTM_RemoveSco(xx);
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_removed
+ *
+ * Description This function is called by BTIF when an SCO connection
+ * is removed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_removed(uint16_t hci_handle, uint8_t reason) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+#endif
+
+ btm_cb.sco_cb.sco_disc_reason = reason;
+
+#if (BTM_MAX_SCO_LINKS > 0)
+ p = &btm_cb.sco_cb.sco_db[0];
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((p->state != SCO_ST_UNUSED) && (p->state != SCO_ST_LISTENING) &&
+ (p->hci_handle == hci_handle)) {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+ p->hci_handle = BTM_INVALID_HCI_HANDLE;
+ p->rem_bd_known = false;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_acl_removed
+ *
+ * Description This function is called when an ACL connection is
+ * removed. If the BD address is NULL, it is assumed that
+ * the local device is down, and all SCO links are removed.
+ * If a specific BD address is passed, only SCO connections
+ * to that BD address are removed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sco_acl_removed(BD_ADDR bda) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state != SCO_ST_UNUSED) {
+ if ((!bda) || (!memcmp(p->esco.data.bd_addr, bda, BD_ADDR_LEN) &&
+ p->rem_bd_known)) {
+ btm_sco_flush_sco_data(xx);
+
+ p->state = SCO_ST_UNUSED;
+ p->esco.p_esco_cback = NULL; /* Deregister eSCO callback */
+ (*p->p_disc_cb)(xx);
+ }
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetScoPacketTypes
+ *
+ * Description This function is called to set the packet types used for
+ * a specific SCO connection,
+ *
+ * Parameters pkt_types - One or more of the following
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+ *
+ * BTM_SCO_LINK_ALL_MASK - enables all supported types
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tBTM_CHG_ESCO_PARAMS parms;
+ tSCO_CONN* p;
+
+ /* Validity check */
+ if (sco_inx >= BTM_MAX_SCO_LINKS) return (BTM_UNKNOWN_ADDR);
+
+ p = &btm_cb.sco_cb.sco_db[sco_inx];
+ parms.packet_types = pkt_types;
+
+ /* Keep the other parameters the same for SCO */
+ parms.max_latency_ms = p->esco.setup.max_latency_ms;
+ parms.retransmission_effort = p->esco.setup.retransmission_effort;
+
+ return (BTM_ChangeEScoLinkParms(sco_inx, &parms));
+#else
+ return (BTM_UNKNOWN_ADDR);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoPacketTypes
+ *
+ * Description This function is read the packet types used for a specific
+ * SCO connection.
+ *
+ * Returns Packet types supported for the connection
+ * One or more of the following (bitmask):
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+ return (p->esco.setup.packet_types);
+ else
+ return (0);
+#else
+ return (0);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoDiscReason
+ *
+ * Description This function is returns the reason why an (e)SCO connection
+ * has been removed. It contains the value until read, or until
+ * another (e)SCO connection has disconnected.
+ *
+ * Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoDiscReason(void) {
+ uint16_t res = btm_cb.sco_cb.sco_disc_reason;
+ btm_cb.sco_cb.sco_disc_reason = BTM_INVALID_SCO_DISC_REASON;
+ return (res);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceScoPacketTypes
+ *
+ * Description This function is read the SCO packet types that
+ * the device supports.
+ *
+ * Returns Packet types supported by the device.
+ * One or more of the following (bitmask):
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV3
+ * BTM_SCO_PKT_TYPES_MASK_NO_2_EV5
+ * BTM_SCO_PKT_TYPES_MASK_NO_3_EV5
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDeviceScoPacketTypes(void) {
+ return (btm_cb.btm_sco_pkt_types_supported);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoHandle
+ *
+ * Description This function is used to read the HCI handle used for a
+ * specific SCO connection,
+ *
+ * Returns handle for the connection, or 0xFFFF if invalid SCO index.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoHandle(uint16_t sco_inx) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->state == SCO_ST_CONNECTED))
+ return (p->hci_handle);
+ else
+ return (BTM_INVALID_HCI_HANDLE);
+#else
+ return (BTM_INVALID_HCI_HANDLE);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoBdAddr
+ *
+ * Description This function is read the remote BD Address for a specific
+ * SCO connection,
+ *
+ * Returns pointer to BD address or NULL if not known
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadScoBdAddr(uint16_t sco_inx) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[sco_inx];
+
+ /* Validity check */
+ if ((sco_inx < BTM_MAX_SCO_LINKS) && (p->rem_bd_known))
+ return (p->esco.data.bd_addr);
+ else
+ return (NULL);
+#else
+ return (NULL);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEScoMode
+ *
+ * Description This function sets up the negotiated parameters for SCO or
+ * eSCO, and sets as the default mode used for outgoing calls
+ * to BTM_CreateSco. It does not change any currently active
+ * (e)SCO links.
+ * Note: Incoming (e)SCO connections will always use packet
+ * types supported by the controller. If eSCO is not
+ * desired the feature should be disabled in the
+ * controller's feature mask.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_BUSY if there are one or more active (e)SCO links.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) {
+ enh_esco_params_t* p_def = &btm_cb.sco_cb.def_esco_parms;
+
+ if (btm_cb.sco_cb.esco_supported) {
+ *p_def = *p_parms;
+ } else {
+ /* Load defaults for SCO only */
+ *p_def = esco_parameters_for_codec(ESCO_CODEC_CVSD);
+ p_def->packet_types &= BTM_SCO_LINK_ONLY_MASK;
+ p_def->retransmission_effort = ESCO_RETRANSMISSION_OFF;
+ p_def->max_latency_ms = 12;
+ BTM_TRACE_WARNING("%s: eSCO not supported", __func__);
+ }
+
+ BTM_TRACE_API(
+ "%s: txbw 0x%08x, rxbw 0x%08x, max_lat 0x%04x, "
+ "pkt 0x%04x, rtx effort 0x%02x",
+ __func__, p_def->transmit_bandwidth, p_def->receive_bandwidth,
+ p_def->max_latency_ms, p_def->packet_types, p_def->retransmission_effort);
+
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RegForEScoEvts
+ *
+ * Description This function registers a SCO event callback with the
+ * specified instance. It should be used to received
+ * connection indication events and change of link parameter
+ * events.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+ * BTM_MODE_UNSUPPORTED if controller version is not BT1.2 or
+ * later or does not support eSCO.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
+ tBTM_ESCO_CBACK* p_esco_cback) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ if (!btm_cb.sco_cb.esco_supported) {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = NULL;
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_UNUSED) {
+ btm_cb.sco_cb.sco_db[sco_inx].esco.p_esco_cback = p_esco_cback;
+ return (BTM_SUCCESS);
+ }
+ return (BTM_ILLEGAL_VALUE);
+#else
+ return (BTM_MODE_UNSUPPORTED);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadEScoLinkParms
+ *
+ * Description This function returns the current eSCO link parameters for
+ * the specified handle. This can be called anytime a
+ * connection is active, but is typically called after
+ * receiving the SCO opened callback.
+ *
+ * Note: If called over a 1.1 controller, only the packet types
+ * field has meaning.
+ *
+ * Returns BTM_SUCCESS if returned data is valid connection.
+ * BTM_WRONG_MODE if no connection with a peer device or bad
+ * sco_inx.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx, tBTM_ESCO_DATA* p_parms) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ uint8_t index;
+
+ BTM_TRACE_API("%s: -> sco_inx 0x%04x", __func__, sco_inx);
+
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state >= SCO_ST_CONNECTED) {
+ *p_parms = btm_cb.sco_cb.sco_db[sco_inx].esco.data;
+ return (BTM_SUCCESS);
+ }
+
+ if (sco_inx == BTM_FIRST_ACTIVE_SCO_INDEX) {
+ for (index = 0; index < BTM_MAX_SCO_LINKS; index++) {
+ if (btm_cb.sco_cb.sco_db[index].state >= SCO_ST_CONNECTED) {
+ BTM_TRACE_API("%s: the first active SCO index is %d", __func__, index);
+ *p_parms = btm_cb.sco_cb.sco_db[index].esco.data;
+ return (BTM_SUCCESS);
+ }
+ }
+ }
+
+#endif
+
+ BTM_TRACE_API("BTM_ReadEScoLinkParms cannot find the SCO index!");
+ memset(p_parms, 0, sizeof(tBTM_ESCO_DATA));
+ return (BTM_WRONG_MODE);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ChangeEScoLinkParms
+ *
+ * Description This function requests renegotiation of the parameters on
+ * the current eSCO Link. If any of the changes are accepted
+ * by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+ * the tBTM_ESCO_CBACK function with the current settings of
+ * the link. The callback is registered through the call to
+ * BTM_SetEScoMode.
+ *
+ * Note: If called over a SCO link (including 1.1 controller),
+ * a change packet type request is sent out instead.
+ *
+ * Returns BTM_CMD_STARTED if command is successfully initiated.
+ * BTM_NO_RESOURCES - not enough resources to initiate command.
+ * BTM_WRONG_MODE if no connection with a peer device or bad
+ * sco_inx.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
+ tBTM_CHG_ESCO_PARAMS* p_parms) {
+#if (BTM_MAX_SCO_LINKS > 0)
+
+ /* Make sure sco handle is valid and on an active link */
+ if (sco_inx >= BTM_MAX_SCO_LINKS ||
+ btm_cb.sco_cb.sco_db[sco_inx].state != SCO_ST_CONNECTED)
+ return (BTM_WRONG_MODE);
+
+ tSCO_CONN* p_sco = &btm_cb.sco_cb.sco_db[sco_inx];
+ enh_esco_params_t* p_setup = &p_sco->esco.setup;
+
+ /* Save the previous types in case command fails */
+ uint16_t saved_packet_types = p_setup->packet_types;
+
+ /* If SCO connection OR eSCO not supported just send change packet types */
+ if (p_sco->esco.data.link_type == BTM_LINK_TYPE_SCO ||
+ !btm_cb.sco_cb.esco_supported) {
+ p_setup->packet_types =
+ p_parms->packet_types &
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_LINK_ONLY_MASK);
+
+ BTM_TRACE_API("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__,
+ p_sco->hci_handle, p_setup->packet_types);
+
+ BTM_TRACE_API("%s: SCO Link for handle 0x%04x, pkt 0x%04x", __func__,
+ p_sco->hci_handle, p_setup->packet_types);
+
+ btsnd_hcic_change_conn_type(p_sco->hci_handle,
+ BTM_ESCO_2_SCO(p_setup->packet_types));
+ } else /* eSCO is supported and the link type is eSCO */
+ {
+ uint16_t temp_packet_types =
+ (p_parms->packet_types & BTM_SCO_SUPPORTED_PKTS_MASK &
+ btm_cb.btm_sco_pkt_types_supported);
+
+ /* OR in any exception packet types */
+ temp_packet_types |=
+ ((p_parms->packet_types & BTM_SCO_EXCEPTION_PKTS_MASK) |
+ (btm_cb.btm_sco_pkt_types_supported & BTM_SCO_EXCEPTION_PKTS_MASK));
+ p_setup->packet_types = temp_packet_types;
+
+ BTM_TRACE_API("%s -> eSCO Link for handle 0x%04x", __func__,
+ p_sco->hci_handle);
+ BTM_TRACE_API(
+ " txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, pkt 0x%04x",
+ p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_parms->max_latency_ms, p_parms->retransmission_effort,
+ temp_packet_types);
+
+ /** M: Change feature For enhanced setup synchronous connection. @{ */
+ // MTK platform uses differenct command by codec type.
+ /* Use Enhanced Synchronous commands if supported */
+ if (p_setup && (p_setup->transmit_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC
+ && p_setup->receive_coding_format.coding_format == ESCO_CODING_FORMAT_MSBC)) {
+ /*if (controller_get_interface()
+ ->supports_enhanced_setup_synchronous_connection()) {*/
+ /* Use the saved SCO routing */
+ /** @} */
+ p_setup->input_data_path = p_setup->output_data_path =
+ btm_cb.sco_cb.sco_route;
+
+ btsnd_hcic_enhanced_set_up_synchronous_connection(p_sco->hci_handle,
+ p_setup);
+ p_setup->packet_types = saved_packet_types;
+ } else { /* Use older command */
+ uint16_t voice_content_format = btm_sco_voice_settings_to_legacy(p_setup);
+ /* When changing an existing link, only change latency, retrans, and
+ * pkts */
+ btsnd_hcic_setup_esco_conn(p_sco->hci_handle, p_setup->transmit_bandwidth,
+ p_setup->receive_bandwidth,
+ p_parms->max_latency_ms, voice_content_format,
+ p_parms->retransmission_effort,
+ p_setup->packet_types);
+ }
+
+ BTM_TRACE_API(
+ "%s: txbw 0x%x, rxbw 0x%x, lat 0x%x, retrans 0x%02x, pkt 0x%04x",
+ __func__, p_setup->transmit_bandwidth, p_setup->receive_bandwidth,
+ p_parms->max_latency_ms, p_parms->retransmission_effort,
+ temp_packet_types);
+ }
+
+ return (BTM_CMD_STARTED);
+#else
+ return (BTM_WRONG_MODE);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_EScoConnRsp
+ *
+ * Description This function is called upon receipt of an (e)SCO connection
+ * request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+ * the request. Parameters used to negotiate eSCO links.
+ * If p_parms is NULL, then values set through BTM_SetEScoMode
+ * are used.
+ * If the link type of the incoming request is SCO, then only
+ * the tx_bw, max_latency, content format, and packet_types are
+ * valid. The hci_status parameter should be
+ * ([0x0] to accept, [0x0d..0x0f] to reject)
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
+ enh_esco_params_t* p_parms) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ if (sco_inx < BTM_MAX_SCO_LINKS &&
+ btm_cb.sco_cb.sco_db[sco_inx].state == SCO_ST_W4_CONN_RSP) {
+ btm_esco_conn_rsp(sco_inx, hci_status,
+ btm_cb.sco_cb.sco_db[sco_inx].esco.data.bd_addr, p_parms);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_def_esco_mode
+ *
+ * Description This function copies the current default esco settings into
+ * the return buffer.
+ *
+ * Returns tBTM_SCO_TYPE
+ *
+ ******************************************************************************/
+void btm_read_def_esco_mode(enh_esco_params_t* p_parms) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ *p_parms = btm_cb.sco_cb.def_esco_parms;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_esco_proc_conn_chg
+ *
+ * Description This function is called by BTIF when an SCO connection
+ * is changed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_esco_proc_conn_chg(uint8_t status, uint16_t handle,
+ uint8_t tx_interval, uint8_t retrans_window,
+ uint16_t rx_pkt_len, uint16_t tx_pkt_len) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ tBTM_CHG_ESCO_EVT_DATA data;
+ uint16_t xx;
+
+ BTM_TRACE_EVENT("btm_esco_proc_conn_chg -> handle 0x%04x, status 0x%02x",
+ handle, status);
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (p->state == SCO_ST_CONNECTED && handle == p->hci_handle) {
+ /* If upper layer wants notification */
+ if (p->esco.p_esco_cback) {
+ memcpy(data.bd_addr, p->esco.data.bd_addr, BD_ADDR_LEN);
+ data.hci_status = status;
+ data.sco_inx = xx;
+ data.rx_pkt_len = p->esco.data.rx_pkt_len = rx_pkt_len;
+ data.tx_pkt_len = p->esco.data.tx_pkt_len = tx_pkt_len;
+ data.tx_interval = p->esco.data.tx_interval = tx_interval;
+ data.retrans_window = p->esco.data.retrans_window = retrans_window;
+
+ (*p->esco.p_esco_cback)(BTM_ESCO_CHG_EVT, (tBTM_ESCO_EVT_DATA*)&data);
+ }
+ return;
+ }
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_is_sco_active
+ *
+ * Description This function is called to see if a SCO handle is already in
+ * use.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btm_is_sco_active(uint16_t handle) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ uint16_t xx;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if (handle == p->hci_handle && p->state == SCO_ST_CONNECTED) return (true);
+ }
+#endif
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumScoLinks
+ *
+ * Description This function returns the number of active sco links.
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+uint8_t BTM_GetNumScoLinks(void) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+ uint16_t xx;
+ uint8_t num_scos = 0;
+
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ switch (p->state) {
+ case SCO_ST_W4_CONN_RSP:
+ case SCO_ST_CONNECTING:
+ case SCO_ST_CONNECTED:
+ case SCO_ST_DISCONNECTING:
+ case SCO_ST_PEND_UNPARK:
+ num_scos++;
+ }
+ }
+ return (num_scos);
+#else
+ return (0);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_is_sco_active_by_bdaddr
+ *
+ * Description This function is called to see if a SCO connection is active
+ * for a bd address.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool btm_is_sco_active_by_bdaddr(BD_ADDR remote_bda) {
+#if (BTM_MAX_SCO_LINKS > 0)
+ uint8_t xx;
+ tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
+
+ /* If any SCO is being established to the remote BD address, refuse this */
+ for (xx = 0; xx < BTM_MAX_SCO_LINKS; xx++, p++) {
+ if ((!memcmp(p->esco.data.bd_addr, remote_bda, BD_ADDR_LEN)) &&
+ (p->state == SCO_ST_CONNECTED)) {
+ return (true);
+ }
+ }
+#endif
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sco_voice_settings_2_legacy
+ *
+ * Description This function is called to convert the Enhanced eSCO
+ * parameters into voice setting parameter mask used
+ * for legacy setup synchronous connection HCI commands
+ *
+ * Returns UINT16 - 16-bit mask for voice settings
+ *
+ * HCI_INP_CODING_LINEAR 0x0000 (0000000000)
+ * HCI_INP_CODING_U_LAW 0x0100 (0100000000)
+ * HCI_INP_CODING_A_LAW 0x0200 (1000000000)
+ * HCI_INP_CODING_MASK 0x0300 (1100000000)
+ *
+ * HCI_INP_DATA_FMT_1S_COMPLEMENT 0x0000 (0000000000)
+ * HCI_INP_DATA_FMT_2S_COMPLEMENT 0x0040 (0001000000)
+ * HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 (0010000000)
+ * HCI_INP_DATA_FMT_UNSIGNED 0x00c0 (0011000000)
+ * HCI_INP_DATA_FMT_MASK 0x00c0 (0011000000)
+ *
+ * HCI_INP_SAMPLE_SIZE_8BIT 0x0000 (0000000000)
+ * HCI_INP_SAMPLE_SIZE_16BIT 0x0020 (0000100000)
+ * HCI_INP_SAMPLE_SIZE_MASK 0x0020 (0000100000)
+ *
+ * HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c (0000011100)
+ * HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2
+ *
+ * HCI_AIR_CODING_FORMAT_CVSD 0x0000 (0000000000)
+ * HCI_AIR_CODING_FORMAT_U_LAW 0x0001 (0000000001)
+ * HCI_AIR_CODING_FORMAT_A_LAW 0x0002 (0000000010)
+ * HCI_AIR_CODING_FORMAT_TRANSPNT 0x0003 (0000000011)
+ * HCI_AIR_CODING_FORMAT_MASK 0x0003 (0000000011)
+ *
+ * default (0001100000)
+ * HCI_DEFAULT_VOICE_SETTINGS (HCI_INP_CODING_LINEAR \
+ * | HCI_INP_DATA_FMT_2S_COMPLEMENT \
+ * | HCI_INP_SAMPLE_SIZE_16BIT \
+ * | HCI_AIR_CODING_FORMAT_CVSD)
+ *
+ ******************************************************************************/
+static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_params) {
+ uint16_t voice_settings = 0;
+
+ /* Convert Input Coding Format: If no uLaw or aLAW then Linear will be used
+ * (0) */
+ if (p_params->input_coding_format.coding_format == ESCO_CODING_FORMAT_ULAW)
+ voice_settings |= HCI_INP_CODING_U_LAW;
+ else if (p_params->input_coding_format.coding_format ==
+ ESCO_CODING_FORMAT_ALAW)
+ voice_settings |= HCI_INP_CODING_A_LAW;
+ /* else default value of '0 is good 'Linear' */
+
+ /* Convert Input Data Format. Use 2's Compliment as the default */
+ switch (p_params->input_pcm_data_format) {
+ case ESCO_PCM_DATA_FORMAT_1_COMP:
+ /* voice_settings |= HCI_INP_DATA_FMT_1S_COMPLEMENT; value is '0'
+ * already */
+ break;
+
+ case ESCO_PCM_DATA_FORMAT_SIGN:
+ voice_settings |= HCI_INP_DATA_FMT_SIGN_MAGNITUDE;
+ break;
+
+ case ESCO_PCM_DATA_FORMAT_UNSIGN:
+ voice_settings |= HCI_INP_DATA_FMT_UNSIGNED;
+ break;
+
+ default: /* 2's Compliment */
+ voice_settings |= HCI_INP_DATA_FMT_2S_COMPLEMENT;
+ break;
+ }
+
+ /* Convert Over the Air Coding. Use CVSD as the default */
+ switch (p_params->transmit_coding_format.coding_format) {
+ case ESCO_CODING_FORMAT_ULAW:
+ voice_settings |= HCI_AIR_CODING_FORMAT_U_LAW;
+ break;
+
+ case ESCO_CODING_FORMAT_ALAW:
+ voice_settings |= HCI_AIR_CODING_FORMAT_A_LAW;
+ break;
+
+ case ESCO_CODING_FORMAT_MSBC:
+ voice_settings |= HCI_AIR_CODING_FORMAT_TRANSPNT;
+ break;
+
+ default: /* CVSD (0) */
+ break;
+ }
+
+ /* Convert PCM payload MSB position (0000011100) */
+ voice_settings |= (uint16_t)(((p_params->input_pcm_payload_msb_position & 0x7)
+ << HCI_INP_LINEAR_PCM_BIT_POS_OFFS));
+
+ /* Convert Input Sample Size (0000011100) */
+ if (p_params->input_coded_data_size == 16)
+ voice_settings |= HCI_INP_SAMPLE_SIZE_16BIT;
+ else /* Use 8 bit for all others */
+ voice_settings |= HCI_INP_SAMPLE_SIZE_8BIT;
+
+ BTM_TRACE_DEBUG("%s: voice setting for legacy 0x%03x", __func__,
+ voice_settings);
+
+ return (voice_settings);
+}
+
+#else /* SCO_EXCLUDED == TRUE (Link in stubs) */
+
+tBTM_STATUS BTM_CreateSco(BD_ADDR remote_bda, bool is_orig, uint16_t pkt_types,
+ uint16_t* p_sco_inx, tBTM_SCO_CB* p_conn_cb,
+ tBTM_SCO_CB* p_disc_cb) {
+ return (BTM_NO_RESOURCES);
+}
+tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx) { return (BTM_NO_RESOURCES); }
+tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types) {
+ return (BTM_NO_RESOURCES);
+}
+uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx) { return (0); }
+uint16_t BTM_ReadDeviceScoPacketTypes(void) { return (0); }
+uint16_t BTM_ReadScoHandle(uint16_t sco_inx) {
+ return (BTM_INVALID_HCI_HANDLE);
+}
+uint8_t* BTM_ReadScoBdAddr(uint16_t sco_inx) { return ((uint8_t*)NULL); }
+uint16_t BTM_ReadScoDiscReason(void) { return (BTM_INVALID_SCO_DISC_REASON); }
+tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms) {
+ return (BTM_MODE_UNSUPPORTED);
+}
+tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
+ tBTM_ESCO_CBACK* p_esco_cback) {
+ return (BTM_ILLEGAL_VALUE);
+}
+tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx, tBTM_ESCO_DATA* p_parms) {
+ return (BTM_MODE_UNSUPPORTED);
+}
+tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
+ tBTM_CHG_ESCO_PARAMS* p_parms) {
+ return (BTM_MODE_UNSUPPORTED);
+}
+void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
+ enh_esco_params_t* p_parms) {}
+uint8_t BTM_GetNumScoLinks(void) { return (0); }
+
+#endif /* If SCO is being used */
diff --git a/mtkbt/code/bt/stack/btm/btm_sec.cc b/mtkbt/code/bt/stack/btm/btm_sec.cc
new file mode 100755
index 0000000..eb4c641
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btm/btm_sec.cc
@@ -0,0 +1,6246 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the Bluetooth Security Manager
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btm_sec"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "device/include/controller.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+
+#include "gatt_int.h"
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+#include "device_class.h"
+#include <cutils/properties.h>
+#include "osi/include/properties.h"
+#endif
+
+
+/** M: disable security check for IOT device @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+/** @} */
+
+#define BTM_SEC_MAX_COLLISION_DELAY (5000)
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+bool(APPL_AUTH_WRITE_EXCEPTION)(BD_ADDR bd_addr);
+#endif
+
+/*******************************************************************************
+ * L O C A L F U N C T I O N P R O T O T Y P E S *
+ ******************************************************************************/
+tBTM_SEC_SERV_REC* btm_sec_find_first_serv(bool is_originator, uint16_t psm);
+static tBTM_SEC_SERV_REC* btm_sec_find_next_serv(tBTM_SEC_SERV_REC* p_cur);
+static tBTM_SEC_SERV_REC* btm_sec_find_mx_serv(uint8_t is_originator,
+ uint16_t psm,
+ uint32_t mx_proto_id,
+ uint32_t mx_chan_id);
+
+static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec);
+static void btm_sec_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec);
+static void btm_sec_start_encryption(tBTM_SEC_DEV_REC* p_dev_rec);
+static void btm_sec_collision_timeout(void* data);
+static void btm_restore_mode(void);
+static void btm_sec_pairing_timeout(void* data);
+static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec);
+static void btm_sec_change_pairing_state(tBTM_PAIRING_STATE new_state);
+
+static const char* btm_pair_state_descr(tBTM_PAIRING_STATE state);
+
+static void btm_sec_check_pending_reqs(void);
+static bool btm_sec_queue_mx_request(BD_ADDR bd_addr, uint16_t psm,
+ bool is_orig, uint32_t mx_proto_id,
+ uint32_t mx_chan_id,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data);
+static void btm_sec_bond_cancel_complete(void);
+static void btm_send_link_key_notif(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_sec_check_prefetch_pin(tBTM_SEC_DEV_REC* p_dev_rec);
+
+static uint8_t btm_sec_start_authorization(tBTM_SEC_DEV_REC* p_dev_rec);
+bool btm_sec_are_all_trusted(uint32_t p_mask[]);
+
+static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec,
+ uint8_t reason,
+ uint16_t conn_handle);
+uint8_t btm_sec_start_role_switch(tBTM_SEC_DEV_REC* p_dev_rec);
+tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state);
+
+static bool btm_sec_set_security_level(CONNECTION_TYPE conn_type,
+ const char* p_name, uint8_t service_id,
+ uint16_t sec_level, uint16_t psm,
+ uint32_t mx_proto_id,
+ uint32_t mx_chan_id);
+
+static bool btm_dev_authenticated(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_dev_encrypted(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_dev_authorized(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_serv_trusted(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBTM_SEC_SERV_REC* p_serv_rec);
+static bool btm_sec_is_serv_level0(uint16_t psm);
+static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security,
+ bool is_originator);
+
+static bool btm_sec_queue_encrypt_request(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data,
+ tBTM_BLE_SEC_ACT sec_act);
+static void btm_sec_check_pending_enc_req(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBT_TRANSPORT transport,
+ uint8_t encr_enable);
+
+static bool btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC* p_dev_rec);
+static bool btm_sec_is_master(tBTM_SEC_DEV_REC* p_dev_rec);
+
+/* true - authenticated link key is possible */
+static const bool btm_sec_io_map[BTM_IO_CAP_MAX][BTM_IO_CAP_MAX] = {
+ /* OUT, IO, IN, NONE */
+ /* OUT */ {false, false, true, false},
+ /* IO */ {false, true, true, false},
+ /* IN */ {true, true, true, false},
+ /* NONE */ {false, false, false, false}};
+/* BTM_IO_CAP_OUT 0 DisplayOnly */
+/* BTM_IO_CAP_IO 1 DisplayYesNo */
+/* BTM_IO_CAP_IN 2 KeyboardOnly */
+/* BTM_IO_CAP_NONE 3 NoInputNoOutput */
+
+/*******************************************************************************
+ *
+ * Function btm_dev_authenticated
+ *
+ * Description check device is authenticated
+ *
+ * Returns bool true or false
+ *
+ ******************************************************************************/
+static bool btm_dev_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) {
+ if (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED) {
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_dev_encrypted
+ *
+ * Description check device is encrypted
+ *
+ * Returns bool true or false
+ *
+ ******************************************************************************/
+static bool btm_dev_encrypted(tBTM_SEC_DEV_REC* p_dev_rec) {
+ if (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) {
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_dev_authorized
+ *
+ * Description check device is authorized
+ *
+ * Returns bool true or false
+ *
+ ******************************************************************************/
+static bool btm_dev_authorized(tBTM_SEC_DEV_REC* p_dev_rec) {
+ if (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) {
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_dev_16_digit_authenticated
+ *
+ * Description check device is authenticated by using 16 digit pin or MITM
+ *
+ * Returns bool true or false
+ *
+ ******************************************************************************/
+static bool btm_dev_16_digit_authenticated(tBTM_SEC_DEV_REC* p_dev_rec) {
+ // BTM_SEC_16_DIGIT_PIN_AUTHED is set if MITM or 16 digit pin is used
+ if (p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) {
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_serv_trusted
+ *
+ * Description check service is trusted
+ *
+ * Returns bool true or false
+ *
+ ******************************************************************************/
+static bool btm_serv_trusted(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBTM_SEC_SERV_REC* p_serv_rec) {
+ if (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_serv_rec->service_id)) {
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecRegister
+ *
+ * Description Application manager calls this function to register for
+ * security services. There can be one and only one
+ * application saving link keys. BTM allows only first
+ * registration.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegister(tBTM_APPL_INFO* p_cb_info) {
+ BT_OCTET16 temp_value = {0};
+
+ BTM_TRACE_EVENT("%s application registered", __func__);
+
+ LOG_INFO(LOG_TAG, "%s p_cb_info->p_le_callback == 0x%p", __func__,
+ p_cb_info->p_le_callback);
+ if (p_cb_info->p_le_callback) {
+ BTM_TRACE_EVENT("%s SMP_Register( btm_proc_smp_cback )", __func__);
+ SMP_Register(btm_proc_smp_cback);
+ /* if no IR is loaded, need to regenerate all the keys */
+ if (memcmp(btm_cb.devcb.id_keys.ir, &temp_value, sizeof(BT_OCTET16)) == 0) {
+ btm_ble_reset_id();
+ }
+ } else {
+ LOG_WARN(LOG_TAG, "%s p_cb_info->p_le_callback == NULL", __func__);
+ }
+
+ btm_cb.api = *p_cb_info;
+ LOG_INFO(LOG_TAG, "%s btm_cb.api.p_le_callback = 0x%p ", __func__,
+ btm_cb.api.p_le_callback);
+ BTM_TRACE_EVENT("%s application registered", __func__);
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecRegisterLinkKeyNotificationCallback
+ *
+ * Description Application manager calls this function to register for
+ * link key notification. When there is nobody registered
+ * we should avoid changing link key
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegisterLinkKeyNotificationCallback(
+ tBTM_LINK_KEY_CALLBACK* p_callback) {
+ btm_cb.api.p_link_key_callback = p_callback;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddRmtNameNotifyCallback
+ *
+ * Description Any profile can register to be notified when name of the
+ * remote device is resolved.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] == NULL) {
+ btm_cb.p_rmt_name_callback[i] = p_callback;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecDeleteRmtNameNotifyCallback
+ *
+ * Description Any profile can deregister notification when a new Link Key
+ * is generated per connection.
+ *
+ * Returns true if OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] == p_callback) {
+ btm_cb.p_rmt_name_callback[i] = NULL;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlags
+ *
+ * Description Get security flags for the device
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlags(BD_ADDR bd_addr, uint8_t* p_sec_flags) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ *p_sec_flags = (uint8_t)p_dev_rec->sec_flags;
+ return (true);
+ }
+ BTM_TRACE_ERROR("BTM_GetSecurityFlags false");
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlagsByTransport
+ *
+ * Description Get security flags for the device on a particular transport
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlagsByTransport(BD_ADDR bd_addr, uint8_t* p_sec_flags,
+ tBT_TRANSPORT transport) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ if (transport == BT_TRANSPORT_BR_EDR)
+ *p_sec_flags = (uint8_t)p_dev_rec->sec_flags;
+ else
+ *p_sec_flags = (uint8_t)(p_dev_rec->sec_flags >> 8);
+
+ return (true);
+ }
+ BTM_TRACE_ERROR("BTM_GetSecurityFlags false");
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPinType
+ *
+ * Description Set PIN type for the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len) {
+ BTM_TRACE_API(
+ "BTM_SetPinType: pin type %d [variable-0, fixed-1], code %s, length %d",
+ pin_type, (char*)pin_code, pin_code_len);
+
+ /* If device is not up security mode will be set as a part of startup */
+ if ((btm_cb.cfg.pin_type != pin_type) &&
+ controller_get_interface()->get_is_ready()) {
+ btsnd_hcic_write_pin_type(pin_type);
+ }
+
+ btm_cb.cfg.pin_type = pin_type;
+ btm_cb.cfg.pin_code_len = pin_code_len;
+ memcpy(btm_cb.cfg.pin_code, pin_code, pin_code_len);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPairableMode
+ *
+ * Description Enable or disable pairing
+ *
+ * Parameters allow_pairing - (true or false) whether or not the device
+ * allows pairing.
+ * connect_only_paired - (true or false) whether or not to
+ * only allow paired devices to connect.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetPairableMode(bool allow_pairing, bool connect_only_paired) {
+ BTM_TRACE_API(
+ "BTM_SetPairableMode() allow_pairing: %u connect_only_paired: %u",
+ allow_pairing, connect_only_paired);
+
+ btm_cb.pairing_disabled = !allow_pairing;
+ btm_cb.connect_only_paired = connect_only_paired;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecureConnectionsOnly
+ *
+ * Description Enable or disable default treatment for Mode 4 Level 0
+ * services
+ *
+ * Parameter secure_connections_only_mode -
+ * true means that the device should treat Mode 4 Level 0
+ * services as services of other levels.
+ * false means that the device should provide default
+ * treatment for Mode 4 Level 0 services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetSecureConnectionsOnly(bool secure_connections_only_mode) {
+ BTM_TRACE_API("%s: Mode : %u", __func__, secure_connections_only_mode);
+
+ btm_cb.devcb.secure_connections_only = secure_connections_only_mode;
+ btm_cb.security_mode = BTM_SEC_MODE_SC;
+}
+#define BTM_NO_AVAIL_SEC_SERVICES ((uint16_t)0xffff)
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecurityLevel
+ *
+ * Description Register service security level with Security Manager
+ *
+ * Parameters: is_originator - true if originating the connection
+ * p_name - Name of the service relevant only if
+ * authorization will show this name to user.
+ * Ignored if BTM_SEC_SERVICE_NAME_LEN is 0.
+ * service_id - service ID for the service passed to
+ * authorization callback
+ * sec_level - bit mask of the security features
+ * psm - L2CAP PSM
+ * mx_proto_id - protocol ID of multiplexing proto below
+ * mx_chan_id - channel ID of multiplexing proto below
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
+ uint8_t service_id, uint16_t sec_level, uint16_t psm,
+ uint32_t mx_proto_id, uint32_t mx_chan_id) {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ CONNECTION_TYPE conn_type;
+
+ if (is_originator)
+ conn_type = CONN_ORIENT_ORIG;
+ else
+ conn_type = CONN_ORIENT_TERM;
+
+ return (btm_sec_set_security_level(conn_type, p_name, service_id, sec_level,
+ psm, mx_proto_id, mx_chan_id));
+#else
+ return (btm_sec_set_security_level(is_originator, p_name, service_id,
+ sec_level, psm, mx_proto_id, mx_chan_id));
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_set_security_level
+ *
+ * Description Register service security level with Security Manager
+ *
+ * Parameters: conn_type - true if originating the connection
+ * p_name - Name of the service relevant only if
+ * authorization will show this name to user.
+ * Ignored if BTM_SEC_SERVICE_NAME_LEN is 0.
+ * service_id - service ID for the service passed to
+ * authorization callback
+ * sec_level - bit mask of the security features
+ * psm - L2CAP PSM
+ * mx_proto_id - protocol ID of multiplexing proto below
+ * mx_chan_id - channel ID of multiplexing proto below
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+static bool btm_sec_set_security_level(CONNECTION_TYPE conn_type,
+ const char* p_name, uint8_t service_id,
+ uint16_t sec_level, uint16_t psm,
+ uint32_t mx_proto_id,
+ uint32_t mx_chan_id) {
+ tBTM_SEC_SERV_REC* p_srec;
+ uint16_t index;
+ uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
+ bool record_allocated = false;
+ bool is_originator;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ bool is_ucd;
+
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = true;
+ else
+ is_originator = false;
+
+ if (conn_type & CONNECTION_TYPE_CONNLESS_MASK) {
+ is_ucd = true;
+ } else {
+ is_ucd = false;
+ }
+#else
+ is_originator = conn_type;
+#endif
+
+ BTM_TRACE_API("%s : sec: 0x%x", __func__, sec_level);
+
+ /* See if the record can be reused (same service name, psm, mx_proto_id,
+ service_id, and mx_chan_id), or obtain the next unused record */
+
+ p_srec = &btm_cb.sec_serv_rec[0];
+
+ for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) {
+ /* Check if there is already a record for this service */
+ if (p_srec->security_flags & BTM_SEC_IN_USE) {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id && p_name &&
+ (!strncmp(p_name, (char*)p_srec->orig_service_name,
+ /* strlcpy replaces end char with termination char*/
+ BTM_SEC_SERVICE_NAME_LEN - 1) ||
+ !strncmp(p_name, (char*)p_srec->term_service_name,
+ /* strlcpy replaces end char with termination char*/
+ BTM_SEC_SERVICE_NAME_LEN - 1)))
+#else
+ if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id &&
+ service_id == p_srec->service_id)
+#endif
+ {
+ record_allocated = true;
+ break;
+ }
+ }
+ /* Mark the first available service record */
+ else if (!record_allocated) {
+ memset(p_srec, 0, sizeof(tBTM_SEC_SERV_REC));
+ record_allocated = true;
+ first_unused_record = index;
+ }
+ }
+
+ if (!record_allocated) {
+ BTM_TRACE_WARNING("BTM_SEC_REG: Out of Service Records (%d)",
+ BTM_SEC_MAX_SERVICE_RECORDS);
+ return (record_allocated);
+ }
+
+ /* Process the request if service record is valid */
+ /* If a duplicate service wasn't found, use the first available */
+ if (index >= BTM_SEC_MAX_SERVICE_RECORDS) {
+ index = first_unused_record;
+ p_srec = &btm_cb.sec_serv_rec[index];
+ }
+
+ p_srec->psm = psm;
+ p_srec->service_id = service_id;
+ p_srec->mx_proto_id = mx_proto_id;
+
+ if (is_originator) {
+ p_srec->orig_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ strlcpy((char*)p_srec->orig_service_name, p_name,
+ BTM_SEC_SERVICE_NAME_LEN + 1);
+#endif
+/* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (is_ucd) {
+ p_srec->ucd_security_flags &= ~(
+ BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM | BTM_SEC_FORCE_MASTER |
+ BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ } else
+#endif
+ {
+ p_srec->security_flags &= ~(
+ BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM | BTM_SEC_FORCE_MASTER |
+ BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+ }
+
+ /* Parameter validation. Originator should not set requirements for
+ * incoming connections */
+ sec_level &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE |
+ BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM;
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_OUT_ENCRYPT) sec_level |= BTM_SEC_OUT_AUTHENTICATE;
+
+/* outgoing connections usually set the security level right before
+ * the connection is initiated.
+ * set it to be the outgoing service */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (is_ucd == false)
+#endif
+ {
+ btm_cb.p_out_serv = p_srec;
+ }
+ } else {
+ p_srec->term_mx_chan_id = mx_chan_id;
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ strlcpy((char*)p_srec->term_service_name, p_name,
+ BTM_SEC_SERVICE_NAME_LEN + 1);
+#endif
+/* clear out the old setting, just in case it exists */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (is_ucd) {
+ p_srec->ucd_security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT |
+ BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | BTM_SEC_FORCE_MASTER |
+ BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE |
+ BTM_SEC_ATTEMPT_SLAVE | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+ } else
+#endif
+ {
+ p_srec->security_flags &=
+ ~(BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT |
+ BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM | BTM_SEC_FORCE_MASTER |
+ BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE |
+ BTM_SEC_ATTEMPT_SLAVE | BTM_SEC_IN_MIN_16_DIGIT_PIN);
+ }
+
+ /* Parameter validation. Acceptor should not set requirements for outgoing
+ * connections */
+ sec_level &= ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_ENCRYPT |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM;
+ }
+
+ /* Make sure the authenticate bit is set, when encrypt bit is set */
+ if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE;
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (is_ucd) {
+ p_srec->security_flags |= (uint16_t)(BTM_SEC_IN_USE);
+ p_srec->ucd_security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+ } else {
+ p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+ }
+
+ BTM_TRACE_API(
+ "BTM_SEC_REG[%d]: id %d, conn_type 0x%x, psm 0x%04x, proto_id %d, "
+ "chan_id %d",
+ index, service_id, conn_type, psm, mx_proto_id, mx_chan_id);
+
+ BTM_TRACE_API(
+ " : security_flags: 0x%04x, ucd_security_flags: 0x%04x",
+ p_srec->security_flags, p_srec->ucd_security_flags);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API(" : service name [%s] (up to %d chars saved)",
+ p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#else
+ p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
+
+ BTM_TRACE_API(
+ "BTM_SEC_REG[%d]: id %d, is_orig %d, psm 0x%04x, proto_id %d, chan_id %d",
+ index, service_id, is_originator, psm, mx_proto_id, mx_chan_id);
+
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ BTM_TRACE_API(
+ " : sec: 0x%x, service name [%s] (up to %d chars saved)",
+ p_srec->security_flags, p_name, BTM_SEC_SERVICE_NAME_LEN);
+#endif
+#endif
+
+ return (record_allocated);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClrService
+ *
+ * Description Removes specified service record(s) from the security
+ * database. All service records with the specified name are
+ * removed. Typically used only by devices with limited RAM so
+ * that it can reuse an old security service record.
+ *
+ * Note: Unpredictable results may occur if a service is
+ * cleared that is still in use by an application/profile.
+ *
+ * Parameters Service ID - Id of the service to remove. '0' removes all
+ * service records (except SDP).
+ *
+ * Returns Number of records that were freed.
+ *
+ ******************************************************************************/
+uint8_t BTM_SecClrService(uint8_t service_id) {
+ tBTM_SEC_SERV_REC* p_srec = &btm_cb.sec_serv_rec[0];
+ uint8_t num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) &&
+ (p_srec->psm != BT_PSM_SDP) &&
+ (!service_id || (service_id == p_srec->service_id))) {
+ BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d", i, service_id);
+ p_srec->security_flags = 0;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_srec->ucd_security_flags = 0;
+#endif
+ num_freed++;
+ }
+ }
+
+ return (num_freed);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_clr_service_by_psm
+ *
+ * Description Removes specified service record from the security database.
+ * All service records with the specified psm are removed.
+ * Typically used by L2CAP to free up the service record used
+ * by dynamic PSM clients when the channel is closed.
+ * The given psm must be a virtual psm.
+ *
+ * Parameters Service ID - Id of the service to remove. '0' removes all
+ * service records (except SDP).
+ *
+ * Returns Number of records that were freed.
+ *
+ ******************************************************************************/
+uint8_t btm_sec_clr_service_by_psm(uint16_t psm) {
+ tBTM_SEC_SERV_REC* p_srec = &btm_cb.sec_serv_rec[0];
+ uint8_t num_freed = 0;
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
+ /* Delete services with specified name (if in use and not SDP) */
+ if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm)) {
+ BTM_TRACE_API("BTM_SEC_CLR[%d]: id %d ", i, p_srec->service_id);
+ p_srec->security_flags = 0;
+ num_freed++;
+ }
+ }
+ BTM_TRACE_API("btm_sec_clr_service_by_psm psm:0x%x num_freed:%d", psm,
+ num_freed);
+
+ return (num_freed);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_clr_temp_auth_service
+ *
+ * Description Removes specified device record's temporary authorization
+ * flag from the security database.
+ *
+ * Parameters Device address to be cleared
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void btm_sec_clr_temp_auth_service(BD_ADDR bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ p_dev_rec = btm_find_dev(bda);
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_WARNING("btm_sec_clr_temp_auth_service() - no dev CB");
+ return;
+ }
+
+ /* Reset the temporary authorized flag so that next time (untrusted) service
+ * is accessed autorization will take place */
+ if (p_dev_rec->last_author_service_id != BTM_SEC_NO_LAST_SERVICE_ID &&
+ p_dev_rec->p_cur_service) {
+ BTM_TRACE_DEBUG(
+ "btm_sec_clr_auth_service_by_psm [clearing device: "
+ "%02x:%02x:%02x:%02x:%02x:%02x]",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ p_dev_rec->last_author_service_id = BTM_SEC_NO_LAST_SERVICE_ID;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_PINCodeReply
+ *
+ * Description This function is called after Security Manager submitted
+ * PIN code request to the UI.
+ *
+ * Parameters: bd_addr - Address of the device for which PIN was
+ * requested
+ * res - result of the operation BTM_SUCCESS
+ * if success
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ ******************************************************************************/
+void BTM_PINCodeReply(BD_ADDR bd_addr, uint8_t res, uint8_t pin_len,
+ uint8_t* p_pin, uint32_t trusted_mask[]) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_API(
+ "BTM_PINCodeReply(): PairState: %s PairFlags: 0x%02x PinLen:%d "
+ "Result:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), btm_cb.pairing_flags, pin_len,
+ res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) {
+ BTM_TRACE_WARNING("BTM_PINCodeReply() - Wrong State: %d",
+ btm_cb.pairing_state);
+ return;
+ }
+
+ if (memcmp(bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) {
+ BTM_TRACE_ERROR("BTM_PINCodeReply() - Wrong BD Addr");
+ return;
+ }
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("BTM_PINCodeReply() - no dev CB");
+ return;
+ }
+
+ if ((pin_len > PIN_CODE_LEN) || (pin_len == 0) || (p_pin == NULL))
+ res = BTM_ILLEGAL_VALUE;
+
+ if (res != BTM_SUCCESS) {
+ /* if peer started dd OR we started dd and pre-fetch pin was not used send
+ * negative reply */
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) ||
+ ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE))) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed
+ * event */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ btsnd_hcic_pin_code_neg_reply(bd_addr);
+ } else {
+ p_dev_rec->security_required = BTM_SEC_NONE;
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+ return;
+ }
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ p_dev_rec->pin_code_length = pin_len;
+ if (pin_len >= 16) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) &&
+ (btm_cb.security_mode_changed == false)) {
+ /* This is start of the dedicated bonding if local device is 2.0 */
+ btm_cb.pin_code_len = pin_len;
+ memcpy(btm_cb.pin_code, p_pin, pin_len);
+
+ btm_cb.security_mode_changed = true;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if (!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ btsnd_hcic_write_auth_enable(true);
+
+ btm_cb.acl_disc_reason = 0xff;
+
+ /* if we rejected incoming connection request, we have to wait
+ * HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) {
+ BTM_TRACE_WARNING(
+ "BTM_PINCodeReply(): waiting HCI_Connection_Complete after rejected "
+ "incoming connection");
+ /* we change state little bit early so btm_sec_connected() will originate
+ * connection */
+ /* when existing ACL link is down completely */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+ }
+ /* if we already accepted incoming connection from pairing device */
+ else if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) {
+ BTM_TRACE_WARNING(
+ "BTM_PINCodeReply(): link is connecting so wait pin code request "
+ "from peer");
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+ } else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_AUTHED;
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_ERR_AUTH_FAILURE);
+ }
+ return;
+ }
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+ btsnd_hcic_pin_code_req_reply(bd_addr, pin_len, p_pin);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_bond_by_transport
+ *
+ * Description this is the bond function that will start either SSP or SMP.
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ * Note: After 2.1 parameters are not used and preserved here not to change API
+ ******************************************************************************/
+tBTM_STATUS btm_sec_bond_by_transport(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ uint8_t pin_len, uint8_t* p_pin,
+ uint32_t trusted_mask[]) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_STATUS status;
+ uint8_t* p_features;
+ uint8_t ii;
+ tACL_CONN* p = btm_bda_to_acl(bd_addr, transport);
+ BTM_TRACE_API("btm_sec_bond_by_transport BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+
+ BTM_TRACE_DEBUG("btm_sec_bond_by_transport: Transport used %d", transport);
+
+ /* Other security process is in progress */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+ BTM_TRACE_ERROR("BTM_SecBond: already busy in state: %s",
+ btm_pair_state_descr(btm_cb.pairing_state));
+ return (BTM_WRONG_MODE);
+ }
+
+ p_dev_rec = btm_find_or_alloc_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ return (BTM_NO_RESOURCES);
+ }
+
+ if (!controller_get_interface()->get_is_ready()) {
+ BTM_TRACE_ERROR("%s controller module is not ready", __func__);
+ return (BTM_NO_RESOURCES);
+ }
+
+ BTM_TRACE_DEBUG("before update sec_flags=0x%x", p_dev_rec->sec_flags);
+
+ /* Finished if connection is active and already paired */
+ if (((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) &&
+ transport == BT_TRANSPORT_BR_EDR &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
+ ((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) &&
+ transport == BT_TRANSPORT_LE &&
+ (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))) {
+ BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
+ return (BTM_SUCCESS);
+ }
+
+ /* Tell controller to get rid of the link key if it has one stored */
+ if ((BTM_DeleteStoredLinkKey(bd_addr, NULL)) != BTM_SUCCESS)
+ return (BTM_NO_RESOURCES);
+
+ /* Save the PIN code if we got a valid one */
+ if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) {
+ btm_cb.pin_code_len = pin_len;
+ p_dev_rec->pin_code_length = pin_len;
+ memcpy(btm_cb.pin_code, p_pin, PIN_CODE_LEN);
+ }
+
+ memcpy(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
+
+ p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->is_originator = true;
+ if (trusted_mask)
+ BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
+
+ if (transport == BT_TRANSPORT_LE) {
+ btm_ble_init_pseudo_addr(p_dev_rec, bd_addr);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LE_MASK;
+
+ if (SMP_Pair(bd_addr) == SMP_STARTED) {
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ return BTM_CMD_STARTED;
+ }
+
+ btm_cb.pairing_flags = 0;
+ return (BTM_NO_RESOURCES);
+ }
+
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED |
+ BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
+
+ BTM_TRACE_DEBUG("after update sec_flags=0x%x", p_dev_rec->sec_flags);
+ if (!controller_get_interface()->supports_simple_pairing()) {
+ /* The special case when we authenticate keyboard. Set pin type to fixed */
+ /* It would be probably better to do it from the application, but it is */
+ /* complicated */
+ if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
+ BTM_COD_MAJOR_PERIPHERAL) &&
+ (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) &&
+ (btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {
+ btm_cb.pin_type_changed = true;
+ btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);
+ }
+ }
+
+ for (ii = 0; ii <= HCI_EXT_FEATURES_PAGE_MAX; ii++) {
+ p_features = p_dev_rec->feature_pages[ii];
+ BTM_TRACE_EVENT(" remote_features page[%1d] = %02x-%02x-%02x-%02x", ii,
+ p_features[0], p_features[1], p_features[2], p_features[3]);
+ BTM_TRACE_EVENT(" %02x-%02x-%02x-%02x",
+ p_features[4], p_features[5], p_features[6], p_features[7]);
+ }
+
+ BTM_TRACE_EVENT("BTM_SecBond: Remote sm4: 0x%x HCI Handle: 0x%04x",
+ p_dev_rec->sm4, p_dev_rec->hci_handle);
+
+#if (BTM_SEC_FORCE_RNR_FOR_DBOND == TRUE)
+ p_dev_rec->sec_flags &= ~BTM_SEC_NAME_KNOWN;
+#endif
+
+ /* If connection already exists... */
+ if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) {
+ btm_sec_start_authentication(p_dev_rec);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+ /* Mark lcb as bonding */
+ l2cu_update_lcb_4_bonding(bd_addr, true);
+ return (BTM_CMD_STARTED);
+ }
+
+ BTM_TRACE_DEBUG("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
+ if (!controller_get_interface()->supports_simple_pairing() ||
+ (p_dev_rec->sm4 == BTM_SM4_KNOWN)) {
+ if (btm_sec_check_prefetch_pin(p_dev_rec)) return (BTM_CMD_STARTED);
+ }
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* local is 2.1 and peer is unknown */
+ if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) {
+ /* we are not accepting connection request from peer
+ * -> RNR (to learn if peer is 2.1)
+ * RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
+ status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
+ } else {
+ /* We are accepting connection request from peer */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+ status = BTM_CMD_STARTED;
+ }
+ BTM_TRACE_DEBUG("State:%s sm4: 0x%x sec_state:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), p_dev_rec->sm4,
+ p_dev_rec->sec_state);
+ } else {
+ /* both local and peer are 2.1 */
+ status = btm_sec_dd_create_conn(p_dev_rec);
+ }
+
+ if (status != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR(
+ "%s BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x",
+ __func__, (int)status);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBondByTransport
+ *
+ * Description This function is called to perform bonding with peer device.
+ * If the connection is already up, but not secure, pairing
+ * is attempted. If already paired BTM_SUCCESS is returned.
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * transport - doing SSP over BR/EDR or SMP over LE
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ * Note: After 2.1 parameters are not used and preserved here not to change API
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondByTransport(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ uint8_t pin_len, uint8_t* p_pin,
+ uint32_t trusted_mask[]) {
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
+ /* LE device, do SMP pairing */
+ if ((transport == BT_TRANSPORT_LE && (dev_type & BT_DEVICE_TYPE_BLE) == 0) ||
+ (transport == BT_TRANSPORT_BR_EDR &&
+ (dev_type & BT_DEVICE_TYPE_BREDR) == 0)) {
+ return BTM_ILLEGAL_ACTION;
+ }
+ return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin,
+ trusted_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBond
+ *
+ * Description This function is called to perform bonding with peer device.
+ * If the connection is already up, but not secure, pairing
+ * is attempted. If already paired BTM_SUCCESS is returned.
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ * Note: After 2.1 parameters are not used and preserved here not to change API
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBond(BD_ADDR bd_addr, uint8_t pin_len, uint8_t* p_pin,
+ uint32_t trusted_mask[]) {
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+ if (BTM_UseLeLink(bd_addr)) transport = BT_TRANSPORT_LE;
+ return btm_sec_bond_by_transport(bd_addr, transport, pin_len, p_pin,
+ trusted_mask);
+}
+/*******************************************************************************
+ *
+ * Function BTM_SecBondCancel
+ *
+ * Description This function is called to cancel ongoing bonding process
+ * with peer device.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - false for BR/EDR link; true for LE link
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_API("BTM_SecBondCancel() State: %s flags:0x%x",
+ btm_pair_state_descr(btm_cb.pairing_state),
+ btm_cb.pairing_flags);
+ p_dev_rec = btm_find_dev(bd_addr);
+ if ((p_dev_rec == NULL) ||
+ (memcmp(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0)) {
+ return BTM_UNKNOWN_ADDR;
+ }
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_LE_ACTIVE) {
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ BTM_TRACE_DEBUG("Cancel LE pairing");
+ if (SMP_PairCancel(bd_addr)) {
+ return BTM_CMD_STARTED;
+ }
+ }
+ return BTM_WRONG_MODE;
+ }
+
+ BTM_TRACE_DEBUG("hci_handle:0x%x sec_state:%d", p_dev_rec->hci_handle,
+ p_dev_rec->sec_state);
+ if (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) {
+ /* pre-fetching pin for dedicated bonding */
+ btm_sec_bond_cancel_complete();
+ return BTM_SUCCESS;
+ }
+
+ /* If this BDA is in a bonding procedure */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* If the HCI link is up */
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) {
+ /* If some other thread disconnecting, we do not send second command */
+ if ((p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING) ||
+ (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH))
+ return (BTM_CMD_STARTED);
+
+ /* If the HCI link was set up by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)
+ return btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER,
+ p_dev_rec->hci_handle);
+ else
+ l2cu_update_lcb_4_bonding(bd_addr, false);
+
+ return BTM_NOT_AUTHORIZED;
+ } else /*HCI link is not up */
+ {
+ /* If the HCI link creation was started by Bonding process */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
+ btsnd_hcic_create_conn_cancel(bd_addr);
+ return BTM_CMD_STARTED;
+ }
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) {
+ BTM_CancelRemoteDeviceName();
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_WE_CANCEL_DD;
+ return BTM_CMD_STARTED;
+ }
+ return BTM_NOT_AUTHORIZED;
+ }
+ }
+
+ return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKey
+ *
+ * Description This function is called to obtain link key for the device
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Parameters: bd_addr - Address of the device
+ * link_key - Link Key is copied into this array
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey(BD_ADDR bd_addr, LINK_KEY link_key) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ p_dev_rec = btm_find_dev(bd_addr);
+ if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ memcpy(link_key, p_dev_rec->link_key, LINK_KEY_LEN);
+ return (BTM_SUCCESS);
+ }
+ return (BTM_UNKNOWN_ADDR);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKeyType
+ *
+ * Description This function is called to obtain link key type for the
+ * device.
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type
+ * otherwise.
+ *
+ ******************************************************************************/
+tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if ((p_dev_rec != NULL) && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ return p_dev_rec->link_key_type;
+ }
+ return BTM_LKEY_TYPE_IGNORE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEncryption
+ *
+ * Description This function is called to ensure that connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - Link transport
+ * p_callback - Pointer to callback function called if
+ * this function returns PENDING after required
+ * procedures are completed. Can be set to
+ * NULL if status is not desired.
+ * p_ref_data - pointer to any data the caller wishes to
+ * receive in the callback function upon
+ * completion. can be set to NULL if not used.
+ * sec_act - LE security action, unused for BR/EDR
+ *
+ * Returns BTM_SUCCESS - already encrypted
+ * BTM_PENDING - command will be returned in the callback
+ * BTM_WRONG_MODE- connection not up.
+ * BTM_BUSY - security procedures are currently active
+ * BTM_MODE_UNSUPPORTED - if security manager not linked in.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEncryption(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ tBTM_SEC_CBACK* p_callback, void* p_ref_data,
+ tBTM_BLE_SEC_ACT sec_act) {
+ tBTM_STATUS rc = 0;
+
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (!p_dev_rec || (transport == BT_TRANSPORT_BR_EDR &&
+ p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) ||
+ (transport == BT_TRANSPORT_LE &&
+ p_dev_rec->ble_hci_handle == BTM_SEC_INVALID_HANDLE)) {
+ /* Connection should be up and runnning */
+ BTM_TRACE_WARNING("Security Manager: BTM_SetEncryption not connected");
+
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_WRONG_MODE);
+
+ return (BTM_WRONG_MODE);
+ }
+
+ if (transport == BT_TRANSPORT_BR_EDR &&
+ (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED)) {
+ BTM_TRACE_EVENT("Security Manager: BTM_SetEncryption already encrypted");
+
+ if (p_callback) (*p_callback)(bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+
+ /* enqueue security request if security is active */
+ if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) {
+ BTM_TRACE_WARNING(
+ "Security Manager: BTM_SetEncryption busy, enqueue request");
+
+ if (btm_sec_queue_encrypt_request(bd_addr, transport, p_callback,
+ p_ref_data, sec_act)) {
+ return BTM_CMD_STARTED;
+ } else {
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_NO_RESOURCES);
+ return BTM_NO_RESOURCES;
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->security_required |=
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ p_dev_rec->is_originator = false;
+
+ BTM_TRACE_API(
+ "Security Manager: BTM_SetEncryption Handle:%d State:%d Flags:0x%x "
+ "Required:0x%x",
+ p_dev_rec->hci_handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required);
+
+ if (transport == BT_TRANSPORT_LE) {
+ tACL_CONN* p = btm_bda_to_acl(bd_addr, transport);
+ if (p) {
+ rc = btm_ble_set_encryption(bd_addr, sec_act, p->link_role);
+ } else {
+ rc = BTM_WRONG_MODE;
+ BTM_TRACE_WARNING("%s: cannot call btm_ble_set_encryption, p is NULL",
+ __func__);
+ }
+ } else {
+ rc = btm_sec_execute_procedure(p_dev_rec);
+ }
+
+ if (rc != BTM_CMD_STARTED && rc != BTM_BUSY) {
+ if (p_callback) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback)(bd_addr, transport, p_dev_rec->p_ref_data, rc);
+ }
+ }
+
+ return (rc);
+}
+
+/*******************************************************************************
+ * disconnect the ACL link, if it's not done yet.
+ ******************************************************************************/
+static tBTM_STATUS btm_sec_send_hci_disconnect(tBTM_SEC_DEV_REC* p_dev_rec,
+ uint8_t reason,
+ uint16_t conn_handle) {
+ uint8_t old_state = p_dev_rec->sec_state;
+ tBTM_STATUS status = BTM_CMD_STARTED;
+
+ BTM_TRACE_EVENT("btm_sec_send_hci_disconnect: handle:0x%x, reason=0x%x",
+ conn_handle, reason);
+
+ /* send HCI_Disconnect on a transport only once */
+ switch (old_state) {
+ case BTM_SEC_STATE_DISCONNECTING:
+ if (conn_handle == p_dev_rec->hci_handle) return status;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+ break;
+
+ case BTM_SEC_STATE_DISCONNECTING_BLE:
+ if (conn_handle == p_dev_rec->ble_hci_handle) return status;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_DISCONNECTING_BOTH;
+ break;
+
+ case BTM_SEC_STATE_DISCONNECTING_BOTH:
+ return status;
+
+ default:
+ p_dev_rec->sec_state = (conn_handle == p_dev_rec->hci_handle)
+ ? BTM_SEC_STATE_DISCONNECTING
+ : BTM_SEC_STATE_DISCONNECTING_BLE;
+
+ break;
+ }
+
+ /* If a role switch is in progress, delay the HCI Disconnect to avoid
+ * controller problem */
+ if (p_dev_rec->rs_disc_pending == BTM_SEC_RS_PENDING &&
+ p_dev_rec->hci_handle == conn_handle) {
+ BTM_TRACE_DEBUG(
+ "RS in progress - Set DISC Pending flag in btm_sec_send_hci_disconnect "
+ "to delay disconnect");
+ p_dev_rec->rs_disc_pending = BTM_SEC_DISC_PENDING;
+ status = BTM_SUCCESS;
+ }
+ /* Tear down the HCI link */
+ else {
+ btsnd_hcic_disconnect(conn_handle, reason);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ConfirmReqReply
+ *
+ * Description This function is called to confirm the numeric value for
+ * Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if
+ * success
+ * bd_addr - Address of the peer device
+ *
+ ******************************************************************************/
+void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ BTM_TRACE_EVENT("BTM_ConfirmReqReply() State: %s Res: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM) ||
+ (memcmp(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0))
+ return;
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if ((res == BTM_SUCCESS) || (res == BTM_SUCCESS_NO_SECURITY)) {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+
+ if (res == BTM_SUCCESS) {
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_AUTHED;
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+ }
+
+ btsnd_hcic_user_conf_reply(bd_addr, true);
+ } else {
+ /* Report authentication failed event from state
+ * BTM_PAIR_STATE_WAIT_AUTH_COMPLETE */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_conf_reply(bd_addr, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_PasskeyReqReply
+ *
+ * Description This function is called to provide the passkey for
+ * Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if success
+ * bd_addr - Address of the peer device
+ * passkey - numeric value in the range of
+ * BTM_MIN_PASSKEY_VAL(0) -
+ * BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr, uint32_t passkey) {
+ BTM_TRACE_API("BTM_PasskeyReqReply: State: %s res:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ if ((btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) ||
+ (memcmp(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0)) {
+ return;
+ }
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) &&
+ (res != BTM_SUCCESS)) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) {
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_AUTH_FAILURE,
+ p_dev_rec->hci_handle);
+ else
+ BTM_SecBondCancel(bd_addr);
+
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_LINK_KEY_KNOWN);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ return;
+ }
+ } else if (btm_cb.pairing_state != BTM_PAIR_STATE_KEY_ENTRY)
+ return;
+
+ if (passkey > BTM_MAX_PASSKEY_VAL) res = BTM_ILLEGAL_VALUE;
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed
+ * event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_user_passkey_neg_reply(bd_addr);
+ } else {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_user_passkey_reply(bd_addr, passkey);
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function BTM_SendKeypressNotif
+ *
+ * Description This function is used during the passkey entry model
+ * by a device with KeyboardOnly IO capabilities
+ * (very likely to be a HID Device).
+ * It is called by a HID Device to inform the remote device
+ * when a key has been entered or erased.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * type - notification type
+ *
+ ******************************************************************************/
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type) {
+ /* This API only make sense between PASSKEY_REQ and SP complete */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_KEY_ENTRY)
+ btsnd_hcic_send_keypress_notif(bd_addr, type);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function BTM_IoCapRsp
+ *
+ * Description This function is called in response to BTM_SP_IO_REQ_EVT
+ * When the event data io_req.oob_data is set to
+ * BTM_OOB_UNKNOWN by the tBTM_SP_CALLBACK implementation,
+ * this function is called to provide the actual response
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * io_cap - The IO capability of local device.
+ * oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+ * auth_req- MITM protection required or not.
+ *
+ ******************************************************************************/
+void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob,
+ tBTM_AUTH_REQ auth_req) {
+ BTM_TRACE_EVENT("BTM_IoCapRsp: state: %s oob: %d io_cap: %d",
+ btm_pair_state_descr(btm_cb.pairing_state), oob, io_cap);
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS) ||
+ (memcmp(btm_cb.pairing_bda, bd_addr, BD_ADDR_LEN) != 0))
+ return;
+
+ if (oob < BTM_OOB_UNKNOWN && io_cap < BTM_IO_CAP_MAX) {
+ btm_cb.devcb.loc_auth_req = auth_req;
+ btm_cb.devcb.loc_io_caps = io_cap;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ auth_req = (BTM_AUTH_DD_BOND | (auth_req & BTM_AUTH_YN_BIT));
+
+ btsnd_hcic_io_cap_req_reply(bd_addr, io_cap, oob, auth_req);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalOobData
+ *
+ * Description This function is called to read the local OOB data from
+ * LM
+ *
+ ******************************************************************************/
+void BTM_ReadLocalOobData(void) { btsnd_hcic_read_local_oob_data(); }
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoteOobDataReply
+ *
+ * Description This function is called to provide the remote OOB data for
+ * Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr, BT_OCTET16 c,
+ BT_OCTET16 r) {
+ BTM_TRACE_EVENT("%s() - State: %s res: %d", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state), res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP) return;
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+
+ if (res != BTM_SUCCESS) {
+ /* use BTM_PAIR_STATE_WAIT_AUTH_COMPLETE to report authentication failed
+ * event */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply(bd_addr);
+ } else {
+ btm_cb.acl_disc_reason = HCI_SUCCESS;
+ btsnd_hcic_rem_oob_reply(bd_addr, c, r);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BuildOobData
+ *
+ * Description This function is called to build the OOB data payload to
+ * be sent over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * max_len - p_data size.
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ * name_len- 0, local device name would not be included.
+ * otherwise, the local device name is included for
+ * up to this specified length
+ *
+ * Returns Number of bytes in p_data.
+ *
+ ******************************************************************************/
+uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, BT_OCTET16 c,
+ BT_OCTET16 r, uint8_t name_len) {
+ uint8_t* p = p_data;
+ uint16_t len = 0;
+ uint16_t name_size;
+ uint8_t name_type = BTM_EIR_SHORTENED_LOCAL_NAME_TYPE;
+
+ if (p_data && max_len >= BTM_OOB_MANDATORY_SIZE) {
+ /* add mandatory part */
+ UINT16_TO_STREAM(p, len);
+ BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address);
+
+ len = BTM_OOB_MANDATORY_SIZE;
+ max_len -= len;
+
+ /* now optional part */
+
+ /* add Hash C */
+ uint16_t delta = BTM_OOB_HASH_C_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_HASH_C_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_HASH_C_TYPE;
+ ARRAY_TO_STREAM(p, c, BTM_OOB_HASH_C_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add Rand R */
+ delta = BTM_OOB_RAND_R_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_RAND_R_SIZE + 1;
+ *p++ = BTM_EIR_OOB_SSP_RAND_R_TYPE;
+ ARRAY_TO_STREAM(p, r, BTM_OOB_RAND_R_SIZE);
+ len += delta;
+ max_len -= delta;
+ }
+
+ /* add class of device */
+ delta = BTM_OOB_COD_SIZE + 2;
+ if (max_len >= delta) {
+ *p++ = BTM_OOB_COD_SIZE + 1;
+ *p++ = BTM_EIR_OOB_COD_TYPE;
+ DEVCLASS_TO_STREAM(p, btm_cb.devcb.dev_class);
+ len += delta;
+ max_len -= delta;
+ }
+ name_size = name_len;
+ if (name_size > strlen(btm_cb.cfg.bd_name)) {
+ name_type = BTM_EIR_COMPLETE_LOCAL_NAME_TYPE;
+ name_size = (uint16_t)strlen(btm_cb.cfg.bd_name);
+ }
+ delta = name_size + 2;
+ if (max_len >= delta) {
+ *p++ = name_size + 1;
+ *p++ = name_type;
+ ARRAY_TO_STREAM(p, btm_cb.cfg.bd_name, name_size);
+ len += delta;
+ max_len -= delta;
+ }
+ /* update len */
+ p = p_data;
+ UINT16_TO_STREAM(p, len);
+ }
+ return len;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BothEndsSupportSecureConnections
+ *
+ * Description This function is called to check if both the local device
+ * and the peer device specified by bd_addr support BR/EDR
+ * Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by both
+ * local and the remote device, else false.
+ *
+ ******************************************************************************/
+bool BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr) {
+ return ((controller_get_interface()->supports_secure_connections()) &&
+ (BTM_PeerSupportsSecureConnections(bd_addr)));
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_PeerSupportsSecureConnections
+ *
+ * Description This function is called to check if the peer supports
+ * BR/EDR Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by the peer,
+ * else false.
+ *
+ ******************************************************************************/
+bool BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_WARNING("%s: unknown BDA: %08x%04x", __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) +
+ (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return false;
+ }
+
+ return (p_dev_rec->remote_supports_secure_connections);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadOobData
+ *
+ * Description This function is called to parse the OOB data payload
+ * received over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * eir_tag - The associated EIR tag to read the data.
+ * *p_len(output) - the length of the data with the given tag.
+ *
+ * Returns the beginning of the data with the given tag.
+ * NULL, if the tag is not found.
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadOobData(uint8_t* p_data, uint8_t eir_tag, uint8_t* p_len) {
+ uint8_t* p = p_data;
+ uint16_t max_len;
+ uint8_t len, type;
+ uint8_t* p_ret = NULL;
+ uint8_t ret_len = 0;
+
+ if (p_data) {
+ STREAM_TO_UINT16(max_len, p);
+ if (max_len >= BTM_OOB_MANDATORY_SIZE) {
+ if (BTM_EIR_OOB_BD_ADDR_TYPE == eir_tag) {
+ p_ret = p; /* the location for bd_addr */
+ ret_len = BTM_OOB_BD_ADDR_SIZE;
+ } else {
+ p += BD_ADDR_LEN;
+ max_len -= BTM_OOB_MANDATORY_SIZE;
+ /* now the optional data in EIR format */
+ while (max_len > 0) {
+ len = *p++; /* tag data len + 1 */
+ type = *p++;
+ if (eir_tag == type) {
+ p_ret = p;
+ ret_len = len - 1;
+ break;
+ }
+ /* the data size of this tag is len + 1 (tag data len + 2) */
+ if (max_len > len) {
+ max_len -= len;
+ max_len--;
+ len--;
+ p += len;
+ } else
+ max_len = 0;
+ }
+ }
+ }
+ }
+
+ if (p_len) *p_len = ret_len;
+
+ return p_ret;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetOutService
+ *
+ * Description This function is called to set the service for
+ * outgoing connections.
+ *
+ * If the profile/application calls BTM_SetSecurityLevel
+ * before initiating a connection, this function does not
+ * need to be called.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetOutService(BD_ADDR bd_addr, uint8_t service_id,
+ uint32_t mx_chan_id) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0];
+
+ btm_cb.p_out_serv = p_serv_rec;
+ p_dev_rec = btm_find_dev(bd_addr);
+
+ for (int i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) &&
+ (p_serv_rec->service_id == service_id) &&
+ (p_serv_rec->orig_mx_chan_id == mx_chan_id)) {
+ BTM_TRACE_API(
+ "BTM_SetOutService p_out_serv id %d, psm 0x%04x, proto_id %d, "
+ "chan_id %d",
+ p_serv_rec->service_id, p_serv_rec->psm, p_serv_rec->mx_proto_id,
+ p_serv_rec->orig_mx_chan_id);
+ btm_cb.p_out_serv = p_serv_rec;
+ if (p_dev_rec) p_dev_rec->p_cur_service = p_serv_rec;
+ break;
+ }
+ }
+}
+
+/************************************************************************
+ * I N T E R N A L F U N C T I O N S
+ ************************************************************************/
+/*******************************************************************************
+ *
+ * Function btm_sec_is_upgrade_possible
+ *
+ * Description This function returns true if the existing link key
+ * can be upgraded or if the link key does not exist.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+static bool btm_sec_is_upgrade_possible(tBTM_SEC_DEV_REC* p_dev_rec,
+ bool is_originator) {
+ uint16_t mtm_check = is_originator ? BTM_SEC_OUT_MITM : BTM_SEC_IN_MITM;
+ bool is_possible = true;
+
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) {
+ is_possible = false;
+ if (p_dev_rec->p_cur_service) {
+ BTM_TRACE_DEBUG(
+ "%s() id: %d, link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x, "
+ "flags: 0x%x",
+ __func__, p_dev_rec->p_cur_service->service_id,
+ p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check,
+ p_dev_rec->p_cur_service->security_flags);
+ } else {
+ BTM_TRACE_DEBUG(
+ "%s() link_key_typet: %d, rmt_io_caps: %d, chk flags: 0x%x", __func__,
+ p_dev_rec->link_key_type, p_dev_rec->rmt_io_caps, mtm_check);
+ }
+ /* Already have a link key to the connected peer. Is the link key secure
+ *enough?
+ ** Is a link key upgrade even possible?
+ */
+ if ((p_dev_rec->security_required & mtm_check) /* needs MITM */
+ && ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB) ||
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256))
+ /* has unauthenticated
+ link key */
+ && (p_dev_rec->rmt_io_caps < BTM_IO_CAP_MAX) /* a valid peer IO cap */
+ && (btm_sec_io_map[p_dev_rec->rmt_io_caps][btm_cb.devcb.loc_io_caps]))
+ /* authenticated
+ link key is possible */
+ {
+ /* upgrade is possible: check if the application wants the upgrade.
+ * If the application is configured to use a global MITM flag,
+ * it probably would not want to upgrade the link key based on the
+ * security level database */
+ is_possible = true;
+ }
+ }
+ BTM_TRACE_DEBUG("%s() is_possible: %d sec_flags: 0x%x", __func__, is_possible,
+ p_dev_rec->sec_flags);
+ return is_possible;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_check_upgrade
+ *
+ * Description This function is called to check if the existing link key
+ * needs to be upgraded.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_sec_check_upgrade(tBTM_SEC_DEV_REC* p_dev_rec,
+ bool is_originator) {
+ BTM_TRACE_DEBUG("%s()", __func__);
+
+ /* Only check if link key already exists */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) return;
+
+ if (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == true) {
+ BTM_TRACE_DEBUG("need upgrade!! sec_flags:0x%x", p_dev_rec->sec_flags);
+ /* upgrade is possible: check if the application wants the upgrade.
+ * If the application is configured to use a global MITM flag,
+ * it probably would not want to upgrade the link key based on the security
+ * level database */
+ tBTM_SP_UPGRADE evt_data;
+ memcpy(evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ evt_data.upgrade = true;
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback)(BTM_SP_UPGRADE_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+
+ BTM_TRACE_DEBUG("evt_data.upgrade:0x%x", evt_data.upgrade);
+ if (evt_data.upgrade) {
+ /* if the application confirms the upgrade, set the upgrade bit */
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+
+ /* Clear the link key known to go through authentication/pairing again */
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED);
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHENTICATED;
+ BTM_TRACE_DEBUG("sec_flags:0x%x", p_dev_rec->sec_flags);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_l2cap_access_req
+ *
+ * Description This function is called by the L2CAP to grant permission to
+ * establish L2CAP connection to or from the peer device.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * psm - L2CAP PSM
+ * is_originator - true if protocol above L2CAP originates
+ * connection
+ * p_callback - Pointer to callback function called if
+ * this function returns PENDING after required
+ * procedures are complete. MUST NOT BE NULL.
+ *
+ * Returns tBTM_STATUS
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_sec_l2cap_access_req(BD_ADDR bd_addr, uint16_t psm,
+ uint16_t handle, CONNECTION_TYPE conn_type,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_SEC_SERV_REC* p_serv_rec;
+ uint16_t security_required;
+ uint16_t old_security_required;
+ bool old_is_originator;
+ tBTM_STATUS rc = BTM_SUCCESS;
+ bool chk_acp_auth_done = false;
+ bool is_originator;
+ tBT_TRANSPORT transport =
+ BT_TRANSPORT_BR_EDR; /* should check PSM range in LE connection oriented
+ L2CAP connection */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = true;
+ else
+ is_originator = false;
+
+ BTM_TRACE_DEBUG("%s() conn_type: 0x%x, 0x%x", __func__, conn_type,
+ p_ref_data);
+#else
+ is_originator = conn_type;
+
+ BTM_TRACE_DEBUG("%s() is_originator:%d, 0x%x", __func__, is_originator,
+ p_ref_data);
+#endif
+
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev(bd_addr);
+
+ p_dev_rec->hci_handle = handle;
+
+ /* Find the service record for the PSM */
+ p_serv_rec = btm_sec_find_first_serv(conn_type, psm);
+
+ /* If there is no application registered with this PSM do not allow connection
+ */
+ if (!p_serv_rec) {
+ BTM_TRACE_WARNING("%s() PSM: %d no application registerd", __func__, psm);
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+ return (BTM_MODE_UNSUPPORTED);
+ }
+
+ /* Services level0 by default have no security */
+ if ((btm_sec_is_serv_level0(psm)) &&
+ (!btm_cb.devcb.secure_connections_only)) {
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_SUCCESS_NO_SECURITY);
+ return (BTM_SUCCESS);
+ }
+
+/** M: disable security check for IOT device @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ //Some device reconnect with no authentication action. Do not check their security and use
+ //them as normal for temporary.
+ if(!is_originator && interop_mtk_match_addr(INTEROP_MTK_DISABLE_SERVICE_SECURITY_CHECK,
+ (const bt_bdaddr_t*)bd_addr))
+ {
+ if(p_callback)
+ {
+ (*p_callback)(bd_addr,transport,p_ref_data,BTM_SUCCESS);
+ return(BTM_SUCCESS);
+ }
+ }
+#endif
+/** @} */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_CONNLESS_MASK) {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ security_required = btm_sec_set_serv_level4_flags(
+ p_serv_rec->ucd_security_flags, is_originator);
+ } else {
+ security_required = p_serv_rec->ucd_security_flags;
+ }
+
+ rc = BTM_CMD_STARTED;
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ BTM_SEC_OUT_AUTHENTICATE) &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) &&
+ (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)))) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) ==
+ BTM_SEC_IN_AUTHENTICATE) &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) &&
+ (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED)))) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) ==
+ BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
+ btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+
+ if (rc == BTM_SUCCESS) {
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, (void*)p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+ } else
+#endif
+ {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ security_required = btm_sec_set_serv_level4_flags(
+ p_serv_rec->security_flags, is_originator);
+ } else {
+ security_required = p_serv_rec->security_flags;
+ }
+ }
+
+ BTM_TRACE_DEBUG(
+ "%s: security_required 0x%04x, is_originator 0x%02x, psm 0x%04x",
+ __func__, security_required, is_originator, psm);
+
+ if ((!is_originator) && (security_required & BTM_SEC_MODE4_LEVEL4)) {
+ bool local_supports_sc =
+ controller_get_interface()->supports_secure_connections();
+ /* acceptor receives L2CAP Channel Connect Request for Secure Connections
+ * Only service */
+ if (!(local_supports_sc) ||
+ !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d",
+ "rmt_support_for_sc : %d -> fail pairing", __func__,
+ local_supports_sc,
+ p_dev_rec->remote_supports_secure_connections);
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, (void*)p_ref_data,
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+
+ return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+ }
+
+ /* there are some devices (moto KRZR) which connects to several services at
+ * the same time */
+ /* we will process one after another */
+ if ((p_dev_rec->p_callback) ||
+ (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)) {
+ BTM_TRACE_EVENT("%s() - busy - PSM:%d delayed state: %s mode:%d, sm4:0x%x",
+ __func__, psm, btm_pair_state_descr(btm_cb.pairing_state),
+ btm_cb.security_mode, p_dev_rec->sm4);
+ BTM_TRACE_EVENT("security_flags:x%x, sec_flags:x%x", security_required,
+ p_dev_rec->sec_flags);
+ rc = BTM_CMD_STARTED;
+ if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ (BTM_SM4_KNOWN == p_dev_rec->sm4) ||
+ (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+ (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false))) {
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy
+ * or SM4 with no possibility of link key upgrade */
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ BTM_SEC_OUT_AUTHENTICATE) &&
+ btm_dev_authenticated(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) &&
+ btm_dev_encrypted(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) == BTM_SEC_OUT_FLAGS) &&
+ btm_dev_authorized(p_dev_rec) && btm_dev_encrypted(p_dev_rec)))) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ BTM_SEC_IN_AUTHENTICATE) &&
+ btm_dev_authenticated(p_dev_rec)) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) &&
+ btm_dev_encrypted(p_dev_rec)) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) &&
+ (btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_AUTHORIZE)) &&
+ ((btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec)) &&
+ btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHORIZE)) &&
+ ((btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec)) &&
+ btm_dev_encrypted(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_FLAGS) &&
+ btm_dev_encrypted(p_dev_rec) &&
+ (btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec)))) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) ==
+ BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
+ btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+
+ if (rc == BTM_SUCCESS) {
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, (void*)p_ref_data, BTM_SUCCESS);
+ return (BTM_SUCCESS);
+ }
+ }
+
+ btm_cb.sec_req_pending = true;
+ return (BTM_CMD_STARTED);
+ }
+
+ /* Save pointer to service record */
+ p_dev_rec->p_cur_service = p_serv_rec;
+
+ /* Modify security_required in btm_sec_l2cap_access_req for Lisbon */
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if (is_originator) {
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+ } else /* acceptor */
+ {
+ /* SM4 to SM4: the acceptor needs to make sure the authentication is
+ * already done */
+ chk_acp_auth_done = true;
+ /* SM4 to SM4 -> always authenticate & encrypt */
+ security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+ }
+ } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) {
+ /* the remote features are not known yet */
+ BTM_TRACE_DEBUG("%s: (%s) remote features unknown!!sec_flags:0x%02x",
+ __func__, (is_originator) ? "initiator" : "acceptor",
+ p_dev_rec->sec_flags);
+
+ p_dev_rec->sm4 |= BTM_SM4_REQ_PEND;
+ return (BTM_CMD_STARTED);
+ }
+ }
+
+ BTM_TRACE_DEBUG(
+ "%s() sm4:0x%x, sec_flags:0x%x, security_required:0x%x chk:%d", __func__,
+ p_dev_rec->sm4, p_dev_rec->sec_flags, security_required,
+ chk_acp_auth_done);
+
+ old_security_required = p_dev_rec->security_required;
+ old_is_originator = p_dev_rec->is_originator;
+ p_dev_rec->security_required = security_required;
+ p_dev_rec->p_ref_data = p_ref_data;
+ p_dev_rec->is_originator = is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (conn_type & CONNECTION_TYPE_CONNLESS_MASK)
+ p_dev_rec->is_ucd = true;
+ else
+ p_dev_rec->is_ucd = false;
+#endif
+
+/* If there are multiple service records used through the same PSM */
+/* leave security decision for the multiplexor on the top */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (((btm_sec_find_next_serv(p_serv_rec)) != NULL) &&
+ (!(conn_type & CONNECTION_TYPE_CONNLESS_MASK))) /* if not UCD */
+#else
+ if ((btm_sec_find_next_serv(p_serv_rec)) != NULL)
+#endif
+ {
+ BTM_TRACE_DEBUG("no next_serv sm4:0x%x, chk:%d", p_dev_rec->sm4,
+ chk_acp_auth_done);
+ if (!BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ BTM_TRACE_EVENT(
+ "Security Manager: l2cap_access_req PSM:%d postponed for multiplexer",
+ psm);
+ /* pre-Lisbon: restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+ }
+
+ /* if the originator is using dynamic PSM in legacy mode, do not start any
+ * security process now
+ * The layer above L2CAP needs to carry out the security requirement after
+ * L2CAP connect
+ * response is received */
+ if (is_originator && ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ !BTM_SEC_IS_SM4(p_dev_rec->sm4)) &&
+ (psm >= 0x1001)) {
+ BTM_TRACE_EVENT(
+ "dynamic PSM:0x%x in legacy mode - postponed for upper layer", psm);
+ /* restore the old settings */
+ p_dev_rec->security_required = old_security_required;
+ p_dev_rec->is_originator = old_is_originator;
+
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_SUCCESS);
+
+ return (BTM_SUCCESS);
+ }
+
+ if (chk_acp_auth_done) {
+ BTM_TRACE_DEBUG(
+ "(SM4 to SM4) btm_sec_l2cap_access_req rspd. authenticated: x%x, enc: "
+ "x%x",
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED),
+ (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED));
+ /* SM4, but we do not know for sure which level of security we need.
+ * as long as we have a link key, it's OK */
+ if ((0 == (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
+ (0 == (p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED))) {
+ rc = BTM_DELAY_CHECK;
+ /*
+ 2046 may report HCI_Encryption_Change and L2C Connection Request out of
+ sequence
+ because of data path issues. Delay this disconnect a little bit
+ */
+ LOG_INFO(
+ LOG_TAG,
+ "%s peer should have initiated security process by now (SM4 to SM4)",
+ __func__);
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->sec_state = BTM_SEC_STATE_DELAY_FOR_ENC;
+ (*p_callback)(bd_addr, transport, p_ref_data, rc);
+
+ return BTM_SUCCESS;
+ }
+ }
+
+ p_dev_rec->p_callback = p_callback;
+
+ if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID ||
+ p_dev_rec->last_author_service_id !=
+ p_dev_rec->p_cur_service->service_id) {
+ /* Although authentication and encryption are per connection
+ ** authorization is per access request. For example when serial connection
+ ** is up and authorized and client requests to read file (access to other
+ ** scn), we need to request user's permission again.
+ */
+ p_dev_rec->sec_flags &= ~BTM_SEC_AUTHORIZED;
+ }
+
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case
+ */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) {
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+ }
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+ BTM_SEC_AUTHENTICATED);
+ BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags);
+ } else {
+ /* If we already have a link key to the connected peer, is it secure
+ * enough? */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+ }
+
+ BTM_TRACE_EVENT(
+ "%s() PSM:%d Handle:%d State:%d Flags: 0x%x Required: 0x%x Service ID:%d",
+ __func__, psm, handle, p_dev_rec->sec_state, p_dev_rec->sec_flags,
+ p_dev_rec->security_required, p_dev_rec->p_cur_service->service_id);
+
+ rc = btm_sec_execute_procedure(p_dev_rec);
+ if (rc != BTM_CMD_STARTED) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback)(bd_addr, transport, p_dev_rec->p_ref_data, (uint8_t)rc);
+ }
+
+ return (rc);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_mx_access_request
+ *
+ * Description This function is called by all Multiplexing Protocols during
+ * establishing connection to or from peer device to grant
+ * permission to establish application connection.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * psm - L2CAP PSM
+ * is_originator - true if protocol above L2CAP originates
+ * connection
+ * mx_proto_id - protocol ID of the multiplexer
+ * mx_chan_id - multiplexer channel to reach application
+ * p_callback - Pointer to callback function called if
+ * this function returns PENDING after required
+ * procedures are completed
+ * p_ref_data - Pointer to any reference data needed by the
+ * the callback function.
+ *
+ * Returns BTM_CMD_STARTED
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_sec_mx_access_request(BD_ADDR bd_addr, uint16_t psm,
+ bool is_originator, uint32_t mx_proto_id,
+ uint32_t mx_chan_id,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_SEC_SERV_REC* p_serv_rec;
+ tBTM_STATUS rc;
+ uint16_t security_required;
+ bool transport = false; /* should check PSM range in LE connection oriented
+ L2CAP connection */
+
+ BTM_TRACE_DEBUG("%s() is_originator: %d", __func__, is_originator);
+ /* Find or get oldest record */
+ p_dev_rec = btm_find_or_alloc_dev(bd_addr);
+
+ /* Find the service record for the PSM */
+ p_serv_rec =
+ btm_sec_find_mx_serv(is_originator, psm, mx_proto_id, mx_chan_id);
+
+ /* If there is no application registered with this PSM do not allow connection
+ */
+ if (!p_serv_rec) {
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, p_ref_data, BTM_MODE_UNSUPPORTED);
+
+ BTM_TRACE_ERROR(
+ "Security Manager: MX service not found PSM:%d Proto:%d SCN:%d", psm,
+ mx_proto_id, mx_chan_id);
+ return BTM_NO_RESOURCES;
+ }
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ (!btm_sec_is_serv_level0(psm))) {
+ security_required = btm_sec_set_serv_level4_flags(
+ p_serv_rec->security_flags, is_originator);
+ } else {
+ security_required = p_serv_rec->security_flags;
+ }
+
+ /* there are some devices (moto phone) which connects to several services at
+ * the same time */
+ /* we will process one after another */
+ if ((p_dev_rec->p_callback) ||
+ (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE)) {
+ BTM_TRACE_EVENT("%s() service PSM:%d Proto:%d SCN:%d delayed state: %s",
+ __func__, psm, mx_proto_id, mx_chan_id,
+ btm_pair_state_descr(btm_cb.pairing_state));
+
+ rc = BTM_CMD_STARTED;
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_UNDEFINED ||
+ btm_cb.security_mode == BTM_SEC_MODE_NONE ||
+ btm_cb.security_mode == BTM_SEC_MODE_SERVICE ||
+ btm_cb.security_mode == BTM_SEC_MODE_LINK) ||
+ (BTM_SM4_KNOWN == p_dev_rec->sm4) ||
+ (BTM_SEC_IS_SM4(p_dev_rec->sm4) &&
+ (btm_sec_is_upgrade_possible(p_dev_rec, is_originator) == false))) {
+ /* legacy mode - local is legacy or local is lisbon/peer is legacy
+ * or SM4 with no possibility of link key upgrade */
+ if (is_originator) {
+ if (((security_required & BTM_SEC_OUT_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ BTM_SEC_OUT_AUTHENTICATE) &&
+ btm_dev_authenticated(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_OUT_FLAGS) ==
+ (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) &&
+ btm_dev_encrypted(p_dev_rec)))) {
+ rc = BTM_SUCCESS;
+ }
+ } else {
+ if (((security_required & BTM_SEC_IN_FLAGS) == 0) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) ==
+ BTM_SEC_IN_AUTHENTICATE) &&
+ btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) == BTM_SEC_IN_AUTHORIZE) &&
+ (btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_AUTHENTICATE)) &&
+ ((btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec)) &&
+ btm_dev_authenticated(p_dev_rec))) ||
+ (((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHORIZE | BTM_SEC_IN_ENCRYPT)) &&
+ ((btm_dev_authorized(p_dev_rec) ||
+ btm_serv_trusted(p_dev_rec, p_serv_rec)) &&
+ btm_dev_encrypted(p_dev_rec))) ||
+ ((((security_required & BTM_SEC_IN_FLAGS) ==
+ (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) &&
+ btm_dev_encrypted(p_dev_rec)))) {
+ // Check for 16 digits (or MITM)
+ if (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) == 0) ||
+ (((security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) ==
+ BTM_SEC_IN_MIN_16_DIGIT_PIN) &&
+ btm_dev_16_digit_authenticated(p_dev_rec))) {
+ rc = BTM_SUCCESS;
+ }
+ }
+ }
+ if ((rc == BTM_SUCCESS) && (security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ rc = BTM_CMD_STARTED;
+ }
+ }
+
+ if (rc == BTM_SUCCESS) {
+ BTM_TRACE_EVENT("%s: allow to bypass, checking authorization", __func__);
+ /* the security in BTM_SEC_IN_FLAGS is fullfilled so far, check the
+ * requirements in */
+ /* btm_sec_execute_procedure */
+ if ((is_originator &&
+ (p_serv_rec->security_flags & BTM_SEC_OUT_AUTHORIZE)) ||
+ (!is_originator &&
+ (p_serv_rec->security_flags & BTM_SEC_IN_AUTHORIZE))) {
+ BTM_TRACE_EVENT("%s: still need authorization", __func__);
+ rc = BTM_CMD_STARTED;
+ }
+ }
+
+ /* Check whether there is a pending security procedure, if so we should
+ * always queue */
+ /* the new security request */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE) {
+ BTM_TRACE_EVENT("%s: There is a pending security procedure", __func__);
+ rc = BTM_CMD_STARTED;
+ }
+ if (rc == BTM_CMD_STARTED) {
+ BTM_TRACE_EVENT("%s: call btm_sec_queue_mx_request", __func__);
+ btm_sec_queue_mx_request(bd_addr, psm, is_originator, mx_proto_id,
+ mx_chan_id, p_callback, p_ref_data);
+ } else /* rc == BTM_SUCCESS */
+ {
+ /* access granted */
+ if (p_callback) {
+ (*p_callback)(bd_addr, transport, p_ref_data, (uint8_t)rc);
+ }
+ }
+
+ BTM_TRACE_EVENT("%s: return with rc = 0x%02x in delayed state %s", __func__,
+ rc, btm_pair_state_descr(btm_cb.pairing_state));
+ return rc;
+ }
+
+ if ((!is_originator) && ((security_required & BTM_SEC_MODE4_LEVEL4) ||
+ (btm_cb.security_mode == BTM_SEC_MODE_SC))) {
+ bool local_supports_sc =
+ controller_get_interface()->supports_secure_connections();
+ /* acceptor receives service connection establishment Request for */
+ /* Secure Connections Only service */
+ if (!(local_supports_sc) ||
+ !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service,local_support_for_sc %d,",
+ "remote_support_for_sc %d: fail pairing", __func__,
+ local_supports_sc,
+ p_dev_rec->remote_supports_secure_connections);
+
+ if (p_callback)
+ (*p_callback)(bd_addr, transport, (void*)p_ref_data,
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+
+ return (BTM_MODE4_LEVEL4_NOT_SUPPORTED);
+ }
+ }
+
+ p_dev_rec->p_cur_service = p_serv_rec;
+ p_dev_rec->security_required = security_required;
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ /* BTM_LKEY_TYPE_AUTH_COMB_P_256 is the only acceptable key in this case
+ */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) != 0) {
+ p_dev_rec->sm4 |= BTM_SM4_UPGRADE;
+ }
+
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+ BTM_SEC_AUTHENTICATED);
+ BTM_TRACE_DEBUG("%s: sec_flags:0x%x", __func__, p_dev_rec->sec_flags);
+ } else {
+ /* If we already have a link key, check if that link key is good enough
+ */
+ btm_sec_check_upgrade(p_dev_rec, is_originator);
+ }
+ }
+ }
+
+ p_dev_rec->is_originator = is_originator;
+ p_dev_rec->p_callback = p_callback;
+ p_dev_rec->p_ref_data = p_ref_data;
+
+ /* Although authentication and encryption are per connection */
+ /* authorization is per access request. For example when serial connection */
+ /* is up and authorized and client requests to read file (access to other */
+ /* scn, we need to request user's permission again. */
+ p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED);
+
+ BTM_TRACE_EVENT(
+ "%s() proto_id:%d chan_id:%d State:%d Flags:0x%x Required:0x%x Service "
+ "ID:%d",
+ __func__, mx_proto_id, mx_chan_id, p_dev_rec->sec_state,
+ p_dev_rec->sec_flags, p_dev_rec->security_required,
+ p_dev_rec->p_cur_service->service_id);
+
+ rc = btm_sec_execute_procedure(p_dev_rec);
+ if (rc != BTM_CMD_STARTED) {
+ if (p_callback) {
+ p_dev_rec->p_callback = NULL;
+ (*p_callback)(bd_addr, transport, p_ref_data, (uint8_t)rc);
+ }
+ }
+
+ return rc;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_conn_req
+ *
+ * Description This function is when the peer device is requesting
+ * connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_conn_req(uint8_t* bda, uint8_t* dc) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+ int major_dev_class = 0;
+ int remote_a2dp_role = 0; //0: a2dp source; 1: a2dp sink
+ int connected_dev_a2dp_role = 0; // 0: no connect to any a2dp device; 1: connect source device; 2: connect sink device
+ int repeat_num = 0;
+
+ // is_switch_role[0] = '0' means no switch; is_switch_role[0] = '2' means switching role
+ char is_switch_role[PROPERTY_VALUE_MAX] = {0};
+#endif
+
+ /* Some device may request a connection before we are done with the HCI_Reset
+ * sequence */
+ if (!controller_get_interface()->get_is_ready()) {
+ BTM_TRACE_EVENT("Security Manager: connect request when device not ready");
+ btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+ // Get Major device class of Remote device
+ major_dev_class = device_class_get_major_device((const bt_device_class_t *) dc);
+ BTM_TRACE_EVENT("major class device:0x%x", major_dev_class);
+ if (major_dev_class == BTM_COD_MAJOR_AUDIO) {
+ BTM_TRACE_DEBUG("Remote is sink device");
+ remote_a2dp_role = 2;
+ } else if (major_dev_class == BTM_COD_MAJOR_PHONE) {
+ BTM_TRACE_DEBUG("Remote is source device");
+ remote_a2dp_role = 1;
+ }
+
+ osi_property_get("mtk.a2dp.changeRole", is_switch_role, "0");
+ BTM_TRACE_DEBUG("is switch role:%s", is_switch_role);
+
+ if (remote_a2dp_role != 0) {
+ // 1. check current enabled service
+ char a2dp_role[PROPERTY_VALUE_MAX] = {0};
+ osi_property_get("mtk.a2dp.role", a2dp_role, "0");
+ BTM_TRACE_DEBUG("current a2dp role:%s", a2dp_role);
+
+ // 2. Reject the connection request when swtiching a2dp service
+ if (is_switch_role[0] == '2') {
+ BTM_TRACE_EVENT("Security Manager: connect request when a2dp role switch");
+ btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ // 3. check if there is any a2dp link in-use
+ connected_dev_a2dp_role = l2c_link_check_a2dp_link(bda);
+
+ // 2. if the enabled service is the same as remote device role, switch it
+ if ((a2dp_role[0] == '1' && remote_a2dp_role == 1) ||
+ (a2dp_role[0] == '2' && remote_a2dp_role == 2)) {
+ if (connected_dev_a2dp_role == 0){ // No connect any a2dp device, Switch the service
+ if(osi_property_set("mtk.a2dp.changeRole", "1") < 0) {
+ BTM_TRACE_ERROR("Set swtich role property fail");
+ }
+ }
+
+ // we check total 6 (s)
+ for (repeat_num = 0; repeat_num < BTM_CHECK_ROLE_SWITCH_TIMES; repeat_num++) {
+ osi_property_get("mtk.a2dp.changeRole", is_switch_role, "0");
+ BTM_TRACE_DEBUG("Role swtich status:%s", is_switch_role);
+ usleep(100000);
+ if (is_switch_role[0] == '0') {
+ break;
+ }
+ }
+
+ // need to switch a2dp service to a2dp sink service
+ BTM_TRACE_EVENT("After role switch, new a2dp role:%s", a2dp_role);
+ }
+ }
+#endif
+
+ /* Security guys wants us not to allow connection from not paired devices */
+
+ /* Check if connection is allowed for only paired devices */
+ if (btm_cb.connect_only_paired) {
+ if (!p_dev_rec || !(p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) {
+ BTM_TRACE_EVENT(
+ "Security Manager: connect request from non-paired device");
+ btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+
+#if (BTM_ALLOW_CONN_IF_NONDISCOVER == FALSE)
+ /* If non-discoverable, only allow known devices to connect */
+ if (btm_cb.btm_inq_vars.discoverable_mode == BTM_NON_DISCOVERABLE) {
+ if (!p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "Security Manager: connect request from not paired device");
+ btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+ }
+#endif
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (!memcmp(btm_cb.pairing_bda, bda, BD_ADDR_LEN))) {
+ BTM_TRACE_EVENT(
+ "Security Manager: reject connect request from bonding device");
+
+ /* incoming connection from bonding device is rejected */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ btsnd_hcic_reject_conn(bda, HCI_ERR_HOST_REJECT_DEVICE);
+ return;
+ }
+
+ /* Host is not interested or approved connection. Save BDA and DC and */
+ /* pass request to L2CAP */
+ memcpy(btm_cb.connecting_bda, bda, BD_ADDR_LEN);
+ memcpy(btm_cb.connecting_dc, dc, DEV_CLASS_LEN);
+
+ if (l2c_link_hci_conn_req(bda)) {
+ if (!p_dev_rec) {
+ /* accept the connection -> allocate a device record */
+ p_dev_rec = btm_sec_alloc_dev(bda);
+ }
+ if (p_dev_rec) {
+ p_dev_rec->sm4 |= BTM_SM4_CONN_PEND;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_bond_cancel_complete
+ *
+ * Description This function is called to report bond cancel complete
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_sec_bond_cancel_complete(void) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) ||
+ (BTM_PAIR_STATE_WAIT_LOCAL_PIN == btm_cb.pairing_state &&
+ BTM_PAIR_FLAGS_WE_STARTED_DD & btm_cb.pairing_flags) ||
+ (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME &&
+ BTM_PAIR_FLAGS_WE_CANCEL_DD & btm_cb.pairing_flags)) {
+ /* for dedicated bonding in legacy mode, authentication happens at "link
+ * level"
+ * btm_sec_connected is called with failed status.
+ * In theory, the code that handles is_pairing_device/true should clean out
+ * security related code.
+ * However, this function may clean out the security related flags and
+ * btm_sec_connected would not know
+ * this function also needs to do proper clean up.
+ */
+ p_dev_rec = btm_find_dev(btm_cb.pairing_bda);
+ if (p_dev_rec != NULL) p_dev_rec->security_required = BTM_SEC_NONE;
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ /* Notify application that the cancel succeeded */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback)
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_create_conn_cancel_complete
+ *
+ * Description This function is called when the command complete message
+ * is received from the HCI for the create connection cancel
+ * command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_create_conn_cancel_complete(uint8_t* p) {
+ uint8_t status;
+
+ STREAM_TO_UINT8(status, p);
+ BTM_TRACE_EVENT("btm_create_conn_cancel_complete(): in State: %s status:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), status);
+
+ /* if the create conn cancel cmd was issued by the bond cancel,
+ ** the application needs to be notified that bond cancel succeeded
+ */
+ switch (status) {
+ case HCI_SUCCESS:
+ btm_sec_bond_cancel_complete();
+ break;
+ case HCI_ERR_CONNECTION_EXISTS:
+ case HCI_ERR_NO_CONNECTION:
+ default:
+ /* Notify application of the error */
+ if (btm_cb.api.p_bond_cancel_cmpl_callback)
+ btm_cb.api.p_bond_cancel_cmpl_callback(BTM_ERR_PROCESSING);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_check_pending_reqs
+ *
+ * Description This function is called at the end of the security procedure
+ * to let L2CAP and RFCOMM know to re-submit any pending
+ * requests
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_check_pending_reqs(void) {
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ /* First, resubmit L2CAP requests */
+ if (btm_cb.sec_req_pending) {
+ btm_cb.sec_req_pending = false;
+ l2cu_resubmit_pending_sec_req(NULL);
+ }
+
+ /* Now, re-submit anything in the mux queue */
+ fixed_queue_t* bq = btm_cb.sec_pending_q;
+
+ btm_cb.sec_pending_q = fixed_queue_new(SIZE_MAX);
+
+ tBTM_SEC_QUEUE_ENTRY* p_e;
+ while ((p_e = (tBTM_SEC_QUEUE_ENTRY*)fixed_queue_try_dequeue(bq)) != NULL) {
+ /* Check that the ACL is still up before starting security procedures */
+ if (btm_bda_to_acl(p_e->bd_addr, p_e->transport) != NULL) {
+ if (p_e->psm != 0) {
+ BTM_TRACE_EVENT(
+ "%s PSM:0x%04x Is_Orig:%u mx_proto_id:%u mx_chan_id:%u", __func__,
+ p_e->psm, p_e->is_orig, p_e->mx_proto_id, p_e->mx_chan_id);
+
+ btm_sec_mx_access_request(p_e->bd_addr, p_e->psm, p_e->is_orig,
+ p_e->mx_proto_id, p_e->mx_chan_id,
+ p_e->p_callback, p_e->p_ref_data);
+ } else {
+ BTM_SetEncryption(p_e->bd_addr, p_e->transport, p_e->p_callback,
+ p_e->p_ref_data, p_e->sec_act);
+ }
+ }
+
+ osi_free(p_e);
+ }
+ fixed_queue_free(bq, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_init
+ *
+ * Description This function is on the SEC startup
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_init(uint8_t sec_mode) {
+ btm_cb.security_mode = sec_mode;
+ memset(btm_cb.pairing_bda, 0xff, BD_ADDR_LEN);
+ btm_cb.max_collision_delay = BTM_SEC_MAX_COLLISION_DELAY;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_device_down
+ *
+ * Description This function should be called when device is disabled or
+ * turned off
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_device_down(void) {
+ BTM_TRACE_EVENT("%s() State: %s", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state));
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_dev_reset
+ *
+ * Description This function should be called after device reset
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_dev_reset(void) {
+ if (controller_get_interface()->supports_simple_pairing()) {
+ /* set the default IO capabilities */
+ btm_cb.devcb.loc_io_caps = BTM_LOCAL_IO_CAPS;
+ /* add mx service to use no security */
+ BTM_SetSecurityLevel(false, "RFC_MUX", BTM_SEC_SERVICE_RFC_MUX,
+ BTM_SEC_NONE, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 0);
+ } else {
+ btm_cb.security_mode = BTM_SEC_MODE_SERVICE;
+ }
+
+ BTM_TRACE_DEBUG("btm_sec_dev_reset sec mode: %d", btm_cb.security_mode);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_abort_access_req
+ *
+ * Description This function is called by the L2CAP or RFCOMM to abort
+ * the pending operation.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_abort_access_req(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+
+ if (!p_dev_rec) return;
+
+ if ((p_dev_rec->sec_state != BTM_SEC_STATE_AUTHORIZING) &&
+ (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING))
+ return;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_dd_create_conn
+ *
+ * Description This function is called to create the ACL connection for
+ * the dedicated boding process
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec) {
+ tL2C_LCB* p_lcb =
+ l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb && (p_lcb->link_state == LST_CONNECTED ||
+ p_lcb->link_state == LST_CONNECTING)) {
+ BTM_TRACE_WARNING("%s Connection already exists", __func__);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+ return BTM_CMD_STARTED;
+ }
+
+ /* Make sure an L2cap link control block is available */
+ if (!p_lcb &&
+ (p_lcb = l2cu_allocate_lcb(p_dev_rec->bd_addr, true,
+ BT_TRANSPORT_BR_EDR)) == NULL) {
+ BTM_TRACE_WARNING(
+ "Security Manager: failed allocate LCB [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ return (BTM_NO_RESOURCES);
+ }
+
+ /* set up the control block to indicated dedicated bonding */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+
+ if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) {
+ BTM_TRACE_WARNING(
+ "Security Manager: failed create [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ l2cu_release_lcb(p_lcb);
+ return (BTM_NO_RESOURCES);
+ }
+
+ btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);
+
+ BTM_TRACE_DEBUG(
+ "Security Manager: btm_sec_dd_create_conn [%02x%02x%02x%02x%02x%02x]",
+ p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2],
+ p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
+
+ return (BTM_CMD_STARTED);
+}
+
+bool is_state_getting_name(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME) {
+ return false;
+ }
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_rmt_name_request_complete
+*
+ * Description This function is called when remote name was obtained from
+ * the peer device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_rmt_name_request_complete(uint8_t* p_bd_addr, uint8_t* p_bd_name,
+ uint8_t status) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ int i;
+ DEV_CLASS dev_class;
+ uint8_t old_sec_state;
+
+ BTM_TRACE_EVENT("btm_sec_rmt_name_request_complete");
+ if (((p_bd_addr == NULL) && !BTM_ACL_IS_CONNECTED(btm_cb.connecting_bda)) ||
+ ((p_bd_addr != NULL) && !BTM_ACL_IS_CONNECTED(p_bd_addr))) {
+ btm_acl_resubmit_page();
+ }
+
+ /* If remote name request failed, p_bd_addr is null and we need to search */
+ /* based on state assuming that we are doing 1 at a time */
+ if (p_bd_addr)
+ p_dev_rec = btm_find_dev(p_bd_addr);
+ else {
+ list_node_t* node =
+ list_foreach(btm_cb.sec_dev_rec, is_state_getting_name, NULL);
+ if (node != NULL) {
+ p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(list_node(node));
+ p_bd_addr = p_dev_rec->bd_addr;
+ } else {
+ p_dev_rec = NULL;
+ }
+ }
+
+ /* Commenting out trace due to obf/compilation problems.
+ */
+ if (!p_bd_name) p_bd_name = (uint8_t*)"";
+
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "%s PairState: %s RemName: %s status: %d State:%d p_dev_rec: "
+ "0x%08x ",
+ __func__, btm_pair_state_descr(btm_cb.pairing_state), p_bd_name, status,
+ p_dev_rec->sec_state, p_dev_rec);
+ } else {
+ BTM_TRACE_EVENT("%s PairState: %s RemName: %s status: %d", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state), p_bd_name,
+ status);
+ }
+
+ if (p_dev_rec) {
+ old_sec_state = p_dev_rec->sec_state;
+ if (status == HCI_SUCCESS) {
+ strlcpy((char*)p_dev_rec->sec_bd_name, (char*)p_bd_name,
+ BTM_MAX_REM_BD_NAME_LEN);
+ p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
+ BTM_TRACE_EVENT("setting BTM_SEC_NAME_KNOWN sec_flags:0x%x",
+ p_dev_rec->sec_flags);
+ } else {
+ /* Notify all clients waiting for name to be resolved even if it failed so
+ * clients can continue */
+ p_dev_rec->sec_bd_name[0] = 0;
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_GETTING_NAME)
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* Notify all clients waiting for name to be resolved */
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] && p_bd_addr)
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name);
+ }
+ } else {
+ dev_class[0] = 0;
+ dev_class[1] = 0;
+ dev_class[2] = 0;
+
+ /* Notify all clients waiting for name to be resolved even if not found so
+ * clients can continue */
+ for (i = 0; i < BTM_SEC_MAX_RMT_NAME_CALLBACKS; i++) {
+ if (btm_cb.p_rmt_name_callback[i] && p_bd_addr)
+ (*btm_cb.p_rmt_name_callback[i])(p_bd_addr, dev_class, (uint8_t*)"");
+ }
+
+ return;
+ }
+
+ /* If we were delaying asking UI for a PIN because name was not resolved, ask
+ * now */
+ if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_LOCAL_PIN) && p_bd_addr &&
+ (memcmp(btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0)) {
+ BTM_TRACE_EVENT(
+ "%s() delayed pin now being requested flags:0x%x, "
+ "(p_pin_callback=0x%p)",
+ __func__, btm_cb.pairing_flags, btm_cb.api.p_pin_callback);
+
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0 &&
+ btm_cb.api.p_pin_callback) {
+ BTM_TRACE_EVENT("%s() calling pin_callback", __func__);
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ (*btm_cb.api.p_pin_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_bd_name,
+ (p_dev_rec->p_cur_service == NULL)
+ ? false
+ : (p_dev_rec->p_cur_service->security_flags &
+ BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+
+ /* Set the same state again to force the timer to be restarted */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ return;
+ }
+
+ /* Check if we were delaying bonding because name was not resolved */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_GET_REM_NAME) {
+ if (p_bd_addr && memcmp(btm_cb.pairing_bda, p_bd_addr, BD_ADDR_LEN) == 0) {
+ BTM_TRACE_EVENT("%s() continue bonding sm4: 0x%04x, status:0x%x",
+ __func__, p_dev_rec->sm4, status);
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_CANCEL_DD) {
+ btm_sec_bond_cancel_complete();
+ return;
+ }
+
+ if (status != HCI_SUCCESS) {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ status);
+ return;
+ }
+
+ /* if peer is very old legacy devices, HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is
+ * not reported */
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* set the KNOWN flag only if BTM_PAIR_FLAGS_REJECTED_CONNECT is not
+ * set.*/
+ /* If it is set, there may be a race condition */
+ BTM_TRACE_DEBUG("%s IS_SM4_UNKNOWN Flags:0x%04x", __func__,
+ btm_cb.pairing_flags);
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) == 0)
+ p_dev_rec->sm4 |= BTM_SM4_KNOWN;
+ }
+
+ BTM_TRACE_DEBUG("%s, SM4 Value: %x, Legacy:%d,IS SM4:%d, Unknown:%d",
+ __func__, p_dev_rec->sm4,
+ BTM_SEC_IS_SM4_LEGACY(p_dev_rec->sm4),
+ BTM_SEC_IS_SM4(p_dev_rec->sm4),
+ BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4));
+
+ /* BT 2.1 or carkit, bring up the connection to force the peer to request
+ *PIN.
+ ** Else prefetch (btm_sec_check_prefetch_pin will do the prefetching if
+ *needed)
+ */
+ if ((p_dev_rec->sm4 != BTM_SM4_KNOWN) ||
+ !btm_sec_check_prefetch_pin(p_dev_rec)) {
+ /* if we rejected incoming connection request, we have to wait
+ * HCI_Connection_Complete event */
+ /* before originating */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT) {
+ BTM_TRACE_WARNING(
+ "%s: waiting HCI_Connection_Complete after rejecting connection",
+ __func__);
+ }
+ /* Both we and the peer are 2.1 - continue to create connection */
+ else if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ BTM_TRACE_WARNING("%s: failed to start connection", __func__);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, HCI_ERR_MEMORY_FULL);
+ }
+ }
+ }
+ return;
+ } else {
+ BTM_TRACE_WARNING("%s: wrong BDA, retry with pairing BDA", __func__);
+ if (BTM_ReadRemoteDeviceName(btm_cb.pairing_bda, NULL,
+ BT_TRANSPORT_BR_EDR) != BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("%s: failed to start remote name request", __func__);
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_ERR_MEMORY_FULL);
+ }
+ };
+ return;
+ }
+ }
+
+ /* check if we were delaying link_key_callback because name was not resolved
+ */
+ if (p_dev_rec->link_key_not_sent) {
+ /* If HCI connection complete has not arrived, wait for it */
+ if (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE) return;
+
+ p_dev_rec->link_key_not_sent = false;
+ btm_send_link_key_notif(p_dev_rec);
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and
+ * auth complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) {
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_SUCCESS);
+ }
+ }
+
+ /* If this is a bonding procedure can disconnect the link now */
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) {
+ BTM_TRACE_WARNING("btm_sec_rmt_name_request_complete (none/ce)");
+ p_dev_rec->security_required &= ~(BTM_SEC_OUT_AUTHENTICATE);
+ l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+ return;
+ }
+
+ if (old_sec_state != BTM_SEC_STATE_GETTING_NAME) return;
+
+ /* If get name failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false);
+ return;
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_REQ_PEND) {
+ BTM_TRACE_EVENT("waiting for remote features!!");
+ return;
+ }
+
+ /* Remote Name succeeded, execute the next security procedure, if any */
+ status = (uint8_t)btm_sec_execute_procedure(p_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status == BTM_CMD_STARTED) return;
+
+ /* There is no next procedure or start of procedure failed, notify the waiting
+ * layer */
+ btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_rmt_host_support_feat_evt
+ *
+ * Description This function is called when the
+ * HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT is received
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_rmt_host_support_feat_evt(uint8_t* p) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BD_ADDR bd_addr; /* peer address */
+ BD_FEATURES features;
+
+ STREAM_TO_BDADDR(bd_addr, p);
+ p_dev_rec = btm_find_or_alloc_dev(bd_addr);
+
+ BTM_TRACE_EVENT("btm_sec_rmt_host_support_feat_evt sm4: 0x%x p[0]: 0x%x",
+ p_dev_rec->sm4, p[0]);
+
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ STREAM_TO_ARRAY(features, p, HCI_FEATURE_BYTES_PER_PAGE);
+ if (HCI_SSP_HOST_SUPPORTED(features)) {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ }
+ BTM_TRACE_EVENT(
+ "btm_sec_rmt_host_support_feat_evt sm4: 0x%x features[0]: 0x%x",
+ p_dev_rec->sm4, features[0]);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_io_capabilities_req
+ *
+ * Description This function is called when LM request for the IO
+ * capability of the local device and
+ * if the OOB data is present for the device in the event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_io_capabilities_req(uint8_t* p) {
+ tBTM_SP_IO_REQ evt_data;
+ uint8_t err_code = 0;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ bool is_orig = true;
+ uint8_t callback_rc = BTM_SUCCESS;
+
+ STREAM_TO_BDADDR(evt_data.bd_addr, p);
+
+ /* setup the default response according to compile options */
+ /* assume that the local IO capability does not change
+ * loc_io_caps is initialized with the default value */
+ evt_data.io_cap = btm_cb.devcb.loc_io_caps;
+ evt_data.oob_data = BTM_OOB_NONE;
+ evt_data.auth_req = BTM_DEFAULT_AUTH_REQ;
+
+ BTM_TRACE_EVENT("%s: State: %s", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state));
+
+ p_dev_rec = btm_find_or_alloc_dev(evt_data.bd_addr);
+
+ BTM_TRACE_DEBUG("%s:Security mode: %d, Num Read Remote Feat pages: %d",
+ __func__, btm_cb.security_mode, p_dev_rec->num_read_pages);
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ (p_dev_rec->num_read_pages == 0)) {
+ BTM_TRACE_EVENT("%s: Device security mode is SC only.",
+ "To continue need to know remote features.", __func__);
+
+ p_dev_rec->remote_features_needed = true;
+ return;
+ }
+
+ p_dev_rec->sm4 |= BTM_SM4_TRUE;
+
+ BTM_TRACE_EVENT("%s: State: %s Flags: 0x%04x p_cur_service: 0x%08x",
+ __func__, btm_pair_state_descr(btm_cb.pairing_state),
+ btm_cb.pairing_flags, p_dev_rec->p_cur_service);
+
+ if (p_dev_rec->p_cur_service) {
+ BTM_TRACE_EVENT("%s: cur_service psm: 0x%04x, security_flags: 0x%04x",
+ __func__, p_dev_rec->p_cur_service->psm,
+ p_dev_rec->p_cur_service->security_flags);
+ }
+
+ switch (btm_cb.pairing_state) {
+ /* initiator connecting */
+ case BTM_PAIR_STATE_IDLE:
+ // TODO: Handle Idle pairing state
+ // security_required = p_dev_rec->security_required;
+ break;
+
+ /* received IO capability response already->acceptor */
+ case BTM_PAIR_STATE_INCOMING_SSP:
+ is_orig = false;
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_PEER_STARTED_DD) {
+ /* acceptor in dedicated bonding */
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ }
+ break;
+
+ /* initiator, at this point it is expected to be dedicated bonding
+ initiated by local device */
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ if (!memcmp(evt_data.bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN)) {
+ evt_data.auth_req = BTM_DEFAULT_DD_AUTH_REQ;
+ } else {
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ }
+ break;
+
+ /* any other state is unexpected */
+ default:
+ err_code = HCI_ERR_HOST_BUSY_PAIRING;
+ BTM_TRACE_ERROR("%s: Unexpected Pairing state received %d", __func__,
+ btm_cb.pairing_state);
+ break;
+ }
+
+ if (btm_cb.pairing_disabled) {
+ /* pairing is not allowed */
+ BTM_TRACE_DEBUG("%s: Pairing is not allowed -> fail pairing.", __func__);
+ err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ bool local_supports_sc =
+ controller_get_interface()->supports_secure_connections();
+ /* device in Secure Connections Only mode */
+ if (!(local_supports_sc) ||
+ !(p_dev_rec->remote_supports_secure_connections)) {
+ BTM_TRACE_DEBUG("%s: SC only service, local_support_for_sc %d,",
+ " remote_support_for_sc 0x%02x -> fail pairing", __func__,
+ local_supports_sc,
+ p_dev_rec->remote_supports_secure_connections);
+
+ err_code = HCI_ERR_PAIRING_NOT_ALLOWED;
+ }
+ }
+
+ if (err_code != 0) {
+ btsnd_hcic_io_cap_req_neg_reply(evt_data.bd_addr, err_code);
+ return;
+ }
+
+ evt_data.is_orig = is_orig;
+
+ if (is_orig) {
+ /* local device initiated the pairing non-bonding -> use p_cur_service */
+ if (!(btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ p_dev_rec->p_cur_service &&
+ (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_AUTHENTICATE)) {
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* SC only mode device requires MITM protection */
+ evt_data.auth_req = BTM_AUTH_SP_YES;
+ } else {
+ evt_data.auth_req =
+ (p_dev_rec->p_cur_service->security_flags & BTM_SEC_OUT_MITM)
+ ? BTM_AUTH_SP_YES
+ : BTM_AUTH_SP_NO;
+ }
+ }
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request(evt_data.bd_addr);
+
+ memcpy(btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+ if (!memcmp(evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS);
+
+ callback_rc = BTM_SUCCESS;
+ if (p_dev_rec->sm4 & BTM_SM4_UPGRADE) {
+ p_dev_rec->sm4 &= ~BTM_SM4_UPGRADE;
+
+ /* link key upgrade: always use SPGB_YES - assuming we want to save the link
+ * key */
+ evt_data.auth_req = BTM_AUTH_SPGB_YES;
+ } else if (btm_cb.api.p_sp_callback) {
+ /* the callback function implementation may change the IO capability... */
+ callback_rc = (*btm_cb.api.p_sp_callback)(BTM_SP_IO_REQ_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+ }
+
+ if ((callback_rc == BTM_SUCCESS) || (BTM_OOB_UNKNOWN != evt_data.oob_data)) {
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ evt_data.auth_req =
+ (BTM_AUTH_DD_BOND | (evt_data.auth_req & BTM_AUTH_YN_BIT));
+ }
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* At this moment we know that both sides are SC capable, device in */
+ /* SC only mode requires MITM for any service so let's set MITM bit */
+ evt_data.auth_req |= BTM_AUTH_YN_BIT;
+ BTM_TRACE_DEBUG(
+ "%s: for device in \"SC only\" mode set auth_req to 0x%02x", __func__,
+ evt_data.auth_req);
+ }
+
+ /* if the user does not indicate "reply later" by setting the oob_data to
+ * unknown */
+ /* send the response right now. Save the current IO capability in the
+ * control block */
+ btm_cb.devcb.loc_auth_req = evt_data.auth_req;
+ btm_cb.devcb.loc_io_caps = evt_data.io_cap;
+
+ BTM_TRACE_EVENT("%s: State: %s IO_CAP:%d oob_data:%d auth_req:%d",
+ __func__, btm_pair_state_descr(btm_cb.pairing_state),
+ evt_data.io_cap, evt_data.oob_data, evt_data.auth_req);
+
+ btsnd_hcic_io_cap_req_reply(evt_data.bd_addr, evt_data.io_cap,
+ evt_data.oob_data, evt_data.auth_req);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_io_capabilities_rsp
+ *
+ * Description This function is called when the IO capability of the
+ * specified device is received
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_io_capabilities_rsp(uint8_t* p) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_SP_IO_RSP evt_data;
+
+ STREAM_TO_BDADDR(evt_data.bd_addr, p);
+ STREAM_TO_UINT8(evt_data.io_cap, p);
+ STREAM_TO_UINT8(evt_data.oob_data, p);
+ STREAM_TO_UINT8(evt_data.auth_req, p);
+
+ /* Allocate a new device record or reuse the oldest one */
+ p_dev_rec = btm_find_or_alloc_dev(evt_data.bd_addr);
+
+ /* If no security is in progress, this indicates incoming security */
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ memcpy(btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_INCOMING_SSP);
+
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+
+ /* work around for FW bug */
+ btm_inq_stop_on_ssp();
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request(evt_data.bd_addr);
+
+ /* We must have a device record here.
+ * Use the connecting device's CoD for the connection */
+ if (!memcmp(evt_data.bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN))
+ memcpy(p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
+
+ /* peer sets dedicated bonding bit and we did not initiate dedicated bonding
+ */
+ if (btm_cb.pairing_state ==
+ BTM_PAIR_STATE_INCOMING_SSP /* peer initiated bonding */
+ && (evt_data.auth_req &
+ BTM_AUTH_DD_BOND)) /* and dedicated bonding bit is set */
+ {
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ }
+
+ /* save the IO capability in the device record */
+ p_dev_rec->rmt_io_caps = evt_data.io_cap;
+ p_dev_rec->rmt_auth_req = evt_data.auth_req;
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback)(BTM_SP_IO_RSP_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_proc_sp_req_evt
+ *
+ * Description This function is called to process/report
+ * HCI_USER_CONFIRMATION_REQUEST_EVT
+ * or HCI_USER_PASSKEY_REQUEST_EVT
+ * or HCI_USER_PASSKEY_NOTIFY_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_proc_sp_req_evt(tBTM_SP_EVT event, uint8_t* p) {
+ tBTM_STATUS status = BTM_ERR_PROCESSING;
+ tBTM_SP_EVT_DATA evt_data;
+ uint8_t* p_bda = evt_data.cfm_req.bd_addr;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ /* All events start with bd_addr */
+ STREAM_TO_BDADDR(p_bda, p);
+
+ BTM_TRACE_EVENT(
+ "btm_proc_sp_req_evt() BDA: %08x%04x event: 0x%x, State: %s",
+ (p_bda[0] << 24) + (p_bda[1] << 16) + (p_bda[2] << 8) + p_bda[3],
+ (p_bda[4] << 8) + p_bda[5], event,
+ btm_pair_state_descr(btm_cb.pairing_state));
+
+ p_dev_rec = btm_find_dev(p_bda);
+ if ((p_dev_rec != NULL) && (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0)) {
+ memcpy(evt_data.cfm_req.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy(evt_data.cfm_req.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ /** M: sec_bd_name should be used only when BTM_SEC_NAME_KNOWN is set @{*/
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) {
+ strlcpy((char*)evt_data.cfm_req.bd_name, (char*)p_dev_rec->sec_bd_name,
+ BTM_MAX_REM_BD_NAME_LEN);
+ }
+ else
+ evt_data.cfm_req.bd_name[0] = 0;
+ /** @} */
+
+ switch (event) {
+ case BTM_SP_CFM_REQ_EVT:
+ /* Numeric confirmation. Need user to conf the passkey */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM);
+
+ /* The device record must be allocated in the "IO cap exchange" step */
+ STREAM_TO_UINT32(evt_data.cfm_req.num_val, p);
+ BTM_TRACE_DEBUG("BTM_SP_CFM_REQ_EVT: num_val: %u",
+ evt_data.cfm_req.num_val);
+
+ evt_data.cfm_req.just_works = true;
+
+/* process user confirm req in association with the auth_req param */
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_IO)
+ if (p_dev_rec->rmt_io_caps == BTM_IO_CAP_UNKNOWN) {
+ BTM_TRACE_ERROR(
+ "%s did not receive IO cap response prior"
+ " to BTM_SP_CFM_REQ_EVT, failing pairing request",
+ __func__);
+ status = BTM_WRONG_MODE;
+ BTM_ConfirmReqReply(status, p_bda);
+ return;
+ }
+ if ((p_dev_rec->rmt_io_caps == BTM_IO_CAP_IO) &&
+ (btm_cb.devcb.loc_io_caps == BTM_IO_CAP_IO) &&
+ ((p_dev_rec->rmt_auth_req & BTM_AUTH_SP_YES) ||
+ (btm_cb.devcb.loc_auth_req & BTM_AUTH_SP_YES))) {
+ /* Both devices are DisplayYesNo and one or both devices want to
+ authenticate -> use authenticated link key */
+ evt_data.cfm_req.just_works = false;
+ }
+#endif
+ BTM_TRACE_DEBUG(
+ "btm_proc_sp_req_evt() just_works:%d, io loc:%d, rmt:%d, auth "
+ "loc:%d, rmt:%d",
+ evt_data.cfm_req.just_works, btm_cb.devcb.loc_io_caps,
+ p_dev_rec->rmt_io_caps, btm_cb.devcb.loc_auth_req,
+ p_dev_rec->rmt_auth_req);
+
+ evt_data.cfm_req.loc_auth_req = btm_cb.devcb.loc_auth_req;
+ evt_data.cfm_req.rmt_auth_req = p_dev_rec->rmt_auth_req;
+ evt_data.cfm_req.loc_io_caps = btm_cb.devcb.loc_io_caps;
+ evt_data.cfm_req.rmt_io_caps = p_dev_rec->rmt_io_caps;
+ break;
+
+ case BTM_SP_KEY_NOTIF_EVT:
+ /* Passkey notification (other side is a keyboard) */
+ STREAM_TO_UINT32(evt_data.key_notif.passkey, p);
+ BTM_TRACE_DEBUG("BTM_SP_KEY_NOTIF_EVT: passkey: %u",
+ evt_data.key_notif.passkey);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ case BTM_SP_KEY_REQ_EVT:
+ /* HCI_USER_PASSKEY_REQUEST_EVT */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_KEY_ENTRY);
+ break;
+#endif
+ }
+
+ if (btm_cb.api.p_sp_callback) {
+ status = (*btm_cb.api.p_sp_callback)(event, (tBTM_SP_EVT_DATA*)&evt_data);
+ if (status != BTM_NOT_AUTHORIZED) {
+ return;
+ }
+ /* else BTM_NOT_AUTHORIZED means when the app wants to reject the req
+ * right now */
+ } else if ((event == BTM_SP_CFM_REQ_EVT) &&
+ (evt_data.cfm_req.just_works == true)) {
+ /* automatically reply with just works if no sp_cback */
+ status = BTM_SUCCESS;
+ }
+
+ if (event == BTM_SP_CFM_REQ_EVT) {
+ BTM_TRACE_DEBUG("calling BTM_ConfirmReqReply with status: %d", status);
+ BTM_ConfirmReqReply(status, p_bda);
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else if (event == BTM_SP_KEY_REQ_EVT) {
+ BTM_PasskeyReqReply(status, p_bda, 0);
+ }
+#endif
+ return;
+ }
+
+ /* Something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+
+ if (BTM_SP_CFM_REQ_EVT == event) {
+ btsnd_hcic_user_conf_reply(p_bda, false);
+ } else if (BTM_SP_KEY_NOTIF_EVT == event) {
+ /* do nothing -> it very unlikely to happen.
+ This event is most likely to be received by a HID host when it first
+ connects to a HID device.
+ Usually the Host initiated the connection in this case.
+ On Mobile platforms, if there's a security process happening,
+ the host probably can not initiate another connection.
+ BTW (PC) is another story. */
+ p_dev_rec = btm_find_dev(p_bda);
+ if (p_dev_rec != NULL) {
+ btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE);
+ }
+ }
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ else {
+ btsnd_hcic_user_passkey_neg_reply(p_bda);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_keypress_notif_evt
+ *
+ * Description This function is called when a key press notification is
+ * received
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_keypress_notif_evt(uint8_t* p) {
+ tBTM_SP_KEYPRESS evt_data;
+ uint8_t* p_bda;
+
+ /* parse & report BTM_SP_KEYPRESS_EVT */
+ if (btm_cb.api.p_sp_callback) {
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR(p_bda, p);
+ evt_data.notif_type = *p;
+
+ (*btm_cb.api.p_sp_callback)(BTM_SP_KEYPRESS_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_simple_pair_complete
+ *
+ * Description This function is called when simple pairing process is
+ * complete
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_simple_pair_complete(uint8_t* p) {
+ tBTM_SP_COMPLT evt_data;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ uint8_t status;
+ bool disc = false;
+
+ status = *p++;
+ STREAM_TO_BDADDR(evt_data.bd_addr, p);
+
+ p_dev_rec = btm_find_dev(evt_data.bd_addr);
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR("btm_simple_pair_complete() with unknown BDA: %08x%04x",
+ (evt_data.bd_addr[0] << 24) + (evt_data.bd_addr[1] << 16) +
+ (evt_data.bd_addr[2] << 8) + evt_data.bd_addr[3],
+ (evt_data.bd_addr[4] << 8) + evt_data.bd_addr[5]);
+ return;
+ }
+
+ BTM_TRACE_EVENT(
+ "btm_simple_pair_complete() Pair State: %s Status:%d sec_state: %u",
+ btm_pair_state_descr(btm_cb.pairing_state), status, p_dev_rec->sec_state);
+
+ evt_data.status = BTM_ERR_PROCESSING;
+ if (status == HCI_SUCCESS) {
+ evt_data.status = BTM_SUCCESS;
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+ } else {
+ if (status == HCI_ERR_PAIRING_NOT_ALLOWED) {
+ /* The test spec wants the peer device to get this failure code. */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_DISCONNECT);
+
+ /* Change the timer to 1 second */
+ alarm_set_on_queue(btm_cb.pairing_timer, BT_1SEC_TIMEOUT_MS,
+ btm_sec_pairing_timeout, NULL,
+ btu_general_alarm_queue);
+ } else if (memcmp(btm_cb.pairing_bda, evt_data.bd_addr, BD_ADDR_LEN) == 0) {
+ /* stop the timer */
+ alarm_cancel(btm_cb.pairing_timer);
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+ /* the initiating side: will receive auth complete event. disconnect ACL
+ * at that time */
+ disc = true;
+ }
+ } else
+ disc = true;
+ }
+
+ /* Let the pairing state stay active, p_auth_complete_callback will report the
+ * failure */
+ memcpy(evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy(evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback)(BTM_SP_COMPLT_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+
+ if (disc) {
+ /* simple pairing failed */
+ /* Avoid sending disconnect on HCI_ERR_PEER_USER */
+ if ((status != HCI_ERR_PEER_USER) &&
+ (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)) {
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_AUTH_FAILURE,
+ p_dev_rec->hci_handle);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_rem_oob_req
+ *
+ * Description This function is called to process/report
+ * HCI_REMOTE_OOB_DATA_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_rem_oob_req(uint8_t* p) {
+ uint8_t* p_bda;
+ tBTM_SP_RMT_OOB evt_data;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BT_OCTET16 c;
+ BT_OCTET16 r;
+
+ p_bda = evt_data.bd_addr;
+
+ STREAM_TO_BDADDR(p_bda, p);
+
+ BTM_TRACE_EVENT("btm_rem_oob_req() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+ p_dev_rec = btm_find_dev(p_bda);
+ if ((p_dev_rec != NULL) && btm_cb.api.p_sp_callback) {
+ memcpy(evt_data.bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
+ memcpy(evt_data.dev_class, p_dev_rec->dev_class, DEV_CLASS_LEN);
+ strlcpy((char*)evt_data.bd_name, (char*)p_dev_rec->sec_bd_name,
+ BTM_MAX_REM_BD_NAME_LEN);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP);
+ if ((*btm_cb.api.p_sp_callback)(BTM_SP_RMT_OOB_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data) ==
+ BTM_NOT_AUTHORIZED) {
+ BTM_RemoteOobDataReply(true, p_bda, c, r);
+ }
+ return;
+ }
+
+ /* something bad. we can only fail this connection */
+ btm_cb.acl_disc_reason = HCI_ERR_HOST_REJECT_SECURITY;
+ btsnd_hcic_rem_oob_neg_reply(p_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_read_local_oob_complete
+ *
+ * Description This function is called when read local oob data is
+ * completed by the LM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_read_local_oob_complete(uint8_t* p) {
+ tBTM_SP_LOC_OOB evt_data;
+ uint8_t status = *p++;
+
+ BTM_TRACE_EVENT("btm_read_local_oob_complete:%d", status);
+ if (status == HCI_SUCCESS) {
+ evt_data.status = BTM_SUCCESS;
+ STREAM_TO_ARRAY16(evt_data.c, p);
+ STREAM_TO_ARRAY16(evt_data.r, p);
+ } else
+ evt_data.status = BTM_ERR_PROCESSING;
+
+ if (btm_cb.api.p_sp_callback)
+ (*btm_cb.api.p_sp_callback)(BTM_SP_LOC_OOB_EVT,
+ (tBTM_SP_EVT_DATA*)&evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_auth_collision
+ *
+ * Description This function is called when authentication or encryption
+ * needs to be retried at a later time.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_sec_auth_collision(uint16_t handle) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ if (!btm_cb.collision_start_time)
+ btm_cb.collision_start_time = time_get_os_boottime_ms();
+
+ if ((time_get_os_boottime_ms() - btm_cb.collision_start_time) <
+ btm_cb.max_collision_delay) {
+ if (handle == BTM_SEC_INVALID_HANDLE) {
+ p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_AUTHENTICATING);
+ if (p_dev_rec == NULL)
+ p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_ENCRYPTING);
+ } else
+ p_dev_rec = btm_find_dev_by_handle(handle);
+
+ if (p_dev_rec != NULL) {
+ BTM_TRACE_DEBUG(
+ "btm_sec_auth_collision: state %d (retrying in a moment...)",
+ p_dev_rec->sec_state);
+ /* We will restart authentication after timeout */
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING ||
+ p_dev_rec->sec_state == BTM_SEC_STATE_ENCRYPTING)
+ p_dev_rec->sec_state = 0;
+
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ alarm_set_on_queue(btm_cb.sec_collision_timer, BT_1SEC_TIMEOUT_MS,
+ btm_sec_collision_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_auth_complete
+ *
+ * Description This function is when authentication of the connection is
+ * completed by the LM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_auth_complete(uint16_t handle, uint8_t status) {
+ uint8_t old_sm4;
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ bool are_bonding = false;
+
+ /** M: find the correct dev which is in authenticating state @{ */
+ if(handle == BTM_INVALID_HCI_HANDLE)
+ p_dev_rec = btm_sec_find_dev_by_sec_state(BTM_SEC_STATE_AUTHENTICATING);
+ else
+ p_dev_rec = btm_find_dev_by_handle(handle);
+ /** @} */
+
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "Security Manager: auth_complete PairState: %s handle:%u status:%d "
+ "dev->sec_state: %u Bda:%08x, RName:%s",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status,
+ p_dev_rec->sec_state,
+ (p_dev_rec->bd_addr[2] << 24) + (p_dev_rec->bd_addr[3] << 16) +
+ (p_dev_rec->bd_addr[4] << 8) + p_dev_rec->bd_addr[5],
+ p_dev_rec->sec_bd_name);
+ } else {
+ BTM_TRACE_EVENT(
+ "Security Manager: auth_complete PairState: %s handle:%u status:%d",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status);
+ }
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) ||
+ (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ btm_restore_mode();
+
+ /* Check if connection was made just to do bonding. If we authenticate
+ the connection that is up, this is the last event received.
+ */
+ if (p_dev_rec && (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ !(btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE)) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+ }
+
+ if (!p_dev_rec) return;
+
+ /* keep the old sm4 flag and clear the retry bit in control block */
+ old_sm4 = p_dev_rec->sm4;
+ p_dev_rec->sm4 &= ~BTM_SM4_RETRY;
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
+ (memcmp(p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0))
+ are_bonding = true;
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(p_dev_rec->bd_addr, btm_cb.pairing_bda, BD_ADDR_LEN) == 0))
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+ if ((btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS) &&
+ (old_state != BTM_PAIR_STATE_IDLE)) {
+ (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ return;
+ }
+
+ /* There can be a race condition, when we are starting authentication and
+ ** the peer device is doing encryption.
+ ** If first we receive encryption change up, then initiated authentication
+ ** can not be performed. According to the spec we can not do authentication
+ ** on the encrypted link, so device is correct.
+ */
+ if ((status == HCI_ERR_COMMAND_DISALLOWED) &&
+ ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
+ (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
+ status = HCI_SUCCESS;
+ }
+ /* Currently we do not notify user if it is a keyboard which connects */
+ /* User probably Disabled the keyboard while it was asleap. Let her try */
+ if (btm_cb.api.p_auth_complete_callback) {
+ /* report the suthentication status */
+ if ((old_state != BTM_PAIR_STATE_IDLE) || (status != HCI_SUCCESS))
+ (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+
+ /* If this is a bonding procedure can disconnect the link now */
+ if (are_bonding) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ if (status != HCI_SUCCESS) {
+ if (((status != HCI_ERR_PEER_USER) &&
+ (status != HCI_ERR_CONN_CAUSE_LOCAL_HOST)))
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_PEER_USER,
+ p_dev_rec->hci_handle);
+ } else {
+ BTM_TRACE_DEBUG("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL");
+ if (p_dev_rec->new_encryption_key_is_p256 &&
+ (btm_sec_use_smp_br_chnl(p_dev_rec))
+ /* no LE keys are available, do deriving */
+ && (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) ||
+ /* or BR key is higher security than existing LE keys */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) &&
+ (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)))) {
+ BTM_TRACE_DEBUG(
+ "link encrypted afer dedic bonding can use SMP_BR_CHNL");
+
+ if (btm_sec_is_master(p_dev_rec)) {
+ // Encryption is required to start SM over BR/EDR
+ // indicate that this is encryption after authentication
+ BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL,
+ 0);
+ }
+ }
+ l2cu_start_post_bond_timer(p_dev_rec->hci_handle);
+ }
+
+ return;
+ }
+
+ /* If authentication failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ if ((old_sm4 & BTM_SM4_RETRY) == 0) {
+ /* allow retry only once */
+ if (status == HCI_ERR_LMP_ERR_TRANS_COLLISION) {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ BTM_TRACE_DEBUG("Collision retry sm4:x%x sec_flags:0x%x",
+ p_dev_rec->sm4, p_dev_rec->sec_flags);
+ }
+ /* this retry for missing key is for Lisbon or later only.
+ * Legacy device do not need this. the controller will drive the retry
+ * automatically */
+ else if (HCI_ERR_KEY_MISSING == status &&
+ BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
+ /* not retried yet. set the retry bit */
+ p_dev_rec->sm4 |= BTM_SM4_RETRY;
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ BTM_TRACE_DEBUG("Retry for missing key sm4:x%x sec_flags:0x%x",
+ p_dev_rec->sm4, p_dev_rec->sec_flags);
+
+ /* With BRCM controller, we do not need to delete the stored link key in
+ controller.
+ If the stack may sit on top of other controller, we may need this
+ BTM_DeleteStoredLinkKey (bd_addr, NULL); */
+ }
+
+ if (p_dev_rec->sm4 & BTM_SM4_RETRY) {
+ btm_sec_execute_procedure(p_dev_rec);
+ return;
+ }
+ }
+
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false);
+
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_DISC_WHEN_DONE) {
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_AUTH_FAILURE,
+ p_dev_rec->hci_handle);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ // If we have MITM protection we have a higher level of security than
+ // provided by 16 digits PIN
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+ /* Authentication succeeded, execute the next security procedure, if any */
+ status = btm_sec_execute_procedure(p_dev_rec);
+
+ /* If there is no next procedure, or procedure failed to start, notify the
+ * caller */
+ if (status != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_encrypt_change
+ *
+ * Description This function is when encryption of the connection is
+ * completed by the LM
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_encrypt_change(uint16_t handle, uint8_t status,
+ uint8_t encr_enable) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ tACL_CONN* p_acl = NULL;
+ uint8_t acl_idx = btm_handle_to_acl_index(handle);
+ BTM_TRACE_EVENT(
+ "Security Manager: encrypt_change status:%d State:%d, encr_enable = %d",
+ status, (p_dev_rec) ? p_dev_rec->sec_state : 0, encr_enable);
+ BTM_TRACE_DEBUG("before update p_dev_rec->sec_flags=0x%x",
+ (p_dev_rec) ? p_dev_rec->sec_flags : 0);
+
+ /* For transaction collision we need to wait and repeat. There is no need */
+ /* for random timeout because only slave should receive the result */
+ if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) ||
+ (status == HCI_ERR_DIFF_TRANSACTION_COLLISION)) {
+ btm_sec_auth_collision(handle);
+ return;
+ }
+ btm_cb.collision_start_time = 0;
+
+ if (!p_dev_rec) return;
+
+ if ((status == HCI_SUCCESS) && encr_enable) {
+ if (p_dev_rec->hci_handle == handle) {
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED);
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+ } else {
+ p_dev_rec->sec_flags |= (BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
+ }
+ }
+
+ /* It is possible that we decrypted the link to perform role switch */
+ /* mark link not to be encrypted, so that when we execute security next time
+ * it will kick in again */
+ if ((status == HCI_SUCCESS) && !encr_enable) {
+ if (p_dev_rec->hci_handle == handle)
+ p_dev_rec->sec_flags &= ~BTM_SEC_ENCRYPTED;
+ else
+ p_dev_rec->sec_flags &= ~BTM_SEC_LE_ENCRYPTED;
+ }
+
+ BTM_TRACE_DEBUG("after update p_dev_rec->sec_flags=0x%x",
+ p_dev_rec->sec_flags);
+
+ if (acl_idx != MAX_L2CAP_LINKS) p_acl = &btm_cb.acl_db[acl_idx];
+
+ if (p_acl != NULL)
+ btm_sec_check_pending_enc_req(p_dev_rec, p_acl->transport, encr_enable);
+
+ if (p_acl && p_acl->transport == BT_TRANSPORT_LE) {
+ if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE ||
+ status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) {
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN);
+ p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(HANDLE_KEY_MISSING) && (HANDLE_KEY_MISSING == TRUE)
+ p_dev_rec->sec_status = status;
+#endif
+#endif
+ }
+ btm_ble_link_encrypted(p_dev_rec->ble.pseudo_addr, encr_enable);
+ return;
+ } else {
+ /* BR/EDR connection, update the encryption key size to be 16 as always */
+ p_dev_rec->enc_key_size = 16;
+ }
+
+ BTM_TRACE_DEBUG("in %s new_encr_key_256 is %d", __func__,
+ p_dev_rec->new_encryption_key_is_p256);
+
+ if ((status == HCI_SUCCESS) && encr_enable &&
+ (p_dev_rec->hci_handle == handle)) {
+ /* if BR key is temporary no need for LE LTK derivation */
+ bool derive_ltk = true;
+ if (p_dev_rec->rmt_auth_req == BTM_AUTH_SP_NO &&
+ btm_cb.devcb.loc_auth_req == BTM_AUTH_SP_NO) {
+ derive_ltk = false;
+ BTM_TRACE_DEBUG("%s: BR key is temporary, skip derivation of LE LTK",
+ __func__);
+ }
+ if (p_dev_rec->new_encryption_key_is_p256) {
+ if (btm_sec_use_smp_br_chnl(p_dev_rec) && btm_sec_is_master(p_dev_rec) &&
+ /* if LE key is not known, do deriving */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN) ||
+ /* or BR key is higher security than existing LE keys */
+ (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) &&
+ (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))) &&
+ derive_ltk) {
+ /* BR/EDR is encrypted with LK that can be used to derive LE LTK */
+ p_dev_rec->new_encryption_key_is_p256 = false;
+
+ if (p_dev_rec->no_smp_on_br) {
+ BTM_TRACE_DEBUG("%s NO SM over BR/EDR", __func__);
+ } else {
+ BTM_TRACE_DEBUG("%s start SM over BR/EDR", __func__);
+ SMP_BR_PairWith(p_dev_rec->bd_addr);
+ }
+ }
+ } else {
+ // BR/EDR is successfully encrypted. Correct LK type if needed
+ // (BR/EDR LK derived from LE LTK was used for encryption)
+ if ((encr_enable == 1) && /* encryption is ON for SSP */
+ /* LK type is for BR/EDR SC */
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ if (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256)
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ else /* BTM_LKEY_TYPE_AUTH_COMB_P_256 */
+ p_dev_rec->link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+
+ BTM_TRACE_DEBUG("updated link key type to %d",
+ p_dev_rec->link_key_type);
+ btm_send_link_key_notif(p_dev_rec);
+ }
+ }
+ }
+
+ /* If this encryption was started by peer do not need to do anything */
+ if (p_dev_rec->sec_state != BTM_SEC_STATE_ENCRYPTING) {
+ if (BTM_SEC_STATE_DELAY_FOR_ENC == p_dev_rec->sec_state) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->p_callback = NULL;
+ l2cu_resubmit_pending_sec_req(p_dev_rec->bd_addr);
+ }
+ return;
+ }
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ /* If encryption setup failed, notify the waiting layer */
+ if (status != HCI_SUCCESS) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false);
+ return;
+ }
+
+ /* Encryption setup succeeded, execute the next security procedure, if any */
+ status = (uint8_t)btm_sec_execute_procedure(p_dev_rec);
+ /* If there is no next procedure, or procedure failed to start, notify the
+ * caller */
+ if (status != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event(p_dev_rec, status, false);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_connect_after_reject_timeout
+ *
+ * Description Connection for bonding could not start because of the
+ * collision. Initiate outgoing connection
+ *
+ * Returns Pointer to the TLE struct
+ *
+ ******************************************************************************/
+static void btm_sec_connect_after_reject_timeout(UNUSED_ATTR void* data) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_cb.p_collided_dev_rec;
+
+ BTM_TRACE_EVENT("%s", __func__);
+ btm_cb.p_collided_dev_rec = 0;
+
+ if (btm_sec_dd_create_conn(p_dev_rec) != BTM_CMD_STARTED) {
+ BTM_TRACE_WARNING("Security Manager: %s: failed to start connection",
+ __func__);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_ERR_MEMORY_FULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_connected
+ *
+ * Description This function is when a connection to the peer device is
+ * establsihed
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_connected(uint8_t* bda, uint16_t handle, uint8_t status,
+ uint8_t enc_mode) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ uint8_t res;
+ bool is_pairing_device = false;
+ tACL_CONN* p_acl_cb;
+ uint8_t bit_shift = 0;
+
+ btm_acl_resubmit_page();
+
+ if (p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "Security Manager: btm_sec_connected in state: %s handle:%d status:%d "
+ "enc_mode:%d bda:%x RName:%s",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5],
+ p_dev_rec->sec_bd_name);
+ } else {
+ BTM_TRACE_EVENT(
+ "Security Manager: btm_sec_connected in state: %s handle:%d status:%d "
+ "enc_mode:%d bda:%x ",
+ btm_pair_state_descr(btm_cb.pairing_state), handle, status, enc_mode,
+ (bda[2] << 24) + (bda[3] << 16) + (bda[4] << 8) + bda[5]);
+ }
+
+ if (!p_dev_rec) {
+ /* There is no device record for new connection. Allocate one */
+ if (status == HCI_SUCCESS) {
+ p_dev_rec = btm_sec_alloc_dev(bda);
+ } else {
+ /* If the device matches with stored paring address
+ * reset the paring state to idle */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0)) {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+
+ /* can not find the device record and the status is error,
+ * just ignore it */
+ return;
+ }
+ } else /* Update the timestamp for this device */
+ {
+ bit_shift = (handle == p_dev_rec->ble_hci_handle) ? 8 : 0;
+ p_dev_rec->timestamp = btm_cb.dev_rec_count++;
+ if (p_dev_rec->sm4 & BTM_SM4_CONN_PEND) {
+ /* tell L2CAP it's a bonding connection. */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* if incoming connection failed while pairing, then try to connect and
+ * continue */
+ /* Motorola S9 disconnects without asking pin code */
+ if ((status != HCI_SUCCESS) &&
+ (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ)) {
+ BTM_TRACE_WARNING(
+ "Security Manager: btm_sec_connected: incoming connection failed "
+ "without asking PIN");
+
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ alarm_set_on_queue(btm_cb.sec_collision_timer, 0,
+ btm_sec_connect_after_reject_timeout, NULL,
+ btu_general_alarm_queue);
+ } else {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
+ if (BTM_ReadRemoteDeviceName(p_dev_rec->bd_addr, NULL,
+ BT_TRANSPORT_BR_EDR) !=
+ BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("%s cannot read remote name", __func__);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+ }
+#if (BTM_DISC_DURING_RS == TRUE)
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+ return;
+ } else {
+ l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true);
+ }
+ }
+ /* always clear the pending flag */
+ p_dev_rec->sm4 &= ~BTM_SM4_CONN_PEND;
+ }
+ }
+
+ p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
+
+#if (BTM_DISC_DURING_RS == TRUE)
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, bda, BD_ADDR_LEN) == 0)) {
+ /* if we rejected incoming connection from bonding device */
+ if ((status == HCI_ERR_HOST_REJECT_DEVICE) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_REJECTED_CONNECT)) {
+ BTM_TRACE_WARNING(
+ "Security Manager: btm_sec_connected: HCI_Conn_Comp Flags:0x%04x, "
+ "sm4: 0x%x",
+ btm_cb.pairing_flags, p_dev_rec->sm4);
+
+ btm_cb.pairing_flags &= ~BTM_PAIR_FLAGS_REJECTED_CONNECT;
+ if (BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
+ /* Try again: RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
+ if (BTM_ReadRemoteDeviceName(bda, NULL, BT_TRANSPORT_BR_EDR) !=
+ BTM_CMD_STARTED) {
+ BTM_TRACE_ERROR("%s cannot read remote name", __func__);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+ return;
+ }
+
+ /* if we already have pin code */
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_LOCAL_PIN) {
+ /* Start timer with 0 to initiate connection with new LCB */
+ /* because L2CAP will delete current LCB with this event */
+ btm_cb.p_collided_dev_rec = p_dev_rec;
+ alarm_set_on_queue(btm_cb.sec_collision_timer, 0,
+ btm_sec_connect_after_reject_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+
+ return;
+ }
+ /* wait for incoming connection without resetting pairing state */
+ else if (status == HCI_ERR_CONNECTION_EXISTS) {
+ BTM_TRACE_WARNING(
+ "Security Manager: btm_sec_connected: Wait for incoming connection");
+ return;
+ }
+
+ is_pairing_device = true;
+ }
+
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ /* if connection fails during pin request, notify application */
+ if (status != HCI_SUCCESS) {
+ /* If connection failed because of during pairing, need to tell user */
+ if (is_pairing_device) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &=
+ ~((BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED) << bit_shift);
+ BTM_TRACE_DEBUG("security_required:%x ", p_dev_rec->security_required);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ }
+ /*
+ Do not send authentication failure, if following conditions hold good
+ 1. BTM Sec Pairing state is idle
+ 2. Link key for the remote device is present.
+ 3. Remote is SSP capable.
+ */
+ else if ((p_dev_rec->link_key_type <= BTM_LKEY_TYPE_REMOTE_UNIT) &&
+ (((status == HCI_ERR_AUTH_FAILURE) ||
+ (status == HCI_ERR_KEY_MISSING) ||
+ (status == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (status == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (status == HCI_ERR_UNIT_KEY_USED) ||
+ (status == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (status == HCI_ERR_REPEATED_ATTEMPTS)))) {
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_LINK_KEY_KNOWN << bit_shift);
+
+#ifdef BRCM_NOT_4_BTE
+ /* If we rejected pairing, pass this special result code */
+ if (btm_cb.acl_disc_reason == HCI_ERR_HOST_REJECT_SECURITY) {
+ status = HCI_ERR_HOST_REJECT_SECURITY;
+ }
+#endif
+
+ /* We need to notify host that the key is not known any more */
+ if (btm_cb.api.p_auth_complete_callback) {
+ (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, status);
+ }
+ }
+
+ if (status == HCI_ERR_CONNECTION_TOUT ||
+ status == HCI_ERR_LMP_RESPONSE_TIMEOUT ||
+ status == HCI_ERR_UNSPECIFIED || status == HCI_ERR_PAGE_TIMEOUT)
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_DEVICE_TIMEOUT, false);
+ else
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, false);
+
+ return;
+ }
+
+ /* If initiated dedicated bonding, return the link key now, and initiate
+ * disconnect */
+ /* If dedicated bonding, and we now have a link key, we are all done */
+ if (is_pairing_device && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN)) {
+ if (p_dev_rec->link_key_not_sent) {
+ p_dev_rec->link_key_not_sent = false;
+ btm_send_link_key_notif(p_dev_rec);
+ }
+
+ p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
+
+ /* remember flag before it is initialized */
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ res = true;
+ else
+ res = false;
+
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_SUCCESS);
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+
+ if (res) {
+ /* Let l2cap start bond timer */
+ l2cu_update_lcb_4_bonding(p_dev_rec->bd_addr, true);
+ }
+
+ return;
+ }
+
+ p_dev_rec->hci_handle = handle;
+
+ /* role may not be correct here, it will be updated by l2cap, but we need to
+ */
+ /* notify btm_acl that link is up, so starting of rmt name request will not */
+ /* set paging flag up */
+ p_acl_cb = btm_bda_to_acl(bda, BT_TRANSPORT_BR_EDR);
+ if (p_acl_cb) {
+/* whatever is in btm_establish_continue() without reporting the BTM_BL_CONN_EVT
+ * event */
+#if (BTM_BYPASS_EXTRA_ACL_SETUP == FALSE)
+ /* For now there are a some devices that do not like sending */
+ /* commands events and data at the same time. */
+ /* Set the packet types to the default allowed by the device */
+ btm_set_packet_types(p_acl_cb, btm_cb.btm_acl_pkt_types_supported);
+
+ if (btm_cb.btm_def_link_policy)
+ BTM_SetLinkPolicy(p_acl_cb->remote_addr, &btm_cb.btm_def_link_policy);
+#endif
+ }
+ btm_acl_created(bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name, handle,
+ HCI_ROLE_SLAVE, BT_TRANSPORT_BR_EDR);
+
+ /* Initialize security flags. We need to do that because some */
+ /* authorization complete could have come after the connection is dropped */
+ /* and that would set wrong flag that link has been authorized already */
+ p_dev_rec->sec_flags &= ~((BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED |
+ BTM_SEC_ENCRYPTED | BTM_SEC_ROLE_SWITCHED)
+ << bit_shift);
+
+ if (enc_mode != HCI_ENCRYPT_MODE_DISABLED)
+ p_dev_rec->sec_flags |=
+ ((BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED) << bit_shift);
+
+ if (btm_cb.security_mode == BTM_SEC_MODE_LINK)
+ p_dev_rec->sec_flags |= (BTM_SEC_AUTHENTICATED << bit_shift);
+
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= (BTM_SEC_16_DIGIT_PIN_AUTHED << bit_shift);
+ }
+
+ p_dev_rec->link_key_changed = false;
+
+ /* After connection is established we perform security if we do not know */
+ /* the name, or if we are originator because some procedure can have */
+ /* been scheduled while connection was down */
+ BTM_TRACE_DEBUG("is_originator:%d ", p_dev_rec->is_originator);
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) ||
+ p_dev_rec->is_originator) {
+ res = btm_sec_execute_procedure(p_dev_rec);
+ if (res != BTM_CMD_STARTED)
+ btm_sec_dev_rec_cback_event(p_dev_rec, res, false);
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_disconnect
+ *
+ * Description This function is called to disconnect HCI link
+ *
+ * Returns btm status
+ *
+ ******************************************************************************/
+tBTM_STATUS btm_sec_disconnect(uint16_t handle, uint8_t reason) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+
+ /* In some weird race condition we may not have a record */
+ if (!p_dev_rec) {
+ btsnd_hcic_disconnect(handle, reason);
+ return (BTM_SUCCESS);
+ }
+
+ /* If we are in the process of bonding we need to tell client that auth failed
+ */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) &&
+ (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* we are currently doing bonding. Link will be disconnected when done */
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
+ return (BTM_BUSY);
+ }
+
+ return (btm_sec_send_hci_disconnect(p_dev_rec, reason, handle));
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_disconnected
+ *
+ * Description This function is when a connection to the peer device is
+ * dropped
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_disconnected(uint16_t handle, uint8_t reason) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ uint8_t old_pairing_flags = btm_cb.pairing_flags;
+ int result = HCI_ERR_AUTH_FAILURE;
+ tBTM_SEC_CALLBACK* p_callback = NULL;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ /* If page was delayed for disc complete, can do it now */
+ btm_cb.discing = false;
+
+ if (!p_dev_rec)
+ {
+ /** M: fix for scheduling resubmit page wrong @{ */
+ btm_acl_resubmit_page();
+ /** @} */
+ return;
+ }
+ /** M: fix for scheduling resubmit page wrong @{ */
+ else if(btm_cb.paging && !memcmp(btm_cb.connecting_bda,p_dev_rec->bd_addr,BD_ADDR_LEN))
+ btm_acl_resubmit_page();
+ /** @} */
+
+ transport =
+ (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE;
+
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+
+#if (BTM_DISC_DURING_RS == TRUE)
+ LOG_INFO(LOG_TAG, "%s clearing pending flag handle:%d reason:%d", __func__,
+ handle, reason);
+ p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */
+#endif
+
+ /* clear unused flags */
+ p_dev_rec->sm4 &= BTM_SM4_TRUE;
+
+ uint8_t* bd_addr = (uint8_t*)p_dev_rec->bd_addr;
+ BTM_TRACE_EVENT(
+ "%s sec_req:x%x state:%s reason:%d bd_addr:%02x:%02x:%02x:%02x:%02x:%02x"
+ " remote_name:%s",
+ __func__, p_dev_rec->security_required,
+ btm_pair_state_descr(btm_cb.pairing_state), reason, bd_addr[0],
+ bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5],
+ p_dev_rec->sec_bd_name);
+
+ BTM_TRACE_EVENT("%s before update sec_flags=0x%x", __func__,
+ p_dev_rec->sec_flags);
+
+ btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, p_dev_rec->bd_addr,
+ HCI_SUCCESS);
+ /* see sec_flags processing in btm_acl_removed */
+
+ if (transport == BT_TRANSPORT_LE) {
+ p_dev_rec->ble_hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED);
+ p_dev_rec->enc_key_size = 0;
+ } else {
+ p_dev_rec->hci_handle = BTM_SEC_INVALID_HANDLE;
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED |
+ BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
+ /** M: remove link key for temporary bonding @{ */
+ if(p_dev_rec->bond_type == BOND_TYPE_TEMPORARY)
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ /** @} */
+ }
+
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_DISCONNECTING_BOTH) {
+ p_dev_rec->sec_state = (transport == BT_TRANSPORT_LE)
+ ? BTM_SEC_STATE_DISCONNECTING
+ : BTM_SEC_STATE_DISCONNECTING_BLE;
+ return;
+ }
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ p_dev_rec->security_required = BTM_SEC_NONE;
+
+ p_callback = p_dev_rec->p_callback;
+
+ /* if security is pending, send callback to clean up the security state */
+ if (p_callback) {
+ p_dev_rec->p_callback =
+ NULL; /* when the peer device time out the authentication before
+ we do, this call back must be reset here */
+ (*p_callback)(p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data,
+ BTM_ERR_PROCESSING);
+ }
+
+ BTM_TRACE_EVENT("%s after update sec_flags=0x%x", __func__,
+ p_dev_rec->sec_flags);
+
+/** M: tell client at the last, because the p_dev_rec will be freed in btm_cb.api.p_auth_complete_callback @{*/
+ /* If we are in the process of bonding we need to tell client that auth failed
+ */
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)) {
+
+ /** M: Cleanup security collision info when link down @{*/
+ if (btm_cb.collision_start_time != 0) {
+ btm_cb.collision_start_time = 0;
+ btm_cb.p_collided_dev_rec = NULL;
+ alarm_cancel(btm_cb.sec_collision_timer);
+ }
+ /** @} */
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ p_dev_rec->sec_flags &= ~BTM_SEC_LINK_KEY_KNOWN;
+ if (btm_cb.api.p_auth_complete_callback) {
+ /* If the disconnection reason is REPEATED_ATTEMPTS,
+ send this error message to complete callback function
+ to display the error message of Repeated attempts.
+ All others, send HCI_ERR_AUTH_FAILURE. */
+ if (reason == HCI_ERR_REPEATED_ATTEMPTS) {
+ result = HCI_ERR_REPEATED_ATTEMPTS;
+ } else if (old_pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ result = HCI_ERR_HOST_REJECT_SECURITY;
+ }
+ (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
+ p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, result);
+ }
+ }
+/** @} */
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_link_key_notification
+ *
+ * Description This function is called when a new connection link key is
+ * generated
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+void btm_sec_link_key_notification(uint8_t* p_bda, uint8_t* p_link_key,
+ uint8_t key_type) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_bda);
+ bool we_are_bonding = false;
+ bool ltk_derived_lk = false;
+
+ BTM_TRACE_EVENT(
+ "btm_sec_link_key_notification() BDA:%04x%08x, TYPE: %d",
+ (p_bda[0] << 8) + p_bda[1],
+ (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5],
+ key_type);
+
+ if ((key_type >= BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_COMBINATION) &&
+ (key_type <=
+ BTM_LTK_DERIVED_LKEY_OFFSET + BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ ltk_derived_lk = true;
+ key_type -= BTM_LTK_DERIVED_LKEY_OFFSET;
+ }
+ /* If connection was made to do bonding restore link security if changed */
+ btm_restore_mode();
+
+ if (key_type != BTM_LKEY_TYPE_CHANGED_COMB)
+ p_dev_rec->link_key_type = key_type;
+
+ p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
+
+ /*
+ * Until this point in time, we do not know if MITM was enabled, hence we
+ * add the extended security flag here.
+ */
+ if (p_dev_rec->pin_code_length >= 16 ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
+ p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
+ p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
+ }
+
+ /* BR/EDR connection, update the encryption key size to be 16 as always */
+ p_dev_rec->enc_key_size = 16;
+ memcpy(p_dev_rec->link_key, p_link_key, LINK_KEY_LEN);
+
+ if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
+ (memcmp(btm_cb.pairing_bda, p_bda, BD_ADDR_LEN) == 0)) {
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ we_are_bonding = true;
+ else
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
+
+ /* save LTK derived LK no matter what */
+ if (ltk_derived_lk) {
+ if (btm_cb.api.p_link_key_callback) {
+ BTM_TRACE_DEBUG("%s() Save LTK derived LK (key_type = %d)", __func__,
+ p_dev_rec->link_key_type);
+ (*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->link_key_type);
+ }
+ } else {
+ if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) ||
+ (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ p_dev_rec->new_encryption_key_is_p256 = true;
+ BTM_TRACE_DEBUG("%s set new_encr_key_256 to %d", __func__,
+ p_dev_rec->new_encryption_key_is_p256);
+ }
+ }
+
+ /* If name is not known at this point delay calling callback until the name is
+ */
+ /* resolved. Unless it is a HID Device and we really need to send all link
+ * keys. */
+ if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) &&
+ ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) !=
+ BTM_COD_MAJOR_PERIPHERAL)) &&
+ !ltk_derived_lk) {
+ BTM_TRACE_EVENT(
+ "btm_sec_link_key_notification() Delayed BDA: %08x%04x Type:%d",
+ (p_bda[0] << 24) + (p_bda[1] << 16) + (p_bda[2] << 8) + p_bda[3],
+ (p_bda[4] << 8) + p_bda[5], key_type);
+
+ p_dev_rec->link_key_not_sent = true;
+
+ /* If it is for bonding nothing else will follow, so we need to start name
+ * resolution */
+ if (we_are_bonding) {
+ btsnd_hcic_rmt_name_req(p_bda, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ }
+
+ BTM_TRACE_EVENT("rmt_io_caps:%d, sec_flags:x%x, dev_class[1]:x%02x",
+ p_dev_rec->rmt_io_caps, p_dev_rec->sec_flags,
+ p_dev_rec->dev_class[1])
+ return;
+ }
+
+ /* If its not us who perform authentication, we should tell stackserver */
+ /* that some authentication has been completed */
+ /* This is required when different entities receive link notification and auth
+ * complete */
+ if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)
+ /* for derived key, always send authentication callback for BR channel */
+ || ltk_derived_lk) {
+ if (btm_cb.api.p_auth_complete_callback)
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_SUCCESS);
+ }
+
+/* We will save link key only if the user authorized it - BTE report link key in
+ * all cases */
+#ifdef BRCM_NONE_BTE
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)
+#endif
+ {
+ if (btm_cb.api.p_link_key_callback) {
+ if (ltk_derived_lk) {
+ BTM_TRACE_DEBUG(
+ "btm_sec_link_key_notification() LTK derived LK is saved already"
+ " (key_type = %d)",
+ p_dev_rec->link_key_type);
+ } else {
+ (*btm_cb.api.p_link_key_callback)(p_bda, p_dev_rec->dev_class,
+ p_dev_rec->sec_bd_name, p_link_key,
+ p_dev_rec->link_key_type);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_link_key_request
+ *
+ * Description This function is called when controller requests link key
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+void btm_sec_link_key_request(uint8_t* p_bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_bda);
+
+ BTM_TRACE_EVENT(
+ "btm_sec_link_key_request() BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ p_bda[0], p_bda[1], p_bda[2], p_bda[3], p_bda[4], p_bda[5]);
+
+ if ((btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_PIN_REQ) &&
+ (btm_cb.collision_start_time != 0) &&
+ (memcmp(btm_cb.p_collided_dev_rec->bd_addr, p_bda, BD_ADDR_LEN) == 0)) {
+ BTM_TRACE_EVENT(
+ "btm_sec_link_key_request() rejecting link key req "
+ "State: %d START_TIMEOUT : %d",
+ btm_cb.pairing_state, btm_cb.collision_start_time);
+ btsnd_hcic_link_key_neg_reply(p_bda);
+ return;
+ }
+ if (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) {
+ btsnd_hcic_link_key_req_reply(p_bda, p_dev_rec->link_key);
+ return;
+ }
+
+ /* Notify L2CAP to increase timeout */
+ l2c_pin_code_request(p_bda);
+
+ /* The link key is not in the database and it is not known to the manager */
+ btsnd_hcic_link_key_neg_reply(p_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_pairing_timeout
+ *
+ * Description This function is called when host does not provide PIN
+ * within requested time
+ *
+ * Returns Pointer to the TLE struct
+ *
+ ******************************************************************************/
+static void btm_sec_pairing_timeout(UNUSED_ATTR void* data) {
+ tBTM_CB* p_cb = &btm_cb;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+#if (BTM_LOCAL_IO_CAPS == BTM_IO_CAP_NONE)
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_NO;
+#else
+ tBTM_AUTH_REQ auth_req = BTM_AUTH_AP_YES;
+#endif
+ uint8_t name[2];
+
+ p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+
+ BTM_TRACE_EVENT("%s State: %s Flags: %u", __func__,
+ btm_pair_state_descr(p_cb->pairing_state),
+ p_cb->pairing_flags);
+
+ switch (p_cb->pairing_state) {
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ btm_sec_bond_cancel_complete();
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
+ if ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PRE_FETCH_PIN) == 0)
+ btsnd_hcic_pin_code_neg_reply(p_cb->pairing_bda);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ /* We need to notify the UI that no longer need the PIN */
+ if (btm_cb.api.p_auth_complete_callback) {
+ if (p_dev_rec == NULL) {
+ name[0] = 0;
+ (*btm_cb.api.p_auth_complete_callback)(p_cb->pairing_bda, NULL, name,
+ HCI_ERR_CONNECTION_TOUT);
+ } else
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_ERR_CONNECTION_TOUT);
+ }
+ break;
+
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:
+ btsnd_hcic_user_conf_reply(p_cb->pairing_bda, false);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+
+#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE)
+ case BTM_PAIR_STATE_KEY_ENTRY:
+ btsnd_hcic_user_passkey_neg_reply(p_cb->pairing_bda);
+ /* btm_sec_change_pairing_state (BTM_PAIR_STATE_IDLE); */
+ break;
+#endif /* !BTM_IO_CAP_NONE */
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD)
+ auth_req |= BTM_AUTH_DD_BOND;
+
+ btsnd_hcic_io_cap_req_reply(p_cb->pairing_bda, btm_cb.devcb.loc_io_caps,
+ BTM_OOB_NONE, auth_req);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:
+ btsnd_hcic_rem_oob_neg_reply(p_cb->pairing_bda);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_DISCONNECT:
+ /* simple pairing failed. Started a 1-sec timer at simple pairing
+ * complete.
+ * now it's time to tear down the ACL link*/
+ if (p_dev_rec == NULL) {
+ BTM_TRACE_ERROR(
+ "%s BTM_PAIR_STATE_WAIT_DISCONNECT unknown BDA: %08x%04x", __func__,
+ (p_cb->pairing_bda[0] << 24) + (p_cb->pairing_bda[1] << 16) +
+ (p_cb->pairing_bda[2] << 8) + p_cb->pairing_bda[3],
+ (p_cb->pairing_bda[4] << 8) + p_cb->pairing_bda[5]);
+ break;
+ }
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_AUTH_FAILURE,
+ p_dev_rec->hci_handle);
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ break;
+
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:
+ case BTM_PAIR_STATE_GET_REM_NAME:
+ /* We need to notify the UI that timeout has happened while waiting for
+ * authentication*/
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ if (btm_cb.api.p_auth_complete_callback) {
+ if (p_dev_rec == NULL) {
+ name[0] = 0;
+ (*btm_cb.api.p_auth_complete_callback)(p_cb->pairing_bda, NULL, name,
+ HCI_ERR_CONNECTION_TOUT);
+ } else
+ (*btm_cb.api.p_auth_complete_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ HCI_ERR_CONNECTION_TOUT);
+ }
+ break;
+
+ default:
+ BTM_TRACE_WARNING("%s not processed state: %s", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state));
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_pin_code_request
+ *
+ * Description This function is called when controller requests PIN code
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+void btm_sec_pin_code_request(uint8_t* p_bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_CB* p_cb = &btm_cb;
+
+ BTM_TRACE_EVENT(
+ "btm_sec_pin_code_request() State: %s, BDA:%04x%08x",
+ btm_pair_state_descr(btm_cb.pairing_state), (p_bda[0] << 8) + p_bda[1],
+ (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5]);
+
+ if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) {
+ if ((memcmp(p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) &&
+ (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE)) {
+ btsnd_hcic_pin_code_neg_reply(p_bda);
+ return;
+ } else if ((btm_cb.pairing_state != BTM_PAIR_STATE_WAIT_PIN_REQ) ||
+ memcmp(p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) != 0) {
+ BTM_TRACE_WARNING("btm_sec_pin_code_request() rejected - state: %s",
+ btm_pair_state_descr(btm_cb.pairing_state));
+ btsnd_hcic_pin_code_neg_reply(p_bda);
+ return;
+ }
+ }
+
+ p_dev_rec = btm_find_or_alloc_dev(p_bda);
+ /* received PIN code request. must be non-sm4 */
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+
+ if (btm_cb.pairing_state == BTM_PAIR_STATE_IDLE) {
+ memcpy(btm_cb.pairing_bda, p_bda, BD_ADDR_LEN);
+
+ btm_cb.pairing_flags = BTM_PAIR_FLAGS_PEER_STARTED_DD;
+ /* Make sure we reset the trusted mask to help against attacks */
+ BTM_SEC_CLR_TRUSTED_DEVICE(p_dev_rec->trusted_mask);
+ }
+
+ if (!p_cb->pairing_disabled && (p_cb->cfg.pin_type == HCI_PIN_TYPE_FIXED)) {
+ BTM_TRACE_EVENT("btm_sec_pin_code_request fixed pin replying");
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ btsnd_hcic_pin_code_req_reply(p_bda, p_cb->cfg.pin_code_len,
+ p_cb->cfg.pin_code);
+ return;
+ }
+
+ /* Use the connecting device's CoD for the connection */
+ if ((!memcmp(p_bda, p_cb->connecting_bda, BD_ADDR_LEN)) &&
+ (p_cb->connecting_dc[0] || p_cb->connecting_dc[1] ||
+ p_cb->connecting_dc[2]))
+ memcpy(p_dev_rec->dev_class, p_cb->connecting_dc, DEV_CLASS_LEN);
+
+ /* We could have started connection after asking user for the PIN code */
+ if (btm_cb.pin_code_len != 0) {
+ BTM_TRACE_EVENT("btm_sec_pin_code_request bonding sending reply");
+ btsnd_hcic_pin_code_req_reply(p_bda, btm_cb.pin_code_len, p_cb->pin_code);
+
+ /* Mark that we forwarded received from the user PIN code */
+ btm_cb.pin_code_len = 0;
+
+ /* We can change mode back right away, that other connection being
+ * established */
+ /* is not forced to be secure - found a FW issue, so we can not do this
+ btm_restore_mode(); */
+
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
+ }
+
+ /* If pairing disabled OR (no PIN callback and not bonding) */
+ /* OR we could not allocate entry in the database reject pairing request */
+ else if (
+ p_cb->pairing_disabled || (p_cb->api.p_pin_callback == NULL)
+
+ /* OR Microsoft keyboard can for some reason try to establish connection
+ */
+ /* the only thing we can do here is to shut it up. Normally we will be
+ originator */
+ /* for keyboard bonding */
+ || (!p_dev_rec->is_originator &&
+ ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
+ BTM_COD_MAJOR_PERIPHERAL) &&
+ (p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD))) {
+ BTM_TRACE_WARNING(
+ "btm_sec_pin_code_request(): Pairing disabled:%d; PIN callback:%x, Dev "
+ "Rec:%x!",
+ p_cb->pairing_disabled, p_cb->api.p_pin_callback, p_dev_rec);
+
+ btsnd_hcic_pin_code_neg_reply(p_bda);
+ }
+ /* Notify upper layer of PIN request and start expiration timer */
+ else {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+ /* Pin code request can not come at the same time as connection request */
+ memcpy(p_cb->connecting_bda, p_bda, BD_ADDR_LEN);
+ memcpy(p_cb->connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
+
+ /* Check if the name is known */
+ /* Even if name is not known we might not be able to get one */
+ /* this is the case when we are already getting something from the */
+ /* device, so HCI level is flow controlled */
+ /* Also cannot send remote name request while paging, i.e. connection is not
+ * completed */
+ if (p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) {
+ BTM_TRACE_EVENT("btm_sec_pin_code_request going for callback");
+
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ if (p_cb->api.p_pin_callback) {
+ (*p_cb->api.p_pin_callback)(
+ p_bda, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ (p_dev_rec->p_cur_service == NULL)
+ ? false
+ : (p_dev_rec->p_cur_service->security_flags &
+ BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+ } else {
+ BTM_TRACE_EVENT("btm_sec_pin_code_request going for remote name");
+
+ /* We received PIN code request for the device with unknown name */
+ /* it is not user friendly just to ask for the PIN without name */
+ /* try to get name at first */
+ btsnd_hcic_rmt_name_req(p_dev_rec->bd_addr, HCI_PAGE_SCAN_REP_MODE_R1,
+ HCI_MANDATARY_PAGE_SCAN_MODE, 0);
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_update_clock_offset
+ *
+ * Description This function is called to update clock offset
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_update_clock_offset(uint16_t handle, uint16_t clock_offset) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ tBTM_INQ_INFO* p_inq_info;
+
+ p_dev_rec = btm_find_dev_by_handle(handle);
+ if (p_dev_rec == NULL) return;
+
+ p_dev_rec->clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+
+ p_inq_info = BTM_InqDbRead(p_dev_rec->bd_addr);
+ if (p_inq_info == NULL) return;
+
+ p_inq_info->results.clock_offset = clock_offset | BTM_CLOCK_OFFSET_VALID;
+}
+
+/******************************************************************
+ * S T A T I C F U N C T I O N S
+ ******************************************************************/
+
+/*******************************************************************************
+ *
+ * Function btm_sec_execute_procedure
+ *
+ * Description This function is called to start required security
+ * procedure. There is a case when multiplexing protocol
+ * calls this function on the originating side, connection to
+ * the peer will not be established. This function in this
+ * case performs only authorization.
+ *
+ * Returns BTM_SUCCESS - permission is granted
+ * BTM_CMD_STARTED - in process
+ * BTM_NO_RESOURCES - permission declined
+ *
+ ******************************************************************************/
+static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec) {
+ BTM_TRACE_EVENT(
+ "btm_sec_execute_procedure: Required:0x%x Flags:0x%x State:%d",
+ p_dev_rec->security_required, p_dev_rec->sec_flags, p_dev_rec->sec_state);
+
+ /* There is a chance that we are getting name. Wait until done. */
+ if (p_dev_rec->sec_state != 0) return (BTM_CMD_STARTED);
+
+ /* If any security is required, get the name first */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) &&
+ (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+ BTM_TRACE_EVENT("Security Manager: Start get name");
+ if (!btm_sec_start_get_name(p_dev_rec)) {
+ return (BTM_NO_RESOURCES);
+ }
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If connection is not authenticated and authentication is required */
+ /* start authentication and return PENDING to the caller */
+ if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) &&
+ ((p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) ||
+ (!p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE)))) ||
+ (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
+ (!p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) &&
+ (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+/*
+ * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
+ * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
+ * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
+ * authenticated connections, hence we cannot distinguish here.
+ */
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if (!p_dev_rec->is_originator && (p_dev_rec->is_ucd == true))
+ return (BTM_FAILED_ON_SECURITY);
+#endif
+
+ BTM_TRACE_EVENT("Security Manager: Start authentication");
+
+ /*
+ * If we do have a link-key, but we end up here because we need an
+ * upgrade, then clear the link-key known and authenticated flag before
+ * restarting authentication.
+ * WARNING: If the controller has link-key, it is optional and
+ * recommended for the controller to send a Link_Key_Request.
+ * In case we need an upgrade, the only alternative would be to delete
+ * the existing link-key. That could lead to very bad user experience
+ * or even IOP issues, if a reconnect causes a new connection that
+ * requires an upgrade.
+ */
+ if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) &&
+ (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
+ (!p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
+ p_dev_rec->sec_flags &=
+ ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+ BTM_SEC_AUTHENTICATED);
+ }
+
+ btm_sec_start_authentication(p_dev_rec);
+ return (BTM_CMD_STARTED);
+ }
+
+ /* If connection is not encrypted and encryption is required */
+ /* start encryption and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_ENCRYPTED) &&
+ ((p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_OUT_ENCRYPT)) ||
+ (!p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_IN_ENCRYPT))) &&
+ (p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE)) {
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if incoming UCD packet, discard it */
+ if (!p_dev_rec->is_originator && (p_dev_rec->is_ucd == true))
+ return (BTM_FAILED_ON_SECURITY);
+#endif
+
+ BTM_TRACE_EVENT("Security Manager: Start encryption");
+
+ btm_sec_start_encryption(p_dev_rec);
+ return (BTM_CMD_STARTED);
+ }
+
+ if ((p_dev_rec->security_required & BTM_SEC_MODE4_LEVEL4) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256)) {
+ BTM_TRACE_EVENT(
+ "%s: Security Manager: SC only service, but link key type is 0x%02x -",
+ "security failure", __func__, p_dev_rec->link_key_type);
+ return (BTM_FAILED_ON_SECURITY);
+ }
+
+ /* If connection is not authorized and authorization is required */
+ /* start authorization and return PENDING to the caller */
+ if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHORIZED) &&
+ ((p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_OUT_AUTHORIZE)) ||
+ (!p_dev_rec->is_originator &&
+ (p_dev_rec->security_required & BTM_SEC_IN_AUTHORIZE)))) {
+ BTM_TRACE_EVENT(
+ "service id:%d, is trusted:%d", p_dev_rec->p_cur_service->service_id,
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id)));
+ if ((btm_sec_are_all_trusted(p_dev_rec->trusted_mask) == false) &&
+ (p_dev_rec->p_cur_service->service_id < BTM_SEC_MAX_SERVICES) &&
+ (BTM_SEC_IS_SERVICE_TRUSTED(p_dev_rec->trusted_mask,
+ p_dev_rec->p_cur_service->service_id) ==
+ false)) {
+ BTM_TRACE_EVENT("Security Manager: Start authorization");
+ return (btm_sec_start_authorization(p_dev_rec));
+ }
+ }
+
+ /* All required security procedures already established */
+ p_dev_rec->security_required &=
+ ~(BTM_SEC_OUT_AUTHORIZE | BTM_SEC_IN_AUTHORIZE |
+ BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |
+ BTM_SEC_OUT_ENCRYPT | BTM_SEC_IN_ENCRYPT | BTM_SEC_FORCE_MASTER |
+ BTM_SEC_ATTEMPT_MASTER | BTM_SEC_FORCE_SLAVE | BTM_SEC_ATTEMPT_SLAVE);
+
+ BTM_TRACE_EVENT("Security Manager: trusted:0x%04x%04x",
+ p_dev_rec->trusted_mask[1], p_dev_rec->trusted_mask[0]);
+ BTM_TRACE_EVENT("Security Manager: access granted");
+
+ return (BTM_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_start_get_name
+ *
+ * Description This function is called to start get name procedure
+ *
+ * Returns true if started
+ *
+ ******************************************************************************/
+static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec) {
+ uint8_t tempstate = p_dev_rec->sec_state;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_GETTING_NAME;
+
+ /* 0 and NULL are as timeout and callback params because they are not used in
+ * security get name case */
+ if ((btm_initiate_rem_name(p_dev_rec->bd_addr, BTM_RMT_NAME_SEC, 0, NULL)) !=
+ BTM_CMD_STARTED) {
+ p_dev_rec->sec_state = tempstate;
+ return (false);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_start_authentication
+ *
+ * Description This function is called to start authentication
+ *
+ ******************************************************************************/
+static void btm_sec_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
+ btsnd_hcic_auth_request(p_dev_rec->hci_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_start_encryption
+ *
+ * Description This function is called to start encryption
+ *
+ ******************************************************************************/
+static void btm_sec_start_encryption(tBTM_SEC_DEV_REC* p_dev_rec) {
+ btsnd_hcic_set_conn_encrypt(p_dev_rec->hci_handle, true);
+ p_dev_rec->sec_state = BTM_SEC_STATE_ENCRYPTING;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_start_authorization
+ *
+ * Description This function is called to start authorization
+ *
+ * Returns true if started
+ *
+ ******************************************************************************/
+static uint8_t btm_sec_start_authorization(tBTM_SEC_DEV_REC* p_dev_rec) {
+ uint8_t result;
+ uint8_t* p_service_name = NULL;
+ uint8_t service_id;
+
+ if ((p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN) ||
+ (p_dev_rec->hci_handle == BTM_SEC_INVALID_HANDLE)) {
+ if (!btm_cb.api.p_authorize_callback) return (BTM_MODE_UNSUPPORTED);
+
+ if (p_dev_rec->p_cur_service) {
+#if BTM_SEC_SERVICE_NAME_LEN > 0
+ if (p_dev_rec->is_originator)
+ p_service_name = p_dev_rec->p_cur_service->orig_service_name;
+ else
+ p_service_name = p_dev_rec->p_cur_service->term_service_name;
+#endif
+ service_id = p_dev_rec->p_cur_service->service_id;
+ } else
+ service_id = 0;
+
+ /* Send authorization request if not already sent during this service
+ * connection */
+ if (p_dev_rec->last_author_service_id == BTM_SEC_NO_LAST_SERVICE_ID ||
+ p_dev_rec->last_author_service_id != service_id) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_AUTHORIZING;
+ result = (*btm_cb.api.p_authorize_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ p_service_name, service_id, p_dev_rec->is_originator);
+ }
+
+ else /* Already authorized once for this L2CAP bringup */
+ {
+ BTM_TRACE_DEBUG(
+ "btm_sec_start_authorization: (Ignoring extra Authorization prompt "
+ "for service %d)",
+ service_id);
+ return (BTM_SUCCESS);
+ }
+
+ if (result == BTM_SUCCESS) {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHORIZED;
+
+ /* Save the currently authorized service in case we are asked again by
+ * another multiplexer layer */
+ if (!p_dev_rec->is_originator)
+ p_dev_rec->last_author_service_id = service_id;
+
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ }
+ return (result);
+ }
+ btm_sec_start_get_name(p_dev_rec);
+ return (BTM_CMD_STARTED);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_are_all_trusted
+ *
+ * Description This function is called check if all services are trusted
+ *
+ * Returns true if all are trusted, otherwise false
+ *
+ ******************************************************************************/
+bool btm_sec_are_all_trusted(uint32_t p_mask[]) {
+ uint32_t trusted_inx;
+ for (trusted_inx = 0; trusted_inx < BTM_SEC_SERVICE_ARRAY_SIZE;
+ trusted_inx++) {
+ if (p_mask[trusted_inx] != BTM_SEC_TRUST_ALL) return (false);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_find_first_serv
+ *
+ * Description Look for the first record in the service database
+ * with specified PSM
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_SERV_REC* btm_sec_find_first_serv(CONNECTION_TYPE conn_type,
+ uint16_t psm) {
+ tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+ bool is_originator;
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+ if (conn_type & CONNECTION_TYPE_ORIG_MASK)
+ is_originator = true;
+ else
+ is_originator = false;
+#else
+ is_originator = conn_type;
+#endif
+
+ if (is_originator && btm_cb.p_out_serv && btm_cb.p_out_serv->psm == psm) {
+ /* If this is outgoing connection and the PSM matches p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, just find the first record with the specified PSM */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) &&
+ (p_serv_rec->psm == psm))
+ return (p_serv_rec);
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_find_next_serv
+ *
+ * Description Look for the next record in the service database
+ * with specified PSM
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+static tBTM_SEC_SERV_REC* btm_sec_find_next_serv(tBTM_SEC_SERV_REC* p_cur) {
+ tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) &&
+ (p_serv_rec->psm == p_cur->psm)) {
+ if (p_cur != p_serv_rec) {
+ return (p_serv_rec);
+ }
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_find_mx_serv
+ *
+ * Description Look for the record in the service database with specified
+ * PSM and multiplexor channel information
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+static tBTM_SEC_SERV_REC* btm_sec_find_mx_serv(uint8_t is_originator,
+ uint16_t psm,
+ uint32_t mx_proto_id,
+ uint32_t mx_chan_id) {
+ tBTM_SEC_SERV_REC* p_out_serv = btm_cb.p_out_serv;
+ tBTM_SEC_SERV_REC* p_serv_rec = &btm_cb.sec_serv_rec[0];
+ int i;
+
+ BTM_TRACE_DEBUG("%s()", __func__);
+ if (is_originator && p_out_serv && p_out_serv->psm == psm &&
+ p_out_serv->mx_proto_id == mx_proto_id &&
+ p_out_serv->orig_mx_chan_id == mx_chan_id) {
+ /* If this is outgoing connection and the parameters match p_out_serv,
+ * use it as the current service */
+ return btm_cb.p_out_serv;
+ }
+
+ /* otherwise, the old way */
+ for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
+ if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) &&
+ (p_serv_rec->psm == psm) && (p_serv_rec->mx_proto_id == mx_proto_id) &&
+ ((is_originator && (p_serv_rec->orig_mx_chan_id == mx_chan_id)) ||
+ (!is_originator && (p_serv_rec->term_mx_chan_id == mx_chan_id)))) {
+ return (p_serv_rec);
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_collision_timeout
+ *
+ * Description Encryption could not start because of the collision
+ * try to do it again
+ *
+ * Returns Pointer to the TLE struct
+ *
+ ******************************************************************************/
+static void btm_sec_collision_timeout(UNUSED_ATTR void* data) {
+ BTM_TRACE_EVENT("%s()", __func__);
+
+ tBTM_STATUS status = btm_sec_execute_procedure(btm_cb.p_collided_dev_rec);
+
+ /* If result is pending reply from the user or from the device is pending */
+ if (status != BTM_CMD_STARTED) {
+ /* There is no next procedure or start of procedure failed, notify the
+ * waiting layer */
+ btm_sec_dev_rec_cback_event(btm_cb.p_collided_dev_rec, status, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_link_key_request
+ *
+ * Description This function is called when controller requests link key
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+static void btm_send_link_key_notif(tBTM_SEC_DEV_REC* p_dev_rec) {
+ if (btm_cb.api.p_link_key_callback)
+ (*btm_cb.api.p_link_key_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ p_dev_rec->link_key, p_dev_rec->link_key_type);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTrustedMask
+ *
+ * Description Get trusted mask for the peer device
+ *
+ * Parameters: bd_addr - Address of the device
+ *
+ * Returns NULL, if the device record is not found.
+ * otherwise, the trusted mask
+ *
+ ******************************************************************************/
+uint32_t* BTM_ReadTrustedMask(BD_ADDR bd_addr) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if (p_dev_rec != NULL) return (p_dev_rec->trusted_mask);
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_restore_mode
+ *
+ * Description This function returns the security mode to previous setting
+ * if it was changed during bonding.
+ *
+ *
+ * Parameters: void
+ *
+ ******************************************************************************/
+static void btm_restore_mode(void) {
+ if (btm_cb.security_mode_changed) {
+ btm_cb.security_mode_changed = false;
+ BTM_TRACE_DEBUG("%s() Auth enable -> %d", __func__,
+ (btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ btsnd_hcic_write_auth_enable(
+ (uint8_t)(btm_cb.security_mode == BTM_SEC_MODE_LINK));
+ }
+
+ if (btm_cb.pin_type_changed) {
+ btm_cb.pin_type_changed = false;
+ btsnd_hcic_write_pin_type(btm_cb.cfg.pin_type);
+ }
+}
+
+bool is_sec_state_equal(void* data, void* context) {
+ tBTM_SEC_DEV_REC* p_dev_rec = static_cast<tBTM_SEC_DEV_REC*>(data);
+ uint8_t* state = static_cast<uint8_t*>(context);
+
+ if (p_dev_rec->sec_state == *state) return false;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_find_dev_by_sec_state
+ *
+ * Description Look for the record in the device database for the device
+ * which is being authenticated or encrypted
+ *
+ * Returns Pointer to the record or NULL
+ *
+ ******************************************************************************/
+tBTM_SEC_DEV_REC* btm_sec_find_dev_by_sec_state(uint8_t state) {
+ list_node_t* n = list_foreach(btm_cb.sec_dev_rec, is_sec_state_equal, &state);
+ if (n) return static_cast<tBTM_SEC_DEV_REC*>(list_node(n));
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_change_pairing_state
+ *
+ * Description This function is called to change pairing state
+ *
+ ******************************************************************************/
+static void btm_sec_change_pairing_state(tBTM_PAIRING_STATE new_state) {
+ tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
+
+ BTM_TRACE_EVENT("%s() Old: %s", __func__,
+ btm_pair_state_descr(btm_cb.pairing_state));
+ BTM_TRACE_EVENT("%s() New: %s pairing_flags:0x%x", __func__,
+ btm_pair_state_descr(new_state), btm_cb.pairing_flags);
+
+ btm_cb.pairing_state = new_state;
+
+ if (new_state == BTM_PAIR_STATE_IDLE) {
+ alarm_cancel(btm_cb.pairing_timer);
+
+ btm_cb.pairing_flags = 0;
+ btm_cb.pin_code_len = 0;
+
+ /* Make sure the the lcb shows we are not bonding */
+ l2cu_update_lcb_4_bonding(btm_cb.pairing_bda, false);
+
+ btm_restore_mode();
+ btm_sec_check_pending_reqs();
+ btm_inq_clear_ssp();
+
+ memset(btm_cb.pairing_bda, 0xFF, BD_ADDR_LEN);
+ } else {
+ /* If transitioning out of idle, mark the lcb as bonding */
+ if (old_state == BTM_PAIR_STATE_IDLE)
+ l2cu_update_lcb_4_bonding(btm_cb.pairing_bda, true);
+
+ alarm_set_on_queue(btm_cb.pairing_timer, BTM_SEC_TIMEOUT_VALUE * 1000,
+ btm_sec_pairing_timeout, NULL, btu_general_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_pair_state_descr
+ *
+ * Description Return state description for tracing
+ *
+ ******************************************************************************/
+static const char* btm_pair_state_descr(tBTM_PAIRING_STATE state) {
+ switch (state) {
+ case BTM_PAIR_STATE_IDLE:
+ return ("IDLE");
+ case BTM_PAIR_STATE_GET_REM_NAME:
+ return ("GET_REM_NAME");
+ case BTM_PAIR_STATE_WAIT_PIN_REQ:
+ return ("WAIT_PIN_REQ");
+ case BTM_PAIR_STATE_WAIT_LOCAL_PIN:
+ return ("WAIT_LOCAL_PIN");
+ case BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM:
+ return ("WAIT_NUM_CONFIRM");
+ case BTM_PAIR_STATE_KEY_ENTRY:
+ return ("KEY_ENTRY");
+ case BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP:
+ return ("WAIT_LOCAL_OOB_RSP");
+ case BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS:
+ return ("WAIT_LOCAL_IOCAPS");
+ case BTM_PAIR_STATE_INCOMING_SSP:
+ return ("INCOMING_SSP");
+ case BTM_PAIR_STATE_WAIT_AUTH_COMPLETE:
+ return ("WAIT_AUTH_COMPLETE");
+ case BTM_PAIR_STATE_WAIT_DISCONNECT:
+ return ("WAIT_DISCONNECT");
+ }
+
+ return ("???");
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_dev_rec_cback_event
+ *
+ * Description This function calls the callback function with the given
+ * result and clear the callback function.
+ *
+ * Parameters: void
+ *
+ ******************************************************************************/
+void btm_sec_dev_rec_cback_event(tBTM_SEC_DEV_REC* p_dev_rec, uint8_t res,
+ bool is_le_transport) {
+ tBTM_SEC_CALLBACK* p_callback = p_dev_rec->p_callback;
+
+ if (p_dev_rec->p_callback) {
+ p_dev_rec->p_callback = NULL;
+
+ if (is_le_transport)
+ (*p_callback)(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE,
+ p_dev_rec->p_ref_data, res);
+ else
+ (*p_callback)(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR,
+ p_dev_rec->p_ref_data, res);
+ }
+
+ btm_sec_check_pending_reqs();
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_queue_mx_request
+ *
+ * Description Return state description for tracing
+ *
+ ******************************************************************************/
+static bool btm_sec_queue_mx_request(BD_ADDR bd_addr, uint16_t psm,
+ bool is_orig, uint32_t mx_proto_id,
+ uint32_t mx_chan_id,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data) {
+ tBTM_SEC_QUEUE_ENTRY* p_e =
+ (tBTM_SEC_QUEUE_ENTRY*)osi_malloc(sizeof(tBTM_SEC_QUEUE_ENTRY));
+
+ p_e->psm = psm;
+ p_e->is_orig = is_orig;
+ p_e->p_callback = p_callback;
+ p_e->p_ref_data = p_ref_data;
+ p_e->mx_proto_id = mx_proto_id;
+ p_e->mx_chan_id = mx_chan_id;
+ p_e->transport = BT_TRANSPORT_BR_EDR;
+ p_e->sec_act = 0;
+
+ memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ BTM_TRACE_EVENT(
+ "%s() PSM: 0x%04x Is_Orig: %u mx_proto_id: %u mx_chan_id: %u",
+ __func__, psm, is_orig, mx_proto_id, mx_chan_id);
+
+ fixed_queue_enqueue(btm_cb.sec_pending_q, p_e);
+
+ return true;
+}
+
+static bool btm_sec_check_prefetch_pin(tBTM_SEC_DEV_REC* p_dev_rec) {
+ uint8_t major = (uint8_t)(p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK);
+ uint8_t minor = (uint8_t)(p_dev_rec->dev_class[2] & BTM_COD_MINOR_CLASS_MASK);
+ bool rv = false;
+
+ if ((major == BTM_COD_MAJOR_AUDIO) &&
+ ((minor == BTM_COD_MINOR_CONFM_HANDSFREE) ||
+ (minor == BTM_COD_MINOR_CAR_AUDIO))) {
+ BTM_TRACE_EVENT(
+ "%s() Skipping pre-fetch PIN for carkit COD Major: 0x%02x Minor: "
+ "0x%02x",
+ __func__, major, minor);
+
+ if (btm_cb.security_mode_changed == false) {
+ btm_cb.security_mode_changed = true;
+#ifdef APPL_AUTH_WRITE_EXCEPTION
+ if (!(APPL_AUTH_WRITE_EXCEPTION)(p_dev_rec->bd_addr))
+#endif
+ btsnd_hcic_write_auth_enable(true);
+ }
+ } else {
+ btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_LOCAL_PIN);
+
+ /* If we got a PIN, use that, else try to get one */
+ if (btm_cb.pin_code_len) {
+ BTM_PINCodeReply(p_dev_rec->bd_addr, BTM_SUCCESS, btm_cb.pin_code_len,
+ btm_cb.pin_code, p_dev_rec->trusted_mask);
+ } else {
+ /* pin was not supplied - pre-fetch pin code now */
+ if (btm_cb.api.p_pin_callback &&
+ ((btm_cb.pairing_flags & BTM_PAIR_FLAGS_PIN_REQD) == 0)) {
+ BTM_TRACE_DEBUG("%s() PIN code callback called", __func__);
+ if (btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR) == NULL)
+ btm_cb.pairing_flags |= BTM_PAIR_FLAGS_PIN_REQD;
+ (btm_cb.api.p_pin_callback)(
+ p_dev_rec->bd_addr, p_dev_rec->dev_class, p_dev_rec->sec_bd_name,
+ (p_dev_rec->p_cur_service == NULL)
+ ? false
+ : (p_dev_rec->p_cur_service->security_flags &
+ BTM_SEC_IN_MIN_16_DIGIT_PIN));
+ }
+ }
+
+ rv = true;
+ }
+
+ return rv;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_auth_payload_tout
+ *
+ * Description Processes the HCI Autheniticated Payload Timeout Event
+ * indicating that a packet containing a valid MIC on the
+ * connection handle was not received within the programmed
+ * timeout value. (Spec Default is 30 secs, but can be
+ * changed via the BTM_SecSetAuthPayloadTimeout() function.
+ *
+ ******************************************************************************/
+void btm_sec_auth_payload_tout(uint8_t* p, uint16_t hci_evt_len) {
+ uint16_t handle;
+
+ STREAM_TO_UINT16(handle, p);
+ handle = HCID_GET_HANDLE(handle);
+
+ /* Will be exposed to upper layers in the future if/when determined necessary
+ */
+ BTM_TRACE_ERROR("%s on handle 0x%02x", __func__, handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_queue_encrypt_request
+ *
+ * Description encqueue encryption request when device has active security
+ * process pending.
+ *
+ ******************************************************************************/
+static bool btm_sec_queue_encrypt_request(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport,
+ tBTM_SEC_CALLBACK* p_callback,
+ void* p_ref_data,
+ tBTM_BLE_SEC_ACT sec_act) {
+ tBTM_SEC_QUEUE_ENTRY* p_e =
+ (tBTM_SEC_QUEUE_ENTRY*)osi_malloc(sizeof(tBTM_SEC_QUEUE_ENTRY) + 1);
+
+ p_e->psm = 0; /* if PSM 0, encryption request */
+ p_e->p_callback = p_callback;
+ p_e->p_ref_data = p_ref_data;
+ p_e->transport = transport;
+ p_e->sec_act = sec_act;
+ memcpy(p_e->bd_addr, bd_addr, BD_ADDR_LEN);
+ fixed_queue_enqueue(btm_cb.sec_pending_q, p_e);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_set_peer_sec_caps
+ *
+ * Description This function is called to set sm4 and rmt_sec_caps fields
+ * based on the available peer device features.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_set_peer_sec_caps(tACL_CONN* p_acl_cb,
+ tBTM_SEC_DEV_REC* p_dev_rec) {
+ BD_ADDR rem_bd_addr;
+ uint8_t* p_rem_bd_addr;
+
+ if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
+ btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
+ btm_cb.security_mode == BTM_SEC_MODE_SC) &&
+ HCI_SSP_HOST_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[1])) {
+ p_dev_rec->sm4 = BTM_SM4_TRUE;
+ p_dev_rec->remote_supports_secure_connections =
+ (HCI_SC_HOST_SUPPORTED(p_acl_cb->peer_lmp_feature_pages[1]));
+ } else {
+ p_dev_rec->sm4 = BTM_SM4_KNOWN;
+ p_dev_rec->remote_supports_secure_connections = false;
+ }
+
+ BTM_TRACE_API("%s: sm4: 0x%02x, rmt_support_for_secure_connections %d",
+ __func__, p_dev_rec->sm4,
+ p_dev_rec->remote_supports_secure_connections);
+
+ if (p_dev_rec->remote_features_needed) {
+ BTM_TRACE_EVENT(
+ "%s: Now device in SC Only mode, waiting for peer remote features!",
+ __func__);
+ p_rem_bd_addr = (uint8_t*)rem_bd_addr;
+ BDADDR_TO_STREAM(p_rem_bd_addr, p_dev_rec->bd_addr);
+ p_rem_bd_addr = (uint8_t*)rem_bd_addr;
+ btm_io_capabilities_req(p_rem_bd_addr);
+ p_dev_rec->remote_features_needed = false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_is_serv_level0
+ *
+ * Description This function is called to check if the service
+ * corresponding to PSM is security mode 4 level 0 service.
+ *
+ * Returns true if the service is security mode 4 level 0 service
+ *
+ ******************************************************************************/
+static bool btm_sec_is_serv_level0(uint16_t psm) {
+ if (psm == BT_PSM_SDP) {
+ BTM_TRACE_DEBUG("%s: PSM: 0x%04x -> mode 4 level 0 service", __func__, psm);
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_check_pending_enc_req
+ *
+ * Description This function is called to send pending encryption callback
+ * if waiting
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btm_sec_check_pending_enc_req(tBTM_SEC_DEV_REC* p_dev_rec,
+ tBT_TRANSPORT transport,
+ uint8_t encr_enable) {
+ if (fixed_queue_is_empty(btm_cb.sec_pending_q)) return;
+
+ uint8_t res = encr_enable ? BTM_SUCCESS : BTM_ERR_PROCESSING;
+ list_t* list = fixed_queue_get_list(btm_cb.sec_pending_q);
+ for (const list_node_t* node = list_begin(list); node != list_end(list);) {
+ tBTM_SEC_QUEUE_ENTRY* p_e = (tBTM_SEC_QUEUE_ENTRY*)list_node(node);
+ node = list_next(node);
+
+ if (memcmp(p_e->bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0 &&
+ p_e->psm == 0 && p_e->transport == transport) {
+ if (encr_enable == 0 || transport == BT_TRANSPORT_BR_EDR ||
+ p_e->sec_act == BTM_BLE_SEC_ENCRYPT ||
+ p_e->sec_act == BTM_BLE_SEC_ENCRYPT_NO_MITM ||
+ (p_e->sec_act == BTM_BLE_SEC_ENCRYPT_MITM &&
+ p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED)) {
+ if (p_e->p_callback)
+ (*p_e->p_callback)(p_dev_rec->bd_addr, transport, p_e->p_ref_data,
+ res);
+ fixed_queue_try_remove_from_queue(btm_cb.sec_pending_q, (void*)p_e);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_set_serv_level4_flags
+ *
+ * Description This function is called to set security mode 4 level 4
+ * flags.
+ *
+ * Returns service security requirements updated to include secure
+ * connections only mode.
+ *
+ ******************************************************************************/
+static uint16_t btm_sec_set_serv_level4_flags(uint16_t cur_security,
+ bool is_originator) {
+ uint16_t sec_level4_flags =
+ is_originator ? BTM_SEC_OUT_LEVEL4_FLAGS : BTM_SEC_IN_LEVEL4_FLAGS;
+
+ return cur_security | sec_level4_flags;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_clear_ble_keys
+ *
+ * Description This function is called to clear out the BLE keys.
+ * Typically when devices are removed in BTM_SecDeleteDevice,
+ * or when a new BT Link key is generated.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btm_sec_clear_ble_keys(tBTM_SEC_DEV_REC* p_dev_rec) {
+ BTM_TRACE_DEBUG("%s() Clearing BLE Keys", __func__);
+ p_dev_rec->ble.key_type = BTM_LE_KEY_NONE;
+ memset(&p_dev_rec->ble.keys, 0, sizeof(tBTM_SEC_BLE_KEYS));
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_resolving_list_remove_dev(p_dev_rec);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_is_a_bonded_dev
+ *
+ * Description Is the specified device is a bonded device
+ *
+ * Returns true - dev is bonded
+ *
+ ******************************************************************************/
+bool btm_sec_is_a_bonded_dev(BD_ADDR bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ bool is_bonded = false;
+
+ if (p_dev_rec && ((p_dev_rec->ble.key_type &&
+ (p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_KNOWN)) ||
+ (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN))) {
+ is_bonded = true;
+ }
+ BTM_TRACE_DEBUG("%s() is_bonded=%d", __func__, is_bonded);
+ return (is_bonded);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_is_le_capable_dev
+ *
+ * Description Is the specified device is dual mode or LE only device
+ *
+ * Returns true - dev is a dual mode
+ *
+ ******************************************************************************/
+bool btm_sec_is_le_capable_dev(BD_ADDR bda) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ bool le_capable = false;
+
+ if (p_dev_rec &&
+ (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE)
+ le_capable = true;
+ return le_capable;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_use_smp_br_chnl
+ *
+ * Description The function checks if SMP BR connection can be used with
+ * the peer.
+ * Is called when authentication for dedicated bonding is
+ * successfully completed.
+ *
+ * Returns true - if SMP BR connection can be used (the link key is
+ * generated from P-256 and the peer supports Security
+ * Manager over BR).
+ *
+ ******************************************************************************/
+static bool btm_sec_use_smp_br_chnl(tBTM_SEC_DEV_REC* p_dev_rec) {
+ uint32_t ext_feat;
+ uint8_t chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+
+ BTM_TRACE_DEBUG("%s() link_key_type = 0x%x", __func__,
+ p_dev_rec->link_key_type);
+
+ if ((p_dev_rec->link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256) &&
+ (p_dev_rec->link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256))
+ return false;
+
+ if (!L2CA_GetPeerFeatures(p_dev_rec->bd_addr, &ext_feat, chnl_mask))
+ return false;
+
+ if (!(chnl_mask[0] & L2CAP_FIXED_CHNL_SMP_BR_BIT)) return false;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function btm_sec_is_master
+ *
+ * Description The function checks if the device is BR/EDR master after
+ * pairing is completed.
+ *
+ * Returns true - if the device is master.
+ *
+ ******************************************************************************/
+static bool btm_sec_is_master(tBTM_SEC_DEV_REC* p_dev_rec) {
+ tACL_CONN* p = btm_bda_to_acl(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
+ return (p && (p->link_role == BTM_ROLE_MASTER));
+}
diff --git a/mtkbt/code/bt/stack/btu/btu_hcif.cc b/mtkbt/code/bt/stack/btu/btu_hcif.cc
new file mode 100755
index 0000000..0fb63d4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btu/btu_hcif.cc
@@ -0,0 +1,1746 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions that interface with the HCI transport. On
+ * the receive side, it routes events to the appropriate handler, e.g.
+ * L2CAP, ScoMgr. On the transmit side, it manages the command
+ * transmission.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btu_hcif"
+
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hci_layer.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+using tracked_objects::Location;
+
+// TODO(zachoverflow): remove this horrible hack
+extern fixed_queue_t* btu_hci_msg_queue;
+
+extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_ble_test_command_complete(uint8_t* p);
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void btu_hcif_inquiry_comp_evt(uint8_t* p);
+static void btu_hcif_inquiry_result_evt(uint8_t* p);
+static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p);
+static void btu_hcif_extended_inquiry_result_evt(uint8_t* p);
+
+static void btu_hcif_connection_comp_evt(uint8_t* p);
+static void btu_hcif_connection_request_evt(uint8_t* p);
+static void btu_hcif_disconnection_comp_evt(uint8_t* p);
+static void btu_hcif_authentication_comp_evt(uint8_t* p);
+static void btu_hcif_rmt_name_request_comp_evt(uint8_t* p, uint16_t evt_len);
+static void btu_hcif_encryption_change_evt(uint8_t* p);
+static void btu_hcif_read_rmt_features_comp_evt(uint8_t* p);
+static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p);
+static void btu_hcif_read_rmt_version_comp_evt(uint8_t* p);
+static void btu_hcif_qos_setup_comp_evt(uint8_t* p);
+static void btu_hcif_command_complete_evt(BT_HDR* response, void* context);
+static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
+ void* context);
+static void btu_hcif_hardware_error_evt(uint8_t* p);
+static void btu_hcif_flush_occured_evt(void);
+static void btu_hcif_role_change_evt(uint8_t* p);
+static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p);
+static void btu_hcif_mode_change_evt(uint8_t* p);
+static void btu_hcif_pin_code_request_evt(uint8_t* p);
+static void btu_hcif_link_key_request_evt(uint8_t* p);
+static void btu_hcif_link_key_notification_evt(uint8_t* p);
+static void btu_hcif_loopback_command_evt(void);
+static void btu_hcif_data_buf_overflow_evt(void);
+static void btu_hcif_max_slots_changed_evt(void);
+static void btu_hcif_read_clock_off_comp_evt(uint8_t* p);
+static void btu_hcif_conn_pkt_type_change_evt(void);
+static void btu_hcif_qos_violation_evt(uint8_t* p);
+static void btu_hcif_page_scan_mode_change_evt(void);
+static void btu_hcif_page_scan_rep_mode_chng_evt(void);
+static void btu_hcif_esco_connection_comp_evt(uint8_t* p);
+static void btu_hcif_esco_connection_chg_evt(uint8_t* p);
+
+/* Simple Pairing Events */
+static void btu_hcif_host_support_evt(uint8_t* p);
+static void btu_hcif_io_cap_request_evt(uint8_t* p);
+static void btu_hcif_io_cap_response_evt(uint8_t* p);
+static void btu_hcif_user_conf_request_evt(uint8_t* p);
+static void btu_hcif_user_passkey_request_evt(uint8_t* p);
+static void btu_hcif_user_passkey_notif_evt(uint8_t* p);
+static void btu_hcif_keypress_notif_evt(uint8_t* p);
+static void btu_hcif_rem_oob_request_evt(uint8_t* p);
+
+static void btu_hcif_simple_pair_complete_evt(uint8_t* p);
+#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
+static void btu_hcif_enhanced_flush_complete_evt(void);
+#endif
+
+#if (BTM_SSR_INCLUDED == TRUE)
+static void btu_hcif_ssr_evt(uint8_t* p, uint16_t evt_len);
+#endif /* BTM_SSR_INCLUDED == TRUE */
+
+static void btu_ble_ll_conn_complete_evt(uint8_t* p, uint16_t evt_len);
+static void btu_ble_read_remote_feat_evt(uint8_t* p);
+static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len);
+static void btu_ble_proc_ltk_req(uint8_t* p);
+static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p);
+static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len);
+#if (BLE_LLT_INCLUDED == TRUE)
+static void btu_ble_rc_param_req_evt(uint8_t* p);
+#endif
+#if (BLE_PRIVACY_SPT == TRUE)
+static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len);
+#endif
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_process_event
+ *
+ * Description This function is called when an event is received from
+ * the Host Controller.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) {
+ uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint8_t hci_evt_code, hci_evt_len;
+ uint8_t ble_sub_code;
+ STREAM_TO_UINT8(hci_evt_code, p);
+ STREAM_TO_UINT8(hci_evt_len, p);
+
+ switch (hci_evt_code) {
+ case HCI_INQUIRY_COMP_EVT:
+ btu_hcif_inquiry_comp_evt(p);
+ break;
+ case HCI_INQUIRY_RESULT_EVT:
+ btu_hcif_inquiry_result_evt(p);
+ break;
+ case HCI_INQUIRY_RSSI_RESULT_EVT:
+ btu_hcif_inquiry_rssi_result_evt(p);
+ break;
+ case HCI_EXTENDED_INQUIRY_RESULT_EVT:
+ btu_hcif_extended_inquiry_result_evt(p);
+ break;
+ case HCI_CONNECTION_COMP_EVT:
+ btu_hcif_connection_comp_evt(p);
+ break;
+ case HCI_CONNECTION_REQUEST_EVT:
+ btu_hcif_connection_request_evt(p);
+ break;
+ case HCI_DISCONNECTION_COMP_EVT:
+ btu_hcif_disconnection_comp_evt(p);
+ break;
+ case HCI_AUTHENTICATION_COMP_EVT:
+ btu_hcif_authentication_comp_evt(p);
+ break;
+ case HCI_RMT_NAME_REQUEST_COMP_EVT:
+ btu_hcif_rmt_name_request_comp_evt(p, hci_evt_len);
+ break;
+ case HCI_ENCRYPTION_CHANGE_EVT:
+ btu_hcif_encryption_change_evt(p);
+ break;
+ case HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT:
+ btu_hcif_encryption_key_refresh_cmpl_evt(p);
+ break;
+ case HCI_READ_RMT_FEATURES_COMP_EVT:
+ btu_hcif_read_rmt_features_comp_evt(p);
+ break;
+ case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:
+ btu_hcif_read_rmt_ext_features_comp_evt(p);
+ break;
+ case HCI_READ_RMT_VERSION_COMP_EVT:
+ btu_hcif_read_rmt_version_comp_evt(p);
+ break;
+ case HCI_QOS_SETUP_COMP_EVT:
+ btu_hcif_qos_setup_comp_evt(p);
+ break;
+ case HCI_COMMAND_COMPLETE_EVT:
+ LOG_ERROR(LOG_TAG,
+ "%s should not have received a command complete event. "
+ "Someone didn't go through the hci transmit_command function.",
+ __func__);
+ break;
+ case HCI_COMMAND_STATUS_EVT:
+ LOG_ERROR(LOG_TAG,
+ "%s should not have received a command status event. "
+ "Someone didn't go through the hci transmit_command function.",
+ __func__);
+ break;
+ case HCI_HARDWARE_ERROR_EVT:
+ btu_hcif_hardware_error_evt(p);
+ break;
+ case HCI_FLUSH_OCCURED_EVT:
+ btu_hcif_flush_occured_evt();
+ break;
+ case HCI_ROLE_CHANGE_EVT:
+ btu_hcif_role_change_evt(p);
+ break;
+ case HCI_NUM_COMPL_DATA_PKTS_EVT:
+ btu_hcif_num_compl_data_pkts_evt(p);
+ break;
+ case HCI_MODE_CHANGE_EVT:
+ btu_hcif_mode_change_evt(p);
+ break;
+ case HCI_PIN_CODE_REQUEST_EVT:
+ btu_hcif_pin_code_request_evt(p);
+ break;
+ case HCI_LINK_KEY_REQUEST_EVT:
+ btu_hcif_link_key_request_evt(p);
+ break;
+ case HCI_LINK_KEY_NOTIFICATION_EVT:
+ btu_hcif_link_key_notification_evt(p);
+ break;
+ case HCI_LOOPBACK_COMMAND_EVT:
+ btu_hcif_loopback_command_evt();
+ break;
+ case HCI_DATA_BUF_OVERFLOW_EVT:
+ btu_hcif_data_buf_overflow_evt();
+ break;
+ case HCI_MAX_SLOTS_CHANGED_EVT:
+ btu_hcif_max_slots_changed_evt();
+ break;
+ case HCI_READ_CLOCK_OFF_COMP_EVT:
+ btu_hcif_read_clock_off_comp_evt(p);
+ break;
+ case HCI_CONN_PKT_TYPE_CHANGE_EVT:
+ btu_hcif_conn_pkt_type_change_evt();
+ break;
+ case HCI_QOS_VIOLATION_EVT:
+ btu_hcif_qos_violation_evt(p);
+ break;
+ case HCI_PAGE_SCAN_MODE_CHANGE_EVT:
+ btu_hcif_page_scan_mode_change_evt();
+ break;
+ case HCI_PAGE_SCAN_REP_MODE_CHNG_EVT:
+ btu_hcif_page_scan_rep_mode_chng_evt();
+ break;
+ case HCI_ESCO_CONNECTION_COMP_EVT:
+ btu_hcif_esco_connection_comp_evt(p);
+ break;
+ case HCI_ESCO_CONNECTION_CHANGED_EVT:
+ btu_hcif_esco_connection_chg_evt(p);
+ break;
+#if (BTM_SSR_INCLUDED == TRUE)
+ case HCI_SNIFF_SUB_RATE_EVT:
+ btu_hcif_ssr_evt(p, hci_evt_len);
+ break;
+#endif /* BTM_SSR_INCLUDED == TRUE */
+ case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT:
+ btu_hcif_host_support_evt(p);
+ break;
+ case HCI_IO_CAPABILITY_REQUEST_EVT:
+ btu_hcif_io_cap_request_evt(p);
+ break;
+ case HCI_IO_CAPABILITY_RESPONSE_EVT:
+ btu_hcif_io_cap_response_evt(p);
+ break;
+ case HCI_USER_CONFIRMATION_REQUEST_EVT:
+ btu_hcif_user_conf_request_evt(p);
+ break;
+ case HCI_USER_PASSKEY_REQUEST_EVT:
+ btu_hcif_user_passkey_request_evt(p);
+ break;
+ case HCI_REMOTE_OOB_DATA_REQUEST_EVT:
+ btu_hcif_rem_oob_request_evt(p);
+ break;
+ case HCI_SIMPLE_PAIRING_COMPLETE_EVT:
+ btu_hcif_simple_pair_complete_evt(p);
+ break;
+ case HCI_USER_PASSKEY_NOTIFY_EVT:
+ btu_hcif_user_passkey_notif_evt(p);
+ break;
+ case HCI_KEYPRESS_NOTIFY_EVT:
+ btu_hcif_keypress_notif_evt(p);
+ break;
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ case HCI_ENHANCED_FLUSH_COMPLETE_EVT:
+ btu_hcif_enhanced_flush_complete_evt();
+ break;
+#endif
+
+ case HCI_BLE_EVENT: {
+ STREAM_TO_UINT8(ble_sub_code, p);
+
+ HCI_TRACE_EVENT("BLE HCI(id=%d) event = 0x%02x)", hci_evt_code,
+ ble_sub_code);
+
+ uint8_t ble_evt_len = hci_evt_len - 1;
+ switch (ble_sub_code) {
+ case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */
+ HCI_TRACE_EVENT("HCI_BLE_ADV_PKT_RPT_EVT");
+ btm_ble_process_adv_pkt(ble_evt_len, p);
+ break;
+ case HCI_BLE_CONN_COMPLETE_EVT:
+ btu_ble_ll_conn_complete_evt(p, hci_evt_len);
+ break;
+ case HCI_BLE_LL_CONN_PARAM_UPD_EVT:
+ btu_ble_ll_conn_param_upd_evt(p, hci_evt_len);
+ break;
+ case HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT:
+ btu_ble_read_remote_feat_evt(p);
+ break;
+ case HCI_BLE_LTK_REQ_EVT: /* received only at slave device */
+ btu_ble_proc_ltk_req(p);
+ break;
+#if (BLE_PRIVACY_SPT == TRUE)
+ case HCI_BLE_ENHANCED_CONN_COMPLETE_EVT:
+ btu_ble_proc_enhanced_conn_cmpl(p, hci_evt_len);
+ break;
+#endif
+#if (BLE_LLT_INCLUDED == TRUE)
+ case HCI_BLE_RC_PARAM_REQ_EVT:
+ btu_ble_rc_param_req_evt(p);
+ break;
+#endif
+ case HCI_BLE_DATA_LENGTH_CHANGE_EVT:
+ btu_ble_data_length_change_evt(p, hci_evt_len);
+ break;
+
+ case HCI_LE_PHY_UPDATE_COMPLETE_EVT:
+ btm_ble_process_phy_update_pkt(ble_evt_len, p);
+ break;
+
+ case HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT:
+ btm_ble_process_ext_adv_pkt(hci_evt_len, p);
+ break;
+
+ case HCI_LE_ADVERTISING_SET_TERMINATED_EVT:
+ btm_le_on_advertising_set_terminated(p, hci_evt_len);
+ break;
+ }
+ break;
+ }
+
+ case HCI_VENDOR_SPECIFIC_EVT:
+ btm_vendor_specific_evt(p, hci_evt_len);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_send_cmd
+ *
+ * Description This function is called to send commands to the Host
+ * Controller.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) {
+ if (!p_buf) return;
+
+ uint16_t opcode;
+ uint8_t* stream = p_buf->data + p_buf->offset;
+ void* vsc_callback = NULL;
+
+ STREAM_TO_UINT16(opcode, stream);
+
+ // Eww...horrible hackery here
+ /* If command was a VSC, then extract command_complete callback */
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC ||
+ (opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) {
+ vsc_callback = *((void**)(p_buf + 1));
+ }
+
+ hci_layer_get_interface()->transmit_command(
+ p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
+ vsc_callback);
+}
+
+using hci_cmd_cb = base::Callback<void(uint8_t* /* return_parameters */,
+ uint16_t /* return_parameters_length*/)>;
+
+struct cmd_with_cb_data {
+ hci_cmd_cb cb;
+ Location posted_from;
+};
+
+void cmd_with_cb_data_init(cmd_with_cb_data* cb_wrapper) {
+ new (&cb_wrapper->cb) hci_cmd_cb;
+ new (&cb_wrapper->posted_from) Location;
+}
+
+void cmd_with_cb_data_cleanup(cmd_with_cb_data* cb_wrapper) {
+ cb_wrapper->cb.~hci_cmd_cb();
+ cb_wrapper->posted_from.~Location();
+}
+
+static void btu_hcif_command_complete_evt_with_cb_on_task(BT_HDR* event) {
+ command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
+
+ command_opcode_t opcode;
+ uint8_t* stream =
+ hack->response->data + hack->response->offset +
+ 3; // 2 to skip the event headers, 1 to skip the command credits
+ STREAM_TO_UINT16(opcode, stream);
+
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ HCI_TRACE_DEBUG("command complete for: %s",
+ cb_wrapper->posted_from.ToString().c_str());
+ cb_wrapper->cb.Run(stream, hack->response->len - 5);
+ cmd_with_cb_data_cleanup(cb_wrapper);
+ osi_free(cb_wrapper);
+
+ osi_free(hack->response);
+ osi_free(event);
+}
+
+static void btu_hcif_command_complete_evt_with_cb(BT_HDR* response,
+ void* context) {
+ BT_HDR* event = static_cast<BT_HDR*>(
+ osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
+ command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
+
+ hack->callback = btu_hcif_command_complete_evt_with_cb_on_task;
+ hack->response = response;
+ hack->context = context;
+ event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+ fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+static void btu_hcif_command_status_evt_with_cb_on_task(BT_HDR* event) {
+ command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
+
+ command_opcode_t opcode;
+ uint8_t* stream = hack->command->data + hack->command->offset;
+ STREAM_TO_UINT16(opcode, stream);
+
+ CHECK(hack->status != 0);
+
+ // report command status error
+ cmd_with_cb_data* cb_wrapper = (cmd_with_cb_data*)hack->context;
+ HCI_TRACE_DEBUG("command status for: %s",
+ cb_wrapper->posted_from.ToString().c_str());
+ cb_wrapper->cb.Run(&hack->status, sizeof(uint16_t));
+ cmd_with_cb_data_cleanup(cb_wrapper);
+ osi_free(cb_wrapper);
+
+ osi_free(hack->command);
+ osi_free(event);
+}
+
+static void btu_hcif_command_status_evt_with_cb(uint8_t status, BT_HDR* command,
+ void* context) {
+ // Command is pending, we report only error.
+ if (!status) {
+ osi_free(command);
+ return;
+ }
+
+ BT_HDR* event = static_cast<BT_HDR*>(
+ osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
+ command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
+
+ hack->callback = btu_hcif_command_status_evt_with_cb_on_task;
+ hack->status = status;
+ hack->command = command;
+ hack->context = context;
+
+ event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+ fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+/* This function is called to send commands to the Host Controller. |cb| is
+ * called when command status event is called with error code, or when the
+ * command complete event is received. */
+void btu_hcif_send_cmd_with_cb(const tracked_objects::Location& posted_from,
+ uint16_t opcode, uint8_t* params,
+ uint8_t params_len, hci_cmd_cb cb) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + params_len;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, opcode);
+ UINT8_TO_STREAM(pp, params_len);
+ if (params) {
+ memcpy(pp, params, params_len);
+ }
+
+ cmd_with_cb_data* cb_wrapper =
+ (cmd_with_cb_data*)osi_malloc(sizeof(cmd_with_cb_data));
+
+ cmd_with_cb_data_init(cb_wrapper);
+ cb_wrapper->cb = cb;
+ cb_wrapper->posted_from = posted_from;
+
+ hci_layer_get_interface()->transmit_command(
+ p, btu_hcif_command_complete_evt_with_cb,
+ btu_hcif_command_status_evt_with_cb, (void*)cb_wrapper);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_inquiry_comp_evt
+ *
+ * Description Process event HCI_INQUIRY_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_inquiry_comp_evt(uint8_t* p) {
+ uint8_t status;
+
+ STREAM_TO_UINT8(status, p);
+
+ /* Tell inquiry processing that we are done */
+ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_inquiry_result_evt
+ *
+ * Description Process event HCI_INQUIRY_RESULT_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_inquiry_result_evt(uint8_t* p) {
+ /* Store results in the cache */
+ btm_process_inq_results(p, BTM_INQ_RESULT_STANDARD);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_inquiry_rssi_result_evt
+ *
+ * Description Process event HCI_INQUIRY_RSSI_RESULT_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_inquiry_rssi_result_evt(uint8_t* p) {
+ /* Store results in the cache */
+ btm_process_inq_results(p, BTM_INQ_RESULT_WITH_RSSI);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_extended_inquiry_result_evt
+ *
+ * Description Process event HCI_EXTENDED_INQUIRY_RESULT_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_extended_inquiry_result_evt(uint8_t* p) {
+ /* Store results in the cache */
+ btm_process_inq_results(p, BTM_INQ_RESULT_EXTENDED);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_connection_comp_evt
+ *
+ * Description Process event HCI_CONNECTION_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_connection_comp_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+ BD_ADDR bda;
+ uint8_t link_type;
+ uint8_t enc_mode;
+#if (BTM_SCO_INCLUDED == TRUE)
+ tBTM_ESCO_DATA esco_data;
+#endif
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_UINT8(link_type, p);
+ STREAM_TO_UINT8(enc_mode, p);
+
+ handle = HCID_GET_HANDLE(handle);
+
+ if (link_type == HCI_LINK_TYPE_ACL) {
+ btm_sec_connected(bda, handle, status, enc_mode);
+
+ l2c_link_hci_conn_comp(status, handle, bda);
+ }
+#if (BTM_SCO_INCLUDED == TRUE)
+ else {
+ memset(&esco_data, 0, sizeof(tBTM_ESCO_DATA));
+ /* esco_data.link_type = HCI_LINK_TYPE_SCO; already zero */
+ memcpy(esco_data.bd_addr, bda, BD_ADDR_LEN);
+ btm_sco_connected(status, bda, handle, &esco_data);
+ }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_connection_request_evt
+ *
+ * Description Process event HCI_CONNECTION_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_connection_request_evt(uint8_t* p) {
+ BD_ADDR bda;
+ DEV_CLASS dc;
+ uint8_t link_type;
+
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_DEVCLASS(dc, p);
+ STREAM_TO_UINT8(link_type, p);
+
+ /* Pass request to security manager to check connect filters before */
+ /* passing request to l2cap */
+ if (link_type == HCI_LINK_TYPE_ACL) {
+ btm_sec_conn_req(bda, dc);
+ }
+#if (BTM_SCO_INCLUDED == TRUE)
+ else {
+ btm_sco_conn_req(bda, dc, link_type);
+ }
+#endif /* BTM_SCO_INCLUDED */
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_disconnection_comp_evt
+ *
+ * Description Process event HCI_DISCONNECTION_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_disconnection_comp_evt(uint8_t* p) {
+ uint16_t handle;
+ uint8_t reason;
+
+ ++p;
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(reason, p);
+
+ handle = HCID_GET_HANDLE(handle);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ /* If L2CAP doesn't know about it, send it to SCO */
+ if (!l2c_link_hci_disc_comp(handle, reason)) btm_sco_removed(handle, reason);
+#else
+ l2c_link_hci_disc_comp(handle, reason);
+#endif /* BTM_SCO_INCLUDED */
+
+ /* Notify security manager */
+ btm_sec_disconnected(handle, reason);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_authentication_comp_evt
+ *
+ * Description Process event HCI_AUTHENTICATION_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_authentication_comp_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+
+ btm_sec_auth_complete(handle, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_rmt_name_request_comp_evt
+ *
+ * Description Process event HCI_RMT_NAME_REQUEST_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_rmt_name_request_comp_evt(uint8_t* p, uint16_t evt_len) {
+ uint8_t status;
+ BD_ADDR bd_addr;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_BDADDR(bd_addr, p);
+
+ evt_len -= (1 + BD_ADDR_LEN);
+
+ btm_process_remote_name(bd_addr, p, evt_len, status);
+
+ btm_sec_rmt_name_request_complete(bd_addr, p, status);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_encryption_change_evt
+ *
+ * Description Process event HCI_ENCRYPTION_CHANGE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_encryption_change_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+ uint8_t encr_enable;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(encr_enable, p);
+
+ btm_acl_encrypt_change(handle, status, encr_enable);
+ btm_sec_encrypt_change(handle, status, encr_enable);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_read_rmt_features_comp_evt
+ *
+ * Description Process event HCI_READ_RMT_FEATURES_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_read_rmt_features_comp_evt(uint8_t* p) {
+ btm_read_remote_features_complete(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_read_rmt_ext_features_comp_evt
+ *
+ * Description Process event HCI_READ_RMT_EXT_FEATURES_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_read_rmt_ext_features_comp_evt(uint8_t* p) {
+ uint8_t* p_cur = p;
+ uint8_t status;
+ uint16_t handle;
+
+ STREAM_TO_UINT8(status, p_cur);
+
+ if (status == HCI_SUCCESS)
+ btm_read_remote_ext_features_complete(p);
+ else {
+ STREAM_TO_UINT16(handle, p_cur);
+ btm_read_remote_ext_features_failed(status, handle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_read_rmt_version_comp_evt
+ *
+ * Description Process event HCI_READ_RMT_VERSION_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_read_rmt_version_comp_evt(uint8_t* p) {
+ btm_read_remote_version_complete(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_qos_setup_comp_evt
+ *
+ * Description Process event HCI_QOS_SETUP_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_qos_setup_comp_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+ FLOW_SPEC flow;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(flow.qos_flags, p);
+ STREAM_TO_UINT8(flow.service_type, p);
+ STREAM_TO_UINT32(flow.token_rate, p);
+ STREAM_TO_UINT32(flow.peak_bandwidth, p);
+ STREAM_TO_UINT32(flow.latency, p);
+ STREAM_TO_UINT32(flow.delay_variation, p);
+
+ btm_qos_setup_complete(status, handle, &flow);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_esco_connection_comp_evt
+ *
+ * Description Process event HCI_ESCO_CONNECTION_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_esco_connection_comp_evt(uint8_t* p) {
+#if (BTM_SCO_INCLUDED == TRUE)
+ tBTM_ESCO_DATA data;
+ uint16_t handle;
+ BD_ADDR bda;
+ uint8_t status;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_BDADDR(bda, p);
+
+ STREAM_TO_UINT8(data.link_type, p);
+ STREAM_TO_UINT8(data.tx_interval, p);
+ STREAM_TO_UINT8(data.retrans_window, p);
+ STREAM_TO_UINT16(data.rx_pkt_len, p);
+ STREAM_TO_UINT16(data.tx_pkt_len, p);
+ STREAM_TO_UINT8(data.air_mode, p);
+
+ memcpy(data.bd_addr, bda, BD_ADDR_LEN);
+ btm_sco_connected(status, bda, handle, &data);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_esco_connection_chg_evt
+ *
+ * Description Process event HCI_ESCO_CONNECTION_CHANGED_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_esco_connection_chg_evt(uint8_t* p) {
+#if (BTM_SCO_INCLUDED == TRUE)
+ uint16_t handle;
+ uint16_t tx_pkt_len;
+ uint16_t rx_pkt_len;
+ uint8_t status;
+ uint8_t tx_interval;
+ uint8_t retrans_window;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+
+ STREAM_TO_UINT8(tx_interval, p);
+ STREAM_TO_UINT8(retrans_window, p);
+ STREAM_TO_UINT16(rx_pkt_len, p);
+ STREAM_TO_UINT16(tx_pkt_len, p);
+
+ btm_esco_proc_conn_chg(status, handle, tx_interval, retrans_window,
+ rx_pkt_len, tx_pkt_len);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_hdl_command_complete
+ *
+ * Description Handle command complete event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p,
+ uint16_t evt_len,
+ void* p_cplt_cback) {
+ switch (opcode) {
+ case HCI_INQUIRY_CANCEL:
+ /* Tell inquiry processing that we are done */
+ btm_process_cancel_complete(HCI_SUCCESS, BTM_BR_INQUIRY_MASK);
+ break;
+ case HCI_SET_EVENT_FILTER:
+ btm_event_filter_complete(p);
+ break;
+
+ case HCI_DELETE_STORED_LINK_KEY:
+ btm_delete_stored_link_key_complete(p);
+ break;
+
+ case HCI_READ_LOCAL_NAME:
+ btm_read_local_name_complete(p, evt_len);
+ break;
+
+ case HCI_GET_LINK_QUALITY:
+ btm_read_link_quality_complete(p);
+ break;
+
+ case HCI_READ_RSSI:
+ btm_read_rssi_complete(p);
+ break;
+
+ case HCI_READ_TRANSMIT_POWER_LEVEL:
+ btm_read_tx_power_complete(p, false);
+ break;
+
+ case HCI_CREATE_CONNECTION_CANCEL:
+ btm_create_conn_cancel_complete(p);
+ break;
+
+ case HCI_READ_LOCAL_OOB_DATA:
+ btm_read_local_oob_complete(p);
+ break;
+
+ case HCI_READ_INQ_TX_POWER_LEVEL:
+ btm_read_inq_tx_power_complete(p);
+ break;
+
+ /* BLE Commands sComplete*/
+ case HCI_BLE_ADD_WHITE_LIST:
+ btm_ble_add_2_white_list_complete(*p);
+ break;
+
+ case HCI_BLE_CLEAR_WHITE_LIST:
+ btm_ble_clear_white_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_REMOVE_WHITE_LIST:
+ btm_ble_remove_from_white_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_RAND:
+ case HCI_BLE_ENCRYPT:
+ btm_ble_rand_enc_complete(p, opcode, (tBTM_RAND_ENC_CB*)p_cplt_cback);
+ break;
+
+ case HCI_BLE_READ_ADV_CHNL_TX_POWER:
+ btm_read_tx_power_complete(p, true);
+ break;
+
+ case HCI_BLE_WRITE_ADV_ENABLE:
+ btm_ble_write_adv_enable_complete(p);
+ break;
+
+ case HCI_BLE_CREATE_LL_CONN:
+ btm_ble_create_ll_conn_complete(*p);
+ break;
+
+ case HCI_BLE_TRANSMITTER_TEST:
+ case HCI_BLE_RECEIVER_TEST:
+ case HCI_BLE_TEST_END:
+ btm_ble_test_command_complete(p);
+ break;
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ case HCI_BLE_ADD_DEV_RESOLVING_LIST:
+ btm_ble_add_resolving_list_entry_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_RM_DEV_RESOLVING_LIST:
+ btm_ble_remove_resolving_list_entry_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_CLEAR_RESOLVING_LIST:
+ btm_ble_clear_resolving_list_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_READ_RESOLVABLE_ADDR_PEER:
+ btm_ble_read_resolving_list_entry_complete(p, evt_len);
+ break;
+
+ case HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL:
+ case HCI_BLE_SET_ADDR_RESOLUTION_ENABLE:
+ case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT:
+ break;
+#endif
+ default:
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete(p, opcode, evt_len, (tBTM_CMPL_CB*)p_cplt_cback);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_command_complete_evt
+ *
+ * Description Process event HCI_COMMAND_COMPLETE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_command_complete_evt_on_task(BT_HDR* event) {
+ command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
+
+ command_opcode_t opcode;
+ uint8_t* stream =
+ hack->response->data + hack->response->offset +
+ 3; // 2 to skip the event headers, 1 to skip the command credits
+ STREAM_TO_UINT16(opcode, stream);
+
+ btu_hcif_hdl_command_complete(
+ opcode, stream,
+ hack->response->len -
+ 5, // 3 for the command complete headers, 2 for the event headers
+ hack->context);
+
+ osi_free(hack->response);
+ osi_free(event);
+}
+
+static void btu_hcif_command_complete_evt(BT_HDR* response, void* context) {
+ BT_HDR* event = static_cast<BT_HDR*>(
+ osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t)));
+ command_complete_hack_t* hack = (command_complete_hack_t*)&event->data[0];
+
+ hack->callback = btu_hcif_command_complete_evt_on_task;
+ hack->response = response;
+ hack->context = context;
+
+ event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+ fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_hdl_command_status
+ *
+ * Description Handle a command status event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_hdl_command_status(uint16_t opcode, uint8_t status,
+ uint8_t* p_cmd,
+ void* p_vsc_status_cback) {
+ BD_ADDR bd_addr;
+ uint16_t handle;
+#if (BTM_SCO_INCLUDED == TRUE)
+ tBTM_ESCO_DATA esco_data;
+#endif
+
+ switch (opcode) {
+ case HCI_EXIT_SNIFF_MODE:
+ case HCI_EXIT_PARK_MODE:
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ if (status != HCI_SUCCESS) {
+ /* Allow SCO initiation to continue if waiting for change mode event */
+ if (p_cmd != NULL) {
+ p_cmd++; /* bypass length field */
+ STREAM_TO_UINT16(handle, p_cmd);
+ btm_sco_chk_pend_unpark(status, handle);
+ }
+ }
+#endif
+ /* Case Falls Through */
+
+ case HCI_HOLD_MODE:
+ case HCI_SNIFF_MODE:
+ case HCI_PARK_MODE:
+ btm_pm_proc_cmd_status(status);
+ break;
+
+ default:
+ /* If command failed to start, we may need to tell BTM */
+ if (status != HCI_SUCCESS) {
+ switch (opcode) {
+ case HCI_INQUIRY:
+ /* Tell inquiry processing that we are done */
+ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK);
+ break;
+
+ case HCI_RMT_NAME_REQUEST:
+ /* Tell inquiry processing that we are done */
+ btm_process_remote_name(NULL, NULL, 0, status);
+
+ btm_sec_rmt_name_request_complete(NULL, NULL, status);
+ break;
+
+ case HCI_QOS_SETUP_COMP_EVT:
+ /* Tell qos setup that we are done */
+ btm_qos_setup_complete(status, 0, NULL);
+ break;
+
+ case HCI_SWITCH_ROLE:
+ /* Tell BTM that the command failed */
+ /* read bd addr out of stored command */
+ if (p_cmd != NULL) {
+ p_cmd++;
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ btm_acl_role_changed(status, bd_addr, BTM_ROLE_UNDEFINED);
+ } else
+ btm_acl_role_changed(status, NULL, BTM_ROLE_UNDEFINED);
+ l2c_link_role_changed(NULL, BTM_ROLE_UNDEFINED,
+ HCI_ERR_COMMAND_DISALLOWED);
+ break;
+
+ case HCI_CREATE_CONNECTION:
+ /* read bd addr out of stored command */
+ if (p_cmd != NULL) {
+ p_cmd++;
+ STREAM_TO_BDADDR(bd_addr, p_cmd);
+ btm_sec_connected(bd_addr, HCI_INVALID_HANDLE, status, 0);
+ l2c_link_hci_conn_comp(status, HCI_INVALID_HANDLE, bd_addr);
+ }
+ break;
+
+ case HCI_READ_RMT_EXT_FEATURES:
+ if (p_cmd != NULL) {
+ p_cmd++; /* skip command length */
+ STREAM_TO_UINT16(handle, p_cmd);
+ } else
+ handle = HCI_INVALID_HANDLE;
+
+ btm_read_remote_ext_features_failed(status, handle);
+ break;
+
+ case HCI_AUTHENTICATION_REQUESTED:
+ /* Device refused to start authentication. That should be treated
+ * as authentication failure. */
+ btm_sec_auth_complete(BTM_INVALID_HCI_HANDLE, status);
+ break;
+
+ case HCI_SET_CONN_ENCRYPTION:
+ /* Device refused to start encryption. That should be treated as
+ * encryption failure. */
+ btm_sec_encrypt_change(BTM_INVALID_HCI_HANDLE, status, false);
+ break;
+
+ case HCI_BLE_CREATE_LL_CONN:
+ btm_ble_create_ll_conn_complete(status);
+ break;
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ case HCI_SETUP_ESCO_CONNECTION:
+ case HCI_ENH_SETUP_ESCO_CONNECTION:
+ /* read handle out of stored command */
+ if (p_cmd != NULL) {
+ p_cmd++;
+ STREAM_TO_UINT16(handle, p_cmd);
+
+ /* Determine if initial connection failed or is a change
+ * of setup */
+ if (btm_is_sco_active(handle))
+ btm_esco_proc_conn_chg(status, handle, 0, 0, 0, 0);
+ else
+ btm_sco_connected(status, NULL, handle, &esco_data);
+ }
+ break;
+#endif
+
+ /* This is commented out until an upper layer cares about returning
+ event
+ #if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ case HCI_ENHANCED_FLUSH:
+ break;
+ #endif
+ */
+ default:
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete(&status, opcode, 1,
+ (tBTM_CMPL_CB*)p_vsc_status_cback);
+ break;
+ }
+
+ } else {
+ if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC)
+ btm_vsc_complete(&status, opcode, 1,
+ (tBTM_CMPL_CB*)p_vsc_status_cback);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_command_status_evt
+ *
+ * Description Process event HCI_COMMAND_STATUS_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_command_status_evt_on_task(BT_HDR* event) {
+ command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
+
+ command_opcode_t opcode;
+ uint8_t* stream = hack->command->data + hack->command->offset;
+ STREAM_TO_UINT16(opcode, stream);
+
+ btu_hcif_hdl_command_status(opcode, hack->status, stream, hack->context);
+
+ osi_free(hack->command);
+ osi_free(event);
+}
+
+static void btu_hcif_command_status_evt(uint8_t status, BT_HDR* command,
+ void* context) {
+ BT_HDR* event = static_cast<BT_HDR*>(
+ osi_calloc(sizeof(BT_HDR) + sizeof(command_status_hack_t)));
+ command_status_hack_t* hack = (command_status_hack_t*)&event->data[0];
+
+ hack->callback = btu_hcif_command_status_evt_on_task;
+ hack->status = status;
+ hack->command = command;
+ hack->context = context;
+
+ event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK;
+
+ fixed_queue_enqueue(btu_hci_msg_queue, event);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_hardware_error_evt
+ *
+ * Description Process event HCI_HARDWARE_ERROR_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_hardware_error_evt(uint8_t* p) {
+ HCI_TRACE_ERROR("Ctlr H/w error event - code:0x%x", *p);
+
+ /* If anyone wants device status notifications, give him one. */
+ btm_report_device_status(BTM_DEV_STATUS_DOWN);
+
+ /* Reset the controller */
+ if (BTM_IsDeviceUp()) BTM_DeviceReset(NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_flush_occured_evt
+ *
+ * Description Process event HCI_FLUSH_OCCURED_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_flush_occured_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_role_change_evt
+ *
+ * Description Process event HCI_ROLE_CHANGE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_role_change_evt(uint8_t* p) {
+ uint8_t status;
+ BD_ADDR bda;
+ uint8_t role;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_UINT8(role, p);
+
+ l2c_link_role_changed(bda, role, status);
+ btm_acl_role_changed(status, bda, role);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_num_compl_data_pkts_evt
+ *
+ * Description Process event HCI_NUM_COMPL_DATA_PKTS_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_num_compl_data_pkts_evt(uint8_t* p) {
+ /* Process for L2CAP and SCO */
+ l2c_link_process_num_completed_pkts(p);
+
+ /* Send on to SCO */
+ /*?? No SCO for now */
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_mode_change_evt
+ *
+ * Description Process event HCI_MODE_CHANGE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_mode_change_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+ uint8_t current_mode;
+ uint16_t interval;
+
+ STREAM_TO_UINT8(status, p);
+
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(current_mode, p);
+ STREAM_TO_UINT16(interval, p);
+#if (BTM_SCO_WAKE_PARKED_LINK == TRUE)
+ btm_sco_chk_pend_unpark(status, handle);
+#endif
+ btm_pm_proc_mode_change(status, handle, current_mode, interval);
+
+#if (HID_DEV_INCLUDED == TRUE && HID_DEV_PM_INCLUDED == TRUE)
+ hidd_pm_proc_mode_change(status, current_mode, interval);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_ssr_evt
+ *
+ * Description Process event HCI_SNIFF_SUB_RATE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+static void btu_hcif_ssr_evt(uint8_t* p, uint16_t evt_len) {
+ btm_pm_proc_ssr_evt(p, evt_len);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_pin_code_request_evt
+ *
+ * Description Process event HCI_PIN_CODE_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_pin_code_request_evt(uint8_t* p) {
+ BD_ADDR bda;
+
+ STREAM_TO_BDADDR(bda, p);
+
+ /* Tell L2CAP that there was a PIN code request, */
+ /* it may need to stretch timeouts */
+ l2c_pin_code_request(bda);
+
+ btm_sec_pin_code_request(bda);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_link_key_request_evt
+ *
+ * Description Process event HCI_LINK_KEY_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_link_key_request_evt(uint8_t* p) {
+ BD_ADDR bda;
+
+ STREAM_TO_BDADDR(bda, p);
+ btm_sec_link_key_request(bda);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_link_key_notification_evt
+ *
+ * Description Process event HCI_LINK_KEY_NOTIFICATION_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_link_key_notification_evt(uint8_t* p) {
+ BD_ADDR bda;
+ LINK_KEY key;
+ uint8_t key_type;
+
+ STREAM_TO_BDADDR(bda, p);
+ STREAM_TO_ARRAY16(key, p);
+ STREAM_TO_UINT8(key_type, p);
+
+ btm_sec_link_key_notification(bda, key, key_type);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_loopback_command_evt
+ *
+ * Description Process event HCI_LOOPBACK_COMMAND_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_loopback_command_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_data_buf_overflow_evt
+ *
+ * Description Process event HCI_DATA_BUF_OVERFLOW_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_data_buf_overflow_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_max_slots_changed_evt
+ *
+ * Description Process event HCI_MAX_SLOTS_CHANGED_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_max_slots_changed_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_read_clock_off_comp_evt
+ *
+ * Description Process event HCI_READ_CLOCK_OFF_COMP_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_read_clock_off_comp_evt(uint8_t* p) {
+ uint8_t status;
+ uint16_t handle;
+ uint16_t clock_offset;
+
+ STREAM_TO_UINT8(status, p);
+
+ /* If failed to get clock offset just drop the result */
+ if (status != HCI_SUCCESS) return;
+
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(clock_offset, p);
+
+ handle = HCID_GET_HANDLE(handle);
+
+ btm_process_clk_off_comp_evt(handle, clock_offset);
+ btm_sec_update_clock_offset(handle, clock_offset);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_conn_pkt_type_change_evt
+ *
+ * Description Process event HCI_CONN_PKT_TYPE_CHANGE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_conn_pkt_type_change_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_qos_violation_evt
+ *
+ * Description Process event HCI_QOS_VIOLATION_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_qos_violation_evt(uint8_t* p) {
+ uint16_t handle;
+
+ STREAM_TO_UINT16(handle, p);
+
+ handle = HCID_GET_HANDLE(handle);
+
+ l2c_link_hci_qos_violation(handle);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_page_scan_mode_change_evt
+ *
+ * Description Process event HCI_PAGE_SCAN_MODE_CHANGE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_page_scan_mode_change_evt(void) {}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_page_scan_rep_mode_chng_evt
+ *
+ * Description Process event HCI_PAGE_SCAN_REP_MODE_CHNG_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_page_scan_rep_mode_chng_evt(void) {}
+
+/**********************************************
+ * Simple Pairing Events
+ **********************************************/
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_host_support_evt
+ *
+ * Description Process event HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_host_support_evt(uint8_t* p) {
+ btm_sec_rmt_host_support_feat_evt(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_io_cap_request_evt
+ *
+ * Description Process event HCI_IO_CAPABILITY_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_io_cap_request_evt(uint8_t* p) {
+ btm_io_capabilities_req(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_io_cap_response_evt
+ *
+ * Description Process event HCI_IO_CAPABILITY_RESPONSE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_io_cap_response_evt(uint8_t* p) {
+ btm_io_capabilities_rsp(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_user_conf_request_evt
+ *
+ * Description Process event HCI_USER_CONFIRMATION_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_user_conf_request_evt(uint8_t* p) {
+ btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_user_passkey_request_evt
+ *
+ * Description Process event HCI_USER_PASSKEY_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_user_passkey_request_evt(uint8_t* p) {
+ btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_user_passkey_notif_evt
+ *
+ * Description Process event HCI_USER_PASSKEY_NOTIFY_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_user_passkey_notif_evt(uint8_t* p) {
+ btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_keypress_notif_evt
+ *
+ * Description Process event HCI_KEYPRESS_NOTIFY_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_keypress_notif_evt(uint8_t* p) {
+ btm_keypress_notif_evt(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_rem_oob_request_evt
+ *
+ * Description Process event HCI_REMOTE_OOB_DATA_REQUEST_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_rem_oob_request_evt(uint8_t* p) { btm_rem_oob_req(p); }
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_simple_pair_complete_evt
+ *
+ * Description Process event HCI_SIMPLE_PAIRING_COMPLETE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void btu_hcif_simple_pair_complete_evt(uint8_t* p) {
+ btm_simple_pair_complete(p);
+}
+
+/*******************************************************************************
+ *
+ * Function btu_hcif_enhanced_flush_complete_evt
+ *
+ * Description Process event HCI_ENHANCED_FLUSH_COMPLETE_EVT
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+static void btu_hcif_enhanced_flush_complete_evt(void) {
+ /* This is empty until an upper layer cares about returning event */
+}
+#endif
+/**********************************************
+ * End of Simple Pairing Events
+ **********************************************/
+
+/**********************************************
+ * BLE Events
+ **********************************************/
+static void btu_hcif_encryption_key_refresh_cmpl_evt(uint8_t* p) {
+ uint8_t status;
+ uint8_t enc_enable = 0;
+ uint16_t handle;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+
+ if (status == HCI_SUCCESS) enc_enable = 1;
+
+ btm_sec_encrypt_change(handle, status, enc_enable);
+}
+
+static void btu_ble_ll_conn_complete_evt(uint8_t* p, uint16_t evt_len) {
+ btm_ble_conn_complete(p, evt_len, false);
+}
+#if (BLE_PRIVACY_SPT == TRUE)
+static void btu_ble_proc_enhanced_conn_cmpl(uint8_t* p, uint16_t evt_len) {
+ btm_ble_conn_complete(p, evt_len, true);
+}
+#endif
+
+extern void gatt_notify_conn_update(uint16_t handle, uint16_t interval,
+ uint16_t latency, uint16_t timeout,
+ uint8_t status);
+
+static void btu_ble_ll_conn_param_upd_evt(uint8_t* p, uint16_t evt_len) {
+ /* LE connection update has completed successfully as a master. */
+ /* We can enable the update request if the result is a success. */
+ /* extract the HCI handle first */
+ uint8_t status;
+ uint16_t handle;
+ uint16_t interval;
+ uint16_t latency;
+ uint16_t timeout;
+
+ STREAM_TO_UINT8(status, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(interval, p);
+ STREAM_TO_UINT16(latency, p);
+ STREAM_TO_UINT16(timeout, p);
+
+ l2cble_process_conn_update_evt(handle, status, interval, latency, timeout);
+
+ gatt_notify_conn_update(handle & 0x0FFF, interval, latency, timeout, status);
+}
+
+static void btu_ble_read_remote_feat_evt(uint8_t* p) {
+ btm_ble_read_remote_features_complete(p);
+}
+
+static void btu_ble_proc_ltk_req(uint8_t* p) {
+ uint16_t ediv, handle;
+ uint8_t* pp;
+
+ STREAM_TO_UINT16(handle, p);
+ pp = p + 8;
+ STREAM_TO_UINT16(ediv, pp);
+ btm_ble_ltk_request(handle, p, ediv);
+ /* This is empty until an upper layer cares about returning event */
+}
+
+static void btu_ble_data_length_change_evt(uint8_t* p, uint16_t evt_len) {
+ uint16_t handle;
+ uint16_t tx_data_len;
+ uint16_t rx_data_len;
+
+ if (!controller_get_interface()->supports_ble_packet_extension()) {
+ HCI_TRACE_WARNING("%s, request not supported", __func__);
+ return;
+ }
+
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(tx_data_len, p);
+ p += 2; /* Skip the TxTimer */
+ STREAM_TO_UINT16(rx_data_len, p);
+
+ l2cble_process_data_length_change_event(handle, tx_data_len, rx_data_len);
+}
+
+/**********************************************
+ * End of BLE Events Handler
+ **********************************************/
+#if (BLE_LLT_INCLUDED == TRUE)
+static void btu_ble_rc_param_req_evt(uint8_t* p) {
+ uint16_t handle;
+ uint16_t int_min, int_max, latency, timeout;
+
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(int_min, p);
+ STREAM_TO_UINT16(int_max, p);
+ STREAM_TO_UINT16(latency, p);
+ STREAM_TO_UINT16(timeout, p);
+
+ l2cble_process_rc_param_request_evt(handle, int_min, int_max, latency,
+ timeout);
+}
+#endif /* BLE_LLT_INCLUDED */
diff --git a/mtkbt/code/bt/stack/btu/btu_init.cc b/mtkbt/code/bt/stack/btu/btu_init.cc
new file mode 100755
index 0000000..e0e090b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btu/btu_init.cc
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_task"
+
+#include <base/logging.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "l2c_int.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/log.h"
+#include "osi/include/thread.h"
+#include "sdpint.h"
+#include "smp_int.h"
+
+// RT priority for audio-related tasks
+#define BTU_TASK_RT_PRIORITY 1
+
+extern fixed_queue_t* btif_msg_queue;
+
+// Communication queue from bta thread to bt_workqueue.
+fixed_queue_t* btu_bta_msg_queue;
+
+// Communication queue from hci thread to bt_workqueue.
+extern fixed_queue_t* btu_hci_msg_queue;
+
+// General timer queue.
+fixed_queue_t* btu_general_alarm_queue;
+
+thread_t* bt_workqueue_thread;
+static const char* BT_WORKQUEUE_NAME = "bt_workqueue";
+
+extern void PLATFORM_DisableHciTransport(uint8_t bDisable);
+/*****************************************************************************
+ * V A R I A B L E S *
+ *****************************************************************************/
+// TODO(cmanton) Move this out of this file
+const BD_ADDR BT_BD_ANY = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+void btu_task_start_up(void* context);
+void btu_task_shut_down(void* context);
+
+/*****************************************************************************
+ *
+ * Function btu_init_core
+ *
+ * Description Initialize control block memory for each core component.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void btu_init_core(void) {
+ /* Initialize the mandatory core stack components */
+ btm_init();
+
+ l2c_init();
+
+ sdp_init();
+
+ gatt_init();
+
+ SMP_Init();
+
+ btm_ble_init();
+}
+
+/*****************************************************************************
+ *
+ * Function btu_free_core
+ *
+ * Description Releases control block memory for each core component.
+ *
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void btu_free_core(void) {
+ /* Free the mandatory core stack components */
+ /** M: Fix fdleak bug @{ */
+ btm_free();
+ /** @} */
+ l2c_free();
+
+ gatt_free();
+}
+
+/*****************************************************************************
+ *
+ * Function BTU_StartUp
+ *
+ * Description Initializes the BTU control block.
+ *
+ * NOTE: Must be called before creating any tasks
+ * (RPC, BTU, HCIT, APPL, etc.)
+ *
+ * Returns void
+ *
+ *****************************************************************************/
+void BTU_StartUp(void) {
+ btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
+
+ btu_bta_msg_queue = fixed_queue_new(SIZE_MAX);
+ if (btu_bta_msg_queue == NULL) goto error_exit;
+
+ btu_general_alarm_queue = fixed_queue_new(SIZE_MAX);
+ if (btu_general_alarm_queue == NULL) goto error_exit;
+
+ bt_workqueue_thread = thread_new(BT_WORKQUEUE_NAME);
+ if (bt_workqueue_thread == NULL) goto error_exit;
+
+ thread_set_rt_priority(bt_workqueue_thread, BTU_TASK_RT_PRIORITY);
+
+ // Continue startup on bt workqueue thread.
+ thread_post(bt_workqueue_thread, btu_task_start_up, NULL);
+ return;
+
+error_exit:;
+ LOG_ERROR(LOG_TAG, "%s Unable to allocate resources for bt_workqueue",
+ __func__);
+ BTU_ShutDown();
+}
+
+void BTU_ShutDown(void) {
+ btu_task_shut_down(NULL);
+
+ fixed_queue_free(btu_bta_msg_queue, NULL);
+ btu_bta_msg_queue = NULL;
+
+ fixed_queue_free(btu_general_alarm_queue, NULL);
+ btu_general_alarm_queue = NULL;
+
+ thread_free(bt_workqueue_thread);
+
+ bt_workqueue_thread = NULL;
+}
diff --git a/mtkbt/code/bt/stack/btu/btu_task.cc b/mtkbt/code/bt/stack/btu/btu_task.cc
new file mode 100755
index 0000000..8152d3e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/btu/btu_task.cc
@@ -0,0 +1,196 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btu_task"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_trace.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btcore/include/module.h"
+#include "bte.h"
+#include "btif_common.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "gap_int.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/thread.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "sdpint.h"
+
+#if (BNEP_INCLUDED == TRUE)
+#include "bnep_int.h"
+#endif
+
+#if (PAN_INCLUDED == TRUE)
+#include "pan_int.h"
+#endif
+
+#if (HID_HOST_INCLUDED == TRUE)
+#include "hidh_int.h"
+#endif
+
+#if (AVDT_INCLUDED == TRUE)
+#include "avdt_int.h"
+#else
+extern void avdt_rcv_sync_info(BT_HDR* p_buf); /* this is for hci_test */
+#endif
+
+#if (MCA_INCLUDED == TRUE)
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#endif
+
+#include "bta_sys.h"
+#include "btm_ble_int.h"
+#include "gatt_int.h"
+#include "smp_int.h"
+
+/* Define BTU storage area
+*/
+uint8_t btu_trace_level = HCI_INITIAL_TRACE_LEVEL;
+
+// Communication queue between btu_task and bta.
+extern fixed_queue_t* btu_bta_msg_queue;
+
+// Communication queue between btu_task and hci.
+extern fixed_queue_t* btu_hci_msg_queue;
+
+// General timer queue.
+extern fixed_queue_t* btu_general_alarm_queue;
+
+extern fixed_queue_t* event_queue;
+extern fixed_queue_t* btif_msg_queue;
+
+extern thread_t* bt_workqueue_thread;
+
+static void btu_hci_msg_process(BT_HDR* p_msg);
+
+void btu_hci_msg_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+ BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+ btu_hci_msg_process(p_msg);
+}
+
+void btu_bta_msg_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) {
+ BT_HDR* p_msg = (BT_HDR*)fixed_queue_dequeue(queue);
+ bta_sys_event(p_msg);
+}
+
+static void btu_hci_msg_process(BT_HDR* p_msg) {
+ /* Determine the input message type. */
+ switch (p_msg->event & BT_EVT_MASK) {
+ case BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK: // TODO(zachoverflow): remove
+ // this
+ ((post_to_task_hack_t*)(&p_msg->data[0]))->callback(p_msg);
+ break;
+ case BT_EVT_TO_BTU_HCI_ACL:
+ /* All Acl Data goes to L2CAP */
+ l2c_rcv_acl_data(p_msg);
+ break;
+
+ case BT_EVT_TO_BTU_L2C_SEG_XMIT:
+ /* L2CAP segment transmit complete */
+ l2c_link_segments_xmitted(p_msg);
+ break;
+
+ case BT_EVT_TO_BTU_HCI_SCO:
+#if (BTM_SCO_INCLUDED == TRUE)
+ btm_route_sco_data(p_msg);
+ break;
+#endif
+
+ case BT_EVT_TO_BTU_HCI_EVT:
+ btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+ osi_free(p_msg);
+ break;
+
+ case BT_EVT_TO_BTU_HCI_CMD:
+ btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
+ break;
+
+ default:
+ osi_free(p_msg);
+ break;
+ }
+}
+
+void btu_task_start_up(UNUSED_ATTR void* context) {
+ BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
+ "btu_task pending for preload complete event");
+
+ LOG_INFO(LOG_TAG, "Bluetooth chip preload is complete");
+
+ BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
+ "btu_task received preload complete event");
+
+ /* Initialize the mandatory core stack control blocks
+ (BTU, BTM, L2CAP, and SDP)
+ */
+ btu_init_core();
+
+ /* Initialize any optional stack components */
+ BTE_InitStack();
+
+ bta_sys_init();
+
+ /* Initialise platform trace levels at this point as BTE_InitStack() and
+ * bta_sys_init()
+ * reset the control blocks and preset the trace level with
+ * XXX_INITIAL_TRACE_LEVEL
+ */
+ module_init(get_module(BTE_LOGMSG_MODULE));
+
+ // Inform the bt jni thread initialization is ok.
+ btif_transfer_context(btif_init_ok, 0, NULL, 0, NULL);
+
+ fixed_queue_register_dequeue(btu_bta_msg_queue,
+ thread_get_reactor(bt_workqueue_thread),
+ btu_bta_msg_ready, NULL);
+
+ fixed_queue_register_dequeue(btu_hci_msg_queue,
+ thread_get_reactor(bt_workqueue_thread),
+ btu_hci_msg_ready, NULL);
+
+ alarm_register_processing_queue(btu_general_alarm_queue, bt_workqueue_thread);
+}
+
+void btu_task_shut_down(UNUSED_ATTR void* context) {
+ fixed_queue_unregister_dequeue(btu_bta_msg_queue);
+ fixed_queue_unregister_dequeue(btu_hci_msg_queue);
+ alarm_unregister_processing_queue(btu_general_alarm_queue);
+
+ module_clean_up(get_module(BTE_LOGMSG_MODULE));
+
+ bta_sys_free();
+ btu_free_core();
+}
diff --git a/mtkbt/code/bt/stack/gap/gap_api.cc b/mtkbt/code/bt/stack/gap/gap_api.cc
new file mode 100755
index 0000000..994ba65
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gap/gap_api.cc
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gap_int.h"
+
+tGAP_CB gap_cb;
+
+/*******************************************************************************
+ *
+ * Function GAP_SetTraceLevel
+ *
+ * Description This function sets the trace level for GAP. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t GAP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) gap_cb.trace_level = new_level;
+
+ return (gap_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_Init
+ *
+ * Description Initializes the control blocks used by GAP.
+ *
+ * This routine should not be called except once per
+ * stack invocation.
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+void GAP_Init(void) {
+ memset(&gap_cb, 0, sizeof(tGAP_CB));
+
+#if defined(GAP_INITIAL_TRACE_LEVEL)
+ gap_cb.trace_level = GAP_INITIAL_TRACE_LEVEL;
+#else
+ gap_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+#if (GAP_CONN_INCLUDED == TRUE)
+ gap_conn_init();
+#endif
+
+ gap_attr_db_init();
+}
diff --git a/mtkbt/code/bt/stack/gap/gap_ble.cc b/mtkbt/code/bt/stack/gap/gap_ble.cc
new file mode 100755
index 0000000..3c8de00
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gap/gap_ble.cc
@@ -0,0 +1,771 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#include <string.h>
+#include "bt_utils.h"
+#include "btcore/include/uuid.h"
+#include "btm_int.h"
+#include "gap_api.h"
+#include "gap_int.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "gattdefs.h"
+#include "hcimsgs.h"
+#include "osi/include/osi.h"
+
+#define GAP_CHAR_ICON_SIZE 2
+#define GAP_CHAR_DEV_NAME_SIZE 248
+#define GAP_MAX_NUM_INC_SVR 0
+#define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
+#define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE)
+
+#ifndef GAP_ATTR_DB_SIZE
+#define GAP_ATTR_DB_SIZE \
+ GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, \
+ GAP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gap_ble_s_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE op_code,
+ tGATTS_DATA* p_data);
+
+/* client connection callback */
+static void gap_ble_c_connect_cback(tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tGATT_TRANSPORT transport);
+static void gap_ble_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data);
+
+static tGATT_CBACK gap_cback = {gap_ble_c_connect_cback,
+ gap_ble_c_cmpl_cback,
+ NULL,
+ NULL,
+ gap_ble_s_attr_request_cback,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+
+/*******************************************************************************
+ *
+ * Function gap_find_clcb_by_bd_addr
+ *
+ * Description The function searches all LCB with macthing bd address
+ *
+ * Returns total number of clcb found.
+ *
+ ******************************************************************************/
+tGAP_CLCB* gap_find_clcb_by_bd_addr(BD_ADDR bda) {
+ uint8_t i_clcb;
+ tGAP_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
+ return p_clcb;
+ }
+ }
+
+ return NULL;
+}
+
+/* returns LCB with matching connection ID, or NULL if not found */
+tGAP_CLCB* gap_ble_find_clcb_by_conn_id(uint16_t conn_id) {
+ uint8_t i_clcb;
+ tGAP_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
+ return p_clcb;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gap_clcb_alloc
+ *
+ * Description The function allocates a GAP connection link control block
+ *
+ * Returns NULL if not found. Otherwise pointer to the connection link
+ * block.
+ *
+ ******************************************************************************/
+tGAP_CLCB* gap_clcb_alloc(BD_ADDR bda) {
+ uint8_t i_clcb = 0;
+ tGAP_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
+ i_clcb++, p_clcb++) {
+ if (!p_clcb->in_use) {
+ fixed_queue_free(p_clcb->pending_req_q, NULL);
+ memset(p_clcb, 0, sizeof(tGAP_CLCB));
+ p_clcb->in_use = true;
+ memcpy(p_clcb->bda, bda, BD_ADDR_LEN);
+ p_clcb->pending_req_q = fixed_queue_new(SIZE_MAX);
+ return p_clcb;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_dealloc_clcb
+ *
+ * Description The function clean up the pending request queue in GAP
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void gap_ble_dealloc_clcb(tGAP_CLCB* p_clcb) {
+ tGAP_BLE_REQ* p_q;
+
+ while ((p_q = (tGAP_BLE_REQ*)fixed_queue_try_dequeue(
+ p_clcb->pending_req_q)) != NULL) {
+ /* send callback to all pending requests if being removed*/
+ if (p_q->p_cback != NULL) (*p_q->p_cback)(false, p_clcb->bda, 0, NULL);
+
+ osi_free(p_q);
+ }
+ fixed_queue_free(p_clcb->pending_req_q, NULL);
+
+ memset(p_clcb, 0, sizeof(tGAP_CLCB));
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_enqueue_request
+ *
+ * Description The function enqueue a GAP client request
+ *
+ * Returns true is successul; false otherwise
+ *
+ ******************************************************************************/
+bool gap_ble_enqueue_request(tGAP_CLCB* p_clcb, uint16_t uuid,
+ tGAP_BLE_CMPL_CBACK* p_cback) {
+ tGAP_BLE_REQ* p_q = (tGAP_BLE_REQ*)osi_malloc(sizeof(tGAP_BLE_REQ));
+
+ p_q->p_cback = p_cback;
+ p_q->uuid = uuid;
+ fixed_queue_enqueue(p_clcb->pending_req_q, p_q);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_dequeue_request
+ *
+ * Description The function dequeue a GAP client request if any
+ *
+ * Returns true is successul; false otherwise
+ *
+ ******************************************************************************/
+bool gap_ble_dequeue_request(tGAP_CLCB* p_clcb, uint16_t* p_uuid,
+ tGAP_BLE_CMPL_CBACK** p_cback) {
+ tGAP_BLE_REQ* p_q =
+ (tGAP_BLE_REQ*)fixed_queue_try_dequeue(p_clcb->pending_req_q);
+ ;
+
+ if (p_q != NULL) {
+ *p_cback = p_q->p_cback;
+ *p_uuid = p_q->uuid;
+ osi_free(p_q);
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ * GAP Attributes Database Request callback
+ ******************************************************************************/
+tGATT_STATUS gap_read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
+ bool is_long) {
+ tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
+ uint8_t *p = p_value->value, i;
+ uint16_t offset = p_value->offset;
+ uint8_t* p_dev_name = NULL;
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
+ if (handle == p_db_attr->handle) {
+ if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME && is_long == true)
+ return GATT_NOT_LONG;
+
+ switch (p_db_attr->uuid) {
+ case GATT_UUID_GAP_DEVICE_NAME:
+ BTM_ReadLocalDeviceName((char**)&p_dev_name);
+ if (strlen((char*)p_dev_name) > GATT_MAX_ATTR_LEN)
+ p_value->len = GATT_MAX_ATTR_LEN;
+ else
+ p_value->len = (uint16_t)strlen((char*)p_dev_name);
+
+ if (offset > p_value->len)
+ return GATT_INVALID_OFFSET;
+ else {
+ p_value->len -= offset;
+ p_dev_name += offset;
+ ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
+ GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x",
+ p_value->len);
+ }
+ break;
+
+ case GATT_UUID_GAP_ICON:
+ UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
+ p_value->len = 2;
+ break;
+
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ UINT16_TO_STREAM(
+ p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
+ UINT16_TO_STREAM(
+ p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
+ UINT16_TO_STREAM(
+ p, p_db_attr->attr_value.conn_param.latency); /* latency */
+ UINT16_TO_STREAM(
+ p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */
+ p_value->len = 8;
+ break;
+
+ /* address resolution */
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
+ p_value->len = 1;
+ break;
+ }
+ return GATT_SUCCESS;
+ }
+ }
+ return GATT_NOT_FOUND;
+}
+
+/*******************************************************************************
+ * GAP Attributes Database Read/Read Blob Request process
+ ******************************************************************************/
+tGATT_STATUS gap_proc_read(UNUSED_ATTR tGATTS_REQ_TYPE type,
+ tGATT_READ_REQ* p_data, tGATTS_RSP* p_rsp) {
+ tGATT_STATUS status = GATT_NO_RESOURCES;
+
+ if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
+
+ p_rsp->attr_value.handle = p_data->handle;
+
+ status =
+ gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
+
+ return status;
+}
+
+/******************************************************************************
+ *
+ * Function gap_proc_write_req
+ *
+ * Description GAP ATT server process a write request.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+uint8_t gap_proc_write_req(UNUSED_ATTR tGATTS_REQ_TYPE type,
+ tGATT_WRITE_REQ* p_data) {
+ tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
+ uint8_t i;
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
+ if (p_data->handle == p_db_attr->handle) {
+ return GATT_WRITE_NOT_PERMIT;
+ }
+ }
+ return GATT_NOT_FOUND;
+}
+
+/******************************************************************************
+ *
+ * Function gap_ble_s_attr_request_cback
+ *
+ * Description GAP ATT server attribute access request callback.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gap_ble_s_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
+ uint8_t status = GATT_INVALID_PDU;
+ tGATTS_RSP rsp_msg;
+ bool ignore = false;
+
+ GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
+
+ memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+ switch (type) {
+ case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+ status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+ if (!p_data->write_req.need_rsp) ignore = true;
+
+ status = gap_proc_write_req(type, &p_data->write_req);
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_EXEC:
+ ignore = true;
+ GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC");
+ break;
+
+ case GATTS_REQ_TYPE_MTU:
+ GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+ ignore = true;
+ break;
+
+ default:
+ GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ break;
+ }
+
+ if (!ignore) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function btm_ble_att_db_init
+ *
+ * Description GAP ATT database initalization.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gap_attr_db_init(void) {
+ tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+ uint16_t service_handle;
+
+ /* Fill our internal UUID with a fixed pattern 0x82 */
+ memset(&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
+ memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) * GAP_MAX_CHAR_NUM);
+
+ gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
+
+ GATT_StartIf(gap_cb.gatt_if);
+
+ bt_uuid_t svc_uuid, name_uuid, icon_uuid, pref_uuid, addr_res_uuid;
+ uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_GAP_SERVER);
+ uuid_128_from_16(&name_uuid, GATT_UUID_GAP_DEVICE_NAME);
+ uuid_128_from_16(&icon_uuid, GATT_UUID_GAP_ICON);
+ uuid_128_from_16(&pref_uuid, GATT_UUID_GAP_PREF_CONN_PARAM);
+ uuid_128_from_16(&addr_res_uuid, GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
+
+ btgatt_db_element_t service[] = {
+ {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = svc_uuid},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = name_uuid,
+ .properties = GATT_CHAR_PROP_BIT_READ,
+ .permissions = GATT_PERM_READ},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = icon_uuid,
+ .properties = GATT_CHAR_PROP_BIT_READ,
+ .permissions = GATT_PERM_READ},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = addr_res_uuid,
+ .properties = GATT_CHAR_PROP_BIT_READ,
+ .permissions = GATT_PERM_READ}
+#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
+ ,
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = pref_uuid,
+ .properties = GATT_CHAR_PROP_BIT_READ,
+ .permissions = GATT_PERM_READ}
+#endif
+ };
+
+ /* Add a GAP service */
+ GATTS_AddService(gap_cb.gatt_if, service,
+ sizeof(service) / sizeof(btgatt_db_element_t));
+ service_handle = service[0].attribute_handle;
+
+ GAP_TRACE_EVENT("%s: service_handle = %d", __func__, service_handle);
+
+ gap_cb.gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;
+ gap_cb.gatt_attr[0].handle = service[1].attribute_handle;
+
+ gap_cb.gatt_attr[1].uuid = GATT_UUID_GAP_ICON;
+ gap_cb.gatt_attr[1].handle = service[2].attribute_handle;
+
+ gap_cb.gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
+ gap_cb.gatt_attr[2].handle = service[3].attribute_handle;
+ gap_cb.gatt_attr[2].attr_value.addr_resolution = 0;
+
+#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
+
+ gap_cb.gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
+ gap_cb.gatt_attr[3].attr_value.conn_param.int_max =
+ GAP_PREFER_CONN_INT_MAX; /* 6 */
+ gap_cb.gatt_attr[3].attr_value.conn_param.int_min =
+ GAP_PREFER_CONN_INT_MIN; /* 0 */
+ gap_cb.gatt_attr[3].attr_value.conn_param.latency =
+ GAP_PREFER_CONN_LATENCY; /* 0 */
+ gap_cb.gatt_attr[3].attr_value.conn_param.sp_tout =
+ GAP_PREFER_CONN_SP_TOUT; /* 2000 */
+ gap_cb.gatt_attr[3].handle = service[4].attribute_handle;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_BleAttrDBUpdate
+ *
+ * Description GAP ATT database update.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) {
+ tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
+ uint8_t i = 0;
+
+ GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid);
+
+ for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
+ if (p_db_attr->uuid == attr_uuid) {
+ GAP_TRACE_EVENT("Found attr_uuid=0x%04x", attr_uuid);
+
+ switch (attr_uuid) {
+ case GATT_UUID_GAP_ICON:
+ p_db_attr->attr_value.icon = p_value->icon;
+ break;
+
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ memcpy((void*)&p_db_attr->attr_value.conn_param,
+ (const void*)&p_value->conn_param,
+ sizeof(tGAP_BLE_PREF_PARAM));
+ break;
+
+ case GATT_UUID_GAP_DEVICE_NAME:
+ BTM_SetLocalDeviceName((char*)p_value->p_dev_name);
+ break;
+
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
+ break;
+ }
+ break;
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_send_cl_read_request
+ *
+ * Description utility function to send a read request for a GAP
+ * charactersitic
+ *
+ * Returns true if read started, else false if GAP is busy
+ *
+ ******************************************************************************/
+bool gap_ble_send_cl_read_request(tGAP_CLCB* p_clcb) {
+ tGATT_READ_PARAM param;
+ uint16_t uuid = 0;
+ bool started = false;
+
+ if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
+ memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+ param.service.uuid.len = LEN_UUID_16;
+ param.service.uuid.uu.uuid16 = uuid;
+ param.service.s_handle = 1;
+ param.service.e_handle = 0xFFFF;
+ param.service.auth_req = 0;
+
+ if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) ==
+ GATT_SUCCESS) {
+ p_clcb->cl_op_uuid = uuid;
+ started = true;
+ }
+ }
+
+ return started;
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_cl_op_cmpl
+ *
+ * Description GAP client operation complete callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gap_ble_cl_op_cmpl(tGAP_CLCB* p_clcb, bool status, uint16_t len,
+ uint8_t* p_name) {
+ tGAP_BLE_CMPL_CBACK* p_cback = p_clcb->p_cback;
+ uint16_t op = p_clcb->cl_op_uuid;
+
+ GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
+
+ p_clcb->cl_op_uuid = 0;
+ p_clcb->p_cback = NULL;
+
+ if (p_cback && op) {
+ GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
+ (*p_cback)(status, p_clcb->bda, len, (char*)p_name);
+ }
+
+ /* if no further activity is requested in callback, drop the link */
+ if (p_clcb->connected) {
+ if (!gap_ble_send_cl_read_request(p_clcb)) {
+ GATT_Disconnect(p_clcb->conn_id);
+ gap_ble_dealloc_clcb(p_clcb);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_c_connect_cback
+ *
+ * Description Client connection callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_ble_c_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ UNUSED_ATTR tGATT_TRANSPORT transport) {
+ tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(bda);
+
+ if (p_clcb != NULL) {
+ if (connected) {
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = true;
+ /* start operation is pending */
+ gap_ble_send_cl_read_request(p_clcb);
+ } else {
+ p_clcb->connected = false;
+ gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+ /* clean up clcb */
+ gap_ble_dealloc_clcb(p_clcb);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_c_cmpl_cback
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_ble_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status, tGATT_CL_COMPLETE* p_data)
+
+{
+ tGAP_CLCB* p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
+ uint16_t op_type;
+ uint16_t min, max, latency, tout;
+ uint16_t len;
+ uint8_t* pp;
+
+ if (p_clcb == NULL) return;
+
+ op_type = p_clcb->cl_op_uuid;
+
+ GAP_TRACE_EVENT(
+ "gap_ble_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x read_type: "
+ "0x%04x",
+ op, status, op_type);
+ /* Currently we only issue read commands */
+ if (op != GATTC_OPTYPE_READ) return;
+
+ if (status != GATT_SUCCESS) {
+ gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+ return;
+ }
+
+ pp = p_data->att_value.value;
+
+ switch (op_type) {
+ case GATT_UUID_GAP_PREF_CONN_PARAM:
+ GAP_TRACE_EVENT("GATT_UUID_GAP_PREF_CONN_PARAM");
+ /* Extract the peripheral preferred connection parameters and save them */
+
+ STREAM_TO_UINT16(min, pp);
+ STREAM_TO_UINT16(max, pp);
+ STREAM_TO_UINT16(latency, pp);
+ STREAM_TO_UINT16(tout, pp);
+
+ BTM_BleSetPrefConnParams(p_clcb->bda, min, max, latency, tout);
+ /* release the connection here */
+ gap_ble_cl_op_cmpl(p_clcb, true, 0, NULL);
+ break;
+
+ case GATT_UUID_GAP_DEVICE_NAME:
+ GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME");
+ len = (uint16_t)strlen((char*)pp);
+ if (len > GAP_CHAR_DEV_NAME_SIZE) len = GAP_CHAR_DEV_NAME_SIZE;
+ gap_ble_cl_op_cmpl(p_clcb, true, len, pp);
+ break;
+
+ case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
+ gap_ble_cl_op_cmpl(p_clcb, true, 1, pp);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_ble_accept_cl_operation
+ *
+ * Description Start a process to read peer address resolution capability
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool gap_ble_accept_cl_operation(BD_ADDR peer_bda, uint16_t uuid,
+ tGAP_BLE_CMPL_CBACK* p_cback) {
+ tGAP_CLCB* p_clcb;
+ bool started = false;
+
+ if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM)
+ return (started);
+
+ p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
+ if (p_clcb == NULL) {
+ p_clcb = gap_clcb_alloc(peer_bda);
+ if (p_clcb == NULL) {
+ GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
+ return started;
+ }
+ }
+
+ GAP_TRACE_EVENT("%s() - BDA: %08x%04x cl_op_uuid: 0x%04x", __func__,
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) +
+ (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5], uuid);
+
+ if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id,
+ BT_TRANSPORT_LE))
+ p_clcb->connected = true;
+
+ if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, true, BT_TRANSPORT_LE, true))
+ return started;
+
+ /* enqueue the request */
+ gap_ble_enqueue_request(p_clcb, uuid, p_cback);
+
+ if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
+ started = gap_ble_send_cl_read_request(p_clcb);
+ else /* wait for connection up or pending operation to finish */
+ started = true;
+
+ return started;
+}
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerPrefConnParams
+ *
+ * Description Start a process to read a connected peripheral's preferred
+ * connection parameters
+ *
+ * Returns true if read started, else false if GAP is busy
+ *
+ ******************************************************************************/
+bool GAP_BleReadPeerPrefConnParams(BD_ADDR peer_bda) {
+ return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM,
+ NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerDevName
+ *
+ * Description Start a process to read a connected peripheral's device
+ * name.
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_BleReadPeerDevName(BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK* p_cback) {
+ return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_DEVICE_NAME,
+ p_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerAddressResolutionCap
+ *
+ * Description Start a process to read peer address resolution capability
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,
+ tGAP_BLE_CMPL_CBACK* p_cback) {
+ return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
+ p_cback);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_BleCancelReadPeerDevName
+ *
+ * Description Cancel reading a peripheral's device name.
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+bool GAP_BleCancelReadPeerDevName(BD_ADDR peer_bda) {
+ tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
+
+ GAP_TRACE_EVENT(
+ "GAP_BleCancelReadPeerDevName() - BDA: %08x%04x cl_op_uuid: 0x%04x",
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) +
+ peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5],
+ (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid);
+
+ if (p_clcb == NULL) {
+ GAP_TRACE_ERROR("Cannot cancel current op is not get dev name");
+ return false;
+ }
+
+ if (!p_clcb->connected) {
+ if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, true)) {
+ GAP_TRACE_ERROR("Cannot cancel where No connection id");
+ return false;
+ }
+ }
+
+ gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
+
+ return (true);
+}
diff --git a/mtkbt/code/bt/stack/gap/gap_conn.cc b/mtkbt/code/bt/stack/gap/gap_conn.cc
new file mode 100755
index 0000000..c51363b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gap/gap_conn.cc
@@ -0,0 +1,1137 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btu.h"
+#include "gap_int.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+#if (GAP_CONN_INCLUDED == TRUE)
+#include "btm_int.h"
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
+ uint8_t l2cap_id);
+static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
+static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
+static void gap_congestion_ind(uint16_t lcid, bool is_congested);
+static void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent);
+
+static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid);
+static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle);
+static tGAP_CCB* gap_allocate_ccb(void);
+static void gap_release_ccb(tGAP_CCB* p_ccb);
+static void gap_checks_con_flags(tGAP_CCB* p_ccb);
+
+/*******************************************************************************
+ *
+ * Function gap_conn_init
+ *
+ * Description This function is called to initialize GAP connection
+ * management
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gap_conn_init(void) {
+#if (AMP_INCLUDED == TRUE)
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pAMP_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pAMP_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pAMP_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pAMP_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pAMP_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pAMP_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pAMP_TxComplete_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveInd_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveRsp_Cb = NULL;
+ gap_cb.conn.reg_info.pAMP_MoveCfm_Cb = NULL; // gap_move_cfm
+ gap_cb.conn.reg_info.pAMP_MoveCfmRsp_Cb = NULL; // gap_move_cfm_rsp
+
+#else
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+ gap_cb.conn.reg_info.pL2CA_ConnectCfm_Cb = gap_connect_cfm;
+ gap_cb.conn.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_ConfigInd_Cb = gap_config_ind;
+ gap_cb.conn.reg_info.pL2CA_ConfigCfm_Cb = gap_config_cfm;
+ gap_cb.conn.reg_info.pL2CA_DisconnectInd_Cb = gap_disconnect_ind;
+ gap_cb.conn.reg_info.pL2CA_DisconnectCfm_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ gap_cb.conn.reg_info.pL2CA_DataInd_Cb = gap_data_ind;
+ gap_cb.conn.reg_info.pL2CA_CongestionStatus_Cb = gap_congestion_ind;
+ gap_cb.conn.reg_info.pL2CA_TxComplete_Cb = gap_tx_complete_ind;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnOpen
+ *
+ * Description This function is called to open an L2CAP connection.
+ *
+ * Parameters: is_server - If true, the connection is not created
+ * but put into a "listen" mode waiting for
+ * the remote side to connect.
+ *
+ * service_id - Unique service ID from
+ * BTM_SEC_SERVICE_FIRST_EMPTY (6)
+ * to BTM_SEC_MAX_SERVICE_RECORDS (32)
+ *
+ * p_rem_bda - Pointer to remote BD Address.
+ * If a server, and we don't care about the
+ * remote BD Address, then NULL should be passed.
+ *
+ * psm - the PSM used for the connection
+ *
+ * p_config - Optional pointer to configuration structure.
+ * If NULL, the default GAP configuration will
+ * be used.
+ *
+ * security - security flags
+ * chan_mode_mask - (GAP_FCR_CHAN_OPT_BASIC,
+ * GAP_FCR_CHAN_OPT_ERTM,
+ * GAP_FCR_CHAN_OPT_STREAM)
+ *
+ * p_cb - Pointer to callback function for events.
+ *
+ * Returns handle of the connection if successful, else
+ * GAP_INVALID_HANDLE
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
+ bool is_server, BD_ADDR p_rem_bda, uint16_t psm,
+ tL2CAP_CFG_INFO* p_cfg, tL2CAP_ERTM_INFO* ertm_info,
+ uint16_t security, uint8_t chan_mode_mask,
+ tGAP_CONN_CALLBACK* p_cb, tBT_TRANSPORT transport) {
+ tGAP_CCB* p_ccb;
+ uint16_t cid;
+
+ GAP_TRACE_EVENT("GAP_CONN - Open Request");
+
+ /* Allocate a new CCB. Return if none available. */
+ p_ccb = gap_allocate_ccb();
+ if (p_ccb == NULL) return (GAP_INVALID_HANDLE);
+
+ /* update the transport */
+ p_ccb->transport = transport;
+
+ /* If caller specified a BD address, save it */
+ if (p_rem_bda) {
+ /* the bd addr is not BT_BD_ANY, then a bd address was specified */
+ if (memcmp(p_rem_bda, BT_BD_ANY, BD_ADDR_LEN))
+ p_ccb->rem_addr_specified = true;
+
+ memcpy(&p_ccb->rem_dev_address[0], p_rem_bda, BD_ADDR_LEN);
+ } else if (!is_server) {
+ /* remore addr is not specified and is not a server -> bad */
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* A client MUST have specified a bd addr to connect with */
+ if (!p_ccb->rem_addr_specified && !is_server) {
+ gap_release_ccb(p_ccb);
+ GAP_TRACE_ERROR(
+ "GAP ERROR: Client must specify a remote BD ADDR to connect to!");
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Check if configuration was specified */
+ if (p_cfg) p_ccb->cfg = *p_cfg;
+
+ /* Configure L2CAP COC, if transport is LE */
+ if (transport == BT_TRANSPORT_LE) {
+ p_ccb->local_coc_cfg.credits = L2CAP_LE_DEFAULT_CREDIT;
+ p_ccb->local_coc_cfg.mtu = p_cfg->mtu;
+ p_ccb->local_coc_cfg.mps = L2CAP_LE_DEFAULT_MPS;
+ }
+
+ p_ccb->p_callback = p_cb;
+
+/* If originator, use a dynamic PSM */
+#if (AMP_INCLUDED == TRUE)
+ if (!is_server)
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = NULL;
+ else
+ gap_cb.conn.reg_info.pAMP_ConnectInd_Cb = gap_connect_ind;
+#else
+ if (!is_server)
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = NULL;
+ else
+ gap_cb.conn.reg_info.pL2CA_ConnectInd_Cb = gap_connect_ind;
+#endif
+
+ /* Register the PSM with L2CAP */
+ if (transport == BT_TRANSPORT_BR_EDR) {
+ p_ccb->psm =
+ L2CA_REGISTER(psm, &gap_cb.conn.reg_info,
+ AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+ if (p_ccb->psm == 0) {
+ GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
+ gap_release_ccb(p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+ }
+
+ if (transport == BT_TRANSPORT_LE) {
+ p_ccb->psm =
+ L2CA_REGISTER_COC(psm, &gap_cb.conn.reg_info,
+ AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+ if (p_ccb->psm == 0) {
+ GAP_TRACE_ERROR("%s: Failure registering PSM 0x%04x", __func__, psm);
+ gap_release_ccb(p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+ }
+
+ /* Register with Security Manager for the specific security level */
+ p_ccb->service_id = service_id;
+ if (!BTM_SetSecurityLevel((uint8_t)!is_server, p_serv_name, p_ccb->service_id,
+ security, p_ccb->psm, 0, 0)) {
+ GAP_TRACE_ERROR("GAP_CONN - Security Error");
+ gap_release_ccb(p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+
+ /* Fill in eL2CAP parameter data */
+ if (p_ccb->cfg.fcr_present) {
+ if (ertm_info == NULL) {
+ p_ccb->ertm_info.preferred_mode = p_ccb->cfg.fcr.mode;
+ p_ccb->ertm_info.user_rx_buf_size = GAP_DATA_BUF_SIZE;
+ p_ccb->ertm_info.user_tx_buf_size = GAP_DATA_BUF_SIZE;
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_INVALID_ERM_BUF_SIZE;
+ } else {
+ p_ccb->ertm_info = *ertm_info;
+ }
+ }
+
+ /* optional FCR channel modes */
+ if (ertm_info != NULL) {
+ p_ccb->ertm_info.allowed_modes =
+ (chan_mode_mask) ? chan_mode_mask : (uint8_t)L2CAP_FCR_CHAN_OPT_BASIC;
+ }
+
+ if (is_server) {
+ p_ccb->con_flags |=
+ GAP_CCB_FLAGS_SEC_DONE; /* assume btm/l2cap would handle it */
+ p_ccb->con_state = GAP_CCB_STATE_LISTENING;
+ return (p_ccb->gap_handle);
+ } else {
+ /* We are the originator of this connection */
+ p_ccb->con_flags = GAP_CCB_FLAGS_IS_ORIG;
+
+ /* Transition to the next appropriate state, waiting for connection confirm.
+ */
+ p_ccb->con_state = GAP_CCB_STATE_CONN_SETUP;
+
+ /* mark security done flag, when security is not required */
+ if ((security & (BTM_SEC_OUT_AUTHORIZE | BTM_SEC_OUT_AUTHENTICATE |
+ BTM_SEC_OUT_ENCRYPT)) == 0)
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+
+ /* Check if L2CAP started the connection process */
+ if (p_rem_bda && (transport == BT_TRANSPORT_BR_EDR)) {
+ cid = L2CA_CONNECT_REQ(p_ccb->psm, p_rem_bda, &p_ccb->ertm_info);
+ if (cid != 0) {
+ p_ccb->connection_id = cid;
+ return (p_ccb->gap_handle);
+ }
+ }
+
+ if (p_rem_bda && (transport == BT_TRANSPORT_LE)) {
+ cid = L2CA_CONNECT_COC_REQ(p_ccb->psm, p_rem_bda, &p_ccb->local_coc_cfg);
+ if (cid != 0) {
+ p_ccb->connection_id = cid;
+ return (p_ccb->gap_handle);
+ }
+ }
+
+ gap_release_ccb(p_ccb);
+ return (GAP_INVALID_HANDLE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnClose
+ *
+ * Description This function is called to close a connection.
+ *
+ * Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+ *
+ * Returns BT_PASS - closed OK
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnClose(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+
+ GAP_TRACE_EVENT("GAP_CONN - close handle: 0x%x", gap_handle);
+
+ if (p_ccb) {
+ /* Check if we have a connection ID */
+ if (p_ccb->con_state != GAP_CCB_STATE_LISTENING)
+ L2CA_DISCONNECT_REQ(p_ccb->connection_id);
+
+ gap_release_ccb(p_ccb);
+
+ return (BT_PASS);
+ }
+
+ return (GAP_ERR_BAD_HANDLE);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnReadData
+ *
+ * Description Normally not GKI aware application will call this function
+ * after receiving GAP_EVT_RXDATA event.
+ *
+ * Parameters: handle - Handle of the connection returned in the Open
+ * p_data - Data area
+ * max_len - Byte count requested
+ * p_len - Byte count received
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_NO_DATA_AVAIL - no data available
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data,
+ uint16_t max_len, uint16_t* p_len) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ uint16_t copy_len;
+
+ if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
+
+ *p_len = 0;
+
+ if (fixed_queue_is_empty(p_ccb->rx_queue)) return (GAP_NO_DATA_AVAIL);
+
+ mutex_global_lock();
+
+ while (max_len) {
+ BT_HDR* p_buf =
+ static_cast<BT_HDR*>(fixed_queue_try_peek_first(p_ccb->rx_queue));
+ if (p_buf == NULL) break;
+
+ copy_len = (p_buf->len > max_len) ? max_len : p_buf->len;
+ max_len -= copy_len;
+ *p_len += copy_len;
+ if (p_data) {
+ memcpy(p_data, (uint8_t*)(p_buf + 1) + p_buf->offset, copy_len);
+ p_data += copy_len;
+ }
+
+ if (p_buf->len > copy_len) {
+ p_buf->offset += copy_len;
+ p_buf->len -= copy_len;
+ break;
+ }
+ osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
+ }
+
+ p_ccb->rx_queue_size -= *p_len;
+
+ mutex_global_unlock();
+
+ GAP_TRACE_EVENT("GAP_ConnReadData - rx_queue_size left=%d, *p_len=%d",
+ p_ccb->rx_queue_size, *p_len);
+
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_GetRxQueueCnt
+ *
+ * Description This function return number of bytes on the rx queue.
+ *
+ * Parameters: handle - Handle returned in the GAP_ConnOpen
+ * p_rx_queue_count - Pointer to return queue count in.
+ *
+ *
+ ******************************************************************************/
+int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count) {
+ tGAP_CCB* p_ccb;
+ int rc = BT_PASS;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS) {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
+ *p_rx_queue_count = p_ccb->rx_queue_size;
+ } else
+ rc = GAP_INVALID_HANDLE;
+ } else
+ rc = GAP_INVALID_HANDLE;
+
+ GAP_TRACE_EVENT("GAP_GetRxQueueCnt - rc = 0x%04x, rx_queue_count=%d", rc,
+ *p_rx_queue_count);
+
+ return (rc);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnBTRead
+ *
+ * Description Bluetooth-aware applications will call this function after
+ * receiving GAP_EVT_RXDATA event.
+ *
+ * Parameters: handle - Handle of the connection returned in the Open
+ * pp_buf - pointer to address of buffer with data,
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_NO_DATA_AVAIL - no data available
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnBTRead(uint16_t gap_handle, BT_HDR** pp_buf) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ BT_HDR* p_buf;
+
+ if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
+
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rx_queue);
+
+ if (p_buf) {
+ *pp_buf = p_buf;
+
+ p_ccb->rx_queue_size -= p_buf->len;
+ return (BT_PASS);
+ } else {
+ *pp_buf = NULL;
+ return (GAP_NO_DATA_AVAIL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnWriteData
+ *
+ * Description Normally not GKI aware application will call this function
+ * to send data to the connection.
+ *
+ * Parameters: handle - Handle of the connection returned in the Open
+ * p_data - Data area
+ * max_len - Byte count requested
+ * p_len - Byte count received
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_ERR_BAD_STATE - connection not established
+ * GAP_CONGESTION - system is congested
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
+ uint16_t max_len, uint16_t* p_len) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+ BT_HDR* p_buf;
+
+ *p_len = 0;
+
+ if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
+
+ if (p_ccb->con_state != GAP_CCB_STATE_CONNECTED) return (GAP_ERR_BAD_STATE);
+
+ while (max_len) {
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ p_buf = (BT_HDR*)osi_malloc(L2CAP_FCR_ERTM_BUF_SIZE);
+ else
+ p_buf = (BT_HDR*)osi_malloc(GAP_DATA_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len =
+ (p_ccb->rem_mtu_size < max_len) ? p_ccb->rem_mtu_size : max_len;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+ p_data += p_buf->len;
+
+ GAP_TRACE_EVENT("GAP_WriteData %d bytes", p_buf->len);
+
+ fixed_queue_enqueue(p_ccb->tx_queue, p_buf);
+ }
+
+ if (p_ccb->is_congested) {
+ return (BT_PASS);
+ }
+
+ /* Send the buffer through L2CAP */
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) != NULL) {
+ uint8_t status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED) {
+ p_ccb->is_congested = true;
+ break;
+ } else if (status != L2CAP_DW_SUCCESS)
+ return (GAP_ERR_BAD_STATE);
+ }
+
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnReconfig
+ *
+ * Description Applications can call this function to reconfigure the
+ * connection.
+ *
+ * Parameters: handle - Handle of the connection
+ * p_cfg - Pointer to new configuration
+ *
+ * Returns BT_PASS - config process started
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnReconfig(uint16_t gap_handle, tL2CAP_CFG_INFO* p_cfg) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+
+ if (!p_ccb) return (GAP_ERR_BAD_HANDLE);
+
+ p_ccb->cfg = *p_cfg;
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED)
+ L2CA_CONFIG_REQ(p_ccb->connection_id, p_cfg);
+
+ return (BT_PASS);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnSetIdleTimeout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection, or for all future connections. The "idle
+ * timeout" is the amount of time that a connection can remain
+ * up with no L2CAP channels on it. A timeout of zero means
+ * that the connection will be torn down immediately when the
+ * last channel is removed. A timeout of 0xFFFF means no
+ * timeout. Values are in seconds.
+ *
+ * Parameters: handle - Handle of the connection
+ * timeout - in secs
+ * 0 = immediate disconnect when last channel is
+ * removed
+ * 0xFFFF = no idle timeout
+ *
+ * Returns BT_PASS - config process started
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnSetIdleTimeout(uint16_t gap_handle, uint16_t timeout) {
+ tGAP_CCB* p_ccb;
+
+ p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL) return (GAP_ERR_BAD_HANDLE);
+
+ if (L2CA_SetIdleTimeout(p_ccb->connection_id, timeout, false))
+ return (BT_PASS);
+ else
+ return (GAP_ERR_BAD_HANDLE);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetRemoteAddr
+ *
+ * Description This function is called to get the remote BD address
+ * of a connection.
+ *
+ * Parameters: handle - Handle of the connection returned by GAP_ConnOpen
+ *
+ * Returns BT_PASS - closed OK
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_handle(gap_handle);
+
+ GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr gap_handle = %d", gap_handle);
+
+ if ((p_ccb) && (p_ccb->con_state > GAP_CCB_STATE_LISTENING)) {
+ GAP_TRACE_EVENT(
+ "GAP_ConnGetRemoteAddr bda "
+ ":0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+ p_ccb->rem_dev_address[0], p_ccb->rem_dev_address[1],
+ p_ccb->rem_dev_address[2], p_ccb->rem_dev_address[3],
+ p_ccb->rem_dev_address[4], p_ccb->rem_dev_address[5]);
+ return (p_ccb->rem_dev_address);
+ } else {
+ GAP_TRACE_EVENT("GAP_ConnGetRemoteAddr return Error ");
+ return (NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetRemMtuSize
+ *
+ * Description Returns the remote device's MTU size
+ *
+ * Parameters: handle - Handle of the connection
+ *
+ * Returns uint16_t - maximum size buffer that can be transmitted to
+ * the peer
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnGetRemMtuSize(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb;
+
+ p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL) return (0);
+
+ return (p_ccb->rem_mtu_size);
+}
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetL2CAPCid
+ *
+ * Description Returns the L2CAP channel id
+ *
+ * Parameters: handle - Handle of the connection
+ *
+ * Returns uint16_t - The L2CAP channel id
+ * 0, if error
+ *
+ ******************************************************************************/
+uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle) {
+ tGAP_CCB* p_ccb;
+
+ p_ccb = gap_find_ccb_by_handle(gap_handle);
+ if (p_ccb == NULL) return (0);
+
+ return (p_ccb->connection_id);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_tx_connect_ind
+ *
+ * Description Sends out GAP_EVT_TX_EMPTY when transmission has been
+ * completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gap_tx_complete_ind(uint16_t l2cap_cid, uint16_t sdu_sent) {
+ tGAP_CCB* p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) return;
+
+ if ((p_ccb->con_state == GAP_CCB_STATE_CONNECTED) && (sdu_sent == 0xFFFF)) {
+ GAP_TRACE_EVENT("%s: GAP_EVT_TX_EMPTY", __func__);
+ p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_TX_EMPTY);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_connect_ind
+ *
+ * Description This function handles an inbound connection indication
+ * from L2CAP. This is the case where we are acting as a
+ * server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, uint16_t psm,
+ uint8_t l2cap_id) {
+ uint16_t xx;
+ tGAP_CCB* p_ccb;
+
+ /* See if we have a CCB listening for the connection */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
+ xx++, p_ccb++) {
+ if ((p_ccb->con_state == GAP_CCB_STATE_LISTENING) && (p_ccb->psm == psm) &&
+ ((p_ccb->rem_addr_specified == false) ||
+ (!memcmp(bd_addr, p_ccb->rem_dev_address, BD_ADDR_LEN))))
+ break;
+ }
+
+ if (xx == GAP_MAX_CONNECTIONS) {
+ GAP_TRACE_WARNING("*******");
+ GAP_TRACE_WARNING(
+ "WARNING: GAP Conn Indication for Unexpected Bd Addr...Disconnecting");
+ GAP_TRACE_WARNING("*******");
+
+ /* Disconnect because it is an unexpected connection */
+ L2CA_DISCONNECT_REQ(l2cap_cid);
+ return;
+ }
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy(&p_ccb->rem_dev_address[0], bd_addr, BD_ADDR_LEN);
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+ L2CA_CONNECT_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK,
+ &p_ccb->ertm_info);
+
+ if (p_ccb->transport == BT_TRANSPORT_LE) {
+ L2CA_CONNECT_COC_RSP(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK,
+ L2CAP_CONN_OK, &p_ccb->local_coc_cfg);
+
+ /* get the remote coc configuration */
+ L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
+ p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
+
+ /* configuration is not required for LE COC */
+ p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+ p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+ gap_checks_con_flags(p_ccb);
+ }
+
+ GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP conn ind, CID: 0x%x",
+ p_ccb->connection_id);
+
+ /* Send a Configuration Request. */
+ if (p_ccb->transport == BT_TRANSPORT_BR_EDR)
+ L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_checks_con_flags
+ *
+ * Description This function processes the L2CAP configuration indication
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_checks_con_flags(tGAP_CCB* p_ccb) {
+ GAP_TRACE_EVENT("gap_checks_con_flags conn_flags:0x%x, ", p_ccb->con_flags);
+ /* if all the required con_flags are set, report the OPEN event now */
+ if ((p_ccb->con_flags & GAP_CCB_FLAGS_CONN_DONE) == GAP_CCB_FLAGS_CONN_DONE) {
+ p_ccb->con_state = GAP_CCB_STATE_CONNECTED;
+
+ p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_OPENED);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_sec_check_complete
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tGAP_CCB* p_ccb = (tGAP_CCB*)p_ref_data;
+
+ GAP_TRACE_EVENT(
+ "gap_sec_check_complete conn_state:%d, conn_flags:0x%x, status:%d",
+ p_ccb->con_state, p_ccb->con_flags, res);
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE) return;
+
+ if (res == BTM_SUCCESS) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+ gap_checks_con_flags(p_ccb);
+ } else {
+ /* security failed - disconnect the channel */
+ L2CA_DISCONNECT_REQ(p_ccb->connection_id);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_connect_cfm
+ *
+ * Description This function handles the connect confirm events
+ * from L2CAP. This is the case when we are acting as a
+ * client and have sent a connect request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
+ tGAP_CCB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) return;
+
+ /* initiate security process, if needed */
+ if ((p_ccb->con_flags & GAP_CCB_FLAGS_SEC_DONE) == 0 &&
+ p_ccb->transport != BT_TRANSPORT_LE) {
+ btm_sec_mx_access_request(p_ccb->rem_dev_address, p_ccb->psm, true, 0, 0,
+ &gap_sec_check_complete, p_ccb);
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) &&
+ (p_ccb->con_state == GAP_CCB_STATE_CONN_SETUP)) {
+ if (p_ccb->transport == BT_TRANSPORT_BR_EDR) {
+ p_ccb->con_state = GAP_CCB_STATE_CFG_SETUP;
+
+ /* Send a Configuration Request. */
+ L2CA_CONFIG_REQ(l2cap_cid, &p_ccb->cfg);
+ }
+
+ if (p_ccb->transport == BT_TRANSPORT_LE) {
+ /* get the remote coc configuration */
+ L2CA_GET_PEER_COC_CONFIG(l2cap_cid, &p_ccb->peer_coc_cfg);
+ p_ccb->rem_mtu_size = p_ccb->peer_coc_cfg.mtu;
+
+ /* configuration is not required for LE COC */
+ p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+ p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+ p_ccb->con_flags |= GAP_CCB_FLAGS_SEC_DONE;
+ gap_checks_con_flags(p_ccb);
+ }
+ } else {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_callback)
+ (*p_ccb->p_callback)(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+
+ gap_release_ccb(p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_config_ind
+ *
+ * Description This function processes the L2CAP configuration indication
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tGAP_CCB* p_ccb;
+ uint16_t local_mtu_size;
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) return;
+
+ /* Remember the remote MTU size */
+
+ if (p_ccb->cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ local_mtu_size =
+ p_ccb->ertm_info.user_tx_buf_size - sizeof(BT_HDR) - L2CAP_MIN_OFFSET;
+ } else
+ local_mtu_size = L2CAP_MTU_SIZE;
+
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > local_mtu_size)) {
+ p_ccb->rem_mtu_size = local_mtu_size;
+ } else
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = false;
+ p_cfg->mtu_present = false;
+ p_cfg->result = L2CAP_CFG_OK;
+ p_cfg->fcs_present = false;
+
+ L2CA_CONFIG_RSP(l2cap_cid, p_cfg);
+
+ p_ccb->con_flags |= GAP_CCB_FLAGS_HIS_CFG_DONE;
+
+ gap_checks_con_flags(p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_config_cfm
+ *
+ * Description This function processes the L2CAP configuration confirmation
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tGAP_CCB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) return;
+
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ p_ccb->con_flags |= GAP_CCB_FLAGS_MY_CFG_DONE;
+
+ if (p_ccb->cfg.fcr_present)
+ p_ccb->cfg.fcr.mode = p_cfg->fcr.mode;
+ else
+ p_ccb->cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+ gap_checks_con_flags(p_ccb);
+ } else {
+ p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb(p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_disconnect_ind
+ *
+ * Description This function handles a disconnect event from L2CAP. If
+ * requested to, we ack the disconnect before dropping the CCB
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
+ tGAP_CCB* p_ccb;
+
+ GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) return;
+
+ if (ack_needed) L2CA_DISCONNECT_RSP(l2cap_cid);
+
+ p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_CLOSED);
+ gap_release_ccb(p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
+ tGAP_CCB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ osi_free(p_msg);
+ return;
+ }
+
+ if (p_ccb->con_state == GAP_CCB_STATE_CONNECTED) {
+ fixed_queue_enqueue(p_ccb->rx_queue, p_msg);
+
+ p_ccb->rx_queue_size += p_msg->len;
+ /*
+ GAP_TRACE_EVENT ("gap_data_ind - rx_queue_size=%d, msg len=%d",
+ p_ccb->rx_queue_size, p_msg->len);
+ */
+
+ p_ccb->p_callback(p_ccb->gap_handle, GAP_EVT_CONN_DATA_AVAIL);
+ } else {
+ osi_free(p_msg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_congestion_ind
+ *
+ * Description This is a callback function called by L2CAP when
+ * data L2CAP congestion status changes
+ *
+ ******************************************************************************/
+static void gap_congestion_ind(uint16_t lcid, bool is_congested) {
+ tGAP_CCB* p_ccb;
+ uint16_t event;
+ BT_HDR* p_buf;
+ uint8_t status;
+
+ GAP_TRACE_EVENT("GAP_CONN - Rcvd L2CAP Is Congested (%d), CID: 0x%x",
+ is_congested, lcid);
+
+ /* Find CCB based on CID */
+ p_ccb = gap_find_ccb_by_cid(lcid);
+ if (p_ccb == NULL) return;
+
+ p_ccb->is_congested = is_congested;
+
+ event = (is_congested) ? GAP_EVT_CONN_CONGESTED : GAP_EVT_CONN_UNCONGESTED;
+ p_ccb->p_callback(p_ccb->gap_handle, event);
+
+ if (!is_congested) {
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->tx_queue)) !=
+ NULL) {
+ status = L2CA_DATA_WRITE(p_ccb->connection_id, p_buf);
+
+ if (status == L2CAP_DW_CONGESTED) {
+ p_ccb->is_congested = true;
+ break;
+ } else if (status != L2CAP_DW_SUCCESS)
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_find_ccb_by_cid
+ *
+ * Description This function searches the CCB table for an entry with the
+ * passed CID.
+ *
+ * Returns the CCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+static tGAP_CCB* gap_find_ccb_by_cid(uint16_t cid) {
+ uint16_t xx;
+ tGAP_CCB* p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
+ xx++, p_ccb++) {
+ if ((p_ccb->con_state != GAP_CCB_STATE_IDLE) &&
+ (p_ccb->connection_id == cid))
+ return (p_ccb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_find_ccb_by_handle
+ *
+ * Description This function searches the CCB table for an entry with the
+ * passed handle.
+ *
+ * Returns the CCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+static tGAP_CCB* gap_find_ccb_by_handle(uint16_t handle) {
+ tGAP_CCB* p_ccb;
+
+ /* Check that handle is valid */
+ if (handle < GAP_MAX_CONNECTIONS) {
+ p_ccb = &gap_cb.conn.ccb_pool[handle];
+
+ if (p_ccb->con_state != GAP_CCB_STATE_IDLE) return (p_ccb);
+ }
+
+ /* If here, handle points to invalid connection */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_allocate_ccb
+ *
+ * Description This function allocates a new CCB.
+ *
+ * Returns CCB address, or NULL if none available.
+ *
+ ******************************************************************************/
+static tGAP_CCB* gap_allocate_ccb(void) {
+ uint16_t xx;
+ tGAP_CCB* p_ccb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_ccb = gap_cb.conn.ccb_pool; xx < GAP_MAX_CONNECTIONS;
+ xx++, p_ccb++) {
+ if (p_ccb->con_state == GAP_CCB_STATE_IDLE) {
+ memset(p_ccb, 0, sizeof(tGAP_CCB));
+ p_ccb->tx_queue = fixed_queue_new(SIZE_MAX);
+ p_ccb->rx_queue = fixed_queue_new(SIZE_MAX);
+
+ p_ccb->gap_handle = xx;
+ p_ccb->rem_mtu_size = L2CAP_MTU_SIZE;
+
+ return (p_ccb);
+ }
+ }
+
+ /* If here, no free CCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_release_ccb
+ *
+ * Description This function releases a CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gap_release_ccb(tGAP_CCB* p_ccb) {
+ /* Drop any buffers we may be holding */
+ p_ccb->rx_queue_size = 0;
+
+ while (!fixed_queue_is_empty(p_ccb->rx_queue))
+ osi_free(fixed_queue_try_dequeue(p_ccb->rx_queue));
+ fixed_queue_free(p_ccb->rx_queue, NULL);
+ p_ccb->rx_queue = NULL;
+
+ while (!fixed_queue_is_empty(p_ccb->tx_queue))
+ osi_free(fixed_queue_try_dequeue(p_ccb->tx_queue));
+ fixed_queue_free(p_ccb->tx_queue, NULL);
+ p_ccb->tx_queue = NULL;
+
+ p_ccb->con_state = GAP_CCB_STATE_IDLE;
+
+ /* If no-one else is using the PSM, deregister from L2CAP */
+ tGAP_CCB* p_ccb_local = gap_cb.conn.ccb_pool;
+ for (uint16_t i = 0; i < GAP_MAX_CONNECTIONS; i++, p_ccb_local++) {
+ if ((p_ccb_local->con_state != GAP_CCB_STATE_IDLE) &&
+ (p_ccb_local->psm == p_ccb->psm)) {
+ GAP_TRACE_EVENT("%s :%d PSM is still in use, do not deregister",
+ __func__, p_ccb_local->psm);
+ return;
+ }
+ }
+
+ /* Free the security record for this PSM */
+ BTM_SecClrService(p_ccb->service_id);
+ if (p_ccb->transport == BT_TRANSPORT_BR_EDR) L2CA_DEREGISTER(p_ccb->psm);
+ if (p_ccb->transport == BT_TRANSPORT_LE) L2CA_DEREGISTER_COC(p_ccb->psm);
+}
+
+#endif /* GAP_CONN_INCLUDED */
diff --git a/mtkbt/code/bt/stack/gap/gap_int.h b/mtkbt/code/bt/stack/gap/gap_int.h
new file mode 100755
index 0000000..0f27f04
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gap/gap_int.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef GAP_INT_H
+#define GAP_INT_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "gap_api.h"
+#include "gatt_api.h"
+#include "osi/include/fixed_queue.h"
+#define GAP_MAX_BLOCKS 2 /* Concurrent GAP commands pending at a time*/
+/* Define the Generic Access Profile control structure */
+typedef struct {
+ void* p_data; /* Pointer to any data returned in callback */
+ tGAP_CALLBACK* gap_cback; /* Pointer to users callback function */
+ tGAP_CALLBACK* gap_inq_rslt_cback; /* Used for inquiry results */
+ uint16_t event; /* Passed back in the callback */
+ uint8_t index; /* Index of this control block and callback */
+ bool in_use; /* True when structure is allocated */
+} tGAP_INFO;
+
+/* The control block for FindAddrByName (Only 1 active at a time) */
+typedef struct {
+ tGAP_CALLBACK* p_cback;
+ /* Pointer to the current inquiry database entry */
+ tBTM_INQ_INFO* p_cur_inq;
+ tGAP_FINDADDR_RESULTS results;
+ bool in_use;
+} tGAP_FINDADDR_CB;
+
+/* Define the GAP Connection Control Block.
+*/
+typedef struct {
+#define GAP_CCB_STATE_IDLE 0
+#define GAP_CCB_STATE_LISTENING 1
+#define GAP_CCB_STATE_CONN_SETUP 2
+#define GAP_CCB_STATE_CFG_SETUP 3
+#define GAP_CCB_STATE_WAIT_SEC 4
+#define GAP_CCB_STATE_CONNECTED 5
+ uint8_t con_state;
+
+#define GAP_CCB_FLAGS_IS_ORIG 0x01
+#define GAP_CCB_FLAGS_HIS_CFG_DONE 0x02
+#define GAP_CCB_FLAGS_MY_CFG_DONE 0x04
+#define GAP_CCB_FLAGS_SEC_DONE 0x08
+#define GAP_CCB_FLAGS_CONN_DONE 0x0E
+ uint8_t con_flags;
+
+ uint8_t service_id; /* Used by BTM */
+ uint16_t gap_handle; /* GAP handle */
+ uint16_t connection_id; /* L2CAP CID */
+ bool rem_addr_specified;
+ uint8_t chan_mode_mask; /* Supported channel modes (FCR) */
+ BD_ADDR rem_dev_address;
+ uint16_t psm;
+ uint16_t rem_mtu_size;
+
+ bool is_congested;
+ fixed_queue_t* tx_queue; /* Queue of buffers waiting to be sent */
+ fixed_queue_t* rx_queue; /* Queue of buffers waiting to be read */
+
+ uint32_t rx_queue_size; /* Total data count in rx_queue */
+
+ tGAP_CONN_CALLBACK* p_callback; /* Users callback function */
+
+ tL2CAP_CFG_INFO cfg; /* Configuration */
+ tL2CAP_ERTM_INFO ertm_info; /* Pools and modes for ertm */
+ tBT_TRANSPORT transport; /* Transport channel BR/EDR or BLE */
+ tL2CAP_LE_CFG_INFO local_coc_cfg; /* local configuration for LE Coc */
+ tL2CAP_LE_CFG_INFO peer_coc_cfg; /* local configuration for LE Coc */
+} tGAP_CCB;
+
+typedef struct {
+#if (AMP_INCLUDED == TRUE)
+ tAMP_APPL_INFO reg_info;
+#else
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+#endif
+ tGAP_CCB ccb_pool[GAP_MAX_CONNECTIONS];
+} tGAP_CONN;
+
+#define GAP_MAX_CHAR_NUM 4
+
+typedef struct {
+ uint16_t handle;
+ uint16_t uuid;
+ tGAP_BLE_ATTR_VALUE attr_value;
+} tGAP_ATTR;
+/**********************************************************************
+ * M A I N C O N T R O L B L O C K
+ **********************************************************************/
+
+#define GAP_MAX_CL GATT_CL_MAX_LCB
+
+typedef struct {
+ uint16_t uuid;
+ tGAP_BLE_CMPL_CBACK* p_cback;
+} tGAP_BLE_REQ;
+
+typedef struct {
+ BD_ADDR bda;
+ tGAP_BLE_CMPL_CBACK* p_cback;
+ uint16_t conn_id;
+ uint16_t cl_op_uuid;
+ bool in_use;
+ bool connected;
+ fixed_queue_t* pending_req_q;
+
+} tGAP_CLCB;
+
+typedef struct {
+ tGAP_INFO blk[GAP_MAX_BLOCKS];
+ tBTM_CMPL_CB* btm_cback[GAP_MAX_BLOCKS];
+ uint8_t trace_level;
+ tGAP_FINDADDR_CB
+ findaddr_cb; /* Contains the control block for finding a device addr */
+ tBTM_INQ_INFO* cur_inqptr;
+
+#if (GAP_CONN_INCLUDED == TRUE)
+ tGAP_CONN conn;
+#endif
+
+ /* LE GAP attribute database */
+ tGAP_ATTR gatt_attr[GAP_MAX_CHAR_NUM];
+ tGAP_CLCB clcb[GAP_MAX_CL]; /* connection link*/
+ tGATT_IF gatt_if;
+} tGAP_CB;
+
+extern tGAP_CB gap_cb;
+#if (GAP_CONN_INCLUDED == TRUE)
+extern void gap_conn_init(void);
+#endif
+extern void gap_attr_db_init(void);
+#endif
diff --git a/mtkbt/code/bt/stack/gap/gap_utils.cc b/mtkbt/code/bt/stack/gap/gap_utils.cc
new file mode 100755
index 0000000..fa8b30e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gap/gap_utils.cc
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gap_int.h"
+
+/*******************************************************************************
+ *
+ * Function gap_allocate_cb
+ *
+ * Description Look through the GAP Control Blocks for a free one.
+ *
+ * Returns Pointer to the control block or NULL if not found
+ *
+ ******************************************************************************/
+tGAP_INFO* gap_allocate_cb(void) {
+ tGAP_INFO* p_cb = &gap_cb.blk[0];
+ uint8_t x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) {
+ if (!p_cb->in_use) {
+ memset(p_cb, 0, sizeof(tGAP_INFO));
+
+ p_cb->in_use = true;
+ p_cb->index = x;
+ p_cb->p_data = (void*)NULL;
+ return (p_cb);
+ }
+ }
+
+ /* If here, no free control blocks found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_free_cb
+ *
+ * Description Release GAP control block.
+ *
+ * Returns Pointer to the control block or NULL if not found
+ *
+ ******************************************************************************/
+void gap_free_cb(tGAP_INFO* p_cb) {
+ if (p_cb) {
+ p_cb->gap_cback = NULL;
+ p_cb->in_use = false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gap_is_service_busy
+ *
+ * Description Look through the GAP Control Blocks that are in use
+ * and check to see if the event waiting for is the command
+ * requested.
+ *
+ * Returns true if already in use
+ * false if not busy
+ *
+ ******************************************************************************/
+bool gap_is_service_busy(uint16_t request) {
+ tGAP_INFO* p_cb = &gap_cb.blk[0];
+ uint8_t x;
+
+ for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) {
+ if (p_cb->in_use && p_cb->event == request) return (true);
+ }
+
+ /* If here, service is not busy */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function gap_convert_btm_status
+ *
+ * Description Converts a BTM error status into a GAP error status
+ *
+ *
+ * Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized
+ *
+ ******************************************************************************/
+uint16_t gap_convert_btm_status(tBTM_STATUS btm_status) {
+ switch (btm_status) {
+ case BTM_SUCCESS:
+ return (BT_PASS);
+
+ case BTM_CMD_STARTED:
+ return (GAP_CMD_INITIATED);
+
+ case BTM_BUSY:
+ return (GAP_ERR_BUSY);
+
+ case BTM_MODE_UNSUPPORTED:
+ case BTM_ILLEGAL_VALUE:
+ return (GAP_ERR_ILL_PARM);
+
+ case BTM_WRONG_MODE:
+ return (GAP_DEVICE_NOT_UP);
+
+ case BTM_UNKNOWN_ADDR:
+ return (GAP_BAD_BD_ADDR);
+
+ case BTM_DEVICE_TIMEOUT:
+ return (GAP_ERR_TIMEOUT);
+
+ default:
+ return (GAP_ERR_PROCESSING);
+ }
+}
diff --git a/mtkbt/code/bt/stack/gatt/att_protocol.cc b/mtkbt/code/bt/stack/gatt/att_protocol.cc
new file mode 100755
index 0000000..26bacc0
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/att_protocol.cc
@@ -0,0 +1,570 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains ATT protocol functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+#define GATT_HDR_FIND_TYPE_VALUE_LEN 21
+#define GATT_OP_CODE_SIZE 1
+#define GATT_START_END_HANDLE_SIZE 4
+
+/**********************************************************************
+ * ATT protocl message building utility *
+ **********************************************************************/
+/*******************************************************************************
+ *
+ * Function attp_build_mtu_exec_cmd
+ *
+ * Description Build a exchange MTU request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_mtu_cmd(uint8_t op_code, uint16_t rx_mtu) {
+ uint8_t* p;
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, op_code);
+ UINT16_TO_STREAM(p, rx_mtu);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
+
+ return p_buf;
+}
+/*******************************************************************************
+ *
+ * Function attp_build_exec_write_cmd
+ *
+ * Description Build a execute write request or response.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_exec_write_cmd(uint8_t op_code, uint8_t flag) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(GATT_DATA_BUF_SIZE);
+ uint8_t* p;
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_OP_CODE_SIZE;
+
+ UINT8_TO_STREAM(p, op_code);
+
+ if (op_code == GATT_REQ_EXEC_WRITE) {
+ flag &= GATT_PREP_WRITE_EXEC;
+ UINT8_TO_STREAM(p, flag);
+ p_buf->len += 1;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_err_cmd
+ *
+ * Description Build a exchange MTU request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_err_cmd(uint8_t cmd_code, uint16_t err_handle,
+ uint8_t reason) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, GATT_RSP_ERROR);
+ UINT8_TO_STREAM(p, cmd_code);
+ UINT16_TO_STREAM(p, err_handle);
+ UINT8_TO_STREAM(p, reason);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status
+ */
+ p_buf->len = GATT_HDR_SIZE + 1 + 1;
+
+ return p_buf;
+}
+/*******************************************************************************
+ *
+ * Function attp_build_browse_cmd
+ *
+ * Description Build a read information request or read by type request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_browse_cmd(uint8_t op_code, uint16_t s_hdl, uint16_t e_hdl,
+ tBT_UUID uuid) {
+ const size_t payload_size =
+ (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (LEN_UUID_128);
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+ uint8_t* p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ /* Describe the built message location and size */
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = GATT_OP_CODE_SIZE + 4;
+
+ UINT8_TO_STREAM(p, op_code);
+ UINT16_TO_STREAM(p, s_hdl);
+ UINT16_TO_STREAM(p, e_hdl);
+ p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_read_handles_cmd
+ *
+ * Description Build a read by type and value request.
+ *
+ * Returns pointer to the command buffer.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_read_by_type_value_cmd(uint16_t payload_size,
+ tGATT_FIND_TYPE_VALUE* p_value_type) {
+ uint8_t* p;
+ uint16_t len = p_value_type->value_len;
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 5; /* opcode + s_handle + e_handle */
+
+ UINT8_TO_STREAM(p, GATT_REQ_FIND_TYPE_VALUE);
+ UINT16_TO_STREAM(p, p_value_type->s_handle);
+ UINT16_TO_STREAM(p, p_value_type->e_handle);
+
+ p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
+
+ if (p_value_type->value_len + p_buf->len > payload_size)
+ len = payload_size - p_buf->len;
+
+ memcpy(p, p_value_type->value, len);
+ p_buf->len += len;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_read_multi_cmd
+ *
+ * Description Build a read multiple request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_read_multi_cmd(uint16_t payload_size, uint16_t num_handle,
+ uint16_t* p_handle) {
+ uint8_t *p, i = 0;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + num_handle * 2 + 1 +
+ L2CAP_MIN_OFFSET);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 1;
+
+ UINT8_TO_STREAM(p, GATT_REQ_READ_MULTI);
+
+ for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i++) {
+ UINT16_TO_STREAM(p, *(p_handle + i));
+ p_buf->len += 2;
+ }
+
+ return p_buf;
+}
+/*******************************************************************************
+ *
+ * Function attp_build_handle_cmd
+ *
+ * Description Build a read /read blob request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_handle_cmd(uint8_t op_code, uint16_t handle,
+ uint16_t offset) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ p_buf->offset = L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM(p, op_code);
+ p_buf->len = 1;
+
+ UINT16_TO_STREAM(p, handle);
+ p_buf->len += 2;
+
+ if (op_code == GATT_REQ_READ_BLOB) {
+ UINT16_TO_STREAM(p, offset);
+ p_buf->len += 2;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_opcode_cmd
+ *
+ * Description Build a request/response with opcode only.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_opcode_cmd(uint8_t op_code) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ p_buf->offset = L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM(p, op_code);
+ p_buf->len = 1;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_value_cmd
+ *
+ * Description Build a attribute value request
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code,
+ uint16_t handle, uint16_t offset, uint16_t len,
+ uint8_t* p_data) {
+ uint8_t *p, *pp, pair_len, *p_pair_len;
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
+
+ p = pp = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, op_code);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = 1;
+
+ if (op_code == GATT_RSP_READ_BY_TYPE) {
+ p_pair_len = p;
+ pair_len = len + 2;
+ UINT8_TO_STREAM(p, pair_len);
+ p_buf->len += 1;
+ }
+ if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) {
+ UINT16_TO_STREAM(p, handle);
+ p_buf->len += 2;
+ }
+
+ if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) {
+ UINT16_TO_STREAM(p, offset);
+ p_buf->len += 2;
+ }
+
+ if (len > 0 && p_data != NULL) {
+ /* ensure data not exceed MTU size */
+ if (payload_size - p_buf->len < len) {
+ len = payload_size - p_buf->len;
+ /* update handle value pair length */
+ if (op_code == GATT_RSP_READ_BY_TYPE) *p_pair_len = (len + 2);
+
+ GATT_TRACE_WARNING("attribute value too long, to be truncated to %d",
+ len);
+ }
+
+ ARRAY_TO_STREAM(p, p_data, len);
+ p_buf->len += len;
+ }
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_send_msg_to_l2cap
+ *
+ * Description Send message to L2CAP.
+ *
+ ******************************************************************************/
+tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB* p_tcb, BT_HDR* p_toL2CAP) {
+ uint16_t l2cap_ret;
+
+ if (p_tcb->att_lcid == L2CAP_ATT_CID)
+ l2cap_ret =
+ L2CA_SendFixedChnlData(L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
+ else
+ l2cap_ret = (uint16_t)L2CA_DataWrite(p_tcb->att_lcid, p_toL2CAP);
+
+ if (l2cap_ret == L2CAP_DW_FAILED) {
+ GATT_TRACE_ERROR("ATT failed to pass msg:0x%0x to L2CAP",
+ *((uint8_t*)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ return GATT_INTERNAL_ERROR;
+ } else if (l2cap_ret == L2CAP_DW_CONGESTED) {
+ GATT_TRACE_DEBUG("ATT congested, message accepted");
+ return GATT_CONGESTED;
+ }
+ return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_build_sr_msg
+ *
+ * Description Build ATT Server PDUs.
+ *
+ ******************************************************************************/
+BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
+ tGATT_SR_MSG* p_msg) {
+ BT_HDR* p_cmd = NULL;
+ uint16_t offset = 0;
+
+ switch (op_code) {
+ case GATT_RSP_READ_BLOB:
+ case GATT_RSP_PREPARE_WRITE:
+ GATT_TRACE_EVENT(
+ "ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
+ p_msg->attr_value.len, p_msg->attr_value.offset);
+ offset = p_msg->attr_value.offset;
+ /* Coverity: [FALSE-POSITIVE error] intended fall through */
+ /* Missing break statement between cases in switch statement */
+ /* fall through */
+ case GATT_RSP_READ_BY_TYPE:
+ case GATT_RSP_READ:
+ case GATT_HANDLE_VALUE_NOTIF:
+ case GATT_HANDLE_VALUE_IND:
+ p_cmd = attp_build_value_cmd(
+ p_tcb->payload_size, op_code, p_msg->attr_value.handle, offset,
+ p_msg->attr_value.len, p_msg->attr_value.value);
+ break;
+
+ case GATT_RSP_WRITE:
+ p_cmd = attp_build_opcode_cmd(op_code);
+ break;
+
+ case GATT_RSP_ERROR:
+ p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle,
+ p_msg->error.reason);
+ break;
+
+ case GATT_RSP_EXEC_WRITE:
+ p_cmd = attp_build_exec_write_cmd(op_code, 0);
+ break;
+
+ case GATT_RSP_MTU:
+ p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
+ break;
+
+ default:
+ GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
+ break;
+ }
+
+ if (!p_cmd) GATT_TRACE_ERROR("No resources");
+
+ return p_cmd;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_send_sr_msg
+ *
+ * Description This function sends the server response or indication
+ * message to client.
+ *
+ * Parameter p_tcb: pointer to the connecton control block.
+ * p_msg: pointer to message parameters structure.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ *
+ ******************************************************************************/
+tGATT_STATUS attp_send_sr_msg(tGATT_TCB* p_tcb, BT_HDR* p_msg) {
+ tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
+
+ if (p_tcb != NULL) {
+ if (p_msg != NULL) {
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ cmd_sent = attp_send_msg_to_l2cap(p_tcb, p_msg);
+ }
+ }
+ return cmd_sent;
+}
+
+/*******************************************************************************
+ *
+ * Function attp_cl_send_cmd
+ *
+ * Description Send a ATT command or enqueue it.
+ *
+ * Returns GATT_SUCCESS if command sent
+ * GATT_CONGESTED if command sent but channel congested
+ * GATT_CMD_STARTED if command queue up in GATT
+ * GATT_ERROR if command sending failure
+ *
+ ******************************************************************************/
+tGATT_STATUS attp_cl_send_cmd(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+ uint8_t cmd_code, BT_HDR* p_cmd) {
+ tGATT_STATUS att_ret = GATT_SUCCESS;
+
+ if (p_tcb != NULL) {
+ cmd_code &= ~GATT_AUTH_SIGN_MASK;
+
+ /* no pending request or value confirmation */
+ if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
+ cmd_code == GATT_HANDLE_VALUE_CONF) {
+ att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
+ if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) {
+ /* do not enq cmd if handle value confirmation or set request */
+ if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) {
+ gatt_start_rsp_timer(clcb_idx);
+ gatt_cmd_enq(p_tcb, clcb_idx, false, cmd_code, NULL);
+ }
+ } else
+ att_ret = GATT_INTERNAL_ERROR;
+ } else {
+ att_ret = GATT_CMD_STARTED;
+ gatt_cmd_enq(p_tcb, clcb_idx, true, cmd_code, p_cmd);
+ }
+ } else
+ att_ret = GATT_ERROR;
+
+ return att_ret;
+}
+/*******************************************************************************
+ *
+ * Function attp_send_cl_msg
+ *
+ * Description This function sends the client request or confirmation
+ * message to server.
+ *
+ * Parameter p_tcb: pointer to the connectino control block.
+ * clcb_idx: clcb index
+ * op_code: message op code.
+ * p_msg: pointer to message parameters structure.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ *
+ ******************************************************************************/
+tGATT_STATUS attp_send_cl_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+ uint8_t op_code, tGATT_CL_MSG* p_msg) {
+ tGATT_STATUS status = GATT_NO_RESOURCES;
+ BT_HDR* p_cmd = NULL;
+ uint16_t offset = 0, handle;
+
+ if (p_tcb != NULL) {
+ switch (op_code) {
+ case GATT_REQ_MTU:
+ if (p_msg->mtu <= GATT_MAX_MTU_SIZE) {
+ p_tcb->payload_size = p_msg->mtu;
+ p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
+ } else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_FIND_INFO:
+ case GATT_REQ_READ_BY_TYPE:
+ case GATT_REQ_READ_BY_GRP_TYPE:
+ if (GATT_HANDLE_IS_VALID(p_msg->browse.s_handle) &&
+ GATT_HANDLE_IS_VALID(p_msg->browse.e_handle) &&
+ p_msg->browse.s_handle <= p_msg->browse.e_handle) {
+ p_cmd =
+ attp_build_browse_cmd(op_code, p_msg->browse.s_handle,
+ p_msg->browse.e_handle, p_msg->browse.uuid);
+ } else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_READ_BLOB:
+ offset = p_msg->read_blob.offset;
+ /* fall through */
+ case GATT_REQ_READ:
+ handle = (op_code == GATT_REQ_READ) ? p_msg->handle
+ : p_msg->read_blob.handle;
+ /* handle checking */
+ if (GATT_HANDLE_IS_VALID(handle)) {
+ p_cmd = attp_build_handle_cmd(op_code, handle, offset);
+ } else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_HANDLE_VALUE_CONF:
+ p_cmd = attp_build_opcode_cmd(op_code);
+ break;
+
+ case GATT_REQ_PREPARE_WRITE:
+ offset = p_msg->attr_value.offset;
+ /* fall through */
+ case GATT_REQ_WRITE:
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ if (GATT_HANDLE_IS_VALID(p_msg->attr_value.handle)) {
+ p_cmd = attp_build_value_cmd(
+ p_tcb->payload_size, op_code, p_msg->attr_value.handle, offset,
+ p_msg->attr_value.len, p_msg->attr_value.value);
+ } else
+ status = GATT_ILLEGAL_PARAMETER;
+ break;
+
+ case GATT_REQ_EXEC_WRITE:
+ p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
+ break;
+
+ case GATT_REQ_FIND_TYPE_VALUE:
+ p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size,
+ &p_msg->find_type_value);
+ break;
+
+ case GATT_REQ_READ_MULTI:
+ p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size,
+ p_msg->read_multi.num_handles,
+ p_msg->read_multi.handles);
+ break;
+
+ default:
+ break;
+ }
+
+ if (p_cmd != NULL)
+ status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
+
+ } else {
+ GATT_TRACE_ERROR("Peer device not connected");
+ }
+
+ return status;
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_api.cc b/mtkbt/code/bt/stack/gatt/gatt_api.cc
new file mode 100755
index 0000000..ea48652
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_api.cc
@@ -0,0 +1,1485 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains GATT interface functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#include <base/bind.h>
+#include <stdio.h>
+#include <string.h>
+#include "bt_common.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+
+/*******************************************************************************
+ *
+ * Function GATT_SetTraceLevel
+ *
+ * Description This function sets the trace level. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Input Parameters:
+ * level: The level to set the GATT tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t GATT_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) gatt_cb.trace_level = new_level;
+
+ return (gatt_cb.trace_level);
+}
+
+/**
+ * Add an service handle range to the list in decending order of the start
+ * handle. Return reference to the newly added element.
+ **/
+tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) {
+ auto lst_ptr = gatt_cb.hdl_list_info;
+ auto it = lst_ptr->begin();
+ for (; it != lst_ptr->end(); it++) {
+ if (s_handle > it->asgn_range.s_handle) break;
+ }
+
+ auto rit = lst_ptr->emplace(it);
+ return *rit;
+}
+
+/*****************************************************************************
+ *
+ * GATT SERVER API
+ *
+ *****************************************************************************/
+/*******************************************************************************
+ *
+ * Function GATTS_AddHandleRange
+ *
+ * Description This function add the allocated handles range for the
+ * specified application UUID, service UUID and service
+ * instance
+ *
+ * Parameter p_hndl_range: pointer to allocated handles information
+ *
+ **/
+
+void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range) {
+ gatt_add_an_item_to_list(p_hndl_range->s_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_NVRegister
+ *
+ * Description Application manager calls this function to register for
+ * NV save callback function. There can be one and only one
+ * NV save callback function.
+ *
+ * Parameter p_cb_info : callback informaiton
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info) {
+ bool status = false;
+ if (p_cb_info) {
+ gatt_cb.cb_info = *p_cb_info;
+ status = true;
+ gatt_init_srv_chg();
+ }
+
+ return status;
+}
+
+static uint8_t BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static int uuidType(unsigned char* p_uuid) {
+ if (memcmp(p_uuid, BASE_UUID, 12) != 0) return LEN_UUID_128;
+ if (memcmp(p_uuid + 14, BASE_UUID + 14, 2) != 0) return LEN_UUID_32;
+
+ return LEN_UUID_16;
+}
+
+/*******************************************************************************
+ * BTIF -> BTA conversion functions
+ ******************************************************************************/
+
+static void btif_to_bta_uuid(tBT_UUID* p_dest, bt_uuid_t* p_src) {
+ char* p_byte = (char*)p_src;
+ int i = 0;
+
+ p_dest->len = uuidType(p_src->uu);
+
+ switch (p_dest->len) {
+ case LEN_UUID_16:
+ p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
+ break;
+
+ case LEN_UUID_32:
+ p_dest->uu.uuid32 = (p_src->uu[15] << 24) + (p_src->uu[14] << 16) +
+ (p_src->uu[13] << 8) + p_src->uu[12];
+ break;
+
+ case LEN_UUID_128:
+ for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
+ break;
+
+ default:
+ GATT_TRACE_ERROR("%s: Unknown UUID length %d!", __func__, p_dest->len);
+ break;
+ }
+}
+
+void uuid_128_from_16(bt_uuid_t* uuid, uint16_t uuid16) {
+ memcpy(uuid, &BASE_UUID, sizeof(bt_uuid_t));
+
+ uuid->uu[13] = (uint8_t)((0xFF00 & uuid16) >> 8);
+ uuid->uu[12] = (uint8_t)(0x00FF & uuid16);
+}
+
+static uint16_t compute_service_size(btgatt_db_element_t* service, int count) {
+ int db_size = 0;
+ btgatt_db_element_t* el = service;
+
+ for (int i = 0; i < count; i++, el++)
+ if (el->type == BTGATT_DB_PRIMARY_SERVICE ||
+ el->type == BTGATT_DB_SECONDARY_SERVICE ||
+ el->type == BTGATT_DB_DESCRIPTOR ||
+ el->type == BTGATT_DB_INCLUDED_SERVICE)
+ db_size += 1;
+ else if (el->type == BTGATT_DB_CHARACTERISTIC)
+ db_size += 2;
+ else
+ GATT_TRACE_ERROR("%s: Unknown element type: %d", __func__, el->type);
+
+ return db_size;
+}
+
+static bool is_gatt_attr_type(const tBT_UUID& uuid) {
+ if (uuid.len == LEN_UUID_16 && (uuid.uu.uuid16 == GATT_UUID_PRI_SERVICE ||
+ uuid.uu.uuid16 == GATT_UUID_SEC_SERVICE ||
+ uuid.uu.uuid16 == GATT_UUID_INCLUDE_SERVICE ||
+ uuid.uu.uuid16 == GATT_UUID_CHAR_DECLARE)) {
+ return true;
+ }
+ return false;
+}
+
+/** Update the the last primary info for the service list info */
+static void gatt_update_last_pri_srv_info() {
+ gatt_cb.last_primary_s_handle = 0;
+
+ for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info)
+ if (el.is_primary) gatt_cb.last_primary_s_handle = el.s_hdl;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_AddService
+ *
+ * Description This function is called to add GATT service.
+ *
+ * Parameter gatt_if : application if
+ * service : pseudo-representation of service and it's content
+ * count : size of service
+ *
+ * Returns on success GATT_SERVICE_STARTED is returned, and
+ * attribute_handle field inside service elements are filled.
+ * on error error status is returned.
+ *
+ ******************************************************************************/
+uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service,
+ int count) {
+ uint16_t s_hdl = 0;
+ bool save_hdl = false;
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ tBT_UUID* p_app_uuid128;
+
+ bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false;
+ tBT_UUID svc_uuid;
+ btif_to_bta_uuid(&svc_uuid, &service->uuid);
+
+ GATT_TRACE_API("%s", __func__);
+
+ if (p_reg == NULL) {
+ GATT_TRACE_ERROR("Inavlid gatt_if=%d", gatt_if);
+ return GATT_INTERNAL_ERROR;
+ }
+
+ p_app_uuid128 = &p_reg->app_uuid128;
+
+ uint16_t num_handles = compute_service_size(service, count);
+
+ if ((svc_uuid.len == LEN_UUID_16) &&
+ (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) {
+ s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl;
+ } else if ((svc_uuid.len == LEN_UUID_16) &&
+ (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) {
+ s_hdl = gatt_cb.hdl_cfg.gap_start_hdl;
+ } else {
+ if (!gatt_cb.hdl_list_info->empty()) {
+ s_hdl = gatt_cb.hdl_list_info->front().asgn_range.e_handle + 1;
+ }
+
+ if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
+ s_hdl = gatt_cb.hdl_cfg.app_start_hdl;
+
+ save_hdl = true;
+ }
+
+ /* check for space */
+ if (num_handles > (0xFFFF - s_hdl + 1)) {
+ GATT_TRACE_ERROR("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u",
+ s_hdl, num_handles);
+ return GATT_INTERNAL_ERROR;
+ }
+
+ tGATT_HDL_LIST_ELEM& list = gatt_add_an_item_to_list(s_hdl);
+ list.asgn_range.app_uuid128 = *p_app_uuid128;
+ list.asgn_range.svc_uuid = svc_uuid;
+ list.asgn_range.s_handle = s_hdl;
+ list.asgn_range.e_handle = s_hdl + num_handles - 1;
+ list.asgn_range.is_primary = is_pri;
+
+ if (save_hdl) {
+ if (gatt_cb.cb_info.p_nv_save_callback)
+ (*gatt_cb.cb_info.p_nv_save_callback)(true, &list.asgn_range);
+ }
+
+ gatts_init_service_db(list.svc_db, &svc_uuid, is_pri, s_hdl, num_handles);
+
+ GATT_TRACE_DEBUG(
+ "%d: handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", __func__,
+ num_handles, list.asgn_range.s_handle, list.asgn_range.e_handle,
+ ((list.asgn_range.svc_uuid.len == 2) ? "uuid16" : "uuid128"),
+ list.asgn_range.svc_uuid.uu.uuid16, list.asgn_range.is_primary);
+
+ service->attribute_handle = s_hdl;
+
+ btgatt_db_element_t* el = service + 1;
+ for (int i = 0; i < count - 1; i++, el++) {
+ tBT_UUID uuid;
+ btif_to_bta_uuid(&uuid, &el->uuid);
+
+ if (el->type == BTGATT_DB_CHARACTERISTIC) {
+ /* data validity checking */
+ if (((el->properties & GATT_CHAR_PROP_BIT_AUTH) &&
+ !(el->permissions & GATT_WRITE_SIGNED_PERM)) ||
+ ((el->permissions & GATT_WRITE_SIGNED_PERM) &&
+ !(el->properties & GATT_CHAR_PROP_BIT_AUTH))) {
+ GATT_TRACE_DEBUG("Invalid configuration property=0x%02x perm=0x%04x ",
+ el->properties, el->permissions);
+ return GATT_INTERNAL_ERROR;
+ }
+
+ if (is_gatt_attr_type(uuid)) {
+ GATT_TRACE_ERROR(
+ "%s: attept to add characteristic with UUID equal to GATT "
+ "Attribute Type 0x%04x ",
+ __func__, uuid.uu.uuid16);
+ return GATT_INTERNAL_ERROR;
+ }
+
+ el->attribute_handle = gatts_add_characteristic(
+ list.svc_db, el->permissions, el->properties, uuid);
+ } else if (el->type == BTGATT_DB_DESCRIPTOR) {
+ if (is_gatt_attr_type(uuid)) {
+ GATT_TRACE_ERROR(
+ "%s: attept to add descriptor with UUID equal to GATT "
+ "Attribute Type 0x%04x ",
+ __func__, uuid.uu.uuid16);
+ return GATT_INTERNAL_ERROR;
+ }
+
+ el->attribute_handle =
+ gatts_add_char_descr(list.svc_db, el->permissions, uuid);
+ } else if (el->type == BTGATT_DB_INCLUDED_SERVICE) {
+ tGATT_HDL_LIST_ELEM* p_incl_decl;
+ p_incl_decl = gatt_find_hdl_buffer_by_handle(el->attribute_handle);
+ if (p_incl_decl == nullptr) {
+ GATT_TRACE_DEBUG("Included Service not created");
+ return GATT_INTERNAL_ERROR;
+ }
+
+ el->attribute_handle = gatts_add_included_service(
+ list.svc_db, p_incl_decl->asgn_range.s_handle,
+ p_incl_decl->asgn_range.e_handle, p_incl_decl->asgn_range.svc_uuid);
+ }
+ }
+
+ GATT_TRACE_API("%s: service parsed correctly, now starting", __func__);
+
+ /*this is a new application service start */
+
+ // find a place for this service in the list
+ auto lst_ptr = gatt_cb.srv_list_info;
+ auto it = lst_ptr->begin();
+ for (; it != lst_ptr->end(); it++) {
+ if (list.asgn_range.s_handle < it->s_hdl) break;
+ }
+ auto rit = lst_ptr->emplace(it);
+
+ tGATT_SRV_LIST_ELEM& elem = *rit;
+ elem.gatt_if = gatt_if;
+ elem.s_hdl = list.asgn_range.s_handle;
+ elem.e_hdl = list.asgn_range.e_handle;
+ elem.p_db = &list.svc_db;
+ elem.is_primary = list.asgn_range.is_primary;
+
+ memcpy(&elem.app_uuid, &list.asgn_range.app_uuid128, sizeof(tBT_UUID));
+ elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
+ : GATT_UUID_SEC_SERVICE;
+
+ if (elem.type == GATT_UUID_PRI_SERVICE) {
+ tBT_UUID* p_uuid = gatts_get_service_uuid(elem.p_db);
+ elem.sdp_handle = gatt_add_sdp_record(p_uuid, elem.s_hdl, elem.e_hdl);
+ } else {
+ elem.sdp_handle = 0;
+ }
+
+ gatt_update_last_pri_srv_info();
+
+ GATT_TRACE_DEBUG("%s: allocated el: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x",
+ __func__, elem.s_hdl, elem.e_hdl, elem.type,
+ elem.sdp_handle);
+
+ gatt_proc_srv_chg();
+
+ return GATT_SERVICE_STARTED;
+}
+
+bool is_active_service(tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid,
+ uint16_t start_handle) {
+ for (auto& info : *gatt_cb.srv_list_info) {
+ tBT_UUID* p_this_uuid = gatts_get_service_uuid(info.p_db);
+
+ if (p_this_uuid && gatt_uuid_compare(*p_app_uuid128, info.app_uuid) &&
+ gatt_uuid_compare(*p_svc_uuid, *p_this_uuid) &&
+ (start_handle == info.s_hdl)) {
+ GATT_TRACE_ERROR("Active Service Found ");
+ gatt_dbg_display_uuid(*p_svc_uuid);
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_DeleteService
+ *
+ * Description This function is called to delete a service.
+ *
+ * Parameter gatt_if : application interface
+ * p_svc_uuid : service UUID
+ * start_handle : start handle of the service
+ *
+ * Returns true if the operation succeeded, false if the handle block
+ * was not found.
+ *
+ ******************************************************************************/
+bool GATTS_DeleteService(tGATT_IF gatt_if, tBT_UUID* p_svc_uuid,
+ uint16_t svc_inst) {
+ GATT_TRACE_DEBUG("GATTS_DeleteService");
+
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ if (p_reg == NULL) {
+ GATT_TRACE_ERROR("Applicaiton not foud");
+ return false;
+ }
+
+ tBT_UUID* p_app_uuid128 = &p_reg->app_uuid128;
+ auto it = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst);
+ if (it == gatt_cb.hdl_list_info->end()) {
+ GATT_TRACE_ERROR("No Service found");
+ return false;
+ }
+
+ gatt_proc_srv_chg();
+
+ if (is_active_service(p_app_uuid128, p_svc_uuid, svc_inst)) {
+ GATTS_StopService(it->asgn_range.s_handle);
+ }
+
+ GATT_TRACE_DEBUG("released handles s_hdl=%u e_hdl=%u",
+ it->asgn_range.s_handle, it->asgn_range.e_handle);
+
+ if ((it->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) &&
+ gatt_cb.cb_info.p_nv_save_callback)
+ (*gatt_cb.cb_info.p_nv_save_callback)(false, &it->asgn_range);
+
+ gatt_cb.hdl_list_info->erase(it);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_StopService
+ *
+ * Description This function is called to stop a service
+ *
+ * Parameter service_handle : this is the start handle of a service
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void GATTS_StopService(uint16_t service_handle) {
+ GATT_TRACE_API("%s: %u", __func__, service_handle);
+
+ auto it = gatt_sr_find_i_rcb_by_handle(service_handle);
+ if (it == gatt_cb.srv_list_info->end()) {
+ GATT_TRACE_ERROR("%s: service_handle: %u is not in use", __func__,
+ service_handle);
+ }
+
+ if (it->sdp_handle) {
+ SDP_DeleteRecord(it->sdp_handle);
+ }
+
+ gatt_cb.srv_list_info->erase(it);
+ gatt_update_last_pri_srv_info();
+}
+/*******************************************************************************
+ *
+ * Function GATTs_HandleValueIndication
+ *
+ * Description This function sends a handle value indication to a client.
+ *
+ * Parameter conn_id: connection identifier.
+ * attr_handle: Attribute handle of this handle value
+ * indication.
+ * val_len: Length of the indicated attribute value.
+ * p_val: Pointer to the indicated attribute value data.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error
+ * code.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
+ uint16_t val_len, uint8_t* p_val) {
+ tGATT_STATUS cmd_status = GATT_NO_RESOURCES;
+
+ tGATT_VALUE indication;
+ BT_HDR* p_msg;
+ tGATT_VALUE* p_buf;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ GATT_TRACE_API("GATTS_HandleValueIndication");
+ if ((p_reg == NULL) || (p_tcb == NULL)) {
+ GATT_TRACE_ERROR("GATTS_HandleValueIndication Unknown conn_id: %u ",
+ conn_id);
+ return (tGATT_STATUS)GATT_INVALID_CONN_ID;
+ }
+
+ if (!GATT_HANDLE_IS_VALID(attr_handle)) return GATT_ILLEGAL_PARAMETER;
+
+ indication.conn_id = conn_id;
+ indication.handle = attr_handle;
+ indication.len = val_len;
+ memcpy(indication.value, p_val, val_len);
+ indication.auth_req = GATT_AUTH_REQ_NONE;
+
+ if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
+ GATT_TRACE_DEBUG("Add a pending indication");
+ p_buf = gatt_add_pending_ind(p_tcb, &indication);
+ if (p_buf != NULL) {
+ cmd_status = GATT_SUCCESS;
+ } else {
+ cmd_status = GATT_NO_RESOURCES;
+ }
+ } else {
+ p_msg = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_IND,
+ (tGATT_SR_MSG*)&indication);
+ if (p_msg != NULL) {
+ cmd_status = attp_send_sr_msg(p_tcb, p_msg);
+
+ if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
+ p_tcb->indicate_handle = indication.handle;
+ gatt_start_conf_timer(p_tcb);
+ }
+ }
+ }
+ return cmd_status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_HandleValueNotification
+ *
+ * Description This function sends a handle value notification to a client.
+ *
+ * Parameter conn_id: connection identifier.
+ * attr_handle: Attribute handle of this handle value
+ * indication.
+ * val_len: Length of the indicated attribute value.
+ * p_val: Pointer to the indicated attribute value data.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
+ uint16_t attr_handle,
+ uint16_t val_len, uint8_t* p_val) {
+ tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
+ BT_HDR* p_buf;
+ tGATT_VALUE notif;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ GATT_TRACE_API("GATTS_HandleValueNotification");
+
+ if ((p_reg == NULL) || (p_tcb == NULL)) {
+ GATT_TRACE_ERROR("GATTS_HandleValueNotification Unknown conn_id: %u ",
+ conn_id);
+ return (tGATT_STATUS)GATT_INVALID_CONN_ID;
+ }
+
+ if (GATT_HANDLE_IS_VALID(attr_handle)) {
+ notif.handle = attr_handle;
+ notif.len = val_len;
+ memcpy(notif.value, p_val, val_len);
+ notif.auth_req = GATT_AUTH_REQ_NONE;
+ ;
+
+ p_buf = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_NOTIF,
+ (tGATT_SR_MSG*)&notif);
+ if (p_buf != NULL) {
+ cmd_sent = attp_send_sr_msg(p_tcb, p_buf);
+ } else
+ cmd_sent = GATT_NO_RESOURCES;
+ }
+ return cmd_sent;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTS_SendRsp
+ *
+ * Description This function sends the server response to client.
+ *
+ * Parameter conn_id: connection identifier.
+ * trans_id: transaction id
+ * status: response status
+ * p_msg: pointer to message parameters structure.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+ tGATT_STATUS status, tGATTS_RSP* p_msg) {
+ tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ GATT_TRACE_API("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x",
+ conn_id, trans_id, status);
+
+ if ((p_reg == NULL) || (p_tcb == NULL)) {
+ GATT_TRACE_ERROR("GATTS_SendRsp Unknown conn_id: %u ", conn_id);
+ return (tGATT_STATUS)GATT_INVALID_CONN_ID;
+ }
+
+ if (p_tcb->sr_cmd.trans_id != trans_id) {
+ GATT_TRACE_ERROR("GATTS_SendRsp conn_id: %u waiting for op_code = %02x",
+ conn_id, p_tcb->sr_cmd.op_code);
+
+ return (GATT_WRONG_STATE);
+ }
+ /* Process App response */
+ cmd_sent = gatt_sr_process_app_rsp(p_tcb, gatt_if, trans_id,
+ p_tcb->sr_cmd.op_code, status, p_msg);
+
+ return cmd_sent;
+}
+
+/******************************************************************************/
+/* GATT Profile Srvr Functions */
+/******************************************************************************/
+
+/******************************************************************************/
+/* */
+/* GATT CLIENT APIs */
+/* */
+/******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function GATTC_ConfigureMTU
+ *
+ * Description This function is called to configure the ATT MTU size.
+ *
+ * Parameters conn_id: connection identifier.
+ * mtu - attribute MTU size..
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
+ uint8_t ret = GATT_NO_RESOURCES;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ tGATT_CLCB* p_clcb;
+
+ GATT_TRACE_API("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu);
+
+ if ((p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) ||
+ (mtu > GATT_MAX_MTU_SIZE)) {
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ /* Validate that the link is BLE, not BR/EDR */
+ if (p_tcb->transport != BT_TRANSPORT_LE) {
+ return GATT_ERROR;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id)) {
+ GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ p_clcb = gatt_clcb_alloc(conn_id);
+ if (p_clcb != NULL) {
+ p_clcb->p_tcb->payload_size = mtu;
+ p_clcb->operation = GATTC_OPTYPE_CONFIG;
+
+ ret = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU,
+ (tGATT_CL_MSG*)&mtu);
+ }
+
+ return ret;
+}
+
+void read_phy_cb(
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
+ uint8_t* data, uint16_t len) {
+ uint8_t status, tx_phy, rx_phy;
+ uint16_t handle;
+
+ LOG_ASSERT(len == 5) << "Received bad response length: " << len;
+ uint8_t* pp = data;
+ STREAM_TO_UINT8(status, pp);
+ STREAM_TO_UINT16(handle, pp);
+ handle = handle & 0x0FFF;
+ STREAM_TO_UINT8(tx_phy, pp);
+ STREAM_TO_UINT8(rx_phy, pp);
+
+ DVLOG(1) << __func__ << " Received read_phy_cb";
+ cb.Run(tx_phy, rx_phy, status);
+}
+
+void GATTC_ReadPHY(
+ uint16_t conn_id,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ if (p_tcb == NULL) {
+ GATT_TRACE_ERROR("%s: no p_tcb for conn_id %d", __func__, conn_id);
+ cb.Run(0, 0, GATT_INVALID_HANDLE);
+ return;
+ }
+
+ tACL_CONN* p_lcb = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
+ if (p_lcb == NULL) {
+ GATT_TRACE_ERROR("%s: no p_lcb for conn_id %d", __func__, conn_id);
+ cb.Run(0, 0, GATT_INVALID_HANDLE);
+ return;
+ }
+ uint16_t handle = p_lcb->hci_handle;
+
+ const uint8_t len = 2;
+ uint8_t data[len];
+ uint8_t* pp = data;
+ UINT16_TO_STREAM(pp, handle);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_READ_PHY, data, len,
+ base::Bind(&read_phy_cb, std::move(cb)));
+}
+
+void doNothing(uint8_t* data, uint16_t len) {}
+
+void GATTC_SetPreferredPHY(uint16_t conn_id, uint8_t tx_phy, uint8_t rx_phy,
+ uint16_t phy_options) {
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ if (p_tcb == NULL) {
+ GATT_TRACE_ERROR("%s: no p_tcb for conn_id %d", __func__, conn_id);
+ return;
+ }
+
+ tACL_CONN* p_lcb = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
+ if (p_lcb == NULL) {
+ GATT_TRACE_ERROR("%s: no p_lcb for conn_id %d", __func__, conn_id);
+ return;
+ }
+ uint16_t handle = p_lcb->hci_handle;
+
+ uint8_t all_phys = 0;
+ if (tx_phy == 0) all_phys &= 0x01;
+ if (rx_phy == 0) all_phys &= 0x02;
+
+ const uint8_t len = 7;
+ uint8_t data[len];
+ uint8_t* pp = data;
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, all_phys);
+ UINT8_TO_STREAM(pp, tx_phy);
+ UINT8_TO_STREAM(pp, rx_phy);
+ UINT16_TO_STREAM(pp, phy_options);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_SET_PHY, data, len,
+ base::Bind(doNothing));
+}
+
+/*******************************************************************************
+ *
+ * Function GATTC_Discover
+ *
+ * Description This function is called to do a discovery procedure on ATT
+ * server.
+ *
+ * Parameters conn_id: connection identifier.
+ * disc_type:discovery type.
+ * p_param: parameters of discovery requirement.
+ *
+ * Returns GATT_SUCCESS if command received/sent successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_PARAM* p_param) {
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB* p_clcb;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ GATT_TRACE_API("GATTC_Discover conn_id=%d disc_type=%d", conn_id, disc_type);
+
+ if ((p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) ||
+ (disc_type >= GATT_DISC_MAX)) {
+ GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d",
+ disc_type, conn_id);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id)) {
+ GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ p_clcb = gatt_clcb_alloc(conn_id);
+ if (p_clcb != NULL) {
+ if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
+ !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
+ /* search by type does not have a valid UUID param */
+ (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.len == 0)) {
+ gatt_clcb_dealloc(p_clcb);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
+ p_clcb->op_subtype = disc_type;
+ p_clcb->s_handle = p_param->s_handle;
+ p_clcb->e_handle = p_param->e_handle;
+ p_clcb->uuid = p_param->service;
+
+ gatt_act_discovery(p_clcb);
+ } else {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTC_Read
+ *
+ * Description This function is called to read the value of an attribute
+ * from the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * type - attribute read type.
+ * p_read - read operation parameters.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
+ tGATT_READ_PARAM* p_read) {
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB* p_clcb;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ GATT_TRACE_API("GATTC_Read conn_id=%d type=%d", conn_id, type);
+
+ if ((p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) ||
+ ((type >= GATT_READ_MAX) || (type == 0))) {
+ GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id,
+ type);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id)) {
+ GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ p_clcb = gatt_clcb_alloc(conn_id);
+ if (p_clcb != NULL) {
+ p_clcb->operation = GATTC_OPTYPE_READ;
+ p_clcb->op_subtype = type;
+ p_clcb->auth_req = p_read->by_handle.auth_req;
+ p_clcb->counter = 0;
+
+ switch (type) {
+ case GATT_READ_BY_TYPE:
+ case GATT_READ_CHAR_VALUE:
+ p_clcb->s_handle = p_read->service.s_handle;
+ p_clcb->e_handle = p_read->service.e_handle;
+ memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
+ break;
+ case GATT_READ_MULTIPLE: {
+ p_clcb->s_handle = 0;
+ /* copy multiple handles in CB */
+ tGATT_READ_MULTI* p_read_multi =
+ (tGATT_READ_MULTI*)osi_malloc(sizeof(tGATT_READ_MULTI));
+ p_clcb->p_attr_buf = (uint8_t*)p_read_multi;
+ memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
+ break;
+ }
+ case GATT_READ_BY_HANDLE:
+ case GATT_READ_PARTIAL:
+ memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
+ p_clcb->s_handle = p_read->by_handle.handle;
+
+ if (type == GATT_READ_PARTIAL) {
+ p_clcb->counter = p_read->partial.offset;
+ }
+
+ break;
+ default:
+ break;
+ }
+ /* start security check */
+ if (gatt_security_check_start(p_clcb) == false) {
+ status = GATT_NO_RESOURCES;
+ gatt_clcb_dealloc(p_clcb);
+ }
+ } else {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTC_Write
+ *
+ * Description This function is called to write the value of an attribute
+ * to the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * type - attribute write type.
+ * p_write - write operation parameters.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
+ tGATT_VALUE* p_write) {
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB* p_clcb;
+ tGATT_VALUE* p;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ if ((p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) ||
+ ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) &&
+ (type != GATT_WRITE_NO_RSP))) {
+ GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id,
+ type);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id)) {
+ GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ p_clcb = gatt_clcb_alloc(conn_id);
+ if (p_clcb != NULL) {
+ p_clcb->operation = GATTC_OPTYPE_WRITE;
+ p_clcb->op_subtype = type;
+ p_clcb->auth_req = p_write->auth_req;
+
+ p_clcb->p_attr_buf = (uint8_t*)osi_malloc(sizeof(tGATT_VALUE));
+ memcpy(p_clcb->p_attr_buf, (void*)p_write, sizeof(tGATT_VALUE));
+
+ p = (tGATT_VALUE*)p_clcb->p_attr_buf;
+ if (type == GATT_WRITE_PREPARE) {
+ p_clcb->start_offset = p_write->offset;
+ p->offset = 0;
+ }
+
+ if (gatt_security_check_start(p_clcb) == false) {
+ status = GATT_NO_RESOURCES;
+ }
+
+ if (status == GATT_NO_RESOURCES) gatt_clcb_dealloc(p_clcb);
+ } else {
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTC_ExecuteWrite
+ *
+ * Description This function is called to send an Execute write request to
+ * the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * is_execute - to execute or cancel the prepared write
+ * request(s)
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
+ tGATT_STATUS status = GATT_SUCCESS;
+ tGATT_CLCB* p_clcb;
+ tGATT_EXEC_FLAG flag;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ GATT_TRACE_API("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id,
+ is_execute);
+
+ if ((p_tcb == NULL) || (p_reg == NULL)) {
+ GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
+ return GATT_ILLEGAL_PARAMETER;
+ }
+
+ if (gatt_is_clcb_allocated(conn_id)) {
+ GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
+ return GATT_BUSY;
+ }
+
+ p_clcb = gatt_clcb_alloc(conn_id);
+ if (p_clcb != NULL) {
+ p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
+ flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
+ gatt_send_queue_write_cancel(p_clcb->p_tcb, p_clcb, flag);
+ } else {
+ GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
+ status = GATT_NO_RESOURCES;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATTC_SendHandleValueConfirm
+ *
+ * Description This function is called to send a handle value confirmation
+ * as response to a handle value notification from server.
+ *
+ * Parameters conn_id: connection identifier.
+ * handle: the handle of the attribute confirmation.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) {
+ tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
+
+ GATT_TRACE_API("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id,
+ handle);
+
+ if (p_tcb) {
+ if (p_tcb->ind_count > 0) {
+ alarm_cancel(p_tcb->ind_ack_timer);
+
+ GATT_TRACE_DEBUG("notif_count=%d ", p_tcb->ind_count);
+ /* send confirmation now */
+ ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF,
+ (tGATT_CL_MSG*)&handle);
+
+ p_tcb->ind_count = 0;
+
+ } else {
+ GATT_TRACE_DEBUG(
+ "GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting "
+ "for indicaiton ack",
+ conn_id);
+ ret = GATT_SUCCESS;
+ }
+ } else {
+ GATT_TRACE_ERROR("GATTC_SendHandleValueConfirm - Unknown conn_id: %u",
+ conn_id);
+ }
+ return ret;
+}
+
+/******************************************************************************/
+/* */
+/* GATT APIs */
+/* */
+/******************************************************************************/
+/*******************************************************************************
+ *
+ * Function GATT_SetIdleTimeout
+ *
+ * Description This function (common to both client and server) sets the
+ * idle timeout for a tansport connection
+ *
+ * Parameter bd_addr: target device bd address.
+ * idle_tout: timeout value in seconds.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void GATT_SetIdleTimeout(BD_ADDR bd_addr, uint16_t idle_tout,
+ tBT_TRANSPORT transport) {
+ tGATT_TCB* p_tcb;
+ bool status = false;
+
+ p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ if (p_tcb != NULL) {
+ if (p_tcb->att_lcid == L2CAP_ATT_CID) {
+ status = L2CA_SetFixedChannelTout(bd_addr, L2CAP_ATT_CID, idle_tout);
+
+ if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
+ L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
+ GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+ BT_TRANSPORT_LE);
+ } else {
+ status = L2CA_SetIdleTimeout(p_tcb->att_lcid, idle_tout, false);
+ }
+ }
+
+ GATT_TRACE_API(
+ "GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
+ idle_tout, status);
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_Register
+ *
+ * Description This function is called to register an application
+ * with GATT
+ *
+ * Parameter p_app_uuid128: Application UUID
+ * p_cb_info: callback functions.
+ *
+ * Returns 0 for error, otherwise the index of the client registered
+ * with GATT
+ *
+ ******************************************************************************/
+tGATT_IF GATT_Register(tBT_UUID* p_app_uuid128, tGATT_CBACK* p_cb_info) {
+ tGATT_REG* p_reg;
+ uint8_t i_gatt_if = 0;
+ tGATT_IF gatt_if = 0;
+
+ GATT_TRACE_API("%s", __func__);
+ gatt_dbg_display_uuid(*p_app_uuid128);
+
+ for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
+ i_gatt_if++, p_reg++) {
+ if (p_reg->in_use &&
+ !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128,
+ LEN_UUID_128)) {
+ GATT_TRACE_ERROR("application already registered.");
+ return 0;
+ }
+ }
+
+ for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
+ i_gatt_if++, p_reg++) {
+ if (!p_reg->in_use) {
+ memset(p_reg, 0, sizeof(tGATT_REG));
+ i_gatt_if++; /* one based number */
+ p_reg->app_uuid128 = *p_app_uuid128;
+ gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
+ p_reg->app_cb = *p_cb_info;
+ p_reg->in_use = true;
+
+ GATT_TRACE_API("%s: allocated gatt_if=%d", __func__, gatt_if);
+ return gatt_if;
+ }
+ }
+
+ GATT_TRACE_ERROR("%s: can't Register GATT client, MAX client %d reached!",
+ __func__, GATT_MAX_APPS);
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_Deregister
+ *
+ * Description This function deregistered the application from GATT.
+ *
+ * Parameters gatt_if: applicaiton interface.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void GATT_Deregister(tGATT_IF gatt_if) {
+ GATT_TRACE_API("GATT_Deregister gatt_if=%d", gatt_if);
+
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ /* Index 0 is GAP and is never deregistered */
+ if ((gatt_if == 0) || (p_reg == NULL)) {
+ GATT_TRACE_ERROR("GATT_Deregister with invalid gatt_if: %u", gatt_if);
+ return;
+ }
+
+ /* stop all services */
+ /* todo an applcaiton can not be deregistered if its services is also used by
+ other application
+ deregisteration need to bed performed in an orderly fashion
+ no check for now */
+ auto it = gatt_cb.srv_list_info->begin();
+ while( it != gatt_cb.srv_list_info->end()) {
+ /** M: should add iterator first, GATTS_StopService may erase item
+ in srv_list_info which makes iterator lose efficacy. If operate iterator after
+ that, NE happens @{ */
+ auto it_tmp = it++;
+ if (it_tmp->gatt_if == gatt_if) {
+ GATTS_StopService(it_tmp->s_hdl);
+ /** @} */
+ }
+ }
+
+ /* free all services db buffers if owned by this application */
+ gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
+
+ /* When an application deregisters, check remove the link associated with the
+ * app */
+ tGATT_TCB* p_tcb;
+ int i, j;
+ for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) {
+ if (p_tcb->in_use) {
+ if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
+ }
+
+ tGATT_CLCB* p_clcb;
+ for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB;
+ j++, p_clcb++) {
+ if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
+ (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+ gatt_clcb_dealloc(p_clcb);
+ break;
+ }
+ }
+ }
+ }
+
+ gatt_deregister_bgdev_list(gatt_if);
+
+ memset(p_reg, 0, sizeof(tGATT_REG));
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_StartIf
+ *
+ * Description This function is called after registration to start
+ * receiving callbacks for registered interface. Function may
+ * call back with connection status and queued notifications
+ *
+ * Parameter gatt_if: applicaiton interface.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+void GATT_StartIf(tGATT_IF gatt_if) {
+ tGATT_REG* p_reg;
+ tGATT_TCB* p_tcb;
+ BD_ADDR bda;
+ uint8_t start_idx, found_idx;
+ uint16_t conn_id;
+ tGATT_TRANSPORT transport;
+
+ GATT_TRACE_API("GATT_StartIf gatt_if=%d", gatt_if);
+ p_reg = gatt_get_regcb(gatt_if);
+ if (p_reg != NULL) {
+ start_idx = 0;
+ while (
+ gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
+ p_tcb = gatt_find_tcb_by_addr(bda, transport);
+ if (p_reg->app_cb.p_conn_cb && p_tcb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, 0, transport);
+ }
+ start_idx = ++found_idx;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_Connect
+ *
+ * Description This function initiate a connecttion to a remote device on
+ * GATT channel.
+ *
+ * Parameters gatt_if: applicaiton interface
+ * bd_addr: peer device address.
+ * is_direct: is a direct conenection or a background auto
+ * connection
+ *
+ * Returns true if connection started; false if connection start
+ * failure.
+ *
+ ******************************************************************************/
+bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
+ tBT_TRANSPORT transport, bool opportunistic) {
+ uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
+ return GATT_Connect(gatt_if, bd_addr, is_direct, transport, opportunistic,
+ phy);
+}
+
+bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
+ tBT_TRANSPORT transport, bool opportunistic,
+ uint8_t initiating_phys) {
+ tGATT_REG* p_reg;
+ bool status = false;
+
+ GATT_TRACE_API("GATT_Connect gatt_if=%d", gatt_if);
+
+ /* Make sure app is registered */
+ p_reg = gatt_get_regcb(gatt_if);
+ if (p_reg == NULL) {
+ GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
+ return (false);
+ }
+
+ if (is_direct)
+ status = gatt_act_connect(p_reg, bd_addr, transport, opportunistic,
+ initiating_phys);
+ else {
+ if (transport == BT_TRANSPORT_LE)
+ status = gatt_update_auto_connect_dev(gatt_if, true, bd_addr);
+ else {
+ GATT_TRACE_ERROR("Unsupported transport for background connection");
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_CancelConnect
+ *
+ * Description This function terminate the connection initaition to a
+ * remote device on GATT channel.
+ *
+ * Parameters gatt_if: client interface. If 0 used as unconditionally
+ * disconnect, typically used for direct connection
+ * cancellation.
+ * bd_addr: peer device address.
+ *
+ * Returns true if the connection started; false otherwise.
+ *
+ ******************************************************************************/
+bool GATT_CancelConnect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct) {
+ tGATT_REG* p_reg;
+ tGATT_TCB* p_tcb;
+ bool status = true;
+ tGATT_IF temp_gatt_if;
+ uint8_t start_idx, found_idx;
+
+ GATT_TRACE_API("GATT_CancelConnect gatt_if=%d", gatt_if);
+
+ if (gatt_if != 0) {
+ p_reg = gatt_get_regcb(gatt_if);
+ if (p_reg == NULL) {
+ GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered",
+ gatt_if);
+ return (false);
+ }
+ }
+
+ if (is_direct) {
+ if (!gatt_if) {
+ GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
+ start_idx = 0;
+ /* only LE connection can be cancelled */
+ p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_tcb && gatt_num_apps_hold_link(p_tcb)) {
+ while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx,
+ &temp_gatt_if)) {
+ status = gatt_cancel_open(temp_gatt_if, bd_addr);
+ start_idx = ++found_idx;
+ }
+ } else {
+ GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
+ status = false;
+ }
+ } else {
+ status = gatt_cancel_open(gatt_if, bd_addr);
+ }
+ } else {
+ if (!gatt_if) {
+ if (gatt_get_num_apps_for_bg_dev(bd_addr)) {
+ while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
+ gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
+ } else {
+ GATT_TRACE_ERROR(
+ "GATT_CancelConnect -no app associated with the bg device for "
+ "unconditional removal");
+ status = false;
+ }
+ } else {
+ status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_Disconnect
+ *
+ * Description This function disconnects the GATT channel for this
+ * registered application.
+ *
+ * Parameters conn_id: connection identifier.
+ *
+ * Returns GATT_SUCCESS if disconnected.
+ *
+ ******************************************************************************/
+tGATT_STATUS GATT_Disconnect(uint16_t conn_id) {
+ tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
+ tGATT_TCB* p_tcb = NULL;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+
+ GATT_TRACE_API("GATT_Disconnect conn_id=%d ", conn_id);
+
+ p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+
+ if (p_tcb) {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
+ ret = GATT_SUCCESS;
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_GetConnectionInfor
+ *
+ * Description This function uses conn_id to find its associated BD address
+ * and application interface
+ *
+ * Parameters conn_id: connection id (input)
+ * p_gatt_if: applicaiton interface (output)
+ * bd_addr: peer device address. (output)
+ *
+ * Returns true the ligical link information is found for conn_id
+ *
+ ******************************************************************************/
+bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if,
+ BD_ADDR bd_addr, tBT_TRANSPORT* p_transport) {
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ bool status = false;
+
+ GATT_TRACE_API("GATT_GetConnectionInfor conn_id=%d", conn_id);
+
+ if (p_tcb && p_reg) {
+ memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
+ *p_gatt_if = gatt_if;
+ *p_transport = p_tcb->transport;
+ status = true;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_GetConnIdIfConnected
+ *
+ * Description This function find the conn_id if the logical link for BD
+ * address and applciation interface is connected
+ *
+ * Parameters gatt_if: applicaiton interface (input)
+ * bd_addr: peer device address. (input)
+ * p_conn_id: connection id (output)
+ * transport: transport option
+ *
+ * Returns true the logical link is connected
+ *
+ ******************************************************************************/
+bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr,
+ uint16_t* p_conn_id, tBT_TRANSPORT transport) {
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ bool status = false;
+
+ if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)) {
+ *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ status = true;
+ }
+
+ GATT_TRACE_API("GATT_GetConnIdIfConnected status=%d", status);
+ return status;
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_attr.cc b/mtkbt/code/bt/stack/gatt/gatt_attr.cc
new file mode 100755
index 0000000..80ba426
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_attr.cc
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main GATT server attributes access request
+ * handling functions.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+
+#include "btcore/include/uuid.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/osi.h"
+
+/** M: Change feature, process CCCD of Service Changed Characteristic @{ */
+#include "mediatek/include/gatts_mtk.h"
+/** @} */
+
+#define GATTP_MAX_NUM_INC_SVR 0
+#define GATTP_MAX_CHAR_NUM 2
+#define GATTP_MAX_ATTR_NUM (GATTP_MAX_CHAR_NUM * 2 + GATTP_MAX_NUM_INC_SVR + 1)
+#define GATTP_MAX_CHAR_VALUE_SIZE 50
+
+#ifndef GATTP_ATTR_DB_SIZE
+#define GATTP_ATTR_DB_SIZE \
+ GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, \
+ GATTP_MAX_CHAR_VALUE_SIZE)
+#endif
+
+static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
+ uint8_t op_code, tGATTS_DATA* p_data);
+static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport);
+static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data);
+static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status);
+static void gatt_cl_op_cmpl_cback(UNUSED_ATTR uint16_t conn_id,
+ UNUSED_ATTR tGATTC_OPTYPE op,
+ UNUSED_ATTR tGATT_STATUS status,
+ UNUSED_ATTR tGATT_CL_COMPLETE* p_data);
+
+static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb);
+
+static tGATT_CBACK gatt_profile_cback = {gatt_connect_cback,
+ gatt_cl_op_cmpl_cback,
+ gatt_disc_res_cback,
+ gatt_disc_cmpl_cback,
+ gatt_request_cback,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_find_conn_id_by_bd_addr
+ *
+ * Description Find the connection ID by remote address
+ *
+ * Returns Connection ID
+ *
+ ******************************************************************************/
+uint16_t gatt_profile_find_conn_id_by_bd_addr(BD_ADDR remote_bda) {
+ uint16_t conn_id = GATT_INVALID_CONN_ID;
+ GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
+ BT_TRANSPORT_LE);
+ return conn_id;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_find_clcb_by_conn_id
+ *
+ * Description find clcb by Connection ID
+ *
+ * Returns Pointer to the found link conenction control block.
+ *
+ ******************************************************************************/
+static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_conn_id(uint16_t conn_id) {
+ uint8_t i_clcb;
+ tGATT_PROFILE_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->conn_id == conn_id) return p_clcb;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_find_clcb_by_bd_addr
+ *
+ * Description The function searches all LCBs with macthing bd address.
+ *
+ * Returns Pointer to the found link conenction control block.
+ *
+ ******************************************************************************/
+static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_bd_addr(
+ BD_ADDR bda, tBT_TRANSPORT transport) {
+ uint8_t i_clcb;
+ tGATT_PROFILE_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->transport == transport && p_clcb->connected &&
+ !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
+ return p_clcb;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_clcb_alloc
+ *
+ * Description The function allocates a GATT profile connection link
+ * control block
+ *
+ * Returns NULL if not found. Otherwise pointer to the connection link
+ * block.
+ *
+ ******************************************************************************/
+tGATT_PROFILE_CLCB* gatt_profile_clcb_alloc(uint16_t conn_id, BD_ADDR bda,
+ tBT_TRANSPORT tranport) {
+ uint8_t i_clcb = 0;
+ tGATT_PROFILE_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (!p_clcb->in_use) {
+ p_clcb->in_use = true;
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = true;
+ p_clcb->transport = tranport;
+ memcpy(p_clcb->bda, bda, BD_ADDR_LEN);
+ break;
+ }
+ }
+ if (i_clcb < GATT_MAX_APPS) return p_clcb;
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_clcb_dealloc
+ *
+ * Description The function deallocates a GATT profile connection link
+ * control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB* p_clcb) {
+ memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_request_cback
+ *
+ * Description GATT profile attribute access request callback.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
+ uint8_t status = GATT_INVALID_PDU;
+ tGATTS_RSP rsp_msg;
+ bool ignore = false;
+
+ memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+ switch (type) {
+ case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+ status = GATT_READ_NOT_PERMIT;
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+ status = GATT_WRITE_NOT_PERMIT;
+ /** M: Feature change, process write request of Client Characteristic
+ * Configuration Descriptor @{ */
+ {
+ tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+ if (p_clcb &&
+ GATT_SUCCESS ==
+ gatts_srv_chg_proc_write_req(p_clcb->bda, &p_data->write_req))
+ status = GATT_SUCCESS;
+ }
+ /** @} */
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_EXEC:
+ case GATT_CMD_WRITE:
+ ignore = true;
+ GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD");
+ break;
+
+ case GATTS_REQ_TYPE_MTU:
+ GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+ ignore = true;
+ break;
+
+ default:
+ GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ break;
+ }
+
+ if (!ignore) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_connect_cback
+ *
+ * Description Gatt profile connection callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport) {
+ GATT_TRACE_EVENT("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
+ __func__,
+ (bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],
+ (bda[4] << 8) + bda[5], connected, conn_id, reason);
+
+ tGATT_PROFILE_CLCB* p_clcb =
+ gatt_profile_find_clcb_by_bd_addr(bda, transport);
+
+ /** M: Feature change, allocate clcb for connected device @{ */
+ //if (p_clcb == NULL) return;
+ /** @} */
+
+ if (connected) {
+ /** M: Feature change, allocate clcb for connected device @{ */
+ if (p_clcb == NULL)
+ p_clcb = gatt_profile_clcb_alloc(conn_id, bda, transport);
+ if (p_clcb == NULL) return;
+ /** @} */
+
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = true;
+
+ if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING) {
+ p_clcb->ccc_stage++;
+ gatt_cl_start_config_ccc(p_clcb);
+ }
+ } else {
+ /** M: Feature change, allocate clcb for connected device @{ */
+ if (p_clcb != NULL)
+ /** @} */
+ gatt_profile_clcb_dealloc(p_clcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_profile_db_init
+ *
+ * Description Initializa the GATT profile attribute database.
+ *
+ ******************************************************************************/
+void gatt_profile_db_init(void) {
+ tBT_UUID app_uuid = {LEN_UUID_128, {0}};
+ uint16_t service_handle = 0;
+
+ /* Fill our internal UUID with a fixed pattern 0x81 */
+ memset(&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
+
+ /* Create a GATT profile service */
+ gatt_cb.gatt_if = GATT_Register(&app_uuid, &gatt_profile_cback);
+ GATT_StartIf(gatt_cb.gatt_if);
+
+ bt_uuid_t service_uuid;
+ uuid_128_from_16(&service_uuid, UUID_SERVCLASS_GATT_SERVER);
+
+ bt_uuid_t char_uuid;
+ uuid_128_from_16(&char_uuid, GATT_UUID_GATT_SRV_CHGD);
+
+ /** M: Feature change, add Client Characteristic Configuration Descriptor @{ */
+ bt_uuid_t dscp_uuid;
+ uuid_128_from_16(&dscp_uuid, GATT_UUID_CHAR_CLIENT_CONFIG);
+ /** @} */
+
+ btgatt_db_element_t service[] = {
+ {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = service_uuid},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = char_uuid,
+ .properties = GATT_CHAR_PROP_BIT_INDICATE,
+ .permissions = 0},
+ /** M: Feature change, add Client Characteristic Configuration
+ Descriptor @{ */
+ {.type = BTGATT_DB_DESCRIPTOR,
+ .uuid = dscp_uuid,
+ .properties = GATT_CHAR_PROP_BIT_INDICATE,
+ .permissions = GATT_PERM_READ | GATT_PERM_WRITE}};
+ /** @} */
+
+ GATTS_AddService(gatt_cb.gatt_if, service,
+ sizeof(service) / sizeof(btgatt_db_element_t));
+
+ service_handle = service[0].attribute_handle;
+ gatt_cb.handle_of_h_r = service[1].attribute_handle;
+ /** M: Feature change, add Client Characteristic Configuration Descriptor @{ */
+ gatts_srv_chg_set_cccd_handle(service[2].attribute_handle);
+ /** @} */
+
+ GATT_TRACE_ERROR("gatt_profile_db_init: gatt_if=%d", gatt_cb.gatt_if);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_disc_res_cback
+ *
+ * Description Gatt profile discovery result callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data) {
+ tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) return;
+
+ switch (disc_type) {
+ case GATT_DISC_SRVC_BY_UUID: /* stage 1 */
+ p_clcb->e_handle = p_data->value.group_value.e_handle;
+ p_clcb->ccc_result++;
+ break;
+
+ case GATT_DISC_CHAR: /* stage 2 */
+ p_clcb->s_handle = p_data->value.dclr_value.val_handle;
+ p_clcb->ccc_result++;
+ break;
+
+ case GATT_DISC_CHAR_DSCPT: /* stage 3 */
+ if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG) {
+ p_clcb->s_handle = p_data->handle;
+ p_clcb->ccc_result++;
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_disc_cmpl_cback
+ *
+ * Description Gatt profile discovery complete callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status) {
+ tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) return;
+
+ if (status == GATT_SUCCESS && p_clcb->ccc_result > 0) {
+ p_clcb->ccc_result = 0;
+ p_clcb->ccc_stage++;
+ gatt_cl_start_config_ccc(p_clcb);
+ } else {
+ GATT_TRACE_ERROR("%s() - Unable to register for service changed indication",
+ __func__);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_cl_op_cmpl_cback
+ *
+ * Description Gatt profile client operation complete callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_cl_op_cmpl_cback(UNUSED_ATTR uint16_t conn_id,
+ UNUSED_ATTR tGATTC_OPTYPE op,
+ UNUSED_ATTR tGATT_STATUS status,
+ UNUSED_ATTR tGATT_CL_COMPLETE* p_data) {}
+
+/*******************************************************************************
+ *
+ * Function gatt_cl_start_config_ccc
+ *
+ * Description Gatt profile start configure service change CCC
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) {
+ tGATT_DISC_PARAM srvc_disc_param;
+ tGATT_VALUE ccc_value;
+
+ GATT_TRACE_DEBUG("%s() - stage: %d", __func__, p_clcb->ccc_stage);
+
+ memset(&srvc_disc_param, 0, sizeof(tGATT_DISC_PARAM));
+ memset(&ccc_value, 0, sizeof(tGATT_VALUE));
+
+ switch (p_clcb->ccc_stage) {
+ case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
+ srvc_disc_param.s_handle = 1;
+ srvc_disc_param.e_handle = 0xffff;
+ srvc_disc_param.service.len = 2;
+ srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param);
+ break;
+
+ case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
+ srvc_disc_param.s_handle = 1;
+ srvc_disc_param.e_handle = p_clcb->e_handle;
+ srvc_disc_param.service.len = 2;
+ srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param);
+ break;
+
+ case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
+ srvc_disc_param.s_handle = p_clcb->s_handle;
+ srvc_disc_param.e_handle = p_clcb->e_handle;
+ GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param);
+ break;
+
+ case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
+ ccc_value.handle = p_clcb->s_handle;
+ ccc_value.len = 2;
+ ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
+ GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function GATT_ConfigServiceChangeCCC
+ *
+ * Description Configure service change indication on remote device
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void GATT_ConfigServiceChangeCCC(BD_ADDR remote_bda, bool enable,
+ tBT_TRANSPORT transport) {
+ tGATT_PROFILE_CLCB* p_clcb =
+ gatt_profile_find_clcb_by_bd_addr(remote_bda, transport);
+
+ if (p_clcb == NULL)
+ p_clcb = gatt_profile_clcb_alloc(0, remote_bda, transport);
+
+ if (p_clcb == NULL) return;
+
+ if (GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id,
+ transport)) {
+ p_clcb->connected = true;
+ }
+ /* hold the link here */
+ GATT_Connect(gatt_cb.gatt_if, remote_bda, true, transport, true);
+ p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;
+
+ if (!p_clcb->connected) {
+ /* wait for connection */
+ return;
+ }
+
+ p_clcb->ccc_stage++;
+ gatt_cl_start_config_ccc(p_clcb);
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_auth.cc b/mtkbt/code/bt/stack/gatt/gatt_auth.cc
new file mode 100755
index 0000000..82b03a6
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_auth.cc
@@ -0,0 +1,475 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains GATT authentication handling functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#include "bt_utils.h"
+
+#include <string.h>
+#include "bt_common.h"
+
+#include "btm_int.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *
+ * Function gatt_sign_data
+ *
+ * Description This function sign the data for write command.
+ *
+ * Returns true if encrypted, otherwise false.
+ *
+ ******************************************************************************/
+static bool gatt_sign_data(tGATT_CLCB* p_clcb) {
+ tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
+ uint8_t *p_data = NULL, *p;
+ uint16_t payload_size = p_clcb->p_tcb->payload_size;
+ bool status = false;
+ uint8_t* p_signature;
+
+ /* do not need to mark channel securoty activity for data signing */
+ gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK);
+
+ p_data =
+ (uint8_t*)osi_malloc(p_attr->len + 3); /* 3 = 2 byte handle + opcode */
+
+ p = p_data;
+ UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
+ UINT16_TO_STREAM(p, p_attr->handle);
+ ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
+
+ /* sign data length should be attribulte value length plus 2B handle + 1B op
+ * code */
+ if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len)
+ p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
+
+ p_signature = p_attr->value + p_attr->len;
+ if (BTM_BleDataSignature(
+ p_clcb->p_tcb->peer_bda, p_data,
+ (uint16_t)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
+ p_signature)) {
+ p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
+ gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
+ gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA);
+ } else {
+ gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
+ }
+
+ osi_free(p_data);
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_verify_signature
+ *
+ * Description This function start to verify the sign data when receiving
+ * the data from peer device.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+ uint16_t cmd_len;
+ uint8_t op_code;
+ uint8_t *p, *p_orig = (uint8_t *)(p_buf + 1) + p_buf->offset;
+ uint32_t counter;
+
+ if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
+ GATT_TRACE_ERROR("%s: Data length %u less than expected %u", __func__,
+ p_buf->len, GATT_AUTH_SIGN_LEN + 4);
+ return;
+ }
+ cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
+ p = p_orig + cmd_len - 4;
+ STREAM_TO_UINT32(counter, p);
+
+ if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) {
+ STREAM_TO_UINT8(op_code, p_orig);
+ gatt_server_handle_client_req(p_tcb, op_code, (uint16_t)(p_buf->len - 1),
+ p_orig);
+ } else {
+ /* if this is a bad signature, assume from attacker, ignore it */
+ GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
+ }
+
+ return;
+}
+/*******************************************************************************
+ *
+ * Function gatt_sec_check_complete
+ *
+ * Description security check complete and proceed to data sending action.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_sec_check_complete(bool sec_check_ok, tGATT_CLCB* p_clcb,
+ uint8_t sec_act) {
+ if (p_clcb && p_clcb->p_tcb &&
+ fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
+ gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
+ }
+
+ if (!sec_check_ok) {
+ gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
+ } else if (p_clcb->operation == GATTC_OPTYPE_WRITE) {
+ gatt_act_write(p_clcb, sec_act);
+ } else if (p_clcb->operation == GATTC_OPTYPE_READ) {
+ gatt_act_read(p_clcb, p_clcb->counter);
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_enc_cmpl_cback
+ *
+ * Description link encryption complete callback.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ UNUSED_ATTR void* p_ref_data, tBTM_STATUS result) {
+ tGATT_TCB* p_tcb;
+ uint8_t sec_flag;
+ bool status = false;
+
+ GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
+ p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ if (p_tcb != NULL) {
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) return;
+
+ tGATT_PENDING_ENC_CLCB* p_buf =
+ (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
+ p_tcb->pending_enc_clcb);
+ if (p_buf != NULL) {
+ if (result == BTM_SUCCESS) {
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM) {
+ BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
+
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
+ status = true;
+ }
+ } else {
+ status = true;
+ }
+ }
+ gatt_sec_check_complete(status, p_buf->p_clcb, p_tcb->sec_act);
+ osi_free(p_buf);
+ /* start all other pending operation in queue */
+ for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
+ count > 0; count--) {
+ p_buf = (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
+ p_tcb->pending_enc_clcb);
+ if (p_buf != NULL) {
+ gatt_security_check_start(p_buf->p_clcb);
+ osi_free(p_buf);
+ } else
+ break;
+ }
+ } else {
+ GATT_TRACE_ERROR("Unknown operation encryption completed");
+ }
+ } else {
+ GATT_TRACE_ERROR("enc callback for unknown bd_addr");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_notify_enc_cmpl
+ *
+ * Description link encryption complete notification for all encryption
+ * process initiated outside GATT.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+void gatt_notify_enc_cmpl(BD_ADDR bd_addr) {
+ tGATT_TCB* p_tcb;
+ uint8_t i = 0;
+
+ p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_tcb != NULL) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
+ (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if,
+ bd_addr);
+ }
+ }
+
+ if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
+ gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+
+ size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
+ for (; count > 0; count--) {
+ tGATT_PENDING_ENC_CLCB* p_buf =
+ (tGATT_PENDING_ENC_CLCB*)fixed_queue_try_dequeue(
+ p_tcb->pending_enc_clcb);
+ if (p_buf != NULL) {
+ gatt_security_check_start(p_buf->p_clcb);
+ osi_free(p_buf);
+ } else
+ break;
+ }
+ }
+ } else {
+ GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
+ }
+ return;
+}
+/*******************************************************************************
+ *
+ * Function gatt_set_sec_act
+ *
+ * Description This function set the sec_act in clcb
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void gatt_set_sec_act(tGATT_TCB* p_tcb, tGATT_SEC_ACTION sec_act) {
+ if (p_tcb) {
+ p_tcb->sec_act = sec_act;
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_get_sec_act
+ *
+ * Description This function get the sec_act in clcb
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb) {
+ tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
+ if (p_tcb) {
+ sec_act = p_tcb->sec_act;
+ }
+ return sec_act;
+}
+/*******************************************************************************
+ *
+ * Function gatt_determine_sec_act
+ *
+ * Description This routine determine the security action based on
+ * auth_request and current link status
+ *
+ * Returns tGATT_SEC_ACTION security action
+ *
+ ******************************************************************************/
+tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb) {
+ tGATT_SEC_ACTION act = GATT_SEC_OK;
+ uint8_t sec_flag;
+ tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ tGATT_AUTH_REQ auth_req = p_clcb->auth_req;
+ bool is_link_encrypted = false;
+ bool is_link_key_known = false;
+ bool is_key_mitm = false;
+ uint8_t key_type;
+ tBTM_BLE_SEC_REQ_ACT sec_act = BTM_LE_SEC_NONE;
+
+ if (auth_req == GATT_AUTH_REQ_NONE) return act;
+
+ BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag,
+ p_clcb->p_tcb->transport);
+
+ btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act);
+
+ /* if a encryption is pending, need to wait */
+ if (sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD && auth_req != GATT_AUTH_REQ_NONE)
+ return GATT_SEC_ENC_PENDING;
+
+ if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED | BTM_SEC_FLAG_LKEY_KNOWN)) {
+ if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) is_link_encrypted = true;
+
+ is_link_key_known = true;
+
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) is_key_mitm = true;
+ }
+
+ /* first check link key upgrade required or not */
+ switch (auth_req) {
+ case GATT_AUTH_REQ_MITM:
+ case GATT_AUTH_REQ_SIGNED_MITM:
+ if (!is_key_mitm) act = GATT_SEC_ENCRYPT_MITM;
+ break;
+
+ case GATT_AUTH_REQ_NO_MITM:
+ case GATT_AUTH_REQ_SIGNED_NO_MITM:
+ if (!is_link_key_known) act = GATT_SEC_ENCRYPT_NO_MITM;
+ break;
+ default:
+ break;
+ }
+
+ /* now check link needs to be encrypted or not if the link key upgrade is not
+ * required */
+ if (act == GATT_SEC_OK) {
+ if (p_tcb->transport == BT_TRANSPORT_LE &&
+ (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+ (p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
+ /* this is a write command request
+ check data signing required or not */
+ if (!is_link_encrypted) {
+ btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
+
+ if ((key_type & BTM_LE_KEY_LCSRK) &&
+ ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
+ (auth_req == GATT_AUTH_REQ_SIGNED_MITM))) {
+ act = GATT_SEC_SIGN_DATA;
+ } else {
+ act = GATT_SEC_ENCRYPT;
+ }
+ }
+ } else {
+ if (!is_link_encrypted) {
+ act = GATT_SEC_ENCRYPT;
+ }
+ }
+ }
+
+ return act;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_get_link_encrypt_status
+ *
+ * Description This routine get the encryption status of the specified link
+ *
+ *
+ * Returns tGATT_STATUS link encryption status
+ *
+ ******************************************************************************/
+tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB* p_tcb) {
+ tGATT_STATUS encrypt_status = GATT_NOT_ENCRYPTED;
+ uint8_t sec_flag = 0;
+
+ BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
+
+ if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) &&
+ (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) {
+ encrypt_status = GATT_ENCRYPED_NO_MITM;
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+ encrypt_status = GATT_ENCRYPED_MITM;
+ }
+
+ GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x", encrypt_status);
+ return encrypt_status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_convert_sec_action
+ *
+ * Description Convert GATT security action enum into equivalent
+ * BTM BLE security action enum
+ *
+ * Returns bool true - conversation is successful
+ *
+ ******************************************************************************/
+static bool gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act,
+ tBTM_BLE_SEC_ACT* p_btm_sec_act) {
+ bool status = true;
+ switch (gatt_sec_act) {
+ case GATT_SEC_ENCRYPT:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
+ break;
+ case GATT_SEC_ENCRYPT_NO_MITM:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
+ break;
+ case GATT_SEC_ENCRYPT_MITM:
+ *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
+ break;
+ default:
+ status = false;
+ break;
+ }
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function gatt_check_enc_req
+ *
+ * Description check link security.
+ *
+ * Returns true if encrypted, otherwise false.
+ *
+ ******************************************************************************/
+bool gatt_security_check_start(tGATT_CLCB* p_clcb) {
+ tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ tGATT_SEC_ACTION gatt_sec_act;
+ tBTM_BLE_SEC_ACT btm_ble_sec_act;
+ bool status = true;
+ tBTM_STATUS btm_status;
+ tGATT_SEC_ACTION sec_act_old = gatt_get_sec_act(p_tcb);
+
+ gatt_sec_act = gatt_determine_sec_act(p_clcb);
+
+ if (sec_act_old == GATT_SEC_NONE) gatt_set_sec_act(p_tcb, gatt_sec_act);
+
+ switch (gatt_sec_act) {
+ case GATT_SEC_SIGN_DATA:
+ GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
+ gatt_sign_data(p_clcb);
+ break;
+ case GATT_SEC_ENCRYPT:
+ case GATT_SEC_ENCRYPT_NO_MITM:
+ case GATT_SEC_ENCRYPT_MITM:
+ if (sec_act_old < GATT_SEC_ENCRYPT) {
+ GATT_TRACE_DEBUG(
+ "gatt_security_check_start: Encrypt now or key upgreade first");
+ gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
+ btm_status =
+ BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport,
+ gatt_enc_cmpl_cback, NULL, btm_ble_sec_act);
+ if ((btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) {
+ GATT_TRACE_ERROR(
+ "gatt_security_check_start BTM_SetEncryption failed "
+ "btm_status=%d",
+ btm_status);
+ status = false;
+ }
+ }
+ if (status) gatt_add_pending_enc_channel_clcb(p_tcb, p_clcb);
+ break;
+ case GATT_SEC_ENC_PENDING:
+ gatt_add_pending_enc_channel_clcb(p_tcb, p_clcb);
+ /* wait for link encrypotion to finish */
+ break;
+ default:
+ gatt_sec_check_complete(true, p_clcb, gatt_sec_act);
+ break;
+ }
+
+ if (status == false) {
+ gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ }
+
+ return status;
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_cl.cc b/mtkbt/code/bt/stack/gatt/gatt_cl.cc
new file mode 100755
index 0000000..a714c4a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_cl.cc
@@ -0,0 +1,1150 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main GATT client functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "gatt_int.h"
+#include "l2c_int.h"
+#include "osi/include/osi.h"
+
+#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
+#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
+#define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90)
+
+#define GATT_PREP_WRITE_RSP_MIN_LEN 4
+#define GATT_NOTIFICATION_MIN_LEN 2
+#define GATT_WRITE_RSP_MIN_LEN 2
+#define GATT_INFO_RSP_MIN_LEN 1
+#define GATT_MTU_RSP_MIN_LEN 2
+#define GATT_READ_BY_TYPE_RSP_MIN_LEN 1
+
+/*******************************************************************************
+ * G L O B A L G A T T D A T A *
+ ******************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb);
+
+uint8_t disc_type_to_att_opcode[GATT_DISC_MAX] = {
+ 0,
+ GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */
+ GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */
+ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */
+ GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */
+ GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */
+};
+
+uint16_t disc_type_to_uuid[GATT_DISC_MAX] = {
+ 0, /* reserved */
+ GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
+ GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
+ GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
+ GATT_UUID_CHAR_DECLARE, /* <characteristic> for DISC_CHAR */
+ 0 /* no type filtering for DISC_CHAR_DSCPT */
+};
+
+/*******************************************************************************
+ *
+ * Function gatt_act_discovery
+ *
+ * Description GATT discovery operation.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_act_discovery(tGATT_CLCB* p_clcb) {
+ uint8_t op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
+ tGATT_CL_MSG cl_req;
+ tGATT_STATUS st;
+
+ if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) {
+ memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
+
+ cl_req.browse.s_handle = p_clcb->s_handle;
+ cl_req.browse.e_handle = p_clcb->e_handle;
+
+ if (disc_type_to_uuid[p_clcb->op_subtype] != 0) {
+ cl_req.browse.uuid.len = 2;
+ cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+ }
+
+ if (p_clcb->op_subtype ==
+ GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
+ {
+ cl_req.find_type_value.uuid.len = 2;
+ cl_req.find_type_value.uuid.uu.uuid16 =
+ disc_type_to_uuid[p_clcb->op_subtype];
+ cl_req.find_type_value.s_handle = p_clcb->s_handle;
+ cl_req.find_type_value.e_handle = p_clcb->e_handle;
+ cl_req.find_type_value.value_len = p_clcb->uuid.len;
+ /* if service type is 32 bits UUID, convert it now */
+ if (p_clcb->uuid.len == LEN_UUID_32) {
+ cl_req.find_type_value.value_len = LEN_UUID_128;
+ gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value,
+ p_clcb->uuid.uu.uuid32);
+ } else
+ memcpy(cl_req.find_type_value.value, &p_clcb->uuid.uu,
+ p_clcb->uuid.len);
+ }
+
+ st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
+
+ if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) {
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ }
+ } else /* end of handle range */
+ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_act_read
+ *
+ * Description GATT read operation.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset) {
+ tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ uint8_t rt = GATT_INTERNAL_ERROR;
+ tGATT_CL_MSG msg;
+ uint8_t op_code = 0;
+
+ memset(&msg, 0, sizeof(tGATT_CL_MSG));
+
+ switch (p_clcb->op_subtype) {
+ case GATT_READ_CHAR_VALUE:
+ case GATT_READ_BY_TYPE:
+ op_code = GATT_REQ_READ_BY_TYPE;
+ msg.browse.s_handle = p_clcb->s_handle;
+ msg.browse.e_handle = p_clcb->e_handle;
+ if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
+ memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
+ else {
+ msg.browse.uuid.len = LEN_UUID_16;
+ msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
+ }
+ break;
+
+ case GATT_READ_CHAR_VALUE_HDL:
+ case GATT_READ_BY_HANDLE:
+ if (!p_clcb->counter) {
+ op_code = GATT_REQ_READ;
+ msg.handle = p_clcb->s_handle;
+ } else {
+ if (!p_clcb->first_read_blob_after_read)
+ p_clcb->first_read_blob_after_read = true;
+ else
+ p_clcb->first_read_blob_after_read = false;
+
+ GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d",
+ p_clcb->first_read_blob_after_read);
+ op_code = GATT_REQ_READ_BLOB;
+ msg.read_blob.offset = offset;
+ msg.read_blob.handle = p_clcb->s_handle;
+ }
+ p_clcb->op_subtype &= ~0x80;
+ break;
+
+ case GATT_READ_PARTIAL:
+ op_code = GATT_REQ_READ_BLOB;
+ msg.read_blob.handle = p_clcb->s_handle;
+ msg.read_blob.offset = offset;
+ break;
+
+ case GATT_READ_MULTIPLE:
+ op_code = GATT_REQ_READ_MULTI;
+ memcpy(&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
+ break;
+
+ case GATT_READ_INC_SRV_UUID128:
+ op_code = GATT_REQ_READ;
+ msg.handle = p_clcb->s_handle;
+ p_clcb->op_subtype &= ~0x90;
+ break;
+
+ default:
+ GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype);
+ break;
+ }
+
+ if (op_code != 0)
+ rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
+
+ if (op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)) {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_act_write
+ *
+ * Description GATT write operation.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act) {
+ tGATT_TCB* p_tcb = p_clcb->p_tcb;
+ uint8_t rt = GATT_SUCCESS, op_code = 0;
+ tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
+
+ if (p_attr) {
+ switch (p_clcb->op_subtype) {
+ case GATT_WRITE_NO_RSP:
+ p_clcb->s_handle = p_attr->handle;
+ op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE
+ : GATT_CMD_WRITE;
+ rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, op_code,
+ p_attr->handle, p_attr->len, 0, p_attr->value);
+ break;
+
+ case GATT_WRITE:
+ if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE)) {
+ p_clcb->s_handle = p_attr->handle;
+
+ rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_WRITE,
+ p_attr->handle, p_attr->len, 0,
+ p_attr->value);
+ } else /* prepare write for long attribute */
+ {
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ }
+ break;
+
+ case GATT_WRITE_PREPARE:
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ break;
+
+ default:
+ rt = GATT_INTERNAL_ERROR;
+ GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
+ break;
+ }
+ } else
+ rt = GATT_INTERNAL_ERROR;
+
+ if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED) ||
+ (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
+ if (rt != GATT_SUCCESS) {
+ GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code,
+ rt);
+ }
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_send_queue_write_cancel
+ *
+ * Description send queue write cancel
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ tGATT_EXEC_FLAG flag) {
+ uint8_t rt;
+
+ GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
+
+ rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE,
+ (tGATT_CL_MSG*)&flag);
+
+ if (rt != GATT_SUCCESS) {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_check_write_long_terminate
+ *
+ * Description To terminate write long or not.
+ *
+ * Returns true: write long is terminated; false keep sending.
+ *
+ ******************************************************************************/
+bool gatt_check_write_long_terminate(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ tGATT_VALUE* p_rsp_value) {
+ tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
+ bool exec = false;
+ tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
+
+ GATT_TRACE_DEBUG("gatt_check_write_long_terminate ");
+ /* check the first write response status */
+ if (p_rsp_value != NULL) {
+ if (p_rsp_value->handle != p_attr->handle ||
+ p_rsp_value->len != p_clcb->counter ||
+ memcmp(p_rsp_value->value, p_attr->value + p_attr->offset,
+ p_rsp_value->len)) {
+ /* data does not match */
+ p_clcb->status = GATT_ERROR;
+ flag = GATT_PREP_WRITE_CANCEL;
+ exec = true;
+ } else /* response checking is good */
+ {
+ p_clcb->status = GATT_SUCCESS;
+ /* update write offset and check if end of attribute value */
+ if ((p_attr->offset += p_rsp_value->len) >= p_attr->len) exec = true;
+ }
+ }
+ if (exec) {
+ gatt_send_queue_write_cancel(p_tcb, p_clcb, flag);
+ return true;
+ }
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function gatt_send_prepare_write
+ *
+ * Description Send prepare write.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_send_prepare_write(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb) {
+ tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
+ uint16_t to_send, offset;
+ uint8_t rt = GATT_SUCCESS;
+ uint8_t type = p_clcb->op_subtype;
+
+ GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type);
+ to_send = p_attr->len - p_attr->offset;
+
+ if (to_send > (p_tcb->payload_size -
+ GATT_WRITE_LONG_HDR_SIZE)) /* 2 = uint16_t offset bytes */
+ to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
+
+ p_clcb->s_handle = p_attr->handle;
+
+ offset = p_attr->offset;
+ if (type == GATT_WRITE_PREPARE) {
+ offset += p_clcb->start_offset;
+ }
+
+ GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send);
+
+ rt = gatt_send_write_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_PREPARE_WRITE,
+ p_attr->handle, to_send, /* length */
+ offset, /* used as offset */
+ p_attr->value + p_attr->offset); /* data */
+
+ /* remember the write long attribute length */
+ p_clcb->counter = to_send;
+
+ if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED) {
+ gatt_end_operation(p_clcb, rt, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_find_type_value_rsp
+ *
+ * Description This function handles the find by type value response.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_find_type_value_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
+ tGATT_CLCB* p_clcb, uint16_t len,
+ uint8_t* p_data) {
+ tGATT_DISC_RES result;
+ uint8_t* p = p_data;
+
+ GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
+ /* unexpected response */
+ if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY ||
+ p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
+ return;
+
+ memset(&result, 0, sizeof(tGATT_DISC_RES));
+ result.type.len = 2;
+ result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
+
+ /* returns a series of handle ranges */
+ while (len >= 4) {
+ STREAM_TO_UINT16(result.handle, p);
+ STREAM_TO_UINT16(result.value.group_value.e_handle, p);
+ memcpy(&result.value.group_value.service_type, &p_clcb->uuid,
+ sizeof(tBT_UUID));
+
+ len -= 4;
+
+ if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
+ p_clcb->op_subtype, &result);
+ }
+
+ /* last handle + 1 */
+ p_clcb->s_handle = (result.value.group_value.e_handle == 0)
+ ? 0
+ : (result.value.group_value.e_handle + 1);
+ /* initiate another request */
+ gatt_act_discovery(p_clcb);
+}
+/*******************************************************************************
+ *
+ * Function gatt_process_read_info_rsp
+ *
+ * Description This function is called to handle the read information
+ * response.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_read_info_rsp(UNUSED_ATTR tGATT_TCB* p_tcb,
+ tGATT_CLCB* p_clcb, UNUSED_ATTR uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ tGATT_DISC_RES result;
+ uint8_t *p = p_data, uuid_len = 0, type;
+
+ if (len < GATT_INFO_RSP_MIN_LEN) {
+ GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
+ return;
+ }
+ /* unexpected response */
+ if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY ||
+ p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
+ return;
+
+ STREAM_TO_UINT8(type, p);
+ len -= 1;
+
+ if (type == GATT_INFO_TYPE_PAIR_16)
+ uuid_len = LEN_UUID_16;
+ else if (type == GATT_INFO_TYPE_PAIR_128)
+ uuid_len = LEN_UUID_128;
+
+ while (len >= uuid_len + 2) {
+ STREAM_TO_UINT16(result.handle, p);
+
+ if (uuid_len > 0) {
+ if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p)) break;
+ } else
+ memcpy(&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
+
+ len -= (uuid_len + 2);
+
+ if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
+ p_clcb->op_subtype, &result);
+ }
+
+ p_clcb->s_handle = (result.handle == 0) ? 0 : (result.handle + 1);
+ /* initiate another request */
+ gatt_act_discovery(p_clcb);
+}
+/*******************************************************************************
+ *
+ * Function gatt_proc_disc_error_rsp
+ *
+ * Description Process the read by type response and send another request
+ * if needed.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_proc_disc_error_rsp(UNUSED_ATTR tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ uint8_t opcode, UNUSED_ATTR uint16_t handle,
+ uint8_t reason) {
+ tGATT_STATUS status = (tGATT_STATUS)reason;
+
+ GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x",
+ reason, opcode);
+
+ switch (opcode) {
+ case GATT_REQ_READ_BY_GRP_TYPE:
+ case GATT_REQ_FIND_TYPE_VALUE:
+ case GATT_REQ_READ_BY_TYPE:
+ case GATT_REQ_FIND_INFO:
+ if (reason == GATT_NOT_FOUND) {
+ status = GATT_SUCCESS;
+ GATT_TRACE_DEBUG("Discovery completed");
+ }
+ break;
+ default:
+ GATT_TRACE_ERROR("Incorrect discovery opcode %04x", opcode);
+ break;
+ }
+
+ gatt_end_operation(p_clcb, status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_error_rsp
+ *
+ * Description This function is called to handle the error response
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_error_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ UNUSED_ATTR uint8_t op_code,
+ UNUSED_ATTR uint16_t len, uint8_t* p_data) {
+ uint8_t opcode, reason, *p = p_data;
+ uint16_t handle;
+ tGATT_VALUE* p_attr = (tGATT_VALUE*)p_clcb->p_attr_buf;
+
+ GATT_TRACE_DEBUG("gatt_process_error_rsp ");
+ STREAM_TO_UINT8(opcode, p);
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT8(reason, p);
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
+ gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
+ } else {
+ if ((p_clcb->operation == GATTC_OPTYPE_WRITE) &&
+ (p_clcb->op_subtype == GATT_WRITE) &&
+ (opcode == GATT_REQ_PREPARE_WRITE) && (p_attr) &&
+ (handle == p_attr->handle)) {
+ p_clcb->status = reason;
+ gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
+ } else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
+ ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
+ (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
+ (opcode == GATT_REQ_READ_BLOB) &&
+ p_clcb->first_read_blob_after_read &&
+ (reason == GATT_NOT_LONG)) {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p_clcb->p_attr_buf);
+ } else
+ gatt_end_operation(p_clcb, reason, NULL);
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_process_prep_write_rsp
+ *
+ * Description This function is called to handle the read response
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_prep_write_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
+ uint8_t* p = p_data;
+
+ tGATT_VALUE value = {
+ .conn_id = p_clcb->conn_id, .auth_req = GATT_AUTH_REQ_NONE,
+ };
+
+ GATT_TRACE_ERROR("value resp op_code = %s len = %d",
+ gatt_dbg_op_name(op_code), len);
+
+ if (len < GATT_PREP_WRITE_RSP_MIN_LEN) {
+ GATT_TRACE_ERROR("illegal prepare write response length, discard");
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
+ return;
+ }
+
+ STREAM_TO_UINT16(value.handle, p);
+ STREAM_TO_UINT16(value.offset, p);
+
+ value.len = len - 4;
+
+ memcpy(value.value, p, value.len);
+
+ if (p_clcb->op_subtype == GATT_WRITE_PREPARE) {
+ p_clcb->status = GATT_SUCCESS;
+ /* application should verify handle offset
+ and value are matched or not */
+
+ gatt_end_operation(p_clcb, p_clcb->status, &value);
+ } else if (p_clcb->op_subtype == GATT_WRITE) {
+ if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
+ gatt_send_prepare_write(p_tcb, p_clcb);
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_process_notification
+ *
+ * Description Handle the handle value indication/notification.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_notification(tGATT_TCB* p_tcb, uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
+ tGATT_VALUE value;
+ tGATT_REG* p_reg;
+ uint16_t conn_id;
+ tGATT_STATUS encrypt_status;
+ uint8_t *p = p_data, i, event = (op_code == GATT_HANDLE_VALUE_NOTIF)
+ ? GATTC_OPTYPE_NOTIFICATION
+ : GATTC_OPTYPE_INDICATION;
+
+ GATT_TRACE_DEBUG("gatt_process_notification ");
+
+ if (len < GATT_NOTIFICATION_MIN_LEN) {
+ GATT_TRACE_ERROR("illegal notification PDU length, discard");
+ return;
+ }
+
+ memset(&value, 0, sizeof(value));
+ STREAM_TO_UINT16(value.handle, p);
+ value.len = len - 2;
+ memcpy(value.value, p, value.len);
+
+ if (!GATT_HANDLE_IS_VALID(value.handle)) {
+ /* illegal handle, send ack now */
+ if (op_code == GATT_HANDLE_VALUE_IND)
+ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ return;
+ }
+
+ if (event == GATTC_OPTYPE_INDICATION) {
+ if (p_tcb->ind_count) {
+ /* this is an error case that receiving an indication but we
+ still has an indication not being acked yet.
+ For now, just log the error reset the counter.
+ Later we need to disconnect the link unconditionally.
+ */
+ GATT_TRACE_ERROR(
+ "gatt_process_notification rcv Ind. but ind_count=%d (will reset "
+ "ind_count)",
+ p_tcb->ind_count);
+ }
+ p_tcb->ind_count = 0;
+ }
+
+ /* should notify all registered client with the handle value
+ notificaion/indication
+ Note: need to do the indication count and start timer first then do
+ callback
+ */
+
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb &&
+ (event == GATTC_OPTYPE_INDICATION))
+ p_tcb->ind_count++;
+ }
+
+ if (event == GATTC_OPTYPE_INDICATION) {
+ /* start a timer for app confirmation */
+ if (p_tcb->ind_count > 0)
+ gatt_start_ind_ack_timer(p_tcb);
+ else /* no app to indicate, or invalid handle */
+ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+ }
+
+ encrypt_status = gatt_get_link_encrypt_status(p_tcb);
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_cmpl_cb)(conn_id, event, encrypt_status,
+ (tGATT_CL_COMPLETE*)&value);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_read_by_type_rsp
+ *
+ * Description This function is called to handle the read by type response.
+ * read by type can be used for discovery, or read by type or
+ * read characteristic value.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_read_by_type_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
+ tGATT_DISC_RES result;
+ tGATT_DISC_VALUE record_value;
+ uint8_t *p = p_data, value_len, handle_len = 2;
+ uint16_t handle = 0;
+
+ /* discovery procedure and no callback function registered */
+ if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) &&
+ (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
+ return;
+
+ if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN) {
+ GATT_TRACE_ERROR(
+ "Illegal ReadByType/ReadByGroupType Response length, discard");
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
+ return;
+ }
+
+ STREAM_TO_UINT8(value_len, p);
+
+ if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len - 1))) {
+ /* this is an error case that server's response containing a value length
+ which is larger than MTU-2
+ or value_len > message total length -1 */
+ GATT_TRACE_ERROR(
+ "gatt_process_read_by_type_rsp: Discard response op_code=%d "
+ "vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
+ op_code, value_len, (p_tcb->payload_size - 2), (len - 1));
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ return;
+ }
+
+ if (op_code == GATT_RSP_READ_BY_GRP_TYPE) handle_len = 4;
+
+ value_len -= handle_len; /* substract the handle pairs bytes */
+ len -= 1;
+
+ while (len >= (handle_len + value_len)) {
+ STREAM_TO_UINT16(handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(handle)) {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+
+ memset(&result, 0, sizeof(tGATT_DISC_RES));
+ memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
+
+ result.handle = handle;
+ result.type.len = 2;
+ result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
+
+ /* discover all services */
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+ op_code == GATT_RSP_READ_BY_GRP_TYPE) {
+ STREAM_TO_UINT16(handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(handle)) {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ } else {
+ record_value.group_value.e_handle = handle;
+ if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type,
+ value_len, &p)) {
+ GATT_TRACE_ERROR("discover all service response parsing failure");
+ break;
+ }
+ }
+ }
+ /* discover included service */
+ else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_INC_SRVC) {
+ STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
+ STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
+
+ if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
+ !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle)) {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+
+ if (value_len == 6) {
+ STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
+ record_value.incl_service.service_type.len = LEN_UUID_16;
+ } else if (value_len == 4) {
+ p_clcb->s_handle = record_value.incl_service.s_handle;
+ p_clcb->read_uuid128.wait_for_read_rsp = true;
+ p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
+ memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
+ memcpy(&p_clcb->read_uuid128.result.value, &record_value,
+ sizeof(result.value));
+ p_clcb->op_subtype |= 0x90;
+ gatt_act_read(p_clcb, 0);
+ return;
+ } else {
+ GATT_TRACE_ERROR(
+ "gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data "
+ "value_len=%d",
+ value_len);
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void*)p);
+ return;
+ }
+ }
+ /* read by type */
+ else if (p_clcb->operation == GATTC_OPTYPE_READ &&
+ p_clcb->op_subtype == GATT_READ_BY_TYPE) {
+ p_clcb->counter = len - 2;
+ p_clcb->s_handle = handle;
+ if (p_clcb->counter == (p_clcb->p_tcb->payload_size - 4)) {
+ p_clcb->op_subtype = GATT_READ_BY_HANDLE;
+ if (!p_clcb->p_attr_buf)
+ p_clcb->p_attr_buf = (uint8_t*)osi_malloc(GATT_MAX_ATTR_LEN);
+ if (p_clcb->counter <= GATT_MAX_ATTR_LEN) {
+ memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
+ gatt_act_read(p_clcb, p_clcb->counter);
+ } else {
+ gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void*)p);
+ }
+ } else {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p);
+ }
+ return;
+ } else /* discover characterisitic */
+ {
+ STREAM_TO_UINT8(record_value.dclr_value.char_prop, p);
+ STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
+ if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) {
+ gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
+ return;
+ }
+ if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid,
+ (uint16_t)(value_len - 3), &p)) {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+ /* invalid format, and skip the result */
+ return;
+ }
+
+ /* UUID not matching */
+ if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid)) {
+ len -= (value_len + 2);
+ continue; /* skip the result, and look for next one */
+ } else if (p_clcb->operation == GATTC_OPTYPE_READ)
+ /* UUID match for read characteristic value */
+ {
+ /* only read the first matching UUID characteristic value, and
+ discard the rest results */
+ p_clcb->s_handle = record_value.dclr_value.val_handle;
+ p_clcb->op_subtype |= 0x80;
+ gatt_act_read(p_clcb, 0);
+ return;
+ }
+ }
+ len -= (value_len + handle_len);
+
+ /* result is (handle, 16bits UUID) pairs */
+ memcpy(&result.value, &record_value, sizeof(result.value));
+
+ /* send callback if is discover procedure */
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
+ p_clcb->op_subtype, &result);
+ }
+
+ p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
+ /* initiate another request */
+ gatt_act_discovery(p_clcb);
+ } else /* read characteristic value */
+ {
+ gatt_act_read(p_clcb, 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_read_rsp
+ *
+ * Description This function is called to handle the read BLOB response
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_read_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ UNUSED_ATTR uint8_t op_code, uint16_t len,
+ uint8_t* p_data) {
+ uint16_t offset = p_clcb->counter;
+ uint8_t* p = p_data;
+
+ if (p_clcb->operation == GATTC_OPTYPE_READ) {
+ if (p_clcb->op_subtype != GATT_READ_BY_HANDLE) {
+ p_clcb->counter = len;
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p);
+ } else {
+ /* allocate GKI buffer holding up long attribute value */
+ if (!p_clcb->p_attr_buf)
+ p_clcb->p_attr_buf = (uint8_t*)osi_malloc(GATT_MAX_ATTR_LEN);
+
+ /* copy attrobute value into cb buffer */
+ if (offset < GATT_MAX_ATTR_LEN) {
+ if ((len + offset) > GATT_MAX_ATTR_LEN)
+ len = GATT_MAX_ATTR_LEN - offset;
+
+ p_clcb->counter += len;
+
+ memcpy(p_clcb->p_attr_buf + offset, p, len);
+
+ /* send next request if needed */
+
+ if (len == (p_tcb->payload_size -
+ 1) && /* full packet for read or read blob rsp */
+ len + offset < GATT_MAX_ATTR_LEN) {
+ GATT_TRACE_DEBUG(
+ "full pkt issue read blob for remianing bytes old offset=%d "
+ "len=%d new offset=%d",
+ offset, len, p_clcb->counter);
+ gatt_act_read(p_clcb, p_clcb->counter);
+ } else /* end of request, send callback */
+ {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, (void*)p_clcb->p_attr_buf);
+ }
+ } else /* exception, should not happen */
+ {
+ GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset,
+ p_clcb->p_attr_buf);
+ gatt_end_operation(p_clcb, GATT_NO_RESOURCES,
+ (void*)p_clcb->p_attr_buf);
+ }
+ }
+ } else {
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
+ p_clcb->read_uuid128.wait_for_read_rsp) {
+ p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
+ p_clcb->read_uuid128.wait_for_read_rsp = false;
+ if (len == LEN_UUID_128) {
+ memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu
+ .uuid128,
+ p, len);
+ p_clcb->read_uuid128.result.value.incl_service.service_type.len =
+ LEN_UUID_128;
+ if (p_clcb->p_reg->app_cb.p_disc_res_cb)
+ (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id,
+ p_clcb->op_subtype,
+ &p_clcb->read_uuid128.result);
+ gatt_act_discovery(p_clcb);
+ } else {
+ gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void*)p);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_handle_rsp
+ *
+ * Description This function is called to handle the write response
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_handle_rsp(tGATT_CLCB* p_clcb) {
+ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
+}
+/*******************************************************************************
+ *
+ * Function gatt_process_mtu_rsp
+ *
+ * Description Process the configure MTU response.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_mtu_rsp(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb, uint16_t len,
+ uint8_t* p_data) {
+ uint16_t mtu;
+ tGATT_STATUS status = GATT_SUCCESS;
+
+ if (len < GATT_MTU_RSP_MIN_LEN) {
+ GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
+ status = GATT_INVALID_PDU;
+ } else {
+ STREAM_TO_UINT16(mtu, p_data);
+
+ if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
+ p_tcb->payload_size = mtu;
+ }
+
+ l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID,
+ p_tcb->payload_size);
+ gatt_end_operation(p_clcb, status, NULL);
+}
+/*******************************************************************************
+ *
+ * Function gatt_cmd_to_rsp_code
+ *
+ * Description Convert an ATT command op code into the corresponding
+ * response code assume no error occurs.
+ *
+ * Returns response code.
+ *
+ ******************************************************************************/
+uint8_t gatt_cmd_to_rsp_code(uint8_t cmd_code) {
+ uint8_t rsp_code = 0;
+
+ if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE) {
+ rsp_code = cmd_code + 1;
+ }
+ return rsp_code;
+}
+/*******************************************************************************
+ *
+ * Function gatt_cl_send_next_cmd_inq
+ *
+ * Description Find next command in queue and sent to server
+ *
+ * Returns true if command sent, otherwise false.
+ *
+ ******************************************************************************/
+bool gatt_cl_send_next_cmd_inq(tGATT_TCB* p_tcb) {
+ tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ bool sent = false;
+ uint8_t rsp_code;
+ tGATT_CLCB* p_clcb = NULL;
+ tGATT_STATUS att_ret = GATT_SUCCESS;
+
+ while (!sent && p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
+ p_cmd->to_send && p_cmd->p_cmd != NULL) {
+ att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
+
+ if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
+ sent = true;
+ p_cmd->to_send = false;
+ p_cmd->p_cmd = NULL;
+
+ /* dequeue the request if is write command or sign write */
+ if (p_cmd->op_code != GATT_CMD_WRITE &&
+ p_cmd->op_code != GATT_SIGN_CMD_WRITE) {
+ gatt_start_rsp_timer(p_cmd->clcb_idx);
+ } else {
+ p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+
+ /* if no ack needed, keep sending */
+ if (att_ret == GATT_SUCCESS) sent = false;
+
+ p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ /* send command complete callback here */
+ gatt_end_operation(p_clcb, att_ret, NULL);
+ }
+ } else {
+ GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
+
+ memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
+ p_tcb->pending_cl_req++;
+ p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ }
+ }
+ return sent;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_client_handle_server_rsp
+ *
+ * Description This function is called to handle the server response to
+ * client.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ tGATT_CLCB* p_clcb = NULL;
+ uint8_t rsp_code;
+
+ if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
+ p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
+
+ rsp_code = gatt_cmd_to_rsp_code(rsp_code);
+
+ if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR)) {
+ GATT_TRACE_WARNING(
+ "ATT - Ignore wrong response. Receives (%02x) \
+ Request(%02x) Ignored",
+ op_code, rsp_code);
+
+ return;
+ } else {
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+ p_clcb->retry_count = 0;
+ }
+ }
+ /* the size of the message may not be bigger than the local max PDU size*/
+ /* The message has to be smaller than the agreed MTU, len does not count
+ * op_code */
+ if (len >= p_tcb->payload_size) {
+ GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d",
+ len + 1, p_tcb->payload_size);
+ if (op_code != GATT_HANDLE_VALUE_NOTIF && op_code != GATT_HANDLE_VALUE_IND)
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+ } else {
+ switch (op_code) {
+ case GATT_RSP_ERROR:
+ gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_MTU: /* 2 bytes mtu */
+ gatt_process_mtu_rsp(p_tcb, p_clcb, len, p_data);
+ break;
+
+ case GATT_RSP_FIND_INFO:
+ gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_READ_BY_TYPE:
+ case GATT_RSP_READ_BY_GRP_TYPE:
+ gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_READ:
+ case GATT_RSP_READ_BLOB:
+ case GATT_RSP_READ_MULTI:
+ gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
+ gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
+ break;
+
+ case GATT_RSP_WRITE:
+ gatt_process_handle_rsp(p_clcb);
+ break;
+
+ case GATT_RSP_PREPARE_WRITE:
+ gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
+ break;
+
+ case GATT_RSP_EXEC_WRITE:
+ gatt_end_operation(p_clcb, p_clcb->status, NULL);
+ break;
+
+ case GATT_HANDLE_VALUE_NOTIF:
+ case GATT_HANDLE_VALUE_IND:
+ gatt_process_notification(p_tcb, op_code, len, p_data);
+ break;
+
+ default:
+ GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
+ break;
+ }
+ }
+
+ if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF) {
+ gatt_cl_send_next_cmd_inq(p_tcb);
+ }
+
+ return;
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_db.cc b/mtkbt/code/bt/stack/gatt/gatt_db.cc
new file mode 100755
index 0000000..736958d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_db.cc
@@ -0,0 +1,774 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains GATT database building and query functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include "bt_trace.h"
+#include "bt_utils.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "btm_int.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ * L O C A L F U N C T I O N P R O T O T Y P E S *
+ ******************************************************************************/
+static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
+ tGATT_PERM perm);
+static tGATT_STATUS gatts_send_app_read_request(
+ tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
+ uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type);
+
+/**
+ * Initialize a memory space to be a service database.
+ */
+void gatts_init_service_db(tGATT_SVC_DB& db, tBT_UUID* p_service, bool is_pri,
+ uint16_t s_hdl, uint16_t num_handle) {
+ db.attr_list.reserve(num_handle);
+
+ GATT_TRACE_DEBUG("%s: s_hdl= %d num_handle= %d", __func__, s_hdl, num_handle);
+
+ /* update service database information */
+ db.next_handle = s_hdl;
+ db.end_handle = s_hdl + num_handle;
+
+ /* add service declration record */
+ tBT_UUID uuid = {LEN_UUID_16, {0}};
+ uuid.uu.uuid16 = is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE;
+ tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
+ attr.p_value.reset((tGATT_ATTR_VALUE*)(new tBT_UUID));
+ memcpy(&attr.p_value->uuid, p_service, sizeof(tBT_UUID));
+}
+
+tBT_UUID* gatts_get_service_uuid(tGATT_SVC_DB* p_db) {
+ if (!p_db || p_db->attr_list.empty()) {
+ GATT_TRACE_ERROR("service DB empty");
+ return NULL;
+ } else {
+ return &p_db->attr_list[0].p_value->uuid;
+ }
+}
+
+/** Check attribute readability. Returns status of operation. */
+static tGATT_STATUS gatts_check_attr_readability(const tGATT_ATTR& attr,
+ UNUSED_ATTR uint16_t offset,
+ bool read_long,
+ tGATT_SEC_FLAG sec_flag,
+ uint8_t key_size) {
+ uint16_t min_key_size;
+ tGATT_PERM perm = attr.permission;
+
+ min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+ if (min_key_size != 0) {
+ min_key_size += 6;
+ }
+
+ if (!(perm & GATT_READ_ALLOWED)) {
+ GATT_TRACE_ERROR("%s: GATT_READ_NOT_PERMIT", __func__);
+ return GATT_READ_NOT_PERMIT;
+ }
+
+ if ((perm & GATT_READ_AUTH_REQUIRED) &&
+ !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED) &&
+ !(sec_flag & BTM_SEC_FLAG_ENCRYPTED)) {
+ GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION", __func__);
+ return GATT_INSUF_AUTHENTICATION;
+ }
+
+ if ((perm & GATT_READ_MITM_REQUIRED) &&
+ !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) {
+ GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION: MITM Required", __func__);
+ return GATT_INSUF_AUTHENTICATION;
+ }
+
+ if ((perm & GATT_READ_ENCRYPTED_REQUIRED) &&
+ !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
+ GATT_TRACE_ERROR("%s: GATT_INSUF_ENCRYPTION", __func__);
+ return GATT_INSUF_ENCRYPTION;
+ }
+
+ if ((perm & GATT_READ_ENCRYPTED_REQUIRED) &&
+ (sec_flag & GATT_SEC_FLAG_ENCRYPTED) && (key_size < min_key_size)) {
+ GATT_TRACE_ERROR("%s: GATT_INSUF_KEY_SIZE", __func__);
+ return GATT_INSUF_KEY_SIZE;
+ }
+
+ if (read_long && attr.uuid.len == LEN_UUID_16) {
+ switch (attr.uuid.uu.uuid16) {
+ case GATT_UUID_PRI_SERVICE:
+ case GATT_UUID_SEC_SERVICE:
+ case GATT_UUID_CHAR_DECLARE:
+ case GATT_UUID_INCLUDE_SERVICE:
+ case GATT_UUID_CHAR_EXT_PROP:
+ case GATT_UUID_CHAR_CLIENT_CONFIG:
+ case GATT_UUID_CHAR_SRVR_CONFIG:
+ case GATT_UUID_CHAR_PRESENT_FORMAT:
+ GATT_TRACE_ERROR("%s: GATT_NOT_LONG", __func__);
+ return GATT_NOT_LONG;
+
+ default:
+ break;
+ }
+ }
+
+ return GATT_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function read_attr_value
+ *
+ * Description Utility function to read an attribute value.
+ *
+ * Parameter p_attr: pointer to the attribute to read.
+ * offset: read offset.
+ * p_value: output parameter to carry out the attribute value.
+ * p_len: output parameter to carry out the attribute length.
+ * read_long: this is a read blob request.
+ * mtu: MTU
+ * sec_flag: current link security status.
+ * key_size: encryption key size.
+ *
+ * Returns status of operation.
+ *
+ ******************************************************************************/
+static tGATT_STATUS read_attr_value(tGATT_ATTR& attr16, uint16_t offset,
+ uint8_t** p_data, bool read_long,
+ uint16_t mtu, uint16_t* p_len,
+ tGATT_SEC_FLAG sec_flag, uint8_t key_size) {
+ uint16_t len = 0, uuid16 = 0;
+ uint8_t* p = *p_data;
+
+ GATT_TRACE_DEBUG(
+ "%s: uuid=0x%04x perm=0x%02x sec_flag=0x%x offset=%d read_long=%d",
+ __func__, attr16.uuid, attr16.permission, sec_flag, offset, read_long);
+
+ tGATT_STATUS status = gatts_check_attr_readability(attr16, offset, read_long,
+ sec_flag, key_size);
+
+ if (status != GATT_SUCCESS) return status;
+
+ if (attr16.uuid.len == LEN_UUID_16) uuid16 = attr16.uuid.uu.uuid16;
+
+ status = GATT_NO_RESOURCES;
+
+ if (uuid16 == GATT_UUID_PRI_SERVICE || uuid16 == GATT_UUID_SEC_SERVICE) {
+ len = attr16.p_value->uuid.len;
+ if (mtu >= attr16.p_value->uuid.len) {
+ gatt_build_uuid_to_stream(&p, attr16.p_value->uuid);
+ status = GATT_SUCCESS;
+ }
+ } else if (uuid16 == GATT_UUID_CHAR_DECLARE) {
+ tGATT_ATTR* val_attr = &attr16 + 1;
+ len = (val_attr->uuid.len == LEN_UUID_16) ? 5 : 19;
+
+ if (mtu >= len) {
+ UINT8_TO_STREAM(p, attr16.p_value->char_decl.property);
+ UINT16_TO_STREAM(p, attr16.p_value->char_decl.char_val_handle);
+
+ if (val_attr->uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, val_attr->uuid.uu.uuid16);
+ }
+ /* convert a 32bits UUID to 128 bits */
+ else if (val_attr->uuid.len == LEN_UUID_32) {
+ gatt_convert_uuid32_to_uuid128(p, val_attr->uuid.uu.uuid32);
+ p += LEN_UUID_128;
+ } else {
+ ARRAY_TO_STREAM(p, val_attr->uuid.uu.uuid128, LEN_UUID_128);
+ }
+ status = GATT_SUCCESS;
+ }
+
+ } else if (uuid16 == GATT_UUID_INCLUDE_SERVICE) {
+ if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16)
+ len = 6;
+ else
+ len = 4;
+
+ if (mtu >= len) {
+ UINT16_TO_STREAM(p, attr16.p_value->incl_handle.s_handle);
+ UINT16_TO_STREAM(p, attr16.p_value->incl_handle.e_handle);
+
+ if (attr16.p_value->incl_handle.service_type.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, attr16.p_value->incl_handle.service_type.uu.uuid16);
+ }
+ status = GATT_SUCCESS;
+ }
+ } else /* characteristic description or characteristic value */
+ {
+ status = GATT_PENDING;
+ }
+
+ *p_len = len;
+ *p_data = p;
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_db_read_attr_value_by_type
+ *
+ * Description Query attribute value by attribute type.
+ *
+ * Parameter p_db: pointer to the attribute database.
+ * p_rsp: Read By type response data.
+ * s_handle: starting handle of the range we are looking for.
+ * e_handle: ending handle of the range we are looking for.
+ * type: Attribute type.
+ * mtu: MTU.
+ * sec_flag: current link security status.
+ * key_size: encryption key size.
+ *
+ * Returns Status of the operation.
+ *
+ ******************************************************************************/
+tGATT_STATUS gatts_db_read_attr_value_by_type(
+ tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
+ uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
+ tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
+ uint16_t* p_cur_handle) {
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ uint16_t len = 0;
+ uint8_t* p = (uint8_t*)(p_rsp + 1) + p_rsp->len + L2CAP_MIN_OFFSET;
+
+ if (p_db) {
+ for (tGATT_ATTR& attr : p_db->attr_list) {
+ tBT_UUID attr_uuid = attr.uuid;
+
+ if (attr.handle >= s_handle && gatt_uuid_compare(type, attr_uuid)) {
+ if (*p_len <= 2) {
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+
+ UINT16_TO_STREAM(p, attr.handle);
+
+ status = read_attr_value(attr, 0, &p, false, (uint16_t)(*p_len - 2),
+ &len, sec_flag, key_size);
+
+ if (status == GATT_PENDING) {
+ status = gatts_send_app_read_request(p_tcb, op_code, attr.handle, 0,
+ trans_id, attr.gatt_type);
+
+ /* one callback at a time */
+ break;
+ } else if (status == GATT_SUCCESS) {
+ if (p_rsp->offset == 0) p_rsp->offset = len + 2;
+
+ if (p_rsp->offset == len + 2) {
+ p_rsp->len += (len + 2);
+ *p_len -= (len + 2);
+ } else {
+ GATT_TRACE_ERROR("format mismatch");
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+ } else {
+ *p_cur_handle = attr.handle;
+ break;
+ }
+ }
+ }
+ }
+
+#if (BLE_DELAY_REQUEST_ENC == TRUE)
+ uint8_t flag = 0;
+ if (BTM_GetSecurityFlags(p_tcb->peer_bda, &flag)) {
+ if ((p_tcb->att_lcid == L2CAP_ATT_CID) && (status == GATT_PENDING) &&
+ (type.uu.uuid16 == GATT_UUID_GAP_DEVICE_NAME)) {
+ if ((flag & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_FLAG_ENCRYPTED)) ==
+ BTM_SEC_LINK_KEY_KNOWN) {
+ tACL_CONN* p = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
+ if ((p != NULL) && (p->link_role == BTM_ROLE_MASTER))
+ btm_ble_set_encryption(p_tcb->peer_bda, BTM_BLE_SEC_ENCRYPT,
+ p->link_role);
+ }
+ }
+ }
+#endif
+ return status;
+}
+
+/**
+ * This function adds an included service into a database.
+ *
+ * Parameter db: database pointer.
+ * inc_srvc_type: included service type.
+ *
+ * Returns Status of the operation.
+ *
+ */
+uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
+ uint16_t e_handle, tBT_UUID service) {
+ tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_INCLUDE_SERVICE}};
+
+ GATT_TRACE_DEBUG("%s: s_hdl = 0x%04x e_hdl = 0x%04x uuid = 0x%04x", __func__,
+ s_handle, e_handle, service.uu.uuid16);
+
+ if (service.len == 0 || s_handle == 0 || e_handle == 0) {
+ GATT_TRACE_ERROR("%s: Illegal Params.", __func__);
+ return 0;
+ }
+
+ tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
+
+ attr.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_INCL_SRVC));
+ attr.p_value->incl_handle.s_handle = s_handle;
+ attr.p_value->incl_handle.e_handle = e_handle;
+ memcpy(&attr.p_value->incl_handle.service_type, &service, sizeof(tBT_UUID));
+
+ return attr.handle;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_add_characteristic
+ *
+ * Description This function add a characteristics and its descriptor into
+ * a servce identified by the service database pointer.
+ *
+ * Parameter db: database.
+ * perm: permission (authentication and key size requirements)
+ * property: property of the characteristic.
+ * p_char: characteristic value information.
+ *
+ * Returns Status of te operation.
+ *
+ ******************************************************************************/
+uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
+ tGATT_CHAR_PROP property,
+ tBT_UUID& char_uuid) {
+ tBT_UUID uuid = {LEN_UUID_16, {GATT_UUID_CHAR_DECLARE}};
+
+ GATT_TRACE_DEBUG("%s: perm=0x%0x property=0x%0x", __func__, perm, property);
+
+ tGATT_ATTR& char_decl = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
+ tGATT_ATTR& char_val = allocate_attr_in_db(db, char_uuid, perm);
+
+ char_decl.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_CHAR_DECL));
+ char_decl.p_value->char_decl.property = property;
+ char_decl.p_value->char_decl.char_val_handle = char_val.handle;
+ char_val.gatt_type = BTGATT_DB_CHARACTERISTIC;
+ return char_val.handle;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_convertchar_descr_type
+ *
+ * Description Convert a char descript UUID into descriptor type.
+ *
+ * Returns descriptor type.
+ *
+ ******************************************************************************/
+uint8_t gatt_convertchar_descr_type(tBT_UUID* p_descr_uuid) {
+ tBT_UUID std_descr = {LEN_UUID_16, {GATT_UUID_CHAR_EXT_PROP}};
+
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid))
+ return GATT_DESCR_EXT_DSCPTOR;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid))
+ return GATT_DESCR_USER_DSCPTOR;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_CLT_CONFIG;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid)) return GATT_DESCR_SVR_CONFIG;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid))
+ return GATT_DESCR_PRES_FORMAT;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid))
+ return GATT_DESCR_AGGR_FORMAT;
+
+ std_descr.uu.uuid16++;
+ if (gatt_uuid_compare(std_descr, *p_descr_uuid))
+ return GATT_DESCR_VALID_RANGE;
+
+ return GATT_DESCR_UNKNOWN;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_add_char_descr
+ *
+ * Description This function add a characteristics descriptor.
+ *
+ * Parameter p_db: database pointer.
+ * perm: characteristic descriptor permission type.
+ * char_dscp_tpye: the characteristic descriptor masks.
+ * p_dscp_params: characteristic descriptors values.
+ *
+ * Returns Status of the operation.
+ *
+ ******************************************************************************/
+uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
+ tBT_UUID& descr_uuid) {
+ GATT_TRACE_DEBUG("gatts_add_char_descr uuid=0x%04x", descr_uuid.uu.uuid16);
+
+ /* Add characteristic descriptors */
+ tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm);
+ char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR;
+ return char_dscptr.handle;
+}
+
+/******************************************************************************/
+/* Service Attribute Database Query Utility Functions */
+/******************************************************************************/
+tGATT_ATTR* find_attr_by_handle(tGATT_SVC_DB* p_db, uint16_t handle) {
+ if (!p_db) return nullptr;
+
+ for (auto& attr : p_db->attr_list) {
+ if (attr.handle == handle) return &attr;
+ if (attr.handle > handle) return nullptr;
+ }
+
+ return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_read_attr_value_by_handle
+ *
+ * Description Query attribute value by attribute handle.
+ *
+ * Parameter p_db: pointer to the attribute database.
+ * handle: Attribute handle to read.
+ * offset: Read offset.
+ * p_value: output parameter to carry out the attribute value.
+ * p_len: output parameter as attribute length read.
+ * read_long: this is a read blob request.
+ * mtu: MTU.
+ * sec_flag: current link security status.
+ * key_size: encryption key size
+ *
+ * Returns Status of operation.
+ *
+ ******************************************************************************/
+tGATT_STATUS gatts_read_attr_value_by_handle(
+ tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
+ uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
+ tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id) {
+ tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
+ if (!p_attr) return GATT_NOT_FOUND;
+
+ uint8_t* pp = p_value;
+ tGATT_STATUS status = read_attr_value(*p_attr, offset, &pp,
+ (bool)(op_code == GATT_REQ_READ_BLOB),
+ mtu, p_len, sec_flag, key_size);
+
+ if (status == GATT_PENDING) {
+ status = gatts_send_app_read_request(p_tcb, op_code, p_attr->handle, offset,
+ trans_id, p_attr->gatt_type);
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_read_attr_perm_check
+ *
+ * Description Check attribute readability.
+ *
+ * Parameter p_db: pointer to the attribute database.
+ * handle: Attribute handle to read.
+ * offset: Read offset.
+ * p_value: output parameter to carry out the attribute value.
+ * p_len: output parameter as attribute length read.
+ * read_long: this is a read blob request.
+ * mtu: MTU.
+ * sec_flag: current link security status.
+ * key_size: encryption key size
+ *
+ * Returns Status of operation.
+ *
+ ******************************************************************************/
+tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long,
+ uint16_t handle,
+ tGATT_SEC_FLAG sec_flag,
+ uint8_t key_size) {
+ tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
+ if (!p_attr) return GATT_NOT_FOUND;
+
+ return gatts_check_attr_readability(*p_attr, 0, is_long, sec_flag, key_size);
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_write_attr_perm_check
+ *
+ * Description Write attribute value into database.
+ *
+ * Parameter p_db: pointer to the attribute database.
+ * op_code:op code of this write.
+ * handle: handle of the attribute to write.
+ * offset: Write offset if write op code is write blob.
+ * p_data: Attribute value to write.
+ * len: attribute data length.
+ * sec_flag: current link security status.
+ * key_size: encryption key size
+ *
+ * Returns Status of the operation.
+ *
+ ******************************************************************************/
+tGATT_STATUS gatts_write_attr_perm_check(tGATT_SVC_DB* p_db, uint8_t op_code,
+ uint16_t handle, uint16_t offset,
+ uint8_t* p_data, uint16_t len,
+ tGATT_SEC_FLAG sec_flag,
+ uint8_t key_size) {
+ GATT_TRACE_DEBUG(
+ "%s: op_code=0x%0x handle=0x%04x offset=%d len=%d sec_flag=0x%0x "
+ "key_size=%d",
+ __func__, op_code, handle, offset, len, sec_flag, key_size);
+
+ tGATT_ATTR* p_attr = find_attr_by_handle(p_db, handle);
+ if (!p_attr) return GATT_NOT_FOUND;
+
+ tGATT_PERM perm = p_attr->permission;
+ uint16_t min_key_size = (((perm & GATT_ENCRYPT_KEY_SIZE_MASK) >> 12));
+ if (min_key_size != 0) {
+ min_key_size += 6;
+ }
+ GATT_TRACE_DEBUG("%s: p_attr->permission =0x%04x min_key_size==0x%04x",
+ __func__, p_attr->permission, min_key_size);
+
+ if ((op_code == GATT_CMD_WRITE || op_code == GATT_REQ_WRITE) &&
+ (perm & GATT_WRITE_SIGNED_PERM)) {
+ /* use the rules for the mixed security see section 10.2.3*/
+ /* use security mode 1 level 2 when the following condition follows */
+ /* LE security mode 2 level 1 and LE security mode 1 level 2 */
+ if ((perm & GATT_PERM_WRITE_SIGNED) && (perm & GATT_PERM_WRITE_ENCRYPTED)) {
+ perm = GATT_PERM_WRITE_ENCRYPTED;
+ }
+ /* use security mode 1 level 3 when the following condition follows */
+ /* LE security mode 2 level 2 and security mode 1 and LE */
+ else if (((perm & GATT_PERM_WRITE_SIGNED_MITM) &&
+ (perm & GATT_PERM_WRITE_ENCRYPTED)) ||
+ /* LE security mode 2 and security mode 1 level 3 */
+ ((perm & GATT_WRITE_SIGNED_PERM) &&
+ (perm & GATT_PERM_WRITE_ENC_MITM))) {
+ perm = GATT_PERM_WRITE_ENC_MITM;
+ }
+ }
+
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ if ((op_code == GATT_SIGN_CMD_WRITE) && !(perm & GATT_WRITE_SIGNED_PERM)) {
+ status = GATT_WRITE_NOT_PERMIT;
+ GATT_TRACE_DEBUG("%s: sign cmd write not allowed", __func__);
+ }
+ if ((op_code == GATT_SIGN_CMD_WRITE) &&
+ (sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
+ status = GATT_INVALID_PDU;
+ GATT_TRACE_ERROR("%s: Error!! sign cmd write sent on a encypted link",
+ __func__);
+ } else if (!(perm & GATT_WRITE_ALLOWED)) {
+ status = GATT_WRITE_NOT_PERMIT;
+ GATT_TRACE_ERROR("%s: GATT_WRITE_NOT_PERMIT", __func__);
+ }
+ /* require authentication, but not been authenticated */
+ else if ((perm & GATT_WRITE_AUTH_REQUIRED) &&
+ !(sec_flag & GATT_SEC_FLAG_LKEY_UNAUTHED)) {
+ status = GATT_INSUF_AUTHENTICATION;
+ GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION", __func__);
+ } else if ((perm & GATT_WRITE_MITM_REQUIRED) &&
+ !(sec_flag & GATT_SEC_FLAG_LKEY_AUTHED)) {
+ status = GATT_INSUF_AUTHENTICATION;
+ GATT_TRACE_ERROR("%s: GATT_INSUF_AUTHENTICATION: MITM required", __func__);
+ } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) &&
+ !(sec_flag & GATT_SEC_FLAG_ENCRYPTED)) {
+ status = GATT_INSUF_ENCRYPTION;
+ GATT_TRACE_ERROR("%s: GATT_INSUF_ENCRYPTION", __func__);
+ } else if ((perm & GATT_WRITE_ENCRYPTED_PERM) &&
+ (sec_flag & GATT_SEC_FLAG_ENCRYPTED) &&
+ (key_size < min_key_size)) {
+ status = GATT_INSUF_KEY_SIZE;
+ GATT_TRACE_ERROR("%s: GATT_INSUF_KEY_SIZE", __func__);
+ }
+ /* LE security mode 2 attribute */
+ else if (perm & GATT_WRITE_SIGNED_PERM && op_code != GATT_SIGN_CMD_WRITE &&
+ !(sec_flag & GATT_SEC_FLAG_ENCRYPTED) &&
+ (perm & GATT_WRITE_ALLOWED) == 0) {
+ status = GATT_INSUF_AUTHENTICATION;
+ GATT_TRACE_ERROR(
+ "%s: GATT_INSUF_AUTHENTICATION: LE security mode 2 required", __func__);
+ } else /* writable: must be char value declaration or char descritpors
+ */
+ {
+ uint16_t max_size = 0;
+
+ if (p_attr->uuid.len == LEN_UUID_16) {
+ switch (p_attr->uuid.uu.uuid16) {
+ case GATT_UUID_CHAR_PRESENT_FORMAT: /* should be readable only */
+ case GATT_UUID_CHAR_EXT_PROP: /* should be readable only */
+ case GATT_UUID_CHAR_AGG_FORMAT: /* should be readable only */
+ case GATT_UUID_CHAR_VALID_RANGE:
+ status = GATT_WRITE_NOT_PERMIT;
+ break;
+
+ case GATT_UUID_CHAR_CLIENT_CONFIG:
+ /* fall through */
+ case GATT_UUID_CHAR_SRVR_CONFIG:
+ max_size = 2;
+ /* fall through */
+ case GATT_UUID_CHAR_DESCRIPTION:
+ default: /* any other must be character value declaration */
+ status = GATT_SUCCESS;
+ break;
+ }
+ } else if (p_attr->uuid.len == LEN_UUID_128 ||
+ p_attr->uuid.len == LEN_UUID_32) {
+ status = GATT_SUCCESS;
+ } else {
+ status = GATT_INVALID_PDU;
+ }
+
+ if (p_data == NULL && len > 0) {
+ status = GATT_INVALID_PDU;
+ }
+ /* these attribute does not allow write blob */
+ else if ((p_attr->uuid.len == LEN_UUID_16) &&
+ (p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG ||
+ p_attr->uuid.uu.uuid16 == GATT_UUID_CHAR_SRVR_CONFIG)) {
+ if (op_code == GATT_REQ_PREPARE_WRITE &&
+ offset != 0) /* does not allow write blob */
+ {
+ status = GATT_NOT_LONG;
+ GATT_TRACE_ERROR("%s: GATT_NOT_LONG", __func__);
+ } else if (len != max_size) /* data does not match the required format */
+ {
+ status = GATT_INVALID_ATTR_LEN;
+ GATT_TRACE_ERROR("%s: GATT_INVALID_PDU", __func__);
+ } else {
+ status = GATT_SUCCESS;
+ }
+ }
+ }
+
+ return status;
+}
+
+static void uuid_to_str(const tBT_UUID bt_uuid, char* str_buf, size_t buf_len) {
+ if (bt_uuid.len == LEN_UUID_16) {
+ snprintf(str_buf, buf_len, "0x%04x", bt_uuid.uu.uuid16);
+ } else if (bt_uuid.len == LEN_UUID_32) {
+ snprintf(str_buf, buf_len, "0x%08x", bt_uuid.uu.uuid32);
+ } else if (bt_uuid.len == LEN_UUID_128) {
+ int x = snprintf(str_buf, buf_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-",
+ bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14],
+ bt_uuid.uu.uuid128[13], bt_uuid.uu.uuid128[12],
+ bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+ bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+ snprintf(&str_buf[x], buf_len - x, "%02x%02x-%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6],
+ bt_uuid.uu.uuid128[5], bt_uuid.uu.uuid128[4],
+ bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+ bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+ } else
+ snprintf(str_buf, buf_len, "Unknown (len=%d)", bt_uuid.len);
+}
+
+/**
+ * Description Allocate a memory space for a new attribute, and link this
+ * attribute into the database attribute list.
+ *
+ *
+ * Parameter p_db : database pointer.
+ * uuid: attribute UUID
+ *
+ * Returns pointer to the newly allocated attribute.
+ *
+ */
+static tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const tBT_UUID& uuid,
+ tGATT_PERM perm) {
+ if (db.next_handle >= db.end_handle) {
+ LOG(FATAL) << __func__
+ << " wrong number of handles! handle_max = " << +db.end_handle
+ << ", next_handle = " << +db.next_handle;
+ }
+
+ db.attr_list.emplace_back();
+ tGATT_ATTR& attr = db.attr_list.back();
+ attr.handle = db.next_handle++;
+ attr.uuid = uuid;
+ attr.permission = perm;
+
+ char uuid_str[37];
+ uuid_to_str(attr.uuid, uuid_str, sizeof(uuid_str));
+
+ return attr;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_send_app_read_request
+ *
+ * Description Send application read request callback
+ *
+ * Returns status of operation.
+ *
+ ******************************************************************************/
+static tGATT_STATUS gatts_send_app_read_request(
+ tGATT_TCB* p_tcb, uint8_t op_code, uint16_t handle, uint16_t offset,
+ uint32_t trans_id, bt_gatt_db_attribute_type_t gatt_type) {
+ tGATT_SRV_LIST_ELEM& el = *gatt_sr_find_i_rcb_by_handle(handle);
+ uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
+
+ if (trans_id == 0) {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ gatt_sr_update_cback_cnt(p_tcb, el.gatt_if, true, true);
+ }
+
+ if (trans_id != 0) {
+ tGATTS_DATA sr_data;
+ memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+ sr_data.read_req.handle = handle;
+ sr_data.read_req.is_long = (bool)(op_code == GATT_REQ_READ_BLOB);
+ sr_data.read_req.offset = offset;
+
+ uint8_t opcode;
+ if (gatt_type == BTGATT_DB_DESCRIPTOR) {
+ opcode = GATTS_REQ_TYPE_READ_DESCRIPTOR;
+ } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
+ opcode = GATTS_REQ_TYPE_READ_CHARACTERISTIC;
+ } else {
+ GATT_TRACE_ERROR(
+ "%s: Attempt to read attribute that's not tied with"
+ " characteristic or descriptor value.",
+ __func__);
+ return GATT_ERROR;
+ }
+
+ gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data);
+ return (tGATT_STATUS)GATT_PENDING;
+ } else
+ return (tGATT_STATUS)GATT_BUSY; /* max pending command, application error */
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_int.h b/mtkbt/code/bt/stack/gatt/gatt_int.h
new file mode 100755
index 0000000..812d156
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_int.h
@@ -0,0 +1,609 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef GATT_INT_H
+#define GATT_INT_H
+
+#include "bt_target.h"
+
+#include "bt_trace.h"
+#include "btm_ble_api.h"
+#include "btu.h"
+#include "gatt_api.h"
+#include "osi/include/fixed_queue.h"
+
+#include <string.h>
+#include <list>
+#include <vector>
+
+#define GATT_CREATE_CONN_ID(tcb_idx, gatt_if) \
+ ((uint16_t)((((uint8_t)(tcb_idx)) << 8) | ((uint8_t)(gatt_if))))
+#define GATT_GET_TCB_IDX(conn_id) ((uint8_t)(((uint16_t)(conn_id)) >> 8))
+#define GATT_GET_GATT_IF(conn_id) ((tGATT_IF)((uint8_t)(conn_id)))
+
+#define GATT_TRANS_ID_MAX 0x0fffffff /* 4 MSB is reserved */
+
+/* security action for GATT write and read request */
+#define GATT_SEC_NONE 0
+#define GATT_SEC_OK 1
+#define GATT_SEC_SIGN_DATA 2 /* compute the signature for the write cmd */
+#define GATT_SEC_ENCRYPT 3 /* encrypt the link with current key */
+#define GATT_SEC_ENCRYPT_NO_MITM 4 /* unauthenticated encryption or better */
+#define GATT_SEC_ENCRYPT_MITM 5 /* authenticated encryption */
+#define GATT_SEC_ENC_PENDING 6 /* wait for link encryption pending */
+typedef uint8_t tGATT_SEC_ACTION;
+
+#define GATT_ATTR_OP_SPT_MTU (0x00000001 << 0)
+#define GATT_ATTR_OP_SPT_FIND_INFO (0x00000001 << 1)
+#define GATT_ATTR_OP_SPT_FIND_BY_TYPE (0x00000001 << 2)
+#define GATT_ATTR_OP_SPT_READ_BY_TYPE (0x00000001 << 3)
+#define GATT_ATTR_OP_SPT_READ (0x00000001 << 4)
+#define GATT_ATTR_OP_SPT_MULT_READ (0x00000001 << 5)
+#define GATT_ATTR_OP_SPT_READ_BLOB (0x00000001 << 6)
+#define GATT_ATTR_OP_SPT_READ_BY_GRP_TYPE (0x00000001 << 7)
+#define GATT_ATTR_OP_SPT_WRITE (0x00000001 << 8)
+#define GATT_ATTR_OP_SPT_WRITE_CMD (0x00000001 << 9)
+#define GATT_ATTR_OP_SPT_PREP_WRITE (0x00000001 << 10)
+#define GATT_ATTR_OP_SPT_EXE_WRITE (0x00000001 << 11)
+#define GATT_ATTR_OP_SPT_HDL_VALUE_CONF (0x00000001 << 12)
+#define GATT_ATTR_OP_SP_SIGN_WRITE (0x00000001 << 13)
+
+#define GATT_INDEX_INVALID 0xff
+
+#define GATT_PENDING_REQ_NONE 0
+
+#define GATT_WRITE_CMD_MASK 0xc0 /*0x1100-0000*/
+#define GATT_AUTH_SIGN_MASK 0x80 /*0x1000-0000*/
+#define GATT_AUTH_SIGN_LEN 12
+
+#define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */
+
+/* wait for ATT cmd response timeout value */
+#define GATT_WAIT_FOR_RSP_TIMEOUT_MS (30 * 1000)
+#define GATT_WAIT_FOR_DISC_RSP_TIMEOUT_MS (5 * 1000)
+#define GATT_REQ_RETRY_LIMIT 2
+
+/* characteristic descriptor type */
+#define GATT_DESCR_EXT_DSCPTOR 1 /* Characteristic Extended Properties */
+#define GATT_DESCR_USER_DSCPTOR 2 /* Characteristic User Description */
+#define GATT_DESCR_CLT_CONFIG 3 /* Client Characteristic Configuration */
+#define GATT_DESCR_SVR_CONFIG 4 /* Server Characteristic Configuration */
+#define GATT_DESCR_PRES_FORMAT 5 /* Characteristic Presentation Format */
+#define GATT_DESCR_AGGR_FORMAT 6 /* Characteristic Aggregate Format */
+#define GATT_DESCR_VALID_RANGE 7 /* Characteristic Valid Range */
+#define GATT_DESCR_UNKNOWN 0xff
+
+#define GATT_SEC_FLAG_LKEY_UNAUTHED BTM_SEC_FLAG_LKEY_KNOWN
+#define GATT_SEC_FLAG_LKEY_AUTHED BTM_SEC_FLAG_LKEY_AUTHED
+#define GATT_SEC_FLAG_ENCRYPTED BTM_SEC_FLAG_ENCRYPTED
+typedef uint8_t tGATT_SEC_FLAG;
+
+/* Find Information Response Type
+*/
+#define GATT_INFO_TYPE_PAIR_16 0x01
+#define GATT_INFO_TYPE_PAIR_128 0x02
+
+/* GATT client FIND_TYPE_VALUE_Request data */
+typedef struct {
+ tBT_UUID uuid; /* type of attribute to be found */
+ uint16_t s_handle; /* starting handle */
+ uint16_t e_handle; /* ending handle */
+ uint16_t value_len; /* length of the attribute value */
+ uint8_t
+ value[GATT_MAX_MTU_SIZE]; /* pointer to the attribute value to be found */
+} tGATT_FIND_TYPE_VALUE;
+
+/* client request message to ATT protocol
+*/
+typedef union {
+ tGATT_READ_BY_TYPE browse; /* read by type request */
+ tGATT_FIND_TYPE_VALUE find_type_value; /* find by type value */
+ tGATT_READ_MULTI read_multi; /* read multiple request */
+ tGATT_READ_PARTIAL read_blob; /* read blob */
+ tGATT_VALUE attr_value; /* write request */
+ /* prepare write */
+ /* write blob */
+ uint16_t handle; /* read, handle value confirmation */
+ uint16_t mtu;
+ tGATT_EXEC_FLAG exec_write; /* execute write */
+} tGATT_CL_MSG;
+
+/* error response strucutre */
+typedef struct {
+ uint16_t handle;
+ uint8_t cmd_code;
+ uint8_t reason;
+} tGATT_ERROR;
+
+/* server response message to ATT protocol
+*/
+typedef union {
+ /* data type member event */
+ tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+ /* READ_BLOB, READ_BY_TYPE */
+ tGATT_ERROR error; /* ERROR_RSP */
+ uint16_t handle; /* WRITE, WRITE_BLOB */
+ uint16_t mtu; /* exchange MTU request */
+} tGATT_SR_MSG;
+
+/* Characteristic declaration attribute value
+*/
+typedef struct {
+ tGATT_CHAR_PROP property;
+ uint16_t char_val_handle;
+} tGATT_CHAR_DECL;
+
+/* attribute value maintained in the server database
+*/
+typedef union {
+ tBT_UUID uuid; /* service declaration */
+ tGATT_CHAR_DECL char_decl; /* characteristic declaration */
+ tGATT_INCL_SRVC incl_handle; /* included service */
+} tGATT_ATTR_VALUE;
+
+/* Attribute UUID type
+*/
+#define GATT_ATTR_UUID_TYPE_16 0
+#define GATT_ATTR_UUID_TYPE_128 1
+#define GATT_ATTR_UUID_TYPE_32 2
+typedef uint8_t tGATT_ATTR_UUID_TYPE;
+
+/* 16 bits UUID Attribute in server database
+*/
+typedef struct {
+ std::unique_ptr<tGATT_ATTR_VALUE> p_value;
+ tGATT_PERM permission;
+ uint16_t handle;
+ tBT_UUID uuid;
+ bt_gatt_db_attribute_type_t gatt_type;
+} tGATT_ATTR;
+
+/* Service Database definition
+*/
+typedef struct {
+ std::vector<tGATT_ATTR> attr_list; /* pointer to the attributes */
+ uint16_t end_handle; /* Last handle number */
+ uint16_t next_handle; /* Next usable handle value */
+} tGATT_SVC_DB;
+
+/* Data Structure used for GATT server */
+/* An GATT registration record consists of a handle, and 1 or more attributes */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback. */
+
+typedef struct {
+ tBT_UUID app_uuid128;
+ tGATT_CBACK app_cb;
+ tGATT_IF gatt_if; /* one based */
+ bool in_use;
+ uint8_t listening; /* if adv for all has been enabled */
+} tGATT_REG;
+
+/* command queue for each connection */
+typedef struct {
+ BT_HDR* p_cmd;
+ uint16_t clcb_idx;
+ uint8_t op_code;
+ bool to_send;
+} tGATT_CMD_Q;
+
+#if GATT_MAX_SR_PROFILES <= 8
+typedef uint8_t tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 16
+typedef uint16_t tGATT_APP_MASK;
+#elif GATT_MAX_SR_PROFILES <= 32
+typedef uint32_t tGATT_APP_MASK;
+#endif
+
+/* command details for each connection */
+typedef struct {
+ BT_HDR* p_rsp_msg;
+ uint32_t trans_id;
+ tGATT_READ_MULTI multi_req;
+ fixed_queue_t* multi_rsp_q;
+ uint16_t handle;
+ uint8_t op_code;
+ uint8_t status;
+ uint8_t cback_cnt[GATT_MAX_APPS];
+} tGATT_SR_CMD;
+
+#define GATT_CH_CLOSE 0
+#define GATT_CH_CLOSING 1
+#define GATT_CH_CONN 2
+#define GATT_CH_CFG 3
+#define GATT_CH_OPEN 4
+
+typedef uint8_t tGATT_CH_STATE;
+
+#define GATT_GATT_START_HANDLE 1
+#define GATT_GAP_START_HANDLE 20
+#define GATT_APP_START_HANDLE 40
+
+typedef struct hdl_cfg {
+ uint16_t gatt_start_hdl;
+ uint16_t gap_start_hdl;
+ uint16_t app_start_hdl;
+} tGATT_HDL_CFG;
+
+typedef struct hdl_list_elem {
+ tGATTS_HNDL_RANGE asgn_range; /* assigned handle range */
+ tGATT_SVC_DB svc_db;
+} tGATT_HDL_LIST_ELEM;
+
+/* Data Structure used for GATT server */
+/* A GATT registration record consists of a handle, and 1 or more attributes */
+/* A service registration information record consists of beginning and ending */
+/* attribute handle, service UUID and a set of GATT server callback. */
+typedef struct {
+ tGATT_SVC_DB* p_db; /* pointer to the service database */
+ tBT_UUID app_uuid; /* applicatino UUID */
+ uint32_t sdp_handle; /* primamry service SDP handle */
+ uint16_t type; /* service type UUID, primary or secondary */
+ uint16_t s_hdl; /* service starting handle */
+ uint16_t e_hdl; /* service ending handle */
+ tGATT_IF gatt_if; /* this service is belong to which application */
+ bool is_primary;
+} tGATT_SRV_LIST_ELEM;
+
+typedef struct {
+ fixed_queue_t* pending_enc_clcb; /* pending encryption channel q */
+ tGATT_SEC_ACTION sec_act;
+ BD_ADDR peer_bda;
+ tBT_TRANSPORT transport;
+ uint32_t trans_id;
+
+ uint16_t att_lcid; /* L2CAP channel ID for ATT */
+ uint16_t payload_size;
+
+ tGATT_CH_STATE ch_state;
+ uint8_t ch_flags;
+
+ tGATT_IF app_hold_link[GATT_MAX_APPS];
+
+ /* server needs */
+ /* server response data */
+ tGATT_SR_CMD sr_cmd;
+ uint16_t indicate_handle;
+ fixed_queue_t* pending_ind_q;
+
+ alarm_t* conf_timer; /* peer confirm to indication timer */
+
+ uint8_t prep_cnt[GATT_MAX_APPS];
+ uint8_t ind_count;
+
+ tGATT_CMD_Q cl_cmd_q[GATT_CL_MAX_LCB];
+ alarm_t* ind_ack_timer; /* local app confirm to indication timer */
+ uint8_t pending_cl_req;
+ uint8_t next_slot_inq; /* index of next available slot in queue */
+
+ bool in_use;
+ uint8_t tcb_idx;
+} tGATT_TCB;
+
+/* logic channel */
+typedef struct {
+ uint16_t
+ next_disc_start_hdl; /* starting handle for the next inc srvv discovery */
+ tGATT_DISC_RES result;
+ bool wait_for_read_rsp;
+} tGATT_READ_INC_UUID128;
+typedef struct {
+ tGATT_TCB* p_tcb; /* associated TCB of this CLCB */
+ tGATT_REG* p_reg; /* owner of this CLCB */
+ uint8_t sccb_idx;
+ uint8_t* p_attr_buf; /* attribute buffer for read multiple, prepare write */
+ tBT_UUID uuid;
+ uint16_t conn_id; /* connection handle */
+ uint16_t clcb_idx;
+ uint16_t s_handle; /* starting handle of the active request */
+ uint16_t e_handle; /* ending handle of the active request */
+ uint16_t counter; /* used as offset, attribute length, num of prepare write */
+ uint16_t start_offset;
+ tGATT_AUTH_REQ auth_req; /* authentication requirement */
+ uint8_t operation; /* one logic channel can have one operation active */
+ uint8_t op_subtype; /* operation subtype */
+ uint8_t status; /* operation status */
+ bool first_read_blob_after_read;
+ tGATT_READ_INC_UUID128 read_uuid128;
+ bool in_use;
+ alarm_t* gatt_rsp_timer_ent; /* peer response timer */
+ uint8_t retry_count;
+
+} tGATT_CLCB;
+
+typedef struct { tGATT_CLCB* p_clcb; } tGATT_PENDING_ENC_CLCB;
+
+typedef struct {
+ uint16_t clcb_idx;
+ bool in_use;
+} tGATT_SCCB;
+
+typedef struct {
+ uint16_t handle;
+ uint16_t uuid;
+ uint32_t service_change;
+} tGATT_SVC_CHG;
+
+typedef struct {
+ tGATT_IF gatt_if[GATT_MAX_APPS];
+ BD_ADDR remote_bda;
+ bool in_use;
+} tGATT_BG_CONN_DEV;
+
+#define GATT_SVC_CHANGED_CONNECTING 1 /* wait for connection */
+#define GATT_SVC_CHANGED_SERVICE 2 /* GATT service discovery */
+#define GATT_SVC_CHANGED_CHARACTERISTIC 3 /* service change char discovery */
+#define GATT_SVC_CHANGED_DESCRIPTOR 4 /* service change CCC discoery */
+#define GATT_SVC_CHANGED_CONFIGURE_CCCD 5 /* config CCC */
+
+typedef struct {
+ uint16_t conn_id;
+ bool in_use;
+ bool connected;
+ BD_ADDR bda;
+ tBT_TRANSPORT transport;
+
+ /* GATT service change CCC related variables */
+ uint8_t ccc_stage;
+ uint8_t ccc_result;
+ uint16_t s_handle;
+ uint16_t e_handle;
+} tGATT_PROFILE_CLCB;
+
+typedef struct {
+ tGATT_TCB tcb[GATT_MAX_PHY_CHANNEL];
+ fixed_queue_t* sign_op_queue;
+
+ uint16_t next_handle; /* next available handle */
+ uint16_t last_primary_s_handle; /* handle of last primary service */
+ tGATT_SVC_CHG gattp_attr; /* GATT profile attribute service change */
+ tGATT_IF gatt_if;
+ std::list<tGATT_HDL_LIST_ELEM>* hdl_list_info;
+ std::list<tGATT_SRV_LIST_ELEM>* srv_list_info;
+
+ fixed_queue_t* srv_chg_clt_q; /* service change clients queue */
+ tGATT_REG cl_rcb[GATT_MAX_APPS];
+ tGATT_CLCB clcb[GATT_CL_MAX_LCB]; /* connection link control block*/
+ tGATT_SCCB sccb[GATT_MAX_SCCB]; /* sign complete callback function
+ GATT_MAX_SCCB <= GATT_CL_MAX_LCB */
+ uint8_t trace_level;
+ uint16_t def_mtu_size;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+ bool enable_err_rsp;
+ uint8_t req_op_code;
+ uint8_t err_status;
+ uint16_t handle;
+#endif
+
+ tGATT_PROFILE_CLCB profile_clcb[GATT_MAX_APPS];
+ uint16_t
+ handle_of_h_r; /* Handle of the handles reused characteristic value */
+
+ tGATT_APPL_INFO cb_info;
+
+ tGATT_HDL_CFG hdl_cfg;
+ tGATT_BG_CONN_DEV bgconn_dev[GATT_MAX_BG_CONN_DEV];
+
+} tGATT_CB;
+
+#define GATT_SIZE_OF_SRV_CHG_HNDL_RANGE 4
+
+/* Global GATT data */
+extern tGATT_CB gatt_cb;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+extern void gatt_set_err_rsp(bool enable, uint8_t req_op_code,
+ uint8_t err_status);
+#endif
+
+/* from gatt_main.cc */
+extern bool gatt_disconnect(tGATT_TCB* p_tcb);
+extern bool gatt_act_connect(tGATT_REG* p_reg, BD_ADDR bd_addr,
+ tBT_TRANSPORT transport, bool opportunistic,
+ int8_t initiating_phys);
+extern bool gatt_connect(BD_ADDR rem_bda, tGATT_TCB* p_tcb,
+ tBT_TRANSPORT transport, uint8_t initiating_phys);
+extern void gatt_data_process(tGATT_TCB* p_tcb, BT_HDR* p_buf);
+extern void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
+ bool is_add, bool check_acl_link);
+
+extern void gatt_profile_db_init(void);
+extern void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state);
+extern tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb);
+extern void gatt_init_srv_chg(void);
+extern void gatt_proc_srv_chg(void);
+extern void gatt_send_srv_chg_ind(BD_ADDR peer_bda);
+extern void gatt_chk_srv_chg(tGATTS_SRV_CHG* p_srv_chg_clt);
+extern void gatt_add_a_bonded_dev_for_srv_chg(BD_ADDR bda);
+
+/* from gatt_attr.cc */
+extern uint16_t gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
+
+/* Functions provided by att_protocol.cc */
+extern tGATT_STATUS attp_send_cl_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+ uint8_t op_code, tGATT_CL_MSG* p_msg);
+extern BT_HDR* attp_build_sr_msg(tGATT_TCB* p_tcb, uint8_t op_code,
+ tGATT_SR_MSG* p_msg);
+extern tGATT_STATUS attp_send_sr_msg(tGATT_TCB* p_tcb, BT_HDR* p_msg);
+extern tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB* p_tcb, BT_HDR* p_toL2CAP);
+
+/* utility functions */
+extern uint8_t* gatt_dbg_op_name(uint8_t op_code);
+extern uint32_t gatt_add_sdp_record(tBT_UUID* p_uuid, uint16_t start_hdl,
+ uint16_t end_hdl);
+extern bool gatt_parse_uuid_from_cmd(tBT_UUID* p_uuid, uint16_t len,
+ uint8_t** p_data);
+extern uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, tBT_UUID uuid);
+extern bool gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
+extern void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint32_t uuid_32);
+extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport,
+ uint8_t* p_sec_flag, uint8_t* p_key_size);
+extern void gatt_start_rsp_timer(uint16_t clcb_idx);
+extern void gatt_start_conf_timer(tGATT_TCB* p_tcb);
+extern void gatt_rsp_timeout(void* data);
+extern void gatt_indication_confirmation_timeout(void* data);
+extern void gatt_ind_ack_timeout(void* data);
+extern void gatt_start_ind_ack_timer(tGATT_TCB* p_tcb);
+extern tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
+ uint8_t op_code, uint16_t handle,
+ bool deq);
+extern void gatt_dbg_display_uuid(tBT_UUID bt_uuid);
+extern tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(
+ tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb);
+
+extern bool gatt_is_srv_chg_ind_pending(tGATT_TCB* p_tcb);
+extern tGATTS_SRV_CHG* gatt_is_bda_in_the_srv_chg_clt_list(BD_ADDR bda);
+
+extern bool gatt_find_the_connected_bda(uint8_t start_idx, BD_ADDR bda,
+ uint8_t* p_found_idx,
+ tBT_TRANSPORT* p_transport);
+extern void gatt_set_srv_chg(void);
+extern void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr);
+extern tGATT_VALUE* gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind);
+extern void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id);
+extern bool gatt_cl_send_next_cmd_inq(tGATT_TCB* p_tcb);
+
+/* reserved handle list */
+extern std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
+ tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid, uint16_t svc_inst);
+extern tGATT_HDL_LIST_ELEM* gatt_find_hdl_buffer_by_handle(uint16_t handle);
+extern tGATTS_SRV_CHG* gatt_add_srv_chg_clt(tGATTS_SRV_CHG* p_srv_chg);
+
+/* for background connection */
+extern bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add,
+ BD_ADDR bd_addr);
+extern bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if);
+extern bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr);
+extern uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr);
+extern bool gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF* p_gatt_if);
+extern tGATT_BG_CONN_DEV* gatt_find_bg_dev(BD_ADDR remote_bda);
+extern void gatt_deregister_bgdev_list(tGATT_IF gatt_if);
+
+/* server function */
+extern std::list<tGATT_SRV_LIST_ELEM>::iterator gatt_sr_find_i_rcb_by_handle(
+ uint16_t handle);
+extern bool gatt_sr_find_i_rcb_by_app_id(tBT_UUID* p_app_uuid128,
+ tBT_UUID* p_svc_uuid,
+ uint16_t svc_inst);
+extern tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+ uint32_t trans_id, uint8_t op_code,
+ tGATT_STATUS status,
+ tGATTS_RSP* p_msg);
+extern void gatt_server_handle_client_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data);
+extern void gatt_sr_send_req_callback(uint16_t conn_id, uint32_t trans_id,
+ uint8_t op_code, tGATTS_DATA* p_req_data);
+extern uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t handle);
+extern bool gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda);
+extern void gatt_notify_phy_updated(tGATT_TCB* p_tcb, uint8_t tx_phy,
+ uint8_t rx_phy, uint8_t status);
+
+/* */
+
+extern tGATT_REG* gatt_get_regcb(tGATT_IF gatt_if);
+extern bool gatt_is_clcb_allocated(uint16_t conn_id);
+extern tGATT_CLCB* gatt_clcb_alloc(uint16_t conn_id);
+extern void gatt_clcb_dealloc(tGATT_CLCB* p_clcb);
+
+extern void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB* p_tcb);
+extern bool gatt_sr_is_cback_cnt_zero(tGATT_TCB* p_tcb);
+extern bool gatt_sr_is_prep_cnt_zero(tGATT_TCB* p_tcb);
+extern void gatt_sr_reset_cback_cnt(tGATT_TCB* p_tcb);
+extern void gatt_sr_reset_prep_cnt(tGATT_TCB* p_tcb);
+extern void gatt_sr_update_cback_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+ bool is_inc, bool is_reset_first);
+extern void gatt_sr_update_prep_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+ bool is_inc, bool is_reset_first);
+
+extern bool gatt_find_app_hold_link(tGATT_TCB* p_tcb, uint8_t start_idx,
+ uint8_t* p_found_idx, tGATT_IF* p_gatt_if);
+extern uint8_t gatt_num_apps_hold_link(tGATT_TCB* p_tcb);
+extern uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda);
+extern tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid);
+extern tGATT_TCB* gatt_allocate_tcb_by_bdaddr(BD_ADDR bda,
+ tBT_TRANSPORT transport);
+extern tGATT_TCB* gatt_get_tcb_by_idx(uint8_t tcb_idx);
+extern tGATT_TCB* gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport);
+extern bool gatt_send_ble_burst_data(BD_ADDR remote_bda, BT_HDR* p_buf);
+
+/* GATT client functions */
+extern void gatt_dequeue_sr_cmd(tGATT_TCB* p_tcb);
+extern uint8_t gatt_send_write_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+ uint8_t op_code, uint16_t handle,
+ uint16_t len, uint16_t offset,
+ uint8_t* p_data);
+extern void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason,
+ tBT_TRANSPORT transport);
+extern void gatt_end_operation(tGATT_CLCB* p_clcb, tGATT_STATUS status,
+ void* p_data);
+
+extern void gatt_act_discovery(tGATT_CLCB* p_clcb);
+extern void gatt_act_read(tGATT_CLCB* p_clcb, uint16_t offset);
+extern void gatt_act_write(tGATT_CLCB* p_clcb, uint8_t sec_act);
+extern uint8_t gatt_act_send_browse(tGATT_TCB* p_tcb, uint16_t index,
+ uint8_t op, uint16_t s_handle,
+ uint16_t e_handle, tBT_UUID uuid);
+extern tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB* p_tcb, uint8_t* p_opcode);
+extern bool gatt_cmd_enq(tGATT_TCB* p_tcb, uint16_t clcb_idx, bool to_send,
+ uint8_t op_code, BT_HDR* p_buf);
+extern void gatt_client_handle_server_rsp(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data);
+extern void gatt_send_queue_write_cancel(tGATT_TCB* p_tcb, tGATT_CLCB* p_clcb,
+ tGATT_EXEC_FLAG flag);
+
+/* gatt_auth.cc */
+extern bool gatt_security_check_start(tGATT_CLCB* p_clcb);
+extern void gatt_verify_signature(tGATT_TCB* p_tcb, BT_HDR* p_buf);
+extern tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB* p_clcb);
+extern tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB* p_tcb);
+extern tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB* p_tcb);
+extern void gatt_set_sec_act(tGATT_TCB* p_tcb, tGATT_SEC_ACTION sec_act);
+
+/* gatt_db.cc */
+extern void gatts_init_service_db(tGATT_SVC_DB& db, tBT_UUID* p_service,
+ bool is_pri, uint16_t s_hdl,
+ uint16_t num_handle);
+extern uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
+ uint16_t e_handle, tBT_UUID service);
+extern uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
+ tGATT_CHAR_PROP property,
+ tBT_UUID& char_uuid);
+extern uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
+ tBT_UUID& dscp_uuid);
+extern tGATT_STATUS gatts_db_read_attr_value_by_type(
+ tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, BT_HDR* p_rsp,
+ uint16_t s_handle, uint16_t e_handle, tBT_UUID type, uint16_t* p_len,
+ tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id,
+ uint16_t* p_cur_handle);
+extern tGATT_STATUS gatts_read_attr_value_by_handle(
+ tGATT_TCB* p_tcb, tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle,
+ uint16_t offset, uint8_t* p_value, uint16_t* p_len, uint16_t mtu,
+ tGATT_SEC_FLAG sec_flag, uint8_t key_size, uint32_t trans_id);
+extern tGATT_STATUS gatts_write_attr_perm_check(
+ tGATT_SVC_DB* p_db, uint8_t op_code, uint16_t handle, uint16_t offset,
+ uint8_t* p_data, uint16_t len, tGATT_SEC_FLAG sec_flag, uint8_t key_size);
+extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long,
+ uint16_t handle,
+ tGATT_SEC_FLAG sec_flag,
+ uint8_t key_size);
+extern tBT_UUID* gatts_get_service_uuid(tGATT_SVC_DB* p_db);
+
+#endif
diff --git a/mtkbt/code/bt/stack/gatt/gatt_main.cc b/mtkbt/code/bt/stack/gatt/gatt_main.cc
new file mode 100755
index 0000000..4d76811
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_main.cc
@@ -0,0 +1,1217 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main ATT functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include "bt_common.h"
+#include "bt_utils.h"
+#include "btif_storage.h"
+#include "btm_ble_int.h"
+#include "btm_int.h"
+#include "device/include/interop.h"
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+
+/* Configuration flags. */
+#define GATT_L2C_CFG_IND_DONE (1 << 0)
+#define GATT_L2C_CFG_CFM_DONE (1 << 1)
+
+/* minimum GATT MTU size over BR/EDR link
+*/
+#define GATT_MIN_BR_MTU_SIZE 48
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void gatt_le_connect_cback(uint16_t chan, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport);
+static void gatt_le_data_ind(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf);
+static void gatt_le_cong_cback(BD_ADDR remote_bda, bool congest);
+
+static void gatt_l2cif_connect_ind_cback(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ uint16_t psm, uint8_t l2cap_id);
+static void gatt_l2cif_connect_cfm_cback(uint16_t l2cap_cid, uint16_t result);
+static void gatt_l2cif_config_ind_cback(uint16_t l2cap_cid,
+ tL2CAP_CFG_INFO* p_cfg);
+static void gatt_l2cif_config_cfm_cback(uint16_t l2cap_cid,
+ tL2CAP_CFG_INFO* p_cfg);
+static void gatt_l2cif_disconnect_ind_cback(uint16_t l2cap_cid,
+ bool ack_needed);
+static void gatt_l2cif_disconnect_cfm_cback(uint16_t l2cap_cid,
+ uint16_t result);
+static void gatt_l2cif_data_ind_cback(uint16_t l2cap_cid, BT_HDR* p_msg);
+static void gatt_send_conn_cback(tGATT_TCB* p_tcb);
+static void gatt_l2cif_congest_cback(uint16_t cid, bool congested);
+
+static const tL2CAP_APPL_INFO dyn_info = {gatt_l2cif_connect_ind_cback,
+ gatt_l2cif_connect_cfm_cback,
+ NULL,
+ gatt_l2cif_config_ind_cback,
+ gatt_l2cif_config_cfm_cback,
+ gatt_l2cif_disconnect_ind_cback,
+ gatt_l2cif_disconnect_cfm_cback,
+ NULL,
+ gatt_l2cif_data_ind_cback,
+ gatt_l2cif_congest_cback,
+ NULL};
+
+tGATT_CB gatt_cb;
+
+/*******************************************************************************
+ *
+ * Function gatt_init
+ *
+ * Description This function is enable the GATT profile on the device.
+ * It clears out the control blocks, and registers with L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_init(void) {
+ tL2CAP_FIXED_CHNL_REG fixed_reg;
+
+ GATT_TRACE_DEBUG("gatt_init()");
+
+ memset(&gatt_cb, 0, sizeof(tGATT_CB));
+ memset(&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
+
+#if defined(GATT_INITIAL_TRACE_LEVEL)
+ gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
+#else
+ gatt_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
+ gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX);
+ gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX);
+ /* First, register fixed L2CAP channel for ATT over BLE */
+ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
+ fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
+ fixed_reg.fixed_chnl_opts.rtrans_tout = 2000;
+ fixed_reg.fixed_chnl_opts.mon_tout = 12000;
+ fixed_reg.fixed_chnl_opts.mps = 670;
+ fixed_reg.fixed_chnl_opts.tx_win_sz = 1;
+
+ fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
+ fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
+ fixed_reg.pL2CA_FixedCong_Cb = gatt_le_cong_cback; /* congestion callback */
+ fixed_reg.default_idle_tout = 0xffff; /* 0xffff default idle timeout */
+
+ L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
+
+ /* Now, register with L2CAP for ATT PSM over BR/EDR */
+ if (!L2CA_Register(BT_PSM_ATT, (tL2CAP_APPL_INFO*)&dyn_info)) {
+ GATT_TRACE_ERROR("ATT Dynamic Registration failed");
+ }
+
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT,
+ 0, 0);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT,
+ 0, 0);
+
+ gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
+ gatt_cb.hdl_cfg.gap_start_hdl = GATT_GAP_START_HANDLE;
+ gatt_cb.hdl_cfg.app_start_hdl = GATT_APP_START_HANDLE;
+
+ gatt_cb.hdl_list_info = new std::list<tGATT_HDL_LIST_ELEM>();
+ gatt_cb.srv_list_info = new std::list<tGATT_SRV_LIST_ELEM>();
+ gatt_profile_db_init();
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_free
+ *
+ * Description This function frees resources used by the GATT profile.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_free(void) {
+ int i;
+ GATT_TRACE_DEBUG("gatt_free()");
+
+ fixed_queue_free(gatt_cb.sign_op_queue, NULL);
+ gatt_cb.sign_op_queue = NULL;
+ fixed_queue_free(gatt_cb.srv_chg_clt_q, NULL);
+ gatt_cb.srv_chg_clt_q = NULL;
+ for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
+ fixed_queue_free(gatt_cb.tcb[i].pending_enc_clcb, NULL);
+ gatt_cb.tcb[i].pending_enc_clcb = NULL;
+
+ fixed_queue_free(gatt_cb.tcb[i].pending_ind_q, NULL);
+ gatt_cb.tcb[i].pending_ind_q = NULL;
+
+ alarm_free(gatt_cb.tcb[i].conf_timer);
+ gatt_cb.tcb[i].conf_timer = NULL;
+
+ alarm_free(gatt_cb.tcb[i].ind_ack_timer);
+ gatt_cb.tcb[i].ind_ack_timer = NULL;
+
+ fixed_queue_free(gatt_cb.tcb[i].sr_cmd.multi_rsp_q, NULL);
+ gatt_cb.tcb[i].sr_cmd.multi_rsp_q = NULL;
+ }
+
+ gatt_cb.hdl_list_info->clear();
+ gatt_cb.hdl_list_info = nullptr;
+ gatt_cb.srv_list_info->clear();
+ gatt_cb.srv_list_info = nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_connect
+ *
+ * Description This function is called to initiate a connection to a peer
+ * device.
+ *
+ * Parameter rem_bda: remote device address to connect to.
+ *
+ * Returns true if connection is started, otherwise return false.
+ *
+ ******************************************************************************/
+bool gatt_connect(BD_ADDR rem_bda, tGATT_TCB* p_tcb, tBT_TRANSPORT transport,
+ uint8_t initiating_phys) {
+ bool gatt_ret = false;
+
+ if (gatt_get_ch_state(p_tcb) != GATT_CH_OPEN)
+ gatt_set_ch_state(p_tcb, GATT_CH_CONN);
+
+ if (transport == BT_TRANSPORT_LE) {
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+ gatt_ret = L2CA_ConnectFixedChnl(L2CAP_ATT_CID, rem_bda, initiating_phys);
+ } else {
+ p_tcb->att_lcid = L2CA_ConnectReq(BT_PSM_ATT, rem_bda);
+ if (p_tcb->att_lcid != 0) gatt_ret = true;
+ }
+
+ return gatt_ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_disconnect
+ *
+ * Description This function is called to disconnect to an ATT device.
+ *
+ * Parameter p_tcb: pointer to the TCB to disconnect.
+ *
+ * Returns true: if connection found and to be disconnected; otherwise
+ * return false.
+ *
+ ******************************************************************************/
+bool gatt_disconnect(tGATT_TCB* p_tcb) {
+ bool ret = false;
+ tGATT_CH_STATE ch_state;
+
+ GATT_TRACE_EVENT("%s", __func__);
+
+ if (p_tcb != NULL) {
+ ret = true;
+ ch_state = gatt_get_ch_state(p_tcb);
+ if (ch_state != GATT_CH_CLOSING) {
+ if (p_tcb->att_lcid == L2CAP_ATT_CID) {
+ if (ch_state == GATT_CH_OPEN) {
+ /* only LCB exist between remote device and local */
+ ret = L2CA_RemoveFixedChnl(L2CAP_ATT_CID, p_tcb->peer_bda);
+ } else {
+ ret = L2CA_CancelBleConnectReq(p_tcb->peer_bda);
+ if (!ret) gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
+ }
+ gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
+ } else {
+ if ((ch_state == GATT_CH_OPEN) || (ch_state == GATT_CH_CFG))
+ ret = L2CA_DisconnectReq(p_tcb->att_lcid);
+ else
+ GATT_TRACE_DEBUG("%s gatt_disconnect channel not opened", __func__);
+ }
+ } else {
+ GATT_TRACE_DEBUG("%s already in closing state", __func__);
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_update_app_hold_link_status
+ *
+ * Description Update the application use link status
+ *
+ * Returns true if any modifications are made or
+ * when it already exists, false otherwise.
+ *
+ ******************************************************************************/
+bool gatt_update_app_hold_link_status(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
+ bool is_add) {
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->app_hold_link[i] == gatt_if && is_add) {
+ GATT_TRACE_DEBUG("%s: gatt_if %d already exists at idx %d", __func__,
+ gatt_if, i);
+ return true;
+ }
+ }
+
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->app_hold_link[i] == 0 && is_add) {
+ p_tcb->app_hold_link[i] = gatt_if;
+ GATT_TRACE_DEBUG("%s: added gatt_if=%d idx=%d ", __func__, gatt_if, i);
+ return true;
+ } else if (p_tcb->app_hold_link[i] == gatt_if && !is_add) {
+ p_tcb->app_hold_link[i] = 0;
+ GATT_TRACE_DEBUG("%s: removed gatt_if=%d idx=%d", __func__, gatt_if, i);
+ return true;
+ }
+ }
+
+ GATT_TRACE_DEBUG("%s: gatt_if=%d not found; is_add=%d", __func__, gatt_if,
+ is_add);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_update_app_use_link_flag
+ *
+ * Description Update the application use link flag and optional to check
+ * the acl link if the link is up then set the idle time out
+ * accordingly
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void gatt_update_app_use_link_flag(tGATT_IF gatt_if, tGATT_TCB* p_tcb,
+ bool is_add, bool check_acl_link) {
+ GATT_TRACE_DEBUG("%s: is_add=%d chk_link=%d", __func__, is_add,
+ check_acl_link);
+
+ if (!p_tcb) return;
+
+ // If we make no modification, i.e. kill app that was never connected to a
+ // device, skip updating the device state.
+ if (!gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add)) return;
+
+ if (!check_acl_link ||
+ p_tcb->att_lcid !=
+ L2CAP_ATT_CID || /* only update link idle timer for fixed channel */
+ (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) ==
+ GATT_INVALID_ACL_HANDLE)) {
+ /** M: Bug fix for the case of GATT over BREDR, we need to disconnect
+ * dynamic L2cap channel first @{ */
+ if (check_acl_link && p_tcb->transport == BT_TRANSPORT_BR_EDR &&
+ (BTM_GetHCIConnHandle(p_tcb->peer_bda, p_tcb->transport) !=
+ GATT_INVALID_ACL_HANDLE)) {
+ if (!is_add && !gatt_num_apps_hold_link(p_tcb))
+ gatt_disconnect(p_tcb);
+ }
+ /** @} */
+
+ return;
+ }
+
+ if (is_add) {
+ GATT_TRACE_DEBUG("%s: disable link idle timer", __func__);
+ /* acl link is connected disable the idle timeout */
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
+ p_tcb->transport);
+ } else {
+ if (!gatt_num_apps_hold_link(p_tcb)) {
+ /* acl link is connected but no application needs to use the link
+ so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds
+ */
+ GATT_TRACE_DEBUG("%s: start link idle timer =%d sec", __func__,
+ GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
+ p_tcb->transport);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_act_connect
+ *
+ * Description GATT connection initiation.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+bool gatt_act_connect(tGATT_REG* p_reg, BD_ADDR bd_addr,
+ tBT_TRANSPORT transport, bool opportunistic,
+ int8_t initiating_phys) {
+ bool ret = false;
+ tGATT_TCB* p_tcb;
+ uint8_t st;
+
+ p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ if (p_tcb != NULL) {
+ ret = true;
+ st = gatt_get_ch_state(p_tcb);
+
+ /* before link down, another app try to open a GATT connection */
+ if (st == GATT_CH_OPEN && gatt_num_apps_hold_link(p_tcb) == 0 &&
+ transport == BT_TRANSPORT_LE) {
+ if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys))
+ ret = false;
+
+ /** M: Bug fix for the connection procedure while link is disconnecting @{ */
+ if (L2CA_IsFixedChnlPending(L2CAP_ATT_CID, bd_addr))
+ gatt_set_ch_state(p_tcb, GATT_CH_CONN);
+ /** @} */
+ } else if (st == GATT_CH_CLOSING) {
+ /* need to complete the closing first */
+ ret = false;
+ }
+ } else {
+ p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, transport);
+ if (p_tcb != NULL) {
+ if (!gatt_connect(bd_addr, p_tcb, transport, initiating_phys)) {
+ GATT_TRACE_ERROR("gatt_connect failed");
+ fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
+ fixed_queue_free(p_tcb->pending_ind_q, NULL);
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+ } else
+ ret = true;
+ } else {
+ ret = 0;
+ GATT_TRACE_ERROR("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
+ }
+ }
+
+ if (ret) {
+ if (!opportunistic)
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, false);
+ else
+ GATT_TRACE_DEBUG(
+ "%s: connection is opportunistic, not updating app usage", __func__);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_le_connect_cback
+ *
+ * Description This callback function is called by L2CAP to indicate that
+ * the ATT fixed channel for LE is
+ * connected (conn = true)/disconnected (conn = false).
+ *
+ ******************************************************************************/
+static void gatt_le_connect_cback(uint16_t chan, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
+ bool check_srv_chg = false;
+ tGATTS_SRV_CHG* p_srv_chg_clt = NULL;
+
+ /* ignore all fixed channel connect/disconnect on BR/EDR link for GATT */
+ if (transport == BT_TRANSPORT_BR_EDR) return;
+
+ GATT_TRACE_DEBUG(
+ "GATT ATT protocol channel with BDA: %08x%04x is %s",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5],
+ (connected) ? "connected" : "disconnected");
+
+ p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr);
+ if (p_srv_chg_clt != NULL) {
+ check_srv_chg = true;
+ /** M: Feature change, the Characteristic value shall be configured to be
+ * indicated. Vol.3, part G, 7.1 @{ */
+ /*
+ } else {
+ if (btm_sec_is_a_bonded_dev(bd_addr))
+ gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
+ */
+ /** @} */
+ }
+
+ if (connected) {
+ /* do we have a channel initiating a connection? */
+ if (p_tcb) {
+ /* we are initiating connection */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
+ /* send callback */
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+ gatt_send_conn_cback(p_tcb);
+ }
+ if (check_srv_chg) gatt_chk_srv_chg(p_srv_chg_clt);
+ }
+ /* this is incoming connection or background connection callback */
+
+ else {
+ p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_LE);
+ if (p_tcb != NULL) {
+ p_tcb->att_lcid = L2CAP_ATT_CID;
+
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+
+ gatt_send_conn_cback(p_tcb);
+ if (check_srv_chg) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ }
+ } else {
+ GATT_TRACE_ERROR("CCB max out, no rsources");
+ }
+ }
+ } else {
+ gatt_cleanup_upon_disc(bd_addr, reason, transport);
+ GATT_TRACE_DEBUG("ATT disconnected");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_channel_congestion
+ *
+ * Description This function is called to process the congestion callback
+ * from lcb
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_channel_congestion(tGATT_TCB* p_tcb, bool congested) {
+ uint8_t i = 0;
+ tGATT_REG* p_reg = NULL;
+ uint16_t conn_id;
+
+ /* if uncongested, check to see if there is any more pending data */
+ if (p_tcb != NULL && congested == false) {
+ gatt_cl_send_next_cmd_inq(p_tcb);
+ }
+ /* notifying all applications for the connection up event */
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use) {
+ if (p_reg->app_cb.p_congestion_cb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_congestion_cb)(conn_id, congested);
+ }
+ }
+ }
+}
+
+void gatt_notify_phy_updated(tGATT_TCB* p_tcb, uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status) {
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
+ if (p_reg->in_use && p_reg->app_cb.p_phy_update_cb) {
+ uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_phy_update_cb)(p_reg->gatt_if, conn_id, tx_phy, rx_phy,
+ status);
+ }
+ }
+}
+
+void gatt_notify_conn_update(uint16_t handle, uint16_t interval,
+ uint16_t latency, uint16_t timeout,
+ uint8_t status) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
+ if (!p_dev_rec) {
+ return;
+ }
+
+ tGATT_TCB* p_tcb =
+ gatt_find_tcb_by_addr(p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+ if (p_tcb == NULL) return;
+
+ for (int i = 0; i < GATT_MAX_APPS; i++) {
+ tGATT_REG* p_reg = &gatt_cb.cl_rcb[i];
+ if (p_reg->in_use && p_reg->app_cb.p_conn_update_cb) {
+ uint16_t conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_conn_update_cb)(p_reg->gatt_if, conn_id, interval,
+ latency, timeout, status);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_le_cong_cback
+ *
+ * Description This function is called when GATT fixed channel is congested
+ * or uncongested.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_le_cong_cback(BD_ADDR remote_bda, bool congested) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE);
+
+ /* if uncongested, check to see if there is any more pending data */
+ if (p_tcb != NULL) {
+ gatt_channel_congestion(p_tcb, congested);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_le_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ * if we are the originator of the connection, we are the ATT
+ * client, and the received message is queued up for the
+ * client.
+ *
+ * If we are the destination of the connection, we are the ATT
+ * server, so the message is passed to the server processing
+ * function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_le_data_ind(uint16_t chan, BD_ADDR bd_addr, BT_HDR* p_buf) {
+ tGATT_TCB* p_tcb;
+
+ /* Find CCB based on bd addr */
+ if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL &&
+ gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN) {
+ gatt_data_process(p_tcb, p_buf);
+ } else {
+ osi_free(p_buf);
+
+ if (p_tcb != NULL) {
+ GATT_TRACE_WARNING("ATT - Ignored L2CAP data while in state: %d",
+ gatt_get_ch_state(p_tcb));
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_connect_ind
+ *
+ * Description This function handles an inbound connection indication
+ * from L2CAP. This is the case where we are acting as a
+ * server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_l2cif_connect_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ UNUSED_ATTR uint16_t psm, uint8_t id) {
+ /* do we already have a control channel for this peer? */
+ uint8_t result = L2CAP_CONN_OK;
+ tL2CAP_CFG_INFO cfg;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ GATT_TRACE_ERROR("Connection indication cid = %d", lcid);
+ /* new connection ? */
+ if (p_tcb == NULL) {
+ /* allocate tcb */
+ p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_tcb == NULL) {
+ /* no tcb available, reject L2CAP connection */
+ result = L2CAP_CONN_NO_RESOURCES;
+ } else
+ p_tcb->att_lcid = lcid;
+
+ } else /* existing connection , reject it */
+ {
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK) {
+ /* transition to configuration state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2c_connect_cfm_cback
+ *
+ * Description This is the L2CAP connect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_l2cif_connect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tGATT_TCB* p_tcb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* look up clcb for this channel */
+ p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb != NULL) {
+ GATT_TRACE_DEBUG(
+ "gatt_l2c_connect_cfm_cback result: %d ch_state: %d, lcid:0x%x", result,
+ gatt_get_ch_state(p_tcb), p_tcb->att_lcid);
+
+ /* if in correct state */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CONN) {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK) {
+ /* set channel state */
+ gatt_set_ch_state(p_tcb, GATT_CH_CFG);
+
+ /* Send L2CAP config req */
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ cfg.mtu_present = true;
+ cfg.mtu = GATT_MAX_MTU_SIZE;
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+ /* else initiating connection failure */
+ else {
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, result, GATT_TRANSPORT_BR_EDR);
+ }
+ } else /* wrong state, disconnect it */
+ {
+ if (result == L2CAP_CONN_OK) {
+ /* just in case the peer also accepts our connection - Send L2CAP
+ * disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_config_cfm_cback
+ *
+ * Description This is the L2CAP config confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_l2cif_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tGATT_TCB* p_tcb;
+ tGATTS_SRV_CHG* p_srv_chg_clt = NULL;
+
+ /* look up clcb for this channel */
+ p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb != NULL) {
+ /* if in correct state */
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_CFG) {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) {
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+
+ p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ if (p_srv_chg_clt != NULL) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ } else {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send callback */
+ gatt_send_conn_cback(p_tcb);
+ }
+ }
+ /* else failure */
+ else {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_config_ind_cback
+ *
+ * Description This is the L2CAP config indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_l2cif_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tGATT_TCB* p_tcb;
+ tGATTS_SRV_CHG* p_srv_chg_clt = NULL;
+ /* look up clcb for this channel */
+ p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb != NULL) {
+ /* GATT uses the smaller of our MTU and peer's MTU */
+ if (p_cfg->mtu_present &&
+ (p_cfg->mtu >= GATT_MIN_BR_MTU_SIZE && p_cfg->mtu < L2CAP_DEFAULT_MTU))
+ p_tcb->payload_size = p_cfg->mtu;
+ else
+ p_tcb->payload_size = L2CAP_DEFAULT_MTU;
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = L2CAP_CFG_OK;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tcb->ch_flags & GATT_L2C_CFG_IND_DONE) == 0) {
+ /* update flags */
+ p_tcb->ch_flags |= GATT_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tcb->ch_flags & GATT_L2C_CFG_CFM_DONE) {
+ gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
+ p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ if (p_srv_chg_clt != NULL) {
+ gatt_chk_srv_chg(p_srv_chg_clt);
+ } else {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send callback */
+ gatt_send_conn_cback(p_tcb);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_disconnect_ind_cback
+ *
+ * Description This is the L2CAP disconnect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_l2cif_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
+ tGATT_TCB* p_tcb;
+ uint16_t reason;
+
+ /* look up clcb for this channel */
+ p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb != NULL) {
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+ if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from
+ * peer */
+ reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
+ if (reason == 0) reason = GATT_CONN_TERMINATE_PEER_USER;
+
+ /* send disconnect callback */
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_disconnect_cfm_cback
+ *
+ * Description This is the L2CAP disconnect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_l2cif_disconnect_cfm_cback(uint16_t lcid,
+ UNUSED_ATTR uint16_t result) {
+ tGATT_TCB* p_tcb;
+ uint16_t reason;
+
+ /* look up clcb for this channel */
+ p_tcb = gatt_find_tcb_by_cid(lcid);
+ if (p_tcb != NULL) {
+ /* If the device is not in the service changed client list, add it... */
+ if (gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda) == NULL) {
+ if (btm_sec_is_a_bonded_dev(p_tcb->peer_bda))
+ gatt_add_a_bonded_dev_for_srv_chg(p_tcb->peer_bda);
+ }
+
+ /* send disconnect callback */
+ /* if ACL link is still up, no reason is logged, l2cap is disconnect from
+ * peer */
+ reason = L2CA_GetDisconnectReason(p_tcb->peer_bda, p_tcb->transport);
+ if (reason == 0) reason = GATT_CONN_TERMINATE_LOCAL_HOST;
+
+ gatt_cleanup_upon_disc(p_tcb->peer_bda, reason, GATT_TRANSPORT_BR_EDR);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_data_ind_cback
+ *
+ * Description This is the L2CAP data indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_l2cif_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
+ tGATT_TCB* p_tcb;
+
+ /* look up clcb for this channel */
+ if ((p_tcb = gatt_find_tcb_by_cid(lcid)) != NULL &&
+ gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
+ /* process the data */
+ gatt_data_process(p_tcb, p_buf);
+ } else /* prevent buffer leak */
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_l2cif_congest_cback
+ *
+ * Description L2CAP congestion callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_l2cif_congest_cback(uint16_t lcid, bool congested) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_cid(lcid);
+
+ if (p_tcb != NULL) {
+ gatt_channel_congestion(p_tcb, congested);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_send_conn_cback
+ *
+ * Description Callback used to notify layer above about a connection.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatt_send_conn_cback(tGATT_TCB* p_tcb) {
+ uint8_t i;
+ tGATT_REG* p_reg;
+ tGATT_BG_CONN_DEV* p_bg_dev = NULL;
+ uint16_t conn_id;
+
+ p_bg_dev = gatt_find_bg_dev(p_tcb->peer_bda);
+
+ /* notifying all applications for the connection up event */
+ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) {
+ if (p_reg->in_use) {
+ if (p_bg_dev && gatt_is_bg_dev_for_app(p_bg_dev, p_reg->gatt_if))
+ gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, true);
+
+ if (p_reg->app_cb.p_conn_cb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, p_tcb->peer_bda, conn_id,
+ true, 0, p_tcb->transport);
+ }
+ }
+ }
+
+ if (gatt_num_apps_hold_link(p_tcb) && p_tcb->att_lcid == L2CAP_ATT_CID) {
+ /* disable idle timeout if one or more clients are holding the link disable
+ * the idle timer */
+ GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT,
+ p_tcb->transport);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_le_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ * if we are the originator of the connection, we are the ATT
+ * client, and the received message is queued up for the
+ * client.
+ *
+ * If we are the destination of the connection, we are the ATT
+ * server, so the message is passed to the server processing
+ * function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_data_process(tGATT_TCB* p_tcb, BT_HDR* p_buf) {
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint8_t op_code, pseudo_op_code;
+ uint16_t msg_len;
+
+ if (p_buf->len > 0) {
+ msg_len = p_buf->len - 1;
+ STREAM_TO_UINT8(op_code, p);
+
+ /* remove the two MSBs associated with sign write and write cmd */
+ pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);
+
+ if (pseudo_op_code < GATT_OP_CODE_MAX) {
+ if (op_code == GATT_SIGN_CMD_WRITE) {
+ gatt_verify_signature(p_tcb, p_buf);
+ } else {
+ /* message from client */
+ if ((op_code % 2) == 0)
+ gatt_server_handle_client_req(p_tcb, op_code, msg_len, p);
+ else
+ gatt_client_handle_server_rsp(p_tcb, op_code, msg_len, p);
+ }
+ } else {
+ GATT_TRACE_ERROR("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
+ }
+ } else {
+ GATT_TRACE_ERROR("invalid data length, ignore");
+ }
+
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_a_bonded_dev_for_srv_chg
+ *
+ * Description Add a bonded dev to the service changed client list
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_add_a_bonded_dev_for_srv_chg(BD_ADDR bda) {
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG srv_chg_clt;
+
+ memcpy(srv_chg_clt.bda, bda, BD_ADDR_LEN);
+ srv_chg_clt.srv_changed = false;
+ if (gatt_add_srv_chg_clt(&srv_chg_clt) != NULL) {
+ memcpy(req.srv_chg.bda, bda, BD_ADDR_LEN);
+ req.srv_chg.srv_changed = false;
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_ADD_CLIENT, &req,
+ NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_send_srv_chg_ind
+ *
+ * Description This function is called to send a service chnaged indication
+ * to the specified bd address
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_send_srv_chg_ind(BD_ADDR peer_bda) {
+ uint8_t handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
+ uint8_t* p = handle_range;
+ uint16_t conn_id;
+
+ GATT_TRACE_DEBUG("gatt_send_srv_chg_ind");
+
+ if (gatt_cb.handle_of_h_r) {
+ conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda);
+ if (conn_id != GATT_INVALID_CONN_ID) {
+ UINT16_TO_STREAM(p, 1);
+ UINT16_TO_STREAM(p, 0xFFFF);
+ GATTS_HandleValueIndication(conn_id, gatt_cb.handle_of_h_r,
+ GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
+ handle_range);
+ } else {
+ GATT_TRACE_ERROR("Unable to find conn_id for %08x%04x ",
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) +
+ (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5]);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_chk_srv_chg
+ *
+ * Description Check sending service chnaged Indication is required or not
+ * if required then send the Indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_chk_srv_chg(tGATTS_SRV_CHG* p_srv_chg_clt) {
+ GATT_TRACE_DEBUG("gatt_chk_srv_chg srv_changed=%d",
+ p_srv_chg_clt->srv_changed);
+
+ if (p_srv_chg_clt->srv_changed) {
+ gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_init_srv_chg
+ *
+ * Description This function is used to initialize the service changed
+ * attribute value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_init_srv_chg(void) {
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG_RSP rsp;
+ bool status;
+ uint8_t num_clients, i;
+ tGATTS_SRV_CHG srv_chg_clt;
+
+ GATT_TRACE_DEBUG("gatt_init_srv_chg");
+ if (gatt_cb.cb_info.p_srv_chg_callback) {
+ status = (*gatt_cb.cb_info.p_srv_chg_callback)(
+ GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);
+
+ if (status && rsp.num_clients) {
+ GATT_TRACE_DEBUG("gatt_init_srv_chg num_srv_chg_clt_clients=%d",
+ rsp.num_clients);
+ num_clients = rsp.num_clients;
+ i = 1; /* use one based index */
+ while ((i <= num_clients) && status) {
+ req.client_read_index = i;
+ status = (*gatt_cb.cb_info.p_srv_chg_callback)(
+ GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp);
+ if (status == true) {
+ memcpy(&srv_chg_clt, &rsp.srv_chg, sizeof(tGATTS_SRV_CHG));
+ if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL) {
+ GATT_TRACE_ERROR("Unable to add a service change client");
+ status = false;
+ }
+ }
+ i++;
+ }
+ }
+ } else {
+ GATT_TRACE_DEBUG("gatt_init_srv_chg callback not registered yet");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_proc_srv_chg
+ *
+ * Description This function is process the service changed request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_proc_srv_chg(void) {
+ uint8_t start_idx, found_idx;
+ BD_ADDR bda;
+ tGATT_TCB* p_tcb;
+ tBT_TRANSPORT transport;
+
+ GATT_TRACE_DEBUG("gatt_proc_srv_chg");
+
+ if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r) {
+ gatt_set_srv_chg();
+ start_idx = 0;
+ while (
+ gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
+ p_tcb = &gatt_cb.tcb[found_idx];
+
+ bool send_indication = true;
+
+ /** M: Feature change, only send indication to clients configured
+ * indication @{ */
+ if (NULL == gatt_is_bda_in_the_srv_chg_clt_list(bda)) {
+ send_indication = false;
+ }
+ /** @} */
+
+ if (gatt_is_srv_chg_ind_pending(p_tcb)) {
+ send_indication = false;
+ GATT_TRACE_DEBUG("discard srv chg - already has one in the queue");
+ }
+
+ // Some LE GATT clients don't respond to service changed indications.
+ char remote_name[BTM_MAX_REM_BD_NAME_LEN] = "";
+ bt_bdaddr_t bd_addr;
+ for (int i = 0; i < 6; i++) bd_addr.address[i] = bda[i];
+ if (send_indication &&
+ btif_storage_get_stored_remote_name(bd_addr, remote_name)) {
+ if (interop_match_name(INTEROP_GATTC_NO_SERVICE_CHANGED_IND,
+ remote_name)) {
+ GATT_TRACE_DEBUG("discard srv chg - interop matched %s", remote_name);
+ send_indication = false;
+ }
+ }
+
+ if (send_indication) gatt_send_srv_chg_ind(bda);
+
+ start_idx = ++found_idx;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_set_ch_state
+ *
+ * Description This function set the ch_state in tcb
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void gatt_set_ch_state(tGATT_TCB* p_tcb, tGATT_CH_STATE ch_state) {
+ if (p_tcb) {
+ GATT_TRACE_DEBUG("gatt_set_ch_state: old=%d new=%d", p_tcb->ch_state,
+ ch_state);
+ p_tcb->ch_state = ch_state;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_get_ch_state
+ *
+ * Description This function get the ch_state in tcb
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+tGATT_CH_STATE gatt_get_ch_state(tGATT_TCB* p_tcb) {
+ tGATT_CH_STATE ch_state = GATT_CH_CLOSE;
+ if (p_tcb) {
+ GATT_TRACE_DEBUG("gatt_get_ch_state: ch_state=%d", p_tcb->ch_state);
+ ch_state = p_tcb->ch_state;
+ }
+ return ch_state;
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_sr.cc b/mtkbt/code/bt/stack/gatt/gatt_sr.cc
new file mode 100755
index 0000000..a999193
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_sr.cc
@@ -0,0 +1,1268 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the GATT server functions
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#include <string.h>
+#include "gatt_int.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#define GATT_MTU_REQ_MIN_LEN 2
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_enqueue_cmd
+ *
+ * Description This function enqueue the request from client which needs a
+ * application response, and update the transaction ID.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint32_t gatt_sr_enqueue_cmd(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t handle) {
+ tGATT_SR_CMD* p_cmd = &p_tcb->sr_cmd;
+ uint32_t trans_id = 0;
+
+ if ((p_cmd->op_code == 0) ||
+ (op_code == GATT_HANDLE_VALUE_CONF)) /* no pending request */
+ {
+ if (op_code == GATT_CMD_WRITE || op_code == GATT_SIGN_CMD_WRITE ||
+ op_code == GATT_REQ_MTU || op_code == GATT_HANDLE_VALUE_CONF) {
+ trans_id = ++p_tcb->trans_id;
+ } else {
+ p_cmd->trans_id = ++p_tcb->trans_id;
+ p_cmd->op_code = op_code;
+ p_cmd->handle = handle;
+ p_cmd->status = GATT_NOT_FOUND;
+ p_tcb->trans_id %= GATT_TRANS_ID_MAX;
+ trans_id = p_cmd->trans_id;
+ }
+ }
+
+ return trans_id;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_cmd_empty
+ *
+ * Description This function checks if the server command queue is empty.
+ *
+ * Returns true if empty, false if there is pending command.
+ *
+ ******************************************************************************/
+bool gatt_sr_cmd_empty(tGATT_TCB* p_tcb) {
+ return (p_tcb->sr_cmd.op_code == 0);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_dequeue_sr_cmd
+ *
+ * Description This function dequeue the request from command queue.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_dequeue_sr_cmd(tGATT_TCB* p_tcb) {
+ /* Double check in case any buffers are queued */
+ GATT_TRACE_DEBUG("gatt_dequeue_sr_cmd");
+ if (p_tcb->sr_cmd.p_rsp_msg)
+ GATT_TRACE_ERROR("free p_tcb->sr_cmd.p_rsp_msg = %d",
+ p_tcb->sr_cmd.p_rsp_msg);
+ osi_free_and_reset((void**)&p_tcb->sr_cmd.p_rsp_msg);
+
+ while (!fixed_queue_is_empty(p_tcb->sr_cmd.multi_rsp_q))
+ osi_free(fixed_queue_try_dequeue(p_tcb->sr_cmd.multi_rsp_q));
+ fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
+ memset(&p_tcb->sr_cmd, 0, sizeof(tGATT_SR_CMD));
+}
+
+/*******************************************************************************
+ *
+ * Function process_read_multi_rsp
+ *
+ * Description This function check the read multiple response.
+ *
+ * Returns bool if all replies have been received
+ *
+ ******************************************************************************/
+static bool process_read_multi_rsp(tGATT_SR_CMD* p_cmd, tGATT_STATUS status,
+ tGATTS_RSP* p_msg, uint16_t mtu) {
+ uint16_t ii, total_len, len;
+ uint8_t* p;
+ bool is_overflow = false;
+
+ GATT_TRACE_DEBUG("%s status=%d mtu=%d", __func__, status, mtu);
+
+ if (p_cmd->multi_rsp_q == NULL)
+ p_cmd->multi_rsp_q = fixed_queue_new(SIZE_MAX);
+
+ /* Enqueue the response */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(tGATTS_RSP));
+ memcpy((void*)p_buf, (const void*)p_msg, sizeof(tGATTS_RSP));
+ fixed_queue_enqueue(p_cmd->multi_rsp_q, p_buf);
+
+ p_cmd->status = status;
+ if (status == GATT_SUCCESS) {
+ GATT_TRACE_DEBUG("Multi read count=%d num_hdls=%d",
+ fixed_queue_length(p_cmd->multi_rsp_q),
+ p_cmd->multi_req.num_handles);
+ /* Wait till we get all the responses */
+ if (fixed_queue_length(p_cmd->multi_rsp_q) ==
+ p_cmd->multi_req.num_handles) {
+ len = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + mtu;
+ p_buf = (BT_HDR*)osi_calloc(len);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* First byte in the response is the opcode */
+ *p++ = GATT_RSP_READ_MULTI;
+ p_buf->len = 1;
+
+ /* Now walk through the buffers puting the data into the response in order
+ */
+ list_t* list = NULL;
+ const list_node_t* node = NULL;
+ if (!fixed_queue_is_empty(p_cmd->multi_rsp_q))
+ list = fixed_queue_get_list(p_cmd->multi_rsp_q);
+ for (ii = 0; ii < p_cmd->multi_req.num_handles; ii++) {
+ tGATTS_RSP* p_rsp = NULL;
+
+ if (list != NULL) {
+ if (ii == 0)
+ node = list_begin(list);
+ else
+ node = list_next(node);
+ if (node != list_end(list)) p_rsp = (tGATTS_RSP*)list_node(node);
+ }
+
+ if (p_rsp != NULL) {
+ total_len = (p_buf->len + p_rsp->attr_value.len);
+
+ if (total_len > mtu) {
+ /* just send the partial response for the overflow case */
+ len = p_rsp->attr_value.len - (total_len - mtu);
+ is_overflow = true;
+ GATT_TRACE_DEBUG("multi read overflow available len=%d val_len=%d",
+ len, p_rsp->attr_value.len);
+ } else {
+ len = p_rsp->attr_value.len;
+ }
+
+ if (p_rsp->attr_value.handle == p_cmd->multi_req.handles[ii]) {
+ memcpy(p, p_rsp->attr_value.value, len);
+ if (!is_overflow) p += len;
+ p_buf->len += len;
+ } else {
+ p_cmd->status = GATT_NOT_FOUND;
+ break;
+ }
+
+ if (is_overflow) break;
+
+ } else {
+ p_cmd->status = GATT_NOT_FOUND;
+ break;
+ }
+
+ } /* loop through all handles*/
+
+ /* Sanity check on the buffer length */
+ if (p_buf->len == 0) {
+ GATT_TRACE_ERROR("process_read_multi_rsp - nothing found!!");
+ p_cmd->status = GATT_NOT_FOUND;
+ osi_free(p_buf);
+ GATT_TRACE_DEBUG("osi_free(p_buf)");
+ } else if (p_cmd->p_rsp_msg != NULL) {
+ osi_free(p_buf);
+ } else {
+ p_cmd->p_rsp_msg = p_buf;
+ }
+
+ return (true);
+ }
+ } else /* any handle read exception occurs, return error */
+ {
+ return (true);
+ }
+
+ /* If here, still waiting */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_process_app_rsp
+ *
+ * Description This function checks whether the response message from
+ * application matches any pending request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tGATT_STATUS gatt_sr_process_app_rsp(tGATT_TCB* p_tcb, tGATT_IF gatt_if,
+ UNUSED_ATTR uint32_t trans_id,
+ uint8_t op_code, tGATT_STATUS status,
+ tGATTS_RSP* p_msg) {
+ tGATT_STATUS ret_code = GATT_SUCCESS;
+
+ GATT_TRACE_DEBUG("gatt_sr_process_app_rsp gatt_if=%d", gatt_if);
+
+ gatt_sr_update_cback_cnt(p_tcb, gatt_if, false, false);
+
+ if (op_code == GATT_REQ_READ_MULTI) {
+ /* If no error and still waiting, just return */
+ if (!process_read_multi_rsp(&p_tcb->sr_cmd, status, p_msg,
+ p_tcb->payload_size))
+ return (GATT_SUCCESS);
+ } else {
+ if (op_code == GATT_REQ_PREPARE_WRITE && status == GATT_SUCCESS)
+ gatt_sr_update_prep_cnt(p_tcb, gatt_if, true, false);
+
+ if (op_code == GATT_REQ_EXEC_WRITE && status != GATT_SUCCESS)
+ gatt_sr_reset_cback_cnt(p_tcb);
+
+ p_tcb->sr_cmd.status = status;
+
+ if (gatt_sr_is_cback_cnt_zero(p_tcb) && status == GATT_SUCCESS) {
+ if (p_tcb->sr_cmd.p_rsp_msg == NULL) {
+ p_tcb->sr_cmd.p_rsp_msg = attp_build_sr_msg(
+ p_tcb, (uint8_t)(op_code + 1), (tGATT_SR_MSG*)p_msg);
+ } else {
+ GATT_TRACE_ERROR("Exception!!! already has respond message");
+ }
+ }
+ }
+ if (gatt_sr_is_cback_cnt_zero(p_tcb)) {
+ if ((p_tcb->sr_cmd.status == GATT_SUCCESS) && (p_tcb->sr_cmd.p_rsp_msg)) {
+ ret_code = attp_send_sr_msg(p_tcb, p_tcb->sr_cmd.p_rsp_msg);
+ p_tcb->sr_cmd.p_rsp_msg = NULL;
+ } else {
+ ret_code = gatt_send_error_rsp(p_tcb, status, op_code,
+ p_tcb->sr_cmd.handle, false);
+ }
+
+ gatt_dequeue_sr_cmd(p_tcb);
+ }
+
+ GATT_TRACE_DEBUG("gatt_sr_process_app_rsp ret_code=%d", ret_code);
+
+ return ret_code;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_exec_write_req
+ *
+ * Description This function is called to process the execute write request
+ * from client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_exec_write_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ UNUSED_ATTR uint16_t len, uint8_t* p_data) {
+ uint8_t *p = p_data, flag, i = 0;
+ uint32_t trans_id = 0;
+ tGATT_IF gatt_if;
+ uint16_t conn_id;
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) {
+ GATT_TRACE_DEBUG(
+ "Conformance tst: forced err rspv for Execute Write: error status=%d",
+ gatt_cb.err_status);
+
+ gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code,
+ gatt_cb.handle, false);
+
+ return;
+ }
+#endif
+
+ STREAM_TO_UINT8(flag, p);
+
+ /* mask the flag */
+ flag &= GATT_PREP_WRITE_EXEC;
+
+ /* no prep write is queued */
+ if (!gatt_sr_is_prep_cnt_zero(p_tcb)) {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, 0);
+ gatt_sr_copy_prep_cnt_to_cback_cnt(p_tcb);
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->prep_cnt[i]) {
+ gatt_if = (tGATT_IF)(i + 1);
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
+ gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_WRITE_EXEC,
+ (tGATTS_DATA*)&flag);
+ p_tcb->prep_cnt[i] = 0;
+ }
+ }
+ } else /* nothing needs to be executed , send response now */
+ {
+ GATT_TRACE_ERROR("gatt_process_exec_write_req: no prepare write pending");
+ gatt_send_error_rsp(p_tcb, GATT_ERROR, GATT_REQ_EXEC_WRITE, 0, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_process_read_multi_req
+ *
+ * Description This function is called to process the read multiple request
+ * from client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_process_read_multi_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ uint32_t trans_id;
+ uint16_t handle = 0, ll = len;
+ uint8_t* p = p_data;
+ tGATT_STATUS err = GATT_SUCCESS;
+ uint8_t sec_flag, key_size;
+
+ GATT_TRACE_DEBUG("gatt_process_read_multi_req");
+ p_tcb->sr_cmd.multi_req.num_handles = 0;
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) {
+ GATT_TRACE_DEBUG(
+ "Conformance tst: forced err rspvofr ReadMultiple: error status=%d",
+ gatt_cb.err_status);
+
+ STREAM_TO_UINT16(handle, p);
+
+ gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
+ false);
+
+ return;
+ }
+#endif
+
+ while (ll >= 2 &&
+ p_tcb->sr_cmd.multi_req.num_handles < GATT_MAX_READ_MULTI_HANDLES) {
+ STREAM_TO_UINT16(handle, p);
+
+ auto it = gatt_sr_find_i_rcb_by_handle(handle);
+ if (it != gatt_cb.srv_list_info->end()) {
+ p_tcb->sr_cmd.multi_req.handles[p_tcb->sr_cmd.multi_req.num_handles++] =
+ handle;
+
+ /* check read permission */
+ err = gatts_read_attr_perm_check(it->p_db, false, handle, sec_flag,
+ key_size);
+ if (err != GATT_SUCCESS) {
+ GATT_TRACE_DEBUG("read permission denied : 0x%02x", err);
+ break;
+ }
+ } else {
+ /* invalid handle */
+ err = GATT_INVALID_HANDLE;
+ break;
+ }
+ ll -= 2;
+ }
+
+ if (ll != 0) {
+ GATT_TRACE_ERROR("max attribute handle reached in ReadMultiple Request.");
+ }
+
+ if (p_tcb->sr_cmd.multi_req.num_handles == 0) err = GATT_INVALID_HANDLE;
+
+ if (err == GATT_SUCCESS) {
+ trans_id =
+ gatt_sr_enqueue_cmd(p_tcb, op_code, p_tcb->sr_cmd.multi_req.handles[0]);
+ if (trans_id != 0) {
+ gatt_sr_reset_cback_cnt(p_tcb); /* read multiple use multi_rsp_q's count*/
+
+ for (ll = 0; ll < p_tcb->sr_cmd.multi_req.num_handles; ll++) {
+ tGATTS_RSP* p_msg = (tGATTS_RSP*)osi_calloc(sizeof(tGATTS_RSP));
+ handle = p_tcb->sr_cmd.multi_req.handles[ll];
+ auto it = gatt_sr_find_i_rcb_by_handle(handle);
+
+ p_msg->attr_value.handle = handle;
+ err = gatts_read_attr_value_by_handle(
+ p_tcb, it->p_db, op_code, handle, 0, p_msg->attr_value.value,
+ &p_msg->attr_value.len, GATT_MAX_ATTR_LEN, sec_flag, key_size,
+ trans_id);
+
+ if (err == GATT_SUCCESS) {
+ gatt_sr_process_app_rsp(p_tcb, it->gatt_if, trans_id, op_code,
+ GATT_SUCCESS, p_msg);
+ }
+ /* either not using or done using the buffer, release it now */
+ osi_free(p_msg);
+ }
+ } else
+ err = GATT_NO_RESOURCES;
+ }
+
+ /* in theroy BUSY is not possible(should already been checked), protected
+ * check */
+ if (err != GATT_SUCCESS && err != GATT_PENDING && err != GATT_BUSY)
+ gatt_send_error_rsp(p_tcb, err, op_code, handle, false);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_build_primary_service_rsp
+ *
+ * Description Primamry service request processed internally. Theretically
+ * only deal with ReadByTypeVAlue and ReadByGroupType.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tGATT_STATUS gatt_build_primary_service_rsp(
+ BT_HDR* p_msg, tGATT_TCB* p_tcb, uint8_t op_code, uint16_t s_hdl,
+ uint16_t e_hdl, UNUSED_ATTR uint8_t* p_data, tBT_UUID value) {
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ uint8_t handle_len = 4, *p;
+ tBT_UUID* p_uuid;
+
+ p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl >= s_hdl && el.s_hdl <= e_hdl &&
+ el.type == GATT_UUID_PRI_SERVICE) {
+ p_uuid = gatts_get_service_uuid(el.p_db);
+ if (p_uuid != NULL) {
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE) handle_len = 4 + p_uuid->len;
+
+ /* get the length byte in the repsonse */
+ if (p_msg->offset == 0) {
+ *p++ = op_code + 1;
+ p_msg->len++;
+ p_msg->offset = handle_len;
+
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
+ *p++ = (uint8_t)p_msg->offset; /* length byte */
+ p_msg->len++;
+ }
+ }
+
+ if (p_msg->len + p_msg->offset <= p_tcb->payload_size &&
+ handle_len == p_msg->offset) {
+ if (op_code != GATT_REQ_FIND_TYPE_VALUE ||
+ gatt_uuid_compare(value, *p_uuid)) {
+ UINT16_TO_STREAM(p, el.s_hdl);
+
+ if (gatt_cb.last_primary_s_handle &&
+ gatt_cb.last_primary_s_handle == el.s_hdl) {
+ GATT_TRACE_DEBUG("Use 0xFFFF for the last primary attribute");
+ /* see GATT ERRATA 4065, 4063, ATT ERRATA 4062 */
+ UINT16_TO_STREAM(p, 0xFFFF);
+ } else {
+ UINT16_TO_STREAM(p, el.e_hdl);
+ }
+
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
+ gatt_build_uuid_to_stream(&p, *p_uuid);
+
+ status = GATT_SUCCESS;
+ p_msg->len += p_msg->offset;
+ }
+ } else
+ break;
+ }
+ }
+ }
+ p_msg->offset = L2CAP_MIN_OFFSET;
+
+ return status;
+}
+
+/**
+ * fill the find information response information in the given buffer.
+ *
+ * Returns true: if data filled sucessfully.
+ * false: packet full, or format mismatch.
+ */
+static tGATT_STATUS gatt_build_find_info_rsp(tGATT_SRV_LIST_ELEM& el,
+ BT_HDR* p_msg, uint16_t* p_len,
+ uint16_t s_hdl, uint16_t e_hdl) {
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ uint8_t* p;
+ uint16_t len = *p_len;
+ uint8_t info_pair_len[2] = {4, 18};
+
+ if (!el.p_db) return status;
+
+ /* check the attribute database */
+
+ p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET + p_msg->len;
+
+ for (auto& attr : el.p_db->attr_list) {
+ if (attr.handle > e_hdl) {
+ break;
+ }
+
+ if (attr.handle >= s_hdl) {
+ if (p_msg->offset == 0)
+ p_msg->offset = (attr.uuid.len == LEN_UUID_16)
+ ? GATT_INFO_TYPE_PAIR_16
+ : GATT_INFO_TYPE_PAIR_128;
+
+ if (len >= info_pair_len[p_msg->offset - 1]) {
+ if (p_msg->offset == GATT_INFO_TYPE_PAIR_16 &&
+ attr.uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, attr.handle);
+ UINT16_TO_STREAM(p, attr.uuid.uu.uuid16);
+ } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
+ attr.uuid.len == LEN_UUID_128) {
+ UINT16_TO_STREAM(p, attr.handle);
+ ARRAY_TO_STREAM(p, attr.uuid.uu.uuid128, LEN_UUID_128);
+ } else if (p_msg->offset == GATT_INFO_TYPE_PAIR_128 &&
+ attr.uuid.len == LEN_UUID_32) {
+ UINT16_TO_STREAM(p, attr.handle);
+ gatt_convert_uuid32_to_uuid128(p, attr.uuid.uu.uuid32);
+ p += LEN_UUID_128;
+ } else {
+ GATT_TRACE_ERROR("format mismatch");
+ status = GATT_NO_RESOURCES;
+ break;
+ /* format mismatch */
+ }
+ p_msg->len += info_pair_len[p_msg->offset - 1];
+ len -= info_pair_len[p_msg->offset - 1];
+ status = GATT_SUCCESS;
+
+ } else {
+ status = GATT_NO_RESOURCES;
+ break;
+ }
+ }
+ }
+
+ *p_len = len;
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_internal_read_by_type_req
+ *
+ * Description Check to see if the ReadByType request can be handled
+ * internally.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static tGATT_STATUS gatts_validate_packet_format(
+ uint8_t op_code, uint16_t* p_len, uint8_t** p_data, tBT_UUID* p_uuid_filter,
+ uint16_t* p_s_hdl, uint16_t* p_e_hdl) {
+ tGATT_STATUS reason = GATT_SUCCESS;
+ uint16_t uuid_len, s_hdl = 0, e_hdl = 0;
+ uint16_t len = *p_len;
+ uint8_t* p = *p_data;
+
+ if (len >= 4) {
+ /* obtain starting handle, and ending handle */
+ STREAM_TO_UINT16(s_hdl, p);
+ STREAM_TO_UINT16(e_hdl, p);
+ len -= 4;
+
+ if (s_hdl > e_hdl || !GATT_HANDLE_IS_VALID(s_hdl) ||
+ !GATT_HANDLE_IS_VALID(e_hdl)) {
+ reason = GATT_INVALID_HANDLE;
+ }
+ /* for these PDUs, uuid filter must present */
+ else if (op_code == GATT_REQ_READ_BY_GRP_TYPE ||
+ op_code == GATT_REQ_FIND_TYPE_VALUE ||
+ op_code == GATT_REQ_READ_BY_TYPE) {
+ if (len >= 2 && p_uuid_filter != NULL) {
+ uuid_len = (op_code == GATT_REQ_FIND_TYPE_VALUE) ? 2 : len;
+
+ /* parse uuid now */
+ if (gatt_parse_uuid_from_cmd(p_uuid_filter, uuid_len, &p) == false ||
+ p_uuid_filter->len == 0) {
+ GATT_TRACE_DEBUG("UUID filter does not exsit");
+ reason = GATT_INVALID_PDU;
+ } else
+ len -= p_uuid_filter->len;
+ } else
+ reason = GATT_INVALID_PDU;
+ }
+ } else
+ reason = GATT_INVALID_PDU;
+
+ *p_data = p;
+ *p_len = len;
+ *p_s_hdl = s_hdl;
+ *p_e_hdl = e_hdl;
+
+ return reason;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_primary_service_req
+ *
+ * Description Process ReadByGroupType/ReadByTypeValue request, for
+ * discovering all primary services or discover primary service
+ * by UUID request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatts_process_primary_service_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ uint8_t reason = GATT_INVALID_PDU;
+ uint16_t s_hdl = 0, e_hdl = 0;
+ tBT_UUID uuid, value,
+ primary_service = {LEN_UUID_16, {GATT_UUID_PRI_SERVICE}};
+ BT_HDR* p_msg = NULL;
+ uint16_t msg_len =
+ (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+ memset(&value, 0, sizeof(tBT_UUID));
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl,
+ &e_hdl);
+
+ if (reason == GATT_SUCCESS) {
+ if (gatt_uuid_compare(uuid, primary_service)) {
+ if (op_code == GATT_REQ_FIND_TYPE_VALUE) {
+ if (gatt_parse_uuid_from_cmd(&value, len, &p_data) == false)
+ reason = GATT_INVALID_PDU;
+ }
+
+ if (reason == GATT_SUCCESS) {
+ p_msg = (BT_HDR*)osi_calloc(msg_len);
+ reason = gatt_build_primary_service_rsp(p_msg, p_tcb, op_code, s_hdl,
+ e_hdl, p_data, value);
+ }
+ } else {
+ if (op_code == GATT_REQ_READ_BY_GRP_TYPE) {
+ reason = GATT_UNSUPPORT_GRP_TYPE;
+ GATT_TRACE_DEBUG("unexpected ReadByGrpType Group: 0x%04x",
+ uuid.uu.uuid16);
+ } else {
+ /* we do not support ReadByTypeValue with any non-primamry_service type
+ */
+ reason = GATT_NOT_FOUND;
+ GATT_TRACE_DEBUG("unexpected ReadByTypeValue type: 0x%04x",
+ uuid.uu.uuid16);
+ }
+ }
+ }
+
+ if (reason != GATT_SUCCESS) {
+ osi_free(p_msg);
+ gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ } else
+ attp_send_sr_msg(p_tcb, p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_find_info
+ *
+ * Description process find information request, for discover character
+ * descriptors.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatts_process_find_info(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ uint8_t reason = GATT_INVALID_PDU, *p;
+ uint16_t s_hdl = 0, e_hdl = 0, buf_len;
+ BT_HDR* p_msg = NULL;
+
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, NULL, &s_hdl,
+ &e_hdl);
+
+ if (reason == GATT_SUCCESS) {
+ buf_len =
+ (uint16_t)(sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET);
+
+ p_msg = (BT_HDR*)osi_calloc(buf_len);
+ reason = GATT_NOT_FOUND;
+
+ p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ *p++ = op_code + 1;
+ p_msg->len = 2;
+
+ buf_len = p_tcb->payload_size - 2;
+
+ for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
+ reason = gatt_build_find_info_rsp(el, p_msg, &buf_len, s_hdl, e_hdl);
+ if (reason == GATT_NO_RESOURCES) {
+ reason = GATT_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ *p = (uint8_t)p_msg->offset;
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ }
+
+ if (reason != GATT_SUCCESS) {
+ osi_free(p_msg);
+ gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ } else
+ attp_send_sr_msg(p_tcb, p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_mtu_req
+ *
+ * Description This function is called to process excahnge MTU request.
+ * Only used on LE.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatts_process_mtu_req(tGATT_TCB* p_tcb, uint16_t len,
+ uint8_t* p_data) {
+ uint16_t mtu = 0;
+ uint8_t *p = p_data, i;
+ BT_HDR* p_buf;
+ uint16_t conn_id;
+
+ /* BR/EDR conenction, send error response */
+ if (p_tcb->att_lcid != L2CAP_ATT_CID) {
+ gatt_send_error_rsp(p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, false);
+ } else if (len < GATT_MTU_REQ_MIN_LEN) {
+ GATT_TRACE_ERROR("invalid MTU request PDU received.");
+ gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, false);
+ } else {
+ STREAM_TO_UINT16(mtu, p);
+ /* mtu must be greater than default MTU which is 23/48 */
+ if (mtu < GATT_DEF_BLE_MTU_SIZE)
+ p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
+ else if (mtu > GATT_MAX_MTU_SIZE)
+ p_tcb->payload_size = GATT_MAX_MTU_SIZE;
+ else
+ p_tcb->payload_size = mtu;
+
+ GATT_TRACE_ERROR("MTU request PDU with MTU size %d", p_tcb->payload_size);
+
+ l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID,
+ p_tcb->payload_size);
+
+ p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU,
+ (tGATT_SR_MSG*)&p_tcb->payload_size);
+ if (p_buf != NULL) {
+ attp_send_sr_msg(p_tcb, p_buf);
+
+ /* Notify all registered applicaiton with new MTU size. Us a transaction
+ * ID */
+ /* of 0, as no response is allowed from applcations */
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (gatt_cb.cl_rcb[i].in_use) {
+ conn_id =
+ GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_cb.cl_rcb[i].gatt_if);
+ gatt_sr_send_req_callback(conn_id, 0, GATTS_REQ_TYPE_MTU,
+ (tGATTS_DATA*)&p_tcb->payload_size);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_read_by_type_req
+ *
+ * Description process Read By type request.
+ * This PDU can be used to perform:
+ * - read characteristic value
+ * - read characteristic descriptor value
+ * - discover characteristic
+ * - discover characteristic by UUID
+ * - relationship discovery
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatts_process_read_by_type_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ tBT_UUID uuid;
+ size_t msg_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+ uint16_t buf_len, s_hdl, e_hdl, err_hdl = 0;
+ BT_HDR* p_msg = NULL;
+ tGATT_STATUS reason, ret;
+ uint8_t* p;
+ uint8_t sec_flag, key_size;
+
+ reason = gatts_validate_packet_format(op_code, &len, &p_data, &uuid, &s_hdl,
+ &e_hdl);
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) {
+ GATT_TRACE_DEBUG(
+ "Conformance tst: forced err rsp for ReadByType: error status=%d",
+ gatt_cb.err_status);
+
+ gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, s_hdl,
+ false);
+
+ return;
+ }
+#endif
+
+ if (reason == GATT_SUCCESS) {
+ p_msg = (BT_HDR*)osi_calloc(msg_len);
+ p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ *p++ = op_code + 1;
+ /* reserve length byte */
+ p_msg->len = 2;
+ buf_len = p_tcb->payload_size - 2;
+
+ reason = GATT_NOT_FOUND;
+
+ for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= e_hdl && el.e_hdl >= s_hdl) {
+ gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag,
+ &key_size);
+
+ ret = gatts_db_read_attr_value_by_type(p_tcb, el.p_db, op_code, p_msg,
+ s_hdl, e_hdl, uuid, &buf_len,
+ sec_flag, key_size, 0, &err_hdl);
+ if (ret != GATT_NOT_FOUND) {
+ reason = ret;
+
+ if (ret == GATT_NO_RESOURCES) reason = GATT_SUCCESS;
+ }
+ if (ret != GATT_SUCCESS && ret != GATT_NOT_FOUND) {
+ s_hdl = err_hdl;
+ break;
+ }
+ }
+ }
+ *p = (uint8_t)p_msg->offset;
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ }
+ if (reason != GATT_SUCCESS) {
+ osi_free(p_msg);
+
+ /* in theroy BUSY is not possible(should already been checked), protected
+ * check */
+ if (reason != GATT_PENDING && reason != GATT_BUSY)
+ gatt_send_error_rsp(p_tcb, reason, op_code, s_hdl, false);
+ } else
+ attp_send_sr_msg(p_tcb, p_msg);
+}
+
+/**
+ * This function is called to process the write request from client.
+ */
+void gatts_process_write_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
+ uint16_t handle, uint8_t op_code, uint16_t len,
+ uint8_t* p_data,
+ bt_gatt_db_attribute_type_t gatt_type) {
+ tGATTS_DATA sr_data;
+ uint32_t trans_id;
+ tGATT_STATUS status;
+ uint8_t sec_flag, key_size, *p = p_data;
+ uint16_t conn_id;
+
+ memset(&sr_data, 0, sizeof(tGATTS_DATA));
+
+ switch (op_code) {
+ case GATT_REQ_PREPARE_WRITE:
+ if (len < 2) {
+ GATT_TRACE_ERROR(
+ "%s: Prepare write request was invalid - missing offset, sending "
+ "error response",
+ __func__);
+ gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, handle, false);
+ return;
+ }
+ sr_data.write_req.is_prep = true;
+ STREAM_TO_UINT16(sr_data.write_req.offset, p);
+ len -= 2;
+ /* fall through */
+ case GATT_SIGN_CMD_WRITE:
+ if (op_code == GATT_SIGN_CMD_WRITE) {
+ GATT_TRACE_DEBUG("Write CMD with data sigining");
+ len -= GATT_AUTH_SIGN_LEN;
+ }
+ /* fall through */
+ case GATT_CMD_WRITE:
+ case GATT_REQ_WRITE:
+ if (op_code == GATT_REQ_WRITE || op_code == GATT_REQ_PREPARE_WRITE)
+ sr_data.write_req.need_rsp = true;
+ sr_data.write_req.handle = handle;
+ sr_data.write_req.len = len;
+ if (len != 0 && p != NULL) {
+ memcpy(sr_data.write_req.value, p, len);
+ }
+ break;
+ }
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+
+ status = gatts_write_attr_perm_check(el.p_db, op_code, handle,
+ sr_data.write_req.offset, p, len,
+ sec_flag, key_size);
+
+ if (status == GATT_SUCCESS) {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ if (trans_id != 0) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
+
+ uint8_t opcode = 0;
+ if (gatt_type == BTGATT_DB_DESCRIPTOR) {
+ opcode = GATTS_REQ_TYPE_WRITE_DESCRIPTOR;
+ } else if (gatt_type == BTGATT_DB_CHARACTERISTIC) {
+ opcode = GATTS_REQ_TYPE_WRITE_CHARACTERISTIC;
+ } else {
+ GATT_TRACE_ERROR(
+ "%s: Attempt to write attribute that's not tied with"
+ " characteristic or descriptor value.",
+ __func__);
+ status = GATT_ERROR;
+ }
+
+ if (opcode) {
+ gatt_sr_send_req_callback(conn_id, trans_id, opcode, &sr_data);
+ status = GATT_PENDING;
+ }
+ } else {
+ GATT_TRACE_ERROR("max pending command, send error");
+ status = GATT_BUSY; /* max pending command, application error */
+ }
+ }
+
+ /* in theroy BUSY is not possible(should already been checked), protected
+ * check */
+ if (status != GATT_PENDING && status != GATT_BUSY &&
+ (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_REQ_WRITE)) {
+ gatt_send_error_rsp(p_tcb, status, op_code, handle, false);
+ }
+ return;
+}
+
+/**
+ * This function is called to process the read request from client.
+ */
+static void gatts_process_read_req(tGATT_TCB* p_tcb, tGATT_SRV_LIST_ELEM& el,
+ uint8_t op_code, uint16_t handle,
+ UNUSED_ATTR uint16_t len, uint8_t* p_data) {
+ size_t buf_len = sizeof(BT_HDR) + p_tcb->payload_size + L2CAP_MIN_OFFSET;
+ tGATT_STATUS reason;
+ uint8_t sec_flag, key_size, *p;
+ uint16_t offset = 0, value_len = 0;
+ BT_HDR* p_msg = (BT_HDR*)osi_calloc(buf_len);
+
+ if (op_code == GATT_REQ_READ_BLOB) STREAM_TO_UINT16(offset, p_data);
+
+ p = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+ *p++ = op_code + 1;
+ p_msg->len = 1;
+ buf_len = p_tcb->payload_size - 1;
+
+ gatt_sr_get_sec_info(p_tcb->peer_bda, p_tcb->transport, &sec_flag, &key_size);
+
+ reason = gatts_read_attr_value_by_handle(
+ p_tcb, el.p_db, op_code, handle, offset, p, &value_len, (uint16_t)buf_len,
+ sec_flag, key_size, 0);
+
+ p_msg->len += value_len;
+
+ if (reason != GATT_SUCCESS) {
+ osi_free(p_msg);
+
+ /* in theroy BUSY is not possible(should already been checked), protected
+ * check */
+ if (reason != GATT_PENDING && reason != GATT_BUSY)
+ gatt_send_error_rsp(p_tcb, reason, op_code, handle, false);
+ } else
+ attp_send_sr_msg(p_tcb, p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_attribute_req
+ *
+ * Description This function is called to process the per attribute handle
+ * request from client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatts_process_attribute_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ uint16_t handle = 0;
+ uint8_t* p = p_data;
+ tGATT_STATUS status = GATT_INVALID_HANDLE;
+
+ if (len < 2) {
+ GATT_TRACE_ERROR("Illegal PDU length, discard request");
+ status = GATT_INVALID_PDU;
+ } else {
+ STREAM_TO_UINT16(handle, p);
+ len -= 2;
+ }
+
+#if (GATT_CONFORMANCE_TESTING == TRUE)
+ gatt_cb.handle = handle;
+ if (gatt_cb.enable_err_rsp && gatt_cb.req_op_code == op_code) {
+ GATT_TRACE_DEBUG("Conformance tst: forced err rsp: error status=%d",
+ gatt_cb.err_status);
+
+ gatt_send_error_rsp(p_tcb, gatt_cb.err_status, gatt_cb.req_op_code, handle,
+ false);
+
+ return;
+ }
+#endif
+
+ if (GATT_HANDLE_IS_VALID(handle)) {
+ for (auto& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= handle && el.e_hdl >= handle) {
+ for (const auto& attr : el.p_db->attr_list) {
+ if (attr.handle == handle) {
+ switch (op_code) {
+ case GATT_REQ_READ: /* read char/char descriptor value */
+ case GATT_REQ_READ_BLOB:
+ gatts_process_read_req(p_tcb, el, op_code, handle, len, p);
+ break;
+
+ case GATT_REQ_WRITE: /* write char/char descriptor value */
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ case GATT_REQ_PREPARE_WRITE:
+ gatts_process_write_req(p_tcb, el, handle, op_code, len, p,
+ attr.gatt_type);
+ break;
+ default:
+ break;
+ }
+ status = GATT_SUCCESS;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (status != GATT_SUCCESS && op_code != GATT_CMD_WRITE &&
+ op_code != GATT_SIGN_CMD_WRITE)
+ gatt_send_error_rsp(p_tcb, status, op_code, handle, false);
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_proc_srv_chg_ind_ack
+ *
+ * Description This function process the service changed indicaiton ACK
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatts_proc_srv_chg_ind_ack(tGATT_TCB* p_tcb) {
+ tGATTS_SRV_CHG_REQ req;
+ tGATTS_SRV_CHG* p_buf = NULL;
+
+ GATT_TRACE_DEBUG("gatts_proc_srv_chg_ind_ack");
+
+ p_buf = gatt_is_bda_in_the_srv_chg_clt_list(p_tcb->peer_bda);
+ if (p_buf != NULL) {
+ GATT_TRACE_DEBUG("NV update set srv chg = false");
+ p_buf->srv_changed = false;
+ memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,
+ &req, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_chk_pending_ind
+ *
+ * Description This function check any pending indication needs to be sent
+ * if there is a pending indication then sent the indication
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void gatts_chk_pending_ind(tGATT_TCB* p_tcb) {
+ GATT_TRACE_DEBUG("%s", __func__);
+
+ tGATT_VALUE* p_buf =
+ (tGATT_VALUE*)fixed_queue_try_peek_first(p_tcb->pending_ind_q);
+ if (p_buf != NULL) {
+ GATTS_HandleValueIndication(p_buf->conn_id, p_buf->handle, p_buf->len,
+ p_buf->value);
+ osi_free(fixed_queue_try_remove_from_queue(p_tcb->pending_ind_q, p_buf));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_proc_ind_ack
+ *
+ * Description This function processes the Indication ack
+ *
+ * Returns true continue to process the indication ack by the
+ * application if the ACK is not a Service Changed Indication
+ *
+ ******************************************************************************/
+static bool gatts_proc_ind_ack(tGATT_TCB* p_tcb, uint16_t ack_handle) {
+ bool continue_processing = true;
+
+ GATT_TRACE_DEBUG("gatts_proc_ind_ack ack handle=%d", ack_handle);
+
+ if (ack_handle == gatt_cb.handle_of_h_r) {
+ gatts_proc_srv_chg_ind_ack(p_tcb);
+ /* there is no need to inform the application since srv chg is handled
+ * internally by GATT */
+ continue_processing = false;
+ }
+
+ gatts_chk_pending_ind(p_tcb);
+ return continue_processing;
+}
+
+/*******************************************************************************
+ *
+ * Function gatts_process_value_conf
+ *
+ * Description This function is called to process the handle value
+ * confirmation.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatts_process_value_conf(tGATT_TCB* p_tcb, uint8_t op_code) {
+ uint16_t handle = p_tcb->indicate_handle;
+ uint32_t trans_id;
+ bool continue_processing;
+ uint16_t conn_id;
+
+ alarm_cancel(p_tcb->conf_timer);
+ if (GATT_HANDLE_IS_VALID(handle)) {
+ p_tcb->indicate_handle = 0;
+ continue_processing = gatts_proc_ind_ack(p_tcb, handle);
+
+ if (continue_processing) {
+ for (auto& el : *gatt_cb.srv_list_info) {
+ if (el.s_hdl <= handle && el.e_hdl >= handle) {
+ trans_id = gatt_sr_enqueue_cmd(p_tcb, op_code, handle);
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, el.gatt_if);
+ gatt_sr_send_req_callback(conn_id, trans_id, GATTS_REQ_TYPE_CONF,
+ (tGATTS_DATA*)&handle);
+ }
+ }
+ }
+ } else {
+ GATT_TRACE_ERROR("unexpected handle value confirmation");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_server_handle_client_req
+ *
+ * Description This function is called to handle the client requests to
+ * server.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_server_handle_client_req(tGATT_TCB* p_tcb, uint8_t op_code,
+ uint16_t len, uint8_t* p_data) {
+ /* there is pending command, discard this one */
+ if (!gatt_sr_cmd_empty(p_tcb) && op_code != GATT_HANDLE_VALUE_CONF) return;
+
+ /* the size of the message may not be bigger than the local max PDU size*/
+ /* The message has to be smaller than the agreed MTU, len does not include op
+ * code */
+ if (len >= p_tcb->payload_size) {
+ GATT_TRACE_ERROR("server receive invalid PDU size:%d pdu size:%d", len + 1,
+ p_tcb->payload_size);
+ /* for invalid request expecting response, send it now */
+ if (op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE &&
+ op_code != GATT_HANDLE_VALUE_CONF) {
+ gatt_send_error_rsp(p_tcb, GATT_INVALID_PDU, op_code, 0, false);
+ }
+ /* otherwise, ignore the pkt */
+ } else {
+ switch (op_code) {
+ case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
+ case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
+ gatts_process_primary_service_req(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_FIND_INFO: /* discover char descrptor */
+ gatts_process_find_info(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor
+ value */
+ /* discover characteristic, discover char by UUID */
+ gatts_process_read_by_type_req(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_READ: /* read char/char descriptor value */
+ case GATT_REQ_READ_BLOB:
+ case GATT_REQ_WRITE: /* write char/char descriptor value */
+ case GATT_CMD_WRITE:
+ case GATT_SIGN_CMD_WRITE:
+ case GATT_REQ_PREPARE_WRITE:
+ gatts_process_attribute_req(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_HANDLE_VALUE_CONF:
+ gatts_process_value_conf(p_tcb, op_code);
+ break;
+
+ case GATT_REQ_MTU:
+ gatts_process_mtu_req(p_tcb, len, p_data);
+ break;
+
+ case GATT_REQ_EXEC_WRITE:
+ gatt_process_exec_write_req(p_tcb, op_code, len, p_data);
+ break;
+
+ case GATT_REQ_READ_MULTI:
+ gatt_process_read_multi_req(p_tcb, op_code, len, p_data);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/gatt/gatt_utils.cc b/mtkbt/code/bt/stack/gatt/gatt_utils.cc
new file mode 100755
index 0000000..2417b4d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/gatt/gatt_utils.cc
@@ -0,0 +1,2021 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains GATT utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+
+#include <string.h>
+#include "bt_common.h"
+#include "stdio.h"
+
+#include "btm_int.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "gattdefs.h"
+#include "l2cdefs.h"
+#include "sdp_api.h"
+/* check if [x, y] and [a, b] have overlapping range */
+#define GATT_VALIDATE_HANDLE_RANGE(x, y, a, b) ((y) >= (a) && (x) <= (b))
+
+#define GATT_GET_NEXT_VALID_HANDLE(x) (((x) / 10 + 1) * 10)
+
+const char* const op_code_name[] = {"UNKNOWN",
+ "ATT_RSP_ERROR",
+ "ATT_REQ_MTU",
+ "ATT_RSP_MTU",
+ "ATT_REQ_READ_INFO",
+ "ATT_RSP_READ_INFO",
+ "ATT_REQ_FIND_TYPE_VALUE",
+ "ATT_RSP_FIND_TYPE_VALUE",
+ "ATT_REQ_READ_BY_TYPE",
+ "ATT_RSP_READ_BY_TYPE",
+ "ATT_REQ_READ",
+ "ATT_RSP_READ",
+ "ATT_REQ_READ_BLOB",
+ "ATT_RSP_READ_BLOB",
+ "GATT_REQ_READ_MULTI",
+ "GATT_RSP_READ_MULTI",
+ "GATT_REQ_READ_BY_GRP_TYPE",
+ "GATT_RSP_READ_BY_GRP_TYPE",
+ "ATT_REQ_WRITE",
+ "ATT_RSP_WRITE",
+ "ATT_CMD_WRITE",
+ "ATT_SIGN_CMD_WRITE",
+ "ATT_REQ_PREPARE_WRITE",
+ "ATT_RSP_PREPARE_WRITE",
+ "ATT_REQ_EXEC_WRITE",
+ "ATT_RSP_EXEC_WRITE",
+ "Reserved",
+ "ATT_HANDLE_VALUE_NOTIF",
+ "Reserved",
+ "ATT_HANDLE_VALUE_IND",
+ "ATT_HANDLE_VALUE_CONF",
+ "ATT_OP_CODE_MAX"};
+
+static const uint8_t base_uuid[LEN_UUID_128] = {
+ 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function gatt_free_pending_ind
+ *
+ * Description Free all pending indications
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_free_pending_ind(tGATT_TCB* p_tcb) {
+ GATT_TRACE_DEBUG("%s", __func__);
+
+ if (p_tcb->pending_ind_q == NULL) return;
+
+ /* release all queued indications */
+ while (!fixed_queue_is_empty(p_tcb->pending_ind_q))
+ osi_free(fixed_queue_try_dequeue(p_tcb->pending_ind_q));
+ fixed_queue_free(p_tcb->pending_ind_q, NULL);
+ p_tcb->pending_ind_q = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_free_pending_enc_queue
+ *
+ * Description Free all buffers in pending encyption queue
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_free_pending_enc_queue(tGATT_TCB* p_tcb) {
+ GATT_TRACE_DEBUG("%s", __func__);
+
+ if (p_tcb->pending_enc_clcb == NULL) return;
+
+ /* release all queued indications */
+ while (!fixed_queue_is_empty(p_tcb->pending_enc_clcb))
+ osi_free(fixed_queue_try_dequeue(p_tcb->pending_enc_clcb));
+ fixed_queue_free(p_tcb->pending_enc_clcb, NULL);
+ p_tcb->pending_enc_clcb = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_delete_dev_from_srv_chg_clt_list
+ *
+ * Description Delete a device from the service changed client lit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_delete_dev_from_srv_chg_clt_list(BD_ADDR bd_addr) {
+ GATT_TRACE_DEBUG("gatt_delete_dev_from_srv_chg_clt_list");
+
+ tGATTS_SRV_CHG* p_buf = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr);
+ if (p_buf != NULL) {
+ if (gatt_cb.cb_info.p_srv_chg_callback) {
+ /* delete from NV */
+ tGATTS_SRV_CHG_REQ req;
+ memcpy(req.srv_chg.bda, bd_addr, BD_ADDR_LEN);
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_REMOVE_CLIENT,
+ &req, NULL);
+ }
+ osi_free(fixed_queue_try_remove_from_queue(gatt_cb.srv_chg_clt_q, p_buf));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_set_srv_chg
+ *
+ * Description Set the service changed flag to true
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_set_srv_chg(void) {
+ GATT_TRACE_DEBUG("gatt_set_srv_chg");
+
+ if (fixed_queue_is_empty(gatt_cb.srv_chg_clt_q)) return;
+
+ list_t* list = fixed_queue_get_list(gatt_cb.srv_chg_clt_q);
+ for (const list_node_t* node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ GATT_TRACE_DEBUG("found a srv_chg clt");
+
+ tGATTS_SRV_CHG* p_buf = (tGATTS_SRV_CHG*)list_node(node);
+ if (!p_buf->srv_changed) {
+ GATT_TRACE_DEBUG("set srv_changed to true");
+ p_buf->srv_changed = true;
+ tGATTS_SRV_CHG_REQ req;
+ memcpy(&req.srv_chg, p_buf, sizeof(tGATTS_SRV_CHG));
+ if (gatt_cb.cb_info.p_srv_chg_callback)
+ (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_UPDATE_CLIENT,
+ &req, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_pending_ind
+ *
+ * Description Add a pending indication
+ *
+ * Returns Pointer to the current pending indication buffer, NULL no buffer
+ * available
+ *
+ ******************************************************************************/
+tGATT_VALUE* gatt_add_pending_ind(tGATT_TCB* p_tcb, tGATT_VALUE* p_ind) {
+ tGATT_VALUE* p_buf = (tGATT_VALUE*)osi_malloc(sizeof(tGATT_VALUE));
+
+ GATT_TRACE_DEBUG("%s", __func__);
+ GATT_TRACE_DEBUG("enqueue a pending indication");
+
+ memcpy(p_buf, p_ind, sizeof(tGATT_VALUE));
+ fixed_queue_enqueue(p_tcb->pending_ind_q, p_buf);
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_srv_chg_clt
+ *
+ * Description Add a service chnage client to the service change client queue
+ *
+ * Returns Pointer to the service change client buffer; Null no buffer
+ * available
+ *
+ ******************************************************************************/
+tGATTS_SRV_CHG* gatt_add_srv_chg_clt(tGATTS_SRV_CHG* p_srv_chg) {
+ tGATTS_SRV_CHG* p_buf = (tGATTS_SRV_CHG*)osi_malloc(sizeof(tGATTS_SRV_CHG));
+
+ GATT_TRACE_DEBUG("%s", __func__);
+ GATT_TRACE_DEBUG("enqueue a srv chg client");
+
+ memcpy(p_buf, p_srv_chg, sizeof(tGATTS_SRV_CHG));
+ fixed_queue_enqueue(gatt_cb.srv_chg_clt_q, p_buf);
+
+ return p_buf;
+}
+
+/**
+ * Returns pointer to the handle range buffer starting at handle |handle|,
+ * nullptr
+ * if no buffer available
+ */
+tGATT_HDL_LIST_ELEM* gatt_find_hdl_buffer_by_handle(uint16_t handle) {
+ for (auto& elem : *gatt_cb.hdl_list_info) {
+ if (elem.asgn_range.s_handle == handle) return &elem;
+ }
+
+ return nullptr;
+}
+/*******************************************************************************
+ *
+ * Description Find handle range buffer by app ID, service and service instance
+ * ID.
+ *
+ * Returns Pointer to the buffer, NULL no buffer available
+ *
+ ******************************************************************************/
+std::list<tGATT_HDL_LIST_ELEM>::iterator gatt_find_hdl_buffer_by_app_id(
+ tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid, uint16_t start_handle) {
+ auto end_it = gatt_cb.hdl_list_info->end();
+ auto it = gatt_cb.hdl_list_info->begin();
+ for (; it != end_it; it++) {
+ if (gatt_uuid_compare(*p_app_uuid128, it->asgn_range.app_uuid128) &&
+ gatt_uuid_compare(*p_svc_uuid, it->asgn_range.svc_uuid) &&
+ (start_handle == it->asgn_range.s_handle)) {
+ return it;
+ }
+ }
+
+ return it;
+}
+
+/**
+ * free the service attribute database buffers by the owner of the service app
+ * ID.
+ */
+void gatt_free_srvc_db_buffer_app_id(tBT_UUID* p_app_id) {
+ auto end_it = gatt_cb.hdl_list_info->end();
+ for (auto it = gatt_cb.hdl_list_info->begin(); it != end_it; it++) {
+ if (memcmp(p_app_id, &it->asgn_range.app_uuid128, sizeof(tBT_UUID)) == 0) {
+ it = gatt_cb.hdl_list_info->erase(it);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_the_connected_bda
+ *
+ * Description This function find the connected bda
+ *
+ * Returns true if found
+ *
+ ******************************************************************************/
+bool gatt_find_the_connected_bda(uint8_t start_idx, BD_ADDR bda,
+ uint8_t* p_found_idx,
+ tBT_TRANSPORT* p_transport) {
+ uint8_t i;
+ bool found = false;
+ GATT_TRACE_DEBUG("gatt_find_the_connected_bda start_idx=%d", start_idx);
+
+ for (i = start_idx; i < GATT_MAX_PHY_CHANNEL; i++) {
+ if (gatt_cb.tcb[i].in_use && gatt_cb.tcb[i].ch_state == GATT_CH_OPEN) {
+ memcpy(bda, gatt_cb.tcb[i].peer_bda, BD_ADDR_LEN);
+ *p_found_idx = i;
+ *p_transport = gatt_cb.tcb[i].transport;
+ found = true;
+ GATT_TRACE_DEBUG(
+ "gatt_find_the_connected_bda bda :%02x-%02x-%02x-%02x-%02x-%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+ break;
+ }
+ }
+ GATT_TRACE_DEBUG("gatt_find_the_connected_bda found=%d found_idx=%d", found,
+ i);
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_is_srv_chg_ind_pending
+ *
+ * Description Check whether a service chnaged is in the indication pending
+ * queue or waiting for an Ack already
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+bool gatt_is_srv_chg_ind_pending(tGATT_TCB* p_tcb) {
+ bool srv_chg_ind_pending = false;
+
+ GATT_TRACE_DEBUG("gatt_is_srv_chg_ind_pending is_queue_empty=%d",
+ fixed_queue_is_empty(p_tcb->pending_ind_q));
+
+ if (p_tcb->indicate_handle == gatt_cb.handle_of_h_r) {
+ srv_chg_ind_pending = true;
+ } else if (!fixed_queue_is_empty(p_tcb->pending_ind_q)) {
+ list_t* list = fixed_queue_get_list(p_tcb->pending_ind_q);
+ for (const list_node_t* node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ tGATT_VALUE* p_buf = (tGATT_VALUE*)list_node(node);
+ if (p_buf->handle == gatt_cb.handle_of_h_r) {
+ srv_chg_ind_pending = true;
+ break;
+ }
+ }
+ }
+
+ GATT_TRACE_DEBUG("srv_chg_ind_pending = %d", srv_chg_ind_pending);
+ return srv_chg_ind_pending;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_is_bda_in_the_srv_chg_clt_list
+ *
+ * Description This function check the specified bda is in the srv chg
+ * client list or not
+ *
+ * Returns pointer to the found elemenet otherwise NULL
+ *
+ ******************************************************************************/
+tGATTS_SRV_CHG* gatt_is_bda_in_the_srv_chg_clt_list(BD_ADDR bda) {
+ /** M: Bug fix for always return NULL pointer @{ */
+ //tGATTS_SRV_CHG* p_buf = NULL;
+ /** @} */
+
+ GATT_TRACE_DEBUG(
+ "gatt_is_bda_in_the_srv_chg_clt_list :%02x-%02x-%02x-%02x-%02x-%02x",
+ bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
+
+ if (fixed_queue_is_empty(gatt_cb.srv_chg_clt_q)) return NULL;
+
+ list_t* list = fixed_queue_get_list(gatt_cb.srv_chg_clt_q);
+ for (const list_node_t* node = list_begin(list); node != list_end(list);
+ node = list_next(node)) {
+ tGATTS_SRV_CHG* p_buf = (tGATTS_SRV_CHG*)list_node(node);
+ if (!memcmp(bda, p_buf->bda, BD_ADDR_LEN)) {
+ GATT_TRACE_DEBUG("bda is in the srv chg clt list");
+ /** M: Bug fix for always return NULL pointer @{ */
+ return p_buf;
+ /** @} */
+ }
+ }
+ /** M: Bug fix for always return NULL pointer @{ */
+ return NULL;
+ /** @} */
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_is_bda_connected
+ *
+ * Description
+ *
+ * Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+bool gatt_is_bda_connected(BD_ADDR bda) {
+ uint8_t i = 0;
+ bool connected = false;
+
+ for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
+ if (gatt_cb.tcb[i].in_use &&
+ !memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN)) {
+ connected = true;
+ break;
+ }
+ }
+ return connected;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_i_tcb_by_addr
+ *
+ * Description Search for an empty tcb entry, and return the index.
+ *
+ * Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+uint8_t gatt_find_i_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport) {
+ uint8_t i = 0;
+
+ for (; i < GATT_MAX_PHY_CHANNEL; i++) {
+ if (!memcmp(gatt_cb.tcb[i].peer_bda, bda, BD_ADDR_LEN) &&
+ gatt_cb.tcb[i].transport == transport) {
+ return i;
+ }
+ }
+ return GATT_INDEX_INVALID;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_get_tcb_by_idx
+ *
+ * Description The function get TCB using the TCB index
+ *
+ * Returns NULL if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+tGATT_TCB* gatt_get_tcb_by_idx(uint8_t tcb_idx) {
+ tGATT_TCB* p_tcb = NULL;
+
+ if ((tcb_idx < GATT_MAX_PHY_CHANNEL) && gatt_cb.tcb[tcb_idx].in_use)
+ p_tcb = &gatt_cb.tcb[tcb_idx];
+
+ return p_tcb;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_tcb_by_addr
+ *
+ * Description Search for an empty tcb entry, and return pointer.
+ *
+ * Returns NULL if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+tGATT_TCB* gatt_find_tcb_by_addr(BD_ADDR bda, tBT_TRANSPORT transport) {
+ tGATT_TCB* p_tcb = NULL;
+ uint8_t i = 0;
+
+ i = gatt_find_i_tcb_by_addr(bda, transport);
+ if (i != GATT_INDEX_INVALID) p_tcb = &gatt_cb.tcb[i];
+
+ return p_tcb;
+}
+/*******************************************************************************
+ *
+ * Function gatt_find_i_tcb_free
+ *
+ * Description Search for an empty tcb entry, and return the index.
+ *
+ * Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+uint8_t gatt_find_i_tcb_free(void) {
+ uint8_t i = 0, j = GATT_INDEX_INVALID;
+
+ for (i = 0; i < GATT_MAX_PHY_CHANNEL; i++) {
+ if (!gatt_cb.tcb[i].in_use) {
+ j = i;
+ break;
+ }
+ }
+ return j;
+}
+/*******************************************************************************
+ *
+ * Function gatt_allocate_tcb_by_bdaddr
+ *
+ * Description Locate or allocate a new tcb entry for matching bda.
+ *
+ * Returns GATT_INDEX_INVALID if not found. Otherwise index to the tcb.
+ *
+ ******************************************************************************/
+tGATT_TCB* gatt_allocate_tcb_by_bdaddr(BD_ADDR bda, tBT_TRANSPORT transport) {
+ uint8_t i = 0;
+ bool allocated = false;
+ tGATT_TCB* p_tcb = NULL;
+
+ /* search for existing tcb with matching bda */
+ i = gatt_find_i_tcb_by_addr(bda, transport);
+ /* find free tcb */
+ if (i == GATT_INDEX_INVALID) {
+ i = gatt_find_i_tcb_free();
+ allocated = true;
+ }
+ if (i != GATT_INDEX_INVALID) {
+ p_tcb = &gatt_cb.tcb[i];
+
+ if (allocated) {
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+ p_tcb->pending_enc_clcb = fixed_queue_new(SIZE_MAX);
+ p_tcb->pending_ind_q = fixed_queue_new(SIZE_MAX);
+ p_tcb->conf_timer = alarm_new("gatt.conf_timer");
+ p_tcb->ind_ack_timer = alarm_new("gatt.ind_ack_timer");
+ p_tcb->in_use = true;
+ p_tcb->tcb_idx = i;
+ p_tcb->transport = transport;
+ }
+ memcpy(p_tcb->peer_bda, bda, BD_ADDR_LEN);
+ }
+ return p_tcb;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_convert_uuid16_to_uuid128
+ *
+ * Description Convert a 16 bits UUID to be an standard 128 bits one.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+void gatt_convert_uuid16_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint16_t uuid_16) {
+ uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT16_TO_STREAM(p, uuid_16);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_convert_uuid32_to_uuid128
+ *
+ * Description Convert a 32 bits UUID to be an standard 128 bits one.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+void gatt_convert_uuid32_to_uuid128(uint8_t uuid_128[LEN_UUID_128],
+ uint32_t uuid_32) {
+ uint8_t* p = &uuid_128[LEN_UUID_128 - 4];
+
+ memcpy(uuid_128, base_uuid, LEN_UUID_128);
+
+ UINT32_TO_STREAM(p, uuid_32);
+}
+/*******************************************************************************
+ *
+ * Function gatt_uuid_compare
+ *
+ * Description Compare two UUID to see if they are the same.
+ *
+ * Returns true if two uuid match; false otherwise.
+ *
+ ******************************************************************************/
+bool gatt_uuid_compare(tBT_UUID src, tBT_UUID tar) {
+ uint8_t su[LEN_UUID_128], tu[LEN_UUID_128];
+ uint8_t *ps, *pt;
+
+ /* any of the UUID is unspecified */
+ if (src.len == 0 || tar.len == 0) {
+ return true;
+ }
+
+ /* If both are 16-bit, we can do a simple compare */
+ if (src.len == LEN_UUID_16 && tar.len == LEN_UUID_16) {
+ return src.uu.uuid16 == tar.uu.uuid16;
+ }
+
+ /* If both are 32-bit, we can do a simple compare */
+ if (src.len == LEN_UUID_32 && tar.len == LEN_UUID_32) {
+ return src.uu.uuid32 == tar.uu.uuid32;
+ }
+
+ /* One or both of the UUIDs is 128-bit */
+ if (src.len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ gatt_convert_uuid16_to_uuid128(su, src.uu.uuid16);
+ ps = su;
+ } else if (src.len == LEN_UUID_32) {
+ gatt_convert_uuid32_to_uuid128(su, src.uu.uuid32);
+ ps = su;
+ } else
+ ps = src.uu.uuid128;
+
+ if (tar.len == LEN_UUID_16) {
+ /* convert a 16 bits UUID to 128 bits value */
+ gatt_convert_uuid16_to_uuid128(tu, tar.uu.uuid16);
+ pt = tu;
+ } else if (tar.len == LEN_UUID_32) {
+ /* convert a 32 bits UUID to 128 bits value */
+ gatt_convert_uuid32_to_uuid128(tu, tar.uu.uuid32);
+ pt = tu;
+ } else
+ pt = tar.uu.uuid128;
+
+ return (memcmp(ps, pt, LEN_UUID_128) == 0);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_build_uuid_to_stream
+ *
+ * Description Add UUID into stream.
+ *
+ * Returns UUID length.
+ *
+ ******************************************************************************/
+uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, tBT_UUID uuid) {
+ uint8_t* p = *p_dst;
+ uint8_t len = 0;
+
+ if (uuid.len == LEN_UUID_16) {
+ UINT16_TO_STREAM(p, uuid.uu.uuid16);
+ len = LEN_UUID_16;
+ } else if (uuid.len ==
+ LEN_UUID_32) /* always convert 32 bits into 128 bits as alwats */
+ {
+ gatt_convert_uuid32_to_uuid128(p, uuid.uu.uuid32);
+ p += LEN_UUID_128;
+ len = LEN_UUID_128;
+ } else if (uuid.len == LEN_UUID_128) {
+ ARRAY_TO_STREAM(p, uuid.uu.uuid128, LEN_UUID_128);
+ len = LEN_UUID_128;
+ }
+
+ *p_dst = p;
+ return len;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_parse_uuid_from_cmd
+ *
+ * Description Convert a 128 bits UUID into a 16 bits UUID.
+ *
+ * Returns true if command sent, otherwise false.
+ *
+ ******************************************************************************/
+bool gatt_parse_uuid_from_cmd(tBT_UUID* p_uuid_rec, uint16_t uuid_size,
+ uint8_t** p_data) {
+ bool is_base_uuid, ret = true;
+ uint8_t xx;
+ uint8_t* p_uuid = *p_data;
+
+ memset(p_uuid_rec, 0, sizeof(tBT_UUID));
+
+ switch (uuid_size) {
+ case LEN_UUID_16:
+ p_uuid_rec->len = uuid_size;
+ STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
+ *p_data += LEN_UUID_16;
+ break;
+
+ case LEN_UUID_128:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ is_base_uuid = true;
+ for (xx = 0; xx < LEN_UUID_128 - 4; xx++) {
+ if (p_uuid[xx] != base_uuid[xx]) {
+ is_base_uuid = false;
+ break;
+ }
+ }
+ if (is_base_uuid) {
+ if ((p_uuid[LEN_UUID_128 - 1] == 0) &&
+ (p_uuid[LEN_UUID_128 - 2] == 0)) {
+ p_uuid += (LEN_UUID_128 - 4);
+ p_uuid_rec->len = LEN_UUID_16;
+ STREAM_TO_UINT16(p_uuid_rec->uu.uuid16, p_uuid);
+ } else {
+ p_uuid += (LEN_UUID_128 - LEN_UUID_32);
+ p_uuid_rec->len = LEN_UUID_32;
+ STREAM_TO_UINT32(p_uuid_rec->uu.uuid32, p_uuid);
+ }
+ }
+ if (!is_base_uuid) {
+ p_uuid_rec->len = LEN_UUID_128;
+ memcpy(p_uuid_rec->uu.uuid128, p_uuid, LEN_UUID_128);
+ }
+ *p_data += LEN_UUID_128;
+ break;
+
+ /* do not allow 32 bits UUID in ATT PDU now */
+ case LEN_UUID_32:
+ GATT_TRACE_ERROR("DO NOT ALLOW 32 BITS UUID IN ATT PDU");
+ return false;
+ case 0:
+ default:
+ if (uuid_size != 0) ret = false;
+ GATT_TRACE_WARNING("gatt_parse_uuid_from_cmd invalid uuid size");
+ break;
+ }
+
+ return (ret);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_start_rsp_timer
+ *
+ * Description Start a wait_for_response timer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_start_rsp_timer(uint16_t clcb_idx) {
+ tGATT_CLCB* p_clcb = &gatt_cb.clcb[clcb_idx];
+ period_ms_t timeout_ms = GATT_WAIT_FOR_RSP_TIMEOUT_MS;
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_SRVC_ALL) {
+ timeout_ms = GATT_WAIT_FOR_DISC_RSP_TIMEOUT_MS;
+ }
+
+ // TODO: The tGATT_CLCB memory and state management needs cleanup,
+ // and then the timers can be allocated elsewhere.
+ if (p_clcb->gatt_rsp_timer_ent == NULL) {
+ p_clcb->gatt_rsp_timer_ent = alarm_new("gatt.gatt_rsp_timer_ent");
+ }
+ alarm_set_on_queue(p_clcb->gatt_rsp_timer_ent, timeout_ms, gatt_rsp_timeout,
+ p_clcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_start_conf_timer
+ *
+ * Description Start a wait_for_confirmation timer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_start_conf_timer(tGATT_TCB* p_tcb) {
+ alarm_set_on_queue(p_tcb->conf_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
+ gatt_indication_confirmation_timeout, p_tcb,
+ btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_start_ind_ack_timer
+ *
+ * Description start the application ack timer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_start_ind_ack_timer(tGATT_TCB* p_tcb) {
+ /* start notification cache timer */
+ alarm_set_on_queue(p_tcb->ind_ack_timer, GATT_WAIT_FOR_RSP_TIMEOUT_MS,
+ gatt_ind_ack_timeout, p_tcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_rsp_timeout
+ *
+ * Description Called when GATT wait for ATT command response timer expires
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_rsp_timeout(void* data) {
+ tGATT_CLCB* p_clcb = (tGATT_CLCB*)data;
+
+ if (p_clcb == NULL || p_clcb->p_tcb == NULL) {
+ GATT_TRACE_WARNING("%s clcb is already deleted", __func__);
+ return;
+ }
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+ p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+ p_clcb->retry_count < GATT_REQ_RETRY_LIMIT) {
+ uint8_t rsp_code;
+ GATT_TRACE_WARNING("%s retry discovery primary service", __func__);
+ if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code)) {
+ GATT_TRACE_ERROR("%s command queue out of sync, disconnect", __func__);
+ } else {
+ p_clcb->retry_count++;
+ gatt_act_discovery(p_clcb);
+ return;
+ }
+ }
+
+ GATT_TRACE_WARNING("%s disconnecting...", __func__);
+ gatt_disconnect(p_clcb->p_tcb);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_indication_confirmation_timeout
+ *
+ * Description Called when the indication confirmation timer expires
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_indication_confirmation_timeout(void* data) {
+ tGATT_TCB* p_tcb = (tGATT_TCB*)data;
+
+ GATT_TRACE_WARNING("%s disconnecting...", __func__);
+ gatt_disconnect(p_tcb);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_ind_ack_timeout
+ *
+ * Description Called when GATT wait for ATT handle confirmation timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_ind_ack_timeout(void* data) {
+ tGATT_TCB* p_tcb = (tGATT_TCB*)data;
+
+ GATT_TRACE_WARNING("%s send ack now", __func__);
+
+ if (p_tcb != NULL) p_tcb->ind_count = 0;
+
+ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
+}
+/*******************************************************************************
+ *
+ * Description Search for a service that owns a specific handle.
+ *
+ * Returns GATT_MAX_SR_PROFILES if not found. Otherwise the index of
+ * the service.
+ *
+ ******************************************************************************/
+std::list<tGATT_SRV_LIST_ELEM>::iterator gatt_sr_find_i_rcb_by_handle(
+ uint16_t handle) {
+ auto it = gatt_cb.srv_list_info->begin();
+
+ for (; it != gatt_cb.srv_list_info->end(); it++) {
+ if (it->s_hdl <= handle && it->e_hdl >= handle) {
+ return it;
+ }
+ }
+
+ return it;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_get_sec_info
+ *
+ * Description Get the security flag and key size information for the peer
+ * device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_sr_get_sec_info(BD_ADDR rem_bda, tBT_TRANSPORT transport,
+ uint8_t* p_sec_flag, uint8_t* p_key_size) {
+ uint8_t sec_flag = 0;
+
+ BTM_GetSecurityFlagsByTransport(rem_bda, &sec_flag, transport);
+
+ sec_flag &= (GATT_SEC_FLAG_LKEY_UNAUTHED | GATT_SEC_FLAG_LKEY_AUTHED |
+ GATT_SEC_FLAG_ENCRYPTED);
+
+ *p_key_size = btm_ble_read_sec_key_size(rem_bda);
+ *p_sec_flag = sec_flag;
+}
+/*******************************************************************************
+ *
+ * Function gatt_sr_send_req_callback
+ *
+ * Description
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_sr_send_req_callback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ if (!p_reg) {
+ GATT_TRACE_ERROR("p_reg not found discard request");
+ return;
+ }
+
+ if (p_reg->in_use && p_reg->app_cb.p_req_cb) {
+ (*p_reg->app_cb.p_req_cb)(conn_id, trans_id, type, p_data);
+ } else {
+ GATT_TRACE_WARNING("Call back not found for application conn_id=%d",
+ conn_id);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_send_error_rsp
+ *
+ * Description This function sends an error response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tGATT_STATUS gatt_send_error_rsp(tGATT_TCB* p_tcb, uint8_t err_code,
+ uint8_t op_code, uint16_t handle, bool deq) {
+ tGATT_ERROR error;
+ tGATT_STATUS status;
+ BT_HDR* p_buf;
+
+ error.cmd_code = op_code;
+ error.reason = err_code;
+ error.handle = handle;
+
+ p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_ERROR, (tGATT_SR_MSG*)&error);
+ if (p_buf != NULL) {
+ status = attp_send_sr_msg(p_tcb, p_buf);
+ } else
+ status = GATT_INSUF_RESOURCE;
+
+ if (deq) gatt_dequeue_sr_cmd(p_tcb);
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_sdp_record
+ *
+ * Description This function add a SDP record for a GATT primary service
+ *
+ * Returns 0 if error else sdp handle for the record.
+ *
+ ******************************************************************************/
+uint32_t gatt_add_sdp_record(tBT_UUID* p_uuid, uint16_t start_hdl,
+ uint16_t end_hdl) {
+ tSDP_PROTOCOL_ELEM proto_elem_list[2];
+ uint32_t sdp_handle;
+ uint16_t list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ uint8_t buff[60];
+ uint8_t* p = buff;
+
+ GATT_TRACE_DEBUG("gatt_add_sdp_record s_hdl=0x%x s_hdl=0x%x", start_hdl,
+ end_hdl);
+
+ sdp_handle = SDP_CreateRecord();
+ if (sdp_handle == 0) return 0;
+
+ switch (p_uuid->len) {
+ case LEN_UUID_16:
+ SDP_AddServiceClassIdList(sdp_handle, 1, &p_uuid->uu.uuid16);
+ break;
+
+ case LEN_UUID_32:
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+ UINT32_TO_BE_STREAM(p, p_uuid->uu.uuid32);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff);
+ break;
+
+ case LEN_UUID_128:
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM_REVERSE(p, p_uuid->uu.uuid128, LEN_UUID_128);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - buff), buff);
+ break;
+
+ default:
+ GATT_TRACE_ERROR("inavlid UUID len=%d", p_uuid->len);
+ SDP_DeleteRecord(sdp_handle);
+ return 0;
+ break;
+ }
+
+ /*** Fill out the protocol element sequence for SDP ***/
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 1;
+ proto_elem_list[0].params[0] = BT_PSM_ATT;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_ATT;
+ proto_elem_list[1].num_params = 2;
+ proto_elem_list[1].params[0] = start_hdl;
+ proto_elem_list[1].params[1] = end_hdl;
+
+ SDP_AddProtocolList(sdp_handle, 2, proto_elem_list);
+
+ /* Make the service browseable */
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &list);
+
+ return (sdp_handle);
+}
+
+#if GATT_CONFORMANCE_TESTING == TRUE
+/*******************************************************************************
+ *
+ * Function gatt_set_err_rsp
+ *
+ * Description This function is called to set the test confirm value
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void gatt_set_err_rsp(bool enable, uint8_t req_op_code, uint8_t err_status) {
+ GATT_TRACE_DEBUG("gatt_set_err_rsp enable=%d op_code=%d, err_status=%d",
+ enable, req_op_code, err_status);
+ gatt_cb.enable_err_rsp = enable;
+ gatt_cb.req_op_code = req_op_code;
+ gatt_cb.err_status = err_status;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function gatt_get_regcb
+ *
+ * Description The function returns the registration control block.
+ *
+ * Returns pointer to the registration control block or NULL
+ *
+ ******************************************************************************/
+tGATT_REG* gatt_get_regcb(tGATT_IF gatt_if) {
+ uint8_t ii = (uint8_t)gatt_if;
+ tGATT_REG* p_reg = NULL;
+
+ if (ii < 1 || ii > GATT_MAX_APPS) {
+ GATT_TRACE_WARNING("gatt_if out of range [ = %d]", ii);
+ return NULL;
+ }
+
+ // Index for cl_rcb is always 1 less than gatt_if.
+ p_reg = &gatt_cb.cl_rcb[ii - 1];
+
+ if (!p_reg->in_use) {
+ GATT_TRACE_WARNING("gatt_if found but not in use.");
+ return NULL;
+ }
+
+ return p_reg;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_is_clcb_allocated
+ *
+ * Description The function check clcb for conn_id is allocated or not
+ *
+ * Returns True already allocated
+ *
+ ******************************************************************************/
+
+bool gatt_is_clcb_allocated(uint16_t conn_id) {
+ uint8_t i = 0;
+ bool is_allocated = false;
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i++) {
+ if (gatt_cb.clcb[i].in_use && (gatt_cb.clcb[i].conn_id == conn_id)) {
+ is_allocated = true;
+ break;
+ }
+ }
+
+ return is_allocated;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_clcb_alloc
+ *
+ * Description The function allocates a GATT connection link control block
+ *
+ * Returns NULL if not found. Otherwise pointer to the connection link
+ * block.
+ *
+ ******************************************************************************/
+tGATT_CLCB* gatt_clcb_alloc(uint16_t conn_id) {
+ uint8_t i = 0;
+ tGATT_CLCB* p_clcb = NULL;
+ tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
+ uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
+ tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
+ tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i++) {
+ if (!gatt_cb.clcb[i].in_use) {
+ p_clcb = &gatt_cb.clcb[i];
+
+ p_clcb->in_use = true;
+ p_clcb->conn_id = conn_id;
+ p_clcb->clcb_idx = i;
+ p_clcb->p_reg = p_reg;
+ p_clcb->p_tcb = p_tcb;
+ break;
+ }
+ }
+ return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_clcb_dealloc
+ *
+ * Description The function de-allocates a GATT connection link control
+ * block
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_clcb_dealloc(tGATT_CLCB* p_clcb) {
+ if (p_clcb && p_clcb->in_use) {
+ alarm_free(p_clcb->gatt_rsp_timer_ent);
+ memset(p_clcb, 0, sizeof(tGATT_CLCB));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_tcb_by_cid
+ *
+ * Description The function searches for an empty entry
+ * in registration info table for GATT client
+ *
+ * Returns NULL if not found. Otherwise pointer to the rcb.
+ *
+ ******************************************************************************/
+tGATT_TCB* gatt_find_tcb_by_cid(uint16_t lcid) {
+ uint16_t xx = 0;
+ tGATT_TCB* p_tcb = NULL;
+
+ for (xx = 0; xx < GATT_MAX_PHY_CHANNEL; xx++) {
+ if (gatt_cb.tcb[xx].in_use && gatt_cb.tcb[xx].att_lcid == lcid) {
+ p_tcb = &gatt_cb.tcb[xx];
+ break;
+ }
+ }
+ return p_tcb;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_num_apps_hold_link
+ *
+ * Description The function find the number of applcaitions is holding the
+ * link
+ *
+ * Returns total number of applications holding this acl link.
+ *
+ ******************************************************************************/
+uint8_t gatt_num_apps_hold_link(tGATT_TCB* p_tcb) {
+ uint8_t i, num = 0;
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->app_hold_link[i]) num++;
+ }
+
+ GATT_TRACE_DEBUG("gatt_num_apps_hold_link num=%d", num);
+ return num;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_num_clcb_by_bd_addr
+ *
+ * Description The function searches all LCB with macthing bd address
+ *
+ * Returns total number of clcb found.
+ *
+ ******************************************************************************/
+uint8_t gatt_num_clcb_by_bd_addr(BD_ADDR bda) {
+ uint8_t i, num = 0;
+
+ for (i = 0; i < GATT_CL_MAX_LCB; i++) {
+ if (gatt_cb.clcb[i].in_use &&
+ memcmp(gatt_cb.clcb[i].p_tcb->peer_bda, bda, BD_ADDR_LEN) == 0)
+ num++;
+ }
+ return num;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_update_cback_cnt
+ *
+ * Description The function searches all LCB with macthing bd address
+ *
+ * Returns total number of clcb found.
+ *
+ ******************************************************************************/
+void gatt_sr_copy_prep_cnt_to_cback_cnt(tGATT_TCB* p_tcb) {
+ uint8_t i;
+
+ if (p_tcb) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->prep_cnt[i]) {
+ p_tcb->sr_cmd.cback_cnt[i] = 1;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_is_cback_cnt_zero
+ *
+ * Description The function searches all LCB with macthing bd address
+ *
+ * Returns True if thetotal application callback count is zero
+ *
+ ******************************************************************************/
+bool gatt_sr_is_cback_cnt_zero(tGATT_TCB* p_tcb) {
+ bool status = true;
+ uint8_t i;
+
+ if (p_tcb) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->sr_cmd.cback_cnt[i]) {
+ status = false;
+ break;
+ }
+ }
+ } else {
+ status = false;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_is_prep_cnt_zero
+ *
+ * Description Check the prepare write request count is zero or not
+ *
+ * Returns True no prepare write request
+ *
+ ******************************************************************************/
+bool gatt_sr_is_prep_cnt_zero(tGATT_TCB* p_tcb) {
+ bool status = true;
+ uint8_t i;
+
+ if (p_tcb) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->prep_cnt[i]) {
+ status = false;
+ break;
+ }
+ }
+ } else {
+ status = false;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_reset_cback_cnt
+ *
+ * Description Reset the application callback count to zero
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_sr_reset_cback_cnt(tGATT_TCB* p_tcb) {
+ uint8_t i;
+
+ if (p_tcb) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ p_tcb->sr_cmd.cback_cnt[i] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_reset_prep_cnt
+ *
+ * Description Reset the prep write count to zero
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_sr_reset_prep_cnt(tGATT_TCB* p_tcb) {
+ uint8_t i;
+ if (p_tcb) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ p_tcb->prep_cnt[i] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_update_cback_cnt
+ *
+ * Description Update the teh applicaiton callback count
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_sr_update_cback_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if, bool is_inc,
+ bool is_reset_first) {
+ uint8_t idx = ((uint8_t)gatt_if) - 1;
+
+ if (p_tcb) {
+ if (is_reset_first) {
+ gatt_sr_reset_cback_cnt(p_tcb);
+ }
+ if (is_inc) {
+ p_tcb->sr_cmd.cback_cnt[idx]++;
+ } else {
+ if (p_tcb->sr_cmd.cback_cnt[idx]) {
+ p_tcb->sr_cmd.cback_cnt[idx]--;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_sr_update_prep_cnt
+ *
+ * Description Update the teh prepare write request count
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_sr_update_prep_cnt(tGATT_TCB* p_tcb, tGATT_IF gatt_if, bool is_inc,
+ bool is_reset_first) {
+ uint8_t idx = ((uint8_t)gatt_if) - 1;
+
+ GATT_TRACE_DEBUG(
+ "gatt_sr_update_prep_cnt tcb idx=%d gatt_if=%d is_inc=%d "
+ "is_reset_first=%d",
+ p_tcb->tcb_idx, gatt_if, is_inc, is_reset_first);
+
+ if (p_tcb) {
+ if (is_reset_first) {
+ gatt_sr_reset_prep_cnt(p_tcb);
+ }
+ if (is_inc) {
+ p_tcb->prep_cnt[idx]++;
+ } else {
+ if (p_tcb->prep_cnt[idx]) {
+ p_tcb->prep_cnt[idx]--;
+ }
+ }
+ }
+}
+/*******************************************************************************
+ *
+ * Function gatt_cancel_open
+ *
+ * Description Cancel open request
+ *
+ * Returns Boolean
+ *
+ ******************************************************************************/
+bool gatt_cancel_open(tGATT_IF gatt_if, BD_ADDR bda) {
+ tGATT_TCB* p_tcb = NULL;
+ bool status = true;
+
+ p_tcb = gatt_find_tcb_by_addr(bda, BT_TRANSPORT_LE);
+
+ if (p_tcb) {
+ if (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) {
+ GATT_TRACE_ERROR(
+ "GATT_CancelConnect - link connected Too late to cancel");
+ status = false;
+ } else {
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
+ if (!gatt_num_apps_hold_link(p_tcb)) {
+ gatt_disconnect(p_tcb);
+ }
+ }
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_app_hold_link
+ *
+ * Description find the applicaiton that is holding the specified link
+ *
+ * Returns Boolean
+ *
+ ******************************************************************************/
+bool gatt_find_app_hold_link(tGATT_TCB* p_tcb, uint8_t start_idx,
+ uint8_t* p_found_idx, tGATT_IF* p_gatt_if) {
+ uint8_t i;
+ bool found = false;
+
+ for (i = start_idx; i < GATT_MAX_APPS; i++) {
+ if (p_tcb->app_hold_link[i]) {
+ *p_gatt_if = gatt_cb.clcb[i].p_reg->gatt_if;
+ *p_found_idx = i;
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_cmd_enq
+ *
+ * Description Enqueue this command.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+bool gatt_cmd_enq(tGATT_TCB* p_tcb, uint16_t clcb_idx, bool to_send,
+ uint8_t op_code, BT_HDR* p_buf) {
+ tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->next_slot_inq];
+
+ p_cmd->to_send = to_send; /* waiting to be sent */
+ p_cmd->op_code = op_code;
+ p_cmd->p_cmd = p_buf;
+ p_cmd->clcb_idx = clcb_idx;
+
+ if (!to_send) {
+ p_tcb->pending_cl_req = p_tcb->next_slot_inq;
+ }
+
+ p_tcb->next_slot_inq++;
+ p_tcb->next_slot_inq %= GATT_CL_MAX_LCB;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_cmd_dequeue
+ *
+ * Description dequeue the command in the client CCB command queue.
+ *
+ * Returns total number of clcb found.
+ *
+ ******************************************************************************/
+tGATT_CLCB* gatt_cmd_dequeue(tGATT_TCB* p_tcb, uint8_t* p_op_code) {
+ tGATT_CMD_Q* p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
+ tGATT_CLCB* p_clcb = NULL;
+
+ if (p_tcb->pending_cl_req != p_tcb->next_slot_inq) {
+ p_clcb = &gatt_cb.clcb[p_cmd->clcb_idx];
+
+ *p_op_code = p_cmd->op_code;
+
+ p_tcb->pending_cl_req++;
+ p_tcb->pending_cl_req %= GATT_CL_MAX_LCB;
+ }
+
+ return p_clcb;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_send_write_msg
+ *
+ * Description This real function send out the ATT message for write.
+ *
+ * Returns status code
+ *
+ ******************************************************************************/
+uint8_t gatt_send_write_msg(tGATT_TCB* p_tcb, uint16_t clcb_idx,
+ uint8_t op_code, uint16_t handle, uint16_t len,
+ uint16_t offset, uint8_t* p_data) {
+ tGATT_CL_MSG msg;
+
+ msg.attr_value.handle = handle;
+ msg.attr_value.len = len;
+ msg.attr_value.offset = offset;
+
+ memcpy(msg.attr_value.value, p_data, len);
+
+ /* write by handle */
+ return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_act_send_browse
+ *
+ * Description This function ends a browse command request, including read
+ * information request and read by type request.
+ *
+ * Returns status code
+ *
+ ******************************************************************************/
+uint8_t gatt_act_send_browse(tGATT_TCB* p_tcb, uint16_t index, uint8_t op,
+ uint16_t s_handle, uint16_t e_handle,
+ tBT_UUID uuid) {
+ tGATT_CL_MSG msg;
+
+ msg.browse.s_handle = s_handle;
+ msg.browse.e_handle = e_handle;
+ memcpy(&msg.browse.uuid, &uuid, sizeof(tBT_UUID));
+
+ /* write by handle */
+ return attp_send_cl_msg(p_tcb, index, op, &msg);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_end_operation
+ *
+ * Description This function ends a discovery, send callback and finalize
+ * some control value.
+ *
+ * Returns 16 bits uuid.
+ *
+ ******************************************************************************/
+void gatt_end_operation(tGATT_CLCB* p_clcb, tGATT_STATUS status, void* p_data) {
+ tGATT_CL_COMPLETE cb_data;
+ tGATT_CMPL_CBACK* p_cmpl_cb =
+ (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_cmpl_cb : NULL;
+ uint8_t op = p_clcb->operation, disc_type = GATT_DISC_MAX;
+ tGATT_DISC_CMPL_CB* p_disc_cmpl_cb =
+ (p_clcb->p_reg) ? p_clcb->p_reg->app_cb.p_disc_cmpl_cb : NULL;
+ uint16_t conn_id;
+ uint8_t operation;
+
+ GATT_TRACE_DEBUG("gatt_end_operation status=%d op=%d subtype=%d", status,
+ p_clcb->operation, p_clcb->op_subtype);
+ memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+
+ if (p_cmpl_cb != NULL && p_clcb->operation != 0) {
+ if (p_clcb->operation == GATTC_OPTYPE_READ) {
+ cb_data.att_value.handle = p_clcb->s_handle;
+ cb_data.att_value.len = p_clcb->counter;
+
+ if (p_data && p_clcb->counter)
+ memcpy(cb_data.att_value.value, p_data, cb_data.att_value.len);
+ }
+
+ if (p_clcb->operation == GATTC_OPTYPE_WRITE) {
+ memset(&cb_data.att_value, 0, sizeof(tGATT_VALUE));
+ cb_data.handle = cb_data.att_value.handle = p_clcb->s_handle;
+ if (p_clcb->op_subtype == GATT_WRITE_PREPARE) {
+ if (p_data) {
+ cb_data.att_value = *((tGATT_VALUE*)p_data);
+ } else {
+ GATT_TRACE_DEBUG("Rcv Prepare write rsp but no data");
+ }
+ }
+ }
+
+ if (p_clcb->operation == GATTC_OPTYPE_CONFIG)
+ cb_data.mtu = p_clcb->p_tcb->payload_size;
+
+ if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY) {
+ disc_type = p_clcb->op_subtype;
+ }
+ }
+
+ osi_free_and_reset((void**)&p_clcb->p_attr_buf);
+
+ operation = p_clcb->operation;
+ conn_id = p_clcb->conn_id;
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+
+ gatt_clcb_dealloc(p_clcb);
+
+ if (p_disc_cmpl_cb && (op == GATTC_OPTYPE_DISCOVERY))
+ (*p_disc_cmpl_cb)(conn_id, disc_type, status);
+ else if (p_cmpl_cb && op)
+ (*p_cmpl_cb)(conn_id, op, status, &cb_data);
+ else
+ GATT_TRACE_WARNING(
+ "gatt_end_operation not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p",
+ operation, p_disc_cmpl_cb, p_cmpl_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_cleanup_upon_disc
+ *
+ * Description This function cleans up the control blocks when L2CAP
+ * channel disconnect.
+ *
+ * Returns 16 bits uuid.
+ *
+ ******************************************************************************/
+void gatt_cleanup_upon_disc(BD_ADDR bda, uint16_t reason,
+ tBT_TRANSPORT transport) {
+ tGATT_TCB* p_tcb = NULL;
+ tGATT_CLCB* p_clcb;
+ uint8_t i;
+ uint16_t conn_id;
+ tGATT_REG* p_reg = NULL;
+
+ GATT_TRACE_DEBUG("gatt_cleanup_upon_disc ");
+
+ p_tcb = gatt_find_tcb_by_addr(bda, transport);
+ if (p_tcb != NULL) {
+ GATT_TRACE_DEBUG("found p_tcb ");
+ gatt_set_ch_state(p_tcb, GATT_CH_CLOSE);
+ for (i = 0; i < GATT_CL_MAX_LCB; i++) {
+ p_clcb = &gatt_cb.clcb[i];
+ if (p_clcb->in_use && p_clcb->p_tcb == p_tcb) {
+ alarm_cancel(p_clcb->gatt_rsp_timer_ent);
+ GATT_TRACE_DEBUG("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id,
+ p_clcb->clcb_idx);
+ if (p_clcb->operation != GATTC_OPTYPE_NONE)
+ gatt_end_operation(p_clcb, GATT_ERROR, NULL);
+
+ gatt_clcb_dealloc(p_clcb);
+ }
+ }
+
+ alarm_free(p_tcb->ind_ack_timer);
+ p_tcb->ind_ack_timer = NULL;
+ alarm_free(p_tcb->conf_timer);
+ p_tcb->conf_timer = NULL;
+ gatt_free_pending_ind(p_tcb);
+ gatt_free_pending_enc_queue(p_tcb);
+ fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, NULL);
+ p_tcb->sr_cmd.multi_rsp_q = NULL;
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ p_reg = &gatt_cb.cl_rcb[i];
+ if (p_reg->in_use && p_reg->app_cb.p_conn_cb) {
+ conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
+ GATT_TRACE_DEBUG("found p_reg tcb_idx=%d gatt_if=%d conn_id=0x%x",
+ p_tcb->tcb_idx, p_reg->gatt_if, conn_id);
+ (*p_reg->app_cb.p_conn_cb)(p_reg->gatt_if, bda, conn_id, false, reason,
+ transport);
+ }
+ }
+ memset(p_tcb, 0, sizeof(tGATT_TCB));
+ }
+ GATT_TRACE_DEBUG("exit gatt_cleanup_upon_disc ");
+}
+/*******************************************************************************
+ *
+ * Function gatt_dbg_req_op_name
+ *
+ * Description Get op code description name, for debug information.
+ *
+ * Returns uint8_t *: name of the operation.
+ *
+ ******************************************************************************/
+uint8_t* gatt_dbg_op_name(uint8_t op_code) {
+ uint8_t pseduo_op_code_idx = op_code & (~GATT_WRITE_CMD_MASK);
+
+ if (op_code == GATT_CMD_WRITE) {
+ pseduo_op_code_idx = 0x14; /* just an index to op_code_name */
+ }
+
+ if (op_code == GATT_SIGN_CMD_WRITE) {
+ pseduo_op_code_idx = 0x15; /* just an index to op_code_name */
+ }
+
+ if (pseduo_op_code_idx <= GATT_OP_CODE_MAX)
+ return (uint8_t*)op_code_name[pseduo_op_code_idx];
+ else
+ return (uint8_t*)"Op Code Exceed Max";
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_dbg_display_uuid
+ *
+ * Description Disaplay the UUID
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void gatt_dbg_display_uuid(tBT_UUID bt_uuid) {
+ char str_buf[50];
+
+ if (bt_uuid.len == LEN_UUID_16) {
+ snprintf(str_buf, sizeof(str_buf), "0x%04x", bt_uuid.uu.uuid16);
+ } else if (bt_uuid.len == LEN_UUID_32) {
+ snprintf(str_buf, sizeof(str_buf), "0x%08x",
+ (unsigned int)bt_uuid.uu.uuid32);
+ } else if (bt_uuid.len == LEN_UUID_128) {
+ int x = snprintf(
+ str_buf, sizeof(str_buf), "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[15], bt_uuid.uu.uuid128[14], bt_uuid.uu.uuid128[13],
+ bt_uuid.uu.uuid128[12], bt_uuid.uu.uuid128[11], bt_uuid.uu.uuid128[10],
+ bt_uuid.uu.uuid128[9], bt_uuid.uu.uuid128[8]);
+ snprintf(
+ &str_buf[x], sizeof(str_buf) - x, "%02x%02x%02x%02x%02x%02x%02x%02x",
+ bt_uuid.uu.uuid128[7], bt_uuid.uu.uuid128[6], bt_uuid.uu.uuid128[5],
+ bt_uuid.uu.uuid128[4], bt_uuid.uu.uuid128[3], bt_uuid.uu.uuid128[2],
+ bt_uuid.uu.uuid128[1], bt_uuid.uu.uuid128[0]);
+ } else
+ strlcpy(str_buf, "Unknown UUID 0", sizeof(str_buf));
+
+ GATT_TRACE_DEBUG("UUID=[%s]", str_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_is_bg_dev_for_app
+ *
+ * Description Is this one of the background devices for the application
+ *
+ * Returns true if it is, otherwise false
+ *
+ ******************************************************************************/
+bool gatt_is_bg_dev_for_app(tGATT_BG_CONN_DEV* p_dev, tGATT_IF gatt_if) {
+ uint8_t i;
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_dev->in_use && (p_dev->gatt_if[i] == gatt_if)) {
+ return true;
+ }
+ }
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function gatt_find_bg_dev
+ *
+ * Description find background connection device from the list.
+ *
+ * Returns pointer to the device record
+ *
+ ******************************************************************************/
+tGATT_BG_CONN_DEV* gatt_find_bg_dev(BD_ADDR remote_bda) {
+ tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
+ uint8_t i;
+
+ for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
+ if (p_dev_list->in_use &&
+ !memcmp(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN)) {
+ return p_dev_list;
+ }
+ }
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function gatt_alloc_bg_dev
+ *
+ * Description allocate a background connection device record
+ *
+ * Returns pointer to the device record
+ *
+ ******************************************************************************/
+tGATT_BG_CONN_DEV* gatt_alloc_bg_dev(BD_ADDR remote_bda) {
+ tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
+ uint8_t i;
+
+ for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
+ if (!p_dev_list->in_use) {
+ p_dev_list->in_use = true;
+ memcpy(p_dev_list->remote_bda, remote_bda, BD_ADDR_LEN);
+
+ return p_dev_list;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_bg_dev_list
+ *
+ * Description Add/remove a device from the background connection list
+ *
+ * Returns true if device added to the list; false failed
+ *
+ ******************************************************************************/
+bool gatt_add_bg_dev_list(tGATT_REG* p_reg, BD_ADDR bd_addr) {
+ tGATT_IF gatt_if = p_reg->gatt_if;
+ tGATT_BG_CONN_DEV* p_dev = NULL;
+ uint8_t i;
+ bool ret = false;
+
+ p_dev = gatt_find_bg_dev(bd_addr);
+ if (p_dev == NULL) {
+ p_dev = gatt_alloc_bg_dev(bd_addr);
+ }
+
+ if (p_dev) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_dev->gatt_if[i] == gatt_if) {
+ GATT_TRACE_ERROR("device already in iniator white list");
+ return true;
+ } else if (p_dev->gatt_if[i] == 0) {
+ p_dev->gatt_if[i] = gatt_if;
+ if (i == 0)
+ ret = BTM_BleUpdateBgConnDev(true, bd_addr);
+ else
+ ret = true;
+ break;
+ }
+ }
+ } else {
+ GATT_TRACE_ERROR("no device record available");
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_remove_bg_dev_for_app
+ *
+ * Description Remove the application interface for the specified
+ * background device
+ *
+ * Returns Boolean
+ *
+ ******************************************************************************/
+bool gatt_remove_bg_dev_for_app(tGATT_IF gatt_if, BD_ADDR bd_addr) {
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+ bool status;
+
+ if (p_tcb) gatt_update_app_use_link_flag(gatt_if, p_tcb, false, false);
+ status = gatt_update_auto_connect_dev(gatt_if, false, bd_addr);
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_get_num_apps_for_bg_dev
+ *
+ * Description Get the number of applciations for the specified background
+ * device
+ *
+ * Returns uint8_t total number fo applications
+ *
+ ******************************************************************************/
+uint8_t gatt_get_num_apps_for_bg_dev(BD_ADDR bd_addr) {
+ tGATT_BG_CONN_DEV* p_dev = NULL;
+ uint8_t i;
+ uint8_t cnt = 0;
+
+ p_dev = gatt_find_bg_dev(bd_addr);
+ if (p_dev != NULL) {
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_dev->gatt_if[i]) cnt++;
+ }
+ }
+ return cnt;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_find_app_for_bg_dev
+ *
+ * Description Find the application interface for the specified background
+ * device
+ *
+ * Returns Boolean
+ *
+ ******************************************************************************/
+bool gatt_find_app_for_bg_dev(BD_ADDR bd_addr, tGATT_IF* p_gatt_if) {
+ tGATT_BG_CONN_DEV* p_dev = NULL;
+ uint8_t i;
+ bool ret = false;
+
+ p_dev = gatt_find_bg_dev(bd_addr);
+ if (p_dev == NULL) {
+ return ret;
+ }
+
+ for (i = 0; i < GATT_MAX_APPS; i++) {
+ if (p_dev->gatt_if[i] != 0) {
+ *p_gatt_if = p_dev->gatt_if[i];
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_remove_bg_dev_from_list
+ *
+ * Description add/remove device from the back ground connection device
+ * list or listening to advertising list.
+ *
+ * Returns pointer to the device record
+ *
+ ******************************************************************************/
+bool gatt_remove_bg_dev_from_list(tGATT_REG* p_reg, BD_ADDR bd_addr) {
+ tGATT_IF gatt_if = p_reg->gatt_if;
+ tGATT_BG_CONN_DEV* p_dev = NULL;
+ uint8_t i, j;
+ bool ret = false;
+
+ p_dev = gatt_find_bg_dev(bd_addr);
+ if (p_dev == NULL) {
+ return ret;
+ }
+
+ for (i = 0; i < GATT_MAX_APPS && (p_dev->gatt_if[i] > 0); i++) {
+ if (p_dev->gatt_if[i] == gatt_if) {
+ p_dev->gatt_if[i] = 0;
+ /* move all element behind one forward */
+ for (j = i + 1; j < GATT_MAX_APPS; j++)
+ p_dev->gatt_if[j - 1] = p_dev->gatt_if[j];
+
+ if (p_dev->gatt_if[0] == 0)
+ ret = BTM_BleUpdateBgConnDev(false, p_dev->remote_bda);
+ else
+ ret = true;
+
+ break;
+ }
+ }
+
+ if (i != GATT_MAX_APPS && p_dev->gatt_if[0] == 0) {
+ memset(p_dev, 0, sizeof(tGATT_BG_CONN_DEV));
+ }
+
+ return ret;
+}
+/*******************************************************************************
+ *
+ * Function gatt_deregister_bgdev_list
+ *
+ * Description deregister all related back ground connetion device.
+ *
+ * Returns pointer to the device record
+ *
+ ******************************************************************************/
+void gatt_deregister_bgdev_list(tGATT_IF gatt_if) {
+ tGATT_BG_CONN_DEV* p_dev_list = &gatt_cb.bgconn_dev[0];
+ uint8_t i, j, k;
+
+ /* update the BG conn device list */
+ for (i = 0; i < GATT_MAX_BG_CONN_DEV; i++, p_dev_list++) {
+ if (p_dev_list->in_use) {
+ for (j = 0; j < GATT_MAX_APPS; j++) {
+ if (p_dev_list->gatt_if[j] == 0) break;
+
+ if (p_dev_list->gatt_if[j] == gatt_if) {
+ for (k = j + 1; k < GATT_MAX_APPS; k++)
+ p_dev_list->gatt_if[k - 1] = p_dev_list->gatt_if[k];
+
+ if (p_dev_list->gatt_if[0] == 0)
+ BTM_BleUpdateBgConnDev(false, p_dev_list->remote_bda);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_reset_bgdev_list
+ *
+ * Description reset bg device list
+ *
+ * Returns pointer to the device record
+ *
+ ******************************************************************************/
+void gatt_reset_bgdev_list(void) {
+ memset(&gatt_cb.bgconn_dev, 0,
+ sizeof(tGATT_BG_CONN_DEV) * GATT_MAX_BG_CONN_DEV);
+}
+/*******************************************************************************
+ *
+ * Function gatt_update_auto_connect_dev
+ *
+ * Description This function add or remove a device for background
+ * connection procedure.
+ *
+ * Parameters gatt_if: Application ID.
+ * add: add peer device
+ * bd_addr: peer device address.
+ *
+ * Returns true if connection started; false otherwise.
+ *
+ ******************************************************************************/
+bool gatt_update_auto_connect_dev(tGATT_IF gatt_if, bool add, BD_ADDR bd_addr) {
+ bool ret = false;
+ tGATT_REG* p_reg;
+ tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
+
+ GATT_TRACE_API("gatt_update_auto_connect_dev ");
+ /* Make sure app is registered */
+ p_reg = gatt_get_regcb(gatt_if);
+ if (p_reg == NULL) {
+ GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered",
+ gatt_if);
+ return (false);
+ }
+
+ if (add) {
+ ret = gatt_add_bg_dev_list(p_reg, bd_addr);
+
+ if (ret && p_tcb != NULL) {
+ /* if a connected device, update the link holding number */
+ gatt_update_app_use_link_flag(gatt_if, p_tcb, true, true);
+ }
+ } else {
+ ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr);
+ }
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function gatt_add_pending_new_srv_start
+ *
+ * Description Add a pending new srv start to the new service start queue
+ *
+ * Returns Pointer to the new service start buffer, NULL no buffer available
+ *
+ ******************************************************************************/
+tGATT_PENDING_ENC_CLCB* gatt_add_pending_enc_channel_clcb(tGATT_TCB* p_tcb,
+ tGATT_CLCB* p_clcb) {
+ tGATT_PENDING_ENC_CLCB* p_buf =
+ (tGATT_PENDING_ENC_CLCB*)osi_malloc(sizeof(tGATT_PENDING_ENC_CLCB));
+
+ GATT_TRACE_DEBUG("%s", __func__);
+ GATT_TRACE_DEBUG("enqueue a new pending encryption channel clcb");
+
+ p_buf->p_clcb = p_clcb;
+ fixed_queue_enqueue(p_tcb->pending_enc_clcb, p_buf);
+
+ return p_buf;
+}
diff --git a/mtkbt/code/bt/stack/hcic/hciblecmds.cc b/mtkbt/code/bt/stack/hcic/hciblecmds.cc
new file mode 100755
index 0000000..330764b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hcic/hciblecmds.cc
@@ -0,0 +1,798 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains function of the HCIC unit to format and send HCI
+ * commands.
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include <base/bind.h>
+#include <stddef.h>
+#include <string.h>
+
+void btsnd_hcic_ble_set_local_used_feat(uint8_t feat_set[8]) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_USED_FEAT_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_LOCAL_SPT_FEAT);
+ ARRAY_TO_STREAM(pp, feat_set, HCIC_PARAM_SIZE_SET_USED_FEAT_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_random_addr(BD_ADDR random_bda) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_RANDOM_ADDR);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD);
+
+ BDADDR_TO_STREAM(pp, random_bda);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_write_adv_params(uint16_t adv_int_min, uint16_t adv_int_max,
+ uint8_t adv_type, uint8_t addr_type_own,
+ uint8_t addr_type_dir, BD_ADDR direct_bda,
+ uint8_t channel_map,
+ uint8_t adv_filter_policy) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_ADV_PARAMS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS);
+
+ UINT16_TO_STREAM(pp, adv_int_min);
+ UINT16_TO_STREAM(pp, adv_int_max);
+ UINT8_TO_STREAM(pp, adv_type);
+ UINT8_TO_STREAM(pp, addr_type_own);
+ UINT8_TO_STREAM(pp, addr_type_dir);
+ BDADDR_TO_STREAM(pp, direct_bda);
+ UINT8_TO_STREAM(pp, channel_map);
+ UINT8_TO_STREAM(pp, adv_filter_policy);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+void btsnd_hcic_ble_read_adv_chnl_tx_power(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_READ_ADV_CHNL_TX_POWER);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_adv_data(uint8_t data_len, uint8_t* p_data) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_ADV_DATA);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA);
+
+ if (p_data != NULL && data_len > 0) {
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA)
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA;
+
+ UINT8_TO_STREAM(pp, data_len);
+
+ ARRAY_TO_STREAM(pp, p_data, data_len);
+ }
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+void btsnd_hcic_ble_set_scan_rsp_data(uint8_t data_len, uint8_t* p_scan_rsp) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_SCAN_RSP_DATA);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP + 1);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP);
+
+ if (p_scan_rsp != NULL && data_len > 0) {
+ if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP)
+ data_len = HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP;
+
+ UINT8_TO_STREAM(pp, data_len);
+
+ ARRAY_TO_STREAM(pp, p_scan_rsp, data_len);
+ }
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_adv_enable(uint8_t adv_enable) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_ADV_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_ADV_ENABLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE);
+
+ UINT8_TO_STREAM(pp, adv_enable);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+void btsnd_hcic_ble_set_scan_params(uint8_t scan_type, uint16_t scan_int,
+ uint16_t scan_win, uint8_t addr_type_own,
+ uint8_t scan_filter_policy) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_SCAN_PARAMS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM);
+
+ UINT8_TO_STREAM(pp, scan_type);
+ UINT16_TO_STREAM(pp, scan_int);
+ UINT16_TO_STREAM(pp, scan_win);
+ UINT8_TO_STREAM(pp, addr_type_own);
+ UINT8_TO_STREAM(pp, scan_filter_policy);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_scan_enable(uint8_t scan_enable, uint8_t duplicate) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_WRITE_SCAN_ENABLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE);
+
+ UINT8_TO_STREAM(pp, scan_enable);
+ UINT8_TO_STREAM(pp, duplicate);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+/* link layer connection management commands */
+void btsnd_hcic_ble_create_ll_conn(uint16_t scan_int, uint16_t scan_win,
+ uint8_t init_filter_policy,
+ uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t addr_type_own, uint16_t conn_int_min,
+ uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_CREATE_LL_CONN);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN);
+
+ UINT16_TO_STREAM(pp, scan_int);
+ UINT16_TO_STREAM(pp, scan_win);
+ UINT8_TO_STREAM(pp, init_filter_policy);
+
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+ UINT8_TO_STREAM(pp, addr_type_own);
+
+ UINT16_TO_STREAM(pp, conn_int_min);
+ UINT16_TO_STREAM(pp, conn_int_max);
+ UINT16_TO_STREAM(pp, conn_latency);
+ UINT16_TO_STREAM(pp, conn_timeout);
+
+ UINT16_TO_STREAM(pp, min_ce_len);
+ UINT16_TO_STREAM(pp, max_ce_len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_create_conn_cancel(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_CREATE_CONN_CANCEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_clear_white_list(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CLEAR_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_CLEAR_WHITE_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CLEAR_WHITE_LIST);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_add_white_list(uint8_t addr_type, BD_ADDR bda) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_ADD_WHITE_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ADD_WHITE_LIST);
+
+ UINT8_TO_STREAM(pp, addr_type);
+ BDADDR_TO_STREAM(pp, bda);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_remove_from_white_list(uint8_t addr_type, BD_ADDR bda) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REMOVE_WHITE_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_REMOVE_WHITE_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REMOVE_WHITE_LIST);
+
+ UINT8_TO_STREAM(pp, addr_type);
+ BDADDR_TO_STREAM(pp, bda);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_upd_ll_conn_params(uint16_t handle, uint16_t conn_int_min,
+ uint16_t conn_int_max,
+ uint16_t conn_latency,
+ uint16_t conn_timeout,
+ uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_UPD_LL_CONN_PARAMS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ UINT16_TO_STREAM(pp, conn_int_min);
+ UINT16_TO_STREAM(pp, conn_int_max);
+ UINT16_TO_STREAM(pp, conn_latency);
+ UINT16_TO_STREAM(pp, conn_timeout);
+ UINT16_TO_STREAM(pp, min_ce_len);
+ UINT16_TO_STREAM(pp, max_ce_len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_host_chnl_class(
+ uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_HOST_CHNL_CLASS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS);
+
+ ARRAY_TO_STREAM(pp, chnl_map, HCIC_BLE_CHNL_MAP_SIZE);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_read_chnl_map(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CHNL_MAP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_READ_CHNL_MAP);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CHNL_MAP);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_read_remote_feat(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_READ_REMOTE_FEAT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+/* security management commands */
+void btsnd_hcic_ble_encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, void* p_cmd_cplt_cback) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT;
+ p->offset = sizeof(void*);
+
+ *((void**)pp) =
+ p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void*); /* Skip over callback pointer */
+
+ UINT16_TO_STREAM(pp, HCI_BLE_ENCRYPT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+ memset(pp, 0, HCIC_PARAM_SIZE_BLE_ENCRYPT);
+
+ if (key_len > HCIC_BLE_ENCRYT_KEY_SIZE) key_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+ if (pt_len > HCIC_BLE_ENCRYT_KEY_SIZE) pt_len = HCIC_BLE_ENCRYT_KEY_SIZE;
+
+ ARRAY_TO_STREAM(pp, key, key_len);
+ pp += (HCIC_BLE_ENCRYT_KEY_SIZE - key_len);
+ ARRAY_TO_STREAM(pp, plain_text, pt_len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_rand(base::Callback<void(BT_OCTET8)> cb) {
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_RAND, nullptr, 0,
+ base::Bind(
+ [](base::Callback<void(BT_OCTET8)> cb,
+ uint8_t* param, uint16_t param_len) {
+ CHECK(param[0] == 0)
+ << "LE Rand return status must be zero";
+ cb.Run(param + 1 /* skip status */);
+ },
+ std::move(cb)));
+}
+
+void btsnd_hcic_ble_start_enc(uint16_t handle,
+ uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
+ uint16_t ediv,
+ uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_START_ENC;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_START_ENC);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_START_ENC);
+
+ UINT16_TO_STREAM(pp, handle);
+ ARRAY_TO_STREAM(pp, rand, HCIC_BLE_RAND_DI_SIZE);
+ UINT16_TO_STREAM(pp, ediv);
+ ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
+ uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_LTK_REQ_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LTK_REQ_REPLY);
+
+ UINT16_TO_STREAM(pp, handle);
+ ARRAY_TO_STREAM(pp, ltk, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_LTK_REQ_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_receiver_test(uint8_t rx_freq) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_RECEIVER_TEST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, rx_freq);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq, uint8_t test_data_len,
+ uint8_t payload) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_TRANSMITTER_TEST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+ UINT8_TO_STREAM(pp, tx_freq);
+ UINT8_TO_STREAM(pp, test_data_len);
+ UINT8_TO_STREAM(pp, payload);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_test_end(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_TEST_END);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_read_host_supported(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_LE_HOST_SUPPORT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+#if (BLE_LLT_INCLUDED == TRUE)
+
+void btsnd_hcic_ble_rc_param_req_reply(uint16_t handle, uint16_t conn_int_min,
+ uint16_t conn_int_max,
+ uint16_t conn_latency,
+ uint16_t conn_timeout,
+ uint16_t min_ce_len,
+ uint16_t max_ce_len) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_RC_PARAM_REQ_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, conn_int_min);
+ UINT16_TO_STREAM(pp, conn_int_max);
+ UINT16_TO_STREAM(pp, conn_latency);
+ UINT16_TO_STREAM(pp, conn_timeout);
+ UINT16_TO_STREAM(pp, min_ce_len);
+ UINT16_TO_STREAM(pp, max_ce_len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_rc_param_req_neg_reply(uint16_t handle, uint8_t reason) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_RC_PARAM_REQ_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, reason);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif
+
+void btsnd_hcic_ble_add_device_resolving_list(
+ uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_ADD_DEV_RESOLVING_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+ ARRAY_TO_STREAM(pp, irk_peer, HCIC_BLE_ENCRYT_KEY_SIZE);
+ ARRAY_TO_STREAM(pp, irk_local, HCIC_BLE_ENCRYT_KEY_SIZE);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_rm_device_resolving_list(uint8_t addr_type_peer,
+ BD_ADDR bda_peer) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_RM_DEV_RESOLVING_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_privacy_mode(uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t privacy_type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_PRIVACY_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+ UINT8_TO_STREAM(pp, privacy_type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_clear_resolving_list(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_CLEAR_RESOLVING_LIST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_read_resolvable_addr_peer(uint8_t addr_type_peer,
+ BD_ADDR bda_peer) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_READ_RESOLVABLE_ADDR_PEER);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_read_resolvable_addr_local(uint8_t addr_type_peer,
+ BD_ADDR bda_peer) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_addr_resolution_enable(uint8_t addr_resolution_enable) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_ADDR_RESOLUTION_ENABLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE);
+ UINT8_TO_STREAM(pp, addr_resolution_enable);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_rand_priv_addr_timeout(uint16_t rpa_timout) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT);
+ UINT16_TO_STREAM(pp, rpa_timout);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_data_length(uint16_t conn_handle, uint16_t tx_octets,
+ uint16_t tx_time) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_BLE_SET_DATA_LENGTH);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH);
+
+ UINT16_TO_STREAM(pp, conn_handle);
+ UINT16_TO_STREAM(pp, tx_octets);
+ UINT16_TO_STREAM(pp, tx_time);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_extended_scan_params(uint8_t own_address_type,
+ uint8_t scanning_filter_policy,
+ uint8_t scanning_phys,
+ scanning_phy_cfg* phy_cfg) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ int phy_cnt =
+ std::bitset<std::numeric_limits<uint8_t>::digits>(scanning_phys).count();
+
+ uint16_t param_len = 3 + (5 * phy_cnt);
+ p->len = HCIC_PREAMBLE_SIZE + param_len;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_LE_SET_EXTENDED_SCAN_PARAMETERS);
+ UINT8_TO_STREAM(pp, param_len);
+
+ UINT8_TO_STREAM(pp, own_address_type);
+ UINT8_TO_STREAM(pp, scanning_filter_policy);
+ UINT8_TO_STREAM(pp, scanning_phys);
+
+ for (int i = 0; i < phy_cnt; i++) {
+ UINT8_TO_STREAM(pp, phy_cfg[i].scan_type);
+ UINT16_TO_STREAM(pp, phy_cfg[i].scan_int);
+ UINT16_TO_STREAM(pp, phy_cfg[i].scan_win);
+ }
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_set_extended_scan_enable(uint8_t enable,
+ uint8_t filter_duplicates,
+ uint16_t duration,
+ uint16_t period) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ const int param_len = 6;
+ p->len = HCIC_PREAMBLE_SIZE + param_len;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_LE_SET_EXTENDED_SCAN_ENABLE);
+ UINT8_TO_STREAM(pp, param_len);
+
+ UINT8_TO_STREAM(pp, enable);
+ UINT8_TO_STREAM(pp, filter_duplicates);
+ UINT16_TO_STREAM(pp, duration);
+ UINT16_TO_STREAM(pp, period);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_ble_ext_create_conn(uint8_t init_filter_policy,
+ uint8_t addr_type_own,
+ uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t initiating_phys,
+ EXT_CONN_PHY_CFG* phy_cfg) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ int phy_cnt =
+ std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys)
+ .count();
+
+ /* param_len = initial_params + size_per_channel * num_of_channels */
+ uint8_t param_len = 10 + (16 * phy_cnt);
+
+ p->len = HCIC_PREAMBLE_SIZE + param_len;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_LE_EXTENDED_CREATE_CONNECTION);
+ UINT8_TO_STREAM(pp, param_len);
+
+ UINT8_TO_STREAM(pp, init_filter_policy);
+ UINT8_TO_STREAM(pp, addr_type_own);
+ UINT8_TO_STREAM(pp, addr_type_peer);
+ BDADDR_TO_STREAM(pp, bda_peer);
+
+ UINT8_TO_STREAM(pp, initiating_phys);
+
+ for (int i = 0; i < phy_cnt; i++) {
+ UINT16_TO_STREAM(pp, phy_cfg[i].scan_int);
+ UINT16_TO_STREAM(pp, phy_cfg[i].scan_win);
+ UINT16_TO_STREAM(pp, phy_cfg[i].conn_int_min);
+ UINT16_TO_STREAM(pp, phy_cfg[i].conn_int_max);
+ UINT16_TO_STREAM(pp, phy_cfg[i].conn_latency);
+ UINT16_TO_STREAM(pp, phy_cfg[i].sup_timeout);
+ UINT16_TO_STREAM(pp, phy_cfg[i].min_ce_len);
+ UINT16_TO_STREAM(pp, phy_cfg[i].max_ce_len);
+ }
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
diff --git a/mtkbt/code/bt/stack/hcic/hcicmds.cc b/mtkbt/code/bt/stack/hcic/hcicmds.cc
new file mode 100755
index 0000000..6292baa
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hcic/hcicmds.cc
@@ -0,0 +1,1388 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains function of the HCIC unit to format and send HCI
+ * commands.
+ *
+ ******************************************************************************/
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include "btm_int.h" /* Included for UIPC_* macro definitions */
+
+void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration,
+ uint8_t response_cnt) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQUIRY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_INQUIRY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_INQUIRY);
+
+ LAP_TO_STREAM(pp, inq_lap);
+ UINT8_TO_STREAM(pp, duration);
+ UINT8_TO_STREAM(pp, response_cnt);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_inq_cancel(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQ_CANCEL;
+ p->offset = 0;
+ UINT16_TO_STREAM(pp, HCI_INQUIRY_CANCEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_INQ_CANCEL);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_per_inq_mode(uint16_t max_period, uint16_t min_period,
+ const LAP inq_lap, uint8_t duration,
+ uint8_t response_cnt) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PER_INQ_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_PERIODIC_INQUIRY_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_PER_INQ_MODE);
+
+ UINT16_TO_STREAM(pp, max_period);
+ UINT16_TO_STREAM(pp, min_period);
+ LAP_TO_STREAM(pp, inq_lap);
+ UINT8_TO_STREAM(pp, duration);
+ UINT8_TO_STREAM(pp, response_cnt);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_exit_per_inq(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXIT_PER_INQ;
+ p->offset = 0;
+ UINT16_TO_STREAM(pp, HCI_EXIT_PERIODIC_INQUIRY_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_EXIT_PER_INQ);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_create_conn(BD_ADDR dest, uint16_t packet_types,
+ uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
+ uint16_t clock_offset, uint8_t allow_switch) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+#ifndef BT_10A
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN;
+#else
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1;
+#endif
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_CREATE_CONNECTION);
+#ifndef BT_10A
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CREATE_CONN);
+#else
+ UINT8_TO_STREAM(pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1));
+#endif
+ BDADDR_TO_STREAM(pp, dest);
+ UINT16_TO_STREAM(pp, packet_types);
+ UINT8_TO_STREAM(pp, page_scan_rep_mode);
+ UINT8_TO_STREAM(pp, page_scan_mode);
+ UINT16_TO_STREAM(pp, clock_offset);
+#if !defined(BT_10A)
+ UINT8_TO_STREAM(pp, allow_switch);
+#endif
+ btm_acl_paging(p, dest);
+}
+
+void btsnd_hcic_disconnect(uint16_t handle, uint8_t reason) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DISCONNECT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_DISCONNECT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_DISCONNECT);
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, reason);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+#if (BTM_SCO_INCLUDED == TRUE)
+void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ADD_SCO_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ADD_SCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ADD_SCO_CONN);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, packet_types);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif /* BTM_SCO_INCLUDED */
+
+void btsnd_hcic_create_conn_cancel(BD_ADDR dest) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_CREATE_CONNECTION_CANCEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CREATE_CONN_CANCEL);
+
+ BDADDR_TO_STREAM(pp, dest);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_accept_conn(BD_ADDR dest, uint8_t role) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ACCEPT_CONNECTION_REQUEST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ACCEPT_CONN);
+ BDADDR_TO_STREAM(pp, dest);
+ UINT8_TO_STREAM(pp, role);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_reject_conn(BD_ADDR dest, uint8_t reason) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_REJECT_CONNECTION_REQUEST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REJECT_CONN);
+
+ BDADDR_TO_STREAM(pp, dest);
+ UINT8_TO_STREAM(pp, reason);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_link_key_req_reply(BD_ADDR bd_addr, LINK_KEY link_key) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_LINK_KEY_REQUEST_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ ARRAY16_TO_STREAM(pp, link_key);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_link_key_neg_reply(BD_ADDR bd_addr) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_LINK_KEY_REQUEST_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_pin_code_req_reply(BD_ADDR bd_addr, uint8_t pin_code_len,
+ PIN_CODE pin_code) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+ int i;
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_PIN_CODE_REQUEST_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, pin_code_len);
+
+ for (i = 0; i < pin_code_len; i++) *pp++ = *pin_code++;
+
+ for (; i < PIN_CODE_LEN; i++) *pp++ = 0;
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_pin_code_neg_reply(BD_ADDR bd_addr) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_PIN_CODE_REQUEST_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_change_conn_type(uint16_t handle, uint16_t packet_types) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_CONN_TYPE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_CHANGE_CONN_PACKET_TYPE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CHANGE_CONN_TYPE);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, packet_types);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_auth_request(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_AUTHENTICATION_REQUESTED);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_set_conn_encrypt(uint16_t handle, bool enable) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_CONN_ENCRYPT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SET_CONN_ENCRYPTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SET_CONN_ENCRYPT);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, enable);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_name_req(BD_ADDR bd_addr, uint8_t page_scan_rep_mode,
+ uint8_t page_scan_mode, uint16_t clock_offset) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_RMT_NAME_REQUEST);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_RMT_NAME_REQ);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, page_scan_rep_mode);
+ UINT8_TO_STREAM(pp, page_scan_mode);
+ UINT16_TO_STREAM(pp, clock_offset);
+
+ btm_acl_paging(p, bd_addr);
+}
+
+void btsnd_hcic_rmt_name_req_cancel(BD_ADDR bd_addr) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_RMT_NAME_REQUEST_CANCEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_features_req(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_RMT_FEATURES);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_ext_features(uint16_t handle, uint8_t page_num) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_RMT_EXT_FEATURES;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_RMT_EXT_FEATURES);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_RMT_EXT_FEATURES);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, page_num);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rmt_ver_req(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_RMT_VERSION_INFO);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_rmt_clk_offset(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_RMT_CLOCK_OFFSET);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_lmp_handle(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_LMP_HANDLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_setup_esco_conn(uint16_t handle, uint32_t transmit_bandwidth,
+ uint32_t receive_bandwidth,
+ uint16_t max_latency, uint16_t voice,
+ uint8_t retrans_effort, uint16_t packet_types) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SETUP_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SETUP_ESCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SETUP_ESCO);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT32_TO_STREAM(pp, transmit_bandwidth);
+ UINT32_TO_STREAM(pp, receive_bandwidth);
+ UINT16_TO_STREAM(pp, max_latency);
+ UINT16_TO_STREAM(pp, voice);
+ UINT8_TO_STREAM(pp, retrans_effort);
+ UINT16_TO_STREAM(pp, packet_types);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_accept_esco_conn(BD_ADDR bd_addr, uint32_t transmit_bandwidth,
+ uint32_t receive_bandwidth,
+ uint16_t max_latency, uint16_t content_fmt,
+ uint8_t retrans_effort,
+ uint16_t packet_types) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ACCEPT_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ACCEPT_ESCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ACCEPT_ESCO);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT32_TO_STREAM(pp, transmit_bandwidth);
+ UINT32_TO_STREAM(pp, receive_bandwidth);
+ UINT16_TO_STREAM(pp, max_latency);
+ UINT16_TO_STREAM(pp, content_fmt);
+ UINT8_TO_STREAM(pp, retrans_effort);
+ UINT16_TO_STREAM(pp, packet_types);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_reject_esco_conn(BD_ADDR bd_addr, uint8_t reason) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REJECT_ESCO;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_REJECT_ESCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REJECT_ESCO);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, reason);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_hold_mode(uint16_t handle, uint16_t max_hold_period,
+ uint16_t min_hold_period) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_HOLD_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_HOLD_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_HOLD_MODE);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, max_hold_period);
+ UINT16_TO_STREAM(pp, min_hold_period);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_sniff_mode(uint16_t handle, uint16_t max_sniff_period,
+ uint16_t min_sniff_period, uint16_t sniff_attempt,
+ uint16_t sniff_timeout) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SNIFF_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SNIFF_MODE);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, max_sniff_period);
+ UINT16_TO_STREAM(pp, min_sniff_period);
+ UINT16_TO_STREAM(pp, sniff_attempt);
+ UINT16_TO_STREAM(pp, sniff_timeout);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_exit_sniff_mode(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_EXIT_SNIFF_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_park_mode(uint16_t handle, uint16_t beacon_max_interval,
+ uint16_t beacon_min_interval) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_PARK_MODE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_PARK_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_PARK_MODE);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, beacon_max_interval);
+ UINT16_TO_STREAM(pp, beacon_min_interval);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_exit_park_mode(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_EXIT_PARK_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_qos_setup(uint16_t handle, uint8_t flags, uint8_t service_type,
+ uint32_t token_rate, uint32_t peak, uint32_t latency,
+ uint32_t delay_var) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_QOS_SETUP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_QOS_SETUP);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_QOS_SETUP);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, flags);
+ UINT8_TO_STREAM(pp, service_type);
+ UINT32_TO_STREAM(pp, token_rate);
+ UINT32_TO_STREAM(pp, peak);
+ UINT32_TO_STREAM(pp, latency);
+ UINT32_TO_STREAM(pp, delay_var);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_switch_role(BD_ADDR bd_addr, uint8_t role) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SWITCH_ROLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SWITCH_ROLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SWITCH_ROLE);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, role);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_policy_set(uint16_t handle, uint16_t settings) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_POLICY_SET;
+ p->offset = 0;
+ UINT16_TO_STREAM(pp, HCI_WRITE_POLICY_SETTINGS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_POLICY_SET);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, settings);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_def_policy_set(uint16_t settings) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET;
+ p->offset = 0;
+ UINT16_TO_STREAM(pp, HCI_WRITE_DEF_POLICY_SETTINGS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET);
+
+ UINT16_TO_STREAM(pp, settings);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_set_event_filter(uint8_t filt_type, uint8_t filt_cond_type,
+ uint8_t* filt_cond, uint8_t filt_cond_len) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SET_EVENT_FILTER);
+
+ if (filt_type) {
+ p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 2 + filt_cond_len);
+ UINT8_TO_STREAM(pp, (uint8_t)(2 + filt_cond_len));
+
+ UINT8_TO_STREAM(pp, filt_type);
+ UINT8_TO_STREAM(pp, filt_cond_type);
+
+ if (filt_cond_type == HCI_FILTER_COND_DEVICE_CLASS) {
+ DEVCLASS_TO_STREAM(pp, filt_cond);
+ filt_cond += DEV_CLASS_LEN;
+ DEVCLASS_TO_STREAM(pp, filt_cond);
+ filt_cond += DEV_CLASS_LEN;
+
+ filt_cond_len -= (2 * DEV_CLASS_LEN);
+ } else if (filt_cond_type == HCI_FILTER_COND_BD_ADDR) {
+ BDADDR_TO_STREAM(pp, filt_cond);
+ filt_cond += BD_ADDR_LEN;
+
+ filt_cond_len -= BD_ADDR_LEN;
+ }
+
+ if (filt_cond_len) ARRAY_TO_STREAM(pp, filt_cond, filt_cond_len);
+ } else {
+ p->len = (uint16_t)(HCIC_PREAMBLE_SIZE + 1);
+ UINT8_TO_STREAM(pp, 1);
+
+ UINT8_TO_STREAM(pp, filt_type);
+ }
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_pin_type(uint8_t type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_PIN_TYPE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_delete_stored_key(BD_ADDR bd_addr, bool delete_all_flag) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_DELETE_STORED_KEY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_DELETE_STORED_LINK_KEY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_DELETE_STORED_KEY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, delete_all_flag);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_change_name(BD_NAME name) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+ uint16_t len = strlen((char*)name) + 1;
+
+ memset(pp, 0, HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CHANGE_NAME;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_CHANGE_LOCAL_NAME);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CHANGE_NAME);
+
+ if (len > HCIC_PARAM_SIZE_CHANGE_NAME) len = HCIC_PARAM_SIZE_CHANGE_NAME;
+
+ ARRAY_TO_STREAM(pp, name, len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_name(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_LOCAL_NAME);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_page_tout(uint16_t timeout) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_PAGE_TOUT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+ UINT16_TO_STREAM(pp, timeout);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_scan_enable(uint8_t flag) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_SCAN_ENABLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, flag);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_pagescan_cfg(uint16_t interval, uint16_t window) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_PAGESCAN_CFG);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG);
+
+ UINT16_TO_STREAM(pp, interval);
+ UINT16_TO_STREAM(pp, window);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_inqscan_cfg(uint16_t interval, uint16_t window) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_INQUIRYSCAN_CFG);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG);
+
+ UINT16_TO_STREAM(pp, interval);
+ UINT16_TO_STREAM(pp, window);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_auth_enable(uint8_t flag) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_AUTHENTICATION_ENABLE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, flag);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_dev_class(DEV_CLASS dev_class) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM3;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_CLASS_OF_DEVICE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM3);
+
+ DEVCLASS_TO_STREAM(pp, dev_class);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_voice_settings(uint16_t flags) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM2;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_VOICE_SETTINGS);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM2);
+
+ UINT16_TO_STREAM(pp, flags);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_auto_flush_tout(uint16_t handle, uint16_t tout) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_AUTO_FLUSH_TOUT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, tout);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_tx_power(uint16_t handle, uint8_t type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_TX_POWER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_TRANSMIT_POWER_LEVEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_TX_POWER);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_host_num_xmitted_pkts(uint8_t num_handles, uint16_t* handle,
+ uint16_t* num_pkts) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4);
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_HOST_NUM_PACKETS_DONE);
+ UINT8_TO_STREAM(pp, p->len - HCIC_PREAMBLE_SIZE);
+
+ UINT8_TO_STREAM(pp, num_handles);
+
+ for (int i = 0; i < num_handles; i++) {
+ UINT16_TO_STREAM(pp, handle[i]);
+ UINT16_TO_STREAM(pp, num_pkts[i]);
+ }
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_link_super_tout(uint8_t local_controller_id,
+ uint16_t handle, uint16_t timeout) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_LINK_SUPER_TOUT);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, timeout);
+
+ btu_hcif_send_cmd(local_controller_id, p);
+}
+
+void btsnd_hcic_write_cur_iac_lap(uint8_t num_cur_iac, LAP* const iac_lap) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + 1 + (LAP_LEN * num_cur_iac);
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_CURRENT_IAC_LAP);
+ UINT8_TO_STREAM(pp, p->len - HCIC_PREAMBLE_SIZE);
+
+ UINT8_TO_STREAM(pp, num_cur_iac);
+
+ for (int i = 0; i < num_cur_iac; i++) LAP_TO_STREAM(pp, iac_lap[i]);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+/******************************************
+ * Lisbon Features
+ ******************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+
+void btsnd_hcic_sniff_sub_rate(uint16_t handle, uint16_t max_lat,
+ uint16_t min_remote_lat,
+ uint16_t min_local_lat) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SNIFF_SUB_RATE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SNIFF_SUB_RATE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SNIFF_SUB_RATE);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT16_TO_STREAM(pp, max_lat);
+ UINT16_TO_STREAM(pp, min_remote_lat);
+ UINT16_TO_STREAM(pp, min_local_lat);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif /* BTM_SSR_INCLUDED */
+
+/**** Extended Inquiry Response Commands ****/
+void btsnd_hcic_write_ext_inquiry_response(void* buffer, uint8_t fec_req) {
+ BT_HDR* p = (BT_HDR*)buffer;
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_EXT_INQ_RESPONSE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_EXT_INQ_RESP);
+
+ UINT8_TO_STREAM(pp, fec_req);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_io_cap_req_reply(BD_ADDR bd_addr, uint8_t capability,
+ uint8_t oob_present, uint8_t auth_req) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_RESP;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_IO_CAPABILITY_REQUEST_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_IO_CAP_RESP);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, capability);
+ UINT8_TO_STREAM(pp, oob_present);
+ UINT8_TO_STREAM(pp, auth_req);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_enhanced_set_up_synchronous_connection(
+ uint16_t conn_handle, enh_esco_params_t* p_params) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENH_SET_ESCO_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ENH_SETUP_ESCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ENH_SET_ESCO_CONN);
+
+ UINT16_TO_STREAM(pp, conn_handle);
+ UINT32_TO_STREAM(pp, p_params->transmit_bandwidth);
+ UINT32_TO_STREAM(pp, p_params->receive_bandwidth);
+ UINT8_TO_STREAM(pp, p_params->transmit_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->transmit_coding_format.company_id);
+ UINT16_TO_STREAM(pp,
+ p_params->transmit_coding_format.vendor_specific_codec_id);
+ UINT8_TO_STREAM(pp, p_params->receive_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->receive_coding_format.company_id);
+ UINT16_TO_STREAM(pp,
+ p_params->receive_coding_format.vendor_specific_codec_id);
+ UINT16_TO_STREAM(pp, p_params->transmit_codec_frame_size);
+ UINT16_TO_STREAM(pp, p_params->receive_codec_frame_size);
+ UINT32_TO_STREAM(pp, p_params->input_bandwidth);
+ UINT32_TO_STREAM(pp, p_params->output_bandwidth);
+ UINT8_TO_STREAM(pp, p_params->input_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->input_coding_format.company_id);
+ UINT16_TO_STREAM(pp, p_params->input_coding_format.vendor_specific_codec_id);
+ UINT8_TO_STREAM(pp, p_params->output_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->output_coding_format.company_id);
+ UINT16_TO_STREAM(pp, p_params->output_coding_format.vendor_specific_codec_id);
+ UINT16_TO_STREAM(pp, p_params->input_coded_data_size);
+ UINT16_TO_STREAM(pp, p_params->output_coded_data_size);
+ UINT8_TO_STREAM(pp, p_params->input_pcm_data_format);
+ UINT8_TO_STREAM(pp, p_params->output_pcm_data_format);
+ UINT8_TO_STREAM(pp, p_params->input_pcm_payload_msb_position);
+ UINT8_TO_STREAM(pp, p_params->output_pcm_payload_msb_position);
+ UINT8_TO_STREAM(pp, p_params->input_data_path);
+ UINT8_TO_STREAM(pp, p_params->output_data_path);
+ UINT8_TO_STREAM(pp, p_params->input_transport_unit_size);
+ UINT8_TO_STREAM(pp, p_params->output_transport_unit_size);
+ UINT16_TO_STREAM(pp, p_params->max_latency_ms);
+ UINT16_TO_STREAM(pp, p_params->packet_types);
+ UINT8_TO_STREAM(pp, p_params->retransmission_effort);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_enhanced_accept_synchronous_connection(
+ BD_ADDR bd_addr, enh_esco_params_t* p_params) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENH_ACC_ESCO_CONN;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ENH_ACCEPT_ESCO_CONNECTION);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ENH_ACC_ESCO_CONN);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT32_TO_STREAM(pp, p_params->transmit_bandwidth);
+ UINT32_TO_STREAM(pp, p_params->receive_bandwidth);
+ UINT8_TO_STREAM(pp, p_params->transmit_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->transmit_coding_format.company_id);
+ UINT16_TO_STREAM(pp,
+ p_params->transmit_coding_format.vendor_specific_codec_id);
+ UINT8_TO_STREAM(pp, p_params->receive_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->receive_coding_format.company_id);
+ UINT16_TO_STREAM(pp,
+ p_params->receive_coding_format.vendor_specific_codec_id);
+ UINT16_TO_STREAM(pp, p_params->transmit_codec_frame_size);
+ UINT16_TO_STREAM(pp, p_params->receive_codec_frame_size);
+ UINT32_TO_STREAM(pp, p_params->input_bandwidth);
+ UINT32_TO_STREAM(pp, p_params->output_bandwidth);
+ UINT8_TO_STREAM(pp, p_params->input_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->input_coding_format.company_id);
+ UINT16_TO_STREAM(pp, p_params->input_coding_format.vendor_specific_codec_id);
+ UINT8_TO_STREAM(pp, p_params->output_coding_format.coding_format);
+ UINT16_TO_STREAM(pp, p_params->output_coding_format.company_id);
+ UINT16_TO_STREAM(pp, p_params->output_coding_format.vendor_specific_codec_id);
+ UINT16_TO_STREAM(pp, p_params->input_coded_data_size);
+ UINT16_TO_STREAM(pp, p_params->output_coded_data_size);
+ UINT8_TO_STREAM(pp, p_params->input_pcm_data_format);
+ UINT8_TO_STREAM(pp, p_params->output_pcm_data_format);
+ UINT8_TO_STREAM(pp, p_params->input_pcm_payload_msb_position);
+ UINT8_TO_STREAM(pp, p_params->output_pcm_payload_msb_position);
+ UINT8_TO_STREAM(pp, p_params->input_data_path);
+ UINT8_TO_STREAM(pp, p_params->output_data_path);
+ UINT8_TO_STREAM(pp, p_params->input_transport_unit_size);
+ UINT8_TO_STREAM(pp, p_params->output_transport_unit_size);
+ UINT16_TO_STREAM(pp, p_params->max_latency_ms);
+ UINT16_TO_STREAM(pp, p_params->packet_types);
+ UINT8_TO_STREAM(pp, p_params->retransmission_effort);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_io_cap_req_neg_reply(BD_ADDR bd_addr, uint8_t err_code) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_IO_CAP_REQ_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, err_code);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_local_oob_data(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_LOCAL_OOB;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_LOCAL_OOB_DATA);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_R_LOCAL_OOB);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_user_conf_reply(BD_ADDR bd_addr, bool is_yes) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_UCONF_REPLY;
+ p->offset = 0;
+
+ if (!is_yes) {
+ /* Negative reply */
+ UINT16_TO_STREAM(pp, HCI_USER_CONF_VALUE_NEG_REPLY);
+ } else {
+ /* Confirmation */
+ UINT16_TO_STREAM(pp, HCI_USER_CONF_REQUEST_REPLY);
+ }
+
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_UCONF_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_user_passkey_reply(BD_ADDR bd_addr, uint32_t value) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_USER_PASSKEY_REQ_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_U_PKEY_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT32_TO_STREAM(pp, value);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_user_passkey_neg_reply(BD_ADDR bd_addr) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_USER_PASSKEY_REQ_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rem_oob_reply(BD_ADDR bd_addr, uint8_t* p_c, uint8_t* p_r) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_REM_OOB_DATA_REQ_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REM_OOB_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ ARRAY16_TO_STREAM(pp, p_c);
+ ARRAY16_TO_STREAM(pp, p_r);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_rem_oob_neg_reply(BD_ADDR bd_addr) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_REM_OOB_DATA_REQ_NEG_REPLY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_inq_tx_power(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_R_TX_POWER;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_INQ_TX_POWER_LEVEL);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_R_TX_POWER);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_send_keypress_notif(BD_ADDR bd_addr, uint8_t notif) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_SEND_KEYPRESS_NOTIF);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF);
+
+ BDADDR_TO_STREAM(pp, bd_addr);
+ UINT8_TO_STREAM(pp, notif);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+/**** end of Simple Pairing Commands ****/
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+void btsnd_hcic_enhanced_flush(uint16_t handle, uint8_t packet_type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_ENHANCED_FLUSH;
+ p->offset = 0;
+ UINT16_TO_STREAM(pp, HCI_ENHANCED_FLUSH);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_ENHANCED_FLUSH);
+
+ UINT16_TO_STREAM(pp, handle);
+ UINT8_TO_STREAM(pp, packet_type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+#endif
+
+/*************************
+ * End of Lisbon Commands
+ *************************/
+
+void btsnd_hcic_get_link_quality(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_GET_LINK_QUALITY);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_read_rssi(uint16_t handle) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CMD_HANDLE;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_READ_RSSI);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CMD_HANDLE);
+
+ UINT16_TO_STREAM(pp, handle);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_enable_test_mode(void) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_READ_CMD;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_ENABLE_DEV_UNDER_TEST_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_READ_CMD);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_inqscan_type(uint8_t type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_INQSCAN_TYPE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_inquiry_mode(uint8_t mode) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_INQUIRY_MODE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, mode);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+void btsnd_hcic_write_pagescan_type(uint8_t type) {
+ BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1;
+ p->offset = 0;
+
+ UINT16_TO_STREAM(pp, HCI_WRITE_PAGESCAN_TYPE);
+ UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_WRITE_PARAM1);
+
+ UINT8_TO_STREAM(pp, type);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
+
+/* Must have room to store BT_HDR + max VSC length + callback pointer */
+#if (HCI_CMD_BUF_SIZE < 268)
+#error "HCI_CMD_BUF_SIZE must be larger than 268"
+#endif
+
+void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode, uint8_t len,
+ uint8_t* p_data, void* p_cmd_cplt_cback) {
+ BT_HDR* p = (BT_HDR*)buffer;
+ uint8_t* pp = (uint8_t*)(p + 1);
+
+ p->len = HCIC_PREAMBLE_SIZE + len;
+ p->offset = sizeof(void*);
+
+ *((void**)pp) =
+ p_cmd_cplt_cback; /* Store command complete callback in buffer */
+ pp += sizeof(void*); /* Skip over callback pointer */
+
+ UINT16_TO_STREAM(pp, HCI_GRP_VENDOR_SPECIFIC | opcode);
+ UINT8_TO_STREAM(pp, len);
+ ARRAY_TO_STREAM(pp, p_data, len);
+
+ btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
+}
diff --git a/mtkbt/code/bt/stack/hid/hid_conn.h b/mtkbt/code/bt/stack/hid/hid_conn.h
new file mode 100755
index 0000000..5e3ffe7
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hid_conn.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains HID connection internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HID_CONN_H
+#define HID_CONN_H
+
+#include "osi/include/alarm.h"
+
+/* Define the HID Connection Block
+*/
+typedef struct hid_conn {
+#define HID_CONN_STATE_UNUSED (0)
+#define HID_CONN_STATE_CONNECTING_CTRL (1)
+#define HID_CONN_STATE_CONNECTING_INTR (2)
+#define HID_CONN_STATE_CONFIG (3)
+#define HID_CONN_STATE_CONNECTED (4)
+#define HID_CONN_STATE_DISCONNECTING (5)
+#define HID_CONN_STATE_SECURITY (6)
+
+ uint8_t conn_state;
+
+#define HID_CONN_FLAGS_IS_ORIG (0x01)
+#define HID_CONN_FLAGS_HIS_CTRL_CFG_DONE (0x02)
+#define HID_CONN_FLAGS_MY_CTRL_CFG_DONE (0x04)
+#define HID_CONN_FLAGS_HIS_INTR_CFG_DONE (0x08)
+#define HID_CONN_FLAGS_MY_INTR_CFG_DONE (0x10)
+#define HID_CONN_FLAGS_ALL_CONFIGURED (0x1E) /* All the config done */
+#define HID_CONN_FLAGS_CONGESTED (0x20)
+#define HID_CONN_FLAGS_INACTIVE (0x40)
+
+ uint8_t conn_flags;
+
+ uint8_t ctrl_id;
+ uint16_t ctrl_cid;
+ uint16_t intr_cid;
+ uint16_t rem_mtu_size;
+ uint16_t disc_reason; /* Reason for disconnecting (for HID_HDEV_EVT_CLOSE) */
+ alarm_t* process_repage_timer;
+} tHID_CONN;
+
+#define HID_SEC_CHN 1
+#define HID_NOSEC_CHN 2
+
+#define HIDD_SEC_CHN 3
+#define HIDD_NOSEC_CHN 4
+
+#endif
diff --git a/mtkbt/code/bt/stack/hid/hidd_api.cc b/mtkbt/code/bt/stack/hid/hidd_api.cc
new file mode 100755
index 0000000..9879095
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidd_api.cc
@@ -0,0 +1,633 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID Device API entry points
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+#include "hiddefs.h"
+
+#if HID_DYNAMIC_MEMORY == FALSE
+tHID_DEV_CTB hd_cb;
+#endif
+
+/*******************************************************************************
+ *
+ * Function HID_DevInit
+ *
+ * Description Initializes control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void HID_DevInit(void) {
+ uint8_t log_level = hd_cb.trace_level;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ memset(&hd_cb, 0, sizeof(tHID_DEV_CTB));
+ hd_cb.trace_level = log_level;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetTraceLevel
+ *
+ * Description This function sets the trace level for HID Dev. If called
+*with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t HID_DevSetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) hd_cb.trace_level = new_level;
+
+ return (hd_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevRegister
+ *
+ * Description Registers HID device with lower layers
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) {
+ tHID_STATUS st;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
+
+ if (host_cback == NULL) return HID_ERR_INVALID_PARAM;
+
+ /* Register with L2CAP */
+ st = hidd_conn_reg();
+ if (st != HID_SUCCESS) return st;
+
+ hd_cb.callback = host_cback;
+ hd_cb.reg_flag = TRUE;
+
+ if (hd_cb.pending_data) {
+ osi_free(hd_cb.pending_data);
+ hd_cb.pending_data = NULL;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevDeregister
+ *
+ * Description Deregisters HID device with lower layers
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevDeregister(void) {
+ HIDD_TRACE_API("%s", __func__);
+
+ if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ hidd_conn_dereg();
+
+ hd_cb.reg_flag = FALSE;
+
+ return (HID_SUCCESS);
+}
+
+tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl) {
+ HIDD_TRACE_API("%s", __func__);
+
+ if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl,
+ HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) {
+ HIDD_TRACE_ERROR("Security Registration 1 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl,
+ HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) {
+ HIDD_TRACE_ERROR("Security Registration 2 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HIDD_NOSEC_CHN)) {
+ HIDD_TRACE_ERROR("Security Registration 3 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HIDD_NOSEC_CHN)) {
+ HIDD_TRACE_ERROR("Security Registration 4 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE,
+ HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) {
+ HIDD_TRACE_ERROR("Security Registration 5 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE,
+ HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) {
+ HIDD_TRACE_ERROR("Security Registration 6 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevAddRecord
+ *
+ * Description Creates SDP record for HID device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description,
+ char* p_provider, uint16_t subclass,
+ uint16_t desc_len, uint8_t* p_desc_data) {
+ bool result = TRUE;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ // Service Class ID List
+ if (result) {
+ uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
+ result &= SDP_AddServiceClassIdList(handle, 1, &uuid);
+ }
+
+ // Protocol Descriptor List
+ if (result) {
+ tSDP_PROTOCOL_ELEM proto_list[2];
+
+ proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_list[0].num_params = 1;
+ proto_list[0].params[0] = BT_PSM_HIDC;
+
+ proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+ proto_list[1].num_params = 0;
+
+ result &= SDP_AddProtocolList(handle, 2, proto_list);
+ }
+
+ // Language Base Attribute ID List
+ if (result) {
+ result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH,
+ LANG_ID_CHAR_ENCODE_UTF8,
+ LANGUAGE_BASE_ID);
+ }
+
+ // Additional Protocol Descriptor List
+ if (result) {
+ tSDP_PROTO_LIST_ELEM add_proto_list;
+
+ add_proto_list.num_elems = 2;
+ add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ add_proto_list.list_elem[0].num_params = 1;
+ add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI;
+ add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP;
+ add_proto_list.list_elem[1].num_params = 0;
+
+ result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list);
+ }
+
+ // Service Name (O)
+ // Service Description (O)
+ // Provider Name (O)
+ if (result) {
+ const char* srv_name = p_name;
+ const char* srv_desc = p_description;
+ const char* provider_name = p_provider;
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ strlen(srv_name) + 1, (uint8_t*)srv_name);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
+ TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1,
+ (uint8_t*)srv_desc);
+
+ result &=
+ SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE,
+ strlen(provider_name) + 1, (uint8_t*)provider_name);
+ }
+
+ // Bluetooth Profile Descriptor List
+ if (result) {
+ const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE;
+ const uint16_t version = 0x0100;
+
+ result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version);
+ }
+
+ // HID Parser Version
+ if (result) {
+ uint8_t* p;
+ const uint16_t rel_num = 0x0100;
+ const uint16_t parser_version = 0x0111;
+ const uint16_t prof_ver = 0x0100;
+ const uint8_t dev_subclass = subclass;
+ const uint8_t country_code = 0x21;
+ const uint8_t bool_false = 0x00;
+ const uint8_t bool_true = 0x01;
+ uint16_t temp;
+
+ p = (uint8_t*)&temp;
+ UINT16_TO_BE_STREAM(p, rel_num);
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM,
+ UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+
+ p = (uint8_t*)&temp;
+ UINT16_TO_BE_STREAM(p, parser_version);
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION,
+ UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS,
+ UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE,
+ 1, (uint8_t*)&country_code);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+ {
+ static uint8_t cdt = 0x22;
+ uint8_t* p_buf;
+ uint8_t seq_len = 4 + desc_len;
+
+ p_buf = (uint8_t*)osi_malloc(2048);
+
+ if (p_buf == NULL) {
+ HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ",
+ __func__);
+ return HID_ERR_NOT_REGISTERED;
+ }
+
+ p = p_buf;
+
+ UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+ UINT8_TO_BE_STREAM(p, seq_len);
+
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM(p, cdt);
+
+ UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p, desc_len);
+ ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
+
+ osi_free(p_buf);
+ }
+
+ {
+ uint8_t lang_buf[8];
+ p = lang_buf;
+ uint8_t seq_len = 6;
+ uint16_t lang_english = 0x0409;
+ UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p, seq_len);
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, lang_english);
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID);
+ result &=
+ SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE,
+ DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf);
+ }
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE,
+ BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true);
+
+ p = (uint8_t*)&temp;
+ UINT16_TO_BE_STREAM(p, prof_ver);
+ result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION,
+ UINT_DESC_TYPE, 2, (uint8_t*)&temp);
+ }
+
+ if (result) {
+ uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1,
+ &browse_group);
+ }
+
+ if (!result) {
+ HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__);
+
+ return HID_ERR_NOT_REGISTERED;
+ }
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevSendReport
+ *
+ * Description Sends report
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
+ uint16_t len, uint8_t* p_data) {
+ HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel,
+ type, id, len);
+
+ if (channel == HID_CHANNEL_CTRL) {
+ return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len,
+ p_data);
+ }
+
+ if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) {
+ // on INTR we can only send INPUT
+ return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA,
+ HID_PAR_REP_TYPE_INPUT, id, len, p_data);
+ }
+
+ return HID_ERR_INVALID_PARAM;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevVirtualCableUnplug
+ *
+ * Description Sends Virtual Cable Unplug
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevVirtualCableUnplug(void) {
+ HIDD_TRACE_API("%s", __func__);
+
+ return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL,
+ HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevPlugDevice
+ *
+ * Description Establishes virtual cable to given host
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevPlugDevice(BD_ADDR addr) {
+ hd_cb.device.in_use = TRUE;
+ memcpy(hd_cb.device.addr, addr, sizeof(BD_ADDR));
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevUnplugDevice
+ *
+ * Description Unplugs virtual cable from given host
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr) {
+ if (!memcmp(hd_cb.device.addr, addr, sizeof(BD_ADDR))) {
+ hd_cb.device.in_use = FALSE;
+ hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
+ hd_cb.device.conn.ctrl_cid = 0;
+ hd_cb.device.conn.intr_cid = 0;
+ }
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevConnect
+ *
+ * Description Connects to device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevConnect(void) {
+ if (!hd_cb.reg_flag) {
+ return HID_ERR_NOT_REGISTERED;
+ }
+
+ if (!hd_cb.device.in_use) {
+ return HID_ERR_INVALID_PARAM;
+ }
+
+ if (hd_cb.device.state != HIDD_DEV_NO_CONN) {
+ return HID_ERR_ALREADY_CONN;
+ }
+
+ return hidd_conn_initiate();
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevDisconnect
+ *
+ * Description Disconnects from device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevDisconnect(void) {
+ if (!hd_cb.reg_flag) {
+ return HID_ERR_NOT_REGISTERED;
+ }
+
+ if (!hd_cb.device.in_use) {
+ return HID_ERR_INVALID_PARAM;
+ }
+
+ if (hd_cb.device.state == HIDD_DEV_NO_CONN) {
+ /* If we are still trying to connect, just close the connection. */
+ if (hd_cb.device.conn.conn_state != HID_CONN_STATE_UNUSED) {
+ tHID_STATUS ret = hidd_conn_disconnect();
+ hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED;
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+ HID_ERR_DISCONNECTING, NULL);
+ return ret;
+ }
+ return HID_ERR_NO_CONNECTION;
+ }
+
+ return hidd_conn_disconnect();
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetIncomingPolicy
+ *
+ * Description Sets policy for incoming connections (allowed/disallowed)
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetIncomingPolicy(bool allow) {
+ hd_cb.allow_incoming = allow;
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevReportError
+ *
+ * Description Reports error for Set Report via HANDSHAKE
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevReportError(uint8_t error) {
+ uint8_t handshake_param;
+
+ HIDD_TRACE_API("%s: error = %d", __func__, error);
+
+ switch (error) {
+ case HID_PAR_HANDSHAKE_RSP_SUCCESS:
+ case HID_PAR_HANDSHAKE_RSP_NOT_READY:
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID:
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ:
+ case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM:
+ case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN:
+ case HID_PAR_HANDSHAKE_RSP_ERR_FATAL:
+ handshake_param = error;
+ break;
+ default:
+ handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN;
+ break;
+ }
+
+ return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0,
+ NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevGetDevice
+ *
+ * Description Returns the BD Address of virtually cabled device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevGetDevice(BD_ADDR* addr) {
+ HIDD_TRACE_API("%s", __func__);
+
+ if (hd_cb.device.in_use) {
+ memcpy(addr, hd_cb.device.addr, sizeof(BD_ADDR));
+ } else {
+ return HID_ERR_NOT_REGISTERED;
+ }
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetIncomingQos
+ *
+ * Description Sets Incoming QoS values for Interrupt L2CAP Channel
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate,
+ uint32_t token_bucket_size,
+ uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation) {
+ HIDD_TRACE_API("%s", __func__);
+
+ hd_cb.use_in_qos = TRUE;
+
+ hd_cb.in_qos.service_type = service_type;
+ hd_cb.in_qos.token_rate = token_rate;
+ hd_cb.in_qos.token_bucket_size = token_bucket_size;
+ hd_cb.in_qos.peak_bandwidth = peak_bandwidth;
+ hd_cb.in_qos.latency = latency;
+ hd_cb.in_qos.delay_variation = delay_variation;
+
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetOutgoingQos
+ *
+ * Description Sets Outgoing QoS values for Interrupt L2CAP Channel
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate,
+ uint32_t token_bucket_size,
+ uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation) {
+ HIDD_TRACE_API("%s", __func__);
+
+ hd_cb.l2cap_intr_cfg.qos_present = TRUE;
+
+ hd_cb.l2cap_intr_cfg.qos.service_type = service_type;
+ hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate;
+ hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size;
+ hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth;
+ hd_cb.l2cap_intr_cfg.qos.latency = latency;
+ hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation;
+
+ return HID_SUCCESS;
+}
diff --git a/mtkbt/code/bt/stack/hid/hidd_conn.cc b/mtkbt/code/bt/stack/hid/hidd_conn.cc
new file mode 100755
index 0000000..c76e545
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidd_conn.cc
@@ -0,0 +1,980 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the connection interface functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_types.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#include "hiddefs.h"
+
+#include "bt_utils.h"
+#include "hidd_api.h"
+#include "hidd_int.h"
+
+#include "osi/include/osi.h"
+
+static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm,
+ uint8_t id);
+static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
+static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
+static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
+static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
+static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
+
+static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
+ hidd_l2cif_connect_cfm,
+ NULL,
+ hidd_l2cif_config_ind,
+ hidd_l2cif_config_cfm,
+ hidd_l2cif_disconnect_ind,
+ hidd_l2cif_disconnect_cfm,
+ NULL,
+ hidd_l2cif_data_ind,
+ hidd_l2cif_cong_ind,
+ NULL};
+
+/*******************************************************************************
+ *
+ * Function hidd_check_config_done
+ *
+ * Description Checks if connection is configured and callback can be fired
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_check_config_done() {
+ tHID_CONN* p_hcon;
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
+ HID_CONN_FLAGS_ALL_CONFIGURED) &&
+ (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+
+ hd_cb.device.state = HIDD_DEV_CONNECTED;
+
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
+
+ // send outstanding data on intr
+ if (hd_cb.pending_data) {
+ L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
+ hd_cb.pending_data = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_sec_check_complete_term
+ *
+ * Description HID security check complete callback function.
+ *
+ * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
+ * send security block L2C connection response.
+ *
+ ******************************************************************************/
+static void hidd_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
+
+ if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
+ p_dev->conn.disc_reason = HID_SUCCESS;
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+ L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
+ L2CAP_CONN_OK, L2CAP_CONN_OK);
+ L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
+ } else if (res != BTM_SUCCESS) {
+ HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
+
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
+ L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ return;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_sec_check_complete_orig
+ *
+ * Description HID security check complete callback function (device
+*originated)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void hidd_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
+
+ if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
+ HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__,
+ p_dev->conn.conn_state);
+ return;
+ }
+
+ if (res == BTM_SUCCESS) {
+ HIDD_TRACE_EVENT("%s: security ok", __func__);
+ p_dev->conn.disc_reason = HID_SUCCESS;
+
+ p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
+ L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
+ } else {
+ HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
+ p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
+ hidd_conn_disconnect();
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_connect_ind
+ *
+ * Description Handles incoming L2CAP connection (we act as server)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm,
+ uint8_t id) {
+ tHID_CONN* p_hcon;
+ tHID_DEV_DEV_CTB* p_dev;
+ bool accept = TRUE; // accept by default
+
+ HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
+
+ p_dev = &hd_cb.device;
+
+ if (!hd_cb.allow_incoming) {
+ HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting",
+ __func__);
+ L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ if (p_dev->in_use && memcmp(bd_addr, p_dev->addr, sizeof(BD_ADDR))) {
+ HIDD_TRACE_WARNING(
+ "%s: incoming connections from different device, rejecting", __func__);
+ L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ } else if (!p_dev->in_use) {
+ p_dev->in_use = TRUE;
+ memcpy(p_dev->addr, bd_addr, sizeof(BD_ADDR));
+ p_dev->state = HIDD_DEV_NO_CONN;
+ }
+
+ p_hcon = &hd_cb.device.conn;
+
+ switch (psm) {
+ case HID_PSM_INTERRUPT:
+ if (p_hcon->ctrl_cid == 0) {
+ accept = FALSE;
+ HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting",
+ __func__);
+ }
+
+ if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
+ accept = FALSE;
+ HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting",
+ __func__, p_hcon->conn_state);
+ }
+
+ break;
+
+ case HID_PSM_CONTROL:
+ if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
+ accept = FALSE;
+ HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting",
+ __func__, p_hcon->conn_state);
+ }
+
+ break;
+
+ default:
+ accept = FALSE;
+ HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
+ break;
+ }
+
+ if (!accept) {
+ L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ // for CTRL we need to go through security and we reply in callback from there
+ if (psm == HID_PSM_CONTROL) {
+ p_hcon->conn_flags = 0;
+ p_hcon->ctrl_cid = cid;
+ p_hcon->ctrl_id = id;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE,
+ BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
+ &hidd_sec_check_complete,
+ p_dev) == BTM_CMD_STARTED) {
+ L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
+ }
+
+ return;
+ }
+
+ // for INTR we go directly to config state
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_hcon->intr_cid = cid;
+
+ L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_connect_cfm
+ *
+ * Description Handles L2CAP connection response (we act as client)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) {
+ tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
+ tHID_CONN* p_hcon = &hd_cb.device.conn;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
+
+ if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
+ ((cid == p_hcon->ctrl_cid) &&
+ (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
+ ((cid == p_hcon->intr_cid) &&
+ (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
+ HIDD_TRACE_WARNING("%s: unexpected", __func__);
+ return;
+ }
+
+ if (result != L2CAP_CONN_OK) {
+ HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
+
+ if (cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ hidd_conn_disconnect();
+
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+ HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
+ return;
+ }
+
+ /* CTRL connect conf */
+ if (cid == p_hcon->ctrl_cid) {
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ p_hcon->disc_reason =
+ HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
+
+ btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE,
+ BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
+ &hidd_sec_check_complete_orig, p_dev);
+ } else {
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_config_ind
+ *
+ * Description Handles incoming L2CAP configuration request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ tHID_CONN* p_hcon;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
+ p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
+ else
+ p_hcon->rem_mtu_size = p_cfg->mtu;
+
+ // accept without changes
+ p_cfg->flush_to_present = FALSE;
+ p_cfg->mtu_present = FALSE;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
+ p_cfg->qos_present = TRUE;
+ memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
+ }
+
+ L2CA_ConfigRsp(cid, p_cfg);
+
+ // update flags
+ if (cid == p_hcon->ctrl_cid) {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+ (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+ if ((p_hcon->intr_cid =
+ L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
+ hidd_conn_disconnect();
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
+ __func__);
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+ HID_ERR_L2CAP_FAILED, NULL);
+ return;
+ } else {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+ } else {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+ }
+
+ hidd_check_config_done();
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_config_cfm
+ *
+ * Description Handles incoming L2CAP configuration response
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ tHID_CONN* p_hcon;
+ uint32_t reason;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid,
+ p_cfg->result);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if (p_hcon->intr_cid == cid &&
+ p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
+ tL2CAP_CFG_INFO new_qos;
+
+ // QoS parameters not accepted for intr, try again with host proposal
+
+ memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
+ memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
+ new_qos.qos_present = TRUE;
+
+ HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
+
+ L2CA_ConfigReq(cid, &new_qos);
+ return;
+ } else if (p_hcon->intr_cid == cid &&
+ p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
+ // QoS not understood by remote device, try configuring without QoS
+
+ HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
+
+ L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
+ return;
+ } else if (p_cfg->result != L2CAP_CFG_OK) {
+ HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
+
+ hidd_conn_disconnect();
+ reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
+
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
+ return;
+ }
+
+ // update flags
+ if (cid == p_hcon->ctrl_cid) {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+ (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
+ if ((p_hcon->intr_cid =
+ L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
+ hidd_conn_disconnect();
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
+ __func__);
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+ HID_ERR_L2CAP_FAILED, NULL);
+ return;
+ } else {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+ } else {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+ }
+
+ hidd_check_config_done();
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_disconnect_ind
+ *
+ * Description Handler incoming L2CAP disconnection request
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
+ tHID_CONN* p_hcon;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+ (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if (ack_needed) L2CA_DisconnectRsp(cid);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
+ HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
+
+ // clean any outstanding data on intr
+ if (hd_cb.pending_data) {
+ osi_free(hd_cb.pending_data);
+ hd_cb.pending_data = NULL;
+ }
+
+ hd_cb.device.state = HIDD_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason,
+ NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_disconnect_cfm
+ *
+ * Description Handles L2CAP disconection response
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) {
+ tHID_CONN* p_hcon;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+ (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if (cid == p_hcon->ctrl_cid) {
+ p_hcon->ctrl_cid = 0;
+ } else {
+ p_hcon->intr_cid = 0;
+
+ // now disconnect CTRL
+ L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ }
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
+ HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
+
+ hd_cb.device.state = HIDD_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ if (hd_cb.pending_vc_unplug) {
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG,
+ p_hcon->disc_reason, NULL);
+ hd_cb.pending_vc_unplug = FALSE;
+ } else {
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
+ p_hcon->disc_reason, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_cong_ind
+ *
+ * Description Handles L2CAP congestion status event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
+ tHID_CONN* p_hcon;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+ (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ return;
+ }
+
+ if (congested) {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+ } else {
+ p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_l2cif_data_ind
+ *
+ * Description Handler incoming data on L2CAP channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
+ tHID_CONN* p_hcon;
+ uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint8_t msg_type, param;
+ bool err = FALSE;
+
+ HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
+ (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
+ HIDD_TRACE_WARNING("%s: unknown cid", __func__);
+ osi_free(p_msg);
+ return;
+ }
+
+ msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
+ param = HID_GET_PARAM_FROM_HDR(*p_data);
+
+ if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
+ // skip HID header
+ p_msg->offset++;
+ p_msg->len--;
+
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
+ return;
+ }
+
+ switch (msg_type) {
+ case HID_TRANS_GET_REPORT:
+ // at this stage we don't know if Report Id shall be included in request
+ // so we pass complete packet in callback and let other code analyze this
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT,
+ !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
+ break;
+
+ case HID_TRANS_SET_REPORT:
+ // as above
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
+ break;
+
+ case HID_TRANS_GET_IDLE:
+ hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
+ HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0,
+ NULL);
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_SET_IDLE:
+ if (p_msg->len != 2) {
+ HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received",
+ __func__, p_msg->len);
+ err = TRUE;
+ } else {
+ hd_cb.device.idle_time = p_data[1];
+ HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__,
+ hd_cb.device.idle_time);
+ if (hd_cb.device.idle_time) {
+ HIDD_TRACE_WARNING(
+ "%s: idle_time of %d ms not supported by HID Device", __func__,
+ (hd_cb.device.idle_time * 4));
+ err = TRUE;
+ }
+ }
+ if (!err) {
+ hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+ HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
+ } else {
+ hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+ HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0,
+ NULL);
+ }
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_GET_PROTOCOL:
+ hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
+ HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0,
+ NULL);
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_SET_PROTOCOL:
+ hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL,
+ param & HID_PAR_PROTOCOL_MASK, NULL);
+ hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS,
+ 0, 0, NULL);
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_CONTROL:
+ switch (param) {
+ case HID_PAR_CONTROL_SUSPEND:
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
+ break;
+
+ case HID_PAR_CONTROL_EXIT_SUSPEND:
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0,
+ NULL);
+ break;
+
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ hidd_conn_disconnect();
+
+ // set flag so we can notify properly when disconnected
+ hd_cb.pending_vc_unplug = TRUE;
+ break;
+ }
+
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_DATA:
+ default:
+ HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
+ hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
+ HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0,
+ NULL);
+ osi_free(p_msg);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_conn_reg
+ *
+ * Description Registers L2CAP channels
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_reg(void) {
+ HIDD_TRACE_API("%s", __func__);
+
+ memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ hd_cb.l2cap_cfg.mtu_present = TRUE;
+ hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
+ hd_cb.l2cap_cfg.flush_to_present = TRUE;
+ hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
+
+ memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
+ hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
+ hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
+ hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
+
+ if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+ HIDD_TRACE_ERROR("HID Control (device) registration failed");
+ return (HID_ERR_L2CAP_FAILED);
+ }
+
+ if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+ L2CA_Deregister(HID_PSM_CONTROL);
+ HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
+ return (HID_ERR_L2CAP_FAILED);
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_conn_dereg
+ *
+ * Description Deregisters L2CAP channels
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void hidd_conn_dereg(void) {
+ HIDD_TRACE_API("%s", __func__);
+
+ L2CA_Deregister(HID_PSM_CONTROL);
+ L2CA_Deregister(HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_conn_initiate
+ *
+ * Description Initiates HID connection to plugged device
+ *
+ * Returns HID_SUCCESS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_initiate(void) {
+ tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ if (!p_dev->in_use) {
+ HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
+ return (HID_ERR_NOT_REGISTERED);
+ }
+
+ if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
+ HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
+ return (HID_ERR_CONN_IN_PROCESS);
+ }
+
+ p_dev->conn.ctrl_cid = 0;
+ p_dev->conn.intr_cid = 0;
+ p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
+
+ p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+ BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
+
+ /* Check if L2CAP started the connection process */
+ if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) ==
+ 0) {
+ HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
+ hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,
+ NULL);
+ } else {
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_conn_disconnect
+ *
+ * Description Disconnects existing HID connection
+ *
+ * Returns HID_SUCCESS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_disconnect(void) {
+ tHID_CONN* p_hcon;
+
+ HIDD_TRACE_API("%s", __func__);
+
+ // clean any outstanding data on intr
+ if (hd_cb.pending_data) {
+ osi_free(hd_cb.pending_data);
+ hd_cb.pending_data = NULL;
+ }
+
+ p_hcon = &hd_cb.device.conn;
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ /* Set l2cap idle timeout to 0 (so ACL link is disconnected
+ * immediately after last channel is closed) */
+ L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
+
+ if (p_hcon->intr_cid) {
+ L2CA_DisconnectReq(p_hcon->intr_cid);
+ } else if (p_hcon->ctrl_cid) {
+ L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ }
+ } else {
+ HIDD_TRACE_WARNING("%s: already disconnected", __func__);
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function hidd_conn_send_data
+ *
+ * Description Sends data to host
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
+ uint8_t param, uint8_t data, uint16_t len,
+ uint8_t* p_data) {
+ tHID_CONN* p_hcon;
+ BT_HDR* p_buf;
+ uint8_t* p_out;
+ uint16_t cid;
+ uint16_t buf_size;
+
+ HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
+ channel, msg_type, len);
+
+ p_hcon = &hd_cb.device.conn;
+
+ if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
+ return HID_ERR_CONGESTED;
+ }
+
+ switch (msg_type) {
+ case HID_TRANS_HANDSHAKE:
+ case HID_TRANS_CONTROL:
+ cid = p_hcon->ctrl_cid;
+ buf_size = HID_CONTROL_BUF_SIZE;
+ break;
+ case HID_TRANS_DATA:
+ if (channel == HID_CHANNEL_CTRL) {
+ cid = p_hcon->ctrl_cid;
+ buf_size = HID_CONTROL_BUF_SIZE;
+ } else {
+ cid = p_hcon->intr_cid;
+ buf_size = HID_INTERRUPT_BUF_SIZE;
+ }
+ break;
+ default:
+ return (HID_ERR_INVALID_PARAM);
+ }
+
+ p_buf = (BT_HDR*)osi_malloc(buf_size);
+ if (p_buf == NULL) return (HID_ERR_NO_RESOURCES);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+
+ p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_out = HID_BUILD_HDR(msg_type, param);
+ p_out++;
+
+ p_buf->len = 1; // start with header only
+
+ // add report id prefix only if non-zero (which is reserved)
+ if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
+ *p_out = data; // report_id
+ p_out++;
+ p_buf->len++;
+ }
+
+ if (len > 0 && p_data != NULL) {
+ memcpy(p_out, p_data, len);
+ p_buf->len += len;
+ }
+
+ // check if connected
+ if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
+ // for DATA on intr we hold transfer and try to reconnect
+ if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
+ // drop previous data, we do not queue it for now
+ if (hd_cb.pending_data) {
+ osi_free(hd_cb.pending_data);
+ }
+
+ hd_cb.pending_data = p_buf;
+
+ if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
+ hidd_conn_initiate();
+ }
+
+ return HID_SUCCESS;
+ }
+
+ return HID_ERR_NO_CONNECTION;
+ }
+
+#ifdef REPORT_TRANSFER_TIMESTAMP
+ if (report_transfer) {
+ HIDD_TRACE_ERROR("%s: report sent", __func__);
+ }
+#endif
+ HIDD_TRACE_VERBOSE("%s: report sent", __func__);
+
+ if (!L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED);
+
+ return (HID_SUCCESS);
+}
diff --git a/mtkbt/code/bt/stack/hid/hidd_int.h b/mtkbt/code/bt/stack/hid/hidd_int.h
new file mode 100755
index 0000000..cce1302
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidd_int.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains HID DEVICE internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDD_INT_H
+#define HIDD_INT_H
+
+#include "hid_conn.h"
+#include "hidd_api.h"
+#include "l2c_api.h"
+
+enum { HIDD_DEV_NO_CONN, HIDD_DEV_CONNECTED };
+
+typedef struct device_ctb {
+ bool in_use;
+ BD_ADDR addr;
+
+ uint8_t state;
+
+ tHID_CONN conn;
+
+ bool boot_mode;
+
+ uint8_t idle_time;
+} tHID_DEV_DEV_CTB;
+
+typedef struct dev_ctb {
+ tHID_DEV_DEV_CTB device;
+
+ tHID_DEV_HOST_CALLBACK* callback;
+ tL2CAP_CFG_INFO l2cap_cfg;
+ tL2CAP_CFG_INFO l2cap_intr_cfg;
+
+ bool use_in_qos;
+ FLOW_SPEC in_qos;
+
+ bool reg_flag;
+ uint8_t trace_level;
+
+ bool allow_incoming;
+
+ BT_HDR* pending_data;
+
+ bool pending_vc_unplug;
+} tHID_DEV_CTB;
+
+extern tHID_STATUS hidd_conn_reg(void);
+extern void hidd_conn_dereg(void);
+extern tHID_STATUS hidd_conn_initiate(void);
+extern tHID_STATUS hidd_conn_disconnect(void);
+extern tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
+ uint8_t param, uint8_t data,
+ uint16_t len, uint8_t* p_data);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+#if HID_DYNAMIC_MEMORY == FALSE
+extern tHID_DEV_CTB hd_cb;
+#else
+extern tHID_DEV_CTB* hidd_cb_ptr;
+#define hd_cb (*hidd_cb_ptr)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/stack/hid/hidh_api.cc b/mtkbt/code/bt/stack/hid/hidh_api.cc
new file mode 100755
index 0000000..21b3d9e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidh_api.cc
@@ -0,0 +1,597 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the HID HOST API entry points
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hiddefs.h"
+#include "hidh_api.h"
+#include "hidh_int.h"
+
+tHID_HOST_CTB hh_cb;
+
+static void hidh_search_callback(uint16_t sdp_result);
+
+/*******************************************************************************
+ *
+ * Function HID_HostGetSDPRecord
+ *
+ * Description This function reads the device SDP record
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostGetSDPRecord(BD_ADDR addr, tSDP_DISCOVERY_DB* p_db,
+ uint32_t db_len,
+ tHID_HOST_SDP_CALLBACK* sdp_cback) {
+ tSDP_UUID uuid_list;
+
+ if (hh_cb.sdp_busy) return HID_ERR_SDP_BUSY;
+
+ uuid_list.len = 2;
+ uuid_list.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.p_sdp_db = p_db;
+ SDP_InitDiscoveryDb(p_db, db_len, 1, &uuid_list, 0, NULL);
+
+ if (SDP_ServiceSearchRequest(addr, p_db, hidh_search_callback)) {
+ hh_cb.sdp_cback = sdp_cback;
+ hh_cb.sdp_busy = true;
+ return HID_SUCCESS;
+ } else
+ return HID_ERR_NO_RESOURCES;
+}
+
+void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len,
+ char* str) {
+ tSDP_DISC_ATTR* p_attr;
+ uint16_t name_len;
+
+ p_attr = SDP_FindAttributeInRec(p_rec, attr_id);
+ if (p_attr != NULL) {
+ name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ if (name_len < max_len) {
+ memcpy(str, (char*)p_attr->attr_value.v.array, name_len);
+ str[name_len] = '\0';
+ } else {
+ memcpy(str, (char*)p_attr->attr_value.v.array, max_len - 1);
+ str[max_len - 1] = '\0';
+ }
+ } else
+ str[0] = '\0';
+}
+
+static void hidh_search_callback(uint16_t sdp_result) {
+ tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
+ tBT_UUID hid_uuid;
+ tHID_DEV_SDP_INFO* p_nvi = &hh_cb.sdp_rec;
+ uint16_t attr_mask = 0;
+
+ hid_uuid.len = LEN_UUID_16;
+ hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE;
+
+ hh_cb.sdp_busy = false;
+
+ if (sdp_result != SDP_SUCCESS) {
+ hh_cb.sdp_cback(sdp_result, 0, NULL);
+ return;
+ }
+
+ p_rec = SDP_FindServiceUUIDInDb(p_db, &hid_uuid, NULL);
+ if (p_rec == NULL) {
+ hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
+ return;
+ }
+
+ memset(&hh_cb.sdp_rec, 0, sizeof(tHID_DEV_SDP_INFO));
+
+ /* First, verify the mandatory fields we care about */
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) ==
+ NULL) ||
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) ||
+ ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL) ||
+ (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) !=
+ DATA_ELE_SEQ_DESC_TYPE) ||
+ ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) ||
+ ((p_repdesc = p_subattr2->p_next_attr) == NULL) ||
+ (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) {
+ hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
+ return;
+ }
+
+ p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type);
+ if (p_nvi->dscp_info.dl_len != 0)
+ p_nvi->dscp_info.dsc_list = (uint8_t*)&p_repdesc->attr_value;
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) !=
+ NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_VIRTUAL_CABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(
+ p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_RECONN_INIT;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(
+ p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_NORMALLY_CONNECTABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SDP_DISABLE)) !=
+ NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_SDP_DISABLE;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_BATTERY_POWER)) !=
+ NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_BATTERY_POWER;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_REMOTE_WAKE)) !=
+ NULL) &&
+ (p_attr->attr_value.v.u8)) {
+ attr_mask |= HID_REMOTE_WAKE;
+ }
+
+ hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN,
+ p_nvi->svc_name);
+ hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN,
+ p_nvi->svc_descr);
+ hidh_get_str_attr(p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN,
+ p_nvi->prov_name);
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_RELNUM)) !=
+ NULL)) {
+ p_nvi->rel_num = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_COUNTRY_CODE)) !=
+ NULL)) {
+ p_nvi->ctry_code = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) !=
+ NULL)) {
+ p_nvi->sub_class = p_attr->attr_value.v.u8;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_PARSER_VERSION)) !=
+ NULL)) {
+ p_nvi->hpars_ver = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(
+ p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL)) {
+ attr_mask |= HID_SUP_TOUT_AVLBL;
+ p_nvi->sup_timeout = p_attr->attr_value.v.u16;
+ }
+
+ if (((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) !=
+ NULL)) {
+ attr_mask |= HID_SSR_MAX_LATENCY;
+ p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
+ } else
+ p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
+
+ if (((p_attr = SDP_FindAttributeInRec(
+ p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL)) {
+ attr_mask |= HID_SSR_MIN_TOUT;
+ p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
+ } else
+ p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID;
+
+ hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
+ hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostInit
+ *
+ * Description This function initializes the control block and trace
+ * variable
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void HID_HostInit(void) {
+ uint8_t log_level = hh_cb.trace_level;
+ memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
+ hh_cb.trace_level = log_level;
+
+ /**M:Bug fix for memory leak @{*/
+ /*Here free the timer which had been allocated in bta_hh_api_enable process */
+ for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ if(alarm_is_scheduled(hh_cb.devices[i].conn.process_repage_timer))
+ {
+ alarm_free(hh_cb.devices[i].conn.process_repage_timer);
+ hh_cb.devices[i].conn.process_repage_timer = NULL;
+ }
+ }
+ /**@}*/
+ for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ hh_cb.devices[i].conn.process_repage_timer =
+ alarm_new("hid_devices_conn.process_repage_timer");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostSetTraceLevel
+ *
+ * Description This function sets the trace level for HID Host. If called
+ * with 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t HID_HostSetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) hh_cb.trace_level = new_level;
+
+ return (hh_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostRegister
+ *
+ * Description This function registers HID-Host with lower layers
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) {
+ tHID_STATUS st;
+
+ if (hh_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED;
+
+ if (dev_cback == NULL) return HID_ERR_INVALID_PARAM;
+
+ /* Register with L2CAP */
+ st = hidh_conn_reg();
+ if (st != HID_SUCCESS) {
+ return st;
+ }
+
+ hh_cb.callback = dev_cback;
+ hh_cb.reg_flag = true;
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostDeregister
+ *
+ * Description This function is called when the host is about power down.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostDeregister(void) {
+ uint8_t i;
+
+ if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ HID_HostRemoveDev(i);
+ }
+
+ hidh_conn_dereg();
+ hh_cb.reg_flag = false;
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostAddDev
+ *
+ * Description This is called so HID-host may manage this device.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostAddDev(BD_ADDR addr, uint16_t attr_mask, uint8_t* handle) {
+ int i;
+ /* Find an entry for this device in hh_cb.devices array */
+ if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ if ((hh_cb.devices[i].in_use) &&
+ (!memcmp(addr, hh_cb.devices[i].addr, BD_ADDR_LEN)))
+ break;
+ }
+
+ if (i == HID_HOST_MAX_DEVICES) {
+ for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ if (!hh_cb.devices[i].in_use) break;
+ }
+ }
+
+ if (i == HID_HOST_MAX_DEVICES) return HID_ERR_NO_RESOURCES;
+
+ if (!hh_cb.devices[i].in_use) {
+ hh_cb.devices[i].in_use = true;
+ memcpy(hh_cb.devices[i].addr, addr, sizeof(BD_ADDR));
+ hh_cb.devices[i].state = HID_DEV_NO_CONN;
+ hh_cb.devices[i].conn_tries = 0;
+ }
+
+ if (attr_mask != HID_ATTR_MASK_IGNORE) hh_cb.devices[i].attr_mask = attr_mask;
+
+ *handle = i;
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostRemoveDev
+ *
+ * Description This removes the device from the list of devices that the
+ * host has to manage.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) {
+ if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
+ (!hh_cb.devices[dev_handle].in_use))
+ return HID_ERR_INVALID_PARAM;
+
+ HID_HostCloseDev(dev_handle);
+ hh_cb.devices[dev_handle].in_use = false;
+ hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.devices[dev_handle].conn.ctrl_cid =
+ hh_cb.devices[dev_handle].conn.intr_cid = 0;
+ hh_cb.devices[dev_handle].attr_mask = 0;
+ return HID_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostOpenDev
+ *
+ * Description This function is called when the user wants to initiate a
+ * connection attempt to a device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) {
+ if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
+ (!hh_cb.devices[dev_handle].in_use))
+ return HID_ERR_INVALID_PARAM;
+
+ if (hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN)
+ return HID_ERR_ALREADY_CONN;
+
+ hh_cb.devices[dev_handle].conn_tries = 1;
+ return hidh_conn_initiate(dev_handle);
+}
+
+/*******************************************************************************
+ *
+ * Function HID_HostWriteDev
+ *
+ * Description This function is called when the host has a report to send.
+ *
+ * report_id: is only used on GET_REPORT transaction if is
+ * specified. only valid when it is non-zero.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param,
+ uint16_t data, uint8_t report_id, BT_HDR* pbuf) {
+ tHID_STATUS status = HID_SUCCESS;
+
+ if (!hh_cb.reg_flag) {
+ HIDH_TRACE_ERROR("HID_ERR_NOT_REGISTERED");
+ status = HID_ERR_NOT_REGISTERED;
+ }
+
+ if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
+ (!hh_cb.devices[dev_handle].in_use)) {
+ HIDH_TRACE_ERROR("HID_ERR_INVALID_PARAM");
+ status = HID_ERR_INVALID_PARAM;
+ }
+
+ else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {
+ HIDH_TRACE_ERROR("HID_ERR_NO_CONNECTION dev_handle %d", dev_handle);
+ status = HID_ERR_NO_CONNECTION;
+ }
+
+ if (status != HID_SUCCESS)
+ osi_free(pbuf);
+ else
+ status =
+ hidh_conn_snd_data(dev_handle, t_type, param, data, report_id, pbuf);
+
+ return status;
+}
+
+/**M: HID device reconnect fail for collision@{*/
+/*******************************************************************************
+**
+** Function HID_HostCloseCollisionDev
+**
+** Description This function disconnects the device in collision.
+**
+** Returns void
+**
+*******************************************************************************/
+tHID_STATUS HID_HostCloseCollisionDev(uint8_t dev_handle)
+{
+ if( !hh_cb.reg_flag )
+ return (HID_ERR_NOT_REGISTERED);
+
+ HIDH_TRACE_ERROR ("HID_HostCloseCollisionDev, in_use = %d",hh_cb.devices[dev_handle].in_use);
+
+ if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) )
+ return HID_ERR_INVALID_PARAM;
+
+ alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1;
+
+ return hidh_conn_collision_disconnect(dev_handle);
+}
+/**@}*/
+
+/*******************************************************************************
+ *
+ * Function HID_HostCloseDev
+ *
+ * Description This function disconnects the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) {
+ if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
+
+ if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
+ (!hh_cb.devices[dev_handle].in_use))
+ return HID_ERR_INVALID_PARAM;
+
+ if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED)
+ return HID_ERR_NO_CONNECTION;
+
+ alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);
+ hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY + 1;
+ return hidh_conn_disconnect(dev_handle);
+}
+
+tHID_STATUS HID_HostSetSecurityLevel(const char serv_name[], uint8_t sec_lvl) {
+ if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HID_SEC_CHN)) {
+ HIDH_TRACE_ERROR("Security Registration 1 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_SEC_CTRL,
+ sec_lvl, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HID_SEC_CHN)) {
+ HIDH_TRACE_ERROR("Security Registration 2 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HID_NOSEC_CHN)) {
+ HIDH_TRACE_ERROR("Security Registration 3 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_NOSEC_CTRL,
+ BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID,
+ HID_NOSEC_CHN)) {
+ HIDH_TRACE_ERROR("Security Registration 4 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(true, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
+ 0)) {
+ HIDH_TRACE_ERROR("Security Registration 5 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ if (!BTM_SetSecurityLevel(false, serv_name, BTM_SEC_SERVICE_HIDH_INTR,
+ BTM_SEC_NONE, HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID,
+ 0)) {
+ HIDH_TRACE_ERROR("Security Registration 6 failed");
+ return (HID_ERR_NO_RESOURCES);
+ }
+
+ return (HID_SUCCESS);
+}
+
+/******************************************************************************
+ *
+ * Function hid_known_hid_device
+ *
+ * Description check if this device is of type HID Device
+ *
+ * Returns true if device is HID Device else false
+ *
+ ******************************************************************************/
+bool hid_known_hid_device(BD_ADDR bd_addr) {
+ uint8_t i;
+ tBTM_INQ_INFO* p_inq_info = BTM_InqDbRead(bd_addr);
+
+ if (!hh_cb.reg_flag) return false;
+
+ /* First check for class of device , if Inq DB has information about this
+ * device*/
+ if (p_inq_info != NULL) {
+ /* Check if remote major device class is of type BTM_COD_MAJOR_PERIPHERAL */
+ if ((p_inq_info->results.dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
+ BTM_COD_MAJOR_PERIPHERAL) {
+ HIDH_TRACE_DEBUG(
+ "hid_known_hid_device:dev found in InqDB & COD matches HID dev");
+ return true;
+ }
+ } else {
+ /* Look for this device in security device DB */
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
+ if ((p_dev_rec != NULL) &&
+ ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
+ BTM_COD_MAJOR_PERIPHERAL)) {
+ HIDH_TRACE_DEBUG(
+ "hid_known_hid_device:dev found in SecDevDB & COD matches HID dev");
+ return true;
+ }
+ }
+
+ /* Find an entry for this device in hh_cb.devices array */
+ for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
+ if ((hh_cb.devices[i].in_use) &&
+ (memcmp(bd_addr, hh_cb.devices[i].addr, BD_ADDR_LEN) == 0))
+ return true;
+ }
+ /* Check if this device is marked as HID Device in IOP Dev */
+ HIDH_TRACE_DEBUG("hid_known_hid_device:remote is not HID device");
+ return false;
+}
diff --git a/mtkbt/code/bt/stack/hid/hidh_conn.cc b/mtkbt/code/bt/stack/hid/hidh_conn.cc
new file mode 100755
index 0000000..76a29b2
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidh_conn.cc
@@ -0,0 +1,1142 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the connection interface functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+
+#include "hiddefs.h"
+
+#include "bt_utils.h"
+#include "hidh_api.h"
+#include "hidh_int.h"
+
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+static uint8_t find_conn_by_cid(uint16_t cid);
+static void hidh_conn_retry(uint8_t dhandle);
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void hidh_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ uint16_t psm, uint8_t l2cap_id);
+static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
+static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
+static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested);
+
+static const tL2CAP_APPL_INFO hst_reg_info = {
+ hidh_l2cif_connect_ind,
+ hidh_l2cif_connect_cfm,
+ NULL,
+ hidh_l2cif_config_ind,
+ hidh_l2cif_config_cfm,
+ hidh_l2cif_disconnect_ind,
+ hidh_l2cif_disconnect_cfm,
+ NULL,
+ hidh_l2cif_data_ind,
+ hidh_l2cif_cong_ind,
+ NULL /* tL2CA_TX_COMPLETE_CB */
+};
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_reg
+ *
+ * Description This function initializes the SDP unit.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS hidh_conn_reg(void) {
+ int xx;
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ hh_cb.l2cap_cfg.mtu_present = true;
+ hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
+ hh_cb.l2cap_cfg.flush_to_present = true;
+ hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+ HIDH_TRACE_ERROR("HID-Host Control Registration failed");
+ return (HID_ERR_L2CAP_FAILED);
+ }
+ if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+ L2CA_Deregister(HID_PSM_CONTROL);
+ HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed");
+ return (HID_ERR_L2CAP_FAILED);
+ }
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
+ hh_cb.devices[xx].in_use = false;
+ hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_conn_disconnect
+ *
+ * Description This function disconnects a connection.
+ *
+ * Returns true if disconnect started, false if already disconnected
+ *
+ ******************************************************************************/
+tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) {
+ tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
+
+ HIDH_TRACE_EVENT("HID-Host disconnect");
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ /* Set l2cap idle timeout to 0 (so ACL link is disconnected
+ * immediately after last channel is closed) */
+ L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0,
+ BT_TRANSPORT_BR_EDR);
+ /* Disconnect both interrupt and control channels */
+ if (p_hcon->intr_cid)
+ L2CA_DisconnectReq(p_hcon->intr_cid);
+ else if (p_hcon->ctrl_cid)
+ L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ } else {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/**M: HID device reconnect fail for collision@{*/
+/*******************************************************************************
+**
+** Function hidh_conn_process_collision_timeout
+**
+** Description This function disconnects a connection.
+**
+** Returns TRUE if disconnect started, FALSE if already disconnected
+**
+*******************************************************************************/
+void hidh_conn_process_collision_timeout(uint8_t dhandle)
+{
+ uint16_t result = 0;
+ uint16_t l2cap_cid = 0;
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+
+ l2cap_cid = p_hcon->ctrl_cid;
+ hidh_l2cif_disconnect_cfm(l2cap_cid, result);
+}
+
+/*******************************************************************************
+**
+** Function hidh_conn_disconnect
+**
+** Description This function disconnects a connection.
+**
+** Returns TRUE if disconnect started, FALSE if already disconnected
+**
+*******************************************************************************/
+tHID_STATUS hidh_conn_collision_disconnect (uint8_t dhandle)
+{
+ tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
+
+ HIDH_TRACE_ERROR("HID-Host disconnect");
+
+ if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
+ {
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ /* Set l2cap idle timeout to 0 (so ACL link is disconnected
+ * immediately after last channel is closed) */
+ L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
+ /* Disconnect both interrupt and control channels */
+ if (p_hcon->intr_cid)
+ {
+ HIDH_TRACE_ERROR("HID-Host disconnect intruppt channel");
+ L2CA_DisconnectReq (p_hcon->intr_cid);
+ }
+ else if (p_hcon->ctrl_cid)
+ {
+ HIDH_TRACE_ERROR("HID-Host disconnect control channel");
+ L2CA_DisconnectReq (p_hcon->ctrl_cid);
+ }
+ }
+ else
+ {
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ }
+
+ hidh_conn_process_collision_timeout(dhandle);
+
+ return (HID_SUCCESS);
+}
+/**@}*/
+
+/*******************************************************************************
+ *
+ * Function hidh_sec_check_complete_term
+ *
+ * Description HID security check complete callback function.
+ *
+ * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
+ * send security block L2C connection response.
+ *
+ ******************************************************************************/
+void hidh_sec_check_complete_term(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data;
+
+ if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset
+ disc_reason (from
+ HID_ERR_AUTH_FAILED) */
+
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
+ L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+
+ }
+ /* security check fail */
+ else if (res != BTM_SUCCESS) {
+ p_dev->conn.disc_reason =
+ HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+ L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
+ L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_connect_ind
+ *
+ * Description This function handles an inbound connection indication
+ * from L2CAP. This is the case where we are acting as a
+ * server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ uint16_t psm, uint8_t l2cap_id) {
+ tHID_CONN* p_hcon;
+ bool bAccept = true;
+ uint8_t i = HID_HOST_MAX_DEVICES;
+ tHID_HOST_DEV_CTB* p_dev;
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm,
+ l2cap_cid);
+
+ /* always add incoming connection device into HID database by default */
+ if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) {
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
+ return;
+ }
+
+ p_hcon = &hh_cb.devices[i].conn;
+ p_dev = &hh_cb.devices[i];
+
+ /* Check we are in the correct state for this */
+ if (psm == HID_PSM_INTERRUPT) {
+ if (p_hcon->ctrl_cid == 0) {
+ HIDH_TRACE_WARNING(
+ "HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
+ bAccept = false;
+ }
+ if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
+ p_hcon->conn_state);
+ bAccept = false;
+ }
+ } else /* CTRL channel */
+ {
+/**M: Open Macro for accept hid connection @{*/
+/*#if defined(HID_HOST_ACPT_NEW_CONN)*/
+#if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
+/**@}*/
+ p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+#else
+ if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
+ HIDH_TRACE_WARNING("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
+ p_hcon->conn_state);
+ bAccept = false;
+ }
+#endif
+ }
+
+ if (!bAccept) {
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+
+ if (psm == HID_PSM_CONTROL) {
+ p_hcon->conn_flags = 0;
+ p_hcon->ctrl_cid = l2cap_cid;
+ p_hcon->ctrl_id = l2cap_id;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs
+ before security is completed,
+ then set CLOSE_EVT reason code
+ to 'connection failure' */
+
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ if (btm_sec_mx_access_request(
+ p_dev->addr, HID_PSM_CONTROL, false, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED) {
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING,
+ L2CAP_CONN_OK);
+ }
+
+ return;
+ }
+
+ /* Transition to the next appropriate state, configuration */
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ p_hcon->intr_cid = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg);
+
+ HIDH_TRACE_EVENT(
+ "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
+ psm, l2cap_cid);
+}
+
+void hidh_process_repage_timer_timeout(void* data) {
+ uint8_t dhandle = PTR_TO_UINT(data);
+ hidh_try_repage(dhandle);
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_try_repage
+ *
+ * Description This function processes timeout (to page device).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void hidh_try_repage(uint8_t dhandle) {
+ tHID_HOST_DEV_CTB* device;
+
+ hidh_conn_initiate(dhandle);
+
+ device = &hh_cb.devices[dhandle];
+ device->conn_tries++;
+
+ hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
+ device->conn_tries, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_sec_check_complete_orig
+ *
+ * Description This function checks to see if security procedures are being
+ * carried out or not..
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void hidh_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data;
+ uint8_t dhandle;
+
+ // TODO(armansito): This kind of math to determine a device handle is way
+ // too dirty and unnecessary. Why can't |p_dev| store it's handle?
+ dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0]))) /
+ sizeof(tHID_HOST_DEV_CTB);
+ if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
+ HIDH_TRACE_EVENT("HID-Host Originator security pass.");
+ p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset
+ disc_reason (from
+ HID_ERR_AUTH_FAILED) */
+
+ /* Transition to the next appropriate state, configuration */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
+ L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
+ HIDH_TRACE_EVENT("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x",
+ p_dev->conn.ctrl_cid);
+ }
+
+ if (res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if (res == BTM_DEVICE_TIMEOUT) {
+ if (p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY) {
+ hidh_conn_retry(dhandle);
+ return;
+ }
+ }
+#endif
+ p_dev->conn.disc_reason =
+ HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
+ hidh_conn_disconnect(dhandle);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_connect_cfm
+ *
+ * Description This function handles the connect confirm events
+ * from L2CAP. This is the case when we are acting as a
+ * client and have sent a connect request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+ uint32_t reason;
+ tHID_HOST_DEV_CTB* p_dev = NULL;
+
+ /* Find CCB based on CID, and verify we are in a state to accept this message
+ */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) {
+ p_dev = &hh_cb.devices[dhandle];
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
+ ((l2cap_cid == p_hcon->ctrl_cid) &&
+ (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
+ ((l2cap_cid == p_hcon->intr_cid) &&
+ (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
+ (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ",
+ l2cap_cid);
+ return;
+ }
+
+ if (result != L2CAP_CONN_OK) {
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ hidh_conn_disconnect(dhandle);
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if ((hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
+ (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
+ result == HCI_ERR_PAGE_TIMEOUT)) {
+ hidh_conn_retry(dhandle);
+ } else
+#endif
+ {
+ reason = HID_L2CAP_CONN_FAIL | (uint32_t)result;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ reason, NULL);
+ }
+ return;
+ }
+ /* receive Control Channel connect confirmation */
+ if (l2cap_cid == p_hcon->ctrl_cid) {
+ /* check security requirement */
+ p_hcon->conn_state = HID_CONN_STATE_SECURITY;
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs
+ before security is completed,
+ then set CLOSE_EVT reason code
+ to "connection failure" */
+
+ btm_sec_mx_access_request(
+ p_dev->addr, HID_PSM_CONTROL, true, BTM_SEC_PROTO_HID,
+ (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
+ &hidh_sec_check_complete_orig, p_dev);
+ } else {
+ p_hcon->conn_state = HID_CONN_STATE_CONFIG;
+ /* Send a Configuration Request. */
+ L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg);
+ HIDH_TRACE_EVENT("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x",
+ l2cap_cid);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_config_ind
+ *
+ * Description This function processes the L2CAP configuration indication
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+ uint32_t reason;
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) {
+ p_hcon = &hh_cb.devices[dhandle].conn;
+ }
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ /* Remember the remote MTU size */
+ if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
+ p_hcon->rem_mtu_size = HID_HOST_MTU;
+ else
+ p_hcon->rem_mtu_size = p_cfg->mtu;
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = false;
+ p_cfg->mtu_present = false;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp(l2cap_cid, p_cfg);
+
+ if (l2cap_cid == p_hcon->ctrl_cid) {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+ (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
+ /* Connect interrupt channel */
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
+ CLOSE_EVT: Connection
+ Attempt was made but failed
+ */
+ p_hcon->intr_cid =
+ L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr);
+ if (p_hcon->intr_cid == 0) {
+ HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
+ reason = HID_L2CAP_REQ_FAIL;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hidh_conn_disconnect(dhandle);
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ reason, NULL);
+ return;
+ } else {
+ /* Transition to the next appropriate state, waiting for connection
+ * confirm on interrupt channel. */
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+ } else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are
+ * up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
+ HID_CONN_FLAGS_ALL_CONFIGURED) &&
+ (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+ /* Reset disconnect reason to success, as connection successful */
+ p_hcon->disc_reason = HID_SUCCESS;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
+ NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_config_cfm
+ *
+ * Description This function processes the L2CAP configuration confirmation
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+ uint32_t reason;
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid,
+ p_cfg->result);
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ /* If configuration failed, disconnect the channel(s) */
+ if (p_cfg->result != L2CAP_CFG_OK) {
+ hidh_conn_disconnect(dhandle);
+ reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ reason, NULL);
+ return;
+ }
+
+ if (l2cap_cid == p_hcon->ctrl_cid) {
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
+ (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
+ /* Connect interrupt channel */
+ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
+ CLOSE_EVT: Connection
+ Attempt was made but failed
+ */
+ p_hcon->intr_cid =
+ L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr);
+ if (p_hcon->intr_cid == 0) {
+ HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
+ reason = HID_L2CAP_REQ_FAIL;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hidh_conn_disconnect(dhandle);
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ reason, NULL);
+ return;
+ } else {
+ /* Transition to the next appropriate state, waiting for connection
+ * confirm on interrupt channel. */
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
+ }
+ }
+ } else
+ p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
+
+ /* If all configuration is complete, change state and tell management we are
+ * up */
+ if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
+ HID_CONN_FLAGS_ALL_CONFIGURED) &&
+ (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
+ p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
+ /* Reset disconnect reason to success, as connection successful */
+ p_hcon->disc_reason = HID_SUCCESS;
+
+ hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
+ NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_disconnect_ind
+ *
+ * Description This function handles a disconnect event from L2CAP. If
+ * requested to, we ack the disconnect before dropping the CCB
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+ uint16_t disc_res = HCI_SUCCESS;
+ uint16_t hid_close_evt_reason;
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ if (ack_needed) L2CA_DisconnectRsp(l2cap_cid);
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+
+ p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else
+ p_hcon->intr_cid = 0;
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+
+ if (!ack_needed) disc_res = btm_get_acl_disc_reason_code();
+
+#if (HID_HOST_MAX_CONN_RETRY > 0)
+ if ((disc_res == HCI_ERR_CONNECTION_TOUT ||
+ disc_res == HCI_ERR_UNSPECIFIED) &&
+ (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
+ (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) {
+ hh_cb.devices[dhandle].conn_tries = 0;
+ period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ alarm_set_on_queue(hh_cb.devices[dhandle].conn.process_repage_timer,
+ interval_ms, hidh_process_repage_timer_timeout,
+ UINT_TO_PTR(dhandle), btu_general_alarm_queue);
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ disc_res, NULL);
+ } else
+#endif
+ {
+ /* Set reason code for HID_HDEV_EVT_CLOSE */
+ hid_close_evt_reason = p_hcon->disc_reason;
+
+ /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security
+ * failure, then set reason to HID_ERR_AUTH_FAILED */
+ if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
+ (disc_res == HCI_ERR_KEY_MISSING) ||
+ (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (disc_res == HCI_ERR_UNIT_KEY_USED) ||
+ (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
+ (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) {
+ hid_close_evt_reason = HID_ERR_AUTH_FAILED;
+ }
+
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ hid_close_evt_reason, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_disconnect_cfm
+ *
+ * Description This function handles a disconnect confirm event from L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid,
+ UNUSED_ATTR uint16_t result) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ if (l2cap_cid == p_hcon->ctrl_cid)
+ p_hcon->ctrl_cid = 0;
+ else {
+ p_hcon->intr_cid = 0;
+ if (p_hcon->ctrl_cid) {
+ HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection");
+ L2CA_DisconnectReq(p_hcon->ctrl_cid);
+ }
+ }
+
+ if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
+ hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
+ p_hcon->conn_state = HID_CONN_STATE_UNUSED;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ p_hcon->disc_reason, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_cong_ind
+ *
+ * Description This function handles a congestion status event from L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) {
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING(
+ "HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d",
+ l2cap_cid, congested);
+
+ if (congested)
+ p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
+ else {
+ p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_l2cif_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ * if we are the originator of the connection, we are the SDP
+ * client, and the received message is queued up for the
+ * client.
+ *
+ * If we are the destination of the connection, we are the SDP
+ * server, so the message is passed to the server processing
+ * function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
+ uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint8_t ttype, param, rep_type, evt;
+ uint8_t dhandle;
+ tHID_CONN* p_hcon = NULL;
+
+ HIDH_TRACE_DEBUG("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]",
+ l2cap_cid);
+
+ /* Find CCB based on CID */
+ dhandle = find_conn_by_cid(l2cap_cid);
+ if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
+
+ if (p_hcon == NULL) {
+ HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x",
+ l2cap_cid);
+ osi_free(p_msg);
+ return;
+ }
+
+ ttype = HID_GET_TRANS_FROM_HDR(*p_data);
+ param = HID_GET_PARAM_FROM_HDR(*p_data);
+ rep_type = param & HID_PAR_REP_TYPE_MASK;
+ p_data++;
+
+ /* Get rid of the data type */
+ p_msg->len--;
+ p_msg->offset++;
+
+ switch (ttype) {
+ case HID_TRANS_HANDSHAKE:
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
+ HID_HDEV_EVT_HANDSHAKE, param, NULL);
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_CONTROL:
+ switch (param) {
+ case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
+ hidh_conn_disconnect(dhandle);
+ /* Device is unplugging from us. Tell USB */
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
+ HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
+ break;
+
+ default:
+ break;
+ }
+ osi_free(p_msg);
+ break;
+
+ case HID_TRANS_DATA:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
+ ? HID_HDEV_EVT_INTR_DATA
+ : HID_HDEV_EVT_CTRL_DATA;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
+ p_msg);
+ break;
+
+ case HID_TRANS_DATAC:
+ evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
+ ? HID_HDEV_EVT_INTR_DATC
+ : HID_HDEV_EVT_CTRL_DATC;
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
+ p_msg);
+ break;
+
+ default:
+ osi_free(p_msg);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_conn_snd_data
+ *
+ * Description This function is sends out data.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
+ uint8_t param, uint16_t data, uint8_t report_id,
+ BT_HDR* buf) {
+ tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
+ BT_HDR* p_buf;
+ uint8_t* p_out;
+ uint16_t bytes_copied;
+ bool seg_req = false;
+ uint16_t data_size;
+ uint16_t cid;
+ uint16_t buf_size;
+ uint8_t use_data = 0;
+ bool blank_datc = false;
+
+ if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr,
+ BT_TRANSPORT_BR_EDR)) {
+ osi_free(buf);
+ return HID_ERR_NO_CONNECTION;
+ }
+
+ if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
+ osi_free(buf);
+ return HID_ERR_CONGESTED;
+ }
+
+ switch (trans_type) {
+ case HID_TRANS_CONTROL:
+ case HID_TRANS_GET_REPORT:
+ case HID_TRANS_SET_REPORT:
+ case HID_TRANS_GET_PROTOCOL:
+ case HID_TRANS_SET_PROTOCOL:
+ case HID_TRANS_GET_IDLE:
+ case HID_TRANS_SET_IDLE:
+ cid = p_hcon->ctrl_cid;
+ buf_size = HID_CONTROL_BUF_SIZE;
+ break;
+ case HID_TRANS_DATA:
+ cid = p_hcon->intr_cid;
+ buf_size = HID_INTERRUPT_BUF_SIZE;
+ break;
+ default:
+ return (HID_ERR_INVALID_PARAM);
+ }
+
+ if (trans_type == HID_TRANS_SET_IDLE)
+ use_data = 1;
+ else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08))
+ use_data = 2;
+
+ do {
+ if (buf == NULL || blank_datc) {
+ p_buf = (BT_HDR*)osi_malloc(buf_size);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = false;
+ data_size = 0;
+ bytes_copied = 0;
+ blank_datc = false;
+ } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) {
+ p_buf = (BT_HDR*)osi_malloc(buf_size);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ seg_req = true;
+ data_size = buf->len;
+ bytes_copied = p_hcon->rem_mtu_size - 1;
+ } else {
+ p_buf = buf;
+ p_buf->offset -= 1;
+ seg_req = false;
+ data_size = buf->len;
+ bytes_copied = buf->len;
+ }
+
+ p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ *p_out++ = HID_BUILD_HDR(trans_type, param);
+
+ /* If report ID required for this device */
+ if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) {
+ *p_out = report_id;
+ data_size = bytes_copied = 1;
+ }
+
+ if (seg_req) {
+ memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied);
+ buf->offset += bytes_copied;
+ buf->len -= bytes_copied;
+ } else if (use_data == 1) {
+ *(p_out + bytes_copied) = data & 0xff;
+ } else if (use_data == 2) {
+ *(p_out + bytes_copied) = data & 0xff;
+ *(p_out + bytes_copied + 1) = (data >> 8) & 0xff;
+ }
+
+ p_buf->len = bytes_copied + 1 + use_data;
+ data_size -= bytes_copied;
+
+ /* Send the buffer through L2CAP */
+ if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) ||
+ (!L2CA_DataWrite(cid, p_buf)))
+ return (HID_ERR_CONGESTED);
+
+ if (data_size)
+ trans_type = HID_TRANS_DATAC;
+ else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) {
+ trans_type = HID_TRANS_DATAC;
+ blank_datc = true;
+ }
+
+ } while ((data_size != 0) || blank_datc);
+
+ return (HID_SUCCESS);
+}
+/*******************************************************************************
+ *
+ * Function hidh_conn_initiate
+ *
+ * Description This function is called by the management to create a
+ * connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tHID_STATUS hidh_conn_initiate(uint8_t dhandle) {
+ uint8_t service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
+ uint32_t mx_chan_id = HID_NOSEC_CHN;
+
+ tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
+
+ if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED)
+ return (HID_ERR_CONN_IN_PROCESS);
+
+ p_dev->conn.ctrl_cid = 0;
+ p_dev->conn.intr_cid = 0;
+ p_dev->conn.disc_reason =
+ HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection
+ Attempt was made but failed */
+
+ /* We are the originator of this connection */
+ p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
+
+ if (p_dev->attr_mask & HID_SEC_REQUIRED) {
+ service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
+ mx_chan_id = HID_SEC_CHN;
+ }
+ BTM_SetOutService(p_dev->addr, service_id, mx_chan_id);
+
+ /* Check if L2CAP started the connection process */
+ p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr);
+ if (p_dev->conn.ctrl_cid == 0) {
+ HIDH_TRACE_WARNING("HID-Host Originate failed");
+ hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
+ HID_ERR_L2CAP_FAILED, NULL);
+ } else {
+ /* Transition to the next appropriate state, waiting for connection confirm
+ * on control channel. */
+ p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
+ }
+
+ return (HID_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function find_conn_by_cid
+ *
+ * Description This function finds a connection control block based on CID
+ *
+ * Returns address of control block, or NULL if not found
+ *
+ ******************************************************************************/
+static uint8_t find_conn_by_cid(uint16_t cid) {
+ uint8_t xx;
+
+ for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
+ if ((hh_cb.devices[xx].in_use) &&
+ (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) &&
+ ((hh_cb.devices[xx].conn.ctrl_cid == cid) ||
+ (hh_cb.devices[xx].conn.intr_cid == cid)))
+ break;
+ }
+
+ return (xx);
+}
+
+void hidh_conn_dereg(void) {
+ L2CA_Deregister(HID_PSM_CONTROL);
+ L2CA_Deregister(HID_PSM_INTERRUPT);
+}
+
+/*******************************************************************************
+ *
+ * Function hidh_conn_retry
+ *
+ * Description This function is called to retry a failed connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void hidh_conn_retry(uint8_t dhandle) {
+ tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
+
+ p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
+#if (HID_HOST_REPAGE_WIN > 0)
+ period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
+ alarm_set_on_queue(p_dev->conn.process_repage_timer, interval_ms,
+ hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle),
+ btu_general_alarm_queue);
+#else
+ hidh_try_repage(dhandle);
+#endif
+}
diff --git a/mtkbt/code/bt/stack/hid/hidh_int.h b/mtkbt/code/bt/stack/hid/hidh_int.h
new file mode 100755
index 0000000..e3990ae
--- a/dev/null
+++ b/mtkbt/code/bt/stack/hid/hidh_int.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains HID HOST internal definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDH_INT_H
+#define HIDH_INT_H
+
+#include "hid_conn.h"
+#include "hidh_api.h"
+#include "l2c_api.h"
+
+enum { HID_DEV_NO_CONN, HID_DEV_CONNECTED };
+
+typedef struct per_device_ctb {
+ bool in_use;
+ BD_ADDR addr; /* BD-Addr of the host device */
+ uint16_t attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03-
+ reconn_initiate;
+ 0x04- sdp_disable; */
+ uint8_t state; /* Device state if in HOST-KNOWN mode */
+ uint8_t conn_substate;
+ uint8_t conn_tries; /* Remembers the number of connection attempts while
+ CONNECTING */
+
+ tHID_CONN conn; /* L2CAP channel info */
+} tHID_HOST_DEV_CTB;
+
+typedef struct host_ctb {
+ tHID_HOST_DEV_CTB devices[HID_HOST_MAX_DEVICES];
+ tHID_HOST_DEV_CALLBACK* callback; /* Application callbacks */
+ tL2CAP_CFG_INFO l2cap_cfg;
+
+#define MAX_SERVICE_DB_SIZE 4000
+
+ bool sdp_busy;
+ tHID_HOST_SDP_CALLBACK* sdp_cback;
+ tSDP_DISCOVERY_DB* p_sdp_db;
+ tHID_DEV_SDP_INFO sdp_rec;
+ bool reg_flag;
+ uint8_t trace_level;
+} tHID_HOST_CTB;
+
+extern tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
+ uint8_t param, uint16_t data,
+ uint8_t rpt_id, BT_HDR* buf);
+extern tHID_STATUS hidh_conn_reg(void);
+extern void hidh_conn_dereg(void);
+extern tHID_STATUS hidh_conn_disconnect(uint8_t dhandle);
+extern tHID_STATUS hidh_conn_initiate(uint8_t dhandle);
+extern void hidh_process_repage_timer_timeout(void* data);
+/**M: HID device reconnect fail for collision@{*/
+extern tHID_STATUS hidh_conn_collision_disconnect (uint8_t dhandle);
+extern void hidh_conn_process_collision_timeout(uint8_t dhandle);
+/**@}*/
+extern void hidh_try_repage(uint8_t dhandle);
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+extern tHID_HOST_CTB hh_cb;
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/a2dp_aac.h b/mtkbt/code/bt/stack/include/a2dp_aac.h
new file mode 100755
index 0000000..da7f0b4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_aac.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for AAC
+//
+
+#ifndef A2DP_AAC_H
+#define A2DP_AAC_H
+
+#include "a2dp_aac_constants.h"
+#include "a2dp_codec_api.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigAac : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigAac(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigAac();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+ void debug_codec_dump(int fd) override;
+};
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+class A2dpCodecConfigAacSink : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigAacSink(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigAacSink();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+};
+#endif
+// Checks whether the codec capabilities contain a valid A2DP AAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC
+// codec, otherwise false.
+bool A2DP_IsSourceCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP AAC Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP AAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP AAC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid AAC
+// codec, otherwise false.
+bool A2DP_IsPeerSinkCodecValidAac(const uint8_t* p_codec_info);
+
+// Checks whether A2DP AAC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP AAC Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupportedAac(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP AAC Source codec for a peer Source device is
+// supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP AAC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedAac(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_UsesRtpHeaderAac(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Builds A2DP preferred AAC Sink capability from AAC Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigAac(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg);
+
+// Gets the A2DP AAC codec name for a given |p_codec_info|.
+const char* A2DP_CodecNameAac(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP AAC codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_CodecTypeEqualsAac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP AAC codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not AAC, the return value is false.
+bool A2DP_CodecEqualsAac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackSampleRateAac(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleAac(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP AAC codec.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCountAac(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP AAC Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelTypeAac(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// AAC sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcessAac(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info);
+
+// Gets the object type code for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_OBJECT_TYPE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the object type code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetObjectTypeCodeAac(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_CHANNEL_MODE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetChannelModeCodeAac(const uint8_t* p_codec_info);
+
+// Gets the variable bit rate support for the A2DP AAC codec.
+// The actual value is codec-specific - see |A2DP_AAC_VARIABLE_BIT_RATE_*|.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the variable bit rate support on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetVariableBitRateSupportAac(const uint8_t* p_codec_info);
+
+// Gets the bit rate for the A2DP AAC codec.
+// The actual value is codec-specific - for AAC it is in bits per second.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// Returns the bit rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetBitRateAac(const uint8_t* p_codec_info);
+
+// Computes the maximum bit rate for the A2DP AAC codec based on the MTU.
+// The actual value is codec-specific - for AAC it is in bits per second.
+// |p_codec_info| is a pointer to the AAC codec_info to decode.
+// |mtu| is the MTU to use for the computation.
+// Returns the maximum bit rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_ComputeMaxBitRateAac(const uint8_t* p_codec_info, uint16_t mtu);
+
+// Gets the A2DP AAC audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_GetPacketTimestampAac(const uint8_t* p_codec_info,
+ const uint8_t* p_data, uint32_t* p_timestamp);
+
+// Builds A2DP AAC codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_BuildCodecHeaderAac(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Decodes and displays AAC codec info (for debugging).
+// |p_codec_info| is a pointer to the AAC codec_info to decode and display.
+void A2DP_DumpCodecInfoAac(const uint8_t* p_codec_info);
+
+// Gets the A2DP AAC encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP AAC encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceAac(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP AAC codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_AdjustCodecAac(uint8_t* p_codec_info);
+
+// Gets the A2DP AAC Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SourceCodecIndexAac(const uint8_t* p_codec_info);
+
+// Gets the A2DP AAC Source codec name.
+const char* A2DP_CodecIndexStrAac(void);
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+const char* A2DP_CodecIndexStrAacSink(void);
+bool A2DP_InitCodecConfigAacSink(tAVDT_CFG* p_cfg);
+void A2DP_InitDefaultCodecAac(uint8_t* p_codec_info);
+#endif
+// Initializes A2DP AAC Source codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigAac(tAVDT_CFG* p_cfg);
+
+#endif // A2DP_AAC_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_aac_constants.h b/mtkbt/code/bt/stack/include/a2dp_aac_constants.h
new file mode 100755
index 0000000..6102f92
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_aac_constants.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP constants for AAC codec
+//
+
+#ifndef A2DP_AAC_CONSTANTS_H
+#define A2DP_AAC_CONSTANTS_H
+
+// AAC codec specific settings
+#define A2DP_AAC_CODEC_LEN 8
+
+// [Octet 0] Object Type
+#define A2DP_AAC_OBJECT_TYPE_MPEG2_LC 0x80 /* MPEG-2 Low Complexity */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_LC 0x40 /* MPEG-4 Low Complexity */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_LTP 0x20 /* MPEG-4 Long Term Prediction */
+#define A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE 0x10
+// [Octet 1] Sampling Frequency - 8000 to 44100
+#define A2DP_AAC_SAMPLING_FREQ_MASK0 0xFF
+#define A2DP_AAC_SAMPLING_FREQ_8000 0x80
+#define A2DP_AAC_SAMPLING_FREQ_11025 0x40
+#define A2DP_AAC_SAMPLING_FREQ_12000 0x20
+#define A2DP_AAC_SAMPLING_FREQ_16000 0x10
+#define A2DP_AAC_SAMPLING_FREQ_22050 0x08
+#define A2DP_AAC_SAMPLING_FREQ_24000 0x04
+#define A2DP_AAC_SAMPLING_FREQ_32000 0x02
+#define A2DP_AAC_SAMPLING_FREQ_44100 0x01
+// [Octet 2], [Bits 4-7] Sampling Frequency - 48000 to 96000
+// NOTE: Bits offset for the higher-order octet 16-bit integer
+#define A2DP_AAC_SAMPLING_FREQ_MASK1 (0xF0 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_48000 (0x80 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_64000 (0x40 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_88200 (0x20 << 8)
+#define A2DP_AAC_SAMPLING_FREQ_96000 (0x10 << 8)
+// [Octet 2], [Bits 2-3] Channel Mode
+#define A2DP_AAC_CHANNEL_MODE_MASK 0x0C
+#define A2DP_AAC_CHANNEL_MODE_MONO 0x08
+#define A2DP_AAC_CHANNEL_MODE_STEREO 0x04
+// [Octet 2], [Bits 0-1] RFA
+// [Octet 3], [Bit 7] Variable Bit Rate Supported
+#define A2DP_AAC_VARIABLE_BIT_RATE_MASK 0x80
+#define A2DP_AAC_VARIABLE_BIT_RATE_ENABLED 0x80
+#define A2DP_AAC_VARIABLE_BIT_RATE_DISABLED 0x00
+// [Octet 3], [Bits 0-6] Bit Rate - Bits 16-22 in the 23-bit UiMsbf
+#define A2DP_AAC_BIT_RATE_MASK0 (0x7F << 16)
+#define A2DP_AAC_BIT_RATE_MASK1 (0xFF << 8)
+#define A2DP_AAC_BIT_RATE_MASK2 0xFF
+// [Octet 4], [Bits 0-7] Bit Rate - Bits 8-15 in the 23-bit UiMsfb
+// [Octet 5], [Bits 0-7] Bit Rate - Bits 0-7 in the 23-bit UiMsfb
+
+#endif // A2DP_AAC_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_aac_encoder.h b/mtkbt/code/bt/stack/include/a2dp_aac_encoder.h
new file mode 100755
index 0000000..e72b18c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_aac_encoder.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP AAC Encoder
+//
+
+#ifndef A2DP_AAC_ENCODER_H
+#define A2DP_AAC_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP AAC encoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadEncoderAac(void);
+
+// Unloads the A2DP AAC encoder.
+void A2DP_UnloadEncoderAac(void);
+
+// Initialize the A2DP AAC encoder.
+// |p_peer_params| contains the A2DP peer information
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_aac_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP AAC encoder.
+void a2dp_aac_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP AAC encoder.
+void a2dp_aac_feeding_reset(void);
+
+// Flush the feeding for the A2DP AAC encoder.
+void a2dp_aac_feeding_flush(void);
+
+// Get the A2DP AAC encoder interval (in milliseconds).
+period_ms_t a2dp_aac_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP AAC encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_aac_send_frames(uint64_t timestamp_us);
+
+#endif // A2DP_AAC_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_api.h b/mtkbt/code/bt/stack/include/a2dp_api.h
new file mode 100755
index 0000000..bb8411e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_api.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+//
+// A2DP API
+//
+
+#ifndef A2DP_API_H
+#define A2DP_API_H
+
+#include <inttypes.h>
+
+#include "a2dp_constants.h"
+#include "a2dp_error_codes.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+//
+// |MAX_PCM_FRAME_NUM_PER_TICK| controls how many buffers we can hold in
+// the A2DP buffer queues during temporary link congestion.
+//
+#ifndef MAX_PCM_FRAME_NUM_PER_TICK
+#define MAX_PCM_FRAME_NUM_PER_TICK 14
+#endif
+
+/* the return values from A2DP_BitsSet() */
+#define A2DP_SET_ONE_BIT 1 /* one and only one bit is set */
+#define A2DP_SET_ZERO_BIT 0 /* all bits clear */
+#define A2DP_SET_MULTL_BIT 2 /* multiple bits are set */
+
+/*****************************************************************************
+ * type definitions
+ ****************************************************************************/
+
+/* This data type is used in A2DP_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct {
+ uint32_t db_len; /* Length, in bytes, of the discovery database */
+ uint16_t num_attr; /* The number of attributes in p_attrs */
+ uint16_t* p_attrs; /* The attributes filter. If NULL, A2DP API sets the
+ * attribute filter
+ * to be ATTR_ID_SERVICE_CLASS_ID_LIST,
+ * ATTR_ID_BT_PROFILE_DESC_LIST,
+ * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and
+ * ATTR_ID_PROVIDER_NAME.
+ * If not NULL, the input is taken as the filter. */
+} tA2DP_SDP_DB_PARAMS;
+
+/* This data type is used in tA2DP_FIND_CBACK to report the result of the SDP
+ * discovery process. */
+typedef struct {
+ uint16_t service_len; /* Length, in bytes, of the service name */
+ uint16_t provider_len; /* Length, in bytes, of the provider name */
+ char* p_service_name; /* Pointer the service name. This character string may
+ * not be null terminated.
+ * Use the service_len parameter to safely copy this
+ * string */
+ char* p_provider_name; /* Pointer the provider name. This character string
+ * may not be null terminated.
+ * Use the provider_len parameter to safely copy this
+ * string */
+ uint16_t features; /* Profile supported features */
+ uint16_t avdt_version; /* AVDTP protocol version */
+} tA2DP_Service;
+
+/* This is the callback to notify the result of the SDP discovery process. */
+typedef void(tA2DP_FIND_CBACK)(bool found, tA2DP_Service* p_service);
+
+/*****************************************************************************
+ * external function declarations
+ ****************************************************************************/
+/******************************************************************************
+ *
+ * Function A2DP_AddRecord
+ *
+ * Description This function is called by a server application to add
+ * SRC or SNK information to an SDP record. Prior to
+ * calling this function the application must call
+ * SDP_CreateRecord() to create an SDP record.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates SRC or SNK.
+ *
+ * p_service_name: Pointer to a null-terminated character
+ * string containing the service name.
+ *
+ * p_provider_name: Pointer to a null-terminated character
+ * string containing the provider name.
+ *
+ * features: Profile supported features.
+ *
+ * sdp_handle: SDP handle returned by SDP_CreateRecord().
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns A2DP_SUCCESS if function execution succeeded,
+ * A2DP_INVALID_PARAMS if bad parameters are given.
+ * A2DP_FAIL if function execution failed.
+ *
+ *****************************************************************************/
+extern tA2DP_STATUS A2DP_AddRecord(uint16_t service_uuid, char* p_service_name,
+ char* p_provider_name, uint16_t features,
+ uint32_t sdp_handle);
+
+/******************************************************************************
+ *
+ * Function A2DP_FindService
+ *
+ * Description This function is called by a client application to
+ * perform service discovery and retrieve SRC or SNK SDP
+ * record information from a server. Information is
+ * returned for the first service record found on the
+ * server that matches the service UUID. The callback
+ * function will be executed when service discovery is
+ * complete. There can only be one outstanding call to
+ * A2DP_FindService() at a time; the application must wait
+ * for the callback before it makes another call to
+ * the function.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates SRC or SNK.
+ *
+ * bd_addr: BD address of the peer device.
+ *
+ * p_db: Pointer to the information to initialize
+ * the discovery database.
+ *
+ * p_cback: Pointer to the A2DP_FindService()
+ * callback function.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns A2DP_SUCCESS if function execution succeeded,
+ * A2DP_INVALID_PARAMS if bad parameters are given.
+ * A2DP_BUSY if discovery is already in progress.
+ * A2DP_FAIL if function execution failed.
+ *
+ *****************************************************************************/
+extern tA2DP_STATUS A2DP_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+ tA2DP_SDP_DB_PARAMS* p_db,
+ tA2DP_FIND_CBACK* p_cback);
+
+/******************************************************************************
+ *
+ * Function A2DP_SetTraceLevel
+ *
+ * Description Sets the trace level for A2D. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the A2DP tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+extern uint8_t A2DP_SetTraceLevel(uint8_t new_level);
+
+/******************************************************************************
+ * Function A2DP_BitsSet
+ *
+ * Description Check the given num for the number of bits set
+ * Returns A2DP_SET_ONE_BIT, if one and only one bit is set
+ * A2DP_SET_ZERO_BIT, if all bits clear
+ * A2DP_SET_MULTL_BIT, if multiple bits are set
+ *****************************************************************************/
+extern uint8_t A2DP_BitsSet(uint64_t num);
+
+/** M: Bug fix for When doing A2DP close, cancel SDP if it has been started to avoid NE@{ */
+/******************************************************************************
+** Function A2D_Get_Disc_DB
+**
+** Description get discovery database of a2dp
+** Returns point of discovery database
+******************************************************************************/
+extern tSDP_DISCOVERY_DB * A2D_Get_Disc_DB(void);
+/** @} */
+
+// Initializes the A2DP control block.
+void A2DP_Init(void);
+
+#endif // A2DP_API_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_codec_api.h b/mtkbt/code/bt/stack/include/a2dp_codec_api.h
new file mode 100755
index 0000000..e772bef
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_codec_api.h
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codecs API
+//
+
+#ifndef A2DP_CODEC_API_H
+#define A2DP_CODEC_API_H
+
+#include <stddef.h>
+#include <string.h>
+#include <functional>
+#include <list>
+#include <map>
+#include <mutex>
+#include <string>
+
+#include <hardware/bt_av.h>
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+#include "mtk_bt_av.h"
+#endif
+#include "a2dp_api.h"
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "avdt_api.h"
+#include "osi/include/time.h"
+
+/**
+ * Structure used to initialize the A2DP encoder with A2DP peer information
+ */
+typedef struct {
+ bool is_peer_edr; // True if the A2DP peer supports EDR
+ bool peer_supports_3mbps; // True if the A2DP peer supports 3 Mbps EDR
+ uint16_t peer_mtu; // MTU of the A2DP peer
+} tA2DP_ENCODER_INIT_PEER_PARAMS;
+
+class A2dpCodecConfig {
+ friend class A2dpCodecs;
+
+ public:
+ // Creates a codec entry. The selected codec is defined by |codec_index|,
+ // Returns the codec entry on success, otherwise nullptr.
+ static A2dpCodecConfig* createCodec(
+ btav_a2dp_codec_index_t codec_index,
+ btav_a2dp_codec_priority_t codec_priority =
+ BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
+
+ virtual ~A2dpCodecConfig() = 0;
+
+ // Gets the pre-defined codec index.
+ btav_a2dp_codec_index_t codecIndex() const { return codec_index_; }
+
+ // Gets the codec name.
+ const std::string& name() const { return name_; }
+
+ // Gets the current priority of the codec.
+ btav_a2dp_codec_priority_t codecPriority() const { return codec_priority_; }
+
+ // Copies out the current OTA codec config to |p_codec_info|.
+ // Returns true if the current codec config is valid and copied,
+ // otherwise false.
+ bool copyOutOtaCodecConfig(uint8_t* p_codec_info);
+
+ // Gets the current codec configuration.
+ // Returns a copy of the current codec configuration.
+ btav_a2dp_codec_config_t getCodecConfig();
+
+ // Gets the current codec capability.
+ // The capability is computed by intersecting the local codec's capability
+ // and the peer's codec capability. However, if there is an explicit user
+ // configuration for some of the parameters, the result codec configuration
+ // and capability is restricted to the user's configuration choice.
+ // Returns a copy of the current codec capability.
+ btav_a2dp_codec_config_t getCodecCapability();
+
+ // Gets the codec local capability.
+ // Returns a copy of the codec local capability.
+ btav_a2dp_codec_config_t getCodecLocalCapability();
+
+ // Gets the codec selectable capability.
+ // The capability is computed by intersecting the local codec's capability
+ // and the peer's codec capability. Any explicit user configuration is
+ // not included in the result.
+ // Returns a copy of the codec selectable capability.
+ btav_a2dp_codec_config_t getCodecSelectableCapability();
+
+ // Gets the current codec user configuration.
+ // Returns a copy of the current codec user configuration.
+ btav_a2dp_codec_config_t getCodecUserConfig();
+
+ // Gets the current codec audio configuration.
+ // Returns a copy of the current codec audio configuration.
+ btav_a2dp_codec_config_t getCodecAudioConfig();
+
+ // Gets the number of bits per sample of the current codec configuration,
+ // or 0 if not configured.
+ uint8_t getAudioBitsPerSample();
+
+ // Checks whether the codec uses the RTP Header Marker bit (see RFC 6416).
+ // NOTE: Even if the encoded data uses RTP headers, some codecs do not use
+ // the Marker bit - that bit is expected to be set to 0.
+ // Returns true if the encoded data packets have RTP headers, and
+ // the Marker bit in the header is set according to RFC 6416.
+ virtual bool useRtpHeaderMarkerBit() const = 0;
+
+ // Checks whether |codec_config| is empty and contains no configuration.
+ // Returns true if |codec_config| is empty, otherwise false.
+ static bool isCodecConfigEmpty(const btav_a2dp_codec_config_t& codec_config);
+
+ protected:
+ // Sets the current priority of the codec to |codec_priority|.
+ // If |codec_priority| is BTAV_A2DP_CODEC_PRIORITY_DEFAULT, the priority is
+ // reset to its default value.
+ void setCodecPriority(btav_a2dp_codec_priority_t codec_priority);
+
+ // Sets the current priority of the codec to its default value.
+ void setDefaultCodecPriority();
+
+ // Sets the A2DP Source-to-Sink codec configuration to be used
+ // with a peer Sink device.
+ // |p_peer_codec_info| is the peer's A2DP Sink codec information
+ // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
+ // peer's A2DP Sink codec capability, otherwise it contains the peer's
+ // preferred A2DP codec configuration to use.
+ // The result codec configuration is stored in |p_result_codec_config|.
+ // See |A2dpCodecs.setCodecConfig| for detailed description of
+ // the actual mechanism used to compute the configuration.
+ // Returns true on success, othewise false.
+ virtual bool setCodecConfig(const uint8_t* p_peer_codec_info,
+ bool is_capability,
+ uint8_t* p_result_codec_config) = 0;
+
+ // Sets the user prefered codec configuration.
+ // |codec_user_config| contains the preferred codec user configuration.
+ // |codec_audio_config| contains the selected audio feeding configuration.
+ // |p_peer_params| contains the A2DP peer information.
+ // |p_peer_codec_info| is the peer's A2DP Sink codec information
+ // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
+ // peer's A2DP Sink codec capability, otherwise it contains the peer's
+ // preferred A2DP codec configuration to use.
+ // If there is a change in the codec configuration that requires restarting
+ // if the audio input stream, flag |p_restart_input| is set to true.
+ // If there is a change in the encoder configuration that requires restarting
+ // of the A2DP connection, the new codec configuration is stored in
+ // |p_result_codec_config|, and flag |p_restart_output| is set to true.
+ // If there is any change in the codec configuration, flag |p_config_updated|
+ // is set to true.
+ // Returns true on success, otherwise false.
+ virtual bool setCodecUserConfig(
+ const btav_a2dp_codec_config_t& codec_user_config,
+ const btav_a2dp_codec_config_t& codec_audio_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated);
+
+ // Updates the encoder with the user prefered codec configuration.
+ // |p_peer_params| contains the A2DP peer information.
+ // If there is a change in the encoder configuration that requires restarting
+ // the audio input stream, flag |p_restart_input| is set to true.
+ // If there is a change in the encoder configuration that requires restarting
+ // of the A2DP connection, flag |p_restart_output| is set to true.
+ // If there is any change in the codec configuration, flag |p_config_updated|
+ // is set to true.
+ // Returns true on success, otherwise false.
+ virtual bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) = 0;
+
+ // Constructor where |codec_index| is the unique index that identifies the
+ // codec. The user-friendly name is |name|.
+ // The default codec priority is |codec_priority|. If the value is
+ // |BTAV_A2DP_CODEC_PRIORITY_DEFAULT|, the codec priority is computed
+ // internally.
+ A2dpCodecConfig(btav_a2dp_codec_index_t codec_index, const std::string& name,
+ btav_a2dp_codec_priority_t codec_priority);
+
+ // Initializes the codec entry.
+ // Returns true on success, otherwise false.
+ virtual bool init() = 0;
+
+ // Checks whether the internal state is valid
+ virtual bool isValid() const;
+
+ // Returns the encoder's periodic interval (in milliseconds).
+ virtual period_ms_t encoderIntervalMs() const = 0;
+
+ // Checks whether the A2DP Codec Configuration is valid.
+ // Returns true if A2DP Codec Configuration stored in |codec_config|
+ // is valid, otherwise false.
+ static bool codecConfigIsValid(const btav_a2dp_codec_config_t& codec_config);
+
+ // Gets the string representation of A2DP Codec Configuration.
+ // Returns the string representation of A2DP Codec Configuration stored
+ // in |codec_config|. The format is:
+ // "Rate=44100|48000 Bits=16|24 Mode=MONO|STEREO"
+ static std::string codecConfig2Str(
+ const btav_a2dp_codec_config_t& codec_config);
+
+ // Gets the string representation of A2DP Codec Sample Rate.
+ // Returns the string representation of A2DP Codec Sample Rate stored
+ // in |codec_sample_rate|. If there are multiple values stored in
+ // |codec_sample_rate|, the return string format is "rate1|rate2|rate3".
+ static std::string codecSampleRate2Str(
+ btav_a2dp_codec_sample_rate_t codec_sample_rate);
+
+ // Gets the string representation of A2DP Codec Bits Per Sample.
+ // Returns the string representation of A2DP Codec Bits Per Sample stored
+ // in |codec_bits_per_sample|. If there are multiple values stored in
+ // |codec_bits_per_sample|, the return string format is "bits1|bits2|bits3".
+ static std::string codecBitsPerSample2Str(
+ btav_a2dp_codec_bits_per_sample_t codec_bits_per_sample);
+
+ // Gets the string representation of A2DP Codec Channel Mode.
+ // Returns the string representation of A2DP Channel Mode stored
+ // in |codec_channel_mode|. If there are multiple values stored in
+ // |codec_channel_mode|, the return string format is "mode1|mode2|mode3".
+ static std::string codecChannelMode2Str(
+ btav_a2dp_codec_channel_mode_t codec_channel_mode);
+
+ // Dumps codec-related information.
+ // The information is written in user-friendly form to file descriptor |fd|.
+ virtual void debug_codec_dump(int fd);
+
+ std::recursive_mutex codec_mutex_;
+ const btav_a2dp_codec_index_t codec_index_; // The unique codec index
+ const std::string name_; // The codec name
+ btav_a2dp_codec_priority_t codec_priority_; // Codec priority: must be unique
+ btav_a2dp_codec_priority_t default_codec_priority_;
+
+ btav_a2dp_codec_config_t codec_config_;
+ btav_a2dp_codec_config_t codec_capability_;
+ btav_a2dp_codec_config_t codec_local_capability_;
+ btav_a2dp_codec_config_t codec_selectable_capability_;
+
+ // The optional user configuration. The values (if set) are used
+ // as a preference when there is a choice. If a particular value
+ // is not supported by the local or remote device, it is ignored.
+ btav_a2dp_codec_config_t codec_user_config_;
+
+ // The selected audio feeding configuration.
+ btav_a2dp_codec_config_t codec_audio_config_;
+
+ uint8_t ota_codec_config_[AVDT_CODEC_SIZE];
+ uint8_t ota_codec_peer_capability_[AVDT_CODEC_SIZE];
+ uint8_t ota_codec_peer_config_[AVDT_CODEC_SIZE];
+};
+
+class A2dpCodecs {
+ public:
+ // Constructor for class |A2dpCodecs|.
+ // |codec_priorities| contains the codec priorities to use.
+ A2dpCodecs(const std::vector<btav_a2dp_codec_config_t>& codec_priorities);
+ ~A2dpCodecs();
+
+ // Initializes all supported codecs.
+ // Returns true if at least one Source codec and one Sink codec were
+ // initialized, otherwise false.
+ bool init();
+
+ // Finds the Source codec that corresponds to the A2DP over-the-air
+ // |p_codec_info| information.
+ // Returns the Source codec if found, otherwise nullptr.
+ A2dpCodecConfig* findSourceCodecConfig(const uint8_t* p_codec_info);
+
+ // Gets the codec config that is currently selected.
+ // Returns the codec config that is currently selected, or nullptr if
+ // no codec is selected.
+ A2dpCodecConfig* getCurrentCodecConfig() const {
+ return current_codec_config_;
+ }
+
+ // Gets the list of Source codecs ordered by priority: higher priority first.
+ const std::list<A2dpCodecConfig*> orderedSourceCodecs() const {
+ return ordered_source_codecs_;
+ }
+
+ // Gets the list of Sink codecs ordered by priority: higher priority first.
+ const std::list<A2dpCodecConfig*> orderedSinkCodecs() const {
+ return ordered_sink_codecs_;
+ }
+
+ // Sets the A2DP Source-to-Sink codec configuration to be used
+ // with a peer Sink device.
+ // |p_peer_codec_info| is the peer's A2DP Sink codec information
+ // to use. If |is_capability| is true, then |p_peer_codec_info| contains the
+ // peer's A2DP Sink codec capability, otherwise it contains the peer's
+ // preferred A2DP codec configuration to use.
+ // If the codec can be used and |select_current_codec| is true, then
+ // this codec is selected as the current one.
+ //
+ // The codec configuration is built by considering the optional user
+ // configuration, the local codec capabilities, the peer's codec
+ // capabilities, and the codec's locally-defined default values.
+ // For each codec parameter:
+ //
+ // 1. If it is user-configurable parameter (sample rate, bits per sample,
+ // channel mode, and some codec-specific parameters),
+ // if the user has an explicit preference, and that preference
+ // is supported by both the local and remote device, this is the
+ // parameter value that is used.
+ // 2. Otherwise, if the explicit internal default value is supported
+ // by both the local and remote device, this is the parameter value
+ // that is used.
+ // 3. Otherwise, the best match is chosen among all values supported by
+ // the local and remote device.
+ //
+ // In addition, the codec's internal state is updated to reflect
+ // the capabilities that are advertised to the upstream audio source
+ // (Media Framework) to make run-time audio parameter choices:
+ // 4. If the user-configurable parameter was selected, this is the
+ // only parameter value that is advertised to the Media Framework.
+ // 5. Otherwise, all values supported by both the local and remote
+ // devices are advertised to the Media Framework.
+ //
+ // The result codec configuration is stored in |p_result_codec_config|.
+ // Returns true on success, othewise false.
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config,
+ bool select_current_codec);
+
+ // Sets the user prefered codec configuration.
+ // |codec_user_config| contains the preferred codec configuration.
+ // |p_peer_params| contains the A2DP peer information.
+ // |p_peer_sink_capabilities| is the peer's A2DP Sink codec capabilities
+ // to use.
+ // If there is a change in the encoder configuration that requires restarting
+ // the audio input stream, flag |p_restart_input| is set to true.
+ // If there is a change in the encoder configuration that requires restarting
+ // of the A2DP connection, flag |p_restart_output| is set to true, and the
+ // new codec is stored in |p_result_codec_config|.
+ // If there is any change in the codec configuration, flag |p_config_updated|
+ // is set to true.
+ // Returns true on success, otherwise false.
+ bool setCodecUserConfig(const btav_a2dp_codec_config_t& codec_user_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_sink_capabilities,
+ uint8_t* p_result_codec_config, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated);
+
+ // Sets the Audio HAL selected audio feeding parameters.
+ // Those parameters are applied only to the currently selected codec.
+ // |codec_audio_config| contains the selected audio feeding configuration.
+ // |p_peer_params| contains the A2DP peer information.
+ // |p_peer_sink_capabilities| is the peer's A2DP Sink codec capabilities
+ // to use.
+ // If there is a change in the encoder configuration that requires restarting
+ // of the A2DP connection, flag |p_restart_output| is set to true, and the
+ // new codec is stored in |p_result_codec_config|.
+ // If there is any change in the codec configuration, flag |p_config_updated|
+ // is set to true.
+ // Returns true on success, otherwise false.
+ bool setCodecAudioConfig(const btav_a2dp_codec_config_t& codec_audio_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ const uint8_t* p_peer_sink_capabilities,
+ uint8_t* p_result_codec_config,
+ bool* p_restart_output, bool* p_config_updated);
+
+ // Sets the Over-The-Air preferred codec configuration.
+ // The OTA prefered codec configuration is ignored if the current
+ // codec configuration contains explicit user configuration, or if the
+ // codec configuration for the same codec contains explicit user
+ // configuration.
+ // |p_ota_codec_config| contains the received OTA A2DP codec configuration
+ // from the remote peer. Note: this is not the peer codec capability,
+ // but the codec configuration that the peer would like to use.
+ // |p_peer_params| contains the A2DP peer information.
+ // If there is a change in the encoder configuration that requires restarting
+ // the audio input stream, flag |p_restart_input| is set to true.
+ // If there is a change in the encoder configuration that requires restarting
+ // of the A2DP connection, flag |p_restart_output| is set to true, and the
+ // new codec is stored in |p_result_codec_config|.
+ // If there is any change in the codec configuration, flag |p_config_updated|
+ // is set to true.
+ // Returns true on success, otherwise false.
+ bool setCodecOtaConfig(const uint8_t* p_ota_codec_config,
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ uint8_t* p_result_codec_config, bool* p_restart_input,
+ bool* p_restart_output, bool* p_config_updated);
+
+ // Gets the current codec configuration and the capabilities of
+ // all configured codecs.
+ // The current codec configuration is stored in |p_codec_config|.
+ // Local device's codecs capabilities are stored in
+ // |p_codecs_local_capabilities|.
+ // The codecs capabilities that can be used between the local device
+ // and the remote device are stored in |p_codecs_selectable_capabilities|.
+ // Returns true on success, otherwise false.
+ bool getCodecConfigAndCapabilities(
+ btav_a2dp_codec_config_t* p_codec_config,
+ std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,
+ std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities);
+
+ // Dumps codec-related information.
+ // The information is written in user-friendly form to file descriptor |fd|.
+ void debug_codec_dump(int fd);
+
+ private:
+ struct CompareBtBdaddr
+ : public std::binary_function<bt_bdaddr_t, bt_bdaddr_t, bool> {
+ bool operator()(const bt_bdaddr_t& lhs, const bt_bdaddr_t& rhs) const {
+ return (memcmp(&lhs, &rhs, sizeof(lhs)) < 0);
+ }
+ };
+ typedef std::map<btav_a2dp_codec_index_t, A2dpCodecConfig*> IndexedCodecs;
+
+ std::recursive_mutex codec_mutex_;
+ A2dpCodecConfig* current_codec_config_; // Currently selected codec
+ std::map<btav_a2dp_codec_index_t, btav_a2dp_codec_priority_t>
+ codec_priorities_;
+
+ IndexedCodecs indexed_codecs_; // The codecs indexed by codec index
+ IndexedCodecs disabled_codecs_; // The disabled codecs
+
+ // A2DP Source codecs ordered by priority
+ std::list<A2dpCodecConfig*> ordered_source_codecs_;
+
+ // A2DP Sink codecs ordered by priority
+ std::list<A2dpCodecConfig*> ordered_sink_codecs_;
+
+ std::map<bt_bdaddr_t, IndexedCodecs*, CompareBtBdaddr> peer_codecs_;
+};
+
+/**
+ * Structure used to configure the A2DP feeding.
+ */
+typedef struct {
+ tA2DP_SAMPLE_RATE sample_rate; // 44100, 48000, etc
+ tA2DP_BITS_PER_SAMPLE bits_per_sample; // 8, 16, 24, 32
+ tA2DP_CHANNEL_COUNT channel_count; // 1 for mono or 2 for stereo
+} tA2DP_FEEDING_PARAMS;
+
+// Prototype for a callback to read audio data for encoding.
+// |p_buf| is the buffer to store the data. |len| is the number of octets to
+// read.
+// Returns the number of octets read.
+typedef uint32_t (*a2dp_source_read_callback_t)(uint8_t* p_buf, uint32_t len);
+
+// Prototype for a callback to enqueue A2DP Source packets for transmission.
+// |p_buf| is the buffer with the audio data to enqueue. The callback is
+// responsible for freeing |p_buf|.
+// |frames_n| is the number of audio frames in |p_buf| - it is used for
+// statistics purpose.
+// Returns true if the packet was enqueued, otherwise false.
+typedef bool (*a2dp_source_enqueue_callback_t)(BT_HDR* p_buf, size_t frames_n);
+
+//
+// A2DP encoder callbacks interface.
+//
+typedef struct {
+ // Initialize the A2DP encoder.
+ // |p_peer_params| contains the A2DP peer information
+ // The current A2DP codec config is in |a2dp_codec_config|.
+ // |read_callback| is the callback for reading the input audio data.
+ // |enqueue_callback| is the callback for enqueueing the encoded audio data.
+ void (*encoder_init)(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+ // Cleanup the A2DP encoder.
+ void (*encoder_cleanup)(void);
+
+ // Reset the feeding for the A2DP encoder.
+ void (*feeding_reset)(void);
+
+ // Flush the feeding for the A2DP encoder.
+ void (*feeding_flush)(void);
+
+ // Get the A2DP encoder interval (in milliseconds).
+ period_ms_t (*get_encoder_interval_ms)(void);
+
+ // Prepare and send A2DP encoded frames.
+ // |timestamp_us| is the current timestamp (in microseconds).
+ void (*send_frames)(uint64_t timestamp_us);
+
+ // Set transmit queue length for the A2DP encoder.
+ void (*set_transmit_queue_length)(size_t transmit_queue_length);
+} tA2DP_ENCODER_INTERFACE;
+
+// Gets the A2DP codec type.
+// |p_codec_info| contains information about the codec capabilities.
+tA2DP_CODEC_TYPE A2DP_GetCodecType(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid codec,
+// otherwise false.
+bool A2DP_IsPeerSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP Source codec for a peer Source device is supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP Source codec for a peer Source device is supported,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Initialize state with the default A2DP codec.
+// The initialized state with the codec capabilities is stored in
+// |p_codec_info|.
+void A2DP_InitDefaultCodec(uint8_t* p_codec_info);
+
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+void A2DP_InitAacDefaultCodec(uint8_t* p_codec_info);
+#endif
+// Builds A2DP preferred Sink capability from Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfig(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_UsesRtpHeader(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Gets the |AVDT_MEDIA_TYPE_*| media type from the codec capability
+// in |p_codec_info|.
+uint8_t A2DP_GetMediaType(const uint8_t* p_codec_info);
+
+// Gets the A2DP codec name for a given |p_codec_info|.
+const char* A2DP_CodecName(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP codecs |p_codec_info_a| and |p_codec_info_b| have
+// the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_CodecTypeEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP codecs p_codec_info_a| and |p_codec_info_b| are
+// exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_CodecEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackSampleRate(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSample(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP codec.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCount(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelType(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// Sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcess(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_GetPacketTimestamp(const uint8_t* p_codec_info, const uint8_t* p_data,
+ uint32_t* p_timestamp);
+
+// Builds A2DP codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_BuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Gets the A2DP encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterface(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP codec, based on local support and Bluetooth specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_AdjustCodec(uint8_t* p_codec_info);
+
+// Gets the A2DP Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SourceCodecIndex(const uint8_t* p_codec_info);
+
+// Gets the A2DP codec name for a given |codec_index|.
+const char* A2DP_CodecIndexStr(btav_a2dp_codec_index_t codec_index);
+
+// Initializes A2DP codec-specific information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|. The selected codec is defined by |codec_index|.
+// Returns true on success, otherwise false.
+bool A2DP_InitCodecConfig(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg);
+
+// Add enum-based flag operators to the btav_a2dp_codec_config_t fields
+#ifndef DEFINE_ENUM_FLAG_OPERATORS
+#define DEFINE_ENUM_FLAG_OPERATORS(bitmask) \
+ extern "C++" { \
+ inline constexpr bitmask operator&(bitmask X, bitmask Y) { \
+ return static_cast<bitmask>(static_cast<int>(X) & static_cast<int>(Y)); \
+ } \
+ inline constexpr bitmask operator|(bitmask X, bitmask Y) { \
+ return static_cast<bitmask>(static_cast<int>(X) | static_cast<int>(Y)); \
+ } \
+ inline constexpr bitmask operator^(bitmask X, bitmask Y) { \
+ return static_cast<bitmask>(static_cast<int>(X) ^ static_cast<int>(Y)); \
+ } \
+ inline constexpr bitmask operator~(bitmask X) { \
+ return static_cast<bitmask>(~static_cast<int>(X)); \
+ } \
+ inline bitmask& operator&=(bitmask& X, bitmask Y) { \
+ X = X & Y; \
+ return X; \
+ } \
+ inline bitmask& operator|=(bitmask& X, bitmask Y) { \
+ X = X | Y; \
+ return X; \
+ } \
+ inline bitmask& operator^=(bitmask& X, bitmask Y) { \
+ X = X ^ Y; \
+ return X; \
+ } \
+ }
+#endif // DEFINE_ENUM_FLAG_OPERATORS
+DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_sample_rate_t);
+DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_bits_per_sample_t);
+DEFINE_ENUM_FLAG_OPERATORS(btav_a2dp_codec_channel_mode_t);
+
+#endif // A2DP_CODEC_API_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_constants.h b/mtkbt/code/bt/stack/include/a2dp_constants.h
new file mode 100755
index 0000000..479d9e4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_constants.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+//
+// A2DP constants defined by the Profile Specification
+//
+
+#ifndef A2DP_CONSTANTS_H
+#define A2DP_CONSTANTS_H
+
+#include <inttypes.h>
+
+/* Profile supported features */
+#define A2DP_SUPF_PLAYER 0x0001
+#define A2DP_SUPF_MIC 0x0002
+#define A2DP_SUPF_TUNER 0x0004
+#define A2DP_SUPF_MIXER 0x0008
+
+#define A2DP_SUPF_HEADPHONE 0x0001
+#define A2DP_SUPF_SPEAKER 0x0002
+#define A2DP_SUPF_RECORDER 0x0004
+#define A2DP_SUPF_AMP 0x0008
+
+/* AV Media Codec Types (Audio Codec ID) */
+#define A2DP_MEDIA_CT_SBC 0x00 /* SBC media codec type */
+#define A2DP_MEDIA_CT_AAC 0x02 /* AAC media codec type */
+/* Non-A2DP media codec type (vendor-specific codec) */
+#define A2DP_MEDIA_CT_NON_A2DP 0xFF
+
+typedef uint8_t tA2DP_CODEC_TYPE; /* A2DP Codec type: A2DP_MEDIA_CT_* */
+
+#endif // A2DP_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_error_codes.h b/mtkbt/code/bt/stack/include/a2dp_error_codes.h
new file mode 100755
index 0000000..9983a03
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_error_codes.h
@@ -0,0 +1,133 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+//
+// A2DP Error Codes
+//
+
+#ifndef A2DP_ERROR_CODES_H
+#define A2DP_ERROR_CODES_H
+
+#include <inttypes.h>
+
+/* Success */
+#define A2DP_SUCCESS 0
+
+/* Failed */
+#define A2DP_FAIL 0x0A
+
+/* A2DP_FindService is already in progress */
+#define A2DP_BUSY 0x0B
+
+/* Bad parameters */
+#define A2DP_INVALID_PARAMS 0x0C
+
+/* Wrong codec info */
+#define A2DP_WRONG_CODEC 0x0D
+
+/* Media Codec Type is not valid */
+#define A2DP_BAD_CODEC_TYPE 0xC1
+
+/* Media Codec Type is not supported */
+#define A2DP_NS_CODEC_TYPE 0xC2
+
+/* Sampling Frequency is not valid or multiple values have been selected */
+#define A2DP_BAD_SAMP_FREQ 0xC3
+
+/* Sampling Frequency is not supported */
+#define A2DP_NS_SAMP_FREQ 0xC4
+
+/* Channel Mode is not valid or multiple values * have been selected */
+#define A2DP_BAD_CH_MODE 0xC5
+
+/* Channel Mode is not supported */
+#define A2DP_NS_CH_MODE 0xC6
+
+/* None or multiple values have been selected for Number of Subbands */
+#define A2DP_BAD_SUBBANDS 0xC7
+
+/* Number of Subbands is not supported */
+#define A2DP_NS_SUBBANDS 0xC8
+
+/* None or multiple values have been selected for Allocation Method */
+#define A2DP_BAD_ALLOC_METHOD 0xC9
+
+/* Allocation Method is not supported */
+#define A2DP_NS_ALLOC_METHOD 0xCA
+
+/* Minimum Bitpool Value is not valid */
+#define A2DP_BAD_MIN_BITPOOL 0xCB
+
+/* Minimum Bitpool Value is not supported */
+#define A2DP_NS_MIN_BITPOOL 0xCC
+
+/* Maximum Bitpool Value is not valid */
+#define A2DP_BAD_MAX_BITPOOL 0xCD
+
+/* Maximum Bitpool Value is not supported */
+#define A2DP_NS_MAX_BITPOOL 0xCE
+
+/* None or multiple values have been selected for Layer */
+#define A2DP_BAD_LAYER 0xCF
+
+/* Layer is not supported */
+#define A2DP_NS_LAYER 0xD0
+
+/* CRC is not supported */
+#define A2DP_NS_CRC 0xD1
+
+/* MPF-2 is not supported */
+#define A2DP_NS_MPF 0xD2
+
+/* VBR is not supported */
+#define A2DP_NS_VBR 0xD3
+
+/* None or multiple values have been selected for Bit Rate */
+#define A2DP_BAD_BIT_RATE 0xD4
+
+/* Bit Rate is not supported */
+#define A2DP_NS_BIT_RATE 0xD5
+
+/* Either 1) Object type is not valid (b3-b0) or 2) None or multiple values
+ * have been * selected for Object Type
+ */
+#define A2DP_BAD_OBJ_TYPE 0xD6
+
+/* Object type is not supported */
+#define A2DP_NS_OBJ_TYPE 0xD7
+
+/* None or multiple values have been selected for Channels */
+#define A2DP_BAD_CHANNEL 0xD8
+
+/* Channels is not supported */
+#define A2DP_NS_CHANNEL 0xD9
+
+/* None or multiple values have been selected for Block Length */
+#define A2DP_BAD_BLOCK_LEN 0xDD
+
+/* The requested CP Type is not supported. */
+#define A2DP_BAD_CP_TYPE 0xE0
+
+/* The format of Content Protection Service Capability/Content Protection
+ * Scheme Dependent Data is not correct.
+ */
+#define A2DP_BAD_CP_FORMAT 0xE1
+
+typedef uint8_t tA2DP_STATUS;
+
+#endif // A2DP_ERROR_CODES_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_sbc.h b/mtkbt/code/bt/stack/include/a2dp_sbc.h
new file mode 100755
index 0000000..971523e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_sbc.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for low complexity subband codec (SBC)
+//
+
+#ifndef A2DP_SBC_H
+#define A2DP_SBC_H
+
+#include "a2dp_codec_api.h"
+#include "a2dp_sbc_constants.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigSbc : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigSbc(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigSbc();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+ void debug_codec_dump(int fd) override;
+};
+
+class A2dpCodecConfigSbcSink : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigSbcSink(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigSbcSink();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+};
+
+// Checks whether the codec capabilities contain a valid A2DP SBC Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsSourceCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP SBC Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsSinkCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP SBC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsPeerSourceCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP SBC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid SBC codec,
+// otherwise false.
+bool A2DP_IsPeerSinkCodecValidSbc(const uint8_t* p_codec_info);
+
+// Checks whether A2DP SBC Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP SBC Sink codec is supported, otherwise false.
+bool A2DP_IsSinkCodecSupportedSbc(const uint8_t* p_codec_info);
+
+// Checks whether an A2DP SBC Source codec for a peer Source device is
+// supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the A2DP SBC Source codec for a peer Source device is
+// supported, otherwise false.
+bool A2DP_IsPeerSourceCodecSupportedSbc(const uint8_t* p_codec_info);
+
+// Initialize state with the default A2DP SBC codec.
+// The initialized state with the codec capabilities is stored in
+// |p_codec_info|.
+void A2DP_InitDefaultCodecSbc(uint8_t* p_codec_info);
+
+// Builds A2DP preferred SBC Sink capability from SBC Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_BuildSrc2SinkConfigSbc(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg);
+
+// Gets the A2DP SBC codec name for a given |p_codec_info|.
+const char* A2DP_CodecNameSbc(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP SBC codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_CodecTypeEqualsSbc(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP SBC codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not SBC, the return value is false.
+bool A2DP_CodecEqualsSbc(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackSampleRateSbc(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackBitsPerSampleSbc(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetTrackChannelCountSbc(const uint8_t* p_codec_info);
+
+// Gets the number of subbands for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the number of subbands on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfSubbandsSbc(const uint8_t* p_codec_info);
+
+// Gets the number of blocks for the A2DP SBC codec.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the number of blocks on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetNumberOfBlocksSbc(const uint8_t* p_codec_info);
+
+// Gets the allocation method code for the A2DP SBC codec.
+// The actual value is codec-specific - see |A2DP_SBC_IE_ALLOC_MD_*|.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the allocation method code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetAllocationMethodCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP SBC codec.
+// The actual value is codec-specific - see |A2DP_SBC_IE_CH_MD_*|.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetChannelModeCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the sampling frequency code for the A2DP SBC codec.
+// The actual value is codec-specific - see |A2DP_SBC_IE_SAMP_FREQ_*|.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the sampling frequency code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSamplingFrequencyCodeSbc(const uint8_t* p_codec_info);
+
+// Gets the minimum bitpool for the A2DP SBC codec.
+// The actual value is codec-specific - see |A2DP_SBC_IE_MIN_BITPOOL|.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the minimum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMinBitpoolSbc(const uint8_t* p_codec_info);
+
+// Gets the maximum bitpool for the A2DP SBC codec.
+// The actual value is codec-specific - see |A2DP_SBC_IE_MAX_BITPOOL|.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the maximum bitpool on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetMaxBitpoolSbc(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP SBC Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the SBC codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkTrackChannelTypeSbc(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// SBC sink codec. |time_interval_ms| is the time interval (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_GetSinkFramesCountToProcessSbc(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP SBC audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_GetPacketTimestampSbc(const uint8_t* p_codec_info,
+ const uint8_t* p_data, uint32_t* p_timestamp);
+
+// Builds A2DP SBC codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_BuildCodecHeaderSbc(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Decodes and displays SBC codec info (for debugging).
+// |p_codec_info| is a pointer to the SBC codec_info to decode and display.
+void A2DP_DumpCodecInfoSbc(const uint8_t* p_codec_info);
+
+// Gets the A2DP SBC encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP SBC encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_GetEncoderInterfaceSbc(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP SBC codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_AdjustCodecSbc(uint8_t* p_codec_info);
+
+// Gets the A2DP SBC Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_SourceCodecIndexSbc(const uint8_t* p_codec_info);
+
+// Gets the A2DP SBC Source codec name.
+const char* A2DP_CodecIndexStrSbc(void);
+
+// Gets the A2DP SBC Sink codec name.
+const char* A2DP_CodecIndexStrSbcSink(void);
+
+// Initializes A2DP SBC Source codec information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbc(tAVDT_CFG* p_cfg);
+
+// Initializes A2DP SBC Sink codec information into |tAVDT_CFG| configuration
+// entry pointed by |p_cfg|.
+bool A2DP_InitCodecConfigSbcSink(tAVDT_CFG* p_cfg);
+
+#endif // A2DP_SBC_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_sbc_constants.h b/mtkbt/code/bt/stack/include/a2dp_sbc_constants.h
new file mode 100755
index 0000000..cb3b801
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_sbc_constants.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2000-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+//
+// A2DP constants for low complexity subband codec (SBC)
+//
+
+#ifndef A2DP_SBC_CONSTANTS_H
+#define A2DP_SBC_CONSTANTS_H
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/* the length of the SBC Media Payload header. */
+#define A2DP_SBC_MPL_HDR_LEN 1
+
+/* the LOSC of SBC media codec capabilitiy */
+#define A2DP_SBC_INFO_LEN 6
+
+/* for Codec Specific Information Element */
+#define A2DP_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */
+#define A2DP_SBC_IE_SAMP_FREQ_16 0x80 /* b7:16 kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_32 0x40 /* b6:32 kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
+#define A2DP_SBC_IE_SAMP_FREQ_48 0x10 /* b4:48 kHz */
+
+#define A2DP_SBC_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */
+#define A2DP_SBC_IE_CH_MD_MONO 0x08 /* b3: mono */
+#define A2DP_SBC_IE_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2DP_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2DP_SBC_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */
+
+#define A2DP_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */
+#define A2DP_SBC_IE_BLOCKS_4 0x80 /* 4 blocks */
+#define A2DP_SBC_IE_BLOCKS_8 0x40 /* 8 blocks */
+#define A2DP_SBC_IE_BLOCKS_12 0x20 /* 12blocks */
+#define A2DP_SBC_IE_BLOCKS_16 0x10 /* 16blocks */
+
+#define A2DP_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */
+#define A2DP_SBC_IE_SUBBAND_4 0x08 /* b3: 4 */
+#define A2DP_SBC_IE_SUBBAND_8 0x04 /* b2: 8 */
+
+#define A2DP_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */
+#define A2DP_SBC_IE_ALLOC_MD_S 0x02 /* b1: SNR */
+#define A2DP_SBC_IE_ALLOC_MD_L 0x01 /* b0: loundess */
+
+#define A2DP_SBC_IE_MIN_BITPOOL 2
+#define A2DP_SBC_IE_MAX_BITPOOL 250
+
+/* for media payload header */
+#define A2DP_SBC_HDR_F_MSK 0x80
+#define A2DP_SBC_HDR_S_MSK 0x40
+#define A2DP_SBC_HDR_L_MSK 0x20
+#define A2DP_SBC_HDR_NUM_MSK 0x0F
+
+#endif // A2DP_SBC_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_sbc_encoder.h b/mtkbt/code/bt/stack/include/a2dp_sbc_encoder.h
new file mode 100755
index 0000000..6ff1cf7
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_sbc_encoder.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+//
+// Interface to the A2DP SBC Encoder
+//
+
+#ifndef A2DP_SBC_ENCODER_H
+#define A2DP_SBC_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP SBC encoder.
+// Return true on success, otherwise false.
+bool A2DP_LoadEncoderSbc(void);
+
+// Unloads the A2DP SBC encoder.
+void A2DP_UnloadEncoderSbc(void);
+
+// Initialize the A2DP SBC encoder.
+// |p_peer_params| contains the A2DP peer information
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_sbc_encoder_init(const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP SBC encoder.
+void a2dp_sbc_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP SBC encoder.
+void a2dp_sbc_feeding_reset(void);
+
+// Flush the feeding for the A2DP SBC encoder.
+void a2dp_sbc_feeding_flush(void);
+
+// Get the A2DP SBC encoder interval (in milliseconds).
+period_ms_t a2dp_sbc_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP SBC encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_sbc_send_frames(uint64_t timestamp_us);
+
+#endif // A2DP_SBC_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_sbc_up_sample.h b/mtkbt/code/bt/stack/include/a2dp_sbc_up_sample.h
new file mode 100755
index 0000000..234ce54
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_sbc_up_sample.h
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface to utility functions for dealing with SBC data
+ * frames and codec capabilities.
+ *
+ ******************************************************************************/
+#ifndef A2DP_SBC_UP_SAMPLE_H
+#define A2DP_SBC_UP_SAMPLE_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_init_up_sample
+ *
+ * Description initialize the up sample
+ *
+ * src_sps: samples per second (source audio data)
+ * dst_sps: samples per second (converted audio data)
+ * bits: number of bits per pcm sample
+ * n_channels: number of channels (i.e. mono(1), stereo(2)...)
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void a2dp_sbc_init_up_sample(uint32_t src_sps, uint32_t dst_sps, uint8_t bits,
+ uint8_t n_channels);
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (number of bytes)
+ * dst_samples: The size of p_dst (number of bytes)
+ *
+ * Note: An AE reported an issue with this function.
+ * When called with a2dp_sbc_up_sample(src, uint8_array_dst..)
+ * the byte before uint8_array_dst may get overwritten.
+ * Using uint16_array_dst avoids the problem.
+ * This issue is related to endian-ness and is hard to resolve
+ * in a generic manner.
+ * **************** Please use uint16 array as dst.
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_16s (16bits-stereo)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 4
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 4 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_16s(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_16m (16bits-mono)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 2
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 2 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_16m(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_8s (8bits-stereo)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (in uint of 2
+ * bytes)
+ * dst_samples: The size of p_dst (in uint of 2 bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_8s(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+/*******************************************************************************
+ *
+ * Function a2dp_sbc_up_sample_8m (8bits-mono)
+ *
+ * Description Given the source (p_src) audio data and
+ * source speed (src_sps, samples per second),
+ * This function converts it to audio data in the desired
+ * format
+ *
+ * p_src: the data buffer that holds the source audio data
+ * p_dst: the data buffer to hold the converted audio data
+ * src_samples: The number of source samples (number of bytes)
+ * dst_samples: The size of p_dst (number of bytes)
+ *
+ * Returns The number of bytes used in p_dst
+ * The number of bytes used in p_src (in *p_ret)
+ *
+ ******************************************************************************/
+int a2dp_sbc_up_sample_8m(void* p_src, void* p_dst, uint32_t src_samples,
+ uint32_t dst_samples, uint32_t* p_ret);
+
+#endif // A2DP_SBC_UP_SAMPLE_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor.h b/mtkbt/code/bt/stack/include/a2dp_vendor.h
new file mode 100755
index 0000000..2a0a6c8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Vendor Specific A2DP Codecs Support
+//
+
+#ifndef A2DP_VENDOR_H
+#define A2DP_VENDOR_H
+
+#include <stdbool.h>
+#include "a2dp_codec_api.h"
+
+/* Offset for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_START_IDX 3
+
+/* Offset for Vendor ID for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX A2DP_VENDOR_CODEC_START_IDX
+
+/* Offset for Codec ID for A2DP vendor codec */
+#define A2DP_VENDOR_CODEC_CODEC_ID_START_IDX \
+ (A2DP_VENDOR_CODEC_VENDOR_ID_START_IDX + sizeof(uint32_t))
+
+// Checks whether the codec capabilities contain a valid A2DP vendor-specific
+// Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid A2DP vendor-specific
+// Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP
+// vendor-specific Source codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP
+// vendor-specific Sink codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid
+// vendor-specific codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValid(const uint8_t* p_codec_info);
+
+// Checks whether a vendor-specific A2DP Sink codec is supported.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns true if the vendor-specific A2DP Sink codec is supported,
+// otherwise false.
+bool A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info);
+
+// Checks whether a vendor-specific A2DP Source codec for a peer Source device
+// is supported.
+// |p_codec_info| contains information about the codec capabilities of the
+// peer device.
+// Returns true if the vendor-specific A2DP Source codec for a peer Source
+// device is supported, otherwise false.
+bool A2DP_IsVendorPeerSourceCodecSupported(const uint8_t* p_codec_info);
+
+// Builds a vendor-specific A2DP preferred Sink capability from a vendor
+// Source capability.
+// |p_src_cap| is the Source capability to use.
+// |p_pref_cfg| is the result Sink capability to store.
+// Returns |A2DP_SUCCESS| on success, otherwise the corresponding A2DP error
+// status code.
+tA2DP_STATUS A2DP_VendorBuildSrc2SinkConfig(const uint8_t* p_src_cap,
+ uint8_t* p_pref_cfg);
+
+// Gets the Vendor ID for the vendor-specific A2DP codec.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns the Vendor ID for the vendor-specific A2DP codec.
+uint32_t A2DP_VendorCodecGetVendorId(const uint8_t* p_codec_info);
+
+// Gets the Codec ID for the vendor-specific A2DP codec.
+// |p_codec_info| contains information about the codec capabilities.
+// Returns the Codec ID for the vendor-specific A2DP codec.
+uint16_t A2DP_VendorCodecGetCodecId(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP vendor-specific data packets should contain RTP
+// header. |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP vendor-specific data packets should contain RTP
+// header, otherwise false.
+bool A2DP_VendorUsesRtpHeader(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP vendor-specific codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecName(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP vendor-specific codecs |p_codec_info_a| and
+// |p_codec_info_b| have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_VendorCodecTypeEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP vendor-specific codecs |p_codec_info_a| and
+// |p_codec_info_b| are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not recognized, the return value is false.
+bool A2DP_VendorCodecEquals(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackSampleRate(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSample(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP vendor-specific codec.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCount(const uint8_t* p_codec_info);
+
+// Gets the channel type for the A2DP vendor-specific Sink codec:
+// 1 for mono, or 3 for dual/stereo/joint.
+// |p_codec_info| is a pointer to the vendor-specific codec_info to decode.
+// Returns the channel type on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info);
+
+// Computes the number of frames to process in a time window for the A2DP
+// vendor-specific Sink codec. |time_interval_ms| is the time interval
+// (in milliseconds).
+// |p_codec_info| is a pointer to the codec_info to decode.
+// Returns the number of frames to process on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetSinkFramesCountToProcess(uint64_t time_interval_ms,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP codec-specific audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestamp(const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp);
+
+// Builds A2DP vendor-specific codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeader(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Gets the A2DP vendor encoder interface that can be used to encode and
+// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP vendor encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterface(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP vendor-specific codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodec(uint8_t* p_codec_info);
+
+// Gets the A2DP vendor Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndex(
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP vendor codec name for a given |codec_index|.
+const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index);
+
+// Initializes A2DP vendor codec-specific information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|. The selected codec is defined by
+// |codec_index|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index,
+ tAVDT_CFG* p_cfg);
+
+#endif // A2DP_VENDOR_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx.h
new file mode 100755
index 0000000..9fbc5f9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for aptX
+//
+
+#ifndef A2DP_VENDOR_APTX_H
+#define A2DP_VENDOR_APTX_H
+
+#include "a2dp_codec_api.h"
+#include "a2dp_vendor_aptx_constants.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigAptx : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigAptx(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigAptx();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+ void debug_codec_dump(int fd) override;
+};
+
+// Checks whether the codec capabilities contain a valid A2DP aptX Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid aptX
+// codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValidAptx(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP aptX Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid aptX
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValidAptx(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_VendorUsesRtpHeaderAptx(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecNameAptx(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP aptX codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_VendorCodecTypeEqualsAptx(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP aptX codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not aptX, the return value is false.
+bool A2DP_VendorCodecEqualsAptx(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackSampleRateAptx(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptx(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP aptX codec.
+// |p_codec_info| is a pointer to the aptX codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCountAptx(const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestampAptx(const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp);
+
+// Builds A2DP aptX codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeaderAptx(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Decodes and displays aptX codec info (for debugging).
+// |p_codec_info| is a pointer to the aptX codec_info to decode and display.
+void A2DP_VendorDumpCodecInfoAptx(const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP aptX encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptx(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP aptX codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodecAptx(uint8_t* p_codec_info);
+
+// Gets the A2DP aptX Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptx(
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX Source codec name.
+const char* A2DP_VendorCodecIndexStrAptx(void);
+
+// Initializes A2DP aptX Source codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigAptx(tAVDT_CFG* p_cfg);
+
+#endif // A2DP_VENDOR_APTX_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_constants.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_constants.h
new file mode 100755
index 0000000..0f2c7c6
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_constants.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP constants for aptX codec
+//
+
+#ifndef A2DP_VENDOR_APTX_CONSTANTS_H
+#define A2DP_VENDOR_APTX_CONSTANTS_H
+
+/* aptX codec specific settings */
+#define A2DP_APTX_CODEC_LEN 9
+
+#define A2DP_APTX_VENDOR_ID 0x0000004F
+#define A2DP_APTX_CODEC_ID_BLUETOOTH 0x0001
+#define A2DP_APTX_SAMPLERATE_44100 0x20
+#define A2DP_APTX_SAMPLERATE_48000 0x10
+#define A2DP_APTX_CHANNELS_STEREO 0x02
+#define A2DP_APTX_CHANNELS_MONO 0x01
+#define A2DP_APTX_FUTURE_1 0x00
+#define A2DP_APTX_FUTURE_2 0x00
+
+#endif // A2DP_VENDOR_APTX_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_encoder.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_encoder.h
new file mode 100755
index 0000000..7a67307
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_encoder.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP aptX Encoder
+//
+
+#ifndef A2DP_VENDOR_APTX_ENCODER_H
+#define A2DP_VENDOR_APTX_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP aptX encoder.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadEncoderAptx(void);
+
+// Unloads the A2DP aptX encoder.
+void A2DP_VendorUnloadEncoderAptx(void);
+
+// Initialize the A2DP aptX encoder.
+// |p_peer_params| contains the A2DP peer information.
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_vendor_aptx_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP aptX encoder.
+void a2dp_vendor_aptx_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP aptX encoder.
+void a2dp_vendor_aptx_feeding_reset(void);
+
+// Flush the feeding for the A2DP aptX encoder.
+void a2dp_vendor_aptx_feeding_flush(void);
+
+// Get the A2DP aptX encoder interval (in milliseconds).
+period_ms_t a2dp_vendor_aptx_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP aptX encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_vendor_aptx_send_frames(uint64_t timestamp_us);
+
+#endif // A2DP_VENDOR_APTX_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd.h
new file mode 100755
index 0000000..384390c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for aptX-HD
+//
+
+#ifndef A2DP_VENDOR_APTX_HD_H
+#define A2DP_VENDOR_APTX_HD_H
+
+#include "a2dp_codec_api.h"
+#include "a2dp_vendor_aptx_hd_constants.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigAptxHd : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigAptxHd(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigAptxHd();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+ void debug_codec_dump(int fd) override;
+};
+
+// Checks whether the codec capabilities contain a valid A2DP aptX-HD Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid aptX-HD
+// codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValidAptxHd(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP aptX-HD Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid aptX-HD
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValidAptxHd(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_VendorUsesRtpHeaderAptxHd(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX-HD codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecNameAptxHd(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP aptX-HD codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_VendorCodecTypeEqualsAptxHd(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP aptX-HD codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not aptX-HD, the return value is false.
+bool A2DP_VendorCodecEqualsAptxHd(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackSampleRateAptxHd(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleAptxHd(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP aptX-HD codec.
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCountAptxHd(const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX-HD audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestampAptxHd(const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp);
+
+// Builds A2DP aptX-HD codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeaderAptxHd(const uint8_t* p_codec_info,
+ BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Decodes and displays aptX-HD codec info (for debugging).
+// |p_codec_info| is a pointer to the aptX-HD codec_info to decode and display.
+void A2DP_VendorDumpCodecInfoAptxHd(const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX-HD encoder interface that can be used to encode and
+// prepare A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP aptX-HD encoder interface if the |p_codec_info| is valid
+// and supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceAptxHd(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP aptX-HD codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodecAptxHd(uint8_t* p_codec_info);
+
+// Gets the A2DP aptX-HD Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexAptxHd(
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP aptX-HD Source codec name.
+const char* A2DP_VendorCodecIndexStrAptxHd(void);
+
+// Initializes A2DP aptX-HD Source codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigAptxHd(tAVDT_CFG* p_cfg);
+
+#endif // A2DP_VENDOR_APTX_HD_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_constants.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_constants.h
new file mode 100755
index 0000000..40ac8b5
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_constants.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP constants for aptX-HD codec
+//
+
+#ifndef A2DP_VENDOR_APTX_HD_CONSTANTS_H
+#define A2DP_VENDOR_APTX_HD_CONSTANTS_H
+
+/* aptX-HD codec specific settings */
+#define A2DP_APTX_HD_CODEC_LEN 13
+
+#define A2DP_APTX_HD_VENDOR_ID 0x000000D7
+#define A2DP_APTX_HD_CODEC_ID_BLUETOOTH 0x0024
+#define A2DP_APTX_HD_SAMPLERATE_44100 0x20
+#define A2DP_APTX_HD_SAMPLERATE_48000 0x10
+#define A2DP_APTX_HD_CHANNELS_STEREO 0x02
+#define A2DP_APTX_HD_CHANNELS_MONO 0x01
+#define A2DP_APTX_HD_ACL_SPRINT_RESERVED0 0x00
+#define A2DP_APTX_HD_ACL_SPRINT_RESERVED1 0x00
+#define A2DP_APTX_HD_ACL_SPRINT_RESERVED2 0x00
+#define A2DP_APTX_HD_ACL_SPRINT_RESERVED3 0x00
+
+#endif // A2DP_VENDOR_APTX_HD_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_encoder.h b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_encoder.h
new file mode 100755
index 0000000..b662e8e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_aptx_hd_encoder.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP aptX-HD Encoder
+//
+
+#ifndef A2DP_VENDOR_APTX_HD_ENCODER_H
+#define A2DP_VENDOR_APTX_HD_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP aptX-HD encoder.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadEncoderAptxHd(void);
+
+// Unloads the A2DP aptX-HD encoder.
+void A2DP_VendorUnloadEncoderAptxHd(void);
+
+// Initialize the A2DP aptX-HD encoder.
+// |p_peer_params| contains the A2DP peer information.
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_vendor_aptx_hd_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP aptX-HD encoder.
+void a2dp_vendor_aptx_hd_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP aptX-HD encoder.
+void a2dp_vendor_aptx_hd_feeding_reset(void);
+
+// Flush the feeding for the A2DP aptX-HD encoder.
+void a2dp_vendor_aptx_hd_feeding_flush(void);
+
+// Get the A2DP aptX-HD encoder interval (in milliseconds).
+period_ms_t a2dp_vendor_aptx_hd_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP aptX-HD encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_vendor_aptx_hd_send_frames(uint64_t timestamp_us);
+
+#endif // A2DP_VENDOR_APTX_HD_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_ldac.h b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac.h
new file mode 100755
index 0000000..b3f91f2
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP Codec API for LDAC
+//
+
+#ifndef A2DP_VENDOR_LDAC_H
+#define A2DP_VENDOR_LDAC_H
+
+#include "a2dp_codec_api.h"
+#include "a2dp_vendor_ldac_constants.h"
+#include "avdt_api.h"
+
+class A2dpCodecConfigLdac : public A2dpCodecConfig {
+ public:
+ A2dpCodecConfigLdac(btav_a2dp_codec_priority_t codec_priority);
+ virtual ~A2dpCodecConfigLdac();
+
+ bool init() override;
+ period_ms_t encoderIntervalMs() const override;
+ bool setCodecConfig(const uint8_t* p_peer_codec_info, bool is_capability,
+ uint8_t* p_result_codec_config) override;
+
+ private:
+ bool useRtpHeaderMarkerBit() const override;
+ bool updateEncoderUserConfig(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ bool* p_restart_input, bool* p_restart_output,
+ bool* p_config_updated) override;
+ void debug_codec_dump(int fd) override;
+};
+
+// Checks whether the codec capabilities contain a valid A2DP LDAC Source
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorSourceCodecValidLdac(const uint8_t* p_codec_info);
+
+// Checks whether the codec capabilities contain a valid peer A2DP LDAC Sink
+// codec.
+// NOTE: only codecs that are implemented are considered valid.
+// Returns true if |p_codec_info| contains information about a valid LDAC
+// codec, otherwise false.
+bool A2DP_IsVendorPeerSinkCodecValidLdac(const uint8_t* p_codec_info);
+
+// Checks whether the A2DP data packets should contain RTP header.
+// |content_protection_enabled| is true if Content Protection is
+// enabled. |p_codec_info| contains information about the codec capabilities.
+// Returns true if the A2DP data packets should contain RTP header, otherwise
+// false.
+bool A2DP_VendorUsesRtpHeaderLdac(bool content_protection_enabled,
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP LDAC codec name for a given |p_codec_info|.
+const char* A2DP_VendorCodecNameLdac(const uint8_t* p_codec_info);
+
+// Checks whether two A2DP LDAC codecs |p_codec_info_a| and |p_codec_info_b|
+// have the same type.
+// Returns true if the two codecs have the same type, otherwise false.
+bool A2DP_VendorCodecTypeEqualsLdac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Checks whether two A2DP LDAC codecs |p_codec_info_a| and |p_codec_info_b|
+// are exactly the same.
+// Returns true if the two codecs are exactly the same, otherwise false.
+// If the codec type is not LDAC, the return value is false.
+bool A2DP_VendorCodecEqualsLdac(const uint8_t* p_codec_info_a,
+ const uint8_t* p_codec_info_b);
+
+// Gets the track sample rate value for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the track sample rate on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* p_codec_info);
+
+// Gets the bits per audio sample for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the bits per audio sample on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info);
+
+// Gets the channel count for the A2DP LDAC codec.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the channel count on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info);
+
+// Gets the channel mode code for the A2DP LDAC codec.
+// The actual value is codec-specific - see |A2DP_LDAC_CHANNEL_MODE_*|.
+// |p_codec_info| is a pointer to the LDAC codec_info to decode.
+// Returns the channel mode code on success, or -1 if |p_codec_info|
+// contains invalid codec information.
+int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info);
+
+// Gets the A2DP LDAC audio data timestamp from an audio packet.
+// |p_codec_info| contains the codec information.
+// |p_data| contains the audio data.
+// The timestamp is stored in |p_timestamp|.
+// Returns true on success, otherwise false.
+bool A2DP_VendorGetPacketTimestampLdac(const uint8_t* p_codec_info,
+ const uint8_t* p_data,
+ uint32_t* p_timestamp);
+
+// Builds A2DP LDAC codec header for audio data.
+// |p_codec_info| contains the codec information.
+// |p_buf| contains the audio data.
+// |frames_per_packet| is the number of frames in this packet.
+// Returns true on success, otherwise false.
+bool A2DP_VendorBuildCodecHeaderLdac(const uint8_t* p_codec_info, BT_HDR* p_buf,
+ uint16_t frames_per_packet);
+
+// Decodes and displays LDAC codec info (for debugging).
+// |p_codec_info| is a pointer to the LDAC codec_info to decode and display.
+void A2DP_VendorDumpCodecInfoLdac(const uint8_t* p_codec_info);
+
+// Gets the A2DP LDAC encoder interface that can be used to encode and prepare
+// A2DP packets for transmission - see |tA2DP_ENCODER_INTERFACE|.
+// |p_codec_info| contains the codec information.
+// Returns the A2DP LDAC encoder interface if the |p_codec_info| is valid and
+// supported, otherwise NULL.
+const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
+ const uint8_t* p_codec_info);
+
+// Adjusts the A2DP LDAC codec, based on local support and Bluetooth
+// specification.
+// |p_codec_info| contains the codec information to adjust.
+// Returns true if |p_codec_info| is valid and supported, otherwise false.
+bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info);
+
+// Gets the A2DP LDAC Source codec index for a given |p_codec_info|.
+// Returns the corresponding |btav_a2dp_codec_index_t| on success,
+// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
+btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(
+ const uint8_t* p_codec_info);
+
+// Gets the A2DP LDAC Source codec name.
+const char* A2DP_VendorCodecIndexStrLdac(void);
+
+// Initializes A2DP LDAC Source codec information into |tAVDT_CFG|
+// configuration entry pointed by |p_cfg|.
+bool A2DP_VendorInitCodecConfigLdac(tAVDT_CFG* p_cfg);
+
+#endif // A2DP_VENDOR_LDAC_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_abr.h b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_abr.h
new file mode 100755
index 0000000..157dbba
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_abr.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP LDAC ABR
+//
+
+#ifndef A2DP_VENDOR_LDAC_ABR_H
+#define A2DP_VENDOR_LDAC_ABR_H
+
+#include <stdio.h>
+
+#include <ldacBT_abr.h>
+
+// Initial EQMID for ABR mode.
+#define LDAC_ABR_MODE_EQMID LDACBT_EQMID_SQ
+
+// Loads the LDAC ABR library.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadLdacAbr(void);
+
+// Unloads the LDAC ABR library.
+void A2DP_VendorUnloadLdacAbr(void);
+
+// Gets the LDAC ABR handle.
+// Return the LDAC ABR handle.
+HANDLE_LDAC_ABR a2dp_ldac_abr_get_handle(void);
+
+// Free the LDAC ABR handle.
+void a2dp_ldac_abr_free_handle(HANDLE_LDAC_ABR hLdacAbr);
+
+// Initializes the LDAC ABR handle.
+// Return 0 on success, or -1 on failure.
+int a2dp_ldac_abr_init(HANDLE_LDAC_ABR hLdacAbr, unsigned int interval_ms);
+
+// Sets thresholds for the LDAC ABR handle.
+// Return 0 on success, or -1 on failure.
+int a2dp_ldac_abr_set_thresholds(HANDLE_LDAC_ABR hLdacAbr,
+ unsigned int th_critical,
+ unsigned int th_dangerous_trend,
+ unsigned int th_4hqsq);
+
+// LDAC ABR main process.
+// It controls LDAC encoder bit rate based on A2DP transmit queue length.
+// return current EQMID of LDAC encoder.
+int a2dp_ldac_abr_proc(HANDLE_LDAC_BT hLdacParam, HANDLE_LDAC_ABR hLdacAbr,
+ size_t transmit_queue_length, unsigned int flag_enable);
+
+#endif // A2DP_VENDOR_LDAC_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_constants.h b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_constants.h
new file mode 100755
index 0000000..6242add
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_constants.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// A2DP constants for LDAC codec
+//
+
+#ifndef A2DP_VENDOR_LDAC_CONSTANTS_H
+#define A2DP_VENDOR_LDAC_CONSTANTS_H
+
+// LDAC Quality Mode Index
+#define A2DP_LDAC_QUALITY_HIGH 0 // Equal to LDACBT_EQMID_HQ 990kbps
+#define A2DP_LDAC_QUALITY_MID 1 // Equal to LDACBT_EQMID_SQ 660kbps
+#define A2DP_LDAC_QUALITY_LOW 2 // Equal to LDACBT_EQMID_MQ 330kbps
+#define A2DP_LDAC_QUALITY_ABR 3 // ABR mode, range: 990,660,492,396,330(kbps)
+
+// Length of the LDAC Media Payload header
+#define A2DP_LDAC_MPL_HDR_LEN 1
+
+// LDAC Media Payload Header
+#define A2DP_LDAC_HDR_F_MSK 0x80
+#define A2DP_LDAC_HDR_S_MSK 0x40
+#define A2DP_LDAC_HDR_L_MSK 0x20
+#define A2DP_LDAC_HDR_NUM_MSK 0x0F
+
+// LDAC codec specific settings
+#define A2DP_LDAC_CODEC_LEN 10
+// [Octet 0-3] Vendor ID
+#define A2DP_LDAC_VENDOR_ID 0x0000012D
+// [Octet 4-5] Vendor Specific Codec ID
+#define A2DP_LDAC_CODEC_ID 0x00AA
+// [Octet 6], [Bits 0-5] Sampling Frequency
+#define A2DP_LDAC_SAMPLING_FREQ_MASK 0x3F
+#define A2DP_LDAC_SAMPLING_FREQ_44100 0x20
+#define A2DP_LDAC_SAMPLING_FREQ_48000 0x10
+#define A2DP_LDAC_SAMPLING_FREQ_88200 0x08
+#define A2DP_LDAC_SAMPLING_FREQ_96000 0x04
+#define A2DP_LDAC_SAMPLING_FREQ_176400 0x02
+#define A2DP_LDAC_SAMPLING_FREQ_192000 0x01
+// [Octet 7], [Bits 0-2] Channel Mode
+#define A2DP_LDAC_CHANNEL_MODE_MASK 0x07
+#define A2DP_LDAC_CHANNEL_MODE_MONO 0x04
+#define A2DP_LDAC_CHANNEL_MODE_DUAL 0x02
+#define A2DP_LDAC_CHANNEL_MODE_STEREO 0x01
+
+#endif // A2DP_VENDOR_LDAC_CONSTANTS_H
diff --git a/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_encoder.h b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_encoder.h
new file mode 100755
index 0000000..45694f0
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/a2dp_vendor_ldac_encoder.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Interface to the A2DP LDAC Encoder
+//
+
+#ifndef A2DP_VENDOR_LDAC_ENCODER_H
+#define A2DP_VENDOR_LDAC_ENCODER_H
+
+#include "a2dp_codec_api.h"
+#include "osi/include/time.h"
+
+// Loads the A2DP LDAC encoder.
+// Return true on success, otherwise false.
+bool A2DP_VendorLoadEncoderLdac(void);
+
+// Unloads the A2DP LDAC encoder.
+void A2DP_VendorUnloadEncoderLdac(void);
+
+// Initialize the A2DP LDAC encoder.
+// |p_peer_params| contains the A2DP peer information
+// The current A2DP codec config is in |a2dp_codec_config|.
+// |read_callback| is the callback for reading the input audio data.
+// |enqueue_callback| is the callback for enqueueing the encoded audio data.
+void a2dp_vendor_ldac_encoder_init(
+ const tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params,
+ A2dpCodecConfig* a2dp_codec_config,
+ a2dp_source_read_callback_t read_callback,
+ a2dp_source_enqueue_callback_t enqueue_callback);
+
+// Cleanup the A2DP LDAC encoder.
+void a2dp_vendor_ldac_encoder_cleanup(void);
+
+// Reset the feeding for the A2DP LDAC encoder.
+void a2dp_vendor_ldac_feeding_reset(void);
+
+// Flush the feeding for the A2DP LDAC encoder.
+void a2dp_vendor_ldac_feeding_flush(void);
+
+// Get the A2DP LDAC encoder interval (in milliseconds).
+period_ms_t a2dp_vendor_ldac_get_encoder_interval_ms(void);
+
+// Prepare and send A2DP LDAC encoded frames.
+// |timestamp_us| is the current timestamp (in microseconds).
+void a2dp_vendor_ldac_send_frames(uint64_t timestamp_us);
+
+// Set transmit queue length for the A2DP LDAC ABR(Adaptive Bit Rate) mechanism.
+void a2dp_vendor_ldac_set_transmit_queue_length(size_t transmit_queue_length);
+
+#endif // A2DP_VENDOR_LDAC_ENCODER_H
diff --git a/mtkbt/code/bt/stack/include/advertise_data_parser.h b/mtkbt/code/bt/stack/include/advertise_data_parser.h
new file mode 100755
index 0000000..24ee2b3
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/advertise_data_parser.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <vector>
+
+class AdvertiseDataParser {
+ public:
+ /**
+ * Return true if this |ad| represent properly formatted advertising data.
+ */
+ static bool IsValid(const std::vector<uint8_t>& ad) {
+ size_t position = 0;
+
+ size_t ad_len = ad.size();
+ while (position != ad_len) {
+ uint8_t len = ad[position];
+
+ // A field length of 0 would be invalid as it should at least contain the
+ // EIR field type.
+ if (len == 0) return false;
+
+ // If the length of the current field would exceed the total data length,
+ // then the data is badly formatted.
+ if (position + len >= ad_len) {
+ return false;
+ }
+
+ position += len + 1;
+ }
+
+ return true;
+ }
+
+ /**
+ * This function returns a pointer inside the |ad| array of length |ad_len|
+ * where a field of |type| is located, together with its length in |p_length|
+ */
+ static const uint8_t* GetFieldByType(const uint8_t* ad, size_t ad_len,
+ uint8_t type, uint8_t* p_length) {
+ size_t position = 0;
+
+ while (position != ad_len) {
+ uint8_t len = ad[position];
+
+ if (len == 0) break;
+ if (position + len >= ad_len) break;
+
+ uint8_t adv_type = ad[position + 1];
+
+ if (adv_type == type) {
+ /* length doesn't include itself */
+ *p_length = len - 1; /* minus the length of type */
+ return ad + position + 2;
+ }
+
+ position += len + 1; /* skip the length of data */
+ }
+
+ *p_length = 0;
+ return NULL;
+ }
+
+ /**
+ * This function returns a pointer inside the |adv| where a field of |type| is
+ * located, together with it' length in |p_length|
+ */
+ static const uint8_t* GetFieldByType(std::vector<uint8_t> const& ad,
+ uint8_t type, uint8_t* p_length) {
+ return GetFieldByType(ad.data(), ad.size(), type, p_length);
+ }
+};
diff --git a/mtkbt/code/bt/stack/include/avct_api.h b/mtkbt/code/bt/stack/include/avct_api.h
new file mode 100755
index 0000000..6c6914c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/avct_api.h
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This interface file contains the interface to the Audio Video Control
+ * Transport Protocol (AVCTP).
+ *
+ ******************************************************************************/
+#ifndef AVCT_API_H
+#define AVCT_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* API function return value result codes. */
+#define AVCT_SUCCESS 0 /* Function successful */
+#define AVCT_NO_RESOURCES 1 /* Not enough resources */
+#define AVCT_BAD_HANDLE 2 /* Bad handle */
+#define AVCT_PID_IN_USE 3 /* PID already in use */
+#define AVCT_NOT_OPEN 4 /* Connection not open */
+
+/* PSM for AVCT. */
+#define AVCT_PSM 0x0017
+#define AVCT_BR_PSM 0x001B
+
+/* Protocol revision numbers */
+#define AVCT_REV_1_0 0x0100
+#define AVCT_REV_1_2 0x0102
+#define AVCT_REV_1_3 0x0103
+#define AVCT_REV_1_4 0x0104
+
+/* the layer_specific settings */
+#define AVCT_DATA_CTRL 0x0001 /* for the control channel */
+#define AVCT_DATA_BROWSE 0x0002 /* for the browsing channel */
+#define AVCT_DATA_PARTIAL 0x0100 /* Only have room for a partial message */
+
+/* Per the AVRC spec, minimum MTU for the control channel */
+#define AVCT_MIN_CONTROL_MTU 48
+/* Per the AVRC spec, minimum MTU for the browsing channel */
+#define AVCT_MIN_BROWSE_MTU 335
+
+/* Message offset. The number of bytes needed by the protocol stack for the
+ * protocol headers of an AVCTP message packet.
+*/
+#define AVCT_MSG_OFFSET 15
+#define AVCT_BROWSE_OFFSET 17 /* the default offset for browsing channel */
+
+/* Connection role. */
+#define AVCT_INT 0 /* Initiator connection */
+#define AVCT_ACP 1 /* Acceptor connection */
+
+/* Control role. */
+#define AVCT_TARGET 1 /* target */
+#define AVCT_CONTROL 2 /* controller */
+#define AVCT_PASSIVE 4 /* If conflict, allow the other side to succeed */
+
+/* Command/Response indicator. */
+#define AVCT_CMD 0 /* Command message */
+#define AVCT_RSP 2 /* Response message */
+#define AVCT_REJ 3 /* Message rejected */
+
+/* Control callback events. */
+#define AVCT_CONNECT_CFM_EVT 0 /* Connection confirm */
+#define AVCT_CONNECT_IND_EVT 1 /* Connection indication */
+#define AVCT_DISCONNECT_CFM_EVT 2 /* Disconnect confirm */
+#define AVCT_DISCONNECT_IND_EVT 3 /* Disconnect indication */
+#define AVCT_CONG_IND_EVT 4 /* Congestion indication */
+#define AVCT_UNCONG_IND_EVT 5 /* Uncongestion indication */
+#define AVCT_BROWSE_CONN_CFM_EVT 6 /* Browse Connection confirm */
+#define AVCT_BROWSE_CONN_IND_EVT 7 /* Browse Connection indication */
+#define AVCT_BROWSE_DISCONN_CFM_EVT 8 /* Browse Disconnect confirm */
+#define AVCT_BROWSE_DISCONN_IND_EVT 9 /* Browse Disconnect indication */
+#define AVCT_BROWSE_CONG_IND_EVT 10 /* Congestion indication */
+#define AVCT_BROWSE_UNCONG_IND_EVT 11 /* Uncongestion indication */
+
+/* General purpose failure result code for callback events. */
+#define AVCT_RESULT_FAIL 5
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/* Control callback function. */
+typedef void(tAVCT_CTRL_CBACK)(uint8_t handle, uint8_t event, uint16_t result,
+ BD_ADDR peer_addr);
+
+/* Message callback function */
+/* p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE */
+typedef void(tAVCT_MSG_CBACK)(uint8_t handle, uint8_t label, uint8_t cr,
+ BT_HDR* p_pkt);
+
+/* Structure used by AVCT_CreateConn. */
+typedef struct {
+ tAVCT_CTRL_CBACK* p_ctrl_cback; /* Control callback */
+ tAVCT_MSG_CBACK* p_msg_cback; /* Message callback */
+ uint16_t pid; /* Profile ID */
+ uint8_t role; /* Initiator/acceptor role */
+ uint8_t control; /* Control role (Control/Target) */
+} tAVCT_CC;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function AVCT_Register
+ *
+ * Description This is the system level registration function for the
+ * AVCTP protocol. This function initializes AVCTP and
+ * prepares the protocol stack for its use. This function
+ * must be called once by the system or platform using AVCTP
+ * before the other functions of the API an be used.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVCT_Register(uint16_t mtu, uint16_t mtu_br, uint8_t sec_mask);
+
+/*******************************************************************************
+ *
+ * Function AVCT_Deregister
+ *
+ * Description This function is called to deregister use AVCTP protocol.
+ * It is called when AVCTP is no longer being used by any
+ * application in the system. Before this function can be
+ * called, all connections must be removed with
+ * AVCT_RemoveConn().
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVCT_Deregister(void);
+
+/*******************************************************************************
+ *
+ * Function AVCT_CreateConn
+ *
+ * Description Create an AVCTP connection. There are two types of
+ * connections, initiator and acceptor, as determined by
+ * the p_cc->role parameter. When this function is called to
+ * create an initiator connection, an AVCTP connection to
+ * the peer device is initiated if one does not already exist.
+ * If an acceptor connection is created, the connection waits
+ * passively for an incoming AVCTP connection from a peer
+ * device.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_CreateConn(uint8_t* p_handle, tAVCT_CC* p_cc,
+ BD_ADDR peer_addr);
+
+/*******************************************************************************
+ *
+ * Function AVCT_RemoveConn
+ *
+ * Description Remove an AVCTP connection. This function is called when
+ * the application is no longer using a connection. If this
+ * is the last connection to a peer the L2CAP channel for AVCTP
+ * will be closed.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_RemoveConn(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVCT_CreateBrowse
+ *
+ * Description Create an AVCTP connection. There are two types of
+ * connections, initiator and acceptor, as determined by
+ * the p_cc->role parameter. When this function is called to
+ * create an initiator connection, an AVCTP connection to
+ * the peer device is initiated if one does not already exist.
+ * If an acceptor connection is created, the connection waits
+ * passively for an incoming AVCTP connection from a peer
+ * device.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_CreateBrowse(uint8_t handle, uint8_t role);
+
+/*******************************************************************************
+ *
+ * Function AVCT_RemoveBrowse
+ *
+ * Description Remove an AVCTP connection. This function is called when
+ * the application is no longer using a connection. If this
+ * is the last connection to a peer the L2CAP channel for AVCTP
+ * will be closed.
+ *
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_RemoveBrowse(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVCT_GetBrowseMtu
+ *
+ * Description Get the peer_mtu for the AVCTP Browse channel of the given
+ * connection.
+ *
+ * Returns the peer browsing channel MTU.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_GetBrowseMtu(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVCT_GetPeerMtu
+ *
+ * Description Get the peer_mtu for the AVCTP channel of the given
+ * connection.
+ *
+ * Returns the peer MTU size.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_GetPeerMtu(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVCT_MsgReq
+ *
+ * Description Send an AVCTP message to a peer device. In calling
+ * AVCT_MsgReq(), the application should keep track of the
+ * congestion state of AVCTP as communicated with events
+ * AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
+ * application calls AVCT_MsgReq() when AVCTP is congested
+ * the message may be discarded. The application may make its
+ * first call to AVCT_MsgReq() after it receives an
+ * AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control
+ * channel or
+ * AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on
+ * browsing channel.
+ *
+ * p_msg->layer_specific must be set to
+ * AVCT_DATA_CTRL for control channel traffic;
+ * AVCT_DATA_BROWSE for for browse channel traffic.
+ *
+ * Returns AVCT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVCT_MsgReq(uint8_t handle, uint8_t label, uint8_t cr,
+ BT_HDR* p_msg);
+
+#endif /* AVCT_API_H */
diff --git a/mtkbt/code/bt/stack/include/avdt_api.h b/mtkbt/code/bt/stack/include/avdt_api.h
new file mode 100755
index 0000000..53f7064
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/avdt_api.h
@@ -0,0 +1,937 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This interface file contains the interface to the Audio Video
+ * Distribution Transport Protocol (AVDTP).
+ *
+ ******************************************************************************/
+#ifndef AVDT_API_H
+#define AVDT_API_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+#ifndef AVDT_VERSION
+#define AVDT_VERSION 0x0102
+#endif
+#define AVDT_VERSION_SYNC 0x0103
+
+/* Maximum size in bytes of the codec capabilities information element. */
+#define AVDT_CODEC_SIZE 20
+
+/* API function return value result codes. */
+#define AVDT_SUCCESS 0 /* Function successful */
+#define AVDT_BAD_PARAMS 1 /* Invalid parameters */
+#define AVDT_NO_RESOURCES 2 /* Not enough resources */
+#define AVDT_BAD_HANDLE 3 /* Bad handle */
+#define AVDT_BUSY 4 /* A procedure is already in progress */
+#define AVDT_WRITE_FAIL 5 /* Write failed */
+
+/* The index to access the codec type in codec_info[]. */
+#define AVDT_CODEC_TYPE_INDEX 2
+
+/* The size in bytes of a Adaptation Layer header. */
+#define AVDT_AL_HDR_SIZE 3
+
+/* The size in bytes of a media packet header. */
+#define AVDT_MEDIA_HDR_SIZE 12
+
+/* The handle is used when reporting MULTI_AV specific events */
+#define AVDT_MULTI_AV_HANDLE 0xFF
+
+/* The number of bytes needed by the protocol stack for the protocol headers
+ * of a media packet. This is the size of the media packet header, the
+ * L2CAP packet header and HCI header.
+*/
+#define AVDT_MEDIA_OFFSET 23
+
+/* The marker bit is used by the application to mark significant events such
+ * as frame boundaries in the data stream. This constant is used to check or
+ * set the marker bit in the m_pt parameter of an AVDT_WriteReq()
+ * or AVDT_DATA_IND_EVT.
+*/
+#define AVDT_MARKER_SET 0x80
+
+/* SEP Type. This indicates the stream endpoint type. */
+#define AVDT_TSEP_SRC 0 /* Source SEP */
+#define AVDT_TSEP_SNK 1 /* Sink SEP */
+#define AVDT_TSEP_INVALID 3 /* Invalid SEP */
+
+/* initiator/acceptor role for adaption */
+#define AVDT_INT 0 /* initiator */
+#define AVDT_ACP 1 /* acceptor */
+
+/* Media Type of the stream endpoint */
+/* The value does not include the reserved 4-bit LSBs field */
+#define AVDT_MEDIA_TYPE_AUDIO 0 /* Audio SEP */
+#define AVDT_MEDIA_TYPE_VIDEO 1 /* Video SEP */
+#define AVDT_MEDIA_TYPE_MULTI 2 /* Multimedia SEP */
+
+/* for reporting packets (packet types) */
+#define AVDT_RTCP_PT_SR 200 /* SR (Sender Report) */
+#define AVDT_RTCP_PT_RR 201 /* RR (Receiver Report) */
+#define AVDT_RTCP_PT_SDES 202 /* SDES (Source Description) */
+typedef uint8_t AVDT_REPORT_TYPE;
+
+#define AVDT_RTCP_SDES_CNAME 1 /* SDES item CNAME */
+#ifndef AVDT_MAX_CNAME_SIZE
+#define AVDT_MAX_CNAME_SIZE 28
+#endif
+
+/* Protocol service capabilities. This indicates the protocol service
+ * capabilities of a stream endpoint. This value is a mask.
+ * Multiple values can be combined with a bitwise OR.
+*/
+#define AVDT_PSC_TRANS (1 << 1) /* Media transport */
+#define AVDT_PSC_REPORT (1 << 2) /* Reporting */
+#define AVDT_PSC_RECOV (1 << 3) /* Recovery */
+#define AVDT_PSC_HDRCMP (1 << 5) /* Header compression */
+#define AVDT_PSC_MUX (1 << 6) /* Multiplexing */
+#define AVDT_PSC_DELAY_RPT (1 << 8) /* Delay Report */
+
+/* Recovery type. This indicates the recovery type. */
+#define AVDT_RECOV_RFC2733 1 /* RFC2733 recovery */
+
+/* Header compression capabilities. This indicates the header compression
+ * capabilities. This value is a mask. Multiple values can be combined
+ * with a bitwise OR.
+*/
+#define AVDT_HDRCMP_MEDIA (1 << 5) /* Available for media packets */
+#define AVDT_HDRCMP_RECOV (1 << 6) /* Available for recovery packets */
+#define AVDT_HDRCMP_BACKCH (1 << 7) /* Back channel supported */
+
+/* Multiplexing capabilities mask. */
+#define AVDT_MUX_FRAG (1 << 7) /* Allow Adaptation Layer Fragmentation */
+
+/* Application service category. This indicates the application
+ * service category.
+*/
+#define AVDT_ASC_PROTECT 4 /* Content protection */
+#define AVDT_ASC_CODEC 7 /* Codec */
+
+/* the content protection IDs assigned by BT SIG */
+#define AVDT_CP_SCMS_T_ID 0x0002
+#define AVDT_CP_DTCP_ID 0x0001
+
+#define AVDT_CP_LOSC 2
+#define AVDT_CP_INFO_LEN 3
+
+#define AVDT_CP_SCMS_COPY_MASK 3
+#define AVDT_CP_SCMS_COPY_FREE 2
+#define AVDT_CP_SCMS_COPY_ONCE 1
+#define AVDT_CP_SCMS_COPY_NEVER 0
+
+/* Error codes. The following are error codes defined in the AVDTP and GAVDP
+ * specifications. These error codes communicate protocol errors between
+ * AVDTP and the application. More detailed descriptions of the error codes
+ * and their appropriate use can be found in the AVDTP and GAVDP specifications.
+ * These error codes are unrelated to the result values returned by the
+ * AVDTP API functions.
+*/
+/* Bad packet header format */
+#define AVDT_ERR_HEADER 0x01
+/* Bad packet length */
+#define AVDT_ERR_LENGTH 0x11
+/* Invalid SEID */
+#define AVDT_ERR_SEID 0x12
+/* The SEP is in use */
+#define AVDT_ERR_IN_USE 0x13
+/* The SEP is not in use */
+#define AVDT_ERR_NOT_IN_USE 0x14
+/* Bad service category */
+#define AVDT_ERR_CATEGORY 0x17
+/* Bad payload format */
+#define AVDT_ERR_PAYLOAD 0x18
+/* Requested command not supported */
+#define AVDT_ERR_NSC 0x19
+/* Reconfigure attempted invalid capabilities */
+#define AVDT_ERR_INVALID_CAP 0x1A
+/* Requested recovery type not defined */
+#define AVDT_ERR_RECOV_TYPE 0x22
+/* Media transport capability not correct */
+#define AVDT_ERR_MEDIA_TRANS 0x23
+/* Recovery service capability not correct */
+#define AVDT_ERR_RECOV_FMT 0x25
+/* Header compression service capability not correct */
+#define AVDT_ERR_ROHC_FMT 0x26
+/* Content protection service capability not correct */
+#define AVDT_ERR_CP_FMT 0x27
+/* Multiplexing service capability not correct */
+#define AVDT_ERR_MUX_FMT 0x28
+/* Configuration not supported */
+#define AVDT_ERR_UNSUP_CFG 0x29
+/* Message cannot be processed in this state */
+#define AVDT_ERR_BAD_STATE 0x31
+/* Report service capability not correct */
+#define AVDT_ERR_REPORT_FMT 0x65
+/* Invalid service category */
+#define AVDT_ERR_SERVICE 0x80
+/* Insufficient resources */
+#define AVDT_ERR_RESOURCE 0x81
+/* Invalid Media Codec Type */
+#define AVDT_ERR_INVALID_MCT 0xC1
+/* Unsupported Media Codec Type */
+#define AVDT_ERR_UNSUP_MCT 0xC2
+/* Invalid Level */
+#define AVDT_ERR_INVALID_LEVEL 0xC3
+/* Unsupported Level */
+#define AVDT_ERR_UNSUP_LEVEL 0xC4
+/* Invalid Content Protection Type */
+#define AVDT_ERR_INVALID_CP 0xE0
+/* Invalid Content Protection format */
+#define AVDT_ERR_INVALID_FORMAT 0xE1
+
+/* Additional error codes. This indicates error codes used by AVDTP
+ * in addition to the ones defined in the specifications.
+*/
+#define AVDT_ERR_CONNECT 0x07 /* Connection failed. */
+#define AVDT_ERR_TIMEOUT 0x08 /* Response timeout. */
+
+/* Control callback events. */
+#define AVDT_DISCOVER_CFM_EVT 0 /* Discover confirm */
+#define AVDT_GETCAP_CFM_EVT 1 /* Get capabilities confirm */
+#define AVDT_OPEN_CFM_EVT 2 /* Open confirm */
+#define AVDT_OPEN_IND_EVT 3 /* Open indication */
+#define AVDT_CONFIG_IND_EVT 4 /* Configuration indication */
+#define AVDT_START_CFM_EVT 5 /* Start confirm */
+#define AVDT_START_IND_EVT 6 /* Start indication */
+#define AVDT_SUSPEND_CFM_EVT 7 /* Suspend confirm */
+#define AVDT_SUSPEND_IND_EVT 8 /* Suspend indication */
+#define AVDT_CLOSE_CFM_EVT 9 /* Close confirm */
+#define AVDT_CLOSE_IND_EVT 10 /* Close indication */
+#define AVDT_RECONFIG_CFM_EVT 11 /* Reconfiguration confirm */
+#define AVDT_RECONFIG_IND_EVT 12 /* Reconfiguration indication */
+#define AVDT_SECURITY_CFM_EVT 13 /* Security confirm */
+#define AVDT_SECURITY_IND_EVT 14 /* Security indication */
+#define AVDT_WRITE_CFM_EVT 15 /* Write confirm */
+#define AVDT_CONNECT_IND_EVT 16 /* Signaling channel connected */
+#define AVDT_DISCONNECT_IND_EVT 17 /* Signaling channel disconnected */
+#define AVDT_REPORT_CONN_EVT 18 /* Reporting channel connected */
+#define AVDT_REPORT_DISCONN_EVT 19 /* Reporting channel disconnected */
+#define AVDT_DELAY_REPORT_EVT 20 /* Delay report received */
+#define AVDT_DELAY_REPORT_CFM_EVT 21 /* Delay report response received */
+
+#define AVDT_MAX_EVT (AVDT_DELAY_REPORT_CFM_EVT)
+
+/* PSM for AVDT */
+#define AVDT_PSM 0x0019
+
+/* Nonsupported protocol command messages. This value is used in tAVDT_CS */
+#define AVDT_NSC_SUSPEND 0x01 /* Suspend command not supported */
+#define AVDT_NSC_RECONFIG 0x02 /* Reconfigure command not supported */
+#define AVDT_NSC_SECURITY 0x04 /* Security command not supported */
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+typedef struct {
+ uint32_t ntp_sec; /* NTP time: seconds relative to 0h UTC on 1 January 1900 */
+ uint32_t ntp_frac; /* NTP time: the fractional part */
+ uint32_t rtp_time; /* timestamp in RTP header */
+ uint32_t pkt_count; /* sender's packet count: since starting transmission
+ * up until the time this SR packet was generated. */
+ uint32_t octet_count; /* sender's octet count: same comment */
+} tAVDT_SENDER_INFO;
+
+typedef struct {
+ uint8_t frag_lost; /* fraction lost since last RR */
+ uint32_t
+ packet_lost; /* cumulative number of packets lost since the beginning */
+ uint32_t seq_num_rcvd; /* extended highest sequence number received */
+ uint32_t jitter; /* interarrival jitter */
+ uint32_t lsr; /* last SR timestamp */
+ uint32_t dlsr; /* delay since last SR */
+} tAVDT_REPORT_BLK;
+
+typedef union {
+ tAVDT_SENDER_INFO sr;
+ tAVDT_REPORT_BLK rr;
+ uint8_t cname[AVDT_MAX_CNAME_SIZE + 1];
+} tAVDT_REPORT_DATA;
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+ uint16_t ctrl_mtu; /* L2CAP MTU of the AVDTP signaling channel */
+ uint8_t ret_tout; /* AVDTP signaling retransmission timeout */
+ uint8_t sig_tout; /* AVDTP signaling message timeout */
+ uint8_t idle_tout; /* AVDTP idle signaling channel timeout */
+ uint8_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+} tAVDT_REG;
+
+/* This structure contains the SEP information. This information is
+ * transferred during the discovery procedure.
+*/
+typedef struct {
+ bool in_use; /* true if stream is currently in use */
+ uint8_t seid; /* Stream endpoint identifier */
+ uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
+ uint8_t tsep; /* SEP type */
+} tAVDT_SEP_INFO;
+
+/* This structure contains the SEP configuration. */
+typedef struct {
+ uint8_t codec_info[AVDT_CODEC_SIZE]; /* Codec capabilities array */
+ uint8_t protect_info[AVDT_PROTECT_SIZE]; /* Content protection capabilities */
+ uint8_t num_codec; /* Number of media codec information elements */
+ uint8_t num_protect; /* Number of content protection information elements */
+ uint16_t psc_mask; /* Protocol service capabilities mask */
+ uint8_t recov_type; /* Recovery type */
+ uint8_t recov_mrws; /* Maximum recovery window size */
+ uint8_t recov_mnmp; /* Recovery maximum number of media packets */
+ uint8_t hdrcmp_mask; /* Header compression capabilities */
+} tAVDT_CFG;
+
+/* Header structure for callback event parameters. */
+typedef struct {
+ uint8_t
+ err_code; /* Zero if operation succeeded; nonzero if operation failed */
+ uint8_t err_param; /* Error parameter included for some events */
+ uint8_t label; /* Transaction label */
+ uint8_t seid; /* For internal use only */
+ uint8_t sig_id; /* For internal use only */
+ uint8_t ccb_idx; /* For internal use only */
+} tAVDT_EVT_HDR;
+
+/* This data structure is associated with the AVDT_GETCAP_CFM_EVT,
+ * AVDT_RECONFIG_IND_EVT, and AVDT_RECONFIG_CFM_EVT.
+*/
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_CFG* p_cfg; /* Pointer to configuration for this SEP */
+} tAVDT_CONFIG;
+
+/* This data structure is associated with the AVDT_CONFIG_IND_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_CFG* p_cfg; /* Pointer to configuration for this SEP */
+ uint8_t int_seid; /* Stream endpoint ID of stream initiating the operation */
+} tAVDT_SETCONFIG;
+
+/* This data structure is associated with the AVDT_OPEN_IND_EVT and
+ * AVDT_OPEN_CFM_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ uint16_t peer_mtu; /* Transport channel L2CAP MTU of the peer */
+ uint16_t lcid; /* L2CAP LCID for media channel */
+} tAVDT_OPEN;
+
+/* This data structure is associated with the AVDT_SECURITY_IND_EVT
+ * and AVDT_SECURITY_CFM_EVT.
+*/
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ uint8_t* p_data; /* Pointer to security data */
+ uint16_t len; /* Length in bytes of the security data */
+} tAVDT_SECURITY;
+
+/* This data structure is associated with the AVDT_DISCOVER_CFM_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ tAVDT_SEP_INFO* p_sep_info; /* Pointer to SEP information */
+ uint8_t num_seps; /* Number of stream endpoints */
+} tAVDT_DISCOVER;
+
+/* This data structure is associated with the AVDT_DELAY_REPORT_EVT. */
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ uint16_t delay; /* Delay value */
+} tAVDT_DELAY_RPT;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_DISCOVER discover_cfm;
+ tAVDT_CONFIG getcap_cfm;
+ tAVDT_OPEN open_cfm;
+ tAVDT_OPEN open_ind;
+ tAVDT_SETCONFIG config_ind;
+ tAVDT_EVT_HDR start_cfm;
+ tAVDT_EVT_HDR suspend_cfm;
+ tAVDT_EVT_HDR close_cfm;
+ tAVDT_CONFIG reconfig_cfm;
+ tAVDT_CONFIG reconfig_ind;
+ tAVDT_SECURITY security_cfm;
+ tAVDT_SECURITY security_ind;
+ tAVDT_EVT_HDR connect_ind;
+ tAVDT_EVT_HDR disconnect_ind;
+ tAVDT_EVT_HDR report_conn;
+ tAVDT_DELAY_RPT delay_rpt_cmd;
+} tAVDT_CTRL;
+
+/* This is the control callback function. This function passes control events
+ * to the application. This function is required for all registered stream
+ * endpoints and for the AVDT_DiscoverReq() and AVDT_GetCapReq() functions.
+ *
+*/
+typedef void(tAVDT_CTRL_CBACK)(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDT_CTRL* p_data);
+
+/* This is the data callback function. It is executed when AVDTP has a media
+ * packet ready for the application. This function is required for SNK
+ * endpoints and not applicable for SRC endpoints.
+*/
+typedef void(tAVDT_SINK_DATA_CBACK)(uint8_t handle, BT_HDR* p_pkt,
+ uint32_t time_stamp, uint8_t m_pt);
+
+#if (AVDT_REPORTING == TRUE)
+/* This is the report callback function. It is executed when AVDTP has a
+ * reporting packet ready for the application. This function is required for
+ * streams created with AVDT_PSC_REPORT.
+*/
+typedef void(tAVDT_REPORT_CBACK)(uint8_t handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA* p_data);
+#endif
+
+typedef uint16_t(tAVDT_GETCAP_REQ)(BD_ADDR bd_addr, uint8_t seid,
+ tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback);
+
+/* This structure contains information required when a stream is created.
+ * It is passed to the AVDT_CreateStream() function.
+*/
+typedef struct {
+ tAVDT_CFG cfg; /* SEP configuration */
+ tAVDT_CTRL_CBACK* p_ctrl_cback; /* Control callback function */
+ tAVDT_SINK_DATA_CBACK* p_sink_data_cback; /* Sink data callback function */
+#if (AVDT_REPORTING == TRUE)
+ tAVDT_REPORT_CBACK* p_report_cback; /* Report callback function. */
+#endif
+ uint16_t mtu; /* The L2CAP MTU of the transport channel */
+ uint16_t flush_to; /* The L2CAP flush timeout of the transport channel */
+ uint8_t tsep; /* SEP type */
+ uint8_t media_type; /* Media type: AVDT_MEDIA_TYPE_* */
+ uint16_t nsc_mask; /* Nonsupported protocol command messages */
+} tAVDT_CS;
+
+/* AVDT data option mask is used in the write request */
+#define AVDT_DATA_OPT_NONE 0x00 /* No option still add RTP header */
+#define AVDT_DATA_OPT_NO_RTP (0x01 << 0) /* Skip adding RTP header */
+
+typedef uint8_t tAVDT_DATA_OPT_MASK;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function AVDT_Register
+ *
+ * Description This is the system level registration function for the
+ * AVDTP protocol. This function initializes AVDTP and
+ * prepares the protocol stack for its use. This function
+ * must be called once by the system or platform using AVDTP
+ * before the other functions of the API an be used.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDT_Register(tAVDT_REG* p_reg, tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_Deregister
+ *
+ * Description This function is called to deregister use AVDTP protocol.
+ * It is called when AVDTP is no longer being used by any
+ * application in the system. Before this function can be
+ * called, all streams must be removed with AVDT_RemoveStream.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDT_Deregister(void);
+
+/*******************************************************************************
+ *
+ * Function AVDT_AbortReq
+ *
+ * Description Trigger Abort request to pass AVDTP Abort related mandatory
+ * PTS Test case.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+extern void AVDT_AbortReq(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDT_CreateStream
+ *
+ * Description Create a stream endpoint. After a stream endpoint is
+ * created an application can initiate a connection between
+ * this endpoint and an endpoint on a peer device. In
+ * addition, a peer device can discover, get the capabilities,
+ * and connect to this endpoint.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_CreateStream(uint8_t* p_handle, tAVDT_CS* p_cs);
+
+/*******************************************************************************
+ *
+ * Function AVDT_RemoveStream
+ *
+ * Description Remove a stream endpoint. This function is called when
+ * the application is no longer using a stream endpoint.
+ * If this function is called when the endpoint is connected
+ * the connection is closed and then the stream endpoint
+ * is removed.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_RemoveStream(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDT_DiscoverReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and discovers
+ * the stream endpoints on the peer device. (Please note
+ * that AVDTP discovery is unrelated to SDP discovery).
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When discovery is complete, an AVDT_DISCOVER_CFM_EVT
+ * is sent to the application via its callback function.
+ * The application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again to the same device until
+ * discovery is complete.
+ *
+ * The memory addressed by sep_info is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the discovery procedure. This memory must remain
+ * accessible until the application receives the
+ * AVDT_DISCOVER_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO* p_sep_info,
+ uint8_t max_seps, tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetCapReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and gets the
+ * capabilities of a stream endpoint on the peer device.
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+ * sent to the application via its callback function. The
+ * application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again until the procedure is complete.
+ *
+ * The memory pointed to by p_cfg is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the get capabilities procedure. This memory must
+ * remain accessible until the application receives
+ * the AVDT_GETCAP_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_GetCapReq(BD_ADDR bd_addr, uint8_t seid, tAVDT_CFG* p_cfg,
+ tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetAllCapReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and gets the
+ * capabilities of a stream endpoint on the peer device.
+ * This function can be called at any time regardless of
+ * whether there is an AVDTP connection to the peer device.
+ *
+ * When the procedure is complete, an AVDT_GETCAP_CFM_EVT is
+ * sent to the application via its callback function. The
+ * application must not call AVDT_GetCapReq() or
+ * AVDT_DiscoverReq() again until the procedure is complete.
+ *
+ * The memory pointed to by p_cfg is allocated by the
+ * application. This memory is written to by AVDTP as part
+ * of the get capabilities procedure. This memory must
+ * remain accessible until the application receives
+ * the AVDT_GETCAP_CFM_EVT.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_GetAllCapReq(BD_ADDR bd_addr, uint8_t seid,
+ tAVDT_CFG* p_cfg, tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_DelayReport
+ *
+ * Description This functions sends a Delay Report to the peer device
+ * that is associated with a particular SEID.
+ * This function is called by SNK device.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_DelayReport(uint8_t handle, uint8_t seid, uint16_t delay);
+
+/*******************************************************************************
+ *
+ * Function AVDT_OpenReq
+ *
+ * Description This function initiates a connection to the AVDTP service
+ * on the peer device, if not already present, and connects
+ * to a stream endpoint on a peer device. When the connection
+ * is completed, an AVDT_OPEN_CFM_EVT is sent to the
+ * application via the control callback function for this
+ * handle.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_OpenReq(uint8_t handle, BD_ADDR bd_addr, uint8_t seid,
+ tAVDT_CFG* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function AVDT_ConfigRsp
+ *
+ * Description Respond to a configure request from the peer device. This
+ * function must be called if the application receives an
+ * AVDT_CONFIG_IND_EVT through its control callback.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_ConfigRsp(uint8_t handle, uint8_t label,
+ uint8_t error_code, uint8_t category);
+
+/*******************************************************************************
+ *
+ * Function AVDT_StartReq
+ *
+ * Description Start one or more stream endpoints. This initiates the
+ * transfer of media packets for the streams. All stream
+ * endpoints must previously be opened. When the streams
+ * are started, an AVDT_START_CFM_EVT is sent to the
+ * application via the control callback function for each
+ * stream.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_StartReq(uint8_t* p_handles, uint8_t num_handles);
+
+/*******************************************************************************
+ *
+ * Function AVDT_SuspendReq
+ *
+ * Description Suspend one or more stream endpoints. This suspends the
+ * transfer of media packets for the streams. All stream
+ * endpoints must previously be open and started. When the
+ * streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to
+ * the application via the control callback function for
+ * each stream.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_SuspendReq(uint8_t* p_handles, uint8_t num_handles);
+
+/*******************************************************************************
+ *
+ * Function AVDT_CloseReq
+ *
+ * Description Close a stream endpoint. This stops the transfer of media
+ * packets and closes the transport channel associated with
+ * this stream endpoint. When the stream is closed, an
+ * AVDT_CLOSE_CFM_EVT is sent to the application via the
+ * control callback function for this handle.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_CloseReq(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDT_ReconfigReq
+ *
+ * Description Reconfigure a stream endpoint. This allows the application
+ * to change the codec or content protection capabilities of
+ * a stream endpoint after it has been opened. This function
+ * can only be called if the stream is opened but not started
+ * or if the stream has been suspended. When the procedure
+ * is completed, an AVDT_RECONFIG_CFM_EVT is sent to the
+ * application via the control callback function for this
+ * handle.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_ReconfigReq(uint8_t handle, tAVDT_CFG* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function AVDT_ReconfigRsp
+ *
+ * Description Respond to a reconfigure request from the peer device.
+ * This function must be called if the application receives
+ * an AVDT_RECONFIG_IND_EVT through its control callback.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_ReconfigRsp(uint8_t handle, uint8_t label,
+ uint8_t error_code, uint8_t category);
+
+/*******************************************************************************
+ *
+ * Function AVDT_SecurityReq
+ *
+ * Description Send a security request to the peer device. When the
+ * security procedure is completed, an AVDT_SECURITY_CFM_EVT
+ * is sent to the application via the control callback function
+ * for this handle. (Please note that AVDTP security
+ * procedures are unrelated to Bluetooth link level security.)
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_SecurityReq(uint8_t handle, uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function AVDT_SecurityRsp
+ *
+ * Description Respond to a security request from the peer device.
+ * This function must be called if the application receives
+ * an AVDT_SECURITY_IND_EVT through its control callback.
+ * (Please note that AVDTP security procedures are unrelated
+ * to Bluetooth link level security.)
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_SecurityRsp(uint8_t handle, uint8_t label,
+ uint8_t error_code, uint8_t* p_data,
+ uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function AVDT_WriteReq
+ *
+ * Description Send a media packet to the peer device. The stream must
+ * be started before this function is called. Also, this
+ * function can only be called if the stream is a SRC.
+ *
+ * When AVDTP has sent the media packet and is ready for the
+ * next packet, an AVDT_WRITE_CFM_EVT is sent to the
+ * application via the control callback. The application must
+ * wait for the AVDT_WRITE_CFM_EVT before it makes the next
+ * call to AVDT_WriteReq(). If the applications calls
+ * AVDT_WriteReq() before it receives the event the packet
+ * will not be sent. The application may make its first call
+ * to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+ * or AVDT_START_IND_EVT.
+ *
+ * The application passes the packet using the BT_HDR
+ * structure.
+ * This structure is described in section 2.1. The offset
+ * field must be equal to or greater than AVDT_MEDIA_OFFSET.
+ * This allows enough space in the buffer for the L2CAP and
+ * AVDTP headers.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_WriteReq(uint8_t handle, BT_HDR* p_pkt,
+ uint32_t time_stamp, uint8_t m_pt);
+/*******************************************************************************
+ *
+ * Function AVDT_WriteReqOpt
+ *
+ * Description Send a media packet to the peer device. The stream must
+ * be started before this function is called. Also, this
+ * function can only be called if the stream is a SRC
+ *
+ * When AVDTP has sent the media packet and is ready for the
+ * next packet, an AVDT_WRITE_CFM_EVT is sent to the
+ * application via the control callback. The application must
+ * wait for the AVDT_WRITE_CFM_EVT before it makes the next
+ * call to AVDT_WriteReq(). If the applications calls
+ * AVDT_WriteReq() before it receives the event the packet
+ * will not be sent. The application may make its first call
+ * to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT
+ * or AVDT_START_IND_EVT.
+ *
+ * The application passes the packet using the BT_HDR structure
+ * This structure is described in section 2.1. The offset
+ * field must be equal to or greater than AVDT_MEDIA_OFFSET
+ * (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used)
+ * This allows enough space in the buffer for the L2CAP and
+ * AVDTP headers.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ * The opt parameter allows passing specific options like:
+ * - NO_RTP : do not add the RTP header to buffer
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_WriteReqOpt(uint8_t handle, BT_HDR* p_pkt,
+ uint32_t time_stamp, uint8_t m_pt,
+ tAVDT_DATA_OPT_MASK opt);
+
+/*******************************************************************************
+ *
+ * Function AVDT_ConnectReq
+ *
+ * Description This function initiates an AVDTP signaling connection
+ * to the peer device. When the connection is completed, an
+ * AVDT_CONNECT_IND_EVT is sent to the application via its
+ * control callback function. If the connection attempt fails
+ * an AVDT_DISCONNECT_IND_EVT is sent. The security mask
+ * parameter overrides the outgoing security mask set in
+ * AVDT_Register().
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_ConnectReq(BD_ADDR bd_addr, uint8_t sec_mask,
+ tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_DisconnectReq
+ *
+ * Description This function disconnect an AVDTP signaling connection
+ * to the peer device. When disconnected an
+ * AVDT_DISCONNECT_IND_EVT is sent to the application via its
+ * control callback function.
+ *
+ * Returns AVDT_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetL2CapChannel
+ *
+ * Description Get the L2CAP CID used by the handle.
+ *
+ * Returns CID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_GetL2CapChannel(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDT_GetSignalChannel
+ *
+ * Description Get the L2CAP CID used by the signal channel of the given
+ * handle.
+ *
+ * Returns CID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_GetSignalChannel(uint8_t handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function AVDT_SendReport
+ *
+ * Description
+ *
+ *
+ *
+ * Returns
+ *
+ ******************************************************************************/
+extern uint16_t AVDT_SendReport(uint8_t handle, AVDT_REPORT_TYPE type,
+ tAVDT_REPORT_DATA* p_data);
+
+/******************************************************************************
+ *
+ * Function AVDT_SetTraceLevel
+ *
+ * Description Sets the trace level for AVDT. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the AVDT tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+extern uint8_t AVDT_SetTraceLevel(uint8_t new_level);
+
+/** M: Bug fix for not disconnect signal channel @{ */
+/*******************************************************************************
+**
+** Function AVDT_ULCloseReq
+**
+** Description This function to trigger ccb checks for active streams on this CCB
+**
+** Returns AVDT_SUCCESS if successful, otherwise error.
+**
+*******************************************************************************/
+extern uint16_t AVDT_ULCloseReq(BD_ADDR bd_addr);
+/** @} */
+
+#endif /* AVDT_API_H */
diff --git a/mtkbt/code/bt/stack/include/avdtc_api.h b/mtkbt/code/bt/stack/include/avdtc_api.h
new file mode 100755
index 0000000..6009a8c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/avdtc_api.h
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This interface file contains the interface AVDTP conformance API. These
+ * additional API functions and callback events are provided for
+ * conformance testing purposes only. They are not intended to be used by
+ * an application.
+ *
+ ******************************************************************************/
+#ifndef AVDT_CAPI_H
+#define AVDT_CAPI_H
+
+#include "avdt_api.h"
+
+/* start AVDTC events here to distinguish from AVDT events */
+#define AVDTC_EVT_BEGIN 0x80
+
+/* Discover indication */
+#define AVDTC_DISCOVER_IND_EVT (0 + AVDTC_EVT_BEGIN)
+/* Get capabilities indication */
+#define AVDTC_GETCAP_IND_EVT (1 + AVDTC_EVT_BEGIN)
+/* Set configuration confirm */
+#define AVDTC_SETCONFIG_CFM_EVT (2 + AVDTC_EVT_BEGIN)
+/* Get configuration indication */
+#define AVDTC_GETCONFIG_IND_EVT (3 + AVDTC_EVT_BEGIN)
+/* Get configuration confirm */
+#define AVDTC_GETCONFIG_CFM_EVT (4 + AVDTC_EVT_BEGIN)
+/* Open indication */
+#define AVDTC_OPEN_IND_EVT (5 + AVDTC_EVT_BEGIN)
+/* Start indication */
+#define AVDTC_START_IND_EVT (6 + AVDTC_EVT_BEGIN)
+/* Close indication */
+#define AVDTC_CLOSE_IND_EVT (7 + AVDTC_EVT_BEGIN)
+/* Suspend indication */
+#define AVDTC_SUSPEND_IND_EVT (8 + AVDTC_EVT_BEGIN)
+/* Abort indication */
+#define AVDTC_ABORT_IND_EVT (9 + AVDTC_EVT_BEGIN)
+/* Abort confirm */
+#define AVDTC_ABORT_CFM_EVT (10 + AVDTC_EVT_BEGIN)
+
+typedef struct {
+ tAVDT_EVT_HDR hdr; /* Event header */
+ uint8_t seid_list[AVDT_NUM_SEPS]; /* Array of SEID values */
+ uint8_t num_seps; /* Number of values in array */
+} tAVDT_MULTI;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tAVDT_EVT_HDR hdr;
+ tAVDT_CONFIG getconfig_cfm;
+ tAVDT_MULTI start_ind;
+ tAVDT_MULTI suspend_ind;
+} tAVDTC_CTRL;
+
+typedef void tAVDTC_CTRL_CBACK(uint8_t handle, BD_ADDR bd_addr, uint8_t event,
+ tAVDTC_CTRL* p_data);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_Init
+ *
+ * Description This function is called to begin using the conformance API.
+ * It must be called after AVDT_Register() and before any
+ * other API or conformance API functions are called.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_Init(tAVDTC_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_DiscoverRsp
+ *
+ * Description Send a discover response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_DiscoverRsp(BD_ADDR bd_addr, uint8_t label,
+ tAVDT_SEP_INFO sep_info[], uint8_t num_seps);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_GetCapRsp
+ *
+ * Description Send a get capabilities response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_GetCapRsp(BD_ADDR bd_addr, uint8_t label, tAVDT_CFG* p_cap);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_GetAllCapRsp
+ *
+ * Description Send a get all capabilities response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_GetAllCapRsp(BD_ADDR bd_addr, uint8_t label,
+ tAVDT_CFG* p_cap);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_GetConfigReq
+ *
+ * Description Send a get configuration request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_GetConfigReq(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_GetConfigRsp
+ *
+ * Description Send a get configuration response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_GetConfigRsp(uint8_t handle, uint8_t label, tAVDT_CFG* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_OpenReq
+ *
+ * Description Send an open request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_OpenReq(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_OpenRsp
+ *
+ * Description Send an open response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_OpenRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_StartRsp
+ *
+ * Description Send a start response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_StartRsp(uint8_t* p_handles, uint8_t num_handles,
+ uint8_t label);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_CloseRsp
+ *
+ * Description Send a close response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_CloseRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_SuspendRsp
+ *
+ * Description Send a suspend response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_SuspendRsp(uint8_t* p_handles, uint8_t num_handles,
+ uint8_t label);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_AbortReq
+ *
+ * Description Send an abort request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_AbortReq(uint8_t handle);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_AbortRsp
+ *
+ * Description Send an abort response.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_AbortRsp(uint8_t handle, uint8_t label);
+
+/*******************************************************************************
+ *
+ * Function AVDTC_Rej
+ *
+ * Description Send a reject message.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVDTC_Rej(uint8_t handle, BD_ADDR bd_addr, uint8_t cmd,
+ uint8_t label, uint8_t err_code, uint8_t err_param);
+
+#endif /* AVDT_CAPI_H */
diff --git a/mtkbt/code/bt/stack/include/avrc_api.h b/mtkbt/code/bt/stack/include/avrc_api.h
new file mode 100755
index 0000000..010815d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/avrc_api.h
@@ -0,0 +1,717 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * nterface to AVRCP Application Programming Interface
+ *
+ ******************************************************************************/
+#ifndef AVRC_API_H
+#define AVRC_API_H
+#include "avct_api.h"
+#include "avrc_defs.h"
+#include "bt_target.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* API function return value result codes. */
+/* 0 Function successful */
+#define AVRC_SUCCESS AVCT_SUCCESS
+/* 1 Not enough resources */
+#define AVRC_NO_RESOURCES AVCT_NO_RESOURCES
+/* 2 Bad handle */
+#define AVRC_BAD_HANDLE AVCT_BAD_HANDLE
+/* 3 PID already in use */
+#define AVRC_PID_IN_USE AVCT_PID_IN_USE
+/* 4 Connection not open */
+#define AVRC_NOT_OPEN AVCT_NOT_OPEN
+/* 5 the message length exceed the MTU of the browsing channel */
+#define AVRC_MSG_TOO_BIG 5
+/* 0x10 generic failure */
+#define AVRC_FAIL 0x10
+/* 0x11 bad parameter */
+#define AVRC_BAD_PARAM 0x11
+
+/* Control role - same as AVCT_TARGET/AVCT_CONTROL */
+/* target */
+#define AVRC_CT_TARGET 1
+/* controller */
+#define AVRC_CT_CONTROL 2
+/* If conflict, allow the other side to succeed */
+#define AVRC_CT_PASSIVE 4
+
+/* Connection role */
+/* initiator */
+#define AVRC_CONN_INT AVCT_INT
+/* Acceptor */
+#define AVRC_CONN_ACP AVCT_ACP
+
+/* AVRC CTRL events */
+/* AVRC_OPEN_IND_EVT event is sent when the connection is successfully opened.
+ * This eventis sent in response to an AVRC_Open(). */
+#define AVRC_OPEN_IND_EVT 0
+
+/* AVRC_CLOSE_IND_EVT event is sent when a connection is closed.
+ * This event can result from a call to AVRC_Close() or when the peer closes
+ * the connection. It is also sent when a connection attempted through
+ * AVRC_Open() fails. */
+#define AVRC_CLOSE_IND_EVT 1
+
+/* AVRC_CONG_IND_EVT event indicates that AVCTP is congested and cannot send
+ * any more messages. */
+#define AVRC_CONG_IND_EVT 2
+
+/* AVRC_UNCONG_IND_EVT event indicates that AVCTP is uncongested and ready to
+ * send messages. */
+#define AVRC_UNCONG_IND_EVT 3
+
+/* AVRC_BROWSE_OPEN_IND_EVT event is sent when the browse channel is
+* successfully opened.
+* This eventis sent in response to an AVRC_Open() or AVRC_OpenBrowse() . */
+#define AVRC_BROWSE_OPEN_IND_EVT 4
+
+/* AVRC_BROWSE_CLOSE_IND_EVT event is sent when a browse channel is closed.
+ * This event can result from a call to AVRC_Close(), AVRC_CloseBrowse() or
+ * when the peer closes the connection. It is also sent when a connection
+ * attempted through AVRC_OpenBrowse() fails. */
+#define AVRC_BROWSE_CLOSE_IND_EVT 5
+
+/* AVRC_BROWSE_CONG_IND_EVT event indicates that AVCTP browse channel is
+ * congested and cannot send any more messages. */
+#define AVRC_BROWSE_CONG_IND_EVT 6
+
+/* AVRC_BROWSE_UNCONG_IND_EVT event indicates that AVCTP browse channel is
+ * uncongested and ready to send messages. */
+#define AVRC_BROWSE_UNCONG_IND_EVT 7
+
+/* AVRC_CMD_TIMEOUT_EVT event indicates timeout waiting for AVRC command
+ * response from the peer */
+#define AVRC_CMD_TIMEOUT_EVT 8
+
+/* Supported categories */
+#define AVRC_SUPF_CT_CAT1 0x0001 /* Category 1 */
+#define AVRC_SUPF_CT_CAT2 0x0002 /* Category 2 */
+#define AVRC_SUPF_CT_CAT3 0x0004 /* Category 3 */
+#define AVRC_SUPF_CT_CAT4 0x0008 /* Category 4 */
+#define AVRC_SUPF_CT_APP_SETTINGS 0x0010 /* Player Application Settings */
+#define AVRC_SUPF_CT_GROUP_NAVI 0x0020 /* Group Navigation */
+#define AVRC_SUPF_CT_BROWSE 0x0040 /* Browsing */
+
+/* Cover Art, get image property */
+#define AVRC_SUPF_CT_COVER_ART_GET_IMAGE_PROP 0x0080
+/* Cover Art, get image */
+#define AVRC_SUPF_CT_COVER_ART_GET_IMAGE 0x0100
+/* Cover Art, get Linked Thumbnail */
+#define AVRC_SUPF_CT_COVER_ART_GET_THUMBNAIL 0x0200
+
+#define AVRC_SUPF_TG_CAT1 0x0001 /* Category 1 */
+#define AVRC_SUPF_TG_CAT2 0x0002 /* Category 2 */
+#define AVRC_SUPF_TG_CAT3 0x0004 /* Category 3 */
+#define AVRC_SUPF_TG_CAT4 0x0008 /* Category 4 */
+#define AVRC_SUPF_TG_APP_SETTINGS 0x0010 /* Player Application Settings */
+#define AVRC_SUPF_TG_GROUP_NAVI 0x0020 /* Group Navigation */
+#define AVRC_SUPF_TG_BROWSE 0x0040 /* Browsing */
+#define AVRC_SUPF_TG_MULTI_PLAYER 0x0080 /* Muliple Media Player */
+#define AVRC_SUPF_TG_PLAYER_COVER_ART 0x0100 /* Cover Art */
+
+#define AVRC_META_SUCCESS AVRC_SUCCESS
+#define AVRC_META_FAIL AVRC_FAIL
+#define AVRC_METADATA_CMD 0x0000
+#define AVRC_METADATA_RESP 0x0001
+
+/*****************************************************************************
+ * data type definitions
+ ****************************************************************************/
+
+/* This data type is used in AVRC_FindService() to initialize the SDP database
+ * to hold the result service search. */
+typedef struct {
+ uint32_t db_len; /* Length, in bytes, of the discovery database */
+ tSDP_DISCOVERY_DB* p_db; /* Pointer to the discovery database */
+ uint16_t num_attr; /* The number of attributes in p_attrs */
+ uint16_t* p_attrs; /* The attributes filter. If NULL, AVRCP API sets the
+ * attribute filter
+ * to be ATTR_ID_SERVICE_CLASS_ID_LIST,
+ * ATTR_ID_BT_PROFILE_DESC_LIST,
+ * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and
+ * ATTR_ID_PROVIDER_NAME.
+ * If not NULL, the input is taken as the filter. */
+} tAVRC_SDP_DB_PARAMS;
+
+/* This callback function returns service discovery information to the
+ * application after the AVRC_FindService() API function is called. The
+ * implementation of this callback function must copy the p_service_name
+ * and p_provider_name parameters passed to it as they are not guaranteed
+ * to remain after the callback function exits. */
+typedef void(tAVRC_FIND_CBACK)(uint16_t status);
+
+/* This is the control callback function. This function passes events
+ * listed in Table 20 to the application. */
+typedef void(tAVRC_CTRL_CBACK)(uint8_t handle, uint8_t event, uint16_t result,
+ BD_ADDR peer_addr);
+
+/* This is the message callback function. It is executed when AVCTP has
+ * a message packet ready for the application. The implementation of this
+ * callback function must copy the tAVRC_MSG structure passed to it as it
+ * is not guaranteed to remain after the callback function exits. */
+typedef void(tAVRC_MSG_CBACK)(uint8_t handle, uint8_t label, uint8_t opcode,
+ tAVRC_MSG* p_msg);
+
+typedef struct {
+ tAVRC_CTRL_CBACK* p_ctrl_cback; /* pointer to application control callback */
+ tAVRC_MSG_CBACK* p_msg_cback; /* pointer to application message callback */
+ uint32_t company_id; /* the company ID */
+ uint8_t conn; /* Connection role (Initiator/acceptor) */
+ uint8_t control; /* Control role (Control/Target) */
+} tAVRC_CONN_CB;
+
+typedef struct {
+ uint8_t handle;
+ uint8_t label;
+ uint8_t msg_mask;
+} tAVRC_PARAM;
+
+/*****************************************************************************
+ * external function declarations
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * Function AVRC_AddRecord
+ *
+ * Description This function is called to build an AVRCP SDP record.
+ * Prior to calling this function the application must
+ * call SDP_CreateRecord() to create an SDP record.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates
+ * TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ * or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ *
+ * p_service_name: Pointer to a null-terminated character
+ * string containing the service name.
+ * If service name is not used set this to NULL.
+ *
+ * p_provider_name: Pointer to a null-terminated character
+ * string containing the provider name.
+ * If provider name is not used set this to NULL.
+ *
+ * categories: Supported categories.
+ *
+ * sdp_handle: SDP handle returned by SDP_CreateRecord().
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if not enough resources to build the SDP
+ * record.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_AddRecord(uint16_t service_uuid,
+ const char* p_service_name,
+ const char* p_provider_name, uint16_t categories,
+ uint32_t sdp_handle, bool browse_supported,
+ uint16_t profile_version);
+
+/******************************************************************************
+ *
+ * Function AVRC_FindService
+ *
+ * Description This function is called by the application to perform
+ * service discovery and retrieve AVRCP SDP record information
+ * from a peer device. Information is returned for the first
+ * service record found on the server that matches the service
+ * UUID. The callback function will be executed when service
+ * discovery is complete. There can only be one outstanding
+ * call to AVRC_FindService() at a time; the application must
+ * wait for the callback before it makes another call to the
+ * function. The application is responsible for allocating
+ * memory for the discovery database. It is recommended that
+ * the size of the discovery database be at least 300 bytes.
+ * The application can deallocate the memory after the
+ * callback function has executed.
+ *
+ * Input Parameters:
+ * service_uuid: Indicates
+ * TG(UUID_SERVCLASS_AV_REM_CTRL_TARGET)
+ * or CT(UUID_SERVCLASS_AV_REMOTE_CONTROL)
+ *
+ * bd_addr: BD address of the peer device.
+ *
+ * p_db: SDP discovery database parameters.
+ *
+ * p_cback: Pointer to the callback function.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_PARAMS if discovery database parameters are
+ * invalid.
+ * AVRC_NO_RESOURCES if there are not enough resources to
+ * perform the service search.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_FindService(uint16_t service_uuid, BD_ADDR bd_addr,
+ tAVRC_SDP_DB_PARAMS* p_db,
+ tAVRC_FIND_CBACK* p_cback);
+
+/******************************************************************************
+ *
+ * Function AVRC_Open
+ *
+ * Description This function is called to open a connection to AVCTP.
+ * The connection can be either an initiator or acceptor, as
+ * determined by the p_ccb->stream parameter.
+ * The connection can be a target, a controller or for both
+ * roles, as determined by the p_ccb->control parameter.
+ * By definition, a target connection is an acceptor connection
+ * that waits for an incoming AVCTP connection from the peer.
+ * The connection remains available to the application until
+ * the application closes it by calling AVRC_Close(). The
+ * application does not need to reopen the connection after an
+ * AVRC_CLOSE_IND_EVT is received.
+ *
+ * Input Parameters:
+ * p_ccb->company_id: Company Identifier.
+ *
+ * p_ccb->p_ctrl_cback: Pointer to the control callback
+ * function.
+ *
+ * p_ccb->p_msg_cback: Pointer to the message callback
+ * function.
+ *
+ * p_ccb->conn: AVCTP connection role. This is set to
+ * AVCTP_INT for initiator connections and AVCTP_ACP
+ * for acceptor connections.
+ *
+ * p_ccb->control: Control role. This is set to
+ * AVRC_CT_TARGET for target connections, AVRC_CT_CONTROL
+ * for control connections or
+ * (AVRC_CT_TARGET|AVRC_CT_CONTROL) for connections that
+ * support both roles.
+ *
+ * peer_addr: BD address of peer device. This value is
+ * only used for initiator connections; for acceptor
+ * connections it can be set to NULL.
+ *
+ * Output Parameters:
+ * p_handle: Pointer to handle. This parameter is only
+ * valid if AVRC_SUCCESS is returned.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if there are not enough resources to open
+ * the connection.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_Open(uint8_t* p_handle, tAVRC_CONN_CB* p_ccb,
+ BD_ADDR_PTR peer_addr);
+
+/******************************************************************************
+ *
+ * Function AVRC_Close
+ *
+ * Description Close a connection opened with AVRC_Open().
+ * This function is called when the
+ * application is no longer using a connection.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_Close(uint8_t handle);
+
+/******************************************************************************
+ *
+ * Function AVRC_OpenBrowse
+ *
+ * Description This function is called to open a browsing connection to
+ * AVCTP. The connection can be either an initiator or
+ * acceptor, as determined by the conn_role.
+ * The handle is returned by a previous call to AVRC_Open.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_NO_RESOURCES if there are not enough resources to open
+ * the connection.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_OpenBrowse(uint8_t handle, uint8_t conn_role);
+
+/******************************************************************************
+ *
+ * Function AVRC_CloseBrowse
+ *
+ * Description Close a connection opened with AVRC_OpenBrowse().
+ * This function is called when the
+ * application is no longer using a connection.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_CloseBrowse(uint8_t handle);
+
+/******************************************************************************
+ *
+ * Function AVRC_MsgReq
+ *
+ * Description This function is used to send the AVRCP byte stream in p_pkt
+ * down to AVCTP.
+ *
+ * It is expected that:
+ * p_pkt->offset is at least AVCT_MSG_OFFSET
+ * p_pkt->layer_specific is AVCT_DATA_CTRL or AVCT_DATA_BROWSE
+ * p_pkt->event is AVRC_OP_VENDOR, AVRC_OP_PASS_THRU or
+ * AVRC_OP_BROWSING
+ * The above BT_HDR settings are set by the AVRC_Bld*
+ * functions.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_MsgReq(uint8_t handle, uint8_t label, uint8_t ctype,
+ BT_HDR* p_pkt);
+
+/******************************************************************************
+ *
+ * Function AVRC_UnitCmd
+ *
+ * Description Send a UNIT INFO command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_UnitCmd(uint8_t handle, uint8_t label);
+
+/******************************************************************************
+ *
+ * Function AVRC_SubCmd
+ *
+ * Description Send a SUBUNIT INFO command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * page: Specifies which part of the subunit type table
+ * is requested. For AVRCP it is typically zero.
+ * Value range is 0-7.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_SubCmd(uint8_t handle, uint8_t label, uint8_t page);
+
+/******************************************************************************
+ *
+ * Function AVRC_PassCmd
+ *
+ * Description Send a PASS THROUGH command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * p_msg: Pointer to PASS THROUGH message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_PassCmd(uint8_t handle, uint8_t label,
+ tAVRC_MSG_PASS* p_msg);
+
+/******************************************************************************
+ *
+ * Function AVRC_PassRsp
+ *
+ * Description Send a PASS THROUGH response to the peer device. This
+ * function can only be called for target role connections.
+ * This function must be called when a PASS THROUGH command
+ * message is received from the peer through the
+ * tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label. Must be the same value as
+ * passed with the command message in the callback
+ * function.
+ *
+ * p_msg: Pointer to PASS THROUGH message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_PassRsp(uint8_t handle, uint8_t label,
+ tAVRC_MSG_PASS* p_msg);
+
+/******************************************************************************
+ *
+ * Function AVRC_VendorCmd
+ *
+ * Description Send a VENDOR DEPENDENT command to the peer device. This
+ * function can only be called for controller role connections.
+ * Any response message from the peer is passed back through
+ * the tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label.
+ *
+ * p_msg: Pointer to VENDOR DEPENDENT message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_VendorCmd(uint8_t handle, uint8_t label,
+ tAVRC_MSG_VENDOR* p_msg);
+
+/******************************************************************************
+ *
+ * Function AVRC_VendorRsp
+ *
+ * Description Send a VENDOR DEPENDENT response to the peer device. This
+ * function can only be called for target role connections.
+ * This function must be called when a VENDOR DEPENDENT
+ * command message is received from the peer through the
+ * tAVRC_MSG_CBACK callback function.
+ *
+ * Input Parameters:
+ * handle: Handle of this connection.
+ *
+ * label: Transaction label. Must be the same value as
+ * passed with the command message in the callback
+ * function.
+ *
+ * p_msg: Pointer to VENDOR DEPENDENT message structure.
+ *
+ * Output Parameters:
+ * None.
+ *
+ * Returns AVRC_SUCCESS if successful.
+ * AVRC_BAD_HANDLE if handle is invalid.
+ *
+ *****************************************************************************/
+extern uint16_t AVRC_VendorRsp(uint8_t handle, uint8_t label,
+ tAVRC_MSG_VENDOR* p_msg);
+
+/******************************************************************************
+ *
+ * Function AVRC_SetTraceLevel
+ *
+ * Description Sets the trace level for AVRC. If 0xff is passed, the
+ * current trace level is returned.
+ *
+ * Input Parameters:
+ * new_level: The level to set the AVRC tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ *****************************************************************************/
+extern uint8_t AVRC_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function AVRC_Init
+ *
+ * Description This function is called at stack startup to allocate the
+ * control block (if using dynamic memory), and initializes the
+ * control block and tracing level.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void AVRC_Init(void);
+
+/*******************************************************************************
+ *
+ * Function AVRC_Ctrl_ParsCommand
+ *
+ * Description This function is used to parse cmds received for CTRL
+ * Currently it is for SetAbsVolume and Volume Change
+ * Notification..
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg,
+ tAVRC_COMMAND* p_result);
+
+/*******************************************************************************
+ *
+ * Function AVRC_ParsCommand
+ *
+ * Description This function is used to parse the received command.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
+ uint8_t* p_buf, uint16_t buf_len);
+
+/*******************************************************************************
+ *
+ * Function AVRC_ParsResponse
+ *
+ * Description This function is used to parse the received response.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t buf_len);
+
+/*******************************************************************************
+ *
+ * Function AVRC_Ctrl_ParsResponse
+ *
+ * Description This function is a parse response for AVRCP Controller.
+ *
+ * Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
+ * successfully.
+ * Otherwise, the error code defined by AVRCP 1.4
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg,
+ tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t* buf_len);
+
+/*******************************************************************************
+ *
+ * Function AVRC_BldCommand
+ *
+ * Description This function builds the given AVRCP command to the given
+ * GKI buffer
+ *
+ * Returns AVRC_STS_NO_ERROR, if the command is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt);
+
+/*******************************************************************************
+ *
+ * Function AVRC_BldResponse
+ *
+ * Description This function builds the given AVRCP response to the given
+ * GKI buffer
+ *
+ * Returns AVRC_STS_NO_ERROR, if the response is built successfully
+ * Otherwise, the error code.
+ *
+ ******************************************************************************/
+extern tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp,
+ BT_HDR** pp_pkt);
+
+/**************************************************************************
+ *
+ * Function AVRC_IsValidAvcType
+ *
+ * Description Check if correct AVC type is specified
+ *
+ * Returns returns true if it is valid
+ *
+ *
+ ******************************************************************************/
+extern bool AVRC_IsValidAvcType(uint8_t pdu_id, uint8_t avc_type);
+
+/*******************************************************************************
+ *
+ * Function AVRC_IsValidPlayerAttr
+ *
+ * Description Check if the given attrib value is a valid one
+ *
+ *
+ * Returns returns true if it is valid
+ *
+ ******************************************************************************/
+extern bool AVRC_IsValidPlayerAttr(uint8_t attr);
+
+/*******************************************************************************
+ *
+ * Function AVRC_Update_Version
+ *
+ * Description AVRCP update version to match remote device AVRC version.
+ *
+ * Returns bool
+ *
+ ******************************************************************************/
+extern bool AVRC_Update_Version(uint32_t sdp_handle, uint16_t profile_version);
+#endif /* AVRC_API_H */
diff --git a/mtkbt/code/bt/stack/include/avrc_defs.h b/mtkbt/code/bt/stack/include/avrc_defs.h
new file mode 100755
index 0000000..9fe4397
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/avrc_defs.h
@@ -0,0 +1,1537 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2016 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * AVRCP definition and data types
+ *
+ ******************************************************************************/
+#ifndef _AVRC_DEFS_H
+#define _AVRC_DEFS_H
+
+#include "stack/include/bt_types.h"
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* Profile revision numbers */
+#define AVRC_REV_1_0 0x0100
+#define AVRC_REV_1_3 0x0103
+#define AVRC_REV_1_4 0x0104
+#define AVRC_REV_1_5 0x0105
+#define AVRC_REV_1_6 0x0106
+
+/* defines from the spec */
+#define AVRC_PACKET_LEN 512 /* You must support 512 byte RC packets */
+
+#define AVRC_MIN_CONTROL_MTU 48 /* Minimum MTU for the control channel */
+#define AVRC_MIN_BROWSE_MTU 335 /* Minimum MTU for the browsing channel */
+
+#define AVRC_META_PDU_OFFSET 4
+#define AVRC_SUB_TYPE_LEN 4
+#define AVRC_UID_SIZE 8
+#define AVRC_FEATURE_MASK_SIZE 16
+
+/* command type codes */
+#define AVRC_CMD_CTRL 0 /* Instruct a target to perform an operation */
+#define AVRC_CMD_STATUS 1 /* Check a device's current status */
+#define AVRC_CMD_SPEC_INQ \
+ 2 /* Check whether a target supports a particular \
+ control command; all operands are included */
+#define AVRC_CMD_NOTIF 3 /* Notification of a change in a device's state */
+#define AVRC_CMD_GEN_INQ \
+ 4 /* Check whether a target supports a particular \
+ control command; operands are not included */
+
+/* response type codes */
+#define AVRC_RSP_NOT_IMPL \
+ 8 /* The target does not implement the command specified \
+ by the opcode and operand, \
+ or doesn't implement the specified subunit */
+#define AVRC_RSP_ACCEPT \
+ 9 /* The target executed or is executing the command \
+ */
+#define AVRC_RSP_REJ \
+ 10 /* The target implements the command specified by the \
+ opcode but cannot respond because the current state \
+ of the target doesn't allow it */
+#define AVRC_RSP_IN_TRANS \
+ 11 /* The target implements the status command but it is \
+ in a state of transition; the status command may \
+ be retried at a future time */
+#define AVRC_RSP_IMPL_STBL \
+ 12 /* For specific inquiry or general inquiy commands, \
+ the target implements the command; for status \
+ commands, the target returns stable and includes \
+ the status results */
+#define AVRC_RSP_CHANGED \
+ 13 /* The response frame contains a notification that the \
+ target device's state has changed */
+#define AVRC_RSP_INTERIM \
+ 15 /* For control commands, the target has accepted the \
+ request but cannot return information within 100 \
+ milliseconds; for notify commands, the target accepted \
+ the command, and will notify the controller of a change \
+ of target state at a future time */
+
+/* subunit type */
+#define AVRC_SUB_MONITOR 0x00 /* Monitor */
+#define AVRC_SUB_AUDIO 0x01 /* Audio */
+#define AVRC_SUB_PRINTER 0x02 /* Printer */
+#define AVRC_SUB_DISC 0x03 /* Disc */
+#define AVRC_SUB_TAPE 0x04 /* Tape recorder/player */
+#define AVRC_SUB_TUNER 0x05 /* Tuner */
+#define AVRC_SUB_CA 0x06 /* CA */
+#define AVRC_SUB_CAMERA 0x07 /* Camera */
+#define AVRC_SUB_PANEL 0x09 /* Panel */
+#define AVRC_SUB_BB 0x0A /* Bulletin Board */
+#define AVRC_SUB_CAM_STOR 0x0B /* Camera Storage */
+#define AVRC_SUB_VENDOR 0x1C /* Vendor unique */
+#define AVRC_SUB_EXT 0x1E /* Subunit type extended to next byte */
+#define AVRC_SUB_UNIT 0x1F /* Unit */
+
+/* opcodes - defined by 1394ta */
+#define AVRC_OP_UNIT_INFO 0x30 /* Report unit information */
+#define AVRC_OP_SUB_INFO 0x31 /* Report subunit information */
+#define AVRC_OP_VENDOR 0x00 /* Vendor-dependent commands */
+#define AVRC_OP_PASS_THRU 0x7C /* panel subunit opcode */
+/* opcodes 80-9F and E0-FF are not used by 1394ta. Sneak one for browsing */
+#define AVRC_OP_BROWSE 0xFF /* Browsing */
+#define AVRC_OP_INVALID 0xFE /* invalid one */
+
+/* Company ID's
+*/
+#define AVRC_CO_BLUETOOTH_SIG 0x00FFFFFF
+#define AVRC_CO_WIDCOMM 0x00000361
+#define AVRC_CO_BROADCOM 0x00001018
+#define AVRC_CO_GOOGLE 0x00DAA119
+#define AVRC_CO_METADATA \
+ 0x00001958 /* Unique COMPANY ID for Metadata messages */
+
+/* State flag for Passthrough commands
+*/
+#define AVRC_STATE_PRESS 0
+#define AVRC_STATE_RELEASE 1
+
+/* Operation ID list for Passthrough commands
+*/
+#define AVRC_ID_SELECT 0x00 /* select */
+#define AVRC_ID_UP 0x01 /* up */
+#define AVRC_ID_DOWN 0x02 /* down */
+#define AVRC_ID_LEFT 0x03 /* left */
+#define AVRC_ID_RIGHT 0x04 /* right */
+#define AVRC_ID_RIGHT_UP 0x05 /* right-up */
+#define AVRC_ID_RIGHT_DOWN 0x06 /* right-down */
+#define AVRC_ID_LEFT_UP 0x07 /* left-up */
+#define AVRC_ID_LEFT_DOWN 0x08 /* left-down */
+#define AVRC_ID_ROOT_MENU 0x09 /* root menu */
+#define AVRC_ID_SETUP_MENU 0x0A /* setup menu */
+#define AVRC_ID_CONT_MENU 0x0B /* contents menu */
+#define AVRC_ID_FAV_MENU 0x0C /* favorite menu */
+#define AVRC_ID_EXIT 0x0D /* exit */
+#define AVRC_ID_0 0x20 /* 0 */
+#define AVRC_ID_1 0x21 /* 1 */
+#define AVRC_ID_2 0x22 /* 2 */
+#define AVRC_ID_3 0x23 /* 3 */
+#define AVRC_ID_4 0x24 /* 4 */
+#define AVRC_ID_5 0x25 /* 5 */
+#define AVRC_ID_6 0x26 /* 6 */
+#define AVRC_ID_7 0x27 /* 7 */
+#define AVRC_ID_8 0x28 /* 8 */
+#define AVRC_ID_9 0x29 /* 9 */
+#define AVRC_ID_DOT 0x2A /* dot */
+#define AVRC_ID_ENTER 0x2B /* enter */
+#define AVRC_ID_CLEAR 0x2C /* clear */
+#define AVRC_ID_CHAN_UP 0x30 /* channel up */
+#define AVRC_ID_CHAN_DOWN 0x31 /* channel down */
+#define AVRC_ID_PREV_CHAN 0x32 /* previous channel */
+#define AVRC_ID_SOUND_SEL 0x33 /* sound select */
+#define AVRC_ID_INPUT_SEL 0x34 /* input select */
+#define AVRC_ID_DISP_INFO 0x35 /* display information */
+#define AVRC_ID_HELP 0x36 /* help */
+#define AVRC_ID_PAGE_UP 0x37 /* page up */
+#define AVRC_ID_PAGE_DOWN 0x38 /* page down */
+#define AVRC_ID_POWER 0x40 /* power */
+#define AVRC_ID_VOL_UP 0x41 /* volume up */
+#define AVRC_ID_VOL_DOWN 0x42 /* volume down */
+#define AVRC_ID_MUTE 0x43 /* mute */
+#define AVRC_ID_PLAY 0x44 /* play */
+#define AVRC_ID_STOP 0x45 /* stop */
+#define AVRC_ID_PAUSE 0x46 /* pause */
+#define AVRC_ID_RECORD 0x47 /* record */
+#define AVRC_ID_REWIND 0x48 /* rewind */
+#define AVRC_ID_FAST_FOR 0x49 /* fast forward */
+#define AVRC_ID_EJECT 0x4A /* eject */
+#define AVRC_ID_FORWARD 0x4B /* forward */
+#define AVRC_ID_BACKWARD 0x4C /* backward */
+#define AVRC_ID_ANGLE 0x50 /* angle */
+#define AVRC_ID_SUBPICT 0x51 /* subpicture */
+#define AVRC_ID_F1 0x71 /* F1 */
+#define AVRC_ID_F2 0x72 /* F2 */
+#define AVRC_ID_F3 0x73 /* F3 */
+#define AVRC_ID_F4 0x74 /* F4 */
+#define AVRC_ID_F5 0x75 /* F5 */
+#define AVRC_ID_VENDOR 0x7E /* vendor unique */
+#define AVRC_KEYPRESSED_RELEASE 0x80
+
+/*****************************************************************************
+ * Metadata transfer definitions
+ ****************************************************************************/
+
+/* Define the Metadata Packet types
+*/
+#define AVRC_PKT_SINGLE 0
+#define AVRC_PKT_START 1
+#define AVRC_PKT_CONTINUE 2
+#define AVRC_PKT_END 3
+#define AVRC_PKT_TYPE_MASK 3
+
+/* Define the PDUs carried in the vendor dependant data
+*/
+#define AVRC_PDU_GET_CAPABILITIES 0x10
+#define AVRC_PDU_LIST_PLAYER_APP_ATTR 0x11
+#define AVRC_PDU_LIST_PLAYER_APP_VALUES 0x12
+#define AVRC_PDU_GET_CUR_PLAYER_APP_VALUE 0x13
+#define AVRC_PDU_SET_PLAYER_APP_VALUE 0x14
+#define AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT 0x15
+#define AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT 0x16
+#define AVRC_PDU_INFORM_DISPLAY_CHARSET 0x17
+#define AVRC_PDU_INFORM_BATTERY_STAT_OF_CT 0x18
+#define AVRC_PDU_GET_ELEMENT_ATTR 0x20
+#define AVRC_PDU_GET_PLAY_STATUS 0x30
+#define AVRC_PDU_REGISTER_NOTIFICATION 0x31
+#define AVRC_PDU_REQUEST_CONTINUATION_RSP 0x40
+#define AVRC_PDU_ABORT_CONTINUATION_RSP 0x41
+/* added in 1.4 */
+#define AVRC_PDU_SET_ABSOLUTE_VOLUME 0x50
+#define AVRC_PDU_SET_ADDRESSED_PLAYER 0x60
+#define AVRC_PDU_SET_BROWSED_PLAYER 0x70
+#define AVRC_PDU_GET_FOLDER_ITEMS 0x71
+#define AVRC_PDU_CHANGE_PATH 0x72
+#define AVRC_PDU_GET_ITEM_ATTRIBUTES 0x73
+#define AVRC_PDU_PLAY_ITEM 0x74
+/* Added in post 1.5 */
+#define AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS 0x75
+#define AVRC_PDU_SEARCH 0x80
+#define AVRC_PDU_ADD_TO_NOW_PLAYING 0x90
+#define AVRC_PDU_GENERAL_REJECT 0xA0
+
+/* Define the vendor unique id carried in the pass through data
+*/
+#define AVRC_PDU_NEXT_GROUP 0x00
+#define AVRC_PDU_PREV_GROUP 0x01
+/* The only pass through vendor unique commands defined by AVRC are the group
+ * navigation commands.
+ * The len for vendor unique data is 5
+ */
+#define AVRC_PASS_THRU_GROUP_LEN 5
+
+#define AVRC_PDU_INVALID 0xff
+/* 6.15.3 error status code for general reject */
+/* Invalid command, sent if TG received a PDU that it did not understand. */
+#define AVRC_STS_BAD_CMD 0x00
+/* Invalid parameter, sent if the TG received a PDU with a parameter ID that it
+ * did not understand. Sent if there is only one parameter ID in the PDU. */
+#define AVRC_STS_BAD_PARAM 0x01
+/* Specified parameter not found., sent if the parameter ID is understood, but
+ * content is wrong or corrupted. */
+#define AVRC_STS_NOT_FOUND 0x02
+/* Internal Error, sent if there are error conditions not covered by a more
+ * specific error code. */
+#define AVRC_STS_INTERNAL_ERR 0x03
+/* Operation completed without error. This is the status that should be
+ * returned if the operation was successful. */
+#define AVRC_STS_NO_ERROR 0x04
+/* UID Changed - The UIDs on the device have changed */
+#define AVRC_STS_UID_CHANGED 0x05
+/* #define AVRC_STS_GEN_ERROR 0x06 Unknown Error - now "reserved" */
+/* Invalid Direction - The Direction parameter is invalid - Change Path*/
+#define AVRC_STS_BAD_DIR 0x07
+/* Not a Directory - The UID provided does not refer to a folder item -
+ * Change Path */
+#define AVRC_STS_NOT_DIR 0x08
+/* Does Not Exist - The UID provided does not refer to any item - Change Path,
+ * PlayItem, AddToNowPlaying, GetItemAttributes */
+#define AVRC_STS_NOT_EXIST 0x09
+/* Invalid Scope - The scope parameter is invalid - GetFolderItems, PlayItem,
+ * AddToNowPlayer, GetItemAttributes */
+#define AVRC_STS_BAD_SCOPE 0x0a
+/* Range Out of Bounds - The start of range provided is not valid
+ * GetFolderItems*/
+#define AVRC_STS_BAD_RANGE 0x0b
+/* UID is a Directory - The UID provided refers to a directory, which cannot be
+ * handled by this media player - PlayItem, AddToNowPlaying */
+#define AVRC_STS_UID_IS_DIR 0x0c
+/* Media in Use - The media is not able to be used for this operation at this
+ * time - PlayItem, AddToNowPlaying */
+#define AVRC_STS_IN_USE 0x0d
+/* Now Playing List Full - No more items can be added to the Now Playing List -
+ * AddToNowPlaying*/
+#define AVRC_STS_NOW_LIST_FULL 0x0e
+/* Search Not Supported - The Browsed Media Player does not support search -
+ * Search */
+#define AVRC_STS_SEARCH_NOT_SUP 0x0f
+/* Search in Progress - A search operation is already in progress - Search*/
+#define AVRC_STS_SEARCH_BUSY 0x10
+/* Invalid Player Id - The specified Player Id does not refer to a valid player
+ * - SetAddressedPlayer, SetBrowsedPlayer*/
+#define AVRC_STS_BAD_PLAYER_ID 0x11
+/* Player Not Browsable - The Player Id supplied refers to a Media Player which
+ * does not support browsing - SetBrowsedPlayer */
+#define AVRC_STS_PLAYER_N_BR 0x12
+/* Player Not Addressed. The Player Id supplied refers to a player which is not
+ * currently addressed, and the command is not able to be performed if the
+ * player is not set as addressed - Search, SetBrowsedPlayer*/
+#define AVRC_STS_PLAYER_N_ADDR 0x13
+/* No valid Search Results - The Search result list does not contain valid
+ * entries, e.g. after being invalidated due to change of browsed player -
+ * GetFolderItems */
+#define AVRC_STS_BAD_SEARCH_RES 0x14
+/* No available players ALL */
+#define AVRC_STS_NO_AVAL_PLAYER 0x15
+/* Addressed Player Changed - Register Notification */
+#define AVRC_STS_ADDR_PLAYER_CHG 0x16
+typedef uint8_t tAVRC_STS;
+
+/* Define the Capability IDs
+*/
+#define AVRC_CAP_COMPANY_ID 0x02
+#define AVRC_CAP_EVENTS_SUPPORTED 0x03
+#define AVRC_COMPANY_ID_LEN 3
+#define AVRC_CAPABILITY_OFFSET 2
+
+/* Define the Player Application Settings IDs
+*/
+#define AVRC_PLAYER_SETTING_EQUALIZER 0x01
+#define AVRC_PLAYER_SETTING_REPEAT 0x02
+#define AVRC_PLAYER_SETTING_SHUFFLE 0x03
+#define AVRC_PLAYER_SETTING_SCAN 0x04
+#define AVRC_PLAYER_SETTING_LOW_MENU_EXT 0x80
+#define AVRC_PLAYER_SETTING_HIGH_MENU_EXT 0xff
+
+/* Define the possible values of the Player Application Settings
+*/
+#define AVRC_PLAYER_VAL_OFF 0x01
+#define AVRC_PLAYER_VAL_ON 0x02
+#define AVRC_PLAYER_VAL_SINGLE_REPEAT 0x02
+#define AVRC_PLAYER_VAL_ALL_REPEAT 0x03
+#define AVRC_PLAYER_VAL_GROUP_REPEAT 0x04
+#define AVRC_PLAYER_VAL_ALL_SHUFFLE 0x02
+#define AVRC_PLAYER_VAL_GROUP_SHUFFLE 0x03
+#define AVRC_PLAYER_VAL_ALL_SCAN 0x02
+#define AVRC_PLAYER_VAL_GROUP_SCAN 0x03
+
+/* Define the possible values of Battery Status PDU
+*/
+#define AVRC_BATTERY_STATUS_NORMAL 0x00
+#define AVRC_BATTERY_STATUS_WARNING 0x01
+#define AVRC_BATTERY_STATUS_CRITICAL 0x02
+#define AVRC_BATTERY_STATUS_EXTERNAL 0x03
+#define AVRC_BATTERY_STATUS_FULL_CHARGE 0x04
+typedef uint8_t tAVRC_BATTERY_STATUS;
+
+/* Define character set */
+#define AVRC_CHAR_SET_SIZE 2
+
+/* Define the Media Attribute IDs
+*/
+#define AVRC_MEDIA_ATTR_ID_TITLE 0x00000001
+#define AVRC_MEDIA_ATTR_ID_ARTIST 0x00000002
+#define AVRC_MEDIA_ATTR_ID_ALBUM 0x00000003
+#define AVRC_MEDIA_ATTR_ID_TRACK_NUM 0x00000004
+#define AVRC_MEDIA_ATTR_ID_NUM_TRACKS 0x00000005
+#define AVRC_MEDIA_ATTR_ID_GENRE 0x00000006
+#define AVRC_MEDIA_ATTR_ID_PLAYING_TIME 0x00000007 /* in miliseconds */
+#define AVRC_MAX_NUM_MEDIA_ATTR_ID 7
+
+/* Define the possible values of play state
+*/
+#define AVRC_PLAYSTATE_RESP_MSG_SIZE 9
+#define AVRC_PLAYSTATE_STOPPED 0x00 /* Stopped */
+#define AVRC_PLAYSTATE_PLAYING 0x01 /* Playing */
+#define AVRC_PLAYSTATE_PAUSED 0x02 /* Paused */
+#define AVRC_PLAYSTATE_FWD_SEEK 0x03 /* Fwd Seek*/
+#define AVRC_PLAYSTATE_REV_SEEK 0x04 /* Rev Seek*/
+#define AVRC_PLAYSTATE_ERROR 0xFF /* Error */
+typedef uint8_t tAVRC_PLAYSTATE;
+
+/* Define the events that can be registered for notifications
+*/
+#define AVRC_EVT_PLAY_STATUS_CHANGE 0x01
+#define AVRC_EVT_TRACK_CHANGE 0x02
+#define AVRC_EVT_TRACK_REACHED_END 0x03
+#define AVRC_EVT_TRACK_REACHED_START 0x04
+#define AVRC_EVT_PLAY_POS_CHANGED 0x05
+#define AVRC_EVT_BATTERY_STATUS_CHANGE 0x06
+#define AVRC_EVT_SYSTEM_STATUS_CHANGE 0x07
+#define AVRC_EVT_APP_SETTING_CHANGE 0x08
+/* added in AVRCP 1.4 */
+#define AVRC_EVT_NOW_PLAYING_CHANGE 0x09
+#define AVRC_EVT_AVAL_PLAYERS_CHANGE 0x0a
+#define AVRC_EVT_ADDR_PLAYER_CHANGE 0x0b
+#define AVRC_EVT_UIDS_CHANGE 0x0c
+#define AVRC_EVT_VOLUME_CHANGE 0x0d
+
+/* the number of events that can be registered for notifications */
+#define AVRC_NUM_NOTIF_EVENTS 0x0d
+
+#define AVRC_EVT_MSG_LEN_1 0x01
+#define AVRC_EVT_MSG_LEN_2 0x02
+#define AVRC_EVT_MSG_LEN_5 0x05
+#define AVRC_EVT_MSG_LEN_9 0x09
+
+#define AVRC_MAX_VOLUME 0x7F
+
+/* Define the possible values of system status
+*/
+#define AVRC_SYSTEMSTATE_PWR_ON 0x00
+#define AVRC_SYSTEMSTATE_PWR_OFF 0x01
+#define AVRC_SYSTEMSTATE_PWR_UNPLUGGED 0x02
+typedef uint8_t tAVRC_SYSTEMSTATE;
+
+/* the frequently used character set ids */
+#define AVRC_CHARSET_ID_ASCII ((uint16_t)0x0003) /* ASCII */
+#define AVRC_CHARSET_ID_UTF8 ((uint16_t)0x006a) /* UTF-8 */
+#define AVRC_CHARSET_ID_UTF16 ((uint16_t)0x03f7) /* 1015 */
+#define AVRC_CHARSET_ID_UTF32 ((uint16_t)0x03f9) /* 1017 */
+
+/*****************************************************************************
+ * Advanced Control
+ ****************************************************************************/
+#define AVRC_ITEM_PLAYER 0x01
+#define AVRC_ITEM_FOLDER 0x02
+#define AVRC_ITEM_MEDIA 0x03
+
+/* Media Player Item - Contains all available media players */
+#define AVRC_SCOPE_PLAYER_LIST 0x00
+/* Folder Item, Media Element Item - The virtual filesystem containing the media
+ * content of the browsed player */
+#define AVRC_SCOPE_FILE_SYSTEM 0x01
+/* Media Element Item The results of a search operation on the browsed player
+ */
+#define AVRC_SCOPE_SEARCH 0x02
+/* Media Element Item The Now Playing list (or queue) of the addressed player
+ */
+#define AVRC_SCOPE_NOW_PLAYING 0x03
+
+#define AVRC_FOLDER_ITEM_COUNT_NONE 0xFF
+
+/* folder type */
+#define AVRC_FOLDER_TYPE_MIXED 0x00
+#define AVRC_FOLDER_TYPE_TITLES 0x01
+#define AVRC_FOLDER_TYPE_ALNUMS 0x02
+#define AVRC_FOLDER_TYPE_ARTISTS 0x03
+#define AVRC_FOLDER_TYPE_GENRES 0x04
+#define AVRC_FOLDER_TYPE_PLAYLISTS 0x05
+#define AVRC_FOLDER_TYPE_YEARS 0x06
+
+/* major player type */
+#define AVRC_MJ_TYPE_AUDIO 0x01 /* Audio */
+#define AVRC_MJ_TYPE_VIDEO 0x02 /* Video */
+#define AVRC_MJ_TYPE_BC_AUDIO 0x04 /* Broadcasting Audio */
+#define AVRC_MJ_TYPE_BC_VIDEO 0x08 /* Broadcasting Video */
+#define AVRC_MJ_TYPE_INVALID 0xF0
+
+/* player sub type */
+#define AVRC_SUB_TYPE_NONE 0x00
+#define AVRC_SUB_TYPE_AUDIO_BOOK 0x01 /* Audio Book */
+#define AVRC_SUB_TYPE_PODCAST 0x02 /* Podcast */
+#define AVRC_SUB_TYPE_INVALID 0xFC
+
+/* media item - media type */
+#define AVRC_MEDIA_TYPE_AUDIO 0x00
+#define AVRC_MEDIA_TYPE_VIDEO 0x01
+
+#define AVRC_DIR_UP 0x00 /* Folder Up */
+#define AVRC_DIR_DOWN 0x01 /* Folder Down */
+
+#define AVRC_UID_SIZE 8
+typedef uint8_t tAVRC_UID[AVRC_UID_SIZE];
+
+/*****************************************************************************
+ * player attribute - supported features
+ ****************************************************************************/
+#define AVRC_PF_SELECT_BIT_NO 0
+#define AVRC_PF_SELECT_MASK 0x01
+#define AVRC_PF_SELECT_OFF 0
+#define AVRC_PF_SELECT_SUPPORTED(x) \
+ ((x)[AVRC_PF_SELECT_OFF] & AVRC_PF_SELECT_MASK)
+
+#define AVRC_PF_UP_BIT_NO 1
+#define AVRC_PF_UP_MASK 0x02
+#define AVRC_PF_UP_OFF 0
+#define AVRC_PF_UP_SUPPORTED(x) ((x)[AVRC_PF_UP_OFF] & AVRC_PF_UP_MASK)
+
+#define AVRC_PF_DOWN_BIT_NO 2
+#define AVRC_PF_DOWN_MASK 0x04
+#define AVRC_PF_DOWN_OFF 0
+#define AVRC_PF_DOWN_SUPPORTED(x) ((x)[AVRC_PF_DOWN_OFF] & AVRC_PF_DOWN_MASK)
+
+#define AVRC_PF_LEFT_BIT_NO 3
+#define AVRC_PF_LEFT_MASK 0x08
+#define AVRC_PF_LEFT_OFF 0
+#define AVRC_PF_LEFT_SUPPORTED(x) ((x)[AVRC_PF_LEFT_OFF] & AVRC_PF_LEFT_MASK)
+
+#define AVRC_PF_RIGHT_BIT_NO 4
+#define AVRC_PF_RIGHT_MASK 0x10
+#define AVRC_PF_RIGHT_OFF 0
+#define AVRC_PF_RIGHT_SUPPORTED(x) ((x)[AVRC_PF_RIGHT_OFF] & AVRC_PF_RIGHT_MASK)
+
+#define AVRC_PF_RIGHTUP_BIT_NO 5
+#define AVRC_PF_RIGHTUP_MASK 0x20
+#define AVRC_PF_RIGHTUP_OFF 0
+#define AVRC_PF_RIGHTUP_SUPPORTED(x) \
+ ((x)[AVRC_PF_RIGHTUP_OFF] & AVRC_PF_RIGHTUP_MASK)
+
+#define AVRC_PF_RIGHTDOWN_BIT_NO 6
+#define AVRC_PF_RIGHTDOWN_MASK 0x40
+#define AVRC_PF_RIGHTDOWN_OFF 0
+#define AVRC_PF_RIGHTDOWN_SUPPORTED(x) \
+ ((x)[AVRC_PF_RIGHTDOWN_OFF] & AVRC_PF_RIGHTDOWN_MASK)
+
+#define AVRC_PF_LEFTUP_BIT_NO 7
+#define AVRC_PF_LEFTUP_MASK 0x80
+#define AVRC_PF_LEFTUP_OFF 0
+#define AVRC_PF_LEFTUP_SUPPORTED(x) \
+ ((x)[AVRC_PF_LEFTUP_OFF] & AVRC_PF_LEFTUP_MASK)
+
+#define AVRC_PF_LEFTDOWN_BIT_NO 8
+#define AVRC_PF_LEFTDOWN_MASK 0x01
+#define AVRC_PF_LEFTDOWN_OFF 1
+#define AVRC_PF_LEFTDOWN_SUPPORTED(x) \
+ ((x)[AVRC_PF_LEFTDOWN_OFF] & AVRC_PF_LEFTDOWN_MASK)
+
+#define AVRC_PF_ROOT_MENU_BIT_NO 9
+#define AVRC_PF_ROOT_MENU_MASK 0x02
+#define AVRC_PF_ROOT_MENU_OFF 1
+#define AVRC_PF_ROOT_MENU_SUPPORTED(x) \
+ ((x)[AVRC_PF_ROOT_MENU_OFF] & AVRC_PF_ROOT_MENU_MASK)
+
+#define AVRC_PF_SETUP_MENU_BIT_NO 10
+#define AVRC_PF_SETUP_MENU_MASK 0x04
+#define AVRC_PF_SETUP_MENU_OFF 1
+#define AVRC_PF_SETUP_MENU_SUPPORTED(x) \
+ ((x)[AVRC_PF_SETUP_MENU_OFF] & AVRC_PF_SETUP_MENU_MASK)
+
+#define AVRC_PF_CONTENTS_MENU_BIT_NO 11
+#define AVRC_PF_CONTENTS_MENU_MASK 0x08
+#define AVRC_PF_CONTENTS_MENU_OFF 1
+#define AVRC_PF_CONTENTS_MENU_SUPPORTED(x) \
+ ((x)[AVRC_PF_CONTENTS_MENU_OFF] & AVRC_PF_CONTENTS_MENU_MASK)
+
+#define AVRC_PF_FAVORITE_MENU_BIT_NO 12
+#define AVRC_PF_FAVORITE_MENU_MASK 0x10
+#define AVRC_PF_FAVORITE_MENU_OFF 1
+#define AVRC_PF_FAVORITE_MENU_SUPPORTED(x) \
+ ((x)[AVRC_PF_FAVORITE_MENU_OFF] & AVRC_PF_FAVORITE_MENU_MASK)
+
+#define AVRC_PF_EXIT_BIT_NO 13
+#define AVRC_PF_EXIT_MASK 0x20
+#define AVRC_PF_EXIT_OFF 1
+#define AVRC_PF_EXIT_SUPPORTED(x) ((x)[AVRC_PF_EXIT_OFF] & AVRC_PF_EXIT_MASK)
+
+#define AVRC_PF_0_BIT_NO 14
+#define AVRC_PF_0_MASK 0x40
+#define AVRC_PF_0_OFF 1
+#define AVRC_PF_0_SUPPORTED(x) ((x)[AVRC_PF_0_OFF] & AVRC_PF_0_MASK)
+
+#define AVRC_PF_1_BIT_NO 15
+#define AVRC_PF_1_MASK 0x80
+#define AVRC_PF_1_OFF 1
+#define AVRC_PF_1_SUPPORTED(x) ((x)[AVRC_PF_1_OFF] & AVRC_PF_1_MASK)
+
+#define AVRC_PF_2_BIT_NO 16
+#define AVRC_PF_2_MASK 0x01
+#define AVRC_PF_2_OFF 2
+#define AVRC_PF_2_SUPPORTED(x) ((x)[AVRC_PF_2_OFF] & AVRC_PF_2_MASK)
+
+#define AVRC_PF_3_BIT_NO 17
+#define AVRC_PF_3_MASK 0x02
+#define AVRC_PF_3_OFF 2
+#define AVRC_PF_3_SUPPORTED(x) ((x)[AVRC_PF_3_OFF] & AVRC_PF_3_MASK)
+
+#define AVRC_PF_4_BIT_NO 18
+#define AVRC_PF_4_MASK 0x04
+#define AVRC_PF_4_OFF 2
+#define AVRC_PF_4_SUPPORTED(x) ((x)[AVRC_PF_4_OFF] & AVRC_PF_4_MASK)
+
+#define AVRC_PF_5_BIT_NO 19
+#define AVRC_PF_5_MASK 0x08
+#define AVRC_PF_5_OFF 2
+#define AVRC_PF_5_SUPPORTED(x) ((x)[AVRC_PF_5_OFF] & AVRC_PF_5_MASK)
+
+#define AVRC_PF_6_BIT_NO 20
+#define AVRC_PF_6_MASK 0x10
+#define AVRC_PF_6_OFF 2
+#define AVRC_PF_6_SUPPORTED(x) ((x)[AVRC_PF_6_OFF] & AVRC_PF_6_MASK)
+
+#define AVRC_PF_7_BIT_NO 21
+#define AVRC_PF_7_MASK 0x20
+#define AVRC_PF_7_OFF 2
+#define AVRC_PF_7_SUPPORTED(x) ((x)[AVRC_PF_7_OFF] & AVRC_PF_7_MASK)
+
+#define AVRC_PF_8_BIT_NO 22
+#define AVRC_PF_8_MASK 0x40
+#define AVRC_PF_8_OFF 2
+#define AVRC_PF_8_SUPPORTED(x) ((x)[AVRC_PF_8_OFF] & AVRC_PF_8_MASK)
+
+#define AVRC_PF_9_BIT_NO 23
+#define AVRC_PF_9_MASK 0x80
+#define AVRC_PF_9_OFF 2
+#define AVRC_PF_9_SUPPORTED(x) ((x)[AVRC_PF_9_OFF] & AVRC_PF_9_MASK)
+
+#define AVRC_PF_DOT_BIT_NO 24
+#define AVRC_PF_DOT_MASK 0x01
+#define AVRC_PF_DOT_OFF 3
+#define AVRC_PF_DOT_SUPPORTED(x) ((x)[AVRC_PF_DOT_OFF] & AVRC_PF_DOT_MASK)
+
+#define AVRC_PF_ENTER_BIT_NO 25
+#define AVRC_PF_ENTER_MASK 0x02
+#define AVRC_PF_ENTER_OFF 3
+#define AVRC_PF_ENTER_SUPPORTED(x) ((x)[AVRC_PF_ENTER_OFF] & AVRC_PF_ENTER_MASK)
+
+#define AVRC_PF_CLEAR_BIT_NO 26
+#define AVRC_PF_CLEAR_MASK 0x04
+#define AVRC_PF_CLEAR_OFF 3
+#define AVRC_PF_CLEAR_SUPPORTED(x) ((x)[AVRC_PF_CLEAR_OFF] & AVRC_PF_CLEAR_MASK)
+
+#define AVRC_PF_CHNL_UP_BIT_NO 27
+#define AVRC_PF_CHNL_UP_MASK 0x08
+#define AVRC_PF_CHNL_UP_OFF 3
+#define AVRC_PF_CHNL_UP_SUPPORTED(x) \
+ ((x)[AVRC_PF_CHNL_UP_OFF] & AVRC_PF_CHNL_UP_MASK)
+
+#define AVRC_PF_CHNL_DOWN_BIT_NO 28
+#define AVRC_PF_CHNL_DOWN_MASK 0x10
+#define AVRC_PF_CHNL_DOWN_OFF 3
+#define AVRC_PF_CHNL_DOWN_SUPPORTED(x) \
+ ((x)[AVRC_PF_CHNL_DOWN_OFF] & AVRC_PF_CHNL_DOWN_MASK)
+
+#define AVRC_PF_PREV_CHNL_BIT_NO 29
+#define AVRC_PF_PREV_CHNL_MASK 0x20
+#define AVRC_PF_PREV_CHNL_OFF 3
+#define AVRC_PF_PREV_CHNL_SUPPORTED(x) \
+ ((x)[AVRC_PF_PREV_CHNL_OFF] & AVRC_PF_PREV_CHNL_MASK)
+
+#define AVRC_PF_SOUND_SEL_BIT_NO 30
+#define AVRC_PF_SOUND_SEL_MASK 0x40
+#define AVRC_PF_SOUND_SEL_OFF 3
+#define AVRC_PF_SOUND_SEL_SUPPORTED(x) \
+ ((x)[AVRC_PF_SOUND_SEL_OFF] & AVRC_PF_SOUND_SEL_MASK)
+
+#define AVRC_PF_INPUT_SEL_BIT_NO 31
+#define AVRC_PF_INPUT_SEL_MASK 0x80
+#define AVRC_PF_INPUT_SEL_OFF 3
+#define AVRC_PF_INPUT_SEL_SUPPORTED(x) \
+ ((x)[AVRC_PF_INPUT_SEL_OFF] & AVRC_PF_INPUT_SEL_MASK)
+
+#define AVRC_PF_DISP_INFO_BIT_NO 32
+#define AVRC_PF_DISP_INFO_MASK 0x01
+#define AVRC_PF_DISP_INFO_OFF 4
+#define AVRC_PF_DISP_INFO_SUPPORTED(x) \
+ ((x)[AVRC_PF_DISP_INFO_OFF] & AVRC_PF_DISP_INFO_MASK)
+
+#define AVRC_PF_HELP_BIT_NO 33
+#define AVRC_PF_HELP_MASK 0x02
+#define AVRC_PF_HELP_OFF 4
+#define AVRC_PF_HELP_SUPPORTED(x) ((x)[AVRC_PF_HELP_OFF] & AVRC_PF_HELP_MASK)
+
+#define AVRC_PF_PAGE_UP_BIT_NO 34
+#define AVRC_PF_PAGE_UP_MASK 0x04
+#define AVRC_PF_PAGE_UP_OFF 4
+#define AVRC_PF_PAGE_UP_SUPPORTED(x) \
+ ((x)[AVRC_PF_PAGE_UP_OFF] & AVRC_PF_PAGE_UP_MASK)
+
+#define AVRC_PF_PAGE_DOWN_BIT_NO 35
+#define AVRC_PF_PAGE_DOWN_MASK 0x08
+#define AVRC_PF_PAGE_DOWN_OFF 4
+#define AVRC_PF_PAGE_DOWN_SUPPORTED(x) \
+ ((x)[AVRC_PF_PAGE_DOWN_OFF] & AVRC_PF_PAGE_DOWN_MASK)
+
+#define AVRC_PF_POWER_BIT_NO 36
+#define AVRC_PF_POWER_MASK 0x10
+#define AVRC_PF_POWER_OFF 4
+#define AVRC_PF_POWER_SUPPORTED(x) ((x)[AVRC_PF_POWER_OFF] & AVRC_PF_POWER_MASK)
+
+#define AVRC_PF_VOL_UP_BIT_NO 37
+#define AVRC_PF_VOL_UP_MASK 0x20
+#define AVRC_PF_VOL_UP_OFF 4
+#define AVRC_PF_VOL_UP_SUPPORTED(x) \
+ ((x)[AVRC_PF_VOL_UP_OFF] & AVRC_PF_VOL_UP_MASK)
+
+#define AVRC_PF_VOL_DOWN_BIT_NO 38
+#define AVRC_PF_VOL_DOWN_MASK 0x40
+#define AVRC_PF_VOL_DOWN_OFF 4
+#define AVRC_PF_VOL_DOWN_SUPPORTED(x) \
+ ((x)[AVRC_PF_VOL_DOWN_OFF] & AVRC_PF_VOL_DOWN_MASK)
+
+#define AVRC_PF_MUTE_BIT_NO 39
+#define AVRC_PF_MUTE_MASK 0x80
+#define AVRC_PF_MUTE_OFF 4
+#define AVRC_PF_MUTE_SUPPORTED(x) ((x)[AVRC_PF_MUTE_OFF] & AVRC_PF_MUTE_MASK)
+
+#define AVRC_PF_PLAY_BIT_NO 40
+#define AVRC_PF_PLAY_MASK 0x01
+#define AVRC_PF_PLAY_OFF 5
+#define AVRC_PF_PLAY_SUPPORTED(x) ((x)[AVRC_PF_PLAY_OFF] & AVRC_PF_PLAY_MASK)
+
+#define AVRC_PF_STOP_BIT_NO 41
+#define AVRC_PF_STOP_MASK 0x02
+#define AVRC_PF_STOP_OFF 5
+#define AVRC_PF_STOP_SUPPORTED(x) ((x)[AVRC_PF_STOP_OFF] & AVRC_PF_STOP_MASK)
+
+#define AVRC_PF_PAUSE_BIT_NO 42
+#define AVRC_PF_PAUSE_MASK 0x04
+#define AVRC_PF_PAUSE_OFF 5
+#define AVRC_PF_PAUSE_SUPPORTED(x) ((x)[AVRC_PF_PAUSE_OFF] & AVRC_PF_PAUSE_MASK)
+
+#define AVRC_PF_RECORD_BIT_NO 43
+#define AVRC_PF_RECORD_MASK 0x08
+#define AVRC_PF_RECORD_OFF 5
+#define AVRC_PF_RECORD_SUPPORTED(x) \
+ ((x)[AVRC_PF_RECORD_OFF] & AVRC_PF_RECORD_MASK)
+
+#define AVRC_PF_REWIND_BIT_NO 44
+#define AVRC_PF_REWIND_MASK 0x10
+#define AVRC_PF_REWIND_OFF 5
+#define AVRC_PF_REWIND_SUPPORTED(x) \
+ ((x)[AVRC_PF_REWIND_OFF] & AVRC_PF_REWIND_MASK)
+
+#define AVRC_PF_FAST_FWD_BIT_NO 45
+#define AVRC_PF_FAST_FWD_MASK 0x20
+#define AVRC_PF_FAST_FWD_OFF 5
+#define AVRC_PF_FAST_FWD_SUPPORTED(x) \
+ ((x)[AVRC_PF_FAST_FWD_OFF] & AVRC_PF_FAST_FWD_MASK)
+
+#define AVRC_PF_EJECT_BIT_NO 46
+#define AVRC_PF_EJECT_MASK 0x40
+#define AVRC_PF_EJECT_OFF 5
+#define AVRC_PF_EJECT_SUPPORTED(x) ((x)[AVRC_PF_EJECT_OFF] & AVRC_PF_EJECT_MASK)
+
+#define AVRC_PF_FORWARD_BIT_NO 47
+#define AVRC_PF_FORWARD_MASK 0x80
+#define AVRC_PF_FORWARD_OFF 5
+#define AVRC_PF_FORWARD_SUPPORTED(x) \
+ ((x)[AVRC_PF_FORWARD_OFF] & AVRC_PF_FORWARD_MASK)
+
+#define AVRC_PF_BACKWARD_BIT_NO 48
+#define AVRC_PF_BACKWARD_MASK 0x01
+#define AVRC_PF_BACKWARD_OFF 6
+#define AVRC_PF_BACKWARD_SUPPORTED(x) \
+ ((x)[AVRC_PF_BACKWARD_OFF] & AVRC_PF_BACKWARD_MASK)
+
+#define AVRC_PF_ANGLE_BIT_NO 49
+#define AVRC_PF_ANGLE_MASK 0x02
+#define AVRC_PF_ANGLE_OFF 6
+#define AVRC_PF_ANGLE_SUPPORTED(x) ((x)[AVRC_PF_ANGLE_OFF] & AVRC_PF_ANGLE_MASK)
+
+#define AVRC_PF_SUBPICTURE_BIT_NO 50
+#define AVRC_PF_SUBPICTURE_MASK 0x04
+#define AVRC_PF_SUBPICTURE_OFF 6
+#define AVRC_PF_SUBPICTURE_SUPPORTED(x) \
+ ((x)[AVRC_PF_SUBPICTURE_OFF] & AVRC_PF_SUBPICTURE_MASK)
+
+#define AVRC_PF_F1_BIT_NO 51
+#define AVRC_PF_F1_MASK 0x08
+#define AVRC_PF_F1_OFF 6
+#define AVRC_PF_F1_SUPPORTED(x) ((x)[AVRC_PF_F1_OFF] & AVRC_PF_F1_MASK)
+
+#define AVRC_PF_F2_BIT_NO 52
+#define AVRC_PF_F2_MASK 0x10
+#define AVRC_PF_F2_OFF 6
+#define AVRC_PF_F2_SUPPORTED(x) ((x)[AVRC_PF_F2_OFF] & AVRC_PF_F2_MASK)
+
+#define AVRC_PF_F3_BIT_NO 53
+#define AVRC_PF_F3_MASK 0x20
+#define AVRC_PF_F3_OFF 6
+#define AVRC_PF_F3_SUPPORTED(x) ((x)[AVRC_PF_F3_OFF] & AVRC_PF_F3_MASK)
+
+#define AVRC_PF_F4_BIT_NO 54
+#define AVRC_PF_F4_MASK 0x40
+#define AVRC_PF_F4_OFF 6
+#define AVRC_PF_F4_SUPPORTED(x) ((x)[AVRC_PF_F4_OFF] & AVRC_PF_F4_MASK)
+
+#define AVRC_PF_F5_BIT_NO 55
+#define AVRC_PF_F5_MASK 0x80
+#define AVRC_PF_F5_OFF 6
+#define AVRC_PF_F5_SUPPORTED(x) ((x)[AVRC_PF_F5_OFF] & AVRC_PF_F5_MASK)
+
+/* Vendor unique. This PASSTHROUGH command is supported. */
+#define AVRC_PF_VENDOR_BIT_NO 56
+#define AVRC_PF_VENDOR_MASK 0x01
+#define AVRC_PF_VENDOR_OFF 7
+#define AVRC_PF_VENDOR_SUPPORTED(x) \
+ ((x)[AVRC_PF_VENDOR_OFF] & AVRC_PF_VENDOR_MASK)
+
+/* Basic Group Navigation. This overrules the SDP entry as it is set per
+ * player.7 */
+#define AVRC_PF_GROUP_NAVI_BIT_NO 57
+#define AVRC_PF_GROUP_NAVI_MASK 0x02
+#define AVRC_PF_GROUP_NAVI_OFF 7
+#define AVRC_PF_GROUP_NAVI_SUPPORTED(x) \
+ ((x)[AVRC_PF_GROUP_NAVI_OFF] & AVRC_PF_GROUP_NAVI_MASK)
+
+/* Advanced Control Player. This bit is set if the player supports at least
+ * AVRCP 1.4. */
+#define AVRC_PF_ADV_CTRL_BIT_NO 58
+#define AVRC_PF_ADV_CTRL_MASK 0x04
+#define AVRC_PF_ADV_CTRL_OFF 7
+#define AVRC_PF_ADV_CTRL_SUPPORTED(x) \
+ ((x)[AVRC_PF_ADV_CTRL_OFF] & AVRC_PF_ADV_CTRL_MASK)
+
+/* Browsing. This bit is set if the player supports browsing. */
+#define AVRC_PF_BROWSE_BIT_NO 59
+#define AVRC_PF_BROWSE_MASK 0x08
+#define AVRC_PF_BROWSE_OFF 7
+#define AVRC_PF_BROWSE_SUPPORTED(x) \
+ ((x)[AVRC_PF_BROWSE_OFF] & AVRC_PF_BROWSE_MASK)
+
+/* Searching. This bit is set if the player supports searching. */
+#define AVRC_PF_SEARCH_BIT_NO 60
+#define AVRC_PF_SEARCH_MASK 0x10
+#define AVRC_PF_SEARCH_OFF 7
+#define AVRC_PF_SEARCH_SUPPORTED(x) \
+ ((x)[AVRC_PF_SEARCH_OFF] & AVRC_PF_SEARCH_MASK)
+
+/* AddToNowPlaying. This bit is set if the player supports the AddToNowPlaying
+ * command. */
+#define AVRC_PF_ADD2NOWPLAY_BIT_NO 61
+#define AVRC_PF_ADD2NOWPLAY_MASK 0x20
+#define AVRC_PF_ADD2NOWPLAY_OFF 7
+#define AVRC_PF_ADD2NOWPLAY_SUPPORTED(x) \
+ ((x)[AVRC_PF_ADD2NOWPLAY_OFF] & AVRC_PF_ADD2NOWPLAY_MASK)
+
+/* UIDs unique in player browse tree. This bit is set if the player is able to
+ * maintain unique UIDs across the player browse tree. */
+#define AVRC_PF_UID_UNIQUE_BIT_NO 62
+#define AVRC_PF_UID_UNIQUE_MASK 0x40
+#define AVRC_PF_UID_UNIQUE_OFF 7
+#define AVRC_PF_UID_UNIQUE_SUPPORTED(x) \
+ ((x)[AVRC_PF_UID_UNIQUE_OFF] & AVRC_PF_UID_UNIQUE_MASK)
+
+/* OnlyBrowsableWhenAddressed. This bit is set if the player is only able to be
+ * browsed when it is set as the Addressed Player. */
+#define AVRC_PF_BR_WH_ADDR_BIT_NO 63
+#define AVRC_PF_BR_WH_ADDR_MASK 0x80
+#define AVRC_PF_BR_WH_ADDR_OFF 7
+#define AVRC_PF_BR_WH_ADDR_SUPPORTED(x) \
+ ((x)[AVRC_PF_BR_WH_ADDR_OFF] & AVRC_PF_BR_WH_ADDR_MASK)
+
+/* OnlySearchableWhenAddressed. This bit is set if the player is only able to
+ * be searched when it is set as the Addressed player. */
+#define AVRC_PF_SEARCH_WH_ADDR_BIT_NO 64
+#define AVRC_PF_SEARCH_WH_ADDR_MASK 0x01
+#define AVRC_PF_SEARCH_WH_ADDR_OFF 8
+#define AVRC_PF_SEARCH_WH_ADDR_SUPPORTED(x) \
+ ((x)[AVRC_PF_SEARCH_WH_ADDR_OFF] & AVRC_PF_SEARCH_WH_ADDR_MASK)
+
+/* NowPlaying. This bit is set if the player supports the NowPlaying folder.
+ * Note that for all players that support browsing this bit shall be set */
+#define AVRC_PF_NOW_PLAY_BIT_NO 65
+#define AVRC_PF_NOW_PLAY_MASK 0x02
+#define AVRC_PF_NOW_PLAY_OFF 8
+#define AVRC_PF_NOW_PLAY_SUPPORTED(x) \
+ ((x)[AVRC_PF_NOW_PLAY_OFF] & AVRC_PF_NOW_PLAY_MASK)
+
+/* UIDPersistency. This bit is set if the Player is able to persist UID values
+ * between AVRCP Browse Reconnect */
+#define AVRC_PF_UID_PERSIST_BIT_NO 66
+#define AVRC_PF_UID_PERSIST_MASK 0x04
+#define AVRC_PF_UID_PERSIST_OFF 8
+#define AVRC_PF_UID_PERSIST_SUPPORTED(x) \
+ ((x)[AVRC_PF_UID_PERSIST_OFF] & AVRC_PF_UID_PERSIST_MASK)
+
+/* NumberOfItems. This bit is set if player supports the GetTotalNumberOfItems
+ * browsing command. */
+#define AVRC_PF_GET_NUM_OF_ITEMS_BIT_NO 67
+#define AVRC_PF_GET_NUM_OF_ITEMS_MASK 0x08
+#define AVRC_PF_GET_NUM_OF_ITEMS_OFF 8
+#define AVRC_PF_GET_NUM_OF_ITEMS_SUPPORTED(x) \
+ ((x)[AVRC_PF_GET_NUM_OF_ITEMS_OFF] & AVRC_PF_GET_NUM_OF_ITEMS_MASK)
+
+/*****************************************************************************
+ * data type definitions
+ ****************************************************************************/
+
+/*
+This structure contains the header parameters of an AV/C message.
+*/
+typedef struct {
+ uint8_t ctype; /* Command type. */
+ uint8_t subunit_type; /* Subunit type. */
+ uint8_t subunit_id; /* Subunit ID. This value is typically ignored in AVRCP,
+ * except for VENDOR DEPENDENT messages when the value is
+ * vendor-dependent. Value range is 0-7. */
+ uint8_t opcode; /* Op Code (passthrough, vendor, etc) */
+} tAVRC_HDR;
+
+/* This structure contains a UNIT INFO message. */
+typedef struct {
+ tAVRC_HDR hdr; /* Message header. */
+ uint32_t company_id; /* Company identifier. */
+ uint8_t unit_type; /* Unit type. Uses the same values as subunit type. */
+ uint8_t unit; /* This value is vendor dependent and typically zero. */
+} tAVRC_MSG_UNIT;
+
+/* This structure contains a SUBUNIT INFO message. */
+typedef struct {
+ tAVRC_HDR hdr; /* Message header. */
+ uint8_t subunit_type[AVRC_SUB_TYPE_LEN];
+ /* Array containing subunit type values. */
+ bool panel; /* true if the panel subunit type is in the
+ * subunit_type array, false otherwise. */
+ uint8_t page; /* Specifies which part of the subunit type table is
+ * returned. For AVRCP it is typically zero.
+ * Value range is 0-7. */
+} tAVRC_MSG_SUB;
+
+/* This structure contains a VENDOR DEPENDENT message. */
+typedef struct {
+ tAVRC_HDR hdr; /* Message header. */
+ uint32_t company_id; /* Company identifier. */
+ uint8_t* p_vendor_data; /* Pointer to vendor dependent data. */
+ uint16_t vendor_len; /* Length in bytes of vendor dependent data. */
+} tAVRC_MSG_VENDOR;
+
+/* PASS THROUGH message structure */
+typedef struct {
+ tAVRC_HDR hdr; /* hdr.ctype Unused.
+ * hdr.subunit_type Unused.
+ * hdr.subunit_id Unused. */
+ uint8_t op_id; /* Operation ID. */
+ uint8_t state; /* Keypress state. */
+ uint8_t* p_pass_data; /* Pointer to data. This parameter is only valid
+ * when the op_id is AVRC_ID_VENDOR.*/
+ uint8_t pass_len; /* Length in bytes of data. This parameter is only
+ * valid when the op_id is AVRC_ID_VENDOR.*/
+} tAVRC_MSG_PASS;
+
+/* Command/Response indicator. */
+#define AVRC_CMD AVCT_CMD /* Command message */
+#define AVRC_RSP AVCT_RSP /* Response message */
+
+/* Browsing channel message structure */
+typedef struct {
+ tAVRC_HDR hdr; /* hdr.ctype AVRC_CMD or AVRC_RSP.
+ * hdr.subunit_type Unused.
+ * hdr.subunit_id Unused. */
+ uint8_t* p_browse_data; /* Pointer to data. */
+ uint16_t browse_len; /* Length in bytes of data. */
+ BT_HDR* p_browse_pkt; /* The GKI buffer received. Set to NULL, if the callback
+ function wants to keep the buffer */
+} tAVRC_MSG_BROWSE;
+
+/* This is a union of all message type structures. */
+typedef union {
+ tAVRC_HDR hdr; /* Message header. */
+ tAVRC_MSG_UNIT unit; /* UNIT INFO message. */
+ tAVRC_MSG_SUB sub; /* SUBUNIT INFO message. */
+ tAVRC_MSG_VENDOR vendor; /* VENDOR DEPENDENT message. */
+ tAVRC_MSG_PASS pass; /* PASS THROUGH message. */
+ tAVRC_MSG_BROWSE browse; /* messages thru browsing channel */
+} tAVRC_MSG;
+
+/* macros */
+#define AVRC_IS_VALID_CAP_ID(a) \
+ ((((a) == AVRC_CAP_COMPANY_ID) || ((a) == AVRC_CAP_EVENTS_SUPPORTED)) \
+ ? true \
+ : false)
+
+#define AVRC_IS_VALID_EVENT_ID(a) \
+ ((((a) >= AVRC_EVT_PLAY_STATUS_CHANGE) && ((a) <= AVRC_EVT_VOLUME_CHANGE)) \
+ ? true \
+ : false)
+
+#define AVRC_IS_VALID_ATTRIBUTE(a) \
+ ((((((a) > 0) && (a) <= AVRC_PLAYER_SETTING_SCAN)) || \
+ ((a) >= AVRC_PLAYER_SETTING_LOW_MENU_EXT)) \
+ ? true \
+ : false)
+
+#define AVRC_IS_VALID_MEDIA_ATTRIBUTE(a) \
+ (((a) >= AVRC_MEDIA_ATTR_ID_TITLE) && \
+ ((a) <= AVRC_MEDIA_ATTR_ID_PLAYING_TIME) \
+ ? true \
+ : false)
+
+#define AVRC_IS_VALID_BATTERY_STATUS(a) \
+ (((a) <= AVRC_BATTERY_STATUS_FULL_CHARGE) ? true : false)
+
+#define AVRC_IS_VALID_SYSTEM_STATUS(a) \
+ (((a) <= AVRC_SYSTEMSTATE_PWR_UNPLUGGED) ? true : false)
+
+#define AVRC_IS_VALID_GROUP(a) (((a) <= AVRC_PDU_PREV_GROUP) ? true : false)
+
+/* Company ID is 24-bit integer We can not use the macros in bt_types.h */
+#define AVRC_CO_ID_TO_BE_STREAM(p, u32) \
+ { \
+ *(p)++ = (uint8_t)((u32) >> 16); \
+ *(p)++ = (uint8_t)((u32) >> 8); \
+ *(p)++ = (uint8_t)(u32); \
+ }
+#define AVRC_BE_STREAM_TO_CO_ID(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*((p) + 2))) + (((uint32_t)(*((p) + 1))) << 8) + \
+ (((uint32_t)(*(p))) << 16)); \
+ (p) += 3; \
+ }
+
+/*****************************************************************************
+ * data type definitions
+ ****************************************************************************/
+#define AVRC_MAX_APP_ATTR_SIZE 16
+#define AVRC_MAX_CHARSET_SIZE 16
+#define AVRC_MAX_ELEM_ATTR_SIZE 8
+
+/*****************************************************************************
+ * Metadata transfer Building/Parsing definitions
+ ****************************************************************************/
+
+typedef struct {
+ uint16_t charset_id;
+ uint16_t str_len;
+ uint8_t* p_str;
+} tAVRC_FULL_NAME;
+
+typedef struct {
+ uint16_t str_len;
+ uint8_t* p_str;
+} tAVRC_NAME;
+
+#ifndef AVRC_CAP_MAX_NUM_COMP_ID
+#define AVRC_CAP_MAX_NUM_COMP_ID 4
+#endif
+
+#ifndef AVRC_CAP_MAX_NUM_EVT_ID
+#define AVRC_CAP_MAX_NUM_EVT_ID 16
+#endif
+
+typedef union {
+ uint32_t company_id[AVRC_CAP_MAX_NUM_COMP_ID];
+ uint8_t event_id[AVRC_CAP_MAX_NUM_EVT_ID];
+} tAVRC_CAPS_PARAM;
+
+typedef struct {
+ uint8_t attr_id;
+ uint8_t attr_val;
+} tAVRC_APP_SETTING;
+
+typedef struct {
+ uint8_t attr_id;
+ uint16_t charset_id;
+ uint8_t str_len;
+ uint8_t* p_str;
+} tAVRC_APP_SETTING_TEXT;
+
+typedef uint8_t tAVRC_FEATURE_MASK[AVRC_FEATURE_MASK_SIZE];
+
+typedef struct {
+ uint16_t player_id; /* A unique identifier for this media player.*/
+ uint8_t major_type; /* Use AVRC_MJ_TYPE_AUDIO, AVRC_MJ_TYPE_VIDEO,
+ AVRC_MJ_TYPE_BC_AUDIO, or AVRC_MJ_TYPE_BC_VIDEO.*/
+ uint32_t sub_type; /* Use AVRC_SUB_TYPE_NONE, AVRC_SUB_TYPE_AUDIO_BOOK, or
+ AVRC_SUB_TYPE_PODCAST*/
+ uint8_t play_status; /* Use AVRC_PLAYSTATE_STOPPED, AVRC_PLAYSTATE_PLAYING,
+ AVRC_PLAYSTATE_PAUSED, AVRC_PLAYSTATE_FWD_SEEK,
+ AVRC_PLAYSTATE_REV_SEEK, or AVRC_PLAYSTATE_ERROR*/
+ tAVRC_FEATURE_MASK features; /* Supported feature bit mask*/
+ tAVRC_FULL_NAME name; /* The player name, name length and character set id.*/
+} tAVRC_ITEM_PLAYER;
+
+typedef struct {
+ tAVRC_UID uid; /* The uid of this folder */
+ uint8_t type; /* Use AVRC_FOLDER_TYPE_MIXED, AVRC_FOLDER_TYPE_TITLES,
+ AVRC_FOLDER_TYPE_ALNUMS, AVRC_FOLDER_TYPE_ARTISTS,
+ AVRC_FOLDER_TYPE_GENRES,
+ AVRC_FOLDER_TYPE_PLAYLISTS, or AVRC_FOLDER_TYPE_YEARS.*/
+ bool playable; /* true, if the folder can be played. */
+ tAVRC_FULL_NAME name; /* The folder name, name length and character set id. */
+} tAVRC_ITEM_FOLDER;
+
+typedef struct {
+ uint32_t
+ attr_id; /* Use AVRC_MEDIA_ATTR_ID_TITLE, AVRC_MEDIA_ATTR_ID_ARTIST,
+ AVRC_MEDIA_ATTR_ID_ALBUM,
+ AVRC_MEDIA_ATTR_ID_TRACK_NUM, AVRC_MEDIA_ATTR_ID_NUM_TRACKS,
+ AVRC_MEDIA_ATTR_ID_GENRE, AVRC_MEDIA_ATTR_ID_PLAYING_TIME */
+ tAVRC_FULL_NAME
+ name; /* The attribute value, value length and character set id. */
+} tAVRC_ATTR_ENTRY;
+
+typedef struct {
+ tAVRC_UID uid; /* The uid of this media element item */
+ uint8_t type; /* Use AVRC_MEDIA_TYPE_AUDIO or AVRC_MEDIA_TYPE_VIDEO. */
+ tAVRC_FULL_NAME name; /* The media name, name length and character set id. */
+ uint8_t attr_count; /* The number of attributes in p_attr_list */
+ tAVRC_ATTR_ENTRY* p_attr_list; /* Attribute entry list. */
+} tAVRC_ITEM_MEDIA;
+
+typedef struct {
+ uint8_t
+ item_type; /* AVRC_ITEM_PLAYER, AVRC_ITEM_FOLDER, or AVRC_ITEM_MEDIA */
+ union {
+ tAVRC_ITEM_PLAYER player; /* The properties of a media player item.*/
+ tAVRC_ITEM_FOLDER folder; /* The properties of a folder item.*/
+ tAVRC_ITEM_MEDIA media; /* The properties of a media item.*/
+ } u;
+} tAVRC_ITEM;
+
+/* GetCapability */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t capability_id;
+} tAVRC_GET_CAPS_CMD;
+
+/* ListPlayerAppValues */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t attr_id;
+} tAVRC_LIST_APP_VALUES_CMD;
+
+/* GetCurAppValue */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t num_attr;
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_CUR_APP_VALUE_CMD;
+
+/* SetAppValue */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t num_val;
+ tAVRC_APP_SETTING* p_vals;
+} tAVRC_SET_APP_VALUE_CMD;
+
+/* GetAppAttrTxt */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t num_attr;
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_ATTR_TXT_CMD;
+
+/* GetAppValueTxt */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t attr_id;
+ uint8_t num_val;
+ uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_GET_APP_VAL_TXT_CMD;
+
+/* InformCharset */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t num_id;
+ uint16_t charsets[AVRC_MAX_CHARSET_SIZE];
+} tAVRC_INFORM_CHARSET_CMD;
+
+/* InformBatteryStatus */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t battery_status;
+} tAVRC_BATTERY_STATUS_CMD;
+
+/* GetElemAttrs */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t num_attr;
+ uint32_t attrs[AVRC_MAX_ELEM_ATTR_SIZE];
+} tAVRC_GET_ELEM_ATTRS_CMD;
+
+/* RegNotify */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t event_id;
+ uint32_t param;
+} tAVRC_REG_NOTIF_CMD;
+
+/* SetAddrPlayer */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint16_t player_id;
+} tAVRC_SET_ADDR_PLAYER_CMD;
+
+/* SetBrowsedPlayer */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint16_t player_id;
+} tAVRC_SET_BR_PLAYER_CMD;
+
+/* SetAbsVolume */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t volume;
+} tAVRC_SET_VOLUME_CMD;
+
+/* GetFolderItems */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t scope;
+ uint32_t start_item;
+ uint32_t end_item;
+ uint8_t attr_count;
+ uint32_t* p_attr_list;
+} tAVRC_GET_ITEMS_CMD;
+
+/* ChangePath */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint16_t uid_counter;
+ uint8_t direction;
+ tAVRC_UID folder_uid;
+} tAVRC_CHG_PATH_CMD;
+
+/* GetItemAttrs */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t scope;
+ tAVRC_UID uid;
+ uint16_t uid_counter;
+ uint8_t attr_count;
+ uint32_t* p_attr_list;
+} tAVRC_GET_ATTRS_CMD;
+
+/* Search */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ tAVRC_FULL_NAME string;
+} tAVRC_SEARCH_CMD;
+
+/* PlayItem */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t scope;
+ tAVRC_UID uid;
+ uint16_t uid_counter;
+} tAVRC_PLAY_ITEM_CMD;
+
+/* AddToNowPlaying */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t scope;
+ tAVRC_UID uid;
+ uint16_t uid_counter;
+} tAVRC_ADD_TO_PLAY_CMD;
+
+/* GetTotalNumOfItems */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t scope;
+} tAVRC_GET_NUM_OF_ITEMS_CMD;
+
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+} tAVRC_CMD;
+
+/* Continue and Abort */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (assigned by AVRC_BldCommand according to pdu) */
+ uint8_t target_pdu;
+} tAVRC_NEXT_CMD;
+
+typedef union {
+ uint8_t pdu;
+ tAVRC_CMD cmd;
+ tAVRC_GET_CAPS_CMD get_caps; /* GetCapability */
+ tAVRC_CMD list_app_attr; /* ListPlayerAppAttr */
+ tAVRC_LIST_APP_VALUES_CMD list_app_values; /* ListPlayerAppValues */
+ tAVRC_GET_CUR_APP_VALUE_CMD get_cur_app_val; /* GetCurAppValue */
+ tAVRC_SET_APP_VALUE_CMD set_app_val; /* SetAppValue */
+ tAVRC_GET_APP_ATTR_TXT_CMD get_app_attr_txt; /* GetAppAttrTxt */
+ tAVRC_GET_APP_VAL_TXT_CMD get_app_val_txt; /* GetAppValueTxt */
+ tAVRC_INFORM_CHARSET_CMD inform_charset; /* InformCharset */
+ tAVRC_BATTERY_STATUS_CMD inform_battery_status; /* InformBatteryStatus */
+ tAVRC_GET_ELEM_ATTRS_CMD get_elem_attrs; /* GetElemAttrs */
+ tAVRC_CMD get_play_status; /* GetPlayStatus */
+ tAVRC_REG_NOTIF_CMD reg_notif; /* RegNotify */
+ tAVRC_NEXT_CMD continu; /* Continue */
+ tAVRC_NEXT_CMD abort; /* Abort */
+
+ tAVRC_SET_ADDR_PLAYER_CMD addr_player; /* SetAddrPlayer */
+ tAVRC_SET_VOLUME_CMD volume; /* SetAbsVolume */
+ tAVRC_SET_BR_PLAYER_CMD br_player; /* SetBrowsedPlayer */
+ tAVRC_GET_ITEMS_CMD get_items; /* GetFolderItems */
+ tAVRC_CHG_PATH_CMD chg_path; /* ChangePath */
+ tAVRC_GET_ATTRS_CMD get_attrs; /* GetItemAttrs */
+ tAVRC_SEARCH_CMD search; /* Search */
+ tAVRC_PLAY_ITEM_CMD play_item; /* PlayItem */
+ tAVRC_ADD_TO_PLAY_CMD add_to_play; /* AddToNowPlaying */
+ tAVRC_GET_NUM_OF_ITEMS_CMD get_num_of_items; /* GetTotalNumOfItems */
+} tAVRC_COMMAND;
+
+/* GetCapability */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t capability_id;
+ uint8_t count;
+ tAVRC_CAPS_PARAM param;
+} tAVRC_GET_CAPS_RSP;
+
+/* ListPlayerAppAttr */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t num_attr;
+ uint8_t attrs[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_ATTR_RSP;
+
+/* ListPlayerAppValues */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t num_val;
+ uint8_t vals[AVRC_MAX_APP_ATTR_SIZE];
+} tAVRC_LIST_APP_VALUES_RSP;
+
+/* GetCurAppValue */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t num_val;
+ tAVRC_APP_SETTING* p_vals;
+} tAVRC_GET_CUR_APP_VALUE_RSP;
+
+/* GetAppAttrTxt */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t num_attr;
+ tAVRC_APP_SETTING_TEXT* p_attrs;
+} tAVRC_GET_APP_ATTR_TXT_RSP;
+
+/* GetPlayStatus */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint32_t song_len;
+ uint32_t song_pos;
+ uint8_t play_status;
+} tAVRC_GET_PLAY_STATUS_RSP;
+
+/* notification event parameter for AddressedPlayer change */
+typedef struct {
+ uint16_t player_id;
+ uint16_t uid_counter;
+} tAVRC_ADDR_PLAYER_PARAM;
+
+#ifndef AVRC_MAX_APP_SETTINGS
+#define AVRC_MAX_APP_SETTINGS 8
+#endif
+
+/* notification event parameter for Player Application setting change */
+typedef struct {
+ uint8_t num_attr;
+ uint8_t attr_id[AVRC_MAX_APP_SETTINGS];
+ uint8_t attr_value[AVRC_MAX_APP_SETTINGS];
+} tAVRC_PLAYER_APP_PARAM;
+
+typedef union {
+ tAVRC_PLAYSTATE play_status;
+ tAVRC_UID track;
+ uint32_t play_pos;
+ tAVRC_BATTERY_STATUS battery_status;
+ tAVRC_SYSTEMSTATE system_status;
+ tAVRC_PLAYER_APP_PARAM player_setting;
+ tAVRC_ADDR_PLAYER_PARAM addr_player;
+ uint16_t uid_counter;
+ uint8_t volume;
+} tAVRC_NOTIF_RSP_PARAM;
+
+/* RegNotify */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t event_id;
+ tAVRC_NOTIF_RSP_PARAM param;
+} tAVRC_REG_NOTIF_RSP;
+
+/* SetAbsVolume */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t volume;
+} tAVRC_SET_VOLUME_RSP;
+
+/* SetBrowsedPlayer */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint16_t uid_counter;
+ uint32_t num_items;
+ uint16_t charset_id;
+ uint8_t folder_depth;
+ tAVRC_NAME* p_folders;
+} tAVRC_SET_BR_PLAYER_RSP;
+
+/* GetFolderItems */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint16_t uid_counter;
+ uint16_t item_count;
+ tAVRC_ITEM* p_item_list;
+} tAVRC_GET_ITEMS_RSP;
+
+/* ChangePath */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint32_t num_items;
+} tAVRC_CHG_PATH_RSP;
+
+/* GetItemAttrs, GetElemAttrs */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t num_attrs;
+ tAVRC_ATTR_ENTRY* p_attrs;
+} tAVRC_GET_ATTRS_RSP;
+
+/* Get Total Number of Items */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint16_t uid_counter;
+ uint32_t num_items;
+} tAVRC_GET_NUM_OF_ITEMS_RSP;
+
+/* Search */
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint16_t uid_counter;
+ uint32_t num_items;
+} tAVRC_SEARCH_RSP;
+
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+ uint8_t target_pdu;
+} tAVRC_NEXT_RSP;
+
+typedef struct {
+ uint8_t pdu;
+ tAVRC_STS status;
+ uint8_t opcode; /* Op Code (copied from avrc_cmd.opcode by AVRC_BldResponse
+ user. invalid one to generate according to pdu) */
+} tAVRC_RSP;
+
+typedef union {
+ uint8_t pdu;
+ tAVRC_RSP rsp;
+ tAVRC_GET_CAPS_RSP get_caps; /* GetCapability */
+ tAVRC_LIST_APP_ATTR_RSP list_app_attr; /* ListPlayerAppAttr */
+ tAVRC_LIST_APP_VALUES_RSP list_app_values; /* ListPlayerAppValues */
+ tAVRC_GET_CUR_APP_VALUE_RSP get_cur_app_val; /* GetCurAppValue */
+ tAVRC_RSP set_app_val; /* SetAppValue */
+ tAVRC_GET_APP_ATTR_TXT_RSP get_app_attr_txt; /* GetAppAttrTxt */
+ tAVRC_GET_APP_ATTR_TXT_RSP get_app_val_txt; /* GetAppValueTxt */
+ tAVRC_RSP inform_charset; /* InformCharset */
+ tAVRC_RSP inform_battery_status; /* InformBatteryStatus */
+ tAVRC_GET_PLAY_STATUS_RSP get_play_status; /* GetPlayStatus */
+ tAVRC_REG_NOTIF_RSP reg_notif; /* RegNotify */
+ tAVRC_NEXT_RSP continu; /* Continue */
+ tAVRC_NEXT_RSP abort; /* Abort */
+ tAVRC_RSP addr_player; /* SetAddrPlayer */
+ tAVRC_SET_VOLUME_RSP volume; /* SetAbsVolume */
+ tAVRC_SET_BR_PLAYER_RSP br_player; /* SetBrowsedPlayer */
+ tAVRC_GET_ITEMS_RSP get_items; /* GetFolderItems */
+ tAVRC_CHG_PATH_RSP chg_path; /* ChangePath */
+ tAVRC_GET_ATTRS_RSP get_attrs; /* GetItemAttrs, GetElemAttrs */
+ tAVRC_GET_NUM_OF_ITEMS_RSP get_num_of_items; /* GetTotalNumberOfItems */
+ tAVRC_SEARCH_RSP search; /* Search */
+ tAVRC_RSP play_item; /* PlayItem */
+ tAVRC_RSP add_to_play; /* AddToNowPlaying */
+} tAVRC_RESPONSE;
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/ble_advertiser.h b/mtkbt/code/bt/stack/include/ble_advertiser.h
new file mode 100755
index 0000000..a2abead
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/ble_advertiser.h
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BLE_ADVERTISER_H
+#define BLE_ADVERTISER_H
+
+#include <base/bind.h>
+#include <vector>
+#include "btm_ble_api.h"
+
+#define BTM_BLE_MULTI_ADV_SUCCESS 0
+#define BTM_BLE_MULTI_ADV_FAILURE 1
+#define ADVERTISE_FAILED_TOO_MANY_ADVERTISERS 0x02
+
+using MultiAdvCb = base::Callback<void(uint8_t /* status */)>;
+using ParametersCb =
+ base::Callback<void(uint8_t /* status */, int8_t /* tx_power */)>;
+
+// methods we must have defined
+void btm_ble_update_dmt_flag_bits(uint8_t* flag_value,
+ const uint16_t connect_mode,
+ const uint16_t disc_mode);
+/** M: fix truncated conn_handle to uint16_t type @{ */
+void btm_acl_update_conn_addr(uint16_t conn_handle, BD_ADDR address);
+/** @} */
+// methods we expose to c code:
+void btm_ble_multi_adv_cleanup(void);
+void btm_ble_multi_adv_init();
+
+typedef struct {
+ uint16_t advertising_event_properties;
+ uint32_t adv_int_min;
+ uint32_t adv_int_max;
+ tBTM_BLE_ADV_CHNL_MAP channel_map;
+ tBTM_BLE_AFP adv_filter_policy;
+ int8_t tx_power;
+ uint8_t primary_advertising_phy;
+ uint8_t secondary_advertising_phy;
+ uint8_t scan_request_notification_enable;
+} tBTM_BLE_ADV_PARAMS;
+
+typedef struct {
+ uint8_t enable;
+ uint16_t min_interval;
+ uint16_t max_interval;
+ uint16_t periodic_advertising_properties;
+} tBLE_PERIODIC_ADV_PARAMS;
+
+class BleAdvertiserHciInterface;
+
+class BleAdvertisingManager {
+ public:
+ virtual ~BleAdvertisingManager() = default;
+
+ static const uint16_t advertising_prop_legacy_connectable = 0x0011;
+ static const uint16_t advertising_prop_legacy_non_connectable = 0x0010;
+
+ static void Initialize(BleAdvertiserHciInterface* interface);
+ static void CleanUp();
+ static BleAdvertisingManager* Get();
+
+ /* Register an advertising instance, status will be returned in |cb|
+ * callback, with assigned id, if operation succeeds. Instance is freed when
+ * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any
+ * of the operations fails.
+ * The instance will have data set to |advertise_data|, scan response set to
+ * |scan_response_data|, and will be enabled.
+ */
+ virtual void StartAdvertising(uint8_t advertiser_id, MultiAdvCb cb,
+ tBTM_BLE_ADV_PARAMS* params,
+ std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data,
+ int duration, MultiAdvCb timeout_cb) = 0;
+
+ /* Register an advertising instance, status will be returned in |cb|
+ * callback, with assigned id, if operation succeeds. Instance is freed when
+ * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any
+ * of the operations fails.
+ * The instance will have data set to |advertise_data|, scan response set to
+ * |scan_response_data|, periodic data set to |periodic_data| and will be
+ * enabled.
+ */
+ virtual void StartAdvertisingSet(
+ base::Callback<void(uint8_t /* inst_id */, int8_t /* tx_power */,
+ uint8_t /* status */)>
+ cb,
+ tBTM_BLE_ADV_PARAMS* params, std::vector<uint8_t> advertise_data,
+ std::vector<uint8_t> scan_response_data,
+ tBLE_PERIODIC_ADV_PARAMS* periodic_params,
+ std::vector<uint8_t> periodic_data, uint16_t duration,
+ uint8_t maxExtAdvEvents,
+ base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>
+ timeout_cb) = 0;
+
+ /* Register an advertising instance, status will be returned in |cb|
+ * callback, with assigned id, if operation succeeds. Instance is freed when
+ * advertising is disabled by calling |BTM_BleDisableAdvInstance|, or when any
+ * of the operations fails. */
+ virtual void RegisterAdvertiser(
+ base::Callback<void(uint8_t /* inst_id */, uint8_t /* status */)>) = 0;
+
+ /* This function enables/disables an advertising instance. Operation status is
+ * returned in |cb| */
+ virtual void Enable(uint8_t inst_id, bool enable, MultiAdvCb cb,
+ uint16_t duration, uint8_t maxExtAdvEvents,
+ MultiAdvCb timeout_cb) = 0;
+
+ /* This function update a Multi-ADV instance with the specififed adv
+ * parameters. */
+ virtual void SetParameters(uint8_t inst_id, tBTM_BLE_ADV_PARAMS* p_params,
+ ParametersCb cb) = 0;
+
+ /* This function configure a Multi-ADV instance with the specified adv data or
+ * scan response data.*/
+ virtual void SetData(uint8_t inst_id, bool is_scan_rsp,
+ std::vector<uint8_t> data, MultiAdvCb cb) = 0;
+
+ /* This function configure instance with the specified periodic parameters */
+ virtual void SetPeriodicAdvertisingParameters(
+ uint8_t inst_id, tBLE_PERIODIC_ADV_PARAMS* params, MultiAdvCb cb) = 0;
+
+ /* This function configure instance with the specified periodic data */
+ virtual void SetPeriodicAdvertisingData(uint8_t inst_id,
+ std::vector<uint8_t> data,
+ MultiAdvCb cb) = 0;
+
+ /* This function enables/disables periodic advertising on selected instance */
+ virtual void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable,
+ MultiAdvCb cb) = 0;
+
+ /* This function disable a Multi-ADV instance */
+ virtual void Unregister(uint8_t inst_id) = 0;
+
+ /* This method is a member of BleAdvertiserHciInterface, and is exposed here
+ * just for tests. It should never be called from upper layers*/
+ virtual void OnAdvertisingSetTerminated(
+ uint8_t status, uint8_t advertising_handle, uint16_t connection_handle,
+ uint8_t num_completed_extended_adv_events) = 0;
+
+ using GetAddressCallback =
+ base::Callback<void(uint8_t /* address_type*/, bt_bdaddr_t /*address*/)>;
+ virtual void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) = 0;
+};
+
+#endif // BLE_ADVERTISER_H
diff --git a/mtkbt/code/bt/stack/include/bnep_api.h b/mtkbt/code/bt/stack/include/bnep_api.h
new file mode 100755
index 0000000..95b6122
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/bnep_api.h
@@ -0,0 +1,428 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This interface file contains the interface to the Bluetooth Network
+ * Encapsilation Protocol (BNEP).
+ *
+ ******************************************************************************/
+#ifndef BNEP_API_H
+#define BNEP_API_H
+
+#include "l2c_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+ * sending BNEP packets. Note, we are currently not sending
+ * extension headers, but may in the future, so allow
+ * space for them
+*/
+#define BNEP_MINIMUM_OFFSET (15 + L2CAP_MIN_OFFSET)
+#define BNEP_INVALID_HANDLE 0xFFFF
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/* Define the result codes from BNEP
+*/
+enum {
+ BNEP_SUCCESS, /* Success */
+ BNEP_CONN_DISCONNECTED, /* Connection terminated */
+ BNEP_NO_RESOURCES, /* No resources */
+ BNEP_MTU_EXCEDED, /* Attempt to write long data */
+ BNEP_INVALID_OFFSET, /* Insufficient offset in GKI buffer */
+ BNEP_CONN_FAILED, /* Connection failed */
+ BNEP_CONN_FAILED_CFG, /* Connection failed cos of config */
+ BNEP_CONN_FAILED_SRC_UUID, /* Connection failed wrong source UUID */
+ BNEP_CONN_FAILED_DST_UUID, /* Connection failed wrong destination UUID */
+ BNEP_CONN_FAILED_UUID_SIZE, /* Connection failed wrong size UUID */
+ BNEP_Q_SIZE_EXCEEDED, /* Too many buffers to dest */
+ BNEP_TOO_MANY_FILTERS, /* Too many local filters specified */
+ BNEP_SET_FILTER_FAIL, /* Set Filter failed */
+ BNEP_WRONG_HANDLE, /* Wrong handle for the connection */
+ BNEP_WRONG_STATE, /* Connection is in wrong state */
+ BNEP_SECURITY_FAIL, /* Failed because of security */
+ BNEP_IGNORE_CMD, /* To ignore the rcvd command */
+ BNEP_TX_FLOW_ON, /* tx data flow enabled */
+ BNEP_TX_FLOW_OFF /* tx data flow disabled */
+
+};
+typedef uint8_t tBNEP_RESULT;
+
+/***************************
+ * Callback Functions
+ ***************************/
+
+/* Connection state change callback prototype. Parameters are
+ * Connection handle
+ * BD Address of remote
+ * Connection state change result
+ * BNEP_SUCCESS indicates connection is success
+ * All values are used to indicate the reason for failure
+ * Flag to indicate if it is just a role change
+*/
+typedef void(tBNEP_CONN_STATE_CB)(uint16_t handle, BD_ADDR rem_bda,
+ tBNEP_RESULT result, bool is_role_change);
+
+/* Connection indication callback prototype. Parameters are
+ * BD Address of remote, remote UUID and local UUID
+ * and flag to indicate role change and handle to the connection
+ * When BNEP calls this function profile should
+ * use BNEP_ConnectResp call to accept or reject the request
+*/
+typedef void(tBNEP_CONNECT_IND_CB)(uint16_t handle, BD_ADDR bd_addr,
+ tBT_UUID* remote_uuid, tBT_UUID* local_uuid,
+ bool is_role_change);
+
+/* Data buffer received indication callback prototype. Parameters are
+ * Handle to the connection
+ * Source BD/Ethernet Address
+ * Dest BD/Ethernet address
+ * Protocol
+ * Pointer to the buffer
+ * Flag to indicate whether extension headers to be forwarded are
+ * present
+ */
+typedef void(tBNEP_DATA_BUF_CB)(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, BT_HDR* p_buf,
+ bool fw_ext_present);
+
+/* Data received indication callback prototype. Parameters are
+ * Handle to the connection
+ * Source BD/Ethernet Address
+ * Dest BD/Ethernet address
+ * Protocol
+ * Pointer to the beginning of the data
+ * Length of data
+ * Flag to indicate whether extension headers to be forwarded are
+ * present
+ */
+typedef void(tBNEP_DATA_IND_CB)(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, uint8_t* p_data,
+ uint16_t len, bool fw_ext_present);
+
+/* Flow control callback for TX data. Parameters are
+ * Handle to the connection
+ * Event flow status
+*/
+typedef void(tBNEP_TX_DATA_FLOW_CB)(uint16_t handle, tBNEP_RESULT event);
+
+/* Filters received indication callback prototype. Parameters are
+ * Handle to the connection
+ * true if the cb is called for indication
+ * Ignore this if it is indication, otherwise it is the result
+ * for the filter set operation performed by the local
+ * device
+ * Number of protocol filters present
+ * Pointer to the filters start. Filters are present in pairs
+ * of start of the range and end of the range.
+ * They will be present in big endian order. First
+ * two bytes will be starting of the first range and
+ * next two bytes will be ending of the range.
+*/
+typedef void(tBNEP_FILTER_IND_CB)(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters);
+
+/* Multicast Filters received indication callback prototype. Parameters are
+ * Handle to the connection
+ * true if the cb is called for indication
+ * Ignore this if it is indication, otherwise it is the result
+ * for the filter set operation performed by the local
+ * device
+ * Number of multicast filters present
+ * Pointer to the filters start. Filters are present in pairs
+ * of start of the range and end of the range.
+ * First six bytes will be starting of the first range and
+ * next six bytes will be ending of the range.
+*/
+typedef void(tBNEP_MFILTER_IND_CB)(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_mfilters,
+ uint8_t* p_mfilters);
+
+/* This is the structure used by profile to register with BNEP */
+typedef struct {
+ tBNEP_CONNECT_IND_CB* p_conn_ind_cb; /* To indicate the conn request */
+ tBNEP_CONN_STATE_CB* p_conn_state_cb; /* To indicate conn state change */
+ tBNEP_DATA_IND_CB* p_data_ind_cb; /* To pass the data received */
+ tBNEP_DATA_BUF_CB* p_data_buf_cb; /* To pass the data buffer received */
+ tBNEP_TX_DATA_FLOW_CB* p_tx_data_flow_cb; /* data flow callback */
+ tBNEP_FILTER_IND_CB*
+ p_filter_ind_cb; /* To indicate that peer set protocol filters */
+ tBNEP_MFILTER_IND_CB*
+ p_mfilter_ind_cb; /* To indicate that peer set mcast filters */
+
+} tBNEP_REGISTER;
+
+/* This is the structure used by profile to get the status of BNEP */
+typedef struct {
+#define BNEP_STATUS_FAILE 0
+#define BNEP_STATUS_CONNECTED 1
+ uint8_t con_status;
+
+ uint16_t l2cap_cid;
+ BD_ADDR rem_bda;
+ uint16_t rem_mtu_size;
+ uint16_t xmit_q_depth;
+
+ uint16_t sent_num_filters;
+ uint16_t sent_mcast_filters;
+ uint16_t rcvd_num_filters;
+ uint16_t rcvd_mcast_filters;
+ tBT_UUID src_uuid;
+ tBT_UUID dst_uuid;
+
+} tBNEP_STATUS;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BNEP_Register
+ *
+ * Description This function is called by the upper layer to register
+ * its callbacks with BNEP
+ *
+ * Parameters: p_reg_info - contains all callback function pointers
+ *
+ *
+ * Returns BNEP_SUCCESS if registered successfully
+ * BNEP_FAILURE if connection state callback is missing
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_Register(tBNEP_REGISTER* p_reg_info);
+
+/*******************************************************************************
+ *
+ * Function BNEP_Deregister
+ *
+ * Description This function is called by the upper layer to de-register
+ * its callbacks.
+ *
+ * Parameters: void
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BNEP_Deregister(void);
+
+/*******************************************************************************
+ *
+ * Function BNEP_Connect
+ *
+ * Description This function creates a BNEP connection to a remote
+ * device.
+ *
+ * Parameters: p_rem_addr - BD_ADDR of the peer
+ * src_uuid - source uuid for the connection
+ * dst_uuid - destination uuid for the connection
+ * p_handle - pointer to return the handle for the connection
+ *
+ * Returns BNEP_SUCCESS if connection started
+ * BNEP_NO_RESOURCES if no resources
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_Connect(BD_ADDR p_rem_bda, tBT_UUID* src_uuid,
+ tBT_UUID* dst_uuid, uint16_t* p_handle);
+
+/*******************************************************************************
+ *
+ * Function BNEP_ConnectResp
+ *
+ * Description This function is called in responce to connection indication
+ *
+ *
+ * Parameters: handle - handle given in the connection indication
+ * resp - responce for the connection indication
+ *
+ * Returns BNEP_SUCCESS if connection started
+ * BNEP_WRONG_HANDLE if the connection is not found
+ * BNEP_WRONG_STATE if the responce is not expected
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_ConnectResp(uint16_t handle, tBNEP_RESULT resp);
+
+/*******************************************************************************
+ *
+ * Function BNEP_Disconnect
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - handle of the connection
+ *
+ * Returns BNEP_SUCCESS if connection is disconnected
+ * BNEP_WRONG_HANDLE if no connection is not found
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_Disconnect(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function BNEP_WriteBuf
+ *
+ * Description This function sends data in a GKI buffer on BNEP connection
+ *
+ * Parameters: handle - handle of the connection to write
+ * p_dest_addr - BD_ADDR/Ethernet addr of the destination
+ * p_buf - pointer to address of buffer with data
+ * protocol - protocol type of the packet
+ * p_src_addr - (optional) BD_ADDR/ethernet address of the
+ * source (should be NULL if it is the local BD
+ * Addr)
+ * fw_ext_present - forwarded extensions present
+ *
+ * Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+ * BNEP_MTU_EXCEDED - If the data length is greater
+ * than MTU
+ * BNEP_IGNORE_CMD - If the packet is filtered out
+ * BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+ * BNEP_SUCCESS - If written successfully
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_WriteBuf(uint16_t handle, uint8_t* p_dest_addr,
+ BT_HDR* p_buf, uint16_t protocol,
+ uint8_t* p_src_addr, bool fw_ext_present);
+
+/*******************************************************************************
+ *
+ * Function BNEP_Write
+ *
+ * Description This function sends data over a BNEP connection
+ *
+ * Parameters: handle - handle of the connection to write
+ * p_dest_addr - BD_ADDR/Ethernet addr of the destination
+ * p_data - pointer to data start
+ * protocol - protocol type of the packet
+ * p_src_addr - (optional) BD_ADDR/ethernet address of the
+ * source (should be NULL if it is the local BD
+ * Addr)
+ * fw_ext_present - forwarded extensions present
+ *
+ * Returns: BNEP_WRONG_HANDLE - if passed handle is not valid
+ * BNEP_MTU_EXCEDED - If the data length is greater than
+ * the MTU
+ * BNEP_IGNORE_CMD - If the packet is filtered out
+ * BNEP_Q_SIZE_EXCEEDED - If the Tx Q is full
+ * BNEP_NO_RESOURCES - If not able to allocate a buffer
+ * BNEP_SUCCESS - If written successfully
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_Write(uint16_t handle, uint8_t* p_dest_addr,
+ uint8_t* p_data, uint16_t len, uint16_t protocol,
+ uint8_t* p_src_addr, bool fw_ext_present);
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetProtocolFilters
+ *
+ * Description This function sets the protocol filters on peer device
+ *
+ * Parameters: handle - Handle for the connection
+ * num_filters - total number of filter ranges
+ * p_start_array - Array of beginings of all protocol ranges
+ * p_end_array - Array of ends of all protocol ranges
+ *
+ * Returns BNEP_WRONG_HANDLE - if the connection handle is
+ * not valid
+ * BNEP_SET_FILTER_FAIL - if the connection is in the
+ * wrong state
+ * BNEP_TOO_MANY_FILTERS - if too many filters
+ * BNEP_SUCCESS - if request sent successfully
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_SetProtocolFilters(uint16_t handle,
+ uint16_t num_filters,
+ uint16_t* p_start_array,
+ uint16_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetMulticastFilters
+ *
+ * Description This function sets the filters for multicast addresses for
+ * BNEP.
+ *
+ * Parameters: handle - Handle for the connection
+ * num_filters - total number of filter ranges
+ * p_start_array - Pointer to sequence of beginings of all
+ * multicast address ranges
+ * p_end_array - Pointer to sequence of ends of all
+ * multicast address ranges
+ *
+ * Returns BNEP_WRONG_HANDLE - if the connection handle is
+ * not valid
+ * BNEP_SET_FILTER_FAIL - if the connection is in the
+ * wrong state
+ * BNEP_TOO_MANY_FILTERS - if too many filters
+ * BNEP_SUCCESS - if request sent successfully
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_SetMulticastFilters(uint16_t handle,
+ uint16_t num_filters,
+ uint8_t* p_start_array,
+ uint8_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function BNEP_SetTraceLevel
+ *
+ * Description This function sets the trace level for BNEP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t BNEP_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function BNEP_Init
+ *
+ * Description This function initializes the BNEP unit. It should be called
+ * before accessing any other APIs to initialize the control
+ * block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BNEP_Init(void);
+
+/*******************************************************************************
+ *
+ * Function BNEP_GetStatus
+ *
+ * Description This function gets the status information for BNEP
+ * connection
+ *
+ * Returns BNEP_SUCCESS - if the status is available
+ * BNEP_NO_RESOURCES - if no structure is passed for
+ * output
+ * BNEP_WRONG_HANDLE - if the handle is invalid
+ * BNEP_WRONG_STATE - if not in connected state
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT BNEP_GetStatus(uint16_t handle, tBNEP_STATUS* p_status);
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/bt_types.h b/mtkbt/code/bt/stack/include/bt_types.h
new file mode 100755
index 0000000..da0baac
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/bt_types.h
@@ -0,0 +1,1015 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BT_TYPES_H
+#define BT_TYPES_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#ifndef TRUE
+#define TRUE true
+#endif
+
+#ifdef __arm
+#define PACKED __packed
+#define INLINE __inline
+#else
+#define PACKED
+#define INLINE
+#endif
+
+/* READ WELL !!
+ *
+ * This section defines global events. These are events that cross layers.
+ * Any event that passes between layers MUST be one of these events. Tasks
+ * can use their own events internally, but a FUNDAMENTAL design issue is
+ * that global events MUST be one of these events defined below.
+ *
+ * The convention used is the the event name contains the layer that the
+ * event is going to.
+*/
+#define BT_EVT_MASK 0xFF00
+#define BT_SUB_EVT_MASK 0x00FF
+/* To Bluetooth Upper Layers */
+/************************************/
+/* L2CAP event */
+#define BT_EVT_TO_BTU_L2C_EVT 0x0900
+/* HCI Event */
+#define BT_EVT_TO_BTU_HCI_EVT 0x1000
+/* event from BR/EDR controller */
+#define BT_EVT_TO_BTU_HCI_BR_EDR_EVT (0x0000 | BT_EVT_TO_BTU_HCI_EVT)
+/* event from local AMP 1 controller */
+#define BT_EVT_TO_BTU_HCI_AMP1_EVT (0x0001 | BT_EVT_TO_BTU_HCI_EVT)
+/* event from local AMP 2 controller */
+#define BT_EVT_TO_BTU_HCI_AMP2_EVT (0x0002 | BT_EVT_TO_BTU_HCI_EVT)
+/* event from local AMP 3 controller */
+#define BT_EVT_TO_BTU_HCI_AMP3_EVT (0x0003 | BT_EVT_TO_BTU_HCI_EVT)
+
+/* ACL Data from HCI */
+#define BT_EVT_TO_BTU_HCI_ACL 0x1100
+/* SCO Data from HCI */
+#define BT_EVT_TO_BTU_HCI_SCO 0x1200
+/* HCI Transport Error */
+#define BT_EVT_TO_BTU_HCIT_ERR 0x1300
+
+/* Serial Port Event */
+#define BT_EVT_TO_BTU_SP_EVT 0x1400
+/* Serial Port Data */
+#define BT_EVT_TO_BTU_SP_DATA 0x1500
+
+/* HCI command from upper layer */
+#define BT_EVT_TO_BTU_HCI_CMD 0x1600
+
+/* L2CAP segment(s) transmitted */
+#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900
+
+/* BlueStackTester event: incoming message from target */
+#define BT_EVT_PROXY_INCOMING_MSG 0x1A00
+
+/* Insight BTSIM event */
+#define BT_EVT_BTSIM 0x1B00
+/* Insight Script Engine event */
+#define BT_EVT_BTISE 0x1C00
+
+/* To LM */
+/************************************/
+/* HCI Command */
+#define BT_EVT_TO_LM_HCI_CMD 0x2000
+/* HCI ACL Data */
+#define BT_EVT_TO_LM_HCI_ACL 0x2100
+/* HCI SCO Data */
+#define BT_EVT_TO_LM_HCI_SCO 0x2200
+/* HCI Transport Error */
+#define BT_EVT_TO_LM_HCIT_ERR 0x2300
+/* LC event */
+#define BT_EVT_TO_LM_LC_EVT 0x2400
+/* LC Received LMP command frame */
+#define BT_EVT_TO_LM_LC_LMP 0x2500
+/* LC Received ACL data */
+#define BT_EVT_TO_LM_LC_ACL 0x2600
+/* LC Received SCO data (not used) */
+#define BT_EVT_TO_LM_LC_SCO 0x2700
+/* LMP data transmit complete */
+#define BT_EVT_TO_LM_LC_ACL_TX 0x2800
+/* LMP Command transmit complete */
+#define BT_EVT_TO_LM_LC_LMPC_TX 0x2900
+/* Data to be locally loopbacked */
+#define BT_EVT_TO_LM_LOCAL_ACL_LB 0x2a00
+/* HCI ACL Data ack (not used) */
+#define BT_EVT_TO_LM_HCI_ACL_ACK 0x2b00
+/* LM Diagnostics commands */
+#define BT_EVT_TO_LM_DIAG 0x2c00
+
+#define BT_EVT_TO_BTM_CMDS 0x2f00
+#define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS)
+
+#define BT_EVT_TO_TCS_CMDS 0x3000
+
+#define BT_EVT_TO_CTP_CMDS 0x3300
+
+/* ftp events */
+#define BT_EVT_TO_FTP_SRVR_CMDS 0x3600
+#define BT_EVT_TO_FTP_CLNT_CMDS 0x3700
+
+/* SIM Access Profile events */
+#define BT_EVT_TO_BTU_SAP 0x3800
+
+/* opp events */
+#define BT_EVT_TO_OPP_SRVR_CMDS 0x3900
+#define BT_EVT_TO_OPP_CLNT_CMDS 0x3a00
+
+/* gap events */
+#define BT_EVT_TO_GAP_MSG 0x3b00
+
+/* for NFC */
+/************************************/
+/* NCI Command, Notification or Data*/
+#define BT_EVT_TO_NFC_NCI 0x4000
+/* Initialization message */
+#define BT_EVT_TO_NFC_INIT 0x4100
+/* Low power */
+#define BT_EVT_TO_NCI_LP 0x4200
+/* Error notification to NFC Task */
+#define BT_EVT_TO_NFC_ERR 0x4300
+
+/* events to NFCC simulation (NCI packets) */
+#define BT_EVT_TO_NFCCSIM_NCI 0x4a00
+
+/* HCISU Events */
+
+#define BT_EVT_HCISU 0x5000
+
+#define BT_EVT_TO_HCISU_RECONFIG_EVT (0x0001 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_UPDATE_BAUDRATE_EVT (0x0002 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ENABLE_EVT (0x0003 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_DISABLE_EVT (0x0004 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_APP_SLEEPING_EVT (0x0005 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_ALLOW_BT_SLEEP_EVT (0x0006 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_WAKEUP_HOST_EVT (0x0007 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_LP_RCV_H4IBSS_EVT (0x0008 | BT_EVT_HCISU)
+#define BT_EVT_TO_HCISU_H5_RESET_EVT (0x0009 | BT_EVT_HCISU)
+#define BT_EVT_HCISU_START_QUICK_TIMER (0x000a | BT_EVT_HCISU)
+
+#define BT_EVT_DATA_TO_AMP_1 0x5100
+#define BT_EVT_DATA_TO_AMP_15 0x5f00
+
+/* HSP Events */
+
+#define BT_EVT_BTU_HSP2 0x6000
+
+#define BT_EVT_TO_BTU_HSP2_EVT (0x0001 | BT_EVT_BTU_HSP2)
+
+/* BPP Events */
+#define BT_EVT_TO_BPP_PR_CMDS 0x6100 /* Printer Events */
+#define BT_EVT_TO_BPP_SND_CMDS 0x6200 /* BPP Sender Events */
+
+/* BIP Events */
+#define BT_EVT_TO_BIP_CMDS 0x6300
+
+/* HCRP Events */
+
+#define BT_EVT_BTU_HCRP 0x7000
+
+#define BT_EVT_TO_BTU_HCRP_EVT (0x0001 | BT_EVT_BTU_HCRP)
+#define BT_EVT_TO_BTU_HCRPM_EVT (0x0002 | BT_EVT_BTU_HCRP)
+
+#define BT_EVT_BTU_HFP 0x8000
+#define BT_EVT_TO_BTU_HFP_EVT (0x0001 | BT_EVT_BTU_HFP)
+
+#define BT_EVT_BTU_IPC_EVT 0x9000
+#define BT_EVT_BTU_IPC_LOGMSG_EVT (0x0000 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_ACL_EVT (0x0001 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTU_EVT (0x0002 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_EVT (0x0003 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_MSG_EVT (0x0004 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTM_EVT (0x0005 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_AVDT_EVT (0x0006 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_SLIP_EVT (0x0007 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_MGMT_EVT (0x0008 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTTRC_EVT (0x0009 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BURST_EVT (0x000A | BT_EVT_BTU_IPC_EVT)
+
+/* BTIF Events */
+#define BT_EVT_BTIF 0xA000
+#define BT_EVT_CONTEXT_SWITCH_EVT (0x0001 | BT_EVT_BTIF)
+
+/* Define the header of each buffer used in the Bluetooth stack.
+*/
+typedef struct {
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+ uint8_t data[];
+} BT_HDR;
+
+#define BT_HDR_SIZE (sizeof(BT_HDR))
+
+#define BT_PSM_SDP 0x0001
+#define BT_PSM_RFCOMM 0x0003
+#define BT_PSM_TCS 0x0005
+#define BT_PSM_CTP 0x0007
+#define BT_PSM_BNEP 0x000F
+#define BT_PSM_HIDC 0x0011
+#define BT_PSM_HIDI 0x0013
+#define BT_PSM_UPNP 0x0015
+#define BT_PSM_AVCTP 0x0017
+#define BT_PSM_AVDTP 0x0019
+#define BT_PSM_AVCTP_13 0x001B /* Advanced Control - Browsing */
+#define BT_PSM_UDI_CP \
+ 0x001D /* Unrestricted Digital Information Profile C-Plane */
+#define BT_PSM_ATT 0x001F /* Attribute Protocol */
+
+/* These macros extract the HCI opcodes from a buffer
+*/
+#define HCI_GET_CMD_HDR_OPCODE(p) \
+ (uint16_t)((*((uint8_t*)((p) + 1) + (p)->offset) + \
+ (*((uint8_t*)((p) + 1) + (p)->offset + 1) << 8)))
+#define HCI_GET_CMD_HDR_PARAM_LEN(p) \
+ (uint8_t)(*((uint8_t*)((p) + 1) + (p)->offset + 2))
+
+#define HCI_GET_EVT_HDR_OPCODE(p) \
+ (uint8_t)(*((uint8_t*)((p) + 1) + (p)->offset))
+#define HCI_GET_EVT_HDR_PARAM_LEN(p) \
+ (uint8_t)(*((uint8_t*)((p) + 1) + (p)->offset + 1))
+
+/*******************************************************************************
+ * Macros to get and put bytes to and from a stream (Little Endian format).
+*/
+#define UINT64_TO_BE_STREAM(p, u64) \
+ { \
+ *(p)++ = (uint8_t)((u64) >> 56); \
+ *(p)++ = (uint8_t)((u64) >> 48); \
+ *(p)++ = (uint8_t)((u64) >> 40); \
+ *(p)++ = (uint8_t)((u64) >> 32); \
+ *(p)++ = (uint8_t)((u64) >> 24); \
+ *(p)++ = (uint8_t)((u64) >> 16); \
+ *(p)++ = (uint8_t)((u64) >> 8); \
+ *(p)++ = (uint8_t)(u64); \
+ }
+#define UINT32_TO_STREAM(p, u32) \
+ { \
+ *(p)++ = (uint8_t)(u32); \
+ *(p)++ = (uint8_t)((u32) >> 8); \
+ *(p)++ = (uint8_t)((u32) >> 16); \
+ *(p)++ = (uint8_t)((u32) >> 24); \
+ }
+#define UINT24_TO_STREAM(p, u24) \
+ { \
+ *(p)++ = (uint8_t)(u24); \
+ *(p)++ = (uint8_t)((u24) >> 8); \
+ *(p)++ = (uint8_t)((u24) >> 16); \
+ }
+#define UINT16_TO_STREAM(p, u16) \
+ { \
+ *(p)++ = (uint8_t)(u16); \
+ *(p)++ = (uint8_t)((u16) >> 8); \
+ }
+#define UINT8_TO_STREAM(p, u8) \
+ { *(p)++ = (uint8_t)(u8); }
+#define INT8_TO_STREAM(p, u8) \
+ { *(p)++ = (int8_t)(u8); }
+#define ARRAY32_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < 32; ijk++) *(p)++ = (uint8_t)(a)[31 - ijk]; \
+ }
+#define ARRAY16_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < 16; ijk++) *(p)++ = (uint8_t)(a)[15 - ijk]; \
+ }
+#define ARRAY8_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < 8; ijk++) *(p)++ = (uint8_t)(a)[7 - ijk]; \
+ }
+#define BDADDR_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) \
+ *(p)++ = (uint8_t)(a)[BD_ADDR_LEN - 1 - ijk]; \
+ }
+#define LAP_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < LAP_LEN; ijk++) \
+ *(p)++ = (uint8_t)(a)[LAP_LEN - 1 - ijk]; \
+ }
+#define DEVCLASS_TO_STREAM(p, a) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < DEV_CLASS_LEN; ijk++) \
+ *(p)++ = (uint8_t)(a)[DEV_CLASS_LEN - 1 - ijk]; \
+ }
+#define ARRAY_TO_STREAM(p, a, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t)(a)[ijk]; \
+ }
+#define REVERSE_ARRAY_TO_STREAM(p, a, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t)(a)[(len)-1 - ijk]; \
+ }
+
+#define STREAM_TO_INT8(u8, p) \
+ { \
+ (u8) = (*((int8_t*)p)); \
+ (p) += 1; \
+ }
+#define STREAM_TO_UINT8(u8, p) \
+ { \
+ (u8) = (uint8_t)(*(p)); \
+ (p) += 1; \
+ }
+#define STREAM_TO_UINT16(u16, p) \
+ { \
+ (u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
+ (p) += 2; \
+ }
+#define STREAM_TO_UINT24(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
+ ((((uint32_t)(*((p) + 2)))) << 16)); \
+ (p) += 3; \
+ }
+#define STREAM_TO_UINT32(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*(p))) + ((((uint32_t)(*((p) + 1)))) << 8) + \
+ ((((uint32_t)(*((p) + 2)))) << 16) + \
+ ((((uint32_t)(*((p) + 3)))) << 24)); \
+ (p) += 4; \
+ }
+#define STREAM_TO_BDADDR(a, p) \
+ { \
+ int ijk; \
+ uint8_t* pbda = (uint8_t*)(a) + BD_ADDR_LEN - 1; \
+ for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *(p)++; \
+ }
+#define STREAM_TO_ARRAY32(a, p) \
+ { \
+ int ijk; \
+ uint8_t* _pa = (uint8_t*)(a) + 31; \
+ for (ijk = 0; ijk < 32; ijk++) *_pa-- = *(p)++; \
+ }
+#define STREAM_TO_ARRAY16(a, p) \
+ { \
+ int ijk; \
+ uint8_t* _pa = (uint8_t*)(a) + 15; \
+ for (ijk = 0; ijk < 16; ijk++) *_pa-- = *(p)++; \
+ }
+#define STREAM_TO_ARRAY8(a, p) \
+ { \
+ int ijk; \
+ uint8_t* _pa = (uint8_t*)(a) + 7; \
+ for (ijk = 0; ijk < 8; ijk++) *_pa-- = *(p)++; \
+ }
+#define STREAM_TO_DEVCLASS(a, p) \
+ { \
+ int ijk; \
+ uint8_t* _pa = (uint8_t*)(a) + DEV_CLASS_LEN - 1; \
+ for (ijk = 0; ijk < DEV_CLASS_LEN; ijk++) *_pa-- = *(p)++; \
+ }
+#define STREAM_TO_LAP(a, p) \
+ { \
+ int ijk; \
+ uint8_t* plap = (uint8_t*)(a) + LAP_LEN - 1; \
+ for (ijk = 0; ijk < LAP_LEN; ijk++) *plap-- = *(p)++; \
+ }
+#define STREAM_TO_ARRAY(a, p, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) ((uint8_t*)(a))[ijk] = *(p)++; \
+ }
+#define REVERSE_STREAM_TO_ARRAY(a, p, len) \
+ { \
+ int ijk; \
+ uint8_t* _pa = (uint8_t*)(a) + (len)-1; \
+ for (ijk = 0; ijk < (len); ijk++) *_pa-- = *(p)++; \
+ }
+
+#define STREAM_SKIP_UINT8(p) \
+ do { \
+ (p) += 1; \
+ } while (0)
+#define STREAM_SKIP_UINT16(p) \
+ do { \
+ (p) += 2; \
+ } while (0)
+
+/*******************************************************************************
+ * Macros to get and put bytes to and from a field (Little Endian format).
+ * These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_FIELD(p, u32) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)(u32); \
+ *((uint8_t*)(p) + 1) = (uint8_t)((u32) >> 8); \
+ *((uint8_t*)(p) + 2) = (uint8_t)((u32) >> 16); \
+ *((uint8_t*)(p) + 3) = (uint8_t)((u32) >> 24); \
+ }
+#define UINT24_TO_FIELD(p, u24) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)(u24); \
+ *((uint8_t*)(p) + 1) = (uint8_t)((u24) >> 8); \
+ *((uint8_t*)(p) + 2) = (uint8_t)((u24) >> 16); \
+ }
+#define UINT16_TO_FIELD(p, u16) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)(u16); \
+ *((uint8_t*)(p) + 1) = (uint8_t)((u16) >> 8); \
+ }
+#define UINT8_TO_FIELD(p, u8) \
+ { *(uint8_t*)(p) = (uint8_t)(u8); }
+
+/*******************************************************************************
+ * Macros to get and put bytes to and from a stream (Big Endian format)
+*/
+#define UINT32_TO_BE_STREAM(p, u32) \
+ { \
+ *(p)++ = (uint8_t)((u32) >> 24); \
+ *(p)++ = (uint8_t)((u32) >> 16); \
+ *(p)++ = (uint8_t)((u32) >> 8); \
+ *(p)++ = (uint8_t)(u32); \
+ }
+#define UINT24_TO_BE_STREAM(p, u24) \
+ { \
+ *(p)++ = (uint8_t)((u24) >> 16); \
+ *(p)++ = (uint8_t)((u24) >> 8); \
+ *(p)++ = (uint8_t)(u24); \
+ }
+#define UINT16_TO_BE_STREAM(p, u16) \
+ { \
+ *(p)++ = (uint8_t)((u16) >> 8); \
+ *(p)++ = (uint8_t)(u16); \
+ }
+#define UINT8_TO_BE_STREAM(p, u8) \
+ { *(p)++ = (uint8_t)(u8); }
+#define ARRAY_TO_BE_STREAM(p, a, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t)(a)[ijk]; \
+ }
+#define ARRAY_TO_BE_STREAM_REVERSE(p, a, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) *(p)++ = (uint8_t)(a)[(len)-ijk - 1]; \
+ }
+
+#define BE_STREAM_TO_UINT8(u8, p) \
+ { \
+ (u8) = (uint8_t)(*(p)); \
+ (p) += 1; \
+ }
+#define BE_STREAM_TO_UINT16(u16, p) \
+ { \
+ (u16) = (uint16_t)(((uint16_t)(*(p)) << 8) + (uint16_t)(*((p) + 1))); \
+ (p) += 2; \
+ }
+#define BE_STREAM_TO_UINT24(u32, p) \
+ { \
+ (u32) = (((uint32_t)(*((p) + 2))) + ((uint32_t)(*((p) + 1)) << 8) + \
+ ((uint32_t)(*(p)) << 16)); \
+ (p) += 3; \
+ }
+#define BE_STREAM_TO_UINT32(u32, p) \
+ { \
+ (u32) = ((uint32_t)(*((p) + 3)) + ((uint32_t)(*((p) + 2)) << 8) + \
+ ((uint32_t)(*((p) + 1)) << 16) + ((uint32_t)(*(p)) << 24)); \
+ (p) += 4; \
+ }
+#define BE_STREAM_TO_UINT64(u64, p) \
+ { \
+ (u64) = ((uint64_t)(*((p) + 7)) + ((uint64_t)(*((p) + 6)) << 8) + \
+ ((uint64_t)(*((p) + 5)) << 16) + ((uint64_t)(*((p) + 4)) << 24) + \
+ ((uint64_t)(*((p) + 3)) << 32) + ((uint64_t)(*((p) + 2)) << 40) + \
+ ((uint64_t)(*((p) + 1)) << 48) + ((uint64_t)(*(p)) << 56)); \
+ (p) += 8; \
+ }
+#define BE_STREAM_TO_ARRAY(p, a, len) \
+ { \
+ int ijk; \
+ for (ijk = 0; ijk < (len); ijk++) ((uint8_t*)(a))[ijk] = *(p)++; \
+ }
+
+/*******************************************************************************
+ * Macros to get and put bytes to and from a field (Big Endian format).
+ * These are the same as to stream, except the pointer is not incremented.
+*/
+#define UINT32_TO_BE_FIELD(p, u32) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)((u32) >> 24); \
+ *((uint8_t*)(p) + 1) = (uint8_t)((u32) >> 16); \
+ *((uint8_t*)(p) + 2) = (uint8_t)((u32) >> 8); \
+ *((uint8_t*)(p) + 3) = (uint8_t)(u32); \
+ }
+#define UINT24_TO_BE_FIELD(p, u24) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)((u24) >> 16); \
+ *((uint8_t*)(p) + 1) = (uint8_t)((u24) >> 8); \
+ *((uint8_t*)(p) + 2) = (uint8_t)(u24); \
+ }
+#define UINT16_TO_BE_FIELD(p, u16) \
+ { \
+ *(uint8_t*)(p) = (uint8_t)((u16) >> 8); \
+ *((uint8_t*)(p) + 1) = (uint8_t)(u16); \
+ }
+#define UINT8_TO_BE_FIELD(p, u8) \
+ { *(uint8_t*)(p) = (uint8_t)(u8); }
+
+/* Common Bluetooth field definitions */
+#define BD_ADDR_LEN 6 /* Device address length */
+typedef uint8_t BD_ADDR[BD_ADDR_LEN]; /* Device address */
+typedef uint8_t* BD_ADDR_PTR; /* Pointer to Device Address */
+
+#define AMP_KEY_TYPE_GAMP 0
+#define AMP_KEY_TYPE_WIFI 1
+#define AMP_KEY_TYPE_UWB 2
+typedef uint8_t tAMP_KEY_TYPE;
+
+#define BT_OCTET8_LEN 8
+typedef uint8_t BT_OCTET8[BT_OCTET8_LEN]; /* octet array: size 16 */
+
+#define LINK_KEY_LEN 16
+typedef uint8_t LINK_KEY[LINK_KEY_LEN]; /* Link Key */
+
+#define AMP_LINK_KEY_LEN 32
+typedef uint8_t
+ AMP_LINK_KEY[AMP_LINK_KEY_LEN]; /* Dedicated AMP and GAMP Link Keys */
+
+#define BT_OCTET16_LEN 16
+typedef uint8_t BT_OCTET16[BT_OCTET16_LEN]; /* octet array: size 16 */
+
+#define PIN_CODE_LEN 16
+typedef uint8_t PIN_CODE[PIN_CODE_LEN]; /* Pin Code (upto 128 bits) MSB is 0 */
+typedef uint8_t* PIN_CODE_PTR; /* Pointer to Pin Code */
+
+#define BT_OCTET32_LEN 32
+typedef uint8_t BT_OCTET32[BT_OCTET32_LEN]; /* octet array: size 32 */
+
+#define DEV_CLASS_LEN 3
+typedef uint8_t DEV_CLASS[DEV_CLASS_LEN]; /* Device class */
+typedef uint8_t* DEV_CLASS_PTR; /* Pointer to Device class */
+
+#define EXT_INQ_RESP_LEN 3
+typedef uint8_t EXT_INQ_RESP[EXT_INQ_RESP_LEN]; /* Extended Inquiry Response */
+typedef uint8_t* EXT_INQ_RESP_PTR; /* Pointer to Extended Inquiry Response */
+
+#define BD_NAME_LEN 248
+typedef uint8_t BD_NAME[BD_NAME_LEN + 1]; /* Device name */
+typedef uint8_t* BD_NAME_PTR; /* Pointer to Device name */
+
+#define BD_FEATURES_LEN 8
+typedef uint8_t
+ BD_FEATURES[BD_FEATURES_LEN]; /* LMP features supported by device */
+
+#define BT_EVENT_MASK_LEN 8
+typedef uint8_t BT_EVENT_MASK[BT_EVENT_MASK_LEN]; /* Event Mask */
+
+#define LAP_LEN 3
+typedef uint8_t LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */
+typedef uint8_t INQ_LAP[LAP_LEN]; /* IAC as passed to Inquiry (LAP) */
+
+#define RAND_NUM_LEN 16
+typedef uint8_t RAND_NUM[RAND_NUM_LEN];
+
+#define ACO_LEN 12
+typedef uint8_t ACO[ACO_LEN]; /* Authenticated ciphering offset */
+
+#define COF_LEN 12
+typedef uint8_t COF[COF_LEN]; /* ciphering offset number */
+
+typedef struct {
+ uint8_t qos_flags; /* TBD */
+ uint8_t service_type; /* see below */
+ uint32_t token_rate; /* bytes/second */
+ uint32_t token_bucket_size; /* bytes */
+ uint32_t peak_bandwidth; /* bytes/second */
+ uint32_t latency; /* microseconds */
+ uint32_t delay_variation; /* microseconds */
+} FLOW_SPEC;
+
+/* Values for service_type */
+#define NO_TRAFFIC 0
+#define BEST_EFFORT 1
+#define GUARANTEED 2
+
+/* Service class of the CoD */
+#define SERV_CLASS_NETWORKING (1 << 1)
+#define SERV_CLASS_RENDERING (1 << 2)
+#define SERV_CLASS_CAPTURING (1 << 3)
+#define SERV_CLASS_OBJECT_TRANSFER (1 << 4)
+#define SERV_CLASS_OBJECT_AUDIO (1 << 5)
+#define SERV_CLASS_OBJECT_TELEPHONY (1 << 6)
+#define SERV_CLASS_OBJECT_INFORMATION (1 << 7)
+
+/* Second byte */
+#define SERV_CLASS_LIMITED_DISC_MODE (0x20)
+
+/* Field size definitions. Note that byte lengths are rounded up. */
+#define ACCESS_CODE_BIT_LEN 72
+#define ACCESS_CODE_BYTE_LEN 9
+#define SHORTENED_ACCESS_CODE_BIT_LEN 68
+
+typedef uint8_t ACCESS_CODE[ACCESS_CODE_BYTE_LEN];
+
+#define SYNTH_TX 1 /* want synth code to TRANSMIT at this freq */
+#define SYNTH_RX 2 /* want synth code to RECEIVE at this freq */
+
+#define SYNC_REPS 1 /* repeats of sync word transmitted to start of burst */
+
+#define BT_1SEC_TIMEOUT_MS (1 * 1000) /* 1 second */
+
+/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
+#define MAX_UUID_SIZE 16
+typedef struct {
+#define LEN_UUID_16 2
+#define LEN_UUID_32 4
+#define LEN_UUID_128 16
+
+ uint16_t len;
+
+ union {
+ uint16_t uuid16;
+ uint32_t uuid32;
+ uint8_t uuid128[MAX_UUID_SIZE];
+ } uu;
+
+} tBT_UUID;
+
+#define BT_EIR_FLAGS_TYPE 0x01
+#define BT_EIR_MORE_16BITS_UUID_TYPE 0x02
+#define BT_EIR_COMPLETE_16BITS_UUID_TYPE 0x03
+#define BT_EIR_MORE_32BITS_UUID_TYPE 0x04
+#define BT_EIR_COMPLETE_32BITS_UUID_TYPE 0x05
+#define BT_EIR_MORE_128BITS_UUID_TYPE 0x06
+#define BT_EIR_COMPLETE_128BITS_UUID_TYPE 0x07
+#define BT_EIR_SHORTENED_LOCAL_NAME_TYPE 0x08
+#define BT_EIR_COMPLETE_LOCAL_NAME_TYPE 0x09
+#define BT_EIR_TX_POWER_LEVEL_TYPE 0x0A
+#define BT_EIR_OOB_BD_ADDR_TYPE 0x0C
+#define BT_EIR_OOB_COD_TYPE 0x0D
+#define BT_EIR_OOB_SSP_HASH_C_TYPE 0x0E
+#define BT_EIR_OOB_SSP_RAND_R_TYPE 0x0F
+#define BT_EIR_SERVICE_DATA_TYPE 0x16
+#define BT_EIR_SERVICE_DATA_16BITS_UUID_TYPE 0x16
+#define BT_EIR_SERVICE_DATA_32BITS_UUID_TYPE 0x20
+#define BT_EIR_SERVICE_DATA_128BITS_UUID_TYPE 0x21
+#define BT_EIR_MANUFACTURER_SPECIFIC_TYPE 0xFF
+
+#define BT_OOB_COD_SIZE 3
+#define BT_OOB_HASH_C_SIZE 16
+#define BT_OOB_RAND_R_SIZE 16
+
+/* Broadcom proprietary UUIDs and reserved PSMs
+ *
+ * The lowest 4 bytes byte of the UUID or GUID depend on the feature. Typically,
+ * the value of those bytes will be the PSM or SCN.
+*/
+#define BRCM_PROPRIETARY_UUID_BASE \
+ 0xDA, 0x23, 0x41, 0x02, 0xA3, 0xBB, 0xC1, 0x71, 0xBA, 0x09, 0x6f, 0x21
+#define BRCM_PROPRIETARY_GUID_BASE \
+ 0xda23, 0x4102, 0xa3, 0xbb, 0xc1, 0x71, 0xba, 0x09, 0x6f, 0x21
+
+/* We will not allocate a PSM in the reserved range to 3rd party apps
+*/
+#define BRCM_RESERVED_PSM_START 0x5AE1
+#define BRCM_RESERVED_PSM_END 0x5AFF
+
+#define BRCM_UTILITY_SERVICE_PSM 0x5AE1
+#define BRCM_MATCHER_PSM 0x5AE3
+
+/* Connection statistics
+*/
+
+/* Structure to hold connection stats */
+#ifndef BT_CONN_STATS_DEFINED
+#define BT_CONN_STATS_DEFINED
+
+/* These bits are used in the bIsConnected field */
+#define BT_CONNECTED_USING_BREDR 1
+#define BT_CONNECTED_USING_AMP 2
+
+typedef struct {
+ uint32_t is_connected;
+ int32_t rssi;
+ uint32_t bytes_sent;
+ uint32_t bytes_rcvd;
+ uint32_t duration;
+} tBT_CONN_STATS;
+
+#endif
+
+/*****************************************************************************
+ * Low Energy definitions
+ *
+ * Address types
+*/
+#define BLE_ADDR_PUBLIC 0x00
+#define BLE_ADDR_RANDOM 0x01
+#define BLE_ADDR_PUBLIC_ID 0x02
+#define BLE_ADDR_RANDOM_ID 0x03
+typedef uint8_t tBLE_ADDR_TYPE;
+#define BLE_ADDR_TYPE_MASK (BLE_ADDR_RANDOM | BLE_ADDR_PUBLIC)
+
+#define BT_TRANSPORT_INVALID 0
+#define BT_TRANSPORT_BR_EDR 1
+#define BT_TRANSPORT_LE 2
+typedef uint8_t tBT_TRANSPORT;
+
+#define PHY_LE_1M_MASK 1
+#define PHY_LE_2M_MASK 2
+#define PHY_LE_CODED_MASK 4
+
+#define BLE_ADDR_IS_STATIC(x) (((x)[0] & 0xC0) == 0xC0)
+
+typedef struct {
+ tBLE_ADDR_TYPE type;
+ BD_ADDR bda;
+} tBLE_BD_ADDR;
+
+/* Device Types
+*/
+#define BT_DEVICE_TYPE_BREDR 0x01
+#define BT_DEVICE_TYPE_BLE 0x02
+#define BT_DEVICE_TYPE_DUMO 0x03
+typedef uint8_t tBT_DEVICE_TYPE;
+/*****************************************************************************/
+
+/* Define trace levels */
+#define BT_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */
+#define BT_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */
+#define BT_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */
+#define BT_TRACE_LEVEL_API 3 /* API traces */
+#define BT_TRACE_LEVEL_EVENT 4 /* Debug messages for events */
+#define BT_TRACE_LEVEL_DEBUG 5 /* Full debug messages */
+#define BT_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */
+
+#define MAX_TRACE_LEVEL 6
+
+/* Define New Trace Type Definition */
+/* TRACE_CTRL_TYPE 0x^^000000*/
+#define TRACE_CTRL_MASK 0xff000000
+#define TRACE_GET_CTRL(x) ((((uint32_t)(x)) & TRACE_CTRL_MASK) >> 24)
+
+#define TRACE_CTRL_GENERAL 0x00000000
+#define TRACE_CTRL_STR_RESOURCE 0x01000000
+#define TRACE_CTRL_SEQ_FLOW 0x02000000
+#define TRACE_CTRL_MAX_NUM 3
+
+/* LAYER SPECIFIC 0x00^^0000*/
+#define TRACE_LAYER_MASK 0x00ff0000
+#define TRACE_GET_LAYER(x) ((((uint32_t)(x)) & TRACE_LAYER_MASK) >> 16)
+
+#define TRACE_LAYER_NONE 0x00000000
+#define TRACE_LAYER_USB 0x00010000
+#define TRACE_LAYER_SERIAL 0x00020000
+#define TRACE_LAYER_SOCKET 0x00030000
+#define TRACE_LAYER_RS232 0x00040000
+#define TRACE_LAYER_TRANS_MAX_NUM 5
+#define TRACE_LAYER_TRANS_ALL 0x007f0000
+#define TRACE_LAYER_LC 0x00050000
+#define TRACE_LAYER_LM 0x00060000
+#define TRACE_LAYER_HCI 0x00070000
+#define TRACE_LAYER_L2CAP 0x00080000
+#define TRACE_LAYER_RFCOMM 0x00090000
+#define TRACE_LAYER_SDP 0x000a0000
+#define TRACE_LAYER_TCS 0x000b0000
+#define TRACE_LAYER_OBEX 0x000c0000
+#define TRACE_LAYER_BTM 0x000d0000
+#define TRACE_LAYER_GAP 0x000e0000
+#define TRACE_LAYER_ICP 0x00110000
+#define TRACE_LAYER_HSP2 0x00120000
+#define TRACE_LAYER_SPP 0x00130000
+#define TRACE_LAYER_CTP 0x00140000
+#define TRACE_LAYER_BPP 0x00150000
+#define TRACE_LAYER_HCRP 0x00160000
+#define TRACE_LAYER_FTP 0x00170000
+#define TRACE_LAYER_OPP 0x00180000
+#define TRACE_LAYER_BTU 0x00190000
+#define TRACE_LAYER_GKI 0x001a0000 /* OBSOLETED */
+#define TRACE_LAYER_BNEP 0x001b0000
+#define TRACE_LAYER_PAN 0x001c0000
+#define TRACE_LAYER_HFP 0x001d0000
+#define TRACE_LAYER_HID 0x001e0000
+#define TRACE_LAYER_BIP 0x001f0000
+#define TRACE_LAYER_AVP 0x00200000
+#define TRACE_LAYER_A2DP 0x00210000
+#define TRACE_LAYER_SAP 0x00220000
+#define TRACE_LAYER_AMP 0x00230000
+#define TRACE_LAYER_MCA 0x00240000
+#define TRACE_LAYER_ATT 0x00250000
+#define TRACE_LAYER_SMP 0x00260000
+#define TRACE_LAYER_NFC 0x00270000
+#define TRACE_LAYER_NCI 0x00280000
+#define TRACE_LAYER_LLCP 0x00290000
+#define TRACE_LAYER_NDEF 0x002a0000
+#define TRACE_LAYER_RW 0x002b0000
+#define TRACE_LAYER_CE 0x002c0000
+#define TRACE_LAYER_P2P 0x002d0000
+#define TRACE_LAYER_SNEP 0x002e0000
+#define TRACE_LAYER_CHO 0x002f0000
+#define TRACE_LAYER_NFA 0x00300000
+
+#define TRACE_LAYER_MAX_NUM 0x0031
+
+/* TRACE_ORIGINATOR 0x0000^^00*/
+#define TRACE_ORG_MASK 0x0000ff00
+#define TRACE_GET_ORG(x) ((((uint32_t)(x)) & TRACE_ORG_MASK) >> 8)
+
+#define TRACE_ORG_STACK 0x00000000
+#define TRACE_ORG_HCI_TRANS 0x00000100
+#define TRACE_ORG_PROTO_DISP 0x00000200
+#define TRACE_ORG_RPC 0x00000300
+#define TRACE_ORG_GKI 0x00000400 /* OBSOLETED */
+#define TRACE_ORG_APPL 0x00000500
+#define TRACE_ORG_SCR_WRAPPER 0x00000600
+#define TRACE_ORG_SCR_ENGINE 0x00000700
+#define TRACE_ORG_USER_SCR 0x00000800
+#define TRACE_ORG_TESTER 0x00000900
+#define TRACE_ORG_MAX_NUM 10 /* 32-bit mask; must be < 32 */
+#define TRACE_LITE_ORG_MAX_NUM 6
+#define TRACE_ORG_ALL 0x03ff
+#define TRACE_ORG_RPC_TRANS 0x04
+
+#define TRACE_ORG_REG 0x00000909
+#define TRACE_ORG_REG_SUCCESS 0x0000090a
+
+/* TRACE_TYPE 0x000000^^*/
+#define TRACE_TYPE_MASK 0x000000ff
+#define TRACE_GET_TYPE(x) (((uint32_t)(x)) & TRACE_TYPE_MASK)
+
+#define TRACE_TYPE_ERROR 0x00000000
+#define TRACE_TYPE_WARNING 0x00000001
+#define TRACE_TYPE_API 0x00000002
+#define TRACE_TYPE_EVENT 0x00000003
+#define TRACE_TYPE_DEBUG 0x00000004
+#define TRACE_TYPE_STACK_ONLY_MAX TRACE_TYPE_DEBUG
+#define TRACE_TYPE_TX 0x00000005
+#define TRACE_TYPE_RX 0x00000006
+#define TRACE_TYPE_DEBUG_ASSERT 0x00000007
+#define TRACE_TYPE_GENERIC 0x00000008
+#define TRACE_TYPE_REG 0x00000009
+#define TRACE_TYPE_REG_SUCCESS 0x0000000a
+#define TRACE_TYPE_CMD_TX 0x0000000b
+#define TRACE_TYPE_EVT_TX 0x0000000c
+#define TRACE_TYPE_ACL_TX 0x0000000d
+#define TRACE_TYPE_CMD_RX 0x0000000e
+#define TRACE_TYPE_EVT_RX 0x0000000f
+#define TRACE_TYPE_ACL_RX 0x00000010
+#define TRACE_TYPE_TARGET_TRACE 0x00000011
+#define TRACE_TYPE_SCO_TX 0x00000012
+#define TRACE_TYPE_SCO_RX 0x00000013
+
+#define TRACE_TYPE_MAX_NUM 20
+#define TRACE_TYPE_ALL 0xffff
+
+/* Define color for script type */
+#define SCR_COLOR_DEFAULT 0
+#define SCR_COLOR_TYPE_COMMENT 1
+#define SCR_COLOR_TYPE_COMMAND 2
+#define SCR_COLOR_TYPE_EVENT 3
+#define SCR_COLOR_TYPE_SELECT 4
+
+/* Define protocol trace flag values */
+#define SCR_PROTO_TRACE_HCI_SUMMARY 0x00000001
+#define SCR_PROTO_TRACE_HCI_DATA 0x00000002
+#define SCR_PROTO_TRACE_L2CAP 0x00000004
+#define SCR_PROTO_TRACE_RFCOMM 0x00000008
+#define SCR_PROTO_TRACE_SDP 0x00000010
+#define SCR_PROTO_TRACE_TCS 0x00000020
+#define SCR_PROTO_TRACE_OBEX 0x00000040
+#define SCR_PROTO_TRACE_OAPP 0x00000080 /* OBEX Application Profile */
+#define SCR_PROTO_TRACE_AMP 0x00000100
+#define SCR_PROTO_TRACE_BNEP 0x00000200
+#define SCR_PROTO_TRACE_AVP 0x00000400
+#define SCR_PROTO_TRACE_MCA 0x00000800
+#define SCR_PROTO_TRACE_ATT 0x00001000
+#define SCR_PROTO_TRACE_SMP 0x00002000
+#define SCR_PROTO_TRACE_NCI 0x00004000
+#define SCR_PROTO_TRACE_LLCP 0x00008000
+#define SCR_PROTO_TRACE_NDEF 0x00010000
+#define SCR_PROTO_TRACE_RW 0x00020000
+#define SCR_PROTO_TRACE_CE 0x00040000
+#define SCR_PROTO_TRACE_SNEP 0x00080000
+#define SCR_PROTO_TRACE_CHO 0x00100000
+#define SCR_PROTO_TRACE_ALL 0x001fffff
+#define SCR_PROTO_TRACE_HCI_LOGGING_VSE \
+ 0x0800 /* Brcm vs event for logmsg and protocol traces */
+
+#define MAX_SCRIPT_TYPE 5
+
+#define TCS_PSM_INTERCOM 5
+#define TCS_PSM_CORDLESS 7
+#define BT_PSM_BNEP 0x000F
+/* Define PSMs HID uses */
+#define HID_PSM_CONTROL 0x0011
+#define HID_PSM_INTERRUPT 0x0013
+
+/* Define a function for logging */
+typedef void(BT_LOG_FUNC)(int trace_type, const char* fmt_str, ...);
+
+/* bd addr length and type */
+#ifndef BD_ADDR_LEN
+#define BD_ADDR_LEN 6
+typedef uint8_t BD_ADDR[BD_ADDR_LEN];
+#endif
+
+// From bd.c
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* global constant for "any" bd addr */
+static const BD_ADDR bd_addr_any = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+static const BD_ADDR bd_addr_null = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/*****************************************************************************
+ * Functions
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function bdcpy
+ *
+ * Description Copy bd addr b to a.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static inline void bdcpy(BD_ADDR a, const BD_ADDR b) {
+ int i;
+
+ for (i = BD_ADDR_LEN; i != 0; i--) {
+ *a++ = *b++;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function bdcmp
+ *
+ * Description Compare bd addr b to a.
+ *
+ *
+ * Returns Zero if b==a, nonzero otherwise (like memcmp).
+ *
+ ******************************************************************************/
+static inline int bdcmp(const BD_ADDR a, const BD_ADDR b) {
+ int i;
+
+ for (i = BD_ADDR_LEN; i != 0; i--) {
+ if (*a++ != *b++) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ *
+ * Function bdcmpany
+ *
+ * Description Compare bd addr to "any" bd addr.
+ *
+ *
+ * Returns Zero if a equals bd_addr_any.
+ *
+ ******************************************************************************/
+static inline int bdcmpany(const BD_ADDR a) { return bdcmp(a, bd_addr_any); }
+
+/*******************************************************************************
+ *
+ * Function bdsetany
+ *
+ * Description Set bd addr to "any" bd addr.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static inline void bdsetany(BD_ADDR a) { bdcpy(a, bd_addr_any); }
+#endif
diff --git a/mtkbt/code/bt/stack/include/btm_api.h b/mtkbt/code/bt/stack/include/btm_api.h
new file mode 100755
index 0000000..2c0743f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/btm_api.h
@@ -0,0 +1,2076 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the Bluetooth Manager (BTM) API function external
+ * definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_API_H
+#define BTM_API_H
+
+#include "bt_target.h"
+#include "device/include/esco_parameters.h"
+#include "hcidefs.h"
+#include "sdp_api.h"
+
+#include "smp_api.h"
+
+#include "btm_api_types.h"
+
+/*****************************************************************************
+ * DEVICE CONTROL and COMMON
+ ****************************************************************************/
+
+/*****************************************************************************
+ * EXTERNAL FUNCTION DECLARATIONS
+ ****************************************************************************/
+
+/*****************************************************************************
+ * DEVICE CONTROL and COMMON FUNCTIONS
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTM_DeviceReset
+ *
+ * Description This function is called to reset the controller. The
+ * Callback function if provided is called when startup of the
+ * device has completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_DeviceReset(tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsDeviceUp
+ *
+ * Description This function is called to check if the device is up.
+ *
+ * Returns true if device is up, else false
+ *
+ ******************************************************************************/
+extern bool BTM_IsDeviceUp(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLocalDeviceName
+ *
+ * Description This function is called to set the local device name.
+ *
+ * Returns BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetLocalDeviceName(char* p_name);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDeviceClass
+ *
+ * Description This function is called to set the local device class
+ *
+ * Returns BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceName
+ *
+ * Description This function is called to read the local device name.
+ *
+ * Returns status of the operation
+ * If success, BTM_SUCCESS is returned and p_name points stored
+ * local device name
+ * If BTM doesn't store local device name, BTM_NO_RESOURCES is
+ * is returned and p_name is set to NULL
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadLocalDeviceName(char** p_name);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceNameFromController
+ *
+ * Description Get local device name from controller. Do not use cached
+ * name (used to get chip-id prior to btm reset complete).
+ *
+ * Returns BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadLocalDeviceNameFromController(
+ tBTM_CMPL_CB* p_rln_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceClass
+ *
+ * Description This function is called to read the local device class
+ *
+ * Returns pointer to the device class
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadDeviceClass(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalFeatures
+ *
+ * Description This function is called to read the local features
+ *
+ * Returns pointer to the local features string
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadLocalFeatures(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForDeviceStatusNotif
+ *
+ * Description This function is called to register for device status
+ * change notifications.
+ *
+ * Returns pointer to previous caller's callback function or NULL if
+ * first registration.
+ *
+ ******************************************************************************/
+extern tBTM_DEV_STATUS_CB* BTM_RegisterForDeviceStatusNotif(
+ tBTM_DEV_STATUS_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForVSEvents
+ *
+ * Description This function is called to register/deregister for vendor
+ * specific HCI events.
+ *
+ * If is_register=true, then the function will be registered;
+ * otherwise the function will be deregistered.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_BUSY if maximum number of callbacks have already been
+ * registered.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb,
+ bool is_register);
+
+/*******************************************************************************
+ *
+ * Function BTM_VendorSpecificCommand
+ *
+ * Description Send a vendor specific HCI command to the controller.
+ *
+ ******************************************************************************/
+extern void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len,
+ uint8_t* p_param_buf,
+ tBTM_VSC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_AllocateSCN
+ *
+ * Description Look through the Server Channel Numbers for a free one to be
+ * used with an RFCOMM connection.
+ *
+ * Returns Allocated SCN number or 0 if none.
+ *
+ ******************************************************************************/
+extern uint8_t BTM_AllocateSCN(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_TryAllocateSCN
+ *
+ * Description Try to allocate a fixed server channel
+ *
+ * Returns Returns true if server channel was available
+ *
+ ******************************************************************************/
+extern bool BTM_TryAllocateSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function BTM_FreeSCN
+ *
+ * Description Free the specified SCN.
+ *
+ * Returns true if successful, false if SCN is not in use or invalid
+ *
+ ******************************************************************************/
+extern bool BTM_FreeSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetTraceLevel
+ *
+ * Description This function sets the trace level for BTM. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+extern uint8_t BTM_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function BTM_WritePageTimeout
+ *
+ * Description Send HCI Wite Page Timeout.
+ *
+ ******************************************************************************/
+extern void BTM_WritePageTimeout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteVoiceSettings
+ *
+ * Description Send HCI Write Voice Settings command.
+ * See hcidefs.h for settings bitmask values.
+ *
+ ******************************************************************************/
+extern void BTM_WriteVoiceSettings(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_EnableTestMode
+ *
+ * Description Send HCI the enable device under test command.
+ *
+ * Note: Controller can only be taken out of this mode by
+ * resetting the controller.
+ *
+ * Returns
+ * BTM_SUCCESS Command sent.
+ * BTM_NO_RESOURCES If out of resources to send the command.
+ *
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_EnableTestMode(void);
+
+/*******************************************************************************
+ * DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDiscoverability
+ *
+ * Description This function is called to set the device into or out of
+ * discoverable mode. Discoverable mode means inquiry
+ * scans are enabled. If a value of '0' is entered for window
+ * or interval, the default values are used.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_BUSY if a setting of the filter is already in progress
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
+ uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDiscoverability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ *
+ * Output Params: p_window - current inquiry scan duration
+ * p_interval - current inquiry scan interval
+ *
+ * Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ * BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadDiscoverability(uint16_t* p_window,
+ uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPeriodicInquiryMode
+ *
+ * Description This function is called to set the device periodic inquiry
+ * mode. If the duration is zero, the periodic inquiry mode is
+ * cancelled.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * max_delay - maximum amount of time between successive
+ * inquiries
+ * min_delay - minimum amount of time between successive
+ * inquiries
+ * p_results_cb - callback returning pointer to results
+ * (tBTM_INQ_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully started
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_BUSY - if an inquiry is already active
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetPeriodicInquiryMode(
+ tBTM_INQ_PARMS* p_inqparms, uint16_t max_delay, uint16_t min_delay,
+ tBTM_INQ_RESULTS_CB* p_results_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_StartInquiry
+ *
+ * Description This function is called to start an inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * p_results_cb - Pointer to the callback routine which gets
+ * called upon receipt of an inquiry result. If
+ * this field is NULL, the application is not
+ * notified.
+ *
+ * p_cmpl_cb - Pointer to the callback routine which gets
+ * called upon completion. If this field is
+ * NULL, the application is not notified when
+ * completed.
+ * Returns tBTM_STATUS
+ * BTM_CMD_STARTED if successfully initiated
+ * BTM_BUSY if already in progress
+ * BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsInquiryActive
+ *
+ * Description Return a bit mask of the current inquiry state
+ *
+ * Returns BTM_INQUIRY_INACTIVE if inactive (0)
+ * BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ * BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ * BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+extern uint16_t BTM_IsInquiryActive(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelInquiry
+ *
+ * Description This function cancels an inquiry if active
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_CancelInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelPeriodicInquiry
+ *
+ * Description This function cancels a periodic inquiry
+ *
+ * Returns
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_CancelPeriodicInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetConnectability
+ *
+ * Description This function is called to set the device into or out of
+ * connectable mode. Discoverable mode means page scans are
+ * enabled.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
+ uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ * Output Params p_window - current page scan duration
+ * p_interval - current time between page scans
+ *
+ * Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadConnectability(uint16_t* p_window,
+ uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryMode
+ *
+ * Description This function is called to set standard, with RSSI
+ * mode or extended of the inquiry for local device.
+ *
+ * Input Params: BTM_INQ_RESULT_STANDARD, BTM_INQ_RESULT_WITH_RSSI or
+ * BTM_INQ_RESULT_EXTENDED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetInquiryMode(uint8_t mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryScanType
+ *
+ * Description This function is called to set the iquiry scan-type to
+ * standard or interlaced.
+ *
+ * Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPageScanType
+ *
+ * Description This function is called to set the page scan-type to
+ * standard or interlaced.
+ *
+ * Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+
+extern tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteDeviceName
+ *
+ * Description This function initiates a remote device HCI command to the
+ * controller and calls the callback when the process has
+ * completed.
+ *
+ * Input Params: remote_bda - device address of name to retrieve
+ * p_cb - callback function called when
+ * BTM_CMD_STARTED is returned.
+ * A pointer to tBTM_REMOTE_DEV_NAME is
+ * passed to the callback.
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_BUSY if already in progress
+ * BTM_UNKNOWN_ADDR if device address is bad
+ * BTM_NO_RESOURCES if resources could not be allocated to
+ * start the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadRemoteDeviceName(BD_ADDR remote_bda,
+ tBTM_CMPL_CB* p_cb,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelRemoteDeviceName
+ *
+ * Description This function initiates the cancel request for the specified
+ * remote device.
+ *
+ * Input Params: None
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_NO_RESOURCES if resources could not be allocated to
+ * start the command
+ * BTM_WRONG_MODE if there is no active remote name request.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_CancelRemoteDeviceName(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteVersion
+ *
+ * Description This function is called to read a remote device's version
+ *
+ * Returns BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadRemoteVersion(BD_ADDR addr, uint8_t* lmp_version,
+ uint16_t* manufacturer,
+ uint16_t* lmp_sub_version);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteFeatures
+ *
+ * Description This function is called to read a remote device's
+ * supported features mask (features mask located at page 0)
+ *
+ * Note: The size of device features mask page is
+ * BTM_FEATURE_BYTES_PER_PAGE bytes.
+ *
+ * Returns pointer to the remote supported features mask
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadRemoteFeatures(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteExtendedFeatures
+ *
+ * Description This function is called to read a specific extended features
+ * page of the remote device
+ *
+ * Note1: The size of device features mask page is
+ * BTM_FEATURE_BYTES_PER_PAGE bytes.
+ * Note2: The valid device features mask page number depends on
+ * the remote device capabilities. It is expected to be in the
+ * range [0 - BTM_EXT_FEATURES_PAGE_MAX].
+
+ * Returns pointer to the remote extended features mask
+ * or NULL if page_number is not valid
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadRemoteExtendedFeatures(BD_ADDR addr,
+ uint8_t page_number);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadNumberRemoteFeaturesPages
+ *
+ * Description This function is called to retrieve the number of feature
+ * pages read from the remote device
+ *
+ * Returns number of features pages read from the remote device
+ *
+ ******************************************************************************/
+extern uint8_t BTM_ReadNumberRemoteFeaturesPages(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadAllRemoteFeatures
+ *
+ * Description Read all the features of the remote device
+ *
+ * Returns pointer to the byte[0] of the page[0] of the remote device
+ * feature mask.
+ *
+ * Note: the function returns the pointer to the array of the size
+ * BTM_FEATURE_BYTES_PER_PAGE * (BTM_EXT_FEATURES_PAGE_MAX + 1)
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadAllRemoteFeatures(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbRead
+ *
+ * Description This function looks through the inquiry database for a match
+ * based on Bluetooth Device Address. This is the application's
+ * interface to get the inquiry details of a specific BD
+ * address.
+ *
+ * Returns pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+extern tBTM_INQ_INFO* BTM_InqDbRead(const BD_ADDR p_bda);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbFirst
+ *
+ * Description This function looks through the inquiry database for the
+ * first used entry, and returns that. This is used in
+ * conjunction with BTM_InqDbNext by applications as a way to
+ * walk through the inquiry database.
+ *
+ * Returns pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+extern tBTM_INQ_INFO* BTM_InqDbFirst(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbNext
+ *
+ * Description This function looks through the inquiry database for the
+ * next used entry, and returns that. If the input parameter
+ * is NULL, the first entry is returned.
+ *
+ * Returns pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+extern tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur);
+
+/*******************************************************************************
+ *
+ * Function BTM_ClearInqDb
+ *
+ * Description This function is called to clear out a device or all devices
+ * from the inquiry database.
+ *
+ * Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+ * (NULL clears all entries)
+ *
+ * Returns BTM_BUSY if an inquiry, get remote name, or event filter
+ * is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ClearInqDb(BD_ADDR p_bda);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadInquiryRspTxPower
+ *
+ * Description This command will read the inquiry Transmit Power level used
+ * to transmit the FHS and EIR data packets.
+ * This can be used directly in the Tx Power Level EIR data
+ * type.
+ *
+ * Returns BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_StartDiscovery
+ *
+ * Description This function is called by an application (or profile)
+ * when it wants to trigger an service discovery using the
+ * BTM's discovery database.
+ *
+ * Returns tBTM_STATUS
+ * BTM_CMD_STARTED if the discovery was initiated
+ * BTM_BUSY if one is already in progress
+ * BTM_UNKNOWN_ADDR if no addresses are in the INQ DB
+ * BTM_ERR_PROCESSING if err initiating the command
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_StartDiscovery(tBTM_CMPL_CB* p_cmpl_cb,
+ BD_ADDR_PTR p_rem_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_FindAttribute
+ *
+ * Description This function is called by an application (or profile)
+ * when it wants to see if an attribute exists in the BTM
+ * discovery database.
+ *
+ * Returns Pointer to matching record, or NULL
+ *
+ ******************************************************************************/
+extern tSDP_DISC_REC* BTM_FindAttribute(uint16_t attr_id,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function BTM_FindService
+ *
+ * Description This function is called by an application (or profile)
+ * when it wants to see if a service exists in the BTM
+ * discovery database.
+ *
+ * Returns Pointer to matching record, or NULL
+ *
+ ******************************************************************************/
+extern tSDP_DISC_REC* BTM_FindService(uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDiscoveryParams
+ *
+ * Description This function is called to set the BTM default discovery
+ * parameters. These UUID and attribute filters are used during
+ * the call to BTM_StartDiscovery.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetDiscoveryParams(uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+ uint16_t num_attr, uint16_t* p_attr_list);
+
+/*****************************************************************************
+ * ACL CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkPolicy
+ *
+ * Description Create and send HCI "Write Policy Set" command
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetLinkPolicy(BD_ADDR remote_bda, uint16_t* settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkPolicy
+ *
+ * Description Set the default value for HCI "Write Policy Set" command
+ * to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetDefaultLinkPolicy(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkSuperTout
+ *
+ * Description Set the default value for HCI "Write Link Supervision
+ * Timeout" command to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetDefaultLinkSuperTout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkSuperTout
+ *
+ * Description Create and send HCI "Write Link Supervision Timeout" command
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetLinkSuperTout(BD_ADDR remote_bda, uint16_t timeout);
+/*******************************************************************************
+ *
+ * Function BTM_GetLinkSuperTout
+ *
+ * Description Read the link supervision timeout value of the connection
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_GetLinkSuperTout(BD_ADDR remote_bda,
+ uint16_t* p_timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsAclConnectionUp
+ *
+ * Description This function is called to check if an ACL connection exists
+ * to a specific remote BD Address.
+ *
+ * Returns true if connection is up, else false.
+ *
+ ******************************************************************************/
+extern bool BTM_IsAclConnectionUp(BD_ADDR remote_bda, tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetRole
+ *
+ * Description This function is called to get the role of the local device
+ * for the ACL connection with the specified remote device
+ *
+ * Returns BTM_SUCCESS if connection exists.
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_GetRole(BD_ADDR remote_bd_addr, uint8_t* p_role);
+
+/*******************************************************************************
+ *
+ * Function BTM_SwitchRole
+ *
+ * Description This function is called to switch role between master and
+ * slave. If role is already set it will do nothing. If the
+ * command was initiated, the callback function is called upon
+ * completion.
+ *
+ * Returns BTM_SUCCESS if already in specified role.
+ * BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_MODE_UNSUPPORTED if the local device does not support
+ * role switching
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SwitchRole(BD_ADDR remote_bd_addr, uint8_t new_role,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRSSI
+ *
+ * Description This function is called to read the link policy settings.
+ * The address of link policy results are returned in the
+ * callback. (tBTM_RSSI_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadRSSI(const BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTxPower
+ *
+ * Description This function is called to read the current connection
+ * TX power of the connection. The TX power level results
+ * are returned in the callback.
+ * (tBTM_RSSI_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadTxPower(BD_ADDR remote_bda, tBT_TRANSPORT transport,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLinkQuality
+ *
+ * Description This function is called to read the link quality.
+ * The value of the link quality is returned in the callback.
+ * (tBTM_LINK_QUALITY_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadLinkQuality(BD_ADDR remote_bda, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegBusyLevelNotif
+ *
+ * Description This function is called to register a callback to receive
+ * busy level change events.
+ *
+ * Returns BTM_SUCCESS if successfully registered, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_RegBusyLevelNotif(tBTM_BL_CHANGE_CB* p_cb,
+ uint8_t* p_level,
+ tBTM_BL_EVENT_MASK evt_mask);
+
+/*******************************************************************************
+ *
+ * Function BTM_AclRegisterForChanges
+ *
+ * Description This function is called to register a callback to receive
+ * ACL database change events, i.e. new connection or removed.
+ *
+ * Returns BTM_SUCCESS if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_AclRegisterForChanges(tBTM_ACL_DB_CHANGE_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumAclLinks
+ *
+ * Description This function is called to count the number of
+ * ACL links that are active.
+ *
+ * Returns uint16_t Number of active ACL links
+ *
+ ******************************************************************************/
+extern uint16_t BTM_GetNumAclLinks(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetQoS
+ *
+ * Description This function is called to setup QoS
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetQoS(BD_ADDR bd, FLOW_SPEC* p_flow,
+ tBTM_CMPL_CB* p_cb);
+
+/*****************************************************************************
+ * (e)SCO CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_CreateSco
+ *
+ * Description This function is called to create an SCO connection. If the
+ * "is_orig" flag is true, the connection will be originated,
+ * otherwise BTM will wait for the other side to connect.
+ *
+ * Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+ * BTM_BUSY if another SCO being set up to
+ * the same BD address
+ * BTM_NO_RESOURCES if the max SCO limit has been reached
+ * BTM_CMD_STARTED if the connection establishment is started.
+ * In this case, "*p_sco_inx" is filled in
+ * with the sco index used for the connection.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_CreateSco(BD_ADDR remote_bda, bool is_orig,
+ uint16_t pkt_types, uint16_t* p_sco_inx,
+ tBTM_SCO_CB* p_conn_cb,
+ tBTM_SCO_CB* p_disc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveSco
+ *
+ * Description This function is called to remove a specific SCO connection.
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetScoPacketTypes
+ *
+ * Description This function is called to set the packet types used for
+ * a specific SCO connection,
+ *
+ * Parameters pkt_types - One or more of the following
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ * BTM_SCO_LINK_ALL_MASK - enables all supported types
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoPacketTypes
+ *
+ * Description This function is read the packet types used for a specific
+ * SCO connection.
+ *
+ * Returns One or more of the following (bitmask)
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ * Returns packet types supported for the connection
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceScoPacketTypes
+ *
+ * Description This function is read the SCO packet types that
+ * the device supports.
+ *
+ * Returns packet types supported by the device.
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadDeviceScoPacketTypes(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoHandle
+ *
+ * Description Reead the HCI handle used for a specific SCO connection,
+ *
+ * Returns handle for the connection, or 0xFFFF if invalid SCO index.
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadScoHandle(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoBdAddr
+ *
+ * Description This function is read the remote BD Address for a specific
+ * SCO connection,
+ *
+ * Returns pointer to BD address or NULL if not known
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadScoBdAddr(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoDiscReason
+ *
+ * Description This function is returns the reason why an (e)SCO connection
+ * has been removed. It contains the value until read, or until
+ * another (e)SCO connection has disconnected.
+ *
+ * Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+ *
+ ******************************************************************************/
+extern uint16_t BTM_ReadScoDiscReason(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEScoMode
+ *
+ * Description This function sets up the negotiated parameters for SCO or
+ * eSCO, and sets as the default mode used for calls to
+ * BTM_CreateSco. It can be called only when there are no
+ * active (e)SCO links.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_BUSY if there are one or more active (e)SCO links.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetWBSCodec
+ *
+ * Description This function sends command to the controller to setup
+ * WBS codec for the upcoming eSCO connection.
+ *
+ * Returns BTM_SUCCESS.
+ *
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetWBSCodec(tBTM_SCO_CODEC_TYPE codec_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegForEScoEvts
+ *
+ * Description This function registers a SCO event callback with the
+ * specified instance. It should be used to received
+ * connection indication events and change of link parameter
+ * events.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx,
+ tBTM_ESCO_CBACK* p_esco_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadEScoLinkParms
+ *
+ * Description This function returns the current eSCO link parameters for
+ * the specified handle. This can be called anytime a
+ * connection is active, but is typically called after
+ * receiving the SCO opened callback.
+ *
+ * Note: If called over a 1.1 controller, only the packet types
+ * field has meaning.
+ * Note: If the upper layer doesn't know the current sco index,
+ * BTM_FIRST_ACTIVE_SCO_INDEX can be used as the first
+ * parameter to find the first active SCO index
+ *
+ * Returns BTM_SUCCESS if returned data is valid connection.
+ * BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ * BTM_MODE_UNSUPPORTED if local controller does not support
+ * 1.2 specification.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx,
+ tBTM_ESCO_DATA* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_ChangeEScoLinkParms
+ *
+ * Description This function requests renegotiation of the parameters on
+ * the current eSCO Link. If any of the changes are accepted
+ * by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+ * the tBTM_ESCO_CBACK function with the current settings of
+ * the link. The callback is registered through the call to
+ * BTM_SetEScoMode.
+ *
+ *
+ * Returns BTM_CMD_STARTED if command is successfully initiated.
+ * BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ * BTM_NO_RESOURCES - not enough resources to initiate command.
+ * BTM_MODE_UNSUPPORTED if local controller does not support
+ * 1.2 specification.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
+ tBTM_CHG_ESCO_PARAMS* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_EScoConnRsp
+ *
+ * Description This function is called upon receipt of an (e)SCO connection
+ * request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+ * the request. Parameters used to negotiate eSCO links.
+ * If p_parms is NULL, then values set through BTM_SetEScoMode
+ * are used.
+ * If the link type of the incoming request is SCO, then only
+ * the tx_bw, max_latency, content format, and packet_types are
+ * valid. The hci_status parameter should be
+ * ([0x0] to accept, [0x0d..0x0f] to reject)
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
+ enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumScoLinks
+ *
+ * Description This function returns the number of active SCO links.
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+extern uint8_t BTM_GetNumScoLinks(void);
+
+/*****************************************************************************
+ * SECURITY MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_SecRegister
+ *
+ * Description Application manager calls this function to register for
+ * security services. There can be one and only one
+ * application saving link keys. BTM allows only first
+ * registration.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecRegister(tBTM_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecRegisterLinkKeyNotificationCallback
+ *
+ * Description Profiles can register to be notified when a new Link Key
+ * is generated per connection.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecRegisterLinkKeyNotificationCallback(
+ tBTM_LINK_KEY_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddRmtNameNotifyCallback
+ *
+ * Description Profiles can register to be notified when name of the
+ * remote device is resolved (up to
+ * BTM_SEC_MAX_RMT_NAME_CALLBACKS).
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecDeleteRmtNameNotifyCallback
+ *
+ * Description A profile can deregister notification when a new Link Key
+ * is generated per connection.
+ *
+ * Returns true if OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecDeleteRmtNameNotifyCallback(
+ tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlags
+ *
+ * Description Get security flags for the device
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+extern bool BTM_GetSecurityFlags(BD_ADDR bd_addr, uint8_t* p_sec_flags);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlagsByTransport
+ *
+ * Description Get security flags for the device on a particular transport
+ *
+ * Parameters bd_addr: BD address of remote device
+ * p_sec_flags : Out parameter to be filled with security
+ * flags for the connection
+ * transport : Physical transport of the connection
+ * (BR/EDR or LE)
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+extern bool BTM_GetSecurityFlagsByTransport(BD_ADDR bd_addr,
+ uint8_t* p_sec_flags,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTrustedMask
+ *
+ * Description Get trusted mask for the device
+ *
+ * Returns NULL, if the device record is not found.
+ * otherwise, the trusted mask
+ *
+ ******************************************************************************/
+extern uint32_t* BTM_ReadTrustedMask(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPinType
+ *
+ * Description Set PIN type for the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code,
+ uint8_t pin_code_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPairableMode
+ *
+ * Description Enable or disable pairing
+ *
+ * Parameters allow_pairing - (true or false) whether or not the device
+ * allows pairing.
+ * connect_only_paired - (true or false) whether or not to
+ * only allow paired devices to connect.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetPairableMode(bool allow_pairing, bool connect_only_paired);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecureConnectionsOnly
+ *
+ * Description Enable or disable default treatment for Mode 4 Level 0
+ * services
+ *
+ * Parameter secure_connections_only_mode - (true or false)
+ * true means that the device should treat Mode 4 Level 0
+ * services as services of other levels.
+ * false means that the device should provide default
+ * treatment for Mode 4 Level 0 services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetSecureConnectionsOnly(bool secure_connections_only_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecurityLevel
+ *
+ * Description Register service security level with Security Manager. Each
+ * service must register its requirements regardless of the
+ * security level that is used. This API is called once for
+ * originators and again for acceptors of connections.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
+ uint8_t service_id, uint16_t sec_level,
+ uint16_t psm, uint32_t mx_proto_id,
+ uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetOutService
+ *
+ * Description This function is called to set the service for
+ * outgoing connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetOutService(BD_ADDR bd_addr, uint8_t service_id,
+ uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClrService
+ *
+ * Description Removes specified service record(s) from the security
+ * database. All service records with the specified name are
+ * removed. Typically used only by devices with limited RAM
+ * so that it can reuse an old security service record.
+ *
+ * Returns Number of records that were freed.
+ *
+ ******************************************************************************/
+extern uint8_t BTM_SecClrService(uint8_t service_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * stored in the NVRAM.
+ * dev_class, bd_name, link_key, and features are NULL if
+ * unknown
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecAddDevice(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, uint8_t* features,
+ uint32_t trusted_mask[], LINK_KEY link_key,
+ uint8_t key_type, tBTM_IO_CAP io_cap,
+ uint8_t pin_length);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecDeleteDevice
+ *
+ * Description Free resources associated with the device.
+ *
+ * Returns true if rmoved OK, false if not found
+ *
+ ******************************************************************************/
+extern bool BTM_SecDeleteDevice(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClearSecurityFlags
+ *
+ * Description Reset the security flags (mark as not-paired) for a given
+ * remove device.
+ *
+ ******************************************************************************/
+extern void BTM_SecClearSecurityFlags(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKey
+ *
+ * Description This function is called to obtain link key for the device
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Returns BTM_SUCCESS if successful, otherwise error code
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SecGetDeviceLinkKey(BD_ADDR bd_addr, LINK_KEY link_key);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKeyType
+ *
+ * Description This function is called to obtain link key type for the
+ * device.
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type
+ * otherwise.
+ *
+ ******************************************************************************/
+extern tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PINCodeReply
+ *
+ * Description This function is called after Security Manager submitted
+ * PIN code request to the UI.
+ *
+ * Parameters: bd_addr - Address of the device for which PIN was
+ * requested
+ * res - result of the operation BTM_SUCCESS if
+ * success
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_PINCodeReply(BD_ADDR bd_addr, uint8_t res, uint8_t pin_len,
+ uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBond
+ *
+ * Description This function is called to perform bonding with peer device.
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SecBond(BD_ADDR bd_addr, uint8_t pin_len, uint8_t* p_pin,
+ uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBondByTransport
+ *
+ * Description Perform bonding by designated transport
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ * transport : Physical transport to use for bonding
+ * (BR/EDR or LE)
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SecBondByTransport(BD_ADDR bd_addr,
+ tBT_TRANSPORT transport,
+ uint8_t pin_len, uint8_t* p_pin,
+ uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBondCancel
+ *
+ * Description This function is called to cancel ongoing bonding process
+ * with peer device.
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SecBondCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEncryption
+ *
+ * Description This function is called to ensure that connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - Link transport
+ * p_callback - Pointer to callback function called if
+ * this function returns PENDING after required
+ * procedures are completed. Can be set to
+ * NULL if status is not desired.
+ * p_ref_data - pointer to any data the caller wishes to
+ * receive in the callback function upon
+ * completion.
+ * can be set to NULL if not used.
+ * sec_act - LE security action, unused for BR/EDR
+ *
+ * Returns BTM_SUCCESS - already encrypted
+ * BTM_PENDING - command will be returned in the callback
+ * BTM_WRONG_MODE- connection not up.
+ * BTM_BUSY - security procedures are currently active
+ * BTM_MODE_UNSUPPORTED - if security manager not linked in.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetEncryption(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ tBTM_SEC_CBACK* p_callback,
+ void* p_ref_data,
+ tBTM_BLE_SEC_ACT sec_act);
+
+/*******************************************************************************
+ *
+ * Function BTM_ConfirmReqReply
+ *
+ * Description This function is called to confirm the numeric value for
+ * Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if
+ * success
+ * bd_addr - Address of the peer device
+ *
+ ******************************************************************************/
+extern void BTM_ConfirmReqReply(tBTM_STATUS res, BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PasskeyReqReply
+ *
+ * Description This function is called to provide the passkey for
+ * Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if
+ * success
+ * bd_addr - Address of the peer device
+ * passkey - numeric value in the range of
+ * 0 - 999999(0xF423F).
+ *
+ ******************************************************************************/
+extern void BTM_PasskeyReqReply(tBTM_STATUS res, BD_ADDR bd_addr,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function BTM_SendKeypressNotif
+ *
+ * Description This function is used during the passkey entry model
+ * by a device with KeyboardOnly IO capabilities
+ * (very likely to be a HID Device).
+ * It is called by a HID Device to inform the remote device
+ * when a key has been entered or erased.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * type - notification type
+ *
+ ******************************************************************************/
+extern void BTM_SendKeypressNotif(BD_ADDR bd_addr, tBTM_SP_KEY_TYPE type);
+
+/*******************************************************************************
+ *
+ * Function BTM_IoCapRsp
+ *
+ * Description This function is called in response to BTM_SP_IO_REQ_EVT
+ * When the event data io_req.oob_data is set to
+ * BTM_OOB_UNKNOWN by the tBTM_SP_CALLBACK implementation, this
+ * function is called to provide the actual response
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * io_cap - The IO capability of local device.
+ * oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+ * auth_req- MITM protection required or not.
+ *
+ ******************************************************************************/
+extern void BTM_IoCapRsp(BD_ADDR bd_addr, tBTM_IO_CAP io_cap, tBTM_OOB_DATA oob,
+ tBTM_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalOobData
+ *
+ * Description This function is called to read the local OOB data from
+ * LM
+ *
+ ******************************************************************************/
+extern void BTM_ReadLocalOobData(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoteOobDataReply
+ *
+ * Description This function is called to provide the remote OOB data for
+ * Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+extern void BTM_RemoteOobDataReply(tBTM_STATUS res, BD_ADDR bd_addr,
+ BT_OCTET16 c, BT_OCTET16 r);
+
+/*******************************************************************************
+ *
+ * Function BTM_BuildOobData
+ *
+ * Description This function is called to build the OOB data payload to
+ * be sent over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * max_len - p_data size.
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ * name_len- 0, local device name would not be included.
+ * otherwise, the local device name is included for
+ * up to this specified length
+ *
+ * Returns Number of bytes in p_data.
+ *
+ ******************************************************************************/
+extern uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len,
+ BT_OCTET16 c, BT_OCTET16 r, uint8_t name_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_BothEndsSupportSecureConnections
+ *
+ * Description This function is called to check if both the local device
+ * and the peer device specified by bd_addr support BR/EDR
+ * Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by both
+ * local and the remote device.
+ * else false.
+ *
+ ******************************************************************************/
+extern bool BTM_BothEndsSupportSecureConnections(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PeerSupportsSecureConnections
+ *
+ * Description This function is called to check if the peer supports
+ * BR/EDR Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by the peer,
+ * else false.
+ *
+ ******************************************************************************/
+extern bool BTM_PeerSupportsSecureConnections(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadOobData
+ *
+ * Description This function is called to parse the OOB data payload
+ * received over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * eir_tag - The associated EIR tag to read the data.
+ * *p_len(output) - the length of the data with the given tag.
+ *
+ * Returns the beginning of the data with the given tag.
+ * NULL, if the tag is not found.
+ *
+ ******************************************************************************/
+extern uint8_t* BTM_ReadOobData(uint8_t* p_data, uint8_t eir_tag,
+ uint8_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecReadDevName
+ *
+ * Description Looks for the device name in the security database for the
+ * specified BD address.
+ *
+ * Returns Pointer to the name or NULL
+ *
+ ******************************************************************************/
+extern char* BTM_SecReadDevName(BD_ADDR bd_addr);
+
+/*****************************************************************************
+ * POWER MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_PmRegister
+ *
+ * Description register or deregister with power manager
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_NO_RESOURCES if no room to hold registration
+ * BTM_ILLEGAL_VALUE
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
+ tBTM_PM_STATUS_CBACK* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPowerMode
+ *
+ * Description store the mode in control block or
+ * alter ACL connection behavior.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, BD_ADDR remote_bda,
+ tBTM_PM_PWR_MD* p_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadPowerMode
+ *
+ * Description This returns the current mode for a specific
+ * ACL connection.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ *
+ * Output Param p_mode - address where the current mode is copied into.
+ * BTM_ACL_MODE_NORMAL
+ * BTM_ACL_MODE_HOLD
+ * BTM_ACL_MODE_SNIFF
+ * BTM_ACL_MODE_PARK
+ * (valid only if return code is BTM_SUCCESS)
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ReadPowerMode(BD_ADDR remote_bda, tBTM_PM_MODE* p_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSsrParams
+ *
+ * Description This sends the given SSR parameters for the given ACL
+ * connection if it is in ACTIVE mode.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ * max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+ * min_rmt_to - minimum remote timeout
+ * min_loc_to - minimum local timeout
+ *
+ *
+ * Returns BTM_SUCCESS if the HCI command is issued successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ * BTM_CMD_STORED if the command is stored
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetSsrParams(BD_ADDR remote_bda, uint16_t max_lat,
+ uint16_t min_rmt_to, uint16_t min_loc_to);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetHCIConnHandle
+ *
+ * Description This function is called to get the handle for an ACL
+ * connection to a specific remote BD Address.
+ *
+ * Returns the handle of the connection, or 0xFFFF if none.
+ *
+ ******************************************************************************/
+extern uint16_t BTM_GetHCIConnHandle(const BD_ADDR remote_bda,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_DeleteStoredLinkKey
+ *
+ * Description This function is called to delete link key for the specified
+ * device addresses from the NVRAM storage attached to the
+ * Bluetooth controller.
+ *
+ * Parameters: bd_addr - Addresses of the devices
+ * p_cb - Call back function to be called to return
+ * the results
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteEIR
+ *
+ * Description This function is called to write EIR data to controller.
+ *
+ * Parameters p_buff - allocated HCI command buffer including extended
+ * inquriry response
+ *
+ * Returns BTM_SUCCESS - if successful
+ * BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff);
+
+/*******************************************************************************
+ *
+ * Function BTM_HasEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters p_eir_uuid - bit map of UUID list
+ * uuid16 - UUID 16-bit
+ *
+ * Returns true - if found
+ * false - if not found
+ *
+ ******************************************************************************/
+extern bool BTM_HasEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_HasInquiryEirService
+ *
+ * Description Return if a UUID is in the bit map of a UUID list.
+ *
+ * Parameters p_results - inquiry results
+ * uuid16 - UUID 16-bit
+ *
+ * Returns BTM_EIR_FOUND - if found
+ * BTM_EIR_NOT_FOUND - if not found and it is a complete list
+ * BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+extern tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(
+ tBTM_INQ_RESULTS* p_results, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_AddEirService
+ *
+ * Description This function is called to add a service in the bit map UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveEirService
+ *
+ * Description This function is called to remove a service from the bit map
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirSupportedServices
+ *
+ * Description This function is called to get UUID list from bit map UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * p - reference of current pointer of EIR
+ * max_num_uuid16 - max number of UUID can be written in EIR
+ * num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+extern uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
+ uint8_t max_num_uuid16,
+ uint8_t* p_num_uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirUuidList
+ *
+ * Description This function parses EIR and returns UUID list.
+ *
+ * Parameters p_eir - EIR
+ * eirl_len - EIR len
+ * uuid_size - LEN_UUID_16, LEN_UUID_32, LEN_UUID_128
+ * p_num_uuid - return number of UUID in found list
+ * p_uuid_list - return UUID 16-bit list
+ * max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns 0 - if not found
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ * BTM_EIR_MORE_16BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ * BTM_EIR_MORE_32BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ * BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+extern uint8_t BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len,
+ uint8_t uuid_size, uint8_t* p_num_uuid,
+ uint8_t* p_uuid_list, uint8_t max_num_uuid);
+
+/*****************************************************************************
+ * SCO OVER HCI
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_ConfigScoPath
+ *
+ * Description This function enable/disable SCO over HCI and registers SCO
+ * data callback if SCO over HCI is enabled.
+ *
+ * Parameter path: SCO or HCI
+ * p_sco_data_cb: callback function or SCO data if path is set
+ * to transport.
+ * p_pcm_param: pointer to the PCM interface parameter. If a
+ * NULL pointer is used, the PCM parameter
+ * maintained in the control block will be used;
+ * otherwise update the control block value.
+ * err_data_rpt: Lisbon feature to enable the erronous data
+ * report or not.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_NO_RESOURCES: no rsource to start the command.
+ * BTM_ILLEGAL_VALUE: invalid callback function pointer.
+ * BTM_CMD_STARTED : Command sent. Waiting for command
+ * complete event.
+ *
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_ConfigScoPath(esco_data_path_t path,
+ tBTM_SCO_DATA_CB* p_sco_data_cb,
+ tBTM_SCO_PCM_PARAM* p_pcm_param,
+ bool err_data_rpt);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteScoData
+ *
+ * Description This function write SCO data to a specified instance. The
+ * data to be written p_buf needs to carry an offset of
+ * HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+ * exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is
+ * set to 60 and is configurable. Data longer than the maximum
+ * bytes will be truncated.
+ *
+ * Returns BTM_SUCCESS: data write is successful
+ * BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+ * BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO
+ * packet size.
+ * BTM_NO_RESOURCES: no resources.
+ * BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is
+ * not routed via HCI.
+ *
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_WriteScoData(uint16_t sco_inx, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetARCMode
+ *
+ * Description Send Audio Routing Control command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_SetARCMode(uint8_t iface, uint8_t arc_mode,
+ tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_PCM2Setup_Write
+ *
+ * Description Send PCM2_Setup write command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_PCM2Setup_Write(bool clk_master, tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_PM_ReadControllerState
+ *
+ * Description This function is called to obtain the controller state
+ *
+ * Returns Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and
+ * BTM_CONTRL_IDLE)
+ *
+ ******************************************************************************/
+extern tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void);
+
+#endif /* BTM_API_H */
diff --git a/mtkbt/code/bt/stack/include/btm_api_types.h b/mtkbt/code/bt/stack/include/btm_api_types.h
new file mode 100755
index 0000000..3c9bfa4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/btm_api_types.h
@@ -0,0 +1,1881 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_API_TYPES_H
+#define BTM_API_TYPES_H
+
+#include "bt_target.h"
+#include "device/include/esco_parameters.h"
+#include "hcidefs.h"
+#include "smp_api_types.h"
+
+/* Maximum number of bytes allowed for vendor specific command parameters */
+#define BTM_MAX_VENDOR_SPECIFIC_LEN HCI_COMMAND_SIZE
+
+/* BTM application return status codes */
+enum {
+ BTM_SUCCESS = 0, /* 0 Command succeeded */
+ BTM_CMD_STARTED, /* 1 Command started OK. */
+ BTM_BUSY, /* 2 Device busy with another command */
+ BTM_NO_RESOURCES, /* 3 No resources to issue command */
+ BTM_MODE_UNSUPPORTED, /* 4 Request for 1 or more unsupported modes */
+ BTM_ILLEGAL_VALUE, /* 5 Illegal parameter value */
+ BTM_WRONG_MODE, /* 6 Device in wrong mode for request */
+ BTM_UNKNOWN_ADDR, /* 7 Unknown remote BD address */
+ BTM_DEVICE_TIMEOUT, /* 8 Device timeout */
+ BTM_BAD_VALUE_RET, /* 9 A bad value was received from HCI */
+ BTM_ERR_PROCESSING, /* 10 Generic error */
+ BTM_NOT_AUTHORIZED, /* 11 Authorization failed */
+ BTM_DEV_RESET, /* 12 Device has been reset */
+ BTM_CMD_STORED, /* 13 request is stored in control block */
+ BTM_ILLEGAL_ACTION, /* 14 state machine gets illegal command */
+ BTM_DELAY_CHECK, /* 15 delay the check on encryption */
+ BTM_SCO_BAD_LENGTH, /* 16 Bad SCO over HCI data length */
+ BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */
+ BTM_FAILED_ON_SECURITY, /* 18 security failed */
+ BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED /* 20 Secure Connections Only Mode can't be
+ supported */
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#if defined(HANDLE_KEY_MISSING) && (HANDLE_KEY_MISSING == TRUE)
+ ,BTM_ERR_KEY_MISSING /* 21 Handle for Pin_or_Key_Missing Issue*/
+#endif
+#endif
+
+};
+
+typedef uint8_t tBTM_STATUS;
+
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+typedef enum {
+ BTM_BR_ONE, /*0 First state or BR/EDR scan 1*/
+ BTM_BLE_ONE, /*1BLE scan 1*/
+ BTM_BR_TWO, /*2 BR/EDR scan 2*/
+ BTM_BLE_TWO, /*3 BLE scan 2*/
+ BTM_FINISH, /*4 End of Interleave Scan, or normal scan*/
+ BTM_NO_INTERLEAVING /*5 No Interleaving*/
+} btm_inq_state;
+#endif
+
+/*************************
+ * Device Control Types
+ *************************/
+#define BTM_DEVICE_ROLE_BR 0x01
+#define BTM_DEVICE_ROLE_DUAL 0x02
+#define BTM_MAX_DEVICE_ROLE BTM_DEVICE_ROLE_DUAL
+typedef uint8_t tBTM_DEVICE_ROLE;
+
+/* Device name of peer (may be truncated to save space in BTM database) */
+typedef uint8_t tBTM_BD_NAME[BTM_MAX_REM_BD_NAME_LEN + 1];
+
+/* Structure returned with local version information */
+typedef struct {
+ uint8_t hci_version;
+ uint16_t hci_revision;
+ uint8_t lmp_version;
+ uint16_t manufacturer;
+ uint16_t lmp_subversion;
+} tBTM_VERSION_INFO;
+
+/* Structure returned with Vendor Specific Command complete callback */
+typedef struct {
+ uint16_t opcode;
+ uint16_t param_len;
+ uint8_t* p_param_buf;
+} tBTM_VSC_CMPL;
+
+#define BTM_VSC_CMPL_DATA_SIZE \
+ (BTM_MAX_VENDOR_SPECIFIC_LEN + sizeof(tBTM_VSC_CMPL))
+/**************************************************
+ * Device Control and General Callback Functions
+ **************************************************/
+/* Callback function for when device status changes. Appl must poll for
+ * what the new state is (BTM_IsDeviceUp). The event occurs whenever the stack
+ * has detected that the controller status has changed. This asynchronous event
+ * is enabled/disabled by calling BTM_RegisterForDeviceStatusNotif().
+*/
+enum { BTM_DEV_STATUS_UP, BTM_DEV_STATUS_DOWN, BTM_DEV_STATUS_CMD_TOUT };
+
+typedef uint8_t tBTM_DEV_STATUS;
+
+typedef void(tBTM_DEV_STATUS_CB)(tBTM_DEV_STATUS status);
+
+/* Callback function for when a vendor specific event occurs. The length and
+ * array of returned parameter bytes are included. This asynchronous event
+ * is enabled/disabled by calling BTM_RegisterForVSEvents().
+*/
+typedef void(tBTM_VS_EVT_CB)(uint8_t len, uint8_t* p);
+
+/* General callback function for notifying an application that a synchronous
+ * BTM function is complete. The pointer contains the address of any returned
+ * data.
+ */
+typedef void(tBTM_CMPL_CB)(void* p1);
+
+/* VSC callback function for notifying an application that a synchronous
+ * BTM function is complete. The pointer contains the address of any returned
+ * data.
+ */
+typedef void(tBTM_VSC_CMPL_CB)(tBTM_VSC_CMPL* p1);
+
+/* Callback for apps to check connection and inquiry filters.
+ * Parameters are the BD Address of remote and the Dev Class of remote. If the
+ * app returns none zero, the connection or inquiry result will be dropped.
+*/
+typedef uint8_t(tBTM_FILTER_CB)(BD_ADDR bd_addr, DEV_CLASS dc);
+
+/*****************************************************************************
+ * DEVICE DISCOVERY - Inquiry, Remote Name, Discovery, Class of Device
+ ****************************************************************************/
+/*******************************
+ * Device Discovery Constants
+ *******************************/
+/* Discoverable modes */
+#define BTM_NON_DISCOVERABLE 0
+#define BTM_LIMITED_DISCOVERABLE 1
+#define BTM_GENERAL_DISCOVERABLE 2
+#define BTM_DISCOVERABLE_MASK \
+ (BTM_LIMITED_DISCOVERABLE | BTM_GENERAL_DISCOVERABLE)
+#define BTM_MAX_DISCOVERABLE BTM_GENERAL_DISCOVERABLE
+/* high byte for BLE Discoverable modes */
+#define BTM_BLE_NON_DISCOVERABLE 0x0000
+#define BTM_BLE_LIMITED_DISCOVERABLE 0x0100
+#define BTM_BLE_GENERAL_DISCOVERABLE 0x0200
+#define BTM_BLE_MAX_DISCOVERABLE BTM_BLE_GENERAL_DISCOVERABLE
+#define BTM_BLE_DISCOVERABLE_MASK \
+ (BTM_BLE_NON_DISCOVERABLE | BTM_BLE_LIMITED_DISCOVERABLE | \
+ BTM_BLE_GENERAL_DISCOVERABLE)
+
+/* Connectable modes */
+#define BTM_NON_CONNECTABLE 0
+#define BTM_CONNECTABLE 1
+#define BTM_CONNECTABLE_MASK (BTM_NON_CONNECTABLE | BTM_CONNECTABLE)
+/* high byte for BLE Connectable modes */
+#define BTM_BLE_NON_CONNECTABLE 0x0000
+#define BTM_BLE_CONNECTABLE 0x0100
+#define BTM_BLE_MAX_CONNECTABLE BTM_BLE_CONNECTABLE
+#define BTM_BLE_CONNECTABLE_MASK (BTM_BLE_NON_CONNECTABLE | BTM_BLE_CONNECTABLE)
+
+/* Inquiry modes
+ * Note: These modes are associated with the inquiry active values (BTM_*ACTIVE)
+ */
+#define BTM_INQUIRY_NONE 0
+#define BTM_GENERAL_INQUIRY 0x01
+#define BTM_LIMITED_INQUIRY 0x02
+#define BTM_BR_INQUIRY_MASK (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY)
+
+/* high byte of inquiry mode for BLE inquiry mode */
+#define BTM_BLE_INQUIRY_NONE 0x00
+#define BTM_BLE_GENERAL_INQUIRY 0x10
+#define BTM_BLE_LIMITED_INQUIRY 0x20
+#define BTM_BLE_INQUIRY_MASK (BTM_BLE_GENERAL_INQUIRY | BTM_BLE_LIMITED_INQUIRY)
+
+/* BTM_IsInquiryActive return values (Bit Mask)
+ * Note: These bit masks are associated with the inquiry modes (BTM_*_INQUIRY)
+ */
+/* no inquiry in progress */
+#define BTM_INQUIRY_INACTIVE 0x0
+/* a general inquiry is in progress */
+#define BTM_GENERAL_INQUIRY_ACTIVE BTM_GENERAL_INQUIRY
+/* a limited inquiry is in progress */
+#define BTM_LIMITED_INQUIRY_ACTIVE BTM_LIMITED_INQUIRY
+/* a periodic inquiry is active */
+#define BTM_PERIODIC_INQUIRY_ACTIVE 0x8
+/* SSP is active, so inquiry is disallowed (work around for FW bug) */
+#define BTM_SSP_INQUIRY_ACTIVE 0x4
+/* a general inquiry is in progress */
+#define BTM_LE_GENERAL_INQUIRY_ACTIVE BTM_BLE_GENERAL_INQUIRY
+/* a limited inquiry is in progress */
+#define BTM_LE_LIMITED_INQUIRY_ACTIVE BTM_BLE_LIMITED_INQUIRY
+
+/* inquiry activity mask */
+/* BR/EDR inquiry activity mask */
+#define BTM_BR_INQ_ACTIVE_MASK \
+ (BTM_GENERAL_INQUIRY_ACTIVE | BTM_LIMITED_INQUIRY_ACTIVE | \
+ BTM_PERIODIC_INQUIRY_ACTIVE)
+/* LE scan activity mask */
+#define BTM_BLE_SCAN_ACTIVE_MASK 0xF0
+/* LE inquiry activity mask*/
+#define BTM_BLE_INQ_ACTIVE_MASK \
+ (BTM_LE_GENERAL_INQUIRY_ACTIVE | BTM_LE_LIMITED_INQUIRY_ACTIVE)
+/* inquiry activity mask */
+#define BTM_INQUIRY_ACTIVE_MASK \
+ (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)
+
+/* Define scan types */
+#define BTM_SCAN_TYPE_STANDARD 0
+#define BTM_SCAN_TYPE_INTERLACED 1 /* 1.2 devices only */
+
+/* Define inquiry results mode */
+#define BTM_INQ_RESULT_STANDARD 0
+#define BTM_INQ_RESULT_WITH_RSSI 1
+#define BTM_INQ_RESULT_EXTENDED 2
+/* RSSI value not supplied (ignore it) */
+#define BTM_INQ_RES_IGNORE_RSSI 0x7f
+
+/* Inquiry Filter Condition types (see tBTM_INQ_PARMS) */
+/* Inquiry Filtering is turned off */
+#define BTM_CLR_INQUIRY_FILTER 0
+/* Filter on device class */
+#define BTM_FILTER_COND_DEVICE_CLASS HCI_FILTER_COND_DEVICE_CLASS
+/* Filter on device addr */
+#define BTM_FILTER_COND_BD_ADDR HCI_FILTER_COND_BD_ADDR
+
+/* State of the remote name retrieval during inquiry operations.
+ * Used in the tBTM_INQ_INFO structure, and returned in the
+ * BTM_InqDbRead, BTM_InqDbFirst, and BTM_InqDbNext functions.
+ * The name field is valid when the state returned is
+ * BTM_INQ_RMT_NAME_DONE */
+#define BTM_INQ_RMT_NAME_EMPTY 0
+#define BTM_INQ_RMT_NAME_PENDING 1
+#define BTM_INQ_RMT_NAME_DONE 2
+#define BTM_INQ_RMT_NAME_FAILED 3
+
+/*********************************
+ *** Class of Device constants ***
+ *********************************/
+#define BTM_FORMAT_TYPE_1 0x00
+
+/****************************
+ * minor device class field
+ ****************************/
+
+/* 0x00 is used as unclassified for all minor device classes */
+#define BTM_COD_MINOR_UNCLASSIFIED 0x00
+
+/* minor device class field for Computer Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_DESKTOP_WORKSTATION 0x04
+#define BTM_COD_MINOR_SERVER_COMPUTER 0x08
+#define BTM_COD_MINOR_LAPTOP 0x0C
+#define BTM_COD_MINOR_HANDHELD_PC_PDA 0x10 /* clam shell */
+#define BTM_COD_MINOR_PALM_SIZE_PC_PDA 0x14
+#define BTM_COD_MINOR_WEARABLE_COMPUTER 0x18 /* watch sized */
+
+/* minor device class field for Phone Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_CELLULAR 0x04
+#define BTM_COD_MINOR_CORDLESS 0x08
+#define BTM_COD_MINOR_SMART_PHONE 0x0C
+/* wired modem or voice gatway */
+#define BTM_COD_MINOR_WIRED_MDM_V_GTWY 0x10
+#define BTM_COD_MINOR_ISDN_ACCESS 0x14
+
+/* minor device class field for LAN Access Point Major Class */
+/* Load Factor Field bit 5-7 */
+#define BTM_COD_MINOR_FULLY_AVAILABLE 0x00
+#define BTM_COD_MINOR_1_17_UTILIZED 0x20
+#define BTM_COD_MINOR_17_33_UTILIZED 0x40
+#define BTM_COD_MINOR_33_50_UTILIZED 0x60
+#define BTM_COD_MINOR_50_67_UTILIZED 0x80
+#define BTM_COD_MINOR_67_83_UTILIZED 0xA0
+#define BTM_COD_MINOR_83_99_UTILIZED 0xC0
+#define BTM_COD_MINOR_NO_SERVICE_AVAILABLE 0xE0
+/* sub-Field bit 2-4 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+
+/* minor device class field for Audio/Video Major Class */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_CONFM_HEADSET 0x04
+#define BTM_COD_MINOR_CONFM_HANDSFREE 0x08
+#define BTM_COD_MINOR_MICROPHONE 0x10
+#define BTM_COD_MINOR_LOUDSPEAKER 0x14
+#define BTM_COD_MINOR_HEADPHONES 0x18
+#define BTM_COD_MINOR_PORTABLE_AUDIO 0x1C
+#define BTM_COD_MINOR_CAR_AUDIO 0x20
+#define BTM_COD_MINOR_SET_TOP_BOX 0x24
+#define BTM_COD_MINOR_HIFI_AUDIO 0x28
+#define BTM_COD_MINOR_VCR 0x2C
+#define BTM_COD_MINOR_VIDEO_CAMERA 0x30
+#define BTM_COD_MINOR_CAMCORDER 0x34
+#define BTM_COD_MINOR_VIDEO_MONITOR 0x38
+#define BTM_COD_MINOR_VIDDISP_LDSPKR 0x3C
+#define BTM_COD_MINOR_VIDEO_CONFERENCING 0x40
+#define BTM_COD_MINOR_GAMING_TOY 0x48
+
+/* minor device class field for Peripheral Major Class */
+/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */
+#define BTM_COD_MINOR_KEYBOARD 0x40
+#define BTM_COD_MINOR_POINTING 0x80
+#define BTM_COD_MINOR_COMBO 0xC0
+/* Bits 2-5 OR'd with selection from bits 6-7 */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+#define BTM_COD_MINOR_JOYSTICK 0x04
+#define BTM_COD_MINOR_GAMEPAD 0x08
+#define BTM_COD_MINOR_REMOTE_CONTROL 0x0C
+#define BTM_COD_MINOR_SENSING_DEVICE 0x10
+#define BTM_COD_MINOR_DIGITIZING_TABLET 0x14
+#define BTM_COD_MINOR_CARD_READER 0x18 /* e.g. SIM card reader */
+#define BTM_COD_MINOR_DIGITAL_PAN 0x1C
+#define BTM_COD_MINOR_HAND_SCANNER 0x20
+#define BTM_COD_MINOR_HAND_GESTURAL_INPUT 0x24
+
+/* minor device class field for Imaging Major Class */
+/* Bits 5-7 independently specify display, camera, scanner, or printer */
+#define BTM_COD_MINOR_DISPLAY 0x10
+#define BTM_COD_MINOR_CAMERA 0x20
+#define BTM_COD_MINOR_SCANNER 0x40
+#define BTM_COD_MINOR_PRINTER 0x80
+/* Bits 2-3 Reserved */
+/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
+
+/* minor device class field for Wearable Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_WRIST_WATCH 0x04
+#define BTM_COD_MINOR_PAGER 0x08
+#define BTM_COD_MINOR_JACKET 0x0C
+#define BTM_COD_MINOR_HELMET 0x10
+#define BTM_COD_MINOR_GLASSES 0x14
+
+/* minor device class field for Toy Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_ROBOT 0x04
+#define BTM_COD_MINOR_VEHICLE 0x08
+#define BTM_COD_MINOR_DOLL_ACTION_FIGURE 0x0C
+#define BTM_COD_MINOR_CONTROLLER 0x10
+#define BTM_COD_MINOR_GAME 0x14
+
+/* minor device class field for Health Major Class */
+/* Bits 2-7 meaningful */
+#define BTM_COD_MINOR_BLOOD_MONITOR 0x04
+#define BTM_COD_MINOR_THERMOMETER 0x08
+#define BTM_COD_MINOR_WEIGHING_SCALE 0x0C
+#define BTM_COD_MINOR_GLUCOSE_METER 0x10
+#define BTM_COD_MINOR_PULSE_OXIMETER 0x14
+#define BTM_COD_MINOR_HEART_PULSE_MONITOR 0x18
+#define BTM_COD_MINOR_HEALTH_DATA_DISPLAY 0x1C
+#define BTM_COD_MINOR_STEP_COUNTER 0x20
+#define BTM_COD_MINOR_BODY_COM_ANALYZER 0x24
+#define BTM_COD_MINOR_PEAK_FLOW_MONITOR 0x28
+#define BTM_COD_MINOR_MEDICATION_MONITOR 0x2C
+#define BTM_COD_MINOR_KNEE_PROSTHESIS 0x30
+#define BTM_COD_MINOR_ANKLE_PROSTHESIS 0x34
+
+/***************************
+ * major device class field
+ ***************************/
+#define BTM_COD_MAJOR_MISCELLANEOUS 0x00
+#define BTM_COD_MAJOR_COMPUTER 0x01
+#define BTM_COD_MAJOR_PHONE 0x02
+#define BTM_COD_MAJOR_LAN_ACCESS_PT 0x03
+#define BTM_COD_MAJOR_AUDIO 0x04
+#define BTM_COD_MAJOR_PERIPHERAL 0x05
+#define BTM_COD_MAJOR_IMAGING 0x06
+#define BTM_COD_MAJOR_WEARABLE 0x07
+#define BTM_COD_MAJOR_TOY 0x08
+#define BTM_COD_MAJOR_HEALTH 0x09
+#define BTM_COD_MAJOR_UNCLASSIFIED 0x1F
+
+/***************************
+ * service class fields
+ ***************************/
+#define BTM_COD_SERVICE_LMTD_DISCOVER 0x0020
+#define BTM_COD_SERVICE_POSITIONING 0x0100
+#define BTM_COD_SERVICE_NETWORKING 0x0200
+#define BTM_COD_SERVICE_RENDERING 0x0400
+#define BTM_COD_SERVICE_CAPTURING 0x0800
+#define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000
+#define BTM_COD_SERVICE_AUDIO 0x2000
+#define BTM_COD_SERVICE_TELEPHONY 0x4000
+#define BTM_COD_SERVICE_INFORMATION 0x8000
+
+/* class of device field macros */
+#define BTM_COD_FORMAT_TYPE(u8, pd) \
+ { (u8) = (pd)[2] & 0x03; }
+#define BTM_COD_MINOR_CLASS(u8, pd) \
+ { (u8) = (pd)[2] & 0xFC; }
+#define BTM_COD_MAJOR_CLASS(u8, pd) \
+ { (u8) = (pd)[1] & 0x1F; }
+#define BTM_COD_SERVICE_CLASS(u16, pd) \
+ { \
+ (u16) = (pd)[0]; \
+ (u16) <<= 8; \
+ (u16) += (pd)[1] & 0xE0; \
+ }
+
+/* to set the fields (assumes that format type is always 0) */
+#define FIELDS_TO_COD(pd, mn, mj, sv) \
+ { \
+ (pd)[2] = mn; \
+ (pd)[1] = (mj) + ((sv)&BTM_COD_SERVICE_CLASS_LO_B); \
+ (pd)[0] = (sv) >> 8; \
+ }
+
+/* the COD masks */
+#define BTM_COD_FORMAT_TYPE_MASK 0x03
+#define BTM_COD_MINOR_CLASS_MASK 0xFC
+#define BTM_COD_MAJOR_CLASS_MASK 0x1F
+#define BTM_COD_SERVICE_CLASS_LO_B 0x00E0
+#define BTM_COD_SERVICE_CLASS_MASK 0xFFE0
+
+/* BTM service definitions
+ * Used for storing EIR data to bit mask
+*/
+enum {
+ BTM_EIR_UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER,
+ /* BTM_EIR_UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR, */
+ /* BTM_EIR_UUID_SERVCLASS_PUBLIC_BROWSE_GROUP, */
+ BTM_EIR_UUID_SERVCLASS_SERIAL_PORT,
+ BTM_EIR_UUID_SERVCLASS_LAN_ACCESS_USING_PPP,
+ BTM_EIR_UUID_SERVCLASS_DIALUP_NETWORKING,
+ BTM_EIR_UUID_SERVCLASS_IRMC_SYNC,
+ BTM_EIR_UUID_SERVCLASS_OBEX_OBJECT_PUSH,
+ BTM_EIR_UUID_SERVCLASS_OBEX_FILE_TRANSFER,
+ BTM_EIR_UUID_SERVCLASS_IRMC_SYNC_COMMAND,
+ BTM_EIR_UUID_SERVCLASS_HEADSET,
+ BTM_EIR_UUID_SERVCLASS_CORDLESS_TELEPHONY,
+ BTM_EIR_UUID_SERVCLASS_AUDIO_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_AUDIO_SINK,
+ BTM_EIR_UUID_SERVCLASS_AV_REM_CTRL_TARGET,
+ /* BTM_EIR_UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, */
+ BTM_EIR_UUID_SERVCLASS_AV_REMOTE_CONTROL,
+ /* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING, */
+ BTM_EIR_UUID_SERVCLASS_INTERCOM,
+ BTM_EIR_UUID_SERVCLASS_FAX,
+ BTM_EIR_UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ /* BTM_EIR_UUID_SERVCLASS_WAP, */
+ /* BTM_EIR_UUID_SERVCLASS_WAP_CLIENT, */
+ BTM_EIR_UUID_SERVCLASS_PANU,
+ BTM_EIR_UUID_SERVCLASS_NAP,
+ BTM_EIR_UUID_SERVCLASS_GN,
+ BTM_EIR_UUID_SERVCLASS_DIRECT_PRINTING,
+ /* BTM_EIR_UUID_SERVCLASS_REFERENCE_PRINTING, */
+ BTM_EIR_UUID_SERVCLASS_IMAGING,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_RESPONDER,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE,
+ BTM_EIR_UUID_SERVCLASS_IMAGING_REF_OBJECTS,
+ BTM_EIR_UUID_SERVCLASS_HF_HANDSFREE,
+ BTM_EIR_UUID_SERVCLASS_AG_HANDSFREE,
+ BTM_EIR_UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE,
+ /* BTM_EIR_UUID_SERVCLASS_REFLECTED_UI, */
+ BTM_EIR_UUID_SERVCLASS_BASIC_PRINTING,
+ BTM_EIR_UUID_SERVCLASS_PRINTING_STATUS,
+ BTM_EIR_UUID_SERVCLASS_HUMAN_INTERFACE,
+ BTM_EIR_UUID_SERVCLASS_CABLE_REPLACEMENT,
+ BTM_EIR_UUID_SERVCLASS_HCRP_PRINT,
+ BTM_EIR_UUID_SERVCLASS_HCRP_SCAN,
+ /* BTM_EIR_UUID_SERVCLASS_COMMON_ISDN_ACCESS, */
+ /* BTM_EIR_UUID_SERVCLASS_VIDEO_CONFERENCING_GW, */
+ /* BTM_EIR_UUID_SERVCLASS_UDI_MT, */
+ /* BTM_EIR_UUID_SERVCLASS_UDI_TA, */
+ /* BTM_EIR_UUID_SERVCLASS_VCP, */
+ BTM_EIR_UUID_SERVCLASS_SAP,
+ BTM_EIR_UUID_SERVCLASS_PBAP_PCE,
+ BTM_EIR_UUID_SERVCLASS_PBAP_PSE,
+ /* BTM_EIR_UUID_SERVCLASS_TE_PHONE_ACCESS, */
+ /* BTM_EIR_UUID_SERVCLASS_ME_PHONE_ACCESS, */
+ BTM_EIR_UUID_SERVCLASS_PHONE_ACCESS,
+ BTM_EIR_UUID_SERVCLASS_HEADSET_HS,
+ BTM_EIR_UUID_SERVCLASS_PNP_INFORMATION,
+ /* BTM_EIR_UUID_SERVCLASS_GENERIC_NETWORKING, */
+ /* BTM_EIR_UUID_SERVCLASS_GENERIC_FILETRANSFER, */
+ /* BTM_EIR_UUID_SERVCLASS_GENERIC_AUDIO, */
+ /* BTM_EIR_UUID_SERVCLASS_GENERIC_TELEPHONY, */
+ /* BTM_EIR_UUID_SERVCLASS_UPNP_SERVICE, */
+ /* BTM_EIR_UUID_SERVCLASS_UPNP_IP_SERVICE, */
+ /* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_PAN, */
+ /* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_LAP, */
+ /* BTM_EIR_UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP, */
+ BTM_EIR_UUID_SERVCLASS_VIDEO_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_VIDEO_SINK,
+ /* BTM_EIR_UUID_SERVCLASS_VIDEO_DISTRIBUTION */
+ /* BTM_EIR_UUID_SERVCLASS_HDP_PROFILE */
+ BTM_EIR_UUID_SERVCLASS_MESSAGE_ACCESS,
+ BTM_EIR_UUID_SERVCLASS_MESSAGE_NOTIFICATION,
+ BTM_EIR_UUID_SERVCLASS_HDP_SOURCE,
+ BTM_EIR_UUID_SERVCLASS_HDP_SINK,
+ BTM_EIR_MAX_SERVICES
+};
+
+/* search result in EIR of inquiry database */
+#define BTM_EIR_FOUND 0
+#define BTM_EIR_NOT_FOUND 1
+#define BTM_EIR_UNKNOWN 2
+
+typedef uint8_t tBTM_EIR_SEARCH_RESULT;
+
+/* 0x01 */
+#define BTM_EIR_FLAGS_TYPE HCI_EIR_FLAGS_TYPE
+/* 0x02 */
+#define BTM_EIR_MORE_16BITS_UUID_TYPE HCI_EIR_MORE_16BITS_UUID_TYPE
+/* 0x03 */
+#define BTM_EIR_COMPLETE_16BITS_UUID_TYPE HCI_EIR_COMPLETE_16BITS_UUID_TYPE
+/* 0x04 */
+#define BTM_EIR_MORE_32BITS_UUID_TYPE HCI_EIR_MORE_32BITS_UUID_TYPE
+/* 0x05 */
+#define BTM_EIR_COMPLETE_32BITS_UUID_TYPE HCI_EIR_COMPLETE_32BITS_UUID_TYPE
+/* 0x06 */
+#define BTM_EIR_MORE_128BITS_UUID_TYPE HCI_EIR_MORE_128BITS_UUID_TYPE
+/* 0x07 */
+#define BTM_EIR_COMPLETE_128BITS_UUID_TYPE HCI_EIR_COMPLETE_128BITS_UUID_TYPE
+/* 0x08 */
+#define BTM_EIR_SHORTENED_LOCAL_NAME_TYPE HCI_EIR_SHORTENED_LOCAL_NAME_TYPE
+/* 0x09 */
+#define BTM_EIR_COMPLETE_LOCAL_NAME_TYPE HCI_EIR_COMPLETE_LOCAL_NAME_TYPE
+/* 0x0A */
+#define BTM_EIR_TX_POWER_LEVEL_TYPE HCI_EIR_TX_POWER_LEVEL_TYPE
+/* 0xFF */
+#define BTM_EIR_MANUFACTURER_SPECIFIC_TYPE HCI_EIR_MANUFACTURER_SPECIFIC_TYPE
+
+/* the following EIR tags are defined to OOB, not regular EIR data */
+/* 6 bytes */
+#define BTM_EIR_OOB_BD_ADDR_TYPE HCI_EIR_OOB_BD_ADDR_TYPE
+/* 3 bytes */
+#define BTM_EIR_OOB_COD_TYPE HCI_EIR_OOB_COD_TYPE
+/* 16 bytes */
+#define BTM_EIR_OOB_SSP_HASH_C_TYPE HCI_EIR_OOB_SSP_HASH_C_TYPE
+/* 16 bytes */
+#define BTM_EIR_OOB_SSP_RAND_R_TYPE HCI_EIR_OOB_SSP_RAND_R_TYPE
+
+/* include 2 bytes length & 6 bytes bd_addr */
+#define BTM_OOB_MANDATORY_SIZE 8
+#define BTM_OOB_DATA_LEN_SIZE 2
+#define BTM_OOB_BD_ADDR_SIZE 6
+#define BTM_OOB_COD_SIZE BT_OOB_COD_SIZE
+#define BTM_OOB_HASH_C_SIZE BT_OOB_HASH_C_SIZE
+#define BTM_OOB_RAND_R_SIZE BT_OOB_RAND_R_SIZE
+
+#define BTM_BLE_SEC_NONE 0
+/* encrypt the link using current key */
+#define BTM_BLE_SEC_ENCRYPT 1
+#define BTM_BLE_SEC_ENCRYPT_NO_MITM 2
+#define BTM_BLE_SEC_ENCRYPT_MITM 3
+typedef uint8_t tBTM_BLE_SEC_ACT;
+
+/*******************************************************************************
+ * BTM Services MACROS handle array of uint32_t bits for more than 32 services
+ ******************************************************************************/
+/* Determine the number of uint32_t's necessary for services */
+#define BTM_EIR_ARRAY_BITS 32 /* Number of bits in each array element */
+#define BTM_EIR_SERVICE_ARRAY_SIZE \
+ (((uint32_t)BTM_EIR_MAX_SERVICES / BTM_EIR_ARRAY_BITS) + \
+ (((uint32_t)BTM_EIR_MAX_SERVICES % BTM_EIR_ARRAY_BITS) ? 1 : 0))
+
+/* MACRO to set the service bit mask in a bit stream */
+#define BTM_EIR_SET_SERVICE(p, service) \
+ (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] |= \
+ ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)))
+
+/* MACRO to clear the service bit mask in a bit stream */
+#define BTM_EIR_CLR_SERVICE(p, service) \
+ (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] &= \
+ ~((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS)))
+
+/* MACRO to check the service bit mask in a bit stream */
+#define BTM_EIR_HAS_SERVICE(p, service) \
+ ((((uint32_t*)(p))[(((uint32_t)(service)) / BTM_EIR_ARRAY_BITS)] & \
+ ((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) >> \
+ (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))
+
+/* start of EIR in HCI buffer, 4 bytes = HCI Command(2) + Length(1) + FEC_Req(1)
+ */
+#define BTM_HCI_EIR_OFFSET (BT_HDR_SIZE + 4)
+
+/***************************
+ * Device Discovery Types
+ ***************************/
+/* Definitions of the parameters passed to BTM_StartInquiry and
+ * BTM_SetPeriodicInquiryMode.
+*/
+typedef struct /* contains the two device class condition fields */
+{
+ DEV_CLASS dev_class;
+ DEV_CLASS dev_class_mask;
+} tBTM_COD_COND;
+
+typedef union /* contains the inquiry filter condition */
+{
+ BD_ADDR bdaddr_cond;
+ tBTM_COD_COND cod_cond;
+} tBTM_INQ_FILT_COND;
+
+typedef struct /* contains the parameters passed to the inquiry functions */
+{
+ uint8_t mode; /* general or limited */
+ uint8_t duration; /* duration of the inquiry (1.28 sec increments) */
+ uint8_t max_resps; /* maximum number of responses to return */
+ bool report_dup; /* report duplicated inquiry response with higher RSSI value
+ */
+ uint8_t filter_cond_type; /* new devices, BD ADDR, COD, or No filtering */
+ tBTM_INQ_FILT_COND filter_cond; /* filter value based on filter cond type */
+#if (BTA_HOST_INTERLEAVE_SEARCH == TRUE)
+ uint8_t intl_duration
+ [4]; /*duration array storing the interleave scan's time portions*/
+#endif
+} tBTM_INQ_PARMS;
+
+#define BTM_INQ_RESULT_BR 0x01
+#define BTM_INQ_RESULT_BLE 0x02
+
+constexpr uint8_t BLE_EVT_CONNECTABLE_BIT = 0;
+constexpr uint8_t BLE_EVT_SCANNABLE_BIT = 1;
+constexpr uint8_t BLE_EVT_DIRECTED_BIT = 2;
+constexpr uint8_t BLE_EVT_SCAN_RESPONSE_BIT = 3;
+constexpr uint8_t BLE_EVT_LEGACY_BIT = 4;
+
+constexpr uint8_t PHY_LE_NO_PACKET = 0x00;
+constexpr uint8_t PHY_LE_1M = 0x01;
+constexpr uint8_t PHY_LE_2M = 0x02;
+constexpr uint8_t PHY_LE_CODED = 0x03;
+
+constexpr uint8_t NO_ADI_PRESENT = 0xFF;
+constexpr uint8_t TX_POWER_NOT_PRESENT = 0x7F;
+
+/* These are the fields returned in each device's response to the inquiry. It
+ * is returned in the results callback if registered.
+*/
+typedef struct {
+ uint16_t clock_offset;
+ BD_ADDR remote_bd_addr;
+ DEV_CLASS dev_class;
+ uint8_t page_scan_rep_mode;
+ uint8_t page_scan_per_mode;
+ uint8_t page_scan_mode;
+ int8_t rssi; /* Set to BTM_INQ_RES_IGNORE_RSSI if not valid */
+ uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE];
+ bool eir_complete_list;
+ tBT_DEVICE_TYPE device_type;
+ uint8_t inq_result_type;
+ uint8_t ble_addr_type;
+ uint16_t ble_evt_type;
+ uint8_t ble_primary_phy;
+ uint8_t ble_secondary_phy;
+ uint8_t ble_advertising_sid;
+ int8_t ble_tx_power;
+ uint16_t ble_periodic_adv_int;
+ uint8_t flag;
+} tBTM_INQ_RESULTS;
+
+/* This is the inquiry response information held in its database by BTM, and
+ * available to applications via BTM_InqDbRead, BTM_InqDbFirst, and
+ * BTM_InqDbNext.
+*/
+typedef struct {
+ tBTM_INQ_RESULTS results;
+
+ bool appl_knows_rem_name; /* set by application if it knows the remote name of
+ the peer device.
+ This is later used by application to determine if
+ remote name request is
+ required to be done. Having the flag here avoid
+ duplicate store of inquiry results */
+ uint16_t remote_name_len;
+ tBTM_BD_NAME remote_name;
+ uint8_t remote_name_state;
+ uint8_t remote_name_type;
+
+} tBTM_INQ_INFO;
+
+/* Structure returned with inquiry complete callback */
+typedef struct {
+ tBTM_STATUS status;
+ uint8_t num_resp; /* Number of results from the current inquiry */
+} tBTM_INQUIRY_CMPL;
+
+/* Structure returned with remote name request */
+typedef struct {
+ uint16_t status;
+ BD_ADDR bd_addr;
+ uint16_t length;
+ BD_NAME remote_bd_name;
+} tBTM_REMOTE_DEV_NAME;
+
+typedef struct {
+ uint8_t pcm_intf_rate; /* PCM interface rate: 0: 128kbps, 1: 256 kbps;
+ 2:512 bps; 3: 1024kbps; 4: 2048kbps */
+ uint8_t frame_type; /* frame type: 0: short; 1: long */
+ uint8_t sync_mode; /* sync mode: 0: slave; 1: master */
+ uint8_t clock_mode; /* clock mode: 0: slave; 1: master */
+
+} tBTM_SCO_PCM_PARAM;
+
+/****************************************
+ * Device Discovery Callback Functions
+ ****************************************/
+/* Callback function for asynchronous notifications when the BTM inquiry DB
+ * changes. First param is inquiry database, second is if added to or removed
+ * from the inquiry database.
+*/
+typedef void(tBTM_INQ_DB_CHANGE_CB)(void* p1, bool is_new);
+
+/* Callback function for notifications when the BTM gets inquiry response.
+ * First param is inquiry results database, second is pointer of EIR.
+*/
+typedef void(tBTM_INQ_RESULTS_CB)(tBTM_INQ_RESULTS* p_inq_results,
+ uint8_t* p_eir, uint16_t eir_len);
+
+/*****************************************************************************
+ * ACL CHANNEL MANAGEMENT
+ ****************************************************************************/
+/******************
+ * ACL Constants
+ ******************/
+
+/* ACL modes */
+#define BTM_ACL_MODE_NORMAL HCI_MODE_ACTIVE
+#define BTM_ACL_MODE_HOLD HCI_MODE_HOLD
+#define BTM_ACL_MODE_SNIFF HCI_MODE_SNIFF
+#define BTM_ACL_MODE_PARK HCI_MODE_PARK
+
+/* Returned with structure in role switch callback (tBTM_ROLE_SWITCH_CMPL) */
+#define BTM_ROLE_MASTER HCI_ROLE_MASTER
+#define BTM_ROLE_SLAVE HCI_ROLE_SLAVE
+#define BTM_ROLE_UNDEFINED 0xff /* undefined value (error status) */
+
+/* ACL Packet Types */
+#define BTM_ACL_PKT_TYPES_MASK_DM1 HCI_PKT_TYPES_MASK_DM1
+#define BTM_ACL_PKT_TYPES_MASK_DH1 HCI_PKT_TYPES_MASK_DH1
+#define BTM_ACL_PKT_TYPES_MASK_DM3 HCI_PKT_TYPES_MASK_DM3
+#define BTM_ACL_PKT_TYPES_MASK_DH3 HCI_PKT_TYPES_MASK_DH3
+#define BTM_ACL_PKT_TYPES_MASK_DM5 HCI_PKT_TYPES_MASK_DM5
+#define BTM_ACL_PKT_TYPES_MASK_DH5 HCI_PKT_TYPES_MASK_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 HCI_PKT_TYPES_MASK_NO_2_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 HCI_PKT_TYPES_MASK_NO_3_DH1
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 HCI_PKT_TYPES_MASK_NO_2_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 HCI_PKT_TYPES_MASK_NO_3_DH3
+#define BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 HCI_PKT_TYPES_MASK_NO_2_DH5
+#define BTM_ACL_PKT_TYPES_MASK_NO_3_DH5 HCI_PKT_TYPES_MASK_NO_3_DH5
+
+/***************
+ * ACL Types
+ ***************/
+
+/* Structure returned with Role Switch information (in tBTM_CMPL_CB callback
+ * function) in response to BTM_SwitchRole call.
+*/
+typedef struct {
+ uint8_t hci_status; /* HCI status returned with the event */
+ uint8_t role; /* BTM_ROLE_MASTER or BTM_ROLE_SLAVE */
+ BD_ADDR remote_bd_addr; /* Remote BD addr involved with the switch */
+} tBTM_ROLE_SWITCH_CMPL;
+
+/* Structure returned with QoS information (in tBTM_CMPL_CB callback function)
+ * in response to BTM_SetQoS call.
+*/
+typedef struct {
+ FLOW_SPEC flow;
+ uint16_t handle;
+ uint8_t status;
+} tBTM_QOS_SETUP_CMPL;
+
+/* Structure returned with read RSSI event (in tBTM_CMPL_CB callback function)
+ * in response to BTM_ReadRSSI call.
+*/
+typedef struct {
+ tBTM_STATUS status;
+ uint8_t hci_status;
+ int8_t rssi;
+ BD_ADDR rem_bda;
+} tBTM_RSSI_RESULTS;
+
+/* Structure returned with read current TX power event (in tBTM_CMPL_CB callback
+ * function) in response to BTM_ReadTxPower call.
+*/
+typedef struct {
+ tBTM_STATUS status;
+ uint8_t hci_status;
+ int8_t tx_power;
+ BD_ADDR rem_bda;
+} tBTM_TX_POWER_RESULTS;
+
+/* Structure returned with read link quality event (in tBTM_CMPL_CB callback
+ * function) in response to BTM_ReadLinkQuality call.
+*/
+typedef struct {
+ tBTM_STATUS status;
+ uint8_t hci_status;
+ uint8_t link_quality;
+ BD_ADDR rem_bda;
+} tBTM_LINK_QUALITY_RESULTS;
+
+/* Structure returned with read inq tx power quality event (in tBTM_CMPL_CB
+ * callback function) in response to BTM_ReadInquiryRspTxPower call.
+*/
+typedef struct {
+ tBTM_STATUS status;
+ uint8_t hci_status;
+ int8_t tx_power;
+} tBTM_INQ_TXPWR_RESULTS;
+
+enum {
+ BTM_BL_CONN_EVT,
+ BTM_BL_DISCN_EVT,
+ BTM_BL_UPDATE_EVT,
+ BTM_BL_ROLE_CHG_EVT,
+ BTM_BL_COLLISION_EVT
+};
+typedef uint8_t tBTM_BL_EVENT;
+typedef uint16_t tBTM_BL_EVENT_MASK;
+
+#define BTM_BL_CONN_MASK 0x0001
+#define BTM_BL_DISCN_MASK 0x0002
+#define BTM_BL_UPDATE_MASK 0x0004
+#define BTM_BL_ROLE_CHG_MASK 0x0008
+
+/* Device features mask definitions */
+#define BTM_FEATURE_BYTES_PER_PAGE HCI_FEATURE_BYTES_PER_PAGE
+#define BTM_EXT_FEATURES_PAGE_MAX HCI_EXT_FEATURES_PAGE_MAX
+
+/* the data type associated with BTM_BL_CONN_EVT */
+typedef struct {
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the newly connected device */
+ DEV_CLASS_PTR p_dc; /* The device class */
+ BD_NAME_PTR p_bdn; /* The device name */
+ uint8_t* p_features; /* pointer to the remote device's features page[0]
+ (supported features page) */
+ uint16_t handle; /* connection handle */
+ tBT_TRANSPORT transport; /* link is LE or not */
+} tBTM_BL_CONN_DATA;
+
+/* the data type associated with BTM_BL_DISCN_EVT */
+typedef struct {
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the disconnected device */
+ uint16_t handle; /* disconnected connection handle */
+ tBT_TRANSPORT transport; /* link is LE link or not */
+} tBTM_BL_DISCN_DATA;
+
+/* Busy-Level shall have the inquiry_paging mask set when
+ * inquiry/paging is in progress, Else the number of ACL links */
+#define BTM_BL_INQUIRY_PAGING_MASK 0x10
+#define BTM_BL_INQUIRY_STARTED (BTM_BL_INQUIRY_PAGING_MASK | 0x1)
+#define BTM_BL_INQUIRY_CANCELLED (BTM_BL_INQUIRY_PAGING_MASK | 0x2)
+#define BTM_BL_INQUIRY_COMPLETE (BTM_BL_INQUIRY_PAGING_MASK | 0x3)
+#define BTM_BL_PAGING_STARTED (BTM_BL_INQUIRY_PAGING_MASK | 0x4)
+#define BTM_BL_PAGING_COMPLETE (BTM_BL_INQUIRY_PAGING_MASK | 0x5)
+/* the data type associated with BTM_BL_UPDATE_EVT */
+typedef struct {
+ tBTM_BL_EVENT event; /* The event reported. */
+ uint8_t busy_level; /* when paging or inquiring, level is 10.
+ * Otherwise, the number of ACL links. */
+ uint8_t busy_level_flags; /* Notifies actual inquiry/page activities */
+} tBTM_BL_UPDATE_DATA;
+
+/* the data type associated with BTM_BL_ROLE_CHG_EVT */
+typedef struct {
+ tBTM_BL_EVENT event; /* The event reported. */
+ BD_ADDR_PTR p_bda; /* The address of the peer connected device */
+ uint8_t new_role;
+ uint8_t hci_status; /* HCI status returned with the event */
+} tBTM_BL_ROLE_CHG_DATA;
+
+typedef union {
+ tBTM_BL_EVENT event; /* The event reported. */
+ tBTM_BL_CONN_DATA conn; /* The data associated with BTM_BL_CONN_EVT */
+ tBTM_BL_DISCN_DATA discn; /* The data associated with BTM_BL_DISCN_EVT */
+ tBTM_BL_UPDATE_DATA update; /* The data associated with BTM_BL_UPDATE_EVT */
+ tBTM_BL_ROLE_CHG_DATA
+ role_chg; /*The data associated with BTM_BL_ROLE_CHG_EVT */
+} tBTM_BL_EVENT_DATA;
+
+/* Callback function for notifications when the BTM busy level
+ * changes.
+*/
+typedef void(tBTM_BL_CHANGE_CB)(tBTM_BL_EVENT_DATA* p_data);
+
+/***************************
+ * ACL Callback Functions
+ ***************************/
+/* Callback function for notifications when the BTM ACL connection DB
+ * changes. First param is BD address, second is if added or removed.
+ * Registered through BTM_AclRegisterForChanges call.
+*/
+typedef void(tBTM_ACL_DB_CHANGE_CB)(BD_ADDR p_bda, DEV_CLASS p_dc,
+ BD_NAME p_bdn, uint8_t* features,
+ bool is_new, uint16_t handle,
+ tBT_TRANSPORT transport);
+/*****************************************************************************
+ * SCO CHANNEL MANAGEMENT
+ ****************************************************************************/
+/******************
+ * SCO Constants
+ ******************/
+
+/* Define an invalid SCO index and an invalid HCI handle */
+#define BTM_INVALID_SCO_INDEX 0xFFFF
+#define BTM_INVALID_HCI_HANDLE 0xFFFF
+
+/* Define an invalid SCO disconnect reason */
+#define BTM_INVALID_SCO_DISC_REASON 0xFFFF
+
+/* Define first active SCO index */
+#define BTM_FIRST_ACTIVE_SCO_INDEX BTM_MAX_SCO_LINKS
+
+#define BTM_SCO_LINK_ONLY_MASK \
+ (ESCO_PKT_TYPES_MASK_HV1 | ESCO_PKT_TYPES_MASK_HV2 | ESCO_PKT_TYPES_MASK_HV3)
+
+#define BTM_ESCO_LINK_ONLY_MASK \
+ (ESCO_PKT_TYPES_MASK_EV3 | ESCO_PKT_TYPES_MASK_EV4 | ESCO_PKT_TYPES_MASK_EV5)
+
+#define BTM_SCO_LINK_ALL_PKT_MASK \
+ (BTM_SCO_LINK_ONLY_MASK | BTM_ESCO_LINK_ONLY_MASK)
+
+#define BTM_VALID_SCO_ALL_PKT_TYPE HCI_VALID_SCO_ALL_PKT_TYPE
+
+/***************
+ * SCO Types
+ ***************/
+#define BTM_LINK_TYPE_SCO HCI_LINK_TYPE_SCO
+#define BTM_LINK_TYPE_ESCO HCI_LINK_TYPE_ESCO
+typedef uint8_t tBTM_SCO_TYPE;
+
+/*******************
+ * SCO Codec Types
+ *******************/
+// TODO(google) This should use common definitions
+#define BTM_SCO_CODEC_NONE 0x0000
+#define BTM_SCO_CODEC_CVSD 0x0001
+#define BTM_SCO_CODEC_MSBC 0x0002
+typedef uint16_t tBTM_SCO_CODEC_TYPE;
+
+/*******************
+ * SCO Voice Settings
+ *******************/
+#define BTM_VOICE_SETTING_CVSD \
+ ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \
+ HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD))
+
+#define BTM_VOICE_SETTING_TRANS \
+ ((uint16_t)(HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \
+ HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_TRANSPNT))
+
+/*******************
+ * SCO Data Status
+ *******************/
+enum {
+ BTM_SCO_DATA_CORRECT,
+ BTM_SCO_DATA_PAR_ERR,
+ BTM_SCO_DATA_NONE,
+ BTM_SCO_DATA_PAR_LOST
+};
+typedef uint8_t tBTM_SCO_DATA_FLAG;
+
+/***************************
+ * SCO Callback Functions
+ ***************************/
+typedef void(tBTM_SCO_CB)(uint16_t sco_inx);
+typedef void(tBTM_SCO_DATA_CB)(uint16_t sco_inx, BT_HDR* p_data,
+ tBTM_SCO_DATA_FLAG status);
+
+/***************
+ * eSCO Types
+ ***************/
+/* tBTM_ESCO_CBACK event types */
+#define BTM_ESCO_CHG_EVT 1
+#define BTM_ESCO_CONN_REQ_EVT 2
+typedef uint8_t tBTM_ESCO_EVT;
+
+/* Structure passed with SCO change command and events.
+ * Used by both Sync and Enhanced sync messaging
+ */
+typedef struct {
+ uint16_t max_latency_ms;
+ uint16_t packet_types;
+ uint8_t retransmission_effort;
+} tBTM_CHG_ESCO_PARAMS;
+
+/* Returned by BTM_ReadEScoLinkParms() */
+typedef struct {
+ uint16_t rx_pkt_len;
+ uint16_t tx_pkt_len;
+ BD_ADDR bd_addr;
+ uint8_t link_type; /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */
+ uint8_t tx_interval;
+ uint8_t retrans_window;
+ uint8_t air_mode;
+} tBTM_ESCO_DATA;
+
+typedef struct {
+ uint16_t sco_inx;
+ uint16_t rx_pkt_len;
+ uint16_t tx_pkt_len;
+ BD_ADDR bd_addr;
+ uint8_t hci_status;
+ uint8_t tx_interval;
+ uint8_t retrans_window;
+} tBTM_CHG_ESCO_EVT_DATA;
+
+typedef struct {
+ uint16_t sco_inx;
+ BD_ADDR bd_addr;
+ DEV_CLASS dev_class;
+ tBTM_SCO_TYPE link_type;
+} tBTM_ESCO_CONN_REQ_EVT_DATA;
+
+typedef union {
+ tBTM_CHG_ESCO_EVT_DATA chg_evt;
+ tBTM_ESCO_CONN_REQ_EVT_DATA conn_evt;
+} tBTM_ESCO_EVT_DATA;
+
+/***************************
+ * eSCO Callback Functions
+ ***************************/
+typedef void(tBTM_ESCO_CBACK)(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA* p_data);
+
+/*****************************************************************************
+ * SECURITY MANAGEMENT
+ ****************************************************************************/
+/*******************************
+ * Security Manager Constants
+ *******************************/
+
+/* Security Mode (BTM_SetSecurityMode) */
+#define BTM_SEC_MODE_UNDEFINED 0
+#define BTM_SEC_MODE_NONE 1
+#define BTM_SEC_MODE_SERVICE 2
+#define BTM_SEC_MODE_LINK 3
+#define BTM_SEC_MODE_SP 4
+#define BTM_SEC_MODE_SP_DEBUG 5
+#define BTM_SEC_MODE_SC 6
+
+/* Maximum Number of BTM Security Modes */
+#define BTM_SEC_MODES_MAX 7
+
+/* Security Service Levels [bit mask] (BTM_SetSecurityLevel)
+ * Encryption should not be used without authentication
+*/
+/* Nothing required */
+#define BTM_SEC_NONE 0x0000
+/* Inbound call requires authorization */
+#define BTM_SEC_IN_AUTHORIZE 0x0001
+/* Inbound call requires authentication */
+#define BTM_SEC_IN_AUTHENTICATE 0x0002
+/* Inbound call requires encryption */
+#define BTM_SEC_IN_ENCRYPT 0x0004
+/* Outbound call requires authorization */
+#define BTM_SEC_OUT_AUTHORIZE 0x0008
+/* Outbound call requires authentication */
+#define BTM_SEC_OUT_AUTHENTICATE 0x0010
+/* Outbound call requires encryption */
+#define BTM_SEC_OUT_ENCRYPT 0x0020
+/* Secure Connections Only Mode */
+#define BTM_SEC_MODE4_LEVEL4 0x0040
+/* Need to switch connection to be master */
+#define BTM_SEC_FORCE_MASTER 0x0100
+/* Try to switch connection to be master */
+#define BTM_SEC_ATTEMPT_MASTER 0x0200
+/* Need to switch connection to be master */
+#define BTM_SEC_FORCE_SLAVE 0x0400
+/* Try to switch connection to be slave */
+#define BTM_SEC_ATTEMPT_SLAVE 0x0800
+/* inbound Do man in the middle protection */
+#define BTM_SEC_IN_MITM 0x1000
+/* outbound Do man in the middle protection */
+#define BTM_SEC_OUT_MITM 0x2000
+/* enforce a minimum of 16 digit for sec mode 2 */
+#define BTM_SEC_IN_MIN_16_DIGIT_PIN 0x4000
+
+/* Security Flags [bit mask] (BTM_GetSecurityFlags)
+*/
+#define BTM_SEC_FLAG_AUTHORIZED 0x01
+#define BTM_SEC_FLAG_AUTHENTICATED 0x02
+#define BTM_SEC_FLAG_ENCRYPTED 0x04
+#define BTM_SEC_FLAG_LKEY_KNOWN 0x10
+#define BTM_SEC_FLAG_LKEY_AUTHED 0x20
+
+/* PIN types */
+#define BTM_PIN_TYPE_VARIABLE HCI_PIN_TYPE_VARIABLE
+#define BTM_PIN_TYPE_FIXED HCI_PIN_TYPE_FIXED
+
+/* Link Key types used to generate the new link key.
+ * returned in link key notification callback function
+*/
+#define BTM_LKEY_TYPE_COMBINATION HCI_LKEY_TYPE_COMBINATION
+#define BTM_LKEY_TYPE_LOCAL_UNIT HCI_LKEY_TYPE_LOCAL_UNIT
+#define BTM_LKEY_TYPE_REMOTE_UNIT HCI_LKEY_TYPE_REMOTE_UNIT
+#define BTM_LKEY_TYPE_DEBUG_COMB HCI_LKEY_TYPE_DEBUG_COMB
+#define BTM_LKEY_TYPE_UNAUTH_COMB HCI_LKEY_TYPE_UNAUTH_COMB
+#define BTM_LKEY_TYPE_AUTH_COMB HCI_LKEY_TYPE_AUTH_COMB
+#define BTM_LKEY_TYPE_CHANGED_COMB HCI_LKEY_TYPE_CHANGED_COMB
+
+#define BTM_LKEY_TYPE_UNAUTH_COMB_P_256 HCI_LKEY_TYPE_UNAUTH_COMB_P_256
+#define BTM_LKEY_TYPE_AUTH_COMB_P_256 HCI_LKEY_TYPE_AUTH_COMB_P_256
+
+/* "easy" requirements for LK derived from LTK */
+#define BTM_LTK_DERIVED_LKEY_OFFSET 0x20
+#define BTM_LKEY_TYPE_IGNORE \
+ 0xff /* used when event is response from \
+ hci return link keys request */
+
+typedef uint8_t tBTM_LINK_KEY_TYPE;
+
+/* Protocol level security (BTM_SetSecurityLevel) */
+#define BTM_SEC_PROTO_L2CAP 0
+#define BTM_SEC_PROTO_SDP 1
+#define BTM_SEC_PROTO_TCS 2
+#define BTM_SEC_PROTO_RFCOMM 3
+#define BTM_SEC_PROTO_OBEX 4
+#define BTM_SEC_PROTO_BNEP 5
+#define BTM_SEC_PROTO_HID 6 /* HID */
+#define BTM_SEC_PROTO_AVDT 7
+#define BTM_SEC_PROTO_MCA 8
+
+/* Determine the number of uint32_t's necessary for security services */
+#define BTM_SEC_ARRAY_BITS 32 /* Number of bits in each array element */
+#define BTM_SEC_SERVICE_ARRAY_SIZE \
+ (((uint32_t)BTM_SEC_MAX_SERVICES / BTM_SEC_ARRAY_BITS) + \
+ (((uint32_t)BTM_SEC_MAX_SERVICES % BTM_SEC_ARRAY_BITS) ? 1 : 0))
+
+/* Security service definitions (BTM_SetSecurityLevel)
+ * Used for Authorization APIs
+*/
+#define BTM_SEC_SERVICE_SDP_SERVER 0
+#define BTM_SEC_SERVICE_SERIAL_PORT 1
+#define BTM_SEC_SERVICE_LAN_ACCESS 2
+#define BTM_SEC_SERVICE_DUN 3
+#define BTM_SEC_SERVICE_IRMC_SYNC 4
+#define BTM_SEC_SERVICE_IRMC_SYNC_CMD 5
+#define BTM_SEC_SERVICE_OBEX 6
+#define BTM_SEC_SERVICE_OBEX_FTP 7
+#define BTM_SEC_SERVICE_HEADSET 8
+#define BTM_SEC_SERVICE_CORDLESS 9
+#define BTM_SEC_SERVICE_INTERCOM 10
+#define BTM_SEC_SERVICE_FAX 11
+#define BTM_SEC_SERVICE_HEADSET_AG 12
+#define BTM_SEC_SERVICE_PNP_INFO 13
+#define BTM_SEC_SERVICE_GEN_NET 14
+#define BTM_SEC_SERVICE_GEN_FILE 15
+#define BTM_SEC_SERVICE_GEN_AUDIO 16
+#define BTM_SEC_SERVICE_GEN_TEL 17
+#define BTM_SEC_SERVICE_CTP_DATA 18
+#define BTM_SEC_SERVICE_HCRP_CTRL 19
+#define BTM_SEC_SERVICE_HCRP_DATA 20
+#define BTM_SEC_SERVICE_HCRP_NOTIF 21
+#define BTM_SEC_SERVICE_BPP_JOB 22
+#define BTM_SEC_SERVICE_BPP_STATUS 23
+#define BTM_SEC_SERVICE_BPP_REF 24
+#define BTM_SEC_SERVICE_BNEP_PANU 25
+#define BTM_SEC_SERVICE_BNEP_GN 26
+#define BTM_SEC_SERVICE_BNEP_NAP 27
+#define BTM_SEC_SERVICE_HF_HANDSFREE 28
+#define BTM_SEC_SERVICE_AG_HANDSFREE 29
+#define BTM_SEC_SERVICE_TE_PHONE_ACCESS 30
+#define BTM_SEC_SERVICE_ME_PHONE_ACCESS 31
+
+#define BTM_SEC_SERVICE_HIDH_SEC_CTRL 32
+#define BTM_SEC_SERVICE_HIDH_NOSEC_CTRL 33
+#define BTM_SEC_SERVICE_HIDH_INTR 34
+#define BTM_SEC_SERVICE_BIP 35
+#define BTM_SEC_SERVICE_BIP_REF 36
+#define BTM_SEC_SERVICE_AVDTP 37
+#define BTM_SEC_SERVICE_AVDTP_NOSEC 38
+#define BTM_SEC_SERVICE_AVCTP 39
+#define BTM_SEC_SERVICE_SAP 40
+#define BTM_SEC_SERVICE_PBAP 41
+#define BTM_SEC_SERVICE_RFC_MUX 42
+#define BTM_SEC_SERVICE_AVCTP_BROWSE 43
+#define BTM_SEC_SERVICE_MAP 44
+#define BTM_SEC_SERVICE_MAP_NOTIF 45
+#define BTM_SEC_SERVICE_MCAP_CTRL 46
+#define BTM_SEC_SERVICE_MCAP_DATA 47
+#define BTM_SEC_SERVICE_HDP_SNK 48
+#define BTM_SEC_SERVICE_HDP_SRC 49
+#define BTM_SEC_SERVICE_ATT 50
+#define BTM_SEC_SERVICE_HIDD_SEC_CTRL 51
+#define BTM_SEC_SERVICE_HIDD_NOSEC_CTRL 52
+#define BTM_SEC_SERVICE_HIDD_INTR 53
+
+/* Update these as services are added */
+#define BTM_SEC_SERVICE_FIRST_EMPTY 54
+
+#ifndef BTM_SEC_MAX_SERVICES
+#define BTM_SEC_MAX_SERVICES 75
+#endif
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+/***************
+ * A2DP ROLE
+ ***************/
+#define BTM_ROLE_A2DP_SOURCE 1
+#define BTM_ROLE_A2DP_SINK 2
+#define BTM_CHECK_ROLE_SWITCH_TIMES 60
+#endif
+
+/*******************************************************************************
+ * Security Services MACROS handle array of uint32_t bits for more than 32
+ * trusted services
+ ******************************************************************************/
+/* MACRO to set the security service bit mask in a bit stream */
+#define BTM_SEC_SET_SERVICE(p, service) \
+ (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)] |= \
+ ((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))
+
+/* MACRO to clear the security service bit mask in a bit stream */
+#define BTM_SEC_CLR_SERVICE(p, service) \
+ (((uint32_t*)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)] &= \
+ ~((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))
+
+/* MACRO to check the security service bit mask in a bit stream (Returns true or
+ * false) */
+#define BTM_SEC_IS_SERVICE_TRUSTED(p, service) \
+ (((((uint32_t*)(p))[(((uint32_t)(service)) / BTM_SEC_ARRAY_BITS)]) & \
+ (uint32_t)(((uint32_t)1 << (((uint32_t)(service)) % BTM_SEC_ARRAY_BITS)))) \
+ ? true \
+ : false)
+
+/* MACRO to copy two trusted device bitmask */
+#define BTM_SEC_COPY_TRUSTED_DEVICE(p_src, p_dst) \
+ { \
+ uint32_t trst; \
+ for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+ ((uint32_t*)(p_dst))[trst] = ((uint32_t*)(p_src))[trst]; \
+ }
+
+/* MACRO to clear two trusted device bitmask */
+#define BTM_SEC_CLR_TRUSTED_DEVICE(p_dst) \
+ { \
+ uint32_t trst; \
+ for (trst = 0; trst < BTM_SEC_SERVICE_ARRAY_SIZE; trst++) \
+ ((uint32_t*)(p_dst))[trst] = 0; \
+ }
+
+/* Following bits can be provided by host in the trusted_mask array */
+/* 0..31 bits of mask[0] (Least Significant Word) */
+#define BTM_SEC_TRUST_SDP_SERVER (1 << BTM_SEC_SERVICE_SDP_SERVER)
+#define BTM_SEC_TRUST_SERIAL_PORT (1 << BTM_SEC_SERVICE_SERIAL_PORT)
+#define BTM_SEC_TRUST_LAN_ACCESS (1 << BTM_SEC_SERVICE_LAN_ACCESS)
+#define BTM_SEC_TRUST_DUN (1 << BTM_SEC_SERVICE_DUN)
+#define BTM_SEC_TRUST_IRMC_SYNC (1 << BTM_SEC_SERVICE_IRMC_SYNC)
+#define BTM_SEC_TRUST_IRMC_SYNC_CMD (1 << BTM_SEC_SERVICE_IRMC_SYNC_CMD)
+#define BTM_SEC_TRUST_OBEX (1 << BTM_SEC_SERVICE_OBEX)
+#define BTM_SEC_TRUST_OBEX_FTP (1 << BTM_SEC_SERVICE_OBEX_FTP)
+#define BTM_SEC_TRUST_HEADSET (1 << BTM_SEC_SERVICE_HEADSET)
+#define BTM_SEC_TRUST_CORDLESS (1 << BTM_SEC_SERVICE_CORDLESS)
+#define BTM_SEC_TRUST_INTERCOM (1 << BTM_SEC_SERVICE_INTERCOM)
+#define BTM_SEC_TRUST_FAX (1 << BTM_SEC_SERVICE_FAX)
+#define BTM_SEC_TRUST_HEADSET_AG (1 << BTM_SEC_SERVICE_HEADSET_AG)
+#define BTM_SEC_TRUST_PNP_INFO (1 << BTM_SEC_SERVICE_PNP_INFO)
+#define BTM_SEC_TRUST_GEN_NET (1 << BTM_SEC_SERVICE_GEN_NET)
+#define BTM_SEC_TRUST_GEN_FILE (1 << BTM_SEC_SERVICE_GEN_FILE)
+#define BTM_SEC_TRUST_GEN_AUDIO (1 << BTM_SEC_SERVICE_GEN_AUDIO)
+#define BTM_SEC_TRUST_GEN_TEL (1 << BTM_SEC_SERVICE_GEN_TEL)
+#define BTM_SEC_TRUST_CTP_DATA (1 << BTM_SEC_SERVICE_CTP_DATA)
+#define BTM_SEC_TRUST_HCRP_CTRL (1 << BTM_SEC_SERVICE_HCRP_CTRL)
+#define BTM_SEC_TRUST_HCRP_DATA (1 << BTM_SEC_SERVICE_HCRP_DATA)
+#define BTM_SEC_TRUST_HCRP_NOTIF (1 << BTM_SEC_SERVICE_HCRP_NOTIF)
+#define BTM_SEC_TRUST_BPP_JOB (1 << BTM_SEC_SERVICE_JOB)
+#define BTM_SEC_TRUST_BPP_STATUS (1 << BTM_SEC_SERVICE_STATUS)
+#define BTM_SEC_TRUST_BPP_REF (1 << BTM_SEC_SERVICE_REF)
+#define BTM_SEC_TRUST_BNEP_PANU (1 << BTM_SEC_SERVICE_BNEP_PANU)
+#define BTM_SEC_TRUST_BNEP_GN (1 << BTM_SEC_SERVICE_BNEP_GN)
+#define BTM_SEC_TRUST_BNEP_NAP (1 << BTM_SEC_SERVICE_BNEP_NAP)
+#define BTM_SEC_TRUST_HFP_HF (1 << BTM_SEC_SERVICE_HF_HANDSFREE)
+#define BTM_SEC_TRUST_HFP_AG (1 << BTM_SEC_SERVICE_AG_HANDSFREE)
+#define BTM_SEC_TRUST_TE_PHONE_ACCESS (1 << BTM_SEC_SERVICE_TE_PHONE_ACCESS)
+#define BTM_SEC_TRUST_ME_PHONE_ACCESS (1 << BTM_SEC_SERVICE_ME_PHONE_ACCESS)
+
+/* 0..31 bits of mask[1] (Most Significant Word) */
+#define BTM_SEC_TRUST_HIDH_CTRL (1 << (BTM_SEC_SERVICE_HIDH_SEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_NOSEC_CTRL \
+ (1 << (BTM_SEC_SERVICE_HIDH_NOSEC_CTRL - 32))
+#define BTM_SEC_TRUST_HIDH_INTR (1 << (BTM_SEC_SERVICE_HIDH_INTR - 32))
+#define BTM_SEC_TRUST_BIP (1 << (BTM_SEC_SERVICE_BIP - 32))
+#define BTM_SEC_TRUST_BIP_REF (1 << (BTM_SEC_SERVICE_BIP_REF - 32))
+#define BTM_SEC_TRUST_AVDTP (1 << (BTM_SEC_SERVICE_AVDTP - 32))
+#define BTM_SEC_TRUST_AVDTP_NOSEC (1 << (BTM_SEC_SERVICE_AVDTP_NOSEC - 32))
+#define BTM_SEC_TRUST_AVCTP (1 << (BTM_SEC_SERVICE_AVCTP - 32))
+#define BTM_SEC_TRUST_SAP (1 << (BTM_SEC_SERVICE_SAP - 32))
+#define BTM_SEC_TRUST_PBAP (1 << (BTM_SEC_SERVICE_PBAP - 32))
+#define BTM_SEC_TRUST_RFC_MUX (1 << (BTM_SEC_SERVICE_RFC_MUX - 32))
+#define BTM_SEC_TRUST_AVCTP_BROWSE (1 << (BTM_SEC_SERVICE_AVCTP_BROWSE - 32))
+#define BTM_SEC_TRUST_MAP (1 << (BTM_SEC_SERVICE_MAP - 32))
+#define BTM_SEC_TRUST_MAP_NOTIF (1 << (BTM_SEC_SERVICE_MAP_NOTIF - 32))
+#define BTM_SEC_TRUST_MCAP_CTRL (1 << (BTM_SEC_SERVICE_MCAP_CTRL - 32))
+#define BTM_SEC_TRUST_MCAP_DATA (1 << (BTM_SEC_SERVICE_MCAP_DATA - 32))
+#define BTM_SEC_TRUST_HDP_SNK (1 << (BTM_SEC_SERVICE_HDP_SNK - 32))
+#define BTM_SEC_TRUST_HDP_SRC (1 << (BTM_SEC_SERVICE_HDP_SRC - 32))
+
+#define BTM_SEC_TRUST_ALL 0xFFFFFFFF /* for each array element */
+
+/****************************************
+ * Security Manager Callback Functions
+ ****************************************/
+/* Authorize device for service. Parameters are
+ * BD Address of remote
+ * Device Class of remote
+ * BD Name of remote
+ * Service name
+ * Service Id (NULL - unknown service or unused
+ * [BTM_SEC_SERVICE_NAME_LEN set to 0])
+ * Is originator of the connection
+ * Result of the operation
+*/
+typedef uint8_t(tBTM_AUTHORIZE_CALLBACK)(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name,
+ uint8_t* service_name,
+ uint8_t service_id,
+ bool is_originator);
+
+/* Get PIN for the connection. Parameters are
+ * BD Address of remote
+ * Device Class of remote
+ * BD Name of remote
+ * Flag indicating the minimum pin code length to be 16 digits
+*/
+typedef uint8_t(tBTM_PIN_CALLBACK)(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, bool min_16_digit);
+
+/* New Link Key for the connection. Parameters are
+ * BD Address of remote
+ * Link Key
+ * Key Type: Combination, Local Unit, or Remote Unit
+*/
+typedef uint8_t(tBTM_LINK_KEY_CALLBACK)(BD_ADDR bd_addr, DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, uint8_t* key,
+ uint8_t key_type);
+
+/* Remote Name Resolved. Parameters are
+ * BD Address of remote
+ * BD Name of remote
+*/
+typedef void(tBTM_RMT_NAME_CALLBACK)(BD_ADDR bd_addr, DEV_CLASS dc,
+ tBTM_BD_NAME bd_name);
+
+/* Authentication complete for the connection. Parameters are
+ * BD Address of remote
+ * Device Class of remote
+ * BD Name of remote
+ *
+*/
+typedef uint8_t(tBTM_AUTH_COMPLETE_CALLBACK)(BD_ADDR bd_addr,
+ DEV_CLASS dev_class,
+ tBTM_BD_NAME bd_name, int result);
+
+enum {
+ BTM_SP_IO_REQ_EVT, /* received IO_CAPABILITY_REQUEST event */
+ BTM_SP_IO_RSP_EVT, /* received IO_CAPABILITY_RESPONSE event */
+ BTM_SP_CFM_REQ_EVT, /* received USER_CONFIRMATION_REQUEST event */
+ BTM_SP_KEY_NOTIF_EVT, /* received USER_PASSKEY_NOTIFY event */
+ BTM_SP_KEY_REQ_EVT, /* received USER_PASSKEY_REQUEST event */
+ BTM_SP_KEYPRESS_EVT, /* received KEYPRESS_NOTIFY event */
+ BTM_SP_LOC_OOB_EVT, /* received result for READ_LOCAL_OOB_DATA command */
+ BTM_SP_RMT_OOB_EVT, /* received REMOTE_OOB_DATA_REQUEST event */
+ BTM_SP_COMPLT_EVT, /* received SIMPLE_PAIRING_COMPLETE event */
+ BTM_SP_UPGRADE_EVT /* check if the application wants to upgrade the link key
+ */
+};
+typedef uint8_t tBTM_SP_EVT;
+
+#define BTM_IO_CAP_OUT 0 /* DisplayOnly */
+#define BTM_IO_CAP_IO 1 /* DisplayYesNo */
+#define BTM_IO_CAP_IN 2 /* KeyboardOnly */
+#define BTM_IO_CAP_NONE 3 /* NoInputNoOutput */
+#define BTM_IO_CAP_KBDISP 4 /* Keyboard display */
+#define BTM_IO_CAP_MAX 5
+#define BTM_IO_CAP_UNKNOWN 0xFF /* Unknown value */
+
+typedef uint8_t tBTM_IO_CAP;
+
+#define BTM_MAX_PASSKEY_VAL (999999)
+#define BTM_MIN_PASSKEY_VAL (0)
+
+/* MITM Protection Not Required - Single Profile/non-bonding Numeric comparison
+ * with automatic accept allowed */
+#define BTM_AUTH_SP_NO 0
+/* MITM Protection Required - Single Profile/non-bonding. Use IO Capabilities to
+ * determine authentication procedure */
+#define BTM_AUTH_SP_YES 1
+/* MITM Protection Not Required - All Profiles/dedicated bonding Numeric
+ * comparison with automatic accept allowed */
+#define BTM_AUTH_AP_NO 2
+/* MITM Protection Required - All Profiles/dedicated bonding Use IO Capabilities
+ * to determine authentication procedure */
+#define BTM_AUTH_AP_YES 3
+/* MITM Protection Not Required - Single Profiles/general bonding Numeric
+ * comparison with automatic accept allowed */
+#define BTM_AUTH_SPGB_NO 4
+/* MITM Protection Required - Single Profiles/general bonding Use IO
+ * Capabilities to determine authentication procedure */
+#define BTM_AUTH_SPGB_YES 5
+
+/* this bit is ORed with BTM_AUTH_SP_* when IO exchange for dedicated bonding */
+#define BTM_AUTH_DD_BOND 2
+#define BTM_AUTH_GB_BIT 4 /* the genernal bonding bit */
+#define BTM_AUTH_BONDS 6 /* the general/dedicated bonding bits */
+#define BTM_AUTH_YN_BIT 1 /* this is the Yes or No bit */
+
+#define BTM_BLE_INITIATOR_KEY_SIZE 15
+#define BTM_BLE_RESPONDER_KEY_SIZE 15
+#define BTM_BLE_MAX_KEY_SIZE 16
+
+typedef uint8_t tBTM_AUTH_REQ;
+
+enum { BTM_OOB_NONE, BTM_OOB_PRESENT, BTM_OOB_UNKNOWN };
+typedef uint8_t tBTM_OOB_DATA;
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_IO_CAP io_cap; /* local IO capabilities */
+ tBTM_OOB_DATA oob_data; /* OOB data present (locally) for the peer device */
+ tBTM_AUTH_REQ auth_req; /* Authentication required (for local device) */
+ bool is_orig; /* true, if local device initiated the SP process */
+} tBTM_SP_IO_REQ;
+
+/* data type for BTM_SP_IO_RSP_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_IO_CAP io_cap; /* peer IO capabilities */
+ tBTM_OOB_DATA
+ oob_data; /* OOB data present at peer device for the local device */
+ tBTM_AUTH_REQ auth_req; /* Authentication required for peer device */
+} tBTM_SP_IO_RSP;
+
+/* data type for BTM_SP_CFM_REQ_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ uint32_t num_val; /* the numeric value for comparison. If just_works, do not
+ show this number to UI */
+ bool just_works; /* true, if "Just Works" association model */
+ tBTM_AUTH_REQ loc_auth_req; /* Authentication required for local device */
+ tBTM_AUTH_REQ rmt_auth_req; /* Authentication required for peer device */
+ tBTM_IO_CAP loc_io_caps; /* IO Capabilities of the local device */
+ tBTM_IO_CAP rmt_io_caps; /* IO Capabilities of the remot device */
+} tBTM_SP_CFM_REQ;
+
+/* data type for BTM_SP_KEY_REQ_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+} tBTM_SP_KEY_REQ;
+
+/* data type for BTM_SP_KEY_NOTIF_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ uint32_t passkey; /* passkey */
+} tBTM_SP_KEY_NOTIF;
+
+enum {
+ BTM_SP_KEY_STARTED, /* 0 - passkey entry started */
+ BTM_SP_KEY_ENTERED, /* 1 - passkey digit entered */
+ BTM_SP_KEY_ERASED, /* 2 - passkey digit erased */
+ BTM_SP_KEY_CLEARED, /* 3 - passkey cleared */
+ BTM_SP_KEY_COMPLT, /* 4 - passkey entry completed */
+ BTM_SP_KEY_OUT_OF_RANGE /* 5 - out of range */
+};
+typedef uint8_t tBTM_SP_KEY_TYPE;
+
+/* data type for BTM_SP_KEYPRESS_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ tBTM_SP_KEY_TYPE notif_type;
+} tBTM_SP_KEYPRESS;
+
+/* data type for BTM_SP_LOC_OOB_EVT */
+typedef struct {
+ tBTM_STATUS status; /* */
+ BT_OCTET16 c; /* Simple Pairing Hash C */
+ BT_OCTET16 r; /* Simple Pairing Randomnizer R */
+} tBTM_SP_LOC_OOB;
+
+/* data type for BTM_SP_RMT_OOB_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+} tBTM_SP_RMT_OOB;
+
+/* data type for BTM_SP_COMPLT_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ DEV_CLASS dev_class; /* peer CoD */
+ tBTM_BD_NAME bd_name; /* peer device name */
+ tBTM_STATUS status; /* status of the simple pairing process */
+} tBTM_SP_COMPLT;
+
+/* data type for BTM_SP_UPGRADE_EVT */
+typedef struct {
+ BD_ADDR bd_addr; /* peer address */
+ bool upgrade; /* true, to upgrade the link key */
+} tBTM_SP_UPGRADE;
+
+typedef union {
+ tBTM_SP_IO_REQ io_req; /* BTM_SP_IO_REQ_EVT */
+ tBTM_SP_IO_RSP io_rsp; /* BTM_SP_IO_RSP_EVT */
+ tBTM_SP_CFM_REQ cfm_req; /* BTM_SP_CFM_REQ_EVT */
+ tBTM_SP_KEY_NOTIF key_notif; /* BTM_SP_KEY_NOTIF_EVT */
+ tBTM_SP_KEY_REQ key_req; /* BTM_SP_KEY_REQ_EVT */
+ tBTM_SP_KEYPRESS key_press; /* BTM_SP_KEYPRESS_EVT */
+ tBTM_SP_LOC_OOB loc_oob; /* BTM_SP_LOC_OOB_EVT */
+ tBTM_SP_RMT_OOB rmt_oob; /* BTM_SP_RMT_OOB_EVT */
+ tBTM_SP_COMPLT complt; /* BTM_SP_COMPLT_EVT */
+ tBTM_SP_UPGRADE upgrade; /* BTM_SP_UPGRADE_EVT */
+} tBTM_SP_EVT_DATA;
+
+/* Simple Pairing Events. Called by the stack when Simple Pairing related
+ * events occur.
+*/
+typedef uint8_t(tBTM_SP_CALLBACK)(tBTM_SP_EVT event, tBTM_SP_EVT_DATA* p_data);
+
+typedef void(tBTM_MKEY_CALLBACK)(BD_ADDR bd_addr, uint8_t status,
+ uint8_t key_flag);
+
+/* Encryption enabled/disabled complete: Optionally passed with
+ * BTM_SetEncryption.
+ * Parameters are
+ * BD Address of remote
+ * optional data passed in by BTM_SetEncryption
+ * tBTM_STATUS - result of the operation
+*/
+typedef void(tBTM_SEC_CBACK)(BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+ void* p_ref_data, tBTM_STATUS result);
+
+/* Bond Cancel complete. Parameters are
+ * Result of the cancel operation
+ *
+*/
+typedef void(tBTM_BOND_CANCEL_CMPL_CALLBACK)(tBTM_STATUS result);
+
+/* LE related event and data structure */
+/* received IO_CAPABILITY_REQUEST event */
+#define BTM_LE_IO_REQ_EVT SMP_IO_CAP_REQ_EVT
+/* security request event */
+#define BTM_LE_SEC_REQUEST_EVT SMP_SEC_REQUEST_EVT
+/* received USER_PASSKEY_NOTIFY event */
+#define BTM_LE_KEY_NOTIF_EVT SMP_PASSKEY_NOTIF_EVT
+/* received USER_PASSKEY_REQUEST event */
+#define BTM_LE_KEY_REQ_EVT SMP_PASSKEY_REQ_EVT
+/* OOB data request event */
+#define BTM_LE_OOB_REQ_EVT SMP_OOB_REQ_EVT
+/* Numeric Comparison request event */
+#define BTM_LE_NC_REQ_EVT SMP_NC_REQ_EVT
+/* Peer keypress notification recd event */
+#define BTM_LE_PR_KEYPR_NOT_EVT SMP_PEER_KEYPR_NOT_EVT
+/* SC OOB request event (both local and peer OOB data) can be expected in
+ * response */
+#define BTM_LE_SC_OOB_REQ_EVT SMP_SC_OOB_REQ_EVT
+/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
+#define BTM_LE_SC_LOC_OOB_EVT SMP_SC_LOC_OOB_DATA_UP_EVT
+/* SMP over BR keys request event */
+#define BTM_LE_BR_KEYS_REQ_EVT SMP_BR_KEYS_REQ_EVT
+/* SMP complete event */
+#define BTM_LE_COMPLT_EVT SMP_COMPLT_EVT
+#define BTM_LE_LAST_FROM_SMP BTM_LE_BR_KEYS_REQ_EVT
+/* KEY update event */
+#define BTM_LE_KEY_EVT (BTM_LE_LAST_FROM_SMP + 1)
+typedef uint8_t tBTM_LE_EVT;
+
+#define BTM_LE_KEY_NONE 0
+/* encryption information of peer device */
+#define BTM_LE_KEY_PENC SMP_SEC_KEY_TYPE_ENC
+/* identity key of the peer device */
+#define BTM_LE_KEY_PID SMP_SEC_KEY_TYPE_ID
+/* peer SRK */
+#define BTM_LE_KEY_PCSRK SMP_SEC_KEY_TYPE_CSRK
+#define BTM_LE_KEY_PLK SMP_SEC_KEY_TYPE_LK
+#define BTM_LE_KEY_LLK (SMP_SEC_KEY_TYPE_LK << 4)
+/* master role security information:div */
+#define BTM_LE_KEY_LENC (SMP_SEC_KEY_TYPE_ENC << 4)
+/* master device ID key */
+#define BTM_LE_KEY_LID (SMP_SEC_KEY_TYPE_ID << 4)
+/* local CSRK has been deliver to peer */
+#define BTM_LE_KEY_LCSRK (SMP_SEC_KEY_TYPE_CSRK << 4)
+typedef uint8_t tBTM_LE_KEY_TYPE;
+
+#define BTM_LE_AUTH_REQ_NO_BOND SMP_AUTH_NO_BOND /* 0 */
+#define BTM_LE_AUTH_REQ_BOND SMP_AUTH_GEN_BOND /* 1 << 0 */
+#define BTM_LE_AUTH_REQ_MITM SMP_AUTH_YN_BIT /* 1 << 2 */
+typedef uint8_t tBTM_LE_AUTH_REQ;
+#define BTM_LE_SC_SUPPORT_BIT SMP_SC_SUPPORT_BIT /* (1 << 3) */
+#define BTM_LE_KP_SUPPORT_BIT SMP_KP_SUPPORT_BIT /* (1 << 4) */
+#define BTM_LE_H7_SUPPORT_BIT SMP_H7_SUPPORT_BIT /* (1 << 5) */
+
+#define BTM_LE_AUTH_REQ_SC_ONLY SMP_AUTH_SC_ENC_ONLY /* 00101000 */
+#define BTM_LE_AUTH_REQ_SC_BOND SMP_AUTH_SC_GB /* 00101001 */
+#define BTM_LE_AUTH_REQ_SC_MITM SMP_AUTH_SC_MITM_NB /* 00101100 */
+#define BTM_LE_AUTH_REQ_SC_MITM_BOND SMP_AUTH_SC_MITM_GB /* 00101101 */
+#define BTM_LE_AUTH_REQ_MASK SMP_AUTH_MASK /* 0x3D */
+
+/* LE security level */
+#define BTM_LE_SEC_NONE SMP_SEC_NONE
+#define BTM_LE_SEC_UNAUTHENTICATE SMP_SEC_UNAUTHENTICATE /* 1 */
+#define BTM_LE_SEC_AUTHENTICATED SMP_SEC_AUTHENTICATED /* 4 */
+typedef uint8_t tBTM_LE_SEC;
+
+typedef struct {
+ /* local IO capabilities */
+ tBTM_IO_CAP io_cap;
+ /* OOB data present (locally) for the peer device */
+ uint8_t oob_data;
+ /* Authentication request (for local device) containing bonding and MITM
+ * info */
+ tBTM_LE_AUTH_REQ auth_req;
+ uint8_t max_key_size; /* max encryption key size */
+ tBTM_LE_KEY_TYPE init_keys; /* keys to be distributed, bit mask */
+ tBTM_LE_KEY_TYPE resp_keys; /* keys to be distributed, bit mask */
+} tBTM_LE_IO_REQ;
+
+/* data type for tBTM_LE_COMPLT */
+typedef struct {
+ uint8_t reason;
+ uint8_t sec_level;
+ bool is_pair_cancel;
+ bool smp_over_br;
+} tBTM_LE_COMPLT;
+
+/* BLE encryption keys */
+typedef struct {
+ BT_OCTET16 ltk;
+ BT_OCTET8 rand;
+ uint16_t ediv;
+ uint8_t sec_level;
+ uint8_t key_size;
+} tBTM_LE_PENC_KEYS;
+
+/* BLE CSRK keys */
+typedef struct {
+ uint32_t counter;
+ BT_OCTET16 csrk;
+ uint8_t sec_level;
+} tBTM_LE_PCSRK_KEYS;
+
+/* BLE Encryption reproduction keys */
+typedef struct {
+ BT_OCTET16 ltk;
+ uint16_t div;
+ uint8_t key_size;
+ uint8_t sec_level;
+} tBTM_LE_LENC_KEYS;
+
+/* BLE SRK keys */
+typedef struct {
+ uint32_t counter;
+ uint16_t div;
+ uint8_t sec_level;
+ BT_OCTET16 csrk;
+} tBTM_LE_LCSRK_KEYS;
+
+typedef struct {
+ BT_OCTET16 irk;
+ tBLE_ADDR_TYPE addr_type;
+ BD_ADDR static_addr;
+} tBTM_LE_PID_KEYS;
+
+typedef union {
+ tBTM_LE_PENC_KEYS penc_key; /* received peer encryption key */
+ tBTM_LE_PCSRK_KEYS pcsrk_key; /* received peer device SRK */
+ tBTM_LE_PID_KEYS pid_key; /* peer device ID key */
+ tBTM_LE_LENC_KEYS lenc_key; /* local encryption reproduction keys
+ * LTK = = d1(ER,DIV,0) */
+ tBTM_LE_LCSRK_KEYS lcsrk_key; /* local device CSRK = d1(ER,DIV,1)*/
+} tBTM_LE_KEY_VALUE;
+
+typedef struct {
+ tBTM_LE_KEY_TYPE key_type;
+ tBTM_LE_KEY_VALUE* p_key_value;
+} tBTM_LE_KEY;
+
+typedef union {
+ tBTM_LE_IO_REQ io_req; /* BTM_LE_IO_REQ_EVT */
+ uint32_t key_notif; /* BTM_LE_KEY_NOTIF_EVT */
+ /* BTM_LE_NC_REQ_EVT */
+ /* no callback data for
+ * BTM_LE_KEY_REQ_EVT
+ * and BTM_LE_OOB_REQ_EVT */
+ tBTM_LE_COMPLT complt; /* BTM_LE_COMPLT_EVT */
+ tSMP_OOB_DATA_TYPE req_oob_type;
+ tBTM_LE_KEY key;
+} tBTM_LE_EVT_DATA;
+
+/* Simple Pairing Events. Called by the stack when Simple Pairing related
+ * events occur.
+*/
+typedef uint8_t(tBTM_LE_CALLBACK)(tBTM_LE_EVT event, BD_ADDR bda,
+ tBTM_LE_EVT_DATA* p_data);
+
+#define BTM_BLE_KEY_TYPE_ID 1
+#define BTM_BLE_KEY_TYPE_ER 2
+#define BTM_BLE_KEY_TYPE_COUNTER 3 // tobe obsolete
+
+typedef struct {
+ BT_OCTET16 ir;
+ BT_OCTET16 irk;
+ BT_OCTET16 dhk;
+
+} tBTM_BLE_LOCAL_ID_KEYS;
+
+typedef union {
+ tBTM_BLE_LOCAL_ID_KEYS id_keys;
+ BT_OCTET16 er;
+} tBTM_BLE_LOCAL_KEYS;
+
+/* New LE identity key for local device.
+*/
+typedef void(tBTM_LE_KEY_CALLBACK)(uint8_t key_type,
+ tBTM_BLE_LOCAL_KEYS* p_key);
+
+/***************************
+ * Security Manager Types
+ ***************************/
+/* Structure that applications use to register with BTM_SecRegister */
+typedef struct {
+ tBTM_AUTHORIZE_CALLBACK* p_authorize_callback;
+ tBTM_PIN_CALLBACK* p_pin_callback;
+ tBTM_LINK_KEY_CALLBACK* p_link_key_callback;
+ tBTM_AUTH_COMPLETE_CALLBACK* p_auth_complete_callback;
+ tBTM_BOND_CANCEL_CMPL_CALLBACK* p_bond_cancel_cmpl_callback;
+ tBTM_SP_CALLBACK* p_sp_callback;
+ tBTM_LE_CALLBACK* p_le_callback;
+ tBTM_LE_KEY_CALLBACK* p_le_key_callback;
+} tBTM_APPL_INFO;
+
+/* Callback function for when a link supervision timeout event occurs.
+ * This asynchronous event is enabled/disabled by calling BTM_RegForLstoEvt().
+*/
+typedef void(tBTM_LSTO_CBACK)(BD_ADDR remote_bda, uint16_t timeout);
+
+/*****************************************************************************
+ * POWER MANAGEMENT
+ ****************************************************************************/
+/****************************
+ * Power Manager Constants
+ ****************************/
+/* BTM Power manager status codes */
+enum {
+ BTM_PM_STS_ACTIVE = HCI_MODE_ACTIVE,
+ BTM_PM_STS_HOLD = HCI_MODE_HOLD,
+ BTM_PM_STS_SNIFF = HCI_MODE_SNIFF,
+ BTM_PM_STS_PARK = HCI_MODE_PARK,
+ BTM_PM_STS_SSR, /* report the SSR parameters in HCI_SNIFF_SUB_RATE_EVT */
+ BTM_PM_STS_PENDING, /* when waiting for status from controller */
+ BTM_PM_STS_ERROR /* when HCI command status returns error */
+};
+typedef uint8_t tBTM_PM_STATUS;
+
+/* BTM Power manager modes */
+enum {
+ BTM_PM_MD_ACTIVE = BTM_PM_STS_ACTIVE,
+ BTM_PM_MD_HOLD = BTM_PM_STS_HOLD,
+ BTM_PM_MD_SNIFF = BTM_PM_STS_SNIFF,
+ BTM_PM_MD_PARK = BTM_PM_STS_PARK,
+ BTM_PM_MD_FORCE = 0x10 /* OR this to force ACL link to a certain mode */
+};
+typedef uint8_t tBTM_PM_MODE;
+
+#define BTM_PM_SET_ONLY_ID 0x80
+
+/* Operation codes */
+/* The module wants to set the desired power mode */
+#define BTM_PM_REG_SET 1
+/* The module wants to receive mode change event */
+#define BTM_PM_REG_NOTIF 2
+/* The module does not want to involve with PM anymore */
+#define BTM_PM_DEREG 4
+
+/************************
+ * Power Manager Types
+ ************************/
+typedef struct {
+ uint16_t max;
+ uint16_t min;
+ uint16_t attempt;
+ uint16_t timeout;
+ tBTM_PM_MODE mode;
+} tBTM_PM_PWR_MD;
+
+/*************************************
+ * Power Manager Callback Functions
+ *************************************/
+typedef void(tBTM_PM_STATUS_CBACK)(BD_ADDR p_bda, tBTM_PM_STATUS status,
+ uint16_t value, uint8_t hci_status);
+
+/************************
+ * Stored Linkkey Types
+ ************************/
+#define BTM_CB_EVT_DELETE_STORED_LINK_KEYS 4
+
+typedef struct {
+ uint8_t event;
+ uint8_t status;
+ uint16_t num_keys;
+
+} tBTM_DELETE_STORED_LINK_KEY_COMPLETE;
+
+/* MIP evnets, callbacks */
+enum {
+ BTM_MIP_MODE_CHG_EVT,
+ BTM_MIP_DISCONNECT_EVT,
+ BTM_MIP_PKTS_COMPL_EVT,
+ BTM_MIP_RXDATA_EVT
+};
+typedef uint8_t tBTM_MIP_EVT;
+
+typedef struct {
+ tBTM_MIP_EVT event;
+ BD_ADDR bd_addr;
+ uint16_t mip_id;
+} tBTM_MIP_MODE_CHANGE;
+
+typedef struct {
+ tBTM_MIP_EVT event;
+ uint16_t mip_id;
+ uint8_t disc_reason;
+} tBTM_MIP_CONN_TIMEOUT;
+
+#define BTM_MIP_MAX_RX_LEN 17
+
+typedef struct {
+ tBTM_MIP_EVT event;
+ uint16_t mip_id;
+ uint8_t rx_len;
+ uint8_t rx_data[BTM_MIP_MAX_RX_LEN];
+} tBTM_MIP_RXDATA;
+
+typedef struct {
+ tBTM_MIP_EVT event;
+ BD_ADDR bd_addr;
+ uint8_t data[11]; /* data[0] shows Vender-specific device type */
+} tBTM_MIP_EIR_HANDSHAKE;
+
+typedef struct {
+ tBTM_MIP_EVT event;
+ uint16_t num_sent; /* Completed packet count at the controller */
+} tBTM_MIP_PKTS_COMPL;
+
+typedef union {
+ tBTM_MIP_EVT event;
+ tBTM_MIP_MODE_CHANGE mod_chg;
+ tBTM_MIP_CONN_TIMEOUT conn_tmo;
+ tBTM_MIP_EIR_HANDSHAKE eir;
+ tBTM_MIP_PKTS_COMPL completed;
+ tBTM_MIP_RXDATA rxdata;
+} tBTM_MIP_EVENT_DATA;
+
+/* MIP event callback function */
+typedef void(tBTM_MIP_EVENTS_CB)(tBTM_MIP_EVT event, tBTM_MIP_EVENT_DATA data);
+
+/* MIP Device query callback function */
+typedef bool(tBTM_MIP_QUERY_CB)(BD_ADDR dev_addr, uint8_t* p_mode,
+ LINK_KEY link_key);
+
+/* ACL link on, SCO link ongoing, sniff mode */
+#define BTM_CONTRL_ACTIVE 1
+/* Scan state - paging/inquiry/trying to connect*/
+#define BTM_CONTRL_SCAN 2
+/* Idle state - page scan, LE advt, inquiry scan */
+#define BTM_CONTRL_IDLE 3
+
+typedef uint8_t tBTM_CONTRL_STATE;
+
+#endif // BTM_API_TYPES_H
diff --git a/mtkbt/code/bt/stack/include/btm_ble_api.h b/mtkbt/code/bt/stack/include/btm_ble_api.h
new file mode 100755
index 0000000..ee1ede6
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/btm_ble_api.h
@@ -0,0 +1,828 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the Bluetooth Manager (BTM) API function external
+ * definitions.
+ *
+ ******************************************************************************/
+#ifndef BTM_BLE_API_H
+#define BTM_BLE_API_H
+
+#include <base/callback_forward.h>
+#include <hardware/bt_common_types.h>
+#include <memory>
+#include "bt_common.h"
+#include "btm_api.h"
+#include "btm_ble_api_types.h"
+#include "osi/include/alarm.h"
+
+/*****************************************************************************
+ * EXTERNAL FUNCTION DECLARATIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * for a LE device stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * bd_name - Name of the peer device. NULL if unknown.
+ * dev_type - Remote device's device type.
+ * addr_type - LE device address type.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecAddBleDevice(const BD_ADDR bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type,
+ tBLE_ADDR_TYPE addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+*
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+extern bool BTM_SecAddBleKey(BD_ADDR bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
+ tBTM_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetAdvParams
+ *
+ * Description This function is called to set advertising parameters.
+ *
+ * Parameters: None.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_BleSetAdvParams(uint16_t adv_int_min,
+ uint16_t adv_int_max,
+ tBLE_BD_ADDR* p_dir_bda,
+ tBTM_BLE_ADV_CHNL_MAP chnl_map);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleObtainVendorCapabilities
+ *
+ * Description This function is called to obatin vendor capabilties
+ *
+ * Parameters p_cmn_vsc_cb - Returns the vednor capabilities
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleObtainVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+
+/**
+ * This function is called to set scan parameters. |cb| is called with operation
+ * status
+ **/
+extern void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window,
+ tBLE_SCAN_MODE scan_type,
+ base::Callback<void(uint8_t)> cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetVendorCapabilities
+ *
+ * Description This function reads local LE features
+ *
+ * Parameters p_cmn_vsc_cb : Locala LE capability structure
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+/*******************************************************************************
+ *
+ * Function BTM_BleSetStorageConfig
+ *
+ * Description This function is called to setup storage configuration and
+ * setup callbacks.
+ *
+ * Parameters uint8_t batch_scan_full_max -Batch scan full maximum
+ uint8_t batch_scan_trunc_max - Batch scan truncated value
+ maximum
+ uint8_t batch_scan_notify_threshold - Threshold value
+ cb - Setup callback
+ tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback -Threshold
+ callback
+ void *p_ref - Reference value
+ *
+ *
+ ******************************************************************************/
+extern void BTM_BleSetStorageConfig(
+ uint8_t batch_scan_full_max, uint8_t batch_scan_trunc_max,
+ uint8_t batch_scan_notify_threshold,
+ base::Callback<void(uint8_t /* status */)> cb,
+ tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback, tBTM_BLE_REF_VALUE ref_value);
+
+/* This function is called to enable batch scan */
+extern void BTM_BleEnableBatchScan(
+ tBTM_BLE_BATCH_SCAN_MODE scan_mode, uint32_t scan_interval,
+ uint32_t scan_window, tBTM_BLE_DISCARD_RULE discard_rule,
+ tBLE_ADDR_TYPE addr_type, base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to disable batch scanning */
+extern void BTM_BleDisableBatchScan(
+ base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to read batch scan reports */
+extern void BTM_BleReadScanReports(tBLE_SCAN_MODE scan_mode,
+ tBTM_BLE_SCAN_REP_CBACK cb);
+
+/* This function is called to setup the callback for tracking */
+extern void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback,
+ tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleWriteScanRsp
+ *
+ * Description This function is called to write LE scan response.
+ *
+ * Parameters: p_scan_rsp: scan response.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+extern void BTM_BleWriteScanRsp(uint8_t* data, uint8_t length,
+ tBTM_BLE_ADV_DATA_CMPL_CBACK* p_adv_data_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleObserve
+ *
+ * Description This procedure keep the device listening for advertising
+ * events from a broadcast device.
+ *
+ * Parameters start: start or stop observe.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceIDRoot
+ *
+ * Description This function is called to read the local device identity
+ * root.
+ *
+ * Returns void
+ * the local device ER is copied into er
+ *
+ ******************************************************************************/
+extern void BTM_GetDeviceIDRoot(BT_OCTET16 ir);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceEncRoot
+ *
+ * Description This function is called to read the local device encryption
+ * root.
+ *
+ * Returns void
+ * the local device ER is copied into er
+ *
+ ******************************************************************************/
+extern void BTM_GetDeviceEncRoot(BT_OCTET16 er);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetDeviceDHK
+ *
+ * Description This function is called to read the local device DHK.
+ *
+ * Returns void
+ * the local device DHK is copied into dhk
+ *
+ ******************************************************************************/
+extern void BTM_GetDeviceDHK(BT_OCTET16 dhk);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation BTM_SUCCESS if success.
+ * Otherwise, BTM_REPEATED_ATTEMPTS is too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void BTM_SecurityGrant(BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function BTM_BlePasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which passkey was
+ * requested
+ * res - result of the operation SMP_SUCCESS if success
+ * passkey - numeric value in the range of
+ * BTM_MIN_PASSKEY_VAL(0) -
+ * BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+extern void BTM_BlePasskeyReply(BD_ADDR bd_addr, uint8_t res, uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+extern void BTM_BleConfirmReply(BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function BTM_LeOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+extern void BTM_BleOobDataReply(BD_ADDR bd_addr, uint8_t res, uint8_t len,
+ uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ * data is available
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * p_c - pointer to Confirmation
+ * p_r - pointer to Randomizer.
+ *
+ ******************************************************************************/
+extern void BTM_BleSecureConnectionOobDataReply(BD_ADDR bd_addr, uint8_t* p_c,
+ uint8_t* p_r);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleDataSignature
+ *
+ * Description This function is called to sign the data using AES128 CMAC
+ * algorith.
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_text: singing data
+ * len: length of the signing data
+ * signature: output parameter where data signature is going to
+ * be stored.
+ *
+ * Returns true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+extern bool BTM_BleDataSignature(BD_ADDR bd_addr, uint8_t* p_text, uint16_t len,
+ BLE_SIGNATURE signature);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleVerifySignature
+ *
+ * Description This function is called to verify the data signature
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_orig: original data before signature.
+ * len: length of the signing data
+ * counter: counter used when doing data signing
+ * p_comp: signature to be compared against.
+
+ * Returns true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+extern bool BTM_BleVerifySignature(BD_ADDR bd_addr, uint8_t* p_orig,
+ uint16_t len, uint32_t counter,
+ uint8_t* p_comp);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectionAddr
+ *
+ * Description Read the local device random address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_ReadConnectionAddr(BD_ADDR remote_bda, BD_ADDR local_conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteConnectionAddr
+ *
+ * Description Read the remote device address currently used.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern bool BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLoadLocalKeys
+ *
+ * Description Local local identity key, encryption root or sign counter.
+ *
+ * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ * BTM_BLE_KEY_TYPE_ER
+ * or BTM_BLE_KEY_TYPE_COUNTER.
+ * p_key: pointer to the key.
+*
+ * Returns non2.
+ *
+ ******************************************************************************/
+extern void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key);
+
+/**
+ * Set BLE connectable mode to auto connect
+ */
+extern void BTM_BleStartAutoConn();
+
+/*******************************************************************************
+ *
+ * Function BTM_BleUpdateBgConnDev
+ *
+ * Description This function is called to add or remove a device into/from
+ * background connection procedure. The background connection
+* procedure is decided by the background connection type, it
+*can be
+* auto connection, or selective connection.
+ *
+ * Parameters add_remove: true to add; false to remove.
+ * remote_bda: device address to add/remove.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern bool BTM_BleUpdateBgConnDev(bool add_remove, BD_ADDR remote_bda);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleClearBgConnDev
+ *
+ * Description This function is called to clear the whitelist,
+ * end any pending whitelist connections,
+ * and reset the local bg device list.
+ *
+ * Parameters void
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleClearBgConnDev(void);
+
+/********************************************************
+ *
+ * Function BTM_BleSetPrefConnParams
+ *
+ * Description Set a peripheral's preferred connection parameters. When
+ * any of the value does not want to be updated while others
+ * do, use BTM_BLE_CONN_PARAM_UNDEF for the ones want to
+ * leave untouched.
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleSetPrefConnParams(BD_ADDR bd_addr, uint16_t min_conn_int,
+ uint16_t max_conn_int,
+ uint16_t slave_latency,
+ uint16_t supervision_tout);
+
+/******************************************************************************
+ *
+ * Function BTM_BleSetConnScanParams
+ *
+ * Description Set scan parameters used in BLE connection request
+ *
+ * Parameters: scan_interval - scan interval
+ * scan_window - scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleSetConnScanParams(uint32_t scan_interval,
+ uint32_t scan_window);
+
+/******************************************************************************
+ *
+ * Function BTM_BleReadControllerFeatures
+ *
+ * Description Reads BLE specific controller features
+ *
+ * Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when
+ * features are read
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleReadControllerFeatures(
+ tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadDiscoverability
+ *
+ * Description This function is called to read the current LE
+ * discoverability mode of the device.
+ *
+ * Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or
+ * BTM_BLE_GENRAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadDiscoverability();
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadConnectability
+ *
+ * Description This function is called to read the current LE
+ * connectibility mode of the device.
+ *
+ * Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE
+ *
+ ******************************************************************************/
+extern uint16_t BTM_BleReadConnectability();
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDevInfo
+ *
+ * Description This function is called to read the device/address type
+ * of BD address.
+ *
+ * Parameter remote_bda: remote device address
+ * p_dev_type: output parameter to read the device type.
+ * p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+extern void BTM_ReadDevInfo(const BD_ADDR remote_bda,
+ tBT_DEVICE_TYPE* p_dev_type,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectedTransportAddress
+ *
+ * Description This function is called to read the paired device/address
+ * type of other device paired corresponding to the BD_address
+ *
+ * Parameter remote_bda: remote device address, carry out the transport
+ * address
+ * transport: active transport
+ *
+ * Return true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+extern bool BTM_ReadConnectedTransportAddress(BD_ADDR remote_bda,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfigPrivacy
+ *
+ * Description This function is called to enable or disable the privacy in
+ * the local device.
+ *
+ * Parameters enable: true to enable it; false to disable it.
+ *
+ * Returns bool privacy mode set success; otherwise failed.
+ *
+ ******************************************************************************/
+extern bool BTM_BleConfigPrivacy(bool enable);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLocalPrivacyEnabled
+ *
+ * Description Checks if local device supports private address
+ *
+ * Returns Return true if local privacy is enabled else false
+ *
+ ******************************************************************************/
+extern bool BTM_BleLocalPrivacyEnabled(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableMixedPrivacyMode
+ *
+ * Description This function is called to enabled Mixed mode if privacy 1.2
+ * is applicable in controller.
+ *
+ * Parameters mixed_on: mixed mode to be used or not.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleEnableMixedPrivacyMode(bool mixed_on);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleMaxMultiAdvInstanceCount
+ *
+ * Description Returns the maximum number of multi adv instances supported
+ * by the controller.
+ *
+ * Returns Max multi adv instance count
+ *
+ ******************************************************************************/
+extern uint8_t BTM_BleMaxMultiAdvInstanceCount();
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetConnectableMode
+ *
+ * Description This function is called to set BLE connectable mode for a
+ * peripheral device.
+ *
+ * Parameters connectable_mode: directed connectable mode, or
+ * non-directed. It can be
+ * BTM_BLE_CONNECT_EVT,
+ * BTM_BLE_CONNECT_DIR_EVT or
+ * BTM_BLE_CONNECT_LO_DUTY_DIR_EVT
+ *
+ * Returns BTM_ILLEGAL_VALUE if controller does not support BLE.
+ * BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_BleSetConnectableMode(
+ tBTM_BLE_CONN_MODE connectable_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTurnOnPrivacyOnRemote
+ *
+ * Description This function is called to enable or disable the privacy on
+ * the remote device.
+ *
+ * Parameters bd_addr: remote device address.
+ * privacy_on: true to enable it; false to disable it.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void BTM_BleTurnOnPrivacyOnRemote(BD_ADDR bd_addr, bool privacy_on);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleUpdateAdvFilterPolicy
+ *
+ * Description This function update the filter policy of advertiser.
+ *
+ * Parameter adv_policy: advertising filter policy
+ *
+ * Return void
+ ******************************************************************************/
+extern void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReceiverTest
+ *
+ * Description This function is called to start the LE Receiver test
+ *
+ * Parameter rx_freq - Frequency Range
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTransmitterTest
+ *
+ * Description This function is called to start the LE Transmitter test
+ *
+ * Parameter tx_freq - Frequency Range
+ * test_data_len - Length in bytes of payload data in each
+ * packet
+ * packet_payload - Pattern to use in the payload
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
+ uint8_t packet_payload,
+ tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTestEnd
+ *
+ * Description This function is called to stop the in-progress TX or RX test
+ *
+ * Parameter p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_UseLeLink
+ *
+ * Description Select the underlying physical link to use.
+ *
+ * Returns true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+extern bool BTM_UseLeLink(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleStackEnable
+ *
+ * Description Enable/Disable BLE functionality on stack regardless of
+ * controller capability.
+ *
+ * Parameters: enable: true to enable, false to disable.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_BleStackEnable(bool enable);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetLeSecurityState
+ *
+ * Description This function is called to get security mode 1 flags and
+ * encryption key size for LE peer.
+ *
+ * Returns bool true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+extern bool BTM_GetLeSecurityState(BD_ADDR bd_addr, uint8_t* p_le_dev_sec_flags,
+ uint8_t* p_le_key_size);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecurityProcedureIsRunning
+ *
+ * Description This function indicates if LE security procedure is
+ * currently running with the peer.
+ *
+ * Returns bool true if security procedure is running, false otherwise.
+ *
+ ******************************************************************************/
+extern bool BTM_BleSecurityProcedureIsRunning(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetSupportedKeySize
+ *
+ * Description This function gets the maximum encryption key size in bytes
+ * the local device can suport.
+ * record.
+ *
+ * Returns the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+extern uint8_t BTM_BleGetSupportedKeySize(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleAdvFilterParamSetup
+ *
+ * Description This function is called to setup the adv data payload filter
+ * condition.
+ *
+ ******************************************************************************/
+extern void BTM_BleAdvFilterParamSetup(
+ int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+ tBTM_BLE_PF_PARAM_CB cb);
+
+/**
+ * This functions are called to configure the adv data payload filter condition
+ */
+extern void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index);
+extern void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBLE_BD_ADDR addr, tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> name,
+ tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_TYPE filter_type,
+ tBT_UUID uuid,
+ tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+ tBTM_BLE_PF_COND_MASK* p_uuid_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ uint16_t company_id, uint16_t company_id_mask,
+ std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+extern void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableDisableFilterFeature
+ *
+ * Description Enable or disable the APCF feature
+ *
+ * Parameters enable - true - enables APCF, false - disables APCF
+ *
+ ******************************************************************************/
+extern void BTM_BleEnableDisableFilterFeature(
+ uint8_t enable, tBTM_BLE_PF_STATUS_CBACK p_stat_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetEnergyInfo
+ *
+ * Description This function obtains the energy info
+ *
+ * Parameters p_ener_cback - Callback pointer
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_BleGetEnergyInfo(
+ tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetBleDataLength
+ *
+ * Description Set the maximum BLE transmission packet size
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+extern tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr,
+ uint16_t tx_pdu_length);
+
+extern void btm_ble_multi_adv_cleanup(void);
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/btm_ble_api_types.h b/mtkbt/code/bt/stack/include/btm_ble_api_types.h
new file mode 100755
index 0000000..0ae3e52
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/btm_ble_api_types.h
@@ -0,0 +1,560 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BTM_BLE_API_TYPES_H
+#define BTM_BLE_API_TYPES_H
+
+#include <base/callback_forward.h>
+#include <hardware/bt_common_types.h>
+#include <vector>
+
+#define CHNL_MAP_LEN 5
+typedef uint8_t tBTM_BLE_CHNL_MAP[CHNL_MAP_LEN];
+
+/* 0x00-0x04 only used for set advertising parameter command */
+#define BTM_BLE_CONNECT_EVT 0x00
+/* Connectable directed advertising */
+#define BTM_BLE_CONNECT_DIR_EVT 0x01
+/* Scannable undirected advertising */
+#define BTM_BLE_DISCOVER_EVT 0x02
+/* Non connectable undirected advertising */
+#define BTM_BLE_NON_CONNECT_EVT 0x03
+/* Connectable low duty cycle directed advertising */
+#define BTM_BLE_CONNECT_LO_DUTY_DIR_EVT 0x04
+/* 0x00 - 0x05 can be received on adv event type */
+#define BTM_BLE_SCAN_RSP_EVT 0x04
+#define BTM_BLE_SCAN_REQ_EVT 0x05
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+#define BTM_BLE_UNKNOWN_EVT 0xff
+
+typedef uint8_t tBTM_BLE_EVT;
+typedef uint8_t tBTM_BLE_CONN_MODE;
+
+typedef uint32_t tBTM_BLE_REF_VALUE;
+
+#define BTM_BLE_SCAN_MODE_PASS 0
+#define BTM_BLE_SCAN_MODE_ACTI 1
+#define BTM_BLE_SCAN_MODE_NONE 0xff
+typedef uint8_t tBLE_SCAN_MODE;
+
+#define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0
+#define BTM_BLE_BATCH_SCAN_MODE_PASS 1
+#define BTM_BLE_BATCH_SCAN_MODE_ACTI 2
+#define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3
+
+typedef uint8_t tBTM_BLE_BATCH_SCAN_MODE;
+
+/* advertising channel map */
+#define BTM_BLE_ADV_CHNL_37 (0x01 << 0)
+#define BTM_BLE_ADV_CHNL_38 (0x01 << 1)
+#define BTM_BLE_ADV_CHNL_39 (0x01 << 2)
+typedef uint8_t tBTM_BLE_ADV_CHNL_MAP;
+
+/*d efault advertising channel map */
+#ifndef BTM_BLE_DEFAULT_ADV_CHNL_MAP
+#define BTM_BLE_DEFAULT_ADV_CHNL_MAP \
+ (BTM_BLE_ADV_CHNL_37 | BTM_BLE_ADV_CHNL_38 | BTM_BLE_ADV_CHNL_39)
+#endif
+
+/* advertising filter policy */
+#define AP_SCAN_CONN_ALL 0x00 /* default */
+#define AP_SCAN_WL_CONN_ALL 0x01
+#define AP_SCAN_ALL_CONN_WL 0x02
+#define AP_SCAN_CONN_WL 0x03
+#define AP_SCAN_CONN_POLICY_MAX 0x04
+typedef uint8_t tBTM_BLE_AFP;
+
+/* default advertising filter policy */
+#ifndef BTM_BLE_DEFAULT_AFP
+#define BTM_BLE_DEFAULT_AFP AP_SCAN_CONN_ALL
+#endif
+
+/* scanning filter policy */
+/* 0: accept adv packet from all, directed adv pkt not directed */
+/* to local device is ignored */
+#define SP_ADV_ALL 0x00
+/* 1: accept adv packet from device in white list, directed adv */
+/* packet not directed to local device is ignored */
+#define SP_ADV_WL 0x01
+/* 2: accept adv packet from all, directed adv pkt */
+/* not directed to me is ignored except direct adv with RPA */
+#define SP_ADV_ALL_RPA_DIR_ADV 0x02
+/* 3: accept adv packet from device in white list, directed */
+/* adv pkt not directed to me is ignored except direct adv with RPA */
+#define SP_ADV_WL_RPA_DIR_ADV 0x03
+
+typedef uint8_t tBTM_BLE_SFP;
+
+#ifndef BTM_BLE_DEFAULT_SFP
+#define BTM_BLE_DEFAULT_SFP SP_ADV_ALL
+#endif
+
+/* adv parameter boundary values */
+#define BTM_BLE_ADV_INT_MIN 0x0020
+#define BTM_BLE_ADV_INT_MAX 0x4000
+
+/* Full scan boundary values */
+#define BTM_BLE_ADV_SCAN_FULL_MIN 0x00
+#define BTM_BLE_ADV_SCAN_FULL_MAX 0x64
+
+/* Partial scan boundary values */
+#define BTM_BLE_ADV_SCAN_TRUNC_MIN BTM_BLE_ADV_SCAN_FULL_MIN
+#define BTM_BLE_ADV_SCAN_TRUNC_MAX BTM_BLE_ADV_SCAN_FULL_MAX
+
+/* Threshold values */
+#define BTM_BLE_ADV_SCAN_THR_MIN BTM_BLE_ADV_SCAN_FULL_MIN
+#define BTM_BLE_ADV_SCAN_THR_MAX BTM_BLE_ADV_SCAN_FULL_MAX
+
+/* connection parameter boundary values */
+#define BTM_BLE_SCAN_INT_MIN 0x0004
+#define BTM_BLE_SCAN_INT_MAX 0x4000
+#define BTM_BLE_SCAN_WIN_MIN 0x0004
+#define BTM_BLE_SCAN_WIN_MAX 0x4000
+#define BTM_BLE_EXT_SCAN_INT_MAX 0x00FFFFFF
+#define BTM_BLE_EXT_SCAN_WIN_MAX 0xFFFF
+#define BTM_BLE_CONN_INT_MIN 0x0006
+#define BTM_BLE_CONN_INT_MAX 0x0C80
+#define BTM_BLE_CONN_LATENCY_MAX 500
+#define BTM_BLE_CONN_SUP_TOUT_MIN 0x000A
+#define BTM_BLE_CONN_SUP_TOUT_MAX 0x0C80
+/* use this value when a specific value not to be overwritten */
+#define BTM_BLE_CONN_PARAM_UNDEF 0xffff
+#define BTM_BLE_SCAN_PARAM_UNDEF 0xffffffff
+
+/* default connection parameters if not configured, use GAP recommended value
+ * for auto/selective connection */
+/* default scan interval */
+#ifndef BTM_BLE_SCAN_FAST_INT
+#define BTM_BLE_SCAN_FAST_INT 96 /* 30 ~ 60 ms (use 60) = 96 *0.625 */
+#endif
+/* default scan window for background connection, applicable for auto connection
+ * or selective connection */
+#ifndef BTM_BLE_SCAN_FAST_WIN
+#define BTM_BLE_SCAN_FAST_WIN 48 /* 30 ms = 48 *0.625 */
+#endif
+
+/* default scan paramter used in reduced power cycle (background scanning) */
+#ifndef BTM_BLE_SCAN_SLOW_INT_1
+#define BTM_BLE_SCAN_SLOW_INT_1 2048 /* 1.28 s = 2048 *0.625 */
+#endif
+#ifndef BTM_BLE_SCAN_SLOW_WIN_1
+#define BTM_BLE_SCAN_SLOW_WIN_1 48 /* 30 ms = 48 *0.625 */
+#endif
+
+/* default scan paramter used in reduced power cycle (background scanning) */
+#ifndef BTM_BLE_SCAN_SLOW_INT_2
+#define BTM_BLE_SCAN_SLOW_INT_2 4096 /* 2.56 s = 4096 *0.625 */
+#endif
+#ifndef BTM_BLE_SCAN_SLOW_WIN_2
+#define BTM_BLE_SCAN_SLOW_WIN_2 36 /* 22.5 ms = 36 *0.625 */
+#endif
+
+/* default connection interval min */
+#ifndef BTM_BLE_CONN_INT_MIN_DEF
+/* recommended min: 30ms = 24 * 1.25 */
+#define BTM_BLE_CONN_INT_MIN_DEF 24
+#endif
+
+/* default connectino interval max */
+#ifndef BTM_BLE_CONN_INT_MAX_DEF
+/* recommended max: 50 ms = 56 * 1.25 */
+#define BTM_BLE_CONN_INT_MAX_DEF 40
+#endif
+
+/* default slave latency */
+#ifndef BTM_BLE_CONN_SLAVE_LATENCY_DEF
+#define BTM_BLE_CONN_SLAVE_LATENCY_DEF 0 /* 0 */
+#endif
+
+/* default supervision timeout */
+#ifndef BTM_BLE_CONN_TIMEOUT_DEF
+#define BTM_BLE_CONN_TIMEOUT_DEF 500
+#endif
+
+/* minimum supervision timeout */
+#ifndef BTM_BLE_CONN_TIMEOUT_MIN_DEF
+#define BTM_BLE_CONN_TIMEOUT_MIN_DEF 100
+#endif
+
+/* minimum acceptable connection interval */
+#ifndef BTM_BLE_CONN_INT_MIN_LIMIT
+#define BTM_BLE_CONN_INT_MIN_LIMIT 0x0009
+#endif
+
+#define BTM_BLE_DIR_CONN_FALLBACK_UNDIR 1
+#define BTM_BLE_DIR_CONN_FALLBACK_NO_ADV 2
+
+#ifndef BTM_BLE_DIR_CONN_FALLBACK
+#define BTM_BLE_DIR_CONN_FALLBACK BTM_BLE_DIR_CONN_FALLBACK_UNDIR
+#endif
+
+#define BTM_CMAC_TLEN_SIZE 8 /* 64 bits */
+#define BTM_BLE_AUTH_SIGN_LEN \
+ 12 /* BLE data signature length 8 Bytes + 4 bytes counter*/
+typedef uint8_t BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */
+
+#ifndef BTM_BLE_HOST_SUPPORT
+#define BTM_BLE_HOST_SUPPORT 0x01
+#endif
+
+#ifndef BTM_BLE_SIMULTANEOUS_HOST
+#define BTM_BLE_SIMULTANEOUS_HOST 0x01
+#endif
+
+/* Appearance Values Reported with BTM_BLE_AD_TYPE_APPEARANCE */
+#define BTM_BLE_APPEARANCE_UKNOWN 0x0000
+#define BTM_BLE_APPEARANCE_GENERIC_PHONE 0x0040
+#define BTM_BLE_APPEARANCE_GENERIC_COMPUTER 0x0080
+#define BTM_BLE_APPEARANCE_GENERIC_WATCH 0x00C0
+#define BTM_BLE_APPEARANCE_SPORTS_WATCH 0x00C1
+#define BTM_BLE_APPEARANCE_GENERIC_CLOCK 0x0100
+#define BTM_BLE_APPEARANCE_GENERIC_DISPLAY 0x0140
+#define BTM_BLE_APPEARANCE_GENERIC_REMOTE 0x0180
+#define BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES 0x01C0
+#define BTM_BLE_APPEARANCE_GENERIC_TAG 0x0200
+#define BTM_BLE_APPEARANCE_GENERIC_KEYRING 0x0240
+#define BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280
+#define BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0
+#define BTM_BLE_APPEARANCE_GENERIC_THERMOMETER 0x0300
+#define BTM_BLE_APPEARANCE_THERMOMETER_EAR 0x0301
+#define BTM_BLE_APPEARANCE_GENERIC_HEART_RATE 0x0340
+#define BTM_BLE_APPEARANCE_HEART_RATE_BELT 0x0341
+#define BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382
+#define BTM_BLE_APPEARANCE_GENERIC_HID 0x03C0
+#define BTM_BLE_APPEARANCE_HID_KEYBOARD 0x03C1
+#define BTM_BLE_APPEARANCE_HID_MOUSE 0x03C2
+#define BTM_BLE_APPEARANCE_HID_JOYSTICK 0x03C3
+#define BTM_BLE_APPEARANCE_HID_GAMEPAD 0x03C4
+#define BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5
+#define BTM_BLE_APPEARANCE_HID_CARD_READER 0x03C6
+#define BTM_BLE_APPEARANCE_HID_DIGITAL_PEN 0x03C7
+#define BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER 0x03C8
+#define BTM_BLE_APPEARANCE_GENERIC_GLUCOSE 0x0400
+#define BTM_BLE_APPEARANCE_GENERIC_WALKING 0x0440
+#define BTM_BLE_APPEARANCE_WALKING_IN_SHOE 0x0441
+#define BTM_BLE_APPEARANCE_WALKING_ON_SHOE 0x0442
+#define BTM_BLE_APPEARANCE_WALKING_ON_HIP 0x0443
+#define BTM_BLE_APPEARANCE_GENERIC_CYCLING 0x0480
+#define BTM_BLE_APPEARANCE_CYCLING_COMPUTER 0x0481
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED 0x0482
+#define BTM_BLE_APPEARANCE_CYCLING_CADENCE 0x0483
+#define BTM_BLE_APPEARANCE_CYCLING_POWER 0x0484
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485
+#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42
+#define BTM_BLE_APPEARANCE_GENERIC_WEIGHT 0x0C80
+#define BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444
+
+/* Structure returned with Rand/Encrypt complete callback */
+typedef struct {
+ uint8_t status;
+ uint8_t param_len;
+ uint16_t opcode;
+ uint8_t param_buf[BT_OCTET16_LEN];
+} tBTM_RAND_ENC;
+
+/* General callback function for notifying an application that a synchronous
+ * BTM function is complete. The pointer contains the address of any returned
+ * data.
+*/
+typedef void(tBTM_RAND_ENC_CB)(tBTM_RAND_ENC* p1);
+
+#define BTM_BLE_FILTER_TARGET_SCANNER 0x01
+#define BTM_BLE_FILTER_TARGET_ADVR 0x00
+
+#define BTM_BLE_POLICY_BLACK_ALL 0x00 /* relevant to both */
+#define BTM_BLE_POLICY_ALLOW_SCAN 0x01 /* relevant to advertiser */
+#define BTM_BLE_POLICY_ALLOW_CONN 0x02 /* relevant to advertiser */
+#define BTM_BLE_POLICY_WHITE_ALL 0x03 /* relevant to both */
+
+/* ADV data flag bit definition used for BTM_BLE_AD_TYPE_FLAG */
+#define BTM_BLE_LIMIT_DISC_FLAG (0x01 << 0)
+#define BTM_BLE_GEN_DISC_FLAG (0x01 << 1)
+#define BTM_BLE_BREDR_NOT_SPT (0x01 << 2)
+/* 4.1 spec adv flag for simultaneous BR/EDR+LE connection support */
+#define BTM_BLE_DMT_CONTROLLER_SPT (0x01 << 3)
+#define BTM_BLE_DMT_HOST_SPT (0x01 << 4)
+#define BTM_BLE_NON_LIMIT_DISC_FLAG (0x00) /* lowest bit unset */
+#define BTM_BLE_ADV_FLAG_MASK \
+ (BTM_BLE_LIMIT_DISC_FLAG | BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG)
+#define BTM_BLE_LIMIT_DISC_MASK (BTM_BLE_LIMIT_DISC_FLAG)
+
+// TODO(jpawlowski): this should be removed with code that depend on it.
+#define BTM_BLE_AD_BIT_FLAGS (0x00000001 << 1)
+
+#define BTM_BLE_AD_TYPE_FLAG HCI_EIR_FLAGS_TYPE /* 0x01 */
+#define BTM_BLE_AD_TYPE_16SRV_CMPL \
+ HCI_EIR_COMPLETE_16BITS_UUID_TYPE /* 0x03 \
+ */
+#define BTM_BLE_AD_TYPE_NAME_SHORT \
+ HCI_EIR_SHORTENED_LOCAL_NAME_TYPE /* 0x08 \
+ */
+#define BTM_BLE_AD_TYPE_NAME_CMPL HCI_EIR_COMPLETE_LOCAL_NAME_TYPE /* 0x09 */
+
+#define BTM_BLE_AD_TYPE_APPEARANCE 0x19
+
+/* Security settings used with L2CAP LE COC */
+#define BTM_SEC_LE_LINK_ENCRYPTED 0x01
+#define BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM 0x02
+#define BTM_SEC_LE_LINK_PAIRED_WITH_MITM 0x04
+
+/* Min/max Preferred number of payload octets that the local Controller
+ should include in a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_SIZE_MAX 0x00fb
+#define BTM_BLE_DATA_SIZE_MIN 0x001b
+
+/* Preferred maximum number of microseconds that the local Controller
+ should use to transmit a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_TX_TIME_MIN 0x0148
+#define BTM_BLE_DATA_TX_TIME_MAX 0x0848
+
+/* adv tx power level */
+#define BTM_BLE_ADV_TX_POWER_MIN 0 /* minimum tx power */
+#define BTM_BLE_ADV_TX_POWER_LOW 1 /* low tx power */
+#define BTM_BLE_ADV_TX_POWER_MID 2 /* middle tx power */
+#define BTM_BLE_ADV_TX_POWER_UPPER 3 /* upper tx power */
+#define BTM_BLE_ADV_TX_POWER_MAX 4 /* maximum tx power */
+typedef uint8_t tBTM_BLE_ADV_TX_POWER;
+
+/* adv tx power in dBm */
+typedef struct {
+ uint8_t adv_inst_max; /* max adv instance supported in controller */
+ uint8_t rpa_offloading;
+ uint16_t tot_scan_results_strg;
+ uint8_t max_irk_list_sz;
+ uint8_t filter_support;
+ uint8_t max_filter;
+ uint8_t energy_support;
+ bool values_read;
+ uint16_t version_supported;
+ uint16_t total_trackable_advertisers;
+ uint8_t extended_scan_support;
+ uint8_t debug_logging_supported;
+} tBTM_BLE_VSC_CB;
+
+typedef void(tBTM_BLE_ADV_DATA_CMPL_CBACK)(tBTM_STATUS status);
+
+#ifndef BTM_BLE_MULTI_ADV_MAX
+#define BTM_BLE_MULTI_ADV_MAX \
+ 16 /* controller returned adv_inst_max should be less \
+ than this number */
+#endif
+
+typedef uint8_t tGATT_IF;
+
+typedef void(tBTM_BLE_SCAN_THRESHOLD_CBACK)(tBTM_BLE_REF_VALUE ref_value);
+using tBTM_BLE_SCAN_REP_CBACK =
+ base::Callback<void(uint8_t /* status */, uint8_t /* report_format */,
+ uint8_t /* num_reports */, std::vector<uint8_t>)>;
+
+#ifndef BTM_BLE_BATCH_SCAN_MAX
+#define BTM_BLE_BATCH_SCAN_MAX 5
+#endif
+
+#ifndef BTM_BLE_BATCH_REP_MAIN_Q_SIZE
+#define BTM_BLE_BATCH_REP_MAIN_Q_SIZE 2
+#endif
+
+typedef enum {
+ BTM_BLE_SCAN_INVALID_STATE = 0,
+ BTM_BLE_SCAN_ENABLE_CALLED = 1,
+ BTM_BLE_SCAN_ENABLED_STATE = 2,
+ BTM_BLE_SCAN_DISABLE_CALLED = 3,
+ BTM_BLE_SCAN_DISABLED_STATE = 4
+} tBTM_BLE_BATCH_SCAN_STATE;
+
+enum { BTM_BLE_DISCARD_OLD_ITEMS, BTM_BLE_DISCARD_LOWER_RSSI_ITEMS };
+typedef uint8_t tBTM_BLE_DISCARD_RULE;
+
+typedef struct {
+ tBTM_BLE_BATCH_SCAN_STATE cur_state;
+ tBTM_BLE_BATCH_SCAN_MODE scan_mode;
+ uint32_t scan_interval;
+ uint32_t scan_window;
+ tBLE_ADDR_TYPE addr_type;
+ tBTM_BLE_DISCARD_RULE discard_rule;
+ tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback;
+ tBTM_BLE_REF_VALUE ref_value;
+} tBTM_BLE_BATCH_SCAN_CB;
+
+/* filter selection bit index */
+#define BTM_BLE_PF_ADDR_FILTER 0
+#define BTM_BLE_PF_SRVC_DATA 1
+#define BTM_BLE_PF_SRVC_UUID 2
+#define BTM_BLE_PF_SRVC_SOL_UUID 3
+#define BTM_BLE_PF_LOCAL_NAME 4
+#define BTM_BLE_PF_MANU_DATA 5
+#define BTM_BLE_PF_SRVC_DATA_PATTERN 6
+/* when passed in payload filter type all, only clear action is applicable */
+#define BTM_BLE_PF_TYPE_ALL 7
+#define BTM_BLE_PF_TYPE_MAX 8
+
+/* max number of filter spot for different filter type */
+#ifndef BTM_BLE_MAX_UUID_FILTER
+#define BTM_BLE_MAX_UUID_FILTER 8
+#endif
+#ifndef BTM_BLE_MAX_ADDR_FILTER
+#define BTM_BLE_MAX_ADDR_FILTER 8
+#endif
+#ifndef BTM_BLE_PF_STR_COND_MAX
+#define BTM_BLE_PF_STR_COND_MAX 4 /* apply to manu data , or local name */
+#endif
+#ifndef BTM_BLE_PF_STR_LEN_MAX
+#define BTM_BLE_PF_STR_LEN_MAX 29 /* match for first 29 bytes */
+#endif
+
+typedef uint8_t tBTM_BLE_PF_COND_TYPE;
+
+#define BTM_BLE_PF_LOGIC_OR 0
+#define BTM_BLE_PF_LOGIC_AND 1
+typedef uint8_t tBTM_BLE_PF_LOGIC_TYPE;
+
+#define BTM_BLE_PF_ENABLE 1
+#define BTM_BLE_PF_CONFIG 2
+typedef uint8_t tBTM_BLE_PF_ACTION;
+
+typedef uint8_t tBTM_BLE_PF_FILT_INDEX;
+
+typedef uint8_t tBTM_BLE_PF_AVBL_SPACE;
+
+enum {
+ BTM_BLE_SCAN_COND_ADD,
+ BTM_BLE_SCAN_COND_DELETE,
+ BTM_BLE_SCAN_COND_CLEAR = 2
+};
+typedef uint8_t tBTM_BLE_SCAN_COND_OP;
+
+/* BLE adv payload filtering config complete callback */
+using tBTM_BLE_PF_CFG_CBACK = base::Callback<void(
+ uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* status */)>;
+
+/* BLE adv payload filtering status setup complete callback */
+using tBTM_BLE_PF_STATUS_CBACK =
+ base::Callback<void(uint8_t /*action*/, tBTM_STATUS /* status */)>;
+
+/* BLE adv payload filtering param setup complete callback */
+using tBTM_BLE_PF_PARAM_CB = base::Callback<void(
+ uint8_t /* avbl_space */, uint8_t /* action */, uint8_t /* status */)>;
+
+typedef union {
+ uint16_t uuid16_mask;
+ uint32_t uuid32_mask;
+ uint8_t uuid128_mask[LEN_UUID_128];
+} tBTM_BLE_PF_COND_MASK;
+
+/* per device filter + one generic filter indexed by 0 */
+#define BTM_BLE_MAX_FILTER_COUNTER (BTM_BLE_MAX_ADDR_FILTER + 1)
+
+#ifndef BTM_CS_IRK_LIST_MAX
+#define BTM_CS_IRK_LIST_MAX 0x20
+#endif
+
+typedef struct {
+ bool in_use;
+ BD_ADDR bd_addr;
+ uint8_t pf_counter[BTM_BLE_PF_TYPE_MAX]; /* number of filter indexed by
+ tBTM_BLE_PF_COND_TYPE */
+} tBTM_BLE_PF_COUNT;
+
+typedef struct {
+ bool enable;
+ uint8_t op_type;
+ tBTM_BLE_PF_COUNT* p_addr_filter_count; /* per BDA filter array */
+ tBLE_BD_ADDR cur_filter_target;
+} tBTM_BLE_ADV_FILTER_CB;
+
+/* Sub codes */
+#define BTM_BLE_META_PF_ENABLE 0x00
+#define BTM_BLE_META_PF_FEAT_SEL 0x01
+#define BTM_BLE_META_PF_ADDR 0x02
+#define BTM_BLE_META_PF_UUID 0x03
+#define BTM_BLE_META_PF_SOL_UUID 0x04
+#define BTM_BLE_META_PF_LOCAL_NAME 0x05
+#define BTM_BLE_META_PF_MANU_DATA 0x06
+#define BTM_BLE_META_PF_SRVC_DATA 0x07
+#define BTM_BLE_META_PF_ALL 0x08
+
+typedef uint8_t BTM_BLE_ADV_STATE;
+typedef uint8_t BTM_BLE_ADV_INFO_PRESENT;
+typedef uint8_t BTM_BLE_RSSI_VALUE;
+typedef uint16_t BTM_BLE_ADV_INFO_TIMESTAMP;
+
+enum { BTM_BLE_CONN_NONE, BTM_BLE_CONN_AUTO };
+typedef uint8_t tBTM_BLE_CONN_TYPE;
+
+#define ADV_INFO_PRESENT 0x00
+#define NO_ADV_INFO_PRESENT 0x01
+
+typedef btgatt_track_adv_info_t tBTM_BLE_TRACK_ADV_DATA;
+
+typedef void(tBTM_BLE_TRACK_ADV_CBACK)(
+ tBTM_BLE_TRACK_ADV_DATA* p_track_adv_data);
+
+typedef uint8_t tBTM_BLE_TRACK_ADV_EVT;
+
+typedef struct {
+ tBTM_BLE_REF_VALUE ref_value;
+ tBTM_BLE_TRACK_ADV_CBACK* p_track_cback;
+} tBTM_BLE_ADV_TRACK_CB;
+
+enum { BTM_BLE_TRACK_ADV_ADD, BTM_BLE_TRACK_ADV_REMOVE };
+
+typedef uint8_t tBTM_BLE_TRACK_ADV_ACTION;
+
+typedef uint8_t tBTM_BLE_BATCH_SCAN_EVT;
+
+typedef uint32_t tBTM_BLE_TX_TIME_MS;
+typedef uint32_t tBTM_BLE_RX_TIME_MS;
+typedef uint32_t tBTM_BLE_IDLE_TIME_MS;
+typedef uint32_t tBTM_BLE_ENERGY_USED;
+
+typedef void(tBTM_BLE_ENERGY_INFO_CBACK)(tBTM_BLE_TX_TIME_MS tx_time,
+ tBTM_BLE_RX_TIME_MS rx_time,
+ tBTM_BLE_IDLE_TIME_MS idle_time,
+ tBTM_BLE_ENERGY_USED energy_used,
+ tBTM_STATUS status);
+
+typedef struct {
+ tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback;
+} tBTM_BLE_ENERGY_INFO_CB;
+
+typedef bool(tBTM_BLE_SEL_CBACK)(BD_ADDR random_bda, uint8_t* p_remote_name);
+typedef void(tBTM_BLE_CTRL_FEATURES_CBACK)(tBTM_STATUS status);
+
+/* callback function for SMP signing algorithm, signed data in little endian
+ * order with tlen bits long */
+typedef void(tBTM_BLE_SIGN_CBACK)(void* p_ref_data, uint8_t* p_signing_data);
+typedef void(tBTM_BLE_VERIFY_CBACK)(void* p_ref_data, bool match);
+/* random address set complete callback */
+typedef void(tBTM_BLE_RANDOM_SET_CBACK)(BD_ADDR random_bda);
+
+typedef void(tBTM_BLE_SCAN_REQ_CBACK)(BD_ADDR remote_bda,
+ tBLE_ADDR_TYPE addr_type,
+ uint8_t adv_evt);
+typedef void (*tBLE_SCAN_PARAM_SETUP_CBACK)(tGATT_IF client_if,
+ tBTM_STATUS status);
+
+#endif // BTM_BLE_API_TYPES_H
diff --git a/mtkbt/code/bt/stack/include/btu.h b/mtkbt/code/bt/stack/include/btu.h
new file mode 100755
index 0000000..aef8781
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/btu.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the main Bluetooth Upper Layer definitions. The Broadcom
+ * implementations of L2CAP RFCOMM, SDP and the BTIf run as one GKI task. The
+ * btu_task switches between them.
+ *
+ ******************************************************************************/
+
+#ifndef BTU_H
+#define BTU_H
+
+#include <base/callback.h>
+#include <base/location.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+
+// HACK(zachoverflow): temporary dark magic
+#define BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK \
+ 0x1700 // didn't look used in bt_types...here goes nothing
+typedef struct { void (*callback)(BT_HDR*); } post_to_task_hack_t;
+
+typedef struct {
+ void (*callback)(BT_HDR*);
+ BT_HDR* response;
+ void* context;
+} command_complete_hack_t;
+
+typedef struct {
+ void (*callback)(BT_HDR*);
+ uint8_t status;
+ BT_HDR* command;
+ void* context;
+} command_status_hack_t;
+
+/* Global BTU data */
+extern uint8_t btu_trace_level;
+
+extern const BD_ADDR BT_BD_ANY;
+
+/* Functions provided by btu_hcif.cc
+ ***********************************
+*/
+extern void btu_hcif_process_event(uint8_t controller_id, BT_HDR* p_buf);
+extern void btu_hcif_send_cmd(uint8_t controller_id, BT_HDR* p_msg);
+extern void btu_hcif_send_cmd_with_cb(
+ const tracked_objects::Location& posted_from, uint16_t opcode,
+ uint8_t* params, uint8_t params_len,
+ base::Callback<void(uint8_t*, uint16_t)> cb);
+
+/* Functions provided by btu_init.cc
+ ***********************************
+*/
+extern void btu_init_core(void);
+extern void btu_free_core(void);
+
+void BTU_StartUp(void);
+void BTU_ShutDown(void);
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/gap_api.h b/mtkbt/code/bt/stack/include/gap_api.h
new file mode 100755
index 0000000..7954296
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/gap_api.h
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef GAP_API_H
+#define GAP_API_H
+
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "profiles_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/*** GAP Error and Status Codes ***/
+/* Unsupported call */
+#define GAP_UNSUPPORTED (GAP_ERR_GRP + 0x01)
+/* End of inquiry database marker */
+#define GAP_EOINQDB (GAP_ERR_GRP + 0x02)
+/* The requested function was busy */
+#define GAP_ERR_BUSY (GAP_ERR_GRP + 0x03)
+/* No control blocks available */
+#define GAP_ERR_NO_CTRL_BLK (GAP_ERR_GRP + 0x04)
+/* Error occurred while initiating the command */
+#define GAP_ERR_STARTING_CMD (GAP_ERR_GRP + 0x05)
+/* No Inquiry DB record for BD_ADDR */
+#define GAP_NO_BDADDR_REC (GAP_ERR_GRP + 0x06)
+/* An illegal mode parameter was detected */
+#define GAP_ERR_ILL_MODE (GAP_ERR_GRP + 0x07)
+/* An illegal time parameter was detected */
+#define GAP_ERR_ILL_INQ_TIME (GAP_ERR_GRP + 0x08)
+/* An illegal parameter was detected */
+#define GAP_ERR_ILL_PARM (GAP_ERR_GRP + 0x09)
+/* Error starting the remote device name request */
+#define GAP_ERR_REM_NAME (GAP_ERR_GRP + 0x0a)
+/* The GAP command was started (result pending) */
+#define GAP_CMD_INITIATED (GAP_ERR_GRP + 0x0b)
+/* The device was not up; the request was not executed */
+#define GAP_DEVICE_NOT_UP (GAP_ERR_GRP + 0x0c)
+/* The bd addr passed in was not found or invalid */
+#define GAP_BAD_BD_ADDR (GAP_ERR_GRP + 0x0d)
+
+/* Bad GAP handle */
+#define GAP_ERR_BAD_HANDLE (GAP_ERR_GRP + 0x0e)
+/* Buffer offset invalid */
+#define GAP_ERR_BUF_OFFSET (GAP_ERR_GRP + 0x0f)
+/* Connection is in invalid state */
+#define GAP_ERR_BAD_STATE (GAP_ERR_GRP + 0x10)
+/* No data available */
+#define GAP_NO_DATA_AVAIL (GAP_ERR_GRP + 0x11)
+/* BT stack is congested */
+#define GAP_ERR_CONGESTED (GAP_ERR_GRP + 0x12)
+/* Security failed */
+#define GAP_ERR_SECURITY (GAP_ERR_GRP + 0x13)
+
+/* General error processing BTM request */
+#define GAP_ERR_PROCESSING (GAP_ERR_GRP + 0x14)
+/* Timeout occurred while processing cmd */
+#define GAP_ERR_TIMEOUT (GAP_ERR_GRP + 0x15)
+#define GAP_EVT_CONN_OPENED 0x0100
+#define GAP_EVT_CONN_CLOSED 0x0101
+#define GAP_EVT_CONN_DATA_AVAIL 0x0102
+#define GAP_EVT_CONN_CONGESTED 0x0103
+#define GAP_EVT_CONN_UNCONGESTED 0x0104
+#define GAP_EVT_TX_EMPTY 0x0105
+
+/* Values for 'chan_mode_mask' field */
+/* GAP_ConnOpen() - optional channels to negotiate */
+#define GAP_FCR_CHAN_OPT_BASIC L2CAP_FCR_CHAN_OPT_BASIC
+#define GAP_FCR_CHAN_OPT_ERTM L2CAP_FCR_CHAN_OPT_ERTM
+#define GAP_FCR_CHAN_OPT_STREAM L2CAP_FCR_CHAN_OPT_STREAM
+/*** used in connection variables and functions ***/
+#define GAP_INVALID_HANDLE 0xFFFF
+
+/* This is used to change the criteria for AMP */
+#define GAP_PROTOCOL_ID (UUID_PROTOCOL_UDP)
+
+#ifndef GAP_PREFER_CONN_INT_MAX
+#define GAP_PREFER_CONN_INT_MAX BTM_BLE_CONN_INT_MIN
+#endif
+
+#ifndef GAP_PREFER_CONN_INT_MIN
+#define GAP_PREFER_CONN_INT_MIN BTM_BLE_CONN_INT_MIN
+#endif
+
+#ifndef GAP_PREFER_CONN_LATENCY
+#define GAP_PREFER_CONN_LATENCY 0
+#endif
+
+#ifndef GAP_PREFER_CONN_SP_TOUT
+#define GAP_PREFER_CONN_SP_TOUT 2000
+#endif
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+/*
+ * Callback function for connection services
+*/
+typedef void(tGAP_CONN_CALLBACK)(uint16_t gap_handle, uint16_t event);
+
+/*
+ * Define the callback function prototypes. Parameters are specific
+ * to each event and are described below
+*/
+typedef void(tGAP_CALLBACK)(uint16_t event, void* p_data);
+
+/* Definition of the GAP_FindAddrByName results structure */
+typedef struct {
+ uint16_t status;
+ BD_ADDR bd_addr;
+ tBTM_BD_NAME devname;
+} tGAP_FINDADDR_RESULTS;
+
+typedef struct {
+ uint16_t int_min;
+ uint16_t int_max;
+ uint16_t latency;
+ uint16_t sp_tout;
+} tGAP_BLE_PREF_PARAM;
+
+typedef union {
+ tGAP_BLE_PREF_PARAM conn_param;
+ BD_ADDR reconn_bda;
+ uint16_t icon;
+ uint8_t* p_dev_name;
+ uint8_t addr_resolution;
+
+} tGAP_BLE_ATTR_VALUE;
+
+typedef void(tGAP_BLE_CMPL_CBACK)(bool status, BD_ADDR addr, uint16_t length,
+ char* p_name);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*** Functions for L2CAP connection interface ***/
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnOpen
+ *
+ * Description This function is called to open a generic L2CAP connection.
+ *
+ * Returns handle of the connection if successful, else
+ * GAP_INVALID_HANDLE
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
+ bool is_server, BD_ADDR p_rem_bda, uint16_t psm,
+ tL2CAP_CFG_INFO* p_cfg,
+ tL2CAP_ERTM_INFO* ertm_info, uint16_t security,
+ uint8_t chan_mode_mask, tGAP_CONN_CALLBACK* p_cb,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnClose
+ *
+ * Description This function is called to close a connection.
+ *
+ * Returns BT_PASS - closed OK
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnClose(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnReadData
+ *
+ * Description GKI buffer unaware application will call this function
+ * after receiving GAP_EVT_RXDATA event. A data copy is made
+ * into the receive buffer parameter.
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_NO_DATA_AVAIL - no data available
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnReadData(uint16_t gap_handle, uint8_t* p_data,
+ uint16_t max_len, uint16_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function GAP_GetRxQueueCnt
+ *
+ * Description This function return number of bytes on the rx queue.
+ *
+ * Parameters: handle - Handle returned in the GAP_ConnOpen
+ * p_rx_queue_count - Pointer to return queue count in.
+ *
+ *
+ ******************************************************************************/
+extern int GAP_GetRxQueueCnt(uint16_t handle, uint32_t* p_rx_queue_count);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnBTRead
+ *
+ * Description GKI buffer aware applications will call this function after
+ * receiving an GAP_EVT_RXDATA event to process the incoming
+ * data buffer.
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_NO_DATA_AVAIL - no data available
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnBTRead(uint16_t gap_handle, BT_HDR** pp_buf);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnWriteData
+ *
+ * Description GKI buffer unaware application will call this function
+ * to send data to the connection. A data copy is made into a
+ * GKI buffer.
+ *
+ * Returns BT_PASS - data read
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ * GAP_ERR_BAD_STATE - connection not established
+ * GAP_CONGESTION - system is congested
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnWriteData(uint16_t gap_handle, uint8_t* p_data,
+ uint16_t max_len, uint16_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnReconfig
+ *
+ * Description Applications can call this function to reconfigure the
+ * connection.
+ *
+ * Returns BT_PASS - config process started
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnReconfig(uint16_t gap_handle, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnSetIdleTimeout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection, or for all future connections. The "idle
+ * timeout" is the amount of time that a connection can remain
+ * up with no L2CAP channels on it. A timeout of zero means
+ * that the connection will be torn down immediately when the
+ * last channel is removed. A timeout of 0xFFFF means no
+ * timeout. Values are in seconds.
+ *
+ * Returns BT_PASS - config process started
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnSetIdleTimeout(uint16_t gap_handle, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetRemoteAddr
+ *
+ * Description This function is called to get the remote BD address
+ * of a connection.
+ *
+ * Returns BT_PASS - closed OK
+ * GAP_ERR_BAD_HANDLE - invalid handle
+ *
+ ******************************************************************************/
+extern uint8_t* GAP_ConnGetRemoteAddr(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetRemMtuSize
+ *
+ * Description Returns the remote device's MTU size.
+ *
+ * Returns uint16_t - maximum size buffer that can be transmitted to
+ * the peer
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnGetRemMtuSize(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_ConnGetL2CAPCid
+ *
+ * Description Returns the L2CAP channel id
+ *
+ * Parameters: handle - Handle of the connection
+ *
+ * Returns uint16_t - The L2CAP channel id
+ * 0, if error
+ *
+ ******************************************************************************/
+extern uint16_t GAP_ConnGetL2CAPCid(uint16_t gap_handle);
+
+/*******************************************************************************
+ *
+ * Function GAP_SetTraceLevel
+ *
+ * Description This function sets the trace level for GAP. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+extern uint8_t GAP_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function GAP_Init
+ *
+ * Description Initializes the control blocks used by GAP.
+ * This routine should not be called except once per
+ * stack invocation.
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+extern void GAP_Init(void);
+
+/*******************************************************************************
+ *
+ * Function GAP_BleAttrDBUpdate
+ *
+ * Description update GAP local BLE attribute database.
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+extern void GAP_BleAttrDBUpdate(uint16_t attr_uuid,
+ tGAP_BLE_ATTR_VALUE* p_value);
+
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerPrefConnParams
+ *
+ * Description Start a process to read a connected peripheral's preferred
+ * connection parameters
+ *
+ * Returns true if read started, else false if GAP is busy
+ *
+ ******************************************************************************/
+extern bool GAP_BleReadPeerPrefConnParams(BD_ADDR peer_bda);
+
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerDevName
+ *
+ * Description Start a process to read a connected peripheral's device
+ * name.
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+extern bool GAP_BleReadPeerDevName(BD_ADDR peer_bda,
+ tGAP_BLE_CMPL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function GAP_BleReadPeerAddressResolutionCap
+ *
+ * Description Start a process to read peer address resolution capability
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+extern bool GAP_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,
+ tGAP_BLE_CMPL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function GAP_BleCancelReadPeerDevName
+ *
+ * Description Cancel reading a peripheral's device name.
+ *
+ * Returns true if request accepted
+ *
+ ******************************************************************************/
+extern bool GAP_BleCancelReadPeerDevName(BD_ADDR peer_bda);
+
+#endif /* GAP_API_H */
diff --git a/mtkbt/code/bt/stack/include/gatt_api.h b/mtkbt/code/bt/stack/include/gatt_api.h
new file mode 100755
index 0000000..815dce7
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/gatt_api.h
@@ -0,0 +1,1110 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef GATT_API_H
+#define GATT_API_H
+
+#include "bt_target.h"
+#include "btm_ble_api.h"
+#include "gattdefs.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+/* Success code and error codes */
+#define GATT_SUCCESS 0x00
+#define GATT_INVALID_HANDLE 0x01
+#define GATT_READ_NOT_PERMIT 0x02
+#define GATT_WRITE_NOT_PERMIT 0x03
+#define GATT_INVALID_PDU 0x04
+#define GATT_INSUF_AUTHENTICATION 0x05
+#define GATT_REQ_NOT_SUPPORTED 0x06
+#define GATT_INVALID_OFFSET 0x07
+#define GATT_INSUF_AUTHORIZATION 0x08
+#define GATT_PREPARE_Q_FULL 0x09
+#define GATT_NOT_FOUND 0x0a
+#define GATT_NOT_LONG 0x0b
+#define GATT_INSUF_KEY_SIZE 0x0c
+#define GATT_INVALID_ATTR_LEN 0x0d
+#define GATT_ERR_UNLIKELY 0x0e
+#define GATT_INSUF_ENCRYPTION 0x0f
+#define GATT_UNSUPPORT_GRP_TYPE 0x10
+#define GATT_INSUF_RESOURCE 0x11
+
+#define GATT_ILLEGAL_PARAMETER 0x87
+#define GATT_NO_RESOURCES 0x80
+#define GATT_INTERNAL_ERROR 0x81
+#define GATT_WRONG_STATE 0x82
+#define GATT_DB_FULL 0x83
+#define GATT_BUSY 0x84
+#define GATT_ERROR 0x85
+#define GATT_CMD_STARTED 0x86
+#define GATT_PENDING 0x88
+#define GATT_AUTH_FAIL 0x89
+#define GATT_MORE 0x8a
+#define GATT_INVALID_CFG 0x8b
+#define GATT_SERVICE_STARTED 0x8c
+#define GATT_ENCRYPED_MITM GATT_SUCCESS
+#define GATT_ENCRYPED_NO_MITM 0x8d
+#define GATT_NOT_ENCRYPTED 0x8e
+#define GATT_CONGESTED 0x8f
+
+/* 0xE0 ~ 0xFC reserved for future use */
+
+/* Client Characteristic Configuration Descriptor Improperly Configured */
+#define GATT_CCC_CFG_ERR 0xFD
+/* Procedure Already in progress */
+#define GATT_PRC_IN_PROGRESS 0xFE
+/* Attribute value out of range */
+#define GATT_OUT_OF_RANGE 0xFF
+typedef uint8_t tGATT_STATUS;
+
+#define GATT_RSP_ERROR 0x01
+#define GATT_REQ_MTU 0x02
+#define GATT_RSP_MTU 0x03
+#define GATT_REQ_FIND_INFO 0x04
+#define GATT_RSP_FIND_INFO 0x05
+#define GATT_REQ_FIND_TYPE_VALUE 0x06
+#define GATT_RSP_FIND_TYPE_VALUE 0x07
+#define GATT_REQ_READ_BY_TYPE 0x08
+#define GATT_RSP_READ_BY_TYPE 0x09
+#define GATT_REQ_READ 0x0A
+#define GATT_RSP_READ 0x0B
+#define GATT_REQ_READ_BLOB 0x0C
+#define GATT_RSP_READ_BLOB 0x0D
+#define GATT_REQ_READ_MULTI 0x0E
+#define GATT_RSP_READ_MULTI 0x0F
+#define GATT_REQ_READ_BY_GRP_TYPE 0x10
+#define GATT_RSP_READ_BY_GRP_TYPE 0x11
+/* 0001-0010 (write)*/
+#define GATT_REQ_WRITE 0x12
+#define GATT_RSP_WRITE 0x13
+/* changed in V4.0 01001-0010(write cmd)*/
+#define GATT_CMD_WRITE 0x52
+#define GATT_REQ_PREPARE_WRITE 0x16
+#define GATT_RSP_PREPARE_WRITE 0x17
+#define GATT_REQ_EXEC_WRITE 0x18
+#define GATT_RSP_EXEC_WRITE 0x19
+#define GATT_HANDLE_VALUE_NOTIF 0x1B
+#define GATT_HANDLE_VALUE_IND 0x1D
+#define GATT_HANDLE_VALUE_CONF 0x1E
+/* changed in V4.0 1101-0010 (signed write) see write cmd above*/
+#define GATT_SIGN_CMD_WRITE 0xD2
+/* 0x1E = 30 + 1 = 31*/
+#define GATT_OP_CODE_MAX (GATT_HANDLE_VALUE_CONF + 1)
+
+#define GATT_HANDLE_IS_VALID(x) ((x) != 0)
+
+#define GATT_CONN_UNKNOWN 0
+/* general L2cap failure */
+#define GATT_CONN_L2C_FAILURE 1
+/* 0x08 connection timeout */
+#define GATT_CONN_TIMEOUT HCI_ERR_CONNECTION_TOUT
+/* 0x13 connection terminate by peer user */
+#define GATT_CONN_TERMINATE_PEER_USER HCI_ERR_PEER_USER
+/* 0x16 connectionterminated by local host */
+#define GATT_CONN_TERMINATE_LOCAL_HOST HCI_ERR_CONN_CAUSE_LOCAL_HOST
+/* 0x03E connection fail to establish */
+#define GATT_CONN_FAIL_ESTABLISH HCI_ERR_CONN_FAILED_ESTABLISHMENT
+/* 0x22 connection fail for LMP response tout */
+#define GATT_CONN_LMP_TIMEOUT HCI_ERR_LMP_RESPONSE_TIMEOUT
+/* 0x0100 L2CAP connection cancelled */
+#define GATT_CONN_CANCEL L2CAP_CONN_CANCEL
+typedef uint16_t tGATT_DISCONN_REASON;
+
+/* MAX GATT MTU size
+*/
+#ifndef GATT_MAX_MTU_SIZE
+#define GATT_MAX_MTU_SIZE 517
+#endif
+
+/* max legth of an attribute value
+*/
+#ifndef GATT_MAX_ATTR_LEN
+#define GATT_MAX_ATTR_LEN 600
+#endif
+
+/* default GATT MTU size over LE link
+*/
+#define GATT_DEF_BLE_MTU_SIZE 23
+
+/* invalid connection ID
+*/
+#define GATT_INVALID_CONN_ID 0xFFFF
+
+#ifndef GATT_CL_MAX_LCB
+#define GATT_CL_MAX_LCB 22
+#endif
+
+#ifndef GATT_MAX_SCCB
+#define GATT_MAX_SCCB 10
+#endif
+
+/* GATT notification caching timer, default to be three seconds
+*/
+#ifndef GATTC_NOTIF_TIMEOUT
+#define GATTC_NOTIF_TIMEOUT 3
+#endif
+
+/*****************************************************************************
+ * GATT Structure Definition
+ ****************************************************************************/
+
+/* Attribute permissions
+*/
+#define GATT_PERM_READ (1 << 0) /* bit 0 */
+#define GATT_PERM_READ_ENCRYPTED (1 << 1) /* bit 1 */
+#define GATT_PERM_READ_ENC_MITM (1 << 2) /* bit 2 */
+#define GATT_PERM_WRITE (1 << 4) /* bit 4 */
+#define GATT_PERM_WRITE_ENCRYPTED (1 << 5) /* bit 5 */
+#define GATT_PERM_WRITE_ENC_MITM (1 << 6) /* bit 6 */
+#define GATT_PERM_WRITE_SIGNED (1 << 7) /* bit 7 */
+#define GATT_PERM_WRITE_SIGNED_MITM (1 << 8) /* bit 8 */
+typedef uint16_t tGATT_PERM;
+
+/* the MS nibble of tGATT_PERM; key size 7=0; size 16=9 */
+#define GATT_ENCRYPT_KEY_SIZE_MASK (0xF000)
+
+#define GATT_READ_ALLOWED \
+ (GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_AUTH_REQUIRED (GATT_PERM_READ_ENCRYPTED)
+#define GATT_READ_MITM_REQUIRED (GATT_PERM_READ_ENC_MITM)
+#define GATT_READ_ENCRYPTED_REQUIRED \
+ (GATT_PERM_READ_ENCRYPTED | GATT_PERM_READ_ENC_MITM)
+
+#define GATT_WRITE_ALLOWED \
+ (GATT_PERM_WRITE | GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM | \
+ GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_AUTH_REQUIRED \
+ (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_SIGNED)
+
+#define GATT_WRITE_MITM_REQUIRED \
+ (GATT_PERM_WRITE_ENC_MITM | GATT_PERM_WRITE_SIGNED_MITM)
+
+#define GATT_WRITE_ENCRYPTED_PERM \
+ (GATT_PERM_WRITE_ENCRYPTED | GATT_PERM_WRITE_ENC_MITM)
+
+#define GATT_WRITE_SIGNED_PERM \
+ (GATT_PERM_WRITE_SIGNED | GATT_PERM_WRITE_SIGNED_MITM)
+
+/* Characteristic properties
+*/
+#define GATT_CHAR_PROP_BIT_BROADCAST (1 << 0)
+#define GATT_CHAR_PROP_BIT_READ (1 << 1)
+#define GATT_CHAR_PROP_BIT_WRITE_NR (1 << 2)
+#define GATT_CHAR_PROP_BIT_WRITE (1 << 3)
+#define GATT_CHAR_PROP_BIT_NOTIFY (1 << 4)
+#define GATT_CHAR_PROP_BIT_INDICATE (1 << 5)
+#define GATT_CHAR_PROP_BIT_AUTH (1 << 6)
+#define GATT_CHAR_PROP_BIT_EXT_PROP (1 << 7)
+typedef uint8_t tGATT_CHAR_PROP;
+
+/* Format of the value of a characteristic. enumeration type
+*/
+enum {
+ GATT_FORMAT_RES, /* rfu */
+ GATT_FORMAT_BOOL, /* 0x01 boolean */
+ GATT_FORMAT_2BITS, /* 0x02 2 bit */
+ GATT_FORMAT_NIBBLE, /* 0x03 nibble */
+ GATT_FORMAT_UINT8, /* 0x04 uint8 */
+ GATT_FORMAT_UINT12, /* 0x05 uint12 */
+ GATT_FORMAT_UINT16, /* 0x06 uint16 */
+ GATT_FORMAT_UINT24, /* 0x07 uint24 */
+ GATT_FORMAT_UINT32, /* 0x08 uint32 */
+ GATT_FORMAT_UINT48, /* 0x09 uint48 */
+ GATT_FORMAT_UINT64, /* 0x0a uint64 */
+ GATT_FORMAT_UINT128, /* 0x0B uint128 */
+ GATT_FORMAT_SINT8, /* 0x0C signed 8 bit integer */
+ GATT_FORMAT_SINT12, /* 0x0D signed 12 bit integer */
+ GATT_FORMAT_SINT16, /* 0x0E signed 16 bit integer */
+ GATT_FORMAT_SINT24, /* 0x0F signed 24 bit integer */
+ GATT_FORMAT_SINT32, /* 0x10 signed 32 bit integer */
+ GATT_FORMAT_SINT48, /* 0x11 signed 48 bit integer */
+ GATT_FORMAT_SINT64, /* 0x12 signed 64 bit integer */
+ GATT_FORMAT_SINT128, /* 0x13 signed 128 bit integer */
+ GATT_FORMAT_FLOAT32, /* 0x14 float 32 */
+ GATT_FORMAT_FLOAT64, /* 0x15 float 64*/
+ GATT_FORMAT_SFLOAT, /* 0x16 IEEE-11073 16 bit SFLOAT */
+ GATT_FORMAT_FLOAT, /* 0x17 IEEE-11073 32 bit SFLOAT */
+ GATT_FORMAT_DUINT16, /* 0x18 IEEE-20601 format */
+ GATT_FORMAT_UTF8S, /* 0x19 UTF-8 string */
+ GATT_FORMAT_UTF16S, /* 0x1a UTF-16 string */
+ GATT_FORMAT_STRUCT, /* 0x1b Opaque structure*/
+ GATT_FORMAT_MAX /* 0x1c or above reserved */
+};
+typedef uint8_t tGATT_FORMAT;
+
+/* Characteristic Presentation Format Descriptor value
+*/
+typedef struct {
+ uint16_t unit; /* as UUIUD defined by SIG */
+ uint16_t descr; /* as UUID as defined by SIG */
+ tGATT_FORMAT format;
+ int8_t exp;
+ uint8_t name_spc; /* The name space of the description */
+} tGATT_CHAR_PRES;
+
+/* Characteristic Report reference Descriptor format
+*/
+typedef struct {
+ uint8_t rpt_id; /* report ID */
+ uint8_t rpt_type; /* report type */
+} tGATT_CHAR_RPT_REF;
+
+#define GATT_VALID_RANGE_MAX_SIZE 16
+typedef struct {
+ uint8_t format;
+ uint16_t len;
+ uint8_t lower_range[GATT_VALID_RANGE_MAX_SIZE]; /* in little endian format */
+ uint8_t upper_range[GATT_VALID_RANGE_MAX_SIZE];
+} tGATT_VALID_RANGE;
+
+/* Characteristic Aggregate Format attribute value
+*/
+#define GATT_AGGR_HANDLE_NUM_MAX 10
+typedef struct {
+ uint8_t num_handle;
+ uint16_t handle_list[GATT_AGGR_HANDLE_NUM_MAX];
+} tGATT_CHAR_AGGRE;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+/* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_REL_WRITE 0x0001
+/* permits writes to the characteristic descriptor */
+#define GATT_CHAR_BIT_WRITE_AUX 0x0002
+
+/* characteristic descriptor: client configuration value
+*/
+#define GATT_CLT_CONFIG_NONE 0x0000
+#define GATT_CLT_CONFIG_NOTIFICATION 0x0001
+#define GATT_CLT_CONFIG_INDICATION 0x0002
+typedef uint16_t tGATT_CLT_CHAR_CONFIG;
+
+/* characteristic descriptor: server configuration value
+*/
+#define GATT_SVR_CONFIG_NONE 0x0000
+#define GATT_SVR_CONFIG_BROADCAST 0x0001
+typedef uint16_t tGATT_SVR_CHAR_CONFIG;
+
+/* Characteristic descriptor: Extended Properties value
+*/
+/* permits reliable writes of the Characteristic Value */
+#define GATT_CHAR_BIT_REL_WRITE 0x0001
+/* permits writes to the characteristic descriptor */
+#define GATT_CHAR_BIT_WRITE_AUX 0x0002
+
+/* authentication requirement
+*/
+#define GATT_AUTH_REQ_NONE 0
+#define GATT_AUTH_REQ_NO_MITM 1 /* unauthenticated encryption */
+#define GATT_AUTH_REQ_MITM 2 /* authenticated encryption */
+#define GATT_AUTH_REQ_SIGNED_NO_MITM 3
+#define GATT_AUTH_REQ_SIGNED_MITM 4
+typedef uint8_t tGATT_AUTH_REQ;
+
+/* Attribute Value structure
+*/
+typedef struct {
+ uint16_t conn_id;
+ uint16_t handle; /* attribute handle */
+ uint16_t offset; /* attribute value offset, if no offfset is needed for the
+ command, ignore it */
+ uint16_t len; /* length of attribute value */
+ tGATT_AUTH_REQ auth_req; /* authentication request */
+ uint8_t value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */
+} tGATT_VALUE;
+
+/* Union of the event data which is used in the server respond API to carry the
+ * server response information
+*/
+typedef union {
+ /* data type member event */
+ tGATT_VALUE attr_value; /* READ, HANDLE_VALUE_IND, PREPARE_WRITE */
+ /* READ_BLOB, READ_BY_TYPE */
+ uint16_t handle; /* WRITE, WRITE_BLOB */
+
+} tGATTS_RSP;
+
+/* Transports for the primary service */
+#define GATT_TRANSPORT_LE BT_TRANSPORT_LE
+#define GATT_TRANSPORT_BR_EDR BT_TRANSPORT_BR_EDR
+#define GATT_TRANSPORT_LE_BR_EDR (BT_TRANSPORT_LE | BT_TRANSPORT_BR_EDR)
+typedef uint8_t tGATT_TRANSPORT;
+
+#define GATT_PREP_WRITE_CANCEL 0x00
+#define GATT_PREP_WRITE_EXEC 0x01
+typedef uint8_t tGATT_EXEC_FLAG;
+
+/* read request always based on UUID */
+typedef struct {
+ uint16_t handle;
+ uint16_t offset;
+ bool is_long;
+ bt_gatt_db_attribute_type_t
+ gatt_type; /* are we writing characteristic or descriptor */
+} tGATT_READ_REQ;
+
+/* write request data */
+typedef struct {
+ uint16_t handle; /* attribute handle */
+ uint16_t offset; /* attribute value offset, if no offfset is needed for the
+ command, ignore it */
+ uint16_t len; /* length of attribute value */
+ uint8_t value[GATT_MAX_ATTR_LEN]; /* the actual attribute value */
+ bool need_rsp; /* need write response */
+ bool is_prep; /* is prepare write */
+ bt_gatt_db_attribute_type_t
+ gatt_type; /* are we writing characteristic or descriptor */
+} tGATT_WRITE_REQ;
+
+/* callback data for server access request from client */
+typedef union {
+ tGATT_READ_REQ read_req; /* read request, read by Type, read blob */
+
+ tGATT_WRITE_REQ write_req; /* write */
+ /* prepare write */
+ /* write blob */
+ uint16_t handle; /* handle value confirmation */
+ uint16_t mtu; /* MTU exchange request */
+ tGATT_EXEC_FLAG exec_write; /* execute write */
+} tGATTS_DATA;
+
+typedef uint8_t tGATT_SERV_IF; /* GATT Service Interface */
+
+enum {
+ GATTS_REQ_TYPE_READ_CHARACTERISTIC = 1, /* Char read request */
+ GATTS_REQ_TYPE_READ_DESCRIPTOR, /* Desc read request */
+ GATTS_REQ_TYPE_WRITE_CHARACTERISTIC, /* Char write request */
+ GATTS_REQ_TYPE_WRITE_DESCRIPTOR, /* Desc write request */
+ GATTS_REQ_TYPE_WRITE_EXEC, /* Execute write */
+ GATTS_REQ_TYPE_MTU, /* MTU exchange information */
+ GATTS_REQ_TYPE_CONF /* handle value confirmation */
+};
+typedef uint8_t tGATTS_REQ_TYPE;
+
+/* Client Used Data Structure
+*/
+/* definition of different discovery types */
+enum {
+ GATT_DISC_SRVC_ALL = 1, /* discover all services */
+ GATT_DISC_SRVC_BY_UUID, /* discover service of a special type */
+ GATT_DISC_INC_SRVC, /* discover the included service within a service */
+ GATT_DISC_CHAR, /* discover characteristics of a service with/without type
+ requirement */
+ GATT_DISC_CHAR_DSCPT, /* discover characteristic descriptors of a character */
+ GATT_DISC_MAX /* maximnun discover type */
+};
+typedef uint8_t tGATT_DISC_TYPE;
+
+/* Discover parameters of different discovery types
+*/
+typedef struct {
+ tBT_UUID service;
+ uint16_t s_handle;
+ uint16_t e_handle;
+} tGATT_DISC_PARAM;
+
+/* GATT read type enumeration
+*/
+enum {
+ GATT_READ_BY_TYPE = 1,
+ GATT_READ_BY_HANDLE,
+ GATT_READ_MULTIPLE,
+ GATT_READ_CHAR_VALUE,
+ GATT_READ_PARTIAL,
+ GATT_READ_MAX
+};
+typedef uint8_t tGATT_READ_TYPE;
+
+/* Read By Type Request (GATT_READ_BY_TYPE) Data
+*/
+typedef struct {
+ tGATT_AUTH_REQ auth_req;
+ uint16_t s_handle;
+ uint16_t e_handle;
+ tBT_UUID uuid;
+} tGATT_READ_BY_TYPE;
+
+/* GATT_READ_MULTIPLE request data
+*/
+#define GATT_MAX_READ_MULTI_HANDLES \
+ 10 /* Max attributes to read in one request */
+typedef struct {
+ tGATT_AUTH_REQ auth_req;
+ uint16_t num_handles; /* number of handles to read */
+ uint16_t handles[GATT_MAX_READ_MULTI_HANDLES]; /* handles list to be read */
+} tGATT_READ_MULTI;
+
+/* Read By Handle Request (GATT_READ_BY_HANDLE) data */
+typedef struct {
+ tGATT_AUTH_REQ auth_req;
+ uint16_t handle;
+} tGATT_READ_BY_HANDLE;
+
+/* READ_BT_HANDLE_Request data */
+typedef struct {
+ tGATT_AUTH_REQ auth_req;
+ uint16_t handle;
+ uint16_t offset;
+} tGATT_READ_PARTIAL;
+
+/* Read Request Data
+*/
+typedef union {
+ tGATT_READ_BY_TYPE service;
+ tGATT_READ_BY_TYPE char_type; /* characterisitc type */
+ tGATT_READ_MULTI read_multiple;
+ tGATT_READ_BY_HANDLE by_handle;
+ tGATT_READ_PARTIAL partial;
+} tGATT_READ_PARAM;
+
+/* GATT write type enumeration */
+enum { GATT_WRITE_NO_RSP = 1, GATT_WRITE, GATT_WRITE_PREPARE };
+typedef uint8_t tGATT_WRITE_TYPE;
+
+/* Client Operation Complete Callback Data
+*/
+typedef union {
+ tGATT_VALUE att_value;
+ uint16_t mtu;
+ uint16_t handle;
+} tGATT_CL_COMPLETE;
+
+/* GATT client operation type, used in client callback function
+*/
+#define GATTC_OPTYPE_NONE 0
+#define GATTC_OPTYPE_DISCOVERY 1
+#define GATTC_OPTYPE_READ 2
+#define GATTC_OPTYPE_WRITE 3
+#define GATTC_OPTYPE_EXE_WRITE 4
+#define GATTC_OPTYPE_CONFIG 5
+#define GATTC_OPTYPE_NOTIFICATION 6
+#define GATTC_OPTYPE_INDICATION 7
+typedef uint8_t tGATTC_OPTYPE;
+
+/* characteristic declaration
+*/
+typedef struct {
+ tGATT_CHAR_PROP char_prop; /* characterisitc properties */
+ uint16_t val_handle; /* characteristic value attribute handle */
+ tBT_UUID char_uuid; /* characteristic UUID type */
+} tGATT_CHAR_DCLR_VAL;
+
+/* primary service group data
+*/
+typedef struct {
+ uint16_t e_handle; /* ending handle of the group */
+ tBT_UUID service_type; /* group type */
+} tGATT_GROUP_VALUE;
+
+/* included service attribute value
+*/
+typedef struct {
+ tBT_UUID service_type; /* included service UUID */
+ uint16_t s_handle; /* starting handle */
+ uint16_t e_handle; /* ending handle */
+} tGATT_INCL_SRVC;
+
+typedef union {
+ tGATT_INCL_SRVC incl_service; /* include service value */
+ tGATT_GROUP_VALUE group_value; /* Service UUID type.
+ This field is used with GATT_DISC_SRVC_ALL
+ or GATT_DISC_SRVC_BY_UUID
+ type of discovery result callback. */
+
+ uint16_t handle; /* When used with GATT_DISC_INC_SRVC type discovery result,
+ it is the included service starting handle.*/
+
+ tGATT_CHAR_DCLR_VAL
+ dclr_value; /* Characteristic declaration value.
+ This field is used with GATT_DISC_CHAR type discovery.*/
+} tGATT_DISC_VALUE;
+
+/* discover result record
+*/
+typedef struct {
+ tBT_UUID type;
+ uint16_t handle;
+ tGATT_DISC_VALUE value;
+} tGATT_DISC_RES;
+
+#define GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP \
+ 1 /* start a idle timer for this duration \
+ when no application need to use the link */
+
+#define GATT_LINK_NO_IDLE_TIMEOUT 0xFFFF
+
+#define GATT_INVALID_ACL_HANDLE 0xFFFF
+/* discover result callback function */
+typedef void(tGATT_DISC_RES_CB)(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_RES* p_data);
+
+/* discover complete callback function */
+typedef void(tGATT_DISC_CMPL_CB)(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_STATUS status);
+
+/* Define a callback function for when read/write/disc/config operation is
+ * completed. */
+typedef void(tGATT_CMPL_CBACK)(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status, tGATT_CL_COMPLETE* p_data);
+
+/* Define a callback function when an initialized connection is established. */
+typedef void(tGATT_CONN_CBACK)(tGATT_IF gatt_if, BD_ADDR bda, uint16_t conn_id,
+ bool connected, tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport);
+
+/* attribute request callback for ATT server */
+typedef void(tGATT_REQ_CBACK)(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type, tGATTS_DATA* p_data);
+
+/* channel congestion/uncongestion callback */
+typedef void(tGATT_CONGESTION_CBACK)(uint16_t conn_id, bool congested);
+
+/* Define a callback function when encryption is established. */
+typedef void(tGATT_ENC_CMPL_CB)(tGATT_IF gatt_if, BD_ADDR bda);
+
+/* Define a callback function when phy is updated. */
+typedef void(tGATT_PHY_UPDATE_CB)(tGATT_IF gatt_if, uint16_t conn_id,
+ uint8_t tx_phy, uint8_t rx_phy,
+ uint8_t status);
+
+/* Define a callback function when connection parameters are updated */
+typedef void(tGATT_CONN_UPDATE_CB)(tGATT_IF gatt_if, uint16_t conn_id,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout, uint8_t status);
+
+/* Define the structure that applications use to register with
+ * GATT. This structure includes callback functions. All functions
+ * MUST be provided.
+*/
+typedef struct {
+ tGATT_CONN_CBACK* p_conn_cb;
+ tGATT_CMPL_CBACK* p_cmpl_cb;
+ tGATT_DISC_RES_CB* p_disc_res_cb;
+ tGATT_DISC_CMPL_CB* p_disc_cmpl_cb;
+ tGATT_REQ_CBACK* p_req_cb;
+ tGATT_ENC_CMPL_CB* p_enc_cmpl_cb;
+ tGATT_CONGESTION_CBACK* p_congestion_cb;
+ tGATT_PHY_UPDATE_CB* p_phy_update_cb;
+ tGATT_CONN_UPDATE_CB* p_conn_update_cb;
+} tGATT_CBACK;
+
+/***************** Start Handle Management Definitions *********************/
+
+typedef struct {
+ tBT_UUID app_uuid128;
+ tBT_UUID svc_uuid;
+ uint16_t s_handle;
+ uint16_t e_handle;
+ bool is_primary; /* primary service or secondary */
+} tGATTS_HNDL_RANGE;
+
+#define GATTS_SRV_CHG_CMD_ADD_CLIENT 1
+#define GATTS_SRV_CHG_CMD_UPDATE_CLIENT 2
+#define GATTS_SRV_CHG_CMD_REMOVE_CLIENT 3
+#define GATTS_SRV_CHG_CMD_READ_NUM_CLENTS 4
+#define GATTS_SRV_CHG_CMD_READ_CLENT 5
+typedef uint8_t tGATTS_SRV_CHG_CMD;
+
+typedef struct {
+ BD_ADDR bda;
+ bool srv_changed;
+} tGATTS_SRV_CHG;
+
+typedef union {
+ tGATTS_SRV_CHG srv_chg;
+ uint8_t client_read_index; /* only used for sequential reading client srv chg
+ info */
+} tGATTS_SRV_CHG_REQ;
+
+typedef union {
+ tGATTS_SRV_CHG srv_chg;
+ uint8_t num_clients;
+} tGATTS_SRV_CHG_RSP;
+
+/* Attibute server handle ranges NV storage callback functions
+*/
+typedef void(tGATTS_NV_SAVE_CBACK)(bool is_saved,
+ tGATTS_HNDL_RANGE* p_hndl_range);
+typedef bool(tGATTS_NV_SRV_CHG_CBACK)(tGATTS_SRV_CHG_CMD cmd,
+ tGATTS_SRV_CHG_REQ* p_req,
+ tGATTS_SRV_CHG_RSP* p_rsp);
+
+typedef struct {
+ tGATTS_NV_SAVE_CBACK* p_nv_save_callback;
+ tGATTS_NV_SRV_CHG_CBACK* p_srv_chg_callback;
+} tGATT_APPL_INFO;
+
+/******************** End Handle Management Definitions ********************/
+
+/*******************************************************************************
+ * External Function Declarations
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function GATT_SetTraceLevel
+ *
+ * Description This function sets the trace level. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+extern uint8_t GATT_SetTraceLevel(uint8_t new_level);
+
+/******************************************************************************/
+/* GATT Profile API Functions */
+/******************************************************************************/
+/* GATT Profile Server Functions */
+/******************************************************************************/
+/*******************************************************************************
+ *
+ * Function GATTS_AddHandleRange
+ *
+ * Description This function add the allocated handles range for the
+ * specified application UUID, service UUID and service
+ * instance
+ *
+ * Parameter p_hndl_range: pointer to allocated handles information
+ ******************************************************************************/
+
+extern void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range);
+
+/*******************************************************************************
+ *
+ * Function GATTS_NVRegister
+ *
+ * Description Application manager calls this function to register for
+ * NV save callback function. There can be one and only one
+ * NV save callback function.
+ *
+ * Parameter p_cb_info : callback informaiton
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+extern bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info);
+
+/* Converts 16bit uuid to bt_uuid_t that can be used when adding
+ * service/characteristic/descriptor with GATTS_AddService */
+void uuid_128_from_16(bt_uuid_t* uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTA_GATTS_AddService
+ *
+ * Description Add a service. When service is ready, a callback
+ * event BTA_GATTS_ADD_SRVC_EVT is called to report status
+ * and handles to the profile.
+ *
+ * Parameters server_if: server interface.
+ * service: pointer array describing service.
+ * count: number of elements in service array.
+ *
+ * Returns on success GATT_SERVICE_STARTED is returned, and
+ * attribute_handle field inside service elements are filled.
+ * on error error status is returned.
+ *
+ ******************************************************************************/
+extern uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service,
+ int count);
+
+/*******************************************************************************
+ *
+ * Function GATTS_DeleteService
+ *
+ * Description This function is called to delete a service.
+ *
+ * Parameter gatt_if : application interface
+ * p_svc_uuid : service UUID
+ * svc_inst : instance of the service inside the
+ * application
+ *
+ * Returns true if operation succeed, else false
+ *
+ ******************************************************************************/
+extern bool GATTS_DeleteService(tGATT_IF gatt_if, tBT_UUID* p_svc_uuid,
+ uint16_t svc_inst);
+
+/*******************************************************************************
+ *
+ * Function GATTS_StopService
+ *
+ * Description This function is called to stop a service
+ *
+ * Parameter service_handle : this is the start handle of a service
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+extern void GATTS_StopService(uint16_t service_handle);
+
+/*******************************************************************************
+ *
+ * Function GATTs_HandleValueIndication
+ *
+ * Description This function sends a handle value indication to a client.
+ *
+ * Parameter conn_id: connection identifier.
+ * attr_handle: Attribute handle of this handle value
+ * indication.
+ * val_len: Length of the indicated attribute value.
+ * p_val: Pointer to the indicated attribute value data.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error
+ * code.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id,
+ uint16_t attr_handle,
+ uint16_t val_len,
+ uint8_t* p_val);
+
+/*******************************************************************************
+ *
+ * Function GATTS_HandleValueNotification
+ *
+ * Description This function sends a handle value notification to a client.
+ *
+ * Parameter conn_id: connection identifier.
+ * attr_handle: Attribute handle of this handle value
+ * indication.
+ * val_len: Length of the indicated attribute value.
+ * p_val: Pointer to the indicated attribute value data.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
+ uint16_t attr_handle,
+ uint16_t val_len,
+ uint8_t* p_val);
+
+/*******************************************************************************
+ *
+ * Function GATTS_SendRsp
+ *
+ * Description This function sends the server response to client.
+ *
+ * Parameter conn_id: connection identifier.
+ * trans_id: transaction id
+ * status: response status
+ * p_msg: pointer to message parameters structure.
+ *
+ * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
+ tGATT_STATUS status, tGATTS_RSP* p_msg);
+
+/******************************************************************************/
+/* GATT Profile Client Functions */
+/******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function GATTC_ConfigureMTU
+ *
+ * Description This function is called to configure the ATT MTU size for
+ * a connection on an LE transport.
+ *
+ * Parameters conn_id: connection identifier.
+ * mtu - attribute MTU size..
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu);
+
+extern void GATTC_ReadPHY(
+ uint16_t conn_id,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb);
+extern void GATTC_SetPreferredPHY(uint16_t conn_id, uint8_t tx_phy,
+ uint8_t rx_phy, uint16_t phy_options);
+
+/*******************************************************************************
+ *
+ * Function GATTC_Discover
+ *
+ * Description This function is called to do a discovery procedure on ATT
+ * server.
+ *
+ * Parameters conn_id: connection identifier.
+ * disc_type:discovery type.
+ * p_param: parameters of discovery requirement.
+ *
+ * Returns GATT_SUCCESS if command received/sent successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
+ tGATT_DISC_PARAM* p_param);
+/*******************************************************************************
+ *
+ * Function GATTC_Read
+ *
+ * Description This function is called to read the value of an attribute
+ * from the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * type - attribute read type.
+ * p_read - read operation parameters.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
+ tGATT_READ_PARAM* p_read);
+
+/*******************************************************************************
+ *
+ * Function GATTC_Write
+ *
+ * Description This function is called to read the value of an attribute
+ * from the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * type - attribute write type.
+ * p_write - write operation parameters.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
+ tGATT_VALUE* p_write);
+
+/*******************************************************************************
+ *
+ * Function GATTC_ExecuteWrite
+ *
+ * Description This function is called to send an Execute write request to
+ * the server.
+ *
+ * Parameters conn_id: connection identifier.
+ * is_execute - to execute or cancel the prepare write
+ * request(s)
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute);
+
+/*******************************************************************************
+ *
+ * Function GATTC_SendHandleValueConfirm
+ *
+ * Description This function is called to send a handle value confirmation
+ * as response to a handle value notification from server.
+ *
+ * Parameters conn_id: connection identifier.
+ * handle: the handle of the attribute confirmation.
+ *
+ * Returns GATT_SUCCESS if command started successfully.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id,
+ uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function GATT_SetIdleTimeout
+ *
+ * Description This function (common to both client and server) sets the
+ * idle timeout for a tansport connection
+ *
+ * Parameter bd_addr: target device bd address.
+ * idle_tout: timeout value in seconds.
+ * transport: trasnport option.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void GATT_SetIdleTimeout(BD_ADDR bd_addr, uint16_t idle_tout,
+ tGATT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function GATT_Register
+ *
+ * Description This function is called to register an application
+ * with GATT
+ *
+ * Parameter p_app_uuid128: Application UUID
+ * p_cb_info: callback functions.
+ *
+ * Returns 0 for error, otherwise the index of the client registered
+ * with GATT
+ *
+ ******************************************************************************/
+extern tGATT_IF GATT_Register(tBT_UUID* p_app_uuid128, tGATT_CBACK* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function GATT_Deregister
+ *
+ * Description This function deregistered the application from GATT.
+ *
+ * Parameters gatt_if: applicaiton interface.
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+extern void GATT_Deregister(tGATT_IF gatt_if);
+
+/*******************************************************************************
+ *
+ * Function GATT_StartIf
+ *
+ * Description This function is called after registration to start
+ * receiving callbacks for registered interface. Function may
+ * call back with connection status and queued notifications
+ *
+ * Parameter gatt_if: applicaiton interface.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void GATT_StartIf(tGATT_IF gatt_if);
+
+/*******************************************************************************
+ *
+ * Function GATT_Connect
+ *
+ * Description This function initiate a connecttion to a remote device on
+ * GATT channel.
+ *
+ * Parameters gatt_if: applicaiton interface
+ * bd_addr: peer device address.
+ * is_direct: is a direct connection or a background auto
+ * connection
+ * transport : Physical transport for GATT connection
+ * (BR/EDR or LE)
+ * opportunistic: will not keep device connected if other apps
+ * disconnect, will not update connected apps counter, when
+ * disconnected won't cause physical disconnection.
+ *
+ * Returns true if connection started; else false
+ *
+ ******************************************************************************/
+extern bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
+ tBT_TRANSPORT transport, bool opportunistic);
+extern bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
+ tBT_TRANSPORT transport, bool opportunistic,
+ uint8_t initiating_phys);
+
+/*******************************************************************************
+ *
+ * Function GATT_CancelConnect
+ *
+ * Description Terminate the connection initiation to a remote device on a
+ * GATT channel.
+ *
+ * Parameters gatt_if: client interface. If 0 used as unconditionally
+ * disconnect, typically used for direct connection
+ * cancellation.
+ * bd_addr: peer device address.
+ * is_direct: is a direct conenection or a background auto
+ * connection
+ *
+ * Returns true if connection started; else false
+ *
+ ******************************************************************************/
+extern bool GATT_CancelConnect(tGATT_IF gatt_if, BD_ADDR bd_addr,
+ bool is_direct);
+
+/*******************************************************************************
+ *
+ * Function GATT_Disconnect
+ *
+ * Description Disconnect the GATT channel for this registered application.
+ *
+ * Parameters conn_id: connection identifier.
+ *
+ * Returns GATT_SUCCESS if disconnected.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS GATT_Disconnect(uint16_t conn_id);
+
+/*******************************************************************************
+ *
+ * Function GATT_GetConnectionInfor
+ *
+ * Description Use conn_id to find its associated BD address and
+ * application interface
+ *
+ * Parameters conn_id: connection id (input)
+ * p_gatt_if: applicaiton interface (output)
+ * bd_addr: peer device address. (output)
+ * transport : physical transport of the GATT connection
+ * (BR/EDR or LE)
+ *
+ * Returns true the ligical link information is found for conn_id
+ *
+ ******************************************************************************/
+extern bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if,
+ BD_ADDR bd_addr,
+ tBT_TRANSPORT* p_transport);
+
+/*******************************************************************************
+ *
+ * Function GATT_GetConnIdIfConnected
+ *
+ * Description Find the conn_id if the logical link for a BD address
+ * and application interface is connected
+ *
+ * Parameters gatt_if: applicaiton interface (input)
+ * bd_addr: peer device address. (input)
+ * p_conn_id: connection id (output)
+ * transport : physical transport of the GATT connection
+ * (BR/EDR or LE)
+ *
+ * Returns true the ligical link is connected
+ *
+ ******************************************************************************/
+extern bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr,
+ uint16_t* p_conn_id,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function GATT_ConfigServiceChangeCCC
+ *
+ * Description Configure service change indication on remote device
+ *
+ * Returns None.
+ *
+ ******************************************************************************/
+extern void GATT_ConfigServiceChangeCCC(BD_ADDR remote_bda, bool enable,
+ tBT_TRANSPORT transport);
+
+// Enables the GATT profile on the device.
+// It clears out the control blocks, and registers with L2CAP.
+extern void gatt_init(void);
+
+// Frees resources used by the GATT profile.
+extern void gatt_free(void);
+
+// Link encryption complete notification for all encryption process
+// initiated outside GATT.
+extern void gatt_notify_enc_cmpl(BD_ADDR bd_addr);
+
+// Reset bg device list.
+extern void gatt_reset_bgdev_list(void);
+
+#endif /* GATT_API_H */
diff --git a/mtkbt/code/bt/stack/include/gattdefs.h b/mtkbt/code/bt/stack/include/gattdefs.h
new file mode 100755
index 0000000..de968a8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/gattdefs.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used ATT definitions
+ *
+ ******************************************************************************/
+
+#ifndef _GATTDEFS_H
+#define _GATTDEFS_H
+
+#define GATT_ILLEGAL_UUID 0
+
+/* GATT attribute types
+*/
+#define GATT_UUID_PRI_SERVICE 0x2800
+#define GATT_UUID_SEC_SERVICE 0x2801
+#define GATT_UUID_INCLUDE_SERVICE 0x2802
+/* Characteristic Declaration*/
+#define GATT_UUID_CHAR_DECLARE 0x2803
+
+/* Characteristic Extended Properties */
+#define GATT_UUID_CHAR_EXT_PROP 0x2900
+/* Characteristic User Description*/
+#define GATT_UUID_CHAR_DESCRIPTION 0x2901
+/* Client Characteristic Configuration */
+#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902
+/* Server Characteristic Configuration */
+#define GATT_UUID_CHAR_SRVR_CONFIG 0x2903
+/* Characteristic Presentation Format*/
+#define GATT_UUID_CHAR_PRESENT_FORMAT 0x2904
+/* Characteristic Aggregate Format*/
+#define GATT_UUID_CHAR_AGG_FORMAT 0x2905
+/* Characteristic Valid Range */
+#define GATT_UUID_CHAR_VALID_RANGE 0x2906
+#define GATT_UUID_EXT_RPT_REF_DESCR 0x2907
+#define GATT_UUID_RPT_REF_DESCR 0x2908
+
+/* GAP Profile Attributes
+*/
+#define GATT_UUID_GAP_DEVICE_NAME 0x2A00
+#define GATT_UUID_GAP_ICON 0x2A01
+#define GATT_UUID_GAP_PREF_CONN_PARAM 0x2A04
+#define GATT_UUID_GAP_CENTRAL_ADDR_RESOL 0x2AA6
+
+/* Attribute Profile Attribute UUID */
+#define GATT_UUID_GATT_SRV_CHGD 0x2A05
+/* Attribute Protocol Test */
+
+/* Link Loss Service */
+#define GATT_UUID_ALERT_LEVEL 0x2A06 /* Alert Level */
+#define GATT_UUID_TX_POWER_LEVEL 0x2A07 /* TX power level */
+
+/* Time Profile */
+/* Current Time Service */
+#define GATT_UUID_CURRENT_TIME 0x2A2B /* Current Time */
+#define GATT_UUID_LOCAL_TIME_INFO 0x2A0F /* Local time info */
+#define GATT_UUID_REF_TIME_INFO 0x2A14 /* reference time information */
+
+/* NwA Profile */
+#define GATT_UUID_NW_STATUS 0x2A18 /* network availability status */
+#define GATT_UUID_NW_TRIGGER 0x2A1A /* Network availability trigger */
+
+/* phone alert */
+#define GATT_UUID_ALERT_STATUS 0x2A3F /* alert status */
+#define GATT_UUID_RINGER_CP 0x2A40 /* ringer control point */
+#define GATT_UUID_RINGER_SETTING 0x2A41 /* ringer setting */
+
+/* Glucose Service */
+#define GATT_UUID_GM_MEASUREMENT 0x2A18
+#define GATT_UUID_GM_CONTEXT 0x2A34
+#define GATT_UUID_GM_CONTROL_POINT 0x2A52
+#define GATT_UUID_GM_FEATURE 0x2A51
+
+/* device infor characteristic */
+#define GATT_UUID_SYSTEM_ID 0x2A23
+#define GATT_UUID_MODEL_NUMBER_STR 0x2A24
+#define GATT_UUID_SERIAL_NUMBER_STR 0x2A25
+#define GATT_UUID_FW_VERSION_STR 0x2A26
+#define GATT_UUID_HW_VERSION_STR 0x2A27
+#define GATT_UUID_SW_VERSION_STR 0x2A28
+#define GATT_UUID_MANU_NAME 0x2A29
+#define GATT_UUID_IEEE_DATA 0x2A2A
+#define GATT_UUID_PNP_ID 0x2A50
+
+/* HID characteristics */
+#define GATT_UUID_HID_INFORMATION 0x2A4A
+#define GATT_UUID_HID_REPORT_MAP 0x2A4B
+#define GATT_UUID_HID_CONTROL_POINT 0x2A4C
+#define GATT_UUID_HID_REPORT 0x2A4D
+#define GATT_UUID_HID_PROTO_MODE 0x2A4E
+#define GATT_UUID_HID_BT_KB_INPUT 0x2A22
+#define GATT_UUID_HID_BT_KB_OUTPUT 0x2A32
+#define GATT_UUID_HID_BT_MOUSE_INPUT 0x2A33
+
+/* Battery Service char */
+#define GATT_UUID_BATTERY_LEVEL 0x2A19
+
+#define GATT_UUID_SC_CONTROL_POINT 0x2A55
+#define GATT_UUID_SENSOR_LOCATION 0x2A5D
+
+/* RUNNERS SPEED AND CADENCE SERVICE */
+#define GATT_UUID_RSC_MEASUREMENT 0x2A53
+#define GATT_UUID_RSC_FEATURE 0x2A54
+
+/* CYCLING SPEED AND CADENCE SERVICE */
+#define GATT_UUID_CSC_MEASUREMENT 0x2A5B
+#define GATT_UUID_CSC_FEATURE 0x2A5C
+
+/* Scan Parameter charatceristics */
+#define GATT_UUID_SCAN_INT_WINDOW 0x2A4F
+#define GATT_UUID_SCAN_REFRESH 0x2A31
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/hcidefs.h b/mtkbt/code/bt/stack/include/hcidefs.h
new file mode 100755
index 0000000..a219eb9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/hcidefs.h
@@ -0,0 +1,3200 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef HCIDEFS_H
+#define HCIDEFS_H
+
+#define HCI_PROTO_VERSION 0x01 /* Version for BT spec 1.1 */
+#define HCI_PROTO_VERSION_1_2 0x02 /* Version for BT spec 1.2 */
+#define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */
+#define HCI_PROTO_VERSION_2_1 0x04 /* Version for BT spec 2.1 [Lisbon] */
+#define HCI_PROTO_VERSION_3_0 0x05 /* Version for BT spec 3.0 */
+#define HCI_PROTO_VERSION_4_0 0x06 /* Version for BT spec 4.0 */
+#define HCI_PROTO_VERSION_4_1 0x07 /* Version for BT spec 4.1 */
+#define HCI_PROTO_VERSION_4_2 0x08 /* Version for BT spec 4.2 */
+
+/*
+ * Definitions for HCI groups
+*/
+#define HCI_GRP_LINK_CONTROL_CMDS (0x01 << 10) /* 0x0400 */
+#define HCI_GRP_LINK_POLICY_CMDS (0x02 << 10) /* 0x0800 */
+#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */
+#define HCI_GRP_INFORMATIONAL_PARAMS (0x04 << 10) /* 0x1000 */
+#define HCI_GRP_STATUS_PARAMS (0x05 << 10) /* 0x1400 */
+#define HCI_GRP_TESTING_CMDS (0x06 << 10) /* 0x1800 */
+
+#define HCI_GRP_VENDOR_SPECIFIC (0x3F << 10) /* 0xFC00 */
+
+/* Group occupies high 6 bits of the HCI command rest is opcode itself */
+#define HCI_OGF(p) (uint8_t)((0xFC00 & (p)) >> 10)
+#define HCI_OCF(p) (0x3FF & (p))
+
+/*
+ * Definitions for Link Control Commands
+*/
+/* Following opcode is used only in command complete event for flow control */
+#define HCI_COMMAND_NONE 0x0000
+
+/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
+#define HCI_INQUIRY (0x0001 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_INQUIRY_CANCEL (0x0002 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PERIODIC_INQUIRY_MODE (0x0003 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_EXIT_PERIODIC_INQUIRY_MODE (0x0004 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION (0x0005 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT (0x0006 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ADD_SCO_CONNECTION (0x0007 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION_CANCEL (0x0008 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_CONNECTION_REQUEST (0x0009 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_CONNECTION_REQUEST (0x000A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_REPLY (0x000B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY (0x000C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_REPLY (0x000D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY (0x000E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_PACKET_TYPE (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_AUTHENTICATION_REQUESTED (0x0011 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CONN_ENCRYPTION (0x0013 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_LINK_KEY (0x0015 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_MASTER_LINK_KEY (0x0017 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST (0x0019 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST_CANCEL (0x001A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_FEATURES (0x001B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_EXT_FEATURES (0x001C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_VERSION_INFO (0x001D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_CLOCK_OFFSET (0x001F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_LMP_HANDLE (0x0020 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SETUP_ESCO_CONNECTION (0x0028 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_ESCO_CONNECTION (0x0029 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_ESCO_CONNECTION (0x002A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAPABILITY_REQUEST_REPLY (0x002B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_REQUEST_REPLY (0x002C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_VALUE_NEG_REPLY (0x002D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_REPLY (0x002E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_NEG_REPLY (0x002F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_REPLY (0x0030 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_NEG_REPLY (0x0033 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAP_REQ_NEG_REPLY (0x0034 | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* AMP HCI */
+#define HCI_CREATE_PHYSICAL_LINK (0x0035 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_PHYSICAL_LINK (0x0036 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_PHYSICAL_LINK (0x0037 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_LOGICAL_LINK (0x0038 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_LOGICAL_LINK (0x0039 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT_LOGICAL_LINK (0x003A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LOGICAL_LINK_CANCEL (0x003B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_FLOW_SPEC_MODIFY (0x003C | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_ENH_SETUP_ESCO_CONNECTION (0x003D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ENH_ACCEPT_ESCO_CONNECTION (0x003E | HCI_GRP_LINK_CONTROL_CMDS)
+
+/* ConnectionLess Broadcast */
+#define HCI_TRUNCATED_PAGE (0x003F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_TRUNCATED_PAGE_CANCEL (0x0040 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CLB (0x0041 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_CLB (0x0042 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_START_SYNC_TRAIN (0x0043 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RECEIVE_SYNC_TRAIN (0x0044 | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_LINK_CTRL_CMDS_FIRST HCI_INQUIRY
+#define HCI_LINK_CTRL_CMDS_LAST HCI_RECEIVE_SYNC_TRAIN
+
+/* Commands of HCI_GRP_LINK_POLICY_CMDS */
+#define HCI_HOLD_MODE (0x0001 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_MODE (0x0003 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_SNIFF_MODE (0x0004 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_PARK_MODE (0x0005 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_PARK_MODE (0x0006 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_QOS_SETUP (0x0007 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_ROLE_DISCOVERY (0x0009 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SWITCH_ROLE (0x000B | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_POLICY_SETTINGS (0x000C | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_POLICY_SETTINGS (0x000D | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_DEF_POLICY_SETTINGS (0x000E | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_DEF_POLICY_SETTINGS (0x000F | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_FLOW_SPECIFICATION (0x0010 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_SUB_RATE (0x0011 | HCI_GRP_LINK_POLICY_CMDS)
+
+#define HCI_LINK_POLICY_CMDS_FIRST HCI_HOLD_MODE
+#define HCI_LINK_POLICY_CMDS_LAST HCI_SNIFF_SUB_RATE
+
+/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
+#define HCI_SET_EVENT_MASK (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_FILTER (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_FLUSH (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PIN_TYPE (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PIN_TYPE (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CREATE_NEW_UNIT_KEY (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_GET_MWS_TRANS_LAYER_CFG (0x000C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_STORED_LINK_KEY (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_STORED_LINK_KEY (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_STORED_LINK_KEY (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CHANGE_LOCAL_NAME (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_NAME (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CONN_ACCEPT_TOUT (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CONN_ACCEPT_TOUT (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGE_TOUT (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGE_TOUT (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCAN_ENABLE (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCAN_ENABLE (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_CFG (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_CFG (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRYSCAN_CFG (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRYSCAN_CFG (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTHENTICATION_ENABLE \
+ (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTHENTICATION_ENABLE \
+ (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ENCRYPTION_MODE (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ENCRYPTION_MODE (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CLASS_OF_DEVICE (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLASS_OF_DEVICE (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_VOICE_SETTINGS (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_VOICE_SETTINGS (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTO_FLUSH_TOUT (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTO_FLUSH_TOUT (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_BCAST_REXMITS (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_NUM_BCAST_REXMITS (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_HOLD_MODE_ACTIVITY (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_HOLD_MODE_ACTIVITY (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_TRANSMIT_POWER_LEVEL (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCO_FLOW_CTRL_ENABLE (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE \
+ (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_HC_TO_HOST_FLOW_CTRL (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_BUFFER_SIZE (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_NUM_PACKETS_DONE (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LINK_SUPER_TOUT (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LINK_SUPER_TOUT (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_SUPPORTED_IAC (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CURRENT_IAC_LAP (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CURRENT_IAC_LAP (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_PERIOD_MODE (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_PERIOD_MODE \
+ (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_MODE (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_MODE (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_AFH_CHANNELS (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_INQSCAN_TYPE (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQSCAN_TYPE (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRY_MODE (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRY_MODE (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_TYPE (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_TYPE (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AFH_ASSESSMENT_MODE (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AFH_ASSESSMENT_MODE (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_EXT_INQ_RESPONSE (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_EXT_INQ_RESPONSE (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_REFRESH_ENCRYPTION_KEY (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SIMPLE_PAIRING_MODE (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SIMPLE_PAIRING_MODE (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_OOB_DATA (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQ_TX_POWER_LEVEL (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQ_TX_POWER_LEVEL (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ERRONEOUS_DATA_RPT (0x005A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ERRONEOUS_DATA_RPT (0x005B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_ENHANCED_FLUSH (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SEND_KEYPRESS_NOTIF (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+/* AMP HCI */
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT \
+ (0x0061 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT \
+ (0x0062 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_MASK_PAGE_2 (0x0063 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCATION_DATA (0x0064 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LOCATION_DATA (0x0065 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_FLOW_CONTROL_MODE (0x0066 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_FLOW_CONTROL_MODE (0x0067 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_BE_FLUSH_TOUT (0x0069 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_BE_FLUSH_TOUT (0x006A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+/* 802.11 only */
+#define HCI_SHORT_RANGE_MODE (0x006B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LE_HOST_SUPPORT (0x006C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LE_HOST_SUPPORT (0x006D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+/* MWS coexistence */
+#define HCI_SET_MWS_CHANNEL_PARAMETERS \
+ (0x006E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION \
+ (0x006F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SIGNALING (0x0070 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_TRANSPORT_LAYER (0x0071 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE \
+ (0x0072 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_MWS_PATTERN_CONFIGURATION \
+ (0x0073 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+/* Connectionless Broadcast */
+#define HCI_SET_RESERVED_LT_ADDR (0x0074 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_RESERVED_LT_ADDR (0x0075 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLB_DATA (0x0076 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SYNC_TRAIN_PARAM (0x0077 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SYNC_TRAIN_PARAM (0x0078 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_SECURE_CONNS_SUPPORT (0x0079 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SECURE_CONNS_SUPPORT \
+ (0x007A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CONT_BASEBAND_CMDS_FIRST HCI_SET_EVENT_MASK
+#define HCI_CONT_BASEBAND_CMDS_LAST HCI_READ_SYNC_TRAIN_PARAM
+
+/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */
+#define HCI_READ_LOCAL_VERSION_INFO (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CMDS (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_FEATURES (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_EXT_FEATURES (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BUFFER_SIZE (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_COUNTRY_CODE (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BD_ADDR (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_DATA_BLOCK_SIZE (0x000A | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CODECS (0x000B | HCI_GRP_INFORMATIONAL_PARAMS)
+
+#define HCI_INFORMATIONAL_CMDS_FIRST HCI_READ_LOCAL_VERSION_INFO
+#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_LOCAL_SUPPORTED_CODECS
+
+/* Commands of HCI_GRP_STATUS_PARAMS group */
+#define HCI_READ_FAILED_CONTACT_COUNT (0x0001 | HCI_GRP_STATUS_PARAMS)
+#define HCI_RESET_FAILED_CONTACT_COUNT (0x0002 | HCI_GRP_STATUS_PARAMS)
+#define HCI_GET_LINK_QUALITY (0x0003 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_RSSI (0x0005 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_AFH_CH_MAP (0x0006 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_CLOCK (0x0007 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_ENCR_KEY_SIZE (0x0008 | HCI_GRP_STATUS_PARAMS)
+
+/* AMP HCI */
+#define HCI_READ_LOCAL_AMP_INFO (0x0009 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_LOCAL_AMP_ASSOC (0x000A | HCI_GRP_STATUS_PARAMS)
+#define HCI_WRITE_REMOTE_AMP_ASSOC (0x000B | HCI_GRP_STATUS_PARAMS)
+
+#define HCI_STATUS_PARAMS_CMDS_FIRST HCI_READ_FAILED_CONTACT_COUNT
+#define HCI_STATUS_PARAMS_CMDS_LAST HCI_WRITE_REMOTE_AMP_ASSOC
+
+/* Commands of HCI_GRP_TESTING_CMDS group */
+#define HCI_READ_LOOPBACK_MODE (0x0001 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_LOOPBACK_MODE (0x0002 | HCI_GRP_TESTING_CMDS)
+#define HCI_ENABLE_DEV_UNDER_TEST_MODE (0x0003 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE (0x0004 | HCI_GRP_TESTING_CMDS)
+
+/* AMP HCI */
+#define HCI_ENABLE_AMP_RCVR_REPORTS (0x0007 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST_END (0x0008 | HCI_GRP_TESTING_CMDS)
+#define HCI_AMP_TEST (0x0009 | HCI_GRP_TESTING_CMDS)
+
+#define HCI_TESTING_CMDS_FIRST HCI_READ_LOOPBACK_MODE
+#define HCI_TESTING_CMDS_LAST HCI_AMP_TEST
+
+#define HCI_VENDOR_CMDS_FIRST 0x0001
+#define HCI_VENDOR_CMDS_LAST 0xFFFF
+#define HCI_VSC_MULTI_AV_HANDLE 0x0AAA
+#define HCI_VSC_BURST_MODE_HANDLE 0x0BBB
+
+/* BLE HCI */
+#define HCI_GRP_BLE_CMDS (0x08 << 10)
+/* Commands of BLE Controller setup and configuration */
+#define HCI_BLE_SET_EVENT_MASK (0x0001 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_BUFFER_SIZE (0x0002 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_LOCAL_SPT_FEAT (0x0003 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_LOCAL_SPT_FEAT (0x0004 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_RANDOM_ADDR (0x0005 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_ADV_CHNL_TX_POWER (0x0007 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_RSP_DATA (0x0009 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_PARAMS (0x000B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_SCAN_ENABLE (0x000C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_LL_CONN (0x000D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CREATE_CONN_CANCEL (0x000E | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_WHITE_LIST_SIZE (0x000F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_WHITE_LIST (0x0010 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ADD_WHITE_LIST (0x0011 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_REMOVE_WHITE_LIST (0x0012 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_UPD_LL_CONN_PARAMS (0x0013 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_HOST_CHNL_CLASS (0x0014 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_CHNL_MAP (0x0015 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_REMOTE_FEAT (0x0016 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_ENCRYPT (0x0017 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RAND (0x0018 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_START_ENC (0x0019 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_REPLY (0x001A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_LTK_REQ_NEG_REPLY (0x001B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_SUPPORTED_STATES (0x001C | HCI_GRP_BLE_CMDS)
+/* 0x001D, 0x001E and 0x001F are reserved */
+#define HCI_BLE_RECEIVER_TEST (0x001D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_TRANSMITTER_TEST (0x001E | HCI_GRP_BLE_CMDS)
+/* BLE TEST COMMANDS */
+#define HCI_BLE_TEST_END (0x001F | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_REPLY (0x0020 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RC_PARAM_REQ_NEG_REPLY (0x0021 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_SET_DATA_LENGTH (0x0022 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_DEFAULT_DATA_LENGTH (0x0023 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_DEFAULT_DATA_LENGTH (0x0024 | HCI_GRP_BLE_CMDS)
+
+#define HCI_BLE_ADD_DEV_RESOLVING_LIST (0x0027 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_RM_DEV_RESOLVING_LIST (0x0028 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_CLEAR_RESOLVING_LIST (0x0029 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVING_LIST_SIZE (0x002A | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_PEER (0x002B | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_PHY (0x30 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_DEFAULT_PHY (0x31 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PHY (0x32 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_RANDOM_ADDRESS (0x35 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_PARAM (0x36 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_DATA (0x37 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_SCAN_RESP (0x38 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXT_ADVERTISING_ENABLE (0x39 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH (0x003A | HCI_GRP_BLE_CMDS)
+#define HCI_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS \
+ (0x003B | HCI_GRP_BLE_CMDS)
+#define HCI_LE_REMOVE_ADVERTISING_SET (0x003C | HCI_GRP_BLE_CMDS)
+#define HCI_LE_CLEAR_ADVERTISING_SETS (0x003D | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_PARAM (0x003E | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_DATA (0x003F | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_PERIODIC_ADVERTISING_ENABLE (0x0040 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_PARAMETERS (0x0041 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_SET_EXTENDED_SCAN_ENABLE (0x0042 | HCI_GRP_BLE_CMDS)
+#define HCI_LE_EXTENDED_CREATE_CONNECTION (0x0043 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
+
+/* LE Get Vendor Capabilities Command OCF */
+#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Multi adv OCF */
+#define HCI_BLE_MULTI_ADV_OCF (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Batch scan OCF */
+#define HCI_BLE_BATCH_SCAN_OCF (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* ADV filter OCF */
+#define HCI_BLE_ADV_FILTER_OCF (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Tracking OCF */
+#define HCI_BLE_TRACK_ADV_OCF (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Energy info OCF */
+#define HCI_BLE_ENERGY_INFO_OCF (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Extended BLE Scan parameters OCF */
+#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF (0x015A | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Controller debug info OCF */
+#define HCI_CONTROLLER_DEBUG_INFO_OCF (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+
+/* subcode for multi adv feature */
+#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
+#define BTM_BLE_MULTI_ADV_WRITE_ADV_DATA 0x02
+#define BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA 0x03
+#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR 0x04
+#define BTM_BLE_MULTI_ADV_ENB 0x05
+
+/* multi adv VSE subcode */
+/* multi adv instance state change */
+#define HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG 0x55
+
+/* subcode for batch scan feature */
+#define BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE 0x01
+#define BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM 0x02
+#define BTM_BLE_BATCH_SCAN_SET_PARAMS 0x03
+#define BTM_BLE_BATCH_SCAN_READ_RESULTS 0x04
+
+/* batch scan VSE subcode */
+#define HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT 0x54 /* Threshold event */
+
+/* tracking sub event */
+#define HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT 0x56 /* Tracking event */
+
+/* debug info sub event */
+#define HCI_VSE_SUBCODE_DEBUG_INFO_SUB_EVT 0x57
+
+/* LE supported states definition */
+#define HCI_LE_ADV_STATE 0x00000001
+#define HCI_LE_SCAN_STATE 0x00000002
+#define HCI_LE_INIT_STATE 0x00000004
+#define HCI_LE_CONN_SL_STATE 0x00000008
+#define HCI_LE_ADV_SCAN_STATE 0x00000010
+#define HCI_LE_ADV_INIT_STATE 0x00000020
+#define HCI_LE_ADV_MA_STATE 0x00000040
+#define HCI_LE_ADV_SL_STATE 0x00000080
+#define HCI_LE_SCAN_INIT_STATE 0x00000100
+#define HCI_LE_SCAN_MA_STATE 0x00000200
+#define HCI_LE_SCAN_SL_STATE 0x00000400
+#define HCI_LE_INIT_MA_STATE 0x00000800
+
+/* LE Supported States */
+/* Non Connectable Adv state is supported. 0x0000000000000001 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK 0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF 0
+#define HCI_LE_STATES_NON_CONN_ADV_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_MASK)
+
+/* Scanneable Connectable Adv state is supported. 0x0000000000000002 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASK 0x02
+#define HCI_SUPP_LE_STATESSCAN_ADV_OFF 0
+#define HCI_LE_STATES_SCAN_ADV_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATESSCAN_ADV_OFF] & HCI_SUPP_LE_STATES_SCAN_ADV_MASK)
+
+/* Connectable Adv state is supported. 0x0000000000000004 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASK 0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_OFF 0
+#define HCI_LE_STATES_CONN_ADV_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_OFF] & HCI_SUPP_LE_STATES_CONN_ADV_MASK)
+
+/* Hi duty Cycle Directed Adv state is supported. 0x0000000000000008 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK 0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF 0
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_OFF] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASK)
+
+/* Passive Scan state is supported. 0x0000000000000010 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASK 0x10
+#define HCI_SUPP_LE_STATES_PASS_SCAN_OFF 0
+#define HCI_LE_STATES_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_OFF] & HCI_SUPP_LE_STATES_PASS_SCAN_MASK)
+
+/* Active Scan state is supported. 0x0000000000000020 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK 0x20
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF 0
+#define HCI_LE_STATES_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASK)
+
+/* Initiating state is supported. 0x0000000000000040 (or connection state in
+ * master role is also supported) */
+#define HCI_SUPP_LE_STATES_INIT_MASK 0x40
+#define HCI_SUPP_LE_STATES_INIT_OFF 0
+#define HCI_LE_STATES_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_INIT_OFF] & HCI_SUPP_LE_STATES_INIT_MASK)
+
+/* connection state in slave role is also supported. 0x0000000000000080 */
+#define HCI_SUPP_LE_STATES_SLAVE_MASK 0x80
+#define HCI_SUPP_LE_STATES_SLAVE_OFF 0
+#define HCI_LE_STATES_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SLAVE_OFF] & HCI_SUPP_LE_STATES_SLAVE_MASK)
+
+/* Non Connectable Adv state and Passive Scanning State combination is
+ * supported. 0x0000000000000100 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK 0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF 1
+#define HCI_LE_STATES_NON_CONN_ADV_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_PASS_SCAN_MASK)
+
+/* Scannable Adv state and Passive Scanning State combination is supported.
+ * 0x0000000000000200 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK 0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF 1
+#define HCI_LE_STATES_SCAN_ADV_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_SCAN_ADV_PASS_SCAN_MASK)
+
+/* Connectable Adv state and Passive Scanning State combination is supported.
+ * 0x0000000000000400 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK 0x04
+#define HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF 1
+#define HCI_LE_STATES_CONN_ADV_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_CONN_ADV_PASS_SCAN_MASK)
+
+/* High Duty Cycl Directed ADv and Passive Scanning State combination is
+ * supported. 0x0000000000000800 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK 0x08
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF 1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_MASK] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_PASS_SCAN_OFF)
+
+/* Non Connectable Adv state and Passive Scanning State combination is
+ * supported. 0x0000000000001000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK 0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF 1
+#define HCI_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/* Scannable Adv state and Active Scanning State combination is supported.
+ * 0x0000000000002000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK 0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF 1
+#define HCI_LE_STATES_SCAN_ADV_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_SCAN_ADV_ACTIVE_SCAN_MASK)
+
+/* Connectable Adv state and Active Scanning State combination is supported.
+ * 0x0000000000004000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK 0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF 1
+#define HCI_LE_STATES_CONN_ADV_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_CONN_ADV_ACTIVE_SCAN_MASK)
+
+/* High Duty Cycl Directed ADv and ACtive Scanning State combination is
+ * supported. 0x0000000000008000 */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK 0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF 1
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_MASK] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_ACTIVE_SCAN_OFF)
+
+/* Non-Connectable Adv state and Initiating State combination is supported.
+ * 0x0000000000010000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK 0x01
+#define HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF 2
+#define HCI_LE_STATES_NON_CONN_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_INIT_MASK)
+
+/* Scannable Adv state and Initiating State combination is supported.
+ * 0x0000000000020000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK 0x02
+#define HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF 2
+#define HCI_LE_STATES_SCAN_ADV_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_SCAN_ADV_INIT_MASK)
+
+/* Non-Connectable Adv state and Master Role combination is supported.
+ * 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK 0x04
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF 2
+#define HCI_LE_STATES_NON_CONN_ADV_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_MASTER_MASK)
+
+/* Scannable Adv state and Master Role combination is supported.
+ * 0x0000000000040000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK 0x08
+#define HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF 2
+#define HCI_LE_STATES_SCAN_ADV_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_SCAN_ADV_MASTER_MASK)
+
+/* Non-Connectable Adv and Slave Role combination is supported.
+ * 0x000000000100000 */
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK 0x10
+#define HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF 2
+#define HCI_LE_STATES_NON_CONN_ADV_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_NON_CONN_ADV_SLAVE_MASK)
+
+/* Scannable Adv and Slave Role combination is supported. 0x000000000200000 */
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK 0x20
+#define HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF 2
+#define HCI_LE_STATES_SCAN_ADV_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_SCAN_ADV_SLAVE_MASK)
+
+/* Passive Scan and Initiating State combination is supported.
+ * 0x000000000400000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK 0x40
+#define HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF 2
+#define HCI_LE_STATES_PASS_SCAN_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_PASS_SCAN_INIT_MASK)
+
+/* Active Scan and Initiating State combination is supported.
+ * 0x000000000800000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK 0x80
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF 2
+#define HCI_LE_STATES_ACTIVE_SCAN_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_INIT_MASK)
+
+/* Passive Scan and Master Role combination is supported. 0x000000001000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK 0x01
+#define HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF 3
+#define HCI_LE_STATES_PASS_SCAN_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_PASS_SCAN_MASTER_MASK)
+
+/* Active Scan and Master Role combination is supported. 0x000000002000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK 0x02
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF 3
+#define HCI_LE_STATES_ACTIVE_SCAN_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_MASTER_MASK)
+
+/* Passive Scan and Slave Role combination is supported. 0x000000004000000 */
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK 0x04
+#define HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF 3
+#define HCI_LE_STATES_PASS_SCAN_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_PASS_SCAN_SLAVE_MASK)
+
+/* Active Scan and Slave Role combination is supported. 0x000000008000000 */
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK 0x08
+#define HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF 3
+#define HCI_LE_STATES_ACTIVE_SCAN_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_ACTIVE_SCAN_SLAVE_MASK)
+
+/* Link Layer Topology Added States Combo */
+/* Initiating State and Master Role combination supported.
+ Master Role and Master Role combination is also supported. 0x0000000010000000
+ */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_MASK 0x10
+#define HCI_SUPP_LE_STATES_INIT_MASTER_OFF 3
+#define HCI_LE_STATES_INIT_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_INIT_MASTER_MASK)
+
+/* Low Duty Cycle Directed Advertising State . 0x0000000020000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASK 0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_OFF 3
+#define HCI_LE_STATES_LOW_DUTY_DIR_ADV_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_OFF] & \
+ HCI_SUPP_LE_STATES_LOW_DUTY_DIR_ADV_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Passive scan combination.
+ * 0x0000000040000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK 0x40
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF 3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_PASS_SCAN_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Active scan combination.
+ * 0x0000000080000000 */
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK 0x80
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF 3
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_OFF] & \
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_ACTIVE_SCAN_MASK)
+
+/* Connectable Advertising State and Initiating State combination supported.
+ * 0x0000000100000000 */
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK 0x01
+#define HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF 4
+#define HCI_LE_STATES_CONN_ADV_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_CONN_ADV_INIT_MASK)
+
+/* High Duty Cycle Directed Advertising State and Initiating State combination
+ * supported. */
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK 0x02
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF 4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_INIT_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Initiating State combination
+ * supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK 0x04
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF 4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_INIT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_OFF] & \
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_INIT_MASK)
+
+/* Connectable Advertising State and Master Role combination supported.*/
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK 0x08
+#define HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF 4
+#define HCI_LE_STATES_CONN_ADV_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_CONN_ADV_MASTER_MASK)
+
+/* High Duty Cycle Directed Advertising State and Master Role combination
+ * supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK 0x10
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF 4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Low Duty Cycle Directed Advertising State and Master Role combination
+ * supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK 0x20
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF 4
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_MASTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_OFF] & \
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_MASTER_MASK)
+
+/* Connectable Advertising State and Slave Role combination supported. */
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK 0x40
+#define HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF 4
+#define HCI_LE_STATES_CONN_ADV_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_CONN_ADV_SLAVE_MASK)
+
+/* High Duty Cycle Directed Advertising State and slave Role combination
+ * supported.*/
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK 0x80
+#define HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF 4
+#define HCI_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_HI_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Low Duty Cycle Directed Advertising State and slave Role combination
+ * supported.*/
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK 0x01
+#define HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF 5
+#define HCI_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_LO_DUTY_DIR_ADV_SLAVE_MASK)
+
+/* Initiating State and Slave Role combination supported.
+ Master Role and Slave Role combination also supported.
+ */
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK 0x02
+#define HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF 5
+#define HCI_LE_STATES_INIT_MASTER_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_OFF] & \
+ HCI_SUPP_LE_STATES_INIT_MASTER_SLAVE_MASK)
+
+/*
+ * Definitions for HCI Events
+*/
+#define HCI_INQUIRY_COMP_EVT 0x01
+#define HCI_INQUIRY_RESULT_EVT 0x02
+#define HCI_CONNECTION_COMP_EVT 0x03
+#define HCI_CONNECTION_REQUEST_EVT 0x04
+#define HCI_DISCONNECTION_COMP_EVT 0x05
+#define HCI_AUTHENTICATION_COMP_EVT 0x06
+#define HCI_RMT_NAME_REQUEST_COMP_EVT 0x07
+#define HCI_ENCRYPTION_CHANGE_EVT 0x08
+#define HCI_CHANGE_CONN_LINK_KEY_EVT 0x09
+#define HCI_MASTER_LINK_KEY_COMP_EVT 0x0A
+#define HCI_READ_RMT_FEATURES_COMP_EVT 0x0B
+#define HCI_READ_RMT_VERSION_COMP_EVT 0x0C
+#define HCI_QOS_SETUP_COMP_EVT 0x0D
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_HARDWARE_ERROR_EVT 0x10
+#define HCI_FLUSH_OCCURED_EVT 0x11
+#define HCI_ROLE_CHANGE_EVT 0x12
+#define HCI_NUM_COMPL_DATA_PKTS_EVT 0x13
+#define HCI_MODE_CHANGE_EVT 0x14
+#define HCI_RETURN_LINK_KEYS_EVT 0x15
+#define HCI_PIN_CODE_REQUEST_EVT 0x16
+#define HCI_LINK_KEY_REQUEST_EVT 0x17
+#define HCI_LINK_KEY_NOTIFICATION_EVT 0x18
+#define HCI_LOOPBACK_COMMAND_EVT 0x19
+#define HCI_DATA_BUF_OVERFLOW_EVT 0x1A
+#define HCI_MAX_SLOTS_CHANGED_EVT 0x1B
+#define HCI_READ_CLOCK_OFF_COMP_EVT 0x1C
+#define HCI_CONN_PKT_TYPE_CHANGE_EVT 0x1D
+#define HCI_QOS_VIOLATION_EVT 0x1E
+#define HCI_PAGE_SCAN_MODE_CHANGE_EVT 0x1F
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT 0x20
+#define HCI_FLOW_SPECIFICATION_COMP_EVT 0x21
+#define HCI_INQUIRY_RSSI_RESULT_EVT 0x22
+#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT 0x23
+#define HCI_ESCO_CONNECTION_COMP_EVT 0x2C
+#define HCI_ESCO_CONNECTION_CHANGED_EVT 0x2D
+#define HCI_SNIFF_SUB_RATE_EVT 0x2E
+#define HCI_EXTENDED_INQUIRY_RESULT_EVT 0x2F
+#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT 0x30
+#define HCI_IO_CAPABILITY_REQUEST_EVT 0x31
+#define HCI_IO_CAPABILITY_RESPONSE_EVT 0x32
+#define HCI_USER_CONFIRMATION_REQUEST_EVT 0x33
+#define HCI_USER_PASSKEY_REQUEST_EVT 0x34
+#define HCI_REMOTE_OOB_DATA_REQUEST_EVT 0x35
+#define HCI_SIMPLE_PAIRING_COMPLETE_EVT 0x36
+#define HCI_LINK_SUPER_TOUT_CHANGED_EVT 0x38
+#define HCI_ENHANCED_FLUSH_COMPLETE_EVT 0x39
+#define HCI_USER_PASSKEY_NOTIFY_EVT 0x3B
+#define HCI_KEYPRESS_NOTIFY_EVT 0x3C
+#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT 0x3D
+
+/*#define HCI_GENERIC_AMP_LINK_KEY_NOTIF_EVT 0x3E Removed from spec */
+#define HCI_PHYSICAL_LINK_COMP_EVT 0x40
+#define HCI_CHANNEL_SELECTED_EVT 0x41
+#define HCI_DISC_PHYSICAL_LINK_COMP_EVT 0x42
+#define HCI_PHY_LINK_LOSS_EARLY_WARNING_EVT 0x43
+#define HCI_PHY_LINK_RECOVERY_EVT 0x44
+#define HCI_LOGICAL_LINK_COMP_EVT 0x45
+#define HCI_DISC_LOGICAL_LINK_COMP_EVT 0x46
+#define HCI_FLOW_SPEC_MODIFY_COMP_EVT 0x47
+#define HCI_NUM_COMPL_DATA_BLOCKS_EVT 0x48
+#define HCI_SHORT_RANGE_MODE_COMPLETE_EVT 0x4C
+#define HCI_AMP_STATUS_CHANGE_EVT 0x4D
+#define HCI_SET_TRIGGERED_CLOCK_CAPTURE_EVT 0x4E
+
+/* ULP HCI Event */
+#define HCI_BLE_EVENT 0x3e
+/* ULP Event sub code */
+#define HCI_BLE_CONN_COMPLETE_EVT 0x01
+#define HCI_BLE_ADV_PKT_RPT_EVT 0x02
+#define HCI_BLE_LL_CONN_PARAM_UPD_EVT 0x03
+#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT 0x04
+#define HCI_BLE_LTK_REQ_EVT 0x05
+#define HCI_BLE_RC_PARAM_REQ_EVT 0x06
+#define HCI_BLE_DATA_LENGTH_CHANGE_EVT 0x07
+#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT 0x0a
+#define HCI_BLE_DIRECT_ADV_EVT 0x0b
+#define HCI_LE_PHY_UPDATE_COMPLETE_EVT 0x0C
+#define HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT 0x0D
+#define HCI_LE_ADVERTISING_SET_TERMINATED_EVT 0x12
+
+/* Definitions for LE Channel Map */
+#define HCI_BLE_CHNL_MAP_SIZE 5
+
+#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */
+#define HCI_NAP_TRACE_EVT \
+ 0xFF /* was define 0xFE, 0xFD, change to 0xFF \
+ because conflict w/ TCI_EVT and per \
+ specification compliant */
+
+/*
+ * Defentions for HCI Error Codes that are past in the events
+*/
+#define HCI_SUCCESS 0x00
+#define HCI_PENDING 0x00
+#define HCI_ERR_ILLEGAL_COMMAND 0x01
+#define HCI_ERR_NO_CONNECTION 0x02
+#define HCI_ERR_HW_FAILURE 0x03
+#define HCI_ERR_PAGE_TIMEOUT 0x04
+#define HCI_ERR_AUTH_FAILURE 0x05
+#define HCI_ERR_KEY_MISSING 0x06
+#define HCI_ERR_MEMORY_FULL 0x07
+#define HCI_ERR_CONNECTION_TOUT 0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
+#define HCI_ERR_MAX_NUM_OF_SCOS 0x0A
+#define HCI_ERR_CONNECTION_EXISTS 0x0B
+#define HCI_ERR_COMMAND_DISALLOWED 0x0C
+#define HCI_ERR_HOST_REJECT_RESOURCES 0x0D
+#define HCI_ERR_HOST_REJECT_SECURITY 0x0E
+#define HCI_ERR_HOST_REJECT_DEVICE 0x0F
+#define HCI_ERR_HOST_TIMEOUT 0x10
+#define HCI_ERR_UNSUPPORTED_VALUE 0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
+#define HCI_ERR_PEER_USER 0x13
+#define HCI_ERR_PEER_LOW_RESOURCES 0x14
+#define HCI_ERR_PEER_POWER_OFF 0x15
+#define HCI_ERR_CONN_CAUSE_LOCAL_HOST 0x16
+#define HCI_ERR_REPEATED_ATTEMPTS 0x17
+#define HCI_ERR_PAIRING_NOT_ALLOWED 0x18
+#define HCI_ERR_UNKNOWN_LMP_PDU 0x19
+#define HCI_ERR_UNSUPPORTED_REM_FEATURE 0x1A
+#define HCI_ERR_SCO_OFFSET_REJECTED 0x1B
+#define HCI_ERR_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_ERR_SCO_AIR_MODE 0x1D
+#define HCI_ERR_INVALID_LMP_PARAM 0x1E
+#define HCI_ERR_UNSPECIFIED 0x1F
+#define HCI_ERR_UNSUPPORTED_LMP_FEATURE 0x20
+#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_ERR_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_ERR_LMP_ERR_TRANS_COLLISION 0x23
+#define HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_ERR_UNIT_KEY_USED 0x26
+#define HCI_ERR_QOS_NOT_SUPPORTED 0x27
+#define HCI_ERR_INSTANT_PASSED 0x28
+#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29
+#define HCI_ERR_DIFF_TRANSACTION_COLLISION 0x2A
+#define HCI_ERR_UNDEFINED_0x2B 0x2B
+#define HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2C
+#define HCI_ERR_QOS_REJECTED 0x2D
+#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED 0x2E
+#define HCI_ERR_INSUFFCIENT_SECURITY 0x2F
+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
+#define HCI_ERR_UNDEFINED_0x31 0x31
+#define HCI_ERR_ROLE_SWITCH_PENDING 0x32
+#define HCI_ERR_UNDEFINED_0x33 0x33
+#define HCI_ERR_RESERVED_SLOT_VIOLATION 0x34
+#define HCI_ERR_ROLE_SWITCH_FAILED 0x35
+#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE 0x36
+#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED 0x37
+#define HCI_ERR_HOST_BUSY_PAIRING 0x38
+#define HCI_ERR_REJ_NO_SUITABLE_CHANNEL 0x39
+#define HCI_ERR_CONTROLLER_BUSY 0x3A
+#define HCI_ERR_UNACCEPT_CONN_INTERVAL 0x3B
+#define HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT 0x3C
+#define HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE 0x3D
+#define HCI_ERR_CONN_FAILED_ESTABLISHMENT 0x3E
+#define HCI_ERR_MAC_CONNECTION_FAILED 0x3F
+
+/* ConnectionLess Broadcast errors */
+#define HCI_ERR_LT_ADDR_ALREADY_IN_USE 0x40
+#define HCI_ERR_LT_ADDR_NOT_ALLOCATED 0x41
+#define HCI_ERR_CLB_NOT_ENABLED 0x42
+#define HCI_ERR_CLB_DATA_TOO_BIG 0x43
+
+#define HCI_ERR_MAX_ERR 0x43
+
+#define HCI_HINT_TO_RECREATE_AMP_PHYS_LINK 0xFF
+
+/*
+ * Definitions for HCI enable event
+*/
+#define HCI_INQUIRY_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00000001)
+#define HCI_INQUIRY_RESULT_EV(p) (*((uint32_t*)(p)) & 0x00000002)
+#define HCI_CONNECTION_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00000004)
+#define HCI_CONNECTION_REQUEST_EV(p) (*((uint32_t*)(p)) & 0x00000008)
+#define HCI_DISCONNECTION_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00000010)
+#define HCI_AUTHENTICATION_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00000020)
+#define HCI_RMT_NAME_REQUEST_COMPL_EV(p) (*((uint32_t*)(p)) & 0x00000040)
+#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p) (*((uint32_t*)(p)) & 0x00000080)
+#define HCI_CHANGE_CONN_LINK_KEY_EV(p) (*((uint32_t*)(p)) & 0x00000100)
+#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00000200)
+#define HCI_READ_RMT_FEATURES_COMPL_EV(p) (*((uint32_t*)(p)) & 0x00000400)
+#define HCI_READ_RMT_VERSION_COMPL_EV(p) (*((uint32_t*)(p)) & 0x00000800)
+#define HCI_QOS_SETUP_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00001000)
+#define HCI_COMMAND_COMPLETE_EV(p) (*((uint32_t*)(p)) & 0x00002000)
+#define HCI_COMMAND_STATUS_EV(p) (*((uint32_t*)(p)) & 0x00004000)
+#define HCI_HARDWARE_ERROR_EV(p) (*((uint32_t*)(p)) & 0x00008000)
+#define HCI_FLASH_OCCURED_EV(p) (*((uint32_t*)(p)) & 0x00010000)
+#define HCI_ROLE_CHANGE_EV(p) (*((uint32_t*)(p)) & 0x00020000)
+#define HCI_NUM_COMPLETED_PKTS_EV(p) (*((uint32_t*)(p)) & 0x00040000)
+#define HCI_MODE_CHANGE_EV(p) (*((uint32_t*)(p)) & 0x00080000)
+#define HCI_RETURN_LINK_KEYS_EV(p) (*((uint32_t*)(p)) & 0x00100000)
+#define HCI_PIN_CODE_REQUEST_EV(p) (*((uint32_t*)(p)) & 0x00200000)
+#define HCI_LINK_KEY_REQUEST_EV(p) (*((uint32_t*)(p)) & 0x00400000)
+#define HCI_LINK_KEY_NOTIFICATION_EV(p) (*((uint32_t*)(p)) & 0x00800000)
+#define HCI_LOOPBACK_COMMAND_EV(p) (*((uint32_t*)(p)) & 0x01000000)
+#define HCI_DATA_BUF_OVERFLOW_EV(p) (*((uint32_t*)(p)) & 0x02000000)
+#define HCI_MAX_SLOTS_CHANGE_EV(p) (*((uint32_t*)(p)) & 0x04000000)
+#define HCI_READ_CLOCK_OFFSET_COMP_EV(p) (*((uint32_t*)(p)) & 0x08000000)
+#define HCI_CONN_PKT_TYPE_CHANGED_EV(p) (*((uint32_t*)(p)) & 0x10000000)
+#define HCI_QOS_VIOLATION_EV(p) (*((uint32_t*)(p)) & 0x20000000)
+#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p) (*((uint32_t*)(p)) & 0x40000000)
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p) (*((uint32_t*)(p)) & 0x80000000)
+
+/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */
+#define HCI_DEFAULT_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_DEFAULT_EVENT_MASK_1 0x00001FFF
+
+/* the event mask for 2.0 + EDR and later (includes Lisbon events) */
+#define HCI_LISBON_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_LISBON_EVENT_MASK_1 0x1DBFFFFF
+#define HCI_LISBON_EVENT_MASK \
+ { 0x0D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+#define HCI_LISBON_EVENT_MASK_EXT \
+ { 0x1D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+#define HCI_DUMO_EVENT_MASK_EXT \
+ { 0x3D, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+/* 0x00001FFF FFFFFFFF Default - no Lisbon events
+ 0x00000800 00000000 Synchronous Connection Complete Event
+ 0x00001000 00000000 Synchronous Connection Changed Event
+ 0x00002000 00000000 Sniff Subrate Event
+ 0x00004000 00000000 Extended Inquiry Result Event
+ 0x00008000 00000000 Encryption Key Refresh Complete Event
+ 0x00010000 00000000 IO Capability Request Event
+ 0x00020000 00000000 IO Capability Response Event
+ 0x00040000 00000000 User Confirmation Request Event
+ 0x00080000 00000000 User Passkey Request Event
+ 0x00100000 00000000 Remote OOB Data Request Event
+ 0x00200000 00000000 Simple Pairing Complete Event
+ 0x00400000 00000000 Generic AMP Link Key Notification Event
+ 0x00800000 00000000 Link Supervision Timeout Changed Event
+ 0x01000000 00000000 Enhanced Flush Complete Event
+ 0x04000000 00000000 User Passkey Notification Event
+ 0x08000000 00000000 Keypress Notification Event
+ 0x10000000 00000000 Remote Host Supported Features Notification Event
+ 0x20000000 00000000 LE Meta Event
+ */
+
+/* the event mask for AMP controllers */
+#define HCI_AMP_EVENT_MASK_3_0 "\x00\x00\x00\x00\x00\x00\x3F\xFF"
+
+/* 0x0000000000000000 No events specified (default)
+ 0x0000000000000001 Physical Link Complete Event
+ 0x0000000000000002 Channel Selected Event
+ 0x0000000000000004 Disconnection Physical Link Event
+ 0x0000000000000008 Physical Link Loss Early Warning Event
+ 0x0000000000000010 Physical Link Recovery Event
+ 0x0000000000000020 Logical Link Complete Event
+ 0x0000000000000040 Disconnection Logical Link Complete Event
+ 0x0000000000000080 Flow Spec Modify Complete Event
+ 0x0000000000000100 Number of Completed Data Blocks Event
+ 0x0000000000000200 AMP Start Test Event
+ 0x0000000000000400 AMP Test End Event
+ 0x0000000000000800 AMP Receiver Report Event
+ 0x0000000000001000 Short Range Mode Change Complete Event
+ 0x0000000000002000 AMP Status Change Event
+*/
+
+/* the event mask page 2 (CLB + CSA4) for BR/EDR controller */
+#define HCI_PAGE_2_EVENT_MASK "\x00\x00\x00\x00\x00\x7F\xC0\x00"
+/* 0x0000000000004000 Triggered Clock Capture Event
+ 0x0000000000008000 Sync Train Complete Event
+ 0x0000000000010000 Sync Train Received Event
+ 0x0000000000020000 Connectionless Broadcast Receive Event
+ 0x0000000000040000 Connectionless Broadcast Timeout Event
+ 0x0000000000080000 Truncated Page Complete Event
+ 0x0000000000100000 Salve Page Response Timeout Event
+ 0x0000000000200000 Connectionless Broadcast Channel Map Change Event
+ 0x0000000000400000 Inquiry Response Notification Event
+*/
+#if (BLE_PRIVACY_SPT == TRUE)
+/* BLE event mask */
+#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x07\xff"
+#else
+#define HCI_BLE_EVENT_MASK_DEF "\x00\x00\x00\x00\x00\x00\x00\x7f"
+#endif
+/*
+ * Definitions for packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_PKT_TYPES_MASK_NO_2_DH1 0x0002
+#define HCI_PKT_TYPES_MASK_NO_3_DH1 0x0004
+#define HCI_PKT_TYPES_MASK_DM1 0x0008
+#define HCI_PKT_TYPES_MASK_DH1 0x0010
+#define HCI_PKT_TYPES_MASK_HV1 0x0020
+#define HCI_PKT_TYPES_MASK_HV2 0x0040
+#define HCI_PKT_TYPES_MASK_HV3 0x0080
+#define HCI_PKT_TYPES_MASK_NO_2_DH3 0x0100
+#define HCI_PKT_TYPES_MASK_NO_3_DH3 0x0200
+#define HCI_PKT_TYPES_MASK_DM3 0x0400
+#define HCI_PKT_TYPES_MASK_DH3 0x0800
+#define HCI_PKT_TYPES_MASK_NO_2_DH5 0x1000
+#define HCI_PKT_TYPES_MASK_NO_3_DH5 0x2000
+#define HCI_PKT_TYPES_MASK_DM5 0x4000
+#define HCI_PKT_TYPES_MASK_DH5 0x8000
+
+/* Packet type should be one of valid but at least one should be specified */
+#define HCI_VALID_SCO_PKT_TYPE(t) \
+ (((((t) & \
+ ~(HCI_PKT_TYPES_MASK_HV1 | HCI_PKT_TYPES_MASK_HV2 | \
+ HCI_PKT_TYPES_MASK_HV3)) == 0)) && \
+ ((t) != 0))
+
+/* Packet type should not be invalid and at least one should be specified */
+#define HCI_VALID_ACL_PKT_TYPE(t) \
+ (((((t) & \
+ ~(HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 | \
+ HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 | \
+ HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH1 | HCI_PKT_TYPES_MASK_NO_3_DH1 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH3 | HCI_PKT_TYPES_MASK_NO_3_DH3 | \
+ HCI_PKT_TYPES_MASK_NO_2_DH5 | HCI_PKT_TYPES_MASK_NO_3_DH5)) == 0)) && \
+ (((t) & (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 | \
+ HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 | \
+ HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5)) != 0))
+
+/* Packet type should be one of valid but at least one should be specified for
+ * 1.2 */
+#define HCI_VALID_ESCO_PKT_TYPE(t) \
+ (((((t) & \
+ ~(HCI_ESCO_PKT_TYPES_MASK_EV3 | HCI_ESCO_PKT_TYPES_MASK_EV4 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) && \
+ ((t) != 0)) /* Packet type should be one of valid but at least one should \
+ be specified */
+
+#define HCI_VALID_ESCO_SCOPKT_TYPE(t) \
+ (((((t) & \
+ ~(ESCO_PKT_TYPES_MASK_HV1 | HCI_ESCO_PKT_TYPES_MASK_HV2 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0)) && \
+ ((t) != 0))
+
+#define HCI_VALID_SCO_ALL_PKT_TYPE(t) \
+ (((((t) & \
+ ~(ESCO_PKT_TYPES_MASK_HV1 | HCI_ESCO_PKT_TYPES_MASK_HV2 | \
+ HCI_ESCO_PKT_TYPES_MASK_HV3 | HCI_ESCO_PKT_TYPES_MASK_EV3 | \
+ HCI_ESCO_PKT_TYPES_MASK_EV4 | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) && \
+ ((t) != 0))
+
+/*
+ * Define parameters to allow role switch during create connection
+*/
+#define HCI_CR_CONN_NOT_ALLOW_SWITCH 0x00
+#define HCI_CR_CONN_ALLOW_SWITCH 0x01
+
+/*
+ * Hold Mode command destination
+*/
+#define HOLD_MODE_DEST_LOCAL_DEVICE 0x00
+#define HOLD_MODE_DEST_RMT_DEVICE 0x01
+
+/*
+ * Definitions for different HCI parameters
+*/
+#define HCI_PER_INQ_MIN_MAX_PERIOD 0x0003
+#define HCI_PER_INQ_MAX_MAX_PERIOD 0xFFFF
+#define HCI_PER_INQ_MIN_MIN_PERIOD 0x0002
+#define HCI_PER_INQ_MAX_MIN_PERIOD 0xFFFE
+
+#define HCI_MAX_INQUIRY_LENGTH 0x30
+
+#define HCI_MIN_INQ_LAP 0x9E8B00
+#define HCI_MAX_INQ_LAP 0x9E8B3F
+
+/* HCI role defenitions */
+#define HCI_ROLE_MASTER 0x00
+#define HCI_ROLE_SLAVE 0x01
+#define HCI_ROLE_UNKNOWN 0xff
+
+/* HCI mode defenitions */
+#define HCI_MODE_ACTIVE 0x00
+#define HCI_MODE_HOLD 0x01
+#define HCI_MODE_SNIFF 0x02
+#define HCI_MODE_PARK 0x03
+
+/* HCI Flow Control Mode defenitions */
+#define HCI_PACKET_BASED_FC_MODE 0x00
+#define HCI_BLOCK_BASED_FC_MODE 0x01
+
+/* Define Packet types as requested by the Host */
+#define HCI_ACL_PKT_TYPE_NONE 0x0000
+#define HCI_ACL_PKT_TYPE_DM1 0x0008
+#define HCI_ACL_PKT_TYPE_DH1 0x0010
+#define HCI_ACL_PKT_TYPE_AUX1 0x0200
+#define HCI_ACL_PKT_TYPE_DM3 0x0400
+#define HCI_ACL_PKT_TYPE_DH3 0x0800
+#define HCI_ACL_PKT_TYPE_DM5 0x4000
+#define HCI_ACL_PKT_TYPE_DH5 0x8000
+
+/* Define key type in the Master Link Key command */
+#define HCI_USE_SEMI_PERMANENT_KEY 0x00
+#define HCI_USE_TEMPORARY_KEY 0x01
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_REP_MODE_R0 0x00
+#define HCI_PAGE_SCAN_REP_MODE_R1 0x01
+#define HCI_PAGE_SCAN_REP_MODE_R2 0x02
+
+/* Define limits for page scan repetition modes */
+#define HCI_PAGE_SCAN_R1_LIMIT 0x0800
+#define HCI_PAGE_SCAN_R2_LIMIT 0x1000
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_PER_MODE_P0 0x00
+#define HCI_PAGE_SCAN_PER_MODE_P1 0x01
+#define HCI_PAGE_SCAN_PER_MODE_P2 0x02
+
+/* Page scan modes */
+#define HCI_MANDATARY_PAGE_SCAN_MODE 0x00
+#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01
+#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02
+#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03
+
+/* Page and inquiry scan types */
+#define HCI_SCAN_TYPE_STANDARD 0x00
+#define HCI_SCAN_TYPE_INTERLACED 0x01 /* 1.2 devices or later */
+#define HCI_DEF_SCAN_TYPE HCI_SCAN_TYPE_STANDARD
+
+/* Definitions for quality of service service types */
+#define HCI_SERVICE_NO_TRAFFIC 0x00
+#define HCI_SERVICE_BEST_EFFORT 0x01
+#define HCI_SERVICE_GUARANTEED 0x02
+
+#define HCI_QOS_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+#define HCI_QOS_DELAY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for Flow Specification */
+#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for AFH Channel Map */
+#define HCI_AFH_CHANNEL_MAP_LEN 10
+
+/* Definitions for Extended Inquiry Response */
+#define HCI_EXT_INQ_RESPONSE_LEN 240
+#define HCI_EIR_FLAGS_TYPE BT_EIR_FLAGS_TYPE
+#define HCI_EIR_MORE_16BITS_UUID_TYPE BT_EIR_MORE_16BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE BT_EIR_COMPLETE_16BITS_UUID_TYPE
+#define HCI_EIR_MORE_32BITS_UUID_TYPE BT_EIR_MORE_32BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE BT_EIR_COMPLETE_32BITS_UUID_TYPE
+#define HCI_EIR_MORE_128BITS_UUID_TYPE BT_EIR_MORE_128BITS_UUID_TYPE
+#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE BT_EIR_COMPLETE_128BITS_UUID_TYPE
+#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE BT_EIR_SHORTENED_LOCAL_NAME_TYPE
+#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE BT_EIR_COMPLETE_LOCAL_NAME_TYPE
+#define HCI_EIR_TX_POWER_LEVEL_TYPE BT_EIR_TX_POWER_LEVEL_TYPE
+#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE BT_EIR_MANUFACTURER_SPECIFIC_TYPE
+#define HCI_EIR_SERVICE_DATA_TYPE BT_EIR_SERVICE_DATA_TYPE
+#define HCI_EIR_SERVICE_DATA_16BITS_UUID_TYPE \
+ BT_EIR_SERVICE_DATA_16BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_32BITS_UUID_TYPE \
+ BT_EIR_SERVICE_DATA_32BITS_UUID_TYPE
+#define HCI_EIR_SERVICE_DATA_128BITS_UUID_TYPE \
+ BT_EIR_SERVICE_DATA_128BITS_UUID_TYPE
+#define HCI_EIR_OOB_BD_ADDR_TYPE BT_EIR_OOB_BD_ADDR_TYPE
+#define HCI_EIR_OOB_COD_TYPE BT_EIR_OOB_COD_TYPE
+#define HCI_EIR_OOB_SSP_HASH_C_TYPE BT_EIR_OOB_SSP_HASH_C_TYPE
+#define HCI_EIR_OOB_SSP_RAND_R_TYPE BT_EIR_OOB_SSP_RAND_R_TYPE
+
+/* Definitions for Write Simple Pairing Mode */
+#define HCI_SP_MODE_UNDEFINED 0x00
+#define HCI_SP_MODE_ENABLED 0x01
+
+/* Definitions for Write Simple Pairing Debug Mode */
+#define HCI_SPD_MODE_DISABLED 0x00
+#define HCI_SPD_MODE_ENABLED 0x01
+
+/* Definitions for Write Secure Connections Host Support */
+#define HCI_SC_MODE_DISABLED 0x00
+#define HCI_SC_MODE_ENABLED 0x01
+
+/* Definitions for IO Capability Response/Command */
+#define HCI_IO_CAP_DISPLAY_ONLY 0x00
+#define HCI_IO_CAP_DISPLAY_YESNO 0x01
+#define HCI_IO_CAP_KEYBOARD_ONLY 0x02
+#define HCI_IO_CAP_NO_IO 0x03
+
+#define HCI_OOB_AUTH_DATA_NOT_PRESENT 0x00
+#define HCI_OOB_REM_AUTH_DATA_PRESENT 0x01
+
+#define HCI_MITM_PROTECT_NOT_REQUIRED 0x00
+#define HCI_MITM_PROTECT_REQUIRED 0x01
+
+/* Policy settings status */
+#define HCI_DISABLE_ALL_LM_MODES 0x0000
+#define HCI_ENABLE_MASTER_SLAVE_SWITCH 0x0001
+#define HCI_ENABLE_HOLD_MODE 0x0002
+#define HCI_ENABLE_SNIFF_MODE 0x0004
+#define HCI_ENABLE_PARK_MODE 0x0008
+
+/* By default allow switch, because host can not allow that */
+/* that until he created the connection */
+#define HCI_DEFAULT_POLICY_SETTINGS HCI_DISABLE_ALL_LM_MODES
+
+/* Filters that are sent in set filter command */
+#define HCI_FILTER_TYPE_CLEAR_ALL 0x00
+#define HCI_FILTER_INQUIRY_RESULT 0x01
+#define HCI_FILTER_CONNECTION_SETUP 0x02
+
+#define HCI_FILTER_COND_NEW_DEVICE 0x00
+#define HCI_FILTER_COND_DEVICE_CLASS 0x01
+#define HCI_FILTER_COND_BD_ADDR 0x02
+
+#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT 1
+/* role switch disabled */
+#define HCI_DO_AUTO_ACCEPT_CONNECT 2
+/* role switch enabled (1.1 errata 1115) */
+#define HCI_DO_AUTO_ACCEPT_CONNECT_RS 3
+
+/* Auto accept flags */
+#define HCI_AUTO_ACCEPT_OFF 0x00
+#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS 0x01
+#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS 0x02
+
+/* PIN type */
+#define HCI_PIN_TYPE_VARIABLE 0
+#define HCI_PIN_TYPE_FIXED 1
+
+/* Loopback Modes */
+#define HCI_LOOPBACK_MODE_DISABLED 0
+#define HCI_LOOPBACK_MODE_LOCAL 1
+#define HCI_LOOPBACK_MODE_REMOTE 2
+
+#define SLOTS_PER_10MS 16 /* 0.625 ms slots in a 10 ms tick */
+
+/* Maximum connection accept timeout in 0.625msec */
+#define HCI_MAX_CONN_ACCEPT_TOUT 0xB540 /* 29 sec */
+#define HCI_DEF_CONN_ACCEPT_TOUT 0x1F40 /* 5 sec */
+
+/* Page timeout is used in LC only and LC is counting down slots not using OS */
+#define HCI_DEFAULT_PAGE_TOUT 0x2000 /* 5.12 sec (in slots) */
+
+/* Scan enable flags */
+#define HCI_NO_SCAN_ENABLED 0x00
+#define HCI_INQUIRY_SCAN_ENABLED 0x01
+#define HCI_PAGE_SCAN_ENABLED 0x02
+
+/* Pagescan timer definitions in 0.625 ms */
+#define HCI_MIN_PAGESCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_INTERVAL 0x0800 /* 1.28 sec */
+
+/* Parameter for pagescan window is passed to LC and is kept in slots */
+#define HCI_MIN_PAGESCAN_WINDOW 0x11 /* 10.625 ms */
+#define HCI_MAX_PAGESCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Inquiryscan timer definitions in 0.625 ms */
+#define HCI_MIN_INQUIRYSCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */
+
+/* Parameter for inquiryscan window is passed to LC and is kept in slots */
+#define HCI_MIN_INQUIRYSCAN_WINDOW 0x11 /* 10.625 ms */
+#define HCI_MAX_INQUIRYSCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Encryption modes */
+#define HCI_ENCRYPT_MODE_DISABLED 0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01
+#define HCI_ENCRYPT_MODE_ALL 0x02
+
+/* Voice settings */
+#define HCI_INP_CODING_LINEAR 0x0000 /* 0000000000 */
+#define HCI_INP_CODING_U_LAW 0x0100 /* 0100000000 */
+#define HCI_INP_CODING_A_LAW 0x0200 /* 1000000000 */
+#define HCI_INP_CODING_MASK 0x0300 /* 1100000000 */
+
+#define HCI_INP_DATA_FMT_1S_COMPLEMENT 0x0000 /* 0000000000 */
+#define HCI_INP_DATA_FMT_2S_COMPLEMENT 0x0040 /* 0001000000 */
+#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 /* 0010000000 */
+#define HCI_INP_DATA_FMT_UNSIGNED 0x00c0 /* 0011000000 */
+#define HCI_INP_DATA_FMT_MASK 0x00c0 /* 0011000000 */
+
+#define HCI_INP_SAMPLE_SIZE_8BIT 0x0000 /* 0000000000 */
+#define HCI_INP_SAMPLE_SIZE_16BIT 0x0020 /* 0000100000 */
+#define HCI_INP_SAMPLE_SIZE_MASK 0x0020 /* 0000100000 */
+
+#define HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c /* 0000011100 */
+#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2
+
+#define HCI_AIR_CODING_FORMAT_CVSD 0x0000 /* 0000000000 */
+#define HCI_AIR_CODING_FORMAT_U_LAW 0x0001 /* 0000000001 */
+#define HCI_AIR_CODING_FORMAT_A_LAW 0x0002 /* 0000000010 */
+#define HCI_AIR_CODING_FORMAT_TRANSPNT 0x0003 /* 0000000011 */
+#define HCI_AIR_CODING_FORMAT_MASK 0x0003 /* 0000000011 */
+
+/* default 0001100000 */
+#define HCI_DEFAULT_VOICE_SETTINGS \
+ (HCI_INP_CODING_LINEAR | HCI_INP_DATA_FMT_2S_COMPLEMENT | \
+ HCI_INP_SAMPLE_SIZE_16BIT | HCI_AIR_CODING_FORMAT_CVSD)
+
+#define HCI_CVSD_SUPPORTED(x) \
+ (((x)&HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD)
+#define HCI_U_LAW_SUPPORTED(x) \
+ (((x)&HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW)
+#define HCI_A_LAW_SUPPORTED(x) \
+ (((x)&HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW)
+#define HCI_TRANSPNT_SUPPORTED(x) \
+ (((x)&HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT)
+
+/* Retransmit timer definitions in 0.625 */
+#define HCI_MAX_AUTO_FLUSH_TOUT 0x07FF
+#define HCI_DEFAULT_AUTO_FLUSH_TOUT 0 /* No auto flush */
+
+/* Broadcast retransmitions */
+#define HCI_DEFAULT_NUM_BCAST_RETRAN 1
+
+/* Define broadcast data types as passed in the hci data packet */
+#define HCI_DATA_POINT_TO_POINT 0x00
+#define HCI_DATA_ACTIVE_BCAST 0x01
+#define HCI_DATA_PICONET_BCAST 0x02
+
+/* Hold mode activity */
+#define HCI_MAINTAIN_CUR_POWER_STATE 0x00
+#define HCI_SUSPEND_PAGE_SCAN 0x01
+#define HCI_SUSPEND_INQUIRY_SCAN 0x02
+#define HCI_SUSPEND_PERIODIC_INQUIRIES 0x04
+
+/* Default Link Supervision timeoout */
+#define HCI_DEFAULT_INACT_TOUT 0x7D00 /* BR/EDR (20 seconds) */
+#define HCI_DEFAULT_AMP_INACT_TOUT 0x3E80 /* AMP (10 seconds) */
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT 0x00
+#define HCI_READ_MAXIMUM 0x01
+
+/* Link types for connection complete event */
+#define HCI_LINK_TYPE_SCO 0x00
+#define HCI_LINK_TYPE_ACL 0x01
+#define HCI_LINK_TYPE_ESCO 0x02
+
+/* Link Key Notification Event (Key Type) definitions */
+#define HCI_LKEY_TYPE_COMBINATION 0x00
+#define HCI_LKEY_TYPE_LOCAL_UNIT 0x01
+#define HCI_LKEY_TYPE_REMOTE_UNIT 0x02
+#define HCI_LKEY_TYPE_DEBUG_COMB 0x03
+#define HCI_LKEY_TYPE_UNAUTH_COMB 0x04
+#define HCI_LKEY_TYPE_AUTH_COMB 0x05
+#define HCI_LKEY_TYPE_CHANGED_COMB 0x06
+#define HCI_LKEY_TYPE_UNAUTH_COMB_P_256 0x07
+#define HCI_LKEY_TYPE_AUTH_COMB_P_256 0x08
+
+/* Internal definitions - not used over HCI */
+#define HCI_LKEY_TYPE_AMP_WIFI 0x80
+#define HCI_LKEY_TYPE_AMP_UWB 0x81
+#define HCI_LKEY_TYPE_UNKNOWN 0xff
+
+/* Read Local Version HCI Version return values (Command Complete Event) */
+#define HCI_VERSION_1_0B 0x00
+#define HCI_VERSION_1_1 0x01
+
+/* Define an invalid value for a handle */
+#define HCI_INVALID_HANDLE 0xFFFF
+
+/* Define max ammount of data in the HCI command */
+#define HCI_COMMAND_SIZE 255
+
+/* Define the preamble length for all HCI Commands.
+ * This is 2-bytes for opcode and 1 byte for length
+*/
+#define HCIC_PREAMBLE_SIZE 3
+
+/* Define the preamble length for all HCI Events
+ * This is 1-byte for opcode and 1 byte for length
+*/
+#define HCIE_PREAMBLE_SIZE 2
+#define HCI_SCO_PREAMBLE_SIZE 3
+#define HCI_DATA_PREAMBLE_SIZE 4
+
+/* local Bluetooth controller id for AMP HCI */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/* controller id types for AMP HCI */
+#define HCI_CONTROLLER_TYPE_BR_EDR 0
+#define HCI_CONTROLLER_TYPE_802_11 1
+#define HCI_CONTROLLER_TYPE_ECMA 2
+#define HCI_MAX_CONTROLLER_TYPES 3
+
+/* ConnectionLess Broadcast */
+#define HCI_CLB_DISABLE 0x00
+#define HCI_CLB_ENABLE 0x01
+
+/* ConnectionLess Broadcast Data fragment */
+#define HCI_CLB_FRAGMENT_CONT 0x00
+#define HCI_CLB_FRAGMENT_START 0x01
+#define HCI_CLB_FRAGMENT_END 0x02
+#define HCI_CLB_FRAGMENT_SINGLE 0x03
+
+/* AMP Controller Status codes
+*/
+#define HCI_AMP_CTRLR_PHYSICALLY_DOWN 0
+#define HCI_AMP_CTRLR_USABLE_BY_BT 1
+#define HCI_AMP_CTRLR_UNUSABLE_FOR_BT 2
+#define HCI_AMP_CTRLR_LOW_CAP_FOR_BT 3
+#define HCI_AMP_CTRLR_MED_CAP_FOR_BT 4
+#define HCI_AMP_CTRLR_HIGH_CAP_FOR_BT 5
+#define HCI_AMP_CTRLR_FULL_CAP_FOR_BT 6
+
+#define HCI_MAX_AMP_STATUS_TYPES 7
+
+/* Define the extended flow specification fields used by AMP */
+typedef struct {
+ uint8_t id;
+ uint8_t stype;
+ uint16_t max_sdu_size;
+ uint32_t sdu_inter_time;
+ uint32_t access_latency;
+ uint32_t flush_timeout;
+} tHCI_EXT_FLOW_SPEC;
+
+/* HCI message type definitions (for H4 messages) */
+#define HCIT_TYPE_COMMAND 1
+#define HCIT_TYPE_ACL_DATA 2
+#define HCIT_TYPE_SCO_DATA 3
+#define HCIT_TYPE_EVENT 4
+#define HCIT_TYPE_LM_DIAG 7
+#define HCIT_TYPE_NFC 16
+
+#define HCIT_LM_DIAG_LENGTH 63
+
+/* Parameter information for HCI_BRCM_SET_ACL_PRIORITY */
+#define HCI_BRCM_ACL_PRIORITY_PARAM_SIZE 3
+#define HCI_BRCM_ACL_PRIORITY_LOW 0x00
+#define HCI_BRCM_ACL_PRIORITY_HIGH 0xFF
+#define HCI_BRCM_SET_ACL_PRIORITY (0x0057 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Define values for LMP Test Control parameters
+ * Test Scenario, Hopping Mode, Power Control Mode
+*/
+#define LMP_TESTCTL_TESTSC_PAUSE 0
+#define LMP_TESTCTL_TESTSC_TXTEST_0 1
+#define LMP_TESTCTL_TESTSC_TXTEST_1 2
+#define LMP_TESTCTL_TESTSC_TXTEST_1010 3
+#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ 4
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL 5
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO 6
+#define LMP_TESTCTL_TESTSC_ACL_NOWHIT 7
+#define LMP_TESTCTL_TESTSC_SCO_NOWHIT 8
+#define LMP_TESTCTL_TESTSC_TXTEST_11110000 9
+#define LMP_TESTCTL_TESTSC_EXITTESTMODE 255
+
+#define LMP_TESTCTL_HOPMOD_RXTX1FREQ 0
+#define LMP_TESTCTL_HOPMOD_HOP_EURUSA 1
+#define LMP_TESTCTL_HOPMOD_HOP_JAPAN 2
+#define LMP_TESTCTL_HOPMOD_HOP_FRANCE 3
+#define LMP_TESTCTL_HOPMOD_HOP_SPAIN 4
+#define LMP_TESTCTL_HOPMOD_REDUCED_HOP 5
+
+#define LMP_TESTCTL_POWCTL_FIXEDTX_OP 0
+#define LMP_TESTCTL_POWCTL_ADAPTIVE 1
+
+// TODO(zachoverflow): remove this once broadcom specific hacks are removed
+#define LMP_COMPID_BROADCOM 15
+/** M: define MTK comp id @{ */
+#define LMP_COMPID_MEDIATEK 70
+/** @} */
+
+/*
+ * Define the packet types in the packet header, and a couple extra
+*/
+#define PKT_TYPE_NULL 0x00
+#define PKT_TYPE_POLL 0x01
+#define PKT_TYPE_FHS 0x02
+#define PKT_TYPE_DM1 0x03
+
+#define PKT_TYPE_DH1 0x04
+#define PKT_TYPE_HV1 0x05
+#define PKT_TYPE_HV2 0x06
+#define PKT_TYPE_HV3 0x07
+#define PKT_TYPE_DV 0x08
+#define PKT_TYPE_AUX1 0x09
+
+#define PKT_TYPE_DM3 0x0a
+#define PKT_TYPE_DH3 0x0b
+
+#define PKT_TYPE_DM5 0x0e
+#define PKT_TYPE_DH5 0x0f
+
+#define PKT_TYPE_ID 0x10 /* Internally used packet types */
+#define PKT_TYPE_BAD 0x11
+#define PKT_TYPE_NONE 0x12
+
+/*
+ * Define packet size
+*/
+#define HCI_DM1_PACKET_SIZE 17
+#define HCI_DH1_PACKET_SIZE 27
+#define HCI_DM3_PACKET_SIZE 121
+#define HCI_DH3_PACKET_SIZE 183
+#define HCI_DM5_PACKET_SIZE 224
+#define HCI_DH5_PACKET_SIZE 339
+#define HCI_AUX1_PACKET_SIZE 29
+#define HCI_HV1_PACKET_SIZE 10
+#define HCI_HV2_PACKET_SIZE 20
+#define HCI_HV3_PACKET_SIZE 30
+#define HCI_DV_PACKET_SIZE 9
+#define HCI_EDR2_DH1_PACKET_SIZE 54
+#define HCI_EDR2_DH3_PACKET_SIZE 367
+#define HCI_EDR2_DH5_PACKET_SIZE 679
+#define HCI_EDR3_DH1_PACKET_SIZE 83
+#define HCI_EDR3_DH3_PACKET_SIZE 552
+#define HCI_EDR3_DH5_PACKET_SIZE 1021
+
+/* Feature Pages */
+#define HCI_EXT_FEATURES_PAGE_MAX 3 // Parse feature pages 0-3
+
+#define HCI_FEATURE_BYTES_PER_PAGE 8
+
+#define HCI_FEATURES_KNOWN(x) \
+ (((x)[0] | (x)[1] | (x)[2] | (x)[3] | (x)[4] | (x)[5] | (x)[6] | (x)[7]) != 0)
+
+/*
+ * LMP features encoding - page 0
+*/
+#define HCI_FEATURE_3_SLOT_PACKETS_MASK 0x01
+#define HCI_FEATURE_3_SLOT_PACKETS_OFF 0
+#define HCI_3_SLOT_PACKETS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_5_SLOT_PACKETS_MASK 0x02
+#define HCI_FEATURE_5_SLOT_PACKETS_OFF 0
+#define HCI_5_SLOT_PACKETS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_ENCRYPTION_MASK 0x04
+#define HCI_FEATURE_ENCRYPTION_OFF 0
+#define HCI_ENCRYPTION_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK)
+
+#define HCI_FEATURE_SLOT_OFFSET_MASK 0x08
+#define HCI_FEATURE_SLOT_OFFSET_OFF 0
+#define HCI_SLOT_OFFSET_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK)
+
+#define HCI_FEATURE_TIMING_ACC_MASK 0x10
+#define HCI_FEATURE_TIMING_ACC_OFF 0
+#define HCI_TIMING_ACC_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK)
+
+#define HCI_FEATURE_SWITCH_MASK 0x20
+#define HCI_FEATURE_SWITCH_OFF 0
+#define HCI_SWITCH_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
+
+#define HCI_FEATURE_HOLD_MODE_MASK 0x40
+#define HCI_FEATURE_HOLD_MODE_OFF 0
+#define HCI_HOLD_MODE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK)
+
+#define HCI_FEATURE_SNIFF_MODE_MASK 0x80
+#define HCI_FEATURE_SNIFF_MODE_OFF 0
+#define HCI_SNIFF_MODE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK)
+
+#define HCI_FEATURE_PARK_MODE_MASK 0x01
+#define HCI_FEATURE_PARK_MODE_OFF 1
+#define HCI_PARK_MODE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK)
+
+#define HCI_FEATURE_RSSI_MASK 0x02
+#define HCI_FEATURE_RSSI_OFF 1
+#define HCI_RSSI_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK)
+
+#define HCI_FEATURE_CQM_DATA_RATE_MASK 0x04
+#define HCI_FEATURE_CQM_DATA_RATE_OFF 1
+#define HCI_CQM_DATA_RATE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK)
+
+#define HCI_FEATURE_SCO_LINK_MASK 0x08
+#define HCI_FEATURE_SCO_LINK_OFF 1
+#define HCI_SCO_LINK_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK)
+
+#define HCI_FEATURE_HV2_PACKETS_MASK 0x10
+#define HCI_FEATURE_HV2_PACKETS_OFF 1
+#define HCI_HV2_PACKETS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK)
+
+#define HCI_FEATURE_HV3_PACKETS_MASK 0x20
+#define HCI_FEATURE_HV3_PACKETS_OFF 1
+#define HCI_HV3_PACKETS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK)
+
+#define HCI_FEATURE_U_LAW_MASK 0x40
+#define HCI_FEATURE_U_LAW_OFF 1
+#define HCI_LMP_U_LAW_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK)
+
+#define HCI_FEATURE_A_LAW_MASK 0x80
+#define HCI_FEATURE_A_LAW_OFF 1
+#define HCI_LMP_A_LAW_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK)
+
+#define HCI_FEATURE_CVSD_MASK 0x01
+#define HCI_FEATURE_CVSD_OFF 2
+#define HCI_LMP_CVSD_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK)
+
+#define HCI_FEATURE_PAGING_SCHEME_MASK 0x02
+#define HCI_FEATURE_PAGING_SCHEME_OFF 2
+#define HCI_PAGING_SCHEME_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK)
+
+#define HCI_FEATURE_POWER_CTRL_MASK 0x04
+#define HCI_FEATURE_POWER_CTRL_OFF 2
+#define HCI_POWER_CTRL_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK)
+
+#define HCI_FEATURE_TRANSPNT_MASK 0x08
+#define HCI_FEATURE_TRANSPNT_OFF 2
+#define HCI_LMP_TRANSPNT_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK)
+
+#define HCI_FEATURE_FLOW_CTRL_LAG_MASK 0x70
+#define HCI_FEATURE_FLOW_CTRL_LAG_OFF 2
+#define HCI_FLOW_CTRL_LAG_VALUE(x) \
+ (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4)
+
+#define HCI_FEATURE_BROADCAST_ENC_MASK 0x80
+#define HCI_FEATURE_BROADCAST_ENC_OFF 2
+#define HCI_LMP_BCAST_ENC_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK)
+
+#define HCI_FEATURE_SCATTER_MODE_MASK 0x01
+#define HCI_FEATURE_SCATTER_MODE_OFF 3
+#define HCI_LMP_SCATTER_MODE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK)
+
+#define HCI_FEATURE_EDR_ACL_2MPS_MASK 0x02
+#define HCI_FEATURE_EDR_ACL_2MPS_OFF 3
+#define HCI_EDR_ACL_2MPS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ACL_3MPS_MASK 0x04
+#define HCI_FEATURE_EDR_ACL_3MPS_OFF 3
+#define HCI_EDR_ACL_3MPS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK)
+
+#define HCI_FEATURE_ENHANCED_INQ_MASK 0x08
+#define HCI_FEATURE_ENHANCED_INQ_OFF 3
+#define HCI_ENHANCED_INQ_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK)
+
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK 0x10
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & \
+ HCI_FEATURE_INTERLACED_INQ_SCAN_MASK)
+
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK 0x20
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & \
+ HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK)
+
+#define HCI_FEATURE_INQ_RSSI_MASK 0x40
+#define HCI_FEATURE_INQ_RSSI_OFF 3
+#define HCI_LMP_INQ_RSSI_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK)
+
+#define HCI_FEATURE_ESCO_EV3_MASK 0x80
+#define HCI_FEATURE_ESCO_EV3_OFF 3
+#define HCI_ESCO_EV3_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK)
+
+#define HCI_FEATURE_ESCO_EV4_MASK 0x01
+#define HCI_FEATURE_ESCO_EV4_OFF 4
+#define HCI_ESCO_EV4_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK)
+
+#define HCI_FEATURE_ESCO_EV5_MASK 0x02
+#define HCI_FEATURE_ESCO_EV5_OFF 4
+#define HCI_ESCO_EV5_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK)
+
+#define HCI_FEATURE_ABSENCE_MASKS_MASK 0x04
+#define HCI_FEATURE_ABSENCE_MASKS_OFF 4
+#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK)
+
+#define HCI_FEATURE_AFH_CAP_SLAVE_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_SLAVE_OFF 4
+#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF 4
+#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK)
+
+#define HCI_FEATURE_BREDR_NOT_SPT_MASK 0x20
+#define HCI_FEATURE_BREDR_NOT_SPT_OFF 4
+#define HCI_BREDR_NOT_SPT_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_BREDR_NOT_SPT_OFF] & HCI_FEATURE_BREDR_NOT_SPT_MASK)
+
+#define HCI_FEATURE_LE_SPT_MASK 0x40
+#define HCI_FEATURE_LE_SPT_OFF 4
+#define HCI_LE_SPT_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_LE_SPT_OFF] & HCI_FEATURE_LE_SPT_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF 4
+#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK 0x01
+#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF 5
+#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_SNIFF_SUB_RATE_MASK 0x02
+#define HCI_FEATURE_SNIFF_SUB_RATE_OFF 5
+#define HCI_SNIFF_SUB_RATE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK)
+
+#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK 0x04
+#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF 5
+#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK)
+
+#define HCI_FEATURE_AFH_CAP_MASTR_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_MASTR_OFF 5
+#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_MASTR_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_MASTR_OFF 5
+#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_2MPS_MASK 0x20
+#define HCI_FEATURE_EDR_ESCO_2MPS_OFF 5
+#define HCI_EDR_ESCO_2MPS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_3MPS_MASK 0x40
+#define HCI_FEATURE_EDR_ESCO_3MPS_OFF 5
+#define HCI_EDR_ESCO_3MPS_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF 5
+#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK)
+
+#define HCI_FEATURE_EXT_INQ_RSP_MASK 0x01
+#define HCI_FEATURE_EXT_INQ_RSP_OFF 6
+#define HCI_EXT_INQ_RSP_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK)
+
+#if 1 /* TOKYO spec definition */
+#define HCI_FEATURE_SIMUL_LE_BREDR_MASK 0x02
+#define HCI_FEATURE_SIMUL_LE_BREDR_OFF 6
+#define HCI_SIMUL_LE_BREDR_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SIMUL_LE_BREDR_OFF] & HCI_FEATURE_SIMUL_LE_BREDR_MASK)
+
+#else
+#define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02
+#define HCI_FEATURE_ANUM_PIN_AWARE_OFF 6
+#define HCI_ANUM_PIN_AWARE_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK)
+#endif
+
+#define HCI_FEATURE_ANUM_PIN_CAP_MASK 0x04
+#define HCI_FEATURE_ANUM_PIN_CAP_OFF 6
+#define HCI_ANUM_PIN_CAP_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK)
+
+#define HCI_FEATURE_SIMPLE_PAIRING_MASK 0x08
+#define HCI_FEATURE_SIMPLE_PAIRING_OFF 6
+#define HCI_SIMPLE_PAIRING_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK)
+
+#define HCI_FEATURE_ENCAP_PDU_MASK 0x10
+#define HCI_FEATURE_ENCAP_PDU_OFF 6
+#define HCI_ENCAP_PDU_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK)
+
+#define HCI_FEATURE_ERROR_DATA_MASK 0x20
+#define HCI_FEATURE_ERROR_DATA_OFF 6
+#define HCI_ERROR_DATA_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK)
+
+#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK 0x40
+#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF 6
+
+/* This feature is causing frequent link drops when doing call switch with
+ * certain av/hfp headsets */
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x) \
+ (0) //((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] &
+ // HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+
+#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK 0x01
+#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF 7
+#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK)
+
+#define HCI_FEATURE_INQ_RESP_TX_MASK 0x02
+#define HCI_FEATURE_INQ_RESP_TX_OFF 7
+#define HCI_INQ_RESP_TX_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK)
+
+#define HCI_FEATURE_EXTENDED_MASK 0x80
+#define HCI_FEATURE_EXTENDED_OFF 7
+#define HCI_LMP_EXTENDED_SUPPORTED(x) \
+ ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK)
+
+/*
+ * LMP features encoding - page 1
+*/
+#define HCI_EXT_FEATURE_SSP_HOST_MASK 0x01
+#define HCI_EXT_FEATURE_SSP_HOST_OFF 0
+#define HCI_SSP_HOST_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK)
+
+#define HCI_EXT_FEATURE_LE_HOST_MASK 0x02
+#define HCI_EXT_FEATURE_LE_HOST_OFF 0
+#define HCI_LE_HOST_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_LE_HOST_OFF] & HCI_EXT_FEATURE_LE_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK 0x04
+#define HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF 0
+#define HCI_SIMUL_DUMO_HOST_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SIMUL_DUMO_HOST_OFF] & \
+ HCI_EXT_FEATURE_SIMUL_DUMO_HOST_MASK)
+
+#define HCI_EXT_FEATURE_SC_HOST_MASK 0x08
+#define HCI_EXT_FEATURE_SC_HOST_OFF 0
+#define HCI_SC_HOST_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SC_HOST_OFF] & HCI_EXT_FEATURE_SC_HOST_MASK)
+
+/*
+ * LMP features encoding - page 2
+*/
+#define HCI_EXT_FEATURE_CSB_MASTER_MASK 0x01
+#define HCI_EXT_FEATURE_CSB_MASTER_OFF 0
+#define HCI_CSB_MASTER_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_CSB_MASTER_OFF] & HCI_EXT_FEATURE_CSB_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_CSB_SLAVE_MASK 0x02
+#define HCI_EXT_FEATURE_CSB_SLAVE_OFF 0
+#define HCI_CSB_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_CSB_SLAVE_OFF] & HCI_EXT_FEATURE_CSB_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK 0x04
+#define HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF 0
+#define HCI_SYNC_TRAIN_MASTER_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_OFF] & \
+ HCI_EXT_FEATURE_SYNC_TRAIN_MASTER_MASK)
+
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK 0x08
+#define HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF 0
+#define HCI_SYNC_SCAN_SLAVE_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_OFF] & \
+ HCI_EXT_FEATURE_SYNC_SCAN_SLAVE_MASK)
+
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK 0x10
+#define HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF 0
+#define HCI_INQ_RESP_NOTIF_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_INQ_RESP_NOTIF_OFF] & \
+ HCI_EXT_FEATURE_INQ_RESP_NOTIF_MASK)
+
+#define HCI_EXT_FEATURE_SC_CTRLR_MASK 0x01
+#define HCI_EXT_FEATURE_SC_CTRLR_OFF 1
+#define HCI_SC_CTRLR_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_SC_CTRLR_OFF] & HCI_EXT_FEATURE_SC_CTRLR_MASK)
+
+#define HCI_EXT_FEATURE_PING_MASK 0x02
+#define HCI_EXT_FEATURE_PING_OFF 1
+#define HCI_PING_SUPPORTED(x) \
+ ((x)[HCI_EXT_FEATURE_PING_OFF] & HCI_EXT_FEATURE_PING_MASK)
+
+/*
+ * LE features encoding - page 0 (the only page for now)
+*/
+/* LE Encryption */
+#define HCI_LE_FEATURE_LE_ENCRYPTION_MASK 0x01
+#define HCI_LE_FEATURE_LE_ENCRYPTION_OFF 0
+#define HCI_LE_ENCRYPTION_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_LE_ENCRYPTION_OFF] & HCI_LE_FEATURE_LE_ENCRYPTION_MASK)
+
+/* Connection Parameters Request Procedure */
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_MASK 0x02
+#define HCI_LE_FEATURE_CONN_PARAM_REQ_OFF 0
+#define HCI_LE_CONN_PARAM_REQ_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_CONN_PARAM_REQ_OFF] & HCI_LE_FEATURE_CONN_PARAM_REQ_MASK)
+
+/* Extended Reject Indication */
+#define HCI_LE_FEATURE_EXT_REJ_IND_MASK 0x04
+#define HCI_LE_FEATURE_EXT_REJ_IND_OFF 0
+#define HCI_LE_EXT_REJ_IND_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_EXT_REJ_IND_OFF] & HCI_LE_FEATURE_EXT_REJ_IND_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK 0x08
+#define HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF 0
+#define HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_OFF] & \
+ HCI_LE_FEATURE_SLAVE_INIT_FEAT_EXC_MASK)
+
+/* Enhanced privacy Feature: bit 6 */
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK 0x40
+#define HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF 0
+#define HCI_LE_ENHANCED_PRIVACY_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF] & \
+ HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK)
+
+/* Extended scanner filter policy : 7 */
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK 0x80
+#define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF 0
+#define HCI_LE_EXT_SCAN_FILTER_POLICY_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF] & \
+ HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK)
+
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_DATA_LEN_EXT_MASK 0x20
+#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF 0
+#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x) \
+ ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK)
+
+/*
+ * Local Supported Commands encoding
+*/
+#define HCI_NUM_SUPP_COMMANDS_BYTES 64
+
+/* Supported Commands Byte 0 */
+#define HCI_SUPP_COMMANDS_INQUIRY_MASK 0x01
+#define HCI_SUPP_COMMANDS_INQUIRY_OFF 0
+#define HCI_INQUIRY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK 0x02
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF 0
+#define HCI_INQUIRY_CANCEL_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & \
+ HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK 0x04
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF 0
+#define HCI_PERIODIC_INQUIRY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & \
+ HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF 0
+#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & \
+ HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF 0
+#define HCI_CREATE_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_MASK 0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_OFF 0
+#define HCI_DISCONNECT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK)
+
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK 0x40
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF 0
+#define HCI_ADD_SCO_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK 0x80
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF 0
+#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK 0x01
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF 1
+#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & \
+ HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK 0x02
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF 1
+#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & \
+ HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK 0x20
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK 0x40
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF 1
+#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK 0x80
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF 1
+#define HCI_AUTH_REQUEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & \
+ HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF 2
+#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & \
+ HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK 0x02
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF 2
+#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF 2
+#define HCI_MASTER_LINK_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK 0x08
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & \
+ HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK 0x10
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & \
+ HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF 2
+#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & \
+ HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF 2
+#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & \
+ HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF 2
+#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & \
+ HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF 3
+#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & \
+ HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF 3
+#define HCI_READ_LMP_HANDLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK 0x02
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF 4
+#define HCI_HOLD_MODE_CMD_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & \
+ HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK 0x04
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF 4
+#define HCI_SNIFF_MODE_CMD_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & \
+ HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF 4
+#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_PARK_STATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_PARK_STATE_OFF 4
+#define HCI_PARK_STATE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK 0x20
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF 4
+#define HCI_EXIT_PARK_STATE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & \
+ HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK 0x40
+#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF 4
+#define HCI_QOS_SETUP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK)
+
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK 0x80
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF 4
+#define HCI_ROLE_DISCOVERY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & \
+ HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK)
+
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK 0x01
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF 5
+#define HCI_SWITCH_ROLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF 5
+#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK 0x04
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & \
+ HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK 0x20
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF 5
+#define HCI_FLOW_SPECIFICATION_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & \
+ HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK 0x40
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF 5
+#define HCI_SET_EVENT_MASK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & \
+ HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_MASK 0x80
+#define HCI_SUPP_COMMANDS_RESET_OFF 5
+#define HCI_RESET_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF 6
+#define HCI_SET_EVENT_FILTER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & \
+ HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK)
+
+#define HCI_SUPP_COMMANDS_FLUSH_MASK 0x02
+#define HCI_SUPP_COMMANDS_FLUSH_OFF 6
+#define HCI_FLUSH_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF 6
+#define HCI_READ_PIN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF 6
+#define HCI_WRITE_PIN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF 6
+#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF 6
+#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF 6
+#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK 0x80
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF 6
+#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF 7
+#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF 7
+#define HCI_READ_LOCAL_NAME_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF 7
+#define HCI_READ_PAGE_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF 7
+#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF 7
+#define HCI_READ_SCAN_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF 7
+#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF 8
+#define HCI_READ_AUTH_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF 8
+#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF 8
+#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF 8
+#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF 9
+#define HCI_READ_CLASS_DEVICE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF 9
+#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF 9
+#define HCI_READ_VOICE_SETTING_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & \
+ HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF 9
+#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF 9
+#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & \
+ HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF 9
+#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF 10
+#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & \
+ HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK 0x20
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF 10
+#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & \
+ HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK 0x40
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF 10
+#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & \
+ HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK 0x80
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF 10
+#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & \
+ HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF 11
+#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF 11
+#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF 11
+#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & \
+ HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF 11
+#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & \
+ HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF 11
+#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF 12
+#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK 0x02
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF 12
+#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & \
+ HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF 12
+#define HCI_READ_INQUIRY_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF 12
+#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF 13
+#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF 13
+#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF 14
+#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF 14
+#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF 14
+#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF 14
+#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF 14
+#define HCI_READ_BUFFER_SIZE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF 15
+#define HCI_READ_COUNTRY_CODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF 15
+#define HCI_READ_BD_ADDR_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & \
+ HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & \
+ HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK 0x08
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & \
+ HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK 0x10
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF 15
+#define HCI_GET_LINK_QUALITY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & \
+ HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_RSSI_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_RSSI_OFF 15
+#define HCI_READ_RSSI_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF 15
+#define HCI_READ_AFH_CH_MAP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & \
+ HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF 15
+#define HCI_READ_BD_CLOCK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & \
+ HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF 16
+#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF 16
+#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK 0x04
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF 16
+#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & \
+ HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK 0x08
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF 16
+#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF 16
+#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK 0x20
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF 16
+#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF 17
+#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & \
+ HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF 17
+#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF 17
+#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & \
+ HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK)
+
+/* Octet 17, bit 3 is reserved */
+
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF 17
+#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & \
+ HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF 17
+#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & \
+ HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & \
+ HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK 0x80
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF 18
+#define HCI_IO_CAPABILITY_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_IO_CAPABILITY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK 0x01
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK 0x02
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF 19
+#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK 0x40
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF 19
+#define HCI_ENHANCED_FLUSH_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & \
+ HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK 0x80
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK)
+
+/* Supported Commands (Byte 20) */
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK 0x04
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF 20
+#define HCI_SEND_NOTIF_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & \
+ HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF 20
+#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF 20
+#define HCI_READ_ENCR_KEY_SIZE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_ENCR_KEY_SIZE_MASK)
+
+/* Supported Commands (Byte 21) */
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK 0x01
+#define HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF 21
+#define HCI_CREATE_PHYSICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_CREATE_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK 0x02
+#define HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF 21
+#define HCI_ACCEPT_PHYSICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_ACCEPT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK 0x04
+#define HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF 21
+#define HCI_DISCONNECT_PHYSICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_DISCONNECT_PHYSICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK 0x08
+#define HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF 21
+#define HCI_CREATE_LOGICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_CREATE_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK 0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF 21
+#define HCI_ACCEPT_LOGICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_ACCEPT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK 0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF 21
+#define HCI_DISCONNECT_LOGICAL_LINK_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_OFF] & \
+ HCI_SUPP_COMMANDS_DISCONNECT_LOGICAL_LINK_MASK)
+
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK 0x40
+#define HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF 21
+#define HCI_LOGICAL_LINK_CANCEL_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_OFF] & \
+ HCI_SUPP_COMMANDS_LOGICAL_LINK_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK 0x80
+#define HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF 21
+#define HCI_FLOW_SPEC_MODIFY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_OFF] & \
+ HCI_SUPP_COMMANDS_FLOW_SPEC_MODIFY_MASK)
+
+/* Supported Commands (Byte 22) */
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22
+#define HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF 22
+#define HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK 0x04
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF 22
+#define HCI_SET_EVENT_MASK_PAGE_2_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_OFF] & \
+ HCI_SUPP_COMMANDS_SET_EVENT_MASK_PAGE_2_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF 22
+#define HCI_READ_LOCATION_DATA_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCATION_DATA_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF 22
+#define HCI_WRITE_LOCATION_DATA_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_LOCATION_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF 22
+#define HCI_READ_LOCAL_AMP_INFO_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_AMP_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF 22
+#define HCI_READ_LOCAL_AMP_ASSOC_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_AMP_ASSOC_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF 22
+#define HCI_WRITE_REMOTE_AMP_ASSOC_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_REMOTE_AMP_ASSOC_MASK)
+
+/* Supported Commands (Byte 23) */
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF 23
+#define HCI_READ_FLOW_CONTROL_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF 23
+#define HCI_WRITE_FLOW_CONTROL_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_FLOW_CONTROL_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF 23
+#define HCI_READ_DATA_BLOCK_SIZE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_OFF] & \
+ HCI_SUPP_COMMANDS_READ_DATA_BLOCK_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK 0x20
+#define HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF 23
+#define HCI_ENABLE_AMP_RCVR_REPORTS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_OFF] & \
+ HCI_SUPP_COMMANDS_ENABLE_AMP_RCVR_REPORTS_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_MASK 0x40
+#define HCI_SUPP_COMMANDS_AMP_TEST_END_OFF 23
+#define HCI_AMP_TEST_END_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_AMP_TEST_END_OFF] & \
+ HCI_SUPP_COMMANDS_AMP_TEST_END_MASK)
+
+#define HCI_SUPP_COMMANDS_AMP_TEST_MASK 0x80
+#define HCI_SUPP_COMMANDS_AMP_TEST_OFF 23
+#define HCI_AMP_TEST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_AMP_TEST_OFF] & HCI_SUPP_COMMANDS_AMP_TEST_MASK)
+
+/* Supported Commands (Byte 24) */
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF 24
+#define HCI_READ_TRANSMIT_POWER_LEVEL_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_OFF] & \
+ HCI_SUPP_COMMANDS_READ_TRANSMIT_POWER_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF 24
+#define HCI_READ_BE_FLUSH_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF 24
+#define HCI_WRITE_BE_FLUSH_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_BE_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK 0x10
+#define HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF 24
+#define HCI_SHORT_RANGE_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_SHORT_RANGE_MODE_MASK)
+
+/* LE commands TBD
+ * Supported Commands (Byte 24 continued)
+ * Supported Commands (Byte 25)
+ * Supported Commands (Byte 26)
+ * Supported Commands (Byte 27)
+ * Supported Commands (Byte 28)
+*/
+
+/* Supported Commands (Byte 29) */
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK 0x08
+#define HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF 29
+#define HCI_ENH_SETUP_SYNCH_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_ENH_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF 29
+#define HCI_ENH_ACCEPT_SYNCH_CONN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_OFF] & \
+ HCI_SUPP_COMMANDS_ENH_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF 29
+#define HCI_READ_LOCAL_CODECS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_CODECS_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK 0x40
+#define HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF 29
+#define HCI_SET_MWS_CHANNEL_PARAMETERS_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_OFF] & \
+ HCI_SUPP_COMMANDS_SET_MWS_CHANN_PARAM_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK 0x80
+#define HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF 29
+#define HCI_SET_EXTERNAL_FRAME_CONFIGURATION_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_OFF] & \
+ HCI_SUPP_COMMANDS_SET_EXT_FRAME_CONF_MASK)
+
+/* Supported Commands (Byte 30) */
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF 30
+#define HCI_SET_MWS_SIGNALING_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_OFF] & \
+ HCI_SUPP_COMMANDS_SET_MWS_SIGNALING_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK 0x02
+#define HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF 30
+#define HCI_SET_MWS_TRANSPORT_LAYER_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_OFF] & \
+ HCI_SUPP_COMMANDS_SET_MWS_TRANS_LAYER_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK 0x04
+#define HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF 30
+#define HCI_SET_MWS_SCAN_FREQUENCY_TABLE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_OFF] & \
+ HCI_SUPP_COMMANDS_SET_MWS_SCAN_FREQ_TABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK 0x08
+#define HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF 30
+#define HCI_GET_MWS_TRANS_LAYER_CFG_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_OFF] & \
+ HCI_SUPP_COMMANDS_GET_TRANS_LAYER_CONF_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK 0x10
+#define HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF 30
+#define HCI_SET_MWS_PATTERN_CONFIGURATION_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_OFF] & \
+ HCI_SUPP_COMMANDS_SET_MWS_PATTERN_CONF_MASK)
+
+/* Supported Commands (Byte 30 bit 5) */
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK 0x20
+#define HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF 30
+#define HCI_SET_TRIG_CLK_CAP_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_OFF] & \
+ HCI_SUPP_COMMANDS_SET_TRIG_CLK_CAP_MASK)
+
+/* Supported Commands (Byte 30 bit 6-7) */
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE 0x06
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF 30
+#define HCI_TRUNCATED_PAGE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_OFF] & HCI_SUPP_COMMANDS_TRUNCATED_PAGE)
+
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL 0x07
+#define HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF 30
+#define HCI_TRUNCATED_PAGE_CANCEL_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL_OFF] & \
+ HCI_SUPP_COMMANDS_TRUNCATED_PAGE_CANCEL)
+
+/* Supported Commands (Byte 31 bit 6-7) */
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST 0x00
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF 31
+#define HCI_SET_CONLESS_SLAVE_BRCST_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_OFF] & \
+ HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE 0x01
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF 31
+#define HCI_SET_CONLESS_SLAVE_BRCST_RECEIVE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE_OFF] & \
+ HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_RECEIVE)
+
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN 0x02
+#define HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF 31
+#define HCI_START_SYNC_TRAIN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_START_SYNC_TRAIN_OFF] & \
+ HCI_SUPP_COMMANDS_START_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN 0x03
+#define HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF 31
+#define HCI_RECEIVE_SYNC_TRAIN_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN_OFF] & \
+ HCI_SUPP_COMMANDS_RECEIVE_SYNC_TRAIN)
+
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR 0x04
+#define HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF 31
+#define HCI_SET_RESERVED_LT_ADDR_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR_OFF] & \
+ HCI_SUPP_COMMANDS_SET_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR 0x05
+#define HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF 31
+#define HCI_DELETE_RESERVED_LT_ADDR_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR_OFF] & \
+ HCI_SUPP_COMMANDS_DELETE_RESERVED_LT_ADDR)
+
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA 0x06
+#define HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF 31
+#define HCI_SET_CONLESS_SLAVE_BRCST_DATA_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA_OFF] & \
+ HCI_SUPP_COMMANDS_SET_CONLESS_SLAVE_BRCST_DATA)
+
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM 0x07
+#define HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF 31
+#define HCI_READ_SYNC_TRAIN_PARAM_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM_OFF] & \
+ HCI_SUPP_COMMANDS_READ_SYNC_TRAIN_PARAM)
+
+/* Supported Commands (Byte 32 bit 0) */
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM 0x00
+#define HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF 32
+#define HCI_WRITE_SYNC_TRAIN_PARAM_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SYNC_TRAIN_PARAM)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK 0x02
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF 32
+#define HCI_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_OFF] & \
+ HCI_SUPP_COMMANDS_REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF 32
+#define HCI_READ_SECURE_CONNS_SUPPORT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF 32
+#define HCI_WRITE_SECURE_CONNS_SUPPORT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SECURE_CONNS_SUPPORT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF 32
+#define HCI_READ_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_READ_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF 32
+#define HCI_WRITE_AUTHENT_PAYLOAD_TOUT_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_AUTHENT_PAYLOAD_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF 32
+#define HCI_READ_LOCAL_OOB_EXTENDED_DATA_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_OFF] & \
+ HCI_SUPP_COMMANDS_READ_LOCAL_OOB_EXTENDED_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF 32
+#define HCI_WRITE_SECURE_CONNECTIONS_TEST_MODE_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_OFF] & \
+ HCI_SUPP_COMMANDS_WRITE_SECURE_CONNECTIONS_TEST_MODE_MASK)
+
+/* supported LE remote control connection parameter request reply */
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK 0x10
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF 33
+#define HCI_LE_RC_CONN_PARAM_UPD_RPY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_OFF] & \
+ HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_RPY_MASK)
+
+#define HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK 0x20
+#define HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF 33
+#define HCI_LE_RC_CONN_PARAM_UPD_NEG_RPY_SUPPORTED(x) \
+ ((x)[HCI_SUPP_COMMANDS_LE_RC_CONN_PARAM_UPD_NEG_RPY_OFF] & \
+ HCI_SUPP_COMMANDS_RLE_RC_CONN_PARAM_UPD_NEG_RPY_MASK)
+
+#define HCI_LE_2M_PHY_SUPPORTED(x) (((x)[1] & 0x01)) // BIT 8 SET
+#define HCI_LE_CODED_PHY_SUPPORTED(x) (((x)[1] & 0x08)) // BIT 11 SET
+
+/* LE Advertising Extension related Procedurs */
+#define HCI_LE_EXTENDED_ADVERTISING_SUPPORTED(x) \
+ (((x)[1] & 0x10)) // BIT 12 SET
+#define HCI_LE_PERIODIC_ADVERTISING_SUPPORTED(x) \
+ (((x)[1] & 0x20)) // BIT 13 SET
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/hcimsgs.h b/mtkbt/code/bt/stack/include/hcimsgs.h
new file mode 100755
index 0000000..0a1984f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/hcimsgs.h
@@ -0,0 +1,878 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef HCIMSGS_H
+#define HCIMSGS_H
+
+#include "bt_target.h"
+#include "bt_types.h"
+#include "device/include/esco_parameters.h"
+#include "hcidefs.h"
+
+#include <base/callback_forward.h>
+
+void bte_main_hci_send(BT_HDR* p_msg, uint16_t event);
+
+/* Message by message.... */
+
+extern void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration,
+ uint8_t response_cnt);
+
+#define HCIC_PARAM_SIZE_INQUIRY 5
+
+#define HCIC_INQ_INQ_LAP_OFF 0
+#define HCIC_INQ_DUR_OFF 3
+#define HCIC_INQ_RSP_CNT_OFF 4
+/* Inquiry */
+
+/* Inquiry Cancel */
+extern void btsnd_hcic_inq_cancel(void);
+
+#define HCIC_PARAM_SIZE_INQ_CANCEL 0
+
+/* Periodic Inquiry Mode */
+extern void btsnd_hcic_per_inq_mode(uint16_t max_period, uint16_t min_period,
+ const LAP inq_lap, uint8_t duration,
+ uint8_t response_cnt);
+
+#define HCIC_PARAM_SIZE_PER_INQ_MODE 9
+
+#define HCI_PER_INQ_MAX_INTRVL_OFF 0
+#define HCI_PER_INQ_MIN_INTRVL_OFF 2
+#define HCI_PER_INQ_INQ_LAP_OFF 4
+#define HCI_PER_INQ_DURATION_OFF 7
+#define HCI_PER_INQ_RSP_CNT_OFF 8
+/* Periodic Inquiry Mode */
+
+/* Exit Periodic Inquiry Mode */
+extern void btsnd_hcic_exit_per_inq(void);
+
+#define HCIC_PARAM_SIZE_EXIT_PER_INQ 0
+/* Create Connection */
+extern void btsnd_hcic_create_conn(BD_ADDR dest, uint16_t packet_types,
+ uint8_t page_scan_rep_mode,
+ uint8_t page_scan_mode,
+ uint16_t clock_offset, uint8_t allow_switch);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN 13
+
+#define HCIC_CR_CONN_BD_ADDR_OFF 0
+#define HCIC_CR_CONN_PKT_TYPES_OFF 6
+#define HCIC_CR_CONN_REP_MODE_OFF 8
+#define HCIC_CR_CONN_PAGE_SCAN_MODE_OFF 9
+#define HCIC_CR_CONN_CLK_OFF_OFF 10
+#define HCIC_CR_CONN_ALLOW_SWITCH_OFF 12
+/* Create Connection */
+
+/* Disconnect */
+extern void btsnd_hcic_disconnect(uint16_t handle, uint8_t reason);
+
+#define HCIC_PARAM_SIZE_DISCONNECT 3
+
+#define HCI_DISC_HANDLE_OFF 0
+#define HCI_DISC_REASON_OFF 2
+/* Disconnect */
+
+#if (BTM_SCO_INCLUDED == TRUE)
+/* Add SCO Connection */
+extern void btsnd_hcic_add_SCO_conn(uint16_t handle, uint16_t packet_types);
+#endif /* BTM_SCO_INCLUDED */
+
+#define HCIC_PARAM_SIZE_ADD_SCO_CONN 4
+
+#define HCI_ADD_SCO_HANDLE_OFF 0
+#define HCI_ADD_SCO_PACKET_TYPES_OFF 2
+/* Add SCO Connection */
+
+/* Create Connection Cancel */
+extern void btsnd_hcic_create_conn_cancel(BD_ADDR dest);
+
+#define HCIC_PARAM_SIZE_CREATE_CONN_CANCEL 6
+
+#define HCIC_CR_CONN_CANCEL_BD_ADDR_OFF 0
+/* Create Connection Cancel */
+
+/* Accept Connection Request */
+extern void btsnd_hcic_accept_conn(BD_ADDR bd_addr, uint8_t role);
+
+#define HCIC_PARAM_SIZE_ACCEPT_CONN 7
+
+#define HCI_ACC_CONN_BD_ADDR_OFF 0
+#define HCI_ACC_CONN_ROLE_OFF 6
+/* Accept Connection Request */
+
+/* Reject Connection Request */
+extern void btsnd_hcic_reject_conn(BD_ADDR bd_addr, uint8_t reason);
+
+#define HCIC_PARAM_SIZE_REJECT_CONN 7
+
+#define HCI_REJ_CONN_BD_ADDR_OFF 0
+#define HCI_REJ_CONN_REASON_OFF 6
+/* Reject Connection Request */
+
+/* Link Key Request Reply */
+extern void btsnd_hcic_link_key_req_reply(BD_ADDR bd_addr, LINK_KEY link_key);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_REQ_REPLY 22
+
+#define HCI_LINK_KEY_REPLY_BD_ADDR_OFF 0
+#define HCI_LINK_KEY_REPLY_LINK_KEY_OFF 6
+/* Link Key Request Reply */
+
+/* Link Key Request Neg Reply */
+extern void btsnd_hcic_link_key_neg_reply(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_LINK_KEY_NEG_REPLY 6
+
+#define HCI_LINK_KEY_NEG_REP_BD_ADR_OFF 0
+/* Link Key Request Neg Reply */
+
+/* PIN Code Request Reply */
+extern void btsnd_hcic_pin_code_req_reply(BD_ADDR bd_addr, uint8_t pin_code_len,
+ PIN_CODE pin_code);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_REQ_REPLY 23
+
+#define HCI_PIN_CODE_REPLY_BD_ADDR_OFF 0
+#define HCI_PIN_CODE_REPLY_PIN_LEN_OFF 6
+#define HCI_PIN_CODE_REPLY_PIN_CODE_OFF 7
+/* PIN Code Request Reply */
+
+/* Link Key Request Neg Reply */
+extern void btsnd_hcic_pin_code_neg_reply(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_PIN_CODE_NEG_REPLY 6
+
+#define HCI_PIN_CODE_NEG_REP_BD_ADR_OFF 0
+/* Link Key Request Neg Reply */
+
+/* Change Connection Type */
+extern void btsnd_hcic_change_conn_type(uint16_t handle, uint16_t packet_types);
+
+#define HCIC_PARAM_SIZE_CHANGE_CONN_TYPE 4
+
+#define HCI_CHNG_PKT_TYPE_HANDLE_OFF 0
+#define HCI_CHNG_PKT_TYPE_PKT_TYPE_OFF 2
+/* Change Connection Type */
+
+#define HCIC_PARAM_SIZE_CMD_HANDLE 2
+
+#define HCI_CMD_HANDLE_HANDLE_OFF 0
+
+extern void btsnd_hcic_auth_request(
+ uint16_t handle); /* Authentication Request */
+
+/* Set Connection Encryption */
+extern void btsnd_hcic_set_conn_encrypt(uint16_t handle, bool enable);
+#define HCIC_PARAM_SIZE_SET_CONN_ENCRYPT 3
+
+#define HCI_SET_ENCRYPT_HANDLE_OFF 0
+#define HCI_SET_ENCRYPT_ENABLE_OFF 2
+/* Set Connection Encryption */
+
+/* Remote Name Request */
+extern void btsnd_hcic_rmt_name_req(BD_ADDR bd_addr, uint8_t page_scan_rep_mode,
+ uint8_t page_scan_mode,
+ uint16_t clock_offset);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ 10
+
+#define HCI_RMT_NAME_BD_ADDR_OFF 0
+#define HCI_RMT_NAME_REP_MODE_OFF 6
+#define HCI_RMT_NAME_PAGE_SCAN_MODE_OFF 7
+#define HCI_RMT_NAME_CLK_OFF_OFF 8
+/* Remote Name Request */
+
+/* Remote Name Request Cancel */
+extern void btsnd_hcic_rmt_name_req_cancel(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_RMT_NAME_REQ_CANCEL 6
+
+#define HCI_RMT_NAME_CANCEL_BD_ADDR_OFF 0
+/* Remote Name Request Cancel */
+
+extern void btsnd_hcic_rmt_features_req(
+ uint16_t handle); /* Remote Features Request */
+
+/* Remote Extended Features */
+extern void btsnd_hcic_rmt_ext_features(uint16_t handle, uint8_t page_num);
+
+#define HCIC_PARAM_SIZE_RMT_EXT_FEATURES 3
+
+#define HCI_RMT_EXT_FEATURES_HANDLE_OFF 0
+#define HCI_RMT_EXT_FEATURES_PAGE_NUM_OFF 2
+/* Remote Extended Features */
+
+extern void btsnd_hcic_rmt_ver_req(
+ uint16_t handle); /* Remote Version Info Request */
+extern void btsnd_hcic_read_rmt_clk_offset(
+ uint16_t handle); /* Remote Clock Offset */
+extern void btsnd_hcic_read_lmp_handle(uint16_t handle); /* Remote LMP Handle */
+extern void btsnd_hcic_setup_esco_conn(uint16_t handle,
+ uint32_t transmit_bandwidth,
+ uint32_t receive_bandwidth,
+ uint16_t max_latency, uint16_t voice,
+ uint8_t retrans_effort,
+ uint16_t packet_types);
+#define HCIC_PARAM_SIZE_SETUP_ESCO 17
+
+#define HCI_SETUP_ESCO_HANDLE_OFF 0
+#define HCI_SETUP_ESCO_TX_BW_OFF 2
+#define HCI_SETUP_ESCO_RX_BW_OFF 6
+#define HCI_SETUP_ESCO_MAX_LAT_OFF 10
+#define HCI_SETUP_ESCO_VOICE_OFF 12
+#define HCI_SETUP_ESCO_RETRAN_EFF_OFF 14
+#define HCI_SETUP_ESCO_PKT_TYPES_OFF 15
+
+extern void btsnd_hcic_accept_esco_conn(
+ BD_ADDR bd_addr, uint32_t transmit_bandwidth, uint32_t receive_bandwidth,
+ uint16_t max_latency, uint16_t content_fmt, uint8_t retrans_effort,
+ uint16_t packet_types);
+#define HCIC_PARAM_SIZE_ACCEPT_ESCO 21
+
+#define HCI_ACCEPT_ESCO_BDADDR_OFF 0
+#define HCI_ACCEPT_ESCO_TX_BW_OFF 6
+#define HCI_ACCEPT_ESCO_RX_BW_OFF 10
+#define HCI_ACCEPT_ESCO_MAX_LAT_OFF 14
+#define HCI_ACCEPT_ESCO_VOICE_OFF 16
+#define HCI_ACCEPT_ESCO_RETRAN_EFF_OFF 18
+#define HCI_ACCEPT_ESCO_PKT_TYPES_OFF 19
+
+extern void btsnd_hcic_reject_esco_conn(BD_ADDR bd_addr, uint8_t reason);
+#define HCIC_PARAM_SIZE_REJECT_ESCO 7
+
+#define HCI_REJECT_ESCO_BDADDR_OFF 0
+#define HCI_REJECT_ESCO_REASON_OFF 6
+
+/* Hold Mode */
+extern void btsnd_hcic_hold_mode(uint16_t handle, uint16_t max_hold_period,
+ uint16_t min_hold_period);
+
+#define HCIC_PARAM_SIZE_HOLD_MODE 6
+
+#define HCI_HOLD_MODE_HANDLE_OFF 0
+#define HCI_HOLD_MODE_MAX_PER_OFF 2
+#define HCI_HOLD_MODE_MIN_PER_OFF 4
+/* Hold Mode */
+
+/* Sniff Mode */
+extern void btsnd_hcic_sniff_mode(uint16_t handle, uint16_t max_sniff_period,
+ uint16_t min_sniff_period,
+ uint16_t sniff_attempt,
+ uint16_t sniff_timeout);
+
+#define HCIC_PARAM_SIZE_SNIFF_MODE 10
+
+#define HCI_SNIFF_MODE_HANDLE_OFF 0
+#define HCI_SNIFF_MODE_MAX_PER_OFF 2
+#define HCI_SNIFF_MODE_MIN_PER_OFF 4
+#define HCI_SNIFF_MODE_ATTEMPT_OFF 6
+#define HCI_SNIFF_MODE_TIMEOUT_OFF 8
+/* Sniff Mode */
+
+extern void btsnd_hcic_exit_sniff_mode(uint16_t handle); /* Exit Sniff Mode */
+
+/* Park Mode */
+extern void btsnd_hcic_park_mode(uint16_t handle, uint16_t beacon_max_interval,
+ uint16_t beacon_min_interval);
+
+#define HCIC_PARAM_SIZE_PARK_MODE 6
+
+#define HCI_PARK_MODE_HANDLE_OFF 0
+#define HCI_PARK_MODE_MAX_PER_OFF 2
+#define HCI_PARK_MODE_MIN_PER_OFF 4
+/* Park Mode */
+
+extern void btsnd_hcic_exit_park_mode(uint16_t handle); /* Exit Park Mode */
+
+/* QoS Setup */
+extern void btsnd_hcic_qos_setup(uint16_t handle, uint8_t flags,
+ uint8_t service_type, uint32_t token_rate,
+ uint32_t peak, uint32_t latency,
+ uint32_t delay_var);
+
+#define HCIC_PARAM_SIZE_QOS_SETUP 20
+
+#define HCI_QOS_HANDLE_OFF 0
+#define HCI_QOS_FLAGS_OFF 2
+#define HCI_QOS_SERVICE_TYPE_OFF 3
+#define HCI_QOS_TOKEN_RATE_OFF 4
+#define HCI_QOS_PEAK_BANDWIDTH_OFF 8
+#define HCI_QOS_LATENCY_OFF 12
+#define HCI_QOS_DELAY_VAR_OFF 16
+/* QoS Setup */
+
+/* Switch Role Request */
+extern void btsnd_hcic_switch_role(BD_ADDR bd_addr, uint8_t role);
+
+#define HCIC_PARAM_SIZE_SWITCH_ROLE 7
+
+#define HCI_SWITCH_BD_ADDR_OFF 0
+#define HCI_SWITCH_ROLE_OFF 6
+/* Switch Role Request */
+
+/* Write Policy Settings */
+extern void btsnd_hcic_write_policy_set(uint16_t handle, uint16_t settings);
+
+#define HCIC_PARAM_SIZE_WRITE_POLICY_SET 4
+
+#define HCI_WRITE_POLICY_HANDLE_OFF 0
+#define HCI_WRITE_POLICY_SETTINGS_OFF 2
+/* Write Policy Settings */
+
+/* Write Default Policy Settings */
+extern void btsnd_hcic_write_def_policy_set(uint16_t settings);
+
+#define HCIC_PARAM_SIZE_WRITE_DEF_POLICY_SET 2
+
+#define HCI_WRITE_DEF_POLICY_SETTINGS_OFF 0
+/* Write Default Policy Settings */
+
+/******************************************
+ * Lisbon Features
+ ******************************************/
+#if (BTM_SSR_INCLUDED == TRUE)
+/* Sniff Subrating */
+extern void btsnd_hcic_sniff_sub_rate(uint16_t handle, uint16_t max_lat,
+ uint16_t min_remote_lat,
+ uint16_t min_local_lat);
+
+#define HCIC_PARAM_SIZE_SNIFF_SUB_RATE 8
+
+#define HCI_SNIFF_SUB_RATE_HANDLE_OFF 0
+#define HCI_SNIFF_SUB_RATE_MAX_LAT_OFF 2
+#define HCI_SNIFF_SUB_RATE_MIN_REM_LAT_OFF 4
+#define HCI_SNIFF_SUB_RATE_MIN_LOC_LAT_OFF 6
+/* Sniff Subrating */
+
+#else /* BTM_SSR_INCLUDED == FALSE */
+
+#define btsnd_hcic_sniff_sub_rate(handle, max_lat, min_remote_lat, \
+ min_local_lat) \
+ false
+
+#endif /* BTM_SSR_INCLUDED */
+
+/* Extended Inquiry Response */
+extern void btsnd_hcic_write_ext_inquiry_response(void* buffer,
+ uint8_t fec_req);
+
+#define HCIC_PARAM_SIZE_EXT_INQ_RESP 241
+
+#define HCIC_EXT_INQ_RESP_FEC_OFF 0
+#define HCIC_EXT_INQ_RESP_RESPONSE 1
+/* IO Capabilities Response */
+extern void btsnd_hcic_io_cap_req_reply(BD_ADDR bd_addr, uint8_t capability,
+ uint8_t oob_present, uint8_t auth_req);
+
+#define HCIC_PARAM_SIZE_IO_CAP_RESP 9
+
+#define HCI_IO_CAP_BD_ADDR_OFF 0
+#define HCI_IO_CAPABILITY_OFF 6
+#define HCI_IO_CAP_OOB_DATA_OFF 7
+#define HCI_IO_CAP_AUTH_REQ_OFF 8
+
+/* IO Capabilities Req Neg Reply */
+extern void btsnd_hcic_io_cap_req_neg_reply(BD_ADDR bd_addr, uint8_t err_code);
+
+#define HCIC_PARAM_SIZE_IO_CAP_NEG_REPLY 7
+
+#define HCI_IO_CAP_NR_BD_ADDR_OFF 0
+#define HCI_IO_CAP_NR_ERR_CODE 6
+
+/* Read Local OOB Data */
+extern void btsnd_hcic_read_local_oob_data(void);
+
+#define HCIC_PARAM_SIZE_R_LOCAL_OOB 0
+
+extern void btsnd_hcic_user_conf_reply(BD_ADDR bd_addr, bool is_yes);
+
+#define HCIC_PARAM_SIZE_UCONF_REPLY 6
+
+#define HCI_USER_CONF_BD_ADDR_OFF 0
+
+extern void btsnd_hcic_user_passkey_reply(BD_ADDR bd_addr, uint32_t value);
+
+#define HCIC_PARAM_SIZE_U_PKEY_REPLY 10
+
+#define HCI_USER_PASSKEY_BD_ADDR_OFF 0
+#define HCI_USER_PASSKEY_VALUE_OFF 6
+
+extern void btsnd_hcic_user_passkey_neg_reply(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_U_PKEY_NEG_REPLY 6
+
+#define HCI_USER_PASSKEY_NEG_BD_ADDR_OFF 0
+
+/* Remote OOB Data Request Reply */
+extern void btsnd_hcic_rem_oob_reply(BD_ADDR bd_addr, uint8_t* p_c,
+ uint8_t* p_r);
+
+#define HCIC_PARAM_SIZE_REM_OOB_REPLY 38
+
+#define HCI_REM_OOB_DATA_BD_ADDR_OFF 0
+#define HCI_REM_OOB_DATA_C_OFF 6
+#define HCI_REM_OOB_DATA_R_OFF 22
+
+/* Remote OOB Data Request Negative Reply */
+extern void btsnd_hcic_rem_oob_neg_reply(BD_ADDR bd_addr);
+
+#define HCIC_PARAM_SIZE_REM_OOB_NEG_REPLY 6
+
+#define HCI_REM_OOB_DATA_NEG_BD_ADDR_OFF 0
+
+/* Read Tx Power Level */
+extern void btsnd_hcic_read_inq_tx_power(void);
+
+#define HCIC_PARAM_SIZE_R_TX_POWER 0
+
+/* Read Default Erroneous Data Reporting */
+extern void btsnd_hcic_read_default_erroneous_data_rpt(void);
+
+#define HCIC_PARAM_SIZE_R_ERR_DATA_RPT 0
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+extern void btsnd_hcic_enhanced_flush(uint16_t handle, uint8_t packet_type);
+
+#define HCIC_PARAM_SIZE_ENHANCED_FLUSH 3
+#endif
+
+extern void btsnd_hcic_send_keypress_notif(BD_ADDR bd_addr, uint8_t notif);
+
+#define HCIC_PARAM_SIZE_SEND_KEYPRESS_NOTIF 7
+
+#define HCI_SEND_KEYPRESS_NOTIF_BD_ADDR_OFF 0
+#define HCI_SEND_KEYPRESS_NOTIF_NOTIF_OFF 6
+
+/**** end of Simple Pairing Commands ****/
+
+/* Store Current Settings */
+#define MAX_FILT_COND (sizeof(BD_ADDR) + 1)
+
+extern void btsnd_hcic_set_event_filter(uint8_t filt_type,
+ uint8_t filt_cond_type,
+ uint8_t* filt_cond,
+ uint8_t filt_cond_len);
+
+#define HCIC_PARAM_SIZE_SET_EVT_FILTER 9
+
+#define HCI_FILT_COND_FILT_TYPE_OFF 0
+#define HCI_FILT_COND_COND_TYPE_OFF 1
+#define HCI_FILT_COND_FILT_OFF 2
+/* Set Event Filter */
+
+/* Delete Stored Key */
+extern void btsnd_hcic_delete_stored_key(BD_ADDR bd_addr, bool delete_all_flag);
+
+#define HCIC_PARAM_SIZE_DELETE_STORED_KEY 7
+
+#define HCI_DELETE_KEY_BD_ADDR_OFF 0
+#define HCI_DELETE_KEY_ALL_FLAG_OFF 6
+/* Delete Stored Key */
+
+/* Change Local Name */
+extern void btsnd_hcic_change_name(BD_NAME name);
+
+#define HCIC_PARAM_SIZE_CHANGE_NAME BD_NAME_LEN
+
+#define HCI_CHANGE_NAME_NAME_OFF 0
+/* Change Local Name */
+
+#define HCIC_PARAM_SIZE_READ_CMD 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM1 1
+
+#define HCIC_WRITE_PARAM1_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM2 2
+
+#define HCIC_WRITE_PARAM2_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_WRITE_PARAM3 3
+
+#define HCIC_WRITE_PARAM3_PARAM_OFF 0
+
+#define HCIC_PARAM_SIZE_SET_AFH_CHANNELS 10
+
+extern void btsnd_hcic_write_pin_type(uint8_t type); /* Write PIN Type */
+extern void btsnd_hcic_write_auto_accept(uint8_t flag); /* Write Auto Accept */
+extern void btsnd_hcic_read_name(void); /* Read Local Name */
+extern void btsnd_hcic_write_page_tout(
+ uint16_t timeout); /* Write Page Timout */
+extern void btsnd_hcic_write_scan_enable(uint8_t flag); /* Write Scan Enable */
+extern void btsnd_hcic_write_pagescan_cfg(
+ uint16_t interval, uint16_t window); /* Write Page Scan Activity */
+
+#define HCIC_PARAM_SIZE_ENH_SET_ESCO_CONN 59
+#define HCIC_PARAM_SIZE_ENH_ACC_ESCO_CONN 63
+
+#define HCIC_PARAM_SIZE_WRITE_PAGESCAN_CFG 4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF 0
+#define HCI_SCAN_CFG_WINDOW_OFF 2
+/* Write Page Scan Activity */
+
+/* Write Inquiry Scan Activity */
+extern void btsnd_hcic_write_inqscan_cfg(uint16_t interval, uint16_t window);
+
+#define HCIC_PARAM_SIZE_WRITE_INQSCAN_CFG 4
+
+#define HCI_SCAN_CFG_INTERVAL_OFF 0
+#define HCI_SCAN_CFG_WINDOW_OFF 2
+/* Write Inquiry Scan Activity */
+
+extern void btsnd_hcic_write_auth_enable(
+ uint8_t flag); /* Write Authentication Enable */
+extern void btsnd_hcic_write_dev_class(
+ DEV_CLASS dev); /* Write Class of Device */
+extern void btsnd_hcic_write_voice_settings(
+ uint16_t flags); /* Write Voice Settings */
+
+/* Host Controller to Host flow control */
+#define HCI_HOST_FLOW_CTRL_OFF 0
+#define HCI_HOST_FLOW_CTRL_ACL_ON 1
+#define HCI_HOST_FLOW_CTRL_SCO_ON 2
+#define HCI_HOST_FLOW_CTRL_BOTH_ON 3
+
+extern void btsnd_hcic_write_auto_flush_tout(
+ uint16_t handle, uint16_t timeout); /* Write Retransmit Timout */
+
+#define HCIC_PARAM_SIZE_WRITE_AUTO_FLUSH_TOUT 4
+
+#define HCI_FLUSH_TOUT_HANDLE_OFF 0
+#define HCI_FLUSH_TOUT_TOUT_OFF 2
+
+extern void btsnd_hcic_read_tx_power(uint16_t handle,
+ uint8_t type); /* Read Tx Power */
+
+#define HCIC_PARAM_SIZE_READ_TX_POWER 3
+
+#define HCI_READ_TX_POWER_HANDLE_OFF 0
+#define HCI_READ_TX_POWER_TYPE_OFF 2
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT 0x00
+#define HCI_READ_MAXIMUM 0x01
+
+extern void btsnd_hcic_host_num_xmitted_pkts(
+ uint8_t num_handles, uint16_t* handle,
+ uint16_t* num_pkts); /* Set Host Buffer Size */
+
+#define HCIC_PARAM_SIZE_NUM_PKTS_DONE_SIZE sizeof(btmsg_hcic_num_pkts_done_t)
+
+#define MAX_DATA_HANDLES 10
+
+#define HCI_PKTS_DONE_NUM_HANDLES_OFF 0
+#define HCI_PKTS_DONE_HANDLE_OFF 1
+#define HCI_PKTS_DONE_NUM_PKTS_OFF 3
+
+/* Write Link Supervision Timeout */
+extern void btsnd_hcic_write_link_super_tout(uint8_t local_controller_id,
+ uint16_t handle, uint16_t timeout);
+
+#define HCIC_PARAM_SIZE_WRITE_LINK_SUPER_TOUT 4
+
+#define HCI_LINK_SUPER_TOUT_HANDLE_OFF 0
+#define HCI_LINK_SUPER_TOUT_TOUT_OFF 2
+/* Write Link Supervision Timeout */
+
+extern void btsnd_hcic_write_cur_iac_lap(
+ uint8_t num_cur_iac, LAP* const iac_lap); /* Write Current IAC LAP */
+
+#define MAX_IAC_LAPS 0x40
+
+#define HCI_WRITE_IAC_LAP_NUM_OFF 0
+#define HCI_WRITE_IAC_LAP_LAP_OFF 1
+/* Write Current IAC LAP */
+
+extern void btsnd_hcic_get_link_quality(uint16_t handle); /* Get Link Quality */
+extern void btsnd_hcic_read_rssi(uint16_t handle); /* Read RSSI */
+extern void btsnd_hcic_enable_test_mode(
+ void); /* Enable Device Under Test Mode */
+extern void btsnd_hcic_write_pagescan_type(
+ uint8_t type); /* Write Page Scan Type */
+extern void btsnd_hcic_write_inqscan_type(
+ uint8_t type); /* Write Inquiry Scan Type */
+extern void btsnd_hcic_write_inquiry_mode(
+ uint8_t type); /* Write Inquiry Mode */
+
+/* Enhanced setup SCO connection (CSA2) */
+extern void btsnd_hcic_enhanced_set_up_synchronous_connection(
+ uint16_t conn_handle, enh_esco_params_t* p_parms);
+
+/* Enhanced accept SCO connection request (CSA2) */
+extern void btsnd_hcic_enhanced_accept_synchronous_connection(
+ BD_ADDR bd_addr, enh_esco_params_t* p_parms);
+
+#define HCI_DATA_HANDLE_MASK 0x0FFF
+
+#define HCID_GET_HANDLE_EVENT(p) \
+ (uint16_t)((*((uint8_t*)((p) + 1) + (p)->offset) + \
+ (*((uint8_t*)((p) + 1) + (p)->offset + 1) << 8)))
+
+#define HCID_GET_HANDLE(u16) (uint16_t)((u16)&HCI_DATA_HANDLE_MASK)
+
+#define HCI_DATA_EVENT_MASK 3
+#define HCI_DATA_EVENT_OFFSET 12
+#define HCID_GET_EVENT(u16) \
+ (uint8_t)(((u16) >> HCI_DATA_EVENT_OFFSET) & HCI_DATA_EVENT_MASK)
+
+#define HCI_DATA_BCAST_MASK 3
+#define HCI_DATA_BCAST_OFFSET 10
+#define HCID_GET_BCAST(u16) \
+ (uint8_t)(((u16) >> HCI_DATA_BCAST_OFFSET) & HCI_DATA_BCAST_MASK)
+
+#define HCID_GET_ACL_LEN(p) \
+ (uint16_t)((*((uint8_t*)((p) + 1) + (p)->offset + 2) + \
+ (*((uint8_t*)((p) + 1) + (p)->offset + 3) << 8)))
+
+#define HCID_HEADER_SIZE 4
+
+#define HCID_GET_SCO_LEN(p) (*((uint8_t*)((p) + 1) + (p)->offset + 2))
+
+extern void btsnd_hcic_vendor_spec_cmd(void* buffer, uint16_t opcode,
+ uint8_t len, uint8_t* p_data,
+ void* p_cmd_cplt_cback);
+
+/*******************************************************************************
+ * BLE Commands
+ * Note: "local_controller_id" is for transport, not counted in HCI
+ * message size
+ ******************************************************************************/
+#define HCIC_BLE_RAND_DI_SIZE 8
+#define HCIC_BLE_ENCRYT_KEY_SIZE 16
+#define HCIC_BLE_IRK_SIZE 16
+
+#define HCIC_PARAM_SIZE_SET_USED_FEAT_CMD 8
+#define HCIC_PARAM_SIZE_WRITE_RANDOM_ADDR_CMD 6
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS 15
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_RSP 31
+#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE 1
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_PARAM 7
+#define HCIC_PARAM_SIZE_BLE_WRITE_SCAN_ENABLE 2
+#define HCIC_PARAM_SIZE_BLE_CREATE_LL_CONN 25
+#define HCIC_PARAM_SIZE_BLE_CREATE_CONN_CANCEL 0
+#define HCIC_PARAM_SIZE_CLEAR_WHITE_LIST 0
+#define HCIC_PARAM_SIZE_ADD_WHITE_LIST 7
+#define HCIC_PARAM_SIZE_REMOVE_WHITE_LIST 7
+#define HCIC_PARAM_SIZE_BLE_UPD_LL_CONN_PARAMS 14
+#define HCIC_PARAM_SIZE_SET_HOST_CHNL_CLASS 5
+#define HCIC_PARAM_SIZE_READ_CHNL_MAP 2
+#define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT 2
+#define HCIC_PARAM_SIZE_BLE_ENCRYPT 32
+#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED 2
+
+#define HCIC_BLE_RAND_DI_SIZE 8
+#define HCIC_BLE_ENCRYT_KEY_SIZE 16
+#define HCIC_PARAM_SIZE_BLE_START_ENC \
+ (4 + HCIC_BLE_RAND_DI_SIZE + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_REPLY (2 + HCIC_BLE_ENCRYT_KEY_SIZE)
+#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY 2
+#define HCIC_BLE_CHNL_MAP_SIZE 5
+#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA 31
+
+#define HCIC_PARAM_SIZE_BLE_ADD_DEV_RESOLVING_LIST (7 + HCIC_BLE_IRK_SIZE * 2)
+#define HCIC_PARAM_SIZE_BLE_RM_DEV_RESOLVING_LIST 7
+#define HCIC_PARAM_SIZE_BLE_SET_PRIVACY_MODE 8
+#define HCIC_PARAM_SIZE_BLE_CLEAR_RESOLVING_LIST 0
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVING_LIST_SIZE 0
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_PEER 7
+#define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL 7
+#define HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE 1
+#define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT 2
+#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH 6
+#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11
+
+/* ULP HCI command */
+extern void btsnd_hcic_ble_set_evt_mask(BT_EVENT_MASK event_mask);
+
+extern void btsnd_hcic_ble_read_buffer_size(void);
+
+extern void btsnd_hcic_ble_read_local_spt_feat(void);
+
+extern void btsnd_hcic_ble_set_local_used_feat(uint8_t feat_set[8]);
+
+extern void btsnd_hcic_ble_set_random_addr(BD_ADDR random_addr);
+
+extern void btsnd_hcic_ble_write_adv_params(
+ uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
+ uint8_t addr_type_own, uint8_t addr_type_dir, BD_ADDR direct_bda,
+ uint8_t channel_map, uint8_t adv_filter_policy);
+
+extern void btsnd_hcic_ble_read_adv_chnl_tx_power(void);
+
+extern void btsnd_hcic_ble_set_adv_data(uint8_t data_len, uint8_t* p_data);
+
+extern void btsnd_hcic_ble_set_scan_rsp_data(uint8_t data_len,
+ uint8_t* p_scan_rsp);
+
+extern void btsnd_hcic_ble_set_adv_enable(uint8_t adv_enable);
+
+extern void btsnd_hcic_ble_set_scan_params(uint8_t scan_type, uint16_t scan_int,
+ uint16_t scan_win, uint8_t addr_type,
+ uint8_t scan_filter_policy);
+
+extern void btsnd_hcic_ble_set_scan_enable(uint8_t scan_enable,
+ uint8_t duplicate);
+
+extern void btsnd_hcic_ble_create_ll_conn(
+ uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
+ uint8_t addr_type_peer, BD_ADDR bda_peer, uint8_t addr_type_own,
+ uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
+ uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len);
+
+extern void btsnd_hcic_ble_create_conn_cancel(void);
+
+extern void btsnd_hcic_ble_read_white_list_size(void);
+
+extern void btsnd_hcic_ble_clear_white_list(void);
+
+extern void btsnd_hcic_ble_add_white_list(uint8_t addr_type, BD_ADDR bda);
+
+extern void btsnd_hcic_ble_remove_from_white_list(uint8_t addr_type,
+ BD_ADDR bda);
+
+extern void btsnd_hcic_ble_upd_ll_conn_params(
+ uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max,
+ uint16_t conn_latency, uint16_t conn_timeout, uint16_t min_len,
+ uint16_t max_len);
+
+extern void btsnd_hcic_ble_set_host_chnl_class(
+ uint8_t chnl_map[HCIC_BLE_CHNL_MAP_SIZE]);
+
+extern void btsnd_hcic_ble_read_chnl_map(uint16_t handle);
+
+extern void btsnd_hcic_ble_read_remote_feat(uint16_t handle);
+
+extern void btsnd_hcic_ble_encrypt(uint8_t* key, uint8_t key_len,
+ uint8_t* plain_text, uint8_t pt_len,
+ void* p_cmd_cplt_cback);
+
+extern void btsnd_hcic_ble_rand(base::Callback<void(BT_OCTET8)> cb);
+
+extern void btsnd_hcic_ble_start_enc(uint16_t handle,
+ uint8_t rand[HCIC_BLE_RAND_DI_SIZE],
+ uint16_t ediv,
+ uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+extern void btsnd_hcic_ble_ltk_req_reply(uint16_t handle,
+ uint8_t ltk[HCIC_BLE_ENCRYT_KEY_SIZE]);
+
+extern void btsnd_hcic_ble_ltk_req_neg_reply(uint16_t handle);
+
+extern void btsnd_hcic_ble_read_supported_states(void);
+
+extern void btsnd_hcic_ble_write_host_supported(uint8_t le_host_spt,
+ uint8_t simul_le_host_spt);
+
+extern void btsnd_hcic_ble_read_host_supported(void);
+
+extern void btsnd_hcic_ble_receiver_test(uint8_t rx_freq);
+
+extern void btsnd_hcic_ble_transmitter_test(uint8_t tx_freq,
+ uint8_t test_data_len,
+ uint8_t payload);
+extern void btsnd_hcic_ble_test_end(void);
+
+#if (BLE_LLT_INCLUDED == TRUE)
+
+#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_REPLY 14
+extern void btsnd_hcic_ble_rc_param_req_reply(
+ uint16_t handle, uint16_t conn_int_min, uint16_t conn_int_max,
+ uint16_t conn_latency, uint16_t conn_timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len);
+
+#define HCIC_PARAM_SIZE_BLE_RC_PARAM_REQ_NEG_REPLY 3
+extern void btsnd_hcic_ble_rc_param_req_neg_reply(uint16_t handle,
+ uint8_t reason);
+
+#endif /* BLE_LLT_INCLUDED */
+
+extern void btsnd_hcic_ble_set_data_length(uint16_t conn_handle,
+ uint16_t tx_octets,
+ uint16_t tx_time);
+
+extern void btsnd_hcic_ble_add_device_resolving_list(
+ uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
+
+struct scanning_phy_cfg {
+ uint8_t scan_type;
+ uint16_t scan_int;
+ uint16_t scan_win;
+};
+
+extern void btsnd_hcic_ble_set_extended_scan_params(
+ uint8_t own_address_type, uint8_t scanning_filter_policy,
+ uint8_t scanning_phys, scanning_phy_cfg* phy_cfg);
+
+extern void btsnd_hcic_ble_set_extended_scan_enable(uint8_t enable,
+ uint8_t filter_duplicates,
+ uint16_t duration,
+ uint16_t period);
+
+struct EXT_CONN_PHY_CFG {
+ uint16_t scan_int;
+ uint16_t scan_win;
+ uint16_t conn_int_min;
+ uint16_t conn_int_max;
+ uint16_t conn_latency;
+ uint16_t sup_timeout;
+ uint16_t min_ce_len;
+ uint16_t max_ce_len;
+};
+
+extern void btsnd_hcic_ble_ext_create_conn(
+ uint8_t init_filter_policy, uint8_t addr_type_own, uint8_t addr_type_peer,
+ BD_ADDR bda_peer, uint8_t initiating_phys, EXT_CONN_PHY_CFG* phy_cfg);
+
+extern void btsnd_hcic_ble_add_device_resolving_list(
+ uint8_t addr_type_peer, BD_ADDR bda_peer,
+ uint8_t irk_peer[HCIC_BLE_IRK_SIZE], uint8_t irk_local[HCIC_BLE_IRK_SIZE]);
+
+extern void btsnd_hcic_ble_rm_device_resolving_list(uint8_t addr_type_peer,
+ BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_set_privacy_mode(uint8_t addr_type_peer,
+ BD_ADDR bda_peer,
+ uint8_t privacy_type);
+
+extern void btsnd_hcic_ble_clear_resolving_list(void);
+
+extern void btsnd_hcic_ble_read_resolvable_addr_peer(uint8_t addr_type_peer,
+ BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_read_resolvable_addr_local(uint8_t addr_type_peer,
+ BD_ADDR bda_peer);
+
+extern void btsnd_hcic_ble_set_addr_resolution_enable(
+ uint8_t addr_resolution_enable);
+
+extern void btsnd_hcic_ble_set_rand_priv_addr_timeout(uint16_t rpa_timout);
+
+extern void btsnd_hcic_read_authenticated_payload_tout(uint16_t handle);
+
+extern void btsnd_hcic_write_authenticated_payload_tout(uint16_t handle,
+ uint16_t timeout);
+
+#define HCIC_PARAM_SIZE_WRITE_AUTHENT_PAYLOAD_TOUT 4
+
+#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_HANDLE_OFF 0
+#define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_TOUT_OFF 2
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/hidd_api.h b/mtkbt/code/bt/stack/include/hidd_api.h
new file mode 100755
index 0000000..0db58dc
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/hidd_api.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef HIDD_API_H
+#define HIDD_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+enum { HID_CHANNEL_INTR, HID_CHANNEL_CTRL };
+
+/*
+ HID_DHOST_EVT_OPEN - connected to host device (CTRL and INTR), data = n/a
+ HID_DHOST_EVT_CLOSE - disconnected from host device, data=reason
+ HID_DHOST_EVT_GET_REPORT - got GET_REPORT from host
+ HID_DHOST_EVT_SET_REPORT - got SET_REPORT from host
+ HID_DHOST_EVT_SET_PROTOCOL - got SET_PROTOCOL from host
+*/
+
+enum {
+ HID_DHOST_EVT_OPEN,
+ HID_DHOST_EVT_CLOSE,
+ HID_DHOST_EVT_GET_REPORT,
+ HID_DHOST_EVT_SET_REPORT,
+ HID_DHOST_EVT_SET_PROTOCOL,
+ HID_DHOST_EVT_INTR_DATA,
+ HID_DHOST_EVT_VC_UNPLUG,
+ HID_DHOST_EVT_SUSPEND,
+ HID_DHOST_EVT_EXIT_SUSPEND,
+};
+typedef void(tHID_DEV_HOST_CALLBACK)(BD_ADDR bd_addr, uint8_t event,
+ uint32_t data, BT_HDR* p_buf);
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ *
+ * Function HID_DevInit
+ *
+ * Description Initializes control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void HID_DevInit(void);
+
+/*******************************************************************************
+ *
+ * Function HID_DevRegister
+ *
+ * Description Registers HID device with lower layers
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback);
+
+/*******************************************************************************
+ *
+ * Function HID_DevDeregister
+ *
+ * Description Deregisters HID device with lower layers
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevDeregister(void);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetSecurityLevel
+ *
+ * Description Sets security level for HID device connections
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl);
+
+/*******************************************************************************
+ *
+ * Function HID_DevAddRecord
+ *
+ * Description Creates SDP record for HID device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name,
+ char* p_description, char* p_provider,
+ uint16_t subclass, uint16_t desc_len,
+ uint8_t* p_desc_data);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSendReport
+ *
+ * Description Sends report
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id,
+ uint16_t len, uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function HID_DevVirtualCableUnplug
+ *
+ * Description Sends Virtual Cable Unplug
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevVirtualCableUnplug(void);
+
+/*******************************************************************************
+ *
+ * Function HID_DevPlugDevice
+ *
+ * Description Establishes virtual cable to given host
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevPlugDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function HID_DevUnplugDevice
+ *
+ * Description Unplugs virtual cable from given host
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr);
+
+/*******************************************************************************
+ *
+ * Function HID_DevConnect
+ *
+ * Description Connects to device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevConnect(void);
+
+/*******************************************************************************
+ *
+ * Function HID_DevDisconnect
+ *
+ * Description Disconnects from device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevDisconnect(void);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetIncomingPolicy
+ *
+ * Description Sets policy for incoming connections (allowed/disallowed)
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetIncomingPolicy(bool allow);
+
+/*******************************************************************************
+ *
+ * Function HID_DevReportError
+ *
+ * Description Reports error for Set Report via HANDSHAKE
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevReportError(uint8_t error);
+
+/*******************************************************************************
+ *
+ * Function HID_DevGetDevice
+ *
+ * Description Returns the BD Address of virtually cabled device
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevGetDevice(BD_ADDR* addr);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetIncomingQos
+ *
+ * Description Sets Incoming QoS values for Interrupt L2CAP Channel
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetIncomingQos(
+ uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
+ uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetOutgoingQos
+ *
+ * Description Sets Outgoing QoS values for Interrupt L2CAP Channel
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_DevSetOutgoingQos(
+ uint8_t service_type, uint32_t token_rate, uint32_t token_bucket_size,
+ uint32_t peak_bandwidth, uint32_t latency, uint32_t delay_variation);
+
+/*******************************************************************************
+ *
+ * Function HID_DevSetTraceLevel
+ *
+ * Description This function sets the trace level for HID Dev. If called
+ * with a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t HID_DevSetTraceLevel(uint8_t new_level);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HIDD_API_H */
diff --git a/mtkbt/code/bt/stack/include/hiddefs.h b/mtkbt/code/bt/stack/include/hiddefs.h
new file mode 100755
index 0000000..55f7e55
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/hiddefs.h
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains HID protocol definitions
+ *
+ ******************************************************************************/
+
+#ifndef HIDDEFS_H
+#define HIDDEFS_H
+
+#include "sdp_api.h"
+/*
+ * tHID_STATUS: HID result codes, returned by HID and device and host functions.
+*/
+enum {
+ HID_SUCCESS,
+ HID_ERR_NOT_REGISTERED,
+ HID_ERR_ALREADY_REGISTERED,
+ HID_ERR_NO_RESOURCES,
+ HID_ERR_NO_CONNECTION,
+ HID_ERR_INVALID_PARAM,
+ HID_ERR_UNSUPPORTED,
+ HID_ERR_UNKNOWN_COMMAND,
+ HID_ERR_CONGESTED,
+ HID_ERR_CONN_IN_PROCESS,
+ HID_ERR_ALREADY_CONN,
+ HID_ERR_DISCONNECTING,
+ HID_ERR_SET_CONNABLE_FAIL,
+ /* Device specific error codes */
+ HID_ERR_HOST_UNKNOWN,
+ HID_ERR_L2CAP_FAILED,
+ HID_ERR_AUTH_FAILED,
+ HID_ERR_SDP_BUSY,
+ HID_ERR_GATT,
+
+ HID_ERR_INVALID = 0xFF
+};
+
+typedef uint8_t tHID_STATUS;
+
+#define HID_L2CAP_CONN_FAIL \
+ (0x0100) /* Connection Attempt was made but failed */
+#define HID_L2CAP_REQ_FAIL (0x0200) /* L2CAP_ConnectReq API failed */
+#define HID_L2CAP_CFG_FAIL \
+ (0x0400) /* L2CAP Configuration was rejected by peer */
+
+/* Define the HID transaction types
+*/
+#define HID_TRANS_HANDSHAKE (0)
+#define HID_TRANS_CONTROL (1)
+#define HID_TRANS_GET_REPORT (4)
+#define HID_TRANS_SET_REPORT (5)
+#define HID_TRANS_GET_PROTOCOL (6)
+#define HID_TRANS_SET_PROTOCOL (7)
+#define HID_TRANS_GET_IDLE (8)
+#define HID_TRANS_SET_IDLE (9)
+#define HID_TRANS_DATA (10)
+#define HID_TRANS_DATAC (11)
+
+#define HID_GET_TRANS_FROM_HDR(x) (((x) >> 4) & 0x0f)
+#define HID_GET_PARAM_FROM_HDR(x) ((x)&0x0f)
+#define HID_BUILD_HDR(t, p) (uint8_t)(((t) << 4) | ((p)&0x0f))
+
+/* Parameters for Handshake
+*/
+#define HID_PAR_HANDSHAKE_RSP_SUCCESS (0)
+#define HID_PAR_HANDSHAKE_RSP_NOT_READY (1)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID (2)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ (3)
+#define HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM (4)
+#define HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN (14)
+#define HID_PAR_HANDSHAKE_RSP_ERR_FATAL (15)
+
+/* Parameters for Control
+*/
+#define HID_PAR_CONTROL_NOP (0)
+#define HID_PAR_CONTROL_HARD_RESET (1)
+#define HID_PAR_CONTROL_SOFT_RESET (2)
+#define HID_PAR_CONTROL_SUSPEND (3)
+#define HID_PAR_CONTROL_EXIT_SUSPEND (4)
+#define HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG (5)
+
+/* Different report types in get, set, data
+*/
+#define HID_PAR_REP_TYPE_MASK (0x03)
+#define HID_PAR_REP_TYPE_OTHER (0x00)
+#define HID_PAR_REP_TYPE_INPUT (0x01)
+#define HID_PAR_REP_TYPE_OUTPUT (0x02)
+#define HID_PAR_REP_TYPE_FEATURE (0x03)
+
+/* Parameters for Get Report
+*/
+
+/* Buffer size in two bytes after Report ID */
+#define HID_PAR_GET_REP_BUFSIZE_FOLLOWS (0x08)
+
+/* Parameters for Protocol Type
+*/
+#define HID_PAR_PROTOCOL_MASK (0x01)
+#define HID_PAR_PROTOCOL_REPORT (0x01)
+#define HID_PAR_PROTOCOL_BOOT_MODE (0x00)
+
+#define HID_PAR_REP_TYPE_MASK (0x03)
+
+/* Descriptor types in the SDP record
+*/
+#define HID_SDP_DESCRIPTOR_REPORT (0x22)
+#define HID_SDP_DESCRIPTOR_PHYSICAL (0x23)
+
+typedef struct desc_info {
+ uint16_t dl_len;
+ uint8_t* dsc_list;
+} tHID_DEV_DSCP_INFO;
+
+#define HID_SSR_PARAM_INVALID 0xffff
+
+typedef struct sdp_info {
+ char svc_name[HID_MAX_SVC_NAME_LEN]; /*Service Name */
+ char svc_descr[HID_MAX_SVC_DESCR_LEN]; /*Service Description*/
+ char prov_name[HID_MAX_PROV_NAME_LEN]; /*Provider Name.*/
+ uint16_t rel_num; /*Release Number */
+ uint16_t hpars_ver; /*HID Parser Version.*/
+ uint16_t ssr_max_latency; /* HIDSSRHostMaxLatency value, if
+ HID_SSR_PARAM_INVALID not used*/
+ uint16_t
+ ssr_min_tout; /* HIDSSRHostMinTimeout value, if HID_SSR_PARAM_INVALID not
+ used* */
+ uint8_t sub_class; /*Device Subclass.*/
+ uint8_t ctry_code; /*Country Code.*/
+ uint16_t sup_timeout; /* Supervisory Timeout */
+
+ tHID_DEV_DSCP_INFO dscp_info; /* Descriptor list and Report list to be set in
+ the SDP record.
+ This parameter is used if
+ HID_DEV_USE_GLB_SDP_REC is set to false.*/
+ tSDP_DISC_REC* p_sdp_layer_rec;
+} tHID_DEV_SDP_INFO;
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/hidh_api.h b/mtkbt/code/bt/stack/include/hidh_api.h
new file mode 100755
index 0000000..abee12b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/hidh_api.h
@@ -0,0 +1,245 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2002-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef HIDH_API_H
+#define HIDH_API_H
+
+#include "hiddefs.h"
+#include "sdp_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+enum {
+ HID_SDP_NO_SERV_UUID = (SDP_ILLEGAL_PARAMETER + 1),
+ HID_SDP_MANDATORY_MISSING
+};
+
+/* Attributes mask values to be used in HID_HostAddDev API */
+#define HID_VIRTUAL_CABLE 0x0001
+#define HID_NORMALLY_CONNECTABLE 0x0002
+#define HID_RECONN_INIT 0x0004
+#define HID_SDP_DISABLE 0x0008
+#define HID_BATTERY_POWER 0x0010
+#define HID_REMOTE_WAKE 0x0020
+#define HID_SUP_TOUT_AVLBL 0x0040
+#define HID_SSR_MAX_LATENCY 0x0080
+#define HID_SSR_MIN_TOUT 0x0100
+
+#define HID_SEC_REQUIRED 0x8000
+#define HID_ATTR_MASK_IGNORE 0
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+typedef void(tHID_HOST_SDP_CALLBACK)(uint16_t result, uint16_t attr_mask,
+ tHID_DEV_SDP_INFO* sdp_rec);
+
+/* HID-HOST returns the events in the following table to the application via
+ * tHID_HOST_DEV_CALLBACK
+ * HID_HDEV_EVT_OPEN Connected to device with Interrupt and Control Channels
+ * in OPEN state.
+ * Data = NA
+ * HID_HDEV_EVT_CLOSE Connection with device is closed. Data = reason code.
+ * HID_HDEV_EVT_RETRYING Lost connection is being re-connected.
+ * Data = Retrial number
+ * HID_HDEV_EVT_IN_REPORT Device sent an input report Data = Report Type
+ * pdata = pointer to
+ * BT_HDR
+ * (GKI buffer with report
+ * data.)
+ * HID_HDEV_EVT_HANDSHAKE Device sent SET_REPORT Data = Result-code
+ * pdata = NA.
+ * HID_HDEV_EVT_VC_UNPLUG Device sent Virtual Unplug Data = NA. pdata = NA.
+ */
+
+enum {
+ HID_HDEV_EVT_OPEN,
+ HID_HDEV_EVT_CLOSE,
+ HID_HDEV_EVT_RETRYING,
+ HID_HDEV_EVT_INTR_DATA,
+ HID_HDEV_EVT_INTR_DATC,
+ HID_HDEV_EVT_CTRL_DATA,
+ HID_HDEV_EVT_CTRL_DATC,
+ HID_HDEV_EVT_HANDSHAKE,
+ HID_HDEV_EVT_VC_UNPLUG
+};
+typedef void(tHID_HOST_DEV_CALLBACK)(
+ uint8_t dev_handle, BD_ADDR addr,
+ uint8_t event, /* Event from HID-DEVICE. */
+ uint32_t data, /* Integer data corresponding to the event.*/
+ BT_HDR* p_buf); /* Pointer data corresponding to the event. */
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function HID_HostGetSDPRecord
+ *
+ * Description This function reads the device SDP record.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostGetSDPRecord(BD_ADDR addr, tSDP_DISCOVERY_DB* p_db,
+ uint32_t db_len,
+ tHID_HOST_SDP_CALLBACK* sdp_cback);
+
+/*******************************************************************************
+ *
+ * Function HID_HostRegister
+ *
+ * Description This function registers HID-Host with lower layers.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback);
+
+/*******************************************************************************
+ *
+ * Function HID_HostDeregister
+ *
+ * Description This function is called when the host is about power down.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostDeregister(void);
+
+/*******************************************************************************
+ *
+ * Function HID_HostAddDev
+ *
+ * Description This is called so HID-host may manage this device.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostAddDev(BD_ADDR addr, uint16_t attr_mask,
+ uint8_t* handle);
+
+/*******************************************************************************
+ *
+ * Function HID_HostRemoveDev
+ *
+ * Description Removes the device from the list of devices that the host
+ * has to manage.
+ *
+ * Returns tHID_STATUS
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function HID_HostOpenDev
+ *
+ * Description This function is called when the user wants to initiate a
+ * connection attempt to a device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostOpenDev(uint8_t dev_handle);
+
+/*******************************************************************************
+ *
+ * Function HID_HostWriteDev
+ *
+ * Description This function is called when the host has a report to send.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type,
+ uint8_t param, uint16_t data,
+ uint8_t report_id, BT_HDR* pbuf);
+
+/*******************************************************************************
+ *
+ * Function HID_HostCloseDev
+ *
+ * Description This function disconnects the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern tHID_STATUS HID_HostCloseDev(uint8_t dev_handle);
+
+/**M: HID device reconnect fail for collision@{*/
+/*******************************************************************************
+**
+** Function HID_HostCloseCollisionDev
+**
+** Description This function disconnects the device in collision.
+**
+** Returns void
+**
+*******************************************************************************/
+extern tHID_STATUS HID_HostCloseCollisionDev(uint8_t dev_handle);
+/**@}*/
+
+
+/*******************************************************************************
+ * Function HID_HostInit
+ *
+ * Description Initialize the control block and trace variable
+ *
+ * Returns void
+ ******************************************************************************/
+extern void HID_HostInit(void);
+
+/*******************************************************************************
+ * Function HID_HostSetSecurityLevel
+ *
+ * Description This function sets the security level for the devices which
+ * are marked by application as requiring security
+ *
+ * Returns tHID_STATUS
+ ******************************************************************************/
+extern tHID_STATUS HID_HostSetSecurityLevel(const char serv_name[],
+ uint8_t sec_lvl);
+
+/*******************************************************************************
+ *
+ * Function hid_known_hid_device
+ *
+ * Description This function checks if this device is of type HID Device
+ *
+ * Returns true if device exists else false
+ *
+ ******************************************************************************/
+bool hid_known_hid_device(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function HID_HostSetTraceLevel
+ *
+ * Description Set the trace level for HID Host. If called with the value
+ * 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t HID_HostSetTraceLevel(uint8_t new_level);
+
+#endif /* HIDH_API_H */
diff --git a/mtkbt/code/bt/stack/include/l2c_api.h b/mtkbt/code/bt/stack/include/l2c_api.h
new file mode 100755
index 0000000..db4b46d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/l2c_api.h
@@ -0,0 +1,1252 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the L2CAP API definitions
+ *
+ ******************************************************************************/
+#ifndef L2C_API_H
+#define L2C_API_H
+
+#include <stdbool.h>
+
+#include "bt_target.h"
+#include "hcidefs.h"
+#include "l2cdefs.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Define the minimum offset that L2CAP needs in a buffer. This is made up of
+ * HCI type(1), len(2), handle(2), L2CAP len(2) and CID(2) => 9
+*/
+#define L2CAP_MIN_OFFSET 13 /* plus control(2), SDU length(2) */
+
+#define L2CAP_LCC_SDU_LENGTH 2
+#define L2CAP_LCC_OFFSET \
+ (L2CAP_MIN_OFFSET + L2CAP_LCC_SDU_LENGTH) /* plus SDU length(2) */
+
+/* ping result codes */
+#define L2CAP_PING_RESULT_OK 0 /* Ping reply received OK */
+#define L2CAP_PING_RESULT_NO_LINK 1 /* Link could not be setup */
+#define L2CAP_PING_RESULT_NO_RESP 2 /* Remote L2CAP did not reply */
+
+/* result code for L2CA_DataWrite() */
+#define L2CAP_DW_FAILED false
+#define L2CAP_DW_SUCCESS true
+#define L2CAP_DW_CONGESTED 2
+
+/* Values for priority parameter to L2CA_SetAclPriority */
+#define L2CAP_PRIORITY_NORMAL 0
+#define L2CAP_PRIORITY_HIGH 1
+
+/* Values for priority parameter to L2CA_SetTxPriority */
+#define L2CAP_CHNL_PRIORITY_HIGH 0
+#define L2CAP_CHNL_PRIORITY_MEDIUM 1
+#define L2CAP_CHNL_PRIORITY_LOW 2
+
+typedef uint8_t tL2CAP_CHNL_PRIORITY;
+
+/* Values for Tx/Rx data rate parameter to L2CA_SetChnlDataRate */
+#define L2CAP_CHNL_DATA_RATE_HIGH 3
+#define L2CAP_CHNL_DATA_RATE_MEDIUM 2
+#define L2CAP_CHNL_DATA_RATE_LOW 1
+#define L2CAP_CHNL_DATA_RATE_NO_TRAFFIC 0
+
+typedef uint8_t tL2CAP_CHNL_DATA_RATE;
+
+/* Data Packet Flags (bits 2-15 are reserved) */
+/* layer specific 14-15 bits are used for FCR SAR */
+#define L2CAP_FLUSHABLE_MASK 0x0003
+#define L2CAP_FLUSHABLE_CH_BASED 0x0000
+#define L2CAP_FLUSHABLE_PKT 0x0001
+#define L2CAP_NON_FLUSHABLE_PKT 0x0002
+
+/* L2CA_FlushChannel num_to_flush definitions */
+#define L2CAP_FLUSH_CHANS_ALL 0xffff
+#define L2CAP_FLUSH_CHANS_GET 0x0000
+
+/* special CID for Multi-AV for reporting congestion */
+#define L2CAP_MULTI_AV_CID 0
+
+/* length of the HCI header block */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN 8
+
+/* length of padding for 4 bytes align */
+#define L2CAP_MULTI_AV_PADDING_LEN 2
+
+/* length of the HCI header block with padding for FCR */
+/* HCI header(4) + SNK count(1) + FCR bits(1) + AV data length(2) + padding(2)
+ */
+#define L2CAP_MULTI_AV_HCI_HDR_LEN_WITH_PADDING 10
+
+/* length of the L2CAP header block */
+/* HCI header(4) + L2CAP header(4) + padding(4) or control word(2) + FCS(2) */
+#define L2CAP_MULTI_AV_L2C_HDR_LEN 12
+
+/* definition used for L2CA_SetDesireRole */
+#define L2CAP_ROLE_SLAVE HCI_ROLE_SLAVE
+#define L2CAP_ROLE_MASTER HCI_ROLE_MASTER
+/* set this bit to allow switch at create conn */
+#define L2CAP_ROLE_ALLOW_SWITCH 0x80
+/* set this bit to disallow switch at create conn */
+#define L2CAP_ROLE_DISALLOW_SWITCH 0x40
+#define L2CAP_ROLE_CHECK_SWITCH 0xC0
+
+/* Values for 'allowed_modes' field passed in structure tL2CAP_ERTM_INFO
+*/
+#define L2CAP_FCR_CHAN_OPT_BASIC (1 << L2CAP_FCR_BASIC_MODE)
+#define L2CAP_FCR_CHAN_OPT_ERTM (1 << L2CAP_FCR_ERTM_MODE)
+#define L2CAP_FCR_CHAN_OPT_STREAM (1 << L2CAP_FCR_STREAM_MODE)
+
+#define L2CAP_FCR_CHAN_OPT_ALL_MASK \
+ (L2CAP_FCR_CHAN_OPT_BASIC | L2CAP_FCR_CHAN_OPT_ERTM | \
+ L2CAP_FCR_CHAN_OPT_STREAM)
+
+/* Validity check for PSM. PSM values must be odd. Also, all PSM values must
+ * be assigned such that the least significant bit of the most sigificant
+ * octet equals zero.
+*/
+#define L2C_INVALID_PSM(psm) (((psm)&0x0101) != 0x0001)
+#define L2C_IS_VALID_PSM(psm) (((psm)&0x0101) == 0x0001)
+#define L2C_IS_VALID_LE_PSM(psm) (((psm) > 0x0000) && ((psm) < 0x0100))
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+typedef struct {
+#define L2CAP_FCR_BASIC_MODE 0x00
+#define L2CAP_FCR_ERTM_MODE 0x03
+#define L2CAP_FCR_STREAM_MODE 0x04
+#define L2CAP_FCR_LE_COC_MODE 0x05
+
+ uint8_t mode;
+
+ uint8_t tx_win_sz;
+ uint8_t max_transmit;
+ uint16_t rtrans_tout;
+ uint16_t mon_tout;
+ uint16_t mps;
+} tL2CAP_FCR_OPTS;
+
+/* Define a structure to hold the configuration parameters. Since the
+ * parameters are optional, for each parameter there is a boolean to
+ * use to signify its presence or absence.
+*/
+typedef struct {
+ uint16_t result; /* Only used in confirm messages */
+ bool mtu_present;
+ uint16_t mtu;
+ bool qos_present;
+ FLOW_SPEC qos;
+ bool flush_to_present;
+ uint16_t flush_to;
+ bool fcr_present;
+ tL2CAP_FCR_OPTS fcr;
+ bool fcs_present; /* Optionally bypasses FCS checks */
+ uint8_t fcs; /* '0' if desire is to bypass FCS, otherwise '1' */
+ bool ext_flow_spec_present;
+ tHCI_EXT_FLOW_SPEC ext_flow_spec;
+ uint16_t flags; /* bit 0: 0-no continuation, 1-continuation */
+} tL2CAP_CFG_INFO;
+
+/* Define a structure to hold the configuration parameter for LE L2CAP
+ * connection oriented channels.
+*/
+typedef struct {
+ uint16_t mtu;
+ uint16_t mps;
+ uint16_t credits;
+} tL2CAP_LE_CFG_INFO;
+
+/* L2CAP channel configured field bitmap */
+#define L2CAP_CH_CFG_MASK_MTU 0x0001
+#define L2CAP_CH_CFG_MASK_QOS 0x0002
+#define L2CAP_CH_CFG_MASK_FLUSH_TO 0x0004
+#define L2CAP_CH_CFG_MASK_FCR 0x0008
+#define L2CAP_CH_CFG_MASK_FCS 0x0010
+#define L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC 0x0020
+
+typedef uint16_t tL2CAP_CH_CFG_BITS;
+
+/*********************************
+ * Callback Functions Prototypes
+ *********************************/
+
+/* Connection indication callback prototype. Parameters are
+ * BD Address of remote
+ * Local CID assigned to the connection
+ * PSM that the remote wants to connect to
+ * Identifier that the remote sent
+*/
+typedef void(tL2CA_CONNECT_IND_CB)(BD_ADDR, uint16_t, uint16_t, uint8_t);
+
+/* Connection confirmation callback prototype. Parameters are
+ * Local CID
+ * Result - 0 = connected, non-zero means failure reason
+*/
+typedef void(tL2CA_CONNECT_CFM_CB)(uint16_t, uint16_t);
+
+/* Connection pending callback prototype. Parameters are
+ * Local CID
+*/
+typedef void(tL2CA_CONNECT_PND_CB)(uint16_t);
+
+/* Configuration indication callback prototype. Parameters are
+ * Local CID assigned to the connection
+ * Pointer to configuration info
+*/
+typedef void(tL2CA_CONFIG_IND_CB)(uint16_t, tL2CAP_CFG_INFO*);
+
+/* Configuration confirm callback prototype. Parameters are
+ * Local CID assigned to the connection
+ * Pointer to configuration info
+*/
+typedef void(tL2CA_CONFIG_CFM_CB)(uint16_t, tL2CAP_CFG_INFO*);
+
+/* Disconnect indication callback prototype. Parameters are
+ * Local CID
+ * Boolean whether upper layer should ack this
+*/
+typedef void(tL2CA_DISCONNECT_IND_CB)(uint16_t, bool);
+
+/* Disconnect confirm callback prototype. Parameters are
+ * Local CID
+ * Result
+*/
+typedef void(tL2CA_DISCONNECT_CFM_CB)(uint16_t, uint16_t);
+
+/* QOS Violation indication callback prototype. Parameters are
+ * BD Address of violating device
+*/
+typedef void(tL2CA_QOS_VIOLATION_IND_CB)(BD_ADDR);
+
+/* Data received indication callback prototype. Parameters are
+ * Local CID
+ * Address of buffer
+*/
+typedef void(tL2CA_DATA_IND_CB)(uint16_t, BT_HDR*);
+
+/* Echo response callback prototype. Note that this is not included in the
+ * registration information, but is passed to L2CAP as part of the API to
+ * actually send an echo request. Parameters are
+ * Result
+*/
+typedef void(tL2CA_ECHO_RSP_CB)(uint16_t);
+
+/* Callback function prototype to pass broadcom specific echo response */
+/* to the upper layer */
+typedef void(tL2CA_ECHO_DATA_CB)(BD_ADDR, uint16_t, uint8_t*);
+
+/* Congestion status callback protype. This callback is optional. If
+ * an application tries to send data when the transmit queue is full,
+ * the data will anyways be dropped. The parameter is:
+ * Local CID
+ * true if congested, false if uncongested
+*/
+typedef void(tL2CA_CONGESTION_STATUS_CB)(uint16_t, bool);
+
+/* Callback prototype for number of packets completed events.
+ * This callback notifies the application when Number of Completed Packets
+ * event has been received.
+ * This callback is originally designed for 3DG devices.
+ * The parameter is:
+ * peer BD_ADDR
+*/
+typedef void(tL2CA_NOCP_CB)(BD_ADDR);
+
+/* Transmit complete callback protype. This callback is optional. If
+ * set, L2CAP will call it when packets are sent or flushed. If the
+ * count is 0xFFFF, it means all packets are sent for that CID (eRTM
+ * mode only). The parameters are:
+ * Local CID
+ * Number of SDUs sent or dropped
+*/
+typedef void(tL2CA_TX_COMPLETE_CB)(uint16_t, uint16_t);
+
+/* Define the structure that applications use to register with
+ * L2CAP. This structure includes callback functions. All functions
+ * MUST be provided, with the exception of the "connect pending"
+ * callback and "congestion status" callback.
+*/
+typedef struct {
+ tL2CA_CONNECT_IND_CB* pL2CA_ConnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB* pL2CA_ConnectCfm_Cb;
+ tL2CA_CONNECT_PND_CB* pL2CA_ConnectPnd_Cb;
+ tL2CA_CONFIG_IND_CB* pL2CA_ConfigInd_Cb;
+ tL2CA_CONFIG_CFM_CB* pL2CA_ConfigCfm_Cb;
+ tL2CA_DISCONNECT_IND_CB* pL2CA_DisconnectInd_Cb;
+ tL2CA_DISCONNECT_CFM_CB* pL2CA_DisconnectCfm_Cb;
+ tL2CA_QOS_VIOLATION_IND_CB* pL2CA_QoSViolationInd_Cb;
+ tL2CA_DATA_IND_CB* pL2CA_DataInd_Cb;
+ tL2CA_CONGESTION_STATUS_CB* pL2CA_CongestionStatus_Cb;
+ tL2CA_TX_COMPLETE_CB* pL2CA_TxComplete_Cb;
+
+} tL2CAP_APPL_INFO;
+
+/* Define the structure that applications use to create or accept
+ * connections with enhanced retransmission mode.
+*/
+typedef struct {
+ uint8_t preferred_mode;
+ uint8_t allowed_modes;
+ uint16_t user_rx_buf_size;
+ uint16_t user_tx_buf_size;
+ uint16_t fcr_rx_buf_size;
+ uint16_t fcr_tx_buf_size;
+
+} tL2CAP_ERTM_INFO;
+
+#define L2CA_REGISTER(a, b, c) L2CA_Register(a, (tL2CAP_APPL_INFO*)(b))
+#define L2CA_DEREGISTER(a) L2CA_Deregister(a)
+#define L2CA_CONNECT_REQ(a, b, c) L2CA_ErtmConnectReq(a, b, c)
+#define L2CA_CONNECT_RSP(a, b, c, d, e, f) L2CA_ErtmConnectRsp(a, b, c, d, e, f)
+#define L2CA_CONFIG_REQ(a, b) L2CA_ConfigReq(a, b)
+#define L2CA_CONFIG_RSP(a, b) L2CA_ConfigRsp(a, b)
+#define L2CA_DISCONNECT_REQ(a) L2CA_DisconnectReq(a)
+#define L2CA_DISCONNECT_RSP(a) L2CA_DisconnectRsp(a)
+#define L2CA_DATA_WRITE(a, b) L2CA_DataWrite(a, b)
+#define L2CA_REGISTER_COC(a, b, c) L2CA_RegisterLECoc(a, (tL2CAP_APPL_INFO*)(b))
+#define L2CA_DEREGISTER_COC(a) L2CA_DeregisterLECoc(a)
+#define L2CA_CONNECT_COC_REQ(a, b, c) L2CA_ConnectLECocReq(a, b, c)
+#define L2CA_CONNECT_COC_RSP(a, b, c, d, e, f) \
+ L2CA_ConnectLECocRsp(a, b, c, d, e, f)
+#define L2CA_GET_PEER_COC_CONFIG(a, b) L2CA_GetPeerLECocConfig(a, b)
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function L2CA_Register
+ *
+ * Description Other layers call this function to register for L2CAP
+ * services.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectReq() and
+ * BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Deregister
+ *
+ * Description Other layers call this function to deregister for L2CAP
+ * services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void L2CA_Deregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_AllocatePSM
+ *
+ * Description Other layers call this function to find an unused PSM for
+ * L2CAP services.
+ *
+ * Returns PSM to use.
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_AllocatePSM(void);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_ConnectReq(uint16_t psm, BD_ADDR p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+extern bool L2CA_ConnectRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection that needs to use Enhanced Retransmission Mode.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_ErtmConnectReq(uint16_t psm, BD_ADDR p_bd_addr,
+ tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterLECoc
+ *
+ * Description Other layers call this function to register for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectLECocReq()
+ * and BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DeregisterLECoc
+ *
+ * Description Other layers call this function to deregister for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void L2CA_DeregisterLECoc(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocReq
+ *
+ * Description Higher layers call this function to create an L2CAP LE COC.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_ConnectLECocReq(uint16_t psm, BD_ADDR p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP LE COC connection, for which they had gotten a connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+extern bool L2CA_ConnectLECocRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerLECocConfig
+ *
+ * Description Get peers configuration for LE Connection Oriented Channel.
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+extern bool L2CA_GetPeerLECocConfig(uint16_t lcid,
+ tL2CAP_LE_CFG_INFO* peer_cfg);
+
+// This function sets the callback routines for the L2CAP connection referred to
+// by |local_cid|. The callback routines can only be modified for outgoing
+// connections established by |L2CA_ConnectReq| or accepted incoming
+// connections. |callbacks| must not be NULL. This function returns true if the
+// callbacks could be updated, false if not (e.g. |local_cid| was not found).
+bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
+ const tL2CAP_APPL_INFO* callbacks);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback, and for which the higher layer wants
+ * to use Enhanced Retransmission Mode.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+extern bool L2CA_ErtmConnectRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigReq
+ *
+ * Description Higher layers call this function to send configuration.
+ *
+ * Returns true if configuration sent, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigRsp
+ *
+ * Description Higher layers call this function to send a configuration
+ * response.
+ *
+ * Returns true if configuration response sent, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectReq
+ *
+ * Description Higher layers call this function to disconnect a channel.
+ *
+ * Returns true if disconnect sent, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_DisconnectReq(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectRsp
+ *
+ * Description Higher layers call this function to acknowledge the
+ * disconnection of a channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern bool L2CA_DisconnectRsp(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWrite
+ *
+ * Description Higher layers call this function to write data.
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Ping
+ *
+ * Description Higher layers call this function to send an echo request.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+extern bool L2CA_Ping(BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Echo
+ *
+ * Description Higher layers call this function to send an echo request
+ * with application-specific data.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+extern bool L2CA_Echo(BD_ADDR p_bd_addr, BT_HDR* p_data,
+ tL2CA_ECHO_DATA_CB* p_callback);
+
+// Given a local channel identifier, |lcid|, this function returns the bound
+// remote channel identifier, |rcid|, and the ACL link handle, |handle|. If
+// |lcid| is not known or is invalid, this function returns false and does not
+// modify the values pointed at by |rcid| and |handle|. |rcid| and |handle| may
+// be NULL.
+bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection, or for all future connections. The "idle
+ * timeout" is the amount of time that a connection can remain
+ * up with no L2CAP channels on it. A timeout of zero means
+ * that the connection will be torn down immediately when the
+ * last channel is removed. A timeout of 0xFFFF means no
+ * timeout. Values are in seconds.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+extern bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeoutByBdAddr
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection. The "idle timeout" is the amount of time that
+ * a connection can remain up with no L2CAP channels on it.
+ * A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+ * then the idle timeouts for all active l2cap links will be
+ * changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This timeout applies to all logical channels active on the
+ * ACL link.
+ ******************************************************************************/
+extern bool L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTraceLevel
+ *
+ * Description This function sets the trace level for L2CAP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_SetTraceLevel(uint8_t trace_level);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetDesireRole
+ *
+ * Description This function sets the desire role for L2CAP.
+ * If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+ * HciCreateConnection.
+ * If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow
+ * switch on HciCreateConnection.
+ *
+ * If the new role is a valid role (HCI_ROLE_MASTER or
+ * HCI_ROLE_SLAVE), the desire role is set to the new value.
+ * Otherwise, it is not changed.
+ *
+ * Returns the new (current) role
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_SetDesireRole(uint8_t new_role);
+
+/*******************************************************************************
+ *
+ * Function L2CA_LocalLoopbackReq
+ *
+ * Description This function sets up a CID for local loopback
+ *
+ * Returns CID of 0 if none.
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+ BD_ADDR p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlushChannel
+ *
+ * Description This function flushes none, some or all buffers queued up
+ * for xmission for a particular CID. If called with
+ * L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+ * of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+ * flushes all buffers. All other values specifies the maximum
+ * buffers to flush.
+ *
+ * Returns Number of buffers left queued for that CID
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetAclPriority
+ *
+ * Description Sets the transmission priority for an ACL channel.
+ * (For initial implementation only two values are valid.
+ * L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_SetAclPriority(BD_ADDR bd_addr, uint8_t priority);
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlowControl
+ *
+ * Description Higher layers call this function to flow control a channel.
+ *
+ * data_enabled - true data flows, false data is stopped
+ *
+ * Returns true if valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_FlowControl(uint16_t cid, bool data_enabled);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendTestSFrame
+ *
+ * Description Higher layers call this function to send a test S-frame.
+ *
+ * Returns true if valid Channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type,
+ uint8_t back_track);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTxPriority
+ *
+ * Description Sets the transmission priority for a channel. (FCR Mode)
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegForNoCPEvt
+ *
+ * Description Register callback for Number of Completed Packets event.
+ *
+ * Input Param p_cb - callback for Number of completed packets event
+ * p_bda - BT address of remote device
+ *
+ * Returns
+ *
+ ******************************************************************************/
+extern bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, BD_ADDR p_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlDataRate
+ *
+ * Description Sets the tx/rx data rate for a channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
+ tL2CAP_CHNL_DATA_RATE rx);
+
+typedef void(tL2CA_RESERVE_CMPL_CBACK)(void);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFlushTimeout
+ *
+ * Description This function set the automatic flush time out in Baseband
+ * for ACL-U packets.
+ * BdAddr : the remote BD address of ACL link. If it is
+ * BT_DB_ANY then the flush time out will be applied
+ * to all ACL link.
+ * FlushTimeout: flush time out in ms
+ * 0x0000 : No automatic flush
+ * L2CAP_NO_RETRANSMISSION : No retransmission
+ * 0x0002 - 0xFFFE : flush time out, if
+ * (flush_tout * 8) + 3 / 5)
+ * <= HCI_MAX_AUTO_FLUSH_TOUT
+ * (in 625us slot).
+ * Otherwise, return false.
+ * L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This flush timeout applies to all logical channels active on
+ * the ACL link.
+ ******************************************************************************/
+extern bool L2CA_SetFlushTimeout(BD_ADDR bd_addr, uint16_t flush_tout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWriteEx
+ *
+ * Description Higher layers call this function to write data with extended
+ * flags.
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlFlushability
+ *
+ * Description Higher layers call this function to set a channels
+ * flushability flags
+ *
+ * Returns true if CID found, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerFeatures
+ *
+ * Description Get a peers features and fixed channel map
+ *
+ * Parameters: BD address of the peer
+ * Pointers to features and channel mask storage area
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+extern bool L2CA_GetPeerFeatures(BD_ADDR bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBDAddrbyHandle
+ *
+ * Description Get BD address for the given HCI handle
+ *
+ * Parameters: HCI handle
+ * BD address of the peer
+ *
+ * Return value: true if found lcb for the given handle, false otherwise
+ *
+ ******************************************************************************/
+extern bool L2CA_GetBDAddrbyHandle(uint16_t handle, BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetChnlFcrMode
+ *
+ * Description Get the channel FCR mode
+ *
+ * Parameters: Local CID
+ *
+ * Return value: Channel mode
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_GetChnlFcrMode(uint16_t lcid);
+
+/*******************************************************************************
+ *
+ * UCD callback prototypes
+ *
+ ******************************************************************************/
+
+/* UCD discovery. Parameters are
+ * BD Address of remote
+ * Data Type
+ * Data
+*/
+#define L2CAP_UCD_INFO_TYPE_RECEPTION 0x01
+#define L2CAP_UCD_INFO_TYPE_MTU 0x02
+
+typedef void(tL2CA_UCD_DISCOVER_CB)(BD_ADDR, uint8_t, uint32_t);
+
+/* UCD data received. Parameters are
+ * BD Address of remote
+ * Pointer to buffer with data
+*/
+typedef void(tL2CA_UCD_DATA_CB)(BD_ADDR, BT_HDR*);
+
+/* Congestion status callback protype. This callback is optional. If
+ * an application tries to send data when the transmit queue is full,
+ * the data will anyways be dropped. The parameter is:
+ * remote BD_ADDR
+ * true if congested, false if uncongested
+*/
+typedef void(tL2CA_UCD_CONGESTION_STATUS_CB)(BD_ADDR, bool);
+
+/* UCD registration info (the callback addresses and PSM)
+*/
+typedef struct {
+ tL2CA_UCD_DISCOVER_CB* pL2CA_UCD_Discover_Cb;
+ tL2CA_UCD_DATA_CB* pL2CA_UCD_Data_Cb;
+ tL2CA_UCD_CONGESTION_STATUS_CB* pL2CA_UCD_Congestion_Status_Cb;
+} tL2CAP_UCD_CB_INFO;
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdRegister
+ *
+ * Description Register PSM on UCD.
+ *
+ * Parameters: tL2CAP_UCD_CB_INFO
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+extern bool L2CA_UcdRegister(uint16_t psm, tL2CAP_UCD_CB_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDeregister
+ *
+ * Description Deregister PSM on UCD.
+ *
+ * Parameters: PSM
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+extern bool L2CA_UcdDeregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDiscover
+ *
+ * Description Discover UCD of remote device.
+ *
+ * Parameters: PSM
+ * BD_ADDR of remote device
+ * info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+ * L2CAP_UCD_INFO_TYPE_MTU
+ *
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+extern bool L2CA_UcdDiscover(uint16_t psm, BD_ADDR rem_bda, uint8_t info_type);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDataWrite
+ *
+ * Description Send UCD to remote device
+ *
+ * Parameters: PSM
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_UcdDataWrite(uint16_t psm, BD_ADDR rem_bda, BT_HDR* p_buf,
+ uint16_t flags);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdSetIdleTimeout
+ *
+ * Description Set UCD Idle timeout.
+ *
+ * Parameters: BD Addr
+ * Timeout in second
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+extern bool L2CA_UcdSetIdleTimeout(BD_ADDR rem_bda, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UCDSetTxPriority
+ *
+ * Description Sets the transmission priority for a connectionless channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+extern bool L2CA_UCDSetTxPriority(BD_ADDR rem_bda,
+ tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ * Fixed Channel callback prototypes
+ *
+ ******************************************************************************/
+
+/* Fixed channel connected and disconnected. Parameters are
+ * channel
+ * BD Address of remote
+ * true if channel is connected, false if disconnected
+ * Reason for connection failure
+ * transport : physical transport, BR/EDR or LE
+*/
+typedef void(tL2CA_FIXED_CHNL_CB)(uint16_t, BD_ADDR, bool, uint16_t,
+ tBT_TRANSPORT);
+
+/* Signalling data received. Parameters are
+ * channel
+ * BD Address of remote
+ * Pointer to buffer with data
+*/
+typedef void(tL2CA_FIXED_DATA_CB)(uint16_t, BD_ADDR, BT_HDR*);
+
+/* Congestion status callback protype. This callback is optional. If
+ * an application tries to send data when the transmit queue is full,
+ * the data will anyways be dropped. The parameter is:
+ * remote BD_ADDR
+ * true if congested, false if uncongested
+*/
+typedef void(tL2CA_FIXED_CONGESTION_STATUS_CB)(BD_ADDR, bool);
+
+/* Fixed channel registration info (the callback addresses and channel config)
+*/
+typedef struct {
+ tL2CA_FIXED_CHNL_CB* pL2CA_FixedConn_Cb;
+ tL2CA_FIXED_DATA_CB* pL2CA_FixedData_Cb;
+ tL2CA_FIXED_CONGESTION_STATUS_CB* pL2CA_FixedCong_Cb;
+ tL2CAP_FCR_OPTS fixed_chnl_opts;
+
+ uint16_t default_idle_tout;
+ tL2CA_TX_COMPLETE_CB*
+ pL2CA_FixedTxComplete_Cb; /* fixed channel tx complete callback */
+} tL2CAP_FIXED_CHNL_REG;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterFixedChannel
+ *
+ * Description Register a fixed channel.
+ *
+ * Parameters: Fixed Channel #
+ * Channel Callbacks and config
+ *
+ * Return value: true if registered OK
+ *
+ ******************************************************************************/
+extern bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectFixedChnl
+ *
+ * Description Connect an fixed signalling channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ *
+ * Return value: true if connection started
+ *
+ ******************************************************************************/
+extern bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, BD_ADDR bd_addr);
+extern bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, BD_ADDR bd_addr,
+ uint8_t initiating_phys);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendFixedChnlData
+ *
+ * Description Write data on a fixed signalling channel.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, BD_ADDR rem_bda,
+ BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RemoveFixedChnl
+ *
+ * Description Remove a fixed channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Idle timeout to use (or 0xFFFF if don't care)
+ *
+ * Return value: true if channel removed
+ *
+ ******************************************************************************/
+extern bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, BD_ADDR rem_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFixedChannelTout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a fixed channel. The "idle timeout" is the amount of time
+ * that a connection can remain up with no L2CAP channels on
+ * it. A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+ * then the idle timeouts for all active l2cap links will be
+ * changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+extern bool L2CA_SetFixedChannelTout(BD_ADDR rem_bda, uint16_t fixed_cid,
+ uint16_t idle_tout);
+
+#endif /* (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetCurrentConfig
+ *
+ * Description This function returns configurations of L2CAP channel
+ * pp_our_cfg : pointer of our saved configuration options
+ * p_our_cfg_bits : valid config in bitmap
+ * pp_peer_cfg: pointer of peer's saved configuration options
+ * p_peer_cfg_bits : valid config in bitmap
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+extern bool L2CA_GetCurrentConfig(uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+ tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
+ tL2CAP_CFG_INFO** pp_peer_cfg,
+ tL2CAP_CH_CFG_BITS* p_peer_cfg_bits);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetConnectionConfig
+ *
+ * Description This function polulates the mtu, remote cid & lm_handle for
+ * a given local L2CAP channel
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+extern bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu,
+ uint16_t* rcid, uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function L2CA_CancelBleConnectReq
+ *
+ * Description Cancel a pending connection attempt to a BLE device.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if connection was cancelled
+ *
+ ******************************************************************************/
+extern bool L2CA_CancelBleConnectReq(BD_ADDR rem_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UpdateBleConnParams
+ *
+ * Description Update BLE connection parameters.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+extern bool L2CA_UpdateBleConnParams(BD_ADDR rem_bdRa, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_EnableUpdateBleConnParams
+ *
+ * Description Update BLE connection parameters.
+ *
+ * Parameters: BD Address of remote
+ * enable flag
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+extern bool L2CA_EnableUpdateBleConnParams(BD_ADDR rem_bda, bool enable);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBleConnRole
+ *
+ * Description This function returns the connection role.
+ *
+ * Returns link role.
+ *
+ ******************************************************************************/
+extern uint8_t L2CA_GetBleConnRole(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetDisconnectReason
+ *
+ * Description This function returns the disconnect reason code.
+ *
+ * Parameters: BD Address of remote
+ * Physical transport for the L2CAP connection (BR/EDR or LE)
+ *
+ * Returns disconnect reason
+ *
+ ******************************************************************************/
+extern uint16_t L2CA_GetDisconnectReason(BD_ADDR remote_bda,
+ tBT_TRANSPORT transport);
+
+/** M: Bug fix for the connection procedure while link is disconnecting @{ */
+/*******************************************************************************
+**
+** Function L2CA_FixedChnlPending
+**
+** Description This function is to check whether the fixed channel connection
+** request is pending
+**
+** Returns If the fixed channel connection is pending, return ture.
+**
+*******************************************************************************/
+extern bool L2CA_IsFixedChnlPending (uint16_t fixed_cid, BD_ADDR rem_bda);
+/** @} */
+
+#endif /* L2C_API_H */
diff --git a/mtkbt/code/bt/stack/include/l2cap_client.h b/mtkbt/code/bt/stack/include/l2cap_client.h
new file mode 100755
index 0000000..c5ecaf6
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/l2cap_client.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <hardware/bluetooth.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct buffer_t buffer_t;
+typedef struct l2cap_client_t l2cap_client_t;
+
+typedef struct {
+ void (*connected)(l2cap_client_t* client, void* context);
+ void (*disconnected)(l2cap_client_t* client, void* context);
+ void (*read_ready)(l2cap_client_t* client, buffer_t* packet, void* context);
+ void (*write_ready)(l2cap_client_t* client, void* context);
+} l2cap_client_callbacks_t;
+
+// Returns a new buffer with enough space for |size| bytes of L2CAP payload.
+// |size| must be greater than zero. This function returns NULL if the buffer
+// could not be allocated. The returned buffer must be freed with |buffer_free|
+// when it is no longer needed.
+buffer_t* l2cap_buffer_new(size_t size);
+
+// Creates and returns a new L2CAP client object. |callbacks| must not be NULL
+// and must specify a set of functions that should be called back when events
+// occur on the L2CAP connection. |context| may be NULL and will be passed as
+// the argument to all callbacks in |l2cap_client_callbacks_t|. The returned
+// object must be freed with |l2cap_client_free|.
+l2cap_client_t* l2cap_client_new(const l2cap_client_callbacks_t* callbacks,
+ void* context);
+
+// Frees the L2CAP client object allocated with |l2cap_client_new|. |client| may
+// be NULL.
+void l2cap_client_free(l2cap_client_t* client);
+
+// Attempts to connect the |client| to a peer device specified by
+// |remote_bdaddr| using the |psm| protocol specifier. This function returns
+// true if the connect operation could be started and will indicate completion
+// with either a 'connected' callback (success) or a 'disconnected' callback
+// (failure).
+//
+// This function must not be called while a connect operation is in progress or
+// while |l2cap_client_is_connected|. |client| and |remote_bdaddr| must not be
+// NULL. |psm| must be greater than zero.
+bool l2cap_client_connect(l2cap_client_t* client,
+ const bt_bdaddr_t* remote_bdaddr, uint16_t psm);
+
+// Disconnects a connected |client|. This function is asynchronous and
+// idempotent. It will indicate completion with a 'disconnected' callback.
+// |client| must not be NULL.
+void l2cap_client_disconnect(l2cap_client_t* client);
+
+// Returns true if |client| is connected and is ready to accept data written
+// to it. |client| must not be NULL.
+bool l2cap_client_is_connected(const l2cap_client_t* client);
+
+// Writes data contained in |packet| to a connected |client|. This function
+// returns true if the packet was successfully queued for delivery, false if the
+// client cannot accept more data at this time. If this function returns false,
+// the caller must wait for the 'write_ready' callback to write additional data
+// to the client. Neither |client| nor |packet| may be NULL.
+bool l2cap_client_write(l2cap_client_t* client, buffer_t* packet);
diff --git a/mtkbt/code/bt/stack/include/l2cdefs.h b/mtkbt/code/bt/stack/include/l2cdefs.h
new file mode 100755
index 0000000..592d7b3
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/l2cdefs.h
@@ -0,0 +1,395 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef L2CDEFS_H
+#define L2CDEFS_H
+
+/* L2CAP command codes
+*/
+#define L2CAP_CMD_REJECT 0x01
+#define L2CAP_CMD_CONN_REQ 0x02
+#define L2CAP_CMD_CONN_RSP 0x03
+#define L2CAP_CMD_CONFIG_REQ 0x04
+#define L2CAP_CMD_CONFIG_RSP 0x05
+#define L2CAP_CMD_DISC_REQ 0x06
+#define L2CAP_CMD_DISC_RSP 0x07
+#define L2CAP_CMD_ECHO_REQ 0x08
+#define L2CAP_CMD_ECHO_RSP 0x09
+#define L2CAP_CMD_INFO_REQ 0x0A
+#define L2CAP_CMD_INFO_RSP 0x0B
+#define L2CAP_CMD_AMP_CONN_REQ 0x0C
+#define L2CAP_CMD_AMP_CONN_RSP 0x0D
+#define L2CAP_CMD_AMP_MOVE_REQ 0x0E
+#define L2CAP_CMD_AMP_MOVE_RSP 0x0F
+#define L2CAP_CMD_AMP_MOVE_CFM 0x10
+#define L2CAP_CMD_AMP_MOVE_CFM_RSP 0x11
+#define L2CAP_CMD_BLE_UPDATE_REQ 0x12
+#define L2CAP_CMD_BLE_UPDATE_RSP 0x13
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ 0x14
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES 0x15
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT 0x16
+
+/* Define some packet and header lengths
+*/
+/* Length and CID */
+#define L2CAP_PKT_OVERHEAD 4
+/* Cmd code, Id and length */
+#define L2CAP_CMD_OVERHEAD 4
+/* Reason (data is optional) */
+#define L2CAP_CMD_REJECT_LEN 2
+/* PSM and source CID */
+#define L2CAP_CONN_REQ_LEN 4
+/* Dest CID, source CID, reason, status */
+#define L2CAP_CONN_RSP_LEN 8
+/* Dest CID, flags (data is optional) */
+#define L2CAP_CONFIG_REQ_LEN 4
+/* Dest CID, flags, result,data optional*/
+#define L2CAP_CONFIG_RSP_LEN 6
+/* Dest CID, source CID */
+#define L2CAP_DISC_REQ_LEN 4
+/* Dest CID, source CID */
+#define L2CAP_DISC_RSP_LEN 4
+/* Data is optional */
+#define L2CAP_ECHO_REQ_LEN 0
+/* Data is optional */
+#define L2CAP_ECHO_RSP_LEN 0
+/* Info type */
+#define L2CAP_INFO_REQ_LEN 2
+/* Info type, result (data is optional) */
+#define L2CAP_INFO_RSP_LEN 4
+/* Additional connectionless packet overhead */
+#define L2CAP_UCD_OVERHEAD 2
+
+/* PSM, CID, and remote controller ID */
+#define L2CAP_AMP_CONN_REQ_LEN 5
+/* CID and remote controller ID */
+#define L2CAP_AMP_MOVE_REQ_LEN 3
+/* CID and result */
+#define L2CAP_AMP_MOVE_RSP_LEN 4
+/* CID and result */
+#define L2CAP_AMP_MOVE_CFM_LEN 4
+/* CID */
+#define L2CAP_AMP_MOVE_CFM_RSP_LEN 2
+
+/* Min and max interval, latency, tout */
+#define L2CAP_CMD_BLE_UPD_REQ_LEN 8
+/* Result */
+#define L2CAP_CMD_BLE_UPD_RSP_LEN 2
+
+/* LE_PSM, SCID, MTU, MPS, Init Credit */
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN 10
+/* DCID, MTU, MPS, Init credit, Result */
+#define L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN 10
+/* CID, Credit */
+#define L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN 4
+
+/* Define the packet boundary flags
+*/
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+#define L2CAP_PKT_START_FLUSHABLE 2
+#define L2CAP_PKT_START_NON_FLUSHABLE 0
+#endif
+#define L2CAP_COMPLETE_AMP_PKT 3 /* complete L2CAP packet on AMP HCI */
+#define L2CAP_PKT_START 2
+#define L2CAP_PKT_CONTINUE 1
+#define L2CAP_MASK_FLAG 0x0FFF
+#define L2CAP_PKT_TYPE_SHIFT 12
+#define L2CAP_PKT_TYPE_MASK 3
+
+/* Define the L2CAP connection result codes
+*/
+#define L2CAP_CONN_OK 0
+#define L2CAP_CONN_PENDING 1
+#define L2CAP_CONN_NO_PSM 2
+#define L2CAP_CONN_SECURITY_BLOCK 3
+#define L2CAP_CONN_NO_RESOURCES 4
+#define L2CAP_CONN_BAD_CTLR_ID 5 /* AMP related */
+#define L2CAP_CONN_TIMEOUT 0xEEEE
+#define L2CAP_CONN_AMP_FAILED 254
+/* Add a couple of our own for internal use */
+#define L2CAP_CONN_NO_LINK 255
+#define L2CAP_CONN_CANCEL 256 /* L2CAP connection cancelled */
+
+/* Define the LE L2CAP connection result codes
+*/
+#define L2CAP_LE_CONN_OK 0
+#define L2CAP_LE_NO_PSM 2
+#define L2CAP_LE_NO_RESOURCES 4
+#define L2CAP_LE_INSUFFICIENT_AUTHENTICATION 5
+#define L2CAP_LE_INSUFFICIENT_AUTHORIZATION 6
+#define L2CAP_LE_INSUFFICIENT_ENCRYP_KEY_SIZE 7
+#define L2CAP_LE_INSUFFICIENT_ENCRYP 8
+/* We don't like peer device response */
+#define L2CAP_LE_INVALID_SOURCE_CID 9
+#define L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED 0x0A
+
+/* Define L2CAP Move Channel Response result codes
+*/
+#define L2CAP_MOVE_OK 0
+#define L2CAP_MOVE_PENDING 1
+#define L2CAP_MOVE_CTRL_ID_NOT_SUPPORT 2
+#define L2CAP_MOVE_SAME_CTRLR_ID 3
+#define L2CAP_MOVE_CONFIG_NOT_SUPPORTED 4
+#define L2CAP_MOVE_CHAN_COLLISION 5
+#define L2CAP_MOVE_NOT_ALLOWED 6
+
+/* Define L2CAP Move Channel Confirmation result codes
+*/
+#define L2CAP_MOVE_CFM_OK 0
+#define L2CAP_MOVE_CFM_REFUSED 1
+
+/* Define the L2CAP command reject reason codes
+*/
+#define L2CAP_CMD_REJ_NOT_UNDERSTOOD 0
+#define L2CAP_CMD_REJ_MTU_EXCEEDED 1
+#define L2CAP_CMD_REJ_INVALID_CID 2
+
+/* L2CAP Predefined CIDs
+*/
+#define L2CAP_SIGNALLING_CID 1
+#define L2CAP_CONNECTIONLESS_CID 2
+#define L2CAP_AMP_CID 3
+#define L2CAP_ATT_CID 4
+#define L2CAP_BLE_SIGNALLING_CID 5
+#define L2CAP_SMP_CID 6
+#define L2CAP_SMP_BR_CID 7
+#define L2CAP_AMP_TEST_CID 0x003F
+#define L2CAP_BASE_APPL_CID 0x0040
+#define L2CAP_BLE_CONN_MAX_CID 0x007F
+
+/* Fixed Channels mask bits */
+
+/* Signal channel supported (Mandatory) */
+#define L2CAP_FIXED_CHNL_SIG_BIT (1 << L2CAP_SIGNALLING_CID)
+
+/* Connectionless reception */
+#define L2CAP_FIXED_CHNL_CNCTLESS_BIT (1 << L2CAP_CONNECTIONLESS_CID)
+
+/* AMP Manager supported */
+#define L2CAP_FIXED_CHNL_AMP_BIT (1 << L2CAP_AMP_CID)
+
+/* Attribute protocol supported */
+#define L2CAP_FIXED_CHNL_ATT_BIT (1 << L2CAP_ATT_CID)
+
+/* BLE Signalling supported */
+#define L2CAP_FIXED_CHNL_BLE_SIG_BIT (1 << L2CAP_BLE_SIGNALLING_CID)
+
+/* BLE Security Mgr supported */
+#define L2CAP_FIXED_CHNL_SMP_BIT (1 << L2CAP_SMP_CID)
+
+/* Security Mgr over BR supported */
+#define L2CAP_FIXED_CHNL_SMP_BR_BIT (1 << L2CAP_SMP_BR_CID)
+
+/* Define the L2CAP configuration result codes
+*/
+#define L2CAP_CFG_OK 0
+#define L2CAP_CFG_UNACCEPTABLE_PARAMS 1
+#define L2CAP_CFG_FAILED_NO_REASON 2
+#define L2CAP_CFG_UNKNOWN_OPTIONS 3
+#define L2CAP_CFG_PENDING 4
+#define L2CAP_CFG_FLOW_SPEC_REJECTED 5
+
+/* Define the L2CAP configuration option types
+*/
+#define L2CAP_CFG_TYPE_MTU 0x01
+#define L2CAP_CFG_TYPE_FLUSH_TOUT 0x02
+#define L2CAP_CFG_TYPE_QOS 0x03
+#define L2CAP_CFG_TYPE_FCR 0x04
+#define L2CAP_CFG_TYPE_FCS 0x05
+#define L2CAP_CFG_TYPE_EXT_FLOW 0x06
+#define L2CAP_CFG_TYPE_EXT_WIN_SIZE 0x07
+
+#define L2CAP_CFG_MTU_OPTION_LEN 2 /* MTU option length */
+#define L2CAP_CFG_FLUSH_OPTION_LEN 2 /* Flush option len */
+#define L2CAP_CFG_QOS_OPTION_LEN 22 /* QOS option length */
+#define L2CAP_CFG_FCR_OPTION_LEN 9 /* FCR option length */
+#define L2CAP_CFG_FCS_OPTION_LEN 1 /* FCR option length */
+#define L2CAP_CFG_EXT_FLOW_OPTION_LEN 16 /* Extended Flow Spec */
+#define L2CAP_CFG_EXT_WIN_SIZE_LEN 2 /* Ext window size length */
+#define L2CAP_CFG_OPTION_OVERHEAD 2 /* Type and length */
+
+/* Configuration Cmd/Rsp Flags mask
+*/
+#define L2CAP_CFG_FLAGS_MASK_CONT 0x0001 /* Flags mask: Continuation */
+
+/* FCS Check Option values
+*/
+#define L2CAP_CFG_FCS_BYPASS 0 /* Bypass the FCS in streaming or ERTM modes */
+#define L2CAP_CFG_FCS_USE \
+ 1 /* Use the FCS in streaming or ERTM modes [default] */
+
+/* Default values for configuration
+*/
+#define L2CAP_NO_AUTOMATIC_FLUSH 0xFFFF
+#define L2CAP_NO_RETRANSMISSION 0x0001
+
+#define L2CAP_DEFAULT_MTU (672)
+#define L2CAP_DEFAULT_FLUSH_TO L2CAP_NO_AUTOMATIC_FLUSH
+#define L2CAP_DEFAULT_SERV_TYPE 1
+#define L2CAP_DEFAULT_TOKEN_RATE 0
+#define L2CAP_DEFAULT_BUCKET_SIZE 0
+#define L2CAP_DEFAULT_PEAK_BANDWIDTH 0
+#define L2CAP_DEFAULT_LATENCY 0xFFFFFFFF
+#define L2CAP_DEFAULT_DELAY 0xFFFFFFFF
+#define L2CAP_DEFAULT_FCS L2CAP_CFG_FCS_USE
+
+/* Define the L2CAP disconnect result codes
+*/
+#define L2CAP_DISC_OK 0
+#define L2CAP_DISC_TIMEOUT 0xEEEE
+
+/* Define the L2CAP info resp result codes
+*/
+#define L2CAP_INFO_RESP_RESULT_SUCCESS 0
+#define L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED 1
+
+/* Define the info-type fields of information request & response
+*/
+#define L2CAP_CONNLESS_MTU_INFO_TYPE 0x0001
+/* Used in Information Req/Response */
+#define L2CAP_EXTENDED_FEATURES_INFO_TYPE 0x0002
+/* Used in AMP */
+#define L2CAP_FIXED_CHANNELS_INFO_TYPE 0x0003
+
+/* Connectionless MTU size */
+#define L2CAP_CONNLESS_MTU_INFO_SIZE 2
+/* Extended features array size */
+#define L2CAP_EXTENDED_FEATURES_ARRAY_SIZE 4
+/* Fixed channel array size */
+#define L2CAP_FIXED_CHNL_ARRAY_SIZE 8
+
+/* Extended features mask bits
+*/
+/* Retransmission Mode (Not Supported) */
+#define L2CAP_EXTFEA_RTRANS 0x00000001
+/* Flow Control Mode (Not Supported) */
+#define L2CAP_EXTFEA_FC 0x00000002
+#define L2CAP_EXTFEA_QOS 0x00000004
+/* Enhanced retransmission mode */
+#define L2CAP_EXTFEA_ENH_RETRANS 0x00000008
+/* Streaming Mode */
+#define L2CAP_EXTFEA_STREAM_MODE 0x00000010
+/* Optional FCS (if set No FCS desired) */
+#define L2CAP_EXTFEA_NO_CRC 0x00000020
+/* Extended flow spec */
+#define L2CAP_EXTFEA_EXT_FLOW_SPEC 0x00000040
+/* Fixed channels */
+#define L2CAP_EXTFEA_FIXED_CHNLS 0x00000080
+/* Extended Window Size */
+#define L2CAP_EXTFEA_EXT_WINDOW 0x00000100
+/* Unicast Connectionless Data Reception */
+#define L2CAP_EXTFEA_UCD_RECEPTION 0x00000200
+
+/* Mask for locally supported features used in Information Response
+ * (default to none) */
+#ifndef L2CAP_EXTFEA_SUPPORTED_MASK
+#define L2CAP_EXTFEA_SUPPORTED_MASK 0
+#endif
+
+/* Mask for LE supported features used in Information Response
+ * (default to none) */
+#ifndef L2CAP_BLE_EXTFEA_MASK
+#define L2CAP_BLE_EXTFEA_MASK 0
+#endif
+
+/* Define a value that tells L2CAP to use the default HCI ACL buffer size */
+#define L2CAP_INVALID_ERM_BUF_SIZE 0
+/* Define a value that tells L2CAP to use the default MPS */
+#define L2CAP_DEFAULT_ERM_MPS 0x0000
+
+#define L2CAP_FCR_OVERHEAD 2 /* Control word */
+#define L2CAP_FCS_LEN 2 /* FCS takes 2 bytes */
+#define L2CAP_SDU_LEN_OVERHEAD 2 /* SDU length field is 2 bytes */
+#define L2CAP_SDU_LEN_OFFSET 2 /* SDU length offset is 2 bytes */
+#define L2CAP_EXT_CONTROL_OVERHEAD 4 /* Extended Control Field */
+/* length(2), channel(2), control(4), SDU length(2) FCS(2) */
+#define L2CAP_MAX_HEADER_FCS \
+ (L2CAP_PKT_OVERHEAD + L2CAP_EXT_CONTROL_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + \
+ L2CAP_FCS_LEN)
+
+/* To optimize this, it must be a multiple of the L2CAP PDU length AND match
+ * the 3DH5 air including the l2cap headers in each packet. To match the latter,
+ * the -5 is added.
+ * Changed it to 8087 to have same value between BTIF and L2cap layers
+ */
+#define L2CAP_MAX_SDU_LENGTH (8080 + 26 - (L2CAP_MIN_OFFSET + 6))
+#define L2CAP_MAX_BUF_SIZE (10240 + 24)
+
+/* Part of L2CAP_MIN_OFFSET that is not part of L2CAP
+*/
+#define L2CAP_OFFSET_WO_L2HDR \
+ (L2CAP_MIN_OFFSET - (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD))
+
+/* SAR bits in the control word
+*/
+/* Control word to begin with for unsegmented PDU*/
+#define L2CAP_FCR_UNSEG_SDU 0x0000
+/* ...for Starting PDU of a semented SDU */
+#define L2CAP_FCR_START_SDU 0x4000
+/* ...for ending PDU of a segmented SDU */
+#define L2CAP_FCR_END_SDU 0x8000
+/* ...for continuation PDU of a segmented SDU */
+#define L2CAP_FCR_CONT_SDU 0xc000
+
+/* Supervisory frame types */
+/* Supervisory frame - RR */
+#define L2CAP_FCR_SUP_RR 0x0000
+/* Supervisory frame - REJ */
+#define L2CAP_FCR_SUP_REJ 0x0001
+/* Supervisory frame - RNR */
+#define L2CAP_FCR_SUP_RNR 0x0002
+/* Supervisory frame - SREJ */
+#define L2CAP_FCR_SUP_SREJ 0x0003
+
+/* Mask to get the SAR bits from control word */
+#define L2CAP_FCR_SAR_BITS 0xC000
+/* Bits to shift right to get the SAR bits from ctrl-word */
+#define L2CAP_FCR_SAR_BITS_SHIFT 14
+
+/* Mask to check if a PDU is S-frame */
+#define L2CAP_FCR_S_FRAME_BIT 0x0001
+/* Mask to get the req-seq from control word */
+#define L2CAP_FCR_REQ_SEQ_BITS 0x3F00
+/* Bits to shift right to get the req-seq from ctrl-word */
+#define L2CAP_FCR_REQ_SEQ_BITS_SHIFT 8
+/* Mask on get the tx-seq from control word */
+#define L2CAP_FCR_TX_SEQ_BITS 0x007E
+/* Bits to shift right to get the tx-seq from ctrl-word */
+#define L2CAP_FCR_TX_SEQ_BITS_SHIFT 1
+
+/* F-bit in the control word (Sup and I frames) */
+#define L2CAP_FCR_F_BIT 0x0080
+/* P-bit in the control word (Sup frames only) */
+#define L2CAP_FCR_P_BIT 0x0010
+
+#define L2CAP_FCR_F_BIT_SHIFT 7
+#define L2CAP_FCR_P_BIT_SHIFT 4
+
+/* Mask to get the segmentation bits from ctrl-word */
+#define L2CAP_FCR_SEG_BITS 0xC000
+/* Bits to shift right to get the S-bits from ctrl-word */
+#define L2CAP_FCR_SUP_SHIFT 2
+/* Mask to get the supervisory bits from ctrl-word */
+#define L2CAP_FCR_SUP_BITS 0x000C
+
+/* Initial state of the CRC register */
+#define L2CAP_FCR_INIT_CRC 0
+/* Mask for sequence numbers (range 0 - 63) */
+#define L2CAP_FCR_SEQ_MODULO 0x3F
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/mca_api.h b/mtkbt/code/bt/stack/include/mca_api.h
new file mode 100755
index 0000000..2d0128f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/mca_api.h
@@ -0,0 +1,553 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This interface file contains the interface to the Multi-Channel
+ * Adaptation Protocol (MCAP).
+ *
+ ******************************************************************************/
+#ifndef MCA_API_H
+#define MCA_API_H
+
+#include "bt_target.h"
+#include "l2c_api.h"
+
+/* move the following to bt_target.h or other place later */
+#define MCA_NUM_TC_TBL ((MCA_NUM_REGS) * (MCA_NUM_LINKS) * (MCA_NUM_MDLS + 1))
+/* Number of control channel control blocks */
+#define MCA_NUM_CCBS ((MCA_NUM_REGS) * (MCA_NUM_LINKS))
+/* Number of data channel control blocks */
+#define MCA_NUM_DCBS ((MCA_NUM_REGS) * (MCA_NUM_LINKS) * (MCA_NUM_MDLS))
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+/* API function return value result codes. */
+#define MCA_SUCCESS 0 /* Function successful */
+#define MCA_BAD_PARAMS 1 /* Invalid parameters */
+#define MCA_NO_RESOURCES 2 /* Not enough resources */
+#define MCA_BAD_HANDLE 3 /* Bad handle */
+#define MCA_BUSY 4 /* A procedure is already in progress */
+#define MCA_WRITE_FAIL 5 /* Write failed */
+#define MCA_BAD_MDL_ID 6 /* MDL ID is not valid for the current API */
+typedef uint8_t tMCA_RESULT;
+
+/* MDEP data type. */
+#define MCA_TDEP_ECHO 0 /* MDEP for echo test */
+#define MCA_TDEP_DATA 1 /* MDEP for normal data */
+
+/* Control callback events. */
+#define MCA_ERROR_RSP_EVT 0 /* error response */
+#define MCA_CREATE_IND_EVT 1 /* create mdl indication */
+#define MCA_CREATE_CFM_EVT 2 /* create mdl confirm */
+#define MCA_RECONNECT_IND_EVT 3 /* reconnect mdl indication */
+#define MCA_RECONNECT_CFM_EVT 4 /* reconnect mdl confirm */
+#define MCA_ABORT_IND_EVT 5 /* abort mdl indication */
+#define MCA_ABORT_CFM_EVT 6 /* abort mdl confirm */
+#define MCA_DELETE_IND_EVT 7 /* delete mdl indication */
+#define MCA_DELETE_CFM_EVT 8 /* delete mdl confirm */
+
+/* request sync capabilities & requirements */
+#define MCA_SYNC_CAP_IND_EVT 0x11
+#define MCA_SYNC_CAP_CFM_EVT 0x12 /* indicate completion */
+/* request to set the time-stamp clock */
+#define MCA_SYNC_SET_IND_EVT 0x13
+#define MCA_SYNC_SET_CFM_EVT 0x14 /* indicate completion */
+/* update of the actual time-stamp clock instant from the sync slave */
+#define MCA_SYNC_INFO_IND_EVT 0x15
+
+#define MCA_CONNECT_IND_EVT 0x20 /* Control channel connected */
+#define MCA_DISCONNECT_IND_EVT 0x21 /* Control channel disconnected */
+#define MCA_OPEN_IND_EVT 0x22 /* Data channel open indication */
+#define MCA_OPEN_CFM_EVT 0x23 /* Data channel open confirm */
+#define MCA_CLOSE_IND_EVT 0x24 /* Data channel close indication */
+#define MCA_CLOSE_CFM_EVT 0x25 /* Data channel close confirm */
+#define MCA_CONG_CHG_EVT 0x26 /* congestion change event */
+#define MCA_RSP_TOUT_IND_EVT \
+ 0x27 /* Control channel message response timeout \
+ */
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+typedef uint8_t
+ tMCA_HANDLE; /* the handle for registration. 1 based index to rcb */
+typedef uint8_t tMCA_CL; /* the handle for a control channel; reported at
+ MCA_CONNECT_IND_EVT */
+typedef uint8_t
+ tMCA_DEP; /* the handle for MCA_CreateDep. This is also the local mdep_id */
+typedef uint16_t tMCA_DL; /* the handle for the data channel. This is reported
+ at MCA_OPEN_CFM_EVT or MCA_OPEN_IND_EVT */
+
+/* This is the data callback function. It is executed when MCAP has a data
+ * packet ready for the application.
+*/
+typedef void(tMCA_DATA_CBACK)(tMCA_DL mdl, BT_HDR* p_pkt);
+
+/* This structure contains parameters which are set at registration. */
+typedef struct {
+ uint32_t rsp_tout; /* MCAP signaling response timeout */
+ uint16_t ctrl_psm; /* L2CAP PSM for the MCAP control channel */
+ uint16_t data_psm; /* L2CAP PSM for the MCAP data channel */
+ uint16_t sec_mask; /* Security mask for BTM_SetSecurityLevel() */
+} tMCA_REG;
+
+/* This structure contains parameters to create a MDEP. */
+typedef struct {
+ uint8_t type; /* MCA_TDEP_DATA, or MCA_TDEP_ECHO. a regiatration may have only
+ one MCA_TDEP_ECHO MDEP */
+ uint8_t max_mdl; /* The maximum number of MDLs for this MDEP (max is
+ MCA_NUM_MDLS) */
+ tMCA_DATA_CBACK* p_data_cback; /* Data callback function */
+} tMCA_CS;
+
+#define MCA_FCS_NONE 0 /* fcs_present=false */
+#define MCA_FCS_BYPASS 0x10 /* fcs_present=true, fcs=L2CAP_CFG_FCS_BYPASS */
+#define MCA_FCS_USE 0x11 /* fcs_present=true, fcs=L2CAP_CFG_FCS_USE */
+#define MCA_FCS_PRESNT_MASK 0x10 /* fcs_present=true */
+#define MCA_FCS_USE_MASK 0x01 /* mask for fcs */
+typedef uint8_t tMCA_FCS_OPT;
+
+/* This structure contains L2CAP configuration parameters for the channel. */
+typedef struct {
+ tL2CAP_FCR_OPTS fcr_opt;
+ uint16_t user_rx_buf_size;
+ uint16_t user_tx_buf_size;
+ uint16_t fcr_rx_buf_size;
+ uint16_t fcr_tx_buf_size;
+ tMCA_FCS_OPT fcs;
+ uint16_t data_mtu; /* L2CAP MTU of the MCAP data channel */
+} tMCA_CHNL_CFG;
+
+/* Header structure for callback event parameters. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ uint8_t op_code; /* The op (request/response) code */
+} tMCA_EVT_HDR;
+
+/* Response Header structure for callback event parameters. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ uint8_t op_code; /* The op (request/response) code */
+ uint8_t rsp_code; /* The response code */
+} tMCA_RSP_EVT;
+
+/* This data structure is associated with the MCA_CREATE_IND_EVT. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ uint8_t op_code; /* The op (request/response) code */
+ uint8_t dep_id; /* MDEP ID */
+ uint8_t cfg; /* The configuration to negotiate */
+} tMCA_CREATE_IND;
+
+/* This data structure is associated with the MCA_CREATE_CFM_EVT. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ uint8_t op_code; /* The op (request/response) code */
+ uint8_t rsp_code; /* The response code. */
+ uint8_t cfg; /* The configuration to negotiate */
+} tMCA_CREATE_CFM;
+
+/* This data structure is associated with MCA_CONNECT_IND_EVT. */
+typedef struct {
+ BD_ADDR bd_addr; /* The peer address */
+ uint16_t mtu; /* peer mtu */
+} tMCA_CONNECT_IND;
+
+/* This data structure is associated with MCA_DISCONNECT_IND_EVT. */
+typedef struct {
+ BD_ADDR bd_addr; /* The peer address */
+ uint16_t reason; /* disconnect reason given by L2CAP */
+} tMCA_DISCONNECT_IND;
+
+/* This data structure is for MCA_OPEN_IND_EVT, and MCA_OPEN_CFM_EVT. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ tMCA_DL mdl; /* The handle for the data channel */
+ uint16_t mtu; /* peer mtu */
+} tMCA_DL_OPEN;
+
+/* This data structure is for MCA_CLOSE_IND_EVT and MCA_CLOSE_CFM_EVT. */
+typedef struct {
+ uint16_t mdl_id; /* The associated MDL ID */
+ tMCA_DL mdl; /* The handle for the data channel */
+ uint16_t reason; /* disconnect reason given by L2CAP */
+} tMCA_DL_CLOSE;
+
+/* This data structure is associated with MCA_CONG_CHG_EVT. */
+typedef struct {
+ uint16_t mdl_id; /* N/A - This is a place holder */
+ tMCA_DL mdl; /* The handle for the data channel */
+ bool cong; /* true, if the channel is congested */
+} tMCA_CONG_CHG;
+
+/* Union of all control callback event data structures */
+typedef union {
+ tMCA_EVT_HDR hdr;
+ tMCA_RSP_EVT rsp;
+ tMCA_CREATE_IND create_ind;
+ tMCA_CREATE_CFM create_cfm;
+ tMCA_EVT_HDR reconnect_ind;
+ tMCA_RSP_EVT reconnect_cfm;
+ tMCA_EVT_HDR abort_ind;
+ tMCA_RSP_EVT abort_cfm;
+ tMCA_EVT_HDR delete_ind;
+ tMCA_RSP_EVT delete_cfm;
+ tMCA_CONNECT_IND connect_ind;
+ tMCA_DISCONNECT_IND disconnect_ind;
+ tMCA_DL_OPEN open_ind;
+ tMCA_DL_OPEN open_cfm;
+ tMCA_DL_CLOSE close_ind;
+ tMCA_DL_CLOSE close_cfm;
+ tMCA_CONG_CHG cong_chg;
+} tMCA_CTRL;
+
+/* This is the control callback function. This function passes control events
+ * to the application.
+*/
+typedef void(tMCA_CTRL_CBACK)(tMCA_HANDLE handle, tMCA_CL mcl, uint8_t event,
+ tMCA_CTRL* p_data);
+
+/*******************************************************************************
+ *
+ * Function MCA_Init
+ *
+ * Description Initialize MCAP internal control blocks.
+ * This function is called at stack start up.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void MCA_Init(void);
+
+/*******************************************************************************
+ *
+ * Function MCA_SetTraceLevel
+ *
+ * Description This function sets the debug trace level for MCA.
+ * If 0xff is passed, the current trace level is returned.
+ *
+ * Input Parameters:
+ * level: The level to set the MCA tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ ******************************************************************************/
+extern uint8_t MCA_SetTraceLevel(uint8_t level);
+
+/*******************************************************************************
+ *
+ * Function MCA_Register
+ *
+ * Description This function registers an MCAP implementation.
+ * It is assumed that the control channel PSM and data channel
+ * PSM are not used by any other instances of the stack.
+ * If the given p_reg->ctrl_psm is 0, this handle is INT only.
+ *
+ * Returns 0, if failed. Otherwise, the MCA handle.
+ *
+ ******************************************************************************/
+extern tMCA_HANDLE MCA_Register(tMCA_REG* p_reg, tMCA_CTRL_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function MCA_Deregister
+ *
+ * Description Deregister an MCAP implementation. Before this function can
+ * be called, all control and data channels must be removed
+ * with MCA_DisconnectReq and MCA_CloseReq.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void MCA_Deregister(tMCA_HANDLE handle);
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateDep
+ *
+ * Description Create a data endpoint. If the MDEP is created
+ * successfully, the MDEP ID is returned in *p_dep. After a
+ * data endpoint is created, an application can initiate a
+ * connection between this endpoint and an endpoint on a peer
+ * device.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP* p_dep,
+ tMCA_CS* p_cs);
+
+/*******************************************************************************
+ *
+ * Function MCA_DeleteDep
+ *
+ * Description Delete a data endpoint. This function is called when
+ * the implementation is no longer using a data endpoint.
+ * If this function is called when the endpoint is connected
+ * the connection is closed and the data endpoint
+ * is removed.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep);
+
+/*******************************************************************************
+ *
+ * Function MCA_ConnectReq
+ *
+ * Description This function initiates an MCAP control channel connection
+ * to the peer device. When the connection is completed, an
+ * MCA_CONNECT_IND_EVT is reported to the application via its
+ * control callback function.
+ * This control channel is identified by tMCA_CL.
+ * If the connection attempt fails, an MCA_DISCONNECT_IND_EVT
+ * is reported. The security mask parameter overrides the
+ * outgoing security mask set in MCA_Register().
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ uint16_t ctrl_psm, uint16_t sec_mask);
+
+/*******************************************************************************
+ *
+ * Function MCA_DisconnectReq
+ *
+ * Description This function disconnect an MCAP control channel
+ * to the peer device.
+ * If associated data channel exists, they are disconnected.
+ * When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+ * reported to the application via its control callback
+ * function.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl);
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateMdl
+ *
+ * Description This function sends a CREATE_MDL request to the peer device.
+ * When the response is received, a MCA_CREATE_CFM_EVT is
+ * reported with the given MDL ID.
+ * If the response is successful, a data channel is open
+ * with the given p_chnl_cfg
+ * When the data channel is open successfully, a
+ * MCA_OPEN_CFM_EVT is reported. This data channel is
+ * identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+ uint16_t mdl_id, uint8_t peer_dep_id,
+ uint8_t cfg, const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateMdlRsp
+ *
+ * Description This function sends a CREATE_MDL response to the peer device
+ * in response to a received MCA_CREATE_IND_EVT.
+ * If the rsp_code is successful, a data channel is open
+ * with the given p_chnl_cfg
+ * When the data channel is open successfully, a
+ * MCA_OPEN_IND_EVT is reported. This data channel is
+ * identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
+ uint8_t cfg, uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/*******************************************************************************
+ *
+ * Function MCA_CloseReq
+ *
+ * Description Close a data channel. When the channel is closed, an
+ * MCA_CLOSE_CFM_EVT is sent to the application via the
+ * control callback function for this handle.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_CloseReq(tMCA_DL mdl);
+
+/*******************************************************************************
+ *
+ * Function MCA_ReconnectMdl
+ *
+ * Description This function sends a RECONNECT_MDL request to the peer
+ * device. When the response is received, a
+ * MCA_RECONNECT_CFM_EVT is reported. If the response is
+ * successful, a data channel is open. When the data channel is
+ * open successfully, a MCA_OPEN_CFM_EVT is reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep,
+ uint16_t data_psm, uint16_t mdl_id,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/*******************************************************************************
+ *
+ * Function MCA_ReconnectMdlRsp
+ *
+ * Description Send a RECONNECT_MDL response to the peer device in response
+ * to a MCA_RECONNECT_IND_EVT event.
+ * If the response is successful, a data channel is open.
+ * When the data channel is open successfully, a
+ * MCA_OPEN_IND_EVT is reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep,
+ uint16_t mdl_id, uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/*******************************************************************************
+ *
+ * Function MCA_DataChnlCfg
+ *
+ * Description This function initiates a data channel connection toward the
+ * connected peer device.
+ * When the data channel is open successfully, a
+ * MCA_OPEN_CFM_EVT is reported. This data channel is
+ * identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/*******************************************************************************
+ *
+ * Function MCA_Abort
+ *
+ * Description This function sends a ABORT_MDL request to the peer device.
+ * When the response is received, a MCA_ABORT_CFM_EVT is
+ * reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_Abort(tMCA_CL mcl);
+
+/*******************************************************************************
+ *
+ * Function MCA_Delete
+ *
+ * Description This function sends a DELETE_MDL request to the peer device.
+ * When the response is received, a MCA_DELETE_CFM_EVT is
+ * reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id);
+
+/*******************************************************************************
+ *
+ * Function MCA_WriteReq
+ *
+ * Description Send a data packet to the peer device.
+ *
+ * The application passes the packet using the BT_HDR
+ * structure. The offset field must be equal to or greater than
+ * L2CAP_MIN_OFFSET. This allows enough space in the buffer for
+ * the L2CAP header.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+extern tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR* p_pkt);
+
+/*******************************************************************************
+ *
+ * Function MCA_GetL2CapChannel
+ *
+ * Description Get the L2CAP CID used by the given data channel handle.
+ *
+ * Returns L2CAP channel ID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+extern uint16_t MCA_GetL2CapChannel(tMCA_DL mdl);
+
+/**
+ * The following definitions are for test interface only, they mirror function
+ * definitions above. This struct allows an external application to load and
+ * call these methods without linking against the core library.
+ */
+typedef struct {
+ size_t size;
+ void (*init)(void);
+ tMCA_HANDLE (*register_application)(tMCA_REG* p_reg,
+ tMCA_CTRL_CBACK* p_cback);
+ void (*deregister_application)(tMCA_HANDLE handle);
+ tMCA_RESULT (*create_mdep)(tMCA_HANDLE handle, tMCA_DEP* p_dep,
+ tMCA_CS* p_cs);
+ tMCA_RESULT (*delete_mdep)(tMCA_HANDLE handle, tMCA_DEP dep);
+ tMCA_RESULT (*connect_mcl)(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ uint16_t ctrl_psm, uint16_t sec_mask);
+ tMCA_RESULT (*disconnect_mcl)(tMCA_CL mcl);
+ tMCA_RESULT (*create_mdl_request)(tMCA_CL mcl, tMCA_DEP dep,
+ uint16_t data_psm, uint16_t mdl_id,
+ uint8_t peer_dep_id, uint8_t cfg,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+ tMCA_RESULT (*create_mdl_response)(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
+ uint8_t cfg, uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+ tMCA_RESULT (*close_mdl_request)(tMCA_DL mdl);
+ tMCA_RESULT (*reconnect_mdl_request)(tMCA_CL mcl, tMCA_DEP dep,
+ uint16_t data_psm, uint16_t mdl_id,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+ tMCA_RESULT (*reconnect_mdl_response)(tMCA_CL mcl, tMCA_DEP dep,
+ uint16_t mdl_id, uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+ tMCA_RESULT (*data_channel_config)(tMCA_CL mcl,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+ tMCA_RESULT (*abort_mdl)(tMCA_CL mcl);
+ tMCA_RESULT (*delete_mdl)(tMCA_CL mcl, uint16_t mdl_id);
+ tMCA_RESULT (*write_mdl)(tMCA_DL mdl, BT_HDR* p_pkt);
+ uint16_t (*get_l2cap_channel)(tMCA_DL mdl);
+} btmcap_test_interface_t;
+
+#endif /* MCA_API_H */
diff --git a/mtkbt/code/bt/stack/include/mca_defs.h b/mtkbt/code/bt/stack/include/mca_defs.h
new file mode 100755
index 0000000..a442471
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/mca_defs.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This contains constants definitions and other information from the MCAP
+ * specification.
+ *
+ ******************************************************************************/
+#ifndef MCA_DEFS_H
+#define MCA_DEFS_H
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+#define MCA_MIN_MTU 48
+
+/* standard op codes */
+/* invalid opcode response */
+#define MCA_OP_ERROR_RSP 0x00
+/* create an MDL, wait for an associated data channel connection */
+#define MCA_OP_MDL_CREATE_REQ 0x01
+/* response to above request */
+#define MCA_OP_MDL_CREATE_RSP 0x02
+/* req to prepare to rvc a data channel conn associated with a prev MDL */
+#define MCA_OP_MDL_RECONNECT_REQ 0x03
+/* response to above request */
+#define MCA_OP_MDL_RECONNECT_RSP 0x04
+/* stop waiting for a data channel connection */
+#define MCA_OP_MDL_ABORT_REQ 0x05
+/* response to above request */
+#define MCA_OP_MDL_ABORT_RSP 0x06
+/* delete an MDL */
+#define MCA_OP_MDL_DELETE_REQ 0x07
+/* response to above request */
+#define MCA_OP_MDL_DELETE_RSP 0x08
+#define MCA_NUM_STANDARD_OPCODE (1 + MCA_OP_MDL_DELETE_RSP)
+
+/* clock synchronization op codes */
+/* request sync capabilities & requirements */
+#define MCA_OP_SYNC_CAP_REQ 0x11
+/* indicate completion */
+#define MCA_OP_SYNC_CAP_RSP 0x12
+/* request to set the time-stamp clock */
+#define MCA_OP_SYNC_SET_REQ 0x13
+/* indicate completion */
+#define MCA_OP_SYNC_SET_RSP 0x14
+/* update of the actual time-stamp clock instant from the sync slave */
+#define MCA_OP_SYNC_INFO_IND 0x15
+
+#define MCA_FIRST_SYNC_OP MCA_OP_SYNC_CAP_REQ
+#define MCA_LAST_SYNC_OP MCA_OP_SYNC_INFO_IND
+
+/* response code */
+/* The corresponding request was received and processed successfully. */
+#define MCA_RSP_SUCCESS 0x00
+/* The Op Code received is not valid (i.e. neither a Standard Op Code nor a
+ * Clock Synchronization Protocol Op Code). */
+#define MCA_RSP_BAD_OPCODE 0x01
+/* One or more of the values in the received request is invalid. */
+#define MCA_RSP_BAD_PARAM 0x02
+/* MCA_RSP_BAD_PARAM shall be used when:
+- The request length is invalid
+- Some of the parameters have invalid values and none of the other defined
+Response Codes are more appropriate.
+*/
+/* The MDEP ID referenced does not exist on this device. */
+#define MCA_RSP_BAD_MDEP 0x03
+/* The requested MDEP currently has as many active MDLs as it can manage
+ * simultaneously. */
+#define MCA_RSP_MDEP_BUSY 0x04
+/* The MDL ID referenced is invalid. */
+#define MCA_RSP_BAD_MDL 0x05
+/* MCA_RSP_BAD_MDL shall be used when:
+- A reserved or invalid value for MDL ID was used.
+- The MDL ID referenced is not available (was never created, has been deleted,
+or was otherwise lost),
+- The MDL ID referenced in the Abort request is not the same value that was used
+to initiate the PENDING state
+*/
+/* The device is temporarily unable to complete the request. This is intended
+ * for reasons not related to the physical sensor (e.g. communication resources
+ * unavailable). */
+#define MCA_RSP_MDL_BUSY 0x06
+/* The received request is invalid in the current state. */
+#define MCA_RSP_BAD_OP 0x07
+/* MCA_RSP_BAD_OP is used when
+- Abort request was received while not in the PENDING state.
+- Create, Reconnect, or Delete request was received while in the PENDING state.
+- A response is received when a request is expected
+*/
+/* The device is temporarily unable to complete the request. This is intended
+ * for reasons relating to the physical sensor (e.g. hardware fault, low
+ * battery), or when processing resources are temporarily committed to other
+ * processes. */
+#define MCA_RSP_NO_RESOURCE 0x08
+/* An internal error other than those listed in this table was encountered while
+ * processing the request. */
+#define MCA_RSP_ERROR 0x09
+/* The Op Code that was used in this request is not supported. */
+#define MCA_RSP_NO_SUPPORT 0x0A
+/* A configuration required by a MD_CREATE_MDL or MD_RECONNECT_MDL operation has
+ * been rejected. */
+#define MCA_RSP_CFG_REJ 0x0B
+
+/* the valid range for MDEP ID is 1-0x7F */
+#define MCA_MAX_MDEP_ID 0x7F
+#define MCA_IS_VALID_MDL_ID(xxx) (((xxx) > 0) && ((xxx) <= 0xFEFF))
+#define MCA_ALL_MDL_ID 0xFFFF
+
+#endif /* MCA_DEFS_H */
diff --git a/mtkbt/code/bt/stack/include/pan_api.h b/mtkbt/code/bt/stack/include/pan_api.h
new file mode 100755
index 0000000..b4c880c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/pan_api.h
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the PAN API definitions
+ *
+ ******************************************************************************/
+#ifndef PAN_API_H
+#define PAN_API_H
+
+#include "bnep_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Define the minimum offset needed in a GKI buffer for
+ * sending PAN packets. Note, we are currently not sending
+ * extension headers, but may in the future, so allow
+ * space for them
+*/
+#define PAN_MINIMUM_OFFSET BNEP_MINIMUM_OFFSET
+
+/*
+ * The handle is passed from BNEP to PAN. The same handle is used
+ * between PAN and application as well
+*/
+#define PAN_INVALID_HANDLE BNEP_INVALID_HANDLE
+
+/* Bit map for PAN roles */
+#define PAN_ROLE_CLIENT 0x01 /* PANU role */
+#define PAN_ROLE_GN_SERVER 0x02 /* GN role */
+#define PAN_ROLE_NAP_SERVER 0x04 /* NAP role */
+
+/* Bitmap to indicate the usage of the Data */
+#define PAN_DATA_TO_HOST 0x01
+#define PAN_DATA_TO_LAN 0x02
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/* Define the result codes from PAN */
+enum {
+ PAN_SUCCESS, /* Success */
+ PAN_DISCONNECTED = BNEP_CONN_DISCONNECTED, /* Connection terminated */
+ PAN_CONN_FAILED = BNEP_CONN_FAILED, /* Connection failed */
+ PAN_NO_RESOURCES = BNEP_NO_RESOURCES, /* No resources */
+ PAN_MTU_EXCEDED = BNEP_MTU_EXCEDED, /* Attempt to write long data */
+ PAN_INVALID_OFFSET =
+ BNEP_INVALID_OFFSET, /* Insufficient offset in GKI buffer */
+ PAN_CONN_FAILED_CFG =
+ BNEP_CONN_FAILED_CFG, /* Connection failed cos of config */
+ PAN_INVALID_SRC_ROLE =
+ BNEP_CONN_FAILED_SRC_UUID, /* Connection failed wrong source UUID */
+ PAN_INVALID_DST_ROLE =
+ BNEP_CONN_FAILED_DST_UUID, /* Connection failed wrong destination UUID */
+ PAN_CONN_FAILED_UUID_SIZE =
+ BNEP_CONN_FAILED_UUID_SIZE, /* Connection failed wrong size UUID */
+ PAN_Q_SIZE_EXCEEDED = BNEP_Q_SIZE_EXCEEDED, /* Too many buffers to dest */
+ PAN_TOO_MANY_FILTERS =
+ BNEP_TOO_MANY_FILTERS, /* Too many local filters specified */
+ PAN_SET_FILTER_FAIL = BNEP_SET_FILTER_FAIL, /* Set Filter failed */
+ PAN_WRONG_HANDLE = BNEP_WRONG_HANDLE, /* Wrong handle for the connection */
+ PAN_WRONG_STATE = BNEP_WRONG_STATE, /* Connection is in wrong state */
+ PAN_SECURITY_FAIL = BNEP_SECURITY_FAIL, /* Failed because of security */
+ PAN_IGNORE_CMD = BNEP_IGNORE_CMD, /* To ignore the rcvd command */
+ PAN_TX_FLOW_ON = BNEP_TX_FLOW_ON, /* tx data flow enabled */
+ PAN_TX_FLOW_OFF = BNEP_TX_FLOW_OFF, /* tx data flow disabled */
+ PAN_FAILURE /* Failure */
+
+};
+typedef uint8_t tPAN_RESULT;
+
+/*****************************************************************
+ * Callback Function Prototypes
+ ****************************************************************/
+
+/* This is call back function used to report connection status
+ * to the application. The second parameter true means
+ * to create the bridge and false means to remove it.
+*/
+typedef void(tPAN_CONN_STATE_CB)(uint16_t handle, BD_ADDR bd_addr,
+ tPAN_RESULT state, bool is_role_change,
+ uint8_t src_role, uint8_t dst_role);
+
+/* This is call back function used to create bridge for the
+ * Connected device. The parameter "state" indicates
+ * whether to create the bridge or remove it. true means
+ * to create the bridge and false means to remove it.
+*/
+typedef void(tPAN_BRIDGE_REQ_CB)(BD_ADDR bd_addr, bool state);
+
+/* Data received indication callback prototype. Parameters are
+ * Source BD/Ethernet Address
+ * Dest BD/Ethernet address
+ * Protocol
+ * Address of buffer (or data if non-GKI)
+ * Length of data (non-GKI)
+ * ext is flag to indicate whether it has aby extension headers
+ * Flag used to indicate to forward on LAN
+ * false - Use it for internal stack
+ * true - Send it across the ethernet as well
+*/
+typedef void(tPAN_DATA_IND_CB)(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool ext, bool forward);
+
+/* Data buffer received indication callback prototype. Parameters are
+ * Source BD/Ethernet Address
+ * Dest BD/Ethernet address
+ * Protocol
+ * pointer to the data buffer
+ * ext is flag to indicate whether it has aby extension headers
+ * Flag used to indicate to forward on LAN
+ * false - Use it for internal stack
+ * true - Send it across the ethernet as well
+*/
+typedef void(tPAN_DATA_BUF_IND_CB)(uint16_t handle, BD_ADDR src, BD_ADDR dst,
+ uint16_t protocol, BT_HDR* p_buf, bool ext,
+ bool forward);
+
+/* Flow control callback for TX data. Parameters are
+ * Handle to the connection
+ * Event flow status
+*/
+typedef void(tPAN_TX_DATA_FLOW_CB)(uint16_t handle, tPAN_RESULT event);
+
+/* Filters received indication callback prototype. Parameters are
+ * Handle to the connection
+ * true if the cb is called for indication
+ * Ignore this if it is indication, otherwise it is the result
+ * for the filter set operation performed by the local
+ * device
+ * Number of protocol filters present
+ * Pointer to the filters start. Filters are present in pairs
+ * of start of the range and end of the range.
+ * They will be present in big endian order. First
+ * two bytes will be starting of the first range and
+ * next two bytes will be ending of the range.
+*/
+typedef void(tPAN_FILTER_IND_CB)(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters);
+
+/* Multicast Filters received indication callback prototype. Parameters are
+ * Handle to the connection
+ * true if the cb is called for indication
+ * Ignore this if it is indication, otherwise it is the result
+ * for the filter set operation performed by the local
+ * device
+ * Number of multicast filters present
+ * Pointer to the filters start. Filters are present in pairs
+ * of start of the range and end of the range.
+ * First six bytes will be starting of the first range and
+ * next six bytes will be ending of the range.
+*/
+typedef void(tPAN_MFILTER_IND_CB)(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_mfilters,
+ uint8_t* p_mfilters);
+
+/* This structure is used to register with PAN profile
+ * It is passed as a parameter to PAN_Register call.
+*/
+typedef struct {
+ tPAN_CONN_STATE_CB* pan_conn_state_cb; /* Connection state callback */
+ tPAN_BRIDGE_REQ_CB* pan_bridge_req_cb; /* Bridge request callback */
+ tPAN_DATA_IND_CB* pan_data_ind_cb; /* Data indication callback */
+ tPAN_DATA_BUF_IND_CB*
+ pan_data_buf_ind_cb; /* Data buffer indication callback */
+ tPAN_FILTER_IND_CB*
+ pan_pfilt_ind_cb; /* protocol filter indication callback */
+ tPAN_MFILTER_IND_CB*
+ pan_mfilt_ind_cb; /* multicast filter indication callback */
+ tPAN_TX_DATA_FLOW_CB* pan_tx_data_flow_cb; /* data flow callback */
+ char* user_service_name; /* Service name for PANU role */
+ char* gn_service_name; /* Service name for GN role */
+ char* nap_service_name; /* Service name for NAP role */
+
+} tPAN_REGISTER;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function PAN_Register
+ *
+ * Description This function is called by the application to register
+ * its callbacks with PAN profile. The application then
+ * should set the PAN role explicitly.
+ *
+ * Parameters: p_register - contains all callback function pointers
+ *
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+extern void PAN_Register(tPAN_REGISTER* p_register);
+
+/*******************************************************************************
+ *
+ * Function PAN_Deregister
+ *
+ * Description This function is called by the application to de-register
+ * its callbacks with PAN profile. This will make the PAN to
+ * become inactive. This will deregister PAN services from SDP
+ * and close all active connections
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+extern void PAN_Deregister(void);
+
+/*******************************************************************************
+ *
+ * Function PAN_SetRole
+ *
+ * Description This function is called by the application to set the PAN
+ * profile role. This should be called after PAN_Register.
+ * This can be called any time to change the PAN role
+ *
+ * Parameters: role - is bit map of roles to be active
+ * PAN_ROLE_CLIENT is for PANU role
+ * PAN_ROLE_GN_SERVER is for GN role
+ * PAN_ROLE_NAP_SERVER is for NAP role
+ * sec_mask - Security mask for different roles
+ * It is array of uint8_t. The bytes
+ * represent the security for roles PANU,
+ * GN and NAP in order
+ *
+ * p_user_name - Service name for PANU role
+ * p_gn_name - Service name for GN role
+ * p_nap_name - Service name for NAP role
+ * Can be NULL if user wants it to be default
+ *
+ * Returns PAN_SUCCESS - if the role is set successfully
+ * PAN_FAILURE - if the role is not valid
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_SetRole(uint8_t role, uint8_t* sec_mask,
+ const char* p_user_name, const char* p_gn_name,
+ const char* p_nap_name);
+
+/*******************************************************************************
+ *
+ * Function PAN_Connect
+ *
+ * Description This function is called by the application to initiate a
+ * connection to the remote device
+ *
+ * Parameters: rem_bda - BD Addr of the remote device
+ * src_role - Role of the local device for the connection
+ * dst_role - Role of the remote device for the connection
+ * PAN_ROLE_CLIENT is for PANU role
+ * PAN_ROLE_GN_SERVER is for GN role
+ * PAN_ROLE_NAP_SERVER is for NAP role
+ * *handle - Pointer for returning Handle to the connection
+ *
+ * Returns PAN_SUCCESS - if the connection is initiated successfully
+ * PAN_NO_RESOURCES - resources are not sufficent
+ * PAN_FAILURE - if the connection cannot be initiated
+ * this can be because of the combination of
+ * src and dst roles may not be valid or
+ * allowed at that point of time
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_Connect(BD_ADDR rem_bda, uint8_t src_role,
+ uint8_t dst_role, uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function PAN_Disconnect
+ *
+ * Description This is used to disconnect the connection
+ *
+ * Parameters: handle - handle for the connection
+ *
+ * Returns PAN_SUCCESS - if the connection is closed successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in disconnecting
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_Disconnect(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function PAN_Write
+ *
+ * Description This sends data over the PAN connections. If this is called
+ * on GN or NAP side and the packet is multicast or broadcast
+ * it will be sent on all the links. Otherwise the correct link
+ * is found based on the destination address and forwarded on
+ * it. If the return value is not PAN_SUCCESS the application
+ * should take care of releasing the message buffer
+ *
+ * Parameters: dst - MAC or BD Addr of the destination device
+ * src - MAC or BD Addr of the source who sent this packet
+ * protocol - protocol of the ethernet packet like IP or ARP
+ * p_data - pointer to the data
+ * len - length of the data
+ * ext - to indicate that extension headers present
+ *
+ * Returns PAN_SUCCESS - if the data is sent successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in sending data
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_Write(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool ext);
+
+/*******************************************************************************
+ *
+ * Function PAN_WriteBuf
+ *
+ * Description This sends data over the PAN connections. If this is called
+ * on GN or NAP side and the packet is multicast or broadcast
+ * it will be sent on all the links. Otherwise the correct link
+ * is found based on the destination address and forwarded on
+ * it. If the return value is not PAN_SUCCESS the application
+ * should take care of releasing the message buffer
+ *
+ * Parameters: dst - MAC or BD Addr of the destination device
+ * src - MAC or BD Addr of the source who sent this packet
+ * protocol - protocol of the ethernet packet like IP or ARP
+ * p_buf - pointer to the data buffer
+ * ext - to indicate that extension headers present
+ *
+ * Returns PAN_SUCCESS - if the data is sent successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in sending data
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_WriteBuf(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, BT_HDR* p_buf, bool ext);
+
+/*******************************************************************************
+ *
+ * Function PAN_SetProtocolFilters
+ *
+ * Description This function is used to set protocol filters on the peer
+ *
+ * Parameters: handle - handle for the connection
+ * num_filters - number of protocol filter ranges
+ * start - array of starting protocol numbers
+ * end - array of ending protocol numbers
+ *
+ *
+ * Returns PAN_SUCCESS if protocol filters are set successfully
+ * PAN_FAILURE if connection not found or error in setting
+ *
+ ******************************************************************************/
+extern tPAN_RESULT PAN_SetProtocolFilters(uint16_t handle, uint16_t num_filters,
+ uint16_t* p_start_array,
+ uint16_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function PAN_SetMulticastFilters
+ *
+ * Description This function is used to set multicast filters on the peer
+ *
+ * Parameters: handle - handle for the connection
+ * num_filters - number of multicast filter ranges
+ * p_start_array - Pointer to sequence of beginings of all
+ * multicast address ranges
+ * p_end_array - Pointer to sequence of ends of all
+ * multicast address ranges
+ *
+ *
+ * Returns PAN_SUCCESS if multicast filters are set successfully
+ * PAN_FAILURE if connection not found or error in setting
+ *
+ ******************************************************************************/
+extern tBNEP_RESULT PAN_SetMulticastFilters(uint16_t handle,
+ uint16_t num_mcast_filters,
+ uint8_t* p_start_array,
+ uint8_t* p_end_array);
+
+/*******************************************************************************
+ *
+ * Function PAN_SetTraceLevel
+ *
+ * Description This function sets the trace level for PAN. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t PAN_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function PAN_Init
+ *
+ * Description This function initializes the PAN unit. It should be called
+ * before accessing any other APIs to initialize the control
+ * block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void PAN_Init(void);
+
+#endif /* PAN_API_H */
diff --git a/mtkbt/code/bt/stack/include/port_api.h b/mtkbt/code/bt/stack/include/port_api.h
new file mode 100755
index 0000000..ac7aeab
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/port_api.h
@@ -0,0 +1,652 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the PORT API definitions
+ *
+ ******************************************************************************/
+#ifndef PORT_API_H
+#define PORT_API_H
+
+#include "bt_target.h"
+
+/*****************************************************************************
+ * Constants and Types
+ ****************************************************************************/
+
+/*
+ * Define port settings structure send from the application in the
+ * set settings request, or to the application in the set settings indication.
+*/
+typedef struct {
+#define PORT_BAUD_RATE_2400 0x00
+#define PORT_BAUD_RATE_4800 0x01
+#define PORT_BAUD_RATE_7200 0x02
+#define PORT_BAUD_RATE_9600 0x03
+#define PORT_BAUD_RATE_19200 0x04
+#define PORT_BAUD_RATE_38400 0x05
+#define PORT_BAUD_RATE_57600 0x06
+#define PORT_BAUD_RATE_115200 0x07
+#define PORT_BAUD_RATE_230400 0x08
+
+ uint8_t baud_rate;
+
+#define PORT_5_BITS 0x00
+#define PORT_6_BITS 0x01
+#define PORT_7_BITS 0x02
+#define PORT_8_BITS 0x03
+
+ uint8_t byte_size;
+
+#define PORT_ONESTOPBIT 0x00
+#define PORT_ONE5STOPBITS 0x01
+ uint8_t stop_bits;
+
+#define PORT_PARITY_NO 0x00
+#define PORT_PARITY_YES 0x01
+ uint8_t parity;
+
+#define PORT_ODD_PARITY 0x00
+#define PORT_EVEN_PARITY 0x01
+#define PORT_MARK_PARITY 0x02
+#define PORT_SPACE_PARITY 0x03
+
+ uint8_t parity_type;
+
+#define PORT_FC_OFF 0x00
+#define PORT_FC_XONXOFF_ON_INPUT 0x01
+#define PORT_FC_XONXOFF_ON_OUTPUT 0x02
+#define PORT_FC_CTS_ON_INPUT 0x04
+#define PORT_FC_CTS_ON_OUTPUT 0x08
+#define PORT_FC_DSR_ON_INPUT 0x10
+#define PORT_FC_DSR_ON_OUTPUT 0x20
+
+ uint8_t fc_type;
+
+ uint8_t rx_char1;
+
+#define PORT_XON_DC1 0x11
+ uint8_t xon_char;
+
+#define PORT_XOFF_DC3 0x13
+ uint8_t xoff_char;
+
+} tPORT_STATE;
+
+/*
+ * Define the callback function prototypes. Parameters are specific
+ * to each event and are described bellow
+*/
+typedef int(tPORT_DATA_CALLBACK)(uint16_t port_handle, void* p_data,
+ uint16_t len);
+
+#define DATA_CO_CALLBACK_TYPE_INCOMING 1
+#define DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE 2
+#define DATA_CO_CALLBACK_TYPE_OUTGOING 3
+typedef int(tPORT_DATA_CO_CALLBACK)(uint16_t port_handle, uint8_t* p_buf,
+ uint16_t len, int type);
+
+typedef void(tPORT_CALLBACK)(uint32_t code, uint16_t port_handle);
+
+/*
+ * Define events that registered application can receive in the callback
+*/
+
+#define PORT_EV_RXCHAR 0x00000001 /* Any Character received */
+#define PORT_EV_RXFLAG 0x00000002 /* Received certain character */
+#define PORT_EV_TXEMPTY 0x00000004 /* Transmitt Queue Empty */
+#define PORT_EV_CTS 0x00000008 /* CTS changed state */
+#define PORT_EV_DSR 0x00000010 /* DSR changed state */
+#define PORT_EV_RLSD 0x00000020 /* RLSD changed state */
+#define PORT_EV_BREAK 0x00000040 /* BREAK received */
+#define PORT_EV_ERR 0x00000080 /* Line status error occurred */
+#define PORT_EV_RING 0x00000100 /* Ring signal detected */
+#define PORT_EV_CTSS 0x00000400 /* CTS state */
+#define PORT_EV_DSRS 0x00000800 /* DSR state */
+#define PORT_EV_RLSDS 0x00001000 /* RLSD state */
+#define PORT_EV_OVERRUN 0x00002000 /* receiver buffer overrun */
+#define PORT_EV_TXCHAR 0x00004000 /* Any character transmitted */
+
+/* RFCOMM connection established */
+#define PORT_EV_CONNECTED 0x00000200
+/* Unable to establish connection or disconnected */
+#define PORT_EV_CONNECT_ERR 0x00008000
+/* data flow enabled flag changed by remote */
+#define PORT_EV_FC 0x00010000
+/* data flow enable status true = enabled */
+#define PORT_EV_FCS 0x00020000
+
+/*
+ * To register for events application should provide bitmask with
+ * corresponding bit set
+*/
+
+#define PORT_MASK_ALL \
+ (PORT_EV_RXCHAR | PORT_EV_TXEMPTY | PORT_EV_CTS | PORT_EV_DSR | \
+ PORT_EV_RLSD | PORT_EV_BREAK | PORT_EV_ERR | PORT_EV_RING | \
+ PORT_EV_CONNECT_ERR | PORT_EV_DSRS | PORT_EV_CTSS | PORT_EV_RLSDS | \
+ PORT_EV_RXFLAG | PORT_EV_TXCHAR | PORT_EV_OVERRUN | PORT_EV_FC | \
+ PORT_EV_FCS | PORT_EV_CONNECTED)
+
+/*
+ * Define port result codes
+*/
+#define PORT_SUCCESS 0
+
+#define PORT_ERR_BASE 0
+
+#define PORT_UNKNOWN_ERROR (PORT_ERR_BASE + 1)
+#define PORT_ALREADY_OPENED (PORT_ERR_BASE + 2)
+#define PORT_CMD_PENDING (PORT_ERR_BASE + 3)
+#define PORT_APP_NOT_REGISTERED (PORT_ERR_BASE + 4)
+#define PORT_NO_MEM (PORT_ERR_BASE + 5)
+#define PORT_NO_RESOURCES (PORT_ERR_BASE + 6)
+#define PORT_BAD_BD_ADDR (PORT_ERR_BASE + 7)
+#define PORT_BAD_HANDLE (PORT_ERR_BASE + 9)
+#define PORT_NOT_OPENED (PORT_ERR_BASE + 10)
+#define PORT_LINE_ERR (PORT_ERR_BASE + 11)
+#define PORT_START_FAILED (PORT_ERR_BASE + 12)
+#define PORT_PAR_NEG_FAILED (PORT_ERR_BASE + 13)
+#define PORT_PORT_NEG_FAILED (PORT_ERR_BASE + 14)
+#define PORT_SEC_FAILED (PORT_ERR_BASE + 15)
+#define PORT_PEER_CONNECTION_FAILED (PORT_ERR_BASE + 16)
+#define PORT_PEER_FAILED (PORT_ERR_BASE + 17)
+#define PORT_PEER_TIMEOUT (PORT_ERR_BASE + 18)
+#define PORT_CLOSED (PORT_ERR_BASE + 19)
+#define PORT_TX_FULL (PORT_ERR_BASE + 20)
+#define PORT_LOCAL_CLOSED (PORT_ERR_BASE + 21)
+#define PORT_LOCAL_TIMEOUT (PORT_ERR_BASE + 22)
+#define PORT_TX_QUEUE_DISABLED (PORT_ERR_BASE + 23)
+#define PORT_PAGE_TIMEOUT (PORT_ERR_BASE + 24)
+#define PORT_INVALID_SCN (PORT_ERR_BASE + 25)
+
+#define PORT_ERR_MAX (PORT_ERR_BASE + 26)
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_CreateConnection
+ *
+ * Description RFCOMM_CreateConnection is used from the application to
+ * establish a serial port connection to the peer device,
+ * or allow RFCOMM to accept a connection from the peer
+ * application.
+ *
+ * Parameters: scn - Service Channel Number as registered with
+ * the SDP (server) or obtained using SDP from
+ * the peer device (client).
+ * is_server - true if requesting application is a server
+ * mtu - Maximum frame size the application can accept
+ * bd_addr - BD_ADDR of the peer (client)
+ * mask - specifies events to be enabled. A value
+ * of zero disables all events.
+ * p_handle - OUT pointer to the handle.
+ * p_mgmt_cb - pointer to callback function to receive
+ * connection up/down events.
+ * Notes:
+ *
+ * Server can call this function with the same scn parameter multiple times if
+ * it is ready to accept multiple simulteneous connections.
+ *
+ * DLCI for the connection is (scn * 2 + 1) if client originates connection on
+ * existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+ * For the server DLCI can be changed later if client will be calling it using
+ * (scn * 2 + 1) dlci.
+ *
+ ******************************************************************************/
+extern int RFCOMM_CreateConnection(uint16_t uuid, uint8_t scn, bool is_server,
+ uint16_t mtu, BD_ADDR bd_addr,
+ uint16_t* p_handle,
+ tPORT_CALLBACK* p_mgmt_cb);
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_RemoveConnection
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ *
+ ******************************************************************************/
+extern int RFCOMM_RemoveConnection(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_RemoveServer
+ *
+ * Description This function is called to close the server port.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+extern int RFCOMM_RemoveServer(uint16_t handle);
+
+/*******************************************************************************
+ *
+ * Function PORT_SetEventCallback
+ *
+ * Description Set event callback the specified connection.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * p_callback - address of the callback function which should
+ * be called from the RFCOMM when an event
+ * specified in the mask occurs.
+ *
+ ******************************************************************************/
+extern int PORT_SetEventCallback(uint16_t port_handle,
+ tPORT_CALLBACK* p_port_cb);
+
+/*******************************************************************************
+ *
+ * Function PORT_ClearKeepHandleFlag
+ *
+ * Description Called to clear the keep handle flag, which will cause
+ * not to keep the port handle open when closed
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+int PORT_ClearKeepHandleFlag(uint16_t port_handle);
+
+/*******************************************************************************
+ *
+ * Function PORT_SetEventCallback
+ *
+ * Description Set event data callback the specified connection.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * p_callback - address of the callback function which should
+ * be called from the RFCOMM when a data
+ * packet is received.
+ *
+ ******************************************************************************/
+extern int PORT_SetDataCallback(uint16_t port_handle,
+ tPORT_DATA_CALLBACK* p_cb);
+
+extern int PORT_SetDataCOCallback(uint16_t port_handle,
+ tPORT_DATA_CO_CALLBACK* p_port_cb);
+/*******************************************************************************
+ *
+ * Function PORT_SetEventMask
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * mask - specifies events to be enabled. A value
+ * of zero disables all events.
+ *
+ ******************************************************************************/
+extern int PORT_SetEventMask(uint16_t port_handle, uint32_t mask);
+
+/*******************************************************************************
+ *
+ * Function PORT_CheckConnection
+ *
+ * Description This function returns PORT_SUCCESS if connection referenced
+ * by handle is up and running
+ *
+ * Parameters: handle - Handle of the port returned in the Open
+ * bd_addr - OUT bd_addr of the peer
+ * p_lcid - OUT L2CAP's LCID
+ *
+ ******************************************************************************/
+extern int PORT_CheckConnection(uint16_t handle, BD_ADDR bd_addr,
+ uint16_t* p_lcid);
+
+/*******************************************************************************
+ *
+ * Function PORT_IsOpening
+ *
+ * Description This function returns true if there is any RFCOMM connection
+ * opening in process.
+ *
+ * Parameters: true if any connection opening is found
+ * bd_addr - bd_addr of the peer
+ *
+ ******************************************************************************/
+extern bool PORT_IsOpening(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function PORT_SetState
+ *
+ * Description This function configures connection according to the
+ * specifications in the tPORT_STATE structure.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_settings - Pointer to a tPORT_STATE structure containing
+ * configuration information for the connection.
+ *
+ ******************************************************************************/
+extern int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings);
+
+/*******************************************************************************
+ *
+ * Function PORT_GetRxQueueCnt
+ *
+ * Description This function return number of buffers on the rx queue.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_rx_queue_count - Pointer to return queue count in.
+ *
+ ******************************************************************************/
+extern int PORT_GetRxQueueCnt(uint16_t handle, uint16_t* p_rx_queue_count);
+
+/*******************************************************************************
+ *
+ * Function PORT_GetState
+ *
+ * Description This function is called to fill tPORT_STATE structure
+ * with the current control settings for the port
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_settings - Pointer to a tPORT_STATE structure in which
+ * configuration information is returned.
+ *
+ ******************************************************************************/
+extern int PORT_GetState(uint16_t handle, tPORT_STATE* p_settings);
+
+/*******************************************************************************
+ *
+ * Function PORT_Control
+ *
+ * Description This function directs a specified connection to pass control
+ * control information to the peer device.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * signal - specify the function to be passed
+ *
+ ******************************************************************************/
+#define PORT_SET_DTRDSR 0x01
+#define PORT_CLR_DTRDSR 0x02
+#define PORT_SET_CTSRTS 0x03
+#define PORT_CLR_CTSRTS 0x04
+#define PORT_SET_RI 0x05 /* DCE only */
+#define PORT_CLR_RI 0x06 /* DCE only */
+#define PORT_SET_DCD 0x07 /* DCE only */
+#define PORT_CLR_DCD 0x08 /* DCE only */
+#define PORT_BREAK 0x09 /* Break event */
+
+extern int PORT_Control(uint16_t handle, uint8_t signal);
+
+/*******************************************************************************
+ *
+ * Function PORT_FlowControl
+ *
+ * Description This function directs a specified connection to pass
+ * flow control message to the peer device. Enable flag passed
+ * shows if port can accept more data.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * enable - enables data flow
+ *
+ ******************************************************************************/
+extern int PORT_FlowControl(uint16_t handle, bool enable);
+
+/*******************************************************************************
+ *
+ * Function PORT_FlowControl_MaxCredit
+ *
+ * Description This function directs a specified connection to pass
+ * flow control message to the peer device. Enable flag passed
+ * shows if port can accept more data. It also sends max credit
+ * when data flow enabled
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * enable - enables data flow
+ *
+ ******************************************************************************/
+extern int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable);
+
+/*******************************************************************************
+ *
+ * Function PORT_GetModemStatus
+ *
+ * Description This function retrieves modem control signals. Normally
+ * application will call this function after a callback
+ * function is called with notification that one of signals
+ * has been changed.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * callback.
+ * p_signal - specify the pointer to control signals info
+ *
+ ******************************************************************************/
+#define PORT_DTRDSR_ON 0x01
+#define PORT_CTSRTS_ON 0x02
+#define PORT_RING_ON 0x04
+#define PORT_DCD_ON 0x08
+
+/*
+ * Define default initial local modem signals state after connection established
+*/
+#define PORT_OBEX_DEFAULT_SIGNAL_STATE \
+ (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_SPP_DEFAULT_SIGNAL_STATE \
+ (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_PPP_DEFAULT_SIGNAL_STATE \
+ (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON)
+#define PORT_DUN_DEFAULT_SIGNAL_STATE (PORT_DTRDSR_ON | PORT_CTSRTS_ON)
+
+extern int PORT_GetModemStatus(uint16_t handle, uint8_t* p_control_signal);
+
+/*******************************************************************************
+ *
+ * Function PORT_ClearError
+ *
+ * Description This function retreives information about a communications
+ * error and reports current status of a connection. The
+ * function should be called when an error occures to clear
+ * the connection error flag and to enable additional read
+ * and write operations.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_errors - pointer of the variable to receive error codes
+ * p_status - pointer to the tPORT_STATUS structur to receive
+ * connection status
+ *
+ ******************************************************************************/
+
+#define PORT_ERR_BREAK 0x01 /* Break condition occured on the peer device */
+#define PORT_ERR_OVERRUN 0x02 /* Overrun is reported by peer device */
+#define PORT_ERR_FRAME 0x04 /* Framing error reported by peer device */
+#define PORT_ERR_RXOVER 0x08 /* Input queue overflow occured */
+#define PORT_ERR_TXFULL 0x10 /* Output queue overflow occured */
+
+typedef struct {
+#define PORT_FLAG_CTS_HOLD 0x01 /* Tx is waiting for CTS signal */
+#define PORT_FLAG_DSR_HOLD 0x02 /* Tx is waiting for DSR signal */
+#define PORT_FLAG_RLSD_HOLD 0x04 /* Tx is waiting for RLSD signal */
+
+ uint16_t flags;
+ uint16_t in_queue_size; /* Number of bytes in the input queue */
+ uint16_t out_queue_size; /* Number of bytes in the output queue */
+ uint16_t mtu_size; /* peer MTU size */
+} tPORT_STATUS;
+
+extern int PORT_ClearError(uint16_t handle, uint16_t* p_errors,
+ tPORT_STATUS* p_status);
+
+/*******************************************************************************
+ *
+ * Function PORT_SendError
+ *
+ * Description This function send a communications error to the peer device
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * errors - receive error codes
+ *
+ ******************************************************************************/
+extern int PORT_SendError(uint16_t handle, uint8_t errors);
+
+/*******************************************************************************
+ *
+ * Function PORT_GetQueueStatus
+ *
+ * Description This function reports current status of a connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_status - pointer to the tPORT_STATUS structur to receive
+ * connection status
+ *
+ ******************************************************************************/
+extern int PORT_GetQueueStatus(uint16_t handle, tPORT_STATUS* p_status);
+
+/*******************************************************************************
+ *
+ * Function PORT_Purge
+ *
+ * Description This function discards all the data from the output or
+ * input queues of the specified connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * purge_flags - specify the action to take.
+ *
+ ******************************************************************************/
+#define PORT_PURGE_TXCLEAR 0x01
+#define PORT_PURGE_RXCLEAR 0x02
+
+extern int PORT_Purge(uint16_t handle, uint8_t purge_flags);
+
+/*******************************************************************************
+ *
+ * Function PORT_Read
+ *
+ * Description This function returns the pointer to the buffer received
+ * from the peer device. Normally application will call this
+ * function after receiving PORT_EVT_RXCHAR event.
+ * Application calling this function is responsible to free
+ * buffer returned.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * callback.
+ * pp_buf - pointer to address of buffer with data,
+ *
+ ******************************************************************************/
+extern int PORT_Read(uint16_t handle, BT_HDR** pp_buf);
+
+/*******************************************************************************
+ *
+ * Function PORT_ReadData
+ *
+ * Description Normally application will call this function after receiving
+ * PORT_EVT_RXCHAR event.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * callback.
+ * p_data - Data area
+ * max_len - Byte count requested
+ * p_len - Byte count received
+ *
+ ******************************************************************************/
+extern int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len,
+ uint16_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function PORT_Write
+ *
+ * Description This function to send BT buffer to the peer device.
+ * Application should not free the buffer.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_buf - pointer to the buffer with data,
+ *
+ ******************************************************************************/
+extern int PORT_Write(uint16_t handle, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function PORT_WriteData
+ *
+ * Description This function is called from the legacy application to
+ * send data.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_data - Data area
+ * max_len - Byte count to write
+ * p_len - Bytes written
+ *
+ ******************************************************************************/
+extern int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len,
+ uint16_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function PORT_WriteDataCO
+ *
+ * Description Normally not GKI aware application will call this function
+ * to send data to the port by callout functions.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+extern int PORT_WriteDataCO(uint16_t handle, int* p_len);
+
+/*******************************************************************************
+ *
+ * Function PORT_Test
+ *
+ * Description Application can call this function to send RFCOMM Test frame
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_data - Data area
+ * max_len - Byte count requested
+ *
+ ******************************************************************************/
+extern int PORT_Test(uint16_t handle, uint8_t* p_data, uint16_t len);
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_Init
+ *
+ * Description This function is called to initialize RFCOMM layer
+ *
+ ******************************************************************************/
+extern void RFCOMM_Init(void);
+
+/*******************************************************************************
+ *
+ * Function PORT_SetTraceLevel
+ *
+ * Description Set the trace level for RFCOMM. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+extern uint8_t PORT_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function PORT_GetResultString
+ *
+ * Description This function returns the human-readable string for a given
+ * result code.
+ *
+ * Returns a pointer to the human-readable string for the given
+ * result. Note that the string returned must not be freed.
+ *
+ ******************************************************************************/
+extern const char* PORT_GetResultString(const uint8_t result_code);
+
+#endif /* PORT_API_H */
diff --git a/mtkbt/code/bt/stack/include/port_ext.h b/mtkbt/code/bt/stack/include/port_ext.h
new file mode 100755
index 0000000..ec8eb94
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/port_ext.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains external definitions of Port Emulation entity unit
+ *
+ ******************************************************************************/
+
+#ifndef PORTEXT_H
+#define PORTEXT_H
+
+#include "bt_common.h"
+
+extern void rfcomm_port_timer_timeout(void* data);
+extern void rfcomm_mcb_timer_timeout(void* data);
+#endif
diff --git a/mtkbt/code/bt/stack/include/profiles_api.h b/mtkbt/code/bt/stack/include/profiles_api.h
new file mode 100755
index 0000000..aa3b884
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/profiles_api.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef PROFILES_API_H
+#define PROFILES_API_H
+
+#include "bt_target.h"
+#include "btm_api.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+#define BT_PASS 0 /* Used for general successful function returns */
+
+/*** Port entity passes back 8 bit errors; will use upper byte offset ***/
+#define PORT_ERR_GRP 0x0000 /* base offset for port entity */
+#define GAP_ERR_GRP 0x0100 /* base offset for GAP profile */
+#define SPP_ERR_GRP 0x0200 /* base offset for serial port profile */
+#define HCRP_ERR_GRP 0x0300 /* base offset for HCRP */
+#define HCRPM_ERR_GRP 0x0400 /* base offset for HCRPM */
+
+/* #define HSP2_ERR_GRP 0x0F00 */
+
+/* security level definitions (tBT_SECURITY) */
+#define BT_USE_DEF_SECURITY 0
+#define BT_SEC_MODE_NONE BTM_SEC_MODE_NONE
+#define BT_SEC_MODE_SERVICE BTM_SEC_MODE_SERVICE
+#define BT_SEC_MODE_LINK BTM_SEC_MODE_LINK
+
+/* security mask definitions (tBT_SECURITY) */
+/* The following definitions are OR'd together to form the security
+ * requirements */
+/* Inbound call requires authorization */
+#define BT_SEC_IN_AUTHORIZE BTM_SEC_IN_AUTHORIZE
+/* Inbound call requires authentication */
+#define BT_SEC_IN_AUTHENTICATE BTM_SEC_IN_AUTHENTICATE
+/* Inbound call requires encryption */
+#define BT_SEC_IN_ENCRYPT BTM_SEC_IN_ENCRYPT
+/* Outbound call requires authorization */
+#define BT_SEC_OUT_AUTHORIZE BTM_SEC_OUT_AUTHORIZE
+/* Outbound call requires authentication */
+#define BT_SEC_OUT_AUTHENTICATE BTM_SEC_OUT_AUTHENTICATE
+/* Outbound call requires encryption */
+#define BT_SEC_OUT_ENCRYPT BTM_SEC_OUT_ENCRYPT
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/*
+ * Security Definitions
+ * This following definitions are used to indicate the security
+ * requirements for a service.
+*/
+typedef struct {
+ uint8_t level;
+ uint8_t mask;
+} tBT_SECURITY;
+
+#endif /* PROFILES_API_H */
diff --git a/mtkbt/code/bt/stack/include/rfcdefs.h b/mtkbt/code/bt/stack/include/rfcdefs.h
new file mode 100755
index 0000000..5118ccd
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/rfcdefs.h
@@ -0,0 +1,245 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/****************************************************************************
+ *
+ * This file contains definitions for the RFCOMM protocol
+ *
+ ****************************************************************************/
+
+#ifndef RFCDEFS_H
+#define RFCDEFS_H
+
+#define PORT_MAX_RFC_PORTS 31
+
+/*
+ * If nothing is negotiated MTU should be 127
+*/
+#define RFCOMM_DEFAULT_MTU 127
+
+/*
+ * Define used by RFCOMM TS frame types
+*/
+#define RFCOMM_SABME 0x2F
+#define RFCOMM_UA 0x63
+#define RFCOMM_DM 0x0F
+#define RFCOMM_DISC 0x43
+#define RFCOMM_UIH 0xEF
+
+/*
+ * Defenitions for the TS control frames
+*/
+#define RFCOMM_CTRL_FRAME_LEN 3
+#define RFCOMM_MIN_OFFSET 5 /* ctrl 2 , len 1 or 2 bytes, credit 1 byte */
+#define RFCOMM_DATA_OVERHEAD (RFCOMM_MIN_OFFSET + 1) /* add 1 for checksum */
+
+#define RFCOMM_EA 1
+#define RFCOMM_EA_MASK 0x01
+#define RFCOMM_CR_MASK 0x02
+#define RFCOMM_SHIFT_CR 1
+#define RFCOMM_SHIFT_DLCI 2
+#define RFCOMM_SHIFT_DLCI2 6
+#define RFCOMM_PF 0x10
+#define RFCOMM_PF_MASK 0x10
+#define RFCOMM_PF_OFFSET 4
+#define RFCOMM_SHIFT_LENGTH1 1
+#define RFCOMM_SHIFT_LENGTH2 7
+#define RFCOMM_SHIFT_MX_CTRL_TYPE 2
+
+#define RFCOMM_INITIATOR_CMD 1
+#define RFCOMM_INITIATOR_RSP 0
+#define RFCOMM_RESPONDER_CMD 0
+#define RFCOMM_RESPONDER_RSP 1
+
+#define RFCOMM_PARSE_CTRL_FIELD(ea, cr, dlci, p_data) \
+ { \
+ (ea) = *(p_data)&RFCOMM_EA; \
+ (cr) = (*(p_data)&RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR; \
+ (dlci) = *(p_data)++ >> RFCOMM_SHIFT_DLCI; \
+ if (!(ea)) (dlci) += *(p_data)++ << RFCOMM_SHIFT_DLCI2; \
+ }
+
+#define RFCOMM_FORMAT_CTRL_FIELD(p_data, ea, cr, dlci) \
+ (*(p_data)++ = (ea) | (cr) | ((dlci) << RFCOMM_SHIFT_DLCI))
+
+#define RFCOMM_PARSE_TYPE_FIELD(type, pf, p_data) \
+ { \
+ (type) = *(p_data) & ~RFCOMM_PF_MASK; \
+ (pf) = (*(p_data)++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET; \
+ }
+
+#define RFCOMM_FORMAT_TYPE_FIELD(p_data, type, pf) \
+ *(p_data)++ = ((type) | ((pf) << RFCOMM_PF_OFFSET)) { \
+ (type) = *(p_data) & ~RFCOMM_PF_MASK; \
+ (pf) = (*(p_data)++ & RFCOMM_PF_MASK) >> RFCOMM_PF_OFFSET; \
+ }
+
+#define RFCOMM_PARSE_LEN_FIELD(ea, length, p_data) \
+ { \
+ (ea) = (*(p_data)&RFCOMM_EA); \
+ (length) = (*(p_data)++ >> RFCOMM_SHIFT_LENGTH1); \
+ if (!(ea)) (length) += (*(p_data)++ << RFCOMM_SHIFT_LENGTH2); \
+ }
+
+#define RFCOMM_FRAME_IS_CMD(initiator, cr) \
+ (((initiator) && !(cr)) || (!(initiator) && (cr)))
+
+#define RFCOMM_FRAME_IS_RSP(initiator, cr) \
+ (((initiator) && (cr)) || (!(initiator) && !(cr)))
+
+#define RFCOMM_CR(initiator, is_command) \
+ ((((initiator) && (is_command)) || (!(initiator) && !(is_command))) << 1)
+
+#define RFCOMM_I_CR(is_command) ((is_command) ? 0x02 : 0x00)
+
+#define RFCOMM_MAX_DLCI 61
+
+#define RFCOMM_VALID_DLCI(dlci) \
+ (((dlci) == 0) || (((dlci) >= 2) && ((dlci) <= RFCOMM_MAX_DLCI)))
+
+/* Port Negotiation (PN) */
+#define RFCOMM_PN_DLCI_MASK 0x3F
+
+#define RFCOMM_PN_FRAM_TYPE_UIH 0x00
+#define RFCOMM_PN_FRAME_TYPE_MASK 0x0F
+
+#define RFCOMM_PN_CONV_LAYER_MASK 0xF0
+#define RFCOMM_PN_CONV_LAYER_TYPE_1 0
+#define RFCOMM_PN_CONV_LAYER_CBFC_I 0xF0
+#define RFCOMM_PN_CONV_LAYER_CBFC_R 0xE0
+
+#define RFCOMM_PN_PRIORITY_MASK 0x3F
+#define RFCOMM_PN_PRIORITY_0 0
+
+#define RFCOMM_PN_K_MASK 0x07
+
+#define RFCOMM_T1_DSEC 0 /* None negotiable in RFCOMM */
+#define RFCOMM_N2 0 /* Number of retransmissions */
+#define RFCOMM_K 0 /* Window size */
+#define RFCOMM_K_MAX 7 /* Max value of K for credit based flow control */
+
+#define RFCOMM_MSC_FC 0x02 /* Flow control*/
+#define RFCOMM_MSC_RTC 0x04 /* Ready to communicate*/
+#define RFCOMM_MSC_RTR 0x08 /* Ready to receive*/
+#define RFCOMM_MSC_IC 0x40 /* Incomming call indicator*/
+#define RFCOMM_MSC_DV 0x80 /* Data Valid*/
+
+#define RFCOMM_MSC_SHIFT_BREAK 4
+#define RFCOMM_MSC_BREAK_MASK 0xF0
+#define RFCOMM_MSC_BREAK_PRESENT_MASK 0x02
+
+#define RFCOMM_BAUD_RATE_2400 0x00
+#define RFCOMM_BAUD_RATE_4800 0x01
+#define RFCOMM_BAUD_RATE_7200 0x02
+#define RFCOMM_BAUD_RATE_9600 0x03
+#define RFCOMM_BAUD_RATE_19200 0x04
+#define RFCOMM_BAUD_RATE_38400 0x05
+#define RFCOMM_BAUD_RATE_57600 0x06
+#define RFCOMM_BAUD_RATE_115200 0x07
+#define RFCOMM_BAUD_RATE_230400 0x08
+
+#define RFCOMM_5_BITS 0x00
+#define RFCOMM_6_BITS 0x01
+#define RFCOMM_7_BITS 0x02
+#define RFCOMM_8_BITS 0x03
+
+#define RFCOMM_RPN_BITS_MASK 0x03
+#define RFCOMM_RPN_BITS_SHIFT 0
+
+#define RFCOMM_ONESTOPBIT 0x00
+#define RFCOMM_ONE5STOPBITS 0x01
+
+#define RFCOMM_RPN_STOP_BITS_MASK 0x01
+#define RFCOMM_RPN_STOP_BITS_SHIFT 2
+
+#define RFCOMM_PARITY_NO 0x00
+#define RFCOMM_PARITY_YES 0x01
+#define RFCOMM_RPN_PARITY_MASK 0x01
+#define RFCOMM_RPN_PARITY_SHIFT 3
+
+#define RFCOMM_ODD_PARITY 0x00
+#define RFCOMM_EVEN_PARITY 0x01
+#define RFCOMM_MARK_PARITY 0x02
+#define RFCOMM_SPACE_PARITY 0x03
+
+#define RFCOMM_RPN_PARITY_TYPE_MASK 0x03
+#define RFCOMM_RPN_PARITY_TYPE_SHIFT 4
+
+#define RFCOMM_FC_OFF 0x00
+#define RFCOMM_FC_XONXOFF_ON_INPUT 0x01
+#define RFCOMM_FC_XONXOFF_ON_OUTPUT 0x02
+#define RFCOMM_FC_RTR_ON_INPUT 0x04
+#define RFCOMM_FC_RTR_ON_OUTPUT 0x08
+#define RFCOMM_FC_RTC_ON_INPUT 0x10
+#define RFCOMM_FC_RTC_ON_OUTPUT 0x20
+#define RFCOMM_FC_MASK 0x3F
+
+#define RFCOMM_RPN_PM_BIT_RATE 0x0001
+#define RFCOMM_RPN_PM_DATA_BITS 0x0002
+#define RFCOMM_RPN_PM_STOP_BITS 0x0004
+#define RFCOMM_RPN_PM_PARITY 0x0008
+#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010
+#define RFCOMM_RPN_PM_XON_CHAR 0x0020
+#define RFCOMM_RPN_PM_XOFF_CHAR 0x0040
+#define RFCOMM_RPN_PM_XONXOFF_ON_INPUT 0x0100
+#define RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT 0x0200
+#define RFCOMM_RPN_PM_RTR_ON_INPUT 0x0400
+#define RFCOMM_RPN_PM_RTR_ON_OUTPUT 0x0800
+#define RFCOMM_RPN_PM_RTC_ON_INPUT 0x1000
+#define RFCOMM_RPN_PM_RTC_ON_OUTPUT 0x2000
+#define RFCOMM_RPN_PM_MASK 0x3F7F
+
+#define RFCOMM_RLS_ERROR 0x01
+#define RFCOMM_RLS_OVERRUN 0x02
+#define RFCOMM_RLS_PARITY 0x04
+#define RFCOMM_RLS_FRAMING 0x08
+
+/* Multiplexor channel uses DLCI 0 */
+#define RFCOMM_MX_DLCI 0
+
+/*
+ * Define RFCOMM Multiplexer message types
+*/
+#define RFCOMM_MX_PN 0x80
+#define RFCOMM_MX_PN_LEN 8
+
+#define RFCOMM_MX_CLD 0xC0
+#define RFCOMM_MX_CLD_LEN 0
+
+#define RFCOMM_MX_TEST 0x20
+
+#define RFCOMM_MX_FCON 0xA0
+#define RFCOMM_MX_FCON_LEN 0
+
+#define RFCOMM_MX_FCOFF 0x60
+#define RFCOMM_MX_FCOFF_LEN 0
+
+#define RFCOMM_MX_MSC 0xE0
+#define RFCOMM_MX_MSC_LEN_NO_BREAK 2
+#define RFCOMM_MX_MSC_LEN_WITH_BREAK 3
+
+#define RFCOMM_MX_NSC 0x10
+#define RFCOMM_MX_NSC_LEN 1
+
+#define RFCOMM_MX_RPN 0x90
+#define RFCOMM_MX_RPN_REQ_LEN 1
+#define RFCOMM_MX_RPN_LEN 8
+
+#define RFCOMM_MX_RLS 0x50
+#define RFCOMM_MX_RLS_LEN 2
+#endif
diff --git a/mtkbt/code/bt/stack/include/sdp_api.h b/mtkbt/code/bt/stack/include/sdp_api.h
new file mode 100755
index 0000000..a5eead1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/sdp_api.h
@@ -0,0 +1,645 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef SDP_API_H
+#define SDP_API_H
+
+#include "bt_target.h"
+#include "sdpdefs.h"
+
+/*****************************************************************************
+ * Constants
+ ****************************************************************************/
+
+/* Success code and error codes */
+#define SDP_SUCCESS 0x0000
+#define SDP_INVALID_VERSION 0x0001
+#define SDP_INVALID_SERV_REC_HDL 0x0002
+#define SDP_INVALID_REQ_SYNTAX 0x0003
+#define SDP_INVALID_PDU_SIZE 0x0004
+#define SDP_INVALID_CONT_STATE 0x0005
+#define SDP_NO_RESOURCES 0x0006
+#define SDP_DI_REG_FAILED 0x0007
+#define SDP_DI_DISC_FAILED 0x0008
+#define SDP_NO_DI_RECORD_FOUND 0x0009
+#define SDP_ERR_ATTR_NOT_PRESENT 0x000A
+#define SDP_ILLEGAL_PARAMETER 0x000B
+
+#define SDP_NO_RECS_MATCH 0xFFF0
+#define SDP_CONN_FAILED 0xFFF1
+#define SDP_CFG_FAILED 0xFFF2
+#define SDP_GENERIC_ERROR 0xFFF3
+#define SDP_DB_FULL 0xFFF4
+#define SDP_INVALID_PDU 0xFFF5
+#define SDP_SECURITY_ERR 0xFFF6
+#define SDP_CONN_REJECTED 0xFFF7
+#define SDP_CANCEL 0xFFF8
+
+/* Define the PSM that SDP uses */
+#define SDP_PSM 0x0001
+
+/* Legacy #define to avoid code changes - SDP UUID is same as BT UUID */
+#define tSDP_UUID tBT_UUID
+
+/* Masks for attr_value field of tSDP_DISC_ATTR */
+#define SDP_DISC_ATTR_LEN_MASK 0x0FFF
+#define SDP_DISC_ATTR_TYPE(len_type) ((len_type) >> 12)
+#define SDP_DISC_ATTR_LEN(len_type) ((len_type)&SDP_DISC_ATTR_LEN_MASK)
+
+/* Maximum number of protocol list items (list_elem in tSDP_PROTOCOL_ELEM) */
+#define SDP_MAX_LIST_ELEMS 3
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/* Define a callback function for when discovery is complete. */
+typedef void(tSDP_DISC_CMPL_CB)(uint16_t result);
+typedef void(tSDP_DISC_CMPL_CB2)(uint16_t result, void* user_data);
+
+typedef struct {
+ BD_ADDR peer_addr;
+ uint16_t peer_mtu;
+} tSDP_DR_OPEN;
+
+typedef struct {
+ uint8_t* p_data;
+ uint16_t data_len;
+} tSDP_DR_DATA;
+
+typedef union {
+ tSDP_DR_OPEN open;
+ tSDP_DR_DATA data;
+} tSDP_DATA;
+
+/* Define a callback function for when discovery result is received. */
+typedef void(tSDP_DISC_RES_CB)(uint16_t event, tSDP_DATA* p_data);
+
+/* Define a structure to hold the discovered service information. */
+typedef struct {
+ union {
+ uint8_t u8; /* 8-bit integer */
+ uint16_t u16; /* 16-bit integer */
+ uint32_t u32; /* 32-bit integer */
+ uint8_t array[4]; /* Variable length field */
+ struct t_sdp_disc_attr* p_sub_attr; /* Addr of first sub-attr (list)*/
+ } v;
+
+} tSDP_DISC_ATVAL;
+
+typedef struct t_sdp_disc_attr {
+ struct t_sdp_disc_attr* p_next_attr; /* Addr of next linked attr */
+ uint16_t attr_id; /* Attribute ID */
+ uint16_t attr_len_type; /* Length and type fields */
+ tSDP_DISC_ATVAL attr_value; /* Variable length entry data */
+} tSDP_DISC_ATTR;
+
+typedef struct t_sdp_disc_rec {
+ tSDP_DISC_ATTR* p_first_attr; /* First attribute of record */
+ struct t_sdp_disc_rec* p_next_rec; /* Addr of next linked record */
+ uint32_t time_read; /* The time the record was read */
+ BD_ADDR remote_bd_addr; /* Remote BD address */
+} tSDP_DISC_REC;
+
+typedef struct {
+ uint32_t mem_size; /* Memory size of the DB */
+ uint32_t mem_free; /* Memory still available */
+ tSDP_DISC_REC* p_first_rec; /* Addr of first record in DB */
+ uint16_t num_uuid_filters; /* Number of UUIds to filter */
+ tSDP_UUID uuid_filters[SDP_MAX_UUID_FILTERS]; /* UUIDs to filter */
+ uint16_t num_attr_filters; /* Number of attribute filters */
+ uint16_t attr_filters[SDP_MAX_ATTR_FILTERS]; /* Attributes to filter */
+ uint8_t* p_free_mem; /* Pointer to free memory */
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ uint8_t*
+ raw_data; /* Received record from server. allocated/released by client */
+ uint32_t raw_size; /* size of raw_data */
+ uint32_t raw_used; /* length of raw_data used */
+#endif
+} tSDP_DISCOVERY_DB;
+
+/* This structure is used to add protocol lists and find protocol elements */
+typedef struct {
+ uint16_t protocol_uuid;
+ uint16_t num_params;
+ uint16_t params[SDP_MAX_PROTOCOL_PARAMS];
+} tSDP_PROTOCOL_ELEM;
+
+typedef struct {
+ uint16_t num_elems;
+ tSDP_PROTOCOL_ELEM list_elem[SDP_MAX_LIST_ELEMS];
+} tSDP_PROTO_LIST_ELEM;
+
+/* Device Identification (DI) data structure
+*/
+/* Used to set the DI record */
+typedef struct t_sdp_di_record {
+ uint16_t vendor;
+ uint16_t vendor_id_source;
+ uint16_t product;
+ uint16_t version;
+ bool primary_record;
+ char client_executable_url[SDP_MAX_ATTR_LEN]; /* optional */
+ char service_description[SDP_MAX_ATTR_LEN]; /* optional */
+ char documentation_url[SDP_MAX_ATTR_LEN]; /* optional */
+} tSDP_DI_RECORD;
+
+/* Used to get the DI record */
+typedef struct t_sdp_di_get_record {
+ uint16_t spec_id;
+ tSDP_DI_RECORD rec;
+} tSDP_DI_GET_RECORD;
+
+/* API into the SDP layer for service discovery. */
+
+/*******************************************************************************
+ *
+ * Function SDP_InitDiscoveryDb
+ *
+ * Description This function is called to initialize a discovery database.
+ *
+ * Returns true if successful, false if one or more parameters are bad
+ *
+ ******************************************************************************/
+bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+ uint16_t num_attr, uint16_t* p_attr_list);
+
+/*******************************************************************************
+ *
+ * Function SDP_CancelServiceSearch
+ *
+ * Description This function cancels an active query to an SDP server.
+ *
+ * Returns true if discovery cancelled, false if a matching activity is
+ * not found.
+ *
+ ******************************************************************************/
+bool SDP_CancelServiceSearch(tSDP_DISCOVERY_DB* p_db);
+
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchRequest
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchRequest(uint8_t* p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchAttributeRequest
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * The difference between this API function and the function
+ * SDP_ServiceSearchRequest is that this one does a
+ * combined ServiceSearchAttributeRequest SDP function.
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchAttributeRequest(uint8_t* p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchAttributeRequest2
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * The difference between this API function and the function
+ * SDP_ServiceSearchRequest is that this one does a
+ * combined ServiceSearchAttributeRequest SDP function with the
+ * user data piggyback
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchAttributeRequest2(uint8_t* p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb,
+ void* user_data);
+
+/* API of utilities to find data in the local discovery database */
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAttributeInDb
+ *
+ * Description This function queries an SDP database for a specific
+ * attribute. If the p_start_rec pointer is NULL, it looks from
+ * the beginning of the database, else it continues from the
+ * next record after p_start_rec.
+ *
+ * Returns Pointer to matching record, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindAttributeInDb(tSDP_DISCOVERY_DB* p_db, uint16_t attr_id,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAttributeInRec
+ *
+ * Description This function searches an SDP discovery record for a
+ * specific attribute.
+ *
+ * Returns Pointer to matching attribute entry, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_ATTR* SDP_FindAttributeInRec(tSDP_DISC_REC* p_rec, uint16_t attr_id);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceInDb
+ *
+ * Description This function queries an SDP database for a specific
+ * service. If the p_start_rec pointer is NULL, it looks from
+ * the beginning of the database, else it continues from the
+ * next record after p_start_rec.
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceInDb(tSDP_DISCOVERY_DB* p_db,
+ uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInDb
+ *
+ * Description This function queries an SDP database for a specific
+ * service. If the p_start_rec pointer is NULL, it looks from
+ * the beginning of the database, else it continues from the
+ * next record after p_start_rec.
+ *
+ * NOTE the only difference between this function and the previous
+ * function "SDP_FindServiceInDb()" is that this function takes
+ * a tBT_UUID input.
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
+ tBT_UUID* p_uuid,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInRec_128bit
+ *
+ * Description Read the 128-bit service UUID within a record,
+ * if there is any.
+ *
+ * Parameters: p_rec - pointer to a SDP record.
+ * p_uuid - output parameter to save the UUID found.
+ *
+ * Returns true if found, otherwise false.
+ *
+ ******************************************************************************/
+bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceInDb_128bit
+ *
+ * Description Query an SDP database for a specific service.
+ * If the p_start_rec pointer is NULL, look from the beginning
+ * of the database, else continue from the next record after
+ * p_start_rec.
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_start_rec);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindProtocolListElemInRec
+ *
+ * Description This function looks at a specific discovery record for a
+ * protocol list element.
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindProtocolListElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAddProtoListsElemInRec
+ *
+ * Description This function looks at a specific discovery record for a
+ * protocol list element.
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindAddProtoListsElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindProfileVersionInRec
+ *
+ * Description This function looks at a specific discovery record for the
+ * Profile list descriptor, and pulls out the version number.
+ * The version number consists of an 8-bit major version and
+ * an 8-bit minor version.
+ *
+ * Returns true if found, false if not
+ * If found, the major and minor version numbers that were
+ * passed in are filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindProfileVersionInRec(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version);
+
+/* API into SDP for local service database updates */
+
+/*******************************************************************************
+ *
+ * Function SDP_CreateRecord
+ *
+ * Description This function is called to create a record in the database.
+ * This would be through the SDP database maintenance API. The
+ * record is created empty, teh application should then call
+ * "add_attribute" to add the record's attributes.
+ *
+ * Returns Record handle if OK, else 0.
+ *
+ ******************************************************************************/
+uint32_t SDP_CreateRecord(void);
+
+/*******************************************************************************
+ *
+ * Function SDP_DeleteRecord
+ *
+ * Description This function is called to add a record (or all records)
+ * from the database. This would be through the SDP database
+ * maintenance API.
+ *
+ * If a record handle of 0 is passed, all records are deleted.
+ *
+ * Returns true if succeeded, else false
+ *
+ ******************************************************************************/
+bool SDP_DeleteRecord(uint32_t handle);
+
+/*******************************************************************************
+ *
+ * Function SDP_ReadRecord
+ *
+ * Description This function is called to get the raw data of the record
+ * with the given handle from the database.
+ *
+ * Returns -1, if the record is not found.
+ * Otherwise, the offset (0 or 1) to start of data in p_data.
+ *
+ * The size of data copied into p_data is in *p_data_len.
+ *
+ ******************************************************************************/
+int32_t SDP_ReadRecord(uint32_t handle, uint8_t* p_data, int32_t* p_data_len);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddAttribute
+ *
+ * Description This function is called to add an attribute to a record.
+ * This would be through the SDP database maintenance API.
+ * If the attribute already exists in the record, it is
+ * replaced with the new value.
+ *
+ * NOTE Attribute values must be passed as a Big Endian stream.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type,
+ uint32_t attr_len, uint8_t* p_val);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddSequence
+ *
+ * Description This function is called to add a sequence to a record.
+ * This would be through the SDP database maintenance API.
+ * If the sequence already exists in the record, it is replaced
+ * with the new sequence.
+ *
+ * NOTE Element values must be passed as a Big Endian stream.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem,
+ uint8_t type[], uint8_t len[], uint8_t* p_val[]);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddUuidSequence
+ *
+ * Description This function is called to add a UUID sequence to a record.
+ * This would be through the SDP database maintenance API.
+ * If the sequence already exists in the record, it is replaced
+ * with the new sequence.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids,
+ uint16_t* p_uuids);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddProtocolList
+ *
+ * Description This function is called to add a protocol descriptor list to
+ * a record. This would be through the SDP database
+ * maintenance API. If the protocol list already exists in the
+ * record, it is replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem,
+ tSDP_PROTOCOL_ELEM* p_elem_list);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddAdditionProtoLists
+ *
+ * Description This function is called to add a protocol descriptor list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the protocol list already exists in the record, it
+ * is replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem,
+ tSDP_PROTO_LIST_ELEM* p_proto_list);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddProfileDescriptorList
+ *
+ * Description This function is called to add a profile descriptor list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the version already exists in the record, it is
+ * replaced with the new one.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid,
+ uint16_t version);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddLanguageBaseAttrIDList
+ *
+ * Description This function is called to add a language base attr list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the version already exists in the record, it is
+ * replaced with the new one.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang,
+ uint16_t char_enc, uint16_t base_id);
+
+/*******************************************************************************
+ *
+ * Function SDP_AddServiceClassIdList
+ *
+ * Description This function is called to add a service list to a record.
+ * This would be through the SDP database maintenance API.
+ * If the service list already exists in the record, it is
+ * replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services,
+ uint16_t* p_service_uuids);
+
+/*******************************************************************************
+ *
+ * Function SDP_DeleteAttribute
+ *
+ * Description Delete an attribute from a record.
+ * This would be through the SDP database maintenance API.
+ *
+ * Returns true if deleted OK, else false if not found
+ *
+ ******************************************************************************/
+bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id);
+
+/* Device Identification APIs */
+
+/*******************************************************************************
+ *
+ * Function SDP_SetLocalDiRecord
+ *
+ * Description This function adds a DI record to the local SDP database.
+ *
+ * Returns Returns SDP_SUCCESS if record added successfully, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_SetLocalDiRecord(tSDP_DI_RECORD* device_info, uint32_t* p_handle);
+
+/*******************************************************************************
+ *
+ * Function SDP_DiDiscover
+ *
+ * Description This function queries a remote device for DI information.
+ *
+ * Returns SDP_SUCCESS if query started successfully, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_DiDiscover(BD_ADDR remote_device, tSDP_DISCOVERY_DB* p_db,
+ uint32_t len, tSDP_DISC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function SDP_GetNumDiRecords
+ *
+ * Description Searches specified database for DI records
+ *
+ * Returns number of DI records found
+ *
+ ******************************************************************************/
+uint8_t SDP_GetNumDiRecords(tSDP_DISCOVERY_DB* p_db);
+
+/*******************************************************************************
+ *
+ * Function SDP_GetDiRecord
+ *
+ * Description This function retrieves a remote device's DI record from
+ * the specified database.
+ *
+ * Returns SDP_SUCCESS if record retrieved, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_GetDiRecord(uint8_t getRecordIndex,
+ tSDP_DI_GET_RECORD* device_info,
+ tSDP_DISCOVERY_DB* p_db);
+
+/*******************************************************************************
+ *
+ * Function SDP_SetTraceLevel
+ *
+ * Description This function sets the trace level for SDP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t SDP_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInRec
+ *
+ * Description Read the service UUID within a record,
+ * if there is any.
+ *
+ * Parameters: p_rec - pointer to a SDP record.
+ *
+ * Returns true if found, otherwise false.
+ *
+ ******************************************************************************/
+bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid);
+
+// Converts UUID-16 to UUID-128 by including the base UUID.
+// |uuid16| is the 2-byte UUID to convert.
+// The result with the expanded 128-bit UUID is stored in |p_uuid128|.
+void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128);
+
+#endif /* SDP_API_H */
diff --git a/mtkbt/code/bt/stack/include/sdpdefs.h b/mtkbt/code/bt/stack/include/sdpdefs.h
new file mode 100755
index 0000000..ad0e611
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/sdpdefs.h
@@ -0,0 +1,337 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the definitions for the SDP API
+ *
+ ******************************************************************************/
+
+#ifndef SDP_DEFS_H
+#define SDP_DEFS_H
+
+/* Define the service attribute IDs.
+*/
+#define ATTR_ID_SERVICE_RECORD_HDL 0x0000
+#define ATTR_ID_SERVICE_CLASS_ID_LIST 0x0001
+#define ATTR_ID_SERVICE_RECORD_STATE 0x0002
+#define ATTR_ID_SERVICE_ID 0x0003
+#define ATTR_ID_PROTOCOL_DESC_LIST 0x0004
+#define ATTR_ID_BROWSE_GROUP_LIST 0x0005
+#define ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST 0x0006
+#define ATTR_ID_SERVICE_INFO_TIME_TO_LIVE 0x0007
+#define ATTR_ID_SERVICE_AVAILABILITY 0x0008
+#define ATTR_ID_BT_PROFILE_DESC_LIST 0x0009
+#define ATTR_ID_DOCUMENTATION_URL 0x000A
+#define ATTR_ID_CLIENT_EXE_URL 0x000B
+#define ATTR_ID_ICON_URL 0x000C
+#define ATTR_ID_ADDITION_PROTO_DESC_LISTS 0x000D
+
+#define LANGUAGE_BASE_ID 0x0100
+#define ATTR_ID_SERVICE_NAME (LANGUAGE_BASE_ID + 0x0000)
+#define ATTR_ID_SERVICE_DESCRIPTION (LANGUAGE_BASE_ID + 0x0001)
+#define ATTR_ID_PROVIDER_NAME (LANGUAGE_BASE_ID + 0x0002)
+
+/* Device Identification (DI)
+*/
+#define ATTR_ID_SPECIFICATION_ID 0x0200
+#define ATTR_ID_VENDOR_ID 0x0201
+#define ATTR_ID_PRODUCT_ID 0x0202
+#define ATTR_ID_PRODUCT_VERSION 0x0203
+#define ATTR_ID_PRIMARY_RECORD 0x0204
+#define ATTR_ID_VENDOR_ID_SOURCE 0x0205
+
+#define BLUETOOTH_DI_SPECIFICATION 0x0103 /* 1.3 */
+#define DI_VENDOR_ID_DEFAULT 0xFFFF
+#define DI_VENDOR_ID_SOURCE_BTSIG 0x0001
+#define DI_VENDOR_ID_SOURCE_USBIF 0x0002
+
+#define ATTR_ID_IP_SUBNET 0x0200 /* PAN Profile (***) */
+#define ATTR_ID_VERSION_NUMBER_LIST 0x0200
+#define ATTR_ID_GOEP_L2CAP_PSM 0x0200
+#define ATTR_ID_GROUP_ID 0x0200
+#define ATTR_ID_SERVICE_DATABASE_STATE 0x0201
+#define ATTR_ID_SERVICE_VERSION 0x0300
+#define ATTR_ID_HCRP_1284ID 0x0300
+
+#define ATTR_ID_SUPPORTED_DATA_STORES 0x0301
+#define ATTR_ID_NETWORK 0x0301
+#define ATTR_ID_EXTERNAL_NETWORK 0x0301
+#define ATTR_ID_FAX_CLASS_1_SUPPORT 0x0302
+#define ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
+#define ATTR_ID_DEVICE_NAME 0x0302
+#define ATTR_ID_SUPPORTED_FORMATS_LIST 0x0303
+#define ATTR_ID_FAX_CLASS_2_0_SUPPORT 0x0303
+#define ATTR_ID_FAX_CLASS_2_SUPPORT 0x0304
+#define ATTR_ID_FRIENDLY_NAME 0x0304
+#define ATTR_ID_AUDIO_FEEDBACK_SUPPORT 0x0305
+#define ATTR_ID_NETWORK_ADDRESS 0x0306
+#define ATTR_ID_DEVICE_LOCATION 0x0306
+#define ATTR_ID_WAP_GATEWAY 0x0307
+#define ATTR_ID_HOME_PAGE_URL 0x0308
+#define ATTR_ID_WAP_STACK_TYPE 0x0309
+#define ATTR_ID_IMG_SUPPORTED_CAPABILITIES 0x0310 /* Imaging Profile */
+#define ATTR_ID_SUPPORTED_FEATURES 0x0311 /* HFP, BIP */
+#define ATTR_ID_IMG_SUPPORTED_FUNCTIONS 0x0312 /* Imaging Profile */
+#define ATTR_ID_IMG_TOT_DATA_CAPABILITY 0x0313 /* Imaging Profile */
+#define ATTR_ID_SUPPORTED_REPOSITORIES 0x0314 /* Phone book access Profile */
+#define ATTR_ID_MAS_INSTANCE_ID 0x0315 /* MAP profile */
+#define ATTR_ID_SUPPORTED_MSG_TYPE 0x0316 /* MAP profile */
+#define ATTR_ID_MAP_SUPPORTED_FEATURES 0x0317 /* MAP profile */
+#define ATTR_ID_PBAP_SUPPORTED_FEATURES 0x0317 /* PBAP profile */
+
+/* These values are for the BPP profile */
+#define ATTR_ID_DOCUMENT_FORMATS_SUPPORTED 0x0350
+#define ATTR_ID_CHARACTER_REPERTOIRES_SUPPORTED 0x0352
+#define ATTR_ID_XHTML_IMAGE_FORMATS_SUPPORTED 0x0354
+#define ATTR_ID_COLOR_SUPPORTED 0x0356
+#define ATTR_ID_1284ID 0x0358
+#define ATTR_ID_PRINTER_NAME 0x035A
+#define ATTR_ID_PRINTER_LOCATION 0x035C
+#define ATTR_ID_DUPLEX_SUPPORTED 0x035E
+#define ATTR_ID_MEDIA_TYPES_SUPPORTED 0x0360
+#define ATTR_ID_MAX_MEDIA_WIDTH 0x0362
+#define ATTR_ID_MAX_MEDIA_LENGTH 0x0364
+#define ATTR_ID_ENHANCED_LAYOUT_SUPPORTED 0x0366
+#define ATTR_ID_RUI_FORMATS_SUPPORTED 0x0368
+#define ATTR_ID_RUI_REF_PRINTING_SUPPORTED 0x0370 /* Boolean */
+#define ATTR_ID_RUI_DIRECT_PRINTING_SUPPORTED 0x0372 /* Boolean */
+#define ATTR_ID_REF_PRINTING_TOP_URL 0x0374
+#define ATTR_ID_DIRECT_PRINTING_TOP_URL 0x0376
+#define ATTR_ID_PRINTER_ADMIN_RUI_TOP_URL 0x0378
+#define ATTR_ID_BPP_DEVICE_NAME 0x037A
+
+/* These values are for the PAN profile */
+#define ATTR_ID_SECURITY_DESCRIPTION 0x030A
+#define ATTR_ID_NET_ACCESS_TYPE 0x030B
+#define ATTR_ID_MAX_NET_ACCESS_RATE 0x030C
+#define ATTR_ID_IPV4_SUBNET 0x030D
+#define ATTR_ID_IPV6_SUBNET 0x030E
+#define ATTR_ID_PAN_SECURITY 0x0400
+
+/* These values are for HID profile */
+#define ATTR_ID_HID_DEVICE_RELNUM 0x0200
+#define ATTR_ID_HID_PARSER_VERSION 0x0201
+#define ATTR_ID_HID_DEVICE_SUBCLASS 0x0202
+#define ATTR_ID_HID_COUNTRY_CODE 0x0203
+#define ATTR_ID_HID_VIRTUAL_CABLE 0x0204
+#define ATTR_ID_HID_RECONNECT_INITIATE 0x0205
+#define ATTR_ID_HID_DESCRIPTOR_LIST 0x0206
+#define ATTR_ID_HID_LANGUAGE_ID_BASE 0x0207
+#define ATTR_ID_HID_SDP_DISABLE 0x0208
+#define ATTR_ID_HID_BATTERY_POWER 0x0209
+#define ATTR_ID_HID_REMOTE_WAKE 0x020A
+#define ATTR_ID_HID_PROFILE_VERSION 0x020B
+#define ATTR_ID_HID_LINK_SUPERVISION_TO 0x020C
+#define ATTR_ID_HID_NORMALLY_CONNECTABLE 0x020D
+#define ATTR_ID_HID_BOOT_DEVICE 0x020E
+#define ATTR_ID_HID_SSR_HOST_MAX_LAT 0x020F
+#define ATTR_ID_HID_SSR_HOST_MIN_TOUT 0x0210
+
+/* These values are for the HDP profile */
+#define ATTR_ID_HDP_SUP_FEAT_LIST 0x0200 /* Supported features list */
+#define ATTR_ID_HDP_DATA_EXCH_SPEC 0x0301 /* Data exchange specification */
+#define ATTR_ID_HDP_MCAP_SUP_PROC 0x0302 /* MCAP supported procedures */
+
+/* Define common 16-bit protocol UUIDs
+*/
+#define UUID_PROTOCOL_SDP 0x0001
+#define UUID_PROTOCOL_UDP 0x0002
+#define UUID_PROTOCOL_RFCOMM 0x0003
+#define UUID_PROTOCOL_TCP 0x0004
+#define UUID_PROTOCOL_TCS_BIN 0x0005
+#define UUID_PROTOCOL_TCS_AT 0x0006
+#define UUID_PROTOCOL_OBEX 0x0008
+#define UUID_PROTOCOL_IP 0x0009
+#define UUID_PROTOCOL_FTP 0x000A
+#define UUID_PROTOCOL_HTTP 0x000C
+#define UUID_PROTOCOL_WSP 0x000E
+#define UUID_PROTOCOL_BNEP 0x000F
+#define UUID_PROTOCOL_UPNP 0x0010
+#define UUID_PROTOCOL_HIDP 0x0011
+#define UUID_PROTOCOL_HCRP_CTRL 0x0012
+#define UUID_PROTOCOL_HCRP_DATA 0x0014
+#define UUID_PROTOCOL_HCRP_NOTIF 0x0016
+#define UUID_PROTOCOL_AVCTP 0x0017
+#define UUID_PROTOCOL_AVDTP 0x0019
+#define UUID_PROTOCOL_CMTP 0x001B
+#define UUID_PROTOCOL_UDI 0x001D
+#define UUID_PROTOCOL_MCAP_CTRL 0x001E
+#define UUID_PROTOCOL_MCAP_DATA 0x001F
+#define UUID_PROTOCOL_L2CAP 0x0100
+#define UUID_PROTOCOL_ATT 0x0007
+
+/* Define common 16-bit service class UUIDs
+*/
+#define UUID_SERVCLASS_SERVICE_DISCOVERY_SERVER 0X1000
+#define UUID_SERVCLASS_BROWSE_GROUP_DESCRIPTOR 0X1001
+#define UUID_SERVCLASS_PUBLIC_BROWSE_GROUP 0X1002
+#define UUID_SERVCLASS_SERIAL_PORT 0X1101
+#define UUID_SERVCLASS_LAN_ACCESS_USING_PPP 0X1102
+#define UUID_SERVCLASS_DIALUP_NETWORKING 0X1103
+#define UUID_SERVCLASS_IRMC_SYNC 0X1104
+#define UUID_SERVCLASS_OBEX_OBJECT_PUSH 0X1105
+#define UUID_SERVCLASS_OBEX_FILE_TRANSFER 0X1106
+#define UUID_SERVCLASS_IRMC_SYNC_COMMAND 0X1107
+#define UUID_SERVCLASS_HEADSET 0X1108
+#define UUID_SERVCLASS_CORDLESS_TELEPHONY 0X1109
+#define UUID_SERVCLASS_AUDIO_SOURCE 0X110A
+#define UUID_SERVCLASS_AUDIO_SINK 0X110B
+/* Audio/Video Control profile */
+#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C
+/* Advanced Audio Distribution profile */
+#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D
+/* Audio/Video Control profile */
+#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E
+/* Audio/Video Control profile */
+#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F
+#define UUID_SERVCLASS_INTERCOM 0X1110
+#define UUID_SERVCLASS_FAX 0X1111
+#define UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY 0X1112
+#define UUID_SERVCLASS_WAP 0X1113
+#define UUID_SERVCLASS_WAP_CLIENT 0X1114
+#define UUID_SERVCLASS_PANU 0X1115 /* PAN profile */
+#define UUID_SERVCLASS_NAP 0X1116 /* PAN profile */
+#define UUID_SERVCLASS_GN 0X1117 /* PAN profile */
+#define UUID_SERVCLASS_DIRECT_PRINTING 0X1118 /* BPP profile */
+#define UUID_SERVCLASS_REFERENCE_PRINTING 0X1119 /* BPP profile */
+#define UUID_SERVCLASS_IMAGING 0X111A /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_RESPONDER 0X111B /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_AUTO_ARCHIVE 0X111C /* Imaging profile */
+#define UUID_SERVCLASS_IMAGING_REF_OBJECTS 0X111D /* Imaging profile */
+#define UUID_SERVCLASS_HF_HANDSFREE 0X111E /* Handsfree profile */
+#define UUID_SERVCLASS_AG_HANDSFREE 0X111F /* Handsfree profile */
+#define UUID_SERVCLASS_DIR_PRT_REF_OBJ_SERVICE 0X1120 /* BPP profile */
+#define UUID_SERVCLASS_REFLECTED_UI 0X1121 /* BPP profile */
+#define UUID_SERVCLASS_BASIC_PRINTING 0X1122 /* BPP profile */
+#define UUID_SERVCLASS_PRINTING_STATUS 0X1123 /* BPP profile */
+#define UUID_SERVCLASS_HUMAN_INTERFACE 0X1124 /* HID profile */
+#define UUID_SERVCLASS_CABLE_REPLACEMENT 0X1125 /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_PRINT 0X1126 /* HCRP profile */
+#define UUID_SERVCLASS_HCRP_SCAN 0X1127 /* HCRP profile */
+/* CAPI Message Transport Protocol*/
+#define UUID_SERVCLASS_COMMON_ISDN_ACCESS 0X1128
+/* Video Conferencing profile */
+#define UUID_SERVCLASS_VIDEO_CONFERENCING_GW 0X1129
+/* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_UDI_MT 0X112A
+/* Unrestricted Digital Information profile */
+#define UUID_SERVCLASS_UDI_TA 0X112B
+#define UUID_SERVCLASS_VCP 0X112C /* Video Conferencing profile */
+#define UUID_SERVCLASS_SAP 0X112D /* SIM Access profile */
+#define UUID_SERVCLASS_PBAP_PCE 0X112E /* Phonebook Access - PCE */
+#define UUID_SERVCLASS_PBAP_PSE 0X112F /* Phonebook Access - PSE */
+#define UUID_SERVCLASS_PHONE_ACCESS 0x1130
+#define UUID_SERVCLASS_HEADSET_HS 0x1131 /* Headset - HS, from HSP v1.2 */
+#define UUID_SERVCLASS_PNP_INFORMATION 0X1200 /* Device Identification */
+#define UUID_SERVCLASS_GENERIC_NETWORKING 0X1201
+#define UUID_SERVCLASS_GENERIC_FILETRANSFER 0X1202
+#define UUID_SERVCLASS_GENERIC_AUDIO 0X1203
+#define UUID_SERVCLASS_GENERIC_TELEPHONY 0X1204
+#define UUID_SERVCLASS_UPNP_SERVICE 0X1205 /* UPNP_Service [ESDP] */
+#define UUID_SERVCLASS_UPNP_IP_SERVICE 0X1206 /* UPNP_IP_Service [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_PAN 0X1300 /* UPNP_IP_PAN [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_LAP 0X1301 /* UPNP_IP_LAP [ESDP] */
+#define UUID_SERVCLASS_ESDP_UPNP_IP_L2CAP 0X1302 /* UPNP_L2CAP [ESDP] */
+
+/* Video Distribution Profile (VDP) */
+#define UUID_SERVCLASS_VIDEO_SOURCE 0X1303
+#define UUID_SERVCLASS_VIDEO_SINK 0X1304
+#define UUID_SERVCLASS_VIDEO_DISTRIBUTION 0X1305
+
+#define UUID_SERVCLASS_HDP_PROFILE 0X1400 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SOURCE 0X1401 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_HDP_SINK 0X1402 /* Health Device profile (HDP) */
+#define UUID_SERVCLASS_MAP_PROFILE 0X1134 /* MAP profile */
+#define UUID_SERVCLASS_MESSAGE_ACCESS 0X1132 /* Message Access Service */
+#define UUID_SERVCLASS_MESSAGE_NOTIFICATION \
+ 0X1133 /* Message Notification Service */
+
+#define UUID_SERVCLASS_GAP_SERVER 0x1800
+#define UUID_SERVCLASS_GATT_SERVER 0x1801
+#define UUID_SERVCLASS_IMMEDIATE_ALERT 0x1802 /* immediate alert */
+#define UUID_SERVCLASS_LINKLOSS 0x1803 /* Link Loss Alert */
+#define UUID_SERVCLASS_TX_POWER 0x1804 /* TX power */
+#define UUID_SERVCLASS_CURRENT_TIME 0x1805 /* Link Loss Alert */
+#define UUID_SERVCLASS_DST_CHG 0x1806 /* DST Time change */
+#define UUID_SERVCLASS_REF_TIME_UPD 0x1807 /* reference time update */
+#define UUID_SERVCLASS_THERMOMETER 0x1809 /* Thermometer UUID */
+#define UUID_SERVCLASS_DEVICE_INFO 0x180A /* device info service */
+#define UUID_SERVCLASS_NWA 0x180B /* Network availability */
+#define UUID_SERVCLASS_HEART_RATE 0x180D /* Heart Rate service */
+#define UUID_SERVCLASS_PHALERT 0x180E /* phone alert service */
+#define UUID_SERVCLASS_BATTERY 0x180F /* battery service */
+#define UUID_SERVCLASS_BPM 0x1810 /* blood pressure service */
+#define UUID_SERVCLASS_ALERT_NOTIFICATION 0x1811
+#define UUID_SERVCLASS_LE_HID 0x1812 /* HID over LE */
+#define UUID_SERVCLASS_SCAN_PARAM 0x1813 /* Scan Parameter service */
+#define UUID_SERVCLASS_GLUCOSE 0x1808 /* Glucose Meter Service */
+#define UUID_SERVCLASS_RSC 0x1814 /* RUNNERS SPEED AND CADENCE SERVICE */
+#define UUID_SERVCLASS_CSC 0x1816 /* Cycling SPEED AND CADENCE SERVICE */
+
+#define UUID_SERVCLASS_TEST_SERVER 0x9000 /* Test Group UUID */
+
+#define UUID_CODEC_CVSD 0x0001 /* CVSD */
+#define UUID_CODEC_MSBC 0x0002 /* mSBC */
+
+#define UUID_HF_IND_ENHANCED_DRIVER_SAFETY 0x0001 /* Enhanced Safety */
+#define UUID_HF_IND_BATTERY_LEVEL_STATUS 0x0002 /* Battery Status */
+
+/* Define all the 'Descriptor Type' values.
+*/
+#define NULL_DESC_TYPE 0
+#define UINT_DESC_TYPE 1
+#define TWO_COMP_INT_DESC_TYPE 2
+#define UUID_DESC_TYPE 3
+#define TEXT_STR_DESC_TYPE 4
+#define BOOLEAN_DESC_TYPE 5
+#define DATA_ELE_SEQ_DESC_TYPE 6
+#define DATA_ELE_ALT_DESC_TYPE 7
+#define URL_DESC_TYPE 8
+
+/* Define all the "Descriptor Size" values.
+*/
+#define SIZE_ONE_BYTE 0
+#define SIZE_TWO_BYTES 1
+#define SIZE_FOUR_BYTES 2
+#define SIZE_EIGHT_BYTES 3
+#define SIZE_SIXTEEN_BYTES 4
+#define SIZE_IN_NEXT_BYTE 5
+#define SIZE_IN_NEXT_WORD 6
+#define SIZE_IN_NEXT_LONG 7
+
+/* Language Encoding Constants */
+#define LANG_ID_CODE_ENGLISH ((uint16_t)0x656e) /* "en" */
+#define LANG_ID_CHAR_ENCODE_UTF8 ((uint16_t)0x006a) /* UTF-8 */
+
+/* Constants used for display purposes only. These define overlapping attribute
+ * values */
+#define ATTR_ID_VERS_OR_GRP_OR_DRELNUM_OR_IPSUB_OR_SPECID 0x0200
+#define ATTR_ID_VEND_ID_OR_SERVICE_DB_STATE_OR_PARSE_VER 0x0201
+#define ATTR_ID_PROD_ID_OR_HID_DEV_SUBCLASS 0x0202
+#define ATTR_ID_PROD_VER_OR_HID_COUNTRY_CODE 0x0203
+#define ATTR_ID_PRIMARY_REC_OR_HID_VIRTUAL_CABLE 0x0204
+#define ATTR_ID_DI_VENDOR_ID_SOURCE_OR_HID_INIT_RECONNECT 0x0205
+#define ATTR_ID_SERV_VERS_OR_1284ID 0x0300
+#define ATTR_ID_DATA_STORES_OR_NETWORK 0x0301
+#define ATTR_ID_FAX_1_OR_AUD_VOL_OR_DEV_NAME 0x0302
+#define ATTR_ID_FORMATS_OR_FAX_2_0 0x0303
+#define ATTR_ID_FAX_CLASS_2_OR_FRIENDLY_NAME 0x0304
+#define ATTR_ID_NETADDRESS_OR_DEVLOCATION 0x0306
+
+#endif
diff --git a/mtkbt/code/bt/stack/include/smp_api.h b/mtkbt/code/bt/stack/include/smp_api.h
new file mode 100755
index 0000000..7e84217
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/smp_api.h
@@ -0,0 +1,241 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the SMP API function external definitions.
+ *
+ ******************************************************************************/
+#ifndef SMP_API_H
+#define SMP_API_H
+
+#include "bt_target.h"
+#include "smp_api_types.h"
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+/* API of SMP */
+
+/*******************************************************************************
+ *
+ * Function SMP_Init
+ *
+ * Description This function initializes the SMP unit.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern void SMP_Init(void);
+
+/*******************************************************************************
+ *
+ * Function SMP_SetTraceLevel
+ *
+ * Description This function sets the trace level for SMP. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+extern uint8_t SMP_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function SMP_Register
+ *
+ * Description This function register for the SMP service callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern bool SMP_Register(tSMP_CALLBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function SMP_Pair
+ *
+ * Description This function is called to start a SMP pairing.
+ *
+ * Returns SMP_STARTED if bond started, else otherwise exception.
+ *
+ ******************************************************************************/
+extern tSMP_STATUS SMP_Pair(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function SMP_BR_PairWith
+ *
+ * Description This function is called to start a SMP pairing over BR/EDR.
+ *
+ * Returns SMP_STARTED if pairing started, otherwise the reason for the
+ * failure.
+ *
+ ******************************************************************************/
+extern tSMP_STATUS SMP_BR_PairWith(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function SMP_PairCancel
+ *
+ * Description This function is called to cancel a SMP pairing.
+ *
+ * Returns true - pairing cancelled
+ *
+ ******************************************************************************/
+extern bool SMP_PairCancel(BD_ADDR bd_addr);
+
+/*******************************************************************************
+ *
+ * Function SMP_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation SMP_SUCCESS if success.
+ * Otherwise, SMP_REPEATED_ATTEMPTS is too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+extern void SMP_SecurityGrant(BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function SMP_PasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * Passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which PIN was requested
+ * res - result of the operation SMP_SUCCESS if success
+ * passkey - numeric value in the range of
+ * BTM_MIN_PASSKEY_VAL(0) -
+ * BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+extern void SMP_PasskeyReply(BD_ADDR bd_addr, uint8_t res, uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function SMP_ConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result SMP_SUCCESS if success
+ *
+ ******************************************************************************/
+extern void SMP_ConfirmReply(BD_ADDR bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function SMP_OobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to SMP_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - SM Randomizer C.
+ *
+ ******************************************************************************/
+extern void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, uint8_t len,
+ uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function SMP_SecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the SC OOB data for
+ * SMP in response to SMP_SC_OOB_REQ_EVT
+ *
+ * Parameters: p_data - pointer to the data
+ *
+ ******************************************************************************/
+extern void SMP_SecureConnectionOobDataReply(uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function SMP_Encrypt
+ *
+ * Description Encrypt the data with the specified key.
+ *
+ * Parameters: key - Pointer to key key[0] conatins the MSB
+ * key_len - key length
+ * plain_text - Pointer to data to be encrypted
+ * plain_text[0] conatins the MSB
+ * pt_len - plain text length
+ * p_out - pointer to the encrypted outputs
+ *
+ * Returns Boolean - true: encryption is successful
+ ******************************************************************************/
+extern bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, tSMP_ENC* p_out);
+
+/*******************************************************************************
+ *
+ * Function SMP_KeypressNotification
+ *
+ * Description Notify SM about Keypress Notification.
+ *
+ * Parameters: bd_addr - Address of the device to send keypress
+ * notification to
+ * value - keypress notification parameter value
+ *
+ ******************************************************************************/
+extern void SMP_KeypressNotification(BD_ADDR bd_addr, uint8_t value);
+
+/*******************************************************************************
+ *
+ * Function SMP_CreateLocalSecureConnectionsOobData
+ *
+ * Description This function is called to start creation of local SC OOB
+ * data set (tSMP_LOC_OOB_DATA).
+ *
+ * Parameters: bd_addr - Address of the device to send OOB data block
+ * to.
+ *
+ * Returns Boolean - true: creation of local SC OOB data set started.
+ ******************************************************************************/
+extern bool SMP_CreateLocalSecureConnectionsOobData(
+ tBLE_BD_ADDR* addr_to_send_to);
+
+// Called when LTK request is received from controller.
+extern bool smp_proc_ltk_request(BD_ADDR bda);
+
+// Called when link is encrypted and notified to slave device.
+// Proceed to send LTK, DIV and ER to master if bonding the devices.
+extern void smp_link_encrypted(BD_ADDR bda, uint8_t encr_enable);
+
+//
+// The AES-CMAC Generation Function with tlen implemented.
+// |key| - CMAC key in little endian order, expect SRK when used by SMP.
+// |input| - text to be signed in little endian byte order.
+// |length| - length of the input in byte.
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+// Returns false if out of resources, true in other cases.
+//
+bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
+ uint16_t tlen, uint8_t* p_signature);
+
+#endif /* SMP_API_H */
diff --git a/mtkbt/code/bt/stack/include/smp_api_types.h b/mtkbt/code/bt/stack/include/smp_api_types.h
new file mode 100755
index 0000000..f300ec4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/smp_api_types.h
@@ -0,0 +1,281 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SMP_API_TYPES_H
+#define SMP_API_TYPES_H
+
+#include "bt_target.h"
+
+#define SMP_PIN_CODE_LEN_MAX PIN_CODE_LEN
+#define SMP_PIN_CODE_LEN_MIN 6
+
+/* SMP command code */
+#define SMP_OPCODE_PAIRING_REQ 0x01
+#define SMP_OPCODE_PAIRING_RSP 0x02
+#define SMP_OPCODE_CONFIRM 0x03
+#define SMP_OPCODE_RAND 0x04
+#define SMP_OPCODE_PAIRING_FAILED 0x05
+#define SMP_OPCODE_ENCRYPT_INFO 0x06
+#define SMP_OPCODE_MASTER_ID 0x07
+#define SMP_OPCODE_IDENTITY_INFO 0x08
+#define SMP_OPCODE_ID_ADDR 0x09
+#define SMP_OPCODE_SIGN_INFO 0x0A
+#define SMP_OPCODE_SEC_REQ 0x0B
+#define SMP_OPCODE_PAIR_PUBLIC_KEY 0x0C
+#define SMP_OPCODE_PAIR_DHKEY_CHECK 0x0D
+#define SMP_OPCODE_PAIR_KEYPR_NOTIF 0x0E
+#define SMP_OPCODE_MAX SMP_OPCODE_PAIR_KEYPR_NOTIF
+#define SMP_OPCODE_MIN SMP_OPCODE_PAIRING_REQ
+#define SMP_OPCODE_PAIR_COMMITM 0x0F
+
+/* SMP event type */
+#define SMP_IO_CAP_REQ_EVT 1 /* IO capability request event */
+#define SMP_SEC_REQUEST_EVT 2 /* SMP pairing request */
+#define SMP_PASSKEY_NOTIF_EVT 3 /* passkey notification event */
+#define SMP_PASSKEY_REQ_EVT 4 /* passkey request event */
+#define SMP_OOB_REQ_EVT 5 /* OOB request event */
+#define SMP_NC_REQ_EVT 6 /* Numeric Comparison request event */
+#define SMP_COMPLT_EVT 7 /* SMP complete event */
+#define SMP_PEER_KEYPR_NOT_EVT 8 /* Peer keypress notification */
+
+/* SC OOB request event (both local and peer OOB data can be expected in
+ * response) */
+#define SMP_SC_OOB_REQ_EVT 9
+/* SC OOB local data set is created (as result of SMP_CrLocScOobData(...)) */
+#define SMP_SC_LOC_OOB_DATA_UP_EVT 10
+#define SMP_BR_KEYS_REQ_EVT 12 /* SMP over BR keys request event */
+typedef uint8_t tSMP_EVT;
+
+/* pairing failure reason code */
+#define SMP_PASSKEY_ENTRY_FAIL 0x01
+#define SMP_OOB_FAIL 0x02
+#define SMP_PAIR_AUTH_FAIL 0x03
+#define SMP_CONFIRM_VALUE_ERR 0x04
+#define SMP_PAIR_NOT_SUPPORT 0x05
+#define SMP_ENC_KEY_SIZE 0x06
+#define SMP_INVALID_CMD 0x07
+#define SMP_PAIR_FAIL_UNKNOWN 0x08
+#define SMP_REPEATED_ATTEMPTS 0x09
+#define SMP_INVALID_PARAMETERS 0x0A
+#define SMP_DHKEY_CHK_FAIL 0x0B
+#define SMP_NUMERIC_COMPAR_FAIL 0x0C
+#define SMP_BR_PARING_IN_PROGR 0x0D
+#define SMP_XTRANS_DERIVE_NOT_ALLOW 0x0E
+#define SMP_MAX_FAIL_RSN_PER_SPEC SMP_XTRANS_DERIVE_NOT_ALLOW
+
+/* self defined error code */
+#define SMP_PAIR_INTERNAL_ERR (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01) /* 0x0F */
+
+/* Unknown IO capability, unable to decide association model */
+#define SMP_UNKNOWN_IO_CAP (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02) /* 0x10 */
+
+#define SMP_INIT_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x03) /* 0x11 */
+#define SMP_CONFIRM_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x04) /* 0x12 */
+#define SMP_BUSY (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05) /* 0x13 */
+#define SMP_ENC_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06) /* 0x14 */
+#define SMP_STARTED (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07) /* 0x15 */
+#define SMP_RSP_TIMEOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08) /* 0x16 */
+#define SMP_DIV_NOT_AVAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x09) /* 0x17 */
+
+/* Unspecified failure reason */
+#define SMP_FAIL (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A) /* 0x18 */
+
+#define SMP_CONN_TOUT (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B) /* 0x19 */
+#define SMP_SUCCESS 0
+
+typedef uint8_t tSMP_STATUS;
+
+/* Device IO capability */
+#define SMP_IO_CAP_OUT BTM_IO_CAP_OUT /* DisplayOnly */
+#define SMP_IO_CAP_IO BTM_IO_CAP_IO /* DisplayYesNo */
+#define SMP_IO_CAP_IN BTM_IO_CAP_IN /* KeyboardOnly */
+#define SMP_IO_CAP_NONE BTM_IO_CAP_NONE /* NoInputNoOutput */
+#define SMP_IO_CAP_KBDISP BTM_IO_CAP_KBDISP /* Keyboard Display */
+#define SMP_IO_CAP_MAX BTM_IO_CAP_MAX
+typedef uint8_t tSMP_IO_CAP;
+
+#ifndef SMP_DEFAULT_IO_CAPS
+#define SMP_DEFAULT_IO_CAPS SMP_IO_CAP_KBDISP
+#endif
+
+/* OOB data present or not */
+enum { SMP_OOB_NONE, SMP_OOB_PRESENT, SMP_OOB_UNKNOWN };
+typedef uint8_t tSMP_OOB_FLAG;
+
+/* type of OOB data required from application */
+enum { SMP_OOB_INVALID_TYPE, SMP_OOB_PEER, SMP_OOB_LOCAL, SMP_OOB_BOTH };
+typedef uint8_t tSMP_OOB_DATA_TYPE;
+
+#define SMP_AUTH_NO_BOND 0x00
+#define SMP_AUTH_GEN_BOND 0x01 // todo sdh change GEN_BOND to BOND
+
+/* SMP Authentication requirement */
+#define SMP_AUTH_YN_BIT (1 << 2)
+#define SMP_SC_SUPPORT_BIT (1 << 3)
+#define SMP_KP_SUPPORT_BIT (1 << 4)
+#define SMP_H7_SUPPORT_BIT (1 << 5)
+
+#define SMP_AUTH_MASK \
+ (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT | SMP_SC_SUPPORT_BIT | \
+ SMP_KP_SUPPORT_BIT | SMP_H7_SUPPORT_BIT)
+
+#define SMP_AUTH_BOND SMP_AUTH_GEN_BOND
+
+/* no MITM, No Bonding, encryption only */
+#define SMP_AUTH_NB_ENC_ONLY 0x00 //(SMP_AUTH_MASK | BTM_AUTH_SP_NO)
+
+/* MITM, No Bonding, Use IO Capability to determine authentication procedure */
+#define SMP_AUTH_NB_IOCAP (SMP_AUTH_NO_BOND | SMP_AUTH_YN_BIT)
+
+/* No MITM, General Bonding, Encryption only */
+#define SMP_AUTH_GB_ENC_ONLY (SMP_AUTH_GEN_BOND)
+
+/* MITM, General Bonding, Use IO Capability to determine authentication
+ * procedure */
+#define SMP_AUTH_GB_IOCAP (SMP_AUTH_GEN_BOND | SMP_AUTH_YN_BIT)
+
+/* Secure Connections, no MITM, no Bonding */
+#define SMP_AUTH_SC_ENC_ONLY (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT)
+
+/* Secure Connections, no MITM, Bonding */
+#define SMP_AUTH_SC_GB \
+ (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_GEN_BOND)
+
+/* Secure Connections, MITM, no Bonding */
+#define SMP_AUTH_SC_MITM_NB \
+ (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | SMP_AUTH_NO_BOND)
+
+/* Secure Connections, MITM, Bonding */
+#define SMP_AUTH_SC_MITM_GB \
+ (SMP_H7_SUPPORT_BIT | SMP_SC_SUPPORT_BIT | SMP_AUTH_YN_BIT | \
+ SMP_AUTH_GEN_BOND)
+
+/* All AuthReq RFU bits are set to 1 - NOTE: reserved bit in Bonding_Flags is
+ * not set */
+#define SMP_AUTH_ALL_RFU_SET 0xF8
+
+typedef uint8_t tSMP_AUTH_REQ;
+
+#define SMP_SEC_NONE 0
+#define SMP_SEC_UNAUTHENTICATE (1 << 0)
+#define SMP_SEC_AUTHENTICATED (1 << 2)
+typedef uint8_t tSMP_SEC_LEVEL;
+
+/* Maximum Encryption Key Size range */
+#define SMP_ENCR_KEY_SIZE_MIN 7
+#define SMP_ENCR_KEY_SIZE_MAX 16
+
+/* SMP key types */
+#define SMP_SEC_KEY_TYPE_ENC (1 << 0) /* encryption key */
+#define SMP_SEC_KEY_TYPE_ID (1 << 1) /* identity key */
+#define SMP_SEC_KEY_TYPE_CSRK (1 << 2) /* slave CSRK */
+#define SMP_SEC_KEY_TYPE_LK (1 << 3) /* BR/EDR link key */
+typedef uint8_t tSMP_KEYS;
+
+#define SMP_BR_SEC_DEFAULT_KEY \
+ (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK)
+
+/* default security key distribution value */
+#define SMP_SEC_DEFAULT_KEY \
+ (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK | \
+ SMP_SEC_KEY_TYPE_LK)
+
+#define SMP_SC_KEY_STARTED 0 /* passkey entry started */
+#define SMP_SC_KEY_ENTERED 1 /* passkey digit entered */
+#define SMP_SC_KEY_ERASED 2 /* passkey digit erased */
+#define SMP_SC_KEY_CLEARED 3 /* passkey cleared */
+#define SMP_SC_KEY_COMPLT 4 /* passkey entry completed */
+#define SMP_SC_KEY_OUT_OF_RANGE 5 /* out of range */
+typedef uint8_t tSMP_SC_KEY_TYPE;
+
+/* data type for BTM_SP_IO_REQ_EVT */
+typedef struct {
+ tSMP_IO_CAP io_cap; /* local IO capabilities */
+ tSMP_OOB_FLAG oob_data; /* OOB data present (locally) for the peer device */
+ tSMP_AUTH_REQ auth_req; /* Authentication required (for local device) */
+ uint8_t max_key_size; /* max encryption key size */
+ tSMP_KEYS init_keys; /* initiator keys to be distributed */
+ tSMP_KEYS resp_keys; /* responder keys */
+} tSMP_IO_REQ;
+
+typedef struct {
+ tSMP_STATUS reason;
+ tSMP_SEC_LEVEL sec_level;
+ bool is_pair_cancel;
+ bool smp_over_br;
+} tSMP_CMPL;
+
+typedef struct {
+ BT_OCTET32 x;
+ BT_OCTET32 y;
+} tSMP_PUBLIC_KEY;
+
+/* the data associated with the info sent to the peer via OOB interface */
+typedef struct {
+ bool present;
+ BT_OCTET16 randomizer;
+ BT_OCTET16 commitment;
+
+ tBLE_BD_ADDR addr_sent_to;
+ BT_OCTET32 private_key_used; /* is used to calculate: */
+ /* publ_key_used = P-256(private_key_used, curve_p256.G) - send it to the */
+ /* other side */
+ /* dhkey = P-256(private_key_used, publ key rcvd from the other side) */
+ tSMP_PUBLIC_KEY publ_key_used; /* P-256(private_key_used, curve_p256.G) */
+} tSMP_LOC_OOB_DATA;
+
+/* the data associated with the info received from the peer via OOB interface */
+typedef struct {
+ bool present;
+ BT_OCTET16 randomizer;
+ BT_OCTET16 commitment;
+ tBLE_BD_ADDR addr_rcvd_from;
+} tSMP_PEER_OOB_DATA;
+
+typedef struct {
+ tSMP_LOC_OOB_DATA loc_oob_data;
+ tSMP_PEER_OOB_DATA peer_oob_data;
+} tSMP_SC_OOB_DATA;
+
+typedef union {
+ uint32_t passkey;
+ tSMP_IO_REQ io_req; /* IO request */
+ tSMP_CMPL cmplt;
+ tSMP_OOB_DATA_TYPE req_oob_type;
+ tSMP_LOC_OOB_DATA loc_oob_data;
+} tSMP_EVT_DATA;
+
+/* AES Encryption output */
+typedef struct {
+ uint8_t status;
+ uint8_t param_len;
+ uint16_t opcode;
+ uint8_t param_buf[BT_OCTET16_LEN];
+} tSMP_ENC;
+
+/* Security Manager events - Called by the stack when Security Manager related
+ * events occur.*/
+typedef uint8_t(tSMP_CALLBACK)(tSMP_EVT event, BD_ADDR bd_addr,
+ tSMP_EVT_DATA* p_data);
+
+/* callback function for CMAC algorithm
+*/
+typedef void(tCMAC_CMPL_CBACK)(uint8_t* p_mac, uint16_t tlen,
+ uint32_t sign_counter);
+
+#endif // SMP_API_TYPES_H
diff --git a/mtkbt/code/bt/stack/include/srvc_api.h b/mtkbt/code/bt/stack/include/srvc_api.h
new file mode 100755
index 0000000..3219e20
--- a/dev/null
+++ b/mtkbt/code/bt/stack/include/srvc_api.h
@@ -0,0 +1,199 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_DIS_API_H
+#define SRVC_DIS_API_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "gattdefs.h"
+
+#define DIS_SUCCESS GATT_SUCCESS
+#define DIS_ILLEGAL_PARAM GATT_ILLEGAL_PARAMETER
+#define DIS_NO_RESOURCES GATT_NO_RESOURCES
+typedef uint8_t tDIS_STATUS;
+
+/*****************************************************************************
+ * Data structure for DIS
+ ****************************************************************************/
+
+#define DIS_ATTR_SYS_ID_BIT 0x0001
+#define DIS_ATTR_MODEL_NUM_BIT 0x0002
+#define DIS_ATTR_SERIAL_NUM_BIT 0x0004
+#define DIS_ATTR_FW_NUM_BIT 0x0008
+#define DIS_ATTR_HW_NUM_BIT 0x0010
+#define DIS_ATTR_SW_NUM_BIT 0x0020
+#define DIS_ATTR_MANU_NAME_BIT 0x0040
+#define DIS_ATTR_IEEE_DATA_BIT 0x0080
+#define DIS_ATTR_PNP_ID_BIT 0x0100
+typedef uint16_t tDIS_ATTR_MASK;
+
+#define DIS_ATTR_ALL_MASK 0xffff
+
+typedef tDIS_ATTR_MASK tDIS_ATTR_BIT;
+
+typedef struct {
+ uint16_t len;
+ uint8_t* p_data;
+} tDIS_STRING;
+
+typedef struct {
+ uint16_t vendor_id;
+ uint16_t product_id;
+ uint16_t product_version;
+ uint8_t vendor_id_src;
+
+} tDIS_PNP_ID;
+
+typedef union {
+ uint64_t system_id;
+ tDIS_PNP_ID pnp_id;
+ tDIS_STRING data_str;
+} tDIS_ATTR;
+
+#define DIS_MAX_STRING_DATA 7
+
+typedef struct {
+ uint16_t attr_mask;
+ uint64_t system_id;
+ tDIS_PNP_ID pnp_id;
+ uint8_t* data_string[DIS_MAX_STRING_DATA];
+} tDIS_VALUE;
+
+typedef void(tDIS_READ_CBACK)(BD_ADDR addr, tDIS_VALUE* p_dis_value);
+
+/*****************************************************************************
+ * Data structure used by Battery Service
+ ****************************************************************************/
+typedef struct {
+ BD_ADDR remote_bda;
+ bool need_rsp;
+ uint16_t clt_cfg;
+} tBA_WRITE_DATA;
+
+#define BA_READ_CLT_CFG_REQ 1
+#define BA_READ_PRE_FMT_REQ 2
+#define BA_READ_RPT_REF_REQ 3
+#define BA_READ_LEVEL_REQ 4
+#define BA_WRITE_CLT_CFG_REQ 5
+
+typedef void(tBA_CBACK)(uint8_t app_id, uint8_t event, tBA_WRITE_DATA* p_data);
+
+#define BA_LEVEL_NOTIFY 0x01
+#define BA_LEVEL_PRE_FMT 0x02
+#define BA_LEVEL_RPT_REF 0x04
+typedef uint8_t tBA_LEVEL_DESCR;
+
+typedef struct {
+ bool is_pri;
+ tBA_LEVEL_DESCR ba_level_descr;
+ tGATT_TRANSPORT transport;
+ tBA_CBACK* p_cback;
+
+} tBA_REG_INFO;
+
+typedef union {
+ uint8_t ba_level;
+ uint16_t clt_cfg;
+ tGATT_CHAR_RPT_REF rpt_ref;
+ tGATT_CHAR_PRES pres_fmt;
+} tBA_RSP_DATA;
+
+/*****************************************************************************
+ * External Function Declarations
+ ****************************************************************************/
+/*****************************************************************************
+ * Service Engine API
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function srvc_eng_init
+ *
+ * Description Initializa the GATT Service engine, register a GATT
+ * application as for a central service management.
+ *
+ ******************************************************************************/
+extern tGATT_STATUS srvc_eng_init(void);
+
+/*****************************************************************************
+ * DIS Server Function
+ ****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function DIS_SrInit
+ *
+ * Description Initializa the Device Information Service Server.
+ *
+ ******************************************************************************/
+extern tDIS_STATUS DIS_SrInit(tDIS_ATTR_MASK dis_attr_mask);
+/*******************************************************************************
+ *
+ * Function DIS_SrUpdate
+ *
+ * Description Update the DIS server attribute values
+ *
+ ******************************************************************************/
+extern tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR* p_info);
+/*****************************************************************************
+ * DIS Client Function
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function DIS_ReadDISInfo
+ *
+ * Description Read remote device DIS information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+extern bool DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK* p_cback,
+ tDIS_ATTR_MASK mask);
+
+/*******************************************************************************
+ * BATTERY SERVICE API
+ ******************************************************************************/
+/*******************************************************************************
+ *
+ * Function Battery_Instantiate
+ *
+ * Description Instantiate a Battery service
+ *
+ ******************************************************************************/
+extern uint16_t Battery_Instantiate(uint8_t app_id, tBA_REG_INFO* p_reg_info);
+
+/*******************************************************************************
+ *
+ * Function Battery_Rsp
+ *
+ * Description Respond to a battery service request
+ *
+ ******************************************************************************/
+extern void Battery_Rsp(uint8_t app_id, tGATT_STATUS st, uint8_t event,
+ tBA_RSP_DATA* p_rsp);
+/*******************************************************************************
+ *
+ * Function Battery_Notify
+ *
+ * Description Send battery level notification
+ *
+ ******************************************************************************/
+extern void Battery_Notify(uint8_t app_id, BD_ADDR remote_bda,
+ uint8_t battery_level);
+
+#endif
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_api.cc b/mtkbt/code/bt/stack/l2cap/l2c_api.cc
new file mode 100755
index 0000000..f529897
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_api.cc
@@ -0,0 +1,2274 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the L2CAP API code
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_l2cap"
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function L2CA_Register
+ *
+ * Description Other layers call this function to register for L2CAP
+ * services.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectReq(),
+ * L2CA_ErtmConnectReq() and L2CA_Deregister()
+ *
+ ******************************************************************************/
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+ tL2C_RCB* p_rcb;
+ uint16_t vpsm = psm;
+
+ L2CAP_TRACE_API("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm);
+
+ /* Verify that the required callback info has been filled in
+ ** Note: Connection callbacks are required but not checked
+ ** for here because it is possible to be only a client
+ ** or only a server.
+ */
+ if ((!p_cb_info->pL2CA_ConfigCfm_Cb) || (!p_cb_info->pL2CA_ConfigInd_Cb) ||
+ (!p_cb_info->pL2CA_DataInd_Cb) || (!p_cb_info->pL2CA_DisconnectInd_Cb)) {
+ L2CAP_TRACE_ERROR("L2CAP - no cb registering PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Verify PSM is valid */
+ if (L2C_INVALID_PSM(psm)) {
+ L2CAP_TRACE_ERROR("L2CAP - invalid PSM value, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Check if this is a registration for an outgoing-only connection to */
+ /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+ if ((psm >= 0x1001) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
+ for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2) {
+ p_rcb = l2cu_find_rcb_by_psm(vpsm);
+ if (p_rcb == NULL) break;
+ }
+
+ L2CAP_TRACE_API("L2CA_Register - Real PSM: 0x%04x Virtual PSM: 0x%04x",
+ psm, vpsm);
+ }
+
+ /* If registration block already there, just overwrite it */
+ p_rcb = l2cu_find_rcb_by_psm(vpsm);
+ if (p_rcb == NULL) {
+ p_rcb = l2cu_allocate_rcb(vpsm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no RCB available, PSM: 0x%04x vPSM: 0x%04x",
+ psm, vpsm);
+ return (0);
+ }
+ }
+
+ p_rcb->api = *p_cb_info;
+ p_rcb->real_psm = psm;
+
+ return (vpsm);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_Deregister
+ *
+ * Description Other layers call this function to de-register for L2CAP
+ * services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void L2CA_Deregister(uint16_t psm) {
+ tL2C_RCB* p_rcb;
+ tL2C_CCB* p_ccb;
+ tL2C_LCB* p_lcb;
+ int ii;
+
+ L2CAP_TRACE_API("L2CAP - L2CA_Deregister() called for PSM: 0x%04x", psm);
+
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb != NULL) {
+ p_lcb = &l2cb.lcb_pool[0];
+ for (ii = 0; ii < MAX_L2CAP_LINKS; ii++, p_lcb++) {
+ if (p_lcb->in_use) {
+ p_ccb = p_lcb->ccb_queue.p_first_ccb;
+ if ((p_ccb == NULL) || (p_lcb->link_state == LST_DISCONNECTING)) {
+ continue;
+ }
+
+ if ((p_ccb->in_use) &&
+ ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+ (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))) {
+ continue;
+ }
+
+ if (p_ccb->p_rcb == p_rcb) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+ }
+ }
+ }
+ l2cu_release_rcb(p_rcb);
+ } else {
+ L2CAP_TRACE_WARNING("L2CAP - PSM: 0x%04x not found for deregistration",
+ psm);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_AllocatePSM
+ *
+ * Description Other layers call this function to find an unused PSM for
+ * L2CAP services.
+ *
+ * Returns PSM to use.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocatePSM(void) {
+ bool done = false;
+ uint16_t psm = l2cb.dyn_psm;
+
+ L2CAP_TRACE_API("L2CA_AllocatePSM");
+ while (!done) {
+ psm += 2;
+ if (psm > 0xfeff) {
+ psm = 0x1001;
+ } else if (psm & 0x0100) {
+ /* the upper byte must be even */
+ psm += 0x0100;
+ }
+
+ /* if psm is in range of reserved BRCM Aware features */
+ if ((BRCM_RESERVED_PSM_START <= psm) && (psm <= BRCM_RESERVED_PSM_END))
+ continue;
+
+ /* make sure the newlly allocated psm is not used right now */
+ if ((l2cu_find_rcb_by_psm(psm)) == NULL) done = true;
+ }
+ l2cb.dyn_psm = psm;
+
+ return (psm);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection. Note that the connection is not established at
+ * this time, but connection establishment gets started. The
+ * callback function will be invoked when connection
+ * establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectReq(uint16_t psm, BD_ADDR p_bd_addr) {
+ return L2CA_ErtmConnectReq(psm, p_bd_addr, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection. Note that the connection is not established at
+ * this time, but connection establishment gets started. The
+ * callback function will be invoked when connection
+ * establishes or fails.
+ *
+ * Parameters: PSM: L2CAP PSM for the connection
+ * BD address of the peer
+ * Enhaced retransmission mode configurations
+
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ErtmConnectReq(uint16_t psm, BD_ADDR p_bd_addr,
+ tL2CAP_ERTM_INFO* p_ertm_info) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_API(
+ "L2CA_ErtmConnectReq() PSM: 0x%04x BDA: %08x%04x p_ertm_info: 0x%08x "
+ "allowed:0x%x preferred:%d",
+ psm, (p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) + (p_bd_addr[2] << 8) +
+ p_bd_addr[3],
+ (p_bd_addr[4] << 8) + p_bd_addr[5], p_ertm_info,
+ (p_ertm_info) ? p_ertm_info->allowed_modes : 0,
+ (p_ertm_info) ? p_ertm_info->preferred_mode : 0);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("L2CAP connect req - BTU not ready");
+ return (0);
+ }
+ /* Fail if the PSM is not registered */
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_conn_req, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* First, see if we already have a link to the remote */
+ /* assume all ERTM l2cap connection is going over BR/EDR for now */
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
+ /* currently use BR/EDR for ERTM mode l2cap connection */
+ if ((p_lcb == NULL) ||
+ (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - conn not started for PSM: 0x%04x p_lcb: 0x%08x", psm,
+ p_lcb);
+ return (0);
+ }
+ }
+
+ /* Allocate a channel control block */
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_req, PSM: 0x%04x", psm);
+ return (0);
+ }
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ if (p_ertm_info) {
+ p_ccb->ertm_info = *p_ertm_info;
+
+ /* Replace default indicators with the actual default pool */
+ if (p_ccb->ertm_info.fcr_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.fcr_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.user_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.user_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+ p_ccb->max_rx_mtu =
+ p_ertm_info->user_rx_buf_size -
+ (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+ }
+
+ /* If link is up, start the L2CAP connection */
+ if (p_lcb->link_state == LST_CONNECTED) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+ }
+
+ /* If link is disconnecting, save link info to retry after disconnect
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
+ else if (p_lcb->link_state == LST_DISCONNECTING) {
+ L2CAP_TRACE_DEBUG("L2CAP API - link disconnecting: RETRY LATER");
+
+ /* Save ccb so it can be started after disconnect is finished */
+ p_lcb->p_pending_ccb = p_ccb;
+ }
+
+ L2CAP_TRACE_API("L2CAP - L2CA_conn_req(psm: 0x%04x) returned CID: 0x%04x",
+ psm, p_ccb->local_cid);
+
+ /* Return the local CID as our handle */
+ return (p_ccb->local_cid);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterLECoc
+ *
+ * Description Other layers call this function to register for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectLECocReq()
+ * and L2CA_DeregisterLECoc()
+ *
+ ******************************************************************************/
+uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+ L2CAP_TRACE_API("%s called for LE PSM: 0x%04x", __func__, psm);
+
+ /* Verify that the required callback info has been filled in
+ ** Note: Connection callbacks are required but not checked
+ ** for here because it is possible to be only a client
+ ** or only a server.
+ */
+ if ((!p_cb_info->pL2CA_DataInd_Cb) || (!p_cb_info->pL2CA_DisconnectInd_Cb)) {
+ L2CAP_TRACE_ERROR("%s No cb registering BLE PSM: 0x%04x", __func__, psm);
+ return 0;
+ }
+
+ /* Verify PSM is valid */
+ if (!L2C_IS_VALID_LE_PSM(psm)) {
+ L2CAP_TRACE_ERROR("%s Invalid BLE PSM value, PSM: 0x%04x", __func__, psm);
+ return 0;
+ }
+
+ tL2C_RCB* p_rcb;
+ uint16_t vpsm = psm;
+
+ /* Check if this is a registration for an outgoing-only connection to */
+ /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */
+ if ((psm >= 0x0080) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL)) {
+ for (vpsm = 0x0080; vpsm < 0x0100; vpsm++) {
+ p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+ if (p_rcb == NULL) break;
+ }
+
+ L2CAP_TRACE_API("%s Real PSM: 0x%04x Virtual PSM: 0x%04x", __func__, psm,
+ vpsm);
+ }
+
+ /* If registration block already there, just overwrite it */
+ p_rcb = l2cu_find_ble_rcb_by_psm(vpsm);
+ if (p_rcb == NULL) {
+ p_rcb = l2cu_allocate_ble_rcb(vpsm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("%s No BLE RCB available, PSM: 0x%04x vPSM: 0x%04x",
+ __func__, psm, vpsm);
+ return 0;
+ }
+ }
+
+ p_rcb->api = *p_cb_info;
+ p_rcb->real_psm = psm;
+
+ return vpsm;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_DeregisterLECoc
+ *
+ * Description Other layers call this function to de-register for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void L2CA_DeregisterLECoc(uint16_t psm) {
+ L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm);
+
+ tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("%s PSM: 0x%04x not found for deregistration", psm);
+ return;
+ }
+
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+ for (int i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++) {
+ if (!p_lcb->in_use || p_lcb->transport != BT_TRANSPORT_LE) continue;
+
+ tL2C_CCB* p_ccb = p_lcb->ccb_queue.p_first_ccb;
+ if ((p_ccb == NULL) || (p_lcb->link_state == LST_DISCONNECTING)) continue;
+
+ if (p_ccb->in_use && (p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP ||
+ p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))
+ continue;
+
+ if (p_ccb->p_rcb == p_rcb)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+ }
+
+ l2cu_release_rcb(p_rcb);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection. Note that the connection is not established at
+ * this time, but connection establishment gets started. The
+ * callback function will be invoked when connection
+ * establishes or fails.
+ *
+ * Parameters: PSM: L2CAP PSM for the connection
+ * BD address of the peer
+ * Local Coc configurations
+
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectLECocReq(uint16_t psm, BD_ADDR p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ L2CAP_TRACE_API("%s PSM: 0x%04x BDA: %02x:%02x:%02x:%02x:%02x:%02x", __func__,
+ psm, p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3],
+ p_bd_addr[4], p_bd_addr[5]);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("%s BTU not ready", __func__);
+ return 0;
+ }
+
+ /* Fail if the PSM is not registered */
+ tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("%s No BLE RCB, PSM: 0x%04x", __func__, psm);
+ return 0;
+ }
+
+ /* First, see if we already have a le link to the remote */
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_LE);
+ if ((p_lcb == NULL)
+ /* currently use BR/EDR for ERTM mode l2cap connection */
+ || (l2cu_create_conn(p_lcb, BT_TRANSPORT_LE) == false)) {
+ L2CAP_TRACE_WARNING("%s conn not started for PSM: 0x%04x p_lcb: 0x%08x",
+ __func__, psm, p_lcb);
+ return 0;
+ }
+ }
+
+ /* Allocate a channel control block */
+ tL2C_CCB* p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("%s no CCB, PSM: 0x%04x", __func__, psm);
+ return 0;
+ }
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ /* Save the configuration */
+ if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+ /* If link is up, start the L2CAP connection */
+ if (p_lcb->link_state == LST_CONNECTED) {
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG("%s LE Link is up", __func__);
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_REQ, NULL);
+ }
+ }
+
+ /* If link is disconnecting, save link info to retry after disconnect
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
+ else if (p_lcb->link_state == LST_DISCONNECTING) {
+ L2CAP_TRACE_DEBUG("%s link disconnecting: RETRY LATER", __func__);
+
+ /* Save ccb so it can be started after disconnect is finished */
+ p_lcb->p_pending_ccb = p_ccb;
+ }
+
+ L2CAP_TRACE_API("%s(psm: 0x%04x) returned CID: 0x%04x", __func__, psm,
+ p_ccb->local_cid);
+
+ /* Return the local CID as our handle */
+ return p_ccb->local_cid;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP COC connection, for which they had gotten an connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectLECocRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ L2CAP_TRACE_API(
+ "%s CID: 0x%04x Result: %d Status: %d BDA: %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, lcid, result, status, p_bd_addr[0], p_bd_addr[1], p_bd_addr[2],
+ p_bd_addr[3], p_bd_addr[4], p_bd_addr[5]);
+
+ /* First, find the link control block */
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_LE);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ L2CAP_TRACE_WARNING("%s no LCB", __func__);
+ return false;
+ }
+
+ /* Now, find the channel control block */
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("%s no CCB", __func__);
+ return false;
+ }
+
+ /* The IDs must match */
+ if (p_ccb->remote_id != id) {
+ L2CAP_TRACE_WARNING("%s bad id. Expected: %d Got: %d", __func__,
+ p_ccb->remote_id, id);
+ return false;
+ }
+
+ if (p_cfg) memcpy(&p_ccb->local_conn_cfg, p_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+ if (result == L2CAP_CONN_OK)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+ else {
+ tL2C_CONN_INFO conn_info;
+ memcpy(conn_info.bd_addr, p_bd_addr, BD_ADDR_LEN);
+ conn_info.l2cap_result = result;
+ conn_info.l2cap_status = status;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerLECocConfig
+ *
+ * Description Get a peers configuration for LE Connection Oriented
+ * Channel.
+ *
+ * Parameters: local channel id
+ * Pointers to peers configuration storage area
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+ L2CAP_TRACE_API("%s CID: 0x%04x", __func__, lcid);
+
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid);
+ return false;
+ }
+
+ if (peer_cfg != NULL)
+ memcpy(peer_cfg, &p_ccb->peer_conn_cfg, sizeof(tL2CAP_LE_CFG_INFO));
+
+ return true;
+}
+
+bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
+ const tL2CAP_APPL_INFO* callbacks) {
+ CHECK(callbacks != NULL);
+ CHECK(callbacks->pL2CA_ConnectInd_Cb == NULL);
+ CHECK(callbacks->pL2CA_ConnectCfm_Cb != NULL);
+ CHECK(callbacks->pL2CA_ConfigInd_Cb != NULL);
+ CHECK(callbacks->pL2CA_ConfigCfm_Cb != NULL);
+ CHECK(callbacks->pL2CA_DisconnectInd_Cb != NULL);
+ CHECK(callbacks->pL2CA_DisconnectCfm_Cb != NULL);
+ CHECK(callbacks->pL2CA_CongestionStatus_Cb != NULL);
+ CHECK(callbacks->pL2CA_DataInd_Cb != NULL);
+ CHECK(callbacks->pL2CA_TxComplete_Cb != NULL);
+
+ tL2C_CCB* channel_control_block = l2cu_find_ccb_by_cid(NULL, local_cid);
+ if (!channel_control_block) {
+ LOG_ERROR(LOG_TAG,
+ "%s no channel control block found for L2CAP LCID=0x%04x.",
+ __func__, local_cid);
+ return false;
+ }
+
+ // We're making a connection-specific registration control block so we check
+ // if we already have a private one allocated to us on the heap. If not, we
+ // make a new allocation, mark it as heap-allocated, and inherit the fields
+ // from the old control block.
+ tL2C_RCB* registration_control_block = channel_control_block->p_rcb;
+ if (!channel_control_block->should_free_rcb) {
+ registration_control_block = (tL2C_RCB*)osi_calloc(sizeof(tL2C_RCB));
+
+ *registration_control_block = *channel_control_block->p_rcb;
+ channel_control_block->p_rcb = registration_control_block;
+ channel_control_block->should_free_rcb = true;
+ }
+
+ registration_control_block->api = *callbacks;
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status) {
+ return L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result, status, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ErtmConnectRsp(BD_ADDR p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_ERTM_INFO* p_ertm_info) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_ErtmConnectRsp() CID: 0x%04x Result: %d Status: %d BDA: "
+ "%08x%04x p_ertm_info:0x%08x",
+ lcid, result, status, (p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) +
+ (p_bd_addr[2] << 8) + p_bd_addr[3],
+ (p_bd_addr[4] << 8) + p_bd_addr[5], p_ertm_info);
+
+ /* First, find the link control block */
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_conn_rsp");
+ return (false);
+ }
+
+ /* Now, find the channel control block */
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_rsp");
+ return (false);
+ }
+
+ /* The IDs must match */
+ if (p_ccb->remote_id != id) {
+ L2CAP_TRACE_WARNING("L2CAP - bad id in L2CA_conn_rsp. Exp: %d Got: %d",
+ p_ccb->remote_id, id);
+ return (false);
+ }
+
+ if (p_ertm_info) {
+ p_ccb->ertm_info = *p_ertm_info;
+
+ /* Replace default indicators with the actual default pool */
+ if (p_ccb->ertm_info.fcr_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.fcr_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.user_rx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+
+ if (p_ccb->ertm_info.user_tx_buf_size == L2CAP_INVALID_ERM_BUF_SIZE)
+ p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+ p_ccb->max_rx_mtu =
+ p_ertm_info->user_rx_buf_size -
+ (L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET + L2CAP_FCS_LEN);
+ }
+
+ if (result == L2CAP_CONN_OK) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, NULL);
+ } else {
+ tL2C_CONN_INFO conn_info;
+
+ conn_info.l2cap_result = result;
+ conn_info.l2cap_status = status;
+
+ if (result == L2CAP_CONN_PENDING)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP, &conn_info);
+ else
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONNECT_RSP_NEG, &conn_info);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigReq
+ *
+ * Description Higher layers call this function to send configuration.
+ *
+ * Note: The FCR options of p_cfg are not used.
+ *
+ * Returns true if configuration sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_ConfigReq() CID 0x%04x: fcr_present:%d (mode %d) mtu_present:%d "
+ "(%d)",
+ cid, p_cfg->fcr_present, p_cfg->fcr.mode, p_cfg->mtu_present, p_cfg->mtu);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_cfg_req, CID: %d", cid);
+ return (false);
+ }
+
+ /* We need to have at least one mode type common with the peer */
+ if (!l2c_fcr_adj_our_req_options(p_ccb, p_cfg)) return (false);
+
+ /* Don't adjust FCR options if not used */
+ if ((!p_cfg->fcr_present) || (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)) {
+ /* FCR and FCS options are not used in basic mode */
+ p_cfg->fcs_present = false;
+ p_cfg->ext_flow_spec_present = false;
+
+ if ((p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE)) {
+ L2CAP_TRACE_WARNING("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+ }
+ }
+
+ /* Save the adjusted configuration in case it needs to be used for
+ * renegotiation */
+ p_ccb->our_cfg = *p_cfg;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_REQ, p_cfg);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigRsp
+ *
+ * Description Higher layers call this function to send a configuration
+ * response.
+ *
+ * Returns true if configuration response sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_ConfigRsp() CID: 0x%04x Result: %d MTU present:%d Flush TO:%d "
+ "FCR:%d FCS:%d",
+ cid, p_cfg->result, p_cfg->mtu_present, p_cfg->flush_to_present,
+ p_cfg->fcr_present, p_cfg->fcs_present);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_cfg_rsp, CID: %d", cid);
+ return (false);
+ }
+
+ if ((p_cfg->result == L2CAP_CFG_OK) || (p_cfg->result == L2CAP_CFG_PENDING))
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_RSP, p_cfg);
+ else {
+ p_cfg->fcr_present =
+ false; /* FCR options already negotiated before this point */
+
+ /* Clear out any cached options that are being returned as an error
+ * (excluding FCR) */
+ if (p_cfg->mtu_present) p_ccb->peer_cfg.mtu_present = false;
+ if (p_cfg->flush_to_present) p_ccb->peer_cfg.flush_to_present = false;
+ if (p_cfg->qos_present) p_ccb->peer_cfg.qos_present = false;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_RSP_NEG, p_cfg);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectReq
+ *
+ * Description Higher layers call this function to disconnect a channel.
+ *
+ * Returns true if disconnect sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectReq(uint16_t cid) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API("L2CA_DisconnectReq() CID: 0x%04x", cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_disc_req, CID: %d", cid);
+ return (false);
+ }
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectRsp
+ *
+ * Description Higher layers call this function to acknowledge the
+ * disconnection of a channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectRsp(uint16_t cid) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API("L2CA_DisconnectRsp() CID: 0x%04x", cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_disc_rsp, CID: %d", cid);
+ return (false);
+ }
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DISCONNECT_RSP, NULL);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_Ping
+ *
+ * Description Higher layers call this function to send an echo request.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Ping(BD_ADDR p_bd_addr, tL2CA_ECHO_RSP_CB* p_callback) {
+ tL2C_LCB* p_lcb;
+
+ L2CAP_TRACE_API("L2CA_Ping() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ p_bd_addr[0], p_bd_addr[1], p_bd_addr[2], p_bd_addr[3],
+ p_bd_addr[4], p_bd_addr[5]);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) return (false);
+
+ /* First, see if we already have a link to the remote */
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_ping");
+ return (false);
+ }
+ if (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false) {
+ return (false);
+ }
+
+ p_lcb->p_echo_rsp_cb = p_callback;
+
+ return (true);
+ }
+
+ /* We only allow 1 ping outstanding at a time */
+ if (p_lcb->p_echo_rsp_cb != NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - rejected second L2CA_ping");
+ return (false);
+ }
+
+ /* Have a link control block. If link is disconnecting, tell user to retry
+ * later */
+ if (p_lcb->link_state == LST_DISCONNECTING) {
+ L2CAP_TRACE_WARNING("L2CAP - L2CA_ping rejected - link disconnecting");
+ return (false);
+ }
+
+ /* Save address of callback */
+ p_lcb->p_echo_rsp_cb = p_callback;
+
+ if (p_lcb->link_state == LST_CONNECTED) {
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */
+ l2cu_send_peer_echo_req(p_lcb, NULL, 0);
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_ECHO_RSP_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_Echo
+ *
+ * Description Higher layers call this function to send an echo request
+ * with application-specific data.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Echo(BD_ADDR p_bd_addr, BT_HDR* p_data,
+ tL2CA_ECHO_DATA_CB* p_callback) {
+ tL2C_LCB* p_lcb;
+ uint8_t* pp;
+
+ L2CAP_TRACE_API("L2CA_Echo() BDA: %08X%04X",
+ ((p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) +
+ (p_bd_addr[2] << 8) + (p_bd_addr[3])),
+ ((p_bd_addr[4] << 8) + (p_bd_addr[5])));
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) return (false);
+
+ if ((memcmp(BT_BD_ANY, p_bd_addr, BD_ADDR_LEN) == 0) && (p_data == NULL)) {
+ /* Only register callback without sending message. */
+ l2cb.p_echo_data_cb = p_callback;
+ return true;
+ }
+
+ /* We assume the upper layer will call this function only when the link is
+ * established. */
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CA_Echo ERROR : link not established");
+ return false;
+ }
+
+ if (p_lcb->link_state != LST_CONNECTED) {
+ L2CAP_TRACE_ERROR("L2CA_Echo ERROR : link is not connected");
+ return false;
+ }
+
+ /* Save address of callback */
+ l2cb.p_echo_data_cb = p_callback;
+
+ /* Set the pointer to the beginning of the data */
+ pp = (uint8_t*)(p_data + 1) + p_data->offset;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_BRCM_ID); /* Make sure not using Broadcom ID */
+ l2cu_send_peer_echo_req(p_lcb, pp, p_data->len);
+
+ return (true);
+}
+
+bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle) {
+ tL2C_CCB* control_block = l2cu_find_ccb_by_cid(NULL, lcid);
+ if (!control_block) return false;
+
+ if (rcid) *rcid = control_block->remote_cid;
+ if (handle) *handle = control_block->p_lcb->handle;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection, or for all future connections. The "idle
+ * timeout" is the amount of time that a connection can remain
+ * up with no L2CAP channels on it. A timeout of zero means
+ * that the connection will be torn down immediately when the
+ * last channel is removed. A timeout of 0xFFFF means no
+ * timeout. Values are in seconds.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This timeout takes effect after at least 1 channel has been
+ * established and removed. L2CAP maintains its own timer from
+ * whan a connection is established till the first channel is
+ * set up.
+ ******************************************************************************/
+bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global) {
+ tL2C_CCB* p_ccb;
+ tL2C_LCB* p_lcb;
+
+ if (is_global) {
+ l2cb.idle_timeout = timeout;
+ } else {
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetIdleTimeout, CID: %d",
+ cid);
+ return (false);
+ }
+
+ p_lcb = p_ccb->p_lcb;
+
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED))
+ p_lcb->idle_timeout = timeout;
+ else
+ return (false);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeoutByBdAddr
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection. The "idle timeout" is the amount of time that
+ * a connection can remain up with no L2CAP channels on it.
+ * A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+ * then the idle timeouts for all active l2cap links will be
+ * changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This timeout applies to all logical channels active on the
+ * ACL link.
+ ******************************************************************************/
+bool L2CA_SetIdleTimeoutByBdAddr(BD_ADDR bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ tL2C_LCB* p_lcb;
+
+ if (memcmp(BT_BD_ANY, bd_addr, BD_ADDR_LEN)) {
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, transport);
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) {
+ p_lcb->idle_timeout = timeout;
+
+ if (!p_lcb->ccb_queue.p_first_ccb) l2cu_no_dynamic_ccbs(p_lcb);
+ } else
+ return false;
+ } else {
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) {
+ p_lcb->idle_timeout = timeout;
+
+ if (!p_lcb->ccb_queue.p_first_ccb) l2cu_no_dynamic_ccbs(p_lcb);
+ }
+ }
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTraceLevel
+ *
+ * Description This function sets the trace level for L2CAP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) l2cb.l2cap_trace_level = new_level;
+
+ return (l2cb.l2cap_trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetDesireRole
+ *
+ * Description This function sets the desire role for L2CAP.
+ * If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+ * HciCreateConnection.
+ * If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow
+ * switch on HciCreateConnection.
+ *
+ * If the new role is a valid role (HCI_ROLE_MASTER or
+ * HCI_ROLE_SLAVE), the desire role is set to the new value.
+ * Otherwise, it is not changed.
+ *
+ * Returns the new (current) role
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetDesireRole(uint8_t new_role) {
+ L2CAP_TRACE_API("L2CA_SetDesireRole() new:x%x, disallow_switch:%d", new_role,
+ l2cb.disallow_switch);
+
+ if (L2CAP_ROLE_CHECK_SWITCH != (L2CAP_ROLE_CHECK_SWITCH & new_role)) {
+ /* do not process the allow_switch when both bits are set */
+ if (new_role & L2CAP_ROLE_ALLOW_SWITCH) {
+ l2cb.disallow_switch = false;
+ }
+ if (new_role & L2CAP_ROLE_DISALLOW_SWITCH) {
+ l2cb.disallow_switch = true;
+ }
+ }
+
+ if (new_role == HCI_ROLE_MASTER || new_role == HCI_ROLE_SLAVE)
+ l2cb.desire_role = new_role;
+
+ return (l2cb.desire_role);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_LocalLoopbackReq
+ *
+ * Description This function sets up a CID for local loopback
+ *
+ * Returns CID of 0 if none.
+ *
+ ******************************************************************************/
+uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+ BD_ADDR p_bd_addr) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_API("L2CA_LocalLoopbackReq() PSM: %d Handle: 0x%04x", psm,
+ handle);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("L2CAP loop req - BTU not ready");
+ return (0);
+ }
+
+ /* Fail if the PSM is not registered */
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_conn_req, PSM: %d", psm);
+ return (0);
+ }
+
+ p_lcb = l2cu_allocate_lcb(p_bd_addr, false, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_conn_req");
+ return (0);
+ }
+
+ p_lcb->link_state = LST_CONNECTED;
+ p_lcb->handle = handle;
+
+ /* Allocate a channel control block */
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_conn_req");
+ return (0);
+ }
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+ p_ccb->chnl_state = CST_OPEN;
+ p_ccb->remote_cid = p_ccb->local_cid;
+ p_ccb->config_done = CFG_DONE_MASK;
+
+ /* Return the local CID as our handle */
+ return (p_ccb->local_cid);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetAclPriority
+ *
+ * Description Sets the transmission priority for a channel.
+ * (For initial implementation only two values are valid.
+ * L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetAclPriority(BD_ADDR bd_addr, uint8_t priority) {
+ L2CAP_TRACE_API(
+ "L2CA_SetAclPriority() bdaddr: %02x%02x%02x%02x%04x, priority:%d",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], priority);
+
+ return (l2cu_set_acl_priority(bd_addr, priority, false));
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlowControl
+ *
+ * Description Higher layers call this function to flow control a channel.
+ *
+ * data_enabled - true data flows, false data is stopped
+ *
+ * Returns true if valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_FlowControl(uint16_t cid, bool data_enabled) {
+ tL2C_CCB* p_ccb;
+ bool on_off = !data_enabled;
+
+ L2CAP_TRACE_API("L2CA_FlowControl(%d) CID: 0x%04x", on_off, cid);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - no CCB for L2CA_FlowControl, CID: 0x%04x data_enabled: %d",
+ cid, data_enabled);
+ return (false);
+ }
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) {
+ L2CAP_TRACE_EVENT("L2CA_FlowControl() invalid mode:%d",
+ p_ccb->peer_cfg.fcr.mode);
+ return (false);
+ }
+ if (p_ccb->fcrb.local_busy != on_off) {
+ p_ccb->fcrb.local_busy = on_off;
+
+ if ((p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack)) {
+ if (on_off)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+ }
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendTestSFrame
+ *
+ * Description Higher layers call this function to send a test S-frame.
+ *
+ * Returns true if valid Channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type, uint8_t back_track) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_SendTestSFrame() CID: 0x%04x Type: 0x%02x back_track: %u", cid,
+ sup_type, back_track);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SendTestSFrame, CID: %d", cid);
+ return (false);
+ }
+
+ if ((p_ccb->chnl_state != CST_OPEN) ||
+ (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE))
+ return (false);
+
+ p_ccb->fcrb.next_seq_expected -= back_track;
+
+ l2c_fcr_send_S_frame(
+ p_ccb, (uint16_t)(sup_type & 3),
+ (uint16_t)(sup_type & (L2CAP_FCR_P_BIT | L2CAP_FCR_F_BIT)));
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTxPriority
+ *
+ * Description Sets the transmission priority for a channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid,
+ priority);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetTxPriority, CID: %d", cid);
+ return (false);
+ }
+
+ /* it will update the order of CCB in LCB by priority and update round robin
+ * service variables */
+ l2cu_change_pri_ccb(p_ccb, priority);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlDataRate
+ *
+ * Description Sets the tx/rx data rate for a channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
+ tL2CAP_CHNL_DATA_RATE rx) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API("L2CA_SetChnlDataRate() CID: 0x%04x, tx:%d, rx:%d", cid, tx,
+ rx);
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetChnlDataRate, CID: %d",
+ cid);
+ return (false);
+ }
+
+ p_ccb->tx_data_rate = tx;
+ p_ccb->rx_data_rate = rx;
+
+ /* Adjust channel buffer allocation */
+ l2c_link_adjust_chnl_allocation();
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFlushTimeout
+ *
+ * Description This function set the automatic flush time out in Baseband
+ * for ACL-U packets.
+ * BdAddr : the remote BD address of ACL link. If it is
+ * BT_DB_ANY then the flush time out will be applied to
+ * all ACL links.
+ * FlushTimeout: flush time out in ms
+ * 0x0000 : No automatic flush
+ * L2CAP_NO_RETRANSMISSION : No retransmission
+ * 0x0002 - 0xFFFE : flush time out, if
+ * (flush_tout * 8) + 3 / 5) <=
+ * HCI_MAX_AUTO_FLUSH_TOUT
+ * (in 625us slot).
+ * Otherwise, return false.
+ * L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This flush timeout applies to all logical channels active on
+ * the ACL link.
+ ******************************************************************************/
+bool L2CA_SetFlushTimeout(BD_ADDR bd_addr, uint16_t flush_tout) {
+ tL2C_LCB* p_lcb;
+ uint16_t hci_flush_to;
+ uint32_t temp;
+
+ /* no automatic flush (infinite timeout) */
+ if (flush_tout == 0x0000) {
+ hci_flush_to = flush_tout;
+ flush_tout = L2CAP_NO_AUTOMATIC_FLUSH;
+ }
+ /* no retransmission */
+ else if (flush_tout == L2CAP_NO_RETRANSMISSION) {
+ /* not mandatory range for controller */
+ /* Packet is flushed before getting any ACK/NACK */
+ /* To do this, flush timeout should be 1 baseband slot */
+ hci_flush_to = flush_tout;
+ }
+ /* no automatic flush (infinite timeout) */
+ else if (flush_tout == L2CAP_NO_AUTOMATIC_FLUSH) {
+ hci_flush_to = 0x0000;
+ } else {
+ /* convert L2CAP flush_to to 0.625 ms units, with round */
+ temp = (((uint32_t)flush_tout * 8) + 3) / 5;
+
+ /* if L2CAP flush_to within range of HCI, set HCI flush timeout */
+ if (temp > HCI_MAX_AUTO_FLUSH_TOUT) {
+ L2CAP_TRACE_WARNING(
+ "WARNING L2CA_SetFlushTimeout timeout(0x%x) is out of range",
+ flush_tout);
+ return false;
+ } else {
+ hci_flush_to = (uint16_t)temp;
+ }
+ }
+
+ if (memcmp(BT_BD_ANY, bd_addr, BD_ADDR_LEN)) {
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ if ((p_lcb) && (p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) {
+ if (p_lcb->link_flush_tout != flush_tout) {
+ p_lcb->link_flush_tout = flush_tout;
+
+ L2CAP_TRACE_API(
+ "L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+ flush_tout, bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to);
+ }
+ } else {
+ L2CAP_TRACE_WARNING(
+ "WARNING L2CA_SetFlushTimeout No lcb for bd_addr [...;%02x%02x%02x]",
+ bd_addr[3], bd_addr[4], bd_addr[5]);
+ return (false);
+ }
+ } else {
+ int xx;
+ p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTED)) {
+ if (p_lcb->link_flush_tout != flush_tout) {
+ p_lcb->link_flush_tout = flush_tout;
+
+ L2CAP_TRACE_API(
+ "L2CA_SetFlushTimeout 0x%04x ms for bd_addr [...;%02x%02x%02x]",
+ flush_tout, p_lcb->remote_bd_addr[3], p_lcb->remote_bd_addr[4],
+ p_lcb->remote_bd_addr[5]);
+
+ btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to);
+ }
+ }
+ }
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerFeatures
+ *
+ * Description Get a peers features and fixed channel map
+ *
+ * Parameters: BD address of the peer
+ * Pointers to features and channel mask storage area
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerFeatures(BD_ADDR bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ tL2C_LCB* p_lcb;
+
+ /* We must already have a link to the remote */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CA_GetPeerFeatures() No BDA: %08x%04x",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) +
+ (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5]);
+ return (false);
+ }
+
+ L2CAP_TRACE_API(
+ "L2CA_GetPeerFeatures() BDA: %08x%04x ExtFea: 0x%08x Chnl_Mask[0]: "
+ "0x%02x",
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], p_lcb->peer_ext_fea,
+ p_lcb->peer_chnl_mask[0]);
+
+ *p_ext_feat = p_lcb->peer_ext_fea;
+
+ memcpy(p_chnl_mask, p_lcb->peer_chnl_mask, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBDAddrbyHandle
+ *
+ * Description Get BD address for the given HCI handle
+ *
+ * Parameters: HCI handle
+ * BD address of the peer
+ *
+ * Return value: true if found lcb for the given handle, false otherwise
+ *
+ ******************************************************************************/
+bool L2CA_GetBDAddrbyHandle(uint16_t handle, BD_ADDR bd_addr) {
+ tL2C_LCB* p_lcb = NULL;
+ bool found_dev = false;
+
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+ if (p_lcb) {
+ found_dev = true;
+ memcpy(bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ }
+
+ return found_dev;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetChnlFcrMode
+ *
+ * Description Get the channel FCR mode
+ *
+ * Parameters: Local CID
+ *
+ * Return value: Channel mode
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetChnlFcrMode(uint16_t lcid) {
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+ if (p_ccb) {
+ L2CAP_TRACE_API("L2CA_GetChnlFcrMode() returns mode %d",
+ p_ccb->peer_cfg.fcr.mode);
+ return (p_ccb->peer_cfg.fcr.mode);
+ }
+
+ L2CAP_TRACE_API("L2CA_GetChnlFcrMode() returns mode L2CAP_FCR_BASIC_MODE");
+ return (L2CAP_FCR_BASIC_MODE);
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterFixedChannel
+ *
+ * Description Register a fixed channel.
+ *
+ * Parameters: Fixed Channel #
+ * Channel Callbacks and config
+ *
+ * Return value: -
+ *
+ ******************************************************************************/
+bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg) {
+ if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
+ (fixed_cid > L2CAP_LAST_FIXED_CHNL)) {
+ L2CAP_TRACE_ERROR("L2CA_RegisterFixedChannel() Invalid CID: 0x%04x",
+ fixed_cid);
+
+ return (false);
+ }
+
+ l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = *p_freg;
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectFixedChnl
+ *
+ * Description Connect an fixed signalling channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ *
+ * Return value: true if connection started
+ *
+ ******************************************************************************/
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, BD_ADDR rem_bda) {
+ uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
+ return L2CA_ConnectFixedChnl(fixed_cid, rem_bda, phy);
+}
+
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, BD_ADDR rem_bda,
+ uint8_t initiating_phys) {
+ tL2C_LCB* p_lcb;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ L2CAP_TRACE_API(
+ "%s() CID: 0x%04x BDA: %08x%04x", __func__, fixed_cid,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ // Check CID is valid and registered
+ if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
+ (fixed_cid > L2CAP_LAST_FIXED_CHNL) ||
+ (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb ==
+ NULL)) {
+ L2CAP_TRACE_ERROR("%s() Invalid CID: 0x%04x", __func__, fixed_cid);
+ return (false);
+ }
+
+ // Fail if BT is not yet up
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("%s(0x%04x) - BTU not ready", __func__, fixed_cid);
+ return (false);
+ }
+
+ if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+ transport = BT_TRANSPORT_LE;
+
+ tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask;
+
+ // If we already have a link to the remote, check if it supports that CID
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, transport);
+ if (p_lcb != NULL) {
+ // Fixed channels are mandatory on LE transports so ignore the received
+ // channel mask and use the locally cached LE channel mask.
+
+ if (transport == BT_TRANSPORT_LE)
+ peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask;
+ else
+ peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+ // Check for supported channel
+ if (!(peer_channel_mask & (1 << fixed_cid))) {
+ L2CAP_TRACE_EVENT("%s() CID:0x%04x BDA: %08x%04x not supported",
+ __func__, fixed_cid,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return false;
+ }
+
+ // Get a CCB and link the lcb to it
+ if (!l2cu_initialize_fixed_ccb(
+ p_lcb, fixed_cid,
+ &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ L2CAP_TRACE_WARNING("%s(0x%04x) - LCB but no CCB", __func__, fixed_cid);
+ return false;
+ }
+
+ // racing with disconnecting, queue the connection request
+ if (p_lcb->link_state == LST_DISCONNECTING) {
+ L2CAP_TRACE_DEBUG("$s() - link disconnecting: RETRY LATER", __func__);
+ /* Save ccb so it can be started after disconnect is finished */
+ p_lcb->p_pending_ccb =
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+ return true;
+ }
+
+ (*l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedConn_Cb)(
+ fixed_cid, p_lcb->remote_bd_addr, true, 0, p_lcb->transport);
+ return true;
+ }
+
+ // No link. Get an LCB and start link establishment
+ p_lcb = l2cu_allocate_lcb(rem_bda, false, transport);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("%s(0x%04x) - no LCB", __func__, fixed_cid);
+ return false;
+ }
+
+ // Get a CCB and link the lcb to it
+ if (!l2cu_initialize_fixed_ccb(
+ p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ p_lcb->disc_reason = L2CAP_CONN_NO_RESOURCES;
+ L2CAP_TRACE_WARNING("%s(0x%04x) - no CCB", __func__, fixed_cid);
+ l2cu_release_lcb(p_lcb);
+ return false;
+ }
+
+ if (!l2cu_create_conn(p_lcb, transport, initiating_phys)) {
+ L2CAP_TRACE_WARNING("%s() - create_conn failed", __func__);
+ l2cu_release_lcb(p_lcb);
+ return false;
+ }
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendFixedChnlData
+ *
+ * Description Write data on a fixed channel.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, BD_ADDR rem_bda,
+ BT_HDR* p_buf) {
+ tL2C_LCB* p_lcb;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ L2CAP_TRACE_API(
+ "L2CA_SendFixedChnlData() CID: 0x%04x BDA: %08x%04x", fixed_cid,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+ transport = BT_TRANSPORT_LE;
+
+ // Check CID is valid and registered
+ if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
+ (fixed_cid > L2CAP_LAST_FIXED_CHNL) ||
+ (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb ==
+ NULL)) {
+ L2CAP_TRACE_ERROR("L2CA_SendFixedChnlData() Invalid CID: 0x%04x",
+ fixed_cid);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ // Fail if BT is not yet up
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("L2CA_SendFixedChnlData(0x%04x) - BTU not ready",
+ fixed_cid);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ // We need to have a link up
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, transport);
+ if (p_lcb == NULL || p_lcb->link_state == LST_DISCONNECTING) {
+ /* if link is disconnecting, also report data sending failure */
+ L2CAP_TRACE_WARNING("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ tL2C_BLE_FIXED_CHNLS_MASK peer_channel_mask;
+
+ // Select peer channels mask to use depending on transport
+ if (transport == BT_TRANSPORT_LE)
+ peer_channel_mask = l2cb.l2c_ble_fixed_chnls_mask;
+ else
+ peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+ if ((peer_channel_mask & (1 << fixed_cid)) == 0) {
+ L2CAP_TRACE_WARNING(
+ "L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x",
+ fixed_cid);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ p_buf->event = 0;
+ p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED;
+
+ if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) {
+ if (!l2cu_initialize_fixed_ccb(
+ p_lcb, fixed_cid,
+ &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ L2CAP_TRACE_WARNING("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x",
+ fixed_cid);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+ }
+
+ // If already congested, do not accept any more packets
+ if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent) {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - CID: 0x%04x cannot send, already congested \
+ xmit_hold_q.count: %u buff_quota: %u",
+ fixed_cid, fixed_queue_length(
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]
+ ->xmit_hold_q),
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ l2c_enqueue_peer_data(p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL],
+ p_buf);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+
+ // If there is no dynamic CCB on the link, restart the idle timer each time
+ // something is sent
+ if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED &&
+ !p_lcb->ccb_queue.p_first_ccb) {
+ l2cu_no_dynamic_ccbs(p_lcb);
+ }
+
+ if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
+ return (L2CAP_DW_CONGESTED);
+
+ return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_RemoveFixedChnl
+ *
+ * Description Remove a fixed channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Idle timeout to use (or 0xFFFF if don't care)
+ *
+ * Return value: true if channel removed
+ *
+ ******************************************************************************/
+bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, BD_ADDR rem_bda) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ /* Check CID is valid and registered */
+ if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
+ (fixed_cid > L2CAP_LAST_FIXED_CHNL) ||
+ (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb ==
+ NULL)) {
+ L2CAP_TRACE_ERROR("L2CA_RemoveFixedChnl() Invalid CID: 0x%04x", fixed_cid);
+ return (false);
+ }
+
+ if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+ transport = BT_TRANSPORT_LE;
+
+ /* Is a fixed channel connected to the remote BDA ?*/
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, transport);
+
+ if (((p_lcb) == NULL) ||
+ (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])) {
+ L2CAP_TRACE_WARNING(
+ "L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected",
+ fixed_cid, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) +
+ rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (false);
+ }
+
+ L2CAP_TRACE_API(
+ "L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x", fixed_cid,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ /* Release the CCB, starting an inactivity timeout on the LCB if no other CCBs
+ * exist */
+ p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = NULL;
+ p_lcb->disc_reason = HCI_ERR_CONN_CAUSE_LOCAL_HOST;
+
+ // Retain the link for a few more seconds after SMP pairing is done, since
+ // the Android platform always does service discovery after pairing is
+ // complete. This will avoid the link down (pairing is complete) and an
+ // immediate re-connection for service discovery.
+ // Some devices do not do auto advertising when link is dropped, thus fail
+ // the second connection and service discovery.
+ if ((fixed_cid == L2CAP_ATT_CID) && !p_lcb->ccb_queue.p_first_ccb)
+ p_lcb->idle_timeout = 0;
+
+ l2cu_release_ccb(p_ccb);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFixedChannelTout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a fixed channel. The "idle timeout" is the amount of time
+ * that a connection can remain up with no L2CAP channels on
+ * it. A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr = BT_BD_ANY,
+ * then the idle timeouts for all active l2cap links will be
+ * changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+bool L2CA_SetFixedChannelTout(BD_ADDR rem_bda, uint16_t fixed_cid,
+ uint16_t idle_tout) {
+ tL2C_LCB* p_lcb;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+ transport = BT_TRANSPORT_LE;
+
+ /* Is a fixed channel connected to the remote BDA ?*/
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, transport);
+ if (((p_lcb) == NULL) ||
+ (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])) {
+ L2CAP_TRACE_WARNING(
+ "L2CA_SetFixedChannelTout() CID: 0x%04x BDA: %08x%04x not connected",
+ fixed_cid, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) +
+ rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (false);
+ }
+
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]
+ ->fixed_chnl_idle_tout = idle_tout;
+
+ if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED &&
+ !p_lcb->ccb_queue.p_first_ccb) {
+ /* If there are no dynamic CCBs, (re)start the idle timer in case we changed
+ * it */
+ l2cu_no_dynamic_ccbs(p_lcb);
+ }
+
+ return true;
+}
+
+#endif /* #if (L2CAP_NUM_FIXED_CHNLS > 0) */
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetCurrentConfig
+ *
+ * Description This function returns configurations of L2CAP channel
+ * pp_our_cfg : pointer of our saved configuration options
+ * p_our_cfg_bits : valid config in bitmap
+ * pp_peer_cfg: pointer of peer's saved configuration options
+ * p_peer_cfg_bits : valid config in bitmap
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetCurrentConfig(uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+ tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
+ tL2CAP_CFG_INFO** pp_peer_cfg,
+ tL2CAP_CH_CFG_BITS* p_peer_cfg_bits) {
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API("L2CA_GetCurrentConfig() CID: 0x%04x", lcid);
+
+ p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+ if (p_ccb) {
+ *pp_our_cfg = &(p_ccb->our_cfg);
+
+ /* convert valid config items into bitmap */
+ *p_our_cfg_bits = 0;
+ if (p_ccb->our_cfg.mtu_present) *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+ if (p_ccb->our_cfg.qos_present) *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+ if (p_ccb->our_cfg.flush_to_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+ if (p_ccb->our_cfg.fcr_present) *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+ if (p_ccb->our_cfg.fcs_present) *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+ if (p_ccb->our_cfg.ext_flow_spec_present)
+ *p_our_cfg_bits |= L2CAP_CH_CFG_MASK_EXT_FLOW_SPEC;
+
+ *pp_peer_cfg = &(p_ccb->peer_cfg);
+ *p_peer_cfg_bits = p_ccb->peer_cfg_bits;
+
+ return true;
+ } else {
+ L2CAP_TRACE_ERROR("No CCB for CID:0x%04x", lcid);
+ return false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetConnectionConfig
+ *
+ * Description This function returns configurations of L2CAP channel
+ * pp_l2c_ccb : pointer to this channels L2CAP ccb data.
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu, uint16_t* rcid,
+ uint16_t* handle) {
+ tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+ ;
+
+ L2CAP_TRACE_API("%s CID: 0x%04x", __func__, lcid);
+
+ if (p_ccb) {
+ *mtu = L2CAP_MTU_SIZE;
+ if (p_ccb->our_cfg.mtu_present) *mtu = p_ccb->our_cfg.mtu;
+
+ *rcid = p_ccb->remote_cid;
+ *handle = p_ccb->p_lcb->handle;
+ return true;
+ }
+
+ L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegForNoCPEvt
+ *
+ * Description Register callback for Number of Completed Packets event.
+ *
+ * Input Param p_cb - callback for Number of completed packets event
+ * p_bda - BT address of remote device
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, BD_ADDR p_bda) {
+ tL2C_LCB* p_lcb;
+
+ /* Find the link that is associated with this remote bdaddr */
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, BT_TRANSPORT_BR_EDR);
+
+ /* If no link for this handle, nothing to do. */
+ if (!p_lcb) return false;
+
+ p_lcb->p_nocp_cb = p_cb;
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWrite
+ *
+ * Description Higher layers call this function to write data.
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+ L2CAP_TRACE_API("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len);
+ return l2c_data_write(cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlFlushability
+ *
+ * Description Higher layers call this function to set a channels
+ * flushability flags
+ *
+ * Returns true if CID found, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+
+ tL2C_CCB* p_ccb;
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_SetChnlFlushability, CID: %d",
+ cid);
+ return (false);
+ }
+
+ p_ccb->is_flushable = is_flushable;
+
+ L2CAP_TRACE_API("L2CA_SetChnlFlushability() CID: 0x%04x is_flushable: %d",
+ cid, is_flushable);
+
+#endif
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWriteEx
+ *
+ * Description Higher layers call this function to write data with extended
+ * flags.
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
+ L2CAP_TRACE_API("L2CA_DataWriteEx() CID: 0x%04x Len: %d Flags:0x%04X", cid,
+ p_data->len, flags);
+ return l2c_data_write(cid, p_data, flags);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlushChannel
+ *
+ * Description This function flushes none, some or all buffers queued up
+ * for xmission for a particular CID. If called with
+ * L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+ * of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+ * flushes all buffers. All other values specifies the maximum
+ * buffers to flush.
+ *
+ * Returns Number of buffers left queued for that CID
+ *
+ ******************************************************************************/
+uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
+ tL2C_CCB* p_ccb;
+ tL2C_LCB* p_lcb;
+ uint16_t num_left = 0, num_flushed1 = 0, num_flushed2 = 0;
+
+ p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
+
+ if (!p_ccb || (p_ccb->p_lcb == NULL)) {
+ L2CAP_TRACE_WARNING(
+ "L2CA_FlushChannel() abnormally returning 0 CID: 0x%04x", lcid);
+ return (0);
+ }
+ p_lcb = p_ccb->p_lcb;
+
+ if (num_to_flush != L2CAP_FLUSH_CHANS_GET) {
+ L2CAP_TRACE_API(
+ "L2CA_FlushChannel (FLUSH) CID: 0x%04x NumToFlush: %d QC: %u "
+ "pFirst: 0x%08x",
+ lcid, num_to_flush, fixed_queue_length(p_ccb->xmit_hold_q),
+ fixed_queue_try_peek_first(p_ccb->xmit_hold_q));
+ } else {
+ L2CAP_TRACE_API("L2CA_FlushChannel (QUERY) CID: 0x%04x", lcid);
+ }
+
+ /* Cannot flush eRTM buffers once they have a sequence number */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE) {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if (num_to_flush != L2CAP_FLUSH_CHANS_GET) {
+ /* If the controller supports enhanced flush, flush the data queued at the
+ * controller */
+ if ((HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures())) &&
+ (BTM_GetNumScoLinks() == 0)) {
+ if (l2cb.is_flush_active == false) {
+ l2cb.is_flush_active = true;
+
+ /* The only packet type defined - 0 - Automatically-Flushable Only */
+ btsnd_hcic_enhanced_flush(p_lcb->handle, 0);
+ }
+ }
+ }
+#endif
+
+ // Iterate though list and flush the amount requested from
+ // the transmit data queue that satisfy the layer and event conditions.
+ for (const list_node_t* node = list_begin(p_lcb->link_xmit_data_q);
+ (num_to_flush > 0) && node != list_end(p_lcb->link_xmit_data_q);) {
+ BT_HDR* p_buf = (BT_HDR*)list_node(node);
+ node = list_next(node);
+ if ((p_buf->layer_specific == 0) && (p_buf->event == lcid)) {
+ num_to_flush--;
+ num_flushed1++;
+
+ list_remove(p_lcb->link_xmit_data_q, p_buf);
+ osi_free(p_buf);
+ }
+ }
+ }
+
+ /* If needed, flush buffers in the CCB xmit hold queue */
+ while ((num_to_flush != 0) && (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) {
+ BT_HDR* p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+ osi_free(p_buf);
+ num_to_flush--;
+ num_flushed2++;
+ }
+
+ /* If app needs to track all packets, call him */
+ if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) &&
+ (num_flushed2))
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, num_flushed2);
+
+ /* Now count how many are left */
+ for (const list_node_t* node = list_begin(p_lcb->link_xmit_data_q);
+ node != list_end(p_lcb->link_xmit_data_q); node = list_next(node)) {
+ BT_HDR* p_buf = (BT_HDR*)list_node(node);
+ if (p_buf->event == lcid) num_left++;
+ }
+
+ /* Add in the number in the CCB xmit queue */
+ num_left += fixed_queue_length(p_ccb->xmit_hold_q);
+
+ /* Return the local number of buffers left for the CID */
+ L2CAP_TRACE_DEBUG("L2CA_FlushChannel() flushed: %u + %u, num_left: %u",
+ num_flushed1, num_flushed2, num_left);
+
+ /* If we were congested, and now we are not, tell the app */
+ l2cu_check_channel_congestion(p_ccb);
+
+ return (num_left);
+}
+
+/** M: Bug fix for the connection procedure while link is disconnecting @{ */
+/*******************************************************************************
+**
+** Function L2CA_FixedChnlPending
+**
+** Description This function is to check whether the fixed channel connection request
+** request is pending
+**
+** Returns If the fixed channel connection is pending, return true.
+**
+*******************************************************************************/
+bool L2CA_IsFixedChnlPending(uint16_t fixed_cid, BD_ADDR rem_bda) {
+ tL2C_LCB* p_lcb;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ // Check CID is valid and registered
+ if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
+ (fixed_cid > L2CAP_LAST_FIXED_CHNL) ||
+ (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb ==
+ NULL)) {
+ L2CAP_TRACE_ERROR("%s() Invalid CID: 0x%04x", __func__, fixed_cid);
+ return (false);
+ }
+
+ if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
+ transport = BT_TRANSPORT_LE;
+
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, transport)) != NULL) &&
+ (p_lcb->p_pending_ccb != NULL)) {
+ if (p_lcb->p_pending_ccb ==
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) {
+ L2CAP_TRACE_API(
+ "%s() CID: 0x%04x BDA: %08x%04x, the fixed channel connection is "
+ "pending",
+ __func__, fixed_cid, (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (true);
+ }
+ }
+
+ return (false);
+}
+/** @} */
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_ble.cc b/mtkbt/code/bt/stack/l2cap/l2c_ble.cc
new file mode 100755
index 0000000..8b0ef8a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_ble.cc
@@ -0,0 +1,1480 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains functions relating to BLE management.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+#include "stack_config.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+static void l2cble_start_conn_update(tL2C_LCB* p_lcb);
+
+/*******************************************************************************
+ *
+ * Function L2CA_CancelBleConnectReq
+ *
+ * Description Cancel a pending connection attempt to a BLE device.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if connection was cancelled
+ *
+ ******************************************************************************/
+bool L2CA_CancelBleConnectReq(BD_ADDR rem_bda) {
+ tL2C_LCB* p_lcb;
+
+ /* There can be only one BLE connection request outstanding at a time */
+ if (btm_ble_get_conn_st() == BLE_CONN_IDLE) {
+ L2CAP_TRACE_WARNING("%s - no connection pending", __func__);
+ return (false);
+ }
+
+ if (memcmp(rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN)) {
+ L2CAP_TRACE_WARNING(
+ "%s - different BDA Connecting: %08x%04x Cancel: %08x%04x", __func__,
+ (l2cb.ble_connecting_bda[0] << 24) +
+ (l2cb.ble_connecting_bda[1] << 16) +
+ (l2cb.ble_connecting_bda[2] << 8) + l2cb.ble_connecting_bda[3],
+ (l2cb.ble_connecting_bda[4] << 8) + l2cb.ble_connecting_bda[5],
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) +
+ rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ btm_ble_dequeue_direct_conn_req(rem_bda);
+ return (false);
+ }
+
+ btsnd_hcic_ble_create_conn_cancel();
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
+ /* Do not remove lcb if an LE link is already up as a peripheral */
+ if (p_lcb != NULL &&
+ !(p_lcb->link_role == HCI_ROLE_SLAVE &&
+ btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE) != NULL)) {
+ p_lcb->disc_reason = L2CAP_CONN_CANCEL;
+ l2cu_release_lcb(p_lcb);
+ }
+ /* update state to be cancel, wait for connection cancel complete */
+ btm_ble_set_conn_st(BLE_CONN_CANCEL);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UpdateBleConnParams
+ *
+ * Description Update BLE connection parameters.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+bool L2CA_UpdateBleConnParams(BD_ADDR rem_bda, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout) {
+ tL2C_LCB* p_lcb;
+ tACL_CONN* p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE);
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb || !p_acl_cb) {
+ L2CAP_TRACE_WARNING("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x",
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (false);
+ }
+
+ if (p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE",
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (false);
+ }
+
+ p_lcb->min_interval = min_int;
+ p_lcb->max_interval = max_int;
+ p_lcb->latency = latency;
+ p_lcb->timeout = timeout;
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+
+ l2cble_start_conn_update(p_lcb);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_EnableUpdateBleConnParams
+ *
+ * Description Enable or disable update based on the request from the peer
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+bool L2CA_EnableUpdateBleConnParams(BD_ADDR rem_bda, bool enable) {
+ if (stack_config_get_interface()->get_pts_conn_updates_disabled())
+ return false;
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_LE_DISABLE_FAST_CONNECTION,
+ (const bt_bdaddr_t*)rem_bda))
+ return false;
+#endif
+
+ tL2C_LCB* p_lcb;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE);
+
+ if (!p_lcb) {
+ L2CAP_TRACE_WARNING(
+ "L2CA_EnableUpdateBleConnParams - unknown BD_ADDR %08x%04x",
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) +
+ rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+ return (false);
+ }
+
+ L2CAP_TRACE_API(
+ "%s - BD_ADDR %08x%04x enable %d current upd state 0x%02x", __func__,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5], enable, p_lcb->conn_update_mask);
+
+ if (p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("%s - BD_ADDR %08x%04x not LE (link role %d)", __func__,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5], p_lcb->link_role);
+ return (false);
+ }
+
+ if (enable)
+ p_lcb->conn_update_mask &= ~L2C_BLE_CONN_UPDATE_DISABLE;
+ else
+ p_lcb->conn_update_mask |= L2C_BLE_CONN_UPDATE_DISABLE;
+
+ l2cble_start_conn_update(p_lcb);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBleConnRole
+ *
+ * Description This function returns the connection role.
+ *
+ * Returns link role.
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetBleConnRole(BD_ADDR bd_addr) {
+ uint8_t role = HCI_ROLE_UNKNOWN;
+
+ tL2C_LCB* p_lcb;
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+ if (p_lcb != NULL) role = p_lcb->link_role;
+
+ return role;
+}
+/*******************************************************************************
+ *
+ * Function L2CA_GetDisconnectReason
+ *
+ * Description This function returns the disconnect reason code.
+ *
+ * Returns disconnect reason
+ *
+ ******************************************************************************/
+uint16_t L2CA_GetDisconnectReason(BD_ADDR remote_bda, tBT_TRANSPORT transport) {
+ tL2C_LCB* p_lcb;
+ uint16_t reason = 0;
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, transport);
+ if (p_lcb != NULL) reason = p_lcb->disc_reason;
+
+ L2CAP_TRACE_DEBUG("L2CA_GetDisconnectReason=%d ", reason);
+
+ return reason;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_notify_le_connection
+ *
+ * Description This function notifiy the l2cap connection to the app layer
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void l2cble_notify_le_connection(BD_ADDR bda) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+ tACL_CONN* p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
+ tL2C_CCB* p_ccb;
+
+ if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED) {
+ /* update link status */
+ btm_establish_continue(p_acl);
+ /* update l2cap link status and send callback */
+ p_lcb->link_state = LST_CONNECTED;
+ l2cu_process_fixed_chnl_resp(p_lcb);
+ }
+
+ if (p_lcb != NULL) {
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ if (p_ccb->chnl_state == CST_CLOSED)
+ l2c_csm_execute(p_ccb, L2CEVT_LP_CONNECT_CFM, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_scanner_conn_comp
+ *
+ * Description This function is called when an HCI Connection Complete
+ * event is received while we are a scanner (so we are master).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_scanner_conn_comp(uint16_t handle, BD_ADDR bda, tBLE_ADDR_TYPE type,
+ uint16_t conn_interval, uint16_t conn_latency,
+ uint16_t conn_timeout) {
+ tL2C_LCB* p_lcb;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
+
+ L2CAP_TRACE_DEBUG(
+ "l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d "
+ "slave_latency=%d supervision_tout=%d",
+ handle, type, conn_interval, conn_latency, conn_timeout);
+
+ l2cb.is_ble_connecting = false;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+
+ /* If we don't have one, create one. this is auto connection complete. */
+ if (!p_lcb) {
+ p_lcb = l2cu_allocate_lcb(bda, false, BT_TRANSPORT_LE);
+ if (!p_lcb) {
+ btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_ERROR("l2cble_scanner_conn_comp - failed to allocate LCB");
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ return;
+ } else {
+ if (!l2cu_initialize_fixed_ccb(
+ p_lcb, L2CAP_ATT_CID,
+ &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_WARNING("l2cble_scanner_conn_comp - LCB but no CCB");
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ return;
+ }
+ }
+ } else if (p_lcb->link_state != LST_CONNECTING) {
+ L2CAP_TRACE_ERROR("L2CAP got BLE scanner conn_comp in bad state: %d",
+ p_lcb->link_state);
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+ return;
+ }
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ /* Connected OK. Change state to connected, we were scanning so we are master
+ */
+ p_lcb->link_role = HCI_ROLE_MASTER;
+ p_lcb->transport = BT_TRANSPORT_LE;
+
+ /* update link parameter, set slave link as non-spec default upon link up */
+ p_lcb->min_interval = p_lcb->max_interval = conn_interval;
+ p_lcb->timeout = conn_timeout;
+ p_lcb->latency = conn_latency;
+ p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
+
+ /* Tell BTM Acl management about the link */
+ btm_acl_created(bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role,
+ BT_TRANSPORT_LE);
+
+ p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT |
+ L2CAP_FIXED_CHNL_BLE_SIG_BIT |
+ L2CAP_FIXED_CHNL_SMP_BIT;
+
+ btm_ble_set_conn_st(BLE_CONN_IDLE);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_advertiser_conn_comp
+ *
+ * Description This function is called when an HCI Connection Complete
+ * event is received while we are an advertiser (so we are
+ * slave).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_advertiser_conn_comp(uint16_t handle, BD_ADDR bda,
+ UNUSED_ATTR tBLE_ADDR_TYPE type,
+ UNUSED_ATTR uint16_t conn_interval,
+ UNUSED_ATTR uint16_t conn_latency,
+ UNUSED_ATTR uint16_t conn_timeout) {
+ tL2C_LCB* p_lcb;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bda, BT_TRANSPORT_LE);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb) {
+ p_lcb = l2cu_allocate_lcb(bda, false, BT_TRANSPORT_LE);
+ if (!p_lcb) {
+ btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_ERROR("l2cble_advertiser_conn_comp - failed to allocate LCB");
+ return;
+ } else {
+ if (!l2cu_initialize_fixed_ccb(
+ p_lcb, L2CAP_ATT_CID,
+ &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ btm_sec_disconnect(handle, HCI_ERR_NO_CONNECTION);
+ L2CAP_TRACE_WARNING("l2cble_scanner_conn_comp - LCB but no CCB");
+ return;
+ }
+ }
+ }
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ /* Connected OK. Change state to connected, we were advertising, so we are
+ * slave */
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ p_lcb->transport = BT_TRANSPORT_LE;
+
+ /* update link parameter, set slave link as non-spec default upon link up */
+ p_lcb->min_interval = p_lcb->max_interval = conn_interval;
+ p_lcb->timeout = conn_timeout;
+ p_lcb->latency = conn_latency;
+ p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM;
+
+ /* Tell BTM Acl management about the link */
+ p_dev_rec = btm_find_or_alloc_dev(bda);
+
+ btm_acl_created(bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role,
+ BT_TRANSPORT_LE);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
+#endif
+
+ p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT |
+ L2CAP_FIXED_CHNL_BLE_SIG_BIT |
+ L2CAP_FIXED_CHNL_SMP_BIT;
+
+ if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(
+ controller_get_interface()->get_features_ble()->as_array)) {
+ p_lcb->link_state = LST_CONNECTED;
+ l2cu_process_fixed_chnl_resp(p_lcb);
+ }
+
+ /* when adv and initiating are both active, cancel the direct connection */
+ if (l2cb.is_ble_connecting &&
+ memcmp(bda, l2cb.ble_connecting_bda, BD_ADDR_LEN) == 0) {
+ L2CA_CancelBleConnectReq(bda);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_conn_comp
+ *
+ * Description This function is called when an HCI Connection Complete
+ * event is received.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_conn_comp(uint16_t handle, uint8_t role, BD_ADDR bda,
+ tBLE_ADDR_TYPE type, uint16_t conn_interval,
+ uint16_t conn_latency, uint16_t conn_timeout) {
+ btm_ble_update_link_topology_mask(role, true);
+
+ if (role == HCI_ROLE_MASTER) {
+ l2cble_scanner_conn_comp(handle, bda, type, conn_interval, conn_latency,
+ conn_timeout);
+ } else {
+ l2cble_advertiser_conn_comp(handle, bda, type, conn_interval, conn_latency,
+ conn_timeout);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_start_conn_update
+ *
+ * Description Start the BLE connection parameter update process based on
+ * status.
+ *
+ * Parameters: lcb : l2cap link control block
+ *
+ * Return value: none
+ *
+ ******************************************************************************/
+static void l2cble_start_conn_update(tL2C_LCB* p_lcb) {
+ uint16_t min_conn_int, max_conn_int, slave_latency, supervision_tout;
+ tACL_CONN* p_acl_cb = btm_bda_to_acl(p_lcb->remote_bd_addr, BT_TRANSPORT_LE);
+
+ // TODO(armansito): The return value of this call wasn't being used but the
+ // logic of this function might be depending on its side effects. We should
+ // verify if this call is needed at all and remove it otherwise.
+ btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
+
+ if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) return;
+
+ if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) {
+ /* application requests to disable parameters update.
+ If parameters are already updated, lets set them
+ up to what has been requested during connection establishement */
+ if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM &&
+ /* current connection interval is greater than default min */
+ p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) {
+ /* use 7.5 ms as fast connection parameter, 0 slave latency */
+ min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN;
+ slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+ supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF;
+
+ /* if both side 4.1, or we are master device, send HCI command */
+ if (p_lcb->link_role == HCI_ROLE_MASTER
+#if (BLE_LLT_INCLUDED == TRUE)
+ || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(
+ controller_get_interface()->get_features_ble()->as_array) &&
+ HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features))
+#endif
+ ) {
+ btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, min_conn_int,
+ max_conn_int, slave_latency,
+ supervision_tout, 0, 0);
+ p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
+ } else {
+ l2cu_send_peer_ble_par_req(p_lcb, min_conn_int, max_conn_int,
+ slave_latency, supervision_tout);
+ }
+ p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM;
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ }
+ } else {
+ /* application allows to do update, if we were delaying one do it now */
+ if (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM) {
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(
+ INTEROP_MTK_LE_CONN_TIMEOUT_ADJUST,
+ (const bt_bdaddr_t*)&p_lcb->remote_bd_addr)) {
+ p_lcb->timeout = 2000;
+ L2CAP_TRACE_ERROR("change the LE supervision timeout as : %d",
+ p_lcb->timeout);
+ }
+#endif
+
+ /* if both side 4.1, or we are master device, send HCI command */
+ if (p_lcb->link_role == HCI_ROLE_MASTER
+#if (BLE_LLT_INCLUDED == TRUE)
+ || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(
+ controller_get_interface()->get_features_ble()->as_array) &&
+ HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features))
+#endif
+ ) {
+ btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, p_lcb->min_interval,
+ p_lcb->max_interval, p_lcb->latency,
+ p_lcb->timeout, 0, 0);
+ p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING;
+ } else {
+ l2cu_send_peer_ble_par_req(p_lcb, p_lcb->min_interval,
+ p_lcb->max_interval, p_lcb->latency,
+ p_lcb->timeout);
+ }
+ p_lcb->conn_update_mask &= ~L2C_BLE_NEW_CONN_PARAM;
+ p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_process_conn_update_evt
+ *
+ * Description This function enables the connection update request from
+ * remote after a successful connection update response is
+ * received.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout) {
+ L2CAP_TRACE_DEBUG("%s", __func__);
+
+ /* See if we have a link control block for the remote device */
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
+ if (!p_lcb) {
+ L2CAP_TRACE_WARNING("%s: Invalid handle: %d", __func__, handle);
+ return;
+ }
+
+ p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PENDING;
+
+ if (status != HCI_SUCCESS) {
+ L2CAP_TRACE_WARNING("%s: Error status: %d", __func__, status);
+ }
+
+ l2cble_start_conn_update(p_lcb);
+
+ L2CAP_TRACE_DEBUG("%s: conn_update_mask=%d", __func__,
+ p_lcb->conn_update_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_process_sig_cmd
+ *
+ * Description This function is called when a signalling packet is received
+ * on the BLE signalling CID
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
+ uint8_t* p_pkt_end;
+ uint8_t cmd_code, id;
+ uint16_t cmd_len;
+ uint16_t min_interval, max_interval, latency, timeout;
+ tL2C_CONN_INFO con_info;
+ uint16_t lcid = 0, rcid = 0, mtu = 0, mps = 0, initial_credit = 0;
+ tL2C_CCB *p_ccb = NULL, *temp_p_ccb = NULL;
+ tL2C_RCB* p_rcb;
+ uint16_t credit;
+ p_pkt_end = p + pkt_len;
+
+ STREAM_TO_UINT8(cmd_code, p);
+ STREAM_TO_UINT8(id, p);
+ STREAM_TO_UINT16(cmd_len, p);
+
+ /* Check command length does not exceed packet length */
+ if ((p + cmd_len) > p_pkt_end) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - LE - format error, pkt_len: %d cmd_len: %d code: %d",
+ pkt_len, cmd_len, cmd_code);
+ return;
+ }
+
+ switch (cmd_code) {
+ case L2CAP_CMD_REJECT:
+ p += 2;
+ break;
+
+ case L2CAP_CMD_ECHO_REQ:
+ case L2CAP_CMD_ECHO_RSP:
+ case L2CAP_CMD_INFO_RSP:
+ case L2CAP_CMD_INFO_REQ:
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ break;
+
+ case L2CAP_CMD_BLE_UPDATE_REQ:
+ STREAM_TO_UINT16(min_interval, p); /* 0x0006 - 0x0C80 */
+ STREAM_TO_UINT16(max_interval, p); /* 0x0006 - 0x0C80 */
+ STREAM_TO_UINT16(latency, p); /* 0x0000 - 0x03E8 */
+ STREAM_TO_UINT16(timeout, p); /* 0x000A - 0x0C80 */
+ /* If we are a master, the slave wants to update the parameters */
+ if (p_lcb->link_role == HCI_ROLE_MASTER) {
+ if (min_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (!interop_mtk_match_addr_name(
+ INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT,
+ (const bt_bdaddr_t*)&p_lcb->remote_bd_addr))
+#endif
+ min_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+
+ /** M: remove the workaround to reject the request of the conn update
+ parameters stack can not handle @{ */
+ // While this could result in connection parameters that fall
+ // outside fo the range requested, this will allow the connection
+ // to remain established.
+ // In other words, this is a workaround for certain peripherals.
+/*
+ if (max_interval < BTM_BLE_CONN_INT_MIN_LIMIT)
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (!interop_mtk_match_addr_name(
+ INTEROP_MTK_LE_CONN_INT_MIN_LIMIT_ACCEPT,
+ (const bt_bdaddr_t*)&p_lcb->remote_bd_addr))
+#endif
+ max_interval = BTM_BLE_CONN_INT_MIN_LIMIT;
+*/
+ /** @} */
+ if (min_interval < BTM_BLE_CONN_INT_MIN ||
+ min_interval > BTM_BLE_CONN_INT_MAX ||
+ max_interval < BTM_BLE_CONN_INT_MIN ||
+ max_interval > BTM_BLE_CONN_INT_MAX ||
+ latency > BTM_BLE_CONN_LATENCY_MAX ||
+ /*(timeout >= max_interval && latency > (timeout * 10/(max_interval
+ * 1.25) - 1)) ||*/
+ timeout < BTM_BLE_CONN_SUP_TOUT_MIN ||
+ timeout > BTM_BLE_CONN_SUP_TOUT_MAX ||
+ max_interval < min_interval) {
+ l2cu_send_peer_ble_par_rsp(p_lcb, L2CAP_CFG_UNACCEPTABLE_PARAMS, id);
+ } else {
+ l2cu_send_peer_ble_par_rsp(p_lcb, L2CAP_CFG_OK, id);
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(
+ INTEROP_MTK_LE_CONN_LATENCY_ADJUST,
+ (const bt_bdaddr_t*)&p_lcb->remote_bd_addr))
+ latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF;
+#endif
+
+ p_lcb->min_interval = min_interval;
+ p_lcb->max_interval = max_interval;
+ p_lcb->latency = latency;
+ p_lcb->timeout = timeout;
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+
+ l2cble_start_conn_update(p_lcb);
+ }
+ } else
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0,
+ 0);
+ break;
+
+ case L2CAP_CMD_BLE_UPDATE_RSP:
+ p += 2;
+ break;
+
+ case L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ:
+ STREAM_TO_UINT16(con_info.psm, p);
+ STREAM_TO_UINT16(rcid, p);
+ STREAM_TO_UINT16(mtu, p);
+ STREAM_TO_UINT16(mps, p);
+ STREAM_TO_UINT16(initial_credit, p);
+
+ L2CAP_TRACE_DEBUG(
+ "Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ with "
+ "mtu = %d, "
+ "mps = %d, "
+ "initial credit = %d",
+ mtu, mps, initial_credit);
+
+ p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, rcid);
+ if (p_ccb) {
+ L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for duplicated cid: 0x%04x",
+ rcid);
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED);
+ break;
+ }
+
+ p_rcb = l2cu_find_ble_rcb_by_psm(con_info.psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: 0x%04x",
+ con_info.psm);
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_NO_PSM);
+ break;
+ } else {
+ if (!p_rcb->api.pL2CA_ConnectInd_Cb) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - rcvd conn req for outgoing-only connection PSM: %d",
+ con_info.psm);
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_CONN_NO_PSM);
+ break;
+ }
+ }
+
+ /* Allocate a ccb for this.*/
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - unable to allocate CCB");
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_CONN_NO_RESOURCES);
+ break;
+ }
+
+ /* validate the parameters */
+ if (mtu < L2CAP_LE_MIN_MTU || mps < L2CAP_LE_MIN_MPS ||
+ mps > L2CAP_LE_MAX_MPS) {
+ L2CAP_TRACE_ERROR("L2CAP don't like the params");
+ l2cu_reject_ble_connection(p_lcb, id, L2CAP_CONN_NO_RESOURCES);
+ break;
+ }
+
+ p_ccb->remote_id = id;
+ p_ccb->p_rcb = p_rcb;
+ p_ccb->remote_cid = rcid;
+
+ p_ccb->peer_conn_cfg.mtu = mtu;
+ p_ccb->peer_conn_cfg.mps = mps;
+ p_ccb->peer_conn_cfg.credits = initial_credit;
+
+ p_ccb->tx_mps = mps;
+ p_ccb->ble_sdu = NULL;
+ p_ccb->ble_sdu_length = 0;
+ p_ccb->is_first_seg = true;
+ p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
+ break;
+
+ case L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES:
+ L2CAP_TRACE_DEBUG("Recv L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES");
+ /* For all channels, see whose identifier matches this id */
+ for (temp_p_ccb = p_lcb->ccb_queue.p_first_ccb; temp_p_ccb;
+ temp_p_ccb = temp_p_ccb->p_next_ccb) {
+ if (temp_p_ccb->local_id == id) {
+ p_ccb = temp_p_ccb;
+ break;
+ }
+ }
+ if (p_ccb) {
+ L2CAP_TRACE_DEBUG("I remember the connection req");
+ STREAM_TO_UINT16(p_ccb->remote_cid, p);
+ STREAM_TO_UINT16(p_ccb->peer_conn_cfg.mtu, p);
+ STREAM_TO_UINT16(p_ccb->peer_conn_cfg.mps, p);
+ STREAM_TO_UINT16(p_ccb->peer_conn_cfg.credits, p);
+ STREAM_TO_UINT16(con_info.l2cap_result, p);
+ con_info.remote_cid = p_ccb->remote_cid;
+
+ L2CAP_TRACE_DEBUG(
+ "remote_cid = %d, "
+ "mtu = %d, "
+ "mps = %d, "
+ "initial_credit = %d, "
+ "con_info.l2cap_result = %d",
+ p_ccb->remote_cid, p_ccb->peer_conn_cfg.mtu,
+ p_ccb->peer_conn_cfg.mps, p_ccb->peer_conn_cfg.credits,
+ con_info.l2cap_result);
+
+ /* validate the parameters */
+ if (p_ccb->peer_conn_cfg.mtu < L2CAP_LE_MIN_MTU ||
+ p_ccb->peer_conn_cfg.mps < L2CAP_LE_MIN_MPS ||
+ p_ccb->peer_conn_cfg.mps > L2CAP_LE_MAX_MPS) {
+ L2CAP_TRACE_ERROR("L2CAP don't like the params");
+ con_info.l2cap_result = L2CAP_LE_NO_RESOURCES;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+ break;
+ }
+
+ p_ccb->tx_mps = p_ccb->peer_conn_cfg.mps;
+ p_ccb->ble_sdu = NULL;
+ p_ccb->ble_sdu_length = 0;
+ p_ccb->is_first_seg = true;
+ p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;
+
+ if (con_info.l2cap_result == L2CAP_LE_CONN_OK)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
+ else
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+ } else {
+ L2CAP_TRACE_DEBUG("I DO NOT remember the connection req");
+ con_info.l2cap_result = L2CAP_LE_INVALID_SOURCE_CID;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+ }
+ break;
+
+ case L2CAP_CMD_BLE_FLOW_CTRL_CREDIT:
+ STREAM_TO_UINT16(lcid, p);
+ p_ccb = l2cu_find_ccb_by_remote_cid(p_lcb, lcid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_DEBUG("%s Credit received for unknown channel id %d",
+ __func__, lcid);
+ break;
+ }
+
+ STREAM_TO_UINT16(credit, p);
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT, &credit);
+ L2CAP_TRACE_DEBUG("%s Credit received", __func__);
+ break;
+
+ case L2CAP_CMD_DISC_REQ:
+ STREAM_TO_UINT16(lcid, p);
+ STREAM_TO_UINT16(rcid, p);
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ if (p_ccb->remote_cid == rcid) {
+ p_ccb->remote_id = id;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, NULL);
+ }
+ } else
+ l2cu_send_peer_disc_rsp(p_lcb, id, lcid, rcid);
+
+ break;
+
+ case L2CAP_CMD_DISC_RSP:
+ STREAM_TO_UINT16(rcid, p);
+ STREAM_TO_UINT16(lcid, p);
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id))
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, NULL);
+ }
+ break;
+
+ default:
+ L2CAP_TRACE_WARNING("L2CAP - LE - unknown cmd code: %d", cmd_code);
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0, 0);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_init_direct_conn
+ *
+ * Description This function is to initate a direct connection
+ *
+ * Returns true connection initiated, false otherwise.
+ *
+ ******************************************************************************/
+bool l2cble_init_direct_conn(tL2C_LCB* p_lcb) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(p_lcb->remote_bd_addr);
+ tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
+ uint16_t scan_int;
+ uint16_t scan_win;
+ BD_ADDR peer_addr;
+ uint8_t peer_addr_type = BLE_ADDR_PUBLIC;
+ uint8_t own_addr_type = BLE_ADDR_PUBLIC;
+
+ /* There can be only one BLE connection request outstanding at a time */
+ if (p_dev_rec == NULL) {
+ L2CAP_TRACE_WARNING("unknown device, can not initate connection");
+ return (false);
+ }
+
+ scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_FAST_INT
+ : p_cb->scan_int;
+ scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF)
+ ? BTM_BLE_SCAN_FAST_WIN
+ : p_cb->scan_win;
+
+ peer_addr_type = p_lcb->ble_addr_type;
+ memcpy(peer_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+
+#if (BLE_PRIVACY_SPT == TRUE)
+ own_addr_type =
+ btm_cb.ble_ctr_cb.privacy_mode ? BLE_ADDR_RANDOM : BLE_ADDR_PUBLIC;
+ if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
+ if (btm_cb.ble_ctr_cb.privacy_mode >= BTM_PRIVACY_1_2)
+ own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
+
+ btm_ble_enable_resolving_list(BTM_BLE_RL_INIT);
+ btm_random_pseudo_to_identity_addr(peer_addr, &peer_addr_type);
+ } else {
+ btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
+
+ // If we have a current RPA, use that instead.
+ if (!bdaddr_is_empty((const bt_bdaddr_t*)p_dev_rec->ble.cur_rand_addr)) {
+ memcpy(peer_addr, p_dev_rec->ble.cur_rand_addr, BD_ADDR_LEN);
+ }
+ }
+#endif
+
+ if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
+ l2cu_release_lcb(p_lcb);
+ L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation");
+ return false;
+ }
+
+ btm_send_hci_create_connection(
+ scan_int, /* uint16_t scan_int */
+ scan_win, /* uint16_t scan_win */
+ false, /* uint8_t white_list */
+ peer_addr_type, /* uint8_t addr_type_peer */
+ peer_addr, /* BD_ADDR bda_peer */
+ own_addr_type, /* uint8_t addr_type_own */
+ (uint16_t)(
+ (p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ ? p_dev_rec->conn_params.min_conn_int
+ : BTM_BLE_CONN_INT_MIN_DEF), /* uint16_t conn_int_min */
+ (uint16_t)(
+ (p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF)
+ ? p_dev_rec->conn_params.max_conn_int
+ : BTM_BLE_CONN_INT_MAX_DEF), /* uint16_t conn_int_max */
+ (uint16_t)(
+ (p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF)
+ ? p_dev_rec->conn_params.slave_latency
+ : BTM_BLE_CONN_SLAVE_LATENCY_DEF), /* uint16_t conn_latency */
+ (uint16_t)(
+ (p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF)
+ ? p_dev_rec->conn_params.supervision_tout
+ : BTM_BLE_CONN_TIMEOUT_DEF), /* conn_timeout */
+ 0, /* uint16_t min_len */
+ 0, /* uint16_t max_len */
+ p_lcb->initiating_phys);
+
+ p_lcb->link_state = LST_CONNECTING;
+ l2cb.is_ble_connecting = true;
+ memcpy(l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN);
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ btm_ble_set_conn_st(BLE_DIR_CONN);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_create_conn
+ *
+ * Description This function initiates an acl connection via HCI
+ *
+ * Returns true if successful, false if connection not started.
+ *
+ ******************************************************************************/
+bool l2cble_create_conn(tL2C_LCB* p_lcb) {
+ tBTM_BLE_CONN_ST conn_st = btm_ble_get_conn_st();
+ bool rt = false;
+
+ /* There can be only one BLE connection request outstanding at a time */
+ if (conn_st == BLE_CONN_IDLE) {
+ rt = l2cble_init_direct_conn(p_lcb);
+ } else {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - LE - cannot start new connection at conn st: %d", conn_st);
+
+ btm_ble_enqueue_direct_conn_req(p_lcb);
+
+ if (conn_st == BLE_BG_CONN) btm_ble_suspend_bg_conn();
+
+ rt = true;
+ }
+ return rt;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_processs_ble_num_bufs
+ *
+ * Description This function is called when a "controller buffer size"
+ * event is first received from the controller. It updates
+ * the L2CAP values.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_processs_ble_num_bufs(uint16_t num_lm_ble_bufs) {
+ if (num_lm_ble_bufs == 0) {
+ num_lm_ble_bufs = L2C_DEF_NUM_BLE_BUF_SHARED;
+ l2cb.num_lm_acl_bufs -= L2C_DEF_NUM_BLE_BUF_SHARED;
+ }
+
+ l2cb.num_lm_ble_bufs = l2cb.controller_le_xmit_window = num_lm_ble_bufs;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ble_link_adjust_allocation
+ *
+ * Description This function is called when a link is created or removed
+ * to calculate the amount of packets each link may send to
+ * the HCI without an ack coming back.
+ *
+ * Currently, this is a simple allocation, dividing the
+ * number of Controller Packets by the number of links. In
+ * the future, QOS configuration should be examined.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_ble_link_adjust_allocation(void) {
+ uint16_t qq, yy, qq_remainder;
+ tL2C_LCB* p_lcb;
+ uint16_t hi_quota, low_quota;
+ uint16_t num_lowpri_links = 0;
+ uint16_t num_hipri_links = 0;
+ uint16_t controller_xmit_quota = l2cb.num_lm_ble_bufs;
+ uint16_t high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+
+ /* If no links active, reset buffer quotas and controller buffers */
+ if (l2cb.num_ble_links_active == 0) {
+ l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs;
+ l2cb.ble_round_robin_quota = l2cb.ble_round_robin_unacked = 0;
+ return;
+ }
+
+ /* First, count the links */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
+ if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) {
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+ num_hipri_links++;
+ else
+ num_lowpri_links++;
+ }
+ }
+
+ /* now adjust high priority link quota */
+ low_quota = num_lowpri_links ? 1 : 0;
+ while ((num_hipri_links * high_pri_link_quota + low_quota) >
+ controller_xmit_quota)
+ high_pri_link_quota--;
+
+ /* Work out the xmit quota and buffer quota high and low priorities */
+ hi_quota = num_hipri_links * high_pri_link_quota;
+ low_quota =
+ (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
+
+ /* Work out and save the HCI xmit quota for each low priority link */
+
+ /* If each low priority link cannot have at least one buffer */
+ if (num_lowpri_links > low_quota) {
+ l2cb.ble_round_robin_quota = low_quota;
+ qq = qq_remainder = 0;
+ }
+ /* If each low priority link can have at least one buffer */
+ else if (num_lowpri_links > 0) {
+ l2cb.ble_round_robin_quota = 0;
+ l2cb.ble_round_robin_unacked = 0;
+ qq = low_quota / num_lowpri_links;
+ qq_remainder = low_quota % num_lowpri_links;
+ }
+ /* If no low priority link */
+ else {
+ l2cb.ble_round_robin_quota = 0;
+ l2cb.ble_round_robin_unacked = 0;
+ qq = qq_remainder = 0;
+ }
+ L2CAP_TRACE_EVENT(
+ "l2c_ble_link_adjust_allocation num_hipri: %u num_lowpri: %u "
+ "low_quota: %u round_robin_quota: %u qq: %u",
+ num_hipri_links, num_lowpri_links, low_quota, l2cb.ble_round_robin_quota,
+ qq);
+
+ /* Now, assign the quotas to each link */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
+ if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) {
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) {
+ p_lcb->link_xmit_quota = high_pri_link_quota;
+ } else {
+ /* Safety check in case we switched to round-robin with something
+ * outstanding */
+ /* if sent_not_acked is added into round_robin_unacked then don't add it
+ * again */
+ /* l2cap keeps updating sent_not_acked for exiting from round robin */
+ if ((p_lcb->link_xmit_quota > 0) && (qq == 0))
+ l2cb.ble_round_robin_unacked += p_lcb->sent_not_acked;
+
+ p_lcb->link_xmit_quota = qq;
+ if (qq_remainder > 0) {
+ p_lcb->link_xmit_quota++;
+ qq_remainder--;
+ }
+ }
+
+ L2CAP_TRACE_EVENT(
+ "l2c_ble_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d",
+ yy, p_lcb->acl_priority, p_lcb->link_xmit_quota);
+
+ L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d",
+ /** M: here should be ble information @{ */
+ p_lcb->sent_not_acked, l2cb.ble_round_robin_unacked);
+ /** @} */
+
+ /* There is a special case where we have readjusted the link quotas and */
+ /* this link may have sent anything but some other link sent packets so */
+ /* so we may need a timer to kick off this link's transmissions. */
+ if ((p_lcb->link_state == LST_CONNECTED) &&
+ (!list_is_empty(p_lcb->link_xmit_data_q)) &&
+ (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
+ alarm_set_on_queue(
+ p_lcb->l2c_lcb_timer, L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+ }
+ }
+}
+
+#if (BLE_LLT_INCLUDED == TRUE)
+/*******************************************************************************
+ *
+ * Function l2cble_process_rc_param_request_evt
+ *
+ * Description process LE Remote Connection Parameter Request Event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_process_rc_param_request_evt(uint16_t handle, uint16_t int_min,
+ uint16_t int_max, uint16_t latency,
+ uint16_t timeout) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ if (p_lcb != NULL) {
+ p_lcb->min_interval = int_min;
+ p_lcb->max_interval = int_max;
+ p_lcb->latency = latency;
+ p_lcb->timeout = timeout;
+
+ /* if update is enabled, always accept connection parameter update */
+ if ((p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) == 0) {
+ btsnd_hcic_ble_rc_param_req_reply(handle, int_min, int_max, latency,
+ timeout, 0, 0);
+ } else {
+ L2CAP_TRACE_EVENT("L2CAP - LE - update currently disabled");
+ p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM;
+ btsnd_hcic_ble_rc_param_req_neg_reply(handle,
+ HCI_ERR_UNACCEPT_CONN_INTERVAL);
+ }
+
+ } else {
+ L2CAP_TRACE_WARNING("No link to update connection parameter")
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function l2cble_update_data_length
+ *
+ * Description This function update link tx data length if applicable
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_update_data_length(tL2C_LCB* p_lcb) {
+ uint16_t tx_mtu = 0;
+ uint16_t i = 0;
+
+ L2CAP_TRACE_DEBUG("%s", __func__);
+
+ /* See if we have a link control block for the connection */
+ if (p_lcb == NULL) return;
+
+ for (i = 0; i < L2CAP_NUM_FIXED_CHNLS; i++) {
+ if (i + L2CAP_FIRST_FIXED_CHNL != L2CAP_BLE_SIGNALLING_CID) {
+ if ((p_lcb->p_fixed_ccbs[i] != NULL) &&
+ (tx_mtu < (p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD)))
+ tx_mtu = p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD;
+ }
+ }
+
+ if (tx_mtu > BTM_BLE_DATA_SIZE_MAX) tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+ /* update TX data length if changed */
+ if (p_lcb->tx_data_len != tx_mtu)
+ BTM_SetBleDataLength(p_lcb->remote_bd_addr, tx_mtu);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_process_data_length_change_evt
+ *
+ * Description This function process the data length change event
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_process_data_length_change_event(uint16_t handle,
+ uint16_t tx_data_len,
+ uint16_t rx_data_len) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ L2CAP_TRACE_DEBUG("%s TX data len = %d", __func__, tx_data_len);
+ if (p_lcb == NULL) return;
+
+ if (tx_data_len > 0) p_lcb->tx_data_len = tx_data_len;
+
+ /* ignore rx_data len for now */
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_set_fixed_channel_tx_data_length
+ *
+ * Description This function update max fixed channel tx data length if
+ * applicable
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda,
+ uint16_t fix_cid,
+ uint16_t tx_mtu) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, BT_TRANSPORT_LE);
+ uint16_t cid = fix_cid - L2CAP_FIRST_FIXED_CHNL;
+
+ L2CAP_TRACE_DEBUG("%s TX MTU = %d", __func__, tx_mtu);
+
+ if (!controller_get_interface()->supports_ble_packet_extension()) {
+ L2CAP_TRACE_WARNING("%s, request not supported", __func__);
+ return;
+ }
+
+ /* See if we have a link control block for the connection */
+ if (p_lcb == NULL) return;
+
+ if (p_lcb->p_fixed_ccbs[cid] != NULL) {
+ if (tx_mtu > BTM_BLE_DATA_SIZE_MAX) tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+ p_lcb->p_fixed_ccbs[cid]->tx_data_len = tx_mtu;
+ }
+
+ l2cble_update_data_length(p_lcb);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_credit_based_conn_req
+ *
+ * Description This function sends LE Credit Based Connection Request for
+ * LE connection oriented channels.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb) {
+ if (!p_ccb) return;
+
+ if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("LE link doesn't exist");
+ return;
+ }
+
+ l2cu_send_peer_ble_credit_based_conn_req(p_ccb);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_credit_based_conn_res
+ *
+ * Description This function sends LE Credit Based Connection Response for
+ * LE connection oriented channels.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result) {
+ if (!p_ccb) return;
+
+ if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("LE link doesn't exist");
+ return;
+ }
+
+ l2cu_send_peer_ble_credit_based_conn_res(p_ccb, result);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_send_flow_control_credit
+ *
+ * Description This function sends flow control credits for
+ * LE connection oriented channels.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb, uint16_t credit_value) {
+ if (!p_ccb) return;
+
+ if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("LE link doesn't exist");
+ return;
+ }
+
+ l2cu_send_peer_ble_flow_control_credit(p_ccb, credit_value);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_send_peer_disc_req
+ *
+ * Description This function sends disconnect request
+ * to the peer LE device
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb) {
+ L2CAP_TRACE_DEBUG("%s", __func__);
+ if (!p_ccb) return;
+
+ if (p_ccb->p_lcb && p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ L2CAP_TRACE_WARNING("LE link doesn't exist");
+ return;
+ }
+
+ l2cu_send_peer_ble_credit_based_disconn_req(p_ccb);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cble_sec_comp
+ *
+ * Description This function is called when security procedure for an LE
+ * COC link is done
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cble_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT transport, void* p_ref_data,
+ uint8_t status) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, BT_TRANSPORT_LE);
+ tL2CAP_SEC_DATA* p_buf = NULL;
+ uint8_t sec_flag;
+ uint8_t sec_act;
+
+ if (!p_lcb) {
+ L2CAP_TRACE_WARNING("%s security complete for unknown device", __func__);
+ return;
+ }
+
+ sec_act = p_lcb->sec_act;
+ p_lcb->sec_act = 0;
+
+ if (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) {
+ p_buf = (tL2CAP_SEC_DATA*)fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+ if (!p_buf) {
+ L2CAP_TRACE_WARNING(
+ "%s Security complete for request not initiated from L2CAP",
+ __func__);
+ return;
+ }
+
+ if (status != BTM_SUCCESS) {
+ (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+ } else {
+ if (sec_act == BTM_SEC_ENCRYPT_MITM) {
+ BTM_GetSecurityFlagsByTransport(p_bda, &sec_flag, transport);
+ if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
+ (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data,
+ status);
+ else {
+ L2CAP_TRACE_DEBUG("%s MITM Protection Not present", __func__);
+ (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data,
+ BTM_FAILED_ON_SECURITY);
+ }
+ } else {
+ L2CAP_TRACE_DEBUG("%s MITM Protection not required sec_act = %d",
+ __func__, p_lcb->sec_act);
+
+ (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data,
+ status);
+ }
+ }
+ } else {
+ L2CAP_TRACE_WARNING(
+ "%s Security complete for request not initiated from L2CAP", __func__);
+ return;
+ }
+ osi_free(p_buf);
+
+ while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) {
+ p_buf = (tL2CAP_SEC_DATA*)fixed_queue_dequeue(p_lcb->le_sec_pending_q);
+
+ if (status != BTM_SUCCESS)
+ (*(p_buf->p_callback))(p_bda, BT_TRANSPORT_LE, p_buf->p_ref_data, status);
+ else
+ l2ble_sec_access_req(p_bda, p_buf->psm, p_buf->is_originator,
+ p_buf->p_callback, p_buf->p_ref_data);
+
+ osi_free(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2ble_sec_access_req
+ *
+ * Description This function is called by LE COC link to meet the
+ * security requirement for the link
+ *
+ * Returns true - security procedures are started
+ * false - failure
+ *
+ ******************************************************************************/
+bool l2ble_sec_access_req(BD_ADDR bd_addr, uint16_t psm, bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback, void* p_ref_data) {
+ L2CAP_TRACE_DEBUG("%s", __func__);
+ bool status;
+ tL2C_LCB* p_lcb = NULL;
+
+ if (!p_callback) {
+ L2CAP_TRACE_ERROR("%s No callback function", __func__);
+ return false;
+ }
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
+
+ if (!p_lcb) {
+ L2CAP_TRACE_ERROR("%s Security check for unknown device", __func__);
+ p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR);
+ return false;
+ }
+
+ tL2CAP_SEC_DATA* p_buf =
+ (tL2CAP_SEC_DATA*)osi_malloc((uint16_t)sizeof(tL2CAP_SEC_DATA));
+ if (!p_buf) {
+ p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES);
+ return false;
+ }
+
+ p_buf->psm = psm;
+ p_buf->is_originator = is_originator;
+ p_buf->p_callback = p_callback;
+ p_buf->p_ref_data = p_ref_data;
+ fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf);
+ status = btm_ble_start_sec_check(bd_addr, psm, is_originator,
+ &l2cble_sec_comp, p_ref_data);
+
+ return status;
+}
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_csm.cc b/mtkbt/code/bt/stack/l2cap/l2c_csm.cc
new file mode 100755
index 0000000..f9340b9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_csm.cc
@@ -0,0 +1,1444 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the L2CAP channel state machine
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+static void l2c_csm_config(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data);
+
+static const char* l2c_csm_get_event_name(uint16_t event);
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_execute
+ *
+ * Description This function executes the state machine.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_csm_execute(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+ if (!l2cu_is_ccb_active(p_ccb)) {
+ L2CAP_TRACE_WARNING("%s CCB not in use, event (%d) cannot be processed",
+ __func__, event);
+ return;
+ }
+
+ switch (p_ccb->chnl_state) {
+ case CST_CLOSED:
+ l2c_csm_closed(p_ccb, event, p_data);
+ break;
+
+ case CST_ORIG_W4_SEC_COMP:
+ l2c_csm_orig_w4_sec_comp(p_ccb, event, p_data);
+ break;
+
+ case CST_TERM_W4_SEC_COMP:
+ l2c_csm_term_w4_sec_comp(p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CAP_CONNECT_RSP:
+ l2c_csm_w4_l2cap_connect_rsp(p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CA_CONNECT_RSP:
+ l2c_csm_w4_l2ca_connect_rsp(p_ccb, event, p_data);
+ break;
+
+ case CST_CONFIG:
+ l2c_csm_config(p_ccb, event, p_data);
+ break;
+
+ case CST_OPEN:
+ l2c_csm_open(p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CAP_DISCONNECT_RSP:
+ l2c_csm_w4_l2cap_disconnect_rsp(p_ccb, event, p_data);
+ break;
+
+ case CST_W4_L2CA_DISCONNECT_RSP:
+ l2c_csm_w4_l2ca_disconnect_rsp(p_ccb, event, p_data);
+ break;
+
+ default:
+ L2CAP_TRACE_DEBUG("Unhandled event! event = %d", event);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_closed
+ *
+ * Description This function handles events when the channel is in
+ * CLOSED state. This state exists only when the link is
+ * being initially established.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+ tL2C_CONN_INFO* p_ci = (tL2C_CONN_INFO*)p_data;
+ uint16_t local_cid = p_ccb->local_cid;
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind;
+ tL2CA_CONNECT_CFM_CB* connect_cfm;
+
+ if (p_ccb->p_rcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - LCID: 0x%04x st: CLOSED evt: %s p_rcb == NULL",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+ return;
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (local_cid == L2CAP_CONNECTIONLESS_CID) {
+ /* check if this event can be processed by UCD */
+ if (l2c_ucd_process_event(p_ccb, event, p_data)) {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: CLOSED evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ true, &l2c_link_sec_comp, p_ccb);
+ } else {
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
+ p_ccb->p_rcb->psm, p_ccb->p_lcb->handle, true,
+ &l2c_link_sec_comp, p_ccb);
+ }
+ break;
+
+ case L2CEVT_LP_CONNECT_CFM_NEG: /* Link failed */
+ /* Disconnect unless ACL collision and upper layer wants to handle it */
+ if (p_ci->status != HCI_ERR_CONNECTION_EXISTS ||
+ !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr)) {
+ L2CAP_TRACE_API(
+ "L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d",
+ p_ccb->local_cid, p_ci->status);
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, p_ci->status);
+ }
+ break;
+
+ case L2CEVT_L2CA_CONNECT_REQ: /* API connect request */
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ true, &l2c_link_sec_comp, p_ccb);
+ } else {
+ /* Cancel sniff mode if needed */
+ {
+ tBTM_PM_PWR_MD settings;
+ memset((void*)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
+ &settings);
+ }
+
+ /* If sec access does not result in started SEC_COM or COMP_NEG are
+ * already processed */
+ if (btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
+ p_ccb->p_rcb->psm, p_ccb->p_lcb->handle,
+ true, &l2c_link_sec_comp,
+ p_ccb) == BTM_CMD_STARTED)
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ }
+ break;
+
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+
+ /* Wait for the info resp in this state before sending connect req (if
+ * needed) */
+ if (!p_ccb->p_lcb->w4_info_rsp) {
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb)) {
+ l2cu_release_ccb(p_ccb);
+ (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid,
+ L2CAP_CONN_NO_LINK);
+ } else {
+ l2cu_send_peer_connect_req(p_ccb);
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ }
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG: /* something is really bad with security */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d",
+ p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK);
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connect request */
+ /* stop link timer to avoid race condition between A2MP, Security, and
+ * L2CAP */
+ alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+ l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ false, &l2c_link_sec_comp, p_ccb);
+ } else {
+ /* Cancel sniff mode if needed */
+ {
+ tBTM_PM_PWR_MD settings;
+ memset((void*)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
+ &settings);
+ }
+
+ p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+ if (btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
+ p_ccb->p_rcb->psm, p_ccb->p_lcb->handle,
+ false, &l2c_link_sec_comp,
+ p_ccb) == BTM_CMD_STARTED) {
+ /* started the security process, tell the peer to set a longer timer
+ */
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+ }
+ }
+ break;
+
+ case L2CEVT_TIMEOUT:
+ L2CAP_TRACE_API(
+ "L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d",
+ p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+ case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+ osi_free(p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_orig_w4_sec_comp
+ *
+ * Description This function handles events when the channel is in
+ * CST_ORIG_W4_SEC_COMP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB* connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (local_cid == L2CAP_CONNECTIONLESS_CID) {
+ /* check if this event can be processed by UCD */
+ if (l2c_ucd_process_event(p_ccb, event, p_data)) {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ false, &l2c_link_sec_comp, p_ccb);
+ } else {
+ btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr,
+ p_ccb->p_rcb->psm, p_ccb->p_lcb->handle, true,
+ &l2c_link_sec_comp, p_ccb);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP: /* Security completed success */
+ /* Wait for the info resp in this state before sending connect req (if
+ * needed) */
+ p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ l2cble_credit_based_conn_req(p_ccb); /* Start Connection */
+ } else {
+ if (!p_ccb->p_lcb->w4_info_rsp) {
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb)) {
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ } else {
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ l2cu_send_peer_connect_req(p_ccb); /* Start Connection */
+ }
+ }
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ L2CAP_TRACE_API(
+ "L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d",
+ p_ccb->local_cid, HCI_ERR_AUTH_FAILURE);
+
+ /* If last channel immediately disconnect the ACL for better security.
+ Also prevents a race condition between BTM and L2CAP */
+ if ((p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) &&
+ (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb)) {
+ p_ccb->p_lcb->idle_timeout = 0;
+ }
+
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req(p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb(p_ccb);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_term_w4_sec_comp
+ *
+ * Description This function handles events when the channel is in
+ * CST_TERM_W4_SEC_COMP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
+ /* check if this event can be processed by UCD */
+ if (l2c_ucd_process_event(p_ccb, event, p_data)) {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req(p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
+
+ /* Wait for the info resp in next state before sending connect ind (if
+ * needed) */
+ if (!p_ccb->p_lcb->w4_info_rsp) {
+ /* Don't need to get info from peer or already retrieved so continue */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ L2CAP_TRACE_API("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x",
+ p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)(
+ p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm,
+ p_ccb->remote_id);
+ } else {
+ /*
+ ** L2CAP Connect Response will be sent out by 3 sec timer expiration
+ ** because Bluesoleil doesn't respond to L2CAP Information Request.
+ ** Bluesoleil seems to disconnect ACL link as failure case, because
+ ** it takes too long (4~7secs) to get response.
+ ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
+ ** stack version : 05.04.11.20060119
+ */
+
+ /* Waiting for the info resp, tell the peer to set a longer timer */
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ if (((tL2C_CONN_INFO*)p_data)->status == BTM_DELAY_CHECK) {
+ /* start a timer - encryption change not received before L2CAP connect
+ * req */
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ } else {
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+ l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id,
+ L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
+ else
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
+ l2cu_release_ccb(p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+ l2cu_send_peer_disc_rsp(p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid,
+ p_ccb->remote_cid);
+
+ /* Tell security manager to abort */
+ btm_sec_abort_access_req(p_ccb->p_lcb->remote_bd_addr);
+
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* SM4 related. */
+ btsnd_hcic_disconnect(p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE);
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
+ p_ccb->p_lcb->handle, false, &l2c_link_sec_comp,
+ p_ccb);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_w4_l2cap_connect_rsp
+ *
+ * Description This function handles events when the channel is in
+ * CST_W4_L2CAP_CONNECT_RSP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ tL2C_CONN_INFO* p_ci = (tL2C_CONN_INFO*)p_data;
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ tL2CA_CONNECT_CFM_CB* connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ /* Send disc indication unless peer to peer race condition AND normal
+ * disconnect */
+ /* *((uint8_t *)p_data) != HCI_ERR_PEER_USER happens when peer device try
+ * to disconnect for normal reason */
+ p_ccb->chnl_state = CST_CLOSED;
+ if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data ||
+ (*((uint8_t*)p_data) != HCI_ERR_PEER_USER)) {
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ }
+ p_ccb->flags |= CCB_FLAG_NO_RETRY;
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP: /* Got peer connect confirm */
+ p_ccb->remote_cid = p_ci->remote_cid;
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ /* Connection is completed */
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+ p_ccb->chnl_state = CST_OPEN;
+ } else {
+ p_ccb->chnl_state = CST_CONFIG;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ L2CAP_TRACE_API("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success",
+ p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Got peer connect pending */
+ p_ccb->remote_cid = p_ci->remote_cid;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer,
+ L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb) {
+ L2CAP_TRACE_API("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x",
+ p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid);
+ }
+ break;
+
+ case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d",
+ p_ccb->local_cid, p_ci->l2cap_result);
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, p_ci->l2cap_result);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ L2CAP_TRACE_API("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ /* If we know peer CID from connect pending, we can send disconnect */
+ if (p_ccb->remote_cid != 0) {
+ l2cu_send_peer_disc_req(p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ } else {
+ tL2CA_DISCONNECT_CFM_CB* disconnect_cfm =
+ p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
+ l2cu_release_ccb(p_ccb);
+ if (disconnect_cfm) {
+ L2CAP_TRACE_API("%s: L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x",
+ __func__, local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ }
+ }
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* Need to have at least one compatible channel to continue */
+ if (!l2c_fcr_chk_chan_modes(p_ccb)) {
+ l2cu_release_ccb(p_ccb);
+ (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
+ } else {
+ /* We have feature info, so now send peer connect request */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ l2cu_send_peer_connect_req(p_ccb); /* Start Connection */
+ }
+ break;
+
+ case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+ case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+ osi_free(p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_w4_l2ca_connect_rsp
+ *
+ * Description This function handles events when the channel is in
+ * CST_W4_L2CA_CONNECT_RSP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ tL2C_CONN_INFO* p_ci;
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_L2CA_CONNECT_RSP:
+ p_ci = (tL2C_CONN_INFO*)p_data;
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ /* Result should be OK or Reject */
+ if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) {
+ l2cble_credit_based_conn_res(p_ccb, L2CAP_CONN_OK);
+ p_ccb->chnl_state = CST_OPEN;
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+ } else {
+ l2cble_credit_based_conn_res(p_ccb, p_ci->l2cap_result);
+ l2cu_release_ccb(p_ccb);
+ }
+ } else {
+ /* Result should be OK or PENDING */
+ if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) {
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_OK, 0);
+ p_ccb->chnl_state = CST_CONFIG;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ } else {
+ /* If pending, stay in same state and start extended timer */
+ l2cu_send_peer_connect_rsp(p_ccb, p_ci->l2cap_result,
+ p_ci->l2cap_status);
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ }
+ }
+ break;
+
+ case L2CEVT_L2CA_CONNECT_RSP_NEG:
+ p_ci = (tL2C_CONN_INFO*)p_data;
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+ l2cble_credit_based_conn_res(p_ccb, p_ci->l2cap_result);
+ else
+ l2cu_send_peer_connect_rsp(p_ccb, p_ci->l2cap_result,
+ p_ci->l2cap_status);
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_NO_PSM, 0);
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_send_peer_disc_req(p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* We have feature info, so now give the upper layer connect IND */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ L2CAP_TRACE_API("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x",
+ p_ccb->local_cid);
+
+ (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb)(
+ p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid, p_ccb->p_rcb->psm,
+ p_ccb->remote_id);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_config
+ *
+ * Description This function handles events when the channel is in
+ * CONFIG state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_config(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+ tL2CAP_CFG_INFO* p_cfg = (tL2CAP_CFG_INFO*)p_data;
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+ uint8_t cfg_result;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: CONFIG evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
+
+ cfg_result = l2cu_process_peer_cfg_req(p_ccb, p_cfg);
+ if (cfg_result == L2CAP_PEER_CFG_OK) {
+ L2CAP_TRACE_EVENT(
+ "L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
+ p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
+ (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+ } else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT) {
+ /* Disconnect if channels are incompatible */
+ L2CAP_TRACE_EVENT("L2CAP - incompatible configurations disconnect");
+ l2cu_disconnect_chnl(p_ccb);
+ } else /* Return error to peer so he can renegotiate if possible */
+ {
+ L2CAP_TRACE_EVENT(
+ "L2CAP - incompatible configurations trying reconfig");
+ l2cu_send_peer_config_rsp(p_ccb, p_cfg);
+ }
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response */
+ l2cu_process_peer_cfg_rsp(p_ccb, p_cfg);
+
+ if (p_cfg->result != L2CAP_CFG_PENDING) {
+ /* TBD: When config options grow beyong minimum MTU (48 bytes)
+ * logic needs to be added to handle responses with
+ * continuation bit set in flags field.
+ * 1. Send additional config request out until C-bit is cleared in
+ * response
+ */
+ p_ccb->config_done |= OB_CFG_DONE;
+
+ if (p_ccb->config_done & IB_CFG_DONE) {
+ /* Verify two sides are in compatible modes before continuing */
+ if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
+ l2cu_send_peer_disc_req(p_ccb);
+ L2CAP_TRACE_WARNING(
+ "L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
+ "0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+ }
+
+ p_ccb->config_done |= RECONFIG_FLAG;
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_link_adjust_chnl_allocation();
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+
+ /* If using eRTM and waiting for an ACK, restart the ACK timer */
+ if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb);
+
+ /*
+ ** check p_ccb->our_cfg.fcr.mon_tout and
+ *p_ccb->our_cfg.fcr.rtrans_tout
+ ** we may set them to zero when sending config request during
+ *renegotiation
+ */
+ if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
+ ((p_ccb->our_cfg.fcr.mon_tout == 0) ||
+ (p_ccb->our_cfg.fcr.rtrans_tout))) {
+ l2c_fcr_adj_monitor_retran_timeout(p_ccb);
+ }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+#endif
+ /* See if we can forward anything on the hold queue */
+ if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ }
+ }
+ }
+
+ L2CAP_TRACE_API("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x",
+ p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */
+ /* Disable the Timer */
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+
+ /* If failure was channel mode try to renegotiate */
+ if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == false) {
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d",
+ p_ccb->local_cid, p_cfg->result);
+ (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed",
+ p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
+ l2cu_process_our_cfg_req(p_ccb, p_cfg);
+ l2cu_send_peer_config_req(p_ccb, p_cfg);
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp */
+ l2cu_process_our_cfg_rsp(p_ccb, p_cfg);
+
+ /* Not finished if continuation flag is set */
+ if ((p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) ||
+ (p_cfg->result == L2CAP_CFG_PENDING)) {
+ /* Send intermediate response; remain in cfg state */
+ l2cu_send_peer_config_rsp(p_ccb, p_cfg);
+ break;
+ }
+
+ /* Local config done; clear cached configuration in case reconfig takes
+ * place later */
+ p_ccb->peer_cfg.mtu_present = false;
+ p_ccb->peer_cfg.flush_to_present = false;
+ p_ccb->peer_cfg.qos_present = false;
+
+ p_ccb->config_done |= IB_CFG_DONE;
+
+ if (p_ccb->config_done & OB_CFG_DONE) {
+ /* Verify two sides are in compatible modes before continuing */
+ if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
+ l2cu_send_peer_disc_req(p_ccb);
+ L2CAP_TRACE_WARNING(
+ "L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: "
+ "0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+ }
+
+ p_ccb->config_done |= RECONFIG_FLAG;
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_link_adjust_chnl_allocation();
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+ }
+
+ l2cu_send_peer_config_rsp(p_ccb, p_cfg);
+
+ /* If using eRTM and waiting for an ACK, restart the ACK timer */
+ if (p_ccb->fcrb.wait_ack) l2c_fcr_start_timer(p_ccb);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
+#endif
+
+ /* See if we can forward anything on the hold queue */
+ if ((p_ccb->chnl_state == CST_OPEN) &&
+ (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) {
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ }
+ break;
+
+ case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */
+ l2cu_send_peer_config_rsp(p_ccb, p_cfg);
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ l2cu_send_peer_disc_req(p_ccb);
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ L2CAP_TRACE_API("L2CAP - Calling DataInd_Cb(), CID: 0x%04x",
+ p_ccb->local_cid);
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
+ p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL) {
+ if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) {
+ if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
+ .pL2CA_FixedData_Cb)
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
+ .pL2CA_FixedData_Cb)(p_ccb->local_cid,
+ p_ccb->p_lcb->remote_bd_addr,
+ (BT_HDR*)p_data);
+ else
+ osi_free(p_data);
+ break;
+ }
+ }
+#endif
+ (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR*)p_data);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ if (p_ccb->config_done & OB_CFG_DONE)
+ l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_data);
+ else
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_disc_req(p_ccb);
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_open
+ *
+ * Description This function handles events when the channel is in
+ * OPEN state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+ uint16_t local_cid = p_ccb->local_cid;
+ tL2CAP_CFG_INFO* p_cfg;
+ tL2C_CHNL_STATE tempstate;
+ uint8_t tempcfgdone;
+ uint8_t cfg_result;
+ uint16_t* credit;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: OPEN evt: %s", p_ccb->local_cid,
+ l2c_csm_get_event_name(event));
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (local_cid == L2CAP_CONNECTIONLESS_CID) {
+ /* check if this event can be processed by UCD */
+ if (l2c_ucd_process_event(p_ccb, event, p_data)) {
+ /* The event is processed by UCD state machine */
+ return;
+ }
+ }
+#endif
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ if (p_ccb->p_rcb)
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, false);
+ break;
+
+ case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
+ /* Tell upper layer. If service guaranteed, then clear the channel */
+ if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+ (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(
+ p_ccb->p_lcb->remote_bd_addr);
+ break;
+
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
+ p_cfg = (tL2CAP_CFG_INFO*)p_data;
+
+ tempstate = p_ccb->chnl_state;
+ tempcfgdone = p_ccb->config_done;
+ p_ccb->chnl_state = CST_CONFIG;
+ /** M: only maskoff IB_CFG_DONE flag, after peer rsp received, goes into OPEN state @{*/
+ //p_ccb->config_done &= ~CFG_DONE_MASK;
+ p_ccb->config_done &= ~IB_CFG_DONE;
+ /** @} */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+
+ cfg_result = l2cu_process_peer_cfg_req(p_ccb, p_cfg);
+ if (cfg_result == L2CAP_PEER_CFG_OK) {
+ (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
+ }
+
+ /* Error in config parameters: reset state and config flag */
+ else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE) {
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+ p_ccb->chnl_state = tempstate;
+ p_ccb->config_done = tempcfgdone;
+ l2cu_send_peer_config_rsp(p_ccb, p_cfg);
+ } else /* L2CAP_PEER_CFG_DISCONNECT */
+ {
+ /* Disconnect if channels are incompatible
+ * Note this should not occur if reconfigure
+ * since this should have never passed original config.
+ */
+ l2cu_disconnect_chnl(p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
+ if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ /* Make sure we are not in sniff mode */
+ {
+ tBTM_PM_PWR_MD settings;
+ memset((void*)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
+ &settings);
+ }
+ }
+
+ p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed",
+ p_ccb->local_cid);
+ (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, true);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb))
+ (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid,
+ (BT_HDR*)p_data);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
+ if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE) {
+ /* Make sure we are not in sniff mode */
+ {
+ tBTM_PM_PWR_MD settings;
+ memset((void*)&settings, 0, sizeof(settings));
+ settings.mode = BTM_PM_MD_ACTIVE;
+ BTM_SetPowerMode(BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr,
+ &settings);
+ }
+ }
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+ l2cble_send_peer_disc_req(p_ccb);
+ else
+ l2cu_send_peer_disc_req(p_ccb);
+
+ p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_data);
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ break;
+
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
+ p_ccb->chnl_state = CST_CONFIG;
+ /** M: only maskoff IB_CFG_DONE flag, after local rsp sent, goes into OPEN state @{*/
+ //p_ccb->config_done &= ~CFG_DONE_MASK;
+ p_ccb->config_done &= ~IB_CFG_DONE;
+ /** @} */
+ l2cu_process_our_cfg_req(p_ccb, (tL2CAP_CFG_INFO*)p_data);
+ l2cu_send_peer_config_req(p_ccb, (tL2CAP_CFG_INFO*)p_data);
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* Process the monitor/retransmission time-outs in flow control/retrans
+ * mode */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ l2c_fcr_proc_tout(p_ccb);
+ break;
+
+ case L2CEVT_ACK_TIMEOUT:
+ l2c_fcr_proc_ack_tout(p_ccb);
+ break;
+
+ case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+ L2CAP_TRACE_DEBUG("%s Sending credit", __func__);
+ credit = (uint16_t*)p_data;
+ l2cble_send_flow_control_credit(p_ccb, *credit);
+ break;
+
+ case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+ credit = (uint16_t*)p_data;
+ L2CAP_TRACE_DEBUG("%s Credits received %d", __func__, *credit);
+ if ((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_MAX_CREDIT) {
+ /* we have received credits more than max coc credits,
+ * so disconnecting the Le Coc Channel
+ */
+ l2cble_send_peer_disc_req(p_ccb);
+ } else {
+ p_ccb->peer_conn_cfg.credits += *credit;
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_w4_l2cap_disconnect_rsp
+ *
+ * Description This function handles events when the channel is in
+ * CST_W4_L2CAP_DISCONNECT_RSP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ tL2CA_DISCONNECT_CFM_CB* disconnect_cfm =
+ p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
+ l2cu_release_ccb(p_ccb);
+ if (disconnect_cfm) {
+ L2CAP_TRACE_API("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x",
+ local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
+ l2cu_send_peer_disc_rsp(p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid,
+ p_ccb->remote_cid);
+ l2cu_release_ccb(p_ccb);
+ if (disconnect_cfm) {
+ L2CAP_TRACE_API("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x",
+ local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
+ }
+ break;
+
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ case L2CEVT_TIMEOUT: /* Timeout */
+ l2cu_release_ccb(p_ccb);
+ if (disconnect_cfm) {
+ L2CAP_TRACE_API("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x",
+ local_cid);
+ (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
+ }
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ osi_free(p_data);
+ break;
+
+ case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
+ case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
+ osi_free(p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_w4_l2ca_disconnect_rsp
+ *
+ * Description This function handles events when the channel is in
+ * CST_W4_L2CA_DISCONNECT_RSP state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
+ void* p_data) {
+ tL2CA_DISCONNECT_IND_CB* disconnect_ind =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+ uint16_t local_cid = p_ccb->local_cid;
+
+ L2CAP_TRACE_EVENT("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s",
+ p_ccb->local_cid, l2c_csm_get_event_name(event));
+
+ switch (event) {
+ case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ l2cu_send_peer_disc_rsp(p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid,
+ p_ccb->remote_cid);
+ L2CAP_TRACE_API(
+ "L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
+ p_ccb->local_cid);
+ l2cu_release_ccb(p_ccb);
+ (*disconnect_ind)(local_cid, false);
+ break;
+
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper disconnect request */
+ case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper disconnect response */
+ l2cu_send_peer_disc_rsp(p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid,
+ p_ccb->remote_cid);
+ l2cu_release_ccb(p_ccb);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ osi_free(p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_csm_get_event_name
+ *
+ * Description This function returns the event name.
+ *
+ * NOTE conditionally compiled to save memory.
+ *
+ * Returns pointer to the name
+ *
+ ******************************************************************************/
+static const char* l2c_csm_get_event_name(uint16_t event) {
+ switch (event) {
+ case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */
+ return ("LOWER_LAYER_CONNECT_CFM");
+ case L2CEVT_LP_CONNECT_CFM_NEG: /* Lower layer connect confirm (failed) */
+ return ("LOWER_LAYER_CONNECT_CFM_NEG");
+ case L2CEVT_LP_CONNECT_IND: /* Lower layer connect indication */
+ return ("LOWER_LAYER_CONNECT_IND");
+ case L2CEVT_LP_DISCONNECT_IND: /* Lower layer disconnect indication */
+ return ("LOWER_LAYER_DISCONNECT_IND");
+ case L2CEVT_LP_QOS_CFM: /* Lower layer QOS confirmation */
+ return ("LOWER_LAYER_QOS_CFM");
+ case L2CEVT_LP_QOS_CFM_NEG: /* Lower layer QOS confirmation (failed)*/
+ return ("LOWER_LAYER_QOS_CFM_NEG");
+ case L2CEVT_LP_QOS_VIOLATION_IND: /* Lower layer QOS violation indication */
+ return ("LOWER_LAYER_QOS_VIOLATION_IND");
+
+ case L2CEVT_SEC_COMP: /* Security cleared successfully */
+ return ("SECURITY_COMPLETE");
+ case L2CEVT_SEC_COMP_NEG: /* Security procedure failed */
+ return ("SECURITY_COMPLETE_NEG");
+
+ case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connection request */
+ return ("PEER_CONNECT_REQ");
+ case L2CEVT_L2CAP_CONNECT_RSP: /* Peer connection response */
+ return ("PEER_CONNECT_RSP");
+ case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Peer connection response pending */
+ return ("PEER_CONNECT_RSP_PND");
+ case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer connection response (failed) */
+ return ("PEER_CONNECT_RSP_NEG");
+ case L2CEVT_L2CAP_CONFIG_REQ: /* Peer configuration request */
+ return ("PEER_CONFIG_REQ");
+ case L2CEVT_L2CAP_CONFIG_RSP: /* Peer configuration response */
+ return ("PEER_CONFIG_RSP");
+ case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer configuration response (failed) */
+ return ("PEER_CONFIG_RSP_NEG");
+ case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
+ return ("PEER_DISCONNECT_REQ");
+ case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
+ return ("PEER_DISCONNECT_RSP");
+ case L2CEVT_L2CAP_DATA: /* Peer data */
+ return ("PEER_DATA");
+
+ case L2CEVT_L2CA_CONNECT_REQ: /* Upper layer connect request */
+ return ("UPPER_LAYER_CONNECT_REQ");
+ case L2CEVT_L2CA_CONNECT_RSP: /* Upper layer connect response */
+ return ("UPPER_LAYER_CONNECT_RSP");
+ case L2CEVT_L2CA_CONNECT_RSP_NEG: /* Upper layer connect response (failed)*/
+ return ("UPPER_LAYER_CONNECT_RSP_NEG");
+ case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config request */
+ return ("UPPER_LAYER_CONFIG_REQ");
+ case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config response */
+ return ("UPPER_LAYER_CONFIG_RSP");
+ case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config response (failed) */
+ return ("UPPER_LAYER_CONFIG_RSP_NEG");
+ case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper layer disconnect request */
+ return ("UPPER_LAYER_DISCONNECT_REQ");
+ case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper layer disconnect response */
+ return ("UPPER_LAYER_DISCONNECT_RSP");
+ case L2CEVT_L2CA_DATA_READ: /* Upper layer data read */
+ return ("UPPER_LAYER_DATA_READ");
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data write */
+ return ("UPPER_LAYER_DATA_WRITE");
+ case L2CEVT_TIMEOUT: /* Timeout */
+ return ("TIMEOUT");
+ case L2CEVT_SEC_RE_SEND_CMD:
+ return ("SEC_RE_SEND_CMD");
+ case L2CEVT_L2CAP_INFO_RSP: /* Peer information response */
+ return ("L2CEVT_L2CAP_INFO_RSP");
+ case L2CEVT_ACK_TIMEOUT:
+ return ("L2CEVT_ACK_TIMEOUT");
+ case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT: /* Upper layer send credit packet
+ */
+ return ("SEND_FLOW_CONTROL_CREDIT");
+ case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT: /* Peer send credit packet */
+ return ("RECV_FLOW_CONTROL_CREDIT");
+
+ default:
+ return ("???? UNKNOWN EVENT");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_enqueue_peer_data
+ *
+ * Description Enqueues data destined for the peer in the ccb. Handles
+ * FCR segmentation and checks for congestion.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_enqueue_peer_data(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ uint8_t* p;
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ p_buf->event = 0;
+ } else {
+ /* Save the channel ID for faster counting */
+ p_buf->event = p_ccb->local_cid;
+
+ /* Step back to add the L2CAP header */
+ p_buf->offset -= L2CAP_PKT_OVERHEAD;
+ p_buf->len += L2CAP_PKT_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* Now the L2CAP header */
+ UINT16_TO_STREAM(p, p_buf->len - L2CAP_PKT_OVERHEAD);
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ }
+
+ if (p_ccb->xmit_hold_q == NULL) {
+ L2CAP_TRACE_ERROR(
+ "%s: empty queue: p_ccb = %p p_ccb->in_use = %d p_ccb->chnl_state = %d "
+ "p_ccb->local_cid = %u p_ccb->remote_cid = %u",
+ __func__, p_ccb, p_ccb->in_use, p_ccb->chnl_state, p_ccb->local_cid,
+ p_ccb->remote_cid);
+ }
+ fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf);
+
+ l2cu_check_channel_congestion(p_ccb);
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* if new packet is higher priority than serving ccb and it is not overrun */
+ if ((p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority) &&
+ (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0)) {
+ /* send out higher priority packet */
+ p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
+ }
+#endif
+
+ /* if we are doing a round robin scheduling, set the flag */
+ if (p_ccb->p_lcb->link_xmit_quota == 0) l2cb.check_round_robin = true;
+}
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_fcr.cc b/mtkbt/code/bt/stack/l2cap/l2c_fcr.cc
new file mode 100755
index 0000000..47714e1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_fcr.cc
@@ -0,0 +1,2457 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2004-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the L2CAP 1.2 Flow Control and retransmissions
+ * functions
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/* Flag passed to retransmit_i_frames() when all packets should be retransmitted
+ */
+#define L2C_FCR_RETX_ALL_PKTS 0xFF
+
+/* this is the minimal offset required by OBX to process incoming packets */
+static const uint16_t OBX_BUF_MIN_OFFSET = 4;
+
+static const char* SAR_types[] = {"Unsegmented", "Start", "End",
+ "Continuation"};
+static const char* SUP_types[] = {"RR", "REJ", "RNR", "SREJ"};
+
+/* Look-up table for the CRC calculation */
+static const unsigned short crctab[256] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601,
+ 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0,
+ 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81,
+ 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941,
+ 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01,
+ 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0,
+ 0x1680, 0xd641, 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
+ 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00,
+ 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0,
+ 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1, 0xe981,
+ 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41,
+ 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700,
+ 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
+ 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281,
+ 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01,
+ 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1,
+ 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80,
+ 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541,
+ 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
+ 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0,
+ 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481,
+ 0x5440, 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801,
+ 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1,
+ 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581,
+ 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
+ 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+
+/*******************************************************************************
+ * Static local functions
+*/
+static bool process_reqseq(tL2C_CCB* p_ccb, uint16_t ctrl_word);
+static void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word);
+static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word,
+ bool delay_ack);
+static bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq);
+static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
+ bool is_retransmission);
+static void process_stream_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf);
+static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf,
+ uint16_t ctrl_word);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+static void l2c_fcr_collect_ack_delay(tL2C_CCB* p_ccb, uint8_t num_bufs_acked);
+#endif
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_updcrc
+ *
+ * Description This function computes the CRC using the look-up table.
+ *
+ * Returns CRC
+ *
+ ******************************************************************************/
+static unsigned short l2c_fcr_updcrc(unsigned short icrc, unsigned char* icp,
+ int icnt) {
+ unsigned short crc = icrc;
+ unsigned char* cp = icp;
+ int cnt = icnt;
+
+ while (cnt--) {
+ crc = ((crc >> 8) & 0xff) ^ crctab[(crc & 0xff) ^ *cp++];
+ }
+
+ return (crc);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_tx_get_fcs
+ *
+ * Description This function computes the CRC for a frame to be TXed.
+ *
+ * Returns CRC
+ *
+ ******************************************************************************/
+static uint16_t l2c_fcr_tx_get_fcs(BT_HDR* p_buf) {
+ uint8_t* p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+
+ return (l2c_fcr_updcrc(L2CAP_FCR_INIT_CRC, p, p_buf->len));
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_rx_get_fcs
+ *
+ * Description This function computes the CRC for a received frame.
+ *
+ * Returns CRC
+ *
+ ******************************************************************************/
+static uint16_t l2c_fcr_rx_get_fcs(BT_HDR* p_buf) {
+ uint8_t* p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+
+ /* offset points past the L2CAP header, but the CRC check includes it */
+ p -= L2CAP_PKT_OVERHEAD;
+
+ return (
+ l2c_fcr_updcrc(L2CAP_FCR_INIT_CRC, p, p_buf->len + L2CAP_PKT_OVERHEAD));
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_start_timer
+ *
+ * Description This function starts the (monitor or retransmission) timer.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_start_timer(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ uint32_t tout;
+
+ /* The timers which are in milliseconds */
+ if (p_ccb->fcrb.wait_ack) {
+ tout = (uint32_t)p_ccb->our_cfg.fcr.mon_tout;
+ } else {
+ tout = (uint32_t)p_ccb->our_cfg.fcr.rtrans_tout;
+ }
+
+ /* Only start a timer that was not started */
+ if (!alarm_is_scheduled(p_ccb->fcrb.mon_retrans_timer)) {
+ alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, tout,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_stop_timer
+ *
+ * Description This function stops the (monitor or transmission) timer.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_stop_timer(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ alarm_cancel(p_ccb->fcrb.mon_retrans_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_cleanup
+ *
+ * Description This function cleans up the variable used for
+ * flow-control/retrans.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_cleanup(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+
+ alarm_free(p_fcrb->mon_retrans_timer);
+ p_fcrb->mon_retrans_timer = NULL;
+ alarm_free(p_fcrb->ack_timer);
+ p_fcrb->ack_timer = NULL;
+
+ osi_free_and_reset((void**)&p_fcrb->p_rx_sdu);
+
+ fixed_queue_free(p_fcrb->waiting_for_ack_q, osi_free);
+ p_fcrb->waiting_for_ack_q = NULL;
+
+ fixed_queue_free(p_fcrb->srej_rcv_hold_q, osi_free);
+ p_fcrb->srej_rcv_hold_q = NULL;
+
+ fixed_queue_free(p_fcrb->retrans_q, osi_free);
+ p_fcrb->retrans_q = NULL;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ if ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID) &&
+ (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) {
+ uint32_t dur = time_get_os_boottime_ms() - p_ccb->fcrb.connect_tick_count;
+ size_t p_str_size = 120;
+ char* p_str = (char*)osi_malloc(p_str_size);
+ uint16_t i;
+ uint32_t throughput_avg, ack_delay_avg, ack_q_count_avg;
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC,
+ "--- L2CAP ERTM Stats for CID: 0x%04x Duration: %08ums",
+ p_ccb->local_cid, dur);
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC,
+ "Retransmissions:%08u Times Flow Controlled:%08u Retrans "
+ "Touts:%08u Ack Touts:%08u",
+ p_ccb->fcrb.pkts_retransmitted, p_ccb->fcrb.xmit_window_closed,
+ p_ccb->fcrb.retrans_touts, p_ccb->fcrb.xmit_ack_touts);
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC,
+ "Times there is less than 2 packets in controller when flow "
+ "controlled:%08u",
+ p_ccb->fcrb.controller_idle);
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC,
+ "max_held_acks:%08u, in_cfg.fcr.tx_win_sz:%08u",
+ p_ccb->fcrb.max_held_acks, p_ccb->peer_cfg.fcr.tx_win_sz);
+
+ snprintf(
+ p_str, p_str_size,
+ "Sent Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u "
+ "SREJ:%08u",
+ p_ccb->fcrb.ertm_pkt_counts[0], p_ccb->fcrb.ertm_byte_counts[0],
+ (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[0] * 100) / (dur / 10) : 0),
+ p_ccb->fcrb.s_frames_sent[0], p_ccb->fcrb.s_frames_sent[1],
+ p_ccb->fcrb.s_frames_sent[2], p_ccb->fcrb.s_frames_sent[3]);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "%s", p_str);
+
+ snprintf(
+ p_str, p_str_size,
+ "Rcvd Pkts:%08u Bytes:%10u(%06u/sec) RR:%08u REJ:%08u RNR:%08u "
+ "SREJ:%08u",
+ p_ccb->fcrb.ertm_pkt_counts[1], p_ccb->fcrb.ertm_byte_counts[1],
+ (dur >= 10 ? (p_ccb->fcrb.ertm_byte_counts[1] * 100) / (dur / 10) : 0),
+ p_ccb->fcrb.s_frames_rcvd[0], p_ccb->fcrb.s_frames_rcvd[1],
+ p_ccb->fcrb.s_frames_rcvd[2], p_ccb->fcrb.s_frames_rcvd[3]);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "%s", p_str);
+
+ throughput_avg = 0;
+ ack_delay_avg = 0;
+ ack_q_count_avg = 0;
+
+ for (i = 0; i < L2CAP_ERTM_STATS_NUM_AVG; i++) {
+ if (i == p_ccb->fcrb.ack_delay_avg_index) {
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "[%02u] collecting data ...", i);
+ continue;
+ }
+
+ snprintf(p_str, p_str_size,
+ "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, "
+ "ack_q_count avg:%3u, min:%3u, max:%3u",
+ i, p_ccb->fcrb.throughput[i], p_ccb->fcrb.ack_delay_avg[i],
+ p_ccb->fcrb.ack_delay_min[i], p_ccb->fcrb.ack_delay_max[i],
+ p_ccb->fcrb.ack_q_count_avg[i], p_ccb->fcrb.ack_q_count_min[i],
+ p_ccb->fcrb.ack_q_count_max[i]);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "%s", p_str);
+
+ throughput_avg += p_ccb->fcrb.throughput[i];
+ ack_delay_avg += p_ccb->fcrb.ack_delay_avg[i];
+ ack_q_count_avg += p_ccb->fcrb.ack_q_count_avg[i];
+ }
+
+ throughput_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+ ack_delay_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+ ack_q_count_avg /= (L2CAP_ERTM_STATS_NUM_AVG - 1);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC,
+ "throughput_avg: %8u (kbytes/sec), ack_delay_avg: %8u ms, "
+ "ack_q_count_avg: %8u",
+ throughput_avg, ack_delay_avg, ack_q_count_avg);
+
+ osi_free(p_str);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "---");
+ }
+#endif
+
+ memset(p_fcrb, 0, sizeof(tL2C_FCRB));
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_clone_buf
+ *
+ * Description This function allocates and copies requested part of a
+ * buffer at a new-offset.
+ *
+ * Returns pointer to new buffer
+ *
+ ******************************************************************************/
+BT_HDR* l2c_fcr_clone_buf(BT_HDR* p_buf, uint16_t new_offset,
+ uint16_t no_of_bytes) {
+ CHECK(p_buf != NULL);
+ /*
+ * NOTE: We allocate extra L2CAP_FCS_LEN octets, in case we need to put
+ * the FCS (Frame Check Sequence) at the end of the buffer.
+ */
+ uint16_t buf_size = no_of_bytes + sizeof(BT_HDR) + new_offset + L2CAP_FCS_LEN;
+#if (L2CAP_ERTM_STATS == TRUE)
+ /*
+ * NOTE: If L2CAP_ERTM_STATS is enabled, we need 4 extra octets at the
+ * end for a timestamp at the end of an I-frame.
+ */
+ buf_size += sizeof(uint32_t);
+#endif
+ BT_HDR* p_buf2 = (BT_HDR*)osi_malloc(buf_size);
+
+ p_buf2->offset = new_offset;
+ p_buf2->len = no_of_bytes;
+ memcpy(((uint8_t*)(p_buf2 + 1)) + p_buf2->offset,
+ ((uint8_t*)(p_buf + 1)) + p_buf->offset, no_of_bytes);
+
+ return (p_buf2);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_is_flow_controlled
+ *
+ * Description This function checks if the CCB is flow controlled by peer.
+ *
+ * Returns The control word
+ *
+ ******************************************************************************/
+bool l2c_fcr_is_flow_controlled(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ /* Check if remote side flowed us off or the transmit window is full */
+ if ((p_ccb->fcrb.remote_busy == true) ||
+ (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >=
+ p_ccb->peer_cfg.fcr.tx_win_sz)) {
+#if (L2CAP_ERTM_STATS == TRUE)
+ if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+ p_ccb->fcrb.xmit_window_closed++;
+
+ if ((p_ccb->p_lcb->sent_not_acked < 2) &&
+ (l2cb.controller_xmit_window > 0))
+ p_ccb->fcrb.controller_idle++;
+ }
+#endif
+ return (true);
+ }
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function prepare_I_frame
+ *
+ * Description This function sets the FCR variables in an I-frame that is
+ * about to be sent to HCI for transmission. This may be the
+ * first time the I-frame is sent, or a retransmission
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+static void prepare_I_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
+ bool is_retransmission) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+ uint8_t* p;
+ uint16_t fcs;
+ uint16_t ctrl_word;
+ bool set_f_bit = p_fcrb->send_f_rsp;
+
+ p_fcrb->send_f_rsp = false;
+
+ if (is_retransmission) {
+ /* Get the old control word and clear out the old req_seq and F bits */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ ctrl_word &= ~(L2CAP_FCR_REQ_SEQ_BITS + L2CAP_FCR_F_BIT);
+ } else {
+ ctrl_word = p_buf->layer_specific & L2CAP_FCR_SEG_BITS; /* SAR bits */
+ ctrl_word |=
+ (p_fcrb->next_tx_seq << L2CAP_FCR_TX_SEQ_BITS_SHIFT); /* Tx Seq */
+
+ p_fcrb->next_tx_seq = (p_fcrb->next_tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+ }
+
+ /* Set the F-bit and reqseq only if using re-transmission mode */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ if (set_f_bit) ctrl_word |= L2CAP_FCR_F_BIT;
+
+ ctrl_word |= (p_fcrb->next_seq_expected) << L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+ p_fcrb->last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+ alarm_cancel(p_ccb->fcrb.ack_timer);
+ }
+
+ /* Set the control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ UINT16_TO_STREAM(p, ctrl_word);
+
+ /* Compute the FCS and add to the end of the buffer if not bypassed */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+ /* length field in l2cap header has to include FCS length */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+ UINT16_TO_STREAM(p, p_buf->len + L2CAP_FCS_LEN - L2CAP_PKT_OVERHEAD);
+
+ /* Calculate the FCS */
+ fcs = l2c_fcr_tx_get_fcs(p_buf);
+
+ /* Point to the end of the buffer and put the FCS there */
+ /*
+ * NOTE: Here we assume the allocated buffer is large enough
+ * to include extra L2CAP_FCS_LEN octets at the end.
+ */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len;
+
+ UINT16_TO_STREAM(p, fcs);
+
+ p_buf->len += L2CAP_FCS_LEN;
+ }
+
+ if (is_retransmission) {
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM ReTx I-frame CID: 0x%04x Len: %u SAR: %s TxSeq: %u "
+ "ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ } else {
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM Tx I-frame CID: 0x%04x Len: %u SAR: %-12s TxSeq: %u "
+ "ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+
+ /* Start the retransmission timer if not already running */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
+ l2c_fcr_start_timer(p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_send_S_frame
+ *
+ * Description This function formats and sends an S-frame for transmission.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code,
+ uint16_t pf_bit) {
+ CHECK(p_ccb != NULL);
+ uint8_t* p;
+ uint16_t ctrl_word;
+ uint16_t fcs;
+
+ if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN)) return;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.s_frames_sent[function_code]++;
+#endif
+
+ if (pf_bit == L2CAP_FCR_P_BIT) {
+ p_ccb->fcrb.wait_ack = true;
+
+ l2c_fcr_stop_timer(p_ccb); /* Restart the monitor timer */
+ l2c_fcr_start_timer(p_ccb);
+ }
+
+ /* Create the control word to use */
+ ctrl_word = (function_code << L2CAP_FCR_SUP_SHIFT) | L2CAP_FCR_S_FRAME_BIT;
+ ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT);
+ ctrl_word |= pf_bit;
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(L2CAP_CMD_BUF_SIZE);
+ p_buf->offset = HCI_DATA_PREAMBLE_SIZE;
+ p_buf->len = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* Put in the L2CAP header */
+ UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN);
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, ctrl_word);
+
+ /* Compute the FCS and add to the end of the buffer if not bypassed */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+ fcs = l2c_fcr_tx_get_fcs(p_buf);
+
+ UINT16_TO_STREAM(p, fcs);
+ p_buf->len += L2CAP_FCS_LEN;
+ } else {
+ /* rewrite the length without FCS length */
+ p -= 6;
+ UINT16_TO_STREAM(p, L2CAP_FCR_OVERHEAD);
+ }
+
+ /* Now, the HCI transport header */
+ p_buf->layer_specific = L2CAP_NON_FLUSHABLE_PKT;
+ l2cu_set_acl_hci_header(p_buf, p_ccb);
+
+ if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) ||
+ (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s "
+ "ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, ctrl_word,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ L2CAP_TRACE_WARNING(" Buf Len: %u", p_buf->len);
+ } else {
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM Tx S-frame CID: 0x%04x ctrlword: 0x%04x Type: %s "
+ "ReqSeq: %u P: %u F: %u",
+ p_ccb->local_cid, ctrl_word,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ L2CAP_TRACE_EVENT(" Buf Len: %u", p_buf->len);
+ }
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+
+ p_ccb->fcrb.last_ack_sent = p_ccb->fcrb.next_seq_expected;
+
+ alarm_cancel(p_ccb->fcrb.ack_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_proc_pdu
+ *
+ * Description This function is the entry point for processing of a
+ * received PDU when in flow control and/or retransmission
+ * modes.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+ uint8_t* p;
+ uint16_t fcs;
+ uint16_t min_pdu_len;
+ uint16_t ctrl_word;
+
+ /* Check the length */
+ min_pdu_len = (p_ccb->bypass_fcs == L2CAP_BYPASS_FCS)
+ ? (uint16_t)L2CAP_FCR_OVERHEAD
+ : (uint16_t)(L2CAP_FCS_LEN + L2CAP_FCR_OVERHEAD);
+
+ if (p_buf->len < min_pdu_len) {
+ L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x Len too short: %u",
+ p_ccb->local_cid, p_buf->len);
+ osi_free(p_buf);
+ return;
+ }
+
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_STREAM_MODE) {
+ process_stream_frame(p_ccb, p_buf);
+ return;
+ }
+
+ /* Get the control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) {
+ if ((((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 1) ||
+ (((ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT) == 3)) {
+ /* REJ or SREJ */
+ L2CAP_TRACE_WARNING(
+ "L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u "
+ "P: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ } else {
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM Rx S-frame: cid: 0x%04x Len: %u Type: %s ReqSeq: %u "
+ "P: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SUP_types[(ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT],
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_P_BIT) >> L2CAP_FCR_P_BIT_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+ } else {
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u "
+ "ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+ }
+
+ L2CAP_TRACE_EVENT(
+ " eRTM Rx Nxt_tx_seq %u, Lst_rx_ack %u, Nxt_seq_exp %u, Lst_ack_snt "
+ "%u, wt_q.cnt %u, tries %u",
+ p_ccb->fcrb.next_tx_seq, p_ccb->fcrb.last_rx_ack,
+ p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent,
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q), p_ccb->fcrb.num_tries);
+
+ /* Verify FCS if using */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+ /* Extract and drop the FCS from the packet */
+ STREAM_TO_UINT16(fcs, p);
+ p_buf->len -= L2CAP_FCS_LEN;
+
+ if (l2c_fcr_rx_get_fcs(p_buf) != fcs) {
+ L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x BAD FCS",
+ p_ccb->local_cid);
+ osi_free(p_buf);
+ return;
+ }
+ }
+
+ /* Get the control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+ /* If we had a poll bit outstanding, check if we got a final response */
+ if (p_ccb->fcrb.wait_ack) {
+ /* If final bit not set, ignore the frame unless it is a polled S-frame */
+ if (!(ctrl_word & L2CAP_FCR_F_BIT)) {
+ if ((ctrl_word & L2CAP_FCR_P_BIT) &&
+ (ctrl_word & L2CAP_FCR_S_FRAME_BIT)) {
+ if (p_ccb->fcrb.srej_sent)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+ else if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+ /* Got a poll while in wait_ack state, so re-start our timer with
+ * 1-second */
+ /* This is a small optimization... the monitor timer is 12 secs, but we
+ * saw */
+ /* that if the other side sends us a poll when we are waiting for a
+ * final, */
+ /* then it speeds up recovery significantly if we poll him back soon
+ * after his poll. */
+ alarm_set_on_queue(p_ccb->fcrb.mon_retrans_timer, BT_1SEC_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ osi_free(p_buf);
+ return;
+ }
+
+ p_ccb->fcrb.wait_ack = false;
+
+ /* P and F are mutually exclusive */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) ctrl_word &= ~L2CAP_FCR_P_BIT;
+
+ if (fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
+ p_ccb->fcrb.num_tries = 0;
+
+ l2c_fcr_stop_timer(p_ccb);
+ } else {
+ /* Otherwise, ensure the final bit is ignored */
+ ctrl_word &= ~L2CAP_FCR_F_BIT;
+ }
+
+ /* Process receive sequence number */
+ if (!process_reqseq(p_ccb, ctrl_word)) {
+ osi_free(p_buf);
+ return;
+ }
+
+ /* Process based on whether it is an S-frame or an I-frame */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT)
+ process_s_frame(p_ccb, p_buf, ctrl_word);
+ else
+ process_i_frame(p_ccb, p_buf, ctrl_word, false);
+
+ /* Return if the channel got disconnected by a bad packet or max
+ * retransmissions */
+ if ((!p_ccb->in_use) || (p_ccb->chnl_state != CST_OPEN)) return;
+
+ /* If we have some buffers held while doing SREJ, and SREJ has cleared,
+ * process them now */
+ if ((!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.srej_sent) &&
+ (!fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q))) {
+ fixed_queue_t* temp_q = p_ccb->fcrb.srej_rcv_hold_q;
+ p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
+
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(temp_q)) != NULL) {
+ if (p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) {
+ /* Get the control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset - L2CAP_FCR_OVERHEAD;
+
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ L2CAP_TRACE_DEBUG(
+ "l2c_fcr_proc_pdu() CID: 0x%04x Process Buffer from SREJ_Hold_Q "
+ "TxSeq: %u Expected_Seq: %u",
+ p_ccb->local_cid,
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ p_ccb->fcrb.next_seq_expected);
+
+ /* Process the SREJ held I-frame, but do not send an RR for each
+ * individual frame */
+ process_i_frame(p_ccb, p_buf, ctrl_word, true);
+ } else
+ osi_free(p_buf);
+
+ /* If more frames were lost during SREJ, send a REJ */
+ if (p_ccb->fcrb.rej_after_srej) {
+ p_ccb->fcrb.rej_after_srej = false;
+ p_ccb->fcrb.rej_sent = true;
+
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_REJ, 0);
+ }
+ }
+ fixed_queue_free(temp_q, NULL);
+
+ /* Now, if needed, send one RR for the whole held queue */
+ if ((!p_ccb->fcrb.local_busy) && (!p_ccb->fcrb.rej_sent) &&
+ (!p_ccb->fcrb.srej_sent) &&
+ (p_ccb->fcrb.next_seq_expected != p_ccb->fcrb.last_ack_sent))
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
+ else {
+ L2CAP_TRACE_DEBUG(
+ "l2c_fcr_proc_pdu() not sending RR CID: 0x%04x local_busy:%d "
+ "rej_sent:%d srej_sent:%d Expected_Seq:%u Last_Ack:%u",
+ p_ccb->local_cid, p_ccb->fcrb.local_busy, p_ccb->fcrb.rej_sent,
+ p_ccb->fcrb.srej_sent, p_ccb->fcrb.next_seq_expected,
+ p_ccb->fcrb.last_ack_sent);
+ }
+ }
+
+ /* If a window has opened, check if we can send any more packets */
+ if ((!fixed_queue_is_empty(p_ccb->fcrb.retrans_q) ||
+ !fixed_queue_is_empty(p_ccb->xmit_hold_q)) &&
+ (p_ccb->fcrb.wait_ack == false) &&
+ (l2c_fcr_is_flow_controlled(p_ccb) == false)) {
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_lcc_proc_pdu
+ *
+ * Description This function is the entry point for processing of a
+ * received PDU when in LE Coc flow control modes.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint16_t sdu_length;
+ BT_HDR* p_data = NULL;
+
+ /* Buffer length should not exceed local mps */
+ if (p_buf->len > p_ccb->local_conn_cfg.mps) {
+ /* Discard the buffer */
+ osi_free(p_buf);
+ return;
+ }
+
+ if (p_ccb->is_first_seg) {
+ STREAM_TO_UINT16(sdu_length, p);
+ /* Check the SDU Length with local MTU size */
+ if (sdu_length > p_ccb->local_conn_cfg.mtu) {
+ /* Discard the buffer */
+ osi_free(p_buf);
+ return;
+ }
+
+ p_data = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
+ if (p_data == NULL) {
+ osi_free(p_buf);
+ return;
+ }
+
+ p_ccb->ble_sdu = p_data;
+ p_data->len = 0;
+ p_ccb->ble_sdu_length = sdu_length;
+ L2CAP_TRACE_DEBUG("%s SDU Length = %d", __func__, sdu_length);
+ p_buf->len -= sizeof(sdu_length);
+ p_buf->offset += sizeof(sdu_length);
+ p_data->offset = 0;
+
+ } else
+ p_data = p_ccb->ble_sdu;
+
+ memcpy((uint8_t*)(p_data + 1) + p_data->offset + p_data->len,
+ (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+ p_data->len += p_buf->len;
+ p = (uint8_t*)(p_data + 1) + p_data->offset;
+ if (p_data->len == p_ccb->ble_sdu_length) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_data);
+ p_ccb->is_first_seg = true;
+ p_ccb->ble_sdu = NULL;
+ p_ccb->ble_sdu_length = 0;
+ } else if (p_data->len < p_ccb->ble_sdu_length) {
+ p_ccb->is_first_seg = false;
+ } else {
+ L2CAP_TRACE_ERROR("%s Length in the SDU messed up", __func__);
+ // TODO: reset every thing may be???
+ }
+
+ osi_free(p_buf);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_proc_tout
+ *
+ * Description Handle a timeout. We should be in error recovery state.
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_proc_tout(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ L2CAP_TRACE_DEBUG(
+ "l2c_fcr_proc_tout: CID: 0x%04x num_tries: %u (max: %u) wait_ack: %u "
+ "ack_q_count: %u",
+ p_ccb->local_cid, p_ccb->fcrb.num_tries, p_ccb->peer_cfg.fcr.max_transmit,
+ p_ccb->fcrb.wait_ack, fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.retrans_touts++;
+#endif
+
+ if ((p_ccb->peer_cfg.fcr.max_transmit != 0) &&
+ (++p_ccb->fcrb.num_tries > p_ccb->peer_cfg.fcr.max_transmit)) {
+ l2cu_disconnect_chnl(p_ccb);
+ } else {
+ if (!p_ccb->fcrb.srej_sent && !p_ccb->fcrb.rej_sent) {
+ if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_P_BIT);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_P_BIT);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_proc_ack_tout
+ *
+ * Description Send RR/RNR if we have not acked I frame
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2c_fcr_proc_ack_tout(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+ L2CAP_TRACE_DEBUG(
+ "l2c_fcr_proc_ack_tout: CID: 0x%04x State: %u Wack:%u Rq:%d Acked:%d",
+ p_ccb->local_cid, p_ccb->chnl_state, p_ccb->fcrb.wait_ack,
+ p_ccb->fcrb.next_seq_expected, p_ccb->fcrb.last_ack_sent);
+
+ if ((p_ccb->chnl_state == CST_OPEN) && (!p_ccb->fcrb.wait_ack) &&
+ (p_ccb->fcrb.last_ack_sent != p_ccb->fcrb.next_seq_expected)) {
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.xmit_ack_touts++;
+#endif
+ if (p_ccb->fcrb.local_busy)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function process_reqseq
+ *
+ * Description Handle receive sequence number
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+static bool process_reqseq(tL2C_CCB* p_ccb, uint16_t ctrl_word) {
+ CHECK(p_ccb != NULL);
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+ uint8_t req_seq, num_bufs_acked, xx;
+ uint16_t ls;
+ uint16_t full_sdus_xmitted;
+
+ /* Receive sequence number does not ack anything for SREJ with P-bit set to
+ * zero */
+ if ((ctrl_word & L2CAP_FCR_S_FRAME_BIT) &&
+ ((ctrl_word & L2CAP_FCR_SUP_BITS) ==
+ (L2CAP_FCR_SUP_SREJ << L2CAP_FCR_SUP_SHIFT)) &&
+ ((ctrl_word & L2CAP_FCR_P_BIT) == 0)) {
+ /* If anything still waiting for ack, restart the timer if it was stopped */
+ if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
+ l2c_fcr_start_timer(p_ccb);
+
+ return (true);
+ }
+
+ /* Extract the receive sequence number from the control word */
+ req_seq =
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT;
+
+ num_bufs_acked = (req_seq - p_fcrb->last_rx_ack) & L2CAP_FCR_SEQ_MODULO;
+
+ /* Verify the request sequence is in range before proceeding */
+ if (num_bufs_acked > fixed_queue_length(p_fcrb->waiting_for_ack_q)) {
+ /* The channel is closed if ReqSeq is not in range */
+ L2CAP_TRACE_WARNING(
+ "L2CAP eRTM Frame BAD Req_Seq - ctrl_word: 0x%04x req_seq 0x%02x "
+ "last_rx_ack: 0x%02x QCount: %u",
+ ctrl_word, req_seq, p_fcrb->last_rx_ack,
+ fixed_queue_length(p_fcrb->waiting_for_ack_q));
+
+ l2cu_disconnect_chnl(p_ccb);
+ return (false);
+ }
+
+ p_fcrb->last_rx_ack = req_seq;
+
+ /* Now we can release all acknowledged frames, and restart the retransmission
+ * timer if needed */
+ if (num_bufs_acked != 0) {
+ p_fcrb->num_tries = 0;
+ full_sdus_xmitted = 0;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ l2c_fcr_collect_ack_delay(p_ccb, num_bufs_acked);
+#endif
+
+ for (xx = 0; xx < num_bufs_acked; xx++) {
+ BT_HDR* p_tmp =
+ (BT_HDR*)fixed_queue_try_dequeue(p_fcrb->waiting_for_ack_q);
+ ls = p_tmp->layer_specific & L2CAP_FCR_SAR_BITS;
+
+ if ((ls == L2CAP_FCR_UNSEG_SDU) || (ls == L2CAP_FCR_END_SDU))
+ full_sdus_xmitted++;
+
+ osi_free(p_tmp);
+ }
+
+ /* If we are still in a wait_ack state, do not mess with the timer */
+ if (!p_ccb->fcrb.wait_ack) l2c_fcr_stop_timer(p_ccb);
+
+ /* Check if we need to call the "packet_sent" callback */
+ if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_TxComplete_Cb) &&
+ (full_sdus_xmitted)) {
+ /* Special case for eRTM, if all packets sent, send 0xFFFF */
+ if (fixed_queue_is_empty(p_fcrb->waiting_for_ack_q) &&
+ fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+ full_sdus_xmitted = 0xFFFF;
+ }
+
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid,
+ full_sdus_xmitted);
+ }
+ }
+
+ /* If anything still waiting for ack, restart the timer if it was stopped */
+ if (!fixed_queue_is_empty(p_fcrb->waiting_for_ack_q))
+ l2c_fcr_start_timer(p_ccb);
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function process_s_frame
+ *
+ * Description Process an S frame
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+static void process_s_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf,
+ uint16_t ctrl_word) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+ uint16_t s_frame_type =
+ (ctrl_word & L2CAP_FCR_SUP_BITS) >> L2CAP_FCR_SUP_SHIFT;
+ bool remote_was_busy;
+ bool all_ok = true;
+
+ if (p_buf->len != 0) {
+ L2CAP_TRACE_WARNING("Incorrect S-frame Length (%d)", p_buf->len);
+ }
+
+ L2CAP_TRACE_DEBUG("process_s_frame ctrl_word 0x%04x fcrb_remote_busy:%d",
+ ctrl_word, p_fcrb->remote_busy);
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.s_frames_rcvd[s_frame_type]++;
+#endif
+
+ if (ctrl_word & L2CAP_FCR_P_BIT) {
+ p_fcrb->rej_sent = false; /* After checkpoint, we can send anoher REJ */
+ p_fcrb->send_f_rsp = true; /* Set a flag in case an I-frame is pending */
+ }
+
+ switch (s_frame_type) {
+ case L2CAP_FCR_SUP_RR:
+ remote_was_busy = p_fcrb->remote_busy;
+ p_fcrb->remote_busy = false;
+
+ if ((ctrl_word & L2CAP_FCR_F_BIT) || (remote_was_busy))
+ all_ok = retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS);
+ break;
+
+ case L2CAP_FCR_SUP_REJ:
+ p_fcrb->remote_busy = false;
+ all_ok = retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS);
+ break;
+
+ case L2CAP_FCR_SUP_RNR:
+ p_fcrb->remote_busy = true;
+ l2c_fcr_stop_timer(p_ccb);
+ break;
+
+ case L2CAP_FCR_SUP_SREJ:
+ p_fcrb->remote_busy = false;
+ all_ok = retransmit_i_frames(
+ p_ccb, (uint8_t)((ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >>
+ L2CAP_FCR_REQ_SEQ_BITS_SHIFT));
+ break;
+ }
+
+ if (all_ok) {
+ /* If polled, we need to respond with F-bit. Note, we may have sent a
+ * I-frame with the F-bit */
+ if (p_fcrb->send_f_rsp) {
+ if (p_fcrb->srej_sent)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, L2CAP_FCR_F_BIT);
+ else if (p_fcrb->local_busy)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, L2CAP_FCR_F_BIT);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, L2CAP_FCR_F_BIT);
+
+ p_fcrb->send_f_rsp = false;
+ }
+ } else {
+ L2CAP_TRACE_DEBUG("process_s_frame hit_max_retries");
+ }
+
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function process_i_frame
+ *
+ * Description Process an I frame
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+static void process_i_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf, uint16_t ctrl_word,
+ bool delay_ack) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+ uint8_t tx_seq, num_lost, num_to_ack, next_srej;
+
+ /* If we were doing checkpoint recovery, first retransmit all unacked I-frames
+ */
+ if (ctrl_word & L2CAP_FCR_F_BIT) {
+ if (!retransmit_i_frames(p_ccb, L2C_FCR_RETX_ALL_PKTS)) {
+ osi_free(p_buf);
+ return;
+ }
+ }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.ertm_pkt_counts[1]++;
+ p_ccb->fcrb.ertm_byte_counts[1] += p_buf->len;
+#endif
+
+ /* Extract the sequence number */
+ tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ /* If we have flow controlled the peer, ignore any bad I-frames from him */
+ if ((tx_seq != p_fcrb->next_seq_expected) && (p_fcrb->local_busy)) {
+ L2CAP_TRACE_WARNING("Dropping bad I-Frame since we flowed off, tx_seq:%u",
+ tx_seq);
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* Check if tx-sequence is the expected one */
+ if (tx_seq != p_fcrb->next_seq_expected) {
+ num_lost = (tx_seq - p_fcrb->next_seq_expected) & L2CAP_FCR_SEQ_MODULO;
+
+ /* Is the frame a duplicate ? If so, just drop it */
+ if (num_lost >= p_ccb->our_cfg.fcr.tx_win_sz) {
+ /* Duplicate - simply drop it */
+ L2CAP_TRACE_WARNING(
+ "process_i_frame() Dropping Duplicate Frame tx_seq:%u ExpectedTxSeq "
+ "%u",
+ tx_seq, p_fcrb->next_seq_expected);
+ osi_free(p_buf);
+ } else {
+ L2CAP_TRACE_WARNING(
+ "process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u "
+ "Rej: %u SRej: %u",
+ p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected,
+ p_fcrb->rej_sent, p_fcrb->srej_sent);
+
+ if (p_fcrb->srej_sent) {
+ /* If SREJ sent, save the frame for later processing as long as it is in
+ * sequence */
+ next_srej =
+ (((BT_HDR*)fixed_queue_try_peek_last(p_fcrb->srej_rcv_hold_q))
+ ->layer_specific +
+ 1) &
+ L2CAP_FCR_SEQ_MODULO;
+
+ if ((tx_seq == next_srej) &&
+ (fixed_queue_length(p_fcrb->srej_rcv_hold_q) <
+ p_ccb->our_cfg.fcr.tx_win_sz)) {
+ /* If user gave us a pool for held rx buffers, use that */
+ /* TODO: Could that happen? Get rid of this code. */
+ if (p_ccb->ertm_info.fcr_rx_buf_size != L2CAP_FCR_RX_BUF_SIZE) {
+ BT_HDR* p_buf2;
+
+ /* Adjust offset and len so that control word is copied */
+ p_buf->offset -= L2CAP_FCR_OVERHEAD;
+ p_buf->len += L2CAP_FCR_OVERHEAD;
+
+ p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
+
+ if (p_buf2) {
+ osi_free(p_buf);
+ p_buf = p_buf2;
+ }
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ }
+ L2CAP_TRACE_DEBUG(
+ "process_i_frame() Lost: %u tx_seq:%u ExpTxSeq %u Rej: %u "
+ "SRej1",
+ num_lost, tx_seq, p_fcrb->next_seq_expected, p_fcrb->rej_sent);
+
+ p_buf->layer_specific = tx_seq;
+ fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
+ } else {
+ L2CAP_TRACE_WARNING(
+ "process_i_frame() CID: 0x%04x frame dropped in Srej Sent "
+ "next_srej:%u hold_q.count:%u win_sz:%u",
+ p_ccb->local_cid, next_srej,
+ fixed_queue_length(p_fcrb->srej_rcv_hold_q),
+ p_ccb->our_cfg.fcr.tx_win_sz);
+
+ p_fcrb->rej_after_srej = true;
+ osi_free(p_buf);
+ }
+ } else if (p_fcrb->rej_sent) {
+ L2CAP_TRACE_WARNING(
+ "process_i_frame() CID: 0x%04x Lost: %u tx_seq:%u ExpTxSeq %u "
+ "Rej: 1 SRej: %u",
+ p_ccb->local_cid, num_lost, tx_seq, p_fcrb->next_seq_expected,
+ p_fcrb->srej_sent);
+
+ /* If REJ sent, just drop the frame */
+ osi_free(p_buf);
+ } else {
+ L2CAP_TRACE_DEBUG(
+ "process_i_frame() CID: 0x%04x tx_seq:%u ExpTxSeq %u Rej: %u",
+ p_ccb->local_cid, tx_seq, p_fcrb->next_seq_expected,
+ p_fcrb->rej_sent);
+
+ /* If only one lost, we will send SREJ, otherwise we will send REJ */
+ if (num_lost > 1) {
+ osi_free(p_buf);
+ p_fcrb->rej_sent = true;
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_REJ, 0);
+ } else {
+ if (!fixed_queue_is_empty(p_fcrb->srej_rcv_hold_q)) {
+ L2CAP_TRACE_ERROR(
+ "process_i_frame() CID: 0x%04x sending SREJ tx_seq:%d "
+ "hold_q.count:%u",
+ p_ccb->local_cid, tx_seq,
+ fixed_queue_length(p_fcrb->srej_rcv_hold_q));
+ }
+ p_buf->layer_specific = tx_seq;
+ fixed_queue_enqueue(p_fcrb->srej_rcv_hold_q, p_buf);
+ p_fcrb->srej_sent = true;
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_SREJ, 0);
+ }
+ alarm_cancel(p_ccb->fcrb.ack_timer);
+ }
+ }
+ return;
+ }
+
+ /* Seq number is the next expected. Clear possible reject exception in case it
+ * occured */
+ p_fcrb->rej_sent = p_fcrb->srej_sent = false;
+
+ /* Adjust the next_seq, so that if the upper layer sends more data in the
+ callback
+ context, the received frame is acked by an I-frame. */
+ p_fcrb->next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+ /* If any SAR problem in eRTM mode, spec says disconnect. */
+ if (!do_sar_reassembly(p_ccb, p_buf, ctrl_word)) {
+ L2CAP_TRACE_WARNING("process_i_frame() CID: 0x%04x reassembly failed",
+ p_ccb->local_cid);
+ l2cu_disconnect_chnl(p_ccb);
+ return;
+ }
+
+ /* RR optimization - if peer can still send us more, then start an ACK timer
+ */
+ num_to_ack = (p_fcrb->next_seq_expected - p_fcrb->last_ack_sent) &
+ L2CAP_FCR_SEQ_MODULO;
+
+ if ((num_to_ack < p_ccb->fcrb.max_held_acks) && (!p_fcrb->local_busy))
+ delay_ack = true;
+
+ /* We should neve never ack frame if we are not in OPEN state */
+ if ((num_to_ack != 0) && p_ccb->in_use && (p_ccb->chnl_state == CST_OPEN)) {
+ /* If no frames are awaiting transmission or are held, send an RR or RNR
+ * S-frame for ack */
+ if (delay_ack) {
+ /* If it is the first I frame we did not ack, start ack timer */
+ if (!alarm_is_scheduled(p_ccb->fcrb.ack_timer)) {
+ alarm_set_on_queue(p_ccb->fcrb.ack_timer, L2CAP_FCR_ACK_TIMEOUT_MS,
+ l2c_fcrb_ack_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ } else if ((fixed_queue_is_empty(p_ccb->xmit_hold_q) ||
+ l2c_fcr_is_flow_controlled(p_ccb)) &&
+ fixed_queue_is_empty(p_ccb->fcrb.srej_rcv_hold_q)) {
+ if (p_fcrb->local_busy)
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RNR, 0);
+ else
+ l2c_fcr_send_S_frame(p_ccb, L2CAP_FCR_SUP_RR, 0);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function process_stream_frame
+ *
+ * Description This function processes frames in streaming mode
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+static void process_stream_frame(tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+
+ uint16_t ctrl_word;
+ uint16_t fcs;
+ uint8_t* p;
+ uint8_t tx_seq;
+
+ /* Verify FCS if using */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len - L2CAP_FCS_LEN;
+
+ /* Extract and drop the FCS from the packet */
+ STREAM_TO_UINT16(fcs, p);
+ p_buf->len -= L2CAP_FCS_LEN;
+
+ if (l2c_fcr_rx_get_fcs(p_buf) != fcs) {
+ L2CAP_TRACE_WARNING("Rx L2CAP PDU: CID: 0x%04x BAD FCS",
+ p_ccb->local_cid);
+ osi_free(p_buf);
+ return;
+ }
+ }
+
+ /* Get the control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ p_buf->len -= L2CAP_FCR_OVERHEAD;
+ p_buf->offset += L2CAP_FCR_OVERHEAD;
+
+ /* Make sure it is an I-frame */
+ if (ctrl_word & L2CAP_FCR_S_FRAME_BIT) {
+ L2CAP_TRACE_WARNING(
+ "Rx L2CAP PDU: CID: 0x%04x BAD S-frame in streaming mode ctrl_word: "
+ "0x%04x",
+ p_ccb->local_cid, ctrl_word);
+ osi_free(p_buf);
+ return;
+ }
+
+ L2CAP_TRACE_EVENT(
+ "L2CAP eRTM Rx I-frame: cid: 0x%04x Len: %u SAR: %-12s TxSeq: %u "
+ "ReqSeq: %u F: %u",
+ p_ccb->local_cid, p_buf->len,
+ SAR_types[(ctrl_word & L2CAP_FCR_SAR_BITS) >> L2CAP_FCR_SAR_BITS_SHIFT],
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_REQ_SEQ_BITS) >> L2CAP_FCR_REQ_SEQ_BITS_SHIFT,
+ (ctrl_word & L2CAP_FCR_F_BIT) >> L2CAP_FCR_F_BIT_SHIFT);
+
+ /* Extract the sequence number */
+ tx_seq = (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ /* Check if tx-sequence is the expected one */
+ if (tx_seq != p_ccb->fcrb.next_seq_expected) {
+ L2CAP_TRACE_WARNING(
+ "Rx L2CAP PDU: CID: 0x%04x Lost frames Exp: %u Got: %u p_rx_sdu: "
+ "0x%08x",
+ p_ccb->local_cid, p_ccb->fcrb.next_seq_expected, tx_seq,
+ p_ccb->fcrb.p_rx_sdu);
+
+ /* Lost one or more packets, so flush the SAR queue */
+ osi_free_and_reset((void**)&p_ccb->fcrb.p_rx_sdu);
+ }
+
+ p_ccb->fcrb.next_seq_expected = (tx_seq + 1) & L2CAP_FCR_SEQ_MODULO;
+
+ if (!do_sar_reassembly(p_ccb, p_buf, ctrl_word)) {
+ /* Some sort of SAR error, so flush the SAR queue */
+ osi_free_and_reset((void**)&p_ccb->fcrb.p_rx_sdu);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function do_sar_reassembly
+ *
+ * Description Process SAR bits and re-assemble frame
+ *
+ * Returns true if all OK, else false
+ *
+ ******************************************************************************/
+static bool do_sar_reassembly(tL2C_CCB* p_ccb, BT_HDR* p_buf,
+ uint16_t ctrl_word) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_buf != NULL);
+
+ tL2C_FCRB* p_fcrb = &p_ccb->fcrb;
+ uint16_t sar_type = ctrl_word & L2CAP_FCR_SEG_BITS;
+ bool packet_ok = true;
+ uint8_t* p;
+
+ /* Check if the SAR state is correct */
+ if ((sar_type == L2CAP_FCR_UNSEG_SDU) || (sar_type == L2CAP_FCR_START_SDU)) {
+ if (p_fcrb->p_rx_sdu != NULL) {
+ L2CAP_TRACE_WARNING(
+ "SAR - got unexpected unsegmented or start SDU Expected len: %u "
+ "Got so far: %u",
+ p_fcrb->rx_sdu_len, p_fcrb->p_rx_sdu->len);
+
+ packet_ok = false;
+ }
+ /* Check the length of the packet */
+ if ((sar_type == L2CAP_FCR_START_SDU) &&
+ (p_buf->len < L2CAP_SDU_LEN_OVERHEAD)) {
+ L2CAP_TRACE_WARNING("SAR start packet too short: %u", p_buf->len);
+ packet_ok = false;
+ }
+ } else {
+ if (p_fcrb->p_rx_sdu == NULL) {
+ L2CAP_TRACE_WARNING("SAR - got unexpected cont or end SDU");
+ packet_ok = false;
+ }
+ }
+
+ if ((packet_ok) && (sar_type != L2CAP_FCR_UNSEG_SDU)) {
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset;
+
+ /* For start SDU packet, extract the SDU length */
+ if (sar_type == L2CAP_FCR_START_SDU) {
+ /* Get the SDU length */
+ STREAM_TO_UINT16(p_fcrb->rx_sdu_len, p);
+ p_buf->offset += 2;
+ p_buf->len -= 2;
+
+ if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu) {
+ L2CAP_TRACE_WARNING("SAR - SDU len: %u larger than MTU: %u",
+ p_fcrb->rx_sdu_len, p_fcrb->rx_sdu_len);
+ packet_ok = false;
+ } else {
+ p_fcrb->p_rx_sdu = (BT_HDR*)osi_malloc(L2CAP_MAX_BUF_SIZE);
+ p_fcrb->p_rx_sdu->offset = OBX_BUF_MIN_OFFSET;
+ p_fcrb->p_rx_sdu->len = 0;
+ }
+ }
+
+ if (packet_ok) {
+ if ((p_fcrb->p_rx_sdu->len + p_buf->len) > p_fcrb->rx_sdu_len) {
+ L2CAP_TRACE_ERROR(
+ "SAR - SDU len exceeded Type: %u Lengths: %u %u %u", sar_type,
+ p_fcrb->p_rx_sdu->len, p_buf->len, p_fcrb->rx_sdu_len);
+ packet_ok = false;
+ } else if ((sar_type == L2CAP_FCR_END_SDU) &&
+ ((p_fcrb->p_rx_sdu->len + p_buf->len) != p_fcrb->rx_sdu_len)) {
+ L2CAP_TRACE_WARNING("SAR - SDU end rcvd but SDU incomplete: %u %u %u",
+ p_fcrb->p_rx_sdu->len, p_buf->len,
+ p_fcrb->rx_sdu_len);
+ packet_ok = false;
+ } else {
+ memcpy(((uint8_t*)(p_fcrb->p_rx_sdu + 1)) + p_fcrb->p_rx_sdu->offset +
+ p_fcrb->p_rx_sdu->len,
+ p, p_buf->len);
+
+ p_fcrb->p_rx_sdu->len += p_buf->len;
+
+ osi_free(p_buf);
+ p_buf = NULL;
+
+ if (sar_type == L2CAP_FCR_END_SDU) {
+ p_buf = p_fcrb->p_rx_sdu;
+ p_fcrb->p_rx_sdu = NULL;
+ }
+ }
+ }
+ }
+
+ if (packet_ok == false) {
+ osi_free(p_buf);
+ } else if (p_buf != NULL) {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_ccb->local_cid < L2CAP_BASE_APPL_CID &&
+ (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
+ p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)) {
+ if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
+ .pL2CA_FixedData_Cb)
+ (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL]
+ .pL2CA_FixedData_Cb)(p_ccb->local_cid,
+ p_ccb->p_lcb->remote_bd_addr, p_buf);
+ } else
+#endif
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_buf);
+ }
+
+ return (packet_ok);
+}
+
+/*******************************************************************************
+ *
+ * Function retransmit_i_frames
+ *
+ * Description This function retransmits i-frames awaiting acks.
+ *
+ * Returns bool - true if retransmitted
+ *
+ ******************************************************************************/
+static bool retransmit_i_frames(tL2C_CCB* p_ccb, uint8_t tx_seq) {
+ CHECK(p_ccb != NULL);
+
+ BT_HDR* p_buf = NULL;
+ uint8_t* p;
+ uint8_t buf_seq;
+ uint16_t ctrl_word;
+
+ if ((!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) &&
+ (p_ccb->peer_cfg.fcr.max_transmit != 0) &&
+ (p_ccb->fcrb.num_tries >= p_ccb->peer_cfg.fcr.max_transmit)) {
+ L2CAP_TRACE_EVENT(
+ "Max Tries Exceeded: (last_acq: %d CID: 0x%04x num_tries: %u (max: "
+ "%u) ack_q_count: %u",
+ p_ccb->fcrb.last_rx_ack, p_ccb->local_cid, p_ccb->fcrb.num_tries,
+ p_ccb->peer_cfg.fcr.max_transmit,
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+
+ l2cu_disconnect_chnl(p_ccb);
+ return (false);
+ }
+
+ /* tx_seq indicates whether to retransmit a specific sequence or all (if ==
+ * L2C_FCR_RETX_ALL_PKTS) */
+ list_t* list_ack = NULL;
+ const list_node_t* node_ack = NULL;
+ if (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q)) {
+ list_ack = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
+ node_ack = list_begin(list_ack);
+ }
+ if (tx_seq != L2C_FCR_RETX_ALL_PKTS) {
+ /* If sending only one, the sequence number tells us which one. Look for it.
+ */
+ if (list_ack != NULL) {
+ for (; node_ack != list_end(list_ack); node_ack = list_next(node_ack)) {
+ p_buf = (BT_HDR*)list_node(node_ack);
+ /* Get the old control word */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + L2CAP_PKT_OVERHEAD;
+
+ STREAM_TO_UINT16(ctrl_word, p);
+
+ buf_seq =
+ (ctrl_word & L2CAP_FCR_TX_SEQ_BITS) >> L2CAP_FCR_TX_SEQ_BITS_SHIFT;
+
+ L2CAP_TRACE_DEBUG(
+ "retransmit_i_frames() cur seq: %u looking for: %u", buf_seq,
+ tx_seq);
+
+ if (tx_seq == buf_seq) break;
+ }
+ }
+
+ if (!p_buf) {
+ L2CAP_TRACE_ERROR("retransmit_i_frames() UNKNOWN seq: %u q_count: %u",
+ tx_seq,
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q));
+ return (true);
+ }
+ } else {
+ // Iterate though list and flush the amount requested from
+ // the transmit data queue that satisfy the layer and event conditions.
+ for (list_node_t* node_tmp = list_begin(p_ccb->p_lcb->link_xmit_data_q);
+ node_tmp != list_end(p_ccb->p_lcb->link_xmit_data_q);) {
+ BT_HDR* p_tmp = (BT_HDR*)list_node(node_tmp);
+ node_tmp = list_next(node_tmp);
+
+ /* Do not flush other CIDs or partial segments */
+ if ((p_tmp->layer_specific == 0) && (p_tmp->event == p_ccb->local_cid)) {
+ list_remove(p_ccb->p_lcb->link_xmit_data_q, p_tmp);
+ osi_free(p_tmp);
+ }
+ }
+
+ /* Also flush our retransmission queue */
+ while (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q))
+ osi_free(fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q));
+
+ if (list_ack != NULL) node_ack = list_begin(list_ack);
+ }
+
+ if (list_ack != NULL) {
+ while (node_ack != list_end(list_ack)) {
+ p_buf = (BT_HDR*)list_node(node_ack);
+ node_ack = list_next(node_ack);
+
+ BT_HDR* p_buf2 = l2c_fcr_clone_buf(p_buf, p_buf->offset, p_buf->len);
+ if (p_buf2) {
+ p_buf2->layer_specific = p_buf->layer_specific;
+
+ fixed_queue_enqueue(p_ccb->fcrb.retrans_q, p_buf2);
+ }
+
+ if ((tx_seq != L2C_FCR_RETX_ALL_PKTS) || (p_buf2 == NULL)) break;
+ }
+ }
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+
+ if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q)) {
+ p_ccb->fcrb.num_tries++;
+ l2c_fcr_start_timer(p_ccb);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_get_next_xmit_sdu_seg
+ *
+ * Description Get the next SDU segment to transmit.
+ *
+ * Returns pointer to buffer with segment or NULL
+ *
+ ******************************************************************************/
+BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
+ uint16_t max_packet_length) {
+ CHECK(p_ccb != NULL);
+
+ bool first_seg = false, /* The segment is the first part of data */
+ mid_seg = false, /* The segment is the middle part of data */
+ last_seg = false; /* The segment is the last part of data */
+ uint16_t sdu_len = 0;
+ BT_HDR *p_buf, *p_xmit;
+ uint8_t* p;
+ uint16_t max_pdu = p_ccb->tx_mps /* Needed? - L2CAP_MAX_HEADER_FCS*/;
+
+ /* If there is anything in the retransmit queue, that goes first
+ */
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->fcrb.retrans_q);
+ if (p_buf != NULL) {
+ /* Update Rx Seq and FCS if we acked some packets while this one was queued
+ */
+ prepare_I_frame(p_ccb, p_buf, true);
+
+ p_buf->event = p_ccb->local_cid;
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.pkts_retransmitted++;
+ p_ccb->fcrb.ertm_pkt_counts[0]++;
+ p_ccb->fcrb.ertm_byte_counts[0] += (p_buf->len - 8);
+#endif
+ return (p_buf);
+ }
+
+ /* For BD/EDR controller, max_packet_length is set to 0 */
+ /* For AMP controller, max_packet_length is set by available blocks */
+ if ((max_packet_length > L2CAP_MAX_HEADER_FCS) &&
+ (max_pdu + L2CAP_MAX_HEADER_FCS > max_packet_length)) {
+ max_pdu = max_packet_length - L2CAP_MAX_HEADER_FCS;
+ }
+
+ p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+
+ /* If there is more data than the MPS, it requires segmentation */
+ if (p_buf->len > max_pdu) {
+ /* We are using the "event" field to tell is if we already started
+ * segmentation */
+ if (p_buf->event == 0) {
+ first_seg = true;
+ sdu_len = p_buf->len;
+ } else
+ mid_seg = true;
+
+ /* Get a new buffer and copy the data that can be sent in a PDU */
+ p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET + L2CAP_SDU_LEN_OFFSET,
+ max_pdu);
+
+ if (p_xmit != NULL) {
+ p_buf->event = p_ccb->local_cid;
+ p_xmit->event = p_ccb->local_cid;
+
+ p_buf->len -= max_pdu;
+ p_buf->offset += max_pdu;
+
+ /* copy PBF setting */
+ p_xmit->layer_specific = p_buf->layer_specific;
+ } else /* Should never happen if the application has configured buffers
+ correctly */
+ {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - cannot get buffer for segmentation, max_pdu: %u", max_pdu);
+ return (NULL);
+ }
+ } else /* Use the original buffer if no segmentation, or the last segment */
+ {
+ p_xmit = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+
+ if (p_xmit->event != 0) last_seg = true;
+
+ p_xmit->event = p_ccb->local_cid;
+ }
+
+ /* Step back to add the L2CAP headers */
+ p_xmit->offset -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD);
+ p_xmit->len += L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD;
+
+ if (first_seg) {
+ p_xmit->offset -= L2CAP_SDU_LEN_OVERHEAD;
+ p_xmit->len += L2CAP_SDU_LEN_OVERHEAD;
+ }
+
+ /* Set the pointer to the beginning of the data */
+ p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
+
+ /* Now the L2CAP header */
+
+ /* Note: if FCS has to be included then the length is recalculated later */
+ UINT16_TO_STREAM(p, p_xmit->len - L2CAP_PKT_OVERHEAD);
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+
+ if (first_seg) {
+ /* Skip control word and add SDU length */
+ p += 2;
+ UINT16_TO_STREAM(p, sdu_len);
+
+ /* We will store the SAR type in layer-specific */
+ /* layer_specific is shared with flushable flag(bits 0-1), don't clear it */
+ p_xmit->layer_specific |= L2CAP_FCR_START_SDU;
+
+ first_seg = false;
+ } else if (mid_seg)
+ p_xmit->layer_specific |= L2CAP_FCR_CONT_SDU;
+ else if (last_seg)
+ p_xmit->layer_specific |= L2CAP_FCR_END_SDU;
+ else
+ p_xmit->layer_specific |= L2CAP_FCR_UNSEG_SDU;
+
+ prepare_I_frame(p_ccb, p_xmit, false);
+
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ BT_HDR* p_wack =
+ l2c_fcr_clone_buf(p_xmit, HCI_DATA_PREAMBLE_SIZE, p_xmit->len);
+
+ if (!p_wack) {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - no buffer for xmit cloning, CID: 0x%04x Length: %u",
+ p_ccb->local_cid, p_xmit->len);
+
+ /* We will not save the FCS in case we reconfigure and change options */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) p_xmit->len -= L2CAP_FCS_LEN;
+
+ /* Pretend we sent it and it got lost */
+ fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_xmit);
+ return (NULL);
+ } else {
+#if (L2CAP_ERTM_STATS == TRUE)
+ /* set timestamp at the end of tx I-frame to get acking delay */
+ /*
+ * NOTE: Here we assume the allocate buffer is large enough
+ * to include extra 4 octets at the end.
+ */
+ p = ((uint8_t*)(p_wack + 1)) + p_wack->offset + p_wack->len;
+ UINT32_TO_STREAM(p, time_get_os_boottime_ms());
+#endif
+ /* We will not save the FCS in case we reconfigure and change options */
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) p_wack->len -= L2CAP_FCS_LEN;
+
+ p_wack->layer_specific = p_xmit->layer_specific;
+ fixed_queue_enqueue(p_ccb->fcrb.waiting_for_ack_q, p_wack);
+ }
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ p_ccb->fcrb.ertm_pkt_counts[0]++;
+ p_ccb->fcrb.ertm_byte_counts[0] += (p_xmit->len - 8);
+#endif
+ }
+
+ return (p_xmit);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_lcc_get_next_xmit_sdu_seg
+ *
+ * Description Get the next SDU segment to transmit for LE connection
+ * oriented channel
+ *
+ * Returns pointer to buffer with segment or NULL
+ *
+ ******************************************************************************/
+BT_HDR* l2c_lcc_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
+ uint16_t max_packet_length) {
+ bool first_seg = false; /* The segment is the first part of data */
+ bool last_seg = false; /* The segment is the last part of data */
+ uint16_t no_of_bytes_to_send = 0;
+ uint16_t sdu_len = 0;
+ BT_HDR *p_buf, *p_xmit;
+ uint8_t* p;
+ uint16_t max_pdu = p_ccb->peer_conn_cfg.mps;
+
+ p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->xmit_hold_q);
+
+ /* We are using the "event" field to tell is if we already started
+ * segmentation */
+ if (p_buf->event == 0) {
+ first_seg = true;
+ sdu_len = p_buf->len;
+ if (p_buf->len <= (max_pdu - L2CAP_LCC_SDU_LENGTH)) {
+ last_seg = true;
+ no_of_bytes_to_send = p_buf->len;
+ } else
+ no_of_bytes_to_send = max_pdu - L2CAP_LCC_SDU_LENGTH;
+ } else if (p_buf->len <= max_pdu) {
+ last_seg = true;
+ no_of_bytes_to_send = p_buf->len;
+ } else {
+ /* Middle Packet */
+ no_of_bytes_to_send = max_pdu;
+ }
+
+ /* Get a new buffer and copy the data that can be sent in a PDU */
+ if (first_seg == true)
+ p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_LCC_OFFSET, no_of_bytes_to_send);
+ else
+ p_xmit = l2c_fcr_clone_buf(p_buf, L2CAP_MIN_OFFSET, no_of_bytes_to_send);
+
+ if (p_xmit != NULL) {
+ p_buf->event = p_ccb->local_cid;
+ p_xmit->event = p_ccb->local_cid;
+
+ if (first_seg == true) {
+ p_xmit->offset -= L2CAP_LCC_SDU_LENGTH; /* for writing the SDU length. */
+ p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
+ UINT16_TO_STREAM(p, sdu_len);
+ p_xmit->len += L2CAP_LCC_SDU_LENGTH;
+ }
+
+ p_buf->len -= no_of_bytes_to_send;
+ p_buf->offset += no_of_bytes_to_send;
+
+ /* copy PBF setting */
+ p_xmit->layer_specific = p_buf->layer_specific;
+
+ } else /* Should never happen if the application has configured buffers
+ correctly */
+ {
+ L2CAP_TRACE_ERROR("L2CAP - cannot get buffer, for segmentation");
+ return (NULL);
+ }
+
+ if (last_seg == true) {
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+ osi_free(p_buf);
+ }
+
+ /* Step back to add the L2CAP headers */
+ p_xmit->offset -= L2CAP_PKT_OVERHEAD;
+ p_xmit->len += L2CAP_PKT_OVERHEAD;
+
+ /* Set the pointer to the beginning of the data */
+ p = (uint8_t*)(p_xmit + 1) + p_xmit->offset;
+
+ /* Note: if FCS has to be included then the length is recalculated later */
+ UINT16_TO_STREAM(p, p_xmit->len - L2CAP_PKT_OVERHEAD);
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ return (p_xmit);
+}
+
+/*******************************************************************************
+ * Configuration negotiation functions
+ *
+ * The following functions are used in negotiating channel modes during
+ * configuration
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_chk_chan_modes
+ *
+ * Description Validates and adjusts if necessary, the FCR options
+ * based on remote EXT features.
+ *
+ * Note: This assumes peer EXT Features have been received.
+ * Basic mode is used if FCR Options have not been received
+ *
+ * Returns uint8_t - nonzero if can continue, '0' if no compatible
+ * channels
+ *
+ ******************************************************************************/
+uint8_t l2c_fcr_chk_chan_modes(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+
+ /* Remove nonbasic options that the peer does not support */
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_ENH_RETRANS))
+ p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_ERTM;
+
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_STREAM_MODE))
+ p_ccb->ertm_info.allowed_modes &= ~L2CAP_FCR_CHAN_OPT_STREAM;
+
+ /* At least one type needs to be set (Basic, ERTM, STM) to continue */
+ if (!p_ccb->ertm_info.allowed_modes) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - Peer does not support our desired channel types");
+ }
+
+ return (p_ccb->ertm_info.allowed_modes);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_adj_our_req_options
+ *
+ * Description Validates and sets up the FCR options passed in from
+ * L2CA_ConfigReq based on remote device's features.
+ *
+ * Returns true if no errors, Otherwise false
+ *
+ ******************************************************************************/
+bool l2c_fcr_adj_our_req_options(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_cfg != NULL);
+
+ tL2CAP_FCR_OPTS* p_fcr = &p_cfg->fcr;
+
+ if (p_fcr->mode != p_ccb->ertm_info.preferred_mode) {
+ L2CAP_TRACE_WARNING(
+ "l2c_fcr_adj_our_req_options - preferred_mode (%d), does not match "
+ "mode (%d)",
+ p_ccb->ertm_info.preferred_mode, p_fcr->mode);
+
+ /* The preferred mode is passed in through tL2CAP_ERTM_INFO, so override
+ * this one */
+ p_fcr->mode = p_ccb->ertm_info.preferred_mode;
+ }
+
+ /* If upper layer did not request eRTM mode, BASIC must be used */
+ if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) {
+ if (p_cfg->fcr_present && p_fcr->mode != L2CAP_FCR_BASIC_MODE) {
+ L2CAP_TRACE_WARNING(
+ "l2c_fcr_adj_our_req_options (mode %d): ERROR: No FCR options set "
+ "using BASIC mode",
+ p_fcr->mode);
+ }
+ p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+ }
+
+ /* Process the FCR options if initial channel bring-up (not a reconfig
+ *request)
+ ** Determine initial channel mode to try based on our options and remote's
+ *features
+ */
+ if (p_cfg->fcr_present && !(p_ccb->config_done & RECONFIG_FLAG)) {
+ /* We need to have at least one mode type common with the peer */
+ if (!l2c_fcr_chk_chan_modes(p_ccb)) {
+ /* Two channels have incompatible supported types */
+ l2cu_disconnect_chnl(p_ccb);
+ return (false);
+ }
+
+ /* Basic is the only common channel mode between the two devices */
+ else if (p_ccb->ertm_info.allowed_modes == L2CAP_FCR_CHAN_OPT_BASIC) {
+ /* We only want to try Basic, so bypass sending the FCR options entirely
+ */
+ p_cfg->fcr_present = false;
+ p_cfg->fcs_present = false; /* Illegal to use FCS option in basic mode */
+ p_cfg->ext_flow_spec_present =
+ false; /* Illegal to use extended flow spec in basic mode */
+ }
+
+ /* We have at least one non-basic mode available
+ * Override mode from available mode options based on preference, if needed
+ */
+ else {
+ /* If peer does not support STREAMING, try ERTM */
+ if (p_fcr->mode == L2CAP_FCR_STREAM_MODE &&
+ !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_STREAM)) {
+ L2CAP_TRACE_DEBUG(
+ "L2C CFG: mode is STREAM, but peer does not support; Try ERTM");
+ p_fcr->mode = L2CAP_FCR_ERTM_MODE;
+ }
+
+ /* If peer does not support ERTM, try BASIC (will support this if made it
+ * here in the code) */
+ if (p_fcr->mode == L2CAP_FCR_ERTM_MODE &&
+ !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
+ L2CAP_TRACE_DEBUG(
+ "L2C CFG: mode is ERTM, but peer does not support; Try BASIC");
+ p_fcr->mode = L2CAP_FCR_BASIC_MODE;
+ }
+ }
+
+ if (p_fcr->mode != L2CAP_FCR_BASIC_MODE) {
+ /* MTU must be smaller than buffer size */
+ if ((p_cfg->mtu_present) && (p_cfg->mtu > p_ccb->max_rx_mtu)) {
+ L2CAP_TRACE_WARNING("L2CAP - MTU: %u larger than buf size: %u",
+ p_cfg->mtu, p_ccb->max_rx_mtu);
+ return (false);
+ }
+
+ /* application want to use the default MPS */
+ if (p_fcr->mps == L2CAP_DEFAULT_ERM_MPS) {
+ p_fcr->mps = L2CAP_MPS_OVER_BR_EDR;
+ }
+ /* MPS must be less than MTU */
+ else if (p_fcr->mps > p_ccb->max_rx_mtu) {
+ L2CAP_TRACE_WARNING("L2CAP - MPS %u invalid MTU: %u", p_fcr->mps,
+ p_ccb->max_rx_mtu);
+ return (false);
+ }
+
+ /* We always initially read into the HCI buffer pool, so make sure it fits
+ */
+ if (p_fcr->mps > (L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS))
+ p_fcr->mps = L2CAP_MTU_SIZE - L2CAP_MAX_HEADER_FCS;
+ } else {
+ p_cfg->fcs_present = false; /* Illegal to use FCS option in basic mode */
+ p_cfg->ext_flow_spec_present =
+ false; /* Illegal to use extended flow spec in basic mode */
+ }
+
+ p_ccb->our_cfg.fcr = *p_fcr;
+ } else /* Not sure how to send a reconfiguration(??) should fcr be included?
+ */
+ {
+ p_ccb->our_cfg.fcr_present = false;
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_adj_monitor_retran_timeout
+ *
+ * Description Overrides monitor/retrans timer value based on controller
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2c_fcr_adj_monitor_retran_timeout(tL2C_CCB* p_ccb) {
+ CHECK(p_ccb != NULL);
+
+ /* adjust our monitor/retran timeout */
+ if (p_ccb->out_cfg_fcr_present) {
+ /*
+ ** if we requestd ERTM or accepted ERTM
+ ** We may accept ERTM even if we didn't request ERTM, in case of requesting
+ *STREAM
+ */
+ if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) ||
+ (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)) {
+ /* upper layer setting is ignored */
+ p_ccb->our_cfg.fcr.mon_tout = L2CAP_MIN_MONITOR_TOUT;
+ p_ccb->our_cfg.fcr.rtrans_tout = L2CAP_MIN_RETRANS_TOUT;
+ } else {
+ p_ccb->our_cfg.fcr.mon_tout = 0;
+ p_ccb->our_cfg.fcr.rtrans_tout = 0;
+ }
+
+ L2CAP_TRACE_DEBUG(
+ "l2c_fcr_adj_monitor_retran_timeout: mon_tout:%d, rtrans_tout:%d",
+ p_ccb->our_cfg.fcr.mon_tout, p_ccb->our_cfg.fcr.rtrans_tout);
+ }
+}
+/*******************************************************************************
+ *
+ * Function l2c_fcr_adj_our_rsp_options
+ *
+ * Description Overrides any neccesary FCR options passed in from
+ * L2CA_ConfigRsp based on our FCR options.
+ * Only makes adjustments if channel is in ERTM mode.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2c_fcr_adj_our_rsp_options(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_cfg != NULL);
+
+ /* adjust our monitor/retran timeout */
+ l2c_fcr_adj_monitor_retran_timeout(p_ccb);
+
+ p_cfg->fcr_present = p_ccb->out_cfg_fcr_present;
+
+ if (p_cfg->fcr_present) {
+ /* Temporary - until a better algorithm is implemented */
+ /* If peer's tx_wnd_sz requires too many buffers for us to support, then
+ * adjust it. For now, respond with our own tx_wnd_sz. */
+ /* Note: peer is not guaranteed to obey our adjustment */
+ if (p_ccb->peer_cfg.fcr.tx_win_sz > p_ccb->our_cfg.fcr.tx_win_sz) {
+ L2CAP_TRACE_DEBUG("%s: adjusting requested tx_win_sz from %i to %i",
+ __func__, p_ccb->peer_cfg.fcr.tx_win_sz,
+ p_ccb->our_cfg.fcr.tx_win_sz);
+ p_ccb->peer_cfg.fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+ }
+
+ p_cfg->fcr.mode = p_ccb->peer_cfg.fcr.mode;
+ p_cfg->fcr.tx_win_sz = p_ccb->peer_cfg.fcr.tx_win_sz;
+ p_cfg->fcr.max_transmit = p_ccb->peer_cfg.fcr.max_transmit;
+ p_cfg->fcr.mps = p_ccb->peer_cfg.fcr.mps;
+ p_cfg->fcr.rtrans_tout = p_ccb->our_cfg.fcr.rtrans_tout;
+ p_cfg->fcr.mon_tout = p_ccb->our_cfg.fcr.mon_tout;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_renegotiate_chan
+ *
+ * Description Called upon unsuccessful peer response to config request.
+ * If the error is because of the channel mode, it will try
+ * to resend using another supported optional channel.
+ *
+ * Returns true if resent configuration, False if channel matches or
+ * cannot match.
+ *
+ ******************************************************************************/
+bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_cfg != NULL);
+
+ uint8_t peer_mode = p_ccb->our_cfg.fcr.mode;
+ bool can_renegotiate;
+
+ /* Skip if this is a reconfiguration from OPEN STATE or if FCR is not returned
+ */
+ if (!p_cfg->fcr_present || (p_ccb->config_done & RECONFIG_FLAG))
+ return (false);
+
+ /* Only retry if there are more channel options to try */
+ if (p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS) {
+ peer_mode = (p_cfg->fcr_present) ? p_cfg->fcr.mode : L2CAP_FCR_BASIC_MODE;
+
+ if (p_ccb->our_cfg.fcr.mode != peer_mode) {
+ if ((--p_ccb->fcr_cfg_tries) == 0) {
+ p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+ L2CAP_TRACE_WARNING("l2c_fcr_renegotiate_chan (Max retries exceeded)");
+ }
+
+ can_renegotiate = false;
+
+ /* Try another supported mode if available based on our last attempted
+ * channel */
+ switch (p_ccb->our_cfg.fcr.mode) {
+ /* Our Streaming mode request was unnacceptable; try ERTM or Basic */
+ case L2CAP_FCR_STREAM_MODE:
+ /* Peer wants ERTM and we support it */
+ if ((peer_mode == L2CAP_FCR_ERTM_MODE) &&
+ (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
+ L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying ERTM)");
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
+ can_renegotiate = true;
+ } else /* Falls through */
+
+ case L2CAP_FCR_ERTM_MODE: {
+ /* We can try basic for any other peer mode if we support it */
+ if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
+ L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying Basic)");
+ can_renegotiate = true;
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+ } break;
+
+ default:
+ /* All other scenarios cannot be renegotiated */
+ break;
+ }
+
+ if (can_renegotiate) {
+ p_ccb->our_cfg.fcr_present = true;
+
+ if (p_ccb->our_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
+ p_ccb->our_cfg.fcs_present = false;
+ p_ccb->our_cfg.ext_flow_spec_present = false;
+
+ /* Basic Mode uses ACL Data Pool, make sure the MTU fits */
+ if ((p_cfg->mtu_present) && (p_cfg->mtu > L2CAP_MTU_SIZE)) {
+ L2CAP_TRACE_WARNING("L2CAP - adjust MTU: %u too large", p_cfg->mtu);
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+ }
+ }
+
+ l2cu_process_our_cfg_req(p_ccb, &p_ccb->our_cfg);
+ l2cu_send_peer_config_req(p_ccb, &p_ccb->our_cfg);
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ return (true);
+ }
+ }
+ }
+
+ /* Disconnect if the channels do not match */
+ if (p_ccb->our_cfg.fcr.mode != peer_mode) {
+ L2CAP_TRACE_WARNING("L2C CFG: Channels incompatible (local %d, peer %d)",
+ p_ccb->our_cfg.fcr.mode, peer_mode);
+ l2cu_disconnect_chnl(p_ccb);
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_fcr_process_peer_cfg_req
+ *
+ * Description This function is called to process the FCR options passed
+ * in the peer's configuration request.
+ *
+ * Returns uint8_t - L2CAP_PEER_CFG_OK, L2CAP_PEER_CFG_UNACCEPTABLE,
+ * or L2CAP_PEER_CFG_DISCONNECT.
+ *
+ ******************************************************************************/
+uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ CHECK(p_ccb != NULL);
+ CHECK(p_cfg != NULL);
+
+ uint16_t max_retrans_size;
+ uint8_t fcr_ok = L2CAP_PEER_CFG_OK;
+
+ p_ccb->p_lcb->w4_info_rsp =
+ false; /* Handles T61x SonyEricsson Bug in Info Request */
+
+ L2CAP_TRACE_EVENT(
+ "l2c_fcr_process_peer_cfg_req() CFG fcr_present:%d fcr.mode:%d CCB FCR "
+ "mode:%d preferred: %u allowed:%u",
+ p_cfg->fcr_present, p_cfg->fcr.mode, p_ccb->our_cfg.fcr.mode,
+ p_ccb->ertm_info.preferred_mode, p_ccb->ertm_info.allowed_modes);
+
+ /* If Peer wants basic, we are done (accept it or disconnect) */
+ if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE) {
+ /* If we do not allow basic, disconnect */
+ if (!(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC))
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ }
+
+ /* Need to negotiate if our modes are not the same */
+ else if (p_cfg->fcr.mode != p_ccb->ertm_info.preferred_mode) {
+ /* If peer wants a mode that we don't support then retry our mode (ex.
+ *rtx/flc), OR
+ ** If we want ERTM and they wanted streaming retry our mode.
+ ** Note: If we have already determined they support our mode previously
+ ** from their EXF mask.
+ */
+ if ((((1 << p_cfg->fcr.mode) & L2CAP_FCR_CHAN_OPT_ALL_MASK) == 0) ||
+ (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_ERTM_MODE)) {
+ p_cfg->fcr.mode = p_ccb->our_cfg.fcr.mode;
+ p_cfg->fcr.tx_win_sz = p_ccb->our_cfg.fcr.tx_win_sz;
+ p_cfg->fcr.max_transmit = p_ccb->our_cfg.fcr.max_transmit;
+ fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+ }
+
+ /* If we wanted basic, then try to renegotiate it */
+ else if (p_ccb->ertm_info.preferred_mode == L2CAP_FCR_BASIC_MODE) {
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+ p_cfg->fcr.rtrans_tout = p_cfg->fcr.mon_tout = p_cfg->fcr.mps = 0;
+ p_ccb->our_cfg.fcr.rtrans_tout = p_ccb->our_cfg.fcr.mon_tout =
+ p_ccb->our_cfg.fcr.mps = 0;
+ fcr_ok = L2CAP_PEER_CFG_UNACCEPTABLE;
+ }
+
+ /* Only other valid case is if they want ERTM and we wanted STM which should
+ be
+ accepted if we support it; otherwise the channel should be disconnected
+ */
+ else if ((p_cfg->fcr.mode != L2CAP_FCR_ERTM_MODE) ||
+ !(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ }
+ }
+
+ /* Configuration for FCR channels so make any adjustments and fwd to upper
+ * layer */
+ if (fcr_ok == L2CAP_PEER_CFG_OK) {
+ /* by default don't need to send params in the response */
+ p_ccb->out_cfg_fcr_present = false;
+
+ /* Make any needed adjustments for the response to the peer */
+ if (p_cfg->fcr_present && p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ /* Peer desires to bypass FCS check, and streaming or ERTM mode */
+ if (p_cfg->fcs_present) {
+ p_ccb->peer_cfg.fcs = p_cfg->fcs;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCS;
+ if (p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+ p_ccb->bypass_fcs |= L2CAP_CFG_FCS_PEER;
+ }
+
+ max_retrans_size = p_ccb->ertm_info.fcr_tx_buf_size - sizeof(BT_HDR) -
+ L2CAP_MIN_OFFSET - L2CAP_SDU_LEN_OFFSET -
+ L2CAP_FCS_LEN;
+
+ /* Ensure the MPS is not bigger than the MTU */
+ if ((p_cfg->fcr.mps == 0) || (p_cfg->fcr.mps > p_ccb->peer_cfg.mtu)) {
+ p_cfg->fcr.mps = p_ccb->peer_cfg.mtu;
+ p_ccb->out_cfg_fcr_present = true;
+ }
+
+ /* Ensure the MPS is not bigger than our retransmission buffer */
+ if (p_cfg->fcr.mps > max_retrans_size) {
+ L2CAP_TRACE_DEBUG("CFG: Overriding MPS to %d (orig %d)",
+ max_retrans_size, p_cfg->fcr.mps);
+
+ p_cfg->fcr.mps = max_retrans_size;
+ p_ccb->out_cfg_fcr_present = true;
+ }
+
+ if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE ||
+ p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE) {
+ /* Always respond with FCR ERTM parameters */
+ p_ccb->out_cfg_fcr_present = true;
+ }
+ }
+
+ /* Everything ok, so save the peer's adjusted fcr options */
+ p_ccb->peer_cfg.fcr = p_cfg->fcr;
+
+ if (p_cfg->fcr_present) p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FCR;
+ } else if (fcr_ok == L2CAP_PEER_CFG_UNACCEPTABLE) {
+ /* Allow peer only one retry for mode */
+ if (p_ccb->peer_cfg_already_rejected)
+ fcr_ok = L2CAP_PEER_CFG_DISCONNECT;
+ else
+ p_ccb->peer_cfg_already_rejected = true;
+ }
+
+ return (fcr_ok);
+}
+
+#if (L2CAP_ERTM_STATS == TRUE)
+/*******************************************************************************
+ *
+ * Function l2c_fcr_collect_ack_delay
+ *
+ * Description collect throughput, delay, queue size of waiting ack
+ *
+ * Parameters
+ * tL2C_CCB
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_fcr_collect_ack_delay(tL2C_CCB* p_ccb, uint8_t num_bufs_acked) {
+ uint32_t index;
+ BT_HDR* p_buf;
+ uint8_t* p;
+ uint32_t timestamp, delay;
+ uint8_t xx;
+ uint8_t str[120];
+
+ index = p_ccb->fcrb.ack_delay_avg_index;
+
+ /* update sum, max and min of waiting for ack queue size */
+ p_ccb->fcrb.ack_q_count_avg[index] +=
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+ if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) >
+ p_ccb->fcrb.ack_q_count_max[index])
+ p_ccb->fcrb.ack_q_count_max[index] =
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+ if (fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q) <
+ p_ccb->fcrb.ack_q_count_min[index])
+ p_ccb->fcrb.ack_q_count_min[index] =
+ fixed_queue_length(p_ccb->fcrb.waiting_for_ack_q);
+
+ /* update sum, max and min of round trip delay of acking */
+ list_t* list = NULL;
+ if (!fixed_queue_is_empty(p_ccb->fcrb.waiting_for_ack_q))
+ list = fixed_queue_get_list(p_ccb->fcrb.waiting_for_ack_q);
+ if (list != NULL) {
+ for (const list_node_t *node = list_begin(list), xx = 0;
+ (node != list_end(list)) && (xx < num_bufs_acked);
+ node = list_next(node), xx++) {
+ p_buf = list_node(node);
+ /* adding up length of acked I-frames to get throughput */
+ p_ccb->fcrb.throughput[index] += p_buf->len - 8;
+
+ if (xx == num_bufs_acked - 1) {
+ /* get timestamp from tx I-frame that receiver is acking */
+ p = ((uint8_t*)(p_buf + 1)) + p_buf->offset + p_buf->len;
+ if (p_ccb->bypass_fcs != L2CAP_BYPASS_FCS) {
+ p += L2CAP_FCS_LEN;
+ }
+
+ STREAM_TO_UINT32(timestamp, p);
+ delay = time_get_os_boottime_ms() - timestamp;
+
+ p_ccb->fcrb.ack_delay_avg[index] += delay;
+ if (delay > p_ccb->fcrb.ack_delay_max[index])
+ p_ccb->fcrb.ack_delay_max[index] = delay;
+ if (delay < p_ccb->fcrb.ack_delay_min[index])
+ p_ccb->fcrb.ack_delay_min[index] = delay;
+ }
+ }
+ }
+
+ p_ccb->fcrb.ack_delay_avg_count++;
+
+ /* calculate average and initialize next avg, min and max */
+ if (p_ccb->fcrb.ack_delay_avg_count > L2CAP_ERTM_STATS_AVG_NUM_SAMPLES) {
+ p_ccb->fcrb.ack_delay_avg_count = 0;
+
+ p_ccb->fcrb.ack_q_count_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+ p_ccb->fcrb.ack_delay_avg[index] /= L2CAP_ERTM_STATS_AVG_NUM_SAMPLES;
+
+ /* calculate throughput */
+ timestamp = time_get_os_boottime_ms();
+ if (timestamp - p_ccb->fcrb.throughput_start > 0)
+ p_ccb->fcrb.throughput[index] /=
+ (timestamp - p_ccb->fcrb.throughput_start);
+
+ p_ccb->fcrb.throughput_start = timestamp;
+
+ snprintf(
+ str, sizeof(str),
+ "[%02u] throughput: %5u, ack_delay avg:%3u, min:%3u, max:%3u, "
+ "ack_q_count avg:%3u, min:%3u, max:%3u",
+ index, p_ccb->fcrb.throughput[index], p_ccb->fcrb.ack_delay_avg[index],
+ p_ccb->fcrb.ack_delay_min[index], p_ccb->fcrb.ack_delay_max[index],
+ p_ccb->fcrb.ack_q_count_avg[index], p_ccb->fcrb.ack_q_count_min[index],
+ p_ccb->fcrb.ack_q_count_max[index]);
+
+ BT_TRACE(TRACE_CTRL_GENERAL | TRACE_LAYER_GKI | TRACE_ORG_GKI,
+ TRACE_TYPE_GENERIC, "%s", str);
+
+ index = (index + 1) % L2CAP_ERTM_STATS_NUM_AVG;
+ p_ccb->fcrb.ack_delay_avg_index = index;
+
+ p_ccb->fcrb.ack_q_count_max[index] = 0;
+ p_ccb->fcrb.ack_q_count_min[index] = 0xFFFFFFFF;
+ p_ccb->fcrb.ack_q_count_avg[index] = 0;
+
+ p_ccb->fcrb.ack_delay_max[index] = 0;
+ p_ccb->fcrb.ack_delay_min[index] = 0xFFFFFFFF;
+ p_ccb->fcrb.ack_delay_avg[index] = 0;
+
+ p_ccb->fcrb.throughput[index] = 0;
+ }
+}
+#endif
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_int.h b/mtkbt/code/bt/stack/l2cap/l2c_int.h
new file mode 100755
index 0000000..9fb6962
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_int.h
@@ -0,0 +1,846 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains L2CAP internal definitions
+ *
+ ******************************************************************************/
+#ifndef L2C_INT_H
+#define L2C_INT_H
+
+#include <stdbool.h>
+
+#include "bt_common.h"
+#include "btm_api.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "osi/include/list.h"
+
+#define L2CAP_MIN_MTU 48 /* Minimum acceptable MTU is 48 bytes */
+
+/* LE credit based L2CAP connection parameters */
+#define L2CAP_LE_MIN_MTU 23
+#define L2CAP_LE_MIN_MPS 23
+#define L2CAP_LE_MAX_MPS 65533
+#define L2CAP_LE_MIN_CREDIT 0
+#define L2CAP_LE_MAX_CREDIT 65535
+#define L2CAP_LE_DEFAULT_MTU 512
+#define L2CAP_LE_DEFAULT_MPS 23
+#define L2CAP_LE_DEFAULT_CREDIT 1
+
+/*
+ * Timeout values (in milliseconds).
+ */
+#define L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS (10 * 1000) /* 10 seconds */
+#define L2CAP_LINK_CONNECT_TIMEOUT_MS (60 * 1000) /* 30 seconds */
+#define L2CAP_LINK_CONNECT_EXT_TIMEOUT_MS (120 * 1000) /* 120 seconds */
+#define L2CAP_ECHO_RSP_TIMEOUT_MS (30 * 1000) /* 30 seconds */
+#define L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#define L2CAP_LINK_DISCONNECT_TIMEOUT_MS (30 * 1000) /* 30 seconds */
+#define L2CAP_CHNL_CONNECT_TIMEOUT_MS (60 * 1000) /* 60 seconds */
+#define L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS (120 * 1000) /* 120 seconds */
+#define L2CAP_CHNL_CFG_TIMEOUT_MS (30 * 1000) /* 30 seconds */
+#define L2CAP_CHNL_DISCONNECT_TIMEOUT_MS (10 * 1000) /* 10 seconds */
+#define L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS (2 * 1000) /* 2 seconds */
+#define L2CAP_WAIT_INFO_RSP_TIMEOUT_MS (3 * 1000) /* 3 seconds */
+#define L2CAP_BLE_LINK_CONNECT_TIMEOUT_MS (30 * 1000) /* 30 seconds */
+#define L2CAP_FCR_ACK_TIMEOUT_MS 200 /* 200 milliseconds */
+
+/* Define the possible L2CAP channel states. The names of
+ * the states may seem a bit strange, but they are taken from
+ * the Bluetooth specification.
+*/
+typedef enum {
+ CST_CLOSED, /* Channel is in closed state */
+ CST_ORIG_W4_SEC_COMP, /* Originator waits security clearence */
+ CST_TERM_W4_SEC_COMP, /* Acceptor waits security clearence */
+ CST_W4_L2CAP_CONNECT_RSP, /* Waiting for peer conenct response */
+ CST_W4_L2CA_CONNECT_RSP, /* Waiting for upper layer connect rsp */
+ CST_CONFIG, /* Negotiating configuration */
+ CST_OPEN, /* Data transfer state */
+ CST_W4_L2CAP_DISCONNECT_RSP, /* Waiting for peer disconnect rsp */
+ CST_W4_L2CA_DISCONNECT_RSP /* Waiting for upper layer disc rsp */
+} tL2C_CHNL_STATE;
+
+/* Define the possible L2CAP link states
+*/
+typedef enum {
+ LST_DISCONNECTED,
+ LST_CONNECT_HOLDING,
+ LST_CONNECTING_WAIT_SWITCH,
+ LST_CONNECTING,
+ LST_CONNECTED,
+ LST_DISCONNECTING
+} tL2C_LINK_STATE;
+
+/* Define input events to the L2CAP link and channel state machines. The names
+ * of the events may seem a bit strange, but they are taken from
+ * the Bluetooth specification.
+*/
+/* Lower layer */
+#define L2CEVT_LP_CONNECT_CFM 0 /* connect confirm */
+#define L2CEVT_LP_CONNECT_CFM_NEG 1 /* connect confirm (failed) */
+#define L2CEVT_LP_CONNECT_IND 2 /* connect indication */
+#define L2CEVT_LP_DISCONNECT_IND 3 /* disconnect indication */
+#define L2CEVT_LP_QOS_CFM 4 /* QOS confirmation */
+#define L2CEVT_LP_QOS_CFM_NEG 5 /* QOS confirmation (failed)*/
+#define L2CEVT_LP_QOS_VIOLATION_IND 6 /* QOS violation indication */
+
+/* Security */
+#define L2CEVT_SEC_COMP 7 /* cleared successfully */
+#define L2CEVT_SEC_COMP_NEG 8 /* procedure failed */
+
+/* Peer connection */
+#define L2CEVT_L2CAP_CONNECT_REQ 10 /* request */
+#define L2CEVT_L2CAP_CONNECT_RSP 11 /* response */
+#define L2CEVT_L2CAP_CONNECT_RSP_PND 12 /* response pending */
+#define L2CEVT_L2CAP_CONNECT_RSP_NEG 13 /* response (failed) */
+
+/* Peer configuration */
+#define L2CEVT_L2CAP_CONFIG_REQ 14 /* request */
+#define L2CEVT_L2CAP_CONFIG_RSP 15 /* response */
+#define L2CEVT_L2CAP_CONFIG_RSP_NEG 16 /* response (failed) */
+
+#define L2CEVT_L2CAP_DISCONNECT_REQ 17 /* Peer disconnect request */
+#define L2CEVT_L2CAP_DISCONNECT_RSP 18 /* Peer disconnect response */
+#define L2CEVT_L2CAP_INFO_RSP 19 /* Peer information response */
+#define L2CEVT_L2CAP_DATA 20 /* Peer data */
+
+/* Upper layer */
+#define L2CEVT_L2CA_CONNECT_REQ 21 /* connect request */
+#define L2CEVT_L2CA_CONNECT_RSP 22 /* connect response */
+#define L2CEVT_L2CA_CONNECT_RSP_NEG 23 /* connect response (failed)*/
+#define L2CEVT_L2CA_CONFIG_REQ 24 /* config request */
+#define L2CEVT_L2CA_CONFIG_RSP 25 /* config response */
+#define L2CEVT_L2CA_CONFIG_RSP_NEG 26 /* config response (failed) */
+#define L2CEVT_L2CA_DISCONNECT_REQ 27 /* disconnect request */
+#define L2CEVT_L2CA_DISCONNECT_RSP 28 /* disconnect response */
+#define L2CEVT_L2CA_DATA_READ 29 /* data read */
+#define L2CEVT_L2CA_DATA_WRITE 30 /* data write */
+#define L2CEVT_L2CA_FLUSH_REQ 31 /* flush */
+
+#define L2CEVT_TIMEOUT 32 /* Timeout */
+#define L2CEVT_SEC_RE_SEND_CMD 33 /* btm_sec has enough info to proceed */
+
+#define L2CEVT_ACK_TIMEOUT 34 /* RR delay timeout */
+
+#define L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT \
+ 35 /* Upper layer credit packet \
+ */
+#define L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT 36 /* Peer credit packet */
+
+/* Bitmask to skip over Broadcom feature reserved (ID) to avoid sending two
+ successive ID values, '0' id only or both */
+#define L2CAP_ADJ_BRCM_ID 0x1
+#define L2CAP_ADJ_ZERO_ID 0x2
+#define L2CAP_ADJ_ID 0x3
+
+/* Return values for l2cu_process_peer_cfg_req() */
+#define L2CAP_PEER_CFG_UNACCEPTABLE 0
+#define L2CAP_PEER_CFG_OK 1
+#define L2CAP_PEER_CFG_DISCONNECT 2
+
+/* eL2CAP option constants */
+/* Min retransmission timeout if no flush timeout or PBF */
+#define L2CAP_MIN_RETRANS_TOUT 2000
+/* Min monitor timeout if no flush timeout or PBF */
+#define L2CAP_MIN_MONITOR_TOUT 12000
+
+#define L2CAP_MAX_FCR_CFG_TRIES 2 /* Config attempts before disconnecting */
+
+typedef uint8_t tL2C_BLE_FIXED_CHNLS_MASK;
+
+typedef struct {
+ uint8_t next_tx_seq; /* Next sequence number to be Tx'ed */
+ uint8_t last_rx_ack; /* Last sequence number ack'ed by the peer */
+ uint8_t next_seq_expected; /* Next peer sequence number expected */
+ uint8_t last_ack_sent; /* Last peer sequence number ack'ed */
+ uint8_t num_tries; /* Number of retries to send a packet */
+ uint8_t max_held_acks; /* Max acks we can hold before sending */
+
+ bool remote_busy; /* true if peer has flowed us off */
+ bool local_busy; /* true if we have flowed off the peer */
+
+ bool rej_sent; /* Reject was sent */
+ bool srej_sent; /* Selective Reject was sent */
+ bool wait_ack; /* Transmitter is waiting ack (poll sent) */
+ bool rej_after_srej; /* Send a REJ when SREJ clears */
+
+ bool send_f_rsp; /* We need to send an F-bit response */
+
+ uint16_t rx_sdu_len; /* Length of the SDU being received */
+ BT_HDR* p_rx_sdu; /* Buffer holding the SDU being received */
+ fixed_queue_t*
+ waiting_for_ack_q; /* Buffers sent and waiting for peer to ack */
+ fixed_queue_t* srej_rcv_hold_q; /* Buffers rcvd but held pending SREJ rsp */
+ fixed_queue_t* retrans_q; /* Buffers being retransmitted */
+
+ alarm_t* ack_timer; /* Timer delaying RR */
+ alarm_t* mon_retrans_timer; /* Timer Monitor or Retransmission */
+
+#if (L2CAP_ERTM_STATS == TRUE)
+ uint32_t connect_tick_count; /* Time channel was established */
+ uint32_t ertm_pkt_counts[2]; /* Packets sent and received */
+ uint32_t ertm_byte_counts[2]; /* Bytes sent and received */
+ uint32_t s_frames_sent[4]; /* S-frames sent (RR, REJ, RNR, SREJ) */
+ uint32_t s_frames_rcvd[4]; /* S-frames rcvd (RR, REJ, RNR, SREJ) */
+ uint32_t xmit_window_closed; /* # of times the xmit window was closed */
+ uint32_t controller_idle; /* # of times less than 2 packets in controller */
+ /* when the xmit window was closed */
+ uint32_t pkts_retransmitted; /* # of packets that were retransmitted */
+ uint32_t retrans_touts; /* # of retransmission timouts */
+ uint32_t xmit_ack_touts; /* # of xmit ack timouts */
+
+#define L2CAP_ERTM_STATS_NUM_AVG 10
+#define L2CAP_ERTM_STATS_AVG_NUM_SAMPLES 100
+ uint32_t ack_delay_avg_count;
+ uint32_t ack_delay_avg_index;
+ uint32_t throughput_start;
+ uint32_t throughput[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_delay_avg[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_delay_min[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_delay_max[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_q_count_avg[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_q_count_min[L2CAP_ERTM_STATS_NUM_AVG];
+ uint32_t ack_q_count_max[L2CAP_ERTM_STATS_NUM_AVG];
+#endif
+} tL2C_FCRB;
+
+/* Define a registration control block. Every application (e.g. RFCOMM, SDP,
+ * TCS etc) that registers with L2CAP is assigned one of these.
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+#define L2C_UCD_RCB_ID 0x00
+#define L2C_UCD_STATE_UNUSED 0x00
+#define L2C_UCD_STATE_W4_DATA 0x01
+#define L2C_UCD_STATE_W4_RECEPTION 0x02
+#define L2C_UCD_STATE_W4_MTU 0x04
+
+typedef struct {
+ uint8_t state;
+ tL2CAP_UCD_CB_INFO cb_info;
+} tL2C_UCD_REG;
+#endif
+
+typedef struct {
+ bool in_use;
+ uint16_t psm;
+ uint16_t real_psm; /* This may be a dummy RCB for an o/b connection but */
+ /* this is the real PSM that we need to connect to */
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ tL2C_UCD_REG ucd;
+#endif
+
+ tL2CAP_APPL_INFO api;
+} tL2C_RCB;
+
+#ifndef L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA
+#define L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA 100
+#endif
+
+typedef void(tL2CAP_SEC_CBACK)(BD_ADDR bd_addr, tBT_TRANSPORT trasnport,
+ void* p_ref_data, tBTM_STATUS result);
+
+typedef struct {
+ uint16_t psm;
+ tBT_TRANSPORT transport;
+ bool is_originator;
+ tL2CAP_SEC_CBACK* p_callback;
+ void* p_ref_data;
+} tL2CAP_SEC_DATA;
+
+/* Define a channel control block (CCB). There may be many channel control
+ * blocks between the same two Bluetooth devices (i.e. on the same link).
+ * Each CCB has unique local and remote CIDs. All channel control blocks on
+ * the same physical link and are chained together.
+*/
+typedef struct t_l2c_ccb {
+ bool in_use; /* true when in use, false when not */
+ tL2C_CHNL_STATE chnl_state; /* Channel state */
+ tL2CAP_LE_CFG_INFO
+ local_conn_cfg; /* Our config for ble conn oriented channel */
+ tL2CAP_LE_CFG_INFO
+ peer_conn_cfg; /* Peer device config ble conn oriented channel */
+ bool is_first_seg; /* Dtermine whether the received packet is the first
+ segment or not */
+ BT_HDR* ble_sdu; /* Buffer for storing unassembled sdu*/
+ uint16_t ble_sdu_length; /* Length of unassembled sdu length*/
+ struct t_l2c_ccb* p_next_ccb; /* Next CCB in the chain */
+ struct t_l2c_ccb* p_prev_ccb; /* Previous CCB in the chain */
+ struct t_l2c_linkcb* p_lcb; /* Link this CCB is assigned to */
+
+ uint16_t local_cid; /* Local CID */
+ uint16_t remote_cid; /* Remote CID */
+
+ alarm_t* l2c_ccb_timer; /* CCB Timer Entry */
+
+ tL2C_RCB* p_rcb; /* Registration CB for this Channel */
+ bool should_free_rcb; /* True if RCB was allocated on the heap */
+
+#define IB_CFG_DONE 0x01
+#define OB_CFG_DONE 0x02
+#define RECONFIG_FLAG 0x04 /* True after initial configuration */
+#define CFG_DONE_MASK (IB_CFG_DONE | OB_CFG_DONE)
+
+ uint8_t config_done; /* Configuration flag word */
+ uint8_t local_id; /* Transaction ID for local trans */
+ uint8_t remote_id; /* Transaction ID for local */
+
+#define CCB_FLAG_NO_RETRY 0x01 /* no more retry */
+#define CCB_FLAG_SENT_PENDING 0x02 /* already sent pending response */
+ uint8_t flags;
+
+ tL2CAP_CFG_INFO our_cfg; /* Our saved configuration options */
+ tL2CAP_CH_CFG_BITS peer_cfg_bits; /* Store what peer wants to configure */
+ tL2CAP_CFG_INFO peer_cfg; /* Peer's saved configuration options */
+
+ fixed_queue_t* xmit_hold_q; /* Transmit data hold queue */
+ bool cong_sent; /* Set when congested status sent */
+ uint16_t buff_quota; /* Buffer quota before sending congestion */
+
+ tL2CAP_CHNL_PRIORITY ccb_priority; /* Channel priority */
+ tL2CAP_CHNL_DATA_RATE tx_data_rate; /* Channel Tx data rate */
+ tL2CAP_CHNL_DATA_RATE rx_data_rate; /* Channel Rx data rate */
+
+ /* Fields used for eL2CAP */
+ tL2CAP_ERTM_INFO ertm_info;
+ tL2C_FCRB fcrb;
+ uint16_t tx_mps; /* TX MPS adjusted based on current controller */
+ uint16_t max_rx_mtu;
+ uint8_t fcr_cfg_tries; /* Max number of negotiation attempts */
+ bool peer_cfg_already_rejected; /* If mode rejected once, set to true */
+ bool out_cfg_fcr_present; /* true if cfg response shoulkd include fcr options
+ */
+
+#define L2CAP_CFG_FCS_OUR 0x01 /* Our desired config FCS option */
+#define L2CAP_CFG_FCS_PEER 0x02 /* Peer's desired config FCS option */
+#define L2CAP_BYPASS_FCS (L2CAP_CFG_FCS_OUR | L2CAP_CFG_FCS_PEER)
+ uint8_t bypass_fcs;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ bool is_flushable; /* true if channel is flushable */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0 || L2CAP_UCD_INCLUDED == TRUE)
+ uint16_t fixed_chnl_idle_tout; /* Idle timeout to use for the fixed channel */
+#endif
+ uint16_t tx_data_len;
+} tL2C_CCB;
+
+/***********************************************************************
+ * Define a queue of linked CCBs.
+*/
+typedef struct {
+ tL2C_CCB* p_first_ccb; /* The first channel in this queue */
+ tL2C_CCB* p_last_ccb; /* The last channel in this queue */
+} tL2C_CCB_Q;
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/* Round-Robin service for the same priority channels */
+#define L2CAP_NUM_CHNL_PRIORITY \
+ 3 /* Total number of priority group (high, medium, low)*/
+#define L2CAP_CHNL_PRIORITY_WEIGHT \
+ 5 /* weight per priority for burst transmission quota */
+#define L2CAP_GET_PRIORITY_QUOTA(pri) \
+ ((L2CAP_NUM_CHNL_PRIORITY - (pri)) * L2CAP_CHNL_PRIORITY_WEIGHT)
+
+/* CCBs within the same LCB are served in round robin with priority It will make
+ * sure that low priority channel (for example, HF signaling on RFCOMM) can be
+ * sent to the headset even if higher priority channel (for example, AV media
+ * channel) is congested.
+ */
+
+typedef struct {
+ tL2C_CCB* p_serve_ccb; /* current serving ccb within priority group */
+ tL2C_CCB* p_first_ccb; /* first ccb of priority group */
+ uint8_t num_ccb; /* number of channels in priority group */
+ uint8_t quota; /* burst transmission quota */
+} tL2C_RR_SERV;
+
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/* Define a link control block. There is one link control block between
+ * this device and any other device (i.e. BD ADDR).
+*/
+typedef struct t_l2c_linkcb {
+ bool in_use; /* true when in use, false when not */
+ tL2C_LINK_STATE link_state;
+
+ alarm_t* l2c_lcb_timer; /* Timer entry for timeout evt */
+ uint16_t handle; /* The handle used with LM */
+
+ tL2C_CCB_Q ccb_queue; /* Queue of CCBs on this LCB */
+
+ tL2C_CCB* p_pending_ccb; /* ccb of waiting channel during link disconnect */
+ alarm_t* info_resp_timer; /* Timer entry for info resp timeout evt */
+ BD_ADDR remote_bd_addr; /* The BD address of the remote */
+
+ uint8_t link_role; /* Master or slave */
+ uint8_t id;
+ uint8_t cur_echo_id; /* Current id value for echo request */
+ tL2CA_ECHO_RSP_CB* p_echo_rsp_cb; /* Echo response callback */
+ uint16_t idle_timeout; /* Idle timeout */
+ bool is_bonding; /* True - link active only for bonding */
+
+ uint16_t link_flush_tout; /* Flush timeout used */
+
+ uint16_t link_xmit_quota; /* Num outstanding pkts allowed */
+ uint16_t sent_not_acked; /* Num packets sent but not acked */
+
+ bool partial_segment_being_sent; /* Set true when a partial segment */
+ /* is being sent. */
+ bool w4_info_rsp; /* true when info request is active */
+ uint8_t info_rx_bits; /* set 1 if received info type */
+ uint32_t peer_ext_fea; /* Peer's extended features mask */
+ list_t* link_xmit_data_q; /* Link transmit data buffer queue */
+
+ uint8_t peer_chnl_mask[L2CAP_FIXED_CHNL_ARRAY_SIZE];
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ uint16_t ucd_mtu; /* peer MTU on UCD */
+ fixed_queue_t*
+ ucd_out_sec_pending_q; /* Security pending outgoing UCD packet */
+ fixed_queue_t*
+ ucd_in_sec_pending_q; /* Security pending incoming UCD packet */
+#endif
+
+ BT_HDR* p_hcit_rcv_acl; /* Current HCIT ACL buf being rcvd */
+ uint16_t idle_timeout_sv; /* Save current Idle timeout */
+ uint8_t acl_priority; /* L2C_PRIORITY_NORMAL or L2C_PRIORITY_HIGH */
+ tL2CA_NOCP_CB* p_nocp_cb; /* Num Cmpl pkts callback */
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2C_CCB* p_fixed_ccbs[L2CAP_NUM_FIXED_CHNLS];
+ uint16_t disc_reason;
+#endif
+
+ tBT_TRANSPORT transport;
+ uint8_t initiating_phys; // LE PHY used for connection initiation
+ tBLE_ADDR_TYPE ble_addr_type;
+ uint16_t tx_data_len; /* tx data length used in data length extension */
+ fixed_queue_t* le_sec_pending_q; /* LE coc channels waiting for security check
+ completion */
+ uint8_t sec_act;
+#define L2C_BLE_CONN_UPDATE_DISABLE \
+ 0x1 /* disable update connection parameters */
+#define L2C_BLE_NEW_CONN_PARAM 0x2 /* new connection parameter to be set */
+#define L2C_BLE_UPDATE_PENDING \
+ 0x4 /* waiting for connection update finished \
+ */
+#define L2C_BLE_NOT_DEFAULT_PARAM \
+ 0x8 /* not using default connection parameters */
+ uint8_t conn_update_mask;
+
+ uint16_t min_interval; /* parameters as requested by peripheral */
+ uint16_t max_interval;
+ uint16_t latency;
+ uint16_t timeout;
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* each priority group is limited burst transmission */
+ /* round robin service for the same priority channels */
+ tL2C_RR_SERV rr_serv[L2CAP_NUM_CHNL_PRIORITY];
+ uint8_t rr_pri; /* current serving priority group */
+#endif
+
+} tL2C_LCB;
+
+/* Define the L2CAP control structure
+*/
+typedef struct {
+ uint8_t l2cap_trace_level;
+ uint16_t controller_xmit_window; /* Total ACL window for all links */
+
+ uint16_t round_robin_quota; /* Round-robin link quota */
+ uint16_t round_robin_unacked; /* Round-robin unacked */
+ bool check_round_robin; /* Do a round robin check */
+
+ bool is_cong_cback_context;
+
+ tL2C_LCB lcb_pool[MAX_L2CAP_LINKS]; /* Link Control Block pool */
+ tL2C_CCB ccb_pool[MAX_L2CAP_CHANNELS]; /* Channel Control Block pool */
+ tL2C_RCB rcb_pool[MAX_L2CAP_CLIENTS]; /* Registration info pool */
+
+ tL2C_CCB* p_free_ccb_first; /* Pointer to first free CCB */
+ tL2C_CCB* p_free_ccb_last; /* Pointer to last free CCB */
+
+ uint8_t
+ desire_role; /* desire to be master/slave when accepting a connection */
+ bool disallow_switch; /* false, to allow switch at create conn */
+ uint16_t num_lm_acl_bufs; /* # of ACL buffers on controller */
+ uint16_t idle_timeout; /* Idle timeout */
+
+ list_t* rcv_pending_q; /* Recv pending queue */
+ alarm_t* receive_hold_timer; /* Timer entry for rcv hold */
+
+ tL2C_LCB* p_cur_hcit_lcb; /* Current HCI Transport buffer */
+ uint16_t num_links_active; /* Number of links active */
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ uint16_t non_flushable_pbf; /* L2CAP_PKT_START_NON_FLUSHABLE if controller
+ supports */
+ /* Otherwise, L2CAP_PKT_START */
+ bool is_flush_active; /* true if an HCI_Enhanced_Flush has been sent */
+#endif
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ uint32_t test_info_resp; /* Conformance testing needs a dynamic response */
+#endif
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2CAP_FIXED_CHNL_REG
+ fixed_reg[L2CAP_NUM_FIXED_CHNLS]; /* Reg info for fixed channels */
+#endif
+
+ uint16_t num_ble_links_active; /* Number of LE links active */
+ bool is_ble_connecting;
+ BD_ADDR ble_connecting_bda;
+ uint16_t controller_le_xmit_window; /* Total ACL window for all links */
+ tL2C_BLE_FIXED_CHNLS_MASK l2c_ble_fixed_chnls_mask; // LE fixed channels mask
+ uint16_t num_lm_ble_bufs; /* # of ACL buffers on controller */
+ uint16_t ble_round_robin_quota; /* Round-robin link quota */
+ uint16_t ble_round_robin_unacked; /* Round-robin unacked */
+ bool ble_check_round_robin; /* Do a round robin check */
+ tL2C_RCB ble_rcb_pool[BLE_MAX_L2CAP_CLIENTS]; /* Registration info pool */
+
+ tL2CA_ECHO_DATA_CB* p_echo_data_cb; /* Echo data callback */
+
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)
+ uint16_t high_pri_min_xmit_quota; /* Minimum number of ACL credit for high
+ priority link */
+#endif /* (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE) */
+
+ uint16_t dyn_psm;
+} tL2C_CB;
+
+/* Define a structure that contains the information about a connection.
+ * This structure is used to pass between functions, and not all the
+ * fields will always be filled in.
+*/
+typedef struct {
+ BD_ADDR bd_addr; /* Remote BD address */
+ uint8_t status; /* Connection status */
+ uint16_t psm; /* PSM of the connection */
+ uint16_t l2cap_result; /* L2CAP result */
+ uint16_t l2cap_status; /* L2CAP status */
+ uint16_t remote_cid; /* Remote CID */
+} tL2C_CONN_INFO;
+
+typedef void(tL2C_FCR_MGMT_EVT_HDLR)(uint8_t, tL2C_CCB*);
+
+/* Necessary info for postponed TX completion callback
+*/
+typedef struct {
+ uint16_t local_cid;
+ uint16_t num_sdu;
+ tL2CA_TX_COMPLETE_CB* cb;
+} tL2C_TX_COMPLETE_CB_INFO;
+
+/* The offset in a buffer that L2CAP will use when building commands.
+*/
+#define L2CAP_SEND_CMD_OFFSET 0
+
+/* Number of ACL buffers to use for high priority channel
+*/
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == FALSE)
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (L2CAP_HIGH_PRI_MIN_XMIT_QUOTA)
+#else
+#define L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A (l2cb.high_pri_min_xmit_quota)
+#endif
+
+/* L2CAP global data
+ ***********************************
+*/
+extern tL2C_CB l2cb;
+
+/* Functions provided by l2c_main.cc
+ ***********************************
+*/
+void l2c_init(void);
+void l2c_free(void);
+
+extern void l2c_receive_hold_timer_timeout(void* data);
+extern void l2c_ccb_timer_timeout(void* data);
+extern void l2c_lcb_timer_timeout(void* data);
+extern void l2c_fcrb_ack_timer_timeout(void* data);
+extern uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flag);
+extern void l2c_rcv_acl_data(BT_HDR* p_msg);
+extern void l2c_process_held_packets(bool timed_out);
+
+/* Functions provided by l2c_utils.cc
+ ***********************************
+*/
+extern bool l2cu_can_allocate_lcb(void);
+extern tL2C_LCB* l2cu_allocate_lcb(BD_ADDR p_bd_addr, bool is_bonding,
+ tBT_TRANSPORT transport);
+extern bool l2cu_start_post_bond_timer(uint16_t handle);
+extern void l2cu_release_lcb(tL2C_LCB* p_lcb);
+extern tL2C_LCB* l2cu_find_lcb_by_bd_addr(BD_ADDR p_bd_addr,
+ tBT_TRANSPORT transport);
+extern tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t handle);
+extern void l2cu_update_lcb_4_bonding(BD_ADDR p_bd_addr, bool is_bonding);
+
+extern uint8_t l2cu_get_conn_role(tL2C_LCB* p_this_lcb);
+extern bool l2cu_set_acl_priority(BD_ADDR bd_addr, uint8_t priority,
+ bool reset_after_rs);
+
+extern void l2cu_enqueue_ccb(tL2C_CCB* p_ccb);
+extern void l2cu_dequeue_ccb(tL2C_CCB* p_ccb);
+extern void l2cu_change_pri_ccb(tL2C_CCB* p_ccb, tL2CAP_CHNL_PRIORITY priority);
+
+extern tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid);
+extern void l2cu_release_ccb(tL2C_CCB* p_ccb);
+extern tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* p_lcb, uint16_t local_cid);
+extern tL2C_CCB* l2cu_find_ccb_by_remote_cid(tL2C_LCB* p_lcb,
+ uint16_t remote_cid);
+extern void l2cu_adj_id(tL2C_LCB* p_lcb, uint8_t adj_mask);
+extern bool l2c_is_cmd_rejected(uint8_t cmd_code, uint8_t id, tL2C_LCB* p_lcb);
+
+extern void l2cu_send_peer_cmd_reject(tL2C_LCB* p_lcb, uint16_t reason,
+ uint8_t rem_id, uint16_t p1, uint16_t p2);
+extern void l2cu_send_peer_connect_req(tL2C_CCB* p_ccb);
+extern void l2cu_send_peer_connect_rsp(tL2C_CCB* p_ccb, uint16_t result,
+ uint16_t status);
+extern void l2cu_send_peer_config_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+extern void l2cu_send_peer_config_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+extern void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data,
+ uint16_t data_len, uint16_t rej_len);
+extern void l2cu_send_peer_disc_req(tL2C_CCB* p_ccb);
+extern void l2cu_send_peer_disc_rsp(tL2C_LCB* p_lcb, uint8_t remote_id,
+ uint16_t local_cid, uint16_t remote_cid);
+extern void l2cu_send_peer_echo_req(tL2C_LCB* p_lcb, uint8_t* p_data,
+ uint16_t data_len);
+extern void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t id,
+ uint8_t* p_data, uint16_t data_len);
+extern void l2cu_send_peer_info_rsp(tL2C_LCB* p_lcb, uint8_t id,
+ uint16_t info_type);
+extern void l2cu_reject_connection(tL2C_LCB* p_lcb, uint16_t remote_cid,
+ uint8_t rem_id, uint16_t result);
+extern void l2cu_send_peer_info_req(tL2C_LCB* p_lcb, uint16_t info_type);
+extern void l2cu_set_acl_hci_header(BT_HDR* p_buf, tL2C_CCB* p_ccb);
+extern void l2cu_check_channel_congestion(tL2C_CCB* p_ccb);
+extern void l2cu_disconnect_chnl(tL2C_CCB* p_ccb);
+
+extern void l2cu_tx_complete(tL2C_TX_COMPLETE_CB_INFO* p_cbi);
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+extern void l2cu_set_non_flushable_pbf(bool);
+#endif
+
+extern void l2cu_send_peer_ble_par_req(tL2C_LCB* p_lcb, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout);
+extern void l2cu_send_peer_ble_par_rsp(tL2C_LCB* p_lcb, uint16_t reason,
+ uint8_t rem_id);
+extern void l2cu_reject_ble_connection(tL2C_LCB* p_lcb, uint8_t rem_id,
+ uint16_t result);
+extern void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* p_ccb,
+ uint16_t result);
+extern void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* p_ccb);
+extern void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB* p_ccb,
+ uint16_t credit_value);
+extern void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* p_ccb);
+
+extern bool l2cu_initialize_fixed_ccb(tL2C_LCB* p_lcb, uint16_t fixed_cid,
+ tL2CAP_FCR_OPTS* p_fcr);
+extern void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb);
+extern void l2cu_process_fixed_chnl_resp(tL2C_LCB* p_lcb);
+extern bool l2cu_is_ccb_active(tL2C_CCB* p_ccb);
+
+/* Functions provided by l2c_ucd.cc
+ ***********************************
+*/
+#if (L2CAP_UCD_INCLUDED == TRUE)
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB* p_lcb);
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB* p_ccb, void* p_data);
+bool l2c_ucd_check_pending_info_req(tL2C_CCB* p_ccb);
+bool l2c_ucd_check_pending_out_sec_q(tL2C_CCB* p_ccb);
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB* p_ccb);
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB* p_ccb);
+bool l2c_ucd_check_pending_in_sec_q(tL2C_CCB* p_ccb);
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB* p_ccb);
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB* p_ccb);
+bool l2c_ucd_check_rx_pkts(tL2C_LCB* p_lcb, BT_HDR* p_msg);
+bool l2c_ucd_process_event(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+#endif
+
+/* Functions provided for Broadcom Aware
+ ***************************************
+*/
+extern bool l2cu_check_feature_req(tL2C_LCB* p_lcb, uint8_t id, uint8_t* p_data,
+ uint16_t data_len);
+extern void l2cu_check_feature_rsp(tL2C_LCB* p_lcb, uint8_t id, uint8_t* p_data,
+ uint16_t data_len);
+extern void l2cu_send_feature_req(tL2C_CCB* p_ccb);
+
+extern tL2C_RCB* l2cu_allocate_rcb(uint16_t psm);
+extern tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm);
+extern void l2cu_release_rcb(tL2C_RCB* p_rcb);
+extern tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm);
+extern tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm);
+
+extern uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb,
+ tL2CAP_CFG_INFO* p_cfg);
+extern void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+extern void l2cu_process_our_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+extern void l2cu_process_our_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+
+extern void l2cu_device_reset(void);
+extern tL2C_LCB* l2cu_find_lcb_by_state(tL2C_LINK_STATE state);
+extern bool l2cu_lcb_disconnecting(void);
+
+extern bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport);
+extern bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport,
+ uint8_t initiating_phys);
+extern bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb);
+extern BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi);
+extern void l2cu_resubmit_pending_sec_req(BD_ADDR p_bda);
+extern void l2cu_initialize_amp_ccb(tL2C_LCB* p_lcb);
+extern void l2cu_adjust_out_mps(tL2C_CCB* p_ccb);
+
+/* Functions provided by l2c_link.cc
+ ***********************************
+*/
+extern bool l2c_link_hci_conn_req(BD_ADDR bd_addr);
+extern bool l2c_link_hci_conn_comp(uint8_t status, uint16_t handle,
+ BD_ADDR p_bda);
+extern bool l2c_link_hci_disc_comp(uint16_t handle, uint8_t reason);
+extern bool l2c_link_hci_qos_violation(uint16_t handle);
+extern void l2c_link_timeout(tL2C_LCB* p_lcb);
+extern void l2c_info_resp_timer_timeout(void* data);
+extern void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb,
+ BT_HDR* p_buf);
+extern void l2c_link_adjust_allocation(void);
+extern void l2c_link_process_num_completed_pkts(uint8_t* p);
+extern void l2c_link_process_num_completed_blocks(uint8_t controller_id,
+ uint8_t* p, uint16_t evt_len);
+extern void l2c_link_processs_num_bufs(uint16_t num_lm_acl_bufs);
+extern uint8_t l2c_link_pkts_rcvd(uint16_t* num_pkts, uint16_t* handles);
+extern void l2c_link_role_changed(BD_ADDR bd_addr, uint8_t new_role,
+ uint8_t hci_status);
+extern void l2c_link_sec_comp(BD_ADDR p_bda, tBT_TRANSPORT trasnport,
+ void* p_ref_data, uint8_t status);
+extern void l2c_link_segments_xmitted(BT_HDR* p_msg);
+extern void l2c_pin_code_request(BD_ADDR bd_addr);
+extern void l2c_link_adjust_chnl_allocation(void);
+
+extern void l2c_link_processs_ble_num_bufs(uint16_t num_lm_acl_bufs);
+
+#if (L2CAP_WAKE_PARKED_LINK == TRUE)
+extern bool l2c_link_check_power_mode(tL2C_LCB* p_lcb);
+#define L2C_LINK_CHECK_POWER_MODE(x) l2c_link_check_power_mode((x))
+#else // L2CAP_WAKE_PARKED_LINK
+#define L2C_LINK_CHECK_POWER_MODE(x) (false)
+#endif // L2CAP_WAKE_PARKED_LINK
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+/* Used only for conformance testing */
+extern void l2cu_set_info_rsp_mask(uint32_t mask);
+#endif
+
+/* Functions provided by l2c_csm.cc
+ ***********************************
+*/
+extern void l2c_csm_execute(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
+
+extern void l2c_enqueue_peer_data(tL2C_CCB* p_ccb, BT_HDR* p_buf);
+
+/* Functions provided by l2c_fcr.cc
+ ***********************************
+*/
+extern void l2c_fcr_cleanup(tL2C_CCB* p_ccb);
+extern void l2c_fcr_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf);
+extern void l2c_fcr_proc_tout(tL2C_CCB* p_ccb);
+extern void l2c_fcr_proc_ack_tout(tL2C_CCB* p_ccb);
+extern void l2c_fcr_send_S_frame(tL2C_CCB* p_ccb, uint16_t function_code,
+ uint16_t pf_bit);
+extern BT_HDR* l2c_fcr_clone_buf(BT_HDR* p_buf, uint16_t new_offset,
+ uint16_t no_of_bytes);
+extern bool l2c_fcr_is_flow_controlled(tL2C_CCB* p_ccb);
+extern BT_HDR* l2c_fcr_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
+ uint16_t max_packet_length);
+extern void l2c_fcr_start_timer(tL2C_CCB* p_ccb);
+extern void l2c_lcc_proc_pdu(tL2C_CCB* p_ccb, BT_HDR* p_buf);
+extern BT_HDR* l2c_lcc_get_next_xmit_sdu_seg(tL2C_CCB* p_ccb,
+ uint16_t max_packet_length);
+
+/* Configuration negotiation */
+extern uint8_t l2c_fcr_chk_chan_modes(tL2C_CCB* p_ccb);
+extern bool l2c_fcr_adj_our_req_options(tL2C_CCB* p_ccb,
+ tL2CAP_CFG_INFO* p_cfg);
+extern void l2c_fcr_adj_our_rsp_options(tL2C_CCB* p_ccb,
+ tL2CAP_CFG_INFO* p_peer_cfg);
+extern bool l2c_fcr_renegotiate_chan(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg);
+extern uint8_t l2c_fcr_process_peer_cfg_req(tL2C_CCB* p_ccb,
+ tL2CAP_CFG_INFO* p_cfg);
+extern void l2c_fcr_adj_monitor_retran_timeout(tL2C_CCB* p_ccb);
+extern void l2c_fcr_stop_timer(tL2C_CCB* p_ccb);
+
+/* Functions provided by l2c_ble.cc
+ ***********************************
+*/
+extern bool l2cble_create_conn(tL2C_LCB* p_lcb);
+extern void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p,
+ uint16_t pkt_len);
+extern void l2cble_conn_comp(uint16_t handle, uint8_t role, BD_ADDR bda,
+ tBLE_ADDR_TYPE type, uint16_t conn_interval,
+ uint16_t conn_latency, uint16_t conn_timeout);
+extern bool l2cble_init_direct_conn(tL2C_LCB* p_lcb);
+extern void l2cble_notify_le_connection(BD_ADDR bda);
+extern void l2c_ble_link_adjust_allocation(void);
+extern void l2cble_process_conn_update_evt(uint16_t handle, uint8_t status,
+ uint16_t interval, uint16_t latency,
+ uint16_t timeout);
+
+extern void l2cble_credit_based_conn_req(tL2C_CCB* p_ccb);
+extern void l2cble_credit_based_conn_res(tL2C_CCB* p_ccb, uint16_t result);
+extern void l2cble_send_peer_disc_req(tL2C_CCB* p_ccb);
+extern void l2cble_send_flow_control_credit(tL2C_CCB* p_ccb,
+ uint16_t credit_value);
+extern bool l2ble_sec_access_req(BD_ADDR bd_addr, uint16_t psm,
+ bool is_originator,
+ tL2CAP_SEC_CBACK* p_callback,
+ void* p_ref_data);
+
+#if (BLE_LLT_INCLUDED == TRUE)
+extern void l2cble_process_rc_param_request_evt(uint16_t handle,
+ uint16_t int_min,
+ uint16_t int_max,
+ uint16_t latency,
+ uint16_t timeout);
+#endif
+
+extern void l2cble_update_data_length(tL2C_LCB* p_lcb);
+extern void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda,
+ uint16_t fix_cid,
+ uint16_t tx_mtu);
+extern void l2cble_process_data_length_change_event(uint16_t handle,
+ uint16_t tx_data_len,
+ uint16_t rx_data_len);
+
+extern void l2cu_process_fixed_disc_cback(tL2C_LCB* p_lcb);
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+int l2c_link_check_a2dp_link(BD_ADDR bd_addr);
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_link.cc b/mtkbt/code/bt/stack/l2cap/l2c_link.cc
new file mode 100755
index 0000000..2c43fad
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_link.cc
@@ -0,0 +1,1465 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the functions relating to link management. A "link"
+ * is a connection between this device and another device. Only ACL links
+ * are managed.
+ *
+ ******************************************************************************/
+
+#include <base/logging.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btcore/include/bdaddr.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+#include "device_class.h"
+#endif
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi);
+
+/*******************************************************************************
+ *
+ * Function l2c_link_hci_conn_req
+ *
+ * Description This function is called when an HCI Connection Request
+ * event is received.
+ *
+ * Returns true, if accept conn
+ *
+ ******************************************************************************/
+bool l2c_link_hci_conn_req(BD_ADDR bd_addr) {
+ tL2C_LCB* p_lcb;
+ tL2C_LCB* p_lcb_cur;
+ int xx;
+ bool no_links;
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ /* If we don't have one, create one and accept the connection. */
+ if (!p_lcb) {
+ p_lcb = l2cu_allocate_lcb(bd_addr, false, BT_TRANSPORT_BR_EDR);
+ if (!p_lcb) {
+ btsnd_hcic_reject_conn(bd_addr, HCI_ERR_HOST_REJECT_RESOURCES);
+ L2CAP_TRACE_ERROR("L2CAP failed to allocate LCB");
+ return false;
+ }
+
+ no_links = true;
+
+ /* If we already have connection, accept as a master */
+ for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
+ xx++, p_lcb_cur++) {
+ if (p_lcb_cur == p_lcb) continue;
+
+ if (p_lcb_cur->in_use) {
+ no_links = false;
+ p_lcb->link_role = HCI_ROLE_MASTER;
+ break;
+ }
+ }
+
+ if (no_links) {
+ if (!btm_dev_support_switch(bd_addr))
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ else {
+ p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+ /** M: for devices in IOT list, accept connection as master @{*/
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_ACCEPT_CONN_AS_MASTER, ((const bt_bdaddr_t *)bd_addr)))
+ p_lcb->link_role = HCI_ROLE_MASTER;
+#endif
+ /** @} */
+ }
+ } else {
+ /** M: for devices in IOT list, accept connection as slave @{*/
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (interop_mtk_match_addr_name(INTEROP_MTK_ACCEPT_CONN_AS_SLAVE, ((const bt_bdaddr_t *)bd_addr)))
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+#endif
+ /** @} */
+ }
+
+ /* Tell the other side we accept the connection */
+ btsnd_hcic_accept_conn(bd_addr, p_lcb->link_role);
+
+ p_lcb->link_state = LST_CONNECTING;
+
+ /* Start a timer waiting for connect complete */
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ return (true);
+ }
+
+ /* We already had a link control block to the guy. Check what state it is in
+ */
+ if ((p_lcb->link_state == LST_CONNECTING) ||
+ (p_lcb->link_state == LST_CONNECT_HOLDING)) {
+ /* Connection collision. Accept the connection anyways. */
+
+ if (!btm_dev_support_switch(bd_addr))
+ p_lcb->link_role = HCI_ROLE_SLAVE;
+ else
+ p_lcb->link_role = l2cu_get_conn_role(p_lcb);
+
+ btsnd_hcic_accept_conn(bd_addr, p_lcb->link_role);
+
+ p_lcb->link_state = LST_CONNECTING;
+ return (true);
+ } else if (p_lcb->link_state == LST_DISCONNECTING) {
+ /* In disconnecting state, reject the connection. */
+ btsnd_hcic_reject_conn(bd_addr, HCI_ERR_HOST_REJECT_DEVICE);
+ } else {
+ L2CAP_TRACE_ERROR(
+ "L2CAP got conn_req while connected (state:%d). Reject it",
+ p_lcb->link_state);
+ /* Reject the connection with ACL Connection Already exist reason */
+ btsnd_hcic_reject_conn(bd_addr, HCI_ERR_CONNECTION_EXISTS);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_hci_conn_comp
+ *
+ * Description This function is called when an HCI Connection Complete
+ * event is received.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool l2c_link_hci_conn_comp(uint8_t status, uint16_t handle, BD_ADDR p_bda) {
+ tL2C_CONN_INFO ci;
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tBTM_SEC_DEV_REC* p_dev_info = NULL;
+
+ btm_acl_update_busy_level(BTM_BLI_PAGE_DONE_EVT);
+
+ /* Save the parameters */
+ ci.status = status;
+ memcpy(ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* See if we have a link control block for the remote device */
+ p_lcb = l2cu_find_lcb_by_bd_addr(ci.bd_addr, BT_TRANSPORT_BR_EDR);
+
+ /* If we don't have one, this is an error */
+ if (!p_lcb) {
+ L2CAP_TRACE_WARNING("L2CAP got conn_comp for unknown BD_ADDR");
+ return (false);
+ }
+
+ if (p_lcb->link_state != LST_CONNECTING) {
+ L2CAP_TRACE_ERROR("L2CAP got conn_comp in bad state: %d status: 0x%d",
+ p_lcb->link_state, status);
+
+ if (status != HCI_SUCCESS) l2c_link_hci_disc_comp(p_lcb->handle, status);
+
+ return (false);
+ }
+
+ /* Save the handle */
+ p_lcb->handle = handle;
+
+ if (ci.status == HCI_SUCCESS) {
+ /* Connected OK. Change state to connected */
+ p_lcb->link_state = LST_CONNECTED;
+
+ /* Get the peer information if the l2cap flow-control/rtrans is supported */
+ l2cu_send_peer_info_req(p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+
+ /* Tell BTM Acl management about the link */
+ p_dev_info = btm_find_dev(p_bda);
+ if (p_dev_info != NULL)
+ btm_acl_created(ci.bd_addr, p_dev_info->dev_class,
+ p_dev_info->sec_bd_name, handle, p_lcb->link_role,
+ BT_TRANSPORT_BR_EDR);
+ else
+ btm_acl_created(ci.bd_addr, NULL, NULL, handle, p_lcb->link_role,
+ BT_TRANSPORT_BR_EDR);
+
+ BTM_SetLinkSuperTout(ci.bd_addr, btm_cb.btm_def_link_super_tout);
+
+ /* If dedicated bonding do not process any further */
+ if (p_lcb->is_bonding) {
+ if (l2cu_start_post_bond_timer(handle)) return (true);
+ }
+
+ /* Update the timeouts in the hold queue */
+ l2c_process_held_packets(false);
+
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ l2c_csm_execute(p_ccb, L2CEVT_LP_CONNECT_CFM, &ci);
+ }
+
+ if (p_lcb->p_echo_rsp_cb) {
+ l2cu_send_peer_echo_req(p_lcb, NULL, 0);
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_ECHO_RSP_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ } else if (!p_lcb->ccb_queue.p_first_ccb) {
+ period_ms_t timeout_ms = L2CAP_LINK_STARTUP_TOUT * 1000;
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+ }
+ /* Max number of acl connections. */
+ /* If there's an lcb disconnecting set this one to holding */
+ else if ((ci.status == HCI_ERR_MAX_NUM_OF_CONNECTIONS) &&
+ l2cu_lcb_disconnecting()) {
+ p_lcb->link_state = LST_CONNECT_HOLDING;
+ p_lcb->handle = HCI_INVALID_HANDLE;
+ } else {
+ /* Just in case app decides to try again in the callback context */
+ p_lcb->link_state = LST_DISCONNECTING;
+
+ /* Connection failed. For all channels, send the event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {
+ tL2C_CCB* pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute(p_ccb, L2CEVT_LP_CONNECT_CFM_NEG, &ci);
+
+ p_ccb = pn;
+ }
+
+ p_lcb->disc_reason = status;
+ /* Release the LCB */
+ if (p_lcb->ccb_queue.p_first_ccb == NULL)
+ l2cu_release_lcb(p_lcb);
+ else /* there are any CCBs remaining */
+ {
+ if (ci.status == HCI_ERR_CONNECTION_EXISTS) {
+ /* we are in collision situation, wait for connecttion request from
+ * controller */
+ p_lcb->link_state = LST_CONNECTING;
+ } else {
+ l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+ }
+ }
+ }
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_sec_comp
+ *
+ * Description This function is called when required security procedures
+ * are completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_sec_comp(BD_ADDR p_bda, UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t status) {
+ tL2C_CONN_INFO ci;
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_CCB* p_next_ccb;
+ uint8_t event;
+
+ L2CAP_TRACE_DEBUG("l2c_link_sec_comp: %d, 0x%x", status, p_ref_data);
+
+ if (status == BTM_SUCCESS_NO_SECURITY) status = BTM_SUCCESS;
+
+ /* Save the parameters */
+ ci.status = status;
+ memcpy(ci.bd_addr, p_bda, BD_ADDR_LEN);
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, transport);
+
+ /* If we don't have one, this is an error */
+ if (!p_lcb) {
+ L2CAP_TRACE_WARNING("L2CAP got sec_comp for unknown BD_ADDR");
+ return;
+ }
+
+ /* Match p_ccb with p_ref_data returned by sec manager */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) {
+ p_next_ccb = p_ccb->p_next_ccb;
+
+ if (p_ccb == p_ref_data) {
+ switch (status) {
+ case BTM_SUCCESS:
+ event = L2CEVT_SEC_COMP;
+ break;
+
+ case BTM_DELAY_CHECK:
+ /* start a timer - encryption change not received before L2CAP connect
+ * req */
+ alarm_set_on_queue(
+ p_ccb->l2c_ccb_timer, L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
+ l2c_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ return;
+
+ default:
+ event = L2CEVT_SEC_COMP_NEG;
+ }
+ l2c_csm_execute(p_ccb, event, &ci);
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_hci_disc_comp
+ *
+ * Description This function is called when an HCI Disconnect Complete
+ * event is received.
+ *
+ * Returns true if the link is known about, else false
+ *
+ ******************************************************************************/
+bool l2c_link_hci_disc_comp(uint16_t handle, uint8_t reason) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ bool status = true;
+ bool lcb_is_free = true;
+ tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
+
+ /* See if we have a link control block for the connection */
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ /* If we don't have one, maybe an SCO link. Send to MM */
+ if (!p_lcb) {
+ status = false;
+ } else {
+ /* There can be a case when we rejected PIN code authentication */
+ /* otherwise save a new reason */
+ if (btm_cb.acl_disc_reason != HCI_ERR_HOST_REJECT_SECURITY)
+ btm_cb.acl_disc_reason = reason;
+
+ p_lcb->disc_reason = btm_cb.acl_disc_reason;
+
+ /* Just in case app decides to try again in the callback context */
+ p_lcb->link_state = LST_DISCONNECTING;
+
+ /* Check for BLE and handle that differently */
+ if (p_lcb->transport == BT_TRANSPORT_LE)
+ btm_ble_update_link_topology_mask(p_lcb->link_role, false);
+ /* Link is disconnected. For all channels, send the event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {
+ tL2C_CCB* pn = p_ccb->p_next_ccb;
+
+ /* Keep connect pending control block (if exists)
+ * Possible Race condition when a reconnect occurs
+ * on the channel during a disconnect of link. This
+ * ccb will be automatically retried after link disconnect
+ * arrives
+ */
+ if (p_ccb != p_lcb->p_pending_ccb) {
+ l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, &reason);
+ }
+ p_ccb = pn;
+ }
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ if (p_lcb->transport == BT_TRANSPORT_BR_EDR)
+ /* Tell SCO management to drop any SCOs on this ACL */
+ btm_sco_acl_removed(p_lcb->remote_bd_addr);
+#endif
+
+ /* If waiting for disconnect and reconnect is pending start the reconnect
+ now
+ race condition where layer above issued connect request on link that was
+ disconnecting
+ */
+ if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb) {
+ L2CAP_TRACE_DEBUG(
+ "l2c_link_hci_disc_comp: Restarting pending ACL request");
+ transport = p_lcb->transport;
+ /* for LE link, always drop and re-open to ensure to get LE remote feature
+ */
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ l2cb.is_ble_connecting = false;
+ btm_acl_removed(p_lcb->remote_bd_addr, p_lcb->transport);
+ /* Release any held buffers */
+ BT_HDR* p_buf;
+ while (!list_is_empty(p_lcb->link_xmit_data_q)) {
+ p_buf = static_cast<BT_HDR*>(list_front(p_lcb->link_xmit_data_q));
+ list_remove(p_lcb->link_xmit_data_q, p_buf);
+ osi_free(p_buf);
+ }
+ }
+ /** M: for LE link, it is also needed to release fixed channels */
+ {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ /* If we are going to re-use the LCB without dropping it, release all
+ fixed channels
+ here */
+ int xx;
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ if (p_lcb->p_fixed_ccbs[xx] &&
+ p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb) {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
+ p_lcb->disc_reason, p_lcb->transport);
+ if (p_lcb->p_fixed_ccbs[xx] == NULL) {
+ bdstr_t bd_addr_str = {0};
+ L2CAP_TRACE_ERROR(
+ "%s: unexpected p_fixed_ccbs[%d] is NULL remote_bd_addr = %s "
+ "p_lcb = %p in_use = %d link_state = %d handle = %d "
+ "link_role = %d is_bonding = %d disc_reason = %d transport = "
+ "%d",
+ __func__, xx,
+ bdaddr_to_string((bt_bdaddr_t*)&p_lcb->remote_bd_addr,
+ bd_addr_str, sizeof(bd_addr_str)),
+ p_lcb, p_lcb->in_use, p_lcb->link_state, p_lcb->handle,
+ p_lcb->link_role, p_lcb->is_bonding, p_lcb->disc_reason,
+ p_lcb->transport);
+ }
+ CHECK(p_lcb->p_fixed_ccbs[xx] != NULL);
+ l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
+
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ }
+ }
+
+ /** M: re-init lcb parameters before reusing @{ */
+ p_lcb->link_flush_tout = 0xFFFF;
+ p_lcb->idle_timeout = l2cb.idle_timeout;
+ /* timer should be canceled here,
+ Or the lcb maybe released at timer timeout
+ */
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG("%s: le xmit window %d, linkack %d, rr_unacked %d",
+ __func__, l2cb.controller_le_xmit_window, p_lcb->sent_not_acked, l2cb.ble_round_robin_unacked);
+ } else {
+ L2CAP_TRACE_DEBUG("%s: xmit window %d, linkack %d, rr_unacked %d",
+ __func__, l2cb.controller_xmit_window, p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+ }
+
+ if (p_lcb->sent_not_acked > 0) {
+ /* If there are some packets were not acked before disconnected,
+ resuming the xmit window here, and clearing the sent_not_acked of this lcb
+ */
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ /* recover the LE link quota and rr unacked */
+ l2cb.controller_le_xmit_window += p_lcb->sent_not_acked;
+ if (l2cb.controller_le_xmit_window > l2cb.num_lm_ble_bufs)
+ l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs;
+ if (p_lcb->link_xmit_quota == 0) {
+ if (l2cb.ble_round_robin_unacked > p_lcb->sent_not_acked)
+ l2cb.ble_round_robin_unacked -= p_lcb->sent_not_acked;
+ else
+ l2cb.ble_round_robin_unacked = 0;
+ }
+ } else {
+ /* recover the BR/EDR link quota and rr unacked */
+ l2cb.controller_xmit_window += p_lcb->sent_not_acked;
+ if (l2cb.controller_xmit_window > l2cb.num_lm_acl_bufs)
+ l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+ if (p_lcb->link_xmit_quota == 0) {
+ if (l2cb.round_robin_unacked > p_lcb->sent_not_acked)
+ l2cb.round_robin_unacked -= p_lcb->sent_not_acked;
+ else
+ l2cb.round_robin_unacked = 0;
+ }
+ }
+ p_lcb->sent_not_acked = 0;
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG("%s: after resuming, le xmit window %d, linkack %d, "
+ "rr_unacked %d",
+ __func__, l2cb.controller_le_xmit_window, p_lcb->sent_not_acked, l2cb.ble_round_robin_unacked);
+ } else {
+ L2CAP_TRACE_DEBUG("%s: after resuming, xmit window %d, linkack %d, "
+ "rr_unacked %d",
+ __func__, l2cb.controller_xmit_window, p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+ }
+ }
+ /** @} */
+#endif
+ }
+ if (l2cu_create_conn(p_lcb, transport))
+ lcb_is_free = false; /* still using this lcb */
+ }
+
+ p_lcb->p_pending_ccb = NULL;
+
+ /* Release the LCB */
+ if (lcb_is_free) l2cu_release_lcb(p_lcb);
+ }
+
+ /* Now that we have a free acl connection, see if any lcbs are pending */
+ if (lcb_is_free &&
+ ((p_lcb = l2cu_find_lcb_by_state(LST_CONNECT_HOLDING)) != NULL)) {
+ /* we found one-- create a connection */
+ l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_hci_qos_violation
+ *
+ * Description This function is called when an HCI QOS Violation
+ * event is received.
+ *
+ * Returns true if the link is known about, else false
+ *
+ ******************************************************************************/
+bool l2c_link_hci_qos_violation(uint16_t handle) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+
+ /* See if we have a link control block for the connection */
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ /* If we don't have one, maybe an SCO link. */
+ if (!p_lcb) return (false);
+
+ /* For all channels, tell the upper layer about it */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) {
+ if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
+ l2c_csm_execute(p_ccb, L2CEVT_LP_QOS_VIOLATION_IND, NULL);
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_timeout
+ *
+ * Description This function is called when a link timer expires
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_timeout(tL2C_LCB* p_lcb) {
+ tL2C_CCB* p_ccb;
+ tBTM_STATUS rc;
+
+ L2CAP_TRACE_EVENT(
+ "L2CAP - l2c_link_timeout() link state %d first CCB %p is_bonding:%d",
+ p_lcb->link_state, p_lcb->ccb_queue.p_first_ccb, p_lcb->is_bonding);
+
+ /* If link was connecting or disconnecting, clear all channels and drop the
+ * LCB */
+ if ((p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH) ||
+ (p_lcb->link_state == LST_CONNECTING) ||
+ (p_lcb->link_state == LST_CONNECT_HOLDING) ||
+ (p_lcb->link_state == LST_DISCONNECTING)) {
+ p_lcb->p_pending_ccb = NULL;
+
+ /* For all channels, send a disconnect indication event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {
+ tL2C_CCB* pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+ p_ccb = pn;
+ }
+ if (p_lcb->link_state == LST_CONNECTING && l2cb.is_ble_connecting == true) {
+ L2CA_CancelBleConnectReq(l2cb.ble_connecting_bda);
+ }
+ /* Release the LCB */
+ l2cu_release_lcb(p_lcb);
+ }
+
+ /* If link is connected, check for inactivity timeout */
+ if (p_lcb->link_state == LST_CONNECTED) {
+ /* Check for ping outstanding */
+ if (p_lcb->p_echo_rsp_cb) {
+ tL2CA_ECHO_RSP_CB* p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb)(L2CAP_PING_RESULT_NO_RESP);
+
+ L2CAP_TRACE_WARNING("L2CAP - ping timeout");
+
+ /* For all channels, send a disconnect indication event through */
+ /* their FSMs. The CCBs should remove themselves from the LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;) {
+ tL2C_CCB* pn = p_ccb->p_next_ccb;
+
+ l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+
+ p_ccb = pn;
+ }
+ }
+
+ /* If no channels in use, drop the link. */
+ if (!p_lcb->ccb_queue.p_first_ccb) {
+ period_ms_t timeout_ms;
+ bool start_timeout = true;
+
+ rc = btm_sec_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+
+ if (rc == BTM_CMD_STORED) {
+ /* Security Manager will take care of disconnecting, state will be
+ * updated at that time */
+ start_timeout = false;
+ } else if (rc == BTM_CMD_STARTED) {
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+ } else if (rc == BTM_SUCCESS) {
+ l2cu_process_fixed_disc_cback(p_lcb);
+ /* BTM SEC will make sure that link is release (probably after pairing
+ * is done) */
+ p_lcb->link_state = LST_DISCONNECTING;
+ start_timeout = false;
+ } else if (rc == BTM_BUSY) {
+ /* BTM is still executing security process. Let lcb stay as connected */
+ start_timeout = false;
+ } else if (p_lcb->is_bonding) {
+ btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+ l2cu_process_fixed_disc_cback(p_lcb);
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+ } else {
+ /* probably no buffer to send disconnect */
+ timeout_ms = BT_1SEC_TIMEOUT_MS;
+ }
+
+ if (start_timeout) {
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms,
+ l2c_lcb_timer_timeout, p_lcb,
+ btu_general_alarm_queue);
+ }
+ } else {
+ /* Check in case we were flow controlled */
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_info_resp_timer_timeout
+ *
+ * Description This function is called when an info request times out
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_info_resp_timer_timeout(void* data) {
+ tL2C_LCB* p_lcb = (tL2C_LCB*)data;
+ tL2C_CCB* p_ccb;
+ tL2C_CONN_INFO ci;
+
+ /* If we timed out waiting for info response, just continue using basic if
+ * allowed */
+ if (p_lcb->w4_info_rsp) {
+ /* If waiting for security complete, restart the info response timer */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ if ((p_ccb->chnl_state == CST_ORIG_W4_SEC_COMP) ||
+ (p_ccb->chnl_state == CST_TERM_W4_SEC_COMP)) {
+ alarm_set_on_queue(
+ p_lcb->info_resp_timer, L2CAP_WAIT_INFO_RSP_TIMEOUT_MS,
+ l2c_info_resp_timer_timeout, p_lcb, btu_general_alarm_queue);
+ return;
+ }
+ }
+
+ p_lcb->w4_info_rsp = false;
+
+ /* If link is in process of being brought up */
+ if ((p_lcb->link_state != LST_DISCONNECTED) &&
+ (p_lcb->link_state != LST_DISCONNECTING)) {
+ /* Notify active channels that peer info is finished */
+ if (p_lcb->ccb_queue.p_first_ccb) {
+ ci.status = HCI_SUCCESS;
+ memcpy(ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_adjust_allocation
+ *
+ * Description This function is called when a link is created or removed
+ * to calculate the amount of packets each link may send to
+ * the HCI without an ack coming back.
+ *
+ * Currently, this is a simple allocation, dividing the
+ * number of Controller Packets by the number of links. In
+ * the future, QOS configuration should be examined.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_adjust_allocation(void) {
+ uint16_t qq, yy, qq_remainder;
+ tL2C_LCB* p_lcb;
+ uint16_t hi_quota, low_quota;
+ uint16_t num_lowpri_links = 0;
+ uint16_t num_hipri_links = 0;
+ uint16_t controller_xmit_quota = l2cb.num_lm_acl_bufs;
+ uint16_t high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+
+ /* If no links active, reset buffer quotas and controller buffers */
+ if (l2cb.num_links_active == 0) {
+ l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+ l2cb.round_robin_quota = l2cb.round_robin_unacked = 0;
+ return;
+ }
+
+ /* First, count the links */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
+ /** M: only BR links should be counted here @{ */
+ if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_BR_EDR) {
+ /** @} */
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
+ num_hipri_links++;
+ else
+ num_lowpri_links++;
+ }
+ }
+
+ /* now adjust high priority link quota */
+ low_quota = num_lowpri_links ? 1 : 0;
+ while ((num_hipri_links * high_pri_link_quota + low_quota) >
+ controller_xmit_quota)
+ high_pri_link_quota--;
+
+ /* Work out the xmit quota and buffer quota high and low priorities */
+ hi_quota = num_hipri_links * high_pri_link_quota;
+ low_quota =
+ (hi_quota < controller_xmit_quota) ? controller_xmit_quota - hi_quota : 1;
+
+ /* Work out and save the HCI xmit quota for each low priority link */
+
+ /* If each low priority link cannot have at least one buffer */
+ if (num_lowpri_links > low_quota) {
+ l2cb.round_robin_quota = low_quota;
+ /** M: left 0 @{ */
+ qq = qq_remainder = 0;
+ /** @} */
+ }
+ /* If each low priority link can have at least one buffer */
+ else if (num_lowpri_links > 0) {
+ l2cb.round_robin_quota = 0;
+ l2cb.round_robin_unacked = 0;
+ qq = low_quota / num_lowpri_links;
+ qq_remainder = low_quota % num_lowpri_links;
+ }
+ /* If no low priority link */
+ else {
+ l2cb.round_robin_quota = 0;
+ l2cb.round_robin_unacked = 0;
+ /** M: left 0 @{ */
+ qq = qq_remainder = 0;
+ /** @} */
+ }
+
+ L2CAP_TRACE_EVENT(
+ "l2c_link_adjust_allocation num_hipri: %u num_lowpri: %u low_quota: "
+ "%u round_robin_quota: %u qq: %u",
+ num_hipri_links, num_lowpri_links, low_quota, l2cb.round_robin_quota, qq);
+
+ /* Now, assign the quotas to each link */
+ for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
+ /** M: only BR links should be counted here @{ */
+ if (p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_BR_EDR) {
+ /** @} */
+ if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) {
+ p_lcb->link_xmit_quota = high_pri_link_quota;
+ } else {
+ /* Safety check in case we switched to round-robin with something
+ * outstanding */
+ /* if sent_not_acked is added into round_robin_unacked then don't add it
+ * again */
+ /* l2cap keeps updating sent_not_acked for exiting from round robin */
+ if ((p_lcb->link_xmit_quota > 0) && (qq == 0))
+ l2cb.round_robin_unacked += p_lcb->sent_not_acked;
+
+ p_lcb->link_xmit_quota = qq;
+ if (qq_remainder > 0) {
+ p_lcb->link_xmit_quota++;
+ qq_remainder--;
+ }
+ }
+
+ L2CAP_TRACE_EVENT(
+ "l2c_link_adjust_allocation LCB %d Priority: %d XmitQuota: %d", yy,
+ p_lcb->acl_priority, p_lcb->link_xmit_quota);
+
+ L2CAP_TRACE_EVENT(" SentNotAcked: %d RRUnacked: %d",
+ p_lcb->sent_not_acked, l2cb.round_robin_unacked);
+
+ /* There is a special case where we have readjusted the link quotas and */
+ /* this link may have sent anything but some other link sent packets so */
+ /* so we may need a timer to kick off this link's transmissions. */
+ if ((p_lcb->link_state == LST_CONNECTED) &&
+ (!list_is_empty(p_lcb->link_xmit_data_q)) &&
+ (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
+ alarm_set_on_queue(
+ p_lcb->l2c_lcb_timer, L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_adjust_chnl_allocation
+ *
+ * Description This function is called to calculate the amount of packets
+ * each non-F&EC channel may have outstanding.
+ *
+ * Currently, this is a simple allocation, dividing the number
+ * of packets allocated to the link by the number of channels.
+ * In the future, QOS configuration should be examined.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_adjust_chnl_allocation(void) {
+ uint8_t xx;
+
+ L2CAP_TRACE_DEBUG("%s", __func__);
+
+ /* assign buffer quota to each channel based on its data rate requirement */
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) {
+ tL2C_CCB* p_ccb = l2cb.ccb_pool + xx;
+
+ if (!p_ccb->in_use) continue;
+
+ tL2CAP_CHNL_DATA_RATE data_rate = p_ccb->tx_data_rate + p_ccb->rx_data_rate;
+ p_ccb->buff_quota = L2CAP_CBB_DEFAULT_DATA_RATE_BUFF_QUOTA * data_rate;
+ L2CAP_TRACE_EVENT(
+ "CID:0x%04x FCR Mode:%u Priority:%u TxDataRate:%u RxDataRate:%u "
+ "Quota:%u",
+ p_ccb->local_cid, p_ccb->peer_cfg.fcr.mode, p_ccb->ccb_priority,
+ p_ccb->tx_data_rate, p_ccb->rx_data_rate, p_ccb->buff_quota);
+
+ /* quota may be change so check congestion */
+ l2cu_check_channel_congestion(p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_processs_num_bufs
+ *
+ * Description This function is called when a "controller buffer size"
+ * event is first received from the controller. It updates
+ * the L2CAP values.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_processs_num_bufs(uint16_t num_lm_acl_bufs) {
+ l2cb.num_lm_acl_bufs = l2cb.controller_xmit_window = num_lm_acl_bufs;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_pkts_rcvd
+ *
+ * Description This function is called from the HCI transport when it is
+ * time to send a "Host ready for packets" command. This is
+ * only when host to controller flow control is used. It fills
+ * in the arrays of numbers of packets and handles.
+ *
+ * Returns count of number of entries filled in
+ *
+ ******************************************************************************/
+uint8_t l2c_link_pkts_rcvd(UNUSED_ATTR uint16_t* num_pkts,
+ UNUSED_ATTR uint16_t* handles) {
+ uint8_t num_found = 0;
+
+ return (num_found);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_role_changed
+ *
+ * Description This function is called whan a link's master/slave role
+ * change event is received. It simply updates the link control
+ * block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_role_changed(BD_ADDR bd_addr, uint8_t new_role,
+ uint8_t hci_status) {
+ tL2C_LCB* p_lcb;
+ int xx;
+
+ /* Make sure not called from HCI Command Status (bd_addr and new_role are
+ * invalid) */
+ if (bd_addr) {
+ /* If here came form hci role change event */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb) {
+ p_lcb->link_role = new_role;
+
+ /* Reset high priority link if needed */
+ if (hci_status == HCI_SUCCESS)
+ l2cu_set_acl_priority(bd_addr, p_lcb->acl_priority, true);
+ }
+ }
+
+ /* Check if any LCB was waiting for switch to be completed */
+ for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->link_state == LST_CONNECTING_WAIT_SWITCH)) {
+ l2cu_create_conn_after_switch(p_lcb);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_pin_code_request
+ *
+ * Description This function is called whan a pin-code request is received
+ * on a connection. If there are no channels active yet on the
+ * link, it extends the link first connection timer. Make sure
+ * that inactivity timer is not extended if PIN code happens
+ * to be after last ccb released.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_pin_code_request(BD_ADDR bd_addr) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+
+ if ((p_lcb) && (!p_lcb->ccb_queue.p_first_ccb)) {
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_EXT_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+}
+
+#if (L2CAP_WAKE_PARKED_LINK == TRUE)
+/*******************************************************************************
+ *
+ * Function l2c_link_check_power_mode
+ *
+ * Description This function is called to check power mode.
+ *
+ * Returns true if link is going to be active from park
+ * false if nothing to send or not in park mode
+ *
+ ******************************************************************************/
+bool l2c_link_check_power_mode(tL2C_LCB* p_lcb) {
+ tBTM_PM_MODE mode;
+ tL2C_CCB* p_ccb;
+ bool need_to_active = false;
+
+ /*
+ * We only switch park to active only if we have unsent packets
+ */
+ if (list_is_empty(p_lcb->link_xmit_data_q)) {
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+ need_to_active = true;
+ break;
+ }
+ }
+ } else
+ need_to_active = true;
+
+ /* if we have packets to send */
+ if (need_to_active) {
+ /* check power mode */
+ if (BTM_ReadPowerMode(p_lcb->remote_bd_addr, &mode) == BTM_SUCCESS) {
+ if (mode == BTM_PM_STS_PENDING) {
+ L2CAP_TRACE_DEBUG("LCB(0x%x) is in PM pending state", p_lcb->handle);
+
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif /* L2CAP_WAKE_PARKED_LINK == TRUE) */
+
+/*******************************************************************************
+ *
+ * Function l2c_link_check_send_pkts
+ *
+ * Description This function is called to check if it can send packets
+ * to the Host Controller. It may be passed the address of
+ * a packet to send.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_check_send_pkts(tL2C_LCB* p_lcb, tL2C_CCB* p_ccb, BT_HDR* p_buf) {
+ int xx;
+ bool single_write = false;
+
+ /* Save the channel ID for faster counting */
+ if (p_buf) {
+ if (p_ccb != NULL) {
+ p_buf->event = p_ccb->local_cid;
+ single_write = true;
+ } else
+ p_buf->event = 0;
+
+ p_buf->layer_specific = 0;
+ list_append(p_lcb->link_xmit_data_q, p_buf);
+
+ if (p_lcb->link_xmit_quota == 0) {
+ if (p_lcb->transport == BT_TRANSPORT_LE)
+ l2cb.ble_check_round_robin = true;
+ else
+ l2cb.check_round_robin = true;
+ }
+ }
+
+ /* If this is called from uncongested callback context break recursive
+ *calling.
+ ** This LCB will be served when receiving number of completed packet event.
+ */
+ if (l2cb.is_cong_cback_context) return;
+
+ /* If we are in a scenario where there are not enough buffers for each link to
+ ** have at least 1, then do a round-robin for all the LCBs
+ */
+ if ((p_lcb == NULL) || (p_lcb->link_xmit_quota == 0)) {
+ if (p_lcb == NULL)
+ p_lcb = l2cb.lcb_pool;
+ else if (!single_write)
+ p_lcb++;
+
+ /* Loop through, starting at the next */
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ /* Check for wraparound */
+ if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS]) p_lcb = &l2cb.lcb_pool[0];
+
+ /* If controller window is full, nothing to do */
+ if (((l2cb.controller_xmit_window == 0 ||
+ (l2cb.round_robin_unacked >= l2cb.round_robin_quota)) &&
+ (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+ (p_lcb->transport == BT_TRANSPORT_LE &&
+ (l2cb.ble_round_robin_unacked >= l2cb.ble_round_robin_quota ||
+ l2cb.controller_le_xmit_window == 0)))
+ continue;
+
+ if ((!p_lcb->in_use) || (p_lcb->partial_segment_being_sent) ||
+ (p_lcb->link_state != LST_CONNECTED) ||
+ (p_lcb->link_xmit_quota != 0) || (L2C_LINK_CHECK_POWER_MODE(p_lcb)))
+ continue;
+
+ /* See if we can send anything from the Link Queue */
+ if (!list_is_empty(p_lcb->link_xmit_data_q)) {
+ p_buf = (BT_HDR*)list_front(p_lcb->link_xmit_data_q);
+ list_remove(p_lcb->link_xmit_data_q, p_buf);
+ l2c_link_send_to_lower(p_lcb, p_buf, NULL);
+ } else if (single_write) {
+ /* If only doing one write, break out */
+ break;
+ }
+ /* If nothing on the link queue, check the channel queue */
+ else {
+ tL2C_TX_COMPLETE_CB_INFO cbi;
+ p_buf = l2cu_get_next_buffer_to_send(p_lcb, &cbi);
+ if (p_buf != NULL) {
+ l2c_link_send_to_lower(p_lcb, p_buf, &cbi);
+ }
+ }
+ }
+
+ /* If we finished without using up our quota, no need for a safety check */
+ if ((l2cb.controller_xmit_window > 0) &&
+ (l2cb.round_robin_unacked < l2cb.round_robin_quota) &&
+ (p_lcb->transport == BT_TRANSPORT_BR_EDR))
+ l2cb.check_round_robin = false;
+
+ if ((l2cb.controller_le_xmit_window > 0) &&
+ (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota) &&
+ (p_lcb->transport == BT_TRANSPORT_LE))
+ l2cb.ble_check_round_robin = false;
+ } else /* if this is not round-robin service */
+ {
+ /* If a partial segment is being sent, can't send anything else */
+ if ((p_lcb->partial_segment_being_sent) ||
+ (p_lcb->link_state != LST_CONNECTED) ||
+ (L2C_LINK_CHECK_POWER_MODE(p_lcb)))
+ return;
+
+ /* See if we can send anything from the link queue */
+ while (((l2cb.controller_xmit_window != 0 &&
+ (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+ (l2cb.controller_le_xmit_window != 0 &&
+ (p_lcb->transport == BT_TRANSPORT_LE))) &&
+ (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
+ if (list_is_empty(p_lcb->link_xmit_data_q)) break;
+
+ p_buf = (BT_HDR*)list_front(p_lcb->link_xmit_data_q);
+ list_remove(p_lcb->link_xmit_data_q, p_buf);
+ if (!l2c_link_send_to_lower(p_lcb, p_buf, NULL)) break;
+ }
+
+ if (!single_write) {
+ /* See if we can send anything for any channel */
+ while (((l2cb.controller_xmit_window != 0 &&
+ (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+ (l2cb.controller_le_xmit_window != 0 &&
+ (p_lcb->transport == BT_TRANSPORT_LE))) &&
+ (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
+ tL2C_TX_COMPLETE_CB_INFO cbi;
+ p_buf = l2cu_get_next_buffer_to_send(p_lcb, &cbi);
+ if (p_buf == NULL) break;
+
+ if (!l2c_link_send_to_lower(p_lcb, p_buf, &cbi)) break;
+ }
+ }
+
+ /* There is a special case where we have readjusted the link quotas and */
+ /* this link may have sent anything but some other link sent packets so */
+ /* so we may need a timer to kick off this link's transmissions. */
+ if ((!list_is_empty(p_lcb->link_xmit_data_q)) &&
+ (p_lcb->sent_not_acked < p_lcb->link_xmit_quota)) {
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer,
+ L2CAP_LINK_FLOW_CONTROL_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_send_to_lower
+ *
+ * Description This function queues the buffer for HCI transmission
+ *
+ * Returns true for success, false for fail
+ *
+ ******************************************************************************/
+static bool l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
+ uint16_t num_segs;
+ uint16_t xmit_window, acl_data_size;
+ const controller_t* controller = controller_get_interface();
+
+ if ((p_buf->len <= controller->get_acl_packet_size_classic() &&
+ (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
+ ((p_lcb->transport == BT_TRANSPORT_LE) &&
+ (p_buf->len <= controller->get_acl_packet_size_ble()))) {
+ if (p_lcb->link_xmit_quota == 0) {
+ if (p_lcb->transport == BT_TRANSPORT_LE)
+ l2cb.ble_round_robin_unacked++;
+ else
+ l2cb.round_robin_unacked++;
+ }
+ p_lcb->sent_not_acked++;
+ p_buf->layer_specific = 0;
+
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ l2cb.controller_le_xmit_window--;
+ bte_main_hci_send(
+ p_buf, (uint16_t)(BT_EVT_TO_LM_HCI_ACL | LOCAL_BLE_CONTROLLER_ID));
+ } else {
+ l2cb.controller_xmit_window--;
+ bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL);
+ }
+ } else {
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ acl_data_size = controller->get_acl_data_size_ble();
+ xmit_window = l2cb.controller_le_xmit_window;
+
+ } else {
+ acl_data_size = controller->get_acl_data_size_classic();
+ xmit_window = l2cb.controller_xmit_window;
+ }
+ num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) /
+ acl_data_size;
+
+ /* If doing round-robin, then only 1 segment each time */
+ if (p_lcb->link_xmit_quota == 0) {
+ num_segs = 1;
+ p_lcb->partial_segment_being_sent = true;
+ } else {
+ /* Multi-segment packet. Make sure it can fit */
+ if (num_segs > xmit_window) {
+ num_segs = xmit_window;
+ p_lcb->partial_segment_being_sent = true;
+ }
+
+ if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked)) {
+ num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
+ p_lcb->partial_segment_being_sent = true;
+ }
+ }
+
+ p_buf->layer_specific = num_segs;
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ l2cb.controller_le_xmit_window -= num_segs;
+ if (p_lcb->link_xmit_quota == 0) l2cb.ble_round_robin_unacked += num_segs;
+ } else {
+ l2cb.controller_xmit_window -= num_segs;
+
+ if (p_lcb->link_xmit_quota == 0) l2cb.round_robin_unacked += num_segs;
+ }
+
+ p_lcb->sent_not_acked += num_segs;
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ bte_main_hci_send(
+ p_buf, (uint16_t)(BT_EVT_TO_LM_HCI_ACL | LOCAL_BLE_CONTROLLER_ID));
+ } else {
+ bte_main_hci_send(p_buf, BT_EVT_TO_LM_HCI_ACL);
+ }
+ }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG(
+ "TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+ l2cb.controller_le_xmit_window, p_lcb->handle, p_lcb->link_xmit_quota,
+ p_lcb->sent_not_acked, l2cb.ble_round_robin_quota,
+ l2cb.ble_round_robin_unacked);
+ } else {
+ L2CAP_TRACE_DEBUG(
+ "TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
+ l2cb.controller_xmit_window, p_lcb->handle, p_lcb->link_xmit_quota,
+ p_lcb->sent_not_acked, l2cb.round_robin_quota,
+ l2cb.round_robin_unacked);
+ }
+#endif
+
+ if (p_cbi) l2cu_tx_complete(p_cbi);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_process_num_completed_pkts
+ *
+ * Description This function is called when a "number-of-completed-packets"
+ * event is received from the controller. It updates all the
+ * LCB transmit counts.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_process_num_completed_pkts(uint8_t* p) {
+ uint8_t num_handles, xx;
+ uint16_t handle;
+ uint16_t num_sent;
+ tL2C_LCB* p_lcb;
+
+ STREAM_TO_UINT8(num_handles, p);
+
+ for (xx = 0; xx < num_handles; xx++) {
+ STREAM_TO_UINT16(handle, p);
+ STREAM_TO_UINT16(num_sent, p);
+
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ /* Callback for number of completed packet event */
+ /* Originally designed for [3DSG] */
+ if ((p_lcb != NULL) && (p_lcb->p_nocp_cb)) {
+ L2CAP_TRACE_DEBUG("L2CAP - calling NoCP callback");
+ (*p_lcb->p_nocp_cb)(p_lcb->remote_bd_addr);
+ }
+
+ if (p_lcb) {
+ if (p_lcb && (p_lcb->transport == BT_TRANSPORT_LE))
+ l2cb.controller_le_xmit_window += num_sent;
+ else {
+ /* Maintain the total window to the controller */
+ l2cb.controller_xmit_window += num_sent;
+ }
+ /* If doing round-robin, adjust communal counts */
+ if (p_lcb->link_xmit_quota == 0) {
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ /* Don't go negative */
+ if (l2cb.ble_round_robin_unacked > num_sent)
+ l2cb.ble_round_robin_unacked -= num_sent;
+ else
+ l2cb.ble_round_robin_unacked = 0;
+ } else {
+ /* Don't go negative */
+ if (l2cb.round_robin_unacked > num_sent)
+ l2cb.round_robin_unacked -= num_sent;
+ else
+ l2cb.round_robin_unacked = 0;
+ }
+ }
+
+ /* Don't go negative */
+ if (p_lcb->sent_not_acked > num_sent)
+ p_lcb->sent_not_acked -= num_sent;
+ else
+ p_lcb->sent_not_acked = 0;
+
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+
+ /* If we were doing round-robin for low priority links, check 'em */
+ if ((p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) &&
+ (l2cb.check_round_robin) &&
+ (l2cb.round_robin_unacked < l2cb.round_robin_quota)) {
+ l2c_link_check_send_pkts(NULL, NULL, NULL);
+ }
+ if ((p_lcb->transport == BT_TRANSPORT_LE) &&
+ (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) &&
+ ((l2cb.ble_check_round_robin) &&
+ (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota))) {
+ l2c_link_check_send_pkts(NULL, NULL, NULL);
+ }
+ }
+
+#if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
+ if (p_lcb) {
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG(
+ "TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+ l2cb.controller_le_xmit_window, p_lcb->handle,
+ p_lcb->sent_not_acked, l2cb.ble_check_round_robin,
+ l2cb.ble_round_robin_unacked);
+ } else {
+ L2CAP_TRACE_DEBUG(
+ "TotalWin=%d,LinkUnack(0x%x)=%d,RRCheck=%d,RRUnack=%d",
+ l2cb.controller_xmit_window, p_lcb->handle, p_lcb->sent_not_acked,
+ l2cb.check_round_robin, l2cb.round_robin_unacked);
+ }
+ } else {
+ L2CAP_TRACE_DEBUG(
+ "TotalWin=%d LE_Win: %d, Handle=0x%x, RRCheck=%d, RRUnack=%d",
+ l2cb.controller_xmit_window, l2cb.controller_le_xmit_window, handle,
+ l2cb.ble_check_round_robin, l2cb.ble_round_robin_unacked);
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_link_segments_xmitted
+ *
+ * Description This function is called from the HCI Interface when an ACL
+ * data packet segment is transmitted.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_link_segments_xmitted(BT_HDR* p_msg) {
+ uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint16_t handle;
+ tL2C_LCB* p_lcb;
+
+ /* Extract the handle */
+ STREAM_TO_UINT16(handle, p);
+ handle = HCID_GET_HANDLE(handle);
+
+ /* Find the LCB based on the handle */
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - rcvd segment complete, unknown handle: %d",
+ handle);
+ osi_free(p_msg);
+ return;
+ }
+
+ if (p_lcb->link_state == LST_CONNECTED) {
+ /* Enqueue the buffer to the head of the transmit queue, and see */
+ /* if we can transmit anything more. */
+ list_prepend(p_lcb->link_xmit_data_q, p_msg);
+
+ p_lcb->partial_segment_being_sent = false;
+
+ l2c_link_check_send_pkts(p_lcb, NULL, NULL);
+ } else
+ osi_free(p_msg);
+}
+
+#if defined(MTK_A2DP_SINK_SUPPORT) && (MTK_A2DP_SINK_SUPPORT == TRUE)
+/*******************************************************************************
+ *
+ * Function l2c_link_check_a2dp_link
+ *
+ * Description This function is called to check whether there is a2dp device connected
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+int l2c_link_check_a2dp_link(BD_ADDR bd_addr) {
+ tL2C_LCB* p_lcb_cur;
+ int xx;
+ tBTM_SEC_DEV_REC* p_dev_info; // used to store the device information
+ int major_dev_class; // store the major_dev_class of in_use device
+ int connected_a2dp_device_role; // 1: source, 2: sink, 0: no connected device
+
+ // step 1. Check whether there is a2dp link
+ for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
+ xx++, p_lcb_cur++) {
+
+ if (p_lcb_cur->in_use) {
+ // find the device information
+ p_dev_info = btm_find_dev(p_lcb_cur->remote_bd_addr);
+ major_dev_class = device_class_get_major_device((const bt_device_class_t *) p_dev_info->dev_class);
+ if (major_dev_class == 0x04) {
+ BTM_TRACE_EVENT("There is a2dp sink device connected");
+ connected_a2dp_device_role = 2;
+ return 2;
+ } else if (major_dev_class == 0x02) {
+ BTM_TRACE_EVENT("There is a2dp source device connected");
+ connected_a2dp_device_role = 1;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_main.cc b/mtkbt/code/bt/stack/l2cap/l2c_main.cc
new file mode 100755
index 0000000..dfe875a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_main.cc
@@ -0,0 +1,918 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the main L2CAP entry points
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_l2c_main"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len);
+
+/******************************************************************************/
+/* G L O B A L L 2 C A P D A T A */
+/******************************************************************************/
+tL2C_CB l2cb;
+
+/*******************************************************************************
+ *
+ * Function l2c_rcv_acl_data
+ *
+ * Description This function is called from the HCI Interface when an ACL
+ * data packet is received.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_rcv_acl_data(BT_HDR* p_msg) {
+ uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint16_t handle, hci_len;
+ uint8_t pkt_type;
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb = NULL;
+ uint16_t l2cap_len, rcv_cid, psm;
+ uint16_t credit;
+
+ /* Extract the handle */
+ STREAM_TO_UINT16(handle, p);
+ pkt_type = HCID_GET_EVENT(handle);
+ handle = HCID_GET_HANDLE(handle);
+
+ /* Since the HCI Transport is putting segmented packets back together, we */
+ /* should never get a valid packet with the type set to "continuation" */
+ if (pkt_type != L2CAP_PKT_CONTINUE) {
+ /* Find the LCB based on the handle */
+ p_lcb = l2cu_find_lcb_by_handle(handle);
+ if (p_lcb == NULL) {
+ uint8_t cmd_code;
+
+ /* There is a slight possibility (specifically with USB) that we get an */
+ /* L2CAP connection request before we get the HCI connection complete. */
+ /* So for these types of messages, hold them for up to 2 seconds. */
+ STREAM_TO_UINT16(hci_len, p);
+ STREAM_TO_UINT16(l2cap_len, p);
+ STREAM_TO_UINT16(rcv_cid, p);
+ STREAM_TO_UINT8(cmd_code, p);
+
+ if ((p_msg->layer_specific == 0) && (rcv_cid == L2CAP_SIGNALLING_CID) &&
+ (cmd_code == L2CAP_CMD_INFO_REQ || cmd_code == L2CAP_CMD_CONN_REQ)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - holding ACL for unknown handle:%d ls:%d"
+ " cid:%d opcode:%d cur count:%d",
+ handle, p_msg->layer_specific, rcv_cid, cmd_code,
+ list_length(l2cb.rcv_pending_q));
+ p_msg->layer_specific = 2;
+ list_append(l2cb.rcv_pending_q, p_msg);
+
+ if (list_length(l2cb.rcv_pending_q) == 1) {
+ alarm_set_on_queue(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
+ l2c_receive_hold_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+
+ return;
+ } else {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - rcvd ACL for unknown handle:%d ls:%d cid:%d"
+ " opcode:%d cur count:%d",
+ handle, p_msg->layer_specific, rcv_cid, cmd_code,
+ list_length(l2cb.rcv_pending_q));
+ }
+ osi_free(p_msg);
+ return;
+ }
+ } else {
+ L2CAP_TRACE_WARNING("L2CAP - expected pkt start or complete, got: %d",
+ pkt_type);
+ osi_free(p_msg);
+ return;
+ }
+
+ /* Extract the length and update the buffer header */
+ STREAM_TO_UINT16(hci_len, p);
+ p_msg->offset += 4;
+
+ if (hci_len < L2CAP_PKT_OVERHEAD) {
+ /* Must receive at least the L2CAP length and CID */
+ L2CAP_TRACE_WARNING("L2CAP - got incorrect hci header");
+ osi_free(p_msg);
+ return;
+ }
+
+ /* Extract the length and CID */
+ STREAM_TO_UINT16(l2cap_len, p);
+ STREAM_TO_UINT16(rcv_cid, p);
+
+ /* for BLE channel, always notify connection when ACL data received on the
+ * link */
+ if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE &&
+ p_lcb->link_state != LST_DISCONNECTING)
+ /* only process fixed channel data as channel open indication when link is
+ * not in disconnecting mode */
+ l2cble_notify_le_connection(p_lcb->remote_bd_addr);
+
+ /* Find the CCB for this CID */
+ if (rcv_cid >= L2CAP_BASE_APPL_CID) {
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, rcv_cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - unknown CID: 0x%04x", rcv_cid);
+ osi_free(p_msg);
+ return;
+ }
+ }
+
+ p_msg->len = hci_len - L2CAP_PKT_OVERHEAD;
+ p_msg->offset += L2CAP_PKT_OVERHEAD;
+
+ if (l2cap_len != p_msg->len) {
+ L2CAP_TRACE_WARNING("L2CAP - bad length in pkt. Exp: %d Act: %d",
+ l2cap_len, p_msg->len);
+
+ osi_free(p_msg);
+ return;
+ }
+
+ /* Send the data through the channel state machine */
+ if (rcv_cid == L2CAP_SIGNALLING_CID) {
+ process_l2cap_cmd(p_lcb, p, l2cap_len);
+ osi_free(p_msg);
+ } else if (rcv_cid == L2CAP_CONNECTIONLESS_CID) {
+ /* process_connectionless_data (p_lcb); */
+ STREAM_TO_UINT16(psm, p);
+ L2CAP_TRACE_DEBUG("GOT CONNECTIONLESS DATA PSM:%d", psm);
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* if it is not broadcast, check UCD registration */
+ if (l2c_ucd_check_rx_pkts(p_lcb, p_msg)) {
+ /* nothing to do */
+ } else
+#endif
+ osi_free(p_msg);
+ } else if (rcv_cid == L2CAP_BLE_SIGNALLING_CID) {
+ l2cble_process_sig_cmd(p_lcb, p, l2cap_len);
+ osi_free(p_msg);
+ }
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ else if ((rcv_cid >= L2CAP_FIRST_FIXED_CHNL) &&
+ (rcv_cid <= L2CAP_LAST_FIXED_CHNL) &&
+ (l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL]
+ .pL2CA_FixedData_Cb != NULL)) {
+ /* If no CCB for this channel, allocate one */
+ if (p_lcb &&
+ /* only process fixed channel data when link is open or wait for data
+ indication */
+ (p_lcb->link_state != LST_DISCONNECTING) &&
+ l2cu_initialize_fixed_ccb(
+ p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL]
+ .fixed_chnl_opts)) {
+ p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
+
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
+ l2c_fcr_proc_pdu(p_ccb, p_msg);
+ else
+ (*l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)(
+ rcv_cid, p_lcb->remote_bd_addr, p_msg);
+ } else
+ osi_free(p_msg);
+ }
+#endif
+
+ else {
+ if (p_ccb == NULL)
+ osi_free(p_msg);
+ else {
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ l2c_lcc_proc_pdu(p_ccb, p_msg);
+ // Got a pkt, valid send out credits to the peer device
+ credit = L2CAP_LE_DEFAULT_CREDIT;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT, &credit);
+ } else {
+ /* Basic mode packets go straight to the state machine */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+ else {
+ /* eRTM or streaming mode, so we need to validate states first */
+ if ((p_ccb->chnl_state == CST_OPEN) ||
+ (p_ccb->chnl_state == CST_CONFIG))
+ l2c_fcr_proc_pdu(p_ccb, p_msg);
+ else
+ osi_free(p_msg);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function process_l2cap_cmd
+ *
+ * Description This function is called when a packet is received on the
+ * L2CAP signalling CID
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
+ uint8_t *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start;
+ uint8_t cmd_code, cfg_code, cfg_len, id;
+ tL2C_CONN_INFO con_info;
+ tL2CAP_CFG_INFO cfg_info;
+ uint16_t rej_reason, rej_mtu, lcid, rcid, info_type;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+ bool cfg_rej, pkt_size_rej = false;
+ uint16_t cfg_rej_len, cmd_len;
+ uint16_t result;
+ tL2C_CONN_INFO ci;
+
+ /* if l2cap command received in CID 1 on top of an LE link, ignore this
+ * command */
+ if (p_lcb->transport == BT_TRANSPORT_LE) return;
+
+ /* Reject the packet if it exceeds the default Signalling Channel MTU */
+ if (pkt_len > L2CAP_DEFAULT_MTU) {
+ /* Core Spec requires a single response to the first command found in a
+ *multi-command
+ ** L2cap packet. If only responses in the packet, then it will be ignored.
+ ** Here we simply mark the bad packet and decide which cmd ID to reject
+ *later
+ */
+ pkt_size_rej = true;
+ L2CAP_TRACE_ERROR("L2CAP SIG MTU Pkt Len Exceeded (672) -> pkt_len: %d",
+ pkt_len);
+ }
+
+ p_next_cmd = p;
+ p_pkt_end = p + pkt_len;
+
+ memset(&cfg_info, 0, sizeof(cfg_info));
+
+ /* An L2CAP packet may contain multiple commands */
+ while (true) {
+ /* Smallest command is 4 bytes */
+ p = p_next_cmd;
+ if (p > (p_pkt_end - 4)) break;
+
+ STREAM_TO_UINT8(cmd_code, p);
+ STREAM_TO_UINT8(id, p);
+ STREAM_TO_UINT16(cmd_len, p);
+
+ if (cmd_len > BT_SMALL_BUFFER_SIZE) {
+ L2CAP_TRACE_WARNING("L2CAP - Invalid MTU Size");
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id, 0, 0);
+ return;
+ }
+
+ /* Check command length does not exceed packet length */
+ p_next_cmd = p + cmd_len;
+ if (p_next_cmd > p_pkt_end) {
+ L2CAP_TRACE_WARNING("Command len bad pkt_len: %d cmd_len: %d code: %d",
+ pkt_len, cmd_len, cmd_code);
+ break;
+ }
+
+ L2CAP_TRACE_DEBUG("cmd_code: %d, id:%d, cmd_len:%d", cmd_code, id, cmd_len);
+
+ /* Bad L2CAP packet length, look or cmd to reject */
+ if (pkt_size_rej) {
+ /* If command found rejected it and we're done, otherwise keep looking */
+ if (l2c_is_cmd_rejected(cmd_code, id, p_lcb))
+ return;
+ else
+ continue; /* Look for next cmd/response in current packet */
+ }
+
+ switch (cmd_code) {
+ case L2CAP_CMD_REJECT:
+ STREAM_TO_UINT16(rej_reason, p);
+ if (rej_reason == L2CAP_CMD_REJ_MTU_EXCEEDED) {
+ STREAM_TO_UINT16(rej_mtu, p);
+ /* What to do with the MTU reject ? We have negotiated an MTU. For now
+ */
+ /* we will ignore it and let a higher protocol timeout take care of it
+ */
+
+ L2CAP_TRACE_WARNING("L2CAP - MTU rej Handle: %d MTU: %d",
+ p_lcb->handle, rej_mtu);
+ }
+ if (rej_reason == L2CAP_CMD_REJ_INVALID_CID) {
+ STREAM_TO_UINT16(rcid, p);
+ STREAM_TO_UINT16(lcid, p);
+
+ L2CAP_TRACE_WARNING(
+ "L2CAP - rej with CID invalid, LCID: 0x%04x RCID: 0x%04x", lcid,
+ rcid);
+
+ /* Remote CID invalid. Treat as a disconnect */
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if ((p_ccb != NULL) && (p_ccb->remote_cid == rcid)) {
+ /* Fake link disconnect - no reply is generated */
+ l2c_csm_execute(p_ccb, L2CEVT_LP_DISCONNECT_IND, NULL);
+ }
+ }
+
+ /* SonyEricsson Info request Bug workaround (Continue connection) */
+ else if (rej_reason == L2CAP_CMD_REJ_NOT_UNDERSTOOD &&
+ p_lcb->w4_info_rsp) {
+ alarm_cancel(p_lcb->info_resp_timer);
+
+ p_lcb->w4_info_rsp = false;
+ ci.status = HCI_SUCCESS;
+ memcpy(ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ }
+ break;
+
+ case L2CAP_CMD_CONN_REQ:
+ STREAM_TO_UINT16(con_info.psm, p);
+ STREAM_TO_UINT16(rcid, p);
+ p_rcb = l2cu_find_rcb_by_psm(con_info.psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: %d",
+ con_info.psm);
+ l2cu_reject_connection(p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+ break;
+ } else {
+ if (!p_rcb->api.pL2CA_ConnectInd_Cb) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - rcvd conn req for outgoing-only connection PSM: %d",
+ con_info.psm);
+ l2cu_reject_connection(p_lcb, rcid, id, L2CAP_CONN_NO_PSM);
+ break;
+ }
+ }
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - unable to allocate CCB");
+ l2cu_reject_connection(p_lcb, rcid, id, L2CAP_CONN_NO_RESOURCES);
+ break;
+ }
+ p_ccb->remote_id = id;
+ p_ccb->p_rcb = p_rcb;
+ p_ccb->remote_cid = rcid;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
+ break;
+
+ case L2CAP_CMD_CONN_RSP:
+ STREAM_TO_UINT16(con_info.remote_cid, p);
+ STREAM_TO_UINT16(lcid, p);
+ STREAM_TO_UINT16(con_info.l2cap_result, p);
+ STREAM_TO_UINT16(con_info.l2cap_status, p);
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for conn rsp, LCID: %d RCID: %d",
+ lcid, con_info.remote_cid);
+ break;
+ }
+ if (p_ccb->local_id != id) {
+ L2CAP_TRACE_WARNING("L2CAP - con rsp - bad ID. Exp: %d Got: %d",
+ p_ccb->local_id, id);
+ break;
+ }
+
+ if (con_info.l2cap_result == L2CAP_CONN_OK)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
+ else if (con_info.l2cap_result == L2CAP_CONN_PENDING)
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_PND, &con_info);
+ else
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
+
+ break;
+
+ case L2CAP_CMD_CONFIG_REQ:
+ p_cfg_end = p + cmd_len;
+ cfg_rej = false;
+ cfg_rej_len = 0;
+
+ STREAM_TO_UINT16(lcid, p);
+ STREAM_TO_UINT16(cfg_info.flags, p);
+
+ p_cfg_start = p;
+
+ cfg_info.flush_to_present = cfg_info.mtu_present =
+ cfg_info.qos_present = cfg_info.fcr_present = cfg_info.fcs_present =
+ false;
+
+ while (p < p_cfg_end) {
+ STREAM_TO_UINT8(cfg_code, p);
+ STREAM_TO_UINT8(cfg_len, p);
+
+ switch (cfg_code & 0x7F) {
+ case L2CAP_CFG_TYPE_MTU:
+ cfg_info.mtu_present = true;
+ STREAM_TO_UINT16(cfg_info.mtu, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ cfg_info.flush_to_present = true;
+ STREAM_TO_UINT16(cfg_info.flush_to, p);
+ break;
+
+ case L2CAP_CFG_TYPE_QOS:
+ cfg_info.qos_present = true;
+ STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
+ STREAM_TO_UINT8(cfg_info.qos.service_type, p);
+ STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
+ STREAM_TO_UINT32(cfg_info.qos.token_bucket_size, p);
+ STREAM_TO_UINT32(cfg_info.qos.peak_bandwidth, p);
+ STREAM_TO_UINT32(cfg_info.qos.latency, p);
+ STREAM_TO_UINT32(cfg_info.qos.delay_variation, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCR:
+ cfg_info.fcr_present = true;
+ STREAM_TO_UINT8(cfg_info.fcr.mode, p);
+ STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
+ STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
+ STREAM_TO_UINT16(cfg_info.fcr.rtrans_tout, p);
+ STREAM_TO_UINT16(cfg_info.fcr.mon_tout, p);
+ STREAM_TO_UINT16(cfg_info.fcr.mps, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCS:
+ cfg_info.fcs_present = true;
+ STREAM_TO_UINT8(cfg_info.fcs, p);
+ break;
+
+ case L2CAP_CFG_TYPE_EXT_FLOW:
+ cfg_info.ext_flow_spec_present = true;
+ STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
+ STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
+ STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.sdu_inter_time, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.access_latency, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.flush_timeout, p);
+ break;
+
+ default:
+ /* sanity check option length */
+ if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len) {
+ p += cfg_len;
+ if ((cfg_code & 0x80) == 0) {
+ cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ cfg_rej = true;
+ }
+ }
+ /* bad length; force loop exit */
+ else {
+ p = p_cfg_end;
+ cfg_rej = true;
+ }
+ break;
+ }
+ }
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ p_ccb->remote_id = id;
+ if (cfg_rej) {
+ l2cu_send_peer_config_rej(
+ p_ccb, p_cfg_start, (uint16_t)(cmd_len - L2CAP_CONFIG_REQ_LEN),
+ cfg_rej_len);
+ } else {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_REQ, &cfg_info);
+ }
+ } else {
+ /* updated spec says send command reject on invalid cid */
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_INVALID_CID, id, 0, 0);
+ }
+ break;
+
+ case L2CAP_CMD_CONFIG_RSP:
+ p_cfg_end = p + cmd_len;
+ STREAM_TO_UINT16(lcid, p);
+ STREAM_TO_UINT16(cfg_info.flags, p);
+ STREAM_TO_UINT16(cfg_info.result, p);
+
+ cfg_info.flush_to_present = cfg_info.mtu_present =
+ cfg_info.qos_present = cfg_info.fcr_present = cfg_info.fcs_present =
+ false;
+
+ while (p < p_cfg_end) {
+ STREAM_TO_UINT8(cfg_code, p);
+ STREAM_TO_UINT8(cfg_len, p);
+
+ switch (cfg_code & 0x7F) {
+ case L2CAP_CFG_TYPE_MTU:
+ cfg_info.mtu_present = true;
+ STREAM_TO_UINT16(cfg_info.mtu, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ cfg_info.flush_to_present = true;
+ STREAM_TO_UINT16(cfg_info.flush_to, p);
+ break;
+
+ case L2CAP_CFG_TYPE_QOS:
+ cfg_info.qos_present = true;
+ STREAM_TO_UINT8(cfg_info.qos.qos_flags, p);
+ STREAM_TO_UINT8(cfg_info.qos.service_type, p);
+ STREAM_TO_UINT32(cfg_info.qos.token_rate, p);
+ STREAM_TO_UINT32(cfg_info.qos.token_bucket_size, p);
+ STREAM_TO_UINT32(cfg_info.qos.peak_bandwidth, p);
+ STREAM_TO_UINT32(cfg_info.qos.latency, p);
+ STREAM_TO_UINT32(cfg_info.qos.delay_variation, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCR:
+ cfg_info.fcr_present = true;
+ STREAM_TO_UINT8(cfg_info.fcr.mode, p);
+ STREAM_TO_UINT8(cfg_info.fcr.tx_win_sz, p);
+ STREAM_TO_UINT8(cfg_info.fcr.max_transmit, p);
+ STREAM_TO_UINT16(cfg_info.fcr.rtrans_tout, p);
+ STREAM_TO_UINT16(cfg_info.fcr.mon_tout, p);
+ STREAM_TO_UINT16(cfg_info.fcr.mps, p);
+ break;
+
+ case L2CAP_CFG_TYPE_FCS:
+ cfg_info.fcs_present = true;
+ STREAM_TO_UINT8(cfg_info.fcs, p);
+ break;
+
+ case L2CAP_CFG_TYPE_EXT_FLOW:
+ cfg_info.ext_flow_spec_present = true;
+ STREAM_TO_UINT8(cfg_info.ext_flow_spec.id, p);
+ STREAM_TO_UINT8(cfg_info.ext_flow_spec.stype, p);
+ STREAM_TO_UINT16(cfg_info.ext_flow_spec.max_sdu_size, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.sdu_inter_time, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.access_latency, p);
+ STREAM_TO_UINT32(cfg_info.ext_flow_spec.flush_timeout, p);
+ break;
+ }
+ }
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ if (p_ccb->local_id != id) {
+ L2CAP_TRACE_WARNING("L2CAP - cfg rsp - bad ID. Exp: %d Got: %d",
+ p_ccb->local_id, id);
+ break;
+ }
+ if ((cfg_info.result == L2CAP_CFG_OK) ||
+ (cfg_info.result == L2CAP_CFG_PENDING))
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_RSP, &cfg_info);
+ else
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONFIG_RSP_NEG, &cfg_info);
+ } else {
+ L2CAP_TRACE_WARNING("L2CAP - rcvd cfg rsp for unknown CID: 0x%04x",
+ lcid);
+ }
+ break;
+
+ case L2CAP_CMD_DISC_REQ:
+ STREAM_TO_UINT16(lcid, p);
+ STREAM_TO_UINT16(rcid, p);
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ if (p_ccb->remote_cid == rcid) {
+ p_ccb->remote_id = id;
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_REQ, &con_info);
+ }
+ } else
+ l2cu_send_peer_disc_rsp(p_lcb, id, lcid, rcid);
+
+ break;
+
+ case L2CAP_CMD_DISC_RSP:
+ STREAM_TO_UINT16(rcid, p);
+ STREAM_TO_UINT16(lcid, p);
+
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid);
+ if (p_ccb != NULL) {
+ if ((p_ccb->remote_cid == rcid) && (p_ccb->local_id == id)) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DISCONNECT_RSP, &con_info);
+ }
+ }
+ break;
+
+ case L2CAP_CMD_ECHO_REQ:
+ l2cu_send_peer_echo_rsp(p_lcb, id, p, cmd_len);
+ break;
+
+ case L2CAP_CMD_ECHO_RSP:
+ if (p_lcb->p_echo_rsp_cb) {
+ tL2CA_ECHO_RSP_CB* p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb)(L2CAP_PING_RESULT_OK);
+ }
+ break;
+
+ case L2CAP_CMD_INFO_REQ:
+ STREAM_TO_UINT16(info_type, p);
+ l2cu_send_peer_info_rsp(p_lcb, id, info_type);
+ break;
+
+ case L2CAP_CMD_INFO_RSP:
+ /* Stop the link connect timer if sent before L2CAP connection is up */
+ if (p_lcb->w4_info_rsp) {
+ alarm_cancel(p_lcb->info_resp_timer);
+ p_lcb->w4_info_rsp = false;
+ }
+ /** M: ignore the response @{ */
+ else {
+ L2CAP_TRACE_WARNING ("L2CAP_CMD_INFO_RSP is received, but w4_info_rsp is FALSE !!!");
+ break;
+ }
+ /** @} */
+
+ STREAM_TO_UINT16(info_type, p);
+ STREAM_TO_UINT16(result, p);
+
+ p_lcb->info_rx_bits |= (1 << info_type);
+
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
+ (result == L2CAP_INFO_RESP_RESULT_SUCCESS)) {
+ STREAM_TO_UINT32(p_lcb->peer_ext_fea, p);
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (p_lcb->peer_ext_fea & L2CAP_EXTFEA_FIXED_CHNLS) {
+ l2cu_send_peer_info_req(p_lcb, L2CAP_FIXED_CHANNELS_INFO_TYPE);
+ break;
+ } else {
+ l2cu_process_fixed_chnl_resp(p_lcb);
+ }
+#endif
+ }
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) {
+ if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) {
+ memcpy(p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+ }
+
+ l2cu_process_fixed_chnl_resp(p_lcb);
+ }
+#endif
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) {
+ if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) {
+ STREAM_TO_UINT16(p_lcb->ucd_mtu, p);
+ }
+ }
+#endif
+
+ ci.status = HCI_SUCCESS;
+ memcpy(ci.bd_addr, p_lcb->remote_bd_addr, sizeof(BD_ADDR));
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_ccb->p_next_ccb) {
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_INFO_RSP, &ci);
+ }
+ break;
+
+ default:
+ L2CAP_TRACE_WARNING("L2CAP - bad cmd code: %d", cmd_code);
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_NOT_UNDERSTOOD, id, 0,
+ 0);
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_process_held_packets
+ *
+ * Description This function processes any L2CAP packets that arrived
+ * before the HCI connection complete arrived. It is a work
+ * around for badly behaved controllers.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_process_held_packets(bool timed_out) {
+ if (list_is_empty(l2cb.rcv_pending_q)) return;
+
+ if (!timed_out) {
+ alarm_cancel(l2cb.receive_hold_timer);
+ L2CAP_TRACE_WARNING("L2CAP HOLD CONTINUE");
+ } else {
+ L2CAP_TRACE_WARNING("L2CAP HOLD TIMEOUT");
+ }
+
+ for (const list_node_t* node = list_begin(l2cb.rcv_pending_q);
+ node != list_end(l2cb.rcv_pending_q);) {
+ BT_HDR* p_buf = static_cast<BT_HDR*>(list_node(node));
+ node = list_next(node);
+ if (!timed_out || (!p_buf->layer_specific) ||
+ (--p_buf->layer_specific == 0)) {
+ list_remove(l2cb.rcv_pending_q, p_buf);
+ p_buf->layer_specific = 0xFFFF;
+ l2c_rcv_acl_data(p_buf);
+ }
+ }
+
+ /* If anyone still in the queue, restart the timeout */
+ if (!list_is_empty(l2cb.rcv_pending_q)) {
+ alarm_set_on_queue(l2cb.receive_hold_timer, BT_1SEC_TIMEOUT_MS,
+ l2c_receive_hold_timer_timeout, NULL,
+ btu_general_alarm_queue);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_init
+ *
+ * Description This function is called once at startup to initialize
+ * all the L2CAP structures
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2c_init(void) {
+ int16_t xx;
+
+ memset(&l2cb, 0, sizeof(tL2C_CB));
+ /* the psm is increased by 2 before being used */
+ l2cb.dyn_psm = 0xFFF;
+
+ /* Put all the channel control blocks on the free queue */
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS - 1; xx++) {
+ l2cb.ccb_pool[xx].p_next_ccb = &l2cb.ccb_pool[xx + 1];
+ }
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ /* it will be set to L2CAP_PKT_START_NON_FLUSHABLE if controller supports */
+ l2cb.non_flushable_pbf = L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT;
+#endif
+
+ l2cb.p_free_ccb_first = &l2cb.ccb_pool[0];
+ l2cb.p_free_ccb_last = &l2cb.ccb_pool[MAX_L2CAP_CHANNELS - 1];
+
+#ifdef L2CAP_DESIRED_LINK_ROLE
+ l2cb.desire_role = L2CAP_DESIRED_LINK_ROLE;
+#else
+ l2cb.desire_role = HCI_ROLE_SLAVE;
+#endif
+
+ /* Set the default idle timeout */
+ l2cb.idle_timeout = L2CAP_LINK_INACTIVITY_TOUT;
+
+#if defined(L2CAP_INITIAL_TRACE_LEVEL)
+ l2cb.l2cap_trace_level = L2CAP_INITIAL_TRACE_LEVEL;
+#else
+ l2cb.l2cap_trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ /* Conformance testing needs a dynamic response */
+ l2cb.test_info_resp = L2CAP_EXTFEA_SUPPORTED_MASK;
+#endif
+
+/* Number of ACL buffers to use for high priority channel */
+#if (L2CAP_HIGH_PRI_CHAN_QUOTA_IS_CONFIGURABLE == TRUE)
+ l2cb.high_pri_min_xmit_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA;
+#endif
+
+ l2cb.l2c_ble_fixed_chnls_mask = L2CAP_FIXED_CHNL_ATT_BIT |
+ L2CAP_FIXED_CHNL_BLE_SIG_BIT |
+ L2CAP_FIXED_CHNL_SMP_BIT;
+
+ l2cb.rcv_pending_q = list_new(NULL);
+ CHECK(l2cb.rcv_pending_q != NULL);
+
+ l2cb.receive_hold_timer = alarm_new("l2c.receive_hold_timer");
+}
+
+void l2c_free(void) {
+ list_free(l2cb.rcv_pending_q);
+ l2cb.rcv_pending_q = NULL;
+}
+
+void l2c_receive_hold_timer_timeout(UNUSED_ATTR void* data) {
+ /* Update the timeouts in the hold queue */
+ l2c_process_held_packets(true);
+}
+
+void l2c_ccb_timer_timeout(void* data) {
+ tL2C_CCB* p_ccb = (tL2C_CCB*)data;
+
+ l2c_csm_execute(p_ccb, L2CEVT_TIMEOUT, NULL);
+}
+
+void l2c_fcrb_ack_timer_timeout(void* data) {
+ tL2C_CCB* p_ccb = (tL2C_CCB*)data;
+
+ l2c_csm_execute(p_ccb, L2CEVT_ACK_TIMEOUT, NULL);
+}
+
+void l2c_lcb_timer_timeout(void* data) {
+ tL2C_LCB* p_lcb = (tL2C_LCB*)data;
+
+ l2c_link_timeout(p_lcb);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_data_write
+ *
+ * Description API functions call this function to write data.
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t l2c_data_write(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
+ tL2C_CCB* p_ccb;
+
+ /* Find the channel control block. We don't know the link it is on. */
+ p_ccb = l2cu_find_ccb_by_cid(NULL, cid);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_DataWrite, CID: %d", cid);
+ osi_free(p_data);
+ return (L2CAP_DW_FAILED);
+ }
+
+#ifndef TESTER /* Tester may send any amount of data. otherwise sending \
+ message \
+ bigger than mtu size of peer is a violation of protocol */
+ uint16_t mtu;
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
+ mtu = p_ccb->peer_conn_cfg.mtu;
+ else
+ mtu = p_ccb->peer_cfg.mtu;
+
+ if (p_data->len > mtu) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - CID: 0x%04x cannot send message bigger than peer's mtu size: "
+ "len=%u mtu=%u",
+ cid, p_data->len, mtu);
+ osi_free(p_data);
+ return (L2CAP_DW_FAILED);
+ }
+#endif
+
+ /* channel based, packet based flushable or non-flushable */
+ p_data->layer_specific = flags;
+
+ /* If already congested, do not accept any more packets */
+ if (p_ccb->cong_sent) {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - CID: 0x%04x cannot send, already congested "
+ "xmit_hold_q.count: %u buff_quota: %u",
+ p_ccb->local_cid, fixed_queue_length(p_ccb->xmit_hold_q),
+ p_ccb->buff_quota);
+
+ osi_free(p_data);
+ return (L2CAP_DW_FAILED);
+ }
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DATA_WRITE, p_data);
+
+ if (p_ccb->cong_sent) return (L2CAP_DW_CONGESTED);
+
+ return (L2CAP_DW_SUCCESS);
+}
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_ucd.cc b/mtkbt/code/bt/stack/l2cap/l2c_ucd.cc
new file mode 100755
index 0000000..2e9f695
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_ucd.cc
@@ -0,0 +1,1114 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the L2CAP UCD code
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+
+extern fixed_queue_t* btu_bta_alarm_queue;
+
+static bool l2c_ucd_connect(BD_ADDR rem_bda);
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_discover_cback
+ *
+ * Description UCD Discover callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_discover_cback(BD_ADDR rem_bda, uint8_t info_type,
+ uint32_t data) {
+ tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
+ uint16_t xx;
+
+ L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_discover_cback");
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if (p_rcb->in_use) {
+ /* if this application is waiting UCD reception info */
+ if ((info_type == L2CAP_UCD_INFO_TYPE_RECEPTION) &&
+ (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION)) {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(rem_bda, info_type, data);
+ p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION);
+ }
+
+ /* if this application is waiting UCD MTU info */
+ if ((info_type == L2CAP_UCD_INFO_TYPE_MTU) &&
+ (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU)) {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(rem_bda, info_type, data);
+ p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_data_ind_cback
+ *
+ * Description UCD Data callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_data_ind_cback(BD_ADDR rem_bda, BT_HDR* p_buf) {
+ uint8_t* p;
+ uint16_t psm;
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_data_ind_cback");
+
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT16(psm, p)
+
+ p_buf->offset += L2CAP_UCD_OVERHEAD;
+ p_buf->len -= L2CAP_UCD_OVERHEAD;
+
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x",
+ psm);
+ osi_free(p_buf);
+ } else {
+ p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_congestion_status_cback
+ *
+ * Description UCD Congestion Status callback
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_congestion_status_cback(BD_ADDR rem_bda,
+ bool is_congested) {
+ tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
+ uint16_t xx;
+
+ L2CAP_TRACE_DEBUG("L2CAP - l2c_ucd_congestion_status_cback");
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED)) {
+ if (p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
+ L2CAP_TRACE_DEBUG(
+ "L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: "
+ "%08x%04x,",
+ is_congested, p_rcb->psm, (rem_bda[0] << 24) + (rem_bda[1] << 16) +
+ (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(rem_bda,
+ is_congested);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_disconnect_ind_cback
+ *
+ * Description UCD disconnect callback (Prevent to access null pointer)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_disconnect_ind_cback(uint16_t cid, bool result) {
+ /* do nothing */
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_config_ind_cback
+ *
+ * Description UCD config callback (This prevent to access null pointer)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_config_ind_cback(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ /* do nothing */
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_config_cfm_cback
+ *
+ * Description UCD config callback (This prevent to access null pointer)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void l2c_ucd_config_cfm_cback(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ /* do nothing */
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdRegister
+ *
+ * Description Register PSM on UCD.
+ *
+ * Parameters: tL2CAP_UCD_CB_INFO
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdRegister(uint16_t psm, tL2CAP_UCD_CB_INFO* p_cb_info) {
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_API("L2CA_UcdRegister() PSM: 0x%04x", psm);
+
+ if ((!p_cb_info->pL2CA_UCD_Discover_Cb) || (!p_cb_info->pL2CA_UCD_Data_Cb)) {
+ L2CAP_TRACE_ERROR("L2CAP - no callback registering PSM(0x%04x) on UCD",
+ psm);
+ return (false);
+ }
+
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm);
+ return (false);
+ }
+
+ p_rcb->ucd.state = L2C_UCD_STATE_W4_DATA;
+ p_rcb->ucd.cb_info = *p_cb_info;
+
+ /* check if master rcb is created for UCD */
+ p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
+ if (p_rcb == NULL) {
+ p_rcb = l2cu_allocate_rcb(L2C_UCD_RCB_ID);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - no RCB available for L2CA_UcdRegister");
+ return (false);
+ } else {
+ /* these callback functions will forward data to each UCD application */
+ p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb = l2c_ucd_discover_cback;
+ p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb = l2c_ucd_data_ind_cback;
+ p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb =
+ l2c_ucd_congestion_status_cback;
+
+ memset(&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO));
+ p_rcb->api.pL2CA_DisconnectInd_Cb = l2c_ucd_disconnect_ind_cback;
+
+ /* This will make L2CAP check UCD congestion callback */
+ p_rcb->api.pL2CA_CongestionStatus_Cb = NULL;
+
+ /* do nothing but prevent crash */
+ p_rcb->api.pL2CA_ConfigInd_Cb = l2c_ucd_config_ind_cback;
+ p_rcb->api.pL2CA_ConfigCfm_Cb = l2c_ucd_config_cfm_cback;
+ }
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDeregister
+ *
+ * Description Deregister PSM on UCD.
+ *
+ * Parameters: PSM
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDeregister(uint16_t psm) {
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+ uint16_t xx;
+
+ L2CAP_TRACE_API("L2CA_UcdDeregister() PSM: 0x%04x", psm);
+
+ p_rcb = l2cu_find_rcb_by_psm(psm);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x",
+ psm);
+ return (false);
+ }
+
+ p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+
+ /* check this was the last UCD registration */
+ p_rcb = &l2cb.rcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED))
+ return (true);
+ }
+
+ /* delete master rcb for UCD */
+ p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
+ if (p_rcb != NULL) {
+ l2cu_release_rcb(p_rcb);
+ }
+
+ /* delete CCB for UCD */
+ p_ccb = l2cb.ccb_pool;
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) {
+ if ((p_ccb->in_use) && (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)) {
+ l2cu_release_ccb(p_ccb);
+ }
+ p_ccb++;
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDiscover
+ *
+ * Description Discover UCD of remote device.
+ *
+ * Parameters: PSM
+ * BD_ADDR of remote device
+ * info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+ * L2CAP_UCD_INFO_TYPE_MTU
+ *
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDiscover(uint16_t psm, BD_ADDR rem_bda, uint8_t info_type) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_API(
+ "L2CA_UcdDiscover() PSM: 0x%04x BDA: %08x%04x, InfoType=0x%02x", psm,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5], info_type);
+
+ /* Fail if the PSM is not registered */
+ if (((p_rcb = l2cu_find_rcb_by_psm(psm)) == NULL) ||
+ (p_rcb->ucd.state == L2C_UCD_STATE_UNUSED)) {
+ L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x",
+ psm);
+ return (false);
+ }
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block for UCD. */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
+ NULL) ||
+ ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
+ NULL)) {
+ if (l2c_ucd_connect(rem_bda) == false) {
+ return (false);
+ }
+ }
+
+ /* set waiting flags in rcb */
+
+ if (info_type & L2CAP_UCD_INFO_TYPE_RECEPTION)
+ p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION;
+
+ if (info_type & L2CAP_UCD_INFO_TYPE_MTU)
+ p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU;
+
+ /* if link is already established */
+ if ((p_lcb) && (p_lcb->link_state == LST_CONNECTED)) {
+ if (!p_ccb) {
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
+ }
+ l2c_ucd_check_pending_info_req(p_ccb);
+ }
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDataWrite
+ *
+ * Description Send UCD to remote device
+ *
+ * Parameters: PSM
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_UcdDataWrite(uint16_t psm, BD_ADDR rem_bda, BT_HDR* p_buf,
+ uint16_t flags) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+ uint8_t* p;
+
+ L2CAP_TRACE_API(
+ "L2CA_UcdDataWrite() PSM: 0x%04x BDA: %08x%04x", psm,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ /* Fail if the PSM is not registered */
+ if (((p_rcb = l2cu_find_rcb_by_psm(psm)) == NULL) ||
+ (p_rcb->ucd.state == L2C_UCD_STATE_UNUSED)) {
+ L2CAP_TRACE_WARNING("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x",
+ psm);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block for UCD */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
+ NULL) ||
+ ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
+ NULL)) {
+ if (l2c_ucd_connect(rem_bda) == false) {
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* If we still don't have lcb and ccb after connect attempt, then can't
+ * proceed */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
+ NULL) ||
+ ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
+ NULL)) {
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+ }
+
+ /* write PSM */
+ p_buf->offset -= L2CAP_UCD_OVERHEAD;
+ p_buf->len += L2CAP_UCD_OVERHEAD;
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ UINT16_TO_STREAM(p, psm);
+
+ /* UCD MTU check */
+ if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - Handle: 0x%04x UCD bigger than peer's UCD mtu size cannot be "
+ "sent",
+ p_lcb->handle);
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* If already congested, do not accept any more packets */
+ if (p_ccb->cong_sent) {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: "
+ "%u buff_quota: %u",
+ p_lcb->handle, (fixed_queue_length(p_ccb->xmit_hold_q) +
+ fixed_queue_length(p_lcb->ucd_out_sec_pending_q)),
+ p_ccb->buff_quota);
+
+ osi_free(p_buf);
+ return (L2CAP_DW_FAILED);
+ }
+
+ /* channel based, packet based flushable or non-flushable */
+ p_buf->layer_specific = flags;
+
+ l2c_csm_execute(p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf);
+
+ if (p_ccb->cong_sent)
+ return (L2CAP_DW_CONGESTED);
+ else
+ return (L2CAP_DW_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdSetIdleTimeout
+ *
+ * Description Set UCD Idle timeout.
+ *
+ * Parameters: BD Addr
+ * Timeout in second
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdSetIdleTimeout(BD_ADDR rem_bda, uint16_t timeout) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_UcdSetIdleTimeout() Timeout: 0x%04x BDA: %08x%04x", timeout,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ /* First, see if we already have a link to the remote */
+ /* then find the channel control block. */
+ if (((p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR)) ==
+ NULL) ||
+ ((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) ==
+ NULL)) {
+ L2CAP_TRACE_WARNING("L2CAP - no UCD channel");
+ return (false);
+ } else {
+ p_ccb->fixed_chnl_idle_tout = timeout;
+ return (true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function L2CA_UCDSetTxPriority
+ *
+ * Description Sets the transmission priority for a connectionless channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_UCDSetTxPriority(BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+
+ L2CAP_TRACE_API(
+ "L2CA_UCDSetTxPriority() priority: 0x%02x BDA: %08x%04x", priority,
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_UCDSetTxPriority");
+ return (false);
+ }
+
+ /* Find the channel control block */
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for L2CA_UCDSetTxPriority");
+ return (false);
+ }
+
+ /* it will update the order of CCB in LCB by priority and update round robin
+ * service variables */
+ l2cu_change_pri_ccb(p_ccb, priority);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_connect
+ *
+ * Description Connect UCD to remote device.
+ *
+ * Parameters: BD_ADDR of remote device
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+static bool l2c_ucd_connect(BD_ADDR rem_bda) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+
+ L2CAP_TRACE_DEBUG(
+ "l2c_ucd_connect() BDA: %08x%04x",
+ (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3],
+ (rem_bda[4] << 8) + rem_bda[5]);
+
+ /* Fail if we have not established communications with the controller */
+ if (!BTM_IsDeviceUp()) {
+ L2CAP_TRACE_WARNING("l2c_ucd_connect - BTU not ready");
+ return (false);
+ }
+
+ /* First, see if we already have a link to the remote */
+ p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ /* No link. Get an LCB and start link establishment */
+ if (((p_lcb = l2cu_allocate_lcb(rem_bda, false, BT_TRANSPORT_BR_EDR)) ==
+ NULL) ||
+ (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == false)) {
+ L2CAP_TRACE_WARNING("L2CAP - conn not started l2c_ucd_connect");
+ return (false);
+ }
+ } else if (p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE)) {
+ if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - UCD is not supported by peer, l2c_ucd_connect");
+ return (false);
+ }
+ }
+
+ /* Find the channel control block. */
+ p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID);
+ if (p_ccb == NULL) {
+ /* Allocate a channel control block */
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for l2c_ucd_connect");
+ return (false);
+ } else {
+ /* Set CID for the connection */
+ p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
+ p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+ /* Set the default channel priority value to use */
+ l2cu_change_pri_ccb(p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+ p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID);
+ if (p_rcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no UCD registered, l2c_ucd_connect");
+ return (false);
+ }
+ /* Save UCD registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ /* There is no configuration, so if the link is up, the channel is up */
+ if (p_lcb->link_state == LST_CONNECTED) {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ }
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_delete_sec_pending_q
+ *
+ * Description discard all of UCD packets in security pending queue
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2c_ucd_delete_sec_pending_q(tL2C_LCB* p_lcb) {
+ /* clean up any security pending UCD */
+ while (!fixed_queue_is_empty(p_lcb->ucd_out_sec_pending_q))
+ osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q));
+ fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL);
+ p_lcb->ucd_out_sec_pending_q = NULL;
+
+ while (!fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q))
+ osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q));
+ fixed_queue_free(p_lcb->ucd_in_sec_pending_q);
+ p_lcb->ucd_in_sec_pending_q = NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_check_pending_info_req
+ *
+ * Description check if any application is waiting for UCD information
+ *
+ * Return true if any pending UCD info request
+ *
+ ******************************************************************************/
+bool l2c_ucd_check_pending_info_req(tL2C_CCB* p_ccb) {
+ tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
+ uint16_t xx;
+ bool pending = false;
+
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_ERROR("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req");
+ return (false);
+ }
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if (p_rcb->in_use) {
+ /* if application is waiting UCD reception info */
+ if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION) {
+ /* if this information is available */
+ if (p_ccb->p_lcb->info_rx_bits &
+ (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE)) {
+ if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) {
+ L2CAP_TRACE_WARNING(
+ "L2CAP - UCD is not supported by peer, "
+ "l2c_ucd_check_pending_info_req");
+
+ l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb);
+ l2cu_release_ccb(p_ccb);
+ }
+
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(
+ p_ccb->p_lcb->remote_bd_addr, L2CAP_UCD_INFO_TYPE_RECEPTION,
+ p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION);
+ } else {
+ pending = true;
+ if (p_ccb->p_lcb->w4_info_rsp == false) {
+ l2cu_send_peer_info_req(p_ccb->p_lcb,
+ L2CAP_EXTENDED_FEATURES_INFO_TYPE);
+ }
+ }
+ }
+
+ /* if application is waiting for UCD MTU */
+ if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU) {
+ /* if this information is available */
+ if (p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE)) {
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb(
+ p_ccb->p_lcb->remote_bd_addr, L2CAP_UCD_INFO_TYPE_MTU,
+ p_ccb->p_lcb->ucd_mtu);
+ } else {
+ pending = true;
+ if (p_ccb->p_lcb->w4_info_rsp == false) {
+ l2cu_send_peer_info_req(p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE);
+ }
+ }
+ }
+ }
+ }
+ return (pending);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_enqueue_pending_out_sec_q
+ *
+ * Description enqueue outgoing UCD packet into security pending queue
+ * and check congestion
+ *
+ * Return None
+ *
+ ******************************************************************************/
+void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB* p_ccb, void* p_data) {
+ fixed_queue_enqueue(p_ccb->p_lcb->ucd_out_sec_pending_q, p_data);
+ l2cu_check_channel_congestion(p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_check_pending_out_sec_q
+ *
+ * Description check outgoing security
+ *
+ * Return true if any UCD packet for security
+ *
+ ******************************************************************************/
+bool l2c_ucd_check_pending_out_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_peek_first(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+ if (p_buf != NULL) {
+ uint16_t psm;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ STREAM_TO_UINT16(psm, p)
+
+ p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
+ btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, psm,
+ p_ccb->p_lcb->handle, CONNLESS_ORIG,
+ &l2c_link_sec_comp, p_ccb);
+
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_send_pending_out_sec_q
+ *
+ * Description dequeue UCD packet from security pending queue and
+ * enqueue it into CCB
+ *
+ * Return None
+ *
+ ******************************************************************************/
+void l2c_ucd_send_pending_out_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+ if (p_buf != NULL) {
+ l2c_enqueue_peer_data(p_ccb, (BT_HDR*)p_buf);
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_discard_pending_out_sec_q
+ *
+ * Description dequeue UCD packet from security pending queue and
+ * discard it.
+ *
+ * Return None
+ *
+ ******************************************************************************/
+void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
+
+ /* we may need to report to application */
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_check_pending_in_sec_q
+ *
+ * Description check incoming security
+ *
+ * Return true if any UCD packet for security
+ *
+ ******************************************************************************/
+bool l2c_ucd_check_pending_in_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
+
+ if (p_buf != NULL) {
+ uint16_t psm;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ STREAM_TO_UINT16(psm, p)
+
+ p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
+ btm_sec_l2cap_access_req(p_ccb->p_lcb->remote_bd_addr, psm,
+ p_ccb->p_lcb->handle, CONNLESS_TERM,
+ &l2c_link_sec_comp, p_ccb);
+
+ return (true);
+ }
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_send_pending_in_sec_q
+ *
+ * Description dequeue UCD packet from security pending queue and
+ * send it to application
+ *
+ * Return None
+ *
+ ******************************************************************************/
+void l2c_ucd_send_pending_in_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q)
+
+ if (p_buf != NULL) {
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr,
+ (BT_HDR*)p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_discard_pending_in_sec_q
+ *
+ * Description dequeue UCD packet from security pending queue and
+ * discard it.
+ *
+ * Return None
+ *
+ ******************************************************************************/
+void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf =
+ (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_check_rx_pkts
+ *
+ * Description Check if UCD reception is registered.
+ * Process received UCD packet if application is expecting.
+ *
+ * Return true if UCD reception is registered
+ *
+ ******************************************************************************/
+bool l2c_ucd_check_rx_pkts(tL2C_LCB* p_lcb, BT_HDR* p_msg) {
+ tL2C_CCB* p_ccb;
+ tL2C_RCB* p_rcb;
+
+ if (((p_ccb = l2cu_find_ccb_by_cid(p_lcb, L2CAP_CONNECTIONLESS_CID)) !=
+ NULL) ||
+ ((p_rcb = l2cu_find_rcb_by_psm(L2C_UCD_RCB_ID)) != NULL)) {
+ if (p_ccb == NULL) {
+ /* Allocate a channel control block */
+ p_ccb = l2cu_allocate_ccb(p_lcb, 0);
+ if (p_ccb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no CCB for UCD reception");
+ osi_free(p_msg);
+ return true;
+ } else {
+ /* Set CID for the connection */
+ p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID;
+ p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT;
+
+ /* Set the default channel priority value to use */
+ l2cu_change_pri_ccb(p_ccb, L2CAP_UCD_CH_PRIORITY);
+
+ /* Save registration info */
+ p_ccb->p_rcb = p_rcb;
+
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
+ return true;
+ } else
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function l2c_ucd_process_event
+ *
+ * Description This is called from main state machine when LCID is
+ * connectionless. Process the event if it is for UCD.
+ *
+ * Return true if the event is consumed by UCD
+ * false if the event needs to be processed by the main state
+ * machine
+ *
+ ******************************************************************************/
+bool l2c_ucd_process_event(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {
+ /* if the event is not processed by this function, this variable will be set
+ * to false */
+ bool done = true;
+
+ switch (p_ccb->chnl_state) {
+ case CST_CLOSED:
+ switch (event) {
+ case L2CEVT_LP_CONNECT_CFM: /* Link came up */
+ /* check if waiting for UCD info */
+ if (!l2c_ucd_check_pending_info_req(p_ccb)) {
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ if (!l2c_ucd_check_pending_info_req(p_ccb)) {
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ }
+ break;
+
+ default:
+ done = false; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ case CST_ORIG_W4_SEC_COMP:
+ switch (event) {
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ /* check if any outgoing UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_out_sec_q(p_ccb)) {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ break;
+
+ case L2CEVT_SEC_COMP: /* Security completed success */
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_send_pending_out_sec_q(p_ccb);
+
+ if (!fixed_queue_is_empty(p_ccb->p_lcb->ucd_out_sec_pending_q)) {
+ /* start a timer to send next UCD packet in OPEN state */
+ /* it will prevent stack overflow */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, 0, l2c_ccb_timer_timeout,
+ p_ccb, btu_general_alarm_queue);
+ } else {
+ /* start a timer for idle timeout of UCD */
+ period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_discard_pending_out_sec_q(p_ccb);
+
+ /* start a timer for idle timeout of UCD */
+ period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req(p_ccb);
+ break;
+
+ default:
+ done = false; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ case CST_TERM_W4_SEC_COMP:
+ switch (event) {
+ case L2CEVT_SEC_COMP:
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_send_pending_in_sec_q(p_ccb);
+
+ if (!fixed_queue_is_empty(p_ccb->p_lcb->ucd_in_sec_pending_q)) {
+ /* start a timer to check next UCD packet in OPEN state */
+ /* it will prevent stack overflow */
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, 0, l2c_ccb_timer_timeout,
+ p_ccb, btu_general_alarm_queue);
+ } else {
+ /* start a timer for idle timeout of UCD */
+ period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ break;
+
+ case L2CEVT_SEC_COMP_NEG:
+ if (((tL2C_CONN_INFO*)p_data)->status == BTM_DELAY_CHECK) {
+ done = false;
+ break;
+ }
+ p_ccb->chnl_state = CST_OPEN;
+ l2c_ucd_discard_pending_in_sec_q(p_ccb);
+
+ /* start a timer for idle timeout of UCD */
+ period_ms_t timeout_ms = p_ccb->fixed_chnl_idle_tout * 1000;
+ alarm_set_on_queue(p_ccb->l2c_ccb_timer, timeout_ms,
+ l2c_ccb_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+ break;
+
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ break;
+
+ case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
+ /* check if any incoming UCD packet is waiting security check */
+ if (!l2c_ucd_check_pending_in_sec_q(p_ccb)) {
+ p_ccb->chnl_state = CST_OPEN;
+ }
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req(p_ccb);
+ break;
+
+ default:
+ done = false; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ case CST_OPEN:
+ switch (event) {
+ case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
+ /* stop idle timer of UCD */
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+
+ fixed_queue_enqueue(p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
+ l2c_ucd_check_pending_in_sec_q(p_ccb);
+ break;
+
+ case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
+ /* stop idle timer of UCD */
+ alarm_cancel(p_ccb->l2c_ccb_timer);
+
+ l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
+
+ /* success changes state, failure stays in current state */
+ l2c_ucd_check_pending_out_sec_q(p_ccb);
+ break;
+
+ case L2CEVT_TIMEOUT:
+ /* check if any UCD packet is waiting security check */
+ if ((!l2c_ucd_check_pending_in_sec_q(p_ccb)) &&
+ (!l2c_ucd_check_pending_out_sec_q(p_ccb))) {
+ l2cu_release_ccb(p_ccb);
+ }
+ break;
+
+ case L2CEVT_L2CAP_INFO_RSP:
+ /* check if waiting for UCD info */
+ l2c_ucd_check_pending_info_req(p_ccb);
+ break;
+
+ default:
+ done = false; /* main state machine continues to process event */
+ break;
+ }
+ break;
+
+ default:
+ done = false; /* main state machine continues to process event */
+ break;
+ }
+
+ return done;
+}
+#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
diff --git a/mtkbt/code/bt/stack/l2cap/l2c_utils.cc b/mtkbt/code/bt/stack/l2cap/l2c_utils.cc
new file mode 100755
index 0000000..aedbf37
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2c_utils.cc
@@ -0,0 +1,3577 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains L2CAP utility functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "osi/include/allocator.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function l2cu_can_allocate_lcb
+ *
+ * Description Look for an unused LCB
+ *
+ * Returns true if there is space for one more lcb
+ *
+ ******************************************************************************/
+bool l2cu_can_allocate_lcb(void) {
+ for (int i = 0; i < MAX_L2CAP_LINKS; i++) {
+ if (!l2cb.lcb_pool[i].in_use) return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_allocate_lcb
+ *
+ * Description Look for an unused LCB
+ *
+ * Returns LCB address or NULL if none found
+ *
+ ******************************************************************************/
+tL2C_LCB* l2cu_allocate_lcb(BD_ADDR p_bd_addr, bool is_bonding,
+ tBT_TRANSPORT transport) {
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if (!p_lcb->in_use) {
+ alarm_free(p_lcb->l2c_lcb_timer);
+ alarm_free(p_lcb->info_resp_timer);
+ memset(p_lcb, 0, sizeof(tL2C_LCB));
+
+ memcpy(p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN);
+
+ p_lcb->in_use = true;
+ p_lcb->link_state = LST_DISCONNECTED;
+ p_lcb->handle = HCI_INVALID_HANDLE;
+ p_lcb->link_flush_tout = 0xFFFF;
+ p_lcb->l2c_lcb_timer = alarm_new("l2c_lcb.l2c_lcb_timer");
+ p_lcb->info_resp_timer = alarm_new("l2c_lcb.info_resp_timer");
+ p_lcb->idle_timeout = l2cb.idle_timeout;
+ p_lcb->id = 1; /* spec does not allow '0' */
+ p_lcb->is_bonding = is_bonding;
+ p_lcb->transport = transport;
+ p_lcb->tx_data_len =
+ controller_get_interface()->get_ble_default_data_packet_length();
+ p_lcb->le_sec_pending_q = fixed_queue_new(SIZE_MAX);
+
+ if (transport == BT_TRANSPORT_LE) {
+ l2cb.num_ble_links_active++;
+ l2c_ble_link_adjust_allocation();
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+ if (l2cb.num_ble_links_active == 1 && l2cb.num_links_active > 0)
+ l2c_link_adjust_allocation();
+#endif
+ } else {
+ l2cb.num_links_active++;
+ l2c_link_adjust_allocation();
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_lcb->ucd_out_sec_pending_q = fixed_queue_new(SIZE_MAX);
+ p_lcb->ucd_in_sec_pending_q = fixed_queue_new(SIZE_MAX);
+#endif
+ p_lcb->link_xmit_data_q = list_new(NULL);
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no free LCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_update_lcb_4_bonding
+ *
+ * Description Mark the lcb for bonding. Used when bonding takes place on
+ * an existing ACL connection. (Pre-Lisbon devices)
+ *
+ * Returns Nothing
+ *
+ ******************************************************************************/
+void l2cu_update_lcb_4_bonding(BD_ADDR p_bd_addr, bool is_bonding) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(p_bd_addr, BT_TRANSPORT_BR_EDR);
+
+ if (p_lcb) {
+ L2CAP_TRACE_DEBUG("l2cu_update_lcb_4_bonding BDA: %08x%04x is_bonding: %d",
+ (p_bd_addr[0] << 24) + (p_bd_addr[1] << 16) +
+ (p_bd_addr[2] << 8) + p_bd_addr[3],
+ (p_bd_addr[4] << 8) + p_bd_addr[5], is_bonding);
+ p_lcb->is_bonding = is_bonding;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_release_lcb
+ *
+ * Description Release an LCB. All timers will be stopped and freed,
+ * channels dropped, buffers returned etc.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_release_lcb(tL2C_LCB* p_lcb) {
+ tL2C_CCB* p_ccb;
+
+ /** M: do not release twice @{ */
+ if (p_lcb->in_use != TRUE) {
+ L2CAP_TRACE_DEBUG("l2cu_release_lcb: lcb is not inuse !!!");
+ return;
+ }
+ /** @} */
+ p_lcb->in_use = false;
+ p_lcb->is_bonding = false;
+
+ /* Stop and free timers */
+ alarm_free(p_lcb->l2c_lcb_timer);
+ p_lcb->l2c_lcb_timer = NULL;
+ alarm_free(p_lcb->info_resp_timer);
+ p_lcb->info_resp_timer = NULL;
+
+ /* Release any unfinished L2CAP packet on this link */
+ osi_free_and_reset((void**)&p_lcb->p_hcit_rcv_acl);
+
+#if (BTM_SCO_INCLUDED == TRUE)
+ if (p_lcb->transport == BT_TRANSPORT_BR_EDR) /* Release all SCO links */
+ btm_remove_sco_links(p_lcb->remote_bd_addr);
+#endif
+
+ if (p_lcb->sent_not_acked > 0) {
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ l2cb.controller_le_xmit_window += p_lcb->sent_not_acked;
+ if (l2cb.controller_le_xmit_window > l2cb.num_lm_ble_bufs) {
+ l2cb.controller_le_xmit_window = l2cb.num_lm_ble_bufs;
+ }
+ /** M: resume LE rr unacked count @{ */
+ if (p_lcb->link_xmit_quota == 0) {
+ if (l2cb.ble_round_robin_unacked > p_lcb->sent_not_acked)
+ l2cb.ble_round_robin_unacked -= p_lcb->sent_not_acked;
+ else
+ l2cb.ble_round_robin_unacked = 0;
+ }
+ /** @} */
+ } else {
+ l2cb.controller_xmit_window += p_lcb->sent_not_acked;
+ if (l2cb.controller_xmit_window > l2cb.num_lm_acl_bufs) {
+ l2cb.controller_xmit_window = l2cb.num_lm_acl_bufs;
+ }
+ /** M: resume BR rr unacked count @{ */
+ if (p_lcb->link_xmit_quota == 0) {
+ if (l2cb.round_robin_unacked > p_lcb->sent_not_acked)
+ l2cb.round_robin_unacked -= p_lcb->sent_not_acked;
+ else
+ l2cb.round_robin_unacked = 0;
+ }
+ /** @} */
+ }
+ }
+
+ // Reset BLE connecting flag only if the address matches
+ if (!memcmp(l2cb.ble_connecting_bda, p_lcb->remote_bd_addr, BD_ADDR_LEN))
+ l2cb.is_ble_connecting = false;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ l2cu_process_fixed_disc_cback(p_lcb);
+#endif
+
+ /* Ensure no CCBs left on this LCB */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb;
+ p_ccb = p_lcb->ccb_queue.p_first_ccb) {
+ l2cu_release_ccb(p_ccb);
+ }
+
+ /* Tell BTM Acl management the link was removed */
+ if ((p_lcb->link_state == LST_CONNECTED) ||
+ (p_lcb->link_state == LST_DISCONNECTING))
+ btm_acl_removed(p_lcb->remote_bd_addr, p_lcb->transport);
+
+ /* Release any held buffers */
+ if (p_lcb->link_xmit_data_q) {
+ while (!list_is_empty(p_lcb->link_xmit_data_q)) {
+ BT_HDR* p_buf = static_cast<BT_HDR*>(list_front(p_lcb->link_xmit_data_q));
+ list_remove(p_lcb->link_xmit_data_q, p_buf);
+ osi_free(p_buf);
+ }
+ list_free(p_lcb->link_xmit_data_q);
+ p_lcb->link_xmit_data_q = NULL;
+ }
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ /* clean up any security pending UCD */
+ l2c_ucd_delete_sec_pending_q(p_lcb);
+#endif
+
+ /* Re-adjust flow control windows make sure it does not go negative */
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ if (l2cb.num_ble_links_active >= 1) l2cb.num_ble_links_active--;
+
+ l2c_ble_link_adjust_allocation();
+ } else {
+ if (l2cb.num_links_active >= 1) l2cb.num_links_active--;
+
+ l2c_link_adjust_allocation();
+ }
+
+ /* Check for ping outstanding */
+ if (p_lcb->p_echo_rsp_cb) {
+ tL2CA_ECHO_RSP_CB* p_cb = p_lcb->p_echo_rsp_cb;
+
+ /* Zero out the callback in case app immediately calls us again */
+ p_lcb->p_echo_rsp_cb = NULL;
+
+ (*p_cb)(L2CAP_PING_RESULT_NO_LINK);
+ }
+
+ /* Check and release all the LE COC connections waiting for security */
+ if (p_lcb->le_sec_pending_q) {
+ while (!fixed_queue_is_empty(p_lcb->le_sec_pending_q)) {
+ tL2CAP_SEC_DATA* p_buf =
+ (tL2CAP_SEC_DATA*)fixed_queue_try_dequeue(p_lcb->le_sec_pending_q);
+ if (p_buf->p_callback)
+ p_buf->p_callback(p_lcb->remote_bd_addr, p_lcb->transport,
+ p_buf->p_ref_data, BTM_DEV_RESET);
+ osi_free(p_buf);
+ }
+ fixed_queue_free(p_lcb->le_sec_pending_q, NULL);
+ p_lcb->le_sec_pending_q = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_lcb_by_bd_addr
+ *
+ * Description Look through all active LCBs for a match based on the
+ * remote BD address.
+ *
+ * Returns pointer to matched LCB, or NULL if no match
+ *
+ ******************************************************************************/
+tL2C_LCB* l2cu_find_lcb_by_bd_addr(BD_ADDR p_bd_addr, tBT_TRANSPORT transport) {
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && p_lcb->transport == transport &&
+ (!memcmp(p_lcb->remote_bd_addr, p_bd_addr, BD_ADDR_LEN))) {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_get_conn_role
+ *
+ * Description Determine the desired role (master or slave) of a link.
+ * If already got a slave link, this one must be a master. If
+ * already got at least 1 link where we are the master, make
+ * this also a master.
+ *
+ * Returns HCI_ROLE_MASTER or HCI_ROLE_SLAVE
+ *
+ ******************************************************************************/
+uint8_t l2cu_get_conn_role(tL2C_LCB* p_this_lcb) { return l2cb.desire_role; }
+
+/*******************************************************************************
+ *
+ * Function l2c_is_cmd_rejected
+ *
+ * Description Checks if cmd_code is command or response
+ * If a command it will be rejected per spec.
+ * This function is used when a illegal packet length is
+ * detected.
+ *
+ * Returns bool - true if cmd_code is a command and it is rejected,
+ * false if response code. (command not rejected)
+ *
+ ******************************************************************************/
+bool l2c_is_cmd_rejected(uint8_t cmd_code, uint8_t id, tL2C_LCB* p_lcb) {
+ switch (cmd_code) {
+ case L2CAP_CMD_CONN_REQ:
+ case L2CAP_CMD_CONFIG_REQ:
+ case L2CAP_CMD_DISC_REQ:
+ case L2CAP_CMD_ECHO_REQ:
+ case L2CAP_CMD_INFO_REQ:
+ case L2CAP_CMD_AMP_CONN_REQ:
+ case L2CAP_CMD_AMP_MOVE_REQ:
+ case L2CAP_CMD_BLE_UPDATE_REQ:
+ l2cu_send_peer_cmd_reject(p_lcb, L2CAP_CMD_REJ_MTU_EXCEEDED, id,
+ L2CAP_DEFAULT_MTU, 0);
+ L2CAP_TRACE_WARNING("Dumping first Command (%d)", cmd_code);
+ return true;
+
+ default: /* Otherwise a response */
+ return false;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_build_header
+ *
+ * Description Builds the L2CAP command packet header
+ *
+ * Returns Pointer to allocated packet or NULL if no resources
+ *
+ ******************************************************************************/
+BT_HDR* l2cu_build_header(tL2C_LCB* p_lcb, uint16_t len, uint8_t cmd,
+ uint8_t id) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(L2CAP_CMD_BUF_SIZE);
+ uint8_t* p;
+
+ p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+ p_buf->len =
+ len + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+ /* Put in HCI header - handle + pkt boundary */
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ UINT16_TO_STREAM(p, (p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE
+ << L2CAP_PKT_TYPE_SHIFT)));
+ } else {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ UINT16_TO_STREAM(p, p_lcb->handle | l2cb.non_flushable_pbf);
+#else
+ UINT16_TO_STREAM(
+ p, (p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+#endif
+ }
+
+ UINT16_TO_STREAM(p, len + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD);
+ UINT16_TO_STREAM(p, len + L2CAP_CMD_OVERHEAD);
+
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ UINT16_TO_STREAM(p, L2CAP_BLE_SIGNALLING_CID);
+ } else {
+ UINT16_TO_STREAM(p, L2CAP_SIGNALLING_CID);
+ }
+
+ /* Put in L2CAP command header */
+ UINT8_TO_STREAM(p, cmd);
+ UINT8_TO_STREAM(p, id);
+ UINT16_TO_STREAM(p, len);
+
+ return (p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_adj_id
+ *
+ * Description Checks for valid ID based on specified mask
+ * and adjusts the id if invalid.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_adj_id(tL2C_LCB* p_lcb, uint8_t adj_mask) {
+ if ((adj_mask & L2CAP_ADJ_ZERO_ID) && !p_lcb->id) {
+ p_lcb->id++;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_cmd_reject
+ *
+ * Description Build and send an L2CAP "command reject" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_cmd_reject(tL2C_LCB* p_lcb, uint16_t reason, uint8_t rem_id,
+ uint16_t p1, uint16_t p2) {
+ uint16_t param_len;
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ /* Put in L2CAP packet header */
+ if (reason == L2CAP_CMD_REJ_MTU_EXCEEDED)
+ param_len = 2;
+ else if (reason == L2CAP_CMD_REJ_INVALID_CID)
+ param_len = 4;
+ else
+ param_len = 0;
+
+ p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_CMD_REJECT_LEN + param_len),
+ L2CAP_CMD_REJECT, rem_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer cmd_rej");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, reason);
+
+ if (param_len >= 2) UINT16_TO_STREAM(p, p1);
+
+ if (param_len >= 4) UINT16_TO_STREAM(p, p2);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_connect_req
+ *
+ * Description Build and send an L2CAP "connection request" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_connect_req(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_REQ_LEN,
+ L2CAP_CMD_CONN_REQ, p_ccb->local_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->p_rcb->real_psm);
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_connect_rsp
+ *
+ * Description Build and send an L2CAP "connection response" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_connect_rsp(tL2C_CCB* p_ccb, uint16_t result,
+ uint16_t status) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ if (result == L2CAP_CONN_PENDING) {
+ /* if we already sent pending response */
+ if (p_ccb->flags & CCB_FLAG_SENT_PENDING)
+ return;
+ else
+ p_ccb->flags |= CCB_FLAG_SENT_PENDING;
+ }
+
+ p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_CONN_RSP_LEN,
+ L2CAP_CMD_CONN_RSP, p_ccb->remote_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_rsp");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, result);
+ UINT16_TO_STREAM(p, status);
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_reject_connection
+ *
+ * Description Build and send an L2CAP "connection response neg" message
+ * to the peer. This function is called when there is no peer
+ * CCB (non-existant PSM or no resources).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_reject_connection(tL2C_LCB* p_lcb, uint16_t remote_cid,
+ uint8_t rem_id, uint16_t result) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ p_buf =
+ l2cu_build_header(p_lcb, L2CAP_CONN_RSP_LEN, L2CAP_CMD_CONN_RSP, rem_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, 0); /* Local CID of 0 */
+ UINT16_TO_STREAM(p, remote_cid);
+ UINT16_TO_STREAM(p, result);
+ UINT16_TO_STREAM(p, 0); /* Status of 0 */
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_config_req
+ *
+ * Description Build and send an L2CAP "configuration request" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_config_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ BT_HDR* p_buf;
+ uint16_t cfg_len = 0;
+ uint8_t* p;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ if (p_cfg->mtu_present)
+ cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->flush_to_present)
+ cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->qos_present)
+ cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcr_present)
+ cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcs_present)
+ cfg_len += L2CAP_CFG_FCS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->ext_flow_spec_present)
+ cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+ p_buf = l2cu_build_header(p_ccb->p_lcb,
+ (uint16_t)(L2CAP_CONFIG_REQ_LEN + cfg_len),
+ L2CAP_CMD_CONFIG_REQ, p_ccb->local_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, p_cfg->flags); /* Flags (continuation) */
+
+ /* Now, put the options */
+ if (p_cfg->mtu_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_MTU);
+ UINT8_TO_STREAM(p, L2CAP_CFG_MTU_OPTION_LEN);
+ UINT16_TO_STREAM(p, p_cfg->mtu);
+ }
+ if (p_cfg->flush_to_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+ UINT8_TO_STREAM(p, L2CAP_CFG_FLUSH_OPTION_LEN);
+ UINT16_TO_STREAM(p, p_cfg->flush_to);
+ }
+ if (p_cfg->qos_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_QOS);
+ UINT8_TO_STREAM(p, L2CAP_CFG_QOS_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->qos.qos_flags);
+ UINT8_TO_STREAM(p, p_cfg->qos.service_type);
+ UINT32_TO_STREAM(p, p_cfg->qos.token_rate);
+ UINT32_TO_STREAM(p, p_cfg->qos.token_bucket_size);
+ UINT32_TO_STREAM(p, p_cfg->qos.peak_bandwidth);
+ UINT32_TO_STREAM(p, p_cfg->qos.latency);
+ UINT32_TO_STREAM(p, p_cfg->qos.delay_variation);
+ }
+ if (p_cfg->fcr_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_FCR);
+ UINT8_TO_STREAM(p, L2CAP_CFG_FCR_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->fcr.mode);
+ UINT8_TO_STREAM(p, p_cfg->fcr.tx_win_sz);
+ UINT8_TO_STREAM(p, p_cfg->fcr.max_transmit);
+ UINT16_TO_STREAM(p, p_cfg->fcr.rtrans_tout);
+ UINT16_TO_STREAM(p, p_cfg->fcr.mon_tout);
+ UINT16_TO_STREAM(p, p_cfg->fcr.mps);
+ }
+
+ if (p_cfg->fcs_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_FCS);
+ UINT8_TO_STREAM(p, L2CAP_CFG_FCS_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->fcs);
+ }
+
+ if (p_cfg->ext_flow_spec_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_EXT_FLOW);
+ UINT8_TO_STREAM(p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->ext_flow_spec.id);
+ UINT8_TO_STREAM(p, p_cfg->ext_flow_spec.stype);
+ UINT16_TO_STREAM(p, p_cfg->ext_flow_spec.max_sdu_size);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.sdu_inter_time);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.access_latency);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.flush_timeout);
+ }
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_config_rsp
+ *
+ * Description Build and send an L2CAP "configuration response" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_config_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ BT_HDR* p_buf;
+ uint16_t cfg_len = 0;
+ uint8_t* p;
+
+ /* Create an identifier for this packet */
+ if (p_cfg->mtu_present)
+ cfg_len += L2CAP_CFG_MTU_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->flush_to_present)
+ cfg_len += L2CAP_CFG_FLUSH_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->qos_present)
+ cfg_len += L2CAP_CFG_QOS_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->fcr_present)
+ cfg_len += L2CAP_CFG_FCR_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+ if (p_cfg->ext_flow_spec_present)
+ cfg_len += L2CAP_CFG_EXT_FLOW_OPTION_LEN + L2CAP_CFG_OPTION_OVERHEAD;
+
+ p_buf = l2cu_build_header(p_ccb->p_lcb,
+ (uint16_t)(L2CAP_CONFIG_RSP_LEN + cfg_len),
+ L2CAP_CMD_CONFIG_RSP, p_ccb->remote_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for conn_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p,
+ p_cfg->flags); /* Flags (continuation) Must match request */
+ UINT16_TO_STREAM(p, p_cfg->result);
+
+ /* Now, put the options */
+ if (p_cfg->mtu_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_MTU);
+ UINT8_TO_STREAM(p, L2CAP_CFG_MTU_OPTION_LEN);
+ UINT16_TO_STREAM(p, p_cfg->mtu);
+ }
+ if (p_cfg->flush_to_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_FLUSH_TOUT);
+ UINT8_TO_STREAM(p, L2CAP_CFG_FLUSH_OPTION_LEN);
+ UINT16_TO_STREAM(p, p_cfg->flush_to);
+ }
+ if (p_cfg->qos_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_QOS);
+ UINT8_TO_STREAM(p, L2CAP_CFG_QOS_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->qos.qos_flags);
+ UINT8_TO_STREAM(p, p_cfg->qos.service_type);
+ UINT32_TO_STREAM(p, p_cfg->qos.token_rate);
+ UINT32_TO_STREAM(p, p_cfg->qos.token_bucket_size);
+ UINT32_TO_STREAM(p, p_cfg->qos.peak_bandwidth);
+ UINT32_TO_STREAM(p, p_cfg->qos.latency);
+ UINT32_TO_STREAM(p, p_cfg->qos.delay_variation);
+ }
+ if (p_cfg->fcr_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_FCR);
+ UINT8_TO_STREAM(p, L2CAP_CFG_FCR_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->fcr.mode);
+ UINT8_TO_STREAM(p, p_cfg->fcr.tx_win_sz);
+ UINT8_TO_STREAM(p, p_cfg->fcr.max_transmit);
+ UINT16_TO_STREAM(p, p_ccb->our_cfg.fcr.rtrans_tout);
+ UINT16_TO_STREAM(p, p_ccb->our_cfg.fcr.mon_tout);
+ UINT16_TO_STREAM(p, p_cfg->fcr.mps);
+ }
+
+ if (p_cfg->ext_flow_spec_present) {
+ UINT8_TO_STREAM(p, L2CAP_CFG_TYPE_EXT_FLOW);
+ UINT8_TO_STREAM(p, L2CAP_CFG_EXT_FLOW_OPTION_LEN);
+ UINT8_TO_STREAM(p, p_cfg->ext_flow_spec.id);
+ UINT8_TO_STREAM(p, p_cfg->ext_flow_spec.stype);
+ UINT16_TO_STREAM(p, p_cfg->ext_flow_spec.max_sdu_size);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.sdu_inter_time);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.access_latency);
+ UINT32_TO_STREAM(p, p_cfg->ext_flow_spec.flush_timeout);
+ }
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_config_rej
+ *
+ * Description Build and send an L2CAP "configuration reject" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_config_rej(tL2C_CCB* p_ccb, uint8_t* p_data,
+ uint16_t data_len, uint16_t rej_len) {
+ uint16_t len, cfg_len, buf_space, len1;
+ uint8_t *p, *p_hci_len, *p_data_end;
+ uint8_t cfg_code;
+
+ L2CAP_TRACE_DEBUG("l2cu_send_peer_config_rej: data_len=%d, rej_len=%d",
+ data_len, rej_len);
+
+ len = BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD +
+ L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN;
+ len1 = 0xFFFF - len;
+ if (rej_len > len1) {
+ L2CAP_TRACE_ERROR(
+ "L2CAP - cfg_rej pkt size exceeds buffer design max limit.");
+ return;
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(len + rej_len);
+ p_buf->offset = L2CAP_SEND_CMD_OFFSET;
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET;
+
+/* Put in HCI header - handle + pkt boundary */
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if (HCI_NON_FLUSHABLE_PB_SUPPORTED(BTM_ReadLocalFeatures())) {
+ UINT16_TO_STREAM(p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE
+ << L2CAP_PKT_TYPE_SHIFT)));
+ } else
+#endif
+ {
+ UINT16_TO_STREAM(
+ p, (p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT)));
+ }
+
+ /* Remember the HCI header length position, and save space for it */
+ p_hci_len = p;
+ p += 2;
+
+ /* Put in L2CAP packet header */
+ UINT16_TO_STREAM(p, L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len);
+ UINT16_TO_STREAM(p, L2CAP_SIGNALLING_CID);
+
+ /* Put in L2CAP command header */
+ UINT8_TO_STREAM(p, L2CAP_CMD_CONFIG_RSP);
+ UINT8_TO_STREAM(p, p_ccb->remote_id);
+
+ UINT16_TO_STREAM(p, L2CAP_CONFIG_RSP_LEN + rej_len);
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, 0); /* Flags = 0 (no continuation) */
+ UINT16_TO_STREAM(p, L2CAP_CFG_UNKNOWN_OPTIONS);
+
+ buf_space = rej_len;
+
+ /* Now, put the rejected options */
+ p_data_end = p_data + data_len;
+ while (p_data < p_data_end) {
+ cfg_code = *p_data;
+ cfg_len = *(p_data + 1);
+
+ switch (cfg_code & 0x7F) {
+ /* skip known options */
+ case L2CAP_CFG_TYPE_MTU:
+ case L2CAP_CFG_TYPE_FLUSH_TOUT:
+ case L2CAP_CFG_TYPE_QOS:
+ p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ break;
+
+ /* unknown options; copy into rsp if not hints */
+ default:
+ /* sanity check option length */
+ if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= data_len) {
+ if ((cfg_code & 0x80) == 0) {
+ if (buf_space >= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD)) {
+ memcpy(p, p_data, cfg_len + L2CAP_CFG_OPTION_OVERHEAD);
+ p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ buf_space -= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD);
+ } else {
+ L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer");
+ p_data = p_data_end; /* force loop exit */
+ break;
+ }
+ }
+ p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD;
+ }
+ /* bad length; force loop exit */
+ else {
+ p_data = p_data_end;
+ }
+ break;
+ }
+ }
+
+ len = (uint16_t)(p - p_hci_len - 2);
+ UINT16_TO_STREAM(p_hci_len, len);
+
+ p_buf->len = len + 4;
+
+ L2CAP_TRACE_DEBUG("L2CAP - cfg_rej pkt hci_len=%d, l2cap_len=%d", len,
+ (L2CAP_CMD_OVERHEAD + L2CAP_CONFIG_RSP_LEN + rej_len));
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_disc_req
+ *
+ * Description Build and send an L2CAP "disconnect request" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_disc_req(tL2C_CCB* p_ccb) {
+ BT_HDR *p_buf, *p_buf2;
+ uint8_t* p;
+
+ if ((!p_ccb) || (p_ccb->p_lcb == NULL)) {
+ L2CAP_TRACE_ERROR("%s L2CAP - ccb or lcb invalid", __func__);
+ return;
+ }
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ p_buf = l2cu_build_header(p_ccb->p_lcb, L2CAP_DISC_REQ_LEN,
+ L2CAP_CMD_DISC_REQ, p_ccb->local_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for disc_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+
+ /* Move all queued data packets to the LCB. In FCR mode, assume the higher
+ layer checks that all buffers are sent before disconnecting.
+ */
+ if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
+ while ((p_buf2 = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q)) !=
+ NULL) {
+ l2cu_set_acl_hci_header(p_buf2, p_ccb);
+ l2c_link_check_send_pkts(p_ccb->p_lcb, p_ccb, p_buf2);
+ }
+ }
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_disc_rsp
+ *
+ * Description Build and send an L2CAP "disconnect response" message
+ * to the peer.
+ *
+ * This function is passed the parameters for the disconnect
+ * response instead of the CCB address, as it may be called
+ * to send a disconnect response when there is no CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_disc_rsp(tL2C_LCB* p_lcb, uint8_t remote_id,
+ uint16_t local_cid, uint16_t remote_cid) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP,
+ remote_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for disc_rsp");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, local_cid);
+ UINT16_TO_STREAM(p, remote_cid);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_echo_req
+ *
+ * Description Build and send an L2CAP "echo request" message
+ * to the peer. Note that we do not currently allow
+ * data in the echo request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_echo_req(tL2C_LCB* p_lcb, uint8_t* p_data,
+ uint16_t data_len) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ p_lcb->id++;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_ZERO_ID); /* check for wrap to '0' */
+
+ p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_ECHO_REQ_LEN + data_len),
+ L2CAP_CMD_ECHO_REQ, p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for echo_req");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ if (data_len) {
+ ARRAY_TO_STREAM(p, p_data, data_len);
+ }
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_echo_rsp
+ *
+ * Description Build and send an L2CAP "echo response" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_echo_rsp(tL2C_LCB* p_lcb, uint8_t id, uint8_t* p_data,
+ uint16_t data_len) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+ uint16_t maxlen;
+ /* Filter out duplicate IDs or if available buffers are low (intruder
+ * checking) */
+ if (!id || id == p_lcb->cur_echo_id) {
+ /* Dump this request since it is illegal */
+ L2CAP_TRACE_WARNING("L2CAP ignoring duplicate echo request (%d)", id);
+ return;
+ } else
+ p_lcb->cur_echo_id = id;
+
+ uint16_t acl_data_size =
+ controller_get_interface()->get_acl_data_size_classic();
+ uint16_t acl_packet_size =
+ controller_get_interface()->get_acl_packet_size_classic();
+ /* Don't return data if it does not fit in ACL and L2CAP MTU */
+ maxlen = (L2CAP_CMD_BUF_SIZE > acl_packet_size)
+ ? acl_data_size
+ : (uint16_t)L2CAP_CMD_BUF_SIZE;
+ maxlen -=
+ (uint16_t)(BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD +
+ L2CAP_CMD_OVERHEAD + L2CAP_ECHO_RSP_LEN);
+
+ if (data_len > maxlen) data_len = 0;
+
+ p_buf = l2cu_build_header(p_lcb, (uint16_t)(L2CAP_ECHO_RSP_LEN + data_len),
+ L2CAP_CMD_ECHO_RSP, id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for echo_rsp");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ if (data_len) {
+ ARRAY_TO_STREAM(p, p_data, data_len);
+ }
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_info_req
+ *
+ * Description Build and send an L2CAP "info request" message
+ * to the peer.
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_info_req(tL2C_LCB* p_lcb, uint16_t info_type) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ /* check for wrap and/or BRCM ID */
+ p_lcb->id++;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_ID);
+
+ p_buf = l2cu_build_header(p_lcb, 2, L2CAP_CMD_INFO_REQ, p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for info_req");
+ return;
+ }
+
+ L2CAP_TRACE_EVENT("l2cu_send_peer_info_req: type 0x%04x", info_type);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, info_type);
+
+ p_lcb->w4_info_rsp = true;
+ alarm_set_on_queue(p_lcb->info_resp_timer, L2CAP_WAIT_INFO_RSP_TIMEOUT_MS,
+ l2c_info_resp_timer_timeout, p_lcb,
+ btu_general_alarm_queue);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_info_rsp
+ *
+ * Description Build and send an L2CAP "info response" message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_info_rsp(tL2C_LCB* p_lcb, uint8_t remote_id,
+ uint16_t info_type) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+ uint16_t len = L2CAP_INFO_RSP_LEN;
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
+ (l2cb.test_info_resp &
+ (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_EXT_FLOW_SPEC |
+ L2CAP_EXTFEA_FIXED_CHNLS | L2CAP_EXTFEA_EXT_WINDOW |
+ L2CAP_EXTFEA_UCD_RECEPTION)))
+#else
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
+ (L2CAP_EXTFEA_SUPPORTED_MASK &
+ (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_NO_CRC | L2CAP_EXTFEA_FIXED_CHNLS |
+ L2CAP_EXTFEA_UCD_RECEPTION)) != 0)
+#endif
+ {
+ len += L2CAP_EXTENDED_FEATURES_ARRAY_SIZE;
+ } else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) {
+ len += L2CAP_FIXED_CHNL_ARRAY_SIZE;
+ } else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) {
+ len += L2CAP_CONNLESS_MTU_INFO_SIZE;
+ }
+
+ p_buf = l2cu_build_header(p_lcb, len, L2CAP_CMD_INFO_RSP, remote_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no buffer for info_rsp");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, info_type);
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
+ (l2cb.test_info_resp &
+ (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_UCD_RECEPTION)))
+#else
+ if ((info_type == L2CAP_EXTENDED_FEATURES_INFO_TYPE) &&
+ (L2CAP_EXTFEA_SUPPORTED_MASK &
+ (L2CAP_EXTFEA_ENH_RETRANS | L2CAP_EXTFEA_STREAM_MODE |
+ L2CAP_EXTFEA_UCD_RECEPTION)) != 0)
+#endif
+ {
+ UINT16_TO_STREAM(p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+ if (p_lcb->transport == BT_TRANSPORT_LE) {
+ /* optional data are not added for now */
+ UINT32_TO_STREAM(p, L2CAP_BLE_EXTFEA_MASK);
+ } else {
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+ UINT32_TO_STREAM(p, l2cb.test_info_resp);
+#else
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ UINT32_TO_STREAM(p,
+ L2CAP_EXTFEA_SUPPORTED_MASK | L2CAP_EXTFEA_FIXED_CHNLS);
+#else
+ UINT32_TO_STREAM(p, L2CAP_EXTFEA_SUPPORTED_MASK);
+#endif
+#endif
+ }
+ } else if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) {
+ UINT16_TO_STREAM(p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+ memset(p, 0, L2CAP_FIXED_CHNL_ARRAY_SIZE);
+
+ p[0] = L2CAP_FIXED_CHNL_SIG_BIT;
+
+ if (L2CAP_EXTFEA_SUPPORTED_MASK & L2CAP_EXTFEA_UCD_RECEPTION)
+ p[0] |= L2CAP_FIXED_CHNL_CNCTLESS_BIT;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ {
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ /* Skip fixed channels not used on BR/EDR-ACL link */
+ if ((xx >= L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL) &&
+ (xx <= L2CAP_SMP_CID - L2CAP_FIRST_FIXED_CHNL))
+ continue;
+
+ if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL)
+ p[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] |=
+ 1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8);
+ }
+ }
+#endif
+ } else if (info_type == L2CAP_CONNLESS_MTU_INFO_TYPE) {
+ UINT16_TO_STREAM(p, L2CAP_INFO_RESP_RESULT_SUCCESS);
+ UINT16_TO_STREAM(p, L2CAP_UCD_MTU);
+ } else {
+ UINT16_TO_STREAM(
+ p, L2CAP_INFO_RESP_RESULT_NOT_SUPPORTED); /* 'not supported' */
+ }
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_enqueue_ccb
+ *
+ * Description queue CCB by priority. The first CCB is highest priority and
+ * is served at first. The CCB is queued to an LLCB or an LCB.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2cu_enqueue_ccb(tL2C_CCB* p_ccb) {
+ tL2C_CCB* p_ccb1;
+ tL2C_CCB_Q* p_q = NULL;
+
+ /* Find out which queue the channel is on
+ */
+ if (p_ccb->p_lcb != NULL) p_q = &p_ccb->p_lcb->ccb_queue;
+
+ if ((!p_ccb->in_use) || (p_q == NULL)) {
+ L2CAP_TRACE_ERROR(
+ "l2cu_enqueue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x",
+ p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb);
+ return;
+ }
+
+ L2CAP_TRACE_DEBUG("l2cu_enqueue_ccb CID: 0x%04x priority: %d",
+ p_ccb->local_cid, p_ccb->ccb_priority);
+
+ /* If the queue is empty, we go at the front */
+ if (!p_q->p_first_ccb) {
+ p_q->p_first_ccb = p_q->p_last_ccb = p_ccb;
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+ } else {
+ p_ccb1 = p_q->p_first_ccb;
+
+ while (p_ccb1 != NULL) {
+ /* Insert new ccb at the end of the same priority. Lower number, higher
+ * priority */
+ if (p_ccb->ccb_priority < p_ccb1->ccb_priority) {
+ /* Are we at the head of the queue ? */
+ if (p_ccb1 == p_q->p_first_ccb)
+ p_q->p_first_ccb = p_ccb;
+ else
+ p_ccb1->p_prev_ccb->p_next_ccb = p_ccb;
+
+ p_ccb->p_next_ccb = p_ccb1;
+ p_ccb->p_prev_ccb = p_ccb1->p_prev_ccb;
+ p_ccb1->p_prev_ccb = p_ccb;
+ break;
+ }
+
+ p_ccb1 = p_ccb1->p_next_ccb;
+ }
+
+ /* If we are lower then anyone in the list, we go at the end */
+ if (!p_ccb1) {
+ /* add new ccb at the end of the list */
+ p_q->p_last_ccb->p_next_ccb = p_ccb;
+
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = p_q->p_last_ccb;
+ p_q->p_last_ccb = p_ccb;
+ }
+ }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* Adding CCB into round robin service table of its LCB */
+ if (p_ccb->p_lcb != NULL) {
+ /* if this is the first channel in this priority group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0) {
+ /* Set the first channel to this CCB */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+ /* Set the next serving channel in this group to this CCB */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+ /* Initialize quota of this priority group based on its priority */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota =
+ L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+ }
+ /* increase number of channels in this group */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb++;
+ }
+#endif
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_dequeue_ccb
+ *
+ * Description dequeue CCB from a queue
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2cu_dequeue_ccb(tL2C_CCB* p_ccb) {
+ tL2C_CCB_Q* p_q = NULL;
+
+ L2CAP_TRACE_DEBUG("l2cu_dequeue_ccb CID: 0x%04x", p_ccb->local_cid);
+
+ /* Find out which queue the channel is on
+ */
+ if (p_ccb->p_lcb != NULL) p_q = &p_ccb->p_lcb->ccb_queue;
+
+ if ((!p_ccb->in_use) || (p_q == NULL) || (p_q->p_first_ccb == NULL)) {
+ L2CAP_TRACE_ERROR(
+ "l2cu_dequeue_ccb CID: 0x%04x ERROR in_use: %u p_lcb: 0x%08x p_q: "
+ "0x%08x p_q->p_first_ccb: 0x%08x",
+ p_ccb->local_cid, p_ccb->in_use, p_ccb->p_lcb, p_q,
+ p_q ? p_q->p_first_ccb : 0);
+ return;
+ }
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* Removing CCB from round robin service table of its LCB */
+ if (p_ccb->p_lcb != NULL) {
+ /* decrease number of channels in this priority group */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb--;
+
+ /* if it was the last channel in the priority group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb == 0) {
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+ } else {
+ /* if it is the first channel of this group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb == p_ccb) {
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb =
+ p_ccb->p_next_ccb;
+ }
+ /* if it is the next serving channel of this group */
+ if (p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb == p_ccb) {
+ /* simply, start serving from the first channel */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb =
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb;
+ }
+ }
+ }
+#endif
+
+ if (p_ccb == p_q->p_first_ccb) {
+ /* We are removing the first in a queue */
+ p_q->p_first_ccb = p_ccb->p_next_ccb;
+
+ if (p_q->p_first_ccb)
+ p_q->p_first_ccb->p_prev_ccb = NULL;
+ else
+ p_q->p_last_ccb = NULL;
+ } else if (p_ccb == p_q->p_last_ccb) {
+ /* We are removing the last in a queue */
+ p_q->p_last_ccb = p_ccb->p_prev_ccb;
+ p_q->p_last_ccb->p_next_ccb = NULL;
+ } else {
+ /* In the middle of a chain. */
+ p_ccb->p_prev_ccb->p_next_ccb = p_ccb->p_next_ccb;
+ p_ccb->p_next_ccb->p_prev_ccb = p_ccb->p_prev_ccb;
+ }
+
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_change_pri_ccb
+ *
+ * Description
+ *
+ * Returns -
+ *
+ ******************************************************************************/
+void l2cu_change_pri_ccb(tL2C_CCB* p_ccb, tL2CAP_CHNL_PRIORITY priority) {
+ if (p_ccb->ccb_priority != priority) {
+ /* If CCB is not the only guy on the queue */
+ if ((p_ccb->p_next_ccb != NULL) || (p_ccb->p_prev_ccb != NULL)) {
+ L2CAP_TRACE_DEBUG("Update CCB list in logical link");
+
+ /* Remove CCB from queue and re-queue it at new priority */
+ l2cu_dequeue_ccb(p_ccb);
+
+ p_ccb->ccb_priority = priority;
+ l2cu_enqueue_ccb(p_ccb);
+ }
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ else {
+ /* If CCB is the only guy on the queue, no need to re-enqueue */
+ /* update only round robin service data */
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 0;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = NULL;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = NULL;
+
+ p_ccb->ccb_priority = priority;
+
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_first_ccb = p_ccb;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].p_serve_ccb = p_ccb;
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota =
+ L2CAP_GET_PRIORITY_QUOTA(p_ccb->ccb_priority);
+ p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].num_ccb = 1;
+ }
+#endif
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_allocate_ccb
+ *
+ * Description This function allocates a Channel Control Block and
+ * attaches it to a link control block. The local CID
+ * is also assigned.
+ *
+ * Returns pointer to CCB, or NULL if none
+ *
+ ******************************************************************************/
+tL2C_CCB* l2cu_allocate_ccb(tL2C_LCB* p_lcb, uint16_t cid) {
+ tL2C_CCB* p_ccb;
+ tL2C_CCB* p_prev;
+
+ L2CAP_TRACE_DEBUG("l2cu_allocate_ccb: cid 0x%04x", cid);
+
+ if (!l2cb.p_free_ccb_first) return (NULL);
+
+ /* If a CID was passed in, use that, else take the first free one */
+ if (cid == 0) {
+ p_ccb = l2cb.p_free_ccb_first;
+ l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+ } else {
+ p_prev = NULL;
+
+ p_ccb = &l2cb.ccb_pool[cid - L2CAP_BASE_APPL_CID];
+
+ if (p_ccb == l2cb.p_free_ccb_first)
+ l2cb.p_free_ccb_first = p_ccb->p_next_ccb;
+ else {
+ for (p_prev = l2cb.p_free_ccb_first; p_prev != NULL;
+ p_prev = p_prev->p_next_ccb) {
+ if (p_prev->p_next_ccb == p_ccb) {
+ p_prev->p_next_ccb = p_ccb->p_next_ccb;
+
+ if (p_ccb == l2cb.p_free_ccb_last) l2cb.p_free_ccb_last = p_prev;
+
+ break;
+ }
+ }
+ if (p_prev == NULL) {
+ L2CAP_TRACE_ERROR(
+ "l2cu_allocate_ccb: could not find CCB for CID 0x%04x in the free "
+ "list",
+ cid);
+ return NULL;
+ }
+ }
+ }
+
+ p_ccb->p_next_ccb = p_ccb->p_prev_ccb = NULL;
+
+ p_ccb->in_use = true;
+
+ /* Get a CID for the connection */
+ p_ccb->local_cid = L2CAP_BASE_APPL_CID + (uint16_t)(p_ccb - l2cb.ccb_pool);
+
+ p_ccb->p_lcb = p_lcb;
+ p_ccb->p_rcb = NULL;
+ p_ccb->should_free_rcb = false;
+
+ /* Set priority then insert ccb into LCB queue (if we have an LCB) */
+ p_ccb->ccb_priority = L2CAP_CHNL_PRIORITY_LOW;
+
+ if (p_lcb) l2cu_enqueue_ccb(p_ccb);
+
+ /* clear what peer wants to configure */
+ p_ccb->peer_cfg_bits = 0;
+
+ /* Put in default values for configuration */
+ memset(&p_ccb->our_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ memset(&p_ccb->peer_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ /* Put in default values for local/peer configurations */
+ p_ccb->our_cfg.flush_to = p_ccb->peer_cfg.flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ p_ccb->our_cfg.mtu = p_ccb->peer_cfg.mtu = L2CAP_DEFAULT_MTU;
+ p_ccb->our_cfg.qos.service_type = p_ccb->peer_cfg.qos.service_type =
+ L2CAP_DEFAULT_SERV_TYPE;
+ p_ccb->our_cfg.qos.token_rate = p_ccb->peer_cfg.qos.token_rate =
+ L2CAP_DEFAULT_TOKEN_RATE;
+ p_ccb->our_cfg.qos.token_bucket_size = p_ccb->peer_cfg.qos.token_bucket_size =
+ L2CAP_DEFAULT_BUCKET_SIZE;
+ p_ccb->our_cfg.qos.peak_bandwidth = p_ccb->peer_cfg.qos.peak_bandwidth =
+ L2CAP_DEFAULT_PEAK_BANDWIDTH;
+ p_ccb->our_cfg.qos.latency = p_ccb->peer_cfg.qos.latency =
+ L2CAP_DEFAULT_LATENCY;
+ p_ccb->our_cfg.qos.delay_variation = p_ccb->peer_cfg.qos.delay_variation =
+ L2CAP_DEFAULT_DELAY;
+
+ p_ccb->bypass_fcs = 0;
+ memset(&p_ccb->ertm_info, 0, sizeof(tL2CAP_ERTM_INFO));
+ p_ccb->peer_cfg_already_rejected = false;
+ p_ccb->fcr_cfg_tries = L2CAP_MAX_FCR_CFG_TRIES;
+
+ alarm_free(p_ccb->fcrb.ack_timer);
+ p_ccb->fcrb.ack_timer = alarm_new("l2c_fcrb.ack_timer");
+
+ /* CSP408639 Fix: When L2CAP send amp move channel request or receive
+ * L2CEVT_AMP_MOVE_REQ do following sequence. Send channel move
+ * request -> Stop retrans/monitor timer -> Change channel state to
+ * CST_AMP_MOVING. */
+ alarm_free(p_ccb->fcrb.mon_retrans_timer);
+ p_ccb->fcrb.mon_retrans_timer = alarm_new("l2c_fcrb.mon_retrans_timer");
+
+ p_ccb->ertm_info.preferred_mode =
+ L2CAP_FCR_BASIC_MODE; /* Default mode for channel is basic mode */
+ p_ccb->ertm_info.allowed_modes =
+ L2CAP_FCR_CHAN_OPT_BASIC; /* Default mode for channel is basic mode */
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+ p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+ p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+ p_ccb->max_rx_mtu = L2CAP_MTU_SIZE;
+ p_ccb->tx_mps = L2CAP_FCR_TX_BUF_SIZE - 32;
+
+ p_ccb->xmit_hold_q = fixed_queue_new(SIZE_MAX);
+ p_ccb->fcrb.srej_rcv_hold_q = fixed_queue_new(SIZE_MAX);
+ p_ccb->fcrb.retrans_q = fixed_queue_new(SIZE_MAX);
+ p_ccb->fcrb.waiting_for_ack_q = fixed_queue_new(SIZE_MAX);
+
+ p_ccb->cong_sent = false;
+ p_ccb->buff_quota = 2; /* This gets set after config */
+
+ /* If CCB was reserved Config_Done can already have some value */
+ if (cid == 0)
+ p_ccb->config_done = 0;
+ else {
+ L2CAP_TRACE_DEBUG("l2cu_allocate_ccb: cid 0x%04x config_done:0x%x", cid,
+ p_ccb->config_done);
+ }
+
+ p_ccb->chnl_state = CST_CLOSED;
+ p_ccb->flags = 0;
+ p_ccb->tx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+ p_ccb->rx_data_rate = L2CAP_CHNL_DATA_RATE_LOW;
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ p_ccb->is_flushable = false;
+#endif
+
+ alarm_free(p_ccb->l2c_ccb_timer);
+ p_ccb->l2c_ccb_timer = alarm_new("l2c.l2c_ccb_timer");
+
+ l2c_link_adjust_chnl_allocation();
+
+ return (p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_start_post_bond_timer
+ *
+ * Description This function starts the ACL Link inactivity timer after
+ * dedicated bonding
+ * This timer can be longer than the normal link inactivity
+ * timer for some platforms.
+ *
+ * Returns bool - true if idle timer started or disconnect initiated
+ * false if there's one or more pending CCB's exist
+ *
+ ******************************************************************************/
+bool l2cu_start_post_bond_timer(uint16_t handle) {
+ tL2C_LCB* p_lcb = l2cu_find_lcb_by_handle(handle);
+
+ if (!p_lcb) return (true);
+
+ p_lcb->is_bonding = false;
+
+ /* Only start timer if no control blocks allocated */
+ if (p_lcb->ccb_queue.p_first_ccb != NULL) return (false);
+
+ /* If no channels on the connection, start idle timeout */
+ if ((p_lcb->link_state == LST_CONNECTED) ||
+ (p_lcb->link_state == LST_CONNECTING) ||
+ (p_lcb->link_state == LST_DISCONNECTING)) {
+ period_ms_t timeout_ms = L2CAP_BONDING_TIMEOUT * 1000;
+
+ if (p_lcb->idle_timeout == 0) {
+ btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+ }
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms, l2c_lcb_timer_timeout,
+ p_lcb, btu_general_alarm_queue);
+ return (true);
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_release_ccb
+ *
+ * Description This function releases a Channel Control Block. The timer
+ * is stopped, any attached buffers freed, and the CCB is
+ * removed from the link control block.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_release_ccb(tL2C_CCB* p_ccb) {
+ tL2C_LCB* p_lcb = p_ccb->p_lcb;
+ tL2C_RCB* p_rcb = p_ccb->p_rcb;
+
+ L2CAP_TRACE_DEBUG("l2cu_release_ccb: cid 0x%04x in_use: %u",
+ p_ccb->local_cid, p_ccb->in_use);
+
+ /* If already released, could be race condition */
+ if (!p_ccb->in_use) return;
+
+ if (p_rcb && (p_rcb->psm != p_rcb->real_psm)) {
+ btm_sec_clr_service_by_psm(p_rcb->psm);
+ }
+
+ if (p_ccb->should_free_rcb) {
+ osi_free(p_rcb);
+ p_ccb->p_rcb = NULL;
+ p_ccb->should_free_rcb = false;
+ }
+
+ btm_sec_clr_temp_auth_service(p_lcb->remote_bd_addr);
+
+ /* Free the timer */
+ alarm_free(p_ccb->l2c_ccb_timer);
+ p_ccb->l2c_ccb_timer = NULL;
+
+ fixed_queue_free(p_ccb->xmit_hold_q, osi_free);
+ p_ccb->xmit_hold_q = NULL;
+
+ l2c_fcr_cleanup(p_ccb);
+
+ /* Channel may not be assigned to any LCB if it was just pre-reserved */
+ if ((p_lcb) && ((p_ccb->local_cid >= L2CAP_BASE_APPL_CID)
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ || (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID)
+#endif
+ )) {
+ l2cu_dequeue_ccb(p_ccb);
+
+ /* Delink the CCB from the LCB */
+ p_ccb->p_lcb = NULL;
+ }
+
+ /* Put the CCB back on the free pool */
+ if (!l2cb.p_free_ccb_first) {
+ l2cb.p_free_ccb_first = p_ccb;
+ l2cb.p_free_ccb_last = p_ccb;
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = NULL;
+ } else {
+ p_ccb->p_next_ccb = NULL;
+ p_ccb->p_prev_ccb = l2cb.p_free_ccb_last;
+ l2cb.p_free_ccb_last->p_next_ccb = p_ccb;
+ l2cb.p_free_ccb_last = p_ccb;
+ }
+
+ /* Flag as not in use */
+ p_ccb->in_use = false;
+
+ /* If no channels on the connection, start idle timeout */
+ if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED)) {
+ if (!p_lcb->ccb_queue.p_first_ccb) {
+ // Closing a security channel on LE device should not start connection
+ // timeout
+ if (p_lcb->transport == BT_TRANSPORT_LE &&
+ p_ccb->local_cid == L2CAP_SMP_CID)
+ return;
+
+ l2cu_no_dynamic_ccbs(p_lcb);
+ } else {
+ /* Link is still active, adjust channel quotas. */
+ l2c_link_adjust_chnl_allocation();
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_ccb_by_remote_cid
+ *
+ * Description Look through all active CCBs on a link for a match based
+ * on the remote CID.
+ *
+ * Returns pointer to matched CCB, or NULL if no match
+ *
+ ******************************************************************************/
+tL2C_CCB* l2cu_find_ccb_by_remote_cid(tL2C_LCB* p_lcb, uint16_t remote_cid) {
+ tL2C_CCB* p_ccb;
+
+ /* If LCB is NULL, look through all active links */
+ if (!p_lcb) {
+ return NULL;
+ } else {
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb)
+ if ((p_ccb->in_use) && (p_ccb->remote_cid == remote_cid)) return (p_ccb);
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_allocate_rcb
+ *
+ * Description Look through the Registration Control Blocks for a free
+ * one.
+ *
+ * Returns Pointer to the RCB or NULL if not found
+ *
+ ******************************************************************************/
+tL2C_RCB* l2cu_allocate_rcb(uint16_t psm) {
+ tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if (!p_rcb->in_use) {
+ p_rcb->in_use = true;
+ p_rcb->psm = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+ return (p_rcb);
+ }
+ }
+
+ /* If here, no free RCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_allocate_ble_rcb
+ *
+ * Description Look through the BLE Registration Control Blocks for a free
+ * one.
+ *
+ * Returns Pointer to the BLE RCB or NULL if not found
+ *
+ ******************************************************************************/
+tL2C_RCB* l2cu_allocate_ble_rcb(uint16_t psm) {
+ tL2C_RCB* p_rcb = &l2cb.ble_rcb_pool[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if (!p_rcb->in_use) {
+ p_rcb->in_use = true;
+ p_rcb->psm = psm;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
+#endif
+ return (p_rcb);
+ }
+ }
+
+ /* If here, no free RCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_release_rcb
+ *
+ * Description Mark an RCB as no longet in use
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_release_rcb(tL2C_RCB* p_rcb) {
+ p_rcb->in_use = false;
+ p_rcb->psm = 0;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_disconnect_chnl
+ *
+ * Description Disconnect a channel. Typically, this is due to either
+ * receiving a bad configuration, bad packet or max_retries
+ * expiring.
+ *
+ ******************************************************************************/
+void l2cu_disconnect_chnl(tL2C_CCB* p_ccb) {
+ uint16_t local_cid = p_ccb->local_cid;
+
+ if (local_cid >= L2CAP_BASE_APPL_CID) {
+ tL2CA_DISCONNECT_IND_CB* p_disc_cb =
+ p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
+
+ L2CAP_TRACE_WARNING("L2CAP - disconnect_chnl CID: 0x%04x", local_cid);
+
+ l2cu_send_peer_disc_req(p_ccb);
+
+ l2cu_release_ccb(p_ccb);
+
+ (*p_disc_cb)(local_cid, false);
+ } else {
+ /* failure on the AMP channel, probably need to disconnect ACL */
+ L2CAP_TRACE_ERROR("L2CAP - disconnect_chnl CID: 0x%04x Ignored", local_cid);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_rcb_by_psm
+ *
+ * Description Look through the Registration Control Blocks to see if
+ * anyone registered to handle the PSM in question
+ *
+ * Returns Pointer to the RCB or NULL if not found
+ *
+ ******************************************************************************/
+tL2C_RCB* l2cu_find_rcb_by_psm(uint16_t psm) {
+ tL2C_RCB* p_rcb = &l2cb.rcb_pool[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if ((p_rcb->in_use) && (p_rcb->psm == psm)) return (p_rcb);
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_ble_rcb_by_psm
+ *
+ * Description Look through the BLE Registration Control Blocks to see if
+ * anyone registered to handle the PSM in question
+ *
+ * Returns Pointer to the BLE RCB or NULL if not found
+ *
+ ******************************************************************************/
+tL2C_RCB* l2cu_find_ble_rcb_by_psm(uint16_t psm) {
+ tL2C_RCB* p_rcb = &l2cb.ble_rcb_pool[0];
+ uint16_t xx;
+
+ for (xx = 0; xx < BLE_MAX_L2CAP_CLIENTS; xx++, p_rcb++) {
+ if ((p_rcb->in_use) && (p_rcb->psm == psm)) return (p_rcb);
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_process_peer_cfg_req
+ *
+ * Description This function is called when the peer sends us a "config
+ * request" message. It extracts the configuration of interest
+ * and saves it in the CCB.
+ *
+ * Note: Negotiation of the FCR channel type is handled
+ * internally, all others are passed to the upper layer.
+ *
+ * Returns uint8_t - L2CAP_PEER_CFG_OK if passed to upper layer,
+ * L2CAP_PEER_CFG_UNACCEPTABLE if automatically
+ * responded to because parameters are
+ * unnacceptable from a specification point
+ * of view.
+ * L2CAP_PEER_CFG_DISCONNECT if no compatible channel
+ * modes between the two devices, and shall
+ * be closed.
+ *
+ ******************************************************************************/
+uint8_t l2cu_process_peer_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ bool mtu_ok = true;
+ bool qos_type_ok = true;
+ bool flush_to_ok = true;
+ bool fcr_ok = true;
+ uint8_t fcr_status;
+
+ /* Ignore FCR parameters for basic mode */
+ if (!p_cfg->fcr_present) p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+
+ /* Save the MTU that our peer can receive */
+ if (p_cfg->mtu_present) {
+ /* Make sure MTU is at least the minimum */
+ if (p_cfg->mtu >= L2CAP_MIN_MTU) {
+ /* In basic mode, limit the MTU to our buffer size */
+ if ((p_cfg->fcr_present == false) && (p_cfg->mtu > L2CAP_MTU_SIZE))
+ p_cfg->mtu = L2CAP_MTU_SIZE;
+
+ /* Save the accepted value in case of renegotiation */
+ p_ccb->peer_cfg.mtu = p_cfg->mtu;
+ p_ccb->peer_cfg.mtu_present = true;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_MTU;
+ } else /* Illegal MTU value */
+ {
+ p_cfg->mtu = L2CAP_MIN_MTU;
+ mtu_ok = false;
+ }
+ }
+ /* Reload mtu from a previously accepted config request */
+ else if (p_ccb->peer_cfg.mtu_present) {
+ p_cfg->mtu_present = true;
+ p_cfg->mtu = p_ccb->peer_cfg.mtu;
+ }
+
+ /* Verify that the flush timeout is a valid value (0 is illegal) */
+ if (p_cfg->flush_to_present) {
+ if (!p_cfg->flush_to) {
+ p_cfg->flush_to = 0xFFFF; /* Infinite retransmissions (spec default) */
+ flush_to_ok = false;
+ } else /* Save the accepted value in case of renegotiation */
+ {
+ p_ccb->peer_cfg.flush_to_present = true;
+ p_ccb->peer_cfg.flush_to = p_cfg->flush_to;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_FLUSH_TO;
+ }
+ }
+ /* Reload flush_to from a previously accepted config request */
+ else if (p_ccb->peer_cfg.flush_to_present) {
+ p_cfg->flush_to_present = true;
+ p_cfg->flush_to = p_ccb->peer_cfg.flush_to;
+ }
+
+ /* Save the QOS settings the the peer is using */
+ if (p_cfg->qos_present) {
+ /* Make sure service type is not a reserved value; otherwise let upper
+ layer decide if acceptable
+ */
+ if (p_cfg->qos.service_type <= GUARANTEED) {
+ p_ccb->peer_cfg.qos = p_cfg->qos;
+ p_ccb->peer_cfg.qos_present = true;
+ p_ccb->peer_cfg_bits |= L2CAP_CH_CFG_MASK_QOS;
+ } else /* Illegal service type value */
+ {
+ p_cfg->qos.service_type = BEST_EFFORT;
+ qos_type_ok = false;
+ }
+ }
+ /* Reload QOS from a previously accepted config request */
+ else if (p_ccb->peer_cfg.qos_present) {
+ p_cfg->qos_present = true;
+ p_cfg->qos = p_ccb->peer_cfg.qos;
+ }
+
+ fcr_status = l2c_fcr_process_peer_cfg_req(p_ccb, p_cfg);
+ if (fcr_status == L2CAP_PEER_CFG_DISCONNECT) {
+ /* Notify caller to disconnect the channel (incompatible modes) */
+ p_cfg->result = L2CAP_CFG_FAILED_NO_REASON;
+ p_cfg->mtu_present = p_cfg->qos_present = p_cfg->flush_to_present = 0;
+
+ return (L2CAP_PEER_CFG_DISCONNECT);
+ }
+
+ fcr_ok = (fcr_status == L2CAP_PEER_CFG_OK);
+
+ /* Return any unacceptable parameters */
+ if (mtu_ok && flush_to_ok && qos_type_ok && fcr_ok) {
+ l2cu_adjust_out_mps(p_ccb);
+ return (L2CAP_PEER_CFG_OK);
+ } else {
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+
+ if (mtu_ok) p_cfg->mtu_present = false;
+ if (flush_to_ok) p_cfg->flush_to_present = false;
+ if (qos_type_ok) p_cfg->qos_present = false;
+ if (fcr_ok) p_cfg->fcr_present = false;
+
+ return (L2CAP_PEER_CFG_UNACCEPTABLE);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_process_peer_cfg_rsp
+ *
+ * Description This function is called when the peer sends us a "config
+ * response" message. It extracts the configuration of interest
+ * and saves it in the CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_process_peer_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ /* If we wanted QoS and the peer sends us a positive response with QoS, use
+ * his values */
+ if ((p_cfg->qos_present) && (p_ccb->our_cfg.qos_present))
+ p_ccb->our_cfg.qos = p_cfg->qos;
+
+ if (p_cfg->fcr_present) {
+ /* Save the retransmission and monitor timeout values */
+ if (p_cfg->fcr.mode == L2CAP_FCR_ERTM_MODE) {
+ p_ccb->peer_cfg.fcr.rtrans_tout = p_cfg->fcr.rtrans_tout;
+ p_ccb->peer_cfg.fcr.mon_tout = p_cfg->fcr.mon_tout;
+ }
+
+ /* Calculate the max number of packets for which we can delay sending an ack
+ */
+ if (p_cfg->fcr.tx_win_sz < p_ccb->our_cfg.fcr.tx_win_sz)
+ p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+ else
+ p_ccb->fcrb.max_held_acks = p_ccb->our_cfg.fcr.tx_win_sz / 3;
+
+ L2CAP_TRACE_DEBUG(
+ "l2cu_process_peer_cfg_rsp(): peer tx_win_sz: %d, our tx_win_sz: %d, "
+ "max_held_acks: %d",
+ p_cfg->fcr.tx_win_sz, p_ccb->our_cfg.fcr.tx_win_sz,
+ p_ccb->fcrb.max_held_acks);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_process_our_cfg_req
+ *
+ * Description This function is called when we send a "config request"
+ * message. It extracts the configuration of interest and saves
+ * it in the CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_process_our_cfg_req(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ tL2C_LCB* p_lcb;
+ uint16_t hci_flush_to;
+
+ /* Save the QOS settings we are using for transmit */
+ if (p_cfg->qos_present) {
+ p_ccb->our_cfg.qos_present = true;
+ p_ccb->our_cfg.qos = p_cfg->qos;
+ }
+
+ if (p_cfg->fcr_present) {
+ /* Override FCR options if attempting streaming or basic */
+ if (p_cfg->fcr.mode == L2CAP_FCR_BASIC_MODE)
+ memset(&p_cfg->fcr, 0, sizeof(tL2CAP_FCR_OPTS));
+ else {
+ /* On BR/EDR, timer values are zero in config request */
+ /* On class 2 AMP, timer value in config request shall be non-0 processing
+ * time */
+ /* timer value in config response shall be greater than
+ * received processing time */
+ p_cfg->fcr.mon_tout = p_cfg->fcr.rtrans_tout = 0;
+
+ if (p_cfg->fcr.mode == L2CAP_FCR_STREAM_MODE)
+ p_cfg->fcr.max_transmit = p_cfg->fcr.tx_win_sz = 0;
+ }
+
+ /* Set the threshold to send acks (may be updated in the cfg response) */
+ p_ccb->fcrb.max_held_acks = p_cfg->fcr.tx_win_sz / 3;
+
+ /* Include FCS option only if peer can handle it */
+ if (p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_NO_CRC) {
+ /* FCS check can be bypassed if peer also desires to bypass */
+ if (p_cfg->fcs_present && p_cfg->fcs == L2CAP_CFG_FCS_BYPASS)
+ p_ccb->bypass_fcs |= L2CAP_CFG_FCS_OUR;
+ } else
+ p_cfg->fcs_present = false;
+ } else {
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+
+ p_ccb->our_cfg.fcr.mode = p_cfg->fcr.mode;
+ p_ccb->our_cfg.fcr_present = p_cfg->fcr_present;
+
+ /* Check the flush timeout. If it is lower than the current one used */
+ /* then we need to adjust the flush timeout sent to the controller */
+ if (p_cfg->flush_to_present) {
+ if ((p_cfg->flush_to == 0) ||
+ (p_cfg->flush_to == L2CAP_NO_AUTOMATIC_FLUSH)) {
+ /* don't send invalid flush timeout */
+ /* SPEC: The sender of the Request shall specify its flush timeout value
+ */
+ /* if it differs from the default value of 0xFFFF */
+ p_cfg->flush_to_present = false;
+ } else {
+ p_ccb->our_cfg.flush_to = p_cfg->flush_to;
+ p_lcb = p_ccb->p_lcb;
+
+ if (p_cfg->flush_to < p_lcb->link_flush_tout) {
+ p_lcb->link_flush_tout = p_cfg->flush_to;
+
+ /* If the timeout is within range of HCI, set the flush timeout */
+ if (p_cfg->flush_to <= ((HCI_MAX_AUTO_FLUSH_TOUT * 5) / 8)) {
+ /* Convert flush timeout to 0.625 ms units, with round */
+ hci_flush_to = ((p_cfg->flush_to * 8) + 3) / 5;
+ btsnd_hcic_write_auto_flush_tout(p_lcb->handle, hci_flush_to);
+ }
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_process_our_cfg_rsp
+ *
+ * Description This function is called when we send the peer a "config
+ * response" message. It extracts the configuration of interest
+ * and saves it in the CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_process_our_cfg_rsp(tL2C_CCB* p_ccb, tL2CAP_CFG_INFO* p_cfg) {
+ /* If peer wants QoS, we are allowed to change the values in a positive
+ * response */
+ if ((p_cfg->qos_present) && (p_ccb->peer_cfg.qos_present))
+ p_ccb->peer_cfg.qos = p_cfg->qos;
+ else
+ p_cfg->qos_present = false;
+
+ l2c_fcr_adj_our_rsp_options(p_ccb, p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_device_reset
+ *
+ * Description This function is called when reset of the device is
+ * completed. For all active connection simulate HCI_DISC
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_device_reset(void) {
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->handle != HCI_INVALID_HANDLE)) {
+ l2c_link_hci_disc_comp(p_lcb->handle, (uint8_t)-1);
+ }
+ }
+ l2cb.is_ble_connecting = false;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_create_conn
+ *
+ * Description This function initiates an acl connection via HCI
+ *
+ * Returns true if successful, false if get buffer fails.
+ *
+ ******************************************************************************/
+bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport) {
+ uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
+ return l2cu_create_conn(p_lcb, transport, phy);
+}
+
+bool l2cu_create_conn(tL2C_LCB* p_lcb, tBT_TRANSPORT transport,
+ uint8_t initiating_phys) {
+ int xx;
+ tL2C_LCB* p_lcb_cur = &l2cb.lcb_pool[0];
+#if (BTM_SCO_INCLUDED == TRUE)
+ bool is_sco_active;
+#endif
+
+ tBT_DEVICE_TYPE dev_type;
+ tBLE_ADDR_TYPE addr_type;
+
+ BTM_ReadDevInfo(p_lcb->remote_bd_addr, &dev_type, &addr_type);
+
+ if (transport == BT_TRANSPORT_LE) {
+ if (!controller_get_interface()->supports_ble()) return false;
+
+ p_lcb->ble_addr_type = addr_type;
+ p_lcb->transport = BT_TRANSPORT_LE;
+ p_lcb->initiating_phys = initiating_phys;
+
+ return (l2cble_create_conn(p_lcb));
+ }
+
+ /* If there is a connection where we perform as a slave, try to switch roles
+ for this connection */
+ for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
+ xx++, p_lcb_cur++) {
+ if (p_lcb_cur == p_lcb) continue;
+
+ if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE)) {
+#if (BTM_SCO_INCLUDED == TRUE)
+ /* The LMP_switch_req shall be sent only if the ACL logical transport
+ is in active mode, when encryption is disabled, and all synchronous
+ logical transports on the same physical link are disabled." */
+
+ /* Check if there is any SCO Active on this BD Address */
+ is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr);
+
+ L2CAP_TRACE_API(
+ "l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s",
+ (is_sco_active == true) ? "true" : "false");
+
+ if (is_sco_active == true)
+ continue; /* No Master Slave switch not allowed when SCO Active */
+#endif
+ /*4_1_TODO check if btm_cb.devcb.local_features to be used instead */
+ if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures())) {
+ /* mark this lcb waiting for switch to be completed and
+ start switch on the other one */
+ p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH;
+ p_lcb->link_role = HCI_ROLE_MASTER;
+
+ if (BTM_SwitchRole(p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) ==
+ BTM_CMD_STARTED) {
+ alarm_set_on_queue(
+ p_lcb->l2c_lcb_timer, L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+ return (true);
+ }
+ }
+ }
+ }
+
+ p_lcb->link_state = LST_CONNECTING;
+
+ return (l2cu_create_conn_after_switch(p_lcb));
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_get_num_hi_priority
+ *
+ * Description Gets the number of high priority channels.
+ *
+ * Returns
+ *
+ ******************************************************************************/
+uint8_t l2cu_get_num_hi_priority(void) {
+ uint8_t no_hi = 0;
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) {
+ no_hi++;
+ }
+ }
+ return no_hi;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_create_conn_after_switch
+ *
+ * Description This function initiates an acl connection via HCI
+ * If switch required to create connection it is already done.
+ *
+ * Returns true if successful, false if get buffer fails.
+ *
+ ******************************************************************************/
+
+bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb) {
+ uint8_t allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+ tBTM_INQ_INFO* p_inq_info;
+ uint8_t page_scan_rep_mode;
+ uint8_t page_scan_mode;
+ uint16_t clock_offset;
+ uint8_t* p_features;
+ uint16_t num_acl = BTM_GetNumAclLinks();
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_lcb->remote_bd_addr);
+ uint8_t no_hi_prio_chs = l2cu_get_num_hi_priority();
+
+ p_features = BTM_ReadLocalFeatures();
+
+ L2CAP_TRACE_DEBUG(
+ "l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d",
+ l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding);
+ /* FW team says that we can participant in 4 piconets
+ * typically 3 piconet + 1 for scanning.
+ * We can enhance the code to count the number of piconets later. */
+ if (((!l2cb.disallow_switch && (num_acl < 3)) ||
+ (p_lcb->is_bonding && (no_hi_prio_chs == 0))) &&
+ HCI_SWITCH_SUPPORTED(p_features))
+ allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
+ else
+ allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
+
+ p_lcb->link_state = LST_CONNECTING;
+
+ /* Check with the BT manager if details about remote device are known */
+ p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr);
+ if (p_inq_info != NULL) {
+ page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode;
+ page_scan_mode = p_inq_info->results.page_scan_mode;
+ clock_offset = (uint16_t)(p_inq_info->results.clock_offset);
+ } else {
+ /* No info known. Use default settings */
+ page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1;
+ page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;
+
+ clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0;
+ }
+
+ btsnd_hcic_create_conn(
+ p_lcb->remote_bd_addr, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 |
+ HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 |
+ HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5),
+ page_scan_rep_mode, page_scan_mode, clock_offset, allow_switch);
+
+ btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);
+
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS,
+ l2c_lcb_timer_timeout, p_lcb, btu_general_alarm_queue);
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_lcb_by_state
+ *
+ * Description Look through all active LCBs for a match based on the
+ * LCB state.
+ *
+ * Returns pointer to first matched LCB, or NULL if no match
+ *
+ ******************************************************************************/
+tL2C_LCB* l2cu_find_lcb_by_state(tL2C_LINK_STATE state) {
+ uint16_t i;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->link_state == state)) {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_lcb_disconnecting
+ *
+ * Description On each active lcb, check if the lcb is in disconnecting
+ * state, or if there are no ccb's on the lcb (implying
+ idle timeout is running), or if last ccb on the link
+ is in disconnecting state.
+ *
+ * Returns true if any of above conditions met, false otherwise
+ *
+ ******************************************************************************/
+bool l2cu_lcb_disconnecting(void) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ uint16_t i;
+ bool status = false;
+
+ p_lcb = &l2cb.lcb_pool[0];
+
+ for (i = 0; i < MAX_L2CAP_LINKS; i++, p_lcb++) {
+ if (p_lcb->in_use) {
+ /* no ccbs on lcb, or lcb is in disconnecting state */
+ if ((!p_lcb->ccb_queue.p_first_ccb) ||
+ (p_lcb->link_state == LST_DISCONNECTING)) {
+ status = true;
+ break;
+ }
+ /* only one ccb left on lcb */
+ else if (p_lcb->ccb_queue.p_first_ccb == p_lcb->ccb_queue.p_last_ccb) {
+ p_ccb = p_lcb->ccb_queue.p_first_ccb;
+
+ if ((p_ccb->in_use) &&
+ ((p_ccb->chnl_state == CST_W4_L2CAP_DISCONNECT_RSP) ||
+ (p_ccb->chnl_state == CST_W4_L2CA_DISCONNECT_RSP))) {
+ status = true;
+ break;
+ }
+ }
+ }
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_set_acl_priority
+ *
+ * Description Sets the transmission priority for a channel.
+ * (For initial implementation only two values are valid.
+ * L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+
+bool l2cu_set_acl_priority(BD_ADDR bd_addr, uint8_t priority,
+ bool reset_after_rs) {
+ tL2C_LCB* p_lcb;
+ uint8_t* pp;
+ uint8_t command[HCI_BRCM_ACL_PRIORITY_PARAM_SIZE];
+ uint8_t vs_param;
+
+ APPL_TRACE_EVENT("SET ACL PRIORITY %d", priority);
+
+ /* Find the link control block for the acl channel */
+ p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_BR_EDR);
+ if (p_lcb == NULL) {
+ L2CAP_TRACE_WARNING("L2CAP - no LCB for L2CA_SetAclPriority");
+ return (false);
+ }
+
+ if (BTM_IS_BRCM_CONTROLLER()) {
+ /* Called from above L2CAP through API; send VSC if changed */
+ if ((!reset_after_rs && (priority != p_lcb->acl_priority)) ||
+ /* Called because of a master/slave role switch; if high resend VSC */
+ (reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) {
+ pp = command;
+
+ vs_param = (priority == L2CAP_PRIORITY_HIGH) ? HCI_BRCM_ACL_PRIORITY_HIGH
+ : HCI_BRCM_ACL_PRIORITY_LOW;
+
+ UINT16_TO_STREAM(pp, p_lcb->handle);
+ UINT8_TO_STREAM(pp, vs_param);
+
+ BTM_VendorSpecificCommand(HCI_BRCM_SET_ACL_PRIORITY,
+ HCI_BRCM_ACL_PRIORITY_PARAM_SIZE, command,
+ NULL);
+
+ /* Adjust lmp buffer allocation for this channel if priority changed */
+ if (p_lcb->acl_priority != priority) {
+ p_lcb->acl_priority = priority;
+ l2c_link_adjust_allocation();
+ }
+ }
+ }
+
+ /** M: for A2DP not smooth, adjust buffer allocation when acl priority changed @{ */
+ if (BTM_IS_MTK_CONTROLLER()) {
+ /* Called from above L2CAP through API; send VSC if changed */
+ if ((!reset_after_rs && (priority != p_lcb->acl_priority)) ||
+ /* Called because of a master/slave role switch; if high resend VSC */
+ ( reset_after_rs && p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)) {
+ /* Adjust lmp buffer allocation for this channel if priority changed */
+ if (p_lcb->acl_priority != priority){
+ p_lcb->acl_priority = priority;
+ l2c_link_adjust_allocation();
+ }
+ }
+ }
+ /** @} */
+
+ return (true);
+}
+
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+/******************************************************************************
+ *
+ * Function l2cu_set_non_flushable_pbf
+ *
+ * Description set L2CAP_PKT_START_NON_FLUSHABLE if controller supoorts
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_set_non_flushable_pbf(bool is_supported) {
+ if (is_supported)
+ l2cb.non_flushable_pbf =
+ (L2CAP_PKT_START_NON_FLUSHABLE << L2CAP_PKT_TYPE_SHIFT);
+ else
+ l2cb.non_flushable_pbf = (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT);
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function l2cu_resubmit_pending_sec_req
+ *
+ * Description This function is called when required security procedures
+ * are completed and any pending requests can be re-submitted.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_resubmit_pending_sec_req(BD_ADDR p_bda) {
+ tL2C_LCB* p_lcb;
+ tL2C_CCB* p_ccb;
+ tL2C_CCB* p_next_ccb;
+ int xx;
+
+ L2CAP_TRACE_DEBUG("l2cu_resubmit_pending_sec_req p_bda: 0x%08x", p_bda);
+
+ /* If we are called with a BDA, only resubmit for that BDA */
+ if (p_bda) {
+ p_lcb = l2cu_find_lcb_by_bd_addr(p_bda, BT_TRANSPORT_BR_EDR);
+
+ /* If we don't have one, this is an error */
+ if (p_lcb) {
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) {
+ p_next_ccb = p_ccb->p_next_ccb;
+ l2c_csm_execute(p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+ }
+ } else {
+ L2CAP_TRACE_WARNING("l2cu_resubmit_pending_sec_req - unknown BD_ADDR");
+ }
+ } else {
+ /* No BDA pasesed in, so check all links */
+ for (xx = 0, p_lcb = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
+ xx++, p_lcb++) {
+ if (p_lcb->in_use) {
+ /* For all channels, send the event through their FSMs */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_next_ccb) {
+ p_next_ccb = p_ccb->p_next_ccb;
+ l2c_csm_execute(p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL);
+ }
+ }
+ }
+ }
+}
+
+#if (L2CAP_CONFORMANCE_TESTING == TRUE)
+/*******************************************************************************
+ *
+ * Function l2cu_set_info_rsp_mask
+ *
+ * Description This function allows the script wrapper to change the
+ * info resp mask for conformance testing.
+ *
+ * Returns pointer to CCB, or NULL if none
+ *
+ ******************************************************************************/
+void l2cu_set_info_rsp_mask(uint32_t mask) { l2cb.test_info_resp = mask; }
+#endif /* L2CAP_CONFORMANCE_TESTING */
+
+/*******************************************************************************
+ *
+ * Function l2cu_adjust_out_mps
+ *
+ * Description Sets our MPS based on current controller capabilities
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_adjust_out_mps(tL2C_CCB* p_ccb) {
+ uint16_t packet_size;
+
+ /* on the tx side MTU is selected based on packet size of the controller */
+ packet_size = btm_get_max_packet_size(p_ccb->p_lcb->remote_bd_addr);
+
+ if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD +
+ L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)) {
+ /* something is very wrong */
+ L2CAP_TRACE_ERROR(
+ "l2cu_adjust_out_mps bad packet size: %u will use MPS: %u",
+ packet_size, p_ccb->peer_cfg.fcr.mps);
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+ } else {
+ packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD +
+ L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN);
+
+ /* We try to negotiate MTU that each packet can be split into whole
+ number of max packets. For example if link is 1.2 max packet size is 339
+ bytes.
+ At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4
+ overhead.
+ 1695, that will be 5 Dh5 packets. Now maximum L2CAP packet is
+ 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.
+
+ For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5
+ packet
+ 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. */
+ if (p_ccb->peer_cfg.fcr.mps >= packet_size)
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps / packet_size * packet_size;
+ else
+ p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
+
+ L2CAP_TRACE_DEBUG(
+ "l2cu_adjust_out_mps use %d Based on peer_cfg.fcr.mps: %u "
+ "packet_size: %u",
+ p_ccb->tx_mps, p_ccb->peer_cfg.fcr.mps, packet_size);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_initialize_fixed_ccb
+ *
+ * Description Initialize a fixed channel's CCB
+ *
+ * Returns true or false
+ *
+ ******************************************************************************/
+bool l2cu_initialize_fixed_ccb(tL2C_LCB* p_lcb, uint16_t fixed_cid,
+ tL2CAP_FCR_OPTS* p_fcr) {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ tL2C_CCB* p_ccb;
+
+ /* If we already have a CCB, then simply return */
+ p_ccb = p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL];
+ if ((p_ccb != NULL) && p_ccb->in_use) {
+ /*
+ * NOTE: The "in_use" check is needed to ignore leftover entries
+ * that have been already released by l2cu_release_ccb().
+ */
+ return (true);
+ }
+
+ p_ccb = l2cu_allocate_ccb(NULL, 0);
+ if (p_ccb == NULL) return (false);
+
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+
+ /* Set CID for the connection */
+ p_ccb->local_cid = fixed_cid;
+ p_ccb->remote_cid = fixed_cid;
+
+ p_ccb->is_flushable = false;
+
+ if (p_fcr) {
+ /* Set the FCR parameters. For now, we will use default pools */
+ p_ccb->our_cfg.fcr = p_ccb->peer_cfg.fcr = *p_fcr;
+
+ p_ccb->ertm_info.fcr_rx_buf_size = L2CAP_FCR_RX_BUF_SIZE;
+ p_ccb->ertm_info.fcr_tx_buf_size = L2CAP_FCR_TX_BUF_SIZE;
+ p_ccb->ertm_info.user_rx_buf_size = L2CAP_USER_RX_BUF_SIZE;
+ p_ccb->ertm_info.user_tx_buf_size = L2CAP_USER_TX_BUF_SIZE;
+
+ p_ccb->fcrb.max_held_acks = p_fcr->tx_win_sz / 3;
+ }
+
+ /* Link ccb to lcb and lcb to ccb */
+ p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL] = p_ccb;
+ p_ccb->p_lcb = p_lcb;
+
+ /* There is no configuration, so if the link is up, the channel is up */
+ if (p_lcb->link_state == LST_CONNECTED) p_ccb->chnl_state = CST_OPEN;
+
+ /* Set the default idle timeout value to use */
+ p_ccb->fixed_chnl_idle_tout =
+ l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].default_idle_tout;
+#endif
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_no_dynamic_ccbs
+ *
+ * Description Handles the case when there are no more dynamic CCBs. If
+ * there are any fixed CCBs, start the longest of the fixed CCB
+ * timeouts, otherwise start the default link idle timeout or
+ * disconnect.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_no_dynamic_ccbs(tL2C_LCB* p_lcb) {
+ tBTM_STATUS rc;
+ period_ms_t timeout_ms = p_lcb->idle_timeout * 1000;
+ bool start_timeout = true;
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ int xx;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ if ((p_lcb->p_fixed_ccbs[xx] != NULL) &&
+ (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000 > timeout_ms)) {
+ timeout_ms = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout * 1000;
+ }
+ }
+#endif
+
+ /* If the link is pairing, do not mess with the timeouts */
+ if (p_lcb->is_bonding) return;
+
+ if (timeout_ms == 0) {
+ L2CAP_TRACE_DEBUG(
+ "l2cu_no_dynamic_ccbs() IDLE timer 0, disconnecting link");
+
+ rc = btm_sec_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+ if (rc == BTM_CMD_STARTED) {
+ l2cu_process_fixed_disc_cback(p_lcb);
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+ } else if (rc == BTM_SUCCESS) {
+ l2cu_process_fixed_disc_cback(p_lcb);
+ /* BTM SEC will make sure that link is release (probably after pairing is
+ * done) */
+ p_lcb->link_state = LST_DISCONNECTING;
+ start_timeout = false;
+ } else if (p_lcb->is_bonding) {
+ btsnd_hcic_disconnect(p_lcb->handle, HCI_ERR_PEER_USER);
+ l2cu_process_fixed_disc_cback(p_lcb);
+ p_lcb->link_state = LST_DISCONNECTING;
+ timeout_ms = L2CAP_LINK_DISCONNECT_TIMEOUT_MS;
+ } else {
+ /* probably no buffer to send disconnect */
+ timeout_ms = BT_1SEC_TIMEOUT_MS;
+ }
+ }
+
+ if (start_timeout) {
+ L2CAP_TRACE_DEBUG("%s starting IDLE timeout: %d ms", __func__, timeout_ms);
+ alarm_set_on_queue(p_lcb->l2c_lcb_timer, timeout_ms, l2c_lcb_timer_timeout,
+ p_lcb, btu_general_alarm_queue);
+ } else {
+ alarm_cancel(p_lcb->l2c_lcb_timer);
+ }
+}
+
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+/*******************************************************************************
+ *
+ * Function l2cu_process_fixed_chnl_resp
+ *
+ * Description handle a fixed channel response (or lack thereof)
+ * if the link failed, or a fixed channel response was
+ * not received, the bitfield is all zeros.
+ *
+ ******************************************************************************/
+void l2cu_process_fixed_chnl_resp(tL2C_LCB* p_lcb) {
+ if (p_lcb->transport == BT_TRANSPORT_BR_EDR) {
+ /* ignore all not assigned BR/EDR channels */
+ p_lcb->peer_chnl_mask[0] &=
+ (L2CAP_FIXED_CHNL_SIG_BIT | L2CAP_FIXED_CHNL_CNCTLESS_BIT |
+ L2CAP_FIXED_CHNL_SMP_BR_BIT);
+ } else
+ p_lcb->peer_chnl_mask[0] = l2cb.l2c_ble_fixed_chnls_mask;
+
+ /* Tell all registered fixed channels about the connection */
+ for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ /* skip sending LE fix channel callbacks on BR/EDR links */
+ if (p_lcb->transport == BT_TRANSPORT_BR_EDR &&
+ xx + L2CAP_FIRST_FIXED_CHNL >= L2CAP_ATT_CID &&
+ xx + L2CAP_FIRST_FIXED_CHNL <= L2CAP_SMP_CID)
+ continue;
+ if (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL) {
+ if (p_lcb->peer_chnl_mask[(xx + L2CAP_FIRST_FIXED_CHNL) / 8] &
+ (1 << ((xx + L2CAP_FIRST_FIXED_CHNL) % 8))) {
+ if (p_lcb->p_fixed_ccbs[xx])
+ p_lcb->p_fixed_ccbs[xx]->chnl_state = CST_OPEN;
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(xx + L2CAP_FIRST_FIXED_CHNL,
+ p_lcb->remote_bd_addr, true, 0,
+ p_lcb->transport);
+ } else {
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
+ p_lcb->disc_reason, p_lcb->transport);
+
+ if (p_lcb->p_fixed_ccbs[xx]) {
+ l2cu_release_ccb(p_lcb->p_fixed_ccbs[xx]);
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ }
+ }
+ }
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function l2cu_process_fixed_disc_cback
+ *
+ * Description send l2cap fixed channel disconnection callback to the
+ * application
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_process_fixed_disc_cback(tL2C_LCB* p_lcb) {
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+
+ /* Select peer channels mask to use depending on transport */
+ uint8_t peer_channel_mask = p_lcb->peer_chnl_mask[0];
+
+ // For LE, reset the stored peer channel mask
+ if (p_lcb->transport == BT_TRANSPORT_LE) p_lcb->peer_chnl_mask[0] = 0;
+
+ for (int xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ if (p_lcb->p_fixed_ccbs[xx]) {
+ if (p_lcb->p_fixed_ccbs[xx] != p_lcb->p_pending_ccb) {
+ tL2C_CCB* p_l2c_chnl_ctrl_block;
+ p_l2c_chnl_ctrl_block = p_lcb->p_fixed_ccbs[xx];
+ p_lcb->p_fixed_ccbs[xx] = NULL;
+ l2cu_release_ccb(p_l2c_chnl_ctrl_block);
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
+ p_lcb->disc_reason, p_lcb->transport);
+ }
+ } else if ((peer_channel_mask & (1 << (xx + L2CAP_FIRST_FIXED_CHNL))) &&
+ (l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb != NULL))
+ (*l2cb.fixed_reg[xx].pL2CA_FixedConn_Cb)(
+ xx + L2CAP_FIRST_FIXED_CHNL, p_lcb->remote_bd_addr, false,
+ p_lcb->disc_reason, p_lcb->transport);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_par_req
+ *
+ * Description Build and send a BLE parameter update request message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_par_req(tL2C_LCB* p_lcb, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ /* Create an identifier for this packet */
+ p_lcb->id++;
+ l2cu_adj_id(p_lcb, L2CAP_ADJ_ID);
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_UPD_REQ_LEN,
+ L2CAP_CMD_BLE_UPDATE_REQ, p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_send_peer_ble_par_req - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, min_int);
+ UINT16_TO_STREAM(p, max_int);
+ UINT16_TO_STREAM(p, latency);
+ UINT16_TO_STREAM(p, timeout);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_par_rsp
+ *
+ * Description Build and send a BLE parameter update response message
+ * to the peer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_par_rsp(tL2C_LCB* p_lcb, uint16_t reason,
+ uint8_t rem_id) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_UPD_RSP_LEN,
+ L2CAP_CMD_BLE_UPDATE_RSP, rem_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_send_peer_ble_par_rsp - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, reason);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_credit_based_conn_req
+ *
+ * Description Build and send a BLE packet to establish LE connection
+ * oriented L2CAP channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_req(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+ tL2C_LCB* p_lcb = NULL;
+ uint16_t mtu;
+ uint16_t mps;
+ uint16_t initial_credit;
+
+ if (!p_ccb) return;
+ p_lcb = p_ccb->p_lcb;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ_LEN,
+ L2CAP_CMD_BLE_CREDIT_BASED_CONN_REQ, p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ mtu = p_ccb->local_conn_cfg.mtu;
+ mps = p_ccb->local_conn_cfg.mps;
+ initial_credit = p_ccb->local_conn_cfg.credits;
+
+ L2CAP_TRACE_DEBUG(
+ "l2cu_send_peer_ble_credit_based_conn_req PSM:0x%04x local_cid:%d\
+ mtu:%d mps:%d initial_credit:%d",
+ p_ccb->p_rcb->real_psm, p_ccb->local_cid, mtu, mps, initial_credit);
+
+ UINT16_TO_STREAM(p, p_ccb->p_rcb->real_psm);
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+ UINT16_TO_STREAM(p, mtu);
+ UINT16_TO_STREAM(p, mps);
+ UINT16_TO_STREAM(p, initial_credit);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_reject_ble_connection
+ *
+ * Description Build and send an L2CAP "Credit based connection res"
+ * message to the peer. This function is called for non-success
+ * cases.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_reject_ble_connection(tL2C_LCB* p_lcb, uint8_t rem_id,
+ uint16_t result) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+ L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, rem_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_reject_ble_connection - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, 0); /* Local CID of 0 */
+ UINT16_TO_STREAM(p, 0); /* MTU */
+ UINT16_TO_STREAM(p, 0); /* MPS */
+ UINT16_TO_STREAM(p, 0); /* initial credit */
+ UINT16_TO_STREAM(p, result);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_credit_based_conn_res
+ *
+ * Description Build and send an L2CAP "Credit based connection res"
+ * message to the peer. This function is called in case of
+ * success.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_credit_based_conn_res(tL2C_CCB* p_ccb,
+ uint16_t result) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+
+ L2CAP_TRACE_DEBUG("l2cu_send_peer_ble_credit_based_conn_res");
+ p_buf =
+ l2cu_build_header(p_ccb->p_lcb, L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES_LEN,
+ L2CAP_CMD_BLE_CREDIT_BASED_CONN_RES, p_ccb->remote_id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_res - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->local_cid); /* Local CID */
+ UINT16_TO_STREAM(p, p_ccb->local_conn_cfg.mtu); /* MTU */
+ UINT16_TO_STREAM(p, p_ccb->local_conn_cfg.mps); /* MPS */
+ UINT16_TO_STREAM(p, p_ccb->local_conn_cfg.credits); /* initial credit */
+ UINT16_TO_STREAM(p, result);
+
+ l2c_link_check_send_pkts(p_ccb->p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_flow_control_credit
+ *
+ * Description Build and send a BLE packet to give credits to peer device
+ * for LE connection oriented L2CAP channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_flow_control_credit(tL2C_CCB* p_ccb,
+ uint16_t credit_value) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+ tL2C_LCB* p_lcb = NULL;
+
+ if (!p_ccb) return;
+ p_lcb = p_ccb->p_lcb;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+
+ p_buf = l2cu_build_header(p_lcb, L2CAP_CMD_BLE_FLOW_CTRL_CREDIT_LEN,
+ L2CAP_CMD_BLE_FLOW_CTRL_CREDIT, p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING("l2cu_send_peer_ble_credit_based_conn_req - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+ UINT16_TO_STREAM(p, credit_value);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_send_peer_ble_credit_based_conn_req
+ *
+ * Description Build and send a BLE packet to disconnect LE connection
+ * oriented L2CAP channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void l2cu_send_peer_ble_credit_based_disconn_req(tL2C_CCB* p_ccb) {
+ BT_HDR* p_buf;
+ uint8_t* p;
+ tL2C_LCB* p_lcb = NULL;
+ L2CAP_TRACE_DEBUG("%s", __func__);
+
+ if (!p_ccb) return;
+ p_lcb = p_ccb->p_lcb;
+
+ /* Create an identifier for this packet */
+ p_ccb->p_lcb->id++;
+ l2cu_adj_id(p_ccb->p_lcb, L2CAP_ADJ_ID);
+
+ p_ccb->local_id = p_ccb->p_lcb->id;
+ p_buf = l2cu_build_header(p_lcb, L2CAP_DISC_REQ_LEN, L2CAP_CMD_DISC_REQ,
+ p_lcb->id);
+ if (p_buf == NULL) {
+ L2CAP_TRACE_WARNING(
+ "l2cu_send_peer_ble_credit_based_disconn_req - no buffer");
+ return;
+ }
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_SEND_CMD_OFFSET + HCI_DATA_PREAMBLE_SIZE +
+ L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD;
+
+ UINT16_TO_STREAM(p, p_ccb->remote_cid);
+ UINT16_TO_STREAM(p, p_ccb->local_cid);
+
+ l2c_link_check_send_pkts(p_lcb, NULL, p_buf);
+}
+
+/*******************************************************************************
+ * Functions used by both Full and Light Stack
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_lcb_by_handle
+ *
+ * Description Look through all active LCBs for a match based on the
+ * HCI handle.
+ *
+ * Returns pointer to matched LCB, or NULL if no match
+ *
+ ******************************************************************************/
+tL2C_LCB* l2cu_find_lcb_by_handle(uint16_t handle) {
+ int xx;
+ tL2C_LCB* p_lcb = &l2cb.lcb_pool[0];
+
+ for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++) {
+ if ((p_lcb->in_use) && (p_lcb->handle == handle)) {
+ return (p_lcb);
+ }
+ }
+
+ /* If here, no match found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_find_ccb_by_cid
+ *
+ * Description Look through all active CCBs on a link for a match based
+ * on the local CID. If passed the link pointer is NULL, all
+ * active links are searched.
+ *
+ * Returns pointer to matched CCB, or NULL if no match
+ *
+ ******************************************************************************/
+tL2C_CCB* l2cu_find_ccb_by_cid(tL2C_LCB* p_lcb, uint16_t local_cid) {
+ tL2C_CCB* p_ccb = NULL;
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ uint8_t xx;
+#endif
+
+ if (local_cid >= L2CAP_BASE_APPL_CID) {
+ /* find the associated CCB by "index" */
+ local_cid -= L2CAP_BASE_APPL_CID;
+
+ if (local_cid >= MAX_L2CAP_CHANNELS) return NULL;
+
+ p_ccb = l2cb.ccb_pool + local_cid;
+
+ /* make sure the CCB is in use */
+ if (!p_ccb->in_use) {
+ p_ccb = NULL;
+ }
+ /* make sure it's for the same LCB */
+ else if (p_lcb && p_lcb != p_ccb->p_lcb) {
+ p_ccb = NULL;
+ }
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else {
+ /* searching fixed channel */
+ p_ccb = l2cb.ccb_pool;
+ for (xx = 0; xx < MAX_L2CAP_CHANNELS; xx++) {
+ if ((p_ccb->local_cid == local_cid) && (p_ccb->in_use) &&
+ (p_lcb == p_ccb->p_lcb))
+ break;
+ else
+ p_ccb++;
+ }
+ if (xx >= MAX_L2CAP_CHANNELS) return NULL;
+ }
+#endif
+
+ return (p_ccb);
+}
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+
+/******************************************************************************
+ *
+ * Function l2cu_get_next_channel_in_rr
+ *
+ * Description get the next channel to send on a link. It also adjusts the
+ * CCB queue to do a basic priority and round-robin scheduling.
+ *
+ * Returns pointer to CCB or NULL
+ *
+ ******************************************************************************/
+static tL2C_CCB* l2cu_get_next_channel_in_rr(tL2C_LCB* p_lcb) {
+ tL2C_CCB* p_serve_ccb = NULL;
+ tL2C_CCB* p_ccb;
+
+ int i, j;
+
+ /* scan all of priority until finding a channel to serve */
+ for (i = 0; (i < L2CAP_NUM_CHNL_PRIORITY) && (!p_serve_ccb); i++) {
+ /* scan all channel within serving priority group until finding a channel to
+ * serve */
+ for (j = 0; (j < p_lcb->rr_serv[p_lcb->rr_pri].num_ccb) && (!p_serve_ccb);
+ j++) {
+ /* scaning from next serving channel */
+ p_ccb = p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb;
+
+ if (!p_ccb) {
+ L2CAP_TRACE_ERROR("p_serve_ccb is NULL, rr_pri=%d", p_lcb->rr_pri);
+ return NULL;
+ }
+
+ L2CAP_TRACE_DEBUG("RR scan pri=%d, lcid=0x%04x, q_cout=%d",
+ p_ccb->ccb_priority, p_ccb->local_cid,
+ fixed_queue_length(p_ccb->xmit_hold_q));
+
+ /* store the next serving channel */
+ /* this channel is the last channel of its priority group */
+ if ((p_ccb->p_next_ccb == NULL) ||
+ (p_ccb->p_next_ccb->ccb_priority != p_ccb->ccb_priority)) {
+ /* next serving channel is set to the first channel in the group */
+ p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb =
+ p_lcb->rr_serv[p_lcb->rr_pri].p_first_ccb;
+ } else {
+ /* next serving channel is set to the next channel in the group */
+ p_lcb->rr_serv[p_lcb->rr_pri].p_serve_ccb = p_ccb->p_next_ccb;
+ }
+
+ if (p_ccb->chnl_state != CST_OPEN) continue;
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ L2CAP_TRACE_DEBUG("%s : Connection oriented channel", __func__);
+ if (fixed_queue_is_empty(p_ccb->xmit_hold_q)) continue;
+
+ } else {
+ /* eL2CAP option in use */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) continue;
+
+ if (fixed_queue_is_empty(p_ccb->fcrb.retrans_q)) {
+ if (fixed_queue_is_empty(p_ccb->xmit_hold_q)) continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ((p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
+ (l2c_fcr_is_flow_controlled(p_ccb)))
+ continue;
+ }
+ } else {
+ if (fixed_queue_is_empty(p_ccb->xmit_hold_q)) continue;
+ }
+ }
+
+ /* found a channel to serve */
+ p_serve_ccb = p_ccb;
+ /* decrease quota of its priority group */
+ p_lcb->rr_serv[p_lcb->rr_pri].quota--;
+ }
+
+ /* if there is no more quota of the priority group or no channel to have
+ * data to send */
+ if ((p_lcb->rr_serv[p_lcb->rr_pri].quota == 0) || (!p_serve_ccb)) {
+ /* serve next priority group */
+ p_lcb->rr_pri = (p_lcb->rr_pri + 1) % L2CAP_NUM_CHNL_PRIORITY;
+ /* initialize its quota */
+ p_lcb->rr_serv[p_lcb->rr_pri].quota =
+ L2CAP_GET_PRIORITY_QUOTA(p_lcb->rr_pri);
+ }
+ }
+
+ if (p_serve_ccb) {
+ L2CAP_TRACE_DEBUG("RR service pri=%d, quota=%d, lcid=0x%04x",
+ p_serve_ccb->ccb_priority,
+ p_lcb->rr_serv[p_serve_ccb->ccb_priority].quota,
+ p_serve_ccb->local_cid);
+ }
+
+ return p_serve_ccb;
+}
+
+#else /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+/******************************************************************************
+ *
+ * Function l2cu_get_next_channel
+ *
+ * Description get the next channel to send on a link bassed on priority
+ * scheduling.
+ *
+ * Returns pointer to CCB or NULL
+ *
+ ******************************************************************************/
+static tL2C_CCB* l2cu_get_next_channel(tL2C_LCB* p_lcb) {
+ tL2C_CCB* p_ccb;
+
+ /* Get the first CCB with data to send.
+ */
+ for (p_ccb = p_lcb->ccb_queue.p_first_ccb; p_ccb; p_ccb = p_ccb->p_next_ccb) {
+ if (p_ccb->chnl_state != CST_OPEN) continue;
+
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) continue;
+
+ if (!fixed_queue_is_empty(p_ccb->fcrb.retrans_q)) return p_ccb;
+
+ if (fixed_queue_is_empty(p_ccb->xmit_hold_q)) continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ((p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
+ (l2c_fcr_is_flow_controlled(p_ccb)))
+ continue;
+
+ /* If here, we found someone */
+ return p_ccb;
+ }
+
+ return NULL;
+}
+#endif /* (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE) */
+
+void l2cu_tx_complete(tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
+ if (p_cbi && p_cbi->cb != NULL) p_cbi->cb(p_cbi->local_cid, p_cbi->num_sdu);
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_get_next_buffer_to_send
+ *
+ * Description get the next buffer to send on a link. It also adjusts the
+ * CCB queue to do a basic priority and round-robin scheduling.
+ *
+ * Returns pointer to buffer or NULL
+ *
+ ******************************************************************************/
+BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb,
+ tL2C_TX_COMPLETE_CB_INFO* p_cbi) {
+ tL2C_CCB* p_ccb;
+ BT_HDR* p_buf;
+
+/* Highest priority are fixed channels */
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ int xx;
+
+ p_cbi->cb = NULL;
+
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ p_ccb = p_lcb->p_fixed_ccbs[xx];
+ if (p_ccb == NULL) continue;
+
+ /* eL2CAP option in use */
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ if (p_ccb->fcrb.wait_ack || p_ccb->fcrb.remote_busy) continue;
+
+ /* No more checks needed if sending from the reatransmit queue */
+ if (fixed_queue_is_empty(p_ccb->fcrb.retrans_q)) {
+ if (fixed_queue_is_empty(p_ccb->xmit_hold_q)) continue;
+
+ /* If in eRTM mode, check for window closure */
+ if ((p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) &&
+ (l2c_fcr_is_flow_controlled(p_ccb)))
+ continue;
+ }
+
+ p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0);
+ if (p_buf != NULL) {
+ l2cu_check_channel_congestion(p_ccb);
+ l2cu_set_acl_hci_header(p_buf, p_ccb);
+ return (p_buf);
+ }
+ } else {
+ if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+ if (NULL == p_buf) {
+ L2CAP_TRACE_ERROR("%s: No data to be sent", __func__);
+ return (NULL);
+ }
+
+ /* Prepare callback info for TX completion */
+ p_cbi->cb = l2cb.fixed_reg[xx].pL2CA_FixedTxComplete_Cb;
+ p_cbi->local_cid = p_ccb->local_cid;
+ p_cbi->num_sdu = 1;
+
+ l2cu_check_channel_congestion(p_ccb);
+ l2cu_set_acl_hci_header(p_buf, p_ccb);
+ return (p_buf);
+ }
+ }
+ }
+#endif
+
+#if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
+ /* get next serving channel in round-robin */
+ p_ccb = l2cu_get_next_channel_in_rr(p_lcb);
+#else
+ p_ccb = l2cu_get_next_channel(p_lcb);
+#endif
+
+ /* Return if no buffer */
+ if (p_ccb == NULL) return (NULL);
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ /* Check credits */
+ if (p_ccb->peer_conn_cfg.credits == 0) {
+ L2CAP_TRACE_DEBUG("%s No credits to send packets", __func__);
+ return NULL;
+ }
+ p_buf = l2c_lcc_get_next_xmit_sdu_seg(p_ccb, 0);
+ if (p_buf == NULL) return (NULL);
+
+ p_ccb->peer_conn_cfg.credits--;
+ } else {
+ if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ p_buf = l2c_fcr_get_next_xmit_sdu_seg(p_ccb, 0);
+ if (p_buf == NULL) return (NULL);
+ } else {
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->xmit_hold_q);
+ if (NULL == p_buf) {
+ L2CAP_TRACE_ERROR("l2cu_get_buffer_to_send() #2: No data to be sent");
+ return (NULL);
+ }
+ }
+ }
+
+ if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_TxComplete_Cb &&
+ (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_ERTM_MODE))
+ (*p_ccb->p_rcb->api.pL2CA_TxComplete_Cb)(p_ccb->local_cid, 1);
+
+ l2cu_check_channel_congestion(p_ccb);
+
+ l2cu_set_acl_hci_header(p_buf, p_ccb);
+
+ return (p_buf);
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_set_acl_hci_header
+ *
+ * Description Set HCI handle for ACL packet
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2cu_set_acl_hci_header(BT_HDR* p_buf, tL2C_CCB* p_ccb) {
+ uint8_t* p;
+
+ /* Set the pointer to the beginning of the data minus 4 bytes for the packet
+ * header */
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset - HCI_DATA_PREAMBLE_SIZE;
+
+ if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
+ UINT16_TO_STREAM(p, p_ccb->p_lcb->handle | (L2CAP_PKT_START_NON_FLUSHABLE
+ << L2CAP_PKT_TYPE_SHIFT));
+
+ uint16_t acl_data_size =
+ controller_get_interface()->get_acl_data_size_ble();
+ /* The HCI transport will segment the buffers. */
+ if (p_buf->len > acl_data_size) {
+ UINT16_TO_STREAM(p, acl_data_size);
+ } else {
+ UINT16_TO_STREAM(p, p_buf->len);
+ }
+ } else {
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if ((((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) ==
+ L2CAP_FLUSHABLE_CH_BASED) &&
+ (p_ccb->is_flushable)) ||
+ ((p_buf->layer_specific & L2CAP_FLUSHABLE_MASK) ==
+ L2CAP_FLUSHABLE_PKT)) {
+ UINT16_TO_STREAM(
+ p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+ } else {
+ UINT16_TO_STREAM(p, p_ccb->p_lcb->handle | l2cb.non_flushable_pbf);
+ }
+#else
+ UINT16_TO_STREAM(
+ p, p_ccb->p_lcb->handle | (L2CAP_PKT_START << L2CAP_PKT_TYPE_SHIFT));
+#endif
+
+ uint16_t acl_data_size =
+ controller_get_interface()->get_acl_data_size_classic();
+ /* The HCI transport will segment the buffers. */
+ if (p_buf->len > acl_data_size) {
+ UINT16_TO_STREAM(p, acl_data_size);
+ } else {
+ UINT16_TO_STREAM(p, p_buf->len);
+ }
+ }
+ p_buf->offset -= HCI_DATA_PREAMBLE_SIZE;
+ p_buf->len += HCI_DATA_PREAMBLE_SIZE;
+}
+
+/******************************************************************************
+ *
+ * Function l2cu_check_channel_congestion
+ *
+ * Description check if any change in congestion status
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void l2cu_check_channel_congestion(tL2C_CCB* p_ccb) {
+ size_t q_count = fixed_queue_length(p_ccb->xmit_hold_q);
+
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ if (p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
+ q_count += fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q);
+ }
+#endif
+ /* If the CCB queue limit is subject to a quota, check for congestion */
+ /* if this channel has outgoing traffic */
+ if (p_ccb->buff_quota != 0) {
+ /* If this channel was congested */
+ if (p_ccb->cong_sent) {
+ /* If the channel is not congested now, tell the app */
+ if (q_count <= (p_ccb->buff_quota / 2)) {
+ p_ccb->cong_sent = false;
+ if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
+ L2CAP_TRACE_DEBUG(
+ "L2CAP - Calling CongestionStatus_Cb (false), CID: 0x%04x "
+ "xmit_hold_q.count: %u buff_quota: %u",
+ p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+ /* Prevent recursive calling */
+ l2cb.is_cong_cback_context = true;
+ (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid,
+ false);
+ l2cb.is_cong_cback_context = false;
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if (p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
+ if (p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
+ L2CAP_TRACE_DEBUG(
+ "L2CAP - Calling UCD CongestionStatus_Cb (false), "
+ "SecPendingQ:%u,XmitQ:%u,Quota:%u",
+ fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
+ fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota);
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(
+ p_ccb->p_lcb->remote_bd_addr, false);
+ }
+ }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ else {
+ uint8_t xx;
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) {
+ if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
+ (*l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(
+ p_ccb->p_lcb->remote_bd_addr, false);
+ break;
+ }
+ }
+ }
+#endif
+ }
+ } else {
+ /* If this channel was not congested but it is congested now, tell the app
+ */
+ if (q_count > p_ccb->buff_quota) {
+ p_ccb->cong_sent = true;
+ if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) {
+ L2CAP_TRACE_DEBUG(
+ "L2CAP - Calling CongestionStatus_Cb "
+ "(true),CID:0x%04x,XmitQ:%u,Quota:%u",
+ p_ccb->local_cid, q_count, p_ccb->buff_quota);
+
+ (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid,
+ true);
+ }
+#if (L2CAP_UCD_INCLUDED == TRUE)
+ else if (p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) {
+ if (p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb) {
+ L2CAP_TRACE_DEBUG(
+ "L2CAP - Calling UCD CongestionStatus_Cb (true), "
+ "SecPendingQ:%u,XmitQ:%u,Quota:%u",
+ fixed_queue_length(p_ccb->p_lcb->ucd_out_sec_pending_q),
+ fixed_queue_length(p_ccb->xmit_hold_q), p_ccb->buff_quota);
+ p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb(
+ p_ccb->p_lcb->remote_bd_addr, true);
+ }
+ }
+#endif
+#if (L2CAP_NUM_FIXED_CHNLS > 0)
+ else {
+ uint8_t xx;
+ for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++) {
+ if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) {
+ if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL)
+ (*l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(
+ p_ccb->p_lcb->remote_bd_addr, true);
+ break;
+ }
+ }
+ }
+#endif
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function l2cu_is_ccb_active
+ *
+ * Description Check if Channel Control Block is in use or released
+ *
+ * Returns bool - true if Channel Control Block is in use
+ * false if p_ccb is null or is released.
+ *
+ ******************************************************************************/
+bool l2cu_is_ccb_active(tL2C_CCB* p_ccb) { return (p_ccb && p_ccb->in_use); }
diff --git a/mtkbt/code/bt/stack/l2cap/l2cap_client.cc b/mtkbt/code/bt/stack/l2cap/l2cap_client.cc
new file mode 100755
index 0000000..5cef245
--- a/dev/null
+++ b/mtkbt/code/bt/stack/l2cap/l2cap_client.cc
@@ -0,0 +1,464 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_l2cap_client"
+
+#include "stack/include/l2cap_client.h"
+
+#include <base/logging.h>
+#include <string.h>
+
+#include "btcore/include/bdaddr.h"
+#include "osi/include/allocator.h"
+#include "osi/include/buffer.h"
+#include "osi/include/list.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/l2c_api.h"
+
+struct l2cap_client_t {
+ l2cap_client_callbacks_t callbacks;
+ void* context;
+
+ uint16_t local_channel_id;
+ uint16_t remote_mtu;
+ bool configured_self;
+ bool configured_peer;
+ bool is_congested;
+ list_t* outbound_fragments;
+};
+
+static void connect_completed_cb(uint16_t local_channel_id,
+ uint16_t error_code);
+static void config_request_cb(uint16_t local_channel_id,
+ tL2CAP_CFG_INFO* requested_parameters);
+static void config_completed_cb(uint16_t local_channel_id,
+ tL2CAP_CFG_INFO* negotiated_parameters);
+static void disconnect_request_cb(uint16_t local_channel_id, bool ack_required);
+static void disconnect_completed_cb(uint16_t local_channel_id,
+ uint16_t error_code);
+static void congestion_cb(uint16_t local_channel_id, bool is_congested);
+static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet);
+static void write_completed_cb(uint16_t local_channel_id,
+ uint16_t packets_completed);
+
+static void fragment_packet(l2cap_client_t* client, buffer_t* packet);
+static void dispatch_fragments(l2cap_client_t* client);
+static l2cap_client_t* find(uint16_t local_channel_id);
+
+// From the Bluetooth Core specification.
+static const uint16_t L2CAP_MTU_DEFAULT = 672;
+static const uint16_t L2CAP_MTU_MINIMUM = 48;
+
+static const tL2CAP_APPL_INFO l2cap_callbacks = {
+ .pL2CA_ConnectCfm_Cb = connect_completed_cb,
+ .pL2CA_ConfigInd_Cb = config_request_cb,
+ .pL2CA_ConfigCfm_Cb = config_completed_cb,
+ .pL2CA_DisconnectInd_Cb = disconnect_request_cb,
+ .pL2CA_DisconnectCfm_Cb = disconnect_completed_cb,
+ .pL2CA_CongestionStatus_Cb = congestion_cb,
+ .pL2CA_DataInd_Cb = read_ready_cb,
+ .pL2CA_TxComplete_Cb = write_completed_cb,
+};
+
+static list_t*
+ l2cap_clients; // A list of l2cap_client_t. Container does not own objects.
+
+buffer_t* l2cap_buffer_new(size_t size) {
+ buffer_t* buf = buffer_new(size + L2CAP_MIN_OFFSET);
+ buffer_t* slice = NULL;
+ if (buf) slice = buffer_new_slice(buf, size);
+ buffer_free(buf);
+ return slice;
+}
+
+l2cap_client_t* l2cap_client_new(const l2cap_client_callbacks_t* callbacks,
+ void* context) {
+ CHECK(callbacks != NULL);
+ CHECK(callbacks->connected != NULL);
+ CHECK(callbacks->disconnected != NULL);
+ CHECK(callbacks->read_ready != NULL);
+ CHECK(callbacks->write_ready != NULL);
+
+ if (!l2cap_clients) {
+ l2cap_clients = list_new(NULL);
+ if (!l2cap_clients) {
+ LOG_ERROR(LOG_TAG, "%s unable to allocate space for L2CAP client list.",
+ __func__);
+ return NULL;
+ }
+ }
+
+ l2cap_client_t* ret = (l2cap_client_t*)osi_calloc(sizeof(l2cap_client_t));
+
+ ret->callbacks = *callbacks;
+ ret->context = context;
+
+ ret->remote_mtu = L2CAP_MTU_DEFAULT;
+ ret->outbound_fragments = list_new(NULL);
+
+ list_append(l2cap_clients, ret);
+
+ return ret;
+}
+
+void l2cap_client_free(l2cap_client_t* client) {
+ if (!client) return;
+
+ list_remove(l2cap_clients, client);
+ l2cap_client_disconnect(client);
+ list_free(client->outbound_fragments);
+ osi_free(client);
+}
+
+bool l2cap_client_connect(l2cap_client_t* client,
+ const bt_bdaddr_t* remote_bdaddr, uint16_t psm) {
+ CHECK(client != NULL);
+ CHECK(remote_bdaddr != NULL);
+ CHECK(psm != 0);
+ CHECK(!bdaddr_is_empty(remote_bdaddr));
+ CHECK(client->local_channel_id == 0);
+ CHECK(!client->configured_self);
+ CHECK(!client->configured_peer);
+ CHECK(!L2C_INVALID_PSM(psm));
+
+ client->local_channel_id = L2CA_ConnectReq(psm, (uint8_t*)remote_bdaddr);
+ if (!client->local_channel_id) {
+ LOG_ERROR(LOG_TAG, "%s unable to create L2CAP connection.", __func__);
+ return false;
+ }
+
+ L2CA_SetConnectionCallbacks(client->local_channel_id, &l2cap_callbacks);
+ return true;
+}
+
+void l2cap_client_disconnect(l2cap_client_t* client) {
+ CHECK(client != NULL);
+
+ if (client->local_channel_id && !L2CA_DisconnectReq(client->local_channel_id))
+ LOG_ERROR(LOG_TAG, "%s unable to send disconnect message for LCID 0x%04x.",
+ __func__, client->local_channel_id);
+
+ client->local_channel_id = 0;
+ client->remote_mtu = L2CAP_MTU_DEFAULT;
+ client->configured_self = false;
+ client->configured_peer = false;
+ client->is_congested = false;
+
+ for (const list_node_t* node = list_begin(client->outbound_fragments);
+ node != list_end(client->outbound_fragments); node = list_next(node))
+ osi_free(list_node(node));
+
+ list_clear(client->outbound_fragments);
+}
+
+bool l2cap_client_is_connected(const l2cap_client_t* client) {
+ CHECK(client != NULL);
+
+ return client->local_channel_id != 0 && client->configured_self &&
+ client->configured_peer;
+}
+
+bool l2cap_client_write(l2cap_client_t* client, buffer_t* packet) {
+ CHECK(client != NULL);
+ CHECK(packet != NULL);
+ CHECK(l2cap_client_is_connected(client));
+
+ if (client->is_congested) return false;
+
+ fragment_packet(client, packet);
+ dispatch_fragments(client);
+ return true;
+}
+
+static void connect_completed_cb(uint16_t local_channel_id,
+ uint16_t error_code) {
+ CHECK(local_channel_id != 0);
+
+ l2cap_client_t* client = find(local_channel_id);
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client for LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ if (error_code != L2CAP_CONN_OK) {
+ LOG_ERROR(LOG_TAG, "%s error connecting L2CAP channel: %d.", __func__,
+ error_code);
+ client->callbacks.disconnected(client, client->context);
+ return;
+ }
+
+ // Use default L2CAP parameters.
+ tL2CAP_CFG_INFO desired_parameters;
+ memset(&desired_parameters, 0, sizeof(desired_parameters));
+ if (!L2CA_ConfigReq(local_channel_id, &desired_parameters)) {
+ LOG_ERROR(LOG_TAG, "%s error sending L2CAP config parameters.", __func__);
+ client->callbacks.disconnected(client, client->context);
+ }
+}
+
+static void config_request_cb(uint16_t local_channel_id,
+ tL2CAP_CFG_INFO* requested_parameters) {
+ tL2CAP_CFG_INFO response;
+ l2cap_client_t* client = find(local_channel_id);
+
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ memset(&response, 0, sizeof(response));
+ response.result = L2CAP_CFG_OK;
+
+ if (requested_parameters->mtu_present) {
+ // Make sure the peer chose an MTU at least as large as the minimum L2CAP
+ // MTU defined by the Bluetooth Core spec.
+ if (requested_parameters->mtu < L2CAP_MTU_MINIMUM) {
+ response.mtu = L2CAP_MTU_MINIMUM;
+ response.mtu_present = true;
+ response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ } else {
+ client->remote_mtu = requested_parameters->mtu;
+ }
+ }
+
+ if (requested_parameters->fcr_present) {
+ if (requested_parameters->fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ response.fcr_present = true;
+ response.fcr = requested_parameters->fcr;
+ response.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ response.result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ }
+ }
+
+ if (!L2CA_ConfigRsp(local_channel_id, &response)) {
+ LOG_ERROR(LOG_TAG, "%s unable to send config response for LCID 0x%04x.",
+ __func__, local_channel_id);
+ l2cap_client_disconnect(client);
+ return;
+ }
+
+ // If we've configured both endpoints, let the listener know we've connected.
+ client->configured_peer = true;
+ if (l2cap_client_is_connected(client))
+ client->callbacks.connected(client, client->context);
+}
+
+static void config_completed_cb(uint16_t local_channel_id,
+ tL2CAP_CFG_INFO* negotiated_parameters) {
+ l2cap_client_t* client = find(local_channel_id);
+
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ switch (negotiated_parameters->result) {
+ // We'll get another configuration response later.
+ case L2CAP_CFG_PENDING:
+ break;
+
+ case L2CAP_CFG_UNACCEPTABLE_PARAMS:
+ // TODO: see if we can renegotiate parameters instead of dropping the
+ // connection.
+ LOG_WARN(
+ LOG_TAG,
+ "%s dropping L2CAP connection due to unacceptable config parameters.",
+ __func__);
+ l2cap_client_disconnect(client);
+ break;
+
+ case L2CAP_CFG_OK:
+ // If we've configured both endpoints, let the listener know we've
+ // connected.
+ client->configured_self = true;
+ if (l2cap_client_is_connected(client))
+ client->callbacks.connected(client, client->context);
+ break;
+
+ // Failure, no further parameter negotiation possible.
+ default:
+ LOG_WARN(LOG_TAG,
+ "%s L2CAP parameter negotiation failed with error code %d.",
+ __func__, negotiated_parameters->result);
+ l2cap_client_disconnect(client);
+ break;
+ }
+}
+
+static void disconnect_request_cb(uint16_t local_channel_id,
+ bool ack_required) {
+ l2cap_client_t* client = find(local_channel_id);
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ if (ack_required) L2CA_DisconnectRsp(local_channel_id);
+
+ // We already sent a disconnect response so this LCID is now invalid.
+ client->local_channel_id = 0;
+ l2cap_client_disconnect(client);
+
+ client->callbacks.disconnected(client, client->context);
+}
+
+static void disconnect_completed_cb(uint16_t local_channel_id,
+ UNUSED_ATTR uint16_t error_code) {
+ CHECK(local_channel_id != 0);
+
+ l2cap_client_t* client = find(local_channel_id);
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client with LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ client->local_channel_id = 0;
+ l2cap_client_disconnect(client);
+
+ client->callbacks.disconnected(client, client->context);
+}
+
+static void congestion_cb(uint16_t local_channel_id, bool is_congested) {
+ CHECK(local_channel_id != 0);
+
+ l2cap_client_t* client = find(local_channel_id);
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ client->is_congested = is_congested;
+
+ if (!is_congested) {
+ // If we just decongested, dispatch whatever we have left over in our queue.
+ // Once that's done, if we're still decongested, notify the listener so it
+ // can start writing again.
+ dispatch_fragments(client);
+ if (!client->is_congested)
+ client->callbacks.write_ready(client, client->context);
+ }
+}
+
+static void read_ready_cb(uint16_t local_channel_id, BT_HDR* packet) {
+ CHECK(local_channel_id != 0);
+
+ l2cap_client_t* client = find(local_channel_id);
+ if (!client) {
+ LOG_ERROR(LOG_TAG, "%s unable to find L2CAP client matching LCID 0x%04x.",
+ __func__, local_channel_id);
+ return;
+ }
+
+ // TODO(sharvil): eliminate copy from BT_HDR.
+ buffer_t* buffer = buffer_new(packet->len);
+ memcpy(buffer_ptr(buffer), packet->data + packet->offset, packet->len);
+ osi_free(packet);
+
+ client->callbacks.read_ready(client, buffer, client->context);
+ buffer_free(buffer);
+}
+
+static void write_completed_cb(UNUSED_ATTR uint16_t local_channel_id,
+ UNUSED_ATTR uint16_t packets_completed) {
+ // Do nothing. We update congestion state based on the congestion callback
+ // and we've already removed items from outbound_fragments list so we don't
+ // really care how many packets were successfully dispatched.
+}
+
+static void fragment_packet(l2cap_client_t* client, buffer_t* packet) {
+ CHECK(client != NULL);
+ CHECK(packet != NULL);
+
+ // TODO(sharvil): eliminate copy into BT_HDR.
+ BT_HDR* bt_packet = static_cast<BT_HDR*>(
+ osi_malloc(buffer_length(packet) + L2CAP_MIN_OFFSET +
+ sizeof(BT_HDR)));
+ bt_packet->offset = L2CAP_MIN_OFFSET;
+ bt_packet->len = buffer_length(packet);
+ memcpy(bt_packet->data + bt_packet->offset, buffer_ptr(packet),
+ buffer_length(packet));
+
+ for (;;) {
+ if (bt_packet->len <= client->remote_mtu) {
+ if (bt_packet->len > 0)
+ list_append(client->outbound_fragments, bt_packet);
+ else
+ osi_free(bt_packet);
+ break;
+ }
+
+ BT_HDR* fragment =
+ static_cast<BT_HDR*>(osi_malloc(client->remote_mtu + L2CAP_MIN_OFFSET +
+ sizeof(BT_HDR)));
+ fragment->offset = L2CAP_MIN_OFFSET;
+ fragment->len = client->remote_mtu;
+ memcpy(fragment->data + fragment->offset,
+ bt_packet->data + bt_packet->offset, client->remote_mtu);
+
+ list_append(client->outbound_fragments, fragment);
+
+ bt_packet->offset += client->remote_mtu;
+ bt_packet->len -= client->remote_mtu;
+ }
+}
+
+static void dispatch_fragments(l2cap_client_t* client) {
+ CHECK(client != NULL);
+ CHECK(!client->is_congested);
+
+ while (!list_is_empty(client->outbound_fragments)) {
+ BT_HDR* packet = (BT_HDR*)list_front(client->outbound_fragments);
+ list_remove(client->outbound_fragments, packet);
+
+ switch (L2CA_DataWrite(client->local_channel_id, packet)) {
+ case L2CAP_DW_CONGESTED:
+ client->is_congested = true;
+ return;
+
+ case L2CAP_DW_FAILED:
+ LOG_ERROR(LOG_TAG,
+ "%s error writing data to L2CAP connection LCID 0x%04x; "
+ "disconnecting.",
+ __func__, client->local_channel_id);
+ l2cap_client_disconnect(client);
+ return;
+
+ case L2CAP_DW_SUCCESS:
+ break;
+ }
+ }
+}
+
+static l2cap_client_t* find(uint16_t local_channel_id) {
+ CHECK(local_channel_id != 0);
+
+ for (const list_node_t* node = list_begin(l2cap_clients);
+ node != list_end(l2cap_clients); node = list_next(node)) {
+ l2cap_client_t* client = (l2cap_client_t*)list_node(node);
+ if (client->local_channel_id == local_channel_id) return client;
+ }
+
+ return NULL;
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_api.cc b/mtkbt/code/bt/stack/mcap/mca_api.cc
new file mode 100755
index 0000000..fea06ca
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_api.cc
@@ -0,0 +1,857 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the API implementation file for the Multi-Channel Adaptation
+ * Protocol (MCAP).
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_target.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+#include "btu.h"
+
+/*******************************************************************************
+ *
+ * Function mca_process_timeout
+ *
+ * Description This function is called by BTU when an MCA timer
+ * expires.
+ *
+ * This function is for use internal to the stack only.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_ccb_timer_timeout(void* data) {
+ tMCA_CCB* p_ccb = (tMCA_CCB*)data;
+
+ mca_ccb_event(p_ccb, MCA_CCB_RSP_TOUT_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_Init
+ *
+ * Description Initialize MCAP main control block.
+ * This function is called at stack start up.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void MCA_Init(void) {
+ memset(&mca_cb, 0, sizeof(tMCA_CB));
+
+#if defined(MCA_INITIAL_TRACE_LEVEL)
+ mca_cb.trace_level = MCA_INITIAL_TRACE_LEVEL;
+#else
+ mca_cb.trace_level = BT_TRACE_LEVEL_NONE;
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_SetTraceLevel
+ *
+ * Description This function sets the debug trace level for MCA.
+ * If 0xff is passed, the current trace level is returned.
+ *
+ * Input Parameters:
+ * level: The level to set the MCA tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new trace level or current trace level if
+ * the input parameter is 0xff.
+ *
+ ******************************************************************************/
+uint8_t MCA_SetTraceLevel(uint8_t level) {
+ if (level != 0xFF) mca_cb.trace_level = level;
+
+ return (mca_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_Register
+ *
+ * Description This function registers an MCAP implementation.
+ * It is assumed that the control channel PSM and data channel
+ * PSM are not used by any other instances of the stack.
+ * If the given p_reg->ctrl_psm is 0, this handle is INT only.
+ *
+ * Returns 0, if failed. Otherwise, the MCA handle.
+ *
+ ******************************************************************************/
+tMCA_HANDLE MCA_Register(tMCA_REG* p_reg, tMCA_CTRL_CBACK* p_cback) {
+ tMCA_RCB* p_rcb;
+ tMCA_HANDLE handle = 0;
+ tL2CAP_APPL_INFO l2c_cacp_appl;
+ tL2CAP_APPL_INFO l2c_dacp_appl;
+
+ CHECK(p_reg != NULL);
+ CHECK(p_cback != NULL);
+
+ MCA_TRACE_API("MCA_Register: ctrl_psm:0x%x, data_psm:0x%x", p_reg->ctrl_psm,
+ p_reg->data_psm);
+
+ p_rcb = mca_rcb_alloc(p_reg);
+ if (p_rcb != NULL) {
+ if (p_reg->ctrl_psm) {
+ if (L2C_INVALID_PSM(p_reg->ctrl_psm) ||
+ L2C_INVALID_PSM(p_reg->data_psm)) {
+ MCA_TRACE_ERROR("INVALID_PSM");
+ return 0;
+ }
+
+ l2c_cacp_appl = *(tL2CAP_APPL_INFO*)&mca_l2c_int_appl;
+ l2c_cacp_appl.pL2CA_ConnectCfm_Cb = NULL;
+ l2c_dacp_appl = *(tL2CAP_APPL_INFO*)&l2c_cacp_appl;
+ l2c_cacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_cconn_ind_cback;
+ l2c_dacp_appl.pL2CA_ConnectInd_Cb = mca_l2c_dconn_ind_cback;
+ if (L2CA_Register(p_reg->ctrl_psm, (tL2CAP_APPL_INFO*)&l2c_cacp_appl) &&
+ L2CA_Register(p_reg->data_psm, (tL2CAP_APPL_INFO*)&l2c_dacp_appl)) {
+ /* set security level */
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_CTRL,
+ p_reg->sec_mask, p_reg->ctrl_psm,
+ BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+
+ /* in theory, we do not need this one for data_psm
+ * If we don't, L2CAP rejects with security block (3),
+ * which is different reject code from what MCAP spec suggests.
+ * we set this one, so mca_l2c_dconn_ind_cback can reject /w no
+ * resources (4) */
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA,
+ p_reg->sec_mask, p_reg->data_psm,
+ BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+ } else {
+ MCA_TRACE_ERROR("Failed to register to L2CAP");
+ return 0;
+ }
+ } else
+ p_rcb->reg.data_psm = 0;
+ handle = mca_rcb_to_handle(p_rcb);
+ p_rcb->p_cback = p_cback;
+ p_rcb->reg.rsp_tout = p_reg->rsp_tout;
+ }
+ return handle;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_Deregister
+ *
+ * Description Deregister an MCAP implementation. Before this function can
+ * be called, all control and data channels must be removed
+ * with MCA_DisconnectReq and MCA_CloseReq.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void MCA_Deregister(tMCA_HANDLE handle) {
+ tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
+
+ MCA_TRACE_API("MCA_Deregister: %d", handle);
+ if (p_rcb && p_rcb->reg.ctrl_psm) {
+ L2CA_Deregister(p_rcb->reg.ctrl_psm);
+ L2CA_Deregister(p_rcb->reg.data_psm);
+ btm_sec_clr_service_by_psm(p_rcb->reg.ctrl_psm);
+ btm_sec_clr_service_by_psm(p_rcb->reg.data_psm);
+ }
+ mca_rcb_dealloc(handle);
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateDep
+ *
+ * Description Create a data endpoint. If the MDEP is created successfully,
+ * the MDEP ID is returned in *p_dep. After a data endpoint is
+ * created, an application can initiate a connection between
+ * this endpoint and an endpoint on a peer device.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_CreateDep(tMCA_HANDLE handle, tMCA_DEP* p_dep, tMCA_CS* p_cs) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ int i;
+ tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CS* p_depcs;
+
+ CHECK(p_dep != NULL);
+ CHECK(p_cs != NULL);
+ CHECK(p_cs->p_data_cback != NULL);
+
+ MCA_TRACE_API("MCA_CreateDep: %d", handle);
+ if (p_rcb) {
+ if (p_cs->max_mdl > MCA_NUM_MDLS) {
+ MCA_TRACE_ERROR("max_mdl: %d is too big", p_cs->max_mdl);
+ result = MCA_BAD_PARAMS;
+ } else {
+ p_depcs = p_rcb->dep;
+ if (p_cs->type == MCA_TDEP_ECHO) {
+ if (p_depcs->p_data_cback) {
+ MCA_TRACE_ERROR("Already has ECHO MDEP");
+ return MCA_NO_RESOURCES;
+ }
+ memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
+ *p_dep = 0;
+ result = MCA_SUCCESS;
+ } else {
+ result = MCA_NO_RESOURCES;
+ /* non-echo MDEP starts from 1 */
+ p_depcs++;
+ for (i = 1; i < MCA_NUM_DEPS; i++, p_depcs++) {
+ if (p_depcs->p_data_cback == NULL) {
+ memcpy(p_depcs, p_cs, sizeof(tMCA_CS));
+ /* internally use type as the mdep id */
+ p_depcs->type = i;
+ *p_dep = i;
+ result = MCA_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_DeleteDep
+ *
+ * Description Delete a data endpoint. This function is called when
+ * the implementation is no longer using a data endpoint.
+ * If this function is called when the endpoint is connected
+ * the connection is closed and the data endpoint
+ * is removed.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_DeleteDep(tMCA_HANDLE handle, tMCA_DEP dep) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
+ tMCA_DCB* p_dcb;
+ int i, max;
+ tMCA_CS* p_depcs;
+
+ MCA_TRACE_API("MCA_DeleteDep: %d dep:%d", handle, dep);
+ if (p_rcb) {
+ if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
+ result = MCA_SUCCESS;
+ p_rcb->dep[dep].p_data_cback = NULL;
+ p_depcs = &(p_rcb->dep[dep]);
+ i = handle - 1;
+ max = MCA_NUM_MDLS * MCA_NUM_LINKS;
+ p_dcb = &mca_cb.dcb[i * max];
+ /* make sure no MDL exists for this MDEP */
+ for (i = 0; i < max; i++, p_dcb++) {
+ if (p_dcb->state && p_dcb->p_cs == p_depcs) {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_ConnectReq
+ *
+ * Description This function initiates an MCAP control channel connection
+ * to the peer device. When the connection is completed, an
+ * MCA_CONNECT_IND_EVT is reported to the application via its
+ * control callback function.
+ * This control channel is identified by the tMCA_CL.
+ * If the connection attempt fails, an MCA_DISCONNECT_IND_EVT
+ * is reported. The security mask parameter overrides the
+ * outgoing security mask set in MCA_Register().
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_ConnectReq(tMCA_HANDLE handle, BD_ADDR bd_addr,
+ uint16_t ctrl_psm, uint16_t sec_mask) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb;
+ tMCA_TC_TBL* p_tbl;
+
+ MCA_TRACE_API("MCA_ConnectReq: %d psm:0x%x", handle, ctrl_psm);
+ p_ccb = mca_ccb_by_bd(handle, bd_addr);
+ if (p_ccb == NULL)
+ p_ccb = mca_ccb_alloc(handle, bd_addr);
+ else {
+ MCA_TRACE_ERROR("control channel already exists");
+ return MCA_BUSY;
+ }
+
+ if (p_ccb) {
+ p_ccb->ctrl_vpsm =
+ L2CA_Register(ctrl_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
+ result = MCA_NO_RESOURCES;
+ if (p_ccb->ctrl_vpsm) {
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_CTRL, sec_mask,
+ p_ccb->ctrl_vpsm, BTM_SEC_PROTO_MCA, MCA_CTRL_TCID);
+ p_ccb->lcid = mca_l2c_open_req(bd_addr, p_ccb->ctrl_vpsm, NULL);
+ if (p_ccb->lcid) {
+ p_tbl = mca_tc_tbl_calloc(p_ccb);
+ if (p_tbl) {
+ p_tbl->state = MCA_TC_ST_CONN;
+ p_ccb->sec_mask = sec_mask;
+ result = MCA_SUCCESS;
+ }
+ }
+ }
+ if (result != MCA_SUCCESS) mca_ccb_dealloc(p_ccb, NULL);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_DisconnectReq
+ *
+ * Description This function disconnect an MCAP control channel
+ * to the peer device.
+ * If associated data channel exists, they are disconnected.
+ * When the MCL is disconnected an MCA_DISCONNECT_IND_EVT is
+ * reported to the application via its control callback
+ * function.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_DisconnectReq(tMCA_CL mcl) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+
+ MCA_TRACE_API("MCA_DisconnectReq: %d ", mcl);
+ if (p_ccb) {
+ result = MCA_SUCCESS;
+ mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateMdl
+ *
+ * Description This function sends a CREATE_MDL request to the peer device.
+ * When the response is received, a MCA_CREATE_CFM_EVT is
+ * reported with the given MDL ID.
+ * If the response is successful, a data channel is open
+ * with the given p_chnl_cfg
+ * If p_chnl_cfg is NULL, the data channel is not initiated
+ * until MCA_DataChnlCfg is called to provide the p_chnl_cfg.
+ * When the data channel is open successfully, a
+ * MCA_OPEN_CFM_EVT is reported. This data channel is
+ * identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_CreateMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+ uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg,
+ const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_API("MCA_CreateMdl: %d dep=%d mdl_id=%d peer_dep_id=%d", mcl, dep,
+ mdl_id, peer_dep_id);
+ if (p_ccb) {
+ if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
+ MCA_TRACE_ERROR("pending req");
+ return MCA_BUSY;
+ }
+
+ if ((peer_dep_id > MCA_MAX_MDEP_ID) || (!MCA_IS_VALID_MDL_ID(mdl_id))) {
+ MCA_TRACE_ERROR("bad peer dep id:%d or bad mdl id: %d ", peer_dep_id,
+ mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+
+ if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
+ MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
+ return MCA_BAD_MDL_ID;
+ }
+
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ result = MCA_NO_RESOURCES;
+ if (p_dcb) {
+ /* save the info required by dcb connection */
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ tMCA_CCB_MSG* p_evt_data =
+ (tMCA_CCB_MSG*)osi_malloc(sizeof(tMCA_CCB_MSG));
+ if (!p_ccb->data_vpsm)
+ p_ccb->data_vpsm =
+ L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
+ if (p_ccb->data_vpsm) {
+ p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_evt_data->mdep_id = peer_dep_id;
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->param = cfg;
+ p_evt_data->op_code = MCA_OP_MDL_CREATE_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ p_evt_data->hdr.layer_specific = false;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT*)p_evt_data);
+ return MCA_SUCCESS;
+ } else {
+ osi_free(p_evt_data);
+ }
+
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_CreateMdlRsp
+ *
+ * Description This function sends a CREATE_MDL response to the peer device
+ * in response to a received MCA_CREATE_IND_EVT.
+ * If the rsp_code is successful, a data channel is open
+ * with the given p_chnl_cfg
+ * When the data channel is open successfully, a
+ * MCA_OPEN_IND_EVT
+ * is reported. This data channel is identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_CreateMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
+ uint8_t cfg, uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG evt_data;
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_API("MCA_CreateMdlRsp: %d dep=%d mdl_id=%d cfg=%d rsp_code=%d", mcl,
+ dep, mdl_id, cfg, rsp_code);
+ CHECK(p_chnl_cfg != NULL);
+ if (p_ccb) {
+ if (p_ccb->cong) {
+ MCA_TRACE_ERROR("congested");
+ return MCA_BUSY;
+ }
+ if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdep_id == dep) &&
+ (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
+ (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_CREATE_REQ)) {
+ result = MCA_SUCCESS;
+ evt_data.dcb_idx = 0;
+ if (rsp_code == MCA_RSP_SUCCESS) {
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ if (p_dcb) {
+ evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ } else {
+ rsp_code = MCA_RSP_MDEP_BUSY;
+ result = MCA_NO_RESOURCES;
+ }
+ }
+
+ if (result == MCA_SUCCESS) {
+ evt_data.mdl_id = mdl_id;
+ evt_data.param = cfg;
+ evt_data.rsp_code = rsp_code;
+ evt_data.op_code = MCA_OP_MDL_CREATE_RSP;
+ mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT*)&evt_data);
+ }
+ } else {
+ MCA_TRACE_ERROR(
+ "The given MCL is not expecting a MCA_CreateMdlRsp with the given "
+ "parameters");
+ result = MCA_BAD_PARAMS;
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_CloseReq
+ *
+ * Description Close a data channel. When the channel is closed, an
+ * MCA_CLOSE_CFM_EVT is sent to the application via the
+ * control callback function for this handle.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_CloseReq(tMCA_DL mdl) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
+
+ MCA_TRACE_API("MCA_CloseReq: %d ", mdl);
+ if (p_dcb) {
+ result = MCA_SUCCESS;
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_ReconnectMdl
+ *
+ * Description This function sends a RECONNECT_MDL request to the peer
+ * device. When the response is received, a
+ * MCA_RECONNECT_CFM_EVT is reported. If p_chnl_cfg is NULL,
+ * the data channel is not initiated until MCA_DataChnlCfg is
+ * called to provide the p_chnl_cfg. If the response is
+ * successful, a data channel is open. When the data channel is
+ * open successfully, a MCA_OPEN_CFM_EVT is reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdl(tMCA_CL mcl, tMCA_DEP dep, uint16_t data_psm,
+ uint16_t mdl_id, const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_API("MCA_ReconnectMdl: %d ", mcl);
+ /**M: commt out this code @{*/
+ /*CHECK(p_chnl_cfg != NULL);*/
+ /**@}*/
+ if (p_ccb) {
+ if (p_ccb->p_tx_req || p_ccb->p_rx_msg || p_ccb->cong) {
+ MCA_TRACE_ERROR("pending req");
+ return MCA_BUSY;
+ }
+
+ if (!MCA_IS_VALID_MDL_ID(mdl_id)) {
+ MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+
+ if (mca_ccb_uses_mdl_id(p_ccb, mdl_id)) {
+ MCA_TRACE_ERROR("mdl id: %d is used in the control link", mdl_id);
+ return MCA_BAD_MDL_ID;
+ }
+
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ result = MCA_NO_RESOURCES;
+ if (p_dcb) {
+ tMCA_CCB_MSG* p_evt_data =
+ (tMCA_CCB_MSG*)osi_malloc(sizeof(tMCA_CCB_MSG));
+
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ if (!p_ccb->data_vpsm)
+ p_ccb->data_vpsm =
+ L2CA_Register(data_psm, (tL2CAP_APPL_INFO*)&mca_l2c_int_appl);
+ p_evt_data->dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->op_code = MCA_OP_MDL_RECONNECT_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT*)p_evt_data);
+ return MCA_SUCCESS;
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_ReconnectMdlRsp
+ *
+ * Description This function sends a RECONNECT_MDL response to the peer
+ * device in response to a MCA_RECONNECT_IND_EVT event.
+ * If the response is successful, a data channel is open.
+ * When the data channel is open successfully, a
+ * MCA_OPEN_IND_EVT is reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_ReconnectMdlRsp(tMCA_CL mcl, tMCA_DEP dep, uint16_t mdl_id,
+ uint8_t rsp_code,
+ const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_CCB_MSG evt_data;
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_API("MCA_ReconnectMdlRsp: %d ", mcl);
+ CHECK(p_chnl_cfg != NULL);
+ if (p_ccb) {
+ if (p_ccb->cong) {
+ MCA_TRACE_ERROR("congested");
+ return MCA_BUSY;
+ }
+ if (p_ccb->p_rx_msg && (p_ccb->p_rx_msg->mdl_id == mdl_id) &&
+ (p_ccb->p_rx_msg->op_code == MCA_OP_MDL_RECONNECT_REQ)) {
+ result = MCA_SUCCESS;
+ evt_data.dcb_idx = 0;
+ if (rsp_code == MCA_RSP_SUCCESS) {
+ p_dcb = mca_dcb_alloc(p_ccb, dep);
+ if (p_dcb) {
+ evt_data.dcb_idx = mca_dcb_to_hdl(p_dcb);
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ p_dcb->mdl_id = mdl_id;
+ } else {
+ MCA_TRACE_ERROR("Out of MDL for this MDEP");
+ rsp_code = MCA_RSP_MDEP_BUSY;
+ result = MCA_NO_RESOURCES;
+ }
+ }
+
+ evt_data.mdl_id = mdl_id;
+ evt_data.rsp_code = rsp_code;
+ evt_data.op_code = MCA_OP_MDL_RECONNECT_RSP;
+ mca_ccb_event(p_ccb, MCA_CCB_API_RSP_EVT, (tMCA_CCB_EVT*)&evt_data);
+ } else {
+ MCA_TRACE_ERROR(
+ "The given MCL is not expecting a MCA_ReconnectMdlRsp with the given "
+ "parameters");
+ result = MCA_BAD_PARAMS;
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_DataChnlCfg
+ *
+ * Description This function initiates a data channel connection toward the
+ * connected peer device.
+ * When the data channel is open successfully, a
+ * MCA_OPEN_CFM_EVT is reported. This data channel is
+ * identified as tMCA_DL.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_DataChnlCfg(tMCA_CL mcl, const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_DCB* p_dcb;
+ tMCA_TC_TBL* p_tbl;
+
+ MCA_TRACE_API("MCA_DataChnlCfg: %d ", mcl);
+ CHECK(p_chnl_cfg != NULL);
+ if (p_ccb) {
+ result = MCA_NO_RESOURCES;
+ if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
+ MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
+ p_ccb->status);
+ return result;
+ }
+
+ p_dcb->p_chnl_cfg = p_chnl_cfg;
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
+ p_ccb->data_vpsm, BTM_SEC_PROTO_MCA,
+ p_ccb->p_tx_req->dcb_idx);
+ p_dcb->lcid =
+ mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
+ if (p_dcb->lcid) {
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ if (p_tbl) {
+ p_tbl->state = MCA_TC_ST_CONN;
+ result = MCA_SUCCESS;
+ }
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_Abort
+ *
+ * Description This function sends a ABORT_MDL request to the peer device.
+ * When the response is received, a MCA_ABORT_CFM_EVT is
+ * reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_Abort(tMCA_CL mcl) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_API("MCA_Abort: %d", mcl);
+ if (p_ccb) {
+ result = MCA_NO_RESOURCES;
+ /* verify that we are waiting for data channel to come up with the given mdl
+ */
+ if ((p_ccb->p_tx_req == NULL) || (p_ccb->status != MCA_CCB_STAT_PENDING) ||
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) == NULL)) {
+ MCA_TRACE_ERROR("The given MCL is not expecting this API:%d",
+ p_ccb->status);
+ return result;
+ }
+
+ if (p_ccb->cong) {
+ MCA_TRACE_ERROR("congested");
+ return MCA_BUSY;
+ }
+
+ tMCA_CCB_MSG* p_evt_data = (tMCA_CCB_MSG*)osi_malloc(sizeof(tMCA_CCB_MSG));
+ result = MCA_SUCCESS;
+ p_evt_data->op_code = MCA_OP_MDL_ABORT_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT*)p_evt_data);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_Delete
+ *
+ * Description This function sends a DELETE_MDL request to the peer device.
+ * When the response is received, a MCA_DELETE_CFM_EVT is
+ * reported.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_Delete(tMCA_CL mcl, uint16_t mdl_id) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_CCB* p_ccb = mca_ccb_by_hdl(mcl);
+
+ MCA_TRACE_API("MCA_Delete: %d ", mcl);
+ if (p_ccb) {
+ if (p_ccb->cong) {
+ MCA_TRACE_ERROR("congested");
+ return MCA_BUSY;
+ }
+ if (!MCA_IS_VALID_MDL_ID(mdl_id) && (mdl_id != MCA_ALL_MDL_ID)) {
+ MCA_TRACE_ERROR("bad mdl id: %d ", mdl_id);
+ return MCA_BAD_PARAMS;
+ }
+
+ tMCA_CCB_MSG* p_evt_data = (tMCA_CCB_MSG*)osi_malloc(sizeof(tMCA_CCB_MSG));
+ result = MCA_SUCCESS;
+ p_evt_data->mdl_id = mdl_id;
+ p_evt_data->op_code = MCA_OP_MDL_DELETE_REQ;
+ p_evt_data->hdr.event = MCA_CCB_API_REQ_EVT;
+ mca_ccb_event(p_ccb, MCA_CCB_API_REQ_EVT, (tMCA_CCB_EVT*)p_evt_data);
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_WriteReq
+ *
+ * Description Send a data packet to the peer device.
+ *
+ * The application passes the packet using the BT_HDR
+ * structure. The offset field must be equal to or greater than
+ * L2CAP_MIN_OFFSET. This allows enough space in the buffer for
+ * the L2CAP header.
+ *
+ * The memory pointed to by p_pkt must be a GKI buffer
+ * allocated by the application. This buffer will be freed
+ * by the protocol stack; the application must not free
+ * this buffer.
+ *
+ * Returns MCA_SUCCESS if successful, otherwise error.
+ *
+ ******************************************************************************/
+tMCA_RESULT MCA_WriteReq(tMCA_DL mdl, BT_HDR* p_pkt) {
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
+ tMCA_DCB_EVT evt_data;
+
+ MCA_TRACE_API("MCA_WriteReq: %d ", mdl);
+ if (p_dcb) {
+ if (p_dcb->cong) {
+ result = MCA_BUSY;
+ } else {
+ evt_data.p_pkt = p_pkt;
+ result = MCA_SUCCESS;
+ mca_dcb_event(p_dcb, MCA_DCB_API_WRITE_EVT, &evt_data);
+ }
+ }
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function MCA_GetL2CapChannel
+ *
+ * Description Get the L2CAP CID used by the given data channel handle.
+ *
+ * Returns L2CAP channel ID if successful, otherwise 0.
+ *
+ ******************************************************************************/
+uint16_t MCA_GetL2CapChannel(tMCA_DL mdl) {
+ uint16_t lcid = 0;
+ tMCA_DCB* p_dcb = mca_dcb_by_hdl(mdl);
+
+ MCA_TRACE_API("MCA_GetL2CapChannel: %d ", mdl);
+ if (p_dcb) lcid = p_dcb->lcid;
+ return lcid;
+}
+
+static const btmcap_test_interface_t mcap_test_interface = {
+ sizeof(btmcap_test_interface_t),
+ MCA_Init,
+ MCA_Register,
+ MCA_Deregister,
+ MCA_CreateDep,
+ MCA_DeleteDep,
+ MCA_ConnectReq,
+ MCA_DisconnectReq,
+ MCA_CreateMdl,
+ MCA_CreateMdlRsp,
+ MCA_CloseReq,
+ MCA_ReconnectMdl,
+ MCA_ReconnectMdlRsp,
+ MCA_DataChnlCfg,
+ MCA_Abort,
+ MCA_Delete,
+ MCA_WriteReq,
+ MCA_GetL2CapChannel,
+};
+
+const btmcap_test_interface_t* stack_mcap_get_interface(void) {
+ BTIF_TRACE_EVENT("%s", __func__);
+ return &mcap_test_interface;
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_cact.cc b/mtkbt/code/bt/stack/mcap/mca_cact.cc
new file mode 100755
index 0000000..0579f36
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_cact.cc
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP Control Channel Action
+ * Functions.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+#include "btu.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function mca_ccb_rsp_tout
+ *
+ * Description This function processes the response timeout.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_rsp_tout(tMCA_CCB* p_ccb, UNUSED_ATTR tMCA_CCB_EVT* p_data) {
+ tMCA_CTRL evt_data;
+
+ mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_report_event
+ *
+ * Description This function reports the given event.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_report_event(tMCA_CCB* p_ccb, uint8_t event, tMCA_CTRL* p_data) {
+ if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
+ (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb),
+ mca_ccb_to_hdl(p_ccb), event, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_free_msg
+ *
+ * Description This function frees the received message.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_free_msg(UNUSED_ATTR tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ osi_free(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_snd_req
+ *
+ * Description This function builds a request and sends it to the peer.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_snd_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ tMCA_CCB_MSG* p_msg = (tMCA_CCB_MSG*)p_data;
+ uint8_t *p, *p_start;
+ bool is_abort = false;
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_DEBUG("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong,
+ p_msg->op_code);
+ /* check for abort request */
+ if ((p_ccb->status == MCA_CCB_STAT_PENDING) &&
+ (p_msg->op_code == MCA_OP_MDL_ABORT_REQ)) {
+ p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+ /* the Abort API does not have the associated mdl_id.
+ * Get the mdl_id in dcb to compose the request */
+ p_msg->mdl_id = p_dcb->mdl_id;
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ p_ccb->status = MCA_CCB_STAT_NORM;
+ is_abort = true;
+ }
+
+ /* no pending outgoing messages or it's an abort request for a pending data
+ * channel */
+ if ((!p_ccb->p_tx_req) || is_abort) {
+ p_ccb->p_tx_req = p_msg;
+ if (!p_ccb->cong) {
+ BT_HDR* p_pkt = (BT_HDR*)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+ *p++ = p_msg->op_code;
+ UINT16_TO_BE_STREAM(p, p_msg->mdl_id);
+ if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ) {
+ *p++ = p_msg->mdep_id;
+ *p++ = p_msg->param;
+ }
+ p_msg->hdr.layer_specific = true; /* mark this message as sent */
+ p_pkt->len = p - p_start;
+ L2CA_DataWrite(p_ccb->lcid, p_pkt);
+ period_ms_t interval_ms = p_ccb->p_rcb->reg.rsp_tout * 1000;
+ alarm_set_on_queue(p_ccb->mca_ccb_timer, interval_ms,
+ mca_ccb_timer_timeout, p_ccb, btu_general_alarm_queue);
+ }
+ /* else the L2CAP channel is congested. keep the message to be sent later */
+ } else {
+ MCA_TRACE_WARNING("dropping api req");
+ osi_free(p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_snd_rsp
+ *
+ * Description This function builds a response and sends it to
+ * the peer.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_snd_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ tMCA_CCB_MSG* p_msg = (tMCA_CCB_MSG*)p_data;
+ uint8_t *p, *p_start;
+ BT_HDR* p_pkt = (BT_HDR*)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+
+ MCA_TRACE_DEBUG("%s cong=%d req=%d", __func__, p_ccb->cong, p_msg->op_code);
+ /* assume that API functions verified the parameters */
+
+ p_pkt->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
+ *p++ = p_msg->op_code;
+ *p++ = p_msg->rsp_code;
+ UINT16_TO_BE_STREAM(p, p_msg->mdl_id);
+
+ // Only add extra parameters for MCA_RSP_SUCCESS message
+ if (p_msg->rsp_code == MCA_RSP_SUCCESS) {
+ // Append MDL configuration parameters
+ if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP) {
+ *p++ = p_msg->param;
+ }
+ // Check MDL
+ if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP ||
+ p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP) {
+ mca_dcb_by_hdl(p_msg->dcb_idx);
+ BTM_SetSecurityLevel(false, "", BTM_SEC_SERVICE_MCAP_DATA,
+ p_ccb->sec_mask, p_ccb->p_rcb->reg.data_psm,
+ BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ /* set p_tx_req to block API_REQ/API_RSP before DL is up */
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ p_ccb->p_tx_req = p_ccb->p_rx_msg;
+ p_ccb->p_rx_msg = NULL;
+ p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
+ }
+ }
+
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+ p_pkt->len = p - p_start;
+ L2CA_DataWrite(p_ccb->lcid, p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_do_disconn
+ *
+ * Description This function closes a control channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_do_disconn(tMCA_CCB* p_ccb, UNUSED_ATTR tMCA_CCB_EVT* p_data) {
+ mca_dcb_close_by_mdl_id(p_ccb, MCA_ALL_MDL_ID);
+ L2CA_DisconnectReq(p_ccb->lcid);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_cong
+ *
+ * Description This function sets the congestion state for the CCB.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_cong(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ MCA_TRACE_DEBUG("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
+ p_ccb->cong = p_data->llcong;
+ if (!p_ccb->cong) {
+ /* if there's a held packet, send it now */
+ if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific) {
+ p_data = (tMCA_CCB_EVT*)p_ccb->p_tx_req;
+ p_ccb->p_tx_req = NULL;
+ mca_ccb_snd_req(p_ccb, p_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_hdl_req
+ *
+ * Description This function is called when a MCAP request is received from
+ * the peer. It calls the application callback function to
+ * report the event.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_hdl_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ BT_HDR* p_pkt = &p_data->hdr;
+ uint8_t *p, *p_start;
+ tMCA_DCB* p_dcb;
+ tMCA_CTRL evt_data;
+ tMCA_CCB_MSG* p_rx_msg = NULL;
+ uint8_t reject_code = MCA_RSP_NO_RESOURCE;
+ bool send_rsp = false;
+ bool check_req = false;
+ uint8_t reject_opcode;
+
+ MCA_TRACE_DEBUG("mca_ccb_hdl_req status:%d", p_ccb->status);
+ p_rx_msg = (tMCA_CCB_MSG*)p_pkt;
+ p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ evt_data.hdr.op_code = *p++;
+ BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
+ reject_opcode = evt_data.hdr.op_code + 1;
+
+ MCA_TRACE_DEBUG("received mdl id: %d ", evt_data.hdr.mdl_id);
+ if (p_ccb->status == MCA_CCB_STAT_PENDING) {
+ MCA_TRACE_DEBUG("received req inpending state");
+ /* allow abort in pending state */
+ if ((p_ccb->status == MCA_CCB_STAT_PENDING) &&
+ (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ)) {
+ reject_code = MCA_RSP_SUCCESS;
+ send_rsp = true;
+ /* clear the pending status */
+ p_ccb->status = MCA_CCB_STAT_NORM;
+ if (p_ccb->p_tx_req &&
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
+ mca_dcb_dealloc(p_dcb, NULL);
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ }
+ } else
+ reject_code = MCA_RSP_BAD_OP;
+ } else if (p_ccb->p_rx_msg) {
+ MCA_TRACE_DEBUG("still handling prev req");
+ /* still holding previous message, reject this new one ?? */
+
+ } else if (p_ccb->p_tx_req) {
+ MCA_TRACE_DEBUG("still waiting for a response ctrl_vpsm:0x%x",
+ p_ccb->ctrl_vpsm);
+ /* sent a request; waiting for response */
+ if (p_ccb->ctrl_vpsm == 0) {
+ MCA_TRACE_DEBUG("local is ACP. accept the cmd from INT");
+ /* local is acceptor, need to handle the request */
+ check_req = true;
+ reject_code = MCA_RSP_SUCCESS;
+ /* drop the previous request */
+ if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
+ ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ mca_stop_timer(p_ccb);
+ } else {
+ /* local is initiator, ignore the req */
+ osi_free(p_pkt);
+ return;
+ }
+ } else if (p_pkt->layer_specific != MCA_RSP_SUCCESS) {
+ reject_code = (uint8_t)p_pkt->layer_specific;
+ if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
+ (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
+ (evt_data.hdr.op_code > MCA_LAST_SYNC_OP)) {
+ /* invalid op code */
+ reject_opcode = MCA_OP_ERROR_RSP;
+ evt_data.hdr.mdl_id = 0;
+ }
+ } else {
+ check_req = true;
+ reject_code = MCA_RSP_SUCCESS;
+ }
+
+ if (check_req) {
+ if (reject_code == MCA_RSP_SUCCESS) {
+ reject_code = MCA_RSP_BAD_MDL;
+ if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
+ ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) &&
+ (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ))) {
+ reject_code = MCA_RSP_SUCCESS;
+ /* mdl_id is valid according to the spec */
+ switch (evt_data.hdr.op_code) {
+ case MCA_OP_MDL_CREATE_REQ:
+ evt_data.create_ind.dep_id = *p++;
+ evt_data.create_ind.cfg = *p++;
+ p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
+ if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id)) {
+ MCA_TRACE_ERROR("%s: Invalid local MDEP ID %d", __func__,
+ p_rx_msg->mdep_id);
+ reject_code = MCA_RSP_BAD_MDEP;
+ } else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
+ MCA_TRACE_DEBUG("the mdl_id is currently used in the CL(create)");
+ mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+ } else {
+ /* check if this dep still have MDL available */
+ if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0) {
+ MCA_TRACE_ERROR("%s: MAX_MDL is used by MDEP %d", __func__,
+ evt_data.create_ind.dep_id);
+ reject_code = MCA_RSP_MDEP_BUSY;
+ }
+ }
+ break;
+
+ case MCA_OP_MDL_RECONNECT_REQ:
+ if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id)) {
+ MCA_TRACE_ERROR("%s: MDL_ID %d busy, in CL(reconn)", __func__,
+ evt_data.hdr.mdl_id);
+ reject_code = MCA_RSP_MDL_BUSY;
+ }
+ break;
+
+ case MCA_OP_MDL_ABORT_REQ:
+ reject_code = MCA_RSP_BAD_OP;
+ break;
+
+ case MCA_OP_MDL_DELETE_REQ:
+ /* delete the associated mdl */
+ mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
+ send_rsp = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (((reject_code != MCA_RSP_SUCCESS) &&
+ (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND)) ||
+ send_rsp) {
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(MCA_CTRL_MTU + sizeof(BT_HDR));
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ *p++ = reject_opcode;
+ *p++ = reject_code;
+ bool valid_response = true;
+ switch (reject_opcode) {
+ // Fill in the rest of standard opcode response packet with mdl_id
+ case MCA_OP_ERROR_RSP:
+ case MCA_OP_MDL_CREATE_RSP:
+ case MCA_OP_MDL_RECONNECT_RSP:
+ case MCA_OP_MDL_ABORT_RSP:
+ case MCA_OP_MDL_DELETE_RSP:
+ UINT16_TO_BE_STREAM(p, evt_data.hdr.mdl_id);
+ break;
+ // Fill in the rest of clock sync opcode response packet with 0
+ case MCA_OP_SYNC_CAP_RSP:
+ // Page 37/58 MCAP V1.0 Spec: Total length (9) - 2 = 7
+ memset(p, 0, 7);
+ p += 7;
+ break;
+ case MCA_OP_SYNC_SET_RSP:
+ // Page 39/58 MCAP V1.0 Spec: Total length (16) - 2 = 14
+ memset(p, 0, 14);
+ p += 14;
+ break;
+ default:
+ MCA_TRACE_ERROR("%s: reject_opcode 0x%02x not recognized", __func__,
+ reject_opcode);
+ valid_response = false;
+ break;
+ }
+ if (valid_response) {
+ p_buf->len = p - p_start;
+ MCA_TRACE_ERROR("%s: reject_opcode=0x%02x, reject_code=0x%02x, length=%d",
+ __func__, reject_opcode, reject_code, p_buf->len);
+ L2CA_DataWrite(p_ccb->lcid, p_buf);
+ } else {
+ osi_free(p_buf);
+ }
+ }
+
+ if (reject_code == MCA_RSP_SUCCESS) {
+ /* use the received GKI buffer to store information to double check response
+ * API */
+ p_rx_msg->op_code = evt_data.hdr.op_code;
+ p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
+ p_ccb->p_rx_msg = p_rx_msg;
+ if (send_rsp) {
+ osi_free(p_pkt);
+ p_ccb->p_rx_msg = NULL;
+ }
+ mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+ } else
+ osi_free(p_pkt);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_hdl_rsp
+ *
+ * Description This function is called when a MCAP response is received
+ * from the peer. It calls the application callback function
+ * with the results.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_hdl_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ BT_HDR* p_pkt = &p_data->hdr;
+ uint8_t* p;
+ tMCA_CTRL evt_data;
+ bool chk_mdl = false;
+ tMCA_DCB* p_dcb;
+ tMCA_RESULT result = MCA_BAD_HANDLE;
+ tMCA_TC_TBL* p_tbl;
+
+ if (p_ccb->p_tx_req) {
+ /* verify that the received response matches the sent request */
+ p = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ evt_data.hdr.op_code = *p++;
+ if ((evt_data.hdr.op_code == 0) ||
+ ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code)) {
+ evt_data.rsp.rsp_code = *p++;
+ mca_stop_timer(p_ccb);
+ BE_STREAM_TO_UINT16(evt_data.hdr.mdl_id, p);
+ if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP) {
+ evt_data.create_cfm.cfg = *p++;
+ chk_mdl = true;
+ } else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
+ chk_mdl = true;
+
+ if (chk_mdl) {
+ p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
+ if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) {
+ if (evt_data.hdr.mdl_id != p_dcb->mdl_id) {
+ MCA_TRACE_ERROR("peer's mdl_id=%d != our mdl_id=%d",
+ evt_data.hdr.mdl_id, p_dcb->mdl_id);
+ /* change the response code to be an error */
+ if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS) {
+ evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
+ /* send Abort */
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ MCA_Abort(mca_ccb_to_hdl(p_ccb));
+ }
+ } else if (p_dcb->p_chnl_cfg) {
+ /* the data channel configuration is known. Proceed with data
+ * channel initiation */
+ BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_MCAP_DATA,
+ p_ccb->sec_mask, p_ccb->data_vpsm,
+ BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
+ p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm,
+ p_dcb->p_chnl_cfg);
+ if (p_dcb->lcid) {
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ if (p_tbl) {
+ p_tbl->state = MCA_TC_ST_CONN;
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ result = MCA_SUCCESS;
+ }
+ }
+ } else {
+ /* mark this MCL as pending and wait for MCA_DataChnlCfg */
+ p_ccb->status = MCA_CCB_STAT_PENDING;
+ result = MCA_SUCCESS;
+ }
+ }
+
+ if (result != MCA_SUCCESS && p_dcb) {
+ mca_dcb_dealloc(p_dcb, NULL);
+ }
+ } /* end of chk_mdl */
+
+ if (p_ccb->status != MCA_CCB_STAT_PENDING)
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
+ }
+ /* else a bad response is received */
+ } else {
+ /* not expecting any response. drop it */
+ MCA_TRACE_WARNING("dropping received rsp (not expecting a response)");
+ }
+ osi_free(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_ll_open
+ *
+ * Description This function is called to report MCA_CONNECT_IND_EVT event.
+ * It also clears the congestion flag (ccb.cong).
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_ll_open(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ tMCA_CTRL evt_data;
+ p_ccb->cong = false;
+ evt_data.connect_ind.mtu = p_data->open.peer_mtu;
+ memcpy(evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+ mca_ccb_report_event(p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_dl_open
+ *
+ * Description This function is called when data channel is open. It clears
+ * p_tx_req to allow other message exchage on this CL.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_dl_open(tMCA_CCB* p_ccb, UNUSED_ATTR tMCA_CCB_EVT* p_data) {
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+ p_ccb->status = MCA_CCB_STAT_NORM;
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_csm.cc b/mtkbt/code/bt/stack/mcap/mca_csm.cc
new file mode 100755
index 0000000..3c437f6
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_csm.cc
@@ -0,0 +1,328 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP Control channel state
+ * machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "btu.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/*****************************************************************************
+ * data channel state machine constants and types
+ ****************************************************************************/
+enum {
+ MCA_CCB_FREE_MSG,
+ MCA_CCB_SND_REQ,
+ MCA_CCB_SND_RSP,
+ MCA_CCB_DO_DISCONN,
+ MCA_CCB_CONG,
+ MCA_CCB_HDL_REQ,
+ MCA_CCB_HDL_RSP,
+ MCA_CCB_LL_OPEN,
+ MCA_CCB_DL_OPEN,
+ MCA_CCB_DEALLOC,
+ MCA_CCB_RSP_TOUT,
+ MCA_CCB_NUM_ACTIONS
+};
+#define MCA_CCB_IGNORE MCA_CCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_CCB_ACTION mca_ccb_action[] = {
+ mca_ccb_free_msg, mca_ccb_snd_req, mca_ccb_snd_rsp, mca_ccb_do_disconn,
+ mca_ccb_cong, mca_ccb_hdl_req, mca_ccb_hdl_rsp, mca_ccb_ll_open,
+ mca_ccb_dl_open, mca_ccb_dealloc, mca_ccb_rsp_tout,
+};
+
+/* state table information */
+#define MCA_CCB_ACTIONS 1 /* number of actions */
+#define MCA_CCB_ACT_COL 0 /* position of action function */
+#define MCA_CCB_NEXT_STATE 1 /* position of next state */
+#define MCA_CCB_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for opening state */
+const uint8_t mca_ccb_st_opening[][MCA_CCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_LL_OPEN, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+ /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPENING_ST},
+ /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t mca_ccb_st_open[][MCA_CCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_DO_DISCONN, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_SND_REQ, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_SND_RSP, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_HDL_REQ, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_HDL_RSP, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_DL_OPEN, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+ /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_CONG, MCA_CCB_OPEN_ST},
+ /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_RSP_TOUT, MCA_CCB_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t mca_ccb_st_closing[][MCA_CCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_CCB_API_CONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_API_DISCONNECT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_API_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_API_RSP_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_MSG_REQ_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_MSG_RSP_EVT */ {MCA_CCB_FREE_MSG, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_DL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_LL_OPEN_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_LL_CLOSE_EVT */ {MCA_CCB_DEALLOC, MCA_CCB_NULL_ST},
+ /* MCA_CCB_LL_CONG_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST},
+ /* MCA_CCB_RSP_TOUT_EVT */ {MCA_CCB_IGNORE, MCA_CCB_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tMCA_CCB_ST_TBL)[MCA_CCB_NUM_COLS];
+
+/* state table */
+const tMCA_CCB_ST_TBL mca_ccb_st_tbl[] = {mca_ccb_st_opening, mca_ccb_st_open,
+ mca_ccb_st_closing};
+
+/* verbose event strings for trace */
+static const char* const mca_ccb_evt_str[] = {
+ "API_CONNECT_EVT", "API_DISCONNECT_EVT", "API_REQ_EVT", "API_RSP_EVT",
+ "MSG_REQ_EVT", "MSG_RSP_EVT", "DL_OPEN_EVT", "LL_OPEN_EVT",
+ "LL_CLOSE_EVT", "LL_CONG_EVT", "RSP_TOUT_EVT"};
+/* verbose state strings for trace */
+static const char* const mca_ccb_st_str[] = {"NULL_ST", "OPENING_ST", "OPEN_ST",
+ "CLOSING_ST"};
+
+/*******************************************************************************
+ *
+ * Function mca_stop_timer
+ *
+ * Description This function is stop a MCAP timer
+ *
+ * This function is for use internal to MCAP only.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_stop_timer(tMCA_CCB* p_ccb) { alarm_cancel(p_ccb->mca_ccb_timer); }
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_event
+ *
+ * Description This function is the CCB state machine main function.
+ * It uses the state and action function tables to execute
+ * action functions.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_event(tMCA_CCB* p_ccb, uint8_t event, tMCA_CCB_EVT* p_data) {
+ tMCA_CCB_ST_TBL state_table;
+ uint8_t action;
+
+ MCA_TRACE_EVENT("CCB ccb=%d event=%s state=%s", mca_ccb_to_hdl(p_ccb),
+ mca_ccb_evt_str[event], mca_ccb_st_str[p_ccb->state]);
+
+ /* look up the state table for the current state */
+ state_table = mca_ccb_st_tbl[p_ccb->state - 1];
+
+ /* set next state */
+ p_ccb->state = state_table[event][MCA_CCB_NEXT_STATE];
+
+ /* execute action functions */
+ action = state_table[event][MCA_CCB_ACT_COL];
+ if (action != MCA_CCB_IGNORE) {
+ (*mca_ccb_action[action])(p_ccb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_by_bd
+ *
+ * Description This function looks up the CCB based on the BD address.
+ * It returns a pointer to the CCB.
+ * If no CCB is found it returns NULL.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+tMCA_CCB* mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr) {
+ tMCA_CCB* p_ccb = NULL;
+ tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CCB* p_ccb_tmp;
+ int i;
+
+ if (p_rcb) {
+ i = handle - 1;
+ p_ccb_tmp = &mca_cb.ccb[i * MCA_NUM_LINKS];
+ for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb_tmp++) {
+ if (p_ccb_tmp->state != MCA_CCB_NULL_ST &&
+ memcmp(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN) == 0) {
+ p_ccb = p_ccb_tmp;
+ break;
+ }
+ }
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_alloc
+ *
+ * Description This function allocates a CCB and copies the BD address to
+ * the CCB. It returns a pointer to the CCB. If no CCB can
+ * be allocated it returns NULL.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+tMCA_CCB* mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr) {
+ tMCA_CCB* p_ccb = NULL;
+ tMCA_RCB* p_rcb = mca_rcb_by_handle(handle);
+ tMCA_CCB* p_ccb_tmp;
+ int i;
+
+ MCA_TRACE_DEBUG("mca_ccb_alloc handle:0x%x", handle);
+ if (p_rcb) {
+ i = handle - 1;
+ p_ccb_tmp = &mca_cb.ccb[i * MCA_NUM_LINKS];
+ for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb_tmp++) {
+ if (p_ccb_tmp->state == MCA_CCB_NULL_ST) {
+ p_ccb_tmp->p_rcb = p_rcb;
+ p_ccb_tmp->mca_ccb_timer = alarm_new("mca.mca_ccb_timer");
+ p_ccb_tmp->state = MCA_CCB_OPENING_ST;
+ p_ccb_tmp->cong = true;
+ memcpy(p_ccb_tmp->peer_addr, bd_addr, BD_ADDR_LEN);
+ p_ccb = p_ccb_tmp;
+ break;
+ }
+ }
+ }
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_dealloc
+ *
+ * Description This function deallocates a CCB.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_ccb_dealloc(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data) {
+ tMCA_CTRL evt_data;
+
+ MCA_TRACE_DEBUG("mca_ccb_dealloc ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
+ mca_dcb_close_by_mdl_id(p_ccb, MCA_ALL_MDL_ID);
+ if (p_ccb->ctrl_vpsm) {
+ L2CA_Deregister(p_ccb->ctrl_vpsm);
+ }
+ if (p_ccb->data_vpsm) {
+ L2CA_Deregister(p_ccb->data_vpsm);
+ }
+ osi_free_and_reset((void**)&p_ccb->p_rx_msg);
+ osi_free_and_reset((void**)&p_ccb->p_tx_req);
+ mca_stop_timer(p_ccb);
+
+ if (p_data) {
+ /* non-NULL -> an action function -> report disconnect event */
+ memcpy(evt_data.disconnect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
+ evt_data.disconnect_ind.reason = p_data->close.reason;
+ mca_ccb_report_event(p_ccb, MCA_DISCONNECT_IND_EVT, &evt_data);
+ }
+ mca_free_tc_tbl_by_lcid(p_ccb->lcid);
+ alarm_free(p_ccb->mca_ccb_timer);
+ memset(p_ccb, 0, sizeof(tMCA_CCB));
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_to_hdl
+ *
+ * Description This function converts a pointer to a CCB to a tMCA_CL
+ * and returns the value.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+tMCA_CL mca_ccb_to_hdl(tMCA_CCB* p_ccb) {
+ return (uint8_t)(p_ccb - mca_cb.ccb + 1);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_by_hdl
+ *
+ * Description This function converts an index value to a CCB. It returns
+ * a pointer to the CCB. If no valid CCB matches the index it
+ * returns NULL.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+tMCA_CCB* mca_ccb_by_hdl(tMCA_CL mcl) {
+ tMCA_CCB* p_ccb = NULL;
+ if (mcl && mcl <= MCA_NUM_CCBS && mca_cb.ccb[mcl - 1].state)
+ p_ccb = &mca_cb.ccb[mcl - 1];
+ return p_ccb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_ccb_uses_mdl_id
+ *
+ * Description This function checkes if a given mdl_id is in use.
+ *
+ * Returns true, if the given mdl_id is currently used in the MCL.
+ *
+ ******************************************************************************/
+bool mca_ccb_uses_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id) {
+ bool uses = false;
+ tMCA_DCB* p_dcb;
+ int i;
+
+ i = mca_ccb_to_hdl(p_ccb) - 1;
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ for (i = 0; i < MCA_NUM_MDLS; i++, p_dcb++) {
+ if (p_dcb->state != MCA_DCB_NULL_ST && p_dcb->mdl_id == mdl_id) {
+ uses = true;
+ break;
+ }
+ }
+
+ return uses;
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_dact.cc b/mtkbt/code/bt/stack/mcap/mca_dact.cc
new file mode 100755
index 0000000..a99d47c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_dact.cc
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP Data Channel Action
+ * Functions.
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "mca_api.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_report_cong
+ *
+ * Description This function is called to report the congestion flag.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_report_cong(tMCA_DCB* p_dcb) {
+ tMCA_CTRL evt_data;
+
+ evt_data.cong_chg.cong = p_dcb->cong;
+ evt_data.cong_chg.mdl = mca_dcb_to_hdl(p_dcb);
+ evt_data.cong_chg.mdl_id = p_dcb->mdl_id;
+ mca_ccb_report_event(p_dcb->p_ccb, MCA_CONG_CHG_EVT, &evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_tc_open
+ *
+ * Description This function is called to report MCA_OPEN_IND_EVT or
+ * MCA_OPEN_CFM_EVT event.
+ * It also clears the congestion flag (dcb.cong).
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_tc_open(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ tMCA_CTRL evt_data;
+ tMCA_CCB* p_ccb = p_dcb->p_ccb;
+ uint8_t event = MCA_OPEN_IND_EVT;
+
+ if (p_data->open.param == MCA_INT) event = MCA_OPEN_CFM_EVT;
+ p_dcb->cong = false;
+ evt_data.open_cfm.mtu = p_data->open.peer_mtu;
+ evt_data.open_cfm.mdl_id = p_dcb->mdl_id;
+ evt_data.open_cfm.mdl = mca_dcb_to_hdl(p_dcb);
+ mca_ccb_event(p_ccb, MCA_CCB_DL_OPEN_EVT, NULL);
+ mca_ccb_report_event(p_ccb, event, &evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_cong
+ *
+ * Description This function sets the congestion state for the DCB.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_cong(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ p_dcb->cong = p_data->llcong;
+ mca_dcb_report_cong(p_dcb);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_free_data
+ *
+ * Description This function frees the received message.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_free_data(UNUSED_ATTR tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ osi_free(p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_do_disconn
+ *
+ * Description This function closes a data channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_do_disconn(tMCA_DCB* p_dcb, UNUSED_ATTR tMCA_DCB_EVT* p_data) {
+ tMCA_CLOSE close;
+
+ if ((p_dcb->lcid == 0) || (L2CA_DisconnectReq(p_dcb->lcid) == false)) {
+ close.param = MCA_INT;
+ close.reason = L2CAP_DISC_OK;
+ close.lcid = 0;
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT*)&close);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_snd_data
+ *
+ * Description Send the data from application to the peer device.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_snd_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ uint8_t status;
+
+ /* do not need to check cong, because API already checked the status */
+ status = L2CA_DataWrite(p_dcb->lcid, p_data->p_pkt);
+ if (status == L2CAP_DW_CONGESTED) {
+ p_dcb->cong = true;
+ mca_dcb_report_cong(p_dcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_hdl_data
+ *
+ * Description This function reports the received data through the data
+ * callback function.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_hdl_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ (*p_dcb->p_cs->p_data_cback)(mca_dcb_to_hdl(p_dcb), (BT_HDR*)p_data);
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_dsm.cc b/mtkbt/code/bt/stack/mcap/mca_dsm.cc
new file mode 100755
index 0000000..3494448
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_dsm.cc
@@ -0,0 +1,295 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP Data chahnel state machine.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/*****************************************************************************
+ * data channel state machine constants and types
+ ****************************************************************************/
+enum {
+ MCA_DCB_TC_OPEN,
+ MCA_DCB_CONG,
+ MCA_DCB_FREE_DATA,
+ MCA_DCB_DEALLOC,
+ MCA_DCB_DO_DISCONN,
+ MCA_DCB_SND_DATA,
+ MCA_DCB_HDL_DATA,
+ MCA_DCB_NUM_ACTIONS
+};
+#define MCA_DCB_IGNORE MCA_DCB_NUM_ACTIONS
+
+/* action function list */
+const tMCA_DCB_ACTION mca_dcb_action[] = {
+ mca_dcb_tc_open, mca_dcb_cong, mca_dcb_free_data, mca_dcb_dealloc,
+ mca_dcb_do_disconn, mca_dcb_snd_data, mca_dcb_hdl_data};
+
+/* state table information */
+#define MCA_DCB_ACTIONS 1 /* number of actions */
+#define MCA_DCB_ACT_COL 0 /* position of action function */
+#define MCA_DCB_NEXT_STATE 1 /* position of next state */
+#define MCA_DCB_NUM_COLS 2 /* number of columns in state tables */
+
+/* state table for opening state */
+const uint8_t mca_dcb_st_opening[][MCA_DCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
+ /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPENING_ST},
+ /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
+ /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+ /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPENING_ST},
+ /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_OPENING_ST}};
+
+/* state table for open state */
+const uint8_t mca_dcb_st_open[][MCA_DCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_DO_DISCONN, MCA_DCB_CLOSING_ST},
+ /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_SND_DATA, MCA_DCB_OPEN_ST},
+ /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_IGNORE, MCA_DCB_OPEN_ST},
+ /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+ /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_CONG, MCA_DCB_OPEN_ST},
+ /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_HDL_DATA, MCA_DCB_OPEN_ST}};
+
+/* state table for closing state */
+const uint8_t mca_dcb_st_closing[][MCA_DCB_NUM_COLS] = {
+ /* Event Action Next State */
+ /* MCA_DCB_API_CLOSE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+ /* MCA_DCB_API_WRITE_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+ /* MCA_DCB_TC_OPEN_EVT */ {MCA_DCB_TC_OPEN, MCA_DCB_OPEN_ST},
+ /* MCA_DCB_TC_CLOSE_EVT */ {MCA_DCB_DEALLOC, MCA_DCB_NULL_ST},
+ /* MCA_DCB_TC_CONG_EVT */ {MCA_DCB_IGNORE, MCA_DCB_CLOSING_ST},
+ /* MCA_DCB_TC_DATA_EVT */ {MCA_DCB_FREE_DATA, MCA_DCB_CLOSING_ST}};
+
+/* type for state table */
+typedef const uint8_t (*tMCA_DCB_ST_TBL)[MCA_DCB_NUM_COLS];
+
+/* state table */
+const tMCA_DCB_ST_TBL mca_dcb_st_tbl[] = {mca_dcb_st_opening, mca_dcb_st_open,
+ mca_dcb_st_closing};
+
+/* verbose event strings for trace */
+const char* const mca_dcb_evt_str[] = {"API_CLOSE_EVT", "API_WRITE_EVT",
+ "TC_OPEN_EVT", "TC_CLOSE_EVT",
+ "TC_CONG_EVT", "TC_DATA_EVT"};
+/* verbose state strings for trace */
+const char* const mca_dcb_st_str[] = {"NULL_ST", "OPENING_ST", "OPEN_ST",
+ "CLOSING_ST"};
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_event
+ *
+ * Description This function is the DCB state machine main function.
+ * It uses the state and action function tables to execute
+ * action functions.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_event(tMCA_DCB* p_dcb, uint8_t event, tMCA_DCB_EVT* p_data) {
+ tMCA_DCB_ST_TBL state_table;
+ uint8_t action;
+
+ if (p_dcb == NULL) return;
+ MCA_TRACE_EVENT("DCB dcb=%d event=%s state=%s", mca_dcb_to_hdl(p_dcb),
+ mca_dcb_evt_str[event], mca_dcb_st_str[p_dcb->state]);
+
+ /* look up the state table for the current state */
+ state_table = mca_dcb_st_tbl[p_dcb->state - 1];
+
+ /* set next state */
+ p_dcb->state = state_table[event][MCA_DCB_NEXT_STATE];
+
+ /* execute action functions */
+ action = state_table[event][MCA_DCB_ACT_COL];
+ if (action != MCA_DCB_IGNORE) {
+ (*mca_dcb_action[action])(p_dcb, p_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_alloc
+ *
+ * Description This function is called to allocate an DCB.
+ * It initializes the DCB with the data passed to the function.
+ *
+ * Returns tMCA_DCB *
+ *
+ ******************************************************************************/
+tMCA_DCB* mca_dcb_alloc(tMCA_CCB* p_ccb, tMCA_DEP dep) {
+ tMCA_DCB *p_dcb = NULL, *p_dcb_tmp;
+ tMCA_RCB* p_rcb = p_ccb->p_rcb;
+ tMCA_CS* p_cs;
+ int i, max;
+
+ if (dep < MCA_NUM_DEPS) {
+ p_cs = &p_rcb->dep[dep];
+ i = mca_ccb_to_hdl(p_ccb) - 1;
+ p_dcb_tmp = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+ max = p_cs->max_mdl;
+ for (i = 0; i < max; i++, p_dcb_tmp++) {
+ if (p_dcb_tmp->state == MCA_DCB_NULL_ST) {
+ p_dcb_tmp->p_ccb = p_ccb;
+ p_dcb_tmp->state = MCA_DCB_OPENING_ST;
+ p_dcb_tmp->cong = true;
+ p_dcb_tmp->p_cs = p_cs;
+ p_dcb = p_dcb_tmp;
+ break;
+ }
+ }
+ }
+ return p_dcb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dep_free_mdl
+ *
+ * Description This function is called to check the number of free mdl for
+ * the given dep.
+ *
+ * Returns the number of free mdl for the given dep
+ *
+ ******************************************************************************/
+uint8_t mca_dep_free_mdl(tMCA_CCB* p_ccb, tMCA_DEP dep) {
+ tMCA_DCB* p_dcb;
+ tMCA_RCB* p_rcb = p_ccb->p_rcb;
+ tMCA_CS* p_cs;
+ int i, max;
+ uint8_t count = 0;
+ uint8_t left;
+
+ if (dep < MCA_NUM_DEPS) {
+ p_cs = &p_rcb->dep[dep];
+ i = mca_ccb_to_hdl(p_ccb) - 1;
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ /* make sure p_cs->max_mdl is smaller than MCA_NUM_MDLS at MCA_CreateDep */
+ max = p_cs->max_mdl;
+ for (i = 0; i < max; i++, p_dcb++) {
+ if ((p_dcb->state != MCA_DCB_NULL_ST) && (p_dcb->p_cs == p_cs)) {
+ count++;
+ break;
+ }
+ }
+ } else {
+ max = 0;
+ MCA_TRACE_WARNING("Invalid Dep ID");
+ }
+ left = max - count;
+ return left;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_dealloc
+ *
+ * Description This function deallocates an DCB.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_dcb_dealloc(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data) {
+ tMCA_CCB* p_ccb = p_dcb->p_ccb;
+ uint8_t event = MCA_CLOSE_IND_EVT;
+ tMCA_CTRL evt_data;
+
+ MCA_TRACE_DEBUG("mca_dcb_dealloc");
+ osi_free_and_reset((void**)&p_dcb->p_data);
+ if (p_data) {
+ /* non-NULL -> an action function -> report disconnect event */
+ evt_data.close_cfm.mdl = mca_dcb_to_hdl(p_dcb);
+ evt_data.close_cfm.reason = p_data->close.reason;
+ evt_data.close_cfm.mdl_id = p_dcb->mdl_id;
+ if (p_data->close.param == MCA_INT) event = MCA_CLOSE_CFM_EVT;
+ if (p_data->close.lcid) mca_ccb_report_event(p_ccb, event, &evt_data);
+ }
+ mca_free_tc_tbl_by_lcid(p_dcb->lcid);
+ memset(p_dcb, 0, sizeof(tMCA_DCB));
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_to_hdl
+ *
+ * Description Convert a pointer to a DCB to a handle (tMCA_DL).
+ * It returns the handle.
+ *
+ * Returns tMCA_DL.
+ *
+ ******************************************************************************/
+tMCA_DL mca_dcb_to_hdl(tMCA_DCB* p_dcb) {
+ return (uint8_t)(p_dcb - mca_cb.dcb + 1);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_by_hdl
+ *
+ * Description This function finds the DCB for a handle (tMCA_DL).
+ * It returns a pointer to the DCB.
+ * If no DCB matches the handle it returns NULL.
+ *
+ * Returns tMCA_DCB *
+ *
+ ******************************************************************************/
+tMCA_DCB* mca_dcb_by_hdl(tMCA_DL hdl) {
+ tMCA_DCB* p_dcb = NULL;
+ if (hdl && hdl <= MCA_NUM_DCBS && mca_cb.dcb[hdl - 1].state)
+ p_dcb = &mca_cb.dcb[hdl - 1];
+ return p_dcb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_dcb_close_by_mdl_id
+ *
+ * Description This function finds the DCB for a mdl_id and
+ * disconnect the mdl
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_dcb_close_by_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id) {
+ tMCA_DCB* p_dcb;
+ int i;
+
+ MCA_TRACE_DEBUG("mca_dcb_close_by_mdl_id mdl_id=%d", mdl_id);
+ i = mca_ccb_to_hdl(p_ccb) - 1;
+ p_dcb = &mca_cb.dcb[i * MCA_NUM_MDLS];
+ for (i = 0; i < MCA_NUM_MDLS; i++, p_dcb++) {
+ if (p_dcb->state) {
+ if (p_dcb->mdl_id == mdl_id) {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ break;
+ } else if (mdl_id == MCA_ALL_MDL_ID) {
+ mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
+ }
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_int.h b/mtkbt/code/bt/stack/mcap/mca_int.h
new file mode 100755
index 0000000..b2e449b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_int.h
@@ -0,0 +1,370 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains interfaces which are internal to MCAP.
+ *
+ ******************************************************************************/
+#ifndef MCA_INT_H
+#define MCA_INT_H
+#include "bt_common.h"
+#include "mca_api.h"
+#include "osi/include/alarm.h"
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* INT initiates the L2CAP channel */
+#define MCA_ACP 0
+#define MCA_INT 1
+
+/*****************************************************************************
+ * Type Definitions
+ ****************************************************************************/
+
+/* Header structure for api/received request/response. */
+typedef struct {
+ BT_HDR hdr; /* layer specific information */
+ uint8_t op_code; /* the request/response opcode */
+ uint8_t rsp_code; /* valid only if op_code is a response */
+ uint16_t mdl_id; /* the MDL ID associated with this request/response */
+ uint8_t param; /* other parameter */
+ uint8_t mdep_id; /* the MDEP ID associated with this request/response */
+ /* tMCA_HANDLE rcb_idx; For internal use only */
+ /* tMCA_CL ccb_idx; For internal use only */
+ tMCA_DL dcb_idx; /* For internal use only */
+} tMCA_CCB_MSG;
+
+/* This data structure is for AVDT_OPEN_IND_EVT and AVDT_OPEN_CFM_EVT. */
+typedef struct {
+ BT_HDR hdr; /* Event header */
+ uint16_t peer_mtu; /* Transport channel L2CAP MTU of the peer */
+ uint16_t lcid; /* L2CAP LCID */
+ uint8_t param;
+} tMCA_OPEN;
+
+typedef struct {
+ uint16_t reason; /* disconnect reason from L2CAP */
+ uint8_t param; /* MCA_INT or MCA_ACP */
+ uint16_t lcid; /* L2CAP LCID */
+} tMCA_CLOSE;
+
+/* Header structure for state machine event parameters. */
+typedef union {
+ BT_HDR hdr; /* layer specific information */
+ tMCA_CCB_MSG api;
+ bool llcong;
+ uint8_t param;
+ tMCA_OPEN open;
+ tMCA_CLOSE close;
+} tMCA_CCB_EVT;
+
+/* control channel states */
+enum {
+ MCA_CCB_NULL_ST, /* not allocated */
+ MCA_CCB_OPENING_ST,
+ MCA_CCB_OPEN_ST, /* open */
+ MCA_CCB_CLOSING_ST, /* disconnecting */
+ MCA_CCB_MAX_ST
+};
+typedef uint8_t tMCA_CCB_STATE;
+
+/* control channel events */
+enum {
+ MCA_CCB_API_CONNECT_EVT, /* application initiates a connect request. */
+ MCA_CCB_API_DISCONNECT_EVT, /* application initiates a disconnect request. */
+ MCA_CCB_API_REQ_EVT, /* application initiates a request. The request may be
+ create_mdl, delete_mdl, reconnect_mdl or abort_mdl. */
+ MCA_CCB_API_RSP_EVT, /* application initiates a create_mdl or reconnect_mdl
+ response. */
+ MCA_CCB_MSG_REQ_EVT, /* a create_mdl, delete_mdl, reconnect_mdl or abort_mdl
+ request message is received from the peer. */
+ MCA_CCB_MSG_RSP_EVT, /* Response received event. This event is sent whenever
+ a response message is received for an outstanding
+ request message. */
+ MCA_CCB_DL_OPEN_EVT, /* data channel open. */
+ MCA_CCB_LL_OPEN_EVT, /* Lower layer open. This event is sent when the lower
+ layer channel is open. */
+ MCA_CCB_LL_CLOSE_EVT, /* Lower layer close. This event is sent when the lower
+ layer channel is closed. */
+ MCA_CCB_LL_CONG_EVT, /* Lower layer congestion. This event is sent when the
+ lower layer is congested. */
+ MCA_CCB_RSP_TOUT_EVT /* time out for waiting the message response on the
+ control channel */
+};
+
+/* Header structure for callback event parameters. */
+typedef union {
+ tMCA_OPEN open;
+ tMCA_CLOSE close;
+ BT_HDR hdr; /* layer specific information */
+ BT_HDR* p_pkt;
+ bool llcong;
+ uint16_t mdl_id; /* the MDL ID associated with this request/response */
+
+ /* tMCA_HANDLE rcb_idx; For internal use only */
+ /* tMCA_CL ccb_idx; For internal use only */
+ /* tMCA_DL dcb_idx; For internal use only */
+} tMCA_DCB_EVT;
+
+/* data channel states */
+enum {
+ MCA_DCB_NULL_ST, /* not allocated */
+ MCA_DCB_OPENING_ST, /* create/reconnect sequence is successful, waiting for
+ data channel connection */
+ MCA_DCB_OPEN_ST, /* open */
+ MCA_DCB_CLOSING_ST, /* disconnecting */
+ MCA_DCB_MAX_ST
+};
+typedef uint8_t tMCA_DCB_STATE;
+
+/* data channel events */
+enum {
+ MCA_DCB_API_CLOSE_EVT, /* This event is sent when the application wants to
+ disconnect the data channel.*/
+ MCA_DCB_API_WRITE_EVT, /* This event is sent when the application wants to
+ send a data packet to the peer.*/
+ MCA_DCB_TC_OPEN_EVT, /* Transport Channel open. This event is sent when the
+ channel is open.*/
+ MCA_DCB_TC_CLOSE_EVT, /* Transport Channel close.*/
+ MCA_DCB_TC_CONG_EVT, /* Transport Channel congestion status.*/
+ MCA_DCB_TC_DATA_EVT /* This event is sent when a data packet is received from
+ the peer.*/
+};
+
+/* "states" used in transport channel table */
+#define MCA_TC_ST_UNUSED 0 /* Unused - unallocated */
+#define MCA_TC_ST_IDLE 1 /* No connection */
+#define MCA_TC_ST_ACP 2 /* Waiting to accept a connection */
+#define MCA_TC_ST_INT 3 /* Initiating a connection */
+#define MCA_TC_ST_CONN 4 /* Waiting for connection confirm */
+#define MCA_TC_ST_CFG 5 /* Waiting for configuration complete */
+#define MCA_TC_ST_OPEN 6 /* Channel opened */
+#define MCA_TC_ST_SEC_INT 7 /* Security process as INT */
+#define MCA_TC_ST_SEC_ACP 8 /* Security process as ACP */
+
+/* Configuration flags. tMCA_TC_TBL.cfg_flags */
+#define MCA_L2C_CFG_IND_DONE (1 << 0)
+#define MCA_L2C_CFG_CFM_DONE (1 << 1)
+#define MCA_L2C_CFG_CONN_INT (1 << 2)
+#define MCA_L2C_CFG_CONN_ACP (1 << 3)
+#define MCA_L2C_CFG_DISCN_INT (1 << 4)
+#define MCA_L2C_CFG_DISCN_ACP (1 << 5)
+
+#define MCA_CTRL_TCID 0 /* to identify control channel by tMCA_TC_TBL.tcid */
+
+/* transport channel table */
+typedef struct {
+ uint16_t peer_mtu; /* L2CAP mtu of the peer device */
+ uint16_t my_mtu; /* Our MTU for this channel */
+ uint16_t lcid; /* L2CAP LCID */
+ uint8_t tcid; /* transport channel id (0, for control channel. (MDEP ID + 1)
+ for data channel) */
+ tMCA_DL cb_idx; /* 1-based index to ccb or dcb */
+ uint8_t state; /* transport channel state */
+ uint8_t cfg_flags; /* L2CAP configuration flags */
+ uint8_t id; /* L2CAP id sent by peer device (need this to handle security
+ pending) */
+} tMCA_TC_TBL;
+
+/* transport control block */
+typedef struct {
+ tMCA_TC_TBL tc_tbl[MCA_NUM_TC_TBL];
+ uint8_t lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */
+} tMCA_TC;
+
+/* registration control block */
+typedef struct {
+ tMCA_REG reg; /* the parameter at register */
+ tMCA_CS dep[MCA_NUM_DEPS]; /* the registration info for each MDEP */
+ tMCA_CTRL_CBACK* p_cback; /* control callback function */
+} tMCA_RCB;
+
+enum {
+ MCA_CCB_STAT_NORM, /* normal operation (based on ccb state) */
+ MCA_CCB_STAT_PENDING, /* waiting for data channel */
+ MCA_CCB_STAT_RECONN, /* reinitiate connection after transitioning from CLOSING
+ to IDLE state */
+ MCA_CCB_STAT_DISC /* MCA_DisconnectReq or MCA_Deregister is called. waiting
+ for all associated CL and DL to detach */
+};
+typedef uint8_t tMCA_CCB_STAT;
+
+/* control channel control block */
+/* the ccbs association with the rcbs
+ * ccb[0] ...ccb[MCA_NUM_LINKS*1-1] -> rcb[0]
+ * ccb[MCA_NUM_LINKS*1]...ccb[MCA_NUM_LINKS*2-1] -> rcb[1]
+ * ccb[MCA_NUM_LINKS*2]...ccb[MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+ tMCA_RCB* p_rcb; /* the associated registration control block */
+ alarm_t* mca_ccb_timer; /* MCA CCB timer entry */
+ tMCA_CCB_MSG* p_tx_req; /* Current request being sent/awaiting response */
+ tMCA_CCB_MSG* p_rx_msg; /* Current message received/being processed */
+ BD_ADDR peer_addr; /* BD address of peer */
+ uint16_t sec_mask; /* Security mask for connections as initiator */
+ uint16_t ctrl_vpsm; /* The virtual PSM that peer is listening for control
+ channel */
+ uint16_t
+ data_vpsm; /* The virtual PSM that peer is listening for data channel. */
+ uint16_t lcid; /* L2CAP lcid for this control channel */
+ uint8_t state; /* The CCB state machine state */
+ bool cong; /* Whether control channel is congested */
+ tMCA_CCB_STAT status; /* see tMCA_CCB_STAT */
+} tMCA_CCB;
+typedef void (*tMCA_CCB_ACTION)(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+
+enum {
+ MCA_DCB_STAT_NORM, /* normal operation (based on dcb state) */
+ MCA_DCB_STAT_DEL, /* MCA_Delete is called. waiting for the DL to detach */
+ MCA_DCB_STAT_DISC /* MCA_CloseReq is called. waiting for the DL to detach */
+};
+typedef uint8_t tMCA_DCB_STAT;
+
+/* data channel control block */
+/* the dcbs association with the ccbs
+ * dcb[0] ...dcb[MCA_NUM_MDLS*1-1] -> ccb[0]
+ * dcb[MCA_NUM_MDLS*1]...dcb[MCA_NUM_MDLS*2-1] -> ccb[1]
+ * dcb[MCA_NUM_MDLS*2]...dcb[MCA_NUM_MDLS*3-1] -> ccb[2]
+ *
+ * the dcbs association with the rcbs
+ * dcb[0]
+ * ...dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1-1] -> rcb[0]
+ * dcb[MCA_NUM_MDLS*1*MCA_NUM_LINKS*1]
+ * ...dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2-1] -> rcb[1]
+ * dcb[MCA_NUM_MDLS*2*MCA_NUM_LINKS*2]
+ * ...dcb[MCA_NUM_MDLS*3*MCA_NUM_LINKS*3-1] -> rcb[2]
+ */
+typedef struct {
+ tMCA_CCB* p_ccb; /* the associated control control block */
+ BT_HDR* p_data; /* data packet held due to L2CAP channel congestion */
+ tMCA_CS* p_cs; /* the associated MDEP info. p_cs->type is the mdep id(internal
+ use) */
+ const tMCA_CHNL_CFG* p_chnl_cfg; /* cfg params for L2CAP channel */
+ uint16_t mdl_id; /* the MDL ID for this data channel */
+ uint16_t lcid; /* L2CAP lcid */
+ uint8_t state; /* The DCB state machine state */
+ bool cong; /* Whether data channel is congested */
+ tMCA_DCB_STAT status; /* see tMCA_DCB_STAT */
+} tMCA_DCB;
+
+typedef void (*tMCA_DCB_ACTION)(tMCA_DCB* p_ccb, tMCA_DCB_EVT* p_data);
+
+/* Control block for MCA */
+typedef struct {
+ tMCA_RCB rcb[MCA_NUM_REGS]; /* registration control block */
+ tMCA_CCB ccb[MCA_NUM_CCBS]; /* control channel control blocks */
+ tMCA_DCB dcb[MCA_NUM_DCBS]; /* data channel control blocks */
+ tMCA_TC tc; /* transport control block */
+ uint8_t trace_level; /* trace level */
+} tMCA_CB;
+
+/* csm functions */
+extern void mca_ccb_event(tMCA_CCB* p_ccb, uint8_t event, tMCA_CCB_EVT* p_data);
+extern tMCA_CCB* mca_ccb_by_bd(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern tMCA_CCB* mca_ccb_alloc(tMCA_HANDLE handle, BD_ADDR bd_addr);
+extern void mca_ccb_rsp_tout(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_dealloc(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern tMCA_CL mca_ccb_to_hdl(tMCA_CCB* p_ccb);
+extern tMCA_CCB* mca_ccb_by_hdl(tMCA_CL mcl);
+extern bool mca_ccb_uses_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id);
+
+/* cact functions */
+extern void mca_ccb_report_event(tMCA_CCB* p_ccb, uint8_t event,
+ tMCA_CTRL* p_data);
+extern void mca_ccb_free_msg(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_snd_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_snd_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_do_disconn(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_cong(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_hdl_req(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_hdl_rsp(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_ll_open(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+extern void mca_ccb_dl_open(tMCA_CCB* p_ccb, tMCA_CCB_EVT* p_data);
+
+/* dsm functions */
+extern void mca_dcb_event(tMCA_DCB* p_dcb, uint8_t event, tMCA_DCB_EVT* p_data);
+extern tMCA_DCB* mca_dcb_alloc(tMCA_CCB* p_ccb, tMCA_DEP dep);
+extern uint8_t mca_dep_free_mdl(tMCA_CCB* p_ccb, tMCA_DEP dep);
+extern void mca_dcb_dealloc(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern tMCA_DL mca_dcb_to_hdl(tMCA_DCB* p_dcb);
+extern tMCA_DCB* mca_dcb_by_hdl(tMCA_DL hdl);
+extern void mca_dcb_close_by_mdl_id(tMCA_CCB* p_ccb, uint16_t mdl_id);
+
+/* dact functions */
+extern void mca_dcb_tc_open(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern void mca_dcb_cong(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern void mca_dcb_free_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern void mca_dcb_do_disconn(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern void mca_dcb_snd_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+extern void mca_dcb_hdl_data(tMCA_DCB* p_dcb, tMCA_DCB_EVT* p_data);
+
+/* main/utils functions */
+extern tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm);
+extern tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm);
+extern tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb);
+extern tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb);
+extern tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid);
+extern void mca_free_tc_tbl_by_lcid(uint16_t lcid);
+extern void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl);
+extern void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason);
+extern void mca_tc_open_ind(tMCA_TC_TBL* p_tbl);
+extern void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested);
+extern void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf);
+extern tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg);
+extern void mca_rcb_dealloc(tMCA_HANDLE handle);
+extern tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb);
+extern tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle);
+extern bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep);
+extern void mca_ccb_timer_timeout(void* data);
+extern void mca_stop_timer(tMCA_CCB* p_ccb);
+
+/* l2c functions */
+extern uint16_t mca_l2c_open_req(BD_ADDR bd_addr, uint16_t PSM,
+ const tMCA_CHNL_CFG* p_chnl_cfg);
+
+/* callback function declarations */
+extern void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ uint16_t psm, uint8_t id);
+extern void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid,
+ uint16_t psm, uint8_t id);
+extern void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result);
+extern void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+extern void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+extern void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed);
+extern void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result);
+extern void mca_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested);
+extern void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf);
+
+/*****************************************************************************
+ * global data
+ ****************************************************************************/
+
+/******************************************************************************
+ * Main Control Block
+ ******************************************************************************/
+extern tMCA_CB mca_cb;
+
+/* L2CAP callback registration structure */
+extern const tL2CAP_APPL_INFO mca_l2c_int_appl;
+extern const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def;
+extern const uint8_t mca_std_msg_len[];
+
+#endif /* MCA_INT_H */
diff --git a/mtkbt/code/bt/stack/mcap/mca_l2c.cc b/mtkbt/code/bt/stack/mcap/mca_l2c.cc
new file mode 100755
index 0000000..fc08776
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_l2c.cc
@@ -0,0 +1,538 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP at L2CAP Interface.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+#include "osi/include/osi.h"
+
+/* L2CAP callback function structure */
+const tL2CAP_APPL_INFO mca_l2c_int_appl = {NULL,
+ mca_l2c_connect_cfm_cback,
+ NULL,
+ mca_l2c_config_ind_cback,
+ mca_l2c_config_cfm_cback,
+ mca_l2c_disconnect_ind_cback,
+ mca_l2c_disconnect_cfm_cback,
+ NULL,
+ mca_l2c_data_ind_cback,
+ mca_l2c_congestion_ind_cback,
+ NULL};
+
+/* Control channel eL2CAP default options */
+const tL2CAP_FCR_OPTS mca_l2c_fcr_opts_def = {
+ L2CAP_FCR_ERTM_MODE, /* Mandatory for MCAP */
+ MCA_FCR_OPT_TX_WINDOW_SIZE, /* Tx window size */
+ MCA_FCR_OPT_MAX_TX_B4_DISCNT, /* Maximum transmissions before
+ disconnecting */
+ MCA_FCR_OPT_RETX_TOUT, /* Retransmission timeout (2 secs) */
+ MCA_FCR_OPT_MONITOR_TOUT, /* Monitor timeout (12 secs) */
+ MCA_FCR_OPT_MPS_SIZE /* MPS segment size */
+};
+
+/*******************************************************************************
+ *
+ * Function mca_sec_check_complete_term
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void mca_sec_check_complete_term(BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
+ tL2CAP_CFG_INFO cfg;
+ tL2CAP_ERTM_INFO ertm_info;
+
+ MCA_TRACE_DEBUG("mca_sec_check_complete_term res: %d", res);
+
+ if (res == BTM_SUCCESS) {
+ MCA_TRACE_DEBUG("lcid:x%x id:x%x", p_tbl->lcid, p_tbl->id);
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
+ ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
+ ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
+ ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
+ /* Send response to the L2CAP layer. */
+ L2CA_ErtmConnectRsp(bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK,
+ L2CAP_CONN_OK, &ertm_info);
+
+ /* transition to configuration state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl(&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ } else {
+ L2CA_ConnectRsp(bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK,
+ L2CAP_CONN_OK);
+ mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_sec_check_complete_orig
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void mca_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tMCA_TC_TBL* p_tbl = (tMCA_TC_TBL*)p_ref_data;
+ tL2CAP_CFG_INFO cfg;
+
+ MCA_TRACE_DEBUG("mca_sec_check_complete_orig res: %d", res);
+
+ if (res == BTM_SUCCESS) {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl(&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ } else {
+ L2CA_DisconnectReq(p_tbl->lcid);
+ mca_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
+ }
+}
+/*******************************************************************************
+ *
+ * Function mca_l2c_cconn_ind_cback
+ *
+ * Description This is the L2CAP connect indication callback function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_cconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id) {
+ tMCA_HANDLE handle = mca_handle_by_cpsm(psm);
+ tMCA_CCB* p_ccb;
+ tMCA_TC_TBL* p_tbl = NULL;
+ uint16_t result = L2CAP_CONN_NO_RESOURCES;
+ tBTM_STATUS rc;
+ tL2CAP_ERTM_INFO ertm_info, *p_ertm_info = NULL;
+ tL2CAP_CFG_INFO cfg;
+
+ MCA_TRACE_EVENT("mca_l2c_cconn_ind_cback: lcid:x%x psm:x%x id:x%x", lcid, psm,
+ id);
+
+ /* do we already have a control channel for this peer? */
+ p_ccb = mca_ccb_by_bd(handle, bd_addr);
+ if (p_ccb == NULL) {
+ /* no, allocate ccb */
+ p_ccb = mca_ccb_alloc(handle, bd_addr);
+ if (p_ccb != NULL) {
+ /* allocate and set up entry */
+ p_ccb->lcid = lcid;
+ p_tbl = mca_tc_tbl_calloc(p_ccb);
+ p_tbl->id = id;
+ p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
+ /* proceed with connection */
+ /* Check the security */
+ rc = btm_sec_mx_access_request(bd_addr, psm, false, BTM_SEC_PROTO_MCA, 0,
+ &mca_sec_check_complete_term, p_tbl);
+ if (rc == BTM_CMD_STARTED) {
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
+ ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
+ ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
+ ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
+ p_ertm_info = &ertm_info;
+ result = L2CAP_CONN_PENDING;
+ } else
+ result = L2CAP_CONN_OK;
+ }
+
+ /* deal with simultaneous control channel connect case */
+ }
+ /* else reject their connection */
+
+ if (!p_tbl || (p_tbl->state != MCA_TC_ST_CFG)) {
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, L2CAP_CONN_OK, p_ertm_info);
+
+ /* if result ok, proceed with connection and send L2CAP
+ config req */
+ if (result == L2CAP_CONN_OK) {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl(&cfg, p_tbl);
+ L2CA_ConfigReq(p_tbl->lcid, &cfg);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_dconn_ind_cback
+ *
+ * Description This is the L2CAP connect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_dconn_ind_cback(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id) {
+ tMCA_HANDLE handle = mca_handle_by_dpsm(psm);
+ tMCA_CCB* p_ccb;
+ tMCA_DCB* p_dcb;
+ tMCA_TC_TBL* p_tbl = NULL;
+ uint16_t result;
+ tL2CAP_CFG_INFO cfg;
+ tL2CAP_ERTM_INFO *p_ertm_info = NULL, ertm_info;
+ const tMCA_CHNL_CFG* p_chnl_cfg;
+
+ MCA_TRACE_EVENT("mca_l2c_dconn_ind_cback: lcid:x%x psm:x%x ", lcid, psm);
+
+ if (((p_ccb = mca_ccb_by_bd(handle, bd_addr)) != NULL) && /* find the CCB */
+ (p_ccb->status ==
+ MCA_CCB_STAT_PENDING) && /* this CCB is expecting a MDL */
+ (p_ccb->p_tx_req &&
+ (p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL)) {
+ /* found the associated dcb in listening mode */
+ /* proceed with connection */
+ p_dcb->lcid = lcid;
+ p_tbl = mca_tc_tbl_dalloc(p_dcb);
+ p_tbl->id = id;
+ p_tbl->cfg_flags = MCA_L2C_CFG_CONN_ACP;
+ p_chnl_cfg = p_dcb->p_chnl_cfg;
+ /* assume that control channel has verified the security requirement */
+ /* Set the FCR options: control channel mandates ERTM */
+ ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
+ ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
+ ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
+ ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
+ ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
+ ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
+ p_ertm_info = &ertm_info;
+ result = L2CAP_CONN_OK;
+ } else {
+ /* else we're not listening for traffic channel; reject
+ * (this error code is specified by MCAP spec) */
+ result = L2CAP_CONN_NO_RESOURCES;
+ }
+
+ /* Send L2CAP connect rsp */
+ L2CA_ErtmConnectRsp(bd_addr, id, lcid, result, result, p_ertm_info);
+
+ /* if result ok, proceed with connection */
+ if (result == L2CAP_CONN_OK) {
+ /* transition to configuration state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl(&cfg, p_tbl);
+ L2CA_ConfigReq(lcid, &cfg);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_connect_cfm_cback
+ *
+ * Description This is the L2CAP connect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_connect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tMCA_TC_TBL* p_tbl;
+ tL2CAP_CFG_INFO cfg;
+ tMCA_CCB* p_ccb;
+
+ MCA_TRACE_DEBUG("mca_l2c_connect_cfm_cback lcid: x%x, result: %d", lcid,
+ result);
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ MCA_TRACE_DEBUG("p_tbl state: %d, tcid: %d", p_tbl->state, p_tbl->tcid);
+ /* if in correct state */
+ if (p_tbl->state == MCA_TC_ST_CONN) {
+ /* if result successful */
+ if (result == L2CAP_CONN_OK) {
+ if (p_tbl->tcid != 0) {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_CFG;
+
+ /* Send L2CAP config req */
+ mca_set_cfg_by_tbl(&cfg, p_tbl);
+ L2CA_ConfigReq(lcid, &cfg);
+ } else {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ if (p_ccb == NULL) {
+ result = L2CAP_CONN_NO_RESOURCES;
+ } else {
+ /* set channel state */
+ p_tbl->state = MCA_TC_ST_SEC_INT;
+ p_tbl->lcid = lcid;
+ p_tbl->cfg_flags = MCA_L2C_CFG_CONN_INT;
+
+ /* Check the security */
+ btm_sec_mx_access_request(p_ccb->peer_addr, p_ccb->ctrl_vpsm, true,
+ BTM_SEC_PROTO_MCA, p_tbl->tcid,
+ &mca_sec_check_complete_orig, p_tbl);
+ }
+ }
+ }
+
+ /* failure; notify adaption that channel closed */
+ if (result != L2CAP_CONN_OK) {
+ p_tbl->cfg_flags |= MCA_L2C_CFG_DISCN_INT;
+ mca_tc_close_ind(p_tbl, result);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_config_cfm_cback
+ *
+ * Description This is the L2CAP config confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_config_cfm_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tMCA_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ /* if in correct state */
+ if (p_tbl->state == MCA_TC_ST_CFG) {
+ /* if result successful */
+ if (p_cfg->result == L2CAP_CONN_OK) {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= MCA_L2C_CFG_CFM_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) {
+ mca_tc_open_ind(p_tbl);
+ }
+ }
+ /* else failure */
+ else {
+ /* Send L2CAP disconnect req */
+ L2CA_DisconnectReq(lcid);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_config_ind_cback
+ *
+ * Description This is the L2CAP config indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_config_ind_cback(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tMCA_TC_TBL* p_tbl;
+ uint16_t result = L2CAP_CFG_OK;
+
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ /* store the mtu in tbl */
+ if (p_cfg->mtu_present) {
+ p_tbl->peer_mtu = p_cfg->mtu;
+ if (p_tbl->peer_mtu < MCA_MIN_MTU) {
+ result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ }
+ } else {
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ }
+ MCA_TRACE_DEBUG("peer_mtu: %d, lcid: x%x mtu_present:%d", p_tbl->peer_mtu,
+ lcid, p_cfg->mtu_present);
+
+ /* send L2CAP configure response */
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->result = result;
+ L2CA_ConfigRsp(lcid, p_cfg);
+
+ /* if first config ind */
+ if ((p_tbl->cfg_flags & MCA_L2C_CFG_IND_DONE) == 0) {
+ /* update cfg_flags */
+ p_tbl->cfg_flags |= MCA_L2C_CFG_IND_DONE;
+
+ /* if configuration complete */
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_CFM_DONE) {
+ mca_tc_open_ind(p_tbl);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_disconnect_ind_cback
+ *
+ * Description This is the L2CAP disconnect indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_disconnect_ind_cback(uint16_t lcid, bool ack_needed) {
+ tMCA_TC_TBL* p_tbl;
+ uint16_t reason = L2CAP_DISC_TIMEOUT;
+
+ MCA_TRACE_DEBUG("mca_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d", lcid,
+ ack_needed);
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ if (ack_needed) {
+ /* send L2CAP disconnect response */
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_ACP;
+ if (ack_needed) reason = L2CAP_DISC_OK;
+ mca_tc_close_ind(p_tbl, reason);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_disconnect_cfm_cback
+ *
+ * Description This is the L2CAP disconnect confirm callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_disconnect_cfm_cback(uint16_t lcid, uint16_t result) {
+ tMCA_TC_TBL* p_tbl;
+
+ MCA_TRACE_DEBUG("mca_l2c_disconnect_cfm_cback lcid: x%x, result: %d", lcid,
+ result);
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ p_tbl->cfg_flags = MCA_L2C_CFG_DISCN_INT;
+ mca_tc_close_ind(p_tbl, result);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_congestion_ind_cback
+ *
+ * Description This is the L2CAP congestion indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_congestion_ind_cback(uint16_t lcid, bool is_congested) {
+ tMCA_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ mca_tc_cong_ind(p_tbl, is_congested);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_data_ind_cback
+ *
+ * Description This is the L2CAP data indication callback function.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void mca_l2c_data_ind_cback(uint16_t lcid, BT_HDR* p_buf) {
+ tMCA_TC_TBL* p_tbl;
+
+ /* look up info for this channel */
+ p_tbl = mca_tc_tbl_by_lcid(lcid);
+ if (p_tbl != NULL) {
+ mca_tc_data_ind(p_tbl, p_buf);
+ } else /* prevent buffer leak */
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_l2c_open_req
+ *
+ * Description This function calls L2CA_ConnectReq() to initiate a L2CAP
+ * channel.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+uint16_t mca_l2c_open_req(BD_ADDR bd_addr, uint16_t psm,
+ const tMCA_CHNL_CFG* p_chnl_cfg) {
+ tL2CAP_ERTM_INFO ertm_info;
+
+ if (p_chnl_cfg) {
+ ertm_info.preferred_mode = p_chnl_cfg->fcr_opt.mode;
+ ertm_info.allowed_modes = (1 << p_chnl_cfg->fcr_opt.mode);
+ ertm_info.user_rx_buf_size = p_chnl_cfg->user_rx_buf_size;
+ ertm_info.user_tx_buf_size = p_chnl_cfg->user_tx_buf_size;
+ ertm_info.fcr_rx_buf_size = p_chnl_cfg->fcr_rx_buf_size;
+ ertm_info.fcr_tx_buf_size = p_chnl_cfg->fcr_tx_buf_size;
+ } else {
+ ertm_info.preferred_mode = mca_l2c_fcr_opts_def.mode;
+ ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
+ ertm_info.user_rx_buf_size = MCA_USER_RX_BUF_SIZE;
+ ertm_info.user_tx_buf_size = MCA_USER_TX_BUF_SIZE;
+ ertm_info.fcr_rx_buf_size = MCA_FCR_RX_BUF_SIZE;
+ ertm_info.fcr_tx_buf_size = MCA_FCR_TX_BUF_SIZE;
+ }
+ return L2CA_ErtmConnectReq(psm, bd_addr, &ertm_info);
+}
diff --git a/mtkbt/code/bt/stack/mcap/mca_main.cc b/mtkbt/code/bt/stack/mcap/mca_main.cc
new file mode 100755
index 0000000..9f9dbaf
--- a/dev/null
+++ b/mtkbt/code/bt/stack/mcap/mca_main.cc
@@ -0,0 +1,564 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation file for the MCAP Main Control Block and
+ * Utility functions.
+ *
+ ******************************************************************************/
+#include <base/logging.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "l2c_api.h"
+#include "mca_api.h"
+#include "mca_defs.h"
+#include "mca_int.h"
+
+/* Main Control block for MCA */
+tMCA_CB mca_cb;
+
+/*****************************************************************************
+ * constants
+ ****************************************************************************/
+
+/* table of standard opcode message size */
+const uint8_t mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
+ 4, /* MCA_OP_ERROR_RSP */
+ 5, /* MCA_OP_MDL_CREATE_REQ */
+ 5, /* MCA_OP_MDL_CREATE_RSP */
+ 3, /* MCA_OP_MDL_RECONNECT_REQ */
+ 4, /* MCA_OP_MDL_RECONNECT_RSP */
+ 3, /* MCA_OP_MDL_ABORT_REQ */
+ 4, /* MCA_OP_MDL_ABORT_RSP */
+ 3, /* MCA_OP_MDL_DELETE_REQ */
+ 4 /* MCA_OP_MDL_DELETE_RSP */
+};
+
+/*******************************************************************************
+ *
+ * Function mca_handle_by_cpsm
+ *
+ * Description This function returns the handle for the given control
+ * channel PSM. 0, if not found.
+ *
+ * Returns the MCA handle.
+ *
+ ******************************************************************************/
+tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm) {
+ int i;
+ tMCA_HANDLE handle = 0;
+ tMCA_RCB* p_rcb = &mca_cb.rcb[0];
+
+ for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
+ if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm) {
+ handle = i + 1;
+ break;
+ }
+ }
+ return handle;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_handle_by_dpsm
+ *
+ * Description This function returns the handle for the given data
+ * channel PSM. 0, if not found.
+ *
+ * Returns the MCA handle.
+ *
+ ******************************************************************************/
+tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm) {
+ int i;
+ tMCA_HANDLE handle = 0;
+ tMCA_RCB* p_rcb = &mca_cb.rcb[0];
+
+ for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
+ if (p_rcb->p_cback && p_rcb->reg.data_psm == psm) {
+ handle = i + 1;
+ break;
+ }
+ }
+ return handle;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_tbl_calloc
+ *
+ * Description This function allocates a transport table for the given
+ * control channel.
+ *
+ * Returns The tranport table.
+ *
+ ******************************************************************************/
+tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb) {
+ tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
+ int i;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
+ if (p_tbl->state == MCA_TC_ST_UNUSED) {
+ break;
+ }
+ }
+
+ /* sanity check */
+ CHECK(i != MCA_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags = 0;
+ p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb);
+ p_tbl->tcid = MCA_CTRL_TCID;
+ p_tbl->my_mtu = MCA_CTRL_MTU;
+ p_tbl->state = MCA_TC_ST_IDLE;
+ p_tbl->lcid = p_ccb->lcid;
+ mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
+
+ MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
+ return p_tbl;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_tbl_dalloc
+ *
+ * Description This function allocates a transport table for the given
+ * data channel.
+ *
+ * Returns The tranport table.
+ *
+ ******************************************************************************/
+tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb) {
+ tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
+ int i;
+
+ /* find next free entry in tc table */
+ for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
+ if (p_tbl->state == MCA_TC_ST_UNUSED) {
+ break;
+ }
+ }
+
+ /* sanity check */
+ CHECK(i != MCA_NUM_TC_TBL);
+
+ /* initialize entry */
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+ p_tbl->cfg_flags = 0;
+ p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb);
+ p_tbl->tcid = p_dcb->p_cs->type + 1;
+ p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu;
+ p_tbl->state = MCA_TC_ST_IDLE;
+ p_tbl->lcid = p_dcb->lcid;
+ mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
+
+ MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
+ p_tbl->cb_idx);
+ return p_tbl;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_tbl_by_lcid
+ *
+ * Description Find the transport channel table entry by LCID.
+ *
+ *
+ * Returns The tranport table.
+ *
+ ******************************************************************************/
+tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid) {
+ uint8_t idx;
+
+ if (lcid >= L2CAP_BASE_APPL_CID) {
+ idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < MCA_NUM_TC_TBL) {
+ return &mca_cb.tc.tc_tbl[idx];
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_free_tc_tbl_by_lcid
+ *
+ * Description Find the transport table entry by LCID
+ * and free the tc_tbl
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_free_tc_tbl_by_lcid(uint16_t lcid) {
+ uint8_t idx;
+
+ if (lcid >= L2CAP_BASE_APPL_CID) {
+ idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
+
+ if (idx < MCA_NUM_TC_TBL) {
+ mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_set_cfg_by_tbl
+ *
+ * Description Set the L2CAP configuration information
+ *
+ * Returns none.
+ *
+ ******************************************************************************/
+void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl) {
+ tMCA_DCB* p_dcb;
+ const tL2CAP_FCR_OPTS* p_opt;
+ tMCA_FCS_OPT fcs = MCA_FCS_NONE;
+
+ if (p_tbl->tcid == MCA_CTRL_TCID) {
+ p_opt = &mca_l2c_fcr_opts_def;
+ } else {
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb) {
+ p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
+ fcs = p_dcb->p_chnl_cfg->fcs;
+ }
+ }
+ memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
+ p_cfg->mtu_present = true;
+ p_cfg->mtu = p_tbl->my_mtu;
+ p_cfg->fcr_present = true;
+ memcpy(&p_cfg->fcr, p_opt, sizeof(tL2CAP_FCR_OPTS));
+ if (fcs & MCA_FCS_PRESNT_MASK) {
+ p_cfg->fcs_present = true;
+ p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_close_ind
+ *
+ * Description This function is called by the L2CAP interface when the
+ * L2CAP channel is closed. It looks up the CCB or DCB for
+ * the channel and sends it a close event. The reason
+ * parameter is the same value passed by the L2CAP
+ * callback function.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason) {
+ tMCA_CCB* p_ccb;
+ tMCA_DCB* p_dcb;
+ tMCA_CLOSE close;
+
+ close.param = MCA_ACP;
+ close.reason = reason;
+ close.lcid = p_tbl->lcid;
+
+ MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, p_tbl->tcid,
+ p_tbl->cb_idx, p_tbl->state);
+
+ /* Check if the transport channel is in use */
+ if (p_tbl->state == MCA_TC_ST_UNUSED) return;
+
+ /* clear mca_tc_tbl entry */
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_DISCN_INT) close.param = MCA_INT;
+ p_tbl->cfg_flags = 0;
+ p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
+
+ /* if control channel, notify ccb that channel close */
+ if (p_tbl->tcid == MCA_CTRL_TCID) {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, (tMCA_CCB_EVT*)&close);
+ }
+ /* notify dcb that channel close */
+ else {
+ /* look up dcb */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL) {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, (tMCA_DCB_EVT*)&close);
+ }
+ }
+ p_tbl->state = MCA_TC_ST_UNUSED;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_open_ind
+ *
+ * Description This function is called by the L2CAP interface when
+ * the L2CAP channel is opened. It looks up the CCB or DCB
+ * for the channel and sends it an open event.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void mca_tc_open_ind(tMCA_TC_TBL* p_tbl) {
+ tMCA_CCB* p_ccb;
+ tMCA_DCB* p_dcb;
+ tMCA_OPEN open;
+
+ MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid,
+ p_tbl->cb_idx);
+ p_tbl->state = MCA_TC_ST_OPEN;
+
+ open.peer_mtu = p_tbl->peer_mtu;
+ open.lcid = p_tbl->lcid;
+ /* use param to indicate the role of connection.
+ * MCA_ACP, if ACP */
+ open.param = MCA_INT;
+ if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) {
+ open.param = MCA_ACP;
+ }
+
+ /* if control channel, notify ccb that channel open */
+ if (p_tbl->tcid == MCA_CTRL_TCID) {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+
+ mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, (tMCA_CCB_EVT*)&open);
+ }
+ /* must be data channel, notify dcb that channel open */
+ else {
+ /* look up dcb */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+
+ /* put lcid in event data */
+ if (p_dcb != NULL) {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, (tMCA_DCB_EVT*)&open);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_cong_ind
+ *
+ * Description This function is called by the L2CAP interface layer when
+ * L2CAP calls the congestion callback. It looks up the CCB
+ * or DCB for the channel and sends it a congestion event.
+ * The is_congested parameter is the same value passed by
+ * the L2CAP callback function.
+ *
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested) {
+ tMCA_CCB* p_ccb;
+ tMCA_DCB* p_dcb;
+
+ MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
+ p_tbl->cb_idx);
+
+ /* if control channel, notify ccb of congestion */
+ if (p_tbl->tcid == MCA_CTRL_TCID) {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, (tMCA_CCB_EVT*)&is_congested);
+ }
+ /* notify dcb that channel open */
+ else {
+ /* look up dcb by cb_idx */
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL) {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, (tMCA_DCB_EVT*)&is_congested);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_tc_data_ind
+ *
+ * Description This function is called by the L2CAP interface layer when
+ * incoming data is received from L2CAP. It looks up the CCB
+ * or DCB for the channel and routes the data accordingly.
+ *
+ * Returns Nothing.
+ *
+ ******************************************************************************/
+void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf) {
+ tMCA_CCB* p_ccb;
+ tMCA_DCB* p_dcb;
+ uint8_t event = MCA_CCB_MSG_RSP_EVT;
+ uint8_t* p;
+ uint8_t rej_rsp_code = MCA_RSP_SUCCESS;
+
+ MCA_TRACE_DEBUG("%s: tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
+ p_tbl->cb_idx);
+
+ /* if control channel, handle control message */
+ if (p_tbl->tcid == MCA_CTRL_TCID) {
+ p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
+ if (p_ccb) {
+ p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ /* all the request opcode has bit 0 set. response code has bit 0 clear */
+ if ((*p) & 0x01) event = MCA_CCB_MSG_REQ_EVT;
+
+ if (*p < MCA_NUM_STANDARD_OPCODE) {
+ if (p_buf->len != mca_std_msg_len[*p]) {
+ MCA_TRACE_ERROR("%s: opcode 0x%02x required len: %d, got len: %d",
+ __func__, *p, mca_std_msg_len[*p], p_buf->len);
+ rej_rsp_code = MCA_RSP_BAD_PARAM;
+ }
+ } else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) {
+ MCA_TRACE_ERROR("%s: unsupported SYNC opcode: 0x%02x len:%d", __func__,
+ *p, p_buf->len);
+ /* reject unsupported request */
+ rej_rsp_code = MCA_RSP_NO_SUPPORT;
+ } else {
+ MCA_TRACE_ERROR("%s: bad opcode: 0x%02x len:%d", __func__, *p,
+ p_buf->len);
+ /* reject unsupported request */
+ rej_rsp_code = MCA_RSP_BAD_OPCODE;
+ }
+
+ p_buf->layer_specific = rej_rsp_code;
+ /* forward the request/response to state machine */
+ mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf);
+ } /* got a valid ccb */
+ else
+ osi_free(p_buf);
+ }
+ /* else send event to dcb */
+ else {
+ p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
+ if (p_dcb != NULL) {
+ mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf);
+ } else
+ osi_free(p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_rcb_alloc
+ *
+ * Description This function allocates a registration control block.
+ * If no free RCB is available, it returns NULL.
+ *
+ * Returns tMCA_RCB *
+ *
+ ******************************************************************************/
+tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg) {
+ int i;
+ tMCA_RCB* p_rcb = NULL;
+
+ for (i = 0; i < MCA_NUM_REGS; i++) {
+ if (mca_cb.rcb[i].p_cback == NULL) {
+ p_rcb = &mca_cb.rcb[i];
+ memcpy(&p_rcb->reg, p_reg, sizeof(tMCA_REG));
+ break;
+ }
+ }
+ return p_rcb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_rcb_dealloc
+ *
+ * Description This function deallocates the RCB with the given handle.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void mca_rcb_dealloc(tMCA_HANDLE handle) {
+ int i;
+ bool done = true;
+ tMCA_RCB* p_rcb;
+ tMCA_CCB* p_ccb;
+
+ if (handle && (handle <= MCA_NUM_REGS)) {
+ handle--;
+ p_rcb = &mca_cb.rcb[handle];
+ if (p_rcb->p_cback) {
+ p_ccb = &mca_cb.ccb[handle * MCA_NUM_LINKS];
+ /* check if all associated CCB are disconnected */
+ for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb++) {
+ if (p_ccb->p_rcb) {
+ done = false;
+ mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
+ }
+ }
+
+ if (done) {
+ memset(p_rcb, 0, sizeof(tMCA_RCB));
+ MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function mca_rcb_to_handle
+ *
+ * Description This function converts a pointer to an RCB to
+ * a handle (tMCA_HANDLE). It returns the handle.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb) {
+ return (uint8_t)(p_rcb - mca_cb.rcb + 1);
+}
+
+/*******************************************************************************
+ *
+ * Function mca_rcb_by_handle
+ *
+ * Description This function finds the RCB for a handle (tMCA_HANDLE).
+ * It returns a pointer to the RCB. If no RCB matches the
+ * handle it returns NULL.
+ *
+ * Returns tMCA_RCB *
+ *
+ ******************************************************************************/
+tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle) {
+ tMCA_RCB* p_rcb = NULL;
+
+ if (handle && (handle <= MCA_NUM_REGS) && mca_cb.rcb[handle - 1].p_cback) {
+ p_rcb = &mca_cb.rcb[handle - 1];
+ }
+ return p_rcb;
+}
+
+/*******************************************************************************
+ *
+ * Function mca_is_valid_dep_id
+ *
+ * Description This function checks if the given dep_id is valid.
+ *
+ * Returns true, if this is a valid local dep_id
+ *
+ ******************************************************************************/
+bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep) {
+ bool valid = false;
+ if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
+ valid = true;
+ }
+ return valid;
+}
diff --git a/mtkbt/code/bt/stack/pan/pan_api.cc b/mtkbt/code/bt/stack/pan/pan_api.cc
new file mode 100755
index 0000000..997d7c9
--- a/dev/null
+++ b/mtkbt/code/bt/stack/pan/pan_api.cc
@@ -0,0 +1,704 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains main functions to support PAN profile
+ * commands and events.
+ *
+ *****************************************************************************/
+
+#include "pan_api.h"
+#include <string.h>
+#include "bnep_api.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bta_sys.h"
+#include "btm_api.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+
+/*******************************************************************************
+ *
+ * Function PAN_Register
+ *
+ * Description This function is called by the application to register
+ * its callbacks with PAN profile. The application then
+ * should set the PAN role explicitly.
+ *
+ * Parameters: p_register - contains all callback function pointers
+ *
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void PAN_Register(tPAN_REGISTER* p_register) {
+ BTM_SetDiscoverability(BTM_GENERAL_DISCOVERABLE, 0, 0);
+ BTM_SetConnectability(BTM_CONNECTABLE, 0, 0);
+
+ pan_register_with_bnep();
+
+ if (!p_register) return;
+
+ pan_cb.pan_conn_state_cb = p_register->pan_conn_state_cb;
+ pan_cb.pan_bridge_req_cb = p_register->pan_bridge_req_cb;
+ pan_cb.pan_data_buf_ind_cb = p_register->pan_data_buf_ind_cb;
+ pan_cb.pan_data_ind_cb = p_register->pan_data_ind_cb;
+ pan_cb.pan_pfilt_ind_cb = p_register->pan_pfilt_ind_cb;
+ pan_cb.pan_mfilt_ind_cb = p_register->pan_mfilt_ind_cb;
+ pan_cb.pan_tx_data_flow_cb = p_register->pan_tx_data_flow_cb;
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_Deregister
+ *
+ * Description This function is called by the application to de-register
+ * its callbacks with PAN profile. This will make the PAN to
+ * become inactive. This will deregister PAN services from SDP
+ * and close all active connections
+ *
+ * Parameters: none
+ *
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void PAN_Deregister(void) {
+ pan_cb.pan_bridge_req_cb = NULL;
+ pan_cb.pan_data_buf_ind_cb = NULL;
+ pan_cb.pan_data_ind_cb = NULL;
+ pan_cb.pan_conn_state_cb = NULL;
+ pan_cb.pan_pfilt_ind_cb = NULL;
+ pan_cb.pan_mfilt_ind_cb = NULL;
+
+ PAN_SetRole(PAN_ROLE_INACTIVE, NULL, NULL, NULL, NULL);
+ BNEP_Deregister();
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_SetRole
+ *
+ * Description This function is called by the application to set the PAN
+ * profile role. This should be called after PAN_Register.
+ * This can be called any time to change the PAN role
+ *
+ * Parameters: role - is bit map of roles to be active
+ * PAN_ROLE_CLIENT is for PANU role
+ * PAN_ROLE_GN_SERVER is for GN role
+ * PAN_ROLE_NAP_SERVER is for NAP role
+ * sec_mask - Security mask for different roles
+ * It is array of uint8_t. The bytes
+ * represent the security for roles PANU,
+ * GN and NAP in order
+ * p_user_name - Service name for PANU role
+ * p_gn_name - Service name for GN role
+ * p_nap_name - Service name for NAP role
+ * Can be NULL if user wants the default
+ *
+ * Returns PAN_SUCCESS - if the role is set successfully
+ * PAN_FAILURE - if the role is not valid
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_SetRole(uint8_t role, uint8_t* sec_mask,
+ const char* p_user_name, const char* p_gn_name,
+ const char* p_nap_name) {
+ const char* p_desc;
+ uint8_t security[3] = {PAN_PANU_SECURITY_LEVEL, PAN_GN_SECURITY_LEVEL,
+ PAN_NAP_SECURITY_LEVEL};
+ uint8_t* p_sec;
+
+ /* If the role is not a valid combination reject it */
+ if ((!(role &
+ (PAN_ROLE_CLIENT | PAN_ROLE_GN_SERVER | PAN_ROLE_NAP_SERVER))) &&
+ role != PAN_ROLE_INACTIVE) {
+ PAN_TRACE_ERROR("PAN role %d is invalid", role);
+ return PAN_FAILURE;
+ }
+
+ /* If the current active role is same as the role being set do nothing */
+ if (pan_cb.role == role) {
+ PAN_TRACE_EVENT("PAN role already was set to: %d", role);
+ return PAN_SUCCESS;
+ }
+
+ if (!sec_mask)
+ p_sec = security;
+ else
+ p_sec = sec_mask;
+
+ /* Register all the roles with SDP */
+ PAN_TRACE_API("PAN_SetRole() called with role 0x%x", role);
+#if (PAN_SUPPORTS_ROLE_NAP == TRUE)
+ if (role & PAN_ROLE_NAP_SERVER) {
+ /* Check the service name */
+ if ((p_nap_name == NULL) || (*p_nap_name == 0))
+ p_nap_name = PAN_NAP_DEFAULT_SERVICE_NAME;
+
+ /* Registering for NAP service with SDP */
+ p_desc = PAN_NAP_DEFAULT_DESCRIPTION;
+
+ if (pan_cb.pan_nap_sdp_handle != 0)
+ SDP_DeleteRecord(pan_cb.pan_nap_sdp_handle);
+
+ pan_cb.pan_nap_sdp_handle =
+ pan_register_with_sdp(UUID_SERVCLASS_NAP, p_sec[2], p_nap_name, p_desc);
+ bta_sys_add_uuid(UUID_SERVCLASS_NAP);
+ }
+ /* If the NAP role is already active and now being cleared delete the record
+ */
+ else if (pan_cb.role & PAN_ROLE_NAP_SERVER) {
+ if (pan_cb.pan_nap_sdp_handle != 0) {
+ SDP_DeleteRecord(pan_cb.pan_nap_sdp_handle);
+ pan_cb.pan_nap_sdp_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_NAP);
+ }
+ }
+#endif
+
+#if (PAN_SUPPORTS_ROLE_GN == TRUE)
+ if (role & PAN_ROLE_GN_SERVER) {
+ /* Check the service name */
+ if ((p_gn_name == NULL) || (*p_gn_name == 0))
+ p_gn_name = PAN_GN_DEFAULT_SERVICE_NAME;
+
+ /* Registering for GN service with SDP */
+ p_desc = PAN_GN_DEFAULT_DESCRIPTION;
+
+ if (pan_cb.pan_gn_sdp_handle != 0)
+ SDP_DeleteRecord(pan_cb.pan_gn_sdp_handle);
+
+ pan_cb.pan_gn_sdp_handle =
+ pan_register_with_sdp(UUID_SERVCLASS_GN, p_sec[1], p_gn_name, p_desc);
+ bta_sys_add_uuid(UUID_SERVCLASS_GN);
+ }
+ /* If the GN role is already active and now being cleared delete the record */
+ else if (pan_cb.role & PAN_ROLE_GN_SERVER) {
+ if (pan_cb.pan_gn_sdp_handle != 0) {
+ SDP_DeleteRecord(pan_cb.pan_gn_sdp_handle);
+ pan_cb.pan_gn_sdp_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_GN);
+ }
+ }
+#endif
+
+#if (PAN_SUPPORTS_ROLE_PANU == TRUE)
+ if (role & PAN_ROLE_CLIENT) {
+ /* Check the service name */
+ if ((p_user_name == NULL) || (*p_user_name == 0))
+ p_user_name = PAN_PANU_DEFAULT_SERVICE_NAME;
+
+ /* Registering for PANU service with SDP */
+ p_desc = PAN_PANU_DEFAULT_DESCRIPTION;
+ if (pan_cb.pan_user_sdp_handle != 0)
+ SDP_DeleteRecord(pan_cb.pan_user_sdp_handle);
+
+ pan_cb.pan_user_sdp_handle = pan_register_with_sdp(
+ UUID_SERVCLASS_PANU, p_sec[0], p_user_name, p_desc);
+ bta_sys_add_uuid(UUID_SERVCLASS_PANU);
+ }
+ /* If the PANU role is already active and now being cleared delete the record
+ */
+ else if (pan_cb.role & PAN_ROLE_CLIENT) {
+ if (pan_cb.pan_user_sdp_handle != 0) {
+ SDP_DeleteRecord(pan_cb.pan_user_sdp_handle);
+ pan_cb.pan_user_sdp_handle = 0;
+ bta_sys_remove_uuid(UUID_SERVCLASS_PANU);
+ }
+ }
+#endif
+
+ /* Check if it is a shutdown request */
+ if (role == PAN_ROLE_INACTIVE) pan_close_all_connections();
+
+ pan_cb.role = role;
+ PAN_TRACE_EVENT("PAN role set to: %d", role);
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_Connect
+ *
+ * Description This function is called by the application to initiate a
+ * connection to the remote device
+ *
+ * Parameters: rem_bda - BD Addr of the remote device
+ * src_role - Role of the local device for the connection
+ * dst_role - Role of the remote device for the connection
+ * PAN_ROLE_CLIENT is for PANU role
+ * PAN_ROLE_GN_SERVER is for GN role
+ * PAN_ROLE_NAP_SERVER is for NAP role
+ * *handle - Pointer for returning Handle to the connection
+ *
+ * Returns PAN_SUCCESS - if the connection is initiated
+ * successfully
+ * PAN_NO_RESOURCES - resources are not sufficent
+ * PAN_FAILURE - if the connection cannot be initiated
+ * this can be because of the combination of
+ * src and dst roles may not be valid or
+ * allowed at that point of time
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_Connect(BD_ADDR rem_bda, uint8_t src_role, uint8_t dst_role,
+ uint16_t* handle) {
+ tPAN_CONN* pcb;
+ tBNEP_RESULT result;
+ tBT_UUID src_uuid, dst_uuid;
+ uint32_t mx_chan_id;
+
+ /*
+ ** Initialize the handle so that in case of failure return values
+ ** the profile will not get confused
+ */
+ *handle = BNEP_INVALID_HANDLE;
+
+ /* Check if PAN is active or not */
+ if (!(pan_cb.role & src_role)) {
+ PAN_TRACE_ERROR("PAN is not active for the role %d", src_role);
+ return PAN_FAILURE;
+ }
+
+ /* Validate the parameters before proceeding */
+ if ((src_role != PAN_ROLE_CLIENT && src_role != PAN_ROLE_GN_SERVER &&
+ src_role != PAN_ROLE_NAP_SERVER) ||
+ (dst_role != PAN_ROLE_CLIENT && dst_role != PAN_ROLE_GN_SERVER &&
+ dst_role != PAN_ROLE_NAP_SERVER)) {
+ PAN_TRACE_ERROR("Either source %d or destination role %d is invalid",
+ src_role, dst_role);
+ return PAN_FAILURE;
+ }
+
+ /* Check if connection exists for this remote device */
+ pcb = pan_get_pcb_by_addr(rem_bda);
+
+ /* If we are PANU for this role validate destination role */
+ if (src_role == PAN_ROLE_CLIENT) {
+ if ((pan_cb.num_conns > 1) || (pan_cb.num_conns && (!pcb))) {
+ /*
+ ** If the request is not for existing connection reject it
+ ** because if there is already a connection we cannot accept
+ ** another connection in PANU role
+ */
+ PAN_TRACE_ERROR(
+ "Cannot make PANU connections when there are more than one "
+ "connection");
+ return PAN_INVALID_SRC_ROLE;
+ }
+
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ if (dst_role == PAN_ROLE_CLIENT) {
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ } else if (dst_role == PAN_ROLE_GN_SERVER) {
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+ } else {
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+ }
+ mx_chan_id = dst_uuid.uu.uuid16;
+ }
+ /* If destination is PANU role validate source role */
+ else if (dst_role == PAN_ROLE_CLIENT) {
+ if (pan_cb.num_conns && pan_cb.active_role == PAN_ROLE_CLIENT && !pcb) {
+ PAN_TRACE_ERROR("Device already have a connection in PANU role");
+ return PAN_INVALID_SRC_ROLE;
+ }
+
+ dst_uuid.uu.uuid16 = UUID_SERVCLASS_PANU;
+ if (src_role == PAN_ROLE_GN_SERVER) {
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_GN;
+ } else {
+ src_uuid.uu.uuid16 = UUID_SERVCLASS_NAP;
+ }
+ mx_chan_id = src_uuid.uu.uuid16;
+ }
+ /* The role combination is not valid */
+ else {
+ PAN_TRACE_ERROR(
+ "Source %d and Destination roles %d are not valid combination",
+ src_role, dst_role);
+ return PAN_FAILURE;
+ }
+
+ /* Allocate control block and initiate connection */
+ if (!pcb) pcb = pan_allocate_pcb(rem_bda, BNEP_INVALID_HANDLE);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN Connection failed because of no resources");
+ return PAN_NO_RESOURCES;
+ }
+ BTM_SetOutService(rem_bda, BTM_SEC_SERVICE_BNEP_PANU, mx_chan_id);
+
+ PAN_TRACE_API("PAN_Connect() for BD Addr %x.%x.%x.%x.%x.%x", rem_bda[0],
+ rem_bda[1], rem_bda[2], rem_bda[3], rem_bda[4], rem_bda[5]);
+ if (pcb->con_state == PAN_STATE_IDLE) {
+ pan_cb.num_conns++;
+ } else if (pcb->con_state == PAN_STATE_CONNECTED) {
+ pcb->con_flags |= PAN_FLAGS_CONN_COMPLETED;
+ } else
+ /* PAN connection is still in progress */
+ return PAN_WRONG_STATE;
+
+ pcb->con_state = PAN_STATE_CONN_START;
+ pcb->prv_src_uuid = pcb->src_uuid;
+ pcb->prv_dst_uuid = pcb->dst_uuid;
+
+ pcb->src_uuid = src_uuid.uu.uuid16;
+ pcb->dst_uuid = dst_uuid.uu.uuid16;
+
+ src_uuid.len = 2;
+ dst_uuid.len = 2;
+
+ result = BNEP_Connect(rem_bda, &src_uuid, &dst_uuid, &(pcb->handle));
+ if (result != BNEP_SUCCESS) {
+ pan_release_pcb(pcb);
+ return result;
+ }
+
+ PAN_TRACE_DEBUG("PAN_Connect() current active role set to %d", src_role);
+ pan_cb.prv_active_role = pan_cb.active_role;
+ pan_cb.active_role = src_role;
+ *handle = pcb->handle;
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_Disconnect
+ *
+ * Description This is used to disconnect the connection
+ *
+ * Parameters: handle - handle for the connection
+ *
+ * Returns PAN_SUCCESS - if the connection is closed successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in disconnecting
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_Disconnect(uint16_t handle) {
+ tPAN_CONN* pcb;
+ tBNEP_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_Disconnect(pcb->handle);
+ if (pcb->con_state != PAN_STATE_IDLE) pan_cb.num_conns--;
+
+ if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP)
+ (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
+
+ pan_release_pcb(pcb);
+
+ if (result != BNEP_SUCCESS) {
+ PAN_TRACE_EVENT("Error in closing PAN connection");
+ return PAN_FAILURE;
+ }
+
+ PAN_TRACE_EVENT("PAN connection closed");
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_Write
+ *
+ * Description This sends data over the PAN connections. If this is called
+ * on GN or NAP side and the packet is multicast or broadcast
+ * it will be sent on all the links. Otherwise the correct link
+ * is found based on the destination address and forwarded on
+ * it.
+ *
+ * Parameters: handle - handle for the connection
+ * dst - MAC or BD Addr of the destination device
+ * src - MAC or BD Addr of the source who sent this packet
+ * protocol - protocol of the ethernet packet like IP or ARP
+ * p_data - pointer to the data
+ * len - length of the data
+ * ext - to indicate that extension headers present
+ *
+ * Returns PAN_SUCCESS - if the data is sent successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in sending data
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_Write(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool ext) {
+ if (pan_cb.role == PAN_ROLE_INACTIVE || !pan_cb.num_conns) {
+ PAN_TRACE_ERROR("%s PAN is not active, data write failed.", __func__);
+ return PAN_FAILURE;
+ }
+
+ // If the packet is broadcast or multicast, we're going to have to create
+ // a copy of the packet for each connection. We can save one extra copy
+ // by fast-pathing here and calling BNEP_Write instead of placing the packet
+ // in a BT_HDR buffer, calling BNEP_Write, and then freeing the buffer.
+ if (dst[0] & 0x01) {
+ int i;
+ for (i = 0; i < MAX_PAN_CONNS; ++i) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED)
+ BNEP_Write(pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ }
+ return PAN_SUCCESS;
+ }
+
+ BT_HDR* buffer = (BT_HDR*)osi_malloc(PAN_BUF_SIZE);
+ buffer->len = len;
+ buffer->offset = PAN_MINIMUM_OFFSET;
+ memcpy((uint8_t*)buffer + sizeof(BT_HDR) + buffer->offset, p_data,
+ buffer->len);
+
+ return PAN_WriteBuf(handle, dst, src, protocol, buffer, ext);
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_WriteBuf
+ *
+ * Description This sends data over the PAN connections. If this is called
+ * on GN or NAP side and the packet is multicast or broadcast
+ * it will be sent on all the links. Otherwise the correct link
+ * is found based on the destination address and forwarded on
+ * it. If the return value is not PAN_SUCCESS, the application
+ * should take care of releasing the message buffer.
+ *
+ * Parameters: handle - handle for the connection
+ * dst - MAC or BD Addr of the destination device
+ * src - MAC or BD Addr of the source who sent this packet
+ * protocol - protocol of the ethernet packet like IP or ARP
+ * p_buf - pointer to the data buffer
+ * ext - to indicate that extension headers present
+ *
+ * Returns PAN_SUCCESS - if the data is sent successfully
+ * PAN_FAILURE - if the connection is not found or
+ * there is an error in sending data
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_WriteBuf(uint16_t handle, BD_ADDR dst, BD_ADDR src,
+ uint16_t protocol, BT_HDR* p_buf, bool ext) {
+ tPAN_CONN* pcb;
+ uint16_t i;
+ tBNEP_RESULT result;
+
+ if (pan_cb.role == PAN_ROLE_INACTIVE || (!(pan_cb.num_conns))) {
+ PAN_TRACE_ERROR("PAN is not active Data write failed");
+ osi_free(p_buf);
+ return PAN_FAILURE;
+ }
+
+ /* Check if it is broadcast or multicast packet */
+ if (dst[0] & 0x01) {
+ uint8_t* data = (uint8_t*)p_buf + sizeof(BT_HDR) + p_buf->offset;
+ for (i = 0; i < MAX_PAN_CONNS; ++i) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED)
+ BNEP_Write(pan_cb.pcb[i].handle, dst, data, p_buf->len, protocol, src,
+ ext);
+ }
+ osi_free(p_buf);
+ return PAN_SUCCESS;
+ }
+
+ /* Check if the data write is on PANU side */
+ if (pan_cb.active_role == PAN_ROLE_CLIENT) {
+ /* Data write is on PANU connection */
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].src_uuid == UUID_SERVCLASS_PANU)
+ break;
+ }
+
+ if (i == MAX_PAN_CONNS) {
+ PAN_TRACE_ERROR("PAN Don't have any user connections");
+ osi_free(p_buf);
+ return PAN_FAILURE;
+ }
+
+ result =
+ BNEP_WriteBuf(pan_cb.pcb[i].handle, dst, p_buf, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD) {
+ PAN_TRACE_DEBUG("PAN ignored data write for PANU connection");
+ return result;
+ } else if (result != BNEP_SUCCESS) {
+ PAN_TRACE_ERROR("PAN failed to write data for the PANU connection");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG("PAN successfully wrote data for the PANU connection");
+ return PAN_SUCCESS;
+ }
+
+ /* findout to which connection the data is meant for */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN Buf write for wrong handle");
+ osi_free(p_buf);
+ return PAN_FAILURE;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED) {
+ PAN_TRACE_ERROR("PAN Buf write when conn is not active");
+ osi_free(p_buf);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_WriteBuf(pcb->handle, dst, p_buf, protocol, src, ext);
+ if (result == BNEP_IGNORE_CMD) {
+ PAN_TRACE_DEBUG("PAN ignored data buf write to PANU");
+ return result;
+ } else if (result != BNEP_SUCCESS) {
+ PAN_TRACE_ERROR("PAN failed to send data buf to the PANU");
+ return result;
+ }
+
+ PAN_TRACE_DEBUG("PAN successfully sent data buf to the PANU");
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_SetProtocolFilters
+ *
+ * Description This function is used to set protocol filters on the peer
+ *
+ * Parameters: handle - handle for the connection
+ * num_filters - number of protocol filter ranges
+ * start - array of starting protocol numbers
+ * end - array of ending protocol numbers
+ *
+ *
+ * Returns PAN_SUCCESS if protocol filters are set successfully
+ * PAN_FAILURE if connection not found or error in setting
+ *
+ ******************************************************************************/
+tPAN_RESULT PAN_SetProtocolFilters(uint16_t handle, uint16_t num_filters,
+ uint16_t* p_start_array,
+ uint16_t* p_end_array) {
+ tPAN_CONN* pcb;
+ tPAN_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_SetProtocolFilters(pcb->handle, num_filters, p_start_array,
+ p_end_array);
+ if (result != BNEP_SUCCESS) {
+ PAN_TRACE_ERROR("PAN failed to set protocol filters for handle %d", handle);
+ return result;
+ }
+
+ PAN_TRACE_API("PAN successfully sent protocol filters for handle %d", handle);
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_SetMulticastFilters
+ *
+ * Description This function is used to set multicast filters on the peer
+ *
+ * Parameters: handle - handle for the connection
+ * num_filters - number of multicast filter ranges
+ * start - array of starting multicast filter addresses
+ * end - array of ending multicast filter addresses
+ *
+ *
+ * Returns PAN_SUCCESS if multicast filters are set successfully
+ * PAN_FAILURE if connection not found or error in setting
+ *
+ ******************************************************************************/
+tBNEP_RESULT PAN_SetMulticastFilters(uint16_t handle,
+ uint16_t num_mcast_filters,
+ uint8_t* p_start_array,
+ uint8_t* p_end_array) {
+ tPAN_CONN* pcb;
+ tPAN_RESULT result;
+
+ /* Check if the connection exists */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN connection not found for the handle %d", handle);
+ return PAN_FAILURE;
+ }
+
+ result = BNEP_SetMulticastFilters(pcb->handle, num_mcast_filters,
+ p_start_array, p_end_array);
+ if (result != BNEP_SUCCESS) {
+ PAN_TRACE_ERROR("PAN failed to set multicast filters for handle %d",
+ handle);
+ return result;
+ }
+
+ PAN_TRACE_API("PAN successfully sent multicast filters for handle %d",
+ handle);
+ return PAN_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_SetTraceLevel
+ *
+ * Description This function sets the trace level for PAN. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t PAN_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF)
+ pan_cb.trace_level = new_level;
+ else
+ pan_dump_status();
+
+ return (pan_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function PAN_Init
+ *
+ * Description This function initializes the PAN module variables
+ *
+ * Parameters: none
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void PAN_Init(void) {
+ memset(&pan_cb, 0, sizeof(tPAN_CB));
+
+#if defined(PAN_INITIAL_TRACE_LEVEL)
+ pan_cb.trace_level = PAN_INITIAL_TRACE_LEVEL;
+#else
+ pan_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+}
diff --git a/mtkbt/code/bt/stack/pan/pan_int.h b/mtkbt/code/bt/stack/pan/pan_int.h
new file mode 100755
index 0000000..b9cd343
--- a/dev/null
+++ b/mtkbt/code/bt/stack/pan/pan_int.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2001-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used PAN definitions
+ *
+ ******************************************************************************/
+
+#ifndef PAN_INT_H
+#define PAN_INT_H
+
+#include "pan_api.h"
+
+/*
+ * This role is used to shutdown the profile. Used internally
+ * Applications should call PAN_Deregister to shutdown the profile
+*/
+#define PAN_ROLE_INACTIVE 0
+
+/* Protocols supported by the host internal stack, are registered with SDP */
+#define PAN_PROTOCOL_IP 0x0800
+#define PAN_PROTOCOL_ARP 0x0806
+
+#define PAN_PROFILE_VERSION 0x0100 /* Version 1.00 */
+
+/* Define the PAN Connection Control Block
+*/
+typedef struct {
+#define PAN_STATE_IDLE 0
+#define PAN_STATE_CONN_START 1
+#define PAN_STATE_CONNECTED 2
+ uint8_t con_state;
+
+#define PAN_FLAGS_CONN_COMPLETED 0x01
+ uint8_t con_flags;
+
+ uint16_t handle;
+ BD_ADDR rem_bda;
+
+ uint16_t bad_pkts_rcvd;
+ uint16_t src_uuid;
+ uint16_t dst_uuid;
+ uint16_t prv_src_uuid;
+ uint16_t prv_dst_uuid;
+ uint16_t ip_addr_known;
+ uint32_t ip_addr;
+
+} tPAN_CONN;
+
+/* The main PAN control block
+*/
+typedef struct {
+ uint8_t role;
+ uint8_t active_role;
+ uint8_t prv_active_role;
+ tPAN_CONN pcb[MAX_PAN_CONNS];
+
+ tPAN_CONN_STATE_CB* pan_conn_state_cb; /* Connection state callback */
+ tPAN_BRIDGE_REQ_CB* pan_bridge_req_cb;
+ tPAN_DATA_IND_CB* pan_data_ind_cb;
+ tPAN_DATA_BUF_IND_CB* pan_data_buf_ind_cb;
+ tPAN_FILTER_IND_CB*
+ pan_pfilt_ind_cb; /* protocol filter indication callback */
+ tPAN_MFILTER_IND_CB*
+ pan_mfilt_ind_cb; /* multicast filter indication callback */
+ tPAN_TX_DATA_FLOW_CB* pan_tx_data_flow_cb;
+
+ char* user_service_name;
+ char* gn_service_name;
+ char* nap_service_name;
+ uint32_t pan_user_sdp_handle;
+ uint32_t pan_gn_sdp_handle;
+ uint32_t pan_nap_sdp_handle;
+ uint8_t num_conns;
+ uint8_t trace_level;
+} tPAN_CB;
+
+/* Global PAN data
+*/
+extern tPAN_CB pan_cb;
+
+/******************************************************************************/
+extern void pan_register_with_bnep(void);
+extern void pan_conn_ind_cb(uint16_t handle, BD_ADDR p_bda,
+ tBT_UUID* remote_uuid, tBT_UUID* local_uuid,
+ bool is_role_change);
+extern void pan_connect_state_cb(uint16_t handle, BD_ADDR rem_bda,
+ tBNEP_RESULT result, bool is_role_change);
+extern void pan_data_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool fw_ext_present);
+extern void pan_data_buf_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, BT_HDR* p_buf, bool ext);
+extern void pan_tx_data_flow_cb(uint16_t handle, tBNEP_RESULT event);
+void pan_proto_filt_ind_cb(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters);
+void pan_mcast_filt_ind_cb(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters);
+extern uint32_t pan_register_with_sdp(uint16_t uuid, uint8_t sec_mask,
+ const char* p_name, const char* p_desc);
+extern tPAN_CONN* pan_allocate_pcb(BD_ADDR p_bda, uint16_t handle);
+extern tPAN_CONN* pan_get_pcb_by_handle(uint16_t handle);
+extern tPAN_CONN* pan_get_pcb_by_addr(BD_ADDR p_bda);
+extern void pan_close_all_connections(void);
+extern void pan_release_pcb(tPAN_CONN* p_pcb);
+extern void pan_dump_status(void);
+
+/******************************************************************************/
+
+#endif
diff --git a/mtkbt/code/bt/stack/pan/pan_main.cc b/mtkbt/code/bt/stack/pan/pan_main.cc
new file mode 100755
index 0000000..ff60540
--- a/dev/null
+++ b/mtkbt/code/bt/stack/pan/pan_main.cc
@@ -0,0 +1,718 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains main functions to support PAN profile
+ * commands and events.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bnep_api.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+
+tPAN_CB pan_cb;
+
+#define UUID_CONSTANT_PART 12
+uint8_t constant_pan_uuid[UUID_CONSTANT_PART] = {
+ 0, 0, 0x10, 0, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+
+/*******************************************************************************
+ *
+ * Function pan_register_with_bnep
+ *
+ * Description This function registers PAN profile with BNEP
+ *
+ * Parameters: none
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_register_with_bnep(void) {
+ tBNEP_REGISTER reg_info;
+
+ memset(&reg_info, 0, sizeof(tBNEP_REGISTER));
+
+ reg_info.p_conn_ind_cb = pan_conn_ind_cb;
+ reg_info.p_conn_state_cb = pan_connect_state_cb;
+ reg_info.p_data_buf_cb = pan_data_buf_ind_cb;
+ reg_info.p_data_ind_cb = NULL;
+ reg_info.p_tx_data_flow_cb = pan_tx_data_flow_cb;
+ reg_info.p_filter_ind_cb = pan_proto_filt_ind_cb;
+ reg_info.p_mfilter_ind_cb = pan_mcast_filt_ind_cb;
+
+ BNEP_Register(&reg_info);
+}
+
+/*******************************************************************************
+ *
+ * Function pan_conn_ind_cb
+ *
+ * Description This function is registered with BNEP as connection
+ * indication callback. BNEP will call this when there is
+ * connection request from the peer. PAN should call
+ * BNEP_ConnectResp to indicate whether to accept the
+ * connection or reject
+ *
+ * Parameters: handle - handle for the connection
+ * p_bda - BD Addr of the peer requesting the connection
+ * remote_uuid - UUID of the source role (peer device role)
+ * local_uuid - UUID of the destination role (local device
+ * role)
+ * is_role_change - Flag to indicate that it is a role change
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_conn_ind_cb(uint16_t handle, BD_ADDR p_bda, tBT_UUID* remote_uuid,
+ tBT_UUID* local_uuid, bool is_role_change) {
+ tPAN_CONN* pcb;
+ uint8_t req_role;
+ bool wrong_uuid;
+
+ /*
+ ** If we are in GN or NAP role and have one or more
+ ** active connections and the received connection is
+ ** for user role reject it.
+ ** If we are in user role with one connection active
+ ** reject the connection.
+ ** Allocate PCB and store the parameters
+ ** Make bridge request to the host system if connection
+ ** is for NAP
+ */
+ wrong_uuid = false;
+ if (remote_uuid->len == 16) {
+ /*
+ ** If the UUID is 16 bytes forst two bytes should be zeros
+ ** and last 12 bytes should match the spec defined constant value
+ */
+ if (memcmp(constant_pan_uuid, remote_uuid->uu.uuid128 + 4,
+ UUID_CONSTANT_PART))
+ wrong_uuid = true;
+
+ if (remote_uuid->uu.uuid128[0] || remote_uuid->uu.uuid128[1])
+ wrong_uuid = true;
+
+ /* Extract the 16 bit equivalent of the UUID */
+ remote_uuid->uu.uuid16 = (uint16_t)((remote_uuid->uu.uuid128[2] << 8) |
+ remote_uuid->uu.uuid128[3]);
+ remote_uuid->len = 2;
+ }
+ if (remote_uuid->len == 4) {
+ /* First two bytes should be zeros */
+ if (remote_uuid->uu.uuid32 & 0xFFFF0000) wrong_uuid = true;
+
+ remote_uuid->uu.uuid16 = (uint16_t)remote_uuid->uu.uuid32;
+ remote_uuid->len = 2;
+ }
+
+ if (wrong_uuid) {
+ PAN_TRACE_ERROR("PAN Connection failed because of wrong remote UUID ");
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
+ return;
+ }
+
+ wrong_uuid = false;
+ if (local_uuid->len == 16) {
+ /*
+ ** If the UUID is 16 bytes forst two bytes should be zeros
+ ** and last 12 bytes should match the spec defined constant value
+ */
+ if (memcmp(constant_pan_uuid, local_uuid->uu.uuid128 + 4,
+ UUID_CONSTANT_PART))
+ wrong_uuid = true;
+
+ if (local_uuid->uu.uuid128[0] || local_uuid->uu.uuid128[1])
+ wrong_uuid = true;
+
+ /* Extract the 16 bit equivalent of the UUID */
+ local_uuid->uu.uuid16 = (uint16_t)((local_uuid->uu.uuid128[2] << 8) |
+ local_uuid->uu.uuid128[3]);
+ local_uuid->len = 2;
+ }
+ if (local_uuid->len == 4) {
+ /* First two bytes should be zeros */
+ if (local_uuid->uu.uuid32 & 0xFFFF0000) wrong_uuid = true;
+
+ local_uuid->uu.uuid16 = (uint16_t)local_uuid->uu.uuid32;
+ local_uuid->len = 2;
+ }
+
+ if (wrong_uuid) {
+ PAN_TRACE_ERROR("PAN Connection failed because of wrong local UUID ");
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ PAN_TRACE_EVENT(
+ "pan_conn_ind_cb - for handle %d, current role %d, dst uuid 0x%x, src "
+ "uuid 0x%x, role change %s",
+ handle, pan_cb.role, local_uuid->uu.uuid16, remote_uuid->uu.uuid16,
+ is_role_change ? "YES" : "NO");
+ /* The acceptable UUID size is only 2 */
+ if (remote_uuid->len != 2) {
+ PAN_TRACE_ERROR("PAN Connection failed because of wrong UUID size %d",
+ remote_uuid->len);
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_UUID_SIZE);
+ return;
+ }
+
+ /* Check if the source UUID is a valid one */
+ if (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+ remote_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+ remote_uuid->uu.uuid16 != UUID_SERVCLASS_GN) {
+ PAN_TRACE_ERROR("Src UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
+ return;
+ }
+
+ /* Check if the destination UUID is a valid one */
+ if (local_uuid->uu.uuid16 != UUID_SERVCLASS_PANU &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_GN) {
+ PAN_TRACE_ERROR("Dst UUID 0x%x is not valid", remote_uuid->uu.uuid16);
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /* Check if currently we support the destination role requested */
+ if (((!(pan_cb.role & UUID_SERVCLASS_PANU)) &&
+ local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) ||
+ ((!(pan_cb.role & UUID_SERVCLASS_GN)) &&
+ local_uuid->uu.uuid16 == UUID_SERVCLASS_GN) ||
+ ((!(pan_cb.role & UUID_SERVCLASS_NAP)) &&
+ local_uuid->uu.uuid16 == UUID_SERVCLASS_NAP)) {
+ PAN_TRACE_ERROR(
+ "PAN Connection failed because of unsupported destination UUID 0x%x",
+ local_uuid->uu.uuid16);
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /*Check for valid interactions between the tree PAN profile roles */
+ /*
+ * For reference, see Table 1 in PAN profile v1.0 spec.
+ * Note: the remote is the initiator.
+ */
+ bool is_valid_interaction = false;
+ switch (remote_uuid->uu.uuid16) {
+ case UUID_SERVCLASS_NAP:
+ case UUID_SERVCLASS_GN:
+ if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+ is_valid_interaction = true;
+ break;
+ case UUID_SERVCLASS_PANU:
+ is_valid_interaction = true;
+ break;
+ }
+ /*
+ * Explicitly disable connections to the local PANU if the remote is not PANU.
+ */
+ if ((local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) &&
+ (remote_uuid->uu.uuid16 != UUID_SERVCLASS_PANU)) {
+ is_valid_interaction = false;
+ }
+ if (!is_valid_interaction) {
+ PAN_TRACE_ERROR(
+ "PAN Connection failed because of invalid PAN profile roles "
+ "interaction: Remote UUID 0x%x Local UUID 0x%x",
+ remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_SRC_UUID);
+ return;
+ }
+ /* Requested destination role is */
+ if (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU)
+ req_role = PAN_ROLE_CLIENT;
+ else if (local_uuid->uu.uuid16 == UUID_SERVCLASS_GN)
+ req_role = PAN_ROLE_GN_SERVER;
+ else
+ req_role = PAN_ROLE_NAP_SERVER;
+
+ /* If the connection indication is for the existing connection
+ ** Check if the new destination role is acceptable
+ */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (pcb) {
+ if (pan_cb.num_conns > 1 && local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU) {
+ /* There are connections other than this one
+ ** so we cann't accept PANU role. Reject
+ */
+ PAN_TRACE_ERROR(
+ "Dst UUID should be either GN or NAP only because there are other "
+ "connections");
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+
+ /* If it is already in connected state check for bridging status */
+ if (pcb->con_state == PAN_STATE_CONNECTED) {
+ PAN_TRACE_EVENT("PAN Role changing New Src 0x%x Dst 0x%x",
+ remote_uuid->uu.uuid16, local_uuid->uu.uuid16);
+
+ pcb->prv_src_uuid = pcb->src_uuid;
+ pcb->prv_dst_uuid = pcb->dst_uuid;
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP &&
+ local_uuid->uu.uuid16 != UUID_SERVCLASS_NAP) {
+ /* Remove bridging */
+ if (pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
+ }
+ }
+ /* Set the latest active PAN role */
+ pan_cb.active_role = req_role;
+ pcb->src_uuid = local_uuid->uu.uuid16;
+ pcb->dst_uuid = remote_uuid->uu.uuid16;
+ BNEP_ConnectResp(handle, BNEP_SUCCESS);
+ return;
+ } else {
+ /* If this a new connection and destination is PANU role and
+ ** we already have a connection then reject the request.
+ ** If we have a connection in PANU role then reject it
+ */
+ if (pan_cb.num_conns && (local_uuid->uu.uuid16 == UUID_SERVCLASS_PANU ||
+ pan_cb.active_role == PAN_ROLE_CLIENT)) {
+ PAN_TRACE_ERROR("PAN already have a connection and can't be user");
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED_DST_UUID);
+ return;
+ }
+ }
+
+ /* This is a new connection */
+ PAN_TRACE_DEBUG("New connection indication for handle %d", handle);
+ pcb = pan_allocate_pcb(p_bda, handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN no control block for new connection");
+ BNEP_ConnectResp(handle, BNEP_CONN_FAILED);
+ return;
+ }
+
+ PAN_TRACE_EVENT("PAN connection destination UUID is 0x%x",
+ local_uuid->uu.uuid16);
+ /* Set the latest active PAN role */
+ pan_cb.active_role = req_role;
+ pcb->src_uuid = local_uuid->uu.uuid16;
+ pcb->dst_uuid = remote_uuid->uu.uuid16;
+ pcb->con_state = PAN_STATE_CONN_START;
+ pan_cb.num_conns++;
+
+ BNEP_ConnectResp(handle, BNEP_SUCCESS);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_connect_state_cb
+ *
+ * Description This function is registered with BNEP as connection state
+ * change callback. BNEP will call this when the connection
+ * is established successfully or terminated
+ *
+ * Parameters: handle - handle for the connection given in the connection
+ * indication callback
+ * rem_bda - remote device bd addr
+ * result - indicates whether the connection is up or down
+ * BNEP_SUCCESS if the connection is up all other
+ * values indicate appropriate errors.
+ * is_role_change - flag to indicate that it is a role change
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_connect_state_cb(uint16_t handle, UNUSED_ATTR BD_ADDR rem_bda,
+ tBNEP_RESULT result, bool is_role_change) {
+ tPAN_CONN* pcb;
+ uint8_t peer_role;
+
+ PAN_TRACE_EVENT("pan_connect_state_cb - for handle %d, result %d", handle,
+ result);
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN State change indication for wrong handle %d", handle);
+ return;
+ }
+
+ /* If the connection is getting terminated remove bridging */
+ if (result != BNEP_SUCCESS) {
+ /* Inform the application that connection is down */
+ if (pan_cb.pan_conn_state_cb)
+ (*pan_cb.pan_conn_state_cb)(pcb->handle, pcb->rem_bda, result,
+ is_role_change, PAN_ROLE_INACTIVE,
+ PAN_ROLE_INACTIVE);
+
+ /* Check if this failure is for role change only */
+ if (pcb->con_state != PAN_STATE_CONNECTED &&
+ (pcb->con_flags & PAN_FLAGS_CONN_COMPLETED)) {
+ /* restore the original values */
+ PAN_TRACE_EVENT("restoring the connection state to active");
+ pcb->con_state = PAN_STATE_CONNECTED;
+ pcb->con_flags &= (~PAN_FLAGS_CONN_COMPLETED);
+
+ pcb->src_uuid = pcb->prv_src_uuid;
+ pcb->dst_uuid = pcb->prv_dst_uuid;
+ pan_cb.active_role = pan_cb.prv_active_role;
+
+ if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, true);
+
+ return;
+ }
+
+ if (pcb->con_state == PAN_STATE_CONNECTED) {
+ /* If the connections destination role is NAP remove bridging */
+ if ((pcb->src_uuid == UUID_SERVCLASS_NAP) && pan_cb.pan_bridge_req_cb)
+ (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, false);
+ }
+
+ pan_cb.num_conns--;
+ pan_release_pcb(pcb);
+ return;
+ }
+
+ /* Requested destination role is */
+ if (pcb->src_uuid == UUID_SERVCLASS_PANU)
+ pan_cb.active_role = PAN_ROLE_CLIENT;
+ else if (pcb->src_uuid == UUID_SERVCLASS_GN)
+ pan_cb.active_role = PAN_ROLE_GN_SERVER;
+ else
+ pan_cb.active_role = PAN_ROLE_NAP_SERVER;
+
+ if (pcb->dst_uuid == UUID_SERVCLASS_PANU)
+ peer_role = PAN_ROLE_CLIENT;
+ else if (pcb->dst_uuid == UUID_SERVCLASS_GN)
+ peer_role = PAN_ROLE_GN_SERVER;
+ else
+ peer_role = PAN_ROLE_NAP_SERVER;
+
+ pcb->con_state = PAN_STATE_CONNECTED;
+
+ /* Inform the application that connection is down */
+ if (pan_cb.pan_conn_state_cb)
+ (*pan_cb.pan_conn_state_cb)(pcb->handle, pcb->rem_bda, PAN_SUCCESS,
+ is_role_change, pan_cb.active_role, peer_role);
+
+ /* Create bridge if the destination role is NAP */
+ if (pan_cb.pan_bridge_req_cb && pcb->src_uuid == UUID_SERVCLASS_NAP) {
+ PAN_TRACE_EVENT("PAN requesting for bridge");
+ (*pan_cb.pan_bridge_req_cb)(pcb->rem_bda, true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function pan_data_ind_cb
+ *
+ * Description This function is registered with BNEP as data indication
+ * callback. BNEP will call this when the peer sends any data
+ * on this connection
+ *
+ * Parameters: handle - handle for the connection
+ * src - source BD Addr
+ * dst - destination BD Addr
+ * protocol - Network protocol of the Eth packet
+ * p_data - pointer to the data
+ * len - length of the data
+ * fw_ext_present - to indicate whether the data contains any
+ * extension headers before the payload
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_data_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, uint8_t* p_data, uint16_t len,
+ bool ext) {
+ tPAN_CONN* pcb;
+ uint16_t i;
+ bool forward;
+
+ /*
+ ** Check the connection status
+ ** If the destination address is MAC broadcast send on all links
+ ** except on the one received
+ ** If the destination uuid is for NAP send to host system also
+ ** If the destination address is one of the devices connected
+ ** send the packet to over that link
+ ** If the destination address is unknown and destination uuid is NAP
+ ** send it to the host system
+ */
+
+ PAN_TRACE_EVENT("pan_data_ind_cb - for handle %d", handle);
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN Data indication for wrong handle %d", handle);
+ return;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED) {
+ PAN_TRACE_ERROR("PAN Data indication in wrong state %d for handle %d",
+ pcb->con_state, handle);
+ return;
+ }
+
+ /* Check if it is broadcast packet */
+ if (dst[0] & 0x01) {
+ PAN_TRACE_DEBUG("PAN received broadcast packet on handle %d, src uuid 0x%x",
+ handle, pcb->src_uuid);
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].handle != handle &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid) {
+ BNEP_Write(pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ }
+ }
+
+ if (pan_cb.pan_data_ind_cb)
+ (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len,
+ ext, true);
+
+ return;
+ }
+
+ /* Check if it is for any other PAN connection */
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid) {
+ if (memcmp(pan_cb.pcb[i].rem_bda, dst, BD_ADDR_LEN) == 0) {
+ BNEP_Write(pan_cb.pcb[i].handle, dst, p_data, len, protocol, src, ext);
+ return;
+ }
+ }
+ }
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+ forward = true;
+ else
+ forward = false;
+
+ /* Send it over the LAN or give it to host software */
+ if (pan_cb.pan_data_ind_cb)
+ (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len, ext,
+ forward);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_data_buf_ind_cb
+ *
+ * Description This function is registered with BNEP as data buffer
+ * indication callback. BNEP will call this when the peer sends
+ * any data on this connection. PAN is responsible to release
+ * the buffer
+ *
+ * Parameters: handle - handle for the connection
+ * src - source BD Addr
+ * dst - destination BD Addr
+ * protocol - Network protocol of the Eth packet
+ * p_buf - pointer to the data buffer
+ * ext - to indicate whether the data contains any
+ * extension headers before the payload
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_data_buf_ind_cb(uint16_t handle, uint8_t* src, uint8_t* dst,
+ uint16_t protocol, BT_HDR* p_buf, bool ext) {
+ tPAN_CONN *pcb, *dst_pcb;
+ tBNEP_RESULT result;
+ uint16_t i, len;
+ uint8_t* p_data;
+ bool forward = false;
+
+ /* Check if the connection is in right state */
+ pcb = pan_get_pcb_by_handle(handle);
+ if (!pcb) {
+ PAN_TRACE_ERROR("PAN Data buffer indication for wrong handle %d", handle);
+ osi_free(p_buf);
+ return;
+ }
+
+ if (pcb->con_state != PAN_STATE_CONNECTED) {
+ PAN_TRACE_ERROR("PAN Data indication in wrong state %d for handle %d",
+ pcb->con_state, handle);
+ osi_free(p_buf);
+ return;
+ }
+
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ len = p_buf->len;
+
+ PAN_TRACE_EVENT(
+ "pan_data_buf_ind_cb - for handle %d, protocol 0x%x, length %d, ext %d",
+ handle, protocol, len, ext);
+
+ if (pcb->src_uuid == UUID_SERVCLASS_NAP)
+ forward = true;
+ else
+ forward = false;
+
+ /* Check if it is broadcast or multicast packet */
+ if (pcb->src_uuid != UUID_SERVCLASS_PANU) {
+ if (dst[0] & 0x01) {
+ PAN_TRACE_DEBUG(
+ "PAN received broadcast packet on handle %d, src uuid 0x%x", handle,
+ pcb->src_uuid);
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_CONNECTED &&
+ pan_cb.pcb[i].handle != handle &&
+ pcb->src_uuid == pan_cb.pcb[i].src_uuid) {
+ BNEP_Write(pan_cb.pcb[i].handle, dst, p_data, len, protocol, src,
+ ext);
+ }
+ }
+
+ if (pan_cb.pan_data_buf_ind_cb)
+ (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf,
+ ext, forward);
+ else if (pan_cb.pan_data_ind_cb) {
+ (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len,
+ ext, forward);
+ osi_free(p_buf);
+ }
+
+ return;
+ }
+
+ /* Check if it is for any other PAN connection */
+ dst_pcb = pan_get_pcb_by_addr(dst);
+ if (dst_pcb) {
+ PAN_TRACE_EVENT(
+ "%s - destination PANU found on handle %d and sending data, len: %d",
+ __func__, dst_pcb->handle, len);
+
+ result =
+ BNEP_Write(dst_pcb->handle, dst, p_data, len, protocol, src, ext);
+ if (result != BNEP_SUCCESS && result != BNEP_IGNORE_CMD)
+ PAN_TRACE_ERROR("Failed to write data for PAN connection handle %d",
+ dst_pcb->handle);
+ osi_free(p_buf);
+ return;
+ }
+ }
+
+ /* Send it over the LAN or give it to host software */
+ if (pan_cb.pan_data_buf_ind_cb)
+ (*pan_cb.pan_data_buf_ind_cb)(pcb->handle, src, dst, protocol, p_buf, ext,
+ forward);
+ else if (pan_cb.pan_data_ind_cb) {
+ (*pan_cb.pan_data_ind_cb)(pcb->handle, src, dst, protocol, p_data, len, ext,
+ forward);
+ osi_free(p_buf);
+ } else
+ osi_free(p_buf);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_proto_filt_ind_cb
+ *
+ * Description This function is registered with BNEP to receive tx data
+ * flow status
+ *
+ * Parameters: handle - handle for the connection
+ * event - flow status
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_tx_data_flow_cb(uint16_t handle, tBNEP_RESULT event) {
+ if (pan_cb.pan_tx_data_flow_cb) (*pan_cb.pan_tx_data_flow_cb)(handle, event);
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_proto_filt_ind_cb
+ *
+ * Description This function is registered with BNEP as proto filter
+ * indication callback. BNEP will call this when the peer sends
+ * any protocol filter set for the connection or to indicate
+ * the result of the protocol filter set by the local device
+ *
+ * Parameters: handle - handle for the connection
+ * indication - true if this is indication
+ * false if it is called to give the result of
+ * local device protocol filter set
+ * result - This gives the result of the filter set
+ * operation
+ * num_filters - number of filters set by the peer device
+ * p_filters - pointer to the filters set by the peer device
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_proto_filt_ind_cb(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters) {
+ PAN_TRACE_EVENT(
+ "pan_proto_filt_ind_cb - called for handle %d with ind %d, result %d, "
+ "num %d",
+ handle, indication, result, num_filters);
+
+ if (pan_cb.pan_pfilt_ind_cb)
+ (*pan_cb.pan_pfilt_ind_cb)(handle, indication, result, num_filters,
+ p_filters);
+}
+
+/*******************************************************************************
+ *
+ * Function pan_mcast_filt_ind_cb
+ *
+ * Description This function is registered with BNEP as mcast filter
+ * indication callback. BNEP will call this when the peer sends
+ * any multicast filter set for the connection or to indicate
+ * the result of the multicast filter set by the local device
+ *
+ * Parameters: handle - handle for the connection
+ * indication - true if this is indication
+ * false if it is called to give the result of
+ * local device multicast filter set
+ * result - This gives the result of the filter set
+ * operation
+ * num_filters - number of filters set by the peer device
+ * p_filters - pointer to the filters set by the peer device
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_mcast_filt_ind_cb(uint16_t handle, bool indication,
+ tBNEP_RESULT result, uint16_t num_filters,
+ uint8_t* p_filters) {
+ PAN_TRACE_EVENT(
+ "pan_mcast_filt_ind_cb - called for handle %d with ind %d, result %d, "
+ "num %d",
+ handle, indication, result, num_filters);
+
+ if (pan_cb.pan_mfilt_ind_cb)
+ (*pan_cb.pan_mfilt_ind_cb)(handle, indication, result, num_filters,
+ p_filters);
+}
diff --git a/mtkbt/code/bt/stack/pan/pan_utils.cc b/mtkbt/code/bt/stack/pan/pan_utils.cc
new file mode 100755
index 0000000..7f75135
--- a/dev/null
+++ b/mtkbt/code/bt/stack/pan/pan_utils.cc
@@ -0,0 +1,321 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains main functions to support PAN profile
+ * commands and events.
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "bnep_api.h"
+#include "bt_common.h"
+#include "btm_api.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+#include "pan_api.h"
+#include "pan_int.h"
+#include "sdp_api.h"
+#include "sdpdefs.h"
+
+static const uint8_t pan_proto_elem_data[] = {
+ 0x35, 0x18, /* data element sequence of length 0x18 bytes */
+ 0x35, 0x06, /* data element sequence for L2CAP descriptor */
+ 0x19, 0x01, 0x00, /* UUID for L2CAP - 0x0100 */
+ 0x09, 0x00, 0x0F, /* PSM for BNEP - 0x000F */
+ 0x35, 0x0E, /* data element seqence for BNEP descriptor */
+ 0x19, 0x00, 0x0F, /* UUID for BNEP - 0x000F */
+ 0x09, 0x01,
+ 0x00, /* BNEP specific parameter 0 -- Version of BNEP = version 1 = 0x0001
+ */
+ 0x35,
+ 0x06, /* BNEP specific parameter 1 -- Supported network packet type list */
+ 0x09, 0x08, 0x00, /* network packet type IPv4 = 0x0800 */
+ 0x09, 0x08, 0x06 /* network packet type ARP = 0x0806 */
+};
+
+/*******************************************************************************
+ *
+ * Function pan_register_with_sdp
+ *
+ * Description
+ *
+ * Returns
+ *
+ ******************************************************************************/
+uint32_t pan_register_with_sdp(uint16_t uuid, uint8_t sec_mask,
+ const char* p_name, const char* p_desc) {
+ uint32_t sdp_handle;
+ uint16_t browse_list = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP;
+ uint16_t security = 0;
+ uint32_t proto_len = (uint32_t)pan_proto_elem_data[1];
+
+ /* Create a record */
+ sdp_handle = SDP_CreateRecord();
+
+ if (sdp_handle == 0) {
+ PAN_TRACE_ERROR("PAN_SetRole - could not create SDP record");
+ return 0;
+ }
+
+ /* Service Class ID List */
+ SDP_AddServiceClassIdList(sdp_handle, 1, &uuid);
+
+ /* Add protocol element sequence from the constant string */
+ SDP_AddAttribute(sdp_handle, ATTR_ID_PROTOCOL_DESC_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, proto_len,
+ (uint8_t*)(pan_proto_elem_data + 2));
+
+ /* Language base */
+ SDP_AddLanguageBaseAttrIDList(sdp_handle, LANG_ID_CODE_ENGLISH,
+ LANG_ID_CHAR_ENCODE_UTF8, LANGUAGE_BASE_ID);
+
+ /* Profile descriptor list */
+ SDP_AddProfileDescriptorList(sdp_handle, uuid, PAN_PROFILE_VERSION);
+
+ /* Service Name */
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (uint8_t)(strlen(p_name) + 1), (uint8_t*)p_name);
+
+ /* Service description */
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
+ (uint8_t)(strlen(p_desc) + 1), (uint8_t*)p_desc);
+
+ /* Security description */
+ if (sec_mask) {
+ UINT16_TO_BE_FIELD(&security, 0x0001);
+ }
+ SDP_AddAttribute(sdp_handle, ATTR_ID_SECURITY_DESCRIPTION, UINT_DESC_TYPE, 2,
+ (uint8_t*)&security);
+
+#if (PAN_SUPPORTS_ROLE_NAP == TRUE)
+ if (uuid == UUID_SERVCLASS_NAP) {
+ uint16_t NetAccessType = 0x0005; /* Ethernet */
+ uint32_t NetAccessRate = 0x0001312D0; /* 10Mb/sec */
+ uint8_t array[10], *p;
+
+ /* Net access type. */
+ p = array;
+ UINT16_TO_BE_STREAM(p, NetAccessType);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_NET_ACCESS_TYPE, UINT_DESC_TYPE, 2,
+ array);
+
+ /* Net access rate. */
+ p = array;
+ UINT32_TO_BE_STREAM(p, NetAccessRate);
+ SDP_AddAttribute(sdp_handle, ATTR_ID_MAX_NET_ACCESS_RATE, UINT_DESC_TYPE, 4,
+ array);
+
+ /* Register with Security Manager for the specific security level */
+ if ((!BTM_SetSecurityLevel(true, p_name, BTM_SEC_SERVICE_BNEP_NAP, sec_mask,
+ BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_NAP)) ||
+ (!BTM_SetSecurityLevel(false, p_name, BTM_SEC_SERVICE_BNEP_NAP,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_NAP))) {
+ PAN_TRACE_ERROR("PAN Security Registration failed for PANU");
+ }
+ }
+#endif
+#if (PAN_SUPPORTS_ROLE_GN == TRUE)
+ if (uuid == UUID_SERVCLASS_GN) {
+ if ((!BTM_SetSecurityLevel(true, p_name, BTM_SEC_SERVICE_BNEP_GN, sec_mask,
+ BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_GN)) ||
+ (!BTM_SetSecurityLevel(false, p_name, BTM_SEC_SERVICE_BNEP_GN, sec_mask,
+ BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_GN))) {
+ PAN_TRACE_ERROR("PAN Security Registration failed for GN");
+ }
+ }
+#endif
+#if (PAN_SUPPORTS_ROLE_PANU == TRUE)
+ if (uuid == UUID_SERVCLASS_PANU) {
+ if ((!BTM_SetSecurityLevel(true, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_PANU)) ||
+ (!BTM_SetSecurityLevel(false, p_name, BTM_SEC_SERVICE_BNEP_PANU,
+ sec_mask, BT_PSM_BNEP, BTM_SEC_PROTO_BNEP,
+ UUID_SERVCLASS_PANU))) {
+ PAN_TRACE_ERROR("PAN Security Registration failed for PANU");
+ }
+ }
+#endif
+
+ /* Make the service browsable */
+ SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, &browse_list);
+
+ return sdp_handle;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_allocate_pcb
+ *
+ * Description
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tPAN_CONN* pan_allocate_pcb(BD_ADDR p_bda, uint16_t handle) {
+ uint16_t i;
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ pan_cb.pcb[i].handle == handle)
+ return NULL;
+ }
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ memcmp(pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+ return NULL;
+ }
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE) {
+ memset(&(pan_cb.pcb[i]), 0, sizeof(tPAN_CONN));
+ memcpy(pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN);
+ pan_cb.pcb[i].handle = handle;
+ return &(pan_cb.pcb[i]);
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_get_pcb_by_handle
+ *
+ * Description
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tPAN_CONN* pan_get_pcb_by_handle(uint16_t handle) {
+ uint16_t i;
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE &&
+ pan_cb.pcb[i].handle == handle)
+ return &(pan_cb.pcb[i]);
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_get_pcb_by_addr
+ *
+ * Description
+ *
+ * Returns
+ *
+ ******************************************************************************/
+tPAN_CONN* pan_get_pcb_by_addr(BD_ADDR p_bda) {
+ uint16_t i;
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state == PAN_STATE_IDLE) continue;
+
+ if (memcmp(pan_cb.pcb[i].rem_bda, p_bda, BD_ADDR_LEN) == 0)
+ return &(pan_cb.pcb[i]);
+
+ /*
+ if (pan_cb.pcb[i].mfilter_present &&
+ (memcmp (p_bda, pan_cb.pcb[i].multi_cast_bridge, BD_ADDR_LEN) == 0))
+ return &(pan_cb.pcb[i]);
+ */
+ }
+
+ return NULL;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_close_all_connections
+ *
+ * Description
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void pan_close_all_connections(void) {
+ uint16_t i;
+
+ for (i = 0; i < MAX_PAN_CONNS; i++) {
+ if (pan_cb.pcb[i].con_state != PAN_STATE_IDLE) {
+ BNEP_Disconnect(pan_cb.pcb[i].handle);
+ pan_cb.pcb[i].con_state = PAN_STATE_IDLE;
+ }
+ }
+
+ pan_cb.active_role = PAN_ROLE_INACTIVE;
+ pan_cb.num_conns = 0;
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_release_pcb
+ *
+ * Description This function releases a PCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void pan_release_pcb(tPAN_CONN* p_pcb) {
+ /* Drop any response pointer we may be holding */
+ memset(p_pcb, 0, sizeof(tPAN_CONN));
+ p_pcb->con_state = PAN_STATE_IDLE;
+}
+
+/*******************************************************************************
+ *
+ * Function pan_dump_status
+ *
+ * Description This function dumps the pan control block and connection
+ * blocks information
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+void pan_dump_status(void) {
+#if (PAN_SUPPORTS_DEBUG_DUMP == TRUE)
+ uint16_t i;
+ char buff[200];
+ tPAN_CONN* p_pcb;
+
+ PAN_TRACE_DEBUG("PAN role %x, active role %d, num_conns %d", pan_cb.role,
+ pan_cb.active_role, pan_cb.num_conns);
+
+ for (i = 0, p_pcb = pan_cb.pcb; i < MAX_PAN_CONNS; i++, p_pcb++) {
+ snprintf(buff, sizeof(buff),
+ "%d state %d, handle %d, src 0x%x, dst 0x%x, BD %x.%x.%x.%x.%x.%x",
+ i, p_pcb->con_state, p_pcb->handle, p_pcb->src_uuid,
+ p_pcb->dst_uuid, p_pcb->rem_bda[0], p_pcb->rem_bda[1],
+ p_pcb->rem_bda[2], p_pcb->rem_bda[3], p_pcb->rem_bda[4],
+ p_pcb->rem_bda[5]);
+
+ PAN_TRACE_DEBUG(buff);
+ }
+#endif
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/port_api.cc b/mtkbt/code/bt/stack/rfcomm/port_api.cc
new file mode 100755
index 0000000..a3962b2
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/port_api.cc
@@ -0,0 +1,1769 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains the Serial Port API code
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_port_api"
+
+#include <string.h>
+
+#include "osi/include/log.h"
+#include "osi/include/mutex.h"
+
+#include "bt_common.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "l2c_api.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+#include "sdp_api.h"
+
+/** M: Change for bug fix: some devices can not parse multi AT commands in a rfcomm packet. @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#endif
+/** @} */
+
+/* duration of break in 200ms units */
+#define PORT_BREAK_DURATION 1
+
+#define info(fmt, ...) LOG_INFO(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define debug(fmt, ...) LOG_DEBUG(LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+#define error(fmt, ...) \
+ LOG_ERROR(LOG_TAG, "## ERROR : %s: " fmt "##", __func__, ##__VA_ARGS__)
+#define asrt(s) \
+ if (!(s)) \
+ LOG_ERROR(LOG_TAG, "## %s assert %s failed at line:%d ##", __func__, #s, \
+ __LINE__)
+
+/* Mapping from PORT_* result codes to human readable strings. */
+static const char* result_code_strings[] = {"Success",
+ "Unknown error",
+ "Already opened",
+ "Command pending",
+ "App not registered",
+ "No memory",
+ "No resources",
+ "Bad BD address",
+ "Unspecified error",
+ "Bad handle",
+ "Not opened",
+ "Line error",
+ "Start failed",
+ "Parameter negotiation failed",
+ "Port negotiation failed",
+ "Sec failed",
+ "Peer connection failed",
+ "Peer failed",
+ "Peer timeout",
+ "Closed",
+ "TX full",
+ "Local closed",
+ "Local timeout",
+ "TX queue disabled",
+ "Page timeout",
+ "Invalid SCN",
+ "Unknown result code"};
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_CreateConnection
+ *
+ * Description RFCOMM_CreateConnection function is used from the
+ * application to establish serial port connection to the peer
+ * device, or allow RFCOMM to accept a connection from the peer
+ * application.
+ *
+ * Parameters: scn - Service Channel Number as registered with
+ * the SDP (server) or obtained using SDP from
+ * the peer device (client).
+ * is_server - true if requesting application is a server
+ * mtu - Maximum frame size the application can accept
+ * bd_addr - BD_ADDR of the peer (client)
+ * mask - specifies events to be enabled. A value
+ * of zero disables all events.
+ * p_handle - OUT pointer to the handle.
+ * p_mgmt_cb - pointer to callback function to receive
+ * connection up/down events.
+ * Notes:
+ *
+ * Server can call this function with the same scn parameter multiple times if
+ * it is ready to accept multiple simulteneous connections.
+ *
+ * DLCI for the connection is (scn * 2 + 1) if client originates connection on
+ * existing none initiator multiplexer channel. Otherwise it is (scn * 2).
+ * For the server DLCI can be changed later if client will be calling it using
+ * (scn * 2 + 1) dlci.
+ *
+ ******************************************************************************/
+int RFCOMM_CreateConnection(uint16_t uuid, uint8_t scn, bool is_server,
+ uint16_t mtu, BD_ADDR bd_addr, uint16_t* p_handle,
+ tPORT_CALLBACK* p_mgmt_cb) {
+ tPORT* p_port;
+ int i;
+ uint8_t dlci;
+ tRFC_MCB* p_mcb = port_find_mcb(bd_addr);
+ uint16_t rfcomm_mtu;
+
+ RFCOMM_TRACE_API(
+ "RFCOMM_CreateConnection() BDA: %02x-%02x-%02x-%02x-%02x-%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+
+ *p_handle = 0;
+
+ if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
+ /* Server Channel Number(SCN) should be in range 1...30 */
+ RFCOMM_TRACE_ERROR("RFCOMM_CreateConnection - invalid SCN");
+ return (PORT_INVALID_SCN);
+ }
+
+ /* For client that originate connection on the existing none initiator */
+ /* multiplexer channel DLCI should be odd */
+ if (p_mcb && !p_mcb->is_initiator && !is_server)
+ dlci = (scn << 1) + 1;
+ else
+ dlci = (scn << 1);
+ RFCOMM_TRACE_API(
+ "RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, "
+ "p_mcb:%p",
+ scn, dlci, is_server, mtu, p_mcb);
+
+ /* For the server side always allocate a new port. On the client side */
+ /* do not allow the same (dlci, bd_addr) to be opened twice by application */
+ if (!is_server) {
+ p_port = port_find_port(dlci, bd_addr);
+ if (p_port != NULL) {
+ /* if existing port is also a client port */
+ if (p_port->is_server == false) {
+ RFCOMM_TRACE_ERROR(
+ "RFCOMM_CreateConnection - already opened state:%d, RFC state:%d, "
+ "MCB state:%d",
+ p_port->state, p_port->rfc.state,
+ p_port->rfc.p_mcb ? p_port->rfc.p_mcb->state : 0);
+ *p_handle = p_port->inx;
+ return (PORT_ALREADY_OPENED);
+ }
+ }
+ }
+
+ p_port = port_allocate_port(dlci, bd_addr);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("RFCOMM_CreateConnection - no resources");
+ return (PORT_NO_RESOURCES);
+ }
+ RFCOMM_TRACE_API(
+ "RFCOMM_CreateConnection(): scn:%d, dlci:%d, is_server:%d mtu:%d, "
+ "p_mcb:%p, p_port:%p",
+ scn, dlci, is_server, mtu, p_mcb, p_port);
+
+ p_port->default_signal_state =
+ (PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ switch (uuid) {
+ case UUID_PROTOCOL_OBEX:
+ p_port->default_signal_state = PORT_OBEX_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_SERIAL_PORT:
+ p_port->default_signal_state = PORT_SPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_LAN_ACCESS_USING_PPP:
+ p_port->default_signal_state = PORT_PPP_DEFAULT_SIGNAL_STATE;
+ break;
+ case UUID_SERVCLASS_DIALUP_NETWORKING:
+ case UUID_SERVCLASS_FAX:
+ p_port->default_signal_state = PORT_DUN_DEFAULT_SIGNAL_STATE;
+ break;
+ }
+
+ RFCOMM_TRACE_EVENT("RFCOMM_CreateConnection dlci:%d signal state:0x%x", dlci,
+ p_port->default_signal_state);
+
+ *p_handle = p_port->inx;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->uuid = uuid;
+ p_port->is_server = is_server;
+ p_port->scn = scn;
+ p_port->ev_mask = 0;
+
+ /* If the MTU is not specified (0), keep MTU decision until the
+ * PN frame has to be send
+ * at that time connection should be established and we
+ * will know for sure our prefered MTU
+ */
+
+ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+
+ if (mtu)
+ p_port->mtu = (mtu < rfcomm_mtu) ? mtu : rfcomm_mtu;
+ else
+ p_port->mtu = rfcomm_mtu;
+
+ /* server doesn't need to release port when closing */
+ if (is_server) {
+ p_port->keep_port_handle = true;
+
+ /* keep mtu that user asked, p_port->mtu could be updated during param
+ * negotiation */
+ p_port->keep_mtu = p_port->mtu;
+ }
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ p_port->local_ctrl.fc = false;
+
+ p_port->p_mgmt_callback = p_mgmt_cb;
+
+ for (i = 0; i < BD_ADDR_LEN; i++) p_port->bd_addr[i] = bd_addr[i];
+
+ /* If this is not initiator of the connection need to just wait */
+ if (p_port->is_server) {
+ return (PORT_SUCCESS);
+ }
+
+ /* Open will be continued after security checks are passed */
+ return port_open_continue(p_port);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_RemoveConnection
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+int RFCOMM_RemoveConnection(uint16_t handle) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("RFCOMM_RemoveConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ RFCOMM_TRACE_ERROR("RFCOMM_RemoveConnection() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ RFCOMM_TRACE_EVENT("RFCOMM_RemoveConnection() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close(p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_RemoveServer
+ *
+ * Description This function is called to close the server port.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+int RFCOMM_RemoveServer(uint16_t handle) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("RFCOMM_RemoveServer() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ RFCOMM_TRACE_ERROR("RFCOMM_RemoveServer() BAD handle:%d", handle);
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ /* Do not report any events to the client any more. */
+ p_port->p_mgmt_callback = NULL;
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ RFCOMM_TRACE_EVENT("RFCOMM_RemoveServer() Not opened:%d", handle);
+ return (PORT_SUCCESS);
+ }
+
+ /* this port will be deallocated after closing */
+ p_port->keep_port_handle = false;
+ p_port->state = PORT_STATE_CLOSING;
+
+ port_start_close(p_port);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SetEventCallback
+ *
+ * Description This function is called to provide an address of the
+ * function which will be called when one of the events
+ * specified in the mask occures.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_callback - address of the callback function which should
+ * be called from the RFCOMM when an event
+ * specified in the mask occures.
+ *
+ *
+ ******************************************************************************/
+int PORT_SetEventCallback(uint16_t port_handle, tPORT_CALLBACK* p_port_cb) {
+ tPORT* p_port;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_TRACE_API("PORT_SetEventCallback() handle:%d", port_handle);
+
+ p_port->p_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+ *
+ * Function PORT_ClearKeepHandleFlag
+ *
+ * Description Clear the keep handle flag, which will cause not to keep the
+ * port handle open when closed
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ *
+ ******************************************************************************/
+
+int PORT_ClearKeepHandleFlag(uint16_t port_handle) {
+ tPORT* p_port;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+ p_port->keep_port_handle = 0;
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SetDataCallback
+ *
+ * Description This function is when a data packet is received
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_callback - address of the callback function which should
+ * be called from the RFCOMM when data packet
+ * is received.
+ *
+ *
+ ******************************************************************************/
+int PORT_SetDataCallback(uint16_t port_handle, tPORT_DATA_CALLBACK* p_port_cb) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_SetDataCallback() handle:%d cb 0x%x", port_handle,
+ p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+ *
+ * Function PORT_SetCODataCallback
+ *
+ * Description This function is when a data packet is received
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_callback - address of the callback function which should
+ * be called from the RFCOMM when data packet
+ * is received.
+ *
+ *
+ ******************************************************************************/
+int PORT_SetDataCOCallback(uint16_t port_handle,
+ tPORT_DATA_CO_CALLBACK* p_port_cb) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_SetDataCOCallback() handle:%d cb 0x%x", port_handle,
+ p_port_cb);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->p_data_co_callback = p_port_cb;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SetEventMask
+ *
+ * Description This function is called to close the specified connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * mask - Bitmask of the events the host is interested in
+ *
+ ******************************************************************************/
+int PORT_SetEventMask(uint16_t port_handle, uint32_t mask) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_SetEventMask() handle:%d mask:0x%x", port_handle,
+ mask);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((port_handle == 0) || (port_handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[port_handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->ev_mask = mask;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_CheckConnection
+ *
+ * Description This function returns PORT_SUCCESS if connection referenced
+ * by handle is up and running
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * bd_addr - OUT bd_addr of the peer
+ * p_lcid - OUT L2CAP's LCID
+ *
+ ******************************************************************************/
+int PORT_CheckConnection(uint16_t handle, BD_ADDR bd_addr, uint16_t* p_lcid) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_CheckConnection() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb || !p_port->rfc.p_mcb->peer_ready ||
+ (p_port->rfc.state != RFC_STATE_OPENED)) {
+ return (PORT_LINE_ERR);
+ }
+
+ memcpy(bd_addr, p_port->rfc.p_mcb->bd_addr, BD_ADDR_LEN);
+ if (p_lcid) *p_lcid = p_port->rfc.p_mcb->lcid;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_IsOpening
+ *
+ * Description This function returns true if there is any RFCOMM connection
+ * opening in process.
+ *
+ * Parameters: true if any connection opening is found
+ * bd_addr - bd_addr of the peer
+ *
+ ******************************************************************************/
+bool PORT_IsOpening(BD_ADDR bd_addr) {
+ uint8_t xx, yy;
+ tRFC_MCB* p_mcb = NULL;
+ tPORT* p_port;
+ bool found_port;
+
+ /* Check for any rfc_mcb which is in the middle of opening. */
+ for (xx = 0; xx < MAX_BD_CONNECTIONS; xx++) {
+ if ((rfc_cb.port.rfc_mcb[xx].state > RFC_MX_STATE_IDLE) &&
+ (rfc_cb.port.rfc_mcb[xx].state < RFC_MX_STATE_CONNECTED)) {
+ memcpy(bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return true;
+ }
+
+ if (rfc_cb.port.rfc_mcb[xx].state == RFC_MX_STATE_CONNECTED) {
+ found_port = false;
+ p_mcb = &rfc_cb.port.rfc_mcb[xx];
+ p_port = &rfc_cb.port.port[0];
+
+ for (yy = 0; yy < MAX_RFC_PORTS; yy++, p_port++) {
+ if (p_port->rfc.p_mcb == p_mcb) {
+ found_port = true;
+ break;
+ }
+ }
+
+ if ((!found_port) ||
+ (found_port && (p_port->rfc.state < RFC_STATE_OPENED))) {
+ /* Port is not established yet. */
+ memcpy(bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SetState
+ *
+ * Description This function configures connection according to the
+ * specifications in the tPORT_STATE structure.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_settings - Pointer to a tPORT_STATE structure containing
+ * configuration information for the connection.
+ *
+ *
+ ******************************************************************************/
+int PORT_SetState(uint16_t handle, tPORT_STATE* p_settings) {
+ tPORT* p_port;
+ uint8_t baud_rate;
+
+ RFCOMM_TRACE_API("PORT_SetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ return (PORT_LINE_ERR);
+ }
+
+ RFCOMM_TRACE_API("PORT_SetState() handle:%d FC_TYPE:0x%x", handle,
+ p_settings->fc_type);
+
+ baud_rate = p_port->user_port_pars.baud_rate;
+ p_port->user_port_pars = *p_settings;
+
+ /* for now we've been asked to pass only baud rate */
+ if (baud_rate != p_settings->baud_rate) {
+ port_start_par_neg(p_port);
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_GetRxQueueCnt
+ *
+ * Description This function return number of buffers on the rx queue.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_rx_queue_count - Pointer to return queue count in.
+ *
+ ******************************************************************************/
+int PORT_GetRxQueueCnt(uint16_t handle, uint16_t* p_rx_queue_count) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_GetRxQueueCnt() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_rx_queue_count = p_port->rx.queue_size;
+
+ RFCOMM_TRACE_API(
+ "PORT_GetRxQueueCnt() p_rx_queue_count:%d, p_port->rx.queue.count = %d",
+ *p_rx_queue_count, p_port->rx.queue_size);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_GetState
+ *
+ * Description This function is called to fill tPORT_STATE structure
+ * with the curremt control settings for the port
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_settings - Pointer to a tPORT_STATE structure in which
+ * configuration information is returned.
+ *
+ ******************************************************************************/
+int PORT_GetState(uint16_t handle, tPORT_STATE* p_settings) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_GetState() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ return (PORT_LINE_ERR);
+ }
+
+ *p_settings = p_port->user_port_pars;
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_Control
+ *
+ * Description This function directs a specified connection to pass control
+ * control information to the peer device.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * signal = specify the function to be passed
+ *
+ ******************************************************************************/
+int PORT_Control(uint16_t handle, uint8_t signal) {
+ tPORT* p_port;
+ uint8_t old_modem_signal;
+
+ RFCOMM_TRACE_API("PORT_Control() handle:%d signal:0x%x", handle, signal);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ old_modem_signal = p_port->local_ctrl.modem_signal;
+ p_port->local_ctrl.break_signal = 0;
+
+ switch (signal) {
+ case PORT_SET_CTSRTS:
+ p_port->local_ctrl.modem_signal |= PORT_CTSRTS_ON;
+ break;
+
+ case PORT_CLR_CTSRTS:
+ p_port->local_ctrl.modem_signal &= ~PORT_CTSRTS_ON;
+ break;
+
+ case PORT_SET_DTRDSR:
+ p_port->local_ctrl.modem_signal |= PORT_DTRDSR_ON;
+ break;
+
+ case PORT_CLR_DTRDSR:
+ p_port->local_ctrl.modem_signal &= ~PORT_DTRDSR_ON;
+ break;
+
+ case PORT_SET_RI:
+ p_port->local_ctrl.modem_signal |= PORT_RING_ON;
+ break;
+
+ case PORT_CLR_RI:
+ p_port->local_ctrl.modem_signal &= ~PORT_RING_ON;
+ break;
+
+ case PORT_SET_DCD:
+ p_port->local_ctrl.modem_signal |= PORT_DCD_ON;
+ break;
+
+ case PORT_CLR_DCD:
+ p_port->local_ctrl.modem_signal &= ~PORT_DCD_ON;
+ break;
+ }
+
+ if (signal == PORT_BREAK)
+ p_port->local_ctrl.break_signal = PORT_BREAK_DURATION;
+ else if (p_port->local_ctrl.modem_signal == old_modem_signal)
+ return (PORT_SUCCESS);
+
+ port_start_control(p_port);
+
+ RFCOMM_TRACE_EVENT(
+ "PORT_Control DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->local_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_FlowControl
+ *
+ * Description This function directs a specified connection to pass
+ * flow control message to the peer device. Enable flag passed
+ * shows if port can accept more data.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * enable - enables data flow
+ *
+ ******************************************************************************/
+int PORT_FlowControl(uint16_t handle, bool enable) {
+ tPORT* p_port;
+ bool old_fc;
+ uint32_t events;
+
+ RFCOMM_TRACE_API("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
+ if (!p_port->rx.user_fc) {
+ port_flow_control_peer(p_port, true, 0);
+ }
+ } else {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc) port_start_control(p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0)) {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending) {
+ p_port->rx_flag_ev_pending = false;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events) {
+ p_port->p_callback(events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+ *
+ * Function PORT_FlowControl_MaxCredit
+ *
+ * Description This function directs a specified connection to pass
+ * flow control message to the peer device. Enable flag passed
+ * shows if port can accept more data. It also sends max credit
+ * when data flow enabled
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * enable - enables data flow
+ *
+ ******************************************************************************/
+
+int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable) {
+ tPORT* p_port;
+ bool old_fc;
+ uint32_t events;
+
+ RFCOMM_TRACE_API("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
+ if (!p_port->rx.user_fc) {
+ port_flow_control_peer(p_port, true, p_port->credit_rx);
+ }
+ } else {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc) port_start_control(p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0)) {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending) {
+ p_port->rx_flag_ev_pending = false;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events) {
+ p_port->p_callback(events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_GetModemStatus
+ *
+ * Description This function retrieves modem control signals. Normally
+ * application will call this function after a callback
+ * function is called with notification that one of signals
+ * has been changed.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_signal - specify the pointer to control signals info
+ *
+ ******************************************************************************/
+int PORT_GetModemStatus(uint16_t handle, uint8_t* p_signal) {
+ tPORT* p_port;
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_signal = p_port->peer_ctrl.modem_signal;
+
+ RFCOMM_TRACE_API("PORT_GetModemStatus() handle:%d signal:%x", handle,
+ *p_signal);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ClearError
+ *
+ * Description This function retreives information about a communications
+ * error and reports current status of a connection. The
+ * function should be called when an error occures to clear
+ * the connection error flag and to enable additional read
+ * and write operations.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_errors - pointer of the variable to receive error codes
+ * p_status - pointer to the tPORT_STATUS structur to receive
+ * connection status
+ *
+ ******************************************************************************/
+int PORT_ClearError(uint16_t handle, uint16_t* p_errors,
+ tPORT_STATUS* p_status) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_ClearError() handle:%d", handle);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ *p_errors = p_port->line_status;
+
+ /* This is the only call to clear error status. We can not clear */
+ /* connection failed status. To clean it port should be closed and reopened
+ */
+ p_port->line_status = (p_port->line_status & LINE_STATUS_FAILED);
+
+ PORT_GetQueueStatus(handle, p_status);
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SendError
+ *
+ * Description This function send a communications error to the peer device
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * errors - receive error codes
+ *
+ ******************************************************************************/
+int PORT_SendError(uint16_t handle, uint8_t errors) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_SendError() handle:%d errors:0x%x", handle, errors);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb) {
+ return (PORT_NOT_OPENED);
+ }
+
+ RFCOMM_LineStatusReq(p_port->rfc.p_mcb, p_port->dlci, errors);
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_GetQueueStatus
+ *
+ * Description This function reports current status of a connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_status - pointer to the tPORT_STATUS structur to receive
+ * connection status
+ *
+ ******************************************************************************/
+int PORT_GetQueueStatus(uint16_t handle, tPORT_STATUS* p_status) {
+ tPORT* p_port;
+
+ /* RFCOMM_TRACE_API ("PORT_GetQueueStatus() handle:%d", handle); */
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_status->in_queue_size = (uint16_t)p_port->rx.queue_size;
+ p_status->out_queue_size = (uint16_t)p_port->tx.queue_size;
+
+ p_status->mtu_size = (uint16_t)p_port->peer_mtu;
+
+ p_status->flags = 0;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_CTSRTS_ON))
+ p_status->flags |= PORT_FLAG_CTS_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DTRDSR_ON))
+ p_status->flags |= PORT_FLAG_DSR_HOLD;
+
+ if (!(p_port->peer_ctrl.modem_signal & PORT_DCD_ON))
+ p_status->flags |= PORT_FLAG_RLSD_HOLD;
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_Purge
+ *
+ * Description This function discards all the data from the output or
+ * input queues of the specified connection.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * purge_flags - specify the action to take.
+ *
+ ******************************************************************************/
+int PORT_Purge(uint16_t handle, uint8_t purge_flags) {
+ tPORT* p_port;
+ BT_HDR* p_buf;
+ uint16_t count;
+ uint32_t events;
+
+ RFCOMM_TRACE_API("PORT_Purge() handle:%d flags:0x%x", handle, purge_flags);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (purge_flags & PORT_PURGE_RXCLEAR) {
+ mutex_global_lock(); /* to prevent missing credit */
+
+ count = fixed_queue_length(p_port->rx.queue);
+
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
+ osi_free(p_buf);
+
+ p_port->rx.queue_size = 0;
+
+ mutex_global_unlock();
+
+ /* If we flowed controlled peer based on rx_queue size enable data again */
+ if (count) port_flow_control_peer(p_port, true, count);
+ }
+
+ if (purge_flags & PORT_PURGE_TXCLEAR) {
+ mutex_global_lock(); /* to prevent tx.queue_size from being negative */
+
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+ osi_free(p_buf);
+
+ p_port->tx.queue_size = 0;
+
+ mutex_global_unlock();
+
+ events = PORT_EV_TXEMPTY;
+
+ events |= port_flow_control_user(p_port);
+
+ events &= p_port->ev_mask;
+
+ if ((p_port->p_callback != NULL) && events)
+ (p_port->p_callback)(events, p_port->inx);
+ }
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ReadData
+ *
+ * Description Normally not GKI aware application will call this function
+ * after receiving PORT_EV_RXCHAR event.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_data - Data area
+ * max_len - Byte count requested
+ * p_len - Byte count received
+ *
+ ******************************************************************************/
+int PORT_ReadData(uint16_t handle, char* p_data, uint16_t max_len,
+ uint16_t* p_len) {
+ tPORT* p_port;
+ BT_HDR* p_buf;
+ uint16_t count;
+
+ RFCOMM_TRACE_API("PORT_ReadData() handle:%d max_len:%d", handle, max_len);
+
+ /* Initialize this in case of an error */
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ return (PORT_LINE_ERR);
+ }
+
+ if (fixed_queue_is_empty(p_port->rx.queue)) return (PORT_SUCCESS);
+
+ count = 0;
+
+ while (max_len) {
+ p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_port->rx.queue);
+ if (p_buf == NULL) break;
+
+ if (p_buf->len > max_len) {
+ memcpy(p_data, (uint8_t*)(p_buf + 1) + p_buf->offset, max_len);
+ p_buf->offset += max_len;
+ p_buf->len -= max_len;
+
+ *p_len += max_len;
+
+ mutex_global_lock();
+
+ p_port->rx.queue_size -= max_len;
+
+ mutex_global_unlock();
+
+ break;
+ } else {
+ memcpy(p_data, (uint8_t*)(p_buf + 1) + p_buf->offset, p_buf->len);
+
+ *p_len += p_buf->len;
+ max_len -= p_buf->len;
+
+ mutex_global_lock();
+
+ p_port->rx.queue_size -= p_buf->len;
+
+ if (max_len) {
+ p_data += p_buf->len;
+ }
+
+ osi_free(fixed_queue_try_dequeue(p_port->rx.queue));
+
+ mutex_global_unlock();
+
+ count++;
+ }
+ }
+
+ if (*p_len == 1) {
+ RFCOMM_TRACE_EVENT("PORT_ReadData queue:%d returned:%d %x",
+ p_port->rx.queue_size, *p_len, (p_data[0]));
+ } else {
+ RFCOMM_TRACE_EVENT("PORT_ReadData queue:%d returned:%d",
+ p_port->rx.queue_size, *p_len);
+ }
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer(p_port, true, count);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_Read
+ *
+ * Description Normally application will call this function after receiving
+ * PORT_EV_RXCHAR event.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * pp_buf - pointer to address of buffer with data,
+ *
+ ******************************************************************************/
+int PORT_Read(uint16_t handle, BT_HDR** pp_buf) {
+ tPORT* p_port;
+ BT_HDR* p_buf;
+
+ RFCOMM_TRACE_API("PORT_Read() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ return (PORT_LINE_ERR);
+ }
+
+ mutex_global_lock();
+
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue);
+ if (p_buf) {
+ p_port->rx.queue_size -= p_buf->len;
+
+ mutex_global_unlock();
+
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ port_flow_control_peer(p_port, true, 1);
+ } else {
+ mutex_global_unlock();
+ }
+
+ *pp_buf = p_buf;
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function port_write
+ *
+ * Description This function when a data packet is received from the apper
+ * layer task.
+ *
+ * Parameters: p_port - pointer to address of port control block
+ * p_buf - pointer to address of buffer with data,
+ *
+ ******************************************************************************/
+static int port_write(tPORT* p_port, BT_HDR* p_buf) {
+ /* We should not allow to write data in to server port when connection is not
+ * opened */
+ if (p_port->is_server && (p_port->rfc.state != RFC_STATE_OPENED)) {
+ osi_free(p_buf);
+ return (PORT_CLOSED);
+ }
+
+ /* Keep the data in pending queue if peer does not allow data, or */
+ /* Peer is not ready or Port is not yet opened or initial port control */
+ /* command has not been sent */
+ if (p_port->tx.peer_fc || !p_port->rfc.p_mcb ||
+ !p_port->rfc.p_mcb->peer_ready ||
+ (p_port->rfc.state != RFC_STATE_OPENED) ||
+ ((p_port->port_ctrl & (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED)) !=
+ (PORT_CTRL_REQ_SENT | PORT_CTRL_IND_RECEIVED))) {
+ if ((p_port->tx.queue_size > PORT_TX_CRITICAL_WM) ||
+ (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_CRITICAL_WM)) {
+ RFCOMM_TRACE_WARNING("PORT_Write: Queue size: %d", p_port->tx.queue_size);
+
+ osi_free(p_buf);
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & PORT_EV_ERR))
+ p_port->p_callback(PORT_EV_ERR, p_port->inx);
+
+ return (PORT_TX_FULL);
+ }
+
+ RFCOMM_TRACE_EVENT(
+ "PORT_Write : Data is enqued. flow disabled %d peer_ready %d state %d "
+ "ctrl_state %x",
+ p_port->tx.peer_fc,
+ (p_port->rfc.p_mcb && p_port->rfc.p_mcb->peer_ready), p_port->rfc.state,
+ p_port->port_ctrl);
+
+ fixed_queue_enqueue(p_port->tx.queue, p_buf);
+ p_port->tx.queue_size += p_buf->len;
+
+ return (PORT_CMD_PENDING);
+ } else {
+ RFCOMM_TRACE_EVENT("PORT_Write : Data is being sent");
+
+ RFCOMM_DataReq(p_port->rfc.p_mcb, p_port->dlci, p_buf);
+ return (PORT_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_Write
+ *
+ * Description This function when a data packet is received from the apper
+ * layer task.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * pp_buf - pointer to address of buffer with data,
+ *
+ ******************************************************************************/
+int PORT_Write(uint16_t handle, BT_HDR* p_buf) {
+ tPORT* p_port;
+ uint32_t event = 0;
+ int rc;
+
+ RFCOMM_TRACE_API("PORT_Write() handle:%d", handle);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ osi_free(p_buf);
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ osi_free(p_buf);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (p_port->line_status) {
+ RFCOMM_TRACE_WARNING("PORT_Write: Data dropped line_status:0x%x",
+ p_port->line_status);
+ osi_free(p_buf);
+ return (PORT_LINE_ERR);
+ }
+
+ rc = port_write(p_port, p_buf);
+ event |= port_flow_control_user(p_port);
+
+ switch (rc) {
+ case PORT_TX_FULL:
+ event |= PORT_EV_ERR;
+ break;
+
+ case PORT_SUCCESS:
+ event |= (PORT_EV_TXCHAR | PORT_EV_TXEMPTY);
+ break;
+ }
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+/*******************************************************************************
+ *
+ * Function PORT_WriteDataCO
+ *
+ * Description Normally not GKI aware application will call this function
+ * to send data to the port by callout functions
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * fd - socket fd
+ * p_len - Byte count returned
+ *
+ ******************************************************************************/
+int PORT_WriteDataCO(uint16_t handle, int* p_len) {
+ tPORT* p_port;
+ BT_HDR* p_buf;
+ uint32_t event = 0;
+ int rc = 0;
+ uint16_t length;
+
+ RFCOMM_TRACE_API("PORT_WriteDataCO() handle:%d", handle);
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ RFCOMM_TRACE_WARNING("PORT_WriteDataByFd() no port state:%d",
+ p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->peer_mtu) {
+ RFCOMM_TRACE_ERROR("PORT_WriteDataByFd() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ int available = 0;
+ // if(ioctl(fd, FIONREAD, &available) < 0)
+ if (p_port->p_data_co_callback(
+ handle, (uint8_t*)&available, sizeof(available),
+ DATA_CO_CALLBACK_TYPE_OUTGOING_SIZE) == false) {
+ RFCOMM_TRACE_ERROR(
+ "p_data_co_callback DATA_CO_CALLBACK_TYPE_INCOMING_SIZE failed, "
+ "available:%d",
+ available);
+ return (PORT_UNKNOWN_ERROR);
+ }
+ if (available == 0) return PORT_SUCCESS;
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len
+ */
+ length = RFCOMM_DATA_BUF_SIZE -
+ (uint16_t)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ mutex_global_lock();
+
+ p_buf = (BT_HDR*)fixed_queue_try_peek_last(p_port->tx.queue);
+ if ((p_buf != NULL) &&
+ (((int)p_buf->len + available) <= (int)p_port->peer_mtu) &&
+ (((int)p_buf->len + available) <= (int)length)) {
+ // if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len,
+ // available, 0) != available)
+ if (p_port->p_data_co_callback(
+ handle, (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len,
+ available, DATA_CO_CALLBACK_TYPE_OUTGOING) == false)
+
+ {
+ error(
+ "p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, "
+ "available:%d",
+ available);
+ mutex_global_unlock();
+ return (PORT_UNKNOWN_ERROR);
+ }
+ // memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset + p_buf->len, p_data,
+ // max_len);
+ p_port->tx.queue_size += (uint16_t)available;
+
+ *p_len = available;
+ p_buf->len += (uint16_t)available;
+
+ mutex_global_unlock();
+
+ return (PORT_SUCCESS);
+ }
+
+ mutex_global_unlock();
+
+ // int max_read = length < p_port->peer_mtu ? length : p_port->peer_mtu;
+
+ // max_read = available < max_read ? available : max_read;
+
+ while (available) {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
+ (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM)) {
+ port_flow_control_user(p_port);
+ event |= PORT_EV_FC;
+ RFCOMM_TRACE_EVENT(
+ "tx queue is full,tx.queue_size:%d,tx.queue.count:%d,available:%d",
+ p_port->tx.queue_size, fixed_queue_length(p_port->tx.queue),
+ available);
+ break;
+ }
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR*)osi_malloc(RFCOMM_DATA_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length) length = p_port->peer_mtu;
+ if (available < (int)length) length = (uint16_t)available;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ // memcpy ((uint8_t *)(p_buf + 1) + p_buf->offset, p_data, length);
+ // if(recv(fd, (uint8_t *)(p_buf + 1) + p_buf->offset, (int)length, 0) !=
+ // (int)length)
+ if (p_port->p_data_co_callback(
+ handle, (uint8_t*)(p_buf + 1) + p_buf->offset, length,
+ DATA_CO_CALLBACK_TYPE_OUTGOING) == false) {
+ error(
+ "p_data_co_callback DATA_CO_CALLBACK_TYPE_OUTGOING failed, length:%d",
+ length);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ RFCOMM_TRACE_EVENT("PORT_WriteData %d bytes", length);
+
+ rc = port_write(p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user(p_port);
+
+ if (rc == PORT_SUCCESS) event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING)) break;
+
+ *p_len += length;
+ available -= (int)length;
+ }
+ if (!available && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_WriteData
+ *
+ * Description Normally not GKI aware application will call this function
+ * to send data to the port.
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_data - Data area
+ * max_len - Byte count requested
+ * p_len - Byte count received
+ *
+ ******************************************************************************/
+int PORT_WriteData(uint16_t handle, const char* p_data, uint16_t max_len,
+ uint16_t* p_len) {
+ tPORT* p_port;
+ BT_HDR* p_buf;
+ uint32_t event = 0;
+ int rc = 0;
+ uint16_t length;
+
+ RFCOMM_TRACE_API("PORT_WriteData() max_len:%d", max_len);
+
+ *p_len = 0;
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ RFCOMM_TRACE_WARNING("PORT_WriteData() no port state:%d", p_port->state);
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!max_len || !p_port->peer_mtu) {
+ RFCOMM_TRACE_ERROR("PORT_WriteData() peer_mtu:%d", p_port->peer_mtu);
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len
+ */
+ length = RFCOMM_DATA_BUF_SIZE -
+ (uint16_t)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD);
+
+/** M: Change for bug fix: some devices can not parse multi AT commands in a rfcomm packet. @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if (((p_port->uuid == UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY)
+ || (p_port->uuid == UUID_SERVCLASS_AG_HANDSFREE))
+ && interop_mtk_match_addr_name(INTEROP_MTK_FORBID_COMBINE_RFCOMM_DATA,
+ ((const bt_bdaddr_t *)p_port->bd_addr)))
+ {
+ RFCOMM_TRACE_ERROR ("PORT_WriteData() peer_device can not parse the multi-response");
+ }
+ else {
+#endif
+/** @} */
+
+ /* If there are buffers scheduled for transmission check if requested */
+ /* data fits into the end of the queue */
+ mutex_global_lock();
+
+ p_buf = (BT_HDR*)fixed_queue_try_peek_last(p_port->tx.queue);
+ if ((p_buf != NULL) && ((p_buf->len + max_len) <= p_port->peer_mtu) &&
+ ((p_buf->len + max_len) <= length)) {
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len, p_data, max_len);
+ p_port->tx.queue_size += max_len;
+
+ *p_len = max_len;
+ p_buf->len += max_len;
+
+ mutex_global_unlock();
+
+ return (PORT_SUCCESS);
+ }
+
+ mutex_global_unlock();
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ }
+#endif
+
+ while (max_len) {
+ /* if we're over buffer high water mark, we're done */
+ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
+ (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM))
+ break;
+
+ /* continue with rfcomm data write */
+ p_buf = (BT_HDR*)osi_malloc(RFCOMM_DATA_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET;
+ p_buf->layer_specific = handle;
+
+ if (p_port->peer_mtu < length) length = p_port->peer_mtu;
+ if (max_len < length) length = max_len;
+ p_buf->len = length;
+ p_buf->event = BT_EVT_TO_BTU_SP_DATA;
+
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, length);
+
+ RFCOMM_TRACE_EVENT("PORT_WriteData %d bytes", length);
+
+ rc = port_write(p_port, p_buf);
+
+ /* If queue went below the threashold need to send flow control */
+ event |= port_flow_control_user(p_port);
+
+ if (rc == PORT_SUCCESS) event |= PORT_EV_TXCHAR;
+
+ if ((rc != PORT_SUCCESS) && (rc != PORT_CMD_PENDING)) break;
+
+ *p_len += length;
+ max_len -= length;
+ p_data += length;
+ }
+ if (!max_len && (rc != PORT_CMD_PENDING) && (rc != PORT_TX_QUEUE_DISABLED))
+ event |= PORT_EV_TXEMPTY;
+
+ /* Mask out all events that are not of interest to user */
+ event &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && event) (p_port->p_callback)(event, p_port->inx);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_Test
+ *
+ * Description Application can call this function to send RFCOMM Test frame
+ *
+ * Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+ * p_data - Data area
+ * max_len - Byte count requested
+ *
+ ******************************************************************************/
+int PORT_Test(uint16_t handle, uint8_t* p_data, uint16_t len) {
+ tPORT* p_port;
+
+ RFCOMM_TRACE_API("PORT_Test() len:%d", len);
+
+ if ((handle == 0) || (handle > MAX_RFC_PORTS)) {
+ return (PORT_BAD_HANDLE);
+ }
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED)) {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (len > ((p_port->mtu == 0) ? RFCOMM_DEFAULT_MTU : p_port->mtu)) {
+ return (PORT_UNKNOWN_ERROR);
+ }
+
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ p_buf->len = len;
+
+ memcpy((uint8_t*)(p_buf + 1) + p_buf->offset, p_data, p_buf->len);
+
+ rfc_send_test(p_port->rfc.p_mcb, true, p_buf);
+
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_Init
+ *
+ * Description This function is called to initialize RFCOMM layer
+ *
+ ******************************************************************************/
+void RFCOMM_Init(void) {
+ memset(&rfc_cb, 0, sizeof(tRFC_CB)); /* Init RFCOMM control block */
+
+ rfc_cb.rfc.last_mux = MAX_BD_CONNECTIONS;
+
+#if defined(RFCOMM_INITIAL_TRACE_LEVEL)
+ rfc_cb.trace_level = RFCOMM_INITIAL_TRACE_LEVEL;
+#else
+ rfc_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ rfcomm_l2cap_if_init();
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_SetTraceLevel
+ *
+ * Description Set the trace level for RFCOMM. If called with 0xFF, it
+ * simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t PORT_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) rfc_cb.trace_level = new_level;
+
+ return (rfc_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_GetResultString
+ *
+ * Description This function returns the human-readable string for a given
+ * result code.
+ *
+ * Returns a pointer to the human-readable string for the given result.
+ *
+ ******************************************************************************/
+const char* PORT_GetResultString(const uint8_t result_code) {
+ if (result_code > PORT_ERR_MAX) {
+ return result_code_strings[PORT_ERR_MAX];
+ }
+
+ return result_code_strings[result_code];
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/port_int.h b/mtkbt/code/bt/stack/rfcomm/port_int.h
new file mode 100755
index 0000000..8534e30
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/port_int.h
@@ -0,0 +1,241 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains definitions internal to the PORT unit
+ *
+ *****************************************************************************/
+
+#ifndef PORT_INT_H
+#define PORT_INT_H
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "osi/include/alarm.h"
+#include "osi/include/fixed_queue.h"
+#include "port_api.h"
+#include "rfcdefs.h"
+
+/* Local events passed when application event is sent from the api to PORT */
+/* ???*/
+#define PORT_EVENT_OPEN (1 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_CONTROL (2 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_STATE (3 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SET_CALLBACK (5 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_WRITE (6 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_PURGE (7 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_SEND_ERROR (8 | BT_EVT_TO_BTU_SP_EVT)
+#define PORT_EVENT_FLOW_CONTROL (9 | BT_EVT_TO_BTU_SP_EVT)
+
+/*
+ * Flow control configuration values for the mux
+*/
+#define PORT_FC_UNDEFINED 0 /* mux flow control mechanism not defined yet */
+#define PORT_FC_TS710 1 /* use TS 07.10 flow control */
+#define PORT_FC_CREDIT 2 /* use RFCOMM credit based flow control */
+
+/*
+ * Define Port Data Transfere control block
+*/
+typedef struct {
+ fixed_queue_t* queue; /* Queue of buffers waiting to be sent */
+ bool peer_fc; /* true if flow control is set based on peer's request */
+ bool user_fc; /* true if flow control is set based on user's request */
+ uint32_t queue_size; /* Number of data bytes in the queue */
+ tPORT_CALLBACK* p_callback; /* Address of the callback function */
+} tPORT_DATA;
+
+/*
+ * Port control structure used to pass modem info
+*/
+typedef struct {
+#define MODEM_SIGNAL_DTRDSR 0x01
+#define MODEM_SIGNAL_RTSCTS 0x02
+#define MODEM_SIGNAL_RI 0x04
+#define MODEM_SIGNAL_DCD 0x08
+
+ uint8_t modem_signal; /* [DTR/DSR | RTS/CTS | RI | DCD ] */
+
+ uint8_t break_signal; /* 0-3 s in steps of 200 ms */
+
+ uint8_t discard_buffers; /* 0 - do not discard, 1 - discard */
+
+#define RFCOMM_CTRL_BREAK_ASAP 0
+#define RFCOMM_CTRL_BREAK_IN_SEQ 1
+
+ uint8_t break_signal_seq; /* as soon as possible | in sequence (default) */
+
+ bool fc; /* true when the device is unable to accept frames */
+} tPORT_CTRL;
+
+/*
+ * RFCOMM multiplexer Control Block
+*/
+typedef struct {
+ alarm_t* mcb_timer; /* MCB timer */
+ fixed_queue_t* cmd_q; /* Queue for command messages on this mux */
+ uint8_t port_inx[RFCOMM_MAX_DLCI + 1]; /* Array for quick access to */
+ /* tPORT based on dlci */
+ BD_ADDR bd_addr; /* BD ADDR of the peer if initiator */
+ uint16_t lcid; /* Local cid used for this channel */
+ uint16_t peer_l2cap_mtu; /* Max frame that can be sent to peer L2CAP */
+ uint8_t state; /* Current multiplexer channel state */
+ uint8_t is_initiator; /* true if this side sends SABME (dlci=0) */
+ bool local_cfg_sent;
+ bool peer_cfg_rcvd;
+ bool restart_required; /* true if has to restart channel after disc */
+ bool peer_ready; /* True if other side can accept frames */
+ uint8_t flow; /* flow control mechanism for this mux */
+ bool l2cap_congested; /* true if L2CAP is congested */
+ bool is_disc_initiator; /* true if initiated disc of port */
+ uint16_t
+ pending_lcid; /* store LCID for incoming connection while connecting */
+ uint8_t
+ pending_id; /* store l2cap ID for incoming connection while connecting */
+} tRFC_MCB;
+
+/*
+ * RFCOMM Port Connection Control Block
+*/
+typedef struct {
+#define RFC_PORT_STATE_IDLE 0
+#define RFC_PORT_STATE_WAIT_START 1
+#define RFC_PORT_STATE_OPENING 2
+#define RFC_PORT_STATE_OPENED 3
+#define RFC_PORT_STATE_CLOSING 4
+
+ uint8_t state; /* Current state of the connection */
+
+#define RFC_RSP_PN 0x01
+#define RFC_RSP_RPN_REPLY 0x02
+#define RFC_RSP_RPN 0x04
+#define RFC_RSP_MSC 0x08
+#define RFC_RSP_RLS 0x10
+
+ uint8_t expected_rsp;
+
+ tRFC_MCB* p_mcb;
+
+ alarm_t* port_timer;
+} tRFC_PORT;
+
+/*
+ * Define control block containing information about PORT connection
+*/
+typedef struct {
+ uint8_t inx; /* Index of this control block in the port_info array */
+ bool in_use; /* True when structure is allocated */
+
+#define PORT_STATE_CLOSED 0
+#define PORT_STATE_OPENING 1
+#define PORT_STATE_OPENED 2
+#define PORT_STATE_CLOSING 3
+
+ uint8_t state; /* State of the application */
+
+ uint8_t scn; /* Service channel number */
+ uint16_t uuid; /* Service UUID */
+
+ BD_ADDR bd_addr; /* BD ADDR of the device for the multiplexer channel */
+ bool is_server; /* true if the server application */
+ uint8_t dlci; /* DLCI of the connection */
+
+ uint8_t error; /* Last error detected */
+
+ uint8_t line_status; /* Line status as reported by peer */
+
+ uint8_t default_signal_state; /* Initial signal state depending on uuid */
+
+ uint16_t mtu; /* Max MTU that port can receive */
+ uint16_t peer_mtu; /* Max MTU that port can send */
+
+ tPORT_DATA tx; /* Control block for data from app to peer */
+ tPORT_DATA rx; /* Control block for data from peer to app */
+
+ tPORT_STATE user_port_pars; /* Port parameters for user connection */
+ tPORT_STATE peer_port_pars; /* Port parameters for user connection */
+
+ tPORT_CTRL local_ctrl;
+ tPORT_CTRL peer_ctrl;
+
+#define PORT_CTRL_REQ_SENT 0x01
+#define PORT_CTRL_REQ_CONFIRMED 0x02
+#define PORT_CTRL_IND_RECEIVED 0x04
+#define PORT_CTRL_IND_RESPONDED 0x08
+
+ uint8_t port_ctrl; /* Modem Status Command */
+
+ bool rx_flag_ev_pending; /* RXFLAG Character is received */
+
+ tRFC_PORT rfc; /* RFCOMM port control block */
+
+ uint32_t ev_mask; /* Event mask for the callback */
+ tPORT_CALLBACK* p_callback; /* Pointer to users callback function */
+ tPORT_CALLBACK*
+ p_mgmt_callback; /* Callback function to receive connection up/down */
+ tPORT_DATA_CALLBACK*
+ p_data_callback; /* Callback function to receive data indications */
+ tPORT_DATA_CO_CALLBACK*
+ p_data_co_callback; /* Callback function with callouts and flowctrl */
+ uint16_t credit_tx; /* Flow control credits for tx path */
+ uint16_t credit_rx; /* Flow control credits for rx path, this is */
+ /* number of buffers peer is allowed to sent */
+ uint16_t
+ credit_rx_max; /* Max number of credits we will allow this guy to sent */
+ uint16_t credit_rx_low; /* Number of credits when we send credit update */
+ uint16_t rx_buf_critical; /* port receive queue critical watermark level */
+ bool keep_port_handle; /* true if port is not deallocated when closing */
+ /* it is set to true for server when allocating port */
+ uint16_t keep_mtu; /* Max MTU that port can receive by server */
+} tPORT;
+
+/* Define the PORT/RFCOMM control structure
+*/
+typedef struct {
+ tPORT port[MAX_RFC_PORTS]; /* Port info pool */
+ tRFC_MCB rfc_mcb[MAX_BD_CONNECTIONS]; /* RFCOMM bd_connections pool */
+} tPORT_CB;
+
+/*
+ * Functions provided by the port_utils.cc
+*/
+extern tPORT* port_allocate_port(uint8_t dlci, BD_ADDR bd_addr);
+extern void port_set_defaults(tPORT* p_port);
+extern void port_select_mtu(tPORT* p_port);
+extern void port_release_port(tPORT* p_port);
+extern tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci);
+extern tRFC_MCB* port_find_mcb(BD_ADDR bd_addr);
+extern tPORT* port_find_dlci_port(uint8_t dlci);
+extern tPORT* port_find_port(uint8_t dlci, BD_ADDR bd_addr);
+extern uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals,
+ uint8_t signal);
+extern uint32_t port_flow_control_user(tPORT* p_port);
+extern void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count);
+
+/*
+ * Functions provided by the port_rfc.cc
+*/
+extern int port_open_continue(tPORT* p_port);
+extern void port_start_port_open(tPORT* p_port);
+extern void port_start_par_neg(tPORT* p_port);
+extern void port_start_control(tPORT* p_port);
+extern void port_start_close(tPORT* p_port);
+extern void port_rfc_closed(tPORT* p_port, uint8_t res);
+
+#endif
diff --git a/mtkbt/code/bt/stack/rfcomm/port_rfc.cc b/mtkbt/code/bt/stack/rfcomm/port_rfc.cc
new file mode 100755
index 0000000..eb80fed
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/port_rfc.cc
@@ -0,0 +1,1019 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This module contains functions for port emulation entity and RFCOMM
+ * communications
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "osi/include/mutex.h"
+#include "osi/include/osi.h"
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/*
+ * Local function definitions
+*/
+uint32_t port_rfc_send_tx_data(tPORT* p_port);
+void port_rfc_closed(tPORT* p_port, uint8_t res);
+void port_get_credits(tPORT* p_port, uint8_t k);
+
+/*******************************************************************************
+ *
+ * Function port_open_continue
+ *
+ * Description This function is called after security manager completes
+ * required security checks.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+int port_open_continue(tPORT* p_port) {
+ tRFC_MCB* p_mcb;
+
+ RFCOMM_TRACE_EVENT("port_open_continue, p_port:%p", p_port);
+
+ /* Check if multiplexer channel has already been established */
+ p_mcb = rfc_alloc_multiplexer_channel(p_port->bd_addr, true);
+ if (p_mcb == NULL) {
+ RFCOMM_TRACE_WARNING("port_open_continue no mx channel");
+ port_release_port(p_port);
+ return (PORT_NO_RESOURCES);
+ }
+
+ p_port->rfc.p_mcb = p_mcb;
+
+ p_mcb->port_inx[p_port->dlci] = p_port->inx;
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu(p_port);
+
+ if (p_mcb->state == RFC_MX_STATE_CONNECTED) {
+ RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
+ } else if ((p_mcb->state == RFC_MX_STATE_IDLE) ||
+ (p_mcb->state == RFC_MX_STATE_DISC_WAIT_UA)) {
+ /* In RFC_MX_STATE_IDLE state, MX state machine will create connection */
+ /* In RFC_MX_STATE_DISC_WAIT_UA state, MX state machine will recreate
+ * connection */
+ /* after disconnecting is completed */
+ RFCOMM_StartReq(p_mcb);
+ } else {
+ /* MX state machine ignores RFC_MX_EVENT_START_REQ in these states */
+ /* When it enters RFC_MX_STATE_CONNECTED, it will check any openning ports
+ */
+ RFCOMM_TRACE_DEBUG(
+ "port_open_continue: mx state(%d) mx channel is openning",
+ p_mcb->state);
+ }
+ return (PORT_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function port_start_control
+ *
+ * Description This function is called in the BTU_TASK context to
+ * send control information
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void port_start_control(tPORT* p_port) {
+ tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL) return;
+
+ RFCOMM_ControlReq(p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Function port_start_par_neg
+ *
+ * Description This function is called in the BTU_TASK context to
+ * send configuration information
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void port_start_par_neg(tPORT* p_port) {
+ tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
+
+ if (p_mcb == NULL) return;
+
+ RFCOMM_PortNegReq(p_mcb, p_port->dlci, &p_port->user_port_pars);
+}
+
+/*******************************************************************************
+ *
+ * Function port_start_close
+ *
+ * Description This function is called in the BTU_TASK context to
+ * release DLC
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void port_start_close(tPORT* p_port) {
+ tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
+ uint8_t old_signals;
+ uint32_t events = 0;
+
+ /* At first indicate to the user that signals on the connection were dropped
+ */
+ p_port->line_status |= LINE_STATUS_FAILED;
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &=
+ ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes(p_port, old_signals,
+ p_port->peer_ctrl.modem_signal);
+
+ if (p_port->ev_mask & PORT_EV_CONNECT_ERR) events |= PORT_EV_CONNECT_ERR;
+
+ if (p_port->ev_mask & PORT_EV_ERR) events |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback(events, p_port->inx);
+
+ /* Check if RFCOMM side has been closed while the message was queued */
+ if ((p_mcb == NULL) || (p_port->rfc.state == RFC_STATE_CLOSED)) {
+ /* Call management callback function before calling port_release_port() to
+ * clear tPort */
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback(PORT_CLOSED, p_port->inx);
+
+ port_release_port(p_port);
+ } else {
+ RFCOMM_DlcReleaseReq(p_mcb, p_port->dlci);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_StartCnf
+ *
+ * Description This function is called from the RFCOMM layer when
+ * establishing of the multiplexer channel is completed.
+ * Continue establishing of the connection for all ports that
+ * are in the OPENING state
+ *
+ ******************************************************************************/
+void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result) {
+ tPORT* p_port;
+ int i;
+ bool no_ports_up = true;
+
+ RFCOMM_TRACE_EVENT("PORT_StartCnf result:%d", result);
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ if (p_port->rfc.p_mcb == p_mcb) {
+ no_ports_up = false;
+
+ if (result == RFCOMM_SUCCESS)
+ RFCOMM_ParNegReq(p_mcb, p_port->dlci, p_port->mtu);
+ else {
+ RFCOMM_TRACE_WARNING("PORT_StartCnf failed result:%d", result);
+
+ /* Warning: result is also set to 4 when l2cap connection
+ fails due to l2cap connect cnf (no_resources) */
+ if (result == HCI_ERR_PAGE_TIMEOUT)
+ p_port->error = PORT_PAGE_TIMEOUT;
+ else
+ p_port->error = PORT_START_FAILED;
+
+ rfc_release_multiplexer_channel(p_mcb);
+
+ /* Send event to the application */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECT_ERR))
+ (p_port->p_callback)(PORT_EV_CONNECT_ERR, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback(PORT_START_FAILED, p_port->inx);
+
+ port_release_port(p_port);
+ }
+ }
+ }
+
+ /* There can be a situation when after starting connection, user closes the */
+ /* port, we can catch it here to close multiplexor channel */
+ if (no_ports_up) {
+ rfc_check_mcb_active(p_mcb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_StartInd
+ *
+ * Description This function is called from the RFCOMM layer when
+ * some peer device wants to establish a multiplexer
+ * connection. Check if there are any ports open with this
+ * or not assigned multiplexer.
+ *
+ ******************************************************************************/
+void PORT_StartInd(tRFC_MCB* p_mcb) {
+ tPORT* p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT("PORT_StartInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ if ((p_port->rfc.p_mcb == NULL) || (p_port->rfc.p_mcb == p_mcb)) {
+ RFCOMM_TRACE_DEBUG(
+ "PORT_StartInd, RFCOMM_StartRsp RFCOMM_SUCCESS: p_mcb:%p", p_mcb);
+ RFCOMM_StartRsp(p_mcb, RFCOMM_SUCCESS);
+ return;
+ }
+ }
+ RFCOMM_StartRsp(p_mcb, RFCOMM_ERROR);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ParNegInd
+ *
+ * Description This function is called from the RFCOMM layer to change
+ * DLCI parameters (currently only MTU is negotiated).
+ * If can not find the port do not accept the request.
+ * Otherwise save the MTU size supported by the peer.
+ *
+ ******************************************************************************/
+void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
+ uint8_t k) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ uint8_t our_cl;
+ uint8_t our_k;
+
+ RFCOMM_TRACE_EVENT("PORT_ParNegInd dlci:%d mtu:%d", dlci, mtu);
+
+ if (!p_port) {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port(dlci);
+ if (!p_port) {
+ /* If the port cannot be opened, send a DM. Per Errata 1205 */
+ rfc_send_dm(p_mcb, dlci, false);
+ /* check if this is the last port open, some headsets have
+ problem, they don't disconnect if we send DM */
+ rfc_check_mcb_active(p_mcb);
+ RFCOMM_TRACE_EVENT("PORT_ParNegInd: port not found");
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ memcpy(p_port->bd_addr, p_mcb->bd_addr, BD_ADDR_LEN);
+
+ /* Connection is up and we know local and remote features, select MTU */
+ port_select_mtu(p_port);
+
+ p_port->rfc.p_mcb = p_mcb;
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ /* Negotiate the flow control mechanism. If flow control mechanism for */
+ /* mux has not been set yet, set it now. If either we or peer wants TS 07.10,
+ */
+ /* use that. Otherwise both must want credit based, so use that. If flow is
+ */
+ /* already defined for this mux, we respond with that value. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED) {
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) ||
+ (cl == RFCOMM_PN_CONV_LAYER_TYPE_1)) {
+ p_mcb->flow = PORT_FC_TS710;
+ } else {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ }
+
+ /* Regardless of our flow control mechanism, if the PN cl is zero, we must */
+ /* respond with zero. "A responding implementation must set this field to 14
+ */
+ /* if (and only if) the PN request was 15." This could happen if a PN is sent
+ */
+ /* after the DLCI is already established-- the PN in that case must have cl =
+ * 0. */
+ /* See RFCOMM spec 5.5.3 */
+ if (cl == RFCOMM_PN_CONV_LAYER_TYPE_1) {
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ } else if (p_mcb->flow == PORT_FC_CREDIT) {
+ /* get credits */
+ port_get_credits(p_port, k);
+
+ /* Set convergence layer and number of credits (k) */
+ our_cl = RFCOMM_PN_CONV_LAYER_CBFC_R;
+ our_k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
+ : RFCOMM_K_MAX;
+ p_port->credit_rx = our_k;
+ } else {
+ /* must not be using credit based flow control; use TS 7.10 */
+ our_cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ our_k = 0;
+ }
+ RFCOMM_ParNegRsp(p_mcb, dlci, p_port->mtu, our_cl, our_k);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ParNegCnf
+ *
+ * Description This function is called from the RFCOMM layer to change
+ * DLCI parameters (currently only MTU is negotiated).
+ * Save the MTU size supported by the peer.
+ * If the confirmation is received during the port opening
+ * procedure send EstablishRequest to continue.
+ *
+ ******************************************************************************/
+void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
+ uint8_t k) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT("PORT_ParNegCnf dlci:%d mtu:%d cl: %d k: %d", dlci, mtu,
+ cl, k);
+
+ if (!p_port) return;
+
+ /* Flow control mechanism not set yet. Negotiate flow control mechanism. */
+ if (p_mcb->flow == PORT_FC_UNDEFINED) {
+ /* Our stack is configured for TS07.10 and they responded with credit-based.
+ */
+ /* This is illegal-- negotiation fails. */
+ if ((PORT_FC_DEFAULT == PORT_FC_TS710) &&
+ (cl == RFCOMM_PN_CONV_LAYER_CBFC_R)) {
+ rfc_send_disc(p_mcb, p_port->dlci);
+ rfc_port_closed(p_port);
+ return;
+ }
+ /* Our stack is configured for credit-based and they responded with
+ credit-based. */
+ else if (cl == RFCOMM_PN_CONV_LAYER_CBFC_R) {
+ p_mcb->flow = PORT_FC_CREDIT;
+ }
+ /* They responded with any other value. Treat this as negotiation to
+ TS07.10. */
+ else {
+ p_mcb->flow = PORT_FC_TS710;
+ }
+ }
+ /* If mux flow control mechanism set, we honor that setting regardless of */
+ /* the CL value in their response. This allows us to gracefully accept any */
+ /* illegal PN negotiation scenarios. */
+
+ p_port->mtu = (p_port->mtu < mtu) ? p_port->mtu : mtu;
+ p_port->peer_mtu = p_port->mtu;
+
+ if (p_mcb->flow == PORT_FC_CREDIT) {
+ port_get_credits(p_port, k);
+ }
+
+ if (p_port->state == PORT_STATE_OPENING)
+ RFCOMM_DlcEstablishReq(p_mcb, p_port->dlci, p_port->mtu);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_DlcEstablishInd
+ *
+ * Description This function is called from the RFCOMM layer when peer
+ * device wants to establish a new DLC. If this is not the
+ * first message in the establishment procedure port_handle
+ * has a handle to the port control block otherwise the control
+ * block should be found based on the muliplexer channel and
+ * dlci. The block should be allocated allocated before
+ * meaning that application already made open.
+ *
+ ******************************************************************************/
+void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_DEBUG(
+ "PORT_DlcEstablishInd p_mcb:%p, dlci:%d mtu:%di, p_port:%p", p_mcb, dlci,
+ mtu, p_port);
+ RFCOMM_TRACE_DEBUG(
+ "PORT_DlcEstablishInd p_mcb addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ p_mcb->bd_addr[0], p_mcb->bd_addr[1], p_mcb->bd_addr[2],
+ p_mcb->bd_addr[3], p_mcb->bd_addr[4], p_mcb->bd_addr[5]);
+
+ if (!p_port) {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port(dlci);
+ if (!p_port) {
+ RFCOMM_DlcEstablishRsp(p_mcb, dlci, 0, RFCOMM_ERROR);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu)) p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop(p_mcb);
+
+ RFCOMM_DlcEstablishRsp(p_mcb, dlci, p_port->mtu, RFCOMM_SUCCESS);
+
+ /* This is the server side. If application wants to know when connection */
+ /* is established, thats the place */
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_DlcEstablishCnf
+ *
+ * Description This function is called from the RFCOMM layer when peer
+ * acknowledges establish procedure (SABME/UA). Send reply
+ * to the user and set state to OPENED if result was
+ * successfull.
+ *
+ ******************************************************************************/
+void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint16_t result) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT("PORT_DlcEstablishCnf dlci:%d mtu:%d result:%d", dlci, mtu,
+ result);
+
+ if (!p_port) return;
+
+ if (result != RFCOMM_SUCCESS) {
+ p_port->error = PORT_START_FAILED;
+ port_rfc_closed(p_port, PORT_START_FAILED);
+ return;
+ }
+
+ /* If L2CAP's mtu less then RFCOMM's take it */
+ if (mtu && (mtu < p_port->peer_mtu)) p_port->peer_mtu = mtu;
+
+ /* If there was an inactivity timer running for MCB stop it */
+ rfc_timer_stop(p_mcb);
+
+ if (p_port->p_callback && (p_port->ev_mask & PORT_EV_CONNECTED))
+ (p_port->p_callback)(PORT_EV_CONNECTED, p_port->inx);
+
+ if (p_port->p_mgmt_callback)
+ p_port->p_mgmt_callback(PORT_SUCCESS, p_port->inx);
+
+ p_port->state = PORT_STATE_OPENED;
+
+ /* RPN is required only if we want to tell DTE how the port should be opened
+ */
+ if ((p_port->uuid == UUID_SERVCLASS_DIALUP_NETWORKING) ||
+ (p_port->uuid == UUID_SERVCLASS_FAX))
+ RFCOMM_PortNegReq(p_port->rfc.p_mcb, p_port->dlci, NULL);
+ else
+ RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_PortNegInd
+ *
+ * Description This function is called from the RFCOMM layer when peer
+ * device wants to set parameters of the port. As per the spec
+ * this message has to be sent before the first data packet
+ * and can be sent before establish. The block should be
+ * allocated before meaning that application already made open.
+ *
+ ******************************************************************************/
+void PORT_PortNegInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
+ uint16_t param_mask) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT("PORT_PortNegInd");
+
+ if (!p_port) {
+ /* This can be a first request for this port */
+ p_port = port_find_dlci_port(dlci);
+ if (!p_port) {
+ RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, 0);
+ return;
+ }
+ p_mcb->port_inx[dlci] = p_port->inx;
+ }
+
+ /* Check if the flow control is acceptable on local side */
+ p_port->peer_port_pars = *p_pars;
+ RFCOMM_PortNegRsp(p_mcb, dlci, p_pars, param_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_PortNegCnf
+ *
+ * Description This function is called from the RFCOMM layer to change
+ * state for the port. Propagate change to the user.
+ *
+ ******************************************************************************/
+void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci,
+ UNUSED_ATTR tPORT_STATE* p_pars, uint16_t result) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT("PORT_PortNegCnf");
+
+ if (!p_port) {
+ RFCOMM_TRACE_WARNING("PORT_PortNegCnf no port");
+ return;
+ }
+ /* Port negotiation failed. Drop the connection */
+ if (result != RFCOMM_SUCCESS) {
+ p_port->error = PORT_PORT_NEG_FAILED;
+
+ RFCOMM_DlcReleaseReq(p_mcb, p_port->dlci);
+
+ port_rfc_closed(p_port, PORT_PORT_NEG_FAILED);
+ return;
+ }
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT)) {
+ RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ } else {
+ RFCOMM_TRACE_WARNING("PORT_PortNegCnf Control Already sent");
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ControlInd
+ *
+ * Description This function is called from the RFCOMM layer on the modem
+ * signal change. Propagate change to the user.
+ *
+ ******************************************************************************/
+void PORT_ControlInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ uint32_t event;
+ uint8_t old_signals;
+
+ RFCOMM_TRACE_EVENT("PORT_ControlInd");
+
+ if (!p_port) return;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ event = port_get_signal_changes(p_port, old_signals, p_pars->modem_signal);
+
+ p_port->peer_ctrl = *p_pars;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_SENT))
+ RFCOMM_ControlReq(p_port->rfc.p_mcb, p_port->dlci, &p_port->local_ctrl);
+ else {
+ /* If this is the first time we received control RFCOMM is connected */
+ if (!(p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)) {
+ event |= (PORT_EV_CONNECTED & p_port->ev_mask);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED) {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+ }
+
+ p_port->port_ctrl |= (PORT_CTRL_IND_RECEIVED | PORT_CTRL_IND_RESPONDED);
+
+ if (p_pars->break_signal) event |= (PORT_EV_BREAK & p_port->ev_mask);
+
+ /* execute call back function only if the application is registered for events
+ */
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+
+ RFCOMM_TRACE_EVENT(
+ "PORT_ControlInd DTR_DSR : %d, RTS_CTS : %d, RI : %d, DCD : %d",
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DTRDSR) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RTSCTS) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_RI) ? 1 : 0),
+ ((p_port->peer_ctrl.modem_signal & MODEM_SIGNAL_DCD) ? 1 : 0));
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_ControlCnf
+ *
+ * Description This function is called from the RFCOMM layer when
+ * peer acknowleges change of the modem signals.
+ *
+ ******************************************************************************/
+void PORT_ControlCnf(tRFC_MCB* p_mcb, uint8_t dlci,
+ UNUSED_ATTR tPORT_CTRL* p_pars) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ uint32_t event = 0;
+
+ RFCOMM_TRACE_EVENT("PORT_ControlCnf");
+
+ if (!p_port) return;
+
+ if (!(p_port->port_ctrl & PORT_CTRL_REQ_CONFIRMED)) {
+ p_port->port_ctrl |= PORT_CTRL_REQ_CONFIRMED;
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED)
+ event = (p_port->ev_mask & PORT_EV_CONNECTED);
+ }
+
+ if (p_port->port_ctrl & PORT_CTRL_IND_RECEIVED) {
+ event |= port_rfc_send_tx_data(p_port);
+ }
+
+ /* execute call back function only if the application is registered for events
+ */
+ if (event && p_port->p_callback) (p_port->p_callback)(event, p_port->inx);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_LineStatusInd
+ *
+ * Description This function is called from the RFCOMM layer when
+ * peer indicates change in the line status
+ *
+ ******************************************************************************/
+void PORT_LineStatusInd(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t line_status) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ uint32_t event = 0;
+
+ RFCOMM_TRACE_EVENT("PORT_LineStatusInd");
+
+ if (!p_port) return;
+
+ p_port->line_status |= line_status;
+
+ if (line_status & PORT_ERR_OVERRUN) event |= PORT_EV_OVERRUN;
+
+ if (line_status & PORT_ERR_BREAK) event |= PORT_EV_BREAK;
+
+ if (line_status & ~(PORT_ERR_OVERRUN | PORT_ERR_BREAK)) event |= PORT_EV_ERR;
+
+ if ((p_port->p_callback != NULL) && (p_port->ev_mask & event))
+ p_port->p_callback((p_port->ev_mask & event), p_port->inx);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_DlcReleaseInd
+ *
+ * Description This function is called from the RFCOMM layer when
+ * DLC connection is released.
+ *
+ ******************************************************************************/
+void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+
+ RFCOMM_TRACE_EVENT("PORT_DlcReleaseInd");
+
+ if (!p_port) return;
+
+ port_rfc_closed(p_port, PORT_CLOSED);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_CloseInd
+ *
+ * Description This function is called from the RFCOMM layer when
+ * multiplexer connection is released.
+ *
+ ******************************************************************************/
+void PORT_CloseInd(tRFC_MCB* p_mcb) {
+ tPORT* p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT("PORT_CloseInd");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ if (p_port->rfc.p_mcb == p_mcb) {
+ port_rfc_closed(p_port, PORT_PEER_CONNECTION_FAILED);
+ }
+ }
+ rfc_release_multiplexer_channel(p_mcb);
+}
+
+/*******************************************************************************
+ *
+ * Function Port_TimeOutCloseMux
+ *
+ * Description This function is called when RFCOMM timesout on a command
+ * as a result multiplexer connection is closed.
+ *
+ ******************************************************************************/
+void Port_TimeOutCloseMux(tRFC_MCB* p_mcb) {
+ tPORT* p_port;
+ int i;
+
+ RFCOMM_TRACE_EVENT("Port_TimeOutCloseMux");
+
+ p_port = &rfc_cb.port.port[0];
+ for (i = 0; i < MAX_RFC_PORTS; i++, p_port++) {
+ if (p_port->rfc.p_mcb == p_mcb) {
+ port_rfc_closed(p_port, PORT_PEER_TIMEOUT);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_DataInd
+ *
+ * Description This function is called from the RFCOMM layer when data
+ * buffer is received from the peer.
+ *
+ ******************************************************************************/
+void PORT_DataInd(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ uint8_t rx_char1;
+ uint32_t events = 0;
+ uint8_t* p;
+ int i;
+
+ RFCOMM_TRACE_EVENT(
+ "PORT_DataInd with data length %d, p_mcb:%p,p_port:%p,dlci:%d",
+ p_buf->len, p_mcb, p_port, dlci);
+ if (!p_port) {
+ osi_free(p_buf);
+ return;
+ }
+ /* If client registered callout callback with flow control we can just deliver
+ * receive data */
+ if (p_port->p_data_co_callback) {
+ /* Another packet is delivered to user. Send credits to peer if required */
+ if (p_port->p_data_co_callback(p_port->inx, (uint8_t*)p_buf, -1,
+ DATA_CO_CALLBACK_TYPE_INCOMING)) {
+ port_flow_control_peer(p_port, true, 1);
+ } else {
+ port_flow_control_peer(p_port, false, 0);
+ }
+ // osi_free(p_buf);
+ return;
+ }
+ /* If client registered callback we can just deliver receive data */
+ if (p_port->p_data_callback) {
+ /* Another packet is delivered to user. Send credits to peer if required */
+ port_flow_control_peer(p_port, true, 1);
+ p_port->p_data_callback(p_port->inx, (uint8_t*)(p_buf + 1) + p_buf->offset,
+ p_buf->len);
+ osi_free(p_buf);
+ return;
+ }
+ /* Check if rx queue exceeds the limit */
+ if ((p_port->rx.queue_size + p_buf->len > PORT_RX_CRITICAL_WM) ||
+ (fixed_queue_length(p_port->rx.queue) + 1 > p_port->rx_buf_critical)) {
+ RFCOMM_TRACE_EVENT("PORT_DataInd. Buffer over run. Dropping the buffer");
+ osi_free(p_buf);
+ RFCOMM_LineStatusReq(p_mcb, dlci, LINE_STATUS_OVERRUN);
+ return;
+ }
+ /* If user registered to receive notification when a particular byte is */
+ /* received we mast check all received bytes */
+ if (((rx_char1 = p_port->user_port_pars.rx_char1) != 0) &&
+ (p_port->ev_mask & PORT_EV_RXFLAG)) {
+ for (i = 0, p = (uint8_t*)(p_buf + 1) + p_buf->offset; i < p_buf->len;
+ i++) {
+ if (*p++ == rx_char1) {
+ events |= PORT_EV_RXFLAG;
+ break;
+ }
+ }
+ }
+
+ mutex_global_lock();
+
+ fixed_queue_enqueue(p_port->rx.queue, p_buf);
+ p_port->rx.queue_size += p_buf->len;
+
+ mutex_global_unlock();
+
+ /* perform flow control procedures if necessary */
+ port_flow_control_peer(p_port, false, 0);
+
+ /* If user indicated flow control can not deliver any notifications to him */
+ if (p_port->rx.user_fc) {
+ if (events & PORT_EV_RXFLAG) {
+ p_port->rx_flag_ev_pending = true;
+ }
+ return;
+ }
+
+ events |= PORT_EV_RXCHAR;
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ if (p_port->p_callback && events) p_port->p_callback(events, p_port->inx);
+}
+
+/*******************************************************************************
+ *
+ * Function PORT_FlowInd
+ *
+ * Description This function is called from the RFCOMM layer on the flow
+ * control signal change. Propagate change to the user.
+ *
+ ******************************************************************************/
+void PORT_FlowInd(tRFC_MCB* p_mcb, uint8_t dlci, bool enable_data) {
+ tPORT* p_port = (tPORT*)NULL;
+ uint32_t events = 0;
+ int i;
+
+ RFCOMM_TRACE_EVENT("PORT_FlowInd fc:%d", enable_data);
+
+ if (dlci == 0) {
+ p_mcb->peer_ready = enable_data;
+ } else {
+ p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) return;
+
+ p_port->tx.peer_fc = !enable_data;
+ }
+
+ for (i = 0; i < MAX_RFC_PORTS; i++) {
+ /* If DLCI is 0 event applies to all ports */
+ if (dlci == 0) {
+ p_port = &rfc_cb.port.port[i];
+ if (!p_port->in_use || (p_port->rfc.p_mcb != p_mcb) ||
+ (p_port->rfc.state != RFC_STATE_OPENED))
+ continue;
+ }
+ events = 0;
+
+ /* Check if flow of data is still enabled */
+ events |= port_flow_control_user(p_port);
+
+ /* Check if data can be sent and send it */
+ events |= port_rfc_send_tx_data(p_port);
+
+ /* Mask out all events that are not of interest to user */
+ events &= p_port->ev_mask;
+
+ /* Send event to the application */
+ if (p_port->p_callback && events) (p_port->p_callback)(events, p_port->inx);
+
+ /* If DLCI is not 0 event applies to one port only */
+ if (dlci != 0) break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function port_rfc_send_tx_data
+ *
+ * Description This function is when forward data can be sent to the peer
+ *
+ ******************************************************************************/
+uint32_t port_rfc_send_tx_data(tPORT* p_port) {
+ uint32_t events = 0;
+ BT_HDR* p_buf;
+
+ /* if there is data to be sent */
+ if (p_port->tx.queue_size > 0) {
+ /* while the rfcomm peer is not flow controlling us, and peer is ready */
+ while (!p_port->tx.peer_fc && p_port->rfc.p_mcb &&
+ p_port->rfc.p_mcb->peer_ready) {
+ /* get data from tx queue and send it */
+ mutex_global_lock();
+
+ p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue);
+ if (p_buf != NULL) {
+ p_port->tx.queue_size -= p_buf->len;
+
+ mutex_global_unlock();
+
+ RFCOMM_TRACE_DEBUG("Sending RFCOMM_DataReq tx.queue_size=%d",
+ p_port->tx.queue_size);
+
+ RFCOMM_DataReq(p_port->rfc.p_mcb, p_port->dlci, p_buf);
+
+ events |= PORT_EV_TXCHAR;
+
+ if (p_port->tx.queue_size == 0) {
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* queue is empty-- all data sent */
+ else {
+ mutex_global_unlock();
+
+ events |= PORT_EV_TXEMPTY;
+ break;
+ }
+ }
+ /* If we flow controlled user based on the queue size enable data again */
+ events |= port_flow_control_user(p_port);
+ }
+ return (events & p_port->ev_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function port_rfc_closed
+ *
+ * Description This function when RFCOMM side of port is closed
+ *
+ ******************************************************************************/
+void port_rfc_closed(tPORT* p_port, uint8_t res) {
+ uint8_t old_signals;
+ uint32_t events = 0;
+ tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
+
+ if ((p_port->state == PORT_STATE_OPENING) && (p_port->is_server)) {
+ /* The servr side has not been informed that connection is up, ignore */
+ RFCOMM_TRACE_EVENT("port_rfc_closed in OPENING state ignored");
+
+ rfc_port_timer_stop(p_port);
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ if (p_mcb) {
+ p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active(p_mcb);
+ p_port->rfc.p_mcb = NULL;
+ }
+
+ /* Need to restore DLCI to listening state
+ * if the server was on the initiating RFC
+ */
+ p_port->dlci &= 0xfe;
+
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_CLOSING) &&
+ (p_port->state != PORT_STATE_CLOSED)) {
+ p_port->line_status |= LINE_STATUS_FAILED;
+
+ old_signals = p_port->peer_ctrl.modem_signal;
+
+ p_port->peer_ctrl.modem_signal &=
+ ~(PORT_DTRDSR_ON | PORT_CTSRTS_ON | PORT_DCD_ON);
+
+ events |= port_get_signal_changes(p_port, old_signals,
+ p_port->peer_ctrl.modem_signal);
+
+ if (p_port->ev_mask & PORT_EV_CONNECT_ERR) events |= PORT_EV_CONNECT_ERR;
+ }
+ RFCOMM_TRACE_EVENT("port_rfc_closed state:%d sending events:%x",
+ p_port->state, events);
+
+ if ((p_port->p_callback != NULL) && events)
+ p_port->p_callback(events, p_port->inx);
+
+ if (p_port->p_mgmt_callback) p_port->p_mgmt_callback(res, p_port->inx);
+
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ RFCOMM_TRACE_WARNING("%s RFCOMM connection in state %d closed: %s (res: %d)",
+ __func__, p_port->state, PORT_GetResultString(res), res);
+
+ port_release_port(p_port);
+}
+
+/*******************************************************************************
+ *
+ * Function port_get_credits
+ *
+ * Description Set initial values for credits.
+ * Adjust max number of rx credits based on negotiated MTU.
+ * Check max allowed num of bytes, max allowed num buffers,
+ * should be less then 255
+ *
+ ******************************************************************************/
+void port_get_credits(tPORT* p_port, uint8_t k) {
+ p_port->credit_tx = k;
+ if (p_port->credit_tx == 0) p_port->tx.peer_fc = true;
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/port_utils.cc b/mtkbt/code/bt/stack/rfcomm/port_utils.cc
new file mode 100755
index 0000000..20e6a88
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/port_utils.cc
@@ -0,0 +1,535 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Port Emulation entity utilities
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "osi/include/mutex.h"
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+static const tPORT_STATE default_port_pars = {
+ PORT_BAUD_RATE_9600,
+ PORT_8_BITS,
+ PORT_ONESTOPBIT,
+ PORT_PARITY_NO,
+ PORT_ODD_PARITY,
+ PORT_FC_OFF,
+ 0, /* No rx_char */
+ PORT_XON_DC1,
+ PORT_XOFF_DC3,
+};
+
+/*******************************************************************************
+ *
+ * Function port_allocate_port
+ *
+ * Description Look through the Port Control Blocks for a free one. Note
+ * that one server can open several ports with the same SCN
+ * if it can support simulteneous requests from different
+ * clients.
+ *
+ * Returns Pointer to the PORT or NULL if not found
+ *
+ ******************************************************************************/
+tPORT* port_allocate_port(uint8_t dlci, BD_ADDR bd_addr) {
+ tPORT* p_port = &rfc_cb.port.port[0];
+ uint8_t xx, yy;
+
+ for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
+ if (yy >= MAX_RFC_PORTS) yy = 0;
+
+ p_port = &rfc_cb.port.port[yy];
+ if (!p_port->in_use) {
+ memset(p_port, 0, sizeof(tPORT));
+
+ p_port->in_use = true;
+ p_port->inx = yy + 1;
+
+ /* During the open set default state for the port connection */
+ port_set_defaults(p_port);
+
+ p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
+ rfc_cb.rfc.last_port = yy;
+
+ p_port->dlci = dlci;
+ memcpy(p_port->bd_addr, bd_addr, BD_ADDR_LEN);
+
+ RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
+ p_port, rfc_cb.rfc.last_port);
+ RFCOMM_TRACE_DEBUG(
+ "port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ return (p_port);
+ }
+ }
+
+ /* If here, no free PORT found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function port_set_defaults
+ *
+ * Description Set defualt port parameters
+ *
+ *
+ ******************************************************************************/
+void port_set_defaults(tPORT* p_port) {
+ p_port->ev_mask = 0;
+ p_port->p_callback = NULL;
+ p_port->port_ctrl = 0;
+ p_port->error = 0;
+ p_port->line_status = 0;
+ p_port->rx_flag_ev_pending = false;
+ p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
+
+ p_port->user_port_pars = default_port_pars;
+ p_port->peer_port_pars = default_port_pars;
+
+ p_port->credit_tx = 0;
+ p_port->credit_rx = 0;
+
+ memset(&p_port->local_ctrl, 0, sizeof(p_port->local_ctrl));
+ memset(&p_port->peer_ctrl, 0, sizeof(p_port->peer_ctrl));
+ memset(&p_port->rx, 0, sizeof(p_port->rx));
+ memset(&p_port->tx, 0, sizeof(p_port->tx));
+
+ p_port->tx.queue = fixed_queue_new(SIZE_MAX);
+ p_port->rx.queue = fixed_queue_new(SIZE_MAX);
+}
+
+/*******************************************************************************
+ *
+ * Function port_select_mtu
+ *
+ * Description Select MTU which will best serve connection from our
+ * point of view.
+ * If our device is 1.2 or lower we calculate how many DH5s
+ * fit into 1 RFCOMM buffer.
+ *
+ *
+ ******************************************************************************/
+void port_select_mtu(tPORT* p_port) {
+ uint16_t packet_size;
+
+ /* Will select MTU only if application did not setup something */
+ if (p_port->mtu == 0) {
+ /* find packet size which connection supports */
+ packet_size = btm_get_max_packet_size(p_port->bd_addr);
+ if (packet_size == 0) {
+ /* something is very wrong */
+ RFCOMM_TRACE_WARNING("port_select_mtu bad packet size");
+ p_port->mtu = RFCOMM_DEFAULT_MTU;
+ } else {
+ /* We try to negotiate MTU that each packet can be split into whole
+ number of max packets. For example if link is 1.2 max packet size is 339
+ bytes.
+ At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4
+ overhead.
+ 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
+ 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes
+ header overhead 1685
+
+ For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1
+ 3DH5 packet
+ 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes
+ header overhead 1017 */
+ if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) {
+ p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
+ packet_size) -
+ RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
+ RFCOMM_TRACE_DEBUG(
+ "port_select_mtu selected %d based on connection speed",
+ p_port->mtu);
+ } else {
+ p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
+ RFCOMM_TRACE_DEBUG(
+ "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
+ }
+ }
+ } else {
+ RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", p_port->mtu);
+ }
+ p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
+ if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM)
+ p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
+ p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
+ if (p_port->credit_rx_low > PORT_RX_BUF_LOW_WM)
+ p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
+ p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
+ if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM)
+ p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
+ RFCOMM_TRACE_DEBUG(
+ "port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
+ p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
+}
+
+/*******************************************************************************
+ *
+ * Function port_release_port
+ *
+ * Description Release port control block.
+ *
+ * Returns Pointer to the PORT or NULL if not found
+ *
+ ******************************************************************************/
+void port_release_port(tPORT* p_port) {
+ RFCOMM_TRACE_DEBUG("%s p_port: %p state: %d keep_handle: %d", __func__,
+ p_port, p_port->rfc.state, p_port->keep_port_handle);
+
+ mutex_global_lock();
+ BT_HDR* p_buf;
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
+ osi_free(p_buf);
+ p_port->rx.queue_size = 0;
+
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
+ osi_free(p_buf);
+ p_port->tx.queue_size = 0;
+ mutex_global_unlock();
+
+ alarm_cancel(p_port->rfc.port_timer);
+
+ p_port->state = PORT_STATE_CLOSED;
+
+ if (p_port->rfc.state == RFC_STATE_CLOSED) {
+ if (p_port->rfc.p_mcb) {
+ p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active(p_port->rfc.p_mcb);
+ }
+
+ rfc_port_timer_stop(p_port);
+ fixed_queue_free(p_port->tx.queue, NULL);
+ p_port->tx.queue = NULL;
+ fixed_queue_free(p_port->rx.queue, NULL);
+ p_port->rx.queue = NULL;
+
+ if (p_port->keep_port_handle) {
+ RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
+
+ /* save event mask and callback */
+ uint32_t mask = p_port->ev_mask;
+ tPORT_CALLBACK* p_port_cb = p_port->p_callback;
+ tPORT_STATE user_port_pars = p_port->user_port_pars;
+
+ port_set_defaults(p_port);
+
+ /* restore */
+ p_port->ev_mask = mask;
+ p_port->p_callback = p_port_cb;
+ p_port->user_port_pars = user_port_pars;
+ p_port->mtu = p_port->keep_mtu;
+
+ p_port->state = PORT_STATE_OPENING;
+ p_port->rfc.p_mcb = NULL;
+ if (p_port->is_server) p_port->dlci &= 0xfe;
+
+ p_port->local_ctrl.modem_signal = p_port->default_signal_state;
+ memcpy(p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
+ } else {
+ RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
+ alarm_free(p_port->rfc.port_timer);
+ memset(p_port, 0, sizeof(tPORT));
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function port_find_mcb
+ *
+ * Description This function checks if connection exists to device with
+ * the BD_ADDR.
+ *
+ ******************************************************************************/
+tRFC_MCB* port_find_mcb(BD_ADDR bd_addr) {
+ int i;
+
+ for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
+ if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) &&
+ !memcmp(rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)) {
+ /* Multiplexer channel found do not change anything */
+ RFCOMM_TRACE_DEBUG(
+ "port_find_mcb: found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
+ bd_addr[5]);
+ RFCOMM_TRACE_DEBUG(
+ "port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d", i,
+ &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
+ return (&rfc_cb.port.rfc_mcb[i]);
+ }
+ }
+ RFCOMM_TRACE_DEBUG(
+ "port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function port_find_mcb_dlci_port
+ *
+ * Description Find port on the multiplexer channel based on DLCI. If
+ * this port with DLCI not found try to use even DLCI. This
+ * is for the case when client is establishing connection on
+ * none-initiator MCB.
+ *
+ * Returns Pointer to the PORT or NULL if not found
+ *
+ ******************************************************************************/
+tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {
+ uint8_t inx;
+
+ if (!p_mcb) return (NULL);
+
+ if (dlci > RFCOMM_MAX_DLCI) return (NULL);
+
+ inx = p_mcb->port_inx[dlci];
+ if (inx == 0) {
+ RFCOMM_TRACE_DEBUG(
+ "port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb,
+ dlci);
+ return (NULL);
+ } else
+ return (&rfc_cb.port.port[inx - 1]);
+}
+
+/*******************************************************************************
+ *
+ * Function port_find_dlci_port
+ *
+ * Description Find port with DLCI not assigned to multiplexer channel
+ *
+ * Returns Pointer to the PORT or NULL if not found
+ *
+ ******************************************************************************/
+tPORT* port_find_dlci_port(uint8_t dlci) {
+ uint16_t i;
+ tPORT* p_port;
+
+ for (i = 0; i < MAX_RFC_PORTS; i++) {
+ p_port = &rfc_cb.port.port[i];
+
+ if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
+ if (p_port->dlci == dlci) {
+ return (p_port);
+ } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
+ p_port->dlci++;
+ return (p_port);
+ }
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function port_find_port
+ *
+ * Description Find port with DLCI, BD_ADDR
+ *
+ * Returns Pointer to the PORT or NULL if not found
+ *
+ ******************************************************************************/
+tPORT* port_find_port(uint8_t dlci, BD_ADDR bd_addr) {
+ uint16_t i;
+ tPORT* p_port;
+
+ for (i = 0; i < MAX_RFC_PORTS; i++) {
+ p_port = &rfc_cb.port.port[i];
+ if (p_port->in_use && (p_port->dlci == dlci) &&
+ !memcmp(p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
+ return (p_port);
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function port_flow_control_user
+ *
+ * Description Check the current user flow control and if necessary return
+ * events to be send to the user based on the user's specified
+ * flow control type.
+ *
+ * Returns event mask to be returned to the application
+ *
+ ******************************************************************************/
+uint32_t port_flow_control_user(tPORT* p_port) {
+ uint32_t event = 0;
+
+ /* Flow control to the user can be caused by flow controlling by the peer */
+ /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
+ /* tx_queue is full */
+ bool fc = p_port->tx.peer_fc || !p_port->rfc.p_mcb ||
+ !p_port->rfc.p_mcb->peer_ready ||
+ (p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
+ (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
+
+ if (p_port->tx.user_fc == fc) return (0);
+
+ p_port->tx.user_fc = fc;
+
+ if (fc)
+ event = PORT_EV_FC;
+ else
+ event = PORT_EV_FC | PORT_EV_FCS;
+
+ return (event);
+}
+
+/*******************************************************************************
+ *
+ * Function port_get_signal_changes
+ *
+ * Description Check modem signals that has been changed
+ *
+ * Returns event mask to be returned to the application
+ *
+ ******************************************************************************/
+uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals,
+ uint8_t signal) {
+ uint8_t changed_signals = (signal ^ old_signals);
+ uint32_t events = 0;
+
+ if (changed_signals & PORT_DTRDSR_ON) {
+ events |= PORT_EV_DSR;
+
+ if (signal & PORT_DTRDSR_ON) events |= PORT_EV_DSRS;
+ }
+
+ if (changed_signals & PORT_CTSRTS_ON) {
+ events |= PORT_EV_CTS;
+
+ if (signal & PORT_CTSRTS_ON) events |= PORT_EV_CTSS;
+ }
+
+ if (changed_signals & PORT_RING_ON) events |= PORT_EV_RING;
+
+ if (changed_signals & PORT_DCD_ON) {
+ events |= PORT_EV_RLSD;
+
+ if (signal & PORT_DCD_ON) events |= PORT_EV_RLSDS;
+ }
+
+ return (p_port->ev_mask & events);
+}
+
+/*******************************************************************************
+ *
+ * Function port_flow_control_peer
+ *
+ * Description Send flow control messages to the peer for both enabling
+ * and disabling flow control, for both credit-based and
+ * TS 07.10 flow control mechanisms.
+ *
+ * Returns nothing
+ *
+ ******************************************************************************/
+void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count) {
+ if (!p_port->rfc.p_mcb) return;
+
+ /* If using credit based flow control */
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
+ /* if want to enable flow from peer */
+ if (enable) {
+ /* update rx credits */
+ if (count > p_port->credit_rx) {
+ p_port->credit_rx = 0;
+ } else {
+ p_port->credit_rx -= count;
+ }
+
+ /* If credit count is less than low credit watermark, and user */
+ /* did not force flow control, send a credit update */
+ /* There might be a special case when we just adjusted rx_max */
+ if ((p_port->credit_rx <= p_port->credit_rx_low) && !p_port->rx.user_fc &&
+ (p_port->credit_rx_max > p_port->credit_rx)) {
+ rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
+ (uint8_t)(p_port->credit_rx_max - p_port->credit_rx));
+
+ p_port->credit_rx = p_port->credit_rx_max;
+
+ p_port->rx.peer_fc = false;
+ }
+ }
+ /* else want to disable flow from peer */
+ else {
+ /* if client registered data callback, just do what they want */
+ if (p_port->p_data_callback || p_port->p_data_co_callback) {
+ p_port->rx.peer_fc = true;
+ }
+ /* if queue count reached credit rx max, set peer fc */
+ else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
+ p_port->rx.peer_fc = true;
+ }
+ }
+ }
+ /* else using TS 07.10 flow control */
+ else {
+ /* if want to enable flow from peer */
+ if (enable) {
+ /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
+ /* check if it can be resumed now */
+ if (p_port->rx.peer_fc && (p_port->rx.queue_size < PORT_RX_LOW_WM) &&
+ (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
+ p_port->rx.peer_fc = false;
+
+ /* If user did not force flow control allow traffic now */
+ if (!p_port->rx.user_fc)
+ RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, true);
+ }
+ }
+ /* else want to disable flow from peer */
+ else {
+ /* if client registered data callback, just do what they want */
+ if (p_port->p_data_callback || p_port->p_data_co_callback) {
+ p_port->rx.peer_fc = true;
+ RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
+ }
+ /* Check the size of the rx queue. If it exceeds certain */
+ /* level and flow control has not been sent to the peer do it now */
+ else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) ||
+ (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) &&
+ !p_port->rx.peer_fc) {
+ RFCOMM_TRACE_EVENT("PORT_DataInd Data reached HW. Sending FC set.");
+
+ p_port->rx.peer_fc = true;
+ RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
+ }
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_int.h b/mtkbt/code/bt/stack/rfcomm/rfc_int.h
new file mode 100755
index 0000000..2505595
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_int.h
@@ -0,0 +1,378 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains definitions internal to the RFC unit
+ *
+ *****************************************************************************/
+
+#ifndef RFC_INT_H
+#define RFC_INT_H
+
+#include "l2c_api.h"
+#include "port_int.h"
+
+/*
+ * Define RFCOMM result codes
+*/
+#define RFCOMM_SUCCESS 0
+#define RFCOMM_ERROR 1
+#define RFCOMM_LOW_RESOURCES 2
+#define RFCOMM_TRY_LATER 3
+
+#define RFCOMM_USER_ERR 111
+#define RFCOMM_SECURITY_ERR 112
+
+/*
+ * Define max and min RFCOMM MTU (N1)
+*/
+#define RFCOMM_MIN_MTU 23
+#define RFCOMM_MAX_MTU 32767
+
+extern void RFCOMM_StartReq(tRFC_MCB* p_mcb);
+extern void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result);
+
+extern void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
+extern void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint16_t result);
+
+extern void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf);
+
+extern void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci);
+
+extern void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
+extern void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint8_t cl, uint8_t k);
+
+extern void RFCOMM_TestReq(uint8_t* p_data, uint16_t len);
+
+#define RFCOMM_FLOW_STATE_DISABLE 0
+#define RFCOMM_FLOW_STATE_ENABLE 1
+
+extern void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t state);
+
+extern void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars);
+extern void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_STATE* p_pars, uint16_t param_mask);
+
+extern void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_CTRL* p_pars);
+extern void RFCOMM_ControlRsp(tRFC_MCB* p_mcb, uint8_t dlci,
+ tPORT_CTRL* p_pars);
+
+extern void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint8_t line_status);
+/*
+ * Define logical struct used for sending and decoding MX frames
+*/
+typedef struct {
+ uint8_t dlci;
+ uint8_t type;
+ uint8_t cr;
+ uint8_t ea;
+ uint8_t pf;
+ uint8_t credit;
+
+ union {
+ struct {
+ uint8_t dlci;
+ uint8_t frame_type;
+ uint8_t conv_layer;
+ uint8_t priority;
+ uint8_t t1;
+ uint16_t mtu;
+ uint8_t n2;
+ uint8_t k;
+ } pn;
+ struct {
+ uint8_t* p_data;
+ uint16_t data_len;
+ } test;
+ struct {
+ uint8_t dlci;
+ uint8_t signals;
+ uint8_t break_present;
+ uint8_t break_duration;
+ } msc;
+ struct {
+ uint8_t ea;
+ uint8_t cr;
+ uint8_t type;
+ } nsc;
+ struct {
+ uint8_t dlci;
+ uint8_t is_request;
+ uint8_t baud_rate;
+ uint8_t byte_size;
+ uint8_t stop_bits;
+ uint8_t parity;
+ uint8_t parity_type;
+ uint8_t fc_type;
+ uint8_t xon_char;
+ uint8_t xoff_char;
+ uint16_t param_mask;
+ } rpn;
+ struct {
+ uint8_t dlci;
+ uint8_t line_status;
+ } rls;
+ } u;
+} MX_FRAME;
+
+#define LINE_STATUS_NO_ERROR 0x00
+#define LINE_STATUS_OVERRUN 0x02 /* Receive Overrun Error */
+#define LINE_STATUS_RXPARITY 0x04 /* Receive Parity Error */
+#define LINE_STATUS_FRAME 0x08 /* Receive Framing error */
+#define LINE_STATUS_FAILED 0x10 /* Connection Failed */
+
+/*
+ * Define states and events for the RFC multiplexer state machine
+*/
+#define RFC_MX_STATE_IDLE 0
+#define RFC_MX_STATE_WAIT_CONN_CNF 1
+#define RFC_MX_STATE_CONFIGURE 2
+#define RFC_MX_STATE_SABME_WAIT_UA 3
+#define RFC_MX_STATE_WAIT_SABME 4
+#define RFC_MX_STATE_CONNECTED 5
+#define RFC_MX_STATE_DISC_WAIT_UA 6
+
+/*
+ * Define port states
+*/
+#define RFC_STATE_CLOSED 0
+#define RFC_STATE_SABME_WAIT_UA 1
+#define RFC_STATE_ORIG_WAIT_SEC_CHECK 2
+#define RFC_STATE_TERM_WAIT_SEC_CHECK 3
+#define RFC_STATE_OPENED 4
+#define RFC_STATE_DISC_WAIT_UA 5
+
+/*
+ * Events that can be received by multiplexer as well as port state machines
+*/
+#define RFC_EVENT_SABME 0
+#define RFC_EVENT_UA 1
+#define RFC_EVENT_DM 2
+#define RFC_EVENT_DISC 3
+#define RFC_EVENT_UIH 4
+#define RFC_EVENT_TIMEOUT 5
+#define RFC_EVENT_BAD_FRAME 50
+/*
+ * Multiplexer events
+*/
+#define RFC_MX_EVENT_START_REQ 6
+#define RFC_MX_EVENT_START_RSP 7
+#define RFC_MX_EVENT_CLOSE_REQ 8
+#define RFC_MX_EVENT_CONN_CNF 9
+#define RFC_MX_EVENT_CONN_IND 10
+#define RFC_MX_EVENT_CONF_CNF 11
+#define RFC_MX_EVENT_CONF_IND 12
+#define RFC_MX_EVENT_QOS_VIOLATION_IND 13
+#define RFC_MX_EVENT_DISC_IND 14
+#define RFC_MX_EVENT_TEST_CMD 15
+#define RFC_MX_EVENT_TEST_RSP 16
+#define RFC_MX_EVENT_FCON_CMD 17
+#define RFC_MX_EVENT_FCOFF_CMD 18
+#define RFC_MX_EVENT_NSC 19
+#define RFC_MX_EVENT_NSC_RSP 20
+
+/*
+ * Port events
+*/
+#define RFC_EVENT_OPEN 9
+#define RFC_EVENT_ESTABLISH_RSP 11
+#define RFC_EVENT_CLOSE 12
+#define RFC_EVENT_CLEAR 13
+#define RFC_EVENT_DATA 14
+#define RFC_EVENT_SEC_COMPLETE 15
+
+/* seconds to wait for reply with Poll bit */
+#define RFC_T1_TIMEOUT 20
+/* seconds to wait for reply with Poll bit other than MX */
+#define RFC_PORT_T1_TIMEOUT 60
+/* timeout to wait for Mx UIH */
+#define RFC_T2_TIMEOUT 20
+/* If something goes wrong and we send DISC we should not wait for min */
+#define RFC_DISC_TIMEOUT 3
+#define RFC_CLOSE_TIMEOUT 10
+/* first connection to be established on Mx */
+#define RFCOMM_CONN_TIMEOUT 120
+
+/* Define RFComm control block
+*/
+typedef struct {
+ MX_FRAME rx_frame;
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+
+ /* MCB based on the L2CAP's lcid */
+ tRFC_MCB* p_rfc_lcid_mcb[MAX_L2CAP_CHANNELS];
+ bool peer_rx_disabled; /* If true peer sent FCOFF */
+ uint8_t last_mux; /* Last mux allocated */
+ uint8_t last_port; /* Last port allocated */
+} tRFCOMM_CB;
+
+/* Main Control Block for the RFCOMM Layer (PORT and RFC) */
+typedef struct {
+ tRFCOMM_CB rfc;
+ tPORT_CB port;
+ uint8_t trace_level;
+} tRFC_CB;
+
+extern tRFC_CB rfc_cb;
+
+/* Timer running on the multiplexor channel while no DLCI connection is open */
+#define RFC_MCB_INIT_INACT_TIMER 60 /* in seconds */
+
+/* Timer running on the multiplexor channel after last DLCI is released */
+#define RFC_MCB_RELEASE_INACT_TIMER 2 /* in seconds */
+
+/*
+ * Define RFCOMM frame processing errors
+*/
+#define RFCOMM_ERR_BAD_SABME 1
+#define RFCOMM_ERR_BAD_UA 2
+#define RFCOMM_ERR_BAD_DM 3
+#define RFCOMM_ERR_BAD_DISC 4
+#define RFCOMM_ERR_BAD_UIH 5
+
+#ifdef RFCOMM_PRECALC_FCS
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_sabme_fcs[cr][dlci]
+#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_ua_fcs[cr][dlci]
+#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_dm_fcs[cr][dlci]
+#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_disc_fcs[cr][dlci]
+#define RFCOMM_UIH_FCS(p_data, dlci) rfc_uih_fcs[dlci]
+
+#else
+
+extern uint8_t rfc_calc_fcs(uint16_t len, uint8_t* p);
+
+#define RFCOMM_SABME_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_UA_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_DM_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_DISC_FCS(p_data, cr, dlci) rfc_calc_fcs(3, p_data)
+#define RFCOMM_UIH_FCS(p_data, dlci) rfc_calc_fcs(2, p_data)
+
+#endif
+
+extern void rfc_mx_sm_execute(tRFC_MCB* p_mcb, uint16_t event, void* p_data);
+
+/*
+ * Functions provided by the rfc_port_fsm.cc
+*/
+extern void rfc_port_sm_execute(tPORT* p_port, uint16_t event, void* p_data);
+
+extern void rfc_process_pn(tRFC_MCB* p_rfc_mcb, bool is_command,
+ MX_FRAME* p_frame);
+extern void rfc_process_msc(tRFC_MCB* p_rfc_mcb, bool is_command,
+ MX_FRAME* p_frame);
+extern void rfc_process_rpn(tRFC_MCB* p_rfc_mcb, bool is_command,
+ bool is_request, MX_FRAME* p_frame);
+extern void rfc_process_rls(tRFC_MCB* p_rfc_mcb, bool is_command,
+ MX_FRAME* p_frame);
+extern void rfc_process_nsc(tRFC_MCB* p_rfc_mcb, MX_FRAME* p_frame);
+extern void rfc_process_test_rsp(tRFC_MCB* p_rfc_mcb, BT_HDR* p_buf);
+extern void rfc_process_fcon(tRFC_MCB* p_rfc_mcb, bool is_command);
+extern void rfc_process_fcoff(tRFC_MCB* p_rfc_mcb, bool is_command);
+extern void rfc_process_l2cap_congestion(tRFC_MCB* p_mcb, bool is_congested);
+
+/*
+ * Functions provided by the rfc_utils.cc
+*/
+tRFC_MCB* rfc_alloc_multiplexer_channel(BD_ADDR bd_addr, bool is_initiator);
+extern void rfc_release_multiplexer_channel(tRFC_MCB* p_rfc_mcb);
+extern void rfc_timer_start(tRFC_MCB* p_rfc_mcb, uint16_t timeout);
+extern void rfc_timer_stop(tRFC_MCB* p_rfc_mcb);
+extern void rfc_port_timer_start(tPORT* p_port, uint16_t tout);
+extern void rfc_port_timer_stop(tPORT* p_port);
+
+bool rfc_check_uih_fcs(uint8_t dlci, uint8_t received_fcs);
+bool rfc_check_fcs(uint16_t len, uint8_t* p, uint8_t received_fcs);
+tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid);
+extern void rfc_save_lcid_mcb(tRFC_MCB* p_rfc_mcb, uint16_t lcid);
+extern void rfc_check_mcb_active(tRFC_MCB* p_mcb);
+extern void rfc_port_closed(tPORT* p_port);
+extern void rfc_sec_check_complete(BD_ADDR bd_addr, tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res);
+extern void rfc_inc_credit(tPORT* p_port, uint8_t credit);
+extern void rfc_dec_credit(tPORT* p_port);
+extern void rfc_check_send_cmd(tRFC_MCB* p_mcb, BT_HDR* p_buf);
+
+/*
+ * Functions provided by the rfc_ts_frames.cc
+*/
+extern void rfc_send_sabme(tRFC_MCB* p_rfc_mcb, uint8_t dlci);
+extern void rfc_send_ua(tRFC_MCB* p_rfc_mcb, uint8_t dlci);
+extern void rfc_send_dm(tRFC_MCB* p_rfc_mcb, uint8_t dlci, bool pf);
+extern void rfc_send_disc(tRFC_MCB* p_rfc_mcb, uint8_t dlci);
+extern void rfc_send_pn(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ uint16_t mtu, uint8_t cl, uint8_t k);
+extern void rfc_send_test(tRFC_MCB* p_rfc_mcb, bool is_command, BT_HDR* p_buf);
+extern void rfc_send_msc(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ tPORT_CTRL* p_pars);
+extern void rfc_send_rls(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ uint8_t status);
+extern void rfc_send_rpn(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ tPORT_STATE* p_pars, uint16_t mask);
+extern void rfc_send_fcon(tRFC_MCB* p_mcb, bool is_command);
+extern void rfc_send_fcoff(tRFC_MCB* p_mcb, bool is_command);
+extern void rfc_send_buf_uih(tRFC_MCB* p_rfc_mcb, uint8_t dlci, BT_HDR* p_buf);
+extern void rfc_send_credit(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t credit);
+extern void rfc_process_mx_message(tRFC_MCB* p_rfc_mcb, BT_HDR* p_buf);
+extern uint8_t rfc_parse_data(tRFC_MCB* p_rfc_mcb, MX_FRAME* p_frame,
+ BT_HDR* p_buf);
+
+/* Call back functions from RFCOMM */
+extern void rfcomm_l2cap_if_init(void);
+
+extern void PORT_StartInd(tRFC_MCB* p_mcb);
+extern void PORT_StartCnf(tRFC_MCB* p_mcb, uint16_t result);
+
+extern void PORT_CloseInd(tRFC_MCB* p_mcb);
+extern void Port_TimeOutCloseMux(tRFC_MCB* p_mcb);
+
+extern void PORT_DlcEstablishInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu);
+extern void PORT_DlcEstablishCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint16_t result);
+
+extern void PORT_DataInd(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf);
+
+extern void PORT_DlcReleaseInd(tRFC_MCB* p_mcb, uint8_t dlci);
+
+extern void PORT_ParNegInd(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint8_t cl, uint8_t k);
+extern void PORT_ParNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu,
+ uint8_t cl, uint8_t k);
+
+extern void PORT_TestCnf(tRFC_MCB* p_mcb, uint8_t* p_data, uint16_t len);
+
+extern void PORT_FlowInd(tRFC_MCB* p_mcb, uint8_t dlci, bool fc);
+
+extern void PORT_PortNegInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
+ uint16_t param_mask);
+extern void PORT_PortNegCnf(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
+ uint16_t result);
+
+extern void PORT_ControlInd(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars);
+extern void PORT_ControlCnf(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars);
+
+extern void PORT_LineStatusInd(tRFC_MCB* p_mcb, uint8_t dlci,
+ uint8_t line_status);
+
+#endif
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_l2cap_if.cc b/mtkbt/code/bt/stack/rfcomm/rfc_l2cap_if.cc
new file mode 100755
index 0000000..85be99b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_l2cap_if.cc
@@ -0,0 +1,412 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains L2CAP interface functions
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_target.h"
+
+#include "bt_common.h"
+#include "osi/include/osi.h"
+#include "osi/include/time.h"
+
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/*
+ * Define Callback functions to be called by L2CAP
+*/
+static void RFCOMM_ConnectInd(BD_ADDR bd_addr, uint16_t lcid, uint16_t psm,
+ uint8_t id);
+static void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t err);
+static void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+static void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
+static void RFCOMM_DisconnectInd(uint16_t lcid, bool is_clear);
+static void RFCOMM_QoSViolationInd(UNUSED_ATTR BD_ADDR bd_addr);
+static void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf);
+static void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested);
+
+/*******************************************************************************
+ *
+ * Function rfcomm_l2cap_if_init
+ *
+ * Description This function is called during the RFCOMM task startup
+ * to register interface functions with L2CAP.
+ *
+ ******************************************************************************/
+void rfcomm_l2cap_if_init(void) {
+ tL2CAP_APPL_INFO* p_l2c = &rfc_cb.rfc.reg_info;
+
+ p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd;
+ p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf;
+ p_l2c->pL2CA_ConnectPnd_Cb = NULL;
+ p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd;
+ p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf;
+ p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd;
+ p_l2c->pL2CA_DisconnectCfm_Cb = NULL;
+ p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd;
+ p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd;
+ p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
+ p_l2c->pL2CA_TxComplete_Cb = NULL;
+
+ L2CA_Register(BT_PSM_RFCOMM, p_l2c);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ConnectInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_ConnectInd received. Allocate multiplexer control
+ * block and dispatch the event to it.
+ *
+ ******************************************************************************/
+void RFCOMM_ConnectInd(BD_ADDR bd_addr, uint16_t lcid, UNUSED_ATTR uint16_t psm,
+ uint8_t id) {
+ tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false);
+
+ if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) {
+ /* if this is collision case */
+ if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) {
+ p_mcb->pending_lcid = lcid;
+ p_mcb->pending_id = id;
+
+ /* wait random timeout (2 - 12) to resolve collision */
+ /* if peer gives up then local device rejects incoming connection and
+ * continues as initiator */
+ /* if timeout, local device disconnects outgoing connection and continues
+ * as acceptor */
+ RFCOMM_TRACE_DEBUG(
+ "RFCOMM_ConnectInd start timer for collision, initiator's "
+ "LCID(0x%x), acceptor's LCID(0x%x)",
+ p_mcb->lcid, p_mcb->pending_lcid);
+
+ rfc_timer_start(p_mcb, (uint16_t)(time_get_os_boottime_ms() % 10 + 2));
+ return;
+ } else {
+ /* we cannot accept connection request from peer at this state */
+ /* don't update lcid */
+ p_mcb = NULL;
+ }
+ } else {
+ /* store mcb even if null */
+ rfc_save_lcid_mcb(p_mcb, lcid);
+ }
+
+ if (p_mcb == NULL) {
+ L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
+ return;
+ }
+ p_mcb->lcid = lcid;
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &id);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ConnectCnf
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_ConnectCnf received. Save L2CAP handle and dispatch
+ * event to the FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid);
+ return;
+ }
+
+ if (p_mcb->pending_lcid) {
+ /* if peer rejects our connect request but peer's connect request is pending
+ */
+ if (result != L2CAP_CONN_OK) {
+ uint16_t i;
+ uint8_t idx;
+
+ RFCOMM_TRACE_DEBUG(
+ "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)",
+ p_mcb->pending_lcid);
+
+ /* remove mcb from mapping table */
+ rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+
+ p_mcb->lcid = p_mcb->pending_lcid;
+ p_mcb->is_initiator = false;
+ p_mcb->state = RFC_MX_STATE_IDLE;
+
+ /* store mcb into mapping table */
+ rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
+
+ /* update direction bit */
+ for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
+ idx = p_mcb->port_inx[i];
+ if (idx != 0) {
+ p_mcb->port_inx[i] = 0;
+ p_mcb->port_inx[i + 1] = idx;
+ rfc_cb.port.port[idx - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i,
+ rfc_cb.port.port[idx - 1].dlci);
+ }
+ }
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+ return;
+ } else {
+ RFCOMM_TRACE_DEBUG("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)",
+ p_mcb->pending_lcid);
+
+ /* Peer gave up his connection request, make sure cleaning up L2CAP
+ * channel */
+ L2CA_ConnectRsp(p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid,
+ L2CAP_CONN_NO_RESOURCES, 0);
+
+ p_mcb->pending_lcid = 0;
+ }
+ }
+
+ /* Save LCID to be used in all consecutive calls to L2CAP */
+ p_mcb->lcid = lcid;
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ConfigInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_ConfigInd received. Save parameters in the control
+ * block and dispatch event to the FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_IND, (void*)p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ConfigCnf
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_ConfigCnf received. Save L2CAP handle and dispatch
+ * event to the FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_CNF, (void*)p_cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_QoSViolationInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_QoSViolationIndInd received. Dispatch event to the
+ * FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_QoSViolationInd(UNUSED_ATTR BD_ADDR bd_addr) {}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_DisconnectInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * L2CA_DisconnectInd received. Dispatch event to the FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+
+ if (is_conf_needed) {
+ L2CA_DisconnectRsp(lcid);
+ }
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid);
+ return;
+ }
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_BufDataInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * data RFCOMM frame is received. Parse the frames, check
+ * the checksum and dispatch event to multiplexer or port
+ * state machine depending on the frame destination.
+ *
+ ******************************************************************************/
+void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+ tPORT* p_port;
+ uint8_t event;
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_WARNING("RFCOMM_BufDataInd LCID:0x%x", lcid);
+ osi_free(p_buf);
+ return;
+ }
+
+ event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
+
+ /* If the frame did not pass validation just ignore it */
+ if (event == RFC_EVENT_BAD_FRAME) {
+ osi_free(p_buf);
+ return;
+ }
+
+ if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
+ /* Take special care of the Multiplexer Control Messages */
+ if (event == RFC_EVENT_UIH) {
+ rfc_process_mx_message(p_mcb, p_buf);
+ return;
+ }
+
+ /* Other multiplexer events go to state machine */
+ rfc_mx_sm_execute(p_mcb, event, NULL);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* The frame was received on the data channel DLCI, verify that DLC exists */
+ if (((p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci)) ==
+ NULL) ||
+ (!p_port->rfc.p_mcb)) {
+ /* If this is a SABME on the new port, check if any appl is waiting for it
+ */
+ if (event != RFC_EVENT_SABME) {
+ if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) ||
+ (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr))
+ rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
+ osi_free(p_buf);
+ return;
+ }
+
+ p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci);
+ if (p_port == NULL) {
+ rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
+ osi_free(p_buf);
+ return;
+ }
+ p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
+ p_port->rfc.p_mcb = p_mcb;
+ }
+
+ if (event == RFC_EVENT_UIH) {
+ if (p_buf->len > 0)
+ rfc_port_sm_execute(p_port, event, p_buf);
+ else
+ osi_free(p_buf);
+
+ if (rfc_cb.rfc.rx_frame.credit != 0)
+ rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit);
+
+ return;
+ }
+ rfc_port_sm_execute(p_port, event, NULL);
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_CongestionStatusInd
+ *
+ * Description This is a callback function called by L2CAP when
+ * data RFCOMM L2CAP congestion status changes
+ *
+ ******************************************************************************/
+void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) {
+ tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
+
+ if (!p_mcb) {
+ RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
+ return;
+ } else {
+ RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
+ }
+ rfc_process_l2cap_congestion(p_mcb, is_congested);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_find_lcid_mcb
+ *
+ * Description This function returns MCB block supporting local cid
+ *
+ ******************************************************************************/
+tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) {
+ tRFC_MCB* p_mcb;
+
+ if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) {
+ RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid);
+ return (NULL);
+ } else {
+ p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID];
+ if (p_mcb != NULL) {
+ if (p_mcb->lcid != lcid) {
+ RFCOMM_TRACE_WARNING(
+ "rfc_find_lcid_mcb LCID reused LCID:0x%x current:0x%x", lcid,
+ p_mcb->lcid);
+ return (NULL);
+ }
+ }
+ }
+ return (p_mcb);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_save_lcid_mcb
+ *
+ * Description This function returns MCB block supporting local cid
+ *
+ ******************************************************************************/
+void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
+ if (lcid < L2CAP_BASE_APPL_CID) return;
+ rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_mx_fsm.cc b/mtkbt/code/bt/stack/rfcomm/rfc_mx_fsm.cc
new file mode 100755
index 0000000..9897a33
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_mx_fsm.cc
@@ -0,0 +1,669 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains state machine and action routines for multiplexer
+ * channel of the RFCOMM unit
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/** M: Bug Fix For rfcomm connection establishment @{ */
+// Some legacy devices need user input pin code which take a few seconds.
+// It will lead to disconnection when expire the timer that started in PORT_StartCnf.
+// Do not start timer for these devices.
+#include "btm_int.h"
+/** @} */
+
+#define L2CAP_SUCCESS 0
+#define L2CAP_ERROR 1
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, uint16_t event, void* p_data);
+static void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data);
+static void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data);
+static void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data);
+static void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data);
+static void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, uint16_t event,
+ UNUSED_ATTR void* p_data);
+static void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data);
+
+static void rfc_mx_send_config_req(tRFC_MCB* p_mcb);
+static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg);
+static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_execute
+ *
+ * Description This function sends multiplexor events through the state
+ * machine.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_execute(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ switch (p_mcb->state) {
+ case RFC_MX_STATE_IDLE:
+ rfc_mx_sm_state_idle(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_WAIT_CONN_CNF:
+ rfc_mx_sm_state_wait_conn_cnf(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_CONFIGURE:
+ rfc_mx_sm_state_configure(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_SABME_WAIT_UA:
+ rfc_mx_sm_sabme_wait_ua(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_WAIT_SABME:
+ rfc_mx_sm_state_wait_sabme(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_CONNECTED:
+ rfc_mx_sm_state_connected(p_mcb, event, p_data);
+ break;
+
+ case RFC_MX_STATE_DISC_WAIT_UA:
+ rfc_mx_sm_state_disc_wait_ua(p_mcb, event, p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_idle
+ *
+ * Description This function handles events when the multiplexer is in
+ * IDLE state. This state exists when connection is being
+ * initially established.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_idle - evt:%d", event);
+ switch (event) {
+ case RFC_MX_EVENT_START_REQ: {
+ /* Initialize L2CAP MTU */
+ p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+ uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
+ if (lcid == 0) {
+ rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+ p_mcb->lcid = 0;
+ PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ p_mcb->lcid = lcid;
+ /* Save entry for quicker access to mcb based on the LCID */
+ rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
+
+ p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+ return;
+ }
+
+ case RFC_MX_EVENT_START_RSP:
+ case RFC_MX_EVENT_CONN_CNF:
+ case RFC_MX_EVENT_CONF_IND:
+ case RFC_MX_EVENT_CONF_CNF:
+ RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ case RFC_MX_EVENT_CONN_IND:
+
+ rfc_timer_start(p_mcb, RFCOMM_CONN_TIMEOUT);
+ L2CA_ConnectRsp(p_mcb->bd_addr, *((uint8_t*)p_data), p_mcb->lcid,
+ L2CAP_CONN_OK, 0);
+
+ rfc_mx_send_config_req(p_mcb);
+
+ p_mcb->state = RFC_MX_STATE_CONFIGURE;
+ return;
+
+ case RFC_EVENT_SABME:
+ break;
+
+ case RFC_EVENT_UA:
+ case RFC_EVENT_DM:
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, true);
+ return;
+
+ case RFC_EVENT_UIH:
+ rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, false);
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_wait_conn_cnf
+ *
+ * Description This function handles events when the multiplexer is
+ * waiting for Connection Confirm from L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_conn_cnf - evt:%d", event);
+ switch (event) {
+ case RFC_MX_EVENT_START_REQ:
+ RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ /* There is some new timing so that Config Ind comes before security is
+ completed
+ so we are still waiting fo the confirmation. */
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind(p_mcb, (tL2CAP_CFG_INFO*)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONN_CNF:
+ if (*((uint16_t*)p_data) != L2CAP_SUCCESS) {
+ p_mcb->state = RFC_MX_STATE_IDLE;
+
+ PORT_StartCnf(p_mcb, *((uint16_t*)p_data));
+ return;
+ }
+ p_mcb->state = RFC_MX_STATE_CONFIGURE;
+ rfc_mx_send_config_req(p_mcb);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq(p_mcb->lcid);
+
+ /* we gave up outgoing connection request then try peer's request */
+ if (p_mcb->pending_lcid) {
+ uint16_t i;
+ uint8_t idx;
+
+ RFCOMM_TRACE_DEBUG(
+ "RFCOMM MX retry as acceptor in collision case - evt:%d in "
+ "state:%d",
+ event, p_mcb->state);
+
+ rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+ p_mcb->lcid = p_mcb->pending_lcid;
+ rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
+
+ p_mcb->is_initiator = false;
+
+ /* update direction bit */
+ for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
+ idx = p_mcb->port_inx[i];
+ if (idx != 0) {
+ p_mcb->port_inx[i] = 0;
+ p_mcb->port_inx[i + 1] = idx;
+ rfc_cb.port.port[idx - 1].dlci += 1;
+ RFCOMM_TRACE_DEBUG("RFCOMM MX - DLCI:%d -> %d", i,
+ rfc_cb.port.port[idx - 1].dlci);
+ }
+ }
+
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
+ } else {
+ PORT_CloseInd(p_mcb);
+ }
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_configure
+ *
+ * Description This function handles events when the multiplexer in the
+ * configuration state.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_configure - evt:%d", event);
+ switch (event) {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+
+ RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind(p_mcb, (tL2CAP_CFG_INFO*)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONF_CNF:
+ rfc_mx_conf_cnf(p_mcb, (tL2CAP_CFG_INFO*)p_data);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq(p_mcb->lcid);
+
+ PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_sabme_wait_ua
+ *
+ * Description This function handles events when the multiplexer sent
+ * SABME and is waiting for UA reply.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
+ UNUSED_ATTR void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_sabme_wait_ua - evt:%d", event);
+ switch (event) {
+ case RFC_MX_EVENT_START_REQ:
+ case RFC_MX_EVENT_CONN_CNF:
+ RFCOMM_TRACE_ERROR("Mx error state %d event %d", p_mcb->state, event);
+ return;
+
+ /* workaround: we don't support reconfig */
+ /* commented out until we support reconfig
+ case RFC_MX_EVENT_CONF_IND:
+ rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+
+ case RFC_MX_EVENT_CONF_CNF:
+ rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
+ return;
+ */
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_EVENT_UA:
+ rfc_timer_stop(p_mcb);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = true;
+
+ PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_timer_stop(p_mcb);
+ /* Case falls through */
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq(p_mcb->lcid);
+
+ PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_wait_sabme
+ *
+ * Description This function handles events when the multiplexer is
+ * waiting for SABME on the acceptor side after configuration
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, uint16_t event, void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_wait_sabme - evt:%d", event);
+ switch (event) {
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* if we gave up outgoing connection request */
+ if (p_mcb->pending_lcid) {
+ p_mcb->pending_lcid = 0;
+
+ rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
+
+ rfc_timer_stop(p_mcb);
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = true;
+
+ /* MX channel collision has been resolved, continue to open ports */
+ PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
+ } else {
+ rfc_timer_stop(p_mcb);
+ PORT_StartInd(p_mcb);
+ }
+ return;
+
+ case RFC_MX_EVENT_START_RSP:
+ if (*((uint16_t*)p_data) != RFCOMM_SUCCESS)
+ rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, true);
+ else {
+ rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
+
+ p_mcb->state = RFC_MX_STATE_CONNECTED;
+ p_mcb->peer_ready = true;
+ /** M: Bug Fix For rfcomm connection establishment @{ */
+ // Some legacy devices need user input pin code which take a few seconds.
+ // It will lead to disconnection when expire the timer that started in PORT_StartCnf.
+ // Do not start timer for these devices.
+ tBTM_SEC_DEV_REC *p_dev_rec;
+ p_dev_rec = btm_find_dev(p_mcb->bd_addr);
+ if (p_dev_rec && !BTM_SEC_IS_SM4(p_dev_rec->sm4))
+ {
+ RFCOMM_TRACE_EVENT ("Do not start timer for devices that not support sm4");
+ return;
+ }
+ else
+ /** @} */
+ PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
+ }
+ return;
+
+ case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
+ case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
+ case RFC_EVENT_TIMEOUT:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ L2CA_DisconnectReq(p_mcb->lcid);
+
+ PORT_CloseInd(p_mcb);
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_connected
+ *
+ * Description This function handles events when the multiplexer is
+ * in the CONNECTED state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, uint16_t event,
+ UNUSED_ATTR void* p_data) {
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_connected - evt:%d", event);
+
+ switch (event) {
+ case RFC_EVENT_TIMEOUT:
+ case RFC_MX_EVENT_CLOSE_REQ:
+ rfc_timer_start(p_mcb, RFC_DISC_TIMEOUT);
+ p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA;
+ rfc_send_disc(p_mcb, RFCOMM_MX_DLCI);
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_EVENT_DISC:
+ /* Reply with UA. If initiator bring down L2CAP connection */
+ /* If server wait for some time if client decide to reinitiate channel */
+ rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
+ if (p_mcb->is_initiator) {
+ L2CA_DisconnectReq(p_mcb->lcid);
+ }
+ /* notify all ports that connection is gone */
+ PORT_CloseInd(p_mcb);
+ return;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_sm_state_disc_wait_ua
+ *
+ * Description This function handles events when the multiplexer sent
+ * DISC and is waiting for UA reply.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, uint16_t event,
+ void* p_data) {
+ BT_HDR* p_buf;
+
+ RFCOMM_TRACE_EVENT("rfc_mx_sm_state_disc_wait_ua - evt:%d", event);
+ switch (event) {
+ case RFC_EVENT_UA:
+ case RFC_EVENT_DM:
+ case RFC_EVENT_TIMEOUT:
+ L2CA_DisconnectReq(p_mcb->lcid);
+
+ if (p_mcb->restart_required) {
+ /* Start Request was received while disconnecting. Execute it again */
+ uint16_t lcid = L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
+ if (lcid == 0) {
+ rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+ p_mcb->lcid = 0;
+ PORT_StartCnf(p_mcb, RFCOMM_ERROR);
+ return;
+ }
+ p_mcb->lcid = lcid;
+ /* Save entry for quicker access to mcb based on the LCID */
+ rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
+
+ /* clean up before reuse it */
+ while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_mcb->cmd_q)) != NULL)
+ osi_free(p_buf);
+
+ rfc_timer_start(p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+ p_mcb->is_initiator = true;
+ p_mcb->restart_required = false;
+ p_mcb->local_cfg_sent = false;
+ p_mcb->peer_cfg_rcvd = false;
+
+ p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
+ return;
+ }
+ rfc_release_multiplexer_channel(p_mcb);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, false);
+ return;
+
+ case RFC_MX_EVENT_START_REQ:
+ p_mcb->restart_required = true;
+ return;
+
+ case RFC_MX_EVENT_DISC_IND:
+ p_mcb->state = RFC_MX_STATE_IDLE;
+ PORT_CloseInd(p_mcb);
+ return;
+
+ case RFC_MX_EVENT_CLOSE_REQ:
+ return;
+
+ case RFC_MX_EVENT_QOS_VIOLATION_IND:
+ break;
+ }
+ RFCOMM_TRACE_EVENT("RFCOMM MX ignored - evt:%d in state:%d", event,
+ p_mcb->state);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_send_config_req
+ *
+ * Description This function handles L2CA_ConnectInd message from the
+ * L2CAP. Accept connection.
+ *
+ ******************************************************************************/
+static void rfc_mx_send_config_req(tRFC_MCB* p_mcb) {
+ tL2CAP_CFG_INFO cfg;
+
+ RFCOMM_TRACE_EVENT("rfc_mx_send_config_req");
+
+ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
+
+ cfg.mtu_present = true;
+ cfg.mtu = L2CAP_MTU_SIZE;
+
+ /* Defaults set by memset
+ cfg.flush_to_present = false;
+ cfg.qos_present = false;
+ cfg.fcr_present = false;
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcs_present = false;
+ cfg.fcs = N/A when fcs_present is false;
+ */
+ L2CA_ConfigReq(p_mcb->lcid, &cfg);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_conf_cnf
+ *
+ * Description This function handles L2CA_ConfigCnf message from the
+ * L2CAP. If result is not success tell upper layer that
+ * start has not been accepted. If initiator send SABME
+ * on DLCI 0. T1 is still running.
+ *
+ ******************************************************************************/
+static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
+ RFCOMM_TRACE_EVENT("rfc_mx_conf_cnf p_cfg:%08x res:%d ", p_cfg,
+ (p_cfg) ? p_cfg->result : 0);
+
+ if (p_cfg->result != L2CAP_CFG_OK) {
+ if (p_mcb->is_initiator) {
+ PORT_StartCnf(p_mcb, p_cfg->result);
+ L2CA_DisconnectReq(p_mcb->lcid);
+ }
+ rfc_release_multiplexer_channel(p_mcb);
+ return;
+ }
+
+ p_mcb->local_cfg_sent = true;
+ if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->peer_cfg_rcvd) {
+ if (p_mcb->is_initiator) {
+ p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+ rfc_send_sabme(p_mcb, RFCOMM_MX_DLCI);
+ rfc_timer_start(p_mcb, RFC_T1_TIMEOUT);
+ } else {
+ p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+ rfc_timer_start(
+ p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
+ to allow the user more than 10 sec to type in the
+ pin which can be e.g. 16 digits */
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_mx_conf_ind
+ *
+ * Description This function handles L2CA_ConfigInd message from the
+ * L2CAP. Send the L2CA_ConfigRsp message.
+ *
+ ******************************************************************************/
+static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
+ /* Save peer L2CAP MTU if present */
+ /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
+ if (p_cfg->mtu_present)
+ p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
+ else
+ p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
+
+ p_cfg->mtu_present = false;
+ p_cfg->flush_to_present = false;
+ p_cfg->qos_present = false;
+
+ p_cfg->result = L2CAP_CFG_OK;
+
+ L2CA_ConfigRsp(p_mcb->lcid, p_cfg);
+
+ p_mcb->peer_cfg_rcvd = true;
+ if ((p_mcb->state == RFC_MX_STATE_CONFIGURE) && p_mcb->local_cfg_sent) {
+ if (p_mcb->is_initiator) {
+ p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
+ rfc_send_sabme(p_mcb, RFCOMM_MX_DLCI);
+ rfc_timer_start(p_mcb, RFC_T1_TIMEOUT);
+ } else {
+ p_mcb->state = RFC_MX_STATE_WAIT_SABME;
+ rfc_timer_start(
+ p_mcb, RFCOMM_CONN_TIMEOUT); /* - increased from T2=20 to CONN=120
+ to allow the user more than 10 sec to type in the
+ pin which can be e.g. 16 digits */
+ }
+ }
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_port_fsm.cc b/mtkbt/code/bt/stack/rfcomm/rfc_port_fsm.cc
new file mode 100755
index 0000000..dfe4b04
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_port_fsm.cc
@@ -0,0 +1,864 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains state machine and action routines for a port of the
+ * RFCOMM unit
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void rfc_port_sm_state_closed(tPORT* p_port, uint16_t event,
+ void* p_data);
+static void rfc_port_sm_sabme_wait_ua(tPORT* p_port, uint16_t event,
+ void* p_data);
+static void rfc_port_sm_opened(tPORT* p_port, uint16_t event, void* p_data);
+static void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, uint16_t event,
+ void* p_data);
+static void rfc_port_sm_term_wait_sec_check(tPORT* p_port, uint16_t event,
+ void* p_data);
+static void rfc_port_sm_disc_wait_ua(tPORT* p_port, uint16_t event,
+ void* p_data);
+
+static void rfc_port_uplink_data(tPORT* p_port, BT_HDR* p_buf);
+
+static void rfc_set_port_state(tPORT_STATE* port_pars, MX_FRAME* p_frame);
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_execute
+ *
+ * Description This function sends port events through the state
+ * machine.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_execute(tPORT* p_port, uint16_t event, void* p_data) {
+ if (!p_port) {
+ RFCOMM_TRACE_WARNING("NULL port event %d", event);
+ return;
+ }
+
+ switch (p_port->rfc.state) {
+ case RFC_STATE_CLOSED:
+ rfc_port_sm_state_closed(p_port, event, p_data);
+ break;
+
+ case RFC_STATE_SABME_WAIT_UA:
+ rfc_port_sm_sabme_wait_ua(p_port, event, p_data);
+ break;
+
+ case RFC_STATE_ORIG_WAIT_SEC_CHECK:
+ rfc_port_sm_orig_wait_sec_check(p_port, event, p_data);
+ break;
+
+ case RFC_STATE_TERM_WAIT_SEC_CHECK:
+ rfc_port_sm_term_wait_sec_check(p_port, event, p_data);
+ break;
+
+ case RFC_STATE_OPENED:
+ rfc_port_sm_opened(p_port, event, p_data);
+ break;
+
+ case RFC_STATE_DISC_WAIT_UA:
+ rfc_port_sm_disc_wait_ua(p_port, event, p_data);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_state_closed
+ *
+ * Description This function handles events when the port is in
+ * CLOSED state. This state exists when port is
+ * being initially established.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_state_closed(tPORT* p_port, uint16_t event, void* p_data) {
+ switch (event) {
+ case RFC_EVENT_OPEN:
+ p_port->rfc.state = RFC_STATE_ORIG_WAIT_SEC_CHECK;
+ btm_sec_mx_access_request(
+ p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM, true, BTM_SEC_PROTO_RFCOMM,
+ (uint32_t)(p_port->dlci / 2), &rfc_sec_check_complete, p_port);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ break;
+
+ case RFC_EVENT_CLEAR:
+ return;
+
+ case RFC_EVENT_DATA:
+ osi_free(p_data);
+ break;
+
+ case RFC_EVENT_SABME:
+ /* make sure the multiplexer disconnect timer is not running (reconnect
+ * case) */
+ rfc_timer_stop(p_port->rfc.p_mcb);
+
+ /* Open will be continued after security checks are passed */
+ p_port->rfc.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
+ btm_sec_mx_access_request(p_port->rfc.p_mcb->bd_addr, BT_PSM_RFCOMM,
+ false, BTM_SEC_PROTO_RFCOMM,
+ (uint32_t)(p_port->dlci / 2),
+ &rfc_sec_check_complete, p_port);
+ return;
+
+ case RFC_EVENT_UA:
+ return;
+
+ case RFC_EVENT_DM:
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, false);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, false);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ Port_TimeOutCloseMux(p_port->rfc.p_mcb);
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+ }
+
+ RFCOMM_TRACE_WARNING("Port state closed Event ignored %d", event);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_sabme_wait_ua
+ *
+ * Description This function handles events when SABME on the DLC was
+ * sent and SM is waiting for UA or DM.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_sabme_wait_ua(tPORT* p_port, uint16_t event, void* p_data) {
+ switch (event) {
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_ESTABLISH_RSP:
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT);
+ rfc_send_disc(p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.expected_rsp = 0;
+ p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ osi_free(p_data);
+ break;
+
+ case RFC_EVENT_UA:
+ rfc_port_timer_stop(p_port);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
+ p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
+ return;
+
+ case RFC_EVENT_DM:
+ p_port->rfc.p_mcb->is_disc_initiator = true;
+ PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
+ p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+ PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
+ p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* Continue to wait for the UA the SABME this side sent */
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
+ p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_ERROR);
+ return;
+ }
+ RFCOMM_TRACE_WARNING("Port state sabme_wait_ua Event ignored %d", event);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_term_wait_sec_check
+ *
+ * Description This function handles events for the port in the
+ * WAIT_SEC_CHECK state. SABME has been received from the
+ * peer and Security Manager verifes BD_ADDR, before we can
+ * send ESTABLISH_IND to the Port entity
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_term_wait_sec_check(tPORT* p_port, uint16_t event,
+ void* p_data) {
+ switch (event) {
+ case RFC_EVENT_SEC_COMPLETE:
+ if (*((uint8_t*)p_data) != BTM_SUCCESS) {
+ /* Authentication/authorization failed. If link is still */
+ /* up send DM and check if we need to start inactive timer */
+ if (p_port->rfc.p_mcb) {
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, true);
+ p_port->rfc.p_mcb->is_disc_initiator = true;
+ port_rfc_closed(p_port, PORT_SEC_FAILED);
+ }
+ } else {
+ PORT_DlcEstablishInd(p_port->rfc.p_mcb, p_port->dlci,
+ p_port->rfc.p_mcb->peer_l2cap_mtu);
+ }
+ return;
+
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_CLOSE:
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+
+ case RFC_EVENT_CLEAR:
+ btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ RFCOMM_TRACE_ERROR("Port error state Term Wait Sec event Data");
+ osi_free(p_data);
+ return;
+
+ case RFC_EVENT_SABME:
+ /* Ignore SABME retransmission if client dares to do so */
+ return;
+
+ case RFC_EVENT_DISC:
+ btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+
+ PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ return;
+
+ case RFC_EVENT_ESTABLISH_RSP:
+ if (*((uint8_t*)p_data) != RFCOMM_SUCCESS) {
+ if (p_port->rfc.p_mcb)
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, true);
+ } else {
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.state = RFC_STATE_OPENED;
+ }
+ return;
+ }
+ RFCOMM_TRACE_WARNING("Port state term_wait_sec_check Event ignored %d",
+ event);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_orig_wait_sec_check
+ *
+ * Description This function handles events for the port in the
+ * ORIG_WAIT_SEC_CHECK state. RFCOMM is waiting for Security
+ * manager to finish before sending SABME to the peer
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, uint16_t event,
+ void* p_data) {
+ switch (event) {
+ case RFC_EVENT_SEC_COMPLETE:
+ if (*((uint8_t*)p_data) != BTM_SUCCESS) {
+ p_port->rfc.p_mcb->is_disc_initiator = true;
+ PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, 0,
+ RFCOMM_SECURITY_ERR);
+ rfc_port_closed(p_port);
+ return;
+ }
+ rfc_send_sabme(p_port->rfc.p_mcb, p_port->dlci);
+ rfc_port_timer_start(p_port, RFC_PORT_T1_TIMEOUT);
+ p_port->rfc.state = RFC_STATE_SABME_WAIT_UA;
+ return;
+
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_SABME: /* Peer should not use the same dlci */
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ RFCOMM_TRACE_ERROR("Port error state Orig Wait Sec event Data");
+ osi_free(p_data);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ return;
+ }
+ RFCOMM_TRACE_WARNING("Port state orig_wait_sec_check Event ignored %d",
+ event);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_opened
+ *
+ * Description This function handles events for the port in the OPENED
+ * state
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_opened(tPORT* p_port, uint16_t event, void* p_data) {
+ switch (event) {
+ case RFC_EVENT_OPEN:
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+
+ case RFC_EVENT_CLOSE:
+ rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT);
+ rfc_send_disc(p_port->rfc.p_mcb, p_port->dlci);
+ p_port->rfc.expected_rsp = 0;
+ p_port->rfc.state = RFC_STATE_DISC_WAIT_UA;
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ /* Send credits in the frame. Pass them in the layer specific member of
+ * the hdr. */
+ /* There might be an initial case when we reduced rx_max and credit_rx is
+ * still */
+ /* bigger. Make sure that we do not send 255 */
+ if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) &&
+ (((BT_HDR*)p_data)->len < p_port->peer_mtu) &&
+ (!p_port->rx.user_fc) &&
+ (p_port->credit_rx_max > p_port->credit_rx)) {
+ ((BT_HDR*)p_data)->layer_specific =
+ (uint8_t)(p_port->credit_rx_max - p_port->credit_rx);
+ p_port->credit_rx = p_port->credit_rx_max;
+ } else {
+ ((BT_HDR*)p_data)->layer_specific = 0;
+ }
+ rfc_send_buf_uih(p_port->rfc.p_mcb, p_port->dlci, (BT_HDR*)p_data);
+ rfc_dec_credit(p_port);
+ return;
+
+ case RFC_EVENT_UA:
+ return;
+
+ case RFC_EVENT_SABME:
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_DM:
+ PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DISC:
+ p_port->rfc.state = RFC_STATE_CLOSED;
+ rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
+ if (!fixed_queue_is_empty(p_port->rx.queue)) {
+ /* give a chance to upper stack to close port properly */
+ RFCOMM_TRACE_DEBUG("port queue is not empty");
+ rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT);
+ } else
+ PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
+ return;
+
+ case RFC_EVENT_UIH:
+ rfc_port_uplink_data(p_port, (BT_HDR*)p_data);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ Port_TimeOutCloseMux(p_port->rfc.p_mcb);
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+ }
+ RFCOMM_TRACE_WARNING("Port state opened Event ignored %d", event);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_sm_disc_wait_ua
+ *
+ * Description This function handles events when DISC on the DLC was
+ * sent and SM is waiting for UA or DM.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_sm_disc_wait_ua(tPORT* p_port, uint16_t event, void* p_data) {
+ switch (event) {
+ case RFC_EVENT_OPEN:
+ case RFC_EVENT_ESTABLISH_RSP:
+ RFCOMM_TRACE_ERROR("Port error state %d event %d", p_port->rfc.state,
+ event);
+ return;
+
+ case RFC_EVENT_CLEAR:
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_DATA:
+ osi_free(p_data);
+ return;
+
+ case RFC_EVENT_UA:
+ p_port->rfc.p_mcb->is_disc_initiator = true;
+ /* Case falls through */
+
+ case RFC_EVENT_DM:
+ rfc_port_closed(p_port);
+ return;
+
+ case RFC_EVENT_SABME:
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, true);
+ return;
+
+ case RFC_EVENT_DISC:
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, true);
+ return;
+
+ case RFC_EVENT_UIH:
+ osi_free(p_data);
+ rfc_send_dm(p_port->rfc.p_mcb, p_port->dlci, false);
+ return;
+
+ case RFC_EVENT_TIMEOUT:
+ rfc_port_closed(p_port);
+ return;
+ }
+
+ RFCOMM_TRACE_WARNING("Port state disc_wait_ua Event ignored %d", event);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_uplink_data
+ *
+ * Description This function handles uplink information data frame.
+ *
+ ******************************************************************************/
+void rfc_port_uplink_data(tPORT* p_port, BT_HDR* p_buf) {
+ PORT_DataInd(p_port->rfc.p_mcb, p_port->dlci, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_pn
+ *
+ * Description This function handles DLC parameter negotiation frame.
+ * Record MTU and pass indication to the upper layer.
+ *
+ ******************************************************************************/
+void rfc_process_pn(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
+ tPORT* p_port;
+ uint8_t dlci = p_frame->dlci;
+
+ if (is_command) {
+ /* Ignore if Multiplexer is being shut down */
+ if (p_mcb->state != RFC_MX_STATE_DISC_WAIT_UA) {
+ PORT_ParNegInd(p_mcb, dlci, p_frame->u.pn.mtu, p_frame->u.pn.conv_layer,
+ p_frame->u.pn.k);
+ } else {
+ rfc_send_dm(p_mcb, dlci, false);
+ RFCOMM_TRACE_WARNING("***** MX PN while disconnecting *****");
+ }
+
+ return;
+ }
+ /* If we are not awaiting response just ignore it */
+ p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if ((p_port == NULL) || !(p_port->rfc.expected_rsp & RFC_RSP_PN)) return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_PN;
+
+ rfc_port_timer_stop(p_port);
+
+ PORT_ParNegCnf(p_mcb, dlci, p_frame->u.pn.mtu, p_frame->u.pn.conv_layer,
+ p_frame->u.pn.k);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_rpn
+ *
+ * Description This function handles Remote DLC parameter negotiation
+ * command/response. Pass command to the user.
+ *
+ ******************************************************************************/
+void rfc_process_rpn(tRFC_MCB* p_mcb, bool is_command, bool is_request,
+ MX_FRAME* p_frame) {
+ tPORT_STATE port_pars;
+ tPORT* p_port;
+
+ p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
+ if (p_port == NULL) {
+ /* This is the first command on the port */
+ if (is_command) {
+ memset(&port_pars, 0, sizeof(tPORT_STATE));
+ rfc_set_port_state(&port_pars, p_frame);
+
+ PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars,
+ p_frame->u.rpn.param_mask);
+ }
+ return;
+ }
+
+ if (is_command && is_request) {
+ /* This is the special situation when peer just request local pars */
+ port_pars = p_port->peer_port_pars;
+ rfc_send_rpn(p_mcb, p_frame->dlci, false, &p_port->peer_port_pars, 0);
+ return;
+ }
+
+ port_pars = p_port->peer_port_pars;
+
+ rfc_set_port_state(&port_pars, p_frame);
+
+ if (is_command) {
+ PORT_PortNegInd(p_mcb, p_frame->dlci, &port_pars,
+ p_frame->u.rpn.param_mask);
+ return;
+ }
+
+ /* If we are not awaiting response just ignore it */
+ p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
+ if ((p_port == NULL) ||
+ !(p_port->rfc.expected_rsp & (RFC_RSP_RPN | RFC_RSP_RPN_REPLY)))
+ return;
+
+ /* If we sent a request for port parameters to the peer he is replying with */
+ /* mask 0. */
+ rfc_port_timer_stop(p_port);
+
+ if (p_port->rfc.expected_rsp & RFC_RSP_RPN_REPLY) {
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RPN_REPLY;
+
+ p_port->peer_port_pars = port_pars;
+
+ if ((port_pars.fc_type ==
+ (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT)) ||
+ (port_pars.fc_type ==
+ (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT))) {
+ /* This is satisfactory port parameters. Set mask as it was Ok */
+ p_frame->u.rpn.param_mask = RFCOMM_RPN_PM_MASK;
+ } else {
+ /* Current peer parameters are not good, try to fix them */
+ p_port->peer_port_pars.fc_type =
+ (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT);
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+ rfc_send_rpn(p_mcb, p_frame->dlci, true, &p_port->peer_port_pars,
+ RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+ return;
+ }
+ } else
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RPN;
+
+ /* Check if all suggested parameters were accepted */
+ if (((p_frame->u.rpn.param_mask &
+ (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) ==
+ (RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT)) ||
+ ((p_frame->u.rpn.param_mask &
+ (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT)) ==
+ (RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT))) {
+ PORT_PortNegCnf(p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+ return;
+ }
+
+ /* If we were proposing RTR flow control try RTC flow control */
+ /* If we were proposing RTC flow control try no flow control */
+ /* otherwise drop the connection */
+ if (p_port->peer_port_pars.fc_type ==
+ (RFCOMM_FC_RTR_ON_INPUT | RFCOMM_FC_RTR_ON_OUTPUT)) {
+ /* Current peer parameters are not good, try to fix them */
+ p_port->peer_port_pars.fc_type =
+ (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT);
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+ rfc_send_rpn(p_mcb, p_frame->dlci, true, &p_port->peer_port_pars,
+ RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+ return;
+ }
+
+ /* Other side does not support flow control */
+ if (p_port->peer_port_pars.fc_type ==
+ (RFCOMM_FC_RTC_ON_INPUT | RFCOMM_FC_RTC_ON_OUTPUT)) {
+ p_port->peer_port_pars.fc_type = RFCOMM_FC_OFF;
+ PORT_PortNegCnf(p_mcb, p_port->dlci, &port_pars, RFCOMM_SUCCESS);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_msc
+ *
+ * Description This function handles Modem Status Command.
+ * Pass command to the user.
+ *
+ ******************************************************************************/
+void rfc_process_msc(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
+ tPORT_CTRL pars;
+ tPORT* p_port;
+ uint8_t modem_signals = p_frame->u.msc.signals;
+ bool new_peer_fc = false;
+
+ p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
+ if (p_port == NULL) return;
+
+ pars.modem_signal = 0;
+
+ if (modem_signals & RFCOMM_MSC_RTC) pars.modem_signal |= MODEM_SIGNAL_DTRDSR;
+
+ if (modem_signals & RFCOMM_MSC_RTR) pars.modem_signal |= MODEM_SIGNAL_RTSCTS;
+
+ if (modem_signals & RFCOMM_MSC_IC) pars.modem_signal |= MODEM_SIGNAL_RI;
+
+ if (modem_signals & RFCOMM_MSC_DV) pars.modem_signal |= MODEM_SIGNAL_DCD;
+
+ pars.fc = ((modem_signals & RFCOMM_MSC_FC) == RFCOMM_MSC_FC);
+
+ pars.break_signal =
+ (p_frame->u.msc.break_present) ? p_frame->u.msc.break_duration : 0;
+ pars.discard_buffers = 0;
+ pars.break_signal_seq = RFCOMM_CTRL_BREAK_IN_SEQ; /* this is default */
+
+ /* Check if this command is passed only to indicate flow control */
+ if (is_command) {
+ rfc_send_msc(p_mcb, p_frame->dlci, false, &pars);
+
+ if (p_port->rfc.p_mcb->flow != PORT_FC_CREDIT) {
+ /* Spec 1.1 indicates that only FC bit is used for flow control */
+ p_port->peer_ctrl.fc = new_peer_fc = pars.fc;
+
+ if (new_peer_fc != p_port->tx.peer_fc)
+ PORT_FlowInd(p_mcb, p_frame->dlci, (bool)!new_peer_fc);
+ }
+
+ PORT_ControlInd(p_mcb, p_frame->dlci, &pars);
+
+ return;
+ }
+
+ /* If we are not awaiting response just ignore it */
+ if (!(p_port->rfc.expected_rsp & RFC_RSP_MSC)) return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_MSC;
+
+ rfc_port_timer_stop(p_port);
+
+ PORT_ControlCnf(p_port->rfc.p_mcb, p_port->dlci, &pars);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_rls
+ *
+ * Description This function handles Remote Line Status command.
+ * Pass command to the user.
+ *
+ ******************************************************************************/
+void rfc_process_rls(tRFC_MCB* p_mcb, bool is_command, MX_FRAME* p_frame) {
+ tPORT* p_port;
+
+ if (is_command) {
+ PORT_LineStatusInd(p_mcb, p_frame->dlci, p_frame->u.rls.line_status);
+ rfc_send_rls(p_mcb, p_frame->dlci, false, p_frame->u.rls.line_status);
+ } else {
+ p_port = port_find_mcb_dlci_port(p_mcb, p_frame->dlci);
+
+ /* If we are not awaiting response just ignore it */
+ if (!p_port || !(p_port->rfc.expected_rsp & RFC_RSP_RLS)) return;
+
+ p_port->rfc.expected_rsp &= ~RFC_RSP_RLS;
+
+ rfc_port_timer_stop(p_port);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_nsc
+ *
+ * Description This function handles None Supported Command frame.
+ *
+ ******************************************************************************/
+void rfc_process_nsc(UNUSED_ATTR tRFC_MCB* p_mcb,
+ UNUSED_ATTR MX_FRAME* p_frame) {}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_test
+ *
+ * Description This function handles Test frame. If this is a command
+ * reply to it. Otherwise pass response to the user.
+ *
+ ******************************************************************************/
+void rfc_process_test_rsp(UNUSED_ATTR tRFC_MCB* p_mcb, BT_HDR* p_buf) {
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_fcon
+ *
+ * Description This function handles FCON frame. The peer entity is able
+ * to receive new information
+ *
+ ******************************************************************************/
+void rfc_process_fcon(tRFC_MCB* p_mcb, bool is_command) {
+ if (is_command) {
+ rfc_cb.rfc.peer_rx_disabled = false;
+
+ rfc_send_fcon(p_mcb, false);
+
+ if (!p_mcb->l2cap_congested) PORT_FlowInd(p_mcb, 0, true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_fcoff
+ *
+ * Description This function handles FCOFF frame. The peer entity is
+ * unable to receive new information
+ *
+ ******************************************************************************/
+void rfc_process_fcoff(tRFC_MCB* p_mcb, bool is_command) {
+ if (is_command) {
+ rfc_cb.rfc.peer_rx_disabled = true;
+
+ if (!p_mcb->l2cap_congested) PORT_FlowInd(p_mcb, 0, false);
+
+ rfc_send_fcoff(p_mcb, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_l2cap_congestion
+ *
+ * Description This function handles L2CAP congestion messages
+ *
+ ******************************************************************************/
+void rfc_process_l2cap_congestion(tRFC_MCB* p_mcb, bool is_congested) {
+ p_mcb->l2cap_congested = is_congested;
+
+ if (!is_congested) {
+ rfc_check_send_cmd(p_mcb, NULL);
+ }
+
+ if (!rfc_cb.rfc.peer_rx_disabled) {
+ if (!is_congested)
+ PORT_FlowInd(p_mcb, 0, true);
+ else
+ PORT_FlowInd(p_mcb, 0, false);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_set_port_pars
+ *
+ * Description This function sets the tPORT_STATE structure given a
+ * p_frame.
+ *
+ ******************************************************************************/
+
+void rfc_set_port_state(tPORT_STATE* port_pars, MX_FRAME* p_frame) {
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_BIT_RATE)
+ port_pars->baud_rate = p_frame->u.rpn.baud_rate;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_DATA_BITS)
+ port_pars->byte_size = p_frame->u.rpn.byte_size;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_STOP_BITS)
+ port_pars->stop_bits = p_frame->u.rpn.stop_bits;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY)
+ port_pars->parity = p_frame->u.rpn.parity;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_PARITY_TYPE)
+ port_pars->parity_type = p_frame->u.rpn.parity_type;
+ if (p_frame->u.rpn.param_mask &
+ (RFCOMM_RPN_PM_XONXOFF_ON_INPUT | RFCOMM_RPN_PM_XONXOFF_ON_OUTPUT |
+ RFCOMM_RPN_PM_RTR_ON_INPUT | RFCOMM_RPN_PM_RTR_ON_OUTPUT |
+ RFCOMM_RPN_PM_RTC_ON_INPUT | RFCOMM_RPN_PM_RTC_ON_OUTPUT))
+ port_pars->fc_type = p_frame->u.rpn.fc_type;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XON_CHAR)
+ port_pars->xon_char = p_frame->u.rpn.xon_char;
+ if (p_frame->u.rpn.param_mask & RFCOMM_RPN_PM_XOFF_CHAR)
+ port_pars->xoff_char = p_frame->u.rpn.xoff_char;
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_port_if.cc b/mtkbt/code/bt/stack/rfcomm/rfc_port_if.cc
new file mode 100755
index 0000000..4f8f38a
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_port_if.cc
@@ -0,0 +1,332 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains functions callable by an application
+ * running on top of RFCOMM
+ *
+ *****************************************************************************/
+
+#include <string.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "l2c_api.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+tRFC_CB rfc_cb;
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_StartReq
+ *
+ * Description This function handles Start Request from the upper layer.
+ * If RFCOMM multiplexer channel can not be allocated
+ * send start not accepted confirmation. Otherwise dispatch
+ * start event to the state machine.
+ *
+ ******************************************************************************/
+void RFCOMM_StartReq(tRFC_MCB* p_mcb) {
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_StartRsp
+ *
+ * Description This function handles Start Response from the upper layer.
+ * Save upper layer handle and result of the Start Indication
+ * in the control block and dispatch event to the FSM.
+ *
+ ******************************************************************************/
+void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result) {
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_RSP, &result);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_DlcEstablishReq
+ *
+ * Description This function is called by the user app to establish
+ * connection with the specific dlci on a specific bd device.
+ * It will allocate RFCOMM connection control block if not
+ * allocated before and dispatch open event to the state
+ * machine.
+ *
+ ******************************************************************************/
+void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci,
+ UNUSED_ATTR uint16_t mtu) {
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
+ PORT_DlcEstablishCnf(p_mcb, dlci, 0, RFCOMM_ERROR);
+ return;
+ }
+
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_DlcEstablishRsp
+ *
+ * Description This function is called by the port emulation entity
+ * acks Establish Indication.
+ *
+ ******************************************************************************/
+void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci,
+ UNUSED_ATTR uint16_t mtu, uint16_t result) {
+ if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) {
+ PORT_DlcReleaseInd(p_mcb, dlci);
+ return;
+ }
+
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+ rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ParNegReq
+ *
+ * Description This function is called by the user app to start
+ * DLC parameter negotiation. Port emulation can send this
+ * request before actually establishing the DLC. In this
+ * case the function will allocate RFCOMM connection control
+ * block.
+ *
+ ******************************************************************************/
+void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
+ uint8_t flow;
+ uint8_t cl;
+ uint8_t k;
+
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
+ p_port->error = PORT_PAR_NEG_FAILED;
+ return;
+ }
+
+ /* Negotiate the flow control mechanism. If flow control mechanism for */
+ /* mux has not been set yet, use our default value. If it has been set, */
+ /* use that value. */
+ flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
+
+ /* Set convergence layer and number of credits (k) */
+ if (flow == PORT_FC_CREDIT) {
+ cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
+ k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
+ : RFCOMM_K_MAX;
+ p_port->credit_rx = k;
+ } else {
+ cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
+ k = 0;
+ }
+
+ /* Send Parameter Negotiation Command UIH frame */
+ p_port->rfc.expected_rsp |= RFC_RSP_PN;
+
+ rfc_send_pn(p_mcb, dlci, true, mtu, cl, k);
+
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ParNegRsp
+ *
+ * Description This function is called by the user app to acknowledge
+ * DLC parameter negotiation.
+ *
+ ******************************************************************************/
+void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
+ uint8_t k) {
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
+
+ /* Send Parameter Negotiation Response UIH frame */
+ rfc_send_pn(p_mcb, dlci, false, mtu, cl, k);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_PortNegReq
+ *
+ * Description This function is called by the user app to start
+ * Remote Port parameter negotiation. Port emulation can
+ * send this request before actually establishing the DLC.
+ * In this case the function will allocate RFCOMM connection
+ * control block.
+ *
+ ******************************************************************************/
+void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
+ PORT_PortNegCnf(p_mcb, dlci, NULL, RFCOMM_ERROR);
+ return;
+ }
+
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ /* Send Parameter Negotiation Command UIH frame */
+ if (!p_pars)
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
+ else
+ p_port->rfc.expected_rsp |= RFC_RSP_RPN;
+
+ rfc_send_rpn(p_mcb, dlci, true, p_pars, RFCOMM_RPN_PM_MASK);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_PortNegRsp
+ *
+ * Description This function is called by the user app to acknowledge
+ * Port parameters negotiation.
+ *
+ ******************************************************************************/
+void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
+ uint16_t param_mask) {
+ if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
+
+ rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_ControlReq
+ *
+ * Description This function is called by the port entity to send control
+ * parameters to remote port emulation entity.
+ *
+ ******************************************************************************/
+void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_OPENED) ||
+ (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+ rfc_send_msc(p_mcb, dlci, true, p_pars);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_FlowReq
+ *
+ * Description This function is called by the port entity when flow
+ * control state has changed. Enable flag passed shows if
+ * port can accept more data.
+ *
+ ******************************************************************************/
+void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t enable) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_OPENED) ||
+ (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->local_ctrl.fc = !enable;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_MSC;
+
+ rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_LineStatusReq
+ *
+ * Description This function is called by the port entity when line
+ * status should be delivered to the peer.
+ *
+ ******************************************************************************/
+void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == NULL) {
+ RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
+ return;
+ }
+
+ if ((p_port->state != PORT_STATE_OPENED) ||
+ (p_port->rfc.state != RFC_STATE_OPENED))
+ return;
+
+ p_port->rfc.expected_rsp |= RFC_RSP_RLS;
+
+ rfc_send_rls(p_mcb, dlci, true, status);
+ rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_DlcReleaseReq
+ *
+ * Description This function is called by the PORT unit to close DLC
+ *
+ ******************************************************************************/
+void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
+ rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE, 0);
+}
+
+/*******************************************************************************
+ *
+ * Function RFCOMM_DataReq
+ *
+ * Description This function is called by the user app to send data buffer
+ *
+ ******************************************************************************/
+void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
+ rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA,
+ p_buf);
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_ts_frames.cc b/mtkbt/code/bt/stack/rfcomm/rfc_ts_frames.cc
new file mode 100755
index 0000000..aa4138f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_ts_frames.cc
@@ -0,0 +1,805 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions to send TS 07.10 frames
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "bt_common.h"
+#include "bt_target.h"
+#include "l2c_api.h"
+#include "port_api.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+/*******************************************************************************
+ *
+ * Function rfc_send_sabme
+ *
+ * Description This function sends SABME frame.
+ *
+ ******************************************************************************/
+void rfc_send_sabme(tRFC_MCB* p_mcb, uint8_t dlci) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* SABME frame, command, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_SABME | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data =
+ RFCOMM_SABME_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_ua
+ *
+ * Description This function sends UA frame.
+ *
+ ******************************************************************************/
+void rfc_send_ua(tRFC_MCB* p_mcb, uint8_t dlci) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* ua frame, response, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UA | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_UA_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_dm
+ *
+ * Description This function sends DM frame.
+ *
+ ******************************************************************************/
+void rfc_send_dm(tRFC_MCB* p_mcb, uint8_t dlci, bool pf) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* DM frame, response, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0);
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_DM_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_disc
+ *
+ * Description This function sends DISC frame.
+ *
+ ******************************************************************************/
+void rfc_send_disc(tRFC_MCB* p_mcb, uint8_t dlci) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* DISC frame, command, PF = 1, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_DISC | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+
+ *p_data = RFCOMM_DISC_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);
+
+ p_buf->len = 4;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_buf_uih
+ *
+ * Description This function sends UIH frame.
+ *
+ ******************************************************************************/
+void rfc_send_buf_uih(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+ uint8_t credits;
+
+ p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
+ if (p_buf->len > 127) p_buf->offset--;
+
+ if (dlci)
+ credits = (uint8_t)p_buf->layer_specific;
+ else
+ credits = 0;
+
+ if (credits) p_buf->offset--;
+
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ /* UIH frame, command, PF = 0, dlci */
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0);
+ if (p_buf->len <= 127) {
+ *p_data++ = RFCOMM_EA | (p_buf->len << 1);
+ p_buf->len += 3;
+ } else {
+ *p_data++ = (p_buf->len & 0x7f) << 1;
+ *p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2;
+ p_buf->len += 4;
+ }
+
+ if (credits) {
+ *p_data++ = credits;
+ p_buf->len++;
+ }
+
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len++;
+
+ *p_data = RFCOMM_UIH_FCS((uint8_t*)(p_buf + 1) + p_buf->offset, dlci);
+
+ if (dlci == RFCOMM_MX_DLCI) {
+ rfc_check_send_cmd(p_mcb, p_buf);
+ } else {
+ L2CA_DataWrite(p_mcb->lcid, p_buf);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_pn
+ *
+ * Description This function sends DLC Parameters Negotiation Frame.
+ *
+ ******************************************************************************/
+void rfc_send_pn(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command, uint16_t mtu,
+ uint8_t cl, uint8_t k) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1);
+
+ *p_data++ = dlci;
+ *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl;
+
+ /* It appeared that we need to reply with the same priority bits as we
+ *received.
+ ** We will use the fact that we reply in the same context so rx_frame can
+ *still be used.
+ */
+ if (is_command)
+ *p_data++ = RFCOMM_PN_PRIORITY_0;
+ else
+ *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;
+
+ *p_data++ = RFCOMM_T1_DSEC;
+ *p_data++ = mtu & 0xFF;
+ *p_data++ = mtu >> 8;
+ *p_data++ = RFCOMM_N2;
+ *p_data = k;
+
+ /* Total length is sizeof PN data + mx header 2 */
+ p_buf->len = RFCOMM_MX_PN_LEN + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_fcon
+ *
+ * Description This function sends Flow Control On Command.
+ *
+ ******************************************************************************/
+void rfc_send_fcon(tRFC_MCB* p_mcb, bool is_command) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCON;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCON_LEN << 1);
+
+ /* Total length is sizeof FCON data + mx header 2 */
+ p_buf->len = RFCOMM_MX_FCON_LEN + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_fcoff
+ *
+ * Description This function sends Flow Control Off Command.
+ *
+ ******************************************************************************/
+void rfc_send_fcoff(tRFC_MCB* p_mcb, bool is_command) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1);
+
+ /* Total length is sizeof FCOFF data + mx header 2 */
+ p_buf->len = RFCOMM_MX_FCOFF_LEN + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_msc
+ *
+ * Description This function sends Modem Status Command Frame.
+ *
+ ******************************************************************************/
+void rfc_send_msc(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ tPORT_CTRL* p_pars) {
+ uint8_t* p_data;
+ uint8_t signals;
+ uint8_t break_duration;
+ uint8_t len;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ signals = p_pars->modem_signal;
+ break_duration = p_pars->break_signal;
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ if (break_duration)
+ len = RFCOMM_MX_MSC_LEN_WITH_BREAK;
+ else
+ len = RFCOMM_MX_MSC_LEN_NO_BREAK;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC;
+ *p_data++ = RFCOMM_EA | (len << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_EA | ((p_pars->fc) ? RFCOMM_MSC_FC : 0) |
+ ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) |
+ ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) |
+ ((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) |
+ ((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0);
+
+ if (break_duration) {
+ *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK |
+ (break_duration << RFCOMM_MSC_SHIFT_BREAK);
+ }
+
+ /* Total length is sizeof MSC data + mx header 2 */
+ p_buf->len = len + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_rls
+ *
+ * Description This function sends Remote Line Status Command Frame.
+ *
+ ******************************************************************************/
+void rfc_send_rls(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ uint8_t status) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_RLS_ERROR | status;
+
+ /* Total length is sizeof RLS data + mx header 2 */
+ p_buf->len = RFCOMM_MX_RLS_LEN + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_nsc
+ *
+ * Description This function sends Non Supported Command Response.
+ *
+ ******************************************************************************/
+void rfc_send_nsc(tRFC_MCB* p_mcb) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(false) | RFCOMM_MX_NSC;
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1);
+
+ *p_data++ = rfc_cb.rfc.rx_frame.ea |
+ (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) |
+ rfc_cb.rfc.rx_frame.type;
+
+ /* Total length is sizeof NSC data + mx header 2 */
+ p_buf->len = RFCOMM_MX_NSC_LEN + 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_rpn
+ *
+ * Description This function sends Remote Port Negotiation Command
+ *
+ ******************************************************************************/
+void rfc_send_rpn(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
+ tPORT_STATE* p_pars, uint16_t mask) {
+ uint8_t* p_data;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RPN;
+
+ if (!p_pars) {
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_REQ_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+
+ p_buf->len = RFCOMM_MX_RPN_REQ_LEN + 2;
+ } else {
+ *p_data++ = RFCOMM_EA | (RFCOMM_MX_RPN_LEN << 1);
+
+ *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = p_pars->baud_rate;
+ *p_data++ = (p_pars->byte_size << RFCOMM_RPN_BITS_SHIFT) |
+ (p_pars->stop_bits << RFCOMM_RPN_STOP_BITS_SHIFT) |
+ (p_pars->parity << RFCOMM_RPN_PARITY_SHIFT) |
+ (p_pars->parity_type << RFCOMM_RPN_PARITY_TYPE_SHIFT);
+ *p_data++ = p_pars->fc_type;
+ *p_data++ = p_pars->xon_char;
+ *p_data++ = p_pars->xoff_char;
+ *p_data++ = (mask & 0xFF);
+ *p_data++ = (mask >> 8);
+
+ /* Total length is sizeof RPN data + mx header 2 */
+ p_buf->len = RFCOMM_MX_RPN_LEN + 2;
+ }
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_test
+ *
+ * Description This function sends Test frame.
+ *
+ ******************************************************************************/
+void rfc_send_test(tRFC_MCB* p_mcb, bool is_command, BT_HDR* p_buf) {
+ /* Shift buffer to give space for header */
+ if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) {
+ uint8_t* p_src = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len - 1;
+ BT_HDR* p_new_buf =
+ (BT_HDR*)osi_malloc(p_buf->len + (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET +
+ 2 + sizeof(BT_HDR) + 1));
+
+ p_new_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
+ p_new_buf->len = p_buf->len;
+
+ uint8_t* p_dest =
+ (uint8_t*)(p_new_buf + 1) + p_new_buf->offset + p_new_buf->len - 1;
+
+ for (uint16_t xx = 0; xx < p_buf->len; xx++) *p_dest-- = *p_src--;
+
+ osi_free(p_buf);
+ p_buf = p_new_buf;
+ }
+
+ /* Adjust offset by number of bytes we are going to fill */
+ p_buf->offset -= 2;
+ uint8_t* p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST;
+ *p_data++ = RFCOMM_EA | (p_buf->len << 1);
+
+ p_buf->len += 2;
+
+ rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_send_credit
+ *
+ * Description This function sends a flow control credit in UIH frame.
+ *
+ ******************************************************************************/
+void rfc_send_credit(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t credit) {
+ uint8_t* p_data;
+ uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+ *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
+ *p_data++ = RFCOMM_UIH | RFCOMM_PF;
+ *p_data++ = RFCOMM_EA | 0;
+ *p_data++ = credit;
+ *p_data = RFCOMM_UIH_FCS((uint8_t*)(p_buf + 1) + p_buf->offset, dlci);
+
+ p_buf->len = 5;
+
+ rfc_check_send_cmd(p_mcb, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_parse_data
+ *
+ * Description This function processes data packet received from L2CAP
+ *
+ ******************************************************************************/
+uint8_t rfc_parse_data(tRFC_MCB* p_mcb, MX_FRAME* p_frame, BT_HDR* p_buf) {
+ uint8_t ead, eal, fcs;
+ uint8_t* p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint8_t* p_start = p_data;
+ uint16_t len;
+
+ if (p_buf->len < RFCOMM_CTRL_FRAME_LEN) {
+ RFCOMM_TRACE_ERROR("Bad Length1: %d", p_buf->len);
+ return (RFC_EVENT_BAD_FRAME);
+ }
+
+ RFCOMM_PARSE_CTRL_FIELD(ead, p_frame->cr, p_frame->dlci, p_data);
+ if (!ead) {
+ RFCOMM_TRACE_ERROR("Bad Address(EA must be 1)");
+ return (RFC_EVENT_BAD_FRAME);
+ }
+ RFCOMM_PARSE_TYPE_FIELD(p_frame->type, p_frame->pf, p_data);
+ RFCOMM_PARSE_LEN_FIELD(eal, len, p_data);
+
+ p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */
+ p_buf->offset += (3 + !ead + !eal);
+
+ /* handle credit if credit based flow control */
+ if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) &&
+ (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) {
+ p_frame->credit = *p_data++;
+ p_buf->len--;
+ p_buf->offset++;
+ } else
+ p_frame->credit = 0;
+
+ if (p_buf->len != len) {
+ RFCOMM_TRACE_ERROR("Bad Length2 %d %d", p_buf->len, len);
+ return (RFC_EVENT_BAD_FRAME);
+ }
+
+ fcs = *(p_data + len);
+
+ /* All control frames that we are sending are sent with P=1, expect */
+ /* reply with F=1 */
+ /* According to TS 07.10 spec ivalid frames are discarded without */
+ /* notification to the sender */
+ switch (p_frame->type) {
+ case RFCOMM_SABME:
+ if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) ||
+ !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) ||
+ !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
+ RFCOMM_TRACE_ERROR("Bad SABME");
+ return (RFC_EVENT_BAD_FRAME);
+ } else
+ return (RFC_EVENT_SABME);
+
+ case RFCOMM_UA:
+ if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) ||
+ !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) ||
+ !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
+ RFCOMM_TRACE_ERROR("Bad UA");
+ return (RFC_EVENT_BAD_FRAME);
+ } else
+ return (RFC_EVENT_UA);
+
+ case RFCOMM_DM:
+ if (RFCOMM_FRAME_IS_CMD(p_mcb->is_initiator, p_frame->cr) || len ||
+ !RFCOMM_VALID_DLCI(p_frame->dlci) ||
+ !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
+ RFCOMM_TRACE_ERROR("Bad DM");
+ return (RFC_EVENT_BAD_FRAME);
+ } else
+ return (RFC_EVENT_DM);
+
+ case RFCOMM_DISC:
+ if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr) ||
+ !p_frame->pf || len || !RFCOMM_VALID_DLCI(p_frame->dlci) ||
+ !rfc_check_fcs(RFCOMM_CTRL_FRAME_LEN, p_start, fcs)) {
+ RFCOMM_TRACE_ERROR("Bad DISC");
+ return (RFC_EVENT_BAD_FRAME);
+ } else
+ return (RFC_EVENT_DISC);
+
+ case RFCOMM_UIH:
+ if (!RFCOMM_VALID_DLCI(p_frame->dlci)) {
+ RFCOMM_TRACE_ERROR("Bad UIH - invalid DLCI");
+ return (RFC_EVENT_BAD_FRAME);
+ } else if (!rfc_check_fcs(2, p_start, fcs)) {
+ RFCOMM_TRACE_ERROR("Bad UIH - FCS");
+ return (RFC_EVENT_BAD_FRAME);
+ } else if (RFCOMM_FRAME_IS_RSP(p_mcb->is_initiator, p_frame->cr)) {
+ /* we assume that this is ok to allow bad implementations to work */
+ RFCOMM_TRACE_ERROR("Bad UIH - response");
+ return (RFC_EVENT_UIH);
+ } else
+ return (RFC_EVENT_UIH);
+ }
+
+ return (RFC_EVENT_BAD_FRAME);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_process_mx_message
+ *
+ * Description This function processes UIH frames received on the
+ * multiplexer control channel.
+ *
+ ******************************************************************************/
+void rfc_process_mx_message(tRFC_MCB* p_mcb, BT_HDR* p_buf) {
+ uint8_t* p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ MX_FRAME* p_rx_frame = &rfc_cb.rfc.rx_frame;
+ uint16_t length = p_buf->len;
+ uint8_t ea, cr, mx_len;
+ bool is_command;
+
+ p_rx_frame->ea = *p_data & RFCOMM_EA;
+ p_rx_frame->cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->type = *p_data++ & ~(RFCOMM_CR_MASK | RFCOMM_EA_MASK);
+
+ if (!p_rx_frame->ea || !length) {
+ RFCOMM_TRACE_ERROR("Illegal MX Frame ea:%d len:%d", p_rx_frame->ea, length);
+ osi_free(p_buf);
+ return;
+ }
+
+ length--;
+
+ is_command = p_rx_frame->cr;
+
+ ea = *p_data & RFCOMM_EA;
+
+ mx_len = *p_data++ >> RFCOMM_SHIFT_LENGTH1;
+ length--;
+
+ if (!ea) {
+ mx_len += *p_data++ << RFCOMM_SHIFT_LENGTH2;
+ length--;
+ }
+
+ if (mx_len != length) {
+ RFCOMM_TRACE_ERROR("Bad MX frame");
+ osi_free(p_buf);
+ return;
+ }
+
+ switch (p_rx_frame->type) {
+ case RFCOMM_MX_PN:
+ if (length != RFCOMM_MX_PN_LEN) break;
+
+ p_rx_frame->dlci = *p_data++ & RFCOMM_PN_DLCI_MASK;
+ p_rx_frame->u.pn.frame_type = *p_data & RFCOMM_PN_FRAME_TYPE_MASK;
+ p_rx_frame->u.pn.conv_layer = *p_data++ & RFCOMM_PN_CONV_LAYER_MASK;
+ p_rx_frame->u.pn.priority = *p_data++ & RFCOMM_PN_PRIORITY_MASK;
+ p_rx_frame->u.pn.t1 = *p_data++;
+ p_rx_frame->u.pn.mtu = *p_data + (*(p_data + 1) << 8);
+ p_data += 2;
+ p_rx_frame->u.pn.n2 = *p_data++;
+ p_rx_frame->u.pn.k = *p_data++ & RFCOMM_PN_K_MASK;
+
+ if (!p_rx_frame->dlci || !RFCOMM_VALID_DLCI(p_rx_frame->dlci) ||
+ (p_rx_frame->u.pn.mtu < RFCOMM_MIN_MTU) ||
+ (p_rx_frame->u.pn.mtu > RFCOMM_MAX_MTU)) {
+ RFCOMM_TRACE_ERROR("Bad PN frame");
+ break;
+ }
+
+ osi_free(p_buf);
+
+ rfc_process_pn(p_mcb, is_command, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_TEST:
+ if (!length) break;
+
+ p_rx_frame->u.test.p_data = p_data;
+ p_rx_frame->u.test.data_len = length;
+
+ p_buf->offset += 2;
+ p_buf->len -= 2;
+
+ if (is_command)
+ rfc_send_test(p_mcb, false, p_buf);
+ else
+ rfc_process_test_rsp(p_mcb, p_buf);
+ return;
+
+ case RFCOMM_MX_FCON:
+ if (length != RFCOMM_MX_FCON_LEN) break;
+
+ osi_free(p_buf);
+
+ rfc_process_fcon(p_mcb, is_command);
+ return;
+
+ case RFCOMM_MX_FCOFF:
+ if (length != RFCOMM_MX_FCOFF_LEN) break;
+
+ osi_free(p_buf);
+
+ rfc_process_fcoff(p_mcb, is_command);
+ return;
+
+ case RFCOMM_MX_MSC:
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ if (!ea || !cr || !p_rx_frame->dlci ||
+ !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) {
+ RFCOMM_TRACE_ERROR("Bad MSC frame");
+ break;
+ }
+
+ p_rx_frame->u.msc.signals = *p_data++;
+
+ if (mx_len == RFCOMM_MX_MSC_LEN_WITH_BREAK) {
+ p_rx_frame->u.msc.break_present =
+ *p_data & RFCOMM_MSC_BREAK_PRESENT_MASK;
+ p_rx_frame->u.msc.break_duration =
+ (*p_data & RFCOMM_MSC_BREAK_MASK) >> RFCOMM_MSC_SHIFT_BREAK;
+ } else {
+ p_rx_frame->u.msc.break_present = false;
+ p_rx_frame->u.msc.break_duration = 0;
+ }
+ osi_free(p_buf);
+
+ rfc_process_msc(p_mcb, is_command, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_NSC:
+ if ((length != RFCOMM_MX_NSC_LEN) || !is_command) break;
+
+ p_rx_frame->u.nsc.ea = *p_data & RFCOMM_EA;
+ p_rx_frame->u.nsc.cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->u.nsc.type = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ osi_free(p_buf);
+
+ rfc_process_nsc(p_mcb, p_rx_frame);
+ return;
+
+ case RFCOMM_MX_RPN:
+ if ((length != RFCOMM_MX_RPN_REQ_LEN) && (length != RFCOMM_MX_RPN_LEN))
+ break;
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+
+ if (!ea || !cr || !p_rx_frame->dlci ||
+ !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) {
+ RFCOMM_TRACE_ERROR("Bad RPN frame");
+ break;
+ }
+
+ p_rx_frame->u.rpn.is_request = (length == RFCOMM_MX_RPN_REQ_LEN);
+
+ if (!p_rx_frame->u.rpn.is_request) {
+ p_rx_frame->u.rpn.baud_rate = *p_data++;
+ p_rx_frame->u.rpn.byte_size =
+ (*p_data >> RFCOMM_RPN_BITS_SHIFT) & RFCOMM_RPN_BITS_MASK;
+ p_rx_frame->u.rpn.stop_bits =
+ (*p_data >> RFCOMM_RPN_STOP_BITS_SHIFT) & RFCOMM_RPN_STOP_BITS_MASK;
+ p_rx_frame->u.rpn.parity =
+ (*p_data >> RFCOMM_RPN_PARITY_SHIFT) & RFCOMM_RPN_PARITY_MASK;
+ p_rx_frame->u.rpn.parity_type =
+ (*p_data++ >> RFCOMM_RPN_PARITY_TYPE_SHIFT) &
+ RFCOMM_RPN_PARITY_TYPE_MASK;
+
+ p_rx_frame->u.rpn.fc_type = *p_data++ & RFCOMM_FC_MASK;
+ p_rx_frame->u.rpn.xon_char = *p_data++;
+ p_rx_frame->u.rpn.xoff_char = *p_data++;
+ p_rx_frame->u.rpn.param_mask =
+ (*p_data + (*(p_data + 1) << 8)) & RFCOMM_RPN_PM_MASK;
+ }
+ osi_free(p_buf);
+
+ rfc_process_rpn(p_mcb, is_command, p_rx_frame->u.rpn.is_request,
+ p_rx_frame);
+ return;
+
+ case RFCOMM_MX_RLS:
+ if (length != RFCOMM_MX_RLS_LEN) break;
+
+ ea = *p_data & RFCOMM_EA;
+ cr = (*p_data & RFCOMM_CR_MASK) >> RFCOMM_SHIFT_CR;
+
+ p_rx_frame->dlci = *p_data++ >> RFCOMM_SHIFT_DLCI;
+ p_rx_frame->u.rls.line_status = (*p_data & ~0x01);
+
+ if (!ea || !cr || !p_rx_frame->dlci ||
+ !RFCOMM_VALID_DLCI(p_rx_frame->dlci)) {
+ RFCOMM_TRACE_ERROR("Bad RPN frame");
+ break;
+ }
+
+ osi_free(p_buf);
+
+ rfc_process_rls(p_mcb, is_command, p_rx_frame);
+ return;
+ }
+
+ osi_free(p_buf);
+
+ if (is_command) rfc_send_nsc(p_mcb);
+}
diff --git a/mtkbt/code/bt/stack/rfcomm/rfc_utils.cc b/mtkbt/code/bt/stack/rfcomm/rfc_utils.cc
new file mode 100755
index 0000000..bad58f3
--- a/dev/null
+++ b/mtkbt/code/bt/stack/rfcomm/rfc_utils.cc
@@ -0,0 +1,445 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * This file contains collection of utility functions used the RFCOMM unit
+ *
+ *****************************************************************************/
+
+#include "bt_common.h"
+#include "bt_target.h"
+
+#include "bt_utils.h"
+#include "btm_api.h"
+#include "btm_int.h"
+#include "btu.h"
+#include "osi/include/osi.h"
+#include "port_api.h"
+#include "port_ext.h"
+#include "port_int.h"
+#include "rfc_int.h"
+#include "rfcdefs.h"
+
+#include <string.h>
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function rfc_calc_fcs
+ *
+ * Description Reversed CRC Table , 8-bit, poly=0x07
+ * (GSM 07.10 TS 101 369 V6.3.0)
+ ******************************************************************************/
+static const uint8_t rfc_crctable[] = {
+ 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED,
+ 0x7C, 0x09, 0x98, 0xEA, 0x7B, 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A,
+ 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 0x38,
+ 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44,
+ 0x31, 0xA0, 0xD2, 0x43, 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0,
+ 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+
+ 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D,
+ 0x0C, 0x79, 0xE8, 0x9A, 0x0B, 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA,
+ 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 0x48,
+ 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34,
+ 0x41, 0xD0, 0xA2, 0x33, 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0,
+ 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+
+ 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D,
+ 0x9C, 0xE9, 0x78, 0x0A, 0x9B, 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A,
+ 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 0xD8,
+ 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4,
+ 0xD1, 0x40, 0x32, 0xA3, 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20,
+ 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+
+ 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D,
+ 0xEC, 0x99, 0x08, 0x7A, 0xEB, 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A,
+ 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7, 0xA8,
+ 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4,
+ 0xA1, 0x30, 0x42, 0xD3, 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50,
+ 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF};
+
+/*******************************************************************************
+ *
+ * Function rfc_calc_fcs
+ *
+ * Description This function calculate FCS for the RFCOMM frame
+ * (GSM 07.10 TS 101 369 V6.3.0)
+ *
+ * Input len - number of bytes in the message
+ * p - points to message
+ *
+ ******************************************************************************/
+uint8_t rfc_calc_fcs(uint16_t len, uint8_t* p) {
+ uint8_t fcs = 0xFF;
+
+ while (len--) {
+ fcs = rfc_crctable[fcs ^ *p++];
+ }
+
+ /* Ones compliment */
+ return (0xFF - fcs);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_check_fcs
+ *
+ * Description This function checks FCS for the RFCOMM frame
+ * (GSM 07.10 TS 101 369 V6.3.0)
+ *
+ * Input len - number of bytes in the message
+ * p - points to message
+ * received_fcs - received FCS
+ *
+ ******************************************************************************/
+bool rfc_check_fcs(uint16_t len, uint8_t* p, uint8_t received_fcs) {
+ uint8_t fcs = 0xFF;
+
+ while (len--) {
+ fcs = rfc_crctable[fcs ^ *p++];
+ }
+
+ /* Ones compliment */
+ fcs = rfc_crctable[fcs ^ received_fcs];
+
+ /*0xCF is the reversed order of 11110011.*/
+ return (fcs == 0xCF);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_alloc_multiplexer_channel
+ *
+ * Description This function returns existing or new control block for
+ * the BD_ADDR.
+ *
+ ******************************************************************************/
+tRFC_MCB* rfc_alloc_multiplexer_channel(BD_ADDR bd_addr, bool is_initiator) {
+ int i, j;
+ tRFC_MCB* p_mcb = NULL;
+ RFCOMM_TRACE_DEBUG(
+ "rfc_alloc_multiplexer_channel: bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
+ RFCOMM_TRACE_DEBUG("rfc_alloc_multiplexer_channel:is_initiator:%d",
+ is_initiator);
+
+ for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
+ RFCOMM_TRACE_DEBUG(
+ "rfc_alloc_multiplexer_channel rfc_cb.port.rfc_mcb[%d].state:%d", i,
+ rfc_cb.port.rfc_mcb[i].state);
+ RFCOMM_TRACE_DEBUG(
+ "(rfc_cb.port.rfc_mcb[i].bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
+ rfc_cb.port.rfc_mcb[i].bd_addr[0], rfc_cb.port.rfc_mcb[i].bd_addr[1],
+ rfc_cb.port.rfc_mcb[i].bd_addr[2], rfc_cb.port.rfc_mcb[i].bd_addr[3],
+ rfc_cb.port.rfc_mcb[i].bd_addr[4], rfc_cb.port.rfc_mcb[i].bd_addr[5]);
+
+ if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) &&
+ (!memcmp(rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN))) {
+ /* Multiplexer channel found do not change anything */
+ /* If there was an inactivity timer running stop it now */
+ if (rfc_cb.port.rfc_mcb[i].state == RFC_MX_STATE_CONNECTED)
+ rfc_timer_stop(&rfc_cb.port.rfc_mcb[i]);
+ RFCOMM_TRACE_DEBUG(
+ "rfc_alloc_multiplexer_channel:is_initiator:%d, found, state:%d, "
+ "p_mcb:%p",
+ is_initiator, rfc_cb.port.rfc_mcb[i].state, &rfc_cb.port.rfc_mcb[i]);
+ return (&rfc_cb.port.rfc_mcb[i]);
+ }
+ }
+
+ /* connection with bd_addr does not exist */
+ for (i = 0, j = rfc_cb.rfc.last_mux + 1; i < MAX_BD_CONNECTIONS; i++, j++) {
+ if (j >= MAX_BD_CONNECTIONS) j = 0;
+
+ p_mcb = &rfc_cb.port.rfc_mcb[j];
+ if (rfc_cb.port.rfc_mcb[j].state == RFC_MX_STATE_IDLE) {
+ /* New multiplexer control block */
+ alarm_free(p_mcb->mcb_timer);
+ fixed_queue_free(p_mcb->cmd_q, NULL);
+ memset(p_mcb, 0, sizeof(tRFC_MCB));
+ memcpy(p_mcb->bd_addr, bd_addr, BD_ADDR_LEN);
+ RFCOMM_TRACE_DEBUG(
+ "rfc_alloc_multiplexer_channel:is_initiator:%d, create new p_mcb:%p, "
+ "index:%d",
+ is_initiator, &rfc_cb.port.rfc_mcb[j], j);
+
+ p_mcb->mcb_timer = alarm_new("rfcomm_mcb.mcb_timer");
+ p_mcb->cmd_q = fixed_queue_new(SIZE_MAX);
+
+ p_mcb->is_initiator = is_initiator;
+
+ rfc_timer_start(p_mcb, RFC_MCB_INIT_INACT_TIMER);
+
+ rfc_cb.rfc.last_mux = (uint8_t)j;
+ return (p_mcb);
+ }
+ }
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_release_multiplexer_channel
+ *
+ * Description Release a multiplexer control block
+ *
+ ******************************************************************************/
+void rfc_release_multiplexer_channel(tRFC_MCB* p_mcb) {
+ /* Remove the MCB from the mapping table */
+ rfc_save_lcid_mcb(NULL, p_mcb->lcid);
+
+ /* Remove the MCB from the ports */
+ for (int i = 0; i < MAX_RFC_PORTS; i++) {
+ if (rfc_cb.port.port[i].rfc.p_mcb == p_mcb)
+ rfc_cb.port.port[i].rfc.p_mcb = NULL;
+ }
+
+ rfc_timer_stop(p_mcb);
+ alarm_free(p_mcb->mcb_timer);
+
+ fixed_queue_free(p_mcb->cmd_q, osi_free);
+
+ memset(p_mcb, 0, sizeof(tRFC_MCB));
+ p_mcb->state = RFC_MX_STATE_IDLE;
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_timer_start
+ *
+ * Description Start RFC Timer
+ *
+ ******************************************************************************/
+void rfc_timer_start(tRFC_MCB* p_mcb, uint16_t timeout) {
+ RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout);
+
+ period_ms_t interval_ms = timeout * 1000;
+ alarm_set_on_queue(p_mcb->mcb_timer, interval_ms, rfcomm_mcb_timer_timeout,
+ p_mcb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_timer_stop
+ *
+ * Description Stop RFC Timer
+ *
+ ******************************************************************************/
+void rfc_timer_stop(tRFC_MCB* p_mcb) {
+ RFCOMM_TRACE_EVENT("%s", __func__);
+
+ alarm_cancel(p_mcb->mcb_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_timer_start
+ *
+ * Description Start RFC Timer
+ *
+ ******************************************************************************/
+void rfc_port_timer_start(tPORT* p_port, uint16_t timeout) {
+ RFCOMM_TRACE_EVENT("%s - timeout:%d seconds", __func__, timeout);
+
+ period_ms_t interval_ms = timeout * 1000;
+ alarm_set_on_queue(p_port->rfc.port_timer, interval_ms,
+ rfcomm_port_timer_timeout, p_port,
+ btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_timer_stop
+ *
+ * Description Stop RFC Timer
+ *
+ ******************************************************************************/
+void rfc_port_timer_stop(tPORT* p_port) {
+ RFCOMM_TRACE_EVENT("%s", __func__);
+
+ alarm_cancel(p_port->rfc.port_timer);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_check_mcb_active
+ *
+ * Description Check if there are any opened ports on the MCB if not
+ * start MCB Inact timer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_check_mcb_active(tRFC_MCB* p_mcb) {
+ uint16_t i;
+
+ for (i = 0; i < RFCOMM_MAX_DLCI; i++) {
+ if (p_mcb->port_inx[i] != 0) {
+ p_mcb->is_disc_initiator = false;
+ return;
+ }
+ }
+ /* The last port was DISCed. On the client side start disconnecting Mx */
+ /* On the server side start inactivity timer */
+ if (p_mcb->is_disc_initiator) {
+ p_mcb->is_disc_initiator = false;
+ rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CLOSE_REQ, NULL);
+ } else
+ rfc_timer_start(p_mcb, RFC_MCB_RELEASE_INACT_TIMER);
+}
+
+void rfcomm_port_timer_timeout(void* data) {
+ tPORT* p_port = (tPORT*)data;
+
+ rfc_port_sm_execute(p_port, RFC_EVENT_TIMEOUT, NULL);
+}
+
+void rfcomm_mcb_timer_timeout(void* data) {
+ tRFC_MCB* p_mcb = (tRFC_MCB*)data;
+
+ rfc_mx_sm_execute(p_mcb, RFC_EVENT_TIMEOUT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_sec_check_complete
+ *
+ * Description The function called when Security Manager finishes
+ * verification of the service side connection
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr,
+ UNUSED_ATTR tBT_TRANSPORT transport,
+ void* p_ref_data, uint8_t res) {
+ tPORT* p_port = (tPORT*)p_ref_data;
+
+ /* Verify that PORT is still waiting for Security to complete */
+ if (!p_port->in_use ||
+ ((p_port->rfc.state != RFC_STATE_ORIG_WAIT_SEC_CHECK) &&
+ (p_port->rfc.state != RFC_STATE_TERM_WAIT_SEC_CHECK)))
+ return;
+
+ rfc_port_sm_execute((tPORT*)p_ref_data, RFC_EVENT_SEC_COMPLETE, &res);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_port_closed
+ *
+ * Description The function is called when port is released based on the
+ * event received from the lower layer, typically L2CAP
+ * connection down, DISC, or DM frame.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_port_closed(tPORT* p_port) {
+ tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
+
+ RFCOMM_TRACE_DEBUG("rfc_port_closed");
+
+ rfc_port_timer_stop(p_port);
+
+ p_port->rfc.state = RFC_STATE_CLOSED;
+
+ /* If multiplexer channel was up mark it as down */
+ if (p_mcb) {
+ p_mcb->port_inx[p_port->dlci] = 0;
+
+ /* If there are no more ports opened on this MCB release it */
+ rfc_check_mcb_active(p_mcb);
+ }
+
+ /* Notify port that RFC connection is gone */
+ port_rfc_closed(p_port, PORT_CLOSED);
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_inc_credit
+ *
+ * Description The function is called when a credit is received in a UIH
+ * frame. It increments the TX credit count, and if data
+ * flow had halted, it restarts it.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_inc_credit(tPORT* p_port, uint8_t credit) {
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
+ p_port->credit_tx += credit;
+
+ RFCOMM_TRACE_EVENT("rfc_inc_credit:%d", p_port->credit_tx);
+
+ if (p_port->tx.peer_fc == true)
+ PORT_FlowInd(p_port->rfc.p_mcb, p_port->dlci, true);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_dec_credit
+ *
+ * Description The function is called when a UIH frame of user data is
+ * sent. It decrements the credit count. If credit count
+ * Reaches zero, peer_fc is set.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_dec_credit(tPORT* p_port) {
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
+ if (p_port->credit_tx > 0) p_port->credit_tx--;
+
+ if (p_port->credit_tx == 0) p_port->tx.peer_fc = true;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function rfc_check_send_cmd
+ *
+ * Description This function is called to send an RFCOMM command message
+ * or to handle the RFCOMM command message queue.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void rfc_check_send_cmd(tRFC_MCB* p_mcb, BT_HDR* p_buf) {
+ /* if passed a buffer queue it */
+ if (p_buf != NULL) {
+ if (p_mcb->cmd_q == NULL) {
+ RFCOMM_TRACE_ERROR(
+ "%s: empty queue: p_mcb = %p p_mcb->lcid = %u cached p_mcb = %p",
+ __func__, p_mcb, p_mcb->lcid, rfc_find_lcid_mcb(p_mcb->lcid));
+ }
+ fixed_queue_enqueue(p_mcb->cmd_q, p_buf);
+ }
+
+ /* handle queue if L2CAP not congested */
+ while (p_mcb->l2cap_congested == false) {
+ BT_HDR* p = (BT_HDR*)fixed_queue_try_dequeue(p_mcb->cmd_q);
+ if (p == NULL) break;
+ L2CA_DataWrite(p_mcb->lcid, p);
+ }
+}
diff --git a/mtkbt/code/bt/stack/sdp/sdp_api.cc b/mtkbt/code/bt/stack/sdp/sdp_api.cc
new file mode 100755
index 0000000..b9cdb53
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_api.cc
@@ -0,0 +1,1147 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains SDP interface functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+
+#include "btu.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#include "osi/include/osi.h"
+
+/**********************************************************************
+ * C L I E N T F U N C T I O N P R O T O T Y P E S *
+ **********************************************************************/
+
+/*******************************************************************************
+ *
+ * Function SDP_InitDiscoveryDb
+ *
+ * Description This function is called to initialize a discovery database.
+ *
+ * Parameters: p_db - (input) address of an area of memory where the
+ * discovery database is managed.
+ * len - (input) size (in bytes) of the memory
+ * NOTE: This must be larger than
+ * sizeof(tSDP_DISCOVERY_DB)
+ * num_uuid - (input) number of UUID filters applied
+ * p_uuid_list - (input) list of UUID filters
+ * num_attr - (input) number of attribute filters applied
+ * p_attr_list - (input) list of attribute filters
+ *
+ *
+ * Returns bool
+ * true if successful
+ * false if one or more parameters are bad
+ *
+ ******************************************************************************/
+bool SDP_InitDiscoveryDb(tSDP_DISCOVERY_DB* p_db, uint32_t len,
+ uint16_t num_uuid, tSDP_UUID* p_uuid_list,
+ uint16_t num_attr, uint16_t* p_attr_list) {
+ uint16_t xx;
+
+ /* verify the parameters */
+ if (p_db == NULL || (sizeof(tSDP_DISCOVERY_DB) > len) ||
+ num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) {
+ SDP_TRACE_ERROR(
+ "SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, "
+ "num_attr %d",
+ PTR_TO_UINT(p_db), len, num_uuid, num_attr);
+
+ return (false);
+ }
+
+ memset(p_db, 0, (size_t)len);
+
+ p_db->mem_size = len - sizeof(tSDP_DISCOVERY_DB);
+ p_db->mem_free = p_db->mem_size;
+ p_db->p_first_rec = NULL;
+ p_db->p_free_mem = (uint8_t*)(p_db + 1);
+
+ for (xx = 0; xx < num_uuid; xx++) p_db->uuid_filters[xx] = *p_uuid_list++;
+
+ p_db->num_uuid_filters = num_uuid;
+
+ for (xx = 0; xx < num_attr; xx++) p_db->attr_filters[xx] = *p_attr_list++;
+
+ /* sort attributes */
+ sdpu_sort_attr_list(num_attr, p_db);
+
+ p_db->num_attr_filters = num_attr;
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_CancelServiceSearch
+ *
+ * Description This function cancels an active query to an SDP server.
+ *
+ * Returns true if discovery cancelled, false if a matching activity is
+ * not found.
+ *
+ ******************************************************************************/
+bool SDP_CancelServiceSearch(tSDP_DISCOVERY_DB* p_db) {
+ tCONN_CB* p_ccb = sdpu_find_ccb_by_db(p_db);
+ if (!p_ccb) return (false);
+
+ sdp_disconnect(p_ccb, SDP_CANCEL);
+ p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchRequest
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchRequest(uint8_t* p_bd_addr, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ tCONN_CB* p_ccb;
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate(p_bd_addr);
+
+ if (!p_ccb) return (false);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = p_db;
+ p_ccb->p_cb = p_cb;
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchAttributeRequest
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * The difference between this API function and the function
+ * SDP_ServiceSearchRequest is that this one does a
+ * combined ServiceSearchAttributeRequest SDP function.
+ * (This is for Unplug Testing)
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchAttributeRequest(uint8_t* p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB* p_cb) {
+ tCONN_CB* p_ccb;
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate(p_bd_addr);
+
+ if (!p_ccb) return (false);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = p_db;
+ p_ccb->p_cb = p_cb;
+
+ p_ccb->is_attr_search = true;
+
+ return (true);
+}
+/*******************************************************************************
+ *
+ * Function SDP_ServiceSearchAttributeRequest2
+ *
+ * Description This function queries an SDP server for information.
+ *
+ * The difference between this API function and the function
+ * SDP_ServiceSearchRequest is that this one does a
+ * combined ServiceSearchAttributeRequest SDP function.
+ * (This is for Unplug Testing)
+ *
+ * Returns true if discovery started, false if failed.
+ *
+ ******************************************************************************/
+bool SDP_ServiceSearchAttributeRequest2(uint8_t* p_bd_addr,
+ tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_CMPL_CB2* p_cb2,
+ void* user_data) {
+ tCONN_CB* p_ccb;
+
+ /* Specific BD address */
+ p_ccb = sdp_conn_originate(p_bd_addr);
+
+ if (!p_ccb) return (false);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_CONN;
+ p_ccb->p_db = p_db;
+ p_ccb->p_cb2 = p_cb2;
+
+ p_ccb->is_attr_search = true;
+ p_ccb->user_data = user_data;
+
+ return (true);
+}
+
+void SDP_SetIdleTimeout(UNUSED_ATTR BD_ADDR addr,
+ UNUSED_ATTR uint16_t timeout) {}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAttributeInDb
+ *
+ * Description This function queries an SDP database for a specific
+ * attribute. If the p_start_rec pointer is NULL, it looks from
+ * the beginning of the database, else it continues from the
+ * next record after p_start_rec.
+ *
+ * Returns Pointer to matching record, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindAttributeInDb(tSDP_DISCOVERY_DB* p_db, uint16_t attr_id,
+ tSDP_DISC_REC* p_start_rec) {
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR* p_attr;
+
+ /* Must have a valid database */
+ if (p_db == NULL) return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec) {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if (p_attr->attr_id == attr_id) return (p_rec);
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+ /* If here, no matching attribute found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAttributeInRec
+ *
+ * Description This function searches an SDP discovery record for a
+ * specific attribute.
+ *
+ * Returns Pointer to matching attribute entry, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_ATTR* SDP_FindAttributeInRec(tSDP_DISC_REC* p_rec, uint16_t attr_id) {
+ tSDP_DISC_ATTR* p_attr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if (p_attr->attr_id == attr_id) return (p_attr);
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ /* If here, no matching attribute found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInRec
+ *
+ * Description This function is called to read the service UUID within a
+ * record if there is any.
+ *
+ * Parameters: p_rec - pointer to a SDP record.
+ * p_uuid - output parameter to save the UUID found.
+ *
+ * Returns true if found, otherwise false.
+ *
+ ******************************************************************************/
+bool SDP_FindServiceUUIDInRec(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid) {
+ tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
+
+ p_attr = p_rec->p_first_attr;
+
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
+ if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) {
+ p_uuid->len = LEN_UUID_16;
+ p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
+ } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
+ LEN_UUID_128) {
+ p_uuid->len = LEN_UUID_128;
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] =
+ p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
+ } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) {
+ p_uuid->len = LEN_UUID_32;
+ p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
+ }
+
+ return (true);
+ }
+
+ /* Checking for Toyota G Block Car Kit:
+ ** This car kit puts an extra data element sequence
+ ** where the UUID is suppose to be!!!
+ */
+ else {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE) {
+ /* Look through data element sequence until no more UUIDs */
+ for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr;
+ p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
+ /* Increment past this to see if the next attribut is UUID */
+ if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
+ UUID_DESC_TYPE)
+ /* only support 16 bits UUID for now */
+ && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) {
+ p_uuid->len = 2;
+ p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
+ return (true);
+ }
+ }
+ }
+ }
+ }
+ break;
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+ /* only support 16 bits UUID for now */
+ && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) {
+ p_uuid->len = 2;
+ p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
+ return (true);
+ }
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInRec_128bit
+ *
+ * Description This function is called to read the 128-bit service UUID
+ * within a record if there is any.
+ *
+ * Parameters: p_rec - pointer to a SDP record.
+ * p_uuid - output parameter to save the UUID found.
+ *
+ * Returns true if found, otherwise false.
+ *
+ ******************************************************************************/
+bool SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC* p_rec, tBT_UUID* p_uuid) {
+ tSDP_DISC_ATTR* p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
+ tSDP_DISC_ATTR* p_sattr = p_attr->attr_value.v.p_sub_attr;
+ while (p_sattr) {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
+ /* only support 128 bits UUID for now */
+ if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) {
+ p_uuid->len = LEN_UUID_128;
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] =
+ p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
+ }
+ return (true);
+ }
+
+ p_sattr = p_sattr->p_next_attr;
+ }
+ break;
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
+ /* only support 128 bits UUID for now */
+ && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
+ p_uuid->len = LEN_UUID_128;
+ for (uint8_t i = 0; i != LEN_UUID_128; ++i)
+ p_uuid->uu.uuid128[i] =
+ p_attr->attr_value.v.array[LEN_UUID_128 - i - 1];
+ return (true);
+ }
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceInDb
+ *
+ * Description This function queries an SDP database for a specific
+ * service. If the p_start_rec pointer is NULL, it looks from
+ * the beginning of the database, else it continues from the
+ * next record after p_start_rec.
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceInDb(tSDP_DISCOVERY_DB* p_db,
+ uint16_t service_uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL) return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec) {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
+ SDP_TRACE_DEBUG(
+ "SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x",
+ p_sattr->attr_value.v.u16, service_uuid);
+ if (service_uuid == UUID_SERVCLASS_HDP_PROFILE) {
+ if ((p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE) ||
+ (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK)) {
+ SDP_TRACE_DEBUG(
+ "SDP_FindServiceInDb found HDP source or sink\n");
+ return (p_rec);
+ }
+ }
+ }
+
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE &&
+ (service_uuid == 0 ||
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2 &&
+ p_sattr->attr_value.v.u16 == service_uuid)))
+ /* for a specific uuid, or any one */
+ {
+ return (p_rec);
+ }
+
+ /* Checking for Toyota G Block Car Kit:
+ ** This car kit puts an extra data element sequence
+ ** where the UUID is suppose to be!!!
+ */
+ else {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE) {
+ /* Look through data element sequence until no more UUIDs */
+ for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr;
+ p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
+ /* Increment past this to see if the next attribut is UUID */
+ if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) ==
+ UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
+ /* for a specific uuid, or any one */
+ && ((p_extra_sattr->attr_value.v.u16 == service_uuid) ||
+ (service_uuid == 0))) {
+ return (p_rec);
+ }
+ }
+ }
+ }
+ }
+ break;
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
+ /* find a specific UUID or anyone */
+ &&
+ ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0))
+ return (p_rec);
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+ /* If here, no matching UUID found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceInDb_128bit
+ *
+ * Description Query an SDP database for a specific service. If the
+ * p_start_rec pointer is NULL, it looks from the beginning of
+ * the database, else it continues from the next record after
+ * p_start_rec.
+ *
+ * This function is kept separate from SDP_FindServiceInDb
+ * since that API is expected to return only 16-bit UUIDs
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_start_rec) {
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL) return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec) {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) {
+ return (p_rec);
+ }
+ }
+ break;
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16))
+ return (p_rec);
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+ /* If here, no matching UUID found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindServiceUUIDInDb
+ *
+ * Description Query an SDP database for a specific service. If the
+ * p_start_rec pointer is NULL, it looks from the beginning of
+ * the database, else it continues from the next record after
+ * p_start_rec.
+ *
+ * NOTE the only difference between this function and the previous
+ * function "SDP_FindServiceInDb()" is that this function takes
+ * a tBT_UUID input
+ *
+ * Returns Pointer to record containing service class, or NULL
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* SDP_FindServiceUUIDInDb(tSDP_DISCOVERY_DB* p_db,
+ tBT_UUID* p_uuid,
+ tSDP_DISC_REC* p_start_rec) {
+ tSDP_DISC_REC* p_rec;
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ /* Must have a valid database */
+ if (p_db == NULL) return (NULL);
+
+ if (!p_start_rec)
+ p_rec = p_db->p_first_rec;
+ else
+ p_rec = p_start_rec->p_next_rec;
+
+ while (p_rec) {
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
+ if (sdpu_compare_uuid_with_attr(p_uuid, p_sattr)) return (p_rec);
+ }
+ }
+ break;
+ } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) {
+ if (sdpu_compare_uuid_with_attr(p_uuid, p_attr)) return (p_rec);
+ }
+ }
+
+ p_attr = p_attr->p_next_attr;
+ }
+
+ p_rec = p_rec->p_next_rec;
+ }
+ /* If here, no matching UUID found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_fill_proto_elem
+ *
+ * Description This function retrieves the protocol element.
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+static bool sdp_fill_proto_elem(tSDP_DISC_ATTR* p_attr, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) {
+ tSDP_DISC_ATTR* p_sattr;
+
+ /* Walk through the protocol descriptor list */
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
+ p_attr = p_attr->p_next_attr) {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ return (false);
+
+ /* Now, see if the entry contains the layer we are interested in */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
+ p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
+
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) &&
+ (p_sattr->attr_value.v.u16 == layer_uuid)) {
+ /* Bingo. Now fill in the passed element */
+ p_elem->protocol_uuid = layer_uuid;
+ p_elem->num_params = 0;
+
+ /* Store the parameters, if any */
+ for (p_sattr = p_sattr->p_next_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE)
+ break;
+
+ if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
+ p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
+ else
+ p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
+
+ if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) break;
+ }
+ return (true);
+ }
+ }
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindProtocolListElemInRec
+ *
+ * Description This function looks at a specific discovery record for a
+ * protocol list element.
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindProtocolListElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) {
+ tSDP_DISC_ATTR* p_attr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ /* Find the protocol descriptor list */
+ if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
+ return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+ /* If here, no match found */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindAddProtoListsElemInRec
+ *
+ * Description This function looks at a specific discovery record for a
+ * protocol list element.
+ *
+ * Returns true if found, false if not
+ * If found, the passed protocol list element is filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindAddProtoListsElemInRec(tSDP_DISC_REC* p_rec, uint16_t layer_uuid,
+ tSDP_PROTOCOL_ELEM* p_elem) {
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+ bool ret = false;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ /* Find the additional protocol descriptor list attribute */
+ if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
+ DATA_ELE_SEQ_DESC_TYPE) {
+ ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem);
+ if (ret == true) break;
+ }
+ }
+ return ret;
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+ /* If here, no match found */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_FindProfileVersionInRec
+ *
+ * Description This function looks at a specific discovery record for the
+ * Profile list descriptor, and pulls out the version number.
+ * The version number consists of an 8-bit major version and
+ * an 8-bit minor version.
+ *
+ * Returns true if found, false if not
+ * If found, the major and minor version numbers that were
+ * passed in are filled in.
+ *
+ ******************************************************************************/
+bool SDP_FindProfileVersionInRec(tSDP_DISC_REC* p_rec, uint16_t profile_uuid,
+ uint16_t* p_version) {
+ tSDP_DISC_ATTR *p_attr, *p_sattr;
+
+ p_attr = p_rec->p_first_attr;
+ while (p_attr) {
+ /* Find the profile descriptor list */
+ if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
+ (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
+ /* Walk through the protocol descriptor list */
+ for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr;
+ p_attr = p_attr->p_next_attr) {
+ /* Safety check - each entry should itself be a sequence */
+ if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE)
+ return (false);
+
+ /* Now, see if the entry contains the profile UUID we are interested in
+ */
+ for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr;
+ p_sattr = p_sattr->p_next_attr) {
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) ==
+ 2) /* <- This is bytes, not size code! */
+ && (p_sattr->attr_value.v.u16 == profile_uuid)) {
+ /* Now fill in the major and minor numbers */
+ /* if the attribute matches the description for version (type UINT,
+ * size 2 bytes) */
+ p_sattr = p_sattr->p_next_attr;
+
+ if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) ==
+ UINT_DESC_TYPE) &&
+ (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
+ /* The high order 8 bits is the major number, low order is the
+ * minor number (big endian) */
+ *p_version = p_sattr->attr_value.v.u16;
+
+ return (true);
+ } else
+ return (false); /* The type and/or size was not valid for the
+ profile list version */
+ }
+ }
+ }
+
+ return (false);
+ }
+ p_attr = p_attr->p_next_attr;
+ }
+
+ /* If here, no match found */
+ return (false);
+}
+
+/*******************************************************************************
+ * Device Identification (DI) Client Functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function SDP_DiDiscover
+ *
+ * Description This function queries a remote device for DI information.
+ *
+ * Returns SDP_SUCCESS if query started successfully, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_DiDiscover(BD_ADDR remote_device, tSDP_DISCOVERY_DB* p_db,
+ uint32_t len, tSDP_DISC_CMPL_CB* p_cb) {
+ uint16_t result = SDP_DI_DISC_FAILED;
+ uint16_t num_uuids = 1;
+ uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
+
+ /* build uuid for db init */
+ tSDP_UUID init_uuid;
+ init_uuid.len = 2;
+ init_uuid.uu.uuid16 = di_uuid;
+
+ if (SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL))
+ if (SDP_ServiceSearchRequest(remote_device, p_db, p_cb))
+ result = SDP_SUCCESS;
+
+ return result;
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_GetNumDiRecords
+ *
+ * Description Searches specified database for DI records
+ *
+ * Returns number of DI records found
+ *
+ ******************************************************************************/
+uint8_t SDP_GetNumDiRecords(tSDP_DISCOVERY_DB* p_db) {
+ uint8_t num_records = 0;
+ tSDP_DISC_REC* p_curr_record = NULL;
+
+ do {
+ p_curr_record = SDP_FindServiceInDb(p_db, UUID_SERVCLASS_PNP_INFORMATION,
+ p_curr_record);
+ if (p_curr_record) num_records++;
+ } while (p_curr_record);
+
+ return num_records;
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AttrStringCopy
+ *
+ * Description This function copy given attribute to specified buffer as a
+ * string
+ *
+ * Returns none
+ *
+ ******************************************************************************/
+static void SDP_AttrStringCopy(char* dst, tSDP_DISC_ATTR* p_attr,
+ uint16_t dst_size) {
+ if (dst == NULL) return;
+ if (p_attr) {
+ uint16_t len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+ if (len > dst_size - 1) {
+ len = dst_size - 1;
+ }
+ memcpy(dst, (char*)p_attr->attr_value.v.array, len);
+ dst[len] = '\0';
+ } else {
+ dst[0] = '\0';
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_GetDiRecord
+ *
+ * Description This function retrieves a remote device's DI record from
+ * the specified database.
+ *
+ * Returns SDP_SUCCESS if record retrieved, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_GetDiRecord(uint8_t get_record_index,
+ tSDP_DI_GET_RECORD* p_device_info,
+ tSDP_DISCOVERY_DB* p_db) {
+ uint16_t result = SDP_NO_DI_RECORD_FOUND;
+ uint8_t curr_record_index = 1;
+
+ tSDP_DISC_REC* p_curr_record = NULL;
+
+ /* find the requested SDP record in the discovery database */
+ do {
+ p_curr_record = SDP_FindServiceInDb(p_db, UUID_SERVCLASS_PNP_INFORMATION,
+ p_curr_record);
+ if (p_curr_record) {
+ if (curr_record_index++ == get_record_index) {
+ result = SDP_SUCCESS;
+ break;
+ }
+ }
+ } while (p_curr_record);
+
+ if (result == SDP_SUCCESS) {
+ /* copy the information from the SDP record to the DI record */
+ tSDP_DISC_ATTR* p_curr_attr = NULL;
+
+ /* ClientExecutableURL is optional */
+ p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_CLIENT_EXE_URL);
+ SDP_AttrStringCopy(p_device_info->rec.client_executable_url, p_curr_attr,
+ SDP_MAX_ATTR_LEN);
+
+ /* Service Description is optional */
+ p_curr_attr =
+ SDP_FindAttributeInRec(p_curr_record, ATTR_ID_SERVICE_DESCRIPTION);
+ SDP_AttrStringCopy(p_device_info->rec.service_description, p_curr_attr,
+ SDP_MAX_ATTR_LEN);
+
+ /* DocumentationURL is optional */
+ p_curr_attr =
+ SDP_FindAttributeInRec(p_curr_record, ATTR_ID_DOCUMENTATION_URL);
+ SDP_AttrStringCopy(p_device_info->rec.documentation_url, p_curr_attr,
+ SDP_MAX_ATTR_LEN);
+
+ p_curr_attr =
+ SDP_FindAttributeInRec(p_curr_record, ATTR_ID_SPECIFICATION_ID);
+ if (p_curr_attr)
+ p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_VENDOR_ID);
+ if (p_curr_attr)
+ p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr =
+ SDP_FindAttributeInRec(p_curr_record, ATTR_ID_VENDOR_ID_SOURCE);
+ if (p_curr_attr)
+ p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRODUCT_ID);
+ if (p_curr_attr)
+ p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr =
+ SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRODUCT_VERSION);
+ if (p_curr_attr)
+ p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+
+ p_curr_attr = SDP_FindAttributeInRec(p_curr_record, ATTR_ID_PRIMARY_RECORD);
+ if (p_curr_attr)
+ p_device_info->rec.primary_record = (bool)p_curr_attr->attr_value.v.u8;
+ else
+ result = SDP_ERR_ATTR_NOT_PRESENT;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ * Device Identification (DI) Server Functions
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function SDP_SetLocalDiRecord
+ *
+ * Description This function adds a DI record to the local SDP database.
+ *
+ *
+ *
+ * Returns Returns SDP_SUCCESS if record added successfully, else error
+ *
+ ******************************************************************************/
+uint16_t SDP_SetLocalDiRecord(tSDP_DI_RECORD* p_device_info,
+ uint32_t* p_handle) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t result = SDP_SUCCESS;
+ uint32_t handle;
+ uint16_t di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
+ uint16_t di_specid = BLUETOOTH_DI_SPECIFICATION;
+ uint8_t temp_u16[2];
+ uint8_t* p_temp;
+ uint8_t u8;
+
+ *p_handle = 0;
+ if (p_device_info == NULL) return SDP_ILLEGAL_PARAMETER;
+
+ /* if record is to be primary record, get handle to replace old primary */
+ if (p_device_info->primary_record == true &&
+ sdp_cb.server_db.di_primary_handle)
+ handle = sdp_cb.server_db.di_primary_handle;
+ else {
+ handle = SDP_CreateRecord();
+ if (handle == 0) return SDP_NO_RESOURCES;
+ }
+
+ *p_handle = handle;
+
+ /* build the SDP entry */
+ /* Add the UUID to the Service Class ID List */
+ if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == false)
+ result = SDP_DI_REG_FAILED;
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, di_specid);
+ if (!(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID, UINT_DESC_TYPE,
+ sizeof(di_specid), temp_u16)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if (result == SDP_SUCCESS) {
+ if (p_device_info->client_executable_url[0] != '\0') {
+ if (!((strlen(p_device_info->client_executable_url) + 1 <=
+ SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(
+ handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
+ (uint32_t)(strlen(p_device_info->client_executable_url) + 1),
+ (uint8_t*)p_device_info->client_executable_url)))
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if (result == SDP_SUCCESS) {
+ if (p_device_info->service_description[0] != '\0') {
+ if (!((strlen(p_device_info->service_description) + 1 <=
+ SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(
+ handle, ATTR_ID_SERVICE_DESCRIPTION, TEXT_STR_DESC_TYPE,
+ (uint32_t)(strlen(p_device_info->service_description) + 1),
+ (uint8_t*)p_device_info->service_description)))
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* optional - if string is null, do not add attribute */
+ if (result == SDP_SUCCESS) {
+ if (p_device_info->documentation_url[0] != '\0') {
+ if (!((strlen(p_device_info->documentation_url) + 1 <=
+ SDP_MAX_ATTR_LEN) &&
+ SDP_AddAttribute(
+ handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
+ (uint32_t)(strlen(p_device_info->documentation_url) + 1),
+ (uint8_t*)p_device_info->documentation_url)))
+ result = SDP_DI_REG_FAILED;
+ }
+ }
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
+ if (!(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
+ sizeof(p_device_info->vendor), temp_u16)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->product);
+ if (!(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID, UINT_DESC_TYPE,
+ sizeof(p_device_info->product), temp_u16)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->version);
+ if (!(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
+ sizeof(p_device_info->version), temp_u16)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ u8 = (uint8_t)p_device_info->primary_record;
+ if (!(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD, BOOLEAN_DESC_TYPE, 1,
+ &u8)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ /* mandatory */
+ if (result == SDP_SUCCESS) {
+ p_temp = temp_u16;
+ UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
+ if (!(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
+ sizeof(p_device_info->vendor_id_source), temp_u16)))
+ result = SDP_DI_REG_FAILED;
+ }
+
+ if (result != SDP_SUCCESS)
+ SDP_DeleteRecord(handle);
+ else if (p_device_info->primary_record == true)
+ sdp_cb.server_db.di_primary_handle = handle;
+
+ return result;
+#else /* SDP_SERVER_ENABLED is FALSE */
+ return SDP_DI_REG_FAILED;
+#endif /* if SDP_SERVER_ENABLED */
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_SetTraceLevel
+ *
+ * Description This function sets the trace level for SDP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t SDP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) sdp_cb.trace_level = new_level;
+
+ return (sdp_cb.trace_level);
+}
diff --git a/mtkbt/code/bt/stack/sdp/sdp_db.cc b/mtkbt/code/bt/stack/sdp/sdp_db.cc
new file mode 100755
index 0000000..49f4269
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_db.cc
@@ -0,0 +1,905 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains functions that handle the database
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_target.h"
+
+#include "bt_common.h"
+
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#if (SDP_SERVER_ENABLED == TRUE)
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_his_uuid,
+ uint16_t his_len, int nest_level);
+
+/*******************************************************************************
+ *
+ * Function sdp_db_service_search
+ *
+ * Description This function searches for a record that contains the
+ * specified UIDs. It is passed either NULL to start at the
+ * beginning, or the previous record found.
+ *
+ * Returns Pointer to the record, or NULL if not found.
+ *
+ ******************************************************************************/
+tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec, tSDP_UUID_SEQ* p_seq) {
+ uint16_t xx, yy;
+ tSDP_ATTRIBUTE* p_attr;
+ tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+ /* If NULL, start at the beginning, else start at the first specified record
+ */
+ if (!p_rec)
+ p_rec = &sdp_cb.server_db.record[0];
+ else
+ p_rec++;
+
+ /* Look through the records. The spec says that a match occurs if */
+ /* the record contains all the passed UUIDs in it. */
+ for (; p_rec < p_end; p_rec++) {
+ for (yy = 0; yy < p_seq->num_uids; yy++) {
+ p_attr = &p_rec->attribute[0];
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
+ if (p_attr->type == UUID_DESC_TYPE) {
+ if (sdpu_compare_uuid_arrays(p_attr->value_ptr, p_attr->len,
+ &p_seq->uuid_entry[yy].value[0],
+ p_seq->uuid_entry[yy].len))
+ break;
+ } else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) {
+ if (find_uuid_in_seq(p_attr->value_ptr, p_attr->len,
+ &p_seq->uuid_entry[yy].value[0],
+ p_seq->uuid_entry[yy].len, 0))
+ break;
+ }
+ }
+ /* If any UUID was not found, on to the next record */
+ if (xx == p_rec->num_attributes) break;
+ }
+
+ /* If every UUID was found in the record, return the record */
+ if (yy == p_seq->num_uids) return (p_rec);
+ }
+
+ /* If here, no more records found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function find_uuid_in_seq
+ *
+ * Description This function searches a data element sequenct for a UUID.
+ *
+ * Returns true if found, else false
+ *
+ ******************************************************************************/
+static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_uuid,
+ uint16_t uuid_len, int nest_level) {
+ uint8_t* p_end = p + seq_len;
+ uint8_t type;
+ uint32_t len;
+
+ /* A little safety check to avoid excessive recursion */
+ if (nest_level > 3) return (false);
+
+ while (p < p_end) {
+ type = *p++;
+ p = sdpu_get_len_from_type(p, type, &len);
+ type = type >> 3;
+ if (type == UUID_DESC_TYPE) {
+ if (sdpu_compare_uuid_arrays(p, len, p_uuid, uuid_len)) return (true);
+ } else if (type == DATA_ELE_SEQ_DESC_TYPE) {
+ if (find_uuid_in_seq(p, len, p_uuid, uuid_len, nest_level + 1))
+ return (true);
+ }
+ p = p + len;
+ }
+
+ /* If here, failed to match */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_db_find_record
+ *
+ * Description This function searches for a record with a specific handle
+ * It is passed the handle of the record.
+ *
+ * Returns Pointer to the record, or NULL if not found.
+ *
+ ******************************************************************************/
+tSDP_RECORD* sdp_db_find_record(uint32_t handle) {
+ tSDP_RECORD* p_rec;
+ tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
+
+ /* Look through the records for the caller's handle */
+ for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++) {
+ if (p_rec->record_handle == handle) return (p_rec);
+ }
+
+ /* Record with that handle not found. */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_db_find_attr_in_rec
+ *
+ * Description This function searches a record for specific attributes.
+ * It is passed a pointer to the record. If the record contains
+ * the specified attribute, (the caller may specify be a range
+ * of attributes), the attribute is returned.
+ *
+ * Returns Pointer to the attribute, or NULL if not found.
+ *
+ ******************************************************************************/
+tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec, uint16_t start_attr,
+ uint16_t end_attr) {
+ tSDP_ATTRIBUTE* p_at;
+ uint16_t xx;
+
+ /* Note that the attributes in a record are assumed to be in sorted order */
+ for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
+ xx++, p_at++) {
+ if ((p_at->id >= start_attr) && (p_at->id <= end_attr)) return (p_at);
+ }
+
+ /* No matching attribute found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_compose_proto_list
+ *
+ * Description This function is called to compose a data sequence from
+ * protocol element list struct pointer
+ *
+ * Returns the length of the data sequence
+ *
+ ******************************************************************************/
+static int sdp_compose_proto_list(uint8_t* p, uint16_t num_elem,
+ tSDP_PROTOCOL_ELEM* p_elem_list) {
+ uint16_t xx, yy, len;
+ bool is_rfcomm_scn;
+ uint8_t* p_head = p;
+ uint8_t* p_len;
+
+ /* First, build the protocol list. This consists of a set of data element
+ ** sequences, one for each layer. Each layer sequence consists of layer's
+ ** UUID and optional parameters
+ */
+ for (xx = 0; xx < num_elem; xx++, p_elem_list++) {
+ len = 3 + (p_elem_list->num_params * 3);
+ UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+ p_len = p;
+ *p++ = (uint8_t)len;
+
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, p_elem_list->protocol_uuid);
+
+ if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
+ is_rfcomm_scn = true;
+ else
+ is_rfcomm_scn = false;
+
+ for (yy = 0; yy < p_elem_list->num_params; yy++) {
+ if (is_rfcomm_scn) {
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
+ UINT8_TO_BE_STREAM(p, p_elem_list->params[yy]);
+
+ *p_len -= 1;
+ } else {
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, p_elem_list->params[yy]);
+ }
+ }
+ }
+ return (p - p_head);
+}
+
+#endif /* SDP_SERVER_ENABLED == TRUE */
+
+/*******************************************************************************
+ *
+ * Function SDP_CreateRecord
+ *
+ * Description This function is called to create a record in the database.
+ * This would be through the SDP database maintenance API. The
+ * record is created empty, teh application should then call
+ * "add_attribute" to add the record's attributes.
+ *
+ * Returns Record handle if OK, else 0.
+ *
+ ******************************************************************************/
+uint32_t SDP_CreateRecord(void) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint32_t handle;
+ uint8_t buf[4];
+ tSDP_DB* p_db = &sdp_cb.server_db;
+
+ /* First, check if there is a free record */
+ if (p_db->num_records < SDP_MAX_RECORDS) {
+ memset(&p_db->record[p_db->num_records], 0, sizeof(tSDP_RECORD));
+
+ /* We will use a handle of the first unreserved handle plus last record
+ ** number + 1 */
+ if (p_db->num_records)
+ handle = p_db->record[p_db->num_records - 1].record_handle + 1;
+ else
+ handle = 0x10000;
+
+ p_db->record[p_db->num_records].record_handle = handle;
+
+ p_db->num_records++;
+ SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records);
+ /* Add the first attribute (the handle) automatically */
+ UINT32_TO_BE_FIELD(buf, handle);
+ SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4,
+ buf);
+
+ return (p_db->record[p_db->num_records - 1].record_handle);
+ } else
+ SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d",
+ SDP_MAX_RECORDS);
+#endif
+ return (0);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_DeleteRecord
+ *
+ * Description This function is called to add a record (or all records)
+ * from the database. This would be through the SDP database
+ * maintenance API.
+ *
+ * If a record handle of 0 is passed, all records are deleted.
+ *
+ * Returns true if succeeded, else false
+ *
+ ******************************************************************************/
+bool SDP_DeleteRecord(uint32_t handle) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx, yy, zz;
+ tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
+
+ if (handle == 0 || sdp_cb.server_db.num_records == 0) {
+ /* Delete all records in the database */
+ sdp_cb.server_db.num_records = 0;
+
+ /* require new DI record to be created in SDP_SetLocalDiRecord */
+ sdp_cb.server_db.di_primary_handle = 0;
+
+ return (true);
+ } else {
+ /* Find the record in the database */
+ for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
+ if (p_rec->record_handle == handle) {
+ /* Found it. Shift everything up one */
+ for (yy = xx; yy < sdp_cb.server_db.num_records - 1; yy++, p_rec++) {
+ *p_rec = *(p_rec + 1);
+
+ /* Adjust the attribute value pointer for each attribute */
+ for (zz = 0; zz < p_rec->num_attributes; zz++)
+ p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
+ }
+
+ sdp_cb.server_db.num_records--;
+
+ SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d",
+ sdp_cb.server_db.num_records);
+ /* if we're deleting the primary DI record, clear the */
+ /* value in the control block */
+ if (sdp_cb.server_db.di_primary_handle == handle) {
+ sdp_cb.server_db.di_primary_handle = 0;
+ }
+
+ return (true);
+ }
+ }
+ }
+#endif
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddAttribute
+ *
+ * Description This function is called to add an attribute to a record.
+ * This would be through the SDP database maintenance API.
+ * If the attribute already exists in the record, it is
+ * replaced with the new value.
+ *
+ * NOTE Attribute values must be passed as a Big Endian stream.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type,
+ uint32_t attr_len, uint8_t* p_val) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx, yy, zz;
+ tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
+
+ if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) {
+ if ((attr_type == UINT_DESC_TYPE) ||
+ (attr_type == TWO_COMP_INT_DESC_TYPE) ||
+ (attr_type == UUID_DESC_TYPE) ||
+ (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
+ (attr_type == DATA_ELE_ALT_DESC_TYPE)) {
+ uint8_t num_array[400];
+ uint32_t len = (attr_len > 200) ? 200 : attr_len;
+
+ num_array[0] = '\0';
+ for (uint32_t i = 0; i < len; i++) {
+ snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
+ (uint8_t)(p_val[i]));
+ }
+ SDP_TRACE_DEBUG(
+ "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
+ "*p_val:%s",
+ handle, attr_id, attr_type, attr_len, p_val, num_array);
+ } else if (attr_type == BOOLEAN_DESC_TYPE) {
+ SDP_TRACE_DEBUG(
+ "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
+ "*p_val:%d",
+ handle, attr_id, attr_type, attr_len, p_val, *p_val);
+ } else {
+ SDP_TRACE_DEBUG(
+ "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, "
+ "*p_val:%s",
+ handle, attr_id, attr_type, attr_len, p_val, p_val);
+ }
+ }
+
+ /* Find the record in the database */
+ for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++) {
+ if (p_rec->record_handle == handle) {
+ tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
+
+ /* Found the record. Now, see if the attribute already exists */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
+ /* The attribute exists. replace it */
+ if (p_attr->id == attr_id) {
+ SDP_DeleteAttribute(handle, attr_id);
+ break;
+ }
+ if (p_attr->id > attr_id) break;
+ }
+
+ if (p_rec->num_attributes == SDP_MAX_REC_ATTR) return (false);
+
+ /* If not found, see if we can allocate a new entry */
+ if (xx == p_rec->num_attributes)
+ p_attr = &p_rec->attribute[p_rec->num_attributes];
+ else {
+ /* Since the attributes are kept in sorted order, insert ours here */
+ for (yy = p_rec->num_attributes; yy > xx; yy--)
+ p_rec->attribute[yy] = p_rec->attribute[yy - 1];
+ }
+
+ p_attr->id = attr_id;
+ p_attr->type = attr_type;
+ p_attr->len = attr_len;
+
+ if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) {
+ /* do truncate only for text string type descriptor */
+ if (attr_type == TEXT_STR_DESC_TYPE) {
+ SDP_TRACE_WARNING(
+ "SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
+ attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr);
+
+ attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
+ p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr + 1] = '\0';
+ } else
+ attr_len = 0;
+ }
+
+ if ((attr_len > 0) && (p_val != 0)) {
+ p_attr->len = attr_len;
+ memcpy(&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
+ p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
+ p_rec->free_pad_ptr += attr_len;
+ } else if ((attr_len == 0 &&
+ p_attr->len !=
+ 0) || /* if truncate to 0 length, simply don't add */
+ p_val == 0) {
+ SDP_TRACE_ERROR(
+ "SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
+ attr_id, attr_len);
+ p_attr->id = p_attr->type = p_attr->len = 0;
+ return (false);
+ }
+ p_rec->num_attributes++;
+ return (true);
+ }
+ }
+#endif
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddSequence
+ *
+ * Description This function is called to add a sequence to a record.
+ * This would be through the SDP database maintenance API.
+ * If the sequence already exists in the record, it is replaced
+ * with the new sequence.
+ *
+ * NOTE Element values must be passed as a Big Endian stream.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem,
+ uint8_t type[], uint8_t len[], uint8_t* p_val[]) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx;
+ uint8_t* p;
+ uint8_t* p_head;
+ bool result;
+ uint8_t* p_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+ p = p_buff;
+
+ /* First, build the sequence */
+ for (xx = 0; xx < num_elem; xx++) {
+ p_head = p;
+ switch (len[xx]) {
+ case 1:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_ONE_BYTE);
+ break;
+ case 2:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_TWO_BYTES);
+ break;
+ case 4:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_FOUR_BYTES);
+ break;
+ case 8:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
+ break;
+ case 16:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
+ break;
+ default:
+ UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p, len[xx]);
+ break;
+ }
+
+ ARRAY_TO_BE_STREAM(p, p_val[xx], len[xx]);
+
+ if (p - p_buff > SDP_MAX_ATTR_LEN) {
+ /* go back to before we add this element */
+ p = p_head;
+ if (p_head == p_buff) {
+ /* the first element exceed the max length */
+ SDP_TRACE_ERROR("SDP_AddSequence - too long(attribute is not added)!!");
+ osi_free(p_buff);
+ return false;
+ } else
+ SDP_TRACE_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx,
+ num_elem);
+ break;
+ }
+ }
+ result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
+ (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddUuidSequence
+ *
+ * Description This function is called to add a UUID sequence to a record.
+ * This would be through the SDP database maintenance API.
+ * If the sequence already exists in the record, it is replaced
+ * with the new sequence.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids,
+ uint16_t* p_uuids) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx;
+ uint8_t* p;
+ int32_t max_len = SDP_MAX_ATTR_LEN - 3;
+ bool result;
+ uint8_t* p_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+ p = p_buff;
+
+ /* First, build the sequence */
+ for (xx = 0; xx < num_uuids; xx++, p_uuids++) {
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, *p_uuids);
+
+ if ((p - p_buff) > max_len) {
+ SDP_TRACE_WARNING("SDP_AddUuidSequence - too long, add %d uuids of %d",
+ xx, num_uuids);
+ break;
+ }
+ }
+
+ result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
+ (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddProtocolList
+ *
+ * Description This function is called to add a protocol descriptor list to
+ * a record. This would be through the SDP database
+ * maintenance API. If the protocol list already exists in the
+ * record, it is replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem,
+ tSDP_PROTOCOL_ELEM* p_elem_list) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ int offset;
+ bool result;
+ uint8_t* p_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+ offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list);
+ result = SDP_AddAttribute(handle, ATTR_ID_PROTOCOL_DESC_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buff);
+ osi_free(p_buff);
+ return result;
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddAdditionProtoLists
+ *
+ * Description This function is called to add a protocol descriptor list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the protocol list already exists in the record, it
+ * is replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem,
+ tSDP_PROTO_LIST_ELEM* p_proto_list) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx;
+ uint8_t* p;
+ uint8_t* p_len;
+ int offset;
+ bool result;
+ uint8_t* p_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+ p = p_buff;
+
+ /* for each ProtocolDescriptorList */
+ for (xx = 0; xx < num_elem; xx++, p_proto_list++) {
+ UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_len = p++;
+
+ offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
+ p_proto_list->list_elem);
+ p += offset;
+
+ *p_len = (uint8_t)(p - p_len - 1);
+ }
+ result =
+ SDP_AddAttribute(handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddProfileDescriptorList
+ *
+ * Description This function is called to add a profile descriptor list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the version already exists in the record, it is
+ * replaced with the new one.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid,
+ uint16_t version) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint8_t* p;
+ bool result;
+ uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+
+ p = p_buff + 2;
+
+ /* First, build the profile descriptor list. This consists of a data element
+ * sequence. */
+ /* The sequence consists of profile's UUID and version number */
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, profile_uuid);
+
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, version);
+
+ /* Add in type and length fields */
+ *p_buff = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ *(p_buff + 1) = (uint8_t)(p - (p_buff + 2));
+
+ result =
+ SDP_AddAttribute(handle, ATTR_ID_BT_PROFILE_DESC_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddLanguageBaseAttrIDList
+ *
+ * Description This function is called to add a language base attr list to
+ * a record. This would be through the SDP database maintenance
+ * API. If the version already exists in the record, it is
+ * replaced with the new one.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang,
+ uint16_t char_enc, uint16_t base_id) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint8_t* p;
+ bool result;
+ uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+
+ p = p_buff;
+
+ /* First, build the language base descriptor list. This consists of a data */
+ /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, lang);
+
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, char_enc);
+
+ UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, base_id);
+
+ result =
+ SDP_AddAttribute(handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_AddServiceClassIdList
+ *
+ * Description This function is called to add a service list to a record.
+ * This would be through the SDP database maintenance API.
+ * If the service list already exists in the record, it is
+ * replaced with the new list.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services,
+ uint16_t* p_service_uuids) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx;
+ uint8_t* p;
+ bool result;
+ uint8_t* p_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2);
+
+ p = p_buff;
+
+ for (xx = 0; xx < num_services; xx++, p_service_uuids++) {
+ UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p, *p_service_uuids);
+ }
+
+ result =
+ SDP_AddAttribute(handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
+ DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff);
+ osi_free(p_buff);
+ return result;
+#else /* SDP_SERVER_ENABLED == FALSE */
+ return (false);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_DeleteAttribute
+ *
+ * Description This function is called to delete an attribute from a
+ * record. This would be through the SDP database maintenance
+ * API.
+ *
+ * Returns true if deleted OK, else false if not found
+ *
+ ******************************************************************************/
+bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t xx, yy;
+ tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0];
+ uint8_t* pad_ptr;
+ uint32_t len; /* Number of bytes in the entry */
+
+ /* Find the record in the database */
+ for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) {
+ if (p_rec->record_handle == handle) {
+ tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0];
+
+ SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
+ /* Found it. Now, find the attribute */
+ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) {
+ if (p_attr->id == attr_id) {
+ pad_ptr = p_attr->value_ptr;
+ len = p_attr->len;
+
+ if (len) {
+ for (yy = 0; yy < p_rec->num_attributes; yy++) {
+ if (p_rec->attribute[yy].value_ptr > pad_ptr)
+ p_rec->attribute[yy].value_ptr -= len;
+ }
+ }
+
+ /* Found it. Shift everything up one */
+ p_rec->num_attributes--;
+
+ for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++) {
+ *p_attr = *(p_attr + 1);
+ }
+
+ /* adjust attribute values if needed */
+ if (len) {
+ xx =
+ (p_rec->free_pad_ptr - ((pad_ptr + len) - &p_rec->attr_pad[0]));
+ for (yy = 0; yy < xx; yy++, pad_ptr++) *pad_ptr = *(pad_ptr + len);
+ p_rec->free_pad_ptr -= len;
+ }
+ return (true);
+ }
+ }
+ }
+ }
+#endif
+ /* If here, not found */
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function SDP_ReadRecord
+ *
+ * Description This function is called to get the raw data of the record
+ * with the given handle from the database.
+ *
+ * Returns -1, if the record is not found.
+ * Otherwise, the offset (0 or 1) to start of data in p_data.
+ *
+ * The size of data copied into p_data is in *p_data_len.
+ *
+ ******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+int32_t SDP_ReadRecord(uint32_t handle, uint8_t* p_data, int32_t* p_data_len) {
+ int32_t len = 0; /* Number of bytes in the entry */
+ int32_t offset = -1; /* default to not found */
+#if (SDP_SERVER_ENABLED == TRUE)
+ tSDP_RECORD* p_rec;
+ uint16_t start = 0;
+ uint16_t end = 0xffff;
+ tSDP_ATTRIBUTE* p_attr;
+ uint16_t rem_len;
+ uint8_t* p_rsp;
+
+ /* Find the record in the database */
+ p_rec = sdp_db_find_record(handle);
+ if (p_rec && p_data && p_data_len) {
+ p_rsp = &p_data[3];
+ while ((p_attr = sdp_db_find_attr_in_rec(p_rec, start, end)) != NULL) {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = *p_data_len - (uint16_t)(p_rsp - p_data);
+
+ if (p_attr->len > (uint32_t)(rem_len - 6)) break;
+
+ p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
+
+ /* next attr id */
+ start = p_attr->id + 1;
+ }
+ len = (int32_t)(p_rsp - p_data);
+
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (len > 255) {
+ offset = 0;
+ p_data[0] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_data[1] = (uint8_t)((len - 3) >> 8);
+ p_data[2] = (uint8_t)(len - 3);
+ } else {
+ offset = 1;
+
+ p_data[1] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_data[2] = (uint8_t)(len - 3);
+
+ len--;
+ }
+ *p_data_len = len;
+ }
+#endif
+ /* If here, not found */
+ return (offset);
+}
+#endif
diff --git a/mtkbt/code/bt/stack/sdp/sdp_discovery.cc b/mtkbt/code/bt/stack/sdp/sdp_discovery.cc
new file mode 100755
index 0000000..a410f87
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_discovery.cc
@@ -0,0 +1,974 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * this file contains SDP discovery functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "btm_api.h"
+#include "btu.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#ifndef SDP_DEBUG_RAW
+#define SDP_DEBUG_RAW false
+#endif
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply);
+static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply);
+static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply);
+static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end);
+static tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db, BD_ADDR p_bda);
+static uint8_t* add_attr(uint8_t* p, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_rec, uint16_t attr_id,
+ tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level);
+
+/* Safety check in case we go crazy */
+#define MAX_NEST_LEVELS 5
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/*******************************************************************************
+ *
+ * Function sdpu_build_uuid_seq
+ *
+ * Description This function builds a UUID sequence from the list of
+ * passed UUIDs. It is also passed the address of the output
+ * buffer.
+ *
+ * Returns Pointer to next byte in the output buffer.
+ *
+ ******************************************************************************/
+static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids,
+ tSDP_UUID* p_uuid_list) {
+ uint16_t xx;
+ uint8_t* p_len;
+
+ /* First thing is the data element header */
+ UINT8_TO_BE_STREAM(p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+
+ /* Remember where the length goes. Leave space for it. */
+ p_len = p_out;
+ p_out += 1;
+
+ /* Now, loop through and put in all the UUID(s) */
+ for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) {
+ if (p_uuid_list->len == 2) {
+ UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid16);
+ } else if (p_uuid_list->len == 4) {
+ UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+ UINT32_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid32);
+ } else {
+ UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
+ ARRAY_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
+ }
+ }
+
+ /* Now, put in the length */
+ xx = (uint16_t)(p_out - p_len - 1);
+ UINT8_TO_BE_STREAM(p_len, xx);
+
+ return (p_out);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_snd_service_search_req
+ *
+ * Description Send a service search request to the SDP server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_snd_service_search_req(tCONN_CB* p_ccb, uint8_t cont_len,
+ uint8_t* p_cont) {
+ uint8_t *p, *p_start, *p_param_len;
+ BT_HDR* p_cmd = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ uint16_t param_len;
+
+ /* Prepare the buffer for sending the packet to L2CAP */
+ p_cmd->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_cmd + 1) + L2CAP_MIN_OFFSET;
+
+ /* Build a service search request packet */
+ UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_REQ);
+ UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+/* Build the UID sequence. */
+#if (SDP_BROWSE_PLUS == TRUE)
+ p = sdpu_build_uuid_seq(p, 1,
+ &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+ p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters,
+ p_ccb->p_db->uuid_filters);
+#endif
+
+ /* Set max service record count */
+ UINT16_TO_BE_STREAM(p, sdp_cb.max_recs_per_search);
+
+ /* Set continuation state */
+ UINT8_TO_BE_STREAM(p, cont_len);
+
+ /* if this is not the first request */
+ if (cont_len && p_cont) {
+ memcpy(p, p_cont, cont_len);
+ p += cont_len;
+ }
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = (uint16_t)(p - p_param_len - 2);
+ UINT16_TO_BE_STREAM(p_param_len, param_len);
+
+ p_ccb->disc_state = SDP_DISC_WAIT_HANDLES;
+
+ /* Set the length of the SDP data in the buffer */
+ p_cmd->len = (uint16_t)(p - p_start);
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d",
+ cont_len, p_ccb->disc_state);
+#endif
+
+ L2CA_DataWrite(p_ccb->connection_id, p_cmd);
+
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_disc_connected
+ *
+ * Description This function is called when an SDP discovery attempt is
+ * connected.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_disc_connected(tCONN_CB* p_ccb) {
+ if (p_ccb->is_attr_search) {
+ p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
+
+ process_service_search_attr_rsp(p_ccb, NULL);
+ } else {
+ /* First step is to get a list of the handles from the server. */
+ /* We are not searching for a specific attribute, so we will */
+ /* first search for the service, then get all attributes of it */
+
+ p_ccb->num_handles = 0;
+ sdp_snd_service_search_req(p_ccb, 0, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_disc_server_rsp
+ *
+ * Description This function is called when there is a response from
+ * the server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg) {
+ uint8_t *p, rsp_pdu;
+ bool invalid_pdu = true;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state);
+#endif
+
+ /* stop inactivity timer when we receive a response */
+ alarm_cancel(p_ccb->sdp_conn_timer);
+
+ /* Got a reply!! Check what we got back */
+ p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+
+ BE_STREAM_TO_UINT8(rsp_pdu, p);
+
+ p_msg->len--;
+
+ switch (rsp_pdu) {
+ case SDP_PDU_SERVICE_SEARCH_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) {
+ process_service_search_rsp(p_ccb, p);
+ invalid_pdu = false;
+ }
+ break;
+
+ case SDP_PDU_SERVICE_ATTR_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) {
+ process_service_attr_rsp(p_ccb, p);
+ invalid_pdu = false;
+ }
+ break;
+
+ case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
+ if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) {
+ process_service_search_attr_rsp(p_ccb, p);
+ invalid_pdu = false;
+ }
+ break;
+ }
+
+ if (invalid_pdu) {
+ SDP_TRACE_WARNING("SDP - Unexp. PDU: %d in state: %d", rsp_pdu,
+ p_ccb->disc_state);
+ sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
+ }
+}
+
+/******************************************************************************
+ *
+ * Function process_service_search_rsp
+ *
+ * Description This function is called when there is a search response from
+ * the server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) {
+ uint16_t xx;
+ uint16_t total, cur_handles, orig;
+ uint8_t cont_len;
+
+ /* Skip transaction, and param len */
+ p_reply += 4;
+ BE_STREAM_TO_UINT16(total, p_reply);
+ BE_STREAM_TO_UINT16(cur_handles, p_reply);
+
+ orig = p_ccb->num_handles;
+ p_ccb->num_handles += cur_handles;
+ if (p_ccb->num_handles == 0) {
+ SDP_TRACE_WARNING("SDP - Rcvd ServiceSearchRsp, no matches");
+ sdp_disconnect(p_ccb, SDP_NO_RECS_MATCH);
+ return;
+ }
+
+ /* Save the handles that match. We will can only process a certain number. */
+ if (total > sdp_cb.max_recs_per_search) total = sdp_cb.max_recs_per_search;
+ if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
+ p_ccb->num_handles = sdp_cb.max_recs_per_search;
+
+ for (xx = orig; xx < p_ccb->num_handles; xx++)
+ BE_STREAM_TO_UINT32(p_ccb->handles[xx], p_reply);
+
+ BE_STREAM_TO_UINT8(cont_len, p_reply);
+ if (cont_len != 0) {
+ if (cont_len > SDP_MAX_CONTINUATION_LEN) {
+ sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+ /* stay in the same state */
+ sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
+ } else {
+ /* change state */
+ p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
+
+ /* Kick off the first attribute request */
+ process_service_attr_rsp(p_ccb, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_copy_raw_data
+ *
+ * Description copy the raw data
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+static void sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) {
+ unsigned int cpy_len;
+ uint32_t list_len;
+ uint8_t* p;
+ uint8_t type;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT];
+ uint32_t i;
+
+ for (i = 0; i < p_ccb->list_len; i++) {
+ snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X",
+ (uint8_t)(p_ccb->rsp_list[i]));
+ }
+ SDP_TRACE_WARNING("result :%s", num_array);
+#endif
+
+ if (p_ccb->p_db->raw_data) {
+ cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
+ list_len = p_ccb->list_len;
+ p = &p_ccb->rsp_list[0];
+
+ if (offset) {
+ type = *p++;
+ p = sdpu_get_len_from_type(p, type, &list_len);
+ }
+ /** M: cpy_len should be list_len evenif list_len is 0 @{ */
+ if (list_len < cpy_len) {
+ /** @} */
+ cpy_len = list_len;
+ }
+ SDP_TRACE_WARNING(
+ "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
+ "raw_used:%d raw_data:%p",
+ __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db,
+ p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data);
+ memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
+ p_ccb->p_db->raw_used += cpy_len;
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function process_service_attr_rsp
+ *
+ * Description This function is called when there is a attribute response
+ * from the server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) {
+ uint8_t *p_start, *p_param_len;
+ uint16_t param_len, list_byte_count;
+ bool cont_request_needed = false;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d",
+ SDP_RAW_DATA_INCLUDED);
+#endif
+ /* If p_reply is NULL, we were called after the records handles were read */
+ if (p_reply) {
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1],
+ p_reply[2], p_reply[3]);
+#endif
+ /* Skip transaction ID and length */
+ p_reply += 4;
+
+ BE_STREAM_TO_UINT16(list_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count);
+#endif
+
+ /* Copy the response to the scratchpad. First, a safety check on the length
+ */
+ if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT) {
+ sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
+ return;
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len,
+ list_byte_count);
+#endif
+ if (p_ccb->rsp_list == NULL)
+ p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
+ memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
+ p_ccb->list_len += list_byte_count;
+ p_reply += list_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len);
+
+ /* Check if we need to request a continuation */
+ SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+ if (*p_reply) {
+ if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
+ sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+ cont_request_needed = true;
+ } else {
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ SDP_TRACE_WARNING("process_service_attr_rsp");
+ sdp_copy_raw_data(p_ccb, false);
+#endif
+
+ /* Save the response in the database. Stop on any error */
+ if (!save_attr_seq(p_ccb, &p_ccb->rsp_list[0],
+ &p_ccb->rsp_list[p_ccb->list_len])) {
+ sdp_disconnect(p_ccb, SDP_DB_FULL);
+ return;
+ }
+ p_ccb->list_len = 0;
+ p_ccb->cur_handle++;
+ }
+ }
+
+ /* Now, ask for the next handle. Re-use the buffer we just got. */
+ if (p_ccb->cur_handle < p_ccb->num_handles) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ uint8_t* p;
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ /* Get all the attributes from the server */
+ UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_ATTR_REQ);
+ UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+ UINT32_TO_BE_STREAM(p, p_ccb->handles[p_ccb->cur_handle]);
+
+ /* Max attribute byte count */
+ UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size);
+
+ /* If no attribute filters, build a wildcard attribute sequence */
+ if (p_ccb->p_db->num_attr_filters)
+ p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters,
+ p_ccb->p_db->num_attr_filters);
+ else
+ p = sdpu_build_attrib_seq(p, NULL, 0);
+
+ /* Was this a continuation request ? */
+ if (cont_request_needed) {
+ memcpy(p, p_reply, *p_reply + 1);
+ p += *p_reply + 1;
+ } else
+ UINT8_TO_BE_STREAM(p, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = (uint16_t)(p - p_param_len - 2);
+ UINT16_TO_BE_STREAM(p_param_len, param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_msg->len = (uint16_t)(p - p_start);
+
+ L2CA_DataWrite(p_ccb->connection_id, p_msg);
+
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+ } else {
+ sdp_disconnect(p_ccb, SDP_SUCCESS);
+ return;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function process_service_search_attr_rsp
+ *
+ * Description This function is called when there is a search attribute
+ * response from the server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) {
+ uint8_t *p, *p_start, *p_end, *p_param_len;
+ uint8_t type;
+ uint32_t seq_len;
+ uint16_t param_len, lists_byte_count = 0;
+ bool cont_request_needed = false;
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("process_service_search_attr_rsp");
+#endif
+ /* If p_reply is NULL, we were called for the initial read */
+ if (p_reply) {
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1],
+ p_reply[2], p_reply[3]);
+#endif
+ /* Skip transaction ID and length */
+ p_reply += 4;
+
+ BE_STREAM_TO_UINT16(lists_byte_count, p_reply);
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count);
+#endif
+
+ /* Copy the response to the scratchpad. First, a safety check on the length
+ */
+ if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT) {
+ sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
+ return;
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len,
+ lists_byte_count);
+#endif
+ if (p_ccb->rsp_list == NULL)
+ p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
+ memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
+ p_ccb->list_len += lists_byte_count;
+ p_reply += lists_byte_count;
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len);
+
+ /* Check if we need to request a continuation */
+ SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
+#endif
+ if (*p_reply) {
+ if (*p_reply > SDP_MAX_CONTINUATION_LEN) {
+ sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+
+ cont_request_needed = true;
+ }
+ }
+
+#if (SDP_DEBUG_RAW == TRUE)
+ SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed);
+#endif
+ /* If continuation request (or first time request) */
+ if ((cont_request_needed) || (!p_reply)) {
+ BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ uint8_t* p;
+
+ p_msg->offset = L2CAP_MIN_OFFSET;
+ p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET;
+
+ /* Build a service search request packet */
+ UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ);
+ UINT16_TO_BE_STREAM(p, p_ccb->transaction_id);
+ p_ccb->transaction_id++;
+
+ /* Skip the length, we need to add it at the end */
+ p_param_len = p;
+ p += 2;
+
+/* Build the UID sequence. */
+#if (SDP_BROWSE_PLUS == TRUE)
+ p = sdpu_build_uuid_seq(p, 1,
+ &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
+#else
+ p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters,
+ p_ccb->p_db->uuid_filters);
+#endif
+
+ /* Max attribute byte count */
+ UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size);
+
+ /* If no attribute filters, build a wildcard attribute sequence */
+ if (p_ccb->p_db->num_attr_filters)
+ p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters,
+ p_ccb->p_db->num_attr_filters);
+ else
+ p = sdpu_build_attrib_seq(p, NULL, 0);
+
+ /* No continuation for first request */
+ if (p_reply) {
+ memcpy(p, p_reply, *p_reply + 1);
+ p += *p_reply + 1;
+ } else
+ UINT8_TO_BE_STREAM(p, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ param_len = p - p_param_len - 2;
+ UINT16_TO_BE_STREAM(p_param_len, param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_msg->len = p - p_start;
+
+ L2CA_DataWrite(p_ccb->connection_id, p_msg);
+
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+
+ return;
+ }
+
+/*******************************************************************/
+/* We now have the full response, which is a sequence of sequences */
+/*******************************************************************/
+
+#if (SDP_RAW_DATA_INCLUDED == TRUE)
+ SDP_TRACE_WARNING("process_service_search_attr_rsp");
+ sdp_copy_raw_data(p_ccb, true);
+#endif
+
+ p = &p_ccb->rsp_list[0];
+
+ /* The contents is a sequence of attribute sequences */
+ type = *p++;
+
+ if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) {
+ SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type);
+ return;
+ }
+ p = sdpu_get_len_from_type(p, type, &seq_len);
+
+ p_end = &p_ccb->rsp_list[p_ccb->list_len];
+
+ if ((p + seq_len) != p_end) {
+ sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE);
+ return;
+ }
+
+ while (p < p_end) {
+ p = save_attr_seq(p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]);
+ if (!p) {
+ sdp_disconnect(p_ccb, SDP_DB_FULL);
+ return;
+ }
+ }
+
+ /* Since we got everything we need, disconnect the call */
+ sdp_disconnect(p_ccb, SDP_SUCCESS);
+}
+
+/*******************************************************************************
+ *
+ * Function save_attr_seq
+ *
+ * Description This function is called when there is a response from
+ * the server.
+ *
+ * Returns pointer to next byte or NULL if error
+ *
+ ******************************************************************************/
+static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) {
+ uint32_t seq_len, attr_len;
+ uint16_t attr_id;
+ uint8_t type, *p_seq_end;
+ tSDP_DISC_REC* p_rec;
+
+ type = *p++;
+
+ if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) {
+ SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type);
+ return (NULL);
+ }
+
+ p = sdpu_get_len_from_type(p, type, &seq_len);
+ if ((p + seq_len) > p_msg_end) {
+ SDP_TRACE_WARNING("SDP - Bad len in attr_rsp %d", seq_len);
+ return (NULL);
+ }
+
+ /* Create a record */
+ p_rec = add_record(p_ccb->p_db, p_ccb->device_address);
+ if (!p_rec) {
+ SDP_TRACE_WARNING("SDP - DB full add_record");
+ return (NULL);
+ }
+
+ p_seq_end = p + seq_len;
+
+ while (p < p_seq_end) {
+ /* First get the attribute ID */
+ type = *p++;
+ p = sdpu_get_len_from_type(p, type, &attr_len);
+ if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) {
+ SDP_TRACE_WARNING("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type,
+ attr_len);
+ return (NULL);
+ }
+ BE_STREAM_TO_UINT16(attr_id, p);
+
+ /* Now, add the attribute value */
+ p = add_attr(p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
+
+ if (!p) {
+ SDP_TRACE_WARNING("SDP - DB full add_attr");
+ return (NULL);
+ }
+ }
+
+ return (p);
+}
+
+/*******************************************************************************
+ *
+ * Function add_record
+ *
+ * Description This function allocates space for a record from the DB.
+ *
+ * Returns pointer to next byte in data stream
+ *
+ ******************************************************************************/
+tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db, BD_ADDR p_bda) {
+ tSDP_DISC_REC* p_rec;
+
+ /* See if there is enough space in the database */
+ if (p_db->mem_free < sizeof(tSDP_DISC_REC)) return (NULL);
+
+ p_rec = (tSDP_DISC_REC*)p_db->p_free_mem;
+ p_db->p_free_mem += sizeof(tSDP_DISC_REC);
+ p_db->mem_free -= sizeof(tSDP_DISC_REC);
+
+ p_rec->p_first_attr = NULL;
+ p_rec->p_next_rec = NULL;
+
+ memcpy(p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN);
+
+ /* Add the record to the end of chain */
+ if (!p_db->p_first_rec)
+ p_db->p_first_rec = p_rec;
+ else {
+ tSDP_DISC_REC* p_rec1 = p_db->p_first_rec;
+
+ while (p_rec1->p_next_rec) p_rec1 = p_rec1->p_next_rec;
+
+ p_rec1->p_next_rec = p_rec;
+ }
+
+ return (p_rec);
+}
+
+#define SDP_ADDITIONAL_LIST_MASK 0x80
+/*******************************************************************************
+ *
+ * Function add_attr
+ *
+ * Description This function allocates space for an attribute from the DB
+ * and copies the data into it.
+ *
+ * Returns pointer to next byte in data stream
+ *
+ ******************************************************************************/
+static uint8_t* add_attr(uint8_t* p, tSDP_DISCOVERY_DB* p_db,
+ tSDP_DISC_REC* p_rec, uint16_t attr_id,
+ tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level) {
+ tSDP_DISC_ATTR* p_attr;
+ uint32_t attr_len;
+ uint32_t total_len;
+ uint16_t attr_type;
+ uint16_t id;
+ uint8_t type;
+ uint8_t* p_end;
+ uint8_t is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
+
+ nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
+
+ type = *p++;
+ p = sdpu_get_len_from_type(p, type, &attr_len);
+
+ attr_len &= SDP_DISC_ATTR_LEN_MASK;
+ attr_type = (type >> 3) & 0x0f;
+
+ /* See if there is enough space in the database */
+ if (attr_len > 4)
+ total_len = attr_len - 4 + (uint16_t)sizeof(tSDP_DISC_ATTR);
+ else
+ total_len = sizeof(tSDP_DISC_ATTR);
+
+ /* Ensure it is a multiple of 4 */
+ total_len = (total_len + 3) & ~3;
+
+ /* See if there is enough space in the database */
+ if (p_db->mem_free < total_len) return (NULL);
+
+ p_attr = (tSDP_DISC_ATTR*)p_db->p_free_mem;
+ p_attr->attr_id = attr_id;
+ p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
+ p_attr->p_next_attr = NULL;
+
+ /* Store the attribute value */
+ switch (attr_type) {
+ case UINT_DESC_TYPE:
+ if ((is_additional_list != 0) && (attr_len == 2)) {
+ BE_STREAM_TO_UINT16(id, p);
+ if (id != ATTR_ID_PROTOCOL_DESC_LIST)
+ p -= 2;
+ else {
+ /* Reserve the memory for the attribute now, as we need to add
+ * sub-attributes */
+ p_db->p_free_mem += sizeof(tSDP_DISC_ATTR);
+ p_db->mem_free -= sizeof(tSDP_DISC_ATTR);
+ p_end = p + attr_len;
+ total_len = 0;
+
+ /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
+ if (nest_level >= MAX_NEST_LEVELS) {
+ SDP_TRACE_ERROR("SDP - attr nesting too deep");
+ return (p_end);
+ }
+
+ /* Now, add the list entry */
+ p = add_attr(p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr,
+ (uint8_t)(nest_level + 1));
+
+ break;
+ }
+ }
+ /* Case falls through */
+
+ case TWO_COMP_INT_DESC_TYPE:
+ switch (attr_len) {
+ case 1:
+ p_attr->attr_value.v.u8 = *p++;
+ break;
+ case 2:
+ BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
+ break;
+ case 4:
+ BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
+ break;
+ default:
+ BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len);
+ break;
+ }
+ break;
+
+ case UUID_DESC_TYPE:
+ switch (attr_len) {
+ case 2:
+ BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
+ break;
+ case 4:
+ BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
+ if (p_attr->attr_value.v.u32 < 0x10000) {
+ attr_len = 2;
+ p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12);
+ p_attr->attr_value.v.u16 = (uint16_t)p_attr->attr_value.v.u32;
+ }
+ break;
+ case 16:
+ /* See if we can compress his UUID down to 16 or 32bit UUIDs */
+ if (sdpu_is_base_uuid(p)) {
+ if ((p[0] == 0) && (p[1] == 0)) {
+ p_attr->attr_len_type =
+ (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
+ p += 2;
+ BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p);
+ p += MAX_UUID_SIZE - 4;
+ } else {
+ p_attr->attr_len_type =
+ (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
+ BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p);
+ p += MAX_UUID_SIZE - 4;
+ }
+ } else {
+ BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array,
+ (int32_t)attr_len);
+ }
+ break;
+ default:
+ SDP_TRACE_WARNING("SDP - bad len in UUID attr: %d", attr_len);
+ return (p + attr_len);
+ }
+ break;
+
+ case DATA_ELE_SEQ_DESC_TYPE:
+ case DATA_ELE_ALT_DESC_TYPE:
+ /* Reserve the memory for the attribute now, as we need to add
+ * sub-attributes */
+ p_db->p_free_mem += sizeof(tSDP_DISC_ATTR);
+ p_db->mem_free -= sizeof(tSDP_DISC_ATTR);
+ p_end = p + attr_len;
+ total_len = 0;
+
+ /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */
+ if (nest_level >= MAX_NEST_LEVELS) {
+ SDP_TRACE_ERROR("SDP - attr nesting too deep");
+ return (p_end);
+ }
+ if (is_additional_list != 0 ||
+ attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
+ nest_level |= SDP_ADDITIONAL_LIST_MASK;
+ /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
+
+ while (p < p_end) {
+ /* Now, add the list entry */
+ p = add_attr(p, p_db, p_rec, 0, p_attr, (uint8_t)(nest_level + 1));
+
+ if (!p) return (NULL);
+ }
+ break;
+
+ case TEXT_STR_DESC_TYPE:
+ case URL_DESC_TYPE:
+ BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len);
+ break;
+
+ case BOOLEAN_DESC_TYPE:
+ switch (attr_len) {
+ case 1:
+ p_attr->attr_value.v.u8 = *p++;
+ break;
+ default:
+ SDP_TRACE_WARNING("SDP - bad len in boolean attr: %d", attr_len);
+ return (p + attr_len);
+ }
+ break;
+
+ default: /* switch (attr_type) */
+ break;
+ }
+
+ p_db->p_free_mem += total_len;
+ p_db->mem_free -= total_len;
+
+ /* Add the attribute to the end of the chain */
+ if (!p_parent_attr) {
+ if (!p_rec->p_first_attr)
+ p_rec->p_first_attr = p_attr;
+ else {
+ tSDP_DISC_ATTR* p_attr1 = p_rec->p_first_attr;
+
+ while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr;
+
+ p_attr1->p_next_attr = p_attr;
+ }
+ } else {
+ if (!p_parent_attr->attr_value.v.p_sub_attr) {
+ p_parent_attr->attr_value.v.p_sub_attr = p_attr;
+ /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)",
+ p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */
+ } else {
+ tSDP_DISC_ATTR* p_attr1 = p_parent_attr->attr_value.v.p_sub_attr;
+ /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)",
+ p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */
+
+ while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr;
+
+ p_attr1->p_next_attr = p_attr;
+ /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */
+ }
+ }
+
+ return (p);
+}
diff --git a/mtkbt/code/bt/stack/sdp/sdp_main.cc b/mtkbt/code/bt/stack/sdp/sdp_main.cc
new file mode 100755
index 0000000..0cb4481
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_main.cc
@@ -0,0 +1,677 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the main SDP functions
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "hcidefs.h"
+#include "hcimsgs.h"
+
+#include "l2c_api.h"
+#include "l2cdefs.h"
+#include "osi/include/osi.h"
+
+#include "btm_api.h"
+#include "btu.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/******************************************************************************/
+/* G L O B A L S D P D A T A */
+/******************************************************************************/
+tSDP_CB sdp_cb;
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void sdp_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ UNUSED_ATTR uint16_t psm, uint8_t l2cap_id);
+static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void sdp_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
+static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
+static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
+
+static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result);
+static void sdp_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
+
+/*******************************************************************************
+ *
+ * Function sdp_init
+ *
+ * Description This function initializes the SDP unit.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_init(void) {
+ /* Clears all structures and local SDP database (if Server is enabled) */
+ memset(&sdp_cb, 0, sizeof(tSDP_CB));
+
+ /* Initialize the L2CAP configuration. We only care about MTU and flush */
+ sdp_cb.l2cap_my_cfg.mtu_present = true;
+ sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
+ sdp_cb.l2cap_my_cfg.flush_to_present = true;
+ sdp_cb.l2cap_my_cfg.flush_to = SDP_FLUSH_TO;
+
+ sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
+ sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
+
+#if (SDP_SERVER_ENABLED == TRUE)
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel(false, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) {
+ SDP_TRACE_ERROR("Security Registration Server failed");
+ return;
+ }
+#endif
+
+ /* Register with Security Manager for the specific security level */
+ if (!BTM_SetSecurityLevel(true, SDP_SERVICE_NAME, BTM_SEC_SERVICE_SDP_SERVER,
+ SDP_SECURITY_LEVEL, SDP_PSM, 0, 0)) {
+ SDP_TRACE_ERROR("Security Registration for Client failed");
+ return;
+ }
+
+#if defined(SDP_INITIAL_TRACE_LEVEL)
+ sdp_cb.trace_level = SDP_INITIAL_TRACE_LEVEL;
+#else
+ sdp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+
+ sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind;
+ sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm;
+ sdp_cb.reg_info.pL2CA_ConnectPnd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind;
+ sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm;
+ sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind;
+ sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm;
+ sdp_cb.reg_info.pL2CA_QoSViolationInd_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
+ sdp_cb.reg_info.pL2CA_CongestionStatus_Cb = NULL;
+ sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
+
+ /* Now, register with L2CAP */
+ if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info)) {
+ SDP_TRACE_ERROR("SDP Registration failed");
+ }
+}
+
+#if (SDP_DEBUG == TRUE)
+/*******************************************************************************
+ *
+ * Function sdp_set_max_attr_list_size
+ *
+ * Description This function sets the max attribute list size to use
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint16_t sdp_set_max_attr_list_size(uint16_t max_size) {
+ if (max_size > (sdp_cb.l2cap_my_cfg.mtu - 16))
+ max_size = sdp_cb.l2cap_my_cfg.mtu - 16;
+
+ sdp_cb.max_attr_list_size = max_size;
+
+ return sdp_cb.max_attr_list_size;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * Function sdp_connect_ind
+ *
+ * Description This function handles an inbound connection indication
+ * from L2CAP. This is the case where we are acting as a
+ * server.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid,
+ UNUSED_ATTR uint16_t psm, uint8_t l2cap_id) {
+#if (SDP_SERVER_ENABLED == TRUE)
+ tCONN_CB* p_ccb;
+
+ /* Allocate a new CCB. Return if none available. */
+ p_ccb = sdpu_allocate_ccb();
+ if (p_ccb == NULL) return;
+
+ /* Transition to the next appropriate state, waiting for config setup. */
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy(&p_ccb->device_address[0], bd_addr, sizeof(BD_ADDR));
+ p_ccb->connection_id = l2cap_cid;
+
+ /* Send response to the L2CAP layer. */
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
+ {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present) {
+ SDP_TRACE_DEBUG(
+ "sdp_connect_ind: mode %u, txwinsz %u, max_trans %u, rtrans_tout "
+ "%u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout, cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq(l2cap_cid, &cfg)) && cfg.fcr_present &&
+ cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ cfg.fcr_present = false;
+ L2CA_ConfigReq(l2cap_cid, &cfg);
+ }
+ }
+
+ SDP_TRACE_EVENT("SDP - Rcvd L2CAP conn ind, sent config req, CID 0x%x",
+ p_ccb->connection_id);
+#else /* No server */
+ /* Reject the connection */
+ L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_PSM, 0);
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_connect_cfm
+ *
+ * Description This function handles the connect confirm events
+ * from L2CAP. This is the case when we are acting as a
+ * client and have sent a connect request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
+ tCONN_CB* p_ccb;
+ tL2CAP_CFG_INFO cfg;
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* If the connection response contains success status, then */
+ /* Transition to the next state and startup the timer. */
+ if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP)) {
+ p_ccb->con_state = SDP_STATE_CFG_SETUP;
+
+ cfg = sdp_cb.l2cap_my_cfg;
+
+ if (cfg.fcr_present) {
+ SDP_TRACE_DEBUG(
+ "sdp_connect_cfm: mode %u, txwinsz %u, max_trans %u, rtrans_tout "
+ "%u, mon_tout %u, mps %u",
+ cfg.fcr.mode, cfg.fcr.tx_win_sz, cfg.fcr.max_transmit,
+ cfg.fcr.rtrans_tout, cfg.fcr.mon_tout, cfg.fcr.mps);
+ }
+
+ if ((!L2CA_ConfigReq(l2cap_cid, &cfg)) && cfg.fcr_present &&
+ cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ /* FCR not desired; try again in basic mode */
+ cfg.fcr_present = false;
+ cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ L2CA_ConfigReq(l2cap_cid, &cfg);
+ }
+
+ SDP_TRACE_EVENT("SDP - got conn cnf, sent cfg req, CID: 0x%x",
+ p_ccb->connection_id);
+ } else {
+ SDP_TRACE_WARNING("SDP - Rcvd conn cnf with error: 0x%x CID 0x%x", result,
+ p_ccb->connection_id);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb || p_ccb->p_cb2) {
+ uint16_t err = -1;
+ if ((result == HCI_ERR_HOST_REJECT_SECURITY) ||
+ (result == HCI_ERR_AUTH_FAILURE) ||
+ (result == HCI_ERR_PAIRING_NOT_ALLOWED) ||
+ (result == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
+ (result == HCI_ERR_KEY_MISSING))
+ err = SDP_SECURITY_ERR;
+ else if (result == HCI_ERR_HOST_REJECT_DEVICE)
+ err = SDP_CONN_REJECTED;
+ else
+ err = SDP_CONN_FAILED;
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb)(err);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(err, p_ccb->user_data);
+ }
+ sdpu_release_ccb(p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_config_ind
+ *
+ * Description This function processes the L2CAP configuration indication
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tCONN_CB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* Remember the remote MTU size */
+ if (!p_cfg->mtu_present) {
+ /* use min(L2CAP_DEFAULT_MTU,SDP_MTU_SIZE) for GKI buffer size reasons */
+ p_ccb->rem_mtu_size =
+ (L2CAP_DEFAULT_MTU > SDP_MTU_SIZE) ? SDP_MTU_SIZE : L2CAP_DEFAULT_MTU;
+ } else {
+ if (p_cfg->mtu > SDP_MTU_SIZE)
+ p_ccb->rem_mtu_size = SDP_MTU_SIZE;
+ else
+ p_ccb->rem_mtu_size = p_cfg->mtu;
+ }
+
+ /* For now, always accept configuration from the other side */
+ p_cfg->flush_to_present = false;
+ p_cfg->mtu_present = false;
+ p_cfg->result = L2CAP_CFG_OK;
+
+ /* Check peer config request against our rfcomm configuration */
+ if (p_cfg->fcr_present) {
+ /* Reject the window size if it is bigger than we want it to be */
+ if (p_cfg->fcr.mode != L2CAP_FCR_BASIC_MODE) {
+ if (sdp_cb.l2cap_my_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE &&
+ p_cfg->fcr.tx_win_sz > sdp_cb.l2cap_my_cfg.fcr.tx_win_sz) {
+ p_cfg->fcr.tx_win_sz = sdp_cb.l2cap_my_cfg.fcr.tx_win_sz;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG(
+ "sdp_config_ind(CONFIG) -> Please try again with SMALLER TX "
+ "WINDOW");
+ }
+
+ /* Reject if locally we want basic and they don't */
+ if (sdp_cb.l2cap_my_cfg.fcr.mode == L2CAP_FCR_BASIC_MODE) {
+ /* Ask for a new setup */
+ p_cfg->fcr.mode = L2CAP_FCR_BASIC_MODE;
+ p_cfg->result = L2CAP_CFG_UNACCEPTABLE_PARAMS;
+ SDP_TRACE_DEBUG(
+ "sdp_config_ind(CONFIG) -> Please try again with BASIC mode");
+ }
+ /* Remain in configure state and give the peer our desired configuration
+ */
+ if (p_cfg->result != L2CAP_CFG_OK) {
+ SDP_TRACE_WARNING(
+ "SDP - Rcvd cfg ind, Unacceptable Parameters sent cfg cfm, CID: "
+ "0x%x",
+ l2cap_cid);
+ L2CA_ConfigRsp(l2cap_cid, p_cfg);
+ return;
+ }
+ } else /* We agree with peer's request */
+ p_cfg->fcr_present = false;
+ }
+
+ L2CA_ConfigRsp(l2cap_cid, p_cfg);
+
+ SDP_TRACE_EVENT("SDP - Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
+
+ p_ccb->con_flags |= SDP_FLAGS_HIS_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_MY_CFG_DONE) {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
+ sdp_disc_connected(p_ccb);
+ } else {
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_config_cfm
+ *
+ * Description This function processes the L2CAP configuration confirmation
+ * event.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
+ tCONN_CB* p_ccb;
+
+ SDP_TRACE_EVENT("SDP - Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid,
+ p_cfg->result);
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ /* For now, always accept configuration from the other side */
+ if (p_cfg->result == L2CAP_CFG_OK) {
+ p_ccb->con_flags |= SDP_FLAGS_MY_CFG_DONE;
+
+ if (p_ccb->con_flags & SDP_FLAGS_HIS_CFG_DONE) {
+ p_ccb->con_state = SDP_STATE_CONNECTED;
+
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) {
+ sdp_disc_connected(p_ccb);
+ } else {
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb,
+ btu_general_alarm_queue);
+ }
+ }
+ } else {
+ /* If peer has rejected FCR and suggested basic then try basic */
+ if (p_cfg->fcr_present) {
+ tL2CAP_CFG_INFO cfg = sdp_cb.l2cap_my_cfg;
+ cfg.fcr_present = false;
+ L2CA_ConfigReq(l2cap_cid, &cfg);
+
+ /* Remain in configure state */
+ return;
+ }
+
+ sdp_disconnect(p_ccb, SDP_CFG_FAILED);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_disconnect_ind
+ *
+ * Description This function handles a disconnect event from L2CAP. If
+ * requested to, we ack the disconnect before dropping the CCB
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
+ tCONN_CB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
+ return;
+ }
+
+ if (ack_needed) L2CA_DisconnectRsp(l2cap_cid);
+
+ SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb) {
+ /** M: fix unexcepted change of pairng addr @{ */
+ if((p_ccb->con_state == SDP_STATE_CONNECTED) &&
+ (p_ccb->disc_state != SDP_DISC_WAIT_SEARCH_ATTR) &&
+ (p_ccb->disc_state != SDP_DISC_WAIT_HANDLES))
+ (*p_ccb->p_cb) ((uint16_t) SDP_SUCCESS);
+ else
+ (*p_ccb->p_cb) ((uint16_t) SDP_CONN_FAILED);
+ /** @} */
+ }
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(
+ (uint16_t)((p_ccb->con_state == SDP_STATE_CONNECTED) ? SDP_SUCCESS
+ : SDP_CONN_FAILED),
+ p_ccb->user_data);
+
+ sdpu_release_ccb(p_ccb);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_data_ind
+ *
+ * Description This function is called when data is received from L2CAP.
+ * if we are the originator of the connection, we are the SDP
+ * client, and the received message is queued for the client.
+ *
+ * If we are the destination of the connection, we are the SDP
+ * server, so the message is passed to the server processing
+ * function.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
+ tCONN_CB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb != NULL) {
+ if (p_ccb->con_state == SDP_STATE_CONNECTED) {
+ if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG)
+ sdp_disc_server_rsp(p_ccb, p_msg);
+ else
+ sdp_server_handle_client_req(p_ccb, p_msg);
+ } else {
+ SDP_TRACE_WARNING(
+ "SDP - Ignored L2CAP data while in state: %d, CID: 0x%x",
+ p_ccb->con_state, l2cap_cid);
+ }
+ } else {
+ SDP_TRACE_WARNING("SDP - Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
+ }
+
+ osi_free(p_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_conn_originate
+ *
+ * Description This function is called from the API to originate a
+ * connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tCONN_CB* sdp_conn_originate(uint8_t* p_bd_addr) {
+ tCONN_CB* p_ccb;
+ uint16_t cid;
+
+ /* Allocate a new CCB. Return if none available. */
+ p_ccb = sdpu_allocate_ccb();
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - no spare CCB for orig");
+ return (NULL);
+ }
+
+ SDP_TRACE_EVENT("SDP - Originate started");
+
+ /* We are the originator of this connection */
+ p_ccb->con_flags |= SDP_FLAGS_IS_ORIG;
+
+ /* Save the BD Address and Channel ID. */
+ memcpy(&p_ccb->device_address[0], p_bd_addr, sizeof(BD_ADDR));
+
+ /* Transition to the next appropriate state, waiting for connection confirm.
+ */
+ p_ccb->con_state = SDP_STATE_CONN_SETUP;
+
+ cid = L2CA_ConnectReq(SDP_PSM, p_bd_addr);
+
+ /* Check if L2CAP started the connection process */
+ if (cid != 0) {
+ p_ccb->connection_id = cid;
+
+ return (p_ccb);
+ } else {
+ SDP_TRACE_WARNING("SDP - Originate failed");
+ sdpu_release_ccb(p_ccb);
+ return (NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_disconnect
+ *
+ * Description This function disconnects a connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason) {
+#if (SDP_BROWSE_PLUS == TRUE)
+
+ /* If we are browsing for multiple UUIDs ... */
+ if ((p_ccb->con_state == SDP_STATE_CONNECTED) &&
+ (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) &&
+ ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH))) {
+ /* If the browse found something, do no more searching */
+ if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec))
+ p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters;
+
+ while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters) {
+ /* Check we have not already found the UUID (maybe through browse) */
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2) &&
+ (SDP_FindServiceInDb(
+ p_ccb->p_db,
+ p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16, NULL)))
+ continue;
+
+ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2) &&
+ (SDP_FindServiceUUIDInDb(
+ p_ccb->p_db, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx],
+ NULL)))
+ continue;
+
+ p_ccb->cur_handle = 0;
+
+ SDP_TRACE_EVENT("SDP - looking for for more, CID: 0x%x",
+ p_ccb->connection_id);
+
+ sdp_disc_connected(p_ccb);
+ return;
+ }
+ }
+
+ if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec))
+ reason = SDP_SUCCESS;
+
+#endif
+
+ SDP_TRACE_EVENT("SDP - disconnect CID: 0x%x", p_ccb->connection_id);
+
+ /* Check if we have a connection ID */
+ if (p_ccb->connection_id != 0) {
+ L2CA_DisconnectReq(p_ccb->connection_id);
+ p_ccb->disconnect_reason = reason;
+ }
+
+ /* If at setup state, we may not get callback ind from L2CAP */
+ /* Call user callback immediately */
+ if (p_ccb->con_state == SDP_STATE_CONN_SETUP) {
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb)(reason);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(reason, p_ccb->user_data);
+
+ sdpu_release_ccb(p_ccb);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdp_disconnect_cfm
+ *
+ * Description This function handles a disconnect confirm event from L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void sdp_disconnect_cfm(uint16_t l2cap_cid,
+ UNUSED_ATTR uint16_t result) {
+ tCONN_CB* p_ccb;
+
+ /* Find CCB based on CID */
+ p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
+ if (p_ccb == NULL) {
+ SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x",
+ l2cap_cid);
+ return;
+ }
+
+ SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
+
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb)(p_ccb->disconnect_reason);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(p_ccb->disconnect_reason, p_ccb->user_data);
+
+ sdpu_release_ccb(p_ccb);
+}
+
+
+/*******************************************************************************
+ *
+ * Function sdp_conn_timer_timeout
+ *
+ * Description This function processes a timeout. Currently, we simply send
+ * a disconnect request to L2CAP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_conn_timer_timeout(void* data) {
+ tCONN_CB* p_ccb = (tCONN_CB*)data;
+
+ SDP_TRACE_EVENT("SDP - CCB timeout in state: %d CID: 0x%x", p_ccb->con_state,
+ p_ccb->connection_id);
+
+ L2CA_DisconnectReq(p_ccb->connection_id);
+ /* Tell the user if he has a callback */
+ if (p_ccb->p_cb)
+ (*p_ccb->p_cb)(SDP_CONN_FAILED);
+ else if (p_ccb->p_cb2)
+ (*p_ccb->p_cb2)(SDP_CONN_FAILED, p_ccb->user_data);
+ sdpu_release_ccb(p_ccb);
+}
diff --git a/mtkbt/code/bt/stack/sdp/sdp_server.cc b/mtkbt/code/bt/stack/sdp/sdp_server.cc
new file mode 100755
index 0000000..377506f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_server.cc
@@ -0,0 +1,871 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions that handle the SDP server functions.
+ * This is mainly dealing with client requests
+ *
+ ******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btu.h"
+
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+
+#include "osi/include/osi.h"
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+#include "mediatek/include/interop_mtk.h"
+#define MTK_HFP_VERSION_SDP_POSITION 7
+#define MTK_HFP_VERSION_OFFSET 5
+#define MTK_HFP_VERSION_16 0x06
+#endif
+
+#if (SDP_SERVER_ENABLED == TRUE)
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+/* Maximum number of bytes to reserve out of SDP MTU for response data */
+#define SDP_MAX_SERVICE_RSPHDR_LEN 12
+#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
+#define SDP_MAX_ATTR_RSPHDR_LEN 10
+
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ UNUSED_ATTR uint8_t* p_req_end);
+
+static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ uint8_t* p_req_end);
+
+static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ UNUSED_ATTR uint8_t* p_req_end);
+
+/******************************************************************************/
+/* E R R O R T E X T S T R I N G S */
+/* */
+/* The default is to have no text string, but we allow the strings to be */
+/* configured in target.h if people want them. */
+/******************************************************************************/
+#ifndef SDP_TEXT_BAD_HEADER
+#define SDP_TEXT_BAD_HEADER NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_PDU
+#define SDP_TEXT_BAD_PDU NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_UUID_LIST
+#define SDP_TEXT_BAD_UUID_LIST NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_HANDLE
+#define SDP_TEXT_BAD_HANDLE NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_ATTR_LIST
+#define SDP_TEXT_BAD_ATTR_LIST NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_LEN
+#define SDP_TEXT_BAD_CONT_LEN NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_CONT_INX
+#define SDP_TEXT_BAD_CONT_INX NULL
+#endif
+
+#ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
+#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
+#endif
+
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+/*******************************************************************************
+**
+** Function sdp_hfp_blacklist_check
+**
+** Description This function check if
+** 1. The device address matches the HFP 1.7 blacklist
+** 2. The attribute id is profile desciptor
+** 3. The profile uuid is HFP
+** change HFP version to be 1.6
+**
+** Returns void
+**
+*******************************************************************************/
+void sdp_hfp_blacklist_check(tSDP_ATTRIBUTE* p_attr, uint8_t* p_attr_start,
+ BD_ADDR addr) {
+ SDP_TRACE_EVENT("sdp_hfp_blacklist_check");
+ if ((p_attr->id == ATTR_ID_BT_PROFILE_DESC_LIST) &&
+ (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) &&
+ (p_attr_start[MTK_HFP_VERSION_SDP_POSITION] == ((UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES)) &&
+ (((p_attr_start[MTK_HFP_VERSION_SDP_POSITION + 1] << 8) |
+ p_attr_start[MTK_HFP_VERSION_SDP_POSITION + 2]) ==
+ UUID_SERVCLASS_HF_HANDSFREE)) {
+ if (interop_mtk_match_addr_name(INTEROP_MTK_HFP_17_TO_16,
+ (const bt_bdaddr_t*)addr)) {
+ SDP_TRACE_WARNING(
+ "SDP - HFP 1.7 IOT device, fallback the version to 1.6");
+ p_attr_start[MTK_HFP_VERSION_SDP_POSITION + MTK_HFP_VERSION_OFFSET] = MTK_HFP_VERSION_16;
+ }
+ }
+}
+
+#endif
+
+/*******************************************************************************
+ *
+ * Function sdp_server_handle_client_req
+ *
+ * Description This is the main dispatcher of the SDP server. It is called
+ * when any data is received from L2CAP, and dispatches the
+ * request to the appropriate handler.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg) {
+ uint8_t* p_req = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ uint8_t* p_req_end = p_req + p_msg->len;
+ uint8_t pdu_id;
+ uint16_t trans_num, param_len;
+
+ /* Start inactivity timer */
+ alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
+ sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
+
+ /* The first byte in the message is the pdu type */
+ pdu_id = *p_req++;
+
+ /* Extract the transaction number and parameter length */
+ BE_STREAM_TO_UINT16(trans_num, p_req);
+ BE_STREAM_TO_UINT16(param_len, p_req);
+
+ if ((p_req + param_len) != p_req_end) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_PDU_SIZE,
+ SDP_TEXT_BAD_HEADER);
+ return;
+ }
+
+ switch (pdu_id) {
+ case SDP_PDU_SERVICE_SEARCH_REQ:
+ process_service_search(p_ccb, trans_num, param_len, p_req, p_req_end);
+ break;
+
+ case SDP_PDU_SERVICE_ATTR_REQ:
+ process_service_attr_req(p_ccb, trans_num, param_len, p_req, p_req_end);
+ break;
+
+ case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
+ process_service_search_attr_req(p_ccb, trans_num, param_len, p_req,
+ p_req_end);
+ break;
+
+ default:
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_PDU);
+ SDP_TRACE_WARNING("SDP - server got unknown PDU: 0x%x", pdu_id);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function process_service_search
+ *
+ * Description This function handles a service search request from the
+ * client. It builds a reply message with info from the
+ * database, and sends the reply back to the client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ UNUSED_ATTR uint8_t* p_req_end) {
+ uint16_t max_replies, cur_handles, rem_handles, cont_offset;
+ tSDP_UUID_SEQ uid_seq;
+ uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ uint16_t rsp_param_len, num_rsp_handles, xx;
+ uint32_t rsp_handles[SDP_MAX_RECORDS] = {0};
+ tSDP_RECORD* p_rec = NULL;
+ bool is_cont = false;
+
+ p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq);
+
+ if ((!p_req) || (!uid_seq.num_uids)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_UUID_LIST);
+ return;
+ }
+
+ /* Get the max replies we can send. Cap it at our max anyways. */
+ BE_STREAM_TO_UINT16(max_replies, p_req);
+
+ if (max_replies > SDP_MAX_RECORDS) max_replies = SDP_MAX_RECORDS;
+
+ if ((!p_req) || (p_req > p_req_end)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_MAX_RECORDS_LIST);
+ return;
+ }
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (num_rsp_handles = 0; num_rsp_handles < max_replies;) {
+ p_rec = sdp_db_service_search(p_rec, &uid_seq);
+
+ if (p_rec)
+ rsp_handles[num_rsp_handles++] = p_rec->record_handle;
+ else
+ break;
+ }
+
+ /* Check if this is a continuation request */
+ if (*p_req) {
+ if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16(cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+
+ rem_handles =
+ num_rsp_handles - cont_offset; /* extract the remaining handles */
+ } else {
+ rem_handles = num_rsp_handles;
+ cont_offset = 0;
+ p_ccb->cont_offset = 0;
+ }
+
+ /* Calculate how many handles will fit in one PDU */
+ cur_handles =
+ (uint16_t)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
+
+ if (rem_handles <= cur_handles)
+ cur_handles = rem_handles;
+ else /* Continuation is set */
+ {
+ p_ccb->cont_offset += cur_handles;
+ is_cont = true;
+ }
+
+ /* Get a buffer to use to build the response */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
+ UINT16_TO_BE_STREAM(p_rsp, trans_num);
+
+ /* Skip the length, we need to add it at the end */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ /* Put in total and current number of handles, and handles themselves */
+ UINT16_TO_BE_STREAM(p_rsp, num_rsp_handles);
+ UINT16_TO_BE_STREAM(p_rsp, cur_handles);
+
+ /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d,
+ cont %d",
+ num_rsp_handles, cur_handles, cont_offset,
+ cont_offset + cur_handles-1, is_cont); */
+ for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
+ UINT32_TO_BE_STREAM(p_rsp, rsp_handles[xx]);
+
+ if (is_cont) {
+ UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
+ } else
+ UINT8_TO_BE_STREAM(p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite(p_ccb->connection_id, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function process_service_attr_req
+ *
+ * Description This function handles an attribute request from the client.
+ * It builds a reply message with info from the database,
+ * and sends the reply back to the client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ uint8_t* p_req_end) {
+ uint16_t max_list_len, len_to_send, cont_offset;
+ int16_t rem_len;
+ tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
+ uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ uint16_t rsp_param_len, xx;
+ uint32_t rec_handle;
+ tSDP_RECORD* p_rec;
+ tSDP_ATTRIBUTE* p_attr;
+ bool is_cont = false;
+ uint16_t attr_len;
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ uint8_t* p_attr_start;
+#endif
+ /** @} */
+
+ /* Extract the record handle */
+ BE_STREAM_TO_UINT32(rec_handle, p_req);
+
+ if (p_req > p_req_end) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL,
+ SDP_TEXT_BAD_HANDLE);
+ return;
+ }
+
+ /* Get the max list length we can send. Cap it at MTU size minus overhead */
+ BE_STREAM_TO_UINT16(max_list_len, p_req);
+
+ if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
+ max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
+
+ p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq);
+
+ if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_ATTR_LIST);
+ return;
+ }
+
+ memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ));
+
+ /* Find a record with the record handle */
+ p_rec = sdp_db_find_record(rec_handle);
+ if (!p_rec) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL,
+ SDP_TEXT_BAD_HANDLE);
+ return;
+ }
+
+ /* Free and reallocate buffer */
+ osi_free(p_ccb->rsp_list);
+ p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len);
+
+ /* Check if this is a continuation request */
+ if (*p_req) {
+ if (*p_req++ != SDP_CONTINUATION_LEN) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16(cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+ is_cont = true;
+
+ /* Initialise for continuation response */
+ p_rsp = &p_ccb->rsp_list[0];
+ attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
+ p_ccb->cont_info.next_attr_start_id;
+ } else {
+ p_ccb->cont_offset = 0;
+ p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
+
+ /* Reset continuation parameters in p_ccb */
+ p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.attr_offset = 0;
+ }
+
+ /* Search for attributes that match the list given to us */
+ for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
+ p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start,
+ attr_seq.attr_entry[xx].end);
+
+ if (p_attr) {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
+
+ /* just in case */
+ if (rem_len <= 0) {
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ break;
+ }
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ p_attr_start = p_rsp;
+#endif
+ /** @} */
+
+ attr_len = sdpu_get_attrib_entry_len(p_attr);
+ /* if there is a partial attribute pending to be sent */
+ if (p_ccb->cont_info.attr_offset) {
+ p_rsp = sdpu_build_partial_attrib_entry(p_rsp, p_attr, rem_len,
+ &p_ccb->cont_info.attr_offset);
+
+ /* If the partial attrib could not been fully added yet */
+ if (p_ccb->cont_info.attr_offset != attr_len)
+ break;
+ else /* If the partial attrib has been added in full by now */
+ p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+ } else if (rem_len <
+ attr_len) /* Not enough space for attr... so add partially */
+ {
+ if (attr_len >= SDP_MAX_ATTR_LEN) {
+ SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
+ max_list_len, attr_len);
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+
+ /* add the partial attribute if possible */
+ p_rsp = sdpu_build_partial_attrib_entry(
+ p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
+
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ break;
+ } else /* build the whole attribute */
+ p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if ((uint8_t)(p_rsp - p_attr_start) >= (MTK_HFP_VERSION_SDP_POSITION
+ + MTK_HFP_VERSION_OFFSET)) {
+ sdp_hfp_blacklist_check(p_attr, p_attr_start, p_ccb->device_address);
+ }
+#endif
+ /** @} */
+
+ /* If doing a range, stick with this one till no more attributes found */
+ if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
+ /* Update for next time through */
+ attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+ xx--;
+ }
+ }
+ }
+ /* If all the attributes have been accomodated in p_rsp,
+ reset next_attr_index */
+ if (xx == attr_seq.num_attr) p_ccb->cont_info.next_attr_index = 0;
+
+ len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
+ cont_offset = 0;
+
+ if (!is_cont) {
+ p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (p_ccb->list_len > 255) {
+ p_ccb->rsp_list[0] =
+ (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
+ p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
+ } else {
+ cont_offset = 1;
+
+ p_ccb->rsp_list[1] =
+ (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
+
+ p_ccb->list_len--;
+ len_to_send--;
+ }
+ }
+
+ /* Get a buffer to use to build the response */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
+ UINT16_TO_BE_STREAM(p_rsp, trans_num);
+
+ /* Skip the parameter length, add it when we know the length */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ UINT16_TO_BE_STREAM(p_rsp, len_to_send);
+
+ memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+ p_rsp += len_to_send;
+
+ p_ccb->cont_offset += len_to_send;
+
+ /* If anything left to send, continuation needed */
+ if (p_ccb->cont_offset < p_ccb->list_len) {
+ is_cont = true;
+
+ UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
+ } else
+ UINT8_TO_BE_STREAM(p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite(p_ccb->connection_id, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function process_service_search_attr_req
+ *
+ * Description This function handles a combined service search and
+ * attribute read request from the client. It builds a reply
+ * message with info from the database, and sends the reply
+ * back to the client.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t param_len, uint8_t* p_req,
+ UNUSED_ATTR uint8_t* p_req_end) {
+ uint16_t max_list_len;
+ int16_t rem_len;
+ uint16_t len_to_send, cont_offset;
+ tSDP_UUID_SEQ uid_seq;
+ uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ uint16_t rsp_param_len, xx;
+ tSDP_RECORD* p_rec;
+ tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
+ tSDP_ATTRIBUTE* p_attr;
+ bool maxxed_out = false, is_cont = false;
+ uint8_t* p_seq_start;
+ uint16_t seq_len, attr_len;
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ uint8_t* p_attr_start;
+#endif
+ /** @} */
+
+ /* Extract the UUID sequence to search for */
+ p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq);
+
+ if ((!p_req) || (!uid_seq.num_uids)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_UUID_LIST);
+ return;
+ }
+
+ /* Get the max list length we can send. Cap it at our max list length. */
+ BE_STREAM_TO_UINT16(max_list_len, p_req);
+
+ if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
+ max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
+
+ p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq);
+
+ if ((!p_req) || (!attr_seq.num_attr)) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
+ SDP_TEXT_BAD_ATTR_LIST);
+ return;
+ }
+
+ memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ));
+
+ /* Free and reallocate buffer */
+ osi_free(p_ccb->rsp_list);
+ p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len);
+
+ /* Check if this is a continuation request */
+ if (*p_req) {
+ if (*p_req++ != SDP_CONTINUATION_LEN) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_LEN);
+ return;
+ }
+ BE_STREAM_TO_UINT16(cont_offset, p_req);
+
+ if (cont_offset != p_ccb->cont_offset) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
+ SDP_TEXT_BAD_CONT_INX);
+ return;
+ }
+ is_cont = true;
+
+ /* Initialise for continuation response */
+ p_rsp = &p_ccb->rsp_list[0];
+ attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
+ p_ccb->cont_info.next_attr_start_id;
+ } else {
+ p_ccb->cont_offset = 0;
+ p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
+
+ /* Reset continuation parameters in p_ccb */
+ p_ccb->cont_info.prev_sdp_rec = NULL;
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.last_attr_seq_desc_sent = false;
+ p_ccb->cont_info.attr_offset = 0;
+ }
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (p_rec = sdp_db_service_search(p_ccb->cont_info.prev_sdp_rec, &uid_seq);
+ p_rec; p_rec = sdp_db_service_search(p_rec, &uid_seq)) {
+ /* Allow space for attribute sequence type and length */
+ p_seq_start = p_rsp;
+ if (p_ccb->cont_info.last_attr_seq_desc_sent == false) {
+ /* See if there is enough room to include a new service in the current
+ * response */
+ rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
+ if (rem_len < 3) {
+ /* Not enough room. Update continuation info for next response */
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
+ break;
+ }
+ p_rsp += 3;
+ }
+
+ /* Get a list of handles that match the UUIDs given to us */
+ for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
+ p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start,
+ attr_seq.attr_entry[xx].end);
+
+ if (p_attr) {
+ /* Check if attribute fits. Assume 3-byte value type/length */
+ rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
+
+ /* just in case */
+ if (rem_len <= 0) {
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ maxxed_out = true;
+ break;
+ }
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ p_attr_start = p_rsp;
+#endif
+ /** @} */
+
+ attr_len = sdpu_get_attrib_entry_len(p_attr);
+ /* if there is a partial attribute pending to be sent */
+ if (p_ccb->cont_info.attr_offset) {
+ p_rsp = sdpu_build_partial_attrib_entry(
+ p_rsp, p_attr, rem_len, &p_ccb->cont_info.attr_offset);
+
+ /* If the partial attrib could not been fully added yet */
+ if (p_ccb->cont_info.attr_offset != attr_len) {
+ maxxed_out = true;
+ break;
+ } else /* If the partial attrib has been added in full by now */
+ p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
+ } else if (rem_len <
+ attr_len) /* Not enough space for attr... so add partially */
+ {
+ if (attr_len >= SDP_MAX_ATTR_LEN) {
+ SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
+ max_list_len, attr_len);
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
+ return;
+ }
+
+ /* add the partial attribute if possible */
+ p_rsp = sdpu_build_partial_attrib_entry(
+ p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
+
+ p_ccb->cont_info.next_attr_index = xx;
+ p_ccb->cont_info.next_attr_start_id = p_attr->id;
+ maxxed_out = true;
+ break;
+ } else /* build the whole attribute */
+ p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
+
+ /* If doing a range, stick with this one till no more attributes found
+ */
+
+ /** M: Add for HFP 1.7 to 1.6 blacklist @{ */
+#if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE)
+ if ((uint8_t)(p_rsp - p_attr_start) >=
+ (MTK_HFP_VERSION_SDP_POSITION + MTK_HFP_VERSION_OFFSET)) {
+ sdp_hfp_blacklist_check(p_attr, p_attr_start, p_ccb->device_address);
+ }
+#endif
+ /** @} */
+
+ if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
+ /* Update for next time through */
+ attr_seq.attr_entry[xx].start = p_attr->id + 1;
+
+ xx--;
+ }
+ }
+ }
+
+ /* Go back and put the type and length into the buffer */
+ if (p_ccb->cont_info.last_attr_seq_desc_sent == false) {
+ seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
+ if (seq_len != 0) {
+ UINT8_TO_BE_STREAM(p_seq_start,
+ (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM(p_seq_start, seq_len);
+
+ if (maxxed_out) p_ccb->cont_info.last_attr_seq_desc_sent = true;
+ } else
+ p_rsp = p_seq_start;
+ }
+
+ if (maxxed_out) break;
+
+ /* Restore the attr_seq to look for in the next sdp record */
+ memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ));
+
+ /* Reset the next attr index */
+ p_ccb->cont_info.next_attr_index = 0;
+ p_ccb->cont_info.prev_sdp_rec = p_rec;
+ p_ccb->cont_info.last_attr_seq_desc_sent = false;
+ }
+
+ /* response length */
+ len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
+ cont_offset = 0;
+
+ // The current SDP server design has a critical flaw where it can run into
+ // an infinite request/response loop with the client. Here's the scenario:
+ // - client makes SDP request
+ // - server returns the first fragment of the response with a continuation
+ // token
+ // - an SDP record is deleted from the server
+ // - client issues another request with previous continuation token
+ // - server has nothing to send back because the record is unavailable but
+ // in the first fragment, it had specified more response bytes than are
+ // now available
+ // - server sends back no additional response bytes and returns the same
+ // continuation token
+ // - client issues another request with the continuation token, and the
+ // process repeats
+ //
+ // We work around this design flaw here by checking if we will make forward
+ // progress (i.e. we will send > 0 response bytes) on a continued request.
+ // If not, we must have run into the above situation and we tell the peer an
+ // error occurred.
+ //
+ // TODO(sharvil): rewrite SDP server.
+ if (is_cont && len_to_send == 0) {
+ sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
+ return;
+ }
+
+ /* If first response, insert sequence header */
+ if (!is_cont) {
+ /* Get the total list length for requested uid and attribute sequence */
+ p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
+ /* Put in the sequence header (2 or 3 bytes) */
+ if (p_ccb->list_len > 255) {
+ p_ccb->rsp_list[0] =
+ (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
+ p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
+ } else {
+ cont_offset = 1;
+
+ p_ccb->rsp_list[1] =
+ (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
+
+ p_ccb->list_len--;
+ len_to_send--;
+ }
+ }
+
+ /* Get a buffer to use to build the response */
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ /* Start building a rsponse */
+ UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
+ UINT16_TO_BE_STREAM(p_rsp, trans_num);
+
+ /* Skip the parameter length, add it when we know the length */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ /* Stream the list length to send */
+ UINT16_TO_BE_STREAM(p_rsp, len_to_send);
+
+ /* copy from rsp_list to the actual buffer to be sent */
+ memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
+ p_rsp += len_to_send;
+
+ p_ccb->cont_offset += len_to_send;
+
+ /* If anything left to send, continuation needed */
+ if (p_ccb->cont_offset < p_ccb->list_len) {
+ is_cont = true;
+
+ UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
+ UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
+ } else
+ UINT8_TO_BE_STREAM(p_rsp, 0);
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite(p_ccb->connection_id, p_buf);
+}
+
+#endif /* SDP_SERVER_ENABLED == TRUE */
diff --git a/mtkbt/code/bt/stack/sdp/sdp_utils.cc b/mtkbt/code/bt/stack/sdp/sdp_utils.cc
new file mode 100755
index 0000000..720c746
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdp_utils.cc
@@ -0,0 +1,927 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains SDP utility functions
+ *
+ ******************************************************************************/
+
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt_common.h"
+#include "bt_types.h"
+
+#include "hcidefs.h"
+#include "hcimsgs.h"
+#include "l2cdefs.h"
+
+#include "sdp_api.h"
+#include "sdpint.h"
+
+#include "btu.h"
+
+static const uint8_t sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB};
+
+/*******************************************************************************
+ *
+ * Function sdpu_find_ccb_by_cid
+ *
+ * Description This function searches the CCB table for an entry with the
+ * passed CID.
+ *
+ * Returns the CCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+tCONN_CB* sdpu_find_ccb_by_cid(uint16_t cid) {
+ uint16_t xx;
+ tCONN_CB* p_ccb;
+
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->connection_id == cid))
+ return (p_ccb);
+ }
+
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_find_ccb_by_db
+ *
+ * Description This function searches the CCB table for an entry with the
+ * passed discovery db.
+ *
+ * Returns the CCB address, or NULL if not found.
+ *
+ ******************************************************************************/
+tCONN_CB* sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB* p_db) {
+ uint16_t xx;
+ tCONN_CB* p_ccb;
+
+ if (p_db) {
+ /* Look through each connection control block */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if ((p_ccb->con_state != SDP_STATE_IDLE) && (p_ccb->p_db == p_db))
+ return (p_ccb);
+ }
+ }
+ /* If here, not found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_allocate_ccb
+ *
+ * Description This function allocates a new CCB.
+ *
+ * Returns CCB address, or NULL if none available.
+ *
+ ******************************************************************************/
+tCONN_CB* sdpu_allocate_ccb(void) {
+ uint16_t xx;
+ tCONN_CB* p_ccb;
+
+ /* Look through each connection control block for a free one */
+ for (xx = 0, p_ccb = sdp_cb.ccb; xx < SDP_MAX_CONNECTIONS; xx++, p_ccb++) {
+ if (p_ccb->con_state == SDP_STATE_IDLE) {
+ memset(p_ccb, 0, sizeof(tCONN_CB));
+ p_ccb->sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
+ return (p_ccb);
+ }
+ }
+
+ /* If here, no free CCB found */
+ return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_release_ccb
+ *
+ * Description This function releases a CCB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdpu_release_ccb(tCONN_CB* p_ccb) {
+ /* Ensure timer is stopped */
+ alarm_free(p_ccb->sdp_conn_timer);
+ p_ccb->sdp_conn_timer = NULL;
+
+ /* Drop any response pointer we may be holding */
+ p_ccb->con_state = SDP_STATE_IDLE;
+ p_ccb->is_attr_search = false;
+
+ /* Free the response buffer */
+ if (p_ccb->rsp_list) SDP_TRACE_DEBUG("releasing SDP rsp_list");
+ osi_free_and_reset((void**)&p_ccb->rsp_list);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_build_attrib_seq
+ *
+ * Description This function builds an attribute sequence from the list of
+ * passed attributes. It is also passed the address of the
+ * output buffer.
+ *
+ * Returns Pointer to next byte in the output buffer.
+ *
+ ******************************************************************************/
+uint8_t* sdpu_build_attrib_seq(uint8_t* p_out, uint16_t* p_attr,
+ uint16_t num_attrs) {
+ uint16_t xx;
+
+ /* First thing is the data element header. See if the length fits 1 byte */
+ /* If no attributes, assume a 4-byte wildcard */
+ if (!p_attr)
+ xx = 5;
+ else
+ xx = num_attrs * 3;
+
+ if (xx > 255) {
+ UINT8_TO_BE_STREAM(p_out,
+ (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM(p_out, xx);
+ } else {
+ UINT8_TO_BE_STREAM(p_out,
+ (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p_out, xx);
+ }
+
+ /* If there are no attributes specified, assume caller wants wildcard */
+ if (!p_attr) {
+ UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
+ UINT16_TO_BE_STREAM(p_out, 0);
+ UINT16_TO_BE_STREAM(p_out, 0xFFFF);
+ } else {
+ /* Loop through and put in all the attributes(s) */
+ for (xx = 0; xx < num_attrs; xx++, p_attr++) {
+ UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p_out, *p_attr);
+ }
+ }
+
+ return (p_out);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_build_attrib_entry
+ *
+ * Description This function builds an attribute entry from the passed
+ * attribute record. It is also passed the address of the
+ * output buffer.
+ *
+ * Returns Pointer to next byte in the output buffer.
+ *
+ ******************************************************************************/
+uint8_t* sdpu_build_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr) {
+ /* First, store the attribute ID. Goes as a UINT */
+ UINT8_TO_BE_STREAM(p_out, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
+ UINT16_TO_BE_STREAM(p_out, p_attr->id);
+
+ /* the attribute is in the db record.
+ * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+ switch (p_attr->type) {
+ case TEXT_STR_DESC_TYPE: /* 4 */
+ case DATA_ELE_SEQ_DESC_TYPE: /* 6 */
+ case DATA_ELE_ALT_DESC_TYPE: /* 7 */
+ case URL_DESC_TYPE: /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+ if (p_attr->len > 0xFFFF) {
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_LONG);
+ UINT32_TO_BE_STREAM(p_out, p_attr->len);
+ } else
+#endif /* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+ if (p_attr->len > 0xFF) {
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_WORD);
+ UINT16_TO_BE_STREAM(p_out, p_attr->len);
+ } else
+#endif /* 0xFF and less*/
+ {
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p_out, p_attr->len);
+ }
+
+ if (p_attr->value_ptr != NULL) {
+ ARRAY_TO_BE_STREAM(p_out, p_attr->value_ptr, (int)p_attr->len);
+ }
+
+ return (p_out);
+ }
+
+ /* Now, store the attribute value */
+ switch (p_attr->len) {
+ case 1:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_ONE_BYTE);
+ break;
+ case 2:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_TWO_BYTES);
+ break;
+ case 4:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_FOUR_BYTES);
+ break;
+ case 8:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_EIGHT_BYTES);
+ break;
+ case 16:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_SIXTEEN_BYTES);
+ break;
+ default:
+ UINT8_TO_BE_STREAM(p_out, (p_attr->type << 3) | SIZE_IN_NEXT_BYTE);
+ UINT8_TO_BE_STREAM(p_out, p_attr->len);
+ break;
+ }
+
+ if (p_attr->value_ptr != NULL) {
+ ARRAY_TO_BE_STREAM(p_out, p_attr->value_ptr, (int)p_attr->len);
+ }
+
+ return (p_out);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_build_n_send_error
+ *
+ * Description This function builds and sends an error packet.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdpu_build_n_send_error(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t error_code, char* p_error_text) {
+ uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
+ uint16_t rsp_param_len;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
+
+ SDP_TRACE_WARNING("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x",
+ error_code, p_ccb->connection_id);
+
+ /* Send the packet to L2CAP */
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_ERROR_RESPONSE);
+ UINT16_TO_BE_STREAM(p_rsp, trans_num);
+
+ /* Skip the parameter length, we need to add it at the end */
+ p_rsp_param_len = p_rsp;
+ p_rsp += 2;
+
+ UINT16_TO_BE_STREAM(p_rsp, error_code);
+
+ /* Unplugfest example traces do not have any error text */
+ if (p_error_text)
+ ARRAY_TO_BE_STREAM(p_rsp, p_error_text, (int)strlen(p_error_text));
+
+ /* Go back and put the parameter length into the buffer */
+ rsp_param_len = p_rsp - p_rsp_param_len - 2;
+ UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
+
+ /* Set the length of the SDP data in the buffer */
+ p_buf->len = p_rsp - p_rsp_start;
+
+ /* Send the buffer through L2CAP */
+ L2CA_DataWrite(p_ccb->connection_id, p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_extract_uid_seq
+ *
+ * Description This function extracts a UUID sequence from the passed input
+ * buffer, and puts it into the passed output list.
+ *
+ * Returns Pointer to next byte in the input buffer after the sequence.
+ *
+ ******************************************************************************/
+uint8_t* sdpu_extract_uid_seq(uint8_t* p, uint16_t param_len,
+ tSDP_UUID_SEQ* p_seq) {
+ uint8_t* p_seq_end;
+ uint8_t descr, type, size;
+ uint32_t seq_len, uuid_len;
+
+ /* Assume none found */
+ p_seq->num_uids = 0;
+
+ /* A UID sequence is composed of a bunch of UIDs. */
+
+ BE_STREAM_TO_UINT8(descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != DATA_ELE_SEQ_DESC_TYPE) return (NULL);
+
+ switch (size) {
+ case SIZE_TWO_BYTES:
+ seq_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ seq_len = 4;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ seq_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8(seq_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16(seq_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32(seq_len, p);
+ break;
+ default:
+ return (NULL);
+ }
+
+ if (seq_len >= param_len) return (NULL);
+
+ p_seq_end = p + seq_len;
+
+ /* Loop through, extracting the UIDs */
+ for (; p < p_seq_end;) {
+ BE_STREAM_TO_UINT8(descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != UUID_DESC_TYPE) return (NULL);
+
+ switch (size) {
+ case SIZE_TWO_BYTES:
+ uuid_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ uuid_len = 4;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ uuid_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8(uuid_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16(uuid_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32(uuid_len, p);
+ break;
+ default:
+ return (NULL);
+ }
+
+ /* If UUID length is valid, copy it across */
+ if ((uuid_len == 2) || (uuid_len == 4) || (uuid_len == 16)) {
+ p_seq->uuid_entry[p_seq->num_uids].len = (uint16_t)uuid_len;
+ BE_STREAM_TO_ARRAY(p, p_seq->uuid_entry[p_seq->num_uids].value,
+ (int)uuid_len);
+ p_seq->num_uids++;
+ } else
+ return (NULL);
+
+ /* We can only do so many */
+ if (p_seq->num_uids >= MAX_UUIDS_PER_SEQ) return (NULL);
+ }
+
+ if (p != p_seq_end) return (NULL);
+
+ return (p);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_extract_attr_seq
+ *
+ * Description This function extracts an attribute sequence from the passed
+ * input buffer, and puts it into the passed output list.
+ *
+ * Returns Pointer to next byte in the input buffer after the sequence.
+ *
+ ******************************************************************************/
+uint8_t* sdpu_extract_attr_seq(uint8_t* p, uint16_t param_len,
+ tSDP_ATTR_SEQ* p_seq) {
+ uint8_t* p_end_list;
+ uint8_t descr, type, size;
+ uint32_t list_len, attr_len;
+
+ /* Assume none found */
+ p_seq->num_attr = 0;
+
+ /* Get attribute sequence info */
+ BE_STREAM_TO_UINT8(descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != DATA_ELE_SEQ_DESC_TYPE) return (p);
+
+ switch (size) {
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8(list_len, p);
+ break;
+
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16(list_len, p);
+ break;
+
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32(list_len, p);
+ break;
+
+ default:
+ return (p);
+ }
+
+ if (list_len > param_len) return (p);
+
+ p_end_list = p + list_len;
+
+ /* Loop through, extracting the attribute IDs */
+ for (; p < p_end_list;) {
+ BE_STREAM_TO_UINT8(descr, p);
+ type = descr >> 3;
+ size = descr & 7;
+
+ if (type != UINT_DESC_TYPE) return (p);
+
+ switch (size) {
+ case SIZE_TWO_BYTES:
+ attr_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ attr_len = 4;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8(attr_len, p);
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16(attr_len, p);
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32(attr_len, p);
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+
+ /* Attribute length must be 2-bytes or 4-bytes for a paired entry. */
+ if (attr_len == 2) {
+ BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].start, p);
+ p_seq->attr_entry[p_seq->num_attr].end =
+ p_seq->attr_entry[p_seq->num_attr].start;
+ } else if (attr_len == 4) {
+ BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].start, p);
+ BE_STREAM_TO_UINT16(p_seq->attr_entry[p_seq->num_attr].end, p);
+ } else
+ return (NULL);
+
+ /* We can only do so many */
+ if (++p_seq->num_attr >= MAX_ATTR_PER_SEQ) return (NULL);
+ }
+
+ return (p);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_get_len_from_type
+ *
+ * Description This function gets the length
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint8_t* sdpu_get_len_from_type(uint8_t* p, uint8_t type, uint32_t* p_len) {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+
+ switch (type & 7) {
+ case SIZE_ONE_BYTE:
+ *p_len = 1;
+ break;
+ case SIZE_TWO_BYTES:
+ *p_len = 2;
+ break;
+ case SIZE_FOUR_BYTES:
+ *p_len = 4;
+ break;
+ case SIZE_EIGHT_BYTES:
+ *p_len = 8;
+ break;
+ case SIZE_SIXTEEN_BYTES:
+ *p_len = 16;
+ break;
+ case SIZE_IN_NEXT_BYTE:
+ BE_STREAM_TO_UINT8(u8, p);
+ *p_len = u8;
+ break;
+ case SIZE_IN_NEXT_WORD:
+ BE_STREAM_TO_UINT16(u16, p);
+ *p_len = u16;
+ break;
+ case SIZE_IN_NEXT_LONG:
+ BE_STREAM_TO_UINT32(u32, p);
+ *p_len = (uint16_t)u32;
+ break;
+ }
+
+ return (p);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_is_base_uuid
+ *
+ * Description This function checks a 128-bit UUID with the base to see if
+ * it matches. Only the last 12 bytes are compared.
+ *
+ * Returns true if matched, else false
+ *
+ ******************************************************************************/
+bool sdpu_is_base_uuid(uint8_t* p_uuid) {
+ uint16_t xx;
+
+ for (xx = 4; xx < MAX_UUID_SIZE; xx++)
+ if (p_uuid[xx] != sdp_base_uuid[xx]) return (false);
+
+ /* If here, matched */
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_compare_uuid_arrays
+ *
+ * Description This function compares 2 BE UUIDs. If needed, they are
+ * expanded to 128-bit UUIDs, then compared.
+ *
+ * NOTE it is assumed that the arrays are in Big Endian format
+ *
+ * Returns true if matched, else false
+ *
+ ******************************************************************************/
+bool sdpu_compare_uuid_arrays(uint8_t* p_uuid1, uint32_t len1, uint8_t* p_uuid2,
+ uint16_t len2) {
+ uint8_t nu1[MAX_UUID_SIZE];
+ uint8_t nu2[MAX_UUID_SIZE];
+
+ if (((len1 != 2) && (len1 != 4) && (len1 != 16)) ||
+ ((len2 != 2) && (len2 != 4) && (len2 != 16))) {
+ SDP_TRACE_ERROR("%s: invalid length", __func__);
+ return false;
+ }
+
+ /* If lengths match, do a straight compare */
+ if (len1 == len2) {
+ if (len1 == 2)
+ return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]));
+ if (len1 == 4)
+ return ((p_uuid1[0] == p_uuid2[0]) && (p_uuid1[1] == p_uuid2[1]) &&
+ (p_uuid1[2] == p_uuid2[2]) && (p_uuid1[3] == p_uuid2[3]));
+ else
+ return (memcmp(p_uuid1, p_uuid2, (size_t)len1) == 0);
+ } else if (len1 > len2) {
+ /* If the len1 was 4-byte, (so len2 is 2-byte), compare on the fly */
+ if (len1 == 4) {
+ return ((p_uuid1[0] == 0) && (p_uuid1[1] == 0) &&
+ (p_uuid1[2] == p_uuid2[0]) && (p_uuid1[3] == p_uuid2[1]));
+ } else {
+ /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+ memcpy(nu1, p_uuid1, MAX_UUID_SIZE);
+ memcpy(nu2, sdp_base_uuid, MAX_UUID_SIZE);
+
+ if (len2 == 4)
+ memcpy(nu2, p_uuid2, len2);
+ else if (len2 == 2)
+ memcpy(nu2 + 2, p_uuid2, len2);
+
+ return (memcmp(nu1, nu2, MAX_UUID_SIZE) == 0);
+ }
+ } else {
+ /* len2 is greater than len1 */
+ /* If the len2 was 4-byte, (so len1 is 2-byte), compare on the fly */
+ if (len2 == 4) {
+ return ((p_uuid2[0] == 0) && (p_uuid2[1] == 0) &&
+ (p_uuid2[2] == p_uuid1[0]) && (p_uuid2[3] == p_uuid1[1]));
+ } else {
+ /* Normalize UUIDs to 16-byte form, then compare. Len1 must be 16 */
+ memcpy(nu2, p_uuid2, MAX_UUID_SIZE);
+ memcpy(nu1, sdp_base_uuid, MAX_UUID_SIZE);
+
+ if (len1 == 4)
+ memcpy(nu1, p_uuid1, (size_t)len1);
+ else if (len1 == 2)
+ memcpy(nu1 + 2, p_uuid1, (size_t)len1);
+
+ return (memcmp(nu1, nu2, MAX_UUID_SIZE) == 0);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_compare_bt_uuids
+ *
+ * Description This function compares 2 BT UUID structures.
+ *
+ * NOTE it is assumed that BT UUID structures are compressed to the
+ * smallest possible UUIDs (by removing the base SDP UUID)
+ *
+ * Returns true if matched, else false
+ *
+ ******************************************************************************/
+bool sdpu_compare_bt_uuids(tBT_UUID* p_uuid1, tBT_UUID* p_uuid2) {
+ /* Lengths must match for BT UUIDs to match */
+ if (p_uuid1->len == p_uuid2->len) {
+ if (p_uuid1->len == 2)
+ return (p_uuid1->uu.uuid16 == p_uuid2->uu.uuid16);
+ else if (p_uuid1->len == 4)
+ return (p_uuid1->uu.uuid32 == p_uuid2->uu.uuid32);
+ else if (!memcmp(p_uuid1->uu.uuid128, p_uuid2->uu.uuid128, 16))
+ return (true);
+ }
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_compare_uuid_with_attr
+ *
+ * Description This function compares a BT UUID structure with the UUID in
+ * an SDP attribute record. If needed, they are expanded to
+ * 128-bit UUIDs, then compared.
+ *
+ * NOTE - it is assumed that BT UUID structures are compressed to the
+ * smallest possible UUIDs (by removing the base SDP UUID).
+ * - it is also assumed that the discovery atribute is compressed
+ * to the smallest possible
+ *
+ * Returns true if matched, else false
+ *
+ ******************************************************************************/
+bool sdpu_compare_uuid_with_attr(tBT_UUID* p_btuuid, tSDP_DISC_ATTR* p_attr) {
+ uint16_t attr_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
+
+ /* Since both UUIDs are compressed, lengths must match */
+ if (p_btuuid->len != attr_len) return (false);
+
+ if (p_btuuid->len == 2)
+ return (bool)(p_btuuid->uu.uuid16 == p_attr->attr_value.v.u16);
+ else if (p_btuuid->len == 4)
+ return (bool)(p_btuuid->uu.uuid32 == p_attr->attr_value.v.u32);
+ else if (!memcmp(p_btuuid->uu.uuid128, (void*)p_attr->attr_value.v.array,
+ MAX_UUID_SIZE))
+ return (true);
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_sort_attr_list
+ *
+ * Description sorts a list of attributes in numeric order from lowest to
+ * highest to conform to SDP specification
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void sdpu_sort_attr_list(uint16_t num_attr, tSDP_DISCOVERY_DB* p_db) {
+ uint16_t i;
+ uint16_t x;
+
+ /* Done if no attributes to sort */
+ if (num_attr <= 1) {
+ return;
+ } else if (num_attr > SDP_MAX_ATTR_FILTERS) {
+ num_attr = SDP_MAX_ATTR_FILTERS;
+ }
+
+ num_attr--; /* for the for-loop */
+ for (i = 0; i < num_attr;) {
+ if (p_db->attr_filters[i] > p_db->attr_filters[i + 1]) {
+ /* swap the attribute IDs and start from the beginning */
+ x = p_db->attr_filters[i];
+ p_db->attr_filters[i] = p_db->attr_filters[i + 1];
+ p_db->attr_filters[i + 1] = x;
+
+ i = 0;
+ } else
+ i++;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_get_list_len
+ *
+ * Description gets the total list length in the sdp database for a given
+ * uid sequence and attr sequence
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint16_t sdpu_get_list_len(tSDP_UUID_SEQ* uid_seq, tSDP_ATTR_SEQ* attr_seq) {
+ tSDP_RECORD* p_rec;
+ uint16_t len = 0;
+ uint16_t len1;
+
+ for (p_rec = sdp_db_service_search(NULL, uid_seq); p_rec;
+ p_rec = sdp_db_service_search(p_rec, uid_seq)) {
+ len += 3;
+
+ len1 = sdpu_get_attrib_seq_len(p_rec, attr_seq);
+
+ if (len1 != 0)
+ len += len1;
+ else
+ len -= 3;
+ }
+ return len;
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_get_attrib_seq_len
+ *
+ * Description gets the length of the specific attributes in a given
+ * sdp record
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint16_t sdpu_get_attrib_seq_len(tSDP_RECORD* p_rec, tSDP_ATTR_SEQ* attr_seq) {
+ tSDP_ATTRIBUTE* p_attr;
+ uint16_t len1 = 0;
+ uint16_t xx;
+ bool is_range = false;
+ uint16_t start_id = 0, end_id = 0;
+
+ for (xx = 0; xx < attr_seq->num_attr; xx++) {
+ if (is_range == false) {
+ start_id = attr_seq->attr_entry[xx].start;
+ end_id = attr_seq->attr_entry[xx].end;
+ }
+ p_attr = sdp_db_find_attr_in_rec(p_rec, start_id, end_id);
+ if (p_attr) {
+ len1 += sdpu_get_attrib_entry_len(p_attr);
+
+ /* If doing a range, stick with this one till no more attributes found */
+ if (start_id != end_id) {
+ /* Update for next time through */
+ start_id = p_attr->id + 1;
+ xx--;
+ is_range = true;
+ } else
+ is_range = false;
+ } else
+ is_range = false;
+ }
+ return len1;
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_get_attrib_entry_len
+ *
+ * Description gets the length of a specific attribute
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE* p_attr) {
+ uint16_t len = 3;
+
+ /* the attribute is in the db record.
+ * assuming the attribute len is less than SDP_MAX_ATTR_LEN */
+ switch (p_attr->type) {
+ case TEXT_STR_DESC_TYPE: /* 4 */
+ case DATA_ELE_SEQ_DESC_TYPE: /* 6 */
+ case DATA_ELE_ALT_DESC_TYPE: /* 7 */
+ case URL_DESC_TYPE: /* 8 */
+#if (SDP_MAX_ATTR_LEN > 0xFFFF)
+ if (p_attr->len > 0xFFFF) {
+ len += 5;
+ } else
+#endif /* 0xFFFF - 0xFF */
+#if (SDP_MAX_ATTR_LEN > 0xFF)
+ if (p_attr->len > 0xFF) {
+ len += 3;
+ } else
+#endif /* 0xFF and less*/
+ {
+ len += 2;
+ }
+ len += p_attr->len;
+ return len;
+ }
+
+ /* Now, the attribute value */
+ switch (p_attr->len) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ len += 1;
+ break;
+ default:
+ len += 2;
+ break;
+ }
+
+ len += p_attr->len;
+ return len;
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_build_partial_attrib_entry
+ *
+ * Description This function fills a buffer with partial attribute. It is
+ * assumed that the maximum size of any attribute is 256 bytes.
+ *
+ * p_out: output buffer
+ * p_attr: attribute to be copied partially into p_out
+ * rem_len: num bytes to copy into p_out
+ * offset: current start offset within the attr that needs to
+ * be copied
+ *
+ * Returns Pointer to next byte in the output buffer.
+ * offset is also updated
+ *
+ ******************************************************************************/
+uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr,
+ uint16_t len, uint16_t* offset) {
+ uint8_t* p_attr_buff =
+ (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN);
+ sdpu_build_attrib_entry(p_attr_buff, p_attr);
+
+ uint16_t attr_len = sdpu_get_attrib_entry_len(p_attr);
+
+ if (len > SDP_MAX_ATTR_LEN) {
+ SDP_TRACE_ERROR("%s len %d exceeds SDP_MAX_ATTR_LEN", __func__, len);
+ len = SDP_MAX_ATTR_LEN;
+ }
+
+ size_t len_to_copy =
+ ((attr_len - *offset) < len) ? (attr_len - *offset) : len;
+ memcpy(p_out, &p_attr_buff[*offset], len_to_copy);
+
+ p_out = &p_out[len_to_copy];
+ *offset += len_to_copy;
+
+ osi_free(p_attr_buff);
+ return p_out;
+}
+
+/*******************************************************************************
+ *
+ * Function sdpu_uuid16_to_uuid128
+ *
+ * Description This function converts UUID-16 to UUID-128 by including the
+ * base UUID
+ *
+ * uuid16: 2-byte UUID
+ * p_uuid128: Expanded 128-bit UUID
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void sdpu_uuid16_to_uuid128(uint16_t uuid16, uint8_t* p_uuid128) {
+ uint16_t uuid16_bo;
+ memset(p_uuid128, 0, 16);
+
+ memcpy(p_uuid128, sdp_base_uuid, MAX_UUID_SIZE);
+ uuid16_bo = ntohs(uuid16);
+ memcpy(p_uuid128 + 2, &uuid16_bo, sizeof(uint16_t));
+}
diff --git a/mtkbt/code/bt/stack/sdp/sdpint.h b/mtkbt/code/bt/stack/sdp/sdpint.h
new file mode 100755
index 0000000..9c1f112
--- a/dev/null
+++ b/mtkbt/code/bt/stack/sdp/sdpint.h
@@ -0,0 +1,305 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used SDP definitions
+ *
+ ******************************************************************************/
+
+#ifndef SDP_INT_H
+#define SDP_INT_H
+
+#include "bt_target.h"
+#include "l2c_api.h"
+#include "osi/include/alarm.h"
+#include "sdp_api.h"
+
+/* Continuation length - we use a 2-byte offset */
+#define SDP_CONTINUATION_LEN 2
+#define SDP_MAX_CONTINUATION_LEN 16 /* As per the spec */
+
+/* Timeout definitions. */
+#define SDP_INACT_TIMEOUT_MS (30 * 1000) /* Inactivity timeout (in ms) */
+
+/* Define the Out-Flow default values. */
+#define SDP_OFLOW_QOS_FLAG 0
+#define SDP_OFLOW_SERV_TYPE 0
+#define SDP_OFLOW_TOKEN_RATE 0
+#define SDP_OFLOW_TOKEN_BUCKET_SIZE 0
+#define SDP_OFLOW_PEAK_BANDWIDTH 0
+#define SDP_OFLOW_LATENCY 0
+#define SDP_OFLOW_DELAY_VARIATION 0
+
+/* Define the In-Flow default values. */
+#define SDP_IFLOW_QOS_FLAG 0
+#define SDP_IFLOW_SERV_TYPE 0
+#define SDP_IFLOW_TOKEN_RATE 0
+#define SDP_IFLOW_TOKEN_BUCKET_SIZE 0
+#define SDP_IFLOW_PEAK_BANDWIDTH 0
+#define SDP_IFLOW_LATENCY 0
+#define SDP_IFLOW_DELAY_VARIATION 0
+
+#define SDP_LINK_TO 0
+
+/* Define the type of device notification. */
+/* (Inquiry Scan and Page Scan) */
+#define SDP_DEVICE_NOTI_LEN \
+ (sizeof(BT_HDR) + HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_WRITE_PARAM1)
+
+#define SDP_DEVICE_NOTI_FLAG 0x03
+
+/* Define the Protocol Data Unit (PDU) types.
+*/
+#define SDP_PDU_ERROR_RESPONSE 0x01
+#define SDP_PDU_SERVICE_SEARCH_REQ 0x02
+#define SDP_PDU_SERVICE_SEARCH_RSP 0x03
+#define SDP_PDU_SERVICE_ATTR_REQ 0x04
+#define SDP_PDU_SERVICE_ATTR_RSP 0x05
+#define SDP_PDU_SERVICE_SEARCH_ATTR_REQ 0x06
+#define SDP_PDU_SERVICE_SEARCH_ATTR_RSP 0x07
+
+/* Max UUIDs and attributes we support per sequence */
+#define MAX_UUIDS_PER_SEQ 16
+#define MAX_ATTR_PER_SEQ 16
+
+/* Max length we support for any attribute */
+#ifdef SDP_MAX_ATTR_LEN
+#define MAX_ATTR_LEN SDP_MAX_ATTR_LEN
+#else
+#define MAX_ATTR_LEN 256
+#endif
+
+/* Internal UUID sequence representation */
+typedef struct {
+ uint16_t len;
+ uint8_t value[MAX_UUID_SIZE];
+} tUID_ENT;
+
+typedef struct {
+ uint16_t num_uids;
+ tUID_ENT uuid_entry[MAX_UUIDS_PER_SEQ];
+} tSDP_UUID_SEQ;
+
+/* Internal attribute sequence definitions */
+typedef struct {
+ uint16_t start;
+ uint16_t end;
+} tATT_ENT;
+
+typedef struct {
+ uint16_t num_attr;
+ tATT_ENT attr_entry[MAX_ATTR_PER_SEQ];
+} tSDP_ATTR_SEQ;
+
+/* Define the attribute element of the SDP database record */
+typedef struct {
+ uint32_t len; /* Number of bytes in the entry */
+ uint8_t* value_ptr; /* Points to attr_pad */
+ uint16_t id;
+ uint8_t type;
+} tSDP_ATTRIBUTE;
+
+/* An SDP record consists of a handle, and 1 or more attributes */
+typedef struct {
+ uint32_t record_handle;
+ uint32_t free_pad_ptr;
+ uint16_t num_attributes;
+ tSDP_ATTRIBUTE attribute[SDP_MAX_REC_ATTR];
+ uint8_t attr_pad[SDP_MAX_PAD_LEN];
+} tSDP_RECORD;
+
+/* Define the SDP database */
+typedef struct {
+ uint32_t
+ di_primary_handle; /* Device ID Primary record or NULL if nonexistent */
+ uint16_t num_records;
+ tSDP_RECORD record[SDP_MAX_RECORDS];
+} tSDP_DB;
+
+enum {
+ SDP_IS_SEARCH,
+ SDP_IS_ATTR_SEARCH,
+};
+
+#if (SDP_SERVER_ENABLED == TRUE)
+/* Continuation information for the SDP server response */
+typedef struct {
+ uint16_t next_attr_index; /* attr index for next continuation response */
+ uint16_t next_attr_start_id; /* attr id to start with for the attr index in
+ next cont. response */
+ tSDP_RECORD* prev_sdp_rec; /* last sdp record that was completely sent in the
+ response */
+ bool last_attr_seq_desc_sent; /* whether attr seq length has been sent
+ previously */
+ uint16_t attr_offset; /* offset within the attr to keep trak of partial
+ attributes in the responses */
+} tSDP_CONT_INFO;
+#endif /* SDP_SERVER_ENABLED == TRUE */
+
+/* Define the SDP Connection Control Block */
+typedef struct {
+#define SDP_STATE_IDLE 0
+#define SDP_STATE_CONN_SETUP 1
+#define SDP_STATE_CFG_SETUP 2
+#define SDP_STATE_CONNECTED 3
+ uint8_t con_state;
+
+#define SDP_FLAGS_IS_ORIG 0x01
+#define SDP_FLAGS_HIS_CFG_DONE 0x02
+#define SDP_FLAGS_MY_CFG_DONE 0x04
+ uint8_t con_flags;
+
+ BD_ADDR device_address;
+ alarm_t* sdp_conn_timer;
+ uint16_t rem_mtu_size;
+ uint16_t connection_id;
+ uint16_t list_len; /* length of the response in the GKI buffer */
+ uint8_t* rsp_list; /* pointer to GKI buffer holding response */
+
+ tSDP_DISCOVERY_DB* p_db; /* Database to save info into */
+ tSDP_DISC_CMPL_CB* p_cb; /* Callback for discovery done */
+ tSDP_DISC_CMPL_CB2*
+ p_cb2; /* Callback for discovery done piggy back with the user data */
+ void* user_data; /* piggy back user data */
+ uint32_t
+ handles[SDP_MAX_DISC_SERVER_RECS]; /* Discovered server record handles */
+ uint16_t num_handles; /* Number of server handles */
+ uint16_t cur_handle; /* Current handle being processed */
+ uint16_t transaction_id;
+ uint16_t disconnect_reason; /* Disconnect reason */
+#if (SDP_BROWSE_PLUS == TRUE)
+ uint16_t cur_uuid_idx;
+#endif
+
+#define SDP_DISC_WAIT_CONN 0
+#define SDP_DISC_WAIT_HANDLES 1
+#define SDP_DISC_WAIT_ATTR 2
+#define SDP_DISC_WAIT_SEARCH_ATTR 3
+#define SDP_DISC_WAIT_CANCEL 5
+
+ uint8_t disc_state;
+ uint8_t is_attr_search;
+
+#if (SDP_SERVER_ENABLED == TRUE)
+ uint16_t cont_offset; /* Continuation state data in the server response */
+ tSDP_CONT_INFO cont_info; /* structure to hold continuation information for
+ the server response */
+#endif /* SDP_SERVER_ENABLED == TRUE */
+
+} tCONN_CB;
+
+/* The main SDP control block */
+typedef struct {
+ tL2CAP_CFG_INFO l2cap_my_cfg; /* My L2CAP config */
+ tCONN_CB ccb[SDP_MAX_CONNECTIONS];
+#if (SDP_SERVER_ENABLED == TRUE)
+ tSDP_DB server_db;
+#endif
+ tL2CAP_APPL_INFO reg_info; /* L2CAP Registration info */
+ uint16_t max_attr_list_size; /* Max attribute list size to use */
+ uint16_t max_recs_per_search; /* Max records we want per seaarch */
+ uint8_t trace_level;
+} tSDP_CB;
+
+/* Global SDP data */
+extern tSDP_CB sdp_cb;
+
+/* Functions provided by sdp_main.cc */
+extern void sdp_init(void);
+extern void sdp_disconnect(tCONN_CB* p_ccb, uint16_t reason);
+
+#if (SDP_DEBUG == TRUE)
+extern uint16_t sdp_set_max_attr_list_size(uint16_t max_size);
+#endif
+
+/* Functions provided by sdp_conn.cc
+*/
+extern void sdp_conn_rcv_l2e_conn_ind(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_conn_cfm(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_disc(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_config_ind(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_config_cfm(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_connected(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_conn_failed(BT_HDR* p_msg);
+extern void sdp_conn_rcv_l2e_data(BT_HDR* p_msg);
+extern void sdp_conn_timer_timeout(void* data);
+
+extern tCONN_CB* sdp_conn_originate(uint8_t* p_bd_addr);
+
+/* Functions provided by sdp_utils.cc
+*/
+extern tCONN_CB* sdpu_find_ccb_by_cid(uint16_t cid);
+extern tCONN_CB* sdpu_find_ccb_by_db(tSDP_DISCOVERY_DB* p_db);
+extern tCONN_CB* sdpu_allocate_ccb(void);
+extern void sdpu_release_ccb(tCONN_CB* p_ccb);
+
+extern uint8_t* sdpu_build_attrib_seq(uint8_t* p_out, uint16_t* p_attr,
+ uint16_t num_attrs);
+extern uint8_t* sdpu_build_attrib_entry(uint8_t* p_out, tSDP_ATTRIBUTE* p_attr);
+extern void sdpu_build_n_send_error(tCONN_CB* p_ccb, uint16_t trans_num,
+ uint16_t error_code, char* p_error_text);
+
+extern uint8_t* sdpu_extract_attr_seq(uint8_t* p, uint16_t param_len,
+ tSDP_ATTR_SEQ* p_seq);
+extern uint8_t* sdpu_extract_uid_seq(uint8_t* p, uint16_t param_len,
+ tSDP_UUID_SEQ* p_seq);
+
+extern uint8_t* sdpu_get_len_from_type(uint8_t* p, uint8_t type,
+ uint32_t* p_len);
+extern bool sdpu_is_base_uuid(uint8_t* p_uuid);
+extern bool sdpu_compare_uuid_arrays(uint8_t* p_uuid1, uint32_t len1,
+ uint8_t* p_uuid2, uint16_t len2);
+extern bool sdpu_compare_bt_uuids(tBT_UUID* p_uuid1, tBT_UUID* p_uuid2);
+extern bool sdpu_compare_uuid_with_attr(tBT_UUID* p_btuuid,
+ tSDP_DISC_ATTR* p_attr);
+
+extern void sdpu_sort_attr_list(uint16_t num_attr, tSDP_DISCOVERY_DB* p_db);
+extern uint16_t sdpu_get_list_len(tSDP_UUID_SEQ* uid_seq,
+ tSDP_ATTR_SEQ* attr_seq);
+extern uint16_t sdpu_get_attrib_seq_len(tSDP_RECORD* p_rec,
+ tSDP_ATTR_SEQ* attr_seq);
+extern uint16_t sdpu_get_attrib_entry_len(tSDP_ATTRIBUTE* p_attr);
+extern uint8_t* sdpu_build_partial_attrib_entry(uint8_t* p_out,
+ tSDP_ATTRIBUTE* p_attr,
+ uint16_t len, uint16_t* offset);
+
+/* Functions provided by sdp_db.cc
+*/
+extern tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec,
+ tSDP_UUID_SEQ* p_seq);
+extern tSDP_RECORD* sdp_db_find_record(uint32_t handle);
+extern tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec,
+ uint16_t start_attr,
+ uint16_t end_attr);
+
+/* Functions provided by sdp_server.cc
+*/
+#if (SDP_SERVER_ENABLED == TRUE)
+extern void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg);
+#else
+#define sdp_server_handle_client_req(p_ccb, p_msg)
+#endif
+
+/* Functions provided by sdp_discovery.cc
+*/
+extern void sdp_disc_connected(tCONN_CB* p_ccb);
+extern void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg);
+
+#endif
diff --git a/mtkbt/code/bt/stack/smp/aes.cc b/mtkbt/code/bt/stack/smp/aes.cc
new file mode 100755
index 0000000..362a4ee
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/aes.cc
@@ -0,0 +1,953 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+#define HAVE_MEMCPY
+#include <string.h>
+#if 0
+#if defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(memcpy)
+#endif
+#endif
+#endif
+
+#include <stdlib.h>
+
+/* add the target configuration to allow using internal data types and
+ * compilation options */
+#include "bt_target.h"
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+#define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+#define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+#define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined(HAVE_UINT_32T)
+typedef uint32_t uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY))
+#define f4(x) \
+ (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY))
+#define f8(x) \
+ (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \
+ ((((x) >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ (x))
+#define f9(x) (f8(x) ^ (x))
+#define fb(x) (f8(x) ^ f2(x) ^ (x))
+#define fd(x) (f8(x) ^ f4(x) ^ (x))
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined(USE_TABLES)
+
+#define sb_data(w) \
+ { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \
+ w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \
+ w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \
+ w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \
+ w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \
+ w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \
+ w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \
+ w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \
+ w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \
+ w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \
+ w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \
+ w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \
+ w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \
+ w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \
+ w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
+ w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \
+ w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \
+ w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \
+ w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \
+ w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \
+ w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \
+ w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \
+ w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
+ w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \
+ w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \
+ w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \
+ w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \
+ w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \
+ w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \
+ w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \
+ w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
+ w(0x54), w(0xbb), w(0x16) \
+ }
+
+#define isb_data(w) \
+ { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \
+ w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \
+ w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \
+ w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \
+ w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \
+ w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \
+ w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \
+ w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \
+ w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \
+ w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \
+ w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \
+ w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \
+ w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \
+ w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \
+ w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
+ w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \
+ w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \
+ w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \
+ w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \
+ w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \
+ w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \
+ w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \
+ w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
+ w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \
+ w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \
+ w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \
+ w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \
+ w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \
+ w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \
+ w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \
+ w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
+ w(0x21), w(0x0c), w(0x7d) \
+ }
+
+#define mm_data(w) \
+ { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \
+ w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \
+ w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \
+ w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \
+ w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \
+ w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \
+ w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \
+ w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \
+ w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \
+ w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \
+ w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \
+ w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \
+ w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \
+ w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \
+ w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
+ w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \
+ w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \
+ w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \
+ w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \
+ w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \
+ w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \
+ w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \
+ w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
+ w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \
+ w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \
+ w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \
+ w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \
+ w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \
+ w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \
+ w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \
+ w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
+ w(0xfd), w(0xfe), w(0xff) \
+ }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x) {
+ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x) {
+ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if (x < 2) return x;
+
+ for (;;) {
+ if (n1)
+ while (n2 >= n1) /* divide polynomial p2 by p1 */
+ {
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ else
+ return v1;
+
+ if (n2) /* repeat with values swapped */
+ while (n1 >= n2) {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ else
+ return v2;
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^
+ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined(HAVE_MEMCPY)
+#define block_copy_nn(d, s, l) memcpy(d, s, l)
+#define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+#define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+#define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined(HAVE_MEMCPY)
+static void copy_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_block_nn(void* d, const void* s, uint_8t nn) {
+ while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++;
+}
+#endif
+
+static void xor_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_and_key(void* d, const void* s, const void* k) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3];
+#elif 1
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) {
+ xor_block(d, k);
+}
+
+static void shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = s_box(st[0]);
+ st[4] = s_box(st[4]);
+ st[8] = s_box(st[8]);
+ st[12] = s_box(st[12]);
+
+ tt = st[1];
+ st[1] = s_box(st[5]);
+ st[5] = s_box(st[9]);
+ st[9] = s_box(st[13]);
+ st[13] = s_box(tt);
+
+ tt = st[2];
+ st[2] = s_box(st[10]);
+ st[10] = s_box(tt);
+ tt = st[6];
+ st[6] = s_box(st[14]);
+ st[14] = s_box(tt);
+
+ tt = st[15];
+ st[15] = s_box(st[11]);
+ st[11] = s_box(st[7]);
+ st[7] = s_box(st[3]);
+ st[3] = s_box(tt);
+}
+
+static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = is_box(st[0]);
+ st[4] = is_box(st[4]);
+ st[8] = is_box(st[8]);
+ st[12] = is_box(st[12]);
+
+ tt = st[13];
+ st[13] = is_box(st[9]);
+ st[9] = is_box(st[5]);
+ st[5] = is_box(st[1]);
+ st[1] = is_box(tt);
+
+ tt = st[2];
+ st[2] = is_box(st[10]);
+ st[10] = is_box(tt);
+ tt = st[6];
+ st[6] = is_box(st[14]);
+ st[14] = is_box(tt);
+
+ tt = st[3];
+ st[3] = is_box(st[7]);
+ st[7] = is_box(st[11]);
+ st[11] = is_box(st[15]);
+ st[15] = is_box(tt);
+}
+
+#if defined(VERSION_1)
+static void mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+}
+
+#if defined(VERSION_1)
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3]));
+ dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3]));
+ dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3]));
+ dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3]));
+
+ dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7]));
+ dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7]));
+ dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7]));
+ dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7]));
+
+ dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] =
+ is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] =
+ is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+}
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+/* Set the cipher key for the pre-keyed version */
+/* NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]) {
+ uint_8t cc, rc, hi;
+
+ switch (keylen) {
+ case 16:
+ case 128: /* length in bits (128 = 8*16) */
+ keylen = 16;
+ break;
+ case 24:
+ case 192: /* length in bits (192 = 8*24) */
+ keylen = 24;
+ break;
+ case 32:
+ /* case 256: length in bits (256 = 8*32) */
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type)-1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for (cc = keylen, rc = 1; cc < hi; cc += 4) {
+ uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if (cc % keylen == 0) {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ } else if (keylen > 24 && cc % keylen == 16) {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+/* Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch);
+
+ for (r = 1; r < ctx->rnd; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows(s1);
+ copy_and_key(out, s1, ctx->ksch + r * N_BLOCK);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ xor_block(iv, in);
+ if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+/* Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK);
+ inv_shift_sub_rows(s1);
+
+ for (r = ctx->rnd; --r;)
+#if defined(VERSION_1)
+ {
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, ctx->ksch);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_ENC_128_OTFK)
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if (o_key != key) block_copy(o_key, key);
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 10; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ update_encrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if (o_key != key) block_copy(o_key, key);
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 10; --r;)
+#if defined(VERSION_1)
+ {
+ update_decrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 20; cc < 32; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 14; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ if (r & 1)
+ add_round_key(s1, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ if (r & 1)
+ copy_and_key(s1, s2, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 28; cc > 16; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 14; --r;)
+#if defined(VERSION_1)
+ {
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key + 16);
+ } else
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ copy_and_key(s2, s1, o_key + 16);
+ } else
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
diff --git a/mtkbt/code/bt/stack/smp/aes.h b/mtkbt/code/bt/stack/smp/aes.h
new file mode 100755
index 0000000..2ff6fbd
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/aes.h
@@ -0,0 +1,154 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#if 1
+#define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
+#endif
+#if 1
+#define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */
+#endif
+#if 1
+#define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+#define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+#define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
+#endif
+#if 1
+#define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
+#endif
+
+#define N_ROW 4
+#define N_COL 4
+#define N_BLOCK (N_ROW * N_COL)
+#define N_MAX_ROUNDS 14
+
+typedef unsigned char uint_8t;
+
+typedef uint_8t return_type;
+
+/* Warning: The key length for 256 bit keys overflows a byte
+ (see comment below)
+*/
+
+typedef uint_8t length_type;
+
+typedef struct {
+ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
+ uint_8t rnd;
+} aes_context;
+
+/* The following calls are for a precomputed key schedule
+
+ NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]);
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]);
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]);
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]);
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]);
+#endif
+
+/* The following calls are for 'on the fly' keying. In this case the
+ encryption and decryption keys are different.
+
+ The encryption subroutines take a key in an array of bytes in
+ key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
+ 192, and 256 bits respectively. They then encrypts the input
+ data, in[] with this key and put the reult in the output array
+ out[]. In addition, the second key array, o_key[L], is used
+ to output the key that is needed by the decryption subroutine
+ to reverse the encryption operation. The two key arrays can
+ be the same array but in this case the original key will be
+ overwritten.
+
+ In the same way, the decryption subroutines output keys that
+ can be used to reverse their effect when used for encryption.
+
+ Only 128 and 256 bit keys are supported in these 'on the fly'
+ modes.
+*/
+
+#if defined(AES_ENC_128_OTFK)
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], uint_8t o_key[N_BLOCK]);
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]);
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]);
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]);
+#endif
+
+#endif
diff --git a/mtkbt/code/bt/stack/smp/p_256_curvepara.cc b/mtkbt/code/bt/stack/smp/p_256_curvepara.cc
new file mode 100755
index 0000000..d9bee31
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/p_256_curvepara.cc
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "p_256_ecc_pp.h"
+
+void p_256_init_curve(uint32_t keyLength) {
+ elliptic_curve_t* ec;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ ec = &curve_p256;
+
+ ec->p[7] = 0xFFFFFFFF;
+ ec->p[6] = 0x00000001;
+ ec->p[5] = 0x0;
+ ec->p[4] = 0x0;
+ ec->p[3] = 0x0;
+ ec->p[2] = 0xFFFFFFFF;
+ ec->p[1] = 0xFFFFFFFF;
+ ec->p[0] = 0xFFFFFFFF;
+
+ memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
+ memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
+
+ ec->a_minus3 = true;
+
+ // b
+ ec->b[7] = 0x5ac635d8;
+ ec->b[6] = 0xaa3a93e7;
+ ec->b[5] = 0xb3ebbd55;
+ ec->b[4] = 0x769886bc;
+ ec->b[3] = 0x651d06b0;
+ ec->b[2] = 0xcc53b0f6;
+ ec->b[1] = 0x3bce3c3e;
+ ec->b[0] = 0x27d2604b;
+
+ // base point
+ ec->G.x[7] = 0x6b17d1f2;
+ ec->G.x[6] = 0xe12c4247;
+ ec->G.x[5] = 0xf8bce6e5;
+ ec->G.x[4] = 0x63a440f2;
+ ec->G.x[3] = 0x77037d81;
+ ec->G.x[2] = 0x2deb33a0;
+ ec->G.x[1] = 0xf4a13945;
+ ec->G.x[0] = 0xd898c296;
+
+ ec->G.y[7] = 0x4fe342e2;
+ ec->G.y[6] = 0xfe1a7f9b;
+ ec->G.y[5] = 0x8ee7eb4a;
+ ec->G.y[4] = 0x7c0f9e16;
+ ec->G.y[3] = 0x2bce3357;
+ ec->G.y[2] = 0x6b315ece;
+ ec->G.y[1] = 0xcbb64068;
+ ec->G.y[0] = 0x37bf51f5;
+ }
+}
diff --git a/mtkbt/code/bt/stack/smp/p_256_ecc_pp.cc b/mtkbt/code/bt/stack/smp/p_256_ecc_pp.cc
new file mode 100755
index 0000000..b416e1d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/p_256_ecc_pp.cc
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ * Cryptography for private public key
+ *
+ ******************************************************************************/
+#include "p_256_ecc_pp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "p_256_multprecision.h"
+
+elliptic_curve_t curve;
+elliptic_curve_t curve_p256;
+
+static void p_256_init_point(Point* q) { memset(q, 0, sizeof(Point)); }
+
+static void p_256_copy_point(Point* q, Point* p) {
+ memcpy(q, p, sizeof(Point));
+}
+
+// q=2q
+static void ECC_Double(Point* q, Point* p, uint32_t keyLength) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t t3[KEY_LENGTH_DWORDS_P256];
+ uint32_t* x1;
+ uint32_t* x3;
+ uint32_t* y1;
+ uint32_t* y3;
+ uint32_t* z1;
+ uint32_t* z3;
+
+ if (multiprecision_iszero(p->z, keyLength)) {
+ multiprecision_init(q->z, keyLength);
+ return; // return infinity
+ }
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x3 = q->x;
+ y3 = q->y;
+ z3 = q->z;
+
+ multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2, keyLength);
+ multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2
+
+ multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3, keyLength);
+
+ multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3, keyLength);
+ multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3, keyLength);
+ multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3, keyLength);
+
+ multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3
+}
+
+// q=q+p, zp must be 1
+static void ECC_Add(Point* r, Point* p, Point* q, uint32_t keyLength) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t* x1;
+ uint32_t* x2;
+ uint32_t* x3;
+ uint32_t* y1;
+ uint32_t* y2;
+ uint32_t* y3;
+ uint32_t* z1;
+ uint32_t* z2;
+ uint32_t* z3;
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x2 = q->x;
+ y2 = q->y;
+ z2 = q->z;
+ x3 = r->x;
+ y3 = r->y;
+ z3 = r->z;
+
+ // if Q=infinity, return p
+ if (multiprecision_iszero(z2, keyLength)) {
+ p_256_copy_point(r, p);
+ return;
+ }
+
+ // if P=infinity, return q
+ if (multiprecision_iszero(z1, keyLength)) {
+ p_256_copy_point(r, q);
+ return;
+ }
+
+ multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2
+
+ multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1
+
+ if (multiprecision_iszero(t1, keyLength)) {
+ if (multiprecision_iszero(t2, keyLength)) {
+ ECC_Double(r, q, keyLength);
+ return;
+ } else {
+ multiprecision_init(z3, keyLength);
+ return; // return infinity
+ }
+ }
+
+ multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1, keyLength);
+}
+
+// Computing the Non-Adjacent Form of a positive integer
+static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k,
+ uint32_t keyLength) {
+ uint32_t sign;
+ int i = 0;
+ int j;
+ uint32_t var;
+
+ while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
+ if (k[0] & 0x01) // k is odd
+ {
+ sign = (k[0] & 0x03); // 1 or 3
+
+ // k = k-naf[i]
+ if (sign == 1)
+ k[0] = k[0] & 0xFFFFFFFE;
+ else {
+ k[0] = k[0] + 1;
+ if (k[0] == 0) // overflow
+ {
+ j = 1;
+ do {
+ k[j]++;
+ } while (k[j++] == 0); // overflow
+ }
+ }
+ } else
+ sign = 0;
+
+ multiprecision_rshift(k, k, keyLength);
+ naf[i / 4] |= (sign) << ((i % 4) * 2);
+ i++;
+ }
+
+ *NumNAF = i;
+}
+
+// Binary Non-Adjacent Form for point multiplication
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n,
+ uint32_t keyLength) {
+ uint32_t sign;
+ uint8_t naf[256 / 4 + 1];
+ uint32_t NumNaf;
+ Point minus_p;
+ Point r;
+ uint32_t* modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ modp = curve.p;
+ }
+
+ p_256_init_point(&r);
+ multiprecision_init(p->z, keyLength);
+ p->z[0] = 1;
+
+ // initialization
+ p_256_init_point(q);
+
+ // -p
+ multiprecision_copy(minus_p.x, p->x, keyLength);
+ multiprecision_sub(minus_p.y, modp, p->y, keyLength);
+
+ multiprecision_init(minus_p.z, keyLength);
+ minus_p.z[0] = 1;
+
+ // NAF
+ memset(naf, 0, sizeof(naf));
+ ECC_NAF(naf, &NumNaf, n, keyLength);
+
+ for (int i = NumNaf - 1; i >= 0; i--) {
+ p_256_copy_point(&r, q);
+ ECC_Double(q, &r, keyLength);
+ sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
+
+ if (sign == 1) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, p, keyLength);
+ } else if (sign == 3) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, &minus_p, keyLength);
+ }
+ }
+
+ multiprecision_inv_mod(minus_p.x, q->z, keyLength);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
+}
diff --git a/mtkbt/code/bt/stack/smp/p_256_ecc_pp.h b/mtkbt/code/bt/stack/smp/p_256_ecc_pp.h
new file mode 100755
index 0000000..dcc4211
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/p_256_ecc_pp.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ *Cryptography for private public key
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "p_256_multprecision.h"
+
+typedef struct {
+ uint32_t x[KEY_LENGTH_DWORDS_P256];
+ uint32_t y[KEY_LENGTH_DWORDS_P256];
+ uint32_t z[KEY_LENGTH_DWORDS_P256];
+} Point;
+
+typedef struct {
+ // curve's coefficients
+ uint32_t a[KEY_LENGTH_DWORDS_P256];
+ uint32_t b[KEY_LENGTH_DWORDS_P256];
+
+ // whether a is -3
+ int a_minus3;
+
+ // prime modulus
+ uint32_t p[KEY_LENGTH_DWORDS_P256];
+
+ // Omega, p = 2^m -omega
+ uint32_t omega[KEY_LENGTH_DWORDS_P256];
+
+ // base point, a point on E of order r
+ Point G;
+
+} elliptic_curve_t;
+
+extern elliptic_curve_t curve;
+extern elliptic_curve_t curve_p256;
+
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n, uint32_t keyLength);
+
+#define ECC_PointMult(q, p, n, keyLength) \
+ ECC_PointMult_Bin_NAF(q, p, n, keyLength)
+
+void p_256_init_curve(uint32_t keyLength);
diff --git a/mtkbt/code/bt/stack/smp/p_256_multprecision.cc b/mtkbt/code/bt/stack/smp/p_256_multprecision.cc
new file mode 100755
index 0000000..a44ea0c
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/p_256_multprecision.cc
@@ -0,0 +1,614 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include "p_256_multprecision.h"
+#include <string.h>
+#include "bt_target.h"
+#include "p_256_ecc_pp.h"
+
+void multiprecision_init(uint32_t* c, uint32_t keyLength) {
+ for (uint32_t i = 0; i < keyLength; i++) c[i] = 0;
+}
+
+void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+ for (uint32_t i = 0; i < keyLength; i++) c[i] = a[i];
+}
+
+int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength) {
+ for (int i = keyLength - 1; i >= 0; i--) {
+ if (a[i] > b[i]) return 1;
+ if (a[i] < b[i]) return -1;
+ }
+ return 0;
+}
+
+int multiprecision_iszero(uint32_t* a, uint32_t keyLength) {
+ for (uint32_t i = 0; i < keyLength; i++)
+ if (a[i]) return 0;
+
+ return 1;
+}
+
+uint32_t multiprecision_dword_bits(uint32_t a) {
+ uint32_t i;
+ for (i = 0; i < DWORD_BITS; i++, a >>= 1)
+ if (a == 0) break;
+
+ return i;
+}
+
+uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength) {
+ int i;
+ for (i = keyLength - 1; i >= 0; i--)
+ if (a[i]) break;
+ return (i + 1);
+}
+
+uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength) {
+ int aMostSignDWORDs;
+
+ aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength);
+ if (aMostSignDWORDs == 0) return 0;
+
+ return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) +
+ multiprecision_dword_bits(a[aMostSignDWORDs - 1]));
+}
+
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t carrier;
+ uint32_t temp;
+
+ carrier = 0;
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i] + carrier;
+ carrier = (temp < carrier);
+ temp += b[i];
+ carrier |= (temp < b[i]);
+ c[i] = temp;
+ }
+
+ return carrier;
+}
+
+// c=a-b
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t borrow;
+ uint32_t temp;
+
+ borrow = 0;
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i] - borrow;
+ borrow = (temp > a[i]);
+ c[i] = temp - b[i];
+ borrow |= (c[i] > temp);
+ }
+
+ return borrow;
+}
+
+// c = a << 1
+void multiprecision_lshift_mod(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+ uint32_t carrier;
+ uint32_t* modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else
+ return;
+
+ carrier = multiprecision_lshift(c, a, keyLength);
+ if (carrier) {
+ multiprecision_sub(c, c, modp, keyLength);
+ } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
+ multiprecision_sub(c, c, modp, keyLength);
+ }
+}
+
+// c=a>>1
+void multiprecision_rshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+ int j;
+ uint32_t b = 1;
+
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+ for (int i = keyLength - 1; i >= 0; i--) {
+ temp = a[i]; // in case of c==a
+ c[i] = (temp >> b) | carrier;
+ carrier = temp << j;
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime,
+// p=2^(KEY_LENGTH_BITS)-omega
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t cc[2 * KEY_LENGTH_DWORDS_P256];
+
+ multiprecision_mult(cc, a, b, keyLength);
+ if (keyLength == 6) {
+ multiprecision_fast_mod(c, cc);
+ } else if (keyLength == 8) {
+ multiprecision_fast_mod_P256(c, cc);
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
+ uint32_t keyLength) {
+ multiprecision_mersenns_mult_mod(c, a, a, keyLength);
+}
+
+// c=(a+b) mod p, b<p, a<p
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t carrier;
+ uint32_t* modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else
+ return;
+
+ carrier = multiprecision_add(c, a, b, keyLength);
+ if (carrier) {
+ multiprecision_sub(c, c, modp, keyLength);
+ } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
+ multiprecision_sub(c, c, modp, keyLength);
+ }
+}
+
+// c=(a-b) mod p, a<p, b<p
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t borrow;
+ uint32_t* modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P192) {
+ modp = curve.p;
+ } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else
+ return;
+
+ borrow = multiprecision_sub(c, a, b, keyLength);
+ if (borrow) multiprecision_add(c, c, modp, keyLength);
+}
+
+// c=a<<b, b<DWORD_BITS, c has a buffer size of Numuint32_ts+1
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+ int j;
+ uint32_t b = 1;
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+
+ for (uint32_t i = 0; i < keyLength; i++) {
+ temp = a[i]; // in case c==a
+ c[i] = (temp << b) | carrier;
+ carrier = temp >> j;
+ }
+
+ return carrier;
+}
+
+// c=a*b; c must have a buffer of 2*Key_LENGTH_uint32_tS, c != a != b
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength) {
+ uint32_t W;
+ uint32_t U;
+ uint32_t V;
+
+ U = V = W = 0;
+ multiprecision_init(c, keyLength);
+
+ // assume little endian right now
+ for (uint32_t i = 0; i < keyLength; i++) {
+ U = 0;
+ for (uint32_t j = 0; j < keyLength; j++) {
+ uint64_t result;
+ result = ((uint64_t)a[i]) * ((uint64_t)b[j]);
+ W = result >> 32;
+ V = a[i] * b[j];
+ V = V + U;
+ U = (V < U);
+ U += W;
+ V = V + c[i + j];
+ U += (V < c[i + j]);
+ c[i + j] = V;
+ }
+ c[i + keyLength] = U;
+ }
+}
+
+void multiprecision_fast_mod(uint32_t* c, uint32_t* a) {
+ uint32_t U;
+ uint32_t V;
+ uint32_t* modp = curve.p;
+
+ c[0] = a[0] + a[6];
+ U = c[0] < a[0];
+ c[0] += a[10];
+ U += c[0] < a[10];
+
+ c[1] = a[1] + U;
+ U = c[1] < a[1];
+ c[1] += a[7];
+ U += c[1] < a[7];
+ c[1] += a[11];
+ U += c[1] < a[11];
+
+ c[2] = a[2] + U;
+ U = c[2] < a[2];
+ c[2] += a[6];
+ U += c[2] < a[6];
+ c[2] += a[8];
+ U += c[2] < a[8];
+ c[2] += a[10];
+ U += c[2] < a[10];
+
+ c[3] = a[3] + U;
+ U = c[3] < a[3];
+ c[3] += a[7];
+ U += c[3] < a[7];
+ c[3] += a[9];
+ U += c[3] < a[9];
+ c[3] += a[11];
+ U += c[3] < a[11];
+
+ c[4] = a[4] + U;
+ U = c[4] < a[4];
+ c[4] += a[8];
+ U += c[4] < a[8];
+ c[4] += a[10];
+ U += c[4] < a[10];
+
+ c[5] = a[5] + U;
+ U = c[5] < a[5];
+ c[5] += a[9];
+ U += c[5] < a[9];
+ c[5] += a[11];
+ U += c[5] < a[11];
+
+ c[0] += U;
+ V = c[0] < U;
+ c[1] += V;
+ V = c[1] < V;
+ c[2] += V;
+ V = c[2] < V;
+ c[2] += U;
+ V = c[2] < U;
+ c[3] += V;
+ V = c[3] < V;
+ c[4] += V;
+ V = c[4] < V;
+ c[5] += V;
+ V = c[5] < V;
+
+ if (V) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ } else if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ }
+}
+
+void multiprecision_fast_mod_P256(uint32_t* c, uint32_t* a) {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint32_t E;
+ uint32_t F;
+ uint32_t G;
+ uint8_t UA;
+ uint8_t UB;
+ uint8_t UC;
+ uint8_t UD;
+ uint8_t UE;
+ uint8_t UF;
+ uint8_t UG;
+ uint32_t U;
+ uint32_t* modp = curve_p256.p;
+
+ // C = a[13] + a[14] + a[15];
+ C = a[13];
+ C += a[14];
+ UC = (C < a[14]);
+ C += a[15];
+ UC += (C < a[15]);
+
+ // E = a[8] + a[9];
+ E = a[8];
+ E += a[9];
+ UE = (E < a[9]);
+
+ // F = a[9] + a[10];
+ F = a[9];
+ F += a[10];
+ UF = (F < a[10]);
+
+ // G = a[10] + a[11]
+ G = a[10];
+ G += a[11];
+ UG = (G < a[11]);
+
+ // B = a[12] + a[13] + a[14] + a[15] == C + a[12]
+ B = C;
+ UB = UC;
+ B += a[12];
+ UB += (B < a[12]);
+
+ // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15]
+ A = B;
+ UA = UB;
+ A += a[11];
+ UA += (A < a[11]);
+ UA -= (A < a[15]);
+ A -= a[15];
+
+ // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14]
+ D = A;
+ UD = UA;
+ D += a[10];
+ UD += (D < a[10]);
+ UD -= (D < a[14]);
+ D -= a[14];
+
+ c[0] = a[0];
+ c[0] += E;
+ U = (c[0] < E);
+ U += UE;
+ U -= (c[0] < A);
+ U -= UA;
+ c[0] -= A;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[1] < UU);
+ c[1] = a[1] - UU;
+ } else {
+ c[1] = a[1] + U;
+ U = (c[1] < a[1]);
+ }
+
+ c[1] += F;
+ U += (c[1] < F);
+ U += UF;
+ U -= (c[1] < B);
+ U -= UB;
+ c[1] -= B;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[2] < UU);
+ c[2] = a[2] - UU;
+ } else {
+ c[2] = a[2] + U;
+ U = (c[2] < a[2]);
+ }
+
+ c[2] += G;
+ U += (c[2] < G);
+ U += UG;
+ U -= (c[2] < C);
+ U -= UC;
+ c[2] -= C;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[3] < UU);
+ c[3] = a[3] - UU;
+ } else {
+ c[3] = a[3] + U;
+ U = (c[3] < a[3]);
+ }
+
+ c[3] += A;
+ U += (c[3] < A);
+ U += UA;
+ c[3] += a[11];
+ U += (c[3] < a[11]);
+ c[3] += a[12];
+ U += (c[3] < a[12]);
+ U -= (c[3] < a[14]);
+ c[3] -= a[14];
+ U -= (c[3] < a[15]);
+ c[3] -= a[15];
+ U -= (c[3] < E);
+ U -= UE;
+ c[3] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[4] < UU);
+ c[4] = a[4] - UU;
+ } else {
+ c[4] = a[4] + U;
+ U = (c[4] < a[4]);
+ }
+
+ c[4] += B;
+ U += (c[4] < B);
+ U += UB;
+ U -= (c[4] < a[15]);
+ c[4] -= a[15];
+ c[4] += a[12];
+ U += (c[4] < a[12]);
+ c[4] += a[13];
+ U += (c[4] < a[13]);
+ U -= (c[4] < F);
+ U -= UF;
+ c[4] -= F;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[5] < UU);
+ c[5] = a[5] - UU;
+ } else {
+ c[5] = a[5] + U;
+ U = (c[5] < a[5]);
+ }
+
+ c[5] += C;
+ U += (c[5] < C);
+ U += UC;
+ c[5] += a[13];
+ U += (c[5] < a[13]);
+ c[5] += a[14];
+ U += (c[5] < a[14]);
+ U -= (c[5] < G);
+ U -= UG;
+ c[5] -= G;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[6] < UU);
+ c[6] = a[6] - UU;
+ } else {
+ c[6] = a[6] + U;
+ U = (c[6] < a[6]);
+ }
+
+ c[6] += C;
+ U += (c[6] < C);
+ U += UC;
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[15];
+ U += (c[6] < a[15]);
+ U -= (c[6] < E);
+ U -= UE;
+ c[6] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[7] < UU);
+ c[7] = a[7] - UU;
+ } else {
+ c[7] = a[7] + U;
+ U = (c[7] < a[7]);
+ }
+
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[8];
+ U += (c[7] < a[8]);
+ U -= (c[7] < D);
+ U -= UD;
+ c[7] -= D;
+
+ if (U & 0x80000000) {
+ while (U) {
+ multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ U++;
+ }
+ } else if (U) {
+ while (U) {
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ U--;
+ }
+ }
+
+ if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256) >= 0)
+ multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+}
+
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u, uint32_t keyLength) {
+ uint32_t v[KEY_LENGTH_DWORDS_P256];
+ uint32_t A[KEY_LENGTH_DWORDS_P256 + 1];
+ uint32_t C[KEY_LENGTH_DWORDS_P256 + 1];
+ uint32_t* modp;
+
+ if (keyLength == KEY_LENGTH_DWORDS_P256) {
+ modp = curve_p256.p;
+ } else {
+ modp = curve.p;
+ }
+
+ multiprecision_copy(v, modp, keyLength);
+ multiprecision_init(A, keyLength);
+ multiprecision_init(C, keyLength);
+ A[0] = 1;
+
+ while (!multiprecision_iszero(u, keyLength)) {
+ while (!(u[0] & 0x01)) // u is even
+ {
+ multiprecision_rshift(u, u, keyLength);
+ if (!(A[0] & 0x01)) // A is even
+ multiprecision_rshift(A, A, keyLength);
+ else {
+ A[keyLength] = multiprecision_add(A, A, modp, keyLength); // A =A+p
+ multiprecision_rshift(A, A, keyLength);
+ A[keyLength - 1] |= (A[keyLength] << 31);
+ }
+ }
+
+ while (!(v[0] & 0x01)) // v is even
+ {
+ multiprecision_rshift(v, v, keyLength);
+ if (!(C[0] & 0x01)) // C is even
+ {
+ multiprecision_rshift(C, C, keyLength);
+ } else {
+ C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p
+ multiprecision_rshift(C, C, keyLength);
+ C[keyLength - 1] |= (C[keyLength] << 31);
+ }
+ }
+
+ if (multiprecision_compare(u, v, keyLength) >= 0) {
+ multiprecision_sub(u, u, v, keyLength);
+ multiprecision_sub_mod(A, A, C, keyLength);
+ } else {
+ multiprecision_sub(v, v, u, keyLength);
+ multiprecision_sub_mod(C, C, A, keyLength);
+ }
+ }
+
+ if (multiprecision_compare(C, modp, keyLength) >= 0)
+ multiprecision_sub(aminus, C, modp, keyLength);
+ else
+ multiprecision_copy(aminus, C, keyLength);
+}
diff --git a/mtkbt/code/bt/stack/smp/p_256_multprecision.h b/mtkbt/code/bt/stack/smp/p_256_multprecision.h
new file mode 100755
index 0000000..ca5311b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/p_256_multprecision.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2006-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "bt_types.h"
+
+#define DWORD_BITS 32
+#define DWORD_BYTES 4
+#define DWORD_BITS_SHIFT 5
+
+#define KEY_LENGTH_DWORDS_P192 6
+#define KEY_LENGTH_DWORDS_P256 8
+/* Arithmetic Operations */
+
+int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength);
+int multiprecision_iszero(uint32_t* a, uint32_t keyLength);
+void multiprecision_init(uint32_t* c, uint32_t keyLength);
+void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength);
+uint32_t multiprecision_dword_bits(uint32_t a);
+uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength);
+uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength);
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a, uint32_t keyLength);
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength); // c=a+b
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength);
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength); // c=a-b
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength);
+void multiprecision_rshift(uint32_t* c, uint32_t* a,
+ uint32_t keyLength); // c=a>>1, return carrier
+void multiprecision_lshift_mod(uint32_t* c, uint32_t* a,
+ uint32_t keyLength); // c=a<<b, return carrier
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a,
+ uint32_t keyLength); // c=a<<b, return carrier
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength); // c=a*b
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength);
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
+ uint32_t keyLength);
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength);
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
+ uint32_t keyLength);
+void multiprecision_fast_mod(uint32_t* c, uint32_t* a);
+void multiprecision_fast_mod_P256(uint32_t* c, uint32_t* a);
diff --git a/mtkbt/code/bt/stack/smp/smp_act.cc b/mtkbt/code/bt/stack/smp/smp_act.cc
new file mode 100755
index 0000000..51b8972
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_act.cc
@@ -0,0 +1,2017 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "btif_common.h"
+#include "device/include/interop.h"
+#include "include/bt_target.h"
+#include "stack/btm/btm_int.h"
+#include "stack/include/l2c_api.h"
+#include "stack/smp/smp_int.h"
+#include "utils/include/bt_utils.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+#define SMP_KEY_DIST_TYPE_MAX 4
+const tSMP_ACT smp_distribute_act[] = {smp_generate_ltk, smp_send_id_info,
+ smp_generate_csrk,
+ smp_set_derive_link_key};
+
+static bool lmp_version_below(BD_ADDR bda, uint8_t version) {
+ tACL_CONN* acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE);
+ if (acl == NULL || acl->lmp_version == 0) {
+ SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
+ return false;
+ }
+ SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version,
+ version);
+ return acl->lmp_version < version;
+}
+
+static bool pts_test_send_authentication_complete_failure(tSMP_CB* p_cb) {
+ uint8_t reason = 0;
+
+ if (p_cb->cert_failure < 2 || p_cb->cert_failure > 6) return false;
+
+ SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+
+ switch (p_cb->cert_failure) {
+ case 2:
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ case 3:
+ reason = SMP_PAIR_FAIL_UNKNOWN;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ case 4:
+ reason = SMP_PAIR_NOT_SUPPORT;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ case 5:
+ reason = SMP_PASSKEY_ENTRY_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ case 6:
+ reason = SMP_REPEATED_ATTEMPTS;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ }
+
+ return true;
+ ;
+}
+
+/*******************************************************************************
+ * Function smp_update_key_mask
+ * Description This function updates the key mask for sending or receiving.
+ ******************************************************************************/
+static void smp_update_key_mask(tSMP_CB* p_cb, uint8_t key_type, bool recv) {
+ SMP_TRACE_DEBUG(
+ "%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x",
+ __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key);
+
+ if (((p_cb->le_secure_connections_mode_is_used) || (p_cb->smp_over_br)) &&
+ ((key_type == SMP_SEC_KEY_TYPE_ENC) ||
+ (key_type == SMP_SEC_KEY_TYPE_LK))) {
+ /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of
+ ** being exchanged with the peer */
+ p_cb->local_i_key &= ~key_type;
+ p_cb->local_r_key &= ~key_type;
+ } else if (p_cb->role == HCI_ROLE_SLAVE) {
+ if (recv)
+ p_cb->local_i_key &= ~key_type;
+ else
+ p_cb->local_r_key &= ~key_type;
+ } else {
+ if (recv)
+ p_cb->local_r_key &= ~key_type;
+ else
+ p_cb->local_i_key &= ~key_type;
+ }
+
+ SMP_TRACE_DEBUG("updated local_i_key = %02x, local_r_key = %02x",
+ p_cb->local_i_key, p_cb->local_r_key);
+}
+
+/*******************************************************************************
+ * Function smp_send_app_cback
+ * Description notifies application about the events the application is
+ * interested in
+ ******************************************************************************/
+void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tSMP_EVT_DATA cb_data;
+ tSMP_STATUS callback_rc;
+ SMP_TRACE_DEBUG("%s p_cb->cb_evt=%d", __func__, p_cb->cb_evt);
+ if (p_cb->p_callback && p_cb->cb_evt != 0) {
+ switch (p_cb->cb_evt) {
+ case SMP_IO_CAP_REQ_EVT:
+ cb_data.io_req.auth_req = p_cb->peer_auth_req;
+ cb_data.io_req.oob_data = SMP_OOB_NONE;
+ cb_data.io_req.io_cap = SMP_DEFAULT_IO_CAPS;
+ cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ cb_data.io_req.init_keys = p_cb->local_i_key;
+ cb_data.io_req.resp_keys = p_cb->local_r_key;
+ SMP_TRACE_WARNING("io_cap = %d", cb_data.io_req.io_cap);
+ break;
+
+ case SMP_NC_REQ_EVT:
+ cb_data.passkey = p_data->passkey;
+ break;
+ case SMP_SC_OOB_REQ_EVT:
+ cb_data.req_oob_type = p_data->req_oob_type;
+ break;
+ case SMP_SC_LOC_OOB_DATA_UP_EVT:
+ cb_data.loc_oob_data = p_cb->sc_oob_data.loc_oob_data;
+ break;
+
+ case SMP_BR_KEYS_REQ_EVT:
+ cb_data.io_req.auth_req = 0;
+ cb_data.io_req.oob_data = SMP_OOB_NONE;
+ cb_data.io_req.io_cap = 0;
+ cb_data.io_req.max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ cb_data.io_req.init_keys = SMP_BR_SEC_DEFAULT_KEY;
+ cb_data.io_req.resp_keys = SMP_BR_SEC_DEFAULT_KEY;
+ break;
+
+ default:
+ break;
+ }
+
+ callback_rc =
+ (*p_cb->p_callback)(p_cb->cb_evt, p_cb->pairing_bda, &cb_data);
+
+ SMP_TRACE_DEBUG("%s: callback_rc=%d p_cb->cb_evt=%d", __func__,
+ callback_rc, p_cb->cb_evt);
+
+ if (callback_rc == SMP_SUCCESS) {
+ switch (p_cb->cb_evt) {
+ case SMP_IO_CAP_REQ_EVT:
+ p_cb->loc_auth_req = cb_data.io_req.auth_req;
+ p_cb->local_io_capability = cb_data.io_req.io_cap;
+ p_cb->loc_oob_flag = cb_data.io_req.oob_data;
+ p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+ p_cb->local_i_key = cb_data.io_req.init_keys;
+ p_cb->local_r_key = cb_data.io_req.resp_keys;
+
+ if (!(p_cb->loc_auth_req & SMP_AUTH_BOND)) {
+ SMP_TRACE_WARNING("Non bonding: No keys will be exchanged");
+ p_cb->local_i_key = 0;
+ p_cb->local_r_key = 0;
+ }
+
+ SMP_TRACE_WARNING(
+ "rcvd auth_req: 0x%02x, io_cap: %d \
+ loc_oob_flag: %d loc_enc_size: %d,"
+ "local_i_key: 0x%02x, local_r_key: 0x%02x",
+ p_cb->loc_auth_req, p_cb->local_io_capability, p_cb->loc_oob_flag,
+ p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key);
+
+ p_cb->secure_connections_only_mode_required =
+ (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false;
+
+ if (p_cb->secure_connections_only_mode_required) {
+ p_cb->loc_auth_req |= SMP_SC_SUPPORT_BIT;
+ }
+
+ if (!(p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ||
+ lmp_version_below(p_cb->pairing_bda, HCI_PROTO_VERSION_4_2) ||
+ interop_match_addr(INTEROP_DISABLE_LE_SECURE_CONNECTIONS,
+ (const bt_bdaddr_t*)&p_cb->pairing_bda)) {
+ p_cb->loc_auth_req &= ~SMP_KP_SUPPORT_BIT;
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ SMP_TRACE_WARNING(
+ "set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x",
+ p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key);
+
+ smp_sm_event(p_cb, SMP_IO_RSP_EVT, NULL);
+ break;
+
+ case SMP_BR_KEYS_REQ_EVT:
+ p_cb->loc_enc_size = cb_data.io_req.max_key_size;
+ p_cb->local_i_key = cb_data.io_req.init_keys;
+ p_cb->local_r_key = cb_data.io_req.resp_keys;
+ p_cb->loc_auth_req |= SMP_H7_SUPPORT_BIT;
+
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+ SMP_TRACE_WARNING(
+ "for SMP over BR max_key_size: 0x%02x,\
+ local_i_key: 0x%02x, local_r_key: 0x%02x, p_cb->loc_auth_req: 0x%02x",
+ p_cb->loc_enc_size, p_cb->local_i_key, p_cb->local_r_key,
+ p_cb->loc_auth_req);
+
+ smp_br_state_machine_event(p_cb, SMP_BR_KEYS_RSP_EVT, NULL);
+ break;
+ }
+ }
+ }
+
+ if (!p_cb->cb_evt && p_cb->discard_sec_req) {
+ p_cb->discard_sec_req = false;
+ smp_sm_event(p_cb, SMP_DISCARD_SEC_REQ_EVT, NULL);
+ }
+
+ SMP_TRACE_DEBUG("%s return", __func__);
+}
+
+/*******************************************************************************
+ * Function smp_send_pair_fail
+ * Description pairing failure to peer device if needed.
+ ******************************************************************************/
+void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ p_cb->status = *(uint8_t*)p_data;
+ p_cb->failure = *(uint8_t*)p_data;
+
+ SMP_TRACE_DEBUG("%s status=%d failure=%d ", __func__, p_cb->status,
+ p_cb->failure);
+
+ if (p_cb->status <= SMP_MAX_FAIL_RSN_PER_SPEC &&
+ p_cb->status != SMP_SUCCESS) {
+ smp_send_cmd(SMP_OPCODE_PAIRING_FAILED, p_cb);
+ p_cb->wait_for_authorization_complete = true;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_send_pair_req
+ * Description actions related to sending pairing request
+ ******************************************************************************/
+void smp_send_pair_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ /* erase all keys when master sends pairing req*/
+ if (p_dev_rec) btm_sec_clear_ble_keys(p_dev_rec);
+ /* do not manipulate the key, let app decide,
+ leave out to BTM to mandate key distribution for bonding case */
+ smp_send_cmd(SMP_OPCODE_PAIRING_REQ, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_pair_rsp
+ * Description actions related to sending pairing response
+ ******************************************************************************/
+void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+
+ if (smp_send_cmd(SMP_OPCODE_PAIRING_RSP, p_cb)) {
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB)
+ smp_use_oob_private_key(p_cb, NULL);
+ else
+ smp_decide_association_model(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_send_confirm
+ * Description send confirmation to the peer
+ ******************************************************************************/
+void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_CONFIRM, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_init
+ * Description process pairing initializer to slave device
+ ******************************************************************************/
+void smp_send_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_INIT, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_rand
+ * Description send pairing random to the peer
+ ******************************************************************************/
+void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_RAND, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_pair_public_key
+ * Description send pairing public key command to the peer
+ ******************************************************************************/
+void smp_send_pair_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_PUBLIC_KEY, p_cb);
+}
+
+/*******************************************************************************
+ * Function SMP_SEND_COMMITMENT
+ * Description send commitment command to the peer
+ ******************************************************************************/
+void smp_send_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_COMMITM, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_dhkey_check
+ * Description send DHKey Check command to the peer
+ ******************************************************************************/
+void smp_send_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_send_cmd(SMP_OPCODE_PAIR_DHKEY_CHECK, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_keypress_notification
+ * Description send Keypress Notification command to the peer
+ ******************************************************************************/
+void smp_send_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ p_cb->local_keypress_notification = *(uint8_t*)p_data;
+ smp_send_cmd(SMP_OPCODE_PAIR_KEYPR_NOTIF, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_send_enc_info
+ * Description send encryption information command.
+ ******************************************************************************/
+void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_LE_LENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s p_cb->loc_enc_size = %d", __func__, p_cb->loc_enc_size);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+
+ smp_send_cmd(SMP_OPCODE_ENCRYPT_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_MASTER_ID, p_cb);
+
+ /* save the DIV and key size information when acting as slave device */
+ memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.div = p_cb->div;
+ le_key.key_size = p_cb->loc_enc_size;
+ le_key.sec_level = p_cb->sec_level;
+
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
+ (p_cb->loc_auth_req & SMP_AUTH_BOND))
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC,
+ (tBTM_LE_KEY_VALUE*)&le_key, true);
+
+ SMP_TRACE_WARNING("%s", __func__);
+
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_send_id_info
+ * Description send ID information command.
+ ******************************************************************************/
+void smp_send_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_LE_KEY_VALUE le_key;
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ID, false);
+
+ smp_send_cmd(SMP_OPCODE_IDENTITY_INFO, p_cb);
+ smp_send_cmd(SMP_OPCODE_ID_ADDR, p_cb);
+
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
+ (p_cb->loc_auth_req & SMP_AUTH_BOND))
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LID, &le_key, true);
+
+ SMP_TRACE_WARNING("%s", __func__);
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_send_csrk_info
+ * Description send CSRK command.
+ ******************************************************************************/
+void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_LE_LCSRK_KEYS key;
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_CSRK, false);
+
+ if (smp_send_cmd(SMP_OPCODE_SIGN_INFO, p_cb)) {
+ key.div = p_cb->div;
+ key.sec_level = p_cb->sec_level;
+ key.counter = 0; /* initialize the local counter */
+ memcpy(key.csrk, p_cb->csrk, BT_OCTET16_LEN);
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LCSRK,
+ (tBTM_LE_KEY_VALUE*)&key, true);
+ }
+
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_send_ltk_reply
+ * Description send LTK reply
+ ******************************************************************************/
+void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* send stk as LTK response */
+ btm_ble_ltk_request_reply(p_cb->pairing_bda, true, p_data->key.p_data);
+}
+
+/*******************************************************************************
+ * Function smp_proc_sec_req
+ * Description process security request.
+ ******************************************************************************/
+void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_LE_AUTH_REQ auth_req = *(tBTM_LE_AUTH_REQ*)p_data;
+ tBTM_BLE_SEC_REQ_ACT sec_req_act;
+ uint8_t reason;
+
+ SMP_TRACE_DEBUG("%s auth_req=0x%x", __func__, auth_req);
+
+ p_cb->cb_evt = 0;
+
+ btm_ble_link_sec_check(p_cb->pairing_bda, auth_req, &sec_req_act);
+
+ SMP_TRACE_DEBUG("%s sec_req_act=0x%x", __func__, sec_req_act);
+
+ switch (sec_req_act) {
+ case BTM_BLE_SEC_REQ_ACT_ENCRYPT:
+ SMP_TRACE_DEBUG("%s BTM_BLE_SEC_REQ_ACT_ENCRYPT", __func__);
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_PAIR:
+ p_cb->secure_connections_only_mode_required =
+ (btm_cb.security_mode == BTM_SEC_MODE_SC) ? true : false;
+
+ /* respond to non SC pairing request as failure in SC only mode */
+ if (p_cb->secure_connections_only_mode_required &&
+ (auth_req & SMP_SC_SUPPORT_BIT) == 0) {
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ } else {
+ /* initialize local i/r key to be default keys */
+ p_cb->peer_auth_req = auth_req;
+ p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ }
+ break;
+
+ case BTM_BLE_SEC_REQ_ACT_DISCARD:
+ p_cb->discard_sec_req = true;
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_proc_sec_grant
+ * Description process security grant.
+ ******************************************************************************/
+void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t res = *(uint8_t*)p_data;
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (res != SMP_SUCCESS) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, p_data);
+ } else /*otherwise, start pairing */
+ {
+ /* send IO request callback */
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_proc_pair_fail
+ * Description process pairing failure from peer device
+ ******************************************************************************/
+void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->status = *(uint8_t*)p_data;
+
+ /* Cancel pending auth complete timer if set */
+ alarm_cancel(p_cb->delayed_auth_timer_ent);
+}
+
+/*******************************************************************************
+ * Function smp_proc_pair_cmd
+ * Description Process the SMP pairing request/response from peer device
+ ******************************************************************************/
+void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_ENC_KEY_SIZE;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* erase all keys if it is slave proc pairing req*/
+ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
+ btm_sec_clear_ble_keys(p_dev_rec);
+
+ p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+ STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+ STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+ STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+ STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+ STREAM_TO_UINT8(p_cb->peer_i_key, p);
+ STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ reason = SMP_INVALID_PARAMETERS;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ // PTS Testing failure modes
+ if (pts_test_send_authentication_complete_failure(p_cb)) return;
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
+ /* peer (master) started pairing sending Pairing Request */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ p_cb->cb_evt = SMP_SEC_REQUEST_EVT;
+ } else /* update local i/r key according to pairing request */
+ {
+ /* pairing started with this side (slave) sending Security Request */
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model ==
+ SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR(
+ "%s pairing failed - slave requires secure connection only mode",
+ __func__);
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) {
+ if (smp_request_oob_data(p_cb)) return;
+ } else {
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+ }
+ } else /* Master receives pairing response */
+ {
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR(
+ "Master requires secure connection only mode \
+ but it can't be provided -> Master fails pairing");
+ reason = SMP_PAIR_AUTH_FAIL;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) {
+ if (smp_request_oob_data(p_cb)) return;
+ } else {
+ smp_decide_association_model(p_cb, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+ * Function smp_proc_confirm
+ * Description process pairing confirm from peer device
+ ******************************************************************************/
+void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ /* save the SConfirm for comparison later */
+ STREAM_TO_ARRAY(p_cb->rconfirm, p, BT_OCTET16_LEN);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAGS_CMD_CONFIRM;
+}
+
+/*******************************************************************************
+ * Function smp_proc_init
+ * Description process pairing initializer from peer device
+ ******************************************************************************/
+void smp_proc_init(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ * Function smp_proc_rand
+ * Description process pairing random (nonce) from peer device
+ ******************************************************************************/
+void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* save the SRand for comparison */
+ STREAM_TO_ARRAY(p_cb->rrand, p, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ * Function smp_process_pairing_public_key
+ * Description process pairing public key command from the peer device
+ * - saves the peer public key;
+ * - sets the flag indicating that the peer public key is received;
+ * - calls smp_wait_for_both_public_keys(...).
+ *
+ ******************************************************************************/
+void smp_process_pairing_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
+ STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
+
+ smp_wait_for_both_public_keys(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_process_pairing_commitment
+ * Description process pairing commitment from peer device
+ ******************************************************************************/
+void smp_process_pairing_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_COMM;
+
+ if (p != NULL) {
+ STREAM_TO_ARRAY(p_cb->remote_commitment, p, BT_OCTET16_LEN);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_process_dhkey_check
+ * Description process DHKey Check from peer device
+ ******************************************************************************/
+void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ STREAM_TO_ARRAY(p_cb->remote_dhkey_check, p, BT_OCTET16_LEN);
+ }
+
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK;
+}
+
+/*******************************************************************************
+ * Function smp_process_keypress_notification
+ * Description process pairing keypress notification from peer device
+ ******************************************************************************/
+void smp_process_keypress_notification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_INVALID_PARAMETERS;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->status = *(uint8_t*)p_data;
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p != NULL) {
+ STREAM_TO_UINT8(p_cb->peer_keypress_notification, p);
+ } else {
+ p_cb->peer_keypress_notification = BTM_SP_KEY_OUT_OF_RANGE;
+ }
+ p_cb->cb_evt = SMP_PEER_KEYPR_NOT_EVT;
+}
+
+/*******************************************************************************
+ * Function smp_br_process_pairing_command
+ * Description Process the SMP pairing request/response from peer device via
+ * BR/EDR transport.
+ ******************************************************************************/
+void smp_br_process_pairing_command(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ uint8_t reason = SMP_ENC_KEY_SIZE;
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* rejecting BR pairing request over non-SC BR link */
+ if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) {
+ reason = SMP_XTRANS_DERIVE_NOT_ALLOW;
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* erase all keys if it is slave proc pairing req*/
+ if (p_dev_rec && (p_cb->role == HCI_ROLE_SLAVE))
+ btm_sec_clear_ble_keys(p_dev_rec);
+
+ p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
+
+ STREAM_TO_UINT8(p_cb->peer_io_caps, p);
+ STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
+ STREAM_TO_UINT8(p_cb->peer_auth_req, p);
+ STREAM_TO_UINT8(p_cb->peer_enc_size, p);
+ STREAM_TO_UINT8(p_cb->peer_i_key, p);
+ STREAM_TO_UINT8(p_cb->peer_r_key, p);
+
+ if (smp_command_has_invalid_parameters(p_cb)) {
+ reason = SMP_INVALID_PARAMETERS;
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ /* peer (master) started pairing sending Pairing Request */
+ /* or being master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ p_dev_rec->new_encryption_key_is_p256 = false;
+ /* shortcut to skip Security Grant step */
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ } else /* Master receives pairing response */
+ {
+ SMP_TRACE_DEBUG(
+ "%s master rcvs valid PAIRING RESPONSE."
+ " Supposed to move to key distribution phase. ",
+ __func__);
+ }
+
+ /* auth_req received via BR/EDR SM channel is set to 0,
+ but everything derived/exchanged has to be saved */
+ p_cb->peer_auth_req |= SMP_AUTH_BOND;
+ p_cb->loc_auth_req |= SMP_AUTH_BOND;
+}
+
+/*******************************************************************************
+ * Function smp_br_process_security_grant
+ * Description process security grant in case of pairing over BR/EDR transport.
+ ******************************************************************************/
+void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t res = *(uint8_t*)p_data;
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (res != SMP_SUCCESS) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, p_data);
+ } else /*otherwise, start pairing */
+ {
+ /* send IO request callback */
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_br_check_authorization_request
+ * Description sets the SMP kes to be derived/distribute over BR/EDR transport
+ * before starting the distribution/derivation
+ ******************************************************************************/
+void smp_br_check_authorization_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason = SMP_SUCCESS;
+
+ SMP_TRACE_DEBUG(
+ "%s rcvs i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)",
+ __func__, p_cb->local_i_key, p_cb->local_r_key);
+
+ /* In LE SC mode LK field is ignored when BR/EDR transport is used */
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+
+ /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+ ** Set local_r_key on master to expect only these keys. */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+ }
+
+ /* Check if H7 function needs to be used for key derivation*/
+ if ((p_cb->loc_auth_req & SMP_H7_SUPPORT_BIT) &&
+ (p_cb->peer_auth_req & SMP_H7_SUPPORT_BIT)) {
+ p_cb->key_derivation_h7_used = TRUE;
+ }
+ SMP_TRACE_DEBUG("%s: use h7 = %d", __func__, p_cb->key_derivation_h7_used);
+
+ SMP_TRACE_DEBUG(
+ "%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)",
+ __func__, p_cb->local_i_key, p_cb->local_r_key);
+
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->local_i_key || p_cb->local_r_key)) {
+ smp_br_state_machine_event(p_cb, SMP_BR_BOND_REQ_EVT, NULL);
+
+ /* if no peer key is expected, start master key distribution */
+ if (p_cb->role == HCI_ROLE_MASTER && p_cb->local_r_key == 0)
+ smp_key_distribution_by_transport(p_cb, NULL);
+ } else {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_br_select_next_key
+ * Description selects the next key to derive/send when BR/EDR transport is
+ * used.
+ ******************************************************************************/
+void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason = SMP_SUCCESS;
+ SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", __func__,
+ p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE ||
+ (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->local_i_key && !p_cb->local_r_key) {
+ /* state check to prevent re-entrance */
+ if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) {
+ if (p_cb->total_tx_unacked == 0)
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ else
+ p_cb->wait_for_authorization_complete = true;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Function smp_proc_enc_info
+ * Description process encryption information from peer device
+ ******************************************************************************/
+void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ STREAM_TO_ARRAY(p_cb->ltk, p, BT_OCTET16_LEN);
+
+ smp_key_distribution(p_cb, NULL);
+}
+/*******************************************************************************
+ * Function smp_proc_master_id
+ * Description process master ID from slave device
+ ******************************************************************************/
+void smp_proc_master_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ tBTM_LE_PENC_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, true);
+
+ STREAM_TO_UINT16(le_key.ediv, p);
+ STREAM_TO_ARRAY(le_key.rand, p, BT_OCTET8_LEN);
+
+ /* store the encryption keys from peer device */
+ memcpy(le_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ le_key.sec_level = p_cb->sec_level;
+ le_key.key_size = p_cb->loc_enc_size;
+
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
+ (p_cb->loc_auth_req & SMP_AUTH_BOND))
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC,
+ (tBTM_LE_KEY_VALUE*)&le_key, true);
+
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_proc_enc_info
+ * Description process identity information from peer device
+ ******************************************************************************/
+void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ STREAM_TO_ARRAY(p_cb->tk, p, BT_OCTET16_LEN); /* reuse TK for IRK */
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_proc_id_addr
+ * Description process identity address from peer device
+ ******************************************************************************/
+void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = (uint8_t*)p_data;
+ tBTM_LE_PID_KEYS pid_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ID, true);
+
+ STREAM_TO_UINT8(pid_key.addr_type, p);
+ STREAM_TO_BDADDR(pid_key.static_addr, p);
+ memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
+
+ /* to use as BD_ADDR for lk derived from ltk */
+ p_cb->id_addr_rcvd = true;
+ p_cb->id_addr_type = pid_key.addr_type;
+ memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN);
+
+ /* store the ID key from peer device */
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
+ (p_cb->loc_auth_req & SMP_AUTH_BOND))
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID,
+ (tBTM_LE_KEY_VALUE*)&pid_key, true);
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_proc_srk_info
+ * Description process security information from peer device
+ ******************************************************************************/
+void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_LE_PCSRK_KEYS le_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_CSRK, true);
+
+ /* save CSRK to security record */
+ le_key.sec_level = p_cb->sec_level;
+ maybe_non_aligned_memcpy(le_key.csrk, p_data,
+ BT_OCTET16_LEN); /* get peer CSRK */
+ le_key.counter = 0; /* initialize the peer counter */
+
+ if ((p_cb->peer_auth_req & SMP_AUTH_BOND) &&
+ (p_cb->loc_auth_req & SMP_AUTH_BOND))
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PCSRK,
+ (tBTM_LE_KEY_VALUE*)&le_key, true);
+ smp_key_distribution_by_transport(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_proc_compare
+ * Description process compare value
+ ******************************************************************************/
+void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (!memcmp(p_cb->rconfirm, p_data->key.p_data, BT_OCTET16_LEN)) {
+ /* compare the max encryption key size, and save the smaller one for the
+ * link */
+ if (p_cb->peer_enc_size < p_cb->loc_enc_size)
+ p_cb->loc_enc_size = p_cb->peer_enc_size;
+
+ if (p_cb->role == HCI_ROLE_SLAVE)
+ smp_sm_event(p_cb, SMP_RAND_EVT, NULL);
+ else {
+ /* master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ }
+
+ } else {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_proc_sl_key
+ * Description process key ready events.
+ ******************************************************************************/
+void smp_proc_sl_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t key_type = p_data->key.key_type;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (key_type == SMP_KEY_TYPE_TK) {
+ smp_generate_srand_mrand_confirm(p_cb, NULL);
+ } else if (key_type == SMP_KEY_TYPE_CFM) {
+ smp_set_state(SMP_STATE_WAIT_CONFIRM);
+
+ if (p_cb->flags & SMP_PAIR_FLAGS_CMD_CONFIRM)
+ smp_sm_event(p_cb, SMP_CONFIRM_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_start_enc
+ * Description start encryption
+ ******************************************************************************/
+void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tBTM_STATUS cmd;
+ uint8_t reason = SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (p_data != NULL)
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, true, p_data->key.p_data);
+ else
+ cmd = btm_ble_start_encrypt(p_cb->pairing_bda, false, NULL);
+
+ if (cmd != BTM_CMD_STARTED && cmd != BTM_BUSY)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+/*******************************************************************************
+ * Function smp_proc_discard
+ * Description processing for discard security request
+ ******************************************************************************/
+void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
+ smp_reset_control_value(p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_enc_cmpl
+ * Description encryption success
+ ******************************************************************************/
+void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t enc_enable = *(uint8_t*)p_data;
+ uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+}
+
+/*******************************************************************************
+ * Function smp_check_auth_req
+ * Description check authentication request
+ ******************************************************************************/
+void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t enc_enable = *(uint8_t*)p_data;
+ uint8_t reason = enc_enable ? SMP_SUCCESS : SMP_ENC_FAIL;
+
+ SMP_TRACE_DEBUG(
+ "%s rcvs enc_enable=%d i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)",
+ __func__, enc_enable, p_cb->local_i_key, p_cb->local_r_key);
+ if (enc_enable == 1) {
+ if (p_cb->le_secure_connections_mode_is_used) {
+ /* In LE SC mode LTK is used instead of STK and has to be always saved */
+ p_cb->local_i_key |= SMP_SEC_KEY_TYPE_ENC;
+ p_cb->local_r_key |= SMP_SEC_KEY_TYPE_ENC;
+
+ /* In LE SC mode LK is derived from LTK only if both sides request it */
+ if (!(p_cb->local_i_key & SMP_SEC_KEY_TYPE_LK) ||
+ !(p_cb->local_r_key & SMP_SEC_KEY_TYPE_LK)) {
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+
+ /* In LE SC mode only IRK, IAI, CSRK are exchanged with the peer.
+ ** Set local_r_key on master to expect only these keys.
+ */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->local_r_key &= (SMP_SEC_KEY_TYPE_ID | SMP_SEC_KEY_TYPE_CSRK);
+ }
+ } else {
+ /* in legacy mode derivation of BR/EDR LK is not supported */
+ p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
+ p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
+ }
+ SMP_TRACE_DEBUG(
+ "%s rcvs upgrades: i_keys=0x%x r_keys=0x%x "
+ "(i-initiator r-responder)",
+ __func__, p_cb->local_i_key, p_cb->local_r_key);
+
+ if (/*((p_cb->peer_auth_req & SMP_AUTH_BOND) ||
+ (p_cb->loc_auth_req & SMP_AUTH_BOND)) &&*/
+ (p_cb->local_i_key || p_cb->local_r_key)) {
+ smp_sm_event(p_cb, SMP_BOND_REQ_EVT, NULL);
+ } else
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ } else if (enc_enable == 0) {
+ /* if failed for encryption after pairing, send callback */
+ if (p_cb->flags & SMP_PAIR_FLAG_ENC_AFTER_PAIR)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ /* if enc failed for old security information */
+ /* if master device, clean up and abck to idle; slave device do nothing */
+ else if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+ }
+}
+
+/*******************************************************************************
+ * Function smp_key_pick_key
+ * Description Pick a key distribution function based on the key mask.
+ ******************************************************************************/
+void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t key_to_dist =
+ (p_cb->role == HCI_ROLE_SLAVE) ? p_cb->local_r_key : p_cb->local_i_key;
+ uint8_t i = 0;
+
+ SMP_TRACE_DEBUG("%s key_to_dist=0x%x", __func__, key_to_dist);
+ while (i < SMP_KEY_DIST_TYPE_MAX) {
+ SMP_TRACE_DEBUG("key to send = %02x, i = %d", key_to_dist, i);
+
+ if (key_to_dist & (1 << i)) {
+ SMP_TRACE_DEBUG("smp_distribute_act[%d]", i);
+ (*smp_distribute_act[i])(p_cb, p_data);
+ break;
+ }
+ i++;
+ }
+}
+/*******************************************************************************
+ * Function smp_key_distribution
+ * Description start key distribution if required.
+ ******************************************************************************/
+void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x", __func__,
+ p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
+
+ if (p_cb->role == HCI_ROLE_SLAVE ||
+ (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER)) {
+ smp_key_pick_key(p_cb, p_data);
+ }
+
+ if (!p_cb->local_i_key && !p_cb->local_r_key) {
+ /* state check to prevent re-entrant */
+ if (smp_get_state() == SMP_STATE_BOND_PENDING) {
+ if (p_cb->derive_lk) {
+ smp_derive_link_key_from_long_term_key(p_cb, NULL);
+ p_cb->derive_lk = false;
+ }
+
+ if (p_cb->total_tx_unacked == 0) {
+ /*
+ * Instead of declaring authorization complete immediately,
+ * delay the event from being sent by SMP_DELAYED_AUTH_TIMEOUT_MS.
+ * This allows the slave to send over Pairing Failed if the
+ * last key is rejected. During this waiting window, the
+ * state should remain in SMP_STATE_BOND_PENDING.
+ */
+ if (!alarm_is_scheduled(p_cb->delayed_auth_timer_ent)) {
+ SMP_TRACE_DEBUG("%s delaying auth complete.", __func__);
+ alarm_set_on_queue(
+ p_cb->delayed_auth_timer_ent, SMP_DELAYED_AUTH_TIMEOUT_MS,
+ smp_delayed_auth_complete_timeout, NULL, btu_general_alarm_queue);
+ }
+ } else {
+ p_cb->wait_for_authorization_complete = true;
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * Function smp_decide_association_model
+ * Description This function is called to select assoc model to be used for
+ * STK generation and to start STK generation process.
+ *
+ ******************************************************************************/
+void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t failure = SMP_UNKNOWN_IO_CAP;
+ uint8_t int_evt = 0;
+ tSMP_KEY key;
+ tSMP_INT_DATA* p = NULL;
+
+ SMP_TRACE_DEBUG("%s Association Model = %d", __func__,
+ p_cb->selected_association_model);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_ENCRYPTION_ONLY: /* TK = 0, go calculate Confirm */
+ if (p_cb->role == HCI_ROLE_MASTER &&
+ ((p_cb->peer_auth_req & SMP_AUTH_YN_BIT) != 0) &&
+ ((p_cb->loc_auth_req & SMP_AUTH_YN_BIT) == 0)) {
+ SMP_TRACE_ERROR(
+ "IO capability does not meet authentication requirement");
+ failure = SMP_PAIR_AUTH_FAIL;
+ p = (tSMP_INT_DATA*)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ } else {
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ",
+ p_cb->sec_level);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+ p = (tSMP_INT_DATA*)&key;
+
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ /* TK, ready */
+ int_evt = SMP_KEY_READY_EVT;
+ }
+ break;
+
+ case SMP_MODEL_PASSKEY:
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ",
+ p_cb->sec_level);
+
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ break;
+
+ case SMP_MODEL_OOB:
+ SMP_TRACE_ERROR("Association Model = SMP_MODEL_OOB");
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ",
+ p_cb->sec_level);
+
+ p_cb->cb_evt = SMP_OOB_REQ_EVT;
+ int_evt = SMP_TK_REQ_EVT;
+ break;
+
+ case SMP_MODEL_KEY_NOTIF:
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_DEBUG("Need to generate Passkey");
+
+ /* generate passkey and notify application */
+ smp_generate_passkey(p_cb, NULL);
+ break;
+
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ case SMP_MODEL_SEC_CONN_OOB:
+ int_evt = SMP_PUBL_KEY_EXCH_REQ_EVT;
+ break;
+
+ case SMP_MODEL_OUT_OF_RANGE:
+ SMP_TRACE_ERROR("Association Model = SMP_MODEL_OUT_OF_RANGE (failed)");
+ p = (tSMP_INT_DATA*)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ break;
+
+ default:
+ SMP_TRACE_ERROR(
+ "Association Model = %d (SOMETHING IS WRONG WITH THE CODE)",
+ p_cb->selected_association_model);
+ p = (tSMP_INT_DATA*)&failure;
+ int_evt = SMP_AUTH_CMPL_EVT;
+ }
+
+ SMP_TRACE_EVENT("sec_level=%d ", p_cb->sec_level);
+ if (int_evt) smp_sm_event(p_cb, int_evt, p);
+}
+
+/*******************************************************************************
+ * Function smp_process_io_response
+ * Description process IO response for a slave device.
+ ******************************************************************************/
+void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason = SMP_PAIR_AUTH_FAIL;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ /* pairing started by local (slave) Security Request */
+ smp_set_state(SMP_STATE_SEC_REQ_PENDING);
+ smp_send_cmd(SMP_OPCODE_SEC_REQ, p_cb);
+ } else /* plan to send pairing respond */
+ {
+ /* pairing started by peer (master) Pairing Request */
+ p_cb->selected_association_model = smp_select_association_model(p_cb);
+
+ if (p_cb->secure_connections_only_mode_required &&
+ (!(p_cb->le_secure_connections_mode_is_used) ||
+ (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS))) {
+ SMP_TRACE_ERROR(
+ "Slave requires secure connection only mode \
+ but it can't be provided -> Slave fails pairing");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_OOB) {
+ if (smp_request_oob_data(p_cb)) return;
+ }
+
+ // PTS Testing failure modes
+ if (pts_test_send_authentication_complete_failure(p_cb)) return;
+
+ smp_send_pair_rsp(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_br_process_slave_keys_response
+ * Description process application keys response for a slave device
+ * (BR/EDR transport).
+ ******************************************************************************/
+void smp_br_process_slave_keys_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ smp_br_send_pair_response(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_br_send_pair_response
+ * Description actions related to sending pairing response over BR/EDR
+ * transport.
+ ******************************************************************************/
+void smp_br_send_pair_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ p_cb->local_i_key &= p_cb->peer_i_key;
+ p_cb->local_r_key &= p_cb->peer_r_key;
+
+ smp_send_cmd(SMP_OPCODE_PAIRING_RSP, p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_pairing_cmpl
+ * Description This function is called to send the pairing complete
+ * callback and remove the connection if needed.
+ ******************************************************************************/
+void smp_pairing_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ if (p_cb->total_tx_unacked == 0) {
+ /* process the pairing complete */
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_pair_terminate
+ * Description This function is called to send the pairing complete
+ * callback and remove the connection if needed.
+ ******************************************************************************/
+void smp_pair_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->status = SMP_CONN_TOUT;
+ smp_proc_pairing_cmpl(p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_idle_terminate
+ * Description This function calledin idle state to determine to send
+ * authentication complete or not.
+ ******************************************************************************/
+void smp_idle_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ if (p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ SMP_TRACE_DEBUG("Pairing terminated at IDLE state.");
+ p_cb->status = SMP_FAIL;
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_fast_conn_param
+ * Description apply default connection parameter for pairing process
+ ******************************************************************************/
+void smp_fast_conn_param(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ /* Disable L2CAP connection parameter updates while bonding since
+ some peripherals are not able to revert to fast connection parameters
+ during the start of service discovery. Connection paramter updates
+ get enabled again once service discovery completes. */
+ L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, false);
+}
+
+/*******************************************************************************
+ * Function smp_both_have_public_keys
+ * Description The function is called when both local and peer public keys are
+ * saved.
+ * Actions:
+ * - invokes DHKey computation;
+ * - on slave side invokes sending local public key to the peer.
+ * - invokes SC phase 1 process.
+ ******************************************************************************/
+void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ /* invokes DHKey computation */
+ smp_compute_dhkey(p_cb);
+
+ /* on slave side invokes sending local public key to the peer */
+ if (p_cb->role == HCI_ROLE_SLAVE) smp_send_pair_public_key(p_cb, NULL);
+
+ smp_sm_event(p_cb, SMP_SC_DHKEY_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_start_secure_connection_phase1
+ * Description Start Secure Connection phase1 i.e. invokes initialization of
+ * Secure Connection phase 1 parameters and starts building/sending
+ * to the peer messages appropriate for the role and association
+ * model.
+ ******************************************************************************/
+void smp_start_secure_connection_phase1(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ p_cb->sec_level = SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_UNAUTHENTICATE) ",
+ p_cb->sec_level);
+ } else {
+ p_cb->sec_level = SMP_SEC_AUTHENTICATED;
+ SMP_TRACE_EVENT("p_cb->sec_level =%d (SMP_SEC_AUTHENTICATED) ",
+ p_cb->sec_level);
+ }
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ memset(p_cb->local_random, 0, BT_OCTET16_LEN);
+ smp_start_nonce_generation(p_cb);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ /* user has to provide passkey */
+ p_cb->cb_evt = SMP_PASSKEY_REQ_EVT;
+ smp_sm_event(p_cb, SMP_TK_REQ_EVT, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ /* passkey has to be provided to user */
+ SMP_TRACE_DEBUG("Need to generate SC Passkey");
+ smp_generate_passkey(p_cb, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ /* use the available OOB information */
+ smp_process_secure_connection_oob_data(p_cb, NULL);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+ p_cb->selected_association_model);
+ break;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_process_local_nonce
+ * Description The function processes new local nonce.
+ *
+ * Note It is supposed to be called in SC phase1.
+ ******************************************************************************/
+void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ /* slave calculates and sends local commitment */
+ smp_calculate_local_commitment(p_cb);
+ smp_send_commitment(p_cb, NULL);
+ /* slave has to wait for peer nonce */
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ } else /* i.e. master */
+ {
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) {
+ /* slave commitment is already received, send local nonce, wait for
+ * remote nonce*/
+ SMP_TRACE_DEBUG(
+ "master in assoc mode = %d \
+ already rcvd slave commitment - race condition",
+ p_cb->selected_association_model);
+ p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+ smp_send_rand(p_cb, NULL);
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ }
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ smp_calculate_local_commitment(p_cb);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_send_commitment(p_cb, NULL);
+ } else /* slave */
+ {
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_COMM) {
+ /* master commitment is already received */
+ smp_send_commitment(p_cb, NULL);
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ }
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+ p_cb->selected_association_model);
+ break;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_process_peer_nonce
+ * Description The function processes newly received and saved in CB peer
+ * nonce. The actions depend on the selected association model and
+ * the role.
+ *
+ * Note It is supposed to be called in SC phase1.
+ ******************************************************************************/
+void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason;
+
+ SMP_TRACE_DEBUG("%s start ", __func__);
+
+ // PTS Testing failure modes
+ if (p_cb->cert_failure == 1) {
+ SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ /* in these models only master receives commitment */
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ if (!smp_check_commitment(p_cb)) {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ }
+ } else {
+ /* slave sends local nonce */
+ smp_send_rand(p_cb, NULL);
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_JUSTWORKS) {
+ /* go directly to phase 2 */
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ } else /* numeric comparison */
+ {
+ smp_set_state(SMP_STATE_WAIT_NONCE);
+ smp_sm_event(p_cb, SMP_SC_CALC_NC_EVT, NULL);
+ }
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ if (!smp_check_commitment(p_cb) && p_cb->cert_failure != 9) {
+ reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ break;
+ }
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ if (++p_cb->round < 20) {
+ smp_set_state(SMP_STATE_SEC_CONN_PHS1_START);
+ p_cb->flags &= ~SMP_PAIR_FLAG_HAVE_PEER_COMM;
+ smp_start_nonce_generation(p_cb);
+ break;
+ }
+
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_send_rand(p_cb, NULL);
+ }
+
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+ p_cb->selected_association_model);
+ break;
+ }
+
+ SMP_TRACE_DEBUG("%s end ", __func__);
+}
+
+/*******************************************************************************
+ * Function smp_match_dhkey_checks
+ * Description checks if the calculated peer DHKey Check value is the same as
+ * received from the peer DHKey check value.
+ ******************************************************************************/
+void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t reason = SMP_DHKEY_CHK_FAIL;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (memcmp(p_data->key.p_data, p_cb->remote_dhkey_check, BT_OCTET16_LEN)) {
+ SMP_TRACE_WARNING("dhkey chcks do no match");
+ p_cb->failure = reason;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ SMP_TRACE_EVENT("dhkey chcks match");
+
+ /* compare the max encryption key size, and save the smaller one for the link
+ */
+ if (p_cb->peer_enc_size < p_cb->loc_enc_size)
+ p_cb->loc_enc_size = p_cb->peer_enc_size;
+
+ if (p_cb->role == HCI_ROLE_SLAVE) {
+ smp_sm_event(p_cb, SMP_PAIR_DHKEY_CHCK_EVT, NULL);
+ } else {
+ /* master device always use received i/r key as keys to distribute */
+ p_cb->local_i_key = p_cb->peer_i_key;
+ p_cb->local_r_key = p_cb->peer_r_key;
+ smp_sm_event(p_cb, SMP_ENC_REQ_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_move_to_secure_connections_phase2
+ * Description Signal State Machine to start SC phase 2 initialization (to
+ * compute local DHKey Check value).
+ *
+ * Note SM is supposed to be in the state SMP_STATE_SEC_CONN_PHS2_START.
+ ******************************************************************************/
+void smp_move_to_secure_connections_phase2(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_sm_event(p_cb, SMP_SC_PHASE1_CMPLT_EVT, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_phase_2_dhkey_checks_are_present
+ * Description generates event if dhkey check from the peer is already
+ * received.
+ *
+ * Note It is supposed to be used on slave to prevent race condition.
+ * It is supposed to be called after slave dhkey check is
+ * calculated.
+ ******************************************************************************/
+void smp_phase_2_dhkey_checks_are_present(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK)
+ smp_sm_event(p_cb, SMP_SC_2_DHCK_CHKS_PRES_EVT, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_wait_for_both_public_keys
+ * Description generates SMP_BOTH_PUBL_KEYS_RCVD_EVT event when both local and
+ * master public keys are available.
+ *
+ * Note on the slave it is used to prevent race condition.
+ *
+ ******************************************************************************/
+void smp_wait_for_both_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if ((p_cb->flags & SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY) &&
+ (p_cb->flags & SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY)) {
+ if ((p_cb->role == HCI_ROLE_SLAVE) &&
+ ((p_cb->req_oob_type == SMP_OOB_LOCAL) ||
+ (p_cb->req_oob_type == SMP_OOB_BOTH))) {
+ smp_set_state(SMP_STATE_PUBLIC_KEY_EXCH);
+ }
+ smp_sm_event(p_cb, SMP_BOTH_PUBL_KEYS_RCVD_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_start_passkey_verification
+ * Description Starts SC passkey entry verification.
+ ******************************************************************************/
+void smp_start_passkey_verification(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t* p = NULL;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ p = p_cb->local_random;
+ UINT32_TO_STREAM(p, p_data->passkey);
+
+ p = p_cb->peer_random;
+ UINT32_TO_STREAM(p, p_data->passkey);
+
+ p_cb->round = 0;
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_process_secure_connection_oob_data
+ * Description Processes local/peer SC OOB data received from somewhere.
+ ******************************************************************************/
+void smp_process_secure_connection_oob_data(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ tSMP_SC_OOB_DATA* p_sc_oob_data = &p_cb->sc_oob_data;
+ if (p_sc_oob_data->loc_oob_data.present) {
+ memcpy(p_cb->local_random, p_sc_oob_data->loc_oob_data.randomizer,
+ sizeof(p_cb->local_random));
+ } else {
+ SMP_TRACE_EVENT("%s: local OOB randomizer is absent", __func__);
+ memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ }
+
+ if (!p_sc_oob_data->peer_oob_data.present) {
+ SMP_TRACE_EVENT("%s: peer OOB data is absent", __func__);
+ memset(p_cb->peer_random, 0, sizeof(p_cb->peer_random));
+ } else {
+ memcpy(p_cb->peer_random, p_sc_oob_data->peer_oob_data.randomizer,
+ sizeof(p_cb->peer_random));
+ memcpy(p_cb->remote_commitment, p_sc_oob_data->peer_oob_data.commitment,
+ sizeof(p_cb->remote_commitment));
+
+ uint8_t reason = SMP_CONFIRM_VALUE_ERR;
+ /* check commitment */
+ if (!smp_check_commitment(p_cb)) {
+ p_cb->failure = reason;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ if (p_cb->peer_oob_flag != SMP_OOB_PRESENT) {
+ /* the peer doesn't have local randomiser */
+ SMP_TRACE_EVENT(
+ "%s: peer didn't receive local OOB data, set local randomizer to 0",
+ __func__);
+ memset(p_cb->local_random, 0, sizeof(p_cb->local_random));
+ }
+ }
+
+ print128(p_cb->local_random, (const uint8_t*)"local OOB randomizer");
+ print128(p_cb->peer_random, (const uint8_t*)"peer OOB randomizer");
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_set_local_oob_keys
+ * Description Saves calculated private/public keys in
+ * sc_oob_data.loc_oob_data, starts nonce generation
+ * (to be saved in sc_oob_data.loc_oob_data.randomizer).
+ ******************************************************************************/
+void smp_set_local_oob_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ memcpy(p_cb->sc_oob_data.loc_oob_data.private_key_used, p_cb->private_key,
+ BT_OCTET32_LEN);
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used = p_cb->loc_publ_key;
+ smp_start_nonce_generation(p_cb);
+}
+
+/*******************************************************************************
+ * Function smp_set_local_oob_random_commitment
+ * Description Saves calculated randomizer and commitment in
+ * sc_oob_data.loc_oob_data, passes sc_oob_data.loc_oob_data up
+ * for safekeeping.
+ ******************************************************************************/
+void smp_set_local_oob_random_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ memcpy(p_cb->sc_oob_data.loc_oob_data.randomizer, p_cb->rand, BT_OCTET16_LEN);
+
+ smp_calculate_f4(p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.publ_key_used.x,
+ p_cb->sc_oob_data.loc_oob_data.randomizer, 0,
+ p_cb->sc_oob_data.loc_oob_data.commitment);
+
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_print = NULL;
+ SMP_TRACE_DEBUG("local SC OOB data set:");
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.addr_sent_to;
+ smp_debug_print_nbyte_little_endian(p_print, "addr_sent_to",
+ sizeof(tBLE_BD_ADDR));
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.private_key_used;
+ smp_debug_print_nbyte_little_endian(p_print, "private_key_used",
+ BT_OCTET32_LEN);
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.publ_key_used.x;
+ smp_debug_print_nbyte_little_endian(p_print, "publ_key_used.x",
+ BT_OCTET32_LEN);
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.publ_key_used.y;
+ smp_debug_print_nbyte_little_endian(p_print, "publ_key_used.y",
+ BT_OCTET32_LEN);
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.randomizer;
+ smp_debug_print_nbyte_little_endian(p_print, "randomizer", BT_OCTET16_LEN);
+ p_print = (uint8_t*)&p_cb->sc_oob_data.loc_oob_data.commitment;
+ smp_debug_print_nbyte_little_endian(p_print, "commitment", BT_OCTET16_LEN);
+ SMP_TRACE_DEBUG("");
+#endif
+
+ /* pass created OOB data up */
+ p_cb->cb_evt = SMP_SC_LOC_OOB_DATA_UP_EVT;
+ smp_send_app_cback(p_cb, NULL);
+
+ smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_link_encrypted
+ *
+ * Description This function is called when link is encrypted and notified
+ * to the slave device. Proceed to to send LTK, DIV and ER to
+ * master if bonding the devices.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_link_encrypted(BD_ADDR bda, uint8_t encr_enable) {
+ tSMP_CB* p_cb = &smp_cb;
+
+ SMP_TRACE_DEBUG("%s encr_enable=%d", __func__, encr_enable);
+
+ if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) {
+ /* encryption completed with STK, remmeber the key size now, could be
+ * overwite
+ * when key exchange happens */
+ if (p_cb->loc_enc_size != 0 && encr_enable) {
+ /* update the link encryption key size if a SMP pairing just performed */
+ btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
+ }
+
+ smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_proc_ltk_request
+ *
+ * Description This function is called when LTK request is received from
+ * controller.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool smp_proc_ltk_request(BD_ADDR bda) {
+ SMP_TRACE_DEBUG("%s state = %d", __func__, smp_cb.state);
+ bool match = false;
+
+ if (!memcmp(bda, smp_cb.pairing_bda, BD_ADDR_LEN)) {
+ match = true;
+ } else {
+ BD_ADDR dummy_bda = {0};
+ tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bda);
+ if (p_dev_rec != NULL &&
+ 0 == memcmp(p_dev_rec->ble.pseudo_addr, smp_cb.pairing_bda,
+ BD_ADDR_LEN) &&
+ 0 != memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN)) {
+ match = true;
+ }
+ }
+
+ if (match && smp_cb.state == SMP_STATE_ENCRYPTION_PENDING) {
+ smp_sm_event(&smp_cb, SMP_ENC_REQ_EVT, NULL);
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_process_secure_connection_long_term_key
+ *
+ * Description This function is called to process SC LTK.
+ * SC LTK is calculated and used instead of STK.
+ * Here SC LTK is saved in BLE DB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_process_secure_connection_long_term_key(void) {
+ tSMP_CB* p_cb = &smp_cb;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_save_secure_connections_long_term_key(p_cb);
+
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_set_derive_link_key
+ *
+ * Description This function is called to set flag that indicates that
+ * BR/EDR LK has to be derived from LTK after all keys are
+ * distributed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_set_derive_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ p_cb->derive_lk = true;
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_LK, false);
+ smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_derive_link_key_from_long_term_key
+ *
+ * Description This function is called to derive BR/EDR LK from LTK.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_derive_link_key_from_long_term_key(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (!smp_calculate_link_key_from_long_term_key(p_cb)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_br_process_link_key
+ *
+ * Description This function is called to process BR/EDR LK:
+ * - to derive SMP LTK from BR/EDR LK;
+*8 - to save SMP LTK.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (!smp_calculate_long_term_key_from_link_key(p_cb)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ smp_sm_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+ return;
+ }
+
+ SMP_TRACE_DEBUG("%s: LTK derivation from LK successfully completed",
+ __func__);
+ smp_save_secure_connections_long_term_key(p_cb);
+ smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ENC, false);
+ smp_br_select_next_key(p_cb, NULL);
+}
+
+/*******************************************************************************
+ * Function smp_key_distribution_by_transport
+ * Description depending on the transport used at the moment calls either
+ * smp_key_distribution(...) or smp_br_key_distribution(...).
+ ******************************************************************************/
+void smp_key_distribution_by_transport(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ if (p_cb->smp_over_br) {
+ smp_br_select_next_key(p_cb, NULL);
+ } else {
+ smp_key_distribution(p_cb, NULL);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_br_pairing_complete
+ * Description This function is called to send the pairing complete
+ * callback and remove the connection if needed.
+ ******************************************************************************/
+void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->total_tx_unacked == 0) {
+ /* process the pairing complete */
+ smp_proc_pairing_cmpl(p_cb);
+ }
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_api.cc b/mtkbt/code/bt/stack/smp/smp_api.cc
new file mode 100755
index 0000000..ebd300b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_api.cc
@@ -0,0 +1,576 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the SMP interface used by
+ * applications that can run over an SMP.
+ *
+ ******************************************************************************/
+#include <string.h>
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "stack_config.h"
+
+#include "btm_int.h"
+#include "hcimsgs.h"
+#include "l2c_int.h"
+#include "l2cdefs.h"
+#include "smp_api.h"
+#include "smp_int.h"
+
+#include "btu.h"
+#include "p_256_ecc_pp.h"
+
+/*******************************************************************************
+ *
+ * Function SMP_Init
+ *
+ * Description This function initializes the SMP unit.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void SMP_Init(void) {
+ memset(&smp_cb, 0, sizeof(tSMP_CB));
+ smp_cb.smp_rsp_timer_ent = alarm_new("smp.smp_rsp_timer_ent");
+ smp_cb.delayed_auth_timer_ent = alarm_new("smp.delayed_auth_timer_ent");
+
+#if defined(SMP_INITIAL_TRACE_LEVEL)
+ smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL;
+#else
+ smp_cb.trace_level = BT_TRACE_LEVEL_NONE; /* No traces */
+#endif
+ SMP_TRACE_EVENT("%s", __func__);
+
+ smp_l2cap_if_init();
+ /* initialization of P-256 parameters */
+ p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+
+ /* Initialize failure case for certification */
+ smp_cb.cert_failure =
+ stack_config_get_interface()->get_pts_smp_failure_case();
+ if (smp_cb.cert_failure)
+ SMP_TRACE_ERROR("%s PTS FAILURE MODE IN EFFECT (CASE %d)", __func__,
+ smp_cb.cert_failure);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_SetTraceLevel
+ *
+ * Description This function sets the trace level for SMP. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Input Parameters:
+ * level: The level to set the GATT tracing to:
+ * 0xff-returns the current setting.
+ * 0-turns off tracing.
+ * >= 1-Errors.
+ * >= 2-Warnings.
+ * >= 3-APIs.
+ * >= 4-Events.
+ * >= 5-Debug.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+extern uint8_t SMP_SetTraceLevel(uint8_t new_level) {
+ if (new_level != 0xFF) smp_cb.trace_level = new_level;
+
+ return (smp_cb.trace_level);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_Register
+ *
+ * Description This function register for the SMP services callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool SMP_Register(tSMP_CALLBACK* p_cback) {
+ SMP_TRACE_EVENT("SMP_Register state=%d", smp_cb.state);
+
+ if (smp_cb.p_callback != NULL) {
+ SMP_TRACE_ERROR("SMP_Register: duplicate registration, overwrite it");
+ }
+ smp_cb.p_callback = p_cback;
+
+ return (true);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_Pair
+ *
+ * Description This function call to perform a SMP pairing with peer
+ * device. Device support one SMP pairing at one time.
+ *
+ * Parameters bd_addr - peer device bd address.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+tSMP_STATUS SMP_Pair(BD_ADDR bd_addr) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t status = SMP_PAIR_INTERNAL_ERR;
+
+ SMP_TRACE_EVENT("%s state=%d br_state=%d flag=0x%x ", __func__, p_cb->state,
+ p_cb->br_state, p_cb->flags);
+ if (p_cb->state != SMP_STATE_IDLE ||
+ p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD || p_cb->smp_over_br) {
+ /* pending security on going, reject this one */
+ return SMP_BUSY;
+ } else {
+ p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+
+ memcpy(p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ if (!L2CA_ConnectFixedChnl(L2CAP_SMP_CID, bd_addr)) {
+ SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_BR_PairWith
+ *
+ * Description This function is called to start a SMP pairing over BR/EDR.
+ * Device support one SMP pairing at one time.
+ *
+ * Parameters bd_addr - peer device bd address.
+ *
+ * Returns SMP_STARTED if pairing started, otherwise the reason for
+ * failure.
+ *
+ ******************************************************************************/
+tSMP_STATUS SMP_BR_PairWith(BD_ADDR bd_addr) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t status = SMP_PAIR_INTERNAL_ERR;
+
+ SMP_TRACE_EVENT("%s state=%d br_state=%d flag=0x%x ", __func__, p_cb->state,
+ p_cb->br_state, p_cb->flags);
+
+ if (p_cb->state != SMP_STATE_IDLE || p_cb->smp_over_br ||
+ p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
+ /* pending security on going, reject this one */
+ return SMP_BUSY;
+ }
+
+ p_cb->role = HCI_ROLE_MASTER;
+ p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
+ p_cb->smp_over_br = true;
+
+ memcpy(p_cb->pairing_bda, bd_addr, BD_ADDR_LEN);
+
+ if (!L2CA_ConnectFixedChnl(L2CAP_SMP_BR_CID, bd_addr)) {
+ SMP_TRACE_ERROR("%s: L2C connect fixed channel failed.", __func__);
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+ return status;
+ }
+
+ return SMP_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_PairCancel
+ *
+ * Description This function call to cancel a SMP pairing with peer device.
+ *
+ * Parameters bd_addr - peer device bd address.
+ *
+ * Returns true - Pairining is cancelled
+ *
+ ******************************************************************************/
+bool SMP_PairCancel(BD_ADDR bd_addr) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t err_code = SMP_PAIR_FAIL_UNKNOWN;
+ bool status = false;
+
+ // PTS SMP failure test cases
+ if (p_cb->cert_failure == 7)
+ err_code = SMP_PASSKEY_ENTRY_FAIL;
+ else if (p_cb->cert_failure == 8)
+ err_code = SMP_NUMERIC_COMPAR_FAIL;
+
+ BTM_TRACE_EVENT("SMP_CancelPair state=%d flag=0x%x ", p_cb->state,
+ p_cb->flags);
+ if ((p_cb->state != SMP_STATE_IDLE) &&
+ (!memcmp(p_cb->pairing_bda, bd_addr, BD_ADDR_LEN))) {
+ p_cb->is_pair_cancel = true;
+ SMP_TRACE_DEBUG("Cancel Pairing: set fail reason Unknown");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &err_code);
+ status = true;
+ }
+
+ return status;
+}
+/*******************************************************************************
+ *
+ * Function SMP_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation SMP_SUCCESS if success.
+ * Otherwise, SMP_REPEATED_ATTEMPTS if too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void SMP_SecurityGrant(BD_ADDR bd_addr, uint8_t res) {
+ SMP_TRACE_EVENT("SMP_SecurityGrant ");
+
+ if (smp_cb.smp_over_br) {
+ if (smp_cb.br_state != SMP_BR_STATE_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp(smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN)) {
+ return;
+ }
+
+ /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+ /* avoid generating duplicate pair request */
+ smp_cb.cb_evt = 0;
+ smp_br_state_machine_event(&smp_cb, SMP_BR_API_SEC_GRANT_EVT, &res);
+ return;
+ }
+
+ if (smp_cb.state != SMP_STATE_WAIT_APP_RSP ||
+ smp_cb.cb_evt != SMP_SEC_REQUEST_EVT ||
+ memcmp(smp_cb.pairing_bda, bd_addr, BD_ADDR_LEN))
+ return;
+ /* clear the SMP_SEC_REQUEST_EVT event after get grant */
+ /* avoid generate duplicate pair request */
+ smp_cb.cb_evt = 0;
+ smp_sm_event(&smp_cb, SMP_API_SEC_GRANT_EVT, &res);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_PasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which passkey was
+ * requested
+ * res - result of the operation SMP_SUCCESS if success
+ * passkey - numeric value in the range of
+ * BTM_MIN_PASSKEY_VAL(0) -
+ * BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+void SMP_PasskeyReply(BD_ADDR bd_addr, uint8_t res, uint32_t passkey) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t failure = SMP_PASSKEY_ENTRY_FAIL;
+
+ SMP_TRACE_EVENT("SMP_PasskeyReply: Key: %d Result:%d", passkey, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT) {
+ SMP_TRACE_WARNING("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
+ return;
+ }
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR("SMP_PasskeyReply() - Wrong BD Addr");
+ return;
+ }
+
+ if (btm_find_dev(bd_addr) == NULL) {
+ SMP_TRACE_ERROR("SMP_PasskeyReply() - no dev CB");
+ return;
+ }
+
+ if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS) {
+ SMP_TRACE_WARNING(
+ "SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail",
+ passkey);
+ /* send pairing failure */
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+
+ } else if (p_cb->selected_association_model ==
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
+ smp_sm_event(&smp_cb, SMP_SC_KEY_READY_EVT, &passkey);
+ } else {
+ smp_convert_string_to_tk(p_cb->tk, passkey);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_ConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result SMP_SUCCESS if success
+ *
+ ******************************************************************************/
+void SMP_ConfirmReply(BD_ADDR bd_addr, uint8_t res) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t failure = SMP_NUMERIC_COMPAR_FAIL;
+
+ SMP_TRACE_EVENT("%s: Result:%d", __func__, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->cb_evt != SMP_NC_REQ_EVT) {
+ SMP_TRACE_WARNING("%s() - Wrong State: %d", __func__, p_cb->state);
+ return;
+ }
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR("%s() - Wrong BD Addr", __func__);
+ return;
+ }
+
+ if (btm_find_dev(bd_addr) == NULL) {
+ SMP_TRACE_ERROR("%s() - no dev CB", __func__);
+ return;
+ }
+
+ if (res != SMP_SUCCESS) {
+ SMP_TRACE_WARNING("%s() - Numeric Comparison fails", __func__);
+ /* send pairing failure */
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ } else {
+ smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_OobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to SMP_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+void SMP_OobDataReply(BD_ADDR bd_addr, tSMP_STATUS res, uint8_t len,
+ uint8_t* p_data) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t failure = SMP_OOB_FAIL;
+ tSMP_KEY key;
+
+ SMP_TRACE_EVENT("%s State: %d res:%d", __func__, smp_cb.state, res);
+
+ /* If timeout already expired or has been canceled, ignore the reply */
+ if (p_cb->state != SMP_STATE_WAIT_APP_RSP || p_cb->cb_evt != SMP_OOB_REQ_EVT)
+ return;
+
+ if (res != SMP_SUCCESS || len == 0 || !p_data) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ } else {
+ if (len > BT_OCTET16_LEN) len = BT_OCTET16_LEN;
+
+ memcpy(p_cb->tk, p_data, len);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_SecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the SC OOB data for
+ * SMP in response to SMP_SC_OOB_REQ_EVT
+ *
+ * Parameters: p_data - pointer to the data
+ *
+ ******************************************************************************/
+void SMP_SecureConnectionOobDataReply(uint8_t* p_data) {
+ tSMP_CB* p_cb = &smp_cb;
+
+ uint8_t failure = SMP_OOB_FAIL;
+ tSMP_SC_OOB_DATA* p_oob = (tSMP_SC_OOB_DATA*)p_data;
+ if (!p_oob) {
+ SMP_TRACE_ERROR("%s received no data", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ return;
+ }
+
+ SMP_TRACE_EVENT(
+ "%s req_oob_type: %d, loc_oob_data.present: %d, "
+ "peer_oob_data.present: %d",
+ __func__, p_cb->req_oob_type, p_oob->loc_oob_data.present,
+ p_oob->peer_oob_data.present);
+
+ if (p_cb->state != SMP_STATE_WAIT_APP_RSP ||
+ p_cb->cb_evt != SMP_SC_OOB_REQ_EVT)
+ return;
+
+ bool data_missing = false;
+ switch (p_cb->req_oob_type) {
+ case SMP_OOB_PEER:
+ if (!p_oob->peer_oob_data.present) data_missing = true;
+ break;
+ case SMP_OOB_LOCAL:
+ if (!p_oob->loc_oob_data.present) data_missing = true;
+ break;
+ case SMP_OOB_BOTH:
+ if (!p_oob->loc_oob_data.present || !p_oob->peer_oob_data.present)
+ data_missing = true;
+ break;
+ default:
+ SMP_TRACE_EVENT("Unexpected OOB data type requested. Fail OOB");
+ data_missing = true;
+ break;
+ }
+
+ if (data_missing) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ return;
+ }
+
+ p_cb->sc_oob_data = *p_oob;
+
+ smp_sm_event(&smp_cb, SMP_SC_OOB_DATA_EVT, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_Encrypt
+ *
+ * Description This function is called to encrypt the data with the
+ * specified key
+ *
+ * Parameters: key - Pointer to key key[0] conatins the MSB
+ * key_len - key length
+ * plain_text - Pointer to data to be encrypted
+ * plain_text[0] conatins the MSB
+ * pt_len - plain text length
+ * p_out - output of the encrypted texts
+ *
+ * Returns Boolean - request is successful
+ ******************************************************************************/
+bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, tSMP_ENC* p_out)
+
+{
+ bool status = false;
+ status = smp_encrypt_data(key, key_len, plain_text, pt_len, p_out);
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_KeypressNotification
+ *
+ * Description This function is called to notify Security Manager about
+ * Keypress Notification.
+ *
+ * Parameters: bd_addr Address of the device to send keypress
+ * notification to
+ * value Keypress notification parameter value
+ *
+ ******************************************************************************/
+void SMP_KeypressNotification(BD_ADDR bd_addr, uint8_t value) {
+ tSMP_CB* p_cb = &smp_cb;
+
+ SMP_TRACE_EVENT("%s: Value: %d", __func__, value);
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
+ SMP_TRACE_ERROR("%s() - Wrong BD Addr", __func__);
+ return;
+ }
+
+ if (btm_find_dev(bd_addr) == NULL) {
+ SMP_TRACE_ERROR("%s() - no dev CB", __func__);
+ return;
+ }
+
+ /* Keypress Notification is used by a device with KeyboardOnly IO capabilities
+ * during the passkey entry protocol */
+ if (p_cb->local_io_capability != SMP_IO_CAP_IN) {
+ SMP_TRACE_ERROR("%s() - wrong local IO capabilities %d", __func__,
+ p_cb->local_io_capability);
+ return;
+ }
+
+ if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
+ SMP_TRACE_ERROR("%s() - wrong protocol %d", __func__,
+ p_cb->selected_association_model);
+ return;
+ }
+
+ smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value);
+}
+
+/*******************************************************************************
+ *
+ * Function SMP_CreateLocalSecureConnectionsOobData
+ *
+ * Description This function is called to start creation of local SC OOB
+ * data set (tSMP_LOC_OOB_DATA).
+ *
+ * Parameters: bd_addr - Address of the device to send OOB data block to
+ *
+ * Returns Boolean - true: creation of local SC OOB data set started.
+ ******************************************************************************/
+bool SMP_CreateLocalSecureConnectionsOobData(tBLE_BD_ADDR* addr_to_send_to) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t* bd_addr;
+
+ if (addr_to_send_to == NULL) {
+ SMP_TRACE_ERROR("%s addr_to_send_to is not provided", __func__);
+ return false;
+ }
+
+ bd_addr = addr_to_send_to->bda;
+
+ SMP_TRACE_EVENT(
+ "%s addr type: %u, BDA: %08x%04x, state: %u, br_state: %u", __func__,
+ addr_to_send_to->type,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5], p_cb->state, p_cb->br_state);
+
+ if ((p_cb->state != SMP_STATE_IDLE) || (p_cb->smp_over_br)) {
+ SMP_TRACE_WARNING(
+ "%s creation of local OOB data set "
+ "starts only in IDLE state",
+ __func__);
+ return false;
+ }
+
+ p_cb->sc_oob_data.loc_oob_data.addr_sent_to = *addr_to_send_to;
+ smp_sm_event(p_cb, SMP_CR_LOC_SC_OOB_DATA_EVT, NULL);
+
+ return true;
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_br_main.cc b/mtkbt/code/bt/stack/smp/smp_br_main.cc
new file mode 100755
index 0000000..260b9c4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_br_main.cc
@@ -0,0 +1,352 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "smp_int.h"
+
+const char* const smp_br_state_name[SMP_BR_STATE_MAX + 1] = {
+ "SMP_BR_STATE_IDLE", "SMP_BR_STATE_WAIT_APP_RSP",
+ "SMP_BR_STATE_PAIR_REQ_RSP", "SMP_BR_STATE_BOND_PENDING",
+ "SMP_BR_STATE_OUT_OF_RANGE"};
+
+const char* const smp_br_event_name[SMP_BR_MAX_EVT] = {
+ "BR_PAIRING_REQ_EVT", "BR_PAIRING_RSP_EVT",
+ "BR_CONFIRM_EVT", "BR_RAND_EVT",
+ "BR_PAIRING_FAILED_EVT", "BR_ENCRPTION_INFO_EVT",
+ "BR_MASTER_ID_EVT", "BR_ID_INFO_EVT",
+ "BR_ID_ADDR_EVT", "BR_SIGN_INFO_EVT",
+ "BR_SECURITY_REQ_EVT", "BR_PAIR_PUBLIC_KEY_EVT",
+ "BR_PAIR_DHKEY_CHCK_EVT", "BR_PAIR_KEYPR_NOTIF_EVT",
+ "BR_KEY_READY_EVT", "BR_ENCRYPTED_EVT",
+ "BR_L2CAP_CONN_EVT", "BR_L2CAP_DISCONN_EVT",
+ "BR_KEYS_RSP_EVT", "BR_API_SEC_GRANT_EVT",
+ "BR_TK_REQ_EVT", "BR_AUTH_CMPL_EVT",
+ "BR_ENC_REQ_EVT", "BR_BOND_REQ_EVT",
+ "BR_DISCARD_SEC_REQ_EVT", "BR_OUT_OF_RANGE_EVT"};
+
+const char* smp_get_br_event_name(tSMP_BR_EVENT event);
+const char* smp_get_br_state_name(tSMP_BR_STATE state);
+
+#define SMP_BR_SM_IGNORE 0
+#define SMP_BR_NUM_ACTIONS 2
+#define SMP_BR_SME_NEXT_STATE 2
+#define SMP_BR_SM_NUM_COLS 3
+typedef const uint8_t (*tSMP_BR_SM_TBL)[SMP_BR_SM_NUM_COLS];
+
+enum {
+ SMP_SEND_PAIR_REQ,
+ SMP_BR_SEND_PAIR_RSP,
+ SMP_SEND_PAIR_FAIL,
+ SMP_SEND_ID_INFO,
+ SMP_BR_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_ID_INFO,
+ SMP_PROC_ID_ADDR,
+ SMP_PROC_SRK_INFO,
+ SMP_BR_PROC_SEC_GRANT,
+ SMP_BR_PROC_SL_KEYS_RSP,
+ SMP_BR_KEY_DISTRIBUTION,
+ SMP_BR_PAIRING_COMPLETE,
+ SMP_SEND_APP_CBACK,
+ SMP_BR_CHECK_AUTH_REQ,
+ SMP_PAIR_TERMINATE,
+ SMP_IDLE_TERMINATE,
+ SMP_BR_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_br_sm_action[] = {smp_send_pair_req,
+ smp_br_send_pair_response,
+ smp_send_pair_fail,
+ smp_send_id_info,
+ smp_br_process_pairing_command,
+ smp_proc_pair_fail,
+ smp_proc_id_info,
+ smp_proc_id_addr,
+ smp_proc_srk_info,
+ smp_br_process_security_grant,
+ smp_br_process_slave_keys_response,
+ smp_br_select_next_key,
+ smp_br_pairing_complete,
+ smp_send_app_cback,
+ smp_br_check_authorization_request,
+ smp_pair_terminate,
+ smp_idle_terminate};
+
+static const uint8_t smp_br_all_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_FAILED */
+ {SMP_PROC_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+ /* BR_AUTH_CMPL */
+ {SMP_SEND_PAIR_FAIL, SMP_BR_PAIRING_COMPLETE, SMP_BR_STATE_IDLE},
+ /* BR_L2CAP_DISCONN */
+ {SMP_PAIR_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}};
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const uint8_t smp_br_master_entry_map[][SMP_BR_STATE_MAX] = {
+ /* br_state name: Idle WaitApp Pair Bond
+ Rsp ReqRsp Pend */
+ /* BR_PAIRING_REQ */ {0, 0, 0, 0},
+ /* BR_PAIRING_RSP */ {0, 0, 1, 0},
+ /* BR_CONFIRM */ {0, 0, 0, 0},
+ /* BR_RAND */ {0, 0, 0, 0},
+ /* BR_PAIRING_FAILED */ {0, 0x81, 0x81, 0},
+ /* BR_ENCRPTION_INFO */ {0, 0, 0, 0},
+ /* BR_MASTER_ID */ {0, 0, 0, 0},
+ /* BR_ID_INFO */ {0, 0, 0, 1},
+ /* BR_ID_ADDR */ {0, 0, 0, 2},
+ /* BR_SIGN_INFO */ {0, 0, 0, 3},
+ /* BR_SECURITY_REQ */ {0, 0, 0, 0},
+ /* BR_PAIR_PUBLIC_KEY_EVT */ {0, 0, 0, 0},
+ /* BR_PAIR_DHKEY_CHCK_EVT */ {0, 0, 0, 0},
+ /* BR_PAIR_KEYPR_NOTIF_EVT */ {0, 0, 0, 0},
+ /* BR_KEY_READY */ {0, 0, 0, 0},
+ /* BR_ENCRYPTED */ {0, 0, 0, 0},
+ /* BR_L2CAP_CONN */ {1, 0, 0, 0},
+ /* BR_L2CAP_DISCONN */ {2, 0x83, 0x83, 0x83},
+ /* BR_KEYS_RSP */ {0, 1, 0, 0},
+ /* BR_API_SEC_GRANT */ {0, 0, 0, 0},
+ /* BR_TK_REQ */ {0, 0, 0, 0},
+ /* BR_AUTH_CMPL */ {0, 0x82, 0x82, 0x82},
+ /* BR_ENC_REQ */ {0, 0, 0, 0},
+ /* BR_BOND_REQ */ {0, 0, 2, 0},
+ /* BR_DISCARD_SEC_REQ */ {0, 0, 0, 0}};
+
+static const uint8_t smp_br_master_idle_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_L2CAP_CONN */
+ {SMP_SEND_APP_CBACK, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_L2CAP_DISCONN */
+ {SMP_IDLE_TERMINATE, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_IDLE}};
+
+static const uint8_t
+ smp_br_master_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_KEYS_RSP */
+ {SMP_SEND_PAIR_REQ, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_PAIR_REQ_RSP}};
+
+static const uint8_t
+ smp_br_master_pair_request_response_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_RSP */
+ {SMP_BR_PROC_PAIR_CMD, SMP_BR_CHECK_AUTH_REQ,
+ SMP_BR_STATE_PAIR_REQ_RSP},
+ /* BR_BOND_REQ */
+ {SMP_BR_SM_NO_ACTION, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}};
+
+static const uint8_t smp_br_master_bond_pending_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_ID_INFO */
+ {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_ID_ADDR */
+ {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_SIGN_INFO */
+ {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}};
+
+static const uint8_t smp_br_slave_entry_map[][SMP_BR_STATE_MAX] = {
+ /* br_state name: Idle WaitApp Pair Bond
+ Rsp ReqRsp Pend */
+ /* BR_PAIRING_REQ */ {1, 0, 0, 0},
+ /* BR_PAIRING_RSP */ {0, 0, 0, 0},
+ /* BR_CONFIRM */ {0, 0, 0, 0},
+ /* BR_RAND */ {0, 0, 0, 0},
+ /* BR_PAIRING_FAILED */ {0, 0x81, 0x81, 0x81},
+ /* BR_ENCRPTION_INFO */ {0, 0, 0, 0},
+ /* BR_MASTER_ID */ {0, 0, 0, 0},
+ /* BR_ID_INFO */ {0, 0, 0, 1},
+ /* BR_ID_ADDR */ {0, 0, 0, 2},
+ /* BR_SIGN_INFO */ {0, 0, 0, 3},
+ /* BR_SECURITY_REQ */ {0, 0, 0, 0},
+ /* BR_PAIR_PUBLIC_KEY_EVT */ {0, 0, 0, 0},
+ /* BR_PAIR_DHKEY_CHCK_EVT */ {0, 0, 0, 0},
+ /* BR_PAIR_KEYPR_NOTIF_EVT */ {0, 0, 0, 0},
+ /* BR_KEY_READY */ {0, 0, 0, 0},
+ /* BR_ENCRYPTED */ {0, 0, 0, 0},
+ /* BR_L2CAP_CONN */ {0, 0, 0, 0},
+ /* BR_L2CAP_DISCONN */ {0, 0x83, 0x83, 0x83},
+ /* BR_KEYS_RSP */ {0, 2, 0, 0},
+ /* BR_API_SEC_GRANT */ {0, 1, 0, 0},
+ /* BR_TK_REQ */ {0, 0, 0, 0},
+ /* BR_AUTH_CMPL */ {0, 0x82, 0x82, 0x82},
+ /* BR_ENC_REQ */ {0, 0, 0, 0},
+ /* BR_BOND_REQ */ {0, 3, 0, 0},
+ /* BR_DISCARD_SEC_REQ */ {0, 0, 0, 0}};
+
+static const uint8_t smp_br_slave_idle_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_PAIRING_REQ */
+ {SMP_BR_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP}};
+
+static const uint8_t
+ smp_br_slave_wait_appln_response_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_API_SEC_GRANT */
+ {SMP_BR_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_KEYS_RSP */
+ {SMP_BR_PROC_SL_KEYS_RSP, SMP_BR_CHECK_AUTH_REQ,
+ SMP_BR_STATE_WAIT_APP_RSP},
+ /* BR_BOND_REQ */
+ {SMP_BR_KEY_DISTRIBUTION, SMP_BR_SM_NO_ACTION,
+ SMP_BR_STATE_BOND_PENDING}};
+
+static const uint8_t smp_br_slave_bond_pending_table[][SMP_BR_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* BR_ID_INFO */
+ {SMP_PROC_ID_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_ID_ADDR */
+ {SMP_PROC_ID_ADDR, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING},
+ /* BR_SIGN_INFO */
+ {SMP_PROC_SRK_INFO, SMP_BR_SM_NO_ACTION, SMP_BR_STATE_BOND_PENDING}};
+
+static const tSMP_BR_SM_TBL smp_br_state_table[][2] = {
+ /* SMP_BR_STATE_IDLE */
+ {smp_br_master_idle_table, smp_br_slave_idle_table},
+
+ /* SMP_BR_STATE_WAIT_APP_RSP */
+ {smp_br_master_wait_appln_response_table,
+ smp_br_slave_wait_appln_response_table},
+
+ /* SMP_BR_STATE_PAIR_REQ_RSP */
+ {smp_br_master_pair_request_response_table, NULL},
+
+ /* SMP_BR_STATE_BOND_PENDING */
+ {smp_br_master_bond_pending_table, smp_br_slave_bond_pending_table},
+};
+
+typedef const uint8_t (*tSMP_BR_ENTRY_TBL)[SMP_BR_STATE_MAX];
+
+static const tSMP_BR_ENTRY_TBL smp_br_entry_table[] = {smp_br_master_entry_map,
+ smp_br_slave_entry_map};
+
+#define SMP_BR_ALL_TABLE_MASK 0x80
+
+/*******************************************************************************
+ * Function smp_set_br_state
+ * Returns None
+ ******************************************************************************/
+void smp_set_br_state(tSMP_BR_STATE br_state) {
+ if (br_state < SMP_BR_STATE_MAX) {
+ SMP_TRACE_DEBUG("BR_State change: %s(%d) ==> %s(%d)",
+ smp_get_br_state_name(smp_cb.br_state), smp_cb.br_state,
+ smp_get_br_state_name(br_state), br_state);
+ smp_cb.br_state = br_state;
+ } else {
+ SMP_TRACE_DEBUG("%s invalid br_state =%d", __func__, br_state);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_get_br_state
+ * Returns The smp_br state
+ ******************************************************************************/
+tSMP_BR_STATE smp_get_br_state(void) { return smp_cb.br_state; }
+
+/*******************************************************************************
+ * Function smp_get_br_state_name
+ * Returns The smp_br state name.
+ ******************************************************************************/
+const char* smp_get_br_state_name(tSMP_BR_STATE br_state) {
+ const char* p_str = smp_br_state_name[SMP_BR_STATE_MAX];
+
+ if (br_state < SMP_BR_STATE_MAX) p_str = smp_br_state_name[br_state];
+
+ return p_str;
+}
+/*******************************************************************************
+ * Function smp_get_br_event_name
+ * Returns The smp_br event name.
+ ******************************************************************************/
+const char* smp_get_br_event_name(tSMP_BR_EVENT event) {
+ const char* p_str = smp_br_event_name[SMP_BR_MAX_EVT - 1];
+
+ if (event < SMP_BR_MAX_EVT) {
+ p_str = smp_br_event_name[event - 1];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_br_state_machine_event
+ *
+ * Description Handle events to the state machine. It looks up the entry
+ * in the smp_br_entry_table array.
+ * If it is a valid entry, it gets the state table. Set the next
+ * state, if not NULL state. Execute the action function according
+ * to the state table. If the state returned by action function is
+ * not NULL state, adjust the new state to the returned state.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
+ void* p_data) {
+ tSMP_BR_STATE curr_state = p_cb->br_state;
+ tSMP_BR_SM_TBL state_table;
+ uint8_t action, entry;
+ tSMP_BR_ENTRY_TBL entry_table = smp_br_entry_table[p_cb->role];
+
+ SMP_TRACE_EVENT("main %s", __func__);
+ if (curr_state >= SMP_BR_STATE_MAX) {
+ SMP_TRACE_DEBUG("Invalid br_state: %d", curr_state);
+ return;
+ }
+
+ SMP_TRACE_DEBUG("SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
+ (p_cb->role == HCI_ROLE_SLAVE) ? "Slave" : "Master",
+ smp_get_br_state_name(p_cb->br_state), p_cb->br_state,
+ smp_get_br_event_name(event), event);
+
+ /* look up the state table for the current state */
+ /* lookup entry / w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if ((event <= SMP_BR_MAX_EVT) &&
+ ((entry = entry_table[event - 1][curr_state]) != SMP_BR_SM_IGNORE)) {
+ if (entry & SMP_BR_ALL_TABLE_MASK) {
+ entry &= ~SMP_BR_ALL_TABLE_MASK;
+ state_table = smp_br_all_table;
+ } else {
+ state_table = smp_br_state_table[curr_state][p_cb->role];
+ }
+ } else {
+ SMP_TRACE_DEBUG("Ignore event [%s (%d)] in state [%s (%d)]",
+ smp_get_br_event_name(event), event,
+ smp_get_br_state_name(curr_state), curr_state);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+
+ smp_set_br_state(state_table[entry - 1][SMP_BR_SME_NEXT_STATE]);
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action functions */
+ for (uint8_t i = 0; i < SMP_BR_NUM_ACTIONS; i++) {
+ action = state_table[entry - 1][i];
+ if (action != SMP_BR_SM_NO_ACTION) {
+ (*smp_br_sm_action[action])(p_cb, (tSMP_INT_DATA*)p_data);
+ } else {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG("result state = %s", smp_get_br_state_name(p_cb->br_state));
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_cmac.cc b/mtkbt/code/bt/stack/smp/smp_cmac.cc
new file mode 100755
index 0000000..876c420
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_cmac.cc
@@ -0,0 +1,313 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2008-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "btm_ble_api.h"
+#include "hcimsgs.h"
+#include "smp_int.h"
+
+typedef struct {
+ uint8_t* text;
+ uint16_t len;
+ uint16_t round;
+} tCMAC_CB;
+
+tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+BT_OCTET16 const_Rb = {0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+void print128(BT_OCTET16 x, const uint8_t* key_name) {
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+ uint8_t* p = (uint8_t*)x;
+ uint8_t i;
+
+ SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
+
+ for (i = 0; i < 4; i++) {
+ SMP_TRACE_WARNING("%02x %02x %02x %02x", p[BT_OCTET16_LEN - i * 4 - 1],
+ p[BT_OCTET16_LEN - i * 4 - 2],
+ p[BT_OCTET16_LEN - i * 4 - 3],
+ p[BT_OCTET16_LEN - i * 4 - 4]);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function padding
+ *
+ * Description utility function to padding the given text to be a 128 bits
+ * data. The parameter dest is input and output parameter, it
+ * must point to a BT_OCTET16_LEN memory space; where include
+ * length bytes valid data.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void padding(BT_OCTET16 dest, uint8_t length) {
+ uint8_t i, *p = dest;
+ /* original last block */
+ for (i = length; i < BT_OCTET16_LEN; i++)
+ p[BT_OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
+}
+/*******************************************************************************
+ *
+ * Function leftshift_onebit
+ *
+ * Description utility function to left shift one bit for a 128 bits value.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void leftshift_onebit(uint8_t* input, uint8_t* output) {
+ uint8_t i, overflow = 0, next_overflow = 0;
+ SMP_TRACE_EVENT("leftshift_onebit ");
+ /* input[0] is LSB */
+ for (i = 0; i < BT_OCTET16_LEN; i++) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+/*******************************************************************************
+ *
+ * Function cmac_aes_cleanup
+ *
+ * Description clean up function for AES_CMAC algorithm.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void cmac_aes_cleanup(void) {
+ osi_free(cmac_cb.text);
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+}
+
+/*******************************************************************************
+ *
+ * Function cmac_aes_k_calculate
+ *
+ * Description This function is the calculation of block cipher using
+ * AES-128.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static bool cmac_aes_k_calculate(BT_OCTET16 key, uint8_t* p_signature,
+ uint16_t tlen) {
+ tSMP_ENC output;
+ uint8_t i = 1, err = 0;
+ uint8_t x[16] = {0};
+ uint8_t* p_mac;
+
+ SMP_TRACE_EVENT("cmac_aes_k_calculate ");
+
+ while (i <= cmac_cb.round) {
+ smp_xor_128(&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
+ x); /* Mi' := Mi (+) X */
+
+ if (!SMP_Encrypt(key, BT_OCTET16_LEN,
+ &cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
+ BT_OCTET16_LEN, &output)) {
+ err = 1;
+ break;
+ }
+
+ memcpy(x, output.param_buf, BT_OCTET16_LEN);
+ i++;
+ }
+
+ if (!err) {
+ p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+
+ SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac);
+ SMP_TRACE_DEBUG(
+ "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
+ "0x%02x",
+ *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
+ SMP_TRACE_DEBUG(
+ "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
+ "0x%02x",
+ *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
+
+ return true;
+
+ } else
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function cmac_prepare_last_block
+ *
+ * Description This function proceeed to prepare the last block of message
+ * Mn depending on the size of the message.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void cmac_prepare_last_block(BT_OCTET16 k1, BT_OCTET16 k2) {
+ // uint8_t x[16] = {0};
+ bool flag;
+
+ SMP_TRACE_EVENT("cmac_prepare_last_block ");
+ /* last block is a complete block set flag to 1 */
+ flag =
+ ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
+
+ SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round);
+
+ if (flag) { /* last block is complete block */
+ smp_xor_128(&cmac_cb.text[0], k1);
+ } else /* padding then xor with k2 */
+ {
+ padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+ smp_xor_128(&cmac_cb.text[0], k2);
+ }
+}
+/*******************************************************************************
+ *
+ * Function cmac_subkey_cont
+ *
+ * Description This is the callback function when CIPHk(0[128]) is
+ * completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void cmac_subkey_cont(tSMP_ENC* p) {
+ uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
+ uint8_t* pp = p->param_buf;
+ SMP_TRACE_EVENT("cmac_subkey_cont ");
+ print128(pp, (const uint8_t*)"K1 before shift");
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ((pp[BT_OCTET16_LEN - 1] & 0x80) != 0) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1);
+ smp_xor_128(k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1);
+ }
+
+ if ((k1[BT_OCTET16_LEN - 1] & 0x80) != 0) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1, k2);
+ smp_xor_128(k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1, k2);
+ }
+
+ print128(k1, (const uint8_t*)"K1");
+ print128(k2, (const uint8_t*)"K2");
+
+ cmac_prepare_last_block(k1, k2);
+}
+/*******************************************************************************
+ *
+ * Function cmac_generate_subkey
+ *
+ * Description This is the function to generate the two subkeys.
+ *
+ * Parameters key - CMAC key, expect SRK when used by SMP.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static bool cmac_generate_subkey(BT_OCTET16 key) {
+ BT_OCTET16 z = {0};
+ bool ret = true;
+ tSMP_ENC output;
+ SMP_TRACE_EVENT(" cmac_generate_subkey");
+
+ if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) {
+ cmac_subkey_cont(&output);
+ ;
+ } else
+ ret = false;
+
+ return ret;
+}
+/*******************************************************************************
+ *
+ * Function aes_cipher_msg_auth_code
+ *
+ * Description This is the AES-CMAC Generation Function with tlen
+ * implemented.
+ *
+ * Parameters key - CMAC key in little endian order, expect SRK when used
+ * by SMP.
+ * input - text to be signed in little endian byte order.
+ * length - length of the input in byte.
+ * tlen - lenth of mac desired
+ * p_signature - data pointer to where signed data to be
+ * stored, tlen long.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ ******************************************************************************/
+bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
+ uint16_t tlen, uint8_t* p_signature) {
+ uint16_t len, diff;
+ uint16_t n = (length + BT_OCTET16_LEN - 1) /
+ BT_OCTET16_LEN; /* n is number of rounds */
+ bool ret = false;
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ if (n == 0) n = 1;
+ len = n * BT_OCTET16_LEN;
+
+ SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len);
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ cmac_cb.text = (uint8_t*)osi_calloc(len);
+ cmac_cb.round = n;
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff], input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ if (cmac_generate_subkey(key)) {
+ /* start calculation */
+ ret = cmac_aes_k_calculate(key, p_signature, tlen);
+ }
+ /* clean up */
+ cmac_aes_cleanup();
+
+ return ret;
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_int.h b/mtkbt/code/bt/stack/smp/smp_int.h
new file mode 100755
index 0000000..ed22968
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_int.h
@@ -0,0 +1,545 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains internally used SMP definitions
+ *
+ ******************************************************************************/
+#ifndef SMP_INT_H
+#define SMP_INT_H
+
+#include "btm_api.h"
+#include "btm_ble_api.h"
+#include "btu.h"
+#include "smp_api.h"
+
+/* Legacy mode */
+#define SMP_MODEL_ENCRYPTION_ONLY 0 /* Just Works model */
+#define SMP_MODEL_PASSKEY 1 /* Passkey Entry model, input the key */
+#define SMP_MODEL_OOB 2 /* OOB model */
+#define SMP_MODEL_KEY_NOTIF 3 /* Passkey Entry model, display the key */
+/* Secure connections mode */
+#define SMP_MODEL_SEC_CONN_JUSTWORKS 4 /* Just Works model */
+#define SMP_MODEL_SEC_CONN_NUM_COMP 5 /* Numeric Comparison model */
+#define SMP_MODEL_SEC_CONN_PASSKEY_ENT 6 /* Passkey Entry model, */
+ /* this side inputs the key */
+#define SMP_MODEL_SEC_CONN_PASSKEY_DISP 7 /* Passkey Entry model, */
+ /* this side displays the key */
+#define SMP_MODEL_SEC_CONN_OOB 8 /* Secure Connections mode, OOB model */
+#define SMP_MODEL_OUT_OF_RANGE 9
+typedef uint8_t tSMP_ASSO_MODEL;
+
+#ifndef SMP_MAX_CONN
+#define SMP_MAX_CONN 2
+#endif
+
+#define SMP_WAIT_FOR_RSP_TIMEOUT_MS (30 * 1000)
+#define SMP_DELAYED_AUTH_TIMEOUT_MS 500
+
+#define SMP_OPCODE_INIT 0x04
+
+/* SMP events */
+#define SMP_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ
+#define SMP_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP
+#define SMP_CONFIRM_EVT SMP_OPCODE_CONFIRM
+#define SMP_RAND_EVT SMP_OPCODE_RAND
+#define SMP_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED
+#define SMP_ENCRPTION_INFO_EVT SMP_OPCODE_ENCRYPT_INFO
+#define SMP_MASTER_ID_EVT SMP_OPCODE_MASTER_ID
+#define SMP_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO
+#define SMP_ID_ADDR_EVT SMP_OPCODE_ID_ADDR
+#define SMP_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO
+#define SMP_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ
+
+#define SMP_PAIR_PUBLIC_KEY_EVT SMP_OPCODE_PAIR_PUBLIC_KEY
+#define SMP_PAIR_KEYPRESS_NOTIFICATION_EVT SMP_OPCODE_PAIR_KEYPR_NOTIF
+
+#define SMP_PAIR_COMMITM_EVT SMP_OPCODE_PAIR_COMMITM
+
+#define SMP_SELF_DEF_EVT (SMP_PAIR_COMMITM_EVT + 1)
+#define SMP_KEY_READY_EVT (SMP_SELF_DEF_EVT)
+#define SMP_ENCRYPTED_EVT (SMP_SELF_DEF_EVT + 1)
+#define SMP_L2CAP_CONN_EVT (SMP_SELF_DEF_EVT + 2)
+#define SMP_L2CAP_DISCONN_EVT (SMP_SELF_DEF_EVT + 3)
+#define SMP_IO_RSP_EVT (SMP_SELF_DEF_EVT + 4)
+#define SMP_API_SEC_GRANT_EVT (SMP_SELF_DEF_EVT + 5)
+#define SMP_TK_REQ_EVT (SMP_SELF_DEF_EVT + 6)
+#define SMP_AUTH_CMPL_EVT (SMP_SELF_DEF_EVT + 7)
+#define SMP_ENC_REQ_EVT (SMP_SELF_DEF_EVT + 8)
+#define SMP_BOND_REQ_EVT (SMP_SELF_DEF_EVT + 9)
+#define SMP_DISCARD_SEC_REQ_EVT (SMP_SELF_DEF_EVT + 10)
+
+#define SMP_PAIR_DHKEY_CHCK_EVT SMP_OPCODE_PAIR_DHKEY_CHECK
+
+/* request to start public key exchange */
+#define SMP_PUBL_KEY_EXCH_REQ_EVT (SMP_SELF_DEF_EVT + 11)
+
+/* local public key created */
+#define SMP_LOC_PUBL_KEY_CRTD_EVT (SMP_SELF_DEF_EVT + 12)
+
+/* both local and peer public keys are saved in cb */
+#define SMP_BOTH_PUBL_KEYS_RCVD_EVT (SMP_SELF_DEF_EVT + 13)
+
+/* DHKey computation is completed, time to start SC phase1 */
+#define SMP_SC_DHKEY_CMPLT_EVT (SMP_SELF_DEF_EVT + 14)
+
+/* new local nonce is generated and saved in p_cb->rand */
+#define SMP_HAVE_LOC_NONCE_EVT (SMP_SELF_DEF_EVT + 15)
+
+/* time to start SC phase2 */
+#define SMP_SC_PHASE1_CMPLT_EVT (SMP_SELF_DEF_EVT + 16)
+
+/* request to calculate number for user check. Used only in the numeric compare
+ * protocol */
+#define SMP_SC_CALC_NC_EVT (SMP_SELF_DEF_EVT + 17)
+
+/* Request to display the number for user check to the user.*/
+/* Used only in the numeric compare protocol */
+#define SMP_SC_DSPL_NC_EVT (SMP_SELF_DEF_EVT + 18)
+
+/* user confirms 'OK' numeric comparison request */
+#define SMP_SC_NC_OK_EVT (SMP_SELF_DEF_EVT + 19)
+
+/* both local and peer DHKey Checks are already present - it is used on slave to
+ * prevent a race condition */
+#define SMP_SC_2_DHCK_CHKS_PRES_EVT (SMP_SELF_DEF_EVT + 20)
+
+/* same meaning as SMP_KEY_READY_EVT to separate between SC and legacy actions
+ */
+#define SMP_SC_KEY_READY_EVT (SMP_SELF_DEF_EVT + 21)
+#define SMP_KEYPRESS_NOTIFICATION_EVENT (SMP_SELF_DEF_EVT + 22)
+
+/* SC OOB data from some repository is provided */
+#define SMP_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 23)
+
+#define SMP_CR_LOC_SC_OOB_DATA_EVT (SMP_SELF_DEF_EVT + 24)
+#define SMP_MAX_EVT SMP_CR_LOC_SC_OOB_DATA_EVT
+
+typedef uint8_t tSMP_EVENT;
+
+/* Assumption it's only using the low 8 bits, if bigger than that, need to
+ * expand it to 16 bits */
+#define SMP_SEC_KEY_MASK 0x00ff
+
+/* SMP pairing state */
+enum {
+ SMP_STATE_IDLE,
+ SMP_STATE_WAIT_APP_RSP,
+ SMP_STATE_SEC_REQ_PENDING,
+ SMP_STATE_PAIR_REQ_RSP,
+ SMP_STATE_WAIT_CONFIRM,
+ SMP_STATE_CONFIRM,
+ SMP_STATE_RAND,
+ SMP_STATE_PUBLIC_KEY_EXCH,
+ SMP_STATE_SEC_CONN_PHS1_START,
+ SMP_STATE_WAIT_COMMITMENT,
+ SMP_STATE_WAIT_NONCE,
+ SMP_STATE_SEC_CONN_PHS2_START,
+ SMP_STATE_WAIT_DHK_CHECK,
+ SMP_STATE_DHK_CHECK,
+ SMP_STATE_ENCRYPTION_PENDING,
+ SMP_STATE_BOND_PENDING,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA,
+ SMP_STATE_MAX
+};
+typedef uint8_t tSMP_STATE;
+
+/* SMP over BR/EDR events */
+#define SMP_BR_PAIRING_REQ_EVT SMP_OPCODE_PAIRING_REQ
+#define SMP_BR_PAIRING_RSP_EVT SMP_OPCODE_PAIRING_RSP
+#define SMP_BR_CONFIRM_EVT SMP_OPCODE_CONFIRM /* not over BR/EDR */
+#define SMP_BR_RAND_EVT SMP_OPCODE_RAND /* not over BR/EDR */
+#define SMP_BR_PAIRING_FAILED_EVT SMP_OPCODE_PAIRING_FAILED
+#define SMP_BR_ENCRPTION_INFO_EVT \
+ SMP_OPCODE_ENCRYPT_INFO /* not over BR/EDR \
+ */
+#define SMP_BR_MASTER_ID_EVT SMP_OPCODE_MASTER_ID /* not over BR/EDR */
+#define SMP_BR_ID_INFO_EVT SMP_OPCODE_IDENTITY_INFO
+#define SMP_BR_ID_ADDR_EVT SMP_OPCODE_ID_ADDR
+#define SMP_BR_SIGN_INFO_EVT SMP_OPCODE_SIGN_INFO
+#define SMP_BR_SECURITY_REQ_EVT SMP_OPCODE_SEC_REQ /* not over BR/EDR */
+#define SMP_BR_PAIR_PUBLIC_KEY_EVT \
+ SMP_OPCODE_PAIR_PUBLIC_KEY /* not over BR/EDR */
+#define SMP_BR_PAIR_DHKEY_CHCK_EVT \
+ SMP_OPCODE_PAIR_DHKEY_CHECK /* not over BR/EDR */
+#define SMP_BR_PAIR_KEYPR_NOTIF_EVT \
+ SMP_OPCODE_PAIR_KEYPR_NOTIF /* not over BR/EDR */
+#define SMP_BR_SELF_DEF_EVT SMP_BR_PAIR_KEYPR_NOTIF_EVT
+#define SMP_BR_KEY_READY_EVT (SMP_BR_SELF_DEF_EVT + 1)
+#define SMP_BR_ENCRYPTED_EVT (SMP_BR_SELF_DEF_EVT + 2)
+#define SMP_BR_L2CAP_CONN_EVT (SMP_BR_SELF_DEF_EVT + 3)
+#define SMP_BR_L2CAP_DISCONN_EVT (SMP_BR_SELF_DEF_EVT + 4)
+#define SMP_BR_KEYS_RSP_EVT (SMP_BR_SELF_DEF_EVT + 5)
+#define SMP_BR_API_SEC_GRANT_EVT (SMP_BR_SELF_DEF_EVT + 6)
+#define SMP_BR_TK_REQ_EVT (SMP_BR_SELF_DEF_EVT + 7)
+#define SMP_BR_AUTH_CMPL_EVT (SMP_BR_SELF_DEF_EVT + 8)
+#define SMP_BR_ENC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 9)
+#define SMP_BR_BOND_REQ_EVT (SMP_BR_SELF_DEF_EVT + 10)
+#define SMP_BR_DISCARD_SEC_REQ_EVT (SMP_BR_SELF_DEF_EVT + 11)
+#define SMP_BR_MAX_EVT (SMP_BR_SELF_DEF_EVT + 12)
+typedef uint8_t tSMP_BR_EVENT;
+
+/* SMP over BR/EDR pairing states */
+enum {
+ SMP_BR_STATE_IDLE = SMP_STATE_IDLE,
+ SMP_BR_STATE_WAIT_APP_RSP,
+ SMP_BR_STATE_PAIR_REQ_RSP,
+ SMP_BR_STATE_BOND_PENDING,
+ SMP_BR_STATE_MAX
+};
+typedef uint8_t tSMP_BR_STATE;
+
+enum {
+ SMP_KEY_TYPE_TK,
+ SMP_KEY_TYPE_CFM,
+ SMP_KEY_TYPE_CMP,
+ SMP_KEY_TYPE_PEER_DHK_CHCK,
+ SMP_KEY_TYPE_STK,
+ SMP_KEY_TYPE_LTK
+};
+typedef struct {
+ uint8_t key_type;
+ uint8_t* p_data;
+} tSMP_KEY;
+
+typedef union {
+ uint8_t* p_data; /* uint8_t type data pointer */
+ tSMP_KEY key;
+ uint16_t reason;
+ uint32_t passkey;
+ tSMP_OOB_DATA_TYPE req_oob_type;
+} tSMP_INT_DATA;
+
+/* internal status mask */
+#define SMP_PAIR_FLAGS_WE_STARTED_DD (1)
+#define SMP_PAIR_FLAGS_PEER_STARTED_DD (1 << 1)
+#define SMP_PAIR_FLAGS_CMD_CONFIRM (1 << SMP_OPCODE_CONFIRM) /* 1 << 3 */
+#define SMP_PAIR_FLAG_ENC_AFTER_PAIR (1 << 4)
+#define SMP_PAIR_FLAG_HAVE_PEER_DHK_CHK \
+ (1 << 5) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY \
+ (1 << 6) /* used on slave to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_PEER_COMM \
+ (1 << 7) /* used to resolve race condition */
+#define SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY \
+ (1 << 8) /* used on slave to resolve race condition */
+
+/* check if authentication requirement need MITM protection */
+#define SMP_NO_MITM_REQUIRED(x) (((x)&SMP_AUTH_YN_BIT) == 0)
+
+#define SMP_ENCRYT_KEY_SIZE 16
+#define SMP_ENCRYT_DATA_SIZE 16
+#define SMP_ECNCRPYT_STATUS HCI_SUCCESS
+
+typedef struct {
+ BD_ADDR bd_addr;
+ BT_HDR* p_copy;
+} tSMP_REQ_Q_ENTRY;
+
+/* SMP control block */
+typedef struct {
+ tSMP_CALLBACK* p_callback;
+ alarm_t* smp_rsp_timer_ent;
+ uint8_t trace_level;
+ BD_ADDR pairing_bda;
+ tSMP_STATE state;
+ bool derive_lk;
+ bool id_addr_rcvd;
+ tBLE_ADDR_TYPE id_addr_type;
+ BD_ADDR id_addr;
+ bool smp_over_br;
+ tSMP_BR_STATE br_state; /* if SMP over BR/ERD has priority over SMP */
+ uint8_t failure;
+ uint8_t status;
+ uint8_t role;
+ uint16_t flags;
+ uint8_t cb_evt;
+ tSMP_SEC_LEVEL sec_level;
+ bool connect_initialized;
+ BT_OCTET16 confirm;
+ BT_OCTET16 rconfirm;
+ BT_OCTET16 rrand; /* for SC this is peer nonce */
+ BT_OCTET16 rand; /* for SC this is local nonce */
+ BT_OCTET32 private_key;
+ BT_OCTET32 dhkey;
+ BT_OCTET16 commitment;
+ BT_OCTET16 remote_commitment;
+ BT_OCTET16 local_random; /* local randomizer - passkey or OOB randomizer */
+ BT_OCTET16 peer_random; /* peer randomizer - passkey or OOB randomizer */
+ BT_OCTET16 dhkey_check;
+ BT_OCTET16 remote_dhkey_check;
+ tSMP_PUBLIC_KEY loc_publ_key;
+ tSMP_PUBLIC_KEY peer_publ_key;
+ tSMP_OOB_DATA_TYPE req_oob_type;
+ tSMP_SC_OOB_DATA sc_oob_data;
+ tSMP_IO_CAP peer_io_caps;
+ tSMP_IO_CAP local_io_capability;
+ tSMP_OOB_FLAG peer_oob_flag;
+ tSMP_OOB_FLAG loc_oob_flag;
+ tSMP_AUTH_REQ peer_auth_req;
+ tSMP_AUTH_REQ loc_auth_req;
+ bool secure_connections_only_mode_required; /* true if locally SM is required
+ to operate */
+ /* either in Secure Connections mode or not at all */
+ tSMP_ASSO_MODEL selected_association_model;
+ bool le_secure_connections_mode_is_used;
+ bool key_derivation_h7_used;
+ bool le_sc_kp_notif_is_used;
+ tSMP_SC_KEY_TYPE local_keypress_notification;
+ tSMP_SC_KEY_TYPE peer_keypress_notification;
+ uint8_t
+ round; /* authentication stage 1 round for passkey association model */
+ uint32_t number_to_display;
+ BT_OCTET16 mac_key;
+ uint8_t peer_enc_size;
+ uint8_t loc_enc_size;
+ uint8_t peer_i_key;
+ uint8_t peer_r_key;
+ uint8_t local_i_key;
+ uint8_t local_r_key;
+
+ BT_OCTET16 tk;
+ BT_OCTET16 ltk;
+ uint16_t div;
+ BT_OCTET16 csrk; /* storage for local CSRK */
+ uint16_t ediv;
+ BT_OCTET8 enc_rand;
+ uint8_t addr_type;
+ BD_ADDR local_bda;
+ bool is_pair_cancel;
+ bool discard_sec_req;
+ uint8_t rcvd_cmd_code;
+ uint8_t rcvd_cmd_len;
+ uint16_t total_tx_unacked;
+ bool wait_for_authorization_complete;
+ uint8_t cert_failure; /*failure case for certification */
+ alarm_t* delayed_auth_timer_ent;
+} tSMP_CB;
+
+/* Server Action functions are of this type */
+typedef void (*tSMP_ACT)(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+
+extern tSMP_CB smp_cb;
+
+/* Functions provided by att_main.cc */
+extern void smp_init(void);
+
+/* smp main */
+extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data);
+
+extern void smp_proc_sec_request(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_set_fail_nc(bool enable);
+extern void smp_set_fail_conf(bool enable);
+extern void smp_set_passk_entry_fail(bool enable);
+extern void smp_set_oob_fail(bool enable);
+extern void smp_set_peer_sc_notif(bool enable);
+extern void smp_aes_cmac_rfc4493_chk(uint8_t* key, uint8_t* msg,
+ uint8_t msg_len, uint8_t mac_len,
+ uint8_t* mac);
+extern void smp_f4_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Z,
+ uint8_t* mac);
+extern void smp_g2_calc_chk(uint8_t* U, uint8_t* V, uint8_t* X, uint8_t* Y);
+extern void smp_h6_calc_chk(uint8_t* key, uint8_t* key_id, uint8_t* mac);
+extern void smp_f5_key_calc_chk(uint8_t* w, uint8_t* mac);
+extern void smp_f5_mackey_or_ltk_calc_chk(uint8_t* t, uint8_t* counter,
+ uint8_t* key_id, uint8_t* n1,
+ uint8_t* n2, uint8_t* a1, uint8_t* a2,
+ uint8_t* length, uint8_t* mac);
+extern void smp_f5_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
+extern void smp_f6_calc_chk(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
+ uint8_t* iocap, uint8_t* a1, uint8_t* a2,
+ uint8_t* mac);
+/* smp_main */
+extern void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data);
+extern tSMP_STATE smp_get_state(void);
+extern void smp_set_state(tSMP_STATE state);
+
+/* smp_br_main */
+extern void smp_br_state_machine_event(tSMP_CB* p_cb, tSMP_BR_EVENT event,
+ void* p_data);
+extern tSMP_BR_STATE smp_get_br_state(void);
+extern void smp_set_br_state(tSMP_BR_STATE state);
+
+/* smp_act.cc */
+extern void smp_send_pair_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_pair_public_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_commitment(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_keypress_notification(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_confirm(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_rand(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_process_pairing_public_key(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_proc_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_master_id(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_id_addr(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_sec_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_sec_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_sl_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_start_enc(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_enc_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_discard(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_pairing_cmpl(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_decide_association_model(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_app_cback(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_check_auth_req(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_process_io_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_id_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_enc_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_csrk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_ltk_reply(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_pair_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_idle_terminate(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_send_pair_rsp(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_key_distribution(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_proc_srk_info(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_generate_csrk(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_fast_conn_param(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_key_pick_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_both_have_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_start_secure_connection_phase1(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_process_local_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_process_pairing_commitment(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_process_peer_nonce(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_process_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_match_dhkey_checks(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_process_keypress_notification(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_move_to_secure_connections_phase2(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_phase_2_dhkey_checks_are_present(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_wait_for_both_public_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_start_passkey_verification(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_process_secure_connection_oob_data(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_process_secure_connection_long_term_key(void);
+extern void smp_set_local_oob_keys(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_set_local_oob_random_commitment(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_set_derive_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_derive_link_key_from_long_term_key(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_br_process_pairing_command(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_br_process_security_grant(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_br_process_slave_keys_response(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_br_send_pair_response(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_br_check_authorization_request(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_br_select_next_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_br_process_link_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_key_distribution_by_transport(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_br_pairing_complete(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+
+/* smp_l2c */
+extern void smp_l2cap_if_init(void);
+extern void smp_data_ind(BD_ADDR bd_addr, BT_HDR* p_buf);
+
+/* smp_util.cc */
+extern bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb);
+extern void smp_cb_cleanup(tSMP_CB* p_cb);
+extern void smp_reset_control_value(tSMP_CB* p_cb);
+extern void smp_proc_pairing_cmpl(tSMP_CB* p_cb);
+extern void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey);
+extern void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data);
+extern void smp_rsp_timeout(void* data);
+extern void smp_delayed_auth_complete_timeout(void* data);
+extern void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b);
+extern bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, tSMP_ENC* p_out);
+extern bool smp_command_has_invalid_parameters(tSMP_CB* p_cb);
+extern void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr);
+extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb);
+extern void smp_reverse_array(uint8_t* arr, uint8_t len);
+extern uint8_t smp_calculate_random_input(uint8_t* random, uint8_t round);
+extern void smp_collect_local_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb);
+extern void smp_collect_peer_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb);
+extern void smp_collect_local_ble_address(uint8_t* le_addr, tSMP_CB* p_cb);
+extern void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb);
+extern bool smp_check_commitment(tSMP_CB* p_cb);
+extern void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb);
+extern bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb);
+extern void smp_remove_fixed_channel(tSMP_CB* p_cb);
+extern bool smp_request_oob_data(tSMP_CB* p_cb);
+
+/* smp_keys.cc */
+extern void smp_generate_srand_mrand_confirm(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_generate_compare(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_generate_stk(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_generate_ltk(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_generate_passkey(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_generate_rand_cont(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_create_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_compute_dhkey(tSMP_CB* p_cb);
+extern void smp_calculate_local_commitment(tSMP_CB* p_cb);
+extern void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf);
+extern void smp_calculate_numeric_comparison_display_number(
+ tSMP_CB* p_cb, tSMP_INT_DATA* p_data);
+extern void smp_calculate_local_dhkey_check(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data);
+extern void smp_start_nonce_generation(tSMP_CB* p_cb);
+extern bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb);
+extern bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb);
+extern void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
+ uint8_t* c);
+extern uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x,
+ uint8_t* y);
+extern bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* mac_key, uint8_t* ltk);
+extern bool smp_calculate_f5_mackey_or_long_term_key(
+ uint8_t* t, uint8_t* counter, uint8_t* key_id, uint8_t* n1, uint8_t* n2,
+ uint8_t* a1, uint8_t* a2, uint8_t* length, uint8_t* mac);
+extern bool smp_calculate_f5_key(uint8_t* w, uint8_t* t);
+extern bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
+ uint8_t* iocap, uint8_t* a1, uint8_t* a2,
+ uint8_t* f3);
+extern bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* h2);
+extern bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* h2);
+#if (SMP_DEBUG == TRUE)
+extern void smp_debug_print_nbyte_little_endian(uint8_t* p,
+ const char* key_name,
+ uint8_t len);
+#endif
+
+/* smp_cmac.cc */
+extern bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input,
+ uint16_t length, uint16_t tlen,
+ uint8_t* p_signature);
+extern void print128(BT_OCTET16 x, const uint8_t* key_name);
+
+#endif /* SMP_INT_H */
diff --git a/mtkbt/code/bt/stack/smp/smp_keys.cc b/mtkbt/code/bt/stack/smp/smp_keys.cc
new file mode 100755
index 0000000..fb77c77
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_keys.cc
@@ -0,0 +1,1924 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains security manager protocol utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#if (SMP_DEBUG == TRUE)
+#include <stdio.h>
+#endif
+#include <base/bind.h>
+#include <string.h>
+#include "aes.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_ble_int.h"
+#include "btm_int.h"
+#include "device/include/controller.h"
+#include "hcimsgs.h"
+#include "osi/include/osi.h"
+#include "p_256_ecc_pp.h"
+#include "smp_int.h"
+
+using base::Bind;
+
+#ifndef SMP_MAX_ENC_REPEAT
+#define SMP_MAX_ENC_REPEAT 3
+#endif
+
+static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p);
+static bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb,
+ tSMP_ENC* output);
+static void smp_process_private_key(tSMP_CB* p_cb);
+
+#define SMP_PASSKEY_MASK 0xfff00000
+
+void smp_debug_print_nbyte_little_endian(uint8_t* p, const char* key_name,
+ uint8_t len) {
+#if (SMP_DEBUG == TRUE)
+ int ind;
+ int col_count = 32;
+ int row_count;
+ uint8_t p_buf[512];
+
+ SMP_TRACE_DEBUG("%s(LSB ~ MSB):", key_name);
+ memset(p_buf, 0, sizeof(p_buf));
+ row_count = len % col_count ? len / col_count + 1 : len / col_count;
+
+ ind = 0;
+ for (int row = 0; row < row_count; row++) {
+ for (int column = 0, x = 0; (ind < len) && (column < col_count);
+ column++, ind++) {
+ x += snprintf((char*)&p_buf[x], sizeof(p_buf) - x, "%02x ", p[ind]);
+ }
+ SMP_TRACE_DEBUG(" [%03d]: %s", row * col_count, p_buf);
+ }
+#endif
+}
+
+void smp_debug_print_nbyte_big_endian(uint8_t* p, const char* key_name,
+ uint8_t len) {
+#if (SMP_DEBUG == TRUE)
+ uint8_t p_buf[512];
+
+ SMP_TRACE_DEBUG("%s(MSB ~ LSB):", key_name);
+ memset(p_buf, 0, sizeof(p_buf));
+
+ int ind = 0;
+ int ncols = 32; /* num entries in one line */
+ int nrows; /* num lines */
+
+ nrows = len % ncols ? len / ncols + 1 : len / ncols;
+ for (int row = 0; row < nrows; row++) {
+ for (int col = 0, x = 0; (ind < len) && (col < ncols); col++, ind++) {
+ x += snprintf((char*)&p_buf[len - x - 1], sizeof(p_buf) - (len - x - 1),
+ "%02x ", p[ind]);
+ }
+ SMP_TRACE_DEBUG("[%03d]: %s", row * ncols, p_buf);
+ }
+#endif
+}
+
+/*******************************************************************************
+ *
+ * Function smp_encrypt_data
+ *
+ * Description This function is called to encrypt data.
+ * It uses AES-128 encryption algorithm.
+ * Plain_text is encrypted using key, the result is at p_out.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool smp_encrypt_data(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, tSMP_ENC* p_out) {
+ aes_context ctx;
+ uint8_t* p_start = NULL;
+ uint8_t* p = NULL;
+ uint8_t* p_rev_data = NULL; /* input data in big endilan format */
+ uint8_t* p_rev_key = NULL; /* input key in big endilan format */
+ uint8_t* p_rev_output = NULL; /* encrypted output in big endilan format */
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ if ((p_out == NULL) || (key_len != SMP_ENCRYT_KEY_SIZE)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ return false;
+ }
+
+ p_start = (uint8_t*)osi_calloc(SMP_ENCRYT_DATA_SIZE * 4);
+
+ if (pt_len > SMP_ENCRYT_DATA_SIZE) pt_len = SMP_ENCRYT_DATA_SIZE;
+
+ p = p_start;
+ ARRAY_TO_STREAM(p, plain_text, pt_len); /* byte 0 to byte 15 */
+ p_rev_data = p = p_start + SMP_ENCRYT_DATA_SIZE; /* start at byte 16 */
+ REVERSE_ARRAY_TO_STREAM(p, p_start,
+ SMP_ENCRYT_DATA_SIZE); /* byte 16 to byte 31 */
+ p_rev_key = p; /* start at byte 32 */
+ REVERSE_ARRAY_TO_STREAM(p, key, SMP_ENCRYT_KEY_SIZE); /* byte 32 to byte 47 */
+
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+ smp_debug_print_nbyte_little_endian(key, "Key", SMP_ENCRYT_KEY_SIZE);
+ smp_debug_print_nbyte_little_endian(p_start, "Plain text",
+ SMP_ENCRYT_DATA_SIZE);
+#endif
+ p_rev_output = p;
+ aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
+ aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
+
+ p = p_out->param_buf;
+ REVERSE_ARRAY_TO_STREAM(p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
+#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
+ smp_debug_print_nbyte_little_endian(p_out->param_buf, "Encrypted text",
+ SMP_ENCRYT_KEY_SIZE);
+#endif
+
+ p_out->param_len = SMP_ENCRYT_KEY_SIZE;
+ p_out->status = HCI_SUCCESS;
+ p_out->opcode = HCI_BLE_ENCRYPT;
+
+ osi_free(p_start);
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_proc_passkey
+ *
+ * Description This function is called to process a passkey.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_proc_passkey(tSMP_CB* p_cb, BT_OCTET8 rand) {
+ uint8_t* tt = p_cb->tk;
+ tSMP_KEY key;
+ uint32_t passkey; /* 19655 test number; */
+ uint8_t* pp = rand;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ STREAM_TO_UINT32(passkey, pp);
+ passkey &= ~SMP_PASSKEY_MASK;
+
+ /* truncate by maximum value */
+ while (passkey > BTM_MAX_PASSKEY_VAL) passkey >>= 1;
+
+ /* save the TK */
+ memset(p_cb->tk, 0, BT_OCTET16_LEN);
+ UINT32_TO_STREAM(tt, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = p_cb->tk;
+
+ if (p_cb->p_callback) {
+ (*p_cb->p_callback)(SMP_PASSKEY_NOTIF_EVT, p_cb->pairing_bda,
+ (tSMP_EVT_DATA*)&passkey);
+ }
+
+ if (p_cb->selected_association_model == SMP_MODEL_SEC_CONN_PASSKEY_DISP) {
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &passkey);
+ } else {
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, (tSMP_INT_DATA*)&key);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_passkey
+ *
+ * Description This function is called to generate passkey.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_generate_passkey(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* generate MRand or SRand */
+ btsnd_hcic_ble_rand(Bind(&smp_proc_passkey, p_cb));
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_stk
+ *
+ * Description This function is called to generate STK calculated by
+ * running AES with the TK value as key and a concatenation of
+ * the random values.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_generate_stk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->le_secure_connections_mode_is_used) {
+ SMP_TRACE_WARNING("FOR LE SC LTK IS USED INSTEAD OF STK");
+ output.param_len = SMP_ENCRYT_KEY_SIZE;
+ output.status = HCI_SUCCESS;
+ output.opcode = HCI_BLE_ENCRYPT;
+ memcpy(output.param_buf, p_cb->ltk, SMP_ENCRYT_DATA_SIZE);
+ } else if (!smp_calculate_legacy_short_term_key(p_cb, &output)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+
+ smp_process_stk(p_cb, &output);
+}
+
+/**
+ * This function is called to calculate CSRK
+ */
+void smp_compute_csrk(uint16_t div, tSMP_CB* p_cb) {
+ BT_OCTET16 er;
+ uint8_t buffer[4]; /* for (r || DIV) r=1*/
+ uint16_t r = 1;
+ uint8_t* p = buffer;
+ tSMP_ENC output;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ p_cb->div = div;
+
+ SMP_TRACE_DEBUG("%s: div=%x", __func__, p_cb->div);
+ BTM_GetDeviceEncRoot(er);
+ /* CSRK = d1(ER, DIV, 1) */
+ UINT16_TO_STREAM(p, p_cb->div);
+ UINT16_TO_STREAM(p, r);
+
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, buffer, 4, &output)) {
+ SMP_TRACE_ERROR("smp_generate_csrk failed");
+ if (p_cb->smp_over_br) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &status);
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+ } else {
+ memcpy((void*)p_cb->csrk, output.param_buf, BT_OCTET16_LEN);
+ smp_send_csrk_info(p_cb, NULL);
+ }
+}
+
+/**
+ * This function is called to calculate CSRK, starting with DIV generation.
+ */
+void smp_generate_csrk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ bool div_status;
+
+ SMP_TRACE_DEBUG("smp_generate_csrk");
+
+ div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+ if (div_status) {
+ smp_compute_csrk(p_cb->div, p_cb);
+ } else {
+ SMP_TRACE_DEBUG("Generate DIV for CSRK");
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ uint16_t div;
+ STREAM_TO_UINT16(div, rand);
+ smp_compute_csrk(div, p_cb);
+ },
+ p_cb));
+ }
+}
+
+/*******************************************************************************
+ * Function smp_concatenate_peer - LSB first
+ * add pairing command sent from local device into p1.
+ ******************************************************************************/
+void smp_concatenate_local(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) {
+ uint8_t* p = *p_data;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->local_io_capability);
+ UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM(p, p_cb->local_i_key);
+ UINT8_TO_STREAM(p, p_cb->local_r_key);
+
+ *p_data = p;
+}
+
+/*******************************************************************************
+ * Function smp_concatenate_peer - LSB first
+ * add pairing command received from peer device into p1.
+ ******************************************************************************/
+void smp_concatenate_peer(tSMP_CB* p_cb, uint8_t** p_data, uint8_t op_code) {
+ uint8_t* p = *p_data;
+
+ SMP_TRACE_DEBUG("smp_concatenate_peer ");
+ UINT8_TO_STREAM(p, op_code);
+ UINT8_TO_STREAM(p, p_cb->peer_io_caps);
+ UINT8_TO_STREAM(p, p_cb->peer_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->peer_auth_req);
+ UINT8_TO_STREAM(p, p_cb->peer_enc_size);
+ UINT8_TO_STREAM(p, p_cb->peer_i_key);
+ UINT8_TO_STREAM(p, p_cb->peer_r_key);
+
+ *p_data = p;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_gen_p1_4_confirm
+ *
+ * Description Generate Confirm/Compare Step1:
+ * p1 = (MSB) pres || preq || rat' || iat' (LSB)
+ * Fill in values LSB first thus
+ * p1 = iat' || rat' || preq || pres
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_gen_p1_4_confirm(tSMP_CB* p_cb, tBLE_ADDR_TYPE remote_bd_addr_type,
+ BT_OCTET16 p1) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ uint8_t* p = (uint8_t*)p1;
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ /* iat': initiator's (local) address type */
+ UINT8_TO_STREAM(p, p_cb->addr_type);
+ /* rat': responder's (remote) address type */
+ UINT8_TO_STREAM(p, remote_bd_addr_type);
+ /* preq : Pairing Request (local) command */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* pres : Pairing Response (remote) command */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ } else {
+ /* iat': initiator's (remote) address type */
+ UINT8_TO_STREAM(p, remote_bd_addr_type);
+ /* rat': responder's (local) address type */
+ UINT8_TO_STREAM(p, p_cb->addr_type);
+ /* preq : Pairing Request (remote) command */
+ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ);
+ /* pres : Pairing Response (local) command */
+ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP);
+ }
+ smp_debug_print_nbyte_little_endian((uint8_t*)p1,
+ "p1 = iat' || rat' || preq || pres", 16);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_gen_p2_4_confirm
+ *
+ * Description Generate Confirm/Compare Step2:
+ * p2 = (MSB) padding || ia || ra (LSB)
+ * Fill values LSB first and thus:
+ * p2 = ra || ia || padding
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_gen_p2_4_confirm(tSMP_CB* p_cb, BD_ADDR remote_bda, BT_OCTET16 p2) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ uint8_t* p = (uint8_t*)p2;
+ /* 32-bit Padding */
+ memset(p, 0, sizeof(BT_OCTET16));
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ /* ra : Responder's (remote) address */
+ BDADDR_TO_STREAM(p, remote_bda);
+ /* ia : Initiator's (local) address */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ } else {
+ /* ra : Responder's (local) address */
+ BDADDR_TO_STREAM(p, p_cb->local_bda);
+ /* ia : Initiator's (remote) address */
+ BDADDR_TO_STREAM(p, remote_bda);
+ }
+ smp_debug_print_nbyte_little_endian(p2, "p2 = ra || ia || padding", 16);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_comfirm
+ *
+ * Description This function (c1) is called to calculate Confirm value.
+ *
+ * Returns tSMP_STATUS status of confirmation calculation
+ *
+ ******************************************************************************/
+tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
+ tSMP_ENC* output) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ BD_ADDR remote_bda;
+ tBLE_ADDR_TYPE remote_bd_addr_type = 0;
+ /* get remote connection specific bluetooth address */
+ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, remote_bda,
+ &remote_bd_addr_type)) {
+ SMP_TRACE_ERROR("%s: cannot obtain remote device address", __func__);
+ return SMP_PAIR_FAIL_UNKNOWN;
+ }
+ /* get local connection specific bluetooth address */
+ BTM_ReadConnectionAddr(p_cb->pairing_bda, p_cb->local_bda, &p_cb->addr_type);
+ /* generate p1 = pres || preq || rat' || iat' */
+ BT_OCTET16 p1;
+ smp_gen_p1_4_confirm(p_cb, remote_bd_addr_type, p1);
+ /* p1' = rand XOR p1 */
+ smp_xor_128(p1, rand);
+ smp_debug_print_nbyte_little_endian((uint8_t*)p1, "p1' = p1 XOR r", 16);
+ /* calculate e1 = e(k, p1'), where k = TK */
+ smp_debug_print_nbyte_little_endian(p_cb->tk, "TK", 16);
+ memset(output, 0, sizeof(tSMP_ENC));
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, output)) {
+ SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p1')");
+ return SMP_PAIR_FAIL_UNKNOWN;
+ }
+ smp_debug_print_nbyte_little_endian(output->param_buf, "e1 = e(k, p1')", 16);
+ /* generate p2 = padding || ia || ra */
+ BT_OCTET16 p2;
+ smp_gen_p2_4_confirm(p_cb, remote_bda, p2);
+ /* calculate p2' = (p2 XOR e1) */
+ smp_xor_128(p2, output->param_buf);
+ smp_debug_print_nbyte_little_endian((uint8_t*)p2, "p2' = p2 XOR e1", 16);
+ /* calculate: c1 = e(k, p2') */
+ memset(output, 0, sizeof(tSMP_ENC));
+ if (!SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, p2, BT_OCTET16_LEN, output)) {
+ SMP_TRACE_ERROR("%s: failed encryption at e1 = e(k, p2')");
+ return SMP_PAIR_FAIL_UNKNOWN;
+ }
+ return SMP_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_confirm
+ *
+ * Description This function is called when random number (MRand or SRand)
+ * is generated by the controller and the stack needs to
+ * calculate c1 value (MConfirm or SConfirm) for the first time
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void smp_generate_confirm(tSMP_CB* p_cb) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rand, "local_rand", 16);
+ tSMP_ENC output;
+ tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rand, &output);
+ if (status != SMP_SUCCESS) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+ tSMP_KEY key;
+ memcpy(p_cb->confirm, output.param_buf, BT_OCTET16_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->confirm, "Local Confirm generated",
+ 16);
+ key.key_type = SMP_KEY_TYPE_CFM;
+ key.p_data = output.param_buf;
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_srand_mrand_confirm
+ *
+ * Description This function is called to start the second pairing phase by
+ * start generating random number.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_generate_srand_mrand_confirm(tSMP_CB* p_cb,
+ UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* generate MRand or SRand */
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)p_cb->rand, rand, 8);
+
+ /* generate 64 MSB of MRand or SRand */
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)&p_cb->rand[8], rand, BT_OCTET8_LEN);
+ smp_generate_confirm(p_cb);
+ },
+ p_cb));
+ },
+ p_cb));
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_compare
+ *
+ * Description This function is called when random number (MRand or SRand)
+ * is received from remote device and the c1 value (MConfirm
+ * or SConfirm) needs to be generated to authenticate remote
+ * device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_generate_compare(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("smp_generate_compare ");
+ smp_debug_print_nbyte_little_endian((uint8_t*)p_cb->rrand, "peer rand", 16);
+ tSMP_ENC output;
+ tSMP_STATUS status = smp_calculate_comfirm(p_cb, p_cb->rrand, &output);
+ if (status != SMP_SUCCESS) {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ return;
+ }
+ tSMP_KEY key;
+ smp_debug_print_nbyte_little_endian(output.param_buf,
+ "Remote Confirm generated", 16);
+ key.key_type = SMP_KEY_TYPE_CMP;
+ key.p_data = output.param_buf;
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_process_stk
+ *
+ * Description This function is called when STK is generated
+ * proceed to send the encrypt the link using STK.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void smp_process_stk(tSMP_CB* p_cb, tSMP_ENC* p) {
+ tSMP_KEY key;
+
+ SMP_TRACE_DEBUG("smp_process_stk ");
+#if (SMP_DEBUG == TRUE)
+ SMP_TRACE_ERROR("STK Generated");
+#endif
+ smp_mask_enc_key(p_cb->loc_enc_size, p->param_buf);
+
+ key.key_type = SMP_KEY_TYPE_STK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/**
+ * This function is to calculate EDIV = Y xor DIV
+ */
+static void smp_process_ediv(tSMP_CB* p_cb, tSMP_ENC* p) {
+ tSMP_KEY key;
+ uint8_t* pp = p->param_buf;
+ uint16_t y;
+
+ SMP_TRACE_DEBUG("smp_process_ediv ");
+ STREAM_TO_UINT16(y, pp);
+
+ /* EDIV = Y xor DIV */
+ p_cb->ediv = p_cb->div ^ y;
+ /* send LTK ready */
+ SMP_TRACE_ERROR("LTK ready");
+ key.key_type = SMP_KEY_TYPE_LTK;
+ key.p_data = p->param_buf;
+
+ smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/**
+ * This function is to proceed generate Y = E(DHK, Rand)
+ */
+static void smp_generate_y(tSMP_CB* p_cb, BT_OCTET8 rand) {
+ SMP_TRACE_DEBUG("%s ", __func__);
+
+ BT_OCTET16 dhk;
+ BTM_GetDeviceDHK(dhk);
+
+ memcpy(p_cb->enc_rand, rand, BT_OCTET8_LEN);
+ tSMP_ENC output;
+ if (!SMP_Encrypt(dhk, BT_OCTET16_LEN, rand, BT_OCTET8_LEN, &output)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ smp_process_ediv(p_cb, &output);
+ }
+}
+
+/**
+ * Calculate LTK = d1(ER, DIV, 0)= e(ER, DIV)
+ */
+static void smp_generate_ltk_cont(uint16_t div, tSMP_CB* p_cb) {
+ p_cb->div = div;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ BT_OCTET16 er;
+ BTM_GetDeviceEncRoot(er);
+
+ tSMP_ENC output;
+ /* LTK = d1(ER, DIV, 0)= e(ER, DIV)*/
+ if (!SMP_Encrypt(er, BT_OCTET16_LEN, (uint8_t*)&p_cb->div, sizeof(uint16_t),
+ &output)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ } else {
+ /* mask the LTK */
+ smp_mask_enc_key(p_cb->loc_enc_size, output.param_buf);
+ memcpy((void*)p_cb->ltk, output.param_buf, BT_OCTET16_LEN);
+
+ /* generate EDIV and rand now */
+ btsnd_hcic_ble_rand(Bind(&smp_generate_y, p_cb));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_generate_ltk
+ *
+ * Description This function is called:
+ * - in legacy pairing - to calculate LTK, starting with DIV
+ * generation;
+ * - in LE Secure Connections pairing over LE transport - to
+ * process LTK already generated to encrypt LE link;
+ * - in LE Secure Connections pairing over BR/EDR transport -
+ * to start BR/EDR Link Key processing.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_generate_ltk(tSMP_CB* p_cb, UNUSED_ATTR tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (smp_get_br_state() == SMP_BR_STATE_BOND_PENDING) {
+ smp_br_process_link_key(p_cb, NULL);
+ return;
+ } else if (p_cb->le_secure_connections_mode_is_used) {
+ smp_process_secure_connection_long_term_key();
+ return;
+ }
+
+ bool div_status = btm_get_local_div(p_cb->pairing_bda, &p_cb->div);
+
+ if (div_status) {
+ smp_generate_ltk_cont(p_cb->div, p_cb);
+ } else {
+ SMP_TRACE_DEBUG("%s: Generate DIV for LTK", __func__);
+
+ /* generate MRand or SRand */
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ uint16_t div;
+ STREAM_TO_UINT16(div, rand);
+ smp_generate_ltk_cont(div, p_cb);
+ },
+ p_cb));
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_legacy_short_term_key
+ *
+ * Description The function calculates legacy STK.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ ******************************************************************************/
+bool smp_calculate_legacy_short_term_key(tSMP_CB* p_cb, tSMP_ENC* output) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ BT_OCTET16 ptext;
+ uint8_t* p = ptext;
+ memset(p, 0, BT_OCTET16_LEN);
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ memcpy(p, p_cb->rand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rrand, BT_OCTET8_LEN);
+ } else {
+ memcpy(p, p_cb->rrand, BT_OCTET8_LEN);
+ memcpy(&p[BT_OCTET8_LEN], p_cb->rand, BT_OCTET8_LEN);
+ }
+
+ /* generate STK = Etk(rand|rrand)*/
+ bool encrypted =
+ SMP_Encrypt(p_cb->tk, BT_OCTET16_LEN, ptext, BT_OCTET16_LEN, output);
+ if (!encrypted) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ }
+ return encrypted;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_create_private_key
+ *
+ * Description This function is called to create private key used to
+ * calculate public key and DHKey.
+ * The function starts private key creation requesting
+ * for the controller to generate [0-7] octets of private key.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_create_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)p_cb->private_key, rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)&p_cb->private_key[8], rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)&p_cb->private_key[16], rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)&p_cb->private_key[24], rand,
+ BT_OCTET8_LEN);
+ smp_process_private_key(p_cb);
+ },
+ p_cb));
+ },
+ p_cb));
+ },
+ p_cb));
+ },
+ p_cb));
+}
+
+/*******************************************************************************
+ *
+ * Function smp_use_oob_private_key
+ *
+ * Description This function is called
+ * - to save the secret key used to calculate the public key
+ * used in calculations of commitment sent OOB to a peer
+ * - to use this secret key to recalculate the public key and
+ * start the process of sending this public key to the peer
+ * if secret/public keys have to be reused.
+ * If the keys aren't supposed to be reused, continue from the
+ * point from which request for OOB data was issued.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_use_oob_private_key(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s req_oob_type: %d, role: %d", __func__, p_cb->req_oob_type,
+ p_cb->role);
+
+ switch (p_cb->req_oob_type) {
+ case SMP_OOB_BOTH:
+ case SMP_OOB_LOCAL:
+ SMP_TRACE_DEBUG("%s restore secret key", __func__)
+ memcpy(p_cb->private_key, p_cb->sc_oob_data.loc_oob_data.private_key_used,
+ BT_OCTET32_LEN);
+ smp_process_private_key(p_cb);
+ break;
+ default:
+ SMP_TRACE_DEBUG("%s create secret key anew", __func__);
+ smp_set_state(SMP_STATE_PAIR_REQ_RSP);
+ smp_decide_association_model(p_cb, NULL);
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_process_private_key
+ *
+ * Description This function processes private key.
+ * It calculates public key and notifies SM that private key /
+ * public key pair is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_process_private_key(tSMP_CB* p_cb) {
+ Point public_key;
+ BT_OCTET32 private_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
+ ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key,
+ KEY_LENGTH_DWORDS_P256);
+ memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN);
+ memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN);
+
+ smp_debug_print_nbyte_little_endian(p_cb->private_key, "private",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->loc_publ_key.x, "local public(x)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->loc_publ_key.y, "local public(y)",
+ BT_OCTET32_LEN);
+ p_cb->flags |= SMP_PAIR_FLAG_HAVE_LOCAL_PUBL_KEY;
+ smp_sm_event(p_cb, SMP_LOC_PUBL_KEY_CRTD_EVT, NULL);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_compute_dhkey
+ *
+ * Description The function:
+ * - calculates a new public key using as input local private
+ * key and peer public key;
+ * - saves the new public key x-coordinate as DHKey.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_compute_dhkey(tSMP_CB* p_cb) {
+ Point peer_publ_key, new_publ_key;
+ BT_OCTET32 private_key;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
+ memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
+ memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
+
+ ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key,
+ KEY_LENGTH_DWORDS_P256);
+
+ memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
+
+ smp_debug_print_nbyte_little_endian(p_cb->dhkey, "Old DHKey", BT_OCTET32_LEN);
+
+ smp_debug_print_nbyte_little_endian(p_cb->private_key, "private",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->peer_publ_key.x, "rem public(x)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->peer_publ_key.y, "rem public(y)",
+ BT_OCTET32_LEN);
+ smp_debug_print_nbyte_little_endian(p_cb->dhkey, "Reverted DHKey",
+ BT_OCTET32_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_local_commitment
+ *
+ * Description The function calculates and saves local commmitment in CB.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_calculate_local_commitment(tSMP_CB* p_cb) {
+ uint8_t random_input;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_MASTER)
+ SMP_TRACE_WARNING(
+ "local commitment calc on master is not expected \
+ for Just Works/Numeric Comparison models");
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+ 0, p_cb->commitment);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ random_input =
+ smp_calculate_random_input(p_cb->local_random, p_cb->round);
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand,
+ random_input, p_cb->commitment);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ SMP_TRACE_WARNING(
+ "local commitment calc is expected for OOB model BEFORE pairing");
+ smp_calculate_f4(p_cb->loc_publ_key.x, p_cb->loc_publ_key.x,
+ p_cb->local_random, 0, p_cb->commitment);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+ p_cb->selected_association_model);
+ return;
+ }
+
+ SMP_TRACE_EVENT("local commitment calculation is completed");
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_peer_commitment
+ *
+ * Description The function calculates and saves peer commmitment at the
+ * provided output buffer.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_calculate_peer_commitment(tSMP_CB* p_cb, BT_OCTET16 output_buf) {
+ uint8_t ri;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ switch (p_cb->selected_association_model) {
+ case SMP_MODEL_SEC_CONN_JUSTWORKS:
+ case SMP_MODEL_SEC_CONN_NUM_COMP:
+ if (p_cb->role == HCI_ROLE_SLAVE)
+ SMP_TRACE_WARNING(
+ "peer commitment calc on slave is not expected \
+ for Just Works/Numeric Comparison models");
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
+ 0, output_buf);
+ break;
+ case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
+ case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
+ ri = smp_calculate_random_input(p_cb->peer_random, p_cb->round);
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand,
+ ri, output_buf);
+ break;
+ case SMP_MODEL_SEC_CONN_OOB:
+ smp_calculate_f4(p_cb->peer_publ_key.x, p_cb->peer_publ_key.x,
+ p_cb->peer_random, 0, output_buf);
+ break;
+ default:
+ SMP_TRACE_ERROR("Association Model = %d is not used in LE SC",
+ p_cb->selected_association_model);
+ return;
+ }
+
+ SMP_TRACE_EVENT("peer commitment calculation is completed");
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f4
+ *
+ * Description The function calculates
+ * C = f4(U, V, X, Z) = AES-CMAC (U||V||Z)
+ * X
+ * where
+ * input: U is 256 bit,
+ * V is 256 bit,
+ * X is 128 bit,
+ * Z is 8 bit,
+ * output: C is 128 bit.
+ *
+ * Returns void
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+void smp_calculate_f4(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t z,
+ uint8_t* c) {
+ uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */ +
+ 1 /* Z size */;
+ uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + 1];
+ uint8_t key[BT_OCTET16_LEN];
+ uint8_t cmac[BT_OCTET16_LEN];
+ uint8_t* p = NULL;
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+#if (SMP_DEBUG == TRUE)
+ p_prnt = u;
+ smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
+ p_prnt = v;
+ smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
+ p_prnt = x;
+ smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
+ p_prnt = &z;
+ smp_debug_print_nbyte_little_endian(p_prnt, "Z", 1);
+#endif
+
+ p = msg;
+ UINT8_TO_STREAM(p, z);
+ ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+ ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
+#endif
+
+ aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian(p_prnt, "AES_CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_numeric_comparison_display_number
+ *
+ * Description The function calculates and saves number to display in
+ * numeric comparison association mode.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_calculate_numeric_comparison_display_number(tSMP_CB* p_cb,
+ tSMP_INT_DATA* p_data) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ p_cb->number_to_display = smp_calculate_g2(
+ p_cb->loc_publ_key.x, p_cb->peer_publ_key.x, p_cb->rand, p_cb->rrand);
+ } else {
+ p_cb->number_to_display = smp_calculate_g2(
+ p_cb->peer_publ_key.x, p_cb->loc_publ_key.x, p_cb->rrand, p_cb->rand);
+ }
+
+ if (p_cb->number_to_display >= (BTM_MAX_PASSKEY_VAL + 1)) {
+ uint8_t reason;
+ reason = p_cb->failure = SMP_PAIR_FAIL_UNKNOWN;
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ return;
+ }
+
+ SMP_TRACE_EVENT("Number to display in numeric comparison = %d",
+ p_cb->number_to_display);
+ p_cb->cb_evt = SMP_NC_REQ_EVT;
+ smp_sm_event(p_cb, SMP_SC_DSPL_NC_EVT, &p_cb->number_to_display);
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_g2
+ *
+ * Description The function calculates
+ * g2(U, V, X, Y) = AES-CMAC (U||V||Y) mod 2**32 mod 10**6
+ * X
+ * and
+ * Vres = g2(U, V, X, Y) mod 10**6
+ * where
+ * input: U is 256 bit,
+ * V is 256 bit,
+ * X is 128 bit,
+ * Y is 128 bit,
+ *
+ * Returns Vres.
+ * Expected value has to be in the range [0 - 999999] i.e.
+ * [0 - 0xF423F].
+ * Vres = 1000000 means that the calculation fails.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+uint32_t smp_calculate_g2(uint8_t* u, uint8_t* v, uint8_t* x, uint8_t* y) {
+ uint8_t msg_len = BT_OCTET32_LEN /* U size */ + BT_OCTET32_LEN /* V size */
+ + BT_OCTET16_LEN /* Y size */;
+ uint8_t msg[BT_OCTET32_LEN + BT_OCTET32_LEN + BT_OCTET16_LEN];
+ uint8_t key[BT_OCTET16_LEN];
+ uint8_t cmac[BT_OCTET16_LEN];
+ uint8_t* p = NULL;
+ uint32_t vres;
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ p = msg;
+ ARRAY_TO_STREAM(p, y, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, v, BT_OCTET32_LEN);
+ ARRAY_TO_STREAM(p, u, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = u;
+ smp_debug_print_nbyte_little_endian(p_prnt, "U", BT_OCTET32_LEN);
+ p_prnt = v;
+ smp_debug_print_nbyte_little_endian(p_prnt, "V", BT_OCTET32_LEN);
+ p_prnt = x;
+ smp_debug_print_nbyte_little_endian(p_prnt, "X", BT_OCTET16_LEN);
+ p_prnt = y;
+ smp_debug_print_nbyte_little_endian(p_prnt, "Y", BT_OCTET16_LEN);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, x, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
+#endif
+
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ return (BTM_MAX_PASSKEY_VAL + 1);
+ }
+
+#if (SMP_DEBUG == TRUE)
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ p = &cmac[0];
+ STREAM_TO_UINT32(vres, p);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = (uint8_t*)&vres;
+ smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32", 4);
+#endif
+
+ while (vres > BTM_MAX_PASSKEY_VAL) vres -= (BTM_MAX_PASSKEY_VAL + 1);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = (uint8_t*)&vres;
+ smp_debug_print_nbyte_little_endian(p_prnt, "cmac mod 2**32 mod 10**6", 4);
+#endif
+
+ SMP_TRACE_ERROR("Value for numeric comparison = %d", vres);
+ return vres;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f5
+ *
+ * Description The function provides two AES-CMAC that are supposed to be
+ * used as
+ * - MacKey (used in pairing DHKey check calculation);
+ * - LTK (used to ecrypt the link after completion of Phase 2
+ * and on reconnection, to derive BR/EDR LK).
+ * The function inputs are W, N1, N2, A1, A2.
+ * F5 rules:
+ * - the value used as key in MacKey/LTK (T) is calculated
+ * (function smp_calculate_f5_key(...));
+ * The formula is:
+ * T = AES-CMAC (W)
+ * salt
+ * where salt is internal parameter of
+ * smp_calculate_f5_key(...).
+ * - MacKey and LTK are calculated as AES-MAC values received
+ * with the key T calculated in the previous step and the
+ * plaintext message built from the external parameters N1,
+ * N2, A1, A2 and the internal parameters counter, keyID,
+ * length.
+ * The function smp_calculate_f5_mackey_or_long_term_key(...)
+ * is used in the calculations.
+ * The same formula is used in calculation of MacKey and LTK
+ * and the same parameter values except the value of the
+ * internal parameter counter:
+ * - in MacKey calculations the value is 0;
+ * - in LTK calculations the value is 1.
+ * MacKey =
+ * AES-CMAC (Counter=0||keyID||N1||N2||A1||A2||Length=256)
+ * T
+ * LTK =
+ * AES-CMAC (Counter=1||keyID||N1||N2||A1||A2||Length=256)
+ * T
+ * The parameters are
+ * input:
+ * W is 256 bits,
+ * N1 is 128 bits,
+ * N2 is 128 bits,
+ * A1 is 56 bit,
+ * A2 is 56 bit.
+ * internal:
+ * Counter is 8 bits, its value is 0 for MacKey,
+ * 1 for LTK;
+ * KeyId is 32 bits, its value is
+ * 0x62746c65 (MSB~LSB);
+ * Length is 16 bits, its value is 0x0100
+ * (MSB~LSB).
+ * output:
+ * MacKey is 128 bits;
+ * LTK is 128 bits
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+bool smp_calculate_f5(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* mac_key, uint8_t* ltk) {
+ BT_OCTET16 t; /* AES-CMAC output in smp_calculate_f5_key(...), key in */
+ /* smp_calculate_f5_mackey_or_long_term_key(...) */
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_prnt = NULL;
+#endif
+ /* internal parameters: */
+
+ /*
+ counter is 0 for MacKey,
+ is 1 for LTK
+ */
+ uint8_t counter_mac_key[1] = {0};
+ uint8_t counter_ltk[1] = {1};
+ /*
+ keyID 62746c65
+ */
+ uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62};
+ /*
+ length 0100
+ */
+ uint8_t length[2] = {0x00, 0x01};
+
+ SMP_TRACE_DEBUG("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = w;
+ smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
+ p_prnt = n1;
+ smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
+ p_prnt = n2;
+ smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
+ p_prnt = a1;
+ smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
+ p_prnt = a2;
+ smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
+#endif
+
+ if (!smp_calculate_f5_key(w, t)) {
+ SMP_TRACE_ERROR("%s failed to calc T", __func__);
+ return false;
+ }
+#if (SMP_DEBUG == TRUE)
+ p_prnt = t;
+ smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
+#endif
+
+ if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_mac_key, key_id, n1,
+ n2, a1, a2, length, mac_key)) {
+ SMP_TRACE_ERROR("%s failed to calc MacKey", __func__);
+ return false;
+ }
+#if (SMP_DEBUG == TRUE)
+ p_prnt = mac_key;
+ smp_debug_print_nbyte_little_endian(p_prnt, "MacKey", BT_OCTET16_LEN);
+#endif
+
+ if (!smp_calculate_f5_mackey_or_long_term_key(t, counter_ltk, key_id, n1, n2,
+ a1, a2, length, ltk)) {
+ SMP_TRACE_ERROR("%s failed to calc LTK", __func__);
+ return false;
+ }
+#if (SMP_DEBUG == TRUE)
+ p_prnt = ltk;
+ smp_debug_print_nbyte_little_endian(p_prnt, "LTK", BT_OCTET16_LEN);
+#endif
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f5_mackey_or_long_term_key
+ *
+ * Description The function calculates the value of MacKey or LTK by the
+ * rules defined for f5 function.
+ * At the moment exactly the same formula is used to calculate
+ * LTK and MacKey.
+ * The difference is the value of input parameter Counter:
+ * - in MacKey calculations the value is 0;
+ * - in LTK calculations the value is 1.
+ * The formula:
+ * mac = AES-CMAC (Counter||keyID||N1||N2||A1||A2||Length)
+ * T
+ * where
+ * input: T is 256 bits;
+ * Counter is 8 bits, its value is 0 for MacKey,
+ * 1 for LTK;
+ * keyID is 32 bits, its value is 0x62746c65;
+ * N1 is 128 bits;
+ * N2 is 128 bits;
+ * A1 is 56 bits;
+ * A2 is 56 bits;
+ * Length is 16 bits, its value is 0x0100
+ * output: LTK is 128 bit.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+bool smp_calculate_f5_mackey_or_long_term_key(uint8_t* t, uint8_t* counter,
+ uint8_t* key_id, uint8_t* n1,
+ uint8_t* n2, uint8_t* a1,
+ uint8_t* a2, uint8_t* length,
+ uint8_t* mac) {
+ uint8_t* p = NULL;
+ uint8_t cmac[BT_OCTET16_LEN];
+ uint8_t key[BT_OCTET16_LEN];
+ uint8_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ +
+ BT_OCTET16_LEN /* N1 size */ +
+ BT_OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ +
+ 7 /* A2 size*/ + 2 /* Length size */;
+ uint8_t msg[1 + 4 + BT_OCTET16_LEN + BT_OCTET16_LEN + 7 + 7 + 2];
+ bool ret = true;
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = t;
+ smp_debug_print_nbyte_little_endian(p_prnt, "T", BT_OCTET16_LEN);
+ p_prnt = counter;
+ smp_debug_print_nbyte_little_endian(p_prnt, "Counter", 1);
+ p_prnt = key_id;
+ smp_debug_print_nbyte_little_endian(p_prnt, "KeyID", 4);
+ p_prnt = n1;
+ smp_debug_print_nbyte_little_endian(p_prnt, "N1", BT_OCTET16_LEN);
+ p_prnt = n2;
+ smp_debug_print_nbyte_little_endian(p_prnt, "N2", BT_OCTET16_LEN);
+ p_prnt = a1;
+ smp_debug_print_nbyte_little_endian(p_prnt, "A1", 7);
+ p_prnt = a2;
+ smp_debug_print_nbyte_little_endian(p_prnt, "A2", 7);
+ p_prnt = length;
+ smp_debug_print_nbyte_little_endian(p_prnt, "Length", 2);
+#endif
+
+ p = key;
+ ARRAY_TO_STREAM(p, t, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
+#endif
+ p = msg;
+ ARRAY_TO_STREAM(p, length, 2);
+ ARRAY_TO_STREAM(p, a2, 7);
+ ARRAY_TO_STREAM(p, a1, 7);
+ ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, key_id, 4);
+ ARRAY_TO_STREAM(p, counter, 1);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian(p_prnt, "M", msg_len);
+#endif
+
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ ret = false;
+ }
+
+#if (SMP_DEBUG == TRUE)
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = mac;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f5_key
+ *
+ * Description The function calculates key T used in calculation of
+ * MacKey and LTK (f5 output is defined as MacKey || LTK).
+ * T = AES-CMAC (W)
+ * salt
+ * where
+ * Internal: salt is 128 bit.
+ * input: W is 256 bit.
+ * Output: T is 128 bit.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+bool smp_calculate_f5_key(uint8_t* w, uint8_t* t) {
+ uint8_t* p = NULL;
+ /* Please see 2.2.7 LE Secure Connections Key Generation Function f5 */
+ /*
+ salt: 6C88 8391 AAF5 A538 6037 0BDB 5A60 83BE
+ */
+ BT_OCTET16 salt = {0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60,
+ 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_prnt = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = salt;
+ smp_debug_print_nbyte_little_endian(p_prnt, "salt", BT_OCTET16_LEN);
+ p_prnt = w;
+ smp_debug_print_nbyte_little_endian(p_prnt, "W", BT_OCTET32_LEN);
+#endif
+
+ BT_OCTET16 key;
+ BT_OCTET32 msg;
+
+ p = key;
+ ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
+ p = msg;
+ ARRAY_TO_STREAM(p, w, BT_OCTET32_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_prnt = key;
+ smp_debug_print_nbyte_little_endian(p_prnt, "K", BT_OCTET16_LEN);
+ p_prnt = msg;
+ smp_debug_print_nbyte_little_endian(p_prnt, "M", BT_OCTET32_LEN);
+#endif
+
+ BT_OCTET16 cmac;
+ bool ret = true;
+ if (!aes_cipher_msg_auth_code(key, msg, BT_OCTET32_LEN, BT_OCTET16_LEN,
+ cmac)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ ret = false;
+ }
+
+#if (SMP_DEBUG == TRUE)
+ p_prnt = cmac;
+ smp_debug_print_nbyte_little_endian(p_prnt, "AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = t;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_local_dhkey_check
+ *
+ * Description The function calculates and saves local device DHKey check
+ * value in CB.
+ * Before doing this it calls
+ * smp_calculate_f5_mackey_and_long_term_key(...).
+ * to calculate MacKey and LTK.
+ * MacKey is used in dhkey calculation.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_calculate_local_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t iocap[3], a[7], b[7];
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ smp_calculate_f5_mackey_and_long_term_key(p_cb);
+
+ smp_collect_local_io_capabilities(iocap, p_cb);
+
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ smp_calculate_f6(p_cb->mac_key, p_cb->rand, p_cb->rrand, p_cb->peer_random,
+ iocap, a, b, p_cb->dhkey_check);
+
+ SMP_TRACE_EVENT("local DHKey check calculation is completed");
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_peer_dhkey_check
+ *
+ * Description The function calculates peer device DHKey check value.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_calculate_peer_dhkey_check(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
+ uint8_t iocap[3], a[7], b[7];
+ BT_OCTET16 param_buf;
+ bool ret;
+ tSMP_KEY key;
+ tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ smp_collect_peer_io_capabilities(iocap, p_cb);
+
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ ret = smp_calculate_f6(p_cb->mac_key, p_cb->rrand, p_cb->rand,
+ p_cb->local_random, iocap, b, a, param_buf);
+
+ if (ret) {
+ SMP_TRACE_EVENT("peer DHKey check calculation is completed");
+#if (SMP_DEBUG == TRUE)
+ smp_debug_print_nbyte_little_endian(param_buf, "peer DHKey check",
+ BT_OCTET16_LEN);
+#endif
+ key.key_type = SMP_KEY_TYPE_PEER_DHK_CHCK;
+ key.p_data = param_buf;
+ smp_sm_event(p_cb, SMP_SC_KEY_READY_EVT, &key);
+ } else {
+ SMP_TRACE_EVENT("peer DHKey check calculation failed");
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &status);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f6
+ *
+ * Description The function calculates
+ * C = f6(W, N1, N2, R, IOcap, A1, A2) =
+ * AES-CMAC (N1||N2||R||IOcap||A1||A2)
+ * W
+ * where
+ * input: W is 128 bit,
+ * N1 is 128 bit,
+ * N2 is 128 bit,
+ * R is 128 bit,
+ * IOcap is 24 bit,
+ * A1 is 56 bit,
+ * A2 is 56 bit,
+ * output: C is 128 bit.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+bool smp_calculate_f6(uint8_t* w, uint8_t* n1, uint8_t* n2, uint8_t* r,
+ uint8_t* iocap, uint8_t* a1, uint8_t* a2, uint8_t* c) {
+ uint8_t* p = NULL;
+ uint8_t msg_len = BT_OCTET16_LEN /* N1 size */ +
+ BT_OCTET16_LEN /* N2 size */ + BT_OCTET16_LEN /* R size */ +
+ 3 /* IOcap size */ + 7 /* A1 size*/
+ + 7 /* A2 size*/;
+ uint8_t msg[BT_OCTET16_LEN + BT_OCTET16_LEN + BT_OCTET16_LEN + 3 + 7 + 7];
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_print = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+ p_print = w;
+ smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
+ p_print = n1;
+ smp_debug_print_nbyte_little_endian(p_print, "N1", BT_OCTET16_LEN);
+ p_print = n2;
+ smp_debug_print_nbyte_little_endian(p_print, "N2", BT_OCTET16_LEN);
+ p_print = r;
+ smp_debug_print_nbyte_little_endian(p_print, "R", BT_OCTET16_LEN);
+ p_print = iocap;
+ smp_debug_print_nbyte_little_endian(p_print, "IOcap", 3);
+ p_print = a1;
+ smp_debug_print_nbyte_little_endian(p_print, "A1", 7);
+ p_print = a2;
+ smp_debug_print_nbyte_little_endian(p_print, "A2", 7);
+#endif
+
+ uint8_t cmac[BT_OCTET16_LEN];
+ uint8_t key[BT_OCTET16_LEN];
+
+ p = key;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_print = key;
+ smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
+#endif
+
+ p = msg;
+ ARRAY_TO_STREAM(p, a2, 7);
+ ARRAY_TO_STREAM(p, a1, 7);
+ ARRAY_TO_STREAM(p, iocap, 3);
+ ARRAY_TO_STREAM(p, r, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n2, BT_OCTET16_LEN);
+ ARRAY_TO_STREAM(p, n1, BT_OCTET16_LEN);
+#if (SMP_DEBUG == TRUE)
+ p_print = msg;
+ smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
+#endif
+
+ bool ret = true;
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ ret = false;
+ }
+
+#if (SMP_DEBUG == TRUE)
+ p_print = cmac;
+ smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_link_key_from_long_term_key
+ *
+ * Description The function calculates and saves BR/EDR link key derived
+ * from LE SC LTK.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ ******************************************************************************/
+bool smp_calculate_link_key_from_long_term_key(tSMP_CB* p_cb) {
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ BD_ADDR bda_for_lk;
+ tBLE_ADDR_TYPE conn_addr_type;
+ BT_OCTET16 salt = {0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC) {
+ SMP_TRACE_DEBUG(
+ "Use rcvd identity address as BD_ADDR of LK rcvd identity address");
+ memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN);
+ } else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk,
+ &conn_addr_type)) &&
+ conn_addr_type == BLE_ADDR_PUBLIC) {
+ SMP_TRACE_DEBUG("Use rcvd connection address as BD_ADDR of LK");
+ } else {
+ SMP_TRACE_WARNING("Don't have peer public address to associate with LK");
+ return false;
+ }
+
+ p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+ if (p_dev_rec == NULL) {
+ SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
+ return false;
+ }
+
+ BT_OCTET16 intermediate_link_key;
+ bool ret = true;
+
+ if (p_cb->key_derivation_h7_used)
+ ret = smp_calculate_h7((uint8_t*)salt, p_cb->ltk, intermediate_link_key);
+ else
+ ret = smp_calculate_h6(p_cb->ltk, (uint8_t*)"1pmt" /* reversed "tmp1" */,
+ intermediate_link_key);
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed to derive intermediate_link_key", __func__);
+ return ret;
+ }
+
+ BT_OCTET16 link_key;
+ ret = smp_calculate_h6(intermediate_link_key,
+ (uint8_t*)"rbel" /* reversed "lebr" */, link_key);
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ } else {
+ uint8_t link_key_type;
+ if (btm_cb.security_mode == BTM_SEC_MODE_SC) {
+ /* Secure Connections Only Mode */
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ } else if (controller_get_interface()->supports_secure_connections()) {
+ /* both transports are SC capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256;
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB_P_256;
+ } else if (btm_cb.security_mode == BTM_SEC_MODE_SP) {
+ /* BR/EDR transport is SSP capable */
+ if (p_cb->sec_level == SMP_SEC_AUTHENTICATED)
+ link_key_type = BTM_LKEY_TYPE_AUTH_COMB;
+ else
+ link_key_type = BTM_LKEY_TYPE_UNAUTH_COMB;
+ } else {
+ SMP_TRACE_ERROR(
+ "%s failed to update link_key. Sec Mode = %d, sm4 = 0x%02x", __func__,
+ btm_cb.security_mode, p_dev_rec->sm4);
+ return false;
+ }
+
+ link_key_type += BTM_LTK_DERIVED_LKEY_OFFSET;
+
+ uint8_t* p;
+ BT_OCTET16 notif_link_key;
+ p = notif_link_key;
+ ARRAY16_TO_STREAM(p, link_key);
+
+ btm_sec_link_key_notification(bda_for_lk, notif_link_key, link_key_type);
+
+ SMP_TRACE_EVENT("%s is completed", __func__);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_long_term_key_from_link_key
+ *
+ * Description The function calculates and saves SC LTK derived from BR/EDR
+ * link key.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ ******************************************************************************/
+bool smp_calculate_long_term_key_from_link_key(tSMP_CB* p_cb) {
+ bool ret = true;
+ tBTM_SEC_DEV_REC* p_dev_rec;
+ uint8_t rev_link_key[16];
+ BT_OCTET16 salt = {0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ p_dev_rec = btm_find_dev(p_cb->pairing_bda);
+ if (p_dev_rec == NULL) {
+ SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
+ return false;
+ }
+
+ uint8_t br_link_key_type;
+ br_link_key_type = BTM_SecGetDeviceLinkKeyType(p_cb->pairing_bda);
+ if (br_link_key_type == BTM_LKEY_TYPE_IGNORE) {
+ SMP_TRACE_ERROR("%s failed to retrieve BR link type", __func__);
+ return false;
+ }
+
+ if ((br_link_key_type != BTM_LKEY_TYPE_AUTH_COMB_P_256) &&
+ (br_link_key_type != BTM_LKEY_TYPE_UNAUTH_COMB_P_256)) {
+ SMP_TRACE_ERROR("%s LE SC LTK can't be derived from LK %d", __func__,
+ br_link_key_type);
+ return false;
+ }
+
+ uint8_t* p1;
+ uint8_t* p2;
+ p1 = rev_link_key;
+ p2 = p_dev_rec->link_key;
+ REVERSE_ARRAY_TO_STREAM(p1, p2, 16);
+
+ BT_OCTET16 intermediate_long_term_key;
+ if (p_cb->key_derivation_h7_used) {
+ ret = smp_calculate_h7((uint8_t*)salt, rev_link_key,
+ intermediate_long_term_key);
+ } else {
+ /* "tmp2" obtained from the spec */
+ ret = smp_calculate_h6(rev_link_key, (uint8_t*)"2pmt" /* reversed "tmp2" */,
+ intermediate_long_term_key);
+ }
+
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed to derive intermediate_long_term_key", __func__);
+ return ret;
+ }
+
+ /* "brle" obtained from the spec */
+ ret = smp_calculate_h6(intermediate_long_term_key,
+ (uint8_t*)"elrb" /* reversed "brle" */, p_cb->ltk);
+
+ if (!ret) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ } else {
+ p_cb->sec_level = (br_link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256)
+ ? SMP_SEC_AUTHENTICATED
+ : SMP_SEC_UNAUTHENTICATE;
+ SMP_TRACE_EVENT("%s is completed", __func__);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_h6
+ *
+ * Description The function calculates
+ * C = h6(W, KeyID) = AES-CMAC (KeyID)
+ * W
+ * where
+ * input: W is 128 bit,
+ * KeyId is 32 bit,
+ * output: C is 128 bit.
+ *
+ * Returns false if out of resources, true in other cases.
+ *
+ * Note The LSB is the first octet, the MSB is the last octet of
+ * the AES-CMAC input/output stream.
+ *
+ ******************************************************************************/
+bool smp_calculate_h6(uint8_t* w, uint8_t* keyid, uint8_t* c) {
+#if (SMP_DEBUG == TRUE)
+ uint8_t* p_print = NULL;
+#endif
+
+ SMP_TRACE_DEBUG("%s", __func__);
+#if (SMP_DEBUG == TRUE)
+ p_print = w;
+ smp_debug_print_nbyte_little_endian(p_print, "W", BT_OCTET16_LEN);
+ p_print = keyid;
+ smp_debug_print_nbyte_little_endian(p_print, "keyID", 4);
+#endif
+
+ uint8_t* p = NULL;
+ uint8_t key[BT_OCTET16_LEN];
+
+ p = key;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+
+#if (SMP_DEBUG == TRUE)
+ p_print = key;
+ smp_debug_print_nbyte_little_endian(p_print, "K", BT_OCTET16_LEN);
+#endif
+
+ uint8_t msg_len = 4 /* KeyID size */;
+ uint8_t msg[4];
+
+ p = msg;
+ ARRAY_TO_STREAM(p, keyid, 4);
+
+#if (SMP_DEBUG == TRUE)
+ p_print = msg;
+ smp_debug_print_nbyte_little_endian(p_print, "M", msg_len);
+#endif
+
+ bool ret = true;
+ uint8_t cmac[BT_OCTET16_LEN];
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ ret = false;
+ }
+
+#if (SMP_DEBUG == TRUE)
+ p_print = cmac;
+ smp_debug_print_nbyte_little_endian(p_print, "AES-CMAC", BT_OCTET16_LEN);
+#endif
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function smp_calculate_h7
+**
+** Description The function calculates
+** C = h7(SALT, W) = AES-CMAC (W)
+** SALT
+** where
+** input: W is 128 bit,
+** SALT is 128 bit,
+** output: C is 128 bit.
+**
+** Returns FALSE if out of resources, TRUE in other cases.
+**
+** Note The LSB is the first octet, the MSB is the last octet of
+** the AES-CMAC input/output stream.
+**
+*******************************************************************************/
+bool smp_calculate_h7(uint8_t* salt, uint8_t* w, uint8_t* c) {
+ SMP_TRACE_DEBUG("%s", __FUNCTION__);
+
+ uint8_t key[BT_OCTET16_LEN];
+ uint8_t* p = key;
+ ARRAY_TO_STREAM(p, salt, BT_OCTET16_LEN);
+
+ uint8_t msg_len = BT_OCTET16_LEN /* msg size */;
+ uint8_t msg[BT_OCTET16_LEN];
+ p = msg;
+ ARRAY_TO_STREAM(p, w, BT_OCTET16_LEN);
+
+ bool ret = true;
+ uint8_t cmac[BT_OCTET16_LEN];
+ if (!aes_cipher_msg_auth_code(key, msg, msg_len, BT_OCTET16_LEN, cmac)) {
+ SMP_TRACE_ERROR("%s failed", __FUNCTION__);
+ ret = false;
+ }
+
+ p = c;
+ ARRAY_TO_STREAM(p, cmac, BT_OCTET16_LEN);
+ return ret;
+}
+
+/**
+ * This function generates nonce.
+ */
+void smp_start_nonce_generation(tSMP_CB* p_cb) {
+ SMP_TRACE_DEBUG("%s", __func__);
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)p_cb->rand, rand, BT_OCTET8_LEN);
+ btsnd_hcic_ble_rand(Bind(
+ [](tSMP_CB* p_cb, BT_OCTET8 rand) {
+ memcpy((void*)&p_cb->rand[8], rand, BT_OCTET8_LEN);
+ SMP_TRACE_DEBUG("%s round %d", __func__, p_cb->round);
+ /* notifies SM that it has new nonce. */
+ smp_sm_event(p_cb, SMP_HAVE_LOC_NONCE_EVT, NULL);
+ },
+ p_cb));
+ },
+ p_cb));
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_l2c.cc b/mtkbt/code/bt/stack/smp/smp_l2c.cc
new file mode 100755
index 0000000..98ac52d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_l2c.cc
@@ -0,0 +1,321 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the SMP L2Cap interface
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "btm_ble_api.h"
+#include "l2c_api.h"
+
+#include "smp_int.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt);
+
+static void smp_connect_callback(uint16_t channel, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport);
+static void smp_data_received(uint16_t channel, BD_ADDR bd_addr, BT_HDR* p_buf);
+
+static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport);
+static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr,
+ BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function smp_l2cap_if_init
+ *
+ * Description This function is called during the SMP task startup
+ * to register interface functions with L2CAP.
+ *
+ ******************************************************************************/
+void smp_l2cap_if_init(void) {
+ tL2CAP_FIXED_CHNL_REG fixed_reg;
+ SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
+ fixed_reg.fixed_chnl_opts.mode = L2CAP_FCR_BASIC_MODE;
+ fixed_reg.fixed_chnl_opts.max_transmit = 0;
+ fixed_reg.fixed_chnl_opts.rtrans_tout = 0;
+ fixed_reg.fixed_chnl_opts.mon_tout = 0;
+ fixed_reg.fixed_chnl_opts.mps = 0;
+ fixed_reg.fixed_chnl_opts.tx_win_sz = 0;
+
+ fixed_reg.pL2CA_FixedConn_Cb = smp_connect_callback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_data_received;
+ fixed_reg.pL2CA_FixedTxComplete_Cb = smp_tx_complete_callback;
+
+ fixed_reg.pL2CA_FixedCong_Cb =
+ NULL; /* do not handle congestion on this channel */
+ fixed_reg.default_idle_tout =
+ 60; /* set 60 seconds timeout, 0xffff default idle timeout */
+
+ L2CA_RegisterFixedChannel(L2CAP_SMP_CID, &fixed_reg);
+
+ fixed_reg.pL2CA_FixedConn_Cb = smp_br_connect_callback;
+ fixed_reg.pL2CA_FixedData_Cb = smp_br_data_received;
+
+ L2CA_RegisterFixedChannel(L2CAP_SMP_BR_CID, &fixed_reg);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_connect_callback
+ *
+ * Description This callback function is called by L2CAP to indicate that
+ * SMP channel is
+ * connected (conn = true)/disconnected (conn = false).
+ *
+ ******************************************************************************/
+static void smp_connect_callback(uint16_t channel, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport) {
+ tSMP_CB* p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+ BD_ADDR dummy_bda = {0};
+
+ SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
+
+ if (transport == BT_TRANSPORT_BR_EDR ||
+ memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0)
+ return;
+
+ if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ SMP_TRACE_EVENT("%s() for pairing BDA: %08x%04x Event: %s", __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) +
+ (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5],
+ (connected) ? "connected" : "disconnected");
+
+ if (connected) {
+ if (!p_cb->connect_initialized) {
+ p_cb->connect_initialized = true;
+ /* initiating connection established */
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+
+ /* initialize local i/r key to be default keys */
+ p_cb->local_r_key = p_cb->local_i_key = SMP_SEC_DEFAULT_KEY;
+ p_cb->loc_auth_req = p_cb->peer_auth_req = SMP_DEFAULT_AUTH_REQ;
+ p_cb->cb_evt = SMP_IO_CAP_REQ_EVT;
+ smp_sm_event(p_cb, SMP_L2CAP_CONN_EVT, NULL);
+ }
+ } else {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_sm_event(p_cb, SMP_L2CAP_DISCONN_EVT, &int_data);
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_data_received
+ *
+ * Description This function is called when data is received from L2CAP on
+ * SMP channel.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void smp_data_received(uint16_t channel, BD_ADDR bd_addr,
+ BT_HDR* p_buf) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint8_t cmd;
+ SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
+
+ STREAM_TO_UINT8(cmd, p);
+
+ /* sanity check */
+ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
+ SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* reject the pairing request if there is an on-going SMP pairing */
+ if (SMP_OPCODE_PAIRING_REQ == cmd || SMP_OPCODE_SEC_REQ == cmd) {
+ if ((p_cb->state == SMP_STATE_IDLE) &&
+ (p_cb->br_state == SMP_BR_STATE_IDLE) &&
+ !(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD)) {
+ p_cb->role = L2CA_GetBleConnRole(bd_addr);
+ memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+ } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
+ osi_free(p_buf);
+ smp_reject_unexpected_pairing_command(bd_addr);
+ return;
+ }
+ /* else, out of state pairing request/security request received, passed into
+ * SM */
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ alarm_set_on_queue(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
+ smp_rsp_timeout, NULL, btu_general_alarm_queue);
+
+ if (cmd == SMP_OPCODE_CONFIRM) {
+ SMP_TRACE_DEBUG(
+ "in %s cmd = 0x%02x, peer_auth_req = 0x%02x,"
+ "loc_auth_req = 0x%02x",
+ __func__, cmd, p_cb->peer_auth_req, p_cb->loc_auth_req);
+
+ if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
+ (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
+ cmd = SMP_OPCODE_PAIR_COMMITM;
+ }
+ }
+
+ p_cb->rcvd_cmd_code = cmd;
+ p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
+ smp_sm_event(p_cb, cmd, p);
+ }
+
+ osi_free(p_buf);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_tx_complete_callback
+ *
+ * Description SMP channel tx complete callback
+ *
+ ******************************************************************************/
+static void smp_tx_complete_callback(uint16_t cid, uint16_t num_pkt) {
+ tSMP_CB* p_cb = &smp_cb;
+
+ if (p_cb->total_tx_unacked >= num_pkt)
+ p_cb->total_tx_unacked -= num_pkt;
+ else
+ SMP_TRACE_ERROR("Unexpected %s: num_pkt = %d", __func__, num_pkt);
+
+ uint8_t reason = SMP_SUCCESS;
+ if (p_cb->total_tx_unacked == 0 && p_cb->wait_for_authorization_complete) {
+ if (cid == L2CAP_SMP_CID)
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+ else
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_br_connect_callback
+ *
+ * Description This callback function is called by L2CAP to indicate that
+ * SMP BR channel is
+ * connected (conn = true)/disconnected (conn = false).
+ *
+ ******************************************************************************/
+static void smp_br_connect_callback(uint16_t channel, BD_ADDR bd_addr,
+ bool connected, uint16_t reason,
+ tBT_TRANSPORT transport) {
+ tSMP_CB* p_cb = &smp_cb;
+ tSMP_INT_DATA int_data;
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ if (transport != BT_TRANSPORT_BR_EDR) {
+ SMP_TRACE_WARNING("%s is called on unexpected transport %d", __func__,
+ transport);
+ return;
+ }
+
+ if (!(memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0)) return;
+
+ SMP_TRACE_EVENT(
+ "%s for pairing BDA: %08x%04x Event: %s", __func__,
+ (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+ (bd_addr[4] << 8) + bd_addr[5],
+ (connected) ? "connected" : "disconnected");
+
+ if (connected) {
+ if (!p_cb->connect_initialized) {
+ p_cb->connect_initialized = true;
+ /* initialize local i/r key to be default keys */
+ p_cb->local_r_key = p_cb->local_i_key = SMP_BR_SEC_DEFAULT_KEY;
+ p_cb->loc_auth_req = p_cb->peer_auth_req = 0;
+ p_cb->cb_evt = SMP_BR_KEYS_REQ_EVT;
+ smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_CONN_EVT, NULL);
+ }
+ } else {
+ int_data.reason = reason;
+ /* Disconnected while doing security */
+ smp_br_state_machine_event(p_cb, SMP_BR_L2CAP_DISCONN_EVT, &int_data);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_br_data_received
+ *
+ * Description This function is called when data is received from L2CAP on
+ * SMP BR channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void smp_br_data_received(uint16_t channel, BD_ADDR bd_addr,
+ BT_HDR* p_buf) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+ uint8_t cmd;
+ SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
+
+ STREAM_TO_UINT8(cmd, p);
+
+ /* sanity check */
+ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) {
+ SMP_TRACE_WARNING("Ignore received command with RESERVED code 0x%02x", cmd);
+ osi_free(p_buf);
+ return;
+ }
+
+ /* reject the pairing request if there is an on-going SMP pairing */
+ if (SMP_OPCODE_PAIRING_REQ == cmd) {
+ if ((p_cb->state == SMP_STATE_IDLE) &&
+ (p_cb->br_state == SMP_BR_STATE_IDLE)) {
+ p_cb->role = HCI_ROLE_SLAVE;
+ p_cb->smp_over_br = true;
+ memcpy(&p_cb->pairing_bda[0], bd_addr, BD_ADDR_LEN);
+ } else if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN)) {
+ osi_free(p_buf);
+ smp_reject_unexpected_pairing_command(bd_addr);
+ return;
+ }
+ /* else, out of state pairing request received, passed into State Machine */
+ }
+
+ if (memcmp(&bd_addr[0], p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
+ alarm_set_on_queue(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
+ smp_rsp_timeout, NULL, btu_general_alarm_queue);
+
+ p_cb->rcvd_cmd_code = cmd;
+ p_cb->rcvd_cmd_len = (uint8_t)p_buf->len;
+ smp_br_state_machine_event(p_cb, cmd, p);
+ }
+
+ osi_free(p_buf);
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_main.cc b/mtkbt/code/bt/stack/smp/smp_main.cc
new file mode 100755
index 0000000..829a5d4
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_main.cc
@@ -0,0 +1,1032 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+
+#include <string.h>
+#include "smp_int.h"
+
+const char* const smp_state_name[] = {
+ "SMP_STATE_IDLE",
+ "SMP_STATE_WAIT_APP_RSP",
+ "SMP_STATE_SEC_REQ_PENDING",
+ "SMP_STATE_PAIR_REQ_RSP",
+ "SMP_STATE_WAIT_CONFIRM",
+ "SMP_STATE_CONFIRM",
+ "SMP_STATE_RAND",
+ "SMP_STATE_PUBLIC_KEY_EXCH",
+ "SMP_STATE_SEC_CONN_PHS1_START",
+ "SMP_STATE_WAIT_COMMITMENT",
+ "SMP_STATE_WAIT_NONCE",
+ "SMP_STATE_SEC_CONN_PHS2_START",
+ "SMP_STATE_WAIT_DHK_CHECK",
+ "SMP_STATE_DHK_CHECK",
+ "SMP_STATE_ENCRYPTION_PENDING",
+ "SMP_STATE_BOND_PENDING",
+ "SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA",
+ "SMP_STATE_MAX"};
+
+const char* const smp_event_name[] = {"PAIRING_REQ_EVT",
+ "PAIRING_RSP_EVT",
+ "CONFIRM_EVT",
+ "RAND_EVT",
+ "PAIRING_FAILED_EVT",
+ "ENC_INFO_EVT",
+ "MASTER_ID_EVT",
+ "ID_INFO_EVT",
+ "ID_ADDR_EVT",
+ "SIGN_INFO_EVT",
+ "SECURITY_REQ_EVT",
+ "PAIR_PUBLIC_KEY_EVT",
+ "PAIR_DHKEY_CHECK_EVT",
+ "PAIR_KEYPRESS_NOTIFICATION_EVT",
+ "PAIR_COMMITMENT_EVT",
+ "KEY_READY_EVT",
+ "ENCRYPTED_EVT",
+ "L2CAP_CONN_EVT",
+ "L2CAP_DISCONN_EVT",
+ "API_IO_RSP_EVT",
+ "API_SEC_GRANT_EVT",
+ "TK_REQ_EVT",
+ "AUTH_CMPL_EVT",
+ "ENC_REQ_EVT",
+ "BOND_REQ_EVT",
+ "DISCARD_SEC_REQ_EVT",
+ "PUBLIC_KEY_EXCHANGE_REQ_EVT",
+ "LOCAL_PUBLIC_KEY_CRTD_EVT",
+ "BOTH_PUBLIC_KEYS_RCVD_EVT",
+ "SEC_CONN_DHKEY_COMPLETE_EVT",
+ "HAVE_LOCAL_NONCE_EVT",
+ "SEC_CONN_PHASE1_CMPLT_EVT",
+ "SEC_CONN_CALC_NC_EVT",
+ "SEC_CONN_DISPLAY_NC_EVT",
+ "SEC_CONN_OK_EVT",
+ "SEC_CONN_2_DHCK_CHECKS_PRESENT_EVT",
+ "SEC_CONN_KEY_READY_EVT",
+ "KEYPRESS_NOTIFICATION_EVT",
+ "SEC_CONN_OOB_DATA_EVT",
+ "CREATE_LOCAL_SEC_CONN_OOB_DATA_EVT",
+ "OUT_OF_RANGE_EVT"};
+
+const char* smp_get_event_name(tSMP_EVENT event);
+const char* smp_get_state_name(tSMP_STATE state);
+
+#define SMP_SM_IGNORE 0
+#define SMP_NUM_ACTIONS 2
+#define SMP_SME_NEXT_STATE 2
+#define SMP_SM_NUM_COLS 3
+
+typedef const uint8_t (*tSMP_SM_TBL)[SMP_SM_NUM_COLS];
+
+enum {
+ SMP_PROC_SEC_REQ,
+ SMP_SEND_PAIR_REQ,
+ SMP_SEND_PAIR_RSP,
+ SMP_SEND_CONFIRM,
+ SMP_SEND_PAIR_FAIL,
+ SMP_SEND_RAND,
+ SMP_SEND_ENC_INFO,
+ SMP_SEND_ID_INFO,
+ SMP_SEND_LTK_REPLY,
+ SMP_PROC_PAIR_CMD,
+ SMP_PROC_PAIR_FAIL,
+ SMP_PROC_CONFIRM,
+ SMP_PROC_RAND,
+ SMP_PROC_ENC_INFO,
+ SMP_PROC_MASTER_ID,
+ SMP_PROC_ID_INFO,
+ SMP_PROC_ID_ADDR,
+ SMP_PROC_SRK_INFO,
+ SMP_PROC_SEC_GRANT,
+ SMP_PROC_SL_KEY,
+ SMP_PROC_COMPARE,
+ SMP_PROC_IO_RSP,
+ SMP_GENERATE_COMPARE,
+ SMP_GENERATE_CONFIRM,
+ SMP_GENERATE_STK,
+ SMP_KEY_DISTRIBUTE,
+ SMP_START_ENC,
+ SMP_PAIRING_CMPL,
+ SMP_DECIDE_ASSO_MODEL,
+ SMP_SEND_APP_CBACK,
+ SMP_CHECK_AUTH_REQ,
+ SMP_PAIR_TERMINATE,
+ SMP_ENC_CMPL,
+ SMP_PROC_DISCARD,
+ SMP_CREATE_PRIVATE_KEY,
+ SMP_USE_OOB_PRIVATE_KEY,
+ SMP_SEND_PAIR_PUBLIC_KEY,
+ SMP_PROCESS_PAIR_PUBLIC_KEY,
+ SMP_HAVE_BOTH_PUBLIC_KEYS,
+ SMP_START_SEC_CONN_PHASE1,
+ SMP_PROCESS_LOCAL_NONCE,
+ SMP_SEND_COMMITMENT,
+ SMP_PROCESS_PAIRING_COMMITMENT,
+ SMP_PROCESS_PEER_NONCE,
+ SMP_CALCULATE_LOCAL_DHKEY_CHECK,
+ SMP_SEND_DHKEY_CHECK,
+ SMP_PROCESS_DHKEY_CHECK,
+ SMP_CALCULATE_PEER_DHKEY_CHECK,
+ SMP_MATCH_DHKEY_CHECKS,
+ SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER,
+ SMP_MOVE_TO_SEC_CONN_PHASE2,
+ SMP_PH2_DHKEY_CHECKS_ARE_PRESENT,
+ SMP_WAIT_FOR_BOTH_PUBLIC_KEYS,
+ SMP_START_PASSKEY_VERIFICATION,
+ SMP_SEND_KEYPRESS_NOTIFICATION,
+ SMP_PROCESS_KEYPRESS_NOTIFICATION,
+ SMP_PROCESS_SECURE_CONNECTION_OOB_DATA,
+ SMP_SET_LOCAL_OOB_KEYS,
+ SMP_SET_LOCAL_OOB_RAND_COMMITMENT,
+ SMP_IDLE_TERMINATE,
+ SMP_FAST_CONN_PARAM,
+ SMP_SM_NO_ACTION
+};
+
+static const tSMP_ACT smp_sm_action[] = {
+ smp_proc_sec_req,
+ smp_send_pair_req,
+ smp_send_pair_rsp,
+ smp_send_confirm,
+ smp_send_pair_fail,
+ smp_send_rand,
+ smp_send_enc_info,
+ smp_send_id_info,
+ smp_send_ltk_reply,
+ smp_proc_pair_cmd,
+ smp_proc_pair_fail,
+ smp_proc_confirm,
+ smp_proc_rand,
+ smp_proc_enc_info,
+ smp_proc_master_id,
+ smp_proc_id_info,
+ smp_proc_id_addr,
+ smp_proc_srk_info,
+ smp_proc_sec_grant,
+ smp_proc_sl_key,
+ smp_proc_compare,
+ smp_process_io_response,
+ smp_generate_compare,
+ smp_generate_srand_mrand_confirm,
+ smp_generate_stk,
+ smp_key_distribution,
+ smp_start_enc,
+ smp_pairing_cmpl,
+ smp_decide_association_model,
+ smp_send_app_cback,
+ smp_check_auth_req,
+ smp_pair_terminate,
+ smp_enc_cmpl,
+ smp_proc_discard,
+ smp_create_private_key,
+ smp_use_oob_private_key,
+ smp_send_pair_public_key,
+ smp_process_pairing_public_key,
+ smp_both_have_public_keys,
+ smp_start_secure_connection_phase1,
+ smp_process_local_nonce,
+ smp_send_commitment,
+ smp_process_pairing_commitment,
+ smp_process_peer_nonce,
+ smp_calculate_local_dhkey_check,
+ smp_send_dhkey_check,
+ smp_process_dhkey_check,
+ smp_calculate_peer_dhkey_check,
+ smp_match_dhkey_checks,
+ smp_calculate_numeric_comparison_display_number,
+ smp_move_to_secure_connections_phase2,
+ smp_phase_2_dhkey_checks_are_present,
+ smp_wait_for_both_public_keys,
+ smp_start_passkey_verification,
+ smp_send_keypress_notification,
+ smp_process_keypress_notification,
+ smp_process_secure_connection_oob_data,
+ smp_set_local_oob_keys,
+ smp_set_local_oob_random_commitment,
+ smp_idle_terminate,
+ smp_fast_conn_param};
+
+/************ SMP Master FSM State/Event Indirection Table **************/
+static const uint8_t smp_master_entry_map[][SMP_STATE_MAX] = {
+ /* state name: */
+ /* Idle, WaitApp Rsp, SecReq Pend, Pair ReqRsp, Wait Cfm, Confirm, Rand,
+ PublKey Exch, SCPhs1 Strt, Wait Cmtm, Wait Nonce, SCPhs2 Strt, Wait
+ DHKChk, DHKChk, Enc Pend, Bond Pend, CrLocSc OobData */
+ /* PAIR_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_RSP */
+ {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* CONFIRM */
+ {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* RAND */
+ {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+ /* PAIR_FAIL */
+ {0, 0x81, 0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0, 0x81, 0},
+ /* ENC_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
+ /* MASTER_ID */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0},
+ /* ID_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
+ /* ID_ADDR */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0},
+ /* SIGN_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0},
+ /* SEC_REQ */
+ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_PUBLIC_KEY */
+ {0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_DHKEY_CHCK */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
+ /* PAIR_KEYPR_NOTIF */
+ {0, 8, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_COMMITM */
+ {0, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0},
+ /* KEY_READY */
+ {0, 3, 0, 3, 1, 0, 2, 0, 4, 0, 0, 0, 0, 0, 1, 6, 0},
+ /* ENC_CMPL */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0},
+ /* L2C_CONN */
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* L2C_DISC */
+ {3, 0x83, 0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0},
+ /* IO_RSP */
+ {0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SEC_GRANT */
+ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* TK_REQ */
+ {0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* AUTH_CMPL */
+ {4, 0x82, 0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0},
+ /* ENC_REQ */
+ {0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0},
+ /* BOND_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0},
+ /* DISCARD_SEC_REQ */
+ {0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0},
+ /* PUBL_KEY_EXCH_REQ */
+ {0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* LOC_PUBL_KEY_CRTD */
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ /* BOTH_PUBL_KEYS_RCVD */
+ {0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_DHKEY_CMPLT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* HAVE_LOC_NONCE */
+ {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2},
+ /* SC_PHASE1_CMPLT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
+ /* SC_CALC_NC */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
+ /* SC_DSPL_NC */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0},
+ /* SC_NC_OK */
+ {0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_2_DHCK_CHKS_PRES */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_KEY_READY */
+ {0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ /* KEYPR_NOTIF */
+ {0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_OOB_DATA */
+ {0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* CR_LOC_SC_OOB_DATA */
+ {5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static const uint8_t smp_all_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_FAIL */
+ {SMP_PROC_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+ /* AUTH_CMPL */
+ {SMP_SEND_PAIR_FAIL, SMP_PAIRING_CMPL, SMP_STATE_IDLE},
+ /* L2C_DISC */
+ {SMP_PAIR_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE}};
+
+static const uint8_t smp_master_idle_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* L2C_CONN */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SEC_REQ */
+ {SMP_PROC_SEC_REQ, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* L2C_DISC */
+ {SMP_IDLE_TERMINATE, SMP_SM_NO_ACTION, SMP_STATE_IDLE},
+ /* AUTH_CMPL */
+ {SMP_PAIRING_CMPL, SMP_SM_NO_ACTION, SMP_STATE_IDLE},
+ /* CR_LOC_SC_OOB_DATA */
+ {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}
+
+};
+
+static const uint8_t smp_master_wait_for_app_response_table[][SMP_SM_NUM_COLS] =
+ {
+ /* Event Action Next State */
+ /* SEC_GRANT */
+ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* IO_RSP */
+ {SMP_SEND_PAIR_REQ, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+
+ /* TK ready */
+ /* KEY_READY */
+ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM},
+
+ /* start enc mode setup */
+ /* ENC_REQ */
+ {SMP_START_ENC, SMP_FAST_CONN_PARAM, SMP_STATE_ENCRYPTION_PENDING},
+ /* DISCARD_SEC_REQ */
+ {SMP_PROC_DISCARD, SMP_SM_NO_ACTION, SMP_STATE_IDLE}
+ /* user confirms NC 'OK', i.e. phase 1 is completed */
+ /* SC_NC_OK */,
+ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS2_START},
+ /* user-provided passkey is rcvd */
+ /* SC_KEY_READY */
+ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_WAIT_APP_RSP},
+ /* KEYPR_NOTIF */
+ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_WAIT_APP_RSP},
+ /* SC_OOB_DATA */
+ {SMP_USE_OOB_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}};
+
+static const uint8_t smp_master_pair_request_response_table[][SMP_SM_NUM_COLS] =
+ {
+ /* Event Action Next State */
+ /* PAIR_RSP */
+ {SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+ /* TK_REQ */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+
+ /* TK ready */
+ /* KEY_READY */
+ {SMP_GENERATE_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}
+ /* PUBL_KEY_EXCH_REQ */,
+ {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH}};
+
+static const uint8_t smp_master_wait_for_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* KEY_READY*/
+ /* CONFIRM ready */
+ {SMP_SEND_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}};
+
+static const uint8_t smp_master_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* CONFIRM */
+ {SMP_PROC_CONFIRM, SMP_SEND_RAND, SMP_STATE_RAND}};
+
+static const uint8_t smp_master_rand_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* RAND */
+ {SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND},
+ /* KEY_READY */
+ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* Compare ready */
+ /* ENC_REQ */
+ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}};
+
+static const uint8_t smp_master_public_key_exchange_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */
+ {SMP_SEND_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */
+ {SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* BOTH_PUBL_KEYS_RCVD */
+ {SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_master_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_DHKEY_CMPLT */
+ {SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* HAVE_LOC_NONCE */
+ {SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+ /* TK_REQ */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,*/
+ /* It's time to start commitment calculation */
+ /* KEY_READY */
+ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_COMMITM */
+ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_master_wait_commitment_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_COMMITM */
+ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_RAND, SMP_STATE_WAIT_NONCE},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const uint8_t smp_master_wait_nonce_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* peer nonce is received */
+ /* RAND */
+ {SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+ /* NC model, time to calculate number for NC */
+ /* SC_CALC_NC */
+ {SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION,
+ SMP_STATE_WAIT_NONCE},
+ /* NC model, time to display calculated number for NC to the user */
+ /* SC_DSPL_NC */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const uint8_t smp_master_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_PHASE1_CMPLT */
+ {SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_SEND_DHKEY_CHECK,
+ SMP_STATE_WAIT_DHK_CHECK},
+};
+
+static const uint8_t smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_DHKEY_CHCK */
+ {SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK,
+ SMP_STATE_DHK_CHECK},
+};
+
+static const uint8_t smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* locally calculated peer dhkey check is ready -> compare it withs DHKey
+ * Check
+ * actually received from peer */
+ /* SC_KEY_READY */
+ {SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+ /* locally calculated peer dhkey check is ready -> calculate STK, go to
+ * sending
+ */
+ /* HCI LE Start Encryption command */
+ /* ENC_REQ */
+ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const uint8_t smp_master_enc_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* STK ready */
+ /* KEY_READY */
+ {SMP_START_ENC, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* ENCRYPTED */
+ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* BOND_REQ */
+ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}};
+static const uint8_t smp_master_bond_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* ENC_INFO */
+ {SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_INFO */
+ {SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* SIGN_INFO */
+ {SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* MASTER_ID */
+ {SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_ADDR */
+ {SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* KEY_READY */
+ /* LTK ready */
+ {SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}};
+
+static const uint8_t
+ smp_master_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */
+ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+ /* HAVE_LOC_NONCE */
+ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}};
+
+/************ SMP Slave FSM State/Event Indirection Table **************/
+static const uint8_t smp_slave_entry_map[][SMP_STATE_MAX] = {
+ /* state name: */
+ /* Idle, WaitApp Rsp, SecReq Pend, Pair ReqRsp, Wait Cfm, Confirm, Rand,
+ PublKey Exch, SCPhs1 Strt, Wait Cmtm, Wait Nonce, SCPhs2 Strt, Wait
+ DHKChk, DHKChk, Enc Pend, Bond Pend, CrLocSc OobData */
+ /* PAIR_REQ */
+ {2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_RSP */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* CONFIRM */
+ {0, 4, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* RAND */
+ {0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+ /* PAIR_FAIL */
+ {0, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0, 0},
+ /* ENC_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0},
+ /* MASTER_ID */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0},
+ /* ID_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0},
+ /* ID_ADDR */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0},
+ /* SIGN_INFO */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0},
+ /* SEC_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_PUBLIC_KEY */
+ {0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_DHKEY_CHCK */
+ {0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0},
+ /* PAIR_KEYPR_NOTIF */
+ {0, 9, 0, 0, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0},
+ /* PAIR_COMMITM */
+ {0, 8, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 0, 0},
+ /* KEY_READY */
+ {0, 3, 0, 3, 2, 2, 1, 0, 4, 0, 0, 0, 0, 0, 2, 1, 0},
+ /* ENC_CMPL */
+ {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0},
+ /* L2C_CONN */
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* L2C_DISC */
+ {0, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0},
+ /* IO_RSP */
+ {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SEC_GRANT */
+ {0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* TK_REQ */
+ {0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* AUTH_CMPL */
+ {0, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0},
+ /* ENC_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
+ /* BOND_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0},
+ /* DISCARD_SEC_REQ */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* PUBL_KEY_EXCH_REQ */
+ {0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* LOC_PUBL_KEY_CRTD */
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+ /* BOTH_PUBL_KEYS_RCVD */
+ {0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_DHKEY_CMPLT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* HAVE_LOC_NONCE */
+ {0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2},
+ /* SC_PHASE1_CMPLT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
+ /* SC_CALC_NC */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
+ /* SC_DSPL_NC */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0},
+ /* SC_NC_OK */
+ {0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_2_DHCK_CHKS_PRES */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0},
+ /* SC_KEY_READY */
+ {0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ /* KEYPR_NOTIF */
+ {0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* SC_OOB_DATA */
+ {0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ /* CR_LOC_SC_OOB_DATA */
+ {3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static const uint8_t smp_slave_idle_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* L2C_CONN */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* PAIR_REQ */
+ {SMP_PROC_PAIR_CMD, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+ /* CR_LOC_SC_OOB_DATA */
+ {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA}};
+
+static const uint8_t smp_slave_wait_for_app_response_table[][SMP_SM_NUM_COLS] =
+ {
+ /* Event Action Next State */
+ /* IO_RSP */
+ {SMP_PROC_IO_RSP, SMP_FAST_CONN_PARAM, SMP_STATE_PAIR_REQ_RSP},
+ /* SEC_GRANT */
+ {SMP_PROC_SEC_GRANT, SMP_SEND_APP_CBACK, SMP_STATE_WAIT_APP_RSP},
+
+ /* TK ready */
+ /* KEY_READY */
+ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* CONFIRM */
+ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM},
+ /* DHKey Check from master is received before phase 1 is completed -
+ race */
+ /* PAIR_DHKEY_CHCK */
+ {SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* user confirms NC 'OK', i.e. phase 1 is completed */
+ /* SC_NC_OK */
+ {SMP_MOVE_TO_SEC_CONN_PHASE2, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS2_START},
+ /* user-provided passkey is rcvd */
+ /* SC_KEY_READY */
+ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_COMMITM */
+ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION,
+ SMP_STATE_WAIT_APP_RSP},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_WAIT_APP_RSP},
+ /* KEYPR_NOTIF */
+ {SMP_SEND_KEYPRESS_NOTIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_WAIT_APP_RSP},
+ /* SC_OOB_DATA */
+ {SMP_SEND_PAIR_RSP, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_sec_request_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_REQ */
+ {SMP_PROC_PAIR_CMD, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+ /* ENCRYPTED*/
+ {SMP_ENC_CMPL, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_pair_request_response_table[][SMP_SM_NUM_COLS] =
+ {
+ /* Event Action Next State */
+ /* CONFIRM */
+ {SMP_PROC_CONFIRM, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM},
+ /* TK_REQ */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+
+ /* TK/Confirm ready */
+ /* KEY_READY */
+ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+ /* PUBL_KEY_EXCH_REQ */
+ {SMP_CREATE_PRIVATE_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */
+ {SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PAIR_REQ_RSP},
+};
+
+static const uint8_t smp_slave_wait_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* CONFIRM */
+ {SMP_PROC_CONFIRM, SMP_SEND_CONFIRM, SMP_STATE_CONFIRM},
+ /* KEY_READY*/
+ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_WAIT_CONFIRM}};
+
+static const uint8_t smp_slave_confirm_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* RAND */
+ {SMP_PROC_RAND, SMP_GENERATE_COMPARE, SMP_STATE_RAND},
+
+ /* TK/Confirm ready */
+ /* KEY_READY*/
+ {SMP_PROC_SL_KEY, SMP_SM_NO_ACTION, SMP_STATE_CONFIRM}};
+
+static const uint8_t smp_slave_rand_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* KEY_READY */
+ {SMP_PROC_COMPARE, SMP_SM_NO_ACTION, SMP_STATE_RAND}, /* compare match */
+ /* RAND */
+ {SMP_SEND_RAND, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING}};
+
+static const uint8_t smp_slave_public_key_exch_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */
+ {SMP_WAIT_FOR_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION,
+ SMP_STATE_PUBLIC_KEY_EXCH},
+ /* PAIR_PUBLIC_KEY */
+ {SMP_PROCESS_PAIR_PUBLIC_KEY, SMP_SM_NO_ACTION, SMP_STATE_PUBLIC_KEY_EXCH},
+ /* BOTH_PUBL_KEYS_RCVD */
+ {SMP_HAVE_BOTH_PUBLIC_KEYS, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_slave_sec_conn_phs1_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_DHKEY_CMPLT */
+ {SMP_START_SEC_CONN_PHASE1, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* HAVE_LOC_NONCE */
+ {SMP_PROCESS_LOCAL_NONCE, SMP_SM_NO_ACTION, SMP_STATE_WAIT_COMMITMENT},
+ /* TK_REQ */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+ /* SMP_MODEL_SEC_CONN_PASSKEY_DISP model, passkey is sent up to display,
+ * it's
+ * time to start */
+ /* commitment calculation */
+ /* KEY_READY */
+ {SMP_START_PASSKEY_VERIFICATION, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_SEC_CONN_PHS1_START},
+ /*COMMIT*/
+ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SM_NO_ACTION,
+ SMP_STATE_SEC_CONN_PHS1_START},
+};
+
+static const uint8_t smp_slave_wait_commitment_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_COMMITM */
+ {SMP_PROCESS_PAIRING_COMMITMENT, SMP_SEND_COMMITMENT, SMP_STATE_WAIT_NONCE},
+ /* PAIR_KEYPR_NOTIF */
+ {SMP_PROCESS_KEYPRESS_NOTIFICATION, SMP_SEND_APP_CBACK,
+ SMP_STATE_WAIT_COMMITMENT},
+};
+
+static const uint8_t smp_slave_wait_nonce_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* peer nonce is received */
+ /* RAND */
+ {SMP_PROC_RAND, SMP_PROCESS_PEER_NONCE, SMP_STATE_SEC_CONN_PHS2_START},
+ /* NC model, time to calculate number for NC */
+ /* SC_CALC_NC */
+ {SMP_CALCULATE_NUMERIC_COMPARISON_DISPLAY_NUMBER, SMP_SM_NO_ACTION,
+ SMP_STATE_WAIT_NONCE},
+ /* NC model, time to display calculated number for NC to the user */
+ /* SC_DSPL_NC */
+ {SMP_SEND_APP_CBACK, SMP_SM_NO_ACTION, SMP_STATE_WAIT_APP_RSP},
+};
+
+static const uint8_t smp_slave_sec_conn_phs2_start_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* SC_PHASE1_CMPLT */
+ {SMP_CALCULATE_LOCAL_DHKEY_CHECK, SMP_PH2_DHKEY_CHECKS_ARE_PRESENT,
+ SMP_STATE_WAIT_DHK_CHECK},
+ /* DHKey Check from master is received before slave DHKey calculation is
+ * completed - race */
+ /* PAIR_DHKEY_CHCK */
+ {SMP_PROCESS_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_SEC_CONN_PHS2_START},
+};
+
+static const uint8_t smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* PAIR_DHKEY_CHCK */
+ {SMP_PROCESS_DHKEY_CHECK, SMP_CALCULATE_PEER_DHKEY_CHECK,
+ SMP_STATE_DHK_CHECK},
+ /* DHKey Check from master was received before slave came to this state */
+ /* SC_2_DHCK_CHKS_PRES */
+ {SMP_CALCULATE_PEER_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+};
+
+static const uint8_t smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+
+ /* locally calculated peer dhkey check is ready -> compare it withs DHKey
+ * Check
+ */
+ /* actually received from peer */
+ /* SC_KEY_READY */
+ {SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK},
+
+ /* dhkey checks match -> send local dhkey check to master, go to wait for
+ * HCI LE
+ */
+ /* Long Term Key Request Event */
+ /* PAIR_DHKEY_CHCK */
+ {SMP_SEND_DHKEY_CHECK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+};
+
+static const uint8_t smp_slave_enc_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* ENC_REQ */
+ {SMP_GENERATE_STK, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+
+ /* STK ready */
+ /* KEY_READY */
+ {SMP_SEND_LTK_REPLY, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* ENCRYPTED */
+ {SMP_CHECK_AUTH_REQ, SMP_SM_NO_ACTION, SMP_STATE_ENCRYPTION_PENDING},
+ /* BOND_REQ */
+ {SMP_KEY_DISTRIBUTE, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}};
+static const uint8_t smp_slave_bond_pending_table[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+
+ /* LTK ready */
+ /* KEY_READY */
+ {SMP_SEND_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+
+ /* rev SRK */
+ /* SIGN_INFO */
+ {SMP_PROC_SRK_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ENC_INFO */
+ {SMP_PROC_ENC_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_INFO */
+ {SMP_PROC_ID_INFO, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* MASTER_ID*/
+ {SMP_PROC_MASTER_ID, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING},
+ /* ID_ADDR */
+ {SMP_PROC_ID_ADDR, SMP_SM_NO_ACTION, SMP_STATE_BOND_PENDING}
+
+};
+
+static const uint8_t
+ smp_slave_create_local_sec_conn_oob_data[][SMP_SM_NUM_COLS] = {
+ /* Event Action Next State */
+ /* LOC_PUBL_KEY_CRTD */
+ {SMP_SET_LOCAL_OOB_KEYS, SMP_SM_NO_ACTION,
+ SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA},
+ /* HAVE_LOC_NONCE */
+ {SMP_SET_LOCAL_OOB_RAND_COMMITMENT, SMP_SM_NO_ACTION, SMP_STATE_IDLE}};
+
+static const tSMP_SM_TBL smp_state_table[][2] = {
+ /* SMP_STATE_IDLE */
+ {smp_master_idle_table, smp_slave_idle_table},
+
+ /* SMP_STATE_WAIT_APP_RSP */
+ {smp_master_wait_for_app_response_table,
+ smp_slave_wait_for_app_response_table},
+
+ /* SMP_STATE_SEC_REQ_PENDING */
+ {NULL, smp_slave_sec_request_table},
+
+ /* SMP_STATE_PAIR_REQ_RSP */
+ {smp_master_pair_request_response_table,
+ smp_slave_pair_request_response_table},
+
+ /* SMP_STATE_WAIT_CONFIRM */
+ {smp_master_wait_for_confirm_table, smp_slave_wait_confirm_table},
+
+ /* SMP_STATE_CONFIRM */
+ {smp_master_confirm_table, smp_slave_confirm_table},
+
+ /* SMP_STATE_RAND */
+ {smp_master_rand_table, smp_slave_rand_table},
+
+ /* SMP_STATE_PUBLIC_KEY_EXCH */
+ {smp_master_public_key_exchange_table, smp_slave_public_key_exch_table},
+
+ /* SMP_STATE_SEC_CONN_PHS1_START */
+ {smp_master_sec_conn_phs1_start_table, smp_slave_sec_conn_phs1_start_table},
+
+ /* SMP_STATE_WAIT_COMMITMENT */
+ {smp_master_wait_commitment_table, smp_slave_wait_commitment_table},
+
+ /* SMP_STATE_WAIT_NONCE */
+ {smp_master_wait_nonce_table, smp_slave_wait_nonce_table},
+
+ /* SMP_STATE_SEC_CONN_PHS2_START */
+ {smp_master_sec_conn_phs2_start_table, smp_slave_sec_conn_phs2_start_table},
+
+ /* SMP_STATE_WAIT_DHK_CHECK */
+ {smp_master_wait_dhk_check_table, smp_slave_wait_dhk_check_table},
+
+ /* SMP_STATE_DHK_CHECK */
+ {smp_master_dhk_check_table, smp_slave_dhk_check_table},
+
+ /* SMP_STATE_ENCRYPTION_PENDING */
+ {smp_master_enc_pending_table, smp_slave_enc_pending_table},
+
+ /* SMP_STATE_BOND_PENDING */
+ {smp_master_bond_pending_table, smp_slave_bond_pending_table},
+
+ /* SMP_STATE_CREATE_LOCAL_SEC_CONN_OOB_DATA */
+ {smp_master_create_local_sec_conn_oob_data,
+ smp_slave_create_local_sec_conn_oob_data}};
+
+typedef const uint8_t (*tSMP_ENTRY_TBL)[SMP_STATE_MAX];
+static const tSMP_ENTRY_TBL smp_entry_table[] = {smp_master_entry_map,
+ smp_slave_entry_map};
+
+tSMP_CB smp_cb;
+
+#define SMP_ALL_TBL_MASK 0x80
+
+/*******************************************************************************
+ * Function smp_set_state
+ * Returns None
+ ******************************************************************************/
+void smp_set_state(tSMP_STATE state) {
+ if (state < SMP_STATE_MAX) {
+ SMP_TRACE_DEBUG("State change: %s(%d) ==> %s(%d)",
+ smp_get_state_name(smp_cb.state), smp_cb.state,
+ smp_get_state_name(state), state);
+ smp_cb.state = state;
+ } else {
+ SMP_TRACE_DEBUG("smp_set_state invalid state =%d", state);
+ }
+}
+
+/*******************************************************************************
+ * Function smp_get_state
+ * Returns The smp state
+ ******************************************************************************/
+tSMP_STATE smp_get_state(void) { return smp_cb.state; }
+
+/*******************************************************************************
+ *
+ * Function smp_sm_event
+ *
+ * Description Handle events to the state machine. It looks up the entry
+ * in the smp_entry_table array.
+ * If it is a valid entry, it gets the state table. Set the next
+ * state, if not NULL state. Execute the action function according
+ * to the state table. If the state returned by action function is
+ * not NULL state, adjust the new state to the returned state. If
+ * (api_evt != MAX), call callback function.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+void smp_sm_event(tSMP_CB* p_cb, tSMP_EVENT event, void* p_data) {
+ uint8_t curr_state = p_cb->state;
+ tSMP_SM_TBL state_table;
+ uint8_t action, entry, i;
+ tSMP_ENTRY_TBL entry_table = smp_entry_table[p_cb->role];
+
+ SMP_TRACE_EVENT("main smp_sm_event");
+ if (curr_state >= SMP_STATE_MAX) {
+ SMP_TRACE_DEBUG("Invalid state: %d", curr_state);
+ return;
+ }
+
+ SMP_TRACE_DEBUG("SMP Role: %s State: [%s (%d)], Event: [%s (%d)]",
+ (p_cb->role == 0x01) ? "Slave" : "Master",
+ smp_get_state_name(p_cb->state), p_cb->state,
+ smp_get_event_name(event), event);
+
+ /* look up the state table for the current state */
+ /* lookup entry /w event & curr_state */
+ /* If entry is ignore, return.
+ * Otherwise, get state table (according to curr_state or all_state) */
+ if ((event <= SMP_MAX_EVT) &&
+ ((entry = entry_table[event - 1][curr_state]) != SMP_SM_IGNORE)) {
+ if (entry & SMP_ALL_TBL_MASK) {
+ entry &= ~SMP_ALL_TBL_MASK;
+ state_table = smp_all_table;
+ } else
+ state_table = smp_state_table[curr_state][p_cb->role];
+ } else {
+ SMP_TRACE_DEBUG("Ignore event [%s (%d)] in state [%s (%d)]",
+ smp_get_event_name(event), event,
+ smp_get_state_name(curr_state), curr_state);
+ return;
+ }
+
+ /* Get possible next state from state table. */
+
+ smp_set_state(state_table[entry - 1][SMP_SME_NEXT_STATE]);
+
+ /* If action is not ignore, clear param, exec action and get next state.
+ * The action function may set the Param for cback.
+ * Depending on param, call cback or free buffer. */
+ /* execute action */
+ /* execute action functions */
+ for (i = 0; i < SMP_NUM_ACTIONS; i++) {
+ action = state_table[entry - 1][i];
+ if (action != SMP_SM_NO_ACTION) {
+ (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA*)p_data);
+ } else {
+ break;
+ }
+ }
+ SMP_TRACE_DEBUG("result state = %s", smp_get_state_name(p_cb->state));
+}
+
+/*******************************************************************************
+ * Function smp_get_state_name
+ * Returns The smp state name.
+ ******************************************************************************/
+const char* smp_get_state_name(tSMP_STATE state) {
+ const char* p_str = smp_state_name[SMP_STATE_MAX];
+
+ if (state < SMP_STATE_MAX) {
+ p_str = smp_state_name[state];
+ }
+ return p_str;
+}
+
+/*******************************************************************************
+ * Function smp_get_event_name
+ * Returns The smp event name.
+ ******************************************************************************/
+const char* smp_get_event_name(tSMP_EVENT event) {
+ const char* p_str = smp_event_name[SMP_MAX_EVT];
+
+ if (event <= SMP_MAX_EVT) {
+ p_str = smp_event_name[event - 1];
+ }
+ return p_str;
+}
diff --git a/mtkbt/code/bt/stack/smp/smp_utils.cc b/mtkbt/code/bt/stack/smp/smp_utils.cc
new file mode 100755
index 0000000..f613ed1
--- a/dev/null
+++ b/mtkbt/code/bt/stack/smp/smp_utils.cc
@@ -0,0 +1,1532 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for the SMP L2CAP utility functions
+ *
+ ******************************************************************************/
+#include "bt_target.h"
+
+#include <ctype.h>
+#include <string.h>
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "btm_ble_api.h"
+#include "btm_int.h"
+#include "device/include/controller.h"
+#include "hcidefs.h"
+#include "l2c_api.h"
+#include "l2c_int.h"
+#include "osi/include/osi.h"
+#include "smp_int.h"
+
+extern fixed_queue_t* btu_general_alarm_queue;
+
+#define SMP_PAIRING_REQ_SIZE 7
+#define SMP_CONFIRM_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_RAND_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_INIT_CMD_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ENC_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_MASTER_ID_SIZE (BT_OCTET8_LEN + 2 + 1)
+#define SMP_ID_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_ID_ADDR_SIZE (BD_ADDR_LEN + 1 + 1)
+#define SMP_SIGN_INFO_SIZE (BT_OCTET16_LEN + 1)
+#define SMP_PAIR_FAIL_SIZE 2
+#define SMP_SECURITY_REQUEST_SIZE 2
+#define SMP_PAIR_PUBL_KEY_SIZE (1 /* opcode */ + (2 * BT_OCTET32_LEN))
+#define SMP_PAIR_COMMITM_SIZE (1 /* opcode */ + BT_OCTET16_LEN /*Commitment*/)
+#define SMP_PAIR_DHKEY_CHECK_SIZE \
+ (1 /* opcode */ + BT_OCTET16_LEN /*DHKey Check*/)
+#define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/)
+
+/* SMP command sizes per spec */
+static const uint8_t smp_cmd_size_per_spec[] = {
+ 0,
+ SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */
+ SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */
+ SMP_CONFIRM_CMD_SIZE, /* 0x03: pairing confirm */
+ SMP_RAND_CMD_SIZE, /* 0x04: pairing random */
+ SMP_PAIR_FAIL_SIZE, /* 0x05: pairing failed */
+ SMP_ENC_INFO_SIZE, /* 0x06: encryption information */
+ SMP_MASTER_ID_SIZE, /* 0x07: master identification */
+ SMP_ID_INFO_SIZE, /* 0x08: identity information */
+ SMP_ID_ADDR_SIZE, /* 0x09: identity address information */
+ SMP_SIGN_INFO_SIZE, /* 0x0A: signing information */
+ SMP_SECURITY_REQUEST_SIZE, /* 0x0B: security request */
+ SMP_PAIR_PUBL_KEY_SIZE, /* 0x0C: pairing public key */
+ SMP_PAIR_DHKEY_CHECK_SIZE, /* 0x0D: pairing dhkey check */
+ SMP_PAIR_KEYPR_NOTIF_SIZE, /* 0x0E: pairing keypress notification */
+ SMP_PAIR_COMMITM_SIZE /* 0x0F: pairing commitment */
+};
+
+static bool smp_parameter_unconditionally_valid(tSMP_CB* p_cb);
+static bool smp_parameter_unconditionally_invalid(tSMP_CB* p_cb);
+
+/* type for SMP command length validation functions */
+typedef bool (*tSMP_CMD_LEN_VALID)(tSMP_CB* p_cb);
+
+static bool smp_command_has_valid_fixed_length(tSMP_CB* p_cb);
+
+static const tSMP_CMD_LEN_VALID smp_cmd_len_is_valid[] = {
+ smp_parameter_unconditionally_invalid,
+ smp_command_has_valid_fixed_length, /* 0x01: pairing request */
+ smp_command_has_valid_fixed_length, /* 0x02: pairing response */
+ smp_command_has_valid_fixed_length, /* 0x03: pairing confirm */
+ smp_command_has_valid_fixed_length, /* 0x04: pairing random */
+ smp_command_has_valid_fixed_length, /* 0x05: pairing failed */
+ smp_command_has_valid_fixed_length, /* 0x06: encryption information */
+ smp_command_has_valid_fixed_length, /* 0x07: master identification */
+ smp_command_has_valid_fixed_length, /* 0x08: identity information */
+ smp_command_has_valid_fixed_length, /* 0x09: identity address information */
+ smp_command_has_valid_fixed_length, /* 0x0A: signing information */
+ smp_command_has_valid_fixed_length, /* 0x0B: security request */
+ smp_command_has_valid_fixed_length, /* 0x0C: pairing public key */
+ smp_command_has_valid_fixed_length, /* 0x0D: pairing dhkey check */
+ smp_command_has_valid_fixed_length, /* 0x0E: pairing keypress notification*/
+ smp_command_has_valid_fixed_length /* 0x0F: pairing commitment */
+};
+
+/* type for SMP command parameter ranges validation functions */
+typedef bool (*tSMP_CMD_PARAM_RANGES_VALID)(tSMP_CB* p_cb);
+
+static bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb);
+static bool smp_pairing_keypress_notification_is_valid(tSMP_CB* p_cb);
+
+static const tSMP_CMD_PARAM_RANGES_VALID smp_cmd_param_ranges_are_valid[] = {
+ smp_parameter_unconditionally_invalid,
+ smp_pairing_request_response_parameters_are_valid, /* 0x01: pairing
+ request */
+ smp_pairing_request_response_parameters_are_valid, /* 0x02: pairing
+ response */
+ smp_parameter_unconditionally_valid, /* 0x03: pairing confirm */
+ smp_parameter_unconditionally_valid, /* 0x04: pairing random */
+ smp_parameter_unconditionally_valid, /* 0x05: pairing failed */
+ smp_parameter_unconditionally_valid, /* 0x06: encryption information */
+ smp_parameter_unconditionally_valid, /* 0x07: master identification */
+ smp_parameter_unconditionally_valid, /* 0x08: identity information */
+ smp_parameter_unconditionally_valid, /* 0x09: identity address
+ information */
+ smp_parameter_unconditionally_valid, /* 0x0A: signing information */
+ smp_parameter_unconditionally_valid, /* 0x0B: security request */
+ smp_parameter_unconditionally_valid, /* 0x0C: pairing public key */
+ smp_parameter_unconditionally_valid, /* 0x0D: pairing dhkey check */
+ smp_pairing_keypress_notification_is_valid, /* 0x0E: pairing keypress
+ notification */
+ smp_parameter_unconditionally_valid /* 0x0F: pairing commitment */
+};
+
+/* type for action functions */
+typedef BT_HDR* (*tSMP_CMD_ACT)(uint8_t cmd_code, tSMP_CB* p_cb);
+
+static BT_HDR* smp_build_pairing_cmd(uint8_t cmd_code, tSMP_CB* p_cb);
+static BT_HDR* smp_build_confirm_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_rand_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB* p_cb);
+static BT_HDR* smp_build_pairing_fail(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_encrypt_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_security_request(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_signing_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_master_id_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_id_addr_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_pair_public_key_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_pairing_commitment_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_pair_dhkey_check_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb);
+static BT_HDR* smp_build_pairing_keypress_notification_cmd(
+ UNUSED_ATTR uint8_t cmd_code, tSMP_CB* p_cb);
+
+static const tSMP_CMD_ACT smp_cmd_build_act[] = {
+ NULL, smp_build_pairing_cmd, /* 0x01: pairing request */
+ smp_build_pairing_cmd, /* 0x02: pairing response */
+ smp_build_confirm_cmd, /* 0x03: pairing confirm */
+ smp_build_rand_cmd, /* 0x04: pairing random */
+ smp_build_pairing_fail, /* 0x05: pairing failure */
+ smp_build_encrypt_info_cmd, /* 0x06: encryption information */
+ smp_build_master_id_cmd, /* 0x07: master identification */
+ smp_build_identity_info_cmd, /* 0x08: identity information */
+ smp_build_id_addr_cmd, /* 0x09: identity address information */
+ smp_build_signing_info_cmd, /* 0x0A: signing information */
+ smp_build_security_request, /* 0x0B: security request */
+ smp_build_pair_public_key_cmd, /* 0x0C: pairing public key */
+ smp_build_pair_dhkey_check_cmd, /* 0x0D: pairing DHKey check */
+ smp_build_pairing_keypress_notification_cmd, /* 0x0E: pairing keypress
+ notification */
+ smp_build_pairing_commitment_cmd /* 0x0F: pairing commitment */
+};
+
+static const uint8_t smp_association_table[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] =
+ {
+ /* display only */ /* Display Yes/No */ /* keyboard only */
+ /* No Input/Output */ /* keyboard display */
+
+ /* initiator */
+ /* model = tbl[peer_io_caps][loc_io_caps] */
+ /* Display Only */
+ {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+ /* Display Yes/No */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_PASSKEY, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+ /* Keyboard only */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+ /* No Input No Output */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY},
+
+ /* keyboard display */
+ {SMP_MODEL_KEY_NOTIF, SMP_MODEL_KEY_NOTIF, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF}},
+
+ /* responder */
+ /* model = tbl[loc_io_caps][peer_io_caps] */
+ /* Display Only */
+ {{SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+ /* Display Yes/No */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_KEY_NOTIF, SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_KEY_NOTIF},
+
+ /* keyboard only */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY},
+
+ /* No Input No Output */
+ {SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_ENCRYPTION_ONLY,
+ SMP_MODEL_ENCRYPTION_ONLY},
+
+ /* keyboard display */
+ {SMP_MODEL_PASSKEY, SMP_MODEL_PASSKEY, SMP_MODEL_KEY_NOTIF,
+ SMP_MODEL_ENCRYPTION_ONLY, SMP_MODEL_PASSKEY}}};
+
+static const uint8_t
+ smp_association_table_sc[2][SMP_IO_CAP_MAX][SMP_IO_CAP_MAX] = {
+ /* display only */ /* Display Yes/No */ /* keyboard only */
+ /* No InputOutput */ /* keyboard display */
+
+ /* initiator */
+ /* model = tbl[peer_io_caps][loc_io_caps] */
+
+ /* Display Only */
+ {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT},
+
+ /* Display Yes/No */
+ {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_NUM_COMP},
+
+ /* keyboard only */
+ {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_PASSKEY_DISP,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP},
+
+ /* No Input No Output */
+ {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS},
+
+ /* keyboard display */
+ {SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_NUM_COMP,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_NUM_COMP}},
+
+ /* responder */
+ /* model = tbl[loc_io_caps][peer_io_caps] */
+
+ /* Display Only */
+ {{SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP},
+
+ /* Display Yes/No */
+ {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_NUM_COMP,
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_NUM_COMP},
+
+ /* keyboard only */
+ {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_PASSKEY_ENT,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_PASSKEY_ENT},
+
+ /* No Input No Output */
+ {SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_JUSTWORKS},
+
+ /* keyboard display */
+ {SMP_MODEL_SEC_CONN_PASSKEY_ENT, SMP_MODEL_SEC_CONN_NUM_COMP,
+ SMP_MODEL_SEC_CONN_PASSKEY_DISP, SMP_MODEL_SEC_CONN_JUSTWORKS,
+ SMP_MODEL_SEC_CONN_NUM_COMP}}};
+
+static tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB* p_cb);
+static tSMP_ASSO_MODEL smp_select_association_model_secure_connections(
+ tSMP_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function smp_send_msg_to_L2CAP
+ *
+ * Description Send message to L2CAP.
+ *
+ ******************************************************************************/
+bool smp_send_msg_to_L2CAP(BD_ADDR rem_bda, BT_HDR* p_toL2CAP) {
+ uint16_t l2cap_ret;
+ uint16_t fixed_cid = L2CAP_SMP_CID;
+
+ if (smp_cb.smp_over_br) {
+ fixed_cid = L2CAP_SMP_BR_CID;
+ }
+
+ SMP_TRACE_EVENT("%s", __func__);
+ smp_cb.total_tx_unacked += 1;
+
+ l2cap_ret = L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_toL2CAP);
+ if (l2cap_ret == L2CAP_DW_FAILED) {
+ smp_cb.total_tx_unacked -= 1;
+ SMP_TRACE_ERROR("SMP failed to pass msg:0x%0x to L2CAP",
+ *((uint8_t*)(p_toL2CAP + 1) + p_toL2CAP->offset));
+ return false;
+ } else
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_send_cmd
+ *
+ * Description send a SMP command on L2CAP channel.
+ *
+ ******************************************************************************/
+bool smp_send_cmd(uint8_t cmd_code, tSMP_CB* p_cb) {
+ BT_HDR* p_buf;
+ bool sent = false;
+ uint8_t failure = SMP_PAIR_INTERNAL_ERR;
+ SMP_TRACE_EVENT("smp_send_cmd on l2cap cmd_code=0x%x", cmd_code);
+ if (cmd_code <= (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */) &&
+ smp_cmd_build_act[cmd_code] != NULL) {
+ p_buf = (*smp_cmd_build_act[cmd_code])(cmd_code, p_cb);
+
+ if (p_buf != NULL && smp_send_msg_to_L2CAP(p_cb->pairing_bda, p_buf)) {
+ sent = true;
+ alarm_set_on_queue(p_cb->smp_rsp_timer_ent, SMP_WAIT_FOR_RSP_TIMEOUT_MS,
+ smp_rsp_timeout, NULL, btu_general_alarm_queue);
+ }
+ }
+
+ if (!sent) {
+ if (p_cb->smp_over_br) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+ }
+ return sent;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_rsp_timeout
+ *
+ * Description Called when SMP wait for SMP command response timer expires
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_rsp_timeout(UNUSED_ATTR void* data) {
+ tSMP_CB* p_cb = &smp_cb;
+ uint8_t failure = SMP_RSP_TIMEOUT;
+
+ SMP_TRACE_EVENT("%s state:%d br_state:%d", __func__, p_cb->state,
+ p_cb->br_state);
+
+ if (p_cb->smp_over_br) {
+ smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &failure);
+ } else {
+ smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_delayed_auth_complete_timeout
+ *
+ * Description Called when no pairing failed command received within
+ * timeout period.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_delayed_auth_complete_timeout(UNUSED_ATTR void* data) {
+ /*
+ * Waited for potential pair failure. Send SMP_AUTH_CMPL_EVT if
+ * the state is still in bond pending.
+ */
+ if (smp_get_state() == SMP_STATE_BOND_PENDING) {
+ uint8_t reason = SMP_SUCCESS;
+ SMP_TRACE_EVENT("%s sending delayed auth complete.", __func__);
+ smp_sm_event(&smp_cb, SMP_AUTH_CMPL_EVT, &reason);
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pairing_req_cmd
+ *
+ * Description Build pairing request command.
+ *
+ ******************************************************************************/
+BT_HDR* smp_build_pairing_cmd(uint8_t cmd_code, tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIRING_REQ_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, cmd_code);
+ UINT8_TO_STREAM(p, p_cb->local_io_capability);
+ UINT8_TO_STREAM(p, p_cb->loc_oob_flag);
+ UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+ UINT8_TO_STREAM(p, p_cb->loc_enc_size);
+ UINT8_TO_STREAM(p, p_cb->local_i_key);
+ UINT8_TO_STREAM(p, p_cb->local_r_key);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ /* 1B ERR_RSP op code + 1B cmd_op_code + 2B handle + 1B status */
+ p_buf->len = SMP_PAIRING_REQ_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_confirm_cmd
+ *
+ * Description Build confirm request command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_confirm_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_CONFIRM_CMD_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
+ ARRAY_TO_STREAM(p, p_cb->confirm, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_CONFIRM_CMD_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_rand_cmd
+ *
+ * Description Build Random command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_rand_cmd(UNUSED_ATTR uint8_t cmd_code, tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_RAND_CMD_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_RAND);
+ ARRAY_TO_STREAM(p, p_cb->rand, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_RAND_CMD_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_encrypt_info_cmd
+ *
+ * Description Build security information command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_encrypt_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ENC_INFO_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_ENCRYPT_INFO);
+ ARRAY_TO_STREAM(p, p_cb->ltk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ENC_INFO_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_master_id_cmd
+ *
+ * Description Build security information command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_master_id_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_MASTER_ID_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_MASTER_ID);
+ UINT16_TO_STREAM(p, p_cb->ediv);
+ ARRAY_TO_STREAM(p, p_cb->enc_rand, BT_OCTET8_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_MASTER_ID_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_identity_info_cmd
+ *
+ * Description Build identity information command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_identity_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ UNUSED_ATTR tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_OCTET16 irk;
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_INFO_SIZE + L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+
+ BTM_GetDeviceIDRoot(irk);
+
+ UINT8_TO_STREAM(p, SMP_OPCODE_IDENTITY_INFO);
+ ARRAY_TO_STREAM(p, irk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_INFO_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_id_addr_cmd
+ *
+ * Description Build identity address information command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_id_addr_cmd(UNUSED_ATTR uint8_t cmd_code,
+ UNUSED_ATTR tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf =
+ (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_ID_ADDR_SIZE + L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_ID_ADDR);
+ UINT8_TO_STREAM(p, 0);
+ BDADDR_TO_STREAM(p, controller_get_interface()->get_address()->address);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_ID_ADDR_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_signing_info_cmd
+ *
+ * Description Build signing information command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_signing_info_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_SIGN_INFO_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_SIGN_INFO);
+ ARRAY_TO_STREAM(p, p_cb->csrk, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_SIGN_INFO_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pairing_fail
+ *
+ * Description Build Pairing Fail command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_pairing_fail(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED);
+ UINT8_TO_STREAM(p, p_cb->failure);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_FAIL_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_security_request
+ *
+ * Description Build security request command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_security_request(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 2 + L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_SEC_REQ);
+ UINT8_TO_STREAM(p, p_cb->loc_auth_req);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_SECURITY_REQUEST_SIZE;
+
+ SMP_TRACE_EVENT("opcode=%d auth_req=0x%x", SMP_OPCODE_SEC_REQ,
+ p_cb->loc_auth_req);
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pair_public_key_cmd
+ *
+ * Description Build pairing public key command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_pair_public_key_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ uint8_t publ_key[2 * BT_OCTET32_LEN];
+ uint8_t* p_publ_key = publ_key;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_PUBL_KEY_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ memcpy(p_publ_key, p_cb->loc_publ_key.x, BT_OCTET32_LEN);
+ memcpy(p_publ_key + BT_OCTET32_LEN, p_cb->loc_publ_key.y, BT_OCTET32_LEN);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_PUBLIC_KEY);
+ ARRAY_TO_STREAM(p, p_publ_key, 2 * BT_OCTET32_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_PUBL_KEY_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pairing_commitment_cmd
+ *
+ * Description Build pairing commitment command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_pairing_commitment_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_COMMITM_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_CONFIRM);
+ ARRAY_TO_STREAM(p, p_cb->commitment, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_COMMITM_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pair_dhkey_check_cmd
+ *
+ * Description Build pairing DHKey check command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_pair_dhkey_check_cmd(UNUSED_ATTR uint8_t cmd_code,
+ tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(
+ sizeof(BT_HDR) + SMP_PAIR_DHKEY_CHECK_SIZE + L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_DHKEY_CHECK);
+ ARRAY_TO_STREAM(p, p_cb->dhkey_check, BT_OCTET16_LEN);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_DHKEY_CHECK_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_build_pairing_keypress_notification_cmd
+ *
+ * Description Build keypress notification command.
+ *
+ ******************************************************************************/
+static BT_HDR* smp_build_pairing_keypress_notification_cmd(
+ UNUSED_ATTR uint8_t cmd_code, tSMP_CB* p_cb) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(
+ sizeof(BT_HDR) + SMP_PAIR_KEYPR_NOTIF_SIZE + L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_EVENT("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_PAIR_KEYPR_NOTIF);
+ UINT8_TO_STREAM(p, p_cb->local_keypress_notification);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_KEYPR_NOTIF_SIZE;
+
+ return p_buf;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_convert_string_to_tk
+ *
+ * Description This function is called to convert a 6 to 16 digits numeric
+ * character string into SMP TK.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_convert_string_to_tk(BT_OCTET16 tk, uint32_t passkey) {
+ uint8_t* p = tk;
+ tSMP_KEY key;
+ SMP_TRACE_EVENT("smp_convert_string_to_tk");
+ UINT32_TO_STREAM(p, passkey);
+
+ key.key_type = SMP_KEY_TYPE_TK;
+ key.p_data = tk;
+
+ smp_sm_event(&smp_cb, SMP_KEY_READY_EVT, &key);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_mask_enc_key
+ *
+ * Description This function is called to mask off the encryption key based
+ * on the maximum encryption key size.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_mask_enc_key(uint8_t loc_enc_size, uint8_t* p_data) {
+ SMP_TRACE_EVENT("smp_mask_enc_key");
+ if (loc_enc_size < BT_OCTET16_LEN) {
+ for (; loc_enc_size < BT_OCTET16_LEN; loc_enc_size++)
+ *(p_data + loc_enc_size) = 0;
+ }
+ return;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_xor_128
+ *
+ * Description utility function to do an biteise exclusive-OR of two bit
+ * strings of the length of BT_OCTET16_LEN.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_xor_128(BT_OCTET16 a, BT_OCTET16 b) {
+ uint8_t i, *aa = a, *bb = b;
+
+ SMP_TRACE_EVENT("smp_xor_128");
+ for (i = 0; i < BT_OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function smp_cb_cleanup
+ *
+ * Description Clean up SMP control block
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_cb_cleanup(tSMP_CB* p_cb) {
+ tSMP_CALLBACK* p_callback = p_cb->p_callback;
+ uint8_t trace_level = p_cb->trace_level;
+ alarm_t* smp_rsp_timer_ent = p_cb->smp_rsp_timer_ent;
+ alarm_t* delayed_auth_timer_ent = p_cb->delayed_auth_timer_ent;
+
+ SMP_TRACE_EVENT("smp_cb_cleanup");
+
+ alarm_cancel(p_cb->smp_rsp_timer_ent);
+ alarm_cancel(p_cb->delayed_auth_timer_ent);
+ memset(p_cb, 0, sizeof(tSMP_CB));
+ p_cb->p_callback = p_callback;
+ p_cb->trace_level = trace_level;
+ p_cb->smp_rsp_timer_ent = smp_rsp_timer_ent;
+ p_cb->delayed_auth_timer_ent = delayed_auth_timer_ent;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_remove_fixed_channel
+ *
+ * Description This function is called to remove the fixed channel
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_remove_fixed_channel(tSMP_CB* p_cb) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->smp_over_br)
+ L2CA_RemoveFixedChnl(L2CAP_SMP_BR_CID, p_cb->pairing_bda);
+ else
+ L2CA_RemoveFixedChnl(L2CAP_SMP_CID, p_cb->pairing_bda);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_reset_control_value
+ *
+ * Description This function is called to reset the control block value
+ * when the pairing procedure finished.
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_reset_control_value(tSMP_CB* p_cb) {
+ SMP_TRACE_EVENT("%s", __func__);
+
+ alarm_cancel(p_cb->smp_rsp_timer_ent);
+ p_cb->flags = 0;
+ /* set the link idle timer to drop the link when pairing is done
+ usually service discovery will follow authentication complete, to avoid
+ racing condition for a link down/up, set link idle timer to be
+ SMP_LINK_TOUT_MIN to guarantee SMP key exchange */
+ L2CA_SetIdleTimeoutByBdAddr(p_cb->pairing_bda, SMP_LINK_TOUT_MIN,
+ BT_TRANSPORT_LE);
+
+ /* We can tell L2CAP to remove the fixed channel (if it has one) */
+ smp_remove_fixed_channel(p_cb);
+ smp_cb_cleanup(p_cb);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_proc_pairing_cmpl
+ *
+ * Description This function is called to process pairing complete
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_proc_pairing_cmpl(tSMP_CB* p_cb) {
+ tSMP_EVT_DATA evt_data = {0};
+ tSMP_CALLBACK* p_callback = p_cb->p_callback;
+ BD_ADDR pairing_bda;
+
+ SMP_TRACE_DEBUG("smp_proc_pairing_cmpl ");
+
+ evt_data.cmplt.reason = p_cb->status;
+ evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
+
+ if (p_cb->status == SMP_SUCCESS) evt_data.cmplt.sec_level = p_cb->sec_level;
+
+ evt_data.cmplt.is_pair_cancel = false;
+
+ if (p_cb->is_pair_cancel) evt_data.cmplt.is_pair_cancel = true;
+
+ SMP_TRACE_DEBUG("send SMP_COMPLT_EVT reason=0x%0x sec_level=0x%0x",
+ evt_data.cmplt.reason, evt_data.cmplt.sec_level);
+
+ memcpy(pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
+
+ smp_reset_control_value(p_cb);
+
+ if (p_callback) (*p_callback)(SMP_COMPLT_EVT, pairing_bda, &evt_data);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_command_has_invalid_parameters
+ *
+ * Description Checks if the received SMP command has invalid parameters
+ * i.e. if the command length is valid and the command
+ * parameters are inside specified range.
+ * It returns true if the command has invalid parameters.
+ *
+ * Returns true if the command has invalid parameters, false otherwise.
+ *
+ ******************************************************************************/
+bool smp_command_has_invalid_parameters(tSMP_CB* p_cb) {
+ uint8_t cmd_code = p_cb->rcvd_cmd_code;
+
+ if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) ||
+ (cmd_code < SMP_OPCODE_MIN)) {
+ SMP_TRACE_WARNING("%s: Received command with RESERVED code 0x%02x",
+ __func__, cmd_code);
+ return true;
+ }
+
+ if (!(*smp_cmd_len_is_valid[cmd_code])(p_cb)) {
+ SMP_TRACE_WARNING("%s: Command length not valid for cmd_code 0x%02x",
+ __func__, cmd_code);
+ return true;
+ }
+
+ if (!(*smp_cmd_param_ranges_are_valid[cmd_code])(p_cb)) {
+ SMP_TRACE_WARNING("%s: Parameter ranges not valid code 0x%02x", __func__,
+ cmd_code);
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_command_has_valid_fixed_length
+ *
+ * Description Checks if the received command size is equal to the size
+ * according to specs.
+ *
+ * Returns true if the command size is as expected, false otherwise.
+ *
+ * Note The command is expected to have fixed length.
+ ******************************************************************************/
+bool smp_command_has_valid_fixed_length(tSMP_CB* p_cb) {
+ uint8_t cmd_code = p_cb->rcvd_cmd_code;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, cmd_code);
+
+ if (p_cb->rcvd_cmd_len != smp_cmd_size_per_spec[cmd_code]) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with invalid length\
+ 0x%02x (per spec the length is 0x%02x).",
+ cmd_code, p_cb->rcvd_cmd_len, smp_cmd_size_per_spec[cmd_code]);
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_pairing_request_response_parameters_are_valid
+ *
+ * Description Validates parameter ranges in the received SMP command
+ * pairing request or pairing response.
+ * The parameters to validate:
+ * IO capability,
+ * OOB data flag,
+ * Bonding_flags in AuthReq
+ * Maximum encryption key size.
+ * Returns false if at least one of these parameters is out of
+ * range.
+ *
+ ******************************************************************************/
+bool smp_pairing_request_response_parameters_are_valid(tSMP_CB* p_cb) {
+ uint8_t io_caps = p_cb->peer_io_caps;
+ uint8_t oob_flag = p_cb->peer_oob_flag;
+ uint8_t bond_flag =
+ p_cb->peer_auth_req & 0x03; // 0x03 is gen bond with appropriate mask
+ uint8_t enc_size = p_cb->peer_enc_size;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code);
+
+ if (io_caps >= BTM_IO_CAP_MAX) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with IO Capabilty \
+ value (0x%02x) out of range).",
+ p_cb->rcvd_cmd_code, io_caps);
+ return false;
+ }
+
+ if (!((oob_flag == SMP_OOB_NONE) || (oob_flag == SMP_OOB_PRESENT))) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with OOB data flag value \
+ (0x%02x) out of range).",
+ p_cb->rcvd_cmd_code, oob_flag);
+ return false;
+ }
+
+ if (!((bond_flag == SMP_AUTH_NO_BOND) || (bond_flag == SMP_AUTH_BOND))) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with Bonding_Flags value (0x%02x)\
+ out of range).",
+ p_cb->rcvd_cmd_code, bond_flag);
+ return false;
+ }
+
+ if ((enc_size < SMP_ENCR_KEY_SIZE_MIN) ||
+ (enc_size > SMP_ENCR_KEY_SIZE_MAX)) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with Maximum Encryption \
+ Key value (0x%02x) out of range).",
+ p_cb->rcvd_cmd_code, enc_size);
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_pairing_keypress_notification_is_valid
+ *
+ * Description Validates Notification Type parameter range in the received
+ * SMP command pairing keypress notification.
+ * Returns false if this parameter is out of range.
+ *
+ ******************************************************************************/
+bool smp_pairing_keypress_notification_is_valid(tSMP_CB* p_cb) {
+ tBTM_SP_KEY_TYPE keypress_notification = p_cb->peer_keypress_notification;
+
+ SMP_TRACE_DEBUG("%s for cmd code 0x%02x", __func__, p_cb->rcvd_cmd_code);
+
+ if (keypress_notification >= BTM_SP_KEY_OUT_OF_RANGE) {
+ SMP_TRACE_WARNING(
+ "Rcvd from the peer cmd 0x%02x with Pairing Keypress \
+ Notification value (0x%02x) out of range).",
+ p_cb->rcvd_cmd_code, keypress_notification);
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_parameter_unconditionally_valid
+ *
+ * Description Always returns true.
+ *
+ ******************************************************************************/
+bool smp_parameter_unconditionally_valid(UNUSED_ATTR tSMP_CB* p_cb) {
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_parameter_unconditionally_invalid
+ *
+ * Description Always returns false.
+ *
+ ******************************************************************************/
+bool smp_parameter_unconditionally_invalid(UNUSED_ATTR tSMP_CB* p_cb) {
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_reject_unexpected_pairing_command
+ *
+ * Description send pairing failure to an unexpected pairing command during
+ * an active pairing process.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_reject_unexpected_pairing_command(BD_ADDR bd_addr) {
+ uint8_t* p;
+ BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + SMP_PAIR_FAIL_SIZE +
+ L2CAP_MIN_OFFSET);
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
+ UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED);
+ UINT8_TO_STREAM(p, SMP_PAIR_NOT_SUPPORT);
+
+ p_buf->offset = L2CAP_MIN_OFFSET;
+ p_buf->len = SMP_PAIR_FAIL_SIZE;
+
+ smp_send_msg_to_L2CAP(bd_addr, p_buf);
+}
+
+/*******************************************************************************
+ * Function smp_select_association_model
+ *
+ * Description This function selects association model to use for STK
+ * generation. Selection is based on both sides' io capability,
+ * oob data flag and authentication request.
+ *
+ * Note If Secure Connections Only mode is required locally then we
+ * come to this point only if both sides support Secure
+ * Connections mode, i.e.
+ * if p_cb->secure_connections_only_mode_required = true
+ * then we come to this point only if
+ * (p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) ==
+ * (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT) ==
+ * SMP_SC_SUPPORT_BIT
+ *
+ ******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb) {
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+ p_cb->le_secure_connections_mode_is_used = false;
+
+ SMP_TRACE_EVENT("%s", __func__);
+ SMP_TRACE_DEBUG("%s p_cb->peer_io_caps = %d p_cb->local_io_capability = %d",
+ __func__, p_cb->peer_io_caps, p_cb->local_io_capability);
+ SMP_TRACE_DEBUG("%s p_cb->peer_oob_flag = %d p_cb->loc_oob_flag = %d",
+ __func__, p_cb->peer_oob_flag, p_cb->loc_oob_flag);
+ SMP_TRACE_DEBUG("%s p_cb->peer_auth_req = 0x%02x p_cb->loc_auth_req = 0x%02x",
+ __func__, p_cb->peer_auth_req, p_cb->loc_auth_req);
+ SMP_TRACE_DEBUG(
+ "%s p_cb->secure_connections_only_mode_required = %s", __func__,
+ p_cb->secure_connections_only_mode_required ? "true" : "false");
+
+ if ((p_cb->peer_auth_req & SMP_SC_SUPPORT_BIT) &&
+ (p_cb->loc_auth_req & SMP_SC_SUPPORT_BIT)) {
+ p_cb->le_secure_connections_mode_is_used = true;
+ }
+
+ if ((p_cb->peer_auth_req & SMP_H7_SUPPORT_BIT) &&
+ (p_cb->loc_auth_req & SMP_H7_SUPPORT_BIT)) {
+ p_cb->key_derivation_h7_used = TRUE;
+ }
+
+ SMP_TRACE_DEBUG("use_sc_process = %d, h7 use = %d",
+ p_cb->le_secure_connections_mode_is_used,
+ p_cb->key_derivation_h7_used);
+
+ if (p_cb->le_secure_connections_mode_is_used) {
+ model = smp_select_association_model_secure_connections(p_cb);
+ } else {
+ model = smp_select_legacy_association_model(p_cb);
+ }
+ return model;
+}
+
+/*******************************************************************************
+ * Function smp_select_legacy_association_model
+ *
+ * Description This function is called to select association mode if at
+ * least one side doesn't support secure connections.
+ *
+ ******************************************************************************/
+tSMP_ASSO_MODEL smp_select_legacy_association_model(tSMP_CB* p_cb) {
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* if OOB data is present on both devices, then use OOB association model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT &&
+ p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+ return SMP_MODEL_OOB;
+
+ /* else if neither device requires MITM, then use Just Works association model
+ */
+ if (SMP_NO_MITM_REQUIRED(p_cb->peer_auth_req) &&
+ SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+ return SMP_MODEL_ENCRYPTION_ONLY;
+
+ /* otherwise use IO capability to select association model */
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX &&
+ p_cb->local_io_capability < SMP_IO_CAP_MAX) {
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ model = smp_association_table[p_cb->role][p_cb->peer_io_caps]
+ [p_cb->local_io_capability];
+ } else {
+ model = smp_association_table[p_cb->role][p_cb->local_io_capability]
+ [p_cb->peer_io_caps];
+ }
+ }
+
+ return model;
+}
+
+/*******************************************************************************
+ * Function smp_select_association_model_secure_connections
+ *
+ * Description This function is called to select association mode if both
+ * sides support secure connections.
+ *
+ ******************************************************************************/
+tSMP_ASSO_MODEL smp_select_association_model_secure_connections(tSMP_CB* p_cb) {
+ tSMP_ASSO_MODEL model = SMP_MODEL_OUT_OF_RANGE;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+ /* if OOB data is present on at least one device, then use OOB association
+ * model */
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT ||
+ p_cb->loc_oob_flag == SMP_OOB_PRESENT)
+ return SMP_MODEL_SEC_CONN_OOB;
+
+ /* else if neither device requires MITM, then use Just Works association model
+ */
+ if (SMP_NO_MITM_REQUIRED(p_cb->peer_auth_req) &&
+ SMP_NO_MITM_REQUIRED(p_cb->loc_auth_req))
+ return SMP_MODEL_SEC_CONN_JUSTWORKS;
+
+ /* otherwise use IO capability to select association model */
+ if (p_cb->peer_io_caps < SMP_IO_CAP_MAX &&
+ p_cb->local_io_capability < SMP_IO_CAP_MAX) {
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ model = smp_association_table_sc[p_cb->role][p_cb->peer_io_caps]
+ [p_cb->local_io_capability];
+ } else {
+ model = smp_association_table_sc[p_cb->role][p_cb->local_io_capability]
+ [p_cb->peer_io_caps];
+ }
+ }
+
+ return model;
+}
+
+/*******************************************************************************
+ * Function smp_reverse_array
+ *
+ * Description This function reverses array bytes
+ *
+ ******************************************************************************/
+void smp_reverse_array(uint8_t* arr, uint8_t len) {
+ uint8_t i = 0, tmp;
+
+ SMP_TRACE_DEBUG("smp_reverse_array");
+
+ for (i = 0; i < len / 2; i++) {
+ tmp = arr[i];
+ arr[i] = arr[len - 1 - i];
+ arr[len - 1 - i] = tmp;
+ }
+}
+
+/*******************************************************************************
+ * Function smp_calculate_random_input
+ *
+ * Description This function returns random input value to be used in
+ * commitment calculation for SC passkey entry association mode
+ * (if bit["round"] in "random" array == 1 then returns 0x81
+ * else returns 0x80).
+ *
+ * Returns ri value
+ *
+ ******************************************************************************/
+uint8_t smp_calculate_random_input(uint8_t* random, uint8_t round) {
+ uint8_t i = round / 8;
+ uint8_t j = round % 8;
+ uint8_t ri;
+
+ SMP_TRACE_DEBUG("random: 0x%02x, round: %d, i: %d, j: %d", random[i], round,
+ i, j);
+ ri = ((random[i] >> j) & 1) | 0x80;
+ SMP_TRACE_DEBUG("%s ri=0x%02x", __func__, ri);
+ return ri;
+}
+
+/*******************************************************************************
+ * Function smp_collect_local_io_capabilities
+ *
+ * Description This function puts into IOcap array local device
+ * IOCapability, OOB data, AuthReq.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_collect_local_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ iocap[0] = p_cb->local_io_capability;
+ iocap[1] = p_cb->loc_oob_flag;
+ iocap[2] = p_cb->loc_auth_req;
+}
+
+/*******************************************************************************
+ * Function smp_collect_peer_io_capabilities
+ *
+ * Description This function puts into IOcap array peer device
+ * IOCapability, OOB data, AuthReq.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_collect_peer_io_capabilities(uint8_t* iocap, tSMP_CB* p_cb) {
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ iocap[0] = p_cb->peer_io_caps;
+ iocap[1] = p_cb->peer_oob_flag;
+ iocap[2] = p_cb->peer_auth_req;
+}
+
+/*******************************************************************************
+ * Function smp_collect_local_ble_address
+ *
+ * Description Put the the local device LE address into the le_addr array:
+ * le_addr[0-5] = local BD ADDR,
+ * le_addr[6] = local le address type (PUBLIC/RANDOM).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_collect_local_ble_address(uint8_t* le_addr, tSMP_CB* p_cb) {
+ tBLE_ADDR_TYPE addr_type = 0;
+ BD_ADDR bda;
+ uint8_t* p = le_addr;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ BTM_ReadConnectionAddr(p_cb->pairing_bda, bda, &addr_type);
+ BDADDR_TO_STREAM(p, bda);
+ UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+ * Function smp_collect_peer_ble_address
+ *
+ * Description Put the peer device LE addr into the le_addr array:
+ * le_addr[0-5] = peer BD ADDR,
+ * le_addr[6] = peer le address type (PUBLIC/RANDOM).
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_collect_peer_ble_address(uint8_t* le_addr, tSMP_CB* p_cb) {
+ tBLE_ADDR_TYPE addr_type = 0;
+ BD_ADDR bda;
+ uint8_t* p = le_addr;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (!BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda, &addr_type)) {
+ SMP_TRACE_ERROR(
+ "can not collect peer le addr information for unknown device");
+ return;
+ }
+
+ BDADDR_TO_STREAM(p, bda);
+ UINT8_TO_STREAM(p, addr_type);
+}
+
+/*******************************************************************************
+ * Function smp_check_commitment
+ *
+ * Description This function compares peer commitment values:
+ * - expected (i.e. calculated locally),
+ * - received from the peer.
+ *
+ * Returns true if the values are the same
+ * false otherwise
+ *
+ ******************************************************************************/
+bool smp_check_commitment(tSMP_CB* p_cb) {
+ BT_OCTET16 expected;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ smp_calculate_peer_commitment(p_cb, expected);
+ print128(expected, (const uint8_t*)"calculated peer commitment");
+ print128(p_cb->remote_commitment, (const uint8_t*)"received peer commitment");
+
+ if (memcmp(p_cb->remote_commitment, expected, BT_OCTET16_LEN)) {
+ SMP_TRACE_WARNING("%s: Commitment check fails", __func__);
+ return false;
+ }
+
+ SMP_TRACE_DEBUG("%s: Commitment check succeeds", __func__);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_save_secure_connections_long_term_key
+ *
+ * Description The function saves SC LTK as BLE key for future use as local
+ * and/or peer key.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void smp_save_secure_connections_long_term_key(tSMP_CB* p_cb) {
+ tBTM_LE_LENC_KEYS lle_key;
+ tBTM_LE_PENC_KEYS ple_key;
+
+ SMP_TRACE_DEBUG("%s-Save LTK as local LTK key", __func__);
+ memcpy(lle_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ lle_key.div = 0;
+ lle_key.key_size = p_cb->loc_enc_size;
+ lle_key.sec_level = p_cb->sec_level;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_LENC,
+ (tBTM_LE_KEY_VALUE*)&lle_key, true);
+
+ SMP_TRACE_DEBUG("%s-Save LTK as peer LTK key", __func__);
+ ple_key.ediv = 0;
+ memset(ple_key.rand, 0, BT_OCTET8_LEN);
+ memcpy(ple_key.ltk, p_cb->ltk, BT_OCTET16_LEN);
+ ple_key.sec_level = p_cb->sec_level;
+ ple_key.key_size = p_cb->loc_enc_size;
+ btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PENC,
+ (tBTM_LE_KEY_VALUE*)&ple_key, true);
+}
+
+/*******************************************************************************
+ *
+ * Function smp_calculate_f5_mackey_and_long_term_key
+ *
+ * Description The function calculates MacKey and LTK and saves them in CB.
+ * To calculate MacKey and LTK it calls smp_calc_f5(...).
+ * MacKey is used in dhkey calculation, LTK is used to encrypt
+ * the link.
+ *
+ * Returns false if out of resources, true otherwise.
+ *
+ ******************************************************************************/
+bool smp_calculate_f5_mackey_and_long_term_key(tSMP_CB* p_cb) {
+ uint8_t a[7];
+ uint8_t b[7];
+ uint8_t* p_na;
+ uint8_t* p_nb;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->role == HCI_ROLE_MASTER) {
+ smp_collect_local_ble_address(a, p_cb);
+ smp_collect_peer_ble_address(b, p_cb);
+ p_na = p_cb->rand;
+ p_nb = p_cb->rrand;
+ } else {
+ smp_collect_local_ble_address(b, p_cb);
+ smp_collect_peer_ble_address(a, p_cb);
+ p_na = p_cb->rrand;
+ p_nb = p_cb->rand;
+ }
+
+ if (!smp_calculate_f5(p_cb->dhkey, p_na, p_nb, a, b, p_cb->mac_key,
+ p_cb->ltk)) {
+ SMP_TRACE_ERROR("%s failed", __func__);
+ return false;
+ }
+
+ SMP_TRACE_EVENT("%s is completed", __func__);
+ return true;
+}
+
+/*******************************************************************************
+ *
+ * Function smp_request_oob_data
+ *
+ * Description Requests application to provide OOB data.
+ *
+ * Returns true - OOB data has to be provided by application
+ * false - otherwise (unexpected)
+ *
+ ******************************************************************************/
+bool smp_request_oob_data(tSMP_CB* p_cb) {
+ tSMP_OOB_DATA_TYPE req_oob_type = SMP_OOB_INVALID_TYPE;
+
+ SMP_TRACE_DEBUG("%s", __func__);
+
+ if (p_cb->peer_oob_flag == SMP_OOB_PRESENT &&
+ p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ /* both local and peer rcvd data OOB */
+ req_oob_type = SMP_OOB_BOTH;
+ } else if (p_cb->peer_oob_flag == SMP_OOB_PRESENT) {
+ /* peer rcvd OOB local data, local didn't receive OOB peer data */
+ req_oob_type = SMP_OOB_LOCAL;
+ } else if (p_cb->loc_oob_flag == SMP_OOB_PRESENT) {
+ req_oob_type = SMP_OOB_PEER;
+ }
+
+ SMP_TRACE_DEBUG("req_oob_type = %d", req_oob_type);
+
+ if (req_oob_type == SMP_OOB_INVALID_TYPE) return false;
+
+ p_cb->req_oob_type = req_oob_type;
+ p_cb->cb_evt = SMP_SC_OOB_REQ_EVT;
+ smp_sm_event(p_cb, SMP_TK_REQ_EVT, &req_oob_type);
+
+ return true;
+}
diff --git a/mtkbt/code/bt/stack/srvc/srvc_battery.cc b/mtkbt/code/bt/stack/srvc/srvc_battery.cc
new file mode 100755
index 0000000..7600f9d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_battery.cc
@@ -0,0 +1,362 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btcore/include/uuid.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/osi.h"
+#include "srvc_battery_int.h"
+#include "srvc_eng_int.h"
+
+#define BA_MAX_CHAR_NUM 1
+
+/* max 3 descriptors, 1 desclration and 1 value */
+#define BA_MAX_ATTR_NUM (BA_MAX_CHAR_NUM * 5 + 1)
+
+#ifndef BATTER_LEVEL_PROP
+#define BATTER_LEVEL_PROP (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY)
+#endif
+
+#ifndef BATTER_LEVEL_PERM
+#define BATTER_LEVEL_PERM (GATT_PERM_READ)
+#endif
+
+tBATTERY_CB battery_cb;
+
+/*******************************************************************************
+ * battery_valid_handle_range
+ *
+ * validate a handle to be a DIS attribute handle or not.
+ ******************************************************************************/
+bool battery_valid_handle_range(uint16_t handle) {
+ uint8_t i = 0;
+ tBA_INST* p_inst = &battery_cb.battery_inst[0];
+
+ for (; i < BA_MAX_INT_NUM; i++, p_inst++) {
+ if (handle == p_inst->ba_level_hdl || handle == p_inst->clt_cfg_hdl ||
+ handle == p_inst->rpt_ref_hdl || handle == p_inst->pres_fmt_hdl) {
+ return true;
+ }
+ }
+ return false;
+}
+/*******************************************************************************
+ * battery_s_write_attr_value
+ *
+ * Process write DIS attribute request.
+ ******************************************************************************/
+uint8_t battery_s_write_attr_value(uint8_t clcb_idx, tGATT_WRITE_REQ* p_value,
+ tGATT_STATUS* p_status) {
+ uint8_t *p = p_value->value, i;
+ uint16_t handle = p_value->handle;
+ tBA_INST* p_inst = &battery_cb.battery_inst[0];
+ tGATT_STATUS st = GATT_NOT_FOUND;
+ tBA_WRITE_DATA cfg;
+ uint8_t act = SRVC_ACT_RSP;
+
+ for (i = 0; i < BA_MAX_INT_NUM; i++, p_inst++) {
+ /* read battery level */
+ if (handle == p_inst->clt_cfg_hdl) {
+ memcpy(cfg.remote_bda, srvc_eng_cb.clcb[clcb_idx].bda, BD_ADDR_LEN);
+ STREAM_TO_UINT16(cfg.clt_cfg, p);
+
+ if (p_inst->p_cback) {
+ p_inst->pending_clcb_idx = clcb_idx;
+ p_inst->pending_evt = BA_WRITE_CLT_CFG_REQ;
+ p_inst->pending_handle = handle;
+ cfg.need_rsp = p_value->need_rsp;
+ act = SRVC_ACT_PENDING;
+
+ (*p_inst->p_cback)(p_inst->app_id, BA_WRITE_CLT_CFG_REQ, &cfg);
+ }
+ } else /* all other handle is not writable */
+ {
+ st = GATT_WRITE_NOT_PERMIT;
+ break;
+ }
+ }
+ *p_status = st;
+
+ return act;
+}
+/*******************************************************************************
+ * BA Attributes Database Server Request callback
+ ******************************************************************************/
+uint8_t battery_s_read_attr_value(uint8_t clcb_idx, uint16_t handle,
+ UNUSED_ATTR tGATT_VALUE* p_value,
+ bool is_long, tGATT_STATUS* p_status) {
+ uint8_t i;
+ tBA_INST* p_inst = &battery_cb.battery_inst[0];
+ tGATT_STATUS st = GATT_NOT_FOUND;
+ uint8_t act = SRVC_ACT_RSP;
+
+ for (i = 0; i < BA_MAX_INT_NUM; i++, p_inst++) {
+ /* read battery level */
+ if (handle == p_inst->ba_level_hdl || handle == p_inst->clt_cfg_hdl ||
+ handle == p_inst->rpt_ref_hdl || handle == p_inst->pres_fmt_hdl) {
+ if (is_long) st = GATT_NOT_LONG;
+
+ if (p_inst->p_cback) {
+ if (handle == p_inst->ba_level_hdl)
+ p_inst->pending_evt = BA_READ_LEVEL_REQ;
+ if (handle == p_inst->clt_cfg_hdl)
+ p_inst->pending_evt = BA_READ_CLT_CFG_REQ;
+ if (handle == p_inst->pres_fmt_hdl)
+ p_inst->pending_evt = BA_READ_PRE_FMT_REQ;
+ if (handle == p_inst->rpt_ref_hdl)
+ p_inst->pending_evt = BA_READ_RPT_REF_REQ;
+
+ p_inst->pending_clcb_idx = clcb_idx;
+ p_inst->pending_handle = handle;
+ act = SRVC_ACT_PENDING;
+
+ (*p_inst->p_cback)(p_inst->app_id, p_inst->pending_evt, NULL);
+ } else /* application is not registered */
+ st = GATT_ERR_UNLIKELY;
+ break;
+ }
+ /* else attribute not found */
+ }
+
+ *p_status = st;
+ return act;
+}
+
+/*******************************************************************************
+ *
+ * Function battery_gatt_c_read_ba_req
+ *
+ * Description Read remote device BA level attribute request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool battery_gatt_c_read_ba_req(UNUSED_ATTR uint16_t conn_id) { return true; }
+
+/*******************************************************************************
+ *
+ * Function battery_c_cmpl_cback
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void battery_c_cmpl_cback(UNUSED_ATTR tSRVC_CLCB* p_clcb,
+ UNUSED_ATTR tGATTC_OPTYPE op,
+ UNUSED_ATTR tGATT_STATUS status,
+ UNUSED_ATTR tGATT_CL_COMPLETE* p_data) {}
+
+/*******************************************************************************
+ *
+ * Function Battery_Instantiate
+ *
+ * Description Instantiate a Battery service
+ *
+ ******************************************************************************/
+uint16_t Battery_Instantiate(uint8_t app_id, tBA_REG_INFO* p_reg_info) {
+ uint16_t srvc_hdl = 0;
+ tGATT_STATUS status = GATT_ERROR;
+ tBA_INST* p_inst;
+
+ if (battery_cb.inst_id == BA_MAX_INT_NUM) {
+ GATT_TRACE_ERROR("MAX battery service has been reached");
+ return 0;
+ }
+
+ p_inst = &battery_cb.battery_inst[battery_cb.inst_id];
+
+ btgatt_db_element_t service[BA_MAX_ATTR_NUM] = {};
+
+ bt_uuid_t service_uuid;
+ uuid_128_from_16(&service_uuid, UUID_SERVCLASS_BATTERY);
+ service[0].type = /* p_reg_info->is_pri */ BTGATT_DB_PRIMARY_SERVICE;
+ service[0].uuid = service_uuid;
+
+ bt_uuid_t char_uuid;
+ uuid_128_from_16(&char_uuid, GATT_UUID_BATTERY_LEVEL);
+ service[1].type = BTGATT_DB_CHARACTERISTIC;
+ service[1].uuid = char_uuid;
+ service[1].properties = GATT_CHAR_PROP_BIT_READ;
+ if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY)
+ service[1].properties |= GATT_CHAR_PROP_BIT_NOTIFY;
+
+ int i = 2;
+ if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
+ bt_uuid_t desc_uuid;
+ uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_CLIENT_CONFIG);
+
+ service[i].type = BTGATT_DB_DESCRIPTOR;
+ service[i].uuid = desc_uuid;
+ service[i].permissions = (GATT_PERM_READ | GATT_PERM_WRITE);
+ i++;
+ }
+
+ /* need presentation format descriptor? */
+ if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
+ bt_uuid_t desc_uuid;
+ uuid_128_from_16(&desc_uuid, GATT_UUID_CHAR_PRESENT_FORMAT);
+
+ service[i].type = BTGATT_DB_DESCRIPTOR;
+ service[i].uuid = desc_uuid;
+ service[i].permissions = GATT_PERM_READ;
+ i++;
+ }
+
+ /* need presentation format descriptor? */
+ if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
+ bt_uuid_t desc_uuid;
+ uuid_128_from_16(&desc_uuid, GATT_UUID_RPT_REF_DESCR);
+
+ service[i].type = BTGATT_DB_DESCRIPTOR;
+ service[i].uuid = desc_uuid;
+ service[i].permissions = GATT_PERM_READ;
+ i++;
+ }
+
+ GATTS_AddService(srvc_eng_cb.gatt_if, service, i);
+
+ if (status != GATT_SUCCESS) {
+ battery_cb.inst_id--;
+ GATT_TRACE_ERROR("%s: Failed to add battery servuce!", __func__);
+ }
+
+ battery_cb.inst_id++;
+
+ p_inst->app_id = app_id;
+ p_inst->p_cback = p_reg_info->p_cback;
+
+ srvc_hdl = service[0].attribute_handle;
+ p_inst->ba_level_hdl = service[1].attribute_handle;
+
+ i = 2;
+ if (p_reg_info->ba_level_descr & BA_LEVEL_NOTIFY) {
+ p_inst->clt_cfg_hdl = service[i].attribute_handle;
+ i++;
+ }
+
+ if (p_reg_info->ba_level_descr & BA_LEVEL_PRE_FMT) {
+ p_inst->pres_fmt_hdl = service[i].attribute_handle;
+ i++;
+ }
+
+ if (p_reg_info->ba_level_descr & BA_LEVEL_RPT_REF) {
+ p_inst->rpt_ref_hdl = service[i].attribute_handle;
+ i++;
+ }
+
+ return srvc_hdl;
+}
+/*******************************************************************************
+ *
+ * Function Battery_Rsp
+ *
+ * Description Respond to a battery service request
+ *
+ ******************************************************************************/
+void Battery_Rsp(uint8_t app_id, tGATT_STATUS st, uint8_t event,
+ tBA_RSP_DATA* p_rsp) {
+ tBA_INST* p_inst = &battery_cb.battery_inst[0];
+ tGATTS_RSP rsp;
+ uint8_t* pp;
+
+ uint8_t i = 0;
+ while (i < BA_MAX_INT_NUM) {
+ if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) break;
+ i++;
+ }
+
+ if (i == BA_MAX_INT_NUM) return;
+
+ memset(&rsp, 0, sizeof(tGATTS_RSP));
+
+ if (p_inst->pending_evt == event) {
+ switch (event) {
+ case BA_READ_CLT_CFG_REQ:
+ rsp.attr_value.handle = p_inst->pending_handle;
+ rsp.attr_value.len = 2;
+ pp = rsp.attr_value.value;
+ UINT16_TO_STREAM(pp, p_rsp->clt_cfg);
+ srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+ break;
+
+ case BA_READ_LEVEL_REQ:
+ rsp.attr_value.handle = p_inst->pending_handle;
+ rsp.attr_value.len = 1;
+ pp = rsp.attr_value.value;
+ UINT8_TO_STREAM(pp, p_rsp->ba_level);
+ srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+ break;
+
+ case BA_WRITE_CLT_CFG_REQ:
+ srvc_sr_rsp(p_inst->pending_clcb_idx, st, NULL);
+ break;
+
+ case BA_READ_RPT_REF_REQ:
+ rsp.attr_value.handle = p_inst->pending_handle;
+ rsp.attr_value.len = 2;
+ pp = rsp.attr_value.value;
+ UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_id);
+ UINT8_TO_STREAM(pp, p_rsp->rpt_ref.rpt_type);
+ srvc_sr_rsp(p_inst->pending_clcb_idx, st, &rsp);
+ break;
+
+ default:
+ break;
+ }
+ p_inst->pending_clcb_idx = 0;
+ p_inst->pending_evt = 0;
+ p_inst->pending_handle = 0;
+ }
+ return;
+}
+/*******************************************************************************
+ *
+ * Function Battery_Notify
+ *
+ * Description Send battery level notification
+ *
+ ******************************************************************************/
+void Battery_Notify(uint8_t app_id, BD_ADDR remote_bda, uint8_t battery_level) {
+ tBA_INST* p_inst = &battery_cb.battery_inst[0];
+ uint8_t i = 0;
+
+ while (i < BA_MAX_INT_NUM) {
+ if (p_inst->app_id == app_id && p_inst->ba_level_hdl != 0) break;
+ i++;
+ }
+
+ if (i == BA_MAX_INT_NUM || p_inst->clt_cfg_hdl == 0) return;
+
+ srvc_sr_notify(remote_bda, p_inst->ba_level_hdl, 1, &battery_level);
+}
+/*******************************************************************************
+ *
+ * Function Battery_ReadBatteryLevel
+ *
+ * Description Read remote device Battery Level information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool Battery_ReadBatteryLevel(UNUSED_ATTR BD_ADDR peer_bda) {
+ /* to be implemented */
+ return true;
+}
diff --git a/mtkbt/code/bt/stack/srvc/srvc_battery_int.h b/mtkbt/code/bt/stack/srvc/srvc_battery_int.h
new file mode 100755
index 0000000..fc191e8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_battery_int.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_BATTERY_INT_H
+#define SRVC_BATTERY_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+
+#ifndef BA_MAX_INT_NUM
+#define BA_MAX_INT_NUM 4
+#endif
+
+#define BATTERY_LEVEL_SIZE 1
+
+typedef struct {
+ uint8_t app_id;
+ uint16_t ba_level_hdl;
+ uint16_t clt_cfg_hdl;
+ uint16_t rpt_ref_hdl;
+ uint16_t pres_fmt_hdl;
+
+ tBA_CBACK* p_cback;
+
+ uint16_t pending_handle;
+ uint8_t pending_clcb_idx;
+ uint8_t pending_evt;
+
+} tBA_INST;
+
+typedef struct {
+ tBA_INST battery_inst[BA_MAX_INT_NUM];
+ uint8_t inst_id;
+ bool enabled;
+
+} tBATTERY_CB;
+
+/* Global GATT data */
+extern tBATTERY_CB battery_cb;
+
+extern bool battery_valid_handle_range(uint16_t handle);
+
+extern uint8_t battery_s_write_attr_value(uint8_t clcb_idx,
+ tGATT_WRITE_REQ* p_value,
+ tGATT_STATUS* p_status);
+extern uint8_t battery_s_read_attr_value(uint8_t clcb_idx, uint16_t handle,
+ tGATT_VALUE* p_value, bool is_long,
+ tGATT_STATUS* p_status);
+
+#endif
diff --git a/mtkbt/code/bt/stack/srvc/srvc_dis.cc b/mtkbt/code/bt/stack/srvc/srvc_dis.cc
new file mode 100755
index 0000000..b149c3f
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_dis.cc
@@ -0,0 +1,476 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_srvc"
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "btcore/include/uuid.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "srvc_dis_int.h"
+#include "srvc_eng_int.h"
+
+#define DIS_MAX_NUM_INC_SVR 0
+#define DIS_MAX_CHAR_NUM 9
+#define DIS_MAX_ATTR_NUM (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1)
+
+#ifndef DIS_ATTR_DB_SIZE
+#define DIS_ATTR_DB_SIZE \
+ GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0)
+#endif
+
+#define uint64_t_TO_STREAM(p, u64) \
+ { \
+ *(p)++ = (uint8_t)(u64); \
+ *(p)++ = (uint8_t)((u64) >> 8); \
+ *(p)++ = (uint8_t)((u64) >> 16); \
+ *(p)++ = (uint8_t)((u64) >> 24); \
+ *(p)++ = (uint8_t)((u64) >> 32); \
+ *(p)++ = (uint8_t)((u64) >> 40); \
+ *(p)++ = (uint8_t)((u64) >> 48); \
+ *(p)++ = (uint8_t)((u64) >> 56); \
+ }
+
+#define STREAM_TO_UINT64(u64, p) \
+ { \
+ (u64) = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + \
+ ((((uint64_t)(*((p) + 2)))) << 16) + \
+ ((((uint64_t)(*((p) + 3)))) << 24) + \
+ ((((uint64_t)(*((p) + 4)))) << 32) + \
+ ((((uint64_t)(*((p) + 5)))) << 40) + \
+ ((((uint64_t)(*((p) + 6)))) << 48) + \
+ ((((uint64_t)(*((p) + 7)))) << 56)); \
+ (p) += 8; \
+ }
+
+static const uint16_t dis_attr_uuid[DIS_MAX_CHAR_NUM] = {
+ GATT_UUID_SYSTEM_ID,
+ GATT_UUID_MODEL_NUMBER_STR,
+ GATT_UUID_SERIAL_NUMBER_STR,
+ GATT_UUID_FW_VERSION_STR,
+ GATT_UUID_HW_VERSION_STR,
+ GATT_UUID_SW_VERSION_STR,
+ GATT_UUID_MANU_NAME,
+ GATT_UUID_IEEE_DATA,
+ GATT_UUID_PNP_ID};
+
+tDIS_CB dis_cb;
+
+static tDIS_ATTR_MASK dis_uuid_to_attr(uint16_t uuid) {
+ switch (uuid) {
+ case GATT_UUID_SYSTEM_ID:
+ return DIS_ATTR_SYS_ID_BIT;
+ case GATT_UUID_MODEL_NUMBER_STR:
+ return DIS_ATTR_MODEL_NUM_BIT;
+ case GATT_UUID_SERIAL_NUMBER_STR:
+ return DIS_ATTR_SERIAL_NUM_BIT;
+ case GATT_UUID_FW_VERSION_STR:
+ return DIS_ATTR_FW_NUM_BIT;
+ case GATT_UUID_HW_VERSION_STR:
+ return DIS_ATTR_HW_NUM_BIT;
+ case GATT_UUID_SW_VERSION_STR:
+ return DIS_ATTR_SW_NUM_BIT;
+ case GATT_UUID_MANU_NAME:
+ return DIS_ATTR_MANU_NAME_BIT;
+ case GATT_UUID_IEEE_DATA:
+ return DIS_ATTR_IEEE_DATA_BIT;
+ case GATT_UUID_PNP_ID:
+ return DIS_ATTR_PNP_ID_BIT;
+ default:
+ return 0;
+ };
+}
+
+/*******************************************************************************
+ * dis_valid_handle_range
+ *
+ * validate a handle to be a DIS attribute handle or not.
+ ******************************************************************************/
+bool dis_valid_handle_range(uint16_t handle) {
+ if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle)
+ return true;
+ else
+ return false;
+}
+/*******************************************************************************
+ * dis_write_attr_value
+ *
+ * Process write DIS attribute request.
+ ******************************************************************************/
+uint8_t dis_write_attr_value(UNUSED_ATTR tGATT_WRITE_REQ* p_data,
+ tGATT_STATUS* p_status) {
+ *p_status = GATT_WRITE_NOT_PERMIT;
+ return SRVC_ACT_RSP;
+}
+/*******************************************************************************
+ * DIS Attributes Database Server Request callback
+ ******************************************************************************/
+uint8_t dis_read_attr_value(UNUSED_ATTR uint8_t clcb_idx, uint16_t handle,
+ tGATT_VALUE* p_value, bool is_long,
+ tGATT_STATUS* p_status) {
+ tDIS_DB_ENTRY* p_db_attr = dis_cb.dis_attr;
+ uint8_t *p = p_value->value, i, *pp;
+ uint16_t offset = p_value->offset;
+ uint8_t act = SRVC_ACT_RSP;
+ tGATT_STATUS st = GATT_NOT_FOUND;
+
+ for (i = 0; i < DIS_MAX_CHAR_NUM; i++, p_db_attr++) {
+ if (handle == p_db_attr->handle) {
+ if ((p_db_attr->uuid == GATT_UUID_PNP_ID ||
+ p_db_attr->uuid == GATT_UUID_SYSTEM_ID) &&
+ is_long == true) {
+ st = GATT_NOT_LONG;
+ break;
+ }
+ st = GATT_SUCCESS;
+
+ switch (p_db_attr->uuid) {
+ case GATT_UUID_MANU_NAME:
+ case GATT_UUID_MODEL_NUMBER_STR:
+ case GATT_UUID_SERIAL_NUMBER_STR:
+ case GATT_UUID_FW_VERSION_STR:
+ case GATT_UUID_HW_VERSION_STR:
+ case GATT_UUID_SW_VERSION_STR:
+ case GATT_UUID_IEEE_DATA:
+ pp = dis_cb.dis_value
+ .data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR];
+ if (pp != NULL) {
+ if (strlen((char*)pp) > GATT_MAX_ATTR_LEN)
+ p_value->len = GATT_MAX_ATTR_LEN;
+ else
+ p_value->len = (uint16_t)strlen((char*)pp);
+ } else
+ p_value->len = 0;
+
+ if (offset > p_value->len) {
+ st = GATT_INVALID_OFFSET;
+ break;
+ } else {
+ p_value->len -= offset;
+ pp += offset;
+ ARRAY_TO_STREAM(p, pp, p_value->len);
+ GATT_TRACE_EVENT("GATT_UUID_MANU_NAME len=0x%04x", p_value->len);
+ }
+ break;
+
+ case GATT_UUID_SYSTEM_ID:
+ uint64_t_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
+ p_value->len = DIS_SYSTEM_ID_SIZE;
+ break;
+
+ case GATT_UUID_PNP_ID:
+ UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src);
+ UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id);
+ UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id);
+ UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version);
+ p_value->len = DIS_PNP_ID_SIZE;
+ break;
+ }
+ break;
+ }
+ }
+ *p_status = st;
+ return act;
+}
+
+/*******************************************************************************
+ *
+ * Function dis_gatt_c_read_dis_value_cmpl
+ *
+ * Description Client read DIS database complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void dis_gatt_c_read_dis_value_cmpl(uint16_t conn_id) {
+ tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+ dis_cb.dis_read_uuid_idx = 0xff;
+
+ srvc_eng_release_channel(conn_id);
+
+ if (dis_cb.p_read_dis_cback && p_clcb) {
+ LOG_INFO(LOG_TAG, "%s conn_id:%d attr_mask = 0x%04x", __func__, conn_id,
+ p_clcb->dis_value.attr_mask);
+
+ (*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
+ dis_cb.p_read_dis_cback = NULL;
+ }
+}
+
+/*******************************************************************************
+ *
+ * Function dis_gatt_c_read_dis_req
+ *
+ * Description Read remote device DIS attribute request.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool dis_gatt_c_read_dis_req(uint16_t conn_id) {
+ tGATT_READ_PARAM param;
+
+ memset(&param, 0, sizeof(tGATT_READ_PARAM));
+
+ param.service.uuid.len = LEN_UUID_16;
+ param.service.s_handle = 1;
+ param.service.e_handle = 0xFFFF;
+ param.service.auth_req = 0;
+
+ while (dis_cb.dis_read_uuid_idx < DIS_MAX_CHAR_NUM) {
+ if (dis_uuid_to_attr(dis_attr_uuid[dis_cb.dis_read_uuid_idx]) &
+ dis_cb.request_mask) {
+ param.service.uuid.uu.uuid16 = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+
+ if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
+ return true;
+
+ GATT_TRACE_ERROR("Read DISInfo: 0x%04x GATT_Read Failed",
+ param.service.uuid.uu.uuid16);
+ }
+
+ dis_cb.dis_read_uuid_idx++;
+ }
+
+ dis_gatt_c_read_dis_value_cmpl(conn_id);
+
+ return (false);
+}
+
+/*******************************************************************************
+ *
+ * Function dis_c_cmpl_cback
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op, tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ uint16_t read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
+ uint8_t *pp = NULL, *p_str;
+ uint16_t conn_id = p_clcb->conn_id;
+
+ GATT_TRACE_EVENT(
+ "dis_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x \
+ read_type: 0x%04x",
+ op, status, read_type);
+
+ if (op != GATTC_OPTYPE_READ) return;
+
+ if (p_data != NULL && status == GATT_SUCCESS) {
+ pp = p_data->att_value.value;
+
+ switch (read_type) {
+ case GATT_UUID_SYSTEM_ID:
+ GATT_TRACE_EVENT("DIS_ATTR_SYS_ID_BIT");
+ if (p_data->att_value.len == DIS_SYSTEM_ID_SIZE) {
+ p_clcb->dis_value.attr_mask |= DIS_ATTR_SYS_ID_BIT;
+ /* save system ID*/
+ STREAM_TO_UINT64(p_clcb->dis_value.system_id, pp);
+ }
+ break;
+
+ case GATT_UUID_PNP_ID:
+ if (p_data->att_value.len == DIS_PNP_ID_SIZE) {
+ p_clcb->dis_value.attr_mask |= DIS_ATTR_PNP_ID_BIT;
+ STREAM_TO_UINT8(p_clcb->dis_value.pnp_id.vendor_id_src, pp);
+ STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.vendor_id, pp);
+ STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_id, pp);
+ STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_version, pp);
+ }
+ break;
+
+ case GATT_UUID_MODEL_NUMBER_STR:
+ case GATT_UUID_SERIAL_NUMBER_STR:
+ case GATT_UUID_FW_VERSION_STR:
+ case GATT_UUID_HW_VERSION_STR:
+ case GATT_UUID_SW_VERSION_STR:
+ case GATT_UUID_MANU_NAME:
+ case GATT_UUID_IEEE_DATA:
+ p_str = p_clcb->dis_value
+ .data_string[read_type - GATT_UUID_MODEL_NUMBER_STR];
+ osi_free(p_str);
+ p_str = (uint8_t*)osi_malloc(p_data->att_value.len + 1);
+ p_clcb->dis_value.attr_mask |= dis_uuid_to_attr(read_type);
+ memcpy(p_str, p_data->att_value.value, p_data->att_value.len);
+ p_str[p_data->att_value.len] = 0;
+ p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR] =
+ p_str;
+ break;
+
+ default:
+ break;
+
+ break;
+ } /* end switch */
+ } /* end if */
+
+ dis_cb.dis_read_uuid_idx++;
+
+ dis_gatt_c_read_dis_req(conn_id);
+}
+
+/*******************************************************************************
+ *
+ * Function DIS_SrInit
+ *
+ * Description Initialize the Device Information Service Server.
+ *
+ ******************************************************************************/
+tDIS_STATUS DIS_SrInit(tDIS_ATTR_MASK dis_attr_mask) {
+ tGATT_STATUS status;
+
+ if (dis_cb.enabled) {
+ GATT_TRACE_ERROR("DIS already initalized");
+ return DIS_SUCCESS;
+ }
+
+ memset(&dis_cb, 0, sizeof(tDIS_CB));
+
+ btgatt_db_element_t service[DIS_MAX_ATTR_NUM] = {};
+
+ bt_uuid_t svc_uuid;
+ uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_DEVICE_INFO);
+ service[0].type = BTGATT_DB_PRIMARY_SERVICE;
+ service[0].uuid = svc_uuid;
+
+ for (int i = 0; dis_attr_mask != 0 && i < DIS_MAX_CHAR_NUM; i++) {
+ dis_cb.dis_attr[i].uuid = dis_attr_uuid[i];
+
+ bt_uuid_t char_uuid;
+ uuid_128_from_16(&char_uuid, dis_cb.dis_attr[i].uuid);
+ /* index 0 is service, so characteristics start from 1 */
+ service[i + 1].type = BTGATT_DB_CHARACTERISTIC;
+ service[i + 1].uuid = char_uuid;
+ service[i + 1].properties = GATT_CHAR_PROP_BIT_READ;
+ service[i + 1].permissions = GATT_PERM_READ;
+
+ dis_attr_mask >>= 1;
+ }
+
+ /* Add a GAP service */
+ status = GATTS_AddService(srvc_eng_cb.gatt_if, service,
+ sizeof(service) / sizeof(btgatt_db_element_t));
+ if (status != GATT_SERVICE_STARTED) {
+ GATT_TRACE_ERROR("Can not create service, DIS_Init failed!");
+ return GATT_ERROR;
+ }
+
+ dis_cb.service_handle = service[0].attribute_handle;
+ dis_cb.max_handle = dis_cb.service_handle + DIS_MAX_ATTR_NUM;
+
+ for (int i = 0; i < DIS_MAX_CHAR_NUM; i++) {
+ dis_cb.dis_attr[i].handle = service[i + 1].attribute_handle;
+
+ GATT_TRACE_DEBUG("%s: handle of new attribute 0x%04 = x%d", __func__,
+ dis_cb.dis_attr[i].uuid, dis_cb.dis_attr[i].handle);
+ }
+
+ dis_cb.enabled = true;
+ return (tDIS_STATUS)status;
+}
+/*******************************************************************************
+ *
+ * Function DIS_SrUpdate
+ *
+ * Description Update the DIS server attribute values
+ *
+ ******************************************************************************/
+tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR* p_info) {
+ uint8_t i = 1;
+ tDIS_STATUS st = DIS_SUCCESS;
+
+ if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT) {
+ dis_cb.dis_value.system_id = p_info->system_id;
+ } else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT) {
+ dis_cb.dis_value.pnp_id.vendor_id = p_info->pnp_id.vendor_id;
+ dis_cb.dis_value.pnp_id.vendor_id_src = p_info->pnp_id.vendor_id_src;
+ dis_cb.dis_value.pnp_id.product_id = p_info->pnp_id.product_id;
+ dis_cb.dis_value.pnp_id.product_version = p_info->pnp_id.product_version;
+ } else {
+ st = DIS_ILLEGAL_PARAM;
+
+ while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM - 1)) {
+ if (dis_attr_bit & (uint16_t)(1 << i)) {
+ osi_free(dis_cb.dis_value.data_string[i - 1]);
+ dis_cb.dis_value.data_string[i - 1] =
+ (uint8_t*)osi_malloc(p_info->data_str.len + 1);
+ memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data,
+ p_info->data_str.len);
+ dis_cb.dis_value.data_string[i - 1][p_info->data_str.len] =
+ 0; /* make sure null terminate */
+ st = DIS_SUCCESS;
+
+ break;
+ }
+ i++;
+ }
+ }
+ return st;
+}
+/*******************************************************************************
+ *
+ * Function DIS_ReadDISInfo
+ *
+ * Description Read remote device DIS information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool DIS_ReadDISInfo(BD_ADDR peer_bda, tDIS_READ_CBACK* p_cback,
+ tDIS_ATTR_MASK mask) {
+ uint16_t conn_id;
+
+ /* Initialize the DIS client if it hasn't been initialized already. */
+ srvc_eng_init();
+
+ /* For now we only handle one at a time */
+ if (dis_cb.dis_read_uuid_idx != 0xff) return (false);
+
+ if (p_cback == NULL) return (false);
+
+ dis_cb.p_read_dis_cback = p_cback;
+ /* Mark currently active operation */
+ dis_cb.dis_read_uuid_idx = 0;
+
+ dis_cb.request_mask = mask;
+
+ GATT_TRACE_EVENT("DIS_ReadDISInfo() - BDA: %08x%04x cl_read_uuid: 0x%04x",
+ (peer_bda[0] << 24) + (peer_bda[1] << 16) +
+ (peer_bda[2] << 8) + peer_bda[3],
+ (peer_bda[4] << 8) + peer_bda[5],
+ dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
+
+ GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id,
+ BT_TRANSPORT_LE);
+
+ /* need to enhance it as multiple service is needed */
+ srvc_eng_request_channel(peer_bda, SRVC_ID_DIS);
+
+ if (conn_id == GATT_INVALID_CONN_ID) {
+ return GATT_Connect(srvc_eng_cb.gatt_if, peer_bda, true, BT_TRANSPORT_LE,
+ false);
+ }
+
+ return dis_gatt_c_read_dis_req(conn_id);
+}
diff --git a/mtkbt/code/bt/stack/srvc/srvc_dis_int.h b/mtkbt/code/bt/stack/srvc/srvc_dis_int.h
new file mode 100755
index 0000000..880f068
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_dis_int.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_DIS_INT_H
+#define SRVC_DIS_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+#include "srvc_eng_int.h"
+
+#define DIS_MAX_CHAR_NUM 9
+
+typedef struct {
+ uint16_t uuid;
+ uint16_t handle;
+} tDIS_DB_ENTRY;
+
+#define DIS_SYSTEM_ID_SIZE 8
+#define DIS_PNP_ID_SIZE 7
+
+typedef struct {
+ tDIS_DB_ENTRY dis_attr[DIS_MAX_CHAR_NUM];
+ tDIS_VALUE dis_value;
+
+ tDIS_READ_CBACK* p_read_dis_cback;
+
+ uint16_t service_handle;
+ uint16_t max_handle;
+
+ bool enabled;
+
+ uint8_t dis_read_uuid_idx;
+
+ tDIS_ATTR_MASK request_mask;
+} tDIS_CB;
+
+/* Global GATT data */
+extern tDIS_CB dis_cb;
+
+extern bool dis_valid_handle_range(uint16_t handle);
+extern uint8_t dis_read_attr_value(uint8_t clcb_idx, uint16_t handle,
+ tGATT_VALUE* p_value, bool is_long,
+ tGATT_STATUS* p_status);
+extern uint8_t dis_write_attr_value(tGATT_WRITE_REQ* p_data,
+ tGATT_STATUS* p_status);
+
+extern void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op,
+ tGATT_STATUS status, tGATT_CL_COMPLETE* p_data);
+
+#endif
diff --git a/mtkbt/code/bt/stack/srvc/srvc_eng.cc b/mtkbt/code/bt/stack/srvc/srvc_eng.cc
new file mode 100755
index 0000000..568b66e
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_eng.cc
@@ -0,0 +1,440 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "bt_target.h"
+#include "bt_utils.h"
+#include "gatt_api.h"
+#include "gatt_int.h"
+#include "osi/include/osi.h"
+#include "srvc_eng_int.h"
+
+#include "srvc_battery_int.h"
+#include "srvc_dis_int.h"
+
+static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id,
+ uint8_t op_code, tGATTS_DATA* p_data);
+static void srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ tBT_TRANSPORT transport);
+static void srvc_eng_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data);
+
+static tGATT_CBACK srvc_gatt_cback = {srvc_eng_connect_cback,
+ srvc_eng_c_cmpl_cback,
+ NULL,
+ NULL,
+ srvc_eng_s_request_cback,
+ NULL,
+ NULL,
+ NULL,
+ NULL};
+/* type for action functions */
+typedef void (*tSRVC_ENG_C_CMPL_ACTION)(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data);
+
+const tSRVC_ENG_C_CMPL_ACTION srvc_eng_c_cmpl_act[SRVC_ID_MAX] = {
+ dis_c_cmpl_cback,
+};
+
+tSRVC_ENG_CB srvc_eng_cb;
+
+/*******************************************************************************
+ *
+ * Function srvc_eng_find_conn_id_by_bd_addr
+ *
+ * Description The function searches all LCB with macthing bd address
+ *
+ * Returns total number of clcb found.
+ *
+ ******************************************************************************/
+uint16_t srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda) {
+ uint8_t i_clcb;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected &&
+ !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
+ return p_clcb->conn_id;
+ }
+ }
+
+ return GATT_INVALID_CONN_ID;
+}
+
+/*******************************************************************************
+ *
+ * Function srvc_eng_find_clcb_by_bd_addr
+ *
+ * Description The function searches all LCBs with macthing bd address.
+ *
+ * Returns Pointer to the found link conenction control block.
+ *
+ ******************************************************************************/
+tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda) {
+ uint8_t i_clcb;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected &&
+ !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
+ return p_clcb;
+ }
+ }
+
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_find_clcb_by_conn_id
+ *
+ * Description The function searches all LCBs with macthing connection ID.
+ *
+ * Returns Pointer to the found link conenction control block.
+ *
+ ******************************************************************************/
+tSRVC_CLCB* srvc_eng_find_clcb_by_conn_id(uint16_t conn_id) {
+ uint8_t i_clcb;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
+ return p_clcb;
+ }
+ }
+
+ return NULL;
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_find_clcb_by_conn_id
+ *
+ * Description The function searches all LCBs with macthing connection ID.
+ *
+ * Returns Pointer to the found link conenction control block.
+ *
+ ******************************************************************************/
+uint8_t srvc_eng_find_clcb_idx_by_conn_id(uint16_t conn_id) {
+ uint8_t i_clcb;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
+ return i_clcb;
+ }
+ }
+
+ return SRVC_MAX_APPS;
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_clcb_alloc
+ *
+ * Description Allocate a GATT profile connection link control block
+ *
+ * Returns NULL if not found. Otherwise pointer to the connection link
+ * block.
+ *
+ ******************************************************************************/
+tSRVC_CLCB* srvc_eng_clcb_alloc(uint16_t conn_id, BD_ADDR bda) {
+ uint8_t i_clcb = 0;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (!p_clcb->in_use) {
+ p_clcb->in_use = true;
+ p_clcb->conn_id = conn_id;
+ p_clcb->connected = true;
+ memcpy(p_clcb->bda, bda, BD_ADDR_LEN);
+ break;
+ }
+ }
+ return p_clcb;
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_clcb_dealloc
+ *
+ * Description De-allocate a GATT profile connection link control block
+ *
+ * Returns True the deallocation is successful
+ *
+ ******************************************************************************/
+bool srvc_eng_clcb_dealloc(uint16_t conn_id) {
+ uint8_t i_clcb = 0;
+ tSRVC_CLCB* p_clcb = NULL;
+
+ for (i_clcb = 0, p_clcb = srvc_eng_cb.clcb; i_clcb < SRVC_MAX_APPS;
+ i_clcb++, p_clcb++) {
+ if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id)) {
+ unsigned j;
+ for (j = 0; j < ARRAY_SIZE(p_clcb->dis_value.data_string); j++)
+ osi_free(p_clcb->dis_value.data_string[j]);
+
+ memset(p_clcb, 0, sizeof(tSRVC_CLCB));
+ return true;
+ }
+ }
+ return false;
+}
+/*******************************************************************************
+ * Service Engine Server Attributes Database Read/Read Blob Request process
+ ******************************************************************************/
+uint8_t srvc_eng_process_read_req(uint8_t clcb_idx, tGATT_READ_REQ* p_data,
+ tGATTS_RSP* p_rsp, tGATT_STATUS* p_status) {
+ tGATT_STATUS status = GATT_NOT_FOUND;
+ uint8_t act = SRVC_ACT_RSP;
+
+ if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
+
+ p_rsp->attr_value.handle = p_data->handle;
+
+ if (dis_valid_handle_range(p_data->handle))
+ act = dis_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
+ p_data->is_long, p_status);
+
+ else if (battery_valid_handle_range(p_data->handle))
+ act =
+ battery_s_read_attr_value(clcb_idx, p_data->handle, &p_rsp->attr_value,
+ p_data->is_long, p_status);
+
+ else
+ *p_status = status;
+ return act;
+}
+/*******************************************************************************
+ * Service Engine Server Attributes Database write Request process
+ ******************************************************************************/
+uint8_t srvc_eng_process_write_req(uint8_t clcb_idx, tGATT_WRITE_REQ* p_data,
+ UNUSED_ATTR tGATTS_RSP* p_rsp,
+ tGATT_STATUS* p_status) {
+ uint8_t act = SRVC_ACT_RSP;
+
+ if (dis_valid_handle_range(p_data->handle)) {
+ act = dis_write_attr_value(p_data, p_status);
+ } else if (battery_valid_handle_range(p_data->handle)) {
+ act = battery_s_write_attr_value(clcb_idx, p_data, p_status);
+ } else
+ *p_status = GATT_NOT_FOUND;
+
+ return act;
+}
+
+/*******************************************************************************
+ *
+ * Function srvc_eng_s_request_cback
+ *
+ * Description GATT DIS attribute access request callback.
+ *
+ * Returns void.
+ *
+ ******************************************************************************/
+static void srvc_eng_s_request_cback(uint16_t conn_id, uint32_t trans_id,
+ tGATTS_REQ_TYPE type,
+ tGATTS_DATA* p_data) {
+ uint8_t status = GATT_INVALID_PDU;
+ tGATTS_RSP rsp_msg;
+ uint8_t act = SRVC_ACT_IGNORE;
+ uint8_t clcb_idx = srvc_eng_find_clcb_idx_by_conn_id(conn_id);
+
+ GATT_TRACE_EVENT("srvc_eng_s_request_cback : recv type (0x%02x)", type);
+
+ memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
+
+ srvc_eng_cb.clcb[clcb_idx].trans_id = trans_id;
+
+ switch (type) {
+ case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_READ_DESCRIPTOR:
+ act = srvc_eng_process_read_req(clcb_idx, &p_data->read_req, &rsp_msg,
+ &status);
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
+ case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
+ act = srvc_eng_process_write_req(clcb_idx, &p_data->write_req, &rsp_msg,
+ &status);
+ if (!p_data->write_req.need_rsp) act = SRVC_ACT_IGNORE;
+ break;
+
+ case GATTS_REQ_TYPE_WRITE_EXEC:
+ GATT_TRACE_EVENT("Ignore GATT_REQ_EXEC_WRITE/WRITE_CMD");
+ break;
+
+ case GATTS_REQ_TYPE_MTU:
+ GATT_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
+ break;
+
+ default:
+ GATT_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
+ break;
+ }
+
+ srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+
+ if (act == SRVC_ACT_RSP) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
+}
+
+/*******************************************************************************
+ *
+ * Function srvc_eng_c_cmpl_cback
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void srvc_eng_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
+ tGATT_STATUS status,
+ tGATT_CL_COMPLETE* p_data) {
+ tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+ GATT_TRACE_EVENT("srvc_eng_c_cmpl_cback() - op_code: 0x%02x status: 0x%02x ",
+ op, status);
+
+ if (p_clcb == NULL) {
+ GATT_TRACE_ERROR("srvc_eng_c_cmpl_cback received for unknown connection");
+ return;
+ }
+
+ if (p_clcb->cur_srvc_id != SRVC_ID_NONE && p_clcb->cur_srvc_id <= SRVC_ID_MAX)
+ srvc_eng_c_cmpl_act[p_clcb->cur_srvc_id - 1](p_clcb, op, status, p_data);
+}
+
+/*******************************************************************************
+ *
+ * Function srvc_eng_connect_cback
+ *
+ * Description Gatt profile connection callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void srvc_eng_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
+ uint16_t conn_id, bool connected,
+ tGATT_DISCONN_REASON reason,
+ UNUSED_ATTR tBT_TRANSPORT transport) {
+ GATT_TRACE_EVENT(
+ "srvc_eng_connect_cback: from %08x%04x connected:%d conn_id=%d reason = "
+ "0x%04x",
+ (bda[0] << 24) + (bda[1] << 16) + (bda[2] << 8) + bda[3],
+ (bda[4] << 8) + bda[5], connected, conn_id, reason);
+
+ if (connected) {
+ if (srvc_eng_clcb_alloc(conn_id, bda) == NULL) {
+ GATT_TRACE_ERROR("srvc_eng_connect_cback: no_resource");
+ return;
+ }
+ } else {
+ srvc_eng_clcb_dealloc(conn_id);
+ }
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_c_cmpl_cback
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool srvc_eng_request_channel(BD_ADDR remote_bda, uint8_t srvc_id) {
+ bool set = true;
+ tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_bd_addr(remote_bda);
+
+ if (p_clcb == NULL) p_clcb = srvc_eng_clcb_alloc(0, remote_bda);
+
+ if (p_clcb && p_clcb->cur_srvc_id == SRVC_ID_NONE)
+ p_clcb->cur_srvc_id = srvc_id;
+ else
+ set = false;
+
+ return set;
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_release_channel
+ *
+ * Description Client operation complete callback.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void srvc_eng_release_channel(uint16_t conn_id) {
+ tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
+
+ if (p_clcb == NULL) {
+ GATT_TRACE_ERROR("%s: invalid connection id %d", __func__, conn_id);
+ return;
+ }
+
+ p_clcb->cur_srvc_id = SRVC_ID_NONE;
+
+ /* check pending request */
+ GATT_Disconnect(p_clcb->conn_id);
+}
+/*******************************************************************************
+ *
+ * Function srvc_eng_init
+ *
+ * Description Initializa the GATT Service engine.
+ *
+ ******************************************************************************/
+tGATT_STATUS srvc_eng_init(void) {
+ tBT_UUID app_uuid = {LEN_UUID_16, {UUID_SERVCLASS_DEVICE_INFO}};
+
+ if (srvc_eng_cb.enabled) {
+ GATT_TRACE_ERROR("DIS already initalized");
+ } else {
+ memset(&srvc_eng_cb, 0, sizeof(tSRVC_ENG_CB));
+
+ /* Create a GATT profile service */
+ srvc_eng_cb.gatt_if = GATT_Register(&app_uuid, &srvc_gatt_cback);
+ GATT_StartIf(srvc_eng_cb.gatt_if);
+
+ GATT_TRACE_DEBUG("Srvc_Init: gatt_if=%d ", srvc_eng_cb.gatt_if);
+
+ srvc_eng_cb.enabled = true;
+ dis_cb.dis_read_uuid_idx = 0xff;
+ }
+ return GATT_SUCCESS;
+}
+
+void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP* p_rsp) {
+ if (srvc_eng_cb.clcb[clcb_idx].trans_id != 0) {
+ GATTS_SendRsp(srvc_eng_cb.clcb[clcb_idx].conn_id,
+ srvc_eng_cb.clcb[clcb_idx].trans_id, st, p_rsp);
+
+ srvc_eng_cb.clcb[clcb_idx].trans_id = 0;
+ }
+}
+void srvc_sr_notify(BD_ADDR remote_bda, uint16_t handle, uint16_t len,
+ uint8_t* p_value) {
+ uint16_t conn_id = srvc_eng_find_conn_id_by_bd_addr(remote_bda);
+
+ if (conn_id != GATT_INVALID_CONN_ID) {
+ GATTS_HandleValueNotification(conn_id, handle, len, p_value);
+ }
+}
diff --git a/mtkbt/code/bt/stack/srvc/srvc_eng_int.h b/mtkbt/code/bt/stack/srvc/srvc_eng_int.h
new file mode 100755
index 0000000..3362748
--- a/dev/null
+++ b/mtkbt/code/bt/stack/srvc/srvc_eng_int.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1999-2013 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef SRVC_ENG_INT_H
+#define SRVC_ENG_INT_H
+
+#include "bt_target.h"
+#include "gatt_api.h"
+#include "srvc_api.h"
+
+#define SRVC_MAX_APPS GATT_CL_MAX_LCB
+
+#define SRVC_ID_NONE 0
+#define SRVC_ID_DIS 1
+#define SRVC_ID_MAX SRVC_ID_DIS
+
+#define SRVC_ACT_IGNORE 0
+#define SRVC_ACT_RSP 1
+#define SRVC_ACT_PENDING 2
+
+typedef struct {
+ bool in_use;
+ uint16_t conn_id;
+ bool connected;
+ BD_ADDR bda;
+ uint32_t trans_id;
+ uint8_t cur_srvc_id;
+
+ tDIS_VALUE dis_value;
+
+} tSRVC_CLCB;
+
+/* service engine control block */
+typedef struct {
+ tSRVC_CLCB clcb[SRVC_MAX_APPS]; /* connection link*/
+ tGATT_IF gatt_if;
+ bool enabled;
+
+} tSRVC_ENG_CB;
+
+/* Global GATT data */
+extern tSRVC_ENG_CB srvc_eng_cb;
+
+extern tSRVC_CLCB* srvc_eng_find_clcb_by_conn_id(uint16_t conn_id);
+extern tSRVC_CLCB* srvc_eng_find_clcb_by_bd_addr(BD_ADDR bda);
+extern uint16_t srvc_eng_find_conn_id_by_bd_addr(BD_ADDR bda);
+
+extern void srvc_eng_release_channel(uint16_t conn_id);
+extern bool srvc_eng_request_channel(BD_ADDR remote_bda, uint8_t srvc_id);
+extern void srvc_sr_rsp(uint8_t clcb_idx, tGATT_STATUS st, tGATTS_RSP* p_rsp);
+extern void srvc_sr_notify(BD_ADDR remote_bda, uint16_t handle, uint16_t len,
+ uint8_t* p_value);
+
+#endif
diff --git a/mtkbt/code/bt/stack/test/ad_parser_unittest.cc b/mtkbt/code/bt/stack/test/ad_parser_unittest.cc
new file mode 100755
index 0000000..46ff3ec
--- a/dev/null
+++ b/mtkbt/code/bt/stack/test/ad_parser_unittest.cc
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+#include "advertise_data_parser.h"
+
+TEST(AdvertiseDataParserTest, IsValidEmpty) {
+ const std::vector<uint8_t> data0;
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data0));
+
+ // Single empty field not allowed.
+ const std::vector<uint8_t> data1{0x00};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data1));
+}
+
+TEST(AdvertiseDataParserTest, IsValidBad) {
+ // Single field, field empty.
+ const std::vector<uint8_t> data0{0x01};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data0));
+
+ // Single field, first field length too long.
+ const std::vector<uint8_t> data1{0x05, 0x02, 0x00, 0x00, 0x00};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data1));
+
+ // Two fields, second field length too long.
+ const std::vector<uint8_t> data2{0x02, 0x02, 0x00, 0x02, 0x00};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data2));
+
+ // Two fields, second field empty.
+ const std::vector<uint8_t> data3{0x02, 0x02, 0x00, 0x01};
+ EXPECT_FALSE(AdvertiseDataParser::IsValid(data3));
+}
+
+TEST(AdvertiseDataParserTest, IsValidGood) {
+ // Single field.
+ const std::vector<uint8_t> data0{0x03, 0x02, 0x01, 0x02};
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data0));
+
+ // Two fields.
+ const std::vector<uint8_t> data1{0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x01};
+ EXPECT_TRUE(AdvertiseDataParser::IsValid(data1));
+}
+
+TEST(AdvertiseDataParserTest, GetFieldByType) {
+ // Single field.
+ const std::vector<uint8_t> data0{0x03, 0x02, 0x01, 0x02};
+
+ uint8_t p_length;
+ const uint8_t* data =
+ AdvertiseDataParser::GetFieldByType(data0, 0x02, &p_length);
+ EXPECT_EQ(data0.data() + 2, data);
+ EXPECT_EQ(2, p_length);
+
+ // Two fields, second field length too long.
+ const std::vector<uint8_t> data1{0x02, 0x02, 0x00, 0x03, 0x00};
+
+ // First field is ok.
+ data = AdvertiseDataParser::GetFieldByType(data1, 0x02, &p_length);
+ EXPECT_EQ(data1.data() + 2, data);
+ EXPECT_EQ(0x01, p_length);
+
+ // Second field have bad length.
+ data = AdvertiseDataParser::GetFieldByType(data1, 0x03, &p_length);
+ EXPECT_EQ(nullptr, data);
+ EXPECT_EQ(0, p_length);
+} \ No newline at end of file
diff --git a/mtkbt/code/bt/stack/test/ble_advertiser_test.cc b/mtkbt/code/bt/stack/test/ble_advertiser_test.cc
new file mode 100755
index 0000000..2d7879b
--- a/dev/null
+++ b/mtkbt/code/bt/stack/test/ble_advertiser_test.cc
@@ -0,0 +1,745 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "device/include/controller.h"
+#include "stack/btm/ble_advertiser_hci_interface.h"
+#include "stack/include/ble_advertiser.h"
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::ElementsAreArray;
+using ::testing::Exactly;
+using ::testing::IsEmpty;
+using ::testing::SaveArg;
+using base::Bind;
+using status_cb = BleAdvertiserHciInterface::status_cb;
+using parameters_cb = BleAdvertiserHciInterface::parameters_cb;
+
+const int num_adv_instances = 16;
+
+/* Below are methods that must be implemented if we don't want to compile the
+ * whole stack. They will be removed, or changed into mocks one by one in the
+ * future, as the refactoring progresses */
+bool BTM_BleLocalPrivacyEnabled() { return true; }
+uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
+ return true;
+}
+bool SMP_Encrypt(uint8_t* key, uint8_t key_len, uint8_t* plain_text,
+ uint8_t pt_len, tSMP_ENC* p_out) {
+ return true;
+}
+void BTM_GetDeviceIDRoot(BT_OCTET16 irk) {}
+void btm_ble_update_dmt_flag_bits(uint8_t* flag_value,
+ const uint16_t connect_mode,
+ const uint16_t disc_mode) {}
+/** M: fix truncated conn_handle to uint16_t type@{ */
+void btm_acl_update_conn_addr(uint16_t conn_handle, BD_ADDR address) {}
+/** @} */
+void btm_gen_resolvable_private_addr(base::Callback<void(uint8_t[8])> cb) {
+ uint8_t fake_rand[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ cb.Run(fake_rand);
+}
+
+alarm_callback_t last_alarm_cb = nullptr;
+void* last_alarm_data = nullptr;
+void alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms,
+ alarm_callback_t cb, void* data, fixed_queue_t* queue) {
+ last_alarm_cb = cb;
+ last_alarm_data = data;
+}
+
+void alarm_cancel(alarm_t* alarm) {}
+alarm_t* alarm_new_periodic(const char* name) { return nullptr; }
+alarm_t* alarm_new(const char* name) { return nullptr; }
+void alarm_free(alarm_t* alarm) {}
+const controller_t* controller_get_interface() { return nullptr; }
+fixed_queue_t* btu_general_alarm_queue = nullptr;
+
+namespace {
+void DoNothing(uint8_t) {}
+
+void DoNothing2(uint8_t, uint8_t) {}
+
+void TriggerRandomAddressUpdate() {
+ // Call to StartAdvertisingSet set the last_alarm_cb to random address timeout
+ // callback. Call it now in order to trigger address update
+ last_alarm_cb(last_alarm_data);
+}
+
+constexpr uint8_t INTERMEDIATE =
+ 0x00; // Intermediate fragment of fragmented data
+constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data
+constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data
+constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data
+
+class AdvertiserHciMock : public BleAdvertiserHciInterface {
+ public:
+ AdvertiserHciMock() = default;
+ ~AdvertiserHciMock() override = default;
+
+ MOCK_METHOD1(ReadInstanceCount,
+ void(base::Callback<void(uint8_t /* inst_cnt*/)>));
+ MOCK_METHOD1(SetAdvertisingEventObserver,
+ void(AdvertisingEventObserver* observer));
+ MOCK_METHOD6(SetAdvertisingData,
+ void(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t*, status_cb));
+ MOCK_METHOD6(SetScanResponseData,
+ void(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t*, status_cb));
+ MOCK_METHOD3(SetRandomAddress, void(uint8_t, BD_ADDR, status_cb));
+ MOCK_METHOD5(Enable, void(uint8_t, uint8_t, uint16_t, uint8_t, status_cb));
+ MOCK_METHOD5(SetPeriodicAdvertisingParameters,
+ void(uint8_t, uint16_t, uint16_t, uint16_t, status_cb));
+ MOCK_METHOD5(SetPeriodicAdvertisingData,
+ void(uint8_t, uint8_t, uint8_t, uint8_t*, status_cb));
+ MOCK_METHOD3(SetPeriodicAdvertisingEnable, void(uint8_t, uint8_t, status_cb));
+ MOCK_METHOD2(RemoveAdvertisingSet, void(uint8_t, status_cb));
+ MOCK_METHOD1(ClearAdvertisingSets, void(status_cb));
+
+ MOCK_METHOD9(SetParameters1,
+ void(uint8_t, uint16_t, uint32_t, uint32_t, uint8_t, uint8_t,
+ BD_ADDR, uint8_t, BD_ADDR));
+ MOCK_METHOD8(SetParameters2, void(uint8_t, int8_t, uint8_t, uint8_t, uint8_t,
+ uint8_t, uint8_t, parameters_cb));
+
+ void SetParameters(uint8_t handle, uint16_t properties, uint32_t adv_int_min,
+ uint32_t adv_int_max, uint8_t channel_map,
+ uint8_t own_address_type, BD_ADDR own_address,
+ uint8_t peer_address_type, BD_ADDR peer_address,
+ uint8_t filter_policy, int8_t tx_power,
+ uint8_t primary_phy, uint8_t secondary_max_skip,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ uint8_t scan_request_notify_enable,
+ parameters_cb cmd_complete) override {
+ SetParameters1(handle, properties, adv_int_min, adv_int_max, channel_map,
+ own_address_type, own_address, peer_address_type,
+ peer_address);
+ SetParameters2(filter_policy, tx_power, primary_phy, secondary_max_skip,
+ secondary_phy, advertising_sid, scan_request_notify_enable,
+ cmd_complete);
+ };
+
+ bool QuirkAdvertiserZeroHandle() { return false; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AdvertiserHciMock);
+};
+
+} // namespace
+
+class BleAdvertisingManagerTest : public testing::Test {
+ protected:
+ int reg_inst_id = -1;
+ int reg_status = -1;
+ int set_params_status = -1;
+ int set_data_status = -1;
+ int enable_status = -1;
+ int start_advertising_status = -1;
+ int start_advertising_set_advertiser_id = -1;
+ int start_advertising_set_tx_power = -1;
+ int start_advertising_set_status = -1;
+
+ std::unique_ptr<AdvertiserHciMock> hci_mock;
+
+ virtual void SetUp() {
+ hci_mock.reset(new AdvertiserHciMock());
+
+ base::Callback<void(uint8_t)> inst_cnt_Cb;
+ EXPECT_CALL(*hci_mock, ReadInstanceCount(_))
+ .Times(Exactly(1))
+ .WillOnce(SaveArg<0>(&inst_cnt_Cb));
+
+ BleAdvertisingManager::Initialize(hci_mock.get());
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // we are a truly gracious fake controller, let the command succeed!
+ inst_cnt_Cb.Run(num_adv_instances);
+ }
+
+ virtual void TearDown() {
+ BleAdvertisingManager::CleanUp();
+ hci_mock.reset();
+ }
+
+ public:
+ void RegistrationCb(uint8_t inst_id, uint8_t status) {
+ reg_inst_id = inst_id;
+ reg_status = status;
+ }
+
+ void SetParametersCb(uint8_t status, int8_t tx_power) {
+ set_params_status = status;
+ }
+ void SetDataCb(uint8_t status) { set_data_status = status; }
+ void EnableCb(uint8_t status) { enable_status = status; }
+ void StartAdvertisingCb(uint8_t status) { start_advertising_status = status; }
+ void StartAdvertisingSetCb(uint8_t advertiser_id, int8_t tx_power,
+ uint8_t status) {
+ start_advertising_set_advertiser_id = advertiser_id;
+ start_advertising_set_tx_power = tx_power;
+ start_advertising_set_status = status;
+ }
+};
+
+TEST_F(BleAdvertisingManagerTest, test_registration) {
+ for (int i = 0; i < num_adv_instances; i++) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(Bind(
+ &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ EXPECT_EQ(i, reg_inst_id);
+ }
+
+ // This call should return an error - no more advertisers left.
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(ADVERTISE_FAILED_TOO_MANY_ADVERTISERS, reg_status);
+ // Don't bother checking inst_id, it doesn't matter
+
+ status_cb remove_cb;
+ EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(_, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&remove_cb));
+ BleAdvertisingManager::Get()->Unregister(5);
+ remove_cb.Run(0);
+
+ // One advertiser was freed, so should be able to register one now
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ EXPECT_EQ(5, reg_inst_id);
+}
+
+/* This test verifies that the following flow is working correctly: register,
+ * set parameters, set data, enable, ... (advertise) ..., unregister*/
+TEST_F(BleAdvertisingManagerTest, test_android_flow) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ int advertiser_id = reg_inst_id;
+
+ parameters_cb set_params_cb;
+ tBTM_BLE_ADV_PARAMS params;
+ EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+ BleAdvertisingManager::Get()->SetParameters(
+ advertiser_id, &params, Bind(&BleAdvertisingManagerTest::SetParametersCb,
+ base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // we are a truly gracious fake controller, let the command succeed!
+ set_params_cb.Run(0, 0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+
+ status_cb set_data_cb;
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, std::vector<uint8_t>(),
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ set_data_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ status_cb enable_cb;
+ EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, advertiser_id, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+ BleAdvertisingManager::Get()->Enable(
+ advertiser_id, true,
+ Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)), 0, 0,
+ base::Callback<void(uint8_t)>());
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ enable_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, enable_status);
+
+ /* fake controller should be advertising */
+
+ EXPECT_CALL(*hci_mock, Enable(0x00 /* disable */, advertiser_id, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+ status_cb remove_cb;
+ EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(_, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&remove_cb));
+ BleAdvertisingManager::Get()->Unregister(advertiser_id);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ enable_cb.Run(0);
+ remove_cb.Run(0);
+}
+
+/* This test verifies that when advertising data is set, tx power and flags will
+ * be properly filled. */
+TEST_F(BleAdvertisingManagerTest, test_adv_data_filling) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ int advertiser_id = reg_inst_id;
+
+ parameters_cb set_params_cb;
+ tBTM_BLE_ADV_PARAMS params;
+ params.advertising_event_properties =
+ BleAdvertisingManager::advertising_prop_legacy_connectable;
+ params.tx_power = -15;
+ EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*hci_mock, SetParameters2(_, params.tx_power, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+ BleAdvertisingManager::Get()->SetParameters(
+ advertiser_id, &params, Bind(&BleAdvertisingManagerTest::SetParametersCb,
+ base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // let the set parameters command succeed!
+ set_params_cb.Run(0, 0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+
+ status_cb set_data_cb;
+ /* verify that flags will be added, and tx power filled, if call to SetData
+ * contained only tx power, and the advertisement is connectable */
+ uint8_t expected_adv_data[] = {
+ 0x02 /* len */, 0x01 /* flags */,
+ 0x02 /* flags value */, 0x02 /* len */,
+ 0x0A /* tx_power */, static_cast<uint8_t>(params.tx_power)};
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _))
+ .With(Args<4, 3>(ElementsAreArray(expected_adv_data)))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false,
+ std::vector<uint8_t>({0x02 /* len */, 0x0A /* tx_power */, 0x00}),
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ set_data_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+}
+
+/* This test verifies that when advertising is non-connectable, flags will not
+ * be added. */
+TEST_F(BleAdvertisingManagerTest, test_adv_data_not_filling) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ int advertiser_id = reg_inst_id;
+
+ parameters_cb set_params_cb;
+ tBTM_BLE_ADV_PARAMS params;
+ params.advertising_event_properties =
+ BleAdvertisingManager::advertising_prop_legacy_non_connectable;
+ params.tx_power = -15;
+ EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*hci_mock,
+ SetParameters2(_, (uint8_t)params.tx_power, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+ BleAdvertisingManager::Get()->SetParameters(
+ advertiser_id, &params, Bind(&BleAdvertisingManagerTest::SetParametersCb,
+ base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // let the set parameters command succeed!
+ set_params_cb.Run(0, -15);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_params_status);
+
+ status_cb set_data_cb;
+ /* verify that flags will not be added */
+ uint8_t expected_adv_data[] = {
+ 0x02 /* len */, 0xFF /* manufacturer specific */, 0x01 /* data */};
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _))
+ .With(Args<4, 3>(ElementsAreArray(expected_adv_data)))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, std::vector<uint8_t>({0x02 /* len */, 0xFF, 0x01}),
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ set_data_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+}
+
+TEST_F(BleAdvertisingManagerTest, test_reenabling) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ EXPECT_EQ(0, reg_inst_id);
+
+ uint8_t advertiser_id = reg_inst_id;
+
+ status_cb enable_cb;
+ EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, advertiser_id, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+ BleAdvertisingManager::Get()->OnAdvertisingSetTerminated(advertiser_id, 0x00,
+ 0x05, 0x00);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ enable_cb.Run(0);
+}
+
+/* Make sure that instance is not reenabled if it's already disabled */
+TEST_F(BleAdvertisingManagerTest, test_reenabling_disabled_instance) {
+ uint8_t advertiser_id = 1; // any unregistered value
+
+ EXPECT_CALL(*hci_mock, Enable(_, _, _, _, _)).Times(Exactly(0));
+ BleAdvertisingManager::Get()->OnAdvertisingSetTerminated(advertiser_id, 0x00,
+ 0x05, 0x00);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+}
+
+/* This test verifies that the only flow that is currently used on Android, is
+ * working correctly in happy case scenario. */
+TEST_F(BleAdvertisingManagerTest, test_start_advertising_set) {
+ std::vector<uint8_t> adv_data;
+ std::vector<uint8_t> scan_resp;
+ tBTM_BLE_ADV_PARAMS params;
+ tBLE_PERIODIC_ADV_PARAMS periodic_params;
+ periodic_params.enable = false;
+ std::vector<uint8_t> periodic_data;
+
+ parameters_cb set_params_cb;
+ status_cb set_address_cb;
+ status_cb set_data_cb;
+ status_cb set_scan_resp_data_cb;
+ status_cb enable_cb;
+ EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+ EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<2>(&set_address_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_scan_resp_data_cb));
+ EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+
+ BleAdvertisingManager::Get()->StartAdvertisingSet(
+ Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb,
+ base::Unretained(this)),
+ &params, adv_data, scan_resp, &periodic_params, periodic_data,
+ 0 /* duration */, 0 /* maxExtAdvEvents */, Bind(DoNothing2));
+
+ // we are a truly gracious fake controller, let the commands succeed!
+ int selected_tx_power = -15;
+ set_params_cb.Run(0, selected_tx_power);
+ set_address_cb.Run(0);
+ set_data_cb.Run(0);
+ set_scan_resp_data_cb.Run(0);
+ enable_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status);
+ EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power);
+ int advertiser_id = start_advertising_set_advertiser_id;
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // ... advertising ...
+
+ // Disable advertiser
+ status_cb disable_cb;
+ EXPECT_CALL(*hci_mock, Enable(0x00 /* disable */, advertiser_id, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&disable_cb));
+ status_cb remove_cb;
+ EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&remove_cb));
+ BleAdvertisingManager::Get()->Unregister(advertiser_id);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ disable_cb.Run(0);
+ remove_cb.Run(0);
+}
+
+TEST_F(BleAdvertisingManagerTest, test_start_advertising_set_params_failed) {
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ int advertiser_id = reg_inst_id;
+
+ std::vector<uint8_t> adv_data;
+ std::vector<uint8_t> scan_resp;
+ tBTM_BLE_ADV_PARAMS params;
+
+ parameters_cb set_params_cb;
+ EXPECT_CALL(*hci_mock, SetParameters1(advertiser_id, _, _, _, _, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, _, _, _, _, _))
+ .Times(Exactly(0));
+
+ BleAdvertisingManager::Get()->StartAdvertising(
+ advertiser_id, Bind(&BleAdvertisingManagerTest::StartAdvertisingCb,
+ base::Unretained(this)),
+ &params, adv_data, scan_resp, 0, base::Callback<void(uint8_t)>());
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // set params failed
+ set_params_cb.Run(0x01, 0);
+
+ // Expect the whole flow to fail right away
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, start_advertising_status);
+}
+
+TEST_F(BleAdvertisingManagerTest, test_data_sender) {
+ // prepare test input vector
+ const int max_data_size = 1650;
+ std::vector<uint8_t> data(max_data_size);
+ for (int i = 0; i < max_data_size; i++) data[i] = i;
+
+ BleAdvertisingManager::Get()->RegisterAdvertiser(
+ Bind(&BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this)));
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status);
+ int advertiser_id = reg_inst_id;
+
+ status_cb set_data_cb;
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock,
+ SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _))
+ .Times(5)
+ .WillRepeatedly(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 144, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ for (int i = 0; i < 7; i++) {
+ set_data_cb.Run(0x00);
+ }
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(503);
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock,
+ SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _))
+ .Times(1)
+ .WillRepeatedly(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 1, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ for (int i = 0; i < 3; i++) {
+ set_data_cb.Run(0x00);
+ }
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(502);
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ for (int i = 0; i < 2; i++) {
+ set_data_cb.Run(0x00);
+ }
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(501);
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 250, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ for (int i = 0; i < 2; i++) {
+ set_data_cb.Run(0x00);
+ }
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(251);
+ EXPECT_CALL(*hci_mock,
+ SetAdvertisingData(advertiser_id, COMPLETE, _, 251, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ set_data_cb.Run(0x00);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(120);
+ EXPECT_CALL(*hci_mock,
+ SetAdvertisingData(advertiser_id, COMPLETE, _, 120, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ set_data_cb.Run(0x00);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+
+ // ***************** Try again with different data size *********************
+ data.resize(0);
+ EXPECT_CALL(*hci_mock,
+ SetAdvertisingData(advertiser_id, COMPLETE, _, 0, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ BleAdvertisingManager::Get()->SetData(
+ advertiser_id, false, data,
+ Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this)));
+ set_data_cb.Run(0x00);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+ // Expect the whole flow to succeed
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status);
+}
+
+/* This test makes sure that conectable advertisment with timeout will get it's
+ * address updated once the timeout passes and one tries to enable it again.*/
+TEST_F(BleAdvertisingManagerTest,
+ test_connectable_address_update_during_timeout) {
+ std::vector<uint8_t> adv_data;
+ std::vector<uint8_t> scan_resp;
+ tBTM_BLE_ADV_PARAMS params;
+ params.advertising_event_properties = 0x1 /* connectable */;
+ tBLE_PERIODIC_ADV_PARAMS periodic_params;
+ periodic_params.enable = false;
+ std::vector<uint8_t> periodic_data;
+
+ uint8_t maxExtAdvEvents = 50;
+
+ parameters_cb set_params_cb;
+ status_cb set_address_cb;
+ status_cb set_data_cb;
+ status_cb set_scan_resp_data_cb;
+ status_cb enable_cb;
+ EXPECT_CALL(*hci_mock, SetParameters1(_, _, _, _, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(*hci_mock, SetParameters2(_, _, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<7>(&set_params_cb));
+ EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<2>(&set_address_cb));
+ EXPECT_CALL(*hci_mock, SetAdvertisingData(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_data_cb));
+ EXPECT_CALL(*hci_mock, SetScanResponseData(_, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<5>(&set_scan_resp_data_cb));
+ EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _, maxExtAdvEvents, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+
+ BleAdvertisingManager::Get()->StartAdvertisingSet(
+ Bind(&BleAdvertisingManagerTest::StartAdvertisingSetCb,
+ base::Unretained(this)),
+ &params, adv_data, scan_resp, &periodic_params, periodic_data,
+ 0 /* duration */, maxExtAdvEvents, Bind(DoNothing2));
+
+ // we are a truly gracious fake controller, let the commands succeed!
+ int selected_tx_power = -15;
+ set_params_cb.Run(0, selected_tx_power);
+ set_address_cb.Run(0);
+ set_data_cb.Run(0);
+ set_scan_resp_data_cb.Run(0);
+ enable_cb.Run(0);
+ EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, start_advertising_set_status);
+ EXPECT_EQ(selected_tx_power, start_advertising_set_tx_power);
+ int advertiser_id = start_advertising_set_advertiser_id;
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // ... advertising ...
+
+ // No HCI calls should be triggered, becuase there is a timeout on a
+ // connectable advertisement.
+ TriggerRandomAddressUpdate();
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // Set terminated because we advertised maxExtAdvEvents times!
+ BleAdvertisingManager::Get()->OnAdvertisingSetTerminated(
+ 0x43 /*status */, advertiser_id, 0x00 /* conn_handle*/, maxExtAdvEvents);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // Try to Enable the advertiser. It should first update it's random address.
+ EXPECT_CALL(*hci_mock, SetRandomAddress(_, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<2>(&set_address_cb));
+ EXPECT_CALL(*hci_mock, Enable(0x01 /* enable */, _, _, maxExtAdvEvents, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&enable_cb));
+ BleAdvertisingManager::Get()->Enable(
+ advertiser_id, true,
+ Bind(&BleAdvertisingManagerTest::EnableCb, base::Unretained(this)), 0,
+ maxExtAdvEvents, Bind(DoNothing));
+ set_address_cb.Run(0);
+ enable_cb.Run(0);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ // Disable advertiser
+ status_cb disable_cb;
+ EXPECT_CALL(*hci_mock, Enable(0x00 /* disable */, advertiser_id, _, _, _))
+ .Times(1)
+ .WillOnce(SaveArg<4>(&disable_cb));
+ status_cb remove_cb;
+ EXPECT_CALL(*hci_mock, RemoveAdvertisingSet(advertiser_id, _))
+ .Times(1)
+ .WillOnce(SaveArg<1>(&remove_cb));
+ BleAdvertisingManager::Get()->Unregister(advertiser_id);
+ ::testing::Mock::VerifyAndClearExpectations(hci_mock.get());
+
+ disable_cb.Run(0);
+ remove_cb.Run(0);
+}
diff --git a/mtkbt/code/bt/stack/test/stack_a2dp_test.cc b/mtkbt/code/bt/stack/test/stack_a2dp_test.cc
new file mode 100755
index 0000000..58c5cf8
--- a/dev/null
+++ b/mtkbt/code/bt/stack/test/stack_a2dp_test.cc
@@ -0,0 +1,944 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <dlfcn.h>
+
+#include <set>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "stack/include/a2dp_aac.h"
+#include "stack/include/a2dp_api.h"
+#include "stack/include/a2dp_codec_api.h"
+#include "stack/include/a2dp_sbc.h"
+#include "stack/include/a2dp_vendor.h"
+
+namespace {
+const uint8_t codec_info_sbc[AVDT_CODEC_SIZE] = {
+ 6, // Length (A2DP_SBC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 0, // Media Codec Type: A2DP_MEDIA_CT_SBC
+ 0x20 | 0x01, // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
+ // Channel Mode: A2DP_SBC_IE_CH_MD_JOINT
+ 0x10 | 0x04 | 0x01, // Block Length: A2DP_SBC_IE_BLOCKS_16 |
+ // Subbands: A2DP_SBC_IE_SUBBAND_8 |
+ // Allocation Method: A2DP_SBC_IE_ALLOC_MD_L
+ 2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
+ 53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
+const uint8_t codec_info_sbc_sink_capability[AVDT_CODEC_SIZE] = {
+ 6, // Length (A2DP_SBC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 0, // Media Codec Type: A2DP_MEDIA_CT_SBC
+ 0x20 | 0x10 | // Sample Frequency: A2DP_SBC_IE_SAMP_FREQ_44 |
+ // A2DP_SBC_IE_SAMP_FREQ_48 |
+ 0x08 | 0x04 | 0x02 | 0x01, // Channel Mode: A2DP_SBC_IE_CH_MD_MONO |
+ // A2DP_SBC_IE_CH_MD_DUAL |
+ // A2DP_SBC_IE_CH_MD_STEREO |
+ // A2DP_SBC_IE_CH_MD_JOINT
+ 0x80 | 0x40 | 0x20 | 0x10 | // Block Length: A2DP_SBC_IE_BLOCKS_4 |
+ // A2DP_SBC_IE_BLOCKS_8 |
+ // A2DP_SBC_IE_BLOCKS_12 |
+ // A2DP_SBC_IE_BLOCKS_16 |
+ 0x08 | 0x04 | // Subbands: A2DP_SBC_IE_SUBBAND_4 |
+ // A2DP_SBC_IE_SUBBAND_8 |
+ 0x02 | 0x01, // Allocation Method: A2DP_SBC_IE_ALLOC_MD_S |
+ // A2DP_SBC_IE_ALLOC_MD_L
+ 2, // MinimumBitpool Value: A2DP_SBC_IE_MIN_BITPOOL
+ 53, // Maximum Bitpool Value: A2DP_SBC_MAX_BITPOOL
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
+const uint8_t codec_info_aac[AVDT_CODEC_SIZE] = {
+ 8, // Length (A2DP_AAC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 2, // Media Codec Type: A2DP_MEDIA_CT_AAC
+ 0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
+ 0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+ 0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
+ 0x00 | 0x4, // Variable Bit Rate:
+ // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
+ // Bit Rate: 320000 = 0x4e200
+ 0xe2, // Bit Rate: 320000 = 0x4e200
+ 0x00, // Bit Rate: 320000 = 0x4e200
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
+const uint8_t codec_info_aac_capability[AVDT_CODEC_SIZE] = {
+ 8, // Length (A2DP_AAC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 2, // Media Codec Type: A2DP_MEDIA_CT_AAC
+ 0x80, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC
+ 0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+ // TODO: AAC 48.0kHz sampling rate should be added back - see b/62301376
+ 0x04, // Channels: A2DP_AAC_CHANNEL_MODE_STEREO
+ 0x00 | 0x4, // Variable Bit Rate:
+ // A2DP_AAC_VARIABLE_BIT_RATE_DISABLED
+ // Bit Rate: 320000 = 0x4e200
+ 0xe2, // Bit Rate: 320000 = 0x4e200
+ 0x00, // Bit Rate: 320000 = 0x4e200
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
+const uint8_t codec_info_aac_sink_capability[AVDT_CODEC_SIZE] = {
+ 8, // Length (A2DP_AAC_INFO_LEN)
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 2, // Media Codec Type: A2DP_MEDIA_CT_AAC
+ 0x80 | 0x40 | 0x20 | 0x10, // Object Type: A2DP_AAC_OBJECT_TYPE_MPEG2_LC |
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_LC
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_LTP
+ // A2DP_AAC_OBJECT_TYPE_MPEG4_SCALABLE
+ 0x01, // Sampling Frequency: A2DP_AAC_SAMPLING_FREQ_44100
+ 0x80 | 0x20 | 0x10 | 0x08 | 0x04, // Sampling Frequency:
+ // A2DP_AAC_SAMPLING_FREQ_48000 |
+ // A2DP_AAC_SAMPLING_FREQ_88200 |
+ // A2DP_AAC_SAMPLING_FREQ_96000 |
+ // Channels:
+ // A2DP_AAC_CHANNEL_MODE_MONO |
+ // A2DP_AAC_CHANNEL_MODE_STEREO
+ 0x80 | 0x4, // Variable Bit Rate:
+ // A2DP_AAC_VARIABLE_BIT_RATE_ENABLED
+ // Bit Rate: 320000 = 0x4e200
+ 0xe2, // Bit Rate: 320000 = 0x4e200
+ 0x00, // Bit Rate: 320000 = 0x4e200
+ 7, // Dummy
+ 8, // Dummy
+ 9 // Dummy
+};
+
+const uint8_t codec_info_non_a2dp[AVDT_CODEC_SIZE] = {
+ 8, // Length
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 0xFF, // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
+ 3, 4, 0, 0, // Vendor ID: LSB first, upper two octets should be 0
+ 7, 8, // Codec ID: LSB first
+ 9 // Dummy
+};
+
+const uint8_t codec_info_non_a2dp_dummy[AVDT_CODEC_SIZE] = {
+ 8, // Length
+ 0, // Media Type: AVDT_MEDIA_TYPE_AUDIO
+ 0xFF, // Media Codec Type: A2DP_MEDIA_CT_NON_A2DP
+ 3, 4, 0, 0, // Vendor ID: LSB first, upper two octets should be 0
+ 7, 8, // Codec ID: LSB first
+ 10 // Dummy
+};
+
+static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
+static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
+static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
+
+static bool has_shared_library(const char* name) {
+ void* lib_handle = dlopen(name, RTLD_NOW);
+ if (lib_handle != nullptr) {
+ dlclose(lib_handle);
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+class StackA2dpTest : public ::testing::Test {
+ protected:
+ StackA2dpTest() {
+ // Create the set with all supported codecs
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1);
+#else
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX;
+#endif
+ i++) {
+ btav_a2dp_codec_index_t codec_index =
+ static_cast<btav_a2dp_codec_index_t>(i);
+
+ bool supported = false;
+ switch (codec_index) {
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
+ supported = true;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
+ supported = true;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
+ // Codec aptX is supported only if the device has the corresponding
+ // shared library installed.
+ supported = has_shared_library(APTX_ENCODER_LIB_NAME);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
+ // Codec aptX-HD is supported only if the device has the corresponding
+ // shared library installed.
+ supported = has_shared_library(APTX_HD_ENCODER_LIB_NAME);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
+ // Codec LDAC is supported only if the device has the corresponding
+ // shared library installed.
+ supported = has_shared_library(LDAC_ENCODER_LIB_NAME);
+ break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ supported = true;
+ break;
+ case BTAV_A2DP_CODEC_INDEX_MAX:
+ // Needed to avoid using "default:" case so we can capture when
+ // a new codec is added, and it can be included here.
+ break;
+ }
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ if (BTAV_A2DP_CODEC_INDEX_SINK_AAC == codec_index)
+ supported = true;
+#endif
+
+ if (supported) {
+ supported_codecs_.insert(codec_index);
+ }
+ }
+ }
+
+ bool has_codec_support(btav_a2dp_codec_index_t codec_index) {
+ return supported_codecs_.find(codec_index) != supported_codecs_.end();
+ }
+
+ private:
+ std::set<btav_a2dp_codec_index_t> supported_codecs_;
+};
+
+class A2dpCodecConfigTest : public StackA2dpTest {};
+
+TEST_F(StackA2dpTest, test_a2dp_bits_set) {
+ EXPECT_TRUE(A2DP_BitsSet(0x0) == A2DP_SET_ZERO_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x1) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x2) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x3) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x7f) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x80) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x81) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xc0) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xff) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x8000) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x8001) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xc000) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xffff) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x80000) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x80001) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xc0000) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xfffff) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x80000000) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x80000001) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xc0000000) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xffffffff) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x8000000000000000) == A2DP_SET_ONE_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0x8000000000000001) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xc000000000000000) == A2DP_SET_MULTL_BIT);
+ EXPECT_TRUE(A2DP_BitsSet(0xffffffffffffffff) == A2DP_SET_MULTL_BIT);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_sbc) {
+ EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_sbc));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecValid(codec_info_sbc));
+
+ EXPECT_TRUE(A2DP_IsSinkCodecValid(codec_info_sbc_sink_capability));
+ EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_sink_capability));
+
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_non_a2dp));
+
+ // Test with invalid SBC codecs
+ uint8_t codec_info_sbc_invalid[AVDT_CODEC_SIZE];
+ memset(codec_info_sbc_invalid, 0, sizeof(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+
+ memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_invalid[0] = 0; // Corrupt the Length field
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+
+ memcpy(codec_info_sbc_invalid, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_invalid[1] = 0xff; // Corrupt the Media Type field
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsSinkCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecValid(codec_info_sbc_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_sbc_invalid));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_is_codec_valid_aac) {
+ EXPECT_TRUE(A2DP_IsSourceCodecValid(codec_info_aac));
+ EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_capability));
+ EXPECT_TRUE(A2DP_IsPeerSinkCodecValid(codec_info_aac_sink_capability));
+
+ // Test with invalid AAC codecs
+ uint8_t codec_info_aac_invalid[AVDT_CODEC_SIZE];
+ memset(codec_info_aac_invalid, 0, sizeof(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
+
+ memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
+ codec_info_aac_invalid[0] = 0; // Corrupt the Length field
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
+
+ memcpy(codec_info_aac_invalid, codec_info_aac, sizeof(codec_info_aac));
+ codec_info_aac_invalid[1] = 0xff; // Corrupt the Media Type field
+ EXPECT_FALSE(A2DP_IsSourceCodecValid(codec_info_aac_invalid));
+ EXPECT_FALSE(A2DP_IsPeerSinkCodecValid(codec_info_aac_invalid));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_codec_type) {
+ tA2DP_CODEC_TYPE codec_type = A2DP_GetCodecType(codec_info_sbc);
+ EXPECT_EQ(codec_type, A2DP_MEDIA_CT_SBC);
+
+ codec_type = A2DP_GetCodecType(codec_info_aac);
+ EXPECT_EQ(codec_type, A2DP_MEDIA_CT_AAC);
+
+ codec_type = A2DP_GetCodecType(codec_info_non_a2dp);
+ EXPECT_EQ(codec_type, A2DP_MEDIA_CT_NON_A2DP);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_is_sink_codec_supported) {
+ EXPECT_TRUE(A2DP_IsSinkCodecSupported(codec_info_sbc));
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_sbc_sink_capability));
+
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac));
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_capability));
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_aac_sink_capability));
+
+ EXPECT_FALSE(A2DP_IsSinkCodecSupported(codec_info_non_a2dp));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_is_peer_source_codec_supported) {
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc));
+ EXPECT_TRUE(A2DP_IsPeerSourceCodecSupported(codec_info_sbc_sink_capability));
+
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_capability));
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_aac_sink_capability));
+
+ EXPECT_FALSE(A2DP_IsPeerSourceCodecSupported(codec_info_non_a2dp));
+}
+
+TEST_F(StackA2dpTest, test_init_default_codec) {
+ uint8_t codec_info_result[AVDT_CODEC_SIZE];
+
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ A2DP_InitDefaultCodec(codec_info_result);
+
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+ }
+}
+
+TEST_F(StackA2dpTest, test_build_src2sink_config) {
+ uint8_t codec_info_result[AVDT_CODEC_SIZE];
+
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc, codec_info_result),
+ A2DP_SUCCESS);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+ }
+
+ // Include extra (less preferred) capabilities and test again - SBC
+ uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
+ memcpy(codec_info_sbc_test1, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_test1[3] |= (A2DP_SBC_IE_CH_MD_STEREO |
+ A2DP_SBC_IE_CH_MD_DUAL | A2DP_SBC_IE_CH_MD_MONO);
+ codec_info_sbc_test1[4] |=
+ (A2DP_SBC_IE_BLOCKS_12 | A2DP_SBC_IE_BLOCKS_8 | A2DP_SBC_IE_BLOCKS_4);
+ codec_info_sbc_test1[4] |= A2DP_SBC_IE_SUBBAND_4;
+ codec_info_sbc_test1[4] |= A2DP_SBC_IE_ALLOC_MD_S;
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ EXPECT_EQ(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
+ A2DP_SUCCESS);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+ }
+
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_aac, codec_info_result),
+ A2DP_SUCCESS);
+
+ // Test invalid codec info
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
+ EXPECT_NE(A2DP_BuildSrc2SinkConfig(codec_info_sbc_test1, codec_info_result),
+ A2DP_SUCCESS);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_uses_rtp_header) {
+ EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_sbc));
+ EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_sbc));
+
+ EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_aac));
+ EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_aac));
+
+ EXPECT_TRUE(A2DP_UsesRtpHeader(true, codec_info_non_a2dp));
+ EXPECT_TRUE(A2DP_UsesRtpHeader(false, codec_info_non_a2dp));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_media_type) {
+ uint8_t codec_info_test[AVDT_CODEC_SIZE];
+
+ EXPECT_EQ(A2DP_GetMediaType(codec_info_sbc), AVDT_MEDIA_TYPE_AUDIO);
+ EXPECT_EQ(A2DP_GetMediaType(codec_info_aac), AVDT_MEDIA_TYPE_AUDIO);
+ EXPECT_EQ(A2DP_GetMediaType(codec_info_non_a2dp), AVDT_MEDIA_TYPE_AUDIO);
+
+ // Prepare dummy codec info for video and for multimedia
+ memset(codec_info_test, 0, sizeof(codec_info_test));
+ codec_info_test[0] = sizeof(codec_info_test);
+ codec_info_test[1] = 0x01 << 4;
+ EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_VIDEO);
+ codec_info_test[1] = 0x02 << 4;
+ EXPECT_EQ(A2DP_GetMediaType(codec_info_test), AVDT_MEDIA_TYPE_MULTI);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_codec_name) {
+ uint8_t codec_info_test[AVDT_CODEC_SIZE];
+
+ // Explicit tests for known codecs
+ EXPECT_STREQ(A2DP_CodecName(codec_info_sbc), "SBC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_sbc_sink_capability), "SBC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_aac), "AAC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_aac_capability), "AAC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_aac_sink_capability), "AAC");
+ EXPECT_STREQ(A2DP_CodecName(codec_info_non_a2dp), "UNKNOWN VENDOR CODEC");
+
+ // Test all unknown codecs
+ memcpy(codec_info_test, codec_info_sbc, sizeof(codec_info_sbc));
+ for (uint8_t codec_type = A2DP_MEDIA_CT_AAC + 1;
+ codec_type < A2DP_MEDIA_CT_NON_A2DP; codec_type++) {
+ codec_info_test[2] = codec_type; // Unknown codec type
+ EXPECT_STREQ(A2DP_CodecName(codec_info_test), "UNKNOWN CODEC");
+ }
+}
+
+TEST_F(StackA2dpTest, test_a2dp_vendor) {
+ EXPECT_EQ(A2DP_VendorCodecGetVendorId(codec_info_non_a2dp),
+ (uint32_t)0x00000403);
+ EXPECT_EQ(A2DP_VendorCodecGetCodecId(codec_info_non_a2dp), (uint16_t)0x0807);
+ EXPECT_TRUE(A2DP_VendorUsesRtpHeader(true, codec_info_non_a2dp));
+ EXPECT_TRUE(A2DP_VendorUsesRtpHeader(false, codec_info_non_a2dp));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_codec_type_equals) {
+ EXPECT_TRUE(
+ A2DP_CodecTypeEquals(codec_info_sbc, codec_info_sbc_sink_capability));
+ EXPECT_TRUE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_capability));
+ EXPECT_TRUE(
+ A2DP_CodecTypeEquals(codec_info_aac, codec_info_aac_sink_capability));
+ EXPECT_TRUE(
+ A2DP_CodecTypeEquals(codec_info_non_a2dp, codec_info_non_a2dp_dummy));
+ EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_aac, codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_CodecTypeEquals(codec_info_sbc, codec_info_aac));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_codec_equals) {
+ uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+ uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
+ uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
+
+ // Test two identical SBC codecs
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+ // Test two identical AAC codecs
+ memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+ memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+ EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+
+ // Test two identical non-A2DP codecs that are not recognized
+ memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
+ memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
+ sizeof(codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_non_a2dp, codec_info_non_a2dp_test));
+
+ // Test two codecs that have different types
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_aac));
+
+ // Test two SBC codecs that are slightly different
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_test[5] = codec_info_sbc[5] + 1;
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+ codec_info_sbc_test[5] = codec_info_sbc[5];
+ codec_info_sbc_test[6] = codec_info_sbc[6] + 1;
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+ // Test two AAC codecs that are slightly different
+ memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+ memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+ codec_info_aac_test[7] = codec_info_aac[7] + 1;
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+ codec_info_aac_test[7] = codec_info_aac[7];
+ codec_info_aac_test[8] = codec_info_aac[8] + 1;
+ EXPECT_FALSE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+
+ // Test two SBC codecs that are identical, but with different dummy
+ // trailer data.
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_test[7] = codec_info_sbc[7] + 1;
+ EXPECT_TRUE(A2DP_CodecEquals(codec_info_sbc, codec_info_sbc_test));
+
+ // Test two AAC codecs that are identical, but with different dummy
+ // trailer data.
+ memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+ memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+ codec_info_aac_test[9] = codec_info_aac[9] + 1;
+ EXPECT_TRUE(A2DP_CodecEquals(codec_info_aac, codec_info_aac_test));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_track_sample_rate) {
+ EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_sbc), 44100);
+ EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_aac), 44100);
+ EXPECT_EQ(A2DP_GetTrackSampleRate(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_track_bits_per_sample) {
+ EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_sbc), 16);
+ EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_aac), 16);
+ EXPECT_EQ(A2DP_GetTrackBitsPerSample(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_track_channel_count) {
+ EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_sbc), 2);
+ EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_aac), 2);
+ EXPECT_EQ(A2DP_GetTrackChannelCount(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_number_of_subbands_sbc) {
+ EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_sbc), 8);
+ EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetNumberOfSubbandsSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_number_of_blocks_sbc) {
+ EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_sbc), 16);
+ EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetNumberOfBlocksSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_allocation_method_code_sbc) {
+ EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_sbc), 0);
+ EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetAllocationMethodCodeSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_sbc) {
+ EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_sbc), 3);
+ EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetChannelModeCodeSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_sampling_frequency_code_sbc) {
+ EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_sbc), 2);
+ EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetSamplingFrequencyCodeSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_min_bitpool_sbc) {
+ EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc), 2);
+ EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_sbc_sink_capability), 2);
+ EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetMinBitpoolSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_max_bitpool_sbc) {
+ EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc), 53);
+ EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_sbc_sink_capability), 53);
+ EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetMaxBitpoolSbc(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_sink_track_channel_type) {
+ EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_sbc), 3);
+ EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetSinkTrackChannelType(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_sink_frames_count_to_process) {
+ EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_sbc), 7);
+ EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_aac), -1);
+ EXPECT_EQ(A2DP_GetSinkFramesCountToProcess(20, codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_object_type_code_aac) {
+ EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_sbc), -1);
+ EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_aac), 0x80);
+ EXPECT_EQ(A2DP_GetObjectTypeCodeAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_channel_mode_code_aac) {
+ EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_sbc), -1);
+ EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_aac), 0x04);
+ EXPECT_EQ(A2DP_GetChannelModeCodeAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_variable_bit_rate_support_aac) {
+ EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_sbc), -1);
+ EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_aac), 0);
+ EXPECT_EQ(A2DP_GetVariableBitRateSupportAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_bit_rate_aac) {
+ EXPECT_EQ(A2DP_GetBitRateAac(codec_info_sbc), -1);
+ EXPECT_EQ(A2DP_GetBitRateAac(codec_info_aac), 320000);
+ EXPECT_EQ(A2DP_GetBitRateAac(codec_info_non_a2dp), -1);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_get_packet_timestamp) {
+ uint8_t a2dp_data[1000];
+ uint32_t timestamp;
+ uint32_t* p_ts = reinterpret_cast<uint32_t*>(a2dp_data);
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ *p_ts = 0x12345678;
+ timestamp = 0xFFFFFFFF;
+ EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_sbc, a2dp_data, &timestamp));
+ EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ *p_ts = 0x12345678;
+ timestamp = 0xFFFFFFFF;
+ EXPECT_TRUE(A2DP_GetPacketTimestamp(codec_info_aac, a2dp_data, &timestamp));
+ EXPECT_EQ(timestamp, static_cast<uint32_t>(0x12345678));
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ *p_ts = 0x12345678;
+ timestamp = 0xFFFFFFFF;
+ EXPECT_FALSE(
+ A2DP_GetPacketTimestamp(codec_info_non_a2dp, a2dp_data, &timestamp));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_build_codec_header) {
+ uint8_t a2dp_data[1000];
+ BT_HDR* p_buf = reinterpret_cast<BT_HDR*>(a2dp_data);
+ const uint16_t BT_HDR_LEN = 500;
+ const uint16_t BT_HDR_OFFSET = 50;
+ const uint8_t FRAMES_PER_PACKET = 0xCD;
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ p_buf->len = BT_HDR_LEN;
+ p_buf->offset = BT_HDR_OFFSET;
+ EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_sbc, p_buf, FRAMES_PER_PACKET));
+ EXPECT_EQ(p_buf->offset + 1,
+ BT_HDR_OFFSET); // Modified by A2DP_SBC_MPL_HDR_LEN
+ EXPECT_EQ(p_buf->len - 1, BT_HDR_LEN); // Modified by A2DP_SBC_MPL_HDR_LEN
+ const uint8_t* p =
+ reinterpret_cast<const uint8_t*>(p_buf + 1) + p_buf->offset;
+ EXPECT_EQ(
+ *p, static_cast<uint8_t>(0x0D)); // 0xCD masked with A2DP_SBC_HDR_NUM_MSK
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ p_buf->len = BT_HDR_LEN;
+ p_buf->offset = BT_HDR_OFFSET;
+ EXPECT_TRUE(A2DP_BuildCodecHeader(codec_info_aac, p_buf, FRAMES_PER_PACKET));
+
+ memset(a2dp_data, 0xAB, sizeof(a2dp_data));
+ p_buf->len = BT_HDR_LEN;
+ p_buf->offset = BT_HDR_OFFSET;
+ EXPECT_FALSE(
+ A2DP_BuildCodecHeader(codec_info_non_a2dp, p_buf, FRAMES_PER_PACKET));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_adjust_codec) {
+ uint8_t codec_info_sbc_test[AVDT_CODEC_SIZE];
+ uint8_t codec_info_aac_test[AVDT_CODEC_SIZE];
+ uint8_t codec_info_non_a2dp_test[AVDT_CODEC_SIZE];
+
+ // Test updating a valid SBC codec that doesn't need adjustment
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
+ EXPECT_TRUE(
+ memcmp(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc)) == 0);
+
+ // Test updating a valid SBC codec that needs adjustment
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_test[6] = 54; // A2DP_SBC_MAX_BITPOOL + 1
+ EXPECT_TRUE(A2DP_AdjustCodec(codec_info_sbc_test));
+ EXPECT_TRUE(
+ memcmp(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc)) == 0);
+
+ // Test updating an invalid SBC codec
+ memset(codec_info_sbc_test, 0xAB, sizeof(codec_info_sbc_test));
+ memcpy(codec_info_sbc_test, codec_info_sbc, sizeof(codec_info_sbc));
+ codec_info_sbc_test[6] = 255; // Invalid MAX_BITPOOL
+ EXPECT_FALSE(A2DP_AdjustCodec(codec_info_sbc_test));
+
+ // Test updating a valid AAC codec that doesn't need adjustment
+ memset(codec_info_aac_test, 0xAB, sizeof(codec_info_aac_test));
+ memcpy(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac));
+ EXPECT_TRUE(A2DP_AdjustCodec(codec_info_aac_test));
+ EXPECT_TRUE(
+ memcmp(codec_info_aac_test, codec_info_aac, sizeof(codec_info_aac)) == 0);
+
+ // Test updating a non-A2DP codec that is not recognized
+ memset(codec_info_non_a2dp_test, 0xAB, sizeof(codec_info_non_a2dp_test));
+ memcpy(codec_info_non_a2dp_test, codec_info_non_a2dp,
+ sizeof(codec_info_non_a2dp));
+ EXPECT_FALSE(A2DP_AdjustCodec(codec_info_non_a2dp_test));
+}
+
+TEST_F(StackA2dpTest, test_a2dp_source_codec_index) {
+ // Explicit tests for known codecs
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_sbc_sink_capability),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_SBC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_capability),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_aac_sink_capability),
+ BTAV_A2DP_CODEC_INDEX_SOURCE_AAC);
+ EXPECT_EQ(A2DP_SourceCodecIndex(codec_info_non_a2dp),
+ BTAV_A2DP_CODEC_INDEX_MAX);
+}
+
+TEST_F(StackA2dpTest, test_a2dp_codec_index_str) {
+ // Explicit tests for known codecs
+ EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC), "SBC");
+ EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_SBC), "SBC SINK");
+ EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC), "AAC");
+ #if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_SINK_AAC), "AAC SINK");
+ #endif
+
+ // Test that the unknown codec string has not changed
+ EXPECT_STREQ(A2DP_CodecIndexStr(BTAV_A2DP_CODEC_INDEX_MAX),
+ "UNKNOWN CODEC INDEX");
+
+ // Test that each codec has a known string
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ btav_a2dp_codec_index_t codec_index =
+ static_cast<btav_a2dp_codec_index_t>(i);
+ EXPECT_STRNE(A2DP_CodecIndexStr(codec_index), "UNKNOWN CODEC INDEX");
+ }
+}
+
+TEST_F(StackA2dpTest, test_a2dp_init_codec_config) {
+ tAVDT_CFG avdt_cfg;
+
+ //
+ // Test for SBC Source
+ //
+ memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+ EXPECT_TRUE(
+ A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, &avdt_cfg));
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc[i]);
+ }
+// Test for content protection
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC);
+ EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF));
+ EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF));
+ EXPECT_EQ(avdt_cfg.num_protect, 1);
+#endif
+
+ //
+ // Test for SBC Sink
+ //
+ memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+ EXPECT_TRUE(A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_SBC, &avdt_cfg));
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc_sink_capability[0] + 1; i++) {
+ EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_sbc_sink_capability[i]);
+ }
+
+ //
+ // Test for AAC Source
+ //
+ memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+ EXPECT_TRUE(
+ A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SOURCE_AAC, &avdt_cfg));
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_aac_capability[0] + 1; i++) {
+ EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_aac_capability[i]);
+ }
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ //
+ // Test for AAC Sink
+ //
+ memset(&avdt_cfg, 0, sizeof(avdt_cfg));
+ EXPECT_TRUE(
+ A2DP_InitCodecConfig(BTAV_A2DP_CODEC_INDEX_SINK_AAC, &avdt_cfg));
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_aac_sink_capability[0] + 1; i++) {
+ EXPECT_EQ(avdt_cfg.codec_info[i], codec_info_aac_sink_capability[i]);
+ }
+#endif
+// Test for content protection
+#if (BTA_AV_CO_CP_SCMS_T == TRUE)
+ EXPECT_EQ(avdt_cfg.protect_info[0], AVDT_CP_LOSC);
+ EXPECT_EQ(avdt_cfg.protect_info[1], (AVDT_CP_SCMS_T_ID & 0xFF));
+ EXPECT_EQ(avdt_cfg.protect_info[2], ((AVDT_CP_SCMS_T_ID >> 8) & 0xFF));
+ EXPECT_EQ(avdt_cfg.num_protect, 1);
+#endif
+}
+
+TEST_F(A2dpCodecConfigTest, createCodec) {
+#if defined(MTK_A2DP_SNK_AAC_CODEC) && (MTK_A2DP_SNK_AAC_CODEC == TRUE)
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < (BTAV_A2DP_CODEC_INDEX_MAX + 1); i++) {
+#else
+ for (int i = BTAV_A2DP_CODEC_INDEX_MIN; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
+#endif
+ btav_a2dp_codec_index_t codec_index =
+ static_cast<btav_a2dp_codec_index_t>(i);
+
+ // Ignore codecs that are not supported on the device
+ if (!has_codec_support(codec_index)) {
+ continue;
+ }
+
+ A2dpCodecConfig* codec_config = A2dpCodecConfig::createCodec(codec_index);
+ EXPECT_NE(codec_config, nullptr);
+ EXPECT_EQ(codec_config->codecIndex(), codec_index);
+ EXPECT_FALSE(codec_config->name().empty());
+ EXPECT_NE(codec_config->codecPriority(), BTAV_A2DP_CODEC_PRIORITY_DISABLED);
+ EXPECT_NE(codec_config->codecPriority(), BTAV_A2DP_CODEC_PRIORITY_DEFAULT);
+ delete codec_config;
+ }
+}
+
+TEST_F(A2dpCodecConfigTest, setCodecConfig) {
+ uint8_t codec_info_result[AVDT_CODEC_SIZE];
+ btav_a2dp_codec_index_t peer_codec_index;
+ A2dpCodecs* a2dp_codecs =
+ new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());
+ A2dpCodecConfig* codec_config;
+
+ EXPECT_TRUE(a2dp_codecs->init());
+
+ // Create the codec capability - SBC
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc_sink_capability);
+ EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+ codec_config =
+ a2dp_codecs->findSourceCodecConfig(codec_info_sbc_sink_capability);
+ EXPECT_NE(codec_config, nullptr);
+ EXPECT_TRUE(a2dp_codecs->setCodecConfig(
+ codec_info_sbc_sink_capability, true /* is_capability */,
+ codec_info_result, true /* select_current_codec */));
+ EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+ }
+
+ // Create the codec capability - AAC
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac_sink_capability);
+ EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+ codec_config =
+ a2dp_codecs->findSourceCodecConfig(codec_info_aac_sink_capability);
+ EXPECT_NE(codec_config, nullptr);
+ EXPECT_TRUE(a2dp_codecs->setCodecConfig(
+ codec_info_aac_sink_capability, true /* is_capability */,
+ codec_info_result, true /* select_current_codec */));
+ EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+ }
+
+ // Create the codec config - SBC
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ peer_codec_index = A2DP_SourceCodecIndex(codec_info_sbc);
+ EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+ codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_sbc);
+ EXPECT_NE(codec_config, nullptr);
+ EXPECT_TRUE(a2dp_codecs->setCodecConfig(
+ codec_info_sbc, false /* is_capability */, codec_info_result,
+ true /* select_current_codec */));
+ EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_sbc[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_sbc[i]);
+ }
+ EXPECT_FALSE(codec_config->useRtpHeaderMarkerBit());
+
+ // Create the codec config - AAC
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ peer_codec_index = A2DP_SourceCodecIndex(codec_info_aac);
+ EXPECT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
+ codec_config = a2dp_codecs->findSourceCodecConfig(codec_info_aac);
+ EXPECT_NE(codec_config, nullptr);
+ EXPECT_TRUE(a2dp_codecs->setCodecConfig(
+ codec_info_aac, false /* is_capability */, codec_info_result,
+ true /* select_current_codec */));
+ EXPECT_EQ(a2dp_codecs->getCurrentCodecConfig(), codec_config);
+ // Compare the result codec with the local test codec info
+ for (size_t i = 0; i < codec_info_aac[0] + 1; i++) {
+ EXPECT_EQ(codec_info_result[i], codec_info_aac[i]);
+ }
+ EXPECT_TRUE(codec_config->useRtpHeaderMarkerBit());
+
+ // Test invalid codec info
+ uint8_t codec_info_sbc_test1[AVDT_CODEC_SIZE];
+ memset(codec_info_result, 0, sizeof(codec_info_result));
+ memset(codec_info_sbc_test1, 0, sizeof(codec_info_sbc_test1));
+ EXPECT_FALSE(a2dp_codecs->setCodecConfig(
+ codec_info_sbc_test1, true /* is_capability */, codec_info_result,
+ true /* select_current_codec */));
+ delete a2dp_codecs;
+}
+
+TEST_F(A2dpCodecConfigTest, init) {
+ std::vector<btav_a2dp_codec_config_t> default_priorities;
+ A2dpCodecs codecs(default_priorities);
+
+ EXPECT_TRUE(codecs.init());
+
+ const std::list<A2dpCodecConfig*> orderedSourceCodecs =
+ codecs.orderedSourceCodecs();
+ EXPECT_FALSE(orderedSourceCodecs.empty());
+
+ const std::list<A2dpCodecConfig*> orderedSinkCodecs =
+ codecs.orderedSinkCodecs();
+ EXPECT_FALSE(orderedSinkCodecs.empty());
+}
diff --git a/mtkbt/code/bt/stack/test/stack_smp_test.cc b/mtkbt/code/bt/stack/test/stack_smp_test.cc
new file mode 100755
index 0000000..04b472d
--- a/dev/null
+++ b/mtkbt/code/bt/stack/test/stack_smp_test.cc
@@ -0,0 +1,227 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#include <stdarg.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "bt_trace.h"
+#include "hcidefs.h"
+#include "stack/include/smp_api.h"
+#include "stack/smp/smp_int.h"
+
+/*
+ * This test verifies various key distribution methods in SMP works using the
+ * following parameter set:
+ *
+ * When testing target as Master (Initiator is local, Responder is remote)
+ *
+ * Initiator's Pairing Request: 0x070710000001(01)
+ * Responder's Pairing Response: 0x050008000003(02)
+ * Initiator's Bluetooth Address: 0xA1A2A3A4A5A6
+ * Initiator's Bluetooth Address Type: 0x01
+ * Responder's Bluetooth Address: 0xB1B2B3B4B5B6
+ * Responder's Bluetooth Address Type: 0x00
+ * Initiator's Random Number: 0x5783D52156AD6F0E6388274EC6702EE0
+ * TK Encryption Key: 0x0
+ *
+ * Correct values:
+ *
+ * p1: 0x05000800000302070710000001010001
+ * p1 XOR r: 0x5283dd2156ae6d096498274ec7712ee1
+ * p1 prime: 0x02c7aa2a9857ac866ff91232df0e3c95
+ * p2: 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
+ * MConfirm (c1): 0x1e1e3fef878988ead2a74dc5bef13b86
+ *
+ * NOTE: All these values are presented in mathematical reasonable canonical
+ * form that has MSB on the left and LSB on the right. In Bluetooth packets,
+ * they are mostly reversed to be Little Endian which have LSB on the left and
+ * MSB on the right.
+ */
+
+// Set remote bda to 0xB1B2B3B4B5B6
+bool BTM_ReadRemoteConnectionAddr(BD_ADDR pseudo_addr, BD_ADDR conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ const uint8_t local_bda[] = {0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6};
+ memcpy(conn_addr, local_bda, sizeof(local_bda));
+ *p_addr_type = 0x00;
+ return true;
+}
+
+// Set local_bda to 0xA1A2A3A4A5A6
+void BTM_ReadConnectionAddr(BD_ADDR remote_bda, BD_ADDR local_conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ const uint8_t local_bda[] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6};
+ memcpy(local_conn_addr, local_bda, sizeof(local_bda));
+ *p_addr_type = 0x01;
+}
+
+// Require bte_logmsg.cc to run, here is just to fake it as we don't care about
+// trace in unit test
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {
+ va_list args;
+ va_start(args, fmt_str);
+ vprintf(fmt_str, args);
+ va_end(args);
+}
+
+extern void smp_gen_p1_4_confirm(tSMP_CB* p_cb,
+ tBLE_ADDR_TYPE remote_bd_addr_type,
+ BT_OCTET16 p1);
+
+extern void smp_gen_p2_4_confirm(tSMP_CB* p_cb, BD_ADDR remote_bda,
+ BT_OCTET16 p2);
+
+extern tSMP_STATUS smp_calculate_comfirm(tSMP_CB* p_cb, BT_OCTET16 rand,
+ tSMP_ENC* output);
+
+namespace testing {
+
+void dump_uint128(BT_OCTET16 a, char* buffer) {
+ for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+ snprintf(buffer, 3, "%02x", a[i]);
+ buffer += 2;
+ }
+ *buffer = '\0';
+}
+
+void dump_uint128_reverse(BT_OCTET16 a, char* buffer) {
+ for (int i = (int)(sizeof(BT_OCTET16) - 1); i >= 0; --i) {
+ snprintf(buffer, 3, "%02x", a[i]);
+ buffer += 2;
+ }
+ *buffer = '\0';
+}
+
+void print_uint128(BT_OCTET16 a) {
+ for (unsigned int i = 0; i < sizeof(BT_OCTET16); ++i) {
+ printf("%02x", a[i]);
+ }
+ printf("\n");
+}
+
+void parse_uint128(const char* input, BT_OCTET16 output) {
+ memset(output, 0, sizeof(BT_OCTET16));
+ for (unsigned int count = 0; count < sizeof(BT_OCTET16); count++) {
+ sscanf(input, "%2hhx", &output[count]);
+ input += 2;
+ }
+}
+
+void reverse_array_inplace(BT_OCTET16 a) {
+ uint8_t tmp;
+ uint8_t* a_end = a + sizeof(BT_OCTET16) - 1;
+ while (a_end > a) {
+ tmp = *a_end;
+ *a_end = *a;
+ *a = tmp;
+ ++a;
+ --a_end;
+ }
+}
+
+class SmpCalculateConfirmTest : public Test {
+ protected:
+ tSMP_CB p_cb_;
+ // Set random to 0x5783D52156AD6F0E6388274EC6702EE0
+ BT_OCTET16 rand_ = {0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
+ 0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
+
+ void SetUp() {
+ memset(p_cb_.tk, 0, sizeof(p_cb_.tk));
+ // Set pairing request packet to 0x070710000001(01)
+ p_cb_.local_io_capability = 0x01;
+ p_cb_.loc_oob_flag = 0x00;
+ p_cb_.loc_auth_req = 0x00;
+ p_cb_.loc_enc_size = 0x10;
+ p_cb_.local_i_key = 0x07;
+ p_cb_.local_r_key = 0x07;
+ // Set pairing response packet to 0x050008000003(02)
+ p_cb_.peer_io_caps = 0x03;
+ p_cb_.peer_oob_flag = 0x00;
+ p_cb_.peer_auth_req = 0x00;
+ p_cb_.peer_enc_size = 0x08;
+ p_cb_.peer_i_key = 0x00;
+ p_cb_.peer_r_key = 0x05;
+ // Set role to master
+ p_cb_.role = HCI_ROLE_MASTER;
+ reverse_array_inplace(rand_);
+ }
+ void TearDown() {}
+
+ public:
+};
+
+// Test smp_gen_p2_4_confirm function implementation
+TEST_F(SmpCalculateConfirmTest, test_smp_gen_p2_4_confirm_as_master) {
+ BT_OCTET16 p2;
+ BD_ADDR remote_bda;
+ tBLE_ADDR_TYPE remote_bd_addr_type = 0;
+ BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
+ &remote_bd_addr_type);
+ BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
+ smp_gen_p2_4_confirm(&p_cb_, remote_bda, p2);
+ // Correct p2 is 0x00000000a1a2a3a4a5a6b1b2b3b4b5b6
+ const char expected_p2_str[] = "00000000a1a2a3a4a5a6b1b2b3b4b5b6";
+ char p2_str[2 * sizeof(BT_OCTET16) + 1];
+ dump_uint128_reverse(p2, p2_str);
+ ASSERT_THAT(p2_str, StrEq(expected_p2_str));
+}
+
+// Test smp_gen_p1_4_confirm and SMP_Encrypt function implementation
+TEST_F(SmpCalculateConfirmTest, test_SMP_Encrypt_as_master) {
+ BT_OCTET16 p1;
+ BD_ADDR remote_bda;
+ tBLE_ADDR_TYPE remote_bd_addr_type = 0;
+ BTM_ReadRemoteConnectionAddr(p_cb_.pairing_bda, remote_bda,
+ &remote_bd_addr_type);
+ BTM_ReadConnectionAddr(p_cb_.pairing_bda, p_cb_.local_bda, &p_cb_.addr_type);
+ smp_gen_p1_4_confirm(&p_cb_, remote_bd_addr_type, p1);
+ // Correct p1 is 0x05000800000302070710000001010001
+ const char expected_p1_str[] = "05000800000302070710000001010001";
+ char p1_str[2 * sizeof(BT_OCTET16) + 1];
+ dump_uint128_reverse(p1, p1_str);
+ ASSERT_THAT(p1_str, StrEq(expected_p1_str));
+ smp_xor_128(p1, rand_);
+ // Correct p1 xor r is 0x5283dd2156ae6d096498274ec7712ee1
+ const char expected_p1_xor_r_str[] = "5283dd2156ae6d096498274ec7712ee1";
+ char p1_xor_r_str[2 * sizeof(BT_OCTET16) + 1];
+ dump_uint128_reverse(p1, p1_xor_r_str);
+ ASSERT_THAT(p1_xor_r_str, StrEq(expected_p1_xor_r_str));
+ tSMP_ENC output;
+ memset(&output, 0, sizeof(tSMP_ENC));
+ ASSERT_TRUE(
+ SMP_Encrypt(p_cb_.tk, BT_OCTET16_LEN, p1, BT_OCTET16_LEN, &output));
+ const char expected_p1_prime_str[] = "02c7aa2a9857ac866ff91232df0e3c95";
+ char p1_prime_str[2 * sizeof(BT_OCTET16) + 1];
+ dump_uint128_reverse(output.param_buf, p1_prime_str);
+ ASSERT_THAT(p1_prime_str, StrEq(expected_p1_prime_str));
+}
+
+// Test smp_calculate_comfirm function implementation
+TEST_F(SmpCalculateConfirmTest, test_smp_calculate_comfirm_as_master) {
+ tSMP_ENC output;
+ tSMP_STATUS status = smp_calculate_comfirm(&p_cb_, rand_, &output);
+ EXPECT_EQ(status, SMP_SUCCESS);
+ // Correct MConfirm is 0x1e1e3fef878988ead2a74dc5bef13b86
+ const char expected_confirm_str[] = "1e1e3fef878988ead2a74dc5bef13b86";
+ char confirm_str[2 * sizeof(BT_OCTET16) + 1];
+ dump_uint128_reverse(output.param_buf, confirm_str);
+ ASSERT_THAT(confirm_str, StrEq(expected_confirm_str));
+}
+}
diff --git a/mtkbt/code/bt/test/Android.bp b/mtkbt/code/bt/test/Android.bp
new file mode 100755
index 0000000..8cf611e
--- a/dev/null
+++ b/mtkbt/code/bt/test/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+ "rootcanal",
+ "suite",
+]
diff --git a/mtkbt/code/bt/test/README.md b/mtkbt/code/bt/test/README.md
new file mode 100755
index 0000000..7b72f30
--- a/dev/null
+++ b/mtkbt/code/bt/test/README.md
@@ -0,0 +1,81 @@
+# Fluoride Bluetooth Tests
+
+This document refers to the tests in the system/bt/test directory.
+
+The tests are designed to be run when the Android runtime is not running. From a terminal, run:
+
+## Before you run tests
+```sh
+adb shell stop
+```
+
+## After you're done
+```sh
+adb shell start
+```
+
+## Running tests
+Then see what options the test script provides:
+
+```sh
+./run_unit_tests.sh --help
+```
+
+But for the impatient, run specific groups of tests like this:
+
+```sh
+./run_unit_tests.sh net_test_bluetooth
+```
+
+a single test:
+
+```sh
+./run_unit_tests.sh net_test_bluetooth.BluetoothTest.AdapterRepeatedEnableDisable
+```
+
+## Sample Output
+
+system/bt/test$ ./run_unit_tests.sh net_test_bluetooth
+--- net_test_bluetooth ---
+pushing...
+/tbd/aosp-master/out/target/product/bullhead/data/nativetest/n...st_bluetooth: 1 file pushed. 9.2 MB/s (211832 bytes in 0.022s)
+running...
+
+Running main() from gtest_main.cc
+[==========] Running 11 tests from 2 test cases.
+[----------] Global test environment set-up.
+[----------] 6 tests from BluetoothTest
+[ RUN ] BluetoothTest.AdapterEnableDisable
+[ OK ] BluetoothTest.AdapterEnableDisable (2538 ms)
+[ RUN ] BluetoothTest.AdapterRepeatedEnableDisable
+[ OK ] BluetoothTest.AdapterRepeatedEnableDisable (11384 ms)
+[ RUN ] BluetoothTest.AdapterSetGetName
+[ OK ] BluetoothTest.AdapterSetGetName (2378 ms)
+[ RUN ] BluetoothTest.AdapterStartDiscovery
+[ OK ] BluetoothTest.AdapterStartDiscovery (2397 ms)
+[ RUN ] BluetoothTest.AdapterCancelDiscovery
+[ OK ] BluetoothTest.AdapterCancelDiscovery (2401 ms)
+[ RUN ] BluetoothTest.AdapterDisableDuringBonding
+[ OK ] BluetoothTest.AdapterDisableDuringBonding (11689 ms)
+[----------] 6 tests from BluetoothTest (32789 ms total)
+
+[----------] 5 tests from GattTest
+[ RUN ] GattTest.GattClientRegister
+[ OK ] GattTest.GattClientRegister (2370 ms)
+[ RUN ] GattTest.GattClientScanRemoteDevice
+[ OK ] GattTest.GattClientScanRemoteDevice (2273 ms)
+[ RUN ] GattTest.GattClientAdvertise
+[ OK ] GattTest.GattClientAdvertise (2236 ms)
+[ RUN ] GattTest.GattServerRegister
+[ OK ] GattTest.GattServerRegister (2391 ms)
+[ RUN ] GattTest.GattServerBuild
+[ OK ] GattTest.GattServerBuild (2435 ms)
+[----------] 5 tests from GattTest (11706 ms total)
+
+[----------] Global test environment tear-down
+[==========] 11 tests from 2 test cases ran. (44495 ms total)
+[ PASSED ] 11 tests.
+
+## Troubleshooting: Your phone is bricked!
+Probably not. See [After you're done](#After-you're-done)
+
diff --git a/mtkbt/code/bt/test/rootcanal/Android.bp b/mtkbt/code/bt/test/rootcanal/Android.bp
new file mode 100755
index 0000000..a7c5d48
--- a/dev/null
+++ b/mtkbt/code/bt/test/rootcanal/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "android.hardware.bluetooth@1.0-service.sim",
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ "bluetooth_hci.cc",
+ "service.cc",
+ ],
+
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libbase",
+ "libchrome",
+ "libcutils",
+ "libhardware",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DHAS_NO_BDROID_BUILDCFG",
+ ],
+ static_libs: [
+ "android.hardware.bluetooth-async",
+ "android.hardware.bluetooth-hci",
+ "libbt-rootcanal",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ init_rc: ["android.hardware.bluetooth@1.0-service.sim.rc"],
+}
diff --git a/mtkbt/code/bt/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc b/mtkbt/code/bt/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
new file mode 100755
index 0000000..2f53e5d
--- a/dev/null
+++ b/mtkbt/code/bt/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
@@ -0,0 +1,4 @@
+service bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim
+ class hal
+ user bluetooth
+ group bluetooth
diff --git a/mtkbt/code/bt/test/rootcanal/bluetooth_hci.cc b/mtkbt/code/bt/test/rootcanal/bluetooth_hci.cc
new file mode 100755
index 0000000..413b31b
--- a/dev/null
+++ b/mtkbt/code/bt/test/rootcanal/bluetooth_hci.cc
@@ -0,0 +1,183 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "android.hardware.bluetooth@1.0.sim"
+
+#include "bluetooth_hci.h"
+
+#include <base/logging.h>
+#include <string.h>
+#include <utils/Log.h>
+
+#include "hci_internals.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace sim {
+
+using android::hardware::hidl_vec;
+using test_vendor_lib::AsyncManager;
+using test_vendor_lib::AsyncTaskId;
+using test_vendor_lib::CommandPacket;
+using test_vendor_lib::DualModeController;
+using test_vendor_lib::EventPacket;
+using test_vendor_lib::TaskCallback;
+using test_vendor_lib::TestChannelTransport;
+
+class BluetoothDeathRecipient : public hidl_death_recipient {
+ public:
+ BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
+
+ virtual void serviceDied(
+ uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+ ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+ has_died_ = true;
+ mHci->close();
+ }
+ sp<IBluetoothHci> mHci;
+ bool getHasDied() const { return has_died_; }
+ void setHasDied(bool has_died) { has_died_ = has_died; }
+
+ private:
+ bool has_died_;
+};
+
+BluetoothHci::BluetoothHci()
+ : death_recipient_(new BluetoothDeathRecipient(this)) {}
+
+Return<void> BluetoothHci::initialize(const sp<IBluetoothHciCallbacks>& cb) {
+ ALOGI("%s", __func__);
+
+ if (cb == nullptr) {
+ ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+ return Void();
+ }
+
+ death_recipient_->setHasDied(false);
+ cb->linkToDeath(death_recipient_, 0);
+
+ test_channel_transport_.RegisterCommandHandler(
+ [this](const std::string& name, const std::vector<std::string>& args) {
+ async_manager_.ExecAsync(
+ std::chrono::milliseconds(0), [this, name, args]() {
+ controller_.HandleTestChannelCommand(name, args);
+ });
+ });
+
+ controller_.RegisterEventChannel([cb](std::unique_ptr<EventPacket> event) {
+ size_t header_bytes = event->GetHeaderSize();
+ size_t payload_bytes = event->GetPayloadSize();
+ hidl_vec<uint8_t> hci_event;
+ hci_event.resize(header_bytes + payload_bytes);
+ memcpy(hci_event.data(), event->GetHeader().data(), header_bytes);
+ memcpy(hci_event.data() + header_bytes, event->GetPayload().data(),
+ payload_bytes);
+
+ cb->hciEventReceived(hci_event);
+ });
+
+ /* RegisterAcl and RegisterSco
+ cb->aclDataReceived(hci_packet);
+ cb->scoDataReceived(hci_packet);
+ */
+
+ controller_.RegisterTaskScheduler(
+ [this](std::chrono::milliseconds delay, const TaskCallback& task) {
+ return async_manager_.ExecAsync(delay, task);
+ });
+
+ controller_.RegisterPeriodicTaskScheduler(
+ [this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& task) {
+ return async_manager_.ExecAsyncPeriodically(delay, period, task);
+ });
+
+ controller_.RegisterTaskCancel(
+ [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
+
+ SetUpTestChannel(6111);
+
+ unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+ if (death_recipient->getHasDied())
+ ALOGI("Skipping unlink call, service died.");
+ else
+ cb->unlinkToDeath(death_recipient);
+ };
+
+ cb->initializationComplete(Status::SUCCESS);
+ return Void();
+}
+
+Return<void> BluetoothHci::close() {
+ ALOGI("%s", __func__);
+ return Void();
+}
+
+Return<void> BluetoothHci::sendHciCommand(const hidl_vec<uint8_t>& packet) {
+ async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
+ uint16_t opcode = packet[0] | (packet[1] << 8);
+ std::unique_ptr<CommandPacket> command =
+ std::unique_ptr<CommandPacket>(new CommandPacket(opcode));
+ for (size_t i = 3; i < packet.size(); i++)
+ command->AddPayloadOctets1(packet[i]);
+
+ controller_.HandleCommand(std::move(command));
+ });
+ return Void();
+}
+
+Return<void> BluetoothHci::sendAclData(const hidl_vec<uint8_t>& /* packet */) {
+ CHECK(false) << __func__ << " not yet implemented";
+ return Void();
+}
+
+Return<void> BluetoothHci::sendScoData(const hidl_vec<uint8_t>& /* packet */) {
+ CHECK(false) << __func__ << " not yet implemented";
+ return Void();
+}
+
+void BluetoothHci::SetUpTestChannel(int port) {
+ int socket_fd = test_channel_transport_.SetUp(port);
+
+ if (socket_fd == -1) {
+ ALOGE("Test channel SetUp(%d) failed.", port);
+ return;
+ }
+
+ ALOGI("Test channel SetUp() successful");
+ async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
+ int conn_fd = test_channel_transport_.Accept(socket_fd);
+ if (conn_fd < 0) {
+ ALOGE("Error watching test channel fd.");
+ return;
+ }
+ ALOGI("Test channel connection accepted.");
+ async_manager_.WatchFdForNonBlockingReads(conn_fd, [this](int conn_fd) {
+ test_channel_transport_.OnCommandReady(conn_fd, [this, conn_fd]() {
+ async_manager_.StopWatchingFileDescriptor(conn_fd);
+ });
+ });
+ });
+}
+
+} // namespace gce
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/mtkbt/code/bt/test/rootcanal/bluetooth_hci.h b/mtkbt/code/bt/test/rootcanal/bluetooth_hci.h
new file mode 100755
index 0000000..2ddf8ee
--- a/dev/null
+++ b/mtkbt/code/bt/test/rootcanal/bluetooth_hci.h
@@ -0,0 +1,79 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+
+#include <hidl/MQDescriptor.h>
+
+#include "hci_packetizer.h"
+
+#include "async_manager.h"
+#include "dual_mode_controller.h"
+#include "test_channel_transport.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace V1_0 {
+namespace sim {
+
+class BluetoothDeathRecipient;
+
+class BluetoothHci : public IBluetoothHci {
+ public:
+ BluetoothHci();
+
+ ::android::hardware::Return<void> initialize(
+ const sp<IBluetoothHciCallbacks>& cb) override;
+
+ ::android::hardware::Return<void> sendHciCommand(
+ const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+ ::android::hardware::Return<void> sendAclData(
+ const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+ ::android::hardware::Return<void> sendScoData(
+ const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
+ ::android::hardware::Return<void> close() override;
+
+ static void OnPacketReady();
+
+ static BluetoothHci* get();
+
+ private:
+ sp<BluetoothDeathRecipient> death_recipient_;
+
+ std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
+
+ void HandleIncomingPacket();
+
+ test_vendor_lib::AsyncManager async_manager_;
+
+ void SetUpTestChannel(int port);
+
+ test_vendor_lib::DualModeController controller_;
+
+ test_vendor_lib::TestChannelTransport test_channel_transport_;
+};
+
+} // namespace sim
+} // namespace V1_0
+} // namespace bluetooth
+} // namespace hardware
+} // namespace android
diff --git a/mtkbt/code/bt/test/rootcanal/service.cc b/mtkbt/code/bt/test/rootcanal/service.cc
new file mode 100755
index 0000000..e08f735
--- a/dev/null
+++ b/mtkbt/code/bt/test/rootcanal/service.cc
@@ -0,0 +1,40 @@
+//
+// Copyright 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "android.hardware.bluetooth@1.0-service.sim"
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+
+#include "bluetooth_hci.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::sim::BluetoothHci;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+int main(int /* argc */, char** /* argv */) {
+ sp<IBluetoothHci> bluetooth = new BluetoothHci;
+ configureRpcThreadpool(1, true);
+ android::status_t status = bluetooth->registerAsService();
+ if (status == android::OK)
+ joinRpcThreadpool();
+ else
+ ALOGE("Could not register as a service!");
+}
diff --git a/mtkbt/code/bt/test/run_unit_tests.sh b/mtkbt/code/bt/test/run_unit_tests.sh
new file mode 100755
index 0000000..f8488d7
--- a/dev/null
+++ b/mtkbt/code/bt/test/run_unit_tests.sh
@@ -0,0 +1,138 @@
+#!/bin/sh
+
+known_tests=(
+ bluetoothtbd_test
+ net_test_audio_a2dp_hw
+ net_test_bluetooth
+ net_test_btcore
+ net_test_bta
+ net_test_btif
+ net_test_device
+ net_test_hci
+ net_test_stack
+ net_test_stack_multi_adv
+ net_test_stack_ad_parser
+ net_test_stack_smp
+ net_test_osi
+)
+
+known_remote_tests=(
+ net_test_rfcomm
+)
+
+
+usage() {
+ binary="$(basename "$0")"
+ echo "Usage: ${binary} --help"
+ echo " ${binary} [-i <iterations>] [-s <specific device>] [--all] [<test name>[.<filter>] ...] [--<arg> ...]"
+ echo
+ echo "Unknown long arguments are passed to the test."
+ echo
+ echo "Known test names:"
+
+ for name in "${known_tests[@]}"
+ do
+ echo " ${name}"
+ done
+
+ echo
+ echo "Known tests that need a remote device:"
+ for name in "${known_remote_tests[@]}"
+ do
+ echo " ${name}"
+ done
+}
+
+iterations=1
+device=
+tests=()
+test_args=()
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -i)
+ shift
+ if [ $# -eq 0 ]; then
+ echo "error: number of iterations expected" 1>&2
+ usage
+ exit 2
+ fi
+ iterations=$(( $1 ))
+ shift
+ ;;
+ -s)
+ shift
+ if [ $# -eq 0 ]; then
+ echo "error: no device specified" 1>&2
+ usage
+ exit 2
+ fi
+ device="$1"
+ shift
+ ;;
+ --all)
+ tests+=( "${known_tests[@]}" )
+ shift
+ ;;
+ --*)
+ test_args+=( "$1" )
+ shift
+ ;;
+ *)
+ tests+=( "$1" )
+ shift
+ ;;
+ esac
+done
+
+if [ "${#tests[@]}" -eq 0 ]; then
+ tests+=( "${known_tests[@]}" )
+fi
+
+adb=( "adb" )
+if [ -n "${device}" ]; then
+ adb+=( "-s" "${device}" )
+fi
+
+failed_tests=()
+for spec in "${tests[@]}"
+do
+ name="${spec%%.*}"
+ binary="/data/nativetest/${name}/${name}"
+
+ push_command=( "${adb[@]}" push {"${ANDROID_PRODUCT_OUT}",}"${binary}" )
+ test_command=( "${adb[@]}" shell "${binary}" )
+ if [ "${name}" != "${spec}" ]; then
+ filter="${spec#*.}"
+ test_command+=( "--gtest_filter=${filter}" )
+ fi
+ test_command+=( "${test_args[@]}" )
+
+ echo "--- ${name} ---"
+ echo "pushing..."
+ "${push_command[@]}"
+ echo "running..."
+ failed_count=0
+ for i in $(seq 1 ${iterations})
+ do
+ "${test_command[@]}" || failed_count=$(( $failed_count + 1 ))
+ done
+
+ if [ $failed_count != 0 ]; then
+ failed_tests+=( "${name} ${failed_count}/${iterations}" )
+ fi
+done
+
+if [ "${#failed_tests[@]}" -ne 0 ]; then
+ for failed_test in "${failed_tests[@]}"
+ do
+ echo "!!! FAILED TEST: ${failed_test} !!!"
+ done
+ exit 1
+fi
+
+exit 0
diff --git a/mtkbt/code/bt/test/suite/Android.bp b/mtkbt/code/bt/test/suite/Android.bp
new file mode 100755
index 0000000..4e8affd
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/Android.bp
@@ -0,0 +1,50 @@
+// Bluetooth test suite for target
+// ========================================================
+cc_test {
+ name: "net_test_bluetooth",
+ defaults: ["fluoride_defaults"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs: [
+ "adapter/adapter_unittest.cc",
+ "adapter/bluetooth_test.cc",
+ "gatt/gatt_test.cc",
+ "gatt/gatt_unittest.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcutils",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libosi",
+ ],
+ whole_static_libs: [
+ "libbluetoothtbd_hal",
+ ],
+}
+
+// Bluetooth test suite for target
+// ========================================================
+cc_test {
+ name: "net_test_rfcomm",
+ defaults: ["fluoride_defaults"],
+ include_dirs: ["vendor/mediatek/limit_open/system/bt"],
+ srcs: [
+ "adapter/bluetooth_test.cc",
+ "rfcomm/rfcomm_test.cc",
+ "rfcomm/rfcomm_unittest.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcutils",
+ ],
+ static_libs: [
+ "libbtcore",
+ "libosi",
+ ],
+ whole_static_libs: [
+ "libbluetoothtbd_hal",
+ ],
+}
diff --git a/mtkbt/code/bt/test/suite/BUILD.gn b/mtkbt/code/bt/test/suite/BUILD.gn
new file mode 100755
index 0000000..e413eb0
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/BUILD.gn
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+executable("net_test_bluetooth") {
+ testonly = true
+ sources = [
+ "adapter/adapter_unittest.cc",
+ "adapter/bluetooth_test.cc",
+ ]
+
+ include_dirs = [
+ "//",
+ "//test/suite",
+ ]
+
+ deps = [
+ "//btcore",
+ "//main:bluetooth.default",
+ "//service:service",
+ "//service:service_unittests",
+ "//third_party/libchrome:base",
+ "//osi",
+ "//third_party/googletest:gtest_main",
+ ]
+
+ libs = [
+ "-lpthread",
+ "-lrt",
+ "-ldl",
+ "-latomic",
+ ]
+}
diff --git a/mtkbt/code/bt/test/suite/adapter/adapter_unittest.cc b/mtkbt/code/bt/test/suite/adapter/adapter_unittest.cc
new file mode 100755
index 0000000..f53de32
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/adapter/adapter_unittest.cc
@@ -0,0 +1,195 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "adapter/bluetooth_test.h"
+#include "btcore/include/property.h"
+#include "stack/include/bt_types.h"
+
+namespace {
+
+// Each iteration of the test takes about 2 seconds to run, so choose a value
+// that matches your time constraints. For example, 5 iterations would take
+// about 10 seconds to run
+const int kTestRepeatCount = 5;
+
+} // namespace
+
+namespace bttest {
+
+TEST_F(BluetoothTest, AdapterEnableDisable) {
+ EXPECT_EQ(GetState(), BT_STATE_OFF)
+ << "Test should be run with Adapter disabled";
+
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterRepeatedEnableDisable) {
+ EXPECT_EQ(GetState(), BT_STATE_OFF)
+ << "Test should be run with Adapter disabled";
+
+ for (int i = 0; i < kTestRepeatCount; ++i) {
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+ }
+}
+
+TEST_F(BluetoothTest, AdapterSetGetName) {
+ bt_property_t* new_name = property_new_name("BluetoothTestName1");
+
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON)
+ << "Test should be run with Adapter enabled";
+
+ // Enabling the interface will call the properties callback twice before
+ // ever reaching this point.
+ ClearSemaphore(adapter_properties_callback_sem_);
+
+ EXPECT_EQ(bt_interface()->get_adapter_property(BT_PROPERTY_BDNAME),
+ BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_properties_callback_sem_);
+ EXPECT_GT(GetPropertiesChangedCount(), 0)
+ << "Expected at least one adapter property to change";
+ bt_property_t* name_property = GetProperty(BT_PROPERTY_BDNAME);
+ EXPECT_NE(name_property, nullptr);
+ if (property_equals(name_property, new_name)) {
+ property_free(new_name);
+ new_name = property_new_name("BluetoothTestName2");
+ }
+ std::string old_name((const char*)property_as_name(name_property)->name);
+
+ EXPECT_EQ(bt_interface()->set_adapter_property(new_name), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_properties_callback_sem_);
+ EXPECT_GT(GetPropertiesChangedCount(), 0)
+ << "Expected at least one adapter property to change";
+ EXPECT_TRUE(GetProperty(BT_PROPERTY_BDNAME))
+ << "The Bluetooth name property did not change.";
+ EXPECT_TRUE(property_equals(GetProperty(BT_PROPERTY_BDNAME), new_name))
+ << "Bluetooth name "
+ << property_as_name(GetProperty(BT_PROPERTY_BDNAME))->name
+ << " does not match test value " << property_as_name(new_name)->name;
+
+ bt_property_t* old_name_property = property_new_name(old_name.c_str());
+ EXPECT_EQ(bt_interface()->set_adapter_property(old_name_property),
+ BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_properties_callback_sem_);
+ EXPECT_TRUE(
+ property_equals(GetProperty(BT_PROPERTY_BDNAME), old_name_property))
+ << "Bluetooth name "
+ << property_as_name(GetProperty(BT_PROPERTY_BDNAME))->name
+ << " does not match original name" << old_name;
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+ property_free(new_name);
+ property_free(old_name_property);
+}
+
+TEST_F(BluetoothTest, AdapterStartDiscovery) {
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON)
+ << "Test should be run with Adapter enabled";
+
+ EXPECT_EQ(bt_interface()->start_discovery(), BT_STATUS_SUCCESS);
+ semaphore_wait(discovery_state_changed_callback_sem_);
+ EXPECT_EQ(GetDiscoveryState(), BT_DISCOVERY_STARTED)
+ << "Unable to start discovery.";
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterCancelDiscovery) {
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON)
+ << "Test should be run with Adapter enabled";
+
+ EXPECT_EQ(bt_interface()->start_discovery(), BT_STATUS_SUCCESS);
+ semaphore_wait(discovery_state_changed_callback_sem_);
+ EXPECT_EQ(bt_interface()->cancel_discovery(), BT_STATUS_SUCCESS);
+ semaphore_wait(discovery_state_changed_callback_sem_);
+
+ EXPECT_EQ(GetDiscoveryState(), BT_DISCOVERY_STOPPED)
+ << "Unable to stop discovery.";
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+}
+
+TEST_F(BluetoothTest, AdapterDisableDuringBonding) {
+ EXPECT_EQ(GetState(), BT_STATE_OFF)
+ << "Test should be run with Adapter disabled";
+
+ bt_bdaddr_t bdaddr = {{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}};
+
+ for (int i = 0; i < kTestRepeatCount; ++i) {
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
+
+ EXPECT_EQ(bt_interface()->create_bond(&bdaddr, BT_TRANSPORT_BR_EDR),
+ BT_STATUS_SUCCESS);
+
+ EXPECT_EQ(bt_interface()->cancel_bond(&bdaddr), BT_STATUS_SUCCESS);
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+ }
+}
+
+TEST_F(BluetoothTest, AdapterCleanupDuringDiscovery) {
+ EXPECT_EQ(GetState(), BT_STATE_OFF)
+ << "Test should be run with Adapter disabled";
+
+ bt_callbacks_t* bt_callbacks =
+ bluetooth::hal::BluetoothInterface::Get()->GetHALCallbacks();
+ ASSERT_TRUE(bt_callbacks != nullptr);
+
+ for (int i = 0; i < kTestRepeatCount; ++i) {
+ bt_interface()->init(bt_callbacks);
+ EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
+
+ EXPECT_EQ(bt_interface()->start_discovery(), BT_STATUS_SUCCESS);
+
+ EXPECT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_EQ(GetState(), BT_STATE_OFF) << "Adapter did not turn off.";
+ bt_interface()->cleanup();
+ }
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/adapter/bluetooth_test.cc b/mtkbt/code/bt/test/suite/adapter/bluetooth_test.cc
new file mode 100755
index 0000000..eb4afd5
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/adapter/bluetooth_test.cc
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "adapter/bluetooth_test.h"
+#include <mutex>
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+
+namespace {
+
+// Mutex lock used by callbacks to protect |callback_semaphores_| from
+// racey behaviour caused when Wait and Notify are called at the same time
+std::mutex callback_lock;
+
+} // namespace
+
+namespace bttest {
+
+void BluetoothTest::SetUp() {
+ bt_interface_ = nullptr;
+ state_ = BT_STATE_OFF;
+ properties_changed_count_ = 0;
+ last_changed_properties_ = nullptr;
+ remote_device_properties_changed_count_ = 0;
+ remote_device_last_changed_properties_ = nullptr;
+ discovery_state_ = BT_DISCOVERY_STOPPED;
+ acl_state_ = BT_ACL_STATE_DISCONNECTED;
+ bond_state_ = BT_BOND_STATE_NONE;
+
+ adapter_properties_callback_sem_ = semaphore_new(0);
+ remote_device_properties_callback_sem_ = semaphore_new(0);
+ adapter_state_changed_callback_sem_ = semaphore_new(0);
+ discovery_state_changed_callback_sem_ = semaphore_new(0);
+
+ bluetooth::hal::BluetoothInterface::Initialize();
+ ASSERT_TRUE(bluetooth::hal::BluetoothInterface::IsInitialized());
+ auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
+ bt_hal_interface->AddObserver(this);
+ bt_interface_ = bt_hal_interface->GetHALInterface();
+ ASSERT_NE(nullptr, bt_interface_) << "bt_interface is null.";
+}
+
+void BluetoothTest::TearDown() {
+ semaphore_free(adapter_properties_callback_sem_);
+ semaphore_free(remote_device_properties_callback_sem_);
+ semaphore_free(adapter_state_changed_callback_sem_);
+ semaphore_free(discovery_state_changed_callback_sem_);
+
+ auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
+ bt_hal_interface->RemoveObserver(this);
+ bt_hal_interface->CleanUp();
+ ASSERT_FALSE(bt_hal_interface->IsInitialized());
+}
+
+void BluetoothTest::ClearSemaphore(semaphore_t* sem) {
+ while (semaphore_try_wait(sem))
+ ;
+}
+
+const bt_interface_t* BluetoothTest::bt_interface() { return bt_interface_; }
+
+bt_state_t BluetoothTest::GetState() { return state_; }
+
+int BluetoothTest::GetPropertiesChangedCount() {
+ return properties_changed_count_;
+}
+
+bt_property_t* BluetoothTest::GetProperty(bt_property_type_t type) {
+ for (int i = 0; i < properties_changed_count_; ++i) {
+ if (last_changed_properties_[i].type == type) {
+ return &last_changed_properties_[i];
+ }
+ }
+ return nullptr;
+}
+
+bt_property_t* BluetoothTest::GetRemoteDeviceProperty(const bt_bdaddr_t* addr,
+ bt_property_type_t type) {
+ if (!bdaddr_equals(&curr_remote_device_, addr)) return nullptr;
+
+ for (int i = 0; i < remote_device_properties_changed_count_; i++) {
+ if (remote_device_last_changed_properties_[i].type == type) {
+ return &remote_device_last_changed_properties_[i];
+ }
+ }
+ return nullptr;
+}
+
+bt_discovery_state_t BluetoothTest::GetDiscoveryState() {
+ return discovery_state_;
+}
+
+bt_acl_state_t BluetoothTest::GetAclState() { return acl_state_; }
+
+// Returns the device bond state.
+bt_bond_state_t BluetoothTest::GetBondState() { return bond_state_; }
+
+// callback
+void BluetoothTest::AdapterStateChangedCallback(bt_state_t new_state) {
+ state_ = new_state;
+ semaphore_post(adapter_state_changed_callback_sem_);
+}
+
+// callback
+void BluetoothTest::AdapterPropertiesCallback(bt_status_t status,
+ int num_properties,
+ bt_property_t* new_properties) {
+ property_free_array(last_changed_properties_, properties_changed_count_);
+ last_changed_properties_ =
+ property_copy_array(new_properties, num_properties);
+ properties_changed_count_ = num_properties;
+ semaphore_post(adapter_properties_callback_sem_);
+}
+
+// callback
+void BluetoothTest::RemoteDevicePropertiesCallback(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ int num_properties,
+ bt_property_t* properties) {
+ bdaddr_copy(&curr_remote_device_, remote_bd_addr);
+ property_free_array(remote_device_last_changed_properties_,
+ remote_device_properties_changed_count_);
+ remote_device_last_changed_properties_ =
+ property_copy_array(properties, num_properties);
+ remote_device_properties_changed_count_ = num_properties;
+ semaphore_post(remote_device_properties_callback_sem_);
+}
+
+// callback
+void BluetoothTest::DiscoveryStateChangedCallback(bt_discovery_state_t state) {
+ discovery_state_ = state;
+ semaphore_post(discovery_state_changed_callback_sem_);
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/adapter/bluetooth_test.h b/mtkbt/code/bt/test/suite/adapter/bluetooth_test.h
new file mode 100755
index 0000000..2c12aff
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/adapter/bluetooth_test.h
@@ -0,0 +1,120 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <gtest/gtest.h>
+#include <hardware/bluetooth.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_pan.h>
+#include <hardware/bt_sock.h>
+#include <hardware/hardware.h>
+#include <signal.h>
+#include <time.h>
+#include <map>
+#include <string>
+#include "osi/include/semaphore.h"
+#include "service/hal/bluetooth_interface.h"
+
+namespace bttest {
+
+// This class represents the Bluetooth testing framework and provides
+// helpers and callbacks for GUnit to use for testing.
+class BluetoothTest : public ::testing::Test,
+ public bluetooth::hal::BluetoothInterface::Observer {
+ protected:
+ BluetoothTest() = default;
+ virtual ~BluetoothTest() = default;
+
+ // Getter for the bt_interface
+ const bt_interface_t* bt_interface();
+
+ // Gets the current state of the Bluetooth Interface
+ bt_state_t GetState();
+
+ // Get the number of properties that have changed on the
+ // Adapter Properties callback
+ int GetPropertiesChangedCount();
+
+ // Get the value of a specific property
+ bt_property_t* GetProperty(bt_property_type_t type);
+
+ // Get the value of a specific remote device property
+ bt_property_t* GetRemoteDeviceProperty(const bt_bdaddr_t* addr,
+ bt_property_type_t type);
+
+ // Get the current discovery state
+ bt_discovery_state_t GetDiscoveryState();
+
+ // Get the current Acl State
+ bt_acl_state_t GetAclState();
+
+ // Get the current Bond State
+ bt_bond_state_t GetBondState();
+
+ // Reset a semaphores count to 0
+ void ClearSemaphore(semaphore_t* sem);
+
+ // SetUp initializes the Bluetooth interface and registers the callbacks
+ // before running every test
+ void SetUp() override;
+
+ // TearDown cleans up the stack and interface at the end of every test
+ void TearDown() override;
+
+ // A callback that is called when a property changes
+ void AdapterPropertiesCallback(bt_status_t status, int num_properties,
+ bt_property_t* properties) override;
+
+ // A callback that is called when the remote device's property changes
+ void RemoteDevicePropertiesCallback(bt_status_t status,
+ bt_bdaddr_t* remote_bd_addr,
+ int num_properties,
+ bt_property_t* properties) override;
+
+ // A callback that is called when the adapter state changes
+ void AdapterStateChangedCallback(bt_state_t state) override;
+
+ // A callback that is called when the Discovery state changes
+ void DiscoveryStateChangedCallback(bt_discovery_state_t state) override;
+
+ // Semaphores used to wait for specific callback execution. Each callback
+ // has its own semaphore associated with it.
+ semaphore_t* adapter_properties_callback_sem_;
+ semaphore_t* remote_device_properties_callback_sem_;
+ semaphore_t* adapter_state_changed_callback_sem_;
+ semaphore_t* discovery_state_changed_callback_sem_;
+
+ private:
+ // The bluetooth interface that all the tests use to interact with the HAL
+ const bt_interface_t* bt_interface_;
+
+ bt_state_t state_;
+ int properties_changed_count_;
+ bt_property_t* last_changed_properties_;
+ bt_bdaddr_t curr_remote_device_;
+ int remote_device_properties_changed_count_;
+ bt_property_t* remote_device_last_changed_properties_;
+ bt_discovery_state_t discovery_state_;
+ bt_acl_state_t acl_state_;
+ bt_bond_state_t bond_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothTest);
+};
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/gatt/gatt_test.cc b/mtkbt/code/bt/test/suite/gatt/gatt_test.cc
new file mode 100755
index 0000000..2ea43cf
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/gatt/gatt_test.cc
@@ -0,0 +1,143 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "gatt/gatt_test.h"
+#include "adapter/bluetooth_test.h"
+#include "btcore/include/bdaddr.h"
+
+namespace bttest {
+
+void GattTest::SetUp() {
+ gatt_client_interface_ = nullptr;
+ gatt_server_interface_ = nullptr;
+
+ client_interface_id_ = 0;
+ server_interface_id_ = 0;
+ service_handle_ = 0;
+ characteristic_handle_ = 0;
+ descriptor_handle_ = 0;
+ status_ = 0;
+
+ BluetoothTest::SetUp();
+ ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ EXPECT_TRUE(GetState() == BT_STATE_ON);
+
+ register_client_callback_sem_ = semaphore_new(0);
+ scan_result_callback_sem_ = semaphore_new(0);
+
+ register_server_callback_sem_ = semaphore_new(0);
+ service_added_callback_sem_ = semaphore_new(0);
+ service_stopped_callback_sem_ = semaphore_new(0);
+ service_deleted_callback_sem_ = semaphore_new(0);
+
+ bluetooth::hal::BluetoothGattInterface::Initialize();
+ ASSERT_TRUE(bluetooth::hal::BluetoothGattInterface::IsInitialized());
+ auto gatt_interface = bluetooth::hal::BluetoothGattInterface::Get();
+ gatt_interface->AddClientObserver(this);
+ gatt_interface->AddServerObserver(this);
+
+ gatt_client_interface_ = gatt_interface->GetClientHALInterface();
+ gatt_server_interface_ = gatt_interface->GetServerHALInterface();
+
+ ASSERT_NE(nullptr, gatt_client_interface_);
+ ASSERT_NE(nullptr, gatt_server_interface_);
+}
+
+void GattTest::TearDown() {
+ gatt_client_interface_ = nullptr;
+ gatt_server_interface_ = nullptr;
+
+ semaphore_free(register_client_callback_sem_);
+ semaphore_free(scan_result_callback_sem_);
+
+ semaphore_free(register_server_callback_sem_);
+ semaphore_free(service_added_callback_sem_);
+ semaphore_free(service_stopped_callback_sem_);
+ semaphore_free(service_deleted_callback_sem_);
+
+ bluetooth::hal::BluetoothGattInterface::CleanUp();
+
+ ASSERT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ BluetoothTest::TearDown();
+}
+
+const BleScannerInterface* GattTest::gatt_scanner_interface() {
+ return gatt_scanner_interface_;
+}
+
+const btgatt_client_interface_t* GattTest::gatt_client_interface() {
+ return gatt_client_interface_;
+}
+
+const btgatt_server_interface_t* GattTest::gatt_server_interface() {
+ return gatt_server_interface_;
+}
+
+void GattTest::RegisterClientCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int clientIf, const bt_uuid_t& app_uuid) {
+ status_ = status;
+ client_interface_id_ = clientIf;
+ semaphore_post(register_client_callback_sem_);
+}
+
+void GattTest::ScanResultCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */,
+ const bt_bdaddr_t& bda, int rssi, std::vector<uint8_t> adv_data) {
+ semaphore_post(scan_result_callback_sem_);
+}
+
+// GATT server callbacks
+void GattTest::RegisterServerCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, const bt_uuid_t& uuid) {
+ status_ = status;
+ server_interface_id_ = server_if;
+ semaphore_post(register_server_callback_sem_);
+}
+
+void GattTest::ServiceAddedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, std::vector<btgatt_db_element_t> service) {
+ status_ = status;
+ server_interface_id_ = server_if;
+ service_handle_ = service[0].attribute_handle;
+ semaphore_post(service_added_callback_sem_);
+}
+
+void GattTest::ServiceStoppedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, int srvc_handle) {
+ status_ = status;
+ server_interface_id_ = server_if;
+ service_handle_ = srvc_handle;
+ semaphore_post(service_stopped_callback_sem_);
+}
+
+void GattTest::ServiceDeletedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, int srvc_handle) {
+ status_ = status;
+ server_interface_id_ = server_if;
+ service_handle_ = srvc_handle;
+ semaphore_post(service_deleted_callback_sem_);
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/gatt/gatt_test.h b/mtkbt/code/bt/test/suite/gatt/gatt_test.h
new file mode 100755
index 0000000..cdf532c
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/gatt/gatt_test.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "adapter/bluetooth_test.h"
+#include "service/hal/bluetooth_gatt_interface.h"
+
+namespace bttest {
+
+// This class represents the Bluetooth GATT testing framework and provides
+// helpers and callbacks for GUnit to use for testing gatt.
+class GattTest : public BluetoothTest,
+ public bluetooth::hal::BluetoothGattInterface::ClientObserver,
+ public bluetooth::hal::BluetoothGattInterface::ScannerObserver,
+ public bluetooth::hal::BluetoothGattInterface::ServerObserver {
+ protected:
+ GattTest() = default;
+ virtual ~GattTest() = default;
+
+ // Gets the gatt_scanner_interface
+ const BleScannerInterface* gatt_scanner_interface();
+
+ // Gets the gatt_client_interface
+ const btgatt_client_interface_t* gatt_client_interface();
+
+ // Gets the gatt_server_interface
+ const btgatt_server_interface_t* gatt_server_interface();
+
+ // Getters for variables that track GATT-related state
+ int client_interface_id() const { return client_interface_id_; }
+ int server_interface_id() const { return server_interface_id_; }
+ int service_handle() const { return service_handle_; }
+ int characteristic_handle() const { return characteristic_handle_; }
+ int descriptor_handle() const { return descriptor_handle_; }
+ int status() const { return status_; }
+
+ // SetUp initializes the Bluetooth interfaces and the GATT Interface as well
+ // as registers the callbacks and initializes the semaphores before every test
+ virtual void SetUp();
+
+ // TearDown cleans up the Bluetooth and GATT interfaces and destroys the
+ // callback semaphores at the end of every test
+ virtual void TearDown();
+
+ // bluetooth::hal::BluetoothGattInterface::ClientObserver overrides
+ void RegisterClientCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int clientIf, const bt_uuid_t& app_uuid) override;
+ void ScanResultCallback(bluetooth::hal::BluetoothGattInterface* /* unused */,
+ const bt_bdaddr_t& bda, int rssi,
+ std::vector<uint8_t> adv_data) override;
+
+ // bluetooth::hal::BluetoothGattInterface::ServerObserver overrides
+ void RegisterServerCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, const bt_uuid_t& uuid) override;
+ void ServiceAddedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, std::vector<btgatt_db_element_t> service) override;
+ void ServiceStoppedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, int srvc_handle) override;
+ void ServiceDeletedCallback(
+ bluetooth::hal::BluetoothGattInterface* /* unused */, int status,
+ int server_if, int srvc_handle) override;
+
+ // Semaphores used to wait for specific callback execution. Each callback
+ // has its own semaphore associated with it
+ semaphore_t* register_client_callback_sem_;
+ semaphore_t* scan_result_callback_sem_;
+ semaphore_t* listen_callback_sem_;
+
+ semaphore_t* register_server_callback_sem_;
+ semaphore_t* service_added_callback_sem_;
+ semaphore_t* characteristic_added_callback_sem_;
+ semaphore_t* descriptor_added_callback_sem_;
+ semaphore_t* service_started_callback_sem_;
+ semaphore_t* service_stopped_callback_sem_;
+ semaphore_t* service_deleted_callback_sem_;
+
+ private:
+ // The btgatt_scanner_interface_t that all the tests use to interact with the
+ // HAL
+ const BleScannerInterface* gatt_scanner_interface_;
+
+ // The gatt_client_interface that all the tests use to interact with the HAL
+ const btgatt_client_interface_t* gatt_client_interface_;
+
+ // The gatt_server_interface that all the tests use to interact with the HAL
+ const btgatt_server_interface_t* gatt_server_interface_;
+
+ // No mutex needed for these as the semaphores should ensure
+ // synchronous access
+
+ // An ID that is used as a handle for each gatt client.
+ int client_interface_id_;
+
+ // An ID that is used as a handle for each gatt server.
+ int server_interface_id_;
+
+ // A handle to the last used service.
+ int service_handle_;
+
+ // A handle to the last characteristic added.
+ int characteristic_handle_;
+
+ // A handle to the last descriptor added.
+ int descriptor_handle_;
+
+ // The status of the last callback. Is BT_STATUS_SUCCESS if no issues.
+ int status_;
+
+ DISALLOW_COPY_AND_ASSIGN(GattTest);
+};
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/gatt/gatt_unittest.cc b/mtkbt/code/bt/test/suite/gatt/gatt_unittest.cc
new file mode 100755
index 0000000..598ae41
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/gatt/gatt_unittest.cc
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "gatt/gatt_test.h"
+
+#define DEFAULT_RANDOM_SEED 42
+
+namespace {
+
+static void create_random_uuid(bt_uuid_t* uuid, int seed) {
+ srand(seed < 0 ? time(NULL) : seed);
+ for (int i = 0; i < 16; ++i) {
+ uuid->uu[i] = (uint8_t)(rand() % 256);
+ }
+}
+
+} // namespace
+
+namespace bttest {
+
+TEST_F(GattTest, GattClientRegister) {
+ // Registers gatt client.
+ bt_uuid_t gatt_client_uuid;
+ create_random_uuid(&gatt_client_uuid, DEFAULT_RANDOM_SEED);
+ gatt_client_interface()->register_client(&gatt_client_uuid);
+ semaphore_wait(register_client_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+ << "Error registering GATT client app callback.";
+
+ // Unregisters gatt client. No callback is expected.
+ gatt_client_interface()->unregister_client(client_interface_id());
+}
+
+TEST_F(GattTest, GattServerRegister) {
+ // Registers gatt server.
+ bt_uuid_t gatt_server_uuid;
+ create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+ gatt_server_interface()->register_server(&gatt_server_uuid);
+ semaphore_wait(register_server_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+ << "Error registering GATT server app callback.";
+
+ // Unregisters gatt server. No callback is expected.
+ gatt_server_interface()->unregister_server(server_interface_id());
+}
+
+TEST_F(GattTest, GattServerBuild) {
+ // Registers gatt server.
+ bt_uuid_t gatt_server_uuid;
+ create_random_uuid(&gatt_server_uuid, DEFAULT_RANDOM_SEED);
+ gatt_server_interface()->register_server(&gatt_server_uuid);
+ semaphore_wait(register_server_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS)
+ << "Error registering GATT server app callback.";
+
+ // Service UUID.
+ bt_uuid_t srvc_uuid;
+ create_random_uuid(&srvc_uuid, -1);
+
+ // Characteristics UUID.
+ bt_uuid_t char_uuid;
+ create_random_uuid(&char_uuid, -1);
+
+ // Descriptor UUID.
+ bt_uuid_t desc_uuid;
+ create_random_uuid(&desc_uuid, -1);
+
+ // Adds service.
+ int server_if = server_interface_id();
+
+ std::vector<btgatt_db_element_t> service = {
+ {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = srvc_uuid},
+ {.type = BTGATT_DB_CHARACTERISTIC,
+ .uuid = char_uuid,
+ .properties = 0x10 /* notification */,
+ .permissions = 0x01 /* read only */},
+ {.type = BTGATT_DB_DESCRIPTOR, .uuid = desc_uuid, .permissions = 0x01}};
+
+ gatt_server_interface()->add_service(server_if, service);
+ semaphore_wait(service_added_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error adding service.";
+
+ // Stops server.
+ gatt_server_interface()->stop_service(server_if, service_handle());
+ semaphore_wait(service_stopped_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error stopping server.";
+
+ // Deletes service.
+ gatt_server_interface()->delete_service(server_if, service_handle());
+ semaphore_wait(service_deleted_callback_sem_);
+ EXPECT_TRUE(status() == BT_STATUS_SUCCESS) << "Error deleting service.";
+
+ // Unregisters gatt server. No callback is expected.
+ gatt_server_interface()->unregister_server(server_if);
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.cc b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.cc
new file mode 100755
index 0000000..adde7ce
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.cc
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "rfcomm/rfcomm_test.h"
+#include "adapter/bluetooth_test.h"
+
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/uuid.h"
+
+namespace bttest {
+
+const bt_uuid_t RFCommTest::HFP_UUID = {{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00,
+ 0x10, 0x00, 0x80, 0x00, 0x00, 0x80,
+ 0x5F, 0x9B, 0x34, 0xFB}};
+
+void RFCommTest::SetUp() {
+ BluetoothTest::SetUp();
+
+ ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+ ASSERT_TRUE(GetState() == BT_STATE_ON);
+ socket_interface_ =
+ (const btsock_interface_t*)bt_interface()->get_profile_interface(
+ BT_PROFILE_SOCKETS_ID);
+ ASSERT_NE(socket_interface_, nullptr);
+
+ // Find a bonded device that supports HFP
+ string_to_bdaddr("00:00:00:00:00:00", &bt_remote_bdaddr_);
+ char value[1280];
+
+ bt_property_t* bonded_devices_prop =
+ GetProperty(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
+ bt_bdaddr_t* devices = (bt_bdaddr_t*)bonded_devices_prop->val;
+ int num_bonded_devices = bonded_devices_prop->len / sizeof(bt_bdaddr_t);
+
+ for (int i = 0; i < num_bonded_devices && bdaddr_is_empty(&bt_remote_bdaddr_);
+ i++) {
+ ClearSemaphore(remote_device_properties_callback_sem_);
+ bt_interface()->get_remote_device_property(&devices[i], BT_PROPERTY_UUIDS);
+ semaphore_wait(remote_device_properties_callback_sem_);
+
+ bt_property_t* uuid_prop =
+ GetRemoteDeviceProperty(&devices[i], BT_PROPERTY_UUIDS);
+ if (uuid_prop == nullptr) continue;
+ bt_uuid_t* uuids = (bt_uuid_t*)uuid_prop->val;
+ int num_uuids = uuid_prop->len / sizeof(bt_uuid_t);
+
+ for (int j = 0; j < num_uuids; j++) {
+ uuid_to_string(&uuids[j], (uuid_string_t*)value);
+ if (!memcmp(uuids + j, &HFP_UUID, sizeof(bt_uuid_t))) {
+ bdaddr_copy(&bt_remote_bdaddr_, devices + i);
+ break;
+ }
+ }
+ }
+
+ ASSERT_FALSE(bdaddr_is_empty(&bt_remote_bdaddr_))
+ << "Could not find paired device that supports HFP";
+}
+
+void RFCommTest::TearDown() {
+ socket_interface_ = NULL;
+
+ ASSERT_EQ(bt_interface()->disable(), BT_STATUS_SUCCESS);
+ semaphore_wait(adapter_state_changed_callback_sem_);
+
+ BluetoothTest::TearDown();
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.h b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.h
new file mode 100755
index 0000000..662fdb1
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_test.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "adapter/bluetooth_test.h"
+
+namespace bttest {
+
+class RFCommTest : public BluetoothTest {
+ protected:
+ RFCommTest() = default;
+ virtual ~RFCommTest() = default;
+
+ // Getter for the RFCOMM socket
+ const btsock_interface_t* socket_interface() const {
+ return socket_interface_;
+ }
+
+ // SetUp initializes the Bluetooth interfaces and the RFCOMM interface
+ virtual void SetUp();
+
+ // TearDown cleans up the Bluetooth and RFCOMM interfaces
+ virtual void TearDown();
+
+ bt_bdaddr_t bt_remote_bdaddr_;
+
+ static const bt_uuid_t HFP_UUID;
+
+ private:
+ const btsock_interface_t* socket_interface_;
+};
+
+} // bttest
diff --git a/mtkbt/code/bt/test/suite/rfcomm/rfcomm_unittest.cc b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_unittest.cc
new file mode 100755
index 0000000..b81f781
--- a/dev/null
+++ b/mtkbt/code/bt/test/suite/rfcomm/rfcomm_unittest.cc
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "adapter/bluetooth_test.h"
+#include "rfcomm/rfcomm_test.h"
+
+#include "btcore/include/bdaddr.h"
+
+#include <sys/socket.h>
+#include <unistd.h>
+
+namespace {
+static const char HANDSHAKE_COMMAND[] = "AT+BRSF=29\r";
+} // namespace
+
+namespace bttest {
+
+TEST_F(RFCommTest, RfcommConnectPairedDevice) {
+ int fd = -1;
+ int error = 0;
+ size_t len = 0;
+
+ error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
+ (const uint8_t*)&HFP_UUID, 0, &fd, 0,
+ getuid());
+ EXPECT_TRUE(error == BT_STATUS_SUCCESS) << "Error creating RFCOMM socket: "
+ << error;
+ EXPECT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
+
+ int channel;
+ sock_connect_signal_t signal;
+ len = read(fd, &channel, sizeof(channel));
+ EXPECT_TRUE(len == sizeof(channel))
+ << "Channel not read from RFCOMM socket. Bytes read: " << len;
+ len = read(fd, &signal, sizeof(signal));
+ EXPECT_TRUE(len == sizeof(signal))
+ << "Connection signal not read from RFCOMM socket. Bytes read: " << len;
+
+ EXPECT_TRUE(!memcmp(&signal.bd_addr, &bt_remote_bdaddr_, sizeof(bt_bdaddr_t)))
+ << "Connected to a different bdaddr than expected.";
+ EXPECT_TRUE(channel == signal.channel)
+ << "Inconsistent channels returned: " << channel << " and "
+ << signal.channel;
+
+ len = write(fd, HANDSHAKE_COMMAND, sizeof(HANDSHAKE_COMMAND));
+ EXPECT_TRUE(len == sizeof(HANDSHAKE_COMMAND))
+ << "Unable to send HFP handshake. Bytes written: " << len;
+
+ char response[1024];
+ len = read(fd, response, sizeof(response));
+ EXPECT_TRUE(len > 0) << "Read " << len << " bytes";
+
+ close(fd);
+}
+
+TEST_F(RFCommTest, RfcommRepeatedConnectPairedDevice) {
+ static const int max_iterations = 128;
+ int channel_fail = 0, signal_fail = 0, handshake_fail = 0, read_fail = 0;
+
+ for (int i = 0; i < max_iterations; ++i) {
+ int fd = -1;
+ int error = 0;
+ size_t len = 0;
+
+ error = socket_interface()->connect(&bt_remote_bdaddr_, BTSOCK_RFCOMM,
+ (const uint8_t*)&HFP_UUID, 0, &fd, 0,
+ getuid());
+ ASSERT_TRUE(error == BT_STATUS_SUCCESS) << "Error creating RFCOMM socket: "
+ << error;
+ ASSERT_TRUE(fd != -1) << "Error creating RFCOMM socket: invalid fd";
+
+ int channel;
+ sock_connect_signal_t signal;
+ len = read(fd, &channel, sizeof(channel));
+ if (len != sizeof(channel)) {
+ ADD_FAILURE() << "Channel not read from RFCOMM socket. Bytes read: "
+ << len << ", Sizeof channel: " << sizeof(channel);
+ channel_fail++;
+ }
+
+ len = read(fd, &signal, sizeof(signal));
+ if (len != sizeof(signal)) {
+ ADD_FAILURE()
+ << "Connection signal not read from RFCOMM socket. Bytes read: "
+ << len;
+ signal_fail++;
+ }
+
+ EXPECT_TRUE(
+ !memcmp(&signal.bd_addr, &bt_remote_bdaddr_, sizeof(bt_bdaddr_t)))
+ << "Connected to a different bdaddr than expected.";
+ EXPECT_TRUE(channel == signal.channel)
+ << "Inconsistent channels returned: " << channel << " and "
+ << signal.channel;
+ len = write(fd, HANDSHAKE_COMMAND, sizeof(HANDSHAKE_COMMAND));
+ if (len != sizeof(HANDSHAKE_COMMAND)) {
+ ADD_FAILURE() << "Unable to send HFP handshake. Bytes written: " << len;
+ handshake_fail++;
+ }
+
+ char response[1024];
+ len = read(fd, response, sizeof(response));
+ if (len <= 0) {
+ ADD_FAILURE() << "Read " << len << " bytes";
+ read_fail++;
+ }
+
+ close(fd);
+ }
+
+ if (channel_fail > 0 || signal_fail > 0 || handshake_fail > 0 ||
+ read_fail > 0) {
+ ADD_FAILURE() << "Number of channel read fails: " << channel_fail << "\n"
+ << "Number of signal read fails: " << signal_fail << "\n"
+ << "Number of handshake send fails: " << handshake_fail
+ << "\n"
+ << "Number of read response fails: " << read_fail;
+ }
+}
+
+} // bttest
diff --git a/mtkbt/code/bt/tools/Android.mk.disabled b/mtkbt/code/bt/tools/Android.mk.disabled
new file mode 100755
index 0000000..5053e7d
--- a/dev/null
+++ b/mtkbt/code/bt/tools/Android.mk.disabled
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/mtkbt/code/bt/tools/bdtool/Android.mk.disabled b/mtkbt/code/bt/tools/bdtool/Android.mk.disabled
new file mode 100755
index 0000000..fa616e5
--- a/dev/null
+++ b/mtkbt/code/bt/tools/bdtool/Android.mk.disabled
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth tools for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_bdtool
+
+LOCAL_SRC_FILES := \
+ adapter.c \
+ bdtool.c \
+ ../../test/suite/support/callbacks.c \
+ ../../test/suite/support/gatt.c \
+ ../../test/suite/support/hal.c \
+ ../../test/suite/support/pan.c
+
+LOCAL_STATIC_LIBRARIES := \
+ libbtcore \
+ libosi
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../test/suite \
+ $(LOCAL_PATH)/../..
+
+LOCAL_SHARED_LIBRARIES := \
+ libhardware liblog
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
diff --git a/mtkbt/code/bt/tools/bdtool/adapter.c b/mtkbt/code/bt/tools/bdtool/adapter.c
new file mode 100755
index 0000000..70b1b70
--- a/dev/null
+++ b/mtkbt/code/bt/tools/bdtool/adapter.c
@@ -0,0 +1,275 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include "support/adapter.h"
+#include "base.h"
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+#include "support/callbacks.h"
+
+static bt_state_t state;
+static int property_count = 0;
+static bt_property_t* properties = NULL;
+static bt_discovery_state_t discovery_state;
+static bt_acl_state_t acl_state;
+static bt_bond_state_t bond_state;
+
+static void parse_properties(int num_properties, bt_property_t* property);
+
+// Returns the current adapter state.
+bt_state_t adapter_get_state() { return state; }
+
+// Returns the number of adapter properties.
+int adapter_get_property_count() { return property_count; }
+
+// Returns the specified property.
+bt_property_t* adapter_get_property(bt_property_type_t type) {
+ for (int i = 0; i < property_count; ++i) {
+ if (properties[i].type == type) {
+ return &properties[i];
+ }
+ }
+
+ return NULL;
+}
+
+// Returns the device discovery state.
+bt_discovery_state_t adapter_get_discovery_state() { return discovery_state; }
+
+// Returns the device acl state.
+bt_acl_state_t adapter_get_acl_state() { return acl_state; }
+
+// Returns the device bond state.
+bt_bond_state_t adapter_get_bond_state() { return bond_state; }
+
+// callback
+void acl_state_changed(bt_status_t status, bt_bdaddr_t* remote_bd_addr,
+ bt_acl_state_t state) {
+ acl_state = state;
+ CALLBACK_RET();
+}
+
+// callback
+void adapter_properties(bt_status_t status, int num_properties,
+ bt_property_t* new_properties) {
+ property_free_array(properties, property_count);
+ properties = property_copy_array(new_properties, num_properties);
+ property_count = num_properties;
+
+ CALLBACK_RET();
+}
+
+// callback
+void adapter_state_changed(bt_state_t new_state) {
+ state = new_state;
+ CALLBACK_RET();
+}
+
+// callback
+void bond_state_changed(bt_status_t status, bt_bdaddr_t* bdaddr,
+ bt_bond_state_t state) {
+ char buf[18];
+ bond_state = state;
+
+ const char* state_name = "Bond state unknown";
+ switch (bond_state) {
+ case BT_BOND_STATE_NONE:
+ state_name = "Bond state none";
+ break;
+
+ case BT_BOND_STATE_BONDING:
+ state_name = "Bond state bonding";
+ break;
+
+ case BT_BOND_STATE_BONDED:
+ state_name = "Bond state bonded";
+ break;
+
+ // default none
+ }
+ fprintf(stdout, "Bond state changed callback addr:%s state:%s\n",
+ bdaddr_to_string(bdaddr, buf, sizeof(buf)), state_name);
+
+ CALLBACK_RET();
+}
+
+// callback
+void device_found(int num_properties, bt_property_t* property) {
+ fprintf(stdout, "Device found num_properties:%d\n", num_properties);
+ parse_properties(num_properties, property);
+
+ CALLBACK_RET();
+}
+
+// callback
+void discovery_state_changed(bt_discovery_state_t state) {
+ const char* state_name = "Unknown";
+ discovery_state = state;
+
+ switch (discovery_state) {
+ case BT_DISCOVERY_STOPPED:
+ state_name = "Discovery stopped";
+ break;
+
+ case BT_DISCOVERY_STARTED:
+ state_name = "Discovery started";
+ break;
+
+ // default omitted
+ }
+ fprintf(stdout, "Discover state %s\n", state_name);
+
+ CALLBACK_RET();
+}
+
+// callback
+void remote_device_properties(bt_status_t status, bt_bdaddr_t* bdaddr,
+ int num_properties, bt_property_t* properties) {
+ char buf[18];
+ fprintf(stdout, "Device found bdaddr:%s num_properties:%d\n",
+ bdaddr_to_string(bdaddr, buf, sizeof(buf)), num_properties);
+
+ parse_properties(num_properties, properties);
+
+ CALLBACK_RET();
+}
+
+// callback
+void ssp_request(bt_bdaddr_t* remote_bd_addr, bt_bdname_t* bd_name,
+ uint32_t cod, bt_ssp_variant_t pairing_variant,
+ uint32_t pass_key) {
+ char* pairing_variant_name = "Unknown";
+
+ switch (pairing_variant) {
+ case BT_SSP_VARIANT_PASSKEY_CONFIRMATION:
+ pairing_variant_name = "Passkey confirmation";
+ break;
+ case BT_SSP_VARIANT_PASSKEY_ENTRY:
+ pairing_variant_name = "Passkey entry";
+ break;
+
+ case BT_SSP_VARIANT_CONSENT:
+ pairing_variant_name = "Passkey consent";
+ break;
+
+ case BT_SSP_VARIANT_PASSKEY_NOTIFICATION:
+ pairing_variant_name = "Passkey notification";
+ break;
+ }
+
+ fprintf(stdout,
+ "Got ssp request device_class:%u passkey:%x pairing_variant:%s\n",
+ cod, pass_key, pairing_variant_name);
+ char buf[18];
+ fprintf(stdout, "Device found:%s %s\n",
+ bdaddr_to_string(remote_bd_addr, buf, sizeof(buf)), bd_name->name);
+
+ fprintf(stdout, "auto-accepting bond\n");
+ bool accept = true;
+ int rc = bt_interface->ssp_reply(remote_bd_addr, pairing_variant,
+ (uint8_t)accept, pass_key);
+ CALLBACK_RET();
+}
+
+// callback
+void thread_evt(bt_cb_thread_evt evt) { CALLBACK_RET(); }
+
+static void parse_properties(int num_properties, bt_property_t* property) {
+ while (num_properties-- > 0) {
+ switch (property->type) {
+ case BT_PROPERTY_BDNAME: {
+ const bt_bdname_t* name = property_as_name(property);
+ if (name) fprintf(stdout, " name:%s\n", name->name);
+ } break;
+
+ case BT_PROPERTY_BDADDR: {
+ char buf[18];
+ const bt_bdaddr_t* addr = property_as_addr(property);
+ if (addr)
+ fprintf(stdout, " addr:%s\n",
+ bdaddr_to_string(addr, buf, sizeof(buf)));
+ } break;
+
+ case BT_PROPERTY_UUIDS: {
+ size_t num_uuid;
+ const bt_uuid_t* uuid = property_as_uuids(property, &num_uuid);
+ if (uuid) {
+ for (size_t i = 0; i < num_uuid; i++) {
+ fprintf(stdout, " uuid:%zd: ", i);
+ for (size_t j = 0; j < sizeof(uuid); j++) {
+ fprintf(stdout, "%02x", uuid->uu[j]);
+ }
+ fprintf(stdout, "\n");
+ }
+ }
+ } break;
+
+ case BT_PROPERTY_TYPE_OF_DEVICE: {
+ bt_device_type_t device_type = property_as_device_type(property);
+ if (device_type) {
+ const struct {
+ const char* device_type;
+ } device_type_lookup[] = {
+ {"Unknown"},
+ {"Classic Only"},
+ {"BLE Only"},
+ {"Both Classic and BLE"},
+ };
+ int idx = (int)device_type;
+ if (idx > BT_DEVICE_DEVTYPE_DUAL) idx = 0;
+ fprintf(stdout, " device_type:%s\n",
+ device_type_lookup[idx].device_type);
+ }
+ } break;
+
+ case BT_PROPERTY_CLASS_OF_DEVICE: {
+ const bt_device_class_t* dc = property_as_device_class(property);
+ int dc_int = device_class_to_int(dc);
+ fprintf(stdout, " device_class:0x%x\n", dc_int);
+ } break;
+
+ case BT_PROPERTY_REMOTE_RSSI: {
+ int8_t rssi = property_as_rssi(property);
+ fprintf(stdout, " rssi:%d\n", rssi);
+ } break;
+
+ case BT_PROPERTY_REMOTE_FRIENDLY_NAME: {
+ const bt_bdname_t* name = property_as_name(property);
+ if (name) fprintf(stdout, " remote_name:%s\n", name->name);
+ } break;
+
+ case BT_PROPERTY_SERVICE_RECORD:
+ case BT_PROPERTY_ADAPTER_SCAN_MODE:
+ case BT_PROPERTY_ADAPTER_BONDED_DEVICES:
+ case BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT:
+ case BT_PROPERTY_REMOTE_VERSION_INFO:
+ case BT_PROPERTY_LOCAL_LE_FEATURES:
+ case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:
+ default: {
+ fprintf(stderr, "Unhandled property type:%d len:%d\n", property->type,
+ property->len);
+ uint8_t* p = (uint8_t*)property->val;
+ for (int i = 0; i < property->len; ++i, p++) {
+ fprintf(stderr, " %02x", *p);
+ }
+ if (property->len != 0) fprintf(stderr, "\n");
+ }
+ }
+ property++;
+ }
+}
diff --git a/mtkbt/code/bt/tools/bdtool/bdtool.c b/mtkbt/code/bt/tools/bdtool/bdtool.c
new file mode 100755
index 0000000..f25cf24
--- a/dev/null
+++ b/mtkbt/code/bt/tools/bdtool/bdtool.c
@@ -0,0 +1,361 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <getopt.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "btcore/include/bdaddr.h"
+#include "btcore/include/property.h"
+#include "osi/include/osi.h"
+#include "test/suite/support/callbacks.h"
+#include "test/suite/support/hal.h"
+
+static const bt_uuid_t HFP_UUID = {{0x00, 0x00, 0x11, 0x1E, 0x00, 0x00, 0x10,
+ 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
+ 0x34, 0xFB}};
+static const bt_uuid_t HFP_AG_UUID = {{0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10,
+ 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B,
+ 0x34, 0xFB}};
+
+const bt_interface_t* bt_interface;
+
+bt_bdaddr_t bt_remote_bdaddr;
+
+static int f_verbose;
+static bool discover = false;
+static bool discoverable = false;
+static bool bond = false;
+static bool up = false;
+static bool get_name = false;
+static bool set_name = false;
+static bool sco_listen = false;
+static bool sco_connect = false;
+
+static int timeout_in_sec = 30;
+static char* bd_name;
+
+static struct option long_options[] = {
+ {"bdaddr", required_argument, 0, 0}, {"discover", no_argument, 0, 0},
+ {"discoverable", no_argument, 0, 0}, {"time", required_argument, 0, 0},
+ {"bond", no_argument, 0, 0}, {"up", no_argument, 0, 0},
+ {"verbose", no_argument, 0, 0}, {"get_name", no_argument, 0, 0},
+ {"set_name", required_argument, 0, 0}, {"sco_listen", no_argument, 0, 0},
+ {"sco_connect", no_argument, 0, 0}, {0, 0, 0, 0}};
+
+static void usage(const char* name);
+static bool parse_args(int argc, char** argv);
+static void sig_handler(int signo);
+
+bt_property_t* adapter_get_property(bt_property_type_t type);
+
+int main(int argc, char** argv) {
+ if (!parse_args(argc, argv)) {
+ usage(argv[0]);
+ }
+
+ if (bond && discoverable) {
+ fprintf(stderr, "Can only select either bond or discoverable, not both\n");
+ usage(argv[0]);
+ }
+
+ if (sco_listen && sco_connect) {
+ fprintf(stderr,
+ "Can only select either sco_listen or sco_connect, not both\n");
+ usage(argv[0]);
+ }
+
+ if (!bond && !discover && !discoverable && !up && !get_name && !set_name &&
+ !sco_listen && !sco_connect) {
+ fprintf(stderr, "Must specify one command\n");
+ usage(argv[0]);
+ }
+
+ if (signal(SIGINT, sig_handler) == SIG_ERR) {
+ fprintf(stderr, "Will be unable to catch signals\n");
+ }
+
+ fprintf(stdout, "Bringing up bluetooth adapter\n");
+ if (!hal_open(callbacks_get_adapter_struct())) {
+ fprintf(stderr, "Unable to open Bluetooth HAL.\n");
+ return 1;
+ }
+
+ if (discover) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ fprintf(stdout, "Starting to start discovery\n");
+ CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed);
+ fprintf(stdout, "Started discovery for %d seconds\n", timeout_in_sec);
+
+ sleep(timeout_in_sec);
+
+ fprintf(stdout, "Starting to cancel discovery\n");
+ CALL_AND_WAIT(bt_interface->cancel_discovery(), discovery_state_changed);
+ fprintf(stdout, "Cancelled discovery after %d seconds\n", timeout_in_sec);
+ }
+
+ if (discoverable) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ bt_property_t* property =
+ property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+
+ int rc = bt_interface->set_adapter_property(property);
+ fprintf(stdout, "Set rc:%d device as discoverable for %d seconds\n", rc,
+ timeout_in_sec);
+
+ sleep(timeout_in_sec);
+
+ property_free(property);
+ }
+
+ if (bond) {
+ if (bdaddr_is_empty(&bt_remote_bdaddr)) {
+ fprintf(stderr,
+ "Must specify a remote device address [ "
+ "--bdaddr=xx:yy:zz:aa:bb:cc ]\n");
+ exit(1);
+ }
+
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ int rc = bt_interface->create_bond(
+ &bt_remote_bdaddr, 0 /* UNKNOWN; Currently not documented :( */);
+ fprintf(stdout, "Started bonding:%d for %d seconds\n", rc, timeout_in_sec);
+
+ sleep(timeout_in_sec);
+ }
+
+ if (up) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ fprintf(stdout, "Waiting for %d seconds\n", timeout_in_sec);
+ sleep(timeout_in_sec);
+ }
+
+ if (get_name) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+ int error;
+ CALL_AND_WAIT(
+ error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME),
+ adapter_properties);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to get adapter property\n");
+ exit(1);
+ }
+ bt_property_t* property = adapter_get_property(BT_PROPERTY_BDNAME);
+ const bt_bdname_t* name = property_as_name(property);
+ if (name)
+ printf("Queried bluetooth device name:%s\n", name->name);
+ else
+ printf("No name\n");
+ }
+
+ if (set_name) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ bt_property_t* property = property_new_name(bd_name);
+ printf("Setting bluetooth device name to:%s\n", bd_name);
+ int error;
+ CALL_AND_WAIT(error = bt_interface->set_adapter_property(property),
+ adapter_properties);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to set adapter property\n");
+ exit(1);
+ }
+ CALL_AND_WAIT(
+ error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME),
+ adapter_properties);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to get adapter property\n");
+ exit(1);
+ }
+ property_free(property);
+ sleep(timeout_in_sec);
+ }
+
+ const int app_uid = 0;
+
+ if (sco_listen) {
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ bt_property_t* property =
+ property_new_scan_mode(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ CALL_AND_WAIT(bt_interface->set_adapter_property(property),
+ adapter_properties);
+ property_free(property);
+
+ const btsock_interface_t* sock =
+ bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+
+ int rfcomm_fd = INVALID_FD;
+ int error =
+ sock->listen(BTSOCK_RFCOMM, "meow", (const uint8_t*)&HFP_AG_UUID, 0,
+ &rfcomm_fd, 0, app_uid);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to listen for incoming RFCOMM socket: %d\n",
+ error);
+ exit(1);
+ }
+
+ int sock_fd = INVALID_FD;
+ error = sock->listen(BTSOCK_SCO, NULL, NULL, 5, &sock_fd, 0, app_uid);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to listen for incoming SCO sockets: %d\n", error);
+ exit(1);
+ }
+ fprintf(stdout, "Waiting for incoming SCO connections...\n");
+ sleep(timeout_in_sec);
+ }
+
+ if (sco_connect) {
+ if (bdaddr_is_empty(&bt_remote_bdaddr)) {
+ fprintf(stderr,
+ "Must specify a remote device address [ "
+ "--bdaddr=xx:yy:zz:aa:bb:cc ]\n");
+ exit(1);
+ }
+
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is up\n");
+
+ const btsock_interface_t* sock =
+ bt_interface->get_profile_interface(BT_PROFILE_SOCKETS_ID);
+
+ int rfcomm_fd = INVALID_FD;
+ int error =
+ sock->connect(&bt_remote_bdaddr, BTSOCK_RFCOMM,
+ (const uint8_t*)&HFP_AG_UUID, 0, &rfcomm_fd, 0, app_uid);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to connect to RFCOMM socket: %d.\n", error);
+ exit(1);
+ }
+
+ WAIT(acl_state_changed);
+
+ fprintf(stdout, "Establishing SCO connection...\n");
+
+ int sock_fd = INVALID_FD;
+ error = sock->connect(&bt_remote_bdaddr, BTSOCK_SCO, NULL, 5, &sock_fd, 0,
+ app_uid);
+ if (error != BT_STATUS_SUCCESS) {
+ fprintf(stderr, "Unable to connect to SCO socket: %d.\n", error);
+ exit(1);
+ }
+ sleep(timeout_in_sec);
+ }
+
+ CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+ fprintf(stdout, "BT adapter is down\n");
+}
+
+static void sig_handler(int signo) {
+ if (signo == SIGINT) {
+ fprintf(stderr, "Received SIGINT\n");
+ CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+ fprintf(stderr, "BT adapter is down\n");
+ exit(1);
+ }
+}
+
+static void usage(const char* name) {
+ fprintf(stderr,
+ "Usage: %s "
+ "[--bond|--discover|--discoverable|--up|--sco_listen|--sco_connect] "
+ "[--bdaddr=<bdaddr>] [--time=<time_in_sec>] --verbose\n",
+ name);
+ fprintf(stderr, " bond: Discover actively advertising devices\n");
+ fprintf(stderr, " discover: Discover actively advertising devices\n");
+ fprintf(stderr,
+ " discoverable: Set into a connectable and discoverable mode\n");
+ fprintf(stderr, " up: Only bring up stack\n");
+ fprintf(stderr, " sco_listen: Listen for incoming SCO connections\n");
+ fprintf(stderr,
+ " sco_connect: Establish a SCO connection with another device\n");
+ fprintf(stderr, " time: Time to hold in the specified mode\n");
+ exit(1);
+}
+
+static bool parse_args(int argc, char** argv) {
+ while (1) {
+ int option_index = 0;
+ int c = getopt_long_only(argc, argv, "", long_options, &option_index);
+ if (c != 0) break;
+
+ switch (c) {
+ case 0:
+ if (option_index == 0) {
+ if (!string_to_bdaddr(optarg, &bt_remote_bdaddr)) {
+ return false;
+ }
+ }
+ if (option_index == 1) {
+ discover = true;
+ }
+ if (option_index == 2) {
+ discoverable = true;
+ }
+ if (option_index == 3) {
+ timeout_in_sec = atoi(optarg);
+ }
+ if (option_index == 4) {
+ bond = true;
+ }
+ if (option_index == 5) {
+ up = true;
+ }
+ if (option_index == 6) {
+ f_verbose++;
+ }
+ if (option_index == 7) {
+ get_name = true;
+ }
+ if (option_index == 8) {
+ bd_name = (char*)optarg;
+ set_name = true;
+ }
+ if (option_index == 9) {
+ sco_listen = true;
+ }
+ if (option_index == 10) {
+ sco_connect = true;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "non-option ARGV-elements: ");
+ while (optind < argc) fprintf(stderr, "%s ", argv[optind++]);
+ fprintf(stderr, "\n");
+ return false;
+ }
+ return true;
+}
diff --git a/mtkbt/code/bt/tools/hci/Android.mk.disabled b/mtkbt/code/bt/tools/hci/Android.mk.disabled
new file mode 100755
index 0000000..3e2286a
--- a/dev/null
+++ b/mtkbt/code/bt/tools/hci/Android.mk.disabled
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Bluetooth HCI tools for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := net_hci
+
+LOCAL_SRC_FILES := main.c
+LOCAL_STATIC_LIBRARIES := libosi
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../
+
+LOCAL_CFLAGS += $(bluetooth_CFLAGS)
+LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
+LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
+
+include $(BUILD_EXECUTABLE)
diff --git a/mtkbt/code/bt/tools/hci/main.c b/mtkbt/code/bt/tools/hci/main.c
new file mode 100755
index 0000000..c167886
--- a/dev/null
+++ b/mtkbt/code/bt/tools/hci/main.c
@@ -0,0 +1,215 @@
+#include <hardware/bluetooth.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "osi/include/osi.h"
+
+typedef int (*handler_t)(int argc, char** argv);
+
+typedef enum {
+ HCI_PACKET_COMMAND = 1,
+ HCI_PACKET_ACL_DATA = 2,
+ HCI_PACKET_SCO_DATA = 3,
+ HCI_PACKET_EVENT = 4,
+} hci_packet_t;
+
+typedef struct {
+ const char* name;
+ const char* help;
+ handler_t handler;
+} command_t;
+
+static int help(int argc, char** argv);
+static int set_discoverable(int argc, char** argv);
+static int set_name(int argc, char** argv);
+static int set_pcm_loopback(int argc, char** argv);
+static int set_sco_route(int argc, char** argv);
+
+static bool write_hci_command(hci_packet_t type, const void* packet,
+ size_t length);
+static const command_t* find_command(const char* name);
+static void usage(const char* name);
+
+static const command_t commands[] = {
+ {"help", "<command> - shows help text for <command>.", help},
+ {"setDiscoverable",
+ "(true|false) - whether the controller should be discoverable.",
+ set_discoverable},
+ {"setName", "<name> - sets the device's Bluetooth name to <name>.",
+ set_name},
+ {"setPcmLoopback",
+ "(true|false) - enables or disables PCM loopback on the controller.",
+ set_pcm_loopback},
+ {"setScoRoute",
+ "(pcm|i2s|uart) - sets the SCO packet route to one of the specified "
+ "buses.",
+ set_sco_route},
+};
+
+static int help(int argc, char** argv) {
+ if (!argc) {
+ printf("No help command specified.\n");
+ return 1;
+ }
+
+ const command_t* command = find_command(argv[0]);
+ if (!command) {
+ printf("No command named '%s'.\n", argv[0]);
+ return 2;
+ }
+
+ printf("%s %s\n", argv[0], command->help);
+ return 0;
+}
+
+static int set_discoverable(int argc, char** argv) {
+ if (argc != 1) {
+ printf("Discoverable mode not specified.\n");
+ return 1;
+ }
+
+ if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) {
+ printf("Invalid discoverable mode '%s'.\n", argv[0]);
+ return 2;
+ }
+
+ uint8_t packet[] = {0x1A, 0x0C, 0x01, 0x00};
+ if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x03;
+
+ return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+static int set_name(int argc, char** argv) {
+ if (argc != 1) {
+ printf("Device name not specified.\n");
+ return 1;
+ }
+
+ size_t len = strlen(argv[0]);
+ if (len > 247) {
+ printf("Device name cannot exceed 247 bytes.\n");
+ return 2;
+ }
+
+ uint8_t packet[251] = {0x13, 0x0C, 248};
+ memcpy(&packet[3], argv[0], len + 1);
+
+ if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) return 1;
+
+ memset(&packet[0], 0, sizeof(packet));
+ packet[0] = 0x52;
+ packet[1] = 0x0C;
+ packet[2] = 0xF1; // HCI command packet length.
+ packet[3] = 0x01; // FEC required.
+ packet[4] = len + 1;
+ packet[5] = 0x09; // Device name field tag.
+ memcpy(&packet[6], argv[0], len);
+ return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4);
+}
+
+static int set_pcm_loopback(int argc, char** argv) {
+ if (argc != 1) {
+ printf("PCM loopback mode not specified.\n");
+ return 1;
+ }
+
+ if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) {
+ printf("Invalid PCM mode '%s'.\n", argv[0]);
+ return 2;
+ }
+
+ uint8_t packet[] = {0x24, 0xFC, 0x01, 0x00};
+ if (argv[0][0] == 't') packet[ARRAY_SIZE(packet) - 1] = 0x01;
+
+ return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+static int set_sco_route(int argc, char** argv) {
+ if (argc != 1) {
+ printf("SCO route parameter must be specified.\n");
+ return 1;
+ }
+
+ uint8_t route = 0xFF;
+ if (!strcmp(argv[0], "pcm"))
+ route = 0;
+ else if (!strcmp(argv[0], "i2s"))
+ route = 3;
+ else if (!strcmp(argv[0], "uart"))
+ route = 1;
+
+ if (route == 0xFF) {
+ printf("Invalid SCO route specified: %s\n", argv[0]);
+ return 2;
+ }
+
+ uint8_t packet[] = {0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00};
+ packet[3] = route;
+
+ return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet));
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ const command_t* command = find_command(argv[1]);
+ if (!command) {
+ printf("Unrecognized command '%s'.\n", argv[1]);
+ return -2;
+ }
+
+ if (!command->handler) {
+ printf("Unhandled command '%s'.\n", argv[1]);
+ return -3;
+ }
+
+ return command->handler(argc - 2, &argv[2]);
+}
+
+static bool write_hci_command(hci_packet_t type, const void* packet,
+ size_t length) {
+ int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == INVALID_FD) goto error;
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(0x7F000001);
+ addr.sin_port = htons(8873);
+ int ret;
+ OSI_NO_INTR(ret = connect(sock, (const struct sockaddr*)&addr, sizeof(addr)));
+ if (ret == -1) goto error;
+
+ if (send(sock, &type, 1, 0) != 1) goto error;
+
+ if (send(sock, &length, 2, 0) != 2) goto error;
+
+ if (send(sock, packet, length, 0) != (ssize_t)length) goto error;
+
+ close(sock);
+ return true;
+
+error:;
+ close(sock);
+ return false;
+}
+
+static const command_t* find_command(const char* name) {
+ for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
+ if (!strcmp(commands[i].name, name)) return &commands[i];
+ return NULL;
+}
+
+static void usage(const char* name) {
+ printf("Usage: %s <command> [options]\n", name);
+ printf("Commands:\n");
+ for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
+ printf(" %s\n", commands[i].name);
+ printf("For detailed help on a command, run '%s help <command>'.\n", name);
+}
diff --git a/mtkbt/code/bt/tools/scripts/btsnooz.py b/mtkbt/code/bt/tools/scripts/btsnooz.py
new file mode 100755
index 0000000..6e0e112
--- a/dev/null
+++ b/mtkbt/code/bt/tools/scripts/btsnooz.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+"""
+This script extracts btsnooz content from bugreports and generates
+a valid btsnoop log file which can be viewed using standard tools
+like Wireshark.
+
+btsnooz is a custom format designed to be included in bugreports.
+It can be described as:
+
+base64 {
+ file_header
+ deflate {
+ repeated {
+ record_header
+ record_data
+ }
+ }
+}
+
+where the file_header and record_header are modified versions of
+the btsnoop headers.
+"""
+
+
+import base64
+import fileinput
+import struct
+import sys
+import zlib
+
+
+# Enumeration of the values the 'type' field can take in a btsnooz
+# header. These values come from the Bluetooth stack's internal
+# representation of packet types.
+TYPE_IN_EVT = 0x10
+TYPE_IN_ACL = 0x11
+TYPE_IN_SCO = 0x12
+TYPE_OUT_CMD = 0x20
+TYPE_OUT_ACL = 0x21
+TYPE_OUT_SCO = 0x22
+
+
+def type_to_direction(type):
+ """
+ Returns the inbound/outbound direction of a packet given its type.
+ 0 = sent packet
+ 1 = received packet
+ """
+ if type in [TYPE_IN_EVT, TYPE_IN_ACL, TYPE_IN_SCO]:
+ return 1
+ return 0
+
+
+def type_to_hci(type):
+ """
+ Returns the HCI type of a packet given its btsnooz type.
+ """
+ if type == TYPE_OUT_CMD:
+ return '\x01'
+ if type == TYPE_IN_ACL or type == TYPE_OUT_ACL:
+ return '\x02'
+ if type == TYPE_IN_SCO or type == TYPE_OUT_SCO:
+ return '\x03'
+ if type == TYPE_IN_EVT:
+ return '\x04'
+
+
+def decode_snooz(snooz):
+ """
+ Decodes all known versions of a btsnooz file into a btsnoop file.
+ """
+ version, last_timestamp_ms = struct.unpack_from('=bQ', snooz)
+
+ if version != 1 and version != 2:
+ sys.stderr.write('Unsupported btsnooz version: %s\n' % version)
+ exit(1)
+
+ # Oddly, the file header (9 bytes) is not compressed, but the rest is.
+ decompressed = zlib.decompress(snooz[9:])
+
+ sys.stdout.write('btsnoop\x00\x00\x00\x00\x01\x00\x00\x03\xea')
+
+ if version == 1:
+ decode_snooz_v1(decompressed, last_timestamp_ms)
+ elif version == 2:
+ decode_snooz_v2(decompressed, last_timestamp_ms)
+
+
+def decode_snooz_v1(decompressed, last_timestamp_ms):
+ """
+ Decodes btsnooz v1 files into a btsnoop file.
+ """
+ # An unfortunate consequence of the file format design: we have to do a
+ # pass of the entire file to determine the timestamp of the first packet.
+ first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+ offset = 0
+ while offset < len(decompressed):
+ length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+ offset += 7 + length - 1
+ first_timestamp_ms -= delta_time_ms
+
+ # Second pass does the actual writing out to stdout.
+ offset = 0
+ while offset < len(decompressed):
+ length, delta_time_ms, type = struct.unpack_from('=HIb', decompressed, offset)
+ first_timestamp_ms += delta_time_ms
+ offset += 7
+ sys.stdout.write(struct.pack('>II', length, length))
+ sys.stdout.write(struct.pack('>II', type_to_direction(type), 0))
+ sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+ sys.stdout.write(type_to_hci(type))
+ sys.stdout.write(decompressed[offset : offset + length - 1])
+ offset += length - 1
+
+
+def decode_snooz_v2(decompressed, last_timestamp_ms):
+ """
+ Decodes btsnooz v2 files into a btsnoop file.
+ """
+ # An unfortunate consequence of the file format design: we have to do a
+ # pass of the entire file to determine the timestamp of the first packet.
+ first_timestamp_ms = last_timestamp_ms + 0x00dcddb30f2f8000
+ offset = 0
+ while offset < len(decompressed):
+ length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+ offset += 9 + length - 1
+ first_timestamp_ms -= delta_time_ms
+
+ # Second pass does the actual writing out to stdout.
+ offset = 0
+ while offset < len(decompressed):
+ length, packet_length, delta_time_ms, snooz_type = struct.unpack_from('=HHIb', decompressed, offset)
+ first_timestamp_ms += delta_time_ms
+ offset += 9
+ sys.stdout.write(struct.pack('>II', packet_length, length))
+ sys.stdout.write(struct.pack('>II', type_to_direction(snooz_type), 0))
+ sys.stdout.write(struct.pack('>II', (first_timestamp_ms >> 32), (first_timestamp_ms & 0xFFFFFFFF)))
+ sys.stdout.write(type_to_hci(snooz_type))
+ sys.stdout.write(decompressed[offset : offset + length - 1])
+ offset += length - 1
+
+
+def main():
+ if len(sys.argv) > 2:
+ sys.stderr.write('Usage: %s [bugreport]\n' % sys.argv[0])
+ exit(1)
+
+ iterator = fileinput.input()
+ found = False
+ base64_string = ""
+ for line in iterator:
+ if found:
+ if line.find('--- END:BTSNOOP_LOG_SUMMARY') != -1:
+ decode_snooz(base64.standard_b64decode(base64_string))
+ sys.exit(0)
+ base64_string += line.strip()
+
+ if line.find('--- BEGIN:BTSNOOP_LOG_SUMMARY') != -1:
+ found = True
+
+ if not found:
+ sys.stderr.write('No btsnooz section found in bugreport.\n')
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/mtkbt/code/bt/tools/scripts/change_types.sh b/mtkbt/code/bt/tools/scripts/change_types.sh
new file mode 100755
index 0000000..244363c
--- a/dev/null
+++ b/mtkbt/code/bt/tools/scripts/change_types.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# This script will recursively search all |FILES| from the current
+# directory and replace all |TYPES| according to the list below.
+
+# NOTE 1:
+# If this script is run from .../system/bt (as it's intended to be),
+# please edit stack/include/bt_types.h next and remove the typedef's
+# near the top and restore the definitions of TRUE and FALSE. These
+# are still used in the vnd_* files and device specific repositories.
+
+# NOTE 2:
+# The list of files to be modified also includes "*.patch", which means
+# this script can be used to help cherry-picking changes from older
+# branches. Follow this workflow outline:
+# 1. git format-patch [-1] <your sha1>
+# 2. Run change_type script on patch[es]
+# 3. git apply / git am
+
+
+# Regular expression matching the file name
+FILES="\.h$|\.c$|\.cpp$|\.cc$|\.patch$"
+
+# Search/replace terms, separated by ":"
+TYPES=(
+ "UINT8 :uint8_t "
+ "UINT16 :uint16_t "
+ "UINT32 :uint32_t "
+ "UINT64 :uint64_t "
+ "INT8 :int8_t "
+ "INT16 :int16_t "
+ "INT32 :int32_t "
+ "INT64 :int64_t "
+ "UINT8:uint8_t"
+ "UINT16:uint16_t"
+ "UINT32:uint32_t"
+ "UINT64:uint64_t"
+ "INT8:int8_t"
+ "INT16:int16_t"
+ "INT32:int32_t"
+ "INT64:int64_t"
+ "BOOLEAN:bool "
+ "TRUE:true"
+ "FALSE:false"
+ "__FUNCTION__:__func__"
+)
+
+function process_file
+{
+ echo -n "Processing file $1 "
+
+ for tt in "${TYPES[@]}" ;
+ do
+ before=${tt%%:*}
+ after=${tt#*:}
+
+ echo -n "."
+ sed -i -e "s/\b${before}/${after}/g; s/${after}_/${before}_/g;" "$1"
+ done
+ echo
+}
+
+function process_files
+{
+ until [ -z "$1" ]
+ do
+ process_file "$1"
+ shift
+ done
+}
+
+
+# Let's do this ...
+process_files `find ./ | grep -E "${FILES}"`
+
+# All done ...
+echo
+echo "All done."
+
+# Try to be helpful ...
+PWD=`pwd`
+if [[ "${PWD}" == */system/bt ]]
+then
+ echo "Please edit ${PWD}/stack/include/bt_types.h next."
+fi
diff --git a/mtkbt/code/bt/tools/scripts/viewbtsnoop.sh b/mtkbt/code/bt/tools/scripts/viewbtsnoop.sh
new file mode 100755
index 0000000..61f2485
--- a/dev/null
+++ b/mtkbt/code/bt/tools/scripts/viewbtsnoop.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# This is a script that will allow you to open a btsnooz log
+# in wireshark directly from a zip file. This script will handle
+# the unzipping if it is a zip file, or will convert the btsnooz
+# directly in the case of a plain text file for use with wireshark.
+# After wireshark closes, it will clean up all the temporary files
+# used.
+
+WIRESHARK="${WIRESHARK:-wireshark}"
+BTSNOOZ="${BTSNOOZ:-btsnooz.py}"
+
+if ! hash "${WIRESHARK}" 2>/dev/null;
+then
+ echo "Please make sure wireshark is in your path before running."
+ exit 1;
+fi
+
+if ! hash btsnooz.py 2>/dev/null;
+then
+ echo "Please make sure btsnooz.py is in your path before running."
+ exit 2;
+fi
+
+if [ $# -eq 0 ];
+then
+ echo "Usage: $0 bugreport(.txt|.zip)"
+ exit 3;
+fi
+
+BUGREPORT="$1"
+FILENAME="$(basename ${BUGREPORT})"
+TMPDIR=$(mktemp --tmpdir -d "viewbtsnooz_XXXXX")
+LOGFILE="${TMPDIR}/${FILENAME%.*}.btsnooz"
+
+trap ctrl_c INT
+function ctrl_c() {
+ rm -rf "${TMPDIR}"
+}
+
+if [ ! -f "${BUGREPORT}" ];
+then
+ echo "File ${BUGREPORT} does not exist."
+ exit 4;
+fi
+
+if [ ! -d "${TMPDIR}" ];
+then
+ echo "Unable to create temp. dir (${TMPDIR}) :("
+ exit 5;
+fi
+
+if [ "${BUGREPORT: -4}" == ".zip" ];
+then
+ unzip "${BUGREPORT}" -d "${TMPDIR}"
+ BUGREPORT="${TMPDIR}/${FILENAME%.*}.txt"
+fi
+
+if [ -f "${BUGREPORT}" ];
+then
+ ${BTSNOOZ} "${BUGREPORT}" > "${LOGFILE}"
+ if [ ! $? -eq 0 ];
+ then
+ echo "Could not extract btsnooz data from ${BUGREPORT}."
+ rm -rf "${TMPDIR}"
+ exit 6;
+ fi
+
+ ${WIRESHARK} "${LOGFILE}"
+else
+ echo "Looks like there is no plain text bugreport (${BUGREPORT})?"
+fi
+
+rm -rf "${TMPDIR}"
diff --git a/mtkbt/code/bt/udrv/Android.bp b/mtkbt/code/bt/udrv/Android.bp
new file mode 100755
index 0000000..e4dd8f2
--- a/dev/null
+++ b/mtkbt/code/bt/udrv/Android.bp
@@ -0,0 +1,19 @@
+cc_library_static {
+ name: "libudrv-uipc",
+ defaults: ["fluoride_defaults"],
+ srcs: [
+ "ulinux/uipc.cc",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+}
diff --git a/mtkbt/code/bt/udrv/BUILD.gn b/mtkbt/code/bt/udrv/BUILD.gn
new file mode 100755
index 0000000..679d469
--- a/dev/null
+++ b/mtkbt/code/bt/udrv/BUILD.gn
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+source_set("udrv") {
+ sources = [
+ "ulinux/uipc.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "uipc",
+ "//",
+ "//include",
+ "//stack/include",
+ "//utils/include",
+ ]
+}
diff --git a/mtkbt/code/bt/udrv/include/uipc.h b/mtkbt/code/bt/udrv/include/uipc.h
new file mode 100755
index 0000000..62fadf1
--- a/dev/null
+++ b/mtkbt/code/bt/udrv/include/uipc.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2007-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+#ifndef UIPC_H
+#define UIPC_H
+
+#define UIPC_CH_ID_AV_CTRL 0
+#define UIPC_CH_ID_AV_AUDIO 1
+#define UIPC_CH_NUM 2
+
+#define UIPC_CH_ID_ALL 3 /* used to address all the ch id at once */
+
+#define DEFAULT_READ_POLL_TMO_MS 100
+
+typedef uint8_t tUIPC_CH_ID;
+
+/* Events generated */
+typedef enum {
+ UIPC_OPEN_EVT = 0x0001,
+ UIPC_CLOSE_EVT = 0x0002,
+ UIPC_RX_DATA_EVT = 0x0004,
+ UIPC_RX_DATA_READY_EVT = 0x0008,
+ UIPC_TX_DATA_READY_EVT = 0x0010
+} tUIPC_EVENT;
+
+/*
+ * UIPC IOCTL Requests
+ */
+
+#define UIPC_REQ_RX_FLUSH 1
+#define UIPC_REG_CBACK 2
+#define UIPC_REG_REMOVE_ACTIVE_READSET 3
+#define UIPC_SET_READ_POLL_TMO 4
+
+typedef void(tUIPC_RCV_CBACK)(
+ tUIPC_CH_ID ch_id,
+ tUIPC_EVENT event); /* points to BT_HDR which describes event type and
+ length of data; len contains the number of bytes of
+ entire message (sizeof(BT_HDR) + offset + size of
+ data) */
+
+const char* dump_uipc_event(tUIPC_EVENT event);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Init
+ *
+ * Description Initialize UIPC module
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void UIPC_Init(void*);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Open
+ *
+ * Description Open UIPC interface
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Close
+ *
+ * Description Close UIPC interface
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void UIPC_Close(tUIPC_CH_ID ch_id);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Send
+ *
+ * Description Called to transmit a message over UIPC.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool UIPC_Send(tUIPC_CH_ID ch_id, uint16_t msg_evt, const uint8_t* p_buf,
+ uint16_t msglen);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Read
+ *
+ * Description Called to read a message from UIPC.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+uint32_t UIPC_Read(tUIPC_CH_ID ch_id, uint16_t* p_msg_evt, uint8_t* p_buf,
+ uint32_t len);
+
+/*******************************************************************************
+ *
+ * Function UIPC_Ioctl
+ *
+ * Description Called to control UIPC.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param);
+
+#endif /* UIPC_H */
diff --git a/mtkbt/code/bt/udrv/ulinux/uipc.cc b/mtkbt/code/bt/udrv/ulinux/uipc.cc
new file mode 100755
index 0000000..a524a36
--- a/dev/null
+++ b/mtkbt/code/bt/udrv/ulinux/uipc.cc
@@ -0,0 +1,769 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: uipc.cc
+ *
+ * Description: UIPC implementation for fluoride
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <mutex>
+
+#include "audio_a2dp_hw/include/audio_a2dp_hw.h"
+#include "bt_common.h"
+#include "bt_types.h"
+#include "bt_utils.h"
+#include "osi/include/osi.h"
+#include "osi/include/socket_utils/sockets.h"
+#include "uipc.h"
+
+/*****************************************************************************
+ * Constants & Macros
+ *****************************************************************************/
+
+#define PCM_FILENAME "/data/test.pcm"
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define CASE_RETURN_STR(const) \
+ case const: \
+ return #const;
+
+#define UIPC_DISCONNECTED (-1)
+
+#define SAFE_FD_ISSET(fd, set) (((fd) == -1) ? false : FD_ISSET((fd), (set)))
+
+#define UIPC_FLUSH_BUFFER_SIZE 1024
+
+/*****************************************************************************
+ * Local type definitions
+ *****************************************************************************/
+
+typedef enum {
+ UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
+} tUIPC_TASK_FLAGS;
+
+typedef struct {
+ int srvfd;
+ int fd;
+ int read_poll_tmo_ms;
+ int task_evt_flags; /* event flags pending to be processed in read task */
+ tUIPC_RCV_CBACK* cback;
+} tUIPC_CHAN;
+
+typedef struct {
+ pthread_t tid; /* main thread id */
+ int running;
+ std::recursive_mutex mutex;
+
+ fd_set active_set;
+ fd_set read_set;
+ int max_fd;
+ int signal_fds[2];
+
+ tUIPC_CHAN ch[UIPC_CH_NUM];
+} tUIPC_MAIN;
+
+/*****************************************************************************
+ * Static variables
+ *****************************************************************************/
+
+static tUIPC_MAIN uipc_main;
+
+/*****************************************************************************
+ * Static functions
+ *****************************************************************************/
+
+static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
+
+/*****************************************************************************
+ * Externs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Helper functions
+ *****************************************************************************/
+
+const char* dump_uipc_event(tUIPC_EVENT event) {
+ switch (event) {
+ CASE_RETURN_STR(UIPC_OPEN_EVT)
+ CASE_RETURN_STR(UIPC_CLOSE_EVT)
+ CASE_RETURN_STR(UIPC_RX_DATA_EVT)
+ CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT)
+ CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+/*****************************************************************************
+ * socket helper functions
+ ****************************************************************************/
+
+static inline int create_server_socket(const char* name) {
+ int s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (s < 0) return -1;
+
+ BTIF_TRACE_EVENT("create_server_socket %s", name);
+
+ if (osi_socket_local_server_bind(s, name,
+#if defined(OS_GENERIC)
+ ANDROID_SOCKET_NAMESPACE_FILESYSTEM
+#else // !defined(OS_GENERIC)
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT
+#endif // defined(OS_GENERIC)
+ ) < 0) {
+ BTIF_TRACE_EVENT("socket failed to create (%s)", strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ if (listen(s, 5) < 0) {
+ BTIF_TRACE_EVENT("listen failed", strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ BTIF_TRACE_EVENT("created socket fd %d", s);
+ return s;
+}
+
+static int accept_server_socket(int sfd) {
+ struct sockaddr_un remote;
+ struct pollfd pfd;
+ int fd;
+ socklen_t len = sizeof(struct sockaddr_un);
+
+ BTIF_TRACE_EVENT("accept fd %d", sfd);
+
+ /* make sure there is data to process */
+ pfd.fd = sfd;
+ pfd.events = POLLIN;
+
+ int poll_ret;
+ OSI_NO_INTR(poll_ret = poll(&pfd, 1, 0));
+ if (poll_ret == 0) {
+ BTIF_TRACE_WARNING("accept poll timeout");
+ return -1;
+ }
+
+ // BTIF_TRACE_EVENT("poll revents 0x%x", pfd.revents);
+
+ OSI_NO_INTR(fd = accept(sfd, (struct sockaddr*)&remote, &len));
+ if (fd == -1) {
+ BTIF_TRACE_ERROR("sock accept failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ // match socket buffer size option with client
+ const int size = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
+ int ret =
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
+ if (ret < 0) {
+ BTIF_TRACE_ERROR("setsockopt failed (%s)", strerror(errno));
+ }
+
+ // BTIF_TRACE_EVENT("new fd %d", fd);
+
+ return fd;
+}
+
+/*****************************************************************************
+ *
+ * uipc helper functions
+ *
+ ****************************************************************************/
+
+static int uipc_main_init(void) {
+ int i;
+
+ BTIF_TRACE_EVENT("### uipc_main_init ###");
+
+ uipc_main.tid = 0;
+ uipc_main.running = 0;
+ memset(&uipc_main.active_set, 0, sizeof(uipc_main.active_set));
+ memset(&uipc_main.read_set, 0, sizeof(uipc_main.read_set));
+ uipc_main.max_fd = 0;
+ memset(&uipc_main.signal_fds, 0, sizeof(uipc_main.signal_fds));
+ memset(&uipc_main.ch, 0, sizeof(uipc_main.ch));
+
+ /* setup interrupt socket pair */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc_main.signal_fds) < 0) {
+ return -1;
+ }
+
+ FD_SET(uipc_main.signal_fds[0], &uipc_main.active_set);
+ uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.signal_fds[0]);
+
+ for (i = 0; i < UIPC_CH_NUM; i++) {
+ tUIPC_CHAN* p = &uipc_main.ch[i];
+ p->srvfd = UIPC_DISCONNECTED;
+ p->fd = UIPC_DISCONNECTED;
+ p->task_evt_flags = 0;
+ p->cback = NULL;
+ }
+
+ return 0;
+}
+
+void uipc_main_cleanup(void) {
+ int i;
+
+ BTIF_TRACE_EVENT("uipc_main_cleanup");
+
+ close(uipc_main.signal_fds[0]);
+ close(uipc_main.signal_fds[1]);
+
+ /* close any open channels */
+ for (i = 0; i < UIPC_CH_NUM; i++) uipc_close_ch_locked(i);
+}
+
+/* check pending events in read task */
+static void uipc_check_task_flags_locked(void) {
+ int i;
+
+ for (i = 0; i < UIPC_CH_NUM; i++) {
+ if (uipc_main.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
+ uipc_main.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
+ uipc_close_ch_locked(i);
+ }
+
+ /* add here */
+ }
+}
+
+static int uipc_check_fd_locked(tUIPC_CH_ID ch_id) {
+ if (ch_id >= UIPC_CH_NUM) return -1;
+
+ // BTIF_TRACE_EVENT("CHECK SRVFD %d (ch %d)", uipc_main.ch[ch_id].srvfd,
+ // ch_id);
+
+ if (SAFE_FD_ISSET(uipc_main.ch[ch_id].srvfd, &uipc_main.read_set)) {
+ BTIF_TRACE_EVENT("INCOMING CONNECTION ON CH %d", ch_id);
+
+ // Close the previous connection
+ if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
+ close(uipc_main.ch[ch_id].fd);
+ FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+ uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
+ }
+
+ uipc_main.ch[ch_id].fd = accept_server_socket(uipc_main.ch[ch_id].srvfd);
+
+ BTIF_TRACE_EVENT("NEW FD %d", uipc_main.ch[ch_id].fd);
+
+ if ((uipc_main.ch[ch_id].fd >= 0) && uipc_main.ch[ch_id].cback) {
+ /* if we have a callback we should add this fd to the active set
+ and notify user with callback event */
+ BTIF_TRACE_EVENT("ADD FD %d TO ACTIVE SET", uipc_main.ch[ch_id].fd);
+ FD_SET(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+ uipc_main.max_fd = MAX(uipc_main.max_fd, uipc_main.ch[ch_id].fd);
+ }
+
+ if (uipc_main.ch[ch_id].fd < 0) {
+ BTIF_TRACE_ERROR("FAILED TO ACCEPT CH %d (%s)", ch_id, strerror(errno));
+ return -1;
+ }
+
+ if (uipc_main.ch[ch_id].cback)
+ uipc_main.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
+ }
+
+ // BTIF_TRACE_EVENT("CHECK FD %d (ch %d)", uipc_main.ch[ch_id].fd, ch_id);
+
+ if (SAFE_FD_ISSET(uipc_main.ch[ch_id].fd, &uipc_main.read_set)) {
+ // BTIF_TRACE_EVENT("INCOMING DATA ON CH %d", ch_id);
+
+ if (uipc_main.ch[ch_id].cback)
+ uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
+ }
+ return 0;
+}
+
+static void uipc_check_interrupt_locked(void) {
+ if (SAFE_FD_ISSET(uipc_main.signal_fds[0], &uipc_main.read_set)) {
+ char sig_recv = 0;
+ OSI_NO_INTR(recv(uipc_main.signal_fds[0], &sig_recv, sizeof(sig_recv),
+ MSG_WAITALL));
+ }
+}
+
+static inline void uipc_wakeup_locked(void) {
+ char sig_on = 1;
+ BTIF_TRACE_EVENT("UIPC SEND WAKE UP");
+
+ OSI_NO_INTR(send(uipc_main.signal_fds[1], &sig_on, sizeof(sig_on), 0));
+}
+
+static int uipc_setup_server_locked(tUIPC_CH_ID ch_id, const char* name,
+ tUIPC_RCV_CBACK* cback) {
+ int fd;
+
+ BTIF_TRACE_EVENT("SETUP CHANNEL SERVER %d", ch_id);
+
+ if (ch_id >= UIPC_CH_NUM) return -1;
+
+ std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
+
+ fd = create_server_socket(name);
+
+ if (fd < 0) {
+ BTIF_TRACE_ERROR("failed to setup %s", name, strerror(errno));
+ return -1;
+ }
+
+ BTIF_TRACE_EVENT("ADD SERVER FD TO ACTIVE SET %d", fd);
+ FD_SET(fd, &uipc_main.active_set);
+ uipc_main.max_fd = MAX(uipc_main.max_fd, fd);
+
+ uipc_main.ch[ch_id].srvfd = fd;
+ uipc_main.ch[ch_id].cback = cback;
+ uipc_main.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
+
+ /* trigger main thread to update read set */
+ uipc_wakeup_locked();
+
+ return 0;
+}
+
+static void uipc_flush_ch_locked(tUIPC_CH_ID ch_id) {
+ char buf[UIPC_FLUSH_BUFFER_SIZE];
+ struct pollfd pfd;
+
+ pfd.events = POLLIN;
+ pfd.fd = uipc_main.ch[ch_id].fd;
+
+ if (uipc_main.ch[ch_id].fd == UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("%s() - fd disconnected. Exiting", __func__);
+ return;
+ }
+
+ while (1) {
+ int ret;
+ OSI_NO_INTR(ret = poll(&pfd, 1, 1));
+ if (ret == 0) {
+ BTIF_TRACE_VERBOSE("%s(): poll() timeout - nothing to do. Exiting",
+ __func__);
+ return;
+ }
+ if (ret < 0) {
+ BTIF_TRACE_WARNING(
+ "%s() - poll() failed: return %d errno %d (%s). Exiting", __func__,
+ ret, errno, strerror(errno));
+ return;
+ }
+ BTIF_TRACE_VERBOSE("%s() - polling fd %d, revents: 0x%x, ret %d", __func__,
+ pfd.fd, pfd.revents, ret);
+ if (pfd.revents & (POLLERR | POLLHUP)) {
+ BTIF_TRACE_WARNING("%s() - POLLERR or POLLHUP. Exiting", __func__);
+ return;
+ }
+
+ /* read sufficiently large buffer to ensure flush empties socket faster than
+ it is getting refilled */
+ read(pfd.fd, &buf, UIPC_FLUSH_BUFFER_SIZE);
+ }
+}
+
+static void uipc_flush_locked(tUIPC_CH_ID ch_id) {
+ if (ch_id >= UIPC_CH_NUM) return;
+
+ switch (ch_id) {
+ case UIPC_CH_ID_AV_CTRL:
+ uipc_flush_ch_locked(UIPC_CH_ID_AV_CTRL);
+ break;
+
+ case UIPC_CH_ID_AV_AUDIO:
+ uipc_flush_ch_locked(UIPC_CH_ID_AV_AUDIO);
+ break;
+ }
+}
+
+static int uipc_close_ch_locked(tUIPC_CH_ID ch_id) {
+ int wakeup = 0;
+
+ BTIF_TRACE_EVENT("CLOSE CHANNEL %d", ch_id);
+
+ if (ch_id >= UIPC_CH_NUM) return -1;
+
+ if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("CLOSE SERVER (FD %d)", uipc_main.ch[ch_id].srvfd);
+ close(uipc_main.ch[ch_id].srvfd);
+ FD_CLR(uipc_main.ch[ch_id].srvfd, &uipc_main.active_set);
+ uipc_main.ch[ch_id].srvfd = UIPC_DISCONNECTED;
+ wakeup = 1;
+ }
+
+ if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("CLOSE CONNECTION (FD %d)", uipc_main.ch[ch_id].fd);
+ close(uipc_main.ch[ch_id].fd);
+ FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+ uipc_main.ch[ch_id].fd = UIPC_DISCONNECTED;
+ wakeup = 1;
+ }
+
+ /* notify this connection is closed */
+ if (uipc_main.ch[ch_id].cback)
+ uipc_main.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
+
+ /* trigger main thread update if something was updated */
+ if (wakeup) uipc_wakeup_locked();
+
+ return 0;
+}
+
+void uipc_close_locked(tUIPC_CH_ID ch_id) {
+ if (uipc_main.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("CHANNEL %d ALREADY CLOSED", ch_id);
+ return;
+ }
+
+ /* schedule close on this channel */
+ uipc_main.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
+ uipc_wakeup_locked();
+}
+
+static void* uipc_read_task(UNUSED_ATTR void* arg) {
+ int ch_id;
+ int result;
+
+ prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0);
+
+ raise_priority_a2dp(TASK_UIPC_READ);
+
+ while (uipc_main.running) {
+ uipc_main.read_set = uipc_main.active_set;
+
+ result =
+ select(uipc_main.max_fd + 1, &uipc_main.read_set, NULL, NULL, NULL);
+
+ if (result == 0) {
+ BTIF_TRACE_EVENT("select timeout");
+ continue;
+ }
+ if (result < 0) {
+ if (errno != EINTR) {
+ BTIF_TRACE_EVENT("select failed %s", strerror(errno));
+ }
+ continue;
+ }
+
+ {
+ std::lock_guard<std::recursive_mutex> guard(uipc_main.mutex);
+
+ /* clear any wakeup interrupt */
+ uipc_check_interrupt_locked();
+
+ /* check pending task events */
+ uipc_check_task_flags_locked();
+
+ /* make sure we service audio channel first */
+ uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);
+
+ /* check for other connections */
+ for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
+ if (ch_id != UIPC_CH_ID_AV_AUDIO) uipc_check_fd_locked(ch_id);
+ }
+ }
+ }
+
+ BTIF_TRACE_EVENT("UIPC READ THREAD EXITING");
+
+ uipc_main_cleanup();
+
+ uipc_main.tid = 0;
+
+ BTIF_TRACE_EVENT("UIPC READ THREAD DONE");
+
+ return nullptr;
+}
+
+int uipc_start_main_server_thread(void) {
+ uipc_main.running = 1;
+
+ if (pthread_create(&uipc_main.tid, (const pthread_attr_t*)NULL,
+ uipc_read_task, nullptr) < 0) {
+ BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* blocking call */
+void uipc_stop_main_server_thread(void) {
+ /* request shutdown of read thread */
+ {
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+ uipc_main.running = 0;
+ uipc_wakeup_locked();
+ }
+
+ /* wait until read thread is fully terminated */
+ /* tid might hold pointer value where it's value
+ is negative vaule with singed bit is set, so
+ corrected the logic to check zero or non zero */
+ if (uipc_main.tid) pthread_join(uipc_main.tid, NULL);
+}
+
+/*******************************************************************************
+ **
+ ** Function UIPC_Init
+ **
+ ** Description Initialize UIPC module
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+
+void UIPC_Init(UNUSED_ATTR void* p_data) {
+ BTIF_TRACE_DEBUG("UIPC_Init");
+
+ uipc_main_init();
+ uipc_start_main_server_thread();
+}
+
+/*******************************************************************************
+ **
+ ** Function UIPC_Open
+ **
+ ** Description Open UIPC interface
+ **
+ ** Returns true in case of success, false in case of failure.
+ **
+ ******************************************************************************/
+bool UIPC_Open(tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback) {
+ BTIF_TRACE_DEBUG("UIPC_Open : ch_id %d, p_cback %x", ch_id, p_cback);
+
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+
+ if (ch_id >= UIPC_CH_NUM) {
+ return false;
+ }
+
+ if (uipc_main.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
+ BTIF_TRACE_EVENT("CHANNEL %d ALREADY OPEN", ch_id);
+ return 0;
+ }
+
+ switch (ch_id) {
+ case UIPC_CH_ID_AV_CTRL:
+ uipc_setup_server_locked(ch_id, A2DP_CTRL_PATH, p_cback);
+ break;
+
+ case UIPC_CH_ID_AV_AUDIO:
+ uipc_setup_server_locked(ch_id, A2DP_DATA_PATH, p_cback);
+ break;
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ **
+ ** Function UIPC_Close
+ **
+ ** Description Close UIPC interface
+ **
+ ** Returns void
+ **
+ ******************************************************************************/
+
+void UIPC_Close(tUIPC_CH_ID ch_id) {
+ BTIF_TRACE_DEBUG("UIPC_Close : ch_id %d", ch_id);
+
+ /* special case handling uipc shutdown */
+ if (ch_id != UIPC_CH_ID_ALL) {
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+ uipc_close_locked(ch_id);
+ return;
+ }
+ BTIF_TRACE_DEBUG("UIPC_Close : waiting for shutdown to complete");
+ uipc_stop_main_server_thread();
+ BTIF_TRACE_DEBUG("UIPC_Close : shutdown complete");
+}
+
+/*******************************************************************************
+ **
+ ** Function UIPC_Send
+ **
+ ** Description Called to transmit a message over UIPC.
+ **
+ ** Returns true in case of success, false in case of failure.
+ **
+ ******************************************************************************/
+bool UIPC_Send(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t msg_evt,
+ const uint8_t* p_buf, uint16_t msglen) {
+ BTIF_TRACE_DEBUG("UIPC_Send : ch_id:%d %d bytes", ch_id, msglen);
+
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+
+ ssize_t ret;
+ OSI_NO_INTR(ret = write(uipc_main.ch[ch_id].fd, p_buf, msglen));
+ if (ret < 0) {
+ BTIF_TRACE_ERROR("failed to write (%s)", strerror(errno));
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function UIPC_Read
+ **
+ ** Description Called to read a message from UIPC.
+ **
+ ** Returns return the number of bytes read.
+ **
+ ******************************************************************************/
+
+uint32_t UIPC_Read(tUIPC_CH_ID ch_id, UNUSED_ATTR uint16_t* p_msg_evt,
+ uint8_t* p_buf, uint32_t len) {
+ int n_read = 0;
+ int fd = uipc_main.ch[ch_id].fd;
+ struct pollfd pfd;
+
+ if (ch_id >= UIPC_CH_NUM) {
+ BTIF_TRACE_ERROR("UIPC_Read : invalid ch id %d", ch_id);
+ return 0;
+ }
+
+ if (fd == UIPC_DISCONNECTED) {
+ BTIF_TRACE_ERROR("UIPC_Read : channel %d closed", ch_id);
+ return 0;
+ }
+
+ while (n_read < (int)len) {
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLHUP;
+
+ /* make sure there is data prior to attempting read to avoid blocking
+ a read for more than poll timeout */
+
+ int poll_ret;
+ OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc_main.ch[ch_id].read_poll_tmo_ms));
+ if (poll_ret == 0) {
+ BTIF_TRACE_WARNING("poll timeout (%d ms)",
+ uipc_main.ch[ch_id].read_poll_tmo_ms);
+ break;
+ }
+ if (poll_ret < 0) {
+ BTIF_TRACE_ERROR("%s(): poll() failed: return %d errno %d (%s)", __func__,
+ poll_ret, errno, strerror(errno));
+ break;
+ }
+
+ // BTIF_TRACE_EVENT("poll revents %x", pfd.revents);
+
+ if (pfd.revents & (POLLHUP | POLLNVAL)) {
+ BTIF_TRACE_WARNING("poll : channel detached remotely");
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+ uipc_close_locked(ch_id);
+ return 0;
+ }
+
+ ssize_t n;
+ OSI_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
+
+ // BTIF_TRACE_EVENT("read %d bytes", n);
+
+ if (n == 0) {
+ BTIF_TRACE_WARNING("UIPC_Read : channel detached remotely");
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+ uipc_close_locked(ch_id);
+ return 0;
+ }
+
+ if (n < 0) {
+ BTIF_TRACE_WARNING("UIPC_Read : read failed (%s)", strerror(errno));
+ return 0;
+ }
+
+ n_read += n;
+ }
+
+ return n_read;
+}
+
+/*******************************************************************************
+ *
+ * Function UIPC_Ioctl
+ *
+ * Description Called to control UIPC.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+
+extern bool UIPC_Ioctl(tUIPC_CH_ID ch_id, uint32_t request, void* param) {
+ BTIF_TRACE_DEBUG("#### UIPC_Ioctl : ch_id %d, request %d ####", ch_id,
+ request);
+ std::lock_guard<std::recursive_mutex> lock(uipc_main.mutex);
+
+ switch (request) {
+ case UIPC_REQ_RX_FLUSH:
+ uipc_flush_locked(ch_id);
+ break;
+
+ case UIPC_REG_CBACK:
+ // BTIF_TRACE_EVENT("register callback ch %d srvfd %d, fd %d", ch_id,
+ // uipc_main.ch[ch_id].srvfd, uipc_main.ch[ch_id].fd);
+ uipc_main.ch[ch_id].cback = (tUIPC_RCV_CBACK*)param;
+ break;
+
+ case UIPC_REG_REMOVE_ACTIVE_READSET:
+ /* user will read data directly and not use select loop */
+ if (uipc_main.ch[ch_id].fd != UIPC_DISCONNECTED) {
+ /* remove this channel from active set */
+ FD_CLR(uipc_main.ch[ch_id].fd, &uipc_main.active_set);
+
+ /* refresh active set */
+ uipc_wakeup_locked();
+ }
+ break;
+
+ case UIPC_SET_READ_POLL_TMO:
+ uipc_main.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
+ BTIF_TRACE_EVENT("UIPC_SET_READ_POLL_TMO : CH %d, TMO %d ms", ch_id,
+ uipc_main.ch[ch_id].read_poll_tmo_ms);
+ break;
+
+ default:
+ BTIF_TRACE_EVENT("UIPC_Ioctl : request not handled (%d)", request);
+ break;
+ }
+
+ return false;
+}
diff --git a/mtkbt/code/bt/utils/Android.bp b/mtkbt/code/bt/utils/Android.bp
new file mode 100755
index 0000000..c3defbc
--- a/dev/null
+++ b/mtkbt/code/bt/utils/Android.bp
@@ -0,0 +1,15 @@
+// Utils static library for target
+// ========================================================
+cc_library_static {
+ name: "libbt-utils",
+ defaults: ["fluoride_defaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/btcore/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ srcs: ["src/bt_utils.cc"],
+}
diff --git a/mtkbt/code/bt/utils/BUILD.gn b/mtkbt/code/bt/utils/BUILD.gn
new file mode 100755
index 0000000..13d57a1
--- a/dev/null
+++ b/mtkbt/code/bt/utils/BUILD.gn
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2015 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+static_library("utils") {
+ sources = [
+ "src/bt_utils.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ "//stack/include",
+ ]
+}
diff --git a/mtkbt/code/bt/utils/include/bt_utils.h b/mtkbt/code/bt/utils/include/bt_utils.h
new file mode 100755
index 0000000..e315365
--- a/dev/null
+++ b/mtkbt/code/bt/utils/include/bt_utils.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#ifndef BT_UTILS_H
+#define BT_UTILS_H
+
+static const char BT_UTILS_MODULE[] = "bt_utils_module";
+
+/*******************************************************************************
+ * Type definitions
+ ******************************************************************************/
+
+typedef enum {
+ TASK_HIGH_MEDIA = 0,
+ TASK_UIPC_READ,
+ TASK_HIGH_MAX
+} tHIGH_PRIORITY_TASK;
+
+/*******************************************************************************
+ * Functions
+ ******************************************************************************/
+
+void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task);
+/**M:Bug fix for A2DP start fail @{*/
+void raise_priority_jni(bool raise);
+/**@}*/
+#endif /* BT_UTILS_H */
diff --git a/mtkbt/code/bt/utils/src/bt_utils.cc b/mtkbt/code/bt/utils/src/bt_utils.cc
new file mode 100755
index 0000000..6fb68c2
--- a/dev/null
+++ b/mtkbt/code/bt/utils/src/bt_utils.cc
@@ -0,0 +1,178 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2012 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename: bt_utils.cc
+ *
+ * Description: Miscellaneous helper functions
+ *
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_utils"
+
+#include "bt_utils.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <mutex>
+
+#define A2DP_RT_PRIORITY 1
+#ifndef OS_GENERIC
+#include <cutils/sched_policy.h>
+#endif
+
+#include "bt_types.h"
+#include "btcore/include/module.h"
+#include "osi/include/compat.h"
+#include "osi/include/log.h"
+#include "osi/include/properties.h"
+
+/*******************************************************************************
+ * Type definitions for callback functions
+ ******************************************************************************/
+static pthread_once_t g_DoSchedulingGroupOnce[TASK_HIGH_MAX];
+static bool g_DoSchedulingGroup[TASK_HIGH_MAX];
+static std::mutex gIdxLock;
+static int g_TaskIdx;
+static int g_TaskIDs[TASK_HIGH_MAX];
+#define INVALID_TASK_ID (-1)
+
+static future_t* init(void) {
+ int i;
+
+ for (i = 0; i < TASK_HIGH_MAX; i++) {
+ g_DoSchedulingGroupOnce[i] = PTHREAD_ONCE_INIT;
+ g_DoSchedulingGroup[i] = true;
+ g_TaskIDs[i] = INVALID_TASK_ID;
+ }
+
+ return NULL;
+}
+
+static future_t* clean_up(void) {
+ return NULL;
+}
+
+EXPORT_SYMBOL extern const module_t bt_utils_module = {.name = BT_UTILS_MODULE,
+ .init = init,
+ .start_up = NULL,
+ .shut_down = NULL,
+ .clean_up = clean_up,
+ .dependencies = {NULL}};
+
+/*****************************************************************************
+ *
+ * Function check_do_scheduling_group
+ *
+ * Description check if it is ok to change schedule group
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+static void check_do_scheduling_group(void) {
+ char buf[PROPERTY_VALUE_MAX];
+ int len = osi_property_get("debug.sys.noschedgroups", buf, "");
+ if (len > 0) {
+ int temp;
+ if (sscanf(buf, "%d", &temp) == 1) {
+ g_DoSchedulingGroup[g_TaskIdx] = temp == 0;
+ }
+ }
+}
+
+/*****************************************************************************
+ *
+ * Function raise_priority_a2dp
+ *
+ * Description Raise task priority for A2DP streaming
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) {
+ int rc = 0;
+ int tid = gettid();
+
+ {
+ std::lock_guard<std::mutex> lock(gIdxLock);
+ g_TaskIdx = high_task;
+
+// TODO(armansito): Remove this conditional check once we find a solution
+// for system/core on non-Android platforms.
+#if defined(OS_GENERIC)
+ rc = -1;
+#else // !defined(OS_GENERIC)
+ pthread_once(&g_DoSchedulingGroupOnce[g_TaskIdx],
+ check_do_scheduling_group);
+ if (g_DoSchedulingGroup[g_TaskIdx]) {
+ // set_sched_policy does not support tid == 0
+ rc = set_sched_policy(tid, SP_AUDIO_SYS);
+ }
+#endif // defined(OS_GENERIC)
+
+ g_TaskIDs[high_task] = tid;
+ }
+
+ if (rc) {
+ LOG_WARN(LOG_TAG, "failed to change sched policy, tid %d, err: %d", tid,
+ errno);
+ }
+
+ // make A2DP threads use RT scheduling policy since they are part of the
+ // audio pipeline
+ {
+ struct sched_param rt_params;
+ rt_params.sched_priority = A2DP_RT_PRIORITY;
+
+ const int rc = sched_setscheduler(tid, SCHED_FIFO, &rt_params);
+ if (rc != 0) {
+ LOG_ERROR(LOG_TAG,
+ "%s unable to set SCHED_FIFO priority %d for tid %d, error %s",
+ __func__, A2DP_RT_PRIORITY, tid, strerror(errno));
+ }
+ }
+}
+
+/**M:Bug fix for A2DP start fail @{*/
+/*****************************************************************************
+**
+** Function raise_priority_jni
+**
+** Description Raise task priority for jni thread,this method not suggest
+** using in others condition
+** Returns void
+**
+*******************************************************************************/
+void raise_priority_jni(bool raise) {
+ int priority = 0;
+
+ if(raise){
+ priority = -19;
+ }
+
+ if (setpriority(PRIO_PROCESS, gettid(), priority) < 0) {
+ LOG_WARN(LOG_TAG, "failed to change priority tid: %d to %d", gettid(), priority);
+ }
+}
+/**@}*/ \ No newline at end of file
diff --git a/mtkbt/code/bt/vendor_libs/Android.bp b/mtkbt/code/bt/vendor_libs/Android.bp
new file mode 100755
index 0000000..07dde0f
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+ "test_vendor_lib",
+]
diff --git a/mtkbt/code/bt/vendor_libs/Android.mk b/mtkbt/code/bt/vendor_libs/Android.mk
new file mode 100755
index 0000000..31d6e6b
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/Android.mk
@@ -0,0 +1,28 @@
+# Common C/C++ compiler flags for test-vendor lib
+#
+# -Wno-gnu-variable-sized-type-not-at-end is needed, because struct BT_HDR
+# is defined as a variable-size header in a struct.
+# -Wno-typedef-redefinition is needed because of the way the struct typedef
+# is done in osi/include header files. This issue can be obsoleted by
+# switching to C11 or C++.
+# -Wno-unused-parameter is needed, because there are too many unused
+# parameters in all the code.
+#
+test-vendor_CFLAGS += \
+ -fvisibility=hidden \
+ -Wall \
+ -Wextra \
+ -Werror \
+ -Wno-gnu-variable-sized-type-not-at-end \
+ -Wno-typedef-redefinition \
+ -Wno-unused-parameter \
+ -DLOG_NDEBUG=1 \
+ -DEXPORT_SYMBOL="__attribute__((visibility(\"default\")))"
+
+test-vendor_CONLYFLAGS += -std=c99
+
+include $(call all-subdir-makefiles)
+
+# Cleanup our locals
+test-vendor_CFLAGS :=
+test-vendor_CONLYFLAGS :=
diff --git a/mtkbt/code/bt/vendor_libs/linux/Android.mk b/mtkbt/code/bt/vendor_libs/linux/Android.mk
new file mode 100755
index 0000000..30a7389
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/linux/Android.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2015 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(BOARD_HAVE_BLUETOOTH_LINUX), true)
+
+# libbt-vendor shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := \
+ bt_vendor_linux.cc
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils
+
+LOCAL_STATIC_LIBRARIES := libosi
+
+LOCAL_MODULE := libbt-vendor
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += $(test-vendor_CFLAGS)
+LOCAL_CONLYFLAGS += $(test-vendor_CONLYFLAGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # BOARD_HAVE_BLUETOOTH_LINUX
diff --git a/mtkbt/code/bt/vendor_libs/linux/bt_vendor_linux.cc b/mtkbt/code/bt/vendor_libs/linux/bt_vendor_linux.cc
new file mode 100755
index 0000000..5270eab
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/linux/bt_vendor_linux.cc
@@ -0,0 +1,411 @@
+/**********************************************************************
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ **********************************************************************/
+
+#define LOG_TAG "bt_vendor"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "hci/include/bt_vendor_lib.h"
+#include "osi/include/compat.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+#define BTPROTO_HCI 1
+#define HCI_CHANNEL_USER 1
+#define HCI_CHANNEL_CONTROL 3
+#define HCI_DEV_NONE 0xffff
+
+#define RFKILL_TYPE_BLUETOOTH 2
+#define RFKILL_OP_CHANGE_ALL 3
+
+#define MGMT_OP_INDEX_LIST 0x0003
+#define MGMT_EV_INDEX_ADDED 0x0004
+#define MGMT_EV_COMMAND_COMP 0x0001
+#define MGMT_EV_SIZE_MAX 1024
+#define MGMT_EV_POLL_TIMEOUT 3000 /* 3000ms */
+
+#define IOCTL_HCIDEVDOWN _IOW('H', 202, int)
+
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+ unsigned short hci_channel;
+};
+
+struct rfkill_event {
+ uint32_t idx;
+ uint8_t type;
+ uint8_t op;
+ uint8_t soft, hard;
+} __attribute__((packed));
+
+struct mgmt_pkt {
+ uint16_t opcode;
+ uint16_t index;
+ uint16_t len;
+ uint8_t data[MGMT_EV_SIZE_MAX];
+} __attribute__((packed));
+
+struct mgmt_event_read_index {
+ uint16_t cc_opcode;
+ uint8_t status;
+ uint16_t num_intf;
+ uint16_t index[0];
+} __attribute__((packed));
+
+static const bt_vendor_callbacks_t* bt_vendor_callbacks;
+static unsigned char bt_vendor_local_bdaddr[6];
+static int bt_vendor_fd = -1;
+static int hci_interface;
+static int rfkill_en;
+static int bt_hwcfg_en;
+
+static int bt_vendor_init(const bt_vendor_callbacks_t* p_cb,
+ unsigned char* local_bdaddr) {
+ char prop_value[PROPERTY_VALUE_MAX];
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (p_cb == NULL) {
+ LOG_ERROR(LOG_TAG, "init failed with no user callbacks!");
+ return -1;
+ }
+
+ bt_vendor_callbacks = p_cb;
+
+ memcpy(bt_vendor_local_bdaddr, local_bdaddr, sizeof(bt_vendor_local_bdaddr));
+
+ osi_property_get("bluetooth.interface", prop_value, "0");
+
+ errno = 0;
+ if (memcmp(prop_value, "hci", 3))
+ hci_interface = strtol(prop_value, NULL, 10);
+ else
+ hci_interface = strtol(prop_value + 3, NULL, 10);
+ if (errno) hci_interface = 0;
+
+ LOG_INFO(LOG_TAG, "Using interface hci%d", hci_interface);
+
+ osi_property_get("bluetooth.rfkill", prop_value, "0");
+
+ rfkill_en = atoi(prop_value);
+ if (rfkill_en) LOG_INFO(LOG_TAG, "RFKILL enabled");
+
+ bt_hwcfg_en =
+ osi_property_get("bluetooth.hwcfg", prop_value, NULL) > 0 ? 1 : 0;
+ if (bt_hwcfg_en) LOG_INFO(LOG_TAG, "HWCFG enabled");
+
+ return 0;
+}
+
+static int bt_vendor_hw_cfg(int stop) {
+ if (!bt_hwcfg_en) return 0;
+
+ if (stop) {
+ if (osi_property_set("bluetooth.hwcfg", "stop") < 0) {
+ LOG_ERROR(LOG_TAG, "%s cannot stop btcfg service via prop", __func__);
+ return 1;
+ }
+ } else {
+ if (osi_property_set("bluetooth.hwcfg", "start") < 0) {
+ LOG_ERROR(LOG_TAG, "%s cannot start btcfg service via prop", __func__);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int bt_vendor_wait_hcidev(void) {
+ struct sockaddr_hci addr;
+ struct pollfd fds[1];
+ struct mgmt_pkt ev;
+ int fd;
+ int ret = 0;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "Bluetooth socket error: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = HCI_DEV_NONE;
+ addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ LOG_ERROR(LOG_TAG, "HCI Channel Control: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ fds[0].fd = fd;
+ fds[0].events = POLLIN;
+
+ /* Read Controller Index List Command */
+ ev.opcode = MGMT_OP_INDEX_LIST;
+ ev.index = HCI_DEV_NONE;
+ ev.len = 0;
+
+ ssize_t wrote;
+ OSI_NO_INTR(wrote = write(fd, &ev, 6));
+ if (wrote != 6) {
+ LOG_ERROR(LOG_TAG, "Unable to write mgmt command: %s", strerror(errno));
+ ret = -1;
+ goto end;
+ }
+
+ while (1) {
+ int n;
+ OSI_NO_INTR(n = poll(fds, 1, MGMT_EV_POLL_TIMEOUT));
+ if (n == -1) {
+ LOG_ERROR(LOG_TAG, "Poll error: %s", strerror(errno));
+ ret = -1;
+ break;
+ } else if (n == 0) {
+ LOG_ERROR(LOG_TAG, "Timeout, no HCI device detected");
+ ret = -1;
+ break;
+ }
+
+ if (fds[0].revents & POLLIN) {
+ OSI_NO_INTR(n = read(fd, &ev, sizeof(struct mgmt_pkt)));
+ if (n < 0) {
+ LOG_ERROR(LOG_TAG, "Error reading control channel: %s",
+ strerror(errno));
+ ret = -1;
+ break;
+ }
+
+ if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
+ goto end;
+ } else if (ev.opcode == MGMT_EV_COMMAND_COMP) {
+ struct mgmt_event_read_index* cc;
+ int i;
+
+ cc = (struct mgmt_event_read_index*)ev.data;
+
+ if (cc->cc_opcode != MGMT_OP_INDEX_LIST || cc->status != 0) continue;
+
+ for (i = 0; i < cc->num_intf; i++) {
+ if (cc->index[i] == hci_interface) goto end;
+ }
+ }
+ }
+ }
+
+end:
+ close(fd);
+ return ret;
+}
+
+static int bt_vendor_open(void* param) {
+ int(*fd_array)[] = (int(*)[])param;
+ int fd;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "socket create error %s", strerror(errno));
+ return -1;
+ }
+
+ (*fd_array)[CH_CMD] = fd;
+ (*fd_array)[CH_EVT] = fd;
+ (*fd_array)[CH_ACL_OUT] = fd;
+ (*fd_array)[CH_ACL_IN] = fd;
+
+ bt_vendor_fd = fd;
+
+ LOG_INFO(LOG_TAG, "%s returning %d", __func__, bt_vendor_fd);
+
+ return 1;
+}
+
+static int bt_vendor_close(void* param) {
+ (void)(param);
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (bt_vendor_fd != -1) {
+ close(bt_vendor_fd);
+ bt_vendor_fd = -1;
+ }
+
+ return 0;
+}
+
+static int bt_vendor_rfkill(int block) {
+ struct rfkill_event event;
+ int fd;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ fd = open("/dev/rfkill", O_WRONLY);
+ if (fd < 0) {
+ LOG_ERROR(LOG_TAG, "Unable to open /dev/rfkill");
+ return -1;
+ }
+
+ memset(&event, 0, sizeof(struct rfkill_event));
+ event.op = RFKILL_OP_CHANGE_ALL;
+ event.type = RFKILL_TYPE_BLUETOOTH;
+ event.hard = block;
+ event.soft = block;
+
+ ssize_t len;
+ OSI_NO_INTR(len = write(fd, &event, sizeof(event)));
+ if (len < 0) {
+ LOG_ERROR(LOG_TAG, "Failed to change rfkill state");
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+/* TODO: fw config should thread the device waiting and return immedialty */
+static void bt_vendor_fw_cfg(void) {
+ struct sockaddr_hci addr;
+ int fd = bt_vendor_fd;
+
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ if (fd == -1) {
+ LOG_ERROR(LOG_TAG, "bt_vendor_fd: %s", strerror(EBADF));
+ goto failure;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.hci_family = AF_BLUETOOTH;
+ addr.hci_dev = hci_interface;
+ addr.hci_channel = HCI_CHANNEL_USER;
+
+ if (bt_vendor_wait_hcidev()) {
+ LOG_ERROR(LOG_TAG, "HCI interface (%d) not found", hci_interface);
+ goto failure;
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ LOG_ERROR(LOG_TAG, "socket bind error %s", strerror(errno));
+ goto failure;
+ }
+
+ LOG_INFO(LOG_TAG, "HCI device ready");
+
+ bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+
+ return;
+
+failure:
+ LOG_ERROR(LOG_TAG, "Hardware Config Error");
+ bt_vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+}
+
+static int bt_vendor_op(bt_vendor_opcode_t opcode, void* param) {
+ int retval = 0;
+
+ LOG_INFO(LOG_TAG, "%s op %d", __func__, opcode);
+
+ switch (opcode) {
+ case BT_VND_OP_POWER_CTRL:
+ if (!rfkill_en || !param) break;
+
+ if (*((int*)param) == BT_VND_PWR_ON) {
+ retval = bt_vendor_rfkill(0);
+ if (!retval) retval = bt_vendor_hw_cfg(0);
+ } else {
+ retval = bt_vendor_hw_cfg(1);
+ if (!retval) retval = bt_vendor_rfkill(1);
+ }
+
+ break;
+
+ case BT_VND_OP_FW_CFG:
+ bt_vendor_fw_cfg();
+ break;
+
+ case BT_VND_OP_SCO_CFG:
+ bt_vendor_callbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_USERIAL_OPEN:
+ retval = bt_vendor_open(param);
+ break;
+
+ case BT_VND_OP_USERIAL_CLOSE:
+ retval = bt_vendor_close(param);
+ break;
+
+ case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+ *((uint32_t*)param) = 3000;
+ retval = 0;
+ break;
+
+ case BT_VND_OP_LPM_SET_MODE:
+ bt_vendor_callbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_LPM_WAKE_SET_STATE:
+ break;
+
+ case BT_VND_OP_SET_AUDIO_STATE:
+ bt_vendor_callbacks->audio_state_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_EPILOG:
+ bt_vendor_callbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+ break;
+
+ case BT_VND_OP_A2DP_OFFLOAD_START:
+ break;
+
+ case BT_VND_OP_A2DP_OFFLOAD_STOP:
+ break;
+ }
+
+ LOG_INFO(LOG_TAG, "%s op %d retval %d", __func__, opcode, retval);
+
+ return retval;
+}
+
+static void bt_vendor_cleanup(void) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+
+ bt_vendor_callbacks = NULL;
+}
+
+EXPORT_SYMBOL const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+ sizeof(bt_vendor_interface_t), bt_vendor_init, bt_vendor_op,
+ bt_vendor_cleanup,
+};
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/Android.bp b/mtkbt/code/bt/vendor_libs/test_vendor_lib/Android.bp
new file mode 100755
index 0000000..94547b0
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/Android.bp
@@ -0,0 +1,81 @@
+// simulation library for testing virtual devices
+// ========================================================
+cc_library_static {
+ name: "libbt-rootcanal",
+ proprietary: true,
+ srcs: [
+ "src/async_manager.cc",
+ "src/bt_address.cc",
+ "src/command_packet.cc",
+ "src/dual_mode_controller.cc",
+ "src/event_packet.cc",
+ "src/packet.cc",
+ "src/packet_stream.cc",
+ "src/test_channel_transport.cc",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DHAS_NO_BDROID_BUILDCFG",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ export_include_dirs: ["include"],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ shared_libs: [
+ "libbase",
+ "libchrome",
+ "liblog",
+ ],
+}
+
+// test-vendor unit tests for host
+// ========================================================
+cc_test_host {
+ name: "test-vendor_test_host",
+ srcs: [
+ "src/async_manager.cc",
+ "src/bt_address.cc",
+ "src/command_packet.cc",
+ "src/event_packet.cc",
+ "src/packet.cc",
+ "src/packet_stream.cc",
+ "test/async_manager_unittest.cc",
+ "test/bt_address_unittest.cc",
+ "test/packet_stream_unittest.cc",
+ ],
+ local_include_dirs: [
+ "include",
+ ],
+ include_dirs: [
+ "vendor/mediatek/limit_open/system/bt",
+ "vendor/mediatek/limit_open/system/bt/utils/include",
+ "vendor/mediatek/limit_open/system/bt/hci/include",
+ "vendor/mediatek/limit_open/system/bt/stack/include",
+ ],
+ shared_libs: [
+ "liblog",
+ "libchrome",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DLOG_NDEBUG=1",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
+}
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/data/controller_properties.json b/mtkbt/code/bt/vendor_libs/test_vendor_lib/data/controller_properties.json
new file mode 100755
index 0000000..32adc52
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/data/controller_properties.json
@@ -0,0 +1,13 @@
+{
+ "AclDataPacketSize": "1024",
+ "ScoDataPacketSize": "255",
+ "NumAclDataPackets": "10",
+ "NumScoDataPackets": "10",
+ "Version": "4",
+ "Revision": "0",
+ "LmpPalVersion": "0",
+ "ManufacturerName": "0",
+ "LmpPalSubversion": "0",
+ "MaximumPageNumber": "0",
+ "BdAddress": "123456"
+}
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/async_manager.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/async_manager.h
new file mode 100755
index 0000000..6ee8c0b
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/async_manager.h
@@ -0,0 +1,115 @@
+#ifndef TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+#define TEST_VENDOR_LIB_ASYNC_MANAGER_H_
+
+#include <time.h>
+#include <cstdint>
+#include <map>
+#include <set>
+#include "errno.h"
+#include "stdio.h"
+
+#include "osi/include/log.h"
+
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+
+namespace test_vendor_lib {
+
+using TaskCallback = std::function<void(void)>;
+using ReadCallback = std::function<void(int)>;
+using CriticalCallback = std::function<void(void)>;
+using AsyncTaskId = uint16_t;
+constexpr uint16_t kInvalidTaskId = 0;
+
+// Manages tasks that should be done in the future. It can watch file
+// descriptors to call a given callback when it is certain that a non-blocking
+// read is possible or can call a callback at a specific time (aproximately) and
+// (optionally) repeat the call periodically.
+// The class is thread safe in the sense that all its member functions can be
+// called simultaneously from different concurrent threads. The exception to
+// this rule is the class destructor, which is unsafe to call concurrently with
+// calls to other class member functions. This exception also has its own
+// exception: it is safe to destroy the object even if some of its callbacks may
+// call its member functions, because the destructor will make sure all callback
+// calling threads are stopped before actually destroying anything. Callbacks
+// that wait for file descriptor always run on the same thread, so there is no
+// need of additional synchronization between them. The same applies to task
+// callbacks since they also run on a thread of their own, however it is
+// possible for a read callback and a task callback to execute at the same time
+// (they are garanteed to run in different threads) so synchronization is needed
+// to access common state (other than the internal state of the AsyncManager
+// class). While not required, it is strongly recommended to use the
+// Synchronize(const CriticalCallback&) member function to execute code inside
+// critical sections. Callbacks passed to this method on the same AsyncManager
+// object from different threads are granted to *NOT* run concurrently.
+class AsyncManager {
+ public:
+ // Starts watching a file descriptor in a separate thread. The
+ // on_read_fd_ready_callback() will be asynchronously called when it is
+ // guaranteed that a call to read() on the FD will not block. No promise is
+ // made about when in the future the callback will be called, in particular,
+ // it is perfectly possible to have it called before this function returns. A
+ // return of 0 means success, an error code is returned otherwise.
+ int WatchFdForNonBlockingReads(int file_descriptor,
+ const ReadCallback& on_read_fd_ready_callback);
+
+ // If the fd was not being watched before the call will be ignored.
+ void StopWatchingFileDescriptor(int file_descriptor);
+
+ // Schedules an action to occur in the future. Even if the delay given is not
+ // positive the callback will be called asynchronously.
+ AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
+ const TaskCallback& callback);
+
+ // Schedules an action to occur periodically in the future. If the delay given
+ // is not positive the callback will be asynchronously called once for each
+ // time in the past that it should have been called and then scheduled for
+ // future times.
+ AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
+ std::chrono::milliseconds period,
+ const TaskCallback& callback);
+
+ // Cancels the/every future ocurrence of the action specified by this id. It
+ // is guaranteed that the asociated callback will not be called after this
+ // method returns (it could be called during the execution of the method).
+ // The calling thread may block until the scheduling thread acknowledges the
+ // cancelation.
+ bool CancelAsyncTask(AsyncTaskId async_task_id);
+
+ // Execs the given code in a synchronized manner. It is guaranteed that code
+ // given on (possibly)concurrent calls to this member function on the same
+ // AsyncManager object will never be executed simultaneously. It is the
+ // class's user's resposability to ensure that no calls to Synchronize are
+ // made from inside a CriticalCallback, since that would cause a lock to be
+ // acquired twice with unpredictable results. It is strongly recommended to
+ // have very simple CriticalCallbacks, preferably using lambda expressions.
+ void Synchronize(const CriticalCallback&);
+
+ AsyncManager();
+
+ ~AsyncManager();
+
+ private:
+ // Implementation of the FD watching part of AsyncManager, extracted to its
+ // own class for clarity purposes.
+ class AsyncFdWatcher;
+
+ // Implementation of the asynchronous tasks part of AsyncManager, extracted to
+ // its own class for clarity purposes.
+ class AsyncTaskManager;
+
+ AsyncManager(const AsyncManager&) = delete;
+ AsyncManager& operator=(const AsyncManager&) = delete;
+
+ // Kept as pointers because we may want to support reseting either without
+ // destroying the other one
+ std::unique_ptr<AsyncFdWatcher> fdWatcher_p_;
+ std::unique_ptr<AsyncTaskManager> taskManager_p_;
+
+ std::mutex synchronization_mutex_;
+};
+}
+#endif // TEST_VENDOR_LIB_ASYNC_MANAGER_H_
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/bt_address.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/bt_address.h
new file mode 100755
index 0000000..c37624f
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/bt_address.h
@@ -0,0 +1,87 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace test_vendor_lib {
+
+// Encapsulate handling for Bluetooth Addresses:
+// - store the address
+// - convert to/from strings and vectors of bytes
+// - check strings to see if they represent a valid address
+class BtAddress {
+ public:
+ // Conversion constants
+ static const size_t kStringLength = 17; // "XX:XX:XX:XX:XX:XX"
+ static const size_t kOctets = 6; // "X0:X1:X2:X3:X4:X5"
+
+ BtAddress() : address_(0){};
+ virtual ~BtAddress() = default;
+
+ // Returns true if |addr| has the form "XX:XX:XX:XX:XX:XX":
+ // - the length of |addr| is >= kStringLength
+ // - every third character is ':'
+ // - each remaining character is a hexadecimal digit
+ static bool IsValid(const std::string& addr);
+
+ inline bool operator==(const BtAddress& right) {
+ return address_ == right.address_;
+ }
+ inline bool operator!=(const BtAddress& right) {
+ return address_ != right.address_;
+ }
+ inline bool operator<(const BtAddress& right) {
+ return address_ < right.address_;
+ }
+ inline bool operator>(const BtAddress& right) {
+ return address_ > right.address_;
+ }
+ inline bool operator<=(const BtAddress& right) {
+ return address_ <= right.address_;
+ }
+ inline bool operator>=(const BtAddress& right) {
+ return address_ >= right.address_;
+ }
+
+ inline void operator=(const BtAddress& right) { address_ = right.address_; }
+ inline void operator|=(const BtAddress& right) { address_ |= right.address_; }
+ inline void operator&=(const BtAddress& right) { address_ &= right.address_; }
+
+ // Set the address to the address represented by |str|.
+ // returns true if |str| represents a valid address, otherwise false.
+ bool FromString(const std::string& str);
+
+ // Set the address to the address represented by |str|.
+ // returns true if octets.size() >= kOctets, otherwise false.
+ bool FromVector(const std::vector<uint8_t>& octets);
+
+ // Appends the Bluetooth address to the vector |octets|.
+ void ToVector(std::vector<uint8_t>& octets) const;
+
+ // Return a string representation of the Bluetooth address, in this format:
+ // "xx:xx:xx:xx:xx:xx", where x represents a lowercase hexadecimal digit.
+ std::string ToString() const;
+
+ private:
+ // The Bluetooth Address is stored in the lower 48 bits of a 64-bit value
+ uint64_t address_;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/command_packet.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/command_packet.h
new file mode 100755
index 0000000..3f7debb
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/command_packet.h
@@ -0,0 +1,81 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include "base/macros.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.1 (page 470). Command Packets begin with a 3
+// octet header formatted as follows:
+// - Opcode: 2 octets
+// - Opcode Group Field (OGF): Upper bits 10-15
+// - Opcode Command Field (OCF): Lower bits 0-9
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains command specific
+// parameters and has a maximum size of 255 octets. Valid command opcodes are
+// defined in stack/include/hcidefs.h. The OGF ranges from 0x00 to 0x3F, with
+// 0x3F reserved for vendor-specific debug functions. The OCF ranges from
+// 0x0000 to 0x03FF. Note that the payload size is the size in octets of the
+// command parameters and not the number of parameters. Finally, although the
+// parameters contained in the payload are command specific (including the size
+// and number of parameters), each parameter will be an integer number of octets
+// in size.
+class CommandPacket : public Packet {
+ public:
+ explicit CommandPacket(std::vector<uint8_t> header);
+ explicit CommandPacket(uint16_t opcode);
+ CommandPacket(std::vector<uint8_t> header, std::vector<uint8_t> payload);
+
+ CommandPacket(const CommandPacket&) = default;
+ CommandPacket& operator=(const CommandPacket&) = default;
+ CommandPacket(CommandPacket&&) = default;
+ CommandPacket& operator=(CommandPacket&&) = default;
+ virtual ~CommandPacket() override = default;
+
+ // Returns the command opcode as defined in stack/include/hcidefs.h.
+ // See the Bluetooth Core Specification Version 4.2, Volume 2, Part E,
+ // Section 7 for more information about each HCI commands and for a listing
+ // of their specific opcodes/OGF and OCF values.
+ uint16_t GetOpcode() const;
+
+ // Returns the 6 bit opcode group field that specifies the general category of
+ // the command. The OGF can be one of seven values:
+ // - 0x01: Link control commands
+ // - 0x02: Link policy commands
+ // - 0x03: Controller and baseband commands
+ // - 0x04: Informational parameters commands
+ // - 0x05: Status parameters commands
+ // - 0x06: Testing commands
+ // - 0x08: Low energy controller commands
+ // The upper 2 bits will be zero filled.
+ uint8_t GetOGF() const;
+
+ // Returns the 10 bit opcode command field that specifies an exact command
+ // within an opcode group field. The upper 6 bits will be zero filled.
+ uint16_t GetOCF() const;
+
+ // Size of a command packet header, which consists of a 2 octet opcode
+ static const size_t kCommandHeaderSize = 2;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
new file mode 100755
index 0000000..bf861b7
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/dual_mode_controller.h
@@ -0,0 +1,547 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "async_manager.h"
+#include "base/json/json_value_converter.h"
+#include "base/time/time.h"
+#include "bt_address.h"
+#include "command_packet.h"
+#include "event_packet.h"
+#include "test_channel_transport.h"
+
+namespace test_vendor_lib {
+
+// Emulates a dual mode BR/EDR + LE controller by maintaining the link layer
+// state machine detailed in the Bluetooth Core Specification Version 4.2,
+// Volume 6, Part B, Section 1.1 (page 30). Provides methods corresponding to
+// commands sent by the HCI. These methods will be registered as callbacks from
+// a controller instance with the HciHandler. To implement a new Bluetooth
+// command, simply add the method declaration below, with return type void and a
+// single const std::vector<uint8_t>& argument. After implementing the
+// method, simply register it with the HciHandler using the SET_HANDLER macro in
+// the controller's default constructor. Be sure to name your method after the
+// corresponding Bluetooth command in the Core Specification with the prefix
+// "Hci" to distinguish it as a controller command.
+class DualModeController {
+ public:
+ class Properties {
+ public:
+ explicit Properties(const std::string& file_name);
+
+ // Access private configuration data
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+ const std::vector<uint8_t>& GetLocalVersionInformation() const;
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+ const std::vector<uint8_t>& GetLocalSupportedCommands() const {
+ return local_supported_commands_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.3
+ uint64_t GetLocalSupportedFeatures() const {
+ return local_extended_features_[0];
+ };
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+ uint8_t GetLocalExtendedFeaturesMaximumPageNumber() const {
+ return local_extended_features_.size() - 1;
+ };
+
+ uint64_t GetLocalExtendedFeatures(uint8_t page_number) const {
+ CHECK(page_number < local_extended_features_.size());
+ return local_extended_features_[page_number];
+ };
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+ uint16_t GetAclDataPacketSize() const { return acl_data_packet_size_; }
+
+ uint8_t GetSynchronousDataPacketSize() const {
+ return sco_data_packet_size_;
+ }
+
+ uint16_t GetTotalNumAclDataPackets() const { return num_acl_data_packets_; }
+
+ uint16_t GetTotalNumSynchronousDataPackets() const {
+ return num_sco_data_packets_;
+ }
+
+ const BtAddress& GetAddress() const { return address_; }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+ const std::vector<uint8_t>& GetSupportedCodecs() const {
+ return supported_codecs_;
+ }
+
+ const std::vector<uint32_t>& GetVendorSpecificCodecs() const {
+ return vendor_specific_codecs_;
+ }
+
+ const std::string& GetLocalName() const { return local_name_; }
+
+ uint8_t GetVersion() const { return version_; }
+
+ uint16_t GetRevision() const { return revision_; }
+
+ uint8_t GetLmpPalVersion() const { return lmp_pal_version_; }
+
+ uint16_t GetLmpPalSubversion() const { return lmp_pal_subversion_; }
+
+ uint16_t GetManufacturerName() const { return manufacturer_name_; }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+ uint16_t GetLeDataPacketLength() const { return le_data_packet_length_; }
+
+ uint8_t GetTotalNumLeDataPackets() const { return num_le_data_packets_; }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+ uint64_t GetLeLocalSupportedFeatures() const {
+ return le_supported_features_;
+ }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+ uint8_t GetLeWhiteListSize() const { return le_white_list_size_; }
+
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+ uint64_t GetLeSupportedStates() const { return le_supported_states_; }
+
+ // Vendor-specific commands (see hcidefs.h)
+ const std::vector<uint8_t>& GetLeVendorCap() const {
+ return le_vendor_cap_;
+ }
+
+ static void RegisterJSONConverter(
+ base::JSONValueConverter<Properties>* converter);
+
+ private:
+ uint16_t acl_data_packet_size_;
+ uint8_t sco_data_packet_size_;
+ uint16_t num_acl_data_packets_;
+ uint16_t num_sco_data_packets_;
+ uint8_t version_;
+ uint16_t revision_;
+ uint8_t lmp_pal_version_;
+ uint16_t manufacturer_name_;
+ uint16_t lmp_pal_subversion_;
+ std::vector<uint8_t> supported_codecs_;
+ std::vector<uint32_t> vendor_specific_codecs_;
+ std::vector<uint8_t> local_supported_commands_;
+ std::string local_name_;
+ std::vector<uint64_t> local_extended_features_;
+ BtAddress address_;
+
+ uint16_t le_data_packet_length_;
+ uint8_t num_le_data_packets_;
+ uint8_t le_white_list_size_;
+ uint64_t le_supported_features_;
+ uint64_t le_supported_states_;
+ std::vector<uint8_t> le_vendor_cap_;
+ };
+
+ // Sets all of the methods to be used as callbacks in the HciHandler.
+ DualModeController();
+
+ ~DualModeController() = default;
+
+ // Preprocesses the command, primarily checking testh channel hooks. If
+ // possible, dispatches the corresponding controller method corresponding to
+ // carry out the command.
+ void HandleCommand(std::unique_ptr<CommandPacket> command_packet);
+
+ // Dispatches the test channel action corresponding to the command specified
+ // by |name|.
+ void HandleTestChannelCommand(const std::string& name,
+ const std::vector<std::string>& args);
+
+ // Set the callbacks for scheduling tasks.
+ void RegisterTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+ evtScheduler);
+
+ void RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds,
+ std::chrono::milliseconds, const TaskCallback&)>
+ periodicEvtScheduler);
+
+ void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
+
+ // Sets the callback to be used for sending events back to the HCI.
+ void RegisterEventChannel(
+ const std::function<void(std::unique_ptr<EventPacket>)>& send_event);
+
+ // Controller commands. For error codes, see the Bluetooth Core Specification,
+ // Version 4.2, Volume 2, Part D (page 370).
+
+ // OGF: 0x0003
+ // OCF: 0x0003
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.2
+ void HciReset(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OGF: 0x0005
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.5
+ void HciReadBufferSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0033
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.39
+ void HciHostBufferSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.1
+ void HciReadLocalVersionInformation(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0009
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.6
+ void HciReadBdAddr(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0002
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.2
+ void HciReadLocalSupportedCommands(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x0004
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.4
+ void HciReadLocalExtendedFeatures(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0004
+ // OCF: 0x000B
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4.8
+ void HciReadLocalSupportedCodecs(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0056
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.59
+ void HciWriteSimplePairingMode(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x006D
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.79
+ void HciWriteLeHostSupport(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.1
+ void HciSetEventMask(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0045
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.50
+ void HciWriteInquiryMode(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0047
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.52
+ void HciWritePageScanType(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0043
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.48
+ void HciWriteInquiryScanType(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0024
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.26
+ void HciWriteClassOfDevice(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0018
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.16
+ void HciWritePageTimeout(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0002
+ // OCF: 0x000F
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2.12
+ void HciWriteDefaultLinkPolicySettings(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0014
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.12
+ void HciReadLocalName(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0013
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.11
+ void HciWriteLocalName(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0052
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.56
+ void HciWriteExtendedInquiryResponse(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0026
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.28
+ void HciWriteVoiceSetting(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x003A
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.45
+ void HciWriteCurrentIacLap(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x001E
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.22
+ void HciWriteInquiryScanActivity(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x001A
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.18
+ void HciWriteScanEnable(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0005
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.3
+ void HciSetEventFilter(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0001
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.1
+ void HciInquiry(const std::vector<uint8_t>& args);
+
+ void InquiryTimeout();
+
+ // OGF: 0x0001
+ // OCF: 0x0002
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.2
+ void HciInquiryCancel(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0003
+ // OCF: 0x0012
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3.10
+ void HciDeleteStoredLinkKey(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0001
+ // OCF: 0x0019
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1.19
+ void HciRemoteNameRequest(const std::vector<uint8_t>& args);
+
+ // LE Controller Commands
+
+ // OGF: 0x0008
+ // OCF: 0x0001
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.1
+ void HciLeSetEventMask(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0002
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.2
+ void HciLeReadBufferSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0003
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.3
+ void HciLeReadLocalSupportedFeatures(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0005
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.4
+ void HciLeSetRandomAddress(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0006
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.5
+ void HciLeSetAdvertisingParameters(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0008
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.7
+ void HciLeSetAdvertisingData(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x000B
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.10
+ void HciLeSetScanParameters(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x000C
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.11
+ void HciLeSetScanEnable(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x000F
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.14
+ void HciLeReadWhiteListSize(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x0018
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.23
+ void HciLeRand(const std::vector<uint8_t>& args);
+
+ // OGF: 0x0008
+ // OCF: 0x001C
+ // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8.27
+ void HciLeReadSupportedStates(const std::vector<uint8_t>& args);
+
+ // Vendor-specific commands (see hcidefs.h)
+
+ // OGF: 0x00FC
+ // OCF: 0x0027
+ void HciBleVendorSleepMode(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x0153
+ void HciBleVendorCap(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x0154
+ void HciBleVendorMultiAdv(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x0155
+ void HciBleVendor155(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x0157
+ void HciBleVendor157(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x0159
+ void HciBleEnergyInfo(const std::vector<uint8_t>& args);
+
+ // OGF: 0x00FC
+ // OCF: 0x015A
+ void HciBleExtendedScanParams(const std::vector<uint8_t>& args);
+
+ // Test Channel commands:
+
+ // Clears all test channel modifications.
+ void TestChannelClear(const std::vector<std::string>& args);
+
+ // Sets the response delay for events to 0.
+ void TestChannelClearEventDelay(const std::vector<std::string>& args);
+
+ // Discovers a fake device.
+ void TestChannelDiscover(const std::vector<std::string>& args);
+
+ // Causes events to be sent after a delay.
+ void TestChannelSetEventDelay(const std::vector<std::string>& args);
+
+ // Causes all future HCI commands to timeout.
+ void TestChannelTimeoutAll(const std::vector<std::string>& args);
+
+ void HandleTimerTick();
+ void SetTimerPeriod(std::chrono::milliseconds new_period);
+ void StartTimer();
+ void StopTimer();
+
+ private:
+ // Current link layer state of the controller.
+ enum State {
+ kStandby, // Not receiving/transmitting any packets from/to other devices.
+ kInquiry, // The controller is discovering other nearby devices.
+ };
+
+ enum TestChannelState {
+ kNone, // The controller is running normally.
+ kTimeoutAll, // All commands should time out, i.e. send no response.
+ kDelayedResponse, // Event responses are sent after a delay.
+ };
+
+ // Set a timer for a future action
+ void AddControllerEvent(std::chrono::milliseconds,
+ const TaskCallback& callback);
+
+ // Creates a command complete event and sends it back to the HCI.
+ void SendCommandComplete(uint16_t command_opcode,
+ const std::vector<uint8_t>& return_parameters) const;
+
+ // Sends a command complete event with no return parameters. This event is
+ // typically sent for commands that can be completed immediately.
+ void SendCommandCompleteSuccess(uint16_t command_opcode) const;
+
+ // Sends a command complete event with no return parameters. This event is
+ // typically sent for commands that can be completed immediately.
+ void SendCommandCompleteOnlyStatus(uint16_t command_opcode,
+ uint8_t status) const;
+
+ // Creates a command status event and sends it back to the HCI.
+ void SendCommandStatus(uint8_t status, uint16_t command_opcode) const;
+
+ // Sends a command status event with default event parameters.
+ void SendCommandStatusSuccess(uint16_t command_opcode) const;
+
+ void SetEventDelay(int64_t delay);
+
+ // Callbacks to schedule tasks.
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+ schedule_task_;
+ std::function<AsyncTaskId(std::chrono::milliseconds,
+ std::chrono::milliseconds, const TaskCallback&)>
+ schedule_periodic_task_;
+
+ std::function<void(AsyncTaskId)> cancel_task_;
+
+ // Callback provided to send events from the controller back to the HCI.
+ std::function<void(std::unique_ptr<EventPacket>)> send_event_;
+
+ // Maintains the commands to be registered and used in the HciHandler object.
+ // Keys are command opcodes and values are the callbacks to handle each
+ // command.
+ std::unordered_map<uint16_t, std::function<void(const std::vector<uint8_t>&)>>
+ active_hci_commands_;
+
+ std::unordered_map<std::string,
+ std::function<void(const std::vector<std::string>&)>>
+ active_test_channel_commands_;
+
+ // Specifies the format of Inquiry Result events to be returned during the
+ // Inquiry command.
+ // 0x00: Standard Inquiry Result event format (default).
+ // 0x01: Inquiry Result format with RSSI.
+ // 0x02 Inquiry Result with RSSI format or Extended Inquiry Result format.
+ // 0x03-0xFF: Reserved.
+ uint8_t inquiry_mode_;
+
+ std::vector<uint8_t> le_event_mask_;
+
+ BtAddress le_random_address_;
+
+ uint8_t le_scan_type_;
+ uint16_t le_scan_interval_;
+ uint16_t le_scan_window_;
+ uint8_t own_address_type_;
+ uint8_t scanning_filter_policy_;
+
+ uint8_t le_scan_enable_;
+ uint8_t filter_duplicates_;
+
+ State state_;
+
+ Properties properties_;
+
+ TestChannelState test_channel_state_;
+
+ std::vector<AsyncTaskId> controller_events_;
+ AsyncTaskId timer_tick_task_;
+ std::chrono::milliseconds timer_period_ = std::chrono::milliseconds(1000);
+
+ DualModeController(const DualModeController& cmdPckt) = delete;
+ DualModeController& operator=(const DualModeController& cmdPckt) = delete;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/event_packet.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/event_packet.h
new file mode 100755
index 0000000..d7c8268
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/event_packet.h
@@ -0,0 +1,158 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "bt_address.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// Event Packets are specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.4
+class EventPacket : public Packet {
+ public:
+ virtual ~EventPacket() override = default;
+
+ uint8_t GetEventCode() const;
+
+ // Static functions for creating event packets:
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+ static std::unique_ptr<EventPacket> CreateInquiryCompleteEvent(
+ uint8_t status);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
+ // This should only be used for testing to send non-standard packets
+ // Most code should use the more specific functions that follow
+ static std::unique_ptr<EventPacket> CreateCommandCompleteEvent(
+ uint16_t command_opcode,
+ const std::vector<uint8_t>& event_return_parameters);
+
+ static std::unique_ptr<EventPacket> CreateCommandCompleteOnlyStatusEvent(
+ uint16_t command_opcode, uint8_t status);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+ static std::unique_ptr<EventPacket> CreateCommandStatusEvent(
+ uint8_t status, uint16_t command_opcode);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+ static std::unique_ptr<EventPacket> CreateCommandCompleteReadLocalName(
+ uint8_t status, const std::string& local_name);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteReadLocalVersionInformation(uint8_t status,
+ uint8_t hci_version,
+ uint16_t hci_revision,
+ uint8_t lmp_pal_version,
+ uint16_t manufacturer_name,
+ uint16_t lmp_pal_subversion);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteReadLocalSupportedCommands(
+ uint8_t status, const std::vector<uint8_t>& supported_commands);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteReadLocalExtendedFeatures(
+ uint8_t status, uint8_t page_number, uint8_t maximum_page_number,
+ uint64_t extended_lmp_features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+ static std::unique_ptr<EventPacket> CreateCommandCompleteReadBufferSize(
+ uint8_t status, uint16_t hc_acl_data_packet_length,
+ uint8_t hc_synchronous_data_packet_length,
+ uint16_t hc_total_num_acl_data_packets,
+ uint16_t hc_total_synchronous_data_packets);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
+ static std::unique_ptr<EventPacket> CreateCommandCompleteReadBdAddr(
+ uint8_t status, const BtAddress& bt_address);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteReadLocalSupportedCodecs(
+ uint8_t status, const std::vector<uint8_t>& supported_codecs,
+ const std::vector<uint32_t>& vendor_specific_codecs);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
+ enum PageScanRepetitionMode {
+ kR0 = 0,
+ kR1 = 1,
+ kR2 = 2,
+ };
+
+ static std::unique_ptr<EventPacket> CreateInquiryResultEvent(
+ const BtAddress& bt_address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset);
+
+ void AddInquiryResult(const BtAddress& bt_address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
+ static std::unique_ptr<EventPacket> CreateExtendedInquiryResultEvent(
+ const BtAddress& bt_address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
+ const std::vector<uint8_t>& extended_inquiry_response);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+ static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadBufferSize(
+ uint8_t status, uint16_t hc_le_data_packet_length,
+ uint8_t hc_total_num_le_data_packets);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteLeReadLocalSupportedFeatures(uint8_t status,
+ uint64_t le_features);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+ static std::unique_ptr<EventPacket> CreateCommandCompleteLeReadWhiteListSize(
+ uint8_t status, uint8_t white_list_size);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
+ static std::unique_ptr<EventPacket> CreateCommandCompleteLeRand(
+ uint8_t status, uint64_t random_val);
+
+ // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+ static std::unique_ptr<EventPacket>
+ CreateCommandCompleteLeReadSupportedStates(uint8_t status,
+ uint64_t le_states);
+
+ // Vendor-specific commands (see hcidefs.h)
+
+ static std::unique_ptr<EventPacket> CreateCommandCompleteLeVendorCap(
+ uint8_t status, const std::vector<uint8_t>& vendor_cap);
+
+ // Size of a data packet header, which consists of a 1 octet event code
+ static const size_t kEventHeaderSize = 1;
+
+ private:
+ explicit EventPacket(uint8_t event_code);
+ EventPacket(uint8_t event_code, const std::vector<uint8_t>& payload);
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet.h
new file mode 100755
index 0000000..0feeb58
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet.h
@@ -0,0 +1,95 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include "bt_address.h"
+#include "hci/include/hci_hal.h"
+
+namespace test_vendor_lib {
+
+const size_t kReservedZero = 0;
+
+// Abstract base class that is subclassed to provide type-specifc accessors on
+// data. Manages said data's memory and guarantees the data's persistence for IO
+// operations.
+class Packet {
+ public:
+ virtual ~Packet() = default;
+
+ // Returns the size in octets of the entire packet, which consists of the type
+ // octet, the header, and the payload.
+ size_t GetPacketSize() const;
+
+ const std::vector<uint8_t>& GetPayload() const;
+
+ size_t GetPayloadSize() const;
+
+ const std::vector<uint8_t>& GetHeader() const;
+
+ uint8_t GetHeaderSize() const;
+
+ serial_data_type_t GetType() const;
+
+ // Add |octets| bytes to the payload. Return true if:
+ // - the size of |bytes| is equal to |octets| and
+ // - the new size of the payload is still < |kMaxPacketOctets|
+ bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
+
+ private:
+ // Add |octets| bytes to the payload. Return true if:
+ // - the value of |value| fits in |octets| bytes and
+ // - the new size of the payload is still < |kMaxPacketOctets|
+ bool AddPayloadOctets(size_t octets, uint64_t value);
+
+ public:
+ // Add type-checking versions
+ bool AddPayloadOctets1(uint8_t value) { return AddPayloadOctets(1, value); }
+ bool AddPayloadOctets2(uint16_t value) { return AddPayloadOctets(2, value); }
+ bool AddPayloadOctets3(uint32_t value) { return AddPayloadOctets(3, value); }
+ bool AddPayloadOctets4(uint32_t value) { return AddPayloadOctets(4, value); }
+ bool AddPayloadOctets6(uint64_t value) { return AddPayloadOctets(6, value); }
+ bool AddPayloadOctets8(uint64_t value) { return AddPayloadOctets(8, value); }
+
+ // Add |address| to the payload. Return true if:
+ // - the new size of the payload is still < |kMaxPacketOctets|
+ bool AddPayloadBtAddress(const BtAddress& address);
+
+ protected:
+ // Constructs an empty packet of type |type| and header |header|
+ Packet(serial_data_type_t type, std::vector<uint8_t> header);
+
+ bool IncrementPayloadCounter(size_t index);
+ bool IncrementPayloadCounter(size_t index, uint8_t max_val);
+
+ private:
+ const size_t kMaxPacketOctets = 256; // Includes the Octet count
+
+ // Underlying containers for storing the actual packet
+
+ // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
+ // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
+ serial_data_type_t type_;
+
+ std::vector<uint8_t> header_;
+
+ std::vector<uint8_t> payload_;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet_stream.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet_stream.h
new file mode 100755
index 0000000..e2cec7d
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/packet_stream.h
@@ -0,0 +1,66 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "command_packet.h"
+#include "event_packet.h"
+#include "packet.h"
+
+namespace test_vendor_lib {
+
+// Provides abstractions for IO with Packet objects. Used to receive commands
+// and data from the HCI and to send controller events back to the host.
+class PacketStream {
+ public:
+ PacketStream() = default;
+
+ virtual ~PacketStream() = default;
+
+ // Reads a command packet from the file descriptor at |fd| and returns the
+ // packet back to the caller, along with the responsibility of managing the
+ // packet.
+ std::unique_ptr<CommandPacket> ReceiveCommand(int fd) const;
+
+ // Reads a single octet from |fd| and interprets it as a packet type octet.
+ // Validates the type octet for correctness.
+ serial_data_type_t ReceivePacketType(int fd) const;
+
+ // Sends an event to file descriptor |fd|. The ownership of the event is left
+ // with the caller.
+ bool SendEvent(std::unique_ptr<EventPacket> event, int fd) const;
+
+ private:
+ // Checks if |type| is in the valid range from DATA_TYPE_COMMAND to
+ // DATA_TYPE_SCO.
+ bool ValidateTypeOctet(serial_data_type_t type) const;
+
+ // Attempts to receive |num_octets_to_receive| into |destination| from |fd|,
+ // returning false if an error occurs.
+ bool ReceiveAll(std::vector<uint8_t>& destination,
+ size_t num_octets_to_receive, int fd) const;
+
+ // Attempts to send |num_octets_to_send| from |source| to |fd|, returning
+ // false if an error occurs.
+ bool SendAll(const std::vector<uint8_t>& source, size_t num_octets_to_send,
+ int fd) const;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h
new file mode 100755
index 0000000..b38a8ce
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/include/test_channel_transport.h
@@ -0,0 +1,65 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+
+namespace test_vendor_lib {
+
+// Manages communications between test channel and the controller. Mirrors the
+// HciTransport for the test channel.
+class TestChannelTransport {
+ public:
+ TestChannelTransport() {}
+
+ ~TestChannelTransport() {}
+
+ // Opens a port and returns the file descriptor for the socket.
+ // Returns -1 on an error.
+ int SetUp(int port);
+
+ // Closes the port (if succesfully opened in SetUp).
+ void CleanUp();
+
+ // Waits for a connection request from the test channel program and
+ // returns the file descriptor to watch for run-time parameters.
+ // Returns -1 on an error.
+ int Accept(int listen_fd);
+
+ // Sets the callback that fires when data is read in WatchFd().
+ void RegisterCommandHandler(
+ const std::function<void(const std::string&,
+ const std::vector<std::string>&)>& callback);
+
+ void OnCommandReady(int fd, std::function<void(void)> unwatch);
+
+ private:
+ std::function<void(const std::string&, const std::vector<std::string>&)>
+ command_handler_;
+
+ int listen_fd_ = -1;
+
+ TestChannelTransport(const TestChannelTransport& cmdPckt) = delete;
+ TestChannelTransport& operator=(const TestChannelTransport& cmdPckt) = delete;
+};
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh b/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
new file mode 100755
index 0000000..34e0cfe
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/build_and_run.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Builds and pushes the test vendor library to a connected device and starts
+# logcat with project-specific tag filters. If the --test-channel flag is set,
+# logcat is started in a separate process and the test channel is run in the
+# current shell. The kTestChannelEnabled flag must be set in the vendor manager
+# if the test channel is to be used. Also ensure that 'lunch' has been run for
+# the appropriate device.
+
+if [[ "$#" -ne 2 && "$#" -ne 4 ]]; then
+ echo "Usage:"
+ echo "./build_and_run.sh [/path/to/aosp] [device_name] or"
+ echo "./build_and_run.sh [/path/to/aosp] [device_name] --test-channel [port]"
+ exit 1
+fi
+
+# Exit the script if any command fails.
+set -e
+
+# The home directory for AOSP.
+AOSP_ABS=$1
+# The name of the device to build for.
+DEVICE=$2
+
+# The location of Bluetooth within AOSP.
+BT_REL=/system/bt
+BT_ABS=${AOSP_ABS}${BT_REL}
+
+# The location of the test vendor library.
+TEST_VENDOR_LIB_REL=/vendor_libs/test_vendor_lib
+TEST_VENDOR_LIB_ABS=${BT_ABS}${TEST_VENDOR_LIB_REL}
+
+DEVICE_TARGET_REL=/out/target/product
+DEVICE_TARGET_ABS=${AOSP_ABS}${DEVICE_TARGET_REL}
+
+VENDOR_SYMBOLS_REL=/symbols/system/vendor/lib
+VENDOR_SYMBOLS_ABS=${DEVICE_TARGET_ABS}/${DEVICE}/${VENDOR_SYMBOLS_REL}
+
+# The name of the object built by the test vendor library.
+TEST_VENDOR_LIB=test-vendor.so
+# The name of the regular vendor object to be replaced by $TEST_VENDOR_LIB.
+VENDOR_LIB=libbt-vendor.so
+# The config file specifying controller properties.
+CONTROLLER_PROPERTIES=controller_properties.json
+
+if [[ "$#" -eq 4 && $3 == "--test-channel" ]]; then
+ TEST_CHANNEL_PORT=$4
+ TEST_CHANNEL_REL=/scripts
+ TEST_CHANNEL_ABS=${TEST_VENDOR_LIB_ABS}${TEST_CHANNEL_REL}
+
+ # Start logcat in a subshell.
+ x-terminal-emulator -e "scripts/build_and_run.sh ${AOSP_ABS} ${DEVICE}"
+
+ echo "Setting up build environment."
+ cd ${AOSP_ABS}
+ source build/envsetup.sh
+
+ # Forward local port to the same port on the device.
+ echo "Forwarding port ${TEST_CHANNEL_PORT} to device."
+ adb forward tcp:${TEST_CHANNEL_PORT} tcp:${TEST_CHANNEL_PORT}
+
+ # Turn Bluetooth on. Requires user approval via a dialog on the device.
+ echo "Enabling Bluetooth. Please see dialog on device."
+ adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE
+
+ # Start the test channel once Bluetooth is on and logcat has started.
+ read -p "Press [ENTER] once Bluetooth is enabling AND logcat has started."
+
+ # Start the test channel.
+ python ${TEST_CHANNEL_ABS}/test_channel.py localhost ${TEST_CHANNEL_PORT}
+else
+ echo "Setting up build environment."
+ cd ${AOSP_ABS}
+ source build/envsetup.sh
+
+ echo "Navigating to test vendor library: ${TEST_VENDOR_LIB_ABS}"
+ cd ${TEST_VENDOR_LIB_ABS}
+
+ echo "Building test vendor library."
+ mm
+
+ echo "Remounting device rootfs."
+ adb shell mount -o remount,rw /
+ adb remount
+
+ # Replace the actual vendor library with the test vendor library.
+ mv ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/${TEST_VENDOR_LIB} \
+ ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB}
+
+ # Push the test vendor library to the device.
+ echo "Pushing the test vendor library to device: $DEVICE"
+ adb push ${VENDOR_SYMBOLS_ABS}/${VENDOR_LIB} /vendor/lib
+
+ echo "Pushing controller properties."
+ adb push ${TEST_VENDOR_LIB_ABS}/data/${CONTROLLER_PROPERTIES} /etc/bluetooth/
+
+ echo "Pushing libevent."
+ adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libevent.so /system/lib/
+
+ echo "Pushing libchrome."
+ adb push ${DEVICE_TARGET_ABS}/${DEVICE}/system/lib/libchrome.so /system/lib/
+
+ # Clear logcat.
+ adb logcat -c
+
+ # Run logcat with filters.
+ adb logcat bt_btif:D bt_btif_core:D bt_hci:D bt_main:D bt_vendor:D \
+ bte_logmsg:D command_packet:D dual_mode_controller:D event_packet:D \
+ hci_transport:D hci_handler:D packet:D packet_stream:D \
+ test_channel_transport:D vendor_manager:D *:S
+fi
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py b/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py
new file mode 100755
index 0000000..cf470f9
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -0,0 +1,247 @@
+#
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Script for sending testing parameters and commands to a Bluetooth device.
+
+This script provides a simple shell interface for sending data at run-time to a
+Bluetooth device. It is intended to be used in tandem with the test vendor
+library project.
+
+Usage:
+ Option A: Script
+ 1. Run build_and_run.sh in scripts/ with the --test-channel flag set and the
+ port to use for the test channel.
+ Option B: Manual
+ 1. Choose a port to use for the test channel. Use 'adb forward tcp:<port>
+ tcp:<port>' to forward the port to the device.
+ 2. In a separate shell, build and push the test vendor library to the device
+ using the script mentioned in option A (i.e. without the --test-channel flag
+ set).
+ 3. Once logcat has started, turn Bluetooth on from the device.
+ 4. Run this program, in the shell from step 1, the port, also from step 1,
+ as arguments.
+"""
+
+#!/usr/bin/env python
+
+import cmd
+import random
+import socket
+import string
+import struct
+import sys
+
+DEVICE_NAME_LENGTH = 6
+DEVICE_ADDRESS_LENGTH = 6
+
+# Used to generate fake device names and addresses during discovery.
+def generate_random_name():
+ return ''.join(random.SystemRandom().choice(string.ascii_uppercase + \
+ string.digits) for _ in range(DEVICE_NAME_LENGTH))
+
+def generate_random_address():
+ return ''.join(random.SystemRandom().choice(string.digits) for _ in \
+ range(DEVICE_ADDRESS_LENGTH))
+
+class Connection(object):
+ """Simple wrapper class for a socket object.
+
+ Attributes:
+ socket: The underlying socket created for the specified address and port.
+ """
+
+ def __init__(self, port):
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self._socket.connect(('localhost', port))
+
+ def close(self):
+ self._socket.close()
+
+ def send(self, data):
+ self._socket.sendall(data)
+
+class TestChannel(object):
+ """Checks outgoing commands and sends them once verified.
+
+ Attributes:
+ connection: The connection to the test vendor library that commands are sent
+ on.
+ """
+
+ def __init__(self, port):
+ self._connection = Connection(port)
+ self._discovered_devices = DeviceManager()
+
+ def discover_new_device(self, name=None, address=None):
+ device = Device(name, address)
+ self._discovered_devices.add_device(device)
+ return device
+
+ def close(self):
+ self._connection.close()
+
+ def send_command(self, name, args):
+ name_size = len(name)
+ args_size = len(args)
+ self.lint_command(name, args, name_size, args_size)
+ encoded_name = chr(name_size) + name
+ encoded_args = chr(args_size) + ''.join(chr(len(arg)) + arg for arg in args)
+ command = encoded_name + encoded_args
+ self._connection.send(command)
+
+ def lint_command(self, name, args, name_size, args_size):
+ assert name_size == len(name) and args_size == len(args)
+ try:
+ name.encode('utf-8')
+ for arg in args:
+ arg.encode('utf-8')
+ except UnicodeError:
+ print 'Unrecognized characters.'
+ raise
+ if name_size > 255 or args_size > 255:
+ raise ValueError # Size must be encodable in one octet.
+ for arg in args:
+ if len(arg) > 255:
+ raise ValueError # Size must be encodable in one octet.
+
+class DeviceManager(object):
+ """Maintains the active fake devices that have been "discovered".
+
+ Attributes:
+ device_list: Maps device addresses (keys) to devices (values).
+ """
+
+ def __init__(self):
+ self.device_list = {}
+
+ def add_device(self, device):
+ self.device_list[device.get_address()] = device
+
+class Device(object):
+ """A fake device to be returned in inquiry and scan results. Note that if an
+ explicit name or address is not provided, a random string of characters
+ is used.
+
+ Attributes:
+ name: The device name for use in extended results.
+ address: The BD address of the device.
+ """
+
+ def __init__(self, name=None, address=None):
+ # TODO(dennischeng): Generate device properties more robustly.
+ self._name = generate_random_name() if name is None else name
+ self._address = generate_random_address() if address is None else address
+
+ def get_name(self):
+ return self._name
+
+ def get_address(self):
+ return self._address
+
+class TestChannelShell(cmd.Cmd):
+ """Shell for sending test channel data to controller.
+
+ Manages the test channel to the controller and defines a set of commands the
+ user can send to the controller as well. These commands are processed parallel
+ to commands sent from the device stack and used to provide additional
+ debugging/testing capabilities.
+
+ Attributes:
+ test_channel: The communication channel to send data to the controller.
+ """
+
+ def __init__(self, test_channel):
+ print 'Type \'help\' for more information.'
+ cmd.Cmd.__init__(self)
+ self._test_channel = test_channel
+
+ def do_clear(self, args):
+ """
+ Arguments: None.
+ Resets the controller to its original, unmodified state.
+ """
+ self._test_channel.send_command('CLEAR', [])
+
+ def do_clear_event_delay(self, args):
+ """
+ Arguments: None.
+ Clears the response delay set by set_event_delay.
+ """
+ self._test_channel.send_command('CLEAR_EVENT_DELAY', args.split())
+
+ def do_discover(self, args):
+ """
+ Arguments: name_1 name_2 ...
+ Sends an inquiry result for named device(s). If no names are provided, a
+ random name is used instead.
+ """
+ if len(args) == 0:
+ args = generate_random_name()
+ device_list = [self._test_channel.discover_new_device(arg) for arg in \
+ args.split()]
+ device_names_and_addresses = []
+ for device in device_list:
+ device_names_and_addresses.append(device.get_name())
+ device_names_and_addresses.append(device.get_address())
+ self._test_channel.send_command('DISCOVER', device_names_and_addresses)
+
+ def do_set_event_delay(self, args):
+ """
+ Arguments: interval_in_ms
+ Sets the response delay for all event packets sent from the controller back
+ to the HCI.
+ """
+ self._test_channel.send_command('SET_EVENT_DELAY', args.split())
+
+ def do_timeout_all(self, args):
+ """
+ Arguments: None.
+ Causes all HCI commands to timeout.
+ """
+ self._test_channel.send_command('TIMEOUT_ALL', [])
+
+ def do_quit(self, args):
+ """
+ Arguments: None.
+ Exits the test channel.
+ """
+ self._test_channel.send_command('CLOSE_TEST_CHANNEL', [])
+ self._test_channel.close()
+ print 'Goodbye.'
+ return True
+
+def main(argv):
+ if len(argv) != 2:
+ print 'Usage: python test_channel.py [port]'
+ return
+ try:
+ port = int(argv[1])
+ except ValueError:
+ print 'Error parsing port.'
+ else:
+ try:
+ test_channel = TestChannel(port)
+ except socket.error, e:
+ print 'Error connecting to socket: %s' % e
+ except:
+ print 'Error creating test channel (check argument).'
+ else:
+ test_channel_shell = TestChannelShell(test_channel)
+ test_channel_shell.prompt = '$ '
+ test_channel_shell.cmdloop()
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/async_manager.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/async_manager.cc
new file mode 100755
index 0000000..423fc72
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/async_manager.cc
@@ -0,0 +1,518 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "async_manager"
+
+#include "async_manager.h"
+
+#include <algorithm>
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <vector>
+#include "fcntl.h"
+#include "sys/select.h"
+#include "unistd.h"
+
+namespace test_vendor_lib {
+// Implementation of AsyncManager is divided between two classes, three if
+// AsyncManager itself is taken into account, but its only responsability
+// besides being a proxy for the other two classes is to provide a global
+// synchronization mechanism for callbacks and client code to use.
+
+// The watching of file descriptors is done through AsyncFdWatcher. Several
+// objects of this class may coexist simultaneosly as they share no state.
+// After construction of this objects nothing happens beyond some very simple
+// member initialization. When the first FD is set up for watching the object
+// starts a new thread which watches the given (and later provided) FDs using
+// select() inside a loop. A special FD (a pipe) is also watched which is
+// used to notify the thread of internal changes on the object state (like
+// the addition of new FDs to watch on). Every access to internal state is
+// synchronized using a single internal mutex. The thread is only stopped on
+// destruction of the object, by modifying a flag, which is the only member
+// variable accessed without acquiring the lock (because the notification to
+// the thread is done later by writing to a pipe which means the thread will
+// be notified regardless of what phase of the loop it is in that moment)
+
+// The scheduling of asynchronous tasks, periodic or not, is handled by the
+// AsyncTaskManager class. Like the one for FDs, this class shares no internal
+// state between different instances so it is safe to use several objects of
+// this class, also nothing interesting happens upon construction, but only
+// after a Task has been scheduled and access to internal state is synchronized
+// using a single internal mutex. When the first task is scheduled a thread
+// is started which monitors a queue of tasks. The queue is peeked to see
+// when the next task should be carried out and then the thread performs a
+// (absolute) timed wait on a condition variable. The wait ends because of a
+// time out or a notify on the cond var, the former means a task is due
+// for execution while the later means there has been a change in internal
+// state, like a task has been scheduled/canceled or the flag to stop has
+// been set. Setting and querying the stop flag or modifying the task queue
+// and subsequent notification on the cond var is done atomically (e.g while
+// holding the lock on the internal mutex) to ensure that the thread never
+// misses the notification, since notifying a cond var is not persistent as
+// writing on a pipe (if not done this way, the thread could query the
+// stopping flag and be put aside by the OS scheduler right after, then the
+// 'stop thread' procedure could run, setting the flag, notifying a cond
+// var that no one is waiting on and joining the thread, the thread then
+// resumes execution believing that it needs to continue and waits on the
+// cond var possibly forever if there are no tasks scheduled, efectively
+// causing a deadlock).
+
+// This number also states the maximum number of scheduled tasks we can handle
+// at a given time
+static const uint16_t kMaxTaskId =
+ -1; /* 2^16 - 1, permisible ids are {1..2^16-1}*/
+static inline AsyncTaskId NextAsyncTaskId(const AsyncTaskId id) {
+ return (id == kMaxTaskId) ? 1 : id + 1;
+}
+// The buffer is only 10 bytes because the expected number of bytes
+// written on this socket is 1. It is possible that the thread is notified
+// more than once but highly unlikely, so a buffer of size 10 seems enough
+// and the reads are performed inside a while just in case it isn't. From
+// the thread routine's point of view it is the same to have been notified
+// just once or 100 times so it just tries to consume the entire buffer.
+// In the cases where an interrupt would cause read to return without
+// having read everything that was available a new iteration of the thread
+// loop will bring execution to this point almost immediately, so there is
+// no need to treat that case.
+static const int kNotificationBufferSize = 10;
+
+// Async File Descriptor Watcher Implementation:
+class AsyncManager::AsyncFdWatcher {
+ public:
+ int WatchFdForNonBlockingReads(
+ int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+ // add file descriptor and callback
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_[file_descriptor] = on_read_fd_ready_callback;
+ }
+
+ // start the thread if not started yet
+ int started = tryStartThread();
+ if (started != 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ return started;
+ }
+
+ // notify the thread so that it knows of the new FD
+ notifyThread();
+
+ return 0;
+ }
+
+ void StopWatchingFileDescriptor(int file_descriptor) {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_.erase(file_descriptor);
+ }
+
+ AsyncFdWatcher() = default;
+
+ ~AsyncFdWatcher() = default;
+
+ int stopThread() {
+ if (!std::atomic_exchange(&running_, false)) {
+ return 0; // if not running already
+ }
+
+ notifyThread();
+
+ if (std::this_thread::get_id() != thread_.get_id()) {
+ thread_.join();
+ } else {
+ LOG_WARN(LOG_TAG,
+ "%s: Starting thread stop from inside the reading thread itself",
+ __func__);
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ watched_shared_fds_.clear();
+ }
+
+ return 0;
+ }
+
+ private:
+ AsyncFdWatcher(const AsyncFdWatcher&) = delete;
+ AsyncFdWatcher& operator=(const AsyncFdWatcher&) = delete;
+
+ // Make sure to call this with at least one file descriptor ready to be
+ // watched upon or the thread routine will return immediately
+ int tryStartThread() {
+ if (std::atomic_exchange(&running_, true)) {
+ return 0; // if already running
+ }
+ // set up the communication channel
+ int pipe_fds[2];
+ if (pipe2(pipe_fds, O_NONBLOCK)) {
+ LOG_ERROR(LOG_TAG,
+ "%s:Unable to establish a communication channel to the reading "
+ "thread",
+ __func__);
+ return -1;
+ }
+ notification_listen_fd_ = pipe_fds[0];
+ notification_write_fd_ = pipe_fds[1];
+
+ thread_ = std::thread([this]() { ThreadRoutine(); });
+ if (!thread_.joinable()) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ int notifyThread() {
+ char buffer = '0';
+ if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to send message to reading thread",
+ __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ int setUpFileDescriptorSet(fd_set& read_fds) {
+ // add comm channel to the set
+ FD_SET(notification_listen_fd_, &read_fds);
+ int nfds = notification_listen_fd_;
+
+ // add watched FDs to the set
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ for (auto& fdp : watched_shared_fds_) {
+ FD_SET(fdp.first, &read_fds);
+ nfds = std::max(fdp.first, nfds);
+ }
+ }
+ return nfds;
+ }
+
+ // check the comm channel and read everything there
+ bool consumeThreadNotifications(fd_set& read_fds) {
+ if (FD_ISSET(notification_listen_fd_, &read_fds)) {
+ char buffer[kNotificationBufferSize];
+ while (TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer,
+ kNotificationBufferSize)) ==
+ kNotificationBufferSize) {
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // check all file descriptors and call callbacks if necesary
+ void runAppropriateCallbacks(fd_set& read_fds) {
+ // not a good idea to call a callback while holding the FD lock,
+ // nor to release the lock while traversing the map
+ std::vector<decltype(watched_shared_fds_)::value_type> fds;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ for (auto& fdc : watched_shared_fds_) {
+ if (FD_ISSET(fdc.first, &read_fds)) {
+ fds.push_back(fdc);
+ }
+ }
+ }
+ for (auto& p : fds) {
+ p.second(p.first);
+ }
+ }
+
+ void ThreadRoutine() {
+ while (running_) {
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ int nfds = setUpFileDescriptorSet(read_fds);
+
+ // wait until there is data available to read on some FD
+ int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL);
+ if (retval <= 0) { // there was some error or a timeout
+ LOG_ERROR(LOG_TAG,
+ "%s: There was an error while waiting for data on the file "
+ "descriptors",
+ __func__);
+ continue;
+ }
+
+ consumeThreadNotifications(read_fds);
+
+ // Do not read if there was a call to stop running
+ if (!running_) {
+ break;
+ }
+
+ runAppropriateCallbacks(read_fds);
+ }
+ }
+
+ std::atomic_bool running_{false};
+ std::thread thread_;
+ std::mutex internal_mutex_;
+
+ std::map<int, ReadCallback> watched_shared_fds_;
+
+ // A pair of FD to send information to the reading thread
+ int notification_listen_fd_;
+ int notification_write_fd_;
+};
+
+// Async task manager implementation
+class AsyncManager::AsyncTaskManager {
+ public:
+ AsyncTaskId ExecAsync(std::chrono::milliseconds delay,
+ const TaskCallback& callback) {
+ return scheduleTask(std::make_shared<Task>(
+ std::chrono::steady_clock::now() + delay, callback));
+ }
+
+ AsyncTaskId ExecAsyncPeriodically(std::chrono::milliseconds delay,
+ std::chrono::milliseconds period,
+ const TaskCallback& callback) {
+ return scheduleTask(std::make_shared<Task>(
+ std::chrono::steady_clock::now() + delay, period, callback));
+ }
+
+ bool CancelAsyncTask(AsyncTaskId async_task_id) {
+ // remove task from queue (and task id asociation) while holding lock
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ if (tasks_by_id.count(async_task_id) == 0) {
+ return false;
+ }
+ task_queue_.erase(tasks_by_id[async_task_id]);
+ tasks_by_id.erase(async_task_id);
+ return true;
+ }
+
+ AsyncTaskManager() = default;
+
+ ~AsyncTaskManager() = default;
+
+ int stopThread() {
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ tasks_by_id.clear();
+ task_queue_.clear();
+ if (!running_) {
+ return 0;
+ }
+ running_ = false;
+ // notify the thread
+ internal_cond_var_.notify_one();
+ } // release the lock before joining a thread that is likely waiting for it
+ if (std::this_thread::get_id() != thread_.get_id()) {
+ thread_.join();
+ } else {
+ LOG_WARN(LOG_TAG,
+ "%s: Starting thread stop from inside the task thread itself",
+ __func__);
+ }
+ return 0;
+ }
+
+ private:
+ // Holds the data for each task
+ class Task {
+ public:
+ Task(std::chrono::steady_clock::time_point time,
+ std::chrono::milliseconds period, const TaskCallback& callback)
+ : time(time),
+ periodic(true),
+ period(period),
+ callback(callback),
+ task_id(kInvalidTaskId) {}
+ Task(std::chrono::steady_clock::time_point time,
+ const TaskCallback& callback)
+ : time(time),
+ periodic(false),
+ callback(callback),
+ task_id(kInvalidTaskId) {}
+
+ // Operators needed to be in a collection
+ bool operator<(const Task& another) const {
+ return std::make_pair(time, task_id) <
+ std::make_pair(another.time, another.task_id);
+ }
+
+ bool isPeriodic() const { return periodic; }
+
+ // These fields should no longer be public if the class ever becomes
+ // public or gets more complex
+ std::chrono::steady_clock::time_point time;
+ bool periodic;
+ std::chrono::milliseconds period;
+ TaskCallback callback;
+ AsyncTaskId task_id;
+ };
+
+ // A comparator class to put shared pointers to tasks in an ordered set
+ struct task_p_comparator {
+ bool operator()(const std::shared_ptr<Task>& t1,
+ const std::shared_ptr<Task>& t2) const {
+ return *t1 < *t2;
+ }
+ };
+
+ AsyncTaskManager(const AsyncTaskManager&) = delete;
+ AsyncTaskManager& operator=(const AsyncTaskManager&) = delete;
+
+ AsyncTaskId scheduleTask(const std::shared_ptr<Task>& task) {
+ AsyncTaskId task_id = kInvalidTaskId;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // no more room for new tasks, we need a larger type for IDs
+ if (tasks_by_id.size() == kMaxTaskId) // TODO potentially type unsafe
+ return kInvalidTaskId;
+ do {
+ lastTaskId_ = NextAsyncTaskId(lastTaskId_);
+ } while (isTaskIdInUse(lastTaskId_));
+ task->task_id = lastTaskId_;
+ // add task to the queue and map
+ tasks_by_id[lastTaskId_] = task;
+ task_queue_.insert(task);
+ task_id = lastTaskId_;
+ }
+ // start thread if necessary
+ int started = tryStartThread();
+ if (started != 0) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ return kInvalidTaskId;
+ }
+ // notify the thread so that it knows of the new task
+ internal_cond_var_.notify_one();
+ // return task id
+ return task_id;
+ }
+
+ bool isTaskIdInUse(const AsyncTaskId& task_id) const {
+ return tasks_by_id.count(task_id) != 0;
+ }
+
+ int tryStartThread() {
+ // need the lock because of the running flag and the cond var
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // check that the thread is not yet running
+ if (running_) {
+ return 0;
+ }
+ // start the thread
+ running_ = true;
+ thread_ = std::thread([this]() { ThreadRoutine(); });
+ if (!thread_.joinable()) {
+ LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __func__);
+ return -1;
+ }
+ return 0;
+ }
+
+ void ThreadRoutine() {
+ while (1) {
+ TaskCallback callback;
+ bool run_it = false;
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ if (!task_queue_.empty()) {
+ std::shared_ptr<Task> task_p = *(task_queue_.begin());
+ if (task_p->time < std::chrono::steady_clock::now()) {
+ run_it = true;
+ callback = task_p->callback;
+ task_queue_.erase(task_p); // need to remove and add again if
+ // periodic to update order
+ if (task_p->isPeriodic()) {
+ task_p->time += task_p->period;
+ task_queue_.insert(task_p);
+ } else {
+ tasks_by_id.erase(task_p->task_id);
+ }
+ }
+ }
+ }
+ if (run_it) {
+ callback();
+ }
+ {
+ std::unique_lock<std::mutex> guard(internal_mutex_);
+ // wait on condition variable with timeout just in time for next task if
+ // any
+ if (task_queue_.size() > 0) {
+ internal_cond_var_.wait_until(guard, (*task_queue_.begin())->time);
+ } else {
+ internal_cond_var_.wait(guard);
+ }
+ // check for termination right after being notified (and maybe before?)
+ if (!running_) break;
+ }
+ }
+ }
+
+ bool running_ = false;
+ std::thread thread_;
+ std::mutex internal_mutex_;
+ std::condition_variable internal_cond_var_;
+
+ AsyncTaskId lastTaskId_ = kInvalidTaskId;
+ std::map<AsyncTaskId, std::shared_ptr<Task> > tasks_by_id;
+ std::set<std::shared_ptr<Task>, task_p_comparator> task_queue_;
+};
+
+// Async Manager Implementation:
+AsyncManager::AsyncManager()
+ : fdWatcher_p_(new AsyncFdWatcher()),
+ taskManager_p_(new AsyncTaskManager()) {}
+
+AsyncManager::~AsyncManager() {
+ // Make sure the threads are stopped before destroying the object.
+ // The threads need to be stopped here and not in each internal class'
+ // destructor because unique_ptr's reset() first assigns nullptr to the
+ // pointer and only then calls the destructor, so any callback running
+ // on these threads would dereference a null pointer if they called a member
+ // function of this class.
+ fdWatcher_p_->stopThread();
+ taskManager_p_->stopThread();
+}
+
+int AsyncManager::WatchFdForNonBlockingReads(
+ int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
+ return fdWatcher_p_->WatchFdForNonBlockingReads(file_descriptor,
+ on_read_fd_ready_callback);
+}
+
+void AsyncManager::StopWatchingFileDescriptor(int file_descriptor) {
+ fdWatcher_p_->StopWatchingFileDescriptor(file_descriptor);
+}
+
+AsyncTaskId AsyncManager::ExecAsync(std::chrono::milliseconds delay,
+ const TaskCallback& callback) {
+ return taskManager_p_->ExecAsync(delay, callback);
+}
+
+AsyncTaskId AsyncManager::ExecAsyncPeriodically(
+ std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& callback) {
+ return taskManager_p_->ExecAsyncPeriodically(delay, period, callback);
+}
+
+bool AsyncManager::CancelAsyncTask(AsyncTaskId async_task_id) {
+ return taskManager_p_->CancelAsyncTask(async_task_id);
+}
+
+void AsyncManager::Synchronize(const CriticalCallback& critical) {
+ std::unique_lock<std::mutex> guard(synchronization_mutex_);
+ critical();
+}
+}
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/bt_address.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/bt_address.cc
new file mode 100755
index 0000000..4deffb3
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/bt_address.cc
@@ -0,0 +1,84 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "bt_address.h"
+#include <iomanip>
+#include <vector>
+using std::vector;
+
+#include <base/logging.h>
+
+namespace test_vendor_lib {
+
+bool BtAddress::IsValid(const std::string& addr) {
+ if (addr.length() < kStringLength) return false;
+
+ for (size_t i = 0; i < kStringLength; i++) {
+ if (i % 3 == 2) { // Every third character must be ':'
+ if (addr[i] != ':') return false;
+ } else { // The rest must be hexadecimal digits
+ if (!isxdigit(addr[i])) return false;
+ }
+ }
+ return true;
+}
+
+bool BtAddress::FromString(const std::string& str) {
+ std::string tok;
+ std::istringstream iss(str);
+
+ if (IsValid(str) == false) return false;
+
+ address_ = 0;
+ for (size_t i = 0; i < kOctets; i++) {
+ getline(iss, tok, ':');
+ uint64_t octet = std::stoi(tok, nullptr, 16);
+ address_ |= (octet << (8 * ((kOctets - 1) - i)));
+ }
+ return true;
+}
+
+bool BtAddress::FromVector(const vector<uint8_t>& octets) {
+ if (octets.size() < kOctets) return false;
+
+ address_ = 0;
+ for (size_t i = 0; i < kOctets; i++) {
+ uint64_t to_shift = octets[i];
+ address_ |= to_shift << (8 * i);
+ }
+ return true;
+}
+
+void BtAddress::ToVector(vector<uint8_t>& octets) const {
+ for (size_t i = 0; i < kOctets; i++) {
+ octets.push_back(address_ >> (8 * i));
+ }
+}
+
+std::string BtAddress::ToString() const {
+ std::stringstream ss;
+
+ ss << std::hex << std::setfill('0') << std::setw(2);
+ for (size_t i = 0; i < kOctets; i++) {
+ uint64_t octet = (address_ >> (8 * ((kOctets - 1) - i))) & 0xff;
+ ss << std::hex << std::setfill('0') << std::setw(2) << octet;
+ if (i != kOctets - 1) ss << std::string(":");
+ }
+
+ return ss.str();
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/command_packet.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/command_packet.cc
new file mode 100755
index 0000000..79935dc
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/command_packet.cc
@@ -0,0 +1,49 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "command_packet"
+
+#include "command_packet.h"
+
+#include "hci/include/hci_hal.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+CommandPacket::CommandPacket(vector<uint8_t> header)
+ : Packet(DATA_TYPE_COMMAND, std::move(header)) {}
+
+CommandPacket::CommandPacket(uint16_t opcode)
+ : Packet(DATA_TYPE_COMMAND, {static_cast<uint8_t>(opcode),
+ static_cast<uint8_t>(opcode >> 8)}) {}
+
+CommandPacket::CommandPacket(vector<uint8_t> header, vector<uint8_t> payload)
+ : Packet(DATA_TYPE_COMMAND, std::move(header)) {
+ AddPayloadOctets(payload.size(), std::move(payload));
+}
+
+uint16_t CommandPacket::GetOpcode() const {
+ return 0 | (GetHeader()[0] | (GetHeader()[1] << 8));
+}
+
+uint8_t CommandPacket::GetOGF() const { return HCI_OGF(GetOpcode()); }
+
+uint16_t CommandPacket::GetOCF() const { return HCI_OCF(GetOpcode()); }
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
new file mode 100755
index 0000000..86f920b
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/dual_mode_controller.cc
@@ -0,0 +1,747 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "dual_mode_controller"
+
+#include "dual_mode_controller.h"
+
+#include <memory>
+
+#include <base/logging.h>
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "event_packet.h"
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace {
+
+// Included in certain events to indicate success (specific to the event
+// context).
+const uint8_t kSuccessStatus = 0;
+
+const uint8_t kUnknownHciCommand = 1;
+
+// The location of the config file loaded to populate controller attributes.
+const std::string kControllerPropertiesFile =
+ "/etc/bluetooth/controller_properties.json";
+
+// Inquiry modes for specifiying inquiry result formats.
+const uint8_t kStandardInquiry = 0x00;
+const uint8_t kRssiInquiry = 0x01;
+const uint8_t kExtendedOrRssiInquiry = 0x02;
+
+// The bd address of another (fake) device.
+const vector<uint8_t> kOtherDeviceBdAddress = {6, 5, 4, 3, 2, 1};
+
+void LogCommand(const char* command) {
+ LOG_INFO(LOG_TAG, "Controller performing command: %s", command);
+}
+
+// Functions used by JSONValueConverter to read stringified JSON into Properties
+// object.
+bool ParseUint8t(const base::StringPiece& value, uint8_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+bool ParseUint16t(const base::StringPiece& value, uint16_t* field) {
+ *field = std::stoi(value.as_string());
+ return true;
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+
+void DualModeController::AddControllerEvent(std::chrono::milliseconds delay,
+ const TaskCallback& task) {
+ controller_events_.push_back(schedule_task_(delay, task));
+}
+
+void DualModeController::SendCommandCompleteSuccess(
+ uint16_t command_opcode) const {
+ send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ command_opcode, kSuccessStatus));
+}
+
+void DualModeController::SendCommandCompleteOnlyStatus(uint16_t command_opcode,
+ uint8_t status) const {
+ send_event_(EventPacket::CreateCommandCompleteOnlyStatusEvent(command_opcode,
+ status));
+}
+
+void DualModeController::SendCommandStatus(uint8_t status,
+ uint16_t command_opcode) const {
+ send_event_(EventPacket::CreateCommandStatusEvent(status, command_opcode));
+}
+
+void DualModeController::SendCommandStatusSuccess(
+ uint16_t command_opcode) const {
+ SendCommandStatus(kSuccessStatus, command_opcode);
+}
+
+DualModeController::DualModeController()
+ : state_(kStandby),
+ properties_(kControllerPropertiesFile),
+ test_channel_state_(kNone) {
+#define SET_HANDLER(opcode, method) \
+ active_hci_commands_[opcode] = [this](const vector<uint8_t>& param) { \
+ method(param); \
+ };
+ SET_HANDLER(HCI_RESET, HciReset);
+ SET_HANDLER(HCI_READ_BUFFER_SIZE, HciReadBufferSize);
+ SET_HANDLER(HCI_HOST_BUFFER_SIZE, HciHostBufferSize);
+ SET_HANDLER(HCI_READ_LOCAL_VERSION_INFO, HciReadLocalVersionInformation);
+ SET_HANDLER(HCI_READ_BD_ADDR, HciReadBdAddr);
+ SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CMDS, HciReadLocalSupportedCommands);
+ SET_HANDLER(HCI_READ_LOCAL_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
+ SET_HANDLER(HCI_READ_LOCAL_EXT_FEATURES, HciReadLocalExtendedFeatures);
+ SET_HANDLER(HCI_WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
+ SET_HANDLER(HCI_WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+ SET_HANDLER(HCI_SET_EVENT_MASK, HciSetEventMask);
+ SET_HANDLER(HCI_WRITE_INQUIRY_MODE, HciWriteInquiryMode);
+ SET_HANDLER(HCI_WRITE_PAGESCAN_TYPE, HciWritePageScanType);
+ SET_HANDLER(HCI_WRITE_INQSCAN_TYPE, HciWriteInquiryScanType);
+ SET_HANDLER(HCI_WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
+ SET_HANDLER(HCI_WRITE_PAGE_TOUT, HciWritePageTimeout);
+ SET_HANDLER(HCI_WRITE_DEF_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+ SET_HANDLER(HCI_READ_LOCAL_NAME, HciReadLocalName);
+ SET_HANDLER(HCI_CHANGE_LOCAL_NAME, HciWriteLocalName);
+ SET_HANDLER(HCI_WRITE_EXT_INQ_RESPONSE, HciWriteExtendedInquiryResponse);
+ SET_HANDLER(HCI_WRITE_VOICE_SETTINGS, HciWriteVoiceSetting);
+ SET_HANDLER(HCI_WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
+ SET_HANDLER(HCI_WRITE_INQUIRYSCAN_CFG, HciWriteInquiryScanActivity);
+ SET_HANDLER(HCI_WRITE_SCAN_ENABLE, HciWriteScanEnable);
+ SET_HANDLER(HCI_SET_EVENT_FILTER, HciSetEventFilter);
+ SET_HANDLER(HCI_INQUIRY, HciInquiry);
+ SET_HANDLER(HCI_INQUIRY_CANCEL, HciInquiryCancel);
+ SET_HANDLER(HCI_DELETE_STORED_LINK_KEY, HciDeleteStoredLinkKey);
+ SET_HANDLER(HCI_RMT_NAME_REQUEST, HciRemoteNameRequest);
+ SET_HANDLER(HCI_BLE_SET_EVENT_MASK, HciLeSetEventMask);
+ SET_HANDLER(HCI_BLE_READ_BUFFER_SIZE, HciLeReadBufferSize);
+ SET_HANDLER(HCI_BLE_READ_LOCAL_SPT_FEAT, HciLeReadLocalSupportedFeatures);
+ SET_HANDLER(HCI_BLE_WRITE_RANDOM_ADDR, HciLeSetRandomAddress);
+ SET_HANDLER(HCI_BLE_WRITE_ADV_DATA, HciLeSetAdvertisingData);
+ SET_HANDLER(HCI_BLE_WRITE_ADV_PARAMS, HciLeSetAdvertisingParameters);
+ SET_HANDLER(HCI_BLE_WRITE_SCAN_PARAMS, HciLeSetScanParameters);
+ SET_HANDLER(HCI_BLE_WRITE_SCAN_ENABLE, HciLeSetScanEnable);
+ SET_HANDLER(HCI_BLE_READ_WHITE_LIST_SIZE, HciLeReadWhiteListSize);
+ SET_HANDLER(HCI_BLE_RAND, HciLeRand);
+ SET_HANDLER(HCI_BLE_READ_SUPPORTED_STATES, HciLeReadSupportedStates);
+ SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x27), HciBleVendorSleepMode);
+ SET_HANDLER(HCI_BLE_VENDOR_CAP_OCF, HciBleVendorCap);
+ SET_HANDLER(HCI_BLE_MULTI_ADV_OCF, HciBleVendorMultiAdv);
+ SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x155), HciBleVendor155);
+ SET_HANDLER((HCI_GRP_VENDOR_SPECIFIC | 0x157), HciBleVendor157);
+ SET_HANDLER(HCI_BLE_ENERGY_INFO_OCF, HciBleEnergyInfo);
+ SET_HANDLER(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF, HciBleExtendedScanParams);
+#undef SET_HANDLER
+
+#define SET_TEST_HANDLER(command_name, method) \
+ active_test_channel_commands_[command_name] = \
+ [this](const vector<std::string>& param) { method(param); };
+ SET_TEST_HANDLER("CLEAR", TestChannelClear);
+ SET_TEST_HANDLER("CLEAR_EVENT_DELAY", TestChannelClearEventDelay);
+ SET_TEST_HANDLER("DISCOVER", TestChannelDiscover);
+ SET_TEST_HANDLER("SET_EVENT_DELAY", TestChannelSetEventDelay);
+ SET_TEST_HANDLER("TIMEOUT_ALL", TestChannelTimeoutAll);
+#undef SET_TEST_HANDLER
+}
+
+void DualModeController::RegisterTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
+ oneshotScheduler) {
+ schedule_task_ = oneshotScheduler;
+}
+
+void DualModeController::RegisterPeriodicTaskScheduler(
+ std::function<AsyncTaskId(std::chrono::milliseconds,
+ std::chrono::milliseconds, const TaskCallback&)>
+ periodicScheduler) {
+ schedule_periodic_task_ = periodicScheduler;
+}
+
+void DualModeController::RegisterTaskCancel(
+ std::function<void(AsyncTaskId)> task_cancel) {
+ cancel_task_ = task_cancel;
+}
+
+void DualModeController::HandleTestChannelCommand(
+ const std::string& name, const vector<std::string>& args) {
+ if (active_test_channel_commands_.count(name) == 0) return;
+ active_test_channel_commands_[name](args);
+}
+
+void DualModeController::HandleCommand(
+ std::unique_ptr<CommandPacket> command_packet) {
+ uint16_t opcode = command_packet->GetOpcode();
+ LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
+ command_packet->GetOGF(), command_packet->GetOCF());
+
+ // The command hasn't been registered with the handler yet. There is nothing
+ // to do.
+ if (active_hci_commands_.count(opcode) == 0)
+ return;
+ else if (test_channel_state_ == kTimeoutAll)
+ return;
+ active_hci_commands_[opcode](command_packet->GetPayload());
+}
+
+void DualModeController::RegisterEventChannel(
+ const std::function<void(std::unique_ptr<EventPacket>)>& callback) {
+ send_event_ = callback;
+}
+
+void DualModeController::HandleTimerTick() {
+ // PageScan();
+ if (le_scan_enable_) LOG_ERROR(LOG_TAG, "LE scan");
+ // LeScan();
+}
+
+void DualModeController::SetTimerPeriod(std::chrono::milliseconds new_period) {
+ timer_period_ = new_period;
+
+ if (timer_tick_task_ == kInvalidTaskId) return;
+
+ // Restart the timer with the new period
+ StopTimer();
+ StartTimer();
+}
+
+void DualModeController::StartTimer() {
+ LOG_ERROR(LOG_TAG, "StartTimer");
+ timer_tick_task_ = schedule_periodic_task_(
+ std::chrono::milliseconds(0), timer_period_,
+ [this]() { DualModeController::HandleTimerTick(); });
+}
+
+void DualModeController::StopTimer() {
+ LOG_ERROR(LOG_TAG, "StopTimer");
+ cancel_task_(timer_tick_task_);
+ timer_tick_task_ = kInvalidTaskId;
+}
+
+void DualModeController::TestChannelClear(
+ UNUSED_ATTR const vector<std::string>& args) {
+ LogCommand("TestChannel Clear");
+ test_channel_state_ = kNone;
+}
+
+void DualModeController::TestChannelDiscover(
+ UNUSED_ATTR const vector<std::string>& args) {
+ LogCommand("TestChannel Discover");
+ /* TODO: Replace with adding devices */
+ /*
+
+ for (size_t i = 0; i < args.size() - 1; i += 2)
+ SendExtendedInquiryResult(args[i], args[i + 1]);
+ */
+}
+
+void DualModeController::TestChannelTimeoutAll(
+ UNUSED_ATTR const vector<std::string>& args) {
+ LogCommand("TestChannel Timeout All");
+ test_channel_state_ = kTimeoutAll;
+}
+
+void DualModeController::TestChannelSetEventDelay(
+ const vector<std::string>& args UNUSED_ATTR) {
+ LogCommand("TestChannel Set Event Delay");
+ test_channel_state_ = kDelayedResponse;
+}
+
+void DualModeController::TestChannelClearEventDelay(
+ UNUSED_ATTR const vector<std::string>& args) {
+ LogCommand("TestChannel Clear Event Delay");
+ test_channel_state_ = kNone;
+}
+
+void DualModeController::HciReset(UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Reset");
+ state_ = kStandby;
+ if (timer_tick_task_ != kInvalidTaskId) {
+ LOG_INFO(LOG_TAG, "The timer was already running!");
+ StopTimer();
+ }
+ LOG_INFO(LOG_TAG, "Starting timer.");
+ StartTimer();
+
+ SendCommandCompleteSuccess(HCI_RESET);
+}
+
+void DualModeController::HciReadBufferSize(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Read Buffer Size");
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadBufferSize(
+ kSuccessStatus, properties_.GetAclDataPacketSize(),
+ properties_.GetSynchronousDataPacketSize(),
+ properties_.GetTotalNumAclDataPackets(),
+ properties_.GetTotalNumSynchronousDataPackets());
+
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciHostBufferSize(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Host Buffer Size");
+ SendCommandCompleteSuccess(HCI_HOST_BUFFER_SIZE);
+}
+
+void DualModeController::HciReadLocalVersionInformation(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Read Local Version Information");
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadLocalVersionInformation(
+ kSuccessStatus, properties_.GetVersion(), properties_.GetRevision(),
+ properties_.GetLmpPalVersion(), properties_.GetManufacturerName(),
+ properties_.GetLmpPalSubversion());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadBdAddr(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadBdAddr(kSuccessStatus,
+ properties_.GetAddress());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalSupportedCommands(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Read Local Supported Commands");
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
+ kSuccessStatus, properties_.GetLocalSupportedCommands());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalSupportedCodecs(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Read Local Supported Codecs");
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
+ kSuccessStatus, properties_.GetSupportedCodecs(),
+ properties_.GetVendorSpecificCodecs());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciReadLocalExtendedFeatures(
+ const vector<uint8_t>& args) {
+ LogCommand("Read Local Extended Features");
+ CHECK(args.size() == 2);
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
+ kSuccessStatus, args[1],
+ properties_.GetLocalExtendedFeaturesMaximumPageNumber(),
+ properties_.GetLocalExtendedFeatures(args[1]));
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciWriteSimplePairingMode(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Simple Pairing Mode");
+ SendCommandCompleteSuccess(HCI_WRITE_SIMPLE_PAIRING_MODE);
+}
+
+void DualModeController::HciWriteLeHostSupport(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Le Host Support");
+ SendCommandCompleteSuccess(HCI_WRITE_LE_HOST_SUPPORT);
+}
+
+void DualModeController::HciSetEventMask(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Set Event Mask");
+ SendCommandCompleteSuccess(HCI_SET_EVENT_MASK);
+}
+
+void DualModeController::HciWriteInquiryMode(const vector<uint8_t>& args) {
+ LogCommand("Write Inquiry Mode");
+ CHECK(args.size() == 2);
+ inquiry_mode_ = args[1];
+ SendCommandCompleteSuccess(HCI_WRITE_INQUIRY_MODE);
+}
+
+void DualModeController::HciWritePageScanType(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Page Scan Type");
+ SendCommandCompleteSuccess(HCI_WRITE_PAGESCAN_TYPE);
+}
+
+void DualModeController::HciWriteInquiryScanType(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Inquiry Scan Type");
+ SendCommandCompleteSuccess(HCI_WRITE_INQSCAN_TYPE);
+}
+
+void DualModeController::HciWriteClassOfDevice(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Class Of Device");
+ SendCommandCompleteSuccess(HCI_WRITE_CLASS_OF_DEVICE);
+}
+
+void DualModeController::HciWritePageTimeout(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Page Timeout");
+ SendCommandCompleteSuccess(HCI_WRITE_PAGE_TOUT);
+}
+
+void DualModeController::HciWriteDefaultLinkPolicySettings(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Default Link Policy Settings");
+ SendCommandCompleteSuccess(HCI_WRITE_DEF_POLICY_SETTINGS);
+}
+
+void DualModeController::HciReadLocalName(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Get Local Name");
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteReadLocalName(
+ kSuccessStatus, properties_.GetLocalName());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciWriteLocalName(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Local Name");
+ SendCommandCompleteSuccess(HCI_CHANGE_LOCAL_NAME);
+}
+
+void DualModeController::HciWriteExtendedInquiryResponse(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Extended Inquiry Response");
+ SendCommandCompleteSuccess(HCI_WRITE_EXT_INQ_RESPONSE);
+}
+
+void DualModeController::HciWriteVoiceSetting(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Voice Setting");
+ SendCommandCompleteSuccess(HCI_WRITE_VOICE_SETTINGS);
+}
+
+void DualModeController::HciWriteCurrentIacLap(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Current IAC LAP");
+ SendCommandCompleteSuccess(HCI_WRITE_CURRENT_IAC_LAP);
+}
+
+void DualModeController::HciWriteInquiryScanActivity(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Inquiry Scan Activity");
+ SendCommandCompleteSuccess(HCI_WRITE_INQUIRYSCAN_CFG);
+}
+
+void DualModeController::HciWriteScanEnable(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Write Scan Enable");
+ SendCommandCompleteSuccess(HCI_WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciSetEventFilter(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Set Event Filter");
+ SendCommandCompleteSuccess(HCI_SET_EVENT_FILTER);
+}
+
+void DualModeController::HciInquiry(const vector<uint8_t>& args) {
+ // Fake inquiry response for a fake device.
+ const EventPacket::PageScanRepetitionMode kPageScanRepetitionMode =
+ EventPacket::kR0;
+ const uint32_t kClassOfDevice = 0x030201;
+ const uint16_t kClockOffset = 513;
+ BtAddress other_addr;
+ other_addr.FromVector(kOtherDeviceBdAddress);
+
+ LogCommand("Inquiry");
+ state_ = kInquiry;
+ SendCommandStatusSuccess(HCI_INQUIRY);
+ switch (inquiry_mode_) {
+ case (kStandardInquiry): {
+ std::unique_ptr<EventPacket> inquiry_result_evt =
+ EventPacket::CreateInquiryResultEvent(other_addr,
+ kPageScanRepetitionMode,
+ kClassOfDevice, kClockOffset);
+ send_event_(std::move(inquiry_result_evt));
+ /* TODO: Return responses from modeled devices */
+ } break;
+
+ case (kRssiInquiry):
+ LOG_INFO(LOG_TAG, "RSSI Inquiry Mode currently not supported.");
+ break;
+
+ case (kExtendedOrRssiInquiry): {
+ const std::string name = "Foobar";
+ vector<uint8_t> extended_inquiry_data = {
+ static_cast<uint8_t>(name.length() + 1), 0x09};
+
+ for (size_t i = 0; i < name.length(); i++)
+ extended_inquiry_data.push_back(name[i]);
+ extended_inquiry_data.push_back('\0');
+
+ uint8_t rssi = static_cast<uint8_t>(-20);
+ send_event_(EventPacket::CreateExtendedInquiryResultEvent(
+ other_addr, kPageScanRepetitionMode, kClassOfDevice, kClockOffset,
+ rssi, extended_inquiry_data));
+ /* TODO: Return responses from modeled devices */
+ } break;
+ }
+ AddControllerEvent(std::chrono::milliseconds(args[4] * 1280),
+ [this]() { DualModeController::InquiryTimeout(); });
+}
+
+void DualModeController::HciInquiryCancel(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Inquiry Cancel");
+ CHECK(state_ == kInquiry);
+ state_ = kStandby;
+ SendCommandCompleteSuccess(HCI_INQUIRY_CANCEL);
+}
+
+void DualModeController::InquiryTimeout() {
+ LOG_INFO(LOG_TAG, "InquiryTimer fired");
+ if (state_ == kInquiry) {
+ state_ = kStandby;
+ send_event_(EventPacket::CreateInquiryCompleteEvent(kSuccessStatus));
+ }
+}
+
+void DualModeController::HciDeleteStoredLinkKey(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Delete Stored Link Key");
+ /* Check the last octect in |args|. If it is 0, delete only the link key for
+ * the given BD_ADDR. If is is 1, delete all stored link keys. */
+ SendCommandCompleteOnlyStatus(HCI_INQUIRY_CANCEL, kUnknownHciCommand);
+}
+
+void DualModeController::HciRemoteNameRequest(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("Remote Name Request");
+ SendCommandStatusSuccess(HCI_RMT_NAME_REQUEST);
+}
+
+void DualModeController::HciLeSetEventMask(const vector<uint8_t>& args) {
+ LogCommand("LE SetEventMask");
+ le_event_mask_ = args;
+ SendCommandCompleteSuccess(HCI_BLE_SET_EVENT_MASK);
+}
+
+void DualModeController::HciLeReadBufferSize(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeReadBufferSize(
+ kSuccessStatus, properties_.GetLeDataPacketLength(),
+ properties_.GetTotalNumLeDataPackets());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeReadLocalSupportedFeatures(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
+ kSuccessStatus, properties_.GetLeLocalSupportedFeatures());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeSetRandomAddress(const vector<uint8_t>& args) {
+ LogCommand("LE SetRandomAddress");
+ CHECK(args.size() == 7);
+ vector<uint8_t> new_addr = {args[1], args[2], args[3],
+ args[4], args[5], args[6]};
+ CHECK(le_random_address_.FromVector(new_addr));
+ SendCommandCompleteSuccess(HCI_BLE_WRITE_RANDOM_ADDR);
+}
+
+void DualModeController::HciLeSetAdvertisingParameters(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("LE SetAdvertisingParameters");
+ SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_PARAMS);
+}
+
+void DualModeController::HciLeSetAdvertisingData(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ LogCommand("LE SetAdvertisingData");
+ SendCommandCompleteSuccess(HCI_BLE_WRITE_ADV_DATA);
+}
+
+void DualModeController::HciLeSetScanParameters(const vector<uint8_t>& args) {
+ LogCommand("LE SetScanParameters");
+ CHECK(args.size() == 8);
+ le_scan_type_ = args[1];
+ le_scan_interval_ = args[2] | (args[3] << 8);
+ le_scan_window_ = args[4] | (args[5] << 8);
+ own_address_type_ = args[6];
+ scanning_filter_policy_ = args[7];
+ SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_PARAMS);
+}
+
+void DualModeController::HciLeSetScanEnable(const vector<uint8_t>& args) {
+ LogCommand("LE SetScanEnable");
+ CHECK(args.size() == 3);
+ CHECK(args[0] == 2);
+ le_scan_enable_ = args[1];
+ filter_duplicates_ = args[2];
+ SendCommandCompleteSuccess(HCI_BLE_WRITE_SCAN_ENABLE);
+}
+
+void DualModeController::HciLeReadWhiteListSize(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeReadWhiteListSize(
+ kSuccessStatus, properties_.GetLeWhiteListSize());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeRand(UNUSED_ATTR const vector<uint8_t>& args) {
+ uint64_t random_val = rand();
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeRand(kSuccessStatus, random_val);
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciLeReadSupportedStates(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeReadSupportedStates(
+ kSuccessStatus, properties_.GetLeSupportedStates());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciBleVendorSleepMode(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x27,
+ kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendorCap(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ std::unique_ptr<EventPacket> command_complete =
+ EventPacket::CreateCommandCompleteLeVendorCap(
+ kSuccessStatus, properties_.GetLeVendorCap());
+ send_event_(std::move(command_complete));
+}
+
+void DualModeController::HciBleVendorMultiAdv(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_BLE_MULTI_ADV_OCF, kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendor155(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x155,
+ kUnknownHciCommand);
+}
+
+void DualModeController::HciBleVendor157(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_GRP_VENDOR_SPECIFIC | 0x157,
+ kUnknownHciCommand);
+}
+
+void DualModeController::HciBleEnergyInfo(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_BLE_ENERGY_INFO_OCF, kUnknownHciCommand);
+}
+
+void DualModeController::HciBleExtendedScanParams(
+ UNUSED_ATTR const vector<uint8_t>& args) {
+ SendCommandCompleteOnlyStatus(HCI_BLE_EXTENDED_SCAN_PARAMS_OCF,
+ kUnknownHciCommand);
+}
+
+DualModeController::Properties::Properties(const std::string& file_name)
+ : acl_data_packet_size_(1024),
+ sco_data_packet_size_(255),
+ num_acl_data_packets_(10),
+ num_sco_data_packets_(10),
+ version_(4),
+ revision_(1),
+ lmp_pal_version_(0),
+ manufacturer_name_(0),
+ lmp_pal_subversion_(0),
+ le_data_packet_length_(27),
+ num_le_data_packets_(15),
+ le_white_list_size_(15) {
+ std::string properties_raw;
+
+ local_extended_features_ = {0xffffffffffffffff, 0x7};
+
+ CHECK(address_.FromString("01:02:03:04:05:06"));
+ local_name_ = "DefaultName";
+
+ supported_codecs_ = {1};
+ vendor_specific_codecs_ = {};
+
+ for (int i = 0; i < 64; i++) local_supported_commands_.push_back(0xff);
+
+ le_supported_features_ = 0x1f;
+ le_supported_states_ = 0x3ffffffffff;
+ le_vendor_cap_ = {0x05, 0x01, 0x00, 0x04, 0x80, 0x01, 0x10,
+ 0x01, 0x60, 0x00, 0x0a, 0x00, 0x01, 0x01};
+
+ LOG_INFO(LOG_TAG, "Reading controller properties from %s.",
+ file_name.c_str());
+ if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
+ LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
+ return;
+ }
+
+ std::unique_ptr<base::Value> properties_value_ptr =
+ base::JSONReader::Read(properties_raw);
+ if (properties_value_ptr.get() == nullptr)
+ LOG_INFO(LOG_TAG,
+ "Error controller properties may consist of ill-formed JSON.");
+
+ // Get the underlying base::Value object, which is of type
+ // base::Value::TYPE_DICTIONARY, and read it into member variables.
+ base::Value& properties_dictionary = *(properties_value_ptr.get());
+ base::JSONValueConverter<DualModeController::Properties> converter;
+
+ if (!converter.Convert(properties_dictionary, this))
+ LOG_INFO(LOG_TAG,
+ "Error converting JSON properties into Properties object.");
+}
+
+// static
+void DualModeController::Properties::RegisterJSONConverter(
+ base::JSONValueConverter<DualModeController::Properties>* converter) {
+// TODO(dennischeng): Use RegisterIntField() here?
+#define REGISTER_UINT8_T(field_name, field) \
+ converter->RegisterCustomField<uint8_t>( \
+ field_name, &DualModeController::Properties::field, &ParseUint8t);
+#define REGISTER_UINT16_T(field_name, field) \
+ converter->RegisterCustomField<uint16_t>( \
+ field_name, &DualModeController::Properties::field, &ParseUint16t);
+ REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
+ REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+ REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
+ REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
+ REGISTER_UINT8_T("Version", version_);
+ REGISTER_UINT16_T("Revision", revision_);
+ REGISTER_UINT8_T("LmpPalVersion", lmp_pal_version_);
+ REGISTER_UINT16_T("ManufacturerName", manufacturer_name_);
+ REGISTER_UINT16_T("LmpPalSubversion", lmp_pal_subversion_);
+#undef REGISTER_UINT8_T
+#undef REGISTER_UINT16_T
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/event_packet.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/event_packet.cc
new file mode 100755
index 0000000..78a0435
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/event_packet.cc
@@ -0,0 +1,328 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "event_packet"
+
+#include "event_packet.h"
+
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+EventPacket::EventPacket(uint8_t event_code)
+ : Packet(DATA_TYPE_EVENT, {event_code}) {}
+
+uint8_t EventPacket::GetEventCode() const { return GetHeader()[0]; }
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryCompleteEvent(
+ uint8_t status) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_COMP_EVT));
+ CHECK(evt_ptr->AddPayloadOctets1(status));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
+ uint16_t command_opcode, const vector<uint8_t>& event_return_parameters) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+ CHECK(evt_ptr->AddPayloadOctets(event_return_parameters.size(),
+ event_return_parameters));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ uint16_t command_opcode, uint8_t status) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_COMPLETE_EVT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+ CHECK(evt_ptr->AddPayloadOctets1(status));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
+std::unique_ptr<EventPacket> EventPacket::CreateCommandStatusEvent(
+ uint8_t status, uint16_t command_opcode) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ std::unique_ptr<EventPacket>(new EventPacket(HCI_COMMAND_STATUS_EVT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(status));
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
+ CHECK(evt_ptr->AddPayloadOctets2(command_opcode));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadLocalName(
+ uint8_t status, const std::string& local_name) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_LOCAL_NAME,
+ status);
+
+ for (size_t i = 0; i < local_name.length(); i++)
+ CHECK(evt_ptr->AddPayloadOctets1(local_name[i]));
+ CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
+ for (size_t i = 0; i < 248 - local_name.length() - 1; i++)
+ CHECK(evt_ptr->AddPayloadOctets1(0xFF));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalVersionInformation(
+ uint8_t status, uint8_t hci_version, uint16_t hci_revision,
+ uint8_t lmp_pal_version, uint16_t manufacturer_name,
+ uint16_t lmp_pal_subversion) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_READ_LOCAL_VERSION_INFO, status);
+
+ CHECK(evt_ptr->AddPayloadOctets1(hci_version));
+ CHECK(evt_ptr->AddPayloadOctets2(hci_revision));
+ CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
+ CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
+ CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalSupportedCommands(
+ uint8_t status, const vector<uint8_t>& supported_commands) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_READ_LOCAL_SUPPORTED_CMDS, status);
+
+ CHECK(evt_ptr->AddPayloadOctets(64, supported_commands));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalExtendedFeatures(
+ uint8_t status, uint8_t page_number, uint8_t maximum_page_number,
+ uint64_t extended_lmp_features) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_READ_LOCAL_EXT_FEATURES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets1(page_number));
+ CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
+ CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadBufferSize(
+ uint8_t status, uint16_t hc_acl_data_packet_length,
+ uint8_t hc_synchronous_data_packet_length,
+ uint16_t hc_total_num_acl_data_packets,
+ uint16_t hc_total_synchronous_data_packets) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_BUFFER_SIZE,
+ status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(hc_acl_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets1(hc_synchronous_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets2(hc_total_num_acl_data_packets));
+ CHECK(evt_ptr->AddPayloadOctets2(hc_total_synchronous_data_packets));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteReadBdAddr(
+ uint8_t status, const BtAddress& address) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_READ_BD_ADDR,
+ status);
+
+ CHECK(evt_ptr->AddPayloadBtAddress(address));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteReadLocalSupportedCodecs(
+ uint8_t status, const vector<uint8_t>& supported_codecs,
+ const vector<uint32_t>& vendor_specific_codecs) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_READ_LOCAL_SUPPORTED_CODECS, status);
+
+ CHECK(evt_ptr->AddPayloadOctets(supported_codecs.size(), supported_codecs));
+ for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
+ CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
+
+ return evt_ptr;
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateInquiryResultEvent(
+ const BtAddress& address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ std::unique_ptr<EventPacket>(new EventPacket(HCI_INQUIRY_RESULT_EVT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // Start with a single response
+
+ CHECK(evt_ptr->AddPayloadBtAddress(address));
+ CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
+ CHECK(evt_ptr->AddPayloadOctets2(kReservedZero));
+ CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
+ CHECK(!(clock_offset & 0x8000));
+ CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+
+ return evt_ptr;
+}
+
+void EventPacket::AddInquiryResult(
+ const BtAddress& address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset) {
+ CHECK(GetEventCode() == HCI_INQUIRY_RESULT_EVT);
+
+ CHECK(IncrementPayloadCounter(1)); // Increment the number of responses
+
+ CHECK(AddPayloadBtAddress(address));
+ CHECK(AddPayloadOctets1(page_scan_repetition_mode));
+ CHECK(AddPayloadOctets2(kReservedZero));
+ CHECK(AddPayloadOctets3(class_of_device));
+ CHECK(!(clock_offset & 0x8000));
+ CHECK(AddPayloadOctets2(clock_offset));
+}
+
+std::unique_ptr<EventPacket> EventPacket::CreateExtendedInquiryResultEvent(
+ const BtAddress& address,
+ const PageScanRepetitionMode page_scan_repetition_mode,
+ uint32_t class_of_device, uint16_t clock_offset, uint8_t rssi,
+ const vector<uint8_t>& extended_inquiry_response) {
+ std::unique_ptr<EventPacket> evt_ptr = std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_EXTENDED_INQUIRY_RESULT_EVT));
+
+ CHECK(evt_ptr->AddPayloadOctets1(1)); // Always contains a single response
+
+ CHECK(evt_ptr->AddPayloadBtAddress(address));
+ CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
+ CHECK(evt_ptr->AddPayloadOctets1(kReservedZero));
+ CHECK(evt_ptr->AddPayloadOctets3(class_of_device));
+ CHECK(!(clock_offset & 0x8000));
+ CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
+ CHECK(evt_ptr->AddPayloadOctets1(rssi));
+ CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response.size(),
+ extended_inquiry_response));
+ while (evt_ptr->AddPayloadOctets1(0xff))
+ ; // Fill packet
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeReadBufferSize(
+ uint8_t status, uint16_t hc_le_data_packet_length,
+ uint8_t hc_total_num_le_data_packets) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_BLE_READ_BUFFER_SIZE, status);
+
+ CHECK(evt_ptr->AddPayloadOctets2(hc_le_data_packet_length));
+ CHECK(evt_ptr->AddPayloadOctets1(hc_total_num_le_data_packets));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteLeReadLocalSupportedFeatures(
+ uint8_t status, uint64_t le_features) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_BLE_READ_LOCAL_SPT_FEAT, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(le_features));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteLeReadWhiteListSize(uint8_t status,
+ uint8_t white_list_size) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_BLE_READ_WHITE_LIST_SIZE, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(white_list_size));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeRand(
+ uint8_t status, uint64_t random_val) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_RAND, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(random_val));
+
+ return evt_ptr;
+}
+
+// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
+std::unique_ptr<EventPacket>
+EventPacket::CreateCommandCompleteLeReadSupportedStates(uint8_t status,
+ uint64_t le_states) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(
+ HCI_BLE_READ_SUPPORTED_STATES, status);
+
+ CHECK(evt_ptr->AddPayloadOctets8(le_states));
+
+ return evt_ptr;
+}
+
+// Vendor-specific commands (see hcidefs.h)
+
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteLeVendorCap(
+ uint8_t status, const vector<uint8_t>& vendor_cap) {
+ std::unique_ptr<EventPacket> evt_ptr =
+ EventPacket::CreateCommandCompleteOnlyStatusEvent(HCI_BLE_VENDOR_CAP_OCF,
+ status);
+
+ CHECK(evt_ptr->AddPayloadOctets(vendor_cap.size(), vendor_cap));
+
+ return evt_ptr;
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet.cc
new file mode 100755
index 0000000..a622a5f
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet.cc
@@ -0,0 +1,108 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "packet"
+
+#include "packet.h"
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+Packet::Packet(serial_data_type_t type, vector<uint8_t> header)
+ : type_(type), header_(std::move(header)) {
+ payload_ = {0};
+}
+
+bool Packet::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
+ if (octets + payload_.size() > kMaxPacketOctets) return false;
+
+ if (octets != bytes.size()) return false;
+
+ payload_.insert(payload_.end(), bytes.begin(), bytes.end());
+ payload_[0] = payload_.size() - 1;
+
+ return true;
+}
+
+bool Packet::AddPayloadOctets(size_t octets, uint64_t value) {
+ vector<uint8_t> val_vector;
+
+ uint64_t v = value;
+
+ if (octets > sizeof(uint64_t)) return false;
+
+ for (size_t i = 0; i < octets; i++) {
+ val_vector.push_back(v & 0xff);
+ v = v >> 8;
+ }
+
+ if (v != 0) return false;
+
+ return AddPayloadOctets(octets, val_vector);
+}
+
+bool Packet::AddPayloadBtAddress(const BtAddress& address) {
+ if (BtAddress::kOctets + payload_.size() > kMaxPacketOctets) return false;
+
+ address.ToVector(payload_);
+
+ payload_[0] = payload_.size() - 1;
+
+ return true;
+}
+
+bool Packet::IncrementPayloadCounter(size_t index) {
+ if (payload_.size() < index - 1) return false;
+
+ payload_[index]++;
+ return true;
+}
+
+bool Packet::IncrementPayloadCounter(size_t index, uint8_t max_val) {
+ if (payload_.size() < index - 1) return false;
+
+ if (payload_[index] + 1 > max_val) return false;
+
+ payload_[index]++;
+ return true;
+}
+
+const vector<uint8_t>& Packet::GetHeader() const {
+ // Every packet must have a header.
+ CHECK(GetHeaderSize() > 0);
+ return header_;
+}
+
+uint8_t Packet::GetHeaderSize() const { return header_.size(); }
+
+size_t Packet::GetPacketSize() const {
+ // Add one for the type octet.
+ return 1 + header_.size() + payload_.size();
+}
+
+const vector<uint8_t>& Packet::GetPayload() const { return payload_; }
+
+size_t Packet::GetPayloadSize() const { return payload_.size(); }
+
+serial_data_type_t Packet::GetType() const { return type_; }
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc
new file mode 100755
index 0000000..224283c
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/packet_stream.cc
@@ -0,0 +1,129 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "packet_stream"
+
+#include "packet_stream.h"
+
+#include <base/logging.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "osi/include/log.h"
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand(int fd) const {
+ vector<uint8_t> header;
+ vector<uint8_t> params_size;
+ vector<uint8_t> payload;
+
+ if (!ReceiveAll(header, CommandPacket::kCommandHeaderSize, fd)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command header.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+
+ if (!ReceiveAll(params_size, 1, fd)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving params size.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+
+ if (!ReceiveAll(payload, params_size[0], fd)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+ return std::unique_ptr<CommandPacket>(new CommandPacket(header, payload));
+}
+
+serial_data_type_t PacketStream::ReceivePacketType(int fd) const {
+ vector<uint8_t> raw_type_octet;
+
+ if (!ReceiveAll(raw_type_octet, 1, fd)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not receive packet type.");
+ }
+
+ // Check that the type octet received is in the valid range, i.e. the packet
+ // must be a command or data packet.
+ const serial_data_type_t type =
+ static_cast<serial_data_type_t>(raw_type_octet[0]);
+ if (!ValidateTypeOctet(type)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Received invalid packet type.");
+ }
+ return type;
+}
+
+bool PacketStream::SendEvent(std::unique_ptr<EventPacket> event, int fd) const {
+ if (event->GetPayload()[0] != event->GetPayloadSize() - 1)
+ LOG_WARN(LOG_TAG, "Malformed event: 0x%04X, payload size %zu, reported %u",
+ event->GetEventCode(), event->GetPacketSize(),
+ event->GetPayload()[0]);
+
+ if (!SendAll({static_cast<uint8_t>(event->GetType())}, 1, fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event type.");
+ return false;
+ }
+
+ if (!SendAll(event->GetHeader(), event->GetHeaderSize(), fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event header.");
+ return false;
+ }
+
+ if (!SendAll(event->GetPayload(), event->GetPayloadSize(), fd)) {
+ LOG_ERROR(LOG_TAG, "Error: Could not send event payload.");
+ return false;
+ }
+ return true;
+}
+
+bool PacketStream::ValidateTypeOctet(serial_data_type_t type) const {
+ // The only types of packets that should be received from the HCI are command
+ // packets and data packets.
+ return (type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO);
+}
+
+bool PacketStream::ReceiveAll(vector<uint8_t>& destination,
+ size_t num_octets_to_receive, int fd) const {
+ destination.resize(num_octets_to_receive);
+ size_t octets_remaining = num_octets_to_receive;
+ while (octets_remaining > 0) {
+ const int num_octets_received =
+ read(fd, &destination[num_octets_to_receive - octets_remaining],
+ octets_remaining);
+ if (num_octets_received < 0) return false;
+ octets_remaining -= num_octets_received;
+ }
+ return true;
+}
+
+bool PacketStream::SendAll(const vector<uint8_t>& source,
+ size_t num_octets_to_send, int fd) const {
+ CHECK(source.size() >= num_octets_to_send);
+ size_t octets_remaining = num_octets_to_send;
+ while (octets_remaining > 0) {
+ const int num_octets_sent = write(
+ fd, &source[num_octets_to_send - octets_remaining], octets_remaining);
+ if (num_octets_sent < 0) return false;
+ octets_remaining -= num_octets_sent;
+ }
+ return true;
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
new file mode 100755
index 0000000..adb3f7b
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/src/test_channel_transport.cc
@@ -0,0 +1,142 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "test_channel_transport"
+
+#include "test_channel_transport.h"
+
+#include <base/logging.h>
+
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+using std::vector;
+
+namespace test_vendor_lib {
+
+int TestChannelTransport::SetUp(int port) {
+ struct sockaddr_in listen_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&listen_address, 0, sockaddr_in_size);
+
+ OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
+ if (listen_fd_ < 0) {
+ LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ return -1;
+ }
+
+ LOG_INFO(LOG_TAG, "port: %d", port);
+ listen_address.sin_family = AF_INET;
+ listen_address.sin_port = htons(port);
+ listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address),
+ sockaddr_in_size) < 0) {
+ LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+ close(listen_fd_);
+ return -1;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ close(listen_fd_);
+ return -1;
+ }
+ return listen_fd_;
+}
+
+void TestChannelTransport::CleanUp() {
+ if (listen_fd_ == -1) {
+ return;
+ }
+ if (close(listen_fd_)) {
+ LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+ }
+ listen_fd_ = -1;
+}
+
+int TestChannelTransport::Accept(int listen_fd_) {
+ int accept_fd = -1;
+ struct sockaddr_in test_channel_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&test_channel_address, 0, sockaddr_in_size);
+
+ OSI_NO_INTR(accept_fd = accept(listen_fd_, reinterpret_cast<sockaddr*>(
+ &test_channel_address),
+ &sockaddr_in_size));
+ if (accept_fd < 0) {
+ LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).",
+ errno, strerror(errno));
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+ close(listen_fd_);
+ return -1;
+ }
+ }
+
+ LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+
+ return accept_fd;
+}
+
+void TestChannelTransport::OnCommandReady(int fd,
+ std::function<void(void)> unwatch) {
+ uint8_t command_name_size = 0;
+ read(fd, &command_name_size, 1);
+ vector<uint8_t> command_name_raw;
+ command_name_raw.resize(command_name_size);
+ read(fd, &command_name_raw[0], command_name_size);
+ std::string command_name(command_name_raw.begin(), command_name_raw.end());
+ LOG_INFO(LOG_TAG, "Received command from test channel: %s",
+ command_name.data());
+
+ if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
+ LOG_INFO(LOG_TAG, "Test channel closed");
+ unwatch();
+ close(fd);
+ return;
+ }
+
+ uint8_t num_args = 0;
+ read(fd, &num_args, 1);
+ LOG_INFO(LOG_TAG, "num_args: %d", num_args);
+ vector<std::string> args;
+ for (uint8_t i = 0; i < num_args; ++i) {
+ uint8_t arg_size = 0;
+ read(fd, &arg_size, 1);
+ vector<uint8_t> arg;
+ arg.resize(arg_size);
+ read(fd, &arg[0], arg_size);
+ args.push_back(std::string(arg.begin(), arg.end()));
+ }
+
+ for (size_t i = 0; i < args.size(); ++i)
+ LOG_INFO(LOG_TAG, "Command argument %zu: %s", i, args[i].data());
+
+ command_handler_(command_name, args);
+}
+
+void TestChannelTransport::RegisterCommandHandler(
+ const std::function<void(const std::string&, const vector<std::string>&)>&
+ callback) {
+ command_handler_ = callback;
+}
+
+} // namespace test_vendor_lib {
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
new file mode 100755
index 0000000..816a19b
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/async_manager_unittest.cc
@@ -0,0 +1,174 @@
+//
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "async_manager.h"
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <cstring>
+#include <vector>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace test_vendor_lib {
+
+class AsyncManagerSocketTest : public ::testing::Test {
+ public:
+ static const uint16_t kPort = 6111;
+ static const size_t kBufferSize = 16;
+
+ bool CheckBufferEquals() {
+ return strcmp(server_buffer_, client_buffer_) == 0;
+ }
+
+ protected:
+ int StartServer() {
+ struct sockaddr_in serv_addr;
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(fd < 0);
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(kPort);
+ int reuse_flag = 1;
+ EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag,
+ sizeof(reuse_flag)) < 0);
+ EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
+
+ listen(fd, 1);
+ return fd;
+ }
+
+ int AcceptConnection(int fd) {
+ struct sockaddr_in cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ socklen_t clilen = sizeof(cli_addr);
+
+ int connection_fd = accept(fd, (struct sockaddr*)&cli_addr, &clilen);
+ EXPECT_FALSE(connection_fd < 0);
+
+ return connection_fd;
+ }
+
+ void ReadIncomingMessage(int fd) {
+ int n = TEMP_FAILURE_RETRY(read(fd, server_buffer_, kBufferSize - 1));
+ EXPECT_FALSE(n < 0);
+
+ if (n == 0) { // got EOF
+ async_manager_.StopWatchingFileDescriptor(fd);
+ close(fd);
+ } else {
+ n = write(fd, "1", 1);
+ }
+ }
+
+ void SetUp() override {
+ memset(server_buffer_, 0, kBufferSize);
+
+ socket_fd_ = StartServer();
+
+ async_manager_.WatchFdForNonBlockingReads(socket_fd_, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+
+ async_manager_.WatchFdForNonBlockingReads(
+ connection_fd, [this](int fd) { ReadIncomingMessage(fd); });
+ });
+ }
+
+ void TearDown() override {
+ async_manager_.StopWatchingFileDescriptor(socket_fd_);
+ close(socket_fd_);
+ EXPECT_TRUE(CheckBufferEquals());
+ }
+
+ int ConnectClient() {
+ int socket_cli_fd = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_FALSE(socket_cli_fd < 0);
+
+ struct hostent* server;
+ server = gethostbyname("localhost");
+ EXPECT_FALSE(server == NULL);
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = *(reinterpret_cast<in_addr_t*>(server->h_addr));
+ serv_addr.sin_port = htons(kPort);
+
+ int result =
+ connect(socket_cli_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ EXPECT_FALSE(result < 0);
+
+ return socket_cli_fd;
+ }
+
+ void WriteFromClient(int socket_cli_fd) {
+ strcpy(client_buffer_, "1");
+ int n = write(socket_cli_fd, client_buffer_, strlen(client_buffer_));
+ EXPECT_TRUE(n > 0);
+ }
+
+ void AwaitServerResponse(int socket_cli_fd) {
+ int n = read(socket_cli_fd, client_buffer_, 1);
+ EXPECT_TRUE(n > 0);
+ }
+
+ private:
+ AsyncManager async_manager_;
+ int socket_fd_;
+ char server_buffer_[kBufferSize];
+ char client_buffer_[kBufferSize];
+};
+
+TEST_F(AsyncManagerSocketTest, TestOneConnection) {
+ int socket_cli_fd = ConnectClient();
+
+ WriteFromClient(socket_cli_fd);
+
+ AwaitServerResponse(socket_cli_fd);
+
+ close(socket_cli_fd);
+}
+
+TEST_F(AsyncManagerSocketTest, TestRepeatedConnections) {
+ static const int num_connections = 300;
+ for (int i = 0; i < num_connections; i++) {
+ int socket_cli_fd = ConnectClient();
+ WriteFromClient(socket_cli_fd);
+ AwaitServerResponse(socket_cli_fd);
+ close(socket_cli_fd);
+ }
+}
+
+TEST_F(AsyncManagerSocketTest, TestMultipleConnections) {
+ static const int num_connections = 300;
+ int socket_cli_fd[num_connections];
+ for (int i = 0; i < num_connections; i++) {
+ socket_cli_fd[i] = ConnectClient();
+ EXPECT_TRUE(socket_cli_fd[i] > 0);
+ WriteFromClient(socket_cli_fd[i]);
+ }
+ for (int i = 0; i < num_connections; i++) {
+ AwaitServerResponse(socket_cli_fd[i]);
+ close(socket_cli_fd[i]);
+ }
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
new file mode 100755
index 0000000..d998179
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/bt_address_unittest.cc
@@ -0,0 +1,194 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+using std::vector;
+
+#include "bt_address.h"
+
+namespace {
+const std::string kTestAddr1 = "12:34:56:78:9a:bc";
+const std::string kTestAddr2 = "cb:a9:87:65:43:21";
+const std::string kTestAddr3 = "cb:a9:56:78:9a:bc";
+const std::string kUpperMask = "ff:ff:00:00:00:00";
+const std::string kLowerMask = "00:00:ff:ff:ff:ff";
+const std::string kZeros = "00:00:00:00:00:00";
+const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
+}
+
+namespace test_vendor_lib {
+
+class BtAddressTest : public ::testing::Test {
+ public:
+ BtAddressTest() {}
+ ~BtAddressTest() {}
+};
+
+TEST_F(BtAddressTest, IsValid) {
+ EXPECT_FALSE(BtAddress::IsValid(""));
+ EXPECT_FALSE(BtAddress::IsValid("000000000000"));
+ EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:0000"));
+ EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0"));
+ EXPECT_FALSE(BtAddress::IsValid("00:00:00:00:00:0;"));
+ EXPECT_FALSE(BtAddress::IsValid("00:00:000:00:00:0;"));
+ EXPECT_TRUE(BtAddress::IsValid("00:00:00:00:00:00"));
+ EXPECT_FALSE(BtAddress::IsValid("aB:cD:eF:Gh:iJ:Kl"));
+ EXPECT_TRUE(BtAddress::IsValid(kTestAddr1));
+ EXPECT_TRUE(BtAddress::IsValid(kTestAddr2));
+ EXPECT_TRUE(BtAddress::IsValid(kTestAddr3));
+}
+
+TEST_F(BtAddressTest, test_comparisons) {
+ BtAddress btaddr1;
+ BtAddress btaddr1_copy;
+ BtAddress btaddr2;
+
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+
+ EXPECT_TRUE(btaddr1 == btaddr1_copy);
+ EXPECT_FALSE(btaddr1 == btaddr2);
+
+ EXPECT_FALSE(btaddr1 != btaddr1_copy);
+ EXPECT_TRUE(btaddr1 != btaddr2);
+
+ EXPECT_FALSE(btaddr1 < btaddr1_copy);
+ EXPECT_TRUE(btaddr1 < btaddr2);
+ EXPECT_FALSE(btaddr2 < btaddr1);
+
+ EXPECT_FALSE(btaddr1 > btaddr1_copy);
+ EXPECT_FALSE(btaddr1 > btaddr2);
+ EXPECT_TRUE(btaddr2 > btaddr1);
+
+ EXPECT_TRUE(btaddr1 <= btaddr1_copy);
+ EXPECT_TRUE(btaddr1 <= btaddr2);
+ EXPECT_FALSE(btaddr2 <= btaddr1);
+
+ EXPECT_TRUE(btaddr1 >= btaddr1_copy);
+ EXPECT_FALSE(btaddr1 >= btaddr2);
+ EXPECT_TRUE(btaddr2 >= btaddr1);
+}
+
+TEST_F(BtAddressTest, test_assignment) {
+ BtAddress btaddr1;
+ BtAddress btaddr2;
+ BtAddress btaddr3;
+
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+ EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
+
+ EXPECT_TRUE(btaddr1 != btaddr2);
+ EXPECT_TRUE(btaddr2 != btaddr3);
+ EXPECT_TRUE(btaddr1 != btaddr3);
+
+ btaddr1 = btaddr2;
+ EXPECT_TRUE(btaddr1 == btaddr2);
+ EXPECT_TRUE(btaddr2 != btaddr3);
+ EXPECT_TRUE(btaddr1 != btaddr3);
+
+ btaddr3 = btaddr2;
+ EXPECT_TRUE(btaddr1 == btaddr2);
+ EXPECT_TRUE(btaddr2 == btaddr3);
+ EXPECT_TRUE(btaddr1 == btaddr3);
+}
+
+TEST_F(BtAddressTest, test_bitoperations) {
+ BtAddress btaddr1;
+ BtAddress btaddr2;
+ BtAddress btaddr3;
+ BtAddress btaddr_lowmask;
+ BtAddress btaddr_upmask;
+
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+ EXPECT_TRUE(btaddr3.FromString(kTestAddr3));
+ EXPECT_TRUE(btaddr_lowmask.FromString(kLowerMask));
+ EXPECT_TRUE(btaddr_upmask.FromString(kUpperMask));
+
+ EXPECT_TRUE(btaddr1 != btaddr2);
+ EXPECT_TRUE(btaddr2 != btaddr3);
+ btaddr1 &= btaddr_lowmask;
+ btaddr2 &= btaddr_upmask;
+ btaddr1 |= btaddr2;
+ EXPECT_TRUE(btaddr1 == btaddr3);
+}
+
+TEST_F(BtAddressTest, FromString) {
+ BtAddress btaddrA;
+ BtAddress btaddrB;
+ BtAddress btaddrC;
+ EXPECT_TRUE(btaddrA.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddrA != btaddrB);
+ EXPECT_TRUE(btaddrC == btaddrB);
+ EXPECT_TRUE(btaddrB.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddrC.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddrA == btaddrB);
+ EXPECT_TRUE(btaddrC == btaddrB);
+}
+
+TEST_F(BtAddressTest, FromVector) {
+ BtAddress btaddr1;
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ BtAddress btaddrA;
+ BtAddress btaddrB;
+ EXPECT_TRUE(btaddrA.FromVector(kTestAddr1_octets));
+ EXPECT_TRUE(btaddrA != btaddrB);
+ EXPECT_TRUE(btaddrB.FromVector(kTestAddr1_octets));
+ EXPECT_TRUE(btaddrA == btaddrB);
+ EXPECT_TRUE(btaddr1 == btaddrB);
+}
+
+TEST_F(BtAddressTest, ToVector) {
+ BtAddress btaddr1;
+ BtAddress btaddr1_copy;
+ BtAddress btaddr2;
+ vector<uint8_t> octets1;
+ vector<uint8_t> octets1_copy;
+ vector<uint8_t> octets2;
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr1_copy.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr2.FromString(kTestAddr2));
+ EXPECT_TRUE(btaddr1 == btaddr1_copy);
+ EXPECT_TRUE(btaddr1 != btaddr2);
+ btaddr1.ToVector(octets1);
+ btaddr2.ToVector(octets2);
+ btaddr1_copy.ToVector(octets1_copy);
+ EXPECT_TRUE(octets1 != octets2);
+ EXPECT_TRUE(octets1 == octets1_copy);
+ EXPECT_TRUE(octets1.size() == BtAddress::kOctets);
+ btaddr1.ToVector(octets1);
+ EXPECT_TRUE(octets1.size() == (2 * BtAddress::kOctets));
+}
+
+TEST_F(BtAddressTest, ToString) {
+ BtAddress btaddr_zeros;
+ BtAddress btaddr1;
+ EXPECT_TRUE(btaddr_zeros.FromString(kZeros));
+ EXPECT_TRUE(btaddr1.FromString(kTestAddr1));
+ EXPECT_TRUE(btaddr_zeros.ToString() == kZeros);
+ EXPECT_TRUE(btaddr1.ToString() == kTestAddr1);
+ EXPECT_TRUE(btaddr_zeros.ToString() != kTestAddr1);
+ EXPECT_TRUE(btaddr1.ToString() != kZeros);
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
new file mode 100755
index 0000000..3908b9e
--- a/dev/null
+++ b/mtkbt/code/bt/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
@@ -0,0 +1,154 @@
+//
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "packet_stream.h"
+#include "command_packet.h"
+#include "event_packet.h"
+#include "packet.h"
+
+#include <gtest/gtest.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+using std::vector;
+
+#include "hci/include/hci_hal.h"
+#include "stack/include/hcidefs.h"
+
+#include <sys/socket.h>
+
+namespace {
+const char small_payload[] = "foo bar baz";
+const char large_payload[] =
+ "Aristotle's principles will then be no more principles to him, than those "
+ "of Epicurus and the Stoics: let this diversity of opinions be propounded "
+ "to, and laid before him; he will himself choose, if he be able; if not, "
+ "he will remain in doubt.";
+} // namespace
+
+namespace test_vendor_lib {
+
+class PacketStreamTest : public ::testing::Test {
+ public:
+ PacketStreamTest() {
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_);
+ CheckSocketpairInit();
+ }
+
+ ~PacketStreamTest() {
+ close(socketpair_fds_[0]);
+ close(socketpair_fds_[1]);
+ }
+
+ void CheckedReceiveCommand(const char* payload, uint16_t opcode) {
+ uint8_t payload_size = strlen(payload);
+ vector<uint8_t> packet;
+
+ packet.push_back(DATA_TYPE_COMMAND);
+ packet.push_back(opcode);
+ packet.push_back(opcode >> 8);
+ packet.push_back(payload_size);
+
+ // Set the packet's payload.
+ for (int i = 0; i < payload_size; ++i) packet.push_back(payload[i]);
+
+ // Send the packet to |packet_stream_|.
+ write(socketpair_fds_[1], &packet[1], packet.size());
+
+ // Read the command packet.
+ std::unique_ptr<CommandPacket> command =
+ packet_stream_.ReceiveCommand(socketpair_fds_[0]);
+
+ const vector<uint8_t> received_payload = command->GetPayload();
+
+ // Validate the packet by checking that it's the appropriate size and then
+ // checking each byte.
+ EXPECT_EQ(packet.size(), command->GetPacketSize());
+ EXPECT_EQ(DATA_TYPE_COMMAND, command->GetType());
+ EXPECT_EQ(opcode, command->GetOpcode());
+ EXPECT_EQ(static_cast<size_t>(payload_size + 1), command->GetPayloadSize());
+ EXPECT_EQ(payload_size, received_payload[0]);
+ for (int i = 0; i < payload_size; ++i)
+ EXPECT_EQ(packet[4 + i], received_payload[i + 1]);
+ }
+
+ void CheckedSendEvent(std::unique_ptr<EventPacket> event) {
+ const vector<uint8_t> expected_payload = event->GetPayload();
+ auto expected_size = event->GetPacketSize();
+ auto expected_code = event->GetEventCode();
+ auto expected_payload_size = event->GetPayloadSize();
+
+ EXPECT_TRUE(packet_stream_.SendEvent(std::move(event), socketpair_fds_[0]));
+
+ // Read the packet sent by |packet_stream_|.
+ uint8_t event_header[2];
+ read(socketpair_fds_[1], event_header, 2);
+
+ uint8_t return_parameters_size;
+ read(socketpair_fds_[1], &return_parameters_size, 1);
+
+ uint8_t return_parameters[return_parameters_size];
+ read(socketpair_fds_[1], return_parameters, sizeof(return_parameters));
+
+ // Validate the packet by checking that it's the
+ // appropriate size and then checking each byte.
+ EXPECT_EQ(expected_size, sizeof(event_header) + return_parameters_size + 1);
+ EXPECT_EQ(DATA_TYPE_EVENT, event_header[0]);
+ EXPECT_EQ(expected_code, event_header[1]);
+ EXPECT_EQ(expected_payload_size,
+ static_cast<size_t>(return_parameters_size) + 1);
+ for (int i = 0; i < return_parameters_size; ++i)
+ EXPECT_EQ(expected_payload[i + 1], return_parameters[i]);
+ }
+
+ protected:
+ PacketStream packet_stream_;
+
+ int socketpair_fds_[2];
+
+ private:
+ // Workaround because ASSERT cannot be used directly in a constructor
+ void CheckSocketpairInit() {
+ ASSERT_TRUE(socketpair_fds_[0] > 0);
+ ASSERT_TRUE(socketpair_fds_[1] > 0);
+ }
+};
+
+TEST_F(PacketStreamTest, ReceivePacketType) {
+ serial_data_type_t command_type = DATA_TYPE_COMMAND;
+ write(socketpair_fds_[1], &command_type, 1);
+ EXPECT_EQ(command_type, packet_stream_.ReceivePacketType(socketpair_fds_[0]));
+}
+
+TEST_F(PacketStreamTest, ReceiveEmptyCommand) {
+ CheckedReceiveCommand("", HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveSmallCommand) {
+ CheckedReceiveCommand(small_payload, HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, ReceiveLargeCommand) {
+ CheckedReceiveCommand(large_payload, HCI_RESET);
+}
+
+TEST_F(PacketStreamTest, SendEvent) {
+ const vector<uint8_t> return_parameters = {0};
+ CheckedSendEvent(
+ EventPacket::CreateCommandCompleteEvent(HCI_RESET, return_parameters));
+}
+
+} // namespace test_vendor_lib
diff --git a/mtkbt/code/bt/vnd/ble/vendor_hcidefs.h b/mtkbt/code/bt/vnd/ble/vendor_hcidefs.h
new file mode 100755
index 0000000..d0bbaf3
--- a/dev/null
+++ b/mtkbt/code/bt/vnd/ble/vendor_hcidefs.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2003-2014 Broadcom Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Name vendor_hcidefs.h
+ *
+ * Function This file contains Broadcom Specific Host Controller Interface
+ * definitions.
+ *
+ *****************************************************************************/
+
+#ifndef VENDOR_HCIDEFS_H
+#define VENDOR_HCIDEFS_H
+
+/*****************************************************************************
+ * Private address resolution VSC
+ *****************************************************************************/
+
+/* VSC */
+#define HCI_VENDOR_BLE_RPA_VSC (0x0155 | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Sub codes */
+#define HCI_VENDOR_BLE_RPA_ENABLE 0x01
+#define HCI_VENDOR_BLE_RPA_ADD_IRK 0x02
+#define HCI_VENDOR_BLE_RPA_REMOVE_IRK 0x03
+#define HCI_VENDOR_BLE_RPA_CLEAR_IRK 0x04
+#define HCI_VENDOR_BLE_RPA_READ_IRK 0x05
+
+/*****************************************************************************
+ * Advertising data payload filter VSC
+ *****************************************************************************/
+
+/* VSC */
+#define HCI_VENDOR_BLE_PCF_VSC (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+
+#endif
diff --git a/mtkbt/code/bt/vnd/include/vendor_api.h b/mtkbt/code/bt/vnd/include/vendor_api.h
new file mode 100755
index 0000000..a26ee72
--- a/dev/null
+++ b/mtkbt/code/bt/vnd/include/vendor_api.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+ *
+ * Name: vendor_api.h
+ *
+ * Description: Vendor specific BTE API function external definitions.
+ *
+ * Copyright (c) 2009-2011, BROADCOM Inc., All Rights Reserved.
+ * Broadcom Bluetooth Core. Proprietary and confidential.
+ *
+ *****************************************************************************/
+#ifndef VENDOR_API_H
+#define VENDOR_API_H
+
+#include "bt_types.h"
+#include "btm_api.h"
+
+/****************************************************************************
+ * Resolvable private address offload VSC specific definitions
+ *****************************************************************************/
+
+enum { BTM_BLE_PRIVACY_ENABLE, BTM_BLE_PRIVACY_DISABLE };
+
+#endif
diff --git a/mtkbt/code/libdriver/Android.mk b/mtkbt/code/libdriver/Android.mk
new file mode 100755
index 0000000..d5198cc
--- a/dev/null
+++ b/mtkbt/code/libdriver/Android.mk
@@ -0,0 +1,57 @@
+LOCAL_PATH := $(call my-dir)
+#$(call config-custom-folder,custom:hal/bluetooth)
+
+###########################################################################
+# MTK BT CHIP INIT LIBRARY FOR BLUEDROID
+###########################################################################
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ mtk.c \
+ radiomgr.c\
+ platform.c
+LOCAL_C_INCLUDES := \
+ hardware/mtk/bluetooth/mtkbt/code/bt/hci/include \
+
+
+LOCAL_CFLAGS += -DMTK_MT7662
+
+
+ifeq ($(TARGET_BUILD_VARIANT), eng)
+LOCAL_CFLAGS += -DBD_ADDR_AUTOGEN
+endif
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libbluetooth_mtk
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+include $(BUILD_SHARED_LIBRARY)
+
+###########################################################################
+# MTK BT DRIVER FOR BLUEDROID
+###########################################################################
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ bt_drv.c \
+ bperf_util.c
+
+LOCAL_C_INCLUDES := \
+ hardware/mtk/bluetooth/mtkbt/code/bt/hci/include \
+
+LOCAL_CFLAGS += -DMTK_VENDOR_OPCODE=FALSE
+LOCAL_CFLAGS += -DMTK_BPERF_ENABLE=FALSE
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libbt-vendor
+LOCAL_SHARED_LIBRARIES := liblog libbluetooth_mtk libcutils
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/mtkbt/code/libdriver/bperf_util.c b/mtkbt/code/libdriver/bperf_util.c
new file mode 100755
index 0000000..ea8941c
--- a/dev/null
+++ b/mtkbt/code/libdriver/bperf_util.c
@@ -0,0 +1,1249 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include "bperf_util.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define BPERF_LIBRARY_VERSION "700.0.17071101"
+#define LOG_TAG "bperf"
+#define MAX_BPERF_EVENTS_IN_A_SECOND 500
+#define MAX_BPERF_LE_SCAN_ENTRY 64
+#define MAX_BPERF_BT_SCAN_ENTRY 64
+
+static pthread_mutex_t event_data_lock;
+static pthread_t bperf_thread_main;
+static unsigned int bperf_main_thread_status;
+static unsigned int bperf_main_thread_should_stop;
+static unsigned int bperf_global_counter;
+static uint8_t bperf_global_bitpool;
+static uint8_t bperf_global_voble_codec; /* 0: ADPCM, 1:OPUS */
+static unsigned char bperf_a2dp_string_interval[64];
+static unsigned char bperf_a2dp_string_throughput[64];
+static unsigned char bperf_a2dp_string_bitpool[64];
+
+static unsigned int bperf_average_accumulate;
+static unsigned int bperf_average_total_time;
+
+static int event_len_summary_rc_fw_upgrade = 0;
+static int event_len_summary_voice = 0;
+static int event_len_summary_a2dp = 0;
+static int event_counter_summary_hid = 0;
+static int event_counter_summary_hid_cursor = 0;
+static int event_counter_summary_hogp = 0;
+static int event_counter_summary_hogp_cursor = 0;
+static int event_counter_summary_hid_delta_time_max = 0;
+static int event_counter_summary_hid_cursor_delta_time_max = 0;
+static int event_counter_summary_hogp_delta_time_max = 0;
+static int event_counter_summary_hogp_cursor_delta_time_max = 0;
+static int event_counter_summary_ble_adv = 0;
+
+static struct bperf_event *bperf_event_voice, *bperf_event_voice_analysis;
+static struct bperf_event *bperf_event_rc_fw_upgrade, *bperf_event_rc_fw_upgrade_analysis;
+static struct bperf_event *bperf_event_hid, *bperf_event_hid_analysis;
+static struct bperf_event *bperf_event_hid_cursor, *bperf_event_hid_cursor_analysis;
+static struct bperf_event *bperf_event_hogp, *bperf_event_hogp_analysis;
+static struct bperf_event *bperf_event_hogp_cursor, *bperf_event_hogp_cursor_analysis;
+static struct bperf_event *bperf_event_a2dp, *bperf_event_a2dp_analysis;
+static struct bperf_event *bperf_event_ble_adv, *bperf_event_ble_adv_analysis;
+
+static unsigned int _bperf_get_microseconds(void)
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return (now.tv_sec * 1000000 + now.tv_usec);
+}
+
+static void _bperf_mem_record_event(struct bperf_event* event, const uint8_t *buf, const unsigned int buf_len)
+{
+ int i;
+ (void)buf;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( event[i].id == 0 && event[i].time == 0 )
+ {
+ pthread_mutex_lock(&event_data_lock);
+ event[i].id = 1+i;
+ event[i].time = _bperf_get_microseconds();
+ event[i].buf_len = buf_len;
+
+ /* HT RC Voice Search (2640)(BLE Data Length Extension) */
+ if ( buf_len == 111 && buf[2] == 0x6b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
+ {
+ event[i].extra_info = ((buf[11] >>3 )& 0x1F);
+ }
+ pthread_mutex_unlock(&event_data_lock);
+ break;
+ }
+ }
+}
+
+static void _bperf_mem_reset()
+{
+ if ( bperf_event_voice )
+ memset(bperf_event_voice, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_rc_fw_upgrade )
+ memset(bperf_event_rc_fw_upgrade, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid )
+ memset(bperf_event_hid, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_cursor )
+ memset(bperf_event_hid_cursor, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp )
+ memset(bperf_event_hogp, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_cursor )
+ memset(bperf_event_hogp_cursor, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_a2dp )
+ memset(bperf_event_a2dp, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_ble_adv )
+ memset(bperf_event_ble_adv, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+}
+
+static void _bperf_mem_reset_analysis()
+{
+ if ( bperf_event_voice_analysis )
+ memset(bperf_event_voice_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_rc_fw_upgrade_analysis )
+ memset(bperf_event_rc_fw_upgrade_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_analysis )
+ memset(bperf_event_hid_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_cursor_analysis )
+ memset(bperf_event_hid_cursor_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_analysis )
+ memset(bperf_event_hogp_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_cursor_analysis )
+ memset(bperf_event_hogp_cursor_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_a2dp_analysis )
+ memset(bperf_event_a2dp_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_ble_adv_analysis )
+ memset(bperf_event_ble_adv_analysis, 0, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+}
+
+static void _bperf_mem_init()
+{
+ if ( bperf_event_voice == NULL )
+ bperf_event_voice = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_rc_fw_upgrade == NULL )
+ bperf_event_rc_fw_upgrade = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid == NULL )
+ bperf_event_hid = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_cursor == NULL )
+ bperf_event_hid_cursor = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp == NULL )
+ bperf_event_hogp = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_cursor == NULL )
+ bperf_event_hogp_cursor= malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_a2dp == NULL )
+ bperf_event_a2dp = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_ble_adv == NULL )
+ bperf_event_ble_adv = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+
+ if ( bperf_event_voice_analysis == NULL )
+ bperf_event_voice_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_rc_fw_upgrade_analysis == NULL )
+ bperf_event_rc_fw_upgrade_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_analysis == NULL )
+ bperf_event_hid_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hid_cursor_analysis == NULL )
+ bperf_event_hid_cursor_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_analysis == NULL )
+ bperf_event_hogp_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_hogp_cursor_analysis == NULL )
+ bperf_event_hogp_cursor_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_a2dp_analysis == NULL )
+ bperf_event_a2dp_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ if ( bperf_event_ble_adv_analysis == NULL )
+ bperf_event_ble_adv_analysis = malloc(sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+
+ _bperf_mem_reset();
+ _bperf_mem_reset_analysis();
+}
+
+static void _bperf_mem_free()
+{
+ if ( bperf_event_voice )
+ free(bperf_event_voice);
+ if ( bperf_event_rc_fw_upgrade )
+ free(bperf_event_rc_fw_upgrade);
+ if ( bperf_event_hid )
+ free(bperf_event_hid);
+ if ( bperf_event_hid_cursor )
+ free(bperf_event_hid_cursor);
+ if ( bperf_event_hogp )
+ free(bperf_event_hogp);
+ if ( bperf_event_hogp_cursor )
+ free(bperf_event_hogp_cursor);
+ if ( bperf_event_a2dp )
+ free(bperf_event_a2dp);
+ if ( bperf_event_ble_adv )
+ free(bperf_event_ble_adv);
+
+ if ( bperf_event_voice_analysis )
+ free(bperf_event_voice_analysis);
+ if ( bperf_event_rc_fw_upgrade_analysis )
+ free(bperf_event_rc_fw_upgrade_analysis);
+ if ( bperf_event_hid_analysis )
+ free(bperf_event_hid_analysis);
+ if ( bperf_event_hid_cursor_analysis )
+ free(bperf_event_hid_cursor_analysis);
+ if ( bperf_event_hogp_analysis )
+ free(bperf_event_hogp_analysis);
+ if ( bperf_event_hogp_cursor_analysis )
+ free(bperf_event_hogp_cursor_analysis);
+ if ( bperf_event_a2dp_analysis )
+ free(bperf_event_a2dp_analysis);
+ if ( bperf_event_ble_adv_analysis )
+ free(bperf_event_ble_adv_analysis);
+}
+
+static void _bperf_mem_copy()
+{
+ memcpy(bperf_event_voice_analysis, bperf_event_voice, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_rc_fw_upgrade_analysis, bperf_event_rc_fw_upgrade, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_hid_analysis, bperf_event_hid, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_hid_cursor_analysis, bperf_event_hid_cursor, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_hogp_analysis, bperf_event_hogp, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_hogp_cursor_analysis, bperf_event_hogp_cursor, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_a2dp_analysis, bperf_event_a2dp, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+ memcpy(bperf_event_ble_adv_analysis, bperf_event_ble_adv, sizeof(struct bperf_event)*MAX_BPERF_EVENTS_IN_A_SECOND);
+}
+
+static void _bperf_analysis_rc_fw_upgrade(struct bperf_event *bperf_event)
+{
+ if ( bperf_event )
+ {
+ int i;
+ int event_counter=0;
+ int event_len_total=0;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( bperf_event[i].id )
+ {
+ event_counter++;
+ event_len_total += (bperf_event[i].buf_len - 4); /* 4 byte hci header should be removed */
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( i > 0 )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_len_summary_rc_fw_upgrade += event_len_total;
+ }
+
+ LOG_PER(LIGHT_BLUE "[bperf](%d) RC FW Upgrade Num(%d), Throughput" GREEN "(%dbps)" NONECOLOR,
+ bperf_global_counter, event_counter, (event_len_total<<3));
+ }
+ }
+}
+
+static void _bperf_analysis_voice(struct bperf_event *bperf_event)
+{
+ if ( bperf_event )
+ {
+ int i;
+ int event_counter = 0;
+ int event_len_total = 0;
+ int event_len_voice = 0;
+ int event_counter_packet_drop = 0;
+ int event_counter_packet_not_in_time = 0;
+ int event_delta_time = 0;
+ int event_max_delta_time = 0;
+ static int latest_voice_data_seq = 0;
+ static int latest_voice_data_timestamp = 0;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( bperf_event[i].id )
+ {
+ event_counter++;
+
+ /* Voice data packet contains 4 bytes hci header, 4 bytes l2cap header, 3 bytes ATT header, 1 bytes rc header, 19 bytes audio data */
+ event_len_total += (bperf_event[i].buf_len - 4);
+ event_len_voice += (bperf_event[i].buf_len - 11);
+
+ if ( i > 0 )
+ {
+ /* check sequence num */
+ if ( bperf_event[i].extra_info != 0 && bperf_event[i].extra_info - bperf_event[i-1].extra_info != 1 )
+ {
+ event_counter_packet_drop++;
+ }
+ else if ( bperf_event[i].extra_info == 0 && bperf_event[i-1].extra_info != 0 && bperf_event[i-1].extra_info != 31 )
+ {
+ event_counter_packet_drop++;
+ }
+
+ /* check delta time */
+ event_delta_time = bperf_event[i].time - bperf_event[i-1].time;
+ if ( event_delta_time > 30000 )
+ {
+ event_counter_packet_not_in_time++;
+ }
+
+ latest_voice_data_seq = bperf_event[i].extra_info;
+ latest_voice_data_timestamp = bperf_event[i].time;
+ }
+ else if ( i == 0 )
+ {
+ /* check sequence num */
+ if ( bperf_event[i].extra_info != 0 && bperf_event[i].extra_info - latest_voice_data_seq != 1 )
+ {
+ event_counter_packet_drop++;
+ }
+ else if ( bperf_event[i].extra_info == 0 && latest_voice_data_seq != 0 && latest_voice_data_seq != 31 )
+ {
+ event_counter_packet_drop++;
+ }
+
+ /* check delta time */
+ event_delta_time = bperf_event[i].time - latest_voice_data_timestamp;
+ if ( bperf_event[i].time - latest_voice_data_timestamp > 30000 )
+ {
+ event_counter_packet_not_in_time++;
+ }
+ event_max_delta_time = event_delta_time;
+ }
+
+ /* check max delta time */
+ if ( event_delta_time > event_max_delta_time )
+ {
+ event_max_delta_time = event_delta_time;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( i > 0 )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_len_summary_voice += event_len_voice;
+ }
+
+ if (bperf_global_voble_codec == 0) /* codec : ADPCM */
+ {
+ /* Normal ADPCM voice data rate is abount 66,400 bps. */
+ if ( ((event_len_voice<<3) < 60000) || (event_counter_packet_drop>0) )
+ LOG_PER(LIGHT_BLUE "[bperf](%d) VOICE Num(%d), " LIGHT_BLUE ", Voice Data Rate" LIGHT_RED "(%dbps), Packet Drop (%d), Not in time (%d), Max Latency(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, (event_len_voice<<3), event_counter_packet_drop, event_counter_packet_not_in_time, event_max_delta_time/1000);
+ else
+ LOG_PER(LIGHT_BLUE "[bperf](%d) VOICE Num(%d), " LIGHT_BLUE ", Voice Data Rate" GREEN "(%dbps), Packet Drop (%d), Not in Time (%d), Max Latency(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, (event_len_voice<<3), event_counter_packet_drop, event_counter_packet_not_in_time, event_max_delta_time/1000);
+ }
+ else /* codec : OPUS */
+ {
+ /* Normal ADPCM voice data rate is abount 16,800 bps. */
+ if ( (event_len_voice<<3) < 15000 )
+ LOG_PER(LIGHT_BLUE "[bperf](%d) VOICE Num(%d), " LIGHT_BLUE ", Voice Data Rate" LIGHT_RED "(%dbps)" NONECOLOR,
+ bperf_global_counter, event_counter, (event_len_voice<<3));
+ else
+ LOG_PER(LIGHT_BLUE "[bperf](%d) VOICE Num(%d), " LIGHT_BLUE ", Voice Data Rate" GREEN "(%dbps)" NONECOLOR,
+ bperf_global_counter, event_counter, (event_len_voice<<3));
+ }
+ }
+ }
+}
+
+static void _bperf_analysis_hid_hogp(struct bperf_event *bperf_event)
+{
+ if ( bperf_event )
+ {
+ int i;
+ int event_counter=0;
+ int delta_time=0;
+ int delta_time_max=0;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( bperf_event[i].id )
+ {
+ event_counter++;
+ if ( i == 0 )
+ {
+ delta_time = 0;
+ delta_time_max = 0;
+ }
+ else
+ {
+ delta_time = bperf_event[i].time - bperf_event[i-1].time;
+ if ( delta_time > delta_time_max )
+ delta_time_max = delta_time;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( i > 0 )
+ {
+ if ( bperf_event == bperf_event_hid_analysis )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_counter_summary_hid += event_counter;
+ if ( delta_time_max > event_counter_summary_hid_delta_time_max )
+ event_counter_summary_hid_delta_time_max = delta_time_max;
+ }
+
+ LOG_PER(LIGHT_WHITE "[bperf](%d) HID Num(%d) Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, delta_time_max/1000);
+ }
+ else if ( bperf_event == bperf_event_hid_cursor_analysis )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_counter_summary_hid_cursor += event_counter;
+ if ( delta_time_max > event_counter_summary_hid_cursor_delta_time_max )
+ event_counter_summary_hid_cursor_delta_time_max = delta_time_max;
+ }
+
+ LOG_PER(LIGHT_WHITE "[bperf](%d) HID_Cursor Num(%d) Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, delta_time_max/1000);
+ }
+ else if ( bperf_event == bperf_event_hogp_analysis )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_counter_summary_hogp += event_counter;
+ if ( delta_time_max > event_counter_summary_hogp_delta_time_max )
+ event_counter_summary_hogp_delta_time_max = delta_time_max;
+ }
+
+ LOG_PER(LIGHT_WHITE "[bperf](%d) HOGP Num(%d) Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, delta_time_max/1000);
+ }
+ else if ( bperf_event == bperf_event_hogp_cursor_analysis )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_counter_summary_hogp_cursor += event_counter;
+ if ( delta_time_max > event_counter_summary_hogp_cursor_delta_time_max )
+ event_counter_summary_hogp_cursor_delta_time_max = delta_time_max;
+ }
+
+ LOG_PER(LIGHT_WHITE "[bperf](%d) HOGP_Cursor Num(%d) Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_global_counter, event_counter, delta_time_max/1000);
+ }
+ }
+ }
+}
+
+static void _bperf_analysis_a2dp(struct bperf_event *bperf_event)
+{
+ if ( bperf_event )
+ {
+ int i;
+ int event_counter=0;
+ int delta_time_max=0;
+ int delta_time_min=0;
+ int delta_time_average=0;
+ int delta_time=0;
+ int event_len_total=0;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( bperf_event[i].id )
+ {
+ event_counter++;
+ /* A2DP data packet contains 4byte HCI header, 4 byte L2CAP header, 12 byte AVDTP header*/
+ event_len_total += (bperf_event[i].buf_len - 20);
+ if ( i == 0 )
+ {
+ delta_time_max = delta_time_average = 0;
+ delta_time_min = 999999999;
+ }
+ else
+ {
+ if ( bperf_event[i].time > bperf_event[i-1].time )
+ delta_time = bperf_event[i].time - bperf_event[i-1].time;
+ else
+ delta_time = 0;
+
+ if ( delta_time > delta_time_max )
+ delta_time_max = delta_time;
+ if ( delta_time < delta_time_min )
+ delta_time_min = delta_time;
+ delta_time_average += delta_time;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( i > 0 )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_len_summary_a2dp += event_len_total;
+ }
+
+ delta_time_average = delta_time_average/i;
+ memset(bperf_a2dp_string_interval, 0, sizeof(bperf_a2dp_string_interval));
+ memset(bperf_a2dp_string_throughput, 0, sizeof(bperf_a2dp_string_throughput));
+ memset(bperf_a2dp_string_bitpool, 0, sizeof(bperf_a2dp_string_bitpool));
+
+ if (bperf_global_bitpool==53)
+ {
+ snprintf((char*)bperf_a2dp_string_bitpool, sizeof(bperf_a2dp_string_bitpool), "%sBitpool%s(%d)%s", LIGHT_PURPLE, GREEN, bperf_global_bitpool, NONECOLOR);
+
+ if (delta_time_max > 150000)
+ snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, LIGHT_RED, delta_time_max/1000, NONECOLOR);
+ else if (delta_time_max <= 150000 && delta_time_max > 100000)
+ snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, YELLOW, delta_time_max/1000, NONECOLOR);
+ else
+ snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, GREEN, delta_time_max/1000, NONECOLOR);
+
+ /* 90% : 328*1024*0.9 = 302285 */
+ /* 85% : 328*1024*0.85 = 285491 */
+ if ((event_len_total<<3) < 285491)
+ snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%dbps)%s", LIGHT_PURPLE, LIGHT_RED, (event_len_total<<3), NONECOLOR);
+ else if ((event_len_total<<3) >= 285491 && (event_len_total<<3) < 302285)
+ snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%dbps)%s", LIGHT_PURPLE, YELLOW, (event_len_total<<3), NONECOLOR);
+ else
+ snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%dbps)%s", LIGHT_PURPLE, GREEN, (event_len_total<<3), NONECOLOR);
+ }
+ else
+ {
+ snprintf((char*)bperf_a2dp_string_bitpool, sizeof(bperf_a2dp_string_bitpool), "%sBitpool%s(%d)%s", LIGHT_PURPLE, YELLOW, bperf_global_bitpool, NONECOLOR);
+ snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, LIGHT_WHITE, delta_time_max/1000, NONECOLOR);
+ snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%dbps)%s", LIGHT_PURPLE, LIGHT_WHITE, (event_len_total<<3), NONECOLOR);
+ }
+
+ LOG_PER(LIGHT_PURPLE "[bperf](%d) A2DP Num(%d), %s, %s, %s" NONECOLOR,
+ bperf_global_counter, event_counter, bperf_a2dp_string_bitpool, bperf_a2dp_string_interval, bperf_a2dp_string_throughput);
+
+ }
+ }
+}
+
+static void _bperf_analysis_ble_adv(struct bperf_event *bperf_event)
+{
+ if ( bperf_event )
+ {
+ int i;
+ int event_counter=0;
+
+ for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
+ {
+ if ( bperf_event[i].id )
+ {
+ event_counter++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( i > 0 )
+ {
+ if ( bperf_average_accumulate == 1 )
+ {
+ event_counter_summary_ble_adv += event_counter;
+ }
+
+ LOG_PER(LIGHT_WHITE "[bperf](%d) BLE ADV Num(%d)" NONECOLOR, bperf_global_counter, event_counter);
+ }
+ }
+}
+
+static void _bperf_analysis_inquiry(const uint8_t *buf, const unsigned int buf_len)
+{
+ int i;
+ int entry_found = MAX_BPERF_BT_SCAN_ENTRY;
+ int entry_empty = MAX_BPERF_BT_SCAN_ENTRY;
+ int entry_used = MAX_BPERF_BT_SCAN_ENTRY;
+ int save_entry = 0;
+ static unsigned int bt_scan_start_time;
+ static unsigned int bt_scan_result_time[MAX_BPERF_BT_SCAN_ENTRY][3];
+ static uint8_t bt_scan_result_address[MAX_BPERF_BT_SCAN_ENTRY][6];
+
+ /* HCI_INQUIRY */
+ if ( buf_len == 8 && buf[0] == 0x01 && buf[1] == 0x04 && buf[2] == 0x05 )
+ {
+ LOG_PER(YELLOW "[bperf] HCI_INQUIRY Started (Inquiry_Length:%.2fs)(0ms)" NONECOLOR, (buf[6]*1.28));
+ bt_scan_start_time = _bperf_get_microseconds();
+ for ( i = 0 ; i < MAX_BPERF_LE_SCAN_ENTRY ; i++ )
+ {
+ bt_scan_result_time[i][0] = 0;
+ bt_scan_result_time[i][1] = 0;
+ bt_scan_result_time[i][2] = 0;
+ bt_scan_result_address[i][0] = 0;
+ bt_scan_result_address[i][1] = 0;
+ bt_scan_result_address[i][2] = 0;
+ bt_scan_result_address[i][3] = 0;
+ bt_scan_result_address[i][4] = 0;
+ bt_scan_result_address[i][5] = 0;
+ }
+ }
+ /* HCI_EXTEND_INQUIRY_RESULT || HCI_REMOTE_NAME_REQUEST ||HCI_REMOTE_NAME_REQUEST_COMPLETE*/
+ else if ( (buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01) ||
+ (buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a) ||
+ (buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00) )
+ {
+ for ( i = 0 ; i < MAX_BPERF_BT_SCAN_ENTRY ; i++ )
+ {
+ if ( bt_scan_result_address[i][0] == 0 && bt_scan_result_address[i][1] == 0 && bt_scan_result_address[i][2] == 0 &&
+ bt_scan_result_address[i][3] == 0 && bt_scan_result_address[i][4] == 0 && bt_scan_result_address[i][5] == 0 )
+ {
+ entry_empty = i;
+ break;
+ }
+ }
+
+ for ( i = 0 ; i < MAX_BPERF_BT_SCAN_ENTRY ; i++ )
+ {
+ if ( strncmp((char*)(&bt_scan_result_address[i][0]), (char*)(&buf[3]), 6) == 0 )
+ {
+ entry_found = i;
+ break;
+ }
+ }
+
+ /* Entry found */
+ if ( entry_found != MAX_BPERF_BT_SCAN_ENTRY )
+ {
+ save_entry = 1;
+ entry_used = entry_found;
+ }
+ /* Entry not found, use empty entry */
+ else if ( entry_found == MAX_BPERF_BT_SCAN_ENTRY && entry_empty != MAX_BPERF_BT_SCAN_ENTRY )
+ {
+ save_entry = 1;
+ entry_used = entry_empty;
+ }
+ /* Entry full */
+ else
+ {
+ save_entry = 0;
+ LOG_PER(YELLOW "[bperf] HCI_EXTEND_INQUIRY_RESULT Entry FULL!! (%d)" NONECOLOR, MAX_BPERF_BT_SCAN_ENTRY);
+ }
+
+ if ( save_entry )
+ {
+ /* HCI_EXTEND_INQUIRY_RESULT */
+ if ( buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01 )
+ {
+ strncpy((char*)(&bt_scan_result_address[entry_used][0]), (char*)(&buf[3]), 6);
+ bt_scan_result_time[entry_used][0] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_EXTEND_INQUIRY_RESULT (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)" NONECOLOR,
+ entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
+ (int)((bt_scan_result_time[entry_used][0]-bt_scan_start_time)/1000));
+ }
+ /* HCI_REMOTE_NAME_REQUEST */
+ else if ( buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a )
+ {
+ bt_scan_result_time[entry_used][1] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_REMOTE_NAME_REQUEST (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)" NONECOLOR,
+ entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
+ (int)((bt_scan_result_time[entry_used][1]-bt_scan_start_time)/1000));
+ }
+ /* HCI_REMOTE_NAME_REQUEST_COMPLETE */
+ else if ( buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00 )
+ {
+ bt_scan_result_time[entry_used][2] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_REMOTE_NAME_REQUEST_COMPLETE (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(%s)" NONECOLOR,
+ entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
+ (int)((bt_scan_result_time[entry_used][2]-bt_scan_start_time)/1000),
+ (char*)(&buf[9]));
+ }
+ }
+ /* Duplicate, skip it */
+ else
+ {}
+ }
+ /* HCI_INQUIRY_COMPLETE */
+ else if ( buf_len == 3 && buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0x00 )
+ {
+ LOG_PER(YELLOW "[bperf] HCI_INQUIRY_COMPLETE (%dms)" NONECOLOR, ((_bperf_get_microseconds()-bt_scan_start_time)/1000));
+ }
+}
+
+static void _bperf_analysis_le_scan(const uint8_t *buf, const unsigned int buf_len)
+{
+ int i;
+ int entry_found = MAX_BPERF_LE_SCAN_ENTRY;
+ int entry_empty = MAX_BPERF_LE_SCAN_ENTRY;
+ int entry_used = MAX_BPERF_LE_SCAN_ENTRY;
+ int save_entry = 0;
+ static unsigned int le_scan_start_time;
+ static unsigned int le_scan_result_time[MAX_BPERF_LE_SCAN_ENTRY][3];
+ static uint8_t le_scan_result_address[MAX_BPERF_LE_SCAN_ENTRY][6];
+
+ /* HCI_LE_SCAN_ENABLE */
+ if ( buf_len == 5 && buf[0] == 0x0c && buf[1] == 0x20 && buf[2] == 0x02 )
+ {
+ if ( buf[3] == 1 )
+ {
+ LOG_PER(YELLOW "[bperf] HCI_LE_SCAN_ENABLE Started (Duplicate_Filter:%02x)(0ms)" NONECOLOR, buf[4]);
+ le_scan_start_time = _bperf_get_microseconds();
+ }
+ else if ( buf[3] == 0 )
+ {
+ LOG_PER(YELLOW "[bperf] HCI_LE_SCAN_ENABLE Stopped (Duplicate_Filter:%02x)(%dms)" NONECOLOR, buf[4],
+ ((_bperf_get_microseconds()-le_scan_start_time)/1000));
+ le_scan_start_time = 0;
+ for ( i = 0 ; i < MAX_BPERF_LE_SCAN_ENTRY ; i++ )
+ {
+ le_scan_result_time[i][0] = 0;
+ le_scan_result_time[i][1] = 0;
+ le_scan_result_time[i][2] = 0;
+ le_scan_result_address[i][0] = 0;
+ le_scan_result_address[i][1] = 0;
+ le_scan_result_address[i][2] = 0;
+ le_scan_result_address[i][3] = 0;
+ le_scan_result_address[i][4] = 0;
+ le_scan_result_address[i][5] = 0;
+ }
+ }
+ }
+ /* HCI_LE_SET_SCAN_PARAMETER */
+ else if ( buf_len == 10 && buf[0] == 0x0b && buf[1] == 0x20 && buf[2] == 0x07 )
+ {
+ float interval = (buf[4] + (buf[5]<<8))*0.625;
+ float window = (buf[6] + (buf[7]<<8))*0.625;
+
+ LOG_PER(YELLOW "[bperf] HCI_LE_SET_SCAN_PARAMETER scan_interval(%.2fms) scan_window(%.2fms)" NONECOLOR, interval, window);
+ }
+ /* HCI_LE_ADVERTISING_REPORT */
+ else
+ {
+ _bperf_mem_record_event(bperf_event_ble_adv, buf, buf_len);
+
+ for ( i = 0 ; i < MAX_BPERF_LE_SCAN_ENTRY ; i++ )
+ {
+ if ( le_scan_result_address[i][0] == 0 && le_scan_result_address[i][1] == 0 && le_scan_result_address[i][2] == 0 &&
+ le_scan_result_address[i][3] == 0 && le_scan_result_address[i][4] == 0 && le_scan_result_address[i][5] == 0 )
+ {
+ entry_empty = i;
+ break;
+ }
+ }
+
+ for ( i = 0 ; i < MAX_BPERF_LE_SCAN_ENTRY ; i++ )
+ {
+ if ( strncmp((char*)(&le_scan_result_address[i][0]), (char*)(&buf[6]), 6) == 0 )
+ {
+ entry_found = i;
+ break;
+ }
+ }
+
+ /* Entry found */
+ if ( entry_found != MAX_BPERF_LE_SCAN_ENTRY )
+ {
+ save_entry = 1;
+ entry_used = entry_found;
+ }
+ /* Entry not found, use empty entry */
+ else if ( entry_found == MAX_BPERF_LE_SCAN_ENTRY && entry_empty != MAX_BPERF_LE_SCAN_ENTRY )
+ {
+ save_entry = 1;
+ entry_used = entry_empty;
+ strncpy((char*)(&le_scan_result_address[entry_used][0]), (char*)(&buf[6]), 6);
+ }
+ /* Entry full */
+ else
+ {
+ save_entry = 0;
+ LOG_PER(YELLOW "[bperf] HCI_LE_ADV_REPORT Entry FULL!! (%d)" NONECOLOR, MAX_BPERF_LE_SCAN_ENTRY);
+ }
+
+ if ( save_entry )
+ {
+ /* Connectable Undirected */
+ if ( buf[4] == 0x00 && le_scan_result_time[entry_used][0] == 0x00 )
+ {
+ le_scan_result_time[entry_used][0] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_LE_ADV_REPORT (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(Connectable_Undirected)" NONECOLOR,
+ entry_used, buf[11], buf[10], buf[9], buf[8], buf[7], buf[6], (int)((le_scan_result_time[entry_used][0]-le_scan_start_time)/1000));
+ }
+ /* Scan Response */
+ else if ( buf[4] == 0x04 && le_scan_result_time[entry_used][1] == 0x00 )
+ {
+ le_scan_result_time[entry_used][1] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_LE_ADV_REPORT (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(Scan_Response)" NONECOLOR,
+ entry_used, buf[11], buf[10], buf[9], buf[8], buf[7], buf[6], (int)((le_scan_result_time[entry_used][1]-le_scan_start_time)/1000));
+ }
+ /* Non Connectable Undirected */
+ else if ( buf[4] == 0x03 && le_scan_result_time[entry_used][2] == 0x00 )
+ {
+ le_scan_result_time[entry_used][2] = _bperf_get_microseconds();
+ LOG_PER(YELLOW "[bperf] HCI_LE_ADV_REPORT (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(Non_Connectable_Undirected)" NONECOLOR,
+ entry_used, buf[11], buf[10], buf[9], buf[8], buf[7], buf[6], (int)((le_scan_result_time[entry_used][2]-le_scan_start_time)/1000));
+ }
+ /* Unknown Type */
+ else if ( buf[4] != 0x00 && buf[4] != 0x04 && buf[4] != 0x03 )
+ {
+ LOG_PER(YELLOW "[bperf] HCI_LE_ADV_REPORT (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(UNKNOWN 0x%02x)" NONECOLOR,
+ entry_used, buf[11], buf[10], buf[9], buf[8], buf[7], buf[6], (int)((_bperf_get_microseconds()-le_scan_start_time)/1000), buf[4]);
+ }
+ }
+ /* Duplicate, skip it */
+ else
+ {}
+ }
+}
+
+static void _bperf_analysis()
+{
+ char prop_value_char[PROPERTY_VALUE_MAX];
+ int prop_value_int = 0;
+ if ( property_get("persist.bluetooth.bperf.average", prop_value_char, "0") > 0 )
+ {
+ prop_value_int = atoi(prop_value_char);
+ if ( prop_value_int > 0 && prop_value_int < 100000 )
+ {
+ bperf_average_total_time ++;
+ bperf_average_accumulate = 1;
+ }
+ }
+
+ if ( bperf_event_ble_adv )
+ {
+ _bperf_analysis_ble_adv(bperf_event_ble_adv_analysis);
+ }
+
+ if ( bperf_event_a2dp_analysis )
+ {
+ _bperf_analysis_a2dp(bperf_event_a2dp_analysis);
+ }
+
+ if ( bperf_event_voice_analysis )
+ {
+ _bperf_analysis_voice(bperf_event_voice_analysis);
+ }
+
+ if ( bperf_event_rc_fw_upgrade_analysis )
+ {
+ _bperf_analysis_rc_fw_upgrade(bperf_event_rc_fw_upgrade_analysis);
+ }
+
+ if ( bperf_event_hid_analysis )
+ {
+ _bperf_analysis_hid_hogp(bperf_event_hid_analysis);
+ }
+
+ if ( bperf_event_hid_cursor_analysis )
+ {
+ _bperf_analysis_hid_hogp(bperf_event_hid_cursor_analysis);
+ }
+
+ if ( bperf_event_hogp_analysis )
+ {
+ _bperf_analysis_hid_hogp(bperf_event_hogp_analysis);
+ }
+
+ if ( bperf_event_hogp_cursor_analysis )
+ {
+ _bperf_analysis_hid_hogp(bperf_event_hogp_cursor_analysis);
+ }
+
+ if ( prop_value_int > 0 )
+ {
+ prop_value_int--;
+ snprintf(prop_value_char, 5, "%d", prop_value_int);
+ property_set("persist.bluetooth.bperf.average", prop_value_char);
+
+ if ( prop_value_int == 0 )
+ {
+ if ( bperf_average_total_time )
+ {
+ if ( event_counter_summary_ble_adv )
+ {
+ LOG_PER(YELLOW "[bperf] BLE ADV Num(average)(%ds) " LIGHT_CYAN "(%d)" NONECOLOR, bperf_average_total_time, (event_counter_summary_ble_adv/bperf_average_total_time));
+ event_counter_summary_ble_adv = 0;
+ snprintf(prop_value_char, 5, "%d", event_counter_summary_ble_adv);
+ property_set("persist.bt.adv_num", prop_value_char);
+ }
+ if ( event_len_summary_a2dp )
+ {
+ LOG_PER(YELLOW "[bperf] A2DP(average)(%ds) Throughput" LIGHT_CYAN "(%dbps)" NONECOLOR, bperf_average_total_time, (event_len_summary_a2dp<<3)/bperf_average_total_time);
+ event_len_summary_a2dp = 0;
+ snprintf(prop_value_char, 8, "%d", (event_len_summary_a2dp<<3)/bperf_average_total_time);
+ property_set("persist.bt.a2dp_avg_rate", prop_value_char);
+ }
+ if ( event_counter_summary_hid )
+ {
+ LOG_PER(YELLOW "[bperf] HID(average)(%ds) Num" LIGHT_CYAN "(%d)" YELLOW " Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_average_total_time,
+ event_counter_summary_hid/bperf_average_total_time,
+ event_counter_summary_hid_delta_time_max/1000);
+ snprintf(prop_value_char, 5, "%d", event_counter_summary_hid);
+ property_set("persist.bt.hid_num", prop_value_char);
+ event_counter_summary_hid = 0;
+ event_counter_summary_hid_delta_time_max = 0;
+ }
+ if ( event_counter_summary_hid_cursor )
+ {
+ LOG_PER(YELLOW "[bperf] HID_Cursor(average)(%ds) Num" LIGHT_CYAN "(%d)" YELLOW " Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_average_total_time,
+ event_counter_summary_hid_cursor/bperf_average_total_time,
+ event_counter_summary_hid_cursor_delta_time_max/1000);
+ snprintf(prop_value_char, 5, "%d", event_counter_summary_hid_cursor);
+ property_set("persist.bt.hid_cur_num", prop_value_char);
+ event_counter_summary_hid_cursor = 0;
+ event_counter_summary_hid_cursor_delta_time_max = 0;
+ }
+ if ( event_counter_summary_hogp )
+ {
+ LOG_PER(YELLOW "[bperf] HOGP(average)(%ds) Num" LIGHT_CYAN "(%d)" YELLOW " Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_average_total_time,
+ event_counter_summary_hogp/bperf_average_total_time,
+ event_counter_summary_hogp_delta_time_max/1000);
+ snprintf(prop_value_char, 5, "%d", event_counter_summary_hogp);
+ property_set("persist.bt.hopg_num", prop_value_char);
+ event_counter_summary_hogp = 0;
+ event_counter_summary_hogp_delta_time_max = 0;
+ }
+ if ( event_counter_summary_hogp_cursor )
+ {
+ LOG_PER(YELLOW "[bperf] HOGP_Cursor(average)(%ds) Num" LIGHT_CYAN "(%d)" YELLOW " Max_Delta_Time(%dms)" NONECOLOR,
+ bperf_average_total_time,
+ event_counter_summary_hogp_cursor/bperf_average_total_time,
+ event_counter_summary_hogp_cursor_delta_time_max/1000);
+ snprintf(prop_value_char, 5, "%d", event_counter_summary_hogp_cursor);
+ property_set("persist.bt.hopg_cur_num", prop_value_char);
+ event_counter_summary_hogp_cursor = 0;
+ event_counter_summary_hogp_cursor_delta_time_max = 0;
+ }
+ if ( event_len_summary_voice )
+ {
+ LOG_PER(YELLOW "[bperf] VOICE(average)(%ds) Voice Data Rate" LIGHT_CYAN "(%dbps)" NONECOLOR, bperf_average_total_time, (event_len_summary_voice<<3)/bperf_average_total_time);
+ snprintf(prop_value_char, 8, "%d", (event_len_summary_voice<<3)/bperf_average_total_time);
+ property_set("persist.bt.voble_avg_rate", prop_value_char);
+ event_len_summary_voice = 0;
+ }
+ if ( event_len_summary_rc_fw_upgrade )
+ {
+ LOG_PER(YELLOW "[bperf] VOICE(average)(%ds) Voice Data Rate" LIGHT_CYAN "(%dbps)" NONECOLOR, bperf_average_total_time, (event_len_summary_rc_fw_upgrade<<3)/bperf_average_total_time);
+ snprintf(prop_value_char, 5, "%d", (event_len_summary_rc_fw_upgrade<<3)/bperf_average_total_time);
+ property_set("persist.bt.rc_fw_upg_avg_rate", prop_value_char);
+ event_len_summary_rc_fw_upgrade = 0;
+ }
+ }
+
+ bperf_average_total_time = 0;
+ bperf_average_accumulate = 0;
+ }
+ }
+ /* prop_value_int == 0 */
+ else
+ {
+ property_get("persist.bluetooth.perf.average", prop_value_char, "0");
+ prop_value_int = atoi(prop_value_char);
+ if ( prop_value_int > 0 )
+ {
+ property_set("persist.bluetooth.bperf.average", prop_value_char);
+ }
+ }
+}
+
+static void *_bperf_thread_main(void *arg)
+{
+ unsigned int time_begin;
+ unsigned int time_end;
+ unsigned int time_sleep;
+ (void)arg;
+ LOG_DBG("Thread Started");
+
+ if ( !bperf_event_voice || !bperf_event_voice_analysis ||
+ !bperf_event_rc_fw_upgrade || !bperf_event_rc_fw_upgrade_analysis ||
+ !bperf_event_hid || !bperf_event_hid_analysis ||
+ !bperf_event_hid_cursor || !bperf_event_hid_cursor_analysis ||
+ !bperf_event_hogp || !bperf_event_hogp_analysis ||
+ !bperf_event_hogp_cursor || !bperf_event_hogp_cursor_analysis ||
+ !bperf_event_a2dp || !bperf_event_a2dp_analysis ||
+ !bperf_event_ble_adv || !bperf_event_ble_adv_analysis )
+ {
+ LOG_ERR("Allocate memory failed!");
+ LOG_DBG("Thread Stopped");
+ return 0;
+ }
+
+ bperf_main_thread_status = BPERF_STATE_THREAD_RUNNING;
+ while(!bperf_main_thread_should_stop)
+ {
+ time_begin = _bperf_get_microseconds();
+
+ pthread_mutex_lock(&event_data_lock);
+ _bperf_mem_copy();
+ _bperf_mem_reset();
+ pthread_mutex_unlock(&event_data_lock);
+
+ _bperf_analysis();
+ _bperf_mem_reset_analysis();
+ time_end = _bperf_get_microseconds();
+ time_sleep = 1000000-(time_end-time_begin);
+ usleep(time_sleep);
+ bperf_global_counter++;
+ }
+
+ bperf_main_thread_should_stop = 0;
+ bperf_main_thread_status = BPERF_STATE_THREAD_STOPPED;
+ LOG_DBG("Thread Stopped");
+ return 0;
+}
+
+static void _bperf_thread_start()
+{
+ if ( bperf_main_thread_status != BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop)
+ {
+ LOG_DBG("Create thread");
+ pthread_create(&bperf_thread_main, NULL, _bperf_thread_main, NULL);
+ }
+}
+
+static void _bperf_thread_stop()
+{
+ bperf_main_thread_should_stop = 1;
+}
+
+void bperf_notify_cmd(const uint8_t *buf, const unsigned int buf_len)
+{
+ if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
+ {
+ /* HCI_LE_SCAN_ENABLE */
+ if ( buf_len == 5 && buf[0] == 0x0c && buf[1] == 0x20 && buf[2] == 0x02 )
+ {
+ _bperf_analysis_le_scan(buf, buf_len);
+ }
+ /* HCI_LE_SET_SCAN_PARAMETER */
+ else if ( buf_len == 10 && buf[0] == 0x0b && buf[1] == 0x20 && buf[2] == 0x07 )
+ {
+ _bperf_analysis_le_scan(buf, buf_len);
+ }
+ /* HCI_INQUIRY */
+ else if ( buf_len == 8 && buf[0] == 0x01 && buf[1] == 0x04 && buf[2] == 0x05 )
+ {
+ _bperf_analysis_inquiry(buf, buf_len);
+ }
+ /* HCI_REMOTE_NAME_REQUEST */
+ else if ( buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a )
+ {
+ _bperf_analysis_inquiry(buf, buf_len);
+ }
+ }
+}
+
+void bperf_notify_event(const uint8_t *buf, const unsigned int buf_len)
+{
+ if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
+ {
+ /* HCI_LE_ADVERTISING_REPORT */
+ if ( (buf_len > 12) && buf[0] == 0x3e && buf[2] == 0x02 && buf[3] == 0x01 )
+ {
+ _bperf_analysis_le_scan(buf, buf_len);
+ }
+ /* HCI_INQUIRY_COMPLETE */
+ else if ( buf_len == 3 && buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0x00 )
+ {
+ _bperf_analysis_inquiry(buf, buf_len);
+ }
+ /* HCI_REMOTE_NAME_REQUEST_COMPLETE */
+ else if ( buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00 )
+ {
+ _bperf_analysis_inquiry(buf, buf_len);
+ }
+ /* HCI_EXTEND_INQUIRY_RESULT */
+ else if ( buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01 )
+ {
+ _bperf_analysis_inquiry(buf, buf_len);
+ }
+ }
+}
+
+void bperf_notify_data(const uint8_t *buf, const unsigned int buf_len)
+{
+ if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
+ {
+ /* HT RC Voice Search (2541) */
+ if ( (buf_len == 12 || buf_len == 31) &&
+ (buf[2] == 0x08 || buf[2] == 0x1b) && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x35 && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 0;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* HT RC Voice Search (2640) */
+ else if ( buf_len == 31 && buf[2] == 0x1b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 0;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* HT RC Voice Search (2640)(BLE Data Length Extension) */
+ else if ( buf_len == 111 && buf[2] == 0x6b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 0;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* Airoha Voice Search */
+ else if ( buf_len == 31 && buf[2] == 0x1b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x29 && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 0;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* Nordic Voice Search, Turnkey */
+ else if ( buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x1d && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 1;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* Nordic Voice Search, Huitong */
+ else if ( buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x23 && buf[10] == 0x00 )
+ {
+ bperf_global_voble_codec = 1;
+ _bperf_mem_record_event(bperf_event_voice, buf, buf_len);
+ }
+ /* HT RC Button */
+ else if ( buf_len == 12 && buf[2] == 0x08 && buf[3] == 0x00 && buf[4] == 0x04 && buf[5] == 0x00 && buf[8] == 0x1b )
+ {
+ _bperf_mem_record_event(bperf_event_hogp, buf, buf_len);
+ }
+ /* HT RC Button */
+ else if ( buf_len == 13 && buf[2] == 0x09 && buf[3] == 0x00 && buf[4] == 0x05 && buf[5] == 0x00 && buf[8] == 0x1b )
+ {
+ _bperf_mem_record_event(bperf_event_hogp, buf, buf_len);
+ }
+ /* HID : SNOW RC */
+ else if ( buf_len == 13 && buf[2] == 0x09 && buf[3] == 0x00 && buf[4] == 0x05 && buf[5] == 0x00 && buf[8] == 0xa1 )
+ {
+ _bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
+ }
+ /* HID : Logitech Keyboard */
+ else if ( buf_len == 18 && buf[2] == 0x0e && buf[3] == 0x00 && buf[4] == 0x0a && buf[5] == 0x00 && buf[8] == 0xa1 )
+ {
+ _bperf_mem_record_event(bperf_event_hid, buf, buf_len);
+ }
+ /* HID_Curosr : Microsoft Sculpt Comfort Mouse */
+ else if ( buf_len == 19 && buf[2] == 0x0f && buf[3] == 0x00 && buf[4] == 0x0b && buf[5] == 0x00 && buf[9] == 0x1a )
+ {
+ _bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
+ }
+ /* HID_Cursor : Logitech M557 */
+ else if ( buf_len == 16 && buf[2] == 0x0c && buf[3] == 0x00 && buf[4] == 0x08 && buf[5] == 0x00 && buf[8] == 0xa1 )
+ {
+ _bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
+ }
+ /* HID_Cursor : Logitech M558 */
+ else if ( buf_len == 17 && buf[2] == 0x0d && buf[3] == 0x00 && buf[4] == 0x09 && buf[5] == 0x00 && buf[8] == 0xa1 )
+ {
+ _bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
+ }
+ /* HOGP_Cursor : Microsoft Designer BLE Mouse*/
+ else if ( buf_len == 20 && buf[2] == 0x10 && buf[3] == 0x00 && buf[4] == 0x0c && buf[5] == 0x00 && buf[8] == 0x1b )
+ {
+ _bperf_mem_record_event(bperf_event_hogp_cursor, buf, buf_len);
+ }
+ /* HOGP_Cursor : Elecom BLE Mouse */
+ else if ( buf_len == 17 && buf[2] == 0x0d && buf[3] == 0x00 && buf[4] == 0x09 && buf[5] == 0x00 && buf[8] == 0x1b )
+ {
+ _bperf_mem_record_event(bperf_event_hogp_cursor, buf, buf_len);
+ }
+ /* A2DP Sink */
+ else if ( buf[8] == 0x80 && buf[9] == 0x60 )
+ {
+ _bperf_mem_record_event(bperf_event_a2dp, buf, buf_len);
+ if ( buf[20] == 0x00 ) /* SCMS-T */
+ bperf_global_bitpool = buf[24];
+ else
+ bperf_global_bitpool = buf[23];
+ }
+ /* A2DP Src */
+ else if ( buf_len == 587 && buf[8] == 0x80 && buf[9] == 0x60 && buf[20] == 0x00 )
+ {
+ _bperf_mem_record_event(bperf_event_a2dp, buf, buf_len);
+ bperf_global_bitpool = buf[24];
+ }
+ /* HT RC FW Upgrade */
+ else if ( buf_len == 29 && buf[2] == 0x19 && buf[3] == 0x00 && buf[4] == 0x15 && buf[5] == 0x00 && buf[9] == 0x48 && buf[10] == 0x00 )
+ {
+ _bperf_mem_record_event(bperf_event_rc_fw_upgrade, buf, buf_len);
+ }
+#if 0
+ /* HID : DS4 */
+ else if ( buf_len == 19 && buf[2] == 0x0f && buf[3] == 0x00 && buf[4] == 0x0b && buf[5] == 0x00 && buf[8] == 0xa1 )
+ {
+ _bperf_mem_record_event(bperf_event_hid, buf, buf_len);
+ }
+#endif
+ }
+}
+
+void bperf_init()
+{
+ LOG_PER(YELLOW "[bperf] Version : %s" NONECOLOR, BPERF_LIBRARY_VERSION);
+ bperf_global_counter = 0;
+ pthread_mutex_init(&event_data_lock, NULL);
+ _bperf_mem_init();
+ _bperf_thread_start();
+ return;
+}
+
+void bperf_uninit()
+{
+ _bperf_thread_stop();
+ _bperf_mem_free();
+ pthread_mutex_destroy(&event_data_lock);
+ return;
+}
diff --git a/mtkbt/code/libdriver/bperf_util.h b/mtkbt/code/libdriver/bperf_util.h
new file mode 100755
index 0000000..ea706c0
--- a/dev/null
+++ b/mtkbt/code/libdriver/bperf_util.h
@@ -0,0 +1,85 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __BT_BPERF_IF_H__
+#define __BT_BPERF_IF_H__
+
+#include "os_dep.h"
+
+#define NONECOLOR "\033[m"
+#define GRAY "\033[1;30m"
+#define RED "\033[0;31m"
+#define LIGHT_RED "\033[1;31m"
+#define GREEN "\033[0;32m"
+#define LIGHT_GREEN "\033[1;32m"
+#define BROWN "\033[0;33m"
+#define YELLOW "\033[1;33m"
+#define BLUE "\033[0;34m"
+#define LIGHT_BLUE "\033[1;34m"
+#define PURPLE "\033[0;35m"
+#define LIGHT_PURPLE "\033[1;35m"
+#define CYAN "\033[0;36m"
+#define LIGHT_CYAN "\033[1;36m"
+#define LIGHT_WHITE "\033[1;37m"
+
+enum{
+ BPERF_STATE_UNKNOWN,
+ BPERF_STATE_THREAD_RUNNING,
+ BPERF_STATE_THREAD_STOPPED
+};
+
+enum{
+ BPERF_DATA_TYPE_HOGP,
+ BPERF_DATA_TYPE_HID,
+ BPERF_DATA_TYPE_A2DP,
+ BPERF_DATA_TYPE_VOICE,
+ BPERF_DATA_TYPE_UNKNOWN
+};
+
+struct bperf_event {
+ unsigned short id;
+ unsigned int time;
+ unsigned int buf_len;
+ unsigned int extra_info;
+};
+
+void bperf_notify_cmd(const uint8_t *buf, const unsigned int buf_len);
+void bperf_notify_event(const uint8_t *buf, const unsigned int buf_len);
+void bperf_notify_data(const uint8_t *buf, const unsigned int buf_len);
+void bperf_init();
+void bperf_uninit();
+#endif
diff --git a/mtkbt/code/libdriver/bt_drv.c b/mtkbt/code/libdriver/bt_drv.c
new file mode 100755
index 0000000..e0abcdf
--- a/dev/null
+++ b/mtkbt/code/libdriver/bt_drv.c
@@ -0,0 +1,425 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <fcntl.h>
+#if defined(MTK_LINUX)
+#else
+#include <cutils/sockets.h>
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+#include "bperf_util.h"
+#endif
+#endif
+#include "bt_vendor_lib.h"
+#include "bt_mtk.h"
+
+#define VENDOR_LIBRARY_VERSION "700.0.17122701"
+
+//=============== V A R I A B L E S =======================
+static unsigned int remaining_length = 0; // the remaing data length
+static uint8_t data_buffer[1024]; // store the hci event
+static uint8_t* remaining_data_buffer = NULL; // pointer to current data position
+static uint8_t* current_pos = NULL;
+static void whole_chip_reset(void);
+static int fw_dump_started = 0;
+static int fw_dump_fp = -1;
+static char fw_dump_log_path[64]={0};
+
+#ifndef INVALID_FD
+#define INVALID_FD (-1)
+#endif
+
+// copy from hci_hal.h
+typedef enum {
+ DATA_TYPE_COMMAND = 1,
+ DATA_TYPE_ACL = 2,
+ DATA_TYPE_SCO = 3,
+ DATA_TYPE_EVENT = 4
+} serial_data_type_t;
+
+static void mtk_bt_notify_incoming_msg(void* param);
+
+//=============== P R I V A T E A P I =======================
+void do_signal_kill(int signum)
+{
+ if (signum == SIGIO) {
+ LOG_DBG("BT VENDOR DRIVER GET KILL SIGNAL\n");
+ whole_chip_reset();
+ } else {
+ LOG_DBG("BT VENDOR DRIVER GET UNKNOWN SIGNAL (%d)\n", signum);
+ }
+}
+
+static void _mtk_bt_handle_voice_search_data(const uint8_t *buf, const unsigned int buf_len)
+{
+#if defined(MTK_LINUX)
+#else
+ if ( (buf_len == 12 || buf_len == 31) &&
+ (buf[2] == 0x08 || buf[2] == 0x1b) && buf[3] == 0x00 &&
+ buf[8] == 0x1b && buf[9] == 0x35 && buf[10] == 0x00 )
+ {
+ int i;
+ int ret;
+
+ // GATT data pattern for key code (len = 4):
+ // Key Press : 4b 00 00 0x
+ // Key Release : 4b 00 00 00
+ // Voice key press : 4b 00 00 07
+ // Voice key release : 4b 00 00 00
+ // GATT data pattern for voice data :
+ // Frist : 35 00 04
+ // Second : 35 00 xx xx xx (total 22Byte)
+ static int g_connection_created = FALSE;
+ static int g_voice_sockfd = -1;
+ static struct sockaddr_un g_voice_sockaddr;
+ static socklen_t g_voice_sockaddr_len;
+ static const char* const serverAddr="voice.source.address";
+ int err;
+#ifdef BT_DRV_PRINT_DBG_LOG
+ if ( buf_len == 12 )
+ LOG_DBG("hci_event(%d):%02X\n", buf_len, buf[11]);
+ else
+ LOG_DBG("hci_event(%d):%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ buf_len,
+ buf[11],
+ buf[12],
+ buf[13],
+ buf[14],
+ buf[15],
+ buf[16],
+ buf[17],
+ buf[18],
+ buf[19],
+ buf[20],
+ buf[21],
+ buf[22],
+ buf[23],
+ buf[24],
+ buf[25],
+ buf[26],
+ buf[27],
+ buf[28],
+ buf[29],
+ buf[30]);
+#endif
+ if ( buf_len == 12 && buf[11] == 0x04 && g_connection_created == TRUE && g_voice_sockfd )
+ {
+ LOG_DBG("close existing socket\n");
+ close(g_voice_sockfd);
+ g_connection_created = FALSE;
+ }
+
+ if ( g_connection_created == FALSE )
+ {
+ extern int socket_make_sockaddr_un(const char *name, int ns_id, struct sockaddr_un *p_addr, socklen_t *alen);
+ err = socket_make_sockaddr_un(serverAddr,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ &g_voice_sockaddr, &g_voice_sockaddr_len);
+ if ( err )
+ {
+ LOG_ERR("Create socket failed.");
+ return;
+ }
+
+ g_voice_sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (g_voice_sockfd < 0)
+ {
+ LOG_ERR("Create server socket failed.");
+ return;
+ }
+ g_connection_created = TRUE;
+ }
+
+ if ( g_voice_sockfd < 0 )
+ {
+ LOG_ERR("Create server socket failed.");
+ return;
+ }
+
+ err = sendto(g_voice_sockfd, buf+11, buf_len-11 , MSG_DONTWAIT , (struct sockaddr*) &g_voice_sockaddr, g_voice_sockaddr_len) ;
+ if ( err < 0 )
+ {
+ static int counter=0;
+ counter++;
+ if ( counter == 100 )
+ {
+ LOG_ERR("send FAILED (%s:%d) x 100\n", strerror(errno), errno);
+ counter = 0;
+ }
+ }
+ }
+#endif
+}
+
+//=============== I N T E R F A C E S =======================
+static int mtk_bt_init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr)
+{
+ LOG_DBG("%s : VENDOR LIBRARY VERSION =%s\n", __FUNCTION__, VENDOR_LIBRARY_VERSION);
+ (void)local_bdaddr;
+ LOG_TRC();
+ set_callbacks(p_cb);
+ remaining_data_buffer = data_buffer;
+ return 0;
+}
+
+static int mtk_bt_op(bt_vendor_opcode_t opcode, void *param)
+{
+ int ret = 0;
+ int oflag;
+ int bt_fd;
+
+ switch(opcode)
+ {
+ case BT_VND_OP_POWER_CTRL:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_POWER_CTRL %d\n", *((int*)param));
+ /* DO NOTHING on combo chip */
+ break;
+
+ case BT_VND_OP_USERIAL_OPEN:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_USERIAL_OPEN\n");
+ ((int*)param)[0] = init_uart();
+ bt_fd = ((int *)param)[0];
+ if (bt_fd >= 0) {
+ fcntl(bt_fd, F_SETOWN, getpid());
+ oflag = fcntl(bt_fd, F_GETFL);
+ fcntl(bt_fd, F_SETFL, oflag | FASYNC);
+ signal(SIGIO, do_signal_kill);
+ LOG_DBG("[Larson Jiang]BT VENDOR start wait signal from kernel!");
+ }
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+ bperf_init();
+#endif
+ ret = 1; // CMD/EVT/ACL-In/ACL-Out via the same fd
+ break;
+
+ case BT_VND_OP_USERIAL_CLOSE:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_USERIAL_CLOSE\n");
+ close_uart();
+
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+ bperf_uninit();
+#endif
+ break;
+
+ case BT_VND_OP_FW_CFG:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_FW_CFG\n");
+ vendor_fw_cfg();
+ break;
+
+ case BT_VND_OP_SCO_CFG:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_SCO_CFG\n");
+ break;
+
+ case BT_VND_OP_GET_LPM_IDLE_TIMEOUT:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_GET_LPM_IDLE_TIMEOUT\n");
+ *((uint32_t*)param) = 5000; //ms
+ break;
+
+ case BT_VND_OP_LPM_SET_MODE:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_LPM_SET_MODE %d\n", *((uint8_t*)param));
+ vendor_op_lmp_set_mode();
+ break;
+
+ case BT_VND_OP_LPM_WAKE_SET_STATE:
+ break;
+
+ case BT_VND_OP_EPILOG:
+ LOG_DBG("[Larson Jiang]BT_VND_OP_EPILOG\n");
+ ret = mtk_prepare_off();
+ break;
+#if (defined(MTK_VENDOR_OPCODE) && (MTK_VENDOR_OPCODE == TRUE))
+ case BT_VND_OP_HANDLE_VENDOR_MESSAGE:
+ mtk_bt_notify_incoming_msg(param);
+ break;
+#endif
+ default:
+ LOG_DBG("[Larson Jiang]Unknown operation %d\n", opcode);
+ break;
+ }
+
+ return ret;
+}
+
+static void mtk_bt_cleanup()
+{
+ fw_dump_started = 0;
+ if ( fw_dump_fp >0)
+ {
+ LOG_DBG("Close fw dump file : %s", fw_dump_log_path);
+ close(fw_dump_fp);
+ }
+
+ LOG_TRC();
+ remaining_data_buffer = NULL;
+ clean_resource();
+ clean_callbacks();
+ return;
+}
+
+static void mtk_bt_handle_cmd(const uint8_t *buf, const unsigned int buf_len)
+{
+ (void)buf;
+ (void)buf_len;
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+ bperf_notify_cmd(buf, buf_len);
+#endif
+ return;
+}
+
+static void mtk_bt_handle_acl(const uint8_t *buf, const unsigned int buf_len)
+{
+ (void)buf;
+ (void)buf_len;
+#if defined(MTK_LINUX)
+#else
+ /* HT RC Voice Search (2541) */
+ if ( (buf_len == 12 || buf_len == 31) &&
+ (buf[2] == 0x08 || buf[2] == 0x1b) && buf[3] == 0x00 &&
+ buf[8] == 0x1b && buf[9] == 0x35 && buf[10] == 0x00 )
+ {
+ _mtk_bt_handle_voice_search_data(buf, buf_len);
+ }
+#endif
+
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+ bperf_notify_data(buf, buf_len);
+#endif
+ return;
+}
+
+static void mtk_bt_handle_event(const uint8_t *buf, const unsigned int buf_len)
+{
+ (void)buf;
+ (void)buf_len;
+#if defined(MTK_BPERF_ENABLE) && (MTK_BPERF_ENABLE == TRUE)
+ bperf_notify_event(buf, buf_len);
+#endif
+ return;
+}
+
+#if (defined(MTK_VENDOR_OPCODE) && (MTK_VENDOR_OPCODE == TRUE))
+static void mtk_bt_notify_incoming_msg(void* param)
+{
+ bt_vendor_op_handle_vendor_msg_t* incoming_msg = (bt_vendor_op_handle_vendor_msg_t*)param;
+ const uint8_t type = incoming_msg->type;
+ const uint16_t buf_len = incoming_msg->len;
+ const uint8_t* buf = incoming_msg->data;
+ unsigned int length = buf_len;
+
+ uint8_t* buffer = (uint8_t*)buf;
+ BT_HDR_T hdr = 0x00;
+ unsigned int size = 0;
+
+#ifdef BT_DRV_PRINT_DBG_LOG
+ LOG_DBG("%s=(%d=%s)=========(len=%d) %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ __FUNCTION__,
+ type,
+ type==DATA_TYPE_COMMAND?"CMD":
+ type==DATA_TYPE_ACL?"ACL":
+ type==DATA_TYPE_SCO?"SCO":
+ type==DATA_TYPE_EVENT?"EVENT":"UNKNOWN",
+ buf_len,
+ buf[0],
+ buf[1],
+ buf[2],
+ buf[3],
+ buf[4],
+ buf[5],
+ buf[6],
+ buf[7]);
+
+#endif
+ unsigned char reset_event[] = {0x04, 0xFF, 0x04, 0x00, 0x01, 0xFF, 0xFF};
+
+ switch (type)
+ {
+ case DATA_TYPE_COMMAND:
+ mtk_bt_handle_cmd(buf, buf_len);
+ break;
+
+ case DATA_TYPE_ACL:
+ mtk_bt_handle_acl(buf, buf_len);
+ break;
+
+ case DATA_TYPE_EVENT:
+ // handle reset condition
+ if ( type == DATA_TYPE_EVENT && buf_len == 6 &&
+ buf[0] == 0xFF && buf[1] == 0x04 && buf[2] == 0x00 &&
+ buf[3] == 0x01 && buf[4] == 0xFF && buf[5] == 0xFF )
+ {
+ LOG_DBG("%s : kill self to trigger reset", __FUNCTION__);
+ whole_chip_reset();
+ }
+ else
+ {
+ mtk_bt_handle_event(buf, buf_len);
+ }
+ break;
+
+ case DATA_TYPE_SCO:
+ default:
+ LOG_ERR("Not handled event type %d !", type);
+ break;
+ }
+ return;
+}
+#endif
+
+#if defined(MTK_LINUX)
+EXPORT_SYMBOL const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+#else
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+#endif
+ sizeof(bt_vendor_interface_t),
+ mtk_bt_init,
+ mtk_bt_op,
+ mtk_bt_cleanup,
+};
+
+static void whole_chip_reset(void)
+{
+ LOG_ERR("Restarting BT process");
+ usleep(10000); /* 10 milliseconds */
+ /* Killing the process to force a restart as part of fault tolerance */
+ kill(getpid(), SIGKILL);
+}
diff --git a/mtkbt/code/libdriver/bt_drv.h b/mtkbt/code/libdriver/bt_drv.h
new file mode 100755
index 0000000..024bec4
--- a/dev/null
+++ b/mtkbt/code/libdriver/bt_drv.h
@@ -0,0 +1,102 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2010. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __BT_DRV_IF_H__
+#define __BT_DRV_IF_H__
+
+typedef enum {
+ BT_COLD_OP_GET_ADDR = 0,
+ BT_HOT_OP_SET_FWASSERT,
+ BT_AUDIO_OP_GET_CONFIG
+} BT_OP;
+
+/* Audio config related defination */
+typedef enum {
+ PCM = 0, // PCM 4 pins interface
+ I2S, // I2S interface
+ MERGE_INTERFACE, // PCM & I2S merge interface
+ CVSD_REMOVAL // SOC consys
+} AUDIO_IF;
+
+typedef enum {
+ SYNC_8K = 0,
+ SYNC_16K
+} SYNC_CLK; // DAIBT sample rate
+
+typedef enum {
+ SHORT_FRAME = 0,
+ LONG_FRAME
+} SYNC_FORMAT; // DAIBT sync
+
+typedef struct {
+ AUDIO_IF hw_if;
+ SYNC_CLK sample_rate;
+ SYNC_FORMAT sync_format;
+ unsigned int bit_len; // bit-length of sync frame in long frame sync
+} AUDIO_CONFIG;
+
+/* Information carring for all OPs (In/Out) */
+typedef union {
+ unsigned char addr[7];
+ struct {
+ int fd;
+ int reason;
+ } assert;
+ AUDIO_CONFIG audio_conf;
+} BT_INFO;
+
+typedef struct {
+ BT_OP op;
+ BT_INFO param;
+} BT_REQ;
+
+typedef struct {
+ unsigned char status;
+ BT_INFO param;
+} BT_RESULT;
+
+typedef void (*rx_callback)();
+
+
+
+int mtk_bt_enable(int flag, rx_callback func_cb);
+int mtk_bt_disable(int bt_fd);
+int mtk_bt_write(int bt_fd, unsigned char *buffer, unsigned short length);
+int mtk_bt_read(int bt_fd, unsigned char *buffer, unsigned short length);
+void mtk_bt_op(BT_REQ req, BT_RESULT *result);
+
+#endif \ No newline at end of file
diff --git a/mtkbt/code/libdriver/bt_mtk.h b/mtkbt/code/libdriver/bt_mtk.h
new file mode 100755
index 0000000..c212374
--- a/dev/null
+++ b/mtkbt/code/libdriver/bt_mtk.h
@@ -0,0 +1,105 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef _BT_MTK_H
+#define _BT_MTK_H
+
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_lib.h"
+#include "os_dep.h"
+
+
+#define HCI_CMD_MAX_SIZE 251
+
+
+/*********** Structure Definitions ***********/
+
+typedef enum {
+ CMD_SUCCESS,
+ CMD_FAIL,
+ CMD_PENDING,
+} HCI_CMD_STATUS_T;
+
+typedef BOOL (*HCI_CMD_FUNC_T) (HC_BT_HDR *);
+typedef struct {
+ HCI_CMD_FUNC_T command_func;
+} HCI_SEQ_T;
+
+typedef INT32 (*SETUP_UART_PARAM_T)(UINT32 u4Baud, UINT32 u4FlowControl);
+
+typedef struct {
+ UINT32 chip_id;
+ UINT32 bt_baud;
+ UINT32 host_baud;
+ UINT32 flow_ctrl;
+ SETUP_UART_PARAM_T host_uart_cback;
+ PUCHAR patch_ext_data;
+ UINT32 patch_ext_len;
+ UINT32 patch_ext_offset;
+ PUCHAR patch_data;
+ UINT32 patch_len;
+ UINT32 patch_offset;
+ HCI_SEQ_T *cur_script;
+} BT_INIT_VAR_T;
+
+/* Thread control block for Controller initialize */
+typedef struct {
+ pthread_t worker_thread;
+ pthread_mutex_t mutex;
+ pthread_mutexattr_t attr;
+ pthread_cond_t cond;
+ BOOL worker_thread_running;
+} BT_INIT_CB_T;
+
+typedef enum {
+ BT_HCI_CMD = 0x01,
+ BT_ACL,
+ BT_SCO,
+ BT_HCI_EVENT
+} BT_HDR_T;
+
+/*********** Function Declaration ***********/
+void set_callbacks(const bt_vendor_callbacks_t* p_cb);
+void clean_callbacks(void);
+int init_uart(void);
+void close_uart(void);
+int mtk_prepare_off(void);
+void clean_resource(void);
+void vendor_fw_cfg(void);
+void vendor_op_lmp_set_mode(void);
+
+#endif
diff --git a/mtkbt/code/libdriver/mtk.c b/mtkbt/code/libdriver/mtk.c
new file mode 100755
index 0000000..0b08c76
--- a/dev/null
+++ b/mtkbt/code/libdriver/mtk.c
@@ -0,0 +1,227 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#if defined(MTK_LINUX)
+//#include "osi/include/properties.h"
+#else
+#include <cutils/properties.h>
+#endif
+#include "bt_mtk.h"
+
+/**************************************************************************
+ * G L O B A L V A R I A B L E S *
+***************************************************************************/
+
+bt_vendor_callbacks_t *bt_vnd_cbacks = NULL;
+static int bt_fd = -1;
+
+/**************************************************************************
+ * F U N C T I O N D E C L A R A T I O N S *
+***************************************************************************/
+
+extern VOID BT_Cleanup(VOID);
+
+/**************************************************************************
+ * F U N C T I O N S *
+***************************************************************************/
+
+static BOOL is_memzero(unsigned char *buf, int size)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ if (*(buf+i) != 0) return FALSE;
+ }
+ return TRUE;
+}
+
+/* Register callback functions to libbt-hci.so */
+void set_callbacks(const bt_vendor_callbacks_t *p_cb)
+{
+ bt_vnd_cbacks = (bt_vendor_callbacks_t*)p_cb;
+}
+
+/* Cleanup callback functions previously registered */
+void clean_callbacks(void)
+{
+ bt_vnd_cbacks = NULL;
+}
+
+#if 0
+/* Initialize UART port */
+int init_uart(void)
+{
+ int retry = 50;
+ LOG_TRC();
+
+ while(1) {
+ bt_fd = open("/dev/stpbt", O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
+ if (bt_fd < 0 && bt_fd==(-EAGAIN)) {
+ LOG_WAN("Can't open serial port, Retry\n");
+ usleep(200000);/*200ms*/
+ if (retry <= 0)
+ break;
+
+ retry--;
+ }
+ else
+ break;
+ }
+
+
+ if (bt_fd < 0) {
+ LOG_ERR("Can't open serial port stpbt\n");
+ return -1;
+ }
+
+ return bt_fd;
+}
+
+/* Close UART port previously opened */
+void close_uart(void)
+{
+ if (bt_fd >= 0) close(bt_fd);
+ bt_fd = -1;
+}
+#else
+extern int load_mtkbt(void);
+extern void mtkbt_unload(void);
+int init_uart(void)
+{
+ int retry_cnt = 1;
+ LOG_TRC();
+ /*insmod bt driver*/
+ if(0 == load_mtkbt())
+ {
+ while(retry_cnt < 1000)
+ {
+ usleep(200000);//20ms
+ ALOGD("%s: attemping(%d) to open stpbt...\n", __FUNCTION__, retry_cnt);
+ bt_fd = open("/dev/stpbt", O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if(bt_fd > 0)
+ break;
+
+ retry_cnt ++;
+ }
+
+ if(bt_fd > 0)
+ {
+ ALOGD("%s: open stpbt succeesed[%d]...\n", __FUNCTION__, bt_fd);
+ return bt_fd;
+ }
+ else
+ {
+ LOG_ERR("%s: Can't open serial port: %s.\n", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ }
+ else
+ {
+ LOG_ERR("insmod bt driver error");
+ return -1;
+ }
+}
+#endif
+
+void close_uart(void)
+{
+ if (bt_fd >= 0) close(bt_fd);
+ bt_fd = -1;
+ mtkbt_unload();
+}
+
+/* Vendor FW Config, do nothing and then callback */
+void vendor_fw_cfg(void)
+{
+ if (bt_vnd_cbacks) {
+ bt_vnd_cbacks->fwcfg_cb(BT_VND_OP_RESULT_SUCCESS);
+ }
+}
+
+void vendor_op_lmp_set_mode(void)
+{
+ if (bt_vnd_cbacks) {
+ bt_vnd_cbacks->lpm_cb(BT_VND_OP_RESULT_SUCCESS);
+ }
+}
+
+/* MTK specific deinitialize process */
+int mtk_prepare_off(void)
+{
+ /*
+ * On KK, BlueDroid adds BT_VND_OP_EPILOG procedure when BT disable:
+ * - 1. BT_VND_OP_EPILOG;
+ * - 2. In vendor epilog_cb, send EXIT event to bt_hc_worker_thread;
+ * - 3. Wait for bt_hc_worker_thread exit;
+ * - 4. userial close;
+ * - 5. vendor cleanup;
+ * - 6. Set power off.
+ * On L, the disable flow is modified as below:
+ * - 1. userial Rx thread exit;
+ * - 2. BT_VND_OP_EPILOG;
+ * - 3. Write reactor->event_fd to trigger bt_hc_worker_thread exit
+ * (not wait to vendor epilog_cb and do nothing in epilog_cb);
+ * - 4. Wait for bt_hc_worker_thread exit;
+ * - 5. userial close;
+ * - 6. Set power off;
+ * - 7. vendor cleanup.
+ *
+ * It seems BlueDroid does not expect Tx/Rx interaction with chip during
+ * BT_VND_OP_EPILOG procedure, and also does not need to do it in a new
+ * thread context (NE may occur in __pthread_start if bt_hc_worker_thread
+ * has already exited).
+ * So BT_VND_OP_EPILOG procedure may be not for chip deinitialization,
+ * do nothing, just notify success.
+ *
+ * [FIXME!!]How to do if chip deinit is needed?
+ */
+ //return (BT_DeinitDevice() == TRUE ? 0 : -1);
+ if (bt_vnd_cbacks) {
+ bt_vnd_cbacks->epilog_cb(BT_VND_OP_RESULT_SUCCESS);
+ }
+ return 0;
+}
+
+/* Cleanup driver resources, e.g thread exit */
+void clean_resource(void)
+{
+ BT_Cleanup();
+}
diff --git a/mtkbt/code/libdriver/os_dep.h b/mtkbt/code/libdriver/os_dep.h
new file mode 100755
index 0000000..0382b21
--- a/dev/null
+++ b/mtkbt/code/libdriver/os_dep.h
@@ -0,0 +1,115 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef _OS_DEP_H
+#define _OS_DEP_H
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef BOOL
+#define BOOL bool
+#endif
+
+typedef unsigned char BYTE;
+typedef unsigned char UCHAR;
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned int UINT32;
+typedef unsigned long long UINT64;
+typedef unsigned char* PBYTE;
+typedef unsigned char* PUCHAR;
+typedef char INT8;
+typedef short INT16;
+typedef int INT32;
+typedef long long INT64;
+typedef void VOID;
+typedef void* PVOID;
+
+
+/* LOG_TAG must be defined before log.h */
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "[BT]"
+
+#if defined(MTK_LINUX)
+
+#if defined(MTK_COMMON) && (MTK_COMMON == TRUE)
+#define LOGWRAPPER(tag, fmt, args...) printf("%s: " fmt "\n", tag, ## args)
+#else
+#define LOGWRAPPER(tag, fmt, args...) fprintf(stderr, "%s: " fmt "\n", tag, ## args)
+#endif
+
+#define BT_DRIVER_DEBUG 1
+
+#define LOG_ERR(...) LOGWRAPPER(LOG_TAG,__VA_ARGS__)
+#define LOG_WAN(...) LOGWRAPPER(LOG_TAG,__VA_ARGS__)
+#if BT_DRIVER_DEBUG
+#define LOG_DBG(...) LOGWRAPPER(LOG_TAG,__VA_ARGS__)
+#define LOG_TRC(f) ((void)0)
+#define LOG_PER(...) LOGWRAPPER(LOG_TAG,__VA_ARGS__)
+#else
+#define LOG_DBG(...) ((void)0)
+#define LOG_TRC(f) ((void)0)
+#define LOG_PER(f, ...) ((void)0)
+#endif
+
+#else /* MTK_LINUX */
+#include <cutils/log.h>
+#define BT_DRIVER_DEBUG 1
+#define LOG_ERR(f, ...) ALOGE("%s: " f, __FUNCTION__, ##__VA_ARGS__)
+#define LOG_WAN(f, ...) ALOGE("%s: " f, __FUNCTION__, ##__VA_ARGS__)
+#if BT_DRIVER_DEBUG
+#define LOG_DBG(f, ...) ALOGE("%s: " f, __FUNCTION__, ##__VA_ARGS__)
+#define LOG_TRC(f) ALOGE("%s #%d", __FUNCTION__, __LINE__)
+#define LOG_PER(f, ...) ALOGE("" f, ##__VA_ARGS__)
+#else
+#define LOG_DBG(...) ((void)0)
+#define LOG_TRC(f) ((void)0)
+#define LOG_PER(f, ...) ((void)0)
+#endif
+#endif /* MTK_LINUX */
+#endif
diff --git a/mtkbt/code/libdriver/platform.c b/mtkbt/code/libdriver/platform.c
new file mode 100755
index 0000000..89d8f8c
--- a/dev/null
+++ b/mtkbt/code/libdriver/platform.c
@@ -0,0 +1,295 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#define LOG_TAG "bt-platform"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <cutils/properties.h>
+#include <errno.h>
+#include <asm/ioctl.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+#include <string.h>
+
+#define SDIO_POWER_UP _IO('m',3)
+#define SDIO_POWER_DOWN _IO('m',4)
+
+#define BT_POWER_OFF 0
+#define BT_POWER_ON 1
+
+#define RFKILL_DEVICE 1
+#define DEV_NODE_DEVICE 2
+
+#ifndef PROPERTY_VALUE_MAX
+#define PROPERTY_VALUE_MAX 92
+#endif
+
+#define CLEAR_ERROR_INFO (errno = 0)
+
+static const char DRIVER_PROP_NAME[] = "bluetooth.btdriver.mtk";
+
+
+const char *rfkill_board_list[] = {
+ "24",
+ NULL
+};
+const char *devNode_board_List[] = {
+ "19",
+ NULL
+};
+
+int getBoardCapabilities(){
+
+ int index_ptr = 0;
+ char prpt[PROPERTY_VALUE_MAX];
+ memset(prpt, '\0', PROPERTY_VALUE_MAX);
+ property_get("ro.build.version.sdk", prpt, NULL);
+
+ do{
+ if(0 == strcmp(devNode_board_List[index_ptr], prpt))
+ {
+ ALOGD("Matched a dev_node device: %s", prpt);
+ return DEV_NODE_DEVICE;
+ }
+ index_ptr ++;
+ }while(devNode_board_List[index_ptr] != NULL);
+
+
+ ALOGD("We're goting to access rfkill to power on this device(sdk: %s) by default...", prpt);
+ return RFKILL_DEVICE;
+}
+
+static int is_rfkill_disabled(void)
+{
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.rfkilldisabled", value, "0");
+
+ if (strcmp(value, "1") == 0) {
+ ALOGE("is_rfkill_disabled ? [%s]", value);
+ return -1;
+ }
+ return 0;
+}
+
+static int init_rfkill(char **rfkill_state_path)
+{
+ char path[64];
+ char buf[16];
+ int fd, sz, id;
+
+ if (is_rfkill_disabled())
+ {
+ ALOGE("The rfkill module has been disabled!");
+ return -1;
+ }
+
+ for (id = 0; ; id++)
+ {
+ snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ {
+ ALOGE("init_rfkill : open(%s) failed: %s (%d)\n", \
+ path, strerror(errno), errno);
+ errno = 0;
+ return -1;
+ }
+
+ sz = read(fd, &buf, sizeof(buf));
+ close(fd);
+
+ if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0)
+ break;
+ }
+
+ asprintf(rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", id);
+ ALOGD("rfkill state path init successed: %s", *rfkill_state_path);
+ return 0;
+}
+
+int rfkill_operations(int on)
+{
+ int fd = -1, ret = -1, sz, ops;
+ char buffer = '0';
+ static char *rfkill_state_path = NULL;
+ CLEAR_ERROR_INFO;
+ if(rfkill_state_path)
+ ALOGW("rfkill_state_path already init: %s", rfkill_state_path);
+ else
+ {
+ if (init_rfkill(&rfkill_state_path))
+ {
+ ALOGE("####INIT rfkill fail###");
+ return ret;
+ }
+ }
+
+ fd = open(rfkill_state_path, O_WRONLY);
+ ALOGD("open %s :%d(%s)", rfkill_state_path, fd, strerror(errno));
+ if(fd > 0)
+ {
+ switch(on)
+ {
+ case BT_POWER_OFF:
+ buffer = '0';
+ break;
+
+ case BT_POWER_ON:
+ buffer = '1';
+ break;
+ default:
+ ALOGE("Unsupported ops(%d)!", on);
+ close(fd);
+ return ret;
+ }
+
+ //write(fd, "0", 1);//pull down first.
+ //usleep(10000);//10ms
+
+ if(write(fd, &buffer, 1) > 0)
+ {
+ // fsync(fd);
+ usleep(10000);//10ms
+ ret = 0;
+ }
+ close(fd);
+ if(buffer == '0')
+ {
+ free(rfkill_state_path);
+ rfkill_state_path = NULL;
+ }
+ }
+ ALOGD("%s: power %s %s(%s)!\n", __FUNCTION__, BT_POWER_ON == on? "up":"down", ret == 0? "done":"failed", strerror(errno));
+ CLEAR_ERROR_INFO;
+ return ret;
+}
+
+int dev_node_operations(int on)
+{
+ int fd = -1, ret = -1, sz, ops;
+
+ CLEAR_ERROR_INFO;
+
+ fd = open("/dev/wifi_power", O_RDWR);
+ ALOGD("open: %d", fd);
+ if(fd > 0)
+ {
+ switch(on)
+ {
+ case BT_POWER_OFF:
+ ops = SDIO_POWER_DOWN;
+ break;
+
+ case BT_POWER_ON:
+ ops = SDIO_POWER_UP;
+ break;
+ default:
+ ALOGE("Unsupported ops(%d)!", on);
+ close(fd);
+ return ret;
+ }
+ if(ioctl(fd, ops) >= 0)
+ {
+ usleep(10000);//10ms
+ ret = 0;
+ }
+ close(fd);
+ }
+ ALOGD("%s: power %s %s(%s)!\n", __FUNCTION__, BT_POWER_ON == on? "up":"down", ret == 0? "done":"failed", strerror(errno));
+ CLEAR_ERROR_INFO;
+ return ret;
+}
+
+int set_sdio_power(int on)
+{
+ CLEAR_ERROR_INFO;
+
+ switch(getBoardCapabilities())
+ {
+ case RFKILL_DEVICE:
+ return rfkill_operations(on);
+ case DEV_NODE_DEVICE:
+ return dev_node_operations(on);
+ default:
+ return -1; //never get to this line.
+ }
+}
+
+int ismod_bt_driver()
+{
+ char driver_status[PROPERTY_VALUE_MAX];
+ unsigned retry = 0;
+ CLEAR_ERROR_INFO;
+
+ property_get(DRIVER_PROP_NAME, driver_status, "mtkdrunkown");
+ ALOGD("%s: driver_status = %s ", __FUNCTION__, driver_status);
+ if(strcmp("true", driver_status) == 0)
+ {
+ ALOGW("%s: btmtksdio.ko is already insmod!", __FUNCTION__);
+ return 0;
+ }
+ ALOGE("%s: set bluetooth.btdriver.mtk true\n", __FUNCTION__);
+ property_set(DRIVER_PROP_NAME,"true");
+
+ return 0;
+}
+
+int load_mtkbt()
+{
+ if(set_sdio_power(1))
+ {
+ ALOGE("%s: failed to power up, so return directly!\n", __FUNCTION__);
+ return -1;
+ }
+
+ if(ismod_bt_driver())
+ {
+ ALOGE("%s: failed to insmod bt driver, so return directly!\n", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+void mtkbt_unload()
+{
+ property_set(DRIVER_PROP_NAME,"false");
+ usleep(500000);
+ set_sdio_power(0);
+}
diff --git a/mtkbt/code/libdriver/radiomgr.c b/mtkbt/code/libdriver/radiomgr.c
new file mode 100755
index 0000000..5f0d30f
--- a/dev/null
+++ b/mtkbt/code/libdriver/radiomgr.c
@@ -0,0 +1,57 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2014. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include "bt_mtk.h"
+
+
+/**************************************************************************
+ * F U N C T I O N S *
+***************************************************************************/
+
+VOID BT_Cleanup(VOID)
+{
+ if (SIG_ERR == signal(SIGRTMIN, SIG_DFL)) {
+ LOG_ERR("Restore signal handler fails errno(%d)\n", errno);
+ }
+ return;
+} \ No newline at end of file
diff --git a/mtkbt/mtkbt.mk b/mtkbt/mtkbt.mk
new file mode 100755
index 0000000..03e93e3
--- a/dev/null
+++ b/mtkbt/mtkbt.mk
@@ -0,0 +1,8 @@
+# Amlogic RELEASE NAME: 20171125_TV_ANDROID_7.1
+
+BOARD_HAVE_BLUETOOTH_MTK := true
+
+
+PRODUCT_PACKAGES += \
+ Bluetooth \
+ audio.a2dp.default
diff --git a/realtek/Android.mk b/realtek/Android.mk
new file mode 100755
index 0000000..cfd03be
--- a/dev/null
+++ b/realtek/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH:= $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))